Merge commit 'f450cc7bc595155bacdb9f5d2414a076ccf81b4a'
authorMatthieu Bouron <matthieu.bouron@gmail.com>
Mon, 16 Jan 2017 10:33:47 +0000 (11:33 +0100)
committerMatthieu Bouron <matthieu.bouron@gmail.com>
Tue, 17 Jan 2017 13:38:48 +0000 (14:38 +0100)
* commit 'f450cc7bc595155bacdb9f5d2414a076ccf81b4a':
  h264: eliminate decode_postinit()

Also includes fixes from 1f7b4f9abc and e344e65109.

Original patch replace H264Context.next_output_pic (H264Picture *) by
H264Context.output_frame (AVFrame *). This change is discarded as it
is incompatible with the frame reconstruction and motion vectors
display code which needs the extra information from the H264Picture.

Merged-by: Clément Bœsch <u@pkh.me>
Merged-by: Matthieu Bouron <matthieu.bouron@gmail.com>
1  2 
libavcodec/h264_slice.c
libavcodec/h264dec.c

@@@ -44,6 -44,6 +44,7 @@@
  #include "golomb.h"
  #include "mathops.h"
  #include "mpegutils.h"
++#include "mpegvideo.h"
  #include "rectangle.h"
  #include "thread.h"
  
@@@ -1283,6 -1140,140 +1284,105 @@@ static int h264_export_frame_props(H264
      return 0;
  }
  
 -    int invalid = 0, cnt = 0;
 -    int ret;
+ static int h264_select_output_frame(H264Context *h)
+ {
+     const SPS *sps = h->ps.sps;
+     H264Picture *out = h->cur_pic_ptr;
+     H264Picture *cur = h->cur_pic_ptr;
+     int i, pics, out_of_order, out_idx;
 -        h->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
++
++    cur->mmco_reset = h->mmco_reset;
++    h->mmco_reset = 0;
+     if (sps->bitstream_restriction_flag ||
 -    assert(pics <= MAX_DELAYED_PIC_COUNT);
++        h->avctx->strict_std_compliance >= FF_COMPLIANCE_STRICT) {
+         h->avctx->has_b_frames = FFMAX(h->avctx->has_b_frames, sps->num_reorder_frames);
+     }
++    for (i = 0; 1; i++) {
++        if(i == MAX_DELAYED_PIC_COUNT || cur->poc < h->last_pocs[i]){
++            if(i)
++                h->last_pocs[i-1] = cur->poc;
++            break;
++        } else if(i) {
++            h->last_pocs[i-1]= h->last_pocs[i];
++        }
++    }
++    out_of_order = MAX_DELAYED_PIC_COUNT - i;
++    if(   cur->f->pict_type == AV_PICTURE_TYPE_B
++       || (h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > INT_MIN && h->last_pocs[MAX_DELAYED_PIC_COUNT-1] - h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > 2))
++        out_of_order = FFMAX(out_of_order, 1);
++    if (out_of_order == MAX_DELAYED_PIC_COUNT) {
++        av_log(h->avctx, AV_LOG_VERBOSE, "Invalid POC %d<%d\n", cur->poc, h->last_pocs[0]);
++        for (i = 1; i < MAX_DELAYED_PIC_COUNT; i++)
++            h->last_pocs[i] = INT_MIN;
++        h->last_pocs[0] = cur->poc;
++        cur->mmco_reset = 1;
++    } else if(h->avctx->has_b_frames < out_of_order && !sps->bitstream_restriction_flag){
++        int loglevel = h->avctx->frame_number > 1 ? AV_LOG_WARNING : AV_LOG_VERBOSE;
++        av_log(h->avctx, loglevel, "Increasing reorder buffer to %d\n", out_of_order);
++        h->avctx->has_b_frames = out_of_order;
++    }
++
+     pics = 0;
+     while (h->delayed_pic[pics])
+         pics++;
 -    /* Frame reordering. This code takes pictures from coding order and sorts
 -     * them by their incremental POC value into display order. It supports POC
 -     * gaps, MMCO reset codes and random resets.
 -     * A "display group" can start either with a IDR frame (f.key_frame = 1),
 -     * and/or can be closed down with a MMCO reset code. In sequences where
 -     * there is no delay, we can't detect that (since the frame was already
 -     * output to the user), so we also set h->mmco_reset to detect the MMCO
 -     * reset code.
 -     * FIXME: if we detect insufficient delays (as per h->avctx->has_b_frames),
 -     * we increase the delay between input and output. All frames affected by
 -     * the lag (e.g. those that should have been output before another frame
 -     * that we already returned to the user) will be dropped. This is a bug
 -     * that we will fix later. */
 -    for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++) {
 -        cnt     += out->poc < h->last_pocs[i];
 -        invalid += out->poc == INT_MIN;
 -    }
 -    if (!h->mmco_reset && !cur->f->key_frame &&
 -        cnt + invalid == MAX_DELAYED_PIC_COUNT && cnt > 0) {
 -        h->mmco_reset = 2;
 -        if (pics > 1)
 -            h->delayed_pic[pics - 2]->mmco_reset = 2;
 -    }
 -    if (h->mmco_reset || cur->f->key_frame) {
 -        for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++)
 -            h->last_pocs[i] = INT_MIN;
 -        cnt     = 0;
 -        invalid = MAX_DELAYED_PIC_COUNT;
 -    }
