2 * $Id: HdmvSub.cpp 3720 2011-09-12 00:30:00Z aleksoid $
4 * (C) 2006-2010 see AUTHORS
6 * This file is part of mplayerc.
8 * Mplayerc is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * Mplayerc is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "../DSUtil/GolombBuffer.h"
27 #if (0) // Set to 1 to activate HDMV subtitles traces
28 #define TRACE_HDMVSUB(_x_) {CString tmp;tmp.Format _x_; XY_LOG_INFO( tmp.GetString() );}
30 #define TRACE_HDMVSUB(_x_)
33 CHdmvSub::CHdmvSub(void)
38 m_nCurSegment
= NO_SEGMENT
;
40 m_nTotalSegBuffer
= 0;
43 m_pCurrentObject
= NULL
;
44 m_pDefaultPalette
= NULL
;
45 m_nDefaultPaletteNbEntry
= 0;
47 memset (&m_VideoDescriptor
, 0, sizeof(VIDEO_DESCRIPTOR
));
54 delete[] m_pSegBuffer
;
55 delete[] m_pDefaultPalette
;
56 delete m_pCurrentObject
;
60 void CHdmvSub::AllocSegment(int nSize
)
62 if (nSize
> m_nTotalSegBuffer
) {
63 delete[] m_pSegBuffer
;
64 m_pSegBuffer
= DNew BYTE
[nSize
];
65 m_nTotalSegBuffer
= nSize
;
71 POSITION
CHdmvSub::GetStartPosition(REFERENCE_TIME rt
, double fps
)
73 CompositionObject
* pObject
;
74 TRACE_HDMVSUB( (_T("CHdmvSub:GetStartPosition rt=%lS\n"), ReftimeToCString(rt
)) );
76 while (m_pObjects
.GetCount()>0) {
77 pObject
= m_pObjects
.GetHead();
78 if (pObject
->m_rtStop
< rt
) {
79 TRACE_HDMVSUB( (_T("CHdmvSub:HDMV remove object %d %lS => %lS (rt=%lS)\n"), pObject
->GetRLEDataSize(),
80 ReftimeToCString (pObject
->m_rtStart
), ReftimeToCString(pObject
->m_rtStop
), ReftimeToCString(rt
)));
81 m_pObjects
.RemoveHead();
87 // log first 2 objects
89 // POSITION pos = m_pObjects.GetHeadPosition();
90 // for (int i=0;i<2 && pos!=NULL; i++)
92 // CompositionObject* pObject = m_pObjects.GetNext(pos);
93 // TRACE_HDMVSUB( (_T("CHdmvSub:HDMV cur %d object %d %lS => %lS\n"), i, pObject->GetRLEDataSize(),
94 // ReftimeToCString (pObject->m_rtStart), ReftimeToCString(pObject->m_rtStop)));
98 POSITION pos
= m_pObjects
.GetHeadPosition();
101 CompositionObject
* pObject
= m_pObjects
.GetAt (pos
);
103 if (rt
>= pObject
->m_rtStart
&& rt
< pObject
->m_rtStop
) {
106 else if( rt
< pObject
->m_rtStart
)
112 m_pObjects
.GetNext(pos
);
117 HRESULT
CHdmvSub::ParseSample(IMediaSample
* pSample
)
119 CheckPointer (pSample
, E_POINTER
);
121 REFERENCE_TIME rtStart
= INVALID_TIME
, rtStop
= INVALID_TIME
;
125 hr
= pSample
->GetPointer(&pData
);
126 if(FAILED(hr
) || pData
== NULL
) {
129 lSampleLen
= pSample
->GetActualDataLength();
131 pSample
->GetTime(&rtStart
, &rtStop
);
133 CGolombBuffer
SampleBuffer (pData
, lSampleLen
);
135 while (!SampleBuffer
.IsEOF()) {
136 if (m_nCurSegment
== NO_SEGMENT
) {
137 HDMV_SEGMENT_TYPE nSegType
= (HDMV_SEGMENT_TYPE
)SampleBuffer
.ReadByte();
138 USHORT nUnitSize
= SampleBuffer
.ReadShort();
144 case PRESENTATION_SEG
:
145 case END_OF_DISPLAY
:
146 m_nCurSegment
= nSegType
;
147 AllocSegment (nUnitSize
);
151 case INTERACTIVE_SEG
:
155 SampleBuffer
.SkipBytes(nUnitSize
);
158 return VFW_E_SAMPLE_REJECTED
;
162 if (m_nCurSegment
!= NO_SEGMENT
) {
163 if (m_nSegBufferPos
< m_nSegSize
) {
164 int nSize
= min (m_nSegSize
-m_nSegBufferPos
, lSampleLen
);
165 SampleBuffer
.ReadBuffer (m_pSegBuffer
+m_nSegBufferPos
, nSize
);
166 m_nSegBufferPos
+= nSize
;
169 if (m_nSegBufferPos
>= m_nSegSize
) {
170 CGolombBuffer
SegmentBuffer (m_pSegBuffer
, m_nSegSize
);
172 switch (m_nCurSegment
) {
174 TRACE_HDMVSUB( (_T("CHdmvSub:PALETTE rtStart=%10I64d\n"), rtStart
));
175 ParsePalette(&SegmentBuffer
, m_nSegSize
);
178 TRACE_HDMVSUB( (_T("CHdmvSub:OBJECT %lS\n"), ReftimeToCString(rtStart
)));
179 ParseObject(&SegmentBuffer
, m_nSegSize
);
181 case PRESENTATION_SEG
:
182 TRACE_HDMVSUB( (_T("CHdmvSub:PRESENTATION_SEG %lS (size=%d)\n"), ReftimeToCString(rtStart
), m_nSegSize
));
184 if (m_pCurrentObject
) {
185 TRACE_HDMVSUB( (_T("CHdmvSub:PRESENTATION_SEG %d\n"), m_pCurrentObject
->m_nObjectNumber
));
186 if(m_pCurrentObject
->m_nObjectNumber
> 1) {
187 m_pCurrentObject
->m_nObjectNumber
--;
190 m_pCurrentObject
->m_rtStop
= rtStart
;
191 m_pObjects
.AddTail (m_pCurrentObject
);
192 TRACE_HDMVSUB( (_T("CHdmvSub:HDMV : %lS => %lS\n"), ReftimeToCString (m_pCurrentObject
->m_rtStart
), ReftimeToCString(rtStart
)));
193 m_pCurrentObject
= NULL
;
196 if (ParsePresentationSegment(&SegmentBuffer
) > 0) {
197 m_pCurrentObject
->m_rtStart
= rtStart
;
198 m_pCurrentObject
->m_rtStop
= _I64_MAX
;
202 // TRACE_HDMVSUB( (_T("CHdmvSub:WINDOW_DEF %S\n", ReftimeToCString(rtStart));
204 case END_OF_DISPLAY
:
205 // TRACE_HDMVSUB( (_T("CHdmvSub:END_OF_DISPLAY %S\n", ReftimeToCString(rtStart));
208 TRACE_HDMVSUB( (_T("CHdmvSub:UNKNOWN Seg %d rtStart=0x%10dd\n"), m_nCurSegment
, rtStart
));
211 m_nCurSegment
= NO_SEGMENT
;
220 int CHdmvSub::ParsePresentationSegment(CGolombBuffer
* pGBuffer
)
222 COMPOSITION_DESCRIPTOR CompositionDescriptor
;
224 //bool palette_update_flag;
225 //BYTE palette_id_ref;
227 ParseVideoDescriptor(pGBuffer
, &m_VideoDescriptor
);
228 ParseCompositionDescriptor(pGBuffer
, &CompositionDescriptor
);
229 pGBuffer
->ReadByte(); //palette_update_flag = !!(pGBuffer->ReadByte() & 0x80);
230 pGBuffer
->ReadByte(); //palette_id_ref = pGBuffer->ReadByte();
231 nObjectNumber
= pGBuffer
->ReadByte();
233 TRACE_HDMVSUB( (_T("CHdmvSub::ParsePresentationSegment Size = %d, nObjectNumber = %d\n"), pGBuffer
->GetSize(), nObjectNumber
));
235 if (nObjectNumber
> 0) {
236 delete m_pCurrentObject
;
237 m_pCurrentObject
= DNew
CompositionObject();
238 m_pCurrentObject
->m_nObjectNumber
= nObjectNumber
;
239 for(int i
=0; i
<nObjectNumber
; i
++) {
240 ParseCompositionObject (pGBuffer
, m_pCurrentObject
);
244 return nObjectNumber
;
247 void CHdmvSub::ParsePalette(CGolombBuffer
* pGBuffer
, USHORT nSize
) // #497
250 BYTE palette_id
= pGBuffer
->ReadByte();
251 BYTE palette_version_number
= pGBuffer
->ReadByte();
252 UNUSED_ALWAYS(palette_id
);
253 UNUSED_ALWAYS(palette_version_number
);
255 ASSERT ((nSize
-2) % sizeof(HDMV_PALETTE
) == 0);
256 nNbEntry
= (nSize
-2) / sizeof(HDMV_PALETTE
);
257 HDMV_PALETTE
* pPalette
= (HDMV_PALETTE
*)pGBuffer
->GetBufferPos();
259 if (m_pDefaultPalette
== NULL
|| m_nDefaultPaletteNbEntry
!= nNbEntry
) {
260 delete[] m_pDefaultPalette
;
261 m_pDefaultPalette
= new HDMV_PALETTE
[nNbEntry
];
262 m_nDefaultPaletteNbEntry
= nNbEntry
;
264 memcpy (m_pDefaultPalette
, pPalette
, nNbEntry
*sizeof(HDMV_PALETTE
));
266 if (m_pCurrentObject
) {
267 m_pCurrentObject
->SetPalette (nNbEntry
, pPalette
, m_VideoDescriptor
.nVideoWidth
>720);
271 void CHdmvSub::ParseObject(CGolombBuffer
* pGBuffer
, USHORT nUnitSize
) // #498
273 SHORT object_id
= pGBuffer
->ReadShort();
274 UNUSED_ALWAYS(object_id
);
275 BYTE m_sequence_desc
;
277 ASSERT (m_pCurrentObject
!= NULL
);
278 if (m_pCurrentObject
) { // && m_pCurrentObject->m_object_id_ref == object_id)
279 m_pCurrentObject
->m_version_number
= pGBuffer
->ReadByte();
280 m_sequence_desc
= pGBuffer
->ReadByte();
282 if (m_sequence_desc
& 0x80) {
283 DWORD object_data_length
= (DWORD
)pGBuffer
->BitRead(24);
285 m_pCurrentObject
->m_width
= pGBuffer
->ReadShort();
286 m_pCurrentObject
->m_height
= pGBuffer
->ReadShort();
288 m_pCurrentObject
->SetRLEData (pGBuffer
->GetBufferPos(), nUnitSize
-11, object_data_length
-4);
290 TRACE_HDMVSUB( (_T("CHdmvSub:NewObject size=%ld, total obj=%d, %dx%d\n"), object_data_length
, m_pObjects
.GetCount(),
291 m_pCurrentObject
->m_width
, m_pCurrentObject
->m_height
));
293 m_pCurrentObject
->AppendRLEData (pGBuffer
->GetBufferPos(), nUnitSize
-4);
298 void CHdmvSub::ParseCompositionObject(CGolombBuffer
* pGBuffer
, CompositionObject
* pCompositionObject
)
301 pCompositionObject
->m_object_id_ref
= pGBuffer
->ReadShort();
302 pCompositionObject
->m_window_id_ref
= pGBuffer
->ReadByte();
303 bTemp
= pGBuffer
->ReadByte();
304 pCompositionObject
->m_object_cropped_flag
= !!(bTemp
& 0x80);
305 pCompositionObject
->m_forced_on_flag
= !!(bTemp
& 0x40);
306 pCompositionObject
->m_horizontal_position
= pGBuffer
->ReadShort();
307 pCompositionObject
->m_vertical_position
= pGBuffer
->ReadShort();
309 if (pCompositionObject
->m_object_cropped_flag
) {
310 pCompositionObject
->m_cropping_horizontal_position
= pGBuffer
->ReadShort();
311 pCompositionObject
->m_cropping_vertical_position
= pGBuffer
->ReadShort();
312 pCompositionObject
->m_cropping_width
= pGBuffer
->ReadShort();
313 pCompositionObject
->m_cropping_height
= pGBuffer
->ReadShort();
317 void CHdmvSub::ParseVideoDescriptor(CGolombBuffer
* pGBuffer
, VIDEO_DESCRIPTOR
* pVideoDescriptor
)
319 pVideoDescriptor
->nVideoWidth
= pGBuffer
->ReadShort();
320 pVideoDescriptor
->nVideoHeight
= pGBuffer
->ReadShort();
321 pVideoDescriptor
->bFrameRate
= pGBuffer
->ReadByte();
324 void CHdmvSub::ParseCompositionDescriptor(CGolombBuffer
* pGBuffer
, COMPOSITION_DESCRIPTOR
* pCompositionDescriptor
)
326 pCompositionDescriptor
->nNumber
= pGBuffer
->ReadShort();
327 pCompositionDescriptor
->bState
= pGBuffer
->ReadByte();
330 void CHdmvSub::Render(SubPicDesc
& spd
, REFERENCE_TIME rt
, RECT
& bbox
)
332 CompositionObject
* pObject
= FindObject (rt
);
334 ASSERT (pObject
!=NULL
&& spd
.w
>= (pObject
->m_horizontal_position
+ pObject
->m_width
) && spd
.h
>= (pObject
->m_vertical_position
+ pObject
->m_height
));
336 if (pObject
&& pObject
->GetRLEDataSize() && pObject
->m_width
> 0 && pObject
->m_height
> 0 &&
337 spd
.w
>= (pObject
->m_horizontal_position
+ pObject
->m_width
) &&
338 spd
.h
>= (pObject
->m_vertical_position
+ pObject
->m_height
)) {
339 if (!pObject
->HavePalette()) {
340 pObject
->SetPalette (m_nDefaultPaletteNbEntry
, m_pDefaultPalette
, m_VideoDescriptor
.nVideoWidth
>720);
342 pObject
->InitColor(spd
);
343 TRACE_HDMVSUB( (_T("CHdmvSub:Render size=%ld, ObjRes=%dx%d, SPDRes=%dx%d\n"), pObject
->GetRLEDataSize(),
344 pObject
->m_width
, pObject
->m_height
, spd
.w
, spd
.h
));
345 pObject
->RenderHdmv(spd
);
347 bbox
.left
= pObject
->m_horizontal_position
;
348 bbox
.top
= pObject
->m_vertical_position
;
349 bbox
.right
= bbox
.left
+ pObject
->m_width
;
350 bbox
.bottom
= bbox
.top
+ pObject
->m_height
;
354 HRESULT
CHdmvSub::GetTextureSize (POSITION pos
, SIZE
& MaxTextureSize
, SIZE
& VideoSize
, POINT
& VideoTopLeft
)
356 CompositionObject
* pObject
= m_pObjects
.GetAt (pos
);
358 MaxTextureSize
.cx
= m_VideoDescriptor
.nVideoWidth
;
359 MaxTextureSize
.cy
= m_VideoDescriptor
.nVideoHeight
;
361 VideoSize
.cx
= m_VideoDescriptor
.nVideoWidth
;
362 VideoSize
.cy
= m_VideoDescriptor
.nVideoHeight
;
364 // The subs will be directly rendered into the proper position!
365 VideoTopLeft
.x
= 0; //pObject->m_horizontal_position;
366 VideoTopLeft
.y
= 0; //pObject->m_vertical_position;
376 void CHdmvSub::Reset()
378 CompositionObject
* pObject
;
379 while (m_pObjects
.GetCount() > 0) {
380 pObject
= m_pObjects
.RemoveHead();
385 CompositionObject
* CHdmvSub::FindObject(REFERENCE_TIME rt
)
387 POSITION pos
= m_pObjects
.GetHeadPosition();
390 CompositionObject
* pObject
= m_pObjects
.GetAt (pos
);
392 if (rt
>= pObject
->m_rtStart
&& rt
< pObject
->m_rtStop
) {
396 m_pObjects
.GetNext(pos
);