[dvblast-devel] [PATCH] Add support for ECM and EMM passthrough

Georgi Chorbadzhiyski gf at unixsol.org
Wed Jun 8 16:49:07 CEST 2011


Around 06/07/2011 11:42 PM, Christophe Massiot scribbled:
> Le 6 juin 2011 à 21:27, Georgi Chorbadzhiyski a écrit :
> 
>> The attached patch adds support for two new options -M and -C
>> that allow EMM and ECM pass through. The patch is against dvblast
>> 1.2 because that is what I were using. I'll send patch against
>> trunk tomorrow.
> 
> You'll see that the trunk no longer relies on libdvbpsi but instead on biTStream. biTStream doesn't support CAT yet, but it shouldn't be difficult to implement, and patches are welcome.

Attached are patches against dvbpsi-trunk (r190) and biTStream
that implement EMM and ECM pass through. Unfortunately in trunk
-M and -C options are taken, so the new option that activate
EMM pass through is -W and the new option for ECM pass through
is -Y.

biTSstream CAT support is a little different than other tables,
because without allocations standard descriptor functions can't
be used.

Future development will be per output ECM/EMM support. Right now
emm/noemm/ecm/noecm keywords are parsed in output config but are
not used for anything.

-- 
Georgi Chorbadzhiyski
http://georgi.unixsol.org/
-------------- next part --------------
commit e9569f214047945fa05e6bacc56714862d3ecf34
Author: Georgi Chorbadzhiyski <gf at unixsol.org>
Date:   Wed Jun 8 17:34:02 2011 +0300

    Add support for Conditional Access table

diff --git a/mpeg/psi.h b/mpeg/psi.h
index ab59eda..18cd4dd 100644
--- a/mpeg/psi.h
+++ b/mpeg/psi.h
@@ -967,6 +967,88 @@ static inline void pat_table_print(uint8_t **pp_sections, f_print pf_print,
 }
 
 /*****************************************************************************
+ * Conditional Access Table
+ *****************************************************************************/
+#define CAT_PID                 0x01
+#define CAT_TABLE_ID            0x01
+#define CAT_HEADER_SIZE         PSI_HEADER_SIZE_SYNTAX1
+
+static inline void cat_init(uint8_t *p_cat)
+{
+    psi_init(p_cat, true);
+    psi_set_tableid(p_cat, CAT_TABLE_ID);
+    p_cat[1] &= ~0x40;
+    psi_set_section(p_cat, 0);
+    psi_set_lastsection(p_cat, 0);
+}
+
+static inline void cat_set_length(uint8_t *p_cat, uint16_t i_cat_length)
+{
+    psi_set_length(p_cat, CAT_HEADER_SIZE + PSI_CRC_SIZE - PSI_HEADER_SIZE
+                    + i_cat_length);
+}
+
+static inline uint16_t cat_get_desclength(const uint8_t *p_cat)
+{
+    return psi_get_length(p_cat) - (CAT_HEADER_SIZE + PSI_CRC_SIZE - PSI_HEADER_SIZE);
+}
+
+static inline uint8_t *cat_alloc_descs(uint8_t *p_cat)
+{
+    uint16_t i_desc_len = cat_get_desclength(p_cat);
+    uint8_t *p_buf = malloc(i_desc_len + 2);
+    if (!p_buf)
+        return NULL;
+
+    memcpy(p_buf + 2, p_cat + 8, i_desc_len);
+    descs_set_length(p_buf, i_desc_len);
+
+    return p_buf;
+}
+
+static inline void cat_free_descs(uint8_t *p_cat_descs)
+{
+    free(p_cat_descs);
+}
+
+static inline bool cat_validate(const uint8_t *p_cat)
+{
+    uint16_t i_section_size = psi_get_length(p_cat) + PSI_HEADER_SIZE
+                               - PSI_CRC_SIZE;
+    const uint8_t *p_cat_n;
+
+    if (!psi_get_syntax(p_cat) || psi_get_section(p_cat)
+         || psi_get_lastsection(p_cat)
+         || psi_get_tableid(p_cat) != CAT_TABLE_ID)
+        return false;
+
+    if (!psi_check_crc(p_cat))
+        return false;
+
+    if (i_section_size < CAT_HEADER_SIZE
+         || i_section_size < CAT_HEADER_SIZE + cat_get_desclength(p_cat))
+        return false;
+
+    return true;
+}
+
+static inline bool cat_table_validate(uint8_t **pp_sections)
+{
+    uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
+    uint8_t i;
+
+    for (i = 0; i <= i_last_section; i++) {
+        uint8_t *p_section = psi_table_get_section(pp_sections, i);
+        int j = 0;
+
+        if (!psi_check_crc(p_section))
+            return false;
+    }
+
+    return true;
+}
+
+/*****************************************************************************
  * Program Map Table
  *****************************************************************************/
 #define PMT_TABLE_ID            0x2
