PageRenderTime 29ms CodeModel.GetById 8ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/cores/dvdplayer/DVDCodecs/Overlay/DVDOverlayCodecTX3G.cpp

http://github.com/xbmc/xbmc
C++ | 266 lines | 174 code | 34 blank | 58 comment | 40 complexity | 9a314a29fcb8121ec306cba4506bbc1c MD5 | raw file
  1/*
  2 *      Copyright (C) 2011-2013 Team XBMC
  3 *      http://xbmc.org
  4 *
  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)
  8 *  any later version.
  9 *
 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.
 14 *
 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/>.
 18 *
 19 */
 20
 21#include "system.h"
 22#include "DVDClock.h"
 23#include "DVDOverlayCodecTX3G.h"
 24#include "DVDOverlayText.h"
 25#include "DVDStreamInfo.h"
 26#include "DVDCodecs/DVDCodecs.h"
 27#include "settings/Settings.h"
 28#include "utils/log.h"
 29
 30// 3GPP/TX3G (aka MPEG-4 Timed Text) Subtitle support
 31// 3GPP -> 3rd Generation Partnership Program
 32// adapted from https://trac.handbrake.fr/browser/trunk/libhb/dectx3gsub.c;
 33
 34// NOTE: None of these macros check for buffer overflow
 35#define READ_U8()       *pos;                                                     pos += 1;
 36#define READ_U16()      (pos[0] << 8)  |  pos[1];                                 pos += 2;
 37#define READ_U32()      (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) | pos[3]; pos += 4;
 38#define READ_ARRAY(n)    pos;                                                     pos += n;
 39#define SKIP_ARRAY(n)    pos += n;
 40
 41#define FOURCC(str)  ((((uint32_t) str[0]) << 24) | \
 42                      (((uint32_t) str[1]) << 16) | \
 43                      (((uint32_t) str[2]) << 8) | \
 44                      (((uint32_t) str[3]) << 0))
 45                      
 46typedef enum {
 47 BOLD       = 0x1,
 48 ITALIC     = 0x2,
 49 UNDERLINE  = 0x4
 50} FaceStyleFlag;
 51
 52// NOTE: indices in terms of *character* (not: byte) positions
 53typedef struct {
 54  uint16_t  bgnChar;
 55  uint16_t  endChar;
 56  uint16_t  fontID;
 57  uint8_t   faceStyleFlags;  // FaceStyleFlag
 58  uint8_t   fontSize;
 59  uint32_t  textColorRGBA;
 60} StyleRecord;
 61
 62CDVDOverlayCodecTX3G::CDVDOverlayCodecTX3G() : CDVDOverlayCodec("TX3G Subtitle Decoder")
 63{
 64  m_pOverlay = NULL;
 65  // stupid, this comes from a static global in GUIWindowFullScreen.cpp
 66  uint32_t colormap[8] = { 0xFFFFFF00, 0xFFFFFFFF, 0xFF0099FF, 0xFF00FF00, 0xFFCCFF00, 0xFF00FFFF, 0xFFE5E5E5, 0xFFC0C0C0 };
 67  m_textColor = colormap[CSettings::Get().GetInt("subtitles.color")];
 68}
 69
 70CDVDOverlayCodecTX3G::~CDVDOverlayCodecTX3G()
 71{
 72  if (m_pOverlay)
 73    SAFE_RELEASE(m_pOverlay);
 74}
 75
 76bool CDVDOverlayCodecTX3G::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
 77{
 78  if (hints.codec == AV_CODEC_ID_MOV_TEXT)
 79    return true;
 80  return false;
 81}
 82
 83void CDVDOverlayCodecTX3G::Dispose()
 84{
 85  if (m_pOverlay)
 86    SAFE_RELEASE(m_pOverlay);
 87}
 88
 89int CDVDOverlayCodecTX3G::Decode(DemuxPacket *pPacket)
 90{
 91  if (m_pOverlay)
 92    SAFE_RELEASE(m_pOverlay);
 93
 94  uint8_t *data = pPacket->pData;
 95  int size = pPacket->iSize;
 96
 97  m_pOverlay = new CDVDOverlayText();
 98  CDVDOverlayCodec::GetAbsoluteTimes(m_pOverlay->iPTSStartTime, m_pOverlay->iPTSStopTime, pPacket, m_pOverlay->replace);
 99
100  // do not move this. READ_XXXX macros modify pos.
101  uint8_t  *pos = data;
102  uint8_t  *end = pos + size;
103
104  // Parse the packet as a TX3G TextSample.
105  // Look for a single StyleBox ('styl') and 
106  // read all contained StyleRecords.
107  // Ignore all other box types.
108  // NOTE: Buffer overflows on read are not checked.
109  // ALSO: READ_XXXX/SKIP_XXXX macros will modify pos.
110  uint16_t textLength = READ_U16();
111  uint8_t *text = READ_ARRAY(textLength);
112
113  int numStyleRecords = 0;
114  // reserve one more style slot for broken encoders
115  uint8_t *bgnStyle   = (uint8_t*)calloc(textLength+1, 1);
116  uint8_t *endStyle   = (uint8_t*)calloc(textLength+1, 1);
117  int bgnColorIndex = 0, endColorIndex = 0;
118  uint32_t textColorRGBA = m_textColor;
119  while (pos < end)
120  {
121    // Read TextSampleModifierBox
122    uint32_t size = READ_U32();
123    if (size == 0)
124      size = pos - end;   // extends to end of packet
125    if (size == 1)
126    {
127      CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: TextSampleModifierBox has unsupported large size" );
128      break;
129    }
130    uint32_t type = READ_U32();
131    if (type == FOURCC("uuid"))
132    {
133      CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: TextSampleModifierBox has unsupported extended type" );
134      break;
135    }
136
137    if (type == FOURCC("styl"))
138    {
139      // Found a StyleBox. Parse the contained StyleRecords
140      if ( numStyleRecords != 0 )
141      {
142        CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: found additional StyleBoxes on subtitle; skipping" );
143        SKIP_ARRAY(size);
144        continue;
145      }
146
147      numStyleRecords = READ_U16();
148      for (int i = 0; i < numStyleRecords; i++)
149      {
150        StyleRecord curRecord;
151        curRecord.bgnChar         = READ_U16();
152        curRecord.endChar         = READ_U16();
153        curRecord.fontID          = READ_U16();
154        curRecord.faceStyleFlags  = READ_U8();
155        curRecord.fontSize        = READ_U8();
156        curRecord.textColorRGBA   = READ_U32();
157        // clamp bgnChar/bgnChar to textLength,
158        // we alloc enough space above and this
159        // fixes borken encoders that do not handle
160        // endChar correctly.
161        if (curRecord.bgnChar > textLength)
162          curRecord.bgnChar = textLength;
163        if (curRecord.endChar > textLength)
164          curRecord.endChar = textLength;
165
166        bgnStyle[curRecord.bgnChar] |= curRecord.faceStyleFlags;
167        endStyle[curRecord.endChar] |= curRecord.faceStyleFlags;
168        bgnColorIndex = curRecord.bgnChar;
169        endColorIndex = curRecord.endChar;
170        textColorRGBA = curRecord.textColorRGBA;
171      }
172    }
173    else
174    {
175      // Found some other kind of TextSampleModifierBox. Skip it.
176      SKIP_ARRAY(size);
177    }
178  }
179
180  // Copy text to out and add HTML markup for the style records
181  int charIndex = 0;
182  CStdStringA strUTF8;
183  // index over textLength chars to include broken encoders,
184  // so we pickup closing styles on broken encoders
185  for (pos = text, end = text + textLength; pos <= end; pos++)
186  {
187    if ((*pos & 0xC0) == 0x80)
188    {
189      // Is a non-first byte of a multi-byte UTF-8 character
190      strUTF8.append((const char*)pos, 1);
191      continue;   // ...without incrementing 'charIndex'
192    }
193
194    uint8_t bgnStyles = bgnStyle[charIndex];
195    uint8_t endStyles = endStyle[charIndex];
196
197    // [B] or [/B] -> toggle bold on and off
198    // [I] or [/I] -> toggle italics on and off
199    // [COLOR ffab007f] or [/COLOR] -> toggle color on and off
200    // [CAPS <option>]  or [/CAPS]  -> toggle capatilization on and off
201
202    if (endStyles & BOLD)
203      strUTF8.append("[/B]");
204    if (endStyles & ITALIC)
205      strUTF8.append("[/I]");
206    // we do not support underline
207    //if (endStyles & UNDERLINE)
208    //  strUTF8.append("[/U]");
209    if (endColorIndex == charIndex && textColorRGBA != m_textColor)
210      strUTF8.append("[/COLOR]");
211
212    // invert the order from above so we bracket the text correctly.
213    if (bgnColorIndex == charIndex && textColorRGBA != m_textColor)
214      strUTF8.AppendFormat("[COLOR %8x]", textColorRGBA);
215    // we do not support underline
216    //if (bgnStyles & UNDERLINE)
217    //  strUTF8.append("[U]");
218    if (bgnStyles & ITALIC)
219      strUTF8.append("[I]");
220    if (bgnStyles & BOLD)
221      strUTF8.append("[B]");
222
223    // stuff the UTF8 char
224    strUTF8.append((const char*)pos, 1);
225
226    // this is a char index, not a byte index.
227    charIndex++;
228  }
229  
230  free(bgnStyle);
231  free(endStyle);
232    
233  if (strUTF8.IsEmpty())
234    return OC_BUFFER;
235
236  if (strUTF8[strUTF8.size()-1] == '\n')
237    strUTF8.Delete(strUTF8.size()-1);
238
239  // add a new text element to our container
240  m_pOverlay->AddElement(new CDVDOverlayText::CElementText(strUTF8.c_str()));
241
242  return OC_OVERLAY;
243}
244
245void CDVDOverlayCodecTX3G::Reset()
246{
247  if (m_pOverlay)
248    SAFE_RELEASE(m_pOverlay);
249}
250
251void CDVDOverlayCodecTX3G::Flush()
252{
253  if (m_pOverlay)
254    SAFE_RELEASE(m_pOverlay);
255}
256
257CDVDOverlay* CDVDOverlayCodecTX3G::GetOverlay()
258{
259  if (m_pOverlay)
260  {
261    CDVDOverlay* overlay = m_pOverlay;
262    m_pOverlay = NULL;
263    return overlay;
264  }
265  return NULL;
266}