]> git.sesse.net Git - vlc/blob - plugins/mp4/mp4.c
* all : preliminary mp4 (and some mov) demux plugin. I've not enabled
[vlc] / plugins / mp4 / mp4.c
1 /*****************************************************************************
2  * mp4.c : MP4 file input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: mp4.c,v 1.1 2002/07/17 21:37:27 fenrir 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 "libmp4.h"
35 #include "mp4.h"
36
37 /*****************************************************************************
38  * Local prototypes
39  *****************************************************************************/
40 static void input_getfunctions( function_list_t * );
41 static int  MP4Demux         ( input_thread_t * );
42 static int  MP4Init          ( input_thread_t * );
43 static void MP4End           ( input_thread_t * );
44
45 /*****************************************************************************
46  * Build configuration tree.
47  *****************************************************************************/
48 MODULE_CONFIG_START
49 MODULE_CONFIG_STOP
50
51 MODULE_INIT_START
52     SET_DESCRIPTION( "MP4 file input" )
53     ADD_CAPABILITY( DEMUX, 242 )
54 MODULE_INIT_STOP
55
56 MODULE_ACTIVATE_START
57     input_getfunctions( &p_module->p_functions->demux );
58 MODULE_ACTIVATE_STOP
59
60 MODULE_DEACTIVATE_START
61 MODULE_DEACTIVATE_STOP
62
63 /*****************************************************************************
64  * Functions exported as capabilities. They are declared as static so that
65  * we don't pollute the namespace too much.
66  *****************************************************************************/
67 static void input_getfunctions( function_list_t * p_function_list )
68 {
69 #define input p_function_list->functions.demux
70     input.pf_init             = MP4Init;
71     input.pf_end              = MP4End;
72     input.pf_demux            = MP4Demux;
73     input.pf_rewind           = NULL;
74 #undef input
75 }
76
77 /*****************************************************************************
78  * Declaration of local function 
79  *****************************************************************************/
80 static void MP4_ParseTrack();
81
82 static int MP4_CreateChunksIndex();
83 static int MP4_CreateSamplesIndex();
84
85 static void MP4_StartDecoder();
86 static void MP4_StopDecoder();
87
88 static int  MP4_ReadSample();
89 static int  MP4_DecodeSample();
90
91 #define MP4_Set4BytesLE( p, dw ) \
92     *((u8*)p) = ( dw&0xff ); \
93     *((u8*)p+1) = ( ((dw)>> 8)&0xff ); \
94     *((u8*)p+2) = ( ((dw)>>16)&0xff ); \
95     *((u8*)p+3) = ( ((dw)>>24)&0xff )
96
97 #define MP4_Set2BytesLE( p, dw ) \
98     *((u8*)p) = ( (dw)&0xff ); \
99     *((u8*)p+1) = ( ((dw)>> 8)&0xff )
100
101     
102 /*****************************************************************************
103  * MP4Init: check file and initializes MP4 structures
104  *****************************************************************************/
105 static int MP4Init( input_thread_t *p_input )
106 {
107     u8  *p_peek;
108     u32 i_type;
109     
110     demux_data_mp4_t *p_demux;
111     
112     MP4_Box_t *p_moov;    
113     MP4_Box_t *p_ftyp;
114
115
116     MP4_Box_t *p_mvhd;
117     MP4_Box_t *p_trak;
118
119     int i;
120     /* I need to seek */
121     if( !p_input->stream.b_seekable )
122     {
123         msg_Warn( p_input, "MP4 plugin discarded (unseekable)" );
124         return( -1 );
125             
126     } 
127     /* Initialize access plug-in structures. */
128     if( p_input->i_mtu == 0 )
129     {
130         /* Improve speed. */
131         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
132     }
133
134     /* a little test to see if it could be a mp4 */
135     if( input_Peek( p_input, &p_peek, 8 ) < 8 )
136     {
137         msg_Warn( p_input, "MP4 plugin discarded (cannot peek)" );
138         return( -1 );
139     }
140     i_type = ( p_peek[4] << 24 ) + ( p_peek[5] << 16 ) +
141                 ( p_peek[6] << 8 ) + ( p_peek[7] );
142     switch( i_type )
143     {
144         case( FOURCC_ftyp ):
145         case( FOURCC_moov ):
146         case( FOURCC_moof ):
147         case( FOURCC_mdat ):
148         case( FOURCC_udta ): /* should never match but ... */
149         case( FOURCC_free ):
150         case( FOURCC_skip ):
151         case( FOURCC_wide ): /* not mp4 compliant but ... */
152             break;
153          default:
154             msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
155             return( -1 );
156     }
157
158     /* create our structure that will contains all data */
159     if( !( p_input->p_demux_data = 
160                 p_demux = malloc( sizeof( demux_data_mp4_t ) ) ) )
161     {
162         msg_Err( p_input, "out of memory" );
163         return( -1 );
164     }
165     memset( p_demux, 0, sizeof( demux_data_mp4_t ) );
166     p_input->p_demux_data = p_demux;
167        
168
169     /* Now load all boxes ( except raw data ) */
170     if( !MP4_ReadBoxRoot( p_input, &p_demux->box_root ) )
171     {
172         msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
173         return( -1 );
174     }
175
176     MP4_DumpBoxStructure( p_input, &p_demux->box_root );
177
178     if( ( p_ftyp = MP4_FindBox( &p_demux->box_root, FOURCC_ftyp ) ) )
179     {
180         switch( p_ftyp->data.p_ftyp->i_major_brand )
181         {
182             case( FOURCC_isom ):
183                 msg_Info( p_input, 
184                           "ISO Media file (isom) version %d.",
185                           p_ftyp->data.p_ftyp->i_minor_version );
186                 break;
187             default:
188                 msg_Info( p_input,
189                           "Unrecognize major file specification." );
190                 break;
191         }
192     }
193     else
194     {
195         msg_Info( p_input, "File Type box missing(assume ISO Media file)" );
196     }
197
198     /* the file need to have one moov box */
199     if( !( p_moov = MP4_FindBox( &p_demux->box_root, FOURCC_moov ) ) )
200     {
201         msg_Warn( p_input, "MP4 plugin discarded (missing moov box)" );
202         MP4End( p_input );
203         return( -1 );
204     }
205
206     if( MP4_CountBox( &p_demux->box_root, FOURCC_moov ) != 1 )
207     {
208         msg_Warn( p_input, "more than one \"moov\" box (continuying anyway)" );
209     }
210
211     if( !(p_mvhd = MP4_FindBox( p_moov, FOURCC_mvhd ) ) )
212     {
213         msg_Err( p_input, "cannot find \"mvhd\" box" );
214         MP4End( p_input );
215         return( -1 );
216     }
217     else
218     {
219         p_demux->i_timescale = p_mvhd->data.p_mvhd->i_timescale;
220     }
221     
222     p_demux->i_tracks = MP4_CountBox( p_moov, FOURCC_trak );
223     msg_Dbg( p_input, "find %d track%c",
224                         p_demux->i_tracks,
225                         p_demux->i_tracks ? 's':' ' );
226
227     if( !( p_trak = MP4_FindBox( p_moov, FOURCC_trak ) ) )
228     {
229         msg_Err( p_input, "cannot find /moov/trak !" );
230         MP4End( p_input );
231         return( -1 );
232     }
233
234     /* allocate memory */
235     p_demux->track = calloc( p_demux->i_tracks, sizeof( track_data_mp4_t ) );
236
237     /* now process each track and extract all usefull informations */
238     for( i = 0; i < p_demux->i_tracks; i++ )
239     {
240         MP4_ParseTrack( p_input, &p_demux->track[i], p_trak );
241
242         if( p_demux->track[i].b_ok )
243         {
244             char *psz_cat;
245             switch( p_demux->track[i].i_cat )
246             {
247                 case( VIDEO_ES ):
248                     psz_cat = "video";
249                     break;
250                 case( AUDIO_ES ):
251                     psz_cat = "audio";
252                     break;
253                 default:
254                     psz_cat = "";
255                     break;
256             }
257             
258             msg_Dbg( p_input, "adding track(%d) %s (%s) language %c%c%c",
259                             i,
260                             psz_cat,
261                             p_demux->track[i].b_enable ? "enable":"disable",
262                             p_demux->track[i].i_language[0],
263                             p_demux->track[i].i_language[1], 
264                             p_demux->track[i].i_language[2] );
265         }
266         else
267         {
268             msg_Dbg( p_input, "ignoring track(%d)", i );
269         }
270
271         p_trak = MP4_FindNextBox( p_trak );
272     }
273   
274     /*  create one program */
275     vlc_mutex_lock( &p_input->stream.stream_lock );
276     if( input_InitStream( p_input, 0 ) == -1)
277     {
278         vlc_mutex_unlock( &p_input->stream.stream_lock );
279         msg_Err( p_input, "cannot init stream" );
280         MP4End( p_input );
281         return( -1 );
282     }
283     if( input_AddProgram( p_input, 0, 0) == NULL )
284     {
285         vlc_mutex_unlock( &p_input->stream.stream_lock );
286         msg_Err( p_input, "cannot add program" );
287         MP4End( p_input );
288         return( -1 );
289     }
290     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
291     p_input->stream.i_mux_rate = 0 ; /* FIXME */
292     vlc_mutex_unlock( &p_input->stream.stream_lock );
293    
294     
295     for( i = 0; i < p_demux->i_tracks; i++ )
296     {
297         /* start decoder for this track if enable by default*/
298         if( p_demux->track[i].b_enable )
299         {
300             MP4_StartDecoder( p_input, &p_demux->track[i] );
301         }
302     }
303
304     vlc_mutex_lock( &p_input->stream.stream_lock );
305     p_input->stream.p_selected_program->b_is_ok = 1;
306     vlc_mutex_unlock( &p_input->stream.stream_lock );
307         
308     return( 0 );    
309
310 }
311
312 /*****************************************************************************
313  * MP4Demux: read packet and send them to decoders 
314  *****************************************************************************/
315 static int MP4Demux( input_thread_t *p_input )
316 {
317     demux_data_mp4_t *p_demux = p_input->p_demux_data;
318     int i_track;
319
320     /* first wait for the good time to read a packet */
321
322     input_ClockManageRef( p_input,
323                           p_input->stream.p_selected_program,
324                           p_demux->i_pcr );
325
326
327     /* update pcr XXX in mpeg scale so in 90000 unit/s */
328     p_demux->i_pcr = MP4_GetMoviePTS( p_demux ) * 9 / 100;
329     
330
331     /* we will read 100ms for each stream so ...*/
332     p_demux->i_time += __MAX( p_demux->i_timescale / 10 , 1 );
333     
334
335     for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
336     {
337         if( ( !p_demux->track[i_track].b_ok )||
338             ( !p_demux->track[i_track].p_es )||
339             ( !p_demux->track[i_track].p_es->p_decoder_fifo )||
340             ( MP4_GetTrackPTS( &p_demux->track[i_track] ) >=
341                         MP4_GetMoviePTS( p_demux ) ) )
342         {
343             continue; /* no need to read something */
344         }
345
346         while( MP4_GetTrackPTS( &p_demux->track[i_track] ) <
347                         MP4_GetMoviePTS( p_demux ) )
348         {
349
350             pes_packet_t *p_pes;
351
352             /* read a sample */
353             if( !MP4_ReadSample( p_input ,
354                                  &p_demux->track[i_track],
355                                  &p_pes ) )
356             {
357                 break;
358             }
359
360             /* send it to decoder and update time of this track 
361                  it also launch a new decoder if needed */
362             MP4_DecodeSample( p_input ,
363                               &p_demux->track[i_track],
364                               p_pes );
365         }
366
367     }
368     
369     /* now check if all tracks are finished or unhandled*/
370     
371     for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
372     {
373         if( ( p_demux->track[i_track].b_ok )&&
374             ( p_demux->track[i_track].i_sample < p_demux->track[i_track].i_sample_count )&&
375             ( p_demux->track[i_track].p_es )&&
376             ( p_demux->track[i_track].p_es->p_decoder_fifo ) )
377         {
378             return( 1 );
379         }
380     }
381
382     return( 0 ); /* EOF */
383 }
384
385 /*****************************************************************************
386  * MP4End: frees unused data
387  *****************************************************************************/
388 static void MP4End( input_thread_t *p_input )
389 {   
390 #define FREE( p ) \
391     if( p ) { free( p ); } 
392     int i_track;
393     demux_data_mp4_t *p_demux = p_input->p_demux_data;
394     
395     msg_Dbg( p_input, "Freeing all memory" );
396     MP4_FreeBox( p_input, &p_demux->box_root );
397     for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
398     {
399         int i_chunk;
400         for( i_chunk = 0; 
401                 i_chunk < p_demux->track[i_track].i_chunk_count; i_chunk++ )
402         {
403             if( p_demux->track[i_track].chunk )
404             {
405                FREE(p_demux->track[i_track].chunk[i_chunk].p_sample_count_dts);
406                FREE(p_demux->track[i_track].chunk[i_chunk].p_sample_delta_dts );
407             }
408         }
409         if( p_demux->track->p_data_init )
410         {
411             input_DeletePacket( p_input->p_method_data, 
412                                 p_demux->track->p_data_init );
413         }
414         if( !p_demux->track[i_track].i_sample_size )
415         {
416             FREE( p_demux->track[i_track].p_sample_size );
417         }
418     }
419     FREE( p_demux->track );
420 #undef FREE
421 }
422
423
424 /****************************************************************************
425  * Local functions, specific to vlc
426  ****************************************************************************/
427
428 /****************************************************************************
429  * Parse track information and create all needed data to run a track
430  * If it succeed b_ok is set to 1 else to 0
431  ****************************************************************************/
432 static void MP4_ParseTrack( input_thread_t *p_input,
433                      track_data_mp4_t *p_demux_track,
434                      MP4_Box_t  * p_trak )
435 {
436     int i;
437
438     MP4_Box_t *p_tkhd = MP4_FindBox( p_trak, FOURCC_tkhd );
439     MP4_Box_t *p_tref = MP4_FindBox( p_trak, FOURCC_tref );
440     MP4_Box_t *p_edts = MP4_FindBox( p_trak, FOURCC_edts );
441     MP4_Box_t *p_mdia = MP4_FindBox( p_trak, FOURCC_mdia );
442
443     MP4_Box_t *p_mdhd;
444     MP4_Box_t *p_hdlr;
445     MP4_Box_t *p_minf;
446
447     MP4_Box_t *p_vmhd;
448     MP4_Box_t *p_smhd; 
449
450     /* hint track unsuported */
451
452     /* by default, track isn't usable */
453     p_demux_track->b_ok = 0;
454
455     /* by default, we don't known the categorie */
456     p_demux_track->i_cat = UNKNOWN_ES;
457     
458     if( ( !p_tkhd )||( !p_mdia ) )
459     {
460         return;
461     }
462
463     /* do we launch this track by default ? */
464     p_demux_track->b_enable = ( ( p_tkhd->data.p_tkhd->i_flags&MP4_TRACK_ENABLED ) != 0 );
465
466     p_demux_track->i_track_ID = p_tkhd->data.p_tkhd->i_track_ID;
467     p_demux_track->i_width = p_tkhd->data.p_tkhd->i_width / 65536;
468     p_demux_track->i_height = p_tkhd->data.p_tkhd->i_height / 65536;
469     
470     if( !p_edts )
471     {
472 //        msg_Warn( p_input, "Unhandled box: edts --> FIXME" );
473     }
474
475     if( !p_tref )
476     {
477 //        msg_Warn( p_input, "Unhandled box: tref --> FIXME" );
478     } 
479
480     p_mdhd = MP4_FindBox( p_mdia, FOURCC_mdhd );
481     p_hdlr = MP4_FindBox( p_mdia, FOURCC_hdlr );
482     p_minf = MP4_FindBox( p_mdia, FOURCC_minf );
483     
484     if( ( !p_mdhd )||( !p_hdlr )||( !p_minf ) )
485     {
486         return;
487     }
488
489     p_demux_track->i_timescale = p_mdhd->data.p_mdhd->i_timescale;
490
491     for( i = 0; i < 3; i++ ) 
492     {
493         p_demux_track->i_language[i] = p_mdhd->data.p_mdhd->i_language[i];
494     }
495     
496     switch( p_hdlr->data.p_hdlr->i_handler_type )
497     {
498         case( FOURCC_soun ):
499             if( !( p_smhd = MP4_FindBox( p_minf, FOURCC_smhd ) ) )
500             {
501                 return;
502             }
503             p_demux_track->i_cat = AUDIO_ES;
504             break;
505
506         case( FOURCC_vide ):
507             if( !( p_vmhd = MP4_FindBox( p_minf, FOURCC_vmhd ) ) )
508             {
509                 return;
510             }
511             p_demux_track->i_cat = VIDEO_ES;
512             break;
513             
514         default:
515             return;
516     }
517 /*  FIXME
518     add support to:
519     p_dinf = MP4_FindBox( p_minf, FOURCC_dinf );
520 */
521     if( !( p_demux_track->p_stbl = MP4_FindBox( p_minf, FOURCC_stbl ) ) )
522     {
523         return;
524     }
525     
526     if( !( p_demux_track->p_stsd = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stsd ) ) )
527     {
528         return;
529     }
530     
531     /* Create chunk  index table */
532     if( !MP4_CreateChunksIndex( p_input,p_demux_track  ) )
533     {
534         return; /* cannot create chunks index */
535     }
536     
537     /* create sample index table needed for reading and seeking */
538     if( !MP4_CreateSamplesIndex( p_input, p_demux_track ) )
539     {
540         return; /* cannot create samples index */
541     }
542      
543     p_demux_track->b_ok = 1;        
544 }
545                      
546
547
548 /* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */
549 static int MP4_CreateChunksIndex( input_thread_t *p_input,
550                                    track_data_mp4_t *p_demux_track )
551 {
552     MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */
553     MP4_Box_t *p_stsc;
554
555     int i_chunk;
556     int i_index, i_last;
557    
558
559     if( ( !(p_co64 = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stco ) )&&
560                  !(p_co64 = MP4_FindBox( p_demux_track->p_stbl, FOURCC_co64 ) ) )|| 
561         ( !(p_stsc = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stsc ) ) ))
562     {
563         return( 0 );
564     }
565      
566     p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count;
567     if( !p_demux_track->i_chunk_count )
568     {
569         msg_Warn( p_input, "No chunk defined" );
570         return( 0 );
571     }
572     p_demux_track->chunk = calloc( p_demux_track->i_chunk_count, 
573                                    sizeof( chunk_data_mp4_t ) );
574
575     /* first we read chunk offset */
576     for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
577     {
578         p_demux_track->chunk[i_chunk].i_offset = 
579                 p_co64->data.p_co64->i_chunk_offset[i_chunk];
580     }
581
582     /* now we read index for SampleEntry( soun vide mp4a mp4v ...) 
583         to be used for the sample XXX begin to 1 
584         We construct it begining at the end */
585     i_last = p_demux_track->i_chunk_count; /* last chunk proceded */
586     i_index = p_stsc->data.p_stsc->i_entry_count;
587     if( !i_index )
588     {
589         msg_Warn( p_input, "cannot read chunk table or table empty" );
590         return( 0 );
591     }
592
593     while( i_index )
594     {
595         i_index--;
596         for( i_chunk = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;
597                 i_chunk < i_last; i_chunk++ )
598         {
599             p_demux_track->chunk[i_chunk].i_sample_description_index = 
600                     p_stsc->data.p_stsc->i_sample_description_index[i_index];
601             p_demux_track->chunk[i_chunk].i_sample_count =
602                     p_stsc->data.p_stsc->i_samples_per_chunk[i_index];
603         }
604         i_last = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;
605     }
606
607     p_demux_track->chunk[i_chunk].i_sample_first = 0;
608     for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
609     {
610         p_demux_track->chunk[i_chunk].i_sample_first =
611             p_demux_track->chunk[i_chunk-1].i_sample_first + 
612                 p_demux_track->chunk[i_chunk-1].i_sample_count;
613         
614     }
615     
616     msg_Dbg( p_input, "read %d chunk", p_demux_track->i_chunk_count );
617     return( 1 );
618
619 }
620
621
622
623 static int MP4_CreateSamplesIndex( input_thread_t *p_input,
624                                    track_data_mp4_t *p_demux_track )
625 {
626     MP4_Box_t *p_stts; /* makes mapping between sample and decoding time,
627                           ctts make same mapping but for composition time, 
628                           not yet used and probably not usefull */
629     MP4_Box_t *p_stsz; /* gives sample size of each samples, there is also stz2 
630                           that uses a compressed form FIXME make them in libmp4 
631                           as a unique type */
632     /* TODO use also stss and stsh table for seeking */
633     /* FIXME use edit table */
634     int i_sample;
635     int i_chunk;
636
637     int i_index;
638     int i_index_sample_used;
639
640     u64 i_last_dts; 
641     
642     p_stts = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stts );
643     p_stsz = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stsz ); /* FIXME and stz2 */
644
645     
646     if( ( !p_stts )||( !p_stsz ) )
647     {
648         msg_Warn( p_input, "cannot read sample table" );
649         return( 0 ); 
650     }
651         
652     p_demux_track->i_sample_count = p_stsz->data.p_stsz->i_sample_count;
653
654
655     /* for sample size, there are 2 case */
656     if( p_stsz->data.p_stsz->i_sample_size )
657     {
658         /* 1: all sample have the same size, so no need to construct a table */
659         p_demux_track->i_sample_size = p_stsz->data.p_stsz->i_sample_size;
660         p_demux_track->p_sample_size = NULL;
661     }
662     else
663     {
664         /* 2: each sample can have a different size */
665         p_demux_track->i_sample_size = 0;
666         p_demux_track->p_sample_size = 
667             calloc( p_demux_track->i_sample_count, sizeof( u32 ) );
668         
669         for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
670         {
671             p_demux_track->p_sample_size[i_sample] = 
672                     p_stsz->data.p_stsz->i_entry_size[i_sample];
673         }
674     }
675     /* we have extract all information from stsz,
676         now use stts */
677
678     /* if we don't want to waste too much memory, we can't expand
679        the box !, so each chunk will contain an "extract" of this table 
680        for fast research */
681         
682     i_last_dts = 0;
683     i_index = 0; i_index_sample_used =0;
684     /* create and init last data for each chunk */
685     for(i_chunk = 0 ; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
686     {
687
688         int i_entry, i_sample_count, i;
689         /* save last dts */
690         p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts;
691     /* count how many entries needed for this chunk 
692        for p_sample_delta_dts and p_sample_count_dts */
693
694         i_entry = 0;
695         i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
696         while( i_sample_count > 0 )
697         {
698             i_sample_count -= p_stts->data.p_stts->i_sample_count[i_index+i_entry];
699             if( i_entry == 0 )
700             {
701                 i_sample_count += i_index_sample_used; /* don't count already used sample 
702                                                    int this entry */
703             }
704             i_entry++;
705         }
706         /* allocate them */
707         p_demux_track->chunk[i_chunk].p_sample_count_dts = 
708             calloc( i_entry, sizeof( u32 ) );
709         p_demux_track->chunk[i_chunk].p_sample_delta_dts =
710             calloc( i_entry, sizeof( u32 ) );
711
712         /* now copy */
713         i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
714         for( i = 0; i < i_entry; i++ )
715         {
716             int i_used;
717             int i_rest;
718             
719             i_rest = p_stts->data.p_stts->i_sample_count[i_index] - i_index_sample_used;
720
721             i_used = __MIN( i_rest, i_sample_count );
722
723             i_index_sample_used += i_used;
724
725             p_demux_track->chunk[i_chunk].p_sample_count_dts[i] = i_used;
726
727             p_demux_track->chunk[i_chunk].p_sample_delta_dts[i] =
728                         p_stts->data.p_stts->i_sample_delta[i_index];
729             
730             i_last_dts += i_used * 
731                     p_demux_track->chunk[i_chunk].p_sample_delta_dts[i];
732
733             if( i_index_sample_used >=
734                              p_stts->data.p_stts->i_sample_count[i_index] )
735             {
736                 i_index++;
737                 i_index_sample_used = 0;
738             }
739         }
740         
741     }
742
743     msg_Dbg( p_input, "read %d samples", p_demux_track->i_sample_count );
744
745     return( 1 );
746 }
747
748 static void MP4_StartDecoder( input_thread_t *p_input,
749                                  track_data_mp4_t *p_demux_track )
750 {
751     MP4_Box_t *p_sample;
752     int i;
753     int i_chunk;
754     u8  *p_bmih;
755  
756     int i_codec;
757     char *psz_name;
758     
759     MP4_Box_t *p_esds;
760
761     
762     if( (!p_demux_track->b_ok )||( p_demux_track->i_cat == UNKNOWN_ES ) )
763     {
764         return;
765     }
766     
767     msg_Dbg( p_input, "Starting decoder (track ID 0x%x)",
768                       p_demux_track->i_track_ID );
769
770     /* launch decoder according in chunk we are */
771     i_chunk = p_demux_track->i_chunk;
772
773     if( !p_demux_track->chunk[i_chunk].i_sample_description_index )
774     {
775         msg_Warn( p_input, "invalid SampleEntry index for this track i_cat %d" );
776         return;
777     } 
778     
779     p_sample = MP4_FindNbBox( p_demux_track->p_stsd,
780                               p_demux_track->chunk[i_chunk].i_sample_description_index - 1);
781
782     if( !p_sample )
783     {
784         msg_Warn( p_input, "cannot find SampleEntry for this track" );
785         return;
786     }
787
788     
789     vlc_mutex_lock( &p_input->stream.stream_lock );
790     p_demux_track->p_es = input_AddES( p_input,
791                                        p_input->stream.p_selected_program, 
792                                        p_demux_track->i_track_ID,
793                                        0 );
794     vlc_mutex_unlock( &p_input->stream.stream_lock );
795     /* Initialise ES, first language as description */
796     for( i = 0; i < 3; i++ )
797     {
798         p_demux_track->p_es->psz_desc[i] = p_demux_track->i_language[i];
799     }
800     p_demux_track->p_es->psz_desc[4] = 0;
801     
802     p_demux_track->p_es->i_stream_id = p_demux_track->i_track_ID;
803
804     p_demux_track->p_es->i_type = UNKNOWN_ES;
805     p_demux_track->p_es->i_cat = p_demux_track->i_cat;
806
807     /* search for the codec */
808     if( !MP4_GetCodec( p_sample->i_type, &i_codec, &psz_name ) )
809     {
810         msg_Warn( p_input, "%s (%c%c%c%c) unsupported", 
811                   psz_name,
812                   (p_sample->i_type >> 24)&0xff,
813                   (p_sample->i_type >> 16)&0xff,
814                   (p_sample->i_type >> 8)&0xff,
815                   (p_sample->i_type )&0xff);
816         p_demux_track->b_ok = 0;
817         return;
818     }
819     else
820     {
821         p_demux_track->p_es->i_type = i_codec;
822         msg_Info( p_input, "%s supported", psz_name );
823     }
824
825     switch( p_demux_track->i_cat )
826     {
827         case( VIDEO_ES ):    
828             p_demux_track->p_es->b_audio = 0;
829
830             /* now create a bitmapinfoheader_t for decoder */
831             p_bmih = malloc( 40 );
832             memset( p_bmih, 0, 40);
833             MP4_Set4BytesLE( p_bmih, 40 );
834             if( p_sample->data.p_sample_mp4v->i_width )
835             {
836                 MP4_Set4BytesLE( p_bmih + 4, p_sample->data.p_sample_mp4v->i_width );
837             }
838             else
839             {
840                 /* use display size */
841                 MP4_Set4BytesLE( p_bmih + 4, p_demux_track->i_width );
842             }
843             if( p_sample->data.p_sample_mp4v->i_height )
844             {
845                 MP4_Set4BytesLE( p_bmih + 8, p_sample->data.p_sample_mp4v->i_height );
846             }
847             else
848             {
849                 MP4_Set4BytesLE( p_bmih + 8, p_demux_track->i_height );
850             }
851
852             p_demux_track->p_es->p_demux_data = p_bmih;
853             break;
854         case( AUDIO_ES ):
855             p_demux_track->p_es->b_audio = 1;
856             break;
857         default:
858             break;
859     }
860
861     vlc_mutex_lock( &p_input->stream.stream_lock );
862     input_SelectES( p_input, p_demux_track->p_es );
863     vlc_mutex_unlock( &p_input->stream.stream_lock );
864     
865
866     p_demux_track->b_ok = 1;
867
868     /* now see if esds is present and i so create a data packet 
869         with decoder_specific_info  */
870     if( ( p_esds = MP4_FindBox( p_sample, FOURCC_esds ) )&&
871         ( p_esds->data.p_esds->es_descriptor.p_decConfigDescr )&&
872         ( p_esds->data.p_esds->es_descriptor.p_decConfigDescr->i_decoder_specific_info_len ) )
873     {
874         data_packet_t *p_data;
875         int i_size = p_esds->data.p_esds->es_descriptor.p_decConfigDescr->i_decoder_specific_info_len;
876
877         /* data packet for the data */
878         if( !(p_data = input_NewPacket( p_input->p_method_data, i_size ) ) )
879         {
880             return;
881         }
882
883         /* initialisation of all the field */
884         memcpy( p_data->p_payload_start,
885                 p_esds->data.p_esds->es_descriptor.p_decConfigDescr->p_decoder_specific_info,
886                 i_size ); 
887         p_demux_track->p_data_init = p_data;
888     }
889                            
890     
891     return;
892 }
893
894
895 static void MP4_StopDecoder( input_thread_t *p_input,
896                              track_data_mp4_t *p_demux_track )
897 {
898     msg_Dbg( p_input, "Stopping decoder (track ID 0x%x)",
899                       p_demux_track->i_track_ID );
900
901     input_UnselectES( p_input, p_demux_track->p_es );
902     p_demux_track->p_es = NULL;
903     if( p_demux_track->p_data_init )
904     {
905         input_DeletePacket( p_input->p_method_data, 
906                             p_demux_track->p_data_init );
907         p_demux_track->p_data_init = NULL;
908     }
909     
910 }
911
912 static int  MP4_ReadSample( input_thread_t *p_input,
913                             track_data_mp4_t *p_demux_track,
914                             pes_packet_t **pp_pes )
915 {
916     int i_size;
917     off_t i_pos;
918
919     data_packet_t *p_data;
920
921
922     /* this track have already reach the end */
923     if( p_demux_track->i_sample >= p_demux_track->i_sample_count )
924     {
925         *pp_pes = NULL;
926         return( 0 );
927     }
928     /* caculate size and position for this sample */
929     i_size = p_demux_track->i_sample_size ? 
930         p_demux_track->i_sample_size : p_demux_track->p_sample_size[p_demux_track->i_sample];
931     /* TODO */
932     i_pos  = MP4_GetTrackPos( p_demux_track );
933
934     /* go,go go ! */
935     if( ! MP4_SeekAbsolute( p_input, i_pos ) )
936     {
937         return( 0 );
938     }
939
940     /* now create a pes */
941     if( !(*pp_pes = input_NewPES( p_input->p_method_data ) ) )
942     {
943         return( 0 );
944     }
945     /* and a data packet for the data */
946     if( !(p_data = input_NewPacket( p_input->p_method_data, i_size ) ) )
947     {
948         input_DeletePES( p_input->p_method_data, *pp_pes );
949         *pp_pes = NULL;
950         return( 0 );
951     }
952     
953     /* initialisation of all the field */
954     (*pp_pes)->i_dts =
955         (*pp_pes)->i_pts = MP4_GetTrackPTS( p_demux_track );
956     (*pp_pes)->p_first = (*pp_pes)->p_last  = p_data;
957     (*pp_pes)->i_nb_data = 1;
958     (*pp_pes)->i_pes_size = i_size;
959
960     if( !i_size )    
961     {
962         return( 1 );
963     }
964     
965 //    msg_Dbg( p_input, "will read %d bytes", i_size );
966     if( !MP4_ReadData( p_input, p_data->p_payload_start, i_size ) )
967     {
968         input_DeletePES( p_input->p_method_data, *pp_pes );
969         input_DeletePacket( p_input->p_method_data, p_data );
970         return( 0 );
971     }
972
973         return( 1 );
974 }
975
976
977 static int  MP4_DecodeSample( input_thread_t *p_input,
978                               track_data_mp4_t *p_demux_track,
979                               pes_packet_t *p_pes )
980 {
981
982     if( !p_pes )
983     {
984         return( 0 );
985     }
986
987     /* don't forget to convert in mpeg clock */
988     /* FIXME correct ffmpeg to use dts instead of pts that it incorrect 
989        and, set it here ( and correct avi demux ) */
990     p_pes->i_dts =
991         p_pes->i_pts = input_ClockGetTS( p_input,
992                                          p_input->stream.p_selected_program,
993                                          p_pes->i_pts * 9/100);
994
995     
996     if( p_demux_track->p_data_init )
997     {
998         pes_packet_t *p_pes_init;
999         /* create a pes packet containing decoder initialisation 
1000            with the one we will send to decoder */
1001         if( !(p_pes_init = input_NewPES( p_input->p_method_data ) ) )
1002         {
1003             msg_Err( p_input, "out of memory" );
1004             return( 0 );
1005         }
1006         
1007         p_pes_init->p_first = 
1008             p_pes_init->p_last = p_demux_track->p_data_init;
1009
1010         p_pes_init->i_pes_size = p_demux_track->p_data_init->p_payload_end - 
1011                                    p_demux_track->p_data_init->p_payload_start;
1012         p_pes_init->i_nb_data = 1;
1013
1014         input_DecodePES( p_demux_track->p_es->p_decoder_fifo, p_pes_init );
1015         p_demux_track->p_data_init = NULL;
1016     }
1017
1018     input_DecodePES( p_demux_track->p_es->p_decoder_fifo, p_pes );
1019     
1020     /* now update sample position */
1021     p_demux_track->i_sample++; /* easy ;) */
1022     if( p_demux_track->i_sample >= p_demux_track->i_sample_count )
1023     {
1024         /* we have reach end of the track so free decoder stuff */
1025         MP4_StopDecoder( p_input, p_demux_track );
1026         return( 1 );
1027     }
1028     /* Have we changed chunk ? */
1029     if( p_demux_track->i_sample >=
1030             p_demux_track->chunk[p_demux_track->i_chunk].i_sample_first +
1031                 p_demux_track->chunk[p_demux_track->i_chunk].i_sample_count )
1032     {
1033         /* we haven't reached the end of the track, so see if we 
1034            have to change the decoder for the next frame because 
1035            i_sample_description_index have changed */
1036
1037         p_demux_track->i_chunk++;
1038         if( p_demux_track->chunk[p_demux_track->i_chunk-1].i_sample_description_index 
1039               != p_demux_track->chunk[p_demux_track->i_chunk].i_sample_description_index  )
1040         {
1041             /* FIXME */
1042             msg_Err( p_input, "I need to change the decoder but not yet implemented" );
1043             return( 0 );
1044         }
1045     }
1046
1047     
1048     return( 1 );
1049 }
1050
1051
1052