/*
* (C) 2003-2006 Gabest
* (C) 2006-2015 see Authors.txt
*
* This file is part of MPC-HC.
*
* MPC-HC 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.
*
* MPC-HC 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 "AVI2AC3Filter.h"
#include "../../../DSUtil/DSUtil.h"
#ifdef STANDALONE_FILTER
#include
#endif
#include "moreuuids.h"
#ifdef STANDALONE_FILTER
const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = {
{&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DOLBY_AC3},
{&MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DTS},
};
const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = {
{&MEDIATYPE_Audio, &MEDIASUBTYPE_NULL},
};
const AMOVIESETUP_PIN sudpPins[] = {
{L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesIn), sudPinTypesIn},
{L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(sudPinTypesOut), sudPinTypesOut}
};
const AMOVIESETUP_FILTER sudFilter[] = {
{&__uuidof(CAVI2AC3Filter), AVI2AC3FilterName, MERIT_NORMAL, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory}
};
CFactoryTemplate g_Templates[] = {
{sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}
};
int g_cTemplates = _countof(g_Templates);
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2(TRUE);
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2(FALSE);
}
#include "../../FilterApp.h"
CFilterApp theApp;
#endif
//
// CAVI2AC3Filter
//
CAVI2AC3Filter::CAVI2AC3Filter(LPUNKNOWN lpunk, HRESULT* phr)
: CTransformFilter(NAME("CAVI2AC3Filter"), lpunk, __uuidof(this))
{
if (phr) {
*phr = S_OK;
}
}
CAVI2AC3Filter::~CAVI2AC3Filter()
{
}
HRESULT CAVI2AC3Filter::Transform(IMediaSample* pSample, IMediaSample* pOutSample)
{
HRESULT hr;
BYTE* pIn = nullptr;
if (FAILED(hr = pSample->GetPointer(&pIn))) {
return hr;
}
BYTE* pInOrg = pIn;
long len = pSample->GetActualDataLength();
if (len <= 0) {
return S_FALSE;
}
BYTE* pOut = nullptr;
if (FAILED(hr = pOutSample->GetPointer(&pOut))) {
return hr;
}
BYTE* pOutOrg = pOut;
long size = pOutSample->GetSize();
if ((CheckAC3(&m_pInput->CurrentMediaType()) || CheckDTS(&m_pInput->CurrentMediaType()))
&& (CheckWAVEAC3(&m_pOutput->CurrentMediaType()) || CheckWAVEDTS(&m_pOutput->CurrentMediaType()))) {
if (*(DWORD*)pIn == 0xBA010000) {
pIn += 14;
}
if (*(DWORD*)pIn == 0xBD010000) {
pIn += 8 + 1 + pIn[8] + 1 + 3;
}
len -= long(pInOrg - pIn);
if (size < len) {
return E_FAIL;
}
memcpy(pOut, pIn, len);
pOut += len;
} else if ((CheckWAVEAC3(&m_pInput->CurrentMediaType()) || CheckWAVEDTS(&m_pInput->CurrentMediaType()))
&& (CheckAC3(&m_pOutput->CurrentMediaType()) || CheckDTS(&m_pOutput->CurrentMediaType()))) {
if ((m_pOutput->CurrentMediaType().majortype == MEDIATYPE_DVD_ENCRYPTED_PACK
|| m_pOutput->CurrentMediaType().majortype == MEDIATYPE_MPEG2_PES)
&& (len + 12 + 3) >= 0x10000) { // damn, this can happen if the interleave time is too big
REFERENCE_TIME rtStart = 0, rtStop = 1;
bool fHasTime = (S_OK == pSample->GetTime(&rtStart, &rtStop));
bool fDiscontinuity = (S_OK == pOutSample->IsDiscontinuity());
long pos = 0;
while (pos < len) {
int curlen = std::min(len - pos, 2013l);
pos += 2013;
CComPtr pNewOutSample;
hr = InitializeOutputSample(pSample, &pNewOutSample);
if (fDiscontinuity) {
if (fHasTime) {
rtStop = rtStart + (rtStop - rtStart) * curlen / len;
pNewOutSample->SetTime(&rtStart, &rtStop);
}
fDiscontinuity = false;
} else {
pNewOutSample->SetTime(nullptr, nullptr);
pNewOutSample->SetDiscontinuity(FALSE);
}
BYTE* pNewOut = nullptr;
if (FAILED(hr = pNewOutSample->GetPointer(&pNewOut))) {
return hr;
}
BYTE* pNewOutOrg = pNewOut;
long newSize = pNewOutSample->GetSize();
const GUID* majortype = &m_pOutput->CurrentMediaType().majortype;
const GUID* subtype = &m_pOutput->CurrentMediaType().subtype;
if (*majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) {
if (newSize < curlen + 32 + 3) {
return E_FAIL;
}
BYTE PESHeader[] = {
0x00, 0x00, 0x01, 0xBA, // PES id
0x44, 0x00, 0x04, 0x00, 0x04, 0x01, // SCR (0)
0x01, 0x89, 0xC3, 0xF8, // mux rate (1260000 bytes/sec, 22bits), marker (2bits), reserved (~0, 5bits), stuffing (0, 3bits)
};
memcpy(pNewOut, &PESHeader, sizeof(PESHeader));
pNewOut += sizeof(PESHeader);
majortype = &MEDIATYPE_MPEG2_PES;
}
if (*majortype == MEDIATYPE_MPEG2_PES) {
if (newSize < curlen + 20 + 3) {
return E_FAIL;
}
BYTE Private1Header[] = {
0x00, 0x00, 0x01, 0xBD, // private stream 1 id
0x07, 0xEC, // packet length (TODO: modify it later)
0x81, 0x80, // marker, original, PTS - flags
0x08, // packet data starting offset
0x21, 0x00, 0x01, 0x00, 0x01, // PTS (0)
0xFF, 0xFF, 0xFF, // stuffing
0x80, // stream id (0)
0x01, 0x00, 0x01, // no idea about the first byte, the sencond+third seem to show the ac3/dts header sync offset plus one (dvd2avi doesn't output it to the ac3/dts file so we have to put it back)
};
int packetlen = curlen + 12 + 3;
ASSERT(packetlen <= 0xffff);
Private1Header[4] = (packetlen >> 8) & 0xff;
Private1Header[5] = packetlen & 0xff;
if (*subtype == MEDIASUBTYPE_DTS) {
Private1Header[17] += 8;
}
if (*subtype == MEDIASUBTYPE_DOLBY_AC3) {
for (int i = 0; i < curlen; i++) {
if (*(DWORD*)&pIn[i] == 0x770B) {
i++;
Private1Header[19] = (i >> 8) & 0xff;
Private1Header[20] = i & 0xff;
break;
}
}
} else if (*subtype == MEDIASUBTYPE_DTS) {
for (int i = 0; i < curlen; i++) {
if (*(DWORD*)&pIn[i] == 0x0180FE7F) {
i++;
Private1Header[19] = (i >> 8) & 0xff;
Private1Header[20] = i & 0xff;
break;
}
}
}
memcpy(pNewOut, &Private1Header, sizeof(Private1Header));
pNewOut += sizeof(Private1Header);
majortype = &MEDIATYPE_Audio;
}
if (*majortype == MEDIATYPE_Audio) {
if (newSize < curlen) {
return E_FAIL;
}
memcpy(pNewOut, pIn, curlen);
pIn += curlen;
pNewOut += curlen;
}
pNewOutSample->SetActualDataLength(long(pNewOut - pNewOutOrg));
m_pOutput->Deliver(pNewOutSample);
}
return S_FALSE;
} else { // phew, we can do the easier way
const GUID* majortype = &m_pOutput->CurrentMediaType().majortype;
const GUID* subtype = &m_pOutput->CurrentMediaType().subtype;
if (*majortype == MEDIATYPE_DVD_ENCRYPTED_PACK) {
if (size < len + 32 + 3) {
return E_FAIL;
}
BYTE PESHeader[] = {
0x00, 0x00, 0x01, 0xBA, // PES id
0x44, 0x00, 0x04, 0x00, 0x04, 0x01, // SCR (0)
0x01, 0x89, 0xC3, 0xF8, // mux rate (1260000 bytes/sec, 22bits), marker (2bits), reserved (~0, 5bits), stuffing (0, 3bits)
};
memcpy(pOut, &PESHeader, sizeof(PESHeader));
pOut += sizeof(PESHeader);
majortype = &MEDIATYPE_MPEG2_PES;
}
if (*majortype == MEDIATYPE_MPEG2_PES) {
if (size < len + 20 + 3) {
return E_FAIL;
}
BYTE Private1Header[] = {
0x00, 0x00, 0x01, 0xBD, // private stream 1 id
0x07, 0xEC, // packet length (TODO: modify it later)
0x81, 0x80, // marker, original, PTS - flags
0x08, // packet data starting offset
0x21, 0x00, 0x01, 0x00, 0x01, // PTS (0)
0xFF, 0xFF, 0xFF, // stuffing
0x80, // stream id (0)
0x01, 0x00, 0x01, // no idea about the first byte, the sencond+third seem to show the ac3/dts header sync offset plus one (dvd2avi doesn't output it to the ac3/dts file so we have to put it back)
};
int packetlen = len + 12 + 3;
ASSERT(packetlen <= 0xffff);
Private1Header[4] = (packetlen >> 8) & 0xff;
Private1Header[5] = packetlen & 0xff;
if (*subtype == MEDIASUBTYPE_DTS) {
Private1Header[17] += 8;
}
memcpy(pOut, &Private1Header, sizeof(Private1Header));
pOut += sizeof(Private1Header);
majortype = &MEDIATYPE_Audio;
}
if (*majortype == MEDIATYPE_Audio) {
if (size < len) {
return E_FAIL;
}
memcpy(pOut, pIn, len);
pIn += len;
pOut += len;
}
}
} else {
return E_FAIL;
}
pOutSample->SetActualDataLength(int(pOut - pOutOrg));
return S_OK;
}
bool CAVI2AC3Filter::CheckAC3(const CMediaType* pmt)
{
return (pmt->majortype == MEDIATYPE_Audio
|| pmt->majortype == MEDIATYPE_MPEG2_PES
|| pmt->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK)
&& pmt->subtype == MEDIASUBTYPE_DOLBY_AC3;
}
bool CAVI2AC3Filter::CheckDTS(const CMediaType* pmt)
{
return (pmt->majortype == MEDIATYPE_Audio
|| pmt->majortype == MEDIATYPE_MPEG2_PES
|| pmt->majortype == MEDIATYPE_DVD_ENCRYPTED_PACK)
&& pmt->subtype == MEDIASUBTYPE_DTS;
}
bool CAVI2AC3Filter::CheckWAVEAC3(const CMediaType* pmt)
{
return pmt->majortype == MEDIATYPE_Audio
&& pmt->subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3
&& pmt->formattype == FORMAT_WaveFormatEx
&& ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_DOLBY_AC3;
}
bool CAVI2AC3Filter::CheckWAVEDTS(const CMediaType* pmt)
{
return pmt->majortype == MEDIATYPE_Audio
&& pmt->subtype == MEDIASUBTYPE_WAVE_DTS
&& pmt->formattype == FORMAT_WaveFormatEx
&& ((WAVEFORMATEX*)pmt->pbFormat)->wFormatTag == WAVE_FORMAT_DVD_DTS;
}
HRESULT CAVI2AC3Filter::CheckInputType(const CMediaType* mtIn)
{
bool fWaveFormatEx = !!(mtIn->formattype == FORMAT_WaveFormatEx);
return CheckAC3(mtIn) && fWaveFormatEx || CheckDTS(mtIn) && fWaveFormatEx
|| CheckWAVEAC3(mtIn) || CheckWAVEDTS(mtIn)
? S_OK
: VFW_E_TYPE_NOT_ACCEPTED;
}
HRESULT CAVI2AC3Filter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
{
return CheckAC3(mtIn) && CheckWAVEAC3(mtOut)
|| CheckWAVEAC3(mtIn) && CheckAC3(mtOut)
|| CheckDTS(mtIn) && CheckWAVEDTS(mtOut)
|| CheckWAVEDTS(mtIn) && CheckDTS(mtOut)
? S_OK
: VFW_E_TYPE_NOT_ACCEPTED;
}
HRESULT CAVI2AC3Filter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
{
if (m_pInput->IsConnected() == FALSE) {
return E_UNEXPECTED;
}
CComPtr pAllocatorIn;
m_pInput->GetAllocator(&pAllocatorIn);
if (!pAllocatorIn) {
return E_UNEXPECTED;
}
pAllocatorIn->GetProperties(pProperties);
pProperties->cBuffers = 2;
pProperties->cbBuffer = std::max(pProperties->cbBuffer, 1024l * 1024l); // this should be enough...
pProperties->cbAlign = 1;
pProperties->cbPrefix = 0;
HRESULT hr;
ALLOCATOR_PROPERTIES Actual;
if (FAILED(hr = pAllocator->SetProperties(pProperties, &Actual))) {
return hr;
}
return (pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
? E_FAIL
: NOERROR);
}
HRESULT CAVI2AC3Filter::GetMediaType(int iPosition, CMediaType* pMediaType)
{
if (m_pInput->IsConnected() == FALSE) {
return E_UNEXPECTED;
}
const GUID& majortype = m_pInput->CurrentMediaType().majortype;
const GUID& subtype = m_pInput->CurrentMediaType().subtype;
UNREFERENCED_PARAMETER(majortype);
if (CheckAC3(&m_pInput->CurrentMediaType()) || CheckDTS(&m_pInput->CurrentMediaType())) {
if (iPosition < 0) {
return E_INVALIDARG;
}
if (iPosition > 0) {
return VFW_S_NO_MORE_ITEMS;
}
pMediaType->majortype = MEDIATYPE_Audio;
pMediaType->formattype = FORMAT_WaveFormatEx;
WAVEFORMATEX* wfe = (WAVEFORMATEX*)pMediaType->AllocFormatBuffer(sizeof(WAVEFORMATEX));
ZeroMemory(wfe, sizeof(WAVEFORMATEX));
wfe->cbSize = sizeof(WAVEFORMATEX);
wfe->nAvgBytesPerSec = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->nAvgBytesPerSec;
wfe->nSamplesPerSec = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->nSamplesPerSec;
wfe->wBitsPerSample = ((WAVEFORMATEX*)m_pInput->CurrentMediaType().pbFormat)->wBitsPerSample;
wfe->nChannels = 2;
wfe->nBlockAlign = 1;
if (subtype == MEDIASUBTYPE_DOLBY_AC3) {
pMediaType->subtype = MEDIASUBTYPE_WAVE_DOLBY_AC3;
wfe->wFormatTag = WAVE_FORMAT_DOLBY_AC3;
} else if (subtype == MEDIASUBTYPE_DTS) {
pMediaType->subtype = MEDIASUBTYPE_WAVE_DTS;
wfe->wFormatTag = WAVE_FORMAT_DVD_DTS;
} else {
return E_INVALIDARG;
}
} else if (CheckWAVEAC3(&m_pInput->CurrentMediaType()) || CheckWAVEDTS(&m_pInput->CurrentMediaType())) {
if (iPosition < 0) {
return E_INVALIDARG;
}
if (iPosition > 4) {
return VFW_S_NO_MORE_ITEMS;
}
if (subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3) {
pMediaType->subtype = MEDIASUBTYPE_DOLBY_AC3;
pMediaType->formattype = FORMAT_WaveFormatEx;
DOLBYAC3WAVEFORMAT* wfe = (DOLBYAC3WAVEFORMAT*)pMediaType->AllocFormatBuffer(sizeof(DOLBYAC3WAVEFORMAT));
ZeroMemory(wfe, sizeof(DOLBYAC3WAVEFORMAT));
// unfortunately we can't tell what we are going to get in transform,
// so we just set the most common values and hope that the ac3 decoder
// is flexible enough (it is usually :) to find out these from the bitstream
wfe->wfx.cbSize = sizeof(DOLBYAC3WAVEFORMAT) - sizeof(WAVEFORMATEX);
wfe->wfx.wFormatTag = WAVE_FORMAT_DOLBY_AC3;
wfe->wfx.nSamplesPerSec = 48000;
wfe->wfx.nChannels = 6;
wfe->bBigEndian = TRUE;
} else if (subtype == MEDIASUBTYPE_WAVE_DTS) {
pMediaType->subtype = MEDIASUBTYPE_DTS;
pMediaType->formattype = FORMAT_WaveFormatEx;
WAVEFORMATEX* wfe = (WAVEFORMATEX*)pMediaType->AllocFormatBuffer(sizeof(WAVEFORMATEX));
ZeroMemory(wfe, sizeof(WAVEFORMATEX));
// same case as with ac3, but this time we don't even know the structure
wfe->cbSize = sizeof(WAVEFORMATEX);
wfe->wFormatTag = WAVE_FORMAT_PCM;
wfe->nSamplesPerSec = 48000;
wfe->nChannels = 6;
} else {
return E_INVALIDARG;
}
switch (iPosition) {
case 0:
pMediaType->majortype = MEDIATYPE_Audio;
break;
case 1:
pMediaType->ResetFormatBuffer();
pMediaType->formattype = FORMAT_None;
// no break
case 2:
pMediaType->majortype = MEDIATYPE_MPEG2_PES;
break;
case 3:
pMediaType->ResetFormatBuffer();
pMediaType->formattype = FORMAT_None;
// no break
case 4:
pMediaType->majortype = MEDIATYPE_DVD_ENCRYPTED_PACK;
break;
default:
ASSERT(FALSE); // Shouldn't happen
return E_INVALIDARG;
}
} else {
return VFW_S_NO_MORE_ITEMS;
}
return S_OK;
}