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 <assert.h>
33 #include <windows.h>
34
35 #include "adebug.h"
36
37 #include "ACMStream.h"
38
39 #include <lame.h>
40
41 // static methods
42
Create()43 ACMStream * ACMStream::Create()
44 {
45 ACMStream * Result;
46
47 Result = new ACMStream;
48
49 return Result;
50 }
51
Erase(const ACMStream * a_ACMStream)52 const bool ACMStream::Erase(const ACMStream * a_ACMStream)
53 {
54 delete a_ACMStream;
55 return true;
56 }
57
58 // class methods
59
ACMStream()60 ACMStream::ACMStream() :
61 m_WorkingBufferUseSize(0),
62 gfp(NULL)
63 {
64 /// \todo get the debug level from the registry
65 my_debug = new ADbg(DEBUG_LEVEL_CREATION);
66 if (my_debug != NULL) {
67 unsigned char DebugFileName[512];
68
69 my_debug->setPrefix("LAMEstream"); /// \todo get it from the registry
70 my_debug->setIncludeTime(true); /// \todo get it from the registry
71
72 // Check in the registry if we have to Output Debug information
73 DebugFileName[0] = '\0';
74
75 HKEY OssKey;
76 if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SOFTWARE\\MUKOLI", 0, KEY_READ , &OssKey ) == ERROR_SUCCESS) {
77 DWORD DataType;
78 DWORD DebugFileNameSize = 512;
79 if (RegQueryValueEx( OssKey, "DebugFile", NULL, &DataType, DebugFileName, &DebugFileNameSize ) == ERROR_SUCCESS) {
80 if (DataType == REG_SZ) {
81 my_debug->setUseFile(true);
82 my_debug->setDebugFile((char *)DebugFileName);
83 my_debug->OutPut("Debug file is %s",(char *)DebugFileName);
84 }
85 }
86 }
87 my_debug->OutPut(DEBUG_LEVEL_FUNC_START, "ACMStream Creation (0X%08X)",this);
88 }
89 else {
90 ADbg debug;
91 debug.OutPut("ACMStream::ACMACMStream : Impossible to create my_debug");
92 }
93
94 }
95
~ACMStream()96 ACMStream::~ACMStream()
97 {
98 // release memory - encoding is finished
99 if (gfp) lame_close( gfp );
100
101 if (my_debug != NULL)
102 {
103 my_debug->OutPut(DEBUG_LEVEL_FUNC_START, "ACMStream Deletion (0X%08X)",this);
104 delete my_debug;
105 }
106 }
107
init(const int nSamplesPerSec,const int nOutputSamplesPerSec,const int nChannels,const int nAvgBytesPerSec,const vbr_mode mode)108 bool ACMStream::init(const int nSamplesPerSec, const int nOutputSamplesPerSec, const int nChannels, const int nAvgBytesPerSec, const vbr_mode mode)
109 {
110 bool bResult = false;
111
112 my_SamplesPerSec = nSamplesPerSec;
113 my_OutBytesPerSec = nOutputSamplesPerSec;
114 my_Channels = nChannels;
115 my_AvgBytesPerSec = nAvgBytesPerSec;
116 my_VBRMode = mode;
117
118 bResult = true;
119
120 return bResult;
121
122 }
123
open(const AEncodeProperties & the_Properties)124 bool ACMStream::open(const AEncodeProperties & the_Properties)
125 {
126 bool bResult = false;
127
128 // Init the MP3 Stream
129 // Init the global flags structure
130 gfp = lame_init();
131
132 // Set input sample frequency
133 lame_set_in_samplerate( gfp, my_SamplesPerSec );
134
135 // Set output sample frequency
136 lame_set_out_samplerate( gfp, my_OutBytesPerSec );
137
138 lame_set_num_channels( gfp, my_Channels );
139 if (my_Channels == 1)
140 lame_set_mode( gfp, MONO );
141 else
142 lame_set_mode( gfp, (MPEG_mode_e)the_Properties.GetChannelModeValue()) ; /// \todo Get the mode from the default configuration
143
144 // lame_set_VBR( gfp, vbr_off ); /// \note VBR not supported for the moment
145 lame_set_VBR( gfp, my_VBRMode ); /// \note VBR not supported for the moment
146
147 if (my_VBRMode == vbr_abr)
148 {
149 lame_set_VBR_q( gfp, 1 );
150
151 lame_set_VBR_mean_bitrate_kbps( gfp, (my_AvgBytesPerSec * 8 + 500) / 1000 );
152
153 if (24000 > lame_get_in_samplerate( gfp ))
154 {
155 // For MPEG-II
156 lame_set_VBR_min_bitrate_kbps( gfp, 8);
157
158 lame_set_VBR_max_bitrate_kbps( gfp, 160);
159 }
160 else
161 {
162 // For MPEG-I
163 lame_set_VBR_min_bitrate_kbps( gfp, 32);
164
165 lame_set_VBR_max_bitrate_kbps( gfp, 320);
166 }
167 }
168
169 // Set bitrate
170 lame_set_brate( gfp, my_AvgBytesPerSec * 8 / 1000 );
171
172 /// \todo Get the mode from the default configuration
173 // Set copyright flag?
174 lame_set_copyright( gfp, the_Properties.GetCopyrightMode()?1:0 );
175 // Do we have to tag it as non original
176 lame_set_original( gfp, the_Properties.GetOriginalMode()?1:0 );
177 // Add CRC?
178 lame_set_error_protection( gfp, the_Properties.GetCRCMode()?1:0 );
179 // Set private bit?
180 lame_set_extension( gfp, the_Properties.GetPrivateMode()?1:0 );
181 // INFO tag support not possible in ACM - it requires rewinding
182 // output stream to the beginning after encoding is finished.
183 lame_set_bWriteVbrTag( gfp, 0 );
184
185 if (0 == lame_init_params( gfp ))
186 {
187 //LAME encoding call will accept any number of samples.
188 if ( 0 == lame_get_version( gfp ) )
189 {
190 // For MPEG-II, only 576 samples per frame per channel
191 my_SamplesPerBlock = 576 * lame_get_num_channels( gfp );
192 }
193 else
194 {
195 // For MPEG-I, 1152 samples per frame per channel
196 my_SamplesPerBlock = 1152 * lame_get_num_channels( gfp );
197 }
198 }
199
200 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "version =%d",lame_get_version( gfp ) );
201 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "Layer =3");
202 switch ( lame_get_mode( gfp ) )
203 {
204 case STEREO: my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "mode =Stereo" ); break;
205 case JOINT_STEREO: my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "mode =Joint-Stereo" ); break;
206 case DUAL_CHANNEL: my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "mode =Forced Stereo" ); break;
207 case MONO: my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "mode =Mono" ); break;
208 case NOT_SET: /* FALLTROUGH */
209 default: my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "mode =Error (unknown)" ); break;
210 }
211
212 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "sampling frequency =%.1f kHz", lame_get_in_samplerate( gfp ) /1000.0 );
213 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "bitrate =%d kbps", lame_get_brate( gfp ) );
214 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "Vbr Min bitrate =%d kbps", lame_get_VBR_min_bitrate_kbps( gfp ) );
215 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "Vbr Max bitrate =%d kbps", lame_get_VBR_max_bitrate_kbps( gfp ) );
216 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "Quality Setting =%d", lame_get_quality( gfp ) );
217
218 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "Low pass frequency =%d", lame_get_lowpassfreq( gfp ) );
219 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "Low pass width =%d", lame_get_lowpasswidth( gfp ) );
220
221 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "High pass frequency =%d", lame_get_highpassfreq( gfp ) );
222 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "High pass width =%d", lame_get_highpasswidth( gfp ) );
223
224 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "No Short Blocks =%d", lame_get_no_short_blocks( gfp ) );
225
226 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "de-emphasis =%d", lame_get_emphasis( gfp ) );
227 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "private flag =%d", lame_get_extension( gfp ) );
228
229 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "copyright flag =%d", lame_get_copyright( gfp ) );
230 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "original flag =%d", lame_get_original( gfp ) );
231 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "CRC =%s", lame_get_error_protection( gfp ) ? "on" : "off" );
232 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "Fast mode =%s", ( lame_get_quality( gfp ) )? "enabled" : "disabled" );
233 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "Force mid/side stereo =%s", ( lame_get_force_ms( gfp ) )?"enabled":"disabled" );
234 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "Disable Resorvoir =%d", lame_get_disable_reservoir( gfp ) );
235 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "VBR =%s, VBR_q =%d, VBR method =",
236 ( lame_get_VBR( gfp ) !=vbr_off ) ? "enabled": "disabled",
237 lame_get_VBR_q( gfp ) );
238
239 switch ( lame_get_VBR( gfp ) )
240 {
241 case vbr_off: my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "vbr_off" ); break;
242 case vbr_mt : my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "vbr_mt" ); break;
243 case vbr_rh : my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "vbr_rh" ); break;
244 case vbr_mtrh: my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "vbr_mtrh" ); break;
245 case vbr_abr:
246 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "vbr_abr (average bitrate %d kbps)", lame_get_VBR_mean_bitrate_kbps( gfp ) );
247 break;
248 default:
249 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "error, unknown VBR setting");
250 break;
251 }
252
253 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "Write VBR Header =%s\n", ( lame_get_bWriteVbrTag( gfp ) ) ?"Yes":"No");
254
255 #ifdef FROM_DLL
256 beConfig.format.LHV1.dwReSampleRate = my_OutBytesPerSec; // force the user resampling
257 #endif // FROM_DLL
258
259 bResult = true;
260
261 return bResult;
262 }
263
close(LPBYTE pOutputBuffer,DWORD * pOutputSize)264 bool ACMStream::close(LPBYTE pOutputBuffer, DWORD *pOutputSize)
265 {
266
267 bool bResult = false;
268
269 int nOutputSamples = 0;
270
271 nOutputSamples = lame_encode_flush( gfp, pOutputBuffer, 0 );
272
273 if ( nOutputSamples < 0 )
274 {
275 // BUFFER_TOO_SMALL
276 *pOutputSize = 0;
277 }
278 else
279 {
280 *pOutputSize = nOutputSamples;
281
282 bResult = true;
283 }
284
285 // lame will be closed in destructor
286 //lame_close( gfp );
287
288 return bResult;
289 }
290
GetOutputSizeForInput(const DWORD the_SrcLength) const291 DWORD ACMStream::GetOutputSizeForInput(const DWORD the_SrcLength) const
292 {
293 /* double OutputInputRatio;
294
295 if (my_VBRMode == vbr_off)
296 OutputInputRatio = double(my_AvgBytesPerSec) / double(my_OutBytesPerSec * 2);
297 else // reserve the space for 320 kbps
298 OutputInputRatio = 40000.0 / double(my_OutBytesPerSec * 2);
299
300 OutputInputRatio *= 1.15; // allow 15% more*/
301
302 DWORD Result;
303
304 // Result = DWORD(double(the_SrcLength) * OutputInputRatio);
305 Result = DWORD(1.25*the_SrcLength + 7200);
306
307 my_debug->OutPut(DEBUG_LEVEL_FUNC_CODE, "Result = %d",Result);
308
309 return Result;
310 }
311
ConvertBuffer(LPACMDRVSTREAMHEADER a_StreamHeader)312 bool ACMStream::ConvertBuffer(LPACMDRVSTREAMHEADER a_StreamHeader)
313 {
314 bool result;
315
316 if (my_debug != NULL)
317 {
318 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "enter ACMStream::ConvertBuffer");
319 }
320
321 DWORD InSize = a_StreamHeader->cbSrcLength / 2, OutSize = a_StreamHeader->cbDstLength; // 2 for 8<->16 bits
322
323 // Encode it
324 int dwSamples;
325 int nOutputSamples = 0;
326
327 dwSamples = InSize / lame_get_num_channels( gfp );
328
329 if ( 1 == lame_get_num_channels( gfp ) )
330 {
331 nOutputSamples = lame_encode_buffer(gfp,(PSHORT)a_StreamHeader->pbSrc,(PSHORT)a_StreamHeader->pbSrc,dwSamples,a_StreamHeader->pbDst,a_StreamHeader->cbDstLength);
332 }
333 else
334 {
335 nOutputSamples = lame_encode_buffer_interleaved(gfp,(PSHORT)a_StreamHeader->pbSrc,dwSamples,a_StreamHeader->pbDst,a_StreamHeader->cbDstLength);
336 }
337
338 a_StreamHeader->cbSrcLengthUsed = a_StreamHeader->cbSrcLength;
339 a_StreamHeader->cbDstLengthUsed = nOutputSamples;
340
341 result = a_StreamHeader->cbDstLengthUsed <= a_StreamHeader->cbDstLength;
342
343 my_debug->OutPut(DEBUG_LEVEL_FUNC_CODE, "UsedSize = %d / EncodedSize = %d, result = %d (%d <= %d)", InSize, OutSize, result, a_StreamHeader->cbDstLengthUsed, a_StreamHeader->cbDstLength);
344
345 if (my_debug != NULL)
346 {
347 my_debug->OutPut(DEBUG_LEVEL_FUNC_DEBUG, "ACMStream::ConvertBuffer result = %d (0x%02X 0x%02X)",result,a_StreamHeader->pbDst[0],a_StreamHeader->pbDst[1]);
348 }
349
350 return result;
351 }
352
353 /* map frequency to a valid MP3 sample frequency
354 *
355 * Robert Hegemann 2000-07-01
356 */
357 static int
map2MP3Frequency(int freq)358 map2MP3Frequency(int freq)
359 {
360 if (freq <= 8000)
361 return 8000;
362 if (freq <= 11025)
363 return 11025;
364 if (freq <= 12000)
365 return 12000;
366 if (freq <= 16000)
367 return 16000;
368 if (freq <= 22050)
369 return 22050;
370 if (freq <= 24000)
371 return 24000;
372 if (freq <= 32000)
373 return 32000;
374 if (freq <= 44100)
375 return 44100;
376
377 return 48000;
378 }
379
380
GetOutputSampleRate(int samples_per_sec,int bitrate,int channels)381 unsigned int ACMStream::GetOutputSampleRate(int samples_per_sec, int bitrate, int channels)
382 {
383 if (bitrate==0)
384 bitrate = (64000*channels)/8;
385
386 /// \todo pass through the same LAME routine
387 unsigned int OutputFrequency;
388 double compression_ratio = double(samples_per_sec * 16 * channels / (bitrate * 8));
389 if (compression_ratio > 13.)
390 OutputFrequency = map2MP3Frequency( (10. * bitrate * 8) / (16 * channels));
391 else
392 OutputFrequency = map2MP3Frequency( 0.97 * samples_per_sec );
393
394 return OutputFrequency;
395
396 }
397
398