diff mbox series

[FFmpeg-devel] lavc: deprecate AV_CODEC_FLAG_DROPCHANGED

Message ID 20230709125746.8054-1-anton@khirnov.net
State New
Headers show
Series [FFmpeg-devel] lavc: deprecate AV_CODEC_FLAG_DROPCHANGED | expand

Checks

Context Check Description
andriy/configure_x86 warning Failed to apply patch
yinshiyou/configure_loongarch64 warning Failed to apply patch

Commit Message

Anton Khirnov July 9, 2023, 12:57 p.m. UTC
This decoding flag makes decoders drop all frames after a parameter
change, but what exactly constitutes a parameter change is not well
defined and will typically depend on the exact use case.
This functionality then does not belong in libavcodec, but rather in
user code
---
 doc/APIchanges             |  3 +++
 libavcodec/avcodec.c       |  2 ++
 libavcodec/avcodec.h       |  7 ++++---
 libavcodec/decode.c        | 11 +++++++++--
 libavcodec/internal.h      |  2 ++
 libavcodec/options_table.h |  2 ++
 libavcodec/version_major.h |  1 +
 7 files changed, 23 insertions(+), 5 deletions(-)

Comments

James Almer July 12, 2023, 12:42 p.m. UTC | #1
On 7/9/2023 9:57 AM, Anton Khirnov wrote:
> This decoding flag makes decoders drop all frames after a parameter
> change, but what exactly constitutes a parameter change is not well
> defined and will typically depend on the exact use case.
> This functionality then does not belong in libavcodec, but rather in
> user code
> ---
>   doc/APIchanges             |  3 +++
>   libavcodec/avcodec.c       |  2 ++
>   libavcodec/avcodec.h       |  7 ++++---
>   libavcodec/decode.c        | 11 +++++++++--
>   libavcodec/internal.h      |  2 ++
>   libavcodec/options_table.h |  2 ++
>   libavcodec/version_major.h |  1 +
>   7 files changed, 23 insertions(+), 5 deletions(-)
> 
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 0cda51fdee..6217502492 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09
>   
>   API changes, most recent first:
>   
> +2023-07-xx - xxxxxxxxxx - lavc 60 - avcodec.h
> +  Deprecate AV_CODEC_FLAG_DROPCHANGED without replacement.
> +
>   2023-07-xx - xxxxxxxxxx - lavu 58.15.100 - video_hint.h
>     Add AVVideoHint API.
>   
> diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
> index 8ccc610227..340abe830e 100644
> --- a/libavcodec/avcodec.c
> +++ b/libavcodec/avcodec.c
> @@ -456,7 +456,9 @@ av_cold int avcodec_close(AVCodecContext *avctx)
>   
>           av_bsf_free(&avci->bsf);
>   
> +#if FF_API_DROPCHANGED
>           av_channel_layout_uninit(&avci->initial_ch_layout);
> +#endif
>   
>   #if CONFIG_LCMS2
>           ff_icc_context_uninit(&avci->icc);
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index d17bdc360d..fe41ecc3c9 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -226,11 +226,15 @@ typedef struct RcOverride{
>    * Use qpel MC.
>    */
>   #define AV_CODEC_FLAG_QPEL            (1 <<  4)
> +#if FF_API_DROPCHANGED
>   /**
>    * Don't output frames whose parameters differ from first
>    * decoded frame in stream.
> + *
> + * @deprecated callers should implement this functionality in their own code
>    */
>   #define AV_CODEC_FLAG_DROPCHANGED     (1 <<  5)
> +#endif
>   /**
>    * Request the encoder to output reconstructed frames, i.e.\ frames that would
>    * be produced by decoding the encoded bistream. These frames may be retrieved
> @@ -2713,9 +2717,6 @@ int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
>    *                          no more output frames
>    * @retval AVERROR(EINVAL)  codec not opened, or it is an encoder without the
>    *                          @ref AV_CODEC_FLAG_RECON_FRAME flag enabled
> - * @retval AVERROR_INPUT_CHANGED current decoded frame has changed parameters with
> - *                          respect to first decoded frame. Applicable when flag
> - *                          AV_CODEC_FLAG_DROPCHANGED is set.
>    * @retval "other negative error code" legitimate decoding errors
>    */
>   int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);
> diff --git a/libavcodec/decode.c b/libavcodec/decode.c
> index 269633ce10..40eb7679ca 100644
> --- a/libavcodec/decode.c
> +++ b/libavcodec/decode.c
> @@ -740,7 +740,7 @@ fail:
>   int ff_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame)
>   {
>       AVCodecInternal *avci = avctx->internal;
> -    int ret, changed;
> +    int ret;
>   
>       if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
>           return AVERROR(EINVAL);
> @@ -770,6 +770,7 @@ FF_DISABLE_DEPRECATION_WARNINGS
>   FF_ENABLE_DEPRECATION_WARNINGS
>   #endif
>   
> +#if FF_API_DROPCHANGED
>       if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED) {
>   
>           if (avctx->frame_num == 1) {
> @@ -790,7 +791,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
>           }
>   
>           if (avctx->frame_num > 1) {
> -            changed = avci->initial_format != frame->format;
> +            int changed = avci->initial_format != frame->format;
>   
>               switch(avctx->codec_type) {
>               case AVMEDIA_TYPE_VIDEO:
> @@ -815,6 +816,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
>               }
>           }
>       }
> +#endif
>       return 0;
>   fail:
>       av_frame_unref(frame);
> @@ -1739,6 +1741,11 @@ int ff_decode_preinit(AVCodecContext *avctx)
>       if (ret < 0)
>           return ret;
>   
> +#if FF_API_DROPCHANGED
> +    if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED)
> +        av_log(avctx, AV_LOG_WARNING, "The dropchanged flag is deprecated.\n");
> +#endif
> +
>       return 0;
>   }
>   
> diff --git a/libavcodec/internal.h b/libavcodec/internal.h
> index 868dd46b48..4dce9f6fbb 100644
> --- a/libavcodec/internal.h
> +++ b/libavcodec/internal.h
> @@ -135,12 +135,14 @@ typedef struct AVCodecInternal {
>       AVFrame *buffer_frame;
>       int draining_done;
>   
> +#if FF_API_DROPCHANGED
>       /* used when avctx flag AV_CODEC_FLAG_DROPCHANGED is set */
>       int changed_frames_dropped;
>       int initial_format;
>       int initial_width, initial_height;
>       int initial_sample_rate;
>       AVChannelLayout initial_ch_layout;
> +#endif
>   
>   #if CONFIG_LCMS2
>       FFIccContext icc; /* used to read and write embedded ICC profiles */
> diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
> index f1a9729c0d..d1244bfc1a 100644
> --- a/libavcodec/options_table.h
> +++ b/libavcodec/options_table.h
> @@ -72,7 +72,9 @@ static const AVOption avcodec_options[] = {
>   {"ilme", "interlaced motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_INTERLACED_ME }, INT_MIN, INT_MAX, V|E, "flags"},
>   {"cgop", "closed GOP", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_CLOSED_GOP }, INT_MIN, INT_MAX, V|E, "flags"},
>   {"output_corrupt", "Output even potentially corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_OUTPUT_CORRUPT }, INT_MIN, INT_MAX, V|D, "flags"},
> +#if FF_API_DROPCHANGED
>   {"drop_changed", "Drop frames whose parameters differ from first decoded frame", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_DROPCHANGED }, INT_MIN, INT_MAX, A|V|D, "flags"},

Missing the deprecated AVOption flag.

> +#endif
>   {"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT}, 0, UINT_MAX, V|A|E|D|S, "flags2"},
>   {"fast", "allow non-spec-compliant speedup tricks", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_FAST }, INT_MIN, INT_MAX, V|E, "flags2"},
>   {"noout", "skip bitstream encoding", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_NO_OUTPUT }, INT_MIN, INT_MAX, V|E, "flags2"},
> diff --git a/libavcodec/version_major.h b/libavcodec/version_major.h
> index 2f5138d079..95c5aec0c5 100644
> --- a/libavcodec/version_major.h
> +++ b/libavcodec/version_major.h
> @@ -48,6 +48,7 @@
>   #define FF_API_SLICE_OFFSET        (LIBAVCODEC_VERSION_MAJOR < 61)
>   #define FF_API_SUBFRAMES           (LIBAVCODEC_VERSION_MAJOR < 61)
>   #define FF_API_TICKS_PER_FRAME     (LIBAVCODEC_VERSION_MAJOR < 61)
> +#define FF_API_DROPCHANGED         (LIBAVCODEC_VERSION_MAJOR < 61)
>   
>   // reminder to remove CrystalHD decoders on next major bump
>   #define FF_CODEC_CRYSTAL_HD        (LIBAVCODEC_VERSION_MAJOR < 61)

LGTM, and good idea.
Gyan Doshi July 12, 2023, 1:14 p.m. UTC | #2
On 2023-07-12 06:12 pm, James Almer wrote:
> On 7/9/2023 9:57 AM, Anton Khirnov wrote:
>> This decoding flag makes decoders drop all frames after a parameter
>> change, but what exactly constitutes a parameter change is not well
>> defined and will typically depend on the exact use case.
>> This functionality then does not belong in libavcodec, but rather in
>> user code

NAK.

The applicable parameters are well defined as set by the implementation.
They are whatever leads to a change in the size of the decoded frame 
payload or the layout/semantics of the elemental unit in a decoded 
frame, so width, height, pixel format, sample format/size, interleaving..etc

Regards,
Gyan
James Almer July 12, 2023, 1:21 p.m. UTC | #3
On 7/12/2023 10:14 AM, Gyan Doshi wrote:
> 
> 
> On 2023-07-12 06:12 pm, James Almer wrote:
>> On 7/9/2023 9:57 AM, Anton Khirnov wrote:
>>> This decoding flag makes decoders drop all frames after a parameter
>>> change, but what exactly constitutes a parameter change is not well
>>> defined and will typically depend on the exact use case.
>>> This functionality then does not belong in libavcodec, but rather in
>>> user code
> 
> NAK.
> 
> The applicable parameters are well defined as set by the implementation.

The implementation defined its own interpretation of what constitutes a 
parameter change, yes, but callers may have their own interpretations 
too. The result is they either don't set this flag, or set it but still 
manually check every frame for other parameters.

> They are whatever leads to a change in the size of the decoded frame 
> payload or the layout/semantics of the elemental unit in a decoded 
> frame, so width, height, pixel format, sample format/size, 
> interleaving..etc

You give pixel format as an example, which would include a change from 
yuv to a yuvj pseudo format. What about decoders that export yuv + 
color_range mpeg and then yuv + color_range jpeg? This implementation 
will not consider that a parameter change, despite being practically the 
same scenario.
Once the yuvj formats are removed, this will be true for all decoders. 
And suddenly starting to check for color_range would be a change in 
implementation here.

This is definitely something that should be left to the caller. They get 
a frame out of the decoder, they decide if they want to drop it.

> 
> Regards,
> Gyan
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Gyan Doshi July 12, 2023, 1:31 p.m. UTC | #4
On 2023-07-12 06:51 pm, James Almer wrote:
> On 7/12/2023 10:14 AM, Gyan Doshi wrote:
>>
>>
>> On 2023-07-12 06:12 pm, James Almer wrote:
>>> On 7/9/2023 9:57 AM, Anton Khirnov wrote:
>>>> This decoding flag makes decoders drop all frames after a parameter
>>>> change, but what exactly constitutes a parameter change is not well
>>>> defined and will typically depend on the exact use case.
>>>> This functionality then does not belong in libavcodec, but rather in
>>>> user code
>>
>> NAK.
>>
>> The applicable parameters are well defined as set by the implementation.
>
> The implementation defined its own interpretation of what constitutes 
> a parameter change, yes, but callers may have their own 
> interpretations too. The result is they either don't set this flag, or 
> set it but still manually check every frame for other parameters.
>
>> They are whatever leads to a change in the size of the decoded frame 
>> payload or the layout/semantics of the elemental unit in a decoded 
>> frame, so width, height, pixel format, sample format/size, 
>> interleaving..etc
>
> You give pixel format as an example, which would include a change from 
> yuv to a yuvj pseudo format. What about decoders that export yuv + 
> color_range mpeg and then yuv + color_range jpeg? This implementation 
> will not consider that a parameter change, despite being practically 
> the same scenario.
> Once the yuvj formats are removed, this will be true for all decoders. 
> And suddenly starting to check for color_range would be a change in 
> implementation here.
>
> This is definitely something that should be left to the caller. They 
> get a frame out of the decoder, they decide if they want to drop it.

They can still do that. Don't set the flag (default) and check 
manually.  Keeping the flag in lavc doesn't prevent callers from 
inserting their own gate.

The color range was not part of the practical problem I was solving at 
the time. At best, that calls for converting this from a bitmask in 
flags to a dedicated parameter with bitmask per attribute.

Regards,
Gyan
Anton Khirnov July 12, 2023, 1:44 p.m. UTC | #5
Quoting Gyan Doshi (2023-07-12 15:31:57)
> 
> 
> On 2023-07-12 06:51 pm, James Almer wrote:
> > On 7/12/2023 10:14 AM, Gyan Doshi wrote:
> >>
> >>
> >> On 2023-07-12 06:12 pm, James Almer wrote:
> >>> On 7/9/2023 9:57 AM, Anton Khirnov wrote:
> >>>> This decoding flag makes decoders drop all frames after a parameter
> >>>> change, but what exactly constitutes a parameter change is not well
> >>>> defined and will typically depend on the exact use case.
> >>>> This functionality then does not belong in libavcodec, but rather in
> >>>> user code
> >>
> >> NAK.
> >>
> >> The applicable parameters are well defined as set by the implementation.
> >
> > The implementation defined its own interpretation of what constitutes 
> > a parameter change, yes, but callers may have their own 
> > interpretations too. The result is they either don't set this flag, or 
> > set it but still manually check every frame for other parameters.
> >
> >> They are whatever leads to a change in the size of the decoded frame 
> >> payload or the layout/semantics of the elemental unit in a decoded 
> >> frame, so width, height, pixel format, sample format/size, 
> >> interleaving..etc
> >
> > You give pixel format as an example, which would include a change from 
> > yuv to a yuvj pseudo format. What about decoders that export yuv + 
> > color_range mpeg and then yuv + color_range jpeg? This implementation 
> > will not consider that a parameter change, despite being practically 
> > the same scenario.
> > Once the yuvj formats are removed, this will be true for all decoders. 
> > And suddenly starting to check for color_range would be a change in 
> > implementation here.
> >
> > This is definitely something that should be left to the caller. They 
> > get a frame out of the decoder, they decide if they want to drop it.
> 
> They can still do that. Don't set the flag (default) and check 
> manually.  Keeping the flag in lavc doesn't prevent callers from 
> inserting their own gate.

The point is that what this code considers a parameter change is
entirely arbitrary.

Why does it not consider any of the colorspace parameters? Or
interlacing, cropping, display transform matrix, or any of the other
AVFrame fields or side data we might add in the future that someone
migth consider a parameter change in their use case.

I see no reason why libavcodec should prefer this specific set of fields
over any other.

> 
> The color range was not part of the practical problem I was solving at 
> the time. At best, that calls for converting this from a bitmask in 
> flags to a dedicated parameter with bitmask per attribute.

Libavcodec is not the place for solving your specific practical
problems, unless it can not be done outside of it. In this specific
case, it can be done very easily in the caller and so does not belong in
libavcodec.
Anton Khirnov July 13, 2023, 10:56 a.m. UTC | #6
If nobody has further comments, I intend to push the patch tomorrow.
Gyan Doshi July 13, 2023, 7:20 p.m. UTC | #7
On 2023-07-12 07:14 pm, Anton Khirnov wrote:
> Quoting Gyan Doshi (2023-07-12 15:31:57)
>>
>> On 2023-07-12 06:51 pm, James Almer wrote:
>>> On 7/12/2023 10:14 AM, Gyan Doshi wrote:
>>>>
>>>> On 2023-07-12 06:12 pm, James Almer wrote:
>>>>> On 7/9/2023 9:57 AM, Anton Khirnov wrote:
>>>>>> This decoding flag makes decoders drop all frames after a parameter
>>>>>> change, but what exactly constitutes a parameter change is not well
>>>>>> defined and will typically depend on the exact use case.
>>>>>> This functionality then does not belong in libavcodec, but rather in
>>>>>> user code
>>>> NAK.
>>>>
>>>> The applicable parameters are well defined as set by the implementation.
>>> The implementation defined its own interpretation of what constitutes
>>> a parameter change, yes, but callers may have their own
>>> interpretations too. The result is they either don't set this flag, or
>>> set it but still manually check every frame for other parameters.
>>>
>>>> They are whatever leads to a change in the size of the decoded frame
>>>> payload or the layout/semantics of the elemental unit in a decoded
>>>> frame, so width, height, pixel format, sample format/size,
>>>> interleaving..etc
>>> You give pixel format as an example, which would include a change from
>>> yuv to a yuvj pseudo format. What about decoders that export yuv +
>>> color_range mpeg and then yuv + color_range jpeg? This implementation
>>> will not consider that a parameter change, despite being practically
>>> the same scenario.
>>> Once the yuvj formats are removed, this will be true for all decoders.
>>> And suddenly starting to check for color_range would be a change in
>>> implementation here.
>>>
>>> This is definitely something that should be left to the caller. They
>>> get a frame out of the decoder, they decide if they want to drop it.
>> They can still do that. Don't set the flag (default) and check
>> manually.  Keeping the flag in lavc doesn't prevent callers from
>> inserting their own gate.
> The point is that what this code considers a parameter change is
> entirely arbitrary.
>
> Why does it not consider any of the colorspace parameters? Or
> interlacing, cropping, display transform matrix, or any of the other
> AVFrame fields or side data we might add in the future that someone
> migth consider a parameter change in their use case.

This flag considers the changes to AVframe raster data that can lead to 
out of bounds read/writes or mangling of that data.
All the side data add-ons are irrelevant.

When is major bump to 61 expected?

Regards,
Gyan
Anton Khirnov July 13, 2023, 8:57 p.m. UTC | #8
Quoting Gyan Doshi (2023-07-13 21:20:32)
> 
> 
> On 2023-07-12 07:14 pm, Anton Khirnov wrote:
> > Quoting Gyan Doshi (2023-07-12 15:31:57)
> >>
> >> On 2023-07-12 06:51 pm, James Almer wrote:
> >>> On 7/12/2023 10:14 AM, Gyan Doshi wrote:
> >>>>
> >>>> On 2023-07-12 06:12 pm, James Almer wrote:
> >>>>> On 7/9/2023 9:57 AM, Anton Khirnov wrote:
> >>>>>> This decoding flag makes decoders drop all frames after a parameter
> >>>>>> change, but what exactly constitutes a parameter change is not well
> >>>>>> defined and will typically depend on the exact use case.
> >>>>>> This functionality then does not belong in libavcodec, but rather in
> >>>>>> user code
> >>>> NAK.
> >>>>
> >>>> The applicable parameters are well defined as set by the implementation.
> >>> The implementation defined its own interpretation of what constitutes
> >>> a parameter change, yes, but callers may have their own
> >>> interpretations too. The result is they either don't set this flag, or
> >>> set it but still manually check every frame for other parameters.
> >>>
> >>>> They are whatever leads to a change in the size of the decoded frame
> >>>> payload or the layout/semantics of the elemental unit in a decoded
> >>>> frame, so width, height, pixel format, sample format/size,
> >>>> interleaving..etc
> >>> You give pixel format as an example, which would include a change from
> >>> yuv to a yuvj pseudo format. What about decoders that export yuv +
> >>> color_range mpeg and then yuv + color_range jpeg? This implementation
> >>> will not consider that a parameter change, despite being practically
> >>> the same scenario.
> >>> Once the yuvj formats are removed, this will be true for all decoders.
> >>> And suddenly starting to check for color_range would be a change in
> >>> implementation here.
> >>>
> >>> This is definitely something that should be left to the caller. They
> >>> get a frame out of the decoder, they decide if they want to drop it.
> >> They can still do that. Don't set the flag (default) and check
> >> manually.  Keeping the flag in lavc doesn't prevent callers from
> >> inserting their own gate.
> > The point is that what this code considers a parameter change is
> > entirely arbitrary.
> >
> > Why does it not consider any of the colorspace parameters? Or
> > interlacing, cropping, display transform matrix, or any of the other
> > AVFrame fields or side data we might add in the future that someone
> > migth consider a parameter change in their use case.
> 
> This flag considers the changes to AVframe raster data that can lead to 
> out of bounds read/writes or mangling of that data.
> All the side data add-ons are irrelevant.

That is inconsistent with its handling of
* audio sample rate (should be ignored)
* audio channel layouts (only channel count should be considered)
* YUVJ formats as James mentioned, possibly also some others

And however that may be, my main point still stands: I see no good
reason why this should be handled in libavcodec rather than in the
caller.

> When is major bump to 61 expected?

Most likely in 7.0 in early 2024, but the 61 check in the patch is a
placeholder - typically deprecated APIs are removed after they've been
deprecated for a longer time. So expect it to actually happen in major
62, probably in early 2025.
diff mbox series

Patch

diff --git a/doc/APIchanges b/doc/APIchanges
index 0cda51fdee..6217502492 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@  The last version increases of all libraries were on 2023-02-09
 
 API changes, most recent first:
 
+2023-07-xx - xxxxxxxxxx - lavc 60 - avcodec.h
+  Deprecate AV_CODEC_FLAG_DROPCHANGED without replacement.
+
 2023-07-xx - xxxxxxxxxx - lavu 58.15.100 - video_hint.h
   Add AVVideoHint API.
 
diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
index 8ccc610227..340abe830e 100644
--- a/libavcodec/avcodec.c
+++ b/libavcodec/avcodec.c
@@ -456,7 +456,9 @@  av_cold int avcodec_close(AVCodecContext *avctx)
 
         av_bsf_free(&avci->bsf);
 
+#if FF_API_DROPCHANGED
         av_channel_layout_uninit(&avci->initial_ch_layout);
+#endif
 
 #if CONFIG_LCMS2
         ff_icc_context_uninit(&avci->icc);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index d17bdc360d..fe41ecc3c9 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -226,11 +226,15 @@  typedef struct RcOverride{
  * Use qpel MC.
  */
 #define AV_CODEC_FLAG_QPEL            (1 <<  4)
+#if FF_API_DROPCHANGED
 /**
  * Don't output frames whose parameters differ from first
  * decoded frame in stream.
+ *
+ * @deprecated callers should implement this functionality in their own code
  */
 #define AV_CODEC_FLAG_DROPCHANGED     (1 <<  5)
+#endif
 /**
  * Request the encoder to output reconstructed frames, i.e.\ frames that would
  * be produced by decoding the encoded bistream. These frames may be retrieved
@@ -2713,9 +2717,6 @@  int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
  *                          no more output frames
  * @retval AVERROR(EINVAL)  codec not opened, or it is an encoder without the
  *                          @ref AV_CODEC_FLAG_RECON_FRAME flag enabled
- * @retval AVERROR_INPUT_CHANGED current decoded frame has changed parameters with
- *                          respect to first decoded frame. Applicable when flag
- *                          AV_CODEC_FLAG_DROPCHANGED is set.
  * @retval "other negative error code" legitimate decoding errors
  */
 int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 269633ce10..40eb7679ca 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -740,7 +740,7 @@  fail:
 int ff_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame)
 {
     AVCodecInternal *avci = avctx->internal;
-    int ret, changed;
+    int ret;
 
     if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
         return AVERROR(EINVAL);
@@ -770,6 +770,7 @@  FF_DISABLE_DEPRECATION_WARNINGS
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
 
+#if FF_API_DROPCHANGED
     if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED) {
 
         if (avctx->frame_num == 1) {
@@ -790,7 +791,7 @@  FF_ENABLE_DEPRECATION_WARNINGS
         }
 
         if (avctx->frame_num > 1) {
-            changed = avci->initial_format != frame->format;
+            int changed = avci->initial_format != frame->format;
 
             switch(avctx->codec_type) {
             case AVMEDIA_TYPE_VIDEO:
@@ -815,6 +816,7 @@  FF_ENABLE_DEPRECATION_WARNINGS
             }
         }
     }
+#endif
     return 0;
 fail:
     av_frame_unref(frame);
@@ -1739,6 +1741,11 @@  int ff_decode_preinit(AVCodecContext *avctx)
     if (ret < 0)
         return ret;
 
+#if FF_API_DROPCHANGED
+    if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED)
+        av_log(avctx, AV_LOG_WARNING, "The dropchanged flag is deprecated.\n");
+#endif
+
     return 0;
 }
 
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 868dd46b48..4dce9f6fbb 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -135,12 +135,14 @@  typedef struct AVCodecInternal {
     AVFrame *buffer_frame;
     int draining_done;
 
+#if FF_API_DROPCHANGED
     /* used when avctx flag AV_CODEC_FLAG_DROPCHANGED is set */
     int changed_frames_dropped;
     int initial_format;
     int initial_width, initial_height;
     int initial_sample_rate;
     AVChannelLayout initial_ch_layout;
+#endif
 
 #if CONFIG_LCMS2
     FFIccContext icc; /* used to read and write embedded ICC profiles */
diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
index f1a9729c0d..d1244bfc1a 100644
--- a/libavcodec/options_table.h
+++ b/libavcodec/options_table.h
@@ -72,7 +72,9 @@  static const AVOption avcodec_options[] = {
 {"ilme", "interlaced motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_INTERLACED_ME }, INT_MIN, INT_MAX, V|E, "flags"},
 {"cgop", "closed GOP", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_CLOSED_GOP }, INT_MIN, INT_MAX, V|E, "flags"},
 {"output_corrupt", "Output even potentially corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_OUTPUT_CORRUPT }, INT_MIN, INT_MAX, V|D, "flags"},
+#if FF_API_DROPCHANGED
 {"drop_changed", "Drop frames whose parameters differ from first decoded frame", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_DROPCHANGED }, INT_MIN, INT_MAX, A|V|D, "flags"},
+#endif
 {"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT}, 0, UINT_MAX, V|A|E|D|S, "flags2"},
 {"fast", "allow non-spec-compliant speedup tricks", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_FAST }, INT_MIN, INT_MAX, V|E, "flags2"},
 {"noout", "skip bitstream encoding", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_NO_OUTPUT }, INT_MIN, INT_MAX, V|E, "flags2"},
diff --git a/libavcodec/version_major.h b/libavcodec/version_major.h
index 2f5138d079..95c5aec0c5 100644
--- a/libavcodec/version_major.h
+++ b/libavcodec/version_major.h
@@ -48,6 +48,7 @@ 
 #define FF_API_SLICE_OFFSET        (LIBAVCODEC_VERSION_MAJOR < 61)
 #define FF_API_SUBFRAMES           (LIBAVCODEC_VERSION_MAJOR < 61)
 #define FF_API_TICKS_PER_FRAME     (LIBAVCODEC_VERSION_MAJOR < 61)
+#define FF_API_DROPCHANGED         (LIBAVCODEC_VERSION_MAJOR < 61)
 
 // reminder to remove CrystalHD decoders on next major bump
 #define FF_CODEC_CRYSTAL_HD        (LIBAVCODEC_VERSION_MAJOR < 61)