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