]> git.sesse.net Git - vlc/blobdiff - modules/demux/ts.c
Trailing ;
[vlc] / modules / demux / ts.c
index ce6b900f5677e55743ac47cf7197f8a60daa995f..da9d51b04d27b3c48a092f4f132bf97543b9ced3 100644 (file)
@@ -34,6 +34,7 @@
 #include <vlc_plugin.h>
 
 #include <ctype.h>
+#include <assert.h>
 
 #include <vlc_access.h> /* DVB-specific things */
 #include <vlc_demux.h>
@@ -155,32 +156,31 @@ static void Close ( vlc_object_t * );
     "Tweak the buffer size for reading and writing an integer number of packets." \
     "Specify the size of the buffer here and not the number of packets." )
 
-vlc_module_begin();
-    set_description( N_("MPEG Transport Stream demuxer") );
-    set_shortname ( "MPEG-TS" );
-    set_category( CAT_INPUT );
-    set_subcategory( SUBCAT_INPUT_DEMUX );
+vlc_module_begin ()
+    set_description( N_("MPEG Transport Stream demuxer") )
+    set_shortname ( "MPEG-TS" )
+    set_category( CAT_INPUT )
+    set_subcategory( SUBCAT_INPUT_DEMUX )
 
-    add_string( "ts-extra-pmt", NULL, NULL, PMT_TEXT, PMT_LONGTEXT, true );
-    add_bool( "ts-es-id-pid", 1, NULL, PID_TEXT, PID_LONGTEXT, true );
-    add_string( "ts-out", NULL, NULL, TSOUT_TEXT, TSOUT_LONGTEXT, true );
+    add_string( "ts-extra-pmt", NULL, NULL, PMT_TEXT, PMT_LONGTEXT, true )
+    add_bool( "ts-es-id-pid", 1, NULL, PID_TEXT, PID_LONGTEXT, true )
+    add_string( "ts-out", NULL, NULL, TSOUT_TEXT, TSOUT_LONGTEXT, true )
     add_integer( "ts-out-mtu", 1400, NULL, MTUOUT_TEXT,
-                 MTUOUT_LONGTEXT, true );
-    add_string( "ts-csa-ck", NULL, NULL, CSA_TEXT, CSA_LONGTEXT, true );
-    add_string( "ts-csa2-ck", NULL, NULL, CSA_TEXT, CSA_LONGTEXT, true );
-    add_integer( "ts-csa-pkt", 188, NULL, CPKT_TEXT, CPKT_LONGTEXT, true );
-    add_bool( "ts-silent", 0, NULL, SILENT_TEXT, SILENT_LONGTEXT, true );
-
-    add_file( "ts-dump-file", NULL, NULL, TSDUMP_TEXT, TSDUMP_LONGTEXT, false );
-        change_unsafe();
-    add_bool( "ts-dump-append", 0, NULL, APPEND_TEXT, APPEND_LONGTEXT, false );
+                 MTUOUT_LONGTEXT, true )
+    add_string( "ts-csa-ck", NULL, NULL, CSA_TEXT, CSA_LONGTEXT, true )
+    add_string( "ts-csa2-ck", NULL, NULL, CSA_TEXT, CSA_LONGTEXT, true )
+    add_integer( "ts-csa-pkt", 188, NULL, CPKT_TEXT, CPKT_LONGTEXT, true )
+    add_bool( "ts-silent", 0, NULL, SILENT_TEXT, SILENT_LONGTEXT, true )
+
+    add_file( "ts-dump-file", NULL, NULL, TSDUMP_TEXT, TSDUMP_LONGTEXT, false )
+    add_bool( "ts-dump-append", 0, NULL, APPEND_TEXT, APPEND_LONGTEXT, false )
     add_integer( "ts-dump-size", 16384, NULL, DUMPSIZE_TEXT,
-                 DUMPSIZE_LONGTEXT, true );
+                 DUMPSIZE_LONGTEXT, true )
 
