Merge commit 'a594f17f83a1ffdc1eec18818208fe39487dd5d7'
authorJames Almer <jamrial@gmail.com>
Mon, 6 Nov 2017 21:46:05 +0000 (18:46 -0300)
committerJames Almer <jamrial@gmail.com>
Mon, 6 Nov 2017 21:46:05 +0000 (18:46 -0300)
* commit 'a594f17f83a1ffdc1eec18818208fe39487dd5d7':
  dvbsubdec: Free subrect memory on allocation error
  dvbsubdec: Fixed segfault when decoding subtitles

See
fbb59a3bf4c8668197521b3db5f26d0e93aed1a6
39dfe6801a3f67c2964a829b65e8e38e3cb22217

Merged-by: James Almer <jamrial@gmail.com>
1  2 
libavcodec/dvbsubdec.c

index 85a59f3ced0d5867ac86fe402d1a05572532985d,b97ff8027b4c8e4aad9f504e6e01399143dde8f0..4e08dba35c544bf7191ff2debab06a4b8476b681
@@@ -647,203 -602,7 +647,208 @@@ static int dvbsub_read_8bit_string(AVCo
      return pixels_read;
  }
  
-         for(i=0; i<sub->num_rects; i++)
 +static void compute_default_clut(AVSubtitleRect *rect, int w, int h)
 +{
 +    uint8_t list[256] = {0};
 +    uint8_t list_inv[256];
 +    int counttab[256] = {0};
 +    int count, i, x, y;
 +    ptrdiff_t stride = rect->linesize[0];
 +#define V(x,y) rect->data[0][(x) + (y)*stride]
 +    for (y = 0; y<h; y++) {
 +        for (x = 0; x<w; x++) {
 +            int v = V(x,y) + 1;
 +            int vl = x     ? V(x-1,y) + 1 : 0;
 +            int vr = x+1<w ? V(x+1,y) + 1 : 0;
 +            int vt = y     ? V(x,y-1) + 1 : 0;
 +            int vb = y+1<h ? V(x,y+1) + 1 : 0;
 +            counttab[v-1] += !!((v!=vl) + (v!=vr) + (v!=vt) + (v!=vb));
 +        }
 +    }
 +#define L(x,y) list[d[(x) + (y)*stride]]
 +
 +    for (i = 0; i<256; i++) {
 +        int scoretab[256] = {0};
 +        int bestscore = 0;
 +        int bestv = 0;
 +        for (y = 0; y<h; y++) {
 +            for (x = 0; x<w; x++) {
 +                uint8_t *d = &rect->data[0][x + y*stride];
 +                int v = *d;
 +                int l_m = list[v];
 +                int l_l = x     ? L(-1, 0) : 1;
 +                int l_r = x+1<w ? L( 1, 0) : 1;
 +                int l_t = y     ? L( 0,-1) : 1;
 +                int l_b = y+1<h ? L( 0, 1) : 1;
 +                if (l_m)
 +                    continue;
 +                scoretab[v] += l_l + l_r + l_t + l_b;
 +            }
 +        }
 +        for (x = 0; x < 256; x++) {
 +            if (scoretab[x]) {
 +                int score = 1024LL*scoretab[x] / counttab[x];
 +                if (score > bestscore) {
 +                    bestscore = score;
 +                    bestv = x;
 +                }
 +            }
 +        }
 +        if (!bestscore)
 +            break;
 +        list    [ bestv ] = 1;
 +        list_inv[     i ] = bestv;
 +    }
 +
 +    count = FFMAX(i - 1, 1);
 +    for (i--; i>=0; i--) {
 +        int v = i*255/count;
 +        AV_WN32(rect->data[1] + 4*list_inv[i], RGBA(v/2,v,v/2,v));
 +    }
 +}
 +
 +
 +static int save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_output)
 +{
 +    DVBSubContext *ctx = avctx->priv_data;
 +    DVBSubRegionDisplay *display;
 +    DVBSubDisplayDefinition *display_def = ctx->display_definition;
 +    DVBSubRegion *region;
 +    AVSubtitleRect *rect;
 +    DVBSubCLUT *clut;
 +    uint32_t *clut_table;
 +    int i;
 +    int offset_x=0, offset_y=0;
 +    int ret = 0;
 +
 +
 +    if (display_def) {
 +        offset_x = display_def->x;
 +        offset_y = display_def->y;
 +    }
 +
 +    /* Not touching AVSubtitles again*/
 +    if(sub->num_rects) {
 +        avpriv_request_sample(ctx, "Different Version of Segment asked Twice");
 +        return AVERROR_PATCHWELCOME;
 +    }
 +    for (display = ctx->display_list; display; display = display->next) {
 +        region = get_region(ctx, display->region_id);
 +        if (region && region->dirty)
 +            sub->num_rects++;
 +    }
 +
 +    if(ctx->compute_edt == 0) {
 +        sub->end_display_time = ctx->time_out * 1000;
 +        *got_output = 1;
 +    } else if (ctx->prev_start != AV_NOPTS_VALUE) {
 +        sub->end_display_time = av_rescale_q((sub->pts - ctx->prev_start ), AV_TIME_BASE_Q, (AVRational){ 1, 1000 }) - 1;
 +        *got_output = 1;
 +    }
 +    if (sub->num_rects > 0) {
 +
 +        sub->rects = av_mallocz_array(sizeof(*sub->rects), sub->num_rects);
 +        if (!sub->rects) {
 +            ret = AVERROR(ENOMEM);
 +            goto fail;
 +        }
 +
++        for (i = 0; i < sub->num_rects; i++) {
 +            sub->rects[i] = av_mallocz(sizeof(*sub->rects[i]));
++            if (!sub->rects[i]) {
++                ret = AVERROR(ENOMEM);
++                goto fail;
++            }
++        }
 +
 +        i = 0;
 +
 +        for (display = ctx->display_list; display; display = display->next) {
 +            region = get_region(ctx, display->region_id);
 +
 +            if (!region)
 +                continue;
 +
 +            if (!region->dirty)
 +                continue;
 +
 +            rect = sub->rects[i];
 +            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 = (1 << region->depth);
 +            rect->type      = SUBTITLE_BITMAP;
 +            rect->linesize[0] = region->width;
 +
 +            clut = get_clut(ctx, region->clut);
 +
 +            if (!clut)
 +                clut = &default_clut;
 +
 +            switch (region->depth) {
 +            case 2:
 +                clut_table = clut->clut4;
 +                break;
 +            case 8:
 +                clut_table = clut->clut256;
 +                break;
 +            case 4:
 +            default:
 +                clut_table = clut->clut16;
 +                break;
 +            }
 +
 +            rect->data[1] = av_mallocz(AVPALETTE_SIZE);
 +            if (!rect->data[1]) {
 +                ret = AVERROR(ENOMEM);
 +                goto fail;
 +            }
 +            memcpy(rect->data[1], clut_table, (1 << region->depth) * sizeof(uint32_t));
 +
 +            rect->data[0] = av_malloc(region->buf_size);
 +            if (!rect->data[0]) {
 +                ret = AVERROR(ENOMEM);
 +                goto fail;
 +            }
 +
 +            memcpy(rect->data[0], region->pbuf, region->buf_size);
 +
 +            if ((clut == &default_clut && ctx->compute_clut == -1) || ctx->compute_clut == 1)
 +                compute_default_clut(rect, rect->w, rect->h);
 +
 +#if FF_API_AVPICTURE
 +FF_DISABLE_DEPRECATION_WARNINGS
 +{
 +            int j;
 +            for (j = 0; j < 4; j++) {
 +                rect->pict.data[j] = rect->data[j];
 +                rect->pict.linesize[j] = rect->linesize[j];
 +            }
 +}
 +FF_ENABLE_DEPRECATION_WARNINGS
 +#endif
 +
 +            i++;
 +        }
 +    }
  
 +    return 0;
 +fail:
 +    if (sub->rects) {
 +        for(i=0; i<sub->num_rects; i++) {
 +            rect = sub->rects[i];
 +            if (rect) {
 +                av_freep(&rect->data[0]);
 +                av_freep(&rect->data[1]);
 +            }
 +            av_freep(&sub->rects[i]);
 +        }
 +        av_freep(&sub->rects);
 +    }
 +    sub->num_rects = 0;
 +    return ret;
 +}
  
  static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDisplay *display,
                                            const uint8_t *buf, int buf_size, int top_bottom, int non_mod)