]> git.sesse.net Git - vlc/blob - plugins/mp4/mp4.c
c5e92eed65c225e6259be75e2e0038540daf7d8a
[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.7 2002/07/23 22:42:20 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] ) + ( p_peek[5] << 8 ) +
141                 ( p_peek[6] << 16 ) + ( p_peek[7] << 24);
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 (%c%c%c%c).",
190                            p_ftyp->data.p_ftyp->i_major_brand&0xff,
191                            ( p_ftyp->data.p_ftyp->i_major_brand >>  8)&0xff,
192                            ( p_ftyp->data.p_ftyp->i_major_brand >> 16 )&0xff,
193                            ( p_ftyp->data.p_ftyp->i_major_brand >> 24 )&0xff );
194                 break;
195         }
196     }
197     else
198     {
199         msg_Info( p_input, "File Type box missing(assume ISO Media file)" );
200     }
201
202     /* the file need to have one moov box */
203     if( !( p_moov = MP4_FindBox( &p_demux->box_root, FOURCC_moov ) ) )
204     {
205         msg_Warn( p_input, "MP4 plugin discarded (missing moov box)" );
206         MP4End( p_input );
207         return( -1 );
208     }
209
210     if( MP4_CountBox( &p_demux->box_root, FOURCC_moov ) != 1 )
211     {
212         msg_Warn( p_input, "more than one \"moov\" box (continuying anyway)" );
213     }
214
215     if( !(p_mvhd = MP4_FindBox( p_moov, FOURCC_mvhd ) ) )
216     {
217         msg_Err( p_input, "cannot find \"mvhd\" box" );
218         MP4End( p_input );
219         return( -1 );
220     }
221     else
222     {
223         p_demux->i_timescale = p_mvhd->data.p_mvhd->i_timescale;
224     }
225     
226     p_demux->i_tracks = MP4_CountBox( p_moov, FOURCC_trak );
227     msg_Dbg( p_input, "find %d track%c",
228                         p_demux->i_tracks,
229                         p_demux->i_tracks ? 's':' ' );
230
231     if( !( p_trak = MP4_FindBox( p_moov, FOURCC_trak ) ) )
232     {
233         msg_Err( p_input, "cannot find /moov/trak !" );
234         MP4End( p_input );
235         return( -1 );
236     }
237
238     /* allocate memory */
239     p_demux->track = calloc( p_demux->i_tracks, sizeof( track_data_mp4_t ) );
240
241     /* now process each track and extract all usefull informations */
242     for( i = 0; i < p_demux->i_tracks; i++ )
243     {
244         MP4_ParseTrack( p_input, &p_demux->track[i], p_trak );
245
246         if( p_demux->track[i].b_ok )
247         {
248             char *psz_cat;
249             switch( p_demux->track[i].i_cat )
250             {
251                 case( VIDEO_ES ):
252                     psz_cat = "video";
253                     break;
254                 case( AUDIO_ES ):
255                     psz_cat = "audio";
256                     break;
257                 default:
258                     psz_cat = "";
259                     break;
260             }
261             
262             msg_Dbg( p_input, "adding track(%d) %s (%s) language %c%c%c",
263                             i,
264                             psz_cat,
265                             p_demux->track[i].b_enable ? "enable":"disable",
266                             p_demux->track[i].i_language[0],
267                             p_demux->track[i].i_language[1], 
268                             p_demux->track[i].i_language[2] );
269         }
270         else
271         {
272             msg_Dbg( p_input, "ignoring track(%d)", i );
273         }
274
275         p_trak = MP4_FindNextBox( p_trak );
276     }
277   
278     /*  create one program */
279     vlc_mutex_lock( &p_input->stream.stream_lock );
280     if( input_InitStream( p_input, 0 ) == -1)
281     {
282         vlc_mutex_unlock( &p_input->stream.stream_lock );
283         msg_Err( p_input, "cannot init stream" );
284         MP4End( p_input );
285         return( -1 );
286     }
287     if( input_AddProgram( p_input, 0, 0) == NULL )
288     {
289         vlc_mutex_unlock( &p_input->stream.stream_lock );
290         msg_Err( p_input, "cannot add program" );
291         MP4End( p_input );
292         return( -1 );
293     }
294     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
295     p_input->stream.i_mux_rate = 0 ; /* FIXME */
296     vlc_mutex_unlock( &p_input->stream.stream_lock );
297    
298     
299     for( i = 0; i < p_demux->i_tracks; i++ )
300     {
301         /* start decoder for this track if enable by default*/
302         if( p_demux->track[i].b_enable )
303         {
304             MP4_StartDecoder( p_input, &p_demux->track[i] );
305         }
306     }
307
308     vlc_mutex_lock( &p_input->stream.stream_lock );
309     p_input->stream.p_selected_program->b_is_ok = 1;
310     vlc_mutex_unlock( &p_input->stream.stream_lock );
311         
312     return( 0 );    
313
314 }
315
316 /*****************************************************************************
317  * MP4Demux: read packet and send them to decoders 
318  *****************************************************************************/
319 static int MP4Demux( input_thread_t *p_input )
320 {
321     demux_data_mp4_t *p_demux = p_input->p_demux_data;
322     int i_track;
323
324     /* first wait for the good time to read a packet */
325
326     input_ClockManageRef( p_input,
327                           p_input->stream.p_selected_program,
328                           p_demux->i_pcr );
329
330
331     /* update pcr XXX in mpeg scale so in 90000 unit/s */
332     p_demux->i_pcr = MP4_GetMoviePTS( p_demux ) * 9 / 100;
333     
334
335     /* we will read 100ms for each stream so ...*/
336     p_demux->i_time += __MAX( p_demux->i_timescale / 10 , 1 );
337     
338
339     for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
340     {
341         if( ( !p_demux->track[i_track].b_ok )||
342             ( !p_demux->track[i_track].p_es )||
343             ( !p_demux->track[i_track].p_es->p_decoder_fifo )||
344             ( MP4_GetTrackPTS( &p_demux->track[i_track] ) >=
345                         MP4_GetMoviePTS( p_demux ) ) )
346         {
347             continue; /* no need to read something */
348         }
349
350         while( MP4_GetTrackPTS( &p_demux->track[i_track] ) <
351                         MP4_GetMoviePTS( p_demux ) )
352         {
353
354             pes_packet_t *p_pes;
355
356             /* read a sample */
357             if( !MP4_ReadSample( p_input ,
358                                  &p_demux->track[i_track],
359                                  &p_pes ) )
360             {
361                 break;
362             }
363
364             /* send it to decoder and update time of this track 
365                  it also launch a new decoder if needed */
366             MP4_DecodeSample( p_input ,
367                               &p_demux->track[i_track],
368                               p_pes );
369         }
370
371     }
372     
373     /* now check if all tracks are finished or unhandled*/
374     
375     for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
376     {
377         if( ( p_demux->track[i_track].b_ok )&&
378             ( p_demux->track[i_track].i_sample < p_demux->track[i_track].i_sample_count )&&
379             ( p_demux->track[i_track].p_es )&&
380             ( p_demux->track[i_track].p_es->p_decoder_fifo ) )
381         {
382             return( 1 );
383         }
384     }
385
386     return( 0 ); /* EOF */
387 }
388
389 /*****************************************************************************
390  * MP4End: frees unused data
391  *****************************************************************************/
392 static void MP4End( input_thread_t *p_input )
393 {   
394 #define FREE( p ) \
395     if( p ) { free( p ); } 
396     int i_track;
397     demux_data_mp4_t *p_demux = p_input->p_demux_data;
398     
399     msg_Dbg( p_input, "Freeing all memory" );
400     MP4_FreeBox( p_input, &p_demux->box_root );
401     for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
402     {
403         int i_chunk;
404         for( i_chunk = 0; 
405                 i_chunk < p_demux->track[i_track].i_chunk_count; i_chunk++ )
406         {
407             if( p_demux->track[i_track].chunk )
408             {
409                FREE(p_demux->track[i_track].chunk[i_chunk].p_sample_count_dts);
410                FREE(p_demux->track[i_track].chunk[i_chunk].p_sample_delta_dts );
411             }
412         }
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
755     int i_decoder_specific_info_len;
756     u8  *p_decoder_specific_info;
757     
758     u8  *p_init;
759  
760     MP4_Box_t *p_esds;
761
762     
763     if( (!p_demux_track->b_ok )||( p_demux_track->i_cat == UNKNOWN_ES ) )
764     {
765         return;
766     }
767     
768     msg_Dbg( p_input, "Starting decoder (track ID 0x%x)",
769                       p_demux_track->i_track_ID );
770
771     /* launch decoder according in chunk we are */
772     i_chunk = p_demux_track->i_chunk;
773
774     if( !p_demux_track->chunk[i_chunk].i_sample_description_index )
775     {
776         msg_Warn( p_input, 
777                   "invalid SampleEntry index (track ID 0x%x)",
778                   p_demux_track->i_track_ID );
779         return;
780     } 
781     
782     p_sample = MP4_FindNbBox( p_demux_track->p_stsd,
783                  p_demux_track->chunk[i_chunk].i_sample_description_index - 1);
784
785     if( ( !p_sample )||( !p_sample->data.p_data ) )
786     {
787         msg_Warn( p_input, 
788                   "cannot find SampleEntry (track ID 0x%x)",
789                   p_demux_track->i_track_ID );
790         return;
791     }
792
793     vlc_mutex_lock( &p_input->stream.stream_lock );
794     p_demux_track->p_es = input_AddES( p_input,
795                                        p_input->stream.p_selected_program, 
796                                        p_demux_track->i_track_ID,
797                                        0 );
798     vlc_mutex_unlock( &p_input->stream.stream_lock );
799     /* Initialise ES, first language as description */
800     for( i = 0; i < 3; i++ )
801     {
802         p_demux_track->p_es->psz_desc[i] = p_demux_track->i_language[i];
803     }
804     p_demux_track->p_es->psz_desc[4] = 0;
805     
806     p_demux_track->p_es->i_stream_id = p_demux_track->i_track_ID;
807
808     /* It's a little ugly but .. there are special cases */
809     switch( p_sample->i_type )
810     {
811         case( VLC_FOURCC( '.', 'm', 'p', '3' ) ):
812         case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ):
813             p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'a' );
814             break;
815         default:
816             p_demux_track->p_es->i_fourcc = p_sample->i_type;
817             break;
818     }
819     
820     p_demux_track->p_es->i_cat = p_demux_track->i_cat;
821     
822     i_decoder_specific_info_len = 0;
823     p_decoder_specific_info = NULL;
824
825     /* now see if esds is present and if so create a data packet 
826         with decoder_specific_info  */
827 #define p_decconfig p_esds->data.p_esds->es_descriptor.p_decConfigDescr
828     if( ( p_esds = MP4_FindBox( p_sample, FOURCC_esds ) )&&
829         ( p_esds->data.p_esds )&&
830         ( p_decconfig ) )
831     {
832         /* First update information based on i_objectTypeIndication */
833         switch( p_decconfig->i_objectTypeIndication )
834         {
835             case( 0x20 ): /* MPEG4 VIDEO */
836                 p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','4','v' );
837                 break;
838             case( 0x40):
839                 p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' );
840                 break;
841             case( 0x60):
842             case( 0x61):
843             case( 0x62):
844             case( 0x63):
845             case( 0x64):
846             case( 0x65): /* MPEG2 video */
847                 p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
848                 break;
849             /* Theses are MPEG2-AAC (what is this codec ?) */
850             case( 0x66): /* main profile */
851             case( 0x67): /* Low complexity profile */
852             case( 0x68): /* Scaleable Sampling rate profile */
853                 p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' );
854                 break;
855             /* true MPEG 2 audio */
856             case( 0x69): 
857                 p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
858                 break;
859             case( 0x6a): /* MPEG1 video */
860                 p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
861                 break;
862             case( 0x6b): /* MPEG1 audio */
863                 p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
864                 break;
865             case( 0x6c ): /* jpeg */
866                 p_demux_track->p_es->i_fourcc = VLC_FOURCC( 'j','p','e','g' );
867                 break;
868             default:
869                 /* Unknown entry, but don't touch i_fourcc */
870                 msg_Warn( p_input, 
871                           "objectTypeIndication(0x%x) unknow (Track ID 0x%x)",
872                           p_decconfig->i_objectTypeIndication,
873                           p_demux_track->i_track_ID );
874                 break;
875         }
876         i_decoder_specific_info_len = 
877                 p_decconfig->i_decoder_specific_info_len;
878         p_decoder_specific_info = 
879                 p_decconfig->p_decoder_specific_info;
880     }
881
882 #undef p_decconfig
883
884     /* some last initialisation */
885     /* XXX I create a bitmapinfoheader_t or 
886        waveformatex_t for each stream, up to now it's the best thing 
887        I've found but it could exist a better solution :) as something 
888        like adding some new fields in p_es ...
889
890        XXX I don't set all values, only thoses that are interesting or known
891         --> bitmapinfoheader_t : width and height 
892         --> waveformatex_t : channels, samplerate, bitspersample
893         and at the end I add p_decoder_specific_info 
894         
895         TODO set more values
896      
897      */
898
899     switch( p_demux_track->i_cat )
900     {
901         case( VIDEO_ES ):    
902             /* now create a bitmapinfoheader_t for decoder and 
903                add information found in p_esds */
904             p_init = malloc( 40 + i_decoder_specific_info_len);
905             memset( p_init, 0, 40 + i_decoder_specific_info_len);
906             MP4_Set4BytesLE( p_init, 40 + i_decoder_specific_info_len );
907             if( p_sample->data.p_sample_vide->i_width )
908             {
909                 MP4_Set4BytesLE( p_init + 4, 
910                                  p_sample->data.p_sample_vide->i_width );
911             }
912             else
913             {
914                 /* use display size */
915                 MP4_Set4BytesLE( p_init + 4, p_demux_track->i_width );
916             }
917             if( p_sample->data.p_sample_vide->i_height )
918             {
919                 MP4_Set4BytesLE( p_init + 8, 
920                                  p_sample->data.p_sample_vide->i_height );
921             }
922             else
923             {
924                 MP4_Set4BytesLE( p_init + 8, p_demux_track->i_height );
925             }
926             if( i_decoder_specific_info_len )
927             {
928                 memcpy( p_init + 40, 
929                         p_decoder_specific_info,
930                         i_decoder_specific_info_len);
931             }
932             break;
933
934         case( AUDIO_ES ):
935             p_init = malloc( 18 + i_decoder_specific_info_len);
936             memset( p_init, 0, 18 + i_decoder_specific_info_len);
937             MP4_Set2BytesLE( p_init + 2, /* i_channel */
938                              p_sample->data.p_sample_soun->i_channelcount );
939             MP4_Set4BytesLE( p_init + 4, /* samplepersec */
940                              p_sample->data.p_sample_soun->i_sampleratehi );
941             MP4_Set4BytesLE( p_init + 8, /* avgbytespersec */
942                              p_sample->data.p_sample_soun->i_channelcount *
943                                 p_sample->data.p_sample_soun->i_sampleratehi *
944                              (p_sample->data.p_sample_soun->i_samplesize/8) );
945             MP4_Set2BytesLE( p_init + 14, /* bits/sample */
946                              p_sample->data.p_sample_soun->i_samplesize );
947
948             MP4_Set2BytesLE( p_init + 16, /* i_size, specific info len*/
949                              i_decoder_specific_info_len );
950             if( i_decoder_specific_info_len )
951             {
952                 memcpy( p_init + 18, 
953                         p_decoder_specific_info,
954                         i_decoder_specific_info_len);
955             }
956             break;
957
958         default:
959             p_init = NULL;
960             break;
961     }
962
963     p_demux_track->p_es->p_demux_data = p_init;
964     vlc_mutex_lock( &p_input->stream.stream_lock );
965     input_SelectES( p_input, p_demux_track->p_es );
966     vlc_mutex_unlock( &p_input->stream.stream_lock );
967
968     p_demux_track->b_ok = 1;
969 }
970
971 static void MP4_StopDecoder( input_thread_t *p_input,
972                              track_data_mp4_t *p_demux_track )
973 {
974     msg_Dbg( p_input, "Stopping decoder (track ID 0x%x)",
975                       p_demux_track->i_track_ID );
976
977     input_UnselectES( p_input, p_demux_track->p_es );
978     p_demux_track->p_es = NULL;
979 }
980
981 static int  MP4_ReadSample( input_thread_t *p_input,
982                             track_data_mp4_t *p_demux_track,
983                             pes_packet_t **pp_pes )
984 {
985     int i_size;
986     off_t i_pos;
987
988     data_packet_t *p_data;
989
990
991     /* this track have already reach the end */
992     if( p_demux_track->i_sample >= p_demux_track->i_sample_count )
993     {
994         *pp_pes = NULL;
995         return( 0 );
996     }
997     /* caculate size and position for this sample */
998     i_size = p_demux_track->i_sample_size ? 
999                     p_demux_track->i_sample_size : 
1000                     p_demux_track->p_sample_size[p_demux_track->i_sample];
1001     /* TODO */
1002     i_pos  = MP4_GetTrackPos( p_demux_track );
1003
1004     /* go,go go ! */
1005     if( ! MP4_SeekAbsolute( p_input, i_pos ) )
1006     {
1007         return( 0 );
1008     }
1009
1010     /* now create a pes */
1011     if( !(*pp_pes = input_NewPES( p_input->p_method_data ) ) )
1012     {
1013         return( 0 );
1014     }
1015     /* and a data packet for the data */
1016     if( !(p_data = input_NewPacket( p_input->p_method_data, i_size ) ) )
1017     {
1018         input_DeletePES( p_input->p_method_data, *pp_pes );
1019         *pp_pes = NULL;
1020         return( 0 );
1021     }
1022     
1023     /* initialisation of all the field */
1024     (*pp_pes)->i_dts =
1025         (*pp_pes)->i_pts = MP4_GetTrackPTS( p_demux_track );
1026     (*pp_pes)->p_first = (*pp_pes)->p_last  = p_data;
1027     (*pp_pes)->i_nb_data = 1;
1028     (*pp_pes)->i_pes_size = i_size;
1029
1030     if( !i_size )    
1031     {
1032         return( 1 );
1033     }
1034     
1035 //    msg_Dbg( p_input, "will read %d bytes", i_size );
1036     if( !MP4_ReadData( p_input, p_data->p_payload_start, i_size ) )
1037     {
1038         input_DeletePES( p_input->p_method_data, *pp_pes );
1039         input_DeletePacket( p_input->p_method_data, p_data );
1040         return( 0 );
1041     }
1042
1043         return( 1 );
1044 }
1045
1046
1047 static int  MP4_DecodeSample( input_thread_t *p_input,
1048                               track_data_mp4_t *p_demux_track,
1049                               pes_packet_t *p_pes )
1050 {
1051
1052     if( !p_pes )
1053     {
1054         return( 0 );
1055     }
1056
1057     /* don't forget to convert in mpeg clock */
1058     /* FIXME correct ffmpeg to use dts instead of pts that it incorrect 
1059        and, set it here ( and correct avi demux ) */
1060     p_pes->i_dts =
1061         p_pes->i_pts = input_ClockGetTS( p_input,
1062                                          p_input->stream.p_selected_program,
1063                                          p_pes->i_pts * 9/100);
1064
1065     
1066     input_DecodePES( p_demux_track->p_es->p_decoder_fifo, p_pes );
1067     
1068     /* now update sample position */
1069     p_demux_track->i_sample++; /* easy ;) */
1070     if( p_demux_track->i_sample >= p_demux_track->i_sample_count )
1071     {
1072         /* we have reach end of the track so free decoder stuff */
1073         MP4_StopDecoder( p_input, p_demux_track );
1074         return( 1 );
1075     }
1076     /* Have we changed chunk ? */
1077     if( p_demux_track->i_sample >=
1078             p_demux_track->chunk[p_demux_track->i_chunk].i_sample_first +
1079                 p_demux_track->chunk[p_demux_track->i_chunk].i_sample_count )
1080     {
1081         /* we haven't reached the end of the track, so see if we 
1082            have to change the decoder for the next frame because 
1083            i_sample_description_index have changed */
1084
1085         p_demux_track->i_chunk++;
1086         if( p_demux_track->chunk[p_demux_track->i_chunk-1].i_sample_description_index 
1087               != p_demux_track->chunk[p_demux_track->i_chunk].i_sample_description_index  )
1088         {
1089             /* FIXME */
1090             msg_Warn( p_input, 
1091                       "SampleEntry have changed, starting a new decoder" );
1092             MP4_StopDecoder( p_input, p_demux_track );
1093             MP4_StartDecoder( p_input, p_demux_track );
1094         }
1095     }
1096
1097     
1098     return( 1 );
1099 }
1100
1101
1102