#include <lib/base/eerror.h>
#include <lib/gdi/gpixmap.h>
-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;
bit->consumed = 0;
}
-int bitstream_get(struct bitstream *bit)
+int bitstream_get(bitstream *bit)
{
int val;
bit->avail -= bit->size;
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_region *region, subtitle_region_object *object, int line, __u8 *data, int len)
{
- struct subtitle_region *region = page->regions;
-// eDebug("line for %d:%d", page->page_id, object_id);
- while (region)
+ int x = object->object_horizontal_position;
+ int y = object->object_vertical_position + line;
+ if (x + len > region->width)
{
- struct subtitle_region_object *object = region->region_objects;
- while (object)
- {
- if (object->object_id == object_id)
- {
- int x = object->object_horizontal_position;
- int y = object->object_vertical_position + line;
- if (x + len > region->region_width)
- {
- //eDebug("[SUB] !!!! XCLIP %d + %d > %d", x, len, region->region_width);
- len = region->region_width - x;
- }
- if (len < 0)
- break;
- if (y >= region->region_height)
- {
- //eDebug("[SUB] !!!! YCLIP %d >= %d", y, region->region_height);
- break;
- }
-// //eDebug("inserting %d bytes (into region %d)", len, region->region_id);
- memcpy((__u8*)region->region_buffer->surface->data + region->region_width * y + x, data, len);
- }
- object = object->next;
- }
- region = region->next;
+// eDebug("[SUB] !!!! XCLIP %d + %d > %d", x, len, region->width);
+ len = region->width - x;
}
+ if (len < 0)
+ return;
+ if (y >= region->height)
+ {
+// eDebug("[SUB] !!!! YCLIP %d >= %d", y, region->height);
+ return;
+ }
+// eDebug("inserting %d bytes (into region %d)", len, region->region_id);
+// eDebug("put data to buffer %p", &(*region->buffer));
+ memcpy((__u8*)region->buffer->surface->data + region->buffer->surface->stride * y + x, data, len);
}
-int eDVBSubtitleParser::subtitle_process_pixel_data(struct subtitle_page *page, int object_id, int *linenr, int *linep, __u8 *data)
+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 eDVBSubtitleParser::subtitle_process_pixel_data(subtitle_region *region, subtitle_region_object *object, int *linenr, int *linep, __u8 *data)
{
int data_type = *data++;
- static __u8 line[720];
+ static __u8 line[1920];
- struct bitstream bit;
+ bitstream bit;
bit.size=0;
switch (data_type)
{
case 0x10: // 2bit pixel data
+// eDebug("2bit pixel data!");
bitstream_init(&bit, data, 2);
while (1)
{
col = bitstream_get(&bit);
}
}
- while (len && ((*linep) < 720))
+ 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)++] = col;
+ line[(*linep)++] = c;
len--;
}
}
bitstream_get(&bit);
return bit.consumed + 1;
case 0x11: // 4bit pixel data
+// eDebug("4bit pixel data!");
bitstream_init(&bit, data, 4);
while (1)
{
col = bitstream_get(&bit);
}
}
- while (len && ((*linep) < 720))
+ 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)++] = col;
+ line[(*linep)++] = c;
len--;
}
}
bitstream_get(&bit);
return bit.consumed + 1;
case 0x12: // 8bit pixel data
+// eDebug("8bit pixel data!");
bitstream_init(&bit, data, 8);
while(1)
{
} else
break;
}
- while (len && ((*linep) < 720))
+ while (len && ((*linep) < m_display_size.width()))
{
line[(*linep)++] = col;
len--;
}
}
return bit.consumed + 1;
- case 0x20: // ignore 2 -> 4bit map table
+ case 0x20:
+// eDebugNoNewLine("2 -> 4 bit table: ");
bitstream_init(&bit, data, 4);
for ( int i=0; i < 4; ++i )
- bitstream_get(&bit);
- break;
- case 0x21: // ignore 2 -> 8bit map table
+ {
+ map_2_to_4_bit_table[i] = bitstream_get(&bit);
+// eDebugNoNewLine("%d ", map_2_to_4_bit_table[i]);
+ }
+ eDebug("");
+ return bit.consumed + 1;
+ case 0x21:
+// eDebugNoNewLine("2 -> 8 bit table: ");
bitstream_init(&bit, data, 8);
for ( int i=0; i < 4; ++i )
- bitstream_get(&bit);
- break;
- case 0x22: // ignore 4 -> 8bit map table
+ {
+ map_2_to_8_bit_table[i] = bitstream_get(&bit);
+// eDebugNoNewLine("%d ", map_2_to_8_bit_table[i]);
+ }
+ return bit.consumed + 1;
+ case 0x22:
+// eDebug("4 -> 8 bit table!");
bitstream_init(&bit, data, 8);
for ( int i=0; i < 16; ++i )
- bitstream_get(&bit);
- break;
+ {
+ map_4_to_8_bit_table[i] = bitstream_get(&bit);
+// eDebugNoNewLine("%d ", map_4_to_8_bit_table[i]);
+ }
+ return bit.consumed + 1;
case 0xF0:
- subtitle_process_line(page, object_id, *linenr, line, *linep);
+ subtitle_process_line(region, object, *linenr, line, *linep);
/* {
int i;
- for (i=0; i<720; ++i)
- //eDebugNoNewLine("%d ", line[i]);
- //eDebug("");
+ for (i=0; i<m_display_size.width(); ++i)
+ eDebugNoNewLine("%d ", line[i]);
+ eDebug("");
} */
(*linenr)+=2; // interlaced
*linep = 0;
-// //eDebug("[SUB] EOL");
+// eDebug("[SUB] EOL");
return 1;
default:
eDebug("subtitle_process_pixel_data: invalid data_type %02x", data_type);
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)
{
int page_time_out = *segment++; processed_length++;
int page_version_number = *segment >> 4;
int page_state = (*segment >> 2) & 0x3;
- //eDebug("pcs with %d bytes data (%d:%d:%d)", segment_length, page_id, page_version_number, page_state);
+// eDebug("pcs with %d bytes data (%d:%d:%d)", segment_length, page_id, page_version_number, page_state);
segment++;
processed_length++;
- //eDebug("page time out: %d", page_time_out);
- //eDebug("page_version_number: %d" ,page_version_number);
- //eDebug("page_state: %d", page_state);
+// eDebug("page time out: %d", page_time_out);
+// eDebug("page_version_number: %d" ,page_version_number);
+// eDebug("page_state: %d", page_state);
if (!page)
{
- //eDebug("page not found");
+// eDebug("page not found");
page = new subtitle_page;
page->page_regions = 0;
page->regions = 0;
// if no update, just skip this data.
if (page->page_version_number == page_version_number)
{
- eDebug("skip data... ");
+// eDebug("skip data... ");
break;
}
}
+ page->state = page_state;
+
// 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->objects)
+ {
+// eDebug("delete region object");
+ subtitle_region_object *ob = page->regions->objects->next;
+ delete page->regions->objects;
+ page->regions->objects = ob;
+ }
+ delete page->regions;
+ page->regions = p;
+ }
+
}
// eDebug("new page.. (%d)", page_state);
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);
+// eDebug("%d / %d data left", processed_length, segment_length);
// go to last entry
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;
pr->region_vertical_address |= *segment++;
processed_length += 2;
- //eDebug("appended active region");
+// eDebug("appended active region");
}
if (processed_length != segment_length)
case 0x11: // region composition segment
{
int region_id = *segment++; processed_length++;
- int region_version_number = *segment >> 4;
+ int version_number = *segment >> 4;
int region_fill_flag = (*segment >> 3) & 1;
segment++; processed_length++;
break;
}
- struct subtitle_region *region, **pregion;
+ subtitle_region *region, **pregion;
region = page->regions; pregion = &page->regions;
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)
+ else if (region->version_number != version_number)
{
- struct subtitle_region_object *objects = region->region_objects;
+ subtitle_region_object *objects = 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->buffer)
{
- if (region->region_buffer->surface)
- delete region->region_buffer->surface;
- region->region_buffer=0;
+// eDebug("no more need of buffer %p", &(*region->buffer));
+ region->buffer=0;
}
+ region->committed = false;
}
else
break;
- //eDebug("region %d:%d update", page_id, region_id);
+// eDebug("region %d:%d update", page_id, region_id);
region->region_id = region_id;
- region->region_version_number = region_version_number;
+ region->version_number = version_number;
- region->region_width = *segment++ << 8;
- region->region_width |= *segment++;
+ region->width = *segment++ << 8;
+ region->width |= *segment++;
processed_length += 2;
- region->region_height = *segment++ << 8;
- region->region_height |= *segment++;
+ region->height = *segment++ << 8;
+ region->height |= *segment++;
processed_length += 2;
- region->region_buffer = new gPixmap(eSize(region->region_width, region->region_height), 8);
+ region->buffer = new gPixmap(eSize(region->width, region->height), 8, 1);
+ memset(region->buffer->surface->data, 0, region->height * region->buffer->surface->stride);
+// eDebug("new buffer %p", &(*region->buffer));
- int region_level_of_compatibility, region_depth;
+ int region_level_of_compatibility, depth;
region_level_of_compatibility = (*segment >> 5) & 7;
- region_depth = (*segment++ >> 2) & 7;
- region->region_depth = (subtitle_region::depth) region_depth;
+ depth = (*segment++ >> 2) & 7;
+
+ region->depth = (subtitle_region::tDepth) depth;
processed_length++;
int CLUT_id = *segment++; processed_length++;
if (region_fill_flag)
{
- 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)
- memset(region->region_buffer->surface->data, region_4bit_pixel_code, region->region_height * region->region_width);
- else if (region_depth == 3)
- memset(region->region_buffer->surface->data, region_8bit_pixel_code, region->region_height * region->region_width);
+// eDebug("region fill buffer %p", &(*region->buffer));
+ 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("!!!! invalid depth");
}
- //eDebug("region %02x, version %d, %dx%d", region->region_id, region->region_version_number, region->region_width, region->region_height);
+// eDebug("region %02x, version %d, %dx%d", region->region_id, region->version_number, region->width, region->height);
- region->region_objects = 0;
- struct subtitle_region_object **pobject = ®ion->region_objects;
+ region->objects = 0;
+ subtitle_region_object **pobject = ®ion->objects;
while (processed_length < segment_length)
{
-
- struct subtitle_region_object *object;
+ subtitle_region_object *object;
object = new subtitle_region_object;
case 0x12: // CLUT definition segment
{
int CLUT_id, CLUT_version_number;
- struct subtitle_clut *clut, **pclut;
+ subtitle_clut *clut, **pclut;
if (!page)
break;
- //eDebug("CLUT: %02x", *segment);
+// eDebug("CLUT: %02x", *segment);
CLUT_id = *segment++;
CLUT_version_number = *segment++ >> 4;
processed_length += 2;
- //eDebug("page %d, CLUT %02x, version %d", page->page_id, CLUT_id, CLUT_version_number);
+// eDebug("page %d, CLUT %02x, version %d", page->page_id, CLUT_id, CLUT_version_number);
clut = page->cluts; pclut = &page->cluts;
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");
+// eDebug("new Clut!");
while (processed_length < segment_length)
{
int CLUT_entry_id, entry_CLUT_flag, full_range;
if (full_range)
{
+// eDebugNoNewLine("f");
v_Y = *segment++;
v_Cr = *segment++;
v_Cb = *segment++;
processed_length += 4;
} else
{
+// eDebugNoNewLine(" ");
v_Y = *segment & 0xFC;
v_Cr = (*segment++ & 3) << 6;
v_Cr |= (*segment & 0xC0) >> 2;
if (entry_CLUT_flag & 1) // 8bit
{
- ASSERT(CLUT_entry_id < 256);
- ++clut->size_8;
+// eDebugNoNewLine("8b");
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;
+// eDebugNoNewLine("4b");
+ 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("CLUT entry marked as 4 bit with id %d (>15)", CLUT_entry_id);
}
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;
+// eDebugNoNewLine("2b");
+ 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("CLUT entry marked as 2 bit with id %d (>3)", CLUT_entry_id);
}
- //eDebug(" %04x %02x %02x %02x %02x", CLUT_entry_id, v_Y, v_Cb, v_Cr, v_T);
+// eDebug(" %04x %02x %02x %02x %02x", CLUT_entry_id, v_Y, v_Cb, v_Cr, v_T);
}
break;
}
non_modifying_color_flag = (*segment++ >> 1) & 1;
processed_length++;
- //eDebug("object id %04x, version %d, object_coding_method %d (page_id %d)", object_id, object_version_number, object_coding_method, page_id);
-
- if (object_coding_method == 0)
+// eDebug("object id %04x, version %d, object_coding_method %d (page_id %d)", object_id, object_version_number, object_coding_method, page_id);
+ subtitle_region *region = page->regions;
+// eDebug("line for %d:%d", page->page_id, object_id);
+ while (region)
{
- int top_field_data_blocklength, bottom_field_data_blocklength;
- int i, line, linep;
-
- top_field_data_blocklength = *segment++ << 8;
- top_field_data_blocklength |= *segment++;
-
- bottom_field_data_blocklength = *segment++ << 8;
- bottom_field_data_blocklength |= *segment++;
- //eDebug("%d / %d bytes", top_field_data_blocklength, bottom_field_data_blocklength);
- processed_length += 4;
-
- i = 0;
- line = 0;
- linep = 0;
- while (i < top_field_data_blocklength)
- {
- int len;
- len = subtitle_process_pixel_data(page, object_id, &line, &linep, segment);
- if (len < 0)
- return -1;
- segment += len;
- processed_length += len;
- i += len;
- }
-
- line = 1;
- linep = 0;
-
- if (bottom_field_data_blocklength)
+ subtitle_region_object *object = region->objects;
+ while (object)
{
- i = 0;
- while (i < bottom_field_data_blocklength)
+ if (object->object_id == object_id)
{
- int len;
- len = subtitle_process_pixel_data(page, object_id, &line, &linep, segment);
- if (len < 0)
- return -1;
- segment += len;
- processed_length += len;
- i += len;
+ 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++;
+// eDebug("%d / %d bytes", top_field_data_blocklength, bottom_field_data_blocklength);
+ 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)
+ return -1;
+ 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)
+ return -1;
+ segment += len;
+ processed_length += len;
+ i += len;
+ }
+ }
+ else if (top_field_data_blocklength)
+ eDebug("!!!! 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("---- object_coding_method 1 unsupported!");
}
+ object = object->next;
}
- else if (top_field_data_blocklength)
- eDebug("!!!! unimplemented: no bottom field! (%d : %d)", top_field_data_blocklength, bottom_field_data_blocklength);
-
- if ((top_field_data_blocklength + bottom_field_data_blocklength) & 1)
+ region = region->next;
+ }
+ break;
+ }
+ case 0x14: // display definition segment
+ {
+ if (segment_length > 4)
+ {
+ int dds_version_number = segment[0] >> 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]);
+// eDebug("version %d, window_flag %d, display_width %d, display_height %d",
+// dds_version_number, display_window_flag, display_width, display_height);
+ processed_length += 5;
+ m_display_size = eSize(display_width+1, display_height+1);
+ if (display_window_flag)
{
- segment++; processed_length++;
+ if (segment_length > 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("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("display window flag set but display definition segment to short %d!", segment_length);
}
}
- else if (object_coding_method == 1)
- eDebug("---- object_coding_method 1 unsupported!");
-
+ else
+ eDebug("display definition segment to short %d!", segment_length);
break;
}
case 0x80: // end of display set segment
{
// eDebug("end of display set segment");
subtitle_redraw_all();
+ m_seen_eod = true;
}
case 0xFF: // stuffing
break;
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--;
if (*pkt != 0x20)
{
- //eDebug("data identifier is 0x%02x, but not 0x20", *pkt);
+// eDebug("data identifier is 0x%02x, but not 0x20", *pkt);
return;
}
pkt++; len--; // data identifier
if (len <= 0)
{
- //eDebug("no data left (%d)", len);
+// eDebug("no data left (%d)", len);
return;
}
+ m_seen_eod = false;
+
while (len && *pkt == 0x0F)
{
int l = subtitle_process_segment(pkt);
pkt += l;
len -= l;
}
- // 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;
+ if (len && *pkt != 0xFF)
+ eDebug("strange data at the end");
+
+ if (!m_seen_eod)
+ subtitle_redraw_all();
+ }
+// else
+// eDebug("");
}
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);
+ if (page->state != 0)
+ 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->version_number, region->width, region->height);
- struct subtitle_region_object *object = region->region_objects;
+ subtitle_region_object *object = 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;
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)
+ while (region->objects)
{
- struct subtitle_region_object *obj = region->region_objects;
- region->region_objects = obj->next;
+ subtitle_region_object *obj = region->objects;
+ region->objects = obj->next;
delete obj;
}
- if (region->region_buffer)
+ if (region->buffer)
{
- if (region->region_buffer->surface)
- delete region->region_buffer->surface;
- region->region_buffer=0;
+// eDebug("no more need of buffer 2 %p", &(*region->buffer));
+ region->buffer=0;
}
page->regions = region->next;
/* 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)
{
}
if (!page)
{
- //eDebug("page not found");
+// eDebug("page not found");
return;
}
-
- //eDebug("iterating regions..");
+// 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)
}
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);
+// eDebug("have %d, want %d", clut->clut_id, main_clut_id);
if (clut->clut_id == reg->clut_id)
break;
clut = clut->next;
}
- if (clut)
+
+ 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];
+// eDebug("create clut data for buffer %p", &(*reg->buffer));
+
+ gRGB *palette = reg->buffer->surface->clut.data;
+
+// if (!clut)
+// eDebug("no CLUT.. use default");
+
+ subtitle_clut_entry *entries=0;
+ switch(reg->depth)
{
- // TODO fill region->surface->clut !!!!!
+ case subtitle_region::bpp2:
+// eDebug("2BPP");
+ if (clut)
+ entries = clut->entries_2bit;
+ memset(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...
+// eDebug("4BPP");
+ if (clut)
+ 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 & 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
+// eDebug("8BPP");
+ if (clut)
+ entries = clut->entries_8bit;
+ memset(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%
+ // 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
+
+ for (int i=0; i<clut_size; ++i)
{
- // apply default clut depending on region->region_depth
- // TODO fill region->surface->clut !!!!!
+ if (entries && entries[i].valid)
+ {
+ int y = entries[i].Y,
+ cr = entries[i].Cr,
+ cb = entries[i].Cb;
+ if (y > 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: y %d cr %d cb %d", i, y, cr, cb);
+ palette[i].r = 0;
+ palette[i].g = 0;
+ palette[i].b = 0;
+ palette[i].a = 0xFF;
+ }
+ }
+// eDebug("%d:%c %02x %02x %02x %02x",
+// i, entries && entries[i].valid ? 'O': 'D', palette[i].r, palette[i].g, palette[i].b, palette[i].a);
}
- // TODO Blit Region Pixmap !!!
- eDebug("blit region");
+
+// eDebug("commit buffer %p", &(*reg->buffer));
+ 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;
}
- else
- eDebug("region not found");
- region = region->next;
+// else
+// eDebug("region not found");
}
- //eDebug("schon gut.");
+ Page.m_display_size = m_display_size;
+ 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)
+ :m_pages(0), m_display_size(720,576)
{
setStreamID(0xBD);
subtitle_reset();
}
-int eDVBSubtitleParser::start(int pid)
+int eDVBSubtitleParser::stop()
+{
+ 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 0
- eDebug("eDVBSubtitleParser::start(%04x)", pid);
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<void, const eDVBSubtitleRegion&> &slot, ePtr<eConnection> &connection)
+void eDVBSubtitleParser::connectNewPage(const Slot1<void, const eDVBSubtitlePage&> &slot, ePtr<eConnection> &connection)
{
- connection = new eConnection(this, m_new_subtitle_region.connect(slot));
+ connection = new eConnection(this, m_new_subtitle_page.connect(slot));
}