[vlc-devel] [PATCH] mux/avformat: normalize pts and dts in AVPacket

Filip Roséen filip at atch.se
Tue Feb 7 13:15:21 CET 2017


According to the ffmpeg documentation of AVPacket when used in muxing,
pkt.{pts,dts} are absolute values for when a packet is to be
interpreted, where the first packet shall start at zero.

As the pts/dts in VLC are all relative to the PCR, those timestamps
are not guaranteed to start at zero; which means that we would confuse
avformat in scenarios where it heavily depends on zero-based pts/dts.

These changes make sure that we start all timestamps at zero by
normalizing each outgoing timestamp to the relative distance from the
first entity received for each stream.

fixes #17988

--

 Ticket:
     - https://trac.videolan.org/vlc/ticket/17988

 Relevant part of ffmpeg mkv mux (explains why the duration becomes wrong):
     - https://www.ffmpeg.org/doxygen/3.2/matroskaenc_8c_source.html#l02148

 AVPacket documentation:
     - https://www.ffmpeg.org/doxygen/3.2/structAVPacket.htmi
---
 modules/demux/avformat/mux.c | 48 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 37 insertions(+), 11 deletions(-)

diff --git a/modules/demux/avformat/mux.c b/modules/demux/avformat/mux.c
index 9072c2f8e1..b2b7bb467d 100644
--- a/modules/demux/avformat/mux.c
+++ b/modules/demux/avformat/mux.c
@@ -66,6 +66,18 @@ struct sout_mux_sys_t
 #endif
 };
 
+typedef struct
+{
+    int i_stream;
+
+    struct {
+        mtime_t i_pts;
+        mtime_t i_dts;
+    } base_ts;
+
+} sout_input_sys_t;
+
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -221,11 +233,14 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
     }
 
     /* */
-    p_input->p_sys = malloc( sizeof( int ) );
-    if( unlikely(p_input->p_sys == NULL) )
+    sout_input_sys_t* p_input_sys = malloc( sizeof *p_input_sys );
+    if( unlikely( p_input_sys == NULL ) )
         return VLC_ENOMEM;
 
-    *((int *)p_input->p_sys) = p_sys->oc->nb_streams;
+    p_input->p_sys = p_input_sys;
+    p_input_sys->i_stream = p_sys->oc->nb_streams;
+    p_input_sys->base_ts.i_pts = VLC_TS_INVALID;
+    p_input_sys->base_ts.i_dts = VLC_TS_INVALID;
 
     /* */
     stream = avformat_new_stream( p_sys->oc, NULL);
@@ -322,11 +337,21 @@ static void DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
     free( p_input->p_sys );
 }
 
+static mtime_t NormalizeTS( mtime_t *base, AVStream* p_stream, mtime_t timestamp )
+{
+    if( *base == VLC_TS_INVALID )
+        *base = timestamp;
+
+    return ( timestamp - *base ) * p_stream->time_base.den /
+           CLOCK_FREQ / p_stream->time_base.num;
+}
+
 static int MuxBlock( sout_mux_t *p_mux, sout_input_t *p_input )
 {
     sout_mux_sys_t *p_sys = p_mux->p_sys;
+    sout_input_sys_t *p_input_sys = p_input->p_sys;
     block_t *p_data = block_FifoGet( p_input->p_fifo );
-    int i_stream = *((int *)p_input->p_sys);
+    int i_stream = p_input_sys->i_stream;
     AVStream *p_stream = p_sys->oc->streams[i_stream];
     AVPacket pkt;
 
@@ -350,15 +375,16 @@ static int MuxBlock( sout_mux_t *p_mux, sout_input_t *p_input )
     }
 
     if( p_data->i_pts > 0 )
-        pkt.pts = p_data->i_pts * p_stream->time_base.den /
-            CLOCK_FREQ / p_stream->time_base.num;
+        pkt.pts = NormalizeTS( &p_input_sys->base_ts.i_pts,
+                                p_stream, p_data->i_pts );
+
     if( p_data->i_dts > 0 )
-        pkt.dts = p_data->i_dts * p_stream->time_base.den /
-            CLOCK_FREQ / p_stream->time_base.num;
+        pkt.dts = NormalizeTS( &p_input_sys->base_ts.i_dts,
+                                p_stream, p_data->i_dts );
 
-    /* this is another hack to prevent libavformat from triggering the "non monotone timestamps" check in avformat/utils.c */
-    p_stream->cur_dts = ( p_data->i_dts * p_stream->time_base.den /
-            CLOCK_FREQ / p_stream->time_base.num ) - 1;
+    /* This is another hack to prevent libavformat from triggering the
+     * "non monotone timestamps" check in avformat/utils.c */
+    p_stream->cur_dts = pkt.dts;
 
     if( av_write_frame( p_sys->oc, &pkt ) < 0 )
     {
-- 
2.11.1



More information about the vlc-devel mailing list