diff options
author | Philip Langdale <philipl@overt.org> | 2022-11-29 11:15:16 -0800 |
---|---|---|
committer | Philip Langdale <github.philipl@overt.org> | 2022-12-03 14:44:18 -0800 |
commit | 4574dd5dc6ff75b1fc693afceec59fbcd51ccd4c (patch) | |
tree | 680ea541592dea8e356809e5dbdd5265781d72fe /common | |
parent | 77e7f5de2c01361a88c501fcd78b51c2fe2d9df0 (diff) | |
download | mpv-4574dd5dc6ff75b1fc693afceec59fbcd51ccd4c.tar.bz2 mpv-4574dd5dc6ff75b1fc693afceec59fbcd51ccd4c.tar.xz |
ffmpeg: update to handle deprecation of `av_init_packet`
This has been a long standing annoyance - ffmpeg is removing
sizeof(AVPacket) from the API which means you cannot stack-allocate
AVPacket anymore. However, that is something we take advantage of
because we use short-lived AVPackets to bridge from native mpv packets
in our main decoding paths.
We don't think that switching these to `av_packet_alloc` is desirable,
given the cost of heap allocation, so this change takes a different
approach - allocating a single packet in the relevant context and
reusing it over and over.
That's fairly straight-forward, with the main caveat being that
re-initialising the packet is unintuitive. There is no function that
does exactly what we need (what `av_init_packet` did). The closest is
`av_packet_unref`, which additionally frees buffers and side-data.
However, we don't copy those things - we just assign them in from our
own packet, so we have to explicitly clear the pointers before calling
`av_packet_unref`. But at least we can make a wrapper function for
that.
The weirdest part of the change is the handling of the vtt subtitle
conversion. This requires two packets, so I had to pre-allocate two in
the context struct. That sounds excessive, but if allocating the
primary packet is too expensive, then allocating the secondary one for
vtt subtitles must also be too expensive.
This change is not conditional as heap allocated AVPackets were
available for years and years before the deprecation.
Diffstat (limited to 'common')
-rw-r--r-- | common/av_common.c | 24 | ||||
-rw-r--r-- | common/av_common.h | 1 | ||||
-rw-r--r-- | common/recorder.c | 16 |
3 files changed, 33 insertions, 8 deletions
diff --git a/common/av_common.c b/common/av_common.c index 8b5a3970d0..db31988c1b 100644 --- a/common/av_common.c +++ b/common/av_common.c @@ -196,7 +196,11 @@ double mp_pts_from_av(int64_t av_pts, AVRational *tb) // Set duration field only if tb is set. void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt, AVRational *tb) { - av_init_packet(dst); + dst->side_data = NULL; + dst->side_data_elems = 0; + dst->buf = NULL; + av_packet_unref(dst); + dst->data = mpkt ? mpkt->buffer : NULL; dst->size = mpkt ? mpkt->len : 0; /* Some codecs (ZeroCodec, some cases of PNG) may want keyframe info @@ -394,3 +398,21 @@ int mp_set_avopts_pos(struct mp_log *log, void *avobj, void *posargs, char **kv) } return success; } + +/** + * Must be used to free an AVPacket that was used with mp_set_av_packet(). + * + * We have a particular pattern where we "borrow" buffers and set them + * into an AVPacket to pass data to ffmpeg without extra copies. + * This applies to buf and side_data, so this function clears them before + * freeing. + */ +void mp_free_av_packet(AVPacket **pkt) +{ + if (*pkt) { + (*pkt)->side_data = NULL; + (*pkt)->side_data_elems = 0; + (*pkt)->buf = NULL; + } + av_packet_free(pkt); +} diff --git a/common/av_common.h b/common/av_common.h index 1b3e468884..dd5e88e003 100644 --- a/common/av_common.h +++ b/common/av_common.h @@ -50,5 +50,6 @@ void mp_set_avdict(struct AVDictionary **dict, char **kv); void mp_avdict_print_unset(struct mp_log *log, int msgl, struct AVDictionary *d); int mp_set_avopts(struct mp_log *log, void *avobj, char **kv); int mp_set_avopts_pos(struct mp_log *log, void *avobj, void *posargs, char **kv); +void mp_free_av_packet(AVPacket **pkt); #endif diff --git a/common/recorder.c b/common/recorder.c index 0cbc81d51c..cee837ba24 100644 --- a/common/recorder.c +++ b/common/recorder.c @@ -64,6 +64,7 @@ struct mp_recorder_sink { struct mp_recorder *owner; struct sh_stream *sh; AVStream *av_stream; + AVPacket *avpkt; double max_out_pts; bool discont; bool proper_eof; @@ -82,10 +83,11 @@ static int add_stream(struct mp_recorder *priv, struct sh_stream *sh) .owner = priv, .sh = sh, .av_stream = avformat_new_stream(priv->mux, NULL), + .avpkt = av_packet_alloc(), .max_out_pts = MP_NOPTS_VALUE, }; - if (!rst->av_stream) + if (!rst->av_stream || !rst->avpkt) return -1; AVCodecParameters *avp = mp_codec_params_to_av(sh->codec); @@ -237,15 +239,14 @@ static void mux_packet(struct mp_recorder_sink *rst, rst->max_out_pts = MP_PTS_MAX(rst->max_out_pts, pkt->pts); - AVPacket avpkt; - mp_set_av_packet(&avpkt, &mpkt, &rst->av_stream->time_base); + mp_set_av_packet(rst->avpkt, &mpkt, &rst->av_stream->time_base); - avpkt.stream_index = rst->av_stream->index; + rst->avpkt->stream_index = rst->av_stream->index; - if (avpkt.duration < 0 && rst->sh->type != STREAM_SUB) - avpkt.duration = 0; + if (rst->avpkt->duration < 0 && rst->sh->type != STREAM_SUB) + rst->avpkt->duration = 0; - AVPacket *new_packet = av_packet_clone(&avpkt); + AVPacket *new_packet = av_packet_clone(rst->avpkt); if (!new_packet) { MP_ERR(priv, "Failed to allocate packet.\n"); return; @@ -319,6 +320,7 @@ void mp_recorder_destroy(struct mp_recorder *priv) for (int n = 0; n < priv->num_streams; n++) { struct mp_recorder_sink *rst = priv->streams[n]; mux_packets(rst); + mp_free_av_packet(&rst->avpkt); } if (av_write_trailer(priv->mux) < 0) |