-    set_capability( "demux", 10 );
-    set_callbacks( Open, Close );
-    add_shortcut( "ts" );
-vlc_module_end();
+    set_capability( "demux", 10 )
+    set_callbacks( Open, Close )
+    add_shortcut( "ts" )
+vlc_module_end ()
 
 /*****************************************************************************
  * Local prototypes
@@ -436,8 +436,6 @@ static int Open( vlc_object_t *p_this )
     bool         b_append;
     bool         b_topfield = false;
 
-    vlc_value_t  val;
-
     if( stream_Peek( p_demux->s, &p_peek, TS_PACKET_SIZE_MAX ) <
         TS_PACKET_SIZE_MAX ) return VLC_EGENERIC;
 
@@ -579,6 +577,7 @@ static int Open( vlc_object_t *p_this )
 
     /* Fill dump mode fields */
     p_sys->i_write = 0;
+    p_sys->buffer = NULL;
     p_sys->p_file = NULL;
     p_sys->b_file_out = false;
     p_sys->psz_file = var_CreateGetString( p_demux, "ts-dump-file" );
@@ -586,9 +585,7 @@ static int Open( vlc_object_t *p_this )
     {
         p_sys->b_file_out = true;
 
-        var_Create( p_demux, "ts-dump-append", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
-        var_Get( p_demux, "ts-dump-append", &val );
-        b_append = val.b_bool;
+        b_append = var_CreateGetBool( p_demux, "ts-dump-append" );
         if ( b_append )
             psz_mode = "ab";
         else
@@ -607,13 +604,9 @@ static int Open( vlc_object_t *p_this )
 
         if( p_sys->b_file_out )
         {
-            vlc_value_t bufsize;
-
             /* Determine how many packets to read. */
-            var_Create( p_demux, "ts-dump-size",
-                        VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
-            var_Get( p_demux, "ts-dump-size", &bufsize );
-            p_sys->i_ts_read = (int) (bufsize.i_int / p_sys->i_packet_size);
+            int bufsize = var_CreateGetInteger( p_demux, "ts-dump-size" );
+            p_sys->i_ts_read = (int) (bufsize / p_sys->i_packet_size);
             if( p_sys->i_ts_read <= 0 )
             {
                 p_sys->i_ts_read = 1500 / p_sys->i_packet_size;
@@ -651,6 +644,7 @@ static int Open( vlc_object_t *p_this )
     p_sys->pid[8191].b_seen = true;
     p_sys->i_packet_size = i_packet_size;
     p_sys->b_udp_out = false;
+    p_sys->fd = -1;
     p_sys->i_ts_read = 50;
     p_sys->csa = NULL;
     p_sys->b_start_record = false;
@@ -686,20 +680,15 @@ static int Open( vlc_object_t *p_this )
 #endif
 
     /* Init PMT array */
-    p_sys->i_pmt = 0;
-    p_sys->pmt   = NULL;
+    TAB_INIT( p_sys->i_pmt, p_sys->pmt );
 
     /* Read config */
-    var_Create( p_demux, "ts-es-id-pid", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Get( p_demux, "ts-es-id-pid", &val );
-    p_sys->b_es_id_pid = val.b_bool;
+    p_sys->b_es_id_pid = var_CreateGetBool( p_demux, "ts-es-id-pid" );
 
-    var_Create( p_demux, "ts-out", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-    var_Get( p_demux, "ts-out", &val );
-    if( val.psz_string && *val.psz_string && !p_sys->b_file_out )
+    char* psz_string = var_CreateGetString( p_demux, "ts-out" );
+    if( psz_string && *psz_string && !p_sys->b_file_out )
     {
-        vlc_value_t mtu;
-        char *psz = strchr( val.psz_string, ':' );
+        char *psz = strchr( psz_string, ':' );
         int   i_port = 0;
 
         p_sys->b_udp_out = true;
@@ -710,9 +699,9 @@ static int Open( vlc_object_t *p_this )
             i_port = atoi( psz );
         }
         if( i_port <= 0 ) i_port  = 1234;
-        msg_Dbg( p_demux, "resend ts to '%s:%d'", val.psz_string, i_port );
+        msg_Dbg( p_demux, "resend ts to '%s:%d'", psz_string, i_port );
 
-        p_sys->fd = net_ConnectUDP( VLC_OBJECT(p_demux), val.psz_string, i_port, 0 );
+        p_sys->fd = net_ConnectUDP( VLC_OBJECT(p_demux), psz_string, i_port, -1 );
         if( p_sys->fd < 0 )
         {
             msg_Err( p_demux, "failed to open udp socket, send disabled" );
@@ -720,10 +709,8 @@ static int Open( vlc_object_t *p_this )
         }
         else
         {
-            var_Create( p_demux, "ts-out-mtu",
-                        VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
-            var_Get( p_demux, "ts-out-mtu", &mtu );
-            p_sys->i_ts_read = mtu.i_int / p_sys->i_packet_size;
+            int i_mtu = var_CreateGetInteger( p_demux, "ts-out-mtu" );
+            p_sys->i_ts_read = i_mtu / p_sys->i_packet_size;
             if( p_sys->i_ts_read <= 0 )
             {
                 p_sys->i_ts_read = 1500 / p_sys->i_packet_size;
@@ -731,38 +718,35 @@ static int Open( vlc_object_t *p_this )
             p_sys->buffer = malloc( p_sys->i_packet_size * p_sys->i_ts_read );
         }
     }
-    free( val.psz_string );
+    free( psz_string );
 
     /* We handle description of an extra PMT */
-    var_Create( p_demux, "ts-extra-pmt", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-    var_Get( p_demux, "ts-extra-pmt", &val );
+    psz_string = var_CreateGetString( p_demux, "ts-extra-pmt" );
     p_sys->b_user_pmt = false;
-    if( val.psz_string && *val.psz_string )
-        UserPmt( p_demux, val.psz_string );
-    free( val.psz_string );
+    if( psz_string && *psz_string )
+        UserPmt( p_demux, psz_string );
+    free( psz_string );
 
-    var_Create( p_demux, "ts-csa-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
-    var_Get( p_demux, "ts-csa-ck", &val );
-    if( val.psz_string && *val.psz_string )
+    psz_string = var_CreateGetStringCommand( p_demux, "ts-csa-ck" );
+    if( psz_string && *psz_string )
     {
         int i_res;
-        vlc_value_t csa2;
+        char* psz_csa2;
 
         p_sys->csa = csa_New();
 
-        var_Create( p_demux, "ts-csa2-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND);
-        var_Get( p_demux, "ts-csa2-ck", &csa2 );
-        i_res = csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, true );
-        if( i_res == VLC_SUCCESS && csa2.psz_string && *csa2.psz_string )
+        psz_csa2 = var_CreateGetStringCommand( p_demux, "ts-csa2-ck" );
+        i_res = csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_string, true );
+        if( i_res == VLC_SUCCESS && psz_csa2 && *psz_csa2 )
         {
-            if( csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, csa2.psz_string, false ) != VLC_SUCCESS )
+            if( csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_csa2, false ) != VLC_SUCCESS )
             {
-                csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, false );
+                csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_string, false );
             }
         }
         else if ( i_res == VLC_SUCCESS )
         {
-            csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, val.psz_string, false );
+            csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_string, false );
         }
         else
         {
@@ -772,29 +756,25 @@ static int Open( vlc_object_t *p_this )
 
         if( p_sys->csa )
         {
-            vlc_value_t pkt_val;
-
             var_AddCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, (void *)1 );
             var_AddCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL );
 
-            var_Create( p_demux, "ts-csa-pkt", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
-            var_Get( p_demux, "ts-csa-pkt", &pkt_val );
-            if( pkt_val.i_int < 4 || pkt_val.i_int > 188 )
+            int i_pkt = var_CreateGetInteger( p_demux, "ts-csa-pkt" );
+            if( i_pkt < 4 || i_pkt > 188 )
             {
-                msg_Err( p_demux, "wrong packet size %d specified.", pkt_val.i_int );
+                msg_Err( p_demux, "wrong packet size %d specified.", i_pkt );
                 msg_Warn( p_demux, "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;
+            else
+                p_sys->i_csa_pkt_size = i_pkt;
             msg_Dbg( p_demux, "decrypting %d bytes of packet", p_sys->i_csa_pkt_size );
         }
-        free( csa2.psz_string );
+        free( psz_csa2 );
     }
-    free( val.psz_string );
+    free( psz_string );
 
-    var_Create( p_demux, "ts-silent", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Get( p_demux, "ts-silent", &val );
-    p_sys->b_silent = val.b_bool;
+    p_sys->b_silent = var_CreateGetBool( p_demux, "ts-silent" );
 
     return VLC_SUCCESS;
 }
@@ -855,22 +835,16 @@ static void Close( vlc_object_t *p_this )
 
     }
 
-    if( p_sys->b_udp_out )
-    {
-        net_Close( p_sys->fd );
-        free( p_sys->buffer );
-    }
     vlc_mutex_lock( &p_sys->csa_lock );
     if( p_sys->csa )
     {
         var_DelCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, NULL );
         var_DelCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL );
         csa_Delete( p_sys->csa );
-        p_sys->csa = NULL;
     }
     vlc_mutex_unlock( &p_sys->csa_lock );
 
-    if( p_sys->i_pmt ) free( p_sys->pmt );
+    TAB_CLEAN( p_sys->i_pmt, p_sys->pmt );
 
     if ( p_sys->p_programs_list )
     {
@@ -888,14 +862,16 @@ static void Close( vlc_object_t *p_this )
         if( p_sys->p_file != stdout )
         {
             fclose( p_sys->p_file );
-            p_sys->p_file = NULL;
         }
-
-        free( p_sys->buffer );
+    }
+    /* When streaming, close the port */
+    if( p_sys->fd > -1 )
+    {
+        net_Close( p_sys->fd );
     }
 
+    free( p_sys->buffer );
     free( p_sys->psz_file );
-    p_sys->psz_file = NULL;
 
     vlc_mutex_destroy( &p_sys->csa_lock );
     free( p_sys );
@@ -1239,11 +1215,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             f = (double) va_arg( args, double );
             i64 = stream_Size( p_demux->s );
 
-            es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
             if( stream_Seek( p_demux->s, (int64_t)(i64 * f) ) )
-            {
                 return VLC_EGENERIC;
-            }
+
             return VLC_SUCCESS;
 #if 0
 
@@ -1363,10 +1337,10 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
                 {
                     stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
                                     ACCESS_SET_PRIVATE_ID_STATE, i_pmt_pid,
-                                    true );
+                                    true )
                     stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
                                     ACCESS_SET_PRIVATE_ID_STATE, p_prg->i_pid_pcr,
-                                    true );
+                                    true )
 
                     for( i = 2; i < 8192; i++ )
                     {
@@ -1568,15 +1542,15 @@ static void PIDInit( ts_pid_t *pid, bool b_psi, ts_psi_t *p_owner )
 
         if( !b_old_valid )
         {
-            free( pid->psi );
             pid->psi = malloc( sizeof( ts_psi_t ) );
             if( pid->psi )
             {
-                pid->psi->handle= NULL;
-                pid->psi->i_prg = 0;
-                pid->psi->prg   = NULL;
+                pid->psi->handle = NULL;
+                TAB_INIT( pid->psi->i_prg, pid->psi->prg );
             }
         }
+        assert( pid->psi );
+
         pid->psi->i_pat_version  = -1;
         pid->psi->i_sdt_version  = -1;
         if( p_owner )
@@ -1670,7 +1644,7 @@ static void PIDClean( es_out_t *out, ts_pid_t *pid )
 static void ParsePES( demux_t *p_demux, ts_pid_t *pid )
 {
     block_t *p_pes = pid->es->p_pes;
-    uint8_t header[30];
+    uint8_t header[34];
     int     i_pes_size = 0;
     int     i_skip = 0;
     mtime_t i_dts = -1;
@@ -1685,7 +1659,7 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid )
     pid->es->pp_last = &pid->es->p_pes;
 
     /* FIXME find real max size */
-    i_max = block_ChainExtract( p_pes, header, 30 );
+    i_max = block_ChainExtract( p_pes, header, 34 );
 
 
     if( header[0] != 0 || header[1] != 0 || header[2] != 1 )
@@ -3055,6 +3029,7 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
 
     ts_pid_t             **pp_clean = NULL;
     int                  i_clean = 0, i;
+    bool                 b_hdmv = false;
 
     msg_Dbg( p_demux, "PMTCallBack called" );
 
@@ -3116,7 +3091,7 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
         /* Set demux filter */
         stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
                         ACCESS_SET_PRIVATE_ID_STATE, prg->i_pid_pcr,
-                        true );
+                        true )
     }
     else if ( p_sys->b_dvb_control )
     {
@@ -3141,6 +3116,26 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
                                 | p_dr->p_data[1];
             msg_Dbg( p_demux, " * descriptor : CA (0x9) SysID 0x%x", i_sysid );
         }
