]> git.sesse.net Git - vlc/blobdiff - modules/mux/mpeg/ts.c
mux: ts: split ts encapsulation
[vlc] / modules / mux / mpeg / ts.c
index e631e7e8f419b5639ad90c117732cdfc491eb289..df7ffd25be98162b8187fb6af609d1c98a822be3 100644 (file)
@@ -45,6 +45,7 @@
 #include "bits.h"
 #include "pes.h"
 #include "csa.h"
+#include "tsutil.h"
 
 # include <dvbpsi/dvbpsi.h>
 # include <dvbpsi/demux.h>
@@ -379,6 +380,7 @@ struct sout_mux_sys_t
     int64_t         i_pcr_delay;
 
     int64_t         i_dts_delay;
+    mtime_t         first_dts;
 
     bool            b_use_key_frames;
 
@@ -722,13 +724,14 @@ static int Open( vlc_object_t *p_this )
 
     p_sys->b_use_key_frames = var_GetBool( p_mux, SOUT_CFG_PREFIX "use-key-frames" );
 
+    p_mux->p_sys        = p_sys;
+
     p_sys->csa = csaSetup(p_this);
 
     p_mux->pf_control   = Control;
     p_mux->pf_addstream = AddStream;
     p_mux->pf_delstream = DelStream;
     p_mux->pf_mux       = Mux;
-    p_mux->p_sys        = p_sys;
 
     return VLC_SUCCESS;
 }
@@ -906,6 +909,10 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
         p_stream->i_stream_id = 0xe0;
         p_stream->i_es_id = p_stream->i_pid;
         break;
+    case VLC_CODEC_HEVC:
+        p_stream->i_stream_type = 0x24;
+        p_stream->i_stream_id = 0xe0;
+        break;
     case VLC_CODEC_H264:
         p_stream->i_stream_type = 0x1b;
         p_stream->i_stream_id = 0xe0;
@@ -935,6 +942,7 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
     /* AUDIO */
 
     case VLC_CODEC_MPGA:
+    case VLC_CODEC_MP3:
         p_stream->i_stream_type =
             p_input->p_fmt->audio.i_rate >= 32000 ? 0x03 : 0x04;
         p_stream->i_stream_id = 0xc0;
@@ -943,14 +951,17 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
         p_stream->i_stream_type = 0x81;
         p_stream->i_stream_id = 0xbd;
         break;
-    case VLC_CODEC_EAC3:
-        p_stream->i_stream_type = 0x06;
-        p_stream->i_stream_id = 0xbd;
-        break;
     case VLC_CODEC_DVD_LPCM:
         p_stream->i_stream_type = 0x83;
         p_stream->i_stream_id = 0xbd;
         break;
+    case VLC_CODEC_OPUS:
+        if (p_input->p_fmt->audio.i_channels > 8) {
+            msg_Err(p_mux, "Too many opus channels (%d > 8)",
+                p_input->p_fmt->audio.i_channels);
+            break;
+        }
+    case VLC_CODEC_EAC3:
     case VLC_CODEC_DTS:
         p_stream->i_stream_type = 0x06;
         p_stream->i_stream_id = 0xbd;
@@ -961,7 +972,6 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
         //p_stream->i_stream_type = 0x11; /* LOAS/LATM */
         p_stream->i_stream_type = 0x0f; /* ADTS */
         p_stream->i_stream_id = 0xc0;
-        p_sys->i_mpeg4_streams++;
         p_stream->i_es_id = p_stream->i_pid;
         break;
 
@@ -990,6 +1000,8 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
 
     if (p_stream->i_stream_type == -1)
     {
+        msg_Warn( p_mux, "rejecting stream with unsupported codec %4.4s",
+                  (char*)&p_stream->i_codec );
         free( p_stream );
         return VLC_EGENERIC;
     }
@@ -1211,6 +1223,20 @@ static void SetHeader( sout_buffer_chain_t *c,
     p_ts->i_flags |= BLOCK_FLAG_HEADER;
 }
 
