From: Gildas Bazin Date: Wed, 22 Sep 2004 13:43:03 +0000 (+0000) Subject: * modules/demux/ps.c,ps.h: PSM parsing remotely based on a patch by Pascal Claes. X-Git-Tag: 0.8.0~346 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=869331a4c7bf0a10ed69f0392f121d6eab65576a;p=vlc * modules/demux/ps.c,ps.h: PSM parsing remotely based on a patch by Pascal Claes. --- diff --git a/modules/access/dvdnav.c b/modules/access/dvdnav.c index 873b6c5b03..439a4181da 100644 --- a/modules/access/dvdnav.c +++ b/modules/access/dvdnav.c @@ -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; diff --git a/modules/access/dvdread.c b/modules/access/dvdread.c index 297701164a..403331d0b0 100644 --- a/modules/access/dvdread.c +++ b/modules/access/dvdread.c @@ -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; diff --git a/modules/demux/ps.c b/modules/demux/ps.c index 6ab15cb29e..2fae218c2a 100644 --- a/modules/demux/ps.c +++ b/modules/demux/ps.c @@ -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 ); } diff --git a/modules/demux/ps.h b/modules/demux/ps.h index 44c1953fbc..771be59cb3 100644 --- a/modules/demux/ps.h +++ b/modules/demux/ps.h @@ -22,7 +22,11 @@ *****************************************************************************/ #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; +}