Commit 596d0665 authored by Christophe Massiot's avatar Christophe Massiot

* modules/access/dvb:

  - Rewrote QPSK frontend tuning functions, after reading the doc - it
    should hopefully fix the infamous "Operation not permitted" problem.
  - Permanently monitor the frontend status, and reinit it if it crashes.
  - New --dvb-high-voltage option for very long cables.
  - Moved all EN 50 221-related code from ts.c to en50221.c. We no longer
    need the --ts-capmt-sysid option because the sysid is determined
    automatically from the CAM.
  - Also changed the way we send the CAPMTs to the CAM, hoping to fix a bug
    with Aston professional CAMs which all of sudden stop descrambling
    a program after a few days.
parent c05cbdf5
......@@ -1427,7 +1427,7 @@ then
then
AC_CHECK_HEADERS(dvbpsi/dr.h,
[ VLC_ADD_PLUGINS([mux_ts ts])
VLC_ADD_LDFLAGS([mux_ts ts],[-ldvbpsi]) ],
VLC_ADD_LDFLAGS([mux_ts ts dvb],[-ldvbpsi]) ],
[ AC_MSG_WARN([cannot find libdvbpsi headers]) ],
[#if defined( HAVE_STDINT_H )
# include <stdint.h>
......@@ -1452,8 +1452,8 @@ then
dnl Use a custom libdvbpsi
AC_MSG_RESULT(${real_dvbpsi_tree}/src/.libs/libdvbpsi.a)
VLC_ADD_BUILTINS([mux_ts ts])
VLC_ADD_CPPFLAGS([mux_ts ts],[-I${real_dvbpsi_tree}/src])
VLC_ADD_LDFLAGS([mux_ts ts],[-L${real_dvbpsi_tree}/src/.libs -ldvbpsi])
VLC_ADD_CPPFLAGS([mux_ts ts dvb],[-I${real_dvbpsi_tree}/src])
VLC_ADD_LDFLAGS([mux_ts ts dvb],[-L${real_dvbpsi_tree}/src/.libs -ldvbpsi])
else
dnl The given libdvbpsi wasn't built
AC_MSG_RESULT(no)
......@@ -1477,8 +1477,8 @@ then
CPPFLAGS="${CPPFLAGS_save} ${CPPFLAGS_test}"
AC_CHECK_HEADERS([dvbpsi/dr.h],[
VLC_ADD_PLUGINS([mux_ts ts])
VLC_ADD_CPPFLAGS([mux_ts ts],[${CPPFLAGS_test}])
VLC_ADD_LDFLAGS([mux_ts ts],[${LDFLAGS_test} -ldvbpsi])
VLC_ADD_CPPFLAGS([mux_ts ts dvb],[${CPPFLAGS_test}])
VLC_ADD_LDFLAGS([mux_ts ts dvb],[${LDFLAGS_test} -ldvbpsi])
],[
if test -n "${enable_dvbpsi}"
......
......@@ -39,6 +39,23 @@
#include <errno.h>
/* Include dvbpsi headers */
#ifdef HAVE_DVBPSI_DR_H
# include <dvbpsi/dvbpsi.h>
# include <dvbpsi/descriptor.h>
# include <dvbpsi/pat.h>
# include <dvbpsi/pmt.h>
# include <dvbpsi/dr.h>
# include <dvbpsi/psi.h>
#else
# include "dvbpsi.h"
# include "descriptor.h"
# include "tables/pat.h"
# include "tables/pmt.h"
# include "descriptors/dr.h"
# include "psi.h"
#endif
#include "dvb.h"
/*****************************************************************************
......@@ -81,11 +98,15 @@ static void Close( vlc_object_t *p_this );
#define BUDGET_LONGTEXT N_("This allows you to stream an entire transponder with a budget card.")
#define SATNO_TEXT N_("Satellite number in the Diseqc system")
#define SATNO_LONGTEXT N_("[0=no diseqc, 1-4=normal diseqc, -1=A, -2=B simple diseqc]")
#define SATNO_LONGTEXT N_("[0=no diseqc, 1-4=satellite number]")
#define VOLTAGE_TEXT N_("LNB voltage")
#define VOLTAGE_LONGTEXT N_("In Volts [0, 13=vertical, 18=horizontal]")
#define HIGH_VOLTAGE_TEXT N_("High LNB voltage")
#define HIGH_VOLTAGE_LONGTEXT N_("Enable high voltage if your cables are " \
"particularly long. This is not supported by all frontends.")
#define TONE_TEXT N_("22 kHz tone")
#define TONE_LONGTEXT N_("[0=off, 1=on, -1=auto]")
......@@ -148,6 +169,8 @@ vlc_module_begin();
VLC_TRUE );
add_integer( "dvb-voltage", 13, NULL, VOLTAGE_TEXT, VOLTAGE_LONGTEXT,
VLC_TRUE );
add_bool( "dvb-high-voltage", 0, NULL, HIGH_VOLTAGE_TEXT,
HIGH_VOLTAGE_LONGTEXT, VLC_TRUE );
add_integer( "dvb-tone", -1, NULL, TONE_TEXT, TONE_LONGTEXT,
VLC_TRUE );
add_integer( "dvb-fec", 9, NULL, FEC_TEXT, FEC_LONGTEXT, VLC_TRUE );
......@@ -305,19 +328,24 @@ static block_t *Block( access_t *p_access )
for ( ; ; )
{
struct timeval timeout;
fd_set fds;
fd_set fds, fde;
int i_ret;
int i_max_handle = p_sys->i_handle;
/* Initialize file descriptor set */
/* Initialize file descriptor sets */
FD_ZERO( &fds );
FD_ZERO( &fde );
FD_SET( p_sys->i_handle, &fds );
FD_SET( p_sys->i_frontend_handle, &fde );
if ( p_sys->i_frontend_handle > i_max_handle )
i_max_handle = p_sys->i_frontend_handle;
/* We'll wait 0.5 second if nothing happens */
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
/* Find if some data is available */
i_ret = select( p_sys->i_handle + 1, &fds, NULL, NULL, &timeout );
i_ret = select( i_max_handle + 1, &fds, NULL, &fde, &timeout );
if ( p_access->b_die )
return NULL;
......@@ -337,6 +365,11 @@ static block_t *Block( access_t *p_access )
p_sys->i_ca_next_event = mdate() + p_sys->i_ca_timeout;
}
if ( FD_ISSET( p_sys->i_frontend_handle, &fde ) )
{
E_(FrontendPoll)( p_access );
}
if ( FD_ISSET( p_sys->i_handle, &fds ) )
{
break;
......@@ -408,15 +441,14 @@ static int Control( access_t *p_access, int i_query, va_list args )
case ACCESS_SET_PRIVATE_ID_CA:
{
uint8_t **pp_capmts;
int i_nb_capmts;
dvbpsi_pmt_t *p_pmt;
pp_capmts = (uint8_t **)va_arg( args, uint8_t ** );
i_nb_capmts = (int)va_arg( args, int );
p_pmt = (dvbpsi_pmt_t *)va_arg( args, dvbpsi_pmt_t * );
E_(CAMSet)( p_access, pp_capmts, i_nb_capmts );
E_(CAMSet)( p_access, p_pmt );
break;
}
default:
msg_Warn( p_access, "unimplemented query in control" );
return VLC_EGENERIC;
......@@ -512,6 +544,7 @@ static void VarInit( access_t *p_access )
var_Create( p_access, "dvb-budget-mode", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-satno", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-voltage", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-high-voltage", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-tone", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-fec", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-srate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
......@@ -575,7 +608,9 @@ static int ParseMRL( access_t *p_access )
else GET_OPTION_BOOL("budget-mode")
else GET_OPTION_INT("voltage")
else GET_OPTION_BOOL("high-voltage")
else GET_OPTION_INT("tone")
else GET_OPTION_INT("satno")
else GET_OPTION_INT("fec")
else GET_OPTION_INT("srate")
......@@ -588,18 +623,6 @@ static int ParseMRL( access_t *p_access )
else GET_OPTION_INT("guard")
else GET_OPTION_INT("hierarchy")
else if( !strncmp( psz_parser, "satno=",
strlen( "satno=" ) ) )
{
psz_parser += strlen( "satno=" );
if ( *psz_parser == 'A' || *psz_parser == 'a' )
val.i_int = -1;
else if ( *psz_parser == 'B' || *psz_parser == 'b' )
val.i_int = -2;
else
val.i_int = strtol( psz_parser, &psz_parser, 0 );
var_Set( p_access, "dvb-satno", val );
}
/* Redundant with voltage but much easier to use */
else if( !strncmp( psz_parser, "polarization=",
strlen( "polarization=" ) ) )
......
......@@ -57,10 +57,11 @@ typedef struct
#define MAX_DEMUX 256
#define MAX_CI_SLOTS 16
#define MAX_SESSIONS 32
#define MAX_PROGRAMS 24
struct access_sys_t
{
int i_handle;
int i_handle, i_frontend_handle;
demux_handle_t p_demux_handles[MAX_DEMUX];
frontend_t *p_frontend;
vlc_bool_t b_budget_mode;
......@@ -71,9 +72,8 @@ struct access_sys_t
vlc_bool_t pb_active_slot[MAX_CI_SLOTS];
vlc_bool_t pb_tc_has_data[MAX_CI_SLOTS];
en50221_session_t p_sessions[MAX_SESSIONS];
mtime_t i_ca_timeout, i_ca_next_event, i_ca_next_pmt;
uint8_t **pp_capmts;
int i_nb_capmts;
mtime_t i_ca_timeout, i_ca_next_event;
dvbpsi_pmt_t *pp_selected_programs[MAX_PROGRAMS];
};
#define VIDEO0_TYPE 1
......@@ -88,6 +88,7 @@ struct access_sys_t
* Prototypes
*****************************************************************************/
int E_(FrontendOpen)( access_t * );
void E_(FrontendPoll)( access_t *p_access );
int E_(FrontendSet)( access_t * );
void E_(FrontendClose)( access_t * );
......@@ -99,10 +100,10 @@ void E_(DVRClose)( access_t * );
int E_(CAMOpen)( access_t * );
int E_(CAMPoll)( access_t * );
int E_(CAMSet)( access_t *, uint8_t **, int );
int E_(CAMSet)( access_t *, dvbpsi_pmt_t * );
void E_(CAMClose)( access_t * );
int E_(en50221_Poll)( access_t * );
int E_(en50221_SetCAPMT)( access_t *, uint8_t **, int );
int E_(en50221_SetCAPMT)( access_t *, dvbpsi_pmt_t * );
void E_(en50221_End)( access_t * );
......@@ -42,6 +42,23 @@
#include <linux/dvb/frontend.h>
#include <linux/dvb/ca.h>
/* Include dvbpsi headers */
#ifdef HAVE_DVBPSI_DR_H
# include <dvbpsi/dvbpsi.h>
# include <dvbpsi/descriptor.h>
# include <dvbpsi/pat.h>
# include <dvbpsi/pmt.h>
# include <dvbpsi/dr.h>
# include <dvbpsi/psi.h>
#else
# include "dvbpsi.h"
# include "descriptor.h"
# include "tables/pat.h"
# include "tables/pmt.h"
# include "descriptors/dr.h"
# include "psi.h"
#endif
#include "dvb.h"
#undef DEBUG_TPDU
......@@ -622,6 +639,10 @@ static int APDUSend( access_t * p_access, int i_session_id, int i_tag,
return i_ret;
}
/*
* Resource Manager
*/
/*****************************************************************************
* ResourceManagerHandle
*****************************************************************************/
......@@ -668,6 +689,10 @@ static void ResourceManagerOpen( access_t * p_access, int i_session_id )
APDUSend( p_access, i_session_id, AOT_PROFILE_ENQ, NULL, 0 );
}
/*
* Application Information
*/
/*****************************************************************************
* ApplicationInformationHandle
*****************************************************************************/
......@@ -719,6 +744,274 @@ static void ApplicationInformationOpen( access_t * p_access, int i_session_id )
APDUSend( p_access, i_session_id, AOT_APPLICATION_INFO_ENQ, NULL, 0 );
}
/*
* Conditional Access
*/
#define MAX_CASYSTEM_IDS 16
typedef struct
{
uint16_t pi_system_ids[MAX_CASYSTEM_IDS + 1];
} system_ids_t;
static vlc_bool_t CheckSystemID( system_ids_t *p_ids, uint16_t i_id )
{
int i = 0;
while ( p_ids->pi_system_ids[i] )
{
if ( p_ids->pi_system_ids[i] == i_id )
return VLC_TRUE;
i++;
}
return VLC_FALSE;
}
/*****************************************************************************
* CAPMTNeedsDescrambling
*****************************************************************************/
static vlc_bool_t CAPMTNeedsDescrambling( dvbpsi_pmt_t *p_pmt )
{
dvbpsi_descriptor_t *p_dr;
dvbpsi_pmt_es_t *p_es;
for( p_dr = p_pmt->p_first_descriptor; p_dr != NULL; p_dr = p_dr->p_next )
{
if( p_dr->i_tag == 0x9 )
{
return VLC_TRUE;
}
}
for( p_es = p_pmt->p_first_es; p_es != NULL; p_es = p_es->p_next )
{
for( p_dr = p_es->p_first_descriptor; p_dr != NULL;
p_dr = p_dr->p_next )
{
if( p_dr->i_tag == 0x9 )
{
return VLC_TRUE;
}
}
}
return VLC_FALSE;
}
/*****************************************************************************
* CAPMTBuild
*****************************************************************************/
static int GetCADSize( system_ids_t *p_ids, dvbpsi_descriptor_t *p_dr )
{
int i_cad_size = 0;
while ( p_dr != NULL )
{
if( p_dr->i_tag == 0x9 )
{
uint16_t i_sysid = ((uint16_t)p_dr->p_data[0] << 8)
| p_dr->p_data[1];
if ( CheckSystemID( p_ids, i_sysid ) )
i_cad_size += p_dr->i_length + 2;
}
p_dr = p_dr->p_next;
}
return i_cad_size;
}
static uint8_t *CAPMTHeader( system_ids_t *p_ids, uint8_t i_list_mgt,
uint16_t i_program_number, uint8_t i_version,
int i_size, dvbpsi_descriptor_t *p_dr )
{
uint8_t *p_data;
if ( i_size )
p_data = malloc( 7 + i_size );
else
p_data = malloc( 6 );
p_data[0] = i_list_mgt;
p_data[1] = i_program_number >> 8;
p_data[2] = i_program_number & 0xff;
p_data[3] = ((i_version & 0x1f) << 1) | 0x1;
if ( i_size )
{
int i;
p_data[4] = (i_size + 1) >> 8;
p_data[5] = (i_size + 1) & 0xff;
p_data[6] = 0x1; /* ok_descrambling */
i = 7;
while ( p_dr != NULL )
{
if( p_dr->i_tag == 0x9 )
{
uint16_t i_sysid = ((uint16_t)p_dr->p_data[0] << 8)
| p_dr->p_data[1];
if ( CheckSystemID( p_ids, i_sysid ) )
{
p_data[i] = 0x9;
p_data[i + 1] = p_dr->i_length;
memcpy( &p_data[i + 2], p_dr->p_data, p_dr->i_length );
i += p_dr->i_length + 2;
}
}
p_dr = p_dr->p_next;
}
}
else
{
p_data[4] = 0;
p_data[5] = 0;
}
return p_data;
}
static uint8_t *CAPMTES( system_ids_t *p_ids, uint8_t *p_capmt,
int i_capmt_size, uint8_t i_type, uint16_t i_pid,
int i_size, dvbpsi_descriptor_t *p_dr )
{
uint8_t *p_data;
int i;
if ( i_size )
p_data = realloc( p_capmt, i_capmt_size + 6 + i_size );
else
p_data = realloc( p_capmt, i_capmt_size + 5 );
i = i_capmt_size;
p_data[i] = i_type;
p_data[i + 1] = i_pid >> 8;
p_data[i + 2] = i_pid & 0xff;
if ( i_size )
{
p_data[i + 3] = (i_size + 1) >> 8;
p_data[i + 4] = (i_size + 1) & 0xff;
p_data[i + 5] = 0x1; /* ok_descrambling */
i += 6;
while ( p_dr != NULL )
{
if( p_dr->i_tag == 0x9 )
{
uint16_t i_sysid = ((uint16_t)p_dr->p_data[0] << 8)
| p_dr->p_data[1];
if ( CheckSystemID( p_ids, i_sysid ) )
{
p_data[i] = 0x9;
p_data[i + 1] = p_dr->i_length;
memcpy( &p_data[i + 2], p_dr->p_data, p_dr->i_length );
i += p_dr->i_length + 2;
}
}
p_dr = p_dr->p_next;
}
}
else
{
p_data[i + 3] = 0;
p_data[i + 4] = 0;
}
return p_data;
}
static uint8_t *CAPMTBuild( access_t * p_access, int i_session_id,
dvbpsi_pmt_t *p_pmt, uint8_t i_list_mgt,
int *pi_capmt_size )
{
access_sys_t *p_sys = p_access->p_sys;
system_ids_t *p_ids =
(system_ids_t *)p_sys->p_sessions[i_session_id - 1].p_sys;
dvbpsi_pmt_es_t *p_es;
int i_cad_size, i_cad_program_size;
uint8_t *p_capmt;
i_cad_size = i_cad_program_size =
GetCADSize( p_ids, p_pmt->p_first_descriptor );
for( p_es = p_pmt->p_first_es; p_es != NULL; p_es = p_es->p_next )
{
i_cad_size += GetCADSize( p_ids, p_es->p_first_descriptor );
}
if ( !i_cad_size )
{
msg_Warn( p_access,
"no compatible scrambling system for SID %d on session %d",
p_pmt->i_program_number, i_session_id );
}
p_capmt = CAPMTHeader( p_ids, i_list_mgt, p_pmt->i_program_number,
p_pmt->i_version, i_cad_program_size,
p_pmt->p_first_descriptor );
if ( i_cad_program_size )
*pi_capmt_size = 7 + i_cad_program_size;
else
*pi_capmt_size = 6;
for( p_es = p_pmt->p_first_es; p_es != NULL; p_es = p_es->p_next )
{
i_cad_size = GetCADSize( p_ids, p_es->p_first_descriptor );
if ( i_cad_size || i_cad_program_size )
{
p_capmt = CAPMTES( p_ids, p_capmt, *pi_capmt_size, p_es->i_type,
p_es->i_pid, i_cad_size,
p_es->p_first_descriptor );
if ( i_cad_size )
*pi_capmt_size += 6 + i_cad_size;
else
*pi_capmt_size += 5;
}
}
return p_capmt;
}
/*****************************************************************************
* CAPMTAdd
*****************************************************************************/
static void CAPMTAdd( access_t * p_access, int i_session_id,
dvbpsi_pmt_t *p_pmt )
{
uint8_t *p_capmt;
int i_capmt_size;
msg_Dbg( p_access, "adding CAPMT for SID %d on session %d",
p_pmt->i_program_number, i_session_id );
p_capmt = CAPMTBuild( p_access, i_session_id, p_pmt,
0x4 /* add */, &i_capmt_size );
APDUSend( p_access, i_session_id, AOT_CA_PMT, p_capmt, i_capmt_size );
}
/*****************************************************************************
* CAPMTUpdate
*****************************************************************************/
static void CAPMTUpdate( access_t * p_access, int i_session_id,
dvbpsi_pmt_t *p_pmt )
{
uint8_t *p_capmt;
int i_capmt_size;
msg_Dbg( p_access, "updating CAPMT for SID %d on session %d",
p_pmt->i_program_number, i_session_id );
p_capmt = CAPMTBuild( p_access, i_session_id, p_pmt,
0x5 /* update */, &i_capmt_size );
APDUSend( p_access, i_session_id, AOT_CA_PMT, p_capmt, i_capmt_size );
}
/*****************************************************************************
* ConditionalAccessHandle
*****************************************************************************/
......@@ -726,28 +1019,38 @@ static void ConditionalAccessHandle( access_t * p_access, int i_session_id,
uint8_t *p_apdu, int i_size )
{
access_sys_t *p_sys = p_access->p_sys;
system_ids_t *p_ids =
(system_ids_t *)p_sys->p_sessions[i_session_id - 1].p_sys;
int i_tag = APDUGetTag( p_apdu, i_size );
switch ( i_tag )
{
case AOT_CA_INFO:
{
if ( p_sys->i_nb_capmts )
{
int i;
msg_Dbg( p_access, "sending CAPMT on session %d", i_session_id );
for ( i = 0; i < p_sys->i_nb_capmts; i++ )
int l = 0;
uint8_t *d = APDUGetLength( p_apdu, &l );
msg_Dbg( p_access, "CA system IDs supported by the application :" );
for ( i = 0; i < l / 2; i++ )
{
int i_size;
uint8_t *p;
p = GetLength( &p_sys->pp_capmts[i][3], &i_size );
SPDUSend( p_access, i_session_id, p_sys->pp_capmts[i],
i_size + (p - p_sys->pp_capmts[i]) );
p_ids->pi_system_ids[i] = ((uint16_t)d[0] << 8) | d[1];
d += 2;
msg_Dbg( p_access, "- 0x%x", p_ids->pi_system_ids[i] );
}
p_ids->pi_system_ids[i] = 0;
for ( i = 0; i < MAX_PROGRAMS; i++ )
{
if ( p_sys->pp_selected_programs[i] != NULL )
{
CAPMTAdd( p_access, i_session_id,
p_sys->pp_selected_programs[i] );
}
p_sys->i_ca_next_pmt = 0;
}
break;
}
default:
msg_Err( p_access,
"unexpected tag in ConditionalAccessHandle (0x%x)",
......@@ -765,10 +1068,17 @@ static void ConditionalAccessOpen( access_t * p_access, int i_session_id )
msg_Dbg( p_access, "opening ConditionalAccess session (%d)", i_session_id );
p_sys->p_sessions[i_session_id - 1].pf_handle = ConditionalAccessHandle;
p_sys->p_sessions[i_session_id - 1].p_sys = malloc(sizeof(system_ids_t));
memset( p_sys->p_sessions[i_session_id - 1].p_sys, 0,
sizeof(system_ids_t) );
APDUSend( p_access, i_session_id, AOT_CA_INFO_ENQ, NULL, 0 );
}
/*
* Date Time
*/
typedef struct
{
int i_interval;
......@@ -883,6 +1193,10 @@ static void DateTimeOpen( access_t * p_access, int i_session_id )
DateTimeSend( p_access, i_session_id );
}
/*
* MMI
*/
/*****************************************************************************
* MMIHandle
*****************************************************************************/
......@@ -1073,30 +1387,6 @@ int E_(en50221_Poll)( access_t * p_access )
}
}
if ( p_sys->i_ca_next_pmt && p_sys->i_ca_next_pmt <= mdate() )
{
for ( i_session_id = 1; i_session_id <= MAX_SESSIONS; i_session_id++ )
{
int i;
if ( p_sys->p_sessions[i_session_id - 1].i_resource_id
!= RI_CONDITIONAL_ACCESS_SUPPORT )
continue;
msg_Dbg( p_access, "sending CAPMT on session %d", i_session_id );
for ( i = 0; i < p_sys->i_nb_capmts; i++ )
{
int i_size;
uint8_t *p;
p = GetLength( &p_sys->pp_capmts[i][3], &i_size );
SPDUSend( p_access, i_session_id, p_sys->pp_capmts[i],
i_size + (p - p_sys->pp_capmts[i]) );
}
}
p_sys->i_ca_next_pmt = 0;
}
return VLC_SUCCESS;
}
......@@ -1104,23 +1394,52 @@ int E_(en50221_Poll)( access_t * p_access )
/*****************************************************************************
* en50221_SetCAPMT :
*****************************************************************************/
int E_(en50221_SetCAPMT)( access_t * p_access, uint8_t **pp_capmts,
int i_nb_capmts )
int E_(en50221_SetCAPMT)( access_t * p_access, dvbpsi_pmt_t *p_pmt )
{
access_sys_t *p_sys = p_access->p_sys;
int i, i_session_id;
vlc_bool_t b_update = VLC_FALSE;
vlc_bool_t b_needs_descrambling = CAPMTNeedsDescrambling( p_pmt );
if ( p_sys->i_nb_capmts )
for ( i = 0; i < MAX_PROGRAMS; i++ )
{
int i;
for ( i = 0; i < p_sys->i_nb_capmts; i++ )
if ( p_sys->pp_selected_programs[i] != NULL
&& p_sys->pp_selected_programs[i]->i_program_number
== p_pmt->i_program_number )
{
free( p_sys->pp_capmts[i] );
b_update = VLC_TRUE;
dvbpsi_DeletePMT( p_sys->pp_selected_programs[i] );
if ( b_needs_descrambling )
p_sys->pp_selected_programs[i] = p_pmt;
else
p_sys->pp_selected_programs[i] = NULL;
break;
}
}
if ( !b_update && b_needs_descrambling )
{
for ( i = 0; i < MAX_PROGRAMS; i++ )
{
if ( p_sys->pp_selected_programs[i] == NULL )
{
p_sys->pp_selected_programs[i] = p_pmt;
break;
}
}
}
for ( i_session_id = 1; i_session_id <= MAX_SESSIONS; i_session_id++ )
{
if ( p_sys->p_sessions[i_session_id - 1].i_resource_id
== RI_CONDITIONAL_ACCESS_SUPPORT )
{
if ( b_update )
CAPMTUpdate( p_access, i_session_id, p_pmt );
else
CAPMTAdd( p_access, i_session_id, p_pmt );
}
free( p_sys->pp_capmts );
}
p_sys->pp_capmts = pp_capmts;
p_sys->i_nb_capmts = i_nb_capmts;
p_sys->i_ca_next_pmt = mdate() + 1000000;
return VLC_SUCCESS;
}
......@@ -1131,15 +1450,14 @@ int E_(en50221_SetCAPMT)( access_t * p_access, uint8_t **pp_capmts,
void E_(en50221_End)( access_t * p_access )
{
access_sys_t *p_sys = p_access->p_sys;
int i;
if ( p_sys->i_nb_capmts )
for ( i = 0; i < MAX_PROGRAMS; i++ )
{
int i;
for ( i = 0; i < p_sys->i_nb_capmts; i++ )
if ( p_sys->pp_selected_programs[i] != NULL )
{
free( p_sys->pp_capmts[i] );
dvbpsi_DeletePMT( p_sys->pp_selected_programs[i] );
}
free( p_sys->pp_capmts );
}
/* TODO */
......
......@@ -44,16 +44,31 @@
#include <linux/dvb/frontend.h>
#include <linux/dvb/ca.h>
#include "dvb.h"
/* Include dvbpsi headers */
#ifdef HAVE_DVBPSI_DR_H
# include <dvbpsi/dvbpsi.h>
# include <dvbpsi/descriptor.h>
# include <dvbpsi/pat.h>
# include <dvbpsi/pmt.h>
# include <dvbpsi/dr.h>
# include <dvbpsi/psi.h>
#else
# include "dvbpsi.h"
# include "descriptor.h"
# include "tables/pat.h"
# include "tables/pmt.h"
# include "descriptors/dr.h"
# include "psi.h"
#endif
#define DMX_BUFFER_SIZE (1024 * 1024)
#include "dvb.h"
/*
* Frontends
*/
struct frontend_t
{
int i_handle;
fe_status_t i_last_status;
struct dvb_frontend_info info;
};
......@@ -62,7 +77,6 @@ static int FrontendInfo( access_t * );
static int FrontendSetQPSK( access_t * );
static int FrontendSetQAM( access_t * );
static int FrontendSetOFDM( access_t * );
static int FrontendCheck( access_t * );
/*****************************************************************************
* FrontendOpen : Determine frontend device information and capabilities
......@@ -88,7 +102,7 @@ int E_(FrontendOpen)( access_t *p_access )
p_sys->p_frontend = p_frontend = malloc( sizeof(frontend_t) );
msg_Dbg( p_access, "Opening device %s", frontend );
if( (p_frontend->i_handle = open(frontend, O_RDWR | O_NONBLOCK)) < 0 )
if( (p_sys->i_frontend_handle = open(frontend, O_RDWR | O_NONBLOCK)) < 0 )
{
msg_Err( p_access, "FrontEndOpen: opening device failed (%s)",
strerror(errno) );
......@@ -103,7 +117,7 @@ int E_(FrontendOpen)( access_t *p_access )
if( FrontendInfo( p_access ) < 0 )
{
close( p_frontend->i_handle );
close( p_sys->i_frontend_handle );
free( p_frontend );
return VLC_EGENERIC;
}
......@@ -148,7 +162,7 @@ int E_(FrontendOpen)( access_t *p_access )
{
msg_Err( p_access, "the user asked for %s, and the tuner is %s",
psz_expected, psz_real );
close( p_frontend->i_handle );
close( p_sys->i_frontend_handle );
free( p_frontend );
return VLC_EGENERIC;
}
......@@ -182,7 +196,7 @@ void E_(FrontendClose)( access_t *p_access )
if( p_sys->p_frontend )
{
close( p_sys->p_frontend->i_handle );
close( p_sys->i_frontend_handle );
free( p_sys->p_frontend );
p_sys->p_frontend = NULL;
......@@ -198,7 +212,7 @@ int E_(FrontendSet)( access_t *p_access )
switch( p_sys->p_frontend->info.type )
{
/* DVB-S: satellite and budget cards (nova) */
/* DVB-S */
case FE_QPSK:
if( FrontendSetQPSK( p_access ) < 0 )
{
......@@ -230,9 +244,86 @@ int E_(FrontendSet)( access_t *p_access )
p_sys->p_frontend->info.name );
return VLC_EGENERIC;
}
p_sys->p_frontend->i_last_status = 0;
return VLC_SUCCESS;
}
/*****************************************************************************
* FrontendPoll : Poll for frontend events
*****************************************************************************/
void E_(FrontendPoll)( access_t *p_access )
{
access_sys_t *p_sys = p_access->p_sys;
frontend_t * p_frontend = p_sys->p_frontend;
int i_ret;
struct dvb_frontend_event event;
fe_status_t i_status, i_diff;
if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_EVENT,
&event )) < 0 )
{
msg_Err( p_access, "reading frontend status failed (%d) %s",
i_ret, strerror(errno) );
return;
}
i_status = event.status;
i_diff = i_status ^ p_frontend->i_last_status;
p_frontend->i_last_status = i_status;
#define IF_UP( x ) \
} \
if ( i_diff & (x) ) \
{ \
if ( i_status & (x) )
{
IF_UP( FE_HAS_SIGNAL )
msg_Dbg( p_access, "frontend has acquired signal" );
else
msg_Dbg( p_access, "frontend has lost signal" );
IF_UP( FE_HAS_CARRIER )
msg_Dbg( p_access, "frontend has acquired carrier" );
else
msg_Dbg( p_access, "frontend has lost carrier" );
IF_UP( FE_HAS_VITERBI )
msg_Dbg( p_access, "frontend has acquired stable FEC" );
else
msg_Dbg( p_access, "frontend has lost FEC" );
IF_UP( FE_HAS_SYNC )
msg_Dbg( p_access, "frontend has acquired sync" );
else
msg_Dbg( p_access, "frontend has lost sync" );
IF_UP( FE_HAS_LOCK )
{
int32_t i_value;
msg_Dbg( p_access, "frontend has acquired lock" );
/* Read some statistics */
if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &i_value ) >= 0 )
msg_Dbg( p_access, "- Bit error rate: %d", i_value );
if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH, &i_value ) >= 0 )
msg_Dbg( p_access, "- Signal strength: %d", i_value );
if( ioctl( p_sys->i_frontend_handle, FE_READ_SNR, &i_value ) >= 0 )
msg_Dbg( p_access, "- SNR: %d", i_value );
}
else
{
msg_Dbg( p_access, "frontend has lost lock" );
}
IF_UP( FE_REINIT )
{
/* The frontend was reinited. */
msg_Warn( p_access, "reiniting frontend");
E_(FrontendSet)( p_access );
}
}
}
/*****************************************************************************
* FrontendInfo : Return information about given frontend
*****************************************************************************/
......@@ -243,7 +334,7 @@ static int FrontendInfo( access_t *p_access )
int i_ret;
/* Determine type of frontend */
if( (i_ret = ioctl( p_frontend->i_handle, FE_GET_INFO,
if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_INFO,
&p_frontend->info )) < 0 )
{
msg_Err( p_access, "ioctl FE_GET_INFO failed (%d) %s", i_ret,
......@@ -477,7 +568,6 @@ struct diseqc_cmd_t
static int DoDiseqc( access_t *p_access )
{
access_sys_t *p_sys = p_access->p_sys;
frontend_t * p_frontend = p_sys->p_frontend;
vlc_value_t val;
int i_frequency, i_lnb_slof;
fe_sec_voltage_t fe_voltage;
......@@ -502,31 +592,42 @@ static int DoDiseqc( access_t *p_access )
fe_voltage = DecodeVoltage( p_access );
fe_tone = DecodeTone( p_access );
if( (i_err = ioctl( p_frontend->i_handle, FE_SET_VOLTAGE, fe_voltage )) < 0 )
/* Switch off continuous tone. */
if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, SEC_TONE_OFF )) < 0 )
{
msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %s",
fe_tone == SEC_TONE_ON ? "on" : "off", i_err,
strerror(errno) );
return i_err;
}
/* Configure LNB voltage. */
if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_VOLTAGE, fe_voltage )) < 0 )
{
msg_Err( p_access, "ioctl FE_SET_VOLTAGE failed, voltage=%d (%d) %s",
fe_voltage, i_err, strerror(errno) );
return i_err;
}
var_Get( p_access, "dvb-high-voltage", &val );
if( (i_err = ioctl( p_sys->i_frontend_handle, FE_ENABLE_HIGH_LNB_VOLTAGE,
val.b_bool )) < 0 && val.b_bool )
{
msg_Err( p_access,
"ioctl FE_ENABLE_HIGH_LNB_VOLTAGE failed, val=%d (%d) %s",
val.b_bool, i_err, strerror(errno) );
}
/* Wait for at least 15 ms. */
msleep(15000);
var_Get( p_access, "dvb-satno", &val );
if( val.i_int != 0 )
if( val.i_int > 0 && val.i_int < 5 )
{
/* digital satellite equipment control,
* specification is available from http://www.eutelsat.com/
*/
if( (i_err = ioctl( p_frontend->i_handle, FE_SET_TONE,
SEC_TONE_OFF )) < 0 )
{
msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=off (%d) %s",
i_err, strerror(errno) );
return i_err;
}
msleep( 15000 );
if( val.i_int >= 1 && val.i_int <= 4 )
{
/* 1.x compatible equipment */
struct diseqc_cmd_t cmd = { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
......@@ -538,7 +639,7 @@ static int DoDiseqc( access_t *p_access )
| (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
| (fe_tone == SEC_TONE_ON ? 1 : 0);
if( (i_err = ioctl( p_frontend->i_handle, FE_DISEQC_SEND_MASTER_CMD,
if( (i_err = ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_MASTER_CMD,
&cmd.cmd )) < 0 )
{
msg_Err( p_access, "ioctl FE_SEND_MASTER_CMD failed (%d) %s",
......@@ -546,24 +647,21 @@ static int DoDiseqc( access_t *p_access )
return i_err;
}
msleep(cmd.wait * 1000);
}
else
{
/* A or B simple diseqc */
if( (i_err = ioctl( p_frontend->i_handle, FE_DISEQC_SEND_BURST,
val.i_int == -1 ? SEC_MINI_A : SEC_MINI_B )) < 0 )
msleep(15000 + cmd.wait * 1000);
/* A or B simple diseqc ("diseqc-compatible") */
if( (i_err = ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_BURST,
((val.i_int - 1) % 2) ? SEC_MINI_B : SEC_MINI_A )) < 0 )
{
msg_Err( p_access, "ioctl FE_SEND_BURST failed (%d) %s",
i_err, strerror(errno) );
return i_err;
}
}
msleep(15000);
}
if( (i_err = ioctl( p_frontend->i_handle, FE_SET_TONE, fe_tone )) < 0 )
if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, fe_tone )) < 0 )
{
msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %s",
fe_tone == SEC_TONE_ON ? "on" : "off", i_err,
......@@ -571,14 +669,13 @@ static int DoDiseqc( access_t *p_access )
return i_err;
}
msleep(15000);
msleep(50000);
return 0;
}
static int FrontendSetQPSK( access_t *p_access )
{
access_sys_t *p_sys = p_access->p_sys;
frontend_t * p_frontend = p_sys->p_frontend;
struct dvb_frontend_parameters fep;
int i_ret;
vlc_value_t val;
......@@ -609,25 +706,24 @@ static int FrontendSetQPSK( access_t *p_access )
return VLC_EGENERIC;
}
msleep(100000);
/* Empty the event queue */
for( ; ; )
{
struct dvb_frontend_event event;
if( ioctl( p_frontend->i_handle, FE_GET_EVENT, &event ) < 0 )
if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
&& errno == EWOULDBLOCK )
break;
}
/* Now send it all to the frontend device */
if( (i_ret = ioctl( p_frontend->i_handle, FE_SET_FRONTEND, &fep )) < 0 )
if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
{
msg_Err( p_access, "DVB-S: setting frontend failed (%d) %s", i_ret,
strerror(errno) );
return VLC_EGENERIC;
}
return FrontendCheck( p_access );
return VLC_SUCCESS;
}
/*****************************************************************************
......@@ -636,7 +732,6 @@ static int FrontendSetQPSK( access_t *p_access )
static int FrontendSetQAM( access_t *p_access )
{
access_sys_t *p_sys = p_access->p_sys;
frontend_t * p_frontend = p_sys->p_frontend;
struct dvb_frontend_parameters fep;
vlc_value_t val;
int i_ret;
......@@ -660,19 +755,20 @@ static int FrontendSetQAM( access_t *p_access )
for( ; ; )
{
struct dvb_frontend_event event;
if( ioctl( p_frontend->i_handle, FE_GET_EVENT, &event ) < 0 )
if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
&& errno == EWOULDBLOCK )
break;
}
/* Now send it all to the frontend device */
if( (i_ret = ioctl( p_frontend->i_handle, FE_SET_FRONTEND, &fep )) < 0 )
if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
{
msg_Err( p_access, "DVB-C: setting frontend failed (%d) %s", i_ret,
strerror(errno) );
return VLC_EGENERIC;
}
return FrontendCheck( p_access );
return VLC_SUCCESS;
}
/*****************************************************************************
......@@ -770,7 +866,6 @@ static fe_hierarchy_t DecodeHierarchy( access_t *p_access )
static int FrontendSetOFDM( access_t * p_access )
{
access_sys_t *p_sys = p_access->p_sys;
frontend_t * p_frontend = p_sys->p_frontend;
struct dvb_frontend_parameters fep;
vlc_value_t val;
int ret;
......@@ -796,93 +891,20 @@ static int FrontendSetOFDM( access_t * p_access )
for( ; ; )
{
struct dvb_frontend_event event;
if( ioctl( p_frontend->i_handle, FE_GET_EVENT, &event ) < 0 )
if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
&& errno == EWOULDBLOCK )
break;
}
/* Now send it all to the frontend device */
if( (ret = ioctl( p_frontend->i_handle, FE_SET_FRONTEND, &fep )) < 0 )
if( (ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
{
msg_Err( p_access, "DVB-T: setting frontend failed (%d) %s", ret,
strerror(errno) );
return -1;
}
return FrontendCheck( p_access );
}
/******************************************************************
* FrontendCheck: Check completion of the frontend control sequence
******************************************************************/
static int FrontendCheck( access_t * p_access )
{
access_sys_t *p_sys = p_access->p_sys;
frontend_t * p_frontend = p_sys->p_frontend;
int i_ret;
while ( !p_access->b_die && !p_access->b_error )
{
fe_status_t status;
if( (i_ret = ioctl( p_frontend->i_handle, FE_READ_STATUS,
&status )) < 0 )
{
msg_Err( p_access, "reading frontend status failed (%d) %s",
i_ret, strerror(errno) );
return i_ret;
}
if(status & FE_HAS_SIGNAL) /* found something above the noise level */
msg_Dbg(p_access, "check frontend ... has signal");
if(status & FE_HAS_CARRIER) /* found a DVB signal */
msg_Dbg(p_access, "check frontend ... has carrier");
if(status & FE_HAS_VITERBI) /* FEC is stable */
msg_Dbg(p_access, "check frontend ... has stable forward error correction");
if(status & FE_HAS_SYNC) /* found sync bytes */
msg_Dbg(p_access, "check frontend ... has sync");
if(status & FE_HAS_LOCK) /* everything's working... */
{
int32_t value;
msg_Dbg(p_access, "check frontend ... has lock");
msg_Dbg(p_access, "tuning succeeded");
/* Read some statistics */
value = 0;
if( ioctl( p_frontend->i_handle, FE_READ_BER, &value ) >= 0 )
msg_Dbg( p_access, "Bit error rate: %d", value );
value = 0;
if( ioctl( p_frontend->i_handle, FE_READ_SIGNAL_STRENGTH, &value ) >= 0 )
msg_Dbg( p_access, "Signal strength: %d", value );
value = 0;
if( ioctl( p_frontend->i_handle, FE_READ_SNR, &value ) >= 0 )
msg_Dbg( p_access, "SNR: %d", value );
return 0;
}
if(status & FE_TIMEDOUT) /* no lock within the last ~2 seconds */
{
msg_Err(p_access, "tuning failed ... timed out");
return -2;
}
if(status & FE_REINIT)
{
/* frontend was reinitialized, */
/* application is recommended to reset */
/* DiSEqC, tone and parameters */
msg_Err(p_access, "tuning failed ... resend frontend parameters");
return -3;
}
msleep(500000);
}
return -1;
return VLC_SUCCESS;
}
......@@ -1084,12 +1106,6 @@ int E_(DVROpen)( access_t * p_access )
return VLC_EGENERIC;
}
if ( ioctl( p_sys->i_handle, DMX_SET_BUFFER_SIZE, DMX_BUFFER_SIZE ) < 0 )
{
msg_Warn( p_access, "couldn't set DMX_BUFFER_SIZE (%s)",
strerror(errno) );
}
return VLC_SUCCESS;
}
......@@ -1184,7 +1200,7 @@ int E_(CAMPoll)( access_t * p_access )
/*****************************************************************************
* CAMSet :
*****************************************************************************/
int E_(CAMSet)( access_t * p_access, uint8_t **pp_capmts, int i_nb_capmts )
int E_(CAMSet)( access_t * p_access, dvbpsi_pmt_t *p_pmt )
{
access_sys_t *p_sys = p_access->p_sys;
......@@ -1193,7 +1209,7 @@ int E_(CAMSet)( access_t * p_access, uint8_t **pp_capmts, int i_nb_capmts )
return VLC_EGENERIC;
}
E_(en50221_SetCAPMT)( p_access, pp_capmts, i_nb_capmts );
E_(en50221_SetCAPMT)( p_access, p_pmt );
return VLC_SUCCESS;
}
......
......@@ -202,10 +202,6 @@ typedef struct
/* IOD stuff (mpeg4) */
iod_descriptor_t *iod;
/* Conditional Access PMT (EN 50 221) */
uint8_t *p_capmt;
int i_capmt_size;
} ts_prg_psi_t;
typedef struct
......@@ -309,8 +305,6 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * );
static iod_descriptor_t *IODNew( int , uint8_t * );
static void IODFree( iod_descriptor_t * );
static void DVBCAPMTSend( demux_t *p_demux );
#define TS_PACKET_SIZE_188 188
#define TS_PACKET_SIZE_192 192
#define TS_PACKET_SIZE_204 204
......@@ -962,9 +956,6 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
}
}
}
/* Set CAM descrambling */
DVBCAPMTSend( p_demux );
}
}
else
......@@ -1015,8 +1006,6 @@ static void PIDInit( ts_pid_t *pid, vlc_bool_t b_psi, ts_psi_t *p_owner )
prg->i_pid_pcr = -1;
prg->i_pid_pmt = -1;
prg->iod = NULL;
prg->p_capmt = NULL;
prg->i_capmt_size = 0;
prg->handle = NULL;
TAB_APPEND( pid->psi->i_prg, pid->psi->prg, prg );
......@@ -1049,8 +1038,6 @@ static void PIDClean( es_out_t *out, ts_pid_t *pid )
{
if( pid->psi->prg[i]->iod )
IODFree( pid->psi->prg[i]->iod );
if ( pid->psi->prg[i]->i_capmt_size )
free( pid->psi->prg[i]->p_capmt );
if( pid->psi->prg[i]->handle )
dvbpsi_DetachPMT( pid->psi->prg[i]->handle );
free( pid->psi->prg[i] );
......@@ -1955,7 +1942,6 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
ts_pid_t *pmt = NULL;
ts_prg_psi_t *prg = NULL;
int i_cad_length = 0;
ts_pid_t **pp_clean = NULL;
int i_clean = 0, i;
......@@ -2008,9 +1994,6 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
IODFree( prg->iod );
prg->iod = NULL;
}
if ( prg->i_capmt_size )
free( prg->p_capmt );
prg->i_capmt_size = 0;
msg_Dbg( p_demux, "new PMT program number=%d version=%d pid_pcr=%d",
p_pmt->i_program_number, p_pmt->i_version, p_pmt->i_pcr_pid );
......@@ -2037,7 +2020,7 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
if( p_dr->i_tag == 0x1d )
{
/* We have found an IOD descriptor */
msg_Warn( p_demux, " * descriptor : IOD (0x1d)" );
msg_Dbg( p_demux, " * descriptor : IOD (0x1d)" );
prg->iod = IODNew( p_dr->i_length, p_dr->p_data );
}
......@@ -2046,8 +2029,6 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
uint16_t i_sysid = ((uint16_t)p_dr->p_data[0] << 8)
| p_dr->p_data[1];
msg_Dbg( p_demux, " * descriptor : CA (0x9) SysID 0x%x", i_sysid );
if ( !p_sys->i_capmt_sysid || p_sys->i_capmt_sysid == i_sysid )
i_cad_length += p_dr->i_length + 2;
}
else
{
......@@ -2055,36 +2036,6 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
}
}
if ( i_cad_length )
{
prg->p_capmt = malloc( 6 + i_cad_length );
prg->i_capmt_size = 6 + i_cad_length;
prg->p_capmt[0] = p_pmt->i_program_number >> 8;
prg->p_capmt[1] = p_pmt->i_program_number & 0xff;
prg->p_capmt[2] = ((p_pmt->i_version & 0x1f) << 1) | 0x1;
prg->p_capmt[3] = (i_cad_length + 1) >> 8;
prg->p_capmt[4] = (i_cad_length + 1) & 0xff;
prg->p_capmt[5] = 0x1; /* ok_descrambling */
i = 6;
for( p_dr = p_pmt->p_first_descriptor; p_dr != NULL; p_dr = p_dr->p_next )
{
if( p_dr->i_tag == 0x9 )
{
uint16_t i_sysid = ((uint16_t)p_dr->p_data[0] << 8)
| p_dr->p_data[1];
if ( !p_sys->i_capmt_sysid || p_sys->i_capmt_sysid == i_sysid )
{
prg->p_capmt[i] = 0x9;
prg->p_capmt[i+1] = p_dr->i_length;
memcpy( &prg->p_capmt[i+2], p_dr->p_data, p_dr->i_length );
i += p_dr->i_length + 2;
}
}
}
}
for( p_es = p_pmt->p_first_es; p_es != NULL; p_es = p_es->p_next )
{
ts_pid_t tmp_pid, *old_pid = 0, *pid = &tmp_pid;
......@@ -2453,7 +2404,6 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
}
}
i_cad_length = 0;
/* Add ES to the list */
if( old_pid )
{
......@@ -2471,78 +2421,8 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
| p_dr->p_data[1];
msg_Dbg( p_demux, " * descriptor : CA (0x9) SysID 0x%x",
i_sysid );
if ( !p_sys->i_capmt_sysid || p_sys->i_capmt_sysid == i_sysid )
i_cad_length += p_dr->i_length + 2;
}
else
{
msg_Dbg( p_demux, " * descriptor : unknown (0x%x)",
p_dr->i_tag );
}
}
if ( i_cad_length )
{
if ( !prg->i_capmt_size )
{
prg->p_capmt = malloc( 5 + 6 + i_cad_length );
prg->i_capmt_size = 5 + 6 + i_cad_length;
prg->p_capmt[0] = p_pmt->i_program_number >> 8;
prg->p_capmt[1] = p_pmt->i_program_number & 0xff;
prg->p_capmt[2] = ((p_pmt->i_version & 0x1f) << 1) | 0x1;
prg->p_capmt[3] = 0; /* cad length */
prg->p_capmt[4] = 0;
i = 5;
}
else
{
prg->p_capmt = realloc( prg->p_capmt,
prg->i_capmt_size + 6 + i_cad_length );
i = prg->i_capmt_size;
prg->i_capmt_size += 6 + i_cad_length;
}
prg->p_capmt[i] = p_es->i_type;
prg->p_capmt[i+1] = p_es->i_pid >> 8;
prg->p_capmt[i+2] = p_es->i_pid & 0xff;
prg->p_capmt[i+3] = (i_cad_length + 1) >> 8;
prg->p_capmt[i+4] = (i_cad_length + 1) & 0xff;
prg->p_capmt[i+5] = 0x1; /* ok_descrambling */
i += 6;
for( p_dr = p_es->p_first_descriptor; p_dr != NULL; p_dr = p_dr->p_next )
{
if( p_dr->i_tag == 0x9 )
{
uint16_t i_sysid = ((uint16_t)p_dr->p_data[0] << 8)
| p_dr->p_data[1];
if ( !p_sys->i_capmt_sysid
|| p_sys->i_capmt_sysid == i_sysid )
{
prg->p_capmt[i] = 0x9;
prg->p_capmt[i+1] = p_dr->i_length;
memcpy( &prg->p_capmt[i+2], p_dr->p_data, p_dr->i_length );
i += p_dr->i_length + 2;
}
}
}
}
else if ( prg->i_capmt_size )
{
prg->p_capmt = realloc( prg->p_capmt,
prg->i_capmt_size + 5 );
i = prg->i_capmt_size;
prg->i_capmt_size += 5;
prg->p_capmt[i] = p_es->i_type;
prg->p_capmt[i+1] = p_es->i_pid >> 8;
prg->p_capmt[i+2] = p_es->i_pid & 0xff;
prg->p_capmt[i+3] = 0;
prg->p_capmt[i+4] = 0;
i += 5;
}
if( DVBProgramIsSelected( p_demux, prg->i_number ) )
{
......@@ -2553,7 +2433,16 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
}
}
if( DVBProgramIsSelected( p_demux, prg->i_number ) )
{
/* Set CAM descrambling */
stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
ACCESS_SET_PRIVATE_ID_CA, p_pmt );
}
else
{
dvbpsi_DeletePMT( p_pmt );
}
for ( i = 0; i < i_clean; i++ )
{
......@@ -2567,12 +2456,6 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
PIDClean( p_demux->out, pp_clean[i] );
}
if( i_clean ) free( pp_clean );
if( DVBProgramIsSelected( p_demux, prg->i_number ) )
{
/* Set CAM descrambling */
DVBCAPMTSend( p_demux );
}
}
static void PATCallBack( demux_t *p_demux, dvbpsi_pat_t *p_pat )
......@@ -2747,117 +2630,3 @@ static void PATCallBack( demux_t *p_demux, dvbpsi_pat_t *p_pat )
dvbpsi_DeletePAT( p_pat );
}
static void DVBCAPMTSend( demux_t *p_demux )
{
demux_sys_t *p_sys = p_demux->p_sys;
int i_nb_capmts = 0;
int i;
for( i = 0; i < p_sys->i_pmt; i++ )
{
ts_pid_t *pmt = p_sys->pmt[i];
int i_prg;
for( i_prg = 0; i_prg < pmt->psi->i_prg; i_prg++ )
{
if( DVBProgramIsSelected( p_demux, pmt->psi->prg[i_prg]->i_number )
&& pmt->psi->prg[i_prg]->i_capmt_size )
{
i_nb_capmts++;
}
}
}
if ( i_nb_capmts )
{
uint8_t **pp_capmts = malloc( i_nb_capmts * sizeof(uint8_t *) );
int i_current_capmt = 0;
for( i = 0; i < p_sys->i_pmt; i++ )
{
ts_pid_t *pmt = p_sys->pmt[i];
int i_prg;
for( i_prg = 0; i_prg < pmt->psi->i_prg; i_prg++ )
{
if( DVBProgramIsSelected( p_demux, pmt->psi->prg[i_prg]->i_number )
&& pmt->psi->prg[i_prg]->i_capmt_size )
{
uint8_t *p_capmt = malloc( pmt->psi->prg[i_prg]->i_capmt_size + 10 );
int i_pos = 0;
pp_capmts[i_current_capmt] = p_capmt;
p_capmt[i_pos] = 0x9F;
p_capmt[i_pos+1] = 0x80;
p_capmt[i_pos+2] = 0x32;
i_pos += 3;
if ( (pmt->psi->prg[i_prg]->i_capmt_size + 1) < 128 )
{
p_capmt[i_pos] = (pmt->psi->prg[i_prg]->i_capmt_size + 1);
i_pos++;
}
else if ( (pmt->psi->prg[i_prg]->i_capmt_size + 1) < 256 )
{
p_capmt[i_pos] = 0x81;
p_capmt[i_pos+1] = (pmt->psi->prg[i_prg]->i_capmt_size + 1);
i_pos += 2;
}
else if ( (pmt->psi->prg[i_prg]->i_capmt_size + 1) < 65536 )
{
p_capmt[i_pos] = 0x82;
p_capmt[i_pos+1] =
(pmt->psi->prg[i_prg]->i_capmt_size + 1) >> 8;
p_capmt[i_pos+2] =
(pmt->psi->prg[i_prg]->i_capmt_size + 1) & 0xff;
i_pos += 3;
}
else if ( (pmt->psi->prg[i_prg]->i_capmt_size + 1) < 16777216 )
{
p_capmt[i_pos] = 0x83;
p_capmt[i_pos+1] =
(pmt->psi->prg[i_prg]->i_capmt_size + 1) >> 16;
p_capmt[i_pos+2] =
((pmt->psi->prg[i_prg]->i_capmt_size + 1) >> 8) & 0xff;
p_capmt[i_pos+3] =
(pmt->psi->prg[i_prg]->i_capmt_size + 1) & 0xff;
i_pos += 4;
}
else
{
p_capmt[i_pos] = 0x84;
p_capmt[i_pos+1] =
(pmt->psi->prg[i_prg]->i_capmt_size + 1) >> 24;
p_capmt[i_pos+2] =
((pmt->psi->prg[i_prg]->i_capmt_size + 1) >> 16) & 0xff;
p_capmt[i_pos+3] =
((pmt->psi->prg[i_prg]->i_capmt_size + 1) >> 8) & 0xff;
p_capmt[i_pos+4] =
(pmt->psi->prg[i_prg]->i_capmt_size + 1) & 0xff;
i_pos += 5;
}
if ( i_nb_capmts > 1 )
{
if ( i_current_capmt == 0 )
p_capmt[i_pos] = 0x1; /* first */
else if ( i_current_capmt == i_nb_capmts - 1 )
p_capmt[i_pos] = 0x2; /* last */
else
p_capmt[i_pos] = 0x0; /* more */
}
else
p_capmt[i_pos] = 0x3; /* only */
i_pos++;
i_current_capmt++;
memcpy( &p_capmt[i_pos], pmt->psi->prg[i_prg]->p_capmt,
pmt->psi->prg[i_prg]->i_capmt_size );
}
}
}
stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
ACCESS_SET_PRIVATE_ID_CA, pp_capmts, i_nb_capmts );
}
}
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