+static block_t *Pack_Opus(block_t *p_data)
+{
+    lldiv_t d = lldiv(p_data->i_buffer, 255);
+    p_data = block_Realloc(p_data, 2 + d.quot + 1, p_data->i_buffer);
+    if (p_data) { /* no flags */
+        p_data->p_buffer[0] = 0x7f;
+        p_data->p_buffer[1] = 0xe0;
+        memset(&p_data->p_buffer[2], 0xff, d.quot);
+        p_data->p_buffer[2+d.quot] = d.rem;
+    }
+
+    return p_data;
+}
+
 /* returns true if needs more data */
 static bool MuxStreams(sout_mux_t *p_mux )
 {
@@ -1271,11 +1297,11 @@ static bool MuxStreams(sout_mux_t *p_mux )
 
                 int64_t i_spu_delay = p_spu->i_dts - p_pcr_stream->i_pes_dts;
                 if( ( i_spu_delay > i_shaping_delay ) &&
-                    ( i_spu_delay < INT64_C(100000000) ) )
+                    ( i_spu_delay < 100 * CLOCK_FREQ ) )
                     continue;
 
-                if ( ( i_spu_delay >= INT64_C(100000000) ) ||
-                     ( i_spu_delay < INT64_C(10000) ) )
+                if ( ( i_spu_delay >= 100 * CLOCK_FREQ ) ||
+                     ( i_spu_delay < CLOCK_FREQ / 100 ) )
                 {
                     BufferChainClean( &p_stream->chain_pes );
                     p_stream->i_pes_dts = 0;
@@ -1289,7 +1315,8 @@ static bool MuxStreams(sout_mux_t *p_mux )
 
         block_t *p_data;
         if( p_stream == p_pcr_stream || p_sys->b_data_alignment
-             || p_input->p_fmt->i_codec != VLC_CODEC_MPGA )
+             || ((p_input->p_fmt->i_codec != VLC_CODEC_MPGA ) &&
+                 (p_input->p_fmt->i_codec != VLC_CODEC_MP3) ) )
         {
             p_data = block_FifoGet( p_input->p_fifo );
             if (p_data->i_pts <= VLC_TS_INVALID)
@@ -1297,6 +1324,8 @@ static bool MuxStreams(sout_mux_t *p_mux )
 
             if( p_input->p_fmt->i_codec == VLC_CODEC_MP4A )
                 p_data = Add_ADTS( p_data, p_input->p_fmt );
+            else if( p_input->p_fmt->i_codec == VLC_CODEC_OPUS )
+                p_data = Pack_Opus( p_data );
         }
         else
             p_data = FixPES( p_mux, p_input->p_fifo );
@@ -1311,13 +1340,16 @@ static bool MuxStreams(sout_mux_t *p_mux )
                    VLC_CODEC_SUBT )
             p_data->i_length = 1000;
 
+        if (p_sys->first_dts == 0)
+            p_sys->first_dts = p_data->i_dts;
+
         if( ( p_pcr_stream->i_pes_dts > 0 &&
-              p_data->i_dts - 10000000 > p_pcr_stream->i_pes_dts +
+              p_data->i_dts - 10 * CLOCK_FREQ > p_pcr_stream->i_pes_dts +
               p_pcr_stream->i_pes_length ) ||
             p_data->i_dts < p_stream->i_pes_dts ||
             ( p_stream->i_pes_dts > 0 &&
               p_input->p_fmt->i_cat != SPU_ES &&
-              p_data->i_dts - 10000000 > p_stream->i_pes_dts +
+              p_data->i_dts - 10 * CLOCK_FREQ > p_stream->i_pes_dts +
               p_stream->i_pes_length ) )
         {
             msg_Warn( p_mux, "packet with too strange dts "
@@ -1371,8 +1403,8 @@ static bool MuxStreams(sout_mux_t *p_mux )
                 p_spu->p_buffer[1] = 1;
                 p_spu->p_buffer[2] = ' ';
 
-                EStoPES( &p_spu, p_spu, p_input->p_fmt,
-                             p_stream->i_stream_id, 1, 0, 0, 0 );
+                EStoPES( &p_spu, p_input->p_fmt,
+                             p_stream->i_stream_id, 1, 0, 0, 0, p_sys->first_dts );
                 p_data->p_next = p_spu;
             }
             break;
@@ -1417,9 +1449,9 @@ static bool MuxStreams(sout_mux_t *p_mux )
             i_max_pes_size = INT_MAX;
         }
 
