Commit 3014d574 authored by Francois Cartegnie's avatar Francois Cartegnie

demux: ts: add support for psip tables

parent ab7c36a7
......@@ -232,6 +232,9 @@ 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_psip.h demux/mpeg/ts_psip.c \
demux/mpeg/ts_psip_dvbpsi_fixes.h demux/mpeg/ts_psip_dvbpsi_fixes.c \
demux/mpeg/ts_decoders.h demux/mpeg/ts_decoders.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 \
......@@ -249,6 +252,7 @@ libts_plugin_la_SOURCES = demux/mpeg/ts.c demux/mpeg/ts.h \
mux/mpeg/tables.c mux/mpeg/tables.h \
mux/mpeg/tsutil.c mux/mpeg/tsutil.h \
codec/scte18.h \
codec/atsc_a65.c codec/atsc_a65.h \
codec/opus_header.c
libts_plugin_la_CFLAGS = $(AM_CFLAGS) $(DVBPSI_CFLAGS)
libts_plugin_la_LIBADD = $(DVBPSI_LIBS) $(SOCKET_LIBS)
......
......@@ -129,6 +129,8 @@ static const char *const arib_mode_list_text[] =
"Forces ARIB STD-B24 mode for decoding characters." \
"This feature affects EPG information and subtitles." )
#define ATSC_MODE_TEXT N_("ATSC")
vlc_module_begin ()
set_description( N_("MPEG Transport Stream demuxer") )
set_shortname ( "MPEG-TS" )
......@@ -155,7 +157,7 @@ vlc_module_begin ()
add_integer( "ts-arib", ARIBMODE_AUTO, SUPPORT_ARIB_TEXT, SUPPORT_ARIB_LONGTEXT, false )
change_integer_list( arib_mode_list, arib_mode_list_text )
add_bool( "ts-eas", false, SCTE18_DESCRIPTION, NULL, false )
add_bool( "ts-atsc", false, ATSC_MODE_TEXT, NULL, false )
add_obsolete_bool( "ts-silent" );
......@@ -519,7 +521,12 @@ static int Open( vlc_object_t *p_this )
p_sys->b_canfastseek = false;
p_sys->b_force_seek_per_percent = var_InheritBool( p_demux, "ts-seek-percent" );
p_sys->b_atsc_eas = var_InheritBool( p_demux, "ts-eas" );
p_sys->b_atsc = var_InheritBool( p_demux, "ts-atsc" );
if( !p_sys->b_atsc )
{
p_sys->b_atsc = !strcmp( p_demux->psz_access, "atsc" ) ||
!strcmp( p_demux->psz_access, "usdigital" );
}
p_sys->arib.e_mode = var_InheritInteger( p_demux, "ts-arib" );
stream_Control( p_sys->stream, STREAM_CAN_SEEK, &p_sys->b_canseek );
......@@ -714,6 +721,12 @@ static int Demux( demux_t *p_demux )
block_Release( p_pkt );
break;
case TYPE_PSIP:
if( p_pid->u.p_psip->handle->p_decoder )
dvbpsi_packet_push( p_pid->u.p_psip->handle, p_pkt->p_buffer );
block_Release( p_pkt );
break;
default:
/* We have to handle PCR if present */
PCRHandle( p_demux, p_pid, p_pkt );
......
......@@ -57,7 +57,7 @@ struct demux_sys_t
bool b_force_seek_per_percent;
bool b_atsc_eas;
bool b_atsc;
struct
{
arib_modes_e e_mode;
......
......@@ -172,6 +172,13 @@ bool PIDSetup( demux_t *p_demux, ts_pid_type_t i_type, ts_pid_t *pid, ts_pid_t *
return false;
break;
case TYPE_PSIP:
PIDReset( pid );
pid->u.p_psip = ts_psip_New( p_demux );
if( !pid->u.p_psip )
return false;
break;
default:
assert(false);
break;
......@@ -241,6 +248,11 @@ void PIDRelease( demux_t *p_demux, ts_pid_t *pid )
ts_psi_Del( p_demux, pid->u.p_psi );
pid->u.p_psi = NULL;
break;
case TYPE_PSIP:
ts_psip_Del( p_demux, pid->u.p_psip );
pid->u.p_psip = NULL;
break;
}
SetPIDFilter( p_demux->p_sys, pid, false );
......
......@@ -35,6 +35,7 @@ typedef enum
TYPE_SDT,
TYPE_TDT,
TYPE_EIT,
TYPE_PSIP,
} ts_pid_type_t;
enum
......@@ -65,6 +66,7 @@ struct ts_pid_t
ts_pmt_t *p_pmt;
ts_pes_t *p_pes;
ts_psi_t *p_psi;
ts_psip_t *p_psip;
} u;
struct
......
......@@ -49,6 +49,7 @@
#include "sections.h"
#include "ts_sl.h"
#include "ts_scte.h"
#include "ts_psip.h"
#include <assert.h>
......@@ -1449,10 +1450,6 @@ void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
dvbpsi_pmt_es_t *p_dvbpsies;
for( p_dvbpsies = p_dvbpsipmt->p_first_es; p_dvbpsies != NULL; p_dvbpsies = p_dvbpsies->p_next )
{
/* Do not mix with arbitrary pid if any */
if( p_sys->b_atsc_eas && p_dvbpsies->i_pid == SCTE18_SI_BASE_PID )
continue;
ts_pid_t *pespid = GetPID(p_sys, p_dvbpsies->i_pid);
if ( pespid->type != TYPE_PES && pespid->type != TYPE_FREE )
{
......@@ -1610,24 +1607,54 @@ void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
}
/* Add arbitrary PID from here */
if ( p_sys->b_atsc_eas && p_pmt->e_streams.i_size )
if ( registration_type == TS_PMT_REGISTRATION_ATSC || p_sys->b_atsc )
{
ts_pid_t *easpid = GetPID(p_sys, SCTE18_SI_BASE_PID);
if ( PIDSetup( p_demux, TYPE_PES, easpid, pmtpid ) )
ts_pid_t *atsc_base_pid = GetPID(p_sys, ATSC_BASE_PID);
if ( PIDSetup( p_demux, TYPE_PSIP, atsc_base_pid, pmtpid ) )
{
ts_psip_t *p_psip = atsc_base_pid->u.p_psip;
if( !ATSC_Attach_Dvbpsi_Base_Decoders( p_psip->handle, atsc_base_pid ) )
{
msg_Err( p_demux, "dvbpsi_atsc_AttachMGT/STT failed for program %d",
p_pmt->i_number );
PIDRelease( p_demux, atsc_base_pid );
}
else
{
p_pmt->p_mgt = atsc_base_pid;
SetPIDFilter( p_demux->p_sys, atsc_base_pid, true );
msg_Dbg( p_demux, " * pid=%d listening for MGT/STT", atsc_base_pid->i_pid );
/* Set up EAS spu es */
if( p_pmt->e_streams.i_size )
{
ts_pes_es_t *p_eas_es = ts_pes_es_New( p_pmt );
if( likely(p_eas_es) )
{
p_eas_es->fmt.i_codec = VLC_CODEC_SCTE_18;
p_eas_es->fmt.i_cat = SPU_ES;
p_eas_es->fmt.i_id = ATSC_BASE_PID;
p_eas_es->fmt.i_group = p_pmt->i_number;
p_eas_es->fmt.psz_description = strdup(SCTE18_DESCRIPTION);
if( p_psip->p_eas_es )
{
ts_pes_es_t *p_next = p_psip->p_eas_es->p_next;
p_psip->p_eas_es->p_next = p_eas_es;
p_eas_es->p_next = p_next;
}
else
{
p_psip->p_eas_es = p_eas_es;
}
msg_Dbg( p_demux, " * pid=%d listening for EAS events", ATSC_BASE_PID );
}
}
}
}
else if( atsc_base_pid->type != TYPE_FREE )
{
ARRAY_APPEND( p_pmt->e_streams, easpid );
ts_pes_t *p_easpes = easpid->u.p_pes;
p_easpes->data_type = TS_ES_DATA_TABLE_SECTION;
p_easpes->p_es->fmt.i_codec = VLC_CODEC_SCTE_18;
p_easpes->p_es->fmt.i_cat = SPU_ES;
p_easpes->p_es->fmt.i_id = SCTE18_SI_BASE_PID;
p_easpes->p_es->fmt.i_group = p_pmt->i_number;
p_easpes->p_es->fmt.psz_description = strdup(SCTE18_DESCRIPTION);
p_easpes->b_always_receive = true;
ts_sections_processor_Add( &p_easpes->p_sections_proc,
SCTE18_TABLE_ID, 0x00,
false, SCTE18_Section_Handler );
msg_Dbg( p_demux, " * pid=%d listening for EAS events", easpid->i_pid );
msg_Err( p_demux, "can't attach PSIP table handlers"
"on already in use ATSC base pid %d", ATSC_BASE_PID );
}
}
......
This diff is collapsed.
/*****************************************************************************
* ts_psip.h : TS demux ATSC A65 PSIP handling
*****************************************************************************
* Copyright (C) 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_ATSC_PSIP_H
#define VLC_ATSC_PSIP_H
#ifndef _DVBPSI_DVBPSI_H_
#include <dvbpsi/dvbpsi.h>
#endif
//#define ATSC_DEBUG_EIT /* Will also shift EPG to current time */
#define ATSC_EIT_MAX_DEPTH_MIN1 3 /* Only keep 4*3 hours tables */
#define ATSC_TABLE_TYPE_TVCT 0x0000
#define ATSC_TABLE_TYPE_TVCT_NEXT 0x0001
#define ATSC_TABLE_TYPE_CVCT 0x0002
#define ATSC_TABLE_TYPE_CVCT_NEXT 0x0003
#define ATSC_TABLE_TYPE_ETT 0x0004
#define ATSC_TABLE_TYPE_DCCSCT 0x0005
#define ATSC_TABLE_TYPE_EIT_0 0x0100
#define ATSC_TABLE_TYPE_EIT_127 0x017F
#define ATSC_TABLE_TYPE_ETT_0 0x0200
#define ATSC_TABLE_TYPE_ETT_127 0x027F
#define ATSC_TABLE_TYPE_RTT_1 0x0301
#define ATSC_TABLE_TYPE_RTT_255 0x03FF
#define ATSC_TABLE_TYPE_DCCT_00 0x1400
#define ATSC_TABLE_TYPE_DCCT_FF 0x14FF
#define ATSC_BASE_PID 0x1FFB
#define ATSC_MGT_TABLE_ID 0xC7
#define ATSC_TVCT_TABLE_ID 0xC8
#define ATSC_CVCT_TABLE_ID 0xC9
#define ATSC_RRT_TABLE_ID 0xCA
#define ATSC_EIT_TABLE_ID 0xCB
#define ATSC_ETT_TABLE_ID 0xCC
#define ATSC_STT_TABLE_ID 0xCD
#define ATSC_DESCRIPTOR_CONTENT_ADVISORY 0x87
#define ATSC_DESCRIPTOR_EXTENDED_CHANNEL_NAME 0xA0
typedef struct ts_psip_context_t ts_psip_context_t;
ts_psip_context_t * ts_psip_context_New( void );
void ts_psip_context_Delete( ts_psip_context_t * );
bool ATSC_Attach_Dvbpsi_Base_Decoders( dvbpsi_t *p_handle, void *p_cb_data );
void ATSC_Detach_Dvbpsi_Decoders( dvbpsi_t *p_handle );
#endif
......@@ -24,6 +24,11 @@
#include <vlc_demux.h>
#include <vlc_es.h>
#ifndef _DVBPSI_DVBPSI_H_
#include <dvbpsi/dvbpsi.h>
#endif
#include <dvbpsi/psi.h>
#include "ts_pid.h"
#include "ts_scte.h"
#include "ts_streams_private.h"
......@@ -31,25 +36,40 @@
#include <assert.h>
void SCTE18_Section_Handler( demux_t *p_demux, ts_pid_t *pid, block_t *p_content )
/* EAS Handling */
void SCTE18_SectionsCallback( dvbpsi_t *p_handle, const dvbpsi_psi_section_t* p_section,
void *p_base_pid )
{
assert( pid->u.p_pes->p_es->fmt.i_codec == VLC_CODEC_SCTE_18 );
ts_pmt_t *p_pmt = pid->u.p_pes->p_es->p_program;
mtime_t i_date = TimeStampWrapAround( p_pmt->pcr.i_first, p_pmt->pcr.i_current );
demux_t *p_demux = (demux_t *) p_handle->p_sys;
ts_pid_t *p_pid = (ts_pid_t *) p_base_pid;
ts_psip_t *p_psip = p_pid->u.p_psip;
if( p_pid->type != TYPE_PSIP || !p_psip->p_eas_es )
return;
int i_priority = scte18_get_EAS_priority( p_content->p_buffer, p_content->i_buffer );
msg_Dbg( p_demux, "Received EAS Alert with priority %d", i_priority );
/* We need to extract the truncated pts stored inside the payload */
ts_pes_es_t *p_es = pid->u.p_pes->p_es;
if( p_es->id )
for( ; p_section; p_section = p_section->p_next )
{
if( i_priority == EAS_PRIORITY_HIGH || i_priority == EAS_PRIORITY_MAX )
size_t i_payload = p_section->p_payload_end - p_section->p_payload_start;
const int i_priority = scte18_get_EAS_priority( p_section->p_payload_start, i_payload );
msg_Dbg( p_demux, "Received EAS Alert with priority %d", i_priority );
if( i_priority != EAS_PRIORITY_HIGH && i_priority != EAS_PRIORITY_MAX )
continue;
for( ts_pes_es_t *p_es = p_psip->p_eas_es; p_es; p_es = p_es->p_next )
{
if( !p_es->id && !(p_es->id = es_out_Add( p_demux->out, &p_es->fmt )) )
continue;
const ts_pmt_t *p_pmt = p_es->p_program;
const mtime_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 );
es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, p_es->id, true );
p_content->i_dts = p_content->i_pts = FROM_SCALE( i_date );
es_out_Send( p_demux->out, p_es->id, p_content );
es_out_Send( p_demux->out, p_es->id, p_block );
}
}
else
block_Release( p_content );
}
void SCTE27_Section_Handler( demux_t *p_demux, ts_pid_t *pid, block_t *p_content )
......
......@@ -21,7 +21,9 @@
#include "../../codec/scte18.h"
void SCTE18_Section_Handler( demux_t *p_demux, ts_pid_t *pid, block_t *p_content );
void SCTE18_SectionsCallback( dvbpsi_t *p_handle,
const dvbpsi_psi_section_t* p_section,
void *p_cb_data );
void SCTE27_Section_Handler( demux_t *p_demux, ts_pid_t *pid, block_t *p_content );
#endif
......@@ -29,7 +29,9 @@
#ifndef _DVBPSI_DVBPSI_H_
#include <dvbpsi/dvbpsi.h>
#endif
#include <dvbpsi/demux.h>
#ifndef _DVBPSI_DEMUX_H_
#include <dvbpsi/demux.h>
#endif
#include <dvbpsi/descriptor.h>
#include <dvbpsi/pat.h>
#include <dvbpsi/pmt.h>
......@@ -43,6 +45,8 @@
#include "ts_pid.h"
#include "ts.h"
#include "ts_psip.h"
static inline bool handle_Init( demux_t *p_demux, dvbpsi_t **handle )
{
*handle = dvbpsi_new( &dvbpsi_messages, DVBPSI_MSG_DEBUG );
......@@ -303,3 +307,48 @@ void ts_psi_Del( demux_t *p_demux, ts_psi_t *psi )
dvbpsi_delete( psi->handle );
free( psi );
}
void ts_psip_Del( demux_t *p_demux, ts_psip_t *psip )
{
if( psip->p_ctx )
ts_psip_context_Delete( psip->p_ctx );
ts_pes_ChainDelete_es( p_demux, psip->p_eas_es );
if( psip->handle )
{
ATSC_Detach_Dvbpsi_Decoders( psip->handle );
dvbpsi_delete( psip->handle );
}
for( int i=0; i<psip->eit.i_size; i++ )
PIDRelease( p_demux, psip->eit.p_elems[i] );
ARRAY_RESET( psip->eit );
free( psip );
}
ts_psip_t *ts_psip_New( demux_t *p_demux )
{
ts_psip_t *psip = malloc( sizeof( ts_psip_t ) );
if( !psip )
return NULL;
if( !handle_Init( p_demux, &psip->handle ) )
{
free( psip );
return NULL;
}
ARRAY_INIT( psip->eit );
psip->i_version = -1;
psip->p_eas_es = NULL;
psip->p_ctx = ts_psip_context_New();
if( !psip->p_ctx )
{
ts_psip_Del( p_demux, psip );
psip = NULL;
}
return psip;
}
......@@ -24,6 +24,7 @@ typedef struct ts_pat_t ts_pat_t;
typedef struct ts_pmt_t ts_pmt_t;
typedef struct ts_pes_t ts_pes_t;
typedef struct ts_psi_t ts_psi_t;
typedef struct ts_psip_t ts_psip_t;
/* Structs */
ts_pat_t *ts_pat_New( demux_t * );
......@@ -44,4 +45,7 @@ void ts_pes_Del( demux_t *, ts_pes_t * );
ts_psi_t *ts_psi_New( demux_t * );
void ts_psi_Del( demux_t *, ts_psi_t * );
ts_psip_t *ts_psip_New( demux_t * );
void ts_psip_Del( demux_t *, ts_psip_t * );
#endif
......@@ -117,10 +117,14 @@ struct ts_psi_t
};
typedef struct ts_psip_context_t ts_psip_context_t;
struct ts_psip_t
{
dvbpsi_t *handle;
int i_version;
ts_pes_es_t *p_eas_es;
ts_psip_context_t *p_ctx;
DECL_ARRAY(ts_pid_t *) eit;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment