diff mbox series

[FFmpeg-devel,3/3] avformat: deprecate muxing uncoded frames

Message ID 20200405233824.29682-3-cus@passwd.hu
State New
Headers show
Series [FFmpeg-devel,1/3] avdevice/xv: change codec to wrapped avframe | expand

Checks

Context Check Description
andriy/ffmpeg-patchwork success Make fate finished

Commit Message

Marton Balint April 5, 2020, 11:38 p.m. UTC
The same goal can be achieved using the WRAPPED_AVFRAME codec with the existing
API.

Signed-off-by: Marton Balint <cus@passwd.hu>
---
 doc/APIchanges                   |  4 ++++
 libavdevice/alsa_enc.c           |  4 ++++
 libavdevice/opengl_enc.c         |  4 ++++
 libavdevice/pulse_audio_enc.c    |  4 ++++
 libavdevice/version.h            |  4 ++--
 libavdevice/xv.c                 |  4 ++++
 libavformat/avformat.h           |  7 +++++++
 libavformat/internal.h           |  2 ++
 libavformat/mux.c                | 16 ++++++++++++++++
 libavformat/uncodedframecrcenc.c |  6 ++++++
 libavformat/version.h            |  6 +++++-
 11 files changed, 58 insertions(+), 3 deletions(-)

Comments

Nicolas George April 6, 2020, 12:58 p.m. UTC | #1
Marton Balint (12020-04-06):
> The same goal can be achieved using the WRAPPED_AVFRAME codec with the existing
> API.

These two APIs are somewhat redundant, but we need to discuss which one
we want to keep.

WRAPPED_AVFRAME is nice because it goes through the normal code path,
and therefore requires no exception. But on the other hand, it requires
many allocations and de-allocations, which is not good since the purpose
of these API was to be more efficient: if the application has a frame,
which is the most likely, it's more efficient to just pass it. And it's
also simpler for the application, less code, less bugs, less
maintenance.

My opinion: merge the two features, keep the simpler code when the two
overlap:

- Keep the WRAPPED_AVFRAME codec and its encoder/decoder pair, for when
  generic code expects an AVPacket.

- For muxers implementations, keep the write_uncoded_frame callback,
  it's simpler. If a packet with WRAPPED_AVFRAME arrives, have the
  framework de-wrap the frame and call write_uncoded_frame.

- Let applications give uncoded unwrapped frames directly. It's simpler,
  it's more efficient, it's more type-safe.

- Possibly later, introduce the symmetric read_uncoded_frame callback.

> 
> Signed-off-by: Marton Balint <cus@passwd.hu>
> ---
>  doc/APIchanges                   |  4 ++++

>  libavdevice/alsa_enc.c           |  4 ++++

Any way, I don't think we should deprecate something when we have not
yet moved our code to its replacement. You can count on me for porting
ALSA, when we have decided in which direction we go.

>  libavdevice/opengl_enc.c         |  4 ++++
>  libavdevice/pulse_audio_enc.c    |  4 ++++
>  libavdevice/version.h            |  4 ++--
>  libavdevice/xv.c                 |  4 ++++
>  libavformat/avformat.h           |  7 +++++++
>  libavformat/internal.h           |  2 ++
>  libavformat/mux.c                | 16 ++++++++++++++++
>  libavformat/uncodedframecrcenc.c |  6 ++++++
>  libavformat/version.h            |  6 +++++-
>  11 files changed, 58 insertions(+), 3 deletions(-)

Regards,
Marton Balint April 11, 2020, 6:55 p.m. UTC | #2
On Mon, 6 Apr 2020, Nicolas George wrote:

> Marton Balint (12020-04-06):
>> The same goal can be achieved using the WRAPPED_AVFRAME codec with the existing
>> API.
>
> These two APIs are somewhat redundant, but we need to discuss which one
> we want to keep.
>
> WRAPPED_AVFRAME is nice because it goes through the normal code path,
> and therefore requires no exception. But on the other hand, it requires
> many allocations and de-allocations, which is not good since the purpose
> of these API was to be more efficient: if the application has a frame,
> which is the most likely, it's more efficient to just pass it. And it's
> also simpler for the application, less code, less bugs, less
> maintenance.

The extra allocations and deallocations are barely measurable. So far 
uncoded_frame was used for realtime outputs. So you get, I don't know 100 
packets/frames per second? Allocating those is peanuts, and I have to 
stress that you are not allocating the data, just the AVFrame struct.

I'd also argue if it is simple for the application. Might be for some 
specific use cases, certainly not for e.g. ffmpeg.c or any other 
application which tries to support multiple output formats. Maybe it is no 
accident that I am not aware of any project on the internet who picked up 
using this API. Are you?

Maintenance for *us* is significant, see the mux.c patches Andreas sent to 
patch the various bugs caused by exceptions in the muxing code. And his 
preferred solution is to wrap the frame in an AVPacket where the 
destructor frees the AVFrame. Just like AVCODEC_ID_WRAPPED_FRAME does it.

>
> My opinion: merge the two features, keep the simpler code when the two
> overlap:
>
> - Keep the WRAPPED_AVFRAME codec and its encoder/decoder pair, for when
>  generic code expects an AVPacket.
>
> - For muxers implementations, keep the write_uncoded_frame callback,
>  it's simpler. If a packet with WRAPPED_AVFRAME arrives, have the
>  framework de-wrap the frame and call write_uncoded_frame.
>
> - Let applications give uncoded unwrapped frames directly. It's simpler,
>  it's more efficient, it's more type-safe.
>
> - Possibly later, introduce the symmetric read_uncoded_frame callback.

Sorry, I don't see the benefits of keeping the API, I only see the huge 
maintenance burden our our part. I'd just drop it at the next bump.

[...]

>>  libavdevice/alsa_enc.c           |  4 ++++
>
> Any way, I don't think we should deprecate something when we have not
> yet moved our code to its replacement. You can count on me for porting
> ALSA, when we have decided in which direction we go.
>

IMHO writing uncoded frame for pulse/alsa audio is pointless. It does not 
support planar, and the performance gain (especially for realtime output) 
is so insignificant, it does not worth maintaining such a feature.

Regards,
Marton
Nicolas George April 14, 2020, 1:26 p.m. UTC | #3
Marton Balint (12020-04-11):
> The extra allocations and deallocations are barely measurable. So far
> uncoded_frame was used for realtime outputs. So you get, I don't know 100
> packets/frames per second? Allocating those is peanuts, and I have to stress
> that you are not allocating the data, just the AVFrame struct.

Dynamic allocations are expensive. A hundred per second, multiplied by
maybe ten or a thousand for a project that handles several clients
simultaneously, that may make the difference.

But I grant you, there are already a lot of allocations, especially if
interleaving of streams is in action.

> I'd also argue if it is simple for the application. Might be for some
> specific use cases, certainly not for e.g. ffmpeg.c or any other application
> which tries to support multiple output formats. Maybe it is no accident that
> I am not aware of any project on the internet who picked up using this API.
> Are you?

I use it in a few of my projects, at least.

> Maintenance for *us* is significant, see the mux.c patches Andreas sent to
> patch the various bugs caused by exceptions in the muxing code. And his
> preferred solution is to wrap the frame in an AVPacket where the destructor
> frees the AVFrame. Just like AVCODEC_ID_WRAPPED_FRAME does it.

Yes, I remembered these issues had to be fixed when designed uncoded
frames.

> Sorry, I don't see the benefits of keeping the API, I only see the huge
> maintenance burden our our part. I'd just drop it at the next bump.

After a closer look, I say this:

For the maintenance burden of mux.c, go ahead, remove everything related
to uncoded frame. In this part of code, uncoded frames and wrapped
frames are the same thing, just implemented differently. The wrapped
frame implementation is cleaner, so let us choose this one.

