• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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