X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/3ef876533bacd91aee5f91800d10bc105726dabc..54994b1053860c52ba35b03bfc0b369f293b66c3:/lib/dvb/subtitle.cpp diff --git a/lib/dvb/subtitle.cpp b/lib/dvb/subtitle.cpp index eae72056..f4b5b7e4 100644 --- a/lib/dvb/subtitle.cpp +++ b/lib/dvb/subtitle.cpp @@ -11,7 +11,7 @@ #include #include -void bitstream_init(struct bitstream *bit, const void *buffer, int size) +void bitstream_init(bitstream *bit, const void *buffer, int size) { bit->data = (__u8*) buffer; bit->size = size; @@ -19,7 +19,7 @@ void bitstream_init(struct bitstream *bit, const void *buffer, int size) bit->consumed = 0; } -int bitstream_get(struct bitstream *bit) +int bitstream_get(bitstream *bit) { int val; bit->avail -= bit->size; @@ -54,13 +54,13 @@ static int extract_pts(pts_t &pts, __u8 *pkt) return -1; } -void eDVBSubtitleParser::subtitle_process_line(struct subtitle_page *page, int object_id, int line, __u8 *data, int len) +void eDVBSubtitleParser::subtitle_process_line(subtitle_page *page, int object_id, int line, __u8 *data, int len) { - struct subtitle_region *region = page->regions; + subtitle_region *region = page->regions; // eDebug("line for %d:%d", page->page_id, object_id); while (region) { - struct subtitle_region_object *object = region->region_objects; + subtitle_region_object *object = region->region_objects; while (object) { if (object->object_id == object_id) @@ -80,6 +80,7 @@ void eDVBSubtitleParser::subtitle_process_line(struct subtitle_page *page, int o break; } // //eDebug("inserting %d bytes (into region %d)", len, region->region_id); +// eDebug("put data to region_buffer %p", &(*region->region_buffer)); memcpy((__u8*)region->region_buffer->surface->data + region->region_width * y + x, data, len); } object = object->next; @@ -88,12 +89,12 @@ void eDVBSubtitleParser::subtitle_process_line(struct subtitle_page *page, int o } } -int eDVBSubtitleParser::subtitle_process_pixel_data(struct subtitle_page *page, int object_id, int *linenr, int *linep, __u8 *data) +int eDVBSubtitleParser::subtitle_process_pixel_data(subtitle_page *page, int object_id, int *linenr, int *linep, __u8 *data) { int data_type = *data++; static __u8 line[720]; - struct bitstream bit; + bitstream bit; bit.size=0; switch (data_type) { @@ -287,13 +288,15 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) segment_length |= *segment++; if (segment_type == 0xFF) return segment_length + 6; -// //eDebug("have %d bytes of segment data", segment_length); + if (page_id != m_composition_page_id && page_id != m_ancillary_page_id) + return segment_length + 6; + //eDebug("have %d bytes of segment data", segment_length); -// //eDebug("page_id %d, segtype %02x", page_id, segment_type); + //eDebug("page_id %d, segtype %02x", page_id, segment_type); - struct subtitle_page *page, **ppage; + subtitle_page *page, **ppage; - page = this->pages; ppage = &this->pages; + page = m_pages; ppage = &m_pages; while (page) { @@ -337,30 +340,46 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) // if no update, just skip this data. if (page->page_version_number == page_version_number) { - eDebug("skip data... "); +// eDebug("skip data... "); break; } } -// eDebug("page updated: old: %d, new: %d", page->page_version_number, page_version_number); + //eDebug("page updated: old: %d, new: %d", page->page_version_number, page_version_number); // when acquisition point or mode change: remove all displayed pages. if ((page_state == 1) || (page_state == 2)) { while (page->page_regions) { - struct subtitle_page_region *p = page->page_regions->next; + subtitle_page_region *p = page->page_regions->next; + //eDebug("delete page_region %d", page->page_regions->region_id); delete page->page_regions; page->page_regions = p; } + while (page->regions) + { + subtitle_region *p = page->regions->next; + //eDebug("delete region %d", page->regions->region_id); + while(page->regions->region_objects) + { + //eDebug("delete region object"); + subtitle_region_object *ob = page->regions->region_objects->next; + delete page->regions->region_objects; + page->regions->region_objects = ob; + } + delete page->regions; + page->regions = p; + } + } -// eDebug("new page.. (%d)", page_state); + //eDebug("new page.. (%d)", page_state); page->page_time_out = page_time_out; page->page_version_number = page_version_number; - struct subtitle_page_region **r = &page->page_regions; + subtitle_page_region **r = &page->page_regions; //eDebug("%d / %d data left", processed_length, segment_length); @@ -368,9 +387,15 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) while (*r) r = &(*r)->next; + if (processed_length == segment_length && !page->page_regions) + { + //eDebug("no regions in page.. clear screen!!"); + subtitle_redraw(page->page_id); + } + while (processed_length < segment_length) { - struct subtitle_page_region *pr; + subtitle_page_region *pr; // append new entry to list pr = new subtitle_page_region; @@ -410,7 +435,7 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) break; } - struct subtitle_region *region, **pregion; + subtitle_region *region, **pregion; region = page->regions; pregion = &page->regions; @@ -425,24 +450,27 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) if (!region) { + //eDebug("create region !!!!!!!!!!"); *pregion = region = new subtitle_region; region->next = 0; + region->committed = false; } else if (region->region_version_number != region_version_number) { - struct subtitle_region_object *objects = region->region_objects; + subtitle_region_object *objects = region->region_objects; + //eDebug("unequal version %p %p", objects, objects?objects->next:objects); while (objects) { - struct subtitle_region_object *n = objects->next; + subtitle_region_object *n = objects->next; delete objects; objects = n; } if (region->region_buffer) { - if (region->region_buffer->surface) - delete region->region_buffer->surface; + //eDebug("no more need of region_buffer %p", &(*region->region_buffer)); region->region_buffer=0; } + region->committed = false; } else break; @@ -461,6 +489,7 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) processed_length += 2; region->region_buffer = new gPixmap(eSize(region->region_width, region->region_height), 8); + //eDebug("new region_buffer %p", &(*region->region_buffer)); int region_level_of_compatibility, region_depth; @@ -487,6 +516,7 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) if (region_fill_flag) { + //eDebug("region fill region_buffer %p", &(*region->region_buffer)); if (region_depth == 1) memset(region->region_buffer->surface->data, region_2bit_pixel_code, region->region_height * region->region_width); else if (region_depth == 2) @@ -500,12 +530,11 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) //eDebug("region %02x, version %d, %dx%d", region->region_id, region->region_version_number, region->region_width, region->region_height); region->region_objects = 0; - struct subtitle_region_object **pobject = ®ion->region_objects; + subtitle_region_object **pobject = ®ion->region_objects; while (processed_length < segment_length) { - - struct subtitle_region_object *object; + subtitle_region_object *object; object = new subtitle_region_object; @@ -542,7 +571,7 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) case 0x12: // CLUT definition segment { int CLUT_id, CLUT_version_number; - struct subtitle_clut *clut, **pclut; + subtitle_clut *clut, **pclut; if (!page) break; @@ -575,11 +604,10 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) break; clut->CLUT_version_number=CLUT_version_number; - clut->size_2 = clut->size_4 = clut->size_8 = 0; - /* invalidate CLUT if updated. */ - if ((this->current_clut_page_id == page_id) && (this->current_clut_id == CLUT_id)) - this->current_clut_id = -1; + 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)); //eDebug("new clut"); while (processed_length < segment_length) @@ -612,29 +640,29 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) if (entry_CLUT_flag & 1) // 8bit { ASSERT(CLUT_entry_id < 256); - ++clut->size_8; 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 { ASSERT(CLUT_entry_id < 16); - ++clut->size_4; 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; } if (entry_CLUT_flag & 4) // 2bit { ASSERT(CLUT_entry_id < 4); - ++clut->size_2; 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; } //eDebug(" %04x %02x %02x %02x %02x", CLUT_entry_id, v_Y, v_Cb, v_Cr, v_T); } @@ -665,7 +693,7 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) bottom_field_data_blocklength = *segment++ << 8; bottom_field_data_blocklength |= *segment++; - //eDebug("%d / %d bytes", top_field_data_blocklength, bottom_field_data_blocklength); + eDebug("%d / %d bytes", top_field_data_blocklength, bottom_field_data_blocklength); processed_length += 4; i = 0; @@ -714,7 +742,7 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) } case 0x80: // end of display set segment { -// eDebug("end of display set segment"); + //eDebug("end of display set segment"); subtitle_redraw_all(); } case 0xFF: // stuffing @@ -728,9 +756,10 @@ int eDVBSubtitleParser::subtitle_process_segment(__u8 *segment) void eDVBSubtitleParser::subtitle_process_pes(__u8 *pkt, int len) { - eDebug("subtitle_process_pes"); - if (!extract_pts(show_time, pkt)) + eDebugNoNewLine("subtitle_process_pes"); + if (!extract_pts(m_show_time, pkt)) { + eDebug(" %lld", m_show_time); pkt += 6; len -= 6; // skip PES header pkt++; len--; @@ -762,82 +791,54 @@ void eDVBSubtitleParser::subtitle_process_pes(__u8 *pkt, int len) pkt += l; len -= l; } - // if (len && *pkt != 0xFF) - // eDebug("strange data at the end"); + if (len && *pkt != 0xFF) + eDebug("strange data at the end"); } else - eDebug("dvb subtitle packet without PTS.. ignore!!"); -} - -void eDVBSubtitleParser::subtitle_clear_screen() -{ - /* clear bbox */ - int y; - - //eDebug("BBOX clear %d:%d -> %d:%d", this->bbox_left, this->bbox_top, this->bbox_right, this->bbox_bottom); - - // do not draw when anyone has locked the - // framebuffer ( non enigma plugins... ) - this->bbox_right = 720; - if (this->bbox_right > this->bbox_left) - for (y=this->bbox_top; y < this->bbox_bottom; ++y) - ; // TODO fixmee clear subtitle screen - - this->bbox_right = 0; - this->bbox_left = this->screen_width; - this->bbox_top = this->screen_height; - this->bbox_bottom = 0; + eDebug("\ndvb subtitle packet without PTS.. ignore!!"); } void eDVBSubtitleParser::subtitle_redraw_all() { #if 1 - struct subtitle_page *page = this->pages; - if ( page ) - { - struct subtitle_page_region *region = page->page_regions; - if ( region ) - subtitle_clear_screen(); - } + subtitle_page *page = m_pages; while(page) { subtitle_redraw(page->page_id); page = page->next; } #else - subtitle_clear_screen(); - - struct subtitle_page *page = this->pages; - //eDebug("----------- end of display set"); - //eDebug("active pages:"); + subtitle_page *page = m_pages; + eDebug("----------- end of display set"); + eDebug("active pages:"); while (page) { - //eDebug(" page_id %02x", page->page_id); - //eDebug(" page_version_number: %d", page->page_version_number); - //eDebug(" active regions:"); + eDebug(" page_id %02x", page->page_id); + eDebug(" page_version_number: %d", page->page_version_number); + eDebug(" active regions:"); { - struct subtitle_page_region *region = page->page_regions; + subtitle_page_region *region = page->page_regions; while (region) { - //eDebug(" region_id: %04x", region->region_id); - //eDebug(" region_horizontal_address: %d", region->region_horizontal_address); - //eDebug(" region_vertical_address: %d", region->region_vertical_address); + eDebug(" region_id: %04x", region->region_id); + eDebug(" region_horizontal_address: %d", region->region_horizontal_address); + eDebug(" region_vertical_address: %d", region->region_vertical_address); region = region->next; } } subtitle_redraw(page->page_id); - //eDebug("defined regions:"); - struct subtitle_region *region = page->regions; + eDebug("defined regions:"); + subtitle_region *region = page->regions; while (region) { - //eDebug(" region_id %04x, version %d, %dx%d", region->region_id, region->region_version_number, region->region_width, region->region_height); + eDebug(" region_id %04x, version %d, %dx%d", region->region_id, region->region_version_number, region->region_width, region->region_height); - struct subtitle_region_object *object = region->region_objects; + subtitle_region_object *object = region->region_objects; while (object) { - //eDebug(" object %02x, type %d, %d:%d", object->object_id, object->object_type, object->object_horizontal_position, object->object_vertical_position); + eDebug(" object %02x, type %d, %d:%d", object->object_id, object->object_type, object->object_horizontal_position, object->object_vertical_position); object = object->next; } region = region->next; @@ -849,31 +850,30 @@ void eDVBSubtitleParser::subtitle_redraw_all() void eDVBSubtitleParser::subtitle_reset() { - while (struct subtitle_page *page = this->pages) + while (subtitle_page *page = m_pages) { /* free page regions */ while (page->page_regions) { - struct subtitle_page_region *p = page->page_regions->next; + subtitle_page_region *p = page->page_regions->next; delete page->page_regions; page->page_regions = p; } /* free regions */ while (page->regions) { - struct subtitle_region *region = page->regions; + subtitle_region *region = page->regions; while (region->region_objects) { - struct subtitle_region_object *obj = region->region_objects; + subtitle_region_object *obj = region->region_objects; region->region_objects = obj->next; delete obj; } if (region->region_buffer) { - if (region->region_buffer->surface) - delete region->region_buffer->surface; +// eDebug("no more need of region_buffer 2 %p", &(*region->region_buffer)); region->region_buffer=0; } @@ -884,21 +884,21 @@ void eDVBSubtitleParser::subtitle_reset() /* free CLUTs */ while (page->cluts) { - struct subtitle_clut *clut = page->cluts; + subtitle_clut *clut = page->cluts; page->cluts = clut->next; delete clut; } - this->pages = page->next; + m_pages = page->next; delete page; } } void eDVBSubtitleParser::subtitle_redraw(int page_id) { - struct subtitle_page *page = this->pages; + subtitle_page *page = m_pages; - //eDebug("displaying page id %d", page_id); +// eDebug("displaying page id %d", page_id); while (page) { @@ -912,15 +912,17 @@ void eDVBSubtitleParser::subtitle_redraw(int page_id) return; } - //eDebug("iterating regions.."); /* iterate all regions in this pcs */ - struct subtitle_page_region *region = page->page_regions; - while (region) + subtitle_page_region *region = page->page_regions; + + eDVBSubtitlePage Page; + Page.m_show_time = m_show_time; + for (; region; region=region->next) { - //eDebug("region %d", region->region_id); +// eDebug("region %d", region->region_id); /* find corresponding region */ - struct subtitle_region *reg = page->regions; + subtitle_region *reg = page->regions; while (reg) { if (reg->region_id == region->region_id) @@ -929,31 +931,22 @@ void eDVBSubtitleParser::subtitle_redraw(int page_id) } if (reg) { - int y; - //eDebug("copy region %d to %d, %d", region->region_id, region->region_horizontal_address, region->region_vertical_address); + if (reg->committed) + continue; +// eDebug("copy region %d to %d, %d", region->region_id, region->region_horizontal_address, region->region_vertical_address); int x0 = region->region_horizontal_address; int y0 = region->region_vertical_address; - int x1 = x0 + reg->region_width; - int y1 = y0 + reg->region_height; - if ((x0 < 0) || (y0 < 0) || (x0 > this->screen_width) || (x0 > this->screen_height)) + if ((x0 < 0) || (y0 < 0)) + { +// eDebug("x0 %d, y0 %d", +// x0, y0); continue; - - /* adjust bbox */ - if (x0 < this->bbox_left) - this->bbox_left = x0; - if (y0 < this->bbox_top) - this->bbox_top = y0; - if (x1 > this->bbox_right) - this->bbox_right = x1; - if (y1 > this->bbox_bottom) - this->bbox_bottom = y1; - - int timeout = page->page_time_out; + } /* find corresponding clut */ - struct subtitle_clut *clut = page->cluts; + subtitle_clut *clut = page->cluts; while (clut) { //eDebug("have %d, want %d", clut->clut_id, main_clut_id); @@ -961,29 +954,176 @@ void eDVBSubtitleParser::subtitle_redraw(int page_id) break; clut = clut->next; } - if (clut) + + int clut_size = reg->region_buffer->surface->clut.colors = reg->region_depth == subtitle_region::bpp2 ? + 4 : reg->region_depth == subtitle_region::bpp4 ? 16 : 256; + + reg->region_buffer->surface->clut.data = new gRGB[clut_size]; +// eDebug("create clut data for region_buffer %p", &(*reg->region_buffer)); + + gRGB *palette = reg->region_buffer->surface->clut.data; + + subtitle_clut_entry *entries=0; + switch(reg->region_depth) { - // TODO fill region->surface->clut !!!!! + case subtitle_region::bpp2: +// eDebug("2BPP"); + entries = clut->entries_2bit; + memset(palette, 0, 4*sizeof(gRGB)); + 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: +// eDebug("4BPP"); + entries = clut->entries_4bit; + memset(palette, 0, 16*sizeof(gRGB)); + for (int i=0; i < 16; ++i) + { + if (!i) + palette[i].a = 0xFF; + else if (i & 1) + { + if (i & 8) + palette[i].r = 0x80; + if (i & 4) + palette[i].g = 0x80; + if (i & 2) + palette[i].b = 0x80; + } + else + { + if (i & 8) + palette[i].r = 0xFF; + if (i & 4) + palette[i].g = 0xFF; + if (i & 2) + palette[i].b = 0xFF; + } + } + break; + case subtitle_region::bpp8: +// eDebug("8BPP"); + entries = clut->entries_8bit; + memset(palette, 0, 16*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% + // fall through!! + 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; } - else + + if (clut) { - // apply default clut depending on region->region_depth - // TODO fill region->surface->clut !!!!! + 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 = MAX(MIN(((298 * y + 543 * cb ) / 256), 255), 0); + palette[i].a = (entries[i].T) & 0xFF; +// eDebug("override clut entry %d RGBA %02x%02x%02x%02x", i, +// palette[i].r, palette[i].g, palette[i].b, palette[i].a); + } + else + { +// eDebug("mist %d", i); + palette[i].r = 0; + palette[i].g = 0; + palette[i].b = 0; + palette[i].a = 0xFF; + } + } + } } - // TODO Blit Region Pixmap !!! - eDebug("blit region"); + +// eDebug("commit region_buffer %p", &(*reg->region_buffer)); + eDVBSubtitleRegion Region; + Region.m_pixmap = reg->region_buffer; + Region.m_position.setX(x0); + Region.m_position.setY(y0); + Page.m_regions.push_back(Region); + reg->committed = true; } else eDebug("region not found"); - region = region->next; } + m_new_subtitle_page(Page); + Page.m_regions.clear(); +// eDebug("page timeout is %d", page->page_time_out); +// Page.m_show_time += (page->page_time_out * 90000); +// m_new_subtitle_page(Page); //eDebug("schon gut."); } DEFINE_REF(eDVBSubtitleParser); eDVBSubtitleParser::eDVBSubtitleParser(iDVBDemux *demux) - :pages(0) + :m_pages(0) { setStreamID(0xBD); @@ -998,18 +1138,30 @@ eDVBSubtitleParser::~eDVBSubtitleParser() subtitle_reset(); } -int eDVBSubtitleParser::start(int pid) +int eDVBSubtitleParser::stop() { -#if 0 - eDebug("eDVBSubtitleParser::start(%04x)", pid); if (m_pes_reader) + { + eDebug("disable dvb subtitles"); + return m_pes_reader->stop(); + } + return -1; +} + +int eDVBSubtitleParser::start(int pid, int composition_page_id, int ancillary_page_id) +{ + if (m_pes_reader) + { + eDebug("start dvb subtitles on pid 0x%04x with composition_page_id %d and ancillary_page_id %d", + pid, composition_page_id, ancillary_page_id); + m_composition_page_id = composition_page_id; + m_ancillary_page_id = ancillary_page_id; return m_pes_reader->start(pid); - else - return -1; -#endif + } + return -1; } -void eDVBSubtitleParser::connectNewRegion(const Slot1 &slot, ePtr &connection) +void eDVBSubtitleParser::connectNewPage(const Slot1 &slot, ePtr &connection) { - connection = new eConnection(this, m_new_subtitle_region.connect(slot)); + connection = new eConnection(this, m_new_subtitle_page.connect(slot)); }