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