X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=ffmpeg%2Flibavcodec%2Fdvdsubdec.c;h=222c71bdcf4d15de2b868267f971facc3b516d27;hb=HEAD;hp=7355c03ec2b1903257b14b2ed530d99f57bf4b2b;hpb=2ba45a602cbfa7b771effba9b11bb4245c21bc00;p=deb_ffmpeg.git diff --git a/ffmpeg/libavcodec/dvdsubdec.c b/ffmpeg/libavcodec/dvdsubdec.c index 7355c03..222c71b 100644 --- a/ffmpeg/libavcodec/dvdsubdec.c +++ b/ffmpeg/libavcodec/dvdsubdec.c @@ -28,17 +28,20 @@ #include "libavutil/opt.h" #include "libavutil/imgutils.h" #include "libavutil/avstring.h" +#include "libavutil/bswap.h" typedef struct DVDSubContext { AVClass *class; uint32_t palette[16]; char *palette_str; + char *ifo_str; int has_palette; uint8_t colormap[4]; uint8_t alpha[256]; - uint8_t *buf; + uint8_t buf[0x10000]; int buf_size; + int forced_subs_only; #ifdef DEBUG int sub_id; #endif @@ -105,6 +108,12 @@ static int decode_rle(uint8_t *bitmap, int linesize, int w, int h, int x, y, len, color; uint8_t *d; + if (start >= buf_size) + return -1; + + if (w <= 0 || h <= 0) + return -1; + bit_len = (buf_size - start) * 8; init_get_bits(&gb, buf + start, bit_len); @@ -356,10 +365,12 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, sub_header->rects[0] = av_mallocz(sizeof(AVSubtitleRect)); sub_header->num_rects = 1; sub_header->rects[0]->pict.data[0] = bitmap; - decode_rle(bitmap, w * 2, w, (h + 1) / 2, - buf, offset1, buf_size, is_8bit); - decode_rle(bitmap + w, w * 2, w, h / 2, - buf, offset2, buf_size, is_8bit); + if (decode_rle(bitmap, w * 2, w, (h + 1) / 2, + buf, offset1, buf_size, is_8bit) < 0) + goto fail; + if (decode_rle(bitmap + w, w * 2, w, h / 2, + buf, offset2, buf_size, is_8bit) < 0) + goto fail; sub_header->rects[0]->pict.data[1] = av_mallocz(AVPALETTE_SIZE); if (is_8bit) { if (!yuv_palette) @@ -498,15 +509,11 @@ static int append_to_cached_buf(AVCodecContext *avctx, { DVDSubContext *ctx = avctx->priv_data; - if (ctx->buf_size > 0xffff - buf_size) { + if (ctx->buf_size >= sizeof(ctx->buf) - buf_size) { av_log(avctx, AV_LOG_WARNING, "Attempt to reconstruct " "too large SPU packets aborted.\n"); - av_freep(&ctx->buf); return AVERROR_INVALIDDATA; } - ctx->buf = av_realloc(ctx->buf, ctx->buf_size + buf_size); - if (!ctx->buf) - return AVERROR(ENOMEM); memcpy(ctx->buf + ctx->buf_size, buf, buf_size); ctx->buf_size += buf_size; return 0; @@ -522,7 +529,7 @@ static int dvdsub_decode(AVCodecContext *avctx, AVSubtitle *sub = data; int is_menu; - if (ctx->buf) { + if (ctx->buf_size) { int ret = append_to_cached_buf(avctx, buf, buf_size); if (ret < 0) { *data_size = 0; @@ -548,6 +555,9 @@ static int dvdsub_decode(AVCodecContext *avctx, if (!is_menu && find_smallest_bounding_rectangle(sub) == 0) goto no_subtitle; + if (ctx->forced_subs_only && !(sub->rects[0]->flags & AV_SUBTITLE_FLAG_FORCED)) + goto no_subtitle; + #if defined(DEBUG) { char ppm_name[32]; @@ -561,7 +571,6 @@ static int dvdsub_decode(AVCodecContext *avctx, } #endif - av_freep(&ctx->buf); ctx->buf_size = 0; *data_size = 1; return buf_size; @@ -579,10 +588,71 @@ static void parse_palette(DVDSubContext *ctx, char *p) } } +static int parse_ifo_palette(DVDSubContext *ctx, char *p) +{ + FILE *ifo; + char ifostr[12]; + uint32_t sp_pgci, pgci, off_pgc, pgc; + uint8_t r, g, b, yuv[65], *buf; + int i, y, cb, cr, r_add, g_add, b_add; + int ret = 0; + const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; + + ctx->has_palette = 0; + if ((ifo = fopen(p, "r")) == NULL) { + av_log(ctx, AV_LOG_WARNING, "Unable to open IFO file \"%s\": %s\n", p, strerror(errno)); + return AVERROR_EOF; + } + if (fread(ifostr, 12, 1, ifo) != 1 || memcmp(ifostr, "DVDVIDEO-VTS", 12)) { + av_log(ctx, AV_LOG_WARNING, "\"%s\" is not a proper IFO file\n", p); + ret = AVERROR_INVALIDDATA; + goto end; + } + if (fseek(ifo, 0xCC, SEEK_SET) == -1) { + ret = AVERROR(errno); + goto end; + } + if (fread(&sp_pgci, 4, 1, ifo) == 1) { + pgci = av_be2ne32(sp_pgci) * 2048; + if (fseek(ifo, pgci + 0x0C, SEEK_SET) == -1) { + ret = AVERROR(errno); + goto end; + } + if (fread(&off_pgc, 4, 1, ifo) == 1) { + pgc = pgci + av_be2ne32(off_pgc); + if (fseek(ifo, pgc + 0xA4, SEEK_SET) == -1) { + ret = AVERROR(errno); + goto end; + } + if (fread(yuv, 64, 1, ifo) == 1) { + buf = yuv; + for(i=0; i<16; i++) { + y = *++buf; + cr = *++buf; + cb = *++buf; + YUV_TO_RGB1_CCIR(cb, cr); + YUV_TO_RGB2_CCIR(r, g, b, y); + ctx->palette[i] = (r << 16) + (g << 8) + b; + buf++; + } + ctx->has_palette = 1; + } + } + } + if (ctx->has_palette == 0) { + av_log(ctx, AV_LOG_WARNING, "Failed to read palette from IFO file \"%s\"\n", p); + ret = AVERROR_INVALIDDATA; + } +end: + fclose(ifo); + return ret; +} + static int dvdsub_parse_extradata(AVCodecContext *avctx) { DVDSubContext *ctx = (DVDSubContext*) avctx->priv_data; char *dataorig, *data; + int ret = 1; if (!avctx->extradata || !avctx->extradata_size) return 1; @@ -603,11 +673,9 @@ static int dvdsub_parse_extradata(AVCodecContext *avctx) } else if (strncmp("size:", data, 5) == 0) { int w, h; if (sscanf(data + 5, "%dx%d", &w, &h) == 2) { - int ret = ff_set_dimensions(avctx, w, h); - if (ret < 0) { - av_free(dataorig); - return ret; - } + ret = ff_set_dimensions(avctx, w, h); + if (ret < 0) + goto fail; } } @@ -615,8 +683,9 @@ static int dvdsub_parse_extradata(AVCodecContext *avctx) data += strspn(data, "\n\r"); } +fail: av_free(dataorig); - return 1; + return ret; } static av_cold int dvdsub_init(AVCodecContext *avctx) @@ -627,6 +696,8 @@ static av_cold int dvdsub_init(AVCodecContext *avctx) if ((ret = dvdsub_parse_extradata(avctx)) < 0) return ret; + if (ctx->ifo_str) + parse_ifo_palette(ctx, ctx->ifo_str); if (ctx->palette_str) parse_palette(ctx, ctx->palette_str); if (ctx->has_palette) { @@ -643,15 +714,16 @@ static av_cold int dvdsub_init(AVCodecContext *avctx) static av_cold int dvdsub_close(AVCodecContext *avctx) { DVDSubContext *ctx = avctx->priv_data; - av_freep(&ctx->buf); ctx->buf_size = 0; return 0; } #define OFFSET(field) offsetof(DVDSubContext, field) -#define VD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM +#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { - { "palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD }, + { "palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD }, + { "ifo_palette", "obtain the global palette from .IFO file", OFFSET(ifo_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD }, + { "forced_subs_only", "Only show forced subtitles", OFFSET(forced_subs_only), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, SD}, { NULL } }; static const AVClass dvdsub_class = {