Skip to content

Commit 4f7c39e

Browse files
committed
avformat/mux: Don't modify packets we don't own
The documentation of av_write_frame explicitly states that the function does not take ownership of the packets sent to it; while av_write_frame does not directly unreference the packets after having written them, it nevertheless modifies the packet in various ways: 1. The timestamps might be modified either by prepare_input_packet or compute_muxer_pkt_fields. 2. If a bitstream filter gets applied, it takes ownership of the packet sent to it in av_bsf_send_packet. In case of do_packet_auto_bsf, the end result is that the returned packet contains the output of the last bsf in the chain. If an error happens, an empty packet will be returned; a packet may also simply not lead to any output (vp9_superframe). This also implies that side data needs to be really copied and can't be shared with the input packet. The method choosen here minimizes copying of data; when the input isn't refcounted and no bitstream filter is applied, the packet's data will not be copied. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
1 parent df10192 commit 4f7c39e

File tree

1 file changed

+26
-5
lines changed

1 file changed

+26
-5
lines changed

libavformat/mux.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -872,11 +872,12 @@ static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) {
872872
return 1;
873873
}
874874

875-
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
875+
int av_write_frame(AVFormatContext *s, AVPacket *in)
876876
{
877+
AVPacket local_pkt, *pkt = &local_pkt;
877878
int ret;
878879

879-
if (!pkt) {
880+
if (!in) {
880881
if (s->oformat->flags & AVFMT_ALLOW_FLUSH) {
881882
ret = s->oformat->write_packet(s, NULL);
882883
flush_if_needed(s);
@@ -887,19 +888,36 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
887888
return 1;
888889
}
889890

891+
/* We don't own in, so we have to make sure not to modify it.
892+
* The following avoids copying in's data unnecessarily.
893+
* Copying side data is unavoidable as a bitstream filter
894+
* may change it, e.g. free it on errors. */
895+
pkt->data = in->data;
896+
pkt->size = in->size;
897+
if (in->buf) {
898+
pkt->buf = av_buffer_ref(in->buf);
899+
if (!pkt->buf)
900+
return AVERROR(ENOMEM);
901+
} else {
902+
pkt->buf = NULL;
903+
}
904+
ret = av_packet_copy_props(pkt, in);
905+
if (ret < 0)
906+
goto fail;
907+
890908
ret = prepare_input_packet(s, pkt);
891909
if (ret < 0)
892-
return ret;
910+
goto fail;
893911

894912
ret = do_packet_auto_bsf(s, pkt);
895913
if (ret <= 0)
896-
return ret;
914+
goto fail;
897915

898916
#if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX
899917
ret = compute_muxer_pkt_fields(s, s->streams[pkt->stream_index], pkt);
900918

901919
if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
902-
return ret;
920+
goto fail;
903921
#endif
904922

905923
ret = write_packet(s, pkt);
@@ -908,6 +926,9 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
908926

909927
if (ret >= 0)
910928
s->streams[pkt->stream_index]->nb_frames++;
929+
930+
fail:
931+
av_packet_unref(pkt);
911932
return ret;
912933
}
913934

0 commit comments

Comments
 (0)