5078fdb14183588efc47a224a544f73b96c2a53a
[vlc.git] / modules / demux / 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.24 2003/04/22 16:28:24 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 #include <vlc_playlist.h>
34 #include "codecs.h"
35 #include "libmp4.h"
36 #include "mp4.h"
37
38 /*****************************************************************************
39  * Local prototypes
40  *****************************************************************************/
41 static int    MP4Init    ( vlc_object_t * );
42 static void __MP4End     ( vlc_object_t * );
43 static int    MP4Demux   ( input_thread_t * );
44
45 /* New input could have something like that... */
46 static int   MP4Seek     ( input_thread_t *, mtime_t );
47
48 #define MP4End(a) __MP4End(VLC_OBJECT(a))
49
50 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53 vlc_module_begin();
54     set_description( _("MP4 demuxer") );
55     set_capability( "demux", 242 );
56     set_callbacks( MP4Init, __MP4End );
57 vlc_module_end();
58
59 /*****************************************************************************
60  * Declaration of local function
61  *****************************************************************************/
62
63 static void MP4_TrackCreate ( input_thread_t *,
64                               track_data_mp4_t *,
65                               MP4_Box_t  * );
66 static void MP4_TrackDestroy( input_thread_t *,
67                               track_data_mp4_t * );
68
69 static int  MP4_TrackSelect ( input_thread_t *,
70                               track_data_mp4_t *,
71                               mtime_t );
72 static void MP4_TrackUnselect(input_thread_t *,
73                               track_data_mp4_t * );
74
75 static int  MP4_TrackSeek   ( input_thread_t *,
76                               track_data_mp4_t *,
77                               mtime_t );
78
79 static uint64_t MP4_GetTrackPos( track_data_mp4_t * );
80 static int  MP4_TrackSampleSize( track_data_mp4_t * );
81 static int  MP4_TrackNextSample( input_thread_t *,
82                                  track_data_mp4_t * );
83
84 #define MP4_Set4BytesLE( p, dw ) \
85     *((uint8_t*)p)   = ( (dw)&0xff ); \
86     *((uint8_t*)p+1) = ( ((dw)>> 8)&0xff ); \
87     *((uint8_t*)p+2) = ( ((dw)>>16)&0xff ); \
88     *((uint8_t*)p+3) = ( ((dw)>>24)&0xff )
89
90 #define MP4_Set2BytesLE( p, dw ) \
91     *((uint8_t*)p) = ( (dw)&0xff ); \
92     *((uint8_t*)p+1) = ( ((dw)>> 8)&0xff )
93
94 #define FREE( p ) \
95     if( p ) { free( p ); (p) = NULL;}
96
97 /*****************************************************************************
98  * MP4Init: check file and initializes MP4 structures
99  *****************************************************************************/
100 static int MP4Init( vlc_object_t * p_this )
101 {
102     input_thread_t  *p_input = (input_thread_t *)p_this;
103     uint8_t         *p_peek;
104
105     demux_sys_t     *p_demux;
106
107     MP4_Box_t       *p_ftyp;
108
109     MP4_Box_t       *p_rmra;
110
111     MP4_Box_t       *p_mvhd;
112     MP4_Box_t       *p_trak;
113
114     unsigned int    i;
115     /* I need to seek */
116     if( !p_input->stream.b_seekable )
117     {
118         msg_Warn( p_input, "MP4 plugin discarded (unseekable)" );
119         return( -1 );
120
121     }
122     /* Initialize access plug-in structures. */
123     if( p_input->i_mtu == 0 )
124     {
125         /* Improve speed. */
126         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
127     }
128
129     p_input->pf_demux = MP4Demux;
130
131     /* a little test to see if it could be a mp4 */
132     if( input_Peek( p_input, &p_peek, 8 ) < 8 )
133     {
134         msg_Warn( p_input, "MP4 plugin discarded (cannot peek)" );
135         return( -1 );
136     }
137
138
139     switch( VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] ) )
140     {
141         case( FOURCC_ftyp ):
142         case( FOURCC_moov ):
143         case( FOURCC_moof ):
144         case( FOURCC_mdat ):
145         case( FOURCC_udta ):
146         case( FOURCC_free ):
147         case( FOURCC_skip ):
148         case( FOURCC_wide ):
149             break;
150          default:
151             msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
152             return( -1 );
153     }
154
155     /* create our structure that will contains all data */
156     if( !( p_input->p_demux_data =
157                 p_demux = malloc( sizeof( demux_sys_t ) ) ) )
158     {
159         msg_Err( p_input, "out of memory" );
160         return( -1 );
161     }
162     memset( p_demux, 0, sizeof( demux_sys_t ) );
163     p_input->p_demux_data = p_demux;
164
165
166     /* Now load all boxes ( except raw data ) */
167     if( !MP4_BoxGetRoot( p_input, &p_demux->box_root ) )
168     {
169         msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
170         return( -1 );
171     }
172
173     MP4_BoxDumpStructure( p_input, &p_demux->box_root );
174
175     if( ( p_ftyp = MP4_BoxGet( &p_demux->box_root, "/ftyp" ) ) )
176     {
177         switch( p_ftyp->data.p_ftyp->i_major_brand )
178         {
179             case( FOURCC_isom ):
180                 msg_Dbg( p_input,
181                          "ISO Media file (isom) version %d.",
182                          p_ftyp->data.p_ftyp->i_minor_version );
183                 break;
184             default:
185                 msg_Dbg( p_input,
186                          "unrecognized major file specification (%4.4s).",
187                           (char*)&p_ftyp->data.p_ftyp->i_major_brand );
188                 break;
189         }
190     }
191     else
192     {
193         msg_Dbg( p_input, "file type box missing (assuming ISO Media file)" );
194     }
195
196     /* the file need to have one moov box */
197     if( MP4_BoxCount( &p_demux->box_root, "/moov" ) != 1 )
198     {
199         msg_Err( p_input,
200                  "MP4 plugin discarded (%d moov boxes)",
201                  MP4_BoxCount( &p_demux->box_root, "/moov" ) );
202 //        MP4End( p_input );
203 //        return( -1 );
204     }
205
206     if( ( p_rmra = MP4_BoxGet( &p_demux->box_root,  "/moov/rmra" ) ) )
207     {
208         playlist_t *p_playlist;
209         int        i_count = MP4_BoxCount( p_rmra, "rmda" );
210         int        i;
211
212         msg_Dbg( p_input, "detected playlist mov file (%d ref)", i_count );
213
214         p_playlist =
215             (playlist_t *)vlc_object_find( p_input,
216                                            VLC_OBJECT_PLAYLIST,
217                                            FIND_ANYWHERE );
218         if( p_playlist )
219         {
220             for( i = 0; i < i_count; i++ )
221             {
222                 MP4_Box_t *p_rdrf = MP4_BoxGet( p_rmra, "rmda[%d]/rdrf", i );
223                 char      *psz_ref;
224                 uint32_t  i_ref_type;
225
226                 if( !p_rdrf || !( psz_ref = p_rdrf->data.p_rdrf->psz_ref ) )
227                 {
228                     continue;
229                 }
230                 i_ref_type = p_rdrf->data.p_rdrf->i_ref_type;
231
232                 msg_Dbg( p_input, "new ref=`%s' type=%4.4s",
233                          psz_ref, (char*)&i_ref_type );
234
235                 if( i_ref_type == VLC_FOURCC( 'u', 'r', 'l', ' ' ) )
236                 {
237                     if( strstr( psz_ref, "qt5gateQT" ) )
238                     {
239                         msg_Dbg( p_input, "ignoring pseudo ref =`%s'", psz_ref );
240                         continue;
241                     }
242                     if( !strncmp( psz_ref, "http://", 7 ) ||
243                         !strncmp( psz_ref, "rtsp://", 7 ) )
244                     {
245                         msg_Dbg( p_input, "adding ref = `%s'", psz_ref );
246                         playlist_Add( p_playlist, psz_ref, PLAYLIST_APPEND, PLAYLIST_END );
247                     }
248                     else
249                     {
250                         /* msg dbg relative ? */
251                         char *psz_absolute = alloca( strlen( p_input->psz_name ) + strlen( psz_ref ) + 1);
252                         char *end = strrchr( p_input->psz_name, '/' );
253
254                         if( end )
255                         {
256                             int i_len = end + 1 - p_input->psz_name;
257
258                             strncpy( psz_absolute, p_input->psz_name, i_len);
259                             psz_absolute[i_len] = '\0';
260                         }
261                         else
262                         {
263                             strcpy( psz_absolute, "" );
264                         }
265                         strcat( psz_absolute, psz_ref );
266                         msg_Dbg( p_input, "adding ref = `%s'", psz_absolute );
267                         playlist_Add( p_playlist, psz_absolute, PLAYLIST_APPEND, PLAYLIST_END );
268                     }
269                 }
270                 else
271                 {
272                     msg_Err( p_input, "unknown ref type=%4.4s FIXME (send a bug report)", (char*)&p_rdrf->data.p_rdrf->i_ref_type );
273                 }
274             }
275             vlc_object_release( p_playlist );
276         }
277         else
278         {
279             msg_Err( p_input, "can't find playlist" );
280         }
281     }
282
283     if( !(p_mvhd = MP4_BoxGet( &p_demux->box_root, "/moov/mvhd" ) ) )
284     {
285         if( !p_rmra )
286         {
287             msg_Err( p_input, "cannot find /moov/mvhd" );
288         }
289         else
290         {
291             msg_Warn( p_input, "cannot find /moov/mvhd (pure ref file)" );
292         }
293         MP4End( p_input );
294         return( -1 );
295     }
296     else
297     {
298         p_demux->i_timescale = p_mvhd->data.p_mvhd->i_timescale;
299         p_demux->i_duration = p_mvhd->data.p_mvhd->i_duration;
300     }
301
302     if( !( p_demux->i_tracks =
303                 MP4_BoxCount( &p_demux->box_root, "/moov/trak" ) ) )
304     {
305         msg_Err( p_input, "cannot find any /moov/trak" );
306         MP4End( p_input );
307         return( -1 );
308     }
309     msg_Dbg( p_input, "find %d track%c",
310                         p_demux->i_tracks,
311                         p_demux->i_tracks ? 's':' ' );
312
313     /*  create one program */
314     vlc_mutex_lock( &p_input->stream.stream_lock );
315     if( input_InitStream( p_input, 0 ) == -1)
316     {
317         vlc_mutex_unlock( &p_input->stream.stream_lock );
318         msg_Err( p_input, "cannot init stream" );
319         MP4End( p_input );
320         return( -1 );
321     }
322     /* Needed to create program _before_ MP4_TrackCreate */
323     if( input_AddProgram( p_input, 0, 0) == NULL )
324     {
325         vlc_mutex_unlock( &p_input->stream.stream_lock );
326         msg_Err( p_input, "cannot add program" );
327         MP4End( p_input );
328         return( -1 );
329     }
330     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
331     /* XXX beurk and beurk, see MP4Demux and MP4Seek */
332     if( p_demux->i_duration/p_demux->i_timescale > 0 )
333     {
334         p_input->stream.i_mux_rate =
335             p_input->stream.p_selected_area->i_size / 50 /
336             ( p_demux->i_duration / p_demux->i_timescale );
337     }
338     else
339     {
340         p_input->stream.i_mux_rate = 0;
341     }
342     vlc_mutex_unlock( &p_input->stream.stream_lock );
343
344
345     /* allocate memory */
346     p_demux->track = calloc( p_demux->i_tracks, sizeof( track_data_mp4_t ) );
347
348     /* now process each track and extract all usefull informations */
349     for( i = 0; i < p_demux->i_tracks; i++ )
350     {
351         p_trak = MP4_BoxGet( &p_demux->box_root, "/moov/trak[%d]", i );
352         MP4_TrackCreate( p_input, &p_demux->track[i], p_trak );
353
354         if( p_demux->track[i].b_ok )
355         {
356             char *psz_cat;
357             switch( p_demux->track[i].i_cat )
358             {
359                 case( VIDEO_ES ):
360                     psz_cat = "video";
361                     break;
362                 case( AUDIO_ES ):
363                     psz_cat = "audio";
364                     break;
365                 default:
366                     psz_cat = "unknown";
367                     break;
368             }
369
370             msg_Dbg( p_input, "adding track[Id 0x%x] %s (%s) language %c%c%c",
371                             p_demux->track[i].i_track_ID,
372                             psz_cat,
373                             p_demux->track[i].b_enable ? "enable":"disable",
374                             p_demux->track[i].i_language[0],
375                             p_demux->track[i].i_language[1],
376                             p_demux->track[i].i_language[2] );
377         }
378         else
379         {
380             msg_Dbg( p_input, "ignoring track[Id 0x%x]", p_demux->track[i].i_track_ID );
381         }
382
383     }
384
385     for( i = 0; i < p_demux->i_tracks; i++ )
386     {
387         /* start decoder for this track if enable by default*/
388         if( p_demux->track[i].b_ok && p_demux->track[i].b_enable )
389         {
390             MP4_TrackSelect( p_input, &p_demux->track[i], 0 );
391         }
392     }
393
394     vlc_mutex_lock( &p_input->stream.stream_lock );
395     p_input->stream.p_selected_program->b_is_ok = 1;
396     vlc_mutex_unlock( &p_input->stream.stream_lock );
397
398     return( 0 );
399
400 }
401
402 /*****************************************************************************
403  * MP4Demux: read packet and send them to decoders
404  *****************************************************************************
405  * TODO check for newly selected track (ie audio upt to now )
406  *****************************************************************************/
407 static int MP4Demux( input_thread_t *p_input )
408 {
409     demux_sys_t *p_demux = p_input->p_demux_data;
410     unsigned int i_track;
411
412
413     unsigned int i_track_selected;
414     vlc_bool_t   b_video;
415     vlc_bool_t   b_play_audio;
416
417     /* check for newly selected/unselected track */
418     for( i_track = 0, i_track_selected = 0, b_video = VLC_FALSE;
419             i_track <  p_demux->i_tracks; i_track++ )
420     {
421 #define track   p_demux->track[i_track]
422         if( track.b_selected && track.i_sample >= track.i_sample_count )
423         {
424             msg_Warn( p_input, "track[0x%x] will be disabled", track.i_track_ID );
425             MP4_TrackUnselect( p_input, &track );
426         }
427         else if( track.b_ok )
428         {
429             if( track.b_selected && track.p_es->p_decoder_fifo == NULL )
430             {
431                 MP4_TrackUnselect( p_input, &track );
432             }
433             else if( !track.b_selected && track.p_es->p_decoder_fifo != NULL )
434             {
435                 MP4_TrackSelect( p_input, &track, MP4_GetMoviePTS( p_demux ) );
436             }
437
438             if( track.b_selected )
439             {
440                 i_track_selected++;
441
442                 if( track.i_cat == VIDEO_ES )
443                 {
444                     b_video = VLC_TRUE;
445                 }
446             }
447         }
448 #undef  track
449     }
450
451     if( i_track_selected <= 0 )
452     {
453         msg_Warn( p_input, "no track selected, exiting..." );
454         return( 0 );
455     }
456
457
458     /* XXX beurk, beuRK and BEURK,
459        but only way I've found to detect seek from interface */
460     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
461     {
462         mtime_t i_date;
463
464         /* first wait for empty buffer, arbitrary time FIXME */
465         msleep( DEFAULT_PTS_DELAY );
466         /* *** calculate new date *** */
467
468         i_date = (mtime_t)1000000 *
469                  (mtime_t)p_demux->i_duration /
470                  (mtime_t)p_demux->i_timescale *
471                  (mtime_t)MP4_TellAbsolute( p_input ) /
472                  (mtime_t)p_input->stream.p_selected_area->i_size;
473         MP4Seek( p_input, i_date );
474     }
475
476     /* first wait for the good time to read a packet */
477     input_ClockManageRef( p_input,
478                           p_input->stream.p_selected_program,
479                           p_demux->i_pcr );
480
481
482     /* update pcr XXX in mpeg scale so in 90000 unit/s */
483     p_demux->i_pcr = MP4_GetMoviePTS( p_demux ) * 9 / 100;
484
485
486     /* we will read 100ms for each stream so ...*/
487     p_demux->i_time += __MAX( p_demux->i_timescale / 10 , 1 );
488
489
490     /* *** send audio data to decoder if rate == DEFAULT_RATE or no video *** */
491     vlc_mutex_lock( &p_input->stream.stream_lock );
492     if( p_input->stream.control.i_rate == DEFAULT_RATE || !b_video )
493     {
494         b_play_audio = VLC_TRUE;
495     }
496     else
497     {
498         b_play_audio = VLC_FALSE;
499     }
500     vlc_mutex_unlock( &p_input->stream.stream_lock );
501
502     for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
503     {
504 #define track p_demux->track[i_track]
505         if( !track.b_ok ||
506             !track.b_selected ||
507             MP4_GetTrackPTS( &track ) >= MP4_GetMoviePTS( p_demux ) )
508         {
509             continue;
510         }
511         while( MP4_GetTrackPTS( &track ) < MP4_GetMoviePTS( p_demux ) )
512         {
513
514             if( !b_play_audio && track.i_cat == AUDIO_ES )
515             {
516                 if( MP4_TrackNextSample( p_input, &track ) )
517                 {
518                     break;
519                 }
520             }
521             else
522             {
523                 size_t i_size;
524                 off_t i_pos;
525
526                 data_packet_t *p_data;
527                 pes_packet_t *p_pes;
528
529                 /* caculate size and position for this sample */
530                 i_size = MP4_TrackSampleSize( &track );
531
532                 i_pos  = MP4_GetTrackPos( &track );
533
534                 //msg_Dbg( p_input, "stream %d size=%6d pos=%8lld",  i_track, i_size, i_pos );
535
536                 /* go,go go ! */
537                 if( ! MP4_SeekAbsolute( p_input, i_pos ) )
538                 {
539                     msg_Warn( p_input, "track[0x%x] will be disabled (eof?)", track.i_track_ID );
540                     MP4_TrackUnselect( p_input, &track );
541                     break;
542                 }
543
544
545                 /* now create a pes */
546                 if( !(p_pes = input_NewPES( p_input->p_method_data ) ) )
547                 {
548                     break;
549                 }
550                 /* and a data packet for the data */
551                 if( !(p_data = input_NewPacket( p_input->p_method_data, i_size ) ) )
552                 {
553                     input_DeletePES( p_input->p_method_data, p_pes );
554                     break;
555                 }
556                 p_data->p_payload_end = p_data->p_payload_start + i_size;
557
558                 /* initialisation of all the field */
559                 p_pes->i_dts = p_pes->i_pts = 0;
560                 p_pes->p_first = p_pes->p_last  = p_data;
561                 p_pes->i_nb_data = 1;
562                 p_pes->i_pes_size = i_size;
563                 if( i_size > 0 )
564                 {
565                     if( !MP4_ReadData( p_input, p_data->p_payload_start, i_size ) )
566                     {
567                         input_DeletePES( p_input->p_method_data, p_pes );
568
569                         msg_Warn( p_input, "track[0x%x] will be disabled (eof?)", track.i_track_ID );
570                         MP4_TrackUnselect( p_input, &track );
571                         break;
572                     }
573                 }
574
575                 p_pes->i_dts =
576                     p_pes->i_pts = input_ClockGetTS( p_input,
577                                                      p_input->stream.p_selected_program,
578                                                      MP4_GetTrackPTS( &track ) * 9/100);
579
580                 if( track.p_es->p_decoder_fifo )
581                 {
582                     input_DecodePES( track.p_es->p_decoder_fifo, p_pes );
583                 }
584                 else
585                 {
586                     input_DeletePES( p_input->p_method_data, p_pes );
587                 }
588
589                 if( MP4_TrackNextSample( p_input, &track ) )
590                 {
591                     break;
592                 }
593             }
594         }
595 #undef track
596     }
597
598     return( 1 );
599 }
600 /*****************************************************************************
601  * MP4Seek: Got to i_date
602  ******************************************************************************/
603 static int   MP4Seek     ( input_thread_t *p_input, mtime_t i_date )
604 {
605     demux_sys_t *p_demux = p_input->p_demux_data;
606     unsigned int i_track;
607     /* First update update global time */
608     p_demux->i_time = i_date * p_demux->i_timescale / 1000000;
609     p_demux->i_pcr  = i_date* 9 / 100;
610
611     /* Now for each stream try to go to this time */
612     for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
613     {
614 #define track p_demux->track[i_track]
615         if( track.b_ok && track.b_selected )
616         {
617             MP4_TrackSeek( p_input, &track, i_date );
618         }
619 #undef  track
620     }
621     return( 1 );
622 }
623
624 /*****************************************************************************
625  * MP4End: frees unused data
626  *****************************************************************************/
627 static void __MP4End ( vlc_object_t * p_this )
628 {
629     unsigned int i_track;
630     input_thread_t *  p_input = (input_thread_t *)p_this;
631     demux_sys_t *p_demux = p_input->p_demux_data;
632
633     msg_Dbg( p_input, "freeing all memory" );
634     MP4_BoxFree( p_input, &p_demux->box_root );
635     for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
636     {
637         MP4_TrackDestroy( p_input, &p_demux->track[i_track] );
638     }
639     FREE( p_demux->track );
640
641     FREE( p_input->p_demux_data );
642 }
643
644
645 /****************************************************************************
646  * Local functions, specific to vlc
647  ****************************************************************************/
648
649 /* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */
650 static int TrackCreateChunksIndex( input_thread_t *p_input,
651                                    track_data_mp4_t *p_demux_track )
652 {
653     MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */
654     MP4_Box_t *p_stsc;
655
656     unsigned int i_chunk;
657     unsigned int i_index, i_last;
658
659     if( ( !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "stco" ) )&&
660           !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "co64" ) ) )||
661         ( !(p_stsc = MP4_BoxGet( p_demux_track->p_stbl, "stsc" ) ) ))
662     {
663         return( VLC_EGENERIC );
664     }
665
666     p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count;
667     if( !p_demux_track->i_chunk_count )
668     {
669         msg_Warn( p_input, "no chunk defined" );
670         return( VLC_EGENERIC );
671     }
672     p_demux_track->chunk = calloc( p_demux_track->i_chunk_count,
673                                    sizeof( chunk_data_mp4_t ) );
674
675     /* first we read chunk offset */
676     for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
677     {
678         p_demux_track->chunk[i_chunk].i_offset =
679                 p_co64->data.p_co64->i_chunk_offset[i_chunk];
680     }
681
682     /* now we read index for SampleEntry( soun vide mp4a mp4v ...)
683         to be used for the sample XXX begin to 1
684         We construct it begining at the end */
685     i_last = p_demux_track->i_chunk_count; /* last chunk proceded */
686     i_index = p_stsc->data.p_stsc->i_entry_count;
687     if( !i_index )
688     {
689         msg_Warn( p_input, "cannot read chunk table or table empty" );
690         return( VLC_EGENERIC );
691     }
692
693     while( i_index )
694     {
695         i_index--;
696         for( i_chunk = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;
697                 i_chunk < i_last; i_chunk++ )
698         {
699             p_demux_track->chunk[i_chunk].i_sample_description_index =
700                     p_stsc->data.p_stsc->i_sample_description_index[i_index];
701             p_demux_track->chunk[i_chunk].i_sample_count =
702                     p_stsc->data.p_stsc->i_samples_per_chunk[i_index];
703         }
704         i_last = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;
705     }
706
707     p_demux_track->chunk[0].i_sample_first = 0;
708     for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
709     {
710         p_demux_track->chunk[i_chunk].i_sample_first =
711             p_demux_track->chunk[i_chunk-1].i_sample_first +
712                 p_demux_track->chunk[i_chunk-1].i_sample_count;
713     }
714
715     msg_Dbg( p_input,
716              "track[Id 0x%x] read %d chunk",
717              p_demux_track->i_track_ID,
718             p_demux_track->i_chunk_count );
719
720     return( VLC_SUCCESS );
721 }
722 static int TrackCreateSamplesIndex( input_thread_t *p_input,
723                                     track_data_mp4_t *p_demux_track )
724 {
725     MP4_Box_t *p_stts; /* makes mapping between sample and decoding time,
726                           ctts make same mapping but for composition time,
727                           not yet used and probably not usefull */
728     MP4_Box_t *p_stsz; /* gives sample size of each samples, there is also stz2
729                           that uses a compressed form FIXME make them in libmp4
730                           as a unique type */
731     /* TODO use also stss and stsh table for seeking */
732     /* FIXME use edit table */
733     int64_t i_sample;
734     int64_t i_chunk;
735
736     int64_t i_index;
737     int64_t i_index_sample_used;
738
739     int64_t i_last_dts;
740
741     p_stts = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
742     p_stsz = MP4_BoxGet( p_demux_track->p_stbl, "stsz" ); /* FIXME and stz2 */
743
744     if( ( !p_stts )||( !p_stsz ) )
745     {
746         msg_Warn( p_input, "cannot read sample table" );
747         return( VLC_EGENERIC );
748     }
749
750     p_demux_track->i_sample_count = p_stsz->data.p_stsz->i_sample_count;
751
752
753     /* for sample size, there are 2 case */
754     if( p_stsz->data.p_stsz->i_sample_size )
755     {
756         /* 1: all sample have the same size, so no need to construct a table */
757         p_demux_track->i_sample_size = p_stsz->data.p_stsz->i_sample_size;
758         p_demux_track->p_sample_size = NULL;
759     }
760     else
761     {
762         /* 2: each sample can have a different size */
763         p_demux_track->i_sample_size = 0;
764         p_demux_track->p_sample_size =
765             calloc( p_demux_track->i_sample_count, sizeof( uint32_t ) );
766
767         for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
768         {
769             p_demux_track->p_sample_size[i_sample] =
770                     p_stsz->data.p_stsz->i_entry_size[i_sample];
771         }
772     }
773     /* we have extract all information from stsz,
774         now use stts */
775
776     /* if we don't want to waste too much memory, we can't expand
777        the box !, so each chunk will contain an "extract" of this table
778        for fast research */
779
780     i_last_dts = 0;
781     i_index = 0; i_index_sample_used =0;
782
783     /* create and init last data for each chunk */
784     for(i_chunk = 0 ; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
785     {
786
787         int64_t i_entry, i_sample_count, i;
788         /* save last dts */
789         p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts;
790     /* count how many entries needed for this chunk
791        for p_sample_delta_dts and p_sample_count_dts */
792
793         i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
794
795         i_entry = 0;
796         while( i_sample_count > 0 )
797         {
798             i_sample_count -= p_stts->data.p_stts->i_sample_count[i_index+i_entry];
799             if( i_entry == 0 )
800             {
801                 i_sample_count += i_index_sample_used; /* don't count already used sample
802                                                    int this entry */
803             }
804             i_entry++;
805         }
806
807         /* allocate them */
808         p_demux_track->chunk[i_chunk].p_sample_count_dts =
809             calloc( i_entry, sizeof( uint32_t ) );
810         p_demux_track->chunk[i_chunk].p_sample_delta_dts =
811             calloc( i_entry, sizeof( uint32_t ) );
812
813         /* now copy */
814         i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
815         for( i = 0; i < i_entry; i++ )
816         {
817             int64_t i_used;
818             int64_t i_rest;
819
820             i_rest = p_stts->data.p_stts->i_sample_count[i_index] - i_index_sample_used;
821
822             i_used = __MIN( i_rest, i_sample_count );
823
824             i_index_sample_used += i_used;
825             i_sample_count -= i_used;
826
827             p_demux_track->chunk[i_chunk].p_sample_count_dts[i] = i_used;
828
829             p_demux_track->chunk[i_chunk].p_sample_delta_dts[i] =
830                         p_stts->data.p_stts->i_sample_delta[i_index];
831
832             i_last_dts += i_used *
833                     p_demux_track->chunk[i_chunk].p_sample_delta_dts[i];
834
835             if( i_index_sample_used >=
836                              p_stts->data.p_stts->i_sample_count[i_index] )
837             {
838
839                 i_index++;
840                 i_index_sample_used = 0;
841             }
842         }
843
844     }
845
846     msg_Dbg( p_input,
847              "track[Id 0x%x] read %d samples length:"I64Fd"s",
848              p_demux_track->i_track_ID,
849              p_demux_track->i_sample_count,
850              i_last_dts / p_demux_track->i_timescale );
851
852     return( VLC_SUCCESS );
853 }
854
855 /*
856  * TrackCreateES:
857  *  Create ES and PES to init decoder if needed, for a track starting at i_chunk
858  */
859 static int  TrackCreateES   ( input_thread_t   *p_input,
860                               track_data_mp4_t *p_track,
861                               unsigned int     i_chunk,
862                               es_descriptor_t  **pp_es,
863                               pes_packet_t     **pp_pes )
864 {
865     MP4_Box_t *  p_sample;
866     unsigned int i;
867
868     unsigned int i_decoder_specific_info_len;
869     uint8_t *    p_decoder_specific_info;
870
871     es_descriptor_t *p_es;
872     pes_packet_t    *p_pes_init;
873
874     uint8_t             *p_init;
875     BITMAPINFOHEADER    *p_bih;
876     WAVEFORMATEX        *p_wf;
877
878     MP4_Box_t   *p_esds;
879
880     if( !p_track->chunk[i_chunk].i_sample_description_index )
881     {
882         msg_Warn( p_input,
883                   "invalid SampleEntry index (track[Id 0x%x])",
884                   p_track->i_track_ID );
885         return( VLC_EGENERIC );
886     }
887
888     p_sample = MP4_BoxGet(  p_track->p_stsd,
889                             "[%d]",
890                 p_track->chunk[i_chunk].i_sample_description_index - 1 );
891
892     if( !p_sample || !p_sample->data.p_data )
893     {
894         msg_Warn( p_input,
895                   "cannot find SampleEntry (track[Id 0x%x])",
896                   p_track->i_track_ID );
897         return( VLC_EGENERIC );
898     }
899
900     p_track->p_sample = p_sample;
901
902     if( p_track->i_sample_size == 1 )
903     {
904         MP4_Box_data_sample_soun_t *p_soun;
905
906         p_soun = p_sample->data.p_sample_soun;
907
908         if( p_soun->i_qt_version == 0 )
909         {
910             switch( p_sample->i_type )
911             {
912                 case VLC_FOURCC( 'i', 'm', 'a', '4' ):
913                     p_soun->i_qt_version = 1;
914                     p_soun->i_sample_per_packet = 64;
915                     p_soun->i_bytes_per_packet  = 34;
916                     p_soun->i_bytes_per_frame   = 34 * p_soun->i_channelcount;
917                     p_soun->i_bytes_per_sample  = 2;
918                     break;
919                 default:
920                     break;
921             }
922         }
923     }
924
925
926     vlc_mutex_lock( &p_input->stream.stream_lock );
927     p_es = input_AddES( p_input,
928                         p_input->stream.p_selected_program,
929                         p_track->i_track_ID,
930                         0 );
931     vlc_mutex_unlock( &p_input->stream.stream_lock );
932     /* Initialise ES, first language as description */
933     for( i = 0; i < 3; i++ )
934     {
935         p_es->psz_desc[i] = p_track->i_language[i];
936     }
937     p_es->psz_desc[3] = '\0';
938
939     p_es->i_stream_id = p_track->i_track_ID;
940
941     /* It's a little ugly but .. there are special cases */
942     switch( p_sample->i_type )
943     {
944         case( VLC_FOURCC( '.', 'm', 'p', '3' ) ):
945         case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ):
946             p_es->i_fourcc = VLC_FOURCC( 'm', 'p', 'g', 'a' );
947             break;
948         case( VLC_FOURCC( 'r', 'a', 'w', ' ' ) ):
949             p_es->i_fourcc = VLC_FOURCC( 'a', 'r', 'a', 'w' );
950             break;
951         default:
952             p_es->i_fourcc = p_sample->i_type;
953             break;
954     }
955
956     p_es->i_cat = p_track->i_cat;
957
958     i_decoder_specific_info_len = 0;
959     p_decoder_specific_info = NULL;
960     p_pes_init = NULL;
961
962     /* now see if esds is present and if so create a data packet
963         with decoder_specific_info  */
964 #define p_decconfig p_esds->data.p_esds->es_descriptor.p_decConfigDescr
965     if( ( p_esds = MP4_BoxGet( p_sample, "esds" ) )&&
966         ( p_esds->data.p_esds )&&
967         ( p_decconfig ) )
968     {
969         /* First update information based on i_objectTypeIndication */
970         switch( p_decconfig->i_objectTypeIndication )
971         {
972             case( 0x20 ): /* MPEG4 VIDEO */
973                 p_es->i_fourcc = VLC_FOURCC( 'm','p','4','v' );
974                 break;
975             case( 0x40):
976                 p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' );
977                 break;
978             case( 0x60):
979             case( 0x61):
980             case( 0x62):
981             case( 0x63):
982             case( 0x64):
983             case( 0x65): /* MPEG2 video */
984                 p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
985                 break;
986             /* Theses are MPEG2-AAC */
987             case( 0x66): /* main profile */
988             case( 0x67): /* Low complexity profile */
989             case( 0x68): /* Scaleable Sampling rate profile */
990                 p_es->i_fourcc = VLC_FOURCC( 'm','p','4','a' );
991                 break;
992             /* true MPEG 2 audio */
993             case( 0x69):
994                 p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
995                 break;
996             case( 0x6a): /* MPEG1 video */
997                 p_es->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
998                 break;
999             case( 0x6b): /* MPEG1 audio */
1000                 p_es->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
1001                 break;
1002             case( 0x6c ): /* jpeg */
1003                 p_es->i_fourcc = VLC_FOURCC( 'j','p','e','g' );
1004                 break;
1005             default:
1006                 /* Unknown entry, but don't touch i_fourcc */
1007                 msg_Warn( p_input,
1008                           "unknown objectTypeIndication(0x%x) (Track[ID 0x%x])",
1009                           p_decconfig->i_objectTypeIndication,
1010                           p_track->i_track_ID );
1011                 break;
1012         }
1013         i_decoder_specific_info_len =
1014                 p_decconfig->i_decoder_specific_info_len;
1015         p_decoder_specific_info =
1016                 p_decconfig->p_decoder_specific_info;
1017     }
1018     else
1019     {
1020         switch( p_sample->i_type )
1021         {
1022             /* qt decoder, send the complete chunk */
1023             case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
1024             case VLC_FOURCC( 'Z', 'y', 'G', 'o' ):
1025                 i_decoder_specific_info_len = p_sample->data.p_sample_vide->i_qt_image_description;
1026                 p_decoder_specific_info     = p_sample->data.p_sample_vide->p_qt_image_description;
1027                 break;
1028             case VLC_FOURCC( 'Q', 'D', 'M', 'C' ):
1029             case VLC_FOURCC( 'Q', 'D', 'M', '2' ):
1030             case VLC_FOURCC( 'Q', 'c', 'l', 'p' ):
1031                 i_decoder_specific_info_len = p_sample->data.p_sample_soun->i_qt_description;
1032                 p_decoder_specific_info     = p_sample->data.p_sample_soun->p_qt_description;
1033                 break;
1034             default:
1035                 break;
1036         }
1037     }
1038
1039 #undef p_decconfig
1040
1041     /* some last initialisation */
1042     /* XXX I create a bitmapinfoheader_t or
1043        waveformatex_t for each stream, up to now it's the best thing
1044        I've found but it could exist a better solution :) as something
1045        like adding some new fields in p_es ...
1046
1047        XXX I don't set all values, only thoses that are interesting or known
1048         --> bitmapinfoheader_t : width and height
1049         --> waveformatex_t : channels, samplerate, bitspersample
1050         and at the end I add p_decoder_specific_info
1051
1052         TODO set more values
1053
1054      */
1055
1056     switch( p_track->i_cat )
1057     {
1058         case( VIDEO_ES ):
1059             /* now create a bitmapinfoheader_t for decoder and
1060                add information found in p_esds */
1061             /* XXX XXX + 16 are for avoid segfault when ffmpeg access beyong the data */
1062             p_init = malloc( sizeof( BITMAPINFOHEADER ) + i_decoder_specific_info_len + 16 );
1063             p_bih = (BITMAPINFOHEADER*)p_init;
1064
1065             p_bih->biSize     = sizeof( BITMAPINFOHEADER ) + i_decoder_specific_info_len;
1066             p_bih->biWidth    = p_sample->data.p_sample_vide->i_width;
1067             p_bih->biHeight   = p_sample->data.p_sample_vide->i_height;
1068             p_bih->biPlanes   = 1;      // FIXME
1069             p_bih->biBitCount = 0;      // FIXME
1070             p_bih->biCompression   = 0; // FIXME
1071             p_bih->biSizeImage     = 0; // FIXME
1072             p_bih->biXPelsPerMeter = 0; // FIXME
1073             p_bih->biYPelsPerMeter = 0; // FIXME
1074             p_bih->biClrUsed       = 0; // FIXME
1075             p_bih->biClrImportant  = 0; // FIXME
1076
1077             if( p_bih->biWidth == 0 )
1078             {
1079                 // fall on display size
1080                 p_bih->biWidth = p_track->i_width;
1081             }
1082             if( p_bih->biHeight == 0 )
1083             {
1084                 // fall on display size
1085                 p_bih->biHeight = p_track->i_height;
1086             }
1087
1088             if( i_decoder_specific_info_len )
1089             {
1090                 data_packet_t   *p_data;
1091
1092                 memcpy( p_init + sizeof( BITMAPINFOHEADER ),
1093                         p_decoder_specific_info,
1094                         i_decoder_specific_info_len);
1095
1096                 /* If stream is mpeg4 video we send specific_info,
1097                    as it's needed to decode it (vol) */
1098                 switch( p_es->i_fourcc )
1099                 {
1100                     case VLC_FOURCC( 'm','p','4','v' ):
1101                     case VLC_FOURCC( 'D','I','V','X' ):
1102                     case VLC_FOURCC( 'd','i','v','x' ):
1103                         p_pes_init = input_NewPES( p_input->p_method_data );
1104                         p_data = input_NewPacket( p_input->p_method_data,
1105                                                   i_decoder_specific_info_len);
1106                         p_data->p_payload_end = p_data->p_payload_start + i_decoder_specific_info_len;
1107
1108                         memcpy( p_data->p_payload_start,
1109                                 p_decoder_specific_info,
1110                                 i_decoder_specific_info_len );
1111                         p_pes_init->i_dts = p_pes_init->i_pts = 0;
1112                         p_pes_init->p_first = p_pes_init->p_last = p_data;
1113                         p_pes_init->i_nb_data = 1;
1114                         p_pes_init->i_pes_size = i_decoder_specific_info_len;
1115                         break;
1116                     default:
1117                         break;
1118                 }
1119
1120             }
1121             break;
1122
1123         case( AUDIO_ES ):
1124             p_init = malloc( sizeof( WAVEFORMATEX ) + i_decoder_specific_info_len + 16 );
1125             p_wf = (WAVEFORMATEX*)p_init;
1126
1127             p_wf->wFormatTag = 1;
1128             p_wf->nChannels = p_sample->data.p_sample_soun->i_channelcount;
1129             p_wf->nSamplesPerSec = p_sample->data.p_sample_soun->i_sampleratehi;
1130             p_wf->nAvgBytesPerSec = p_sample->data.p_sample_soun->i_channelcount *
1131                                     p_sample->data.p_sample_soun->i_sampleratehi *
1132                                     p_sample->data.p_sample_soun->i_samplesize / 8;
1133             p_wf->nBlockAlign = 0;
1134             p_wf->wBitsPerSample = p_sample->data.p_sample_soun->i_samplesize;
1135             p_wf->cbSize = i_decoder_specific_info_len;
1136
1137             if( i_decoder_specific_info_len )
1138             {
1139                 memcpy( p_init + sizeof( WAVEFORMATEX ),
1140                         p_decoder_specific_info,
1141                         i_decoder_specific_info_len);
1142             }
1143
1144             break;
1145
1146         default:
1147             p_init = NULL;
1148             break;
1149     }
1150     if( p_es->i_cat == AUDIO_ES )
1151     {
1152         p_es->p_bitmapinfoheader = NULL;
1153         p_es->p_waveformatex     = (void*)p_init;
1154     }
1155     else if( p_es->i_cat == VIDEO_ES )
1156     {
1157         p_es->p_bitmapinfoheader = (void*)p_init;
1158         p_es->p_waveformatex     = NULL;
1159     }
1160
1161     *pp_es = p_es;
1162     *pp_pes = p_pes_init;
1163     return( VLC_SUCCESS );
1164 }
1165
1166 /* given a time it return sample/chunk */
1167 static int  TrackTimeToSampleChunk( input_thread_t *p_input,
1168                                     track_data_mp4_t *p_track,
1169                                     uint64_t i_start,
1170                                     uint32_t *pi_chunk,
1171                                     uint32_t *pi_sample )
1172 {
1173     MP4_Box_t    *p_stss;
1174     uint64_t     i_dts;
1175     unsigned int i_sample;
1176     unsigned int i_chunk;
1177     int          i_index;
1178
1179     /* convert absolute time to in timescale unit */
1180     i_start = i_start * (mtime_t)p_track->i_timescale / (mtime_t)1000000;
1181
1182     /* FIXME see if it's needed to check p_track->i_chunk_count */
1183     if( !p_track->b_ok || p_track->i_chunk_count == 0 )
1184     {
1185         return( VLC_EGENERIC );
1186     }
1187
1188     /* we start from sample 0/chunk 0, hope it won't take too much time */
1189     /* *** find good chunk *** */
1190     for( i_chunk = 0; ; i_chunk++ )
1191     {
1192         if( i_chunk + 1 >= p_track->i_chunk_count )
1193         {
1194             /* at the end and can't check if i_start in this chunk,
1195                it will be check while searching i_sample */
1196             i_chunk = p_track->i_chunk_count - 1;
1197             break;
1198         }
1199
1200         if( i_start >= p_track->chunk[i_chunk].i_first_dts &&
1201             i_start <  p_track->chunk[i_chunk + 1].i_first_dts )
1202         {
1203             break;
1204         }
1205     }
1206
1207     /* *** find sample in the chunk *** */
1208     i_sample = p_track->chunk[i_chunk].i_sample_first;
1209     i_dts    = p_track->chunk[i_chunk].i_first_dts;
1210     for( i_index = 0; i_sample < p_track->chunk[i_chunk].i_sample_count; )
1211     {
1212         if( i_dts +
1213             p_track->chunk[i_chunk].p_sample_count_dts[i_index] *
1214             p_track->chunk[i_chunk].p_sample_delta_dts[i_index] < i_start )
1215         {
1216             i_dts    +=
1217                 p_track->chunk[i_chunk].p_sample_count_dts[i_index] *
1218                 p_track->chunk[i_chunk].p_sample_delta_dts[i_index];
1219
1220             i_sample += p_track->chunk[i_chunk].p_sample_count_dts[i_index];
1221             i_index++;
1222         }
1223         else
1224         {
1225             if( p_track->chunk[i_chunk].p_sample_delta_dts[i_index] <= 0 )
1226             {
1227                 break;
1228             }
1229             i_sample += ( i_start - i_dts ) / p_track->chunk[i_chunk].p_sample_delta_dts[i_index];
1230             break;
1231         }
1232     }
1233
1234     if( i_sample >= p_track->i_sample_count )
1235     {
1236         msg_Warn( p_input,
1237                   "track[Id 0x%x] will be disabled (seeking too far) chunk=%d sample=%d",
1238                   p_track->i_track_ID, i_chunk, i_sample );
1239         return( VLC_EGENERIC );
1240     }
1241
1242
1243     /* *** Try to find nearest sync points *** */
1244     if( ( p_stss = MP4_BoxGet( p_track->p_stbl, "stss" ) ) )
1245     {
1246         unsigned int i_index;
1247         msg_Dbg( p_input,
1248                     "track[Id 0x%x] using Sync Sample Box (stss)",
1249                     p_track->i_track_ID );
1250         for( i_index = 0; i_index < p_stss->data.p_stss->i_entry_count; i_index++ )
1251         {
1252             if( p_stss->data.p_stss->i_sample_number[i_index] >= i_sample )
1253             {
1254                 if( i_index > 0 )
1255                 {
1256                     msg_Dbg( p_input, "stts gives %d --> %d (sample number)",
1257                             i_sample,
1258                             p_stss->data.p_stss->i_sample_number[i_index-1] );
1259                     i_sample = p_stss->data.p_stss->i_sample_number[i_index-1];
1260                     /* new i_sample is less than old so i_chunk can only decreased */
1261                     while( i_chunk > 0 &&
1262                             i_sample < p_track->chunk[i_chunk].i_sample_first )
1263                     {
1264                         i_chunk--;
1265                     }
1266                 }
1267                 else
1268                 {
1269                     msg_Dbg( p_input, "stts gives %d --> %d (sample number)",
1270                             i_sample,
1271                             p_stss->data.p_stss->i_sample_number[i_index] );
1272                     i_sample = p_stss->data.p_stss->i_sample_number[i_index];
1273                     /* new i_sample is more than old so i_chunk can only increased */
1274                     while( i_chunk < p_track->i_chunk_count - 1 &&
1275                            i_sample >= p_track->chunk[i_chunk].i_sample_first +
1276                                                 p_track->chunk[i_chunk].i_sample_count )
1277                     {
1278                         i_chunk++;
1279                     }
1280                 }
1281                 break;
1282             }
1283         }
1284     }
1285     else
1286     {
1287         msg_Dbg( p_input,
1288                     "track[Id 0x%x] does not provide Sync Sample Box (stss)",
1289                     p_track->i_track_ID );
1290     }
1291
1292     if( pi_chunk  ) *pi_chunk  = i_chunk;
1293     if( pi_sample ) *pi_sample = i_sample;
1294     return( VLC_SUCCESS );
1295 }
1296
1297 static int  TrackGotoChunkSample( input_thread_t   *p_input,
1298                                   track_data_mp4_t *p_track,
1299                                   unsigned int     i_chunk,
1300                                   unsigned int     i_sample )
1301 {
1302     /* now see if actual es is ok */
1303     if( p_track->i_chunk < 0 ||
1304         p_track->i_chunk >= p_track->i_chunk_count ||
1305         p_track->chunk[p_track->i_chunk].i_sample_description_index !=
1306             p_track->chunk[i_chunk].i_sample_description_index )
1307     {
1308         msg_Warn( p_input, "Recreate ES" );
1309
1310         /* no :( recreate es */
1311         vlc_mutex_lock( &p_input->stream.stream_lock );
1312         input_DelES( p_input, p_track->p_es );
1313         vlc_mutex_unlock( &p_input->stream.stream_lock );
1314
1315         if( p_track->p_pes_init )
1316         {
1317             input_DeletePES( p_input->p_method_data, p_track->p_pes_init );
1318         }
1319
1320         if( TrackCreateES( p_input,
1321                            p_track, i_chunk,
1322                            &p_track->p_es,
1323                            &p_track->p_pes_init ) )
1324         {
1325             msg_Err( p_input, "cannot create es for track[Id 0x%x]",
1326                      p_track->i_track_ID );
1327
1328             p_track->b_ok       = VLC_FALSE;
1329             p_track->b_selected = VLC_FALSE;
1330             return( VLC_EGENERIC );
1331         }
1332     }
1333
1334     /* select again the new decoder */
1335     if( p_track->b_selected && p_track->p_es && p_track->p_es->p_decoder_fifo == NULL )
1336     {
1337         vlc_mutex_lock( &p_input->stream.stream_lock );
1338         input_SelectES( p_input, p_track->p_es );
1339         vlc_mutex_unlock( &p_input->stream.stream_lock );
1340
1341         if( p_track->p_es->p_decoder_fifo )
1342         {
1343             if( p_track->p_pes_init != NULL )
1344             {
1345                 input_DecodePES( p_track->p_es->p_decoder_fifo, p_track->p_pes_init );
1346                 p_track->p_pes_init = NULL;
1347             }
1348             p_track->b_selected = VLC_TRUE;
1349         }
1350         else
1351         {
1352             msg_Dbg( p_input, "Argg cannot select this stream" );
1353             if( p_track->p_pes_init != NULL )
1354             {
1355                 input_DeletePES( p_input->p_method_data, p_track->p_pes_init );
1356                 p_track->p_pes_init = NULL;
1357             }
1358             p_track->b_selected = VLC_FALSE;
1359         }
1360     }
1361
1362     p_track->i_chunk    = i_chunk;
1363     p_track->i_sample   = i_sample;
1364
1365     return( VLC_SUCCESS );
1366 }
1367
1368 /****************************************************************************
1369  * MP4_TrackCreate:
1370  ****************************************************************************
1371  * Parse track information and create all needed data to run a track
1372  * If it succeed b_ok is set to 1 else to 0
1373  ****************************************************************************/
1374 static void MP4_TrackCreate( input_thread_t *p_input,
1375                              track_data_mp4_t *p_track,
1376                              MP4_Box_t  * p_box_trak )
1377 {
1378     unsigned int i;
1379
1380     MP4_Box_t *p_tkhd = MP4_BoxGet( p_box_trak, "tkhd" );
1381     MP4_Box_t *p_tref = MP4_BoxGet( p_box_trak, "tref" );
1382     MP4_Box_t *p_elst;
1383
1384     MP4_Box_t *p_mdhd;
1385     MP4_Box_t *p_hdlr;
1386
1387     MP4_Box_t *p_vmhd;
1388     MP4_Box_t *p_smhd;
1389
1390     /* hint track unsuported */
1391
1392     /* set default value (-> track unusable) */
1393     p_track->b_ok       = VLC_FALSE;
1394     p_track->b_enable   = VLC_FALSE;
1395     p_track->b_selected = VLC_FALSE;
1396
1397     p_track->i_cat = UNKNOWN_ES;
1398
1399     if( !p_tkhd )
1400     {
1401         return;
1402     }
1403
1404     /* do we launch this track by default ? */
1405     p_track->b_enable =
1406         ( ( p_tkhd->data.p_tkhd->i_flags&MP4_TRACK_ENABLED ) != 0 );
1407
1408     p_track->i_track_ID = p_tkhd->data.p_tkhd->i_track_ID;
1409     p_track->i_width = p_tkhd->data.p_tkhd->i_width / 65536;
1410     p_track->i_height = p_tkhd->data.p_tkhd->i_height / 65536;
1411
1412     if( ( p_elst = MP4_BoxGet( p_box_trak, "edts/elst" ) ) )
1413     {
1414 /*        msg_Warn( p_input, "unhandled box: edts --> FIXME" ); */
1415     }
1416
1417     if( p_tref )
1418     {
1419 /*        msg_Warn( p_input, "unhandled box: tref --> FIXME" ); */
1420     }
1421
1422     p_mdhd = MP4_BoxGet( p_box_trak, "mdia/mdhd" );
1423     p_hdlr = MP4_BoxGet( p_box_trak, "mdia/hdlr" );
1424
1425     if( ( !p_mdhd )||( !p_hdlr ) )
1426     {
1427         return;
1428     }
1429
1430     p_track->i_timescale = p_mdhd->data.p_mdhd->i_timescale;
1431
1432     for( i = 0; i < 3; i++ )
1433     {
1434         p_track->i_language[i] = p_mdhd->data.p_mdhd->i_language[i];
1435     }
1436     p_mdhd->data.p_mdhd->i_language[3] = 0;
1437
1438     switch( p_hdlr->data.p_hdlr->i_handler_type )
1439     {
1440         case( FOURCC_soun ):
1441             if( !( p_smhd = MP4_BoxGet( p_box_trak, "mdia/minf/smhd" ) ) )
1442             {
1443                 return;
1444             }
1445             p_track->i_cat = AUDIO_ES;
1446             break;
1447
1448         case( FOURCC_vide ):
1449             if( !( p_vmhd = MP4_BoxGet( p_box_trak, "mdia/minf/vmhd" ) ) )
1450             {
1451                 return;
1452             }
1453             p_track->i_cat = VIDEO_ES;
1454             break;
1455
1456         default:
1457             return;
1458     }
1459 /*  TODO
1460     add support for:
1461     p_dinf = MP4_BoxGet( p_minf, "dinf" );
1462 */
1463     if( !( p_track->p_stbl = MP4_BoxGet( p_box_trak,"mdia/minf/stbl" ) ) )
1464     {
1465         return;
1466     }
1467
1468     if( !( p_track->p_stsd = MP4_BoxGet( p_box_trak,"mdia/minf/stbl/stsd") ) )
1469     {
1470         return;
1471     }
1472
1473     /* Create chunk  index table */
1474     if( TrackCreateChunksIndex( p_input,p_track  ) )
1475     {
1476         return; /* cannot create chunks index */
1477     }
1478
1479     /* create sample index table needed for reading and seeking */
1480     if( TrackCreateSamplesIndex( p_input, p_track ) )
1481     {
1482         return; /* cannot create samples index */
1483     }
1484
1485     p_track->i_chunk  = 0;
1486     p_track->i_sample = 0;
1487     /* now create es but does not select it */
1488     /* XXX needed else vlc won't know this track exist */
1489     if( TrackCreateES( p_input,
1490                        p_track, p_track->i_chunk,
1491                        &p_track->p_es,
1492                        &p_track->p_pes_init ) )
1493     {
1494         msg_Err( p_input, "cannot create es for track[Id 0x%x]",
1495                  p_track->i_track_ID );
1496         return;
1497     }
1498 #if 0
1499     {
1500         int i;
1501
1502         for( i = 0; i < p_track->i_chunk_count; i++ )
1503         {
1504             fprintf( stderr, "%-5d sample_count=%d pts=%lld\n", i, p_track->chunk[i].i_sample_count, p_track->chunk[i].i_first_dts );
1505
1506         }
1507     }
1508 #endif
1509     p_track->b_ok = VLC_TRUE;
1510 }
1511
1512 /****************************************************************************
1513  * MP4_TrackDestroy:
1514  ****************************************************************************
1515  * Destroy a track created by MP4_TrackCreate.
1516  ****************************************************************************/
1517 static void MP4_TrackDestroy( input_thread_t *p_input,
1518                               track_data_mp4_t *p_track )
1519 {
1520     unsigned int i_chunk;
1521
1522     p_track->b_ok = VLC_FALSE;
1523     p_track->b_enable   = VLC_FALSE;
1524     p_track->b_selected = VLC_FALSE;
1525
1526     p_track->i_cat = UNKNOWN_ES;
1527
1528     if( p_track->p_pes_init )
1529     {
1530         input_DeletePES( p_input->p_method_data, p_track->p_pes_init );
1531     }
1532
1533     for( i_chunk = 0; i_chunk < p_track->i_chunk_count; i_chunk++ )
1534     {
1535         if( p_track->chunk )
1536         {
1537            FREE(p_track->chunk[i_chunk].p_sample_count_dts);
1538            FREE(p_track->chunk[i_chunk].p_sample_delta_dts );
1539         }
1540     }
1541     FREE( p_track->chunk );
1542
1543     if( !p_track->i_sample_size )
1544     {
1545         FREE( p_track->p_sample_size );
1546     }
1547 }
1548
1549 static int  MP4_TrackSelect ( input_thread_t    *p_input,
1550                               track_data_mp4_t  *p_track,
1551                               mtime_t           i_start )
1552 {
1553     uint32_t i_chunk;
1554     uint32_t i_sample;
1555
1556     if( !p_track->b_ok )
1557     {
1558         return( VLC_EGENERIC );
1559     }
1560
1561     if( p_track->b_selected )
1562     {
1563         msg_Warn( p_input,
1564                   "track[Id 0x%x] already selected",
1565                   p_track->i_track_ID );
1566         return( VLC_SUCCESS );
1567     }
1568
1569     if( TrackTimeToSampleChunk( p_input,
1570                                 p_track, i_start,
1571                                 &i_chunk, &i_sample ) )
1572     {
1573         msg_Warn( p_input,
1574                   "cannot select track[Id 0x%x]",
1575                   p_track->i_track_ID );
1576         return( VLC_EGENERIC );
1577     }
1578
1579     p_track->b_selected = VLC_TRUE;
1580
1581     if( TrackGotoChunkSample( p_input, p_track, i_chunk, i_sample ) )
1582     {
1583         p_track->b_selected = VLC_FALSE;
1584     }
1585
1586     return( p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC );
1587 }
1588
1589 static void MP4_TrackUnselect(input_thread_t    *p_input,
1590                               track_data_mp4_t  *p_track )
1591 {
1592     if( !p_track->b_ok )
1593     {
1594         return;
1595     }
1596
1597     if( !p_track->b_selected )
1598     {
1599         msg_Warn( p_input,
1600                   "track[Id 0x%x] already unselected",
1601                   p_track->i_track_ID );
1602         return;
1603     }
1604
1605     if( p_track->p_es->p_decoder_fifo )
1606     {
1607         vlc_mutex_lock( &p_input->stream.stream_lock );
1608         input_UnselectES( p_input, p_track->p_es );
1609         vlc_mutex_unlock( &p_input->stream.stream_lock );
1610     }
1611
1612     p_track->b_selected = VLC_FALSE;
1613 }
1614
1615 static int  MP4_TrackSeek   ( input_thread_t    *p_input,
1616                               track_data_mp4_t  *p_track,
1617                               mtime_t           i_start )
1618 {
1619     uint32_t i_chunk;
1620     uint32_t i_sample;
1621
1622     if( !p_track->b_ok )
1623     {
1624         return( VLC_EGENERIC );
1625     }
1626
1627     if( TrackTimeToSampleChunk( p_input,
1628                                 p_track, i_start,
1629                                 &i_chunk, &i_sample ) )
1630     {
1631         msg_Warn( p_input,
1632                   "cannot select track[Id 0x%x]",
1633                   p_track->i_track_ID );
1634         return( VLC_EGENERIC );
1635     }
1636
1637     p_track->b_selected = VLC_TRUE;
1638
1639     TrackGotoChunkSample( p_input, p_track, i_chunk, i_sample );
1640
1641     return( p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC );
1642 }
1643
1644
1645
1646
1647
1648 /*
1649  * 3 types: for audio
1650  * 
1651  */
1652
1653 static int  MP4_TrackSampleSize( track_data_mp4_t   *p_track )
1654 {
1655     int i_size;
1656     MP4_Box_data_sample_soun_t *p_soun;
1657
1658     if( p_track->i_sample_size == 0 )
1659     {
1660         /* most simple case */
1661         return( p_track->p_sample_size[p_track->i_sample] );
1662     }
1663     if( p_track->i_cat != AUDIO_ES )
1664     {
1665         return( p_track->i_sample_size );
1666     }
1667
1668     if( p_track->i_sample_size != 1 )
1669     {
1670         //msg_Warn( p_input, "SampleSize != 1" );
1671         return( p_track->i_sample_size );
1672     }
1673
1674     p_soun = p_track->p_sample->data.p_sample_soun;
1675
1676     if( p_soun->i_qt_version == 1 )
1677     {
1678         i_size = p_track->chunk[p_track->i_chunk].i_sample_count / p_soun->i_sample_per_packet * p_soun->i_bytes_per_frame;
1679     }
1680     else
1681     {
1682         //msg_Warn( p_input, "i_qt_version == 0" );
1683         /* FIXME */
1684
1685         i_size = p_track->chunk[p_track->i_chunk].i_sample_count * p_soun->i_channelcount * p_soun->i_samplesize / 8;
1686     }
1687
1688     //fprintf( stderr, "size=%d\n", i_size );
1689     return( i_size );
1690 }
1691
1692
1693 static uint64_t MP4_GetTrackPos( track_data_mp4_t *p_track )
1694 {
1695     unsigned int i_sample;
1696     uint64_t i_pos;
1697
1698
1699     i_pos = p_track->chunk[p_track->i_chunk].i_offset;
1700
1701     if( p_track->i_sample_size )
1702     {
1703 #if 0
1704         i_pos += ( p_track->i_sample -
1705                         p_track->chunk[p_track->i_chunk].i_sample_first ) *
1706                                 MP4_TrackSampleSize( p_track );
1707 #endif
1708         /* we read chunk by chunk */
1709         i_pos += 0;
1710     }
1711     else
1712     {
1713         for( i_sample = p_track->chunk[p_track->i_chunk].i_sample_first;
1714                 i_sample < p_track->i_sample; i_sample++ )
1715         {
1716             i_pos += p_track->p_sample_size[i_sample];
1717         }
1718
1719     }
1720     return( i_pos );
1721 }
1722
1723 static int  MP4_TrackNextSample( input_thread_t     *p_input,
1724                                  track_data_mp4_t   *p_track )
1725 {
1726
1727     if( p_track->i_cat == AUDIO_ES &&
1728         p_track->i_sample_size != 0 )
1729     {
1730         MP4_Box_data_sample_soun_t *p_soun;
1731
1732         p_soun = p_track->p_sample->data.p_sample_soun;
1733
1734         if( p_soun->i_qt_version == 1 )
1735         {
1736             /* chunk by chunk */
1737             p_track->i_sample =
1738                 p_track->chunk[p_track->i_chunk].i_sample_first +
1739                 p_track->chunk[p_track->i_chunk].i_sample_count;
1740         }
1741         else
1742         {
1743             /* FIXME */
1744             p_track->i_sample =
1745                 p_track->chunk[p_track->i_chunk].i_sample_first +
1746                 p_track->chunk[p_track->i_chunk].i_sample_count;
1747         }
1748     }
1749     else
1750     {
1751         p_track->i_sample++;
1752     }
1753
1754     if( p_track->i_sample >= p_track->i_sample_count )
1755     {
1756         /* we have reach end of the track so free decoder stuff */
1757         msg_Warn( p_input, "track[0x%x] will be disabled", p_track->i_track_ID );
1758         MP4_TrackUnselect( p_input, p_track );
1759         return( VLC_EGENERIC );
1760     }
1761
1762     /* Have we changed chunk ? */
1763     if( p_track->i_sample >=
1764             p_track->chunk[p_track->i_chunk].i_sample_first +
1765             p_track->chunk[p_track->i_chunk].i_sample_count )
1766     {
1767         if( TrackGotoChunkSample( p_input,
1768                                   p_track,
1769                                   p_track->i_chunk + 1,
1770                                   p_track->i_sample ) )
1771         {
1772             msg_Warn( p_input, "track[0x%x] will be disabled (cannot restart decoder)", p_track->i_track_ID );
1773             MP4_TrackUnselect( p_input, p_track );
1774             return( VLC_EGENERIC );
1775         }
1776     }
1777
1778     return( VLC_SUCCESS );
1779 }
1780
1781