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; }
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; }