diff --git a/mpeg/psi_print.h b/mpeg/psi_print.h
index 2f482a2..1f3063f 100644
--- a/mpeg/psi_print.h
+++ b/mpeg/psi_print.h
@@ -32,6 +32,45 @@ extern "C"
 #endif
 
 /*****************************************************************************
+ * Conditional Access Table
+ *****************************************************************************/
+static inline void cat_table_print(uint8_t **pp_sections, f_print pf_print,
+                                   void *opaque, print_type_t i_print_type)
+{
+    uint8_t i_last_section = psi_table_get_lastsection(pp_sections);
+    uint8_t i;
+
+    switch (i_print_type) {
+    case PRINT_XML:
+        pf_print(opaque, "<CAT version=\"%hhu\" current_next=\"%d\">",
+                 psi_table_get_version(pp_sections),
+                 !psi_table_get_current(pp_sections) ? 0 : 1);
+        break;
+    default:
+        pf_print(opaque, "new CAT version=%hhu%s",
+                 psi_table_get_version(pp_sections),
+                 !psi_table_get_current(pp_sections) ? " (next)" : "");
+    }
+
+    for (i = 0; i <= i_last_section; i++) {
+        uint8_t *p_section = psi_table_get_section(pp_sections, i);
+        uint8_t *p_descs = cat_alloc_descs(p_section);
+
+        descs_print(p_descs, pf_print, opaque, NULL, NULL, i_print_type);
+
+        cat_free_descs(p_descs);
+    }
+
+    switch (i_print_type) {
+    case PRINT_XML:
+        pf_print(opaque, "</CAT>");
+        break;
+    default:
+        pf_print(opaque, "end CAT");
+    }
+}
+
+/*****************************************************************************
  * Program Map Table
  *****************************************************************************/
 static inline void pmt_print(uint8_t *p_pmt,
-------------- next part --------------
commit 14b574150a138fb472ca9d695ea7a54a39543087
Author: Georgi Chorbadzhiyski <gf at unixsol.org>
Date:   Wed Jun 8 17:30:21 2011 +0300

    Add support for EMM and ECM pass through in trunk

diff --git a/trunk/demux.c b/trunk/demux.c
index c1811be..68d290c 100644
--- a/trunk/demux.c
+++ b/trunk/demux.c
@@ -48,6 +48,9 @@
 #include <bitstream/dvb/si_print.h>
 #include <bitstream/mpeg/psi_print.h>
 
+extern bool b_enable_emm;
+extern bool b_enable_ecm;
+
 /*****************************************************************************
  * Local declarations
  *****************************************************************************/
@@ -61,6 +64,9 @@ typedef struct ts_pid_t
     bool b_pes;
     int8_t i_last_cc;
     int i_demux_fd;
+    /* b_emm is set to true when PID carries EMM packet
+       and should be outputed in all services */
+    bool b_emm;
 
     /* biTStream PSI section gathering */
     uint8_t *p_psi_buffer;
@@ -82,6 +88,8 @@ static int i_nb_sids = 0;
 
 static PSI_TABLE_DECLARE(pp_current_pat_sections);
 static PSI_TABLE_DECLARE(pp_next_pat_sections);
+static PSI_TABLE_DECLARE(pp_current_cat_sections);
+static PSI_TABLE_DECLARE(pp_next_cat_sections);
 static PSI_TABLE_DECLARE(pp_current_nit_sections);
 static PSI_TABLE_DECLARE(pp_next_nit_sections);
 static PSI_TABLE_DECLARE(pp_current_sdt_sections);
@@ -97,6 +105,7 @@ static mtime_t i_last_error = 0;
 static void demux_Handle( block_t *p_ts );
 static void SetDTS( block_t *p_list );
 static void SetPID( uint16_t i_pid );
+static void SetPID_EMM( uint16_t i_pid );
 static void UnsetPID( uint16_t i_pid );
 static void StartPID( output_t *p_output, uint16_t i_pid );
 static void StopPID( output_t *p_output, uint16_t i_pid );
@@ -145,6 +154,13 @@ void demux_Open( void )
     SetPID(PAT_PID);
     p_pids[PAT_PID].i_psi_refcount++;
 
+    if ( b_enable_emm ) {
+        psi_table_init( pp_current_cat_sections );
+        psi_table_init( pp_next_cat_sections );
+        SetPID_EMM(CAT_PID);
+        p_pids[CAT_PID].i_psi_refcount++;
+    }
+
     SetPID(NIT_PID);
     p_pids[NIT_PID].i_psi_refcount++;
 
@@ -292,6 +308,15 @@ static void demux_Handle( block_t *p_ts )
 
     p_pids[i_pid].i_last_cc = i_cc;
 
+    if ( b_enable_emm ) {
+        for ( i = 0; i < i_nb_outputs; i++ )
+        {
+            output_t *p_output = pp_outputs[i];
+            if ( p_output->config.i_config & OUTPUT_VALID && p_pids[i_pid].b_emm )
+                output_Put( p_output, p_ts );
+        }
+    }
+
     /* Output */
     for ( i = 0; i < p_pids[i_pid].i_nb_outputs; i++ )
     {
@@ -567,9 +592,16 @@ static void SetPID( uint16_t i_pid )
         p_pids[i_pid].i_demux_fd = pf_SetFilter( i_pid );
 }
 
+static void SetPID_EMM( uint16_t i_pid )
+{
+    SetPID( i_pid );
+    p_pids[i_pid].b_emm = true;
+}
+
 static void UnsetPID( uint16_t i_pid )
 {
     p_pids[i_pid].i_refcount--;
+    p_pids[i_pid].b_emm = false;
 
     if ( !b_budget_mode && !p_pids[i_pid].i_refcount
           && p_pids[i_pid].i_demux_fd != -1 )
@@ -1442,6 +1474,22 @@ void demux_ResendCAPMTs( void )
             en50221_AddPMT( pp_sids[i]->p_current_pmt );
 }
 
+/* Find CA descriptor that have PID i_ca_pid */
+static uint8_t *ca_desc_find( uint8_t *p_descs, uint16_t i_ca_pid )
+{
+    int j = 0;
+    uint8_t *p_desc;
+
+    while ( (p_desc = descs_get_desc( p_descs, j++ )) != NULL ) {
+        if ( desc_get_tag( p_desc ) != 0x09 || !desc09_validate( p_desc ) )
+            continue;
+        if ( desc09_get_pid( p_desc ) == i_ca_pid )
+            return p_desc;
+    }
+
+    return NULL;
+}
+
 /*****************************************************************************
  * DeleteProgram
  *****************************************************************************/
@@ -1473,6 +1521,19 @@ static void DeleteProgram( uint16_t i_sid, uint16_t i_pid )
                       && i_pcr_pid != p_sid->i_pmt_pid )
                     UnselectPID( i_sid, i_pcr_pid );
 
