]> git.sesse.net Git - vlc/blobdiff - modules/demux/ts.c
Merge branch 1.0-bugfix
[vlc] / modules / demux / ts.c
index 7117ef4f9f658164813252c76fa53432ae3fda72..180507ad5deb3dabfd3b091a168e22cdbcb94c63 100644 (file)
@@ -77,9 +77,7 @@
 #       include "tables/eit.h"
 #   endif
 #endif
-#ifdef HAVE_TIME_H
-#   include <time.h>
-#endif
+#include <time.h>
 #undef TS_DEBUG
 
 /*****************************************************************************
@@ -310,6 +308,7 @@ typedef struct
     bool        b_seen;
     bool        b_valid;
     int         i_cc;   /* countinuity counter */
+    bool        b_scrambled;
 
     /* PSI owner (ie PMT -> PAT, ES -> PMT */
     ts_psi_t   *p_owner;
@@ -780,10 +779,8 @@ static void Close( vlc_object_t *p_this )
     demux_t     *p_demux = (demux_t*)p_this;
     demux_sys_t *p_sys = p_demux->p_sys;
 
-    int          i;
-
     msg_Dbg( p_demux, "pid list:" );
-    for( i = 0; i < 8192; i++ )
+    for( int i = 0; i < 8192; i++ )
     {
         ts_pid_t *pid = &p_sys->pid[i];
 
@@ -1143,7 +1140,6 @@ static int DVBEventInformation( demux_t *p_demux, int64_t *pi_time, int64_t *pi_
     if( pi_time )
         *pi_time = 0;
 
-#ifdef HAVE_TIME_H
     if( p_sys->b_access_control && p_sys->i_dvb_length > 0 )
     {
         /* FIXME we should not use time() but read the date from the tdt */
@@ -1157,7 +1153,6 @@ static int DVBEventInformation( demux_t *p_demux, int64_t *pi_time, int64_t *pi_
             return VLC_SUCCESS;
         }
     }
-#endif
     return VLC_EGENERIC;
 }
 
@@ -1509,6 +1504,7 @@ static void PIDInit( ts_pid_t *pid, bool b_psi, ts_psi_t *p_owner )
 
     pid->b_valid    = true;
     pid->i_cc       = 0xff;
+    pid->b_scrambled = false;
     pid->p_owner    = p_owner;
     pid->i_owner_number = 0;
 
@@ -1741,7 +1737,7 @@ 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' ) &&
+    else if( pid->es->fmt.i_codec == VLC_CODEC_SUBT &&
              pid->es->p_mpeg4desc )
     {
         decoder_config_descriptor_t *dcd = &pid->es->p_mpeg4desc->dec_descr;
@@ -1766,7 +1762,7 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid )
         i_skip += 2;
     }
 #ifdef ZVBI_COMPILED
