]> git.sesse.net Git - vlc/commitdiff
demux: ts: rewrite/split IOD parsing
authorFrancois Cartegnie <fcvlcdev@free.fr>
Thu, 26 Mar 2015 22:13:41 +0000 (23:13 +0100)
committerFrancois Cartegnie <fcvlcdev@free.fr>
Fri, 27 Mar 2015 13:39:07 +0000 (14:39 +0100)
Fixes read overflows.

modules/demux/Makefile.am
modules/demux/mpeg4_iod.c [new file with mode: 0644]
modules/demux/mpeg4_iod.h [new file with mode: 0644]
modules/demux/ts.c

index 78dc9156ef015e37cf3220c333a4478e25b5241f..cd8a5bdef1ce3939617ff7755c8d842fce3a4b96 100644 (file)
@@ -227,6 +227,7 @@ libplaylist_plugin_la_SOURCES = \
 demux_LTLIBRARIES += libplaylist_plugin.la
 
 libts_plugin_la_SOURCES = demux/ts.c \
+        demux/mpeg4_iod.c demux/mpeg4_iod.h \
        mux/mpeg/csa.c mux/mpeg/dvbpsi_compat.h \
        mux/mpeg/streams.h mux/mpeg/tables.c mux/mpeg/tables.h \
        mux/mpeg/tsutil.c mux/mpeg/tsutil.h \
diff --git a/modules/demux/mpeg4_iod.c b/modules/demux/mpeg4_iod.c
new file mode 100644 (file)
index 0000000..b827656
--- /dev/null
@@ -0,0 +1,401 @@
+/*****************************************************************************
+ * mpeg4_iod.c: ISO 14496-1 IOD and parsers
+ *****************************************************************************
+ * Copyright (C) 2004-2015 VLC authors and VideoLAN
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * 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.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+
+#include "mpeg4_iod.h"
+
+//#define IOD_DEBUG 1
+static void iod_debug( vlc_object_t *p_object, const char *format, ... )
+{
+#ifdef IOD_DEBUG
+    va_list ap;
+    va_start(ap, format);
+    msg_GenericVa( p_object, VLC_MSG_DBG, format, ap );
+    va_end(ap);
+#else
+    VLC_UNUSED(format);
+    VLC_UNUSED(p_object);
+#endif
+}
+
+/*****************************************************************************
+ * MP4 specific functions (IOD parser)
+ *****************************************************************************/
+static unsigned IODDescriptorLength( unsigned *pi_data, const uint8_t **pp_data )
+{
+    unsigned int i_b;
+    unsigned int i_len = 0;
+
+    if(*pi_data == 0)
+        return 0;
+
+    do
+    {
+        i_b = **pp_data;
+        (*pp_data)++;
+        (*pi_data)--;
+        i_len = ( i_len << 7 ) + ( i_b&0x7f );
+
+    } while( i_b&0x80 && *pi_data > 0 );
+
+    if (i_len > *pi_data)
+        i_len = *pi_data;
+
+    return i_len;
+}
+
+static unsigned IODGetBytes( unsigned *pi_data, const uint8_t **pp_data, size_t bytes )
+{
+    unsigned res = 0;
+    while( *pi_data > 0 && bytes-- )
+    {
+        res <<= 8;
+        res |= **pp_data;
+        (*pp_data)++;
+        (*pi_data)--;
+    }
+
+    return res;
+}
+
+static char* IODGetURL( unsigned *pi_data, const uint8_t **pp_data )
+{
+    unsigned len = IODGetBytes( pi_data, pp_data, 1 );
+    if (len > *pi_data)
+        len = *pi_data;
+    char *url = strndup( (char*)*pp_data, len );
+    *pp_data += len;
+    *pi_data -= len;
+    return url;
+}
+
+#define IODTag_ObjectDescr           0x01
+#define IODTag_InitialObjectDescr    0x02
+#define IODTag_ESDescr               0x03
+#define IODTag_DecConfigDescr        0x04
+#define IODTag_DecSpecificDescr      0x05
+#define IODTag_SLDescr               0x06
+
+/* Unified pointer for read helper */
+typedef union
+{
+    iod_descriptor_t *p_iod;
+    es_mpeg4_descriptor_t *es_descr;
+    decoder_config_descriptor_t *p_dec_config;
+} iod_read_params_t;
+
+static uint8_t IOD_Desc_Read( vlc_object_t *, unsigned *, const uint8_t **, uint8_t, uint8_t, iod_read_params_t params );
+
+static bool IOD_SLDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data,
+                             iod_read_params_t params )
+{
+    VLC_UNUSED(p_object);
+    VLC_UNUSED(i_data);
+    VLC_UNUSED(p_data);
+    VLC_UNUSED(params);
+    return true;
+}
+
+static bool IOD_DecSpecificDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data,
+                                      iod_read_params_t params )
+{
+    VLC_UNUSED(p_object);
+    decoder_config_descriptor_t *p_dec_config = params.p_dec_config;
+
+    p_dec_config->p_extra = malloc( i_data );
+    if( p_dec_config->p_extra )
+    {
+        p_dec_config->i_extra = i_data;
+        memcpy( p_dec_config->p_extra, p_data, p_dec_config->i_extra );
+    }
+
+    return !!p_dec_config->i_extra;
+}
+
+static bool IOD_DecConfigDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data,
+                                    iod_read_params_t params )
+{
+    decoder_config_descriptor_t *p_dec_config = params.p_dec_config;
+
+    if( i_data < 13 )
+        return false;
+
+    p_dec_config->i_objectTypeIndication = IODGetBytes( &i_data, &p_data, 1 );
+    uint8_t i_flags = IODGetBytes( &i_data, &p_data, 1 );
+    p_dec_config->i_streamType = i_flags >> 2;
+
+    IODGetBytes( &i_data, &p_data, 3 ); /* bufferSizeDB */
+    IODGetBytes( &i_data, &p_data, 4 ); /* maxBitrate */
+    IODGetBytes( &i_data, &p_data, 4 ); /* avgBitrate */
+
+    /* DecoderSpecificDescr */
+    IOD_Desc_Read( p_object, &i_data, &p_data,
+                   IODTag_DecSpecificDescr, 1, params );
+
+    iod_debug( p_object, "   * read decoder objecttype: %x streamtype:%x extra: %u",
+               p_dec_config->i_objectTypeIndication, p_dec_config->i_streamType, p_dec_config->i_extra );
+    /* ProfileLevelIndicator [0..255] */
+    return true;
+}
+
+static bool IOD_ESDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data,
+                             iod_read_params_t params )
+{
+    es_mpeg4_descriptor_t *es_descr = params.es_descr;
+
+    if ( i_data < 3 )
+        return false;
+    es_descr->i_es_id = IODGetBytes( &i_data, &p_data, 2 );
+    uint8_t i_flags = IODGetBytes( &i_data, &p_data, 1 );
+
+    if( ( i_flags >> 7 )&0x01 )
+    {
+        if ( i_data < 2 )
+            return false;
+        IODGetBytes( &i_data, &p_data, 2 ); /* dependOn_es_id */
+    }
+
+    if( (i_flags >> 6) & 0x01 )
+        es_descr->psz_url = IODGetURL( &i_data, &p_data );
+
+    if( ( i_flags >> 5 )&0x01 )
+    {
+        if ( i_data < 2 )
+            return false;
+        IODGetBytes( &i_data, &p_data, 2 ); /* OCR_es_id */
+    }
+
+    iod_debug( p_object, "   * read ES Descriptor for es id %"PRIx16, es_descr->i_es_id );
+
+    /* DecoderConfigDescr */
+    params.p_dec_config = &es_descr->dec_descr;
+    if ( 1 != IOD_Desc_Read( p_object, &i_data, &p_data,
+                             IODTag_DecConfigDescr, 1, params ) )
+        return false;
+
+    /* SLDescr */
+    IOD_Desc_Read( p_object, &i_data, &p_data, IODTag_SLDescr, 1, params );
+
+    /* IPI / IP / IPMP ... */
+
+    es_descr->b_ok = true;
+
+    return true;
+}
+
+static bool IOD_InitialObjectDesc_Read( vlc_object_t *p_object, unsigned i_data,
+                                        const uint8_t *p_data, iod_read_params_t params )
+{
+    iod_descriptor_t *p_iod = params.p_iod;
+    if( i_data < 3 + 5 + 2 )
+        return false;
+
+    uint16_t i_object_descriptor_id = ( IODGetBytes( &i_data, &p_data, 1 ) << 2 );
+    uint8_t i_flags = IODGetBytes( &i_data, &p_data, 1 );
+    i_object_descriptor_id |= i_flags >> 6;
+
+    iod_debug( p_object, "  * ObjectDescriptorID: %"PRIu16, i_object_descriptor_id );
+    iod_debug( p_object, "  * includeInlineProfileLevel flag: 0x%"PRIx8, ( i_flags >> 4 )&0x01 );
+    if ( (i_flags >> 5) & 0x01 )
+    {
+        p_iod->psz_url = IODGetURL( &i_data, &p_data );
+        iod_debug( p_object, "  * URL: %s", p_iod->psz_url );
+        return true; /* leaves out unparsed remaining extdescr */
+    }
+
+    if( i_data < 5 + 2 ) /* at least one ES desc */
+        return false;
+
+    /* Profile Level Indication */
+    IODGetBytes( &i_data, &p_data, 1 ); /* OD */
+    IODGetBytes( &i_data, &p_data, 1 ); /* scene */
+    IODGetBytes( &i_data, &p_data, 1 ); /* audio */
+    IODGetBytes( &i_data, &p_data, 1 ); /* visual */
+    IODGetBytes( &i_data, &p_data, 1 ); /* graphics */
+
+    /* Now read */
+    /* 1..255 ESdescr */
+    uint8_t i_desc_count = IOD_Desc_Read( p_object, &i_data, &p_data,
+                                          IODTag_ESDescr, ES_DESCRIPTOR_COUNT, params );
+    if( i_desc_count == 0 )
+    {
+        iod_debug( p_object, "   * missing ES Descriptor" );
+        return false;
+    }
+
+    /* 0..255 OCIdescr */
+    /* 0..255 IPMPdescpointer */
+    /* 0..255 IPMPdesc */
+    /* 0..1   IPMPtoollistdesc */
+    /* 0..255 Extensiondescr */
+
+    return true;
+}
+
+static uint8_t IOD_Desc_Read( vlc_object_t *p_object, unsigned *pi_data, const uint8_t **pp_data,
+                              uint8_t i_target_tag, uint8_t i_max_desc, iod_read_params_t params )
+{
+    uint8_t i_read_count = 0;
+
+    for (unsigned i = 0; *pi_data > 2 && i < i_max_desc; i++)
+    {
+        const uint8_t i_tag = IODGetBytes( pi_data, pp_data, 1 );
+        const unsigned i_length = IODDescriptorLength( pi_data, pp_data );
+        if( i_target_tag != i_tag || i_length > *pi_data )
+            break;
+
+        unsigned i_descriptor_data = i_length;
+        const uint8_t *p_descriptor_data = *pp_data;
+
+        iod_debug( p_object, "  Reading descriptor 0x%"PRIx8": found tag 0x%"PRIx8" left %d",
+                   i_target_tag, i_tag, *pi_data );
+        switch( i_tag )
+        {
+            case IODTag_InitialObjectDescr:
+            {
+                /* iod_descriptor_t *p_iod = (iod_descriptor_t *) param; */
+                if ( !IOD_InitialObjectDesc_Read( p_object, i_descriptor_data,
+                                                  p_descriptor_data, params ) )
+                {};
+                break;
+            }
+
+            case IODTag_ESDescr: /**/
+            {
+                iod_descriptor_t *p_iod = params.p_iod;
+                params.es_descr = &p_iod->es_descr[i_read_count];
+                if ( !IOD_ESDesc_Read( p_object, i_descriptor_data,
+                                       p_descriptor_data, params ) )
+                {};
+                break;
+            }
+
+            case IODTag_DecConfigDescr:
+            {
+                if ( !IOD_DecConfigDesc_Read( p_object, i_descriptor_data,
+                                              p_descriptor_data, params ) )
+                {};
+                break;
+            }
+
+            case IODTag_DecSpecificDescr:
+            {
+                if ( !IOD_DecSpecificDesc_Read( p_object, i_descriptor_data,
+                                                p_descriptor_data, params ) )
+                {};
+                break;
+            }
+
+            case IODTag_SLDescr:
+            {
+                if ( !IOD_SLDesc_Read( p_object, i_descriptor_data,
+                                       p_descriptor_data, params ) )
+                {};
+                break;
+            }
+
+            default:
+                iod_debug( p_object, "trying to read unsupported descriptor" );
+                break;
+        }
+
+        *pp_data += i_length;
+        *pi_data -= i_length;
+
+        i_read_count++;
+    }
+
+    return i_read_count;
+}
+
+iod_descriptor_t *IODNew( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data )
+{
+    if( i_data < 4 )
+        return NULL;
+
+    uint8_t i_iod_scope = IODGetBytes( &i_data, &p_data, 1 ); /* scope */
+    uint8_t i_iod_label = IODGetBytes( &i_data, &p_data, 1 );
+    if( i_iod_label == 0x02 ) /* old vlc's buggy implementation of the IOD_descriptor */
+    {
+        i_iod_label = i_iod_scope;
+        i_iod_scope = 0x10; /* Add the missing front iod scope byte */
+        i_data++; p_data--; /* next byte must be tag */
+    }
+
+    iod_debug( p_object, "  * iod label:0x%"PRIx8" scope:0x%"PRIx8,
+               i_iod_label, i_iod_scope );
+
+    if( i_iod_scope != 0x10 && i_iod_scope != 0x11 ) /* Uniqueness in program or transport */
+    {
+        iod_debug( p_object, "  * can't handle reserved scope 0x%"PRIx8, i_iod_scope );
+        return NULL;
+    }
+
+    /* Initial Object Descriptor must follow */
+    iod_descriptor_t *p_iod = calloc( 1, sizeof( iod_descriptor_t ) );
+    if( !p_iod )
+        return NULL;
+
+    /* IOD_InitialObjectDescrTag Parsing */
+    iod_read_params_t params;
+    params.p_iod = p_iod;
+    if ( 1 != IOD_Desc_Read( p_object, &i_data, &p_data,
+                             IODTag_InitialObjectDescr, 1, params ) )
+    {
+        iod_debug( p_object, "   cannot read InitialObjectDescr" );
+        free( p_iod );
+        return NULL;
+    }
+
+    return p_iod;
+}
+
+void IODFree( iod_descriptor_t *p_iod )
+{
+    if( p_iod->psz_url )
+    {
+        free( p_iod->psz_url );
+        free( p_iod );
+        return;
+    }
+
+    for( int i = 0; i < 255; i++ )
+    {
+#define es_descr p_iod->es_descr[i]
+        if( es_descr.b_ok )
+        {
+            if( es_descr.psz_url )
+                free( es_descr.psz_url );
+            else
+                free( es_descr.dec_descr.p_extra );
+        }
+#undef  es_descr
+    }
+    free( p_iod );
+}
diff --git a/modules/demux/mpeg4_iod.h b/modules/demux/mpeg4_iod.h
new file mode 100644 (file)
index 0000000..af47b2b
--- /dev/null
@@ -0,0 +1,54 @@
+/*****************************************************************************
+ * mpeg4_iod.h: ISO 14496-1 IOD and parsers
+ *****************************************************************************
+ * Copyright (C) 2004-2015 VLC authors and VideoLAN
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * 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.
+ *****************************************************************************/
+
+#define ES_DESCRIPTOR_COUNT 255
+
+typedef struct
+{
+    uint8_t                 i_objectTypeIndication;
+    uint8_t                 i_streamType;
+
+    unsigned                i_extra;
+    uint8_t                 *p_extra;
+
+} decoder_config_descriptor_t;
+
+typedef struct
+{
+    bool                    b_ok;
+    uint16_t                i_es_id;
+
+    char                    *psz_url;
+
+    decoder_config_descriptor_t    dec_descr;
+
+} es_mpeg4_descriptor_t;
+
+typedef struct
+{
+    /* IOD */
+    char                    *psz_url;
+
+    es_mpeg4_descriptor_t   es_descr[ES_DESCRIPTOR_COUNT];
+
+} iod_descriptor_t;
+
+iod_descriptor_t *IODNew( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data );
+void IODFree( iod_descriptor_t *p_iod );
index 051bdde1e3bbd0259099a1e887586964f5d7d719..2e36f05ba63187b56a3e817602684341b486d7b1 100644 (file)
 
 #include "opus.h"
 
