diff mbox series

[FFmpeg-devel,3/4] avcodec/decode: Set KEY flag+pict_type generically for intra-only codecs

Message ID GV1P250MB07371C1E0C33E95C5433E4EA8FE62@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM
State Accepted
Commit eee88ba0dc67b5beaa31199d5bf1e7fc324e0652
Headers show
Series [FFmpeg-devel,1/5] avcodec/mlpdec: Set AV_FRAME_FLAG_KEY explicitly | expand

Commit Message

Andreas Rheinhardt May 9, 2024, 2:04 a.m. UTC
This commit is the analog of 3f11eac75741888c7b2b6f93c458766f2613bab5
for decoding: It sets the AV_FRAME_FLAG_KEY and (for video decoders)
also pict_type to AV_PICTURE_TYPE_I. It furthermore stops setting
audio frames as always being key frames -- it is wrong for e.g.
TrueHD/MLP. The latter also affects TAK and DFPWM.

The change already improves output for several decoders where
it has been forgotten to set e.g. pict_type like speedhq, wnv1
or tiff. The latter is the reason for the change to the exif-image-tiff
FATE test reference file.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/decode.c            | 29 +++++++++++++++++++++++++++--
 libavcodec/pthread_frame.c     | 17 ++++++++++++++---
 tests/ref/fate/exif-image-tiff |  2 +-
 3 files changed, 42 insertions(+), 6 deletions(-)

Comments

