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