+        else if( p_dr->i_tag == 0x05 )
+        {
+            if( p_dr->i_tag == 0x05 )
+            {
+                /* Registration Descriptor */
+                if( p_dr->i_length != 4 )
+                {
+                    msg_Warn( p_demux, "invalid Registration Descriptor" );
+                }
+                else
+                {
+                    msg_Dbg( p_demux, " * descriptor : registration %4.4s", p_dr->p_data );
+                    if( !memcmp( p_dr->p_data, "HDMV", 4 ) )
+                    {
+                        /* Blu-Ray */
+                        b_hdmv = true;
+                    }
+                }
+            }
+        }
         else
         {
             msg_Dbg( p_demux, " * descriptor : unknown (0x%x)", p_dr->i_tag );
@@ -3171,7 +3166,7 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
                  * parsing the SDT/EDT */
                 dvbpsi_DetachDemux( pid->psi->handle );
                 free( pid->psi );
-                pid->psi = 0;
+                pid->psi = NULL;
             }
             else
             {
@@ -3354,6 +3349,12 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
                     pid->es->fmt.i_cat = AUDIO_ES;
                     pid->es->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
                 }
+                else if( p_dr->i_tag == 0x81 )
+                {
+                    /* ATSC with stream_type 0x06 */
+                    pid->es->fmt.i_cat = AUDIO_ES;
+                    pid->es->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
+                }
                 else if( p_dr->i_tag == 0x7a )
                 {
                     /* DVB with stream_type 0x06 (ETS EN 300 468) */
@@ -3692,6 +3693,41 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
              * Yes it's ugly but it's the only way to have DIV3 working */
             pid->es->fmt.b_packetized = true;
         }