+                if ( b_enable_ecm )
+                {
+                    j = 0;
+                    uint8_t *p_desc;
+
+                    while ((p_desc = descs_get_desc( pmt_get_descs( p_pmt ), j++ )) != NULL)
+                    {
+                        if ( desc_get_tag( p_desc ) != 0x09 || !desc09_validate( p_desc ) )
+                            continue;
+                        UnselectPID( i_sid, desc09_get_pid( p_desc ) );
+                    }
+                }
+
                 j = 0;
                 while ( (p_es = pmt_get_es( p_pmt, j )) != NULL )
                 {
@@ -1756,6 +1817,171 @@ static void HandlePATSection( uint16_t i_pid, uint8_t *p_section,
 }
 
 /*****************************************************************************
+ * HandleCAT
+ *****************************************************************************/
+static void HandleCAT( mtime_t i_dts )
+{
+    bool b_display, b_change = false;
+    PSI_TABLE_DECLARE( pp_old_cat_sections );
+    uint8_t i_last_section = psi_table_get_lastsection( pp_next_cat_sections );
+    uint8_t i_last_section2;
+    uint8_t i, r;
+    uint8_t *p_desc;
+    int j, k;
+
+    if ( psi_table_validate( pp_current_cat_sections ) &&
+         psi_table_compare( pp_current_cat_sections, pp_next_cat_sections ) )
+    {
+        /* Identical CAT. Shortcut. */
+        psi_table_free( pp_next_cat_sections );
+        psi_table_init( pp_next_cat_sections );
+        goto out_cat;
+    }
+
+    if ( !cat_table_validate( pp_next_cat_sections ) )
+    {
+        msg_Warn( NULL, "invalid CAT received" );
+        switch (i_print_type) {
+        case PRINT_XML:
+            printf("<ERROR type=\"invalid_cat\"/>\n");
+            break;
+        default:
+            printf("invalid CAT received\n");
+        }
+        psi_table_free( pp_next_cat_sections );
+        psi_table_init( pp_next_cat_sections );
+        goto out_cat;
+    }
+
+    b_display = !psi_table_validate( pp_current_cat_sections )
+                 || psi_table_get_version( pp_current_cat_sections )
+                     != psi_table_get_version( pp_next_cat_sections );
+
+    /* Switch tables. */
+    psi_table_copy( pp_old_cat_sections, pp_current_cat_sections );
+    psi_table_copy( pp_current_cat_sections, pp_next_cat_sections );
+    psi_table_init( pp_next_cat_sections );
+
+    if ( !psi_table_validate( pp_old_cat_sections )
+          || psi_table_get_tableidext( pp_current_cat_sections )
+              != psi_table_get_tableidext( pp_old_cat_sections ) )
+    {
+        b_display = b_change = true;
+    }
+
+    if ( b_change )
+    {
+        for ( i = 0; i <= i_last_section; i++ )
+        {
+            uint8_t *p_section = psi_table_get_section( pp_current_cat_sections, i );
+
+            j = 0;
+            uint8_t *p_cat_descs = cat_alloc_descs( p_section );
+            while ( (p_desc = descs_get_desc( p_cat_descs, j++ )) != NULL )
+            {
+                if ( desc_get_tag( p_desc ) != 0x09 || !desc09_validate( p_desc ) )
+                    continue;
+
+                SetPID_EMM( desc09_get_pid( p_desc ) );
+            }
+            cat_free_descs( p_cat_descs );
+        }
+    }
+
+    if ( psi_table_validate( pp_old_cat_sections ) )
+    {
+        i_last_section = psi_table_get_lastsection( pp_old_cat_sections );
+        for ( i = 0; i <= i_last_section; i++ )
+        {
+            uint8_t *p_old_section = psi_table_get_section( pp_old_cat_sections, i );
+            j = 0;
+            uint8_t *p_old_cat_descs = cat_alloc_descs( p_old_section );
+            while ( (p_desc = descs_get_desc( p_old_cat_descs, j++ )) != NULL )
+            {
+                uint16_t emm_pid;
+                int pid_found = 0;
+
+                if ( desc_get_tag( p_desc ) != 0x09 || !desc09_validate( p_desc ) )
+                    continue;
+
+                emm_pid = desc09_get_pid( p_desc );
+
+                // Search in current sections if the pid exists
+                i_last_section2 = psi_table_get_lastsection( pp_current_cat_sections );
+                for ( r = 0; r <= i_last_section2; r++ )
+                {
+                    uint8_t *p_section = psi_table_get_section( pp_current_cat_sections, r );
+
+                    k = 0;
+                    uint8_t *p_cat_descs = cat_alloc_descs( p_section );
+                    while ( (p_desc = descs_get_desc( p_cat_descs, k++ )) != NULL )
+                    {
+                        if ( desc_get_tag( p_desc ) != 0x09 || !desc09_validate( p_desc ) )
+                            continue;
+                        if ( ca_desc_find( p_cat_descs, emm_pid ) != NULL )
+                        {
+                            pid_found = 1;
+                            break;
+                        }
+                    }
+                    cat_free_descs( p_cat_descs );
+                }
+
+                if ( !pid_found )
+                {
+                    UnsetPID(emm_pid);
+                    b_display = true;
+                }
+            }
+            cat_free_descs( p_old_cat_descs );
+        }
+
+        psi_table_free( pp_old_cat_sections );
+    }
+
+    if ( b_display )
+    {
+        cat_table_print( pp_current_cat_sections, msg_Dbg, NULL, PRINT_TEXT );
+        if ( i_print_type != -1 )
+        {
+            cat_table_print( pp_current_cat_sections, demux_Print, NULL,
+                             i_print_type );
+            if ( i_print_type == PRINT_XML )
+                printf("\n");
+        }
+    }
+
+out_cat:
+    return;
+}
+
+/*****************************************************************************
+ * HandleCATSection
+ *****************************************************************************/
+static void HandleCATSection( uint16_t i_pid, uint8_t *p_section,
+                              mtime_t i_dts )
+{
+    if ( i_pid != CAT_PID || !cat_validate( p_section ) )
+    {
+        msg_Warn( NULL, "invalid CAT section received on PID %hu", i_pid );
+        switch (i_print_type) {
+        case PRINT_XML:
+            printf("<ERROR type=\"invalid_cat_section\"/>\n");
+            break;
+        default:
+            printf("invalid CAT section received on PID %hu\n", i_pid);
+        }
+        free( p_section );
+        return;
+    }
+
+    if ( !psi_table_section( pp_next_cat_sections, p_section ) )
+        return;
+
+    HandleCAT( i_dts );
+}
+
+/*****************************************************************************
  * HandlePMT
  *****************************************************************************/
 static void HandlePMT( uint16_t i_pid, uint8_t *p_pmt, mtime_t i_dts )
@@ -1766,6 +1992,7 @@ static void HandlePMT( uint16_t i_pid, uint8_t *p_pmt, mtime_t i_dts )
     bool b_needs_descrambling, b_needed_descrambling, b_is_selected;
     uint16_t i_pcr_pid;
     uint8_t *p_es;
+    uint8_t *p_desc;
     int i;
     uint16_t j;
 
@@ -1836,6 +2063,16 @@ static void HandlePMT( uint16_t i_pid, uint8_t *p_pmt, mtime_t i_dts )
                         || psi_get_version( p_sid->p_current_pmt )
                             != psi_get_version( p_pmt );
 
+    if ( b_enable_ecm && b_new ) {
+        j = 0;
+        while ( (p_desc = descs_get_desc( pmt_get_descs( p_pmt ), j++ )) != NULL )
+        {
+            if ( desc_get_tag( p_desc ) != 0x09 || !desc09_validate( p_desc ) )
+                continue;
+            SelectPID( i_sid, desc09_get_pid( p_desc ) );
+        }
+    }
+
     if ( p_sid->p_current_pmt == NULL
           || i_pcr_pid != pmt_get_pcrpid( p_sid->p_current_pmt ) )
     {
@@ -1864,6 +2101,18 @@ static void HandlePMT( uint16_t i_pid, uint8_t *p_pmt, mtime_t i_dts )
 
     if ( p_sid->p_current_pmt != NULL )
     {
+        if ( b_enable_ecm )
+        {
+            j = 0;
+            while ((p_desc = descs_get_desc( pmt_get_descs( p_sid->p_current_pmt ), j++ )) != NULL)
+            {
+                if ( desc_get_tag( p_desc ) != 0x09 || !desc09_validate( p_desc ) )
+                    continue;
+                if ( ca_desc_find( pmt_get_descs( p_pmt ), desc09_get_pid( p_desc ) ) == NULL )
+                    UnselectPID( i_sid, desc09_get_pid( p_desc ) );
+            }
+        }
+
         uint16_t i_current_pcr_pid = pmt_get_pcrpid( p_sid->p_current_pmt );
         if ( i_current_pcr_pid != i_pcr_pid
               && i_current_pcr_pid != PADDING_PID )
@@ -2221,6 +2470,11 @@ static void HandleSection( uint16_t i_pid, uint8_t *p_section, mtime_t i_dts )
         HandlePATSection( i_pid, p_section, i_dts );
         break;
 
+    case CAT_TABLE_ID:
+        if ( b_enable_emm )
+            HandleCATSection( i_pid, p_section, i_dts );
+        break;
+
     case PMT_TABLE_ID:
         HandlePMT( i_pid, p_section, i_dts );
         break;
diff --git a/trunk/dvblast.c b/trunk/dvblast.c
index fc0aef0..866ae91 100644
--- a/trunk/dvblast.c
+++ b/trunk/dvblast.c
@@ -95,6 +95,9 @@ volatile sig_atomic_t b_hup_received = 0;
 int i_verbose = DEFAULT_VERBOSITY;
 int i_syslog = 0;
 
+bool b_enable_emm = false;
+bool b_enable_ecm = false;
+
 uint8_t pi_ssrc_global[4] = { 0, 0, 0, 0 };
 static int b_udp_global = 0;
 static int b_dvb_global = 0;
@@ -138,7 +141,9 @@ static void config_Defaults( output_config_t *p_config )
 
     p_config->i_config = (b_udp_global ? OUTPUT_UDP : 0) |
                          (b_dvb_global ? OUTPUT_DVB : 0) |
-                         (b_epg_global ? OUTPUT_EPG : 0);
+                         (b_epg_global ? OUTPUT_EPG : 0) |
+                         (b_enable_emm ? OUTPUT_EMM : 0) |
+                         (b_enable_ecm ? OUTPUT_ECM : 0);
     p_config->i_max_retention = i_retention_global;
     p_config->i_output_latency = i_latency_global;
     p_config->i_tsid = -1;
@@ -187,6 +192,14 @@ bool config_ParseHost( output_config_t *p_config, char *psz_string )
             p_config->i_config |= OUTPUT_DVB;
         else if ( IS_OPTION("epg") )
             p_config->i_config |= OUTPUT_EPG;
+        else if ( IS_OPTION("emm") )
+            p_config->i_config |= OUTPUT_EMM;
+        else if ( IS_OPTION("noemm") )
+            p_config->i_config &= ~OUTPUT_EMM;
+        else if ( IS_OPTION("ecm") )
+            p_config->i_config |= OUTPUT_ECM;
+        else if ( IS_OPTION("noecm") )
+            p_config->i_config &= ~OUTPUT_ECM;
         else if ( IS_OPTION("tsid=") )
             p_config->i_tsid = strtol( ARG_OPTION("tsid="), NULL, 0 );
         else if ( IS_OPTION("retention=") )
@@ -418,6 +431,8 @@ void usage()
     msg_Raw( NULL, "  -c --config-file <config file>" );
     msg_Raw( NULL, "  -C --dvb-compliance   pass through or build the mandatory DVB tables" );
     msg_Raw( NULL, "  -d --duplicate        duplicate all received packets to a given destination" );
+    msg_Raw( NULL, "  -W --emm-passthrough  pass through EMM data (CA system data)" );
+    msg_Raw( NULL, "  -Y --ecm-passthrough  pass through ECM data (CA program data)" );
     msg_Raw( NULL, "  -e --epg-passthrough  pass through DVB EIT schedule tables" );
     msg_Raw( NULL, "  -E --retention        maximum retention allowed between input and output (default: 40 ms)" );
     msg_Raw( NULL, "  -L --latency          maximum latency allowed between input and output (default: 100 ms)" );
@@ -497,6 +512,8 @@ int main( int i_argc, char **pp_argv )
         { "asi-adapter",     required_argument, NULL, 'A' },
         { "any-type",        no_argument,       NULL, 'z' },
         { "dvb-compliance",  no_argument,       NULL, 'C' },
+        { "emm-passthrough", no_argument,       NULL, 'W' },
+        { "ecm-passthrough", no_argument,       NULL, 'Y' },
         { "epg-passthrough", no_argument,       NULL, 'e' },
         { "network-name",    no_argument,       NULL, 'M' },
         { "network-id",      no_argument,       NULL, 'N' },
@@ -511,7 +528,7 @@ int main( int i_argc, char **pp_argv )
         { 0, 0, 0, 0 }
     };
 
-    while ( (c = getopt_long(i_argc, pp_argv, "q::c:r:t:o:i:a:n:f:F:R:s:S:v:pb:I:m:P:K:G:H:X:O:uwUTL:E:d:D:A:lzCeM:N:j:J:x:Q:hV", long_options, NULL)) != -1 )
+    while ( (c = getopt_long(i_argc, pp_argv, "q::c:r:t:o:i:a:n:f:F:R:s:S:v:pb:I:m:P:K:G:H:X:O:uwUTL:E:d:D:A:lzCWYeM:N:j:J:x:Q:hV", long_options, NULL)) != -1 )
     {
         switch ( c )
         {
@@ -711,6 +728,14 @@ int main( int i_argc, char **pp_argv )
             b_dvb_global = 1;
             break;
 
+        case 'W':
+            b_enable_emm = true;
+            break;
+
+        case 'Y':
+            b_enable_ecm = true;
+            break;
+
         case 'e':
             b_epg_global = 1;
             break;
diff --git a/trunk/dvblast.h b/trunk/dvblast.h
index b6b1dbf..7f534cc 100644
--- a/trunk/dvblast.h
+++ b/trunk/dvblast.h
@@ -52,6 +52,8 @@
  * Bit  4 : Set for file / FIFO output, unset for network (future use)
  * Bit  5 : Set if DVB conformance tables are inserted
  * Bit  6 : Set if DVB EIT schedule tables are forwarded
+ * Bit  7 : Set if EMM pids and CAT are forwarded
+ * Bit  8 : Set if ECM pids are forwarded
  *****************************************************************************/
 
 #define OUTPUT_WATCH         0x01
@@ -61,6 +63,8 @@
 #define OUTPUT_FILE          0x10
 #define OUTPUT_DVB           0x20
 #define OUTPUT_EPG           0x40
+#define OUTPUT_EMM           (1 << 7)
+#define OUTPUT_ECM           (1 << 8)
 
 typedef int64_t mtime_t;
 
diff --git a/trunk/dvblast.1 b/trunk/dvblast.1
index c6bfc34..7e965e0 100644
--- a/trunk/dvblast.1
+++ b/trunk/dvblast.1
@@ -3,7 +3,7 @@
 DVBlast \- Simple and powerful dvb streaming application
 .SH SYNOPSIS
 .B dvblast
-[\fI-q\fR] \fI-c <config_file>\fR [\fI-r <remote_socket>\fR] [\fI-t <ttl>\fR] [\fI-o <SSRC_IP>\fR] [\fI-i <RT_priority>\fR] [\fI-a <adapter>\fR] [\fI-n <frontend number>\fR] [\fI-S <diseqc>\fR] \fI-f <frequency>\fR [\fI-F <fec inner>\fR] [\fI-R <rolloff>\fR] ] [\fI-s <symbol_rate>\fR] [\fI-v <0|13|18>\fR] [\fI-p\fR] [\fI-b <bandwidth>\fR] [\fI-m <modulation\fR] [\fI-u\fR] [\fI-W\fR] [\fI-U\fR] [\fI-d <dest_IP:port>\fR] [\fI-e\fR] [\fI-T\fR] [\fI-l\fR]
+[\fI-q\fR] \fI-c <config_file>\fR [\fI-r <remote_socket>\fR] [\fI-t <ttl>\fR] [\fI-o <SSRC_IP>\fR] [\fI-i <RT_priority>\fR] [\fI-a <adapter>\fR] [\fI-n <frontend number>\fR] [\fI-S <diseqc>\fR] \fI-f <frequency>\fR [\fI-F <fec inner>\fR] [\fI-R <rolloff>\fR] ] [\fI-s <symbol_rate>\fR] [\fI-v <0|13|18>\fR] [\fI-p\fR] [\fI-b <bandwidth>\fR] [\fI-m <modulation\fR] [\fI-u\fR] [\fI-W\fR] [\fI-U\fR] [\fI-d <dest_IP:port>\fR] [\fI-W\fR] [\fI-Y\fR] [\fI-e\fR] [\fI-T\fR] [\fI-l\fR]
 .SH DESCRIPTION
 DVBlast is a simple and powerful streaming application based on the linux-dvb API.
 It opens a DVB device, tunes it, places PID filters, configures a CAM module, and demultiplexes the packets to several RTP outputs.
@@ -35,6 +35,12 @@ Duplicate all received packets to a given destination
 \fB\-D\fR, \fB\-\-rtp\-input\fR
 Read packets from a multicast address instead of a DVB card
 .TP
+\fB\-W\fR, \fB\-\-emm\-passthrough\fR
+Enable EMM pass through (CA system data)
+.TP
+\fB\-Y\fR, \fB\-\-ecm\-passthrough\fR
+Enable ECM pass through (CA program data)
+.TP
 \fB\-e\fR, \fB\-\-epg\-passthrough\fR
 Enable EPG pass through (EIT data)
 .TP


More information about the dvblast-devel mailing list