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)
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);
}
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;
}
}
+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)
{
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;
&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++)
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;
}
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);
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;
}