# include "config.h"
#endif
-#include <vlc/vlc.h>
+#include <limits.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
#include <vlc_sout.h>
#include <vlc_codecs.h>
#include <vlc_block.h>
-#include "iso_lang.h"
+#include <vlc_iso_lang.h>
#include "bits.h"
#include "pes.h"
* if they arrive a bit late
* (We cannot rely on the fact that the fifo should be full)
*/
+
+/*****************************************************************************
+ * Callback prototypes
+ *****************************************************************************/
+static int ChangeKeyCallback ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
+static int ActiveKeyCallback ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
+
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#define CK_LONGTEXT N_("CSA encryption key. This must be a " \
"16 char string (8 hexadecimal bytes).")
+#define CK2_TEXT N_("Second CSA Key")
+#define CK2_LONGTEXT N_("The even CSA encryption key. This must be a " \
+ "16 char string (8 hexadecimal bytes).")
+
+#define CU_TEXT N_("CSA Key in use")
+#define CU_LONGTEXT N_("CSA encryption key used. It can be the odd/first/1 " \
+ "(default) or the even/second/2 one.")
+
#define CPKT_TEXT N_("Packet size in bytes to encrypt")
#define CPKT_LONGTEXT N_("Size of the TS packet to encrypt. " \
"The encryption routines subtract the TS-header from the value before " \
#endif
#define MAX_PMT_PID 64 /* Maximum pids in each pmt. FIXME: I just chose an arbitary number. Where is the maximum in the spec? */
-vlc_module_begin();
- set_description( _("TS muxer (libdvbpsi)") );
- set_shortname( "MPEG-TS");
- set_category( CAT_SOUT );
- set_subcategory( SUBCAT_SOUT_MUX );
- set_capability( "sout mux", 120 );
- add_shortcut( "ts" );
+vlc_module_begin ()
+ set_description( N_("TS muxer (libdvbpsi)") )
+ set_shortname( "MPEG-TS")
+ set_category( CAT_SOUT )
+ set_subcategory( SUBCAT_SOUT_MUX )
+ set_capability( "sout mux", 120 )
+ add_shortcut( "ts" )
add_integer( SOUT_CFG_PREFIX "pid-video", 0, NULL,VPID_TEXT, VPID_LONGTEXT,
- true );
+ true )
add_integer( SOUT_CFG_PREFIX "pid-audio", 0, NULL, APID_TEXT,
- APID_LONGTEXT, true );
+ APID_LONGTEXT, true )
add_integer( SOUT_CFG_PREFIX "pid-spu", 0, NULL, SPUPID_TEXT,
- SPUPID_LONGTEXT, true );
+ SPUPID_LONGTEXT, true )
add_integer( SOUT_CFG_PREFIX "pid-pmt", 0, NULL, PMTPID_TEXT,
- PMTPID_LONGTEXT, true );
+ PMTPID_LONGTEXT, true )
add_integer( SOUT_CFG_PREFIX "tsid", 0, NULL, TSID_TEXT,
- TSID_LONGTEXT, true );
+ TSID_LONGTEXT, true )
#ifdef HAVE_DVBPSI_SDT
add_integer( SOUT_CFG_PREFIX "netid", 0, NULL, NETID_TEXT,
- NETID_LONGTEXT, true );
+ NETID_LONGTEXT, true )
#endif
add_string( SOUT_CFG_PREFIX "program-pmt", NULL, NULL, PMTPROG_TEXT,
- PMTPROG_LONGTEXT, true );
+ PMTPROG_LONGTEXT, true )
add_bool( SOUT_CFG_PREFIX "es-id-pid", 0, NULL, PID_TEXT, PID_LONGTEXT,
- true );
- add_string( SOUT_CFG_PREFIX "muxpmt", NULL, NULL, MUXPMT_TEXT, MUXPMT_LONGTEXT, true );
+ true )
+ add_string( SOUT_CFG_PREFIX "muxpmt", NULL, NULL, MUXPMT_TEXT, MUXPMT_LONGTEXT, true )
#ifdef HAVE_DVBPSI_SDT
- add_string( SOUT_CFG_PREFIX "sdtdesc", NULL, NULL, SDTDESC_TEXT, SDTDESC_LONGTEXT, true );
+ add_string( SOUT_CFG_PREFIX "sdtdesc", NULL, NULL, SDTDESC_TEXT, SDTDESC_LONGTEXT, true )
#endif
add_bool( SOUT_CFG_PREFIX "alignment", true, NULL, ALIGNMENT_TEXT,
- ALIGNMENT_LONGTEXT, true );
+ ALIGNMENT_LONGTEXT, true )
add_integer( SOUT_CFG_PREFIX "shaping", 200, NULL, SHAPING_TEXT,
- SHAPING_LONGTEXT, true );
+ SHAPING_LONGTEXT, true )
add_bool( SOUT_CFG_PREFIX "use-key-frames", false, NULL, KEYF_TEXT,
- KEYF_LONGTEXT, true );
+ KEYF_LONGTEXT, true )
add_integer( SOUT_CFG_PREFIX "pcr", 70, NULL, PCR_TEXT, PCR_LONGTEXT,
- true );
+ true )
add_integer( SOUT_CFG_PREFIX "bmin", 0, NULL, BMIN_TEXT, BMIN_LONGTEXT,
- true );
+ true )
add_integer( SOUT_CFG_PREFIX "bmax", 0, NULL, BMAX_TEXT, BMAX_LONGTEXT,
- true );
+ true )
add_integer( SOUT_CFG_PREFIX "dts-delay", 400, NULL, DTS_TEXT,
- DTS_LONGTEXT, true );
+ DTS_LONGTEXT, true )
add_bool( SOUT_CFG_PREFIX "crypt-audio", true, NULL, ACRYPT_TEXT,
- ACRYPT_LONGTEXT, true );
+ ACRYPT_LONGTEXT, true )
add_bool( SOUT_CFG_PREFIX "crypt-video", true, NULL, VCRYPT_TEXT,
- VCRYPT_LONGTEXT, true );
+ VCRYPT_LONGTEXT, true )
add_string( SOUT_CFG_PREFIX "csa-ck", NULL, NULL, CK_TEXT, CK_LONGTEXT,
- true );
- add_integer( SOUT_CFG_PREFIX "csa-pkt", 188, NULL, CPKT_TEXT, CPKT_LONGTEXT, true );
+ true )
+ add_string( SOUT_CFG_PREFIX "csa2-ck", NULL, NULL, CK2_TEXT, CK2_LONGTEXT,
+ true )
+ add_string( SOUT_CFG_PREFIX "csa-use", "1", NULL, CU_TEXT, CU_LONGTEXT,
+ true )
+ add_integer( SOUT_CFG_PREFIX "csa-pkt", 188, NULL, CPKT_TEXT, CPKT_LONGTEXT, true )
- set_callbacks( Open, Close );
-vlc_module_end();
+ set_callbacks( Open, Close )
+vlc_module_end ()
/*****************************************************************************
* Local data structures
*****************************************************************************/
-static const char *ppsz_sout_options[] = {
+static const char *const ppsz_sout_options[] = {
"pid-video", "pid-audio", "pid-spu", "pid-pmt", "tsid", "netid",
"es-id-pid", "shaping", "pcr", "bmin", "bmax", "use-key-frames",
- "dts-delay", "csa-ck", "csa-pkt", "crypt-audio", "crypt-video",
+ "dts-delay", "csa-ck", "csa2-ck", "csa-use", "csa-pkt", "crypt-audio", "crypt-video",
"muxpmt", "sdtdesc", "program-pmt", "alignment",
NULL
};
int i_pcr_pid;
sout_input_t *p_pcr_input;
+ vlc_mutex_t csa_lock;
+
int i_audio_bound;
int i_video_bound;
p_sys->dvbpmt = NULL;
memset( &p_sys->pmtmap, 0, sizeof(p_sys->pmtmap) );
+ vlc_mutex_init( &p_sys->csa_lock );
+
p_mux->pf_control = Control;
p_mux->pf_addstream = AddStream;
p_mux->pf_delstream = DelStream;
p_sys->i_pcr = 0;
p_sys->csa = NULL;
+ var_Create( p_mux, SOUT_CFG_PREFIX "csa-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
var_Get( p_mux, SOUT_CFG_PREFIX "csa-ck", &val );
if( val.psz_string && *val.psz_string )
{
- char *psz = val.psz_string;
+ int i_res;
+ vlc_value_t csa2;
- /* skip 0x */
- if( psz[0] == '0' && ( psz[1] == 'x' || psz[1] == 'X' ) )
+ p_sys->csa = csa_New();
+
+ var_Create( p_mux, SOUT_CFG_PREFIX "csa2-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
+ var_Get( p_mux, SOUT_CFG_PREFIX "csa2-ck", &csa2 );
+ i_res = csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, val.psz_string, true );
+ if( i_res == VLC_SUCCESS && csa2.psz_string && *csa2.psz_string )
{
- psz += 2;
+ if( csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, csa2.psz_string, false ) != VLC_SUCCESS )
+ {
+ csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, val.psz_string, false );
+ }
}
- if( strlen( psz ) != 16 )
+ else if( i_res == VLC_SUCCESS )
{
- msg_Dbg( p_mux, "invalid csa ck (it must be 16 chars long)" );
+ csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, val.psz_string, false );
}
else
{
- uint64_t i_ck = strtoull( psz, NULL, 16 );
- uint8_t ck[8];
- int i;
+ csa_Delete( p_sys->csa );
+ p_sys->csa = NULL;
+ }
+
+ if( p_sys->csa )
+ {
+ vlc_value_t use_val, pkt_val;
+
+ var_Create( p_mux, SOUT_CFG_PREFIX "csa-use", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
+ var_Get( p_mux, SOUT_CFG_PREFIX "csa-use", &use_val );
+ var_AddCallback( p_mux, SOUT_CFG_PREFIX "csa-use", ActiveKeyCallback, NULL );
+ var_AddCallback( p_mux, SOUT_CFG_PREFIX "csa-ck", ChangeKeyCallback, (void *)1 );
+ var_AddCallback( p_mux, SOUT_CFG_PREFIX "csa2-ck", ChangeKeyCallback, NULL );
- for( i = 0; i < 8; i++ )
+ if ( var_Set( p_mux, SOUT_CFG_PREFIX "csa-use", use_val ) != VLC_SUCCESS )
{
- ck[i] = ( i_ck >> ( 56 - 8*i) )&0xff;
+ var_SetString( p_mux, SOUT_CFG_PREFIX "csa-use", "odd" );
}
-#ifndef TS_NO_CSA_CK_MSG
- msg_Dbg( p_mux, "using CSA scrambling with ck=%x:%x:%x:%x:%x:%x:%x:%x",
- ck[0], ck[1], ck[2], ck[3], ck[4], ck[5], ck[6], ck[7] );
-#endif
- p_sys->csa = csa_New();
- if( p_sys->csa )
- {
- vlc_value_t pkt_val;
-
- csa_SetCW( p_sys->csa, ck, ck );
+ free( use_val.psz_string );
- var_Get( p_mux, SOUT_CFG_PREFIX "csa-pkt", &pkt_val );
- if( pkt_val.i_int < 12 || pkt_val.i_int > 188 )
- {
- msg_Err( p_mux, "wrong packet size %d specified.", pkt_val.i_int );
- msg_Warn( p_mux, "using default packet size of 188 bytes" );
- p_sys->i_csa_pkt_size = 188;
- }
- else p_sys->i_csa_pkt_size = pkt_val.i_int;
- msg_Dbg( p_mux, "encrypting %d bytes of packet", p_sys->i_csa_pkt_size );
+ var_Get( p_mux, SOUT_CFG_PREFIX "csa-pkt", &pkt_val );
+ if( pkt_val.i_int < 12 || pkt_val.i_int > 188 )
+ {
+ msg_Err( p_mux, "wrong packet size %d specified.", pkt_val.i_int );
+ msg_Warn( p_mux, "using default packet size of 188 bytes" );
+ p_sys->i_csa_pkt_size = 188;
}
+ else p_sys->i_csa_pkt_size = pkt_val.i_int;
+ msg_Dbg( p_mux, "encrypting %d bytes of packet", p_sys->i_csa_pkt_size );
}
+ free( csa2.psz_string );
}
free( val.psz_string );
sout_mux_sys_t *p_sys = p_mux->p_sys;
int i;
+ vlc_mutex_lock( &p_sys->csa_lock );
if( p_sys->csa )
{
+ var_DelCallback( p_mux, SOUT_CFG_PREFIX "csa-ck", ChangeKeyCallback, NULL );
+ var_DelCallback( p_mux, SOUT_CFG_PREFIX "csa2-ck", ChangeKeyCallback, NULL );
+ var_DelCallback( p_mux, SOUT_CFG_PREFIX "csa-use", ActiveKeyCallback, NULL );
csa_Delete( p_sys->csa );
+ p_sys->csa = NULL;
}
+ vlc_mutex_unlock( &p_sys->csa_lock );
+
for( i = 0; i < MAX_PMT; i++ )
{
free( p_sys->sdt_descriptors[i].psz_service_name );
free( p_sys->sdt_descriptors[i].psz_provider );
}
+ vlc_mutex_destroy( &p_sys->csa_lock );
free( p_sys->dvbpmt );
free( p_sys );
}
+/*****************************************************************************
+ * ChangeKeyCallback: called when changing the odd encryption key on the fly.
+ *****************************************************************************/
+static int ChangeKeyCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data )
+{
+ VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
+ sout_mux_t *p_mux = (sout_mux_t*)p_this;
+ sout_mux_sys_t *p_sys = p_mux->p_sys;
+ int ret;
+
+ vlc_mutex_lock( &p_sys->csa_lock );
+ ret = csa_SetCW( p_this, p_sys->csa, newval.psz_string,
+ !!(intptr_t)p_data );
+ vlc_mutex_unlock( &p_sys->csa_lock );
+
+ return ret;
+}
+
+/*****************************************************************************
+ * ActiveKeyCallback: called when changing the active (in use) encryption key on the fly.
+ *****************************************************************************/
+static int ActiveKeyCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data )
+{
+ VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
+ sout_mux_t *p_mux = (sout_mux_t*)p_this;
+ sout_mux_sys_t *p_sys = p_mux->p_sys;
+ int i_res = VLC_EBADVAR;
+
+ vlc_mutex_lock( &p_sys->csa_lock );
+ if( !strcmp(newval.psz_string, "odd" ) || !strcmp(newval.psz_string, "first" ) || !strcmp(newval.psz_string, "1" ) )
+ {
+ i_res = csa_UseKey( (vlc_object_t*)p_mux, p_sys->csa, 1 );
+ }
+ else if( !strcmp(newval.psz_string, "even" ) || !strcmp(newval.psz_string, "second" ) || !strcmp(newval.psz_string, "2" ) )
+ {
+ i_res = csa_UseKey( (vlc_object_t*)p_mux, p_sys->csa, 0 );
+ }
+ vlc_mutex_unlock( &p_sys->csa_lock );
+
+ return i_res;
+}
+
/*****************************************************************************
* Control:
*****************************************************************************/
p_stream->i_bih_width = p_input->p_fmt->video.i_width;
p_stream->i_bih_height = p_input->p_fmt->video.i_height;
break;
+ case VLC_FOURCC( 'd', 'r', 'a', 'c' ):
+ /* stream_id makes use of stream_id_extension */
+ p_stream->i_stream_id = (PES_EXTENDED_STREAM_ID << 8) | 0x60;
+ p_stream->i_stream_type = 0xd1;
+ break;
default:
free( p_stream );
return VLC_EGENERIC;
else
{
int i_header_size = 0;
+ int i_max_pes_size = 0;
int b_data_alignment = 0;
if( p_input->p_fmt->i_cat == SPU_ES )
{
p_spu->p_buffer[1] = 1;
p_spu->p_buffer[2] = ' ';
- E_(EStoPES)( p_mux->p_sout, &p_spu, p_spu,
+ EStoPES( p_mux->p_sout, &p_spu, p_spu,
p_input->p_fmt,
p_stream->i_stream_id, 1,
0, 0, 0 );
p_data->i_pts = p_data->i_dts;
}
- E_( EStoPES )( p_mux->p_sout, &p_data, p_data,
+ if( p_input->p_fmt->i_codec ==
+ VLC_FOURCC('d','r','a','c') )
+ {
+ b_data_alignment = 1;
+ /* dirac pes packets should be unbounded in
+ * length, specify a suitibly large max size */
+ i_max_pes_size = INT_MAX;
+ }
+
+ EStoPES ( p_mux->p_sout, &p_data, p_data,
p_input->p_fmt, p_stream->i_stream_id,
- 1, b_data_alignment, i_header_size, 0 );
+ 1, b_data_alignment, i_header_size,
+ i_max_pes_size );
BufferChainAppend( &p_stream->chain_pes, p_data );
else if( i_size > STD_PES_PAYLOAD )
{
block_t *p_new = block_New( p_mux, STD_PES_PAYLOAD );
- p_mux->p_libvlc->pf_memcpy( p_new->p_buffer, p_data->p_buffer, STD_PES_PAYLOAD );
+ vlc_memcpy( p_new->p_buffer, p_data->p_buffer, STD_PES_PAYLOAD );
p_new->i_pts = p_data->i_pts;
p_new->i_dts = p_data->i_dts;
p_new->i_length = p_data->i_length * STD_PES_PAYLOAD
}
i_copy = __MIN( STD_PES_PAYLOAD - i_size, p_next->i_buffer );
- p_mux->p_libvlc->pf_memcpy( &p_data->p_buffer[i_size], p_next->p_buffer,
- i_copy );
+ vlc_memcpy( &p_data->p_buffer[i_size], p_next->p_buffer, i_copy );
p_next->i_pts += p_next->i_length * i_copy / p_next->i_buffer;
p_next->i_dts += p_next->i_length * i_copy / p_next->i_buffer;
p_next->i_length -= p_next->i_length * i_copy / p_next->i_buffer;
}
if( p_ts->i_flags & BLOCK_FLAG_SCRAMBLED )
{
- csa_Encrypt( p_sys->csa, p_ts->p_buffer, p_sys->i_csa_pkt_size, 0 );
+ vlc_mutex_lock( &p_sys->csa_lock );
+ csa_Encrypt( p_sys->csa, p_ts->p_buffer, p_sys->i_csa_pkt_size );
+ vlc_mutex_unlock( &p_sys->csa_lock );
}
/* latency */
bits_write( &bits, 8, 0x21 ); /* Visual 14496-2 */
bits_write( &bits, 6, 0x04 ); /* VisualStream */
}
- else if( p_stream->i_stream_type == 0x11 || p_stream->i_stream_type == 0x0f )
+ else if( p_stream->i_stream_type == 0x11 ||
+ p_stream->i_stream_type == 0x0f )
{
bits_write( &bits, 8, 0x40 ); /* Audio 14496-3 */
bits_write( &bits, 6, 0x05 ); /* AudioStream */
/* "registration" descriptor : "AC-3" */
dvbpsi_PMTESAddDescriptor( p_es, 0x05, 4, format );
}
+ else if( p_stream->i_codec == VLC_FOURCC('d','r','a','c') )
+ {
+ /* Dirac registration descriptor */
+
+ uint8_t data[4] = { 'd', 'r', 'a', 'c' };
+ dvbpsi_PMTESAddDescriptor( p_es, 0x05, 4, data );
+ }
else if( p_stream->i_codec == VLC_FOURCC('d','t','s',' ') )
{
/* DTS registration descriptor (ETSI TS 101 154 Annex F) */