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