Tomas Härdin May 13, 2024, 8:28 a.m. UTC | #1
tor 2024-05-09 klockan 04:04 +0200 skrev Andreas Rheinhardt:
> This commit is the analog of 3f11eac75741888c7b2b6f93c458766f2613bab5
> for decoding: It sets the AV_FRAME_FLAG_KEY and (for video decoders)
> also pict_type to AV_PICTURE_TYPE_I. It furthermore stops setting
> audio frames as always being key frames -- it is wrong for e.g.
> TrueHD/MLP. The latter also affects TAK and DFPWM.
> 
> The change already improves output for several decoders where
> it has been forgotten to set e.g. pict_type like speedhq, wnv1
> or tiff. The latter is the reason for the change to the exif-image-
> tiff
> FATE test reference file.
> 
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
>  libavcodec/decode.c            | 29 +++++++++++++++++++++++++++--
>  libavcodec/pthread_frame.c     | 17 ++++++++++++++---
>  tests/ref/fate/exif-image-tiff |  2 +-
>  3 files changed, 42 insertions(+), 6 deletions(-)
> 
> diff --git a/libavcodec/decode.c b/libavcodec/decode.c
> index d031b1ca17..0ca5344ef5 100644
> --- a/libavcodec/decode.c
> +++ b/libavcodec/decode.c
> @@ -57,6 +57,20 @@
>  typedef struct DecodeContext {
>      AVCodecInternal avci;
>  
> +    /**
> +     * This is set to AV_FRAME_FLAG_KEY for decoders of intra-only
> formats
> +     * (those whose codec descriptor has AV_CODEC_PROP_INTRA_ONLY
> set)
> +     * to set the flag generically.
> +     */
> +    int intra_only_flag;
> +
> +    /**
> +     * This is set to AV_PICTURE_TYPE_I for intra only video
> decoders
> +     * and to AV_PICTURE_TYPE_NONE for other decoders. It is used to
> set
> +     * the AVFrame's pict_type before the decoder receives it.
> +     */
> +    enum AVPictureType initial_pict_type;

Carrying this around as state seems unnecessary when a small static
function could do the same?

> @@ -108,6 +106,10 @@ typedef struct PerThreadContext {
>      int hwaccel_threadsafe;
>  
>      atomic_int debug_threads;       ///< Set if the FF_DEBUG_THREADS
> option is set.
> +
> +    /// The following two fields have the same semantics as the
> DecodeContext field
> +    int intra_only_flag;
> +    enum AVPictureType initial_pict_type;

Same here

/Tomas
Andreas Rheinhardt May 13, 2024, 8:54 a.m. UTC | #2
Tomas Härdin:
> tor 2024-05-09 klockan 04:04 +0200 skrev Andreas Rheinhardt:
>> This commit is the analog of 3f11eac75741888c7b2b6f93c458766f2613bab5
>> for decoding: It sets the AV_FRAME_FLAG_KEY and (for video decoders)
>> also pict_type to AV_PICTURE_TYPE_I. It furthermore stops setting
>> audio frames as always being key frames -- it is wrong for e.g.
>> TrueHD/MLP. The latter also affects TAK and DFPWM.
>>
>> The change already improves output for several decoders where
>> it has been forgotten to set e.g. pict_type like speedhq, wnv1
>> or tiff. The latter is the reason for the change to the exif-image-
>> tiff
>> FATE test reference file.
>>
>> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
>> ---
>>  libavcodec/decode.c            | 29 +++++++++++++++++++++++++++--
>>  libavcodec/pthread_frame.c     | 17 ++++++++++++++---
>>  tests/ref/fate/exif-image-tiff |  2 +-
>>  3 files changed, 42 insertions(+), 6 deletions(-)
>>
>> diff --git a/libavcodec/decode.c b/libavcodec/decode.c
>> index d031b1ca17..0ca5344ef5 100644
>> --- a/libavcodec/decode.c
>> +++ b/libavcodec/decode.c
>> @@ -57,6 +57,20 @@
>>  typedef struct DecodeContext {
>>      AVCodecInternal avci;
>>  
>> +    /**
>> +     * This is set to AV_FRAME_FLAG_KEY for decoders of intra-only
>> formats
>> +     * (those whose codec descriptor has AV_CODEC_PROP_INTRA_ONLY
>> set)
>> +     * to set the flag generically.
>> +     */
>> +    int intra_only_flag;
>> +
>> +    /**
>> +     * This is set to AV_PICTURE_TYPE_I for intra only video
>> decoders
>> +     * and to AV_PICTURE_TYPE_NONE for other decoders. It is used to
>> set
>> +     * the AVFrame's pict_type before the decoder receives it.
>> +     */
>> +    enum AVPictureType initial_pict_type;
> 
> Carrying this around as state seems unnecessary when a small static
> function could do the same?
> 

The aim of this is to avoid branches for every frame.

- Andreas
Tomas Härdin May 13, 2024, 3:52 p.m. UTC | #3
mån 2024-05-13 klockan 10:54 +0200 skrev Andreas Rheinhardt:
> Tomas Härdin:
> > tor 2024-05-09 klockan 04:04 +0200 skrev Andreas Rheinhardt:
> > > This commit is the analog of
> > > 3f11eac75741888c7b2b6f93c458766f2613bab5
> > > for decoding: It sets the AV_FRAME_FLAG_KEY and (for video
> > > decoders)
> > > also pict_type to AV_PICTURE_TYPE_I. It furthermore stops setting
> > > audio frames as always being key frames -- it is wrong for e.g.
> > > TrueHD/MLP. The latter also affects TAK and DFPWM.
> > > 
> > > The change already improves output for several decoders where
> > > it has been forgotten to set e.g. pict_type like speedhq, wnv1
> > > or tiff. The latter is the reason for the change to the exif-
> > > image-
> > > tiff
> > > FATE test reference file.
> > > 
> > > Signed-off-by: Andreas Rheinhardt
> > > <andreas.rheinhardt@outlook.com>
> > > ---
> > >  libavcodec/decode.c            | 29 +++++++++++++++++++++++++++-
> > > -
> > >  libavcodec/pthread_frame.c     | 17 ++++++++++++++---
> > >  tests/ref/fate/exif-image-tiff |  2 +-
> > >  3 files changed, 42 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/libavcodec/decode.c b/libavcodec/decode.c
> > > index d031b1ca17..0ca5344ef5 100644
> > > --- a/libavcodec/decode.c
> > > +++ b/libavcodec/decode.c
> > > @@ -57,6 +57,20 @@
> > >  typedef struct DecodeContext {
> > >      AVCodecInternal avci;
> > >  
> > > +    /**
> > > +     * This is set to AV_FRAME_FLAG_KEY for decoders of intra-
> > > only
> > > formats
> > > +     * (those whose codec descriptor has
> > > AV_CODEC_PROP_INTRA_ONLY
> > > set)
> > > +     * to set the flag generically.
> > > +     */
> > > +    int intra_only_flag;
> > > +
> > > +    /**
> > > +     * This is set to AV_PICTURE_TYPE_I for intra only video
> > > decoders
> > > +     * and to AV_PICTURE_TYPE_NONE for other decoders. It is
> > > used to
> > > set
> > > +     * the AVFrame's pict_type before the decoder receives it.
> > > +     */
> > > +    enum AVPictureType initial_pict_type;
> > 
> > Carrying this around as state seems unnecessary when a small static
> > function could do the same?
> > 
> 
> The aim of this is to avoid branches for every frame.

Checking a single value that will likely reside in cache once per frame
is hardly expensive, especially when the branch predictor will predict
it correctly.

When you carry state around you're carrying around multiple sources of
truth, which is something that tends to cause bugs..

/Tomas
Andreas Rheinhardt May 13, 2024, 3:55 p.m. UTC | #4
Tomas Härdin:
> mån 2024-05-13 klockan 10:54 +0200 skrev Andreas Rheinhardt:
>> Tomas Härdin:
>>> tor 2024-05-09 klockan 04:04 +0200 skrev Andreas Rheinhardt:
>>>> This commit is the analog of
>>>> 3f11eac75741888c7b2b6f93c458766f2613bab5
>>>> for decoding: It sets the AV_FRAME_FLAG_KEY and (for video
>>>> decoders)
>>>> also pict_type to AV_PICTURE_TYPE_I. It furthermore stops setting
>>>> audio frames as always being key frames -- it is wrong for e.g.
>>>> TrueHD/MLP. The latter also affects TAK and DFPWM.
>>>>
>>>> The change already improves output for several decoders where
>>>> it has been forgotten to set e.g. pict_type like speedhq, wnv1
>>>> or tiff. The latter is the reason for the change to the exif-
>>>> image-
>>>> tiff
>>>> FATE test reference file.
>>>>
>>>> Signed-off-by: Andreas Rheinhardt
>>>> <andreas.rheinhardt@outlook.com>
>>>> ---
>>>>  libavcodec/decode.c            | 29 +++++++++++++++++++++++++++-
>>>> -
>>>>  libavcodec/pthread_frame.c     | 17 ++++++++++++++---
>>>>  tests/ref/fate/exif-image-tiff |  2 +-
>>>>  3 files changed, 42 insertions(+), 6 deletions(-)
>>>>
>>>> diff --git a/libavcodec/decode.c b/libavcodec/decode.c
>>>> index d031b1ca17..0ca5344ef5 100644
>>>> --- a/libavcodec/decode.c
>>>> +++ b/libavcodec/decode.c
>>>> @@ -57,6 +57,20 @@
>>>>  typedef struct DecodeContext {
>>>>      AVCodecInternal avci;
>>>>  
>>>> +    /**
>>>> +     * This is set to AV_FRAME_FLAG_KEY for decoders of intra-
>>>> only
>>>> formats
>>>> +     * (those whose codec descriptor has
>>>> AV_CODEC_PROP_INTRA_ONLY
>>>> set)
>>>> +     * to set the flag generically.
>>>> +     */
>>>> +    int intra_only_flag;
>>>> +
>>>> +    /**
>>>> +     * This is set to AV_PICTURE_TYPE_I for intra only video
>>>> decoders
>>>> +     * and to AV_PICTURE_TYPE_NONE for other decoders. It is
>>>> used to
>>>> set
>>>> +     * the AVFrame's pict_type before the decoder receives it.
>>>> +     */
>>>> +    enum AVPictureType initial_pict_type;
>>>
>>> Carrying this around as state seems unnecessary when a small static
>>> function could do the same?
>>>
>>
>> The aim of this is to avoid branches for every frame.
> 
> Checking a single value that will likely reside in cache once per frame
> is hardly expensive, especially when the branch predictor will predict
> it correctly.
> 
> When you carry state around you're carrying around multiple sources of
> truth, which is something that tends to cause bugs..
> 

Given that this is immutable after init, it is not really "state".

- Andreas
Tomas Härdin May 13, 2024, 5:02 p.m. UTC | #5
mån 2024-05-13 klockan 17:55 +0200 skrev Andreas Rheinhardt:
> Tomas Härdin:
> > mån 2024-05-13 klockan 10:54 +0200 skrev Andreas Rheinhardt:
> > > Tomas Härdin:
> > > > tor 2024-05-09 klockan 04:04 +0200 skrev Andreas Rheinhardt:
> > > > > This commit is the analog of
> > > > > 3f11eac75741888c7b2b6f93c458766f2613bab5
> > > > > for decoding: It sets the AV_FRAME_FLAG_KEY and (for video
> > > > > decoders)
> > > > > also pict_type to AV_PICTURE_TYPE_I. It furthermore stops
> > > > > setting
> > > > > audio frames as always being key frames -- it is wrong for
> > > > > e.g.
> > > > > TrueHD/MLP. The latter also affects TAK and DFPWM.
> > > > > 
> > > > > The change already improves output for several decoders where
> > > > > it has been forgotten to set e.g. pict_type like speedhq,
> > > > > wnv1
> > > > > or tiff. The latter is the reason for the change to the exif-
> > > > > image-
> > > > > tiff
> > > > > FATE test reference file.
> > > > > 
> > > > > Signed-off-by: Andreas Rheinhardt
> > > > > <andreas.rheinhardt@outlook.com>
> > > > > ---
> > > > >  libavcodec/decode.c            | 29
> > > > > +++++++++++++++++++++++++++-
> > > > > -
> > > > >  libavcodec/pthread_frame.c     | 17 ++++++++++++++---
> > > > >  tests/ref/fate/exif-image-tiff |  2 +-
> > > > >  3 files changed, 42 insertions(+), 6 deletions(-)
> > > > > 
> > > > > diff --git a/libavcodec/decode.c b/libavcodec/decode.c
> > > > > index d031b1ca17..0ca5344ef5 100644
> > > > > --- a/libavcodec/decode.c
> > > > > +++ b/libavcodec/decode.c
> > > > > @@ -57,6 +57,20 @@
> > > > >  typedef struct DecodeContext {
> > > > >      AVCodecInternal avci;
> > > > >  
> > > > > +    /**
> > > > > +     * This is set to AV_FRAME_FLAG_KEY for decoders of
> > > > > intra-
> > > > > only
> > > > > formats
> > > > > +     * (those whose codec descriptor has
> > > > > AV_CODEC_PROP_INTRA_ONLY
> > > > > set)
> > > > > +     * to set the flag generically.
> > > > > +     */
> > > > > +    int intra_only_flag;
> > > > > +
> > > > > +    /**
> > > > > +     * This is set to AV_PICTURE_TYPE_I for intra only video
> > > > > decoders
> > > > > +     * and to AV_PICTURE_TYPE_NONE for other decoders. It is
> > > > > used to
> > > > > set
> > > > > +     * the AVFrame's pict_type before the decoder receives
> > > > > it.
> > > > > +     */
> > > > > +    enum AVPictureType initial_pict_type;
> > > > 
> > > > Carrying this around as state seems unnecessary when a small
> > > > static
> > > > function could do the same?
> > > > 
> > > 
> > > The aim of this is to avoid branches for every frame.
> > 
> > Checking a single value that will likely reside in cache once per
> > frame
> > is hardly expensive, especially when the branch predictor will
> > predict
> > it correctly.
> > 
> > When you carry state around you're carrying around multiple sources
> > of
> > truth, which is something that tends to cause bugs..
> > 
> 
> Given that this is immutable after init, it is not really "state".

State tends to live in memory..

Perhaps this borders on bikeshedding, but I have said my peace and look
forward to cashing in accrued I-told-you-so's in the future should my
fears come to pass.

/Tomas
diff mbox series

Patch

diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index d031b1ca17..0ca5344ef5 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -57,6 +57,20 @@ 
 typedef struct DecodeContext {
     AVCodecInternal avci;
 
+    /**
+     * This is set to AV_FRAME_FLAG_KEY for decoders of intra-only formats
+     * (those whose codec descriptor has AV_CODEC_PROP_INTRA_ONLY set)
+     * to set the flag generically.
+     */
+    int intra_only_flag;
+
+    /**
+     * This is set to AV_PICTURE_TYPE_I for intra only video decoders
+     * and to AV_PICTURE_TYPE_NONE for other decoders. It is used to set
+     * the AVFrame's pict_type before the decoder receives it.
+     */
+    enum AVPictureType initial_pict_type;
+
     /* to prevent infinite loop on errors when draining */
     int nb_draining_errors;
 
@@ -382,6 +396,7 @@  static int discard_samples(AVCodecContext *avctx, AVFrame *frame, int64_t *disca
 static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame, int64_t *discarded_samples)
 {
     AVCodecInternal   *avci = avctx->internal;
+    DecodeContext     *dc = decode_ctx(avci);
     AVPacket     *const pkt = avci->in_pkt;
     const FFCodec *const codec = ffcodec(avctx->codec);
     int got_frame, consumed;
@@ -409,6 +424,8 @@  static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame,
     if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) {
         consumed = ff_thread_decode_frame(avctx, frame, &got_frame, pkt);
     } else {
+        frame->pict_type = dc->initial_pict_type;
+        frame->flags    |= dc->intra_only_flag;
         consumed = codec->cb.decode(avctx, frame, &got_frame, pkt);
 
         if (!(codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS))
@@ -597,6 +614,8 @@  static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
     av_assert0(!frame->buf[0]);
 
     if (codec->cb_type == FF_CODEC_CB_TYPE_RECEIVE_FRAME) {
+        frame->pict_type = dc->initial_pict_type;
+        frame->flags    |= dc->intra_only_flag;
         ret = codec->cb.receive_frame(avctx, frame);
         emms_c();
         if (!ret) {
@@ -626,8 +645,7 @@  static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
                 frame->width = avctx->width;
             if (!frame->height)
                 frame->height = avctx->height;
-        } else
-            frame->flags |= AV_FRAME_FLAG_KEY;
+        }
 
         ret = fill_frame_props(avctx, frame);
         if (ret < 0) {
@@ -1793,6 +1811,13 @@  int ff_decode_preinit(AVCodecContext *avctx)
     DecodeContext     *dc = decode_ctx(avci);
     int ret = 0;
 
+    dc->initial_pict_type = AV_PICTURE_TYPE_NONE;
+    if (avctx->codec_descriptor->props & AV_CODEC_PROP_INTRA_ONLY) {
+        dc->intra_only_flag = AV_FRAME_FLAG_KEY;
+        if (avctx->codec_type == AVMEDIA_TYPE_VIDEO)
+            dc->initial_pict_type = AV_PICTURE_TYPE_I;
+    }
+
     /* if the decoder init function was already called previously,
      * free the already allocated subtitle_header before overwriting it */
     av_freep(&avctx->subtitle_header);
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 67f09c1f48..982e4a64c5 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -22,13 +22,11 @@ 
  * @see doc/multithreading.txt
  */
 
-#include "config.h"
-
 #include <stdatomic.h>
-#include <stdint.h>
 
 #include "avcodec.h"
 #include "avcodec_internal.h"
+#include "codec_desc.h"
 #include "codec_internal.h"
 #include "decode.h"
 #include "hwaccel_internal.h"
@@ -108,6 +106,10 @@  typedef struct PerThreadContext {
     int hwaccel_threadsafe;
 
     atomic_int debug_threads;       ///< Set if the FF_DEBUG_THREADS option is set.
+
+    /// The following two fields have the same semantics as the DecodeContext field
+    int intra_only_flag;
+    enum AVPictureType initial_pict_type;
 } PerThreadContext;
 
 /**
@@ -220,6 +222,8 @@  static attribute_align_arg void *frame_worker_thread(void *arg)
 
         av_frame_unref(p->frame);
         p->got_frame = 0;
+        p->frame->pict_type = p->initial_pict_type;
+        p->frame->flags    |= p->intra_only_flag;
         p->result = codec->cb.decode(avctx, p->frame, &p->got_frame, p->avpkt);
 
         if ((p->result < 0 || !p->got_frame) && p->frame->buf[0])
@@ -763,6 +767,13 @@  static av_cold int init_thread(PerThreadContext *p, int *threads_to_free,
     AVCodecContext *copy;
     int err;
 
+    p->initial_pict_type = AV_PICTURE_TYPE_NONE;
+    if (avctx->codec_descriptor->props & AV_CODEC_PROP_INTRA_ONLY) {
+        p->intra_only_flag = AV_FRAME_FLAG_KEY;
+        if (avctx->codec_type == AVMEDIA_TYPE_VIDEO)
+            p->initial_pict_type = AV_PICTURE_TYPE_I;
+    }
+
     atomic_init(&p->state, STATE_INPUT_READY);
 
     copy = av_memdup(avctx, sizeof(*avctx));
diff --git a/tests/ref/fate/exif-image-tiff b/tests/ref/fate/exif-image-tiff
index 887c039df9..f5ff4dc16c 100644
--- a/tests/ref/fate/exif-image-tiff
+++ b/tests/ref/fate/exif-image-tiff
@@ -20,7 +20,7 @@  crop_left=0
 crop_right=0
 pix_fmt=rgb24
 sample_aspect_ratio=1:1
-pict_type=?
+pict_type=I
 interlaced_frame=0
 top_field_first=0
 repeat_pict=0