vlc | branch: master | Francois Cartegnie <[email protected]> | 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 _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
