Disable HdmvSub log.
[xy_vsfilter.git] / src / subtitles / HdmvSub.cpp
blobf323766a82b7030fb558259d53014ea50ee8b553
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(_x_) {CString tmp;tmp.Format _x_; XY_LOG_INFO( tmp.GetString() );}
29 #else
30 #define TRACE_HDMVSUB(_x_)
31 #endif
33 CHdmvSub::CHdmvSub(void)
34 : CBaseSub(ST_HDMV)
36 m_nColorNumber = 0;
38 m_nCurSegment = NO_SEGMENT;
39 m_pSegBuffer = NULL;
40 m_nTotalSegBuffer = 0;
41 m_nSegBufferPos = 0;
42 m_nSegSize = 0;
43 m_pCurrentObject = NULL;
44 m_pDefaultPalette = NULL;
45 m_nDefaultPaletteNbEntry = 0;
47 memset (&m_VideoDescriptor, 0, sizeof(VIDEO_DESCRIPTOR));
50 CHdmvSub::~CHdmvSub()
52 Reset();
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;
67 m_nSegBufferPos = 0;
68 m_nSegSize = nSize;
71 POSITION CHdmvSub::GetStartPosition(REFERENCE_TIME rt, double fps)
73 CompositionObject* pObject;
74 TRACE_HDMVSUB( (_T("CHdmvSub:GetStartPosition rt=%lS\n"), ReftimeToCString(rt)) );
75 // Cleanup old PG
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();
82 delete pObject;
83 } else {
84 break;
87 // log first 2 objects
88 // {
89 // POSITION pos = m_pObjects.GetHeadPosition();
90 // for (int i=0;i<2 && pos!=NULL; i++)
91 // {
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)));
95 // }
96 // }
98 POSITION pos = m_pObjects.GetHeadPosition();
100 while (pos) {
101 CompositionObject* pObject = m_pObjects.GetAt (pos);
103 if (rt >= pObject->m_rtStart && rt < pObject->m_rtStop) {
104 break;
106 else if( rt < pObject->m_rtStart )
108 pos = NULL;
109 break;
112 m_pObjects.GetNext(pos);
114 return pos;
117 HRESULT CHdmvSub::ParseSample(IMediaSample* pSample)
119 CheckPointer (pSample, E_POINTER);
120 HRESULT hr;
121 REFERENCE_TIME rtStart = INVALID_TIME, rtStop = INVALID_TIME;
122 BYTE* pData = NULL;
123 int lSampleLen;
125 hr = pSample->GetPointer(&pData);
126 if(FAILED(hr) || pData == NULL) {
127 return hr;
129 lSampleLen = pSample->GetActualDataLength();
131 pSample->GetTime(&rtStart, &rtStop);
132 if (pData) {
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();
139 lSampleLen -=3;
141 switch (nSegType) {
142 case PALETTE :
143 case OBJECT :
144 case PRESENTATION_SEG :
145 case END_OF_DISPLAY :
146 m_nCurSegment = nSegType;
147 AllocSegment (nUnitSize);
148 break;
150 case WINDOW_DEF :
151 case INTERACTIVE_SEG :
152 case HDMV_SUB1 :
153 case HDMV_SUB2 :
154 // Ignored stuff...
155 SampleBuffer.SkipBytes(nUnitSize);
156 break;
157 default :
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) {
173 case PALETTE :
174 TRACE_HDMVSUB( (_T("CHdmvSub:PALETTE rtStart=%10I64d\n"), rtStart));
175 ParsePalette(&SegmentBuffer, m_nSegSize);
176 break;
177 case OBJECT :
178 TRACE_HDMVSUB( (_T("CHdmvSub:OBJECT %lS\n"), ReftimeToCString(rtStart)));
179 ParseObject(&SegmentBuffer, m_nSegSize);
180 break;
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--;
188 break;
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;
200 break;
201 case WINDOW_DEF :
202 // TRACE_HDMVSUB( (_T("CHdmvSub:WINDOW_DEF %S\n", ReftimeToCString(rtStart));
203 break;
204 case END_OF_DISPLAY :
205 // TRACE_HDMVSUB( (_T("CHdmvSub:END_OF_DISPLAY %S\n", ReftimeToCString(rtStart));
206 break;
207 default :
208 TRACE_HDMVSUB( (_T("CHdmvSub:UNKNOWN Seg %d rtStart=0x%10dd\n"), m_nCurSegment, rtStart));
211 m_nCurSegment = NO_SEGMENT;
217 return hr;
220 int CHdmvSub::ParsePresentationSegment(CGolombBuffer* pGBuffer)
222 COMPOSITION_DESCRIPTOR CompositionDescriptor;
223 BYTE nObjectNumber;
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
249 int nNbEntry;
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));
292 } else {
293 m_pCurrentObject->AppendRLEData (pGBuffer->GetBufferPos(), nUnitSize-4);
298 void CHdmvSub::ParseCompositionObject(CGolombBuffer* pGBuffer, CompositionObject* pCompositionObject)
300 BYTE bTemp;
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);
357 if (pObject) {
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;
368 return S_OK;
371 ASSERT (FALSE);
372 return E_INVALIDARG;
376 void CHdmvSub::Reset()
378 CompositionObject* pObject;
379 while (m_pObjects.GetCount() > 0) {
380 pObject = m_pObjects.RemoveHead();
381 delete pObject;
385 CompositionObject* CHdmvSub::FindObject(REFERENCE_TIME rt)
387 POSITION pos = m_pObjects.GetHeadPosition();
389 while (pos) {
390 CompositionObject* pObject = m_pObjects.GetAt (pos);
392 if (rt >= pObject->m_rtStart && rt < pObject->m_rtStop) {
393 return pObject;
396 m_pObjects.GetNext(pos);
399 return NULL;