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