diff --git a/lib/dvb/subtitle.cpp b/lib/dvb/subtitle.cpp index ec21b465ee..b044bd0ba9 100644 --- a/lib/dvb/subtitle.cpp +++ b/lib/dvb/subtitle.cpp @@ -254,10 +254,10 @@ int eDVBSubtitleParser::subtitle_process_pixel_data(subtitle_region *region, sub return 0; } -int eDVBSubtitleParser::subtitle_process_segment(uint8_t *segment) +int eDVBSubtitleParser::subtitle_process_segment(uint8_t *segment, bool isBufferProcess) { int segment_type, page_id, segment_length, processed_length; - if (*segment++ != 0x0F) + if (*segment++ != DVB_SUB_SYNC_BYTE) { eDebug("[eDVBSubtitleParser] out of sync."); return -1; @@ -267,9 +267,9 @@ int eDVBSubtitleParser::subtitle_process_segment(uint8_t *segment) page_id |= *segment++; segment_length = *segment++ << 8; segment_length |= *segment++; - if (segment_type == 0xFF) + if (segment_type == DVB_SUB_SEGMENT_STUFFING) return segment_length + 6; - if (page_id != m_composition_page_id && page_id != m_ancillary_page_id) + if (page_id != m_composition_page_id && page_id != m_ancillary_page_id && !isBufferProcess) return segment_length + 6; subtitle_page *page, **ppage; @@ -288,7 +288,7 @@ int eDVBSubtitleParser::subtitle_process_segment(uint8_t *segment) switch (segment_type) { - case 0x10: // page composition segment + case DVB_SUB_SEGMENT_PAGE_COMPOSITION: { int page_time_out = *segment++; processed_length++; int page_version_number = *segment >> 4; @@ -380,7 +380,7 @@ int eDVBSubtitleParser::subtitle_process_segment(uint8_t *segment) break; } - case 0x11: // region composition segment + case DVB_SUB_SEGMENT_REGION_COMPOSITION: { int region_id = *segment++; processed_length++; int version_number = *segment >> 4; @@ -518,7 +518,7 @@ int eDVBSubtitleParser::subtitle_process_segment(uint8_t *segment) break; } - case 0x12: // CLUT definition segment + case DVB_SUB_SEGMENT_CLUT_DEFINITION: { int CLUT_id, CLUT_version_number; subtitle_clut *clut, **pclut; @@ -620,7 +620,7 @@ int eDVBSubtitleParser::subtitle_process_segment(uint8_t *segment) } break; } - case 0x13: // object data segment + case DVB_SUB_SEGMENT_OBJECT_DATA: { int object_id; int object_coding_method; @@ -717,7 +717,7 @@ int eDVBSubtitleParser::subtitle_process_segment(uint8_t *segment) } break; } - case 0x14: // display definition segment + case DVB_SUB_SEGMENT_DISPLAY_DEFINITION: { if (segment_length > 4) { @@ -749,12 +749,12 @@ int eDVBSubtitleParser::subtitle_process_segment(uint8_t *segment) eDebug("[eDVBSubtitleParser] display definition segment to short %d!", segment_length); break; } - case 0x80: // end of display set segment + case DVB_SUB_SEGMENT_END_OF_DISPLAY_SET: { subtitle_redraw_all(); m_seen_eod = true; } - case 0xFF: // stuffing + case DVB_SUB_SEGMENT_STUFFING: break; default: eDebug("[eDVBSubtitleParser] unhandled segment type %02x", segment_type); @@ -787,7 +787,7 @@ void eDVBSubtitleParser::subtitle_process_pes(uint8_t *pkt, int len) m_seen_eod = false; - while (len && *pkt == 0x0F) + while (len && *pkt == DVB_SUB_SYNC_BYTE) { int l = subtitle_process_segment(pkt); if (l < 0) @@ -801,6 +801,34 @@ void eDVBSubtitleParser::subtitle_process_pes(uint8_t *pkt, int len) } } +void eDVBSubtitleParser::processBuffer(uint8_t *data, size_t len, pts_t pts) +{ + m_show_time = pts; + + if (*data != 0x20) { + eWarning("[eDVBSubtitleParser] Tried to handle a PES packet private data that isn't a subtitle packet (does not start with 0x20)"); + return; + } + + data++; len--; // data identifier + data++; len--; // stream id; + + + m_seen_eod = false; + while (len && *data == DVB_SUB_SYNC_BYTE) + { + int l = subtitle_process_segment(data, true); + if (l < 0) + break; + data += l; + len -= l; + } + + if (len && *data != DVB_SUB_SEGMENT_STUFFING) + eDebug("[eDVBSubtitleParser] strange data at the end"); + +} + void eDVBSubtitleParser::subtitle_redraw_all() { @@ -1067,6 +1095,10 @@ void eDVBSubtitleParser::subtitle_redraw(int page_id) DEFINE_REF(eDVBSubtitleParser); +eDVBSubtitleParser::eDVBSubtitleParser() + :m_pages(0), m_display_size(720,576) +{ } + eDVBSubtitleParser::eDVBSubtitleParser(iDVBDemux *demux) :m_pages(0), m_display_size(720,576) { diff --git a/lib/dvb/subtitle.h b/lib/dvb/subtitle.h index 6aa8a7d055..36c6db44a9 100644 --- a/lib/dvb/subtitle.h +++ b/lib/dvb/subtitle.h @@ -7,6 +7,16 @@ #include #include +#define DVB_SUB_SEGMENT_PAGE_COMPOSITION 0x10 +#define DVB_SUB_SEGMENT_REGION_COMPOSITION 0x11 +#define DVB_SUB_SEGMENT_CLUT_DEFINITION 0x12 +#define DVB_SUB_SEGMENT_OBJECT_DATA 0x13 +#define DVB_SUB_SEGMENT_DISPLAY_DEFINITION 0x14 +#define DVB_SUB_SEGMENT_END_OF_DISPLAY_SET 0x80 +#define DVB_SUB_SEGMENT_STUFFING 0xFF + +#define DVB_SUB_SYNC_BYTE 0x0F + struct subtitle_clut_entry { uint8_t Y, Cr, Cb, T; @@ -121,15 +131,17 @@ class eDVBSubtitleParser bool m_seen_eod; eSize m_display_size; public: + eDVBSubtitleParser(); eDVBSubtitleParser(iDVBDemux *demux); virtual ~eDVBSubtitleParser(); int start(int pid, int composition_page_id, int ancillary_page_id); + void processBuffer(uint8_t *data, size_t len, pts_t pts); int stop(); void connectNewPage(const sigc::slot &slot, ePtr &connection); private: void subtitle_process_line(subtitle_region *region, subtitle_region_object *object, int line, uint8_t *data, int len); int subtitle_process_pixel_data(subtitle_region *region, subtitle_region_object *object, int *linenr, int *linep, uint8_t *data); - int subtitle_process_segment(uint8_t *segment); + int subtitle_process_segment(uint8_t *segment, bool isBufferProcess=false); void subtitle_process_pes(uint8_t *buffer, int len); void subtitle_redraw_all(); void subtitle_reset(); diff --git a/lib/service/servicemp3.cpp b/lib/service/servicemp3.cpp index 822949db5a..c1b7afa86d 100644 --- a/lib/service/servicemp3.cpp +++ b/lib/service/servicemp3.cpp @@ -27,16 +27,6 @@ #define HTTP_TIMEOUT 30 -#define DVB_SUB_SEGMENT_PAGE_COMPOSITION 0x10 -#define DVB_SUB_SEGMENT_REGION_COMPOSITION 0x11 -#define DVB_SUB_SEGMENT_CLUT_DEFINITION 0x12 -#define DVB_SUB_SEGMENT_OBJECT_DATA 0x13 -#define DVB_SUB_SEGMENT_DISPLAY_DEFINITION 0x14 -#define DVB_SUB_SEGMENT_END_OF_DISPLAY_SET 0x80 -#define DVB_SUB_SEGMENT_STUFFING 0xFF - -#define DVB_SUB_SYNC_BYTE 0x0f - /* * UNUSED variable from service reference is now used as buffer flag for gstreamer * REFTYPE:FLAGS:STYPE:SID:TSID:ONID:NS:PARENT_SID:PARENT_TSID:UNUSED @@ -84,28 +74,6 @@ typedef enum #undef GSTREAMER_SUBTITLE_SYNC_MODE_BUG /**/ -void bitstream_gs_init(bitstream *bit, const void *buffer, int size) -{ - bit->data = (uint8_t*) buffer; - bit->size = size; - bit->avail = 8; - bit->consumed = 0; -} - -int bitstream_gs_get(bitstream *bit) -{ - int val; - bit->avail -= bit->size; - val = ((*bit->data) >> bit->avail) & ((1<size) - 1); - if (!bit->avail) - { - bit->data++; - bit->consumed++; - bit->avail = 8; - } - return val; -} - eServiceFactoryMP3::eServiceFactoryMP3() { ePtr sc; @@ -464,12 +432,12 @@ eServiceMP3::eServiceMP3(eServiceReference ref): m_cuesheet_changed(0), m_cutlist_enabled(1), m_ref(ref), - m_pages(0), - m_display_size(720,576), m_pump(eApp, 1, "Servicemp3") { m_subtitle_sync_timer = eTimer::create(eApp); m_dvb_subtitle_sync_timer = eTimer::create(eApp); + m_dvb_subtitle_parser = new eDVBSubtitleParser(); + m_dvb_subtitle_parser->connectNewPage(sigc::mem_fun(*this, &eServiceMP3::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection); m_stream_tags = 0; m_currentAudioStream = -1; m_currentSubtitleStream = -1; @@ -831,6 +799,7 @@ eServiceMP3::~eServiceMP3() gst_object_unref (GST_OBJECT (m_gst_playbin)); eDebug("[eServiceMP3] destruct!"); } + m_new_dvb_subtitle_page_connection = 0; } void eServiceMP3::updateEpgCacheNowNext() @@ -2681,480 +2650,6 @@ void eServiceMP3::gstTextpadHasCAPS_synced(GstPad *pad) } } -void eServiceMP3::subtitle_redraw_all() -{ - subtitle_page *page = m_pages; - - while(page) - { - subtitle_redraw(page->page_id); - page = page->next; - } -} - -void eServiceMP3::subtitle_reset() -{ - while (subtitle_page *page = m_pages) - { - /* free page regions */ - while (page->page_regions) - { - subtitle_page_region *p = page->page_regions->next; - delete page->page_regions; - page->page_regions = p; - } - /* free regions */ - while (page->regions) - { - subtitle_region *region = page->regions; - - while (region->objects) - { - subtitle_region_object *obj = region->objects; - region->objects = obj->next; - delete obj; - } - - if (region->buffer) - region->buffer=0; - - page->regions = region->next; - delete region; - } - - /* free CLUTs */ - while (page->cluts) - { - subtitle_clut *clut = page->cluts; - page->cluts = clut->next; - delete clut; - } - - m_pages = page->next; - delete page; - } -} - -void eServiceMP3::subtitle_redraw(int page_id) -{ - subtitle_page *page = m_pages; - - while (page) - { - if (page->page_id == page_id) - break; - page = page->next; - } - if (!page){ - return; - } - - /* iterate all regions in this pcs */ - subtitle_page_region *region = page->page_regions; - - eDVBSubtitlePage Page; - Page.m_show_time = m_show_time / 1000000ULL; - for (; region; region=region->next) - { - /* find corresponding region */ - subtitle_region *reg = page->regions; - while (reg) - { - eTrace("[eServiceMP3] DVB subtitles reg->region_id/region->region_id = %d/%d", reg->region_id, region->region_id); - if (reg->region_id == region->region_id){ - eTrace("[eServiceMP3] DVB subtitles found correct region"); - break; - } - - reg = reg->next; - } - if (reg) - { - int x0 = region->region_horizontal_address; - int y0 = region->region_vertical_address; - - if ((x0 < 0) || (y0 < 0)) - continue; - - /* find corresponding clut */ - subtitle_clut *clut = page->cluts; - while (clut) - { - if (clut->clut_id == reg->clut_id) - break; - clut = clut->next; - } - - int clut_size = reg->buffer->surface->clut.colors = reg->depth == subtitle_region::bpp2 ? - 4 : reg->depth == subtitle_region::bpp4 ? 16 : 256; - - reg->buffer->surface->clut.data = new gRGB[clut_size]; - - gRGB *palette = reg->buffer->surface->clut.data; - - subtitle_clut_entry *entries=0; - switch(reg->depth) - { - case subtitle_region::bpp2: - if (clut) - entries = clut->entries_2bit; - memset(static_cast(palette), 0, 4 * sizeof(gRGB)); - // this table is tested on cyfra .. but in EN300743 the table palette[2] and palette[1] is swapped.. i dont understand this ;) - palette[0].a = 0xFF; - palette[2].r = palette[2].g = palette[2].b = 0xFF; - palette[3].r = palette[3].g = palette[3].b = 0x80; - break; - case subtitle_region::bpp4: // tested on cyfra... but the map is another in EN300743... dont understand this... - if (clut) - entries = clut->entries_4bit; - memset(static_cast(palette), 0, 16*sizeof(gRGB)); - for (int i=0; i < 16; ++i) - { - if (!i) - palette[i].a = 0xFF; - else if (i & 8) - { - if (i & 1) - palette[i].r = 0x80; - if (i & 2) - palette[i].g = 0x80; - if (i & 4) - palette[i].b = 0x80; - } - else - { - if (i & 1) - palette[i].r = 0xFF; - if (i & 2) - palette[i].g = 0xFF; - if (i & 4) - palette[i].b = 0xFF; - } - } - break; - case subtitle_region::bpp8: // completely untested.. i never seen 8bit DVB subtitles - if (clut) - entries = clut->entries_8bit; - memset(static_cast(palette), 0, 256*sizeof(gRGB)); - for (int i=0; i < 256; ++i) - { - switch (i & 17) - { - case 0: // b1 == 0 && b5 == 0 - if (!(i & 14)) // b2 == 0 && b3 == 0 && b4 == 0 - { - if (!(i & 224)) // b6 == 0 && b7 == 0 && b8 == 0 - palette[i].a = 0xFF; - else - { - if (i & 128) // R = 100% x b8 - palette[i].r = 0xFF; - if (i & 64) // G = 100% x b7 - palette[i].g = 0xFF; - if (i & 32) // B = 100% x b6 - palette[i].b = 0xFF; - palette[i].a = 0xBF; // T = 75% - } - break; - } - [[fallthrough]]; - case 16: // b1 == 0 && b5 == 1 - if (i & 128) // R = 33% x b8 - palette[i].r = 0x55; - if (i & 64) // G = 33% x b7 - palette[i].g = 0x55; - if (i & 32) // B = 33% x b6 - palette[i].b = 0x55; - if (i & 8) // R + 66,7% x b4 - palette[i].r += 0xAA; - if (i & 4) // G + 66,7% x b3 - palette[i].g += 0xAA; - if (i & 2) // B + 66,7% x b2 - palette[i].b += 0xAA; - if (i & 16) // needed for fall through from case 0!! - palette[i].a = 0x80; // T = 50% - break; - case 1: // b1 == 1 && b5 == 0 - palette[i].r = - palette[i].g = - palette[i].b = 0x80; // 50% - [[fallthrough]]; - case 17: // b1 == 1 && b5 == 1 - if (i & 128) // R += 16.7% x b8 - palette[i].r += 0x2A; - if (i & 64) // G += 16.7% x b7 - palette[i].g += 0x2A; - if (i & 32) // B += 16.7% x b6 - palette[i].b += 0x2A; - if (i & 8) // R += 33% x b4 - palette[i].r += 0x55; - if (i & 4) // G += 33% x b3 - palette[i].g += 0x55; - if (i & 2) // B += 33% x b2 - palette[i].b += 0x55; - break; - } - } - break; - } - - int bcktrans = eConfigManager::getConfigIntValue("config.subtitles.dvb_subtitles_backtrans"); - bool yellow = eConfigManager::getConfigBoolValue("config.subtitles.dvb_subtitles_yellow"); - - for (int i=0; i 0) - { - y -= 16; - cr -= 128; - cb -= 128; - palette[i].r = MAX(MIN(((298 * y + 460 * cr) / 256), 255), 0); - palette[i].g = MAX(MIN(((298 * y - 55 * cb - 137 * cr) / 256), 255), 0); - palette[i].b = yellow?0:MAX(MIN(((298 * y + 543 * cb ) / 256), 255), 0); - if (bcktrans) - { - if (palette[i].r || palette[i].g || palette[i].b) - palette[i].a = (entries[i].T) & 0xFF; - else - palette[i].a = bcktrans; - } - else - palette[i].a = (entries[i].T) & 0xFF; - } - else - { - palette[i].r = 0; - palette[i].g = 0; - palette[i].b = 0; - palette[i].a = 0xFF; - } - } - } - - eDVBSubtitleRegion Region; - Region.m_pixmap = reg->buffer; - Region.m_position.setX(x0); - Region.m_position.setY(y0); - Page.m_regions.push_back(Region); - reg->committed = true; - } - } - Page.m_display_size = m_display_size; - m_dvb_subtitle_pages.push_back(Page); - pushDVBSubtitles(); - Page.m_regions.clear(); -} - -void eServiceMP3::subtitle_process_line(subtitle_region *region, subtitle_region_object *object, int line, uint8_t *data, int len) -{ - bool subcentered = eConfigManager::getConfigBoolValue("config.subtitles.dvb_subtitles_centered"); - int x = subcentered ? (region->width - len) /2 : object->object_horizontal_position; - int y = object->object_vertical_position + line; - if (x + len > region->width) - len = region->width - x; - if (len < 0 || y >= region->height) - return; - - memcpy((uint8_t*)region->buffer->surface->data + region->buffer->surface->stride * y + x, data, len); -} - -static int map_2_to_4_bit_table[4]; -static int map_2_to_8_bit_table[4]; -static int map_4_to_8_bit_table[16]; - -int eServiceMP3::subtitle_process_pixel_data(subtitle_region *region, subtitle_region_object *object, int *linenr, int *linep, uint8_t *data) -{ - int data_type = *data++; - static uint8_t line[1920]; - - bitstream bit; - bit.size=0; - switch (data_type) - { - case 0x10: // 2bit pixel data - bitstream_gs_init(&bit, data, 2); - while (1) - { - int len=0, col=0; - int code = bitstream_gs_get(&bit); - if (code) - { - col = code; - len = 1; - } else - { - code = bitstream_gs_get(&bit); - if (!code) - { - code = bitstream_gs_get(&bit); - if (code == 1) - { - col = 0; - len = 2; - } else if (code == 2) - { - len = bitstream_gs_get(&bit) << 2; - len |= bitstream_gs_get(&bit); - len += 12; - col = bitstream_gs_get(&bit); - } else if (code == 3) - { - len = bitstream_gs_get(&bit) << 6; - len |= bitstream_gs_get(&bit) << 4; - len |= bitstream_gs_get(&bit) << 2; - len |= bitstream_gs_get(&bit); - len += 29; - col = bitstream_gs_get(&bit); - } else - break; - } else if (code==1) - { - col = 0; - len = 1; - } else if (code&2) - { - if (code&1) - len = 3 + 4 + bitstream_gs_get(&bit); - else - len = 3 + bitstream_gs_get(&bit); - col = bitstream_gs_get(&bit); - } - } - uint8_t c = region->depth == subtitle_region::bpp4 ? - map_2_to_4_bit_table[col] : - region->depth == subtitle_region::bpp8 ? - map_2_to_8_bit_table[col] : col; - while (len && ((*linep) < m_display_size.width())) - { - line[(*linep)++] = c; - len--; - } - } - while (bit.avail != 8) - bitstream_gs_get(&bit); - return bit.consumed + 1; - case 0x11: // 4bit pixel data - bitstream_gs_init(&bit, data, 4); - while (1) - { - int len=0, col=0; - int code = bitstream_gs_get(&bit); - if (code) - { - col = code; - len = 1; - } else - { - code = bitstream_gs_get(&bit); - if (!code) - break; - else if (code == 0xC) - { - col = 0; - len = 1; - } else if (code == 0xD) - { - col = 0; - len = 2; - } else if (code < 8) - { - col = 0; - len = (code & 7) + 2; - } else if ((code & 0xC) == 0x8) - { - col = bitstream_gs_get(&bit); - len = (code & 3) + 4; - } else if (code == 0xE) - { - len = bitstream_gs_get(&bit) + 9; - col = bitstream_gs_get(&bit); - } else if (code == 0xF) - { - len = bitstream_gs_get(&bit) << 4; - len |= bitstream_gs_get(&bit); - len += 25; - col = bitstream_gs_get(&bit); - } - } - uint8_t c = region->depth == subtitle_region::bpp8 ? - map_4_to_8_bit_table[col] : col; - while (len && ((*linep) < m_display_size.width())) - { - line[(*linep)++] = c; - len--; - } - } - while (bit.avail != 8) - bitstream_gs_get(&bit); - return bit.consumed + 1; - case 0x12: // 8bit pixel data - bitstream_gs_init(&bit, data, 8); - while(1) - { - int len=0, col=0; - int code = bitstream_gs_get(&bit); - if (code) - { - col = code; - len = 1; - } else - { - code = bitstream_gs_get(&bit); - if ((code & 0x80) == 0x80) - { - len = code&0x7F; - col = bitstream_gs_get(&bit); - } else if (code&0x7F) - { - len = code&0x7F; - col = 0; - } else - break; - } - while (len && ((*linep) < m_display_size.width())) - { - line[(*linep)++] = col; - len--; - } - } - return bit.consumed + 1; - case 0x20: - bitstream_gs_init(&bit, data, 4); - for ( int i=0; i < 4; ++i ) - { - map_2_to_4_bit_table[i] = bitstream_gs_get(&bit); - } - return bit.consumed + 1; - case 0x21: - bitstream_gs_init(&bit, data, 8); - for ( int i=0; i < 4; ++i ) - { - map_2_to_8_bit_table[i] = bitstream_gs_get(&bit); - } - return bit.consumed + 1; - case 0x22: - bitstream_gs_init(&bit, data, 8); - for ( int i=0; i < 16; ++i ) - { - map_4_to_8_bit_table[i] = bitstream_gs_get(&bit); - } - return bit.consumed + 1; - case 0xF0: - subtitle_process_line(region, object, *linenr, line, *linep); - (*linenr)+=2; // interlaced - *linep = 0; - return 1; - default: - return -1; - } - return 0; -} - void eServiceMP3::pullSubtitle(GstBuffer *buffer) { if (buffer && m_currentSubtitleStream >= 0 && m_currentSubtitleStream < (int)m_subtitleStreams.size()) @@ -3166,7 +2661,6 @@ void eServiceMP3::pullSubtitle(GstBuffer *buffer) return; } int64_t buf_pos = GST_BUFFER_PTS(buffer); - m_show_time = buf_pos; size_t len = map.size; eTrace("[eServiceMP3] gst_buffer_get_size %zu map.size %zu", gst_buffer_get_size(buffer), len); int64_t duration_ns = GST_BUFFER_DURATION(buffer); @@ -3176,538 +2670,8 @@ void eServiceMP3::pullSubtitle(GstBuffer *buffer) { if (subType == stDVB) { - unsigned int pos = 0; uint8_t * data = map.data; - if (len <= 3) { /* len(0x20 0x00 end_of_PES_data_field_marker) */ - eWarning("Data length too short"); - return; - } - - if (data[pos++] != 0x20) { - eWarning("Tried to handle a PES packet private data that isn't a subtitle packet (does not start with 0x20)"); - return; - } - - if (data[pos++] != 0x00) { - eWarning("'Subtitle stream in this PES packet' was not 0x00, so this is in theory not a DVB subtitle stream (but some other subtitle standard?); bailing out"); - return; - } - - while (data[pos++] == DVB_SUB_SYNC_BYTE) - { - int segment_type, page_id, segment_len, processed_length; - if ((len - pos) < (2 * 2 + 1)) { - eWarning("Data after SYNC BYTE too short, less than needed to even get to segment_length"); - break; - } - segment_type = data[pos++]; - page_id = (data[pos] << 8) | data[pos + 1]; - pos += 2; - segment_len = (data[pos] << 8) | data[pos + 1]; - pos += 2; - if ((len - pos) < segment_len) { - eWarning("segment_length was told to be %u, but we only have %d bytes left", segment_len, len - pos); - break; - } - subtitle_page *page, **ppage; - page = m_pages; ppage = &m_pages; - - while (page) - { - if (page->page_id == page_id) - break; - ppage = &page->next; - page = page->next; - } - - processed_length = 0; - uint8_t* segment = data+pos; - switch (segment_type) { - case DVB_SUB_SEGMENT_PAGE_COMPOSITION: - { - eTrace("Page composition segment at buffer pos %u", pos); - int page_time_out = *segment++; - processed_length++; - int page_version_number = *segment >> 4; - int page_state = ((*segment++) >> 2) & 3; - processed_length++; - if (!page) - { - page = new subtitle_page; - page->page_regions = 0; - page->regions = 0; - page->page_id = page_id; - page->cluts = 0; - page->next = 0; - *ppage = page; - } else - { - if (page->pcs_size != segment_len) - page->page_version_number = -1; - // if no update, just skip this data. - if (page->page_version_number == page_version_number) - break; - } - - page->state = page_state; - - // Clear page_region list before processing any type of PCS - while (page->page_regions) - { - subtitle_page_region *p = page->page_regions->next; - delete page->page_regions; - page->page_regions = p; - } - page->page_regions=0; - - // when acquisition point or mode change: remove all displayed regions. - if ((page_state == 1) || (page_state == 2)) - { - while (page->regions) - { - subtitle_region *p = page->regions->next; - while(page->regions->objects) - { - subtitle_region_object *ob = page->regions->objects->next; - delete page->regions->objects; - page->regions->objects = ob; - } - delete page->regions; - page->regions = p; - } - - } - - page->page_time_out = page_time_out; - - page->page_version_number = page_version_number; - - subtitle_page_region **r = &page->page_regions; - - // go to last entry - while (*r) - r = &(*r)->next; - - while (processed_length < segment_len) - { - uint8_t region_id = *segment++; - segment += 1; - subtitle_page_region *pr; - - // append new entry to list - pr = new subtitle_page_region; - pr->next = 0; - *r = pr; - r = &pr->next; - - pr->region_id = region_id; - processed_length++; - processed_length++; - - pr->region_horizontal_address = GST_READ_UINT16_BE (segment); - segment += 2; - processed_length += 2; - - pr->region_vertical_address = GST_READ_UINT16_BE (segment); - segment += 2; - processed_length += 2; - } - - break; - } - case DVB_SUB_SEGMENT_REGION_COMPOSITION: - { - eDebug("Region composition segment at buffer pos %u", pos); - int region_id = *segment++; - processed_length++; - int version_number = *segment >> 4; - int region_fill_flag = (*segment++ >> 3) & 1; - processed_length++; - - // if we didn't yet received the pcs for this page, drop the region - if (!page) - { - eDebug("[eServiceMP3] ignoring region %x, since page %02x doesn't yet exist.", region_id, page_id); - break; - } - - subtitle_region *region, **pregion; - - region = page->regions; pregion = &page->regions; - - while (region) - { - fflush(stdout); - if (region->region_id == region_id) - break; - pregion = ®ion->next; - region = region->next; - } - - if (!region) - { - *pregion = region = new subtitle_region; - region->next = 0; - region->buffer=0; - region->committed = false; - } - else if (region->version_number != version_number) - { - subtitle_region_object *objects = region->objects; - while (objects) - { - subtitle_region_object *n = objects->next; - delete objects; - objects = n; - } - } - else - break; - - region->region_id = region_id; - region->version_number = version_number; - - region->width = GST_READ_UINT16_BE(segment); - segment += 2; - processed_length += 2; - - region->height = GST_READ_UINT16_BE(segment); - segment += 2; - processed_length += 2; - - //int depth = 1 << (((*segment++) >> 2) & 7); - int depth; - depth = (*segment++ >> 2) & 7; - - region->depth = (subtitle_region::tDepth)depth; - processed_length++; - - int CLUT_id = *segment++; processed_length++; - - region->clut_id = CLUT_id; - - int region_8bit_pixel_code, region_4bit_pixel_code, region_2bit_pixel_code; - region_8bit_pixel_code = *segment++; processed_length++; - region_4bit_pixel_code = *segment >> 4; - region_2bit_pixel_code = (*segment++ >> 2) & 3; - processed_length++; - - if (!region_fill_flag) - { - region_2bit_pixel_code = region_4bit_pixel_code = region_8bit_pixel_code = 0; - region_fill_flag = 1; - } - - // create and initialise buffer only when buffer does not yet exist. - - if (region->buffer==0) { - region->buffer = new gPixmap(eSize(region->width, region->height), 8, 1); - memset(region->buffer->surface->data, 0, region->height * region->buffer->surface->stride); - - if (region_fill_flag) - { - if (depth == 1) - memset(region->buffer->surface->data, region_2bit_pixel_code, region->height * region->width); - else if (depth == 2) - memset(region->buffer->surface->data, region_4bit_pixel_code, region->height * region->width); - else if (depth == 3) - memset(region->buffer->surface->data, region_8bit_pixel_code, region->height * region->width); - else - eDebug("[eServiceMP3] !!!! invalid depth"); - } - } - - region->objects = 0; - subtitle_region_object **pobject = ®ion->objects; - - while (processed_length < segment_len) - { - subtitle_region_object *object; - - object = new subtitle_region_object; - - *pobject = object; - object->next = 0; - pobject = &object->next; - - object->object_id = *segment++ << 8; - object->object_id |= *segment++; processed_length += 2; - - object->object_type = *segment >> 6; - object->object_provider_flag = (*segment >> 4) & 3; - object->object_horizontal_position = (*segment++ & 0xF) << 8; - object->object_horizontal_position |= *segment++; - processed_length += 2; - - object->object_vertical_position = (*segment++ & 0xF) << 8; - object->object_vertical_position |= *segment++ ; - processed_length += 2; - - if ((object->object_type == 1) || (object->object_type == 2)) - { - object->foreground_pixel_value = *segment++; - object->background_pixel_value = *segment++; - processed_length += 2; - } - } - - if (processed_length != segment_len) - eDebug("[eServiceMP3] DVB subtitle too less data! (%d < %d)", segment_len, processed_length); - - break; - } - case DVB_SUB_SEGMENT_CLUT_DEFINITION: - { - eDebug("CLUT definition segment at buffer pos %u", pos); - int CLUT_id, CLUT_version_number; - subtitle_clut *clut, **pclut; - - if (!page) - break; - - CLUT_id = *segment++; - - CLUT_version_number = *segment++ >> 4; - processed_length += 2; - - clut = page->cluts; pclut = &page->cluts; - - while (clut) - { - if (clut->clut_id == CLUT_id) - break; - pclut = &clut->next; - clut = clut->next; - } - - if (!clut) - { - *pclut = clut = new subtitle_clut; - clut->next = 0; - clut->clut_id = CLUT_id; - } - else if (clut->CLUT_version_number == CLUT_version_number) - break; - - clut->CLUT_version_number=CLUT_version_number; - - memset(clut->entries_2bit, 0, sizeof(clut->entries_2bit)); - memset(clut->entries_4bit, 0, sizeof(clut->entries_4bit)); - memset(clut->entries_8bit, 0, sizeof(clut->entries_8bit)); - - while (processed_length < segment_len) - { - int CLUT_entry_id, entry_CLUT_flag, full_range; - int v_Y, v_Cr, v_Cb, v_T; - - CLUT_entry_id = *segment++; - full_range = *segment & 1; - entry_CLUT_flag = (*segment++ & 0xE0) >> 5; - processed_length += 2; - - if (full_range) - { - v_Y = *segment++; - v_Cr = *segment++; - v_Cb = *segment++; - v_T = *segment++; - processed_length += 4; - } else - { - v_Y = *segment & 0xFC; - v_Cr = (*segment++ & 3) << 6; - v_Cr |= (*segment & 0xC0) >> 2; - v_Cb = (*segment & 0x3C) << 2; - v_T = (*segment++ & 3) << 6; - processed_length += 2; - } - - if (entry_CLUT_flag & 1) // 8bit - { - clut->entries_8bit[CLUT_entry_id].Y = v_Y; - clut->entries_8bit[CLUT_entry_id].Cr = v_Cr; - clut->entries_8bit[CLUT_entry_id].Cb = v_Cb; - clut->entries_8bit[CLUT_entry_id].T = v_T; - clut->entries_8bit[CLUT_entry_id].valid = 1; - } - if (entry_CLUT_flag & 2) // 4bit - { - if (CLUT_entry_id < 16) - { - clut->entries_4bit[CLUT_entry_id].Y = v_Y; - clut->entries_4bit[CLUT_entry_id].Cr = v_Cr; - clut->entries_4bit[CLUT_entry_id].Cb = v_Cb; - clut->entries_4bit[CLUT_entry_id].T = v_T; - clut->entries_4bit[CLUT_entry_id].valid = 1; - } - else - eDebug("[eServiceMP3] DVB subtitle CLUT entry marked as 4 bit with id %d (>15)", CLUT_entry_id); - } - if (entry_CLUT_flag & 4) // 2bit - { - if (CLUT_entry_id < 4) - { - clut->entries_2bit[CLUT_entry_id].Y = v_Y; - clut->entries_2bit[CLUT_entry_id].Cr = v_Cr; - clut->entries_2bit[CLUT_entry_id].Cb = v_Cb; - clut->entries_2bit[CLUT_entry_id].T = v_T; - clut->entries_2bit[CLUT_entry_id].valid = 1; - } - else - eDebug("[eServiceMP3] DVB subtitle CLUT entry marked as 2 bit with id %d (>3)", CLUT_entry_id); - } - } - break; - } - case DVB_SUB_SEGMENT_OBJECT_DATA: - { - eDebug("Object data segment at buffer pos %u", pos); - int object_id; - int object_coding_method; - - object_id = *segment++ << 8; - object_id |= *segment++; - processed_length += 2; - - object_coding_method = (*segment >> 2) & 3; - segment++; // non_modifying_color_flag - processed_length++; - - subtitle_region *region = page->regions; - while (region) - { - subtitle_region_object *object = region->objects; - while (object) - { - if (object->object_id == object_id) - { - if (object_coding_method == 0) - { - int top_field_data_blocklength, bottom_field_data_blocklength; - int i=1, line, linep; - - top_field_data_blocklength = *segment++ << 8; - top_field_data_blocklength |= *segment++; - - bottom_field_data_blocklength = *segment++ << 8; - bottom_field_data_blocklength |= *segment++; - processed_length += 4; - - // its working on cyfra channels.. but hmm in EN300743 the default table is 0, 7, 8, 15 - map_2_to_4_bit_table[0] = 0; - map_2_to_4_bit_table[1] = 8; - map_2_to_4_bit_table[2] = 7; - map_2_to_4_bit_table[3] = 15; - - // this map is realy untested... - map_2_to_8_bit_table[0] = 0; - map_2_to_8_bit_table[1] = 0x88; - map_2_to_8_bit_table[2] = 0x77; - map_2_to_8_bit_table[3] = 0xff; - - map_4_to_8_bit_table[0] = 0; - for (; i < 16; ++i) - map_4_to_8_bit_table[i] = i * 0x11; - - i = 0; - line = 0; - linep = 0; - while (i < top_field_data_blocklength) - { - int len; - len = subtitle_process_pixel_data(region, object, &line, &linep, segment); - if (len < 0) - break; - segment += len; - processed_length += len; - i += len; - } - - line = 1; - linep = 0; - - if (bottom_field_data_blocklength) - { - i = 0; - while (i < bottom_field_data_blocklength) - { - int len; - len = subtitle_process_pixel_data(region, object, &line, &linep, segment); - if (len < 0) - break; - segment += len; - processed_length += len; - i += len; - } - } - else if (top_field_data_blocklength) - eDebug("[eDVBSubtitleParser] !!!! unimplemented: no bottom field! (%d : %d)", top_field_data_blocklength, bottom_field_data_blocklength); - - if ((top_field_data_blocklength + bottom_field_data_blocklength) & 1) - { - segment++; processed_length++; - } - } - else if (object_coding_method == 1) - eDebug("[eDVBSubtitleParser] ---- object_coding_method 1 unsupported!"); - } - object = object->next; - } - region = region->next; - } - break; - } - case DVB_SUB_SEGMENT_DISPLAY_DEFINITION: - { - eDebug("display definition segment at buffer pos %u", pos); - if (segment_len > 4) - { - int display_window_flag = (segment[0] >> 3) & 1; - int display_width = (segment[1] << 8) | (segment[2]); - int display_height = (segment[3] << 8) | (segment[4]); - processed_length += 5; - m_display_size = eSize(display_width+1, display_height+1); - if (display_window_flag) - { - if (segment_len > 12) - { - int display_window_horizontal_position_min = (segment[4] << 8) | segment[5]; - int display_window_horizontal_position_max = (segment[6] << 8) | segment[7]; - int display_window_vertical_position_min = (segment[8] << 8) | segment[9]; - int display_window_vertical_position_max = (segment[10] << 8) | segment[11]; - eDebug("[eServiceMP3] DVB subtitle NYI hpos min %d, hpos max %d, vpos min %d, vpos max %d", - display_window_horizontal_position_min, - display_window_horizontal_position_max, - display_window_vertical_position_min, - display_window_vertical_position_max); - processed_length += 8; - } - else - eDebug("[eServiceMP3] DVB subtitle display window flag set but display definition segment to short %d!", segment_len); - } - } - else - eDebug("[eServiceMP3] DVB subtitle display definition segment to short %d!", segment_len); - break; - } - case DVB_SUB_SEGMENT_END_OF_DISPLAY_SET: - { - eDebug("End of display set at buffer pos %u", pos); - subtitle_redraw_all(); - m_seen_eod = true; - break; - } - default: - eWarning("Unhandled segment type 0x%x", segment_type); - break; - } - pos += segment_len; - if (pos == len) { - eWarning("Data ended without a PES data end marker"); - return; - } - } - + m_dvb_subtitle_parser->processBuffer(data, len, buf_pos / 1000000ULL); } else if ( subType < stVOB ) { @@ -3739,6 +2703,12 @@ void eServiceMP3::pullSubtitle(GstBuffer *buffer) } } +void eServiceMP3::newDVBSubtitlePage(const eDVBSubtitlePage &p) +{ + m_dvb_subtitle_pages.push_back(p); + pushDVBSubtitles(); +} + void eServiceMP3::pushDVBSubtitles() { pts_t running_pts = 0, decoder_ms; diff --git a/lib/service/servicemp3.h b/lib/service/servicemp3.h index cac79aaaaa..16e3c046c9 100644 --- a/lib/service/servicemp3.h +++ b/lib/service/servicemp3.h @@ -348,10 +348,6 @@ class eServiceMP3: public iPlayableService, public iPauseableService, GstElement *m_gst_playbin, *audioSink, *videoSink; GstTagList *m_stream_tags; bool m_coverart; - subtitle_page *m_pages; - eSize m_display_size; - bool m_seen_eod; - pts_t m_show_time; std::list m_dvb_subtitle_pages; eFixedMessagePump > m_pump; @@ -388,16 +384,13 @@ class eServiceMP3: public iPlayableService, public iPauseableService, subtitle_pages_map_t m_subtitle_pages; ePtr m_subtitle_sync_timer; ePtr m_dvb_subtitle_sync_timer; + ePtr m_dvb_subtitle_parser; + ePtr m_new_dvb_subtitle_page_connection; + void newDVBSubtitlePage(const eDVBSubtitlePage &p); pts_t m_prev_decoder_time; int m_decoder_time_valid_state; - void subtitle_redraw_all(); - void subtitle_reset(); - void subtitle_redraw(int page_id); - int subtitle_process_pixel_data(subtitle_region *region, subtitle_region_object *object, int *linenr, int *linep, uint8_t *data); - void subtitle_process_line(subtitle_region *region, subtitle_region_object *object, int line, uint8_t *data, int len); - void pushDVBSubtitles(); void pushSubtitles(); void pullSubtitle(GstBuffer *buffer);