]> git.sesse.net Git - vlc/commitdiff
* modules/demux/ps.c,ps.h: PSM parsing remotely based on a patch by Pascal Claes.
authorGildas Bazin <gbazin@videolan.org>
Wed, 22 Sep 2004 13:43:03 +0000 (13:43 +0000)
committerGildas Bazin <gbazin@videolan.org>
Wed, 22 Sep 2004 13:43:03 +0000 (13:43 +0000)
modules/access/dvdnav.c
modules/access/dvdread.c
modules/demux/ps.c
modules/demux/ps.h

index 873b6c5b031b1f3d4eb39dc63774aa3555f0d89a..439a4181da549a18796f9b9ecd886a0b4b80a37b 100644 (file)
@@ -823,7 +823,6 @@ static void ButtonUpdate( demux_t *p_demux )
             dvdnav_get_highlight_area( pci, i_button, 1, &hl );
 
             /* I fear it is plain wrong */
-            //val.p_address = (void *)&hl.palette;
             p_sys->alpha[0] = hl.palette&0x0f;
             p_sys->alpha[1] = (hl.palette>>4)&0x0f;
             p_sys->alpha[2] = (hl.palette>>8)&0x0f;
@@ -993,7 +992,7 @@ static void ESNew( demux_t *p_demux, int i_id )
 
     if( tk->b_seen ) return;
 
-    if( ps_track_fill( tk, i_id ) )
+    if( ps_track_fill( tk, 0, i_id ) )
     {
         msg_Warn( p_demux, "unknown codec for id=0x%x", i_id );
         return;
index 297701164ada56b9418df97b882c4e23eef87324..403331d0b06e63ff055fa3e65fefdd75b64b39d8 100644 (file)
@@ -619,7 +619,7 @@ static void ESNew( demux_t *p_demux, int i_id, int i_lang )
 
     if( tk->b_seen ) return;
 
-    if( ps_track_fill( tk, i_id ) )
+    if( ps_track_fill( tk, 0, i_id ) )
     {
         msg_Warn( p_demux, "unknown codec for id=0x%x", i_id );
         return;
index 6ab15cb29e5bf48903c03dbc7d67816f4104404b..2fae218c2aee736e4efabde80fa167596cac1b12 100644 (file)
@@ -55,6 +55,7 @@ vlc_module_end();
 
 struct demux_sys_t
 {
+    ps_psm_t    psm;
     ps_track_t  tk[PS_TK_COUNT];
 
     int64_t     i_scr;
@@ -99,6 +100,7 @@ static int Open( vlc_object_t *p_this )
     p_sys->i_mux_rate = 0;
     p_sys->i_scr      = -1;
 
+    ps_psm_init( &p_sys->psm );
     ps_track_init( p_sys->tk );
 
     /* TODO prescanning of ES */
@@ -125,6 +127,8 @@ static void Close( vlc_object_t *p_this )
         }
     }
 
+    ps_psm_destroy( &p_sys->psm );
+
     free( p_sys );
 }
 
@@ -170,7 +174,7 @@ static int Demux( demux_t *p_demux )
         break;
 
     case 0x1bb:
