[FFmpeg-devel] [PATCH] avformat/fifo: utilize a clone packet for muxing

Jan Ekström jeebjp at gmail.com
Tue Dec 8 14:54:33 EET 2020


From: Jan Ekström <jan.ekstrom at 24i.com>

This way the timestamp adjustments do not have to be manually
undone in case of failure and need to recover/retry.

Fixes an issue where the timestamp adjustment would be re-done over
and over again when recovery by muxing the same AVPacket again is
attempted. Would become visible if the fifo muxer's time base and
the output muxer's time base do not match (by the value either
becoming smaller and smaller, or larger and larger).

Signed-off-by: Jan Ekström <jan.ekstrom at 24i.com>
---
 libavformat/fifo.c | 39 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/libavformat/fifo.c b/libavformat/fifo.c
index 17748e94ce..aa8bea6d5a 100644
--- a/libavformat/fifo.c
+++ b/libavformat/fifo.c
@@ -43,6 +43,8 @@ typedef struct FifoContext {
     int queue_size;
     AVThreadMessageQueue *queue;
 
+    AVPacket *out_pkt;
+
     pthread_t writer_thread;
 
     /* Return value of last write_trailer_call */
@@ -181,6 +183,7 @@ static int fifo_thread_write_packet(FifoThreadContext *ctx, AVPacket *pkt)
     AVFormatContext *avf = ctx->avf;
     FifoContext *fifo = avf->priv_data;
     AVFormatContext *avf2 = fifo->avf;
+    AVPacket *out_pkt = fifo->out_pkt;
     AVRational src_tb, dst_tb;
     int ret, s_idx;
 
@@ -198,14 +201,34 @@ static int fifo_thread_write_packet(FifoThreadContext *ctx, AVPacket *pkt)
         }
     }
 
-    s_idx = pkt->stream_index;
+    // We will be muxing a packet, so clone it by utilizing references.
+    // This way we do not have to undo any of the tweaking for timestamps etc
+    // that we are doing in this function in case another attempt through
+    // recovery is required.
+    if ((ret = av_packet_ref(out_pkt, pkt)) < 0) {
+        av_log(avf, AV_LOG_ERROR,
+               "Error creating a new reference for output packet (%s)!\n",
+               av_err2str(ret));
+        return ret;
+    }
+
+    s_idx = out_pkt->stream_index;
     src_tb = avf->streams[s_idx]->time_base;
     dst_tb = avf2->streams[s_idx]->time_base;
-    av_packet_rescale_ts(pkt, src_tb, dst_tb);
 
-    ret = av_write_frame(avf2, pkt);
-    if (ret >= 0)
-        av_packet_unref(pkt);
+    av_packet_rescale_ts(out_pkt, src_tb, dst_tb);
+
+    ret = av_write_frame(avf2, out_pkt);
+
+    // Always clear the output packet, as we have no more use for it.
+    av_packet_unref(out_pkt);
+
+    if (ret < 0)
+        return ret;
+
+    // We hit success, unref the actual source packet.
+    av_packet_unref(pkt);
+
     return ret;
 }
 
@@ -525,6 +548,11 @@ static int fifo_init(AVFormatContext *avf)
         return ret;
     }
 
+    if (!(fifo->out_pkt = av_packet_alloc())) {
+        av_log(avf, AV_LOG_ERROR, "Failed to allocate output packet!\n");
+        return AVERROR(ENOMEM);
+    }
+
     ret = fifo_mux_init(avf, oformat, avf->url);
     if (ret < 0)
         return ret;
@@ -650,6 +678,7 @@ static void fifo_deinit(AVFormatContext *avf)
     av_thread_message_queue_free(&fifo->queue);
     if (fifo->overflow_flag_lock_initialized)
         pthread_mutex_destroy(&fifo->overflow_flag_lock);
+    av_packet_free(&fifo->out_pkt);
 }
 
 #define OFFSET(x) offsetof(FifoContext, x)
-- 
2.29.2



More information about the ffmpeg-devel mailing list