[FFmpeg-devel] libavformat: fix copyts and muxrate in mpegts muxer

Submitted by Oliver Collyer via ffmpeg-devel on April 18, 2019, 9:01 a.m.

Details

Message ID 54FngVg9fz3aNdpQwkm65W8zPLWU6TvxGVMANTuxYs1tr0PUVm6dZ23iFw7U0uIrjl-BCtDQPHMD8BRW60CY4HgpbvoXw3IGeiC_GSNZ1vM=@protonmail.com
State New
Headers show

Commit Message

Oliver Collyer via ffmpeg-devel April 18, 2019, 9:01 a.m.
Hi,

This patch resolves one very specific use case:

- When you use the mpegts muxer;
- And use the global parameter “-copyts”;
- And use the parameter “-muxrate” for the mpegts muxer;
- And use too the parameter “-mpegts_copyts”.

The problem is created because the member “first_pcr” of the MpegTSWrite struct isn’t initialized with a correct timestamp (so when copying the timestamps the initial value is 0). And in this case an infinite loop is created because the code never writes PES packets when the “mux_rate” isn’t VBR (equals to 1). See the block that creates the loop here (note the "continue" command at end):
https://github.com/FFmpeg/FFmpeg/blob/a0559fcd81f42f446c93357a943699f9d44eeb79/libavformat/mpegtsenc.c#L1211

So, this patch fixes the problem initializing the “first_pcr” with the first DTS value that comes when using the incoming timestamps.

Regards.
A.H.

---
From 225f3de248625c588b2e8bb169cdff28705db8f5 Mon Sep 17 00:00:00 2001
From:  Andreas Hakon <andreas.hakon@protonmail.com>
Date: Thu, 18 Apr 2019 09:53:30 +0100
Subject: [PATCH] libavformat: fix copyts with muxrate

---
 libavformat/mpegtsenc.c |   10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index fc0ea22..7e94326 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -971,6 +971,9 @@  static int mpegts_init(AVFormatContext *s)
 
         if (ts->copyts < 1)
             ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE);
+        else
+            ts->first_pcr = AV_NOPTS_VALUE;
+
     } else {
         /* Arbitrary values, PAT/PMT will also be written on video key frames */
         ts->sdt_packet_period = 200;
@@ -1186,12 +1189,16 @@  static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
     int64_t pcr = -1; /* avoid warning */
     int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE);
     int force_pat = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && key && !ts_st->prev_payload_key;
+    int last_payload_size = 0;
 
     av_assert0(ts_st->payload != buf || st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO);
     if (ts->flags & MPEGTS_FLAG_PAT_PMT_AT_FRAMES && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
         force_pat = 1;
     }
 
+    if (ts->mux_rate > 1 && dts != AV_NOPTS_VALUE && ts->first_pcr == AV_NOPTS_VALUE)
+        ts->first_pcr = (dts - 1) * 300;
+
     is_start = 1;
     while (payload_size > 0) {
         retransmit_si_info(s, force_pat, dts);
@@ -1209,12 +1216,13 @@  static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
         }
 
         if (ts->mux_rate > 1 && dts != AV_NOPTS_VALUE &&
-            (dts - get_pcr(ts, s->pb) / 300) > delay) {
+            last_payload_size != payload_size && (dts - get_pcr(ts, s->pb) / 300) > delay) {
             /* pcr insert gets priority over null packet insert */
             if (write_pcr)
                 mpegts_insert_pcr_only(s, st);
             else
                 mpegts_insert_null_packet(s);
+            last_payload_size = payload_size;
             /* recalculate write_pcr and possibly retransmit si_info */
             continue;
         }