• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  LAME MP3 encoder for DirectShow
3  *  LAME encoder wrapper
4  *
5  *  Copyright (c) 2000-2005 Marie Orlova, Peter Gubanov, Vitaly Ivanov, Elecard Ltd.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 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  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 
23 #include <streams.h>
24 #include "Encoder.h"
25 
26 
27 //////////////////////////////////////////////////////////////////////
28 // Construction/Destruction
29 //////////////////////////////////////////////////////////////////////
CEncoder()30 CEncoder::CEncoder() :
31     pgf(NULL),
32     m_bInpuTypeSet(FALSE),
33     m_bOutpuTypeSet(FALSE),
34     m_bFinished(FALSE),
35     m_frameCount(0),
36     m_outOffset(0),
37     m_outReadOffset(0)
38 {
39     m_outFrameBuf = new unsigned char[OUT_BUFFER_SIZE];
40 }
41 
~CEncoder()42 CEncoder::~CEncoder()
43 {
44     Close(NULL);
45 
46     if (m_outFrameBuf)
47         delete [] m_outFrameBuf;
48 }
49 
50 //////////////////////////////////////////////////////////////////////
51 // SetInputType - check if given input type is supported
52 //////////////////////////////////////////////////////////////////////
SetInputType(LPWAVEFORMATEX lpwfex,bool bJustCheck)53 HRESULT CEncoder::SetInputType(LPWAVEFORMATEX lpwfex, bool bJustCheck)
54 {
55     CAutoLock l(&m_lock);
56 
57     if (lpwfex->wFormatTag == WAVE_FORMAT_PCM)
58     {
59         if (lpwfex->nChannels == 1 || lpwfex->nChannels == 2)
60         {
61             if (lpwfex->nSamplesPerSec  == 48000 ||
62                 lpwfex->nSamplesPerSec  == 44100 ||
63                 lpwfex->nSamplesPerSec  == 32000 ||
64                 lpwfex->nSamplesPerSec  == 24000 ||
65                 lpwfex->nSamplesPerSec  == 22050 ||
66                 lpwfex->nSamplesPerSec  == 16000 ||
67                 lpwfex->nSamplesPerSec  == 12000 ||
68                 lpwfex->nSamplesPerSec  == 11025 ||
69                 lpwfex->nSamplesPerSec  ==  8000)
70             {
71                 if (lpwfex->wBitsPerSample == 16)
72                 {
73                     if (!bJustCheck)
74                     {
75                         memcpy(&m_wfex, lpwfex, sizeof(WAVEFORMATEX));
76                         m_bInpuTypeSet = true;
77                     }
78 
79                     return S_OK;
80                 }
81             }
82         }
83     }
84 
85     if (!bJustCheck)
86         m_bInpuTypeSet = false;
87 
88     return E_INVALIDARG;
89 }
90 
91 //////////////////////////////////////////////////////////////////////
92 // SetOutputType - try to initialize encoder with given output type
93 //////////////////////////////////////////////////////////////////////
SetOutputType(MPEG_ENCODER_CONFIG & mabsi)94 HRESULT CEncoder::SetOutputType(MPEG_ENCODER_CONFIG &mabsi)
95 {
96     CAutoLock l(&m_lock);
97 
98     m_mabsi = mabsi;
99     m_bOutpuTypeSet = true;
100 
101     return S_OK;
102 }
103 
104 //////////////////////////////////////////////////////////////////////
105 // SetDefaultOutputType - sets default MPEG audio properties according
106 // to input type
107 //////////////////////////////////////////////////////////////////////
SetDefaultOutputType(LPWAVEFORMATEX lpwfex)108 HRESULT CEncoder::SetDefaultOutputType(LPWAVEFORMATEX lpwfex)
109 {
110     CAutoLock l(&m_lock);
111 
112     if(lpwfex->nChannels == 1 || m_mabsi.bForceMono)
113         m_mabsi.ChMode = MONO;
114 
115     if((lpwfex->nSamplesPerSec < m_mabsi.dwSampleRate) || (lpwfex->nSamplesPerSec % m_mabsi.dwSampleRate != 0))
116         m_mabsi.dwSampleRate = lpwfex->nSamplesPerSec;
117 
118     return S_OK;
119 }
120 
121 //////////////////////////////////////////////////////////////////////
122 // Init - initialized or reiniyialized encoder SDK with given input
123 // and output settings
124 //////////////////////////////////////////////////////////////////////
Init()125 HRESULT CEncoder::Init()
126 {
127     CAutoLock l(&m_lock);
128 
129     m_outOffset     = 0;
130     m_outReadOffset = 0;
131 
132     m_bFinished     = FALSE;
133 
134     m_frameCount    = 0;
135 
136     if (!pgf)
137     {
138         if (!m_bInpuTypeSet || !m_bOutpuTypeSet)
139             return E_UNEXPECTED;
140 
141         // Init Lame library
142         // note: newer, safer interface which doesn't
143         // allow or require direct access to 'gf' struct is being written
144         // see the file 'API' included with LAME.
145         if (pgf = lame_init())
146         {
147             lame_set_num_channels(pgf, m_wfex.nChannels);
148             lame_set_in_samplerate(pgf, m_wfex.nSamplesPerSec);
149             lame_set_out_samplerate(pgf, m_mabsi.dwSampleRate);
150             if ((lame_get_out_samplerate(pgf) >= 32000) && (m_mabsi.dwBitrate < 32))
151                 lame_set_brate(pgf, 32);
152             else
153                 lame_set_brate(pgf, m_mabsi.dwBitrate);
154             lame_set_VBR(pgf, m_mabsi.vmVariable);
155             lame_set_VBR_min_bitrate_kbps(pgf, m_mabsi.dwVariableMin);
156             lame_set_VBR_max_bitrate_kbps(pgf, m_mabsi.dwVariableMax);
157 
158             lame_set_copyright(pgf, m_mabsi.bCopyright);
159             lame_set_original(pgf, m_mabsi.bOriginal);
160             lame_set_error_protection(pgf, m_mabsi.bCRCProtect);
161 
162             lame_set_bWriteVbrTag(pgf, m_mabsi.dwXingTag);
163             lame_set_strict_ISO(pgf, m_mabsi.dwStrictISO);
164             lame_set_VBR_hard_min(pgf, m_mabsi.dwEnforceVBRmin);
165 
166             if (lame_get_num_channels(pgf) == 2 && !m_mabsi.bForceMono)
167             {
168                 //int act_br = pgf->VBR ? pgf->VBR_min_bitrate_kbps + pgf->VBR_max_bitrate_kbps / 2 : pgf->brate;
169 
170                 // Disabled. It's for user's consideration now
171                 //int rel = pgf->out_samplerate / (act_br + 1);
172                 //pgf->mode = rel < 200 ? m_mabsi.ChMode : JOINT_STEREO;
173 
174                 lame_set_mode(pgf, m_mabsi.ChMode);
175             }
176             else
177                 lame_set_mode(pgf, MONO);
178 
179             if (lame_get_mode(pgf) == JOINT_STEREO)
180                 lame_set_force_ms(pgf, m_mabsi.dwForceMS);
181             else
182                 lame_set_force_ms(pgf, 0);
183 
184 //            pgf->mode_fixed = m_mabsi.dwModeFixed;
185 
186             if (m_mabsi.dwVoiceMode != 0)
187             {
188                 lame_set_lowpassfreq(pgf,12000);
189                 ///pgf->VBR_max_bitrate_kbps = 160;
190             }
191 
192             if (m_mabsi.dwKeepAllFreq != 0)
193             {
194                 ///pgf->lowpassfreq = -1;
195                 ///pgf->highpassfreq = -1;
196                 /// not available anymore
197             }
198 
199             lame_set_quality(pgf, m_mabsi.dwQuality);
200             lame_set_VBR_q(pgf, m_mabsi.dwVBRq);
201 
202             lame_init_params(pgf);
203 
204             // encoder delay compensation
205             {
206                 int const nch = lame_get_num_channels(pgf);
207                 short * start_padd = (short *)calloc(48, nch * sizeof(short));
208 
209 				int out_bytes = 0;
210 
211                 if (nch == 2)
212                     out_bytes = lame_encode_buffer_interleaved(pgf, start_padd, 48, m_outFrameBuf, OUT_BUFFER_SIZE);
213                 else
214                     out_bytes = lame_encode_buffer(pgf, start_padd, start_padd, 48, m_outFrameBuf, OUT_BUFFER_SIZE);
215 
216 				if (out_bytes > 0)
217 					m_outOffset += out_bytes;
218 
219                 free(start_padd);
220             }
221 
222             return S_OK;
223         }
224 
225         return E_FAIL;
226     }
227 
228     return S_OK;
229 }
230 
231 //////////////////////////////////////////////////////////////////////
232 // Close - closes encoder
233 //////////////////////////////////////////////////////////////////////
Close(IStream * pStream)234 HRESULT CEncoder::Close(IStream* pStream)
235 {
236 	CAutoLock l(&m_lock);
237     if (pgf)
238     {
239 		if(lame_get_bWriteVbrTag(pgf) && pStream)
240 		{
241 			updateLameTagFrame(pStream);
242 		}
243 
244         lame_close(pgf);
245         pgf = NULL;
246     }
247 
248     return S_OK;
249 }
250 
251 //////////////////////////////////////////////////////////////////////
252 // Encode - encodes data placed on pdata and returns
253 // the number of processed bytes
254 //////////////////////////////////////////////////////////////////////
Encode(const short * pdata,int data_size)255 int CEncoder::Encode(const short * pdata, int data_size)
256 {
257     CAutoLock l(&m_lock);
258 
259     if (!pgf || !m_outFrameBuf || !pdata || data_size < 0 || (data_size & (sizeof(short) - 1)))
260         return -1;
261 
262     // some data left in the buffer, shift to start
263     if (m_outReadOffset > 0)
264     {
265         if (m_outOffset > m_outReadOffset)
266             memmove(m_outFrameBuf, m_outFrameBuf + m_outReadOffset, m_outOffset - m_outReadOffset);
267 
268         m_outOffset -= m_outReadOffset;
269     }
270 
271     m_outReadOffset = 0;
272 
273 
274 
275     m_bFinished = FALSE;
276 
277     int bytes_processed = 0;
278     int const nch = lame_get_num_channels(pgf);
279 
280     while (1)
281     {
282         int nsamples = (data_size - bytes_processed) / (sizeof(short) * nch);
283 
284         if (nsamples <= 0)
285             break;
286 
287         if (nsamples > 1152)
288             nsamples = 1152;
289 
290         if (m_outOffset >= OUT_BUFFER_MAX)
291             break;
292 
293         int out_bytes = 0;
294 
295         if (nch == 2)
296             out_bytes = lame_encode_buffer_interleaved(
297                                             pgf,
298                                             (short *)(pdata + (bytes_processed / sizeof(short))),
299                                             nsamples,
300                                             m_outFrameBuf + m_outOffset,
301                                             OUT_BUFFER_SIZE - m_outOffset);
302         else
303             out_bytes = lame_encode_buffer(
304                                             pgf,
305                                             pdata + (bytes_processed / sizeof(short)),
306                                             pdata + (bytes_processed / sizeof(short)),
307                                             nsamples,
308                                             m_outFrameBuf + m_outOffset,
309                                             OUT_BUFFER_SIZE - m_outOffset);
310 
311         if (out_bytes < 0)
312             return -1;
313 
314         m_outOffset     += out_bytes;
315         bytes_processed += nsamples * nch * sizeof(short);
316     }
317 
318     return bytes_processed;
319 }
320 
321 //
322 // Finsh - flush the buffered samples
323 //
Finish()324 HRESULT CEncoder::Finish()
325 {
326     CAutoLock l(&m_lock);
327 
328     if (!pgf || !m_outFrameBuf || (m_outOffset >= OUT_BUFFER_MAX))
329         return E_FAIL;
330 
331     m_outOffset += lame_encode_flush(pgf, m_outFrameBuf + m_outOffset, OUT_BUFFER_SIZE - m_outOffset);
332 
333     m_bFinished = TRUE;
334 
335     return S_OK;
336 }
337 
338 
getFrameLength(const unsigned char * pdata)339 int getFrameLength(const unsigned char * pdata)
340 {
341     if (!pdata || pdata[0] != 0xff || (pdata[1] & 0xe0) != 0xe0)
342         return -1;
343 
344     const int sample_rate_tab[4][4] =
345     {
346         {11025,12000,8000,1},
347         {1,1,1,1},
348         {22050,24000,16000,1},
349         {44100,48000,32000,1}
350     };
351 
352 #define MPEG_VERSION_RESERVED   1
353 #define MPEG_VERSION_1          3
354 
355 #define LAYER_III               1
356 
357 #define BITRATE_FREE            0
358 #define BITRATE_RESERVED        15
359 
360 #define SRATE_RESERVED          3
361 
362 #define EMPHASIS_RESERVED       2
363 
364     int version_id      = (pdata[1] & 0x18) >> 3;
365     int layer           = (pdata[1] & 0x06) >> 1;
366     int bitrate_id      = (pdata[2] & 0xF0) >> 4;
367     int sample_rate_id  = (pdata[2] & 0x0C) >> 2;
368     int padding         = (pdata[2] & 0x02) >> 1;
369     int emphasis        =  pdata[3] & 0x03;
370 
371     if (version_id      != MPEG_VERSION_RESERVED &&
372         layer           == LAYER_III &&
373         bitrate_id      != BITRATE_FREE &&
374         bitrate_id      != BITRATE_RESERVED &&
375         sample_rate_id  != SRATE_RESERVED &&
376         emphasis        != EMPHASIS_RESERVED)
377     {
378         int spf         = (version_id == MPEG_VERSION_1) ? 1152 : 576;
379         int sample_rate = sample_rate_tab[version_id][sample_rate_id];
380         int bitrate     = dwBitRateValue[version_id != MPEG_VERSION_1][bitrate_id - 1] * 1000;
381 
382         return (bitrate * spf) / (8 * sample_rate) + padding;
383     }
384 
385     return -1;
386 }
387 
388 
GetFrame(const unsigned char ** pframe)389 int CEncoder::GetFrame(const unsigned char ** pframe)
390 {
391     if (!pgf || !m_outFrameBuf || !pframe)
392         return -1;
393 
394 	while ((m_outOffset - m_outReadOffset) > 4)
395     {
396         int frame_length = getFrameLength(m_outFrameBuf + m_outReadOffset);
397 
398         if (frame_length < 0)
399         {
400             m_outReadOffset++;
401         }
402         else if (frame_length <= (m_outOffset - m_outReadOffset))
403         {
404             *pframe = m_outFrameBuf + m_outReadOffset;
405             m_outReadOffset += frame_length;
406 
407             m_frameCount++;
408 
409             // don't deliver the first and the last frames
410             if (m_frameCount != 1 && !(m_bFinished && (m_outOffset - m_outReadOffset) < 5))
411                 return frame_length;
412         }
413         else
414             break;
415     }
416 
417     return 0;
418 }
419 
420 ////////////////////////////////////////////////////////////////////////////////
421 // Returns block of a mp3 file, witch size integer multiples of cbAlign
422 // or not aligned if finished
423 ////////////////////////////////////////////////////////////////////////////////
GetBlockAligned(const unsigned char ** pblock,int * piBufferSize,const long & cbAlign)424 int CEncoder::GetBlockAligned(const unsigned char ** pblock, int* piBufferSize, const long& cbAlign)
425 {
426 	ASSERT(piBufferSize);
427     if (!pgf || !m_outFrameBuf || !pblock)
428         return -1;
429 
430 	int iBlockLen = m_outOffset - m_outReadOffset;
431 	ASSERT(iBlockLen >= 0);
432 
433 	if(!m_bFinished)
434 	{
435 		if(cbAlign > 0)
436 			iBlockLen-=iBlockLen%cbAlign;
437 		*piBufferSize = iBlockLen;
438 	}
439 	else
440 	{
441 		if(cbAlign && iBlockLen%cbAlign)
442 		{
443 			*piBufferSize = iBlockLen + cbAlign - iBlockLen%cbAlign;
444 		}
445 		else
446 		{
447 			*piBufferSize = iBlockLen;
448 		}
449 	}
450 
451 	if(iBlockLen) {
452 		*pblock = m_outFrameBuf + m_outReadOffset;
453 		m_outReadOffset+=iBlockLen;
454 	}
455 
456 	return iBlockLen;
457 }
458 
maybeSyncWord(IStream * pStream)459 HRESULT CEncoder::maybeSyncWord(IStream *pStream)
460 {
461 	HRESULT hr = S_OK;
462     unsigned char mp3_frame_header[4];
463 	ULONG nbytes;
464 	if(FAILED(hr = pStream->Read(mp3_frame_header, sizeof(mp3_frame_header), &nbytes)))
465 		return hr;
466 
467     if ( nbytes != sizeof(mp3_frame_header) ) {
468         return E_FAIL;
469     }
470     if ( mp3_frame_header[0] != 0xffu ) {
471         return S_FALSE; /* doesn't look like a sync word */
472     }
473     if ( (mp3_frame_header[1] & 0xE0u) != 0xE0u ) {
474 		return S_FALSE; /* doesn't look like a sync word */
475     }
476     return S_OK;
477 }
478 
skipId3v2(IStream * pStream,size_t lametag_frame_size)479 HRESULT CEncoder::skipId3v2(IStream *pStream, size_t lametag_frame_size)
480 {
481 	HRESULT hr = S_OK;
482     ULONG  nbytes;
483     size_t  id3v2TagSize = 0;
484     unsigned char id3v2Header[10];
485 	LARGE_INTEGER seekTo;
486 
487     /* seek to the beginning of the stream */
488 	seekTo.QuadPart = 0;
489 	if (FAILED(hr = pStream->Seek(seekTo,  STREAM_SEEK_SET, NULL))) {
490         return hr;  /* not seekable, abort */
491     }
492     /* read 10 bytes in case there's an ID3 version 2 header here */
493 	hr = pStream->Read(id3v2Header, sizeof(id3v2Header), &nbytes);
494     if (FAILED(hr))
495 		return hr;
496 	if(nbytes != sizeof(id3v2Header)) {
497         return E_FAIL;  /* not readable, maybe opened Write-Only */
498     }
499     /* does the stream begin with the ID3 version 2 file identifier? */
500     if (!strncmp((char *) id3v2Header, "ID3", 3)) {
501         /* the tag size (minus the 10-byte header) is encoded into four
502         * bytes where the most significant bit is clear in each byte
503         */
504         id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21)
505             | ((id3v2Header[7] & 0x7f) << 14)
506             | ((id3v2Header[8] & 0x7f) << 7)
507             | (id3v2Header[9] & 0x7f))
508             + sizeof id3v2Header;
509     }
510     /* Seek to the beginning of the audio stream */
511 	seekTo.QuadPart = id3v2TagSize;
512 	if (FAILED(hr = pStream->Seek(seekTo, STREAM_SEEK_SET, NULL))) {
513         return hr;
514     }
515     if (S_OK != (hr = maybeSyncWord(pStream))) {
516 		return SUCCEEDED(hr)?E_FAIL:hr;
517     }
518 	seekTo.QuadPart = id3v2TagSize+lametag_frame_size;
519 	if (FAILED(hr = pStream->Seek(seekTo, STREAM_SEEK_SET, NULL))) {
520         return hr;
521     }
522     if (S_OK != (hr = maybeSyncWord(pStream))) {
523         return SUCCEEDED(hr)?E_FAIL:hr;
524     }
525     /* OK, it seems we found our LAME-Tag/Xing frame again */
526     /* Seek to the beginning of the audio stream */
527 	seekTo.QuadPart = id3v2TagSize;
528 	if (FAILED(hr = pStream->Seek(seekTo, STREAM_SEEK_SET, NULL))) {
529         return hr;
530     }
531     return S_OK;
532 }
533 
534 // Updates VBR tag
updateLameTagFrame(IStream * pStream)535 HRESULT CEncoder::updateLameTagFrame(IStream* pStream)
536 {
537 	HRESULT hr = S_OK;
538 	size_t n = lame_get_lametag_frame( pgf, 0, 0 ); /* ask for bufer size */
539 
540     if ( n > 0 )
541     {
542         unsigned char* buffer = 0;
543         ULONG m = n;
544 
545         if ( FAILED(hr = skipId3v2(pStream, n) ))
546         {
547             /*DispErr( "Error updating LAME-tag frame:\n\n"
548                      "can't locate old frame\n" );*/
549             return hr;
550         }
551 
552         buffer = (unsigned char*)malloc( n );
553 
554         if ( buffer == 0 )
555         {
556             /*DispErr( "Error updating LAME-tag frame:\n\n"
557                      "can't allocate frame buffer\n" );*/
558             return E_OUTOFMEMORY;
559         }
560 
561         /* Put it all to disk again */
562         n = lame_get_lametag_frame( pgf, buffer, n );
563         if ( n > 0 )
564         {
565 			hr = pStream->Write(buffer, n, &m);
566         }
567         free( buffer );
568 
569         if ( m != n )
570         {
571             /*DispErr( "Error updating LAME-tag frame:\n\n"
572                      "couldn't write frame into file\n" );*/
573 			return E_FAIL;
574         }
575     }
576     return hr;
577 }
578