/* * $Id$ * * (C) 2003-2006 Gabest * (C) 2006-2012 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 "SubtitleSource.h" #include "../../../DSUtil/DSUtil.h" #include #include static int _WIDTH = 640; static int _HEIGHT = 480; static int _ATPF = 400000; #ifdef REGISTER_FILTER const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] = { {&MEDIATYPE_Subtitle, &MEDIASUBTYPE_NULL}, {&MEDIATYPE_Text, &MEDIASUBTYPE_NULL}, {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB32}, }; const AMOVIESETUP_PIN sudOpPin[] = { {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut), sudPinTypesOut}, }; const AMOVIESETUP_FILTER sudFilter[] = { {&__uuidof(CSubtitleSourceASCII), L"MPC SubtitleSource (S_TEXT/ASCII)", MERIT_NORMAL, countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, {&__uuidof(CSubtitleSourceUTF8), L"MPC SubtitleSource (S_TEXT/UTF8)", MERIT_NORMAL, countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, {&__uuidof(CSubtitleSourceSSA), L"MPC SubtitleSource (S_TEXT/SSA)", MERIT_NORMAL, countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, {&__uuidof(CSubtitleSourceASS), L"MPC SubtitleSource (S_TEXT/ASS)", MERIT_NORMAL, countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, {&__uuidof(CSubtitleSourceUSF), L"MPC SubtitleSource (S_TEXT/USF)", MERIT_NORMAL, countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, {&__uuidof(CSubtitleSourcePreview), L"MPC SubtitleSource (Preview)", MERIT_NORMAL, countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, {&__uuidof(CSubtitleSourceARGB), L"MPC SubtitleSource (ARGB)", MERIT_NORMAL, countof(sudOpPin), sudOpPin, CLSID_LegacyAmFilterCategory}, }; CFactoryTemplate g_Templates[] = { {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance, NULL, &sudFilter[0]}, {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance, NULL, &sudFilter[1]}, {sudFilter[2].strName, sudFilter[2].clsID, CreateInstance, NULL, &sudFilter[2]}, {sudFilter[3].strName, sudFilter[3].clsID, CreateInstance, NULL, &sudFilter[3]}, // {sudFilter[4].strName, sudFilter[4].clsID, CreateInstance, NULL, &sudFilter[4]}, {sudFilter[5].strName, sudFilter[5].clsID, CreateInstance, NULL, &sudFilter[5]}, {sudFilter[6].strName, sudFilter[6].clsID, CreateInstance, NULL, &sudFilter[6]}, }; int g_cTemplates = countof(g_Templates); STDAPI DllRegisterServer() { /* CString clsid = CStringFromGUID(__uuidof(CSubtitleSourcePreview)); SetRegKeyValue( _T("Media Type\\Extensions"), _T(".sub"), _T("Source Filter"), clsid); SetRegKeyValue( _T("Media Type\\Extensions"), _T(".srt"), _T("Source Filter"), clsid); SetRegKeyValue( _T("Media Type\\Extensions"), _T(".smi"), _T("Source Filter"), clsid); SetRegKeyValue( _T("Media Type\\Extensions"), _T(".ssa"), _T("Source Filter"), clsid); SetRegKeyValue( _T("Media Type\\Extensions"), _T(".ass"), _T("Source Filter"), clsid); SetRegKeyValue( _T("Media Type\\Extensions"), _T(".xss"), _T("Source Filter"), clsid); SetRegKeyValue( _T("Media Type\\Extensions"), _T(".usf"), _T("Source Filter"), clsid); */ return AMovieDllRegisterServer2(TRUE); } STDAPI DllUnregisterServer() { DeleteRegKey(_T("Media Type\\Extensions"), _T(".sub")); DeleteRegKey(_T("Media Type\\Extensions"), _T(".srt")); DeleteRegKey(_T("Media Type\\Extensions"), _T(".smi")); DeleteRegKey(_T("Media Type\\Extensions"), _T(".ssa")); DeleteRegKey(_T("Media Type\\Extensions"), _T(".ass")); DeleteRegKey(_T("Media Type\\Extensions"), _T(".xss")); DeleteRegKey(_T("Media Type\\Extensions"), _T(".usf")); /**/ return AMovieDllRegisterServer2(FALSE); } #include "../../FilterApp.h" class CSubtitleSourceApp : public CFilterApp { public: BOOL InitInstance() { if (!__super::InitInstance()) { return FALSE; } _WIDTH = GetProfileInt(_T("SubtitleSource"), _T("w"), 640); _HEIGHT = GetProfileInt(_T("SubtitleSource"), _T("h"), 480); _ATPF = GetProfileInt(_T("SubtitleSource"), _T("atpf"), 400000); if (_ATPF <= 0) { _ATPF = 400000; } WriteProfileInt(_T("SubtitleSource"), _T("w"), _WIDTH); WriteProfileInt(_T("SubtitleSource"), _T("h"), _HEIGHT); WriteProfileInt(_T("SubtitleSource"), _T("atpf"), _ATPF); return TRUE; } }; CSubtitleSourceApp theApp; #endif // // CSubtitleSource // CSubtitleSource::CSubtitleSource(LPUNKNOWN lpunk, HRESULT* phr, const CLSID& clsid) : CSource(NAME("CSubtitleSource"), lpunk, clsid) { } CSubtitleSource::~CSubtitleSource() { } STDMETHODIMP CSubtitleSource::NonDelegatingQueryInterface(REFIID riid, void** ppv) { CheckPointer(ppv, E_POINTER); return QI(IFileSourceFilter) QI(IAMFilterMiscFlags) __super::NonDelegatingQueryInterface(riid, ppv); } // IFileSourceFilter STDMETHODIMP CSubtitleSource::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt) { if (GetPinCount() > 0) { return VFW_E_ALREADY_CONNECTED; } HRESULT hr = S_OK; if (!(DNew CSubtitleStream(pszFileName, this, &hr))) { return E_OUTOFMEMORY; } if (FAILED(hr)) { return hr; } m_fn = pszFileName; return S_OK; } STDMETHODIMP CSubtitleSource::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt) { if (!ppszFileName) { return E_POINTER; } *ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength() + 1) * sizeof(WCHAR)); if (!*ppszFileName) { return E_OUTOFMEMORY; } wcscpy(*ppszFileName, m_fn); return S_OK; } // IAMFilterMiscFlags ULONG CSubtitleSource::GetMiscFlags() { return AM_FILTER_MISC_FLAGS_IS_SOURCE; } STDMETHODIMP CSubtitleSource::QueryFilterInfo(FILTER_INFO* pInfo) { CheckPointer(pInfo, E_POINTER); ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO)); wcscpy(pInfo->achName, SubtitleSourceName); pInfo->pGraph = m_pGraph; if (m_pGraph) { m_pGraph->AddRef(); } return S_OK; } // // CSubtitleStream // CSubtitleStream::CSubtitleStream(const WCHAR* wfn, CSubtitleSource* pParent, HRESULT* phr) : CSourceStream(NAME("SubtitleStream"), phr, pParent, L"Output") , CSourceSeeking(NAME("SubtitleStream"), (IPin*)this, phr, &m_cSharedState) , m_bDiscontinuity(FALSE), m_bFlushing(FALSE) , m_nPosition(0) , m_rts(NULL) { CAutoLock cAutoLock(&m_cSharedState); CString fn(wfn); if (!m_rts.Open(fn, DEFAULT_CHARSET)) { if (phr) { *phr = E_FAIL; } return; } m_rts.CreateDefaultStyle(DEFAULT_CHARSET); m_rts.ConvertToTimeBased(25); m_rts.Sort(); m_rtDuration = 0; for (int i = 0, cnt = m_rts.GetCount(); i < cnt; i++) { m_rtDuration = max(m_rtDuration, 10000i64*m_rts[i].end); } m_rtStop = m_rtDuration; if (phr) { *phr = m_rtDuration > 0 ? S_OK : E_FAIL; } } CSubtitleStream::~CSubtitleStream() { CAutoLock cAutoLock(&m_cSharedState); } STDMETHODIMP CSubtitleStream::NonDelegatingQueryInterface(REFIID riid, void** ppv) { CheckPointer(ppv, E_POINTER); return (riid == IID_IMediaSeeking) ? CSourceSeeking::NonDelegatingQueryInterface(riid, ppv) //GetInterface((IMediaSeeking*)this, ppv) : CSourceStream::NonDelegatingQueryInterface(riid, ppv); } void CSubtitleStream::UpdateFromSeek() { if (ThreadExists()) { // next time around the loop, the worker thread will // pick up the position change. // We need to flush all the existing data - we must do that here // as our thread will probably be blocked in GetBuffer otherwise m_bFlushing = TRUE; DeliverBeginFlush(); // make sure we have stopped pushing Stop(); // complete the flush DeliverEndFlush(); m_bFlushing = FALSE; // restart Run(); } } HRESULT CSubtitleStream::SetRate(double dRate) { if (dRate <= 0) { return E_INVALIDARG; } { CAutoLock lock(CSourceSeeking::m_pLock); m_dRateSeeking = dRate; } UpdateFromSeek(); return S_OK; } HRESULT CSubtitleStream::OnThreadStartPlay() { m_bDiscontinuity = TRUE; return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); } HRESULT CSubtitleStream::ChangeStart() { { CAutoLock lock(CSourceSeeking::m_pLock); OnThreadCreate(); /* if(m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) { m_nPosition = (int)(m_rtStart/10000)*1/1000; } else if(m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) { int m_nSegments = 0; if(!m_rts.SearchSubs((int)(m_rtStart/10000), 25, &m_nPosition, &m_nSegments)) m_nPosition = m_nSegments; } else { m_nPosition = m_rts.SearchSub((int)(m_rtStart/10000), 25); if(m_nPosition < 0) m_nPosition = 0; else if(m_rts[m_nPosition].end <= (int)(m_rtStart/10000)) m_nPosition++; } */ } UpdateFromSeek(); return S_OK; } HRESULT CSubtitleStream::ChangeStop() { /* { CAutoLock lock(CSourceSeeking::m_pLock); if(m_rtPosition < m_rtStop) return S_OK; } */ // We're already past the new stop time -- better flush the graph. UpdateFromSeek(); return S_OK; } HRESULT CSubtitleStream::OnThreadCreate() { CAutoLock cAutoLockShared(&m_cSharedState); if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) { m_nPosition = m_rtStart/_ATPF; } else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) { int m_nSegments = 0; if (!m_rts.SearchSubs((int)(m_rtStart/10000), 10000000/_ATPF, &m_nPosition, &m_nSegments)) { m_nPosition = m_nSegments; } } else { m_nPosition = m_rts.SearchSub((int)(m_rtStart/10000), 25); if (m_nPosition < 0) { m_nPosition = 0; } else if (m_rts[m_nPosition].end <= (int)(m_rtStart/10000)) { m_nPosition++; } } return CSourceStream::OnThreadCreate(); } HRESULT CSubtitleStream::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties) { // CAutoLock cAutoLock(m_pFilter->pStateLock()); ASSERT(pAlloc); ASSERT(pProperties); HRESULT hr = NOERROR; if (m_mt.majortype == MEDIATYPE_Video) { pProperties->cBuffers = 2; pProperties->cbBuffer = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader.biSizeImage; } else { pProperties->cBuffers = 1; pProperties->cbBuffer = 0x10000; } ALLOCATOR_PROPERTIES Actual; if (FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) { return hr; } if (Actual.cbBuffer < pProperties->cbBuffer) { return E_FAIL; } ASSERT(Actual.cBuffers == pProperties->cBuffers); return NOERROR; } HRESULT CSubtitleStream::FillBuffer(IMediaSample* pSample) { HRESULT hr; { CAutoLock cAutoLockShared(&m_cSharedState); BYTE* pData = NULL; if (FAILED(hr = pSample->GetPointer(&pData)) || !pData) { return S_FALSE; } AM_MEDIA_TYPE* pmt; if (SUCCEEDED(pSample->GetMediaType(&pmt)) && pmt) { CMediaType mt(*pmt); SetMediaType(&mt); DeleteMediaType(pmt); } int len = 0; REFERENCE_TIME rtStart, rtStop; if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_ARGB32) { rtStart = (REFERENCE_TIME)((m_nPosition*_ATPF - m_rtStart) / m_dRateSeeking); rtStop = (REFERENCE_TIME)(((m_nPosition+1)*_ATPF - m_rtStart) / m_dRateSeeking); if (m_rtStart+rtStart >= m_rtDuration) { return S_FALSE; } BITMAPINFOHEADER& bmi = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader; SubPicDesc spd; spd.w = _WIDTH; spd.h = _HEIGHT; spd.bpp = 32; spd.pitch = bmi.biWidth*4; spd.bits = pData; len = spd.h*spd.pitch; for (int y = 0; y < spd.h; y++) { memsetd((DWORD*)(pData + spd.pitch*y), 0xff000000, spd.w*4); } RECT bbox; m_rts.Render(spd, m_nPosition*_ATPF, 10000000.0/_ATPF, bbox); for (int y = 0; y < spd.h; y++) { DWORD* p = (DWORD*)(pData + spd.pitch*y); for (int x = 0; x < spd.w; x++, p++) { *p = (0xff000000-(*p&0xff000000))|(*p&0xffffff); } } } else if (m_mt.majortype == MEDIATYPE_Video && m_mt.subtype == MEDIASUBTYPE_RGB32) { const STSSegment* stss = m_rts.GetSegment(m_nPosition); if (!stss) { return S_FALSE; } BITMAPINFOHEADER& bmi = ((VIDEOINFOHEADER*)m_mt.pbFormat)->bmiHeader; SubPicDesc spd; spd.w = _WIDTH; spd.h = _HEIGHT; spd.bpp = 32; spd.pitch = bmi.biWidth*4; spd.bits = pData; len = spd.h*spd.pitch; for (int y = 0; y < spd.h; y++) { DWORD c1 = 0xff606060, c2 = 0xffa0a0a0; if (y&32) { c1 ^= c2, c2 ^= c1, c1 ^= c2; } DWORD* p = (DWORD*)(pData + spd.pitch*y); for (int x = 0; x < spd.w; x+=32, p+=32) { memsetd(p, (x&32) ? c1 : c2, min(spd.w-x,32)*4); } } RECT bbox; m_rts.Render(spd, 10000i64*(stss->start+stss->end)/2, 10000000.0/_ATPF, bbox); rtStart = (REFERENCE_TIME)((10000i64*stss->start - m_rtStart) / m_dRateSeeking); rtStop = (REFERENCE_TIME)((10000i64*stss->end - m_rtStart) / m_dRateSeeking); } else { if ((size_t)m_nPosition >= m_rts.GetCount()) { return S_FALSE; } STSEntry& stse = m_rts[m_nPosition]; if (stse.start >= m_rtStop/10000) { return S_FALSE; } if (m_mt.majortype == MEDIATYPE_Subtitle && m_mt.subtype == MEDIASUBTYPE_UTF8) { CStringA str = UTF16To8(m_rts.GetStrW(m_nPosition, false)); memcpy((char*)pData, str, len = str.GetLength()); } else if (m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS)) { CStringW line; line.Format(L"%d,%d,%s,%s,%d,%d,%d,%s,%s", stse.readorder, stse.layer, CStringW(stse.style), CStringW(stse.actor), stse.marginRect.left, stse.marginRect.right, (stse.marginRect.top+stse.marginRect.bottom)/2, CStringW(stse.effect), m_rts.GetStrW(m_nPosition, true)); CStringA str = UTF16To8(line); memcpy((char*)pData, str, len = str.GetLength()); } else if (m_mt.majortype == MEDIATYPE_Text && m_mt.subtype == MEDIASUBTYPE_NULL) { CStringA str = m_rts.GetStrA(m_nPosition, false); memcpy((char*)pData, str, len = str.GetLength()); } else { return S_FALSE; } rtStart = (REFERENCE_TIME)((10000i64*stse.start - m_rtStart) / m_dRateSeeking); rtStop = (REFERENCE_TIME)((10000i64*stse.end - m_rtStart) / m_dRateSeeking); } pSample->SetTime(&rtStart, &rtStop); pSample->SetActualDataLength(len); m_nPosition++; } pSample->SetSyncPoint(TRUE); if (m_bDiscontinuity) { pSample->SetDiscontinuity(TRUE); m_bDiscontinuity = FALSE; } return S_OK; } HRESULT CSubtitleStream::GetMediaType(CMediaType* pmt) { return (static_cast(m_pFilter))->GetMediaType(pmt); } HRESULT CSubtitleStream::CheckMediaType(const CMediaType* pmt) { CAutoLock lock(m_pFilter->pStateLock()); CMediaType mt; GetMediaType(&mt); if (mt.majortype == pmt->majortype && mt.subtype == pmt->subtype) { return NOERROR; } return E_FAIL; } STDMETHODIMP CSubtitleStream::Notify(IBaseFilter* pSender, Quality q) { return E_NOTIMPL; } // // CSubtitleSourceASCII // CSubtitleSourceASCII::CSubtitleSourceASCII(LPUNKNOWN lpunk, HRESULT* phr) : CSubtitleSource(lpunk, phr, __uuidof(this)) { } HRESULT CSubtitleSourceASCII::GetMediaType(CMediaType* pmt) { CAutoLock cAutoLock(pStateLock()); pmt->InitMediaType(); pmt->SetType(&MEDIATYPE_Text); pmt->SetSubtype(&MEDIASUBTYPE_NULL); pmt->SetFormatType(&FORMAT_None); pmt->ResetFormatBuffer(); return NOERROR; } // // CSubtitleSourceUTF8 // CSubtitleSourceUTF8::CSubtitleSourceUTF8(LPUNKNOWN lpunk, HRESULT* phr) : CSubtitleSource(lpunk, phr, __uuidof(this)) { } HRESULT CSubtitleSourceUTF8::GetMediaType(CMediaType* pmt) { CAutoLock cAutoLock(pStateLock()); pmt->InitMediaType(); pmt->SetType(&MEDIATYPE_Subtitle); pmt->SetSubtype(&MEDIASUBTYPE_UTF8); pmt->SetFormatType(&FORMAT_SubtitleInfo); SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO)); memset(psi, 0, pmt->FormatLength()); strcpy(psi->IsoLang, "eng"); return NOERROR; } // // CSubtitleSourceSSA // CSubtitleSourceSSA::CSubtitleSourceSSA(LPUNKNOWN lpunk, HRESULT* phr) : CSubtitleSource(lpunk, phr, __uuidof(this)) { } HRESULT CSubtitleSourceSSA::GetMediaType(CMediaType* pmt) { CAutoLock cAutoLock(pStateLock()); pmt->InitMediaType(); pmt->SetType(&MEDIATYPE_Subtitle); pmt->SetSubtype(&MEDIASUBTYPE_SSA); pmt->SetFormatType(&FORMAT_SubtitleInfo); CSimpleTextSubtitle sts; sts.Open(CString(m_fn), DEFAULT_CHARSET); sts.RemoveAll(); CFile f; TCHAR path[_MAX_PATH], fn[_MAX_PATH]; if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("mpc_sts"), 0, fn)) { return E_FAIL; } _tremove(fn); _tcscat(fn, _T(".ssa")); if (!sts.SaveAs(fn, EXTSSA, -1, CTextFile::UTF8) || !f.Open(fn, CFile::modeRead)) { return E_FAIL; } int len = (int)f.GetLength()-3; f.Seek(3, CFile::begin); SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO) + len); memset(psi, 0, pmt->FormatLength()); psi->dwOffset = sizeof(SUBTITLEINFO); strcpy(psi->IsoLang, "eng"); f.Read(pmt->pbFormat + psi->dwOffset, len); f.Close(); _tremove(fn); return NOERROR; } // // CSubtitleSourceASS // CSubtitleSourceASS::CSubtitleSourceASS(LPUNKNOWN lpunk, HRESULT* phr) : CSubtitleSource(lpunk, phr, __uuidof(this)) { } HRESULT CSubtitleSourceASS::GetMediaType(CMediaType* pmt) { CAutoLock cAutoLock(pStateLock()); pmt->InitMediaType(); pmt->SetType(&MEDIATYPE_Subtitle); pmt->SetSubtype(&MEDIASUBTYPE_ASS); pmt->SetFormatType(&FORMAT_SubtitleInfo); CSimpleTextSubtitle sts; sts.Open(CString(m_fn), DEFAULT_CHARSET); sts.RemoveAll(); CFile f; TCHAR path[_MAX_PATH], fn[_MAX_PATH]; if (!GetTempPath(MAX_PATH, path) || !GetTempFileName(path, _T("mpc_sts"), 0, fn)) { return E_FAIL; } _tremove(fn); _tcscat(fn, _T(".ass")); if (!sts.SaveAs(fn, EXTASS, -1, CTextFile::UTF8) || !f.Open(fn, CFile::modeRead)) { return E_FAIL; } int len = (int)f.GetLength(); SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO) + len); memset(psi, 0, pmt->FormatLength()); psi->dwOffset = sizeof(SUBTITLEINFO); strcpy(psi->IsoLang, "eng"); f.Read(pmt->pbFormat + psi->dwOffset, len); f.Close(); _tremove(fn); return NOERROR; } // // CSubtitleSourceUSF // CSubtitleSourceUSF::CSubtitleSourceUSF(LPUNKNOWN lpunk, HRESULT* phr) : CSubtitleSource(lpunk, phr, __uuidof(this)) { } HRESULT CSubtitleSourceUSF::GetMediaType(CMediaType* pmt) { CAutoLock cAutoLock(pStateLock()); pmt->InitMediaType(); pmt->SetType(&MEDIATYPE_Subtitle); pmt->SetSubtype(&MEDIASUBTYPE_USF); pmt->SetFormatType(&FORMAT_SubtitleInfo); SUBTITLEINFO* psi = (SUBTITLEINFO*)pmt->AllocFormatBuffer(sizeof(SUBTITLEINFO)); memset(psi, 0, pmt->FormatLength()); strcpy(psi->IsoLang, "eng"); // TODO: ... return NOERROR; } // // CSubtitleSourcePreview // CSubtitleSourcePreview::CSubtitleSourcePreview(LPUNKNOWN lpunk, HRESULT* phr) : CSubtitleSource(lpunk, phr, __uuidof(this)) { } HRESULT CSubtitleSourcePreview::GetMediaType(CMediaType* pmt) { CAutoLock cAutoLock(pStateLock()); pmt->InitMediaType(); pmt->SetType(&MEDIATYPE_Video); pmt->SetSubtype(&MEDIASUBTYPE_RGB32); pmt->SetFormatType(&FORMAT_VideoInfo); VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); memset(pvih, 0, pmt->FormatLength()); pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader); pvih->bmiHeader.biWidth = _WIDTH; pvih->bmiHeader.biHeight = _HEIGHT; pvih->bmiHeader.biBitCount = 32; pvih->bmiHeader.biCompression = BI_RGB; pvih->bmiHeader.biPlanes = 1; pvih->bmiHeader.biSizeImage = pvih->bmiHeader.biWidth*abs(pvih->bmiHeader.biHeight)*pvih->bmiHeader.biBitCount>>3; return NOERROR; } // // CSubtitleSourceARGB // CSubtitleSourceARGB::CSubtitleSourceARGB(LPUNKNOWN lpunk, HRESULT* phr) : CSubtitleSource(lpunk, phr, __uuidof(this)) { } HRESULT CSubtitleSourceARGB::GetMediaType(CMediaType* pmt) { CAutoLock cAutoLock(pStateLock()); pmt->InitMediaType(); pmt->SetType(&MEDIATYPE_Video); pmt->SetSubtype(&MEDIASUBTYPE_ARGB32); pmt->SetFormatType(&FORMAT_VideoInfo); VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)pmt->AllocFormatBuffer(sizeof(VIDEOINFOHEADER)); memset(pvih, 0, pmt->FormatLength()); pvih->bmiHeader.biSize = sizeof(pvih->bmiHeader); // TODO: read w,h,fps from a config file or registry pvih->bmiHeader.biWidth = _WIDTH; pvih->bmiHeader.biHeight = _HEIGHT; pvih->bmiHeader.biBitCount = 32; pvih->bmiHeader.biCompression = BI_RGB; pvih->bmiHeader.biPlanes = 1; pvih->bmiHeader.biSizeImage = pvih->bmiHeader.biWidth*abs(pvih->bmiHeader.biHeight)*pvih->bmiHeader.biBitCount>>3; return NOERROR; }