]> git.sesse.net Git - vlc/blobdiff - modules/demux/ts.c
* modules/demux/ogg.c: fix for --input-repeat
[vlc] / modules / demux / ts.c
index fa28d284fab6be5066a82783d384c1fa8f6a4900..5d7c5c28ffc774a8b78bdfd8d683d18694f82238 100644 (file)
@@ -73,7 +73,7 @@ vlc_module_begin();
     add_bool( "ts-silent", 0, NULL, "Silent mode", "do not complain on encrypted PES", VLC_TRUE );
     set_capability( "demux2", 10 );
     set_callbacks( Open, Close );
-    add_shortcut( "ts2" );
+    add_shortcut( "ts" );
 vlc_module_end();
 
 /*****************************************************************************
@@ -185,6 +185,8 @@ typedef struct
 {
     es_format_t  fmt;
     es_out_id_t *id;
+    int         i_pes_size;
+    int         i_pes_gathered;
     block_t     *p_pes;
     block_t     **pp_last;
 
@@ -290,14 +292,14 @@ static int Open( vlc_object_t *p_this )
     }
     if( i_sync >= i_peek )
     {
-        if( strcmp( p_demux->psz_demux, "ts2" ) )
+        if( strcmp( p_demux->psz_demux, "ts" ) )
         {
             msg_Warn( p_demux, "TS module discarded" );
             return VLC_EGENERIC;
         }
         msg_Warn( p_demux, "this does not look like a TS stream, continuing" );
     }
-    if( strcmp( p_demux->psz_demux, "ts2" ) )
+    if( strcmp( p_demux->psz_demux, "ts" ) )
     {
         /* Check next 3 sync points */
         i_peek = 188*3 + 1 + i_sync;
@@ -643,7 +645,8 @@ static int Demux( demux_t *p_demux )
                     int i_prg;
                     for( i_prg = 0; i_prg < p_pid->psi->i_prg; i_prg++ )
                     {
-                        dvbpsi_PushPacket( p_pid->psi->prg[i_prg]->handle, p_pkt->p_buffer );
+                        dvbpsi_PushPacket( p_pid->psi->prg[i_prg]->handle,
+                                           p_pkt->p_buffer );
                     }
                 }
                 block_Release( p_pkt );
@@ -792,6 +795,8 @@ static void PIDInit( ts_pid_t *pid, vlc_bool_t b_psi, ts_psi_t *p_owner )
         es_format_Init( &pid->es->fmt, UNKNOWN_ES, 0 );
         pid->es->id      = NULL;
         pid->es->p_pes   = NULL;
+        pid->es->i_pes_size= 0;
+        pid->es->i_pes_gathered= 0;
         pid->es->pp_last = &pid->es->p_pes;
         pid->es->p_mpeg4desc = NULL;
         pid->es->b_gather = VLC_FALSE;
@@ -807,8 +812,10 @@ static void PIDClean( es_out_t *out, ts_pid_t *pid )
         if( pid->psi->handle ) dvbpsi_DetachPMT( pid->psi->handle );
         for( i = 0; i < pid->psi->i_prg; i++ )
         {
-            if( pid->psi->prg[i]->iod ) IODFree( pid->psi->prg[i]->iod );
-            if( pid->psi->prg[i]->handle ) dvbpsi_DetachPMT( pid->psi->prg[i]->handle );
+            if( pid->psi->prg[i]->iod )
+                IODFree( pid->psi->prg[i]->iod );
+            if( pid->psi->prg[i]->handle )
+                dvbpsi_DetachPMT( pid->psi->prg[i]->handle );
             free( pid->psi->prg[i] );
         }
         if( pid->psi->prg ) free( pid->psi->prg );
@@ -853,14 +860,17 @@ static void ParsePES ( demux_t *p_demux, ts_pid_t *pid )
 {
     block_t *p_pes = pid->es->p_pes;
     uint8_t header[30];
-    int     i_pes_size;
+    int     i_pes_size = 0;
     int     i_skip = 0;
     mtime_t i_dts = -1;
     mtime_t i_pts = -1;
+    mtime_t i_length = 0;
     int i_max;
 
     /* remove the pes from pid */
     pid->es->p_pes = NULL;
+    pid->es->i_pes_size= 0;
+    pid->es->i_pes_gathered= 0;
     pid->es->pp_last = &pid->es->p_pes;
 
     /* FIXME find real max size */
@@ -875,10 +885,7 @@ static void ParsePES ( demux_t *p_demux, ts_pid_t *pid )
         return;
     }
 
-    i_pes_size = (header[4] << 8)|header[5];
-
     /* TODO check size */
-
     switch( header[3] )
     {
         case 0xBC:  /* Program stream map */
@@ -974,6 +981,30 @@ static void ParsePES ( demux_t *p_demux, ts_pid_t *pid )
     {
         i_skip += 1;
     }
+    else if( pid->es->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) &&
+             pid->es->p_mpeg4desc )
+    {
+        decoder_config_descriptor_t *dcd = &pid->es->p_mpeg4desc->dec_descr;
+
+        if( dcd->i_decoder_specific_info_len > 2 &&
+            dcd->p_decoder_specific_info[0] == 0x10 &&
+            ( dcd->p_decoder_specific_info[1]&0x10 ) )
+        {
+            /* display length */
+            if( p_pes->i_buffer + 2 <= i_skip )
+            {
+                i_length = GetWBE( &p_pes->p_buffer[i_skip] );
+            }
+
+            i_skip += 2;
+        }
+        if( p_pes->i_buffer + 2 <= i_skip )
+        {
+            i_pes_size = GetWBE( &p_pes->p_buffer[i_skip] );
+        }
+        /* */
+        i_skip += 2;
+    }
 
     /* skip header */
     while( p_pes && i_skip > 0 )
@@ -1007,16 +1038,18 @@ static void ParsePES ( demux_t *p_demux, ts_pid_t *pid )
         {
             p_pes->i_pts = i_pts * 100 / 9;
         }
+        p_pes->i_length = i_length * 100 / 9;
 
-        if( 1 ) //pid->es->b_gather )
+        p_block = block_ChainGather( p_pes );
+        if( pid->es->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) )
         {
-            /* For mpeg4/mscodec we first gather the packet.
-             * This will make ffmpeg a lot happier */
-            p_block = block_ChainGather( p_pes );
-        }
-        else
-        {
-            p_block = p_pes;
+            if( i_pes_size > 0 && p_block->i_buffer > i_pes_size )
+            {
+                p_block->i_buffer = i_pes_size;
+            }
+            /* Append a \0 */
+            p_block = block_Realloc( p_block, 0, p_block->i_buffer + 1 );
+            p_block->p_buffer[p_block->i_buffer -1] = '\0';
         }
 
         for( i = 0; i < pid->i_extra_es; i++ )
@@ -1074,17 +1107,22 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
     const vlc_bool_t  b_adaptation= p[3]&0x20;
     const vlc_bool_t  b_payload   = p[3]&0x10;
     const int         i_cc        = p[3]&0x0f;   /* continuity counter */
+
     /* transport_scrambling_control is ignored */
 
     int         i_skip = 0;
-    vlc_bool_t  i_ret   = VLC_FALSE;
-
+    vlc_bool_t  i_ret  = VLC_FALSE;
     int         i_diff;
 
-    //msg_Dbg( p_demux, "pid=0x%x unit_start=%d adaptation=%d payload=%d cc=0x%x", i_pid, b_unit_start, b_adaptation, b_payload, i_continuity_counter);
+#if 0
+    msg_Dbg( p_demux, "pid=0x%x unit_start=%d adaptation=%d payload=%d "
+             "cc=0x%x", pid->i_pid, p[1]&0x40, b_adaptation, b_payload, i_cc);
+#endif
+
     if( p[1]&0x80 )
     {
-        msg_Dbg( p_demux, "transport_error_indicator set (pid=0x%x)", pid->i_pid );
+        msg_Dbg( p_demux, "transport_error_indicator set (pid=0x%x)",
+                 pid->i_pid );
     }
 
     if( p_demux->p_sys->csa )
@@ -1109,11 +1147,13 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
             }
         }
     }
