1 /*
2  *  LAME MP3 encoder for DirectShow
3  *  DirectShow filter implementation
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 <olectl.h>
25 #include <initguid.h>
26 //#include <olectlid.h>
27 #include "uids.h"
28 #include "iaudioprops.h"
29 #include "mpegac.h"
30 #include "resource.h"
31 
32 #include "PropPage.h"
33 #include "PropPage_adv.h"
34 #include "aboutprp.h"
35 
36 #include "Encoder.h"
37 #include "Reg.h"
38 
39 #ifndef _INC_MMREG
40 #include <mmreg.h>
41 #endif
42 
43 // default parameters
44 #define         DEFAULT_LAYER               3
45 #define         DEFAULT_STEREO_MODE         JOINT_STEREO
46 #define         DEFAULT_FORCE_MS            0
47 #define         DEFAULT_MODE_FIXED          0
48 #define         DEFAULT_ENFORCE_MIN         0
49 #define         DEFAULT_VOICE               0
50 #define         DEFAULT_KEEP_ALL_FREQ       0
51 #define         DEFAULT_STRICT_ISO          0
52 #define         DEFAULT_DISABLE_SHORT_BLOCK 0
53 #define         DEFAULT_XING_TAG            0
54 #define         DEFAULT_SAMPLE_RATE         44100
55 #define         DEFAULT_BITRATE             128
56 #define         DEFAULT_VARIABLE            0
57 #define         DEFAULT_CRC                 0
58 #define         DEFAULT_FORCE_MONO          0
59 #define         DEFAULT_SET_DURATION        1
60 #define         DEFAULT_SAMPLE_OVERLAP      1
61 #define         DEFAULT_COPYRIGHT           0
62 #define         DEFAULT_ORIGINAL            0
63 #define         DEFAULT_VARIABLEMIN         80
64 #define         DEFAULT_VARIABLEMAX         160
65 #define         DEFAULT_ENCODING_QUALITY    5
66 #define         DEFAULT_VBR_QUALITY         4
67 #define         DEFAULT_PES                 0
68 
69 #define         DEFAULT_FILTER_MERIT        MERIT_DO_NOT_USE                // Standard compressor merit value
70 
71 #define GET_DATARATE(kbps) (kbps * 1000 / 8)
72 #define GET_FRAMELENGTH(bitrate, sample_rate) ((WORD)(((sample_rate < 32000 ? 72000 : 144000) * (bitrate))/(sample_rate)))
73 #define DECLARE_PTR(type, ptr, expr) type* ptr = (type*)(expr);
74 
75 // Create a list of all (or mostly all) of the encoder CBR output capabilities which
76 // will be parsed into a list of capabilities used by the IAMStreamConfig Interface
77 output_caps_t OutputCapabilities[] =
78 { // {SampleRate, BitRate}
79     { 48000, 320 },{ 48000, 256 },{ 48000, 224 },{ 48000, 192 },            // MPEG 1.0 Spec @ 48KHz
80     { 48000, 160 },{ 48000, 128 },{ 48000, 112 },{ 48000, 96 },
81     { 48000, 80 },{ 48000, 64 },{ 48000, 56 },{ 48000, 48 },
82     { 48000, 40 },{ 48000, 32 },
83 
84     { 24000, 160 },{ 24000, 144 },{ 24000, 128 },{ 24000, 112 },            // MPEG 2.0 Spec @ 24KHz
85     { 24000, 96 },{ 24000, 80 },{ 24000, 64 },{ 24000, 56 },
86     { 24000, 48 },{ 24000, 40 },{ 24000, 32 },{ 24000, 24 },
87     { 24000, 16 },{ 24000, 8 },
88 
89     { 12000, 64 },{ 12000, 56 },{ 12000, 48 },{ 12000, 40 },                // MPEG 2.5 Spec @ 12KHz
90     { 12000, 32 },{ 12000, 24 },{ 12000, 16 },{ 12000, 8 },
91     // ---------------------------                                          --------------------------
92     { 44100, 320 },{ 44100, 256 },{ 44100, 224 },{ 44100, 192 },            // MPEG 1.0 Spec @ 44.1KHz
93     { 44100, 160 },{ 44100, 128 },{ 44100, 112 },{ 44100, 96 },
94     { 44100, 80 },{ 44100, 64 },{ 44100, 56 },{ 44100, 48 },
95     { 44100, 40 },{ 44100, 32 },
96 
97     { 22050, 160 },{ 22050, 144 },{ 22050, 128 },{ 22050, 112 },            // MPEG 2.0 Spec @ 22.05KHz
98     { 22050, 96 },{ 22050, 80 },{ 22050, 64 },{ 22050, 56 },
99     { 22050, 48 },{ 22050, 40 },{ 22050, 32 },{ 22050, 24 },
100     { 22050, 16 },{ 22050, 8 },
101 
102     { 11025, 64 },{ 11025, 56 },{ 11025, 48 },{ 11025, 40 },                // MPEG 2.5 Spec @ 11.025KHz
103     { 11025, 32 },{ 11025, 24 },{ 11025, 16 },{ 11025, 8 },
104     // ---------------------------                                          --------------------------
105     { 32000, 320 },{ 32000, 256 },{ 32000, 224 },{ 32000, 192 },            // MPEG 1.0 Spec @ 32KHz
106     { 32000, 160 },{ 32000, 128 },{ 32000, 112 },{ 32000, 96 },
107     { 32000, 80 },{ 32000, 64 },{ 32000, 56 },{ 32000, 48 },
108     { 32000, 40 },{ 32000, 32 },
109 
110     { 16000, 160 },{ 16000, 144 },{ 16000, 128 },{ 16000, 112 },            // MPEG 2.0 Spec @ 16KHz
111     { 16000, 96 },{ 16000, 80 },{ 16000, 64 },{ 16000, 56 },
112     { 16000, 48 },{ 16000, 40 },{ 16000, 32 },{ 16000, 24 },
113     { 16000, 16 },{ 16000, 8 },
114 
115     { 8000, 64 },{ 8000, 56 },{ 8000, 48 },{ 8000, 40 },                    // MPEG 2.5 Spec @ 8KHz
116     { 8000, 32 },{ 8000, 24 },{ 8000, 16 },{ 8000, 8 }
117 };
118 
119 
120 /*  Registration setup stuff */
121 //  Setup data
122 
123 
124 AMOVIESETUP_MEDIATYPE sudMpgInputType[] =
125 {
126     { &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM }
127 };
128 AMOVIESETUP_MEDIATYPE sudMpgOutputType[] =
129 {
130     { &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1AudioPayload },
131     { &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG2_AUDIO },
132     { &MEDIATYPE_Audio, &MEDIASUBTYPE_MP3 },
133     { &MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1Audio }
134 };
135 
136 AMOVIESETUP_PIN sudMpgPins[] =
137 {
138     { L"PCM Input",
139       FALSE,                               // bRendered
140       FALSE,                               // bOutput
141       FALSE,                               // bZero
142       FALSE,                               // bMany
143       &CLSID_NULL,                         // clsConnectsToFilter
144       NULL,                                // ConnectsToPin
145       NUMELMS(sudMpgInputType),            // Number of media types
146       sudMpgInputType
147     },
148     { L"MPEG Output",
149       FALSE,                               // bRendered
150       TRUE,                                // bOutput
151       FALSE,                               // bZero
152       FALSE,                               // bMany
153       &CLSID_NULL,                         // clsConnectsToFilter
154       NULL,                                // ConnectsToPin
155       NUMELMS(sudMpgOutputType),           // Number of media types
156       sudMpgOutputType
157     }
158 };
159 
160 AMOVIESETUP_FILTER sudMpgAEnc =
161 {
162 	&CLSID_LAMEDShowFilter,
163     L"LAME Audio Encoder",
164     DEFAULT_FILTER_MERIT,                  // Standard compressor merit value
165     NUMELMS(sudMpgPins),                   // 2 pins
166     sudMpgPins
167 };
168 
169 /*****************************************************************************/
170 // COM Global table of objects in this dll
171 static WCHAR g_wszName[] = L"LAME Audio Encoder";
172 CFactoryTemplate g_Templates[] =
173 {
174   { g_wszName, &CLSID_LAMEDShowFilter, CMpegAudEnc::CreateInstance, NULL, &sudMpgAEnc },
175   { L"LAME Audio Encoder Property Page", &CLSID_LAMEDShow_PropertyPage, CMpegAudEncPropertyPage::CreateInstance},
176   { L"LAME Audio Encoder Property Page", &CLSID_LAMEDShow_PropertyPageAdv, CMpegAudEncPropertyPageAdv::CreateInstance},
177   { L"LAME Audio Encoder About", &CLSID_LAMEDShow_About, CMAEAbout::CreateInstance}
178 };
179 // Count of objects listed in g_cTemplates
180 int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
181 
182 
183 
184 ////////////////////////////////////////////
185 // Declare the DirectShow filter information.
186 
187 // Used by IFilterMapper2() in the call to DllRegisterServer()
188 // to register the filter in the CLSID_AudioCompressorCategory.
189 REGFILTER2 rf2FilterReg = {
190     1,                     // Version number.
191     DEFAULT_FILTER_MERIT,  // Merit. This should match the merit specified in the AMOVIESETUP_FILTER definition
192     NUMELMS(sudMpgPins),   // Number of pins.
193     sudMpgPins             // Pointer to pin information.
194 };
195 
DllRegisterServer(void)196 STDAPI DllRegisterServer(void)
197 {
198     HRESULT hr = AMovieDllRegisterServer2(TRUE);
199     if (FAILED(hr)) {
200         return hr;
201     }
202 
203     IFilterMapper2 *pFM2 = NULL;
204     hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, IID_IFilterMapper2, (void **)&pFM2);
205     if (SUCCEEDED(hr)) {
206         hr = pFM2->RegisterFilter(
207             CLSID_LAMEDShowFilter,           // Filter CLSID.
208             g_wszName,                       // Filter name.
209             NULL,                            // Device moniker.
210             &CLSID_AudioCompressorCategory,  // Audio compressor category.
211             g_wszName,                       // Instance data.
212             &rf2FilterReg                    // Filter information.
213             );
214         pFM2->Release();
215     }
216     return hr;
217 }
218 
DllUnregisterServer()219 STDAPI DllUnregisterServer()
220 {
221     HRESULT hr = AMovieDllRegisterServer2(FALSE);
222     if (FAILED(hr)) {
223         return hr;
224     }
225 
226     IFilterMapper2 *pFM2 = NULL;
227     hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, IID_IFilterMapper2, (void **)&pFM2);
228     if (SUCCEEDED(hr)) {
229         hr = pFM2->UnregisterFilter(&CLSID_AudioCompressorCategory, g_wszName, CLSID_LAMEDShowFilter);
230         pFM2->Release();
231     }
232     return hr;
233 }
234 
235 
236 
CreateInstance(LPUNKNOWN lpunk,HRESULT * phr)237 CUnknown *CMpegAudEnc::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)
238 {
239     CMpegAudEnc *punk = new CMpegAudEnc(lpunk, phr);
240     if (punk == NULL)
241         *phr = E_OUTOFMEMORY;
242     return punk;
243 }
244 
CMpegAudEnc(LPUNKNOWN lpunk,HRESULT * phr)245 CMpegAudEnc::CMpegAudEnc(LPUNKNOWN lpunk, HRESULT *phr)
246  :  CTransformFilter(NAME("LAME Audio Encoder"), lpunk, CLSID_LAMEDShowFilter),
247     CPersistStream(lpunk, phr)
248 {
249     // ENCODER OUTPUT PIN
250     // Override the output pin with our own which will implement the IAMStreamConfig Interface
251     CTransformOutputPin *pOut = new CMpegAudEncOutPin( this, phr );
252     if (pOut == NULL) {
253         *phr = E_OUTOFMEMORY;
254         return;
255     }
256     else if (FAILED(*phr)) {             // A failed return code should delete the object
257         delete pOut;
258         return;
259     }
260     m_pOutput = pOut;
261 
262     // ENCODER INPUT PIN
263     // Since we've created our own output pin we must also create
264     // the input pin ourselves because the CTransformFilter base class
265     // will create an extra output pin if the input pin wasn't created.
266     CTransformInputPin *pIn = new CTransformInputPin(NAME("LameEncoderInputPin"),
267                                                      this,              // Owner filter
268                                                      phr,               // Result code
269                                                      L"Input");         // Pin name
270 
271     if (pIn == NULL) {
272         *phr = E_OUTOFMEMORY;
273         return;
274     }
275     else if (FAILED(*phr)) {             // A failed return code should delete the object
276         delete pIn;
277         return;
278     }
279     m_pInput = pIn;
280 
281 
282     MPEG_ENCODER_CONFIG mec;
283     ReadPresetSettings(&mec);
284     m_Encoder.SetOutputType(mec);
285 
286     m_CapsNum = 0;
287     m_hasFinished = TRUE;
288     m_bStreamOutput = FALSE;
289     m_currentMediaTypeIndex = 0;
290 }
291 
~CMpegAudEnc(void)292 CMpegAudEnc::~CMpegAudEnc(void)
293 {
294 }
295 
GetSetupData()296 LPAMOVIESETUP_FILTER CMpegAudEnc::GetSetupData()
297 {
298     return &sudMpgAEnc;
299 }
300 
301 
Receive(IMediaSample * pSample)302 HRESULT CMpegAudEnc::Receive(IMediaSample * pSample)
303 {
304     CAutoLock lock(&m_cs);
305 
306     if (!pSample)
307         return S_OK;
308 
309     BYTE * pSourceBuffer = NULL;
310 
311     if (pSample->GetPointer(&pSourceBuffer) != S_OK || !pSourceBuffer)
312         return S_OK;
313 
314     long sample_size = pSample->GetActualDataLength();
315 
316     REFERENCE_TIME rtStart, rtStop;
317     BOOL gotValidTime = (pSample->GetTime(&rtStart, &rtStop) != VFW_E_SAMPLE_TIME_NOT_SET);
318 
319     if (sample_size <= 0 || pSourceBuffer == NULL || m_hasFinished || (gotValidTime && rtStart < 0))
320         return S_OK;
321 
322     if (gotValidTime)
323     {
324         if (m_rtStreamTime < 0)
325         {
326             m_rtStreamTime = rtStart;
327             m_rtEstimated = rtStart;
328         }
329         else
330         {
331             resync_point_t * sync = m_sync + m_sync_in_idx;
332 
333             if (sync->applied)
334             {
335                 REFERENCE_TIME rtGap = rtStart - m_rtEstimated;
336 
337                 // if old sync data is applied and gap is greater than 1 ms
338                 // then make a new synchronization point
339                 if (rtGap > 10000 || (m_allowOverlap && rtGap < -10000))
340                 {
341                     sync->sample    = m_samplesIn;
342                     sync->delta     = rtGap;
343                     sync->applied   = FALSE;
344 
345                     m_rtEstimated  += sync->delta;
346 
347                     if (m_sync_in_idx < (RESYNC_COUNT - 1))
348                         m_sync_in_idx++;
349                     else
350                         m_sync_in_idx = 0;
351                 }
352             }
353         }
354     }
355 
356     m_rtEstimated   += (LONGLONG)(m_bytesToDuration * sample_size);
357     m_samplesIn     += sample_size / m_bytesPerSample;
358 
359     while (sample_size > 0)
360     {
361         int bytes_processed = m_Encoder.Encode((short *)pSourceBuffer, sample_size);
362 
363         if (bytes_processed <= 0)
364             return S_OK;
365 
366         FlushEncodedSamples();
367 
368         sample_size     -= bytes_processed;
369         pSourceBuffer   += bytes_processed;
370     }
371 
372     return S_OK;
373 }
374 
375 
376 
377 
FlushEncodedSamples()378 HRESULT CMpegAudEnc::FlushEncodedSamples()
379 {
380     IMediaSample * pOutSample = NULL;
381     BYTE * pDst = NULL;
382 
383 	if(m_bStreamOutput)
384 	{
385 		HRESULT hr = S_OK;
386 		const unsigned char *   pblock      = NULL;
387 		int iBufferSize;
388 		int iBlockLength = m_Encoder.GetBlockAligned(&pblock, &iBufferSize, m_cbStreamAlignment);
389 
390 		if(!iBlockLength)
391 			return S_OK;
392 
393 		hr = m_pOutput->GetDeliveryBuffer(&pOutSample, NULL, NULL, 0);
394 		if (hr == S_OK && pOutSample)
395 		{
396 			hr = pOutSample->GetPointer(&pDst);
397 			if (hr == S_OK && pDst)
398 			{
399 				CopyMemory(pDst, pblock, iBlockLength);
400 				REFERENCE_TIME rtEndPos = m_rtBytePos + iBufferSize;
401 				EXECUTE_ASSERT(S_OK == pOutSample->SetTime(&m_rtBytePos, &rtEndPos));
402 				pOutSample->SetActualDataLength(iBufferSize);
403 				m_rtBytePos += iBlockLength;
404 				m_pOutput->Deliver(pOutSample);
405 			}
406 
407 			pOutSample->Release();
408 		}
409 		return S_OK;
410 	}
411 
412     if (m_rtStreamTime < 0)
413         m_rtStreamTime = 0;
414 
415     while (1)
416     {
417         const unsigned char *   pframe      = NULL;
418         int                     frame_size  = m_Encoder.GetFrame(&pframe);
419 
420         if (frame_size <= 0 || !pframe)
421             break;
422 
423         if (!m_sync[m_sync_out_idx].applied && m_sync[m_sync_out_idx].sample <= m_samplesOut)
424         {
425             m_rtStreamTime += m_sync[m_sync_out_idx].delta;
426             m_sync[m_sync_out_idx].applied = TRUE;
427 
428             if (m_sync_out_idx < (RESYNC_COUNT - 1))
429                 m_sync_out_idx++;
430             else
431                 m_sync_out_idx = 0;
432         }
433 
434         REFERENCE_TIME rtStart = m_rtStreamTime;
435         REFERENCE_TIME rtStop = rtStart + m_rtFrameTime;
436 
437 		HRESULT hr = S_OK;
438 
439 		hr = m_pOutput->GetDeliveryBuffer(&pOutSample, NULL, NULL, 0);
440 		if (hr == S_OK && pOutSample)
441 		{
442 			hr = pOutSample->GetPointer(&pDst);
443 			if (hr == S_OK && pDst)
444 			{
445 				CopyMemory(pDst, pframe, frame_size);
446 				pOutSample->SetActualDataLength(frame_size);
447 
448 				pOutSample->SetSyncPoint(TRUE);
449 				pOutSample->SetTime(&rtStart, m_setDuration ? &rtStop : NULL);
450 
451 
452 				m_pOutput->Deliver(pOutSample);
453 			}
454 
455 			pOutSample->Release();
456 		}
457 
458 
459         m_samplesOut += m_samplesPerFrame;
460         m_rtStreamTime = rtStop;
461     }
462 
463     return S_OK;
464 }
465 
466 
467 ////////////////////////////////////////////////////////////////////////////
468 //  StartStreaming - prepare to receive new data
469 ////////////////////////////////////////////////////////////////////////////
StartStreaming()470 HRESULT CMpegAudEnc::StartStreaming()
471 {
472     WAVEFORMATEX * pwfxIn  = (WAVEFORMATEX *) m_pInput->CurrentMediaType().Format();
473 
474     m_bytesPerSample    = pwfxIn->nChannels * sizeof(short);
475 	DWORD dwOutSampleRate;
476 	if(MEDIATYPE_Stream == m_pOutput->CurrentMediaType().majortype)
477 	{
478 		MPEG_ENCODER_CONFIG mcfg;
479 		if(FAILED(m_Encoder.GetOutputType(&mcfg)))
480 			return E_FAIL;
481 
482 		dwOutSampleRate = mcfg.dwSampleRate;
483 	}
484 	else
485 	{
486 		dwOutSampleRate = ((WAVEFORMATEX *) m_pOutput->CurrentMediaType().Format())->nSamplesPerSec;
487 	}
488 	m_samplesPerFrame   = (dwOutSampleRate >= 32000) ? 1152 : 576;
489 
490     m_rtFrameTime = MulDiv(10000000, m_samplesPerFrame, dwOutSampleRate);
491 
492     m_samplesIn = m_samplesOut = 0;
493     m_rtStreamTime = -1;
494 	m_rtBytePos = 0;
495 
496     // initialize encoder
497     m_Encoder.Init();
498 
499     m_hasFinished   = FALSE;
500 
501     for (int i = 0; i < RESYNC_COUNT; i++)
502     {
503         m_sync[i].sample   = 0;
504         m_sync[i].delta    = 0;
505         m_sync[i].applied  = TRUE;
506     }
507 
508     m_sync_in_idx = 0;
509     m_sync_out_idx = 0;
510 
511     get_SetDuration(&m_setDuration);
512     get_SampleOverlap(&m_allowOverlap);
513 
514 	return S_OK;
515 }
516 
517 
StopStreaming()518 HRESULT CMpegAudEnc::StopStreaming()
519 {
520 	IStream *pStream = NULL;
521 	if(m_bStreamOutput && m_pOutput->IsConnected() != FALSE)
522 	{
523 		IPin * pDwnstrmInputPin = m_pOutput->GetConnected();
524 		if(pDwnstrmInputPin && FAILED(pDwnstrmInputPin->QueryInterface(IID_IStream, (LPVOID*)(&pStream))))
525 		{
526 			pStream = NULL;
527 		}
528 	}
529 
530 
531 	m_Encoder.Close(pStream);
532 
533 	if(pStream)
534 		pStream->Release();
535 
536     return S_OK;
537 }
538 
539 
540 ////////////////////////////////////////////////////////////////////////////
541 //  EndOfStream - stop data processing
542 ////////////////////////////////////////////////////////////////////////////
EndOfStream()543 HRESULT CMpegAudEnc::EndOfStream()
544 {
545     CAutoLock lock(&m_cs);
546 
547     // Flush data
548     m_Encoder.Finish();
549     FlushEncodedSamples();
550 
551 	IStream *pStream = NULL;
552     if(m_bStreamOutput && m_pOutput->IsConnected() != FALSE)
553 	{
554 		IPin * pDwnstrmInputPin = m_pOutput->GetConnected();
555 		if(pDwnstrmInputPin)
556 		{
557 			if(FAILED(pDwnstrmInputPin->QueryInterface(IID_IStream, (LPVOID*)(&pStream))))
558 			{
559 				pStream = NULL;
560 			}
561 		}
562 	}
563 
564 	if(pStream)
565 	{
566 		ULARGE_INTEGER size;
567 		size.QuadPart = m_rtBytePos;
568 		pStream->SetSize(size);
569 	}
570 
571 	m_Encoder.Close(pStream);
572 
573 	if(pStream)
574 		pStream->Release();
575 
576     m_hasFinished = TRUE;
577 
578     return CTransformFilter::EndOfStream();
579 }
580 
581 
582 ////////////////////////////////////////////////////////////////////////////
583 //  BeginFlush  - stop data processing
584 ////////////////////////////////////////////////////////////////////////////
BeginFlush()585 HRESULT CMpegAudEnc::BeginFlush()
586 {
587     HRESULT hr = CTransformFilter::BeginFlush();
588 
589     if (SUCCEEDED(hr))
590     {
591         CAutoLock lock(&m_cs);
592 
593         DWORD dwDstSize = 0;
594 
595         // Flush data
596         m_Encoder.Finish();
597         FlushEncodedSamples();
598 
599 		IStream *pStream = NULL;
600 		if(m_bStreamOutput && m_pOutput->IsConnected() != FALSE)
601 		{
602 			IPin * pDwnstrmInputPin = m_pOutput->GetConnected();
603 			if(pDwnstrmInputPin && SUCCEEDED(pDwnstrmInputPin->QueryInterface(IID_IStream, (LPVOID*)(&pStream))))
604 			{
605 				ULARGE_INTEGER size;
606 				size.QuadPart = m_rtBytePos;
607 				pStream->SetSize(size);
608 				pStream->Release();
609 			}
610 		}
611 	    m_rtStreamTime = -1;
612 		m_rtBytePos = 0;
613     }
614 
615     return hr;
616 }
617 
618 
619 
620 ////////////////////////////////////////////////////////////////////////////
621 //	SetMediaType - called when filters are connecting
622 ////////////////////////////////////////////////////////////////////////////
SetMediaType(PIN_DIRECTION direction,const CMediaType * pmt)623 HRESULT CMpegAudEnc::SetMediaType(PIN_DIRECTION direction, const CMediaType * pmt)
624 {
625     HRESULT hr = S_OK;
626 
627     if (direction == PINDIR_INPUT)
628     {
629 		if (*pmt->FormatType() != FORMAT_WaveFormatEx)
630         return VFW_E_INVALIDMEDIATYPE;
631 
632 		if (pmt->FormatLength() < sizeof(WAVEFORMATEX))
633 			return VFW_E_INVALIDMEDIATYPE;
634 
635         DbgLog((LOG_TRACE,1,TEXT("CMpegAudEnc::SetMediaType(), direction = PINDIR_INPUT")));
636 
637         // Pass input media type to encoder
638         m_Encoder.SetInputType((LPWAVEFORMATEX)pmt->Format());
639 
640         WAVEFORMATEX * pwfx = (WAVEFORMATEX *)pmt->Format();
641 
642         if (pwfx)
643             m_bytesToDuration = (float)1.e7 / (float)(pwfx->nChannels * sizeof(short) * pwfx->nSamplesPerSec);
644         else
645             m_bytesToDuration = 0.0;
646 
647         // Parse the encoder output capabilities into the subset of capabilities that are supported
648         // for the current input format. This listing will be utilized by the IAMStreamConfig Interface.
649         LoadOutputCapabilities(pwfx->nSamplesPerSec);
650 
651         Reconnect();
652     }
653     else if (direction == PINDIR_OUTPUT)
654     {
655         // Before we set the output type, we might need to reconnect
656         // the input pin with a new type.
657         if (m_pInput && m_pInput->IsConnected())
658         {
659             // Check if the current input type is compatible.
660             hr = CheckTransform(&m_pInput->CurrentMediaType(), &m_pOutput->CurrentMediaType());
661             if (FAILED(hr)) {
662                 // We need to reconnect the input pin.
663                 // Note: The CheckMediaType method has already called QueryAccept on the upstream filter.
664                 hr = m_pGraph->Reconnect(m_pInput);
665                 return hr;
666             }
667         }
668 
669 //        WAVEFORMATEX wfIn;
670 //        m_Encoder.GetInputType(&wfIn);
671 
672 //        if (wfIn.nSamplesPerSec %
673 //            ((LPWAVEFORMATEX)pmt->Format())->nSamplesPerSec != 0)
674 //            return VFW_E_TYPE_NOT_ACCEPTED;
675     }
676 
677     return hr;
678 }
679 
680 ////////////////////////////////////////////////////////////////////////////
681 // CheckInputType - check if you can support mtIn
682 ////////////////////////////////////////////////////////////////////////////
CheckInputType(const CMediaType * mtIn)683 HRESULT CMpegAudEnc::CheckInputType(const CMediaType* mtIn)
684 {
685     if (*mtIn->Type() == MEDIATYPE_Audio && *mtIn->FormatType() == FORMAT_WaveFormatEx)
686         if (mtIn->FormatLength() >= sizeof(WAVEFORMATEX))
687             if (mtIn->IsTemporalCompressed() == FALSE)
688                 return m_Encoder.SetInputType((LPWAVEFORMATEX)mtIn->Format(), true);
689 
690     return E_INVALIDARG;
691 }
692 
693 ////////////////////////////////////////////////////////////////////////////
694 // CheckTransform - checks if we can support the transform from this input to this output
695 ////////////////////////////////////////////////////////////////////////////
CheckTransform(const CMediaType * mtIn,const CMediaType * mtOut)696 HRESULT CMpegAudEnc::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
697 {
698 	if(MEDIATYPE_Stream != mtOut->majortype)
699 	{
700 		if (*mtOut->FormatType() != FORMAT_WaveFormatEx)
701 			return VFW_E_INVALIDMEDIATYPE;
702 
703 		if (mtOut->FormatLength() < sizeof(WAVEFORMATEX))
704 			return VFW_E_INVALIDMEDIATYPE;
705 
706 		MPEG_ENCODER_CONFIG	mec;
707 		if(FAILED(m_Encoder.GetOutputType(&mec)))
708 			return S_OK;
709 
710 		if (((LPWAVEFORMATEX)mtIn->Format())->nSamplesPerSec % mec.dwSampleRate != 0)
711 			return S_OK;
712 
713 		if (mec.dwSampleRate != ((LPWAVEFORMATEX)mtOut->Format())->nSamplesPerSec)
714 			return VFW_E_TYPE_NOT_ACCEPTED;
715 
716 		return S_OK;
717 	}
718 	else if(mtOut->subtype == MEDIASUBTYPE_MPEG1Audio)
719 		return S_OK;
720 
721 	return VFW_E_TYPE_NOT_ACCEPTED;
722 }
723 
724 ////////////////////////////////////////////////////////////////////////////
725 // DecideBufferSize - sets output buffers number and size
726 ////////////////////////////////////////////////////////////////////////////
DecideBufferSize(IMemAllocator * pAllocator,ALLOCATOR_PROPERTIES * pProperties)727 HRESULT CMpegAudEnc::DecideBufferSize(
728                         IMemAllocator*		  pAllocator,
729                         ALLOCATOR_PROPERTIES* pProperties)
730 {
731     HRESULT hr = S_OK;
732 
733 	if(m_bStreamOutput)
734 		m_cbStreamAlignment = pProperties->cbAlign;
735 
736     ///
737     if (pProperties->cBuffers == 0) pProperties->cBuffers = 1;  // If downstream filter didn't suggest a buffer count then default to 1
738     pProperties->cbBuffer = OUT_BUFFER_SIZE;
739 	//
740 
741 	ASSERT(pProperties->cbBuffer);
742 
743     ALLOCATOR_PROPERTIES Actual;
744     hr = pAllocator->SetProperties(pProperties,&Actual);
745     if(FAILED(hr))
746         return hr;
747 
748     if (Actual.cbBuffer < pProperties->cbBuffer ||
749         Actual.cBuffers < pProperties->cBuffers)
750     {// can't use this allocator
751         return E_INVALIDARG;
752     }
753     return S_OK;
754 }
755 
756 ////////////////////////////////////////////////////////////////////////////
757 // GetMediaType - overrideable for suggesting output pin media types
758 ////////////////////////////////////////////////////////////////////////////
GetMediaType(int iPosition,CMediaType * pMediaType)759 HRESULT CMpegAudEnc::GetMediaType(int iPosition, CMediaType *pMediaType)
760 {
761     DbgLog((LOG_TRACE,1,TEXT("CMpegAudEnc::GetMediaType()")));
762 
763     return m_pOutput->GetMediaType(iPosition, pMediaType);
764 }
765 
766 ////////////////////////////////////////////////////////////////////////////
767 //  Reconnect - called after a manual change has been made to the
768 //  encoder parameters to reset the filter output media type structure
769 //  to match the current encoder out MPEG audio properties
770 ////////////////////////////////////////////////////////////////////////////
Reconnect()771 HRESULT CMpegAudEnc::Reconnect()
772 {
773     HRESULT hr = S_FALSE;
774 
775     if (m_pOutput && m_pOutput->IsConnected() && m_State == State_Stopped)
776     {
777         MPEG_ENCODER_CONFIG mec;
778         hr = m_Encoder.GetOutputType(&mec);
779 
780         if ((hr = m_Encoder.SetOutputType(mec)) == S_OK)
781         {
782             // Create an updated output MediaType using the current encoder settings
783             CMediaType cmt;
784 			cmt.InitMediaType();
785             m_pOutput->GetMediaType(m_currentMediaTypeIndex, &cmt);
786 
787             // If the updated MediaType matches the current output MediaType no reconnect is needed
788             if (m_pOutput->CurrentMediaType() == cmt) return S_OK;
789 
790             // Attempt to reconnect the output pin using the updated MediaType
791             if (S_OK == (hr = m_pOutput->GetConnected()->QueryAccept(&cmt))) {
792                 hr = m_pOutput->SetMediaType(&cmt);
793                 if ( FAILED(hr) ) { return(hr); }
794 
795                 hr = m_pGraph->Reconnect(m_pOutput);
796             }
797             else
798                 hr = m_pOutput->SetMediaType(&cmt);
799         }
800     }
801 
802     return hr;
803 }
804 
805 ////////////////////////////////////////////////////////////////////////////
806 //  LoadOutputCapabilities - create a list of the currently supported output
807 //  format capabilities which will be used by the IAMStreamConfig Interface
808 ////////////////////////////////////////////////////////////////////////////
LoadOutputCapabilities(DWORD sample_rate)809 void CMpegAudEnc::LoadOutputCapabilities(DWORD sample_rate)
810 {
811     m_CapsNum = 0;
812 
813     // Clear out any existing output capabilities
814     ZeroMemory(OutputCaps, sizeof(OutputCaps));
815 
816     // Create the set of Constant Bit Rate output capabilities that are
817     // supported for the current input pin sampling rate.
818     for (int i = 0;  i < NUMELMS(OutputCapabilities); i++) {
819         if (0 == sample_rate % OutputCapabilities[i].nSampleRate) {
820 
821             // Add this output capability to the OutputCaps list
822             OutputCaps[m_CapsNum] = OutputCapabilities[i];
823             m_CapsNum++;
824 
825             // Don't overrun the hard-coded capabilities array limit
826             if (m_CapsNum > (int)MAX_IAMSTREAMCONFIG_CAPS) break;
827         }
828     }
829 }
830 
831 
832 //
833 // Read persistent configuration from Registry
834 //
ReadPresetSettings(MPEG_ENCODER_CONFIG * pmec)835 void CMpegAudEnc::ReadPresetSettings(MPEG_ENCODER_CONFIG * pmec)
836 {
837     DbgLog((LOG_TRACE,1,TEXT("CMpegAudEnc::ReadPresetSettings()")));
838 
839     Lame::CRegKey rk(HKEY_CURRENT_USER, KEY_LAME_ENCODER);
840 
841     pmec->dwBitrate         = rk.getDWORD(VALUE_BITRATE,DEFAULT_BITRATE);
842     pmec->dwVariableMin     = rk.getDWORD(VALUE_VARIABLEMIN,DEFAULT_VARIABLEMIN);
843     pmec->dwVariableMax     = rk.getDWORD(VALUE_VARIABLEMAX,DEFAULT_VARIABLEMAX);
844     pmec->vmVariable        = rk.getDWORD(VALUE_VARIABLE, DEFAULT_VARIABLE) ? vbr_rh : vbr_off;
845     pmec->dwQuality         = rk.getDWORD(VALUE_QUALITY,DEFAULT_ENCODING_QUALITY);
846     pmec->dwVBRq            = rk.getDWORD(VALUE_VBR_QUALITY,DEFAULT_VBR_QUALITY);
847     pmec->lLayer            = rk.getDWORD(VALUE_LAYER, DEFAULT_LAYER);
848     pmec->bCRCProtect       = rk.getDWORD(VALUE_CRC, DEFAULT_CRC);
849     pmec->bForceMono        = rk.getDWORD(VALUE_FORCE_MONO, DEFAULT_FORCE_MONO);
850     pmec->bSetDuration      = rk.getDWORD(VALUE_SET_DURATION, DEFAULT_SET_DURATION);
851     pmec->bSampleOverlap    = rk.getDWORD(VALUE_SAMPLE_OVERLAP, DEFAULT_SAMPLE_OVERLAP);
852     pmec->bCopyright        = rk.getDWORD(VALUE_COPYRIGHT, DEFAULT_COPYRIGHT);
853     pmec->bOriginal         = rk.getDWORD(VALUE_ORIGINAL, DEFAULT_ORIGINAL);
854     pmec->dwSampleRate      = rk.getDWORD(VALUE_SAMPLE_RATE, DEFAULT_SAMPLE_RATE);
855     pmec->dwPES             = rk.getDWORD(VALUE_PES, DEFAULT_PES);
856 
857     pmec->ChMode            = (MPEG_mode)rk.getDWORD(VALUE_STEREO_MODE, DEFAULT_STEREO_MODE);
858     pmec->dwForceMS         = rk.getDWORD(VALUE_FORCE_MS, DEFAULT_FORCE_MS);
859 
860     pmec->dwEnforceVBRmin   = rk.getDWORD(VALUE_ENFORCE_MIN, DEFAULT_ENFORCE_MIN);
861     pmec->dwVoiceMode       = rk.getDWORD(VALUE_VOICE, DEFAULT_VOICE);
862     pmec->dwKeepAllFreq     = rk.getDWORD(VALUE_KEEP_ALL_FREQ, DEFAULT_KEEP_ALL_FREQ);
863     pmec->dwStrictISO       = rk.getDWORD(VALUE_STRICT_ISO, DEFAULT_STRICT_ISO);
864     pmec->dwNoShortBlock    = rk.getDWORD(VALUE_DISABLE_SHORT_BLOCK, DEFAULT_DISABLE_SHORT_BLOCK);
865     pmec->dwXingTag         = rk.getDWORD(VALUE_XING_TAG, DEFAULT_XING_TAG);
866     pmec->dwModeFixed       = rk.getDWORD(VALUE_MODE_FIXED, DEFAULT_MODE_FIXED);
867 
868     rk.Close();
869 }
870 
871 ////////////////////////////////////////////////////////////////
872 //  Property page handling
873 ////////////////////////////////////////////////////////////////
GetPages(CAUUID * pcauuid)874 HRESULT CMpegAudEnc::GetPages(CAUUID *pcauuid)
875 {
876     GUID *pguid;
877 
878     pcauuid->cElems = 3;
879     pcauuid->pElems = pguid = (GUID *) CoTaskMemAlloc(sizeof(GUID) * pcauuid->cElems);
880 
881     if (pcauuid->pElems == NULL)
882         return E_OUTOFMEMORY;
883 
884     pguid[0] = CLSID_LAMEDShow_PropertyPage;
885     pguid[1] = CLSID_LAMEDShow_PropertyPageAdv;
886     pguid[2] = CLSID_LAMEDShow_About;
887 
888     return S_OK;
889 }
890 
NonDelegatingQueryInterface(REFIID riid,void ** ppv)891 STDMETHODIMP CMpegAudEnc::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
892 {
893 
894     if (riid == IID_ISpecifyPropertyPages)
895         return GetInterface((ISpecifyPropertyPages *) this, ppv);
896 	else if(riid == IID_IPersistStream)
897         return GetInterface((IPersistStream *)this, ppv);
898 //    else if (riid == IID_IVAudioEncSettings)
899 //        return GetInterface((IVAudioEncSettings*) this, ppv);
900     else if (riid == IID_IAudioEncoderProperties)
901         return GetInterface((IAudioEncoderProperties*) this, ppv);
902 
903     return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);
904 }
905 
906 ////////////////////////////////////////////////////////////////
907 //IVAudioEncSettings interface methods
908 ////////////////////////////////////////////////////////////////
909 
910 //
911 // IAudioEncoderProperties
912 //
get_PESOutputEnabled(DWORD * dwEnabled)913 STDMETHODIMP CMpegAudEnc::get_PESOutputEnabled(DWORD *dwEnabled)
914 {
915     *dwEnabled = (DWORD)m_Encoder.IsPES();
916     DbgLog((LOG_TRACE, 1, TEXT("get_PESOutputEnabled -> %d"), *dwEnabled));
917 
918     return S_OK;
919 }
920 
set_PESOutputEnabled(DWORD dwEnabled)921 STDMETHODIMP CMpegAudEnc::set_PESOutputEnabled(DWORD dwEnabled)
922 {
923     m_Encoder.SetPES((BOOL)!!dwEnabled);
924     DbgLog((LOG_TRACE, 1, TEXT("set_PESOutputEnabled(%d)"), !!dwEnabled));
925 
926     return S_OK;
927 }
928 
get_MPEGLayer(DWORD * dwLayer)929 STDMETHODIMP CMpegAudEnc::get_MPEGLayer(DWORD *dwLayer)
930 {
931     MPEG_ENCODER_CONFIG mec;
932     m_Encoder.GetOutputType(&mec);
933     *dwLayer = (DWORD)mec.lLayer;
934 
935     DbgLog((LOG_TRACE, 1, TEXT("get_MPEGLayer -> %d"), *dwLayer));
936     return S_OK;
937 }
938 
set_MPEGLayer(DWORD dwLayer)939 STDMETHODIMP CMpegAudEnc::set_MPEGLayer(DWORD dwLayer)
940 {
941     MPEG_ENCODER_CONFIG mec;
942     m_Encoder.GetOutputType(&mec);
943     if (dwLayer == 2)
944         mec.lLayer = 2;
945     else if (dwLayer == 1)
946         mec.lLayer = 1;
947     m_Encoder.SetOutputType(mec);
948 
949     DbgLog((LOG_TRACE, 1, TEXT("set_MPEGLayer(%d)"), dwLayer));
950     return S_OK;
951 }
952 
get_Bitrate(DWORD * dwBitrate)953 STDMETHODIMP CMpegAudEnc::get_Bitrate(DWORD *dwBitrate)
954 {
955     MPEG_ENCODER_CONFIG mec;
956     m_Encoder.GetOutputType(&mec);
957     *dwBitrate = (DWORD)mec.dwBitrate;
958     DbgLog((LOG_TRACE, 1, TEXT("get_Bitrate -> %d"), *dwBitrate));
959     return S_OK;
960 }
961 
set_Bitrate(DWORD dwBitrate)962 STDMETHODIMP CMpegAudEnc::set_Bitrate(DWORD dwBitrate)
963 {
964     MPEG_ENCODER_CONFIG mec;
965     m_Encoder.GetOutputType(&mec);
966     mec.dwBitrate = dwBitrate;
967     m_Encoder.SetOutputType(mec);
968     DbgLog((LOG_TRACE, 1, TEXT("set_Bitrate(%d)"), dwBitrate));
969     return S_OK;
970 }
971 
get_Variable(DWORD * dwVariable)972 STDMETHODIMP CMpegAudEnc::get_Variable(DWORD *dwVariable)
973 {
974     MPEG_ENCODER_CONFIG mec;
975     m_Encoder.GetOutputType(&mec);
976     *dwVariable = (DWORD)(mec.vmVariable == vbr_off ? 0 : 1);
977     DbgLog((LOG_TRACE, 1, TEXT("get_Variable -> %d"), *dwVariable));
978     return S_OK;
979 }
980 
set_Variable(DWORD dwVariable)981 STDMETHODIMP CMpegAudEnc::set_Variable(DWORD dwVariable)
982 {
983     MPEG_ENCODER_CONFIG mec;
984     m_Encoder.GetOutputType(&mec);
985 
986     mec.vmVariable = dwVariable ? vbr_rh : vbr_off;
987     m_Encoder.SetOutputType(mec);
988     DbgLog((LOG_TRACE, 1, TEXT("set_Variable(%d)"), dwVariable));
989     return S_OK;
990 }
991 
get_VariableMin(DWORD * dwMin)992 STDMETHODIMP CMpegAudEnc::get_VariableMin(DWORD *dwMin)
993 {
994     MPEG_ENCODER_CONFIG mec;
995     m_Encoder.GetOutputType(&mec);
996     *dwMin = (DWORD)mec.dwVariableMin;
997     DbgLog((LOG_TRACE, 1, TEXT("get_Variablemin -> %d"), *dwMin));
998     return S_OK;
999 }
1000 
set_VariableMin(DWORD dwMin)1001 STDMETHODIMP CMpegAudEnc::set_VariableMin(DWORD dwMin)
1002 {
1003     MPEG_ENCODER_CONFIG mec;
1004     m_Encoder.GetOutputType(&mec);
1005     mec.dwVariableMin = dwMin;
1006     m_Encoder.SetOutputType(mec);
1007     DbgLog((LOG_TRACE, 1, TEXT("set_Variablemin(%d)"), dwMin));
1008     return S_OK;
1009 }
1010 
get_VariableMax(DWORD * dwMax)1011 STDMETHODIMP CMpegAudEnc::get_VariableMax(DWORD *dwMax)
1012 {
1013     MPEG_ENCODER_CONFIG mec;
1014     m_Encoder.GetOutputType(&mec);
1015     *dwMax = (DWORD)mec.dwVariableMax;
1016     DbgLog((LOG_TRACE, 1, TEXT("get_Variablemax -> %d"), *dwMax));
1017     return S_OK;
1018 }
1019 
set_VariableMax(DWORD dwMax)1020 STDMETHODIMP CMpegAudEnc::set_VariableMax(DWORD dwMax)
1021 {
1022     MPEG_ENCODER_CONFIG mec;
1023     m_Encoder.GetOutputType(&mec);
1024     mec.dwVariableMax = dwMax;
1025     m_Encoder.SetOutputType(mec);
1026     DbgLog((LOG_TRACE, 1, TEXT("set_Variablemax(%d)"), dwMax));
1027     return S_OK;
1028 }
1029 
get_Quality(DWORD * dwQuality)1030 STDMETHODIMP CMpegAudEnc::get_Quality(DWORD *dwQuality)
1031 {
1032     MPEG_ENCODER_CONFIG mec;
1033     m_Encoder.GetOutputType(&mec);
1034     *dwQuality=(DWORD)mec.dwQuality;
1035     DbgLog((LOG_TRACE, 1, TEXT("get_Quality -> %d"), *dwQuality));
1036     return S_OK;
1037 }
1038 
set_Quality(DWORD dwQuality)1039 STDMETHODIMP CMpegAudEnc::set_Quality(DWORD dwQuality)
1040 {
1041     MPEG_ENCODER_CONFIG mec;
1042     m_Encoder.GetOutputType(&mec);
1043     mec.dwQuality = dwQuality;
1044     m_Encoder.SetOutputType(mec);
1045     DbgLog((LOG_TRACE, 1, TEXT("set_Quality(%d)"), dwQuality));
1046     return S_OK;
1047 }
get_VariableQ(DWORD * dwVBRq)1048 STDMETHODIMP CMpegAudEnc::get_VariableQ(DWORD *dwVBRq)
1049 {
1050     MPEG_ENCODER_CONFIG mec;
1051     m_Encoder.GetOutputType(&mec);
1052     *dwVBRq=(DWORD)mec.dwVBRq;
1053     DbgLog((LOG_TRACE, 1, TEXT("get_VariableQ -> %d"), *dwVBRq));
1054     return S_OK;
1055 }
1056 
set_VariableQ(DWORD dwVBRq)1057 STDMETHODIMP CMpegAudEnc::set_VariableQ(DWORD dwVBRq)
1058 {
1059     MPEG_ENCODER_CONFIG mec;
1060     m_Encoder.GetOutputType(&mec);
1061     mec.dwVBRq = dwVBRq;
1062     m_Encoder.SetOutputType(mec);
1063     DbgLog((LOG_TRACE, 1, TEXT("set_VariableQ(%d)"), dwVBRq));
1064     return S_OK;
1065 }
1066 
1067 
get_SourceSampleRate(DWORD * dwSampleRate)1068 STDMETHODIMP CMpegAudEnc::get_SourceSampleRate(DWORD *dwSampleRate)
1069 {
1070     *dwSampleRate = 0;
1071 
1072     WAVEFORMATEX wf;
1073     if(FAILED(m_Encoder.GetInputType(&wf)))
1074         return E_FAIL;
1075 
1076     *dwSampleRate = wf.nSamplesPerSec;
1077     DbgLog((LOG_TRACE, 1, TEXT("get_SourceSampleRate -> %d"), *dwSampleRate));
1078     return S_OK;
1079 }
1080 
get_SourceChannels(DWORD * dwChannels)1081 STDMETHODIMP CMpegAudEnc::get_SourceChannels(DWORD *dwChannels)
1082 {
1083     WAVEFORMATEX wf;
1084     if(FAILED(m_Encoder.GetInputType(&wf)))
1085         return E_FAIL;
1086 
1087     *dwChannels = wf.nChannels;
1088     DbgLog((LOG_TRACE, 1, TEXT("get_SourceChannels -> %d"), *dwChannels));
1089     return S_OK;
1090 }
1091 
get_SampleRate(DWORD * dwSampleRate)1092 STDMETHODIMP CMpegAudEnc::get_SampleRate(DWORD *dwSampleRate)
1093 {
1094     MPEG_ENCODER_CONFIG mec;
1095     m_Encoder.GetOutputType(&mec);
1096     *dwSampleRate = mec.dwSampleRate;
1097     DbgLog((LOG_TRACE, 1, TEXT("get_SampleRate -> %d"), *dwSampleRate));
1098     return S_OK;
1099 }
1100 
set_SampleRate(DWORD dwSampleRate)1101 STDMETHODIMP CMpegAudEnc::set_SampleRate(DWORD dwSampleRate)
1102 {
1103     MPEG_ENCODER_CONFIG mec;
1104     m_Encoder.GetOutputType(&mec);
1105     DWORD dwOldSampleRate = mec.dwSampleRate;
1106     mec.dwSampleRate = dwSampleRate;
1107     m_Encoder.SetOutputType(mec);
1108     DbgLog((LOG_TRACE, 1, TEXT("set_SampleRate(%d)"), dwSampleRate));
1109 
1110     return S_OK;
1111 }
1112 
get_ChannelMode(DWORD * dwChannelMode)1113 STDMETHODIMP CMpegAudEnc::get_ChannelMode(DWORD *dwChannelMode)
1114 {
1115     MPEG_ENCODER_CONFIG mec;
1116     m_Encoder.GetOutputType(&mec);
1117     *dwChannelMode = mec.ChMode;
1118     DbgLog((LOG_TRACE, 1, TEXT("get_ChannelMode -> %d"), *dwChannelMode));
1119     return S_OK;
1120 }
1121 
set_ChannelMode(DWORD dwChannelMode)1122 STDMETHODIMP CMpegAudEnc::set_ChannelMode(DWORD dwChannelMode)
1123 {
1124     MPEG_ENCODER_CONFIG mec;
1125     m_Encoder.GetOutputType(&mec);
1126     mec.ChMode = (MPEG_mode)dwChannelMode;
1127     m_Encoder.SetOutputType(mec);
1128     DbgLog((LOG_TRACE, 1, TEXT("set_ChannelMode(%d)"), dwChannelMode));
1129     return S_OK;
1130 }
1131 
get_ForceMS(DWORD * dwFlag)1132 STDMETHODIMP CMpegAudEnc::get_ForceMS(DWORD *dwFlag)
1133 {
1134     MPEG_ENCODER_CONFIG mec;
1135     m_Encoder.GetOutputType(&mec);
1136     *dwFlag = mec.dwForceMS;
1137     DbgLog((LOG_TRACE, 1, TEXT("get_ForceMS -> %d"), *dwFlag));
1138     return S_OK;
1139 }
1140 
set_ForceMS(DWORD dwFlag)1141 STDMETHODIMP CMpegAudEnc::set_ForceMS(DWORD dwFlag)
1142 {
1143     MPEG_ENCODER_CONFIG mec;
1144     m_Encoder.GetOutputType(&mec);
1145     mec.dwForceMS = dwFlag;
1146     m_Encoder.SetOutputType(mec);
1147     DbgLog((LOG_TRACE, 1, TEXT("set_ForceMS(%d)"), dwFlag));
1148     return S_OK;
1149 }
1150 
1151 
get_CRCFlag(DWORD * dwFlag)1152 STDMETHODIMP CMpegAudEnc::get_CRCFlag(DWORD *dwFlag)
1153 {
1154     MPEG_ENCODER_CONFIG mec;
1155     m_Encoder.GetOutputType(&mec);
1156     *dwFlag = mec.bCRCProtect;
1157     DbgLog((LOG_TRACE, 1, TEXT("get_CRCFlag -> %d"), *dwFlag));
1158     return S_OK;
1159 }
1160 
get_ForceMono(DWORD * dwFlag)1161 STDMETHODIMP CMpegAudEnc::get_ForceMono(DWORD *dwFlag)
1162 {
1163     MPEG_ENCODER_CONFIG mec;
1164     m_Encoder.GetOutputType(&mec);
1165     *dwFlag = mec.bForceMono;
1166     DbgLog((LOG_TRACE, 1, TEXT("get_ForceMono -> %d"), *dwFlag));
1167     return S_OK;
1168 }
1169 
get_SetDuration(DWORD * dwFlag)1170 STDMETHODIMP CMpegAudEnc::get_SetDuration(DWORD *dwFlag)
1171 {
1172     MPEG_ENCODER_CONFIG mec;
1173     m_Encoder.GetOutputType(&mec);
1174     *dwFlag = mec.bSetDuration;
1175     DbgLog((LOG_TRACE, 1, TEXT("get_SetDuration -> %d"), *dwFlag));
1176     return S_OK;
1177 }
1178 
get_SampleOverlap(DWORD * dwFlag)1179 STDMETHODIMP CMpegAudEnc::get_SampleOverlap(DWORD *dwFlag)
1180 {
1181     MPEG_ENCODER_CONFIG mec;
1182     m_Encoder.GetOutputType(&mec);
1183     *dwFlag = mec.bSampleOverlap;
1184     DbgLog((LOG_TRACE, 1, TEXT("get_SampleOverlap -> %d"), *dwFlag));
1185     return S_OK;
1186 }
1187 
set_CRCFlag(DWORD dwFlag)1188 STDMETHODIMP CMpegAudEnc::set_CRCFlag(DWORD dwFlag)
1189 {
1190     MPEG_ENCODER_CONFIG mec;
1191     m_Encoder.GetOutputType(&mec);
1192     mec.bCRCProtect = dwFlag;
1193     m_Encoder.SetOutputType(mec);
1194     DbgLog((LOG_TRACE, 1, TEXT("set_CRCFlag(%d)"), dwFlag));
1195     return S_OK;
1196 }
1197 
set_ForceMono(DWORD dwFlag)1198 STDMETHODIMP CMpegAudEnc::set_ForceMono(DWORD dwFlag)
1199 {
1200     MPEG_ENCODER_CONFIG mec;
1201     m_Encoder.GetOutputType(&mec);
1202     mec.bForceMono = dwFlag;
1203     m_Encoder.SetOutputType(mec);
1204     DbgLog((LOG_TRACE, 1, TEXT("set_ForceMono(%d)"), dwFlag));
1205     return S_OK;
1206 }
1207 
set_SetDuration(DWORD dwFlag)1208 STDMETHODIMP CMpegAudEnc::set_SetDuration(DWORD dwFlag)
1209 {
1210     MPEG_ENCODER_CONFIG mec;
1211     m_Encoder.GetOutputType(&mec);
1212     mec.bSetDuration = dwFlag;
1213     m_Encoder.SetOutputType(mec);
1214     DbgLog((LOG_TRACE, 1, TEXT("set_SetDuration(%d)"), dwFlag));
1215     return S_OK;
1216 }
1217 
set_SampleOverlap(DWORD dwFlag)1218 STDMETHODIMP CMpegAudEnc::set_SampleOverlap(DWORD dwFlag)
1219 {
1220     MPEG_ENCODER_CONFIG mec;
1221     m_Encoder.GetOutputType(&mec);
1222     mec.bSampleOverlap = dwFlag;
1223     m_Encoder.SetOutputType(mec);
1224     DbgLog((LOG_TRACE, 1, TEXT("set_SampleOverlap(%d)"), dwFlag));
1225     return S_OK;
1226 }
1227 
get_EnforceVBRmin(DWORD * dwFlag)1228 STDMETHODIMP CMpegAudEnc::get_EnforceVBRmin(DWORD *dwFlag)
1229 {
1230     MPEG_ENCODER_CONFIG mec;
1231     m_Encoder.GetOutputType(&mec);
1232     *dwFlag = mec.dwEnforceVBRmin;
1233     DbgLog((LOG_TRACE, 1, TEXT("get_EnforceVBRmin -> %d"), *dwFlag));
1234     return S_OK;
1235 }
1236 
set_EnforceVBRmin(DWORD dwFlag)1237 STDMETHODIMP CMpegAudEnc::set_EnforceVBRmin(DWORD dwFlag)
1238 {
1239     MPEG_ENCODER_CONFIG mec;
1240     m_Encoder.GetOutputType(&mec);
1241     mec.dwEnforceVBRmin = dwFlag;
1242     m_Encoder.SetOutputType(mec);
1243     DbgLog((LOG_TRACE, 1, TEXT("set_EnforceVBRmin(%d)"), dwFlag));
1244     return S_OK;
1245 }
1246 
get_VoiceMode(DWORD * dwFlag)1247 STDMETHODIMP CMpegAudEnc::get_VoiceMode(DWORD *dwFlag)
1248 {
1249     MPEG_ENCODER_CONFIG mec;
1250     m_Encoder.GetOutputType(&mec);
1251     *dwFlag = mec.dwVoiceMode;
1252     DbgLog((LOG_TRACE, 1, TEXT("get_VoiceMode -> %d"), *dwFlag));
1253     return S_OK;
1254 }
1255 
set_VoiceMode(DWORD dwFlag)1256 STDMETHODIMP CMpegAudEnc::set_VoiceMode(DWORD dwFlag)
1257 {
1258     MPEG_ENCODER_CONFIG mec;
1259     m_Encoder.GetOutputType(&mec);
1260     mec.dwVoiceMode = dwFlag;
1261     m_Encoder.SetOutputType(mec);
1262     DbgLog((LOG_TRACE, 1, TEXT("set_VoiceMode(%d)"), dwFlag));
1263     return S_OK;
1264 }
1265 
get_KeepAllFreq(DWORD * dwFlag)1266 STDMETHODIMP CMpegAudEnc::get_KeepAllFreq(DWORD *dwFlag)
1267 {
1268     MPEG_ENCODER_CONFIG mec;
1269     m_Encoder.GetOutputType(&mec);
1270     *dwFlag = mec.dwKeepAllFreq;
1271     DbgLog((LOG_TRACE, 1, TEXT("get_KeepAllFreq -> %d"), *dwFlag));
1272     return S_OK;
1273 }
1274 
set_KeepAllFreq(DWORD dwFlag)1275 STDMETHODIMP CMpegAudEnc::set_KeepAllFreq(DWORD dwFlag)
1276 {
1277     MPEG_ENCODER_CONFIG mec;
1278     m_Encoder.GetOutputType(&mec);
1279     mec.dwKeepAllFreq = dwFlag;
1280     m_Encoder.SetOutputType(mec);
1281     DbgLog((LOG_TRACE, 1, TEXT("set_KeepAllFreq(%d)"), dwFlag));
1282     return S_OK;
1283 }
1284 
get_StrictISO(DWORD * dwFlag)1285 STDMETHODIMP CMpegAudEnc::get_StrictISO(DWORD *dwFlag)
1286 {
1287     MPEG_ENCODER_CONFIG mec;
1288     m_Encoder.GetOutputType(&mec);
1289     *dwFlag = mec.dwStrictISO;
1290     DbgLog((LOG_TRACE, 1, TEXT("get_StrictISO -> %d"), *dwFlag));
1291     return S_OK;
1292 }
1293 
set_StrictISO(DWORD dwFlag)1294 STDMETHODIMP CMpegAudEnc::set_StrictISO(DWORD dwFlag)
1295 {
1296     MPEG_ENCODER_CONFIG mec;
1297     m_Encoder.GetOutputType(&mec);
1298     mec.dwStrictISO = dwFlag;
1299     m_Encoder.SetOutputType(mec);
1300     DbgLog((LOG_TRACE, 1, TEXT("set_StrictISO(%d)"), dwFlag));
1301     return S_OK;
1302 }
1303 
get_NoShortBlock(DWORD * dwNoShortBlock)1304 STDMETHODIMP CMpegAudEnc::get_NoShortBlock(DWORD *dwNoShortBlock)
1305 {
1306     MPEG_ENCODER_CONFIG mec;
1307     m_Encoder.GetOutputType(&mec);
1308     *dwNoShortBlock = mec.dwNoShortBlock;
1309     DbgLog((LOG_TRACE, 1, TEXT("get_NoShortBlock -> %d"), *dwNoShortBlock));
1310     return S_OK;
1311 }
1312 
set_NoShortBlock(DWORD dwNoShortBlock)1313 STDMETHODIMP CMpegAudEnc::set_NoShortBlock(DWORD dwNoShortBlock)
1314 {
1315     MPEG_ENCODER_CONFIG mec;
1316     m_Encoder.GetOutputType(&mec);
1317     mec.dwNoShortBlock = dwNoShortBlock;
1318     m_Encoder.SetOutputType(mec);
1319     DbgLog((LOG_TRACE, 1, TEXT("set_NoShortBlock(%d)"), dwNoShortBlock));
1320     return S_OK;
1321 }
1322 
get_XingTag(DWORD * dwXingTag)1323 STDMETHODIMP CMpegAudEnc::get_XingTag(DWORD *dwXingTag)
1324 {
1325     MPEG_ENCODER_CONFIG mec;
1326     m_Encoder.GetOutputType(&mec);
1327     *dwXingTag = mec.dwXingTag;
1328     DbgLog((LOG_TRACE, 1, TEXT("get_XingTag -> %d"), *dwXingTag));
1329     return S_OK;
1330 }
1331 
set_XingTag(DWORD dwXingTag)1332 STDMETHODIMP CMpegAudEnc::set_XingTag(DWORD dwXingTag)
1333 {
1334     MPEG_ENCODER_CONFIG mec;
1335     m_Encoder.GetOutputType(&mec);
1336     mec.dwXingTag = dwXingTag;
1337     m_Encoder.SetOutputType(mec);
1338     DbgLog((LOG_TRACE, 1, TEXT("set_XingTag(%d)"), dwXingTag));
1339     return S_OK;
1340 }
1341 
1342 
1343 
get_OriginalFlag(DWORD * dwFlag)1344 STDMETHODIMP CMpegAudEnc::get_OriginalFlag(DWORD *dwFlag)
1345 {
1346     MPEG_ENCODER_CONFIG mec;
1347     m_Encoder.GetOutputType(&mec);
1348     *dwFlag = mec.bOriginal;
1349     DbgLog((LOG_TRACE, 1, TEXT("get_OriginalFlag -> %d"), *dwFlag));
1350     return S_OK;
1351 }
1352 
set_OriginalFlag(DWORD dwFlag)1353 STDMETHODIMP CMpegAudEnc::set_OriginalFlag(DWORD dwFlag)
1354 {
1355     MPEG_ENCODER_CONFIG mec;
1356     m_Encoder.GetOutputType(&mec);
1357     mec.bOriginal = dwFlag;
1358     m_Encoder.SetOutputType(mec);
1359     DbgLog((LOG_TRACE, 1, TEXT("set_OriginalFlag(%d)"), dwFlag));
1360     return S_OK;
1361 }
1362 
get_CopyrightFlag(DWORD * dwFlag)1363 STDMETHODIMP CMpegAudEnc::get_CopyrightFlag(DWORD *dwFlag)
1364 {
1365     MPEG_ENCODER_CONFIG mec;
1366     m_Encoder.GetOutputType(&mec);
1367     *dwFlag = mec.bCopyright;
1368     DbgLog((LOG_TRACE, 1, TEXT("get_CopyrightFlag -> %d"), *dwFlag));
1369     return S_OK;
1370 }
1371 
set_CopyrightFlag(DWORD dwFlag)1372 STDMETHODIMP CMpegAudEnc::set_CopyrightFlag(DWORD dwFlag)
1373 {
1374     MPEG_ENCODER_CONFIG mec;
1375     m_Encoder.GetOutputType(&mec);
1376     mec.bCopyright = dwFlag;
1377     m_Encoder.SetOutputType(mec);
1378     DbgLog((LOG_TRACE, 1, TEXT("set_CopyrightFlag(%d)"), dwFlag));
1379     return S_OK;
1380 }
1381 
get_ModeFixed(DWORD * dwModeFixed)1382 STDMETHODIMP CMpegAudEnc::get_ModeFixed(DWORD *dwModeFixed)
1383 {
1384     MPEG_ENCODER_CONFIG mec;
1385     m_Encoder.GetOutputType(&mec);
1386     *dwModeFixed = mec.dwModeFixed;
1387     DbgLog((LOG_TRACE, 1, TEXT("get_ModeFixed -> %d"), *dwModeFixed));
1388     return S_OK;
1389 }
1390 
set_ModeFixed(DWORD dwModeFixed)1391 STDMETHODIMP CMpegAudEnc::set_ModeFixed(DWORD dwModeFixed)
1392 {
1393     MPEG_ENCODER_CONFIG mec;
1394     m_Encoder.GetOutputType(&mec);
1395     mec.dwModeFixed = dwModeFixed;
1396     m_Encoder.SetOutputType(mec);
1397     DbgLog((LOG_TRACE, 1, TEXT("set_ModeFixed(%d)"), dwModeFixed));
1398     return S_OK;
1399 }
1400 
get_ParameterBlockSize(BYTE * pcBlock,DWORD * pdwSize)1401 STDMETHODIMP CMpegAudEnc::get_ParameterBlockSize(BYTE *pcBlock, DWORD *pdwSize)
1402 {
1403     DbgLog((LOG_TRACE, 1, TEXT("get_ParameterBlockSize -> %d%d"), *pcBlock, *pdwSize));
1404 
1405     if (pcBlock != NULL) {
1406         if (*pdwSize >= sizeof(MPEG_ENCODER_CONFIG)) {
1407             m_Encoder.GetOutputType((MPEG_ENCODER_CONFIG*)pcBlock);
1408             return S_OK;
1409         }
1410         else {
1411             *pdwSize = sizeof(MPEG_ENCODER_CONFIG);
1412             return E_FAIL;
1413         }
1414     }
1415     else if (pdwSize != NULL) {
1416         *pdwSize = sizeof(MPEG_ENCODER_CONFIG);
1417         return S_OK;
1418     }
1419 
1420     return E_FAIL;
1421 }
1422 
set_ParameterBlockSize(BYTE * pcBlock,DWORD dwSize)1423 STDMETHODIMP CMpegAudEnc::set_ParameterBlockSize(BYTE *pcBlock, DWORD dwSize)
1424 {
1425     DbgLog((LOG_TRACE, 1, TEXT("get_ParameterBlockSize(%d, %d)"), *pcBlock, dwSize));
1426     if (sizeof(MPEG_ENCODER_CONFIG) == dwSize){
1427         m_Encoder.SetOutputType(*(MPEG_ENCODER_CONFIG*)pcBlock);
1428         return S_OK;
1429     }
1430     else return E_FAIL;
1431 }
1432 
1433 
DefaultAudioEncoderProperties()1434 STDMETHODIMP CMpegAudEnc::DefaultAudioEncoderProperties()
1435 {
1436     DbgLog((LOG_TRACE, 1, TEXT("DefaultAudioEncoderProperties()")));
1437 
1438     HRESULT hr = InputTypeDefined();
1439     if (FAILED(hr))
1440         return hr;
1441 
1442     DWORD dwSourceSampleRate;
1443     get_SourceSampleRate(&dwSourceSampleRate);
1444 
1445     set_PESOutputEnabled(DEFAULT_PES);
1446     set_MPEGLayer(DEFAULT_LAYER);
1447 
1448     set_Bitrate(DEFAULT_BITRATE);
1449     set_Variable(FALSE);
1450     set_VariableMin(DEFAULT_VARIABLEMIN);
1451     set_VariableMax(DEFAULT_VARIABLEMAX);
1452     set_Quality(DEFAULT_ENCODING_QUALITY);
1453     set_VariableQ(DEFAULT_VBR_QUALITY);
1454 
1455     set_SampleRate(dwSourceSampleRate);
1456     set_CRCFlag(DEFAULT_CRC);
1457     set_ForceMono(DEFAULT_FORCE_MONO);
1458     set_SetDuration(DEFAULT_SET_DURATION);
1459     set_SampleOverlap(DEFAULT_SAMPLE_OVERLAP);
1460     set_OriginalFlag(DEFAULT_ORIGINAL);
1461     set_CopyrightFlag(DEFAULT_COPYRIGHT);
1462 
1463     set_EnforceVBRmin(DEFAULT_ENFORCE_MIN);
1464     set_VoiceMode(DEFAULT_VOICE);
1465     set_KeepAllFreq(DEFAULT_KEEP_ALL_FREQ);
1466     set_StrictISO(DEFAULT_STRICT_ISO);
1467     set_NoShortBlock(DEFAULT_DISABLE_SHORT_BLOCK);
1468     set_XingTag(DEFAULT_XING_TAG);
1469     set_ForceMS(DEFAULT_FORCE_MS);
1470     set_ChannelMode(DEFAULT_STEREO_MODE);
1471     set_ModeFixed(DEFAULT_MODE_FIXED);
1472 
1473     return S_OK;
1474 }
1475 
LoadAudioEncoderPropertiesFromRegistry()1476 STDMETHODIMP CMpegAudEnc::LoadAudioEncoderPropertiesFromRegistry()
1477 {
1478     DbgLog((LOG_TRACE, 1, TEXT("LoadAudioEncoderPropertiesFromRegistry()")));
1479 
1480     MPEG_ENCODER_CONFIG mec;
1481     ReadPresetSettings(&mec);
1482     if(m_Encoder.SetOutputType(mec) == S_FALSE)
1483         return S_FALSE;
1484     return S_OK;
1485 }
1486 
SaveAudioEncoderPropertiesToRegistry()1487 STDMETHODIMP CMpegAudEnc::SaveAudioEncoderPropertiesToRegistry()
1488 {
1489     DbgLog((LOG_TRACE, 1, TEXT("SaveAudioEncoderPropertiesToRegistry()")));
1490     Lame::CRegKey rk;
1491 
1492     MPEG_ENCODER_CONFIG mec;
1493     if(m_Encoder.GetOutputType(&mec) == S_FALSE)
1494         return E_FAIL;
1495 
1496     if(rk.Create(HKEY_CURRENT_USER, KEY_LAME_ENCODER))
1497     {
1498         rk.setDWORD(VALUE_BITRATE, mec.dwBitrate);
1499         rk.setDWORD(VALUE_VARIABLE, mec.vmVariable);
1500         rk.setDWORD(VALUE_VARIABLEMIN, mec.dwVariableMin);
1501         rk.setDWORD(VALUE_VARIABLEMAX, mec.dwVariableMax);
1502         rk.setDWORD(VALUE_QUALITY, mec.dwQuality);
1503         rk.setDWORD(VALUE_VBR_QUALITY, mec.dwVBRq);
1504 
1505         rk.setDWORD(VALUE_CRC, mec.bCRCProtect);
1506         rk.setDWORD(VALUE_FORCE_MONO, mec.bForceMono);
1507         rk.setDWORD(VALUE_SET_DURATION, mec.bSetDuration);
1508         rk.setDWORD(VALUE_SAMPLE_OVERLAP, mec.bSampleOverlap);
1509         rk.setDWORD(VALUE_PES, mec.dwPES);
1510         rk.setDWORD(VALUE_COPYRIGHT, mec.bCopyright);
1511         rk.setDWORD(VALUE_ORIGINAL, mec.bOriginal);
1512         rk.setDWORD(VALUE_SAMPLE_RATE, mec.dwSampleRate);
1513 
1514         rk.setDWORD(VALUE_STEREO_MODE, mec.ChMode);
1515         rk.setDWORD(VALUE_FORCE_MS, mec.dwForceMS);
1516         rk.setDWORD(VALUE_XING_TAG, mec.dwXingTag);
1517         rk.setDWORD(VALUE_DISABLE_SHORT_BLOCK, mec.dwNoShortBlock);
1518         rk.setDWORD(VALUE_STRICT_ISO, mec.dwStrictISO);
1519         rk.setDWORD(VALUE_KEEP_ALL_FREQ, mec.dwKeepAllFreq);
1520         rk.setDWORD(VALUE_VOICE, mec.dwVoiceMode);
1521         rk.setDWORD(VALUE_ENFORCE_MIN, mec.dwEnforceVBRmin);
1522         rk.setDWORD(VALUE_MODE_FIXED, mec.dwModeFixed);
1523 
1524         rk.Close();
1525     }
1526 
1527     // Reconnect filter graph
1528     Reconnect();
1529 
1530     return S_OK;
1531 }
1532 
InputTypeDefined()1533 STDMETHODIMP CMpegAudEnc::InputTypeDefined()
1534 {
1535     WAVEFORMATEX wf;
1536     if(FAILED(m_Encoder.GetInputType(&wf)))
1537     {
1538         DbgLog((LOG_TRACE, 1, TEXT("!InputTypeDefined()")));
1539         return E_FAIL;
1540     }
1541 
1542     DbgLog((LOG_TRACE, 1, TEXT("InputTypeDefined()")));
1543     return S_OK;
1544 }
1545 
1546 
ApplyChanges()1547 STDMETHODIMP CMpegAudEnc::ApplyChanges()
1548 {
1549     return Reconnect();
1550 }
1551 
1552 //
1553 // CPersistStream stuff
1554 //
1555 
1556 // what is our class ID?
GetClassID(CLSID * pClsid)1557 STDMETHODIMP CMpegAudEnc::GetClassID(CLSID *pClsid)
1558 {
1559     CheckPointer(pClsid, E_POINTER);
1560     *pClsid = CLSID_LAMEDShowFilter;
1561     return S_OK;
1562 }
1563 
WriteToStream(IStream * pStream)1564 HRESULT CMpegAudEnc::WriteToStream(IStream *pStream)
1565 {
1566     DbgLog((LOG_TRACE,1,TEXT("WriteToStream()")));
1567 
1568 	MPEG_ENCODER_CONFIG mec;
1569 
1570 	if(m_Encoder.GetOutputType(&mec) == S_FALSE)
1571 		return E_FAIL;
1572 
1573     return pStream->Write(&mec, sizeof(mec), 0);
1574 }
1575 
1576 
1577 // what device should we use?  Used to re-create a .GRF file that we
1578 // are in
ReadFromStream(IStream * pStream)1579 HRESULT CMpegAudEnc::ReadFromStream(IStream *pStream)
1580 {
1581 	MPEG_ENCODER_CONFIG mec;
1582 
1583     HRESULT hr = pStream->Read(&mec, sizeof(mec), 0);
1584     if(FAILED(hr))
1585         return hr;
1586 
1587 	if(m_Encoder.SetOutputType(mec) == S_FALSE)
1588 		return S_FALSE;
1589 
1590     DbgLog((LOG_TRACE,1,TEXT("ReadFromStream() succeeded")));
1591 
1592     hr = S_OK;
1593     return hr;
1594 }
1595 
1596 
1597 // How long is our data?
SizeMax()1598 int CMpegAudEnc::SizeMax()
1599 {
1600     return sizeof(MPEG_ENCODER_CONFIG);
1601 }
1602 
1603 
1604 
1605 
1606 
1607 //////////////////////////////////////////////////////////////////////////
1608 // CMpegAudEncOutPin is the one and only output pin of CMpegAudEnc
1609 //
1610 //////////////////////////////////////////////////////////////////////////
CMpegAudEncOutPin(CMpegAudEnc * pFilter,HRESULT * pHr)1611 CMpegAudEncOutPin::CMpegAudEncOutPin( CMpegAudEnc * pFilter, HRESULT * pHr ) :
1612         CTransformOutputPin( NAME("LameEncoderOutputPin"), pFilter, pHr, L"Output\0" ),
1613         m_pFilter(pFilter)
1614 {
1615     m_SetFormat = FALSE;
1616 }
1617 
~CMpegAudEncOutPin()1618 CMpegAudEncOutPin::~CMpegAudEncOutPin()
1619 {
1620 }
1621 
NonDelegatingQueryInterface(REFIID riid,void ** ppv)1622 STDMETHODIMP CMpegAudEncOutPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
1623 {
1624     if(riid == IID_IAMStreamConfig) {
1625         CheckPointer(ppv, E_POINTER);
1626         return GetInterface((IAMStreamConfig*)(this), ppv);
1627     }
1628     return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
1629 }
1630 
1631 
1632 //////////////////////////////////////////////////////////////////////////
1633 // This is called after the output format has been negotiated and
1634 // will update the LAME encoder settings so that it matches the
1635 // settings specified in the MediaType structure.
1636 //////////////////////////////////////////////////////////////////////////
SetMediaType(const CMediaType * pmt)1637 HRESULT CMpegAudEncOutPin::SetMediaType(const CMediaType *pmt)
1638 {
1639     // Retrieve the current LAME encoder configuration
1640     MPEG_ENCODER_CONFIG mec;
1641     m_pFilter->m_Encoder.GetOutputType(&mec);
1642 
1643     // Annotate if we are using the MEDIATYPE_Stream output type
1644     m_pFilter->m_bStreamOutput = (pmt->majortype == MEDIATYPE_Stream);
1645 
1646     if (pmt->majortype == MEDIATYPE_Stream) {
1647         // Update the encoder configuration using the settings that were
1648         // cached in the CMpegAudEncOutPin::GetMediaType() call
1649         mec.dwSampleRate = m_CurrentOutputFormat.nSampleRate;
1650         mec.dwBitrate = m_CurrentOutputFormat.nBitRate;
1651         mec.ChMode = m_CurrentOutputFormat.ChMode;
1652     }
1653     else {
1654         // Update the encoder configuration directly using the values
1655         // passed via the CMediaType structure.
1656         MPEGLAYER3WAVEFORMAT *pfmt = (MPEGLAYER3WAVEFORMAT*) pmt->Format();
1657         mec.dwSampleRate = pfmt->wfx.nSamplesPerSec;
1658         mec.dwBitrate = pfmt->wfx.nAvgBytesPerSec * 8 / 1000;
1659 
1660         if (pfmt->wfx.nChannels == 1) { mec.ChMode = MONO; }
1661         else if (pfmt->wfx.nChannels == 2 && mec.ChMode == MONO && !mec.bForceMono) { mec.ChMode = STEREO; }
1662     }
1663     m_pFilter->m_Encoder.SetOutputType(mec);
1664 
1665     // Now configure this MediaType on the output pin
1666     HRESULT hr = CTransformOutputPin::SetMediaType(pmt);
1667     return hr;
1668 }
1669 
1670 
1671 //////////////////////////////////////////////////////////////////////////
1672 // Retrieve the various MediaTypes that match the advertised formats
1673 // supported on the output pin and configure an AM_MEDIA_TYPE output
1674 // structure that is based on the selected format.
1675 //////////////////////////////////////////////////////////////////////////
GetMediaType(int iPosition,CMediaType * pmt)1676 HRESULT CMpegAudEncOutPin::GetMediaType(int iPosition, CMediaType *pmt)
1677 {
1678     if (iPosition < 0) return E_INVALIDARG;
1679 
1680     // If iPosition equals zero then we always return the currently configured MediaType
1681     if (iPosition == 0) {
1682         *pmt = m_mt;
1683         return S_OK;
1684     }
1685 
1686     switch (iPosition)
1687     {
1688         case 1:
1689         {
1690             pmt->SetType(&MEDIATYPE_Audio);
1691             pmt->SetSubtype(&MEDIASUBTYPE_MP3);
1692             break;
1693         }
1694         case 2:
1695         {
1696             pmt->SetType(&MEDIATYPE_Stream);
1697             pmt->SetSubtype(&MEDIASUBTYPE_MPEG1Audio);
1698             pmt->SetFormatType(&GUID_NULL);
1699             break;
1700         }
1701         case 3:
1702         {   // The last case that we evaluate is the MPEG2_PES format, but if the
1703             // encoder isn't configured for it then just return VFW_S_NO_MORE_ITEMS
1704             if ( !m_pFilter->m_Encoder.IsPES() ) { return VFW_S_NO_MORE_ITEMS; }
1705 
1706             pmt->SetType(&MEDIATYPE_MPEG2_PES);
1707             pmt->SetSubtype(&MEDIASUBTYPE_MPEG2_AUDIO);
1708             break;
1709         }
1710         default:
1711             return VFW_S_NO_MORE_ITEMS;
1712     }
1713 
1714 
1715     // Output capabilities are dependent on the input so insure it is connected
1716     if ( !m_pFilter->m_pInput->IsConnected() ) {
1717         pmt->SetFormatType(&FORMAT_None);
1718         return NOERROR;
1719     }
1720 
1721 
1722     // Annotate the current MediaType index for recall in CMpegAudEnc::Reconnect()
1723     m_pFilter->m_currentMediaTypeIndex = iPosition;
1724 
1725     // Configure the remaining AM_MEDIA_TYPE parameters using the cached encoder settings.
1726     // Since MEDIATYPE_Stream doesn't have a format block the current settings
1727     // for CHANNEL MODE, BITRATE and SAMPLERATE are cached in m_CurrentOutputFormat for use
1728     // when we setup the LAME encoder in the call to CMpegAudEncOutPin::SetMediaType()
1729     MPEG_ENCODER_CONFIG mec;
1730     m_pFilter->m_Encoder.GetOutputType(&mec);           // Retrieve the current encoder config
1731 
1732     WAVEFORMATEX wf;                                    // Retrieve the input configuration
1733     m_pFilter->m_Encoder.GetInputType(&wf);
1734 
1735     // Use the current encoder sample rate unless it isn't a modulus of the input rate
1736     if ((wf.nSamplesPerSec % mec.dwSampleRate) == 0) {
1737         m_CurrentOutputFormat.nSampleRate = mec.dwSampleRate;
1738     }
1739     else {
1740         m_CurrentOutputFormat.nSampleRate = wf.nSamplesPerSec;
1741     }
1742 
1743     // Select the output channel config based on the encoder config and input channel count
1744     m_CurrentOutputFormat.ChMode = mec.ChMode;
1745     switch (wf.nChannels)                    // Determine if we need to alter ChMode based upon the channel count and ForceMono flag
1746     {
1747         case 1:
1748         {
1749             m_CurrentOutputFormat.ChMode = MONO;
1750             break;
1751         }
1752         case 2:
1753         {
1754             if (mec.ChMode == MONO && !mec.bForceMono) { m_CurrentOutputFormat.ChMode = STEREO; }
1755             else if ( mec.bForceMono ) { m_CurrentOutputFormat.ChMode = MONO; }
1756             break;
1757         }
1758     }
1759 
1760     // Select the encoder bit rate. In VBR mode we set the data rate parameter
1761     // of the WAVE_FORMAT_MPEGLAYER3 structure to the minimum VBR value
1762     m_CurrentOutputFormat.nBitRate = (mec.vmVariable == vbr_off) ? mec.dwBitrate : mec.dwVariableMin;
1763 
1764     if (pmt->majortype == MEDIATYPE_Stream) return NOERROR;     // No further config required for MEDIATYPE_Stream
1765 
1766 
1767     // Now configure the remainder of the WAVE_FORMAT_MPEGLAYER3 format block
1768     // and its parent AM_MEDIA_TYPE structure
1769     DECLARE_PTR(MPEGLAYER3WAVEFORMAT, p_mp3wvfmt, pmt->AllocFormatBuffer(sizeof(MPEGLAYER3WAVEFORMAT)));
1770     ZeroMemory(p_mp3wvfmt, sizeof(MPEGLAYER3WAVEFORMAT));
1771 
1772     p_mp3wvfmt->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3;
1773     p_mp3wvfmt->wfx.nChannels = (m_CurrentOutputFormat.ChMode == MONO) ? 1 : 2;
1774     p_mp3wvfmt->wfx.nSamplesPerSec = m_CurrentOutputFormat.nSampleRate;
1775     p_mp3wvfmt->wfx.nAvgBytesPerSec = GET_DATARATE(m_CurrentOutputFormat.nBitRate);
1776     p_mp3wvfmt->wfx.nBlockAlign = 1;
1777     p_mp3wvfmt->wfx.wBitsPerSample = 0;
1778     p_mp3wvfmt->wfx.cbSize = sizeof(MPEGLAYER3WAVEFORMAT) - sizeof(WAVEFORMATEX);
1779 
1780     p_mp3wvfmt->wID = MPEGLAYER3_ID_MPEG;
1781     p_mp3wvfmt->fdwFlags = MPEGLAYER3_FLAG_PADDING_ISO;
1782     p_mp3wvfmt->nBlockSize = GET_FRAMELENGTH(m_CurrentOutputFormat.nBitRate, p_mp3wvfmt->wfx.nSamplesPerSec);
1783     p_mp3wvfmt->nFramesPerBlock = 1;
1784     p_mp3wvfmt->nCodecDelay = 0;
1785 
1786     pmt->SetTemporalCompression(FALSE);
1787     pmt->SetSampleSize(OUT_BUFFER_SIZE);
1788     pmt->SetFormat((LPBYTE)p_mp3wvfmt, sizeof(MPEGLAYER3WAVEFORMAT));
1789     pmt->SetFormatType(&FORMAT_WaveFormatEx);
1790 
1791     return NOERROR;
1792 }
1793 
1794 
1795 //////////////////////////////////////////////////////////////////////////
1796 // This method is called to see if a given output format is supported
1797 //////////////////////////////////////////////////////////////////////////
CheckMediaType(const CMediaType * pmtOut)1798 HRESULT CMpegAudEncOutPin::CheckMediaType(const CMediaType *pmtOut)
1799 {
1800     // Fail if the input pin is not connected.
1801     if (!m_pFilter->m_pInput->IsConnected()) {
1802         return VFW_E_NOT_CONNECTED;
1803     }
1804 
1805     // Reject any media types that we know in advance our
1806     // filter cannot use.
1807     if (pmtOut->majortype != MEDIATYPE_Audio && pmtOut->majortype != MEDIATYPE_Stream) { return S_FALSE; }
1808 
1809     // If SetFormat was previously called, check whether pmtOut exactly
1810     // matches the format that was specified in SetFormat.
1811     // Return S_OK if they match, or VFW_E_INVALIDMEDIATYPE otherwise.)
1812     if ( m_SetFormat ) {
1813         if (*pmtOut != m_mt) { return VFW_E_INVALIDMEDIATYPE; }
1814         else { return S_OK; }
1815     }
1816 
1817     // Now do the normal check for this media type.
1818     HRESULT hr;
1819     hr = m_pFilter->CheckTransform (&m_pFilter->m_pInput->CurrentMediaType(),  // The input type.
1820                                     pmtOut);                                   // The proposed output type.
1821 
1822     if (hr == S_OK) {
1823         return S_OK;           // This format is compatible with the current input type.
1824     }
1825 
1826     // This format is not compatible with the current input type.
1827     // Maybe we can reconnect the input pin with a new input type.
1828 
1829     // Enumerate the upstream filter's preferred output types, and
1830     // see if one of them will work.
1831     CMediaType *pmtEnum;
1832     BOOL fFound = FALSE;
1833     IEnumMediaTypes *pEnum;
1834     hr = m_pFilter->m_pInput->GetConnected()->EnumMediaTypes(&pEnum);
1835     if (hr != S_OK) {
1836         return E_FAIL;
1837     }
1838 
1839     while (hr = pEnum->Next(1, (AM_MEDIA_TYPE **)&pmtEnum, NULL), hr == S_OK)
1840     {
1841         // Check this input type against the proposed output type.
1842         hr = m_pFilter->CheckTransform(pmtEnum, pmtOut);
1843         if (hr != S_OK) {
1844             DeleteMediaType(pmtEnum);
1845             continue; // Try the next one.
1846         }
1847 
1848         // This input type is a possible candidate. But, we have to make
1849         // sure that the upstream filter can switch to this type.
1850         hr = m_pFilter->m_pInput->GetConnected()->QueryAccept(pmtEnum);
1851         if (hr != S_OK) {
1852             // The upstream filter will not switch to this type.
1853             DeleteMediaType(pmtEnum);
1854             continue; // Try the next one.
1855         }
1856         fFound = TRUE;
1857         DeleteMediaType(pmtEnum);
1858         break;
1859     }
1860     pEnum->Release();
1861 
1862     if (fFound) {
1863         // This output type is OK, but if we are asked to use it, we will
1864         // need to reconnect our input pin. (See SetFormat, below.)
1865         return S_OK;
1866     }
1867     else {
1868         return VFW_E_INVALIDMEDIATYPE;
1869     }
1870 }
1871 
1872 
1873 
1874 //////////////////////////////////////////////////////////////////////////
1875 //  IAMStreamConfig
1876 //////////////////////////////////////////////////////////////////////////
1877 
SetFormat(AM_MEDIA_TYPE * pmt)1878 HRESULT STDMETHODCALLTYPE CMpegAudEncOutPin::SetFormat(AM_MEDIA_TYPE *pmt)
1879 {
1880     CheckPointer(pmt, E_POINTER);
1881     HRESULT hr;
1882 
1883     // Hold the filter state lock, to make sure that streaming isn't
1884     // in the middle of starting or stopping:
1885     CAutoLock cObjectLock(&m_pFilter->m_csFilter);
1886 
1887     // Cannot set the format unless the filter is stopped.
1888     if (m_pFilter->m_State != State_Stopped) {
1889         return VFW_E_NOT_STOPPED;
1890     }
1891 
1892     // The set of possible output formats depends on the input format,
1893     // so if the input pin is not connected, return a failure code.
1894     if (!m_pFilter->m_pInput->IsConnected()) {
1895         return VFW_E_NOT_CONNECTED;
1896     }
1897 
1898     // If the pin is already using this format, there's nothing to do.
1899     if (IsConnected() && CurrentMediaType() == *pmt) {
1900         if ( m_SetFormat ) return S_OK;
1901     }
1902 
1903     // See if this media type is acceptable.
1904     if ((hr = CheckMediaType((CMediaType *)pmt)) != S_OK) {
1905         return hr;
1906     }
1907 
1908     // If we're connected to a downstream filter, we have to make
1909     // sure that the downstream filter accepts this media type.
1910     if (IsConnected()) {
1911         hr = GetConnected()->QueryAccept(pmt);
1912         if (hr != S_OK) {
1913             return VFW_E_INVALIDMEDIATYPE;
1914         }
1915     }
1916 
1917     // Now make a note that from now on, this is the only format allowed,
1918     // and refuse anything but this in the CheckMediaType() code above.
1919     m_SetFormat = TRUE;
1920     m_mt = *pmt;
1921 
1922     // Changing the format means reconnecting if necessary.
1923     if (IsConnected()) {
1924         m_pFilter->m_pGraph->Reconnect(this);
1925     }
1926 
1927     return NOERROR;
1928 }
1929 
GetFormat(AM_MEDIA_TYPE ** ppmt)1930 HRESULT STDMETHODCALLTYPE CMpegAudEncOutPin::GetFormat(AM_MEDIA_TYPE **ppmt)
1931 {
1932     *ppmt = CreateMediaType(&m_mt);
1933     return S_OK;
1934 }
1935 
GetNumberOfCapabilities(int * piCount,int * piSize)1936 HRESULT STDMETHODCALLTYPE CMpegAudEncOutPin::GetNumberOfCapabilities(int *piCount, int *piSize)
1937 {
1938     // The set of possible output formats depends on the input format,
1939     // so if the input pin is not connected, return a failure code.
1940     if (!m_pFilter->m_pInput->IsConnected()) {
1941         return VFW_E_NOT_CONNECTED;
1942     }
1943 
1944     // Retrieve the current encoder configuration
1945     MPEG_ENCODER_CONFIG mec;
1946     m_pFilter->m_Encoder.GetOutputType(&mec);
1947 
1948     // If the encoder is in VBR mode GetStreamCaps() isn't implemented
1949     if (mec.vmVariable != vbr_off) { *piCount = 0; }
1950     else { *piCount = m_pFilter->m_CapsNum; }
1951 
1952     *piSize = sizeof(AUDIO_STREAM_CONFIG_CAPS);
1953     return S_OK;
1954 }
1955 
GetStreamCaps(int iIndex,AM_MEDIA_TYPE ** pmt,BYTE * pSCC)1956 HRESULT STDMETHODCALLTYPE CMpegAudEncOutPin::GetStreamCaps(int iIndex, AM_MEDIA_TYPE **pmt, BYTE *pSCC)
1957 {
1958     // The set of possible output formats depends on the input format,
1959     // so if the input pin is not connected, return a failure code.
1960     if (!m_pFilter->m_pInput->IsConnected()) {
1961         return VFW_E_NOT_CONNECTED;
1962     }
1963 
1964     // If we don't have a capabilities array GetStreamCaps() isn't implemented
1965     if (m_pFilter->m_CapsNum == 0) return E_NOTIMPL;
1966 
1967     // If the encoder is in VBR mode GetStreamCaps() isn't implemented
1968     MPEG_ENCODER_CONFIG mec;
1969     m_pFilter->m_Encoder.GetOutputType(&mec);
1970     if (mec.vmVariable != vbr_off) return E_NOTIMPL;
1971 
1972     if (iIndex < 0) return E_INVALIDARG;
1973     if (iIndex > m_pFilter->m_CapsNum) return S_FALSE;
1974 
1975     // Load the MPEG Layer3 WaveFormatEx structure with the appropriate entries
1976     // for this IAMStreamConfig index element.
1977     *pmt = CreateMediaType(&m_mt);
1978     if (*pmt == NULL) return E_OUTOFMEMORY;
1979 
1980     DECLARE_PTR(MPEGLAYER3WAVEFORMAT, p_mp3wvfmt, (*pmt)->pbFormat);
1981 
1982     (*pmt)->majortype = MEDIATYPE_Audio;
1983     (*pmt)->subtype = MEDIASUBTYPE_MP3;
1984     (*pmt)->bFixedSizeSamples = TRUE;
1985     (*pmt)->bTemporalCompression = FALSE;
1986     (*pmt)->lSampleSize = OUT_BUFFER_SIZE;
1987     (*pmt)->formattype = FORMAT_WaveFormatEx;
1988     (*pmt)->cbFormat = sizeof(MPEGLAYER3WAVEFORMAT);
1989 
1990     p_mp3wvfmt->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3;
1991     p_mp3wvfmt->wfx.nChannels = 2;
1992     p_mp3wvfmt->wfx.nSamplesPerSec = m_pFilter->OutputCaps[iIndex].nSampleRate;
1993     p_mp3wvfmt->wfx.nAvgBytesPerSec = GET_DATARATE(m_pFilter->OutputCaps[iIndex].nBitRate);
1994     p_mp3wvfmt->wfx.nBlockAlign = 1;
1995     p_mp3wvfmt->wfx.wBitsPerSample = 0;
1996     p_mp3wvfmt->wfx.cbSize = sizeof(MPEGLAYER3WAVEFORMAT) - sizeof(WAVEFORMATEX);
1997 
1998     p_mp3wvfmt->wID = MPEGLAYER3_ID_MPEG;
1999     p_mp3wvfmt->fdwFlags = MPEGLAYER3_FLAG_PADDING_ISO;
2000     p_mp3wvfmt->nBlockSize = GET_FRAMELENGTH(m_pFilter->OutputCaps[iIndex].nBitRate, m_pFilter->OutputCaps[iIndex].nSampleRate);
2001     p_mp3wvfmt->nFramesPerBlock = 1;
2002     p_mp3wvfmt->nCodecDelay = 0;
2003 
2004     // Set up the companion AUDIO_STREAM_CONFIG_CAPS structure
2005     // We are only using the CHANNELS element of the structure
2006     DECLARE_PTR(AUDIO_STREAM_CONFIG_CAPS, pascc, pSCC);
2007 
2008     ZeroMemory(pascc, sizeof(AUDIO_STREAM_CONFIG_CAPS));
2009     pascc->guid = MEDIATYPE_Audio;
2010 
2011     pascc->MinimumChannels = 1;
2012     pascc->MaximumChannels = 2;
2013     pascc->ChannelsGranularity = 1;
2014 
2015     pascc->MinimumSampleFrequency = p_mp3wvfmt->wfx.nSamplesPerSec;
2016     pascc->MaximumSampleFrequency = p_mp3wvfmt->wfx.nSamplesPerSec;
2017     pascc->SampleFrequencyGranularity = 0;
2018 
2019     pascc->MinimumBitsPerSample = p_mp3wvfmt->wfx.wBitsPerSample;
2020     pascc->MaximumBitsPerSample = p_mp3wvfmt->wfx.wBitsPerSample;
2021     pascc->BitsPerSampleGranularity = 0;
2022 
2023     return S_OK;
2024 }
2025 
2026