On 2013-02-13 19:51:19 +0100, Anton Khirnov wrote:
> ---
> libavcodec/h264.c | 310
> +++++++++++++++++++++++++++++-----------------
> libavcodec/h264.h | 5 +
> libavcodec/h264_direct.c | 2 +-
> libavcodec/h264_refs.c | 32 +++--
> 4 files changed, 225 insertions(+), 124 deletions(-)
>
> diff --git a/libavcodec/h264.c b/libavcodec/h264.c
> index 339aecd..6f9263a 100644
> --- a/libavcodec/h264.c
> +++ b/libavcodec/h264.c
> @@ -112,28 +112,25 @@ void ff_h264_draw_horiz_band(H264Context *h, int y, int
> height)
> h->low_delay, h->mb_height * 16, h->mb_width * 16);
> }
>
> -static void free_frame_buffer(H264Context *h, Picture *pic)
> -{
> - ff_thread_release_buffer(h->avctx, &pic->f);
> - av_freep(&pic->f.hwaccel_picture_private);
> -}
> -
> -static void free_picture(H264Context *h, Picture *pic)
> +static void unref_picture(H264Context *h, Picture *pic)
> {
> + int off = offsetof(Picture, tf) + sizeof(pic->tf);
that's nicer than the offsetof use in mpegvideo
> int i;
>
> - if (pic->f.data[0])
> - free_frame_buffer(h, pic);
> + if (!pic->f.data[0])
> + return;
> +
> + ff_thread_release_buffer(h->avctx, &pic->tf);
> + av_buffer_unref(&pic->hwaccel_priv_buf);
>
> - av_freep(&pic->qscale_table_base);
> - pic->qscale_table = NULL;
> - av_freep(&pic->mb_type_base);
> - pic->mb_type = NULL;
> + av_buffer_unref(&pic->qscale_table_buf);
> + av_buffer_unref(&pic->mb_type_buf);
> for (i = 0; i < 2; i++) {
> - av_freep(&pic->motion_val_base[i]);
> - av_freep(&pic->ref_index[i]);
> - pic->motion_val[i] = NULL;
> + av_buffer_unref(&pic->motion_val_buf[i]);
> + av_buffer_unref(&pic->ref_index_buf[i]);
> }
> +
> + memset((uint8_t*)pic + off, 0, sizeof(*pic) - off);
> }
>
> static void release_unused_pictures(H264Context *h, int remove_current)
> @@ -143,13 +140,72 @@ static void release_unused_pictures(H264Context *h, int
> remove_current)
> /* release non reference frames */
> for (i = 0; i < h->picture_count; i++) {
> if (h->DPB[i].f.data[0] && !h->DPB[i].reference &&
> - (!h->DPB[i].owner2 || h->DPB[i].owner2 == h) &&
> (remove_current || &h->DPB[i] != h->cur_pic_ptr)) {
> - free_frame_buffer(h, &h->DPB[i]);
> + unref_picture(h, &h->DPB[i]);
> }
> }
> }
>
> +static int ref_picture(H264Context *h, Picture *dst, Picture *src)
> +{
> + int ret, i;
> +
> + av_assert0(!dst->f.buf[0]);
> + av_assert0(src->f.buf[0]);
> +
> + src->tf.f = &src->f;
modifying the source picture here looks strange but I guess ok if it's
too hard to guarantee src->tf.f == &src->f
> + dst->tf.f = &dst->f;
> + ret = ff_thread_ref_frame(&dst->tf, &src->tf);
> + if (ret < 0)
> + goto fail;
> +
> +
> + dst->qscale_table_buf = av_buffer_ref(src->qscale_table_buf);
> + dst->mb_type_buf = av_buffer_ref(src->mb_type_buf);
> + if (!dst->qscale_table_buf || !dst->mb_type_buf)
> + goto fail;
> + dst->qscale_table = src->qscale_table;
> + dst->mb_type = src->mb_type;
> +
> + for (i = 0; i < 2; i ++) {
> + dst->motion_val_buf[i] = av_buffer_ref(src->motion_val_buf[i]);
> + dst->ref_index_buf[i] = av_buffer_ref(src->ref_index_buf[i]);
> + if (!dst->motion_val_buf[i] || !dst->ref_index_buf[i])
> + goto fail;
> + dst->motion_val[i] = src->motion_val[i];
> + dst->ref_index[i] = src->ref_index[i];
> + }
> +
> + if (src->hwaccel_picture_private) {
> + dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf);
> + if (!dst->hwaccel_priv_buf)
> + goto fail;
> + dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data;
> + }
> +
> + for (i = 0; i < 2; i++)
> + dst->field_poc[i] = src->field_poc[i];
> +
> + memcpy(dst->ref_poc, src->ref_poc, sizeof(src->ref_poc));
> + memcpy(dst->ref_count, src->ref_count, sizeof(src->ref_count));
> +
> + dst->poc = src->poc;
> + dst->frame_num = src->frame_num;
> + dst->mmco_reset = src->mmco_reset;
> + dst->pic_id = src->pic_id;
> + dst->long_ref = src->long_ref;
> + dst->mbaff = src->mbaff;
> + dst->field_picture = src->field_picture;
> + dst->needs_realloc = src->needs_realloc;
We should be able to get rid of needs_realloc with refcounted frames but
that can be done afterwards
> + dst->reference = src->reference;
> +
> + return 0;
> +fail:
> + unref_picture(h, dst);
> + return ret;
> +}
> +
> +
> static int alloc_scratch_buffers(H264Context *h, int linesize)
> {
> int alloc_size = FFALIGN(FFABS(linesize) + 32, 32);
> @@ -171,60 +227,86 @@ static int alloc_scratch_buffers(H264Context *h, int
> linesize)
> return 0;
> }
>
> -static int alloc_picture(H264Context *h, Picture *pic)
> +static int init_table_pools(H264Context *h)
> {
> const int big_mb_num = h->mb_stride * (h->mb_height + 1) + 1;
> const int mb_array_size = h->mb_stride * h->mb_height;
> const int b4_stride = h->mb_width * 4 + 1;
> const int b4_array_size = b4_stride * h->mb_height * 4;
> +
> + h->qscale_table_pool = av_buffer_pool_init(big_mb_num + h->mb_stride,
> + av_buffer_allocz);
> + h->mb_type_pool = av_buffer_pool_init((big_mb_num + h->mb_stride) *
> + sizeof(uint32_t),
> av_buffer_allocz);
> + h->motion_val_pool = av_buffer_pool_init(2 * (b4_array_size + 4) *
> + sizeof(int16_t),
> av_buffer_allocz);
> + h->ref_index_pool = av_buffer_pool_init(4 * mb_array_size,
> av_buffer_allocz);
> +
> + if (!h->qscale_table_pool || !h->mb_type_pool || !h->motion_val_pool ||
> + !h->ref_index_pool) {
> + av_buffer_pool_uninit(&h->qscale_table_pool);
> + av_buffer_pool_uninit(&h->mb_type_pool);
> + av_buffer_pool_uninit(&h->motion_val_pool);
> + av_buffer_pool_uninit(&h->ref_index_pool);
> + return AVERROR(ENOMEM);
> + }
> +
> + return 0;
> +}
> +
> +static int alloc_picture(H264Context *h, Picture *pic)
> +{
> int i, ret = 0;
>
> av_assert0(!pic->f.data[0]);
>
> if (h->avctx->hwaccel) {
> const AVHWAccel *hwaccel = h->avctx->hwaccel;
> - av_assert0(!pic->f.hwaccel_picture_private);
> + av_assert0(!pic->hwaccel_picture_private);
> if (hwaccel->priv_data_size) {
> - pic->f.hwaccel_picture_private =
> av_mallocz(hwaccel->priv_data_size);
> - if (!pic->f.hwaccel_picture_private)
> + pic->hwaccel_priv_buf =
> av_buffer_allocz(hwaccel->priv_data_size);
> + if (!pic->hwaccel_priv_buf)
> return AVERROR(ENOMEM);
> + pic->hwaccel_picture_private = pic->hwaccel_priv_buf->data;
> }
> }
> - ret = ff_thread_get_buffer(h->avctx, &pic->f);
> + pic->tf.f = &pic->f;
> + ret = ff_thread_get_buffer(h->avctx, &pic->tf, pic->reference ?
> + AV_GET_BUFFER_FLAG_REF :
> 0);
> if (ret < 0)
> goto fail;
>
> h->linesize = pic->f.linesize[0];
> h->uvlinesize = pic->f.linesize[1];
>
> - if (pic->qscale_table == NULL) {
> - FF_ALLOCZ_OR_GOTO(h->avctx, pic->qscale_table_base,
> - (big_mb_num + h->mb_stride) * sizeof(uint8_t),
> - fail)
> - FF_ALLOCZ_OR_GOTO(h->avctx, pic->mb_type_base,
> - (big_mb_num + h->mb_stride) * sizeof(uint32_t),
> - fail)
> - pic->mb_type = pic->mb_type_base + 2 * h->mb_stride + 1;
> - pic->qscale_table = pic->qscale_table_base + 2 * h->mb_stride + 1;
> + if (!h->qscale_table_pool) {
> + ret = init_table_pools(h);
> + if (ret < 0)
> + goto fail;
> + }
>
> - for (i = 0; i < 2; i++) {
> - FF_ALLOCZ_OR_GOTO(h->avctx, pic->motion_val_base[i],
> - 2 * (b4_array_size + 4) * sizeof(int16_t),
> - fail)
> - pic->motion_val[i] = pic->motion_val_base[i] + 4;
> - FF_ALLOCZ_OR_GOTO(h->avctx, pic->ref_index[i],
> - 4 * mb_array_size * sizeof(uint8_t), fail)
> - }
> - pic->f.motion_subsample_log2 = 2;
> + pic->qscale_table_buf = av_buffer_alloc_pool(h->qscale_table_pool);
> + pic->mb_type_buf = av_buffer_alloc_pool(h->mb_type_pool);
> + if (!pic->qscale_table_buf || !pic->mb_type_buf)
> + goto fail;
>
> - pic->f.qstride = h->mb_stride;
> - }
> + pic->mb_type = (uint32_t*)pic->mb_type_buf->data + 2 * h->mb_stride
> + 1;
> + pic->qscale_table = pic->qscale_table_buf->data + 2 * h->mb_stride + 1;
>
> - pic->owner2 = h;
> + for (i = 0; i < 2; i++) {
> + pic->motion_val_buf[i] = av_buffer_alloc_pool(h->motion_val_pool);
> + pic->ref_index_buf[i] = av_buffer_alloc_pool(h->ref_index_pool);
> + if (!pic->motion_val_buf[i] || !pic->ref_index_buf[i])
> + goto fail;
> +
> + pic->motion_val[i] = (int16_t (*)[2])pic->motion_val_buf[i]->data +
> 4;
> + pic->ref_index[i] = pic->ref_index_buf[i]->data;
> + }
> + pic->f.motion_subsample_log2 = 2;
>
> return 0;
> fail:
> - free_frame_buffer(h, pic);
> + unref_picture(h, pic);
> return (ret < 0) ? ret : AVERROR(ENOMEM);
> }
>
> @@ -233,8 +315,7 @@ static inline int pic_is_unused(H264Context *h, Picture
> *pic)
> if (pic->f.data[0] == NULL)
> return 1;
> if (pic->needs_realloc && !(pic->reference & DELAYED_PIC_REF))
> - if (!pic->owner2 || pic->owner2 == h)
> - return 1;
> + return 1;
> return 0;
> }
>
> @@ -242,17 +323,14 @@ static int find_unused_picture(H264Context *h)
> {
> int i;
>
> - for (i = h->picture_range_start; i < h->picture_range_end; i++) {
> + for (i = 0; i < h->picture_count; i++) {
> if (pic_is_unused(h, &h->DPB[i]))
> break;
> }
> - if (i == h->picture_range_end)
> - return AVERROR_INVALIDDATA;
Are you sure it's impossible that the loop doesn't break?
> if (h->DPB[i].needs_realloc) {
> h->DPB[i].needs_realloc = 0;
> - free_picture(h, &h->DPB[i]);
> - avcodec_get_frame_defaults(&h->DPB[i].f);
> + unref_picture(h, &h->DPB[i]);
> }
>
> return i;
> @@ -503,7 +581,7 @@ static inline void get_lowest_part_y(H264Context *h, int
> refs[2][48], int n,
> // Error resilience puts the current picture in the ref list.
> // Don't try to wait on these as it will cause a deadlock.
> // Fields can wait on each other, though.
> - if (ref->f.thread_opaque != h->cur_pic.f.thread_opaque ||
> + if (ref->tf.progress->data != h->cur_pic.tf.progress->data ||
it gets even uglier, I'll look if there's a proper fix for this
> (ref->reference & 3) != h->picture_structure) {
> my = get_lowest_part_list_y(h, ref, n, height, y_offset, 0);
> if (refs[0][ref_n] < 0)
> @@ -516,7 +594,7 @@ static inline void get_lowest_part_y(H264Context *h, int
> refs[2][48], int n,
> int ref_n = h->ref_cache[1][scan8[n]];
> Picture *ref = &h->ref_list[1][ref_n];
>
> - if (ref->f.thread_opaque != h->cur_pic.f.thread_opaque ||
> + if (ref->tf.progress->data != h->cur_pic.tf.progress->data ||
> (ref->reference & 3) != h->picture_structure) {
> my = get_lowest_part_list_y(h, ref, n, height, y_offset, 1);
> if (refs[1][ref_n] < 0)
> @@ -614,24 +692,24 @@ static void await_references(H264Context *h)
> nrefs[list]--;
>
> if (!FIELD_PICTURE && ref_field_picture) { // frame
> referencing two fields
> - ff_thread_await_progress(&ref_pic->f,
> + ff_thread_await_progress(&ref_pic->tf,
> FFMIN((row >> 1) - !(row & 1),
> pic_height - 1),
> 1);
> - ff_thread_await_progress(&ref_pic->f,
> + ff_thread_await_progress(&ref_pic->tf,
> FFMIN((row >> 1), pic_height -
> 1),
> 0);
> } else if (FIELD_PICTURE && !ref_field_picture) { // field
> referencing one field of a frame
> - ff_thread_await_progress(&ref_pic->f,
> + ff_thread_await_progress(&ref_pic->tf,
> FFMIN(row * 2 + ref_field,
> pic_height - 1),
> 0);
> } else if (FIELD_PICTURE) {
> - ff_thread_await_progress(&ref_pic->f,
> + ff_thread_await_progress(&ref_pic->tf,
> FFMIN(row, pic_height - 1),
> ref_field);
> } else {
> - ff_thread_await_progress(&ref_pic->f,
> + ff_thread_await_progress(&ref_pic->tf,
> FFMIN(row, pic_height - 1),
> 0);
> }
> @@ -951,9 +1029,14 @@ static void free_tables(H264Context *h, int free_rbsp)
> av_freep(&h->mb2b_xy);
> av_freep(&h->mb2br_xy);
>
> + av_buffer_pool_uninit(&h->qscale_table_pool);
> + av_buffer_pool_uninit(&h->mb_type_pool);
> + av_buffer_pool_uninit(&h->motion_val_pool);
> + av_buffer_pool_uninit(&h->ref_index_pool);
> +
> if (free_rbsp) {
> - for (i = 0; i < h->picture_count && !h->avctx->internal->is_copy;
> i++)
> - free_picture(h, &h->DPB[i]);
> + for (i = 0; i < h->picture_count; i++)
> + unref_picture(h, &h->DPB[i]);
> av_freep(&h->DPB);
> h->picture_count = 0;
> } else if (h->DPB) {
> @@ -1106,7 +1189,7 @@ int ff_h264_alloc_tables(H264Context *h)
> init_dequant_tables(h);
>
> if (!h->DPB) {
> - h->picture_count = MAX_PICTURE_COUNT * FFMAX(1,
> h->avctx->thread_count);
> + h->picture_count = MAX_PICTURE_COUNT;
we can get rid picture_count if it's a constant
> h->DPB = av_mallocz_array(h->picture_count, sizeof(*h->DPB));
> if (!h->DPB)
> return AVERROR(ENOMEM);
> @@ -1306,8 +1389,6 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
> common_init(h);
>
> h->picture_structure = PICT_FRAME;
> - h->picture_range_start = 0;
> - h->picture_range_end = MAX_PICTURE_COUNT;
> h->slice_context_count = 1;
> h->workaround_bugs = avctx->workaround_bugs;
> h->flags = avctx->flags;
> @@ -1347,6 +1428,8 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
> h->low_delay = 0;
> }
>
> + avctx->internal->allocate_progress = 1;
> +
> return 0;
> }
>
> @@ -1398,6 +1481,8 @@ static int decode_init_thread_copy(AVCodecContext
> *avctx)
>
> h->context_initialized = 0;
>
> + avctx->internal->allocate_progress = 1;
> +
unnecessary
> return 0;
> }
>
> @@ -1414,7 +1499,7 @@ static int decode_update_thread_context(AVCodecContext
> *dst,
> {
> H264Context *h = dst->priv_data, *h1 = src->priv_data;
> int inited = h->context_initialized, err = 0;
> - int i;
> + int i, ret;
>
> if (dst == src || !h1->context_initialized)
> return 0;
> @@ -1468,12 +1553,16 @@ static int
> decode_update_thread_context(AVCodecContext *dst,
> memset(&h->me, 0, sizeof(h->me));
> h->context_initialized = 0;
>
> - h->picture_range_start += MAX_PICTURE_COUNT;
> - h->picture_range_end += MAX_PICTURE_COUNT;
> + memset(&h->cur_pic, 0, sizeof(h->cur_pic));
> + avcodec_get_frame_defaults(&h->cur_pic.f);
> + h->cur_pic.tf.f = &h->cur_pic.f;
>
> h->avctx = dst;
> h->DPB = NULL;
> - h->cur_pic.f.extended_data = h->cur_pic.f.data;
> + h->qscale_table_pool = NULL;
> + h->mb_type_pool = NULL;
> + h->ref_index_pool = NULL;
> + h->motion_val_pool = NULL;
>
> if (ff_h264_alloc_tables(h) < 0) {
> av_log(dst, AV_LOG_ERROR, "Could not allocate memory for
> h264\n");
> @@ -1507,15 +1596,17 @@ static int
> decode_update_thread_context(AVCodecContext *dst,
> h->data_partitioning = h1->data_partitioning;
> h->low_delay = h1->low_delay;
>
> - memcpy(h->DPB, h1->DPB, h1->picture_count * sizeof(*h1->DPB));
> -
> - // reset s->picture[].f.extended_data to s->picture[].f.data
> - for (i = 0; i < h->picture_count; i++)
> - h->DPB[i].f.extended_data = h->DPB[i].f.data;
> + for (i = 0; i < h->picture_count; i++) {
> + unref_picture(h, &h->DPB[i]);
> + if (h1->DPB[i].f.data[0] &&
> + (ret = ref_picture(h, &h->DPB[i], &h1->DPB[i])) < 0)
> + return ret;
> + }
>
> h->cur_pic_ptr = REBASE_PICTURE(h1->cur_pic_ptr, h, h1);
> - h->cur_pic = h1->cur_pic;
> - h->cur_pic.f.extended_data = h->cur_pic.f.data;
> + unref_picture(h, &h->cur_pic);
> + if ((ret = ref_picture(h, &h->cur_pic, &h1->cur_pic)) < 0)
> + return ret;
>
> h->workaround_bugs = h1->workaround_bugs;
> h->low_delay = h1->low_delay;
> @@ -1613,8 +1704,9 @@ int ff_h264_frame_start(H264Context *h)
> return ret;
>
> h->cur_pic_ptr = pic;
> - h->cur_pic = *h->cur_pic_ptr;
> - h->cur_pic.f.extended_data = h->cur_pic.f.data;
> + unref_picture(h, &h->cur_pic);
> + if ((ret = ref_picture(h, &h->cur_pic, h->cur_pic_ptr)) < 0)
> + return ret;
>
> ff_er_frame_start(&h->er);
>
> @@ -1681,7 +1773,6 @@ static void decode_postinit(H264Context *h, int
> setup_finished)
> int i, pics, out_of_order, out_idx;
> int invalid = 0, cnt = 0;
>
> - h->cur_pic_ptr->f.qscale_type = FF_QSCALE_TYPE_H264;
> h->cur_pic_ptr->f.pict_type = h->pict_type;
>
> if (h->next_output_pic)
> @@ -1854,7 +1945,6 @@ static void decode_postinit(H264Context *h, int
> setup_finished)
> out->reference &= ~DELAYED_PIC_REF;
> // for frame threading, the owner must be the second field's thread
> or
> // else the first thread can release the picture and reuse it
> unsafely
> - out->owner2 = h;
> for (i = out_idx; h->delayed_pic[i]; i++)
> h->delayed_pic[i] = h->delayed_pic[i + 1];
> }
> @@ -2477,11 +2567,10 @@ static void flush_dpb(AVCodecContext *avctx)
>
> flush_change(h);
>
> - for (i = 0; i < h->picture_count; i++) {
> - if (h->DPB[i].f.data[0])
> - free_frame_buffer(h, &h->DPB[i]);
> - }
> + for (i = 0; i < h->picture_count; i++)
> + unref_picture(h, &h->DPB[i]);
> h->cur_pic_ptr = NULL;
> + unref_picture(h, &h->cur_pic);
>
> h->mb_x = h->mb_y = 0;
>
> @@ -2614,7 +2703,7 @@ static int field_end(H264Context *h, int in_setup)
> h->mb_y = 0;
>
> if (!in_setup && !h->droppable)
> - ff_thread_report_progress(&h->cur_pic_ptr->f, INT_MAX,
> + ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,
> h->picture_structure == PICT_BOTTOM_FIELD);
>
> if (CONFIG_H264_VDPAU_DECODER &&
> @@ -2974,9 +3063,8 @@ static int decode_slice_header(H264Context *h,
> H264Context *h0)
>
> h0->current_slice = 0;
> if (!h0->first_field) {
> - if (h->cur_pic_ptr && !h->droppable &&
> - h->cur_pic_ptr->owner2 == h) {
> - ff_thread_report_progress(&h->cur_pic_ptr->f, INT_MAX,
> + if (h->cur_pic_ptr && !h->droppable) {
> + ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,
> h->picture_structure ==
> PICT_BOTTOM_FIELD);
> }
> h->cur_pic_ptr = NULL;
> @@ -3201,8 +3289,8 @@ static int decode_slice_header(H264Context *h,
> H264Context *h0)
> assert(h0->cur_pic_ptr->reference != DELAYED_PIC_REF);
>
> /* Mark old field/frame as completed */
> - if (!last_pic_droppable && h0->cur_pic_ptr->owner2 == h0) {
> - ff_thread_report_progress(&h0->cur_pic_ptr->f, INT_MAX,
> + if (!last_pic_droppable) {
> + ff_thread_report_progress(&h0->cur_pic_ptr->tf, INT_MAX,
> last_pic_structure ==
> PICT_BOTTOM_FIELD);
> }
>
> @@ -3211,7 +3299,7 @@ static int decode_slice_header(H264Context *h,
> H264Context *h0)
> /* Previous field is unmatched. Don't display it, but let it
> * remain for reference if marked as such. */
> if (!last_pic_droppable && last_pic_structure != PICT_FRAME)
> {
> - ff_thread_report_progress(&h0->cur_pic_ptr->f, INT_MAX,
> + ff_thread_report_progress(&h0->cur_pic_ptr->tf, INT_MAX,
> last_pic_structure ==
> PICT_TOP_FIELD);
> }
> } else {
> @@ -3221,7 +3309,7 @@ static int decode_slice_header(H264Context *h,
> H264Context *h0)
> * pair. Throw away previous field except for reference
> * purposes. */
> if (!last_pic_droppable && last_pic_structure !=
> PICT_FRAME) {
> - ff_thread_report_progress(&h0->cur_pic_ptr->f,
> INT_MAX,
> + ff_thread_report_progress(&h0->cur_pic_ptr->tf,
> INT_MAX,
> last_pic_structure ==
> PICT_TOP_FIELD);
> }
> } else {
> @@ -3244,14 +3332,6 @@ static int decode_slice_header(H264Context *h,
> H264Context *h0)
> h->droppable = last_pic_droppable;
> return AVERROR_PATCHWELCOME;
> }
> -
> - /* Take ownership of this buffer. Note that if another
> thread owned
> - * the first field of this buffer, we're not operating
> on that pointer,
> - * so the original thread is still responsible for
> reporting progress
> - * on that first field (or if that was us, we just did
> that above).
> - * By taking ownership, we assign responsibility to
> ourselves to
> - * report progress on the second field. */
> - h0->cur_pic_ptr->owner2 = h0;
> }
> }
> }
> @@ -3266,8 +3346,8 @@ static int decode_slice_header(H264Context *h,
> H264Context *h0)
> h->prev_frame_num++;
> h->prev_frame_num %= 1 << h->sps.log2_max_frame_num;
> h->cur_pic_ptr->frame_num = h->prev_frame_num;
> - ff_thread_report_progress(&h->cur_pic_ptr->f, INT_MAX, 0);
> - ff_thread_report_progress(&h->cur_pic_ptr->f, INT_MAX, 1);
> + ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 0);
> + ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 1);
> if ((ret = ff_generate_sliding_window_mmcos(h, 1)) < 0 &&
> h->avctx->err_recognition & AV_EF_EXPLODE)
> return ret;
> @@ -3561,16 +3641,16 @@ static int decode_slice_header(H264Context *h,
> H264Context *h0)
> int *ref2frm = h->ref2frm[h->slice_num & (MAX_SLICES - 1)][j];
> for (i = 0; i < 16; i++) {
> id_list[i] = 60;
> - if (h->ref_list[j][i].f.data[0]) {
> + if (i < h->ref_count[j] && h->ref_list[j][i].f.buf[0]) {
> int k;
> - uint8_t *base = h->ref_list[j][i].f.base[0];
> + AVBuffer *buf = h->ref_list[j][i].f.buf[0]->buffer;
> for (k = 0; k < h->short_ref_count; k++)
> - if (h->short_ref[k]->f.base[0] == base) {
> + if (h->short_ref[k]->f.buf[0]->buffer == buf) {
av_buffer_are_equal() to make it less ugly? or should the h264 decoder
use something to keep track of pictures. something to fix later
> id_list[i] = k;
> break;
> }
> for (k = 0; k < h->long_ref_count; k++)
> - if (h->long_ref[k] && h->long_ref[k]->f.base[0] == base)
> {
> + if (h->long_ref[k] && h->long_ref[k]->f.buf[0]->buffer
> == buf) {
> id_list[i] = h->short_ref_count + k;
> break;
> }
> @@ -3976,7 +4056,7 @@ static void decode_finish_row(H264Context *h)
> if (h->droppable)
> return;
>
> - ff_thread_report_progress(&h->cur_pic_ptr->f, top + height - 1,
> + ff_thread_report_progress(&h->cur_pic_ptr->tf, top + height - 1,
> h->picture_structure == PICT_BOTTOM_FIELD);
> }
>
> @@ -4475,9 +4555,8 @@ again:
>
> end:
> /* clean up */
> - if (h->cur_pic_ptr && h->cur_pic_ptr->owner2 == h &&
> - !h->droppable) {
> - ff_thread_report_progress(&h->cur_pic_ptr->f, INT_MAX,
> + if (h->cur_pic_ptr && !h->droppable) {
> + ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,
> h->picture_structure == PICT_BOTTOM_FIELD);
> }
>
> @@ -4505,6 +4584,7 @@ static int decode_frame(AVCodecContext *avctx, void
> *data,
> H264Context *h = avctx->priv_data;
> AVFrame *pict = data;
> int buf_index = 0;
> + int ret;
>
> h->flags = avctx->flags;
>
> @@ -4533,8 +4613,9 @@ out:
> h->delayed_pic[i] = h->delayed_pic[i + 1];
>
> if (out) {
> + if ((ret = av_frame_ref(pict, &out->f)) < 0)
> + return ret;
> *got_frame = 1;
> - *pict = out->f;
> }
>
> return buf_index;
> @@ -4568,8 +4649,9 @@ out:
> /* Wait for second field. */
> *got_frame = 0;
> } else {
> + if ((ret = av_frame_ref(pict, &h->next_output_pic->f)) < 0)
> + return ret;
> *got_frame = 1;
> - *pict = h->next_output_pic->f;
> }
> }
>
> @@ -4598,13 +4680,15 @@ static av_cold int h264_decode_end(AVCodecContext
> *avctx)
>
> ff_h264_free_context(h);
>
> - if (h->DPB && !h->avctx->internal->is_copy) {
> + if (h->DPB) {
> for (i = 0; i < h->picture_count; i++) {
> - free_picture(h, &h->DPB[i]);
> + unref_picture(h, &h->DPB[i]);
> }
> }
> av_freep(&h->DPB);
>
> + unref_picture(h, &h->cur_pic);
> +
> return 0;
> }
>
> diff --git a/libavcodec/h264.h b/libavcodec/h264.h
> index 0a8d259..0f7c1f1 100644
> --- a/libavcodec/h264.h
> +++ b/libavcodec/h264.h
> @@ -621,6 +621,11 @@ typedef struct H264Context {
> uint8_t *bipred_scratchpad;
> uint8_t *edge_emu_buffer;
> int16_t *dc_val_base;
> +
> + AVBufferPool *qscale_table_pool;
> + AVBufferPool *mb_type_pool;
> + AVBufferPool *motion_val_pool;
> + AVBufferPool *ref_index_pool;
> } H264Context;
>
> extern const uint8_t ff_h264_chroma_qp[3][QP_MAX_NUM + 1]; ///< One chroma
> qp table for each supported bit depth (8, 9, 10).
> diff --git a/libavcodec/h264_direct.c b/libavcodec/h264_direct.c
> index b22f321..6c2f175 100644
> --- a/libavcodec/h264_direct.c
> +++ b/libavcodec/h264_direct.c
> @@ -154,7 +154,7 @@ static void await_reference_mb_row(H264Context * const h,
> Picture *ref, int mb_y
> //FIXME it can be safe to access mb stuff
> //even if pixels aren't deblocked yet
>
> - ff_thread_await_progress(&ref->f,
> + ff_thread_await_progress(&ref->tf,
> FFMIN(16 * mb_y >> ref_field_picture,
> ref_height - 1),
> ref_field_picture && ref_field);
> }
> diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c
> index 95b4f83..a283a24 100644
> --- a/libavcodec/h264_refs.c
> +++ b/libavcodec/h264_refs.c
> @@ -34,6 +34,13 @@
> //#undef NDEBUG
> #include <assert.h>
>
> +#define COPY_PICTURE(dst, src) \
> +do {\
> + *(dst) = *(src);\
> + (dst)->f.extended_data = (dst)->f.data;\
> + (dst)->tf.f = &(dst)->f;\
> +} while (0)
> +
>
> static void pic_as_field(Picture *pic, const int parity){
> int i;
> @@ -51,7 +58,7 @@ static int split_field_copy(Picture *dest, Picture *src,
> int match = !!(src->reference & parity);
>
> if (match) {
> - *dest = *src;
> + COPY_PICTURE(dest, src);
> if(parity != PICT_FRAME){
> pic_as_field(dest, parity);
> dest->pic_id *= 2;
> @@ -133,8 +140,12 @@ int ff_h264_fill_default_ref_list(H264Context *h){
>
> if(lens[0] == lens[1] && lens[1] > 1){
> for (i = 0; h->default_ref_list[0][i].f.data[0] ==
> h->default_ref_list[1][i].f.data[0] && i < lens[0]; i++);
> - if(i == lens[0])
> - FFSWAP(Picture, h->default_ref_list[1][0],
> h->default_ref_list[1][1]);
> + if (i == lens[0]) {
> + Picture tmp;
> + COPY_PICTURE(&tmp, &h->default_ref_list[1][0]);
> + COPY_PICTURE(&h->default_ref_list[1][0],
> &h->default_ref_list[1][1]);
> + COPY_PICTURE(&h->default_ref_list[1][1], &tmp);
> + }
> }
> }else{
> len = build_def_list(h->default_ref_list[0] , h->short_ref,
> h->short_ref_count, 0, h->picture_structure);
> @@ -182,13 +193,14 @@ static int pic_num_extract(H264Context *h, int pic_num,
> int *structure){
> }
>
> int ff_h264_decode_ref_pic_list_reordering(H264Context *h){
> - int list, index, pic_structure;
> + int list, index, pic_structure, i;
>
> print_short_term(h);
> print_long_term(h);
>
> for(list=0; list<h->list_count; list++){
> - memcpy(h->ref_list[list], h->default_ref_list[list],
> sizeof(Picture)*h->ref_count[list]);
> + for (i = 0; i < h->ref_count[list]; i++)
> + COPY_PICTURE(&h->ref_list[list][i],
> &h->default_ref_list[list][i]);
>
> if(get_bits1(&h->gb)){
> int pred= h->curr_pic_num;
> @@ -265,9 +277,9 @@ int ff_h264_decode_ref_pic_list_reordering(H264Context
> *h){
> break;
> }
> for(; i > index; i--){
> - h->ref_list[list][i]= h->ref_list[list][i-1];
> + COPY_PICTURE(&h->ref_list[list][i],
> &h->ref_list[list][i - 1]);
> }
> - h->ref_list[list][index]= *ref;
> + COPY_PICTURE(&h->ref_list[list][index], ref);
> if (FIELD_PICTURE){
> pic_as_field(&h->ref_list[list][index],
> pic_structure);
> }
> @@ -284,7 +296,7 @@ int ff_h264_decode_ref_pic_list_reordering(H264Context
> *h){
> if (!h->ref_list[list][index].f.data[0]) {
> av_log(h->avctx, AV_LOG_ERROR, "Missing reference
> picture\n");
> if (h->default_ref_list[list][0].f.data[0])
> - h->ref_list[list][index]= h->default_ref_list[list][0];
> + COPY_PICTURE(&h->ref_list[list][index],
> &h->default_ref_list[list][0]);
> else
> return -1;
> }
> @@ -300,12 +312,12 @@ void ff_h264_fill_mbaff_ref_list(H264Context *h){
> for(i=0; i<h->ref_count[list]; i++){
> Picture *frame = &h->ref_list[list][i];
> Picture *field = &h->ref_list[list][16+2*i];
> - field[0] = *frame;
> + COPY_PICTURE(field, frame);
> for(j=0; j<3; j++)
> field[0].f.linesize[j] <<= 1;
> field[0].reference = PICT_TOP_FIELD;
> field[0].poc= field[0].field_poc[0];
> - field[1] = field[0];
> + COPY_PICTURE(field + 1, field);
> for(j=0; j<3; j++)
> field[1].f.data[j] += frame->f.linesize[j];
> field[1].reference = PICT_BOTTOM_FIELD;
looks ok otherwise
Janne
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel