| Index: ffmpeg/patches/to_upstream/42_vp8_fix_segmentation_maps.patch
|
| diff --git a/ffmpeg/patches/to_upstream/42_vp8_fix_segmentation_maps.patch b/ffmpeg/patches/to_upstream/42_vp8_fix_segmentation_maps.patch
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..46af48ae9a9001a31c49ebffd89da99bd7f4e7cd
|
| --- /dev/null
|
| +++ b/ffmpeg/patches/to_upstream/42_vp8_fix_segmentation_maps.patch
|
| @@ -0,0 +1,180 @@
|
| +diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c
|
| +index 7442b99..447bdb5 100644
|
| +--- a/libavcodec/vp8.c
|
| ++++ b/libavcodec/vp8.c
|
| +@@ -41,24 +41,57 @@ static void free_buffers(VP8Context *s)
|
| + av_freep(&s->top_nnz);
|
| + av_freep(&s->edge_emu_buffer);
|
| + av_freep(&s->top_border);
|
| +- av_freep(&s->segmentation_map);
|
| +
|
| + s->macroblocks = NULL;
|
| + }
|
| +
|
| +-static void vp8_decode_flush(AVCodecContext *avctx)
|
| ++static int vp8_alloc_frame(VP8Context *s, AVFrame *f)
|
| ++{
|
| ++ int ret;
|
| ++ if ((ret = ff_thread_get_buffer(s->avctx, f)) < 0)
|
| ++ return ret;
|
| ++ if (!s->maps_are_invalid && s->num_maps_to_be_freed) {
|
| ++ f->ref_index[0] = s->segmentation_maps[--s->num_maps_to_be_freed];
|
| ++ } else if (!(f->ref_index[0] = av_mallocz(s->mb_width * s->mb_height))) {
|
| ++ ff_thread_release_buffer(s->avctx, f);
|
| ++ return AVERROR(ENOMEM);
|
| ++ }
|
| ++ return 0;
|
| ++}
|
| ++
|
| ++static void vp8_release_frame(VP8Context *s, AVFrame *f, int is_close)
|
| ++{
|
| ++ if (!is_close) {
|
| ++ if (f->ref_index[0]) {
|
| ++ assert(s->num_maps_to_be_freed < FF_ARRAY_ELEMS(s->segmentation_maps));
|
| ++ s->segmentation_maps[s->num_maps_to_be_freed++] = f->ref_index[0];
|
| ++ f->ref_index[0] = NULL;
|
| ++ }
|
| ++ } else {
|
| ++ av_freep(&f->ref_index[0]);
|
| ++ }
|
| ++ ff_thread_release_buffer(s->avctx, f);
|
| ++}
|
| ++
|
| ++static void vp8_decode_flush_impl(AVCodecContext *avctx, int force, int is_close)
|
| + {
|
| + VP8Context *s = avctx->priv_data;
|
| + int i;
|
| +
|
| +- if (!avctx->is_copy) {
|
| ++ if (!avctx->is_copy || force) {
|
| + for (i = 0; i < 5; i++)
|
| + if (s->frames[i].data[0])
|
| +- ff_thread_release_buffer(avctx, &s->frames[i]);
|
| ++ vp8_release_frame(s, &s->frames[i], is_close);
|
| + }
|
| + memset(s->framep, 0, sizeof(s->framep));
|
| +
|
| + free_buffers(s);
|
| ++ s->maps_are_invalid = 1;
|
| ++}
|
| ++
|
| ++static void vp8_decode_flush(AVCodecContext *avctx)
|
| ++{
|
| ++ vp8_decode_flush_impl(avctx, 0, 0);
|
| + }
|
| +
|
| + static int update_dimensions(VP8Context *s, int width, int height)
|
| +@@ -68,7 +101,7 @@ static int update_dimensions(VP8Context *s, int width, int height)
|
| + if (av_image_check_size(width, height, 0, s->avctx))
|
| + return AVERROR_INVALIDDATA;
|
| +
|
| +- vp8_decode_flush(s->avctx);
|
| ++ vp8_decode_flush_impl(s->avctx, 1, 0);
|
| +
|
| + avcodec_set_dimensions(s->avctx, width, height);
|
| + }
|
| +@@ -81,10 +114,9 @@ static int update_dimensions(VP8Context *s, int width, int height)
|
| + s->intra4x4_pred_mode_top = av_mallocz(s->mb_width*4);
|
| + s->top_nnz = av_mallocz(s->mb_width*sizeof(*s->top_nnz));
|
| + s->top_border = av_mallocz((s->mb_width+1)*sizeof(*s->top_border));
|
| +- s->segmentation_map = av_mallocz(s->mb_width*s->mb_height);
|
| +
|
| + if (!s->macroblocks_base || !s->filter_strength || !s->intra4x4_pred_mode_top ||
|
| +- !s->top_nnz || !s->top_border || !s->segmentation_map)
|
| ++ !s->top_nnz || !s->top_border)
|
| + return AVERROR(ENOMEM);
|
| +
|
| + s->macroblocks = s->macroblocks_base + 1;
|
| +@@ -1508,6 +1540,14 @@ static void filter_mb_row_simple(VP8Context *s, AVFrame *curframe, int mb_y)
|
| + }
|
| + }
|
| +
|
| ++static void release_queued_segmaps(VP8Context *s, int is_close)
|
| ++{
|
| ++ int leave_behind = is_close ? 0 : !s->maps_are_invalid;
|
| ++ while (s->num_maps_to_be_freed > leave_behind)
|
| ++ av_freep(&s->segmentation_maps[--s->num_maps_to_be_freed]);
|
| ++ s->maps_are_invalid = 0;
|
| ++}
|
| ++
|
| + static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
|
| + AVPacket *avpkt)
|
| + {
|
| +@@ -1516,6 +1556,8 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
|
| + enum AVDiscard skip_thresh;
|
| + AVFrame *av_uninit(curframe), *prev_frame = s->framep[VP56_FRAME_CURRENT];
|
| +
|
| ++ release_queued_segmaps(s, 0);
|
| ++
|
| + if ((ret = decode_frame_header(s, avpkt->data, avpkt->size)) < 0)
|
| + return ret;
|
| +
|
| +@@ -1538,7 +1580,7 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
|
| + &s->frames[i] != s->framep[VP56_FRAME_PREVIOUS] &&
|
| + &s->frames[i] != s->framep[VP56_FRAME_GOLDEN] &&
|
| + &s->frames[i] != s->framep[VP56_FRAME_GOLDEN2])
|
| +- ff_thread_release_buffer(avctx, &s->frames[i]);
|
| ++ vp8_release_frame(s, &s->frames[i], 0);
|
| +
|
| + // find a free buffer
|
| + for (i = 0; i < 5; i++)
|
| +@@ -1559,8 +1601,7 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
|
| + curframe->key_frame = s->keyframe;
|
| + curframe->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
|
| + curframe->reference = referenced ? 3 : 0;
|
| +- curframe->ref_index[0] = s->segmentation_map;
|
| +- if ((ret = ff_thread_get_buffer(avctx, curframe))) {
|
| ++ if ((ret = vp8_alloc_frame(s, curframe))) {
|
| + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed!\n");
|
| + return ret;
|
| + }
|
| +@@ -1652,8 +1693,8 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
|
| + s->dsp.prefetch(dst[0] + (mb_x&3)*4*s->linesize + 64, s->linesize, 4);
|
| + s->dsp.prefetch(dst[1] + (mb_x&7)*s->uvlinesize + 64, dst[2] - dst[1], 2);
|
| +
|
| +- decode_mb_mode(s, mb, mb_x, mb_y, s->segmentation_map + mb_xy,
|
| +- prev_frame ? prev_frame->ref_index[0] + mb_xy : NULL);
|
| ++ decode_mb_mode(s, mb, mb_x, mb_y, curframe->ref_index[0] + mb_xy,
|
| ++ prev_frame && prev_frame->ref_index[0] ? prev_frame->ref_index[0] + mb_xy : NULL);
|
| +
|
| + prefetch_motion(s, mb, mb_x, mb_y, mb_xy, VP56_FRAME_PREVIOUS);
|
| +
|
| +@@ -1736,7 +1777,8 @@ static av_cold int vp8_decode_init(AVCodecContext *avctx)
|
| +
|
| + static av_cold int vp8_decode_free(AVCodecContext *avctx)
|
| + {
|
| +- vp8_decode_flush(avctx);
|
| ++ vp8_decode_flush_impl(avctx, 0, 1);
|
| ++ release_queued_segmaps(avctx->priv_data, 1);
|
| + return 0;
|
| + }
|
| +
|
| +diff --git a/libavcodec/vp8.h b/libavcodec/vp8.h
|
| +index 5a96cd4..6cbdca2 100644
|
| +--- a/libavcodec/vp8.h
|
| ++++ b/libavcodec/vp8.h
|
| +@@ -130,7 +130,6 @@ typedef struct {
|
| +
|
| + uint8_t *intra4x4_pred_mode_top;
|
| + uint8_t intra4x4_pred_mode_left[4];
|
| +- uint8_t *segmentation_map;
|
| +
|
| + /**
|
| + * Macroblocks can have one of 4 different quants in a frame when
|
| +@@ -237,6 +236,16 @@ typedef struct {
|
| + H264PredContext hpc;
|
| + vp8_mc_func put_pixels_tab[3][3][3];
|
| + AVFrame frames[5];
|
| ++
|
| ++ /**
|
| ++ * A list of segmentation_map buffers that are to be free()'ed in
|
| ++ * the next decoding iteration. We can't free() them right away
|
| ++ * because the map may still be used by subsequent decoding threads.
|
| ++ * Unused if frame threading is off.
|
| ++ */
|
| ++ uint8_t *segmentation_maps[5];
|
| ++ int num_maps_to_be_freed;
|
| ++ int maps_are_invalid;
|
| + } VP8Context;
|
| +
|
| + #endif /* AVCODEC_VP8_H */
|
|
|