Fix some log error.(Now the trace function works and only works in Unicode compile)
[xy_vsfilter.git] / src / subtitles / HdmvSub.cpp
bloba1194d780ccca3d20d8c9f82c49fec690e58fcea
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 (1) // 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;
88 return m_pObjects.GetHeadPosition();
91 HRESULT CHdmvSub::ParseSample(IMediaSample* pSample)
93 CheckPointer (pSample, E_POINTER);
94 HRESULT hr;
95 REFERENCE_TIME rtStart = INVALID_TIME, rtStop = INVALID_TIME;
96 BYTE* pData = NULL;
97 int lSampleLen;
99 hr = pSample->GetPointer(&pData);
100 if(FAILED(hr) || pData == NULL) {
101 return hr;
103 lSampleLen = pSample->GetActualDataLength();
105 pSample->GetTime(&rtStart, &rtStop);
106 if (pData) {
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();
113 lSampleLen -=3;
115 switch (nSegType) {
116 case PALETTE :
117 case OBJECT :
118 case PRESENTATION_SEG :
119 case END_OF_DISPLAY :
120 m_nCurSegment = nSegType;
121 AllocSegment (nUnitSize);
122 break;
124 case WINDOW_DEF :
125 case INTERACTIVE_SEG :
126 case HDMV_SUB1 :
127 case HDMV_SUB2 :
128 // Ignored stuff...
129 SampleBuffer.SkipBytes(nUnitSize);
130 break;
131 default :
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) {
147 case PALETTE :
148 TRACE_HDMVSUB( (_T("CHdmvSub:PALETTE rtStart=%10I64d\n"), rtStart));
149 ParsePalette(&SegmentBuffer, m_nSegSize);
150 break;
151 case OBJECT :
152 TRACE_HDMVSUB( (_T("CHdmvSub:OBJECT %lS\n"), ReftimeToCString(rtStart)));
153 ParseObject(&SegmentBuffer, m_nSegSize);
154 break;
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--;
162 break;
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;
174 break;
175 case WINDOW_DEF :
176 // TRACE_HDMVSUB( (_T("CHdmvSub:WINDOW_DEF %S\n", ReftimeToCString(rtStart));
177 break;
178 case END_OF_DISPLAY :
179 // TRACE_HDMVSUB( (_T("CHdmvSub:END_OF_DISPLAY %S\n", ReftimeToCString(rtStart));
180 break;
181 default :
182 TRACE_HDMVSUB( (_T("CHdmvSub:UNKNOWN Seg %d rtStart=0x%10dd\n"), m_nCurSegment, rtStart));
185 m_nCurSegment = NO_SEGMENT;
191 return hr;
194 int CHdmvSub::ParsePresentationSegment(CGolombBuffer* pGBuffer)
196 COMPOSITION_DESCRIPTOR CompositionDescriptor;
197 BYTE nObjectNumber;
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
223 int nNbEntry;
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));
266 } else {
267 m_pCurrentObject->AppendRLEData (pGBuffer->GetBufferPos(), nUnitSize-4);
272 void CHdmvSub::ParseCompositionObject(CGolombBuffer* pGBuffer, CompositionObject* pCompositionObject)
274 BYTE bTemp;
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);
331 if (pObject) {
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;
342 return S_OK;
345 ASSERT (FALSE);
346 return E_INVALIDARG;
350 void CHdmvSub::Reset()
352 CompositionObject* pObject;
353 while (m_pObjects.GetCount() > 0) {
354 pObject = m_pObjects.RemoveHead();
355 delete pObject;
359 CompositionObject* CHdmvSub::FindObject(REFERENCE_TIME rt)
361 POSITION pos = m_pObjects.GetHeadPosition();
363 while (pos) {
364 CompositionObject* pObject = m_pObjects.GetAt (pos);
366 if (rt >= pObject->m_rtStart && rt < pObject->m_rtStop) {
367 return pObject;
370 m_pObjects.GetNext(pos);
373 return NULL;