X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fvp8.c;h=d9fdd4da441654650f63a032c5e5fe7f86fd3fdb;hb=4466d0e84b3a105a02170ce8bc9e22820ff0152f;hp=d5cdaba486c79cc3ceffbbfafb6eef5b91aad983;hpb=ce42a04884cd6585c596f1ecfe737dacc3e6f396;p=ffmpeg diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c index d5cdaba486c..d9fdd4da441 100644 --- a/libavcodec/vp8.c +++ b/libavcodec/vp8.c @@ -1,4 +1,4 @@ -/** +/* * VP8 compatible video decoder * * Copyright (C) 2010 David Conrad @@ -24,6 +24,7 @@ #include "libavutil/imgutils.h" #include "avcodec.h" +#include "internal.h" #include "vp8.h" #include "vp8data.h" #include "rectangle.h" @@ -50,7 +51,7 @@ 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) { + if (s->num_maps_to_be_freed && !s->maps_are_invalid) { 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); @@ -59,39 +60,50 @@ static int vp8_alloc_frame(VP8Context *s, AVFrame *f) return 0; } -static void vp8_release_frame(VP8Context *s, AVFrame *f, int is_close) +static void vp8_release_frame(VP8Context *s, AVFrame *f, int prefer_delayed_free, int can_direct_free) { - 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]; + if (f->ref_index[0]) { + if (prefer_delayed_free) { + /* Upon a size change, we want to free the maps but other threads may still + * be using them, so queue them. Upon a seek, all threads are inactive so + * we want to cache one to prevent re-allocation in the next decoding + * iteration, but the rest we can free directly. */ + int max_queued_maps = can_direct_free ? 1 : FF_ARRAY_ELEMS(s->segmentation_maps); + if (s->num_maps_to_be_freed < max_queued_maps) { + s->segmentation_maps[s->num_maps_to_be_freed++] = f->ref_index[0]; + } else if (can_direct_free) /* vp8_decode_flush(), but our queue is full */ { + av_free(f->ref_index[0]); + } /* else: MEMLEAK (should never happen, but better that than crash) */ f->ref_index[0] = NULL; + } else /* vp8_decode_free() */ { + av_free(f->ref_index[0]); } - } 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) +static void vp8_decode_flush_impl(AVCodecContext *avctx, + int prefer_delayed_free, int can_direct_free, int free_mem) { VP8Context *s = avctx->priv_data; int i; - if (!avctx->is_copy || force) { + if (!avctx->internal->is_copy) { for (i = 0; i < 5; i++) if (s->frames[i].data[0]) - vp8_release_frame(s, &s->frames[i], is_close); + vp8_release_frame(s, &s->frames[i], prefer_delayed_free, can_direct_free); } memset(s->framep, 0, sizeof(s->framep)); - free_buffers(s); - s->maps_are_invalid = 1; + if (free_mem) { + free_buffers(s); + s->maps_are_invalid = 1; + } } static void vp8_decode_flush(AVCodecContext *avctx) { - vp8_decode_flush_impl(avctx, 0, 0); + vp8_decode_flush_impl(avctx, 1, 1, 0); } static int update_dimensions(VP8Context *s, int width, int height) @@ -101,7 +113,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_impl(s->avctx, 1, 0); + vp8_decode_flush_impl(s->avctx, 1, 0, 1); avcodec_set_dimensions(s->avctx, width, height); } @@ -150,11 +162,23 @@ static void update_lf_deltas(VP8Context *s) VP56RangeCoder *c = &s->c; int i; - for (i = 0; i < 4; i++) - s->lf_delta.ref[i] = vp8_rac_get_sint(c, 6); + for (i = 0; i < 4; i++) { + if (vp8_rac_get(c)) { + s->lf_delta.ref[i] = vp8_rac_get_uint(c, 6); + + if (vp8_rac_get(c)) + s->lf_delta.ref[i] = -s->lf_delta.ref[i]; + } + } + + for (i = MODE_I4x4; i <= VP8_MVMODE_SPLIT; i++) { + if (vp8_rac_get(c)) { + s->lf_delta.mode[i] = vp8_rac_get_uint(c, 6); - for (i = MODE_I4x4; i <= VP8_MVMODE_SPLIT; i++) - s->lf_delta.mode[i] = vp8_rac_get_sint(c, 6); + if (vp8_rac_get(c)) + s->lf_delta.mode[i] = -s->lf_delta.mode[i]; + } + } } static int setup_partitions(VP8Context *s, const uint8_t *buf, int buf_size) @@ -629,7 +653,7 @@ void decode_mb_mode(VP8Context *s, VP8Macroblock *mb, int mb_x, int mb_y, uint8_ if (s->segmentation.update_map) *segment = vp8_rac_get_tree(c, vp8_segmentid_tree, s->prob->segmentid); - else + else if (s->segmentation.enabled) *segment = ref ? *ref : *segment; s->segment = *segment; @@ -1554,12 +1578,14 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size, VP8Context *s = avctx->priv_data; int ret, mb_x, mb_y, i, y, referenced; enum AVDiscard skip_thresh; - AVFrame *av_uninit(curframe), *prev_frame = s->framep[VP56_FRAME_CURRENT]; + AVFrame *av_uninit(curframe), *prev_frame; release_queued_segmaps(s, 0); if ((ret = decode_frame_header(s, avpkt->data, avpkt->size)) < 0) - return ret; + goto err; + + prev_frame = s->framep[VP56_FRAME_CURRENT]; referenced = s->update_last || s->update_golden == VP56_FRAME_CURRENT || s->update_altref == VP56_FRAME_CURRENT; @@ -1569,6 +1595,7 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size, if (avctx->skip_frame >= skip_thresh) { s->invisible = 1; + memcpy(&s->next_framep[0], &s->framep[0], sizeof(s->framep[0]) * 4); goto skip_decode; } s->deblock_filter = s->filter.level && avctx->skip_loop_filter < skip_thresh; @@ -1580,7 +1607,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]) - vp8_release_frame(s, &s->frames[i], 0); + vp8_release_frame(s, &s->frames[i], 1, 0); // find a free buffer for (i = 0; i < 5; i++) @@ -1596,14 +1623,25 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size, abort(); } if (curframe->data[0]) - ff_thread_release_buffer(avctx, curframe); + vp8_release_frame(s, curframe, 1, 0); + + // Given that arithmetic probabilities are updated every frame, it's quite likely + // that the values we have on a random interframe are complete junk if we didn't + // start decode on a keyframe. So just don't display anything rather than junk. + if (!s->keyframe && (!s->framep[VP56_FRAME_PREVIOUS] || + !s->framep[VP56_FRAME_GOLDEN] || + !s->framep[VP56_FRAME_GOLDEN2])) { + av_log(avctx, AV_LOG_WARNING, "Discarding interframe without a prior keyframe!\n"); + ret = AVERROR_INVALIDDATA; + goto err; + } curframe->key_frame = s->keyframe; curframe->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; curframe->reference = referenced ? 3 : 0; if ((ret = vp8_alloc_frame(s, curframe))) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed!\n"); - return ret; + goto err; } // check if golden and altref are swapped @@ -1626,16 +1664,6 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size, ff_thread_finish_setup(avctx); - // Given that arithmetic probabilities are updated every frame, it's quite likely - // that the values we have on a random interframe are complete junk if we didn't - // start decode on a keyframe. So just don't display anything rather than junk. - if (!s->keyframe && (!s->framep[VP56_FRAME_PREVIOUS] || - !s->framep[VP56_FRAME_GOLDEN] || - !s->framep[VP56_FRAME_GOLDEN2])) { - av_log(avctx, AV_LOG_WARNING, "Discarding interframe without a prior keyframe!\n"); - return AVERROR_INVALIDDATA; - } - s->linesize = curframe->linesize[0]; s->uvlinesize = curframe->linesize[1]; @@ -1745,20 +1773,23 @@ static int vp8_decode_frame(AVCodecContext *avctx, void *data, int *data_size, } ff_thread_report_progress(curframe, INT_MAX, 0); + memcpy(&s->framep[0], &s->next_framep[0], sizeof(s->framep[0]) * 4); + skip_decode: // if future frames don't use the updated probabilities, // reset them to the values we saved if (!s->update_probabilities) s->prob[0] = s->prob[1]; - memcpy(&s->framep[0], &s->next_framep[0], sizeof(s->framep[0]) * 4); - if (!s->invisible) { *(AVFrame*)data = *curframe; *data_size = sizeof(AVFrame); } return avpkt->size; +err: + memcpy(&s->next_framep[0], &s->framep[0], sizeof(s->framep[0]) * 4); + return ret; } static av_cold int vp8_decode_init(AVCodecContext *avctx) @@ -1768,8 +1799,8 @@ static av_cold int vp8_decode_init(AVCodecContext *avctx) s->avctx = avctx; avctx->pix_fmt = PIX_FMT_YUV420P; - dsputil_init(&s->dsp, avctx); - ff_h264_pred_init(&s->hpc, CODEC_ID_VP8, 8); + ff_dsputil_init(&s->dsp, avctx); + ff_h264_pred_init(&s->hpc, CODEC_ID_VP8, 8, 1); ff_vp8dsp_init(&s->vp8dsp); return 0; @@ -1777,7 +1808,7 @@ static av_cold int vp8_decode_init(AVCodecContext *avctx) static av_cold int vp8_decode_free(AVCodecContext *avctx) { - vp8_decode_flush_impl(avctx, 0, 1); + vp8_decode_flush_impl(avctx, 0, 1, 1); release_queued_segmaps(avctx->priv_data, 1); return 0; } @@ -1801,6 +1832,9 @@ static int vp8_decode_update_thread_context(AVCodecContext *dst, const AVCodecCo if (s->macroblocks_base && (s_src->mb_width != s->mb_width || s_src->mb_height != s->mb_height)) { free_buffers(s); + s->maps_are_invalid = 1; + s->mb_width = s_src->mb_width; + s->mb_height = s_src->mb_height; } s->prob[0] = s_src->prob[!s_src->update_probabilities]; @@ -1818,16 +1852,16 @@ static int vp8_decode_update_thread_context(AVCodecContext *dst, const AVCodecCo } AVCodec ff_vp8_decoder = { - .name = "vp8", - .type = AVMEDIA_TYPE_VIDEO, - .id = CODEC_ID_VP8, - .priv_data_size = sizeof(VP8Context), - .init = vp8_decode_init, - .close = vp8_decode_free, - .decode = vp8_decode_frame, - .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS, - .flush = vp8_decode_flush, - .long_name = NULL_IF_CONFIG_SMALL("On2 VP8"), + .name = "vp8", + .type = AVMEDIA_TYPE_VIDEO, + .id = CODEC_ID_VP8, + .priv_data_size = sizeof(VP8Context), + .init = vp8_decode_init, + .close = vp8_decode_free, + .decode = vp8_decode_frame, + .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS, + .flush = vp8_decode_flush, + .long_name = NULL_IF_CONFIG_SMALL("On2 VP8"), .init_thread_copy = ONLY_IF_THREADS_ENABLED(vp8_decode_init_thread_copy), .update_thread_context = ONLY_IF_THREADS_ENABLED(vp8_decode_update_thread_context), };