-    else if( pid->es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
+    else if( pid->es->fmt.i_codec == VLC_CODEC_TELETEXT )
         i_skip = 0; /*hack for zvbi support */
 #endif
     /* skip header */
@@ -1808,7 +1804,7 @@ static void ParsePES( demux_t *p_demux, ts_pid_t *pid )
         p_pes->i_length = i_length * 100 / 9;
 
         p_block = block_ChainGather( p_pes );
-        if( pid->es->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) )
+        if( pid->es->fmt.i_codec == VLC_CODEC_SUBT )
         {
             if( i_pes_size > 0 && p_block->i_buffer > i_pes_size )
             {
@@ -1869,6 +1865,7 @@ static bool GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
 {
     const uint8_t *p = p_bk->p_buffer;
     const bool b_unit_start = p[1]&0x40;
+    const bool b_scrambled  = p[3]&0x80;
     const bool b_adaptation = p[3]&0x20;
     const bool b_payload    = p[3]&0x10;
     const int  i_cc         = p[3]&0x0f; /* continuity counter */
@@ -1973,6 +1970,23 @@ static bool GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
         return i_ret;
     }
 
+    /* */
+    if( !pid->b_scrambled != !b_scrambled )
+    {
+        msg_Warn( p_demux, "scrambled state changed on pid %d (%d->%d)",
+                  pid->i_pid, pid->b_scrambled, b_scrambled );
+
+        pid->b_scrambled = b_scrambled;
+
+        for( int i = 0; i < pid->i_extra_es; i++ )
+        {
+            es_out_Control( p_demux->out, ES_OUT_SET_ES_SCRAMBLED_STATE,
+                            pid->extra_es[i]->id, b_scrambled );
+        }
+        es_out_Control( p_demux->out, ES_OUT_SET_ES_SCRAMBLED_STATE,
+                        pid->es->id, b_scrambled );
+    }
+
     /* We have to gather it */
     p_bk->p_buffer += i_skip;
     p_bk->i_buffer -= i_skip;
@@ -2034,38 +2048,38 @@ static int PIDFillFormat( ts_pid_t *pid, int i_stream_type )
     case 0x01:  /* MPEG-1 video */
     case 0x02:  /* MPEG-2 video */
     case 0x80:  /* MPEG-2 MOTO video */
-        es_format_Init( fmt, VIDEO_ES, VLC_FOURCC( 'm', 'p', 'g', 'v' ) );
+        es_format_Init( fmt, VIDEO_ES, VLC_CODEC_MPGV );
         break;
     case 0x03:  /* MPEG-1 audio */
     case 0x04:  /* MPEG-2 audio */
-        es_format_Init( fmt, AUDIO_ES, VLC_FOURCC( 'm', 'p', 'g', 'a' ) );
+        es_format_Init( fmt, AUDIO_ES, VLC_CODEC_MPGA );
         break;
     case 0x11:  /* MPEG4 (audio) */
     case 0x0f:  /* ISO/IEC 13818-7 Audio with ADTS transport syntax */
-        es_format_Init( fmt, AUDIO_ES, VLC_FOURCC( 'm', 'p', '4', 'a' ) );
+        es_format_Init( fmt, AUDIO_ES, VLC_CODEC_MP4A );
         break;
     case 0x10:  /* MPEG4 (video) */
-        es_format_Init( fmt, VIDEO_ES, VLC_FOURCC( 'm', 'p', '4', 'v' ) );
+        es_format_Init( fmt, VIDEO_ES, VLC_CODEC_MP4V );
         pid->es->b_gather = true;
         break;
     case 0x1B:  /* H264 <- check transport syntax/needed descriptor */
-        es_format_Init( fmt, VIDEO_ES, VLC_FOURCC( 'h', '2', '6', '4' ) );
+        es_format_Init( fmt, VIDEO_ES, VLC_CODEC_H264 );
         break;
 
     case 0x81:  /* A52 (audio) */
-        es_format_Init( fmt, AUDIO_ES, VLC_FOURCC( 'a', '5', '2', ' ' ) );
+        es_format_Init( fmt, AUDIO_ES, VLC_CODEC_A52 );
         break;
     case 0x82:  /* DVD_SPU (sub) */
-        es_format_Init( fmt, SPU_ES, VLC_FOURCC( 's', 'p', 'u', ' ' ) );
+        es_format_Init( fmt, SPU_ES, VLC_CODEC_SPU );
         break;
     case 0x83:  /* LPCM (audio) */
-        es_format_Init( fmt, AUDIO_ES, VLC_FOURCC( 'l', 'p', 'c', 'm' ) );
+        es_format_Init( fmt, AUDIO_ES, VLC_CODEC_DVD_LPCM );
         break;
     case 0x84:  /* SDDS (audio) */
-        es_format_Init( fmt, AUDIO_ES, VLC_FOURCC( 's', 'd', 'd', 's' ) );
+        es_format_Init( fmt, AUDIO_ES, VLC_CODEC_SDDS );
         break;
     case 0x85:  /* DTS (audio) */
-        es_format_Init( fmt, AUDIO_ES, VLC_FOURCC( 'd', 't', 's', ' ' ) );
+        es_format_Init( fmt, AUDIO_ES, VLC_CODEC_DTS );
         break;
 
     case 0x91:  /* A52 vls (audio) */
@@ -3019,6 +3033,720 @@ static void PSINewTableCallBack( demux_t *p_demux, dvbpsi_handle h,
 }
 #endif
 
+/*****************************************************************************
+ * PMT callback and helpers
+ *****************************************************************************/
+static dvbpsi_descriptor_t *PMTEsFindDescriptor( const dvbpsi_pmt_es_t *p_es,
+                                                 int i_tag )
+{
+    dvbpsi_descriptor_t *p_dr = p_es->p_first_descriptor;;
+    while( p_dr && ( p_dr->i_tag != i_tag ) )
+        p_dr = p_dr->p_next;
+    return p_dr;
+}
+static bool PMTEsHasRegistration( demux_t *p_demux,
+                                  const dvbpsi_pmt_es_t *p_es,
+                                  const char *psz_tag )
+{
+    dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x05 );
+    if( !p_dr )
+        return false;
+
+    if( p_dr->i_length < 4 )
+    {
+        msg_Warn( p_demux, "invalid Registration Descriptor" );
+        return false;
+    }
+
+    assert( strlen(psz_tag) == 4 );
+    return !memcmp( p_dr->p_data, psz_tag, 4 );
+}
+static void PMTSetupEsISO14496( demux_t *p_demux, ts_pid_t *pid,
+                                const ts_prg_psi_t *prg, const dvbpsi_pmt_es_t *p_es )
+{
+    es_format_t *p_fmt = &pid->es->fmt;
+
+    /* MPEG-4 stream: search SL_DESCRIPTOR */
+    dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x1f );
+
+    if( p_dr && p_dr->i_length == 2 )
+    {
+        const int i_es_id = ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1];
+
+        msg_Warn( p_demux, "found SL_descriptor es_id=%d", i_es_id );
+
+        pid->es->p_mpeg4desc = NULL;
+
+        for( int i = 0; i < 255; i++ )
+        {
+            iod_descriptor_t *iod = prg->iod;
+
+            if( iod->es_descr[i].b_ok &&
+                iod->es_descr[i].i_es_id == i_es_id )
+            {
+                pid->es->p_mpeg4desc = &iod->es_descr[i];
+                break;
+            }
+        }
+    }
+    if( !pid->es->p_mpeg4desc )
+    {
+        msg_Err( p_demux, "MPEG-4 descriptor not found" );
+        return;
+    }
+
+    const decoder_config_descriptor_t *dcd = &pid->es->p_mpeg4desc->dec_descr;
+    if( dcd->i_streamType == 0x04 )    /* VisualStream */
+    {
+        p_fmt->i_cat = VIDEO_ES;
+        switch( dcd->i_objectTypeIndication )
+        {
+        case 0x0B: /* mpeg4 sub */
+            p_fmt->i_cat = SPU_ES;
+            p_fmt->i_codec = VLC_CODEC_SUBT;
+            break;
+
+        case 0x20: /* mpeg4 */
+            p_fmt->i_codec = VLC_CODEC_MP4V;
+            break;
+        case 0x21: /* h264 */
+            p_fmt->i_codec = VLC_CODEC_H264;
+            break;
+        case 0x60:
+        case 0x61:
+        case 0x62:
+        case 0x63:
+        case 0x64:
+        case 0x65: /* mpeg2 */
+            p_fmt->i_codec = VLC_CODEC_MPGV;
+            break;
+        case 0x6a: /* mpeg1 */
+            p_fmt->i_codec = VLC_CODEC_MPGV;
+            break;
+        case 0x6c: /* mpeg1 */
+            p_fmt->i_codec = VLC_CODEC_JPEG;
+            break;
+        default:
+            p_fmt->i_cat = UNKNOWN_ES;
+            break;
+        }
+    }
+    else if( dcd->i_streamType == 0x05 )    /* AudioStream */
+    {
+        p_fmt->i_cat = AUDIO_ES;
+        switch( dcd->i_objectTypeIndication )
+        {
+        case 0x40: /* mpeg4 */
+            p_fmt->i_codec = VLC_CODEC_MP4A;
+            break;
+        case 0x66:
+        case 0x67:
+        case 0x68: /* mpeg2 aac */
+            p_fmt->i_codec = VLC_CODEC_MP4A;
+            break;
+        case 0x69: /* mpeg2 */
+            p_fmt->i_codec = VLC_CODEC_MPGA;
+            break;
+        case 0x6b: /* mpeg1 */
+            p_fmt->i_codec = VLC_CODEC_MPGA;
+            break;
+        default:
+            p_fmt->i_cat = UNKNOWN_ES;
+            break;
+        }
+    }
+    else
+    {
+        p_fmt->i_cat = UNKNOWN_ES;
+    }
+
+    if( p_fmt->i_cat != UNKNOWN_ES )
+    {
+        p_fmt->i_extra = dcd->i_decoder_specific_info_len;
+        if( p_fmt->i_extra > 0 )
+        {
+            p_fmt->p_extra = malloc( p_fmt->i_extra );
+            if( p_fmt->p_extra )
+                memcpy( p_fmt->p_extra,
+                        dcd->p_decoder_specific_info,
+                        p_fmt->i_extra );
+            else
+                p_fmt->i_extra = 0;
+        }
+    }
+}
+
+typedef struct
+{
+    int  i_type;
+    int  i_magazine;
+    int  i_page;
+    char p_iso639[3];
+} ts_teletext_page_t;
+
+static void PMTSetupEsTeletext( demux_t *p_demux, ts_pid_t *pid,
+                                const dvbpsi_pmt_es_t *p_es )
+{
+    es_format_t *p_fmt = &pid->es->fmt;
+
+    ts_teletext_page_t p_page[2 * 64 + 20];
+    int i_page = 0;
+
+    /* Gather pages informations */
+#if defined _DVBPSI_DR_56_H_ && \
+    defined DVBPSI_VERSION && DVBPSI_VERSION_INT > ((0<<16)+(1<<8)+5)
+    for( int i_tag_idx = 0; i_tag_idx < 2; i_tag_idx++ )
+    {
+        dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, i_tag_idx == 0 ? 0x46 : 0x56 );
+        if( !p_dr )
+            continue;
+
+        dvbpsi_teletext_dr_t *p_sub = dvbpsi_DecodeTeletextDr( p_dr );
+        if( !p_sub )
+            continue;
+
+        for( int i = 0; i < p_sub->i_pages_number; i++ )
+        {
+            const dvbpsi_teletextpage_t *p_src = &p_sub->p_pages[i];
+
+            if( p_src->i_teletext_type < 0 || p_src->i_teletext_type >= 0x06 )
+                continue;
+
+            assert( i_page < sizeof(p_page)/sizeof(*p_page) );
+
+            ts_teletext_page_t *p_dst = &p_page[i_page++];
+
+            p_dst->i_type = p_src->i_teletext_type;
+            p_dst->i_magazine = p_src->i_teletext_magazine_number
+                ? p_src->i_teletext_magazine_number : 8;
+            p_dst->i_page = p_src->i_teletext_page_number;
+            memcpy( p_dst->p_iso639, p_src->i_iso6392_language_code, 3 );
+        }
+    }
+#endif
+
+#ifdef _DVBPSI_DR_59_H_
+    dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x59 );
+    if( p_dr )
+    {
+        dvbpsi_subtitling_dr_t *p_sub = dvbpsi_DecodeSubtitlingDr( p_dr );
+        for( int i = 0; p_sub && i < p_sub->i_subtitles_number; i++ )
+        {
+            dvbpsi_subtitle_t *p_src = &p_sub->p_subtitle[i];
+
+            if( p_src->i_subtitling_type < 0x01 || p_src->i_subtitling_type > 0x03 )
+                continue;
+
+            assert( i_page < sizeof(p_page)/sizeof(*p_page) );
+
+            ts_teletext_page_t *p_dst = &p_page[i_page++];
+
+            switch( p_src->i_subtitling_type )
+            {
+            case 0x01:
+                p_dst->i_type = 0x02;
+                break;
+            default:
+                p_dst->i_type = 0x03;
+                break;
+            }
+            /* FIXME check if it is the right split */
+            p_dst->i_magazine = (p_src->i_composition_page_id >> 8)
+                ? (p_src->i_composition_page_id >> 8) : 8;
+            p_dst->i_page = p_src->i_composition_page_id & 0xff;
+            memcpy( p_dst->p_iso639, p_src->i_iso6392_language_code, 3 );
+        }
+    }
+#endif
+
+    /* */
+    es_format_Init( p_fmt, SPU_ES, VLC_CODEC_TELETEXT );
+
+    /* In stream output mode, do not separate the stream by page */
+    if( p_demux->out->b_sout || i_page <= 0 )
+    {
+        p_fmt->subs.teletext.i_magazine = -1;
+        p_fmt->subs.teletext.i_page = 0;
+        p_fmt->psz_description = strdup( vlc_gettext(ppsz_teletext_type[1]) );
+
+        dvbpsi_descriptor_t *p_dr;
+        p_dr = PMTEsFindDescriptor( p_es, 0x46 );
+        if( !p_dr )
+            p_dr = PMTEsFindDescriptor( p_es, 0x56 );
+
+        if( p_demux->out->b_sout && p_dr && p_dr->i_length > 0 )
+        {
+            /* Descriptor pass-through for sout */
+            p_fmt->p_extra = malloc( p_dr->i_length );
+            if( p_fmt->p_extra )
+            {
+                p_fmt->i_extra = p_dr->i_length;
+                memcpy( p_fmt->p_extra, p_dr->p_data, p_dr->i_length );
+            }
+        }
+    }
+    else
+    {
+        for( int i = 0; i < i_page; i++ )
+        {
+            ts_es_t *p_es;
+
+            /* */
+            if( i == 0 )
+            {
+                p_es = pid->es;
+            }
+            else
+            {
+                p_es = malloc( sizeof(*p_es) );
+                if( !p_es )
+                    break;
+
+                es_format_Copy( &p_es->fmt, &pid->es->fmt );
+                free( p_es->fmt.psz_language );
+                free( p_es->fmt.psz_description );
+                p_es->fmt.psz_language = NULL;
+                p_es->fmt.psz_description = NULL;
+
+                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;
+                p_es->b_gather = false;
+
+                TAB_APPEND( pid->i_extra_es, pid->extra_es, p_es );
+            }
+
+            /* */
+            const ts_teletext_page_t *p = &p_page[i];
+            p_es->fmt.psz_language = strndup( p->p_iso639, 3 );
+            p_es->fmt.psz_description = strdup(vlc_gettext(ppsz_teletext_type[p->i_type]));
+            p_es->fmt.subs.teletext.i_magazine = p->i_magazine;
+            p_es->fmt.subs.teletext.i_page = p->i_page;
+
+            msg_Dbg( p_demux,
+                         "    * ttxt type=%s lan=%s page=%d%02x",
+                         p_es->fmt.psz_description,
+                         p_es->fmt.psz_language,
+                         p->i_magazine, p->i_page );
+        }
+    }
+}
+static void PMTSetupEsDvbSubtitle( demux_t *p_demux, ts_pid_t *pid,
+                                   const dvbpsi_pmt_es_t *p_es )
+{
+    es_format_t *p_fmt = &pid->es->fmt;
+
+    es_format_Init( p_fmt, SPU_ES, VLC_CODEC_DVBS );
+
+    dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x59 );
+    int i_page = 0;
+#ifdef _DVBPSI_DR_59_H_
+    dvbpsi_subtitling_dr_t *p_sub = dvbpsi_DecodeSubtitlingDr( p_dr );
+    for( int i = 0; p_sub && i < p_sub->i_subtitles_number; i++ )
+    {
+        const int i_type = p_sub->p_subtitle[i].i_subtitling_type;
+        if( ( i_type >= 0x10 && i_type <= 0x13 ) ||
+            ( i_type >= 0x20 && i_type <= 0x23 ) )
+            i_page++;
+    }
+#endif
+
+    /* In stream output mode, do not separate the stream by page */
+    if( p_demux->out->b_sout  || i_page <= 0 )
+    {
+        p_fmt->subs.dvb.i_id = -1;
+        p_fmt->psz_description = strdup( _("DVB subtitles") );
+
+        if( p_demux->out->b_sout && p_dr && p_dr->i_length > 0 )
+        {
+            /* Descriptor pass-through for sout */
+            p_fmt->p_extra = malloc( p_dr->i_length );
+            if( p_fmt->p_extra )
+            {
+                p_fmt->i_extra = p_dr->i_length;
+                memcpy( p_fmt->p_extra, p_dr->p_data, p_dr->i_length );
+            }
+        }
+    }
+    else
+    {
+#ifdef _DVBPSI_DR_59_H_
+        for( int i = 0; i < p_sub->i_subtitles_number; i++ )
+        {
+            ts_es_t *p_es;
+
+            /* */
+            if( i == 0 )
+            {
+                p_es = pid->es;
+            }
+            else
+            {
+                p_es = malloc( sizeof(*p_es) );
+                if( !p_es )
+                    break;
+
+                es_format_Copy( &p_es->fmt, &pid->es->fmt );
+                free( p_es->fmt.psz_language );
+                free( p_es->fmt.psz_description );
+                p_es->fmt.psz_language = NULL;
+                p_es->fmt.psz_description = NULL;
+
+                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;
+                p_es->b_gather = false;
+
+                TAB_APPEND( pid->i_extra_es, pid->extra_es, p_es );
+            }
+
+            /* */
+            const dvbpsi_subtitle_t *p = &p_sub->p_subtitle[i];
+            p_es->fmt.psz_language = strndup( p->i_iso6392_language_code, 3 );
+            switch( p->i_subtitling_type )
+            {
+            case 0x10: /* unspec. */
+            case 0x11: /* 4:3 */
+            case 0x12: /* 16:9 */
+            case 0x13: /* 2.21:1 */
+                p_es->fmt.psz_description = strdup( _("DVB subtitles") );
+                break;
+            case 0x20: /* Hearing impaired unspec. */
+            case 0x21: /* h.i. 4:3 */
+            case 0x22: /* h.i. 16:9 */
+            case 0x23: /* h.i. 2.21:1 */
+                p_es->fmt.psz_description = strdup( _("DVB subtitles: hearing impaired") );
+                break;
+            default:
+                break;
+            }
+
+            /* Hack, FIXME */
+            p_es->fmt.subs.dvb.i_id = ( p->i_composition_page_id <<  0 ) |
+                                      ( p->i_ancillary_page_id   << 16 );
+        }
+#endif
+    }
+}
+static void PMTSetupEs0x06( demux_t *p_demux, ts_pid_t *pid,
+                            const dvbpsi_pmt_es_t *p_es )
+{
+    es_format_t *p_fmt = &pid->es->fmt;
+
+    if( PMTEsHasRegistration( p_demux, p_es, "AC-3" ) ||
+        PMTEsFindDescriptor( p_es, 0x6a ) ||
+        PMTEsFindDescriptor( p_es, 0x81 ) )
+    {
+        p_fmt->i_cat = AUDIO_ES;
+        p_fmt->i_codec = VLC_CODEC_A52;
+    }
+    else if( PMTEsFindDescriptor( p_es, 0x7a ) )
+    {
+        /* DVB with stream_type 0x06 (ETS EN 300 468) */
+        p_fmt->i_cat = AUDIO_ES;
+        p_fmt->i_codec = VLC_CODEC_EAC3;
+    }
+    else if( PMTEsHasRegistration( p_demux, p_es, "DTS1" ) ||
+             PMTEsHasRegistration( p_demux, p_es, "DTS2" ) ||
+             PMTEsHasRegistration( p_demux, p_es, "DTS3" ) ||
+             PMTEsFindDescriptor( p_es, 0x73 ) )
+    {
+        /*registration descriptor(ETSI TS 101 154 Annex F)*/
+        p_fmt->i_cat = AUDIO_ES;
+        p_fmt->i_codec = VLC_CODEC_DTS;
+    }
+    else if( PMTEsHasRegistration( p_demux, p_es, "BSSD" ) )
+    {
+        p_fmt->i_cat = AUDIO_ES;
+        p_fmt->b_packetized = true;
+        p_fmt->i_codec = VLC_CODEC_302M;
+    }
+    else
+    {
+        /* Subtitle/Teletext/VBI fallbacks */
+        dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x59 );
+
+#ifdef _DVBPSI_DR_59_H_
+        dvbpsi_subtitling_dr_t *p_sub;
+        if( p_dr && ( p_sub = dvbpsi_DecodeSubtitlingDr( p_dr ) ) )
+        {
+            for( int i = 0; i < p_sub->i_subtitles_number; i++ )
+            {
+                if( p_fmt->i_cat != UNKNOWN_ES )
+                    break;
+
+                switch( p_sub->p_subtitle[i].i_subtitling_type )
+                {
+                case 0x01: /* EBU Teletext subtitles */
+                case 0x02: /* Associated EBU Teletext */
+                case 0x03: /* VBI data */
+                    PMTSetupEsTeletext( p_demux, pid, p_es );
+                    break;
+                case 0x10: /* DVB Subtitle (normal) with no monitor AR critical */
+                case 0x11: /*                 ...   on 4:3 AR monitor */
+                case 0x12: /*                 ...   on 16:9 AR monitor */
+                case 0x13: /*                 ...   on 2.21:1 AR monitor */
+                case 0x20: /* DVB Subtitle (impaired) with no monitor AR critical */
+                case 0x21: /*                 ...   on 4:3 AR monitor */
+                case 0x22: /*                 ...   on 16:9 AR monitor */
+                case 0x23: /*                 ...   on 2.21:1 AR monitor */
+                    PMTSetupEsDvbSubtitle( p_demux, pid, p_es );
+                    break;
+                default:
+                    msg_Err( p_demux, "Unrecognized DVB subtitle type" );
+                    break;
+                }
+            }
+        }
+#else
+        if( p_fmt->i_cat == UNKNOWN_ES && p_dr )
+            PMTSetupEsDvbSubtitle( p_demux, pid, p_es );
+#endif
+        if( p_fmt->i_cat == UNKNOWN_ES &&
+            ( PMTEsFindDescriptor( p_es, 0x45 ) ||  /* VBI Data descriptor */
+              PMTEsFindDescriptor( p_es, 0x46 ) ||  /* VBI Teletext descriptor */
+              PMTEsFindDescriptor( p_es, 0x56 ) ) ) /* EBU Teletext descriptor */
+        {
+            /* Teletext/VBI */
+            PMTSetupEsTeletext( p_demux, pid, p_es );
+        }
+    }
+
+#ifdef _DVBPSI_DR_52_H_
+    /* FIXME is it usefull ? */
+    if( PMTEsFindDescriptor( p_es, 0x52 ) )
+    {
+        dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x52 );
+        dvbpsi_stream_identifier_dr_t *p_si = dvbpsi_DecodeStreamIdentifierDr( p_dr );
+
+        msg_Dbg( p_demux, "    * Stream Component Identifier: %d", p_si->i_component_tag );
+    }
+#endif
+}
+
+static void PMTSetupEs0xEA( demux_t *p_demux, ts_pid_t *pid,
+                           const dvbpsi_pmt_es_t *p_es )
+{
+    /* Registration Descriptor */
+    if( !PMTEsHasRegistration( p_demux, p_es, "VC-1" ) )
+    {
+        msg_Err( p_demux, "Registration descriptor not found or invalid" );
+        return;
+    }
+
+    es_format_t *p_fmt = &pid->es->fmt;
+
+    /* registration descriptor for VC-1 (SMPTE rp227) */
+    p_fmt->i_cat = VIDEO_ES;
+    p_fmt->i_codec = VLC_CODEC_VC1;
+
+    /* XXX With Simple and Main profile the SEQUENCE
+     * header is modified: video width and height are
+     * inserted just after the start code as 2 int16_t
+     * The packetizer will take care of that. */
+}
+
+static void PMTSetupEs0xD1( demux_t *p_demux, ts_pid_t *pid,
+                           const dvbpsi_pmt_es_t *p_es )
+{
+    /* Registration Descriptor */
+    if( !PMTEsHasRegistration( p_demux, p_es, "drac" ) )
+    {
+        msg_Err( p_demux, "Registration descriptor not found or invalid" );
+        return;
+    }
+
+    es_format_t *p_fmt = &pid->es->fmt;
+
+    /* registration descriptor for Dirac
+     * (backwards compatable with VC-2 (SMPTE Sxxxx:2008)) */
+    p_fmt->i_cat = VIDEO_ES;
+    p_fmt->i_codec = VLC_CODEC_DIRAC;
+}
+
+static void PMTSetupEs0xA0( demux_t *p_demux, ts_pid_t *pid,
+                           const dvbpsi_pmt_es_t *p_es )
+{
+    /* MSCODEC sent by vlc */
+    dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0xa0 );
+    if( !p_dr || p_dr->i_length < 10 )
+    {
+        msg_Warn( p_demux,
+                  "private MSCODEC (vlc) without bih private descriptor" );
+        return;
+    }
+
+    es_format_t *p_fmt = &pid->es->fmt;
+    p_fmt->i_cat = VIDEO_ES;
+    p_fmt->i_codec = VLC_FOURCC( p_dr->p_data[0], p_dr->p_data[1],
+                                 p_dr->p_data[2], p_dr->p_data[3] );
+    p_fmt->video.i_width = GetWBE( &p_dr->p_data[4] );
+    p_fmt->video.i_height = GetWBE( &p_dr->p_data[6] );
+    p_fmt->i_extra = GetWBE( &p_dr->p_data[8] );
+
+    if( p_fmt->i_extra > 0 )
+    {
+        p_fmt->p_extra = malloc( p_fmt->i_extra );
+        if( p_fmt->p_extra )
+            memcpy( p_fmt->p_extra, &p_dr->p_data[10],
+                    __MIN( p_fmt->i_extra, p_dr->i_length - 10 ) );
+        else
+            p_fmt->i_extra = 0;
+    }
+    /* For such stream we will gather them ourself and don't launch a
+     * packetizer.
+     * Yes it's ugly but it's the only way to have DIV3 working */
+    p_fmt->b_packetized = true;
+}
+
+static void PMTSetupEsHDMV( demux_t *p_demux, ts_pid_t *pid,
+                           const dvbpsi_pmt_es_t *p_es )
+{
+    es_format_t *p_fmt = &pid->es->fmt;
+
+    /* Blu-Ray mapping */
+    switch( p_es->i_type )
+    {
+    case 0x80:
+        p_fmt->i_cat = AUDIO_ES;
+        p_fmt->i_codec = VLC_CODEC_BD_LPCM;
+        break;
+    case 0x82:
+    case 0x85: /* DTS-HD High resolution audio */
+    case 0x86: /* DTS-HD Master audio */
+    case 0xA2: /* Secondary DTS audio */
+        p_fmt->i_cat = AUDIO_ES;
+        p_fmt->i_codec = VLC_CODEC_DTS;
+        break;
+
+    case 0x83: /* TrueHD AC3 */
+        p_fmt->i_cat = AUDIO_ES;
+        p_fmt->i_codec = VLC_CODEC_MLP;
+        break;
+
+    case 0x84: /* E-AC3 */
+    case 0x87: /* E-AC3 */
+    case 0xA1: /* Secondary E-AC3 */
+        p_fmt->i_cat = AUDIO_ES;
+        p_fmt->i_codec = VLC_CODEC_EAC3;
+        break;
+    case 0x90: /* Presentation graphics */
+    case 0x91: /* Interactive graphics */
+    case 0x92: /* Subtitle */
+    default:
+        break;
+    }
+}
+static void PMTParseEsIso639( demux_t *p_demux, ts_pid_t *pid,
+                              const dvbpsi_pmt_es_t *p_es )
+{
+    /* get language descriptor */
+    dvbpsi_descriptor_t *p_dr = PMTEsFindDescriptor( p_es, 0x0a );
+
+    if( !p_dr )
+        return;
+
+    dvbpsi_iso639_dr_t *p_decoded = dvbpsi_DecodeISO639Dr( p_dr );
+    if( !p_decoded )
+    {
+        msg_Err( p_demux, "Failed to decode a ISO 639 descriptor" );
+        return;
+    }
+
+#if defined(DR_0A_API_VER) && (DR_0A_API_VER >= 2)
+    pid->es->fmt.psz_language = malloc( 4 );
+    if( pid->es->fmt.psz_language )
+    {
+        memcpy( pid->es->fmt.psz_language,
+                p_decoded->code[0].iso_639_code, 3 );
+        pid->es->fmt.psz_language[3] = 0;
+        msg_Dbg( p_demux, "found language: %s", pid->es->fmt.psz_language);
+    }
+    switch( p_decoded->code[0].i_audio_type )
+    {
+    case 0:
+        pid->es->fmt.psz_description = NULL;
+        break;
+    case 1:
+        pid->es->fmt.psz_description =
+            strdup(_("clean effects"));
+        break;
+    case 2:
+        pid->es->fmt.psz_description =
+            strdup(_("hearing impaired"));
+        break;
+    case 3:
+        pid->es->fmt.psz_description =
+            strdup(_("visual impaired commentary"));
+        break;
+    default:
+        msg_Dbg( p_demux, "unknown audio type: %d",
+                 p_decoded->code[0].i_audio_type);
+        pid->es->fmt.psz_description = NULL;
+        break;
+    }
+    pid->es->fmt.i_extra_languages = p_decoded->i_code_count-1;
+    if( pid->es->fmt.i_extra_languages > 0 )
+        pid->es->fmt.p_extra_languages =
+            malloc( sizeof(*pid->es->fmt.p_extra_languages) *
+                    pid->es->fmt.i_extra_languages );
+    if( pid->es->fmt.p_extra_languages )
+    {
+        for( int i = 0; i < pid->es->fmt.i_extra_languages; i++ )
+        {
+            msg_Dbg( p_demux, "bang" );
+            pid->es->fmt.p_extra_languages[i].psz_language =
+                malloc(4);
+            if( pid->es->fmt.p_extra_languages[i].psz_language )
+            {
+                memcpy( pid->es->fmt.p_extra_languages[i].psz_language,
+                    p_decoded->code[i+1].iso_639_code, 3 );
+                pid->es->fmt.p_extra_languages[i].psz_language[3] = '\0';
+            }
+            switch( p_decoded->code[i].i_audio_type )
+            {
+            case 0:
+                pid->es->fmt.p_extra_languages[i].psz_description =
+                    NULL;
+                break;
+            case 1:
+                pid->es->fmt.p_extra_languages[i].psz_description =
+                    strdup(_("clean effects"));
+                break;
+            case 2:
+                pid->es->fmt.p_extra_languages[i].psz_description =
+                    strdup(_("hearing impaired"));
+                break;
+            case 3:
+                pid->es->fmt.p_extra_languages[i].psz_description =
+                    strdup(_("visual impaired commentary"));
+                break;
+            default:
+                msg_Dbg( p_demux, "unknown audio type: %d",
+                        p_decoded->code[i].i_audio_type);
+                pid->es->fmt.psz_description = NULL;
+                break;
+            }
+
+        }
+    }
+#else
+    pid->es->fmt.psz_language = malloc( 4 );
+    if( pid->es->fmt.psz_language )
+    {
+        memcpy( pid->es->fmt.psz_language,
+                p_decoded->i_iso_639_code, 3 );
+        pid->es->fmt.psz_language[3] = 0;
+    }
+#endif
+}
+
 static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
 {
     demux_sys_t          *p_sys = p_demux->p_sys;
@@ -3167,6 +3895,13 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
             continue;
         }
 
