X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fdvbsubdec.c;h=1d62b8ad4235443b357df387c8dca5b3da5e1c45;hb=607ad990d31e6be52980970e5ce8cd25ab3de812;hp=689c06883356e205408e24cf48686500ba22b9ad;hpb=25b4c651a3de58ea14c59131c650593736004686;p=ffmpeg diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c index 689c0688335..1d62b8ad423 100644 --- a/libavcodec/dvbsubdec.c +++ b/libavcodec/dvbsubdec.c @@ -1,42 +1,39 @@ /* - * DVB subtitle decoding for ffmpeg - * Copyright (c) 2005 Ian Caulfield. + * DVB subtitle decoding + * Copyright (c) 2005 Ian Caulfield * - * This file is part of FFmpeg. + * This file is part of Libav. * - * FFmpeg is free software; you can redistribute it and/or + * Libav is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * FFmpeg is distributed in the hope that it will be useful, + * Libav is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software + * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "avcodec.h" -#include "dsputil.h" -#include "bitstream.h" -#include "colorspace.h" -//#define DEBUG -//#define DEBUG_PACKET_CONTENTS -//#define DEBUG_SAVE_IMAGES +#include "avcodec.h" +#include "get_bits.h" +#include "bytestream.h" +#include "libavutil/colorspace.h" #define DVBSUB_PAGE_SEGMENT 0x10 #define DVBSUB_REGION_SEGMENT 0x11 #define DVBSUB_CLUT_SEGMENT 0x12 #define DVBSUB_OBJECT_SEGMENT 0x13 +#define DVBSUB_DISPLAYDEFINITION_SEGMENT 0x14 #define DVBSUB_DISPLAY_SEGMENT 0x80 -#define cm (ff_cropTbl + MAX_NEG_CROP) +#define cm (ff_crop_tab + MAX_NEG_CROP) -#ifdef DEBUG_SAVE_IMAGES -#undef fprintf +#ifdef DEBUG #if 0 static void png_save(const char *filename, uint8_t *bitmap, int w, int h, uint32_t *rgba_palette) @@ -51,7 +48,7 @@ static void png_save(const char *filename, uint8_t *bitmap, int w, int h, f = fopen(fname, "w"); if (!f) { perror(fname); - exit(1); + return; } fprintf(f, "P6\n" "%d %d\n" @@ -73,7 +70,7 @@ static void png_save(const char *filename, uint8_t *bitmap, int w, int h, f = fopen(fname2, "w"); if (!f) { perror(fname2); - exit(1); + return; } fprintf(f, "P5\n" "%d %d\n" @@ -107,7 +104,7 @@ static void png_save2(const char *filename, uint32_t *bitmap, int w, int h) f = fopen(fname, "w"); if (!f) { perror(fname); - exit(1); + return; } fprintf(f, "P6\n" "%d %d\n" @@ -129,7 +126,7 @@ static void png_save2(const char *filename, uint32_t *bitmap, int w, int h) f = fopen(fname2, "w"); if (!f) { perror(fname2); - exit(1); + return; } fprintf(f, "P5\n" "%d %d\n" @@ -151,7 +148,7 @@ static void png_save2(const char *filename, uint32_t *bitmap, int w, int h) } #endif -#define RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) +#define RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b)) typedef struct DVBSubCLUT { int id; @@ -216,6 +213,15 @@ typedef struct DVBSubRegion { struct DVBSubRegion *next; } DVBSubRegion; +typedef struct DVBSubDisplayDefinition { + int version; + + int x; + int y; + int width; + int height; +} DVBSubDisplayDefinition; + typedef struct DVBSubContext { int composition_id; int ancillary_id; @@ -227,6 +233,7 @@ typedef struct DVBSubContext { int display_list_size; DVBSubRegionDisplay *display_list; + DVBSubDisplayDefinition *display_definition; } DVBSubContext; @@ -320,9 +327,7 @@ static void delete_state(DVBSubContext *ctx) ctx->region_list = region->next; delete_region_display_list(ctx, region); - if (region->pbuf) - av_free(region->pbuf); - + av_free(region->pbuf); av_free(region); } @@ -334,6 +339,8 @@ static void delete_state(DVBSubContext *ctx) av_free(clut); } + av_freep(&ctx->display_definition); + /* Should already be null */ if (ctx->object_list) av_log(0, AV_LOG_ERROR, "Memory deallocation error!\n"); @@ -342,12 +349,16 @@ static void delete_state(DVBSubContext *ctx) static av_cold int dvbsub_init_decoder(AVCodecContext *avctx) { int i, r, g, b, a = 0; - DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; - - memset(avctx->priv_data, 0, sizeof(DVBSubContext)); + DVBSubContext *ctx = avctx->priv_data; - ctx->composition_id = avctx->sub_id & 0xffff; - ctx->ancillary_id = avctx->sub_id >> 16; + if (!avctx->extradata || avctx->extradata_size != 4) { + av_log(avctx, AV_LOG_WARNING, "Invalid extradata, subtitle streams may be combined!\n"); + ctx->composition_id = -1; + ctx->ancillary_id = -1; + } else { + ctx->composition_id = AV_RB16(avctx->extradata); + ctx->ancillary_id = AV_RB16(avctx->extradata + 2); + } default_clut.id = -1; default_clut.next = NULL; @@ -414,7 +425,7 @@ static av_cold int dvbsub_init_decoder(AVCodecContext *avctx) static av_cold int dvbsub_close_decoder(AVCodecContext *avctx) { - DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; + DVBSubContext *ctx = avctx->priv_data; DVBSubRegionDisplay *display; delete_state(ctx); @@ -439,9 +450,9 @@ static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len, int run_length; int pixels_read = 0; - init_get_bits(&gb, *srcbuf, buf_size << 8); + init_get_bits(&gb, *srcbuf, buf_size << 3); - while (get_bits_count(&gb) < (buf_size << 8) && pixels_read < dbuf_len) { + while (get_bits_count(&gb) < buf_size << 3 && pixels_read < dbuf_len) { bits = get_bits(&gb, 2); if (bits) { @@ -544,9 +555,9 @@ static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len, int run_length; int pixels_read = 0; - init_get_bits(&gb, *srcbuf, buf_size << 8); + init_get_bits(&gb, *srcbuf, buf_size << 3); - while (get_bits_count(&gb) < (buf_size << 8) && pixels_read < dbuf_len) { + while (get_bits_count(&gb) < buf_size << 3 && pixels_read < dbuf_len) { bits = get_bits(&gb, 4); if (bits) { @@ -682,26 +693,19 @@ static int dvbsub_read_8bit_string(uint8_t *destbuf, int dbuf_len, if (run_length == 0) { return pixels_read; } - - if (map_table) - bits = map_table[0]; - else - bits = 0; - while (run_length-- > 0 && pixels_read < dbuf_len) { - *destbuf++ = bits; - pixels_read++; - } } else { bits = *(*srcbuf)++; if (non_mod == 1 && bits == 1) pixels_read += run_length; - if (map_table) - bits = map_table[bits]; - else while (run_length-- > 0 && pixels_read < dbuf_len) { - *destbuf++ = bits; - pixels_read++; - } + } + if (map_table) + bits = map_table[0]; + else + bits = 0; + while (run_length-- > 0 && pixels_read < dbuf_len) { + *destbuf++ = bits; + pixels_read++; } } } @@ -717,7 +721,7 @@ static int dvbsub_read_8bit_string(uint8_t *destbuf, int dbuf_len, static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDisplay *display, const uint8_t *buf, int buf_size, int top_bottom, int non_mod) { - DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; + DVBSubContext *ctx = avctx->priv_data; DVBSubRegion *region = get_region(ctx, display->region_id); const uint8_t *buf_end = buf + buf_size; @@ -731,25 +735,20 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; uint8_t *map_table; -#ifdef DEBUG - av_log(avctx, AV_LOG_INFO, "DVB pixel block size %d, %s field:\n", buf_size, - top_bottom ? "bottom" : "top"); -#endif + av_dlog(avctx, "DVB pixel block size %d, %s field:\n", buf_size, + top_bottom ? "bottom" : "top"); -#ifdef DEBUG_PACKET_CONTENTS for (i = 0; i < buf_size; i++) { if (i % 16 == 0) - av_log(avctx, AV_LOG_INFO, "0x%08p: ", buf+i); + av_dlog(avctx, "0x%8p: ", buf+i); - av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]); + av_dlog(avctx, "%02x ", buf[i]); if (i % 16 == 15) - av_log(avctx, AV_LOG_INFO, "\n"); + av_dlog(avctx, "\n"); } if (i % 16) - av_log(avctx, AV_LOG_INFO, "\n"); - -#endif + av_dlog(avctx, "\n"); if (region == 0) return; @@ -778,7 +777,7 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis map_table = NULL; x_pos += dvbsub_read_2bit_string(pbuf + (y_pos * region->width) + x_pos, - region->width - x_pos, &buf, buf_size, + region->width - x_pos, &buf, buf_end - buf, non_mod, map_table); break; case 0x11: @@ -793,7 +792,7 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis map_table = NULL; x_pos += dvbsub_read_4bit_string(pbuf + (y_pos * region->width) + x_pos, - region->width - x_pos, &buf, buf_size, + region->width - x_pos, &buf, buf_end - buf, non_mod, map_table); break; case 0x12: @@ -803,7 +802,7 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis } x_pos += dvbsub_read_8bit_string(pbuf + (y_pos * region->width) + x_pos, - region->width - x_pos, &buf, buf_size, + region->width - x_pos, &buf, buf_end - buf, non_mod, NULL); break; @@ -833,10 +832,10 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis } -static void dvbsub_parse_object_segment(AVCodecContext *avctx, - const uint8_t *buf, int buf_size) +static int dvbsub_parse_object_segment(AVCodecContext *avctx, + const uint8_t *buf, int buf_size) { - DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; + DVBSubContext *ctx = avctx->priv_data; const uint8_t *buf_end = buf + buf_size; const uint8_t *block; @@ -853,7 +852,7 @@ static void dvbsub_parse_object_segment(AVCodecContext *avctx, object = get_object(ctx, object_id); if (!object) - return; + return AVERROR_INVALIDDATA; coding_method = ((*buf) >> 2) & 3; non_modifying_color = ((*buf++) >> 1) & 1; @@ -866,7 +865,7 @@ static void dvbsub_parse_object_segment(AVCodecContext *avctx, if (buf + top_field_len + bottom_field_len > buf_end) { av_log(avctx, AV_LOG_ERROR, "Field data size too large\n"); - return; + return AVERROR_INVALIDDATA; } for (display = object->display_list; display; display = display->object_list_next) { @@ -890,35 +889,31 @@ static void dvbsub_parse_object_segment(AVCodecContext *avctx, av_log(avctx, AV_LOG_ERROR, "Unknown object coding %d\n", coding_method); } + return 0; } -static void dvbsub_parse_clut_segment(AVCodecContext *avctx, - const uint8_t *buf, int buf_size) +static int dvbsub_parse_clut_segment(AVCodecContext *avctx, + const uint8_t *buf, int buf_size) { - DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; + DVBSubContext *ctx = avctx->priv_data; const uint8_t *buf_end = buf + buf_size; - int clut_id; + int i, clut_id; DVBSubCLUT *clut; int entry_id, depth , full_range; int y, cr, cb, alpha; int r, g, b, r_add, g_add, b_add; -#ifdef DEBUG_PACKET_CONTENTS - int i; - - av_log(avctx, AV_LOG_INFO, "DVB clut packet:\n"); + av_dlog(avctx, "DVB clut packet:\n"); for (i=0; i < buf_size; i++) { - av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]); + av_dlog(avctx, "%02x ", buf[i]); if (i % 16 == 15) - av_log(avctx, AV_LOG_INFO, "\n"); + av_dlog(avctx, "\n"); } if (i % 16) - av_log(avctx, AV_LOG_INFO, "\n"); - -#endif + av_dlog(avctx, "\n"); clut_id = *buf++; buf += 1; @@ -927,6 +922,8 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx, if (!clut) { clut = av_malloc(sizeof(DVBSubCLUT)); + if (!clut) + return AVERROR(ENOMEM); memcpy(clut, &default_clut, sizeof(DVBSubCLUT)); @@ -943,7 +940,7 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx, if (depth == 0) { av_log(avctx, AV_LOG_ERROR, "Invalid clut depth 0x%x!\n", *buf); - return; + return AVERROR_INVALIDDATA; } full_range = (*buf++) & 1; @@ -968,9 +965,7 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx, YUV_TO_RGB1_CCIR(cb, cr); YUV_TO_RGB2_CCIR(r, g, b, y); -#ifdef DEBUG - av_log(avctx, AV_LOG_INFO, "clut %d := (%d,%d,%d,%d)\n", entry_id, r, g, b, alpha); -#endif + av_dlog(avctx, "clut %d := (%d,%d,%d,%d)\n", entry_id, r, g, b, alpha); if (depth & 0x80) clut->clut4[entry_id] = RGBA(r,g,b,255 - alpha); @@ -979,13 +974,15 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx, if (depth & 0x20) clut->clut256[entry_id] = RGBA(r,g,b,255 - alpha); } + + return 0; } -static void dvbsub_parse_region_segment(AVCodecContext *avctx, - const uint8_t *buf, int buf_size) +static int dvbsub_parse_region_segment(AVCodecContext *avctx, + const uint8_t *buf, int buf_size) { - DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; + DVBSubContext *ctx = avctx->priv_data; const uint8_t *buf_end = buf + buf_size; int region_id, object_id; @@ -995,7 +992,7 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx, int fill; if (buf_size < 10) - return; + return AVERROR_INVALIDDATA; region_id = *buf++; @@ -1003,6 +1000,8 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx, if (!region) { region = av_mallocz(sizeof(DVBSubRegion)); + if (!region) + return AVERROR(ENOMEM); region->id = region_id; @@ -1018,12 +1017,13 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx, buf += 2; if (region->width * region->height != region->buf_size) { - if (region->pbuf) - av_free(region->pbuf); + av_free(region->pbuf); region->buf_size = region->width * region->height; region->pbuf = av_malloc(region->buf_size); + if (!region->pbuf) + return AVERROR(ENOMEM); fill = 1; } @@ -1046,15 +1046,11 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx, region->bgcolor = (((*buf++) >> 2) & 3); } -#ifdef DEBUG - av_log(avctx, AV_LOG_INFO, "Region %d, (%dx%d)\n", region_id, region->width, region->height); -#endif + av_dlog(avctx, "Region %d, (%dx%d)\n", region_id, region->width, region->height); if (fill) { memset(region->pbuf, region->bgcolor, region->buf_size); -#ifdef DEBUG - av_log(avctx, AV_LOG_INFO, "Fill region (%d)\n", region->bgcolor); -#endif + av_dlog(avctx, "Fill region (%d)\n", region->bgcolor); } delete_region_display_list(ctx, region); @@ -1067,6 +1063,8 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx, if (!object) { object = av_mallocz(sizeof(DVBSubObject)); + if (!object) + return AVERROR(ENOMEM); object->id = object_id; object->next = ctx->object_list; @@ -1076,6 +1074,8 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx, object->type = (*buf) >> 6; display = av_mallocz(sizeof(DVBSubObjectDisplay)); + if (!display) + return AVERROR(ENOMEM); display->object_id = object_id; display->region_id = region_id; @@ -1096,12 +1096,14 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx, display->object_list_next = object->display_list; object->display_list = display; } + + return 0; } -static void dvbsub_parse_page_segment(AVCodecContext *avctx, - const uint8_t *buf, int buf_size) +static int dvbsub_parse_page_segment(AVCodecContext *avctx, + const uint8_t *buf, int buf_size) { - DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; + DVBSubContext *ctx = avctx->priv_data; DVBSubRegionDisplay *display; DVBSubRegionDisplay *tmp_display_list, **tmp_ptr; @@ -1110,14 +1112,12 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx, int page_state; if (buf_size < 1) - return; + return AVERROR_INVALIDDATA; ctx->time_out = *buf++; page_state = ((*buf++) >> 2) & 3; -#ifdef DEBUG - av_log(avctx, AV_LOG_INFO, "Page time out %ds, state %d\n", ctx->time_out, page_state); -#endif + av_dlog(avctx, "Page time out %ds, state %d\n", ctx->time_out, page_state); if (page_state == 2) { delete_state(ctx); @@ -1139,8 +1139,11 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx, display = display->next; } - if (!display) + if (!display) { display = av_mallocz(sizeof(DVBSubRegionDisplay)); + if (!display) + return AVERROR(ENOMEM); + } display->region_id = region_id; @@ -1155,9 +1158,7 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx, ctx->display_list = display; ctx->display_list_size++; -#ifdef DEBUG - av_log(avctx, AV_LOG_INFO, "Region %d, (%d,%d)\n", region_id, display->x_pos, display->y_pos); -#endif + av_dlog(avctx, "Region %d, (%d,%d)\n", region_id, display->x_pos, display->y_pos); } while (tmp_display_list) { @@ -1168,10 +1169,11 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx, av_free(display); } + return 0; } -#ifdef DEBUG_SAVE_IMAGES +#ifdef DEBUG static void save_display_set(DVBSubContext *ctx) { DVBSubRegion *region; @@ -1221,6 +1223,8 @@ static void save_display_set(DVBSubContext *ctx) if (x_pos >= 0) { pbuf = av_malloc(width * height * 4); + if (!pbuf) + return AVERROR(ENOMEM); for (display = ctx->display_list; display; display = display->next) { region = get_region(ctx, display->region_id); @@ -1266,10 +1270,53 @@ static void save_display_set(DVBSubContext *ctx) } #endif +static int dvbsub_parse_display_definition_segment(AVCodecContext *avctx, + const uint8_t *buf, + int buf_size) +{ + DVBSubContext *ctx = avctx->priv_data; + DVBSubDisplayDefinition *display_def = ctx->display_definition; + int dds_version, info_byte; + + if (buf_size < 5) + return AVERROR_INVALIDDATA; + + info_byte = bytestream_get_byte(&buf); + dds_version = info_byte >> 4; + if (display_def && display_def->version == dds_version) + return 0; // already have this display definition version + + if (!display_def) { + display_def = av_mallocz(sizeof(*display_def)); + if (!display_def) + return AVERROR(ENOMEM); + ctx->display_definition = display_def; + } + + display_def->version = dds_version; + display_def->x = 0; + display_def->y = 0; + display_def->width = bytestream_get_be16(&buf) + 1; + display_def->height = bytestream_get_be16(&buf) + 1; + + if (buf_size < 13) + return AVERROR_INVALIDDATA; + + if (info_byte & 1<<3) { // display_window_flag + display_def->x = bytestream_get_be16(&buf); + display_def->y = bytestream_get_be16(&buf); + display_def->width = bytestream_get_be16(&buf) - display_def->x + 1; + display_def->height = bytestream_get_be16(&buf) - display_def->y + 1; + } + + return 0; +} + static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf, - int buf_size, AVSubtitle *sub) + int buf_size, AVSubtitle *sub) { - DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; + DVBSubContext *ctx = avctx->priv_data; + DVBSubDisplayDefinition *display_def = ctx->display_definition; DVBSubRegion *region; DVBSubRegionDisplay *display; @@ -1277,19 +1324,26 @@ static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf, DVBSubCLUT *clut; uint32_t *clut_table; int i; + int offset_x=0, offset_y=0; sub->rects = NULL; sub->start_display_time = 0; sub->end_display_time = ctx->time_out * 1000; sub->format = 0; + if (display_def) { + offset_x = display_def->x; + offset_y = display_def->y; + } + sub->num_rects = ctx->display_list_size; + if (sub->num_rects <= 0) + return AVERROR_INVALIDDATA; - if (sub->num_rects > 0){ - sub->rects = av_mallocz(sizeof(*sub->rects) * sub->num_rects); - for(i=0; inum_rects; i++) - sub->rects[i] = av_mallocz(sizeof(*sub->rects[i])); - } + sub->rects = av_mallocz_array(sub->num_rects * sub->num_rects, + sizeof(*sub->rects)); + if (!sub->rects) + return AVERROR(ENOMEM); i = 0; @@ -1300,11 +1354,12 @@ static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf, if (!region) continue; - rect->x = display->x_pos; - rect->y = display->y_pos; + rect->x = display->x_pos + offset_x; + rect->y = display->y_pos + offset_y; rect->w = region->width; rect->h = region->height; rect->nb_colors = 16; + rect->type = SUBTITLE_BITMAP; rect->pict.linesize[0] = region->width; clut = get_clut(ctx, region->clut); @@ -1325,10 +1380,19 @@ static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf, break; } - rect->pict.data[1] = av_malloc((1 << region->depth) * sizeof(uint32_t)); + rect->pict.data[1] = av_mallocz(AVPALETTE_SIZE); + if (!rect->pict.data[1]) { + av_free(sub->rects); + return AVERROR(ENOMEM); + } memcpy(rect->pict.data[1], clut_table, (1 << region->depth) * sizeof(uint32_t)); rect->pict.data[0] = av_malloc(region->buf_size); + if (!rect->pict.data[0]) { + av_free(rect->pict.data[1]); + av_free(sub->rects); + return AVERROR(ENOMEM); + } memcpy(rect->pict.data[0], region->pbuf, region->buf_size); i++; @@ -1336,7 +1400,7 @@ static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf, sub->num_rects = i; -#ifdef DEBUG_SAVE_IMAGES +#ifdef DEBUG save_display_set(ctx); #endif @@ -1345,38 +1409,38 @@ static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf, static int dvbsub_decode(AVCodecContext *avctx, void *data, int *data_size, - const uint8_t *buf, int buf_size) + AVPacket *avpkt) { - DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data; - AVSubtitle *sub = (AVSubtitle*) data; + const uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; + DVBSubContext *ctx = avctx->priv_data; + AVSubtitle *sub = data; const uint8_t *p, *p_end; int segment_type; int page_id; int segment_length; - -#ifdef DEBUG_PACKET_CONTENTS int i; - av_log(avctx, AV_LOG_INFO, "DVB sub packet:\n"); + av_dlog(avctx, "DVB sub packet:\n"); for (i=0; i < buf_size; i++) { - av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]); + av_dlog(avctx, "%02x ", buf[i]); if (i % 16 == 15) - av_log(avctx, AV_LOG_INFO, "\n"); + av_dlog(avctx, "\n"); } if (i % 16) - av_log(avctx, AV_LOG_INFO, "\n"); + av_dlog(avctx, "\n"); -#endif - - if (buf_size <= 2) - return -1; + if (buf_size <= 6 || *buf != 0x0f) { + av_dlog(avctx, "incomplete or broken packet"); + return AVERROR_INVALIDDATA; + } p = buf; p_end = buf + buf_size; - while (p < p_end && *p == 0x0f) { + while (p_end - p >= 6 && *p == 0x0f) { p += 1; segment_type = *p++; page_id = AV_RB16(p); @@ -1384,54 +1448,58 @@ static int dvbsub_decode(AVCodecContext *avctx, segment_length = AV_RB16(p); p += 2; - if (page_id == ctx->composition_id || page_id == ctx->ancillary_id) { + if (p_end - p < segment_length) { + av_dlog(avctx, "incomplete or broken packet"); + return -1; + } + + if (page_id == ctx->composition_id || page_id == ctx->ancillary_id || + ctx->composition_id == -1 || ctx->ancillary_id == -1) { + int ret = 0; switch (segment_type) { case DVBSUB_PAGE_SEGMENT: - dvbsub_parse_page_segment(avctx, p, segment_length); + ret = dvbsub_parse_page_segment(avctx, p, segment_length); break; case DVBSUB_REGION_SEGMENT: - dvbsub_parse_region_segment(avctx, p, segment_length); + ret = dvbsub_parse_region_segment(avctx, p, segment_length); break; case DVBSUB_CLUT_SEGMENT: - dvbsub_parse_clut_segment(avctx, p, segment_length); + ret = dvbsub_parse_clut_segment(avctx, p, segment_length); break; case DVBSUB_OBJECT_SEGMENT: - dvbsub_parse_object_segment(avctx, p, segment_length); + ret = dvbsub_parse_object_segment(avctx, p, segment_length); + break; + case DVBSUB_DISPLAYDEFINITION_SEGMENT: + ret = dvbsub_parse_display_definition_segment(avctx, p, + segment_length); break; case DVBSUB_DISPLAY_SEGMENT: - *data_size = dvbsub_display_end_segment(avctx, p, segment_length, sub); + ret = dvbsub_display_end_segment(avctx, p, segment_length, sub); + *data_size = ret; break; default: -#ifdef DEBUG - av_log(avctx, AV_LOG_INFO, "Subtitling segment type 0x%x, page id %d, length %d\n", + av_dlog(avctx, "Subtitling segment type 0x%x, page id %d, length %d\n", segment_type, page_id, segment_length); -#endif break; } + if (ret < 0) + return ret; } p += segment_length; } - if (p != p_end) { -#ifdef DEBUG - av_log(avctx, AV_LOG_INFO, "Junk at end of packet\n"); -#endif - return -1; - } - - return buf_size; + return p - buf; } -AVCodec dvbsub_decoder = { - "dvbsub", - CODEC_TYPE_SUBTITLE, - CODEC_ID_DVB_SUBTITLE, - sizeof(DVBSubContext), - dvbsub_init_decoder, - NULL, - dvbsub_close_decoder, - dvbsub_decode, - .long_name = NULL_IF_CONFIG_SMALL("DVB subtitles"), +AVCodec ff_dvbsub_decoder = { + .name = "dvbsub", + .long_name = NULL_IF_CONFIG_SMALL("DVB subtitles"), + .type = AVMEDIA_TYPE_SUBTITLE, + .id = AV_CODEC_ID_DVB_SUBTITLE, + .priv_data_size = sizeof(DVBSubContext), + .init = dvbsub_init_decoder, + .close = dvbsub_close_decoder, + .decode = dvbsub_decode, };