-        if( !ps_pkt_parse_system( p_pkt, p_sys->tk ) )
+        if( !ps_pkt_parse_system( p_pkt, &p_sys->psm, p_sys->tk ) )
         {
             int i;
             for( i = 0; i < PS_TK_COUNT; i++ )
@@ -187,7 +191,8 @@ static int Demux( demux_t *p_demux )
         break;
 
     case 0x1bc:
-        /* TODO PSM */
+        msg_Dbg( p_demux, "received PSM");
+        ps_psm_fill( &p_sys->psm, p_pkt );
         block_Release( p_pkt );
         break;
 
@@ -198,7 +203,7 @@ static int Demux( demux_t *p_demux )
 
             if( !tk->b_seen )
             {
-                if( !ps_track_fill( tk, i_id ) )
+                if( !ps_track_fill( tk, &p_sys->psm, i_id ) )
                 {
                     tk->es = es_out_Add( p_demux->out, &tk->fmt );
                 }
index 44c1953fbce3c95ed0aded16b24413e0e6add067..771be59cb373b0a9f426b1921ec9d46a6403b681 100644 (file)
  *****************************************************************************/
 
 #define PS_TK_COUNT (512 - 0xc0)
-#define PS_ID_TO_TK( id ) ((id) <= 0xff ? (id) - 0xc0 : ((id)&0xff) + (256 - 0xc0))
+#define PS_ID_TO_TK( id ) ((id) <= 0xff ? (id) - 0xc0 : \
+                                          ((id)&0xff) + (256 - 0xc0))
+
+typedef struct ps_psm_t ps_psm_t;
+static inline int ps_id_to_type( ps_psm_t *, int );
 
 typedef struct
 {
@@ -30,6 +34,7 @@ typedef struct
     int         i_skip;
     es_out_id_t *es;
     es_format_t fmt;
+
 } ps_track_t;
 
 /* Init a set of track */
@@ -46,7 +51,7 @@ static inline void ps_track_init( ps_track_t tk[PS_TK_COUNT] )
 }
 
 /* From id fill i_skip and es_format_t */
-static inline int ps_track_fill( ps_track_t *tk, int i_id )
+static inline int ps_track_fill( ps_track_t *tk, ps_psm_t *p_psm, int i_id )
 {
     tk->i_skip = 0;
     if( ( i_id&0xff00 ) == 0xbd00 )
@@ -87,19 +92,32 @@ static inline int ps_track_fill( ps_track_t *tk, int i_id )
     }
     else
     {
-        if( ( i_id&0xf0 ) == 0xe0 )
+        int i_type = ps_id_to_type( p_psm , i_id );
+
+        es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
+
+        if( (i_id&0xf0) == 0xe0 && i_type == 0x10 )
+        {
+            es_format_Init( &tk->fmt, VIDEO_ES, VLC_FOURCC('m','p','4','v') );
+        }
+        else if( (i_id&0xf0) == 0xe0 && i_type == 0x02 )
         {
             es_format_Init( &tk->fmt, VIDEO_ES, VLC_FOURCC('m','p','g','v') );
         }
-        else if( ( i_id&0xe0 ) == 0xc0 )
+        else if( ( i_id&0xe0 ) == 0xc0 && i_type == 0x03 )
         {
             es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC('m','p','g','a') );
         }
-        else
+
+        if( tk->fmt.i_cat == UNKNOWN_ES && ( i_id&0xf0 ) == 0xe0 )
         {
-            es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
-            return VLC_EGENERIC;
+            es_format_Init( &tk->fmt, VIDEO_ES, VLC_FOURCC('m','p','g','v') );
         }
+        else if( tk->fmt.i_cat == UNKNOWN_ES && ( i_id&0xe0 ) == 0xc0 )
+        {
+            es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC('m','p','g','a') );
+        }
+        else return VLC_EGENERIC;
     }
 
     /* PES packets usually contain truncated frames */
@@ -183,7 +201,7 @@ static inline int ps_pkt_parse_pack( block_t *p_pkt, int64_t *pi_scr,
 }
 
 /* Parse a SYSTEM PES */
-static inline int ps_pkt_parse_system( block_t *p_pkt,
+static inline int ps_pkt_parse_system( block_t *p_pkt, ps_psm_t *p_psm,
                                        ps_track_t tk[PS_TK_COUNT] )
 {
     uint8_t *p = &p_pkt->p_buffer[6 + 3 + 1 + 1 + 1];
@@ -204,7 +222,7 @@ static inline int ps_pkt_parse_system( block_t *p_pkt,
 
             if( !tk[i_tk].b_seen )
             {
-                if( !ps_track_fill( &tk[i_tk], i_id ) )
+                if( !ps_track_fill( &tk[i_tk], p_psm, i_id ) )
                 {
                     tk[i_tk].b_seen = VLC_TRUE;
                 }
@@ -320,3 +338,112 @@ static inline int ps_pkt_parse_pes( block_t *p_pes, int i_skip_extra )
 
     return VLC_SUCCESS;
 }
+
+/* Program stream map handling */
+typedef struct p_es_t
+{
+    int i_type;
+    int i_id;
+
+    int i_descriptor;
+    uint8_t *p_descriptor;
+
+    struct ps_es_t *p_next;
+
+} ps_es_t;
+
+struct ps_psm_t
+{
+    int i_version;
+
+    int     i_es;
+    ps_es_t **es;
+};
+
+static inline int ps_id_to_type( ps_psm_t *p_psm, int i_id )
+{
+    int i;
+    for( i = 0; p_psm && i < p_psm->i_es; i++ )
+    {
+        if( p_psm->es[i]->i_id == i_id ) return p_psm->es[i]->i_type;     
+    }
+    return 0;
+}
+
+static inline void ps_psm_init( ps_psm_t *p_psm )
+{
+    p_psm->i_version = 0xFFFF;
+    p_psm->i_es = 0;
+    p_psm->es = 0;
+}
+
+static inline void ps_psm_destroy( ps_psm_t *p_psm )
+{
+    while( p_psm->i_es-- )
+    {
+        if( p_psm->es[p_psm->i_es]->i_descriptor )
+            free( p_psm->es[p_psm->i_es]->p_descriptor );
+        free( p_psm->es[p_psm->i_es] );
+    }
+    if( p_psm->es ) free( p_psm->es );
+
+    p_psm->es = 0;
+    p_psm->i_es = 0;
+}
+
+static inline int ps_psm_fill( ps_psm_t *p_psm, block_t *p_pkt )
+{
+    int i_buffer = p_pkt->i_buffer;
+    uint8_t *p_buffer = p_pkt->p_buffer;
+    int i_length, i_version, i_info_length, i_esm_length, i_es_base;
+
+    if( !p_psm || p_buffer[3] != 0xbc ) return VLC_EGENERIC;
+
+    i_length = (uint16_t)(p_buffer[4] << 8) + p_buffer[5];
+    if( i_length > i_buffer ) return VLC_EGENERIC;
+
+    //i_current_next_indicator = (p_buffer[6] && 0x01);
+    i_version = (p_buffer[6] && 0xf8);
+
+    if( p_psm->i_version == i_version ) return VLC_EGENERIC;
+
+    ps_psm_destroy( p_psm );
+
+    i_info_length = (uint16_t)(p_buffer[8] << 8) + p_buffer[9];
+    if( i_info_length + 10 > i_length ) return VLC_EGENERIC;
+
+    /* Elementary stream map */
+    i_esm_length = (uint16_t)(p_buffer[ 10 + i_info_length ] << 8) +
+        p_buffer[ 11 + i_info_length];
+    i_es_base = 12 + i_info_length;
+
+    while( i_es_base + 4 < i_length )
+    {
+        ps_es_t es;
+
+        es.i_type = p_buffer[ i_es_base  ];
+        es.i_id = p_buffer[ i_es_base + 1 ];
+        i_info_length = (uint16_t)(p_buffer[ i_es_base + 2 ] << 8) +
+            p_buffer[ i_es_base + 3 ];
+
+        if( i_es_base + 4 + i_info_length > i_length ) break;
+
+        es.p_descriptor = 0;
+        es.i_descriptor = i_info_length;
+        if( i_info_length > 0 )
+        {
+            es.p_descriptor = malloc( i_info_length );
+            memcpy( es.p_descriptor, p_buffer + i_es_base + 4, i_info_length);
+        }
+
+        p_psm->es = realloc( &p_psm->es, sizeof(ps_es_t) * (p_psm->i_es+1) );
+        *p_psm->es[p_psm->i_es++] = es;
+        i_es_base += 4 + i_info_length; 
+    }
+
+    /* TODO: CRC */
+
+    p_psm->i_version = i_version;
+
+    return VLC_SUCCESS;
+}