+        for( p_dr = p_es->p_first_descriptor; p_dr != NULL;
+             p_dr = p_dr->p_next )
+        {
+            msg_Dbg( p_demux, "  * es pid=%d type=%d dr->i_tag=0x%x",
+                     p_es->i_pid, p_es->i_type, p_dr->i_tag );
+        }
+
         PIDInit( pid, false, pmt->psi );
         PIDFillFormat( pid, p_es->i_type );
         pid->i_owner_number = prg->i_number;
@@ -3176,656 +3911,41 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
         if( p_es->i_type == 0x10 || p_es->i_type == 0x11 ||
             p_es->i_type == 0x12 || p_es->i_type == 0x0f )
         {
-            /* MPEG-4 stream: search SL_DESCRIPTOR */
-            dvbpsi_descriptor_t *p_dr = p_es->p_first_descriptor;;
-
-            while( p_dr && ( p_dr->i_tag != 0x1f ) ) p_dr = p_dr->p_next;
-
-            if( p_dr && p_dr->i_length == 2 )
-            {
-                int i_es_id = ( p_dr->p_data[0] << 8 ) | p_dr->p_data[1];
-
-                msg_Warn( p_demux, "found SL_descriptor es_id=%d", i_es_id );
-
-                pid->es->p_mpeg4desc = NULL;
-
-                for( int i = 0; i < 255; i++ )
-                {
-                    iod_descriptor_t *iod = prg->iod;
-
-                    if( iod->es_descr[i].b_ok &&
-                        iod->es_descr[i].i_es_id == i_es_id )
-                    {
-                        pid->es->p_mpeg4desc = &iod->es_descr[i];
-                        break;
-                    }
-                }
-            }
-
-            if( pid->es->p_mpeg4desc != NULL )
-            {
-                decoder_config_descriptor_t *dcd =
-                    &pid->es->p_mpeg4desc->dec_descr;
-
-                if( dcd->i_streamType == 0x04 )    /* VisualStream */
-                {
-                    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;
-                    case 0x21: /* h264 */
-                        pid->es->fmt.i_codec = VLC_FOURCC('h','2','6','4');
-                        break;
-                    case 0x60:
-                    case 0x61:
-                    case 0x62:
-                    case 0x63:
-                    case 0x64:
-                    case 0x65: /* mpeg2 */
-                        pid->es->fmt.i_codec = VLC_FOURCC( 'm','p','g','v' );
-                        break;
-                    case 0x6a: /* mpeg1 */
-                        pid->es->fmt.i_codec = VLC_FOURCC( 'm','p','g','v' );
-                        break;
-                    case 0x6c: /* mpeg1 */
-                        pid->es->fmt.i_codec = VLC_FOURCC( 'j','p','e','g' );
-                        break;
-                    default:
-                        pid->es->fmt.i_cat = UNKNOWN_ES;
-                        break;
-                    }
-                }
-                else if( dcd->i_streamType == 0x05 )    /* AudioStream */
-                {
-                    pid->es->fmt.i_cat = AUDIO_ES;
-                    switch( dcd->i_objectTypeIndication )
-                    {
-                    case 0x40: /* mpeg4 */
-                        pid->es->fmt.i_codec = VLC_FOURCC('m','p','4','a');
-                        break;
-                    case 0x66:
-                    case 0x67:
-                    case 0x68: /* mpeg2 aac */
-                        pid->es->fmt.i_codec = VLC_FOURCC('m','p','4','a');
-                        break;
-                    case 0x69: /* mpeg2 */
-                        pid->es->fmt.i_codec = VLC_FOURCC('m','p','g','a');
-                        break;
-                    case 0x6b: /* mpeg1 */
-                        pid->es->fmt.i_codec = VLC_FOURCC('m','p','g','a');
-                        break;
-                    default:
-                        pid->es->fmt.i_cat = UNKNOWN_ES;
-                        break;
-                    }
-                }
-                else
-                {
-                    pid->es->fmt.i_cat = UNKNOWN_ES;
-                }
-
-                if( pid->es->fmt.i_cat != UNKNOWN_ES )
-                {
-                    pid->es->fmt.i_extra = dcd->i_decoder_specific_info_len;
-                    if( pid->es->fmt.i_extra > 0 )
-                    {
-                        pid->es->fmt.p_extra = malloc( pid->es->fmt.i_extra );
-                        if( pid->es->fmt.p_extra )
-                            memcpy( pid->es->fmt.p_extra,
-                                    dcd->p_decoder_specific_info,
-                                    pid->es->fmt.i_extra );
-                    }
-                }
-            }
+            PMTSetupEsISO14496( p_demux, pid, prg, p_es );
         }
         else if( p_es->i_type == 0x06 )
         {
-            dvbpsi_descriptor_t *p_dr;
-
-            for( p_dr = p_es->p_first_descriptor; p_dr != NULL;
-                 p_dr = p_dr->p_next )
-            {
-                msg_Dbg( p_demux, "  * es pid=%d type=%d dr->i_tag=0x%x",
-                         p_es->i_pid, p_es->i_type, p_dr->i_tag );
-
-                if( p_dr->i_tag == 0x05 )
-                {
-                    /* Registration Descriptor */
-                    if( p_dr->i_length != 4 )
-                    {
-                        msg_Warn( p_demux, "invalid Registration Descriptor" );
-                    }
-                    else
-                    {
-                        if( !memcmp( p_dr->p_data, "AC-3", 4 ) )
-                        {
-                            /* ATSC with stream_type 0x81 (but this descriptor
-                             * is then not mandatory */
-                            pid->es->fmt.i_cat = AUDIO_ES;
-                            pid->es->fmt.i_codec = VLC_FOURCC('a','5','2',' ');
-                        }
-                        else if( !memcmp( p_dr->p_data, "DTS1", 4 ) ||
-                                 !memcmp( p_dr->p_data, "DTS2", 4 ) ||
-                                 !memcmp( p_dr->p_data, "DTS3", 4 ) )
-                        {
-                           /*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( !memcmp( p_dr->p_data, "BSSD", 4 ) )
-                        {
-                            pid->es->fmt.i_cat = AUDIO_ES;
-                            pid->es->fmt.b_packetized = true;
-                            pid->es->fmt.i_codec = VLC_FOURCC('a','e','s','3');
-                        }
-                        else
-                        {
-                            msg_Warn( p_demux,
-                                      "unknown Registration Descriptor (%4.4s)",
-                                      p_dr->p_data );
-                        }
-                    }
-
-                }
-                else if( p_dr->i_tag == 0x6a )
-                {
-                    /* DVB 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 == 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) */
-                    pid->es->fmt.i_cat = AUDIO_ES;
-                    pid->es->fmt.i_codec = VLC_FOURCC( 'e', 'a', 'c', '3' );
-                }
-                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', ' ' );
-                }
-                else if( p_dr->i_tag == 0x45 )
-                {
-                    msg_Dbg( p_demux, "    * VBI Data descriptor" );
-                    /* FIXME : store the information somewhere */
-                }
-                else if( p_dr->i_tag == 0x46 )
-                {
-                    msg_Dbg( p_demux, "    * VBI Teletext descriptor" );
-                    /* FIXME : store the information somewhere */
-                }
-#ifdef _DVBPSI_DR_52_H_
-                else if( p_dr->i_tag == 0x52 )
-                {
-                    dvbpsi_stream_identifier_dr_t *si;
-                    si = dvbpsi_DecodeStreamIdentifierDr( p_dr );
-
-                    msg_Dbg( p_demux, "    * Stream Component Identifier: %d", si->i_component_tag );
-                }
-#endif
-                else if( p_dr->i_tag == 0x56 )
-                {
-                    msg_Dbg( p_demux, "    * EBU Teletext descriptor" );
-                    pid->es->fmt.i_cat = SPU_ES;
-                    pid->es->fmt.i_codec = VLC_FOURCC( 't', 'e', 'l', 'x' );
-                    pid->es->fmt.i_extra = p_dr->i_length;
-                    pid->es->fmt.p_extra = p_dr->i_length ?
-                        malloc( p_dr->i_length ) : NULL;
-                    if( pid->es->fmt.p_extra )
-                        memcpy( pid->es->fmt.p_extra, p_dr->p_data,
-                                p_dr->i_length );
-
-#if defined _DVBPSI_DR_56_H_ && defined DVBPSI_VERSION \
-                    && DVBPSI_VERSION_INT > ((0<<16)+(1<<8)+5)
-                    pid->es->fmt.i_group = p_pmt->i_program_number;
-
-                    /* In stream output mode, only enable descriptor
-                     * pass-through. */
-                    if( !p_demux->out->b_sout )
-                    {
-                        uint16_t n, i = 0;
-                        dvbpsi_teletext_dr_t *sub;
-
-                        sub = dvbpsi_DecodeTeletextDr( p_dr );
-                        if( !sub ) continue;
-
-                        /* Each subtitle ES contains n languages,
-                         * We are going to create n ES for the n tracks */
-                        for( n = 0; n < sub->i_pages_number; n++ )
-                        {
-                            dvbpsi_teletextpage_t *p_page = &sub->p_pages[n];
-                            if( p_page->i_teletext_type > 0x0 &&
-                                p_page->i_teletext_type < 0x6 )
-                            {
-                                ts_es_t *p_es;
-
-                                if( i == 0 )
-                                {
-                                    p_es = pid->es;
-                                }
-                                else
-                                {
-                                    p_es = malloc( sizeof( ts_es_t ) );
-                                    if( !p_es ) break;
-
-                                    es_format_Copy( &p_es->fmt, &pid->es->fmt );
-                                    free( p_es->fmt.psz_language );
-                                    free( p_es->fmt.psz_description );
-                                    p_es->fmt.psz_language = NULL;
-                                    p_es->fmt.psz_description = NULL;
-                                    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;
-
-                                    TAB_APPEND( pid->i_extra_es, pid->extra_es,
-                                                p_es );
-                                }
-
-                                p_es->fmt.psz_language = malloc( 4 );
-                                if( p_es->fmt.psz_language )
-                                {
-                                    memcpy( p_es->fmt.psz_language,
-                                            p_page->i_iso6392_language_code, 3 );
-                                    p_es->fmt.psz_language[3] = 0;
-                                }
-                                p_es->fmt.psz_description = strdup(_(ppsz_teletext_type[p_page->i_teletext_type]));
-
-                                msg_Dbg( p_demux,
-                                             "    * ttxt type=%s lan=%s page=%d%02x",
-                                             p_es->fmt.psz_description,
-                                             p_es->fmt.psz_language,
-                                             p_page->i_teletext_magazine_number,
-                                             p_page->i_teletext_page_number );
-
-                                /* This stores the initial page for this track,
-                                   so that it can be used by the telx and zvbi decoders. */
-                                p_es->fmt.subs.teletext.i_magazine =
-                                    p_page->i_teletext_magazine_number ? : 8;
-                                p_es->fmt.subs.teletext.i_page =
-                                    p_page->i_teletext_page_number;
-
-                                i++;
-                            }
-                        }
-                        if( !i )
-                            pid->es->fmt.i_cat = UNKNOWN_ES;
-                    }
-                    else
-#endif  /* defined _DVBPSI_DR_56_H_  && DVBPSI_VERSION(0,1,6) */
-                    {
-                        pid->es->fmt.subs.teletext.i_magazine = -1;
-                        pid->es->fmt.subs.teletext.i_page = 0;
-                        pid->es->fmt.psz_description = strdup( _(ppsz_teletext_type[1]) );
-                    }
-                }
-                else if( p_dr->i_tag == 0x59 )
-                {
-                    /* DVB subtitles */
-                    pid->es->fmt.i_cat = SPU_ES;
-                    pid->es->fmt.i_codec = VLC_FOURCC( 'd', 'v', 'b', 's' );
-                    pid->es->fmt.i_extra = p_dr->i_length;
-                    pid->es->fmt.p_extra = malloc( p_dr->i_length );
-                    if( pid->es->fmt.p_extra )
-                        memcpy( pid->es->fmt.p_extra, p_dr->p_data,
-                                p_dr->i_length );
-
-#ifdef _DVBPSI_DR_59_H_
-                    pid->es->fmt.i_group = p_pmt->i_program_number;
-
-                    /* In stream output mode, only enable descriptor
-                     * pass-through. */
-                    if( !p_demux->out->b_sout )
-                    {
-                        uint16_t n, i = 0;
-                        dvbpsi_subtitling_dr_t *sub;
-
-                        sub = dvbpsi_DecodeSubtitlingDr( p_dr );
-                        if( !sub ) continue;
-
-                        for( n = 0; n < sub->i_subtitles_number; n++ )
-                        {
-                            dvbpsi_subtitle_t *p_sub = &sub->p_subtitle[n];
-                            ts_es_t *p_es;
-
-                            if( i == 0 )
-                            {
-                                p_es = pid->es;
-                            }
-                            else
-                            {
-                                p_es = malloc( sizeof( ts_es_t ) );
-                                if( !p_es ) break;
-                                es_format_Copy( &p_es->fmt, &pid->es->fmt );
-                                free( p_es->fmt.psz_language ); p_es->fmt.psz_language = NULL;
-                                free( p_es->fmt.psz_description ); p_es->fmt.psz_description = NULL;
-
-                                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;
-
-                                TAB_APPEND( pid->i_extra_es, pid->extra_es,
-                                            p_es );
-                            }
-
-                            p_es->fmt.psz_language = malloc( 4 );
-                            if( p_es->fmt.psz_language )
-                            {
-                                memcpy( p_es->fmt.psz_language,
-                                        p_sub->i_iso6392_language_code, 3 );
-                                p_es->fmt.psz_language[3] = 0;
-                            }
-
-                            switch( p_sub->i_subtitling_type )
-                            {
-                            case 0x10: /* unspec. */
-                            case 0x11: /* 4:3 */
-                            case 0x12: /* 16:9 */
-                            case 0x13: /* 2.21:1 */
-                                p_es->fmt.psz_description =
-                                    strdup(_("DVB subtitles"));
-                                break;
-                            case 0x20: /* Hearing impaired unspec. */
-                            case 0x21: /* h.i. 4:3 */
-                            case 0x22: /* h.i. 16:9 */
-                            case 0x23: /* h.i. 2.21:1 */
-                                p_es->fmt.psz_description =
-                                    strdup(_("DVB subtitles: hearing impaired"));
-                                break;
-                            default:
-                                break;
-                            }
-
-                            p_es->fmt.subs.dvb.i_id =
-                                p_sub->i_composition_page_id;
-                            /* Hack, FIXME */
-                            p_es->fmt.subs.dvb.i_id |=
-                              ((int)p_sub->i_ancillary_page_id << 16);
-
-                            i++;
-                        }
-
-                        if( !i )
-                            pid->es->fmt.i_cat = UNKNOWN_ES;
-                    }
-                    else
-#endif /* _DVBPSI_DR_59_H_ */
-                    {
-                        pid->es->fmt.subs.dvb.i_id = -1;
-                        pid->es->fmt.psz_description = strdup( _("DVB subtitles") );
-                    }
-                }
-            }
+            PMTSetupEs0x06(  p_demux, pid, p_es );
         }
         else if( p_es->i_type == 0xEA )
         {
-            dvbpsi_descriptor_t *p_dr;
-
-            for( p_dr = p_es->p_first_descriptor; p_dr != NULL;
-                 p_dr = p_dr->p_next )
-            {
-                msg_Dbg( p_demux, "  * es pid=%d type=%d dr->i_tag=0x%x",
-                         p_es->i_pid, p_es->i_type, p_dr->i_tag );
-
-                if( p_dr->i_tag == 0x05 )
-                {
-                    /* Registration Descriptor */
-                    if( p_dr->i_length < 4 ) // XXX VC-1 has extended this descriptor with sub-descriptor
-                    {
-                        msg_Warn( p_demux, "invalid Registration Descriptor" );
-                    }
-                    else
-                    {
-                        if( !memcmp( p_dr->p_data, "VC-1", 4 ) )
-                        {
-                            /* registration descriptor for VC-1 (SMPTE rp227) */
-                            pid->es->fmt.i_cat = VIDEO_ES;
-                            pid->es->fmt.i_codec = VLC_FOURCC('W','V','C','1');
-
-                            /* XXX With Simple and Main profile the SEQUENCE
-                             * header is modified: video width and height are
-                             * inserted just after the start code as 2 int16_t
-                             * The packetizer will take care of that. */
-                        }
-                        else
-                        {
-                            msg_Warn( p_demux,
-                                      "unknown Registration Descriptor (%4.4s)",
-                                      p_dr->p_data );
-                        }
-                    }
-                }
-            }
+            PMTSetupEs0xEA( p_demux, pid, p_es );
         }
         else if( p_es->i_type == 0xd1 )
         {
-            dvbpsi_descriptor_t *p_dr;
-
-            for( p_dr = p_es->p_first_descriptor; p_dr != NULL;
-                 p_dr = p_dr->p_next )
-            {
-                msg_Dbg( p_demux, "  * es pid=%d type=%d dr->i_tag=0x%x",
-                         p_es->i_pid, p_es->i_type, p_dr->i_tag );
-
-                if( p_dr->i_tag == 0x05 )
-                {
-                    /* Registration Descriptor */
-                    if( !memcmp( p_dr->p_data, "drac", 4 ) )
-                    {
-                        /* registration descriptor for Dirac
-                         * (backwards compatable with VC-2 (SMPTE Sxxxx:2008)) */
-                        pid->es->fmt.i_cat = VIDEO_ES;
-                        pid->es->fmt.i_codec = VLC_FOURCC('d','r','a','c');
-                    }
-                    else
-                    {
-                        msg_Warn( p_demux,
-                                  "unknown Registration Descriptor (%4.4s)",
-                                  p_dr->p_data );
-                    }
-                }
-            }
+            PMTSetupEs0xD1( p_demux, pid, p_es );
         }
         else if( p_es->i_type == 0xa0 )
         {
-            /* MSCODEC sent by vlc */
-            dvbpsi_descriptor_t *p_dr = p_es->p_first_descriptor;
-
-            while( p_dr && ( p_dr->i_tag != 0xa0 ) ) p_dr = p_dr->p_next;
-
-            if( p_dr && p_dr->i_length >= 8 )
-            {
-                pid->es->fmt.i_cat = VIDEO_ES;
-                pid->es->fmt.i_codec =
-                    VLC_FOURCC( p_dr->p_data[0], p_dr->p_data[1],
-                                p_dr->p_data[2], p_dr->p_data[3] );
-                pid->es->fmt.video.i_width =
-                    ( p_dr->p_data[4] << 8 ) | p_dr->p_data[5];
-                pid->es->fmt.video.i_height =
-                    ( p_dr->p_data[6] << 8 ) | p_dr->p_data[7];
-                pid->es->fmt.i_extra =
-                    (p_dr->p_data[8] << 8) | p_dr->p_data[9];
-
-                if( pid->es->fmt.i_extra > 0 )
-                {
-                    pid->es->fmt.p_extra = malloc( pid->es->fmt.i_extra );
-                    if( pid->es->fmt.p_extra )
-                        memcpy( pid->es->fmt.p_extra, &p_dr->p_data[10],
-                                pid->es->fmt.i_extra );
-                }
-            }
-            else
-            {
-                msg_Warn( p_demux, "private MSCODEC (vlc) without bih private "
-                          "descriptor" );
-            }
-            /* For such stream we will gather them ourself and don't launch a
-             * packetizer.
-             * Yes it's ugly but it's the only way to have DIV3 working */
-            pid->es->fmt.b_packetized = true;
+            PMTSetupEs0xA0( p_demux, pid, p_es );
         }
         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;
-            }
+            PMTSetupEsHDMV( p_demux, pid, p_es );
         }
 
         if( pid->es->fmt.i_cat == AUDIO_ES ||
             ( pid->es->fmt.i_cat == SPU_ES &&
-              pid->es->fmt.i_codec != VLC_FOURCC('d','v','b','s') &&
-              pid->es->fmt.i_codec != VLC_FOURCC('t','e','l','x') ) )
+              pid->es->fmt.i_codec != VLC_CODEC_DVBS &&
+              pid->es->fmt.i_codec != VLC_CODEC_TELETEXT ) )
         {
-            /* get language descriptor */
-            dvbpsi_descriptor_t *p_dr = p_es->p_first_descriptor;
-            while( p_dr && ( p_dr->i_tag != 0x0a ) ) p_dr = p_dr->p_next;
-
-            if( p_dr )
-            {
-                dvbpsi_iso639_dr_t *p_decoded = dvbpsi_DecodeISO639Dr( p_dr );
-
-                if( p_decoded )
-                {
-#if defined(DR_0A_API_VER) && (DR_0A_API_VER >= 2)
-                    pid->es->fmt.psz_language = malloc( 4 );
-                    if( pid->es->fmt.psz_language )
-                    {
-                        memcpy( pid->es->fmt.psz_language,
-                                p_decoded->code[0].iso_639_code, 3 );
-                        pid->es->fmt.psz_language[3] = 0;
-                        msg_Dbg( p_demux, "found language: %s", pid->es->fmt.psz_language);
-                    }
-                    switch( p_decoded->code[0].i_audio_type )
-                    {
-                    case 0:
-                        pid->es->fmt.psz_description = NULL;
-                        break;
-                    case 1:
-                        pid->es->fmt.psz_description =
-                            strdup(_("clean effects"));
-                        break;
-                    case 2:
-                        pid->es->fmt.psz_description =
-                            strdup(_("hearing impaired"));
-                        break;
-                    case 3:
-                        pid->es->fmt.psz_description =
-                            strdup(_("visual impaired commentary"));
-                        break;
-                    default:
-                        msg_Dbg( p_demux, "unknown audio type: %d",
-                                 p_decoded->code[0].i_audio_type);
-                        pid->es->fmt.psz_description = NULL;
-                        break;
-                    }
-                    pid->es->fmt.i_extra_languages = p_decoded->i_code_count-1;
-                    if( pid->es->fmt.i_extra_languages > 0 )
-                        pid->es->fmt.p_extra_languages =
-                            malloc( sizeof(*pid->es->fmt.p_extra_languages) *
-                                    pid->es->fmt.i_extra_languages );
-                    if( pid->es->fmt.p_extra_languages )
-                    {
-                        for( int i = 0; i < pid->es->fmt.i_extra_languages; i++ )
-                        {
-                            msg_Dbg( p_demux, "bang" );
-                            pid->es->fmt.p_extra_languages[i].psz_language =
-                                malloc(4);
-                            if( pid->es->fmt.p_extra_languages[i].psz_language )
-                            {
-                                memcpy( pid->es->fmt.p_extra_languages[i].psz_language,
-                                    p_decoded->code[i+1].iso_639_code, 3 );
-                                pid->es->fmt.p_extra_languages[i].psz_language[3] = '\0';
-                            }
-                            switch( p_decoded->code[i].i_audio_type )
-                            {
-                            case 0:
-                                pid->es->fmt.p_extra_languages[i].psz_description =
-                                    NULL;
-                                break;
-                            case 1:
-                                pid->es->fmt.p_extra_languages[i].psz_description =
-                                    strdup(_("clean effects"));
-                                break;
-                            case 2:
-                                pid->es->fmt.p_extra_languages[i].psz_description =
-                                    strdup(_("hearing impaired"));
-                                break;
-                            case 3:
-                                pid->es->fmt.p_extra_languages[i].psz_description =
-                                    strdup(_("visual impaired commentary"));
-                                break;
-                            default:
-                                msg_Dbg( p_demux, "unknown audio type: %d",
-                                        p_decoded->code[i].i_audio_type);
-                                pid->es->fmt.psz_description = NULL;
-                                break;
-                            }
-
-                        }
-                    }
-#else
-                    pid->es->fmt.psz_language = malloc( 4 );
-                    if( pid->es->fmt.psz_language )
-                    {
-                        memcpy( pid->es->fmt.psz_language,
-                                p_decoded->i_iso_639_code, 3 );
-                        pid->es->fmt.psz_language[3] = 0;
-                    }
-#endif
-                }
-            }
+            PMTParseEsIso639( p_demux, pid, p_es );
         }
 
         pid->es->fmt.i_group = p_pmt->i_program_number;
