]> git.sesse.net Git - vlc/blobdiff - modules/mux/mpeg/ts.c
mux: ts: split ts encapsulation
[vlc] / modules / mux / mpeg / ts.c
index c29dfec948ba44860c6b79f8dae380b3638bb11e..df7ffd25be98162b8187fb6af609d1c98a822be3 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * ts.c: MPEG-II TS Muxer
  *****************************************************************************
- * Copyright (C) 2001-2005 the VideoLAN team
+ * Copyright (C) 2001-2005 VLC authors and VideoLAN
  * $Id$
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
@@ -9,19 +9,19 @@
  *          Jean-Paul Saman <jpsaman #_at_# m2x.nl>
  *          Wallace Wadge <wwadge #_at_# gmail.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /*****************************************************************************
@@ -45,6 +45,7 @@
 #include "bits.h"
 #include "pes.h"
 #include "csa.h"
+#include "tsutil.h"
 
 # include <dvbpsi/dvbpsi.h>
 # include <dvbpsi/demux.h>
@@ -55,6 +56,8 @@
 # include <dvbpsi/dr.h>
 # include <dvbpsi/psi.h>
 
+#include "dvbpsi_compat.h"
+
 /*
  * TODO:
  *  - check PCR frequency requirement
@@ -340,6 +343,9 @@ struct sout_mux_sys_t
 
     vlc_mutex_t     csa_lock;
 
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+    dvbpsi_t        *p_dvbpsi;
+#endif
     bool            b_es_id_pid;
     bool            b_sdt;
     int             i_pid_video;
@@ -374,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;
 
@@ -511,11 +518,16 @@ static int Open( vlc_object_t *p_this )
         return VLC_ENOMEM;
     p_sys->i_num_pmt = 1;
 
-    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;
+
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+    p_sys->p_dvbpsi = dvbpsi_new( &dvbpsi_messages, DVBPSI_MSG_DEBUG );
+    if( !p_sys->p_dvbpsi )
+    {
+        free( p_sys );
+        return VLC_ENOMEM;
+    }
+    p_sys->p_dvbpsi->p_sys = (void *) p_mux;
+#endif
 
     p_sys->b_es_id_pid = var_GetBool( p_mux, SOUT_CFG_PREFIX "es-id-pid" );
 
@@ -542,10 +554,10 @@ static int Open( vlc_object_t *p_this )
         {
             p_sys->pmtmap[p_sys->i_pmtslots].i_pid = i_pid;
             p_sys->pmtmap[p_sys->i_pmtslots].i_prog = p_sys->i_num_pmt - 1;
-            if ( ++p_sys->i_pmtslots > MAX_PMT_PID )
+            if ( ++p_sys->i_pmtslots >= MAX_PMT_PID )
             {
                 msg_Err( p_mux, "Number of pids in PMT > %d", MAX_PMT_PID );
-                p_sys->i_pmtslots = MAX_PMT_PID;
+                p_sys->i_pmtslots = MAX_PMT_PID - 1;
             }
         }
     }
@@ -618,7 +630,7 @@ static int Open( vlc_object_t *p_this )
 
             if( i_pid == 0 )
             {
-                if( i > MAX_PMT )
+                if( i >= MAX_PMT )
                     msg_Err( p_mux, "Number of PMTs > maximum (%d)", MAX_PMT );
             }
             else
@@ -712,8 +724,15 @@ 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;
+
     return VLC_SUCCESS;
 }
 
@@ -725,6 +744,11 @@ static void Close( vlc_object_t * p_this )
     sout_mux_t          *p_mux = (sout_mux_t*)p_this;
     sout_mux_sys_t      *p_sys = p_mux->p_sys;
 
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+    if( p_sys->p_dvbpsi )
+        dvbpsi_delete( p_sys->p_dvbpsi );
+#endif
+
     if( p_sys->csa )
     {
         var_DelCallback( p_mux, SOUT_CFG_PREFIX "csa-ck", ChangeKeyCallback, NULL );
@@ -874,6 +898,8 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
     /* VIDEO */
 
     case VLC_CODEC_MPGV:
+    case VLC_CODEC_MP2V:
+    case VLC_CODEC_MP1V:
         /* TODO: do we need to check MPEG-I/II ? */
         p_stream->i_stream_type = 0x02;
         p_stream->i_stream_id = 0xe0;
@@ -883,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;
@@ -912,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;
@@ -920,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;
@@ -938,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;
 
@@ -967,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;
     }
@@ -1082,8 +1117,11 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
     return VLC_SUCCESS;
 
 oom:
-    free(p_stream->lang);
-    free(p_stream);
+    if(p_stream)
+    {
+        free(p_stream->lang);
+        free(p_stream);
+    }
     return VLC_ENOMEM;
 }
 
@@ -1173,6 +1211,32 @@ static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
     return VLC_SUCCESS;
 }
 
+static void SetHeader( sout_buffer_chain_t *c,
+                        int depth )
+{
+    block_t *p_ts = BufferChainPeek( c );
+    while( depth > 0 )
+    {
+        p_ts = p_ts->p_next;
+        depth--;
+    }
+    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 )
 {
@@ -1233,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;
@@ -1251,12 +1315,17 @@ 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)
+                p_data->i_pts = p_data->i_dts;
 
             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 );
@@ -1271,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 "
@@ -1321,7 +1393,7 @@ static bool MuxStreams(sout_mux_t *p_mux )
             if( p_data->i_length > 0 &&
                 ( p_data->i_buffer != 1 || *p_data->p_buffer != ' ' ) )
             {
-                block_t *p_spu = block_New( p_mux, 3 );
+                block_t *p_spu = block_Alloc( 3 );
 
                 p_spu->i_dts = p_data->i_dts + p_data->i_length;
                 p_spu->i_pts = p_spu->i_dts;
@@ -1331,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;
@@ -1377,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 );
 
