]> git.sesse.net Git - vlc/blob - modules/demux/real.c
* modules/demux/real.c: cleanup + added support for cook.
[vlc] / modules / demux / real.c
1 /*****************************************************************************
2  * real.c: Real demuxer.
3  *****************************************************************************
4  * Copyright (C) 2004 the VideoLAN team
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 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 /*****************************************************************************
33  * Module descriptor
34  *****************************************************************************/
35 static int  Open    ( vlc_object_t * );
36 static void Close  ( vlc_object_t * );
37
38 vlc_module_begin();
39     set_description( _("Real demuxer" ) );
40     set_capability( "demux2", 15 );
41     set_category( CAT_INPUT );
42     set_subcategory( SUBCAT_INPUT_DEMUX );
43     set_callbacks( Open, Close );
44     add_shortcut( "real" );
45     add_shortcut( "rm" );
46 vlc_module_end();
47
48 /*****************************************************************************
49  * Local prototypes
50  *****************************************************************************/
51
52 typedef struct
53 {
54     int         i_id;
55     es_format_t fmt;
56
57     es_out_id_t *p_es;
58
59     int         i_frame;
60     block_t     *p_frame;
61
62 } real_track_t;
63
64 struct demux_sys_t
65 {
66     int64_t  i_data_offset;
67     int64_t  i_data_size;
68     uint32_t i_data_packets_count;
69     uint32_t i_data_packets;
70     int64_t  i_data_offset_next;
71
72     int          i_track;
73     real_track_t **track;
74
75     uint8_t buffer[65536];
76
77     int64_t     i_pcr;
78 };
79
80 static int Demux( demux_t *p_demux );
81 static int Control( demux_t *p_demux, int i_query, va_list args );
82
83 static int HeaderRead( demux_t *p_demux );
84 static int ReadCodecSpecificData( demux_t *p_demux, int i_len, int i_num );
85
86 /*****************************************************************************
87  * Open
88  *****************************************************************************/
89 static int Open( vlc_object_t *p_this )
90 {
91     demux_t     *p_demux = (demux_t*)p_this;
92     demux_sys_t *p_sys;
93
94     uint8_t     *p_peek;
95
96     if( stream_Peek( p_demux->s, &p_peek, 10 ) < 10 ) return VLC_EGENERIC;
97     if( strncmp( (char *)p_peek, ".RMF", 4 ) ) return VLC_EGENERIC;
98
99     /* Fill p_demux field */
100     p_demux->pf_demux = Demux;
101     p_demux->pf_control = Control;
102     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
103     p_sys->i_data_offset = 0;
104     p_sys->i_track = 0;
105     p_sys->track   = NULL;
106     p_sys->i_pcr   = 1;
107
108
109     /* Parse the headers */
110     if( HeaderRead( p_demux ) )
111     {
112         int i;
113         msg_Err( p_demux, "invalid header" );
114         for( i = 0; i < p_sys->i_track; i++ )
115         {
116             real_track_t *tk = p_sys->track[i];
117
118             if( tk->p_es )
119             {
120                 es_out_Del( p_demux->out, tk->p_es );
121             }
122             free( tk );
123         }
124         if( p_sys->i_track > 0 )
125         {
126             free( p_sys->track );
127         }
128         free( p_sys );
129         return VLC_EGENERIC;
130     }
131
132     return VLC_SUCCESS;
133 }
134
135 /*****************************************************************************
136  * Close
137  *****************************************************************************/
138 static void Close( vlc_object_t *p_this )
139 {
140     demux_t *p_demux = (demux_t*)p_this;
141     demux_sys_t *p_sys = p_demux->p_sys;
142     int i;
143
144     for( i = 0; i < p_sys->i_track; i++ )
145     {
146         real_track_t *tk = p_sys->track[i];
147
148         if( tk->p_frame )
149         {
150             block_Release( tk->p_frame );
151         }
152         free( tk );
153     }
154
155     if( p_sys->i_track > 0 )
156     {
157         free( p_sys->track );
158     }
159
160     free( p_sys );
161 }
162
163
164 /*****************************************************************************
165  * Demux:
166  *****************************************************************************/
167 static int Demux( demux_t *p_demux )
168 {
169     demux_sys_t *p_sys = p_demux->p_sys;
170     uint8_t     header[18];
171     int         i_size;
172     int         i_id;
173     int64_t     i_pts;
174     int         i;
175     real_track_t *tk = NULL;
176     vlc_bool_t  b_selected;
177
178     if( p_sys->i_data_packets >= p_sys->i_data_packets_count )
179     {
180
181         if( stream_Read( p_demux->s, header, 18 ) < 18 )
182         {
183             return 0;
184         }
185         if( strncmp( (char *)header, "DATA", 4 ) )
186         {
187             return 0;
188         }
189         p_sys->i_data_offset = stream_Tell( p_demux->s ) - 18;
190         p_sys->i_data_size   = GetDWBE( &header[4] );
191         p_sys->i_data_packets_count = GetDWBE( &header[10] );
192         p_sys->i_data_packets = 0;
193         p_sys->i_data_offset_next = GetDWBE( &header[14] );
194
195         msg_Dbg( p_demux, "entering new DATA packets=%d next=%u",
196                  p_sys->i_data_packets_count,
197                  (uint32_t)p_sys->i_data_offset_next );
198     }
199
200     if( stream_Read( p_demux->s, header, 12 ) < 12 ) return 0;
201
202     i_size = GetWBE( &header[2] ) - 12;
203     i_id   = GetWBE( &header[4] );
204     i_pts  = 1000 * GetDWBE( &header[6] );
205     /* header[11] -> flags 0x02 -> keyframe */
206     msg_Dbg( p_demux, "packet %d size=%d id=%d pts=%u",
207              p_sys->i_data_packets, i_size, i_id, (uint32_t)(i_pts/1000) );
208     p_sys->i_data_packets++;
209
210     stream_Read( p_demux->s, p_sys->buffer, i_size );
211
212     for( i = 0; i < p_sys->i_track; i++ )
213     {
214         if( p_sys->track[i]->i_id == i_id )
215         {
216             tk = p_sys->track[i];
217         }
218     }
219
220     if( tk == NULL )
221     {
222         msg_Warn( p_demux, "unknown track id(0x%x)", i_id );
223         return 1;
224     }
225     es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b_selected );
226
227     if( tk->fmt.i_cat == VIDEO_ES && b_selected )
228     {
229         uint8_t *p = p_sys->buffer;
230
231         while( p < &p_sys->buffer[i_size - 2] )
232         {
233             uint8_t h = *p++;
234             int     i_len = 0;
235             int     i_copy;
236             int     i_subseq = 0;
237             int     i_seqnum = 0;
238             int     i_offset = 0;
239
240             if( (h&0xc0) == 0x40 )
241             {
242                 /* Short header */
243                 p++;
244                 i_len = &p_sys->buffer[i_size] - p;
245             }
246             else
247             {
248                 if( (h&0x40) == 0 )
249                 {
250                     i_subseq = (*p++)&0x7f;
251                 }
252                 i_len = (p[0] << 8)|p[1]; p += 2;
253                 if( (i_len&0xc000) == 0 )
254                 {
255                     i_len <<= 16;
256                     i_len |= (p[0] << 8)|p[1]; p += 2;
257                     i_len &= 0x3fffffff;
258                 }
259                 else
260                 {
261                     i_len &= 0x3fff;
262                 }
263
264                 i_offset = (p[0] << 8)|p[1]; p += 2;
265                 if( (i_offset&0xc000) == 0 )
266                 {
267                     i_offset <<= 16;
268                     i_offset |= (p[0] << 8)|p[1]; p += 2;
269                     i_offset &= 0x3fffffff;
270                 }
271                 else
272                 {
273                     i_offset &= 0x3fff;
274                 }
275                 i_seqnum = *p++;
276             }
277
278             i_copy = i_len - i_offset;
279             if( i_copy > &p_sys->buffer[i_size] - p )
280             {
281                 i_copy = &p_sys->buffer[i_size] - p;
282             }
283             else if( i_copy < 0 )
284             {
285                 break;
286             }
287
288             msg_Dbg( p_demux, "    - len=%d offset=%d size=%d subseq=%d seqnum=%d",
289                      i_len, i_offset, i_copy, i_subseq, i_seqnum );
290
291             if( (h&0xc0) == 0x80 )
292             {
293                 /* last fragment -> fixes */
294                 i_copy = i_offset;
295                 i_offset = i_len - i_copy;
296                 msg_Dbg( p_demux, "last fixing copy=%d offset=%d",
297                          i_copy, i_offset );
298             }
299
300             if( tk->p_frame &&
301                 ( tk->p_frame->i_dts != i_pts ||
302                   tk->i_frame != i_len ) )
303             {
304                 msg_Dbg( p_demux, "sending size=%d", tk->p_frame->i_buffer );
305
306                 if( p_sys->i_pcr < tk->p_frame->i_dts )
307                 {
308                     p_sys->i_pcr = tk->p_frame->i_dts;
309
310                     es_out_Control( p_demux->out, ES_OUT_SET_PCR,
311                                     (int64_t)p_sys->i_pcr );
312                 }
313                 es_out_Send( p_demux->out, tk->p_es, tk->p_frame );
314
315                 tk->i_frame = 0;
316                 tk->p_frame = NULL;
317             }
318
319             if( (h&0xc0) != 0x80 && (h&0xc0) != 0x00 && !tk->p_frame )
320             {
321                 /* no fragment */
322                 i_len = i_copy;
323                 i_offset = 0;
324             }
325
326
327             if( tk->p_frame == NULL )
328             {
329                 msg_Dbg( p_demux, "new frame size=%d", i_len );
330                 tk->i_frame = i_len;
331                 if( !( tk->p_frame = block_New( p_demux, i_len + 8 + 1000) ) )
332                 {
333                     return -1;
334                 }
335                 memset( &tk->p_frame->p_buffer[8], 0, i_len );
336                 tk->p_frame->i_dts = i_pts;
337                 tk->p_frame->i_pts = i_pts;
338
339                 ((uint32_t*)tk->p_frame->p_buffer)[0] = i_len;  /* len */
340                 ((uint32_t*)tk->p_frame->p_buffer)[1] = 0;      /* chunk counts */
341             }
342
343             if( i_offset < tk->i_frame)
344             {
345                 int i_ck = ((uint32_t*)tk->p_frame->p_buffer)[1]++;
346
347                 msg_Dbg( p_demux, "copying new buffer n=%d offset=%d copy=%d",
348                          i_ck, i_offset, i_copy );
349
350                 ((uint32_t*)(tk->p_frame->p_buffer+i_len+8))[i_ck] = i_offset;
351
352                 memcpy( &tk->p_frame->p_buffer[i_offset + 8], p, i_copy );
353             }
354
355             p += i_copy;
356
357             if( (h&0xc0) != 0x80 )
358             {
359                 break;
360             }
361
362 #if 0
363             if( tk->p_frame )
364             {
365                 /* append data */
366                 int i_ck = ((uint32_t*)tk->p_frame->p_buffer)[1]++;
367
368                 if( (h&0xc0) == 0x80 )
369                 {
370                     /* last fragment */
371                     i_copy = i_offset;
372                     i_offset = i_len - i_offset;
373
374                     ((uint32_t*)(tk->p_frame->p_buffer+i_len+8))[i_ck] = i_offset;
375                     memcpy( &tk->p_frame->p_buffer[i_offset+ 8], p, i_copy );
376                     p += i_copy;
377
378                     if( p_sys->i_pcr < tk->p_frame->i_dts )
379                     {
380                         p_sys->i_pcr = tk->p_frame->i_dts;
381                         es_out_Control( p_demux->out, ES_OUT_SET_PCR,
382                                         (int64_t)p_sys->i_pcr );
383                     }
384                     es_out_Send( p_demux->out, tk->p_es, tk->p_frame );
385
386                     tk->i_frame = 0;
387                     tk->p_frame = NULL;
388
389                     continue;
390                 }
391
392                 ((uint32_t*)(tk->p_frame->p_buffer+i_len+8))[i_ck] = i_offset;
393                 memcpy( &tk->p_frame->p_buffer[i_offset + 8], p, i_copy );
394                 break;
395             }
396
397             if( (h&0xc0) != 0x00 )
398             {
399                 block_t *p_frame;
400
401                 /* not fragmented */
402                 if( !( p_frame = block_New( p_demux, i_copy + 8 + 8 ) ) )
403                 {
404                     return -1;
405                 }
406                 p_frame->i_dts = i_pts;
407                 p_frame->i_pts = i_pts;
408
409                 ((uint32_t*)p_frame->p_buffer)[0] = i_copy;
410                 ((uint32_t*)p_frame->p_buffer)[1] = 1;
411                 ((uint32_t*)(p_frame->p_buffer+i_copy+8))[0] = 0;
412                 memcpy( &p_frame->p_buffer[8], p, i_copy );
413
414                 p += i_copy;
415
416                 if( p_sys->i_pcr < p_frame->i_dts )
417                 {
418                     p_sys->i_pcr = p_frame->i_dts;
419                     es_out_Control( p_demux->out, ES_OUT_SET_PCR,
420                                     (int64_t)p_sys->i_pcr );
421                 }
422                 es_out_Send( p_demux->out, tk->p_es, p_frame );
423             }
424             else
425             {
426                 /* First fragment */
427                 tk->i_frame = i_len;
428                 if( !( tk->p_frame = block_New( p_demux, i_len + 8 + 1000) ) )
429                 {
430                     return -1;
431                 }
432                 memset( &tk->p_frame->p_buffer[8], 0, i_len );
433                 tk->p_frame->i_dts = i_pts;
434                 tk->p_frame->i_pts = i_pts;
435
436                 ((uint32_t*)tk->p_frame->p_buffer)[0] = i_len;  /* len */
437                 ((uint32_t*)tk->p_frame->p_buffer)[1] = 1;      /* chunk counts */
438                 ((uint32_t*)(tk->p_frame->p_buffer+i_len+8))[0] = i_offset;
439                 memcpy( &tk->p_frame->p_buffer[i_offset + 8], p, i_copy );
440
441                 break;
442             }
443 #endif
444         }
445     }
446     else if( tk->fmt.i_cat == AUDIO_ES && b_selected )
447     {
448         /* Set PCR */
449         if( p_sys->i_pcr < i_pts )
450         {
451             p_sys->i_pcr = i_pts;
452             es_out_Control( p_demux->out, ES_OUT_SET_PCR,
453                             (int64_t)p_sys->i_pcr );
454         }
455
456         if( tk->fmt.i_codec == VLC_FOURCC( 'm', 'p', '4', 'a' ) )
457         {
458             int     i_sub = (p_sys->buffer[1] >> 4)&0x0f;
459             uint8_t *p_sub = &p_sys->buffer[2+2*i_sub];
460
461             int i;
462             for( i = 0; i < i_sub; i++ )
463             {
464                 int i_sub_size = GetWBE( &p_sys->buffer[2+i*2]);
465                 block_t *p_block = block_New( p_demux, i_sub_size );
466                 if( p_block )
467                 {
468                     memcpy( p_block->p_buffer, p_sub, i_sub_size );
469                     p_sub += i_sub_size;
470
471                     p_block->i_dts =
472                     p_block->i_pts = ( i == 0 ? i_pts : 0 );
473
474                     es_out_Send( p_demux->out, tk->p_es, p_block );
475                 }
476             }
477         }
478         else
479         {
480             block_t *p_block = block_New( p_demux, i_size );
481
482             if( tk->fmt.i_codec == VLC_FOURCC( 'a', '5', '2', ' ' ) )
483             {
484                 uint8_t *src = p_sys->buffer;
485                 uint8_t *dst = p_block->p_buffer;
486
487                 /* byte swap data */
488                 while( dst < &p_block->p_buffer[i_size- 1])
489                 {
490                     *dst++ = src[1];
491                     *dst++ = src[0];
492
493                     src += 2;
494                 }
495             }
496             else
497             {
498                 memcpy( p_block->p_buffer, p_sys->buffer, i_size );
499             }
500             p_block->i_dts =
501             p_block->i_pts = i_pts;
502
503             es_out_Send( p_demux->out, tk->p_es, p_block );
504         }
505     }
506
507
508     return 1;
509 }
510
511 /*****************************************************************************
512  * Control:
513  *****************************************************************************/
514 static int Control( demux_t *p_demux, int i_query, va_list args )
515 {
516 #if 0
517     demux_sys_t *p_sys = p_demux->p_sys;
518     double f, *pf;
519     int64_t i64, *pi64;
520
521     switch( i_query )
522     {
523         case DEMUX_GET_POSITION:
524             pf = (double*) va_arg( args, double* );
525             i64 = stream_Size( p_demux->s );
526             if( i64 > 0 )
527             {
528                 *pf = (double)stream_Tell( p_demux->s ) / (double)i64;
529             }
530             else
531             {
532                 *pf = 0.0;
533             }
534             return VLC_SUCCESS;
535         case DEMUX_SET_POSITION:
536             f = (double) va_arg( args, double );
537             i64 = stream_Size( p_demux->s );
538
539             es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
540
541             return stream_Seek( p_demux->s, (int64_t)(i64 * f) );
542
543         case DEMUX_GET_TIME:
544             pi64 = (int64_t*)va_arg( args, int64_t * );
545             if( p_sys->i_mux_rate > 0 )
546             {
547                 *pi64 = (int64_t)1000000 * ( stream_Tell( p_demux->s ) / 50 ) / p_sys->i_mux_rate;
548                 return VLC_SUCCESS;
549             }
550             *pi64 = 0;
551             return VLC_EGENERIC;
552
553         case DEMUX_GET_LENGTH:
554             pi64 = (int64_t*)va_arg( args, int64_t * );
555             if( p_sys->i_mux_rate > 0 )
556             {
557                 *pi64 = (int64_t)1000000 * ( stream_Size( p_demux->s ) / 50 ) / p_sys->i_mux_rate;
558                 return VLC_SUCCESS;
559             }
560             *pi64 = 0;
561             return VLC_EGENERIC;
562
563         case DEMUX_SET_TIME:
564         case DEMUX_GET_FPS:
565         default:
566             return VLC_EGENERIC;
567     }
568 #endif
569     return VLC_EGENERIC;
570 }
571
572 /*****************************************************************************
573  * HeaderRead:
574  *****************************************************************************/
575 static int HeaderRead( demux_t *p_demux )
576 {
577     demux_sys_t *p_sys = p_demux->p_sys;
578     uint8_t header[100];    /* FIXME */
579
580     uint32_t    i_id;
581     uint32_t    i_size;
582     int64_t     i_skip;
583     int         i_version;
584
585     for( ;; )
586     {
587         /* Read the header */
588         if( stream_Read( p_demux->s, header, 10 ) < 10 )
589         {
590             return VLC_EGENERIC;
591         }
592         i_id        = VLC_FOURCC( header[0], header[1], header[2], header[3] );
593         i_size      = GetDWBE( &header[4] );
594         i_version   = GetWBE( &header[8] );
595
596         msg_Dbg( p_demux, "object %4.4s size=%d version=%d",
597                  (char*)&i_id, i_size, i_version );
598
599         if( i_size < 10 ) return VLC_EGENERIC;
600         i_skip = i_size - 10;
601
602         if( i_id == VLC_FOURCC('.','R','M','F') )
603         {
604             if( stream_Read( p_demux->s, header, 8 ) < 8 ) return VLC_EGENERIC;
605             msg_Dbg( p_demux, "    - file version=0x%x num headers=%d",
606                      GetDWBE( &header[0] ), GetDWBE( &header[4] ) );
607
608             i_skip -= 8;
609         }
610         else if( i_id == VLC_FOURCC('P','R','O','P') )
611         {
612             int i_flags;
613
614             if( stream_Read(p_demux->s, header, 40) < 40 ) return VLC_EGENERIC;
615
616             msg_Dbg( p_demux, "    - max bitrate=%d avg bitrate=%d",
617                      GetDWBE(&header[0]), GetDWBE(&header[4]) );
618             msg_Dbg( p_demux, "    - max packet size=%d avg bitrate=%d",
619                      GetDWBE(&header[8]), GetDWBE(&header[12]) );
620             msg_Dbg( p_demux, "    - packets count=%d", GetDWBE(&header[16]) );
621             msg_Dbg( p_demux, "    - duration=%d ms", GetDWBE(&header[20]) );
622             msg_Dbg( p_demux, "    - preroll=%d ms", GetDWBE(&header[24]) );
623             msg_Dbg( p_demux, "    - index offset=%d", GetDWBE(&header[28]) );
624             msg_Dbg( p_demux, "    - data offset=%d", GetDWBE(&header[32]) );
625             msg_Dbg( p_demux, "    - num streams=%d", GetWBE(&header[36]) );
626             i_flags = GetWBE(&header[38]);
627             msg_Dbg( p_demux, "    - flags=0x%x %s%s%s",
628                      i_flags,
629                      i_flags&0x0001 ? "PN_SAVE_ENABLED " : "",
630                      i_flags&0x0002 ? "PN_PERFECT_PLAY_ENABLED " : "",
631                      i_flags&0x0004 ? "PN_LIVE_BROADCAST" : "" );
632             i_skip -= 40;
633         }
634         else if( i_id == VLC_FOURCC('C','O','N','T') )
635         {
636             int i_len;
637             char *psz;
638
639             stream_Read( p_demux->s, header, 2 );
640             if( ( i_len = GetWBE( header ) ) > 0 )
641             {
642                 psz = malloc( i_len + 1 );
643                 stream_Read( p_demux->s, psz, i_len );
644                 psz[i_len] = '\0';
645
646                 msg_Dbg( p_demux, "    - title=`%s'", psz );
647                 free( psz );
648                 i_skip -= i_len;
649             }
650             i_skip -= 2;
651
652             stream_Read( p_demux->s, header, 2 );
653             if( ( i_len = GetWBE( header ) ) > 0 )
654             {
655                 psz = malloc( i_len + 1 );
656                 stream_Read( p_demux->s, psz, i_len );
657                 psz[i_len] = '\0';
658
659                 msg_Dbg( p_demux, "    - author=`%s'", psz );
660                 free( psz );
661                 i_skip -= i_len;
662             }
663             i_skip -= 2;
664
665             stream_Read( p_demux->s, header, 2 );
666             if( ( i_len = GetWBE( header ) ) > 0 )
667             {
668                 psz = malloc( i_len + 1 );
669                 stream_Read( p_demux->s, psz, i_len );
670                 psz[i_len] = '\0';
671
672                 msg_Dbg( p_demux, "    - copyright=`%s'", psz );
673                 free( psz );
674                 i_skip -= i_len;
675             }
676             i_skip -= 2;
677
678             stream_Read( p_demux->s, header, 2 );
679             if( ( i_len = GetWBE( header ) ) > 0 )
680             {
681                 psz = malloc( i_len + 1 );
682                 stream_Read( p_demux->s, psz, i_len );
683                 psz[i_len] = '\0';
684
685                 msg_Dbg( p_demux, "    - comment=`%s'", psz );
686                 free( psz );
687                 i_skip -= i_len;
688             }
689             i_skip -= 2;
690         }
691         else if( i_id == VLC_FOURCC('M','D','P','R') )
692         {
693             /* Media properties header */
694             int  i_num;
695             int  i_len;
696             char *psz;
697
698             if( stream_Read(p_demux->s, header, 30) < 30 ) return VLC_EGENERIC;
699             i_num = GetWBE( header );
700             msg_Dbg( p_demux, "    - id=0x%x", i_num );
701             msg_Dbg( p_demux, "    - max bitrate=%d avg bitrate=%d",
702                      GetDWBE(&header[2]), GetDWBE(&header[6]) );
703             msg_Dbg( p_demux, "    - max packet size=%d avg packet size=%d",
704                      GetDWBE(&header[10]), GetDWBE(&header[14]) );
705             msg_Dbg( p_demux, "    - start time=%d", GetDWBE(&header[18]) );
706             msg_Dbg( p_demux, "    - preroll=%d", GetDWBE(&header[22]) );
707             msg_Dbg( p_demux, "    - duration=%d", GetDWBE(&header[26]) );
708             i_skip -= 30;
709
710             stream_Read( p_demux->s, header, 1 );
711             if( ( i_len = header[0] ) > 0 )
712             {
713                 psz = malloc( i_len + 1 );
714                 stream_Read( p_demux->s, psz, i_len );
715                 psz[i_len] = '\0';
716
717                 msg_Dbg( p_demux, "    - name=`%s'", psz );
718                 free( psz );
719                 i_skip -= i_len;
720             }
721             i_skip--;
722
723             stream_Read( p_demux->s, header, 1 );
724             if( ( i_len = header[0] ) > 0 )
725             {
726                 psz = malloc( i_len + 1 );
727                 stream_Read( p_demux->s, psz, i_len );
728                 psz[i_len] = '\0';
729
730                 msg_Dbg( p_demux, "    - mime=`%s'", psz );
731                 free( psz );
732                 i_skip -= i_len;
733             }
734             i_skip--;
735
736             stream_Read( p_demux->s, header, 4 );
737             if( ( i_len = GetDWBE( header ) ) > 0 )
738             {
739                 ReadCodecSpecificData( p_demux, i_len, i_num );
740                 stream_Read( p_demux->s, NULL, i_len );
741
742                 i_skip -= i_len;
743             }
744             i_skip -= 4;
745         }
746         else if( i_id == VLC_FOURCC('D','A','T','A') )
747         {
748             stream_Read( p_demux->s, header, 8 );
749
750             p_sys->i_data_offset    = stream_Tell( p_demux->s ) - 10;
751             p_sys->i_data_size      = i_size;
752             p_sys->i_data_packets_count = GetDWBE( header );
753             p_sys->i_data_packets   = 0;
754             p_sys->i_data_offset_next = GetDWBE( &header[4] );
755
756             msg_Dbg( p_demux, "    - packets count=%d next=%u",
757                      p_sys->i_data_packets_count,
758                      (uint32_t)p_sys->i_data_offset_next );
759
760             /* we have finished the header */
761             break;
762         }
763         else
764         {
765             /* unknow header */
766             msg_Dbg( p_demux, "unknown chunk" );
767         }
768
769         if( i_skip < 0 ) return VLC_EGENERIC;
770         stream_Read( p_demux->s, NULL, i_skip );
771     }
772
773     /* TODO read index if possible */
774
775     return VLC_SUCCESS;
776 }
777
778 static int ReadCodecSpecificData( demux_t *p_demux, int i_len, int i_num )
779 {
780     demux_sys_t *p_sys = p_demux->p_sys;
781     es_format_t fmt;
782     real_track_t *tk;
783     uint8_t *p_peek;
784
785     msg_Dbg( p_demux, "    - specific data len=%d", i_len );
786     if( stream_Peek(p_demux->s, &p_peek, i_len) < i_len ) return VLC_EGENERIC;
787
788     if( !strncmp( (char *)&p_peek[4], "VIDO", 4 ) )
789     {
790         es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC( p_peek[8], p_peek[9],
791                         p_peek[10], p_peek[11] ) );
792         fmt.video.i_width = GetWBE( &p_peek[12] );
793         fmt.video.i_height= GetWBE( &p_peek[14] );
794
795         fmt.i_extra = 8;
796         fmt.p_extra = malloc( 8 );
797         ((uint32_t*)fmt.p_extra)[0] = GetDWBE( &p_peek[26] );
798         ((uint32_t*)fmt.p_extra)[1] = GetDWBE( &p_peek[30] );
799
800         msg_Dbg( p_demux, "    - video 0x%08x 0x%08x",
801                  ((uint32_t*)fmt.p_extra)[0], ((uint32_t*)fmt.p_extra)[1] );
802
803         if( GetDWBE( &p_peek[30] ) == 0x10003000 ||
804             GetDWBE( &p_peek[30] ) == 0x10003001 )
805         {
806             fmt.i_codec = VLC_FOURCC( 'R','V','1','3' );
807         }
808
809         msg_Dbg( p_demux, "    - video %4.4s %dx%d",
810                  (char*)&fmt.i_codec, fmt.video.i_width, fmt.video.i_height );
811
812         tk = malloc( sizeof( real_track_t ) );
813         tk->i_id = i_num;
814         tk->fmt = fmt;
815         tk->i_frame = 0;
816         tk->p_frame = NULL;
817         tk->p_es = es_out_Add( p_demux->out, &fmt );
818
819         TAB_APPEND( p_sys->i_track, p_sys->track, tk );
820     }
821     else if( !strncmp( (char *)p_peek, ".ra\xfd", 4 ) )
822     {
823         int i_version = GetWBE( &p_peek[4] );
824         int i_header_size, i_flavor, i_coded_frame_size, i_subpacket_h;
825         int i_frame_size, i_subpacket_size;
826
827         msg_Dbg( p_demux, "    - audio version=%d", i_version );
828
829         p_peek += 6;
830         es_format_Init( &fmt, AUDIO_ES, 0 );
831
832         if( i_version == 3 )
833         {
834             msg_Dbg( p_demux, "    - audio version 3 is not supported!" );
835             return VLC_EGENERIC;
836         }
837
838         p_peek += 2; /* 00 00 */
839         p_peek += 4; /* .ra4 or .ra5 */
840         p_peek += 4; /* ?? */
841         p_peek += 2; /* version (4 or 5) */
842         i_header_size = GetDWBE( p_peek ); p_peek += 4; /* header size */
843         i_flavor = GetWBE( p_peek ); p_peek += 2; /* codec flavor */
844         i_coded_frame_size = GetDWBE( p_peek ); p_peek += 4;
845         p_peek += 4; /* ?? */
846         p_peek += 4; /* ?? */
847         p_peek += 4; /* ?? */
848         i_subpacket_h = GetWBE( p_peek ); p_peek += 2;
849         i_frame_size = GetWBE( p_peek ); p_peek += 2;
850         i_subpacket_size = GetWBE( p_peek ); p_peek += 2;
851         p_peek += 2; /* ?? */
852
853         if( i_version == 5 ) p_peek += 6; /* 0, srate, 0 */
854
855         fmt.audio.i_rate = GetWBE( p_peek ); p_peek += 2;
856         p_peek += 2; /* ?? */
857         fmt.audio.i_bitspersample = GetWBE( p_peek ); p_peek += 2;
858         fmt.audio.i_channels = GetWBE( p_peek ); p_peek += 2;
859         fmt.audio.i_blockalign = i_frame_size;
860
861         if( i_version == 5 )
862         {
863             p_peek += 4; /* genr */
864             memcpy( (char *)&fmt.i_codec, p_peek, 4 ); p_peek += 4;
865         }
866         else
867         {
868             p_peek += p_peek[0] + 1; /* descr 1 */
869             memcpy( (char *)&fmt.i_codec, p_peek + 1, 4 ); /* descr 2 */
870             p_peek += p_peek[0] + 1;
871         }
872
873         msg_Dbg( p_demux, "    - audio codec=%4.4s channels=%d rate=%dHz",
874                  (char*)&fmt.i_codec, fmt.audio.i_channels, fmt.audio.i_rate );
875
876         p_peek += 3; /* ?? */
877         if( i_version == 5 ) p_peek++;
878
879         switch( fmt.i_codec )
880         {
881         case VLC_FOURCC( 'd', 'n', 'e', 't' ):
882             fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
883             break;
884
885         case VLC_FOURCC( 'r', 'a', 'a', 'c' ):
886         case VLC_FOURCC( 'r', 'a', 'c', 'p' ):
887             fmt.i_extra = GetDWBE( p_peek ); p_peek += 4;
888             if( fmt.i_extra > 0 ) { fmt.i_extra--; p_peek++; }
889             if( fmt.i_extra > 0 )
890             {
891                 fmt.p_extra = malloc( fmt.i_extra );
892                 memcpy( fmt.p_extra, p_peek, fmt.i_extra );
893             }
894
895             fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
896             break;
897
898         case VLC_FOURCC('c','o','o','k'):
899             fmt.i_extra = GetDWBE( p_peek ); p_peek += 4;
900             fmt.p_extra = malloc( fmt.i_extra + 10 );
901
902             ((short*)(fmt.p_extra))[0] = i_subpacket_size;
903             ((short*)(fmt.p_extra))[1] = i_subpacket_h;
904             ((short*)(fmt.p_extra))[2] = i_flavor;
905             ((short*)(fmt.p_extra))[3] = i_coded_frame_size;
906             ((short*)(fmt.p_extra))[4] = fmt.i_extra;
907             if( fmt.i_extra ) memcpy( fmt.p_extra + 10, p_peek, fmt.i_extra );
908             fmt.i_extra += 10;
909             break;
910
911         default:
912             msg_Dbg( p_demux, "    - unknown audio codec=%4.4s",
913                      (char*)&fmt.i_codec );
914             break;
915         }
916
917         if( fmt.i_codec != 0 )
918         {
919             msg_Dbg( p_demux, "        - extra data=%d", fmt.i_extra );
920             {
921                 int i;
922                 for( i = 0; i < fmt.i_extra; i++ )
923                 {
924                     msg_Dbg( p_demux, "          data[%d] = 0x%x", i,
925                              ((uint8_t*)fmt.p_extra)[i] );
926                 }
927             }
928
929             tk = malloc( sizeof( real_track_t ) );
930             tk->i_id = i_num;
931             tk->fmt = fmt;
932             tk->i_frame = 0;
933             tk->p_frame = NULL;
934             tk->p_es = es_out_Add( p_demux->out, &fmt );
935
936             TAB_APPEND( p_sys->i_track, p_sys->track, tk );
937         }
938     }
939
940     return VLC_SUCCESS;
941 }