📄 mpegac.cpp
字号:
/* * LAME MP3 encoder for DirectShow * DirectShow filter implementation * * Copyright (c) 2000-2005 Marie Orlova, Peter Gubanov, Vitaly Ivanov, Elecard Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include <streams.h>#include <olectl.h>#include <initguid.h>//#include <olectlid.h>#include "uids.h"#include "iaudioprops.h"#include "mpegac.h"#include "resource.h"#include "PropPage.h"#include "PropPage_adv.h"#include "aboutprp.h"#include "Encoder.h"#include "Reg.h"#ifndef _INC_MMREG#include <mmreg.h>#endif// default parameters#define DEFAULT_LAYER 3#define DEFAULT_STEREO_MODE JOINT_STEREO#define DEFAULT_FORCE_MS 0#define DEFAULT_MODE_FIXED 0#define DEFAULT_ENFORCE_MIN 0#define DEFAULT_VOICE 0#define DEFAULT_KEEP_ALL_FREQ 0#define DEFAULT_STRICT_ISO 0#define DEFAULT_DISABLE_SHORT_BLOCK 0#define DEFAULT_XING_TAG 0#define DEFAULT_SAMPLE_RATE 44100#define DEFAULT_BITRATE 128#define DEFAULT_VARIABLE 0#define DEFAULT_CRC 0#define DEFAULT_FORCE_MONO 0#define DEFAULT_SET_DURATION 1#define DEFAULT_COPYRIGHT 0#define DEFAULT_ORIGINAL 0#define DEFAULT_VARIABLEMIN 80#define DEFAULT_VARIABLEMAX 160#define DEFAULT_ENCODING_QUALITY 5#define DEFAULT_VBR_QUALITY 4#define DEFAULT_PES 0/* Registration setup stuff */// Setup dataAMOVIESETUP_MEDIATYPE sudMpgInputType[] ={ { &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM }};AMOVIESETUP_MEDIATYPE sudMpgOutputType[] ={ { &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1AudioPayload }, { &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG2_AUDIO },};AMOVIESETUP_PIN sudMpgPins[3] ={ { L"PCM Input", FALSE, // bRendered FALSE, // bOutput FALSE, // bZero FALSE, // bMany &CLSID_NULL, // clsConnectsToFilter NULL, // ConnectsToPin NUMELMS(sudMpgInputType), // Number of media types sudMpgInputType }, { L"MPEG Output", FALSE, // bRendered TRUE, // bOutput FALSE, // bZero FALSE, // bMany &CLSID_NULL, // clsConnectsToFilter NULL, // ConnectsToPin NUMELMS(sudMpgOutputType), // Number of media types sudMpgOutputType }};AMOVIESETUP_FILTER sudMpgAEnc ={ &CLSID_LAMEDShowFilter, L"LAME Audio Encoder", MERIT_SW_COMPRESSOR, // Don't use us for real! NUMELMS(sudMpgPins), // 3 pins sudMpgPins};/*****************************************************************************/// COM Global table of objects in this dllCFactoryTemplate g_Templates[] = { { L"LAME Audio Encoder", &CLSID_LAMEDShowFilter, CMpegAudEnc::CreateInstance, NULL, &sudMpgAEnc }, { L"LAME Audio Encoder Property Page", &CLSID_LAMEDShow_PropertyPage, CMpegAudEncPropertyPage::CreateInstance}, { L"LAME Audio Encoder Property Page", &CLSID_LAMEDShow_PropertyPageAdv, CMpegAudEncPropertyPageAdv::CreateInstance}, { L"LAME Audio Encoder About", &CLSID_LAMEDShow_About, CMAEAbout::CreateInstance}};// Count of objects listed in g_cTemplatesint g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);CUnknown *CMpegAudEnc::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr) { CUnknown *punk = new CMpegAudEnc(lpunk, phr); if (punk == NULL) *phr = E_OUTOFMEMORY; return punk;}CMpegAudEnc::CMpegAudEnc(LPUNKNOWN lpunk, HRESULT *phr) : CTransformFilter(NAME("LAME Audio Encoder"), lpunk, CLSID_LAMEDShowFilter), CPersistStream(lpunk, phr){ MPEG_ENCODER_CONFIG mec; ReadPresetSettings(&mec); m_Encoder.SetOutputType(mec); m_hasFinished = TRUE;}CMpegAudEnc::~CMpegAudEnc(void){}LPAMOVIESETUP_FILTER CMpegAudEnc::GetSetupData(){ return &sudMpgAEnc;}HRESULT CMpegAudEnc::Receive(IMediaSample * pSample){ CAutoLock lock(&m_cs); if (!pSample) return S_OK; BYTE * pSourceBuffer = NULL; if (pSample->GetPointer(&pSourceBuffer) != S_OK || !pSourceBuffer) return S_OK; long sample_size = pSample->GetActualDataLength(); REFERENCE_TIME rtStart, rtStop; BOOL gotValidTime = (pSample->GetTime(&rtStart, &rtStop) != VFW_E_SAMPLE_TIME_NOT_SET); if (sample_size <= 0 || pSourceBuffer == NULL || m_hasFinished || (gotValidTime && rtStart < 0)) return S_OK; if (gotValidTime) { if (m_rtStreamTime < 0) { m_rtStreamTime = rtStart; m_rtEstimated = rtStart; } else { resync_point_t * sync = m_sync + m_sync_in_idx; // if old sync data is applied and gap is greater than 1 ms // then make a new synchronization point if (sync->applied && (rtStart - m_rtEstimated > 10000)) { sync->sample = m_samplesIn; sync->delta = rtStart - m_rtEstimated; sync->applied = FALSE; m_rtEstimated += sync->delta; if (m_sync_in_idx < (RESYNC_COUNT - 1)) m_sync_in_idx++; else m_sync_in_idx = 0; } } } m_rtEstimated += (LONGLONG)(m_bytesToDuration * sample_size); m_samplesIn += sample_size / m_bytesPerSample; while (sample_size > 0) { int bytes_processed = m_Encoder.Encode((short *)pSourceBuffer, sample_size); if (bytes_processed <= 0) return S_OK; FlushEncodedSamples(); sample_size -= bytes_processed; pSourceBuffer += bytes_processed; } return S_OK;}HRESULT CMpegAudEnc::FlushEncodedSamples(){ IMediaSample * pOutSample = NULL; BYTE * pDst = NULL; if (m_rtStreamTime < 0) m_rtStreamTime = 0; while (1) { const unsigned char * pframe = NULL; int frame_size = m_Encoder.GetFrame(&pframe); if (frame_size <= 0 || !pframe) break; if (!m_sync[m_sync_out_idx].applied && m_sync[m_sync_out_idx].sample <= m_samplesOut) { m_rtStreamTime += m_sync[m_sync_out_idx].delta; m_sync[m_sync_out_idx].applied = TRUE; if (m_sync_out_idx < (RESYNC_COUNT - 1)) m_sync_out_idx++; else m_sync_out_idx = 0; } REFERENCE_TIME rtStart = m_rtStreamTime; REFERENCE_TIME rtStop = rtStart + m_rtFrameTime; HRESULT hr = m_pOutput->GetDeliveryBuffer(&pOutSample, NULL, NULL, 0); if (hr == S_OK && pOutSample) { hr = pOutSample->GetPointer(&pDst); if (hr == S_OK && pDst) { CopyMemory(pDst, pframe, frame_size); pOutSample->SetSyncPoint(TRUE); pOutSample->SetActualDataLength(frame_size); pOutSample->SetTime(&rtStart, m_setDuration ? &rtStop : NULL); m_pOutput->Deliver(pOutSample); } pOutSample->Release(); } m_samplesOut += m_samplesPerFrame; m_rtStreamTime = rtStop; } return S_OK;}////////////////////////////////////////////////////////////////////////////// StartStreaming - prepare to receive new data////////////////////////////////////////////////////////////////////////////HRESULT CMpegAudEnc::StartStreaming(){ WAVEFORMATEX * pwfxOut = (WAVEFORMATEX *) m_pOutput->CurrentMediaType().Format(); WAVEFORMATEX * pwfxIn = (WAVEFORMATEX *) m_pInput->CurrentMediaType().Format(); m_bytesPerSample = pwfxIn->nChannels * sizeof(short); m_samplesPerFrame = (pwfxOut->nSamplesPerSec >= 32000) ? 1152 : 576; m_rtFrameTime = MulDiv(10000000, m_samplesPerFrame, pwfxOut->nSamplesPerSec); m_samplesIn = m_samplesOut = 0; m_rtStreamTime = -1; // initialize encoder m_Encoder.Init(); m_hasFinished = FALSE; for (int i = 0; i < RESYNC_COUNT; i++) { m_sync[i].sample = 0; m_sync[i].delta = 0; m_sync[i].applied = TRUE; } m_sync_in_idx = 0; m_sync_out_idx = 0; get_SetDuration(&m_setDuration); return S_OK;}HRESULT CMpegAudEnc::StopStreaming(){ m_Encoder.Close(); return S_OK;}////////////////////////////////////////////////////////////////////////////// EndOfStream - stop data processing ////////////////////////////////////////////////////////////////////////////HRESULT CMpegAudEnc::EndOfStream(){ CAutoLock lock(&m_cs); // Flush data m_Encoder.Finish(); FlushEncodedSamples(); // Close encoder m_Encoder.Close(); m_hasFinished = TRUE; return CTransformFilter::EndOfStream();}////////////////////////////////////////////////////////////////////////////// BeginFlush - stop data processing ////////////////////////////////////////////////////////////////////////////HRESULT CMpegAudEnc::BeginFlush(){ HRESULT hr = CTransformFilter::BeginFlush(); if (SUCCEEDED(hr)) { CAutoLock lock(&m_cs); DWORD dwDstSize = 0; // Flush data m_Encoder.Finish(); FlushEncodedSamples(); m_rtStreamTime = -1; } return hr;}////////////////////////////////////////////////////////////////////////////// SetMediaType - called when filters are connecting////////////////////////////////////////////////////////////////////////////HRESULT CMpegAudEnc::SetMediaType(PIN_DIRECTION direction, const CMediaType * pmt){ HRESULT hr = S_OK; if (*pmt->FormatType() != FORMAT_WaveFormatEx) return VFW_E_INVALIDMEDIATYPE; if (pmt->FormatLength() < sizeof(WAVEFORMATEX)) return VFW_E_INVALIDMEDIATYPE; if (direction == PINDIR_INPUT) { DbgLog((LOG_TRACE,1,TEXT("CMpegAudEnc::SetMediaType(), direction = PINDIR_INPUT"))); // Pass input media type to encoder m_Encoder.SetInputType((LPWAVEFORMATEX)pmt->Format()); WAVEFORMATEX * pwfx = (WAVEFORMATEX *)pmt->Format(); if (pwfx) m_bytesToDuration = (float)1.e7 / (float)(pwfx->nChannels * sizeof(short) * pwfx->nSamplesPerSec); else m_bytesToDuration = 0.0; Reconnect(); } else if (direction == PINDIR_OUTPUT) { WAVEFORMATEX wfIn; m_Encoder.GetInputType(&wfIn); if (wfIn.nSamplesPerSec % ((LPWAVEFORMATEX)pmt->Format())->nSamplesPerSec != 0) return VFW_E_TYPE_NOT_ACCEPTED; } return hr;}////////////////////////////////////////////////////////////////////////////// CheckInputType - check if you can support mtIn////////////////////////////////////////////////////////////////////////////HRESULT CMpegAudEnc::CheckInputType(const CMediaType* mtIn){ if (*mtIn->Type() == MEDIATYPE_Audio && *mtIn->FormatType() == FORMAT_WaveFormatEx) if (mtIn->FormatLength() >= sizeof(WAVEFORMATEX)) if (mtIn->IsTemporalCompressed() == FALSE) return m_Encoder.SetInputType((LPWAVEFORMATEX)mtIn->Format(), true); return E_INVALIDARG;}////////////////////////////////////////////////////////////////////////////// CheckTransform - checks if we can support the transform from this input to this output////////////////////////////////////////////////////////////////////////////HRESULT CMpegAudEnc::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut){ if (*mtOut->FormatType() != FORMAT_WaveFormatEx) return VFW_E_INVALIDMEDIATYPE; if (mtOut->FormatLength() < sizeof(WAVEFORMATEX)) return VFW_E_INVALIDMEDIATYPE; MPEG_ENCODER_CONFIG mec; if(FAILED(m_Encoder.GetOutputType(&mec))) return S_OK; if (((LPWAVEFORMATEX)mtIn->Format())->nSamplesPerSec % mec.dwSampleRate != 0) return S_OK; if (mec.dwSampleRate != ((LPWAVEFORMATEX)mtOut->Format())->nSamplesPerSec) return VFW_E_TYPE_NOT_ACCEPTED; return S_OK;}////////////////////////////////////////////////////////////////////////////// DecideBufferSize - sets output buffers number and size////////////////////////////////////////////////////////////////////////////HRESULT CMpegAudEnc::DecideBufferSize( IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties){ HRESULT hr = S_OK; /// pProperties->cBuffers = 1; pProperties->cbBuffer = OUT_BUFFER_SIZE; // ASSERT(pProperties->cbBuffer); ALLOCATOR_PROPERTIES Actual; hr = pAllocator->SetProperties(pProperties,&Actual);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -