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