Bugfix: PGS YVU => YUV
[xy_vsfilter.git] / src / subtitles / SubtitleInputPin.cpp
blob0eab8fe4ae2ab0c80adbde2b43e1a17a0ead0d1e
1 /*
2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "stdafx.h"
23 #include "SubtitleInputPin.h"
24 #include "VobSubFile.h"
25 #include "RTS.h"
26 #include "SSF.h"
27 #include "RenderedHdmvSubtitle.h"
29 #include <initguid.h>
30 #include "..\..\include\moreuuids.h"
32 // our first format id
33 #define __GAB1__ "GAB1"
35 // our tags for __GAB1__ (ushort) + size (ushort)
37 // "lang" + '0'
38 #define __GAB1_LANGUAGE__ 0
39 // (int)start+(int)stop+(char*)line+'0'
40 #define __GAB1_ENTRY__ 1
41 // L"lang" + '0'
42 #define __GAB1_LANGUAGE_UNICODE__ 2
43 // (int)start+(int)stop+(WCHAR*)line+'0'
44 #define __GAB1_ENTRY_UNICODE__ 3
46 // same as __GAB1__, but the size is (uint) and only __GAB1_LANGUAGE_UNICODE__ is valid
47 #define __GAB2__ "GAB2"
49 // (BYTE*)
50 #define __GAB1_RAWTEXTSUBTITLE__ 4
52 CSubtitleInputPin::CSubtitleInputPin(CBaseFilter* pFilter, CCritSec* pLock, CCritSec* pSubLock, HRESULT* phr)
53 : CBaseInputPin(NAME("CSubtitleInputPin"), pFilter, pLock, phr, L"Input")
54 , m_pSubLock(pSubLock)
56 m_bCanReconnectWhenActive = TRUE;
59 HRESULT CSubtitleInputPin::CheckMediaType(const CMediaType* pmt)
61 return pmt->majortype == MEDIATYPE_Text && (pmt->subtype == MEDIASUBTYPE_NULL || pmt->subtype == FOURCCMap((DWORD)0))
62 || pmt->majortype == MEDIATYPE_Subtitle && pmt->subtype == MEDIASUBTYPE_UTF8
63 || pmt->majortype == MEDIATYPE_Subtitle && (pmt->subtype == MEDIASUBTYPE_SSA || pmt->subtype == MEDIASUBTYPE_ASS || pmt->subtype == MEDIASUBTYPE_ASS2)
64 || pmt->majortype == MEDIATYPE_Subtitle && pmt->subtype == MEDIASUBTYPE_SSF
65 || pmt->majortype == MEDIATYPE_Subtitle && (pmt->subtype == MEDIASUBTYPE_VOBSUB)
66 || IsHdmvSub(pmt)
67 ? S_OK
68 : E_FAIL;
71 HRESULT CSubtitleInputPin::CompleteConnect(IPin* pReceivePin)
73 AMTRACE((TEXT(__FUNCTION__),0));
74 if(m_mt.majortype == MEDIATYPE_Text)
76 CRenderedTextSubtitle* pRTS = new CRenderedTextSubtitle(m_pSubLock);
77 if(!(m_pSubStream = pRTS)) return E_FAIL;
78 pRTS->m_name = CString(GetPinName(pReceivePin)) + _T(" (embeded)");
79 pRTS->m_dstScreenSize = CSize(384, 288);
80 pRTS->CreateDefaultStyle(DEFAULT_CHARSET);
82 else if(m_mt.majortype == MEDIATYPE_Subtitle)
84 SUBTITLEINFO* psi = (SUBTITLEINFO*)m_mt.pbFormat;
85 DWORD dwOffset = 0;
86 CString name;
87 LCID lcid = 0;
89 if (psi != NULL) {
90 dwOffset = psi->dwOffset;
92 name = ISO6392ToLanguage(psi->IsoLang);
93 lcid = ISO6392ToLcid(psi->IsoLang);
95 if(wcslen(psi->TrackName) > 0) {
96 name += (!name.IsEmpty() ? _T(", ") : _T("")) + CString(psi->TrackName);
98 if(name.IsEmpty()) {
99 name = _T("Unknown");
103 name.Replace(_T("\x19"), _T(""));//CAUTION: VS may show name.Replace(_T(""),_T("")), however there is a character in the first _T("")
104 name.Replace(_T("\x18"), _T(""));//CAUTION: VS may show name.Replace(_T(""),_T("")), however there is a character in the first _T("")
106 if(m_mt.subtype == MEDIASUBTYPE_UTF8
107 /*|| m_mt.subtype == MEDIASUBTYPE_USF*/
108 || m_mt.subtype == MEDIASUBTYPE_SSA
109 || m_mt.subtype == MEDIASUBTYPE_ASS
110 || m_mt.subtype == MEDIASUBTYPE_ASS2)
112 CRenderedTextSubtitle* pRTS = new CRenderedTextSubtitle(m_pSubLock);
113 if(!(m_pSubStream = pRTS)) return E_FAIL;
114 pRTS->m_name = name;
115 pRTS->m_lcid = lcid;
116 pRTS->m_dstScreenSize = CSize(384, 288);
117 pRTS->CreateDefaultStyle(DEFAULT_CHARSET);
119 if(dwOffset > 0 && m_mt.cbFormat - dwOffset > 0)
121 CMediaType mt = m_mt;
122 if(mt.pbFormat[dwOffset+0] != 0xef
123 && mt.pbFormat[dwOffset+1] != 0xbb
124 && mt.pbFormat[dwOffset+2] != 0xfb)
126 dwOffset -= 3;
127 mt.pbFormat[dwOffset+0] = 0xef;
128 mt.pbFormat[dwOffset+1] = 0xbb;
129 mt.pbFormat[dwOffset+2] = 0xbf;
132 pRTS->Open(mt.pbFormat + dwOffset, mt.cbFormat - dwOffset, DEFAULT_CHARSET, pRTS->m_name);
136 else if(m_mt.subtype == MEDIASUBTYPE_SSF)
138 ssf::CRenderer* pSSF = new ssf::CRenderer(m_pSubLock);
139 if(!(m_pSubStream = pSSF)) return E_FAIL;
141 pSSF->Open(ssf::MemoryInputStream(m_mt.pbFormat + dwOffset, m_mt.cbFormat - dwOffset, false, false), name);
143 else if(m_mt.subtype == MEDIASUBTYPE_VOBSUB)
145 CVobSubStream* pVSS = new CVobSubStream(m_pSubLock);
146 if(!(m_pSubStream = pVSS)) return E_FAIL;
147 pVSS->Open(name, m_mt.pbFormat + dwOffset, m_mt.cbFormat - dwOffset);
149 else if (IsHdmvSub(&m_mt))
151 if(!(m_pSubStream = DNew CRenderedHdmvSubtitle(m_pSubLock, (m_mt.subtype == MEDIASUBTYPE_DVB_SUBTITLES) ? ST_DVB : ST_HDMV, name, lcid))) {
152 return E_FAIL;
157 AddSubStream(m_pSubStream);
159 return __super::CompleteConnect(pReceivePin);
162 HRESULT CSubtitleInputPin::BreakConnect()
164 RemoveSubStream(m_pSubStream);
165 m_pSubStream = NULL;
167 ASSERT(IsStopped());
169 return __super::BreakConnect();
172 STDMETHODIMP CSubtitleInputPin::ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt)
174 if(m_Connected)
176 RemoveSubStream(m_pSubStream);
177 m_pSubStream = NULL;
179 m_Connected->Release();
180 m_Connected = NULL;
183 return __super::ReceiveConnection(pConnector, pmt);
186 STDMETHODIMP CSubtitleInputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
188 DbgLog(( LOG_TRACE, 4, TEXT(__FUNCTION__) ));
189 CAutoLock cAutoLock(&m_csReceive);
191 if(m_mt.majortype == MEDIATYPE_Text
192 || m_mt.majortype == MEDIATYPE_Subtitle
193 && (m_mt.subtype == MEDIASUBTYPE_UTF8
194 /*|| m_mt.subtype == MEDIASUBTYPE_USF*/
195 || m_mt.subtype == MEDIASUBTYPE_SSA
196 || m_mt.subtype == MEDIASUBTYPE_ASS
197 || m_mt.subtype == MEDIASUBTYPE_ASS2))
199 CAutoLock cAutoLock(m_pSubLock);
200 CRenderedTextSubtitle* pRTS = dynamic_cast<CRenderedTextSubtitle*>(static_cast<ISubStream*>(m_pSubStream));
201 pRTS->RemoveAllEntries();
202 pRTS->CreateSegments();
204 else if(m_mt.majortype == MEDIATYPE_Subtitle && m_mt.subtype == MEDIASUBTYPE_SSF)
206 CAutoLock cAutoLock(m_pSubLock);
207 ssf::CRenderer* pSSF = dynamic_cast<ssf::CRenderer*>(static_cast<ISubStream*>(m_pSubStream));
208 // LAME, implement RemoveSubtitles
209 DWORD dwOffset = ((SUBTITLEINFO*)m_mt.pbFormat)->dwOffset;
210 pSSF->Open(ssf::MemoryInputStream(m_mt.pbFormat + dwOffset, m_mt.cbFormat - dwOffset, false, false), _T(""));
211 // pSSF->RemoveSubtitles();
213 else if(m_mt.majortype == MEDIATYPE_Subtitle && (m_mt.subtype == MEDIASUBTYPE_VOBSUB))
215 CAutoLock cAutoLock(m_pSubLock);
216 CVobSubStream* pVSS = dynamic_cast<CVobSubStream*>(static_cast<ISubStream*>(m_pSubStream));
217 pVSS->RemoveAll();
219 else if (IsHdmvSub(&m_mt))
221 CAutoLock cAutoLock(m_pSubLock);
222 CRenderedHdmvSubtitle* pHdmvSubtitle = (CRenderedHdmvSubtitle*)(ISubStream*)m_pSubStream;
223 pHdmvSubtitle->NewSegment (tStart, tStop, dRate);
225 return __super::NewSegment(tStart, tStop, dRate);
228 interface __declspec(uuid("D3D92BC3-713B-451B-9122-320095D51EA5"))
229 IMpeg2DemultiplexerTesting :
230 public IUnknown {
231 STDMETHOD(GetMpeg2StreamType)(ULONG* plType) = NULL;
232 STDMETHOD(toto)() = NULL;
235 STDMETHODIMP CSubtitleInputPin::Receive(IMediaSample* pSample)
237 DbgLog(( LOG_TRACE, 4, TEXT(__FUNCTION__) ));
238 HRESULT hr;
240 hr = __super::Receive(pSample);
241 if(FAILED(hr)) return hr;
243 CAutoLock cAutoLock(&m_csReceive);
245 REFERENCE_TIME tStart, tStop;
246 pSample->GetTime(&tStart, &tStop);
247 tStart += m_tStart;
248 tStop += m_tStart;
250 BYTE* pData = NULL;
251 hr = pSample->GetPointer(&pData);
252 if(FAILED(hr) || pData == NULL) return hr;
254 int len = pSample->GetActualDataLength();
256 bool fInvalidate = false;
258 if(m_mt.majortype == MEDIATYPE_Text)
260 CAutoLock cAutoLock(m_pSubLock);
261 CRenderedTextSubtitle* pRTS = dynamic_cast<CRenderedTextSubtitle*>(static_cast<ISubStream*>(m_pSubStream));
263 if(!strncmp((char*)pData, __GAB1__, strlen(__GAB1__)))
265 char* ptr = (char*)&pData[strlen(__GAB1__)+1];
266 char* end = (char*)&pData[len];
268 while(ptr < end)
270 WORD tag = *((WORD*)(ptr)); ptr += 2;
271 WORD size = *((WORD*)(ptr)); ptr += 2;
273 if(tag == __GAB1_LANGUAGE__)
275 pRTS->m_name = CString(ptr);
277 else if(tag == __GAB1_ENTRY__)
279 pRTS->Add(AToW(&ptr[8]), false, *(int*)ptr, *(int*)(ptr+4));
280 fInvalidate = true;
282 else if(tag == __GAB1_LANGUAGE_UNICODE__)
284 pRTS->m_name = (WCHAR*)ptr;
286 else if(tag == __GAB1_ENTRY_UNICODE__)
288 pRTS->Add((WCHAR*)(ptr+8), true, *(int*)ptr, *(int*)(ptr+4));
289 fInvalidate = true;
292 ptr += size;
295 else if(!strncmp((char*)pData, __GAB2__, strlen(__GAB2__)))
297 char* ptr = (char*)&pData[strlen(__GAB2__)+1];
298 char* end = (char*)&pData[len];
300 while(ptr < end)
302 WORD tag = *((WORD*)(ptr)); ptr += 2;
303 DWORD size = *((DWORD*)(ptr)); ptr += 4;
305 if(tag == __GAB1_LANGUAGE_UNICODE__)
307 pRTS->m_name = (WCHAR*)ptr;
309 else if(tag == __GAB1_RAWTEXTSUBTITLE__)
311 pRTS->Open((BYTE*)ptr, size, DEFAULT_CHARSET, pRTS->m_name);
312 fInvalidate = true;
315 ptr += size;
318 else if(pData != 0 && len > 1 && *pData != 0)
320 CStringA str((char*)pData, len);
322 str.Replace("\r\n", "\n");
323 str.Trim();
325 if(!str.IsEmpty())
327 pRTS->Add(AToW(str), false, (int)(tStart / 10000), (int)(tStop / 10000));
328 fInvalidate = true;
332 else if(m_mt.majortype == MEDIATYPE_Subtitle)
334 CAutoLock cAutoLock(m_pSubLock);
336 if(m_mt.subtype == MEDIASUBTYPE_UTF8)
338 CRenderedTextSubtitle* pRTS = dynamic_cast<CRenderedTextSubtitle*>(static_cast<ISubStream*>(m_pSubStream));
340 CStringW str = UTF8To16(CStringA((LPCSTR)pData, len)).Trim();
341 if(!str.IsEmpty())
343 pRTS->Add(str, true, (int)(tStart / 10000), (int)(tStop / 10000));
344 fInvalidate = true;
347 else if(m_mt.subtype == MEDIASUBTYPE_SSA || m_mt.subtype == MEDIASUBTYPE_ASS || m_mt.subtype == MEDIASUBTYPE_ASS2)
349 CRenderedTextSubtitle* pRTS = dynamic_cast<CRenderedTextSubtitle*>(static_cast<ISubStream*>(m_pSubStream));
351 CStringW str = UTF8To16(CStringA((LPCSTR)pData, len)).Trim();
352 if(!str.IsEmpty())
354 STSEntry stse;
356 int fields = m_mt.subtype == MEDIASUBTYPE_ASS2 ? 10 : 9;
358 CAtlList<CStringW> sl;
359 Explode(str, sl, ',', fields);
360 if(sl.GetCount() == fields)
362 stse.readorder = wcstol(sl.RemoveHead(), NULL, 10);
363 stse.layer = wcstol(sl.RemoveHead(), NULL, 10);
364 stse.style = sl.RemoveHead();
365 stse.actor = sl.RemoveHead();
366 stse.marginRect.left = wcstol(sl.RemoveHead(), NULL, 10);
367 stse.marginRect.right = wcstol(sl.RemoveHead(), NULL, 10);
368 stse.marginRect.top = stse.marginRect.bottom = wcstol(sl.RemoveHead(), NULL, 10);
369 if(fields == 10) stse.marginRect.bottom = wcstol(sl.RemoveHead(), NULL, 10);
370 stse.effect = sl.RemoveHead();
371 stse.str = sl.RemoveHead();
374 if(!stse.str.IsEmpty())
376 pRTS->Add(stse.str, true, (int)(tStart / 10000), (int)(tStop / 10000),
377 stse.style, stse.actor, stse.effect, stse.marginRect, stse.layer, stse.readorder);
378 fInvalidate = true;
382 else if(m_mt.subtype == MEDIASUBTYPE_SSF)
384 ssf::CRenderer* pSSF = dynamic_cast<ssf::CRenderer*>(static_cast<ISubStream*>(m_pSubStream));
386 CStringW str = UTF8To16(CStringA((LPCSTR)pData, len)).Trim();
387 if(!str.IsEmpty())
389 pSSF->Append(tStart, tStop, str);
390 fInvalidate = true;
393 else if(m_mt.subtype == MEDIASUBTYPE_VOBSUB)
395 CVobSubStream* pVSS = dynamic_cast<CVobSubStream*>(static_cast<ISubStream*>(m_pSubStream));
396 pVSS->Add(tStart, tStop, pData, len);
398 else if (IsHdmvSub(&m_mt))
400 CAutoLock cAutoLock(m_pSubLock);
401 CRenderedHdmvSubtitle* pHdmvSubtitle = (CRenderedHdmvSubtitle*)(ISubStream*)m_pSubStream;
402 pHdmvSubtitle->ParseSample (pSample);
406 if(fInvalidate)
408 TRACE(_T("InvalidateSubtitle(%I64d, ..)\n"), tStart);
409 // IMPORTANT: m_pSubLock must not be locked when calling this
410 InvalidateSubtitle(tStart, m_pSubStream);
413 hr = S_OK;
415 return hr;
418 bool CSubtitleInputPin::IsHdmvSub(const CMediaType* pmt)
420 return pmt->majortype == MEDIATYPE_Subtitle && (pmt->subtype == MEDIASUBTYPE_HDMVSUB || // Blu ray presentation graphics
421 pmt->subtype == MEDIASUBTYPE_DVB_SUBTITLES || // DVB subtitles
422 (pmt->subtype == MEDIASUBTYPE_NULL && pmt->formattype == FORMAT_SubtitleInfo)) // Workaround : support for Haali PGS
423 ? true
424 : false;