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 (1) // 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();
88 return m_pObjects
.GetHeadPosition();
91 HRESULT
CHdmvSub::ParseSample(IMediaSample
* pSample
)
93 CheckPointer (pSample
, E_POINTER
);
95 REFERENCE_TIME rtStart
= INVALID_TIME
, rtStop
= INVALID_TIME
;
99 hr
= pSample
->GetPointer(&pData
);
100 if(FAILED(hr
) || pData
== NULL
) {
103 lSampleLen
= pSample
->GetActualDataLength();
105 pSample
->GetTime(&rtStart
, &rtStop
);
107 CGolombBuffer
SampleBuffer (pData
, lSampleLen
);
109 while (!SampleBuffer
.IsEOF()) {
110 if (m_nCurSegment
== NO_SEGMENT
) {
111 HDMV_SEGMENT_TYPE nSegType
= (HDMV_SEGMENT_TYPE
)SampleBuffer
.ReadByte();
112 USHORT nUnitSize
= SampleBuffer
.ReadShort();
118 case PRESENTATION_SEG
:
119 case END_OF_DISPLAY
:
120 m_nCurSegment
= nSegType
;
121 AllocSegment (nUnitSize
);
125 case INTERACTIVE_SEG
:
129 SampleBuffer
.SkipBytes(nUnitSize
);
132 return VFW_E_SAMPLE_REJECTED
;
136 if (m_nCurSegment
!= NO_SEGMENT
) {
137 if (m_nSegBufferPos
< m_nSegSize
) {
138 int nSize
= min (m_nSegSize
-m_nSegBufferPos
, lSampleLen
);
139 SampleBuffer
.ReadBuffer (m_pSegBuffer
+m_nSegBufferPos
, nSize
);
140 m_nSegBufferPos
+= nSize
;
143 if (m_nSegBufferPos
>= m_nSegSize
) {
144 CGolombBuffer
SegmentBuffer (m_pSegBuffer
, m_nSegSize
);
146 switch (m_nCurSegment
) {
148 TRACE_HDMVSUB( (_T("CHdmvSub:PALETTE rtStart=%10I64d\n"), rtStart
));
149 ParsePalette(&SegmentBuffer
, m_nSegSize
);
152 TRACE_HDMVSUB( (_T("CHdmvSub:OBJECT %lS\n"), ReftimeToCString(rtStart
)));
153 ParseObject(&SegmentBuffer
, m_nSegSize
);
155 case PRESENTATION_SEG
:
156 TRACE_HDMVSUB( (_T("CHdmvSub:PRESENTATION_SEG %lS (size=%d)\n"), ReftimeToCString(rtStart
), m_nSegSize
));
158 if (m_pCurrentObject
) {
159 TRACE_HDMVSUB( (_T("CHdmvSub:PRESENTATION_SEG %d\n"), m_pCurrentObject
->m_nObjectNumber
));
160 if(m_pCurrentObject
->m_nObjectNumber
> 1) {
161 m_pCurrentObject
->m_nObjectNumber
--;
164 m_pCurrentObject
->m_rtStop
= rtStart
;
165 m_pObjects
.AddTail (m_pCurrentObject
);
166 TRACE_HDMVSUB( (_T("CHdmvSub:HDMV : %lS => %lS\n"), ReftimeToCString (m_pCurrentObject
->m_rtStart
), ReftimeToCString(rtStart
)));
167 m_pCurrentObject
= NULL
;
170 if (ParsePresentationSegment(&SegmentBuffer
) > 0) {
171 m_pCurrentObject
->m_rtStart
= rtStart
;
172 m_pCurrentObject
->m_rtStop
= _I64_MAX
;
176 // TRACE_HDMVSUB( (_T("CHdmvSub:WINDOW_DEF %S\n", ReftimeToCString(rtStart));
178 case END_OF_DISPLAY
:
179 // TRACE_HDMVSUB( (_T("CHdmvSub:END_OF_DISPLAY %S\n", ReftimeToCString(rtStart));
182 TRACE_HDMVSUB( (_T("CHdmvSub:UNKNOWN Seg %d rtStart=0x%10dd\n"), m_nCurSegment
, rtStart
));
185 m_nCurSegment
= NO_SEGMENT
;
194 int CHdmvSub::ParsePresentationSegment(CGolombBuffer
* pGBuffer
)
196 COMPOSITION_DESCRIPTOR CompositionDescriptor
;
198 //bool palette_update_flag;
199 //BYTE palette_id_ref;
201 ParseVideoDescriptor(pGBuffer
, &m_VideoDescriptor
);
202 ParseCompositionDescriptor(pGBuffer
, &CompositionDescriptor
);
203 pGBuffer
->ReadByte(); //palette_update_flag = !!(pGBuffer->ReadByte() & 0x80);
204 pGBuffer
->ReadByte(); //palette_id_ref = pGBuffer->ReadByte();
205 nObjectNumber
= pGBuffer
->ReadByte();
207 TRACE_HDMVSUB( (_T("CHdmvSub::ParsePresentationSegment Size = %d, nObjectNumber = %d\n"), pGBuffer
->GetSize(), nObjectNumber
));
209 if (nObjectNumber
> 0) {
210 delete m_pCurrentObject
;
211 m_pCurrentObject
= DNew
CompositionObject();
212 m_pCurrentObject
->m_nObjectNumber
= nObjectNumber
;
213 for(int i
=0; i
<nObjectNumber
; i
++) {
214 ParseCompositionObject (pGBuffer
, m_pCurrentObject
);
218 return nObjectNumber
;
221 void CHdmvSub::ParsePalette(CGolombBuffer
* pGBuffer
, USHORT nSize
) // #497
224 BYTE palette_id
= pGBuffer
->ReadByte();
225 BYTE palette_version_number
= pGBuffer
->ReadByte();
226 UNUSED_ALWAYS(palette_id
);
227 UNUSED_ALWAYS(palette_version_number
);
229 ASSERT ((nSize
-2) % sizeof(HDMV_PALETTE
) == 0);
230 nNbEntry
= (nSize
-2) / sizeof(HDMV_PALETTE
);
231 HDMV_PALETTE
* pPalette
= (HDMV_PALETTE
*)pGBuffer
->GetBufferPos();
233 if (m_pDefaultPalette
== NULL
|| m_nDefaultPaletteNbEntry
!= nNbEntry
) {
234 delete[] m_pDefaultPalette
;
235 m_pDefaultPalette
= new HDMV_PALETTE
[nNbEntry
];
236 m_nDefaultPaletteNbEntry
= nNbEntry
;
238 memcpy (m_pDefaultPalette
, pPalette
, nNbEntry
*sizeof(HDMV_PALETTE
));
240 if (m_pCurrentObject
) {
241 m_pCurrentObject
->SetPalette (nNbEntry
, pPalette
, m_VideoDescriptor
.nVideoWidth
>720);
245 void CHdmvSub::ParseObject(CGolombBuffer
* pGBuffer
, USHORT nUnitSize
) // #498
247 SHORT object_id
= pGBuffer
->ReadShort();
248 UNUSED_ALWAYS(object_id
);
249 BYTE m_sequence_desc
;
251 ASSERT (m_pCurrentObject
!= NULL
);
252 if (m_pCurrentObject
) { // && m_pCurrentObject->m_object_id_ref == object_id)
253 m_pCurrentObject
->m_version_number
= pGBuffer
->ReadByte();
254 m_sequence_desc
= pGBuffer
->ReadByte();
256 if (m_sequence_desc
& 0x80) {
257 DWORD object_data_length
= (DWORD
)pGBuffer
->BitRead(24);
259 m_pCurrentObject
->m_width
= pGBuffer
->ReadShort();
260 m_pCurrentObject
->m_height
= pGBuffer
->ReadShort();
262 m_pCurrentObject
->SetRLEData (pGBuffer
->GetBufferPos(), nUnitSize
-11, object_data_length
-4);
264 TRACE_HDMVSUB( (_T("CHdmvSub:NewObject size=%ld, total obj=%d, %dx%d\n"), object_data_length
, m_pObjects
.GetCount(),
265 m_pCurrentObject
->m_width
, m_pCurrentObject
->m_height
));
267 m_pCurrentObject
->AppendRLEData (pGBuffer
->GetBufferPos(), nUnitSize
-4);
272 void CHdmvSub::ParseCompositionObject(CGolombBuffer
* pGBuffer
, CompositionObject
* pCompositionObject
)
275 pCompositionObject
->m_object_id_ref
= pGBuffer
->ReadShort();
276 pCompositionObject
->m_window_id_ref
= pGBuffer
->ReadByte();
277 bTemp
= pGBuffer
->ReadByte();
278 pCompositionObject
->m_object_cropped_flag
= !!(bTemp
& 0x80);
279 pCompositionObject
->m_forced_on_flag
= !!(bTemp
& 0x40);
280 pCompositionObject
->m_horizontal_position
= pGBuffer
->ReadShort();
281 pCompositionObject
->m_vertical_position
= pGBuffer
->ReadShort();
283 if (pCompositionObject
->m_object_cropped_flag
) {
284 pCompositionObject
->m_cropping_horizontal_position
= pGBuffer
->ReadShort();
285 pCompositionObject
->m_cropping_vertical_position
= pGBuffer
->ReadShort();
286 pCompositionObject
->m_cropping_width
= pGBuffer
->ReadShort();
287 pCompositionObject
->m_cropping_height
= pGBuffer
->ReadShort();
291 void CHdmvSub::ParseVideoDescriptor(CGolombBuffer
* pGBuffer
, VIDEO_DESCRIPTOR
* pVideoDescriptor
)
293 pVideoDescriptor
->nVideoWidth
= pGBuffer
->ReadShort();
294 pVideoDescriptor
->nVideoHeight
= pGBuffer
->ReadShort();
295 pVideoDescriptor
->bFrameRate
= pGBuffer
->ReadByte();
298 void CHdmvSub::ParseCompositionDescriptor(CGolombBuffer
* pGBuffer
, COMPOSITION_DESCRIPTOR
* pCompositionDescriptor
)
300 pCompositionDescriptor
->nNumber
= pGBuffer
->ReadShort();
301 pCompositionDescriptor
->bState
= pGBuffer
->ReadByte();
304 void CHdmvSub::Render(SubPicDesc
& spd
, REFERENCE_TIME rt
, RECT
& bbox
)
306 CompositionObject
* pObject
= FindObject (rt
);
308 ASSERT (pObject
!=NULL
&& spd
.w
>= (pObject
->m_horizontal_position
+ pObject
->m_width
) && spd
.h
>= (pObject
->m_vertical_position
+ pObject
->m_height
));
310 if (pObject
&& pObject
->GetRLEDataSize() && pObject
->m_width
> 0 && pObject
->m_height
> 0 &&
311 spd
.w
>= (pObject
->m_horizontal_position
+ pObject
->m_width
) &&
312 spd
.h
>= (pObject
->m_vertical_position
+ pObject
->m_height
)) {
313 if (!pObject
->HavePalette()) {
314 pObject
->SetPalette (m_nDefaultPaletteNbEntry
, m_pDefaultPalette
, m_VideoDescriptor
.nVideoWidth
>720);
317 TRACE_HDMVSUB( (_T("CHdmvSub:Render size=%ld, ObjRes=%dx%d, SPDRes=%dx%d\n"), pObject
->GetRLEDataSize(),
318 pObject
->m_width
, pObject
->m_height
, spd
.w
, spd
.h
));
319 pObject
->RenderHdmv(spd
);
321 bbox
.left
= pObject
->m_horizontal_position
;
322 bbox
.top
= pObject
->m_vertical_position
;
323 bbox
.right
= bbox
.left
+ pObject
->m_width
;
324 bbox
.bottom
= bbox
.top
+ pObject
->m_height
;
328 HRESULT
CHdmvSub::GetTextureSize (POSITION pos
, SIZE
& MaxTextureSize
, SIZE
& VideoSize
, POINT
& VideoTopLeft
)
330 CompositionObject
* pObject
= m_pObjects
.GetAt (pos
);
332 MaxTextureSize
.cx
= m_VideoDescriptor
.nVideoWidth
;
333 MaxTextureSize
.cy
= m_VideoDescriptor
.nVideoHeight
;
335 VideoSize
.cx
= m_VideoDescriptor
.nVideoWidth
;
336 VideoSize
.cy
= m_VideoDescriptor
.nVideoHeight
;
338 // The subs will be directly rendered into the proper position!
339 VideoTopLeft
.x
= 0; //pObject->m_horizontal_position;
340 VideoTopLeft
.y
= 0; //pObject->m_vertical_position;
350 void CHdmvSub::Reset()
352 CompositionObject
* pObject
;
353 while (m_pObjects
.GetCount() > 0) {
354 pObject
= m_pObjects
.RemoveHead();
359 CompositionObject
* CHdmvSub::FindObject(REFERENCE_TIME rt
)
361 POSITION pos
= m_pObjects
.GetHeadPosition();
364 CompositionObject
* pObject
= m_pObjects
.GetAt (pos
);
366 if (rt
>= pObject
->m_rtStart
&& rt
< pObject
->m_rtStop
) {
370 m_pObjects
.GetNext(pos
);