But in that case, av_write_uncoded_frame() just becomes an utility
function that does wrapped_avframe_encode() and av_write_frame(). It
makes writing applications easier: let us keep it that way. Utility
functions are not maintenance burden.

And at the other end, when calling output format callbacks, the handling
for write_uncoded_frame() is six lines of leaf code. We can keep it if
it makes decoders simpler.

Which leads me to an actual proposition:

Rework your patch to clean up wrapped frames, but leave alone the bits
about uncoded frames that are not in the way: they will be broken, let
them be. When you post your patch, I will try to fix them without
getting in the way. And then we cans discuss with something practical
under our eyes.

> IMHO writing uncoded frame for pulse/alsa audio is pointless. It does not
> support planar, and the performance gain (especially for realtime output) is
> so insignificant, it does not worth maintaining such a feature.

Our ALSA code does not, but ALSA itself supports planar formats, and
adding it to our code is quite easy.

Also, please remember that real-time device exist on machines with very
constrained hardware too.

Regards,
diff mbox series

Patch

diff --git a/doc/APIchanges b/doc/APIchanges
index f1d7eac2ee..57d4fdc609 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -15,6 +15,10 @@  libavutil:     2017-10-21
 
 API changes, most recent first:
 
+2020-04-xx - xxxxxxxxxx - lavf 58.43.100 - avformat.h
+  Deprecate av_interleaved_write_uncoded_frame(), av_write_uncoded_frame() and
+  av_write_uncoded_frame_query().
+
 2020-03-29 - xxxxxxxxxx - lavf 58.42.100 - avformat.h
   av_read_frame() now guarantees to handle uninitialized input packets
   and to return refcounted packets on success.
diff --git a/libavdevice/alsa_enc.c b/libavdevice/alsa_enc.c
index 1a6d01e3b1..80c9c509e2 100644
--- a/libavdevice/alsa_enc.c
+++ b/libavdevice/alsa_enc.c
@@ -116,6 +116,7 @@  static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt)
     return 0;
 }
 
