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