From 99a647653d93a343a9d768d6b5940252c29a9c94 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Fri, 14 May 2010 23:51:34 +0300 Subject: cosmetics (removed tabs, ...) removed unused code added enum for segment type added missing lf's to log strings --- src/libspuhdmv/xine_hdmv_decoder.c | 134 ++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 68 deletions(-) diff --git a/src/libspuhdmv/xine_hdmv_decoder.c b/src/libspuhdmv/xine_hdmv_decoder.c index be5e6b638..d37e8d101 100644 --- a/src/libspuhdmv/xine_hdmv_decoder.c +++ b/src/libspuhdmv/xine_hdmv_decoder.c @@ -46,9 +46,18 @@ #endif #define XINE_HDMV_TRACE(x...) printf(x) -/*#define TRACE(x...) */ +/*#define XINE_HDMV_TRACE(x...) */ #define XINE_HDMV_ERROR(x...) fprintf(stderr, "spuhdmv: " x) -/*#define ERROR(x...) lprintf(x) */ +/*#define XINE_HDMV_ERROR(x...) lprintf(x) */ + +enum { + SEGTYPE_PALETTE = 0x14, + SEGTYPE_OBJECT = 0x15, + SEGTYPE_PRESENTATION_SEGMENT = 0x16, + SEGTYPE_WINDOW_DEFINITION = 0x17, + SEGTYPE_INTERACTIVE = 0x18, + SEGTYPE_END_OF_DISPLAY = 0x80, +} eSegmentType; /* * cached palette (xine-lib format) @@ -72,6 +81,7 @@ struct subtitle_object_s { uint16_t xpos, ypos; uint16_t width, height; + /* xine format */ rle_elem_t *rle; unsigned int num_rle; size_t data_size; @@ -149,27 +159,27 @@ struct presentation_segment_s { */ #define LIST_REPLACE(list, obj, FREE_FUNC) \ - do { \ - unsigned int id = obj->id; \ - \ - /* insert to list */ \ - obj->next = list; \ - list = obj; \ - \ - /* remove old */ \ - while (obj->next && obj->next->id != id) \ - obj = obj->next; \ - if (obj->next) { \ - void *tmp = (void*)obj->next; \ - obj->next = obj->next->next; \ - FREE_FUNC(tmp); \ - } \ + do { \ + unsigned int id = obj->id; \ + \ + /* insert to list */ \ + obj->next = list; \ + list = obj; \ + \ + /* remove old */ \ + while (obj->next && obj->next->id != id) \ + obj = obj->next; \ + if (obj->next) { \ + void *tmp = (void*)obj->next; \ + obj->next = obj->next->next; \ + FREE_FUNC(tmp); \ + } \ } while (0); #define LIST_DESTROY(list, FREE_FUNC) \ - while (list) { \ + while (list) { \ void *tmp = (void*)list; \ - list = list->next; \ + list = list->next; \ FREE_FUNC(tmp); \ } @@ -250,8 +260,8 @@ static void segbuf_parse_segment_header(segment_buffer_t *buf) buf->error = 0; if ( buf->segment_type < 0x14 || - ( buf->segment_type > 0x18 && - buf->segment_type != 0x80)) { + ( buf->segment_type > 0x18 && + buf->segment_type != 0x80)) { XINE_HDMV_ERROR("unknown segment type, resetting\n"); segbuf_reset(buf); } @@ -294,7 +304,7 @@ static void segbuf_skip_segment(segment_buffer_t *buf) XINE_HDMV_TRACE(" skip_segment: %zd bytes left\n", buf->len); } else { XINE_HDMV_ERROR(" skip_segment: ERROR - %zd bytes queued, %d required\n", - buf->len, buf->segment_len); + buf->len, buf->segment_len); segbuf_reset (buf); } } @@ -319,7 +329,7 @@ static uint8_t segbuf_get_u8(segment_buffer_t *buf) { if (!(buf->error = ++buf->segment_data > buf->segment_end)) return buf->segment_data[-1]; - XINE_HDMV_ERROR("segbuf_get_u8: read failed (end of segment reached) !"); + XINE_HDMV_ERROR("segbuf_get_u8: read failed (end of segment reached) !\n"); return 0; } @@ -333,19 +343,6 @@ static uint32_t segbuf_get_u24(segment_buffer_t *buf) return (segbuf_get_u8(buf) << 16) | (segbuf_get_u8(buf) << 8) | segbuf_get_u8(buf); } -static uint8_t *segbuf_get_string(segment_buffer_t *buf, size_t len) -{ - if (len > 0) { - uint8_t *val = buf->segment_data; - buf->segment_data += len; - if (buf->segment_data <= buf->segment_end) - return val; - } - XINE_HDMV_ERROR("segbuf_get_string(%zd): read failed (end of segment reached) !", len); - buf->error = 1; - return NULL; -} - /* * decode segments */ @@ -364,11 +361,11 @@ static subtitle_clut_t *segbuf_decode_palette(segment_buffer_t *buf) if (len % 5) { XINE_HDMV_ERROR(" decode_palette: segment size error (%zd ; expected %zd for %zd entries)\n", - len, (5 * entries), entries); + len, (5 * entries), entries); return NULL; } XINE_HDMV_TRACE("decode_palette: %zd items (id %d, version %d)\n", - entries, palette_id, palette_version_number); + entries, palette_id, palette_version_number); /* convert to xine-lib clut */ subtitle_clut_t *clut = calloc(1, sizeof(subtitle_clut_t)); @@ -409,17 +406,17 @@ static int segbuf_decode_rle(segment_buffer_t *buf, subtitle_object_t *obj) } else { byte = segbuf_get_u8 (buf); if (!(byte & 0x80)) { - rlep->color = 0; - if (!(byte & 0x40)) - rlep->len = byte & 0x3f; - else - rlep->len = ((byte & 0x3f) << 8) | segbuf_get_u8 (buf); + rlep->color = 0; + if (!(byte & 0x40)) + rlep->len = byte & 0x3f; + else + rlep->len = ((byte & 0x3f) << 8) | segbuf_get_u8 (buf); } else { - if (!(byte & 0x40)) - rlep->len = byte & 0x3f; - else - rlep->len = ((byte & 0x3f) << 8) | segbuf_get_u8 (buf); - rlep->color = segbuf_get_u8 (buf); + if (!(byte & 0x40)) + rlep->len = byte & 0x3f; + else + rlep->len = ((byte & 0x3f) << 8) | segbuf_get_u8 (buf); + rlep->color = segbuf_get_u8 (buf); } } @@ -431,10 +428,10 @@ static int segbuf_decode_rle(segment_buffer_t *buf, subtitle_object_t *obj) } else { /* end of line marker (00 00) */ if (x < obj->width) { - rlep->len = obj->width - x; - rlep->color = 0xff; - rlep++; - obj->num_rle ++; + rlep->len = obj->width - x; + rlep->color = 0xff; + rlep++; + obj->num_rle ++; } x = 0; y++; @@ -501,7 +498,7 @@ static window_def_t *segbuf_decode_window_definition(segment_buffer_t *buf) wnd->height = segbuf_get_u16 (buf); XINE_HDMV_TRACE(" window: [%02x %d] %d,%d %dx%d\n", a, - wnd->id, wnd->xpos, wnd->ypos, wnd->width, wnd->height); + wnd->id, wnd->xpos, wnd->ypos, wnd->width, wnd->height); if (buf->error) { free(wnd); @@ -518,6 +515,7 @@ static int segbuf_decode_video_descriptor(segment_buffer_t *buf) uint8_t frame_rate = segbuf_get_u8 (buf); XINE_HDMV_TRACE(" video_descriptor: %dx%d fps %d\n", width, height, frame_rate); + return buf->error; } @@ -556,8 +554,8 @@ static composition_object_t *segbuf_decode_composition_object(segment_buffer_t * } XINE_HDMV_TRACE(" composition_object: id: %d, win: %d, position %d,%d crop %d forced %d\n", - cobj->object_id_ref, cobj->window_id_ref, cobj->xpos, cobj->ypos, - cobj->cropped_flag, cobj->forced_flag); + cobj->object_id_ref, cobj->window_id_ref, cobj->xpos, cobj->ypos, + cobj->cropped_flag, cobj->forced_flag); return cobj; } @@ -575,7 +573,7 @@ static presentation_segment_t *segbuf_decode_presentation_segment(segment_buffer seg->object_number = segbuf_get_u8 (buf); XINE_HDMV_TRACE(" presentation_segment: object_number %d, palette %d\n", - seg->object_number, seg->palette_id_ref); + seg->object_number, seg->palette_id_ref); for (index = 0; index < seg->object_number; index++) { composition_object_t *cobj = segbuf_decode_composition_object (buf); @@ -682,7 +680,7 @@ static int decode_presentation_segment(spuhdmv_decoder_t *this) } static int show_overlay(spuhdmv_decoder_t *this, composition_object_t *cobj, unsigned int palette_id_ref, - int overlay_index, int64_t pts, int force_update) + int overlay_index, int64_t pts, int force_update) { video_overlay_manager_t *ovl_manager = this->stream->video_out->get_overlay_manager(this->stream->video_out); metronom_t *metronom = this->stream->metronom; @@ -746,7 +744,7 @@ static int show_overlay(spuhdmv_decoder_t *this, composition_object_t *cobj, uns overlay.hili_right = -1; XINE_HDMV_TRACE(" -> overlay: %d,%d %dx%d\n", - overlay.x, overlay.y, overlay.width, overlay.height); + overlay.x, overlay.y, overlay.width, overlay.height); /* set timings */ @@ -843,36 +841,36 @@ static void free_objs(spuhdmv_decoder_t *this) static void decode_segment(spuhdmv_decoder_t *this) { - XINE_HDMV_TRACE("*** new segment, pts %010ld: 0x%02x (%8d bytes)", - this->pts, this->buf->segment_type, this->buf->segment_len); + XINE_HDMV_TRACE("*** new segment, pts %010"PRId64": 0x%02x (%8d bytes)\n", + this->pts, this->buf->segment_type, this->buf->segment_len); - switch (this->buf->segment_type) { - case 0x14: + switch (segbuf_segment_type(this->buf)) { + case SEGTYPE_PALETTE: XINE_HDMV_TRACE(" segment: PALETTE\n"); decode_palette(this); break; - case 0x15: + case SEGTYPE_OBJECT: XINE_HDMV_TRACE(" segment: OBJECT\n"); decode_object(this); break; - case 0x16: + case SEGTYPE_PRESENTATION_SEGMENT: XINE_HDMV_TRACE(" segment: PRESENTATION SEGMENT\n"); decode_presentation_segment(this); break; - case 0x17: + case SEGTYPE_WINDOW_DEFINITION: XINE_HDMV_TRACE(" segment: WINDOW DEFINITION\n"); decode_window_definition(this); break; - case 0x18: + case SEGTYPE_INTERACTIVE: XINE_HDMV_TRACE(" segment: INTERACTIVE\n"); break; - case 0x80: + case SEGTYPE_END_OF_DISPLAY: XINE_HDMV_TRACE(" segment: END OF DISPLAY\n"); /* drop all cached objects */ free_objs(this); break; default: - XINE_HDMV_ERROR(" segment type 0x%x unknown, skipping\n", this->buf->segment_type); + XINE_HDMV_ERROR(" segment type 0x%x unknown, skipping\n", segbuf_segment_type(this->buf)); break; } if (this->buf->error) { -- cgit v1.2.3 From 643449db9e16266e3d110c8e22d46f3b6cb9fd92 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Fri, 14 May 2010 23:55:20 +0300 Subject: object id is uint16_t --- src/libspuhdmv/xine_hdmv_decoder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libspuhdmv/xine_hdmv_decoder.c b/src/libspuhdmv/xine_hdmv_decoder.c index d37e8d101..955581d88 100644 --- a/src/libspuhdmv/xine_hdmv_decoder.c +++ b/src/libspuhdmv/xine_hdmv_decoder.c @@ -118,7 +118,7 @@ struct window_def_s { typedef struct composition_object_s composition_object_t; struct composition_object_s { uint8_t window_id_ref; - uint8_t object_id_ref; + uint16_t object_id_ref; uint16_t xpos, ypos; @@ -450,7 +450,7 @@ static int segbuf_decode_rle(segment_buffer_t *buf, subtitle_object_t *obj) static subtitle_object_t *segbuf_decode_object(segment_buffer_t *buf) { - uint8_t object_id = segbuf_get_u16(buf); + uint16_t object_id = segbuf_get_u16(buf); uint8_t version = segbuf_get_u8 (buf); uint8_t seq_desc = segbuf_get_u8 (buf); -- cgit v1.2.3 From 3a4b7fe01fbf114a09867717ef0e86bb43330f04 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Fri, 14 May 2010 23:56:49 +0300 Subject: Implemented decoding of objects larger than 64kb --- src/libspuhdmv/xine_hdmv_decoder.c | 108 ++++++++++++++++++++++++++++++------- 1 file changed, 89 insertions(+), 19 deletions(-) diff --git a/src/libspuhdmv/xine_hdmv_decoder.c b/src/libspuhdmv/xine_hdmv_decoder.c index 955581d88..b41de21ae 100644 --- a/src/libspuhdmv/xine_hdmv_decoder.c +++ b/src/libspuhdmv/xine_hdmv_decoder.c @@ -50,6 +50,10 @@ #define XINE_HDMV_ERROR(x...) fprintf(stderr, "spuhdmv: " x) /*#define XINE_HDMV_ERROR(x...) lprintf(x) */ +#ifndef MAX +# define MAX(a,b) (a>b)?(a):(b) +#endif + enum { SEGTYPE_PALETTE = 0x14, SEGTYPE_OBJECT = 0x15, @@ -86,11 +90,11 @@ struct subtitle_object_s { unsigned int num_rle; size_t data_size; -#if 0 - uint8_t *raw_data; /* partial RLE data in HDMV format */ - size_t raw_data_len; - size_t raw_data_size; -#endif + /* HDMV format (used when object does not fit to single segment) */ + uint32_t data_len; /* size of complete object */ + uint8_t *raw_data; /* partial RLE data in HDMV format */ + size_t raw_data_len; /* bytes buffered */ + size_t raw_data_size; /* allocated size */ subtitle_object_t *next; @@ -187,6 +191,7 @@ static void free_subtitle_object(void *ptr) { if (ptr) { free(((subtitle_object_t*)ptr)->rle); + free(((subtitle_object_t*)ptr)->raw_data); free(ptr); } } @@ -448,42 +453,103 @@ static int segbuf_decode_rle(segment_buffer_t *buf, subtitle_object_t *obj) return buf->error; } -static subtitle_object_t *segbuf_decode_object(segment_buffer_t *buf) +static subtitle_object_t *segbuf_decode_object(segment_buffer_t *buf, subtitle_object_t *objects) { uint16_t object_id = segbuf_get_u16(buf); uint8_t version = segbuf_get_u8 (buf); uint8_t seq_desc = segbuf_get_u8 (buf); XINE_HDMV_TRACE(" decode_object: object_id %d, version %d, seq 0x%x\n", - object_id, version, seq_desc); - - //LIST_FIND(); - subtitle_object_t *obj = calloc(1, sizeof(subtitle_object_t)); - obj->id = object_id; + object_id, version, seq_desc); if (seq_desc & 0x80) { + /* new object (first-in-sequence flag set) */ - uint32_t data_len = segbuf_get_u24(buf); + subtitle_object_t *obj = calloc(1, sizeof(subtitle_object_t)); + + obj->id = object_id; + obj->data_len = segbuf_get_u24(buf); obj->width = segbuf_get_u16(buf); obj->height = segbuf_get_u16(buf); - XINE_HDMV_TRACE(" object length %d bytes, size %dx%d\n", data_len, obj->width, obj->height); + if (buf->error) { + XINE_HDMV_TRACE(" decode error at object header\n"); + free_subtitle_object(obj); + return NULL; + } + + obj->data_len -= 4; /* width, height parsed */ + + XINE_HDMV_TRACE(" object length %d bytes, size %dx%d\n", obj->data_len, obj->width, obj->height); + + if (obj->data_len > segbuf_data_length(buf)) { + XINE_HDMV_TRACE(" object length %d bytes, have only %zd bytes -> missing %d bytes\n", + obj->data_len, segbuf_data_length(buf), obj->data_len - (int)segbuf_data_length(buf)); + + if (obj->raw_data) + free(obj->raw_data); + + /* store partial RLE data in HDMV format */ + obj->raw_data_len = segbuf_data_length(buf); + obj->raw_data_size = MAX(obj->data_len, obj->raw_data_len); + obj->raw_data = malloc(obj->raw_data_size); + memcpy(obj->raw_data, buf->segment_data, obj->raw_data_len); + + return obj; + } segbuf_decode_rle (buf, obj); if (buf->error) { + XINE_HDMV_TRACE(" decode error at RLE data\n"); free_subtitle_object(obj); return NULL; } - } else { - XINE_HDMV_ERROR(" TODO: APPEND RLE, length %d bytes\n", buf->segment_len - 4); - /* TODO */ - free_subtitle_object(obj); + return obj; + } + + /* not first-of-sequence --> append data to already existing objct */ + + /* search for object */ + while (objects && objects->id != object_id) + objects = objects->next; + + if (!objects) { + XINE_HDMV_TRACE(" object not found from list, discarding segment\n"); + return NULL; + } + + /* store partial RLE data in HDMV format */ + if (objects->raw_data_size < objects->raw_data_len + segbuf_data_length(buf)) { + XINE_HDMV_ERROR("object larger than object size !\n"); return NULL; } + memcpy(objects->raw_data + objects->raw_data_len, buf->segment_data, segbuf_data_length(buf)); + objects->raw_data_len += segbuf_data_length(buf); - return obj; + /* if complete, decode RLE data */ + if (objects->raw_data_len >= objects->data_len) { + /* create dummy buffer for segbuf_decode_rle */ + segment_buffer_t tmpbuf = {}; + tmpbuf.segment_data = objects->raw_data; + tmpbuf.segment_end = objects->raw_data + objects->raw_data_len; + + /* decode RLE data */ + segbuf_decode_rle (&tmpbuf, objects); + + if (tmpbuf.error) { + XINE_HDMV_TRACE(" error decoding multi-segment object\n"); + } + + /* free decode buffer */ + free(objects->raw_data); + objects->raw_data = NULL; + objects->raw_data_len = 0; + objects->raw_data_size = 0; + } + + return NULL; } static window_def_t *segbuf_decode_window_definition(segment_buffer_t *buf) @@ -641,7 +707,7 @@ static int decode_palette(spuhdmv_decoder_t *this) static int decode_object(spuhdmv_decoder_t *this) { /* decode */ - subtitle_object_t *obj = segbuf_decode_object(this->buf); + subtitle_object_t *obj = segbuf_decode_object(this->buf, this->objects); if (!obj) return 1; @@ -704,6 +770,10 @@ static int show_overlay(spuhdmv_decoder_t *this, composition_object_t *cobj, uns XINE_HDMV_TRACE(" show_overlay: object %d not found !\n", cobj->object_id_ref); return -1; } + if (!obj->rle) { + XINE_HDMV_TRACE(" show_overlay: object %d RLE data not decoded !\n", cobj->object_id_ref); + return -1; + } /* find window */ window_def_t *wnd = this->windows; -- cgit v1.2.3 From 287fa7d3c17fe47a4e44f44732992761d47d3496 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Fri, 8 Jul 2011 13:00:11 +0300 Subject: Improved standard compilance: Drop cached data at epoch start or acquistion point, not at end of display set --- src/libspuhdmv/xine_hdmv_decoder.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libspuhdmv/xine_hdmv_decoder.c b/src/libspuhdmv/xine_hdmv_decoder.c index b41de21ae..fb6b9447b 100644 --- a/src/libspuhdmv/xine_hdmv_decoder.c +++ b/src/libspuhdmv/xine_hdmv_decoder.c @@ -737,6 +737,11 @@ static int decode_presentation_segment(spuhdmv_decoder_t *this) seg->pts = this->pts; + /* epoch start or acquistion point -> drop cached objects */ + if (seg->comp_descr.state) { + free_objs(this); + } + /* replace */ if (this->segments) LIST_DESTROY(this->segments, free_presentation_segment); @@ -936,8 +941,10 @@ static void decode_segment(spuhdmv_decoder_t *this) break; case SEGTYPE_END_OF_DISPLAY: XINE_HDMV_TRACE(" segment: END OF DISPLAY\n"); +#if 0 /* drop all cached objects */ free_objs(this); +#endif break; default: XINE_HDMV_ERROR(" segment type 0x%x unknown, skipping\n", segbuf_segment_type(this->buf)); -- cgit v1.2.3 From 2532a71fa1cd5e697d27e09a7c290faa6ea83acf Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Sat, 9 Jul 2011 16:14:42 +0300 Subject: Fixed hiding subtitles: composition descriptor state has nothing to do with hide/show. Hide overlay when there are no objects to display. --- src/libspuhdmv/xine_hdmv_decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libspuhdmv/xine_hdmv_decoder.c b/src/libspuhdmv/xine_hdmv_decoder.c index fb6b9447b..85732c4f6 100644 --- a/src/libspuhdmv/xine_hdmv_decoder.c +++ b/src/libspuhdmv/xine_hdmv_decoder.c @@ -878,7 +878,7 @@ static void update_overlays(spuhdmv_decoder_t *this) while (pseg) { - if (!pseg->comp_descr.state) { + if (!pseg->object_number) { /* HIDE */ if (!pseg->shown) -- cgit v1.2.3 From 688d5436f3b4aef5982467dfffa1013991583b6e Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Sat, 9 Jul 2011 16:18:54 +0300 Subject: Killed warnings --- src/libspuhdmv/xine_hdmv_decoder.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libspuhdmv/xine_hdmv_decoder.c b/src/libspuhdmv/xine_hdmv_decoder.c index 85732c4f6..3b9843177 100644 --- a/src/libspuhdmv/xine_hdmv_decoder.c +++ b/src/libspuhdmv/xine_hdmv_decoder.c @@ -294,7 +294,7 @@ static void segbuf_fill(segment_buffer_t *buf, uint8_t *data, size_t len) static int segbuf_segment_complete(segment_buffer_t *buf) { - return (buf->segment_len >= 0) && (buf->len >= buf->segment_len + 3); + return (buf->segment_len >= 0) && (buf->len >= (unsigned)buf->segment_len + 3); } static void segbuf_skip_segment(segment_buffer_t *buf) @@ -359,7 +359,7 @@ static subtitle_clut_t *segbuf_decode_palette(segment_buffer_t *buf) size_t len = segbuf_data_length(buf); size_t entries = len / 5; - int i; + size_t i; if (buf->error) return NULL; @@ -531,9 +531,10 @@ static subtitle_object_t *segbuf_decode_object(segment_buffer_t *buf, subtitle_o /* if complete, decode RLE data */ if (objects->raw_data_len >= objects->data_len) { /* create dummy buffer for segbuf_decode_rle */ - segment_buffer_t tmpbuf = {}; - tmpbuf.segment_data = objects->raw_data; - tmpbuf.segment_end = objects->raw_data + objects->raw_data_len; + segment_buffer_t tmpbuf = { + .segment_data = objects->raw_data, + .segment_end = objects->raw_data + objects->raw_data_len, + }; /* decode RLE data */ segbuf_decode_rle (&tmpbuf, objects); -- cgit v1.2.3 From c63c5501af35f886a14a02b479311a8b784db273 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Sat, 9 Jul 2011 16:20:41 +0300 Subject: Cosmetics: reordered functions --- src/libspuhdmv/xine_hdmv_decoder.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libspuhdmv/xine_hdmv_decoder.c b/src/libspuhdmv/xine_hdmv_decoder.c index 3b9843177..88213a5fa 100644 --- a/src/libspuhdmv/xine_hdmv_decoder.c +++ b/src/libspuhdmv/xine_hdmv_decoder.c @@ -693,6 +693,14 @@ typedef struct spuhdmv_decoder_s { } spuhdmv_decoder_t; +static void free_objs(spuhdmv_decoder_t *this) +{ + LIST_DESTROY (this->cluts, free); + LIST_DESTROY (this->objects, free_subtitle_object); + LIST_DESTROY (this->windows, free); + LIST_DESTROY (this->segments, free_presentation_segment); +} + static int decode_palette(spuhdmv_decoder_t *this) { /* decode */ @@ -907,14 +915,6 @@ static void update_overlays(spuhdmv_decoder_t *this) } } -static void free_objs(spuhdmv_decoder_t *this) -{ - LIST_DESTROY (this->cluts, free); - LIST_DESTROY (this->objects, free_subtitle_object); - LIST_DESTROY (this->windows, free); - LIST_DESTROY (this->segments, free_presentation_segment); -} - static void decode_segment(spuhdmv_decoder_t *this) { XINE_HDMV_TRACE("*** new segment, pts %010"PRId64": 0x%02x (%8d bytes)\n", -- cgit v1.2.3 From 8bd4aea3d088824c32ca06f0d8745d591362a086 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Sat, 9 Jul 2011 16:21:36 +0300 Subject: Composition descriptor state is only two bits --- src/libspuhdmv/xine_hdmv_decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libspuhdmv/xine_hdmv_decoder.c b/src/libspuhdmv/xine_hdmv_decoder.c index 88213a5fa..d0a82da09 100644 --- a/src/libspuhdmv/xine_hdmv_decoder.c +++ b/src/libspuhdmv/xine_hdmv_decoder.c @@ -589,7 +589,7 @@ static int segbuf_decode_video_descriptor(segment_buffer_t *buf) static int segbuf_decode_composition_descriptor(segment_buffer_t *buf, composition_descriptor_t *descr) { descr->number = segbuf_get_u16(buf); - descr->state = segbuf_get_u8 (buf); + descr->state = segbuf_get_u8 (buf) & 0xc0; XINE_HDMV_TRACE(" composition_descriptor: number %d, state %d\n", descr->number, descr->state); return buf->error; -- cgit v1.2.3 From 9a60ab6deecbe5e378e63fa2db78d14367ccb717 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Sat, 9 Jul 2011 21:09:38 +0300 Subject: Fixed 24-bit BluRay PCM audio broken by commit 7b6c2dc0ac98. Samples are 24 bit BE, not in DVD format. --- src/libxineadec/xine_lpcm_decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libxineadec/xine_lpcm_decoder.c b/src/libxineadec/xine_lpcm_decoder.c index 17db68550..c34d43b42 100644 --- a/src/libxineadec/xine_lpcm_decoder.c +++ b/src/libxineadec/xine_lpcm_decoder.c @@ -117,7 +117,7 @@ static void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { switch ((buf->decoder_info[2] >> (24+6)) & 0x03) { case 1: bits_per_sample = 16; break; case 2: bits_per_sample = 20; break; - case 3: bits_per_sample = 24; special_dvd_audio = 1; break; + case 3: bits_per_sample = 24; break; default: bits_per_sample = 0; break; } switch ((buf->decoder_info[2] >> 16) & 0x0f) { -- cgit v1.2.3 From 98b26469d9973e7dae3645dc912b0ac0267d3ee2 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Sat, 9 Jul 2011 21:14:08 +0300 Subject: Fixed 20-bit BluRay PCM audio. In this format samples are padded to 24 bits, 4 lowest bits are 0 --> Handle as 24-bit BluRay PCM. --- src/libxineadec/xine_lpcm_decoder.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libxineadec/xine_lpcm_decoder.c b/src/libxineadec/xine_lpcm_decoder.c index c34d43b42..71ac3f802 100644 --- a/src/libxineadec/xine_lpcm_decoder.c +++ b/src/libxineadec/xine_lpcm_decoder.c @@ -116,7 +116,11 @@ static void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { num_channels = channels[(buf->decoder_info[2] >> (16+4)) & 0x0f]; switch ((buf->decoder_info[2] >> (24+6)) & 0x03) { case 1: bits_per_sample = 16; break; - case 2: bits_per_sample = 20; break; + case 2: /*bits_per_sample = 20; break;*/ + /* fall thru. Samples are 0-padded to 24 bits, and + * converted later to 16 bits by dropping 8 lowest bits. + * this needs to be changed if audio out some day accepts 24bit samples. + */ case 3: bits_per_sample = 24; break; default: bits_per_sample = 0; break; } -- cgit v1.2.3 From 812c8af9bfb91e65a7c85a4281cc9aa0d047d9a7 Mon Sep 17 00:00:00 2001 From: Torsten Jager Date: Sat, 13 Aug 2011 18:00:54 +0200 Subject: ffmpeg audio crash fix (sse2 alignment) Certain ffmpeg audio decoders use 32 bit float samples internally (wma, eac3, ...). They are then exported to the calling application as 16 bit integer. That conversion is done by faster sse2 code if your processor supports it. However, sse2 instructions require data buffers to be 16 byte aligned, or hit a segfault otherwise. Plain malloc() / realloc() ensures only 8 byte alignment, giving a 50% chance of a crash. FFmpeg internally uses aligned buffers a lot. It seems to be a good idea to do likewise for input buffers as well, even if current version does not strictly need it yet. Libavutil/av_realloc() has a bug that can break the alignment when enlarging an existing buffer. Thus I included a fixed version of it within ff_audio_decoder.c. --- src/combined/ffmpeg/ff_audio_decoder.c | 36 ++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index 60544ad0c..14a908d2f 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -81,13 +81,41 @@ typedef struct ff_audio_decoder_s { #include "ff_audio_list.h" +#define malloc16(s) realloc16(NULL,s) +#define free16(p) realloc16(p,0) + +static void *realloc16 (void *m, size_t s) { + unsigned int diff, diff2; + unsigned char *p = m, *q; + if (p) { + diff = p[-1]; + if (s == 0) { + free (p - diff); + return (NULL); + } + q = realloc (p - diff, s + 16); + if (!q) return (q); + diff2 = 16 - ((unsigned int)q & 15); + if (diff2 != diff) memmove (q + diff2, q + diff, s); + } else { + if (s == 0) return (NULL); + q = malloc (s + 16); + if (!q) return (q); + diff2 = 16 - ((unsigned int)q & 15); + } + q += diff2; + q[-1] = diff2; + return (q); +} + + static void ff_audio_ensure_buffer_size(ff_audio_decoder_t *this, int size) { if (size > this->bufsize) { this->bufsize = size + size / 2; xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("ffmpeg_audio_dec: increasing buffer to %d to avoid overflow.\n"), this->bufsize); - this->buf = realloc( this->buf, this->bufsize ); + this->buf = realloc16 (this->buf, this->bufsize); } } @@ -247,7 +275,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) this->size = 0; - this->decode_buffer = calloc(1, AVCODEC_MAX_AUDIO_FRAME_SIZE); + this->decode_buffer = malloc16 (AVCODEC_MAX_AUDIO_FRAME_SIZE); return; } @@ -455,8 +483,8 @@ static void ff_audio_dispose (audio_decoder_t *this_gen) { this->stream->audio_out->close (this->stream->audio_out, this->stream); this->output_open = 0; - free(this->buf); - free(this->decode_buffer); + free16 (this->buf); + free16 (this->decode_buffer); if(this->context && this->context->extradata) free(this->context->extradata); -- cgit v1.2.3 From 41500b69fd2f67541904bb7b146d5ba3ee472d21 Mon Sep 17 00:00:00 2001 From: Torsten Jager Date: Sat, 13 Aug 2011 18:02:30 +0200 Subject: VP8 support --- src/combined/ffmpeg/xine_video.list | 1 + src/demuxers/demux_matroska.c | 23 +++++++++++++++++++++++ src/demuxers/matroska.h | 1 + src/xine-engine/buffer.h | 1 + src/xine-engine/buffer_types.c | 8 ++++++++ 5 files changed, 34 insertions(+) diff --git a/src/combined/ffmpeg/xine_video.list b/src/combined/ffmpeg/xine_video.list index a3c961d13..546cfff7c 100644 --- a/src/combined/ffmpeg/xine_video.list +++ b/src/combined/ffmpeg/xine_video.list @@ -34,6 +34,7 @@ VP31 VP3 On2 VP3.1 VP5 VP5 On2 VP5 VP6 VP6 On2 VP6 VP6F VP6F On2 VP6 +VP8 VP8 On2 VP8 4XM 4XM 4X Video CINEPAK CINEPAK Cinepak MSVC MSVIDEO1 Microsoft Video 1 diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c index 694236833..c47cd2657 100644 --- a/src/demuxers/demux_matroska.c +++ b/src/demuxers/demux_matroska.c @@ -1330,6 +1330,29 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_MPEG2)) { lprintf("MATROSKA_CODEC_ID_V_MPEG2\n"); track->buf_type = BUF_VIDEO_MPEG; + init_codec = init_codec_video; + } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_VP8)) { + xine_bmiheader *bih; + + lprintf("MATROSKA_CODEC_ID_V_VP8\n"); + if (track->codec_private_len > 0x7fffffff - sizeof(xine_bmiheader)) + track->codec_private_len = 0x7fffffff - sizeof(xine_bmiheader); + + /* create a bitmap info header struct for vp8 */ + bih = calloc(1, sizeof(xine_bmiheader) + track->codec_private_len); + bih->biSize = sizeof(xine_bmiheader) + track->codec_private_len; + bih->biCompression = ME_FOURCC('v', 'p', '8', '0'); + bih->biWidth = track->video_track->pixel_width; + bih->biHeight = track->video_track->pixel_height; + _x_bmiheader_le2me(bih); + + /* add bih extra data */ + memcpy(bih + 1, track->codec_private, track->codec_private_len); + free(track->codec_private); + track->codec_private = (uint8_t *)bih; + track->codec_private_len = bih->biSize; + track->buf_type = BUF_VIDEO_VP8; + init_codec = init_codec_video; } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_REAL_RV10)) { } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_REAL_RV20)) { diff --git a/src/demuxers/matroska.h b/src/demuxers/matroska.h index e8f124e9b..7af9ef121 100644 --- a/src/demuxers/matroska.h +++ b/src/demuxers/matroska.h @@ -314,6 +314,7 @@ struct matroska_track_s { #define MATROSKA_CODEC_ID_V_REAL_RV40 "V_REAL/RV40" #define MATROSKA_CODEC_ID_V_MJPEG "V_MJPEG" #define MATROSKA_CODEC_ID_V_THEORA "V_THEORA" +#define MATROSKA_CODEC_ID_V_VP8 "V_VP8" #define MATROSKA_CODEC_ID_A_MPEG1_L1 "A_MPEG/L1" #define MATROSKA_CODEC_ID_A_MPEG1_L2 "A_MPEG/L2" diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h index 034f6552a..9198ff103 100644 --- a/src/xine-engine/buffer.h +++ b/src/xine-engine/buffer.h @@ -189,6 +189,7 @@ extern "C" { #define BUF_VIDEO_VC1 0x02650000 #define BUF_VIDEO_VMNC 0x02660000 #define BUF_VIDEO_SNOW 0x02670000 +#define BUF_VIDEO_VP8 0x02680000 /* audio buffer types: (please keep in sync with buffer_types.c) */ diff --git a/src/xine-engine/buffer_types.c b/src/xine-engine/buffer_types.c index e6b846d64..050043c64 100644 --- a/src/xine-engine/buffer_types.c +++ b/src/xine-engine/buffer_types.c @@ -789,6 +789,14 @@ static const video_db_t video_db[] = { BUF_VIDEO_SNOW, "Snow" }, +{ + { + ME_FOURCC('V','P','8','0'), + 0 + }, + BUF_VIDEO_VP8, + "On2 VP8" +}, { { 0 }, 0, "last entry" } }; -- cgit v1.2.3 From e96bac07aae3a9677661fd581b7c7e4e98964831 Mon Sep 17 00:00:00 2001 From: Torsten Jager Date: Sat, 13 Aug 2011 18:02:30 +0200 Subject: rv30 & rv40 support --- src/combined/ffmpeg/ff_video_decoder.c | 6 ++++++ src/combined/ffmpeg/xine_video.list | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c index ad0ee6022..a9c383c48 100644 --- a/src/combined/ffmpeg/ff_video_decoder.c +++ b/src/combined/ffmpeg/ff_video_decoder.c @@ -329,6 +329,10 @@ static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type) this->context->flags |= CODEC_FLAG_EMU_EDGE; } + /* TJ. without this, it wont work at all on my machine */ + this->context->codec_id = this->codec->id; + this->context->codec_type = this->codec->type; + if (this->class->choose_speed_over_accuracy) this->context->flags2 |= CODEC_FLAG2_FAST; @@ -910,6 +914,8 @@ static void ff_handle_header_buffer (ff_video_decoder_t *this, buf_element_t *bu switch (codec_type) { case BUF_VIDEO_RV10: case BUF_VIDEO_RV20: + case BUF_VIDEO_RV30: + case BUF_VIDEO_RV40: this->bih.biWidth = _X_BE_16(&this->buf[12]); this->bih.biHeight = _X_BE_16(&this->buf[14]); diff --git a/src/combined/ffmpeg/xine_video.list b/src/combined/ffmpeg/xine_video.list index 546cfff7c..bd1238d6f 100644 --- a/src/combined/ffmpeg/xine_video.list +++ b/src/combined/ffmpeg/xine_video.list @@ -24,6 +24,8 @@ I263 H263I ITU H.263 H263 H263 H.263 RV10 RV10 Real Video 1.0 RV20 RV20 Real Video 2.0 +RV30 RV30 Real Video 3.0 +RV40 RV40 Real Video 4.0 IV31 INDEO3 Indeo Video 3.1 IV32 INDEO3 Indeo Video 3.2 SORENSON_V1 SVQ1 Sorenson Video 1 -- cgit v1.2.3 From 078eade9b4a427497250ca567ebe1865ecd47a8f Mon Sep 17 00:00:00 2001 From: Torsten Jager Date: Mon, 22 Aug 2011 11:49:01 +0200 Subject: Audio crash fix Audio decoder loop creates a sorted map of available audio channels on the fly. If neither user nor dvdnav intervene, it will pass the first (= lowest index) audio channel to decoders. Now imagine a TV recording with 2 audio channels: audio.0: eac3 5.1 (fra) audio.1: eac3 stereo (qaa) By chance, first audio frame to be demuxed is for channel #1. Track map will be [0]: eac3, channel 1 Audio loop opens ffmpeg audio decoder / stereo out. Fine. Then, first frame for channel #0 comes in. [0]: eac3, channel 0 [1]: eac3, channel 1 Both are same codec, so audio loop just switches to channel 0 without further notice. Audio decoder then runs into a mem leak, or worse, crashes audio out who still thinks we're only stereo. Whenever we insert something at track map index 0, and its going to be auto-selected later, reset current codec type. This forces a clean decoder/output switch. --- src/xine-engine/audio_decoder.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/xine-engine/audio_decoder.c b/src/xine-engine/audio_decoder.c index 3d5ef7e6f..10c20f231 100644 --- a/src/xine-engine/audio_decoder.c +++ b/src/xine-engine/audio_decoder.c @@ -283,6 +283,9 @@ static void *audio_decoder_loop (void *stream_gen) { } stream->audio_track_map[i] = buf->type; stream->audio_track_map_entries++; + /* implicit channel change - reopen decoder below */ + if ((i == 0) && (audio_channel_user == -1) && (stream->audio_channel_auto < 0)) + stream->audio_decoder_streamtype = -1; ui_event.type = XINE_EVENT_UI_CHANNELS_CHANGED; ui_event.data_length = 0; -- cgit v1.2.3 From 7e6f30b0062375c30db8e67b464c7fe003ed15d5 Mon Sep 17 00:00:00 2001 From: Torsten Jager Date: Mon, 22 Aug 2011 11:50:16 +0200 Subject: UI freeze fix xine_play () gets suspended after start or seek until first frame gets displayed. This often wont work on slow machines when first frame gets dropped because its too old. Consequently, UI freezes for full 10 seconds. Let's wake up xine_play when this happens as well. OK, this is a luxury convenience fix ;-) --- src/xine-engine/video_out.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c index 0bbf977f2..f3e24537e 100644 --- a/src/xine-engine/video_out.c +++ b/src/xine-engine/video_out.c @@ -802,7 +802,7 @@ static void expire_frames (vos_t *this, int64_t cur_vpts) { while (img) { - if (img->is_first) { + if (img->is_first > 0) { lprintf("expire_frames: first_frame !\n"); /* @@ -819,6 +819,8 @@ static void expire_frames (vos_t *this, int64_t cur_vpts) { img->vpts = cur_vpts + FIRST_FRAME_POLL_DELAY; } img->is_first--; + /* make sure to wake up xine_play even if this first frame gets discarded */ + if (img->is_first == 0) img->is_first = -1; break; } @@ -848,6 +850,24 @@ static void expire_frames (vos_t *this, int64_t cur_vpts) { pthread_mutex_lock( &img->stream->current_extra_info_lock ); _x_extra_info_merge( img->stream->current_extra_info, img->extra_info ); pthread_mutex_unlock( &img->stream->current_extra_info_lock ); + /* wake up xine_play now if we just discarded first frame */ + if (img->is_first != 0) { + xine_list_iterator_t ite; + pthread_mutex_lock (&this->streams_lock); + for (ite = xine_list_front(this->streams); ite; + ite = xine_list_next(this->streams, ite)) { + xine_stream_t *stream = xine_list_get_value (this->streams, ite); + if (stream == XINE_ANON_STREAM) continue; + pthread_mutex_lock (&stream->first_frame_lock); + if (stream->first_frame_flag) { + stream->first_frame_flag = 0; + pthread_cond_broadcast (&stream->first_frame_reached); + } + pthread_mutex_unlock (&stream->first_frame_lock); + } + pthread_mutex_unlock(&this->streams_lock); + xine_log (this->xine, XINE_LOG_MSG, _("video_out: just discarded first frame after seek\n")); + } } /* when flushing frames, keep the first one as backup */ -- cgit v1.2.3 From edb68926aced0739f3e62ea2501bc32326c02f86 Mon Sep 17 00:00:00 2001 From: Torsten Jager Date: Mon, 22 Aug 2011 11:51:20 +0200 Subject: Video deadlock fix When watching TV with Kaffeine I frequently had complete engine lockups. Multiple mutexes were waiting on each other. net_buf_ctrl requires the demuxer to keep running while playback is still paused. The diff might look a bit confusing. Basically, all I did was to replace phtread_mutex_lock (); ... pthread_mutex_unlock (); with if (pthread_mutex_trylock ()) { ... pthread_mutex_unlock (); } at a place where it does the least damage. --- src/xine-engine/video_out.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c index f3e24537e..a6d39f23f 100644 --- a/src/xine-engine/video_out.c +++ b/src/xine-engine/video_out.c @@ -572,25 +572,28 @@ static int vo_frame_draw (vo_frame_t *img, xine_stream_t *stream) { * check for first frame after seek and mark it */ img->is_first = 0; - pthread_mutex_lock(&this->streams_lock); - for (ite = xine_list_front(this->streams); ite; - ite = xine_list_next(this->streams, ite)) { - stream = xine_list_get_value(this->streams, ite); - if (stream == XINE_ANON_STREAM) continue; - pthread_mutex_lock (&stream->first_frame_lock); - if (stream->first_frame_flag == 2) { - if (this->grab_only) { - stream->first_frame_flag = 0; - pthread_cond_broadcast(&stream->first_frame_reached); - } else - stream->first_frame_flag = 1; - img->is_first = FIRST_FRAME_MAX_POLL; - - lprintf ("get_next_video_frame first_frame_reached\n"); + /* avoid a complex deadlock situation caused by net_buf_control */ + if (!pthread_mutex_trylock(&this->streams_lock)) { + for (ite = xine_list_front(this->streams); ite; + ite = xine_list_next(this->streams, ite)) { + stream = xine_list_get_value(this->streams, ite); + if (stream == XINE_ANON_STREAM) continue; + pthread_mutex_lock (&stream->first_frame_lock); + if (stream->first_frame_flag == 2) { + if (this->grab_only) { + stream->first_frame_flag = 0; + pthread_cond_broadcast(&stream->first_frame_reached); + } else { + stream->first_frame_flag = 1; + } + img->is_first = FIRST_FRAME_MAX_POLL; + + lprintf ("get_next_video_frame first_frame_reached\n"); + } + pthread_mutex_unlock (&stream->first_frame_lock); } - pthread_mutex_unlock (&stream->first_frame_lock); + pthread_mutex_unlock(&this->streams_lock); } - pthread_mutex_unlock(&this->streams_lock); if (!img_already_locked) vo_frame_inc_lock( img ); -- cgit v1.2.3