+        for( int i = 0; i < pid->i_extra_es; i++ )
+            pid->extra_es[i]->fmt.i_group = p_pmt->i_program_number;
+
         if( pid->es->fmt.i_cat == UNKNOWN_ES )
         {
             msg_Dbg( p_demux, "  * es pid=%d type=%d *unknown*",
@@ -3885,16 +4005,12 @@ static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
         }
         p_sys->pid[p_es->i_pid] = *pid;
 
-        for( p_dr = p_es->p_first_descriptor; p_dr != NULL;
-             p_dr = p_dr->p_next )
+        p_dr = PMTEsFindDescriptor( p_es, 0x09 );
+        if( p_dr && p_dr->i_length >= 2 )
         {
-            if( p_dr->i_tag == 0x9 )
-            {
-                uint16_t i_sysid = ((uint16_t)p_dr->p_data[0] << 8)
-                                    | p_dr->p_data[1];
-                msg_Dbg( p_demux, "   * descriptor : CA (0x9) SysID 0x%x",
-                         i_sysid );
-            }
+            uint16_t i_sysid = (p_dr->p_data[0] << 8) | p_dr->p_data[1];
+            msg_Dbg( p_demux, "   * descriptor : CA (0x9) SysID 0x%x",
+                     i_sysid );
         }
 
         if( ProgramIsSelected( p_demux, prg->i_number ) &&