/* * (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 #ifdef STANDALONE_FILTER #include #endif #include #include "MpegSplitter.h" #include "moreuuids.h" #include "../../../DSUtil/AudioParser.h" #include "../../../DSUtil/DSUtil.h" #include "../../../mpc-hc/SettingsDefines.h" TCHAR* MPEG2_Profile[] = { L"0", L"High Profile", L"Spatially Scalable Profile", L"SNR Scalable Profile", L"Main Profile", L"Simple Profile", L"6", L"7", }; TCHAR* MPEG2_Level[] = { L"0", L"1", L"2", L"3", L"High Level", L"4", L"High1440 Level", L"5", L"Main Level", L"6", L"Low Level", L"7", L"8", L"9", L"10", L"11", }; #ifdef STANDALONE_FILTER const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] = { {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1System}, {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG2_PROGRAM}, {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG2_TRANSPORT}, {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG2_PVA}, {&MEDIATYPE_Stream, &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, 0, nullptr}, }; const AMOVIESETUP_FILTER sudFilter[] = { {&__uuidof(CMpegSplitterFilter), MpegSplitterName, MERIT_NORMAL + 1, _countof(sudpPins), sudpPins, CLSID_LegacyAmFilterCategory}, {&__uuidof(CMpegSourceFilter), MpegSourceName, MERIT_UNLIKELY, 0, nullptr, CLSID_LegacyAmFilterCategory}, }; CFactoryTemplate g_Templates[] = { {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, nullptr, &sudFilter[0]}, {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance, nullptr, &sudFilter[1]}, {L"CMpegSplitterPropertyPage", &__uuidof(CMpegSplitterSettingsWnd), CreateInstance>}, }; int g_cTemplates = _countof(g_Templates); STDAPI DllRegisterServer() { DeleteRegKey(_T("Media Type\\Extensions\\"), _T(".ts")); RegisterSourceFilter(CLSID_AsyncReader, MEDIASUBTYPE_MPEG1System, _T("0,16,FFFFFFFFF100010001800001FFFFFFFF,000001BA2100010001800001000001BB"), nullptr); RegisterSourceFilter(CLSID_AsyncReader, MEDIASUBTYPE_MPEG2_PROGRAM, _T("0,5,FFFFFFFFC0,000001BA40"), nullptr); RegisterSourceFilter(CLSID_AsyncReader, MEDIASUBTYPE_MPEG2_PVA, _T("0,8,fffffc00ffe00000,4156000055000000"), nullptr); CAtlList chkbytes; chkbytes.AddTail(_T("0,1,,47,188,1,,47,376,1,,47")); chkbytes.AddTail(_T("4,1,,47,196,1,,47,388,1,,47")); chkbytes.AddTail(_T("0,4,,54467263,1660,1,,47")); // TFrc RegisterSourceFilter(CLSID_AsyncReader, MEDIASUBTYPE_MPEG2_TRANSPORT, chkbytes, nullptr); return AMovieDllRegisterServer2(TRUE); } STDAPI DllUnregisterServer() { return AMovieDllRegisterServer2(FALSE); } #include "../../FilterApp.h" CFilterApp theApp; #endif template t_CType GetFormatHelper(t_CType& _pInfo, const CMediaType* _pFormat) { ASSERT(_pFormat->cbFormat >= sizeof(*_pInfo)); _pInfo = (t_CType)_pFormat->pbFormat; return _pInfo; } static int GetHighestBitSet32(unsigned long _Value) { unsigned long Ret; unsigned char bNonZero = _BitScanReverse(&Ret, _Value); if (bNonZero) { return Ret; } else { return -1; } } CString FormatBitrate(double _Bitrate) { CString Temp; if (_Bitrate > 20000000) { // More than 2 mbit Temp.Format(L"%.2f mbit/s", double(_Bitrate) / 1000000.0); } else { Temp.Format(L"%.1f kbit/s", double(_Bitrate) / 1000.0); } return Temp; } CString FormatString(const wchar_t* pszFormat, ...) { CString Temp; ATLASSERT(AtlIsValidString(pszFormat)); va_list argList; va_start(argList, pszFormat); Temp.FormatV(pszFormat, argList); va_end(argList); return Temp; } CString GetMediaTypeDesc(const CMediaType* _pMediaType, const CHdmvClipInfo::Stream* pClipInfo, int _PresentationType, CString lang) { const WCHAR* pPresentationDesc = nullptr; if (pClipInfo) { pPresentationDesc = StreamTypeToName(pClipInfo->m_Type); } else { pPresentationDesc = StreamTypeToName((PES_STREAM_TYPE)_PresentationType); } CString MajorType; CAtlList Infos; if (_pMediaType->majortype == MEDIATYPE_Video) { MajorType = "Video"; if (pClipInfo) { CString name = ISO6392ToLanguage(pClipInfo->m_LanguageCode); if (!name.IsEmpty()) { Infos.AddTail(name); } } else { if (!lang.IsEmpty()) { Infos.AddTail(lang); } } const VIDEOINFOHEADER* pVideoInfo = nullptr; const VIDEOINFOHEADER2* pVideoInfo2 = nullptr; if (_pMediaType->formattype == FORMAT_MPEGVideo) { Infos.AddTail(L"MPEG"); const MPEG1VIDEOINFO* pInfo = GetFormatHelper(pInfo, _pMediaType); pVideoInfo = &pInfo->hdr; } else if (_pMediaType->formattype == FORMAT_MPEG2_VIDEO) { const MPEG2VIDEOINFO* pInfo = GetFormatHelper(pInfo, _pMediaType); pVideoInfo2 = &pInfo->hdr; bool bIsAVC = false; bool bIsMPEG2 = false; if (pInfo->hdr.bmiHeader.biCompression == '1CVA') { bIsAVC = true; Infos.AddTail(L"AVC (H.264)"); } else if (pInfo->hdr.bmiHeader.biCompression == 'CVMA') { bIsAVC = true; Infos.AddTail(L"MVC (Full)"); } else if (pInfo->hdr.bmiHeader.biCompression == 'CVME') { bIsAVC = true; Infos.AddTail(L"MVC (Subset)"); } else if (pInfo->hdr.bmiHeader.biCompression == 0) { Infos.AddTail(L"MPEG2"); bIsMPEG2 = true; } else { WCHAR Temp[5]; memset(Temp, 0, sizeof(Temp)); Temp[0] = (pInfo->hdr.bmiHeader.biCompression >> 0) & 0xFF; Temp[1] = (pInfo->hdr.bmiHeader.biCompression >> 8) & 0xFF; Temp[2] = (pInfo->hdr.bmiHeader.biCompression >> 16) & 0xFF; Temp[3] = (pInfo->hdr.bmiHeader.biCompression >> 24) & 0xFF; Infos.AddTail(Temp); } if (bIsMPEG2) { Infos.AddTail(MPEG2_Profile[pInfo->dwProfile]); } else if (pInfo->dwProfile) { if (bIsAVC) { switch (pInfo->dwProfile) { case 44: Infos.AddTail(L"CAVLC Profile"); break; case 66: Infos.AddTail(L"Baseline Profile"); break; case 77: Infos.AddTail(L"Main Profile"); break; case 88: Infos.AddTail(L"Extended Profile"); break; case 100: Infos.AddTail(L"High Profile"); break; case 110: Infos.AddTail(L"High 10 Profile"); break; case 118: Infos.AddTail(L"Multiview High Profile"); break; case 122: Infos.AddTail(L"High 4:2:2 Profile"); break; case 244: Infos.AddTail(L"High 4:4:4 Profile"); break; case 128: Infos.AddTail(L"Stereo High Profile"); break; default: Infos.AddTail(FormatString(L"Profile %d", pInfo->dwProfile)); break; } } else { Infos.AddTail(FormatString(L"Profile %d", pInfo->dwProfile)); } } if (bIsMPEG2) { Infos.AddTail(MPEG2_Level[pInfo->dwLevel]); } else if (pInfo->dwLevel) { if (bIsAVC) { Infos.AddTail(FormatString(L"Level %1.1f", double(pInfo->dwLevel) / 10.0)); } else { Infos.AddTail(FormatString(L"Level %d", pInfo->dwLevel)); } } } else if (_pMediaType->formattype == FORMAT_VIDEOINFO2) { const VIDEOINFOHEADER2* pInfo = GetFormatHelper(pInfo, _pMediaType); pVideoInfo2 = pInfo; bool bIsVC1 = false; DWORD CodecType = pInfo->bmiHeader.biCompression; if (CodecType == '1CVW') { bIsVC1 = true; Infos.AddTail(L"VC-1"); } else if (CodecType) { WCHAR Temp[5]; memset(Temp, 0, sizeof(Temp)); Temp[0] = (CodecType >> 0) & 0xFF; Temp[1] = (CodecType >> 8) & 0xFF; Temp[2] = (CodecType >> 16) & 0xFF; Temp[3] = (CodecType >> 24) & 0xFF; Infos.AddTail(Temp); } } else if (_pMediaType->subtype == MEDIASUBTYPE_DVD_SUBPICTURE) { Infos.AddTail(L"DVD Sub Picture"); } else if (_pMediaType->subtype == MEDIASUBTYPE_SVCD_SUBPICTURE) { Infos.AddTail(L"SVCD Sub Picture"); } else if (_pMediaType->subtype == MEDIASUBTYPE_CVD_SUBPICTURE) { Infos.AddTail(L"CVD Sub Picture"); } if (pVideoInfo2) { if (pVideoInfo2->bmiHeader.biWidth && pVideoInfo2->bmiHeader.biHeight) { Infos.AddTail(FormatString(L"%dx%d", pVideoInfo2->bmiHeader.biWidth, pVideoInfo2->bmiHeader.biHeight)); } if (pVideoInfo2->AvgTimePerFrame) { Infos.AddTail(FormatString(L"%.3f fps", 10000000.0 / double(pVideoInfo2->AvgTimePerFrame))); } if (pVideoInfo2->dwBitRate) { Infos.AddTail(FormatBitrate(pVideoInfo2->dwBitRate)); } } else if (pVideoInfo) { if (pVideoInfo->bmiHeader.biWidth && pVideoInfo->bmiHeader.biHeight) { Infos.AddTail(FormatString(L"%dx%d", pVideoInfo->bmiHeader.biWidth, pVideoInfo->bmiHeader.biHeight)); } if (pVideoInfo->AvgTimePerFrame) { Infos.AddTail(FormatString(L"%.3f fps", 10000000.0 / double(pVideoInfo->AvgTimePerFrame))); } if (pVideoInfo->dwBitRate) { Infos.AddTail(FormatBitrate(pVideoInfo->dwBitRate)); } } } else if (_pMediaType->majortype == MEDIATYPE_Audio) { MajorType = "Audio"; if (pClipInfo) { CString name = ISO6392ToLanguage(pClipInfo->m_LanguageCode); if (!name.IsEmpty()) { Infos.AddTail(name); } } else { if (!lang.IsEmpty()) { Infos.AddTail(lang); } } if (_pMediaType->formattype == FORMAT_WaveFormatEx) { const WAVEFORMATEX* pInfo = GetFormatHelper(pInfo, _pMediaType); if (_pMediaType->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { Infos.AddTail(L"DVD LPCM"); } else if (_pMediaType->subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) { const WAVEFORMATEX_HDMV_LPCM* pInfoHDMV = GetFormatHelper(pInfoHDMV, _pMediaType); UNREFERENCED_PARAMETER(pInfoHDMV); Infos.AddTail(L"HDMV LPCM"); } if (_pMediaType->subtype == MEDIASUBTYPE_DOLBY_DDPLUS) { Infos.AddTail(L"Dolby Digital Plus"); } else if (_pMediaType->subtype == MEDIASUBTYPE_DOLBY_TRUEHD) { Infos.AddTail(L"TrueHD"); } else { switch (pInfo->wFormatTag) { case WAVE_FORMAT_PS2_PCM: { Infos.AddTail(L"PS2 PCM"); } break; case WAVE_FORMAT_PS2_ADPCM: { Infos.AddTail(L"PS2 ADPCM"); } break; case WAVE_FORMAT_DVD_DTS: { if (pPresentationDesc) { Infos.AddTail(pPresentationDesc); } else { Infos.AddTail(L"DTS"); } } break; case WAVE_FORMAT_DOLBY_AC3: { if (pPresentationDesc) { Infos.AddTail(pPresentationDesc); } else { Infos.AddTail(L"Dolby Digital"); } } break; case WAVE_FORMAT_AAC: { Infos.AddTail(L"AAC"); } break; case WAVE_FORMAT_MPEGLAYER3: { Infos.AddTail(L"MP3"); } break; case WAVE_FORMAT_MPEG: { const MPEG1WAVEFORMAT* pInfoMPEG1 = GetFormatHelper(pInfoMPEG1, _pMediaType); int layer = GetHighestBitSet32(pInfoMPEG1->fwHeadLayer) + 1; Infos.AddTail(FormatString(L"MPEG1 - Layer %d", layer)); } break; } } if (pClipInfo && (pClipInfo->m_SampleRate == BDVM_SampleRate_48_192 || pClipInfo->m_SampleRate == BDVM_SampleRate_48_96)) { switch (pClipInfo->m_SampleRate) { case BDVM_SampleRate_48_192: Infos.AddTail(FormatString(L"192(48) kHz")); break; case BDVM_SampleRate_48_96: Infos.AddTail(FormatString(L"96(48) kHz")); break; } } else if (pInfo->nSamplesPerSec) { Infos.AddTail(FormatString(L"%.1f kHz", double(pInfo->nSamplesPerSec) / 1000.0)); } if (pInfo->nChannels) { Infos.AddTail(FormatString(L"%d chn", pInfo->nChannels)); } if (pInfo->wBitsPerSample) { Infos.AddTail(FormatString(L"%d bit", pInfo->wBitsPerSample)); } if (pInfo->nAvgBytesPerSec) { Infos.AddTail(FormatBitrate(pInfo->nAvgBytesPerSec * 8)); } } } else if (_pMediaType->majortype == MEDIATYPE_Subtitle) { MajorType = "Subtitle"; if (pPresentationDesc) { Infos.AddTail(pPresentationDesc); } if (pClipInfo) { CString name = ISO6392ToLanguage(pClipInfo->m_LanguageCode); if (!name.IsEmpty()) { Infos.AddHead(name); } else if (!lang.IsEmpty()) { Infos.AddHead(lang); } } else if (_pMediaType->cbFormat == sizeof(SUBTITLEINFO)) { const SUBTITLEINFO* pInfo = GetFormatHelper(pInfo, _pMediaType); CString name = ISO6392ToLanguage(pInfo->IsoLang); if (!lang.IsEmpty()) { Infos.AddHead(lang); } else if (!name.IsEmpty()) { Infos.AddHead(name); } if (pInfo->TrackName[0]) { Infos.AddTail(pInfo->TrackName); } } else if (!lang.IsEmpty()) { Infos.AddHead(lang); } } if (!Infos.IsEmpty()) { CString Ret; Ret += MajorType; Ret += " - "; bool bFirst = true; for (POSITION pos = Infos.GetHeadPosition(); pos; Infos.GetNext(pos)) { CString& String = Infos.GetAt(pos); if (bFirst) { Ret += String; } else { Ret += L", " + String; } bFirst = false; } return Ret; } return CString(); } // // CMpegSplitterFilter // CMpegSplitterFilter::CMpegSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid) : CBaseSplitterFilter(NAME("CMpegSplitterFilter"), pUnk, phr, clsid) , m_pPipoBimbo(false) , m_rtPlaylistDuration(0) , m_csAudioLanguageOrder(_T("")) , m_csSubtitlesLanguageOrder(_T("")) , m_useFastStreamChange(true) , m_ForcedSub(false) , m_AC3CoreOnly(0) , m_nVC1_GuidFlag(1) , m_AlternativeDuration(false) { #ifdef STANDALONE_FILTER CRegKey key; TCHAR buff[256]; ULONG len; if (ERROR_SUCCESS == key.Open(HKEY_CURRENT_USER, _T("Software\\Gabest\\Filters\\MPEG Splitter"), KEY_READ)) { DWORD dw; if (ERROR_SUCCESS == key.QueryDWORDValue(_T("UseFastStreamChange"), dw)) { m_useFastStreamChange = !!dw; } if (ERROR_SUCCESS == key.QueryDWORDValue(_T("ForcedSub"), dw)) { m_ForcedSub = !!dw; } len = _countof(buff); memset(buff, 0, sizeof(buff)); if (ERROR_SUCCESS == key.QueryStringValue(_T("AudioLanguageOrder"), buff, &len)) { m_csAudioLanguageOrder = CString(buff); } len = _countof(buff); memset(buff, 0, sizeof(buff)); if (ERROR_SUCCESS == key.QueryStringValue(_T("SubtitlesLanguageOrder"), buff, &len)) { m_csSubtitlesLanguageOrder = CString(buff); } if (ERROR_SUCCESS == key.QueryDWORDValue(_T("VC1_Decoder_Output"), dw)) { m_nVC1_GuidFlag = dw; } if (ERROR_SUCCESS == key.QueryDWORDValue(_T("AC3CoreOnly"), dw)) { m_AC3CoreOnly = dw; } if (ERROR_SUCCESS == key.QueryDWORDValue(_T("AlternativeDuration"), dw)) { m_AlternativeDuration = !!dw; } } #else m_useFastStreamChange = !!AfxGetApp()->GetProfileInt(_T("Filters\\MPEG Splitter"), _T("UseFastStreamChange"), m_useFastStreamChange); m_ForcedSub = !!AfxGetApp()->GetProfileInt(_T("Filters\\MPEG Splitter"), _T("ForcedSub"), m_ForcedSub); m_csSubtitlesLanguageOrder = AfxGetApp()->GetProfileString(IDS_R_SETTINGS, IDS_RS_SUBTITLESLANGORDER, _T("")); m_csAudioLanguageOrder = AfxGetApp()->GetProfileString(IDS_R_SETTINGS, IDS_RS_AUDIOSLANGORDER, _T("")); m_nVC1_GuidFlag = AfxGetApp()->GetProfileInt(_T("Filters\\MPEG Splitter"), _T("VC1_Decoder_Output"), m_nVC1_GuidFlag); if (m_nVC1_GuidFlag < 1 || m_nVC1_GuidFlag > 3) { m_nVC1_GuidFlag = 1; } m_AC3CoreOnly = AfxGetApp()->GetProfileInt(_T("Filters\\MPEG Splitter"), _T("AC3CoreOnly"), m_AC3CoreOnly); m_AlternativeDuration = !!AfxGetApp()->GetProfileInt(_T("Filters\\MPEG Splitter"), _T("AlternativeDuration"), m_AlternativeDuration); #endif } bool CMpegSplitterFilter::StreamIsTrueHD(const WORD pid) { int iProgram = -1; const CHdmvClipInfo::Stream* pClipInfo; const CMpegSplitterFile::program* pProgram = m_pFile->FindProgram(pid, iProgram, pClipInfo); int StreamType = pClipInfo ? pClipInfo->m_Type : pProgram ? pProgram->streams[iProgram].type : 0; return (StreamType == AUDIO_STREAM_AC3_TRUE_HD); } STDMETHODIMP CMpegSplitterFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv) { CheckPointer(ppv, E_POINTER); return QI(IMpegSplitterFilter) QI(ISpecifyPropertyPages) QI(ISpecifyPropertyPages2) QI(IAMStreamSelect) __super::NonDelegatingQueryInterface(riid, ppv); } STDMETHODIMP CMpegSplitterFilter::GetClassID(CLSID* pClsID) { CheckPointer(pClsID, E_POINTER); if (m_pPipoBimbo) { memcpy(pClsID, &CLSID_WMAsfReader, sizeof(GUID)); return S_OK; } else { return __super::GetClassID(pClsID); } } STDMETHODIMP CMpegSplitterFilter::QueryFilterInfo(FILTER_INFO* pInfo) { CheckPointer(pInfo, E_POINTER); ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); if (m_pName && m_pName[0] == L'M' && m_pName[1] == L'P' && m_pName[2] == L'C') { (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName); } else { wcscpy_s(pInfo->achName, MpegSourceName); } pInfo->pGraph = m_pGraph; if (m_pGraph) { m_pGraph->AddRef(); } return S_OK; } void CMpegSplitterFilter::ReadClipInfo(LPCOLESTR pszFileName) { if (wcslen(pszFileName) > 0) { WCHAR Drive[_MAX_DRIVE]; WCHAR Dir[MAX_PATH]; WCHAR Filename[MAX_PATH]; WCHAR Ext[_MAX_EXT]; if (_wsplitpath_s(pszFileName, Drive, _countof(Drive), Dir, _countof(Dir), Filename, _countof(Filename), Ext, _countof(Ext)) == 0) { CString strClipInfo; _wcslwr_s(Ext, _countof(Ext)); if (wcscmp(Ext, L".ssif") == 0) { if (Drive[0]) { strClipInfo.Format(_T("%s\\%s\\..\\..\\CLIPINF\\%s.clpi"), Drive, Dir, Filename); } else { strClipInfo.Format(_T("%s\\..\\..\\CLIPINF\\%s.clpi"), Dir, Filename); } } else { if (Drive[0]) { strClipInfo.Format(_T("%s\\%s\\..\\CLIPINF\\%s.clpi"), Drive, Dir, Filename); } else { strClipInfo.Format(_T("%s\\..\\CLIPINF\\%s.clpi"), Dir, Filename); } } m_ClipInfo.ReadInfo(strClipInfo); } } } STDMETHODIMP CMpegSplitterFilter::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) { return __super::Load(pszFileName, pmt); } HRESULT CMpegSplitterFilter::DemuxNextPacket(REFERENCE_TIME rtStartOffset) { HRESULT hr; BYTE b; if (m_pFile->m_type == mpeg_ps || m_pFile->m_type == mpeg_es) { if (!m_pFile->NextMpegStartCode(b)) { return S_FALSE; } if (b == 0xba) { // program stream header CMpegSplitterFile::pshdr h; if (!m_pFile->Read(h)) { return S_FALSE; } } else if (b == 0xbb) { // program stream system header CMpegSplitterFile::pssyshdr h; if (!m_pFile->Read(h)) { return S_FALSE; } } else if ((b >= 0xbd && b < 0xf0) || (b == 0xfd)) { // pes packet CMpegSplitterFile::peshdr h; if (!m_pFile->Read(h, b) || !h.len) { return S_FALSE; } if (h.type == CMpegSplitterFile::mpeg2 && h.scrambling) { ASSERT(0); return E_FAIL; } __int64 pos = m_pFile->GetPos(); DWORD TrackNumber = m_pFile->AddStream(0, b, h.id_ext, h.len); if (GetOutputPin(TrackNumber)) { CAutoPtr p(DEBUG_NEW Packet()); p->TrackNumber = TrackNumber; p->bSyncPoint = !!h.fpts; p->bAppendable = !h.fpts; p->rtStart = h.fpts ? (h.pts - rtStartOffset) : Packet::INVALID_TIME; p->rtStop = p->rtStart + 1; p->SetCount(h.len - (size_t)(m_pFile->GetPos() - pos)); m_pFile->ByteRead(p->GetData(), h.len - (m_pFile->GetPos() - pos)); hr = DeliverPacket(p); } m_pFile->Seek(pos + h.len); } } else if (m_pFile->m_type == mpeg_ts) { CMpegSplitterFile::tshdr h; if (!m_pFile->Read(h)) { return S_FALSE; } __int64 pos = m_pFile->GetPos(); m_pFile->UpdatePrograms(h, false); if (h.payload && ISVALIDPID(h.pid)) { DWORD TrackNumber = h.pid; CMpegSplitterFile::peshdr h2; if (h.payloadstart && m_pFile->NextMpegStartCode(b, 4) && m_pFile->Read(h2, b)) { // pes packet if (h2.type == CMpegSplitterFile::mpeg2 && h2.scrambling) { ASSERT(0); return E_FAIL; } TrackNumber = m_pFile->AddStream(h.pid, b, 0, h.bytes - (DWORD)(m_pFile->GetPos() - pos)); } if (GetOutputPin(TrackNumber)) { CAutoPtr p(DEBUG_NEW Packet()); p->TrackNumber = TrackNumber; p->bSyncPoint = !!h2.fpts; p->bAppendable = !h2.fpts; if (h.fPCR) { CRefTime rtNow; StreamTime(rtNow); //TRACE(_T("Now=%s PCR=%s\n"), ReftimeToString(rtNow.m_time), ReftimeToString(h.PCR)); } p->rtStart = h2.fpts ? (h2.pts - rtStartOffset) : Packet::INVALID_TIME; p->rtStop = p->rtStart + 1; p->SetCount(h.bytes - (size_t)(m_pFile->GetPos() - pos)); int nBytes = int(h.bytes - (m_pFile->GetPos() - pos)); m_pFile->ByteRead(p->GetData(), nBytes); hr = DeliverPacket(p); } } m_pFile->Seek(h.next); } else if (m_pFile->m_type == mpeg_pva) { CMpegSplitterFile::pvahdr h; if (!m_pFile->Read(h)) { return S_FALSE; } DWORD TrackNumber = h.streamid; __int64 pos = m_pFile->GetPos(); if (GetOutputPin(TrackNumber)) { CAutoPtr p(DEBUG_NEW Packet()); p->TrackNumber = TrackNumber; p->bSyncPoint = !!h.fpts; p->bAppendable = !h.fpts; p->rtStart = h.fpts ? (h.pts - rtStartOffset) : Packet::INVALID_TIME; p->rtStop = p->rtStart + 1; p->SetCount(h.length); m_pFile->ByteRead(p->GetData(), h.length); hr = DeliverPacket(p); } m_pFile->Seek(pos + h.length); } return S_OK; } // HRESULT CMpegSplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader) { CheckPointer(pAsyncReader, E_POINTER); HRESULT hr = E_FAIL; m_pFile.Free(); ReadClipInfo(GetPartFilename(pAsyncReader)); m_pFile.Attach(DEBUG_NEW CMpegSplitterFile(pAsyncReader, hr, m_ClipInfo.IsHdmv(), m_ClipInfo, m_nVC1_GuidFlag, m_ForcedSub, m_AC3CoreOnly, m_AlternativeDuration)); if (!m_pFile) { return E_OUTOFMEMORY; } if (FAILED(hr)) { m_pFile.Free(); return hr; } if (m_pFile->m_type == mpeg_ps) { if (m_pInput && m_pInput->IsConnected() && (GetCLSID(m_pInput->GetConnected()) == GUIDFromCString(_T("{773EAEDE-D5EE-4fce-9C8F-C4F53D0A2F73}")))) { // MPC VTS Reader pTI = GetFilterFromPin(m_pInput->GetConnected()); } } CString cs_audioProgram = _T(""); CString cs_subpicProgram = _T(""); // Create if (m_ClipInfo.IsHdmv()) { for (size_t i = 0; i < m_ClipInfo.GetStreamNumber(); i++) { CHdmvClipInfo::Stream* stream = m_ClipInfo.GetStreamByIndex(i); if (stream->m_Type == PRESENTATION_GRAPHICS_STREAM) { m_pFile->AddHdmvPGStream(stream->m_PID, stream->m_LanguageCode); } } } CString lang = _T(""); CAtlArray lang_list_audio; CAtlArray lang_list_subpic; int Idx_audio = 0; int Idx_subpic = 0; if (!m_csAudioLanguageOrder.IsEmpty()) { int tPos = 0; lang = m_csAudioLanguageOrder.Tokenize(_T(",; "), tPos); while (tPos != -1) { if (!lang.IsEmpty()) { lang_list_audio.Add(lang); } lang = m_csAudioLanguageOrder.Tokenize(_T(",; "), tPos); } } if (!m_csSubtitlesLanguageOrder.IsEmpty()) { int tPos = 0; lang = m_csSubtitlesLanguageOrder.Tokenize(_T(",; "), tPos); while (tPos != -1) { if (!lang.IsEmpty()) { lang_list_subpic.Add(lang); } lang = m_csSubtitlesLanguageOrder.Tokenize(_T(",; "), tPos); } } for (int i = 0; i < _countof(m_pFile->m_streams); i++) { POSITION pos = m_pFile->m_streams[i].GetHeadPosition(); while (pos) { CMpegSplitterFile::stream& s = m_pFile->m_streams[i].GetNext(pos); CAtlArray mts; mts.Add(s.mt); CStringW name = CMpegSplitterFile::CStreamList::ToString(i); CStringW str; if (i == CMpegSplitterFile::subpic && s.pid == NO_SUBTITLE_PID) { str = NO_SUBTITLE_NAME; continue; } else { int iProgram = -1; const CHdmvClipInfo::Stream* pClipInfo; const CMpegSplitterFile::program* pProgram = m_pFile->FindProgram(s.pid, iProgram, pClipInfo); const wchar_t* pStreamName = nullptr; int StreamType = pClipInfo ? pClipInfo->m_Type : pProgram ? pProgram->streams[iProgram].type : 0; pStreamName = StreamTypeToName((PES_STREAM_TYPE)StreamType); CString lang_name = _T(""); m_pFile->m_pPMT_Lang.Lookup(s.pid, lang_name); lang_name = pTI ? pTI->GetTrackName(s.ps1id) : lang_name; CString FormatDesc = GetMediaTypeDesc(&s.mt, pClipInfo, StreamType, lang_name); if (!FormatDesc.IsEmpty()) { str.Format(L"%s (%04x,%02x,%02x)", FormatDesc.GetString(), s.pid, s.pesid, s.ps1id); // TODO: make this nicer } else if (pStreamName) { str.Format(L"%s - %s (%04x,%02x,%02x)", name, pStreamName, s.pid, s.pesid, s.ps1id); // TODO: make this nicer } else { str.Format(L"%s (%04x,%02x,%02x)", name, s.pid, s.pesid, s.ps1id); // TODO: make this nicer } } if (i == CMpegSplitterFile::audio) { CString str_tmp = str.Mid(8).MakeLower(); if (Idx_audio == 0) { Idx_audio = 1; } else { Idx_audio++; } for (size_t j = 0; j < lang_list_audio.GetCount(); j++) { int num = _tstoi(lang_list_audio[j]); if (num > 0) { // this is track number if (Idx_audio != num) { continue; // not matched } } else { // this is lang string int len = lang_list_audio[j].GetLength(); if (str_tmp.Left(len) != lang_list_audio[j]) { continue; // not matched } } cs_audioProgram = str; break; } } if (i == CMpegSplitterFile::subpic) { CString str_tmp = str.Mid(11).MakeLower(); if (Idx_subpic == 0) { Idx_subpic = 1; } else { Idx_subpic++; } for (size_t j = 0; j < lang_list_subpic.GetCount(); j++) { int num = _tstoi(lang_list_subpic[j]); if (num > 0) { // this is track number if (Idx_subpic != num) { continue; // not matched } } else { // this is lang string int len = lang_list_subpic[j].GetLength(); if (str_tmp.Left(len) != lang_list_subpic[j]) { continue; // not matched } } cs_subpicProgram = str; break; } } } } m_rtNewStart = m_rtCurrent = 0; m_rtNewStop = m_rtStop = m_rtDuration = 0; for (int i = 0; i < _countof(m_pFile->m_streams); i++) { POSITION pos = m_pFile->m_streams[i].GetHeadPosition(); while (pos) { CMpegSplitterFile::stream& s = m_pFile->m_streams[i].GetNext(pos); CAtlArray mts; mts.Add(s.mt); CStringW name = CMpegSplitterFile::CStreamList::ToString(i); CStringW str; if (i == CMpegSplitterFile::subpic && s.pid == NO_SUBTITLE_PID) { str = NO_SUBTITLE_NAME; } else { int iProgram = -1; const CHdmvClipInfo::Stream* pClipInfo; const CMpegSplitterFile::program* pProgram = m_pFile->FindProgram(s.pid, iProgram, pClipInfo); const wchar_t* pStreamName = nullptr; int StreamType = pClipInfo ? pClipInfo->m_Type : pProgram ? pProgram->streams[iProgram].type : 0; pStreamName = StreamTypeToName((PES_STREAM_TYPE)StreamType); CString lang_name = _T(""); m_pFile->m_pPMT_Lang.Lookup(s.pid, lang_name); lang_name = pTI ? pTI->GetTrackName(s.ps1id) : lang_name; CString FormatDesc = GetMediaTypeDesc(&s.mt, pClipInfo, StreamType, lang_name); if (!FormatDesc.IsEmpty()) { str.Format(L"%s (%04x,%02x,%02x)", FormatDesc.GetString(), s.pid, s.pesid, s.ps1id); // TODO: make this nicer } else if (pStreamName) { str.Format(L"%s - %s (%04x,%02x,%02x)", name, pStreamName, s.pid, s.pesid, s.ps1id); // TODO: make this nicer } else { str.Format(L"%s (%04x,%02x,%02x)", name, s.pid, s.pesid, s.ps1id); // TODO: make this nicer } } CAutoPtr pPinOut(DEBUG_NEW CMpegSplitterOutputPin(mts, str, this, this, &hr, m_pFile->m_type)); if (i == CMpegSplitterFile::subpic) { (static_cast(pPinOut.m_p))->SetMaxShift(_I64_MAX); } if (i == CMpegSplitterFile::audio) { if (!cs_audioProgram.IsEmpty()) { if (!cs_audioProgram.Compare(str) && (S_OK == AddOutputPin(s, pPinOut))) { break; } } else { if (S_OK == AddOutputPin(s, pPinOut)) { break; } } } else if (i == CMpegSplitterFile::subpic) { if (!cs_subpicProgram.IsEmpty()) { if (!cs_subpicProgram.Compare(str) && (S_OK == AddOutputPin(s, pPinOut))) { break; } } else { if ((m_pFile->m_streams[CMpegSplitterFile::subpic].GetCount() == 1) && (S_OK == AddOutputPin(s, pPinOut))) { break; } else if ((s.pid != NO_SUBTITLE_PID) && (S_OK == AddOutputPin(s, pPinOut))) { break; } } } else { if (S_OK == AddOutputPin(s, pPinOut)) { break; } } } } if (m_rtPlaylistDuration) { m_rtNewStop = m_rtStop = m_rtDuration = m_rtPlaylistDuration; } else if (m_pFile->IsRandomAccess() && m_pFile->m_rate) { m_rtNewStop = m_rtStop = m_rtDuration = 10000000i64 * m_pFile->GetLength() / m_pFile->m_rate; } return !m_pOutputs.IsEmpty() ? S_OK : E_FAIL; } bool CMpegSplitterFilter::DemuxInit() { SetThreadName((DWORD) - 1, "CMpegSplitterFilter"); if (!m_pFile) { return false; } m_rtStartOffset = 0; return true; } void CMpegSplitterFilter::DemuxSeek(REFERENCE_TIME rt) { CAtlList* pMasterStream = m_pFile->GetMasterStream(); if (!pMasterStream) { ASSERT(0); return; } if (m_pFile->IsStreaming()) { m_pFile->Seek(max(0, m_pFile->GetLength() - 100 * 1024)); m_rtStartOffset = m_pFile->m_rtMin + m_pFile->NextPTS(pMasterStream->GetHead()); return; } REFERENCE_TIME rtPreroll = 10000000; if (rt <= rtPreroll || m_rtDuration <= 0) { m_pFile->Seek(0); } else { __int64 len = m_pFile->GetLength(); __int64 seekpos = (__int64)(1.0 * rt / m_rtDuration * len); __int64 minseekpos = _I64_MAX; REFERENCE_TIME rtmax = rt - rtPreroll; REFERENCE_TIME rtmin = rtmax - 5000000; if (m_rtStartOffset == 0) { for (int i = 0; i < _countof(m_pFile->m_streams) - 1; i++) { POSITION pos = m_pFile->m_streams[i].GetHeadPosition(); while (pos) { DWORD TrackNum = m_pFile->m_streams[i].GetNext(pos); CBaseSplitterOutputPin* pPin = GetOutputPin(TrackNum); if (pPin && pPin->IsConnected()) { m_pFile->Seek(seekpos); __int64 curpos = seekpos; REFERENCE_TIME pdt = _I64_MIN; for (int j = 0; j < 10; j++) { REFERENCE_TIME rt2 = m_pFile->NextPTS(TrackNum); if (rt2 < 0) { break; } REFERENCE_TIME dt = rt2 - rtmax; if (dt > 0 && dt == pdt) { dt = 10000000i64; } if (rtmin <= rt2 && rt2 <= rtmax || pdt > 0 && dt < 0) { minseekpos = min(minseekpos, curpos); break; } curpos -= (__int64)(1.0 * dt / m_rtDuration * len); m_pFile->Seek(curpos); //pdt = dt; } } } } } if (minseekpos != _I64_MAX) { seekpos = minseekpos; } else { // this file is probably screwed up, try plan B, seek simply by bitrate rt -= rtPreroll; seekpos = (__int64)(1.0 * rt / m_rtDuration * len); m_pFile->Seek(seekpos); m_rtStartOffset = m_pFile->m_rtMin + m_pFile->NextPTS(pMasterStream->GetHead()) - rt; } m_pFile->Seek(seekpos); } } bool CMpegSplitterFilter::DemuxLoop() { REFERENCE_TIME rtStartOffset = m_rtStartOffset ? m_rtStartOffset : m_pFile->m_rtMin; HRESULT hr = S_OK; while (SUCCEEDED(hr) && !CheckRequest(nullptr)) { if ((hr = m_pFile->HasMoreData(1024 * 500)) == S_OK) if ((hr = DemuxNextPacket(rtStartOffset)) == S_FALSE) { Sleep(1); } } return true; } bool CMpegSplitterFilter::BuildPlaylist(LPCTSTR pszFileName, CAtlList& Items) { m_rtPlaylistDuration = 0; return SUCCEEDED(m_ClipInfo.ReadPlaylist(pszFileName, m_rtPlaylistDuration, Items)) ? true : false; } bool CMpegSplitterFilter::BuildChapters(LPCTSTR pszFileName, CAtlList& PlaylistItems, CAtlList& Items) { return SUCCEEDED(m_ClipInfo.ReadChapters(pszFileName, PlaylistItems, Items)) ? true : false; } // IAMStreamSelect STDMETHODIMP CMpegSplitterFilter::Count(DWORD* pcStreams) { CheckPointer(pcStreams, E_POINTER); *pcStreams = 0; for (int i = 0; i < _countof(m_pFile->m_streams); i++) { (*pcStreams) += m_pFile->m_streams[i].GetCount(); } return S_OK; } STDMETHODIMP CMpegSplitterFilter::Enable(long lIndex, DWORD dwFlags) { if (!(dwFlags & AMSTREAMSELECTENABLE_ENABLE)) { return E_NOTIMPL; } for (int i = 0, j = 0; i < _countof(m_pFile->m_streams); i++) { int cnt = (int)m_pFile->m_streams[i].GetCount(); if (lIndex >= j && lIndex < j + cnt) { lIndex -= j; POSITION pos = m_pFile->m_streams[i].FindIndex(lIndex); if (!pos) { return E_UNEXPECTED; } CMpegSplitterFile::stream& to = m_pFile->m_streams[i].GetAt(pos); pos = m_pFile->m_streams[i].GetHeadPosition(); while (pos) { CMpegSplitterFile::stream& from = m_pFile->m_streams[i].GetNext(pos); if (!GetOutputPin(from)) { continue; } if (m_useFastStreamChange) { PauseGraph; ResumeGraph; } HRESULT hr; if (FAILED(hr = RenameOutputPin(from, to, &to.mt))) { return hr; } #if 0 // Don't rename other pin for Hdmv! int iProgram; const CHdmvClipInfo::Stream* pClipInfo; const CMpegSplitterFile::program* p = m_pFile->FindProgram(to.pid, iProgram, pClipInfo); if (p != nullptr && !m_ClipInfo.IsHdmv() && !m_pFile->IsHdmv()) { for (int k = 0; k < _countof(m_pFile->m_streams); k++) { if (k == i) { continue; } pos = m_pFile->m_streams[k].GetHeadPosition(); while (pos) { CMpegSplitterFile::stream& from = m_pFile->m_streams[k].GetNext(pos); if (!GetOutputPin(from)) { continue; } for (int l = 0; l < _countof(p->streams); l++) { if (const CMpegSplitterFile::stream* s = m_pFile->m_streams[k].FindStream(p->streams[l].pid)) { if (from != *s) { hr = RenameOutputPin(from, *s, &s->mt); } break; } } } } } #endif return S_OK; } } j += cnt; } return S_FALSE; } LONGLONG GetMediaTypeQuality(const CMediaType* _pMediaType, int _PresentationFormat) { if (_pMediaType->formattype == FORMAT_WaveFormatEx) { __int64 Ret = 0; const WAVEFORMATEX* pInfo = GetFormatHelper(pInfo, _pMediaType); int TypePriority = 0; if (_pMediaType->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO) { TypePriority = 12; } else if (_pMediaType->subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) { TypePriority = 12; } else { if (_PresentationFormat == AUDIO_STREAM_DTS_HD_MASTER_AUDIO) { TypePriority = 12; } else if (_PresentationFormat == AUDIO_STREAM_DTS_HD) { TypePriority = 11; } else if (_PresentationFormat == AUDIO_STREAM_AC3_TRUE_HD) { TypePriority = 12; } else if (_PresentationFormat == AUDIO_STREAM_AC3_PLUS) { TypePriority = 10; } else { switch (pInfo->wFormatTag) { case WAVE_FORMAT_PS2_PCM: { TypePriority = 12; } break; case WAVE_FORMAT_PS2_ADPCM: { TypePriority = 4; } break; case WAVE_FORMAT_DVD_DTS: { TypePriority = 9; } break; case WAVE_FORMAT_DOLBY_AC3: { TypePriority = 8; } break; case WAVE_FORMAT_AAC: { TypePriority = 7; } break; case WAVE_FORMAT_MPEGLAYER3: { TypePriority = 6; } break; case WAVE_FORMAT_MPEG: { TypePriority = 5; } break; } } } Ret += __int64(TypePriority) * 100000000i64 * 1000000000i64; Ret += __int64(pInfo->nChannels) * 1000000i64 * 1000000000i64; Ret += __int64(pInfo->nSamplesPerSec) * 10i64 * 1000000000i64; Ret += __int64(pInfo->wBitsPerSample) * 10000000i64; Ret += __int64(pInfo->nAvgBytesPerSec); return Ret; } return 0; } STDMETHODIMP CMpegSplitterFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk) { for (int i = 0, j = 0; i < _countof(m_pFile->m_streams); i++) { int cnt = (int)m_pFile->m_streams[i].GetCount(); if (lIndex >= j && lIndex < j + cnt) { lIndex -= j; POSITION pos = m_pFile->m_streams[i].FindIndex(lIndex); if (!pos) { return E_UNEXPECTED; } CMpegSplitterFile::stream& s = m_pFile->m_streams[i].GetAt(pos); CHdmvClipInfo::Stream* pStream = m_ClipInfo.FindStream(s.pid); if (ppmt) { *ppmt = CreateMediaType(&s.mt); } if (pdwFlags) { *pdwFlags = GetOutputPin(s) ? (AMSTREAMSELECTINFO_ENABLED | AMSTREAMSELECTINFO_EXCLUSIVE) : 0; } if (plcid) { *plcid = pStream ? pStream->m_LCID : 0; } if (pdwGroup) { *pdwGroup = i; } if (ppObject) { *ppObject = nullptr; } if (ppUnk) { *ppUnk = nullptr; } if (ppszName) { CStringW name = CMpegSplitterFile::CStreamList::ToString(i); CStringW str; if (i == CMpegSplitterFile::subpic && s.pid == NO_SUBTITLE_PID) { str = NO_SUBTITLE_NAME; if (plcid) { *plcid = (LCID)LCID_NOSUBTITLES; } } else { int iProgram; const CHdmvClipInfo::Stream* pClipInfo; const CMpegSplitterFile::program* pProgram = m_pFile->FindProgram(s.pid, iProgram, pClipInfo); const wchar_t* pStreamName = nullptr; int StreamType = pClipInfo ? pClipInfo->m_Type : pProgram ? pProgram->streams[iProgram].type : 0; pStreamName = StreamTypeToName((PES_STREAM_TYPE)StreamType); CString lang_name = _T(""); m_pFile->m_pPMT_Lang.Lookup(s.pid, lang_name); lang_name = pTI ? pTI->GetTrackName(s.ps1id) : lang_name; CString FormatDesc = GetMediaTypeDesc(&s.mt, pClipInfo, StreamType, lang_name); if (!FormatDesc.IsEmpty()) { str.Format(L"%s (%04x,%02x,%02x)", FormatDesc.GetString(), s.pid, s.pesid, s.ps1id); // TODO: make this nicer } else if (pStreamName) { str.Format(L"%s - %s (%04x,%02x,%02x)", name, pStreamName, s.pid, s.pesid, s.ps1id); // TODO: make this nicer } else { str.Format(L"%s (%04x,%02x,%02x)", name, s.pid, s.pesid, s.ps1id); // TODO: make this nicer } } *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength() + 1) * sizeof(WCHAR)); if (*ppszName == nullptr) { return E_OUTOFMEMORY; } wcscpy_s(*ppszName, str.GetLength() + 1, str); } } j += cnt; } return S_OK; } // ISpecifyPropertyPages2 STDMETHODIMP CMpegSplitterFilter::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(CMpegSplitterSettingsWnd); } else { hr = E_OUTOFMEMORY; } return hr; } STDMETHODIMP CMpegSplitterFilter::CreatePage(const GUID& guid, IPropertyPage** ppPage) { CheckPointer(ppPage, E_POINTER); if (*ppPage != nullptr) { return E_INVALIDARG; } HRESULT hr; if (guid == __uuidof(CMpegSplitterSettingsWnd)) { (*ppPage = DEBUG_NEW CInternalPropertyPageTempl(nullptr, &hr))->AddRef(); } return *ppPage ? S_OK : E_FAIL; } // IMpegSplitterFilter STDMETHODIMP CMpegSplitterFilter::Apply() { #ifdef STANDALONE_FILTER CRegKey key; if (ERROR_SUCCESS == key.Create(HKEY_CURRENT_USER, _T("Software\\Gabest\\Filters\\MPEG Splitter"))) { key.SetDWORDValue(_T("UseFastStreamChange"), m_useFastStreamChange); key.SetDWORDValue(_T("ForcedSub"), m_ForcedSub); key.SetStringValue(_T("AudioLanguageOrder"), m_csAudioLanguageOrder); key.SetStringValue(_T("SubtitlesLanguageOrder"), m_csSubtitlesLanguageOrder); key.SetDWORDValue(_T("VC1_Decoder_Output"), m_nVC1_GuidFlag); key.SetDWORDValue(_T("AC3CoreOnly"), m_AC3CoreOnly); key.SetDWORDValue(_T("AlternativeDuration"), m_AlternativeDuration); } #else AfxGetApp()->WriteProfileInt(_T("Filters\\MPEG Splitter"), _T("UseFastStreamChange"), m_useFastStreamChange); AfxGetApp()->WriteProfileInt(_T("Filters\\MPEG Splitter"), _T("ForcedSub"), m_ForcedSub); AfxGetApp()->WriteProfileInt(_T("Filters\\MPEG Splitter"), _T("VC1_Decoder_Output"), m_nVC1_GuidFlag); AfxGetApp()->WriteProfileInt(_T("Filters\\MPEG Splitter"), _T("AC3CoreOnly"), m_AC3CoreOnly); AfxGetApp()->WriteProfileInt(_T("Filters\\MPEG Splitter"), _T("AlternativeDuration"), m_AlternativeDuration); #endif return S_OK; } STDMETHODIMP CMpegSplitterFilter::SetFastStreamChange(BOOL nValue) { CAutoLock cAutoLock(&m_csProps); m_useFastStreamChange = !!nValue; return S_OK; } STDMETHODIMP_(BOOL) CMpegSplitterFilter::GetFastStreamChange() { CAutoLock cAutoLock(&m_csProps); return m_useFastStreamChange; } STDMETHODIMP CMpegSplitterFilter::SetForcedSub(BOOL nValue) { CAutoLock cAutoLock(&m_csProps); m_ForcedSub = !!nValue; return S_OK; } STDMETHODIMP_(BOOL) CMpegSplitterFilter::GetForcedSub() { CAutoLock cAutoLock(&m_csProps); return m_ForcedSub; } STDMETHODIMP CMpegSplitterFilter::SetAudioLanguageOrder(WCHAR* nValue) { CAutoLock cAutoLock(&m_csProps); m_csAudioLanguageOrder = nValue; return S_OK; } STDMETHODIMP_(WCHAR*) CMpegSplitterFilter::GetAudioLanguageOrder() { CAutoLock cAutoLock(&m_csProps); return m_csAudioLanguageOrder.GetBuffer(); } STDMETHODIMP CMpegSplitterFilter::SetSubtitlesLanguageOrder(WCHAR* nValue) { CAutoLock cAutoLock(&m_csProps); m_csSubtitlesLanguageOrder = nValue; return S_OK; } STDMETHODIMP_(WCHAR*) CMpegSplitterFilter::GetSubtitlesLanguageOrder() { CAutoLock cAutoLock(&m_csProps); return m_csSubtitlesLanguageOrder.GetBuffer(); } STDMETHODIMP CMpegSplitterFilter::SetVC1_GuidFlag(int nValue) { CAutoLock cAutoLock(&m_csProps); m_nVC1_GuidFlag = nValue; return S_OK; } STDMETHODIMP_(int) CMpegSplitterFilter::GetVC1_GuidFlag() { CAutoLock cAutoLock(&m_csProps); return m_nVC1_GuidFlag; } STDMETHODIMP CMpegSplitterFilter::SetTrueHD(int nValue) { CAutoLock cAutoLock(&m_csProps); m_AC3CoreOnly = nValue; return S_OK; } STDMETHODIMP_(int) CMpegSplitterFilter::GetTrueHD() { CAutoLock cAutoLock(&m_csProps); return m_AC3CoreOnly; } STDMETHODIMP CMpegSplitterFilter::SetAlternativeDuration(BOOL nValue) { CAutoLock cAutoLock(&m_csProps); m_AlternativeDuration = !!nValue; return S_OK; } STDMETHODIMP_(BOOL) CMpegSplitterFilter::GetAlternativeDuration() { CAutoLock cAutoLock(&m_csProps); return m_AlternativeDuration; } STDMETHODIMP_(int) CMpegSplitterFilter::GetMPEGType() { CAutoLock cAutoLock(&m_csProps); return m_pFile->m_type; } // // CMpegSourceFilter // CMpegSourceFilter::CMpegSourceFilter(LPUNKNOWN pUnk, HRESULT* phr, const CLSID& clsid) : CMpegSplitterFilter(pUnk, phr, clsid) { m_pInput.Free(); } // // CMpegSplitterOutputPin // CMpegSplitterOutputPin::CMpegSplitterOutputPin(CAtlArray& mts, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr, int type) : CBaseSplitterOutputPin(mts, pName, pFilter, pLock, phr) , m_fHasAccessUnitDelimiters(false) , m_rtMaxShift(50000000) , m_bFilterDTSMA(false) , m_type(type) , DD_reset(false) , m_bFlushed(false) { } CMpegSplitterOutputPin::~CMpegSplitterOutputPin() { } HRESULT CMpegSplitterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) { { CAutoLock cAutoLock(this); m_rtPrev = Packet::INVALID_TIME; m_rtOffset = 0; } return __super::DeliverNewSegment(tStart, tStop, dRate); } HRESULT CMpegSplitterOutputPin::DeliverEndFlush() { { CAutoLock cAutoLock(this); m_p.Free(); m_pl.RemoveAll(); DD_reset = true; m_bFlushed = true; } return __super::DeliverEndFlush(); } #define MOVE_TO_H264_START_CODE(b, e) \ while (b <= e-4 && !((*(DWORD *)b == 0x01000000) || ((*(DWORD *)b & 0x00FFFFFF) == 0x00010000))) \ { \ b++; \ } \ if ((b <= e-4) && *(DWORD *)b == 0x01000000) \ b++; HRESULT CMpegSplitterOutputPin::DeliverPacket(CAutoPtr p) { CAutoLock cAutoLock(this); if (p->rtStart != Packet::INVALID_TIME) { REFERENCE_TIME rt = p->rtStart + m_rtOffset; // Filter invalid PTS (if too different from previous packet) if (m_rtPrev != Packet::INVALID_TIME) if (_abs64(rt - m_rtPrev) > m_rtMaxShift) { m_rtOffset += m_rtPrev - rt; } p->rtStart += m_rtOffset; p->rtStop += m_rtOffset; m_rtPrev = p->rtStart; } if (p->pmt) { if (*((CMediaType*)p->pmt) != m_mt) { SetMediaType((CMediaType*)p->pmt); } } if (m_mt.subtype == MEDIASUBTYPE_AAC) { // special code for aac, the currently available decoders only like whole frame samples if (m_p && m_p->GetCount() == 1 && m_p->GetAt(0) == 0xff && !(!p->IsEmpty() && (p->GetAt(0) & 0xf6) == 0xf0)) { m_p.Free(); } if (!m_p) { BYTE* base = p->GetData(); BYTE* s = base; BYTE* e = s + p->GetCount(); for (; s < e; s++) { if (*s != 0xff) { continue; } if (s == e - 1 || (s[1] & 0xf6) == 0xf0) { memmove(base, s, e - s); p->SetCount(e - s); m_p = p; break; } } } else { m_p->Append(*p); } while (m_p && m_p->GetCount() > 9) { BYTE* base = m_p->GetData(); BYTE* s = base; BYTE* e = s + m_p->GetCount(); int len = ((s[3] & 3) << 11) | (s[4] << 3) | (s[5] >> 5); bool crc = !(s[1] & 1); s += 7; len -= 7; if (crc) { s += 2, len -= 2; } if (e - s < len) { break; } if (len <= 0 || e - s >= len + 2 && (s[len] != 0xff || (s[len + 1] & 0xf6) != 0xf0)) { m_p.Free(); break; } CAutoPtr p2(DEBUG_NEW Packet()); p2->TrackNumber = m_p->TrackNumber; p2->bDiscontinuity |= m_p->bDiscontinuity; m_p->bDiscontinuity = false; p2->bSyncPoint = m_p->rtStart != Packet::INVALID_TIME; p2->rtStart = m_p->rtStart; m_p->rtStart = Packet::INVALID_TIME; p2->rtStop = m_p->rtStop; m_p->rtStop = Packet::INVALID_TIME; p2->pmt = m_p->pmt; m_p->pmt = nullptr; p2->SetData(s, len); s += len; memmove(base, s, e - s); m_p->SetCount(e - s); HRESULT hr = __super::DeliverPacket(p2); if (hr != S_OK) { return hr; } } if (m_p && p) { if (!m_p->bDiscontinuity) { m_p->bDiscontinuity = p->bDiscontinuity; } if (!m_p->bSyncPoint) { m_p->bSyncPoint = p->bSyncPoint; } if (m_p->rtStart == Packet::INVALID_TIME) { m_p->rtStart = p->rtStart, m_p->rtStop = p->rtStop; } if (m_p->pmt) { DeleteMediaType(m_p->pmt); } m_p->pmt = p->pmt; p->pmt = nullptr; } return S_OK; } else if (m_mt.subtype == FOURCCMap('1CVA') || m_mt.subtype == FOURCCMap('1cva') || m_mt.subtype == FOURCCMap('CVMA') || m_mt.subtype == FOURCCMap('CVME')) { if (!m_p) { m_p.Attach(DEBUG_NEW Packet()); m_p->TrackNumber = p->TrackNumber; m_p->bDiscontinuity = p->bDiscontinuity; p->bDiscontinuity = FALSE; m_p->bSyncPoint = p->bSyncPoint; p->bSyncPoint = FALSE; m_p->rtStart = p->rtStart; p->rtStart = Packet::INVALID_TIME; m_p->rtStop = p->rtStop; p->rtStop = Packet::INVALID_TIME; } m_p->Append(*p); BYTE* start = m_p->GetData(); BYTE* end = start + m_p->GetCount(); MOVE_TO_H264_START_CODE(start, end); while (start <= end - 4) { BYTE* next = start + 1; MOVE_TO_H264_START_CODE(next, end); if (next >= end - 4) { break; } int size = next - start; CH264Nalu Nalu; Nalu.SetBuffer(start, size, 0); CAutoPtr p2; while (Nalu.ReadNext()) { DWORD dwNalLength = ((Nalu.GetDataLength() >> 24) & 0x000000ff) | ((Nalu.GetDataLength() >> 8) & 0x0000ff00) | ((Nalu.GetDataLength() << 8) & 0x00ff0000) | ((Nalu.GetDataLength() << 24) & 0xff000000); CAutoPtr p3(DEBUG_NEW Packet()); p3->SetCount(Nalu.GetDataLength() + sizeof(dwNalLength)); memcpy(p3->GetData(), &dwNalLength, sizeof(dwNalLength)); memcpy(p3->GetData() + sizeof(dwNalLength), Nalu.GetDataBuffer(), Nalu.GetDataLength()); if (p2 == nullptr) { p2 = p3; } else { p2->Append(*p3); } } start = next; if (!p2) { continue; } p2->TrackNumber = m_p->TrackNumber; p2->bDiscontinuity = m_p->bDiscontinuity; m_p->bDiscontinuity = FALSE; p2->bSyncPoint = m_p->bSyncPoint; m_p->bSyncPoint = FALSE; p2->rtStart = m_p->rtStart; m_p->rtStart = Packet::INVALID_TIME; p2->rtStop = m_p->rtStop; m_p->rtStop = Packet::INVALID_TIME; p2->pmt = m_p->pmt; m_p->pmt = nullptr; m_pl.AddTail(p2); if (p->rtStart != Packet::INVALID_TIME) { m_p->rtStart = p->rtStart; m_p->rtStop = p->rtStop; p->rtStart = Packet::INVALID_TIME; } if (p->bDiscontinuity) { m_p->bDiscontinuity = p->bDiscontinuity; p->bDiscontinuity = FALSE; } if (p->bSyncPoint) { m_p->bSyncPoint = p->bSyncPoint; p->bSyncPoint = FALSE; } if (m_p->pmt) { DeleteMediaType(m_p->pmt); } m_p->pmt = p->pmt; p->pmt = nullptr; } if (start > m_p->GetData()) { m_p->RemoveAt(0, start - m_p->GetData()); } REFERENCE_TIME rtStart = Packet::INVALID_TIME, rtStop = Packet::INVALID_TIME; for (POSITION pos = m_pl.GetHeadPosition(); pos; m_pl.GetNext(pos)) { if (pos == m_pl.GetHeadPosition()) { continue; } Packet* pPacket = m_pl.GetAt(pos); BYTE* pData = pPacket->GetData(); if ((pData[4] & 0x1f) == 0x09) { m_fHasAccessUnitDelimiters = true; } if ((pData[4] & 0x1f) == 0x09 || (!m_fHasAccessUnitDelimiters && pPacket->rtStart != Packet::INVALID_TIME)) { if (pPacket->rtStart == Packet::INVALID_TIME && rtStart != Packet::INVALID_TIME) { pPacket->rtStart = rtStart; pPacket->rtStop = rtStop; } p = m_pl.RemoveHead(); while (pos != m_pl.GetHeadPosition()) { CAutoPtr p2 = m_pl.RemoveHead(); p->Append(*p2); } HRESULT hr = __super::DeliverPacket(p); if (hr != S_OK) { return hr; } } else if (rtStart == Packet::INVALID_TIME) { rtStart = pPacket->rtStart; rtStop = pPacket->rtStop; } } return S_OK; } else if (m_mt.subtype == FOURCCMap('1CVW') || m_mt.subtype == FOURCCMap('1cvw') || m_mt.subtype == MEDIASUBTYPE_WVC1_CYBERLINK || m_mt.subtype == MEDIASUBTYPE_WVC1_ARCSOFT) { // just like aac, this has to be starting nalus, more can be packed together if (!m_p) { m_p.Attach(DEBUG_NEW Packet()); m_p->TrackNumber = p->TrackNumber; m_p->bDiscontinuity = p->bDiscontinuity; p->bDiscontinuity = FALSE; m_p->bSyncPoint = p->bSyncPoint; p->bSyncPoint = FALSE; m_p->rtStart = p->rtStart; p->rtStart = Packet::INVALID_TIME; m_p->rtStop = p->rtStop; p->rtStop = Packet::INVALID_TIME; } m_p->Append(*p); BYTE* start = m_p->GetData(); BYTE* end = start + m_p->GetCount(); bool bSeqFound = false; while (start <= end - 4) { if (*(DWORD*)start == 0x0D010000) { bSeqFound = true; break; } else if (*(DWORD*)start == 0x0F010000) { break; } start++; } while (start <= end - 4) { BYTE* next = start + 1; while (next <= end - 4) { if (*(DWORD*)next == 0x0D010000) { if (bSeqFound) { break; } bSeqFound = true; } else if (*(DWORD*)next == 0x0F010000) { break; } next++; } if (next >= end - 4) { break; } int size = next - start - 4; UNREFERENCED_PARAMETER(size); CAutoPtr p2(DEBUG_NEW Packet()); p2->TrackNumber = m_p->TrackNumber; p2->bDiscontinuity = m_p->bDiscontinuity; m_p->bDiscontinuity = FALSE; p2->bSyncPoint = m_p->bSyncPoint; m_p->bSyncPoint = FALSE; p2->rtStart = m_p->rtStart; m_p->rtStart = Packet::INVALID_TIME; p2->rtStop = m_p->rtStop; m_p->rtStop = Packet::INVALID_TIME; p2->pmt = m_p->pmt; m_p->pmt = nullptr; p2->SetData(start, next - start); HRESULT hr = __super::DeliverPacket(p2); if (hr != S_OK) { return hr; } if (p->rtStart != Packet::INVALID_TIME) { m_p->rtStart = p->rtStop; //p->rtStart; //Sebastiii for enable VC1 decoding in FFDshow (no more shutter) m_p->rtStop = p->rtStop; p->rtStart = Packet::INVALID_TIME; } if (p->bDiscontinuity) { m_p->bDiscontinuity = p->bDiscontinuity; p->bDiscontinuity = FALSE; } if (p->bSyncPoint) { m_p->bSyncPoint = p->bSyncPoint; p->bSyncPoint = FALSE; } if (m_p->pmt) { DeleteMediaType(m_p->pmt); } m_p->pmt = p->pmt; p->pmt = nullptr; start = next; bSeqFound = (*(DWORD*)start == 0x0D010000); } if (start > m_p->GetData()) { m_p->RemoveAt(0, start - m_p->GetData()); } return S_OK; } // DTS HD MA data is causing trouble with some filters, lets just remove it else if (m_bFilterDTSMA && ((m_mt.subtype == MEDIASUBTYPE_DTS || m_mt.subtype == MEDIASUBTYPE_WAVE_DTS))) { if (p->GetCount() < 4 && !p->pmt) { return S_OK; // Should be invalid packet } BYTE* hdr = p->GetData(); int Type; // 16 bits big endian bitstream if (hdr[0] == 0x7f && hdr[1] == 0xfe && hdr[2] == 0x80 && hdr[3] == 0x01) { Type = 16 + 32; } // 16 bits low endian bitstream else if (hdr[0] == 0xfe && hdr[1] == 0x7f && hdr[2] == 0x01 && hdr[3] == 0x80) { Type = 16; } // 14 bits big endian bitstream else if (hdr[0] == 0x1f && hdr[1] == 0xff && hdr[2] == 0xe8 && hdr[3] == 0x00 && hdr[4] == 0x07 && (hdr[5] & 0xf0) == 0xf0) { Type = 14 + 32; } // 14 bits low endian bitstream else if (hdr[0] == 0xff && hdr[1] == 0x1f && hdr[2] == 0x00 && hdr[3] == 0xe8 && (hdr[4] & 0xf0) == 0xf0 && hdr[5] == 0x07) { Type = 14; } // no sync else if (!p->pmt) { return S_OK; } // HDMV LPCM } else if (m_mt.subtype == MEDIASUBTYPE_HDMV_LPCM_AUDIO) { if (!m_p) { m_p.Attach(DEBUG_NEW Packet()); } m_p->Append(*p); if (m_p->GetCount() < 4) { m_p.Free(); return S_OK; // Should be invalid packet } BYTE* start = m_p->GetData(); int samplerate, channels; size_t header_size = ParseHdmvLPCMHeader(start, &samplerate, &channels); if (!header_size || header_size > m_p->GetCount()) { if (!header_size) { m_p.Free(); } return S_OK; } if (!p->pmt && m_bFlushed) { p->pmt = CreateMediaType(&m_mt); m_bFlushed = false; } p->SetData(start + 4, m_p->GetCount() - 4); m_p.Free(); // Dolby_AC3 } else if ((m_type == mpeg_ts) && (m_mt.subtype == MEDIASUBTYPE_DOLBY_AC3) && (static_cast(m_pFilter))->StreamIsTrueHD(p->TrackNumber) && (static_cast(m_pFilter))->GetTrueHD() != 2) { if (p->GetCount() < 8) { return S_OK; // Should be invalid packet } BYTE* start = p->GetData(); if (*(WORD*)start != 0x770b) { // skip none AC3 return S_OK; } // TrueHD } else if (m_mt.subtype == MEDIASUBTYPE_DOLBY_TRUEHD && (static_cast(m_pFilter))->GetTrueHD() != 2) { if (p->GetCount() < 8) { return S_OK; // Should be invalid packet } BYTE* start = p->GetData(); if (*(WORD*)start == 0x770b) { // skip AC3 return S_OK; } if (DD_reset || p->rtStart == 0) { p->bDiscontinuity = true; DD_reset = false; } } else { m_p.Free(); m_pl.RemoveAll(); } return __super::DeliverPacket(p); } STDMETHODIMP CMpegSplitterOutputPin::Connect(IPin* pReceivePin, const AM_MEDIA_TYPE* pmt) { HRESULT hr; PIN_INFO PinInfo; GUID FilterClsid; if (SUCCEEDED(pReceivePin->QueryPinInfo(&PinInfo))) { if (SUCCEEDED(PinInfo.pFilter->GetClassID(&FilterClsid))) { if (FilterClsid == CLSID_DMOWrapperFilter) { (static_cast(m_pFilter))->SetPipo(true); } // AC3 Filter did not support DTS-MA else if (FilterClsid == CLSID_AC3Filter) { m_bFilterDTSMA = true; } } PinInfo.pFilter->Release(); } hr = __super::Connect(pReceivePin, pmt); (static_cast(m_pFilter))->SetPipo(false); return hr; }