-         EStoPES ( &p_data, p_data, p_input->p_fmt, p_stream->i_stream_id,
+        EStoPES ( &p_data, p_input->p_fmt, p_stream->i_stream_id,
                        1, b_data_alignment, i_header_size,
-                       i_max_pes_size );
+                       i_max_pes_size, p_sys->first_dts );
 
         BufferChainAppend( &p_stream->chain_pes, p_data );
 
@@ -1660,19 +1692,8 @@ static block_t *Add_ADTS( block_t *p_data, es_format_t *p_fmt )
 
     int i_channels = (p_extra[i_index == 0x0f ? 4 : 1] >> 3) & 0x0f;
 
-    /* keep a copy in case block_Realloc() fails */
-    block_t *p_bak_block = block_Duplicate( p_data );
-    if( !p_bak_block ) /* OOM, block_Realloc() is likely to lose our block */
-        return p_data; /* the frame isn't correct but that's the best we have */
-
     block_t *p_new_block = block_Realloc( p_data, ADTS_HEADER_SIZE,
                                             p_data->i_buffer );
-    if( !p_new_block )
-        return p_bak_block; /* OOM, send the (incorrect) original frame */
-
-    block_Release( p_bak_block ); /* we don't need the copy anymore */
-
-
     uint8_t *p_buffer = p_new_block->p_buffer;
 
     /* fixed header */
