Example #1
0
int CDVDOverlayCodecTX3G::Decode(DemuxPacket *pPacket)
{
  if (m_pOverlay)
    SAFE_RELEASE(m_pOverlay);

  m_pOverlay = new CDVDOverlayText();
  CDVDOverlayCodec::GetAbsoluteTimes(m_pOverlay->iPTSStartTime, m_pOverlay->iPTSStopTime, pPacket, m_pOverlay->replace);

  // do not move this. READ_XXXX macros modify pos.
  uint8_t  *pos = pPacket->pData;
  uint8_t  *end = pPacket->pData + pPacket->iSize;

  // Parse the packet as a TX3G TextSample.
  // Look for a single StyleBox ('styl') and 
  // read all contained StyleRecords.
  // Ignore all other box types.
  // NOTE: Buffer overflows on read are not checked.
  // ALSO: READ_XXXX/SKIP_XXXX macros will modify pos.
  LEN_CHECK(2);
  uint16_t textLength = READ_U16();
  LEN_CHECK(textLength);
  uint8_t *text = READ_ARRAY(textLength);

  int numStyleRecords = 0;
  // reserve one more style slot for broken encoders

  XUTILS::auto_buffer bgnStyle(textLength+1);
  XUTILS::auto_buffer endStyle(textLength+1);

  memset(bgnStyle.get(), 0, textLength+1);
  memset(endStyle.get(), 0, textLength+1);

  int bgnColorIndex = 0, endColorIndex = 0;
  uint32_t textColorRGBA = m_textColor;
  while (pos < end)
  {
    // Read TextSampleModifierBox
    LEN_CHECK(4);
    uint32_t size = READ_U32();
    if (size == 0)
      size = pos - end;   // extends to end of packet
    if (size == 1)
    {
      CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: TextSampleModifierBox has unsupported large size" );
      break;
    }
    LEN_CHECK(4);
    uint32_t type = READ_U32();
    if (type == FOURCC("uuid"))
    {
      CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: TextSampleModifierBox has unsupported extended type" );
      break;
    }

    if (type == FOURCC("styl"))
    {
      // Found a StyleBox. Parse the contained StyleRecords
      if ( numStyleRecords != 0 )
      {
        CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: found additional StyleBoxes on subtitle; skipping" );
        LEN_CHECK(size);
        SKIP_ARRAY(size);
        continue;
      }

      LEN_CHECK(2);
      numStyleRecords = READ_U16();
      for (int i = 0; i < numStyleRecords; i++)
      {
        StyleRecord curRecord;
        LEN_CHECK(12);
        curRecord.bgnChar         = READ_U16();
        curRecord.endChar         = READ_U16();
        curRecord.fontID          = READ_U16();
        curRecord.faceStyleFlags  = READ_U8();
        curRecord.fontSize        = READ_U8();
        curRecord.textColorRGBA   = READ_U32();
        // clamp bgnChar/bgnChar to textLength,
        // we alloc enough space above and this
        // fixes borken encoders that do not handle
        // endChar correctly.
        if (curRecord.bgnChar > textLength)
          curRecord.bgnChar = textLength;
        if (curRecord.endChar > textLength)
          curRecord.endChar = textLength;

        bgnStyle.get()[curRecord.bgnChar] |= curRecord.faceStyleFlags;
        endStyle.get()[curRecord.endChar] |= curRecord.faceStyleFlags;
        bgnColorIndex = curRecord.bgnChar;
        endColorIndex = curRecord.endChar;
        textColorRGBA = curRecord.textColorRGBA;
      }
    }
    else
    {
      // Found some other kind of TextSampleModifierBox. Skip it.
      LEN_CHECK(size);
      SKIP_ARRAY(size);
    }
  }

  // Copy text to out and add HTML markup for the style records
  int charIndex = 0;
  std::string strUTF8;
  // index over textLength chars to include broken encoders,
  // so we pickup closing styles on broken encoders
  for (pos = text, end = text + textLength; pos <= end; pos++)
  {
    if ((*pos & 0xC0) == 0x80)
    {
      // Is a non-first byte of a multi-byte UTF-8 character
      strUTF8.append((const char*)pos, 1);
      continue;   // ...without incrementing 'charIndex'
    }

    uint8_t bgnStyles = bgnStyle.get()[charIndex];
    uint8_t endStyles = endStyle.get()[charIndex];

    // [B] or [/B] -> toggle bold on and off
    // [I] or [/I] -> toggle italics on and off
    // [COLOR ffab007f] or [/COLOR] -> toggle color on and off
    // [CAPS <option>]  or [/CAPS]  -> toggle capatilization on and off

    if (endStyles & BOLD)
      strUTF8.append("[/B]");
    if (endStyles & ITALIC)
      strUTF8.append("[/I]");
    // we do not support underline
    //if (endStyles & UNDERLINE)
    //  strUTF8.append("[/U]");
    if (endColorIndex == charIndex && textColorRGBA != m_textColor)
      strUTF8.append("[/COLOR]");

    // invert the order from above so we bracket the text correctly.
    if (bgnColorIndex == charIndex && textColorRGBA != m_textColor)
      strUTF8 += StringUtils::Format("[COLOR %8x]", textColorRGBA);
    // we do not support underline
    //if (bgnStyles & UNDERLINE)
    //  strUTF8.append("[U]");
    if (bgnStyles & ITALIC)
      strUTF8.append("[I]");
    if (bgnStyles & BOLD)
      strUTF8.append("[B]");

    // stuff the UTF8 char
    strUTF8.append((const char*)pos, 1);

    // this is a char index, not a byte index.
    charIndex++;
  }
  
  if (strUTF8.empty())
    return OC_BUFFER;

  if (strUTF8[strUTF8.size()-1] == '\n')
    strUTF8.erase(strUTF8.size()-1);

  // add a new text element to our container
  m_pOverlay->AddElement(new CDVDOverlayText::CElementText(strUTF8.c_str()));

  return OC_OVERLAY;
}
int CDVDOverlayCodecTX3G::Decode(BYTE* data, int size, double pts, double duration)
{
  if (m_pOverlay)
    SAFE_RELEASE(m_pOverlay);

  m_pOverlay = new CDVDOverlayText();
  m_pOverlay->iPTSStartTime = pts;
  m_pOverlay->iPTSStopTime  = pts + duration;

  // do not move this. READ_XXXX macros modify pos.
  uint8_t  *pos = data;
  uint8_t  *end = pos + size;

  // Parse the packet as a TX3G TextSample.
  // Look for a single StyleBox ('styl') and 
  // read all contained StyleRecords.
  // Ignore all other box types.
  // NOTE: Buffer overflows on read are not checked.
  // ALSO: READ_XXXX/SKIP_XXXX macros will modify pos.
  uint16_t textLength = READ_U16();
  uint8_t *text = READ_ARRAY(textLength);

  int numStyleRecords = 0;
  uint8_t *bgnStyle   = (uint8_t*)calloc(textLength, 1);
  uint8_t *endStyle   = (uint8_t*)calloc(textLength, 1);
  int bgnColorIndex = 0, endColorIndex = 0;
  uint32_t textColorRGBA = m_textColor;
  while (pos < end)
  {
    // Read TextSampleModifierBox
    uint32_t size = READ_U32();
    if (size == 0)
      size = pos - end;   // extends to end of packet
    if (size == 1)
    {
      CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: TextSampleModifierBox has unsupported large size" );
      break;
    }
    uint32_t type = READ_U32();
    if (type == FOURCC("uuid"))
    {
      CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: TextSampleModifierBox has unsupported extended type" );
      break;
    }

    if (type == FOURCC("styl"))
    {
      // Found a StyleBox. Parse the contained StyleRecords
      if ( numStyleRecords != 0 )
      {
        CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: found additional StyleBoxes on subtitle; skipping" );
        SKIP_ARRAY(size);
        continue;
      }

      numStyleRecords = READ_U16();
      for (int i = 0; i < numStyleRecords; i++)
      {
        StyleRecord curRecord;
        curRecord.bgnChar         = READ_U16();
        curRecord.endChar         = READ_U16();
        curRecord.fontID          = READ_U16();
        curRecord.faceStyleFlags  = READ_U8();
        curRecord.fontSize        = READ_U8();
        curRecord.textColorRGBA   = READ_U32();

        bgnStyle[curRecord.bgnChar] |= curRecord.faceStyleFlags;
        endStyle[curRecord.endChar] |= curRecord.faceStyleFlags;
        bgnColorIndex = curRecord.bgnChar;
        endColorIndex = curRecord.endChar;
        textColorRGBA = curRecord.textColorRGBA;
      }
    }
    else
    {
      // Found some other kind of TextSampleModifierBox. Skip it.
      SKIP_ARRAY(size);
    }
  }

  // Copy text to out and add HTML markup for the style records
  int charIndex = 0;
  CStdStringA strUTF8;
  for (pos = text, end = text + textLength; pos < end; pos++)
  {
    if ((*pos & 0xC0) == 0x80)
    {
      // Is a non-first byte of a multi-byte UTF-8 character
      strUTF8.append((const char*)pos, 1);
      continue;   // ...without incrementing 'charIndex'
    }

    uint8_t bgnStyles = bgnStyle[charIndex];
    uint8_t endStyles = endStyle[charIndex];

    // [B] or [/B] -> toggle bold on and off
    // [I] or [/I] -> toggle italics on and off
    // [COLOR ffab007f] or [/COLOR] -> toggle color on and off
    // [CAPS <option>]  or [/CAPS]  -> toggle capatilization on and off

    if (endStyles & BOLD)
      strUTF8.append("[/B]");
    if (endStyles & ITALIC)
      strUTF8.append("[/I]");
    // we do not support underline
    //if (endStyles & UNDERLINE)
    //  strUTF8.append("[/U]");
    if (endColorIndex == charIndex && textColorRGBA != m_textColor)
      strUTF8.append("[/COLOR]");

    // invert the order from above so we bracket the text correctly.
    if (bgnColorIndex == charIndex && textColorRGBA != m_textColor)
      strUTF8.AppendFormat("[COLOR %8x]", textColorRGBA);
    // we do not support underline
    //if (bgnStyles & UNDERLINE)
    //  strUTF8.append("[U]");
    if (bgnStyles & ITALIC)
      strUTF8.append("[I]");
    if (bgnStyles & BOLD)
      strUTF8.append("[B]");

    // stuff the UTF8 char
    strUTF8.append((const char*)pos, 1);

    // this is a char index, not a byte index.
    charIndex++;
  }
  
  free(bgnStyle);
  free(endStyle);
    
  if (strUTF8.IsEmpty())
    return OC_BUFFER;

  if (strUTF8[strUTF8.size()-1] == '\n')
    strUTF8.Delete(strUTF8.size()-1);

  // add a new text element to our container
  m_pOverlay->AddElement(new CDVDOverlayText::CElementText(strUTF8.c_str()));

  return OC_OVERLAY;
}
Example #3
0
static hb_buffer_t *tx3g_decode_to_utf8( hb_buffer_t *in )
{
    uint8_t *pos = in->data;
    uint8_t *end = in->data + in->size;
    
    uint16_t numStyleRecords = 0;
    
    uint8_t *startStyle;
    uint8_t *endStyle;
    
    /*
     * Parse the packet as a TX3G TextSample.
     * 
     * Look for a single StyleBox ('styl') and read all contained StyleRecords.
     * Ignore all other box types.
     * 
     * NOTE: Buffer overflows on read are not checked.
     */
    uint16_t textLength = READ_U16();
    uint8_t *text = READ_ARRAY(textLength);
    startStyle = calloc( textLength, 1 );
    endStyle = calloc( textLength, 1 );
    while ( pos < end ) {
        /*
         * Read TextSampleModifierBox
         */
        uint32_t size = READ_U32();
        if ( size == 0 ) {
            size = pos - end;   // extends to end of packet
        }
        if ( size == 1 ) {
            hb_log( "dectx3gsub: TextSampleModifierBox has unsupported large size" );
            break;
        }
        uint32_t type = READ_U32();
        if ( type == FOURCC("uuid") ) {
            hb_log( "dectx3gsub: TextSampleModifierBox has unsupported extended type" );
            break;
        }
        
        if ( type == FOURCC("styl") ) {
            // Found a StyleBox. Parse the contained StyleRecords
            
            if ( numStyleRecords != 0 ) {
                hb_log( "dectx3gsub: found additional StyleBoxes on subtitle; skipping" );
                SKIP_ARRAY(size);
                continue;
            }
            
            numStyleRecords = READ_U16();
            
            int i;
            for (i=0; i<numStyleRecords; i++) {
                StyleRecord curRecord;
                curRecord.startChar         = READ_U16();
                curRecord.endChar           = READ_U16();
                curRecord.fontID            = READ_U16();
                curRecord.faceStyleFlags    = READ_U8();
                curRecord.fontSize          = READ_U8();
                curRecord.textColorRGBA     = READ_U32();
                
                startStyle[curRecord.startChar] |= curRecord.faceStyleFlags;
                endStyle[curRecord.endChar]     |= curRecord.faceStyleFlags;
            }
        } else {
            // Found some other kind of TextSampleModifierBox. Skip it.
            SKIP_ARRAY(size);
        }
    }
    
    /*
     * Copy text to output buffer, and add HTML markup for the style records
     */
    int maxOutputSize = textLength + (numStyleRecords * NUM_FACE_STYLE_FLAGS * (MAX_OPEN_TAG_SIZE + MAX_CLOSE_TAG_SIZE));
    hb_buffer_t *out = hb_buffer_init( maxOutputSize );
    if ( out == NULL )
        goto fail;
    uint8_t *dst = out->data;
    int charIndex = 0;
    for ( pos = text, end = text + textLength; pos < end; pos++ ) {
        if (IS_10xxxxxx(*pos)) {
            // Is a non-first byte of a multi-byte UTF-8 character
            WRITE_CHAR(*pos);
            continue;   // ...without incrementing 'charIndex'
        }
        
        uint8_t plusStyles = startStyle[charIndex];
        uint8_t minusStyles = endStyle[charIndex];
        
        if (minusStyles & UNDERLINE)
            WRITE_END_TAG('u');
        if (minusStyles & ITALIC)
            WRITE_END_TAG('i');
        if (minusStyles & BOLD)
            WRITE_END_TAG('b');
        
        if (plusStyles & BOLD)
            WRITE_START_TAG('b');
        if (plusStyles & ITALIC)
            WRITE_START_TAG('i');
        if (plusStyles & UNDERLINE)
            WRITE_START_TAG('u');
        
        WRITE_CHAR(*pos);
        charIndex++;
    }
    
    // Trim output buffer to the actual amount of data written
    out->size = dst - out->data;
    
    // Copy metadata from the input packet to the output packet
    out->s.start = in->s.start;
    out->s.stop = in->s.stop;
    
fail:
    free( startStyle );
    free( endStyle );
    
    return out;
}