[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