2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "DVDDemuxSPU.h"
23 #include "utils/log.h"
26 #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1))
30 void DebugLog(const char *format, ...)
33 static char temp_spubuffer[1024];
37 _vsnprintf(temp_spubuffer, 1024, format, va);
40 CLog::Log(LOGDEBUG,temp_spubuffer);
44 CDVDDemuxSPU::CDVDDemuxSPU()
46 memset(&m_spuData, 0, sizeof(m_spuData));
47 memset(m_clut, 0, sizeof(m_clut));
51 CDVDDemuxSPU::~CDVDDemuxSPU()
53 if (m_spuData.data) free(m_spuData.data);
56 void CDVDDemuxSPU::Reset()
60 // We can't reset this during playback, cause we don't always
61 // get a new clut from libdvdnav leading to invalid colors
62 // so let's just never reset it. It will only be reset
63 // when dvdplayer is destructed and constructed
64 // m_bHasClut = false;
65 // memset(m_clut, 0, sizeof(m_clut));
68 void CDVDDemuxSPU::FlushCurrentPacket()
70 if (m_spuData.data) free(m_spuData.data);
71 memset(&m_spuData, 0, sizeof(m_spuData));
74 CDVDOverlaySpu* CDVDDemuxSPU::AddData(BYTE* data, int iSize, double pts)
76 SPUData* pSPUData = &m_spuData;
78 if (pSPUData->iNeededSize > 0 &&
79 (pSPUData->iSize != pSPUData->iNeededSize) &&
80 ((pSPUData->iSize + iSize) > pSPUData->iNeededSize))
82 DebugLog("corrupt spu data: packet does not fit");
83 m_spuData.iNeededSize = 0;
88 // check if we are about to start a new packet
89 if (pSPUData->iSize == pSPUData->iNeededSize)
91 // for now we don't delete the memory assosiated with m_spuData.data
94 // check spu data lenght, only needed / possible in the first spu pakcet
95 unsigned __int16 length = data[0] << 8 | data[1];
98 DebugLog("corrupt spu data: zero packet");
99 m_spuData.iNeededSize = 0;
103 if (length > iSize) pSPUData->iNeededSize = length;
104 else pSPUData->iNeededSize = iSize;
106 // set presentation time stamp
107 if (pts > 0) pSPUData->pts = pts;
110 // allocate data if not already done ( done in blocks off 16384 bytes )
111 // or allocate some more if 16384 bytes is not enough
112 if((pSPUData->iSize + iSize) > pSPUData->iAllocatedSize)
113 pSPUData->data = (BYTE*)realloc(pSPUData->data, ALIGN(pSPUData->iSize + iSize, 0x4000));
116 return NULL; // crap realloc failed, this will have leaked some memory due to odd realloc
119 memcpy(pSPUData->data + pSPUData->iSize, data, iSize);
120 pSPUData->iSize += iSize;
122 if (pSPUData->iNeededSize - pSPUData->iSize == 1) // to make it even
124 DebugLog("missing 1 byte to complete packet, adding 0xff");
126 pSPUData->data[pSPUData->iSize] = 0xff;
130 if (pSPUData->iSize == pSPUData->iNeededSize)
132 DebugLog("got complete spu packet\n length: %i bytes\n stream: %i\n", pSPUData->iSize);
134 return ParsePacket(pSPUData);
141 #define FSTA_DSP 0x00
144 #define SET_COLOR 0x03
145 #define SET_CONTR 0x04
146 #define SET_DAREA 0x05
147 #define SET_DSPXA 0x06
148 #define CHG_COLCON 0x07
150 CDVDOverlaySpu* CDVDDemuxSPU::ParsePacket(SPUData* pSPUData)
152 unsigned int alpha[4];
153 BYTE* pUnparsedData = NULL;
155 if (pSPUData->iNeededSize != pSPUData->iSize)
157 DebugLog("GetPacket, packet is incomplete, missing: %i bytes", (pSPUData->iNeededSize - pSPUData->iSize));
160 if (pSPUData->data[pSPUData->iSize - 1] != 0xff)
162 DebugLog("GetPacket, missing end of data 0xff");
165 CDVDOverlaySpu* pSPUInfo = new CDVDOverlaySpu();
166 BYTE* p = pSPUData->data; // pointer to walk through all data
169 unsigned __int16 datalength = p[2] << 8 | p[3]; // datalength + 4 control bytes
171 pUnparsedData = pSPUData->data + 4;
173 // if it is set to 0 it means it's a menu overlay by defualt
174 // this is not what we want too, cause you get strange results on a parse error
175 pSPUInfo->iPTSStartTime = -1;
177 //skip data packet and goto control sequence
180 bool bHasNewDCSQ = true;
183 DebugLog(" starting new SP_DCSQT");
184 // p is beginning of first SP_DCSQT now
185 unsigned __int16 delay = p[0] << 8 | p[1];
186 unsigned __int16 next_DCSQ = p[2] << 8 | p[3];
188 //offset within the Sub-Picture Unit to the next SP_DCSQ. If this is the last SP_DCSQ, it points to itself.
189 bHasNewDCSQ = ((pSPUData->data + next_DCSQ) != p);
193 while (*p != CMD_END && (unsigned int)(p - pSPUData->data) <= pSPUData->iSize)
199 DebugLog(" GetPacket, FSTA_DSP: Forced Start Display, no arguments");
200 pSPUInfo->iPTSStartTime = pSPUData->pts;
201 pSPUInfo->iPTSStopTime = 0x9000000000000LL;
202 pSPUInfo->bForced = true;
203 // delay is always 0, the dvdplayer should decide when to display the packet (menu highlight)
208 pSPUInfo->iPTSStartTime = pSPUData->pts;
209 pSPUInfo->iPTSStartTime += (double)delay * 1024 * DVD_TIME_BASE / 90000;
210 DebugLog(" GetPacket, STA_DSP: Start Display, delay: %i", ((delay * 1024) / 90000));
216 pSPUInfo->iPTSStopTime = pSPUData->pts;
217 pSPUInfo->iPTSStopTime += (double)delay * 1024 * DVD_TIME_BASE / 90000;
218 DebugLog(" GetPacket, STP_DSP: Stop Display, delay: %i", ((delay * 1024) / 90000));
227 pSPUInfo->bHasColor = true;
231 idx[0] = (p[0] >> 4) & 0x0f;
232 idx[1] = (p[0]) & 0x0f;
233 idx[2] = (p[1] >> 4) & 0x0f;
234 idx[3] = (p[1]) & 0x0f;
236 for (int i = 0; i < 4 ; i++) // emphasis 1, emphasis 2, pattern, back ground
238 BYTE* iColor = m_clut[idx[i]];
240 pSPUInfo->color[3 - i][0] = iColor[0]; // Y
241 pSPUInfo->color[3 - i][1] = iColor[1]; // Cr
242 pSPUInfo->color[3 - i][2] = iColor[2]; // Cb
246 DebugLog(" GetPacket, SET_COLOR:");
250 case SET_CONTR: // alpha
254 alpha[0] = (p[0] >> 4) & 0x0f;
255 alpha[1] = (p[0]) & 0x0f;
256 alpha[2] = (p[1] >> 4) & 0x0f;
257 alpha[3] = (p[1]) & 0x0f;
259 // Ignore blank alpha palette.
260 if (alpha[0] | alpha[1] | alpha[2] | alpha[3])
262 pSPUInfo->bHasAlpha = true;
265 pSPUInfo->alpha[0] = alpha[3]; //0 // background, should be hidden
266 pSPUInfo->alpha[1] = alpha[2]; //1
267 pSPUInfo->alpha[2] = alpha[1]; //2 // wm button overlay
268 pSPUInfo->alpha[3] = alpha[0]; //3
271 DebugLog(" GetPacket, SET_CONTR:");
278 pSPUInfo->x = (p[0] << 4) | (p[1] >> 4);
279 pSPUInfo->y = (p[3] << 4) | (p[4] >> 4);
280 pSPUInfo->width = (((p[1] & 0x0f) << 8) | p[2]) - pSPUInfo->x + 1;
281 pSPUInfo->height = (((p[4] & 0x0f) << 8) | p[5]) - pSPUInfo->y + 1;
282 DebugLog(" GetPacket, SET_DAREA: x,y:%i,%i width,height:%i,%i",
283 pSPUInfo->x, pSPUInfo->y, pSPUInfo->width, pSPUInfo->height);
290 unsigned __int16 tfaddr = (p[0] << 8 | p[1]); // offset in packet
291 unsigned __int16 bfaddr = (p[2] << 8 | p[3]); // offset in packet
292 pSPUInfo->pTFData = (tfaddr - 4); //pSPUInfo->pData + (tfaddr - 4); // pSPUData->data = packet startaddr - 4
293 pSPUInfo->pBFData = (bfaddr - 4); //pSPUInfo->pData + (bfaddr - 4); // pSPUData->data = packet startaddr - 4
295 DebugLog(" GetPacket, SET_DSPXA: tf: %i bf: %i ", tfaddr, bfaddr);
301 unsigned __int16 paramlength = p[0] << 8 | p[1];
302 DebugLog("GetPacket, CHG_COLCON, skippin %i bytes", paramlength);
308 DebugLog("GetPacket, error parsing control sequence");
314 DebugLog(" end off SP_DCSQT");
315 if (*p == CMD_END) p++;
318 DebugLog("GetPacket, end off SP_DCSQT, but did not found 0xff (CMD_END)");
323 // this should be chnaged so it get's converted to a yuv overlay
324 return ParseRLE(pSPUInfo, pUnparsedData);
327 /*****************************************************************************
328 * AddNibble: read a nibble from a source packet and add it to our integer.
329 *****************************************************************************/
330 inline unsigned int AddNibble( unsigned int i_code, BYTE* p_src, unsigned int* pi_index )
332 if ( *pi_index & 0x1 )
334 return ( i_code << 4 | ( p_src[(*pi_index)++ >> 1] & 0xf ) );
338 return ( i_code << 4 | p_src[(*pi_index)++ >> 1] >> 4 );
342 /*****************************************************************************
343 * ParseRLE: parse the RLE part of the subtitle
344 *****************************************************************************
345 * This part parses the subtitle graphical data and stores it in a more
346 * convenient structure for later decoding. For more information on the
347 * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
348 *****************************************************************************/
349 CDVDOverlaySpu* CDVDDemuxSPU::ParseRLE(CDVDOverlaySpu* pSPU, BYTE* pUnparsedData)
351 BYTE* p_src = pUnparsedData;
353 unsigned int i_code = 0;
355 unsigned int i_width = pSPU->width;
356 unsigned int i_height = pSPU->height;
357 unsigned int i_x, i_y;
359 // allocate a buffer for the result
360 unsigned __int16* p_dest = (unsigned __int16*)pSPU->result;
362 /* The subtitles are interlaced, we need two offsets */
363 unsigned int i_id = 0; /* Start on the even SPU layer */
364 unsigned int pi_table[2];
365 unsigned int *pi_offset;
367 /* Colormap statistics */
369 int stats[4]; stats[0] = stats[1] = stats[2] = stats[3] = 0;
371 pi_table[ 0 ] = pSPU->pTFData << 1;
372 pi_table[ 1 ] = pSPU->pBFData << 1;
374 for ( i_y = 0 ; i_y < i_height ; i_y++ )
376 pi_offset = pi_table + i_id;
378 for ( i_x = 0 ; i_x < i_width ; i_x += i_code >> 2 )
380 i_code = AddNibble( 0, p_src, pi_offset );
384 i_code = AddNibble( i_code, p_src, pi_offset );
388 i_code = AddNibble( i_code, p_src, pi_offset );
390 if ( i_code < 0x040 )
392 i_code = AddNibble( i_code, p_src, pi_offset );
394 if ( i_code < 0x0100 )
396 /* If the 14 first bits are set to 0, then it's a
397 * new line. We emulate it. */
398 if ( i_code < 0x0004 )
400 i_code |= ( i_width - i_x ) << 2;
404 /* We have a boo boo ! */
405 CLog::Log(LOGERROR, "ParseRLE: unknown RLE code 0x%.4x", i_code);
413 if ( ( (i_code >> 2) + i_x + i_y * i_width ) > i_height * i_width )
415 CLog::Log(LOGERROR, "ParseRLE: out of bounds, %i at (%i,%i) is out of %ix%i",
416 i_code >> 2, i_x, i_y, i_width, i_height );
420 // keep trace of all occouring pixels, even keeping the background in mind
421 stats[i_code & 0x3] += i_code >> 2;
423 // count the number of pixels for every occouring parts, without background
424 if (pSPU->alpha[i_code & 0x3] != 0x00)
426 // the last non background pixel is probably the border color
427 i_border = i_code & 0x3;
428 stats[i_border] += i_code >> 2;
431 /* Check we aren't overwriting our data range
432 This occurs on "The Triplets of BelleVille" region 4 disk (NTSC)"
433 where we use around 96k rather than 64k + 20bytes */
434 if ((BYTE *)p_dest >= pSPU->result + sizeof(pSPU->result))
436 CLog::Log(LOGERROR, "ParseRLE: Overrunning our data range. Need %li bytes", (long)((BYTE *)p_dest - pSPU->result));
442 /* Check that we didn't go too far */
445 CLog::Log(LOGERROR, "ParseRLE: i_x overflowed, %i > %i", i_x, i_width );
449 /* Byte-align the stream */
450 if ( *pi_offset & 0x1 )
459 /* We shouldn't get any padding bytes */
460 if ( i_y < i_height )
462 DebugLog("ParseRLE: padding bytes found in RLE sequence" );
463 DebugLog("ParseRLE: send mail to <sam@zoy.org> if you want to help debugging this" );
465 /* Skip them just in case */
466 while ( i_y < i_height )
468 /* Check we aren't overwriting our data range
469 This occurs on "The Triplets of BelleVille" region 4 disk (NTSC)"
470 where we use around 96k rather than 64k + 20bytes */
471 if ((BYTE *)p_dest >= pSPU->result + sizeof(pSPU->result))
473 CLog::Log(LOGERROR, "ParseRLE: Overrunning our data range. Need %li bytes", (long)((BYTE *)p_dest - pSPU->result));
476 *p_dest++ = i_width << 2;
483 DebugLog("ParseRLE: valid subtitle, size: %ix%i, position: %i,%i",
484 pSPU->width, pSPU->height, pSPU->x, pSPU->y );
486 // forced spu's (menu overlays) retrieve their alpha/color information from InputStreamNavigator::GetCurrentButtonInfo
487 // also they may contain completely covering data wich is supposed to be hidden normally
488 // since whole spu is drawn, if this is done for forced, that may be displayed
489 // so we must trust what is given
492 // Handle color if no palette was found.
493 // we only set it if there is a valid i_border color
494 if (!pSPU->bHasColor)
496 CLog::Log(LOGINFO, "%s - no color palette found, using default", __FUNCTION__);
497 FindSubtitleColor(i_border, stats, pSPU);
500 // check alpha values, for non forced spu's we use a default value
503 // check alpha values
504 // the array stats represents the nr of pixels for each color channel
505 // thus if there are no pixels to display, we assume the alphas are incorrect.
506 if (!CanDisplayWithAlphas(pSPU->alpha, stats))
508 CLog::Log(LOGINFO, "%s - no matching color and alpha found, resetting alpha", __FUNCTION__);
510 pSPU->alpha[0] = 0x00; // back ground
511 pSPU->alpha[1] = 0x0f;
512 pSPU->alpha[2] = 0x0f;
513 pSPU->alpha[3] = 0x0f;
518 CLog::Log(LOGINFO, "%s - ignoring blank alpha palette, using default", __FUNCTION__);
520 pSPU->alpha[0] = 0x00; // back ground
521 pSPU->alpha[1] = 0x0f;
522 pSPU->alpha[2] = 0x0f;
523 pSPU->alpha[3] = 0x0f;
531 void CDVDDemuxSPU::FindSubtitleColor(int last_color, int stats[4], CDVDOverlaySpu* pSPU)
533 const int COLOR_INNER = 0;
534 const int COLOR_SHADE = 1;
535 const int COLOR_BORDER = 2;
537 //BYTE custom_subtitle_color[4][3] = { // blue, yellow and something else (xine)
538 // { 0x80, 0x90, 0x80 }, // inner color
539 // { 0x00, 0x90, 0x00 }, // shade color
540 // { 0x00, 0x90, 0xff } // border color
543 BYTE custom_subtitle_color[4][3] = { // inner color white, gray shading and a black border
544 { 0xff, 0x80, 0x80 }, // inner color, white
545 { 0x80, 0x80, 0x80 }, // shade color, gray
546 { 0x00, 0x80, 0x80 } // border color, black
549 //BYTE custom_subtitle_color[4][3] = { // completely white and a black border
550 // { 0xff, 0x80, 0x80 }, // inner color, white
551 // { 0xff, 0x80, 0x80 }, // shade color, white
552 // { 0x00, 0x80, 0x80 } // border color, black
556 int nrOfUsedColors = 0;
557 for (int i = 0; i < 4; i++)
559 if (pSPU->alpha[i] > 0) nrOfUsedColors++;
562 if (nrOfUsedColors == 0)
565 DebugLog("FindSubtitleColor: all 4 alpha channels are 0, nothing todo");
567 else if (nrOfUsedColors == 1)
569 // only one color is used, probably the inner color
570 for (int i = 0; i < 4; i++) // find the position that is used
572 if (pSPU->alpha[i] > 0)
574 pSPU->color[i][0] = custom_subtitle_color[COLOR_INNER][0]; // Y
575 pSPU->color[i][1] = custom_subtitle_color[COLOR_INNER][1]; // Cr ?
576 pSPU->color[i][2] = custom_subtitle_color[COLOR_INNER][2]; // Cb ?
585 int i, i_inner = -1, i_shade = -1;
587 if (last_color >= 0 && last_color < 4)
589 // Set the border color, the last color is probably the border color
590 pSPU->color[last_color][0] = custom_subtitle_color[COLOR_BORDER][0];
591 pSPU->color[last_color][1] = custom_subtitle_color[COLOR_BORDER][1];
592 pSPU->color[last_color][2] = custom_subtitle_color[COLOR_BORDER][2];
593 stats[last_color] = 0;
595 // find the inner colors
596 for ( i = 0 ; i < 4 && i_inner == -1 ; i++ )
604 // try to find the shade color
605 for ( ; i < 4 && i_shade == -1 ; i++)
609 if ( stats[i] > stats[i_inner] )
621 /* Set the inner color */
625 pSPU->color[i_inner][0] = custom_subtitle_color[COLOR_INNER][0]; // Y
626 pSPU->color[i_inner][1] = custom_subtitle_color[COLOR_INNER][1]; // Cr ?
627 pSPU->color[i_inner][2] = custom_subtitle_color[COLOR_INNER][2]; // Cb ?
630 /* Set the anti-aliasing color */
634 pSPU->color[i_shade][0] = custom_subtitle_color[COLOR_SHADE][0];
635 pSPU->color[i_shade][1] = custom_subtitle_color[COLOR_SHADE][1];
636 pSPU->color[i_shade][2] = custom_subtitle_color[COLOR_SHADE][2];
639 DebugLog("ParseRLE: using custom palette (border %i, inner %i, shade %i)", last_color, i_inner, i_shade);
644 bool CDVDDemuxSPU::CanDisplayWithAlphas(int a[4], int stats[4])
647 a[0] * stats[0] > 0 ||
648 a[1] * stats[1] > 0 ||
649 a[2] * stats[2] > 0 ||
650 a[3] * stats[3] > 0);