[FFmpeg-cvslog] h264: wait for initial complete frame before outputing frames

John Stebbins git at videolan.org
Fri Nov 1 13:04:12 CET 2013


ffmpeg | branch: master | John Stebbins <stebbins at jetheaddev.com> | Fri Oct 11 09:51:50 2013 -0700| [28096e0a806e57376541e6222d315619906e3c55] | committer: Anton Khirnov

h264: wait for initial complete frame before outputing frames

This can be optionally disabled whith the "output_corrupt" flags
option.  When in "output_corrupt" mode, incomplete frames are
signalled through AVFrame.flags FRAME_FLAG_INCOMPLETE_FRAME.

Signed-off-by: Anton Khirnov <anton at khirnov.net>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=28096e0a806e57376541e6222d315619906e3c55
---

 doc/APIchanges             |    3 +++
 libavcodec/avcodec.h       |    1 +
 libavcodec/h264.c          |   44 ++++++++++++++++++++++++++++++++++++++++----
 libavcodec/h264.h          |   21 +++++++++++++++++++++
 libavcodec/mpegvideo.h     |    1 +
 libavcodec/options_table.h |    1 +
 libavutil/frame.h          |   10 ++++++++++
 libavutil/version.h        |    2 +-
 8 files changed, 78 insertions(+), 5 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 20fb16e..561c828 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,9 @@ libavutil:     2012-10-22
 
 API changes, most recent first:
 
+2013-08-xx - xxxxxxx - lavu 52.17.0 - avframe.h
+  Add AVFrame.flags and AV_FRAME_FLAG_CORRUPT.
+
 2013-08-xx - xxxxxxx - lavfi 3.11.0 - avfilter.h
   Add AVFilterGraph.execute and AVFilterGraph.opaque for custom slice threading
   implementations.
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 6cd7076..3f3b4d2 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -629,6 +629,7 @@ typedef struct RcOverride{
 #define CODEC_FLAG_UNALIGNED 0x0001
 #define CODEC_FLAG_QSCALE 0x0002  ///< Use fixed qscale.
 #define CODEC_FLAG_4MV    0x0004  ///< 4 MV per MB allowed / advanced prediction for H.263.
+#define CODEC_FLAG_OUTPUT_CORRUPT 0x0008 ///< Output even those frames that might be corrupted
 #define CODEC_FLAG_QPEL   0x0010  ///< Use qpel MC.
 #define CODEC_FLAG_GMC    0x0020  ///< Use GMC.
 #define CODEC_FLAG_MV0    0x0040  ///< Always try a MB with MV=<0,0>.
diff --git a/libavcodec/h264.c b/libavcodec/h264.c
index d093928..f0ef2eb 100644
--- a/libavcodec/h264.c
+++ b/libavcodec/h264.c
@@ -336,6 +336,7 @@ static int ref_picture(H264Context *h, Picture *dst, Picture *src)
     dst->field_picture = src->field_picture;
     dst->needs_realloc = src->needs_realloc;
     dst->reference     = src->reference;
+    dst->recovered     = src->recovered;
 
     return 0;
 fail:
@@ -1560,6 +1561,8 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
     h->prev_poc_msb = 1 << 16;
     h->x264_build   = -1;
     ff_h264_reset_sei(h);
+    h->recovery_frame = -1;
+    h->frame_recovered = 0;
     if (avctx->codec_id == AV_CODEC_ID_H264) {
         if (avctx->ticks_per_frame == 1)
             h->avctx->time_base.den *= 2;
@@ -1839,6 +1842,9 @@ static int decode_update_thread_context(AVCodecContext *dst,
     h->prev_frame_num        = h->frame_num;
     h->outputed_poc          = h->next_outputed_poc;
 
+    h->recovery_frame        = h1->recovery_frame;
+    h->frame_recovered       = h1->frame_recovered;
+
     return err;
 }
 
@@ -1868,6 +1874,7 @@ static int h264_frame_start(H264Context *h)
      */
     pic->f.key_frame = 0;
     pic->mmco_reset  = 0;
+    pic->recovered   = 0;
 
     if ((ret = alloc_picture(h, pic)) < 0)
         return ret;
@@ -2139,6 +2146,15 @@ static void decode_postinit(H264Context *h, int setup_finished)
         av_log(h->avctx, AV_LOG_DEBUG, "no picture\n");
     }
 
+    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);
 }
@@ -2720,6 +2736,8 @@ static void flush_change(H264Context *h)
     memset(h->default_ref_list[0], 0, sizeof(h->default_ref_list[0]));
     memset(h->default_ref_list[1], 0, sizeof(h->default_ref_list[1]));
     ff_h264_reset_sei(h);
+    h->recovery_frame = -1;
+    h->frame_recovered = 0;
 }
 
 /* forget old pics after a seek */
@@ -4609,10 +4627,26 @@ again:
                 if ((err = decode_slice_header(hx, h)))
                     break;
 
+                if (h->sei_recovery_frame_cnt >= 0 && h->recovery_frame < 0) {
+                    h->recovery_frame = (h->frame_num + h->sei_recovery_frame_cnt) &
+                                        ((1 << h->sps.log2_max_frame_num) - 1);
+                }
+
                 h->cur_pic_ptr->f.key_frame |=
                     (hx->nal_unit_type == NAL_IDR_SLICE) ||
                     (h->sei_recovery_frame_cnt >= 0);
 
