From 759001c534287a96dc96d1e274665feb7059145d Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 21 Nov 2012 21:34:46 +0100 Subject: lavc decoders: work with refcounted frames. --- libavcodec/vp3.c | 172 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 103 insertions(+), 69 deletions(-) (limited to 'libavcodec/vp3.c') diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index f46ac32a9a..3d55c784aa 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -131,9 +131,9 @@ typedef struct Vp3DecodeContext { int version; int width, height; int chroma_x_shift, chroma_y_shift; - AVFrame golden_frame; - AVFrame last_frame; - AVFrame current_frame; + ThreadFrame golden_frame; + ThreadFrame last_frame; + ThreadFrame current_frame; int keyframe; DSPContext dsp; VideoDSPContext vdsp; @@ -261,19 +261,11 @@ static void vp3_decode_flush(AVCodecContext *avctx) { Vp3DecodeContext *s = avctx->priv_data; - if (s->golden_frame.data[0]) { - if (s->golden_frame.data[0] == s->last_frame.data[0]) - memset(&s->last_frame, 0, sizeof(AVFrame)); - if (s->current_frame.data[0] == s->golden_frame.data[0]) - memset(&s->current_frame, 0, sizeof(AVFrame)); + if (s->golden_frame.f) ff_thread_release_buffer(avctx, &s->golden_frame); - } - if (s->last_frame.data[0]) { - if (s->current_frame.data[0] == s->last_frame.data[0]) - memset(&s->current_frame, 0, sizeof(AVFrame)); + if (s->last_frame.f) ff_thread_release_buffer(avctx, &s->last_frame); - } - if (s->current_frame.data[0]) + if (s->current_frame.f) ff_thread_release_buffer(avctx, &s->current_frame); } @@ -292,6 +284,12 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx) av_freep(&s->motion_val[1]); av_freep(&s->edge_emu_buffer); + /* release all frames */ + vp3_decode_flush(avctx); + av_frame_free(&s->current_frame.f); + av_frame_free(&s->last_frame.f); + av_frame_free(&s->golden_frame.f); + if (avctx->internal->is_copy) return 0; @@ -308,8 +306,6 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx) ff_free_vlc(&s->mode_code_vlc); ff_free_vlc(&s->motion_vector_vlc); - /* release all frames */ - vp3_decode_flush(avctx); return 0; } @@ -1290,8 +1286,8 @@ static void apply_loop_filter(Vp3DecodeContext *s, int plane, int ystart, int ye int width = s->fragment_width[!!plane]; int height = s->fragment_height[!!plane]; int fragment = s->fragment_start [plane] + ystart * width; - int stride = s->current_frame.linesize[plane]; - uint8_t *plane_data = s->current_frame.data [plane]; + int stride = s->current_frame.f->linesize[plane]; + uint8_t *plane_data = s->current_frame.f->data [plane]; if (!s->flipped_image) stride = -stride; plane_data += s->data_offset[plane] + 8*ystart*stride; @@ -1420,14 +1416,14 @@ static void vp3_draw_horiz_band(Vp3DecodeContext *s, int y) } cy = y >> s->chroma_y_shift; - offset[0] = s->current_frame.linesize[0]*y; - offset[1] = s->current_frame.linesize[1]*cy; - offset[2] = s->current_frame.linesize[2]*cy; + offset[0] = s->current_frame.f->linesize[0]*y; + offset[1] = s->current_frame.f->linesize[1]*cy; + offset[2] = s->current_frame.f->linesize[2]*cy; for (i = 3; i < AV_NUM_DATA_POINTERS; i++) offset[i] = 0; emms_c(); - s->avctx->draw_horiz_band(s->avctx, &s->current_frame, offset, y, 3, h); + s->avctx->draw_horiz_band(s->avctx, s->current_frame.f, offset, y, 3, h); } /** @@ -1436,7 +1432,7 @@ static void vp3_draw_horiz_band(Vp3DecodeContext *s, int y) */ static void await_reference_row(Vp3DecodeContext *s, Vp3Fragment *fragment, int motion_y, int y) { - AVFrame *ref_frame; + ThreadFrame *ref_frame; int ref_row; int border = motion_y&1; @@ -1469,10 +1465,10 @@ static void render_slice(Vp3DecodeContext *s, int slice) return; for (plane = 0; plane < 3; plane++) { - uint8_t *output_plane = s->current_frame.data [plane] + s->data_offset[plane]; - uint8_t * last_plane = s-> last_frame.data [plane] + s->data_offset[plane]; - uint8_t *golden_plane = s-> golden_frame.data [plane] + s->data_offset[plane]; - int stride = s->current_frame.linesize[plane]; + uint8_t *output_plane = s->current_frame.f->data [plane] + s->data_offset[plane]; + uint8_t * last_plane = s-> last_frame.f->data [plane] + s->data_offset[plane]; + uint8_t *golden_plane = s-> golden_frame.f->data [plane] + s->data_offset[plane]; + int stride = s->current_frame.f->linesize[plane]; int plane_width = s->width >> (plane && s->chroma_x_shift); int plane_height = s->height >> (plane && s->chroma_y_shift); int8_t (*motion_val)[2] = s->motion_val[!!plane]; @@ -1657,14 +1653,36 @@ static av_cold int allocate_tables(AVCodecContext *avctx) return 0; } +static av_cold int init_frames(Vp3DecodeContext *s) +{ + s->current_frame.f = av_frame_alloc(); + s->last_frame.f = av_frame_alloc(); + s->golden_frame.f = av_frame_alloc(); + + if (!s->current_frame.f || !s->last_frame.f || !s->golden_frame.f) { + av_frame_free(&s->current_frame.f); + av_frame_free(&s->last_frame.f); + av_frame_free(&s->golden_frame.f); + return AVERROR(ENOMEM); + } + + return 0; +} + static av_cold int vp3_decode_init(AVCodecContext *avctx) { Vp3DecodeContext *s = avctx->priv_data; - int i, inter, plane; + int i, inter, plane, ret; int c_width; int c_height; int y_fragment_count, c_fragment_count; + ret = init_frames(s); + if (ret < 0) + return ret; + + avctx->internal->allocate_progress = 1; + if (avctx->codec_tag == MKTAG('V','P','3','0')) s->version = 0; else @@ -1821,12 +1839,6 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) &motion_vector_vlc_table[0][1], 2, 1, &motion_vector_vlc_table[0][0], 2, 1, 0); - for (i = 0; i < 3; i++) { - s->current_frame.data[i] = NULL; - s->last_frame.data[i] = NULL; - s->golden_frame.data[i] = NULL; - } - return allocate_tables(avctx); vlc_fail: @@ -1835,26 +1847,44 @@ vlc_fail: } /// Release and shuffle frames after decode finishes -static void update_frames(AVCodecContext *avctx) +static int update_frames(AVCodecContext *avctx) { Vp3DecodeContext *s = avctx->priv_data; + int ret = 0; - /* release the last frame, if it is allocated and if it is not the - * golden frame */ - if (s->last_frame.data[0] && s->last_frame.type != FF_BUFFER_TYPE_COPY) - ff_thread_release_buffer(avctx, &s->last_frame); /* shuffle frames (last = current) */ - s->last_frame= s->current_frame; + ff_thread_release_buffer(avctx, &s->last_frame); + ret = ff_thread_ref_frame(&s->last_frame, &s->current_frame); + if (ret < 0) + goto fail; if (s->keyframe) { - if (s->golden_frame.data[0]) - ff_thread_release_buffer(avctx, &s->golden_frame); - s->golden_frame = s->current_frame; - s->last_frame.type = FF_BUFFER_TYPE_COPY; + ff_thread_release_buffer(avctx, &s->golden_frame); + ret = ff_thread_ref_frame(&s->golden_frame, &s->current_frame); } - s->current_frame.data[0]= NULL; /* ensure that we catch any access to this released frame */ +fail: + ff_thread_release_buffer(avctx, &s->current_frame); + return ret; +} + +static int ref_frame(Vp3DecodeContext *s, ThreadFrame *dst, ThreadFrame *src) +{ + ff_thread_release_buffer(s->avctx, dst); + if (src->f->data[0]) + return ff_thread_ref_frame(dst, src); + return 0; +} + +static int ref_frames(Vp3DecodeContext *dst, Vp3DecodeContext *src) +{ + int ret; + if ((ret = ref_frame(dst, &dst->current_frame, &src->current_frame)) < 0 || + (ret = ref_frame(dst, &dst->golden_frame, &src->golden_frame)) < 0 || + (ret = ref_frame(dst, &dst->last_frame, &src->last_frame)) < 0) + return ret; + return 0; } static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) @@ -1864,17 +1894,17 @@ static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext * #define copy_fields(to, from, start_field, end_field) memcpy(&to->start_field, &from->start_field, (char*)&to->end_field - (char*)&to->start_field) - if (!s1->current_frame.data[0] + if (!s1->current_frame.f->data[0] ||s->width != s1->width ||s->height!= s1->height) { if (s != s1) - copy_fields(s, s1, golden_frame, current_frame); + ref_frames(s, s1); return -1; } if (s != s1) { // init tables if the first frame hasn't been decoded - if (!s->current_frame.data[0]) { + if (!s->current_frame.f->data[0]) { int y_fragment_count, c_fragment_count; s->avctx = dst; err = allocate_tables(dst); @@ -1887,7 +1917,10 @@ static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext * } // copy previous frame data - copy_fields(s, s1, golden_frame, dsp); + if ((err = ref_frames(s, s1)) < 0) + return err; + + s->keyframe = s1->keyframe; // copy qscale data if necessary for (i = 0; i < 3; i++) { @@ -1905,9 +1938,7 @@ static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext * #undef copy_fields } - update_frames(dst); - - return 0; + return update_frames(dst); } static int vp3_decode_frame(AVCodecContext *avctx, @@ -1918,7 +1949,7 @@ static int vp3_decode_frame(AVCodecContext *avctx, int buf_size = avpkt->size; Vp3DecodeContext *s = avctx->priv_data; GetBitContext gb; - int i; + int i, ret; init_get_bits(&gb, buf, buf_size * 8); @@ -1960,15 +1991,14 @@ static int vp3_decode_frame(AVCodecContext *avctx, if (avctx->skip_frame >= AVDISCARD_NONKEY && !s->keyframe) return buf_size; - s->current_frame.reference = 3; - s->current_frame.pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; - if (ff_thread_get_buffer(avctx, &s->current_frame) < 0) { + s->current_frame.f->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + if (ff_thread_get_buffer(avctx, &s->current_frame, AV_GET_BUFFER_FLAG_REF) < 0) { av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n"); goto error; } if (!s->edge_emu_buffer) - s->edge_emu_buffer = av_malloc(9*FFABS(s->current_frame.linesize[0])); + s->edge_emu_buffer = av_malloc(9*FFABS(s->current_frame.f->linesize[0])); if (s->keyframe) { if (!s->theora) @@ -1989,17 +2019,17 @@ static int vp3_decode_frame(AVCodecContext *avctx, skip_bits(&gb, 2); /* reserved? */ } } else { - if (!s->golden_frame.data[0]) { + if (!s->golden_frame.f->data[0]) { av_log(s->avctx, AV_LOG_WARNING, "vp3: first frame not a keyframe\n"); - s->golden_frame.reference = 3; - s->golden_frame.pict_type = AV_PICTURE_TYPE_I; - if (ff_thread_get_buffer(avctx, &s->golden_frame) < 0) { + s->golden_frame.f->pict_type = AV_PICTURE_TYPE_I; + if (ff_thread_get_buffer(avctx, &s->golden_frame, AV_GET_BUFFER_FLAG_REF) < 0) { av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n"); goto error; } - s->last_frame = s->golden_frame; - s->last_frame.type = FF_BUFFER_TYPE_COPY; + ff_thread_release_buffer(avctx, &s->last_frame); + if ((ret = ff_thread_ref_frame(&s->last_frame, &s->golden_frame)) < 0) + goto error; ff_thread_report_progress(&s->last_frame, INT_MAX, 0); } } @@ -2033,7 +2063,7 @@ static int vp3_decode_frame(AVCodecContext *avctx, if (s->flipped_image) s->data_offset[i] = 0; else - s->data_offset[i] = (height-1) * s->current_frame.linesize[i]; + s->data_offset[i] = (height-1) * s->current_frame.f->linesize[i]; } s->last_slice_end = 0; @@ -2047,11 +2077,15 @@ static int vp3_decode_frame(AVCodecContext *avctx, } vp3_draw_horiz_band(s, s->avctx->height); + if ((ret = av_frame_ref(data, s->current_frame.f)) < 0) + return ret; *got_frame = 1; - *(AVFrame*)data= s->current_frame; - if (!HAVE_THREADS || !(s->avctx->active_thread_type&FF_THREAD_FRAME)) - update_frames(avctx); + if (!HAVE_THREADS || !(s->avctx->active_thread_type&FF_THREAD_FRAME)) { + ret = update_frames(avctx); + if (ret < 0) + return ret; + } return buf_size; @@ -2059,7 +2093,7 @@ error: ff_thread_report_progress(&s->current_frame, INT_MAX, 0); if (!HAVE_THREADS || !(s->avctx->active_thread_type&FF_THREAD_FRAME)) - avctx->release_buffer(avctx, &s->current_frame); + av_frame_unref(s->current_frame.f); return -1; } @@ -2113,7 +2147,7 @@ static int vp3_init_thread_copy(AVCodecContext *avctx) s->motion_val[1] = NULL; s->edge_emu_buffer = NULL; - return 0; + return init_frames(s); } #if CONFIG_THEORA_DECODER -- cgit v1.2.3