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