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