@@ -1430,6 +1502,7 @@ static bool MuxStreams(sout_mux_t *p_mux )
     /* 3: mux PES into TS */
     BufferChainInit( &chain_ts );
     /* append PAT/PMT  -> FIXME with big pcr delay it won't have enough pat/pmt */
+    bool pat_was_previous = true; //This is to prevent unnecessary double PAT/PMT insertions
     GetPAT( p_mux, &chain_ts );
     GetPMT( p_mux, &chain_ts );
     int i_packet_pos = 0;
@@ -1487,6 +1560,24 @@ static bool MuxStreams(sout_mux_t *p_mux )
         }
         i_packet_pos++;
 
+        /* Write PAT/PMT before every keyframe if use-key-frames is enabled,
+         * this helps to do segmenting with livehttp-output so it can cut segment
+         * and start new one with pat,pmt,keyframe*/
+        if( ( p_sys->b_use_key_frames ) && ( p_ts->i_flags & BLOCK_FLAG_TYPE_I ) )
+        {
+            if( likely( !pat_was_previous ) )
+            {
+                int startcount = chain_ts.i_depth;
+                GetPAT( p_mux, &chain_ts );
+                GetPMT( p_mux, &chain_ts );
+                SetHeader( &chain_ts, startcount );
+                i_packet_count += (chain_ts.i_depth - startcount );
+            } else {
+                SetHeader( &chain_ts, 0); //We just inserted pat/pmt,so just flag it instead of adding new one
+            }
+        }
+        pat_was_previous = false;
+
         /* */
         BufferChainAppend( &chain_ts, p_ts );
     }
@@ -1536,7 +1627,7 @@ static block_t *FixPES( sout_mux_t *p_mux, block_fifo_t *p_fifo )
     }
     else if( i_size > STD_PES_PAYLOAD )
     {
-        block_t *p_new = block_New( p_mux, STD_PES_PAYLOAD );
+        block_t *p_new = block_Alloc( STD_PES_PAYLOAD );
         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;
@@ -1601,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 */
@@ -1728,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 )
         {
@@ -1767,7 +1847,7 @@ static block_t *TSNew( sout_mux_t *p_mux, ts_stream_t *p_stream,
         b_adaptation_field = true;
     }
 
-    block_t *p_ts = block_New( p_mux, 188 );
+    block_t *p_ts = block_Alloc( 188 );
 
     if (b_new_pes && !(p_pes->i_flags & BLOCK_FLAG_NO_KEYFRAME) && p_pes->i_flags & BLOCK_FLAG_TYPE_I)
     {
@@ -1794,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);
             }
         }
     }
@@ -1868,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 )
@@ -1960,6 +1950,8 @@ static block_t *WritePSISection( dvbpsi_psi_section_t* p_section )
                   (p_section->b_syntax_indicator ? 4 : 0);
 
         p_psi = block_Alloc( i_size + 1 );
+        if( !p_psi )
+            goto error;
         p_psi->i_pts = 0;
         p_psi->i_dts = 0;
         p_psi->i_length = 0;
@@ -1976,6 +1968,11 @@ static block_t *WritePSISection( dvbpsi_psi_section_t* p_section )
     }
 
     return( p_first );
+
+error:
+    if( p_first )
+        block_ChainRelease( p_first );
+    return NULL;
 }
 
 static void GetPAT( sout_mux_t *p_mux,
@@ -1993,11 +1990,15 @@ static void GetPAT( sout_mux_t *p_mux,
         dvbpsi_PATAddProgram( &pat, p_sys->i_pmt_program_number[i],
                               p_sys->pmt[i].i_pid );
 
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+    p_section = dvbpsi_pat_sections_generate( p_sys->p_dvbpsi, &pat, 0 );
+#else
     p_section = dvbpsi_GenPATSections( &pat, 0 /* max program per section */ );
-
+#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 );
@@ -2201,8 +2202,14 @@ static void GetPMT( sout_mux_t *p_mux, sout_buffer_chain_t *c )
         psz_sdt_desc[ 2 + provlen ] = (char)servlen;
         memcpy( &psz_sdt_desc[3+provlen], psz_sdtserv, servlen );
 
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+        dvbpsi_sdt_service_descriptor_add( p_service, 0x48,
+                                           (3 + provlen + servlen),
+                                           psz_sdt_desc );
+#else
         dvbpsi_SDTServiceAddDescriptor( p_service, 0x48,
                 3 + provlen + servlen, psz_sdt_desc );
+#endif
     }
 
     if( p_sys->i_mpeg4_streams > 0 )
@@ -2210,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 );
 
@@ -2279,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 )
@@ -2331,18 +2350,30 @@ static void GetPMT( sout_mux_t *p_mux, sout_buffer_chain_t *c )
 
     for (unsigned i = 0; i < p_sys->i_num_pmt; i++ )
     {
-        dvbpsi_psi_section_t *sect = dvbpsi_GenPMTSections( &p_sys->dvbpmt[i] );
+        dvbpsi_psi_section_t *sect;
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+        sect = dvbpsi_pmt_sections_generate( p_sys->p_dvbpsi, &p_sys->dvbpmt[i] );
+#else
+        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] );
     }
 
     if( p_sys->b_sdt )
     {
-        dvbpsi_psi_section_t *sect = dvbpsi_GenSDTSections( &sdt );
+        dvbpsi_psi_section_t *sect;
+#if (DVBPSI_VERSION_INT >= DVBPSI_VERSION_WANTED(1,0,0))
+        sect = dvbpsi_sdt_sections_generate( p_sys->p_dvbpsi, &sdt );
+#else
+        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 );
     }