@@ -1787,7 +1808,7 @@ static void TSDate( sout_mux_t *p_mux, sout_buffer_chain_t *p_chain_ts,
         if( p_ts->i_flags & BLOCK_FLAG_CLOCK )
         {
             /* msg_Dbg( p_mux, "pcr=%lld ms", p_ts->i_dts / 1000 ); */
-            TSSetPCR( p_ts, p_ts->i_dts - p_sys->i_dts_delay );
+            TSSetPCR( p_ts, p_ts->i_dts - p_sys->i_dts_delay - p_sys->first_dts );
         }
         if( p_ts->i_flags & BLOCK_FLAG_SCRAMBLED )
         {
@@ -1853,34 +1874,21 @@ static block_t *TSNew( sout_mux_t *p_mux, ts_stream_t *p_stream,
             p_ts->i_flags |= BLOCK_FLAG_CLOCK;
 
             p_ts->p_buffer[4] = 7 + i_stuffing;
-            p_ts->p_buffer[5] = 0x10;   /* flags */
+            p_ts->p_buffer[5] = 1 << 4; /* PCR_flag */
             if( p_stream->b_discontinuity )
             {
                 p_ts->p_buffer[5] |= 0x80; /* flag TS dicontinuity */
                 p_stream->b_discontinuity = false;
             }
-            p_ts->p_buffer[6] = 0 &0xff;
-            p_ts->p_buffer[7] = 0 &0xff;
-            p_ts->p_buffer[8] = 0 &0xff;
-            p_ts->p_buffer[9] = 0 &0xff;
-            p_ts->p_buffer[10]= ( 0 &0x80 ) | 0x7e;
-            p_ts->p_buffer[11]= 0;
-
-            for (int i = 12; i < 12 + i_stuffing; i++ )
-            {
-                p_ts->p_buffer[i] = 0xff;
-            }
+            memset(&p_ts->p_buffer[12], 0xff, i_stuffing);
         }
         else
         {
-            p_ts->p_buffer[4] = i_stuffing - 1;
-            if( i_stuffing > 1 )
+            p_ts->p_buffer[4] = --i_stuffing;
+            if( i_stuffing-- )
             {
-                p_ts->p_buffer[5] = 0x00;
-                for (int i = 6; i < 6 + i_stuffing - 2; i++ )
-                {
-                    p_ts->p_buffer[i] = 0xff;
-                }
+                p_ts->p_buffer[5] = 0;
+                memset(&p_ts->p_buffer[6], 0xff, i_stuffing);
             }
         }
     }
@@ -1927,86 +1935,9 @@ static void TSSetPCR( block_t *p_ts, mtime_t i_dts )
     p_ts->p_buffer[7]  = ( i_pcr >> 17 )&0xff;
     p_ts->p_buffer[8]  = ( i_pcr >> 9  )&0xff;
     p_ts->p_buffer[9]  = ( i_pcr >> 1  )&0xff;
-    p_ts->p_buffer[10]|= ( i_pcr << 7  )&0x80;
-}
-
-static void PEStoTS( sout_buffer_chain_t *c, block_t *p_pes,
-                     ts_stream_t *p_stream )
-{
-    /* get PES total size */
-    uint8_t *p_data = p_pes->p_buffer;
-    int      i_size = p_pes->i_buffer;
-
-    bool    b_new_pes = true;
-
-    for (;;)
-    {
-        /* write header
-         * 8b   0x47    sync byte
-         * 1b           transport_error_indicator
-         * 1b           payload_unit_start
-         * 1b           transport_priority
-         * 13b          pid
-         * 2b           transport_scrambling_control
-         * 2b           if adaptation_field 0x03 else 0x01
-         * 4b           continuity_counter
-         */
-
-        int i_copy = __MIN( i_size, 184 );
-        bool b_adaptation_field = i_size < 184;
-        block_t *p_ts = block_Alloc( 188 );
-
-        p_ts->p_buffer[0] = 0x47;
-        p_ts->p_buffer[1] = ( b_new_pes ? 0x40 : 0x00 )|
-                            ( ( p_stream->i_pid >> 8 )&0x1f );
-        p_ts->p_buffer[2] = p_stream->i_pid & 0xff;
-        p_ts->p_buffer[3] = ( b_adaptation_field ? 0x30 : 0x10 )|
-                            p_stream->i_continuity_counter;
-
-        b_new_pes = false;
-        p_stream->i_continuity_counter = (p_stream->i_continuity_counter+1)%16;
-
-        if( b_adaptation_field )
-        {
-            int i_stuffing = 184 - i_copy;
-
-            p_ts->p_buffer[4] = i_stuffing - 1;
-            if( i_stuffing > 1 )
-            {
-                p_ts->p_buffer[5] = 0x00;
-                if( p_stream->b_discontinuity )
-                {
-                    p_ts->p_buffer[5] |= 0x80;
-                    p_stream->b_discontinuity = false;
-                }
-                for (int i = 6; i < 6 + i_stuffing - 2; i++ )
-                {
-                    p_ts->p_buffer[i] = 0xff;
-                }
-            }
-        }
-        /* copy payload */
-        memcpy( &p_ts->p_buffer[188 - i_copy], p_data, i_copy );
-        p_data += i_copy;
-        i_size -= i_copy;
-
-        BufferChainAppend( c, p_ts );
-
-        if( i_size <= 0 )
-        {
-            block_t *p_next = p_pes->p_next;
-
-            p_pes->p_next = NULL;
-            block_Release( p_pes );
-            if( p_next == NULL )
-                return;
-
-            b_new_pes = true;
-            p_pes = p_next;
-            i_size = p_pes->i_buffer;
-            p_data = p_pes->p_buffer;
-        }
-    }
+    p_ts->p_buffer[10] = ( i_pcr << 7  )&0x80;
+    p_ts->p_buffer[10] |= 0x7e;
+    p_ts->p_buffer[11] = 0; /* we don't set PCR extension */
 }
 
 static block_t *WritePSISection( dvbpsi_psi_section_t* p_section )