+#if FF_API_UNCODED_FRAME
 static int audio_write_frame(AVFormatContext *s1, int stream_index,
                              AVFrame **frame, unsigned flags)
 {
@@ -133,6 +134,7 @@  static int audio_write_frame(AVFormatContext *s1, int stream_index,
     pkt.duration = (*frame)->pkt_duration;
     return audio_write_packet(s1, &pkt);
 }
+#endif
 
 static void
 audio_get_output_timestamp(AVFormatContext *s1, int stream,
@@ -166,7 +168,9 @@  AVOutputFormat ff_alsa_muxer = {
     .write_header   = audio_write_header,
     .write_packet   = audio_write_packet,
     .write_trailer  = ff_alsa_close,
+#if FF_API_UNCODED_FRAME
     .write_uncoded_frame = audio_write_frame,
+#endif
     .get_device_list = audio_get_device_list,
     .get_output_timestamp = audio_get_output_timestamp,
     .flags          = AVFMT_NOFILE,
diff --git a/libavdevice/opengl_enc.c b/libavdevice/opengl_enc.c
index b8bc46ebb5..a829f9ccb2 100644
--- a/libavdevice/opengl_enc.c
+++ b/libavdevice/opengl_enc.c
@@ -1225,6 +1225,7 @@  static int opengl_write_packet(AVFormatContext *h, AVPacket *pkt)
     return opengl_draw(h, frame, 0);
 }
 
+#if FF_API_UNCODED_FRAME
 static int opengl_write_frame(AVFormatContext *h, int stream_index,
                               AVFrame **frame, unsigned flags)
 {
@@ -1232,6 +1233,7 @@  static int opengl_write_frame(AVFormatContext *h, int stream_index,
         return 0;
     return opengl_draw(h, *frame, 0);
 }
+#endif
 
 #define OFFSET(x) offsetof(OpenGLContext, x)
 #define ENC AV_OPT_FLAG_ENCODING_PARAM
@@ -1259,7 +1261,9 @@  AVOutputFormat ff_opengl_muxer = {
     .video_codec    = AV_CODEC_ID_WRAPPED_AVFRAME,
     .write_header   = opengl_write_header,
     .write_packet   = opengl_write_packet,
+#if FF_API_UNCODED_FRAME
     .write_uncoded_frame = opengl_write_frame,
+#endif
     .write_trailer  = opengl_write_trailer,
     .control_message = opengl_control_message,
     .flags          = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
diff --git a/libavdevice/pulse_audio_enc.c b/libavdevice/pulse_audio_enc.c
index e0a631b227..0b56984ec4 100644
--- a/libavdevice/pulse_audio_enc.c
+++ b/libavdevice/pulse_audio_enc.c
@@ -670,6 +670,7 @@  static int pulse_write_packet(AVFormatContext *h, AVPacket *pkt)
     return AVERROR_EXTERNAL;
 }
 
+#if FF_API_UNCODED_FRAME
 static int pulse_write_frame(AVFormatContext *h, int stream_index,
                              AVFrame **frame, unsigned flags)
 {
@@ -686,6 +687,7 @@  static int pulse_write_frame(AVFormatContext *h, int stream_index,
     pkt.duration = (*frame)->pkt_duration;
     return pulse_write_packet(h, &pkt);
 }
+#endif
 
 
 static void pulse_get_output_timestamp(AVFormatContext *h, int stream, int64_t *dts, int64_t *wall)
@@ -786,7 +788,9 @@  AVOutputFormat ff_pulse_muxer = {
     .video_codec          = AV_CODEC_ID_NONE,
     .write_header         = pulse_write_header,
     .write_packet         = pulse_write_packet,
+#if FF_API_UNCODED_FRAME
     .write_uncoded_frame  = pulse_write_frame,
+#endif
     .write_trailer        = pulse_write_trailer,
     .get_output_timestamp = pulse_get_output_timestamp,
     .get_device_list      = pulse_get_device_list,
diff --git a/libavdevice/version.h b/libavdevice/version.h
index 10717564e9..9ee3d3db4a 100644
--- a/libavdevice/version.h
+++ b/libavdevice/version.h
@@ -28,8 +28,8 @@ 
 #include "libavutil/version.h"
 
 #define LIBAVDEVICE_VERSION_MAJOR  58
-#define LIBAVDEVICE_VERSION_MINOR   9
-#define LIBAVDEVICE_VERSION_MICRO 103
+#define LIBAVDEVICE_VERSION_MINOR  10
+#define LIBAVDEVICE_VERSION_MICRO 100
 
 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
                                                LIBAVDEVICE_VERSION_MINOR, \
diff --git a/libavdevice/xv.c b/libavdevice/xv.c
index 2c5f1a4432..67e1530199 100644
--- a/libavdevice/xv.c
+++ b/libavdevice/xv.c
@@ -325,6 +325,7 @@  static int xv_write_packet(AVFormatContext *s, AVPacket *pkt)
     return write_picture(s, frame->data, frame->linesize);
 }
 
+#if FF_API_UNCODED_FRAME
 static int xv_write_frame(AVFormatContext *s, int stream_index, AVFrame **frame,
                           unsigned flags)
 {
@@ -333,6 +334,7 @@  static int xv_write_frame(AVFormatContext *s, int stream_index, AVFrame **frame,
         return 0;
     return write_picture(s, (*frame)->data, (*frame)->linesize);
 }
+#endif
 
 static int xv_control_message(AVFormatContext *s, int type, void *data, size_t data_size)
 {
@@ -373,7 +375,9 @@  AVOutputFormat ff_xv_muxer = {
     .video_codec    = AV_CODEC_ID_WRAPPED_AVFRAME,
     .write_header   = xv_write_header,
     .write_packet   = xv_write_packet,
+#if FF_API_UNCODED_FRAME
     .write_uncoded_frame = xv_write_frame,
+#endif
     .write_trailer  = xv_write_trailer,
     .control_message = xv_control_message,
     .flags          = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 39b99b4481..c7dd35f714 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -573,6 +573,7 @@  typedef struct AVOutputFormat {
     int (*control_message)(struct AVFormatContext *s, int type,
                            void *data, size_t data_size);
 
+#if FF_API_UNCODED_FRAME
     /**
      * Write an uncoded AVFrame.
      *
@@ -583,6 +584,7 @@  typedef struct AVOutputFormat {
      */
     int (*write_uncoded_frame)(struct AVFormatContext *, int stream_index,
                                AVFrame **frame, unsigned flags);
+#endif
     /**
      * Returns device list with it properties.
      * @see avdevice_list_devices() for more details.
@@ -2636,6 +2638,7 @@  int av_write_frame(AVFormatContext *s, AVPacket *pkt);
  */
 int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt);
 
+#if FF_API_UNCODED_FRAME
 /**
  * Write an uncoded frame to an output media file.
  *
@@ -2644,6 +2647,7 @@  int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt);
  *
  * See av_interleaved_write_uncoded_frame() for details.
  */
+attribute_deprecated
 int av_write_uncoded_frame(AVFormatContext *s, int stream_index,
                            AVFrame *frame);
 
@@ -2663,6 +2667,7 @@  int av_write_uncoded_frame(AVFormatContext *s, int stream_index,
  *
  * @return  >=0 for success, a negative code on error
  */
+attribute_deprecated
 int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index,
                                        AVFrame *frame);
 
@@ -2672,7 +2677,9 @@  int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index,
  * @return  >=0 if an uncoded frame can be written to that muxer and stream,
  *          <0 if not
  */
+attribute_deprecated
 int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index);
+#endif
 
 /**
  * Write the stream trailer to an output media file and free the
diff --git a/libavformat/internal.h b/libavformat/internal.h
index 332477a532..6b16a36a73 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -618,6 +618,7 @@  int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t dts);
 
 void ff_rfps_calculate(AVFormatContext *ic);
 
+#if FF_API_UNCODED_FRAME
 /**
  * Flags for AVFormatContext.write_uncoded_frame()
  */
@@ -630,6 +631,7 @@  enum AVWriteUncodedFrameFlags {
     AV_WRITE_UNCODED_FRAME_QUERY           = 0x0001,
 
 };
+#endif
 
 /**
  * Copies the whilelists from one context to the other
diff --git a/libavformat/mux.c b/libavformat/mux.c
index cc2d1e275a..26af5c5030 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -548,6 +548,7 @@  fail:
     return ret;
 }
 
+#if FF_API_UNCODED_FRAME
 #define AV_PKT_FLAG_UNCODED_FRAME 0x2000
 
 /* Note: using sizeof(AVFrame) from outside lavu is unsafe in general, but
@@ -555,6 +556,7 @@  fail:
    The value is chosen to be very unlikely to appear on its own and to cause
    immediate failure if used anywhere as a real size. */
 #define UNCODED_FRAME_PACKET_SIZE (INT_MIN / 3 * 2 + (int)sizeof(AVFrame))
+#endif
 
 
 #if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX
@@ -649,8 +651,12 @@  static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket *
     /* update pts */
     switch (st->codecpar->codec_type) {
     case AVMEDIA_TYPE_AUDIO:
+#if FF_API_UNCODED_FRAME
         frame_size = (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) ?
                      ((AVFrame *)pkt->data)->nb_samples :
+#else
+        frame_size =
+#endif
                      av_get_audio_frame_duration(st->codec, pkt->size);
 
         /* HACK/FIXME, we skip the initial 0 size packets as they are most
@@ -745,12 +751,16 @@  static int write_packet(AVFormatContext *s, AVPacket *pkt)
         }
     }
 
+#if FF_API_UNCODED_FRAME
     if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
         AVFrame *frame = (AVFrame *)pkt->data;
         av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
         ret = s->oformat->write_uncoded_frame(s, pkt->stream_index, &frame, 0);
         av_frame_free(&frame);
     } else {
+#else
+    {
+#endif
         ret = s->oformat->write_packet(s, pkt);
     }
 
@@ -926,10 +936,14 @@  int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
     this_pktl    = av_malloc(sizeof(AVPacketList));
     if (!this_pktl)
         return AVERROR(ENOMEM);
+#if FF_API_UNCODED_FRAME
     if (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) {
         av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
         av_assert0(((AVFrame *)pkt->data)->buf);
     } else {
+#else
+    {
+#endif
         if ((ret = av_packet_make_refcounted(pkt)) < 0) {
             av_free(this_pktl);
             return ret;
@@ -1319,6 +1333,7 @@  int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt,
     return ret;
 }
 
+#if FF_API_UNCODED_FRAME
 static int write_uncoded_frame_internal(AVFormatContext *s, int stream_index,
                                         AVFrame *frame, int interleaved)
 {
@@ -1366,3 +1381,4 @@  int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index)
     return s->oformat->write_uncoded_frame(s, stream_index, NULL,
                                            AV_WRITE_UNCODED_FRAME_QUERY);
 }
+#endif
diff --git a/libavformat/uncodedframecrcenc.c b/libavformat/uncodedframecrcenc.c
index 2f1a14ca97..6d6b1397b1 100644
--- a/libavformat/uncodedframecrcenc.c
+++ b/libavformat/uncodedframecrcenc.c
@@ -26,6 +26,7 @@ 
 #include "avformat.h"
 #include "internal.h"
 
+#if FF_API_UNCODED_FRAME
 /* Identical to Adler32 when the type is uint8_t. */
 #define DEFINE_CKSUM_LINE(name, type, conv) \
 static void cksum_line_ ## name(unsigned *cksum, void *data, unsigned size) \
@@ -118,12 +119,14 @@  static void audio_frame_cksum(AVBPrint *bp, AVFrame *frame)
         av_bprintf(bp, ", 0x%08"PRIx32, cksum);
     }
 }
+#endif
 
 static int write_header(struct AVFormatContext *s)
 {
     return ff_framehash_write_header(s);
 }
 
+#if FF_API_UNCODED_FRAME
 static int write_frame(struct AVFormatContext *s, int stream_index,
                        AVFrame **frame, unsigned flags)
 {
@@ -158,6 +161,7 @@  static int write_frame(struct AVFormatContext *s, int stream_index,
     av_bprint_finalize(&bp, NULL);
     return ret;
 }
+#endif
 
 static int write_packet(struct AVFormatContext *s, AVPacket *pkt)
 {
@@ -171,7 +175,9 @@  AVOutputFormat ff_uncodedframecrc_muxer = {
     .video_codec       = AV_CODEC_ID_RAWVIDEO,
     .write_header      = write_header,
     .write_packet      = write_packet,
+#if FF_API_UNCODED_FRAME
     .write_uncoded_frame = write_frame,
+#endif
     .flags             = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
                          AVFMT_TS_NEGATIVE,
 };
diff --git a/libavformat/version.h b/libavformat/version.h
index 18c2f5fec2..80bb0e9d1d 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -32,7 +32,7 @@ 
 // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
 // Also please add any ticket numbers that you believe might be affected here
 #define LIBAVFORMAT_VERSION_MAJOR  58
-#define LIBAVFORMAT_VERSION_MINOR  42
+#define LIBAVFORMAT_VERSION_MINOR  43
 #define LIBAVFORMAT_VERSION_MICRO 100
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
@@ -106,6 +106,10 @@ 
 #ifndef FF_API_AVIOFORMAT
 #define FF_API_AVIOFORMAT               (LIBAVFORMAT_VERSION_MAJOR < 59)
 #endif
+#ifndef FF_API_UNCODED_FRAME
+#define FF_API_UNCODED_FRAME            (LIBAVFORMAT_VERSION_MAJOR < 59)
+#endif
+
 
 
 #ifndef FF_API_R_FRAME_RATE