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