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