+                if (hx->nal_unit_type == NAL_IDR_SLICE ||
+                    h->recovery_frame == h->frame_num) {
+                    h->recovery_frame         = -1;
+                    h->cur_pic_ptr->recovered = 1;
+                }
+                // If we have an IDR, all frames after it in decoded order are
+                // "recovered".
+                if (hx->nal_unit_type == NAL_IDR_SLICE)
+                    h->frame_recovered |= FRAME_RECOVERED_IDR;
+                h->cur_pic_ptr->recovered |= !!(h->frame_recovered & FRAME_RECOVERED_IDR);
+
                 if (h->current_slice == 1) {
                     if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS))
                         decode_postinit(h, nal_index >= nals_needed);
@@ -4842,10 +4876,12 @@ out:
 
         field_end(h, 0);
 
-        if (!h->next_output_pic) {
-            /* Wait for second field. */
-            *got_frame = 0;
-        } else {
+        *got_frame = 0;
+        if (h->next_output_pic && ((avctx->flags & CODEC_FLAG_OUTPUT_CORRUPT) ||
+                                   h->next_output_pic->recovered)) {
+            if (!h->next_output_pic->recovered)
+                h->next_output_pic->f.flags |= AV_FRAME_FLAG_CORRUPT;
+
             ret = output_frame(h, pict, &h->next_output_pic->f);
             if (ret < 0)
                 return ret;
diff --git a/libavcodec/h264.h b/libavcodec/h264.h
index cb97067..920e3fc 100644
--- a/libavcodec/h264.h
+++ b/libavcodec/h264.h
@@ -611,6 +611,27 @@ typedef struct H264Context {
      */
     int sei_recovery_frame_cnt;
 
+    /**
+     * recovery_frame is the frame_num at which the next frame should
+     * be fully constructed.
+     *
+     * Set to -1 when not expecting a recovery point.
+     */
+    int recovery_frame;
+
+/**
+ * We have seen an IDR, so all the following frames in coded order are correctly
+ * decodable.
+ */
+#define FRAME_RECOVERED_IDR  (1 << 0)
+/**
+ * Sufficient number of frames have been decoded since a SEI recovery point,
+ * so all the following frames in presentation order are correct.
+ */
+#define FRAME_RECOVERED_SEI  (1 << 1)
+
+    int frame_recovered;    ///< Initial frame has been completely recovered
+
     int luma_weight_flag[2];    ///< 7.4.3.2 luma_weight_lX_flag
     int chroma_weight_flag[2];  ///< 7.4.3.2 chroma_weight_lX_flag
 
diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h
index 9f222c5..78792cf 100644
--- a/libavcodec/mpegvideo.h
+++ b/libavcodec/mpegvideo.h
@@ -172,6 +172,7 @@ typedef struct Picture{
 
     int reference;
     int shared;
+    int recovered;              ///< Picture at IDR or recovery point + recovery count
 } Picture;
 
 /**
diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
index 0706f9a..f6be31b 100644
--- a/libavcodec/options_table.h
+++ b/libavcodec/options_table.h
@@ -68,6 +68,7 @@ static const AVOption avcodec_options[] = {
 {"aic", "H.263 advanced intra coding / MPEG-4 AC prediction", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_AC_PRED }, INT_MIN, INT_MAX, V|E, "flags"},
 {"ilme", "interlaced motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_INTERLACED_ME }, INT_MIN, INT_MAX, V|E, "flags"},
 {"cgop", "closed GOP", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_CLOSED_GOP }, INT_MIN, INT_MAX, V|E, "flags"},
+{"output_corrupt", "Output even potentially corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_OUTPUT_CORRUPT }, INT_MIN, INT_MAX, V|D, "flags"},
 {"fast", "allow non-spec-compliant speedup tricks", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_FAST }, INT_MIN, INT_MAX, V|E, "flags2"},
 {"noout", "skip bitstream encoding", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_NO_OUTPUT }, INT_MIN, INT_MAX, V|E, "flags2"},
 {"ignorecrop", "ignore cropping information from sps", 1, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_IGNORE_CROP }, INT_MIN, INT_MAX, V|D, "flags2"},
diff --git a/libavutil/frame.h b/libavutil/frame.h
index bbff3d1..449a6b7 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -350,6 +350,16 @@ typedef struct AVFrame {
 
     AVFrameSideData **side_data;
     int            nb_side_data;
+
+/**
+ * The frame data may be corrupted, e.g. due to decoding errors.
+ */
+#define AV_FRAME_FLAG_CORRUPT       (1 << 0)
+
+    /**
+     * Frame flags, a combination of AV_FRAME_FLAG_*
+     */
+    int flags;
 } AVFrame;
 
 /**
diff --git a/libavutil/version.h b/libavutil/version.h
index 635055f..aa13a0f 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -37,7 +37,7 @@
  */
 
 #define LIBAVUTIL_VERSION_MAJOR 52
-#define LIBAVUTIL_VERSION_MINOR 16
+#define LIBAVUTIL_VERSION_MINOR 17
 #define LIBAVUTIL_VERSION_MICRO  0
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \



More information about the ffmpeg-cvslog mailing list