mirror of
https://github.com/videolan/vlc.git
synced 2025-01-19 22:28:26 +08:00
* Moved Program Specific Information decoder to the ts demux module
* Added a mpeg_ts_dvbpsi module tha uses libdvbpsi to decode PSIs. It is used by default if the lib is found. It shares much code with mpeg_ts
This commit is contained in:
parent
060c0b88c8
commit
5a70322c5f
1
AUTHORS
1
AUTHORS
@ -46,6 +46,7 @@ E: jobi@via.ecp.fr
|
||||
C: jobi
|
||||
D: VCD input
|
||||
D: Satellite input
|
||||
D: libdvbpsi support
|
||||
S: France
|
||||
|
||||
N: Julien Blache
|
||||
|
1
Makefile
1
Makefile
@ -131,6 +131,7 @@ PLUGINS_TARGETS := a52/a52 \
|
||||
mpeg_system/mpeg_es \
|
||||
mpeg_system/mpeg_ps \
|
||||
mpeg_system/mpeg_ts \
|
||||
mpeg_system/mpeg_ts_dvbpsi \
|
||||
mpeg_adec/mpeg_adec \
|
||||
mpeg_vdec/mpeg_vdec \
|
||||
network/ipv4 \
|
||||
|
@ -73,6 +73,7 @@ builtins_CFLAGS := @builtins_CFLAGS@
|
||||
arts_CFLAGS = @arts_CFLAGS@
|
||||
dvd_CFLAGS = @dvd_CFLAGS@
|
||||
dvdread_CFLAGS = @dvdread_CFLAGS@
|
||||
mpeg_ts_dvbpsi_CFLAGS = @mpeg_ts_dvbpsi_CFLAGS@
|
||||
directx_CFLAGS = @directx_CFLAGS@
|
||||
esd_CFLAGS = @esd_CFLAGS@
|
||||
ffmpeg_CFLAGS = @ffmpeg_CFLAGS@
|
||||
@ -107,6 +108,7 @@ directx_LDFLAGS = @directx_LDFLAGS@
|
||||
dsp_LDFLAGS = @dsp_LDFLAGS@
|
||||
dvd_LDFLAGS = @dvd_LDFLAGS@
|
||||
dvdread_LDFLAGS = @dvdread_LDFLAGS@
|
||||
mpeg_ts_dvbpsi_LDFLAGS = @mpeg_ts_dvbpsi_LDFLAGS@
|
||||
esd_LDFLAGS = @esd_LDFLAGS@
|
||||
filter_distort_LDFLAGS = @filter_distort_LDFLAGS@
|
||||
ffmpeg_LDFLAGS = @ffmpeg_LDFLAGS@
|
||||
|
31
configure.in
31
configure.in
@ -680,6 +680,35 @@ then
|
||||
CPPFLAGS="$save_CPPFLAGS"
|
||||
fi
|
||||
|
||||
dnl
|
||||
dnl libdvbpsi ts demux
|
||||
dnl
|
||||
AC_ARG_ENABLE(dvbpsi,
|
||||
[ --enable-dvbpsi dvbpsi ts demux module (default disabled)])
|
||||
if test "x$enable_dvdread" != "xno"
|
||||
then
|
||||
if test "x$withval" = x
|
||||
then
|
||||
test_LDFLAGS=""
|
||||
test_CFLAGS=""
|
||||
else
|
||||
test_LDFLAGS="-L${withval}/lib"
|
||||
test_CFLAGS="-I${withval}/include"
|
||||
fi
|
||||
CPPFLAGS="$save_CPPFLAGS $test_CFLAGS"
|
||||
AC_CHECK_HEADER([dvbpsi/dvbpsi.h],[
|
||||
PLUGINS="${PLUGINS} mpeg_ts_dvbpsi"
|
||||
mpeg_ts_dvbpsi_LDFLAGS="${mpeg_ts_dvbpsi_LDFLAGS} ${test_LDFLAGS} -ldvbpsi"
|
||||
mpeg_ts_dvbpsi_CFLAGS="${mpeg_ts_dvbpsi_CFLAGS} ${test_CFLAGS}"
|
||||
],[
|
||||
if test "x$enable_dvbpsi" != x
|
||||
then
|
||||
AC_MSG_ERROR([Could not find libdvbpsi on your system: you may get it from www.videolan.org])
|
||||
fi
|
||||
])
|
||||
CPPFLAGS="$save_CPPFLAGS"
|
||||
fi
|
||||
|
||||
dnl
|
||||
dnl VCD module
|
||||
dnl
|
||||
@ -1503,6 +1532,7 @@ AC_SUBST(builtins_CFLAGS)
|
||||
AC_SUBST(arts_CFLAGS)
|
||||
AC_SUBST(dvd_CFLAGS)
|
||||
AC_SUBST(dvdread_CFLAGS)
|
||||
AC_SUBST(mpeg_ts_dvbpsi_CFLAGS)
|
||||
AC_SUBST(directx_CFLAGS)
|
||||
AC_SUBST(esd_CFLAGS)
|
||||
AC_SUBST(ffmpeg_CFLAGS)
|
||||
@ -1534,6 +1564,7 @@ AC_SUBST(directx_LDFLAGS)
|
||||
AC_SUBST(dsp_LDFLAGS)
|
||||
AC_SUBST(dvd_LDFLAGS)
|
||||
AC_SUBST(dvdread_LDFLAGS)
|
||||
AC_SUBST(mpeg_ts_dvbpsi_LDFLAGS)
|
||||
AC_SUBST(esd_LDFLAGS)
|
||||
AC_SUBST(filter_distort_LDFLAGS)
|
||||
AC_SUBST(ffmpeg_LDFLAGS)
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Collection of useful common types and macros definitions
|
||||
*****************************************************************************
|
||||
* Copyright (C) 1998, 1999, 2000 VideoLAN
|
||||
* $Id: common.h,v 1.97 2002/04/24 00:36:24 sam Exp $
|
||||
* $Id: common.h,v 1.98 2002/04/25 02:10:33 jobi Exp $
|
||||
*
|
||||
* Authors: Samuel Hocevar <sam@via.ecp.fr>
|
||||
* Vincent Seguin <seguin@via.ecp.fr>
|
||||
@ -562,6 +562,8 @@ typedef struct module_symbols_s
|
||||
int ( * input_ChangeProgram ) ( struct input_thread_s *, u16 );
|
||||
struct es_descriptor_s * ( * input_FindES ) ( struct input_thread_s *,
|
||||
u16 );
|
||||
struct pgrm_descriptor_s * ( * input_FindProgram )
|
||||
( struct input_thread_s *, u16 );
|
||||
struct es_descriptor_s * ( * input_AddES ) ( struct input_thread_s *,
|
||||
struct pgrm_descriptor_s *, u16, size_t );
|
||||
void ( * input_DelES ) ( struct input_thread_s *,
|
||||
@ -607,11 +609,12 @@ typedef struct module_symbols_s
|
||||
ssize_t ( * input_ReadTS ) ( struct input_thread_s *,
|
||||
struct data_packet_s ** );
|
||||
void ( * input_DemuxTS ) ( struct input_thread_s *,
|
||||
struct data_packet_s * );
|
||||
void ( * input_DemuxPSI ) ( struct input_thread_s *,
|
||||
struct data_packet_s *,
|
||||
struct es_descriptor_s *,
|
||||
boolean_t, boolean_t );
|
||||
void(* pf_psi_callback)
|
||||
( struct input_thread_s *,
|
||||
struct data_packet_s *,
|
||||
struct es_descriptor_s *,
|
||||
boolean_t ) );
|
||||
int ( * input_ClockManageControl ) ( struct input_thread_s *,
|
||||
struct pgrm_descriptor_s *,
|
||||
mtime_t );
|
||||
|
@ -4,7 +4,7 @@
|
||||
* control the pace of reading.
|
||||
*****************************************************************************
|
||||
* Copyright (C) 1999, 2000 VideoLAN
|
||||
* $Id: input_ext-intf.h,v 1.65 2002/04/24 00:36:24 sam Exp $
|
||||
* $Id: input_ext-intf.h,v 1.66 2002/04/25 02:10:33 jobi Exp $
|
||||
*
|
||||
* Authors: Christophe Massiot <massiot@via.ecp.fr>
|
||||
*
|
||||
@ -234,8 +234,7 @@ typedef struct stream_descriptor_s
|
||||
es_descriptor_t * p_newly_selected_es; /* ES selected from
|
||||
* the interface */
|
||||
es_descriptor_t * p_removed_es; /* ES removed from the interface */
|
||||
|
||||
|
||||
|
||||
/* Stream control */
|
||||
stream_ctrl_t control;
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* but exported to plug-ins
|
||||
*****************************************************************************
|
||||
* Copyright (C) 1999-2002 VideoLAN
|
||||
* $Id: input_ext-plugins.h,v 1.22 2002/04/24 00:36:24 sam Exp $
|
||||
* $Id: input_ext-plugins.h,v 1.23 2002/04/25 02:10:33 jobi Exp $
|
||||
*
|
||||
* Authors: Christophe Massiot <massiot@via.ecp.fr>
|
||||
*
|
||||
@ -49,6 +49,7 @@ int input_SetProgram( struct input_thread_s *, struct pgrm_descriptor_s * );
|
||||
struct input_area_s * input_AddArea( struct input_thread_s * );
|
||||
void input_DelArea ( struct input_thread_s *, struct input_area_s * );
|
||||
struct es_descriptor_s * input_FindES( struct input_thread_s *, u16 );
|
||||
struct pgrm_descriptor_s * input_FindProgram( struct input_thread_s *, u16 );
|
||||
struct es_descriptor_s * input_AddES ( struct input_thread_s *,
|
||||
struct pgrm_descriptor_s *, u16,
|
||||
size_t );
|
||||
@ -60,6 +61,7 @@ int input_UnselectES( struct input_thread_s *, struct es_descriptor_s * );
|
||||
# define input_EndStream p_symbols->input_EndStream
|
||||
# define input_SetProgram p_symbols->input_SetProgram
|
||||
# define input_FindES p_symbols->input_FindES
|
||||
# define input_FindProgram p_symbols->input_FindProgram
|
||||
# define input_AddES p_symbols->input_AddES
|
||||
# define input_DelES p_symbols->input_DelES
|
||||
# define input_SelectES p_symbols->input_SelectES
|
||||
@ -203,6 +205,19 @@ static __inline__ void input_NullPacket( input_thread_t * p_input,
|
||||
#define PSI_IS_PMT 0x01
|
||||
#define UNKNOWN_PSI 0xff
|
||||
|
||||
/****************************************************************************
|
||||
* psi_callback_t
|
||||
****************************************************************************
|
||||
* Used by TS demux to handle a PSI, either with the builtin decoder, either
|
||||
* with a library such as libdvbpsi
|
||||
****************************************************************************/
|
||||
typedef void( * psi_callback_t )(
|
||||
input_thread_t * p_input,
|
||||
data_packet_t * p_data,
|
||||
es_descriptor_t * p_es,
|
||||
boolean_t b_unit_start );
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* psi_section_t
|
||||
*****************************************************************************
|
||||
@ -256,6 +271,8 @@ typedef struct pgrm_ts_data_s
|
||||
{
|
||||
u16 i_pcr_pid; /* PCR ES, for TS streams */
|
||||
int i_pmt_version;
|
||||
/* libdvbpsi pmt decoder handle */
|
||||
void * p_pmt_handle;
|
||||
} pgrm_ts_data_t;
|
||||
|
||||
/*****************************************************************************
|
||||
@ -264,6 +281,8 @@ typedef struct pgrm_ts_data_s
|
||||
typedef struct stream_ts_data_s
|
||||
{
|
||||
int i_pat_version; /* Current version of the PAT */
|
||||
/* libdvbpsi pmt decoder handle */
|
||||
void * p_pat_handle;
|
||||
} stream_ts_data_t;
|
||||
|
||||
/*****************************************************************************
|
||||
@ -292,9 +311,8 @@ es_descriptor_t * input_ParsePS( struct input_thread_s *,
|
||||
struct data_packet_s * );
|
||||
ssize_t input_ReadTS ( struct input_thread_s *, struct data_packet_s ** );
|
||||
void input_DemuxPS ( struct input_thread_s *, struct data_packet_s * );
|
||||
void input_DemuxTS ( struct input_thread_s *, struct data_packet_s * );
|
||||
void input_DemuxPSI ( struct input_thread_s *, struct data_packet_s *,
|
||||
struct es_descriptor_s *, boolean_t, boolean_t );
|
||||
void input_DemuxTS ( struct input_thread_s *, struct data_packet_s *,
|
||||
psi_callback_t );
|
||||
#else
|
||||
# define input_ParsePES p_symbols->input_ParsePES
|
||||
# define input_GatherPES p_symbols->input_GatherPES
|
||||
@ -303,7 +321,6 @@ void input_DemuxPSI ( struct input_thread_s *, struct data_packet_s *,
|
||||
# define input_DemuxPS p_symbols->input_DemuxPS
|
||||
# define input_ReadTS p_symbols->input_ReadTS
|
||||
# define input_DemuxTS p_symbols->input_DemuxTS
|
||||
# define input_DemuxPSI p_symbols->input_DemuxPSI
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
mpeg_es_SOURCES = mpeg_es.c
|
||||
mpeg_ps_SOURCES = mpeg_ps.c
|
||||
mpeg_ts_SOURCES = mpeg_ts.c
|
||||
mpeg_ts_dvbpsi_SOURCES = mpeg_ts.c
|
||||
|
@ -2,9 +2,10 @@
|
||||
* mpeg_ts.c : Transport Stream input module for vlc
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2000-2001 VideoLAN
|
||||
* $Id: mpeg_ts.c,v 1.8 2002/04/19 13:56:11 sam Exp $
|
||||
* $Id: mpeg_ts.c,v 1.9 2002/04/25 02:10:33 jobi Exp $
|
||||
*
|
||||
* Authors: Henri Fallon <henri@via.ecp.fr>
|
||||
* Johan Bilien <jobi@via.ecp.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -35,6 +36,12 @@
|
||||
#include "input_ext-dec.h"
|
||||
#include "input_ext-plugins.h"
|
||||
|
||||
#if defined MODULE_NAME_IS_mpeg_ts_dvbpsi
|
||||
#include <dvbpsi/dvbpsi.h>
|
||||
#include <dvbpsi/descriptor.h>
|
||||
#include <dvbpsi/pat.h>
|
||||
#include <dvbpsi/pmt.h>
|
||||
#endif
|
||||
/*****************************************************************************
|
||||
* Constants
|
||||
*****************************************************************************/
|
||||
@ -48,6 +55,23 @@ static int TSInit ( struct input_thread_s * );
|
||||
static void TSEnd ( struct input_thread_s * );
|
||||
static int TSDemux ( struct input_thread_s * );
|
||||
|
||||
#if defined MODULE_NAME_IS_mpeg_ts
|
||||
static void TSDemuxPSI ( struct input_thread_s *, struct data_packet_s *,
|
||||
struct es_descriptor_s *, boolean_t );
|
||||
static void TSDecodePAT( input_thread_t *, es_descriptor_t *);
|
||||
static void TSDecodePMT( input_thread_t *, es_descriptor_t *);
|
||||
#define PSI_CALLBACK TSDemuxPSI
|
||||
#elif defined MODULE_NAME_IS_mpeg_ts_dvbpsi
|
||||
static void TS_DVBPSI_DemuxPSI
|
||||
( struct input_thread_s *, struct data_packet_s *,
|
||||
struct es_descriptor_s *, boolean_t );
|
||||
static void TS_DVBPSI_HandlePAT
|
||||
( struct input_thread_s *, dvbpsi_pat_t * );
|
||||
static void TS_DVBPSI_HandlePMT
|
||||
( struct input_thread_s *, dvbpsi_pmt_t * );
|
||||
#define PSI_CALLBACK TS_DVBPSI_DemuxPSI
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* Build configuration tree.
|
||||
*****************************************************************************/
|
||||
@ -55,9 +79,15 @@ MODULE_CONFIG_START
|
||||
MODULE_CONFIG_STOP
|
||||
|
||||
MODULE_INIT_START
|
||||
#if defined MODULE_NAME_IS_mpeg_ts
|
||||
SET_DESCRIPTION( _("ISO 13818-1 MPEG Transport Stream input") )
|
||||
ADD_CAPABILITY( DEMUX, 160 )
|
||||
ADD_SHORTCUT( "ts" )
|
||||
#elif defined MODULE_NAME_IS_mpeg_ts_dvbpsi
|
||||
SET_DESCRIPTION( _("ISO 13818-1 MPEG Transport Stream input (libdvbpsi)") )
|
||||
ADD_CAPABILITY( DEMUX, 170 )
|
||||
ADD_SHORTCUT( "ts_dvbpsi" )
|
||||
#endif
|
||||
MODULE_INIT_STOP
|
||||
|
||||
MODULE_ACTIVATE_START
|
||||
@ -126,14 +156,27 @@ static int TSInit( input_thread_t * p_input )
|
||||
p_input->i_bufsize = (p_input->i_mtu / TS_PACKET_SIZE) * TS_PACKET_SIZE;
|
||||
}
|
||||
|
||||
vlc_mutex_lock( &p_input->stream.stream_lock );
|
||||
|
||||
if( input_InitStream( p_input, sizeof( stream_ts_data_t ) ) == -1 )
|
||||
{
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
|
||||
p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
|
||||
p_stream_data->i_pat_version = PAT_UNINITIALIZED ;
|
||||
|
||||
#ifdef MODULE_NAME_IS_mpeg_ts_dvbpsi
|
||||
p_stream_data->p_pat_handle = (dvbpsi_handle *)
|
||||
dvbpsi_AttachPAT( (dvbpsi_pat_callback) &TS_DVBPSI_HandlePAT, p_input );
|
||||
|
||||
if( p_stream_data->p_pat_handle == NULL )
|
||||
{
|
||||
intf_ErrMsg( "input: ts: could not create PAT decoder" );
|
||||
return( -1 );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We'll have to catch the PAT in order to continue
|
||||
* Then the input will catch the PMT and then the others ES
|
||||
* The PAT es is indepedent of any program. */
|
||||
@ -145,6 +188,8 @@ static int TSInit( input_thread_t * p_input )
|
||||
p_demux_data->p_psi_section = malloc(sizeof(psi_section_t));
|
||||
p_demux_data->p_psi_section->b_is_complete = 1;
|
||||
|
||||
vlc_mutex_unlock( &p_input->stream.stream_lock );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
@ -180,9 +225,651 @@ static int TSDemux( input_thread_t * p_input )
|
||||
return( i_result );
|
||||
}
|
||||
|
||||
input_DemuxTS( p_input, p_data );
|
||||
input_DemuxTS( p_input, p_data, (psi_callback_t) &PSI_CALLBACK );
|
||||
}
|
||||
|
||||
return( i_read_once );
|
||||
}
|
||||
|
||||
|
||||
#if defined MODULE_NAME_IS_mpeg_ts
|
||||
/*
|
||||
* PSI demultiplexing and decoding without libdvbpsi
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* DemuxPSI : makes up complete PSI data
|
||||
*****************************************************************************/
|
||||
static void TSDemuxPSI( input_thread_t * p_input, data_packet_t * p_data,
|
||||
es_descriptor_t * p_es, boolean_t b_unit_start )
|
||||
{
|
||||
es_ts_data_t * p_demux_data;
|
||||
|
||||
p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
|
||||
|
||||
#define p_psi (p_demux_data->p_psi_section)
|
||||
#define p (p_data->p_payload_start)
|
||||
|
||||
if( b_unit_start )
|
||||
{
|
||||
/* unit_start set to 1 -> presence of a pointer field
|
||||
* (see ISO/IEC 13818 (2.4.4.2) which should be set to 0x00 */
|
||||
if( (u8)p[0] != 0x00 )
|
||||
{
|
||||
intf_WarnMsg( 2, "input: non zero pointer field found, "
|
||||
"trying to continue" );
|
||||
p+=(u8)p[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
p++;
|
||||
}
|
||||
|
||||
/* This is the begining of a new section */
|
||||
|
||||
if( ((u8)(p[1]) & 0xc0) != 0x80 )
|
||||
{
|
||||
intf_WarnMsg( 2, "input: invalid PSI packet" );
|
||||
p_psi->b_trash = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_psi->i_section_length = ((p[1] & 0xF) << 8) | p[2];
|
||||
p_psi->b_section_complete = 0;
|
||||
p_psi->i_read_in_section = 0;
|
||||
p_psi->i_section_number = (u8)p[6];
|
||||
|
||||
if( p_psi->b_is_complete || p_psi->i_section_number == 0 )
|
||||
{
|
||||
/* This is a new PSI packet */
|
||||
p_psi->b_is_complete = 0;
|
||||
p_psi->b_trash = 0;
|
||||
p_psi->i_version_number = ( p[5] >> 1 ) & 0x1f;
|
||||
p_psi->i_last_section_number = (u8)p[7];
|
||||
|
||||
/* We'll write at the begining of the buffer */
|
||||
p_psi->p_current = p_psi->buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( p_psi->b_section_complete )
|
||||
{
|
||||
/* New Section of an already started PSI */
|
||||
p_psi->b_section_complete = 0;
|
||||
|
||||
if( p_psi->i_version_number != (( p[5] >> 1 ) & 0x1f) )
|
||||
{
|
||||
intf_WarnMsg( 2, "input: PSI version differs "
|
||||
"inside same PAT" );
|
||||
p_psi->b_trash = 1;
|
||||
}
|
||||
if( p_psi->i_section_number + 1 != (u8)p[6] )
|
||||
{
|
||||
intf_WarnMsg( 2, "input: PSI Section discontinuity, "
|
||||
"packet lost ?" );
|
||||
p_psi->b_trash = 1;
|
||||
}
|
||||
else
|
||||
p_psi->i_section_number++;
|
||||
}
|
||||
else
|
||||
{
|
||||
intf_WarnMsg( 2, "input: got unexpected new PSI section" );
|
||||
p_psi->b_trash = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* b_unit_start */
|
||||
|
||||
if( !p_psi->b_trash )
|
||||
{
|
||||
/* read */
|
||||
if( (p_data->p_payload_end - p) >=
|
||||
( p_psi->i_section_length - p_psi->i_read_in_section ) )
|
||||
{
|
||||
/* The end of the section is in this TS packet */
|
||||
memcpy( p_psi->p_current, p,
|
||||
(p_psi->i_section_length - p_psi->i_read_in_section) );
|
||||
|
||||
p_psi->b_section_complete = 1;
|
||||
p_psi->p_current +=
|
||||
(p_psi->i_section_length - p_psi->i_read_in_section);
|
||||
|
||||
if( p_psi->i_section_number == p_psi->i_last_section_number )
|
||||
{
|
||||
/* This was the last section of PSI */
|
||||
p_psi->b_is_complete = 1;
|
||||
|
||||
switch( p_demux_data->i_psi_type)
|
||||
{
|
||||
case PSI_IS_PAT:
|
||||
TSDecodePAT( p_input, p_es );
|
||||
break;
|
||||
case PSI_IS_PMT:
|
||||
TSDecodePMT( p_input, p_es );
|
||||
break;
|
||||
default:
|
||||
intf_WarnMsg(2, "Received unknown PSI in DemuxPSI");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( p_psi->buffer, p, p_data->p_payload_end - p );
|
||||
p_psi->i_read_in_section += p_data->p_payload_end - p;
|
||||
|
||||
p_psi->p_current += p_data->p_payload_end - p;
|
||||
}
|
||||
}
|
||||
|
||||
#undef p_psi
|
||||
#undef p
|
||||
|
||||
input_DeletePacket( p_input->p_method_data, p_data );
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* DecodePAT : Decodes Programm association table and deal with it
|
||||
*****************************************************************************/
|
||||
static void TSDecodePAT( input_thread_t * p_input, es_descriptor_t * p_es )
|
||||
{
|
||||
stream_ts_data_t * p_stream_data;
|
||||
es_ts_data_t * p_demux_data;
|
||||
|
||||
pgrm_descriptor_t * p_pgrm;
|
||||
es_descriptor_t * p_current_es;
|
||||
byte_t * p_current_data;
|
||||
|
||||
int i_section_length, i_program_id, i_pmt_pid;
|
||||
int i_loop, i_current_section;
|
||||
|
||||
boolean_t b_changed = 0;
|
||||
|
||||
p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
|
||||
p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
|
||||
|
||||
#define p_psi (p_demux_data->p_psi_section)
|
||||
|
||||
/* Not so fast, Mike ! If the PAT version has changed, we first check
|
||||
* that its content has really changed before doing anything */
|
||||
if( p_stream_data->i_pat_version != p_psi->i_version_number )
|
||||
{
|
||||
int i_programs = p_input->stream.i_pgrm_number;
|
||||
|
||||
p_current_data = p_psi->buffer;
|
||||
|
||||
do
|
||||
{
|
||||
i_section_length = ((u32)(p_current_data[1] & 0xF) << 8) |
|
||||
p_current_data[2];
|
||||
i_current_section = (u8)p_current_data[6];
|
||||
|
||||
for( i_loop = 0;
|
||||
( i_loop < (i_section_length - 9) / 4 ) && !b_changed;
|
||||
i_loop++ )
|
||||
{
|
||||
i_program_id = ( (u32)*(p_current_data + i_loop * 4 + 8) << 8 )
|
||||
| *(p_current_data + i_loop * 4 + 9);
|
||||
i_pmt_pid = ( ((u32)*(p_current_data + i_loop * 4 + 10) & 0x1F)
|
||||
<< 8 )
|
||||
| *(p_current_data + i_loop * 4 + 11);
|
||||
|
||||
if( i_program_id )
|
||||
{
|
||||
if( (p_pgrm = input_FindProgram( p_input, i_program_id ))
|
||||
&& (p_current_es = input_FindES( p_input, i_pmt_pid ))
|
||||
&& p_current_es->p_pgrm == p_pgrm
|
||||
&& p_current_es->i_id == i_pmt_pid
|
||||
&& ((es_ts_data_t *)p_current_es->p_demux_data)->b_psi
|
||||
&& ((es_ts_data_t *)p_current_es->p_demux_data)
|
||||
->i_psi_type == PSI_IS_PMT )
|
||||
{
|
||||
i_programs--;
|
||||
}
|
||||
else
|
||||
{
|
||||
b_changed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p_current_data += 3 + i_section_length;
|
||||
|
||||
} while( ( i_current_section < p_psi->i_last_section_number )
|
||||
&& !b_changed );
|
||||
|
||||
/* If we didn't find the expected amount of programs, the PAT has
|
||||
* changed. Otherwise, it only changed if b_changed is already != 0 */
|
||||
b_changed = b_changed || i_programs;
|
||||
}
|
||||
|
||||
if( b_changed )
|
||||
{
|
||||
/* PAT has changed. We are going to delete all programs and
|
||||
* create new ones. We chose not to only change what was needed
|
||||
* as a PAT change may mean the stream is radically changing and
|
||||
* this is a secure method to avoid crashes */
|
||||
es_ts_data_t * p_es_demux;
|
||||
pgrm_ts_data_t * p_pgrm_demux;
|
||||
|
||||
p_current_data = p_psi->buffer;
|
||||
|
||||
/* Delete all programs */
|
||||
while( p_input->stream.i_pgrm_number )
|
||||
{
|
||||
input_DelProgram( p_input, p_input->stream.pp_programs[0] );
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
i_section_length = ((u32)(p_current_data[1] & 0xF) << 8) |
|
||||
p_current_data[2];
|
||||
i_current_section = (u8)p_current_data[6];
|
||||
|
||||
for( i_loop = 0; i_loop < (i_section_length - 9) / 4 ; i_loop++ )
|
||||
{
|
||||
i_program_id = ( (u32)*(p_current_data + i_loop * 4 + 8) << 8 )
|
||||
| *(p_current_data + i_loop * 4 + 9);
|
||||
i_pmt_pid = ( ((u32)*(p_current_data + i_loop * 4 + 10) & 0x1F)
|
||||
<< 8 )
|
||||
| *(p_current_data + i_loop * 4 + 11);
|
||||
|
||||
/* If program = 0, we're having info about NIT not PMT */
|
||||
if( i_program_id )
|
||||
{
|
||||
/* Add this program */
|
||||
p_pgrm = input_AddProgram( p_input, i_program_id,
|
||||
sizeof( pgrm_ts_data_t ) );
|
||||
|
||||
/* whatis the PID of the PMT of this program */
|
||||
p_pgrm_demux = (pgrm_ts_data_t *)p_pgrm->p_demux_data;
|
||||
p_pgrm_demux->i_pmt_version = PMT_UNINITIALIZED;
|
||||
|
||||
/* Add the PMT ES to this program */
|
||||
p_current_es = input_AddES( p_input, p_pgrm,(u16)i_pmt_pid,
|
||||
sizeof( es_ts_data_t) );
|
||||
p_es_demux = (es_ts_data_t *)p_current_es->p_demux_data;
|
||||
p_es_demux->b_psi = 1;
|
||||
p_es_demux->i_psi_type = PSI_IS_PMT;
|
||||
|
||||
p_es_demux->p_psi_section =
|
||||
malloc( sizeof( psi_section_t ) );
|
||||
p_es_demux->p_psi_section->b_is_complete = 0;
|
||||
}
|
||||
}
|
||||
|
||||
p_current_data += 3 + i_section_length;
|
||||
|
||||
} while( i_current_section < p_psi->i_last_section_number );
|
||||
|
||||
/* Go to the beginning of the next section */
|
||||
p_stream_data->i_pat_version = p_psi->i_version_number;
|
||||
|
||||
}
|
||||
#undef p_psi
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* DecodePMT : decode a given Program Stream Map
|
||||
* ***************************************************************************
|
||||
* When the PMT changes, it may mean a deep change in the stream, and it is
|
||||
* careful to delete the ES and add them again. If the PMT doesn't change,
|
||||
* there no need to do anything.
|
||||
*****************************************************************************/
|
||||
static void TSDecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
|
||||
{
|
||||
|
||||
pgrm_ts_data_t * p_pgrm_data;
|
||||
es_ts_data_t * p_demux_data;
|
||||
|
||||
p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
|
||||
p_pgrm_data = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data;
|
||||
|
||||
#define p_psi (p_demux_data->p_psi_section)
|
||||
|
||||
if( p_psi->i_version_number != p_pgrm_data->i_pmt_version )
|
||||
{
|
||||
es_descriptor_t * p_new_es;
|
||||
es_ts_data_t * p_es_demux;
|
||||
byte_t * p_current_data, * p_current_section;
|
||||
int i_section_length,i_current_section;
|
||||
int i_prog_info_length, i_loop;
|
||||
int i_es_info_length, i_pid, i_stream_type;
|
||||
|
||||
p_current_section = p_psi->buffer;
|
||||
p_current_data = p_psi->buffer;
|
||||
|
||||
p_pgrm_data->i_pcr_pid = ( ((u32)*(p_current_section + 8) & 0x1F) << 8 ) |
|
||||
*(p_current_section + 9);
|
||||
|
||||
|
||||
/* Lock stream information */
|
||||
vlc_mutex_lock( &p_input->stream.stream_lock );
|
||||
|
||||
/* Delete all ES in this program except the PSI. We start from the
|
||||
* end because i_es_number gets decremented after each deletion. */
|
||||
for( i_loop = p_es->p_pgrm->i_es_number ; i_loop ; )
|
||||
{
|
||||
i_loop--;
|
||||
p_es_demux = (es_ts_data_t *)
|
||||
p_es->p_pgrm->pp_es[i_loop]->p_demux_data;
|
||||
if ( ! p_es_demux->b_psi )
|
||||
{
|
||||
input_DelES( p_input, p_es->p_pgrm->pp_es[i_loop] );
|
||||
}
|
||||
}
|
||||
|
||||
/* Then add what we received in this PMT */
|
||||
do
|
||||
{
|
||||
i_section_length = ( ((u32)*(p_current_data + 1) & 0xF) << 8 ) |
|
||||
*(p_current_data + 2);
|
||||
i_current_section = (u8)p_current_data[6];
|
||||
i_prog_info_length = ( ((u32)*(p_current_data + 10) & 0xF) << 8 ) |
|
||||
*(p_current_data + 11);
|
||||
|
||||
/* For the moment we ignore program descriptors */
|
||||
p_current_data += 12 + i_prog_info_length;
|
||||
|
||||
/* The end of the section, before the CRC is at
|
||||
* p_current_section + i_section_length -1 */
|
||||
while( p_current_data < p_current_section + i_section_length -1 )
|
||||
{
|
||||
i_stream_type = (int)p_current_data[0];
|
||||
i_pid = ( ((u32)*(p_current_data + 1) & 0x1F) << 8 ) |
|
||||
*(p_current_data + 2);
|
||||
i_es_info_length = ( ((u32)*(p_current_data + 3) & 0xF) << 8 ) |
|
||||
*(p_current_data + 4);
|
||||
|
||||
/* Add this ES to the program */
|
||||
p_new_es = input_AddES( p_input, p_es->p_pgrm,
|
||||
(u16)i_pid, sizeof( es_ts_data_t ) );
|
||||
|
||||
/* Tell the decoders what kind of stream it is */
|
||||
p_new_es->i_type = i_stream_type;
|
||||
|
||||
/* Tell the interface what kind of stream it is and select
|
||||
* the required ones */
|
||||
{
|
||||
switch( i_stream_type )
|
||||
{
|
||||
case MPEG1_VIDEO_ES:
|
||||
case MPEG2_VIDEO_ES:
|
||||
p_new_es->i_cat = VIDEO_ES;
|
||||
break;
|
||||
case MPEG1_AUDIO_ES:
|
||||
case MPEG2_AUDIO_ES:
|
||||
p_new_es->i_cat = AUDIO_ES;
|
||||
break;
|
||||
case LPCM_AUDIO_ES :
|
||||
case AC3_AUDIO_ES :
|
||||
p_new_es->i_stream_id = 0xBD;
|
||||
p_new_es->i_cat = AUDIO_ES;
|
||||
break;
|
||||
/* Not sure this one is fully specification-compliant */
|
||||
case DVD_SPU_ES :
|
||||
p_new_es->i_stream_id = 0xBD;
|
||||
p_new_es->i_cat = SPU_ES;
|
||||
break;
|
||||
default :
|
||||
p_new_es->i_cat = UNKNOWN_ES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p_current_data += 5 + i_es_info_length;
|
||||
}
|
||||
|
||||
/* Go to the beginning of the next section*/
|
||||
p_current_data += 3 + i_section_length;
|
||||
|
||||
p_current_section++;
|
||||
|
||||
} while( i_current_section < p_psi->i_last_section_number );
|
||||
|
||||
p_pgrm_data->i_pmt_version = p_psi->i_version_number;
|
||||
|
||||
/* if no program is selected :*/
|
||||
if( !p_input->stream.p_selected_program )
|
||||
{
|
||||
pgrm_descriptor_t * p_pgrm_to_select;
|
||||
u16 i_id = (u16)config_GetIntVariable( "program" );
|
||||
|
||||
if( i_id != 0 ) /* if user specified a program */
|
||||
{
|
||||
p_pgrm_to_select = input_FindProgram( p_input, i_id );
|
||||
|
||||
if( p_pgrm_to_select || p_pgrm_to_select == p_es->p_pgrm )
|
||||
p_input->pf_set_program( p_input, p_pgrm_to_select );
|
||||
}
|
||||
else
|
||||
p_input->pf_set_program( p_input, p_es->p_pgrm );
|
||||
}
|
||||
|
||||
/* inform interface that stream has changed */
|
||||
p_input->stream.b_changed = 1;
|
||||
/* Remove lock */
|
||||
vlc_mutex_unlock( &p_input->stream.stream_lock );
|
||||
}
|
||||
|
||||
#undef p_psi
|
||||
}
|
||||
|
||||
#elif defined MODULE_NAME_IS_mpeg_ts_dvbpsi
|
||||
/*
|
||||
* PSI Decoding using libdvbcss
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* DemuxPSI : send the PSI to the right libdvbpsi decoder
|
||||
*****************************************************************************/
|
||||
static void TS_DVBPSI_DemuxPSI( input_thread_t * p_input,
|
||||
data_packet_t * p_data,
|
||||
es_descriptor_t * p_es,
|
||||
boolean_t b_unit_start )
|
||||
{
|
||||
es_ts_data_t * p_es_demux_data;
|
||||
pgrm_ts_data_t * p_pgrm_demux_data;
|
||||
stream_ts_data_t * p_stream_demux_data;
|
||||
|
||||
p_es_demux_data = ( es_ts_data_t * ) p_es->p_demux_data;
|
||||
p_stream_demux_data = ( stream_ts_data_t * ) p_input->stream.p_demux_data;
|
||||
|
||||
switch( p_es_demux_data->i_psi_type)
|
||||
{
|
||||
case PSI_IS_PAT:
|
||||
dvbpsi_PushPacket(
|
||||
( dvbpsi_handle ) p_stream_demux_data->p_pat_handle,
|
||||
p_data->p_demux_start );
|
||||
break;
|
||||
case PSI_IS_PMT:
|
||||
p_pgrm_demux_data = ( pgrm_ts_data_t * )p_es->p_pgrm->p_demux_data;
|
||||
dvbpsi_PushPacket(
|
||||
( dvbpsi_handle ) p_pgrm_demux_data->p_pmt_handle,
|
||||
p_data->p_demux_start );
|
||||
break;
|
||||
default:
|
||||
intf_WarnMsg( 2, "Received unknown PSI in DemuxPSI" );
|
||||
}
|
||||
|
||||
input_DeletePacket( p_input->p_method_data, p_data );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* HandlePAT: will treat a PAT returned by dvbpsi
|
||||
*****************************************************************************/
|
||||
|
||||
void TS_DVBPSI_HandlePAT( input_thread_t * p_input, dvbpsi_pat_t * p_new_pat )
|
||||
{
|
||||
dvbpsi_pat_program_t * p_pgrm;
|
||||
pgrm_descriptor_t * p_new_pgrm;
|
||||
pgrm_ts_data_t * p_pgrm_demux;
|
||||
es_descriptor_t * p_current_es;
|
||||
es_ts_data_t * p_es_demux;
|
||||
stream_ts_data_t * p_stream_data;
|
||||
|
||||
vlc_mutex_lock( &p_input->stream.stream_lock );
|
||||
|
||||
p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
|
||||
|
||||
if ( !p_new_pat->b_current_next ||
|
||||
p_stream_data->i_pat_version == PAT_UNINITIALIZED )
|
||||
{
|
||||
/* Delete all programs */
|
||||
while( p_input->stream.i_pgrm_number )
|
||||
{
|
||||
input_DelProgram( p_input, p_input->stream.pp_programs[0] );
|
||||
}
|
||||
|
||||
/* treat the new programs list */
|
||||
p_pgrm = p_new_pat->p_first_program;
|
||||
|
||||
while( p_pgrm )
|
||||
{
|
||||
/* If program = 0, we're having info about NIT not PMT */
|
||||
if( p_pgrm->i_number )
|
||||
{
|
||||
/* Add this program */
|
||||
p_new_pgrm = input_AddProgram( p_input, p_pgrm->i_number,
|
||||
sizeof( pgrm_ts_data_t ) );
|
||||
|
||||
p_pgrm_demux = (pgrm_ts_data_t *)p_new_pgrm->p_demux_data;
|
||||
p_pgrm_demux->i_pmt_version = PMT_UNINITIALIZED;
|
||||
|
||||
/* Add the PMT ES to this program */
|
||||
p_current_es = input_AddES( p_input, p_new_pgrm,
|
||||
(u16) p_pgrm->i_pid,
|
||||
sizeof( es_ts_data_t) );
|
||||
p_es_demux = (es_ts_data_t *)p_current_es->p_demux_data;
|
||||
p_es_demux->b_psi = 1;
|
||||
p_es_demux->i_psi_type = PSI_IS_PMT;
|
||||
|
||||
p_es_demux->p_psi_section = malloc( sizeof( psi_section_t ) );
|
||||
if ( p_es_demux->p_psi_section == NULL )
|
||||
{
|
||||
intf_ErrMsg( "input: ts: could not malloc pmt section" );
|
||||
p_input->b_error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
p_es_demux->p_psi_section->b_is_complete = 0;
|
||||
|
||||
/* Create a PMT decoder */
|
||||
p_pgrm_demux->p_pmt_handle = (dvbpsi_handle *)
|
||||
dvbpsi_AttachPMT( p_pgrm->i_number,
|
||||
(dvbpsi_pmt_callback) &TS_DVBPSI_HandlePMT,
|
||||
p_input );
|
||||
|
||||
if( p_pgrm_demux->p_pmt_handle == NULL )
|
||||
{
|
||||
intf_ErrMsg( "input: ts: could not create PMT decoder" );
|
||||
p_input->b_error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
p_pgrm = p_pgrm->p_next;
|
||||
}
|
||||
|
||||
p_stream_data->i_pat_version = p_new_pat->i_version;
|
||||
}
|
||||
vlc_mutex_unlock( &p_input->stream.stream_lock );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* HandlePMT: will treat a PMT returned by dvbpsi
|
||||
*****************************************************************************/
|
||||
void TS_DVBPSI_HandlePMT( input_thread_t * p_input, dvbpsi_pmt_t * p_new_pmt )
|
||||
{
|
||||
dvbpsi_pmt_es_t * p_es;
|
||||
pgrm_descriptor_t * p_pgrm;
|
||||
es_descriptor_t * p_new_es;
|
||||
pgrm_ts_data_t * p_pgrm_demux;
|
||||
|
||||
vlc_mutex_lock( &p_input->stream.stream_lock );
|
||||
|
||||
p_pgrm = input_FindProgram( p_input, p_new_pmt->i_program_number );
|
||||
|
||||
if( p_pgrm == NULL )
|
||||
{
|
||||
intf_WarnMsg( 2, "input: ts: PMT of unreferenced program found" );
|
||||
return;
|
||||
}
|
||||
|
||||
p_pgrm_demux = (pgrm_ts_data_t *)p_pgrm->p_demux_data;
|
||||
p_pgrm_demux->i_pcr_pid = p_new_pmt->i_pcr_pid;
|
||||
|
||||
if( !p_new_pmt->b_current_next ||
|
||||
p_pgrm_demux->i_pmt_version == PMT_UNINITIALIZED )
|
||||
{
|
||||
p_es = p_new_pmt->p_first_es;
|
||||
while( p_es )
|
||||
{
|
||||
/* Add this ES */
|
||||
p_new_es = input_AddES( p_input, p_pgrm,
|
||||
(u16)p_es->i_pid, sizeof( es_ts_data_t ) );
|
||||
if( p_new_es == NULL )
|
||||
{
|
||||
intf_ErrMsg( "input: ts: Could not add ES %d", p_es->i_pid );
|
||||
p_input->b_error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
p_new_es->i_type = p_es->i_type;
|
||||
switch( p_es->i_type )
|
||||
{
|
||||
case MPEG1_VIDEO_ES:
|
||||
case MPEG2_VIDEO_ES:
|
||||
p_new_es->i_cat = VIDEO_ES;
|
||||
break;
|
||||
case MPEG1_AUDIO_ES:
|
||||
case MPEG2_AUDIO_ES:
|
||||
p_new_es->i_cat = AUDIO_ES;
|
||||
break;
|
||||
case LPCM_AUDIO_ES:
|
||||
case AC3_AUDIO_ES:
|
||||
p_new_es->i_cat = AUDIO_ES;
|
||||
p_new_es->i_stream_id = 0xBD;
|
||||
break;
|
||||
case DVD_SPU_ES:
|
||||
p_new_es->i_cat = SPU_ES;
|
||||
p_new_es->i_stream_id = 0xBD;
|
||||
break;
|
||||
default:
|
||||
p_new_es->i_cat = UNKNOWN_ES;
|
||||
}
|
||||
p_es = p_es->p_next;
|
||||
}
|
||||
|
||||
/* if no program is selected :*/
|
||||
if( !p_input->stream.p_selected_program )
|
||||
{
|
||||
pgrm_descriptor_t * p_pgrm_to_select;
|
||||
u16 i_id = (u16)config_GetIntVariable( "program" );
|
||||
|
||||
if( i_id != 0 ) /* if user specified a program */
|
||||
{
|
||||
p_pgrm_to_select = input_FindProgram( p_input, i_id );
|
||||
|
||||
if( p_pgrm_to_select && p_pgrm_to_select == p_pgrm )
|
||||
p_input->pf_set_program( p_input, p_pgrm_to_select );
|
||||
}
|
||||
else
|
||||
p_input->pf_set_program( p_input, p_pgrm );
|
||||
}
|
||||
/* if the pmt belongs to the currently selected program, we
|
||||
* reselect it to update its ES */
|
||||
else if( p_pgrm == p_input->stream.p_selected_program )
|
||||
{
|
||||
p_input->pf_set_program( p_input, p_pgrm );
|
||||
}
|
||||
|
||||
p_pgrm_demux->i_pmt_version = p_new_pmt->i_version;
|
||||
p_input->stream.b_changed = 1;
|
||||
}
|
||||
vlc_mutex_unlock( &p_input->stream.stream_lock );
|
||||
}
|
||||
#endif
|
||||
|
@ -2,7 +2,7 @@
|
||||
* mpeg_system.c: TS, PS and PES management
|
||||
*****************************************************************************
|
||||
* Copyright (C) 1998-2001 VideoLAN
|
||||
* $Id: mpeg_system.c,v 1.91 2002/04/23 14:16:20 sam Exp $
|
||||
* $Id: mpeg_system.c,v 1.92 2002/04/25 02:10:33 jobi Exp $
|
||||
*
|
||||
* Authors: Christophe Massiot <massiot@via.ecp.fr>
|
||||
* Michel Lespinasse <walken@via.ecp.fr>
|
||||
@ -39,13 +39,6 @@
|
||||
#include "input_ext-dec.h"
|
||||
#include "input_ext-plugins.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Local prototypes
|
||||
*****************************************************************************/
|
||||
|
||||
static void input_DecodePAT( input_thread_t *, es_descriptor_t *);
|
||||
static void input_DecodePMT( input_thread_t *, es_descriptor_t *);
|
||||
|
||||
/*
|
||||
* PES Packet management
|
||||
*/
|
||||
@ -1087,7 +1080,8 @@ ssize_t input_ReadTS( input_thread_t * p_input, data_packet_t ** pp_data )
|
||||
/*****************************************************************************
|
||||
* input_DemuxTS: first step of demultiplexing: the TS header
|
||||
*****************************************************************************/
|
||||
void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
|
||||
void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data,
|
||||
psi_callback_t pf_psi_callback )
|
||||
{
|
||||
u16 i_pid;
|
||||
int i_dummy;
|
||||
@ -1295,9 +1289,7 @@ void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
|
||||
if( b_psi )
|
||||
{
|
||||
/* The payload contains PSI tables */
|
||||
input_DemuxPSI( p_input, p_data, p_es,
|
||||
b_unit_start, b_lost );
|
||||
|
||||
(* pf_psi_callback) ( p_input, p_data, p_es, b_unit_start );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1310,429 +1302,3 @@ void input_DemuxTS( input_thread_t * p_input, data_packet_t * p_data )
|
||||
#undef p
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* PSI demultiplexing and decoding
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* DemuxPSI : makes up complete PSI data
|
||||
*****************************************************************************/
|
||||
void input_DemuxPSI( input_thread_t * p_input, data_packet_t * p_data,
|
||||
es_descriptor_t * p_es, boolean_t b_unit_start, boolean_t b_lost )
|
||||
{
|
||||
es_ts_data_t * p_demux_data;
|
||||
|
||||
p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
|
||||
|
||||
#define p_psi (p_demux_data->p_psi_section)
|
||||
#define p (p_data->p_payload_start)
|
||||
|
||||
if( b_unit_start )
|
||||
{
|
||||
/* unit_start set to 1 -> presence of a pointer field
|
||||
* (see ISO/IEC 13818 (2.4.4.2) which should be set to 0x00 */
|
||||
if( (u8)p[0] != 0x00 )
|
||||
{
|
||||
intf_WarnMsg( 2, "input: non zero pointer field found, "
|
||||
"trying to continue" );
|
||||
p+=(u8)p[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
p++;
|
||||
}
|
||||
|
||||
/* This is the begining of a new section */
|
||||
|
||||
if( ((u8)(p[1]) & 0xc0) != 0x80 )
|
||||
{
|
||||
intf_WarnMsg( 2, "input: invalid PSI packet" );
|
||||
p_psi->b_trash = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_psi->i_section_length = ((p[1] & 0xF) << 8) | p[2];
|
||||
p_psi->b_section_complete = 0;
|
||||
p_psi->i_read_in_section = 0;
|
||||
p_psi->i_section_number = (u8)p[6];
|
||||
|
||||
if( p_psi->b_is_complete || p_psi->i_section_number == 0 )
|
||||
{
|
||||
/* This is a new PSI packet */
|
||||
p_psi->b_is_complete = 0;
|
||||
p_psi->b_trash = 0;
|
||||
p_psi->i_version_number = ( p[5] >> 1 ) & 0x1f;
|
||||
p_psi->i_last_section_number = (u8)p[7];
|
||||
|
||||
/* We'll write at the begining of the buffer */
|
||||
p_psi->p_current = p_psi->buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( p_psi->b_section_complete )
|
||||
{
|
||||
/* New Section of an already started PSI */
|
||||
p_psi->b_section_complete = 0;
|
||||
|
||||
if( p_psi->i_version_number != (( p[5] >> 1 ) & 0x1f) )
|
||||
{
|
||||
intf_WarnMsg( 2, "input: PSI version differs "
|
||||
"inside same PAT" );
|
||||
p_psi->b_trash = 1;
|
||||
}
|
||||
if( p_psi->i_section_number + 1 != (u8)p[6] )
|
||||
{
|
||||
intf_WarnMsg( 2, "input: PSI Section discontinuity, "
|
||||
"packet lost ?" );
|
||||
p_psi->b_trash = 1;
|
||||
}
|
||||
else
|
||||
p_psi->i_section_number++;
|
||||
}
|
||||
else
|
||||
{
|
||||
intf_WarnMsg( 2, "input: got unexpected new PSI section" );
|
||||
p_psi->b_trash = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* b_unit_start */
|
||||
|
||||
if( !p_psi->b_trash )
|
||||
{
|
||||
/* read */
|
||||
if( (p_data->p_payload_end - p) >=
|
||||
( p_psi->i_section_length - p_psi->i_read_in_section ) )
|
||||
{
|
||||
/* The end of the section is in this TS packet */
|
||||
memcpy( p_psi->p_current, p,
|
||||
(p_psi->i_section_length - p_psi->i_read_in_section) );
|
||||
|
||||
p_psi->b_section_complete = 1;
|
||||
p_psi->p_current +=
|
||||
(p_psi->i_section_length - p_psi->i_read_in_section);
|
||||
|
||||
if( p_psi->i_section_number == p_psi->i_last_section_number )
|
||||
{
|
||||
/* This was the last section of PSI */
|
||||
p_psi->b_is_complete = 1;
|
||||
|
||||
switch( p_demux_data->i_psi_type)
|
||||
{
|
||||
case PSI_IS_PAT:
|
||||
input_DecodePAT( p_input, p_es );
|
||||
break;
|
||||
case PSI_IS_PMT:
|
||||
input_DecodePMT( p_input, p_es );
|
||||
break;
|
||||
default:
|
||||
intf_WarnMsg(2, "Received unknown PSI in DemuxPSI");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( p_psi->buffer, p, p_data->p_payload_end - p );
|
||||
p_psi->i_read_in_section += p_data->p_payload_end - p;
|
||||
|
||||
p_psi->p_current += p_data->p_payload_end - p;
|
||||
}
|
||||
}
|
||||
|
||||
#undef p_psi
|
||||
#undef p
|
||||
|
||||
input_DeletePacket( p_input->p_method_data, p_data );
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* DecodePAT : Decodes Programm association table and deal with it
|
||||
*****************************************************************************/
|
||||
static void input_DecodePAT( input_thread_t * p_input, es_descriptor_t * p_es )
|
||||
{
|
||||
stream_ts_data_t * p_stream_data;
|
||||
es_ts_data_t * p_demux_data;
|
||||
|
||||
pgrm_descriptor_t * p_pgrm;
|
||||
es_descriptor_t * p_current_es;
|
||||
byte_t * p_current_data;
|
||||
|
||||
int i_section_length, i_program_id, i_pmt_pid;
|
||||
int i_loop, i_current_section;
|
||||
|
||||
boolean_t b_changed = 0;
|
||||
|
||||
p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
|
||||
p_stream_data = (stream_ts_data_t *)p_input->stream.p_demux_data;
|
||||
|
||||
#define p_psi (p_demux_data->p_psi_section)
|
||||
|
||||
/* Not so fast, Mike ! If the PAT version has changed, we first check
|
||||
* that its content has really changed before doing anything */
|
||||
if( p_stream_data->i_pat_version != p_psi->i_version_number )
|
||||
{
|
||||
int i_programs = p_input->stream.i_pgrm_number;
|
||||
|
||||
p_current_data = p_psi->buffer;
|
||||
|
||||
do
|
||||
{
|
||||
i_section_length = ((u32)(p_current_data[1] & 0xF) << 8) |
|
||||
p_current_data[2];
|
||||
i_current_section = (u8)p_current_data[6];
|
||||
|
||||
for( i_loop = 0;
|
||||
( i_loop < (i_section_length - 9) / 4 ) && !b_changed;
|
||||
i_loop++ )
|
||||
{
|
||||
i_program_id = ( (u32)*(p_current_data + i_loop * 4 + 8) << 8 )
|
||||
| *(p_current_data + i_loop * 4 + 9);
|
||||
i_pmt_pid = ( ((u32)*(p_current_data + i_loop * 4 + 10) & 0x1F)
|
||||
<< 8 )
|
||||
| *(p_current_data + i_loop * 4 + 11);
|
||||
|
||||
if( i_program_id )
|
||||
{
|
||||
if( (p_pgrm = input_FindProgram( p_input, i_program_id ))
|
||||
&& (p_current_es = input_FindES( p_input, i_pmt_pid ))
|
||||
&& p_current_es->p_pgrm == p_pgrm
|
||||
&& p_current_es->i_id == i_pmt_pid
|
||||
&& ((es_ts_data_t *)p_current_es->p_demux_data)->b_psi
|
||||
&& ((es_ts_data_t *)p_current_es->p_demux_data)
|
||||
->i_psi_type == PSI_IS_PMT )
|
||||
{
|
||||
i_programs--;
|
||||
}
|
||||
else
|
||||
{
|
||||
b_changed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p_current_data += 3 + i_section_length;
|
||||
|
||||
} while( ( i_current_section < p_psi->i_last_section_number )
|
||||
&& !b_changed );
|
||||
|
||||
/* If we didn't find the expected amount of programs, the PAT has
|
||||
* changed. Otherwise, it only changed if b_changed is already != 0 */
|
||||
b_changed = b_changed || i_programs;
|
||||
}
|
||||
|
||||
if( b_changed )
|
||||
{
|
||||
/* PAT has changed. We are going to delete all programs and
|
||||
* create new ones. We chose not to only change what was needed
|
||||
* as a PAT change may mean the stream is radically changing and
|
||||
* this is a secure method to avoid crashes */
|
||||
es_ts_data_t * p_es_demux;
|
||||
pgrm_ts_data_t * p_pgrm_demux;
|
||||
|
||||
p_current_data = p_psi->buffer;
|
||||
|
||||
/* Delete all programs */
|
||||
while( p_input->stream.i_pgrm_number )
|
||||
{
|
||||
input_DelProgram( p_input, p_input->stream.pp_programs[0] );
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
i_section_length = ((u32)(p_current_data[1] & 0xF) << 8) |
|
||||
p_current_data[2];
|
||||
i_current_section = (u8)p_current_data[6];
|
||||
|
||||
for( i_loop = 0; i_loop < (i_section_length - 9) / 4 ; i_loop++ )
|
||||
{
|
||||
i_program_id = ( (u32)*(p_current_data + i_loop * 4 + 8) << 8 )
|
||||
| *(p_current_data + i_loop * 4 + 9);
|
||||
i_pmt_pid = ( ((u32)*(p_current_data + i_loop * 4 + 10) & 0x1F)
|
||||
<< 8 )
|
||||
| *(p_current_data + i_loop * 4 + 11);
|
||||
|
||||
/* If program = 0, we're having info about NIT not PMT */
|
||||
if( i_program_id )
|
||||
{
|
||||
/* Add this program */
|
||||
p_pgrm = input_AddProgram( p_input, i_program_id,
|
||||
sizeof( pgrm_ts_data_t ) );
|
||||
|
||||
/* whatis the PID of the PMT of this program */
|
||||
p_pgrm_demux = (pgrm_ts_data_t *)p_pgrm->p_demux_data;
|
||||
p_pgrm_demux->i_pmt_version = PMT_UNINITIALIZED;
|
||||
|
||||
/* Add the PMT ES to this program */
|
||||
p_current_es = input_AddES( p_input, p_pgrm,(u16)i_pmt_pid,
|
||||
sizeof( es_ts_data_t) );
|
||||
p_es_demux = (es_ts_data_t *)p_current_es->p_demux_data;
|
||||
p_es_demux->b_psi = 1;
|
||||
p_es_demux->i_psi_type = PSI_IS_PMT;
|
||||
|
||||
p_es_demux->p_psi_section =
|
||||
malloc( sizeof( psi_section_t ) );
|
||||
p_es_demux->p_psi_section->b_is_complete = 0;
|
||||
}
|
||||
}
|
||||
|
||||
p_current_data += 3 + i_section_length;
|
||||
|
||||
} while( i_current_section < p_psi->i_last_section_number );
|
||||
|
||||
/* Go to the beginning of the next section */
|
||||
p_stream_data->i_pat_version = p_psi->i_version_number;
|
||||
|
||||
}
|
||||
#undef p_psi
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* DecodePMT : decode a given Program Stream Map
|
||||
* ***************************************************************************
|
||||
* When the PMT changes, it may mean a deep change in the stream, and it is
|
||||
* careful to delete the ES and add them again. If the PMT doesn't change,
|
||||
* there no need to do anything.
|
||||
*****************************************************************************/
|
||||
static void input_DecodePMT( input_thread_t * p_input, es_descriptor_t * p_es )
|
||||
{
|
||||
|
||||
pgrm_ts_data_t * p_pgrm_data;
|
||||
es_ts_data_t * p_demux_data;
|
||||
|
||||
p_demux_data = (es_ts_data_t *)p_es->p_demux_data;
|
||||
p_pgrm_data = (pgrm_ts_data_t *)p_es->p_pgrm->p_demux_data;
|
||||
|
||||
#define p_psi (p_demux_data->p_psi_section)
|
||||
|
||||
if( p_psi->i_version_number != p_pgrm_data->i_pmt_version )
|
||||
{
|
||||
es_descriptor_t * p_new_es;
|
||||
es_ts_data_t * p_es_demux;
|
||||
byte_t * p_current_data, * p_current_section;
|
||||
int i_section_length,i_current_section;
|
||||
int i_prog_info_length, i_loop;
|
||||
int i_es_info_length, i_pid, i_stream_type;
|
||||
|
||||
p_current_section = p_psi->buffer;
|
||||
p_current_data = p_psi->buffer;
|
||||
|
||||
p_pgrm_data->i_pcr_pid = ( ((u32)*(p_current_section + 8) & 0x1F) << 8 ) |
|
||||
*(p_current_section + 9);
|
||||
|
||||
|
||||
/* Lock stream information */
|
||||
vlc_mutex_lock( &p_input->stream.stream_lock );
|
||||
|
||||
/* Delete all ES in this program except the PSI. We start from the
|
||||
* end because i_es_number gets decremented after each deletion. */
|
||||
for( i_loop = p_es->p_pgrm->i_es_number ; i_loop ; )
|
||||
{
|
||||
i_loop--;
|
||||
p_es_demux = (es_ts_data_t *)
|
||||
p_es->p_pgrm->pp_es[i_loop]->p_demux_data;
|
||||
if ( ! p_es_demux->b_psi )
|
||||
{
|
||||
input_DelES( p_input, p_es->p_pgrm->pp_es[i_loop] );
|
||||
}
|
||||
}
|
||||
|
||||
/* Then add what we received in this PMT */
|
||||
do
|
||||
{
|
||||
i_section_length = ( ((u32)*(p_current_data + 1) & 0xF) << 8 ) |
|
||||
*(p_current_data + 2);
|
||||
i_current_section = (u8)p_current_data[6];
|
||||
i_prog_info_length = ( ((u32)*(p_current_data + 10) & 0xF) << 8 ) |
|
||||
*(p_current_data + 11);
|
||||
|
||||
/* For the moment we ignore program descriptors */
|
||||
p_current_data += 12 + i_prog_info_length;
|
||||
|
||||
/* The end of the section, before the CRC is at
|
||||
* p_current_section + i_section_length -1 */
|
||||
while( p_current_data < p_current_section + i_section_length -1 )
|
||||
{
|
||||
i_stream_type = (int)p_current_data[0];
|
||||
i_pid = ( ((u32)*(p_current_data + 1) & 0x1F) << 8 ) |
|
||||
*(p_current_data + 2);
|
||||
i_es_info_length = ( ((u32)*(p_current_data + 3) & 0xF) << 8 ) |
|
||||
*(p_current_data + 4);
|
||||
|
||||
/* Add this ES to the program */
|
||||
p_new_es = input_AddES( p_input, p_es->p_pgrm,
|
||||
(u16)i_pid, sizeof( es_ts_data_t ) );
|
||||
|
||||
/* Tell the decoders what kind of stream it is */
|
||||
p_new_es->i_type = i_stream_type;
|
||||
|
||||
/* Tell the interface what kind of stream it is and select
|
||||
* the required ones */
|
||||
{
|
||||
switch( i_stream_type )
|
||||
{
|
||||
case MPEG1_VIDEO_ES:
|
||||
case MPEG2_VIDEO_ES:
|
||||
p_new_es->i_cat = VIDEO_ES;
|
||||
break;
|
||||
case MPEG1_AUDIO_ES:
|
||||
case MPEG2_AUDIO_ES:
|
||||
p_new_es->i_cat = AUDIO_ES;
|
||||
break;
|
||||
case LPCM_AUDIO_ES :
|
||||
case AC3_AUDIO_ES :
|
||||
p_new_es->i_stream_id = 0xBD;
|
||||
p_new_es->i_cat = AUDIO_ES;
|
||||
break;
|
||||
/* Not sure this one is fully specification-compliant */
|
||||
case DVD_SPU_ES :
|
||||
p_new_es->i_stream_id = 0xBD;
|
||||
p_new_es->i_cat = SPU_ES;
|
||||
break;
|
||||
default :
|
||||
p_new_es->i_cat = UNKNOWN_ES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p_current_data += 5 + i_es_info_length;
|
||||
}
|
||||
|
||||
/* Go to the beginning of the next section*/
|
||||
p_current_data += 3 + i_section_length;
|
||||
|
||||
p_current_section++;
|
||||
|
||||
} while( i_current_section < p_psi->i_last_section_number );
|
||||
|
||||
p_pgrm_data->i_pmt_version = p_psi->i_version_number;
|
||||
|
||||
/* if no program is selected :*/
|
||||
if( !p_input->stream.p_selected_program )
|
||||
{
|
||||
pgrm_descriptor_t * p_pgrm_to_select;
|
||||
u16 i_id = (u16)config_GetIntVariable( "program" );
|
||||
|
||||
if( i_id != 0 ) /* if user specified a program */
|
||||
{
|
||||
p_pgrm_to_select = input_FindProgram( p_input, i_id );
|
||||
|
||||
if( p_pgrm_to_select || p_pgrm_to_select == p_es->p_pgrm )
|
||||
p_input->pf_set_program( p_input, p_pgrm_to_select );
|
||||
}
|
||||
else
|
||||
p_input->pf_set_program( p_input, p_es->p_pgrm );
|
||||
}
|
||||
|
||||
/* inform interface that stream has changed */
|
||||
p_input->stream.b_changed = 1;
|
||||
/* Remove lock */
|
||||
vlc_mutex_unlock( &p_input->stream.stream_lock );
|
||||
}
|
||||
|
||||
#undef p_psi
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* modules_plugin.h : Plugin management functions used by the core application.
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2001 VideoLAN
|
||||
* $Id: modules_plugin.h,v 1.19 2002/04/11 08:55:49 sam Exp $
|
||||
* $Id: modules_plugin.h,v 1.20 2002/04/25 02:10:33 jobi Exp $
|
||||
*
|
||||
* Authors: Samuel Hocevar <sam@zoy.org>
|
||||
*
|
||||
@ -224,6 +224,7 @@ module_error( char *psz_buffer )
|
||||
(p_symbols)->input_ToggleES = input_ToggleES; \
|
||||
(p_symbols)->input_ChangeProgram = input_ChangeProgram; \
|
||||
(p_symbols)->input_ChangeArea = input_ChangeArea; \
|
||||
(p_symbols)->input_FindProgram = input_FindProgram; \
|
||||
(p_symbols)->input_FindES = input_FindES; \
|
||||
(p_symbols)->input_AddES = input_AddES; \
|
||||
(p_symbols)->input_DelES = input_DelES; \
|
||||
@ -247,7 +248,6 @@ module_error( char *psz_buffer )
|
||||
(p_symbols)->input_DemuxPS = input_DemuxPS; \
|
||||
(p_symbols)->input_ReadTS = input_ReadTS; \
|
||||
(p_symbols)->input_DemuxTS = input_DemuxTS; \
|
||||
(p_symbols)->input_DemuxPSI = input_DemuxPSI; \
|
||||
(p_symbols)->input_ClockManageControl = input_ClockManageControl; \
|
||||
(p_symbols)->input_FDSeek = input_FDSeek; \
|
||||
(p_symbols)->input_FDClose = input_FDClose; \
|
||||
|
Loading…
Reference in New Issue
Block a user