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