[vlc-commits] [Git][videolan/vlc][3.0.x] 18 commits: demux: ts: fix scale of first_dts
François Cartegnie (@fcartegnie)
gitlab at videolan.org
Tue May 20 06:32:10 UTC 2025
François Cartegnie pushed to branch 3.0.x at VideoLAN / VLC
Commits:
f854d817 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: fix scale of first_dts
- - - - -
37b7094b by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: typedef timestamps
(adapted from commit 68fcf13842229e17c3db26ed62f457219484ff77)
- - - - -
fd441747 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: split PES processing
(adapted from commit 7ed1257d9d917e486ad58eabb7cde2f46ea199fc)
- - - - -
e63d73a2 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: replace push with explicit drain
(cherry picked from commit 7413a20bb2dbfd4691731dd8c5c8b2d8ea727385)
- - - - -
077e2dca by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: fix output from variable->fixed (refs #23654)
(cherry picked from commit 6efb4c78a573f754987a3bb3df107b720c5986bc)
- - - - -
58d21108 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: don't append empty ts packets into PES (refs #23654)
(cherry picked from commit 8210974f589be933cc9c9150d8d43f2052bce063)
- - - - -
d3465ce8 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: always end PES on PUSI
(cherry picked from commit d7ace86225528b61508845d3bb762c617e3fc2a1)
- - - - -
8aeda189 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: don't start PES without PUSI
(cherry picked from commit afe64934d2b5f488dd28c52dd654569e534f1721)
- - - - -
6fbb86e0 by François Cartegnie at 2025-05-19T03:45:06+00:00
test: add PES assembly tests
(adapted from commit cef77e6f7f0d47df92e3ca609da07916dc44a3fa)
- - - - -
76b66156 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: store last dts on pes struct
(cherry picked from commit cb1c8d6946ee1b08d47551127c45e485ff12ae2a)
- - - - -
4e3a0be7 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: workaround broken teletext
(adapted from commit 4d37595856b6164c4b9b6ce104ae97f21242295c)
- - - - -
76897796 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: change stime_t for ts_90khz_t
(adapted from 0a5bd92c5218f6416d498648254356b4fbc258aa)
- - - - -
ec978224 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: add TS_90KHZ_INVALID
(adapted from commit cf2f062fdf6ed1050ecb098d7c131daa46110243)
- - - - -
7f2c6b67 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: revert native scale changes to fix wrapping
Can never work with timestamp value 0
(adapted from from commit af38707d0e72f81c5e6e0258a91f4718ca7bdf76)
- - - - -
d22791c5 by François Cartegnie at 2025-05-19T03:45:06+00:00
tests: add timestamps wrapping check
(cherry picked from commit 56b1956461e627eb6c7f650b35fe239aaf21a6ac)
- - - - -
c43911de by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: temporary fix timestamps wrapping
for tests & before full fix
- - - - -
75132780 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: fix multiple wrapping
refs streams/ts/1fps93hours.ts
(adapted from commit caf3ea133abc93da7d640fbec5243e3478c3e1d8)
- - - - -
78988161 by François Cartegnie at 2025-05-19T03:45:06+00:00
demux: ts: wrap probing times
- - - - -
20 changed files:
- modules/demux/Makefile.am
- modules/demux/mpeg/pes.h
- modules/demux/mpeg/ps.h
- modules/demux/mpeg/timestamps.h
- modules/demux/mpeg/ts.c
- modules/demux/mpeg/ts_arib.c
- modules/demux/mpeg/ts_hotfixes.c
- + modules/demux/mpeg/ts_pes.c
- + modules/demux/mpeg/ts_pes.h
- modules/demux/mpeg/ts_pid.c
- modules/demux/mpeg/ts_psi.c
- modules/demux/mpeg/ts_psip.c
- modules/demux/mpeg/ts_scte.c
- modules/demux/mpeg/ts_streams.c
- modules/demux/mpeg/ts_streams_private.h
- modules/demux/pva.c
- modules/demux/ty.c
- test/Makefile.am
- + test/modules/demux/timestamps.c
- + test/modules/demux/ts_pes.c
Changes:
=====================================
modules/demux/Makefile.am
=====================================
@@ -261,6 +261,7 @@ libts_plugin_la_SOURCES = demux/mpeg/ts.c demux/mpeg/ts.h \
demux/mpeg/ts_metadata.c demux/mpeg/ts_metadata.h \
demux/mpeg/ts_hotfixes.c demux/mpeg/ts_hotfixes.h \
demux/mpeg/ts_strings.h demux/mpeg/ts_streams_private.h \
+ demux/mpeg/ts_pes.c demux/mpeg/ts_pes.h \
demux/mpeg/pes.h \
demux/mpeg/timestamps.h \
demux/dvb-text.h \
=====================================
modules/demux/mpeg/pes.h
=====================================
@@ -20,7 +20,9 @@
#ifndef VLC_MPEG_PES_H
#define VLC_MPEG_PES_H
-static inline bool ExtractPESTimestamp( const uint8_t *p_data, uint8_t i_flags, vlc_tick_t *ret )
+#include "timestamps.h"
+
+static inline bool ExtractPESTimestamp( const uint8_t *p_data, uint8_t i_flags, ts_90khz_t *ret )
{
/* !warn broken muxers set incorrect flags. see #17773 and #19140 */
/* check marker bits, and i_flags = b 0010, 0011 or 0001 */
@@ -32,29 +34,29 @@ static inline bool ExtractPESTimestamp( const uint8_t *p_data, uint8_t i_flags,
return false;
- *ret = ((vlc_tick_t)(p_data[ 0]&0x0e ) << 29)|
- (vlc_tick_t)(p_data[1] << 22)|
- ((vlc_tick_t)(p_data[2]&0xfe) << 14)|
- (vlc_tick_t)(p_data[3] << 7)|
- (vlc_tick_t)(p_data[4] >> 1);
+ *ret = ((ts_90khz_t)(p_data[ 0]&0x0e ) << 29)|
+ (ts_90khz_t)(p_data[1] << 22)|
+ ((ts_90khz_t)(p_data[2]&0xfe) << 14)|
+ (ts_90khz_t)(p_data[3] << 7)|
+ (ts_90khz_t)(p_data[4] >> 1);
return true;
}
/* PS SCR timestamp as defined in H222 2.5.3.2 */
-static inline vlc_tick_t ExtractPackHeaderTimestamp( const uint8_t *p_data )
+static inline ts_90khz_t ExtractPackHeaderTimestamp( const uint8_t *p_data )
{
- return ((vlc_tick_t)(p_data[ 0]&0x38 ) << 27)|
- ((vlc_tick_t)(p_data[0]&0x03 ) << 28)|
- (vlc_tick_t)(p_data[1] << 20)|
- ((vlc_tick_t)(p_data[2]&0xf8 ) << 12)|
- ((vlc_tick_t)(p_data[2]&0x03 ) << 13)|
- (vlc_tick_t)(p_data[3] << 5) |
- (vlc_tick_t)(p_data[4] >> 3);
+ return ((ts_90khz_t)(p_data[0]&0x38 ) << 27)|
+ ((ts_90khz_t)(p_data[0]&0x03 ) << 28)|
+ (ts_90khz_t)(p_data[1] << 20)|
+ ((ts_90khz_t)(p_data[2]&0xf8 ) << 12)|
+ ((ts_90khz_t)(p_data[2]&0x03 ) << 13)|
+ (ts_90khz_t)(p_data[3] << 5) |
+ (ts_90khz_t)(p_data[4] >> 3);
}
inline
static int ParsePESHeader( vlc_object_t *p_object, const uint8_t *p_header, size_t i_header,
- unsigned *pi_skip, vlc_tick_t *pi_dts, vlc_tick_t *pi_pts,
+ unsigned *pi_skip, ts_90khz_t *pi_dts, ts_90khz_t *pi_pts,
uint8_t *pi_stream_id, bool *pb_pes_scambling )
{
unsigned i_skip;
=====================================
modules/demux/mpeg/ps.h
=====================================
@@ -442,9 +442,10 @@ static inline int ps_pkt_parse_pack( block_t *p_pkt, int64_t *pi_scr,
}
else if( p_pkt->i_buffer >= 12 && (p[4] >> 4) == 0x02 ) /* MPEG-1 Pack SCR, same bits as PES/PTS */
{
- if(!ExtractPESTimestamp( &p[4], 0x02, pi_scr ))
+ ts_90khz_t i_scr;
+ if(!ExtractPESTimestamp( &p[4], 0x02, &i_scr ))
return VLC_EGENERIC;
- *pi_scr = FROM_SCALE_NZ( *pi_scr );
+ *pi_scr = FROM_SCALE_NZ( i_scr );
*pi_mux_rate = ( ( p[9]&0x7f )<< 15 )|( p[10] << 7 )|( p[11] >> 1);
}
else
@@ -494,8 +495,8 @@ static inline int ps_pkt_parse_system( block_t *p_pkt, ps_psm_t *p_psm,
static inline int ps_pkt_parse_pes( vlc_object_t *p_object, block_t *p_pes, int i_skip_extra )
{
unsigned int i_skip = 0;
- vlc_tick_t i_pts = -1;
- vlc_tick_t i_dts = -1;
+ ts_90khz_t i_pts = TS_90KHZ_INVALID;
+ ts_90khz_t i_dts = TS_90KHZ_INVALID;
uint8_t i_stream_id = 0;
bool b_pes_scrambling = false;
@@ -521,12 +522,12 @@ static inline int ps_pkt_parse_pes( vlc_object_t *p_object, block_t *p_pes, int
p_pes->i_buffer -= i_skip;
/* ISO/IEC 13818-1 2.7.5: if no pts and no dts, then dts == pts */
- if( i_pts >= 0 && i_dts < 0 )
+ if( i_pts != TS_90KHZ_INVALID && i_dts == TS_90KHZ_INVALID )
i_dts = i_pts;
- if( i_dts >= 0 )
+ if( i_dts != TS_90KHZ_INVALID )
p_pes->i_dts = FROM_SCALE( i_dts );
- if( i_pts >= 0 )
+ if( i_pts != TS_90KHZ_INVALID )
p_pes->i_pts = FROM_SCALE( i_pts );
return VLC_SUCCESS;
=====================================
modules/demux/mpeg/timestamps.h
=====================================
@@ -25,13 +25,26 @@
#define FROM_SCALE(x) (VLC_TICK_0 + FROM_SCALE_NZ(x))
#define TO_SCALE(x) TO_SCALE_NZ((x) - VLC_TICK_0)
-static inline int64_t TimeStampWrapAround( int64_t i_first_pcr, int64_t i_time )
+typedef int64_t ts_90khz_t;
+#define TS_90KHZ_INVALID -1
+
+
+#define TS_33BITS_ROLL_NZ FROM_SCALE_NZ(0x1FFFFFFFF)
+#define TS_33BITS_HALF_ROLL_NZ FROM_SCALE_NZ(0x0FFFFFFFF)
+
+static inline vlc_tick_t TimeStampWrapAround( vlc_tick_t i_past_pcr, vlc_tick_t i_time )
{
- int64_t i_adjust = 0;
- if( i_first_pcr > 0x0FFFFFFFF && i_time < 0x0FFFFFFFF )
- i_adjust = 0x1FFFFFFFF;
+ if( i_past_pcr == VLC_TICK_INVALID || i_time >= i_past_pcr )
+ return i_time;
+
+ vlc_tick_t delta = i_past_pcr - i_time;
+ if( delta >= TS_33BITS_HALF_ROLL_NZ )
+ {
+ vlc_tick_t rolls = (delta + TS_33BITS_ROLL_NZ - 1) / TS_33BITS_ROLL_NZ;
+ i_time += rolls * TS_33BITS_ROLL_NZ;
+ }
- return i_time + i_adjust;
+ return i_time;
}
#endif
=====================================
modules/demux/mpeg/ts.c
=====================================
@@ -39,6 +39,7 @@
#include "ts_pid.h"
#include "ts_streams.h"
#include "ts_streams_private.h"
+#include "ts_pes.h"
#include "ts_psi.h"
#include "ts_si.h"
#include "ts_psip.h"
@@ -188,17 +189,17 @@ static inline int PIDGet( block_t *p )
{
return ( (p->p_buffer[1]&0x1f)<<8 )|p->p_buffer[2];
}
-static vlc_tick_t GetPCR( const block_t * );
+static ts_90khz_t GetPCR( const block_t * );
static block_t * ProcessTSPacket( demux_t *p_demux, ts_pid_t *pid, block_t *p_pkt, int * );
-static bool GatherPESData( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk, size_t );
static bool GatherSectionsData( demux_t *p_demux, ts_pid_t *, block_t *, size_t );
+static bool GatherPESData( demux_t *p_demux, ts_pid_t *, block_t *, size_t );
static void ProgramSetPCR( demux_t *p_demux, ts_pmt_t *p_prg, vlc_tick_t i_pcr );
static block_t* ReadTSPacket( demux_t *p_demux );
-static int SeekToTime( demux_t *p_demux, const ts_pmt_t *, int64_t time );
+static int SeekToTime( demux_t *p_demux, const ts_pmt_t *, vlc_tick_t time );
static void ReadyQueuesPostSeek( demux_t *p_demux );
-static void PCRHandle( demux_t *p_demux, ts_pid_t *, vlc_tick_t );
+static void PCRHandle( demux_t *p_demux, ts_pid_t *, ts_90khz_t );
static void PCRFixHandle( demux_t *, ts_pmt_t *, block_t * );
#define TS_PACKET_SIZE_188 188
@@ -409,7 +410,7 @@ static int Open( vlc_object_t *p_this )
vlc_dictionary_init( &p_sys->attachments, 0 );
- p_sys->patfix.i_first_dts = -1;
+ p_sys->patfix.i_first_dts = VLC_TICK_INVALID;
p_sys->patfix.i_timesourcepid = 0;
p_sys->patfix.status = var_CreateGetBool( p_demux, "ts-patfix" ) ? PAT_WAITING : PAT_FIXTRIED;
@@ -690,8 +691,8 @@ static int Demux( demux_t *p_demux )
}
/* Adaptation field cannot be scrambled */
- vlc_tick_t i_pcr = GetPCR( p_pkt );
- if( i_pcr > VLC_TICK_INVALID )
+ ts_90khz_t i_pcr = GetPCR( p_pkt );
+ if( i_pcr != TS_90KHZ_INVALID )
PCRHandle( p_demux, p_pid, i_pcr );
/* Probe streams to build PAT/PMT after MIN_PAT_INTERVAL in case we don't see any PAT */
@@ -930,14 +931,13 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
if( !p_sys->b_ignore_time_for_positions &&
p_pmt &&
- p_pmt->pcr.i_first > -1 && p_pmt->i_last_dts > VLC_TICK_INVALID &&
- p_pmt->pcr.i_current > -1 )
+ p_pmt->pcr.i_first != VLC_TICK_INVALID &&
+ p_pmt->i_last_dts != VLC_TICK_INVALID &&
+ p_pmt->pcr.i_current != VLC_TICK_INVALID )
{
- double i_length = TimeStampWrapAround( p_pmt->pcr.i_first,
- p_pmt->i_last_dts ) - p_pmt->pcr.i_first;
+ double i_length = p_pmt->i_last_dts - p_pmt->pcr.i_first;
i_length += p_pmt->pcr.i_pcroffset;
- double i_pos = TimeStampWrapAround( p_pmt->pcr.i_first,
- p_pmt->pcr.i_current ) - p_pmt->pcr.i_first;
+ double i_pos = p_pmt->pcr.i_current - p_pmt->pcr.i_first;
if( i_length > 0 )
{
*pf = i_pos / i_length;
@@ -963,30 +963,30 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
if( p_sys->b_access_control &&
!p_sys->b_ignore_time_for_positions && b_bool && p_pmt )
{
- time_t i_time, i_length;
+ time_t i_time, i_length = 0;
+ vlc_tick_t i_seektime = VLC_TICK_0 + vlc_tick_from_sec( i_length * f );
if( !EITCurrentEventTime( p_pmt, p_sys, &i_time, &i_length ) &&
- i_length > 0 && !SeekToTime( p_demux, p_pmt, (int64_t)(TO_SCALE(i_length * CLOCK_FREQ) * f) ) )
+ i_length > 0 && !SeekToTime( p_demux, p_pmt, i_seektime ) )
{
ReadyQueuesPostSeek( p_demux );
- es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
- (int64_t)(TO_SCALE(i_length * CLOCK_FREQ) * f) );
+ es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_seektime );
return VLC_SUCCESS;
}
}
if( !p_sys->b_ignore_time_for_positions && b_bool && p_pmt &&
- p_pmt->pcr.i_first > -1 && p_pmt->i_last_dts > VLC_TICK_INVALID &&
- p_pmt->pcr.i_current > -1 )
+ p_pmt->pcr.i_first != VLC_TICK_INVALID &&
+ p_pmt->i_last_dts != VLC_TICK_INVALID &&
+ p_pmt->pcr.i_current != VLC_TICK_INVALID )
{
- int64_t i_length = TimeStampWrapAround( p_pmt->pcr.i_first,
- p_pmt->i_last_dts ) - p_pmt->pcr.i_first;
- i64 = p_pmt->pcr.i_first + (int64_t)(i_length * f);
+ vlc_tick_t i_length = p_pmt->i_last_dts - p_pmt->pcr.i_first;
+ i64 = p_pmt->pcr.i_first + i_length * f;
if( i64 <= p_pmt->i_last_dts )
{
if( !SeekToTime( p_demux, p_pmt, i64 ) )
{
ReadyQueuesPostSeek( p_demux );
- es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, FROM_SCALE(i64) );
+ es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i64 );
return VLC_SUCCESS;
}
}
@@ -1004,12 +1004,12 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
case DEMUX_SET_TIME:
i64 = va_arg( args, int64_t );
- if( p_sys->b_canseek && p_pmt && p_pmt->pcr.i_first > -1 &&
- !SeekToTime( p_demux, p_pmt, p_pmt->pcr.i_first + TO_SCALE(i64) ) )
+ if( p_sys->b_canseek && p_pmt && p_pmt->pcr.i_first != VLC_TICK_INVALID &&
+ !SeekToTime( p_demux, p_pmt, p_pmt->pcr.i_first + i64 ) )
{
ReadyQueuesPostSeek( p_demux );
es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
- FROM_SCALE(p_pmt->pcr.i_first) + i64 - VLC_TICK_0 );
+ p_pmt->pcr.i_first + i64 - VLC_TICK_0 );
return VLC_SUCCESS;
}
break;
@@ -1027,10 +1027,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
}
}
- if( p_pmt && p_pmt->pcr.i_current > -1 && p_pmt->pcr.i_first > -1 )
+ if( p_pmt && p_pmt->pcr.i_current != VLC_TICK_INVALID && p_pmt->pcr.i_first != VLC_TICK_INVALID )
{
- int64_t i_pcr = TimeStampWrapAround( p_pmt->pcr.i_first, p_pmt->pcr.i_current );
- *pi64 = FROM_SCALE(i_pcr - p_pmt->pcr.i_first);
+ *pi64 = p_pmt->pcr.i_current - p_pmt->pcr.i_first;
return VLC_SUCCESS;
}
break;
@@ -1050,14 +1049,14 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
if( !p_sys->b_ignore_time_for_positions &&
p_pmt &&
- ( p_pmt->pcr.i_first > -1 || p_pmt->pcr.i_first_dts > VLC_TICK_INVALID ) &&
- p_pmt->i_last_dts > 0 )
+ ( p_pmt->pcr.i_first != VLC_TICK_INVALID || p_pmt->pcr.i_first_dts != VLC_TICK_INVALID ) &&
+ p_pmt->i_last_dts != VLC_TICK_INVALID )
{
- int64_t i_start = (p_pmt->pcr.i_first > -1) ? p_pmt->pcr.i_first :
- TO_SCALE(p_pmt->pcr.i_first_dts);
- int64_t i_last = TimeStampWrapAround( p_pmt->pcr.i_first, p_pmt->i_last_dts );
+ vlc_tick_t i_start = (p_pmt->pcr.i_first != VLC_TICK_INVALID) ? p_pmt->pcr.i_first :
+ p_pmt->pcr.i_first_dts;
+ vlc_tick_t i_last = p_pmt->i_last_dts;
i_last += p_pmt->pcr.i_pcroffset;
- *pi64 = FROM_SCALE(i_last - i_start);
+ *pi64 = i_last - i_start;
return VLC_SUCCESS;
}
break;
@@ -1319,6 +1318,33 @@ invalid:
return NULL;
}
+static vlc_tick_t GetTimeForUntimed( const ts_pmt_t *p_pmt )
+{
+ vlc_tick_t i_ts = p_pmt->pcr.i_current;
+ const ts_stream_t *p_cand = NULL;
+ for( int i=0; i< p_pmt->e_streams.i_size; i++ )
+ {
+ const ts_pid_t *p_pid = p_pmt->e_streams.p_elems[i];
+ if( (p_pid->i_flags & FLAG_FILTERED) && SEEN(p_pid) &&
+ p_pid->type == TYPE_STREAM &&
+ p_pid->u.p_stream->p_es &&
+ p_pid->u.p_stream->i_last_dts != VLC_TICK_INVALID )
+ {
+ const ts_es_t *p_es = p_pid->u.p_stream->p_es;
+ if( p_es->fmt.i_cat == VIDEO_ES || p_es->fmt.i_cat == AUDIO_ES )
+ {
+ if( !p_cand || (p_es->fmt.i_cat == VIDEO_ES &&
+ p_cand->p_es->fmt.i_cat != VIDEO_ES) )
+ {
+ p_cand = p_pid->u.p_stream;
+ i_ts = p_cand->i_last_dts;
+ }
+ }
+ }
+ }
+ return i_ts;
+}
+
static block_t * ConvertPESBlock( demux_t *p_demux, ts_es_t *p_es,
size_t i_pes_size, uint8_t i_stream_id,
block_t *p_block )
@@ -1339,13 +1365,21 @@ static block_t * ConvertPESBlock( demux_t *p_demux, ts_es_t *p_es,
}
else if( p_es->fmt.i_codec == VLC_CODEC_TELETEXT )
{
- if( p_block->i_pts <= VLC_TICK_INVALID )
+ const ts_pmt_t *p_pmt = p_es->p_program;
+ if( p_block->i_pts != VLC_TICK_INVALID &&
+ p_pmt->pcr.i_current != VLC_TICK_INVALID )
+ {
+ /* Teletext can have totally offset timestamps... RAI1, German */
+ if( p_pmt->pcr.i_current < p_block->i_pts || p_pmt->pcr.i_current - p_block->i_pts > CLOCK_FREQ )
+ p_block->i_dts = p_block->i_pts = VLC_TICK_INVALID;
+ }
+ if( p_block->i_pts == VLC_TICK_INVALID )
{
/* Teletext may have missing PTS (ETSI EN 300 472 Annexe A)
* In this case use the last PCR + 40ms */
- vlc_tick_t i_pcr = p_es->p_program->pcr.i_current;
- if( i_pcr > VLC_TICK_INVALID )
- p_block->i_pts = FROM_SCALE(i_pcr) + 40000;
+ vlc_tick_t i_ts = GetTimeForUntimed( p_es->p_program );
+ if( i_ts != VLC_TICK_INVALID )
+ p_block->i_dts = p_block->i_pts = i_ts + VLC_TICK_FROM_MS(40);
}
}
else if( p_es->fmt.i_codec == VLC_CODEC_ARIB_A ||
@@ -1448,14 +1482,16 @@ static void SendDataChain( demux_t *p_demux, ts_es_t *p_es, block_t *p_chain )
* gathering stuff
****************************************************************************/
static void ParsePESDataChain( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes,
- int64_t i_append_pcr )
+ ts_90khz_t i_append_pcr )
{
uint8_t header[34];
unsigned i_pes_size = 0;
unsigned i_skip = 0;
- vlc_tick_t i_dts = -1;
- vlc_tick_t i_pts = -1;
- vlc_tick_t i_length = 0;
+ ts_90khz_t i_pktdts = TS_90KHZ_INVALID;
+ ts_90khz_t i_pktpts = TS_90KHZ_INVALID;
+ ts_90khz_t i_length = 0;
+ vlc_tick_t i_dts = VLC_TICK_INVALID;
+ vlc_tick_t i_pts = VLC_TICK_INVALID;
uint8_t i_stream_id;
bool b_pes_scrambling = false;
const es_mpeg4_descriptor_t *p_mpeg4desc = NULL;
@@ -1486,17 +1522,17 @@ static void ParsePESDataChain( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes,
ts_es_t *p_es = pid->u.p_stream->p_es;
if( ParsePESHeader( VLC_OBJECT(p_demux), (uint8_t*)&header, i_max, &i_skip,
- &i_dts, &i_pts, &i_stream_id, &b_pes_scrambling ) == VLC_EGENERIC )
+ &i_pktdts, &i_pktpts, &i_stream_id, &b_pes_scrambling ) == VLC_EGENERIC )
{
block_ChainRelease( p_pes );
return;
}
else
{
- if( i_pts != -1 && p_es->p_program )
- i_pts = TimeStampWrapAround( p_es->p_program->pcr.i_first, i_pts );
- if( i_dts != -1 && p_es->p_program )
- i_dts = TimeStampWrapAround( p_es->p_program->pcr.i_first, i_dts );
+ if( i_pktpts != TS_90KHZ_INVALID && p_es->p_program )
+ i_pts = TimeStampWrapAround( p_es->p_program->pcr.i_first, FROM_SCALE(i_pktpts) );
+ if( i_pktdts != TS_90KHZ_INVALID && p_es->p_program )
+ i_dts = TimeStampWrapAround( p_es->p_program->pcr.i_first, FROM_SCALE(i_pktdts) );
if( b_pes_scrambling )
p_pes->i_flags |= BLOCK_FLAG_SCRAMBLED;
}
@@ -1555,9 +1591,12 @@ static void ParsePESDataChain( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes,
}
/* ISO/IEC 13818-1 2.7.5: if no pts and no dts, then dts == pts */
- if( i_pts >= 0 && i_dts < 0 )
+ if( i_pts != VLC_TICK_INVALID && i_dts == VLC_TICK_INVALID )
i_dts = i_pts;
+ if( i_dts != TS_90KHZ_INVALID )
+ pid->u.p_stream->i_last_dts = i_dts;
+
if( p_pes )
{
ts_pmt_t *p_pmt = p_es->p_program;
@@ -1567,11 +1606,11 @@ static void ParsePESDataChain( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes,
return;
}
- if( i_dts >= 0 )
- p_pes->i_dts = FROM_SCALE(i_dts);
+ if( i_dts != VLC_TICK_INVALID )
+ p_pes->i_dts = i_dts;
- if( i_pts >= 0 )
- p_pes->i_pts = FROM_SCALE(i_pts);
+ if( i_pts != VLC_TICK_INVALID )
+ p_pes->i_pts = i_pts;
p_pes->i_length = FROM_SCALE_NZ(i_length);
@@ -1585,7 +1624,7 @@ static void ParsePESDataChain( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes,
if( !p_pmt->pcr.b_fix_done ) /* Not seen yet */
PCRFixHandle( p_demux, p_pmt, p_block );
- if( p_es->id && (p_pmt->pcr.i_current > -1 || p_pmt->pcr.b_disable) )
+ if( p_es->id && (p_pmt->pcr.i_current != VLC_TICK_INVALID || p_pmt->pcr.b_disable) )
{
if( pid->u.p_stream->prepcr.p_head )
{
@@ -1603,34 +1642,31 @@ static void ParsePESDataChain( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes,
if ( p_pmt->pcr.b_disable && p_block->i_dts > VLC_TICK_INVALID &&
( p_pmt->i_pid_pcr == pid->i_pid || p_pmt->i_pid_pcr == 0x1FFF ) )
{
- ProgramSetPCR( p_demux, p_pmt, TO_SCALE(p_block->i_dts) - 120000 );
+ ProgramSetPCR( p_demux, p_pmt, p_block->i_dts - 120000 );
}
/* Compute PCR/DTS offset if any */
- int64_t i_pcrref = i_append_pcr > VLC_TICK_INVALID ? i_append_pcr : p_pmt->pcr.i_first;
- if( p_pmt->pcr.i_pcroffset == -1 && p_block->i_dts > VLC_TICK_INVALID &&
- i_pcrref > VLC_TICK_INVALID &&
- (p_es->fmt.i_cat == VIDEO_ES || p_es->fmt.i_cat == AUDIO_ES) )
+ vlc_tick_t i_pcrref = (i_append_pcr != TS_90KHZ_INVALID) ? FROM_SCALE(i_append_pcr) : p_pmt->pcr.i_first;
+ if( p_pmt->pcr.i_pcroffset == -1 && p_block->i_dts != VLC_TICK_INVALID &&
+ i_pcrref != VLC_TICK_INVALID &&
+ (p_es->fmt.i_cat == VIDEO_ES || p_es->fmt.i_cat == AUDIO_ES) )
{
- int64_t i_dts27 = TO_SCALE(p_block->i_dts);
- i_dts27 = TimeStampWrapAround( i_pcrref, i_dts27 );
- i_pcrref = TimeStampWrapAround( p_pmt->pcr.i_first, i_pcrref );
- if( i_dts27 + (CLOCK_FREQ/90000) < i_pcrref )
+ if( p_block->i_dts + FROM_SCALE_NZ(CLOCK_FREQ/90000) < i_pcrref )
{
- p_pmt->pcr.i_pcroffset = i_pcrref - i_dts27 + TO_SCALE_NZ(80000);
+ p_pmt->pcr.i_pcroffset = i_pcrref - p_block->i_dts + VLC_TICK_FROM_MS(80);
msg_Warn( p_demux, "Broken stream: pid %d sends packets with dts %"PRId64
"us later than pcr, applying delay",
- pid->i_pid, FROM_SCALE_NZ(i_pcrref - i_dts27) );
+ pid->i_pid, i_pcrref - p_block->i_dts );
}
else p_pmt->pcr.i_pcroffset = 0;
}
if( p_pmt->pcr.i_pcroffset != -1 )
{
- if( p_block->i_dts > VLC_TICK_INVALID )
- p_block->i_dts += FROM_SCALE_NZ(p_pmt->pcr.i_pcroffset);
- if( p_block->i_pts > VLC_TICK_INVALID )
- p_block->i_pts += FROM_SCALE_NZ(p_pmt->pcr.i_pcroffset);
+ if( p_block->i_dts != VLC_TICK_INVALID )
+ p_block->i_dts += p_pmt->pcr.i_pcroffset;
+ if( p_block->i_pts != VLC_TICK_INVALID )
+ p_block->i_pts += p_pmt->pcr.i_pcroffset;
}
/*** From here, block can become a chain again though conversion below ***/
@@ -1657,7 +1693,7 @@ static void ParsePESDataChain( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes,
block_ChainLastAppend( &pid->u.p_stream->prepcr.pp_last, p_block );
/* PCR Seen and no es->id, cleanup current and prepcr blocks */
- if( p_pmt->pcr.i_current > -1)
+ if( p_pmt->pcr.i_current != VLC_TICK_INVALID )
{
block_ChainRelease( pid->u.p_stream->prepcr.p_head );
pid->u.p_stream->prepcr.p_head = NULL;
@@ -1672,49 +1708,9 @@ static void ParsePESDataChain( demux_t *p_demux, ts_pid_t *pid, block_t *p_pes,
}
}
-static bool PushPESBlock( demux_t *p_demux, ts_pid_t *pid, block_t *p_pkt, bool b_unit_start,
- int64_t i_append_pcr )
+static void PESDataChainHandle( vlc_object_t *p_obj, void *priv, block_t *p_data, ts_90khz_t i_append_pcr )
{
- bool b_ret = false;
- ts_stream_t *p_pes = pid->u.p_stream;
-
- if ( b_unit_start && p_pes->gather.p_data )
- {
- block_t *p_datachain = p_pes->gather.p_data;
- /* Flush the pes from pid */
- p_pes->gather.p_data = NULL;
- p_pes->gather.i_data_size = 0;
- p_pes->gather.i_gathered = 0;
- p_pes->gather.pp_last = &p_pes->gather.p_data;
- ParsePESDataChain( p_demux, pid, p_datachain, p_pes->gather.i_append_pcr );
- b_ret = true;
- }
-
- if( b_unit_start )
- p_pes->gather.i_append_pcr = i_append_pcr;
-
- if( p_pkt == NULL )
- return b_ret;
-
- if( !b_unit_start && p_pes->gather.p_data == NULL )
- {
- /* msg_Dbg( p_demux, "broken packet" ); */
- block_Release( p_pkt );
- return b_ret;
- }
-
- block_ChainLastAppend( &p_pes->gather.pp_last, p_pkt );
- p_pes->gather.i_gathered += p_pkt->i_buffer;
-
- if( p_pes->gather.i_data_size > 0 &&
- p_pes->gather.i_gathered >= p_pes->gather.i_data_size )
- {
- /* re-enter in Flush above */
- assert(p_pes->gather.p_data);
- return PushPESBlock( p_demux, pid, NULL, true, i_append_pcr );
- }
-
- return b_ret;
+ ParsePESDataChain( (demux_t *)p_obj, (ts_pid_t *) priv, p_data, i_append_pcr );
}
static block_t* ReadTSPacket( demux_t *p_demux )
@@ -1795,11 +1791,11 @@ static block_t* ReadTSPacket( demux_t *p_demux )
return p_pkt;
}
-static vlc_tick_t GetPCR( const block_t *p_pkt )
+static ts_90khz_t GetPCR( const block_t *p_pkt )
{
const uint8_t *p = p_pkt->p_buffer;
- vlc_tick_t i_pcr = -1;
+ ts_90khz_t i_pcr = TS_90KHZ_INVALID;
if(unlikely(p_pkt->i_buffer < 12))
return i_pcr;
@@ -1812,11 +1808,11 @@ static vlc_tick_t GetPCR( const block_t *p_pkt )
( p[5] & 0x10 ) ) /* PCR carry flag */
{
/* PCR is 33 bits */
- i_pcr = ( (vlc_tick_t)p[6] << 25 ) |
- ( (vlc_tick_t)p[7] << 17 ) |
- ( (vlc_tick_t)p[8] << 9 ) |
- ( (vlc_tick_t)p[9] << 1 ) |
- ( (vlc_tick_t)p[10] >> 7 );
+ i_pcr = ( (ts_90khz_t)p[6] << 25 ) |
+ ( (ts_90khz_t)p[7] << 17 ) |
+ ( (ts_90khz_t)p[8] << 9 ) |
+ ( (ts_90khz_t)p[9] << 1 ) |
+ ( (ts_90khz_t)p[10] >> 7 );
}
return i_pcr;
}
@@ -1882,7 +1878,7 @@ static void ReadyQueuesPostSeek( demux_t *p_demux )
for( ts_es_t *p_es = p_pes->p_es; p_es; p_es = p_es->p_next )
p_es->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY;
- pid->i_cc = 0xff;
+ pid->u.p_stream->i_last_dts = VLC_TICK_INVALID;
if( pid->u.p_stream->prepcr.p_head )
{
@@ -1896,16 +1892,16 @@ static void ReadyQueuesPostSeek( demux_t *p_demux )
FlushESBuffer( pid->u.p_stream );
}
- p_pmt->pcr.i_current = -1;
+ p_pmt->pcr.i_current = VLC_TICK_INVALID;
}
}
-static int SeekToTime( demux_t *p_demux, const ts_pmt_t *p_pmt, int64_t i_scaledtime )
+static int SeekToTime( demux_t *p_demux, const ts_pmt_t *p_pmt, vlc_tick_t i_seektime )
{
demux_sys_t *p_sys = p_demux->p_sys;
/* Deal with common but worst binary search case */
- if( p_pmt->pcr.i_first == i_scaledtime && p_sys->b_canseek )
+ if( p_pmt->pcr.i_first == i_seektime && p_sys->b_canseek )
return vlc_stream_Seek( p_sys->stream, 0 );
const int64_t i_stream_size = stream_Size( p_sys->stream );
@@ -1934,7 +1930,7 @@ static int SeekToTime( demux_t *p_demux, const ts_pmt_t *p_pmt, int64_t i_scaled
uint64_t i_pos = i_splitpos;
while( i_pos < i_tail_pos )
{
- int64_t i_pcr = -1;
+ ts_90khz_t i_pktpcr = TS_90KHZ_INVALID;
block_t *p_pkt = ReadTSPacket( p_demux );
if( !p_pkt )
{
@@ -1954,37 +1950,37 @@ static int SeekToTime( demux_t *p_demux, const ts_pmt_t *p_pmt, int64_t i_scaled
if( p_pkt->i_buffer >= 4 + 2 + 5 )
{
if( p_pmt->i_pid_pcr == i_pid )
- i_pcr = GetPCR( p_pkt );
+ i_pktpcr = GetPCR( p_pkt );
i_skip += 1 + __MIN(p_pkt->p_buffer[4], 182);
}
}
- if( i_pcr == -1 && p_pid->type == TYPE_STREAM &&
+ if( i_pktpcr == TS_90KHZ_INVALID && p_pid->type == TYPE_STREAM &&
ts_stream_Find_es( p_pid->u.p_stream, p_pmt ) &&
(p_pkt->p_buffer[1] & 0xC0) == 0x40 && /* Payload start but not corrupt */
(p_pkt->p_buffer[3] & 0xD0) == 0x10 /* Has payload but is not encrypted */
)
{
- vlc_tick_t i_dts = -1;
- vlc_tick_t i_pts = -1;
+ ts_90khz_t i_pktdts = TS_90KHZ_INVALID;
+ ts_90khz_t i_pktpts = TS_90KHZ_INVALID;
uint8_t i_stream_id;
if ( VLC_SUCCESS == ParsePESHeader( VLC_OBJECT(p_demux), &p_pkt->p_buffer[i_skip],
p_pkt->i_buffer - i_skip, &i_skip,
- &i_dts, &i_pts, &i_stream_id, NULL ) )
+ &i_pktdts, &i_pktpts, &i_stream_id, NULL ) )
{
- if( i_dts > -1 )
- i_pcr = i_dts;
+ if( i_pktdts != TS_90KHZ_INVALID )
+ i_pktpcr = i_pktdts;
}
}
}
block_Release( p_pkt );
- if( i_pcr != -1 )
+ if( i_pktpcr != TS_90KHZ_INVALID )
{
- int64_t i_diff = i_scaledtime - TimeStampWrapAround( p_pmt->pcr.i_first, i_pcr );
+ vlc_tick_t i_diff = i_seektime - TimeStampWrapAround( p_pmt->pcr.i_first, FROM_SCALE(i_pktpcr) );
if ( i_diff < 0 )
i_tail_pos = (i_splitpos >= p_sys->i_packet_size) ? i_splitpos - p_sys->i_packet_size : 0;
- else if( i_diff < TO_SCALE(VLC_TICK_0 + CLOCK_FREQ / 2) ) // 500ms
+ else if( i_diff < CLOCK_FREQ / 2 ) // 500ms
b_found = true;
else
i_head_pos = i_pos;
@@ -2005,7 +2001,7 @@ static int SeekToTime( demux_t *p_demux, const ts_pmt_t *p_pmt, int64_t i_scaled
return VLC_SUCCESS;
}
-static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_pcr, bool *pb_found )
+static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, ts_90khz_t *pi_pcr, bool *pb_found )
{
demux_sys_t *p_sys = p_demux->p_sys;
int i_count = 0;
@@ -2013,7 +2009,7 @@ static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_
for( ;; )
{
- *pi_pcr = -1;
+ *pi_pcr = TS_90KHZ_INVALID;
if( i_count++ > PROBE_CHUNK_COUNT || !( p_pkt = ReadTSPacket( p_demux ) ) )
{
@@ -2040,7 +2036,7 @@ static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_
if( b_adaptfield && p_pkt->i_buffer >= 4 + 2 + 5 )
*pi_pcr = GetPCR( p_pkt );
- if( *pi_pcr == -1 &&
+ if( *pi_pcr == TS_90KHZ_INVALID &&
(p_pkt->p_buffer[1] & 0xC0) == 0x40 && /* payload start */
(p_pkt->p_buffer[3] & 0xD0) == 0x10 && /* Has payload but is not encrypted */
p_pid->type == TYPE_STREAM &&
@@ -2048,8 +2044,8 @@ static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_
)
{
b_pcrresult = false;
- vlc_tick_t i_dts = -1;
- vlc_tick_t i_pts = -1;
+ ts_90khz_t i_dts = TS_90KHZ_INVALID;
+ ts_90khz_t i_pts = TS_90KHZ_INVALID;
uint8_t i_stream_id;
unsigned i_skip = 4;
if ( b_adaptfield ) // adaptation field
@@ -2059,14 +2055,14 @@ static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_
p_pkt->i_buffer - i_skip, &i_skip,
&i_dts, &i_pts, &i_stream_id, NULL ) )
{
- if( i_dts != -1 )
+ if( i_dts != TS_90KHZ_INVALID )
*pi_pcr = i_dts;
- else if( i_pts != -1 )
+ else if( i_pts != TS_90KHZ_INVALID )
*pi_pcr = i_pts;
}
}
- if( *pi_pcr != -1 )
+ if( *pi_pcr != TS_90KHZ_INVALID )
{
ts_pat_t *p_pat = GetPID(p_sys, 0)->u.p_pat;
for( int i=0; i<p_pat->programs.i_size; i++ )
@@ -2079,15 +2075,15 @@ static int ProbeChunk( demux_t *p_demux, int i_program, bool b_end, int64_t *pi_
{
if( b_end )
{
- p_pmt->i_last_dts = *pi_pcr;
+ p_pmt->i_last_dts = FROM_SCALE(*pi_pcr);
p_pmt->i_last_dts_byte = vlc_stream_Tell( p_sys->stream );
}
/* Start, only keep first */
- else if( b_pcrresult && p_pmt->pcr.i_first == -1 )
+ else if( b_pcrresult && p_pmt->pcr.i_first == VLC_TICK_INVALID )
{
- p_pmt->pcr.i_first = *pi_pcr;
+ p_pmt->pcr.i_first = FROM_SCALE(*pi_pcr);
}
- else if( p_pmt->pcr.i_first_dts < VLC_TICK_0 )
+ else if( p_pmt->pcr.i_first_dts == VLC_TICK_INVALID )
{
p_pmt->pcr.i_first_dts = FROM_SCALE(*pi_pcr);
}
@@ -2113,7 +2109,7 @@ int ProbeStart( demux_t *p_demux, int i_program )
int i_probe_count = 0;
int64_t i_pos;
- vlc_tick_t i_pcr = -1;
+ ts_90khz_t i_pcr = TS_90KHZ_INVALID;
bool b_found = false;
do
@@ -2145,7 +2141,7 @@ int ProbeEnd( demux_t *p_demux, int i_program )
int i_probe_count = PROBE_CHUNK_COUNT;
int64_t i_pos;
- vlc_tick_t i_pcr = -1;
+ ts_90khz_t i_pcr = TS_90KHZ_INVALID;
bool b_found = false;
do
@@ -2175,9 +2171,9 @@ static void ProgramSetPCR( demux_t *p_demux, ts_pmt_t *p_pmt, vlc_tick_t i_pcr )
/* Check if we have enqueued blocks waiting the/before the
PCR barrier, and then adapt pcr so they have valid PCR when dequeuing */
- if( p_pmt->pcr.i_current == -1 && p_pmt->pcr.b_fix_done )
+ if( p_pmt->pcr.i_current == VLC_TICK_INVALID && p_pmt->pcr.b_fix_done )
{
- vlc_tick_t i_mindts = -1;
+ vlc_tick_t i_mindts = VLC_TS_INVALID;
ts_pat_t *p_pat = GetPID(p_sys, 0)->u.p_pat;
for( int i=0; i< p_pat->programs.i_size; i++ )
@@ -2190,7 +2186,7 @@ static void ProgramSetPCR( demux_t *p_demux, ts_pmt_t *p_pmt, vlc_tick_t i_pcr )
while( p_block && p_block->i_dts == VLC_TICK_INVALID )
p_block = p_block->p_next;
- if( p_block && ( i_mindts == -1 || p_block->i_dts < i_mindts ) )
+ if( p_block && ( i_mindts == VLC_TS_INVALID || p_block->i_dts < i_mindts ) )
i_mindts = p_block->i_dts;
}
}
@@ -2198,20 +2194,21 @@ static void ProgramSetPCR( demux_t *p_demux, ts_pmt_t *p_pmt, vlc_tick_t i_pcr )
if( i_mindts > VLC_TICK_INVALID )
{
msg_Dbg( p_demux, "Program %d PCR prequeue fixup %"PRId64"->%"PRId64,
- p_pmt->i_number, TO_SCALE(i_mindts), i_pcr );
- i_pcr = TO_SCALE(i_mindts);
+ p_pmt->i_number, i_mindts, i_pcr );
+ i_pcr = i_mindts;
}
}
p_pmt->pcr.i_current = i_pcr;
- if( p_pmt->pcr.i_first == -1 )
+
+ if( p_pmt->pcr.i_first == VLC_TICK_INVALID )
{
p_pmt->pcr.i_first = i_pcr; // now seen
}
if ( p_sys->i_pmt_es )
{
- es_out_Control( p_demux->out, ES_OUT_SET_GROUP_PCR, p_pmt->i_number, FROM_SCALE(i_pcr) );
+ es_out_Control( p_demux->out, ES_OUT_SET_GROUP_PCR, p_pmt->i_number, i_pcr );
/* growing files/named fifo handling */
if( p_sys->b_access_control == false &&
vlc_stream_Tell( p_sys->stream ) > p_pmt->i_last_dts_byte )
@@ -2279,40 +2276,45 @@ static void PCRCheckDTS( demux_t *p_demux, ts_pmt_t *p_pmt, vlc_tick_t i_pcr)
continue;
unsigned i_skip = 0;
- vlc_tick_t i_dts = -1;
- vlc_tick_t i_pts = -1;
+ ts_90khz_t i_pktdts = TS_90KHZ_INVALID;
+ ts_90khz_t i_pktpts = TS_90KHZ_INVALID;
+ vlc_tick_t i_dts = VLC_TICK_INVALID;
+ vlc_tick_t i_pts = VLC_TICK_INVALID;
uint8_t i_stream_id;
if( ParsePESHeader( VLC_OBJECT(p_demux), (uint8_t*)&header, i_max, &i_skip,
- &i_dts, &i_pts, &i_stream_id, NULL ) == VLC_EGENERIC )
+ &i_pktdts, &i_pktpts, &i_stream_id, NULL ) == VLC_EGENERIC )
continue;
+ if( i_pktdts != TS_90KHZ_INVALID )
+ i_dts = TimeStampWrapAround( i_pcr, FROM_SCALE(i_pktdts) );
+ if( i_pktpts > TS_90KHZ_INVALID )
+ i_pts = TimeStampWrapAround( i_pcr, FROM_SCALE(i_pktpts) );
+
if (p_pmt->pcr.i_pcroffset > 0) {
- if( i_dts > VLC_TICK_INVALID )
+ if( i_dts != VLC_TICK_INVALID )
i_dts += p_pmt->pcr.i_pcroffset;
- if( i_pts > VLC_TICK_INVALID )
+ if( i_pts != VLC_TICK_INVALID )
i_pts += p_pmt->pcr.i_pcroffset;
}
- if( i_dts > VLC_TICK_INVALID )
- i_dts = TimeStampWrapAround( i_pcr, i_dts );
- if( i_pts > VLC_TICK_INVALID )
- i_pts = TimeStampWrapAround( i_pcr, i_pts );
-
- if(( i_dts > VLC_TICK_INVALID && i_dts <= i_pcr ) ||
- ( i_pts > VLC_TICK_INVALID && i_pts <= i_pcr ))
+ if(( i_dts != VLC_TICK_INVALID && i_dts <= i_pcr ) ||
+ ( i_pts != VLC_TICK_INVALID && i_pts <= i_pcr ))
{
if( IsVideoEnd( p_pid ) )
{
msg_Warn( p_demux, "send queued data for pid %d: TS %"PRId64" <= PCR %"PRId64"\n",
- p_pid->i_pid, i_dts > VLC_TICK_INVALID ? i_dts : i_pts, i_pcr);
- PushPESBlock( p_demux, p_pid, NULL, true, VLC_TICK_INVALID ); /* Flush */
+ p_pid->i_pid, i_dts != VLC_TICK_INVALID ? i_dts : i_pts, i_pcr);
+ ts_pes_parse_callback cb = { .p_obj = VLC_OBJECT(p_demux),
+ .priv = p_pid,
+ .pf_parse = PESDataChainHandle };
+ ts_pes_Drain( &cb, p_pes );
}
}
}
}
-static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, vlc_tick_t i_pcr )
+static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, ts_90khz_t i_pcr )
{
demux_sys_t *p_sys = p_demux->p_sys;
@@ -2331,7 +2333,12 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, vlc_tick_t i_pcr )
ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt;
if( p_pmt->pcr.b_disable )
continue;
- vlc_tick_t i_program_pcr = TimeStampWrapAround( p_pmt->pcr.i_first, i_pcr );
+
+ vlc_tick_t i_past_pcr = p_pmt->pcr.i_current;
+ if( i_past_pcr == VLC_TICK_INVALID )
+ i_past_pcr = p_pmt->pcr.i_first;
+
+ vlc_tick_t i_program_pcr = TimeStampWrapAround( i_past_pcr, FROM_SCALE(i_pcr) );
if( p_pmt->i_pid_pcr == 0x1FFF ) /* That program has no dedicated PCR pid ISO/IEC 13818-1 2.4.4.9 */
{
@@ -2347,7 +2354,7 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *pid, vlc_tick_t i_pcr )
if( p_pmt->i_pid_pcr == pid->i_pid ) /* If that program references current pid as PCR */
{
/* We've found a target group for update */
- PCRCheckDTS( p_demux, p_pmt, i_pcr );
+ PCRCheckDTS( p_demux, p_pmt, FROM_SCALE(i_pcr) );
ProgramSetPCR( p_demux, p_pmt, i_program_pcr );
}
}
@@ -2407,13 +2414,13 @@ static void PCRFixHandle( demux_t *p_demux, ts_pmt_t *p_pmt, block_t *p_block )
return;
}
/* Record the first data packet timestamp in case there won't be any PCR */
- else if( !p_pmt->pcr.i_first_dts )
+ else if( p_pmt->pcr.i_first_dts == VLC_TICK_INVALID )
{
- p_pmt->pcr.i_first_dts = p_block->i_dts;
+ p_pmt->pcr.i_first_dts = TO_SCALE(p_block->i_dts);
}
- else if( p_block->i_dts - p_pmt->pcr.i_first_dts > CLOCK_FREQ / 2 ) /* "PCR repeat rate shall not exceed 100ms" */
+ else if( p_block->i_dts - FROM_SCALE(p_pmt->pcr.i_first_dts) > CLOCK_FREQ / 2 ) /* "PCR repeat rate shall not exceed 100ms" */
{
- if( p_pmt->pcr.i_current < 0 &&
+ if( p_pmt->pcr.i_current == VLC_TICK_INVALID &&
GetPID( p_demux->p_sys, p_pmt->i_pid_pcr )->probed.i_pcr_count == 0 )
{
int i_cand = FindPCRCandidate( p_pmt );
@@ -2571,216 +2578,27 @@ static block_t * ProcessTSPacket( demux_t *p_demux, ts_pid_t *pid, block_t *p_pk
return p_pkt;
}
-/* Avoids largest memcpy */
-static bool block_Split( block_t **pp_block, block_t **pp_remain, size_t i_offset )
-{
- block_t *p_block = *pp_block;
- block_t *p_split = NULL;
- *pp_remain = NULL;
-
- size_t i_tocopy = p_block->i_buffer - i_offset;
- if( i_tocopy > i_offset ) /* make new block for head */
- {
- if( i_offset > 0 )
- {
- p_split = block_Alloc( i_offset );
- if( p_split == NULL )
- return false;
- memcpy( p_split->p_buffer, p_block->p_buffer, i_offset );
- p_block->p_buffer += i_offset;
- p_block->i_buffer -= i_offset;
- }
- *pp_remain = p_block;
- *pp_block = p_split;
- }
- else /* other gets the tail of our split */
- {
- if( i_tocopy > 0 )
- {
- p_split = block_Alloc( i_tocopy );
- if( p_split == NULL )
- return false;
- memcpy( p_split->p_buffer, &p_block->p_buffer[i_offset], i_tocopy );
- p_block->i_buffer -= i_tocopy;
- }
- *pp_remain = p_split;
- }
- return true;
-}
-
-static uint8_t *FindNextPESHeader( uint8_t *p_buf, size_t i_buffer )
-{
- const uint8_t *p_end = &p_buf[i_buffer];
- unsigned i_bitflow = 0;
- for( ; p_buf != p_end; p_buf++ )
- {
- i_bitflow <<= 1;
- if( !*p_buf )
- {
- i_bitflow |= 1;
- }
- else if( *p_buf == 0x01 && (i_bitflow & 0x06) == 0x06 ) /* >= two zero prefixed 1 */
- {
- return p_buf - 2;
- }
- }
- return NULL;
-}
-
-static const uint8_t pes_sync[] = { 0, 0, 1 };
-
-static bool MayHaveStartCodeOnEnd( const uint8_t *p_buf, size_t i_buf )
-{
- assert(i_buf > 2);
- return !( *(--p_buf) > 1 || *(--p_buf) > 0 || *(--p_buf) > 0 );
-}
-
-static bool GatherPESData( demux_t *p_demux, ts_pid_t *pid, block_t *p_pkt, size_t i_skip )
+static bool GatherPESData( demux_t *p_demux, ts_pid_t *p_pid, block_t *p_pkt, size_t i_skip )
{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ ts_pes_parse_callback cb = { .p_obj = VLC_OBJECT(p_demux),
+ .priv = p_pid,
+ .pf_parse = PESDataChainHandle };
const bool b_unit_start = p_pkt->p_buffer[1]&0x40;
- bool b_ret = false;
- ts_stream_t *p_pes = pid->u.p_stream;
- const ts_es_t *p_es = p_pes->p_es;
- int64_t i_append_pcr = ( p_es && p_es->p_program ) ? p_es->p_program->pcr.i_current : -1;
- /* We have to gather it */
- p_pkt->p_buffer += i_skip;
+ p_pkt->p_buffer += i_skip; /* point to PES */
p_pkt->i_buffer -= i_skip;
- bool b_single_payload = b_unit_start; /* Single payload in case of unit start */
- bool b_aligned_ts_payload = true;
-
- if( unlikely(p_pes->b_broken_PUSI_conformance) )
- {
- /* Stream does not conform to payload_unit_start flag
- * applied to PES packets (AdTech private_stream_1) */
- b_aligned_ts_payload = false;
- b_single_payload = false;
-
- }
-
- /* We'll cannot parse any pes data */
- if( (p_pkt->i_flags & BLOCK_FLAG_SCRAMBLED) && p_demux->p_sys->b_valid_scrambling )
- {
- block_Release( p_pkt );
- return PushPESBlock( p_demux, pid, NULL, true, i_append_pcr );
- }
-
- /* Data discontinuity, we need to drop or output currently
- * gathered data as it can't match the target size or can
- * have dropped next sync code */
- if( p_pkt->i_flags & BLOCK_FLAG_DISCONTINUITY )
- {
- p_pes->gather.i_saved = 0;
- /* Flush/output current */
- b_ret |= PushPESBlock( p_demux, pid, NULL, true, i_append_pcr );
- /* Propagate to output block to notify packetizers/decoders */
- if( p_pes->p_es )
- p_pes->p_es->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY;
- }
-
- if ( unlikely(p_pes->gather.i_saved > 0) )
- {
- /* Saved from previous packet end */
- assert(p_pes->gather.i_saved < 6);
- if( !b_aligned_ts_payload )
- {
- p_pkt = block_Realloc( p_pkt, p_pes->gather.i_saved, p_pkt->i_buffer );
- if( p_pkt )
- memcpy( p_pkt->p_buffer, p_pes->gather.saved, p_pes->gather.i_saved );
- }
- p_pes->gather.i_saved = 0;
- }
-
- for( bool b_first_sync_done = false; p_pkt; )
- {
- assert( p_pes->gather.i_saved == 0 );
-
- if( p_pes->gather.p_data == NULL && !b_first_sync_done && p_pkt->i_buffer >= 6 )
- {
- if( likely(b_aligned_ts_payload) )
- {
- if( memcmp( p_pkt->p_buffer, pes_sync, 3 ) )
- {
- block_Release( p_pkt );
- return b_ret;
- }
- }
- else
- {
- /* Need to find sync code */
- uint8_t *p_buf = FindNextPESHeader( p_pkt->p_buffer, p_pkt->i_buffer - 3 );
- if( p_buf == NULL )
- {
- /* no first sync code */
- if( MayHaveStartCodeOnEnd( p_pkt->p_buffer, p_pkt->i_buffer ) )
- {
- /* Drop everything except last bytes for next packet */
- p_pkt->p_buffer += p_pkt->i_buffer - 3;
- p_pes->gather.i_saved = p_pkt->i_buffer = 3;
- memcpy(p_pes->gather.saved, p_pkt->p_buffer, p_pkt->i_buffer);
- }
- block_Release( p_pkt );
- return b_ret;
- }
- p_pkt->i_buffer -= p_buf - p_pkt->p_buffer;
- p_pkt->p_buffer = p_buf;
- }
- /* now points to PES header */
- p_pes->gather.i_data_size = GetWBE(&p_pkt->p_buffer[4]);
- if( p_pes->gather.i_data_size > 0 )
- p_pes->gather.i_data_size += 6;
- b_first_sync_done = true; /* Because if size is 0, we woud not look for second sync */
- }
- else
- {
- assert( p_pes->gather.i_data_size > p_pes->gather.i_gathered ||
- p_pes->gather.i_data_size == 0 );
-
- /* If we started reading a fixed size */
- if( p_pes->gather.i_data_size > p_pes->gather.i_gathered )
- {
- const size_t i_remain = p_pes->gather.i_data_size - p_pes->gather.i_gathered;
- /* Append whole block */
- if( likely(p_pkt->i_buffer <= i_remain || b_single_payload) )
- {
- b_ret |= PushPESBlock( p_demux, pid, p_pkt, p_pes->gather.p_data == NULL, i_append_pcr );
- p_pkt = NULL;
- }
- else /* p_pkt->i_buffer > i_remain */
- {
- block_t *p_split;
- if( !block_Split( &p_pkt, &p_split, i_remain ) )
- {
- block_Release( p_pkt );
- return false;
- }
- b_ret |= PushPESBlock( p_demux, pid, p_pkt, p_pes->gather.p_data == NULL, i_append_pcr );
- p_pkt = p_split;
- b_first_sync_done = false;
- }
- }
- else /* if( p_pes->gather.i_data_size == 0 ) // see next packet */
- {
- /* Append or finish current/start new PES depending on unit_start */
- b_ret |= PushPESBlock( p_demux, pid, p_pkt, b_unit_start, i_append_pcr );
- p_pkt = NULL;
- }
- }
+ const ts_es_t *p_es = p_pid->u.p_stream->p_es;
+ ts_90khz_t i_append_pcr = ( p_es && p_es->p_program && p_es->p_program->pcr.i_current != VLC_TICK_INVALID )
+ ? TO_SCALE(p_es->p_program->pcr.i_current)
+ : TS_90KHZ_INVALID;
- if( unlikely(p_pkt && p_pkt->i_buffer < 6) )
- {
- /* save and prepend to next packet */
- assert(!b_single_payload);
- assert(p_pes->gather.i_saved == 0);
- p_pes->gather.i_saved = p_pkt->i_buffer;
- memcpy(p_pes->gather.saved, p_pkt->p_buffer, p_pkt->i_buffer);
- block_Release( p_pkt );
- p_pkt = NULL;
- }
- }
+ return ts_pes_Gather( &cb, p_pid->u.p_stream,
+ p_pkt, b_unit_start,
+ p_sys->b_valid_scrambling,
+ i_append_pcr );
- return b_ret;
}
static bool GatherSectionsData( demux_t *p_demux, ts_pid_t *p_pid, block_t *p_pkt, size_t i_skip )
=====================================
modules/demux/mpeg/ts_arib.c
=====================================
@@ -23,6 +23,7 @@
#include <vlc_common.h>
#include <vlc_demux.h>
+#include "timestamps.h"
#include "ts_pid.h"
#include "ts.h"
=====================================
modules/demux/mpeg/ts_hotfixes.c
=====================================
@@ -82,7 +82,7 @@ void ProbePES( demux_t *p_demux, ts_pid_t *pid, const uint8_t *p_pesstart, size_
return;
size_t i_pesextoffset = 8;
- vlc_tick_t i_dts = -1;
+ ts_90khz_t i_dts = TS_90KHZ_INVALID;
if( p_pes[7] & 0x80 ) // PTS
{
i_pesextoffset += 5;
@@ -192,15 +192,15 @@ void ProbePES( demux_t *p_demux, ts_pid_t *pid, const uint8_t *p_pesstart, size_
}
/* Track timestamps and flag missing PAT */
- if( !p_sys->patfix.i_timesourcepid && i_dts > -1 )
+ if( !p_sys->patfix.i_timesourcepid && i_dts != TS_90KHZ_INVALID )
{
- p_sys->patfix.i_first_dts = i_dts;
+ p_sys->patfix.i_first_dts = FROM_SCALE(i_dts);
p_sys->patfix.i_timesourcepid = pid->i_pid;
}
- else if( p_sys->patfix.i_timesourcepid == pid->i_pid && i_dts > -1 &&
+ else if( p_sys->patfix.i_timesourcepid == pid->i_pid && i_dts != TS_90KHZ_INVALID &&
p_sys->patfix.status == PAT_WAITING )
{
- if( i_dts - p_sys->patfix.i_first_dts > TO_SCALE(MIN_PAT_INTERVAL) )
+ if( i_dts - p_sys->patfix.i_first_dts > MIN_PAT_INTERVAL )
p_sys->patfix.status = PAT_MISSING;
}
=====================================
modules/demux/mpeg/ts_pes.c
=====================================
@@ -0,0 +1,306 @@
+/*****************************************************************************
+ * ts_pes.c: Transport Stream input module for VLC.
+ *****************************************************************************
+ * Copyright (C) 2004-2019 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.
+ *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_demux.h>
+
+#include "ts_streams.h"
+#include "ts_pid.h"
+#include "ts_streams_private.h"
+
+#include "ts_pes.h"
+
+#include <assert.h>
+
+/* Avoids largest memcpy */
+static bool block_Split( block_t **pp_block, block_t **pp_remain, size_t i_offset )
+{
+ block_t *p_block = *pp_block;
+ block_t *p_split = NULL;
+ *pp_remain = NULL;
+
+ size_t i_tocopy = p_block->i_buffer - i_offset;
+ if( i_tocopy > i_offset ) /* make new block for head */
+ {
+ if( i_offset > 0 )
+ {
+ p_split = block_Alloc( i_offset );
+ if( p_split == NULL )
+ return false;
+ memcpy( p_split->p_buffer, p_block->p_buffer, i_offset );
+ p_block->p_buffer += i_offset;
+ p_block->i_buffer -= i_offset;
+ }
+ *pp_remain = p_block;
+ *pp_block = p_split;
+ }
+ else /* other gets the tail of our split */
+ {
+ if( i_tocopy > 0 )
+ {
+ p_split = block_Alloc( i_tocopy );
+ if( p_split == NULL )
+ return false;
+ memcpy( p_split->p_buffer, &p_block->p_buffer[i_offset], i_tocopy );
+ p_block->i_buffer -= i_tocopy;
+ }
+ *pp_remain = p_split;
+ }
+ return true;
+}
+
+static const uint8_t pes_sync[] = { 0, 0, 1 };
+
+static bool MayHaveStartCodeOnEnd( const uint8_t *p_buf, size_t i_buf )
+{
+ assert(i_buf > 2);
+ return !( *(--p_buf) > 1 || *(--p_buf) > 0 || *(--p_buf) > 0 );
+}
+
+static uint8_t *FindNextPESHeader( uint8_t *p_buf, size_t i_buffer )
+{
+ const uint8_t *p_end = &p_buf[i_buffer];
+ unsigned i_bitflow = 0;
+ for( ; p_buf != p_end; p_buf++ )
+ {
+ i_bitflow <<= 1;
+ if( !*p_buf )
+ {
+ i_bitflow |= 1;
+ }
+ else if( *p_buf == 0x01 && (i_bitflow & 0x06) == 0x06 ) /* >= two zero prefixed 1 */
+ {
+ return p_buf - 2;
+ }
+ }
+ return NULL;
+}
+
+static bool ts_pes_Push( ts_pes_parse_callback *cb,
+ ts_stream_t *p_pes, block_t *p_pkt,
+ bool b_unit_start, ts_90khz_t i_append_pcr )
+{
+ bool b_ret = false;
+
+ if ( b_unit_start && p_pes->gather.p_data )
+ {
+ block_t *p_datachain = p_pes->gather.p_data;
+ /* Flush the pes from pid */
+ p_pes->gather.p_data = NULL;
+ p_pes->gather.i_data_size = 0;
+ p_pes->gather.i_gathered = 0;
+ p_pes->gather.pp_last = &p_pes->gather.p_data;
+ cb->pf_parse( cb->p_obj, cb->priv, p_datachain, p_pes->gather.i_append_pcr );
+ b_ret = true;
+ }
+
+ if( b_unit_start )
+ p_pes->gather.i_append_pcr = i_append_pcr;
+
+ if( p_pkt == NULL )
+ return b_ret;
+
+ if( p_pkt->i_buffer == 0 )
+ {
+ block_Release( p_pkt );
+ return b_ret;
+ }
+
+ if( !b_unit_start && p_pes->gather.p_data == NULL )
+ {
+ /* msg_Dbg( p_demux, "broken packet" ); */
+ block_Release( p_pkt );
+ return b_ret;
+ }
+
+ block_ChainLastAppend( &p_pes->gather.pp_last, p_pkt );
+ p_pes->gather.i_gathered += p_pkt->i_buffer;
+
+ if( p_pes->gather.i_data_size > 0 &&
+ p_pes->gather.i_gathered >= p_pes->gather.i_data_size )
+ {
+ /* re-enter in Flush above */
+ assert(p_pes->gather.p_data);
+ return ts_pes_Push( cb, p_pes, NULL, true, i_append_pcr );
+ }
+
+ return b_ret;
+}
+
+bool ts_pes_Drain( ts_pes_parse_callback *cb, ts_stream_t *p_pes )
+{
+ return ts_pes_Push( cb, p_pes, NULL, true, VLC_TICK_INVALID );
+}
+
+bool ts_pes_Gather( ts_pes_parse_callback *cb,
+ ts_stream_t *p_pes, block_t *p_pkt,
+ bool b_unit_start, bool b_valid_scrambling,
+ ts_90khz_t i_append_pcr )
+{
+ bool b_ret = false;
+ bool b_single_payload = b_unit_start; /* Single payload in case of unit start */
+ bool b_aligned_ts_payload = true;
+
+ if( unlikely(p_pes->b_broken_PUSI_conformance) )
+ {
+ /* Stream does not conform to payload_unit_start flag
+ * applied to PES packets (AdTech private_stream_1) */
+ b_aligned_ts_payload = false;
+ b_single_payload = false;
+
+ }
+
+ /* We'll cannot parse any pes data */
+ if( (p_pkt->i_flags & BLOCK_FLAG_SCRAMBLED) && b_valid_scrambling )
+ {
+ block_Release( p_pkt );
+ return ts_pes_Push( cb, p_pes, NULL, true, i_append_pcr );
+ }
+
+ /* Data discontinuity, we need to drop or output currently
+ * gathered data as it can't match the target size or can
+ * have dropped next sync code */
+ if( p_pkt->i_flags & BLOCK_FLAG_DISCONTINUITY )
+ {
+ p_pes->gather.i_saved = 0;
+ /* Flush/output current */
+ b_ret |= ts_pes_Push( cb, p_pes, NULL, true, i_append_pcr );
+ /* Propagate to output block to notify packetizers/decoders */
+ if( p_pes->p_es )
+ p_pes->p_es->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY;
+ }
+
+ if ( unlikely(p_pes->gather.i_saved > 0) )
+ {
+ /* Saved from previous packet end */
+ assert(p_pes->gather.i_saved < 6);
+ if( !b_aligned_ts_payload )
+ {
+ p_pkt = block_Realloc( p_pkt, p_pes->gather.i_saved, p_pkt->i_buffer );
+ if( p_pkt )
+ memcpy( p_pkt->p_buffer, p_pes->gather.saved, p_pes->gather.i_saved );
+ }
+ p_pes->gather.i_saved = 0;
+ }
+
+ for( bool b_first_sync_done = false; p_pkt; )
+ {
+ assert( p_pes->gather.i_saved == 0 );
+
+ if( p_pes->gather.p_data == NULL && b_unit_start && !b_first_sync_done && p_pkt->i_buffer >= 6 )
+ {
+ if( likely(b_aligned_ts_payload) )
+ {
+ if( memcmp( p_pkt->p_buffer, pes_sync, 3 ) )
+ {
+ block_Release( p_pkt );
+ return b_ret;
+ }
+ }
+ else
+ {
+ /* Need to find sync code */
+ uint8_t *p_buf = FindNextPESHeader( p_pkt->p_buffer, p_pkt->i_buffer - 3 );
+ if( p_buf == NULL )
+ {
+ /* no first sync code */
+ if( MayHaveStartCodeOnEnd( p_pkt->p_buffer, p_pkt->i_buffer ) )
+ {
+ /* Drop everything except last bytes for next packet */
+ p_pkt->p_buffer += p_pkt->i_buffer - 3;
+ p_pes->gather.i_saved = p_pkt->i_buffer = 3;
+ memcpy(p_pes->gather.saved, p_pkt->p_buffer, p_pkt->i_buffer);
+ }
+ block_Release( p_pkt );
+ return b_ret;
+ }
+ p_pkt->i_buffer -= p_buf - p_pkt->p_buffer;
+ p_pkt->p_buffer = p_buf;
+ }
+ /* now points to PES header */
+ p_pes->gather.i_data_size = GetWBE(&p_pkt->p_buffer[4]);
+ if( p_pes->gather.i_data_size > 0 )
+ p_pes->gather.i_data_size += 6;
+ b_first_sync_done = true; /* Because if size is 0, we woud not look for second sync */
+ }
+ else
+ {
+ assert( p_pes->gather.i_data_size > p_pes->gather.i_gathered ||
+ p_pes->gather.i_data_size == 0 );
+
+ /* If we started reading a fixed size */
+ if( p_pes->gather.i_data_size > p_pes->gather.i_gathered && !b_single_payload )
+ {
+ const size_t i_remain = p_pes->gather.i_data_size - p_pes->gather.i_gathered;
+ /* Append whole block */
+ if( likely(p_pkt->i_buffer <= i_remain) )
+ {
+ b_ret |= ts_pes_Push( cb, p_pes, p_pkt, p_pes->gather.p_data == NULL, i_append_pcr );
+ p_pkt = NULL;
+ }
+ else /* p_pkt->i_buffer > i_remain */
+ {
+ block_t *p_split;
+ if( !block_Split( &p_pkt, &p_split, i_remain ) )
+ {
+ block_Release( p_pkt );
+ return false;
+ }
+ b_ret |= ts_pes_Push( cb, p_pes, p_pkt, p_pes->gather.p_data == NULL, i_append_pcr );
+ p_pkt = p_split;
+ b_first_sync_done = false;
+ }
+ }
+ else /* if( p_pes->gather.i_data_size == 0 ) // see next packet */
+ {
+ if( likely(b_aligned_ts_payload) && b_unit_start )
+ {
+ b_ret |= ts_pes_Push( cb, p_pes, NULL, true, i_append_pcr );
+ /* now points to PES header */
+ if( p_pkt->i_buffer >= 6 )
+ {
+ p_pes->gather.i_data_size = GetWBE(&p_pkt->p_buffer[4]);
+ if( p_pes->gather.i_data_size > 0 )
+ p_pes->gather.i_data_size += 6;
+ }
+ }
+ /* Append or finish current/start new PES depending on unit_start */
+ b_ret |= ts_pes_Push( cb, p_pes, p_pkt, b_unit_start, i_append_pcr );
+ p_pkt = NULL;
+ }
+ }
+
+ if( unlikely(p_pkt && p_pkt->i_buffer < 6) )
+ {
+ /* save and prepend to next packet */
+ assert(!b_single_payload);
+ assert(p_pes->gather.i_saved == 0);
+ p_pes->gather.i_saved = p_pkt->i_buffer;
+ memcpy(p_pes->gather.saved, p_pkt->p_buffer, p_pkt->i_buffer);
+ block_Release( p_pkt );
+ p_pkt = NULL;
+ }
+ }
+
+ return b_ret;
+}
=====================================
modules/demux/mpeg/ts_pes.h
=====================================
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * ts_pes.h: Transport Stream input module for VLC.
+ *****************************************************************************
+ * Copyright (C) 2004-2019 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.
+ *****************************************************************************/
+#ifndef VLC_TS_PES_H
+#define VLC_TS_PES_H
+
+#include "timestamps.h"
+
+typedef struct
+{
+ vlc_object_t *p_obj;
+ void *priv;
+ void(*pf_parse)(vlc_object_t *, void *, block_t *, ts_90khz_t );
+} ts_pes_parse_callback;
+
+bool ts_pes_Drain( ts_pes_parse_callback *cb, ts_stream_t *p_pes );
+
+bool ts_pes_Gather( ts_pes_parse_callback *cb,
+ ts_stream_t *p_pes, block_t *p_pkt,
+ bool b_unit_start, bool b_valid_scrambling,
+ ts_90khz_t i_append_pcr );
+
+
+#endif
=====================================
modules/demux/mpeg/ts_pid.c
=====================================
@@ -25,6 +25,7 @@
#include "ts_pid.h"
#include "ts_streams.h"
+#include "timestamps.h"
#include "ts.h"
=====================================
modules/demux/mpeg/ts_psi.c
=====================================
@@ -2028,11 +2028,14 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
UpdatePESFilters( p_demux, p_demux->p_sys->seltype == PROGRAM_ALL );
/* Probe Boundaries */
- if( p_sys->b_canfastseek && p_pmt->i_last_dts == -1 )
+ if( p_sys->b_canfastseek && p_pmt->i_last_dts == VLC_TICK_INVALID )
{
- p_pmt->i_last_dts = 0;
+ p_pmt->i_last_dts = VLC_TICK_INVALID;
ProbeStart( p_demux, p_pmt->i_number );
ProbeEnd( p_demux, p_pmt->i_number );
+ if( p_pmt->i_last_dts != VLC_TICK_INVALID &&
+ p_pmt->i_last_dts < p_pmt->pcr.i_first_dts )
+ p_pmt->i_last_dts = TimeStampWrapAround( p_pmt->pcr.i_first_dts, p_pmt->i_last_dts );
}
dvbpsi_pmt_delete( p_dvbpsipmt );
=====================================
modules/demux/mpeg/ts_psip.c
=====================================
@@ -43,6 +43,7 @@
#include "ts_decoders.h"
#include "ts_psip_dvbpsi_fixes.h"
+#include "timestamps.h"
#include "ts_pid.h"
#include "ts.h"
#include "ts_streams_private.h"
=====================================
modules/demux/mpeg/ts_scte.c
=====================================
@@ -61,10 +61,9 @@ void SCTE18_Section_Callback( dvbpsi_t *p_handle, const dvbpsi_psi_section_t* p_
continue;
const ts_pmt_t *p_pmt = p_es->p_program;
- const vlc_tick_t i_date = TimeStampWrapAround( p_pmt->pcr.i_first, p_pmt->pcr.i_current );
block_t *p_block = block_Alloc( p_section->p_payload_end - p_section->p_payload_start );
memcpy( p_block->p_buffer, p_section->p_payload_start, i_payload );
- p_block->i_dts = p_block->i_pts = FROM_SCALE( i_date );
+ p_block->i_dts = p_block->i_pts = p_pmt->pcr.i_current;
es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, p_es->id, true );
es_out_Send( p_demux->out, p_es->id, p_block );
@@ -102,9 +101,9 @@ void SCTE27_Section_Callback( demux_t *p_demux,
bool is_immediate = p_content->p_buffer[i_offset + 3] & 0x40;
if( !is_immediate )
{
- vlc_tick_t i_display_in = GetDWBE( &p_content->p_buffer[i_offset + 4] );
+ vlc_tick_t i_display_in = FROM_SCALE(GetDWBE( &p_content->p_buffer[i_offset + 4] ));
if( i_display_in < i_date )
- i_date = i_display_in + (1ll << 32);
+ i_date = i_display_in + FROM_SCALE_NZ(1ll << 32);
else
i_date = i_display_in;
}
=====================================
modules/demux/mpeg/ts_streams.c
=====================================
@@ -122,14 +122,14 @@ ts_pmt_t *ts_pmt_New( demux_t *p_demux )
pmt->od.i_version = -1;
ARRAY_INIT( pmt->od.objects );
- pmt->i_last_dts = -1;
+ pmt->i_last_dts = VLC_TICK_INVALID;
pmt->i_last_dts_byte = 0;
pmt->p_atsc_si_basepid = NULL;
pmt->p_si_sdt_pid = NULL;
- pmt->pcr.i_current = -1;
- pmt->pcr.i_first = -1;
+ pmt->pcr.i_current = VLC_TICK_INVALID;
+ pmt->pcr.i_first = VLC_TICK_INVALID;
pmt->pcr.b_disable = false;
pmt->pcr.i_first_dts = VLC_TICK_INVALID;
pmt->pcr.i_pcroffset = -1;
@@ -286,13 +286,14 @@ ts_stream_t *ts_stream_New( demux_t *p_demux, ts_pmt_t *p_program )
pes->gather.p_data = NULL;
pes->gather.pp_last = &pes->gather.p_data;
pes->gather.i_saved = 0;
- pes->gather.i_append_pcr = VLC_TICK_INVALID;
+ pes->gather.i_append_pcr = TS_90KHZ_INVALID;
pes->b_broken_PUSI_conformance = false;
pes->b_always_receive = false;
pes->p_sections_proc = NULL;
pes->p_proc = NULL;
pes->prepcr.p_head = NULL;
pes->prepcr.pp_last = &pes->prepcr.p_head;
+ pes->i_last_dts = VLC_TICK_INVALID;
return pes;
}
=====================================
modules/demux/mpeg/ts_streams_private.h
=====================================
@@ -23,6 +23,7 @@ typedef struct dvbpsi_s dvbpsi_t;
typedef struct ts_sections_processor_t ts_sections_processor_t;
#include "mpeg4_iod.h"
+#include "timestamps.h"
#include <vlc_common.h>
#include <vlc_es.h>
@@ -58,7 +59,7 @@ struct ts_pmt_t
struct
{
vlc_tick_t i_current;
- vlc_tick_t i_first; // seen <> != -1
+ vlc_tick_t i_first; // seen <> != TS_TICK_UNKNOWN
/* broken PCR handling */
vlc_tick_t i_first_dts;
vlc_tick_t i_pcroffset;
@@ -125,7 +126,7 @@ struct ts_stream_t
block_t **pp_last;
uint8_t saved[5];
size_t i_saved;
- int64_t i_append_pcr;
+ ts_90khz_t i_append_pcr;
} gather;
bool b_always_receive;
@@ -138,6 +139,8 @@ struct ts_stream_t
block_t *p_head;
block_t **pp_last;
} prepcr;
+
+ vlc_tick_t i_last_dts;
};
typedef struct ts_si_context_t ts_si_context_t;
=====================================
modules/demux/pva.c
=====================================
@@ -32,6 +32,7 @@
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_demux.h>
+#include "mpeg/timestamps.h"
/*****************************************************************************
* Module descriptor
@@ -393,8 +394,8 @@ static void ParsePES( demux_t *p_demux )
uint8_t hdr[30];
unsigned i_skip;
- vlc_tick_t i_dts = -1;
- vlc_tick_t i_pts = -1;
+ ts_90khz_t i_dts = TS_90KHZ_INVALID;
+ ts_90khz_t i_pts = TS_90KHZ_INVALID;
p_sys->p_pes = NULL;
@@ -416,19 +417,19 @@ static void ParsePES( demux_t *p_demux )
i_skip = hdr[8] + 9;
if( hdr[7]&0x80 ) /* has pts */
{
- i_pts = ((vlc_tick_t)(hdr[ 9]&0x0e ) << 29)|
- (vlc_tick_t)(hdr[10] << 22)|
- ((vlc_tick_t)(hdr[11]&0xfe) << 14)|
- (vlc_tick_t)(hdr[12] << 7)|
- (vlc_tick_t)(hdr[12] >> 1);
+ i_pts = ((ts_90khz_t)(hdr[ 9]&0x0e ) << 29)|
+ (ts_90khz_t)(hdr[10] << 22)|
+ ((ts_90khz_t)(hdr[11]&0xfe) << 14)|
+ (ts_90khz_t)(hdr[12] << 7)|
+ (ts_90khz_t)(hdr[12] >> 1);
if( hdr[7]&0x40 ) /* has dts */
{
- i_dts = ((vlc_tick_t)(hdr[14]&0x0e ) << 29)|
- (vlc_tick_t)(hdr[15] << 22)|
- ((vlc_tick_t)(hdr[16]&0xfe) << 14)|
- (vlc_tick_t)(hdr[17] << 7)|
- (vlc_tick_t)(hdr[18] >> 1);
+ i_dts = ((ts_90khz_t)(hdr[14]&0x0e ) << 29)|
+ (ts_90khz_t)(hdr[15] << 22)|
+ ((ts_90khz_t)(hdr[16]&0xfe) << 14)|
+ (ts_90khz_t)(hdr[17] << 7)|
+ (ts_90khz_t)(hdr[18] >> 1);
}
}
@@ -444,10 +445,10 @@ static void ParsePES( demux_t *p_demux )
p_pes->i_buffer -= i_skip;
p_pes->p_buffer += i_skip;
- if( i_dts >= 0 )
- p_pes->i_dts = VLC_TICK_0 + i_dts * 100 / 9;
- if( i_pts >= 0 )
- p_pes->i_pts = VLC_TICK_0 + i_pts * 100 / 9;
+ if( i_dts != TS_90KHZ_INVALID )
+ p_pes->i_dts = FROM_SCALE(i_dts);
+ if( i_pts != TS_90KHZ_INVALID )
+ p_pes->i_pts = FROM_SCALE(i_pts);
/* Set PCR */
if( p_pes->i_pts > 0 )
=====================================
modules/demux/ty.c
=====================================
@@ -46,6 +46,7 @@
#include <vlc_meta.h>
#include <vlc_input.h>
#include "../codec/cc.h"
+#include "mpeg/timestamps.h"
#include <assert.h>
@@ -558,13 +559,13 @@ static void Close( vlc_object_t *p_this )
* Assume buf points to beginning of PTS */
static vlc_tick_t get_pts( const uint8_t *buf )
{
- vlc_tick_t i_pts;
+ ts_90khz_t i_pts;
- i_pts = ((vlc_tick_t)(buf[0]&0x0e ) << 29)|
- (vlc_tick_t)(buf[1] << 22)|
- ((vlc_tick_t)(buf[2]&0xfe) << 14)|
- (vlc_tick_t)(buf[3] << 7)|
- (vlc_tick_t)(buf[4] >> 1);
+ i_pts = ((ts_90khz_t)(buf[0]&0x0e ) << 29)|
+ (ts_90khz_t)(buf[1] << 22)|
+ ((ts_90khz_t)(buf[2]&0xfe) << 14)|
+ (ts_90khz_t)(buf[3] << 7)|
+ (ts_90khz_t)(buf[4] >> 1);
i_pts *= 100 / 9; /* convert PTS (90Khz clock) to microseconds */
return i_pts;
}
=====================================
test/Makefile.am
=====================================
@@ -31,6 +31,8 @@ check_PROGRAMS = \
test_src_misc_epg \
test_src_misc_keystore \
test_modules_packetizer_hxxx \
+ test_modules_demux_timestamps \
+ test_modules_demux_ts_pes \
test_modules_keystore
if ENABLE_SOUT
@@ -130,6 +132,11 @@ test_modules_keystore_SOURCES = modules/keystore/test.c
test_modules_keystore_LDADD = $(LIBVLCCORE) $(LIBVLC)
test_modules_tls_SOURCES = modules/misc/tls.c
test_modules_tls_LDADD = $(LIBVLCCORE) $(LIBVLC)
+test_modules_demux_timestamps_SOURCES = modules/demux/timestamps.c
+test_modules_demux_ts_pes_LDADD = $(LIBVLCCORE) $(LIBVLC)
+test_modules_demux_ts_pes_SOURCES = modules/demux/ts_pes.c \
+ ../modules/demux/mpeg/ts_pes.c \
+ ../modules/demux/mpeg/ts_pes.h
checkall:
$(MAKE) check_PROGRAMS="$(check_PROGRAMS) $(EXTRA_PROGRAMS)" check
=====================================
test/modules/demux/timestamps.c
=====================================
@@ -0,0 +1,96 @@
+/*****************************************************************************
+ * timestamps.c:
+ *****************************************************************************
+ * Copyright © 2025 VideoLabs, VideoLAN and VLC Authors
+ *
+ * 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.
+ *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+
+#include "../../../modules/demux/mpeg/timestamps.h"
+
+#define ASSERT(a) do {\
+if(!(a)) { \
+ fprintf(stderr, "failed line %d\n", __LINE__); \
+ return 1; } \
+} while(0)
+
+int main(void)
+{
+ /* Should not wrap without reference */
+ vlc_tick_t ts1 = 50;
+ vlc_tick_t ts2 = TimeStampWrapAround(VLC_TICK_INVALID, ts1);
+ ASSERT(ts2 == ts1);
+
+ ts1 = TS_33BITS_ROLL_NZ * 3/4;
+ ts2 = TimeStampWrapAround(VLC_TICK_INVALID, ts1);
+ ASSERT(ts2 == ts1);
+
+ /* Should not wrap */
+ ts1 = VLC_TICK_0 + TS_33BITS_HALF_ROLL_NZ;
+ ts2 = TimeStampWrapAround(VLC_TICK_0, ts1);
+ ASSERT(ts2 == ts1);
+
+ ts1 = VLC_TICK_0 + TS_33BITS_ROLL_NZ;
+ ts2 = TimeStampWrapAround(VLC_TICK_0, ts1);
+ ASSERT(ts2 == ts1);
+
+ ts1 = VLC_TICK_0 + TS_33BITS_ROLL_NZ;
+ ts2 = TimeStampWrapAround(ts1, ts1);
+ ASSERT(ts2 == ts1);
+
+ ts1 = VLC_TICK_0 + TS_33BITS_ROLL_NZ;
+ ts2 = TimeStampWrapAround(ts1 - 100, ts1);
+ ASSERT(ts2 == ts1);
+
+ ts1 = VLC_TICK_0 + TS_33BITS_ROLL_NZ;
+ ts2 = TimeStampWrapAround(VLC_TICK_0 + TS_33BITS_HALF_ROLL_NZ, ts1);
+ ASSERT(ts2 == ts1);
+
+ /* Should wrap */
+ ts1 = VLC_TICK_0;
+ ts2 = TimeStampWrapAround(VLC_TICK_0 + TS_33BITS_HALF_ROLL_NZ, ts1);
+ ASSERT(ts2 > ts1);
+ ASSERT(ts2 == ts1 + TS_33BITS_ROLL_NZ);
+
+ ts1 = VLC_TICK_0;
+ ts2 = TimeStampWrapAround(VLC_TICK_0 + TS_33BITS_ROLL_NZ * 3/4, ts1);
+ ASSERT(ts2 == ts1 + TS_33BITS_ROLL_NZ);
+
+ ts1 = VLC_TICK_0;
+ ts2 = TimeStampWrapAround(VLC_TICK_0 + TS_33BITS_ROLL_NZ, ts1);
+ ASSERT(ts2 == ts1 + TS_33BITS_ROLL_NZ);
+
+ ts1 = VLC_TICK_0 + TS_33BITS_HALF_ROLL_NZ;
+ ts2 = TimeStampWrapAround(VLC_TICK_0 + TS_33BITS_ROLL_NZ, ts1);
+ ASSERT(ts2 == ts1 + TS_33BITS_ROLL_NZ);
+
+ /* Should wrap multiple times */
+ ts1 = VLC_TICK_0;
+ ts2 = TimeStampWrapAround(VLC_TICK_0 + TS_33BITS_ROLL_NZ * 2, ts1);
+ ASSERT(ts2 > ts1);
+ ASSERT(ts2 == ts1 + TS_33BITS_ROLL_NZ * 2);
+
+ ts1 = VLC_TICK_0 + TS_33BITS_HALF_ROLL_NZ;
+ ts2 = TimeStampWrapAround(VLC_TICK_0 + TS_33BITS_ROLL_NZ * 5, ts1);
+ ASSERT(ts2 > ts1);
+ ASSERT(ts2 == ts1 + TS_33BITS_ROLL_NZ * 5);
+
+ return 0;
+}
=====================================
test/modules/demux/ts_pes.c
=====================================
@@ -0,0 +1,271 @@
+/*****************************************************************************
+ * ts_pes.c: MPEG PES assembly tests
+ *****************************************************************************
+ * Copyright (C) 2020 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.
+ *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <vlc_common.h>
+#include <vlc_block.h>
+
+#include "../../../modules/demux/mpeg/ts_streams.h"
+#include "../../../modules/demux/mpeg/ts_pid_fwd.h"
+#include "../../../modules/demux/mpeg/ts_streams_private.h"
+#include "../../../modules/demux/mpeg/ts_pes.h"
+
+#include "../../libvlc/test.h"
+
+static void Parse(vlc_object_t *obj, void *priv, block_t *data, ts_90khz_t append_pcr)
+{
+ VLC_UNUSED(obj);
+ VLC_UNUSED(append_pcr);
+ block_t **pp_append = (block_t **) priv;
+ fprintf(stderr, "recv: ");
+ data = block_ChainGather(data);
+ for(size_t i=0; i<data->i_buffer; i++)
+ fprintf(stderr, "%2.2x ", data->p_buffer[i]);
+ fprintf(stderr, "\n");
+ block_ChainAppend(pp_append, data);
+}
+
+#define RESET do {\
+ block_ChainRelease(output);\
+ output = NULL;\
+ block_ChainRelease(pes.gather.p_data);\
+ memset(&pes, 0, sizeof(pes));\
+ pes.transport = TS_TRANSPORT_PES;\
+ pes.gather.pp_last = &pes.gather.p_data;\
+ } while(0)
+
+#define ASSERT(a) do {\
+ if(!(a)) { RESET; \
+ fprintf(stderr, "failed line %d\n", __LINE__); \
+ return 1; } \
+ } while(0)
+
+#define PKT_FROMSZ(a, b) do {\
+ pkt = block_Alloc(sizeof(a) + b);\
+ ASSERT(pkt);\
+ memcpy(pkt->p_buffer, a, sizeof(a));\
+ for(size_t i=1; i<1+b;i++)\
+ pkt->p_buffer[sizeof(a) + i] = i % 0xFF;\
+} while(0)
+
+#define PKT_FROM(a) PKT_FROMSZ(a, 0)
+
+int main()
+{
+ block_t *pkt;
+ block_t *output = NULL;
+ int outputcount = 0;
+ size_t outputsize = 0;
+
+ test_init();
+
+ ts_pes_parse_callback cb =
+ {
+ .p_obj = NULL,
+ .priv = &output,
+ .pf_parse = Parse
+ };
+
+ ts_stream_t pes;
+ memset(&pes, 0, sizeof(pes));
+ pes.transport = TS_TRANSPORT_PES;
+ pes.gather.pp_last = &pes.gather.p_data;
+
+ /* General case, aligned payloads */
+ /* payload == 0 */
+ const uint8_t aligned0[] = {
+ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x03, 0x80, 0x00, 0x00,
+ };
+ PKT_FROM(aligned0);
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+ block_ChainProperties(output, &outputcount, &outputsize, NULL);
+ ASSERT(outputcount == 1);
+ ASSERT(outputsize == 6+3);
+ ASSERT(!memcmp(aligned0, output->p_buffer, outputsize));
+ RESET;
+ /* no output if not unit start */
+ PKT_FROM(aligned0);
+ ASSERT(!ts_pes_Gather(&cb, &pes, pkt, false, true, TS_90KHZ_INVALID));
+ ASSERT(!output);
+ RESET;
+ /* no output if not unit start */
+ PKT_FROM(aligned0);
+ pkt->i_buffer = 1;
+ ASSERT(!ts_pes_Gather(&cb, &pes, pkt, false, true, TS_90KHZ_INVALID));
+ ASSERT(!output);
+ RESET;
+
+ /* payload == 6 */
+ const uint8_t aligned1[] = {
+ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x09, 0x80, 0x00, 0x00,
+ 0xAA, 0xBB, 0xAA, 0xBB, 0xAA, 0xBB,
+ };
+ PKT_FROM(aligned1);
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+ block_ChainProperties(output, &outputcount, &outputsize, NULL);
+ ASSERT(outputcount == 1);
+ ASSERT(outputsize == 6+3+6);
+ ASSERT(!memcmp(aligned1, output->p_buffer, outputsize));
+ RESET;
+ /* no output if not unit start */
+ PKT_FROM(aligned1);
+ ASSERT(!ts_pes_Gather(&cb, &pes, pkt, false, true, TS_90KHZ_INVALID));
+ ASSERT(!output);
+ RESET;
+
+ /* payload == 30, uncomplete */
+ PKT_FROM(aligned1);
+ SetWBE(&pkt->p_buffer[4], 30);
+ ASSERT(!ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(!output);
+ RESET;
+
+ /* packets assembly, payload > 188 - 6 - 4 */
+ PKT_FROMSZ(aligned1, 188-sizeof(aligned1));
+ SetWBE(&pkt->p_buffer[4], 250);
+ ASSERT(!ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(!output);
+ ASSERT(pes.gather.i_data_size == 256);
+ PKT_FROMSZ(aligned1, 188-sizeof(aligned1));
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, false, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+ block_ChainProperties(output, &outputcount, &outputsize, NULL);
+ ASSERT(outputcount == 1);
+ ASSERT(outputsize == 256);
+ RESET;
+
+ /* no packets assembly from unit start */
+ PKT_FROMSZ(aligned1, 188-sizeof(aligned1));
+ SetWBE(&pkt->p_buffer[4], 250);
+ ASSERT(!ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(!output);
+ ASSERT(pes.gather.i_data_size == 256);
+ PKT_FROMSZ(aligned1, 188-sizeof(aligned1));
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+ block_ChainProperties(output, &outputcount, &outputsize, NULL);
+ ASSERT(outputcount == 2);
+ RESET;
+
+ /* packets assembly, payload undef, use next sync code from another payload undef */
+ PKT_FROMSZ(aligned1, 188-sizeof(aligned1));
+ SetWBE(&pkt->p_buffer[4], 0);
+ ASSERT(!ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(!output);
+ ASSERT(pes.gather.i_data_size == 0);
+ PKT_FROMSZ(aligned1, 188-sizeof(aligned1));
+ SetWBE(&pkt->p_buffer[4], 0);
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+ block_ChainProperties(output, &outputcount, &outputsize, NULL);
+ ASSERT(outputcount == 1);
+ ASSERT(outputsize == 188);
+ RESET;
+
+ /* packets assembly, payload undef, use next sync code from fixed size */
+ PKT_FROMSZ(aligned1, 188-sizeof(aligned1));
+ SetWBE(&pkt->p_buffer[4], 0);
+ ASSERT(!ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(!output);
+ ASSERT(pes.gather.i_data_size == 0);
+ PKT_FROMSZ(aligned1, 188-sizeof(aligned1));
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+ block_ChainProperties(output, &outputcount, &outputsize, NULL);
+ ASSERT(outputcount == 2); /* secondary */
+ RESET;
+
+ /* packets assembly, payload undef, use next sync code from fixed size but uncomplete */
+ PKT_FROMSZ(aligned1, 188-sizeof(aligned1));
+ SetWBE(&pkt->p_buffer[4], 0);
+ ASSERT(!ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(!output);
+ ASSERT(pes.gather.i_data_size == 0);
+ PKT_FROM(aligned1);
+ pkt->i_buffer = 6;
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+ block_ChainProperties(output, &outputcount, &outputsize, NULL);
+ ASSERT(outputcount == 1); /* can't output */
+ PKT_FROM(aligned1);
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, false, true, TS_90KHZ_INVALID)); /* add data for last output */
+ ASSERT(output); /* output */
+ RESET;
+
+ const uint8_t aligned2[] = {
+ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x03, 0x80, 0x00, 0x00,
+
+ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES 0xdb header */
+ 0x00, 0x01, 0x02, 0x03, /* PES payload */
+
+ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x07, 0x80, 0x00, 0x00, /* PES 0xdb header */
+ 0xAA, 0xBB, 0xCC, 0xDD, /* PES payload */
+ };
+
+ /* If the payload_unit_start_indicator is set to '1', then one and only one
+ * PES packet starts in this transport stream packet. */
+ PKT_FROM(aligned2);
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+ block_ChainProperties(output, &outputcount, &outputsize, NULL);
+ ASSERT(outputcount == 1);
+ RESET;
+
+ /* Broken PUSI tests */
+ pes.b_broken_PUSI_conformance = true;
+ PKT_FROM(aligned2);
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+ block_ChainProperties(output, &outputcount, &outputsize, NULL);
+ ASSERT(outputcount == 3);
+ RESET;
+
+ pes.b_broken_PUSI_conformance = true;
+ PKT_FROM(aligned2);
+ pkt->p_buffer[0] = 0xFF;
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+ block_ChainProperties(output, &outputcount, &outputsize, NULL);
+ ASSERT(outputcount == 2);
+ RESET;
+
+ for(int split=12; split>9; split--)
+ {
+ pes.b_broken_PUSI_conformance = true;
+ PKT_FROM(aligned2);
+ pkt->i_buffer = split;
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+
+ PKT_FROM(aligned2);
+ pkt->p_buffer += split;
+ pkt->i_buffer -= split;
+ ASSERT(ts_pes_Gather(&cb, &pes, pkt, true, true, TS_90KHZ_INVALID));
+ ASSERT(output);
+
+ RESET;
+ }
+
+ return 0;
+}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/e4cf8ccefe49d9a2a4717409e18997f556b84e21...78988161fdc66355d04ae9540e7947c970b6ea81
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/e4cf8ccefe49d9a2a4717409e18997f556b84e21...78988161fdc66355d04ae9540e7947c970b6ea81
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list