-#undef TS_DEBUG
-VLC_FORMAT(1, 2) static void ts_debug(const char *format, ...)
-{
-#ifdef TS_DEBUG
-    va_list ap;
-    va_start(ap, format);
-    vfprintf(stderr, format, ap);
-    va_end(ap);
-#else
-    (void)format;
-#endif
-}
+#include "mpeg4_iod.h"
 
 #ifdef HAVE_ARIBB24
  #include <aribb24/aribb24.h>
@@ -204,37 +193,6 @@ static const char *const ppsz_teletext_type[] = {
 
 typedef struct ts_pid_t ts_pid_t;
 
-typedef struct
-{
-    uint8_t                 i_objectTypeIndication;
-    uint8_t                 i_streamType;
-
-    unsigned                i_extra;
-    uint8_t                 *p_extra;
-
-} decoder_config_descriptor_t;
-
-typedef struct
-{
-    bool                    b_ok;
-    uint16_t                i_es_id;
-
-    char                    *psz_url;
-
-    decoder_config_descriptor_t    dec_descr;
-
-} es_mpeg4_descriptor_t;
-
-#define ES_DESCRIPTOR_COUNT 255
-typedef struct
-{
-    /* IOD */
-    char                    *psz_url;
-
-    es_mpeg4_descriptor_t   es_descr[ES_DESCRIPTOR_COUNT];
-
-} iod_descriptor_t;
-
 typedef struct
 {
     int             i_version;
@@ -521,8 +479,6 @@ static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * );
 static void PCRFixHandle( demux_t *, ts_pmt_t *, block_t * );
 static int64_t TimeStampWrapAround( ts_pmt_t *, int64_t );
 
-static void              IODFree( iod_descriptor_t * );
-
 #define TS_USER_PMT_NUMBER (0)
 static int UserPmt( demux_t *p_demux, const char * );
 
@@ -3400,227 +3356,6 @@ static void PIDFillFormat( es_format_t *fmt, int i_stream_type )
     fmt->b_packetized = false;
 }
 
