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