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

Reply via email to