Merge some MPC-HC Rev.3895 code to get HdmvSub and DVBSub support.
[xy_vsfilter.git] / src / subtitles / HdmvSub.cpp
blob7c246c4e89011b36d5ee957d9340ff8ab0654d6a
1 /*
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/>.
23 #include "stdafx.h"
24 #include "HdmvSub.h"
25 #include "../DSUtil/GolombBuffer.h"
27 #if (0) // Set to 1 to activate HDMV subtitles traces
28 #define TRACE_HDMVSUB TRACE
29 #else
30 #define TRACE_HDMVSUB
31 #endif
34 CHdmvSub::CHdmvSub(void)
35 : CBaseSub(ST_HDMV)
37 m_nColorNumber = 0;
39 m_nCurSegment = NO_SEGMENT;
40 m_pSegBuffer = NULL;
41 m_nTotalSegBuffer = 0;
42 m_nSegBufferPos = 0;
43 m_nSegSize = 0;
44 m_pCurrentObject = NULL;
45 m_pDefaultPalette = NULL;
46 m_nDefaultPaletteNbEntry = 0;
48 memset (&m_VideoDescriptor, 0, sizeof(VIDEO_DESCRIPTOR));
51 CHdmvSub::~CHdmvSub()
53 Reset();
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;
68 m_nSegBufferPos = 0;
69 m_nSegSize = nSize;
72 POSITION CHdmvSub::GetStartPosition(REFERENCE_TIME rt, double fps)
74 CompositionObject* pObject;
76 // Cleanup old PG
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();
83 delete pObject;
84 } else {
85 break;
89 return m_pObjects.GetHeadPosition();
92 HRESULT CHdmvSub::ParseSample(IMediaSample* pSample)
94 CheckPointer (pSample, E_POINTER);
95 HRESULT hr;
96 REFERENCE_TIME rtStart = INVALID_TIME, rtStop = INVALID_TIME;
97 BYTE* pData = NULL;
98 int lSampleLen;
100 hr = pSample->GetPointer(&pData);
101 if(FAILED(hr) || pData == NULL) {
102 return hr;
104 lSampleLen = pSample->GetActualDataLength();
106 pSample->GetTime(&rtStart, &rtStop);
107 if (pData) {
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();
114 lSampleLen -=3;
116 switch (nSegType) {
117 case PALETTE :
118 case OBJECT :
119 case PRESENTATION_SEG :
120 case END_OF_DISPLAY :
121 m_nCurSegment = nSegType;
122 AllocSegment (nUnitSize);
123 break;
125 case WINDOW_DEF :
126 case INTERACTIVE_SEG :
127 case HDMV_SUB1 :
128 case HDMV_SUB2 :
129 // Ignored stuff...
130 SampleBuffer.SkipBytes(nUnitSize);
131 break;
132 default :
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) {
148 case PALETTE :
149 TRACE_HDMVSUB ("CHdmvSub:PALETTE rtStart=%10I64d\n", rtStart);
150 ParsePalette(&SegmentBuffer, m_nSegSize);
151 break;
152 case OBJECT :
153 TRACE_HDMVSUB ("CHdmvSub:OBJECT %S\n", ReftimeToString(rtStart));
154 ParseObject(&SegmentBuffer, m_nSegSize);
155 break;
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--;
163 break;
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;
175 break;
176 case WINDOW_DEF :
177 // TRACE_HDMVSUB ("CHdmvSub:WINDOW_DEF %S\n", ReftimeToString(rtStart));
178 break;
179 case END_OF_DISPLAY :
180 // TRACE_HDMVSUB ("CHdmvSub:END_OF_DISPLAY %S\n", ReftimeToString(rtStart));
181 break;
182 default :
183 TRACE_HDMVSUB ("CHdmvSub:UNKNOWN Seg %d rtStart=0x%10dd\n", m_nCurSegment, rtStart);
186 m_nCurSegment = NO_SEGMENT;
192 return hr;
195 int CHdmvSub::ParsePresentationSegment(CGolombBuffer* pGBuffer)
197 COMPOSITION_DESCRIPTOR CompositionDescriptor;
198 BYTE nObjectNumber;
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
224 int nNbEntry;
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);
267 } else {
268 m_pCurrentObject->AppendRLEData (pGBuffer->GetBufferPos(), nUnitSize-4);
273 void CHdmvSub::ParseCompositionObject(CGolombBuffer* pGBuffer, CompositionObject* pCompositionObject)
275 BYTE bTemp;
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);
332 if (pObject) {
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;
343 return S_OK;
346 ASSERT (FALSE);
347 return E_INVALIDARG;
351 void CHdmvSub::Reset()
353 CompositionObject* pObject;
354 while (m_pObjects.GetCount() > 0) {
355 pObject = m_pObjects.RemoveHead();
356 delete pObject;
360 CompositionObject* CHdmvSub::FindObject(REFERENCE_TIME rt)
362 POSITION pos = m_pObjects.GetHeadPosition();
364 while (pos) {
365 CompositionObject* pObject = m_pObjects.GetAt (pos);
367 if (rt >= pObject->m_rtStart && rt < pObject->m_rtStop) {
368 return pObject;
371 m_pObjects.GetNext(pos);
374 return NULL;