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)
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
23 #include "SubtitleInputPin.h"
24 #include "VobSubFile.h"
27 #include "RenderedHdmvSubtitle.h"
30 #include "..\..\include\moreuuids.h"
32 // our first format id
33 #define __GAB1__ "GAB1"
35 // our tags for __GAB1__ (ushort) + size (ushort)
38 #define __GAB1_LANGUAGE__ 0
39 // (int)start+(int)stop+(char*)line+'0'
40 #define __GAB1_ENTRY__ 1
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"
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
)
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
;
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
);
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
;
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)
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
= DEBUG_NEW
CRenderedHdmvSubtitle(m_pSubLock
, (m_mt
.subtype
== MEDIASUBTYPE_DVB_SUBTITLES
) ? ST_DVB
: ST_HDMV
, name
, lcid
))) {
157 AddSubStream(m_pSubStream
);
159 return __super::CompleteConnect(pReceivePin
);
162 HRESULT
CSubtitleInputPin::BreakConnect()
164 RemoveSubStream(m_pSubStream
);
169 return __super::BreakConnect();
172 STDMETHODIMP
CSubtitleInputPin::ReceiveConnection(IPin
* pConnector
, const AM_MEDIA_TYPE
* pmt
)
176 RemoveSubStream(m_pSubStream
);
179 m_Connected
->Release();
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
));
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
:
231 STDMETHOD(GetMpeg2StreamType
)(ULONG
* plType
) = NULL
;
232 STDMETHOD(toto
)() = NULL
;
235 STDMETHODIMP
CSubtitleInputPin::Receive(IMediaSample
* pSample
)
237 DbgLog(( LOG_TRACE
, 4, TEXT(__FUNCTION__
) ));
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
);
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
];
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));
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));
295 else if(!strncmp((char*)pData
, __GAB2__
, strlen(__GAB2__
)))
297 char* ptr
= (char*)&pData
[strlen(__GAB2__
)+1];
298 char* end
= (char*)&pData
[len
];
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
);
318 else if(pData
!= 0 && len
> 1 && *pData
!= 0)
320 CStringA
str((char*)pData
, len
);
322 str
.Replace("\r\n", "\n");
327 pRTS
->Add(AToW(str
), false, (int)(tStart
/ 10000), (int)(tStop
/ 10000));
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();
343 pRTS
->Add(str
, true, (int)(tStart
/ 10000), (int)(tStop
/ 10000));
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();
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
);
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();
389 pSSF
->Append(tStart
, tStop
, str
);
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
);
408 TRACE(_T("InvalidateSubtitle(%I64d, ..)\n"), tStart
);
409 // IMPORTANT: m_pSubLock must not be locked when calling this
410 InvalidateSubtitle(tStart
, m_pSubStream
);
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