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