/*
* $Id$
*
* (C) 2006-2007 see AUTHORS
*
* This file is part of mplayerc.
*
* Mplayerc is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Mplayerc 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "stdafx.h"
#include
#include
#include
#include "PODtypes.h"
#include "avcodec.h"
#include "MPCAudioDecFilter.h"
#include "../../../DSUtil/DSUtil.h"
#include
#include
typedef struct
{
const CLSID* clsMinorType;
const enum CodecID nFFCodec;
const int fourcc;
} FFMPEG_CODECS;
const FFMPEG_CODECS ffCodecs[] =
{
// AMVA
{ &MEDIASUBTYPE_IMA_AMV, CODEC_ID_ADPCM_IMA_AMV, MAKEFOURCC('A','M','V','A') },
};
const AMOVIESETUP_MEDIATYPE CMPCAudioDecFilter::sudPinTypesIn[] =
{
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_IMA_AMV },
};
const int CMPCAudioDecFilter::sudPinTypesInCount = countof(CMPCAudioDecFilter::sudPinTypesIn);
const AMOVIESETUP_MEDIATYPE CMPCAudioDecFilter::sudPinTypesOut[] =
{
{&MEDIATYPE_Audio, &MEDIASUBTYPE_PCM}
};
const int CMPCAudioDecFilter::sudPinTypesOutCount = countof(CMPCAudioDecFilter::sudPinTypesOut);
CMPCAudioDecFilter::CMPCAudioDecFilter(LPUNKNOWN lpunk, HRESULT* phr)
: CTransformFilter(NAME("CMPCAudioDecFilter"), lpunk, __uuidof(this))
{
if(!(m_pInput = new CTransformInputPin(NAME("CAudioDecInputPin"), this, phr, L"In"))) *phr = E_OUTOFMEMORY;
if(FAILED(*phr)) return;
if(!(m_pOutput = new CTransformOutputPin(NAME("CAudioDecOutputPin"), this, phr, L"Out"))) *phr = E_OUTOFMEMORY;
if(FAILED(*phr)) {
delete m_pInput, m_pInput = NULL;
return;
}
m_iSampleFormat = SAMPLE_FMT_S16;
m_pAVCodec = NULL;
m_pAVCtx = NULL;
m_pFrame = NULL;
m_nCodecNb = -1;
avcodec_init();
avcodec_register_all();
av_log_set_callback(LogLibAVCodec);
}
CMPCAudioDecFilter::~CMPCAudioDecFilter(void)
{
Cleanup();
}
void CMPCAudioDecFilter::Cleanup()
{
if (m_pAVCtx)
{
avcodec_thread_free (m_pAVCtx);
av_free(m_pAVCtx);
}
if (m_pFrame) av_free(m_pFrame);
m_pAVCodec = NULL;
m_pAVCtx = NULL;
m_pFrame = NULL;
m_nCodecNb = -1;
}
void CMPCAudioDecFilter::LogLibAVCodec(void* par,int level,const char *fmt,va_list valist)
{
#ifdef _DEBUG
//AVCodecContext* m_pAVCtx = (AVCodecContext*) par;
//char Msg [500];
//snprintf (Msg, sizeof(Msg), fmt, valist);
//TRACE("AVLIB : %s", Msg);
#endif
}
STDMETHODIMP CMPCAudioDecFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
return
// QI(IMPCVideoDecFilter)
// QI(ISpecifyPropertyPages)
// QI(ISpecifyPropertyPages2)
__super::NonDelegatingQueryInterface(riid, ppv);
}
HRESULT CMPCAudioDecFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
{
return SUCCEEDED(CheckInputType(mtIn))
&& mtOut->majortype == MEDIATYPE_Audio && mtOut->subtype == MEDIASUBTYPE_PCM
|| mtOut->majortype == MEDIATYPE_Audio && mtOut->subtype == MEDIASUBTYPE_IEEE_FLOAT
? S_OK
: VFW_E_TYPE_NOT_ACCEPTED;
}
HRESULT CMPCAudioDecFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
{
return S_OK;
}
HRESULT CMPCAudioDecFilter::CheckInputType(const CMediaType* mtIn)
{
for (int i=0; imajortype == *sudPinTypesIn[i].clsMajorType) &&
(mtIn->subtype == *sudPinTypesIn[i].clsMinorType))
return S_OK;
}
return VFW_E_TYPE_NOT_ACCEPTED;
}
HRESULT CMPCAudioDecFilter::GetMediaType(int iPosition, CMediaType* pmt)
{
if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
if(iPosition < 0) return E_INVALIDARG;
if(iPosition > 0) return VFW_S_NO_MORE_ITEMS;
CMediaType mt = m_pInput->CurrentMediaType();
const GUID& subtype = mt.subtype;
WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format();
//if(GetSpeakerConfig(ac3) < 0 && (subtype == MEDIASUBTYPE_DOLBY_AC3 || subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3)
//|| GetSpeakerConfig(dts) < 0 && (subtype == MEDIASUBTYPE_DTS || subtype == MEDIASUBTYPE_WAVE_DTS))
//{
// *pmt = CreateMediaTypeSPDIF();
//}
//else if(subtype == MEDIASUBTYPE_Vorbis2)
//{
// *pmt = CreateMediaType(GetSampleFormat(), m_vorbis.vi.rate, m_vorbis.vi.channels);
//}
//else
//{
*pmt = CreateMediaType(GetSampleFormat(), wfe->nSamplesPerSec, min(2, wfe->nChannels));
//}
return S_OK;
}
HRESULT CMPCAudioDecFilter::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt)
{
return __super::SetMediaType(direction, pmt);
}
HRESULT CMPCAudioDecFilter::CompleteConnect(PIN_DIRECTION direction, IPin* pReceivePin)
{
int nNewCodec;
if (direction == PINDIR_OUTPUT)
{
CMediaType& mt = m_pInput->CurrentMediaType();
nNewCodec = FindCodec(&mt);
if ((direction == PINDIR_OUTPUT) && (nNewCodec != -1) && (nNewCodec != m_nCodecNb))
{
WAVEFORMATEX* wfex = (WAVEFORMATEX*) mt.pbFormat;
Cleanup();
m_nCodecNb = nNewCodec;
m_pInput->CurrentMediaType();
m_pAVCodec = avcodec_find_decoder(ffCodecs[nNewCodec].nFFCodec);
CheckPointer (m_pAVCodec, VFW_E_UNSUPPORTED_AUDIO);
m_pAVCtx = avcodec_alloc_context();
CheckPointer (m_pAVCtx, E_POINTER);
m_pAVCtx->sample_rate = wfex->nSamplesPerSec;
m_pAVCtx->channels = wfex->nChannels;
m_pAVCtx->bit_rate = wfex->nAvgBytesPerSec*8;
m_pAVCtx->bits_per_coded_sample = wfex->wBitsPerSample;
m_pAVCtx->block_align = wfex->nBlockAlign;
/*if (codecId==CODEC_ID_FLAC && extradata.size>=4 && *(FOURCC*)extradata.data==mmioFOURCC('f','L','a','C')) // HACK
{
avctx->extradata=extradata.data+8;
avctx->extradata_size=34;
}
else if (codecId==CODEC_ID_COOK && mt.formattype==FORMAT_WaveFormatEx && mt.pbFormat)
{
avctx->extradata=mt.pbFormat+sizeof(WAVEFORMATEX);
avctx->extradata_size=mt.cbFormat-sizeof(WAVEFORMATEX);
for (;avctx->extradata_size;avctx->extradata=(uint8_t*)avctx->extradata+1,avctx->extradata_size--)
if (memcmp(avctx->extradata,"cook",4)==0)
{
avctx->extradata=(uint8_t*)avctx->extradata+12;
avctx->extradata_size-=12;
break;
}
}
else
{
avctx->extradata=extradata.data;
avctx->extradata_size=(int)extradata.size;
}
if (codecId==CODEC_ID_VORBIS && mt.formattype==FORMAT_VorbisFormat2)
{
const VORBISFORMAT2 *vf2=(const VORBISFORMAT2*)mt.pbFormat;
avctx->vorbis_header_size[0]=vf2->HeaderSize[0];
avctx->vorbis_header_size[1]=vf2->HeaderSize[1];
avctx->vorbis_header_size[2]=vf2->HeaderSize[2];
}
if (libavcodec->avcodec_open(avctx,avcodec)<0) return false;
codecinited=true;
switch (avctx->sample_fmt)
{
case SAMPLE_FMT_S16:fmt.sf=TsampleFormat::SF_PCM16;break;
case SAMPLE_FMT_FLT:fmt.sf=TsampleFormat::SF_FLOAT32;break;
}
*/
if (avcodec_open(m_pAVCtx, m_pAVCodec)<0)
return VFW_E_INVALIDMEDIATYPE;
}
}
return __super::CompleteConnect (direction, pReceivePin);
}
HRESULT CMPCAudioDecFilter::Transform(IMediaSample* pIn)
{
HRESULT hr = S_OK;
//BYTE* pDataIn = NULL;
//UINT nSize;
//int got_picture;
//REFERENCE_TIME rtStart = _I64_MIN, rtStop = _I64_MIN;
//if(FAILED(hr = pIn->GetPointer(&pDataIn)))
// return hr;
//nSize = pIn->GetActualDataLength();
//hr = pIn->GetTime(&rtStart, &rtStop);
////FILE* File = fopen ("e:\\temp\\h264.bin", "wb");
////fwrite (pDataIn, nSize, 1, File);
////fclose (File);
//int used_bytes;
//m_pAVCtx->parserRtStart=&rtStart;
//
//while (nSize > 0)
//{
// used_bytes = avcodec_decode_video (m_pAVCtx, m_pFrame, &got_picture, pDataIn, nSize);
// if (!got_picture || !m_pFrame->data[0]) return S_FALSE;
// if(pIn->IsPreroll() == S_OK || rtStart < 0)
// return S_OK;
// CComPtr pOut;
// BYTE* pDataOut = NULL;
// if(FAILED(hr = GetDeliveryBuffer(m_pAVCtx->width, m_pAVCtx->height, &pOut)) || FAILED(hr = pOut->GetPointer(&pDataOut)))
// return hr;
// TRACE ("CMPCAudioDecFilter::Transform %I64d - %I64d\n", rtStart, rtStop);
// //rtStart = m_pFrame->rtStart;
// //rtStop = m_pFrame->rtStart + 1;
// pOut->SetTime(&rtStart, &rtStop);
// pOut->SetDiscontinuity(pIn->IsDiscontinuity() == S_OK);
// CopyBuffer(pDataOut, m_pFrame->data, m_pAVCtx->width, m_pAVCtx->height, m_pFrame->linesize[0], MEDIASUBTYPE_I420, false);
// hr = m_pOutput->Deliver(pOut);
// nSize -= used_bytes;
// pDataIn += used_bytes;
//}
return hr;
}
int CMPCAudioDecFilter::FindCodec(const CMediaType* mtIn)
{
for (int i=0; isubtype == *ffCodecs[i].clsMinorType)
return i;
return -1;
}
STDMETHODIMP_(SampleFormat) CMPCAudioDecFilter::GetSampleFormat()
{
// CAutoLock cAutoLock(&m_csProps);
return m_iSampleFormat;
}
CMediaType CMPCAudioDecFilter::CreateMediaType(SampleFormat sf, DWORD nSamplesPerSec, WORD nChannels, DWORD dwChannelMask)
{
CMediaType mt;
mt.majortype = MEDIATYPE_Audio;
mt.subtype = sf == SAMPLE_FMT_FLT ? MEDIASUBTYPE_IEEE_FLOAT : MEDIASUBTYPE_PCM;
mt.formattype = FORMAT_WaveFormatEx;
WAVEFORMATEXTENSIBLE wfex;
memset(&wfex, 0, sizeof(wfex));
WAVEFORMATEX* wfe = &wfex.Format;
wfe->wFormatTag = (WORD)mt.subtype.Data1;
wfe->nChannels = nChannels;
wfe->nSamplesPerSec = nSamplesPerSec;
switch(sf)
{
default:
case SAMPLE_FMT_S16:
wfe->wBitsPerSample = 16;
break;
case SAMPLE_FMT_S32:
case SAMPLE_FMT_FLT:
wfe->wBitsPerSample = 32;
break;
}
wfe->nBlockAlign = wfe->nChannels*wfe->wBitsPerSample/8;
wfe->nAvgBytesPerSec = wfe->nSamplesPerSec*wfe->nBlockAlign;
// FIXME: 32 bit only seems to work with WAVE_FORMAT_EXTENSIBLE
if(dwChannelMask == 0 && (sf == SAMPLE_FMT_S32))
dwChannelMask = nChannels == 2 ? (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) : SPEAKER_FRONT_CENTER;
if(dwChannelMask)
{
wfex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfex.Format.cbSize = sizeof(wfex) - sizeof(wfex.Format);
wfex.dwChannelMask = dwChannelMask;
wfex.Samples.wValidBitsPerSample = wfex.Format.wBitsPerSample;
wfex.SubFormat = mt.subtype;
}
mt.SetFormat((BYTE*)&wfex, sizeof(wfex.Format) + wfex.Format.cbSize);
return mt;
}