+
     /* test continuity counter */
     /* continuous when (one of this):
         * diff == 1
         * diff == 0 and payload == 0
-        * diff == 0 and duplicate packet (playload != 0) <- do we should test the content ?
+        * diff == 0 and duplicate packet (playload != 0) <- should we
+        *   test the content ?
      */
 
     i_diff = ( i_cc - pid->i_cc )&0x0f;
@@ -1152,7 +1192,7 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
     }
     else
     {
-        const vlc_bool_t b_unit_start= p[1]&0x40;
+        const vlc_bool_t b_unit_start = p[1]&0x40;
 
         /* we have to gather it */
         p_bk->p_buffer += i_skip;
@@ -1167,6 +1207,21 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
             }
 
             block_ChainLastAppend( &pid->es->pp_last, p_bk );
+            if( p_bk->i_buffer > 6 )
+            {
+                pid->es->i_pes_size = GetWBE( &p_bk->p_buffer[4] );
+                if( pid->es->i_pes_size > 0 )
+                {
+                    pid->es->i_pes_size += 6;
+                }
+            }
+            pid->es->i_pes_gathered += p_bk->i_buffer;
+            if( pid->es->i_pes_size > 0 &&
+                pid->es->i_pes_gathered >= pid->es->i_pes_size )
+            {
+                ParsePES( p_demux, pid );
+                i_ret = VLC_TRUE;
+            }
         }
         else
         {
@@ -1177,9 +1232,14 @@ static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
             }
             else
             {
-                /* TODO check if when have gathered enough packets to form a
-                 * PES (ie read PES size)*/
                 block_ChainLastAppend( &pid->es->pp_last, p_bk );
+                pid->es->i_pes_gathered += p_bk->i_buffer;
+                if( pid->es->i_pes_size > 0 &&
+                    pid->es->i_pes_gathered >= pid->es->i_pes_size )
+                {
+                    ParsePES( p_demux, pid );
+                    i_ret = VLC_TRUE;
+                }
             }
         }
     }
@@ -1249,6 +1309,7 @@ static int PIDFillFormat( ts_pid_t *pid, int i_stream_type )
             break;
 
         case 0x06:  /* PES_PRIVATE  (fixed later) */
+        case 0x12:  /* MPEG-4 generic (sub/scene/...) (fixed later) */
         default:
             es_format_Init( fmt, UNKNOWN_ES, 0 );
             break;
@@ -1637,7 +1698,8 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
         int i_prg;
         for( i_prg = 0; i_prg < p_sys->pmt[i]->psi->i_prg; i_prg++ )
         {
-            if( p_sys->pmt[i]->psi->prg[i_prg]->i_number == p_pmt->i_program_number )
+            if( p_sys->pmt[i]->psi->prg[i_prg]->i_number ==
+                p_pmt->i_program_number )
             {
                 pmt = p_sys->pmt[i];
                 prg = p_sys->pmt[i]->psi->prg[i_prg];
@@ -1667,7 +1729,8 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
     {
         ts_pid_t *pid = &p_sys->pid[i];
 
-        if( pid->b_valid && pid->p_owner == pmt->psi && pid->i_owner_number == prg->i_number && pid->psi == NULL )
+        if( pid->b_valid && pid->p_owner == pmt->psi &&
+            pid->i_owner_number == prg->i_number && pid->psi == NULL )
         {
             PIDClean( p_demux->out, pid );
         }
@@ -1714,7 +1777,8 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
         PIDFillFormat( pid, p_es->i_type );
         pid->i_owner_number = prg->i_number;
 
-        if( p_es->i_type == 0x10 || p_es->i_type == 0x11 )
+        if( p_es->i_type == 0x10 || p_es->i_type == 0x11 ||
+            p_es->i_type == 0x12 )
         {
             /* MPEG-4 stream: search SL_DESCRIPTOR */
             dvbpsi_descriptor_t *p_dr = p_es->p_first_descriptor;;
@@ -1753,6 +1817,11 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
                     pid->es->fmt.i_cat = VIDEO_ES;
                     switch( dcd->i_objectTypeIndication )
                     {
+                    case 0x0B: /* mpeg4 sub */
+                        pid->es->fmt.i_cat = SPU_ES;
+                        pid->es->fmt.i_codec = VLC_FOURCC('s','u','b','t');
+                        break;
+
                     case 0x20: /* mpeg4 */
                         pid->es->fmt.i_codec = VLC_FOURCC('m','p','4','v');
                         break;
@@ -1832,6 +1901,20 @@ 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 == 0x05 )
+                {
+
+                    /* DTS registration descriptor (ETSI TS 101 154 Annex F) */
+                    pid->es->fmt.i_cat = AUDIO_ES;
+                    pid->es->fmt.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' );
+                }
+                else if( p_dr->i_tag == 0x73 )
+                {
+                    /* DTS audio descriptor (ETSI TS 101 154 Annex F) */
+                    msg_Dbg( p_demux, "  * DTS audio descriptor not decoded" );
+                    pid->es->fmt.i_cat = AUDIO_ES;
+                    pid->es->fmt.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' );
+                }
 #ifdef _DVBPSI_DR_59_H_
                 else if( p_dr->i_tag == 0x59 )
                 {
@@ -1857,6 +1940,9 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
 
                         pid->es->fmt.subs.dvb.i_id =
                             sub->p_subtitle[0].i_composition_page_id;
+                        /* Hack, FIXME */
+                        pid->es->fmt.subs.dvb.i_id |=
+                            (sub->p_subtitle[0].i_ancillary_page_id << 16);
                     }
                     else pid->es->fmt.i_cat = UNKNOWN_ES;
 
@@ -1866,6 +1952,8 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
                         p_es->fmt = pid->es->fmt;
                         p_es->id = NULL;
                         p_es->p_pes = NULL;
+                        p_es->i_pes_size = 0;
+                        p_es->i_pes_gathered = 0;
                         p_es->pp_last = &p_es->p_pes;
                         p_es->p_mpeg4desc = NULL;
 
@@ -1983,7 +2071,8 @@ static void PATCallBack( demux_t *p_demux, dvbpsi_pat_t *p_pat )
     msg_Dbg( p_demux, "PATCallBack called" );
 
     if( pat->psi->i_pat_version != -1 &&
-        ( !p_pat->b_current_next || p_pat->i_version == pat->psi->i_pat_version ) )
+        ( !p_pat->b_current_next ||
+          p_pat->i_version == pat->psi->i_pat_version ) )
     {
         dvbpsi_DeletePAT( p_pat );
         return;
@@ -2012,7 +2101,8 @@ static void PATCallBack( demux_t *p_demux, dvbpsi_pat_t *p_pat )
                     int i_prg;
                     for( i_prg = 0; i_prg < pmt->psi->i_prg; i_prg++ )
                     {
-                        if( p_program->i_number == pmt->psi->prg[i_prg]->i_number )
+                        if( p_program->i_number ==
+                            pmt->psi->prg[i_prg]->i_number )
                         {
                             b_keep = VLC_TRUE;
                             break;
@@ -2040,8 +2130,8 @@ static void PATCallBack( demux_t *p_demux, dvbpsi_pat_t *p_pat )
                 int i_prg;
                 for( i_prg = 0; i_prg < pid->p_owner->i_prg; i_prg++ )
                 {
-                    if( pid->p_owner->prg[i_prg]->i_pid_pcr == pmt_rm[j]->i_pid &&
-                        pid->es->id )
+                    if( pid->p_owner->prg[i_prg]->i_pid_pcr ==
+                        pmt_rm[j]->i_pid && pid->es->id )
                     {
                         /* We only remove es that aren't defined by extra pmt */
                         PIDClean( p_demux->out, pid );
@@ -2098,8 +2188,10 @@ static void PATCallBack( demux_t *p_demux, dvbpsi_pat_t *p_pat )
                 PIDInit( pmt, VLC_TRUE, pat->psi );
                 pmt->psi->prg[pmt->psi->i_prg-1]->handle =
                     dvbpsi_AttachPMT( p_program->i_number,
-                                      (dvbpsi_pmt_callback)PMTCallBack, p_demux );
-                pmt->psi->prg[pmt->psi->i_prg-1]->i_number = p_program->i_number;
+                                      (dvbpsi_pmt_callback)PMTCallBack,
+                                      p_demux );
+                pmt->psi->prg[pmt->psi->i_prg-1]->i_number =
+                    p_program->i_number;
             }
         }
     }