[vlc-commits] access: live555: generate dts

Francois Cartegnie git at videolan.org
Thu Aug 2 21:15:39 CEST 2018


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Mon Jul 30 21:55:38 2018 +0200| [e5870f5a5c63cbfa4913352fd62f80d88e7d85ae] | committer: Francois Cartegnie

access: live555: generate dts

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=e5870f5a5c63cbfa4913352fd62f80d88e7d85ae
---

 modules/access/Makefile.am      |   3 +-
 modules/access/live555.cpp      |  37 +++++---
 modules/access/live555_dtsgen.h | 183 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 211 insertions(+), 12 deletions(-)

diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am
index 70050ad21e..3ad3e57aa2 100644
--- a/modules/access/Makefile.am
+++ b/modules/access/Makefile.am
@@ -317,7 +317,8 @@ libhttp_plugin_la_SOURCES = access/http.c
 libhttp_plugin_la_LIBADD = $(SOCKET_LIBS)
 access_LTLIBRARIES += libhttp_plugin.la
 
-liblive555_plugin_la_SOURCES = access/live555.cpp access/mms/asf.c access/mms/buffer.c
+liblive555_plugin_la_SOURCES = access/live555.cpp access/mms/asf.c access/mms/buffer.c \
+                               access/live555_dtsgen.h
 liblive555_plugin_la_CXXFLAGS = $(AM_CXXFLAGS) $(CXXFLAGS_live555)
 liblive555_plugin_la_LIBADD = $(LIBS_live555) $(SOCKET_LIBS)
 liblive555_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(accessdir)' \
diff --git a/modules/access/live555.cpp b/modules/access/live555.cpp
index c4541c9849..0060c24904 100644
--- a/modules/access/live555.cpp
+++ b/modules/access/live555.cpp
@@ -62,6 +62,7 @@
 
 extern "C" {
 #include "../access/mms/asf.h"  /* Who said ugly ? */
+#include "live555_dtsgen.h"
 }
 
 /*****************************************************************************
@@ -174,10 +175,12 @@ typedef struct
     bool            b_flushing_discontinuity;
     int             i_next_block_flags;
     char            waiting;
-    int64_t         i_lastpts;
+    int64_t         i_prevpts;
     int64_t         i_pcr;
     double          f_npt;
 
+    struct dtsgen_t dtsgen;
+
     enum
     {
         STATE_NONE,
@@ -489,6 +492,7 @@ static void Close( vlc_object_t *p_this )
         if( tk->p_out_muxed )
             vlc_demux_chained_Delete( tk->p_out_muxed );
         es_format_Clean( &tk->fmt );
+        dtsgen_Clean( &tk->dtsgen );
         free( tk->p_buffer );
         free( tk );
     }
@@ -867,9 +871,10 @@ static int SessionsSetup( demux_t *p_demux )
             tk->b_rtcp_sync = false;
             tk->b_flushing_discontinuity = false;
             tk->i_next_block_flags = 0;
-            tk->i_lastpts   = VLC_TICK_INVALID;
+            tk->i_prevpts   = VLC_TICK_INVALID;
             tk->i_pcr       = VLC_TICK_INVALID;
             tk->f_npt       = 0.;
+            dtsgen_Init( &tk->dtsgen );
             tk->state       = live_track_t::STATE_SELECTED;
             tk->i_buffer    = i_frame_buffer;
             tk->p_buffer    = (uint8_t *)malloc( i_frame_buffer );
@@ -1451,7 +1456,7 @@ static int Demux( demux_t *p_demux )
             for( i = 0; i < p_sys->i_track; i++ )
             {
                 live_track_t *tk = p_sys->track[i];
-                tk->i_lastpts = VLC_TICK_INVALID;
+                tk->i_prevpts = VLC_TICK_INVALID;
                 tk->i_pcr = VLC_TICK_INVALID;
                 tk->f_npt = 0.;
                 tk->b_flushing_discontinuity = false;
@@ -1599,8 +1604,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
                 for( int i = 0; i < p_sys->i_track; i++ )
                 {
                     p_sys->track[i]->b_rtcp_sync = false;
-                    p_sys->track[i]->i_lastpts = VLC_TICK_INVALID;
+                    p_sys->track[i]->i_prevpts = VLC_TICK_INVALID;
                     p_sys->track[i]->i_pcr = VLC_TICK_INVALID;
+                    dtsgen_Resync( &p_sys->track[i]->dtsgen );
                 }
 
                 /* Retrieve the starttime if possible */
@@ -1731,7 +1737,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
                     tk->b_rtcp_sync = false;
                     tk->b_flushing_discontinuity = false;
                     tk->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY;
-                    tk->i_lastpts = VLC_TICK_INVALID;
+                    tk->i_prevpts = VLC_TICK_INVALID;
                     tk->i_pcr = VLC_TICK_INVALID;
                 }
                 p_sys->i_pcr = VLC_TICK_INVALID;