@@ -2066,7 +1997,8 @@ static void GetPAT( sout_mux_t *p_mux,
 #endif
     p_pat = WritePSISection( p_section );
 
-    PEStoTS( c, p_pat, &p_sys->pat );
+    PEStoTS( c, (PEStoTSCallback)BufferChainAppend, p_pat, p_sys->pat.i_pid,
+             &p_sys->pat.b_discontinuity, &p_sys->pat.i_continuity_counter );
 
     dvbpsi_DeletePSISections( p_section );
     dvbpsi_EmptyPAT( &pat );
@@ -2285,9 +2217,10 @@ static void GetPMT( sout_mux_t *p_mux, sout_buffer_chain_t *c )
 
     for (int i_stream = 0; i_stream < p_mux->i_nb_inputs; i_stream++ )
     {
-        ts_stream_t *p_stream = (ts_stream_t*)p_mux->pp_inputs[i_stream]->p_sys;
+        sout_input_t *p_input = p_mux->pp_inputs[i_stream];
+        ts_stream_t *p_stream = (ts_stream_t*)p_input->p_sys;
 
-        int i_pidinput = p_mux->pp_inputs[i_stream]->p_fmt->i_id;
+        int i_pidinput = p_input->p_fmt->i_id;
         pmt_map_t *p_usepid = bsearch( &i_pidinput, p_sys->pmtmap,
                     p_sys->i_pmtslots, sizeof(pmt_map_t), intcompare );
 
@@ -2354,6 +2287,17 @@ static void GetPMT( sout_mux_t *p_mux, sout_buffer_chain_t *c )
             uint8_t data[1] = { 0x00 };
             dvbpsi_PMTESAddDescriptor( p_es, 0x7a, 1, data );
         }
+        else if( p_stream->i_codec == VLC_CODEC_OPUS )
+        {
+            uint8_t data[2] = {
+                0x80, /* tag extension */
+                p_input->p_fmt->audio.i_channels
+            };
+            dvbpsi_PMTESAddDescriptor( p_es, 0x7f, 2, data );
+            uint8_t format[4] = { 'O', 'p', 'u', 's'};
+            /* "registration" descriptor : "Opus" */
+            dvbpsi_PMTESAddDescriptor( p_es, 0x05, 4, format );
+        }
         else if( p_stream->i_codec == VLC_CODEC_TELETEXT )
         {
             if( p_stream->i_extra )
@@ -2413,7 +2357,8 @@ static void GetPMT( sout_mux_t *p_mux, sout_buffer_chain_t *c )
         sect = dvbpsi_GenPMTSections( &p_sys->dvbpmt[i] );
 #endif
         block_t *pmt = WritePSISection( sect );
-        PEStoTS( c, pmt, &p_sys->pmt[i] );
+        PEStoTS( c, (PEStoTSCallback)BufferChainAppend, pmt, p_sys->pmt[i].i_pid,
+                 &p_sys->pmt[i].b_discontinuity, &p_sys->pmt[i].i_continuity_counter );
         dvbpsi_DeletePSISections(sect);
         dvbpsi_EmptyPMT( &p_sys->dvbpmt[i] );
     }
@@ -2427,7 +2372,8 @@ static void GetPMT( sout_mux_t *p_mux, sout_buffer_chain_t *c )
         sect = dvbpsi_GenSDTSections( &sdt );
 #endif
         block_t *p_sdt = WritePSISection( sect );
-        PEStoTS( c, p_sdt, &p_sys->sdt );
+        PEStoTS( c, (PEStoTSCallback)BufferChainAppend, p_sdt, p_sys->sdt.i_pid,
+                 &p_sys->sdt.b_discontinuity, &p_sys->sdt.i_continuity_counter );
         dvbpsi_DeletePSISections( sect );
         dvbpsi_EmptySDT( &sdt );
     }