Commit 28096e0a authored by John Stebbins's avatar John Stebbins Committed by 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: 's avatarAnton Khirnov <anton@khirnov.net>
parent 9af7a852
...@@ -13,6 +13,9 @@ libavutil: 2012-10-22 ...@@ -13,6 +13,9 @@ libavutil: 2012-10-22
API changes, most recent first: 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 2013-08-xx - xxxxxxx - lavfi 3.11.0 - avfilter.h
Add AVFilterGraph.execute and AVFilterGraph.opaque for custom slice threading Add AVFilterGraph.execute and AVFilterGraph.opaque for custom slice threading
implementations. implementations.
......
...@@ -629,6 +629,7 @@ typedef struct RcOverride{ ...@@ -629,6 +629,7 @@ typedef struct RcOverride{
#define CODEC_FLAG_UNALIGNED 0x0001 #define CODEC_FLAG_UNALIGNED 0x0001
#define CODEC_FLAG_QSCALE 0x0002 ///< Use fixed qscale. #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_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_QPEL 0x0010 ///< Use qpel MC.
#define CODEC_FLAG_GMC 0x0020 ///< Use GMC. #define CODEC_FLAG_GMC 0x0020 ///< Use GMC.
#define CODEC_FLAG_MV0 0x0040 ///< Always try a MB with MV=<0,0>. #define CODEC_FLAG_MV0 0x0040 ///< Always try a MB with MV=<0,0>.
......
...@@ -336,6 +336,7 @@ static int ref_picture(H264Context *h, Picture *dst, Picture *src) ...@@ -336,6 +336,7 @@ static int ref_picture(H264Context *h, Picture *dst, Picture *src)
dst->field_picture = src->field_picture; dst->field_picture = src->field_picture;
dst->needs_realloc = src->needs_realloc; dst->needs_realloc = src->needs_realloc;
dst->reference = src->reference; dst->reference = src->reference;
dst->recovered = src->recovered;
return 0; return 0;
fail: fail:
...@@ -1560,6 +1561,8 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx) ...@@ -1560,6 +1561,8 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
h->prev_poc_msb = 1 << 16; h->prev_poc_msb = 1 << 16;
h->x264_build = -1; h->x264_build = -1;
ff_h264_reset_sei(h); ff_h264_reset_sei(h);
h->recovery_frame = -1;
h->frame_recovered = 0;
if (avctx->codec_id == AV_CODEC_ID_H264) { if (avctx->codec_id == AV_CODEC_ID_H264) {
if (avctx->ticks_per_frame == 1) if (avctx->ticks_per_frame == 1)
h->avctx->time_base.den *= 2; h->avctx->time_base.den *= 2;
...@@ -1839,6 +1842,9 @@ static int decode_update_thread_context(AVCodecContext *dst, ...@@ -1839,6 +1842,9 @@ static int decode_update_thread_context(AVCodecContext *dst,
h->prev_frame_num = h->frame_num; h->prev_frame_num = h->frame_num;
h->outputed_poc = h->next_outputed_poc; h->outputed_poc = h->next_outputed_poc;
h->recovery_frame = h1->recovery_frame;
h->frame_recovered = h1->frame_recovered;
return err; return err;
} }
...@@ -1868,6 +1874,7 @@ static int h264_frame_start(H264Context *h) ...@@ -1868,6 +1874,7 @@ static int h264_frame_start(H264Context *h)
*/ */
pic->f.key_frame = 0; pic->f.key_frame = 0;
pic->mmco_reset = 0; pic->mmco_reset = 0;
pic->recovered = 0;
if ((ret = alloc_picture(h, pic)) < 0) if ((ret = alloc_picture(h, pic)) < 0)
return ret; return ret;
...@@ -2139,6 +2146,15 @@ static void decode_postinit(H264Context *h, int setup_finished) ...@@ -2139,6 +2146,15 @@ static void decode_postinit(H264Context *h, int setup_finished)
av_log(h->avctx, AV_LOG_DEBUG, "no picture\n"); 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) if (setup_finished && !h->avctx->hwaccel)
ff_thread_finish_setup(h->avctx); ff_thread_finish_setup(h->avctx);
} }
...@@ -2720,6 +2736,8 @@ static void flush_change(H264Context *h) ...@@ -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[0], 0, sizeof(h->default_ref_list[0]));
memset(h->default_ref_list[1], 0, sizeof(h->default_ref_list[1])); memset(h->default_ref_list[1], 0, sizeof(h->default_ref_list[1]));
ff_h264_reset_sei(h); ff_h264_reset_sei(h);
h->recovery_frame = -1;
h->frame_recovered = 0;
} }
/* forget old pics after a seek */ /* forget old pics after a seek */
...@@ -4609,10 +4627,26 @@ again: ...@@ -4609,10 +4627,26 @@ again:
if ((err = decode_slice_header(hx, h))) if ((err = decode_slice_header(hx, h)))
break; 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 |= h->cur_pic_ptr->f.key_frame |=
(hx->nal_unit_type == NAL_IDR_SLICE) || (hx->nal_unit_type == NAL_IDR_SLICE) ||
(h->sei_recovery_frame_cnt >= 0); (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 (h->current_slice == 1) {
if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS)) if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS))
decode_postinit(h, nal_index >= nals_needed); decode_postinit(h, nal_index >= nals_needed);
...@@ -4842,10 +4876,12 @@ out: ...@@ -4842,10 +4876,12 @@ out:
field_end(h, 0); field_end(h, 0);
if (!h->next_output_pic) {
/* Wait for second field. */
*got_frame = 0; *got_frame = 0;
} else { 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); ret = output_frame(h, pict, &h->next_output_pic->f);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -611,6 +611,27 @@ typedef struct H264Context { ...@@ -611,6 +611,27 @@ typedef struct H264Context {
*/ */
int sei_recovery_frame_cnt; 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 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 int chroma_weight_flag[2]; ///< 7.4.3.2 chroma_weight_lX_flag
......
...@@ -172,6 +172,7 @@ typedef struct Picture{ ...@@ -172,6 +172,7 @@ typedef struct Picture{
int reference; int reference;
int shared; int shared;
int recovered; ///< Picture at IDR or recovery point + recovery count
} Picture; } Picture;
/** /**
......
...@@ -68,6 +68,7 @@ static const AVOption avcodec_options[] = { ...@@ -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"}, {"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"}, {"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"}, {"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"}, {"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"}, {"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"}, {"ignorecrop", "ignore cropping information from sps", 1, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_IGNORE_CROP }, INT_MIN, INT_MAX, V|D, "flags2"},
......
...@@ -350,6 +350,16 @@ typedef struct AVFrame { ...@@ -350,6 +350,16 @@ typedef struct AVFrame {
AVFrameSideData **side_data; AVFrameSideData **side_data;
int nb_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; } AVFrame;
/** /**
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
*/ */
#define LIBAVUTIL_VERSION_MAJOR 52 #define LIBAVUTIL_VERSION_MAJOR 52
#define LIBAVUTIL_VERSION_MINOR 16 #define LIBAVUTIL_VERSION_MINOR 17
#define LIBAVUTIL_VERSION_MICRO 0 #define LIBAVUTIL_VERSION_MICRO 0
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment