]> git.sesse.net Git - vlc/blob - modules/demux/ps.h
* fixing the OSX playlist (at least it compiles again)
[vlc] / modules / demux / ps.h
1 /*****************************************************************************
2  * ps.h: Program Stream demuxer helper
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #define PS_TK_COUNT (512 - 0xc0)
25 #define PS_ID_TO_TK( id ) ((id) <= 0xff ? (id) - 0xc0 : \
26                                           ((id)&0xff) + (256 - 0xc0))
27
28 typedef struct ps_psm_t ps_psm_t;
29 static inline int ps_id_to_type( ps_psm_t *, int );
30
31 typedef struct
32 {
33     vlc_bool_t  b_seen;
34     int         i_skip;
35     int         i_id;
36     es_out_id_t *es;
37     es_format_t fmt;
38
39 } ps_track_t;
40
41 /* Init a set of track */
42 static inline void ps_track_init( ps_track_t tk[PS_TK_COUNT] )
43 {
44     int i;
45     for( i = 0; i < PS_TK_COUNT; i++ )
46     {
47         tk[i].b_seen = VLC_FALSE;
48         tk[i].i_skip = 0;
49         tk[i].i_id   = 0;
50         tk[i].es     = NULL;
51         es_format_Init( &tk[i].fmt, UNKNOWN_ES, 0 );
52     }
53 }
54
55 /* From id fill i_skip and es_format_t */
56 static inline int ps_track_fill( ps_track_t *tk, ps_psm_t *p_psm, int i_id )
57 {
58     tk->i_skip = 0;
59     tk->i_id = i_id;
60     if( ( i_id&0xff00 ) == 0xbd00 )
61     {
62         if( ( i_id&0xf8 ) == 0x88 )
63         {
64             es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC('d','t','s',' ') );
65             tk->i_skip = 4;
66         }
67         else if( ( i_id&0xf0 ) == 0x80 )
68         {
69             es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC('a','5','2',' ') );
70             tk->i_skip = 4;
71         }
72         else if( ( i_id&0xe0 ) == 0x20 )
73         {
74             es_format_Init( &tk->fmt, SPU_ES, VLC_FOURCC('s','p','u',' ') );
75             tk->i_skip = 1;
76         }
77         else if( ( i_id&0xf0 ) == 0xa0 )
78         {
79             es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC('l','p','c','m') );
80             tk->i_skip = 1;
81         }
82         else if( ( i_id&0xff ) == 0x70 )
83         {
84             es_format_Init( &tk->fmt, SPU_ES, VLC_FOURCC('o','g','t',' ') );
85         }
86         else if( ( i_id&0xfc ) == 0x00 )
87         {
88             es_format_Init( &tk->fmt, SPU_ES, VLC_FOURCC('c','v','d',' ') );
89         }
90         else
91         {
92             es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
93             return VLC_EGENERIC;
94         }
95     }
96     else
97     {
98         int i_type = ps_id_to_type( p_psm , i_id );
99
100         es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
101
102         if( (i_id&0xf0) == 0xe0 && i_type == 0x10 )
103         {
104             es_format_Init( &tk->fmt, VIDEO_ES, VLC_FOURCC('m','p','4','v') );
105         }
106         else if( (i_id&0xf0) == 0xe0 && i_type == 0x02 )
107         {
108             es_format_Init( &tk->fmt, VIDEO_ES, VLC_FOURCC('m','p','g','v') );
109         }
110         else if( ( i_id&0xe0 ) == 0xc0 && i_type == 0x03 )
111         {
112             es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC('m','p','g','a') );
113         }
114
115         if( tk->fmt.i_cat == UNKNOWN_ES && ( i_id&0xf0 ) == 0xe0 )
116         {
117             es_format_Init( &tk->fmt, VIDEO_ES, VLC_FOURCC('m','p','g','v') );
118         }
119         else if( tk->fmt.i_cat == UNKNOWN_ES && ( i_id&0xe0 ) == 0xc0 )
120         {
121             es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC('m','p','g','a') );
122         }
123         else if( tk->fmt.i_cat == UNKNOWN_ES ) return VLC_EGENERIC;
124     }
125
126     /* PES packets usually contain truncated frames */
127     tk->fmt.b_packetized = VLC_FALSE;
128
129     return VLC_SUCCESS;
130 }
131
132 /* return the id of a PES (should be valid) */
133 static inline int ps_pkt_id( block_t *p_pkt )
134 {
135     if( p_pkt->p_buffer[3] == 0xbd &&
136         p_pkt->i_buffer >= 9 &&
137         p_pkt->i_buffer >= 9 + p_pkt->p_buffer[8] )
138     {
139         return 0xbd00 | p_pkt->p_buffer[9+p_pkt->p_buffer[8]];
140     }
141     return p_pkt->p_buffer[3];
142 }
143
144 /* return the size of the next packet
145  * XXX you need to give him at least 14 bytes (and it need to start as a
146  * valid packet) */
147 static inline int ps_pkt_size( uint8_t *p, int i_peek )
148 {
149     if( p[3] == 0xb9 && i_peek >= 4 )
150     {
151         return 4;
152     }
153     else if( p[3] == 0xba )
154     {
155         if( (p[4] >> 6) == 0x01 && i_peek >= 14 )
156         {
157             return 14 + (p[13]&0x07);
158         }
159         else if( (p[4] >> 4) == 0x02 && i_peek >= 12 )
160         {
161             return 12;
162         }
163         return -1;
164     }
165     else if( i_peek >= 6 )
166     {
167         return 6 + ((p[4]<<8) | p[5] );
168     }
169     return -1;
170 }
171
172 /* parse a PACK PES */
173 static inline int ps_pkt_parse_pack( block_t *p_pkt, int64_t *pi_scr,
174                                      int *pi_mux_rate )
175 {
176     uint8_t *p = p_pkt->p_buffer;
177     if( p_pkt->i_buffer >= 14 && (p[4] >> 6) == 0x01 )
178     {
179         *pi_scr =((((int64_t)p[4]&0x38) << 27 )|
180                   (((int64_t)p[4]&0x03) << 28 )|
181                    ((int64_t)p[5] << 20 )|
182                   (((int64_t)p[6]&0xf8) << 12 )|
183                   (((int64_t)p[6]&0x03) << 13 )|
184                    ((int64_t)p[7] << 5 )|
185                    ((int64_t)p[8] >> 3 )) * 100 / 9;
186
187         *pi_mux_rate = ( p[10] << 14 )|( p[11] << 6 )|( p[12] >> 2);
188     }
189     else if( p_pkt->i_buffer >= 12 && (p[4] >> 4) == 0x02 )
190     {
191         *pi_scr =((((int64_t)p[4]&0x0e) << 29 )|
192                    ((int64_t)p[5] << 22 )|
193                   (((int64_t)p[6]&0xfe) << 14 )|
194                    ((int64_t)p[7] <<  7 )|
195                    ((int64_t)p[8] >> 1 )) * 100 / 9;
196
197         *pi_mux_rate = ( ( p[9]&0x7f )<< 15 )|( p[10] << 7 )|( p[11] >> 1);
198     }
199     else
200     {
201         return VLC_EGENERIC;
202     }
203     return VLC_SUCCESS;
204 }
205
206 /* Parse a SYSTEM PES */
207 static inline int ps_pkt_parse_system( block_t *p_pkt, ps_psm_t *p_psm,
208                                        ps_track_t tk[PS_TK_COUNT] )
209 {
210     uint8_t *p = &p_pkt->p_buffer[6 + 3 + 1 + 1 + 1];
211
212     /* System header is not useable if it references private streams (0xBD)
213      * or 'all audio streams' (0xB8) or 'all video streams' (0xB9) */
214     while( p < &p_pkt->p_buffer[p_pkt->i_buffer] )
215     {
216         int i_id = p[0];
217
218         /* fprintf( stderr, "   SYSTEM_START_CODEEE: id=0x%x\n", p[0] ); */
219         if( p[0] >= 0xBC || p[0] == 0xB8 || p[0] == 0xB9 ) p += 2;
220         p++;
221
222         if( i_id >= 0xc0 )
223         {
224             int i_tk = PS_ID_TO_TK( i_id );
225
226             if( !tk[i_tk].b_seen )
227             {
228                 if( !ps_track_fill( &tk[i_tk], p_psm, i_id ) )
229                 {
230                     tk[i_tk].b_seen = VLC_TRUE;
231                 }
232             }
233         }
234     }
235     return VLC_SUCCESS;
236 }
237
238 /* Parse a PES (and skip i_skip_extra in the payload) */
239 static inline int ps_pkt_parse_pes( block_t *p_pes, int i_skip_extra )
240 {
241     uint8_t header[30];
242     int     i_skip  = 0;
243
244     memcpy( header, p_pes->p_buffer, __MIN( p_pes->i_buffer, 30 ) );
245
246     switch( header[3] )
247     {
248         case 0xBC:  /* Program stream map */
249         case 0xBE:  /* Padding */
250         case 0xBF:  /* Private stream 2 */
251         case 0xB0:  /* ECM */
252         case 0xB1:  /* EMM */
253         case 0xFF:  /* Program stream directory */
254         case 0xF2:  /* DSMCC stream */
255         case 0xF8:  /* ITU-T H.222.1 type E stream */
256             i_skip = 6;
257             break;
258
259         default:
260             if( ( header[6]&0xC0 ) == 0x80 )
261             {
262                 /* mpeg2 PES */
263                 i_skip = header[8] + 9;
264
265                 if( header[7]&0x80 )    /* has pts */
266                 {
267                     p_pes->i_pts = ((mtime_t)(header[ 9]&0x0e ) << 29)|
268                                     (mtime_t)(header[10] << 22)|
269                                    ((mtime_t)(header[11]&0xfe) << 14)|
270                                     (mtime_t)(header[12] << 7)|
271                                     (mtime_t)(header[13] >> 1);
272
273                     if( header[7]&0x40 )    /* has dts */
274                     {
275                          p_pes->i_dts = ((mtime_t)(header[14]&0x0e ) << 29)|
276                                          (mtime_t)(header[15] << 22)|
277                                         ((mtime_t)(header[16]&0xfe) << 14)|
278                                          (mtime_t)(header[17] << 7)|
279                                          (mtime_t)(header[18] >> 1);
280                     }
281                 }
282             }
283             else
284             {
285                 i_skip = 6;
286                 while( i_skip < 23 && header[i_skip] == 0xff )
287                 {
288                     i_skip++;
289                 }
290                 if( i_skip == 23 )
291                 {
292                     /* msg_Err( p_demux, "too much MPEG-1 stuffing" ); */
293                     return VLC_EGENERIC;
294                 }
295                 if( ( header[i_skip] & 0xC0 ) == 0x40 )
296                 {
297                     i_skip += 2;
298                 }
299
300                 if(  header[i_skip]&0x20 )
301                 {
302                      p_pes->i_pts = ((mtime_t)(header[i_skip]&0x0e ) << 29)|
303                                      (mtime_t)(header[i_skip+1] << 22)|
304                                     ((mtime_t)(header[i_skip+2]&0xfe) << 14)|
305                                      (mtime_t)(header[i_skip+3] << 7)|
306                                      (mtime_t)(header[i_skip+4] >> 1);
307
308                     if( header[i_skip]&0x10 )    /* has dts */
309                     {
310                          p_pes->i_dts = ((mtime_t)(header[i_skip+5]&0x0e ) << 29)|
311                                          (mtime_t)(header[i_skip+6] << 22)|
312                                         ((mtime_t)(header[i_skip+7]&0xfe) << 14)|
313                                          (mtime_t)(header[i_skip+8] << 7)|
314                                          (mtime_t)(header[i_skip+9] >> 1);
315                          i_skip += 10;
316                     }
317                     else
318                     {
319                         i_skip += 5;
320                     }
321                 }
322                 else
323                 {
324                     i_skip += 1;
325                 }
326             }
327     }
328
329     i_skip += i_skip_extra;
330
331     if( p_pes->i_buffer <= i_skip )
332     {
333         return VLC_EGENERIC;
334     }
335
336     p_pes->p_buffer += i_skip;
337     p_pes->i_buffer -= i_skip;
338
339     p_pes->i_dts = 100 * p_pes->i_dts / 9;
340     p_pes->i_pts = 100 * p_pes->i_pts / 9;
341
342     return VLC_SUCCESS;
343 }
344
345 /* Program stream map handling */
346 typedef struct p_es_t
347 {
348     int i_type;
349     int i_id;
350
351     int i_descriptor;
352     uint8_t *p_descriptor;
353
354 } ps_es_t;
355
356 struct ps_psm_t
357 {
358     int i_version;
359
360     int     i_es;
361     ps_es_t **es;
362 };
363
364 static inline int ps_id_to_type( ps_psm_t *p_psm, int i_id )
365 {
366     int i;
367     for( i = 0; p_psm && i < p_psm->i_es; i++ )
368     {
369         if( p_psm->es[i]->i_id == i_id ) return p_psm->es[i]->i_type;     
370     }
371     return 0;
372 }
373
374 static inline void ps_psm_init( ps_psm_t *p_psm )
375 {
376     p_psm->i_version = 0xFFFF;
377     p_psm->i_es = 0;
378     p_psm->es = 0;
379 }
380
381 static inline void ps_psm_destroy( ps_psm_t *p_psm )
382 {
383     while( p_psm->i_es-- )
384     {
385         if( p_psm->es[p_psm->i_es]->i_descriptor )
386             free( p_psm->es[p_psm->i_es]->p_descriptor );
387         free( p_psm->es[p_psm->i_es] );
388     }
389     if( p_psm->es ) free( p_psm->es );
390
391     p_psm->es = 0;
392     p_psm->i_es = 0;
393 }
394
395 static inline int ps_psm_fill( ps_psm_t *p_psm, block_t *p_pkt,
396                                ps_track_t tk[PS_TK_COUNT], es_out_t *out )
397 {
398     int i_buffer = p_pkt->i_buffer;
399     uint8_t *p_buffer = p_pkt->p_buffer;
400     int i_length, i_version, i_info_length, i_esm_length, i_es_base, i;
401
402     if( !p_psm || p_buffer[3] != 0xbc ) return VLC_EGENERIC;
403
404     i_length = (uint16_t)(p_buffer[4] << 8) + p_buffer[5];
405     if( i_length > i_buffer ) return VLC_EGENERIC;
406
407     //i_current_next_indicator = (p_buffer[6] && 0x01);
408     i_version = (p_buffer[6] && 0xf8);
409
410     if( p_psm->i_version == i_version ) return VLC_EGENERIC;
411
412     ps_psm_destroy( p_psm );
413
414     i_info_length = (uint16_t)(p_buffer[8] << 8) + p_buffer[9];
415     if( i_info_length + 10 > i_length ) return VLC_EGENERIC;
416
417     /* Elementary stream map */
418     i_esm_length = (uint16_t)(p_buffer[ 10 + i_info_length ] << 8) +
419         p_buffer[ 11 + i_info_length];
420     i_es_base = 12 + i_info_length;
421
422     while( i_es_base + 4 < i_length )
423     {
424         ps_es_t es;
425
426         es.i_type = p_buffer[ i_es_base  ];
427         es.i_id = p_buffer[ i_es_base + 1 ];
428         i_info_length = (uint16_t)(p_buffer[ i_es_base + 2 ] << 8) +
429             p_buffer[ i_es_base + 3 ];
430
431         if( i_es_base + 4 + i_info_length > i_length ) break;
432
433         es.p_descriptor = 0;
434         es.i_descriptor = i_info_length;
435         if( i_info_length > 0 )
436         {
437             es.p_descriptor = malloc( i_info_length );
438             memcpy( es.p_descriptor, p_buffer + i_es_base + 4, i_info_length);
439         }
440
441         p_psm->es = realloc( p_psm->es, sizeof(ps_es_t *) * (p_psm->i_es+1) );
442         p_psm->es[p_psm->i_es] = malloc( sizeof(ps_es_t) );
443         *p_psm->es[p_psm->i_es++] = es;
444         i_es_base += 4 + i_info_length; 
445     }
446
447     /* TODO: CRC */
448
449     p_psm->i_version = i_version;
450
451     /* Check/Modify our existing tracks */
452     for( i = 0; i < PS_TK_COUNT; i++ )
453     {
454         ps_track_t tk_tmp;
455
456         if( !tk[i].b_seen || !tk[i].es ) continue;
457
458         if( ps_track_fill( &tk_tmp, p_psm, tk[i].i_id ) != VLC_SUCCESS )
459             continue;
460
461         if( tk_tmp.fmt.i_codec == tk[i].fmt.i_codec ) continue;
462
463         es_out_Del( out, tk[i].es );
464         tk[i] = tk_tmp;
465         tk[i].b_seen = VLC_TRUE;
466         tk[i].es = es_out_Add( out, &tk[i].fmt );
467     }
468
469     return VLC_SUCCESS;
470 }