Merge commit 'd466d82faaf6e0e57a3a4be5e38e3902ef251ac3'
authorMichael Niedermayer <michaelni@gmx.at>
Fri, 21 Nov 2014 21:33:23 +0000 (22:33 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Fri, 21 Nov 2014 21:36:01 +0000 (22:36 +0100)
* commit 'd466d82faaf6e0e57a3a4be5e38e3902ef251ac3':
  dvdsubdec: Do not leak on failure path

Conflicts:
libavcodec/dvdsubdec.c

See: 7fa9f7ef1c2f0cee81ec6ea6a4ff10af4c4fc62c
Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavcodec/dvdsubdec.c

@@@ -573,164 -499,49 +573,164 @@@ static int dvdsub_decode(AVCodecContex
      return buf_size;
  }
  
 -static av_cold int dvdsub_init(AVCodecContext *avctx)
 +static void parse_palette(DVDSubContext *ctx, char *p)
  {
 -    DVDSubContext *ctx = avctx->priv_data;
 -    char *data, *cur;
 +    int i;
 +
 +    ctx->has_palette = 1;
 +    for(i=0;i<16;i++) {
 +        ctx->palette[i] = strtoul(p, &p, 16);
 +        while(*p == ',' || av_isspace(*p))
 +            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 0;
 +        return 1;
  
 -    data = av_malloc(avctx->extradata_size + 1);
 +    dataorig = data = av_malloc(avctx->extradata_size+1);
      if (!data)
          return AVERROR(ENOMEM);
      memcpy(data, avctx->extradata, avctx->extradata_size);
      data[avctx->extradata_size] = '\0';
 -    cur = data;
 -
 -    while (*cur) {
 -        if (strncmp("palette:", cur, 8) == 0) {
 -            int i;
 -            char *p = cur + 8;
 -            ctx->has_palette = 1;
 -            for (i = 0; i < 16; i++) {
 -                ctx->palette[i] = strtoul(p, &p, 16);
 -                while (*p == ',' || av_isspace(*p))
 -                    p++;
 -            }
 -        } else if (!strncmp("size:", cur, 5)) {
 +
 +    for(;;) {
 +        int pos = strcspn(data, "\n\r");
 +        if (pos==0 && *data==0)
 +            break;
 +
 +        if (strncmp("palette:", data, 8) == 0) {
 +            parse_palette(ctx, data + 8);
 +        } else if (strncmp("size:", data, 5) == 0) {
              int w, h;
 -            if (sscanf(cur + 5, "%dx%d", &w, &h) == 2) {
 +            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;
              }
          }
 -        cur += strcspn(cur, "\n\r");
 -        cur += strspn(cur, "\n\r");
 +
 +        data += pos;
 +        data += strspn(data, "\n\r");
      }
  
 -    av_free(data);
+ fail:
-     return 1;
 +    av_free(dataorig);
+     return ret;
  }
  
 +static av_cold int dvdsub_init(AVCodecContext *avctx)
 +{
 +    DVDSubContext *ctx = avctx->priv_data;
 +    int ret;
 +
 +    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) {
 +        int i;
 +        av_log(avctx, AV_LOG_DEBUG, "palette:");
 +        for(i=0;i<16;i++)
 +            av_log(avctx, AV_LOG_DEBUG, " 0x%06x", ctx->palette[i]);
 +        av_log(avctx, AV_LOG_DEBUG, "\n");
 +    }
 +
 +    return 1;
 +}
 +
 +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 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, 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 = {
 +    .class_name = "dvdsubdec",
 +    .item_name  = av_default_item_name,
 +    .option     = options,
 +    .version    = LIBAVUTIL_VERSION_INT,
 +};
 +
  AVCodec ff_dvdsub_decoder = {
      .name           = "dvdsub",
      .long_name      = NULL_IF_CONFIG_SMALL("DVD subtitles"),