/*
* (C) 2003-2006 Gabest
* (C) 2006-2013 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
#include
#include
#include
#include "MpaDecFilter.h"
#include "AudioHelper.h"
#include "../../../DSUtil/DSUtil.h"
#include "../../../DSUtil/AudioParser.h"
#ifdef STANDALONE_FILTER
void* __imp_toupper = toupper;
#if defined(_WIN64)
void* __imp_time64 = _time64;
#endif
#include
extern "C" {
void __mingw_raise_matherr(int typ, const char* name, double a1, double a2, double rslt) {}
}
#endif // STANDALONE_FILTER
#include "moreuuids.h"
#include
#include "ffmpeg/libavcodec/avcodec.h"
// options names
#define OPT_REGKEY_MpaDec _T("Software\\Gabest\\Filters\\MPEG Audio Decoder")
#define OPT_SECTION_MpaDec _T("Filters\\MPEG Audio Decoder")
#define OPTION_SFormat_i16 _T("SampleFormat_int16")
#define OPTION_SFormat_i24 _T("SampleFormat_int24")
#define OPTION_SFormat_i32 _T("SampleFormat_int32")
#define OPTION_SFormat_flt _T("SampleFormat_float")
#define OPTION_Mixer _T("Mixer")
#define OPTION_MixerLayout _T("MixerLayout")
#define OPTION_DRC _T("DRC")
#define OPTION_SPDIF_ac3 _T("SPDIF_ac3")
#define OPTION_SPDIF_eac3 _T("HDMI_eac3")
#define OPTION_SPDIF_truehd _T("HDMI_truehd")
#define OPTION_SPDIF_dts _T("SPDIF_dts")
#define OPTION_SPDIF_dtshd _T("HDMI_dtshd")
#define MAX_JITTER 1400000i64 // +-140ms jitter is allowed for now
#define PADDING_SIZE FF_INPUT_BUFFER_PADDING_SIZE
#define BS_HEADER_SIZE 8
#define BS_AC3_SIZE 6144
#define BS_EAC3_SIZE 24576 // 6144 for DD Plus * 4 for IEC 60958 frames
#define BS_MAT_SIZE 61424 // max length of MAT data
#define BS_MAT_OFFSET 2560
#define BS_TRUEHD_SIZE 61440 // 8 header bytes + 61424 of MAT data + 8 zero byte
#define BS_DTSHD_SIZE 32768
const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = {
#if INTERNAL_DECODER_MPEGAUDIO
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_MP3 },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1AudioPayload },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1Payload },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1Packet },
{ &MEDIATYPE_DVD_ENCRYPTED_PACK, &MEDIASUBTYPE_MPEG2_AUDIO },
{ &MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_MPEG2_AUDIO },
{ &MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_MPEG2_AUDIO },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG2_AUDIO },
#endif
#if INTERNAL_DECODER_AC3
{ &MEDIATYPE_DVD_ENCRYPTED_PACK, &MEDIASUBTYPE_DOLBY_AC3 },
{ &MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_DOLBY_AC3 },
{ &MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_DOLBY_AC3 },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_DOLBY_AC3 },
{ &MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_DOLBY_DDPLUS },
{ &MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_DOLBY_DDPLUS },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_DOLBY_DDPLUS },
{ &MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_DOLBY_TRUEHD },
{ &MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_DOLBY_TRUEHD },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_DOLBY_TRUEHD },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DOLBY_AC3 },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_MLP },
#endif
#if INTERNAL_DECODER_DTS
{ &MEDIATYPE_DVD_ENCRYPTED_PACK, &MEDIASUBTYPE_DTS },
{ &MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_DTS },
{ &MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_DTS },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_DTS },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_WAVE_DTS },
#endif
#if INTERNAL_DECODER_LPCM
{ &MEDIATYPE_DVD_ENCRYPTED_PACK, &MEDIASUBTYPE_DVD_LPCM_AUDIO },
{ &MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_DVD_LPCM_AUDIO },
{ &MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_DVD_LPCM_AUDIO },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_DVD_LPCM_AUDIO },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_HDMV_LPCM_AUDIO },
#endif
#if INTERNAL_DECODER_AAC
{ &MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_AAC },
{ &MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_AAC },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_AAC },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_LATM_AAC },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_AAC_ADTS },
{ &MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_MP4A },
{ &MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_MP4A },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_MP4A },
{ &MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_mp4a },
{ &MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_mp4a },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_mp4a },
#endif
#if INTERNAL_DECODER_AMR
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_AMR },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_SAMR },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_SAWB },
#endif
#if INTERNAL_DECODER_PS2AUDIO
{ &MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_PS2_PCM },
{ &MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_PS2_PCM },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_PS2_PCM },
{ &MEDIATYPE_MPEG2_PACK, &MEDIASUBTYPE_PS2_ADPCM },
{ &MEDIATYPE_MPEG2_PES, &MEDIASUBTYPE_PS2_ADPCM },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_PS2_ADPCM },
#endif
#if INTERNAL_DECODER_VORBIS
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_Vorbis2 },
#endif
#if INTERNAL_DECODER_FLAC
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_FLAC_FRAMED },
#endif
#if INTERNAL_DECODER_NELLYMOSER
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_NELLYMOSER },
#endif
#if INTERNAL_DECODER_PCM
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM_NONE },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM_RAW },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM_TWOS },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM_SOWT },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM_IN24 },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM_IN32 },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM_FL32 },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_PCM_FL64 },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_IEEE_FLOAT }, // only for 64-bit float PCM
#endif
#if INTERNAL_DECODER_ADPCM
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_IMA4 },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_ADPCM_SWF },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_ADPCM_AMV },
#endif
#if INTERNAL_DECODER_REALAUDIO
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_14_4 },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_28_8 },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_ATRC },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_COOK },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_DNET },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_SIPR },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_RAAC },
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_RACP },
#endif
#if INTERNAL_DECODER_ALAC
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_ALAC },
#endif
#if INTERNAL_DECODER_ALS
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_ALS },
#endif
#if !HAS_OTHER_AUDIO_DECODERS && !HAS_FFMPEG_AUDIO_DECODERS
{ &MEDIATYPE_Audio, &MEDIASUBTYPE_None } // just to prevent compilation error
#endif
};
#ifdef STANDALONE_FILTER
const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = {
{&MEDIATYPE_Audio, &MEDIASUBTYPE_PCM},
};
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(CMpaDecFilter), MPCAudioDecName, /*MERIT_DO_NOT_USE*/0x40000001, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory},
};
CFactoryTemplate g_Templates[] = {
{sudFilter[0].strName, &__uuidof(CMpaDecFilter), CreateInstance, nullptr, &sudFilter[0]},
{L"CMpaDecPropertyPage", &__uuidof(CMpaDecSettingsWnd), CreateInstance>},
};
int g_cTemplates = _countof(g_Templates);
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2(TRUE);
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2(FALSE);
}
//
#include "../../FilterApp.h"
CFilterApp theApp;
#endif
enum {
IEC61937_AC3 = 0x01, ///< AC-3 data
IEC61937_MPEG1_LAYER1 = 0x04, ///< MPEG-1 layer 1
IEC61937_MPEG1_LAYER23 = 0x05, ///< MPEG-1 layer 2 or 3 data or MPEG-2 without extension
IEC61937_MPEG2_EXT = 0x06, ///< MPEG-2 data with extension
IEC61937_MPEG2_AAC = 0x07, ///< MPEG-2 AAC ADTS
IEC61937_MPEG2_LAYER1_LSF = 0x08, ///< MPEG-2, layer-1 low sampling frequency
IEC61937_MPEG2_LAYER2_LSF = 0x09, ///< MPEG-2, layer-2 low sampling frequency
IEC61937_MPEG2_LAYER3_LSF = 0x0A, ///< MPEG-2, layer-3 low sampling frequency
IEC61937_DTS1 = 0x0B, ///< DTS type I (512 samples)
IEC61937_DTS2 = 0x0C, ///< DTS type II (1024 samples)
IEC61937_DTS3 = 0x0D, ///< DTS type III (2048 samples)
IEC61937_ATRAC = 0x0E, ///< Atrac data
IEC61937_ATRAC3 = 0x0F, ///< Atrac 3 data
IEC61937_ATRACX = 0x10, ///< Atrac 3 plus data
IEC61937_DTSHD = 0x11, ///< DTS HD data
IEC61937_WMAPRO = 0x12, ///< WMA 9 Professional data
IEC61937_MPEG2_AAC_LSF_2048 = 0x13, ///< MPEG-2 AAC ADTS half-rate low sampling frequency
IEC61937_MPEG2_AAC_LSF_4096 = 0x13 | 0x20, ///< MPEG-2 AAC ADTS quarter-rate low sampling frequency
IEC61937_EAC3 = 0x15, ///< E-AC-3 data
IEC61937_TRUEHD = 0x16, ///< TrueHD data
};
#pragma warning(push)
#pragma warning(disable : 4245)
static struct scmap_t {
WORD nChannels;
BYTE ch[8];
DWORD dwChannelMask;
}
// dshow: left, right, center, LFE, left surround, right surround
// lets see how we can map these things to dshow (oh the joy!)
s_scmap_hdmv[] = {
// FL FR FC LFe BL BR FLC FRC
{0, { -1, -1, -1, -1, -1, -1, -1, -1 }, 0}, // INVALID
{1, { 0, -1, -1, -1, -1, -1, -1, -1 }, SPEAKER_FRONT_CENTER}, // Mono M1, 0
{0, { -1, -1, -1, -1, -1, -1, -1, -1 }, 0}, // INVALID
{2, { 0, 1, -1, -1, -1, -1, -1, -1 }, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT}, // Stereo FL, FR
{4, { 0, 1, 2, -1, -1, -1, -1, -1 }, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER}, // 3/0 FL, FR, FC
{4, { 0, 1, 2, -1, -1, -1, -1, -1 }, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_CENTER}, // 2/1 FL, FR, Surround
{4, { 0, 1, 2, 3, -1, -1, -1, -1 }, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER}, // 3/1 FL, FR, FC, Surround
{4, { 0, 1, 2, 3, -1, -1, -1, -1 }, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT}, // 2/2 FL, FR, BL, BR
{6, { 0, 1, 2, 3, 4, -1, -1, -1 }, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT}, // 3/2 FL, FR, FC, BL, BR
{6, { 0, 1, 2, 5, 3, 4, -1, -1 }, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT}, // 3/2+LFe FL, FR, FC, BL, BR, LFe
{8, { 0, 1, 2, 3, 6, 4, 5, -1 }, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT}, // 3/4 FL, FR, FC, BL, Bls, Brs, BR
{8, { 0, 1, 2, 7, 4, 5, 3, 6 }, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT}, // 3/4+LFe FL, FR, FC, BL, Bls, Brs, BR, LFe
};
#pragma warning(pop)
static struct channel_mode_t {
WORD channels;
DWORD ch_layout;
LPCTSTR op_value;
}
channel_mode[] = {
//n libavcodec ID Name
{1, AV_CH_LAYOUT_MONO , _T("1.0") }, // SPK_MONO "Mono"
{2, AV_CH_LAYOUT_STEREO , _T("2.0") }, // SPK_STEREO "Stereo"
{4, AV_CH_LAYOUT_QUAD , _T("4.0") }, // SPK_4_0 "4.0"
{6, AV_CH_LAYOUT_5POINT1, _T("5.1") }, // SPK_5_1 "5.1"
{8, AV_CH_LAYOUT_7POINT1, _T("7.1") }, // SPK_7_1 "7.1"
};
void DD_stats_t::Reset()
{
mode = AV_CODEC_ID_NONE;
ac3_frames = 0;
eac3_frames = 0;
}
bool DD_stats_t::Desired(int type)
{
if (mode != AV_CODEC_ID_NONE) {
return (mode == type);
};
// unknown mode
if (type == AV_CODEC_ID_AC3) {
++ac3_frames;
} else if (type == AV_CODEC_ID_EAC3) {
++eac3_frames;
}
if (ac3_frames + eac3_frames >= 4) {
if (eac3_frames > 2 * ac3_frames) {
mode = AV_CODEC_ID_EAC3; // EAC3
} else {
mode = AV_CODEC_ID_AC3; // AC3 or mixed AC3+EAC3
}
return (mode == type);
}
return true;
}
CMpaDecFilter::CMpaDecFilter(LPUNKNOWN lpunk, HRESULT* phr)
: CTransformFilter(NAME("CMpaDecFilter"), lpunk, __uuidof(this))
, m_rtStart(0)
, m_fDiscontinuity(false)
, m_bResync(false)
, m_buff(PADDING_SIZE)
, m_hdmicount(0)
, m_hdmisize(0)
, m_truehd_samplerate(0)
, m_truehd_framelength(0)
{
if (phr) {
*phr = S_OK;
}
m_pInput = DEBUG_NEW CMpaDecInputPin(this, phr, L"In");
if (!m_pInput) {
*phr = E_OUTOFMEMORY;
}
if (FAILED(*phr)) {
return;
}
m_pOutput = DEBUG_NEW CTransformOutputPin(NAME("CTransformOutputPin"), this, phr, L"Out");
if (!m_pOutput) {
*phr = E_OUTOFMEMORY;
}
if (FAILED(*phr)) {
delete m_pInput, m_pInput = nullptr;
return;
}
m_DDstats.Reset();
// default settings
m_fSampleFmt[SF_PCM16] = true;
m_fSampleFmt[SF_PCM24] = false;
m_fSampleFmt[SF_PCM32] = false;
m_fSampleFmt[SF_FLOAT] = false;
m_fMixer = false;
m_iMixerLayout = SPK_STEREO;
m_fDRC = false;
m_fSPDIF[ac3] = false;
m_fSPDIF[eac3] = false;
m_fSPDIF[truehd] = false;
m_fSPDIF[dts] = false;
m_fSPDIF[dtshd] = false;
// read settings
CString layout_str;
#ifdef STANDALONE_FILTER
CRegKey key;
ULONG len = 8;
if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, OPT_REGKEY_MpaDec, KEY_READ)) {
DWORD dw;
if (ERROR_SUCCESS == key.QueryDWORDValue(OPTION_SFormat_i16, dw)) {
m_fSampleFmt[SF_PCM16] = !!dw;
}
if (ERROR_SUCCESS == key.QueryDWORDValue(OPTION_SFormat_i24, dw)) {
m_fSampleFmt[SF_PCM24] = !!dw;
}
if (ERROR_SUCCESS == key.QueryDWORDValue(OPTION_SFormat_i32, dw)) {
m_fSampleFmt[SF_PCM32] = !!dw;
}
if (ERROR_SUCCESS == key.QueryDWORDValue(OPTION_SFormat_flt, dw)) {
m_fSampleFmt[SF_FLOAT] = !!dw;
}
if (ERROR_SUCCESS == key.QueryDWORDValue(OPTION_Mixer, dw)) {
m_fMixer = !!dw;
}
if (ERROR_SUCCESS == key.QueryStringValue(OPTION_MixerLayout, layout_str.GetBuffer(8), &len)) {
layout_str.ReleaseBufferSetLength(len);
}
if (ERROR_SUCCESS == key.QueryDWORDValue(OPTION_DRC, dw)) {
m_fDRC = !!dw;
}
if (ERROR_SUCCESS == key.QueryDWORDValue(OPTION_SPDIF_ac3, dw)) {
m_fSPDIF[ac3] = !!dw;
}
if (ERROR_SUCCESS == key.QueryDWORDValue(OPTION_SPDIF_eac3, dw)) {
m_fSPDIF[eac3] = !!dw;
}
if (ERROR_SUCCESS == key.QueryDWORDValue(OPTION_SPDIF_truehd, dw)) {
m_fSPDIF[truehd] = !!dw;
}
if (ERROR_SUCCESS == key.QueryDWORDValue(OPTION_SPDIF_dts, dw)) {
m_fSPDIF[dts] = !!dw;
}
if (ERROR_SUCCESS == key.QueryDWORDValue(OPTION_SPDIF_dtshd, dw)) {
m_fSPDIF[dtshd] = !!dw;
}
}
#else
m_fSampleFmt[SF_PCM16] = !!AfxGetApp()->GetProfileInt(OPT_SECTION_MpaDec, OPTION_SFormat_i16, m_fSampleFmt[SF_PCM16]);
m_fSampleFmt[SF_PCM24] = !!AfxGetApp()->GetProfileInt(OPT_SECTION_MpaDec, OPTION_SFormat_i24, m_fSampleFmt[SF_PCM24]);
m_fSampleFmt[SF_PCM32] = !!AfxGetApp()->GetProfileInt(OPT_SECTION_MpaDec, OPTION_SFormat_i32, m_fSampleFmt[SF_PCM32]);
m_fSampleFmt[SF_FLOAT] = !!AfxGetApp()->GetProfileInt(OPT_SECTION_MpaDec, OPTION_SFormat_flt, m_fSampleFmt[SF_FLOAT]);
m_fMixer = !!AfxGetApp()->GetProfileInt(OPT_SECTION_MpaDec, OPTION_Mixer, m_fMixer);
layout_str = AfxGetApp()->GetProfileString(OPT_SECTION_MpaDec, OPTION_MixerLayout, channel_mode[m_iMixerLayout].op_value);
m_fDRC = !!AfxGetApp()->GetProfileInt(OPT_SECTION_MpaDec, OPTION_DRC, m_fDRC);
m_fSPDIF[ac3] = !!AfxGetApp()->GetProfileInt(OPT_SECTION_MpaDec, OPTION_SPDIF_ac3, m_fSPDIF[ac3]);
m_fSPDIF[eac3] = !!AfxGetApp()->GetProfileInt(OPT_SECTION_MpaDec, OPTION_SPDIF_eac3, m_fSPDIF[eac3]);
m_fSPDIF[truehd] = !!AfxGetApp()->GetProfileInt(OPT_SECTION_MpaDec, OPTION_SPDIF_truehd, m_fSPDIF[truehd]);
m_fSPDIF[dts] = !!AfxGetApp()->GetProfileInt(OPT_SECTION_MpaDec, OPTION_SPDIF_dts, m_fSPDIF[dts]);
m_fSPDIF[dtshd] = !!AfxGetApp()->GetProfileInt(OPT_SECTION_MpaDec, OPTION_SPDIF_dtshd, m_fSPDIF[dtshd]);
#endif
if (!(m_fSampleFmt[SF_PCM16] || m_fSampleFmt[SF_PCM24] || m_fSampleFmt[SF_PCM32] || m_fSampleFmt[SF_FLOAT])) {
m_fSampleFmt[SF_PCM16] = true;
}
for (int i = SPK_MONO; i <= SPK_7_1; i++) {
if (layout_str == channel_mode[i].op_value) {
m_iMixerLayout = i;
break;
}
}
}
CMpaDecFilter::~CMpaDecFilter()
{
StopStreaming();
}
STDMETHODIMP CMpaDecFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
return
QI(IMpaDecFilter)
QI(ISpecifyPropertyPages)
QI(ISpecifyPropertyPages2)
__super::NonDelegatingQueryInterface(riid, ppv);
}
HRESULT CMpaDecFilter::EndOfStream()
{
CAutoLock cAutoLock(&m_csReceive);
return __super::EndOfStream();
}
HRESULT CMpaDecFilter::BeginFlush()
{
return __super::BeginFlush();
}
HRESULT CMpaDecFilter::EndFlush()
{
CAutoLock cAutoLock(&m_csReceive);
m_buff.RemoveAll();
#if defined(STANDALONE_FILTER) || HAS_FFMPEG_AUDIO_DECODERS
m_FFAudioDec.FlushBuffers();
#endif
m_Mixer.FlushBuffers();
return __super::EndFlush();
}
HRESULT CMpaDecFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
{
CAutoLock cAutoLock(&m_csReceive);
m_ps2_state.sync = false;
m_hdmicount = 0;
m_hdmisize = 0;
m_truehd_samplerate = 0;
m_truehd_framelength = 0;
m_bResync = true;
return __super::NewSegment(tStart, tStop, dRate);
}
HRESULT CMpaDecFilter::Receive(IMediaSample* pIn)
{
CAutoLock cAutoLock(&m_csReceive);
HRESULT hr;
AM_SAMPLE2_PROPERTIES* const pProps = m_pInput->SampleProps();
if (pProps->dwStreamId != AM_STREAM_MEDIA) {
return m_pOutput->Deliver(pIn);
}
AM_MEDIA_TYPE* pmt;
if (SUCCEEDED(pIn->GetMediaType(&pmt)) && pmt) {
CMediaType mt(*pmt);
m_pInput->SetMediaType(&mt);
DeleteMediaType(pmt);
pmt = nullptr;
}
BYTE* pDataIn = nullptr;
if (FAILED(hr = pIn->GetPointer(&pDataIn))) {
return hr;
}
long len = pIn->GetActualDataLength();
// skip empty packet (StreamBufferSource can produce empty data)
if (len == 0) {
return S_OK;
}
(static_cast(m_pInput))->StripPacket(pDataIn, len);
REFERENCE_TIME rtStart = _I64_MIN, rtStop = _I64_MIN;
hr = pIn->GetTime(&rtStart, &rtStop);
#if 0
if (SUCCEEDED(hr)) {
TRACE(_T("CMpaDecFilter::Receive(): rtStart = %10I64d, rtStop = %10I64d\n"), rtStart, rtStop);
} else {
TRACE(_T("CMpaDecFilter::Receive(): frame without timestamp\n"));
}
#endif
if (pIn->IsDiscontinuity() == S_OK) {
m_fDiscontinuity = true;
m_buff.RemoveAll();
m_rtStart = rtStart;
m_bResync = true;
if (FAILED(hr)) {
TRACE(_T("CMpaDecFilter::Receive() : Discontinuity without timestamp\n"));
return S_OK;
}
}
const GUID& subtype = m_pInput->CurrentMediaType().subtype;
if (subtype == MEDIASUBTYPE_COOK && S_OK == pIn->IsSyncPoint() ||
_abs64(m_rtStart - rtStart) > MAX_JITTER && subtype != MEDIASUBTYPE_COOK && subtype != MEDIASUBTYPE_ATRC && subtype != MEDIASUBTYPE_SIPR) {
m_bResync = true;
}
if (SUCCEEDED(hr) && m_bResync) {
m_buff.RemoveAll();
m_rtStart = rtStart;
m_bResync = false;
}
size_t bufflen = m_buff.GetCount();
m_buff.SetCount(bufflen + len, 4096);
memcpy(m_buff.GetData() + bufflen, pDataIn, len);
len += (long)bufflen;
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_AC3
if (subtype == MEDIASUBTYPE_DOLBY_AC3 || subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3 || subtype == MEDIASUBTYPE_DNET) {
if (GetSPDIF(ac3)) {
return ProcessAC3_SPDIF();
} else {
return ProcessAC3();
}
}
if (GetSPDIF(eac3) && subtype == MEDIASUBTYPE_DOLBY_DDPLUS) {
return ProcessEAC3_SPDIF();
}
if (GetSPDIF(truehd) && subtype == MEDIASUBTYPE_DOLBY_TRUEHD) {
return ProcessTrueHD_SPDIF();
}
#endif
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_DTS
if (GetSPDIF(dts) && (subtype == MEDIASUBTYPE_DTS || subtype == MEDIASUBTYPE_WAVE_DTS)) {
return ProcessDTS_SPDIF();
}
#endif
#if defined(STANDALONE_FILTER) || HAS_FFMPEG_AUDIO_DECODERS
enum AVCodecID nCodecId = FindCodec(subtype);
if (nCodecId != AV_CODEC_ID_NONE) {
return ProcessFFmpeg(nCodecId);
}
#endif
if (0) {} // needed if decoders are disabled below
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_LPCM
else if (subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) {
hr = ProcessLPCM();
} else if (subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) {
// TODO: check if the test is really correct
hr = ProcessHdmvLPCM(pIn->IsSyncPoint() == S_FALSE);
}
#endif
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_PS2AUDIO
else if (subtype == MEDIASUBTYPE_PS2_PCM) {
hr = ProcessPS2PCM();
} else if (subtype == MEDIASUBTYPE_PS2_ADPCM) {
hr = ProcessPS2ADPCM();
}
#endif
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_PCM
else if (subtype == MEDIASUBTYPE_PCM_NONE ||
subtype == MEDIASUBTYPE_PCM_RAW) {
hr = ProcessPCMraw();
} else if (subtype == MEDIASUBTYPE_PCM_TWOS ||
subtype == MEDIASUBTYPE_PCM_IN24 ||
subtype == MEDIASUBTYPE_PCM_IN32) {
hr = ProcessPCMintBE();
} else if (subtype == MEDIASUBTYPE_PCM_SOWT) {
hr = ProcessPCMintLE();
} else if (subtype == MEDIASUBTYPE_PCM_FL32 ||
subtype == MEDIASUBTYPE_PCM_FL64) {
hr = ProcessPCMfloatBE();
} else if (subtype == MEDIASUBTYPE_IEEE_FLOAT) {
hr = ProcessPCMfloatLE();
}
#endif
return hr;
}
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_LPCM
HRESULT CMpaDecFilter::ProcessLPCM()
{
WAVEFORMATEX* wfein = (WAVEFORMATEX*)m_pInput->CurrentMediaType().Format();
WORD nChannels = wfein->nChannels;
if (nChannels < 1 || nChannels > 8) {
return ERROR_NOT_SUPPORTED;
}
BYTE* const base = m_buff.GetData();
BYTE* const end = base + m_buff.GetCount();
BYTE* p = base;
unsigned int blocksize = nChannels * 2 * wfein->wBitsPerSample / 8;
size_t nSamples = (m_buff.GetCount() / blocksize) * 2 * nChannels;
AVSampleFormat out_avsf = AV_SAMPLE_FMT_NONE;
size_t outSize = nSamples * (wfein->wBitsPerSample <= 16 ? 2 : 4); // convert to 16 and 32-bit
CAtlArray outBuff;
outBuff.SetCount(outSize);
switch (wfein->wBitsPerSample) {
case 16: {
out_avsf = AV_SAMPLE_FMT_S16;
uint16_t* pDataOut = (uint16_t*)outBuff.GetData();
for (size_t i = 0; i < nSamples; i++) {
pDataOut[i] = (uint16_t)(*p) << 8 | (uint16_t)(*(p + 1));
p += 2;
}
}
break;
case 24: {
out_avsf = AV_SAMPLE_FMT_S32;
uint32_t* pDataOut = (uint32_t*)outBuff.GetData();
size_t m = nChannels * 2;
for (size_t k = 0, n = nSamples / m; k < n; k++) {
BYTE* q = p + m * 2;
for (size_t i = 0; i < m; i++) {
pDataOut[i] = (uint32_t)(*p) << 24 | (uint32_t)(*(p + 1)) << 16 | (uint32_t)(*q) << 8;
p += 2;
q++;
}
p += m;
pDataOut += m;
}
}
break;
case 20: {
out_avsf = AV_SAMPLE_FMT_S32;
uint32_t* pDataOut = (uint32_t*)outBuff.GetData();
size_t m = nChannels * 2;
for (size_t k = 0, n = nSamples / m; k < n; k++) {
BYTE* q = p + m * 2;
for (size_t i = 0; i < m; i++) {
uint32_t u32 = (uint32_t)(*p) << 24 | (uint32_t)(*(p + 1)) << 16;
if (i & 1) {
u32 |= (*(uint8_t*)q & 0x0F) << 12;
q++;
} else {
u32 |= (*(uint8_t*)q & 0xF0) << 8;
}
pDataOut[i] = u32;
p += 2;
}
p += nChannels;
pDataOut += m;
}
}
break;
}
memmove(base, p, end - p);
m_buff.SetCount(end - p);
return Deliver(outBuff.GetData(), (int)outSize, out_avsf, wfein->nSamplesPerSec, wfein->nChannels, GetDefChannelMask(wfein->nChannels));
}
HRESULT CMpaDecFilter::ProcessHdmvLPCM(bool bAlignOldBuffer) // Blu ray LPCM
{
WAVEFORMATEX_HDMV_LPCM* wfein = (WAVEFORMATEX_HDMV_LPCM*)m_pInput->CurrentMediaType().Format();
scmap_t* remap = &s_scmap_hdmv [wfein->channel_conf];
int nChannels = wfein->nChannels;
int xChannels = nChannels + (nChannels % 2);
int BytesPerSample = (wfein->wBitsPerSample + 7) / 8;
int BytesPerFrame = BytesPerSample * xChannels;
BYTE* pDataIn = m_buff.GetData();
int len = (int)m_buff.GetCount();
len -= len % BytesPerFrame;
if (bAlignOldBuffer) {
m_buff.SetCount(len);
}
int nFrames = len / xChannels / BytesPerSample;
AVSampleFormat out_avsf = AV_SAMPLE_FMT_NONE;
int outSize = nFrames * nChannels * (wfein->wBitsPerSample <= 16 ? 2 : 4); // convert to 16 and 32-bit
CAtlArray outBuff;
outBuff.SetCount(outSize);
switch (wfein->wBitsPerSample) {
case 16: {
out_avsf = AV_SAMPLE_FMT_S16;
int16_t* pDataOut = (int16_t*)outBuff.GetData();
for (int i = 0; i < nFrames; i++) {
for (int j = 0; j < nChannels; j++) {
BYTE nRemap = remap->ch[j];
*pDataOut = (int16_t)(pDataIn[nRemap * 2] << 8 | pDataIn[nRemap * 2 + 1]);
pDataOut++;
}
pDataIn += xChannels * 2;
}
}
break;
case 24:
case 20: {
out_avsf = AV_SAMPLE_FMT_S32;
int32_t* pDataOut = (int32_t*)outBuff.GetData();
for (int i = 0; i < nFrames; i++) {
for (int j = 0; j < nChannels; j++) {
BYTE nRemap = remap->ch[j];
*pDataOut = (int32_t)(pDataIn[nRemap * 3] << 24 | pDataIn[nRemap * 3 + 1] << 16 | pDataIn[nRemap * 3 + 2] << 8);
pDataOut++;
}
pDataIn += xChannels * 3;
}
}
break;
}
memmove(m_buff.GetData(), pDataIn, m_buff.GetCount() - len);
m_buff.SetCount(m_buff.GetCount() - len);
return Deliver(outBuff.GetData(), outSize, out_avsf, wfein->nSamplesPerSec, wfein->nChannels, remap->dwChannelMask);
}
#endif /* INTERNAL_DECODER_LPCM */
#if defined(STANDALONE_FILTER) || HAS_FFMPEG_AUDIO_DECODERS
HRESULT CMpaDecFilter::ProcessFFmpeg(enum AVCodecID nCodecId)
{
BYTE* const base = m_buff.GetData();
BYTE* end = base + m_buff.GetCount();
BYTE* p = base;
if (m_FFAudioDec.GetCodecId() != nCodecId) {
m_FFAudioDec.Init(nCodecId, m_pInput);
m_FFAudioDec.SetDRC(GetDynamicRangeControl());
}
#if INTERNAL_DECODER_REALAUDIO
// RealAudio
CPaddedArray buffRA(FF_INPUT_BUFFER_PADDING_SIZE);
bool isRA = false;
if (nCodecId == AV_CODEC_ID_ATRAC3 || nCodecId == AV_CODEC_ID_COOK || nCodecId == AV_CODEC_ID_SIPR) {
if (m_FFAudioDec.RealPrepare(p, int(end - p), buffRA)) {
p = buffRA.GetData();
end = p + buffRA.GetCount();
isRA = true;
} else {
return S_OK;
}
}
#endif
while (p < end) {
HRESULT hr;
int size = 0;
CAtlArray output;
AVSampleFormat avsamplefmt = AV_SAMPLE_FMT_NONE;
hr = m_FFAudioDec.Decode(nCodecId, p, int(end - p), size, output, avsamplefmt);
if (FAILED(hr)) {
m_buff.RemoveAll();
m_bResync = true;
return S_OK;
} else if (hr == S_FALSE) {
m_bResync = true;
p += size;
continue;
} else if (!output.IsEmpty()) { // && SUCCEEDED(hr)
hr = Deliver(output.GetData(), (int)output.GetCount(), avsamplefmt, m_FFAudioDec.GetSampleRate(), m_FFAudioDec.GetChannels(), m_FFAudioDec.GetChannelMask());
} else if (size == 0) { // && pBuffOut.IsEmpty()
break;
}
p += size;
}
#if INTERNAL_DECODER_REALAUDIO
if (isRA) { // RealAudio
p = base + buffRA.GetCount();
end = base + m_buff.GetCount();
}
#endif
memmove(base, p, end - p);
m_buff.SetCount(end - p);
return S_OK;
}
#endif /* HAS_FFMPEG_AUDIO_DECODERS */
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_AC3
HRESULT CMpaDecFilter::ProcessAC3()
{
HRESULT hr;
BYTE* const base = m_buff.GetData();
BYTE* const end = base + m_buff.GetCount();
BYTE* p = base;
while (p + 8 <= end) {
if (*(WORD*)p != 0x770b) {
p++;
continue;
}
AVCodecID ftype;
int size;
if ((size = GetAC3FrameSize(p)) > 0) {
ftype = AV_CODEC_ID_AC3;
} else if ((size = GetEAC3FrameSize(p)) > 0) {
ftype = AV_CODEC_ID_EAC3;
} else {
p += 2;
continue;
}
if (p + size > end) {
break;
}
if (m_DDstats.Desired(ftype)) {
if (m_FFAudioDec.GetCodecId() != ftype) {
m_FFAudioDec.Init(ftype, m_pInput);
m_FFAudioDec.SetDRC(GetDynamicRangeControl());
}
CAtlArray output;
AVSampleFormat avsamplefmt = AV_SAMPLE_FMT_NONE;
hr = m_FFAudioDec.Decode(ftype, p, size, size, output, avsamplefmt);
if (FAILED(hr)) {
m_buff.RemoveAll();
m_bResync = true;
return S_OK;
} else if (hr == S_FALSE) {
m_bResync = true;
p += size;
continue;
} else if (!output.IsEmpty()) { // && SUCCEEDED(hr)
hr = Deliver(output.GetData(), (int)output.GetCount(), avsamplefmt, m_FFAudioDec.GetSampleRate(), m_FFAudioDec.GetChannels(), m_FFAudioDec.GetChannelMask());
} else if (size == 0) { // && pBuffOut.IsEmpty()
break;
}
}
p += size;
}
memmove(base, p, end - p);
m_buff.SetCount(end - p);
return S_OK;
}
HRESULT CMpaDecFilter::ProcessAC3_SPDIF()
{
HRESULT hr;
BYTE* const base = m_buff.GetData();
BYTE* const end = base + m_buff.GetCount();
BYTE* p = base;
while (p + 8 <= end) { // 8 = AC3 header size + 1
int samplerate, channels, framelength, bitrate;
int size = ParseAC3Header(p, &samplerate, &channels, &framelength, &bitrate);
if (size == 0) {
p++;
continue;
}
if (p + size > end) {
break;
}
if (FAILED(hr = DeliverBitstream(p, size, IEC61937_AC3, samplerate, 1536))) {
return hr;
}
p += size;
}
memmove(base, p, end - p);
m_buff.SetCount(end - p);
return S_OK;
}
HRESULT CMpaDecFilter::ProcessEAC3_SPDIF()
{
HRESULT hr;
BYTE* const base = m_buff.GetData();
BYTE* const end = base + m_buff.GetCount();
BYTE* p = base;
while (p + 8 <= end) {
int samplerate, channels, framelength, frametype;
int size = ParseEAC3Header(p, &samplerate, &channels, &framelength, &frametype);
if (size == 0) {
p++;
continue;
}
if (p + size > end) {
break;
}
static const uint8_t eac3_repeat[4] = {6, 3, 2, 1};
int repeat = 1;
if ((p[4] & 0xc0) != 0xc0) { /* fscod */
repeat = eac3_repeat[(p[4] & 0x30) >> 4]; /* numblkscod */
}
m_hdmicount++;
if (m_hdmisize + size <= BS_EAC3_SIZE - BS_HEADER_SIZE) {
memcpy(m_hdmibuff + m_hdmisize, p, size);
m_hdmisize += size;
} else {
ASSERT(0);
}
p += size;
if (m_hdmicount < repeat) {
break;
}
hr = DeliverBitstream(m_hdmibuff, m_hdmisize, IEC61937_EAC3, samplerate, framelength * repeat);
m_hdmicount = 0;
m_hdmisize = 0;
if (FAILED(hr)) {
return hr;
}
}
memmove(base, p, end - p);
m_buff.SetCount(end - p);
return S_OK;
}
HRESULT CMpaDecFilter::ProcessTrueHD_SPDIF()
{
const BYTE mat_start_code[20] = { 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00, 0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0 };
const BYTE mat_middle_code[12] = { 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA, 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0 };
const BYTE mat_end_code[16] = { 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11 };
HRESULT hr;
BYTE* const base = m_buff.GetData();
BYTE* const end = base + m_buff.GetCount();
BYTE* p = base;
while (p + 16 <= end) {
int samplerate, channels, framelength;
WORD bitdepth;
bool isTrueHD;
int size = ParseMLPHeader(p, &samplerate, &channels, &framelength, &bitdepth, &isTrueHD);
if (size > 0) {
// sync frame
m_truehd_samplerate = samplerate;
m_truehd_framelength = framelength;
} else {
int ac3size = GetAC3FrameSize(p);
if (ac3size == 0) {
ac3size = GetEAC3FrameSize(p);
}
if (ac3size > 0) {
if (p + ac3size > end) {
break;
}
p += ac3size;
continue; // skip ac3 frames
}
}
if (size == 0 && m_truehd_framelength > 0) {
// get not sync frame size
size = ((p[0] << 8 | p[1]) & 0xfff) * 2;
}
if (size < 8) {
p++;
continue;
}
if (p + size > end) {
break;
}
m_hdmicount++;
if (m_hdmicount == 1) {
// skip 8 header bytes and write MAT start code
memcpy(m_hdmibuff + BS_HEADER_SIZE, mat_start_code, sizeof(mat_start_code));
m_hdmisize = BS_HEADER_SIZE + sizeof(mat_start_code);
} else if (m_hdmicount == 13) {
memcpy(m_hdmibuff + (BS_HEADER_SIZE + BS_MAT_SIZE) / 2, mat_middle_code, sizeof(mat_middle_code));
m_hdmisize = (BS_HEADER_SIZE + BS_MAT_SIZE) / 2 + sizeof(mat_middle_code);
}
if (m_hdmisize + size <= m_hdmicount * BS_MAT_OFFSET) {
memcpy(m_hdmibuff + m_hdmisize, p, size);
m_hdmisize += size;
ZeroMemory(m_hdmibuff + m_hdmisize, m_hdmicount * BS_MAT_OFFSET - m_hdmisize);
m_hdmisize = m_hdmicount * BS_MAT_OFFSET;
} else {
ASSERT(0);
}
p += size;
if (m_hdmicount < 24) {
break;
}
memcpy(m_hdmibuff + (BS_HEADER_SIZE + BS_MAT_SIZE) - sizeof(mat_end_code), mat_end_code, sizeof(mat_end_code));
m_hdmisize = (BS_HEADER_SIZE + BS_MAT_SIZE);
hr = DeliverBitstream(m_hdmibuff + BS_HEADER_SIZE, m_hdmisize - BS_HEADER_SIZE, IEC61937_TRUEHD, m_truehd_samplerate, m_truehd_framelength * 24);
m_hdmicount = 0;
m_hdmisize = 0;
if (FAILED(hr)) {
return hr;
}
}
memmove(base, p, end - p);
m_buff.SetCount(end - p);
return S_OK;
}
#endif /* INTERNAL_DECODER_AC3 */
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_DTS
HRESULT CMpaDecFilter::ProcessDTS_SPDIF()
{
HRESULT hr;
BYTE* const base = m_buff.GetData();
BYTE* const end = base + m_buff.GetCount();
BYTE* p = base;
while (p + 16 <= end) {
int samplerate = 0, channels, framelength = 0, bitrate;
int size = GetDTSFrameSize(p);
if (size > 0) {
size = ParseDTSHeader(p, &samplerate, &channels, &framelength, &bitrate);
}
if (size == 0) {
p++;
continue;
}
int sizehd = 0;
if (p + size + 16 <= end) {
sizehd = GetDTSHDFrameSize(p + size);
} else {
break; // need more data
}
if (p + size + sizehd > end) {
break; // need more data
}
bool usehdmi = sizehd && GetSPDIF(dtshd);
if (usehdmi) {
if (FAILED(hr = DeliverBitstream(p, size + sizehd, IEC61937_DTSHD, samplerate, framelength))) {
return hr;
}
} else {
BYTE type;
switch (framelength) {
case 512:
type = IEC61937_DTS1;
break;
case 1024:
type = IEC61937_DTS2;
break;
case 2048:
type = IEC61937_DTS3;
break;
default:
TRACE(_T("CMpaDecFilter:ProcessDTS_SPDIF() - framelength is not supported\n"));
return E_FAIL;
}
if (FAILED(hr = DeliverBitstream(p, size, type, samplerate, framelength))) {
return hr;
}
}
p += (size + sizehd);
}
memmove(base, p, end - p);
m_buff.SetCount(end - p);
return S_OK;
}
#endif /* INTERNAL_DECODER_DTS */
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_PCM
HRESULT CMpaDecFilter::ProcessPCMraw() // 'raw'
{
WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_pInput->CurrentMediaType().Format();
size_t size = m_buff.GetCount();
size_t nSamples = size * 8 / wfe->wBitsPerSample;
AVSampleFormat out_avsf = AV_SAMPLE_FMT_NONE;
CAtlArray outBuff;
outBuff.SetCount(size);
switch (wfe->wBitsPerSample) {
case 8: // unsigned 8-bit
out_avsf = AV_SAMPLE_FMT_U8;
memcpy(outBuff.GetData(), m_buff.GetData(), size);
break;
case 16: { // signed big-endian 16-bit
out_avsf = AV_SAMPLE_FMT_S16;
uint16_t* pIn = (uint16_t*)m_buff.GetData();
uint16_t* pOut = (uint16_t*)outBuff.GetData();
for (size_t i = 0; i < nSamples; i++) {
pOut[i] = bswap_16(pIn[i]);
}
}
break;
}
HRESULT hr;
if (S_OK != (hr = Deliver(outBuff.GetData(), (int)size, out_avsf, wfe->nSamplesPerSec, wfe->nChannels))) {
return hr;
}
m_buff.RemoveAll();
return S_OK;
}
HRESULT CMpaDecFilter::ProcessPCMintBE() //'twos', big-endian 'in24' and 'in32'
{
WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_pInput->CurrentMediaType().Format();
size_t nSamples = m_buff.GetCount() * 8 / wfe->wBitsPerSample;
AVSampleFormat out_avsf = AV_SAMPLE_FMT_NONE;
size_t outSize = nSamples * (wfe->wBitsPerSample <= 16 ? 2 : 4); // convert to 16 and 32-bit
CAtlArray outBuff;
outBuff.SetCount(outSize);
switch (wfe->wBitsPerSample) {
case 8: { // signed 8-bit
out_avsf = AV_SAMPLE_FMT_S16;
int8_t* pIn = (int8_t*)m_buff.GetData();
int16_t* pOut = (int16_t*)outBuff.GetData();
for (size_t i = 0; i < nSamples; i++) {
pOut[i] = (int16_t)pIn[i] << 8;
}
}
break;
case 16: { // signed big-endian 16-bit
out_avsf = AV_SAMPLE_FMT_S16;
uint16_t* pIn = (uint16_t*)m_buff.GetData(); // signed take as an unsigned to shift operations.
uint16_t* pOut = (uint16_t*)outBuff.GetData();
for (size_t i = 0; i < nSamples; i++) {
pOut[i] = bswap_16(pIn[i]);
}
}
break;
case 24: { // signed big-endian 24-bit
out_avsf = AV_SAMPLE_FMT_S32;
uint8_t* pIn = (uint8_t*)m_buff.GetData();
uint32_t* pOut = (uint32_t*)outBuff.GetData();
for (size_t i = 0; i < nSamples; i++) {
pOut[i] = (uint32_t)pIn[3 * i] << 24 |
(uint32_t)pIn[3 * i + 1] << 16 |
(uint32_t)pIn[3 * i + 2] << 8;
}
}
break;
case 32: { // signed big-endian 32-bit
out_avsf = AV_SAMPLE_FMT_S32;
uint32_t* pIn = (uint32_t*)m_buff.GetData(); // signed take as an unsigned to shift operations.
uint32_t* pOut = (uint32_t*)outBuff.GetData();
for (size_t i = 0; i < nSamples; i++) {
pOut[i] = bswap_32(pIn[i]);
}
}
break;
}
HRESULT hr;
if (S_OK != (hr = Deliver(outBuff.GetData(), (int)outSize, out_avsf, wfe->nSamplesPerSec, wfe->nChannels))) {
return hr;
}
m_buff.RemoveAll();
return S_OK;
}
HRESULT CMpaDecFilter::ProcessPCMintLE() // 'sowt', little-endian 'in24' and 'in32'
{
WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_pInput->CurrentMediaType().Format();
size_t nSamples = m_buff.GetCount() * 8 / wfe->wBitsPerSample;
AVSampleFormat out_avsf = AV_SAMPLE_FMT_NONE;
size_t outSize = nSamples * (wfe->wBitsPerSample <= 16 ? 2 : 4); // convert to 16 and 32-bit
CAtlArray outBuff;
outBuff.SetCount(outSize);
switch (wfe->wBitsPerSample) {
case 8: { // signed 8-bit
out_avsf = AV_SAMPLE_FMT_S16;
int8_t* pIn = (int8_t*)m_buff.GetData();
int16_t* pOut = (int16_t*)outBuff.GetData();
for (size_t i = 0; i < nSamples; i++) {
pOut[i] = (int16_t)pIn[i] << 8;
}
}
break;
case 16: // signed little-endian 16-bit
out_avsf = AV_SAMPLE_FMT_S16;
memcpy(outBuff.GetData(), m_buff.GetData(), outSize);
break;
case 24: // signed little-endian 24-bit
out_avsf = AV_SAMPLE_FMT_S32;
convert_int24_to_int32(nSamples, (uint8_t*)m_buff.GetData(), (int32_t*)outBuff.GetData());
break;
case 32: // signed little-endian 32-bit
out_avsf = AV_SAMPLE_FMT_S32;
memcpy(outBuff.GetData(), m_buff.GetData(), outSize);
break;
}
HRESULT hr;
if (S_OK != (hr = Deliver(outBuff.GetData(), (int)outSize, out_avsf, wfe->nSamplesPerSec, wfe->nChannels))) {
return hr;
}
m_buff.RemoveAll();
return S_OK;
}
HRESULT CMpaDecFilter::ProcessPCMfloatBE() // big-endian 'fl32' and 'fl64'
{
WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_pInput->CurrentMediaType().Format();
size_t size = m_buff.GetCount();
size_t nSamples = size * 8 / wfe->wBitsPerSample;
AVSampleFormat out_avsf = AV_SAMPLE_FMT_NONE;
CAtlArray outBuff;
outBuff.SetCount(size);
switch (wfe->wBitsPerSample) {
case 32: {
out_avsf = AV_SAMPLE_FMT_FLT;
uint32_t* pIn = (uint32_t*)m_buff.GetData();
uint32_t* pOut = (uint32_t*)outBuff.GetData();
for (size_t i = 0; i < nSamples; i++) {
pOut[i] = bswap_32(pIn[i]);
}
}
break;
case 64: {
out_avsf = AV_SAMPLE_FMT_DBL;
uint64_t* pIn = (uint64_t*)m_buff.GetData();
uint64_t* pOut = (uint64_t*)outBuff.GetData();
for (size_t i = 0; i < nSamples; i++) {
pOut[i] = bswap_64(pIn[i]);
}
}
break;
}
HRESULT hr;
if (S_OK != (hr = Deliver(outBuff.GetData(), (int)size, out_avsf, wfe->nSamplesPerSec, wfe->nChannels))) {
return hr;
}
m_buff.RemoveAll();
return S_OK;
}
HRESULT CMpaDecFilter::ProcessPCMfloatLE() // little-endian 'fl32' and 'fl64'
{
WAVEFORMATEX* wfe = (WAVEFORMATEX*)m_pInput->CurrentMediaType().Format();
size_t size = m_buff.GetCount();
AVSampleFormat out_avsf = AV_SAMPLE_FMT_NONE;
CAtlArray outBuff;
outBuff.SetCount(size);
switch (wfe->wBitsPerSample) {
case 32:
out_avsf = AV_SAMPLE_FMT_FLT;
break;
case 64:
out_avsf = AV_SAMPLE_FMT_DBL;
break;
}
memcpy(outBuff.GetData(), m_buff.GetData(), size);
HRESULT hr;
if (S_OK != (hr = Deliver(outBuff.GetData(), (int)size, out_avsf, wfe->nSamplesPerSec, wfe->nChannels))) {
return hr;
}
m_buff.RemoveAll();
return S_OK;
}
#endif /* INTERNAL_DECODER_PCM */
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_PS2AUDIO
HRESULT CMpaDecFilter::ProcessPS2PCM()
{
BYTE* const base = m_buff.GetData();
BYTE* const end = base + m_buff.GetCount();
BYTE* p = base;
WAVEFORMATEXPS2* wfe = (WAVEFORMATEXPS2*)m_pInput->CurrentMediaType().Format();
size_t size = wfe->dwInterleave * wfe->nChannels;
AVSampleFormat out_avsf = AV_SAMPLE_FMT_S16P;
CAtlArray outBuff;
outBuff.SetCount(size);
while (p + size <= end) {
DWORD* dw = (DWORD*)p;
if (dw[0] == 'dhSS') {
p += dw[1] + 8;
} else if (dw[0] == 'dbSS') {
p += 8;
m_ps2_state.sync = true;
} else {
if (m_ps2_state.sync) {
memcpy(outBuff.GetData(), p, size);
} else {
ZeroMemory(outBuff.GetData(), size);
}
HRESULT hr;
if (S_OK != (hr = Deliver(outBuff.GetData(), (int)size, out_avsf, wfe->nSamplesPerSec, wfe->nChannels))) {
return hr;
}
p += size;
}
}
memmove(base, p, end - p);
m_buff.SetCount(end - p);
return S_OK;
}
static void decodeps2adpcm(ps2_state_t& s, int channel, BYTE* pin, float* pout)
{
int tbl_index = pin[0] >> 4;
int shift = pin[0] & 0xf;
int unk = pin[1]; // ?
UNREFERENCED_PARAMETER(unk);
if (tbl_index >= 10) {
ASSERT(0);
return;
}
// if (unk == 7) {ASSERT(0); return;} // ???
static double s_tbl[] = {
0.0, 0.0, 0.9375, 0.0, 1.796875, -0.8125, 1.53125, -0.859375, 1.90625, -0.9375,
0.0, 0.0, -0.9375, 0.0, -1.796875, 0.8125, -1.53125, 0.859375, -1.90625, 0.9375
};
double* tbl = &s_tbl[tbl_index * 2];
double& a = s.a[channel];
double& b = s.b[channel];
for (int i = 0; i < 28; i++) {
short input = (short)(((pin[2 + i / 2] >> ((i & 1) << 2)) & 0xf) << 12) >> shift;
double output = a * tbl[1] + b * tbl[0] + input;
a = b;
b = output;
*pout++ = (float)(output / 32768);
}
}
HRESULT CMpaDecFilter::ProcessPS2ADPCM()
{
BYTE* const base = m_buff.GetData();
BYTE* const end = base + m_buff.GetCount();
BYTE* p = base;
WAVEFORMATEXPS2* wfe = (WAVEFORMATEXPS2*)m_pInput->CurrentMediaType().Format();
size_t size = wfe->dwInterleave * wfe->nChannels;
int samples = wfe->dwInterleave * 14 / 16 * 2;
int channels = wfe->nChannels;
AVSampleFormat out_avsf = AV_SAMPLE_FMT_FLTP;
size_t outSize = samples * channels * sizeof(float); // convert to float
CAtlArray outBuff;
outBuff.SetCount(outSize);
float* pOut = (float*)outBuff.GetData();
while (p + size <= end) {
DWORD* dw = (DWORD*)p;
if (dw[0] == 'dhSS') {
p += dw[1] + 8;
} else if (dw[0] == 'dbSS') {
p += 8;
m_ps2_state.sync = true;
} else {
if (m_ps2_state.sync) {
for (int ch = 0, j = 0, k = 0; ch < channels; ch++, j += wfe->dwInterleave) {
for (DWORD i = 0; i < wfe->dwInterleave; i += 16, k += 28) {
decodeps2adpcm(m_ps2_state, ch, p + i + j, pOut + k);
}
}
} else {
ZeroMemory(outBuff.GetData(), outSize);
}
HRESULT hr;
if (S_OK != (hr = Deliver(outBuff.GetData(), (int)outSize, out_avsf, wfe->nSamplesPerSec, wfe->nChannels))) {
return hr;
}
p += size;
}
}
memmove(base, p, end - p);
m_buff.SetCount(end - p);
return S_OK;
}
#endif /* INTERNAL_DECODER_PS2AUDIO */
HRESULT CMpaDecFilter::GetDeliveryBuffer(IMediaSample** pSample, BYTE** pData)
{
HRESULT hr;
*pData = nullptr;
if (FAILED(hr = m_pOutput->GetDeliveryBuffer(pSample, nullptr, nullptr, 0))
|| FAILED(hr = (*pSample)->GetPointer(pData))) {
return hr;
}
AM_MEDIA_TYPE* pmt = nullptr;
if (SUCCEEDED((*pSample)->GetMediaType(&pmt)) && pmt) {
CMediaType mt = *pmt;
m_pOutput->SetMediaType(&mt);
DeleteMediaType(pmt);
pmt = nullptr;
}
return S_OK;
}
HRESULT CMpaDecFilter::Deliver(BYTE* pBuff, int size, AVSampleFormat avsf, DWORD nSamplesPerSec, WORD nChannels, DWORD dwChannelMask)
{
if (dwChannelMask == 0) {
dwChannelMask = GetDefChannelMask(nChannels);
}
ASSERT(nChannels == av_popcount(dwChannelMask));
int nSamples = size / (nChannels * av_get_bytes_per_sample(avsf));
REFERENCE_TIME rtDur = 10000000i64 * nSamples / nSamplesPerSec;
REFERENCE_TIME rtStart = m_rtStart;
REFERENCE_TIME rtStop = m_rtStart + rtDur;
m_rtStart += rtDur;
//TRACE(_T("CMpaDecFilter: %I64d - %I64d\n"), rtStart/10000, rtStop/10000);
if (rtStart < 0 /*200000*/ /* < 0, FIXME: 0 makes strange noises */) {
return S_OK;
}
BYTE* pDataIn = pBuff;
CAtlArray mixData;
if (GetMixer()) {
int sc = GetMixerLayout();
WORD mixed_channels = channel_mode[sc].channels;
DWORD mixed_mask = channel_mode[sc].ch_layout;
if (dwChannelMask != mixed_mask) {
mixData.SetCount(nSamples * mixed_channels);
m_Mixer.Update(avsf, dwChannelMask, mixed_mask);
if (m_Mixer.Mixing(mixData.GetData(), nSamples, pDataIn, nSamples) > 0) {
pDataIn = (BYTE*)mixData.GetData();
avsf = AV_SAMPLE_FMT_FLT; // float after mixing
size = nSamples * mixed_channels * sizeof(float);
nChannels = mixed_channels;
dwChannelMask = mixed_mask;
}
}
}
MPCSampleFormat out_sf;
switch (avsf) {
case AV_SAMPLE_FMT_U8:
case AV_SAMPLE_FMT_U8P:
case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S16P:
out_sf = SF_PCM16;
break;
case AV_SAMPLE_FMT_S32:
case AV_SAMPLE_FMT_S32P:
out_sf = SF_PCM32;
break;
case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP:
case AV_SAMPLE_FMT_DBL:
case AV_SAMPLE_FMT_DBLP:
out_sf = SF_FLOAT;
break;
default:
return E_INVALIDARG;
}
out_sf = SelectSampleFormat(out_sf);
CMediaType mt = CreateMediaType(out_sf, nSamplesPerSec, nChannels, dwChannelMask);
WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format();
HRESULT hr;
if (FAILED(hr = ReconnectOutput(nSamples, mt))) {
return hr;
}
CComPtr pOut;
BYTE* pDataOut = nullptr;
if (FAILED(GetDeliveryBuffer(&pOut, &pDataOut))) {
return E_FAIL;
}
if (hr == S_OK) {
m_pOutput->SetMediaType(&mt);
pOut->SetMediaType(&mt);
}
pOut->SetTime(&rtStart, &rtStop);
pOut->SetMediaTime(nullptr, nullptr);
pOut->SetPreroll(FALSE);
pOut->SetDiscontinuity(m_fDiscontinuity);
m_fDiscontinuity = false;
pOut->SetSyncPoint(TRUE);
pOut->SetActualDataLength(nSamples * nChannels * wfe->wBitsPerSample / 8);
WAVEFORMATEX* wfeout = (WAVEFORMATEX*)m_pOutput->CurrentMediaType().Format();
ASSERT(wfeout->nChannels == wfe->nChannels);
ASSERT(wfeout->nSamplesPerSec == wfe->nSamplesPerSec);
UNREFERENCED_PARAMETER(wfeout);
switch (out_sf) {
case SF_PCM16:
convert_to_int16(avsf, nChannels, nSamples, pDataIn, (int16_t*)pDataOut);
break;
case SF_PCM24:
convert_to_int24(avsf, nChannels, nSamples, pDataIn, pDataOut);
break;
case SF_PCM32:
convert_to_int32(avsf, nChannels, nSamples, pDataIn, (int32_t*)pDataOut);
break;
case SF_FLOAT:
convert_to_float(avsf, nChannels, nSamples, pDataIn, (float*)pDataOut);
break;
}
return m_pOutput->Deliver(pOut);
}
HRESULT CMpaDecFilter::DeliverBitstream(BYTE* pBuff, int size, WORD type, int sample_rate, int samples)
{
HRESULT hr;
WORD subtype = 0;
bool isDTSWAV = false;
bool isHDMI = false;
int length = 0;
switch (type) {
case IEC61937_AC3:
length = BS_AC3_SIZE;
break;
case IEC61937_DTS1:
case IEC61937_DTS2:
case IEC61937_DTS3:
if (size == 4096 && sample_rate == 44100 && samples == 1024) { // DTSWAV
length = size;
isDTSWAV = true;
} else {
while (length < size + 16) {
length += 2048;
}
}
break;
case IEC61937_DTSHD:
length = BS_DTSHD_SIZE;
subtype = 4;
isHDMI = true;
break;
case IEC61937_EAC3:
length = BS_EAC3_SIZE;
isHDMI = true;
break;
case IEC61937_TRUEHD:
length = BS_TRUEHD_SIZE;
isHDMI = true;
break;
default:
TRACE(_T("CMpaDecFilter::DeliverBitstream() - type is not supported\n"));
return E_INVALIDARG;
}
CMediaType mt;
if (isHDMI) {
mt = CreateMediaTypeHDMI(type);
} else {
mt = CreateMediaTypeSPDIF(sample_rate);
}
if (FAILED(hr = ReconnectOutput(length, mt))) {
return hr;
}
CComPtr pOut;
BYTE* pDataOut = nullptr;
if (FAILED(GetDeliveryBuffer(&pOut, &pDataOut))) {
return E_FAIL;
}
if (isDTSWAV) {
memcpy(pDataOut, pBuff, size);
} else {
ZeroMemory(pDataOut + BS_HEADER_SIZE + size, length - (BS_HEADER_SIZE + size)); // Fill after the input buffer with zeros if any extra bytes
int index = 0;
// Fill the 8 bytes (4 words) of IEC header
WORD* pDataOutW = (WORD*)pDataOut;
pDataOutW[index++] = 0xf872;
pDataOutW[index++] = 0x4e1f;
pDataOutW[index++] = type | subtype << 8;
if (type == IEC61937_DTSHD) {
pDataOutW[index++] = (size & ~0xf) + 0x18; // (size without 12 extra bytes) & 0xf + 0x18
// begin dts-hd start code
pDataOutW[index++] = 0x0100;
pDataOutW[index++] = 0;
pDataOutW[index++] = 0;
pDataOutW[index++] = 0;
pDataOutW[index++] = 0xfefe;
// end dts-hd start code
pDataOutW[index++] = size;
} else if (type == IEC61937_EAC3 || type == IEC61937_TRUEHD) {
pDataOutW[index++] = size;
} else {
pDataOutW[index++] = size * 8;
}
_swab((char*)pBuff, (char*)&pDataOutW[index], size & ~1);
if (size & 1) { // _swab doesn't like odd number.
pDataOut[index * 2 + size - 1] = 0;
pDataOut[index * 2 + size] = pBuff[size - 1];
}
}
REFERENCE_TIME rtDur;
rtDur = 10000000i64 * samples / sample_rate;
REFERENCE_TIME rtStart = m_rtStart, rtStop = m_rtStart + rtDur;
m_rtStart += rtDur;
if (rtStart < 0) {
return S_OK;
}
if (hr == S_OK) {
m_pOutput->SetMediaType(&mt);
pOut->SetMediaType(&mt);
}
pOut->SetTime(&rtStart, &rtStop);
pOut->SetMediaTime(nullptr, nullptr);
pOut->SetPreroll(FALSE);
pOut->SetDiscontinuity(m_fDiscontinuity);
m_fDiscontinuity = false;
pOut->SetSyncPoint(TRUE);
pOut->SetActualDataLength(length);
return m_pOutput->Deliver(pOut);
}
HRESULT CMpaDecFilter::ReconnectOutput(int nSamples, CMediaType& mt)
{
HRESULT hr;
CComQIPtr pPin = m_pOutput->GetConnected();
if (!pPin) {
return E_NOINTERFACE;
}
CComPtr pAllocator;
if (FAILED(hr = pPin->GetAllocator(&pAllocator)) || !pAllocator) {
return hr;
}
ALLOCATOR_PROPERTIES props, actual;
if (FAILED(hr = pAllocator->GetProperties(&props))) {
return hr;
}
WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format();
long cbBuffer = nSamples * wfe->nBlockAlign;
if (mt != m_pOutput->CurrentMediaType() || cbBuffer > props.cbBuffer) {
if (cbBuffer > props.cbBuffer) {
props.cBuffers = 4;
props.cbBuffer = cbBuffer * 3 / 2;
if (FAILED(hr = m_pOutput->DeliverBeginFlush())
|| FAILED(hr = m_pOutput->DeliverEndFlush())
|| FAILED(hr = pAllocator->Decommit())
|| FAILED(hr = pAllocator->SetProperties(&props, &actual))
|| FAILED(hr = pAllocator->Commit())) {
return hr;
}
if (props.cBuffers > actual.cBuffers || props.cbBuffer > actual.cbBuffer) {
NotifyEvent(EC_ERRORABORT, hr, 0);
return E_FAIL;
}
}
return S_OK;
}
return S_FALSE;
}
CMediaType CMpaDecFilter::CreateMediaType(MPCSampleFormat sf, DWORD nSamplesPerSec, WORD nChannels, DWORD dwChannelMask)
{
CMediaType mt;
mt.majortype = MEDIATYPE_Audio;
mt.subtype = sf == SF_FLOAT ? MEDIASUBTYPE_IEEE_FLOAT : MEDIASUBTYPE_PCM;
mt.formattype = FORMAT_WaveFormatEx;
WAVEFORMATEXTENSIBLE wfex;
//ZeroMemory(&wfex, sizeof(wfex));
WAVEFORMATEX& wfe = wfex.Format;
wfe.nChannels = nChannels;
wfe.nSamplesPerSec = nSamplesPerSec;
switch (sf) {
default:
case SF_PCM16:
wfe.wBitsPerSample = 16;
break;
case SF_PCM24:
wfe.wBitsPerSample = 24;
break;
case SF_PCM32:
case SF_FLOAT:
wfe.wBitsPerSample = 32;
break;
}
wfe.nBlockAlign = nChannels * wfe.wBitsPerSample / 8;
wfe.nAvgBytesPerSec = nSamplesPerSec * wfe.nBlockAlign;
if (nChannels <= 2 && dwChannelMask <= 0x4 && (sf == SF_PCM16 || sf == SF_FLOAT)) {
// WAVEFORMATEX
wfe.wFormatTag = (sf == SF_FLOAT) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
wfe.cbSize = 0;
mt.SetFormat((BYTE*)&wfe, sizeof(wfe));
} else {
// WAVEFORMATEXTENSIBLE
wfex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfex.Format.cbSize = sizeof(wfex) - sizeof(wfex.Format); // 22
wfex.Samples.wValidBitsPerSample = wfex.Format.wBitsPerSample;
if (dwChannelMask == 0) {
dwChannelMask = GetDefChannelMask(nChannels);
}
wfex.dwChannelMask = dwChannelMask;
wfex.SubFormat = mt.subtype;
mt.SetFormat((BYTE*)&wfex, sizeof(wfex));
}
mt.SetSampleSize(wfex.Format.nBlockAlign);
return mt;
}
CMediaType CMpaDecFilter::CreateMediaTypeSPDIF(DWORD nSamplesPerSec)
{
if (nSamplesPerSec % 11025 == 0) {
nSamplesPerSec = 44100;
} else {
nSamplesPerSec = 48000;
}
CMediaType mt = CreateMediaType(SF_PCM16, nSamplesPerSec, 2, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT);
((WAVEFORMATEX*)mt.pbFormat)->wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
return mt;
}
CMediaType CMpaDecFilter::CreateMediaTypeHDMI(WORD type)
{
// some info here - http://msdn.microsoft.com/en-us/library/windows/desktop/dd316761%28v=vs.85%29.aspx
// but we use WAVEFORMATEXTENSIBLE structure
CMediaType mt;
mt.majortype = MEDIATYPE_Audio;
mt.subtype = MEDIASUBTYPE_PCM;
mt.formattype = FORMAT_WaveFormatEx;
WAVEFORMATEXTENSIBLE wfex;
ZeroMemory(&wfex, sizeof(wfex));
GUID subtype = GUID_NULL;
switch (type) {
case IEC61937_DTSHD:
wfex.Format.nChannels = 8;
wfex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
subtype = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
break;
case IEC61937_EAC3:
wfex.Format.nChannels = 2;
wfex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
subtype = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
break;
case IEC61937_TRUEHD:
wfex.Format.nChannels = 8;
wfex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
subtype = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
break;
default:
ASSERT(0);
break;
}
if (subtype != GUID_NULL) {
wfex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfex.Format.nSamplesPerSec = 192000;
wfex.Format.wBitsPerSample = 16;
wfex.Format.nBlockAlign = wfex.Format.nChannels * wfex.Format.wBitsPerSample / 8;
wfex.Format.nAvgBytesPerSec = wfex.Format.nSamplesPerSec * wfex.Format.nBlockAlign;
wfex.Format.cbSize = sizeof(wfex) - sizeof(wfex.Format);
wfex.Samples.wValidBitsPerSample = wfex.Format.wBitsPerSample;
wfex.SubFormat = subtype;
}
mt.SetSampleSize(1);
mt.SetFormat((BYTE*)&wfex, sizeof(wfex.Format) + wfex.Format.cbSize);
return mt;
}
HRESULT CMpaDecFilter::CheckInputType(const CMediaType* mtIn)
{
if (0) {}
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_LPCM
else if (mtIn->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) {
WAVEFORMATEX* wfe = (WAVEFORMATEX*)mtIn->Format();
if (wfe->nChannels < 1 || wfe->nChannels > 8 || (wfe->wBitsPerSample != 16 && wfe->wBitsPerSample != 20 && wfe->wBitsPerSample != 24)) {
return VFW_E_TYPE_NOT_ACCEPTED;
}
}
#endif
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_PS2AUDIO
else if (mtIn->subtype == MEDIASUBTYPE_PS2_ADPCM) {
WAVEFORMATEXPS2* wfe = (WAVEFORMATEXPS2*)mtIn->Format();
if (wfe->dwInterleave & 0xf) { // has to be a multiple of the block size (16 bytes)
return VFW_E_TYPE_NOT_ACCEPTED;
}
}
#endif
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_PCM
else if (mtIn->subtype == MEDIASUBTYPE_IEEE_FLOAT) {
WAVEFORMATEX* wfe = (WAVEFORMATEX*)mtIn->Format();
if (wfe->wBitsPerSample != 64) { // only for 64-bit float PCM
return VFW_E_TYPE_NOT_ACCEPTED; // not needed any decoders for 32-bit float
}
}
#endif
for (int i = 0; i < _countof(sudPinTypesIn); i++) {
if (*sudPinTypesIn[i].clsMajorType == mtIn->majortype
&& *sudPinTypesIn[i].clsMinorType == mtIn->subtype) {
return S_OK;
}
}
return VFW_E_TYPE_NOT_ACCEPTED;
}
HRESULT CMpaDecFilter::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 CMpaDecFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
{
if (m_pInput->IsConnected() == FALSE) {
return E_UNEXPECTED;
}
CMediaType& mt = m_pInput->CurrentMediaType();
WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format();
UNREFERENCED_PARAMETER(wfe);
pProperties->cBuffers = 4;
// pProperties->cbBuffer = 1;
pProperties->cbBuffer = 48000 * 6 * (32 / 8) / 10; // 48KHz 6ch 32bps 100ms
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 CMpaDecFilter::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();
WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format();
if (wfe == nullptr) {
return E_INVALIDARG;
}
#if defined(STANDALONE_FILTER) || INTERNAL_DECODER_AC3 || INTERNAL_DECODER_DTS
const GUID& subtype = mt.subtype;
if (GetSPDIF(ac3) && (subtype == MEDIASUBTYPE_DOLBY_AC3 || subtype == MEDIASUBTYPE_WAVE_DOLBY_AC3) ||
GetSPDIF(dts) && (subtype == MEDIASUBTYPE_DTS || subtype == MEDIASUBTYPE_WAVE_DTS)) {
*pmt = CreateMediaTypeSPDIF(wfe->nSamplesPerSec);
return S_OK;
}
if (GetSPDIF(eac3) && subtype == MEDIASUBTYPE_DOLBY_DDPLUS) {
*pmt = CreateMediaTypeHDMI(IEC61937_EAC3);
return S_OK;
}
if (GetSPDIF(truehd) && subtype == MEDIASUBTYPE_DOLBY_TRUEHD) {
*pmt = CreateMediaTypeHDMI(IEC61937_TRUEHD);
return S_OK;
}
#endif
if (GetMixer()) {
DWORD in_layout;
#if defined(STANDALONE_FILTER) || HAS_FFMPEG_AUDIO_DECODERS
if (m_FFAudioDec.GetCodecId() != AV_CODEC_ID_NONE) {
in_layout = m_FFAudioDec.GetChannelMask();
} else {
in_layout = GetDefChannelMask(wfe->nChannels);
}
#else
in_layout = GetDefChannelMask(wfe->nChannels);
#endif
int sc = GetMixerLayout();
if (in_layout != channel_mode[sc].ch_layout) {
*pmt = CreateMediaType(SelectSampleFormat(SF_FLOAT), wfe->nSamplesPerSec, channel_mode[sc].channels, channel_mode[sc].ch_layout);
return S_OK;
}
}
#if defined(STANDALONE_FILTER) || HAS_FFMPEG_AUDIO_DECODERS
if (m_FFAudioDec.GetCodecId() != AV_CODEC_ID_NONE) {
AVSampleFormat avsf = m_FFAudioDec.GetSampleFmt();
MPCSampleFormat out_sf;
switch (avsf) {
case AV_SAMPLE_FMT_U8:
case AV_SAMPLE_FMT_U8P:
case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S16P:
out_sf = SF_PCM16;
break;
case AV_SAMPLE_FMT_S32:
case AV_SAMPLE_FMT_S32P:
out_sf = SF_PCM32;
break;
case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP:
case AV_SAMPLE_FMT_DBL:
case AV_SAMPLE_FMT_DBLP:
out_sf = SF_FLOAT;
break;
default:
out_sf = SF_PCM16;
}
out_sf = SelectSampleFormat(out_sf);
*pmt = CreateMediaType(out_sf, m_FFAudioDec.GetSampleRate(), m_FFAudioDec.GetChannels(), m_FFAudioDec.GetChannelMask());
return S_OK;
}
#endif
MPCSampleFormat out_sf;
if (wfe->wFormatTag == WAVE_FORMAT_PCM && wfe->wBitsPerSample > 16) {
out_sf = SF_PCM32;
} else if (wfe->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
out_sf = SF_FLOAT;
} else {
out_sf = SF_PCM16;
}
out_sf = SelectSampleFormat(out_sf);
*pmt = CreateMediaType(out_sf, wfe->nSamplesPerSec, wfe->nChannels);
return S_OK;
}
HRESULT CMpaDecFilter::StartStreaming()
{
HRESULT hr = __super::StartStreaming();
if (FAILED(hr)) {
return hr;
}
m_ps2_state.reset();
m_fDiscontinuity = false;
return S_OK;
}
HRESULT CMpaDecFilter::StopStreaming()
{
#if defined(STANDALONE_FILTER) || HAS_FFMPEG_AUDIO_DECODERS
m_FFAudioDec.StreamFinish();
#endif
return __super::StopStreaming();
}
HRESULT CMpaDecFilter::SetMediaType(PIN_DIRECTION dir, const CMediaType* pmt)
{
#if defined(STANDALONE_FILTER) || HAS_FFMPEG_AUDIO_DECODERS
if (dir == PINDIR_INPUT) {
enum AVCodecID nCodecId = FindCodec(pmt->subtype);
if (nCodecId != AV_CODEC_ID_NONE) {
if (m_FFAudioDec.Init(nCodecId, m_pInput)) {
m_FFAudioDec.SetDRC(GetDynamicRangeControl());
} else {
return VFW_E_TYPE_NOT_ACCEPTED;
}
}
}
#endif
return __super::SetMediaType(dir, pmt);
}
// IMpaDecFilter
STDMETHODIMP CMpaDecFilter::SetSampleFormat(MPCSampleFormat sf, bool enable)
{
CAutoLock cAutoLock(&m_csProps);
if (sf >= 0 && sf < sfcount) {
m_fSampleFmt[sf] = enable;
} else {
return E_INVALIDARG;
}
return S_OK;
}
STDMETHODIMP_(bool) CMpaDecFilter::GetSampleFormat(MPCSampleFormat sf)
{
CAutoLock cAutoLock(&m_csProps);
if (sf >= 0 && sf < sfcount) {
return m_fSampleFmt[sf];
}
return false;
}
STDMETHODIMP_(MPCSampleFormat) CMpaDecFilter::SelectSampleFormat(MPCSampleFormat sf)
{
CAutoLock cAutoLock(&m_csProps);
if (sf >= 0 && sf < sfcount && m_fSampleFmt[sf]) {
return sf;
}
if (m_fSampleFmt[SF_FLOAT]) {
return SF_FLOAT;
}
if (m_fSampleFmt[SF_PCM24]) {
return SF_PCM24;
}
if (m_fSampleFmt[SF_PCM16]) {
return SF_PCM16;
}
if (m_fSampleFmt[SF_PCM32]) {
return SF_PCM32;
}
return SF_PCM16;
}
STDMETHODIMP CMpaDecFilter::SetMixer(bool fMixer)
{
CAutoLock cAutoLock(&m_csProps);
m_fMixer = fMixer;
return S_OK;
}
STDMETHODIMP_(bool) CMpaDecFilter::GetMixer()
{
CAutoLock cAutoLock(&m_csProps);
return m_fMixer;
}
STDMETHODIMP CMpaDecFilter::SetMixerLayout(int sc)
{
CAutoLock cAutoLock(&m_csProps);
if (sc < SPK_MONO || sc > SPK_7_1) {
return E_INVALIDARG;
}
m_iMixerLayout = sc;
return S_OK;
}
STDMETHODIMP_(int) CMpaDecFilter::GetMixerLayout()
{
CAutoLock cAutoLock(&m_csProps);
return m_iMixerLayout;
}
STDMETHODIMP CMpaDecFilter::SetDynamicRangeControl(bool fDRC)
{
CAutoLock cAutoLock(&m_csProps);
m_fDRC = fDRC;
#if HAS_FFMPEG_AUDIO_DECODERS
m_FFAudioDec.SetDRC(fDRC);
#endif
return S_OK;
}
STDMETHODIMP_(bool) CMpaDecFilter::GetDynamicRangeControl()
{
CAutoLock cAutoLock(&m_csProps);
return m_fDRC;
}
STDMETHODIMP CMpaDecFilter::SetSPDIF(enctype et, bool fSPDIF)
{
CAutoLock cAutoLock(&m_csProps);
if (et < 0 || et >= etcount) {
return E_INVALIDARG;
}
m_fSPDIF[et] = fSPDIF;
return S_OK;
}
STDMETHODIMP_(bool) CMpaDecFilter::GetSPDIF(enctype et)
{
CAutoLock cAutoLock(&m_csProps);
if (et < 0 || et >= etcount) {
return false;
}
if (et == dtshd && !m_fSPDIF[dts]) {
return false;
}
return m_fSPDIF[et];
}
STDMETHODIMP CMpaDecFilter::SaveSettings()
{
CAutoLock cAutoLock(&m_csProps);
#ifdef STANDALONE_FILTER
CRegKey key;
if (ERROR_SUCCESS == key.Create(HKEY_CURRENT_USER, OPT_REGKEY_MpaDec)) {
key.SetDWORDValue(OPTION_SFormat_i16, m_fSampleFmt[SF_PCM16]);
key.SetDWORDValue(OPTION_SFormat_i24, m_fSampleFmt[SF_PCM24]);
key.SetDWORDValue(OPTION_SFormat_i32, m_fSampleFmt[SF_PCM32]);
key.SetDWORDValue(OPTION_SFormat_flt, m_fSampleFmt[SF_FLOAT]);
key.SetDWORDValue(OPTION_Mixer, m_fMixer);
key.SetStringValue(OPTION_MixerLayout, channel_mode[m_iMixerLayout].op_value);
key.SetDWORDValue(OPTION_DRC, m_fDRC);
key.SetDWORDValue(OPTION_SPDIF_ac3, m_fSPDIF[ac3]);
key.SetDWORDValue(OPTION_SPDIF_eac3, m_fSPDIF[eac3]);
key.SetDWORDValue(OPTION_SPDIF_truehd, m_fSPDIF[truehd]);
key.SetDWORDValue(OPTION_SPDIF_dts, m_fSPDIF[dts]);
key.SetDWORDValue(OPTION_SPDIF_dtshd, m_fSPDIF[dtshd]);
}
#else
AfxGetApp()->WriteProfileInt(OPT_SECTION_MpaDec, OPTION_SFormat_i16, m_fSampleFmt[SF_PCM16]);
AfxGetApp()->WriteProfileInt(OPT_SECTION_MpaDec, OPTION_SFormat_i24, m_fSampleFmt[SF_PCM24]);
AfxGetApp()->WriteProfileInt(OPT_SECTION_MpaDec, OPTION_SFormat_i32, m_fSampleFmt[SF_PCM32]);
AfxGetApp()->WriteProfileInt(OPT_SECTION_MpaDec, OPTION_SFormat_flt, m_fSampleFmt[SF_FLOAT]);
AfxGetApp()->WriteProfileInt(OPT_SECTION_MpaDec, OPTION_Mixer, m_fMixer);
AfxGetApp()->WriteProfileString(OPT_SECTION_MpaDec, OPTION_MixerLayout, channel_mode[m_iMixerLayout].op_value);
AfxGetApp()->WriteProfileInt(OPT_SECTION_MpaDec, OPTION_DRC, m_fDRC);
AfxGetApp()->WriteProfileInt(OPT_SECTION_MpaDec, OPTION_SPDIF_ac3, m_fSPDIF[ac3]);
AfxGetApp()->WriteProfileInt(OPT_SECTION_MpaDec, OPTION_SPDIF_eac3, m_fSPDIF[eac3]);
AfxGetApp()->WriteProfileInt(OPT_SECTION_MpaDec, OPTION_SPDIF_truehd, m_fSPDIF[truehd]);
AfxGetApp()->WriteProfileInt(OPT_SECTION_MpaDec, OPTION_SPDIF_dts, m_fSPDIF[dts]);
AfxGetApp()->WriteProfileInt(OPT_SECTION_MpaDec, OPTION_SPDIF_dtshd, m_fSPDIF[dtshd]);
#endif
return S_OK;
}
// ISpecifyPropertyPages2
STDMETHODIMP CMpaDecFilter::GetPages(CAUUID* pPages)
{
CheckPointer(pPages, E_POINTER);
HRESULT hr = S_OK;
pPages->cElems = 1;
pPages->pElems = (GUID*)CoTaskMemAlloc(sizeof(GUID) * pPages->cElems);
if (pPages->pElems != nullptr) {
pPages->pElems[0] = __uuidof(CMpaDecSettingsWnd);
} else {
hr = E_OUTOFMEMORY;
}
return hr;
}
STDMETHODIMP CMpaDecFilter::CreatePage(const GUID& guid, IPropertyPage** ppPage)
{
CheckPointer(ppPage, E_POINTER);
if (*ppPage != nullptr) {
return E_INVALIDARG;
}
HRESULT hr;
if (guid == __uuidof(CMpaDecSettingsWnd)) {
(*ppPage = DEBUG_NEW CInternalPropertyPageTempl(nullptr, &hr))->AddRef();
}
return *ppPage ? S_OK : E_FAIL;
}
//
// CMpaDecInputPin
//
CMpaDecInputPin::CMpaDecInputPin(CTransformFilter* pFilter, HRESULT* phr, LPWSTR pName)
: CDeCSSInputPin(NAME("CMpaDecInputPin"), pFilter, phr, pName)
{
}