++    av_assert0(pics <= MAX_DELAYED_PIC_COUNT);
+     h->delayed_pic[pics++] = cur;
+     if (cur->reference == 0)
+         cur->reference = DELAYED_PIC_REF;
 -    for (i = 1; i < MAX_DELAYED_PIC_COUNT &&
 -                h->delayed_pic[i] &&
 -                !h->delayed_pic[i - 1]->mmco_reset &&
 -                !h->delayed_pic[i]->f->key_frame;
+     out     = h->delayed_pic[0];
+     out_idx = 0;
 -        (h->delayed_pic[0]->f->key_frame || h->mmco_reset))
++    for (i = 1; h->delayed_pic[i] &&
++                !h->delayed_pic[i]->f->key_frame &&
++                !h->delayed_pic[i]->mmco_reset;
+          i++)
+         if (h->delayed_pic[i]->poc < out->poc) {
+             out     = h->delayed_pic[i];
+             out_idx = i;
+         }
+     if (h->avctx->has_b_frames == 0 &&
 -    out_of_order = !out->f->key_frame && !h->mmco_reset &&
 -                   (out->poc < h->next_outputed_poc);
++        (h->delayed_pic[0]->f->key_frame || h->delayed_pic[0]->mmco_reset))
+         h->next_outputed_poc = INT_MIN;
 -    if (sps->bitstream_restriction_flag &&
 -        h->avctx->has_b_frames >= sps->num_reorder_frames) {
 -    } else if (out_of_order && pics - 1 == h->avctx->has_b_frames &&
 -               h->avctx->has_b_frames < MAX_DELAYED_PIC_COUNT) {
 -        if (invalid + cnt < MAX_DELAYED_PIC_COUNT) {
 -            h->avctx->has_b_frames = FFMAX(h->avctx->has_b_frames, cnt);
 -        }
 -    } else if (!h->avctx->has_b_frames &&
 -               ((h->next_outputed_poc != INT_MIN &&
 -                 out->poc > h->next_outputed_poc + 2) ||
 -                cur->f->pict_type == AV_PICTURE_TYPE_B)) {
 -        h->avctx->has_b_frames++;
 -    }
 -
 -    if (pics > h->avctx->has_b_frames) {
++    out_of_order = out->poc < h->next_outputed_poc;
 -    memmove(h->last_pocs, &h->last_pocs[1],
 -            sizeof(*h->last_pocs) * (MAX_DELAYED_PIC_COUNT - 1));
 -    h->last_pocs[MAX_DELAYED_PIC_COUNT - 1] = cur->poc;
++    if (out_of_order || pics > h->avctx->has_b_frames) {
+         out->reference &= ~DELAYED_PIC_REF;
+         for (i = out_idx; h->delayed_pic[i]; i++)
+             h->delayed_pic[i] = h->delayed_pic[i + 1];
+     }
 -        av_frame_unref(h->output_frame);
 -        ret = av_frame_ref(h->output_frame, out->f);
 -        if (ret < 0)
 -            return ret;
+     if (!out_of_order && pics > h->avctx->has_b_frames) {
 -            if (!(h->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT))
 -                av_frame_unref(h->output_frame);
 -            else
 -                h->output_frame->flags |= AV_FRAME_FLAG_CORRUPT;
 -        }
 -
 -        if (out->mmco_reset) {
 -            if (out_idx > 0) {
 -                h->next_outputed_poc                    = out->poc;
 -                h->delayed_pic[out_idx - 1]->mmco_reset = out->mmco_reset;
 -            } else {
 -                h->next_outputed_poc = INT_MIN;
 -            }
 -        } else {
 -            if (out_idx == 0 && pics > 1 && h->delayed_pic[0]->f->key_frame) {
 -                h->next_outputed_poc = INT_MIN;
++        h->next_output_pic = out;
++        if (out_idx == 0 && h->delayed_pic[0] && (h->delayed_pic[0]->f->key_frame || h->delayed_pic[0]->mmco_reset)) {
++            h->next_outputed_poc = INT_MIN;
++        } else
++            h->next_outputed_poc = out->poc;
+         if (out->recovered) {
+             // We have reached an recovery point and all frames after it in
+             // display order are "recovered".
+             h->frame_recovered |= FRAME_RECOVERED_SEI;
+         }
+         out->recovered |= !!(h->frame_recovered & FRAME_RECOVERED_SEI);
+         if (!out->recovered) {
 -                h->next_outputed_poc = out->poc;
++            if (!(h->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) &&
++                !(h->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL)) {
++                h->next_output_pic = NULL;
+             } else {
 -        h->mmco_reset = 0;
++                out->f->flags |= AV_FRAME_FLAG_CORRUPT;
+             }
+         }
 -        av_log(h->avctx, AV_LOG_DEBUG, "no picture\n");
+     } else {
++        av_log(h->avctx, AV_LOG_DEBUG, "no picture %s\n", out_of_order ? "ooo" : "");
+     }
+     return 0;
+ }
  /* This function is called right after decoding the slice header for a first
   * slice in a field (or a frame). It decides whether we are decoding a new frame
   * or a second field in a pair and does the necessary setup.
@@@ -1537,12 -1487,22 +1637,16 @@@ static int h264_field_start(H264Contex
      /* Set the frame properties/side data. Only done for the second field in
       * field coded frames, since some SEI information is present for each field
       * and is merged by the SEI parsing code. */
--    if (!FIELD_PICTURE(h) || !h->first_field) {
++    if (!FIELD_PICTURE(h) || !h->first_field || h->missing_fields > 1) {
          ret = h264_export_frame_props(h);
          if (ret < 0)
              return ret;
+         ret = h264_select_output_frame(h);
+         if (ret < 0)
+             return ret;
      }
  
 -    if (h->avctx->hwaccel) {
 -        ret = h->avctx->hwaccel->start_frame(h->avctx, NULL, 0);
 -        if (ret < 0)
 -            return ret;
 -    }
 -
      return 0;
  }
  
@@@ -464,133 -424,8 +464,9 @@@ static int decode_init_thread_copy(AVCo
  
      return 0;
  }
 +#endif
  
  /**
-  * Run setup operations that must be run after slice header decoding.
-  * This includes finding the next displayed frame.
-  *
-  * @param h h264 master context
-  * @param setup_finished enough NALs have been read that we can call
-  * ff_thread_finish_setup()
-  */
- static void decode_postinit(H264Context *h, int setup_finished)
- {
-     const SPS *sps = h->ps.sps;
-     H264Picture *out = h->cur_pic_ptr;
-     H264Picture *cur = h->cur_pic_ptr;
-     int i, pics, out_of_order, out_idx;
-     if (h->next_output_pic)
-         return;
-     if (cur->field_poc[0] == INT_MAX || cur->field_poc[1] == INT_MAX) {
-         /* FIXME: if we have two PAFF fields in one packet, we can't start
-          * the next thread here. If we have one field per packet, we can.
-          * The check in decode_nal_units() is not good enough to find this
-          * yet, so we assume the worst for now. */
-         // if (setup_finished)
-         //    ff_thread_finish_setup(h->avctx);
-         if (cur->field_poc[0] == INT_MAX && cur->field_poc[1] == INT_MAX)
-             return;
-         if (h->avctx->hwaccel || h->missing_fields <=1)
-             return;
-     }
-     cur->mmco_reset = h->mmco_reset;
-     h->mmco_reset = 0;
-     // FIXME do something with unavailable reference frames
-     /* Sort B-frames into display order */
-     if (sps->bitstream_restriction_flag ||
-         h->avctx->strict_std_compliance >= FF_COMPLIANCE_STRICT) {
-         h->avctx->has_b_frames = FFMAX(h->avctx->has_b_frames, sps->num_reorder_frames);
-     }
-     for (i = 0; 1; i++) {
-         if(i == MAX_DELAYED_PIC_COUNT || cur->poc < h->last_pocs[i]){
-             if(i)
-                 h->last_pocs[i-1] = cur->poc;
-             break;
-         } else if(i) {
-             h->last_pocs[i-1]= h->last_pocs[i];
-         }
-     }
-     out_of_order = MAX_DELAYED_PIC_COUNT - i;
-     if(   cur->f->pict_type == AV_PICTURE_TYPE_B
-        || (h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > INT_MIN && h->last_pocs[MAX_DELAYED_PIC_COUNT-1] - h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > 2))
-         out_of_order = FFMAX(out_of_order, 1);
-     if (out_of_order == MAX_DELAYED_PIC_COUNT) {
-         av_log(h->avctx, AV_LOG_VERBOSE, "Invalid POC %d<%d\n", cur->poc, h->last_pocs[0]);
-         for (i = 1; i < MAX_DELAYED_PIC_COUNT; i++)
-             h->last_pocs[i] = INT_MIN;
-         h->last_pocs[0] = cur->poc;
-         cur->mmco_reset = 1;
-     } else if(h->avctx->has_b_frames < out_of_order && !sps->bitstream_restriction_flag){
-         int loglevel = h->avctx->frame_number > 1 ? AV_LOG_WARNING : AV_LOG_VERBOSE;
-         av_log(h->avctx, loglevel, "Increasing reorder buffer to %d\n", out_of_order);
-         h->avctx->has_b_frames = out_of_order;
-     }
-     pics = 0;
-     while (h->delayed_pic[pics])
-         pics++;
-     av_assert0(pics <= MAX_DELAYED_PIC_COUNT);
-     h->delayed_pic[pics++] = cur;
-     if (cur->reference == 0)
-         cur->reference = DELAYED_PIC_REF;
-     out     = h->delayed_pic[0];
-     out_idx = 0;
-     for (i = 1; h->delayed_pic[i] &&
-                 !h->delayed_pic[i]->f->key_frame &&
-                 !h->delayed_pic[i]->mmco_reset;
-          i++)
-         if (h->delayed_pic[i]->poc < out->poc) {
-             out     = h->delayed_pic[i];
-             out_idx = i;
-         }
-     if (h->avctx->has_b_frames == 0 &&
-         (h->delayed_pic[0]->f->key_frame || h->delayed_pic[0]->mmco_reset))
-         h->next_outputed_poc = INT_MIN;
-     out_of_order = out->poc < h->next_outputed_poc;
-     if (out_of_order || pics > h->avctx->has_b_frames) {
-         out->reference &= ~DELAYED_PIC_REF;
-         for (i = out_idx; h->delayed_pic[i]; i++)
-             h->delayed_pic[i] = h->delayed_pic[i + 1];
-     }
-     if (!out_of_order && pics > h->avctx->has_b_frames) {
-         h->next_output_pic = out;
-         if (out_idx == 0 && h->delayed_pic[0] && (h->delayed_pic[0]->f->key_frame || h->delayed_pic[0]->mmco_reset)) {
-             h->next_outputed_poc = INT_MIN;
-         } else
-             h->next_outputed_poc = out->poc;
-     } else {
-         av_log(h->avctx, AV_LOG_DEBUG, "no picture %s\n", out_of_order ? "ooo" : "");
-     }
-     if (h->next_output_pic) {
-         if (h->next_output_pic->recovered) {
-             // We have reached an recovery point and all frames after it in
-             // display order are "recovered".
-             h->frame_recovered |= FRAME_RECOVERED_SEI;
-         }
-         h->next_output_pic->recovered |= !!(h->frame_recovered & FRAME_RECOVERED_SEI);
-     }
-     if (setup_finished && !h->avctx->hwaccel) {
-         ff_thread_finish_setup(h->avctx);
-         if (h->avctx->active_thread_type & FF_THREAD_FRAME)
-             h->setup_finished = 1;
-     }
- }
- /**
   * instantaneous decoder refresh.
   */
  static void idr(H264Context *h)
@@@ -803,38 -556,25 +679,41 @@@ again
              if (sl->redundant_pic_count > 0)
                  break;
  
-             if (h->current_slice == 1) {
-                 if (!(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS))
-                     decode_postinit(h, i >= nals_needed);
+             if (avctx->active_thread_type & FF_THREAD_FRAME && !h->avctx->hwaccel &&
 -                i >= nals_needed) {
++                i >= nals_needed && !h->setup_finished && h->cur_pic_ptr) {
+                 ff_thread_finish_setup(avctx);
+                 h->setup_finished = 1;
+             }
  
 -            if ((avctx->skip_frame < AVDISCARD_NONREF || nal->ref_idc) &&
 -                (avctx->skip_frame < AVDISCARD_BIDIR  ||
 -                 sl->slice_type_nos != AV_PICTURE_TYPE_B) &&
 -                (avctx->skip_frame < AVDISCARD_NONKEY ||
 -                 h->cur_pic_ptr->f->key_frame) &&
 -                avctx->skip_frame < AVDISCARD_ALL) {
 -                if (avctx->hwaccel) {
 -                    ret = avctx->hwaccel->decode_slice(avctx, nal->raw_data, nal->raw_size);
 -                    if (ret < 0)
 -                        return ret;
 -                } else
 -                    context_count++;
++            if (h->current_slice == 1) {
 +                if (h->avctx->hwaccel &&
 +                    (ret = h->avctx->hwaccel->start_frame(h->avctx, buf, buf_size)) < 0)
 +                    goto end;
 +#if FF_API_CAP_VDPAU
 +                if (CONFIG_H264_VDPAU_DECODER &&
 +                    h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU)
 +                    ff_vdpau_h264_picture_start(h);
 +#endif
              }
 +
 +            if (avctx->hwaccel) {
 +                ret = avctx->hwaccel->decode_slice(avctx,
 +                                                   nal->raw_data,
 +                                                   nal->raw_size);
 +                if (ret < 0)
 +                    goto end;
 +#if FF_API_CAP_VDPAU
 +            } else if (CONFIG_H264_VDPAU_DECODER &&
 +                       h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) {
 +                ff_vdpau_add_data_chunk(h->cur_pic_ptr->f->data[0],
 +                                        start_code,
 +                                        sizeof(start_code));
 +                ff_vdpau_add_data_chunk(h->cur_pic_ptr->f->data[0],
 +                                        nal->raw_data,
 +                                        nal->raw_size);
 +#endif
 +            } else
 +                context_count++;
              break;
          case H264_NAL_DPA:
          case H264_NAL_DPB:
@@@ -1015,81 -673,6 +894,78 @@@ static int output_frame(H264Context *h
      return 0;
  }
  
-         if (!out->recovered)
-             out->f->flags |= AV_FRAME_FLAG_CORRUPT;
 +static int is_extra(const uint8_t *buf, int buf_size)
 +{
 +    int cnt= buf[5]&0x1f;
 +    const uint8_t *p= buf+6;
 +    while(cnt--){
 +        int nalsize= AV_RB16(p) + 2;
 +        if(nalsize > buf_size - (p-buf) || (p[2] & 0x9F) != 7)
 +            return 0;
 +        p += nalsize;
 +    }
 +    cnt = *(p++);
 +    if(!cnt)
 +        return 0;
 +    while(cnt--){
 +        int nalsize= AV_RB16(p) + 2;
 +        if(nalsize > buf_size - (p-buf) || (p[2] & 0x9F) != 8)
 +            return 0;
 +        p += nalsize;
 +    }
 +    return 1;
 +}
 +
 +static int finalize_frame(H264Context *h, AVFrame *dst, H264Picture *out, int *got_frame)
 +{
 +    int ret;
 +
 +    if (((h->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) ||
 +         (h->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL) ||
 +         out->recovered)) {
 +
 +        if (!h->avctx->hwaccel &&
 +            (out->field_poc[0] == INT_MAX ||
 +             out->field_poc[1] == INT_MAX)
 +           ) {
 +            int p;
 +            AVFrame *f = out->f;
 +            int field = out->field_poc[0] == INT_MAX;
 +            uint8_t *dst_data[4];
 +            int linesizes[4];
 +            const uint8_t *src_data[4];
 +
 +            av_log(h->avctx, AV_LOG_DEBUG, "Duplicating field %d to fill missing\n", field);
 +
 +            for (p = 0; p<4; p++) {
 +                dst_data[p] = f->data[p] + (field^1)*f->linesize[p];
 +                src_data[p] = f->data[p] +  field   *f->linesize[p];
 +                linesizes[p] = 2*f->linesize[p];
 +            }
 +
 +            av_image_copy(dst_data, linesizes, src_data, linesizes,
 +                          f->format, f->width, f->height>>1);
 +        }
 +
 +        ret = output_frame(h, dst, out);
 +        if (ret < 0)
 +            return ret;
 +
 +        *got_frame = 1;
 +
 +        if (CONFIG_MPEGVIDEO) {
 +            ff_print_debug_info2(h->avctx, dst, NULL,
 +                                 out->mb_type,
 +                                 out->qscale_table,
 +                                 out->motion_val,
 +                                 NULL,
 +                                 h->mb_width, h->mb_height, h->mb_stride, 1);
 +        }
 +    }
 +
 +    return 0;
 +}
 +
  static int h264_decode_frame(AVCodecContext *avctx, void *data,
                               int *got_frame, AVPacket *avpkt)
  {
  
      if (!(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS) ||
          (h->mb_y >= h->mb_height && h->mb_height)) {
-         if (avctx->flags2 & AV_CODEC_FLAG2_CHUNKS)
-             decode_postinit(h, 1);
 -        ff_h264_field_end(h, &h->slice_ctx[0], 0);
 +        if ((ret = ff_h264_field_end(h, &h->slice_ctx[0], 0)) < 0)
 +            return ret;
  
 -        *got_frame = 0;
 -        if (h->output_frame->buf[0]) {
 -            ret = output_frame(h, pict, h->output_frame) ;
 -            av_frame_unref(h->output_frame);
 +        /* Wait for second field. */
 +        if (h->next_output_pic) {
 +            ret = finalize_frame(h, pict, h->next_output_pic, got_frame);
              if (ret < 0)
                  return ret;
 -            *got_frame = 1;
          }
      }