On Saturday, September 7, 2013, John Stebbins wrote:
> This can be optionally disabled whith the "showall" flags2 option.
> When in "showall" mode, incomplete frames are signalled through
> AVFrame.flags FRAME_FLAG_INCOMPLETE_FRAME.
I think it'd be better to leave the current behavior as default and an
option like WAIT_KEYFRAME that implements your idea.
Also does this apply to h264 or does this work with other codecs too? In
the former case then a private decode option would be a better place than
flags2 for this flag.
---
> libavcodec/avcodec.h | 1 +
> libavcodec/h264.c | 34 ++++++++++++++++++++++++++++++----
> libavcodec/h264.h | 9 +++++++++
> libavcodec/mpegvideo.h | 1 +
> libavcodec/options_table.h | 1 +
> libavutil/frame.c | 1 +
> libavutil/frame.h | 3 +++
> 7 files changed, 46 insertions(+), 4 deletions(-)
>
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index caf8284..c818413 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -656,6 +656,7 @@ typedef struct RcOverride{
> #define CODEC_FLAG2_IGNORE_CROP 0x00010000 ///< Discard cropping
> information from SPS.
>
> #define CODEC_FLAG2_CHUNKS 0x00008000 ///< Input bitstream might
> be truncated at a packet boundaries instead of only at frame boundaries.
> +#define CODEC_FLAG2_SHOW_ALL 0x00400000 ///< Show all frames before
> the first keyframe
>
> /* Unsupported options :
> * Syntax Arithmetic coding (SAC)
> diff --git a/libavcodec/h264.c b/libavcodec/h264.c
> index 832b5c7..5812fcb 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:
> @@ -1558,6 +1559,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;
> @@ -1828,6 +1831,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;
> }
>
> @@ -1857,6 +1863,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;
> @@ -2709,6 +2716,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 */
> @@ -4584,10 +4593,22 @@ 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);
> + }
> +
> 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 (h->current_slice == 1) {
> if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS))
> decode_postinit(h, nal_index >= nals_needed);
> @@ -4817,10 +4838,15 @@ out:
>
> field_end(h, 0);
>
> - if (!h->next_output_pic) {
> - /* Wait for second field. */
> - *got_frame = 0;
> - } else {
> + /* Wait for second field. */
> + *got_frame = 0;
> + if (h->next_output_pic && h->next_output_pic->recovered) {
> + h->frame_recovered = 1;
> + }
> + if (h->next_output_pic && ((avctx->flags2 & CODEC_FLAG2_SHOW_ALL)
> ||
> + h->frame_recovered)) {
> + if (!h->frame_recovered)
> + h->next_output_pic->f.flags |=
> FRAME_FLAG_INCOMPLETE_FRAME;
Here you could simplify this section and avoid checking h->next_output_pic
twice.
> 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 3ef8420..0fe9921 100644
> --- a/libavcodec/h264.h
> +++ b/libavcodec/h264.h
> @@ -611,6 +611,15 @@ 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;
> + 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 307ed5f..4f2718d 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 5e9d484..9113272 100644
> --- a/libavcodec/options_table.h
> +++ b/libavcodec/options_table.h
> @@ -72,6 +72,7 @@ static const AVOption avcodec_options[] = {
> {"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"},
> {"local_header", "place global headers at every keyframe instead of in
> extradata", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_LOCAL_HEADER },
> INT_MIN, INT_MAX, V|E, "flags2"},
> +{"showall", "Show all frames before the first keyframe", 0,
> AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_SHOW_ALL }, INT_MIN, INT_MAX, V|D,
> "flags2"},
> {"me_method", "set motion estimation method", OFFSET(me_method),
> AV_OPT_TYPE_INT, {.i64 = ME_EPZS }, INT_MIN, INT_MAX, V|E, "me_method"},
> {"zero", "zero motion estimation (fastest)", 0, AV_OPT_TYPE_CONST, {.i64
> = ME_ZERO }, INT_MIN, INT_MAX, V|E, "me_method" },
> {"full", "full motion estimation (slowest)", 0, AV_OPT_TYPE_CONST, {.i64
> = ME_FULL }, INT_MIN, INT_MAX, V|E, "me_method" },
> diff --git a/libavutil/frame.c b/libavutil/frame.c
> index 098bbed..78bad66 100644
> --- a/libavutil/frame.c
> +++ b/libavutil/frame.c
> @@ -379,6 +379,7 @@ int av_frame_copy_props(AVFrame *dst, const AVFrame
> *src)
> dst->quality = src->quality;
> dst->coded_picture_number = src->coded_picture_number;
> dst->display_picture_number = src->display_picture_number;
> + dst->flags = src->flags;
>
> memcpy(dst->error, src->error, sizeof(dst->error));
>
> diff --git a/libavutil/frame.h b/libavutil/frame.h
> index d71948d..5365682 100644
> --- a/libavutil/frame.h
> +++ b/libavutil/frame.h
> @@ -347,6 +347,9 @@ typedef struct AVFrame {
>
> AVFrameSideData **side_data;
> int nb_side_data;
> +
> + int flags;
> +#define FRAME_FLAG_INCOMPLETE_FRAME 0x0001
> } AVFrame;
>
>
I like the idea too but I'm not sure we should add a new element to AVFrame
for a single flag.
Do you think you could use the AVFrameSideData API for this functionality?
Vittorio
/**
> --
> 1.8.3.1
>
> _______________________________________________
> libav-devel mailing list
> [email protected] <javascript:;>
> https://lists.libav.org/mailman/listinfo/libav-devel
>
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel