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 TRACE
34 CHdmvSub::CHdmvSub(void)
39 m_nCurSegment
= NO_SEGMENT
;
41 m_nTotalSegBuffer
= 0;
44 m_pCurrentObject
= NULL
;
45 m_pDefaultPalette
= NULL
;
46 m_nDefaultPaletteNbEntry
= 0;
48 memset (&m_VideoDescriptor
, 0, sizeof(VIDEO_DESCRIPTOR
));
55 delete[] m_pSegBuffer
;
56 delete[] m_pDefaultPalette
;
57 delete m_pCurrentObject
;
61 void CHdmvSub::AllocSegment(int nSize
)
63 if (nSize
> m_nTotalSegBuffer
) {
64 delete[] m_pSegBuffer
;
65 m_pSegBuffer
= DNew BYTE
[nSize
];
66 m_nTotalSegBuffer
= nSize
;
72 POSITION
CHdmvSub::GetStartPosition(REFERENCE_TIME rt
, double fps
)
74 CompositionObject
* pObject
;
77 while (m_pObjects
.GetCount()>0) {
78 pObject
= m_pObjects
.GetHead();
79 if (pObject
->m_rtStop
< rt
) {
80 TRACE_HDMVSUB ("CHdmvSub:HDMV remove object %d %S => %S (rt=%S)\n", pObject
->GetRLEDataSize(),
81 ReftimeToString (pObject
->m_rtStart
), ReftimeToString(pObject
->m_rtStop
), ReftimeToString(rt
));
82 m_pObjects
.RemoveHead();
89 return m_pObjects
.GetHeadPosition();
92 HRESULT
CHdmvSub::ParseSample(IMediaSample
* pSample
)
94 CheckPointer (pSample
, E_POINTER
);
96 REFERENCE_TIME rtStart
= INVALID_TIME
, rtStop
= INVALID_TIME
;
100 hr
= pSample
->GetPointer(&pData
);
101 if(FAILED(hr
) || pData
== NULL
) {
104 lSampleLen
= pSample
->GetActualDataLength();
106 pSample
->GetTime(&rtStart
, &rtStop
);
108 CGolombBuffer
SampleBuffer (pData
, lSampleLen
);
110 while (!SampleBuffer
.IsEOF()) {
111 if (m_nCurSegment
== NO_SEGMENT
) {
112 HDMV_SEGMENT_TYPE nSegType
= (HDMV_SEGMENT_TYPE
)SampleBuffer
.ReadByte();
113 USHORT nUnitSize
= SampleBuffer
.ReadShort();
119 case PRESENTATION_SEG
:
120 case END_OF_DISPLAY
:
121 m_nCurSegment
= nSegType
;
122 AllocSegment (nUnitSize
);
126 case INTERACTIVE_SEG
:
130 SampleBuffer
.SkipBytes(nUnitSize
);
133 return VFW_E_SAMPLE_REJECTED
;
137 if (m_nCurSegment
!= NO_SEGMENT
) {
138 if (m_nSegBufferPos
< m_nSegSize
) {
139 int nSize
= min (m_nSegSize
-m_nSegBufferPos
, lSampleLen
);
140 SampleBuffer
.ReadBuffer (m_pSegBuffer
+m_nSegBufferPos
, nSize
);
141 m_nSegBufferPos
+= nSize
;
144 if (m_nSegBufferPos
>= m_nSegSize
) {
145 CGolombBuffer
SegmentBuffer (m_pSegBuffer
, m_nSegSize
);
147 switch (m_nCurSegment
) {
149 TRACE_HDMVSUB ("CHdmvSub:PALETTE rtStart=%10I64d\n", rtStart
);
150 ParsePalette(&SegmentBuffer
, m_nSegSize
);
153 TRACE_HDMVSUB ("CHdmvSub:OBJECT %S\n", ReftimeToString(rtStart
));
154 ParseObject(&SegmentBuffer
, m_nSegSize
);
156 case PRESENTATION_SEG
:
157 TRACE_HDMVSUB ("CHdmvSub:PRESENTATION_SEG %S (size=%d)\n", ReftimeToString(rtStart
), m_nSegSize
);
159 if (m_pCurrentObject
) {
160 TRACE_HDMVSUB ("CHdmvSub:PRESENTATION_SEG %d\n", m_pCurrentObject
->m_nObjectNumber
);
161 if(m_pCurrentObject
->m_nObjectNumber
> 1) {
162 m_pCurrentObject
->m_nObjectNumber
--;
165 m_pCurrentObject
->m_rtStop
= rtStart
;
166 m_pObjects
.AddTail (m_pCurrentObject
);
167 TRACE_HDMVSUB ("CHdmvSub:HDMV : %S => %S\n", ReftimeToString (m_pCurrentObject
->m_rtStart
), ReftimeToString(rtStart
));
168 m_pCurrentObject
= NULL
;
171 if (ParsePresentationSegment(&SegmentBuffer
) > 0) {
172 m_pCurrentObject
->m_rtStart
= rtStart
;
173 m_pCurrentObject
->m_rtStop
= _I64_MAX
;
177 // TRACE_HDMVSUB ("CHdmvSub:WINDOW_DEF %S\n", ReftimeToString(rtStart));
179 case END_OF_DISPLAY
:
180 // TRACE_HDMVSUB ("CHdmvSub:END_OF_DISPLAY %S\n", ReftimeToString(rtStart));
183 TRACE_HDMVSUB ("CHdmvSub:UNKNOWN Seg %d rtStart=0x%10dd\n", m_nCurSegment
, rtStart
);
186 m_nCurSegment
= NO_SEGMENT
;
195 int CHdmvSub::ParsePresentationSegment(CGolombBuffer
* pGBuffer
)
197 COMPOSITION_DESCRIPTOR CompositionDescriptor
;
199 //bool palette_update_flag;
200 //BYTE palette_id_ref;
202 ParseVideoDescriptor(pGBuffer
, &m_VideoDescriptor
);
203 ParseCompositionDescriptor(pGBuffer
, &CompositionDescriptor
);
204 pGBuffer
->ReadByte(); //palette_update_flag = !!(pGBuffer->ReadByte() & 0x80);
205 pGBuffer
->ReadByte(); //palette_id_ref = pGBuffer->ReadByte();
206 nObjectNumber
= pGBuffer
->ReadByte();
208 TRACE_HDMVSUB( "CHdmvSub::ParsePresentationSegment Size = %d, nObjectNumber = %d\n", pGBuffer
->GetSize(), nObjectNumber
);
210 if (nObjectNumber
> 0) {
211 delete m_pCurrentObject
;
212 m_pCurrentObject
= DNew
CompositionObject();
213 m_pCurrentObject
->m_nObjectNumber
= nObjectNumber
;
214 for(int i
=0; i
<nObjectNumber
; i
++) {
215 ParseCompositionObject (pGBuffer
, m_pCurrentObject
);
219 return nObjectNumber
;
222 void CHdmvSub::ParsePalette(CGolombBuffer
* pGBuffer
, USHORT nSize
) // #497
225 BYTE palette_id
= pGBuffer
->ReadByte();
226 BYTE palette_version_number
= pGBuffer
->ReadByte();
227 UNUSED_ALWAYS(palette_id
);
228 UNUSED_ALWAYS(palette_version_number
);
230 ASSERT ((nSize
-2) % sizeof(HDMV_PALETTE
) == 0);
231 nNbEntry
= (nSize
-2) / sizeof(HDMV_PALETTE
);
232 HDMV_PALETTE
* pPalette
= (HDMV_PALETTE
*)pGBuffer
->GetBufferPos();
234 if (m_pDefaultPalette
== NULL
|| m_nDefaultPaletteNbEntry
!= nNbEntry
) {
235 delete[] m_pDefaultPalette
;
236 m_pDefaultPalette
= new HDMV_PALETTE
[nNbEntry
];
237 m_nDefaultPaletteNbEntry
= nNbEntry
;
239 memcpy (m_pDefaultPalette
, pPalette
, nNbEntry
*sizeof(HDMV_PALETTE
));
241 if (m_pCurrentObject
) {
242 m_pCurrentObject
->SetPalette (nNbEntry
, pPalette
, m_VideoDescriptor
.nVideoWidth
>720);
246 void CHdmvSub::ParseObject(CGolombBuffer
* pGBuffer
, USHORT nUnitSize
) // #498
248 SHORT object_id
= pGBuffer
->ReadShort();
249 UNUSED_ALWAYS(object_id
);
250 BYTE m_sequence_desc
;
252 ASSERT (m_pCurrentObject
!= NULL
);
253 if (m_pCurrentObject
) { // && m_pCurrentObject->m_object_id_ref == object_id)
254 m_pCurrentObject
->m_version_number
= pGBuffer
->ReadByte();
255 m_sequence_desc
= pGBuffer
->ReadByte();
257 if (m_sequence_desc
& 0x80) {
258 DWORD object_data_length
= (DWORD
)pGBuffer
->BitRead(24);
260 m_pCurrentObject
->m_width
= pGBuffer
->ReadShort();
261 m_pCurrentObject
->m_height
= pGBuffer
->ReadShort();
263 m_pCurrentObject
->SetRLEData (pGBuffer
->GetBufferPos(), nUnitSize
-11, object_data_length
-4);
265 TRACE_HDMVSUB ("CHdmvSub:NewObject size=%ld, total obj=%d, %dx%d\n", object_data_length
, m_pObjects
.GetCount(),
266 m_pCurrentObject
->m_width
, m_pCurrentObject
->m_height
);
268 m_pCurrentObject
->AppendRLEData (pGBuffer
->GetBufferPos(), nUnitSize
-4);
273 void CHdmvSub::ParseCompositionObject(CGolombBuffer
* pGBuffer
, CompositionObject
* pCompositionObject
)
276 pCompositionObject
->m_object_id_ref
= pGBuffer
->ReadShort();
277 pCompositionObject
->m_window_id_ref
= pGBuffer
->ReadByte();
278 bTemp
= pGBuffer
->ReadByte();
279 pCompositionObject
->m_object_cropped_flag
= !!(bTemp
& 0x80);
280 pCompositionObject
->m_forced_on_flag
= !!(bTemp
& 0x40);
281 pCompositionObject
->m_horizontal_position
= pGBuffer
->ReadShort();
282 pCompositionObject
->m_vertical_position
= pGBuffer
->ReadShort();
284 if (pCompositionObject
->m_object_cropped_flag
) {
285 pCompositionObject
->m_cropping_horizontal_position
= pGBuffer
->ReadShort();
286 pCompositionObject
->m_cropping_vertical_position
= pGBuffer
->ReadShort();
287 pCompositionObject
->m_cropping_width
= pGBuffer
->ReadShort();
288 pCompositionObject
->m_cropping_height
= pGBuffer
->ReadShort();
292 void CHdmvSub::ParseVideoDescriptor(CGolombBuffer
* pGBuffer
, VIDEO_DESCRIPTOR
* pVideoDescriptor
)
294 pVideoDescriptor
->nVideoWidth
= pGBuffer
->ReadShort();
295 pVideoDescriptor
->nVideoHeight
= pGBuffer
->ReadShort();
296 pVideoDescriptor
->bFrameRate
= pGBuffer
->ReadByte();
299 void CHdmvSub::ParseCompositionDescriptor(CGolombBuffer
* pGBuffer
, COMPOSITION_DESCRIPTOR
* pCompositionDescriptor
)
301 pCompositionDescriptor
->nNumber
= pGBuffer
->ReadShort();
302 pCompositionDescriptor
->bState
= pGBuffer
->ReadByte();
305 void CHdmvSub::Render(SubPicDesc
& spd
, REFERENCE_TIME rt
, RECT
& bbox
)
307 CompositionObject
* pObject
= FindObject (rt
);
309 ASSERT (pObject
!=NULL
&& spd
.w
>= (pObject
->m_horizontal_position
+ pObject
->m_width
) && spd
.h
>= (pObject
->m_vertical_position
+ pObject
->m_height
));
311 if (pObject
&& pObject
->GetRLEDataSize() && pObject
->m_width
> 0 && pObject
->m_height
> 0 &&
312 spd
.w
>= (pObject
->m_horizontal_position
+ pObject
->m_width
) &&
313 spd
.h
>= (pObject
->m_vertical_position
+ pObject
->m_height
)) {
314 if (!pObject
->HavePalette()) {
315 pObject
->SetPalette (m_nDefaultPaletteNbEntry
, m_pDefaultPalette
, m_VideoDescriptor
.nVideoWidth
>720);
318 TRACE_HDMVSUB ("CHdmvSub:Render size=%ld, ObjRes=%dx%d, SPDRes=%dx%d\n", pObject
->GetRLEDataSize(),
319 pObject
->m_width
, pObject
->m_height
, spd
.w
, spd
.h
);
320 pObject
->RenderHdmv(spd
);
322 bbox
.left
= pObject
->m_horizontal_position
;
323 bbox
.top
= pObject
->m_vertical_position
;
324 bbox
.right
= bbox
.left
+ pObject
->m_width
;
325 bbox
.bottom
= bbox
.top
+ pObject
->m_height
;
329 HRESULT
CHdmvSub::GetTextureSize (POSITION pos
, SIZE
& MaxTextureSize
, SIZE
& VideoSize
, POINT
& VideoTopLeft
)
331 CompositionObject
* pObject
= m_pObjects
.GetAt (pos
);
333 MaxTextureSize
.cx
= m_VideoDescriptor
.nVideoWidth
;
334 MaxTextureSize
.cy
= m_VideoDescriptor
.nVideoHeight
;
336 VideoSize
.cx
= m_VideoDescriptor
.nVideoWidth
;
337 VideoSize
.cy
= m_VideoDescriptor
.nVideoHeight
;
339 // The subs will be directly rendered into the proper position!
340 VideoTopLeft
.x
= 0; //pObject->m_horizontal_position;
341 VideoTopLeft
.y
= 0; //pObject->m_vertical_position;
351 void CHdmvSub::Reset()
353 CompositionObject
* pObject
;
354 while (m_pObjects
.GetCount() > 0) {
355 pObject
= m_pObjects
.RemoveHead();
360 CompositionObject
* CHdmvSub::FindObject(REFERENCE_TIME rt
)
362 POSITION pos
= m_pObjects
.GetHeadPosition();
365 CompositionObject
* pObject
= m_pObjects
.GetAt (pos
);
367 if (rt
>= pObject
->m_rtStart
&& rt
< pObject
->m_rtStop
) {
371 m_pObjects
.GetNext(pos
);