@@ -2103,6 +2109,7 @@ static void StreamRead( void *p_private, unsigned int i_size,
             const vlc_tick_t i_max_diff = vlc_tick_from_sec(( tk->fmt.i_cat == SPU_ES ) ? 60 : 1);
             tk->b_flushing_discontinuity = (llabs(i_pts - tk->i_pcr) > i_max_diff);
             tk->i_pcr = i_pts;
+            tk->dtsgen.count = 0;
         }
     }
 
@@ -2122,15 +2129,22 @@ static void StreamRead( void *p_private, unsigned int i_size,
                 vlc_demux_chained_Send( tk->p_out_muxed, p_block );
                 break;
             default:
-                if( i_pts != tk->i_lastpts )
+                if( i_pts != tk->i_prevpts )
+                {
                     p_block->i_pts = VLC_TICK_0 + i_pts;
+                    tk->i_prevpts = i_pts;
+
+                    dtsgen_AddNextPTS( &tk->dtsgen, i_pts );
+                }
+
                 /*FIXME: for h264 you should check that packetization-mode=1 in sdp-file */
                 switch( tk->fmt.i_codec )
                 {
                     case VLC_CODEC_MPGV:
                     case VLC_CODEC_H264:
                     case VLC_CODEC_HEVC:
-                        p_block->i_dts = VLC_TICK_INVALID;
+                        p_block->i_dts = dtsgen_GetDTS( &tk->dtsgen );
+                        dtsgen_Debug( VLC_OBJECT(p_demux), &tk->dtsgen, p_block->i_dts, p_block->i_pts );
                         break;
                     case VLC_CODEC_VP8:
                     default:
@@ -2146,12 +2160,13 @@ static void StreamRead( void *p_private, unsigned int i_size,
                     p_block->i_flags |= tk->i_next_block_flags;
                     tk->i_next_block_flags = 0;
                 }
+
+                vlc_tick_t i_pcr = p_block->i_dts > VLC_TICK_INVALID ? p_block->i_dts : p_block->i_pts;
                 es_out_Send( p_demux->out, tk->p_es, p_block );
-                if( i_pts > 0 )
+                if( i_pcr > VLC_TICK_INVALID )
                 {
-                    if( tk->i_pcr < i_pts )
-                        tk->i_pcr = i_pts;
-                    tk->i_lastpts = i_pts;
+                    if( tk->i_pcr < i_pcr )
+                        tk->i_pcr = i_pcr;
                 }
                 break;
         }
diff --git a/modules/access/live555_dtsgen.h b/modules/access/live555_dtsgen.h
new file mode 100644
index 0000000000..ea422df0ac
--- /dev/null
+++ b/modules/access/live555_dtsgen.h
@@ -0,0 +1,183 @@
+/*****************************************************************************
+ * live555_dtsgen.h : DTS rebuilder for pts only streams
+ *****************************************************************************
+ * Copyright (C) 2018 VideoLabs, VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#define DTSGEN_REORDER_MAX   4 /* should be enough */
+#define DTSGEN_HISTORY_COUNT (DTSGEN_REORDER_MAX + 1)
+//#define DTSGEN_DEBUG
+
+struct dtsgen_t
+{
+    vlc_tick_t history[DTSGEN_HISTORY_COUNT];
+    vlc_tick_t ordereddts[DTSGEN_HISTORY_COUNT];
+    vlc_tick_t i_startingdts;
+    vlc_tick_t i_startingdiff;
+    unsigned reorderdepth;
+    unsigned count;
+};
+
+static int cmpvlctickp(const void *p1, const void *p2)
+{
+    if(*((vlc_tick_t *)p1) >= *((vlc_tick_t *)p2))
+        return *((vlc_tick_t *)p1) > *((vlc_tick_t *)p2) ? 1 : 0;
+    else
+        return -1;
+}
+
+static void dtsgen_Init(struct dtsgen_t *d)
+{
+    d->count = 0;
+    d->reorderdepth = 0;
+}
+
+static void dtsgen_Resync(struct dtsgen_t *d)
+{
+    d->count = 0;
+}
+
+#define dtsgen_Clean(d)
+
+/*
+ * RTSP sends in decode order, but only provides PTS as timestamp
+ * P0 P2 P3 P1 P5 P7 P8 P6
+ * D0 D2 D3 D1 D5 D7 D8 D6 <- wrong !
+ * creating a non monotonical sequence when used as DTS, then PCR
+ *
+ * We need to have a suitable DTS for proper PCR and transcoding
+ * with the usual requirements DTS0 < DTS1 and DTSN < PTSN
+ *
+ * So we want to find the closest DTS matching those conditions
+ *  P0 P2 P3[P1]P5 P7 P8 P6
+ * [D0]D1 D2 D3 D4 D5 D6 D7
+ *
+ * Which means that within a reorder window,
+ * we want the PTS time index after reorder as DTS
+ * [P0 P2 P3 P1]P5 P7 P8 P6
+ * [P0 P1 P2 P3] reordered
+ * [D0 D1 D2 D3]D4 D5 D6 D7
+ * we need to pick then N frames before in reordered order (== reorder depth)
+ *  P0 P2 P3[P1]P5 P7 P8 P6
+ * [D0]D1 D2 D3 D4 D5 D6 D7
+ * so D0 < P1 (we can also pick D1 if we want DTSN <= PTSN)
+ *
+ * Since it would create big delays with low fps streams we need
+ * - to avoid buffering packets
+ * - to detect real reorder depth (low fps usually have no reorder)
+ *
+ * We need then to:
+ * - Detect reorder depth
+ * - Keep track of last of N past timestamps, > maximum possible reorder
+ * - Make sure a suitable dts is still created while detecting reorder depth
+ *
+ * While receiving the N first packets (N>max reorder):
+ * - check if it needs reorder, or increase depth
+ * - create slow increments in DTS while taking any frame as a start,
+ *   substracting the total difference between first and last packet,
+ *   and removing the possible offset after reorder,
+ *   divided by max possible frames.
+ *
+ * Once reorder depth is fully known,
+ * - use N previous frames reordered PTS as DTS for current PTS.
+ *  (with mandatory gap/increase in DTS caused by previous step)
+ */
+
+static void dtsgen_AddNextPTS(struct dtsgen_t *d, vlc_tick_t i_pts)
+{
+    /* Check saved pts in reception order to find reordering depth */
+    if(d->count > 0 && d->count < DTSGEN_HISTORY_COUNT)
+    {
+        unsigned i;
+        if(d->count > (1 + d->reorderdepth))
+            i = d->count - (1 + d->reorderdepth);
+        else
+            i = 0;
+
+        for(; i < d->count; i++)
+        {
+            if(d->history[i] > i_pts)
+            {
+                if(d->reorderdepth < DTSGEN_REORDER_MAX)
+                    d->reorderdepth++;
+            }
+            break;
+        }
+    }
+
+    /* insert current */
+    if(d->count == DTSGEN_HISTORY_COUNT)
+    {
+        d->ordereddts[0] = i_pts; /* remove lowest */
+        memmove(d->history, &d->history[1],
+                sizeof(d->history[0]) * (d->count - 1));
+    }
+    else
+    {
+        d->history[d->count] = i_pts;
+        d->ordereddts[d->count++] = i_pts;
+    }
+
+    /* order pts in second list, will be used as dts */
+    qsort(&d->ordereddts, d->count, sizeof(d->ordereddts[0]), cmpvlctickp);
+}
+
+static vlc_tick_t dtsgen_GetDTS(struct dtsgen_t *d)
+{
+    vlc_tick_t i_dts = VLC_TICK_INVALID;
+
+    /* When we have inspected enough packets,
+     * use the reorderdepth th packet as dts offset */
+    if(d->count > DTSGEN_REORDER_MAX)
+    {
+        i_dts = d->ordereddts[(d->count - 1) - (d->reorderdepth + 1)];
+    }
+    /* When starting, we craft a slow incrementing DTS to ensure
+       we can't go backward due to reorder need */
+    else if(d->count == 1)
+    {
+        d->i_startingdts =
+        i_dts = __MAX(d->history[0] - VLC_TICK_FROM_MS(150), VLC_TICK_0);
+        d->i_startingdiff = d->history[0] - i_dts;
+    }
+    else if(d->count > 1)
+    {
+        vlc_tick_t i_diff = d->ordereddts[d->count - 1] -
+                            d->ordereddts[0];
+        i_diff = __MIN(d->i_startingdiff, i_diff);
+        d->i_startingdts += i_diff / DTSGEN_REORDER_MAX;
+        i_dts = d->i_startingdts;
+    }
+
+    return i_dts;
+}
+
+#ifdef DTSGEN_DEBUG
+static void dtsgen_Debug(vlc_object_t *p_demux, struct dtsgen_t *d,
+                         vlc_tick_t dts, vlc_tick_t pts)
+{
+    if(pts == VLC_TICK_INVALID)
+        return;
+    msg_Dbg(p_demux, "dtsgen %" PRId64 " / pts %" PRId64 " diff %" PRId64 ", "
+                     "pkt count %u, reorder %u",
+            dts % (10 * CLOCK_FREQ),
+            pts % (10 * CLOCK_FREQ),
+            (pts - dts) % (10 * CLOCK_FREQ),
+            d->count, d->reorderdepth);
+}
+#else
+    #define dtsgen_Debug(a,b,c,d)
+#endif



More information about the vlc-commits mailing list