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