native support for CAM modules (without using an external program).
When used in conjunction with --programs, it also allows to descramble
several services with one professional CAM.
SOURCES_dvb = \
access.c \
linux_dvb.c \
+ en50221.c \
dvb.h \
$(NULL)
#define DEVICE_TEXT N_("Device number to use on adapter")
#define DEVICE_LONGTEXT ""
-#define CAM_TEXT N_("Use CAM")
-#define CAM_LONGTEXT ""
-
#define FREQ_TEXT N_("Transponder/multiplex frequency")
#define FREQ_LONGTEXT N_("In kHz for DVB-S or Hz for DVB-C/T")
VLC_FALSE );
add_integer( "dvb-device", 0, NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
VLC_TRUE );
- add_bool( "dvb-cam", 0, NULL, CAM_TEXT, CAM_LONGTEXT, VLC_FALSE );
add_integer( "dvb-frequency", 11954000, NULL, FREQ_TEXT, FREQ_LONGTEXT,
VLC_FALSE );
add_integer( "dvb-inversion", 2, NULL, INVERSION_TEXT, INVERSION_LONGTEXT,
static block_t *Block( access_t * );
static int Control( access_t *, int, va_list );
-#define SATELLITE_READ_ONCE 3
+#define DVB_READ_ONCE 3
#define TS_PACKET_SIZE 188
static void FilterUnset( access_t *, int i_max );
FilterSet( p_access, 0x0, OTHER_TYPE );
}
- p_sys->b_cam = var_GetBool( p_access, "dvb-cam" );
- if ( p_sys->b_cam )
- {
- msg_Dbg( p_access, "initing CAM..." );
- if ( E_(CAMOpen)( p_access ) < 0 )
- p_sys->b_cam = VLC_FALSE;
- }
+ E_(CAMOpen)( p_access );
return VLC_SUCCESS;
}
E_(DVRClose)( p_access );
E_(FrontendClose)( p_access );
-
- if ( p_sys->b_cam )
- E_(CAMClose)( p_access );
+ E_(CAMClose)( p_access );
free( p_sys );
}
static block_t *Block( access_t *p_access )
{
access_sys_t *p_sys = p_access->p_sys;
- struct timeval timeout;
- fd_set fds;
- int i_ret;
block_t *p_block;
- /* Initialize file descriptor set */
- FD_ZERO( &fds );
- FD_SET( p_sys->i_handle, &fds );
-
- /* We'll wait 0.5 second if nothing happens */
- timeout.tv_sec = 0;
- timeout.tv_usec = 500000;
-
- /* Find if some data is available */
- while( (i_ret = select( p_sys->i_handle + 1, &fds, NULL, NULL, &timeout )) == 0 ||
- (i_ret < 0 && errno == EINTR) )
+ for ( ; ; )
{
+ struct timeval timeout;
+ fd_set fds;
+ int i_ret;
+
+ /* Initialize file descriptor set */
FD_ZERO( &fds );
FD_SET( p_sys->i_handle, &fds );
+
+ /* We'll wait 0.5 second if nothing happens */
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
- if( p_access->b_die )
+ /* Find if some data is available */
+ i_ret = select( p_sys->i_handle + 1, &fds, NULL, NULL, &timeout );
+
+ if ( p_access->b_die )
return NULL;
- }
- if ( i_ret < 0 )
- {
- msg_Err( p_access, "select error (%s)", strerror(errno) );
- return NULL;
+ if ( i_ret < 0 && errno == EINTR )
+ continue;
+
+ if ( i_ret < 0 )
+ {
+ msg_Err( p_access, "select error (%s)", strerror(errno) );
+ return NULL;
+ }
+
+ if ( p_sys->i_ca_handle && mdate() > p_sys->i_ca_next_event )
+ {
+ E_(CAMPoll)( p_access );
+ p_sys->i_ca_next_event = mdate() + p_sys->i_ca_timeout;
+ }
+
+ if ( FD_ISSET( p_sys->i_handle, &fds ) )
+ {
+ break;
+ }
}
- p_block = block_New( p_access, SATELLITE_READ_ONCE * TS_PACKET_SIZE );
- if( ( p_block->i_buffer = read( p_sys->i_handle, p_block->p_buffer, SATELLITE_READ_ONCE * TS_PACKET_SIZE ) ) <= 0 )
+ p_block = block_New( p_access, DVB_READ_ONCE * TS_PACKET_SIZE );
+ if( ( p_block->i_buffer = read( p_sys->i_handle, p_block->p_buffer,
+ DVB_READ_ONCE * TS_PACKET_SIZE ) ) <= 0 )
{
msg_Err( p_access, "read failed (%s)", strerror(errno) );
block_Release( p_block );
/* */
case ACCESS_GET_MTU:
pi_int = (int*)va_arg( args, int * );
- *pi_int = SATELLITE_READ_ONCE * TS_PACKET_SIZE;
+ *pi_int = DVB_READ_ONCE * TS_PACKET_SIZE;
break;
case ACCESS_GET_PTS_DELAY:
break;
case ACCESS_SET_PRIVATE_ID_CA:
- if ( p_sys->b_cam )
- {
- int i_program;
- uint16_t i_vpid, i_apid1, i_apid2, i_apid3;
- uint8_t i_cad_length;
- uint8_t *p_cad;
-
- i_program = (int)va_arg( args, int );
- i_vpid = (int16_t)va_arg( args, int );
- i_apid1 = (uint16_t)va_arg( args, int );
- i_apid2 = (uint16_t)va_arg( args, int );
- i_apid3 = (uint16_t)va_arg( args, int );
- i_cad_length = (uint8_t)va_arg( args, int );
- p_cad = (uint8_t *)va_arg( args, uint8_t * );
-
- E_(CAMSet)( p_access, i_program, i_vpid, i_apid1, i_apid2,
- i_apid3, i_cad_length, p_cad );
- }
- break;
+ {
+ uint8_t **pp_capmts;
+ int i_nb_capmts;
+ pp_capmts = (uint8_t **)va_arg( args, uint8_t ** );
+ i_nb_capmts = (int)va_arg( args, int );
+
+ E_(CAMSet)( p_access, pp_capmts, i_nb_capmts );
+ break;
+ }
default:
msg_Warn( p_access, "unimplemented query in control" );
return VLC_EGENERIC;
/* */
var_Create( p_access, "dvb-adapter", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
- var_Create( p_access, "dvb-cam", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-frequency", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-inversion", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-probe", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
{
GET_OPTION_INT("adapter")
else GET_OPTION_INT("device")
- else GET_OPTION_BOOL("cam")
else GET_OPTION_INT("frequency")
else GET_OPTION_INT("inversion")
else GET_OPTION_BOOL("probe")
#define DMX "/dev/dvb/adapter%d/demux%d"
#define FRONTEND "/dev/dvb/adapter%d/frontend%d"
#define DVR "/dev/dvb/adapter%d/dvr%d"
+#define CA "/dev/dvb/adapter%d/ca%d"
/*****************************************************************************
* Local structures
typedef struct frontend_t frontend_t;
-#define MAX_DEMUX 24
+typedef struct
+{
+ int i_slot;
+ int i_resource_id;
+ void (* pf_handle)( access_t *, int, uint8_t *, int );
+ void (* pf_close)( access_t *, int );
+ void (* pf_manage)( access_t *, int );
+ void *p_sys;
+} en50221_session_t;
+
+#define MAX_DEMUX 48
+#define MAX_CI_SLOTS 16
+#define MAX_SESSIONS 32
struct access_sys_t
{
demux_handle_t p_demux_handles[MAX_DEMUX];
frontend_t *p_frontend;
vlc_bool_t b_budget_mode;
- vlc_bool_t b_cam;
- int i_cam_handle;
+
+ /* CA management */
+ int i_ca_handle;
+ int i_nb_slots;
+ 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;
+ uint8_t **pp_capmts;
+ int i_nb_capmts;
};
#define VIDEO0_TYPE 1
void E_(DVRClose)( access_t * );
int E_(CAMOpen)( access_t * );
-int E_(CAMSet)( access_t *, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t,
- uint16_t, uint8_t * );
+int E_(CAMPoll)( access_t * );
+int E_(CAMSet)( access_t *, uint8_t **, int );
void E_(CAMClose)( access_t * );
+
+int E_(en50221_Init)( access_t * );
+int E_(en50221_Poll)( access_t * );
+int E_(en50221_SetCAPMT)( access_t *, uint8_t **, int );
+void E_(en50221_End)( access_t * );
+
--- /dev/null
+/*****************************************************************************
+ * en50221.c : implementation of the transport, session and applications
+ * layers of EN 50 221
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ *
+ * Authors: Christophe Massiot <massiot@via.ecp.fr>
+ * Based on code from libdvbci Copyright (C) 2000 Klaus Schmidinger
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+
+#include "dvb.h"
+
+#undef DEBUG_TPDU
+
+static void ResourceManagerOpen( access_t * p_access, int i_session_id );
+static void ApplicationInformationOpen( access_t * p_access, int i_session_id );
+static void ConditionalAccessOpen( access_t * p_access, int i_session_id );
+static void DateTimeOpen( access_t * p_access, int i_session_id );
+static void MMIOpen( access_t * p_access, int i_session_id );
+
+/*****************************************************************************
+ * Utility functions
+ *****************************************************************************/
+#define SIZE_INDICATOR 0x80
+
+static uint8_t *GetLength( uint8_t *p_data, int *pi_length )
+{
+ *pi_length = *p_data++;
+
+ if ( (*pi_length & SIZE_INDICATOR) != 0 )
+ {
+ int l = *pi_length & ~SIZE_INDICATOR;
+ int i;
+
+ *pi_length = 0;
+ for ( i = 0; i < l; i++ )
+ *pi_length = (*pi_length << 8) | *p_data++;
+ }
+
+ return p_data;
+}
+
+static uint8_t *SetLength( uint8_t *p_data, int i_length )
+{
+ uint8_t *p = p_data;
+
+ if ( i_length < 128 )
+ {
+ *p++ = i_length;
+ }
+ else if ( i_length < 256 )
+ {
+ *p++ = SIZE_INDICATOR | 0x1;
+ *p++ = i_length;
+ }
+ else if ( i_length < 65536 )
+ {
+ *p++ = SIZE_INDICATOR | 0x2;
+ *p++ = i_length >> 8;
+ *p++ = i_length & 0xff;
+ }
+ else if ( i_length < 16777216 )
+ {
+ *p++ = SIZE_INDICATOR | 0x3;
+ *p++ = i_length >> 16;
+ *p++ = (i_length >> 8) & 0xff;
+ *p++ = i_length & 0xff;
+ }
+ else
+ {
+ *p++ = SIZE_INDICATOR | 0x4;
+ *p++ = i_length >> 24;
+ *p++ = (i_length >> 16) & 0xff;
+ *p++ = (i_length >> 8) & 0xff;
+ *p++ = i_length & 0xff;
+ }
+
+ return p;
+}
+
+
+/*
+ * Transport layer
+ */
+
+#define MAX_TPDU_SIZE 2048
+#define MAX_TPDU_DATA (MAX_TPDU_SIZE - 4)
+
+#define DATA_INDICATOR 0x80
+
+#define T_SB 0x80
+#define T_RCV 0x81
+#define T_CREATE_TC 0x82
+#define T_CTC_REPLY 0x83
+#define T_DELETE_TC 0x84
+#define T_DTC_REPLY 0x85
+#define T_REQUEST_TC 0x86
+#define T_NEW_TC 0x87
+#define T_TC_ERROR 0x88
+#define T_DATA_LAST 0xA0
+#define T_DATA_MORE 0xA1
+
+static void Dump( vlc_bool_t b_outgoing, uint8_t *p_data, int i_size )
+{
+#ifdef DEBUG_TPDU
+ int i;
+#define MAX_DUMP 256
+ fprintf(stderr, "%s ", b_outgoing ? "-->" : "<--");
+ for ( i = 0; i < i_size && i < MAX_DUMP; i++)
+ fprintf(stderr, "%02X ", p_data[i]);
+ fprintf(stderr, "%s\n", i_size >= MAX_DUMP ? "..." : "");
+#endif
+}
+
+/*****************************************************************************
+ * TPDUSend
+ *****************************************************************************/
+static int TPDUSend( access_t * p_access, uint8_t i_slot, uint8_t i_tag,
+ const uint8_t *p_content, int i_length )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ uint8_t i_tcid = i_slot + 1;
+ uint8_t p_data[MAX_TPDU_SIZE];
+ int i_size;
+
+ i_size = 0;
+ p_data[0] = i_slot;
+ p_data[1] = i_tcid;
+ p_data[2] = i_tag;
+
+ switch ( i_tag )
+ {
+ case T_RCV:
+ case T_CREATE_TC:
+ case T_CTC_REPLY:
+ case T_DELETE_TC:
+ case T_DTC_REPLY:
+ case T_REQUEST_TC:
+ p_data[3] = 1; /* length */
+ p_data[4] = i_tcid;
+ i_size = 5;
+ break;
+
+ case T_NEW_TC:
+ case T_TC_ERROR:
+ p_data[3] = 2; /* length */
+ p_data[4] = i_tcid;
+ p_data[5] = p_content[0];
+ i_size = 6;
+ break;
+
+ case T_DATA_LAST:
+ case T_DATA_MORE:
+ {
+ /* i_length <= MAX_TPDU_DATA */
+ uint8_t *p = p_data + 3;
+ p = SetLength( p, i_length + 1 );
+ *p++ = i_tcid;
+
+ if ( i_length )
+ memcpy( p, p_content, i_length );
+ i_size = i_length + (p - p_data);
+ }
+ break;
+
+ default:
+ break;
+ }
+ Dump( VLC_TRUE, p_data, i_size );
+
+ if ( write( p_sys->i_ca_handle, p_data, i_size ) != i_size )
+ {
+ msg_Err( p_access, "cannot write to CAM device (%s)",
+ strerror(errno) );
+ return VLC_EGENERIC;
+ }
+
+ return VLC_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * TPDURecv
+ *****************************************************************************/
+#define CAM_READ_TIMEOUT 3500 // ms
+
+static int TPDURecv( access_t * p_access, uint8_t i_slot, uint8_t *pi_tag,
+ uint8_t *p_data, int *pi_size )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ uint8_t i_tcid = i_slot + 1;
+ int i_size;
+ struct pollfd pfd[1];
+
+ pfd[0].fd = p_sys->i_ca_handle;
+ pfd[0].events = POLLIN;
+ if ( !(poll(pfd, 1, CAM_READ_TIMEOUT) > 0 && (pfd[0].revents & POLLIN)) )
+ {
+ msg_Err( p_access, "cannot poll from CAM device" );
+ return VLC_EGENERIC;
+ }
+
+ if ( pi_size == NULL )
+ {
+ p_data = malloc( MAX_TPDU_SIZE );
+ }
+
+ for ( ; ; )
+ {
+ i_size = read( p_sys->i_ca_handle, p_data, MAX_TPDU_SIZE );
+
+ if ( i_size >= 0 || errno != EINTR )
+ break;
+ }
+
+ if ( i_size < 5 )
+ {
+ msg_Err( p_access, "cannot read from CAM device (%d:%s)", i_size,
+ strerror(errno) );
+ return VLC_EGENERIC;
+ }
+
+ if ( p_data[1] != i_tcid )
+ {
+ msg_Err( p_access, "invalid read from CAM device (%d instead of %d)",
+ p_data[1], i_tcid );
+ return VLC_EGENERIC;
+ }
+
+ *pi_tag = p_data[2];
+ p_sys->pb_tc_has_data[i_slot] = (i_size >= 4
+ && p_data[i_size - 4] == T_SB
+ && p_data[i_size - 3] == 2
+ && (p_data[i_size - 1] & DATA_INDICATOR))
+ ? VLC_TRUE : VLC_FALSE;
+
+ Dump( VLC_FALSE, p_data, i_size );
+
+ if ( pi_size == NULL )
+ free( p_data );
+ else
+ *pi_size = i_size;
+
+ return VLC_SUCCESS;
+}
+
+
+/*
+ * Session layer
+ */
+
+#define ST_SESSION_NUMBER 0x90
+#define ST_OPEN_SESSION_REQUEST 0x91
+#define ST_OPEN_SESSION_RESPONSE 0x92
+#define ST_CREATE_SESSION 0x93
+#define ST_CREATE_SESSION_RESPONSE 0x94
+#define ST_CLOSE_SESSION_REQUEST 0x95
+#define ST_CLOSE_SESSION_RESPONSE 0x96
+
+#define SS_OK 0x00
+#define SS_NOT_ALLOCATED 0xF0
+
+#define RI_RESOURCE_MANAGER 0x00010041
+#define RI_APPLICATION_INFORMATION 0x00020041
+#define RI_CONDITIONAL_ACCESS_SUPPORT 0x00030041
+#define RI_HOST_CONTROL 0x00200041
+#define RI_DATE_TIME 0x00240041
+#define RI_MMI 0x00400041
+
+static int ResourceIdToInt( uint8_t *p_data )
+{
+ return ((int)p_data[0] << 24) | ((int)p_data[1] << 16)
+ | ((int)p_data[2] << 8) | p_data[3];
+}
+
+/*****************************************************************************
+ * SPDUSend
+ *****************************************************************************/
+static int SPDUSend( access_t * p_access, int i_session_id,
+ uint8_t *p_data, int i_size )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ uint8_t *p_spdu = malloc( i_size + 4 );
+ uint8_t *p = p_spdu;
+ uint8_t i_tag;
+ uint8_t i_slot = p_sys->p_sessions[i_session_id - 1].i_slot;
+
+ *p++ = ST_SESSION_NUMBER;
+ *p++ = 0x02;
+ *p++ = (i_session_id >> 8);
+ *p++ = i_session_id & 0xff;
+
+ memcpy( p, p_data, i_size );
+
+ i_size += 4;
+ p = p_spdu;
+
+ while ( i_size > 0 )
+ {
+ if ( i_size > MAX_TPDU_DATA )
+ {
+ if ( TPDUSend( p_access, i_slot, T_DATA_MORE, p,
+ MAX_TPDU_DATA ) != VLC_SUCCESS )
+ {
+ msg_Err( p_access, "couldn't send TPDU on session %d",
+ i_session_id );
+ free( p_spdu );
+ return VLC_EGENERIC;
+ }
+ p += MAX_TPDU_DATA;
+ i_size -= MAX_TPDU_DATA;
+ }
+ else
+ {
+ if ( TPDUSend( p_access, i_slot, T_DATA_LAST, p, i_size )
+ != VLC_SUCCESS )
+ {
+ msg_Err( p_access, "couldn't send TPDU on session %d",
+ i_session_id );
+ free( p_spdu );
+ return VLC_EGENERIC;
+ }
+ i_size = 0;
+ }
+
+ if ( TPDURecv( p_access, i_slot, &i_tag, NULL, NULL ) != VLC_SUCCESS
+ || i_tag != T_SB )
+ {
+ msg_Err( p_access, "couldn't recv TPDU on session %d",
+ i_session_id );
+ free( p_spdu );
+ return VLC_EGENERIC;
+ }
+ }
+
+ free( p_spdu );
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * SessionOpen
+ *****************************************************************************/
+static void SessionOpen( access_t * p_access, uint8_t i_slot,
+ uint8_t *p_spdu, int i_size )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ int i_session_id;
+ int i_resource_id = ResourceIdToInt( &p_spdu[2] );
+ uint8_t p_response[16];
+ int i_status = SS_NOT_ALLOCATED;
+ uint8_t i_tag;
+
+ 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 )
+ break;
+ }
+ if ( i_session_id == MAX_SESSIONS )
+ {
+ msg_Err( p_access, "too many sessions !" );
+ return;
+ }
+ p_sys->p_sessions[i_session_id - 1].i_slot = i_slot;
+ p_sys->p_sessions[i_session_id - 1].i_resource_id = i_resource_id;
+ p_sys->p_sessions[i_session_id - 1].pf_close = NULL;
+ p_sys->p_sessions[i_session_id - 1].pf_manage = NULL;
+
+ if ( i_resource_id == RI_RESOURCE_MANAGER
+ || i_resource_id == RI_APPLICATION_INFORMATION
+ || i_resource_id == RI_CONDITIONAL_ACCESS_SUPPORT
+ || i_resource_id == RI_DATE_TIME
+ || i_resource_id == RI_MMI )
+ {
+ i_status = SS_OK;
+ }
+
+ p_response[0] = ST_OPEN_SESSION_RESPONSE;
+ p_response[1] = 0x7;
+ p_response[2] = i_status;
+ p_response[3] = p_spdu[2];
+ p_response[4] = p_spdu[3];
+ p_response[5] = p_spdu[4];
+ p_response[6] = p_spdu[5];
+ p_response[7] = i_session_id >> 8;
+ p_response[8] = i_session_id & 0xff;
+
+ if ( TPDUSend( p_access, i_slot, T_DATA_LAST, p_response, 9 ) !=
+ VLC_SUCCESS )
+ {
+ msg_Err( p_access,
+ "SessionOpen: couldn't send TPDU on slot %d", i_slot );
+ return;
+ }
+ if ( TPDURecv( p_access, i_slot, &i_tag, NULL, NULL ) != VLC_SUCCESS )
+ {
+ msg_Err( p_access,
+ "SessionOpen: couldn't recv TPDU on slot %d", i_slot );
+ return;
+ }
+
+ switch ( i_resource_id )
+ {
+ case RI_RESOURCE_MANAGER:
+ ResourceManagerOpen( p_access, i_session_id ); break;
+ case RI_APPLICATION_INFORMATION:
+ ApplicationInformationOpen( p_access, i_session_id ); break;
+ case RI_CONDITIONAL_ACCESS_SUPPORT:
+ ConditionalAccessOpen( p_access, i_session_id ); break;
+ case RI_DATE_TIME:
+ DateTimeOpen( p_access, i_session_id ); break;
+ case RI_MMI:
+ MMIOpen( p_access, i_session_id ); break;
+
+ case RI_HOST_CONTROL:
+ default:
+ msg_Err( p_access, "unknown resource id (0x%x)", i_resource_id );
+ p_sys->p_sessions[i_session_id - 1].i_resource_id = 0;
+ }
+}
+
+/*****************************************************************************
+ * SessionClose
+ *****************************************************************************/
+static void SessionClose( access_t * p_access, int i_session_id )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ uint8_t p_response[16];
+ uint8_t i_tag;
+ uint8_t i_slot = p_sys->p_sessions[i_session_id - 1].i_slot;
+
+ if ( p_sys->p_sessions[i_session_id - 1].pf_close != NULL )
+ p_sys->p_sessions[i_session_id - 1].pf_close( p_access, i_session_id );
+ p_sys->p_sessions[i_session_id - 1].i_resource_id = 0;
+
+ p_response[0] = ST_CLOSE_SESSION_RESPONSE;
+ p_response[1] = 0x3;
+ p_response[2] = SS_OK;
+ p_response[3] = i_session_id >> 8;
+ p_response[4] = i_session_id & 0xff;
+
+ if ( TPDUSend( p_access, i_slot, T_DATA_LAST, p_response, 5 ) !=
+ VLC_SUCCESS )
+ {
+ msg_Err( p_access,
+ "SessionOpen: couldn't send TPDU on slot %d", i_slot );
+ return;
+ }
+ if ( TPDURecv( p_access, i_slot, &i_tag, NULL, NULL ) != VLC_SUCCESS )
+ {
+ msg_Err( p_access,
+ "SessionOpen: couldn't recv TPDU on slot %d", i_slot );
+ return;
+ }
+}
+
+/*****************************************************************************
+ * SPDUHandle
+ *****************************************************************************/
+static void SPDUHandle( access_t * p_access, uint8_t i_slot,
+ uint8_t *p_spdu, int i_size )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ int i_session_id;
+
+ switch ( p_spdu[0] )
+ {
+ case ST_SESSION_NUMBER:
+ if ( i_size <= 4 )
+ return;
+ i_session_id = ((int)p_spdu[2] << 8) | p_spdu[3];
+ p_sys->p_sessions[i_session_id - 1].pf_handle( p_access, i_session_id,
+ p_spdu + 4, i_size - 4 );
+ break;
+
+ case ST_OPEN_SESSION_REQUEST:
+ if ( i_size != 6 || p_spdu[1] != 0x4 )
+ return;
+ SessionOpen( p_access, i_slot, p_spdu, i_size );
+ break;
+
+ case ST_CLOSE_SESSION_REQUEST:
+ i_session_id = ((int)p_spdu[2] << 8) | p_spdu[3];
+ SessionClose( p_access, i_session_id );
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/*
+ * Application layer
+ */
+
+#define AOT_NONE 0x000000
+#define AOT_PROFILE_ENQ 0x9F8010
+#define AOT_PROFILE 0x9F8011
+#define AOT_PROFILE_CHANGE 0x9F8012
+#define AOT_APPLICATION_INFO_ENQ 0x9F8020
+#define AOT_APPLICATION_INFO 0x9F8021
+#define AOT_ENTER_MENU 0x9F8022
+#define AOT_CA_INFO_ENQ 0x9F8030
+#define AOT_CA_INFO 0x9F8031
+#define AOT_CA_PMT 0x9F8032
+#define AOT_CA_PMT_REPLY 0x9F8033
+#define AOT_TUNE 0x9F8400
+#define AOT_REPLACE 0x9F8401
+#define AOT_CLEAR_REPLACE 0x9F8402
+#define AOT_ASK_RELEASE 0x9F8403
+#define AOT_DATE_TIME_ENQ 0x9F8440
+#define AOT_DATE_TIME 0x9F8441
+#define AOT_CLOSE_MMI 0x9F8800
+#define AOT_DISPLAY_CONTROL 0x9F8801
+#define AOT_DISPLAY_REPLY 0x9F8802
+#define AOT_TEXT_LAST 0x9F8803
+#define AOT_TEXT_MORE 0x9F8804
+#define AOT_KEYPAD_CONTROL 0x9F8805
+#define AOT_KEYPRESS 0x9F8806
+#define AOT_ENQ 0x9F8807
+#define AOT_ANSW 0x9F8808
+#define AOT_MENU_LAST 0x9F8809
+#define AOT_MENU_MORE 0x9F880A
+#define AOT_MENU_ANSW 0x9F880B
+#define AOT_LIST_LAST 0x9F880C
+#define AOT_LIST_MORE 0x9F880D
+#define AOT_SUBTITLE_SEGMENT_LAST 0x9F880E
+#define AOT_SUBTITLE_SEGMENT_MORE 0x9F880F
+#define AOT_DISPLAY_MESSAGE 0x9F8810
+#define AOT_SCENE_END_MARK 0x9F8811
+#define AOT_SCENE_DONE 0x9F8812
+#define AOT_SCENE_CONTROL 0x9F8813
+#define AOT_SUBTITLE_DOWNLOAD_LAST 0x9F8814
+#define AOT_SUBTITLE_DOWNLOAD_MORE 0x9F8815
+#define AOT_FLUSH_DOWNLOAD 0x9F8816
+#define AOT_DOWNLOAD_REPLY 0x9F8817
+#define AOT_COMMS_CMD 0x9F8C00
+#define AOT_CONNECTION_DESCRIPTOR 0x9F8C01
+#define AOT_COMMS_REPLY 0x9F8C02
+#define AOT_COMMS_SEND_LAST 0x9F8C03
+#define AOT_COMMS_SEND_MORE 0x9F8C04
+#define AOT_COMMS_RCV_LAST 0x9F8C05
+#define AOT_COMMS_RCV_MORE 0x9F8C06
+
+/*****************************************************************************
+ * APDUGetTag
+ *****************************************************************************/
+static int APDUGetTag( const uint8_t *p_apdu, int i_size )
+{
+ if ( i_size >= 3 )
+ {
+ int i, t = 0;
+ for ( i = 0; i < 3; i++ )
+ t = (t << 8) | *p_apdu++;
+ return t;
+ }
+
+ return AOT_NONE;
+}
+
+/*****************************************************************************
+ * APDUGetLength
+ *****************************************************************************/
+static uint8_t *APDUGetLength( uint8_t *p_apdu, int *pi_size )
+{
+ return GetLength( &p_apdu[3], pi_size );
+}
+
+/*****************************************************************************
+ * APDUSend
+ *****************************************************************************/
+static int APDUSend( access_t * p_access, int i_session_id, int i_tag,
+ uint8_t *p_data, int i_size )
+{
+ uint8_t *p_apdu = malloc( i_size + 12 );
+ uint8_t *p = p_apdu;
+ int i_ret;
+
+ *p++ = (i_tag >> 16);
+ *p++ = (i_tag >> 8) & 0xff;
+ *p++ = i_tag & 0xff;
+ p = SetLength( p, i_size );
+ if ( i_size )
+ memcpy( p, p_data, i_size );
+
+ i_ret = SPDUSend( p_access, i_session_id, p_apdu, i_size + p - p_apdu );
+ free( p_apdu );
+ return i_ret;
+}
+
+/*****************************************************************************
+ * ResourceManagerHandle
+ *****************************************************************************/
+static void ResourceManagerHandle( access_t * p_access, int i_session_id,
+ uint8_t *p_apdu, int i_size )
+{
+ int i_tag = APDUGetTag( p_apdu, i_size );
+
+ switch ( i_tag )
+ {
+ case AOT_PROFILE_ENQ:
+ {
+ int resources[] = { htonl(RI_RESOURCE_MANAGER),
+ htonl(RI_APPLICATION_INFORMATION),
+ htonl(RI_CONDITIONAL_ACCESS_SUPPORT),
+ htonl(RI_DATE_TIME),
+ htonl(RI_MMI)
+ };
+ APDUSend( p_access, i_session_id, AOT_PROFILE, (uint8_t*)resources,
+ sizeof(resources) );
+ break;
+ }
+ case AOT_PROFILE:
+ APDUSend( p_access, i_session_id, AOT_PROFILE_CHANGE, NULL, 0 );
+ break;
+
+ default:
+ msg_Err( p_access, "unexpected tag in ResourceManagerHandle (0x%x)",
+ i_tag );
+ }
+}
+
+/*****************************************************************************
+ * ResourceManagerOpen
+ *****************************************************************************/
+static void ResourceManagerOpen( access_t * p_access, int i_session_id )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+
+ msg_Dbg( p_access, "opening ResourceManager session (%d)", i_session_id );
+
+ p_sys->p_sessions[i_session_id - 1].pf_handle = ResourceManagerHandle;
+
+ APDUSend( p_access, i_session_id, AOT_PROFILE_ENQ, NULL, 0 );
+}
+
+/*****************************************************************************
+ * ApplicationInformationHandle
+ *****************************************************************************/
+static void ApplicationInformationHandle( access_t * p_access, int i_session_id,
+ uint8_t *p_apdu, int i_size )
+{
+ int i_tag = APDUGetTag( p_apdu, i_size );
+
+ switch ( i_tag )
+ {
+ case AOT_APPLICATION_INFO:
+ {
+ int i_type, i_manufacturer, i_code;
+ int l = 0;
+ uint8_t *d = APDUGetLength( p_apdu, &l );
+
+ if ( l < 4 ) break;
+ p_apdu[l + 3] = '\0';
+
+ i_type = *d++;
+ i_manufacturer = ((int)d[0] << 8) | d[1];
+ d += 2;
+ i_code = ((int)d[0] << 8) | d[1];
+ d += 2;
+ d = GetLength( d, &l );
+ d[l] = '\0';
+ msg_Info( p_access, "CAM: %s, %02X, %04X, %04X",
+ d, i_type, i_manufacturer, i_code );
+ break;
+ }
+ default:
+ msg_Err( p_access,
+ "unexpected tag in ApplicationInformationHandle (0x%x)",
+ i_tag );
+ }
+}
+
+/*****************************************************************************
+ * ApplicationInformationOpen
+ *****************************************************************************/
+static void ApplicationInformationOpen( access_t * p_access, int i_session_id )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+
+ msg_Dbg( p_access, "opening ApplicationInformation session (%d)", i_session_id );
+
+ p_sys->p_sessions[i_session_id - 1].pf_handle = ApplicationInformationHandle;
+
+ APDUSend( p_access, i_session_id, AOT_APPLICATION_INFO_ENQ, NULL, 0 );
+}
+
+/*****************************************************************************
+ * ConditionalAccessHandle
+ *****************************************************************************/
+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;
+ 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 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_timeout = 100000;
+ }
+ break;
+ }
+ default:
+ msg_Err( p_access,
+ "unexpected tag in ConditionalAccessHandle (0x%x)",
+ i_tag );
+ }
+}
+
+/*****************************************************************************
+ * ConditionalAccessOpen
+ *****************************************************************************/
+static void ConditionalAccessOpen( access_t * p_access, int i_session_id )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+
+ msg_Dbg( p_access, "opening ConditionalAccess session (%d)", i_session_id );
+
+ p_sys->p_sessions[i_session_id - 1].pf_handle = ConditionalAccessHandle;
+
+ APDUSend( p_access, i_session_id, AOT_CA_INFO_ENQ, NULL, 0 );
+}
+
+typedef struct
+{
+ int i_interval;
+ mtime_t i_last;
+} date_time_t;
+
+/*****************************************************************************
+ * DateTimeSend
+ *****************************************************************************/
+static void DateTimeSend( access_t * p_access, int i_session_id )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ date_time_t *p_date =
+ (date_time_t *)p_sys->p_sessions[i_session_id - 1].p_sys;
+
+ time_t t = time(NULL);
+ struct tm tm_gmt;
+ struct tm tm_loc;
+
+ if ( gmtime_r(&t, &tm_gmt) && localtime_r(&t, &tm_loc) )
+ {
+ int Y = tm_gmt.tm_year;
+ int M = tm_gmt.tm_mon + 1;
+ int D = tm_gmt.tm_mday;
+ int L = (M == 1 || M == 2) ? 1 : 0;
+ int MJD = 14956 + D + (int)((Y - L) * 365.25)
+ + (int)((M + 1 + L * 12) * 30.6001);
+ uint8_t p_response[7];
+
+#define DEC2BCD(d) (((d / 10) << 4) + (d % 10))
+
+ p_response[0] = htons(MJD) >> 8;
+ p_response[1] = htons(MJD) & 0xff;
+ p_response[2] = DEC2BCD(tm_gmt.tm_hour);
+ p_response[3] = DEC2BCD(tm_gmt.tm_min);
+ p_response[4] = DEC2BCD(tm_gmt.tm_sec);
+ p_response[5] = htons(tm_loc.tm_gmtoff / 60) >> 8;
+ p_response[6] = htons(tm_loc.tm_gmtoff / 60) & 0xff;
+
+ APDUSend( p_access, i_session_id, AOT_DATE_TIME, p_response, 7 );
+
+ p_date->i_last = mdate();
+ }
+}
+
+/*****************************************************************************
+ * DateTimeHandle
+ *****************************************************************************/
+static void DateTimeHandle( access_t * p_access, int i_session_id,
+ uint8_t *p_apdu, int i_size )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ date_time_t *p_date =
+ (date_time_t *)p_sys->p_sessions[i_session_id - 1].p_sys;
+
+ int i_tag = APDUGetTag( p_apdu, i_size );
+
+ switch ( i_tag )
+ {
+ case AOT_DATE_TIME_ENQ:
+ {
+ int l;
+ const uint8_t *d = APDUGetLength( p_apdu, &l );
+
+ if ( l > 0 )
+ {
+ p_date->i_interval = *d;
+ msg_Dbg( p_access, "DateTimeHandle : interval set to %d",
+ p_date->i_interval );
+ }
+ else
+ p_date->i_interval = 0;
+
+ DateTimeSend( p_access, i_session_id );
+ break;
+ }
+ default:
+ msg_Err( p_access, "unexpected tag in DateTimeHandle (0x%x)", i_tag );
+ }
+}
+
+/*****************************************************************************
+ * DateTimeManage
+ *****************************************************************************/
+static void DateTimeManage( access_t * p_access, int i_session_id )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ date_time_t *p_date =
+ (date_time_t *)p_sys->p_sessions[i_session_id - 1].p_sys;
+
+ if ( p_date->i_interval
+ && mdate() > p_date->i_last + (mtime_t)p_date->i_interval * 1000000 )
+ {
+ DateTimeSend( p_access, i_session_id );
+ }
+}
+
+/*****************************************************************************
+ * DateTimeOpen
+ *****************************************************************************/
+static void DateTimeOpen( access_t * p_access, int i_session_id )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+
+ msg_Dbg( p_access, "opening DateTime session (%d)", i_session_id );
+
+ p_sys->p_sessions[i_session_id - 1].pf_handle = DateTimeHandle;
+ p_sys->p_sessions[i_session_id - 1].pf_manage = DateTimeManage;
+ p_sys->p_sessions[i_session_id - 1].p_sys = malloc(sizeof(date_time_t));
+ memset( p_sys->p_sessions[i_session_id - 1].p_sys, 0, sizeof(date_time_t) );
+
+ DateTimeSend( p_access, i_session_id );
+}
+
+/*****************************************************************************
+ * MMIHandle
+ *****************************************************************************/
+static void MMIHandle( access_t * p_access, int i_session_id,
+ uint8_t *p_apdu, int i_size )
+{
+ int i_tag = APDUGetTag( p_apdu, i_size );
+
+ switch ( i_tag )
+ {
+ default:
+ msg_Err( p_access, "unexpected tag in MMIHandle (0x%x)", i_tag );
+ }
+}
+
+/*****************************************************************************
+ * MMIOpen
+ *****************************************************************************/
+static void MMIOpen( access_t * p_access, int i_session_id )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+
+ msg_Dbg( p_access, "opening MMI session (%d)", i_session_id );
+
+ p_sys->p_sessions[i_session_id - 1].pf_handle = MMIHandle;
+}
+
+
+/*
+ * External entry points
+ */
+
+/*****************************************************************************
+ * en50221_Init : Open the transport layer
+ *****************************************************************************/
+#define MAX_TC_RETRIES 20
+
+int E_(en50221_Init)( access_t * p_access )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ int i_slot, i_active_slots = 0;
+
+ for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
+ {
+ int i;
+ if ( !p_sys->pb_active_slot[i_slot] )
+ continue;
+ p_sys->pb_active_slot[i_slot] = VLC_FALSE;
+
+ if ( TPDUSend( p_access, i_slot, T_CREATE_TC, NULL, 0 )
+ != VLC_SUCCESS )
+ {
+ msg_Err( p_access, "en50221_Init: couldn't send TPDU on slot %d",
+ i_slot );
+ continue;
+ }
+
+ /* This is out of the spec */
+ for ( i = 0; i < MAX_TC_RETRIES; i++ )
+ {
+ uint8_t i_tag;
+ if ( TPDURecv( p_access, i_slot, &i_tag, NULL, NULL ) == VLC_SUCCESS
+ && i_tag == T_CTC_REPLY )
+ {
+ p_sys->pb_active_slot[i_slot] = VLC_TRUE;
+ i_active_slots++;
+ break;
+ }
+
+ if ( TPDUSend( p_access, i_slot, T_CREATE_TC, NULL, 0 )
+ != VLC_SUCCESS )
+ {
+ msg_Err( p_access,
+ "en50221_Init: couldn't send TPDU on slot %d",
+ i_slot );
+ continue;
+ }
+ }
+ }
+ p_sys->i_ca_timeout = 1000;
+
+ return i_active_slots;
+}
+
+/*****************************************************************************
+ * en50221_Poll : Poll the CAM for TPDUs
+ *****************************************************************************/
+int E_(en50221_Poll)( access_t * p_access )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ int i_slot;
+ int i_session_id;
+
+ for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
+ {
+ uint8_t i_tag;
+
+ if ( !p_sys->pb_active_slot[i_slot] )
+ continue;
+
+ if ( !p_sys->pb_tc_has_data[i_slot] )
+ {
+ if ( TPDUSend( p_access, i_slot, T_DATA_LAST, NULL, 0 ) !=
+ VLC_SUCCESS )
+ {
+ msg_Err( p_access,
+ "en50221_Poll: couldn't send TPDU on slot %d",
+ i_slot );
+ continue;
+ }
+ if ( TPDURecv( p_access, i_slot, &i_tag, NULL, NULL ) !=
+ VLC_SUCCESS )
+ {
+ msg_Err( p_access,
+ "en50221_Poll: couldn't recv TPDU on slot %d",
+ i_slot );
+ continue;
+ }
+ }
+
+ while ( p_sys->pb_tc_has_data[i_slot] )
+ {
+ uint8_t p_tpdu[MAX_TPDU_SIZE];
+ int i_size, i_session_size;
+ uint8_t *p_session;
+
+ if ( TPDUSend( p_access, i_slot, T_RCV, NULL, 0 ) != VLC_SUCCESS )
+ {
+ msg_Err( p_access,
+ "en50221_Poll: couldn't send TPDU on slot %d",
+ i_slot );
+ continue;
+ }
+ if ( TPDURecv( p_access, i_slot, &i_tag, p_tpdu, &i_size ) !=
+ VLC_SUCCESS )
+ {
+ msg_Err( p_access,
+ "en50221_Poll: couldn't recv TPDU on slot %d",
+ i_slot );
+ continue;
+ }
+
+ p_session = GetLength( &p_tpdu[3], &i_session_size );
+ if ( i_session_size <= 1 )
+ continue;
+
+ p_session++;
+ i_session_size--;
+
+ if ( i_tag != T_DATA_LAST )
+ {
+ msg_Err( p_access,
+ "en50221_Poll: fragmented TPDU not supported" );
+ break;
+ }
+
+ SPDUHandle( p_access, i_slot, p_session, i_session_size );
+ }
+ }
+
+ 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
+ && p_sys->p_sessions[i_session_id - 1].pf_manage )
+ {
+ p_sys->p_sessions[i_session_id - 1].pf_manage( p_access,
+ i_session_id );
+ }
+ }
+
+ return VLC_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * en50221_SetCAPMT :
+ *****************************************************************************/
+int E_(en50221_SetCAPMT)( access_t * p_access, uint8_t **pp_capmts,
+ int i_nb_capmts )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+ int i_session_id;
+
+ for ( i_session_id = 0; 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 < i_nb_capmts; i++ )
+ {
+ int i_size;
+ uint8_t *p;
+ p = GetLength( &pp_capmts[i][3], &i_size );
+ SPDUSend( p_access, i_session_id, pp_capmts[i],
+ i_size + (p - pp_capmts[i]) );
+ }
+
+ p_sys->i_ca_timeout = 100000;
+ }
+
+ if ( p_sys->i_nb_capmts )
+ {
+ int i;
+ for ( i = 0; i < p_sys->i_nb_capmts; i++ )
+ {
+ free( p_sys->pp_capmts[i] );
+ }
+ free( p_sys->pp_capmts );
+ }
+ p_sys->pp_capmts = pp_capmts;
+ p_sys->i_nb_capmts = i_nb_capmts;
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * en50221_End :
+ *****************************************************************************/
+void E_(en50221_End)( access_t * p_access )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+
+ if ( p_sys->i_nb_capmts )
+ {
+ int i;
+ for ( i = 0; i < p_sys->i_nb_capmts; i++ )
+ {
+ free( p_sys->pp_capmts[i] );
+ }
+ free( p_sys->pp_capmts );
+ }
+
+ /* TODO */
+}
/*****************************************************************************
- * dvb.c : functions to control a DVB card under Linux with v4l2
+ * linux_dvb.c : functions to control a DVB card under Linux with v4l2
*****************************************************************************
* Copyright (C) 1998-2004 VideoLAN
*
#include <linux/dvb/version.h>
#include <linux/dvb/dmx.h>
#include <linux/dvb/frontend.h>
-
-#include <linux/errno.h>
+#include <linux/dvb/ca.h>
#include "dvb.h"
-#include "network.h"
#define DMX_BUFFER_SIZE (1024 * 1024)
+#define CA_MAX_STATE_RETRY 5
/*
* Frontends
/*
* CAM device
- *
- * This uses the external cam_set program from libdvb-0.5.4
*/
/*****************************************************************************
* CAMOpen :
*****************************************************************************/
-int E_(CAMOpen)( access_t * p_access )
+int E_(CAMOpen)( access_t *p_access )
{
access_sys_t *p_sys = p_access->p_sys;
+ char ca[128];
+ int i_adapter, i_device, i_slot, i_active_slots = 0;
+ ca_caps_t caps;
+
+ i_adapter = var_GetInteger( p_access, "dvb-adapter" );
+ i_device = var_GetInteger( p_access, "dvb-device" );
+
+ if( snprintf( ca, sizeof(ca), CA, i_adapter, i_device ) >= (int)sizeof(ca) )
+ {
+ msg_Err( p_access, "snprintf() truncated string for CA" );
+ ca[sizeof(ca) - 1] = '\0';
+ }
+
+ msg_Dbg( p_access, "Opening device %s", ca );
+ if( (p_sys->i_ca_handle = open(ca, O_RDWR | O_NONBLOCK)) < 0 )
+ {
+ msg_Err( p_access, "CAMInit: opening device failed (%s)",
+ strerror(errno) );
+ return VLC_EGENERIC;
+ }
+
+ if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0
+ || caps.slot_num == 0 || caps.slot_type != CA_CI_LINK )
+ {
+ msg_Err( p_access, "CAMInit: no compatible CAM module" );
+ close( p_sys->i_ca_handle );
+ p_sys->i_ca_handle = 0;
+ return VLC_EGENERIC;
+ }
+
+ p_sys->i_nb_slots = caps.slot_num;
+ memset( p_sys->pb_active_slot, 0, sizeof(vlc_bool_t) * MAX_CI_SLOTS );
+
+ for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
+ {
+ ca_slot_info_t sinfo;
+ int i;
+
+ if ( ioctl( p_sys->i_ca_handle, CA_RESET, 1 << i_slot) != 0 )
+ {
+ msg_Err( p_access, "CAMInit: couldn't reset slot %d", i_slot );
+ continue;
+ }
+
+ for ( i = 0; i < CA_MAX_STATE_RETRY; i++ )
+ {
+ msleep(100000);
+
+ sinfo.num = i_slot;
+ if ( ioctl( p_sys->i_ca_handle, CA_GET_SLOT_INFO, &sinfo ) != 0 )
+ {
+ msg_Err( p_access, "CAMInit: couldn't get info on slot %d",
+ i_slot );
+ continue;
+ }
+
+ if ( sinfo.flags & CA_CI_MODULE_READY )
+ {
+ p_sys->pb_active_slot[i_slot] = VLC_TRUE;
+ }
+ }
+ }
- p_sys->i_cam_handle = net_OpenTCP( p_access, "localhost", 4711 );
- if ( p_sys->i_cam_handle < 0 )
+ i_active_slots = E_(en50221_Init)( p_access );
+
+ msg_Dbg( p_access, "CAMInit: found a CI handler with %d slots, %d active",
+ p_sys->i_nb_slots, i_active_slots );
+
+ if ( !i_active_slots )
{
- return -VLC_EGENERIC;
+ close( p_sys->i_ca_handle );
+ p_sys->i_ca_handle = 0;
+ return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
/*****************************************************************************
- * CAMSet :
+ * CAMPoll :
*****************************************************************************/
-int E_(CAMSet)( access_t * p_access, uint16_t i_program, uint16_t i_vpid,
- uint16_t i_apid1, uint16_t i_apid2, uint16_t i_apid3,
- uint16_t i_cad_length, uint8_t *p_cad )
+int E_(CAMPoll)( access_t * p_access )
{
access_sys_t *p_sys = p_access->p_sys;
- uint8_t p_str[12];
-
- memcpy( p_str, &i_program, 2 );
- memcpy( p_str + 2, &i_vpid, 2 );
- memcpy( p_str + 4, &i_apid1, 2 );
- memcpy( p_str + 6, &i_apid2, 2 );
- memcpy( p_str + 8, &i_apid3, 2 );
- memcpy( p_str + 10, &i_cad_length, 2 );
- if ( net_Write( p_access, p_sys->i_cam_handle, p_str, 12 ) != 12 )
+ if ( p_sys->i_ca_handle == 0 )
{
- msg_Err( p_access, "write 1 failed (%s)", strerror(errno) );
- return -VLC_EGENERIC;
+ return VLC_EGENERIC;
}
- if ( i_cad_length )
+ return E_(en50221_Poll)( p_access );
+}
+
+/*****************************************************************************
+ * CAMSet :
+ *****************************************************************************/
+int E_(CAMSet)( access_t * p_access, uint8_t **pp_capmts, int i_nb_capmts )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+
+ if ( p_sys->i_ca_handle == 0 )
{
- if ( net_Write( p_access, p_sys->i_cam_handle, p_cad, i_cad_length )
- != i_cad_length )
- {
- msg_Err( p_access, "write 2 failed (%s) %d", strerror(errno),
- i_cad_length );
- return -VLC_EGENERIC;
- }
+ return VLC_EGENERIC;
}
+ E_(en50221_SetCAPMT)( p_access, pp_capmts, i_nb_capmts );
+
return VLC_SUCCESS;
}
{
access_sys_t *p_sys = p_access->p_sys;
- if ( p_sys->i_cam_handle )
+ E_(en50221_End)( p_access );
+
+ if ( p_sys->i_ca_handle )
{
- close( p_sys->i_cam_handle );
+ close( p_sys->i_ca_handle );
}
}
} iod_descriptor_t;
-#define MAX_CAD 10
-
typedef struct
{
dvbpsi_handle handle;
/* IOD stuff (mpeg4) */
iod_descriptor_t *iod;
- /* Conditional Access descriptor */
- int i_nb_cad;
- uint8_t *cad[MAX_CAD];
- uint8_t i_cad_length[MAX_CAD];
+ /* Conditional Access PMT (EN 50 221) */
+ uint8_t *p_capmt;
+ int i_capmt_size;
} ts_prg_psi_t;
vlc_bool_t b_dvb_control;
int i_dvb_program;
+ vlc_list_t *p_programs_list;
};
static int Demux ( demux_t *p_demux );
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
{
ts_pid_t *pmt = &p_sys->pid[i_pid];
- msg_Dbg( p_demux, "extra pmt specified (pid=0x%x)", i_pid );
+ msg_Dbg( p_demux, "extra pmt specified (pid=%d)", i_pid );
PIDInit( pmt, VLC_TRUE, NULL );
/* FIXME we should also ask for a number */
pmt->psi->prg[0]->handle =
{
pid->es->fmt.i_id = i_pid;
}
- msg_Dbg( p_demux, " * es pid=0x%x type=0x%x "
+ msg_Dbg( p_demux, " * es pid=%d type=%d "
"fcc=%4.4s", i_pid, i_stream_type,
(char*)&pid->es->fmt.i_codec );
pid->es->id = es_out_Add( p_demux->out,
if( pid->b_seen )
{
- msg_Dbg( p_demux, " - pid[0x%x] seen", pid->i_pid );
+ msg_Dbg( p_demux, " - pid[%d] seen", pid->i_pid );
}
if( p_sys->b_dvb_control && pid->i_pid > 0 )
}
if( p_sys->i_pmt ) free( p_sys->pmt );
+
+ if ( p_sys->p_programs_list )
+ {
+ vlc_value_t val;
+ val.p_list = p_sys->p_programs_list;
+ var_Change( p_demux, "programs", VLC_VAR_FREELIST, &val, NULL );
+ }
+
free( p_sys );
}
{
if( !p_pid->b_seen )
{
- msg_Dbg( p_demux, "pid[0x%x] unknown", p_pid->i_pid );
+ msg_Dbg( p_demux, "pid[%d] unknown", p_pid->i_pid );
}
/* We have to handle PCR if present */
PCRHandle( p_demux, p_pid, p_pkt );
{
uint16_t i_vpid = 0, i_apid1 = 0, i_apid2 = 0, i_apid3 = 0;
ts_prg_psi_t *p_prg = NULL;
+ vlc_list_t *p_list;
i_int = (int)va_arg( args, int );
- msg_Dbg( p_demux, "DEMUX_SET_GROUP %d", i_int );
+ p_list = (vlc_list_t *)va_arg( args, vlc_list_t * );
+ msg_Dbg( p_demux, "DEMUX_SET_GROUP %d %p", i_int, p_list );
if( p_sys->b_dvb_control && i_int > 0 && i_int != p_sys->i_dvb_program )
{
stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
ACCESS_SET_PRIVATE_ID_STATE, i_pmt_pid,
VLC_TRUE );
+ stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
+ ACCESS_SET_PRIVATE_ID_STATE, p_prg->i_pid_pcr,
+ VLC_TRUE );
+
for( i = 2; i < 8192; i++ )
{
ts_pid_t *pid = &p_sys->pid[i];
}
/* Set CAM descrambling */
- for ( i = 0; i < p_prg->i_nb_cad; i++ )
- {
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_CA, p_prg->i_number,
- i_vpid, i_apid1, i_apid2, i_apid3,
- p_prg->i_cad_length[i],
- p_prg->cad[i] );
- }
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_CA, p_prg->i_number,
- 0, 0, 0, 0, 0, NULL );
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_CA, 0,
- 0, 0, 0, 0, 0, NULL );
+ DVBCAPMTSend( p_demux );
}
}
+ else
+ {
+ p_sys->i_dvb_program = -1;
+ p_sys->p_programs_list = p_list;
+ }
return VLC_SUCCESS;
}
prg->i_pid_pcr = -1;
prg->i_pid_pmt = -1;
prg->iod = NULL;
- prg->i_nb_cad = 0;
+ prg->p_capmt = NULL;
+ prg->i_capmt_size = 0;
prg->handle = NULL;
TAB_APPEND( pid->psi->i_prg, pid->psi->prg, prg );
if( pid->psi->handle ) dvbpsi_DetachPMT( pid->psi->handle );
for( i = 0; i < pid->psi->i_prg; i++ )
{
- int j;
if( pid->psi->prg[i]->iod )
IODFree( pid->psi->prg[i]->iod );
- for ( j = 0; j < pid->psi->prg[i]->i_nb_cad; j++ )
- free( pid->psi->prg[i]->cad[j] );
+ 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] );
if( header[0] != 0 || header[1] != 0 || header[2] != 1 )
{
if( !p_demux->p_sys->b_silent )
- msg_Warn( p_demux, "invalid header [0x%x:%x:%x:%x] (pid: 0x%x)",
+ msg_Warn( p_demux, "invalid header [0x%x:%x:%x:%x] (pid: %d)",
header[0], header[1],header[2],header[3], pid->i_pid );
block_ChainRelease( p_pes );
return;
int i_diff;
#if 0
- msg_Dbg( p_demux, "pid=0x%x unit_start=%d adaptation=%d payload=%d "
+ msg_Dbg( p_demux, "pid=%d unit_start=%d adaptation=%d payload=%d "
"cc=0x%x", pid->i_pid, b_unit_start, b_adaptation,
b_payload, i_cc );
#endif
if( p[1]&0x80 )
{
- msg_Dbg( p_demux, "transport_error_indicator set (pid=0x%x)",
+ msg_Dbg( p_demux, "transport_error_indicator set (pid=%d)",
pid->i_pid );
}
{
if( p[5]&0x80 )
{
- msg_Warn( p_demux, "discontinuity_indicator (pid=0x%x) "
+ msg_Warn( p_demux, "discontinuity_indicator (pid=%d) "
"ignored", pid->i_pid );
}
}
{
if( pid->i_cc == 0xff )
{
- msg_Warn( p_demux, "first packet for pid=0x%x cc=0x%x",
+ msg_Warn( p_demux, "first packet for pid=%d cc=0x%x",
pid->i_pid, i_cc );
pid->i_cc = i_cc;
}
** libdvbpsi callbacks
****************************************************************************
****************************************************************************/
+static vlc_bool_t DVBProgramIsSelected( demux_t *p_demux, uint16_t i_pgrm )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ if ( !p_sys->b_dvb_control ) return VLC_FALSE;
+ if ( p_sys->i_dvb_program == -1 && p_sys->p_programs_list == NULL )
+ return VLC_TRUE;
+ if ( p_sys->i_dvb_program == i_pgrm ) return VLC_TRUE;
+
+ if ( p_sys->p_programs_list != NULL )
+ {
+ int i;
+ for ( i = 0; i < p_sys->p_programs_list->i_count; i++ )
+ {
+ if ( i_pgrm == p_sys->p_programs_list->p_values[i].i_int )
+ return VLC_TRUE;
+ }
+ }
+ return VLC_FALSE;
+}
+
static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
{
demux_sys_t *p_sys = p_demux->p_sys;
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;
- /* CA descriptor */
- uint16_t i_vpid = 0, i_apid1 = 0, i_apid2 = 0, i_apid3 = 0;
-
msg_Dbg( p_demux, "PMTCallBack called" );
/* First find this PMT declared in PAT */
if( pid->b_valid && pid->p_owner == pmt->psi &&
pid->i_owner_number == prg->i_number && pid->psi == NULL )
{
- if( p_sys->b_dvb_control && ( p_sys->i_dvb_program < 0 ||
- p_sys->i_dvb_program == prg->i_number ) )
- {
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, i, VLC_FALSE );
- }
-
TAB_APPEND( i_clean, pp_clean, pid );
}
}
IODFree( prg->iod );
prg->iod = NULL;
}
- for ( i = 0; i < prg->i_nb_cad; i++ )
- free( prg->cad[i] );
- prg->i_nb_cad = 0;
+ 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=0x%x",
+ 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 );
prg->i_pid_pcr = p_pmt->i_pcr_pid;
prg->i_version = p_pmt->i_version;
+ if( DVBProgramIsSelected( p_demux, prg->i_number ) )
+ {
+ /* Set demux filter */
+ stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
+ ACCESS_SET_PRIVATE_ID_STATE, prg->i_pid_pcr,
+ VLC_TRUE );
+ }
+ else if ( p_sys->b_dvb_control )
+ {
+ msg_Warn( p_demux, "skipping program (not selected)" );
+ dvbpsi_DeletePMT(p_pmt);
+ return;
+ }
+
/* Parse descriptor */
for( p_dr = p_pmt->p_first_descriptor; p_dr != NULL; p_dr = p_dr->p_next )
{
else if( p_dr->i_tag == 0x9 )
{
msg_Dbg( p_demux, " * descriptor : CA (0x9)" );
-
- prg->cad[prg->i_nb_cad] = malloc( p_dr->i_length + 2 );
- prg->cad[prg->i_nb_cad][0] = 0x9;
- prg->cad[prg->i_nb_cad][1] = p_dr->i_length;
- memcpy( prg->cad[prg->i_nb_cad] + 2, p_dr->p_data, p_dr->i_length );
- prg->i_cad_length[prg->i_nb_cad] = p_dr->i_length + 2;
- prg->i_nb_cad++;
+ i_cad_length += p_dr->i_length + 2;
}
else
{
}
}
+ 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 << 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 )
+ {
+ 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;
if( !old_pid && p_sys->pid[p_es->i_pid].b_valid )
{
- msg_Warn( p_demux, "pmt error: pid=0x%x already defined",
+ msg_Warn( p_demux, "pmt error: pid=%d already defined",
p_es->i_pid );
continue;
}
pid->i_pid = p_es->i_pid;
pid->b_seen = p_sys->pid[p_es->i_pid].b_seen;
- if ( pid->es->fmt.i_cat == VIDEO_ES && !i_vpid )
- i_vpid = p_es->i_pid;
- if ( pid->es->fmt.i_cat == AUDIO_ES && !i_apid1 )
- i_apid1 = p_es->i_pid;
- else if ( pid->es->fmt.i_cat == AUDIO_ES && !i_apid2 )
- i_apid2 = p_es->i_pid;
- else if ( pid->es->fmt.i_cat == AUDIO_ES && !i_apid3 )
- i_apid3 = p_es->i_pid;
-
if( p_es->i_type == 0x10 || p_es->i_type == 0x11 ||
p_es->i_type == 0x12 )
{
if( p_dr && p_dr->i_length == 2 )
{
- int i;
int i_es_id = ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1];
msg_Warn( p_demux, "found SL_descriptor es_id=%d", i_es_id );
for( p_dr = p_es->p_first_descriptor; p_dr != NULL;
p_dr = p_dr->p_next )
{
- msg_Dbg( p_demux, " * es pid=0x%x type=0x%x dr->i_tag=0x%x",
+ msg_Dbg( p_demux, " * es pid=%d type=%d dr->i_tag=0x%x",
p_es->i_pid, p_es->i_type, p_dr->i_tag );
if( p_dr->i_tag == 0x6a )
msg_Dbg( p_demux, " * Teletext descriptor" );
pid->es->fmt.i_cat = SPU_ES;
pid->es->fmt.i_codec = VLC_FOURCC( 't', 'e', 'l', 'x' );
+ pid->es->fmt.i_extra = p_dr->i_length;
+ pid->es->fmt.p_extra = malloc( p_dr->i_length );
+ memcpy( pid->es->fmt.p_extra, p_dr->p_data,
+ p_dr->i_length );
}
#ifdef _DVBPSI_DR_59_H_
else if( p_dr->i_tag == 0x59 )
pid->es->fmt.i_group = p_pmt->i_program_number;
if( pid->es->fmt.i_cat == UNKNOWN_ES )
{
- msg_Dbg( p_demux, " * es pid=0x%x type=0x%x *unknown*",
+ msg_Dbg( p_demux, " * es pid=%d type=%d *unknown*",
p_es->i_pid, p_es->i_type );
}
else if( !p_sys->b_udp_out )
{
- int i;
-
- msg_Dbg( p_demux, " * es pid=0x%x type=0x%x fcc=%4.4s",
+ msg_Dbg( p_demux, " * es pid=%d type=%d fcc=%4.4s",
p_es->i_pid, p_es->i_type, (char*)&pid->es->fmt.i_codec );
if( p_sys->b_es_id_pid ) pid->es->fmt.i_id = p_es->i_pid;
}
}
+ i_cad_length = 0;
/* Add ES to the list */
if( old_pid )
{
if( p_dr->i_tag == 0x9 )
{
msg_Dbg( p_demux, " * descriptor : CA (0x9)" );
-
- prg->cad[prg->i_nb_cad] = malloc( p_dr->i_length + 2 );
- prg->cad[prg->i_nb_cad][0] = 0x9;
- prg->cad[prg->i_nb_cad][1] = p_dr->i_length;
- memcpy( prg->cad[prg->i_nb_cad] + 2, p_dr->p_data,
- p_dr->i_length );
- prg->i_cad_length[prg->i_nb_cad] = p_dr->i_length + 2;
- prg->i_nb_cad++;
+ i_cad_length += p_dr->i_length + 2;
}
else
{
}
}
- if( p_sys->b_dvb_control && ( p_sys->i_dvb_program < 0 ||
- p_sys->i_dvb_program == prg->i_number ) )
+ 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 << 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 )
+ {
+ 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 ) )
{
/* Set demux filter */
stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
dvbpsi_DeletePMT( p_pmt );
- for( i = 0; i < i_clean; i++ ) PIDClean( p_demux->out, pp_clean[i] );
- if( i_clean ) free( pp_clean );
-
- if( p_sys->b_dvb_control &&
- ( p_sys->i_dvb_program < 0 || p_sys->i_dvb_program == prg->i_number ) )
+ for ( i = 0; i < i_clean; i++ )
{
- /* Set CAM descrambling */
- for ( i = 0; i < prg->i_nb_cad; i++ )
+ if( DVBProgramIsSelected( p_demux, prg->i_number ) )
{
stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_CA, prg->i_number,
- i_vpid, i_apid1, i_apid2, i_apid3,
- prg->i_cad_length[i], prg->cad[i] );
+ ACCESS_SET_PRIVATE_ID_STATE, pp_clean[i]->i_pid,
+ VLC_FALSE );
}
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_CA, prg->i_number,
- 0, 0, 0, 0, 0, NULL );
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_CA, 0,
- 0, 0, 0, 0, 0, NULL );
+
+ 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 );
}
}
return;
}
- msg_Dbg( p_demux, "new PAT ts_id=0x%x version=%d current_next=%d",
+ msg_Dbg( p_demux, "new PAT ts_id=%d version=%d current_next=%d",
p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
/* Clean old */
for( p_program = p_pat->p_first_program; p_program != NULL;
p_program = p_program->p_next )
{
- msg_Dbg( p_demux, " * number=%d pid=0x%x", p_program->i_number,
+ msg_Dbg( p_demux, " * number=%d pid=%d", p_program->i_number,
p_program->i_pid );
if( p_program->i_number != 0 )
{
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 );
+ }
+}