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