Commit efc1cee9 authored by François Cartegnie's avatar François Cartegnie 🤞

demux: ts: split the beast

parent fb98186a
......@@ -229,14 +229,27 @@ libplaylist_plugin_la_SOURCES = \
demux_LTLIBRARIES += libplaylist_plugin.la
libts_plugin_la_SOURCES = demux/mpeg/ts.c demux/mpeg/ts.h \
demux/mpeg/ts_pid.h demux/mpeg/ts_pid.c \
demux/mpeg/ts_psi.h demux/mpeg/ts_psi.c \
demux/mpeg/ts_psi_eit.h demux/mpeg/ts_psi_eit.c \
demux/mpeg/ts_streams.h demux/mpeg/ts_streams.c \
demux/mpeg/ts_scte.h demux/mpeg/ts_scte.c \
demux/mpeg/sections.c demux/mpeg/sections.h \
demux/mpeg/mpeg4_iod.c demux/mpeg/mpeg4_iod.h \
demux/mpeg/ts_strings.h demux/mpeg/pes.h \
mux/mpeg/csa.c mux/mpeg/dvbpsi_compat.h \
mux/mpeg/streams.h mux/mpeg/tables.c mux/mpeg/tables.h \
demux/mpeg/ts_sl.c demux/mpeg/ts_sl.h \
demux/mpeg/ts_hotfixes.c demux/mpeg/ts_hotfixes.h \
demux/mpeg/ts_strings.h \
demux/mpeg/pes.h \
demux/mpeg/timestamps.h \
demux/dvb-text.h \
demux/opus.h \
mux/mpeg/csa.c \
mux/mpeg/dvbpsi_compat.h \
mux/mpeg/streams.h \
mux/mpeg/tables.c mux/mpeg/tables.h \
mux/mpeg/tsutil.c mux/mpeg/tsutil.h \
codec/scte18.h \
demux/dvb-text.h codec/opus_header.c demux/opus.h
codec/opus_header.c
libts_plugin_la_CFLAGS = $(AM_CFLAGS) $(DVBPSI_CFLAGS)
libts_plugin_la_LIBADD = $(DVBPSI_LIBS) $(SOCKET_LIBS)
if HAVE_ARIBB24
......
......@@ -17,6 +17,8 @@
* 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_MPEG4_IOD_H
#define VLC_MPEG4_IOD_H
#define ES_DESCRIPTOR_COUNT 255
typedef enum
......@@ -61,7 +63,10 @@ typedef struct
mtime_t i_pts;
} sl_header_data;
typedef struct
typedef struct es_mpeg4_descriptor_t es_mpeg4_descriptor_t;
typedef struct decoder_config_descriptor_t decoder_config_descriptor_t;
struct decoder_config_descriptor_t
{
uint8_t i_objectTypeIndication;
uint8_t i_streamType;
......@@ -69,9 +74,9 @@ typedef struct
unsigned i_extra;
uint8_t *p_extra;
} decoder_config_descriptor_t;
};
typedef struct
struct es_mpeg4_descriptor_t
{
bool b_ok;
uint16_t i_es_id;
......@@ -81,7 +86,7 @@ typedef struct
decoder_config_descriptor_t dec_descr;
sl_config_descriptor_t sl_descr;
} es_mpeg4_descriptor_t;
};
typedef struct
{
......@@ -105,3 +110,4 @@ sl_header_data DecodeSLHeader( unsigned i_data, const uint8_t *p_data,
const sl_config_descriptor_t *sl );
void DecodeODCommand( vlc_object_t *p_object, od_descriptors_t *,
unsigned i_data, const uint8_t *p_data );
#endif
......@@ -17,12 +17,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#define FROM_SCALE_NZ(x) ((x) * 100 / 9)
#define TO_SCALE_NZ(x) ((x) * 9 / 100)
#define FROM_SCALE(x) (VLC_TS_0 + FROM_SCALE_NZ(x))
#define TO_SCALE(x) TO_SCALE_NZ((x) - VLC_TS_0)
#ifndef VLC_MPEG_PES_H
#define VLC_MPEG_PES_H
static inline mtime_t ExtractPESTimestamp( const uint8_t *p_data )
{
......@@ -44,6 +40,7 @@ static inline mtime_t ExtractMPEG1PESTimestamp( const uint8_t *p_data )
(mtime_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, mtime_t *pi_dts, mtime_t *pi_pts,
uint8_t *pi_stream_id )
......@@ -140,3 +137,5 @@ static int ParsePESHeader( vlc_object_t *p_object, const uint8_t *p_header, size
*pi_skip = i_skip;
return VLC_SUCCESS;
}
#endif
......@@ -24,6 +24,7 @@
#include <assert.h>
#include <vlc_demux.h>
#include <vlc_memory.h>
#include "timestamps.h"
/* 256-0xC0 for normal stream, 256 for 0xbd stream, 256 for 0xfd stream, 8 for 0xa0 AOB stream */
#define PS_TK_COUNT (256+256+256+8 - 0xc0)
......
......@@ -17,10 +17,16 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include "sections.h"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_block.h>
#include "ts_pid.h"
#include "sections.h"
typedef struct ts_sections_assembler_t
{
int8_t i_version;
......
......@@ -20,13 +20,6 @@
#ifndef TS_SECTIONS_H
#define TS_SECTIONS_H
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "ts.h"
#include <vlc_common.h>
typedef void(* ts_section_callback_t)( demux_t *, ts_pid_t *, block_t * );
typedef struct ts_sections_processor_t ts_sections_processor_t;
......
/*****************************************************************************
* timestamps.h: MPEG TS/PS Timestamps helpers
*****************************************************************************
* Copyright (C) 2004-2016 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 General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifndef VLC_MPEG_TIMESTAMPS_H
#define VLC_MPEG_TIMESTAMPS_H
#define FROM_SCALE_NZ(x) ((x) * 100 / 9)
#define TO_SCALE_NZ(x) ((x) * 9 / 100)
#define FROM_SCALE(x) (VLC_TS_0 + FROM_SCALE_NZ(x))
#define TO_SCALE(x) TO_SCALE_NZ((x) - VLC_TS_0)
static inline int64_t TimeStampWrapAround( int64_t i_first_pcr, int64_t i_time )
{
int64_t i_adjust = 0;
if( i_first_pcr > 0x0FFFFFFFF && i_time < 0x0FFFFFFFF )
i_adjust = 0x1FFFFFFFF;
return i_time + i_adjust;
}
#endif
This diff is collapsed.
......@@ -20,6 +20,114 @@
#ifndef VLC_TS_H
#define VLC_TS_H
typedef struct ts_pid_t ts_pid_t;
#ifdef HAVE_ARIBB24
typedef struct arib_instance_t arib_instance_t;
#endif
typedef struct csa_t csa_t;
#define TS_USER_PMT_NUMBER (0)
typedef enum arib_modes_e
{
ARIBMODE_AUTO = -1,
ARIBMODE_DISABLED = 0,
ARIBMODE_ENABLED = 1
} arib_modes_e;
typedef struct
{
int i_service;
} vdr_info_t;
struct demux_sys_t
{
stream_t *stream;
bool b_canseek;
bool b_canfastseek;
vlc_mutex_t csa_lock;
/* TS packet size (188, 192, 204) */
unsigned i_packet_size;
/* Additional TS packet header size (BluRay TS packets have 4-byte header before sync byte) */
unsigned i_packet_header_size;
/* how many TS packet we read at once */
unsigned i_ts_read;
bool b_force_seek_per_percent;
bool b_atsc_eas;
struct
{
arib_modes_e e_mode;
#ifdef HAVE_ARIBB24
arib_instance_t *p_instance;
#endif
stream_t *b25stream;
} arib;
/* All pid */
ts_pid_list_t pids;
bool b_user_pmt;
int i_pmt_es;
bool b_es_all; /* If we need to return all es/programs */
enum
{
NO_ES, /* for preparse */
DELAY_ES,
CREATE_ES
} es_creation;
#define PREPARSING p_sys->es_creation == NO_ES
/* */
bool b_es_id_pid;
uint16_t i_next_extraid;
csa_t *csa;
int i_csa_pkt_size;
bool b_split_es;
bool b_trust_pcr;
/* */
bool b_access_control;
bool b_end_preparse;
/* */
bool b_dvb_meta;
int64_t i_tdt_delta;
int64_t i_dvb_start;
int64_t i_dvb_length;
bool b_broken_charset; /* True if broken encoding is used in EPG/SDT */
/* Selected programs */
DECL_ARRAY( int ) programs; /* List of selected/access-filtered programs */
bool b_default_selection; /* True if set by default to first pmt seen (to get data from filtered access) */
struct
{
mtime_t i_first_dts; /* first dts encountered for the stream */
int i_timesourcepid; /* which pid we saved the dts from */
enum { PAT_WAITING = 0, PAT_MISSING, PAT_FIXTRIED } status; /* set if we haven't seen PAT within MIN_PAT_INTERVAL */
} patfix;
vdr_info_t vdr;
/* */
bool b_start_record;
};
bool ProgramIsSelected( demux_sys_t *, uint16_t i_pgrm );
void UpdatePESFilters( demux_t *p_demux, bool b_all );
int ProbeStart( demux_t *p_demux, int i_program );
int ProbeEnd( demux_t *p_demux, int i_program );
void AddAndCreateES( demux_t *p_demux, ts_pid_t *pid, bool b_create_delayed );
int FindPCRCandidate( ts_pmt_t *p_pmt );
#endif
/*****************************************************************************
* ts_hotfixes.c : MPEG PMT/PAT less streams fixups
*****************************************************************************
* Copyright (C) 2014-2016 - VideoLAN 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 General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_demux.h>
#include <vlc_es.h>
#ifndef _DVBPSI_DVBPSI_H_
#include <dvbpsi/dvbpsi.h>
#endif
#include <dvbpsi/descriptor.h>
#include <dvbpsi/pat.h>
#include <dvbpsi/pmt.h>
#include "../../mux/mpeg/streams.h"
#include "../../mux/mpeg/tsutil.h"
#include "../../mux/mpeg/tables.h"
#include "timestamps.h"
#include "pes.h"
#include "ts_streams.h"
#include "ts_psi.h"
#include "ts_pid.h"
#include "ts_streams_private.h"
#include "ts.h"
#include "ts_hotfixes.h"
#include <assert.h>
void ProbePES( demux_t *p_demux, ts_pid_t *pid, const uint8_t *p_pesstart, size_t i_data, bool b_adaptfield )
{
demux_sys_t *p_sys = p_demux->p_sys;
const uint8_t *p_pes = p_pesstart;
pid->probed.i_type = -1;
if( b_adaptfield )
{
if ( i_data < 2 )
return;
uint8_t len = *p_pes;
p_pes++; i_data--;
if(len == 0)
{
p_pes++; i_data--;/* stuffing */
}
else
{
if( i_data < len )
return;
if( len >= 7 && (p_pes[1] & 0x10) )
pid->probed.i_pcr_count++;
p_pes += len;
i_data -= len;
}
}
if( i_data < 9 )
return;
if( p_pes[0] != 0 || p_pes[1] != 0 || p_pes[2] != 1 )
return;
size_t i_pesextoffset = 8;
mtime_t i_dts = -1;
if( p_pes[7] & 0x80 ) // PTS
{
i_pesextoffset += 5;
if ( i_data < i_pesextoffset )
return;
i_dts = ExtractPESTimestamp( &p_pes[9] );
}
if( p_pes[7] & 0x40 ) // DTS
{
i_pesextoffset += 5;
if ( i_data < i_pesextoffset )
return;
i_dts = ExtractPESTimestamp( &p_pes[14] );
}
if( p_pes[7] & 0x20 ) // ESCR
i_pesextoffset += 6;
if( p_pes[7] & 0x10 ) // ESrate
i_pesextoffset += 3;
if( p_pes[7] & 0x08 ) // DSM
i_pesextoffset += 1;
if( p_pes[7] & 0x04 ) // CopyInfo
i_pesextoffset += 1;
if( p_pes[7] & 0x02 ) // PESCRC
i_pesextoffset += 2;
if ( i_data < i_pesextoffset )
return;
/* HeaderdataLength */
const size_t i_payloadoffset = 8 + 1 + p_pes[8];
i_pesextoffset += 1;
if ( i_data < i_pesextoffset || i_data < i_payloadoffset )
return;
i_data -= 8 + 1 + p_pes[8];
if( p_pes[7] & 0x01 ) // PESExt
{
size_t i_extension2_offset = 1;
if ( p_pes[i_pesextoffset] & 0x80 ) // private data
i_extension2_offset += 16;
if ( p_pes[i_pesextoffset] & 0x40 ) // pack
i_extension2_offset += 1;
if ( p_pes[i_pesextoffset] & 0x20 ) // seq
i_extension2_offset += 2;
if ( p_pes[i_pesextoffset] & 0x10 ) // P-STD
i_extension2_offset += 2;
if ( p_pes[i_pesextoffset] & 0x01 ) // Extension 2
{
uint8_t i_len = p_pes[i_pesextoffset + i_extension2_offset] & 0x7F;
i_extension2_offset += i_len;
}
if( i_data < i_extension2_offset )
return;
i_data -= i_extension2_offset;
}
/* (i_payloadoffset - i_pesextoffset) 0xFF stuffing */
if ( i_data < 4 )
return;
const uint8_t *p_data = &p_pes[i_payloadoffset];
/* NON MPEG audio & subpictures STREAM */
if(p_pes[3] == 0xBD)
{
if( !memcmp( p_data, "\x7F\xFE\x80\x01", 4 ) )
{
pid->probed.i_type = 0x06;
pid->probed.i_fourcc = VLC_CODEC_DTS;
}
else if( !memcmp( p_data, "\x0B\x77", 2 ) )
{
pid->probed.i_type = 0x06;
pid->probed.i_fourcc = VLC_CODEC_EAC3;
}
}
/* MPEG AUDIO STREAM */
else if(p_pes[3] >= 0xC0 && p_pes[3] <= 0xDF)
{
if( p_data[0] == 0xFF && (p_data[1] & 0xE0) == 0xE0 )
{
switch(p_data[1] & 18)
{
/* 10 - MPEG Version 2 (ISO/IEC 13818-3)
11 - MPEG Version 1 (ISO/IEC 11172-3) */
case 0x10:
pid->probed.i_type = 0x04;
break;
case 0x18:
pid->probed.i_type = 0x03;
default:
break;
}
switch(p_data[1] & 6)
{
/* 01 - Layer III
10 - Layer II
11 - Layer I */
case 0x06:
pid->probed.i_type = 0x04;
pid->probed.i_fourcc = VLC_CODEC_MPGA;
break;
case 0x04:
pid->probed.i_type = 0x04;
pid->probed.i_fourcc = VLC_CODEC_MP2;
break;
case 0x02:
pid->probed.i_type = 0x04;
pid->probed.i_fourcc = VLC_CODEC_MP3;
default:
break;
}
}
}
/* VIDEO STREAM */
else if( p_pes[3] >= 0xE0 && p_pes[3] <= 0xEF )
{
if( !memcmp( p_data, "\x00\x00\x00\x01", 4 ) )
{
pid->probed.i_type = 0x1b;
pid->probed.i_fourcc = VLC_CODEC_H264;
}
else if( !memcmp( p_data, "\x00\x00\x01", 4 ) )
{
pid->probed.i_type = 0x02;
pid->probed.i_fourcc = VLC_CODEC_MPGV;
}
}
/* Track timestamps and flag missing PAT */
if( !p_sys->patfix.i_timesourcepid && i_dts > -1 )
{
p_sys->patfix.i_first_dts = i_dts;
p_sys->patfix.i_timesourcepid = pid->i_pid;
}
else if( p_sys->patfix.i_timesourcepid == pid->i_pid && i_dts > -1 &&
p_sys->patfix.status == PAT_WAITING )
{
if( i_dts - p_sys->patfix.i_first_dts > TO_SCALE(MIN_PAT_INTERVAL) )
p_sys->patfix.status = PAT_MISSING;
}
}
static void BuildPATCallback( void *p_opaque, block_t *p_block )
{
ts_pid_t *pat_pid = (ts_pid_t *) p_opaque;
dvbpsi_packet_push( pat_pid->u.p_pat->handle, p_block->p_buffer );
}
static void BuildPMTCallback( void *p_opaque, block_t *p_block )
{
ts_pid_t *program_pid = (ts_pid_t *) p_opaque;
assert(program_pid->type == TYPE_PMT);
while( p_block )
{
dvbpsi_packet_push( program_pid->u.p_pmt->handle,
p_block->p_buffer );
p_block = p_block->p_next;
}
}
void MissingPATPMTFixup( demux_t *p_demux )
{
demux_sys_t *p_sys = p_demux->p_sys;
int i_program_number = 1234;
int i_program_pid = 1337;
int i_pcr_pid = 0x1FFF;
int i_num_pes = 0;
ts_pid_t *p_program_pid = GetPID( p_sys, i_program_pid );
if( SEEN(p_program_pid) )
{
/* Find a free one */
for( i_program_pid = MIN_ES_PID;
i_program_pid <= MAX_ES_PID && SEEN(p_program_pid);
i_program_pid++ )
{
p_program_pid = GetPID( p_sys, i_program_pid );
}
}
const ts_pid_t *p_pid = NULL;
ts_pid_next_context_t pidnextctx = ts_pid_NextContextInitValue;
while( (p_pid = ts_pid_Next( &p_sys->pids, &pidnextctx )) )
{
if( !SEEN(p_pid) || p_pid->probed.i_type == -1 )
continue;
if( i_pcr_pid == 0x1FFF && ( p_pid->probed.i_type == 0x03 ||
p_pid->probed.i_pcr_count ) )
i_pcr_pid = p_pid->i_pid;
i_num_pes++;
}
if( i_num_pes == 0 )
return;
ts_stream_t patstream =
{
.i_pid = 0,
.i_continuity_counter = 0x10,
.b_discontinuity = false
};
ts_stream_t pmtprogramstream =
{
.i_pid = i_program_pid,
.i_continuity_counter = 0x0,
.b_discontinuity = false
};
BuildPAT( GetPID(p_sys, 0)->u.p_pat->handle,
&p_sys->pids.pat, BuildPATCallback,
0, 1,
&patstream,
1, &pmtprogramstream, &i_program_number );
/* PAT callback should have been triggered */
if( p_program_pid->type != TYPE_PMT )
{
msg_Err( p_demux, "PAT creation failed" );
return;
}
struct esstreams_t
{
pes_stream_t pes;
ts_stream_t ts;
};
es_format_t esfmt = {0};
struct esstreams_t *esstreams = calloc( i_num_pes, sizeof(struct esstreams_t) );
pes_mapped_stream_t *mapped = calloc( i_num_pes, sizeof(pes_mapped_stream_t) );
if( esstreams && mapped )
{
int j=0;
for( int i=0; i<p_sys->pids.i_all; i++ )
{
const ts_pid_t *p_pid = p_sys->pids.pp_all[i];
if( !SEEN(p_pid) ||
p_pid->probed.i_type == -1 )
continue;
esstreams[j].pes.i_codec = p_pid->probed.i_fourcc;
esstreams[j].pes.i_stream_type = p_pid->probed.i_type;
esstreams[j].ts.i_pid = p_pid->i_pid;
mapped[j].pes = &esstreams[j].pes;
mapped[j].ts = &esstreams[j].ts;
mapped[j].fmt = &esfmt;
j++;
}
BuildPMT( GetPID(p_sys, 0)->u.p_pat->handle, VLC_OBJECT(p_demux),
p_program_pid, BuildPMTCallback,
0, 1,
i_pcr_pid,
NULL,
1, &pmtprogramstream, &i_program_number,
i_num_pes, mapped );
}
free(esstreams);
free(mapped);
}
/*****************************************************************************
* ts_hotfixes.h : MPEG PMT/PAT less streams fixups
*****************************************************************************
* Copyright (C) 2014-2016 - VideoLAN 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 General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifndef VLC_TS_HOTFIXES_H
#define VLC_TS_HOTFIXES_H
#define MIN_PAT_INTERVAL CLOCK_FREQ // DVB is 500ms
void ProbePES( demux_t *p_demux, ts_pid_t *pid, const uint8_t *p_pesstart, size_t i_data, bool b_adaptfield );
void MissingPATPMTFixup( demux_t *p_demux );
#endif
/*****************************************************************************
* ts_pid.c: Transport Stream input module for VLC.
*****************************************************************************
* Copyright (C) 2004-2016 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 General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_demux.h>
#include "ts_pid.h"
#include "ts_streams.h"
#include "ts.h"
#include <assert.h>