+        else if( b_hdmv )
+        {
+            /* Blu-Ray mapping */
+            switch( p_es->i_type )
+            {
+            case 0x80:
+                pid->es->fmt.i_cat = AUDIO_ES;
+                pid->es->fmt.i_codec = VLC_FOURCC( 'b', 'p', 'c', 'm' );
+                break;
+            case 0x82:
+            case 0x85: /* DTS-HD High resolution audio */
+            case 0x86: /* DTS-HD Master audio */
+            case 0xA2: /* Secondary DTS audio */
+                pid->es->fmt.i_cat = AUDIO_ES;
+                pid->es->fmt.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' );
+                break;
+
+            case 0x83: /* TrueHD AC3 */
+                pid->es->fmt.i_cat = AUDIO_ES;
+                pid->es->fmt.i_codec = VLC_FOURCC( 'm', 'l', 'p', ' ' );
+                break;
+
+            case 0x84: /* E-AC3 */
+            case 0x87: /* E-AC3 */
+            case 0xA1: /* Secondary E-AC3 */
+                pid->es->fmt.i_cat = AUDIO_ES;
+                pid->es->fmt.i_codec = VLC_FOURCC( 'e', 'a', 'c', '3' );
+                break;
+            case 0x90: /* Presentation graphics */
+            case 0x91: /* Interactive graphics */
+            case 0x92: /* Subtitle */
+            default:
+                break;
+            }
+        }
 
         if( pid->es->fmt.i_cat == AUDIO_ES ||
             ( pid->es->fmt.i_cat == SPU_ES &&
@@ -3874,7 +3910,7 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
             /* Set demux filter */
             stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
                             ACCESS_SET_PRIVATE_ID_STATE, p_es->i_pid,
-                            true );
+                            true )
         }
     }
 
@@ -3968,7 +4004,7 @@ static void PATCallBack( demux_t *p_demux, dvbpsi_pat_t *p_pat )
 
             if( !pid->b_valid || pid->psi ) continue;
 
-            for( j = 0; j < i_pmt_rm; j++ )
+            for( j = 0; j < i_pmt_rm && pid->b_valid; j++ )
             {
                 int i_prg;
                 for( i_prg = 0; i_prg < pid->p_owner->i_prg; i_prg++ )
@@ -3988,8 +4024,6 @@ static void PATCallBack( demux_t *p_demux, dvbpsi_pat_t *p_pat )
                     PIDClean( p_demux->out, pid );
                     break;
                 }
-
-                if( !pid->b_valid ) break;
             }
         }