[FFmpeg-devel] [PATCH, RFC] lavc/hevcdec: add invalid for skip_frame to skip invalid nalus before IRAP
Mark Thompson
sw at jkqxz.net
Fri Aug 14 21:23:11 EEST 2020
On 14/08/2020 11:35, Linjie Fu wrote:
> Add "-skip_frame invalid" option to allow user to request decoder to skip
> invalid nalus before an IRAP.
>
> This would benefit decoding pipeline of bitstreams who didn't start from
> an IRAP frame. NULL pointer pointing to missing reference may lead to
> unexpected hang issues[1] in sub-level like hardware decoding.
>
> Fixing the hang in driver is the first correct thing. Besides, adding a check
> in nalu parsing and skip frames until we got the first IRAP would be another
> good choice to be more robust for error tolerance.
>
> Also this needs worker thread to update the skip_frames field in time.
>
> [1] https://github.com/intel/media-driver/issues/992
H.265 has a standard mechanism for dealing with missing reference pictures, which is defined in 8.3.3. That doesn't directly apply for the case here (it's intended for RASL pictures), but a conformant decoder must be implementing it somewhere - can the Intel driver use that?
Trying to eliminate this case entirely is not going to work - being able to splice intra-refresh streams at any point depends on sensible behaviour for missing references, and streams containing errors due to packet loss can always happen.
>
> Signed-off-by: Linjie Fu <linjie.justin.fu at gmail.com>
> ---
> Request for comments:
> The purpose is to allow decoder to skip frames until an IRAP has arrived, however
> not sure whether we already had this in ffmpeg, hence submit a patch and
> request for comments.
>
> Skip logic identical for AVDISCARD_NONKEY in decode_nal_unit(). >
> libavcodec/avcodec.h | 1 +
> libavcodec/hevcdec.c | 5 ++++-
> libavcodec/options_table.h | 1 +
> libavcodec/pthread_frame.c | 1 +
> 4 files changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index c91b2fd169..376d7f4d6d 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -233,6 +233,7 @@ enum AVDiscard{
> AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames
> AVDISCARD_NONINTRA= 24, ///< discard all non intra frames
> AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes
> + AVDISCARD_INVALID = 33, ///< discard invalid packets like NALs before IRAP
IMO INVALID is not a good name to use here - such packets are perfectly valid in cases like intra-refresh.
"before" would need to be clarified - RADL frames can definitely be thought of as "before" the associated IRAP picture, but this wouldn't be discarding them.
Also, it should probably avoid using H.265-specific terminology for the explanation in the generic header.
> AVDISCARD_ALL = 48, ///< discard all
> };
>
> diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
> index b77df8d89f..78658fd537 100644
> --- a/libavcodec/hevcdec.c
> +++ b/libavcodec/hevcdec.c
> @@ -539,8 +539,11 @@ static int hls_slice_header(HEVCContext *s)
> ff_hevc_clear_refs(s);
> }
> sh->no_output_of_prior_pics_flag = 0;
> - if (IS_IRAP(s))
> + if (IS_IRAP(s)) {
> sh->no_output_of_prior_pics_flag = get_bits1(gb);
> + if (s->avctx->skip_frame == AVDISCARD_INVALID)
> + s->avctx->skip_frame = AVDISCARD_DEFAULT;
> + }
>
> sh->pps_id = get_ue_golomb_long(gb);
> if (sh->pps_id >= HEVC_MAX_PPS_COUNT || !s->ps.pps_list[sh->pps_id]) {
> diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
> index 1d0db1b5a4..d52bce5908 100644
> --- a/libavcodec/options_table.h
> +++ b/libavcodec/options_table.h
> @@ -310,6 +310,7 @@ static const AVOption avcodec_options[] = {
> {"bidir" , "discard all bidirectional frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_BIDIR }, INT_MIN, INT_MAX, V|D, "avdiscard"},
> {"nokey" , "discard all frames except keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONKEY }, INT_MIN, INT_MAX, V|D, "avdiscard"},
> {"nointra" , "discard all frames except I frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONINTRA}, INT_MIN, INT_MAX, V|D, "avdiscard"},
> +{"invalid" , "discard NALUs before IRAP", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_INVALID }, INT_MIN, INT_MAX, V|D, "avdiscard"},
> {"all" , "discard all frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_ALL }, INT_MIN, INT_MAX, V|D, "avdiscard"},
> {"bidir_refine", "refine the two motion vectors used in bidirectional macroblocks", OFFSET(bidir_refine), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, 4, V|E},
> #if FF_API_PRIVATE_OPT
> diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
> index 3255aa9337..302e6149ac 100644
> --- a/libavcodec/pthread_frame.c
> +++ b/libavcodec/pthread_frame.c
> @@ -259,6 +259,7 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src,
>
> dst->has_b_frames = src->has_b_frames;
> dst->idct_algo = src->idct_algo;
> + dst->skip_frame = src->skip_frame;
>
> dst->bits_per_coded_sample = src->bits_per_coded_sample;
> dst->sample_aspect_ratio = src->sample_aspect_ratio;
>
- Mark
More information about the ffmpeg-devel
mailing list