-/*****************************************************************************
- * MP4 specific functions (IOD parser)
- *****************************************************************************/
-static unsigned IODDescriptorLength( unsigned *pi_data, uint8_t **pp_data )
-{
-    unsigned int i_b;
-    unsigned int i_len = 0;
-    do
-    {
-        i_b = **pp_data;
-        (*pp_data)++;
-        (*pi_data)--;
-        i_len = ( i_len << 7 ) + ( i_b&0x7f );
-
-    } while( i_b&0x80 && *pi_data > 0 );
-
-    if (i_len > *pi_data)
-        i_len = *pi_data;
-
-    return i_len;
-}
-
-static unsigned IODGetBytes( unsigned *pi_data, uint8_t **pp_data, size_t bytes )
-{
-    unsigned res = 0;
-    while( *pi_data > 0 && bytes-- )
-    {
-        res <<= 8;
-        res |= **pp_data;
-        (*pp_data)++;
-        (*pi_data)--;
-    }
-
-    return res;
-}
-
-static char* IODGetURL( unsigned *pi_data, uint8_t **pp_data )
-{
-    unsigned len = IODGetBytes( pi_data, pp_data, 1 );
-    if (len > *pi_data)
-        len = *pi_data;
-    char *url = strndup( (char*)*pp_data, len );
-    *pp_data += len;
-    *pi_data -= len;
-    return url;
-}
-
-static iod_descriptor_t *IODNew( unsigned i_data, uint8_t *p_data )
-{
-    uint8_t i_iod_tag, i_iod_label, byte1, byte2, byte3;
-
-    iod_descriptor_t *p_iod = calloc( 1, sizeof( iod_descriptor_t ) );
-    if( !p_iod )
-        return NULL;
-
-    if( i_data < 3 )
-    {
-        return p_iod;
-    }
-
-    byte1 = IODGetBytes( &i_data, &p_data, 1 );
-    byte2 = IODGetBytes( &i_data, &p_data, 1 );
-    byte3 = IODGetBytes( &i_data, &p_data, 1 );
-    if( byte2 == 0x02 ) //old vlc's buggy implementation of the IOD_descriptor
-    {
-        i_iod_label = byte1;
-        i_iod_tag = byte2;
-    }
-    else  //correct implementation of the IOD_descriptor
-    {
-        i_iod_label = byte2;
-        i_iod_tag = byte3;
-    }
-
-    ts_debug( "\n* iod label:%d tag:0x%x", i_iod_label, i_iod_tag );
-
-    if( i_iod_tag != 0x02 )
-    {
-        ts_debug( "\n ERR: tag %02x != 0x02", i_iod_tag );
-        return p_iod;
-    }
-
-    IODDescriptorLength( &i_data, &p_data );
-
-    uint16_t i_od_id = ( IODGetBytes( &i_data, &p_data, 1 ) << 2 );
-    uint8_t i_flags = IODGetBytes( &i_data, &p_data, 1 );
-    i_od_id |= i_flags >> 6;
-    ts_debug( "\n* od_id:%d", i_od_id );
-    ts_debug( "\n* includeInlineProfileLevel flag:%d", ( i_flags >> 4 )&0x01 );
-    if ((i_flags >> 5) & 0x01)
-    {
-        p_iod->psz_url = IODGetURL( &i_data, &p_data );
-        ts_debug( "\n* url string:%s", p_iod->psz_url );
-        ts_debug( "\n*****************************\n" );
-        return p_iod;
-    }
-    else
-    {
-        p_iod->psz_url = NULL;
-    }
-
-    /* Profile Level Indication */
-    IODGetBytes( &i_data, &p_data, 1 ); /* OD */
-    IODGetBytes( &i_data, &p_data, 1 ); /* scene */
-    IODGetBytes( &i_data, &p_data, 1 ); /* audio */
-    IODGetBytes( &i_data, &p_data, 1 ); /* visual */
-    IODGetBytes( &i_data, &p_data, 1 ); /* graphics */
-
-    unsigned i_length = 0;
-    unsigned i_data_sav = i_data;
-    uint8_t *p_data_sav = p_data;
-    for (unsigned i = 0; i_data > 0 && i < ES_DESCRIPTOR_COUNT; i++)
-    {
-        es_mpeg4_descriptor_t *es_descr = &p_iod->es_descr[i];
-
-        p_data = p_data_sav + i_length;
-        i_data = i_data_sav - i_length;
-
-        uint8_t i_tag = IODGetBytes( &i_data, &p_data, 1 );
-        i_length = IODDescriptorLength( &i_data, &p_data );
-
-        i_data_sav = i_data;
-        p_data_sav = p_data;
-
-        i_data = i_length;
-
-        if ( i_tag != 0x03 )
-        {
-            ts_debug( "\n* - OD tag:0x%x Unsupported", i_tag );
-            continue;
-        }
-
-        es_descr->i_es_id = IODGetBytes( &i_data, &p_data, 2 );
-        uint8_t i_flags = IODGetBytes( &i_data, &p_data, 1 );
-        bool b_streamDependenceFlag = ( i_flags >> 7 )&0x01;
-        if( b_streamDependenceFlag )
-            IODGetBytes( &i_data, &p_data, 2 ); /* dependOn_es_id */
-
-        if( (i_flags >> 6) & 0x01 )
-            es_descr->psz_url = IODGetURL( &i_data, &p_data );
-
-        bool b_OCRStreamFlag = ( i_flags >> 5 )&0x01;
-        if( b_OCRStreamFlag )
-            IODGetBytes( &i_data, &p_data, 2 ); /* OCR_es_id */
-
-        if( IODGetBytes( &i_data, &p_data, 1 ) != 0x04 )
-        {
-            ts_debug( "\n* ERR missing DecoderConfigDescr" );
-            continue;
-        }
-        unsigned i_config_desc_length = IODDescriptorLength( &i_data, &p_data ); /* DecoderConfigDescr_length */
-        decoder_config_descriptor_t *dec_descr = &es_descr->dec_descr;
-        dec_descr->i_objectTypeIndication = IODGetBytes( &i_data, &p_data, 1 );
-        i_flags = IODGetBytes( &i_data, &p_data, 1 );
-        dec_descr->i_streamType = i_flags >> 2;
-
-        IODGetBytes( &i_data, &p_data, 3); /* bufferSizeDB */
-        IODGetBytes( &i_data, &p_data, 4); /* maxBitrate */
-        IODGetBytes( &i_data, &p_data, 4 ); /* avgBitrate */
-
-        if( i_config_desc_length > 13 && IODGetBytes( &i_data, &p_data, 1 ) == 0x05 )
-        {
-            dec_descr->i_extra = IODDescriptorLength( &i_data, &p_data );
-            if( dec_descr->i_extra > 0 )
-            {
-                dec_descr->p_extra = xmalloc( dec_descr->i_extra );
-                memcpy(dec_descr->p_extra, p_data, dec_descr->i_extra);
-                p_data += dec_descr->i_extra;
-                i_data -= dec_descr->i_extra;
-            }
-        }
-        else
-        {
-            dec_descr->i_extra = 0;
-            dec_descr->p_extra = NULL;
-        }
-
-        if( IODGetBytes( &i_data, &p_data, 1 ) != 0x06 )
-        {
-            ts_debug( "\n* ERR missing SLConfigDescr" );
-            continue;
-        }
-        IODDescriptorLength( &i_data, &p_data ); /* SLConfigDescr_length */
-        switch( IODGetBytes( &i_data, &p_data, 1 ) /* predefined */ )
-        {
-        default:
-            ts_debug( "\n* ERR unsupported SLConfigDescr predefined" );
-        case 0x01:
-            // FIXME
-            break;
-        }
-        es_descr->b_ok = true;
-    }
-
-    return p_iod;
-}
-
-static void IODFree( iod_descriptor_t *p_iod )
-{
-    if( p_iod->psz_url )
-    {
-        free( p_iod->psz_url );
-        free( p_iod );
-        return;
-    }
-
-    for( int i = 0; i < 255; i++ )
-    {
-#define es_descr p_iod->es_descr[i]
-        if( es_descr.b_ok )
-        {
-            if( es_descr.psz_url )
-                free( es_descr.psz_url );
-            else
-                free( es_descr.dec_descr.p_extra );
-        }
-#undef  es_descr
-    }
-    free( p_iod );
-}
-
 /****************************************************************************
  ****************************************************************************
  ** libdvbpsi callbacks
@@ -5301,7 +5036,7 @@ static void PMTCallBack( void *data, dvbpsi_pmt_t *p_dvbpsipmt )
         {
         case 0x1d: /* We have found an IOD descriptor */
             msg_Dbg( p_demux, " * PMT descriptor : IOD (0x1d)" );
-            p_pmt->iod = IODNew( p_dr->i_length, p_dr->p_data );
+            p_pmt->iod = IODNew( VLC_OBJECT(p_demux), p_dr->i_length, p_dr->p_data );
             break;
 
         case 0x9: