]> git.sesse.net Git - vlc/blob - modules/demux/asf/asf.c
* ALL: changed the prototype of input_AddES() to include enough information so we...
[vlc] / modules / demux / asf / asf.c
1 /*****************************************************************************
2  * asf.c : ASFv01 file input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: asf.c,v 1.28 2003/05/05 22:23:35 gbazin Exp $
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #include <stdlib.h>                                      /* malloc(), free() */
27 #include <string.h>                                              /* strdup() */
28 #include <errno.h>
29 #include <sys/types.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33
34 #include "libasf.h"
35 #include "asf.h"
36
37 /*****************************************************************************
38  * Local prototypes
39  *****************************************************************************/
40 static int    Activate   ( vlc_object_t * );
41 static void   Deactivate ( vlc_object_t * );
42 static int    Demux      ( input_thread_t * );
43
44 /*****************************************************************************
45  * Module descriptor
46  *****************************************************************************/
47 vlc_module_begin();
48     set_description( _("ASF v1.0 demuxer (file only)") );
49     set_capability( "demux", 200 );
50     set_callbacks( Activate, Deactivate );
51     add_shortcut( "asf" );
52 vlc_module_end();
53
54 static uint16_t GetWLE( uint8_t *p_buff )
55 {
56     return( (p_buff[0]) + ( p_buff[1] <<8 ) );
57 }
58 static uint32_t GetDWLE( uint8_t *p_buff )
59 {
60     return( p_buff[0] + ( p_buff[1] <<8 ) +
61             ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
62 }
63
64 /*****************************************************************************
65  * Activate: check file and initializes ASF structures
66  *****************************************************************************/
67 static int Activate( vlc_object_t * p_this )
68 {
69     input_thread_t  *p_input = (input_thread_t *)p_this;
70     uint8_t         *p_peek;
71     guid_t          guid;
72
73     demux_sys_t     *p_demux;
74     int             i_stream;
75
76     vlc_bool_t      b_seekable;
77
78     /* Initialize access plug-in structures. */
79     if( p_input->i_mtu == 0 )
80     {
81         /* Improve speed. */
82         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
83     }
84
85     p_input->pf_demux = Demux;
86
87     /* a little test to see if it could be a asf stream */
88     if( input_Peek( p_input, &p_peek, 16 ) < 16 )
89     {
90         msg_Warn( p_input, "ASF v1.0 plugin discarded (cannot peek)" );
91         return( -1 );
92     }
93     GetGUID( &guid, p_peek );
94     if( !CmpGUID( &guid, &asf_object_header_guid ) )
95     {
96         msg_Warn( p_input, "ASF v1.0 plugin discarded (not a valid file)" );
97         return( -1 );
98     }
99
100     /* create our structure that will contains all data */
101     if( !( p_input->p_demux_data =
102                 p_demux = malloc( sizeof( demux_sys_t ) ) ) )
103     {
104         msg_Err( p_input, "out of memory" );
105         return( -1 );
106     }
107     memset( p_demux, 0, sizeof( demux_sys_t ) );
108     p_demux->i_pcr  = -1;
109     p_demux->i_time = -1;
110
111     /* Now load all object ( except raw data ) */
112     if( p_input->stream.b_seekable && p_input->stream.i_method == INPUT_METHOD_FILE )
113     {
114         b_seekable = VLC_TRUE;
115     }
116     else
117     {
118         b_seekable = VLC_FALSE;
119     }
120     if( !ASF_ReadObjectRoot( p_input, &p_demux->root, b_seekable ) )
121     {
122         msg_Warn( p_input, "ASF v1.0 plugin discarded (not a valid file)" );
123         free( p_demux );
124         return( -1 );
125     }
126     /* Check if we have found all mandatory asf object */
127     if( !p_demux->root.p_hdr || !p_demux->root.p_data )
128     {
129         ASF_FreeObjectRoot( p_input, &p_demux->root );
130         free( p_demux );
131         msg_Warn( p_input, "ASF v1.0 plugin discarded (not a valid file)" );
132         return( -1 );
133     }
134
135     if( !( p_demux->p_fp = ASF_FindObject( p_demux->root.p_hdr,
136                                     &asf_object_file_properties_guid, 0 ) ) )
137     {
138         ASF_FreeObjectRoot( p_input, &p_demux->root );
139         free( p_demux );
140         msg_Warn( p_input, "ASF v1.0 plugin discarded (missing file_properties object)" );
141         return( -1 );
142     }
143
144     if( p_demux->p_fp->i_min_data_packet_size != p_demux->p_fp->i_max_data_packet_size )
145     {
146         ASF_FreeObjectRoot( p_input, &p_demux->root );
147         free( p_demux );
148         msg_Warn( p_input, "ASF v1.0 plugin discarded (invalid file_properties object)" );
149         return( -1 );
150     }
151
152     p_demux->i_streams = ASF_CountObject( p_demux->root.p_hdr,
153                                           &asf_object_stream_properties_guid );
154     if( !p_demux->i_streams )
155     {
156         ASF_FreeObjectRoot( p_input, &p_demux->root );
157         free( p_demux );
158         msg_Warn( p_input, "ASF plugin discarded (cannot find any stream!)" );
159         return( -1 );
160     }
161     else
162     {
163         input_info_category_t *p_cat = input_InfoCategory( p_input, "Asf" );
164         msg_Dbg( p_input, "found %d streams", p_demux->i_streams );
165         input_AddInfo( p_cat, _("Number of streams"), "%d" , p_demux->i_streams );
166     }
167
168     /*  create one program */
169     vlc_mutex_lock( &p_input->stream.stream_lock );
170     if( input_InitStream( p_input, 0 ) == -1)
171     {
172         vlc_mutex_unlock( &p_input->stream.stream_lock );
173         msg_Err( p_input, "cannot init stream" );
174         return( -1 );
175     }
176     if( input_AddProgram( p_input, 0, 0) == NULL )
177     {
178         vlc_mutex_unlock( &p_input->stream.stream_lock );
179         msg_Err( p_input, "cannot add program" );
180         return( -1 );
181     }
182     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
183     p_input->stream.i_mux_rate = 0 ; /* FIXME */
184     vlc_mutex_unlock( &p_input->stream.stream_lock );
185
186     for( i_stream = 0; i_stream < p_demux->i_streams; i_stream ++ )
187     {
188         asf_stream_t    *p_stream;
189         asf_object_stream_properties_t *p_sp;
190         char psz_cat[sizeof("Stream ")+10];
191         input_info_category_t *p_cat;
192         sprintf( psz_cat, "Stream %d", i_stream );
193         p_cat = input_InfoCategory( p_input, psz_cat);
194
195         p_sp = ASF_FindObject( p_demux->root.p_hdr,
196                                &asf_object_stream_properties_guid,
197                                i_stream );
198
199         p_stream =
200             p_demux->stream[p_sp->i_stream_number] =
201                 malloc( sizeof( asf_stream_t ) );
202         memset( p_stream, 0, sizeof( asf_stream_t ) );
203
204         p_stream->i_time = -1;
205         p_stream->p_sp = p_sp;
206
207         vlc_mutex_lock( &p_input->stream.stream_lock );
208         p_stream->p_es = NULL;
209
210         vlc_mutex_unlock( &p_input->stream.stream_lock );
211         if( CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_audio ) )
212         {
213             int i_codec;
214             if( p_sp->p_type_specific_data )
215             {
216                 i_codec = GetWLE( p_sp->p_type_specific_data );
217             }
218             else
219             {
220                 i_codec = -1;
221             }
222
223             p_stream->i_cat = AUDIO_ES;
224             p_stream->p_es = input_AddES( p_input,
225                          p_input->stream.p_selected_program,
226                          p_sp->i_stream_number, AUDIO_ES, NULL, 0 );
227
228             input_AddInfo( p_cat, _("Type"), _("Audio") );
229             msg_Dbg( p_input,
230                     "adding new audio stream(codec:0x%x,ID:%d)",
231                     i_codec,
232                     p_sp->i_stream_number );
233             switch( i_codec )
234             {
235                 case( 0x01 ):
236                     p_stream->p_es->i_fourcc =
237                         VLC_FOURCC( 'a', 'r', 'a', 'w' );
238                     break;
239                 case( 0x50 ):
240                 case( 0x55 ):
241                     p_stream->p_es->i_fourcc =
242                         VLC_FOURCC( 'm','p','g','a' );
243                     break;
244                 case( 0x2000 ):
245                     p_stream->p_es->i_fourcc =
246                         VLC_FOURCC( 'a','5','2',' ' );
247                     break;
248                 case( 0x160 ):
249                     p_stream->p_es->i_fourcc =
250                         VLC_FOURCC( 'w','m','a','1' );
251                     break;
252                 case( 0x161 ):
253                     p_stream->p_es->i_fourcc =
254                         VLC_FOURCC( 'w','m','a','2' );
255                     break;
256                 default:
257                     p_stream->p_es->i_fourcc =
258                         VLC_FOURCC( 'm','s',(i_codec >> 8)&0xff,i_codec&0xff );
259             }
260             input_AddInfo( p_cat, _("Codec"), "%.4s", (char*)&p_stream->p_es->i_fourcc );
261             if( p_sp->i_type_specific_data_length > 0 )
262             {
263                 WAVEFORMATEX    *p_wf;
264                 size_t          i_size;
265                 uint8_t         *p_data;
266
267                 i_size = p_sp->i_type_specific_data_length;
268
269                 p_wf = malloc( i_size );
270                 p_stream->p_es->p_waveformatex = (void*)p_wf;
271                 p_data = p_sp->p_type_specific_data;
272
273                 p_wf->wFormatTag        = GetWLE( p_data );
274                 p_wf->nChannels         = GetWLE( p_data + 2 );
275                 input_AddInfo( p_cat, _("Channels"), "%d", p_wf->nChannels );
276                 p_wf->nSamplesPerSec    = GetDWLE( p_data + 4 );
277                 input_AddInfo( p_cat, _("Sample Rate"), "%d", p_wf->nSamplesPerSec );
278                 p_wf->nAvgBytesPerSec   = GetDWLE( p_data + 8 );
279                 input_AddInfo( p_cat, _("Avg. byterate"), "%d", p_wf->nAvgBytesPerSec );
280                 p_wf->nBlockAlign       = GetWLE( p_data + 12 );
281                 p_wf->wBitsPerSample    = GetWLE( p_data + 14 );
282                 input_AddInfo( p_cat, _("Bits Per Sample"), "%d", p_wf->wBitsPerSample );
283                 p_wf->cbSize            = __MAX( 0,
284                                               i_size - sizeof( WAVEFORMATEX ));
285                 if( i_size > sizeof( WAVEFORMATEX ) )
286                 {
287                     memcpy( (uint8_t*)p_wf + sizeof( WAVEFORMATEX ),
288                             p_data + sizeof( WAVEFORMATEX ),
289                             i_size - sizeof( WAVEFORMATEX ) );
290                 }
291             }
292
293         }
294         else
295         if( CmpGUID( &p_sp->i_stream_type, &asf_object_stream_type_video ) )
296         {
297             p_stream->i_cat = VIDEO_ES;
298             p_stream->p_es = input_AddES( p_input,
299                          p_input->stream.p_selected_program,
300                          p_sp->i_stream_number, VIDEO_ES, NULL, 0 );
301
302             input_AddInfo( p_cat, _("Type"), _("Video") );
303             msg_Dbg( p_input, "adding new video stream(ID:%d)",
304                      p_sp->i_stream_number );
305             if( p_sp->p_type_specific_data )
306             {
307                 p_stream->p_es->i_fourcc =
308                     VLC_FOURCC( p_sp->p_type_specific_data[27],
309                                 p_sp->p_type_specific_data[28],
310                                 p_sp->p_type_specific_data[29],
311                                 p_sp->p_type_specific_data[30] );
312             }
313             else
314             {
315                 p_stream->p_es->i_fourcc =
316                     VLC_FOURCC( 'u','n','d','f' );
317             }
318             input_AddInfo( p_cat, _("Codec"), "%.4s", (char*)&p_stream->p_es->i_fourcc );
319             if( p_sp->i_type_specific_data_length > 11 )
320             {
321                 BITMAPINFOHEADER *p_bih;
322                 size_t      i_size;
323                 uint8_t     *p_data;
324
325                 i_size = p_sp->i_type_specific_data_length - 11;
326
327                 p_bih = malloc( i_size );
328                 p_stream->p_es->p_bitmapinfoheader = (void*)p_bih;
329                 p_data = p_sp->p_type_specific_data + 11;
330
331                 p_bih->biSize       = GetDWLE( p_data );
332                 input_AddInfo( p_cat, _("Size"), "%d", p_bih->biSize );
333                 p_bih->biWidth      = GetDWLE( p_data + 4 );
334                 p_bih->biHeight     = GetDWLE( p_data + 8 );
335                 input_AddInfo( p_cat, _("Resolution"), "%dx%d", p_bih->biWidth, p_bih->biHeight );
336                 p_bih->biPlanes     = GetDWLE( p_data + 12 );
337                 input_AddInfo( p_cat, _("Planes"), "%d", p_bih->biPlanes );
338                 p_bih->biBitCount   = GetDWLE( p_data + 14 );
339                 input_AddInfo( p_cat, _("Bits Per Pixel"), "%d", p_bih->biBitCount );
340                 p_bih->biCompression= GetDWLE( p_data + 16 );
341                 p_bih->biSizeImage  = GetDWLE( p_data + 20 );
342                 input_AddInfo( p_cat, _("Image Size"), "%d", p_bih->biSizeImage );
343                 p_bih->biXPelsPerMeter = GetDWLE( p_data + 24 );
344                 input_AddInfo( p_cat, _("X pixels per meter"), "%d", p_bih->biXPelsPerMeter );
345                 p_bih->biYPelsPerMeter = GetDWLE( p_data + 28 );
346                 input_AddInfo( p_cat, _("Y pixels per meter"), "%d", p_bih->biYPelsPerMeter );
347                 p_bih->biClrUsed       = GetDWLE( p_data + 32 );
348                 p_bih->biClrImportant  = GetDWLE( p_data + 36 );
349
350                 if( i_size > sizeof( BITMAPINFOHEADER ) )
351                 {
352                     memcpy( (uint8_t*)p_bih + sizeof( BITMAPINFOHEADER ),
353                             p_data + sizeof( BITMAPINFOHEADER ),
354                             i_size - sizeof( BITMAPINFOHEADER ) );
355                 }
356             }
357
358         }
359         else
360         {
361             p_stream->i_cat = UNKNOWN_ES;
362             msg_Dbg( p_input, "ignoring unknown stream(ID:%d)",
363                      p_sp->i_stream_number );
364         }
365
366         vlc_mutex_lock( &p_input->stream.stream_lock );
367         if( p_stream->p_es )
368         {
369             input_SelectES( p_input, p_stream->p_es );
370         }
371         vlc_mutex_unlock( &p_input->stream.stream_lock );
372     }
373
374
375     p_demux->i_data_begin = p_demux->root.p_data->i_object_pos + 50;
376     if( p_demux->root.p_data->i_object_size != 0 )
377     { // local file
378         p_demux->i_data_end = p_demux->root.p_data->i_object_pos +
379                                     p_demux->root.p_data->i_object_size;
380     }
381     else
382     { // live/broacast
383         p_demux->i_data_end = -1;
384     }
385
386
387     // go to first packet
388     ASF_SeekAbsolute( p_input, p_demux->i_data_begin );
389
390     vlc_mutex_lock( &p_input->stream.stream_lock );
391     /* try to calculate movie time */
392     if( p_demux->p_fp->i_data_packets_count > 0 )
393     {
394         int64_t i_count;
395         mtime_t i_length;
396
397         /* real number of packets */
398         i_count = ( p_input->stream.p_selected_area->i_size -
399                        p_demux->i_data_begin ) /
400                             p_demux->p_fp->i_min_data_packet_size;
401         /* calculate the time duration in s */
402         i_length = (mtime_t)p_demux->p_fp->i_play_duration / 10 *
403                    (mtime_t)i_count /
404                    (mtime_t)p_demux->p_fp->i_data_packets_count /
405                    (mtime_t)1000000;
406         if( i_length > 0 )
407         {
408             p_input->stream.i_mux_rate =
409                 p_input->stream.p_selected_area->i_size / 50 / i_length;
410         }
411         else
412         {
413             p_input->stream.i_mux_rate = 0;
414         }
415
416     }
417     else
418     {
419         /* cannot known */
420         p_input->stream.i_mux_rate = 0;
421     }
422
423
424
425     p_input->stream.p_selected_program->b_is_ok = 1;
426     vlc_mutex_unlock( &p_input->stream.stream_lock );
427
428     return( 0 );
429 }
430
431
432 static mtime_t GetMoviePTS( demux_sys_t *p_demux )
433 {
434     mtime_t i_time;
435     int     i_stream;
436
437     i_time = -1;
438     for( i_stream = 0; i_stream < 128 ; i_stream++ )
439     {
440 #define p_stream p_demux->stream[i_stream]
441         if( p_stream && p_stream->p_es && p_stream->p_es->p_decoder_fifo && p_stream->i_time > 0)
442         {
443             if( i_time < 0 )
444             {
445                 i_time = p_stream->i_time;
446             }
447             else
448             {
449                 i_time = __MIN( i_time, p_stream->i_time );
450             }
451         }
452 #undef p_stream
453     }
454
455     return( i_time );
456 }
457
458 /*****************************************************************************
459  * Demux: read packet and send them to decoders
460  *****************************************************************************/
461 #define GETVALUE2b( bits, var, def ) \
462     switch( (bits)&0x03 ) \
463     { \
464         case 1: var = p_peek[i_skip]; i_skip++; break; \
465         case 2: var = GetWLE( p_peek + i_skip );  i_skip+= 2; break; \
466         case 3: var = GetDWLE( p_peek + i_skip ); i_skip+= 4; break; \
467         case 0: \
468         default: var = def; break;\
469     }
470
471 static int DemuxPacket( input_thread_t *p_input, vlc_bool_t b_play_audio )
472 {
473     demux_sys_t *p_demux = p_input->p_demux_data;
474     int     i_data_packet_min = p_demux->p_fp->i_min_data_packet_size;
475     uint8_t *p_peek;
476     int     i_skip;
477
478     int     i_packet_size_left;
479     int     i_packet_flags;
480     int     i_packet_property;
481
482     int     b_packet_multiple_payload;
483     int     i_packet_length;
484     int     i_packet_sequence;
485     int     i_packet_padding_length;
486
487     uint32_t    i_packet_send_time;
488     uint16_t    i_packet_duration;
489     int         i_payload;
490     int         i_payload_count;
491     int         i_payload_length_type;
492
493
494     if( input_Peek( p_input, &p_peek, i_data_packet_min ) < i_data_packet_min )
495     {
496         // EOF ?
497         msg_Warn( p_input, "cannot peek while getting new packet, EOF ?" );
498         return( 0 );
499     }
500     i_skip = 0;
501
502     /* *** parse error correction if present *** */
503     if( p_peek[0]&0x80 )
504     {
505         unsigned int i_error_correction_length_type;
506         unsigned int i_error_correction_data_length;
507         unsigned int i_opaque_data_present;
508
509         i_error_correction_data_length = p_peek[0] & 0x0f;  // 4bits
510         i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01;    // 1bit
511         i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03; // 2bits
512         i_skip += 1; // skip error correction flags
513
514         if( i_error_correction_length_type != 0x00 ||
515             i_opaque_data_present != 0 ||
516             i_error_correction_data_length != 0x02 )
517         {
518             goto loop_error_recovery;
519         }
520
521         i_skip += i_error_correction_data_length;
522     }
523     else
524     {
525         msg_Warn( p_input, "p_peek[0]&0x80 != 0x80" );
526     }
527
528     /* sanity check */
529     if( i_skip + 2 >= i_data_packet_min )
530     {
531         goto loop_error_recovery;
532     }
533
534     i_packet_flags = p_peek[i_skip]; i_skip++;
535     i_packet_property = p_peek[i_skip]; i_skip++;
536
537     b_packet_multiple_payload = i_packet_flags&0x01;
538
539     /* read some value */
540     GETVALUE2b( i_packet_flags >> 5, i_packet_length, i_data_packet_min );
541     GETVALUE2b( i_packet_flags >> 1, i_packet_sequence, 0 );
542     GETVALUE2b( i_packet_flags >> 3, i_packet_padding_length, 0 );
543
544     i_packet_send_time = GetDWLE( p_peek + i_skip ); i_skip += 4;
545     i_packet_duration  = GetWLE( p_peek + i_skip ); i_skip += 2;
546
547 //        i_packet_size_left = i_packet_length;   // XXX données reellement lu
548     /* FIXME I have to do that for some file, I don't known why */
549     i_packet_size_left = i_data_packet_min;
550
551     if( b_packet_multiple_payload )
552     {
553         i_payload_count = p_peek[i_skip] & 0x3f;
554         i_payload_length_type = ( p_peek[i_skip] >> 6 )&0x03;
555         i_skip++;
556     }
557     else
558     {
559         i_payload_count = 1;
560         i_payload_length_type = 0x02; // unused
561     }
562
563     for( i_payload = 0; i_payload < i_payload_count ; i_payload++ )
564     {
565         asf_stream_t   *p_stream;
566
567         int i_stream_number;
568         int i_media_object_number;
569         int i_media_object_offset;
570         int i_replicated_data_length;
571         int i_payload_data_length;
572         int i_payload_data_pos;
573         int i_sub_payload_data_length;
574         int i_tmp;
575
576         mtime_t i_pts;
577         mtime_t i_pts_delta;
578
579         if( i_skip >= i_packet_size_left )
580         {
581             /* prevent some segfault with invalid file */
582             break;
583         }
584
585         i_stream_number = p_peek[i_skip] & 0x7f;
586         i_skip++;
587
588         GETVALUE2b( i_packet_property >> 4, i_media_object_number, 0 );
589         GETVALUE2b( i_packet_property >> 2, i_tmp, 0 );
590         GETVALUE2b( i_packet_property, i_replicated_data_length, 0 );
591
592         if( i_replicated_data_length > 1 ) // should be at least 8 bytes
593         {
594             i_pts = (mtime_t)GetDWLE( p_peek + i_skip + 4 ) * 1000;
595             i_skip += i_replicated_data_length;
596             i_pts_delta = 0;
597
598             i_media_object_offset = i_tmp;
599
600             if( i_skip >= i_packet_size_left )
601             {
602                 break;
603             }
604         }
605         else if( i_replicated_data_length == 1 )
606         {
607
608             msg_Dbg( p_input, "found compressed payload" );
609
610             i_pts = (mtime_t)i_tmp * 1000;
611             i_pts_delta = (mtime_t)p_peek[i_skip] * 1000; i_skip++;
612
613             i_media_object_offset = 0;
614         }
615         else
616         {
617             i_pts = (mtime_t)i_packet_send_time * 1000;
618             i_pts_delta = 0;
619
620             i_media_object_offset = i_tmp;
621         }
622
623         i_pts = __MAX( i_pts - p_demux->p_fp->i_preroll * 1000, 0 );
624         if( b_packet_multiple_payload )
625         {
626             GETVALUE2b( i_payload_length_type, i_payload_data_length, 0 );
627         }
628         else
629         {
630             i_payload_data_length = i_packet_length -
631                                         i_packet_padding_length - i_skip;
632         }
633
634         if( i_payload_data_length < 0 || i_skip + i_payload_data_length > i_packet_size_left )
635         {
636             break;
637         }
638
639 #if 0
640          msg_Dbg( p_input,
641                   "payload(%d/%d) stream_number:%d media_object_number:%d media_object_offset:%d replicated_data_length:%d payload_data_length %d",
642                   i_payload + 1,
643                   i_payload_count,
644                   i_stream_number,
645                   i_media_object_number,
646                   i_media_object_offset,
647                   i_replicated_data_length,
648                   i_payload_data_length );
649 #endif
650
651         if( !( p_stream = p_demux->stream[i_stream_number] ) )
652         {
653             msg_Warn( p_input,
654                       "undeclared stream[Id 0x%x]", i_stream_number );
655             i_skip += i_payload_data_length;
656             continue;   // over payload
657         }
658
659         if( !p_stream->p_es || !p_stream->p_es->p_decoder_fifo )
660         {
661             i_skip += i_payload_data_length;
662             continue;
663         }
664
665
666         for( i_payload_data_pos = 0;
667              i_payload_data_pos < i_payload_data_length &&
668                     i_packet_size_left > 0;
669              i_payload_data_pos += i_sub_payload_data_length )
670         {
671             data_packet_t  *p_data;
672             int i_read;
673             // read sub payload length
674             if( i_replicated_data_length == 1 )
675             {
676                 i_sub_payload_data_length = p_peek[i_skip]; i_skip++;
677                 i_payload_data_pos++;
678             }
679             else
680             {
681                 i_sub_payload_data_length = i_payload_data_length;
682             }
683
684             /* FIXME I don't use i_media_object_number, sould I ? */
685             if( p_stream->p_pes && i_media_object_offset == 0 )                 {
686                 /* send complete packet to decoder */
687                 if( p_stream->p_pes->i_pes_size > 0 )
688                 {
689                     if( p_stream->p_es->p_decoder_fifo &&
690                         ( b_play_audio || p_stream->i_cat != AUDIO_ES ) )
691                     {
692                         input_DecodePES( p_stream->p_es->p_decoder_fifo,
693                                          p_stream->p_pes );
694                     }
695                     else
696                     {
697                         input_DeletePES( p_input->p_method_data,
698                                          p_stream->p_pes );
699                     }
700                     p_stream->p_pes = NULL;
701                 }
702             }
703
704             if( !p_stream->p_pes )  // add a new PES
705             {
706                 p_stream->i_time =
707                     ( (mtime_t)i_pts + i_payload * (mtime_t)i_pts_delta );
708
709                 p_stream->p_pes = input_NewPES( p_input->p_method_data );
710                 p_stream->p_pes->i_dts =
711                     p_stream->p_pes->i_pts =
712                         input_ClockGetTS( p_input,
713                                           p_input->stream.p_selected_program,
714                                           p_stream->i_time * 9 /100 );
715
716                 //msg_Err( p_input, "stream[0x%2x] pts=%lld", i_stream_number, p_stream->p_pes->i_pts );
717                 p_stream->p_pes->p_next = NULL;
718                 p_stream->p_pes->i_nb_data = 0;
719                 p_stream->p_pes->i_pes_size = 0;
720             }
721
722             i_read = i_sub_payload_data_length + i_skip;
723             if( input_SplitBuffer( p_input, &p_data, i_read ) < i_read )
724             {
725                 msg_Warn( p_input, "cannot read data" );
726                 return( 0 );
727             }
728             p_data->p_payload_start += i_skip;
729             i_packet_size_left -= i_read;
730
731
732             if( !p_stream->p_pes->p_first )
733             {
734                 p_stream->p_pes->p_first = p_stream->p_pes->p_last = p_data;
735             }
736             else
737             {
738                 p_stream->p_pes->p_last->p_next = p_data;
739                 p_stream->p_pes->p_last = p_data;
740             }
741             p_stream->p_pes->i_pes_size += i_sub_payload_data_length;
742             p_stream->p_pes->i_nb_data++;
743
744             i_skip = 0;
745             if( i_packet_size_left > 0 )
746             {
747                 if( input_Peek( p_input, &p_peek, i_packet_size_left ) < i_packet_size_left )
748                 {
749                     // EOF ?
750                     msg_Warn( p_input, "cannot peek, EOF ?" );
751                     return( 0 );
752                 }
753             }
754         }
755     }
756
757     if( i_packet_size_left > 0 )
758     {
759         if( !ASF_SkipBytes( p_input, i_packet_size_left ) )
760         {
761             msg_Warn( p_input, "cannot skip data, EOF ?" );
762             return( 0 );
763         }
764     }
765
766     return( 1 );
767
768 loop_error_recovery:
769     msg_Warn( p_input, "unsupported packet header" );
770     if( p_demux->p_fp->i_min_data_packet_size != p_demux->p_fp->i_max_data_packet_size )
771     {
772         msg_Err( p_input, "unsupported packet header, fatal error" );
773         return( -1 );
774     }
775     ASF_SkipBytes( p_input, i_data_packet_min );
776
777     return( 1 );
778 }
779
780 static int Demux( input_thread_t *p_input )
781 {
782     demux_sys_t *p_demux = p_input->p_demux_data;
783     vlc_bool_t b_play_audio;
784     int i;
785     vlc_bool_t b_stream;
786
787     b_stream = VLC_FALSE;
788     for( i = 0; i < 128; i++ )
789     {
790         if( p_demux->stream[i] &&
791             p_demux->stream[i]->p_es &&
792             p_demux->stream[i]->p_es->p_decoder_fifo )
793         {
794             b_stream = VLC_TRUE;
795         }
796     }
797     if( !b_stream )
798     {
799         msg_Warn( p_input, "no stream selected, exiting..." );
800         return( 0 );
801     }
802
803     /* catch seek from user */
804     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
805     {
806         off_t i_offset;
807
808         msleep( p_input->i_pts_delay );
809         i_offset = ASF_TellAbsolute( p_input ) - p_demux->i_data_begin;
810
811         if( i_offset  < 0 )
812         {
813             i_offset = 0;
814         }
815         /* XXX work only when i_min_data_packet_size == i_max_data_packet_size */
816         i_offset += p_demux->p_fp->i_min_data_packet_size -
817                         i_offset % p_demux->p_fp->i_min_data_packet_size;
818         ASF_SeekAbsolute( p_input, p_demux->i_data_begin + i_offset );
819
820         p_demux->i_time = -1;
821         for( i = 0; i < 128 ; i++ )
822         {
823 #define p_stream p_demux->stream[i]
824             if( p_stream )
825             {
826                 p_stream->i_time = -1;
827             }
828 #undef p_stream
829         }
830     }
831
832     vlc_mutex_lock( &p_input->stream.stream_lock );
833     if( p_input->stream.control.i_rate == DEFAULT_RATE )
834     {
835         b_play_audio = VLC_TRUE;
836     }
837     else
838     {
839         int i;
840
841         b_play_audio = VLC_TRUE;
842         for( i = 0; i < 128; i++ )
843         {
844             if( p_demux->stream[i] &&
845                 p_demux->stream[i]->i_cat == VIDEO_ES &&
846                 p_demux->stream[i]->p_es &&
847                 p_demux->stream[i]->p_es->p_decoder_fifo )
848             {
849                 /* there is at least ine video track so no need to play audio */
850                 b_play_audio = VLC_FALSE;
851             }
852         }
853     }
854     vlc_mutex_unlock( &p_input->stream.stream_lock );
855
856     for( ;; )
857     {
858         mtime_t i_length;
859         mtime_t i_time_begin = GetMoviePTS( p_demux );
860         int i_result;
861
862         if( p_input->b_die )
863         {
864             break;
865         }
866
867         if( ( i_result = DemuxPacket( p_input, b_play_audio ) ) <= 0 )
868         {
869             return i_result;
870         }
871         if( i_time_begin == -1 )
872         {
873             i_time_begin = GetMoviePTS( p_demux );
874         }
875         else
876         {
877             i_length = GetMoviePTS( p_demux ) - i_time_begin;
878             if( i_length < 0 || i_length >= 40 * 1000 )
879             {
880                 break;
881             }
882         }
883     }
884
885     p_demux->i_time = GetMoviePTS( p_demux );
886     if( p_demux->i_time >= 0 )
887     {
888         /* update pcr XXX in mpeg scale so in 90000 unit/s */
889         p_demux->i_pcr = p_demux->i_time * 9 / 100;
890
891         /* first wait for the good time to read next packets */
892         input_ClockManageRef( p_input,
893                               p_input->stream.p_selected_program,
894                               p_demux->i_pcr );
895     }
896
897     return( 1 );
898 }
899
900 /*****************************************************************************
901  * MP4End: frees unused data
902  *****************************************************************************/
903 static void Deactivate( vlc_object_t * p_this )
904 {
905 #define FREE( p ) \
906     if( p ) { free( p ); }
907
908     input_thread_t *  p_input = (input_thread_t *)p_this;
909     demux_sys_t *p_demux = p_input->p_demux_data;
910     int i_stream;
911
912     msg_Dbg( p_input, "Freeing all memory" );
913     ASF_FreeObjectRoot( p_input, &p_demux->root );
914     for( i_stream = 0; i_stream < 128; i_stream++ )
915     {
916 #define p_stream p_demux->stream[i_stream]
917         if( p_stream )
918         {
919             if( p_stream->p_pes )
920             {
921                 input_DeletePES( p_input->p_method_data, p_stream->p_pes );
922             }
923             free( p_stream );
924         }
925 #undef p_stream
926     }
927     FREE( p_input->p_demux_data );
928 #undef FREE
929 }
930