1 /**
2 *
3 * Lame ACM wrapper, encode/decode MP3 based RIFF/AVI files in MS Windows
4 *
5 * Copyright (c) 2002 Steve Lhomme <steve.lhomme at free.fr>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23 /*!
24 \author Steve Lhomme
25 \version \$Id$
26 */
27
28 #if !defined(STRICT)
29 #define STRICT
30 #endif // STRICT
31
32 #include <algorithm>
33
34 #include <windows.h>
35 #include <windowsx.h>
36 #include <intshcut.h>
37
38 #include <mmreg.h>
39 #include <msacm.h>
40 #include <msacmdrv.h>
41
42 #include <assert.h>
43
44 #include <lame.h>
45
46 #include "adebug.h"
47 #include "resource.h"
48 #include "ACMStream.h"
49
50 #ifdef ENABLE_DECODING
51 #include "DecodeStream.h"
52 #endif // ENABLE_DECODING
53
54 #include "ACM.h"
55
56 #ifndef IDC_HAND
57 #define IDC_HAND MAKEINTRESOURCE(32649)
58 #endif // IDC_HAND
59
60 char ACM::VersionString[120];
61
62 const char ACM_VERSION[] = "0.9.2";
63
64 #ifdef WIN32
65 //
66 // 32-bit versions
67 //
68 #if (WINVER >= 0x0400)
69 #define VERSION_ACM_DRIVER MAKE_ACM_VERSION(4, 0, 0)
70 #else
71 #define VERSION_ACM_DRIVER MAKE_ACM_VERSION(3, 51, 0)
72 #endif
73 #define VERSION_MSACM MAKE_ACM_VERSION(3, 50, 0)
74
75 #else
76 //
77 // 16-bit versions
78 //
79 #define VERSION_ACM_DRIVER MAKE_ACM_VERSION(1, 0, 0)
80 #define VERSION_MSACM MAKE_ACM_VERSION(2, 1, 0)
81
82 #endif
83
84 #define PERSONAL_FORMAT WAVE_FORMAT_MPEGLAYER3
85 #define SIZE_FORMAT_STRUCT sizeof(MPEGLAYER3WAVEFORMAT)
86 //#define SIZE_FORMAT_STRUCT 0
87
88 //static const char channel_mode[][13] = {"mono","stereo","joint stereo","dual channel"};
89 static const char channel_mode[][13] = {"mono","stereo"};
90 static const unsigned int mpeg1_freq[] = {48000,44100,32000};
91 static const unsigned int mpeg2_freq[] = {24000,22050,16000,12000,11025,8000};
92 static const unsigned int mpeg1_bitrate[] = {320, 256, 224, 192, 160, 128, 112, 96, 80, 64, 56, 48, 40, 32};
93 static const unsigned int mpeg2_bitrate[] = {160, 144, 128, 112, 96, 80, 64, 56, 48, 40, 32, 24, 16, 8};
94
95 #define SIZE_CHANNEL_MODE (sizeof(channel_mode) / (sizeof(char) * 13))
96 #define SIZE_FREQ_MPEG1 (sizeof(mpeg1_freq) / sizeof(unsigned int))
97 #define SIZE_FREQ_MPEG2 (sizeof(mpeg2_freq) / sizeof(unsigned int))
98 #define SIZE_BITRATE_MPEG1 (sizeof(mpeg1_bitrate) / sizeof(unsigned int))
99 #define SIZE_BITRATE_MPEG2 (sizeof(mpeg2_bitrate) / sizeof(unsigned int))
100
101 static const int FORMAT_TAG_MAX_NB = 2; // PCM and PERSONAL (mandatory to have at least PCM and your format)
102 static const int FILTER_TAG_MAX_NB = 0; // this is a codec, not a filter
103
104 // number of supported PCM formats
105 static const int FORMAT_MAX_NB_PCM =
106 2 * // number of PCM channel mode (stereo/mono)
107 (SIZE_FREQ_MPEG1 + // number of MPEG 1 sampling freq
108 SIZE_FREQ_MPEG2); // number of MPEG 2 sampling freq
109
110 //////////////////////////////////////////////////////////////////////
111 //
112 //////////////////////////////////////////////////////////////////////
operator <(const bitrate_item & other_bitrate) const113 bool bitrate_item::operator<(const bitrate_item & other_bitrate) const
114 {
115 return (other_bitrate.frequency < frequency ||
116 (other_bitrate.frequency == frequency &&
117 (other_bitrate.bitrate < bitrate ||
118 (other_bitrate.bitrate == bitrate &&
119 (other_bitrate.channels < channels)))));
120 }
121
122 //////////////////////////////////////////////////////////////////////
123 // Configuration Dialog
124 //////////////////////////////////////////////////////////////////////
125 /*
126 static CALLBACK ConfigProc(
127 HWND hwndDlg, // handle to dialog box
128 UINT uMsg, // message
129 WPARAM wParam, // first message parameter
130 LPARAM lParam // second message parameter
131 )
132 {
133 BOOL bResult;
134
135 switch (uMsg) {
136 case WM_COMMAND:
137 UINT command;
138 command = GET_WM_COMMAND_ID(wParam, lParam);
139 if (IDOK == command)
140 {
141 EndDialog(hwndDlg, (IDOK == command));
142 } else if (IDCANCEL == command)
143 {
144 EndDialog(hwndDlg, (IDOK == command));
145 }
146 bResult = FALSE;
147 break;
148 default:
149 bResult = FALSE; // will be treated by DefWindowProc
150 }
151 return bResult;
152 }
153
154
155 inline DWORD ACM::Configure(HWND hParentWindow, LPDRVCONFIGINFO pConfig)
156 {
157 my_debug.OutPut(DEBUG_LEVEL_FUNC_START, "ACM : Configure (Parent Window = 0x%08X)",hParentWindow);
158
159 DialogBoxParam( my_hModule, MAKEINTRESOURCE(IDD_CONFIG), hParentWindow, ::ConfigProc , (LPARAM)this);
160
161 return DRVCNF_OK; // Can also return
162 // DRVCNF_CANCEL
163 // and DRVCNF_RESTART
164 }
165 */
166 //////////////////////////////////////////////////////////////////////
167 // About Dialog
168 //////////////////////////////////////////////////////////////////////
169
AboutProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)170 static BOOL CALLBACK AboutProc(
171 HWND hwndDlg, // handle to dialog box
172 UINT uMsg, // message
173 WPARAM wParam, // first message parameter
174 LPARAM lParam // second message parameter
175 )
176 {
177 static HBRUSH hBrushStatic = NULL;
178 // static LOGFONT lf; // structure for font information
179 // static HFONT hfnt;
180 static HCURSOR hcOverCursor = NULL;
181 BOOL bResult = FALSE;
182
183 switch (uMsg) {
184 case WM_INITDIALOG:
185 char tmp[150];
186 wsprintf(tmp,"LAME MP3 codec v%s", ACM::GetVersionString());
187 ::SetWindowText(GetDlgItem( hwndDlg, IDC_STATIC_ABOUT_TITLE), tmp);
188
189 /*
190 ::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lf);
191 lf.lfUnderline = TRUE;
192
193 hfnt = ::CreateFontIndirect(&lf);
194
195 ::SendMessage(::GetDlgItem(hwndDlg,IDC_STATIC_ABOUT_URL), WM_SETFONT, (WPARAM) hfnt, TRUE);
196 * /
197 hBrushStatic = ::CreateSolidBrush(::GetSysColor (COLOR_BTNFACE));
198 */ hcOverCursor = ::LoadCursor(NULL,(LPCTSTR)IDC_HAND);
199 if (hcOverCursor == NULL)
200 hcOverCursor = ::LoadCursor(NULL,(LPCTSTR)IDC_CROSS);
201
202 bResult = TRUE;
203 break;
204 /*
205 case WM_CTLCOLORSTATIC:
206 /// \todo only if there are URLs
207 if ((HWND)lParam == ::GetDlgItem(hwndDlg,IDC_STATIC_ABOUT_URL))
208 {
209 ::SetTextColor((HDC)wParam, ::GetSysColor (COLOR_HIGHLIGHT));
210 ::SetBkColor((HDC)wParam, ::GetSysColor (COLOR_BTNFACE));
211
212 return (LRESULT) hBrushStatic;
213 }
214 else
215 return (LRESULT) NULL;
216 */
217 case WM_MOUSEMOVE:
218 {
219 POINT pnt;
220 ::GetCursorPos(&pnt);
221
222 RECT rect;
223 ::GetWindowRect( ::GetDlgItem(hwndDlg,IDC_STATIC_ABOUT_URL), &rect);
224
225 if ( ::PtInRect(&rect,pnt) )
226 {
227 ::SetCursor(hcOverCursor);
228 }
229
230
231 }
232 break;
233
234 case WM_LBUTTONUP:
235 {
236 POINT pnt;
237 ::GetCursorPos(&pnt);
238
239 RECT rect;
240 ::GetWindowRect( ::GetDlgItem(hwndDlg,IDC_STATIC_ABOUT_URL), &rect);
241
242 TCHAR Url[200];
243 bool bUrl = false;
244 if (::PtInRect(&rect,pnt))
245 {
246 wsprintf(Url,get_lame_url());
247 bUrl = true;
248 }
249
250 if (bUrl)
251 {
252 ::ShellExecute(hwndDlg,"open",Url,NULL,"",SW_SHOWMAXIMIZED );
253 }
254
255 }
256 break;
257
258 case WM_COMMAND:
259 UINT command;
260 command = GET_WM_COMMAND_ID(wParam, lParam);
261 if (IDOK == command)
262 {
263 EndDialog(hwndDlg, TRUE);
264 }
265 bResult = FALSE;
266 break;
267
268 case IDC_STATIC_ABOUT_URL:
269 break;
270 default:
271 bResult = FALSE; // will be treated by DefWindowProc
272 }
273 return bResult;
274 }
275
About(HWND hParentWindow)276 inline DWORD ACM::About(HWND hParentWindow)
277 {
278 my_debug.OutPut(DEBUG_LEVEL_FUNC_START, "ACM : About (Parent Window = 0x%08X)",hParentWindow);
279
280 DialogBoxParam( my_hModule, MAKEINTRESOURCE(IDD_ABOUT), hParentWindow, ::AboutProc , (LPARAM)this);
281
282 return DRVCNF_OK; // Can also return
283 // DRVCNF_CANCEL
284 // and DRVCNF_RESTART
285 }
286
287
288 //////////////////////////////////////////////////////////////////////
289 // Construction/Destruction
290 //////////////////////////////////////////////////////////////////////
291
ACM(HMODULE hModule)292 ACM::ACM( HMODULE hModule )
293 :my_hModule(hModule),
294 my_hIcon(NULL),
295 my_debug(ADbg(DEBUG_LEVEL_CREATION)),
296 my_EncodingProperties(hModule)
297 {
298 my_EncodingProperties.ParamsRestore();
299
300 /// \todo get the debug level from the registry
301 unsigned char DebugFileName[512];
302
303 char tmp[128];
304 wsprintf(tmp,"LAMEacm 0x%08X",this);
305 my_debug.setPrefix(tmp); /// \todo get it from the registry
306 my_debug.setIncludeTime(true); /// \todo get it from the registry
307
308 // Check in the registry if we have to Output Debug information
309 DebugFileName[0] = '\0';
310
311 HKEY OssKey;
312 if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SOFTWARE\\MUKOLI", 0, KEY_READ , &OssKey ) == ERROR_SUCCESS) {
313 DWORD DataType;
314 DWORD DebugFileNameSize = 512;
315 if (RegQueryValueEx( OssKey, "DebugFile", NULL, &DataType, DebugFileName, &DebugFileNameSize ) == ERROR_SUCCESS) {
316 if (DataType == REG_SZ) {
317 my_debug.setUseFile(true);
318 my_debug.setDebugFile((char *)DebugFileName);
319 my_debug.OutPut("Debug file is %s",(char *)DebugFileName);
320 }
321 }
322 }
323 wsprintf(VersionString,"%s - %s", ACM_VERSION, get_lame_version() );
324 BuildBitrateTable();
325
326 my_debug.OutPut(DEBUG_LEVEL_FUNC_START, "New ACM Creation (0x%08X)",this);
327 }
328
~ACM()329 ACM::~ACM()
330 {
331 // not used, it's done automatically when closing the driver if (my_hIcon != NULL)
332 // CloseHandle(my_hIcon);
333
334 bitrate_table.clear();
335
336 my_debug.OutPut(DEBUG_LEVEL_FUNC_START, "ACM Deleted (0x%08X)",this);
337 }
338
339 //////////////////////////////////////////////////////////////////////
340 // Main message handler
341 //////////////////////////////////////////////////////////////////////
342
DriverProcedure(const HDRVR hdrvr,const UINT msg,LONG lParam1,LONG lParam2)343 LONG ACM::DriverProcedure(const HDRVR hdrvr, const UINT msg, LONG lParam1, LONG lParam2)
344 {
345 DWORD dwRes = 0L;
346
347 //my_debug.OutPut(DEBUG_LEVEL_MSG, "message 0x%08X for ThisACM 0x%08X", msg, this);
348
349 switch (msg) {
350 case DRV_INSTALL:
351 my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_INSTALL");
352 // Sent when the driver is installed.
353 dwRes = DRVCNF_OK; // Can also return
354 break; // DRVCNF_CANCEL
355 // and DRV_RESTART
356
357 case DRV_REMOVE:
358 // Sent when the driver is removed.
359 my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_REMOVE");
360 dwRes = 1L; // return value ignored
361 break;
362
363 case DRV_QUERYCONFIGURE:
364 my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_QUERYCONFIGURE");
365 // Sent to determine if the driver can be
366 // configured.
367 dwRes = 1L; // Zero indicates configuration
368 break; // NOT supported
369
370 case DRV_CONFIGURE:
371 my_debug.OutPut(DEBUG_LEVEL_MSG, "DRV_CONFIGURE");
372 // Sent to display the configuration
373 // dialog box for the driver.
374 // dwRes = Configure( (HWND) lParam1, (LPDRVCONFIGINFO) lParam2 );
375 if (my_EncodingProperties.Config(my_hModule, (HWND) lParam1))
376 {
377 dwRes = DRVCNF_OK; // Can also return
378 // DRVCNF_CANCEL
379 // and DRVCNF_RESTART
380 } else {
381 dwRes = DRVCNF_CANCEL;
382 }
383 break;
384
385 /**************************************
386 // ACM additional messages
387 ***************************************/
388
389 case ACMDM_DRIVER_ABOUT:
390 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_DRIVER_ABOUT");
391
392 dwRes = About( (HWND) lParam1 );
393
394 break;
395
396 case ACMDM_DRIVER_DETAILS: // acmDriverDetails
397 // Fill-in general informations about the driver/codec
398 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_DRIVER_DETAILS");
399
400 dwRes = OnDriverDetails(hdrvr, (LPACMDRIVERDETAILS) lParam1);
401
402 break;
403
404 case ACMDM_FORMATTAG_DETAILS: // acmFormatTagDetails
405 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_FORMATTAG_DETAILS");
406
407 dwRes = OnFormatTagDetails((LPACMFORMATTAGDETAILS) lParam1, lParam2);
408
409 break;
410
411 case ACMDM_FORMAT_DETAILS: // acmFormatDetails
412 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_FORMAT_DETAILS");
413
414 dwRes = OnFormatDetails((LPACMFORMATDETAILS) lParam1, lParam2);
415
416 break;
417
418 case ACMDM_FORMAT_SUGGEST: // acmFormatSuggest
419 // Sent to determine if the driver can be
420 // configured.
421 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_FORMAT_SUGGEST");
422 dwRes = OnFormatSuggest((LPACMDRVFORMATSUGGEST) lParam1);
423 break;
424
425 /**************************************
426 // ACM stream messages
427 ***************************************/
428
429 case ACMDM_STREAM_OPEN:
430 // Sent to determine if the driver can be
431 // configured.
432 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_OPEN");
433 dwRes = OnStreamOpen((LPACMDRVSTREAMINSTANCE) lParam1);
434 break;
435
436 case ACMDM_STREAM_SIZE:
437 // returns a recommended size for a source
438 // or destination buffer on an ACM stream
439 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_SIZE");
440 dwRes = OnStreamSize((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMDRVSTREAMSIZE)lParam2);
441 break;
442
443 case ACMDM_STREAM_PREPARE:
444 // prepares an ACMSTREAMHEADER structure for
445 // an ACM stream conversion
446 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_PREPARE");
447 dwRes = OnStreamPrepareHeader((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMSTREAMHEADER) lParam2);
448 break;
449
450 case ACMDM_STREAM_UNPREPARE:
451 // cleans up the preparation performed by
452 // the ACMDM_STREAM_PREPARE message for an ACM stream
453 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_UNPREPARE");
454 dwRes = OnStreamUnPrepareHeader((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMSTREAMHEADER) lParam2);
455 break;
456
457 case ACMDM_STREAM_CONVERT:
458 // perform a conversion on the specified conversion stream
459 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_CONVERT");
460 dwRes = OnStreamConvert((LPACMDRVSTREAMINSTANCE)lParam1, (LPACMDRVSTREAMHEADER) lParam2);
461
462 break;
463
464 case ACMDM_STREAM_CLOSE:
465 // closes an ACM conversion stream
466 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACMDM_STREAM_CLOSE");
467 dwRes = OnStreamClose((LPACMDRVSTREAMINSTANCE)lParam1);
468 break;
469
470 /**************************************
471 // Unknown message
472 ***************************************/
473
474 default:
475 // Process any other messages.
476 my_debug.OutPut(DEBUG_LEVEL_MSG, "ACM::DriverProc unknown message (0x%08X), lParam1 = 0x%08X, lParam2 = 0x%08X", msg, lParam1, lParam2);
477 return DefDriverProc ((DWORD)this, hdrvr, msg, lParam1, lParam2);
478 }
479
480 return dwRes;
481 }
482
483 //////////////////////////////////////////////////////////////////////
484 // Special message handlers
485 //////////////////////////////////////////////////////////////////////
486 /*!
487 Retreive the config details of this ACM driver
488 The index represent the specified format
489
490 \param a_FormatDetails will be filled with all the corresponding data
491 */
OnFormatDetails(LPACMFORMATDETAILS a_FormatDetails,const LPARAM a_Query)492 inline DWORD ACM::OnFormatDetails(LPACMFORMATDETAILS a_FormatDetails, const LPARAM a_Query)
493 {
494 DWORD Result = ACMERR_NOTPOSSIBLE;
495
496 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATDETAILS a_Query = 0x%08X",a_Query);
497 switch (a_Query & ACM_FORMATDETAILSF_QUERYMASK) {
498
499 // Fill-in the informations corresponding to the FormatDetails->dwFormatTagIndex
500 case ACM_FORMATDETAILSF_INDEX :
501 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "enter ACM_FORMATDETAILSF_INDEX for index 0x%04X:%03d",a_FormatDetails->dwFormatTag,a_FormatDetails->dwFormatIndex);
502 if (a_FormatDetails->dwFormatTag == PERSONAL_FORMAT) {
503 if (a_FormatDetails->dwFormatIndex < GetNumberEncodingFormats()) {
504 LPWAVEFORMATEX WaveExt;
505 WaveExt = a_FormatDetails->pwfx;
506
507 WaveExt->wFormatTag = PERSONAL_FORMAT;
508
509 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format in : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
510 GetMP3FormatForIndex(a_FormatDetails->dwFormatIndex, *WaveExt, a_FormatDetails->szFormat);
511 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format out : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
512 Result = MMSYSERR_NOERROR;
513 }
514 else
515 {
516 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATDETAILSF_INDEX unknown index 0x%04X:%03d",a_FormatDetails->dwFormatTag,a_FormatDetails->dwFormatIndex);
517 }
518 }
519 else if (a_FormatDetails->dwFormatTag == WAVE_FORMAT_PCM) {
520 if (a_FormatDetails->dwFormatIndex < FORMAT_MAX_NB_PCM) {
521 LPWAVEFORMATEX WaveExt;
522 WaveExt = a_FormatDetails->pwfx;
523
524 WaveExt->wFormatTag = WAVE_FORMAT_PCM;
525
526 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format in : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
527 GetPCMFormatForIndex(a_FormatDetails->dwFormatIndex, *WaveExt, a_FormatDetails->szFormat);
528 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "format out : channels %d, sample rate %d", WaveExt->nChannels, WaveExt->nSamplesPerSec);
529 Result = MMSYSERR_NOERROR;
530 }
531 else
532 {
533 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATDETAILSF_INDEX unknown index 0x%04X:%03d",a_FormatDetails->dwFormatTag,a_FormatDetails->dwFormatIndex);
534 }
535 }
536 else
537 {
538 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Unknown a_FormatDetails->dwFormatTag = 0x%08X",a_FormatDetails->dwFormatTag);
539 }
540
541 case ACM_FORMATDETAILSF_FORMAT :
542 /// \todo we may output the corresponding strong (only for personal format)
543 LPWAVEFORMATEX WaveExt;
544 WaveExt = a_FormatDetails->pwfx;
545
546 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "enter ACM_FORMATDETAILSF_FORMAT : 0x%04X:%03d, format in : channels %d, sample rate %d",a_FormatDetails->dwFormatTag,a_FormatDetails->dwFormatIndex, WaveExt->nChannels, WaveExt->nSamplesPerSec);
547
548 Result = MMSYSERR_NOERROR;
549 break;
550
551 default:
552 Result = ACMERR_NOTPOSSIBLE;
553 break;
554 }
555
556 a_FormatDetails->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
557
558 return Result;
559 }
560
561 /*!
562 Retreive the details of each known format by this ACM driver
563 The index represent the specified format (0 = MP3 / 1 = PCM)
564
565 \param a_FormatTagDetails will be filled with all the corresponding data
566 */
OnFormatTagDetails(LPACMFORMATTAGDETAILS a_FormatTagDetails,const LPARAM a_Query)567 inline DWORD ACM::OnFormatTagDetails(LPACMFORMATTAGDETAILS a_FormatTagDetails, const LPARAM a_Query)
568 {
569 DWORD Result;
570 DWORD the_format = WAVE_FORMAT_UNKNOWN; // the format to give details
571
572 if (a_FormatTagDetails->cbStruct >= sizeof(*a_FormatTagDetails)) {
573
574 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACMDM_FORMATTAG_DETAILS, a_Query = 0x%08X",a_Query);
575 switch(a_Query & ACM_FORMATTAGDETAILSF_QUERYMASK) {
576
577 case ACM_FORMATTAGDETAILSF_INDEX:
578 // Fill-in the informations corresponding to the a_FormatDetails->dwFormatTagIndex
579 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "get ACM_FORMATTAGDETAILSF_INDEX for index %03d",a_FormatTagDetails->dwFormatTagIndex);
580
581 if (a_FormatTagDetails->dwFormatTagIndex < FORMAT_TAG_MAX_NB) {
582 switch (a_FormatTagDetails->dwFormatTagIndex)
583 {
584 case 0:
585 the_format = PERSONAL_FORMAT;
586 break;
587 default :
588 the_format = WAVE_FORMAT_PCM;
589 break;
590 }
591 }
592 else
593 {
594 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATTAGDETAILSF_INDEX for unsupported index %03d",a_FormatTagDetails->dwFormatTagIndex);
595 Result = ACMERR_NOTPOSSIBLE;
596 }
597 break;
598
599 case ACM_FORMATTAGDETAILSF_FORMATTAG:
600 // Fill-in the informations corresponding to the a_FormatDetails->dwFormatTagIndex and hdrvr given
601 switch (a_FormatTagDetails->dwFormatTag)
602 {
603 case WAVE_FORMAT_PCM:
604 the_format = WAVE_FORMAT_PCM;
605 break;
606 case PERSONAL_FORMAT:
607 the_format = PERSONAL_FORMAT;
608 break;
609 default:
610 return (ACMERR_NOTPOSSIBLE);
611 }
612 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "get ACM_FORMATTAGDETAILSF_FORMATTAG for index 0x%02X, cStandardFormats = %d",a_FormatTagDetails->dwFormatTagIndex,a_FormatTagDetails->cStandardFormats);
613 break;
614 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
615 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "ACM_FORMATTAGDETAILSF_LARGESTSIZE not used");
616 Result = 0L;
617 break;
618 default:
619 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails Unknown Format tag query");
620 Result = MMSYSERR_NOTSUPPORTED;
621 break;
622 }
623
624 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails the_format = 0x%08X",the_format);
625 switch(the_format)
626 {
627 case WAVE_FORMAT_PCM:
628 a_FormatTagDetails->dwFormatTag = WAVE_FORMAT_PCM;
629 a_FormatTagDetails->dwFormatTagIndex = 0;
630 a_FormatTagDetails->cbFormatSize = sizeof(PCMWAVEFORMAT);
631 /// \note 0 may mean we don't know how to decode
632 a_FormatTagDetails->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
633 a_FormatTagDetails->cStandardFormats = FORMAT_MAX_NB_PCM;
634 // should be filled by Windows a_FormatTagDetails->szFormatTag[0] = '\0';
635 Result = MMSYSERR_NOERROR;
636 break;
637 case PERSONAL_FORMAT:
638 a_FormatTagDetails->dwFormatTag = PERSONAL_FORMAT;
639 a_FormatTagDetails->dwFormatTagIndex = 1;
640 a_FormatTagDetails->cbFormatSize = SIZE_FORMAT_STRUCT;
641 a_FormatTagDetails->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
642 a_FormatTagDetails->cStandardFormats = GetNumberEncodingFormats();
643 lstrcpyW( a_FormatTagDetails->szFormatTag, L"Lame MP3" );
644 Result = MMSYSERR_NOERROR;
645 break;
646 default:
647 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails Unknown format 0x%08X",the_format);
648 return (ACMERR_NOTPOSSIBLE);
649 }
650 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnFormatTagDetails %d possibilities for format 0x%08X",a_FormatTagDetails->cStandardFormats,the_format);
651 }
652 else
653 {
654 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "a_FormatTagDetails->cbStruct < sizeof(*a_FormatDetails)");
655 Result = ACMERR_NOTPOSSIBLE;
656 }
657
658 return Result;
659 }
660
661 /*!
662 Retreive the global details of this ACM driver
663
664 \param a_DriverDetail will be filled with all the corresponding data
665 */
OnDriverDetails(const HDRVR hdrvr,LPACMDRIVERDETAILS a_DriverDetail)666 inline DWORD ACM::OnDriverDetails(const HDRVR hdrvr, LPACMDRIVERDETAILS a_DriverDetail)
667 {
668 if (my_hIcon == NULL)
669 my_hIcon = LoadIcon(GetDriverModuleHandle(hdrvr), MAKEINTRESOURCE(IDI_ICON));
670 a_DriverDetail->hicon = my_hIcon;
671
672 a_DriverDetail->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
673 a_DriverDetail->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
674
675 /// \note this is an explicit hack of the FhG values
676 /// \note later it could be a new value when the decoding is done
677 a_DriverDetail->wMid = MM_FRAUNHOFER_IIS;
678 a_DriverDetail->wPid = MM_FHGIIS_MPEGLAYER3;
679
680 a_DriverDetail->vdwACM = VERSION_MSACM;
681 a_DriverDetail->vdwDriver = VERSION_ACM_DRIVER;
682 a_DriverDetail->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
683 a_DriverDetail->cFormatTags = FORMAT_TAG_MAX_NB; // 2 : MP3 and PCM
684 // a_DriverDetail->cFormatTags = 1; // 2 : MP3 and PCM
685 a_DriverDetail->cFilterTags = FILTER_TAG_MAX_NB;
686
687 lstrcpyW( a_DriverDetail->szShortName, L"LAME MP3" );
688 char tmpStr[128];
689 wsprintf(tmpStr, "LAME MP3 Codec v%s", GetVersionString());
690 int u = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, tmpStr, -1, a_DriverDetail->szLongName, 0);
691 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, tmpStr, -1, a_DriverDetail->szLongName, u);
692 lstrcpyW( a_DriverDetail->szCopyright, L"2002 Steve Lhomme" );
693 lstrcpyW( a_DriverDetail->szLicensing, L"LGPL (see gnu.org)" );
694 /// \todo update this part when the code changes
695 lstrcpyW( a_DriverDetail->szFeatures , L"only CBR implementation" );
696
697 return MMSYSERR_NOERROR; // Can also return DRVCNF_CANCEL
698 }
699
700 /*!
701 Suggest an output format for the specified input format
702
703 \param a_FormatSuggest will be filled with all the corresponding data
704 */
OnFormatSuggest(LPACMDRVFORMATSUGGEST a_FormatSuggest)705 inline DWORD ACM::OnFormatSuggest(LPACMDRVFORMATSUGGEST a_FormatSuggest)
706 {
707 DWORD Result = MMSYSERR_NOTSUPPORTED;
708 DWORD fdwSuggest = (ACM_FORMATSUGGESTF_TYPEMASK & a_FormatSuggest->fdwSuggest);
709
710 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest %s%s%s%s (0x%08X)",
711 (fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS) ? "channels, ":"",
712 (fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC) ? "samples/sec, ":"",
713 (fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE) ? "bits/sample, ":"",
714 (fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG) ? "format, ":"",
715 fdwSuggest);
716
717 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest for source format = 0x%04X, channels = %d, Samples/s = %d, AvgB/s = %d, BlockAlign = %d, b/sample = %d",
718 a_FormatSuggest->pwfxSrc->wFormatTag,
719 a_FormatSuggest->pwfxSrc->nChannels,
720 a_FormatSuggest->pwfxSrc->nSamplesPerSec,
721 a_FormatSuggest->pwfxSrc->nAvgBytesPerSec,
722 a_FormatSuggest->pwfxSrc->nBlockAlign,
723 a_FormatSuggest->pwfxSrc->wBitsPerSample);
724
725 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggested destination format = 0x%04X, channels = %d, Samples/s = %d, AvgB/s = %d, BlockAlign = %d, b/sample = %d",
726 a_FormatSuggest->pwfxDst->wFormatTag,
727 a_FormatSuggest->pwfxDst->nChannels,
728 a_FormatSuggest->pwfxDst->nSamplesPerSec,
729 a_FormatSuggest->pwfxDst->nAvgBytesPerSec,
730 a_FormatSuggest->pwfxDst->nBlockAlign,
731 a_FormatSuggest->pwfxDst->wBitsPerSample);
732
733 switch (a_FormatSuggest->pwfxSrc->wFormatTag)
734 {
735 case WAVE_FORMAT_PCM:
736 /// \todo handle here the decoding ?
737 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest for PCM source");
738 //
739 // if the destination format tag is restricted, verify that
740 // it is within our capabilities...
741 //
742 // this driver is able to decode to PCM
743 //
744 if (ACM_FORMATSUGGESTF_WFORMATTAG & fdwSuggest)
745 {
746 if (PERSONAL_FORMAT != a_FormatSuggest->pwfxDst->wFormatTag)
747 return (ACMERR_NOTPOSSIBLE);
748 }
749 else
750 {
751 a_FormatSuggest->pwfxDst->wFormatTag = PERSONAL_FORMAT;
752 }
753
754
755 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed A");
756 //
757 // if the destination channel count is restricted, verify that
758 // it is within our capabilities...
759 //
760 // this driver is not able to change the number of channels
761 //
762 if (ACM_FORMATSUGGESTF_NCHANNELS & fdwSuggest)
763 {
764 if (a_FormatSuggest->pwfxSrc->nChannels != a_FormatSuggest->pwfxDst->nChannels)
765 return (ACMERR_NOTPOSSIBLE);
766 }
767 else
768 {
769 a_FormatSuggest->pwfxDst->nChannels = a_FormatSuggest->pwfxSrc->nChannels;
770 }
771
772 if (a_FormatSuggest->pwfxSrc->nChannels != 1 && a_FormatSuggest->pwfxSrc->nChannels != 2)
773 return MMSYSERR_INVALPARAM;
774
775
776 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed B");
777 //
778 // if the destination samples per second is restricted, verify
779 // that it is within our capabilities...
780 //
781 // this driver is not able to change the sample rate
782 //
783 if (ACM_FORMATSUGGESTF_NSAMPLESPERSEC & fdwSuggest)
784 {
785 if (a_FormatSuggest->pwfxSrc->nSamplesPerSec != a_FormatSuggest->pwfxDst->nSamplesPerSec)
786 return (ACMERR_NOTPOSSIBLE);
787 }
788 else
789 {
790 a_FormatSuggest->pwfxDst->nSamplesPerSec = a_FormatSuggest->pwfxSrc->nSamplesPerSec;
791 }
792
793
794 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed C");
795 //
796 // if the destination bits per sample is restricted, verify
797 // that it is within our capabilities...
798 //
799 // We prefer decoding to 16-bit PCM.
800 //
801 if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
802 {
803 if ( (16 != a_FormatSuggest->pwfxDst->wBitsPerSample) && (8 != a_FormatSuggest->pwfxDst->wBitsPerSample) )
804 return (ACMERR_NOTPOSSIBLE);
805 }
806 else
807 {
808 a_FormatSuggest->pwfxDst->wBitsPerSample = 16;
809 }
810
811 // a_FormatSuggest->pwfxDst->nBlockAlign = FORMAT_BLOCK_ALIGN;
812 a_FormatSuggest->pwfxDst->nBlockAlign = a_FormatSuggest->pwfxDst->nChannels * a_FormatSuggest->pwfxDst->wBitsPerSample / 8;
813
814 a_FormatSuggest->pwfxDst->nAvgBytesPerSec = a_FormatSuggest->pwfxDst->nChannels * 64000 / 8;
815
816 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed");
817 Result = MMSYSERR_NOERROR;
818
819
820 break;
821 case PERSONAL_FORMAT:
822 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest for PERSONAL source");
823 //
824 // if the destination format tag is restricted, verify that
825 // it is within our capabilities...
826 //
827 // this driver is able to decode to PCM
828 //
829 if (ACM_FORMATSUGGESTF_WFORMATTAG & fdwSuggest)
830 {
831 if (WAVE_FORMAT_PCM != a_FormatSuggest->pwfxDst->wFormatTag)
832 return (ACMERR_NOTPOSSIBLE);
833 }
834 else
835 {
836 a_FormatSuggest->pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
837 }
838
839
840 //
841 // if the destination channel count is restricted, verify that
842 // it is within our capabilities...
843 //
844 // this driver is not able to change the number of channels
845 //
846 if (ACM_FORMATSUGGESTF_NCHANNELS & fdwSuggest)
847 {
848 if (a_FormatSuggest->pwfxSrc->nChannels != a_FormatSuggest->pwfxDst->nChannels)
849 return (ACMERR_NOTPOSSIBLE);
850 }
851 else
852 {
853 a_FormatSuggest->pwfxDst->nChannels = a_FormatSuggest->pwfxSrc->nChannels;
854 }
855
856
857 //
858 // if the destination samples per second is restricted, verify
859 // that it is within our capabilities...
860 //
861 // this driver is not able to change the sample rate
862 //
863 if (ACM_FORMATSUGGESTF_NSAMPLESPERSEC & fdwSuggest)
864 {
865 if (a_FormatSuggest->pwfxSrc->nSamplesPerSec != a_FormatSuggest->pwfxDst->nSamplesPerSec)
866 return (ACMERR_NOTPOSSIBLE);
867 }
868 else
869 {
870 a_FormatSuggest->pwfxDst->nSamplesPerSec = a_FormatSuggest->pwfxSrc->nSamplesPerSec;
871 }
872
873
874 //
875 // if the destination bits per sample is restricted, verify
876 // that it is within our capabilities...
877 //
878 // We prefer decoding to 16-bit PCM.
879 //
880 if (ACM_FORMATSUGGESTF_WBITSPERSAMPLE & fdwSuggest)
881 {
882 if ( (16 != a_FormatSuggest->pwfxDst->wBitsPerSample) && (8 != a_FormatSuggest->pwfxDst->wBitsPerSample) )
883 return (ACMERR_NOTPOSSIBLE);
884 }
885 else
886 {
887 a_FormatSuggest->pwfxDst->wBitsPerSample = 16;
888 }
889
890 // a_FormatSuggest->pwfxDst->nBlockAlign = FORMAT_BLOCK_ALIGN;
891 a_FormatSuggest->pwfxDst->nBlockAlign = a_FormatSuggest->pwfxDst->nChannels * a_FormatSuggest->pwfxDst->wBitsPerSample / 8;
892
893 /// \todo this value must be a correct one !
894 a_FormatSuggest->pwfxDst->nAvgBytesPerSec = a_FormatSuggest->pwfxDst->nSamplesPerSec * a_FormatSuggest->pwfxDst->nChannels * a_FormatSuggest->pwfxDst->wBitsPerSample / 8;
895
896 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggest succeed");
897 Result = MMSYSERR_NOERROR;
898
899
900 break;
901 }
902
903 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Suggested destination format = 0x%04X, channels = %d, Samples/s = %d, AvgB/s = %d, BlockAlign = %d, b/sample = %d",
904 a_FormatSuggest->pwfxDst->wFormatTag,
905 a_FormatSuggest->pwfxDst->nChannels,
906 a_FormatSuggest->pwfxDst->nSamplesPerSec,
907 a_FormatSuggest->pwfxDst->nAvgBytesPerSec,
908 a_FormatSuggest->pwfxDst->nBlockAlign,
909 a_FormatSuggest->pwfxDst->wBitsPerSample);
910
911 return Result;
912 }
913
914 /*!
915 Create a stream instance for decoding/encoding
916
917 \param a_StreamInstance contain information about the stream desired
918 */
OnStreamOpen(LPACMDRVSTREAMINSTANCE a_StreamInstance)919 inline DWORD ACM::OnStreamOpen(LPACMDRVSTREAMINSTANCE a_StreamInstance)
920 {
921 DWORD Result = ACMERR_NOTPOSSIBLE;
922
923 //
924 // the most important condition to check before doing anything else
925 // is that this ACM driver can actually perform the conversion we are
926 // being opened for. this check should fail as quickly as possible
927 // if the conversion is not possible by this driver.
928 //
929 // it is VERY important to fail quickly so the ACM can attempt to
930 // find a driver that is suitable for the conversion. also note that
931 // the ACM may call this driver several times with slightly different
932 // format specifications before giving up.
933 //
934 // this driver first verifies that the source and destination formats
935 // are acceptable...
936 //
937 switch (a_StreamInstance->pwfxSrc->wFormatTag)
938 {
939 case WAVE_FORMAT_PCM:
940 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream for PCM source (%05d samples %d channels %d bits/sample)",a_StreamInstance->pwfxSrc->nSamplesPerSec,a_StreamInstance->pwfxSrc->nChannels,a_StreamInstance->pwfxSrc->wBitsPerSample);
941 if (a_StreamInstance->pwfxDst->wFormatTag == PERSONAL_FORMAT)
942 {
943 unsigned int OutputFrequency;
944
945 /// \todo Smart mode
946 if (my_EncodingProperties.GetSmartOutputMode())
947 OutputFrequency = ACMStream::GetOutputSampleRate(a_StreamInstance->pwfxSrc->nSamplesPerSec,a_StreamInstance->pwfxDst->nAvgBytesPerSec,a_StreamInstance->pwfxDst->nChannels);
948 else
949 OutputFrequency = a_StreamInstance->pwfxSrc->nSamplesPerSec;
950
951 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream for PERSONAL output (%05d samples %d channels %d bits/sample %d kbps)",a_StreamInstance->pwfxDst->nSamplesPerSec,a_StreamInstance->pwfxDst->nChannels,a_StreamInstance->pwfxDst->wBitsPerSample,8 * a_StreamInstance->pwfxDst->nAvgBytesPerSec);
952
953 /// \todo add the possibility to have channel resampling (mono to stereo / stereo to mono)
954 /// \todo support resampling ?
955 /// \todo only do the test on OutputFrequency in "Smart Output" mode
956 if (a_StreamInstance->pwfxDst->nSamplesPerSec != OutputFrequency ||
957 // a_StreamInstance->pwfxSrc->nSamplesPerSec != a_StreamInstance->pwfxDst->nSamplesPerSec ||
958 a_StreamInstance->pwfxSrc->nChannels != a_StreamInstance->pwfxDst->nChannels ||
959 a_StreamInstance->pwfxSrc->wBitsPerSample != 16)
960 {
961 Result = ACMERR_NOTPOSSIBLE;
962 } else {
963 if ((a_StreamInstance->fdwOpen & ACM_STREAMOPENF_QUERY) == 0)
964 {
965 ACMStream * the_stream = ACMStream::Create();
966 a_StreamInstance->dwInstance = (DWORD) the_stream;
967
968 if (the_stream != NULL)
969 {
970 MPEGLAYER3WAVEFORMAT * casted = (MPEGLAYER3WAVEFORMAT *) a_StreamInstance->pwfxDst;
971 vbr_mode a_mode = (casted->fdwFlags-2 == 0)?vbr_abr:vbr_off;
972 if (the_stream->init(a_StreamInstance->pwfxDst->nSamplesPerSec,
973 OutputFrequency,
974 a_StreamInstance->pwfxDst->nChannels,
975 a_StreamInstance->pwfxDst->nAvgBytesPerSec,
976 a_mode))
977 Result = MMSYSERR_NOERROR;
978 else
979 ACMStream::Erase( the_stream );
980 }
981 }
982 else
983 {
984 Result = MMSYSERR_NOERROR;
985 }
986 }
987 }
988 break;
989 case PERSONAL_FORMAT:
990 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream for PERSONAL source (%05d samples %d channels %d bits/sample %d kbps)",a_StreamInstance->pwfxSrc->nSamplesPerSec,a_StreamInstance->pwfxSrc->nChannels,a_StreamInstance->pwfxSrc->wBitsPerSample,8 * a_StreamInstance->pwfxSrc->nAvgBytesPerSec);
991 if (a_StreamInstance->pwfxDst->wFormatTag == WAVE_FORMAT_PCM)
992 {
993 #ifdef ENABLE_DECODING
994 if ((a_StreamInstance->fdwOpen & ACM_STREAMOPENF_QUERY) == 0)
995 {
996 /// \todo create the decoding stream
997 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream for PCM output (%05d samples %d channels %d bits/sample %d B/s)",a_StreamInstance->pwfxDst->nSamplesPerSec,a_StreamInstance->pwfxDst->nChannels,a_StreamInstance->pwfxDst->wBitsPerSample,a_StreamInstance->pwfxDst->nAvgBytesPerSec);
998
999 DecodeStream * the_stream = DecodeStream::Create();
1000 a_StreamInstance->dwInstance = (DWORD) the_stream;
1001
1002 if (the_stream != NULL)
1003 {
1004 if (the_stream->init(a_StreamInstance->pwfxDst->nSamplesPerSec,
1005 a_StreamInstance->pwfxDst->nChannels,
1006 a_StreamInstance->pwfxDst->nAvgBytesPerSec,
1007 a_StreamInstance->pwfxSrc->nAvgBytesPerSec))
1008 Result = MMSYSERR_NOERROR;
1009 else
1010 DecodeStream::Erase( the_stream );
1011 }
1012 }
1013 else
1014 {
1015 /// \todo decoding verification
1016 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream is valid");
1017 Result = MMSYSERR_NOERROR;
1018 }
1019 #endif // ENABLE_DECODING
1020 }
1021 break;
1022 }
1023
1024 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Open stream Result = %d",Result);
1025 return Result;
1026 }
1027
OnStreamSize(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMDRVSTREAMSIZE the_StreamSize)1028 inline DWORD ACM::OnStreamSize(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMDRVSTREAMSIZE the_StreamSize)
1029 {
1030 DWORD Result = ACMERR_NOTPOSSIBLE;
1031
1032 switch (ACM_STREAMSIZEF_QUERYMASK & the_StreamSize->fdwSize)
1033 {
1034 case ACM_STREAMSIZEF_DESTINATION:
1035 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Get source buffer size for destination size = %d",the_StreamSize->cbDstLength);
1036 break;
1037 case ACM_STREAMSIZEF_SOURCE:
1038 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "Get destination buffer size for source size = %d",the_StreamSize->cbSrcLength);
1039 if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1040 PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1041 {
1042 ACMStream * the_stream = (ACMStream *) a_StreamInstance->dwInstance;
1043 if (the_stream != NULL)
1044 {
1045 the_StreamSize->cbDstLength = the_stream->GetOutputSizeForInput(the_StreamSize->cbSrcLength);
1046 Result = MMSYSERR_NOERROR;
1047 }
1048 }
1049 else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1050 WAVE_FORMAT_PCM== a_StreamInstance->pwfxDst->wFormatTag)
1051 {
1052 #ifdef ENABLE_DECODING
1053 DecodeStream * the_stream = (DecodeStream *) a_StreamInstance->dwInstance;
1054 if (the_stream != NULL)
1055 {
1056 the_StreamSize->cbDstLength = the_stream->GetOutputSizeForInput(the_StreamSize->cbSrcLength);
1057 Result = MMSYSERR_NOERROR;
1058 }
1059 #endif // ENABLE_DECODING
1060 }
1061 break;
1062 default:
1063 Result = MMSYSERR_INVALFLAG;
1064 break;
1065 }
1066
1067 return Result;
1068 }
1069
OnStreamClose(LPACMDRVSTREAMINSTANCE a_StreamInstance)1070 inline DWORD ACM::OnStreamClose(LPACMDRVSTREAMINSTANCE a_StreamInstance)
1071 {
1072 DWORD Result = ACMERR_NOTPOSSIBLE;
1073
1074 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamClose the stream 0x%X",a_StreamInstance->dwInstance);
1075 if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1076 PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1077 {
1078 ACMStream::Erase( (ACMStream *) a_StreamInstance->dwInstance );
1079 }
1080 else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1081 WAVE_FORMAT_PCM== a_StreamInstance->pwfxDst->wFormatTag)
1082 {
1083 #ifdef ENABLE_DECODING
1084 DecodeStream::Erase( (DecodeStream *) a_StreamInstance->dwInstance );
1085 #endif // ENABLE_DECODING
1086 }
1087
1088 // nothing to do yet
1089 Result = MMSYSERR_NOERROR;
1090
1091 return Result;
1092 }
1093
OnStreamPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMSTREAMHEADER a_StreamHeader)1094 inline DWORD ACM::OnStreamPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMSTREAMHEADER a_StreamHeader)
1095 {
1096 DWORD Result = ACMERR_NOTPOSSIBLE;
1097
1098 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, " prepare : Src : %d (0x%08X) / %d - Dst : %d (0x%08X) / %d"
1099 , a_StreamHeader->cbSrcLength
1100 , a_StreamHeader->pbSrc
1101 , a_StreamHeader->cbSrcLengthUsed
1102 , a_StreamHeader->cbDstLength
1103 , a_StreamHeader->pbDst
1104 , a_StreamHeader->cbDstLengthUsed
1105 );
1106
1107 if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1108 PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1109 {
1110 ACMStream * the_stream = (ACMStream *)a_StreamInstance->dwInstance;
1111
1112 if (the_stream->open(my_EncodingProperties))
1113 Result = MMSYSERR_NOERROR;
1114 }
1115 else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1116 WAVE_FORMAT_PCM == a_StreamInstance->pwfxDst->wFormatTag)
1117 {
1118 #ifdef ENABLE_DECODING
1119 DecodeStream * the_stream = (DecodeStream *)a_StreamInstance->dwInstance;
1120
1121 if (the_stream->open())
1122 Result = MMSYSERR_NOERROR;
1123 #endif // ENABLE_DECODING
1124 }
1125
1126 return Result;
1127 }
1128
OnStreamUnPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMSTREAMHEADER a_StreamHeader)1129 inline DWORD ACM::OnStreamUnPrepareHeader(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMSTREAMHEADER a_StreamHeader)
1130 {
1131 DWORD Result = ACMERR_NOTPOSSIBLE;
1132
1133 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "unprepare : Src : %d / %d - Dst : %d / %d"
1134 , a_StreamHeader->cbSrcLength
1135 , a_StreamHeader->cbSrcLengthUsed
1136 , a_StreamHeader->cbDstLength
1137 , a_StreamHeader->cbDstLengthUsed
1138 );
1139 if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1140 PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1141 {
1142 ACMStream * the_stream = (ACMStream *)a_StreamInstance->dwInstance;
1143 DWORD OutputSize = a_StreamHeader->cbDstLength;
1144
1145 if (the_stream->close(a_StreamHeader->pbDst, &OutputSize) && (OutputSize <= a_StreamHeader->cbDstLength))
1146 {
1147 a_StreamHeader->cbDstLengthUsed = OutputSize;
1148 Result = MMSYSERR_NOERROR;
1149 }
1150 }
1151 else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1152 WAVE_FORMAT_PCM== a_StreamInstance->pwfxDst->wFormatTag)
1153 {
1154 #ifdef ENABLE_DECODING
1155 DecodeStream * the_stream = (DecodeStream *)a_StreamInstance->dwInstance;
1156 DWORD OutputSize = a_StreamHeader->cbDstLength;
1157
1158 if (the_stream->close(a_StreamHeader->pbDst, &OutputSize) && (OutputSize <= a_StreamHeader->cbDstLength))
1159 {
1160 a_StreamHeader->cbDstLengthUsed = OutputSize;
1161 Result = MMSYSERR_NOERROR;
1162 }
1163 #endif // ENABLE_DECODING
1164 }
1165
1166 return Result;
1167 }
1168
OnStreamConvert(LPACMDRVSTREAMINSTANCE a_StreamInstance,LPACMDRVSTREAMHEADER a_StreamHeader)1169 inline DWORD ACM::OnStreamConvert(LPACMDRVSTREAMINSTANCE a_StreamInstance, LPACMDRVSTREAMHEADER a_StreamHeader)
1170 {
1171 DWORD Result = ACMERR_NOTPOSSIBLE;
1172
1173 if (WAVE_FORMAT_PCM == a_StreamInstance->pwfxSrc->wFormatTag &&
1174 PERSONAL_FORMAT == a_StreamInstance->pwfxDst->wFormatTag)
1175 {
1176 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamConvert SRC = PCM (encode)");
1177
1178 ACMStream * the_stream = (ACMStream *) a_StreamInstance->dwInstance;
1179 if (the_stream != NULL)
1180 {
1181 if (the_stream->ConvertBuffer( a_StreamHeader ))
1182 Result = MMSYSERR_NOERROR;
1183 }
1184 }
1185 else if (PERSONAL_FORMAT == a_StreamInstance->pwfxSrc->wFormatTag &&
1186 WAVE_FORMAT_PCM == a_StreamInstance->pwfxDst->wFormatTag)
1187 {
1188 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamConvert SRC = MP3 (decode)");
1189
1190 #ifdef ENABLE_DECODING
1191 DecodeStream * the_stream = (DecodeStream *) a_StreamInstance->dwInstance;
1192 if (the_stream != NULL)
1193 {
1194 if (the_stream->ConvertBuffer( a_StreamHeader ))
1195 Result = MMSYSERR_NOERROR;
1196 }
1197 #endif // ENABLE_DECODING
1198 }
1199 else
1200 my_debug.OutPut(DEBUG_LEVEL_FUNC_CODE, "OnStreamConvert unsupported conversion");
1201
1202 return Result;
1203 }
1204
1205
GetMP3FormatForIndex(const DWORD the_Index,WAVEFORMATEX & the_Format,unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const1206 void ACM::GetMP3FormatForIndex(const DWORD the_Index, WAVEFORMATEX & the_Format, unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const
1207 {
1208 int Block_size;
1209 char temp[ACMFORMATDETAILS_FORMAT_CHARS];
1210
1211
1212 if (the_Index < bitrate_table.size())
1213 {
1214 // the_Format.wBitsPerSample = 16;
1215 the_Format.wBitsPerSample = 0;
1216
1217 /// \todo handle more channel modes (mono, stereo, joint-stereo, dual-channel)
1218 // the_Format.nChannels = SIZE_CHANNEL_MODE - int(the_Index % SIZE_CHANNEL_MODE);
1219
1220 the_Format.nBlockAlign = 1;
1221
1222 the_Format.nSamplesPerSec = bitrate_table[the_Index].frequency;
1223 the_Format.nAvgBytesPerSec = bitrate_table[the_Index].bitrate * 1000 / 8;
1224 if (bitrate_table[the_Index].frequency >= mpeg1_freq[SIZE_FREQ_MPEG1-1])
1225 Block_size = 1152;
1226 else
1227 Block_size = 576;
1228
1229 the_Format.nChannels = bitrate_table[the_Index].channels;
1230
1231 the_Format.cbSize = sizeof(MPEGLAYER3WAVEFORMAT) - sizeof(WAVEFORMATEX);
1232 MPEGLAYER3WAVEFORMAT * tmpFormat = (MPEGLAYER3WAVEFORMAT *) &the_Format;
1233 tmpFormat->wID = 1;
1234 // this is the only way I found to know if we do CBR or ABR
1235 tmpFormat->fdwFlags = 2 + ((bitrate_table[the_Index].mode == vbr_abr)?0:2);
1236 tmpFormat->nBlockSize = Block_size * the_Format.nAvgBytesPerSec / the_Format.nSamplesPerSec;
1237 tmpFormat->nFramesPerBlock = 1;
1238 tmpFormat->nCodecDelay = 0; // 0x0571 on FHG
1239
1240 /// \todo : generate the string with the appropriate stereo mode
1241 if (bitrate_table[the_Index].mode == vbr_abr)
1242 wsprintfA( temp, "%d Hz, %d kbps ABR, %s", the_Format.nSamplesPerSec, the_Format.nAvgBytesPerSec * 8 / 1000, (the_Format.nChannels == 1)?"Mono":"Stereo");
1243 else
1244 wsprintfA( temp, "%d Hz, %d kbps CBR, %s", the_Format.nSamplesPerSec, the_Format.nAvgBytesPerSec * 8 / 1000, (the_Format.nChannels == 1)?"Mono":"Stereo");
1245
1246 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, temp, -1, the_String, ACMFORMATDETAILS_FORMAT_CHARS);
1247 }
1248 }
1249
GetPCMFormatForIndex(const DWORD the_Index,WAVEFORMATEX & the_Format,unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const1250 void ACM::GetPCMFormatForIndex(const DWORD the_Index, WAVEFORMATEX & the_Format, unsigned short the_String[ACMFORMATDETAILS_FORMAT_CHARS]) const
1251 {
1252 the_Format.nChannels = SIZE_CHANNEL_MODE - int(the_Index % SIZE_CHANNEL_MODE);
1253 the_Format.wBitsPerSample = 16;
1254 the_Format.nBlockAlign = the_Format.nChannels * the_Format.wBitsPerSample / 8;
1255
1256
1257 DWORD a_Channel_Independent = the_Index / SIZE_CHANNEL_MODE;
1258
1259 // first MPEG1 frequencies
1260 if (a_Channel_Independent < SIZE_FREQ_MPEG1)
1261 {
1262 the_Format.nSamplesPerSec = mpeg1_freq[a_Channel_Independent];
1263 }
1264 else
1265 {
1266 a_Channel_Independent -= SIZE_FREQ_MPEG1;
1267 the_Format.nSamplesPerSec = mpeg2_freq[a_Channel_Independent];
1268 }
1269
1270 the_Format.nAvgBytesPerSec = the_Format.nSamplesPerSec * the_Format.nChannels * the_Format.wBitsPerSample / 8;
1271 }
1272
GetNumberEncodingFormats() const1273 DWORD ACM::GetNumberEncodingFormats() const
1274 {
1275 return bitrate_table.size();
1276 }
1277
IsSmartOutput(const int frequency,const int bitrate,const int channels) const1278 bool ACM::IsSmartOutput(const int frequency, const int bitrate, const int channels) const
1279 {
1280 double compression_ratio = double(frequency * 2 * channels) / double(bitrate * 100);
1281
1282 //my_debug.OutPut(DEBUG_LEVEL_FUNC_DEBUG, "compression_ratio %f, freq %d, bitrate %d, channels %d", compression_ratio, frequency, bitrate, channels);
1283
1284 if(my_EncodingProperties.GetSmartOutputMode())
1285 return (compression_ratio <= my_EncodingProperties.GetSmartRatio());
1286 else return true;
1287 }
1288
BuildBitrateTable()1289 void ACM::BuildBitrateTable()
1290 {
1291 my_debug.OutPut("entering BuildBitrateTable");
1292
1293 // fill the table
1294 unsigned int channel,bitrate,freq;
1295
1296 bitrate_table.clear();
1297
1298 // CBR bitrates
1299 for (channel = 0;channel < SIZE_CHANNEL_MODE;channel++)
1300 {
1301 // MPEG I
1302 for (freq = 0;freq < SIZE_FREQ_MPEG1;freq++)
1303 {
1304 for (bitrate = 0;bitrate < SIZE_BITRATE_MPEG1;bitrate++)
1305 {
1306
1307 if (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg1_freq[freq], mpeg1_bitrate[bitrate], channel+1))
1308 {
1309 bitrate_item bitrate_table_tmp;
1310
1311 bitrate_table_tmp.frequency = mpeg1_freq[freq];
1312 bitrate_table_tmp.bitrate = mpeg1_bitrate[bitrate];
1313 bitrate_table_tmp.channels = channel+1;
1314 bitrate_table_tmp.mode = vbr_off;
1315 bitrate_table.push_back(bitrate_table_tmp);
1316 }
1317 }
1318 }
1319 // MPEG II / II.5
1320 for (freq = 0;freq < SIZE_FREQ_MPEG2;freq++)
1321 {
1322 for (bitrate = 0;bitrate < SIZE_BITRATE_MPEG2;bitrate++)
1323 {
1324 if (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg2_freq[freq], mpeg2_bitrate[bitrate], channel+1))
1325 {
1326 bitrate_item bitrate_table_tmp;
1327
1328 bitrate_table_tmp.frequency = mpeg2_freq[freq];
1329 bitrate_table_tmp.bitrate = mpeg2_bitrate[bitrate];
1330 bitrate_table_tmp.channels = channel+1;
1331 bitrate_table_tmp.mode = vbr_abr;
1332 bitrate_table.push_back(bitrate_table_tmp);
1333 }
1334 }
1335 }
1336 }
1337
1338 if (my_EncodingProperties.GetAbrOutputMode())
1339 // ABR bitrates
1340 {
1341 for (channel = 0;channel < SIZE_CHANNEL_MODE;channel++)
1342 {
1343 // MPEG I
1344 for (freq = 0;freq < SIZE_FREQ_MPEG1;freq++)
1345 {
1346 for (bitrate = my_EncodingProperties.GetAbrBitrateMax();
1347 bitrate >= my_EncodingProperties.GetAbrBitrateMin();
1348 bitrate -= my_EncodingProperties.GetAbrBitrateStep())
1349 {
1350 if (bitrate >= mpeg1_bitrate[SIZE_BITRATE_MPEG1-1] && (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg1_freq[freq], bitrate, channel+1)))
1351 {
1352 bitrate_item bitrate_table_tmp;
1353
1354 bitrate_table_tmp.frequency = mpeg1_freq[freq];
1355 bitrate_table_tmp.bitrate = bitrate;
1356 bitrate_table_tmp.channels = channel+1;
1357 bitrate_table_tmp.mode = vbr_abr;
1358 bitrate_table.push_back(bitrate_table_tmp);
1359 }
1360 }
1361 }
1362 // MPEG II / II.5
1363 for (freq = 0;freq < SIZE_FREQ_MPEG2;freq++)
1364 {
1365 for (bitrate = my_EncodingProperties.GetAbrBitrateMax();
1366 bitrate >= my_EncodingProperties.GetAbrBitrateMin();
1367 bitrate -= my_EncodingProperties.GetAbrBitrateStep())
1368 {
1369 if (bitrate >= mpeg2_bitrate[SIZE_BITRATE_MPEG2-1] && (!my_EncodingProperties.GetSmartOutputMode() || IsSmartOutput(mpeg2_freq[freq], bitrate, channel+1)))
1370 {
1371 bitrate_item bitrate_table_tmp;
1372
1373 bitrate_table_tmp.frequency = mpeg2_freq[freq];
1374 bitrate_table_tmp.bitrate = bitrate;
1375 bitrate_table_tmp.channels = channel+1;
1376 bitrate_table_tmp.mode = vbr_abr;
1377 bitrate_table.push_back(bitrate_table_tmp);
1378 }
1379 }
1380 }
1381 }
1382 }
1383
1384 // sorting by frequency/bitrate/channel
1385 std::sort(bitrate_table.begin(), bitrate_table.end());
1386
1387 /* {
1388 // display test
1389 int i=0;
1390 for (i=0; i<bitrate_table.size();i++)
1391 {
1392 my_debug.OutPut("bitrate_table[%d].frequency = %d",i,bitrate_table[i].frequency);
1393 my_debug.OutPut("bitrate_table[%d].bitrate = %d",i,bitrate_table[i].bitrate);
1394 my_debug.OutPut("bitrate_table[%d].channel = %d",i,bitrate_table[i].channels);
1395 my_debug.OutPut("bitrate_table[%d].ABR = %s\n",i,(bitrate_table[i].mode == vbr_abr)?"ABR":"CBR");
1396 }
1397 }*/
1398
1399 my_debug.OutPut("leaving BuildBitrateTable");
1400 }
1401