Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

mp4.c

00001 /*****************************************************************************
00002  * mp4.c : MP4 file input module for vlc
00003  *****************************************************************************
00004  * Copyright (C) 2001-2004 the VideoLAN team
00005  * $Id: mp4.c 13473 2005-11-30 19:34:35Z dionoea $
00006  * Authors: Laurent Aimar <[email protected]>
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00021  *****************************************************************************/
00022 
00023 /*****************************************************************************
00024  * Preamble
00025  *****************************************************************************/
00026 #include <stdlib.h>                                      /* malloc(), free() */
00027 
00028 #include <vlc/vlc.h>
00029 #include <vlc/input.h>
00030 #include <vlc_playlist.h>
00031 #include <vlc_md5.h>
00032 #include "iso_lang.h"
00033 #include "vlc_meta.h"
00034 
00035 #include "libmp4.h"
00036 #include "drms.h"
00037 
00038 #ifdef UNDER_CE
00039 #define uint64_t int64_t
00040 #endif
00041 
00042 /*****************************************************************************
00043  * Module descriptor
00044  *****************************************************************************/
00045 static int  Open ( vlc_object_t * );
00046 static void Close( vlc_object_t * );
00047 
00048 vlc_module_begin();
00049     set_category( CAT_INPUT );
00050     set_subcategory( SUBCAT_INPUT_DEMUX );
00051     set_description( _("MP4 stream demuxer") );
00052     set_capability( "demux2", 242 );
00053     set_callbacks( Open, Close );
00054 vlc_module_end();
00055 
00056 /*****************************************************************************
00057  * Local prototypes
00058  *****************************************************************************/
00059 static int   Demux   ( demux_t * );
00060 static int   DemuxRef( demux_t *p_demux ){ return 0;}
00061 static int   Seek    ( demux_t *, mtime_t );
00062 static int   Control ( demux_t *, int, va_list );
00063 
00064 /* Contain all information about a chunk */
00065 typedef struct
00066 {
00067     uint64_t     i_offset; /* absolute position of this chunk in the file */
00068     uint32_t     i_sample_description_index; /* index for SampleEntry to use */
00069     uint32_t     i_sample_count; /* how many samples in this chunk */
00070     uint32_t     i_sample_first; /* index of the first sample in this chunk */
00071 
00072     /* now provide way to calculate pts, dts, and offset without to
00073         much memory and with fast acces */
00074 
00075     /* with this we can calculate dts/pts without waste memory */
00076     uint64_t     i_first_dts;
00077     uint32_t     *p_sample_count_dts;
00078     uint32_t     *p_sample_delta_dts;   /* dts delta */
00079 
00080     uint32_t     *p_sample_count_pts;
00081     int32_t      *p_sample_offset_pts;  /* pts-dts */
00082 
00083     /* TODO if needed add pts
00084         but quickly *add* support for edts and seeking */
00085 
00086 } mp4_chunk_t;
00087 
00088  /* Contain all needed information for read all track with vlc */
00089 typedef struct
00090 {
00091     int i_track_ID;     /* this should be unique */
00092 
00093     int b_ok;           /* The track is usable */
00094     int b_enable;       /* is the trak enable by default */
00095     vlc_bool_t b_selected;     /* is the trak being played */
00096 
00097     es_format_t fmt;
00098     es_out_id_t *p_es;
00099 
00100     /* display size only ! */
00101     int i_width;
00102     int i_height;
00103 
00104     /* more internal data */
00105     uint64_t        i_timescale;    /* time scale for this track only */
00106 
00107     /* elst */
00108     int             i_elst;         /* current elst */
00109     int64_t         i_elst_time;    /* current elst start time (in movie time scale)*/
00110     MP4_Box_t       *p_elst;        /* elst (could be NULL) */
00111 
00112     /* give the next sample to read, i_chunk is to find quickly where
00113       the sample is located */
00114     uint32_t         i_sample;       /* next sample to read */
00115     uint32_t         i_chunk;        /* chunk where next sample is stored */
00116     /* total count of chunk and sample */
00117     uint32_t         i_chunk_count;
00118     uint32_t         i_sample_count;
00119 
00120     mp4_chunk_t    *chunk; /* always defined  for each chunk */
00121 
00122     /* sample size, p_sample_size defined only if i_sample_size == 0
00123         else i_sample_size is size for all sample */
00124     uint32_t         i_sample_size;
00125     uint32_t         *p_sample_size; /* XXX perhaps add file offset if take
00126                                     too much time to do sumations each time*/
00127 
00128     MP4_Box_t *p_stbl;  /* will contain all timing information */
00129     MP4_Box_t *p_stsd;  /* will contain all data to initialize decoder */
00130     MP4_Box_t *p_sample;/* point on actual sdsd */
00131 
00132     vlc_bool_t b_drms;
00133     void      *p_drms;
00134 
00135 } mp4_track_t;
00136 
00137 
00138 struct demux_sys_t
00139 {
00140     MP4_Box_t    *p_root;      /* container for the whole file */
00141 
00142     mtime_t      i_pcr;
00143 
00144     uint64_t     i_time;        /* time position of the presentation
00145                                  * in movie timescale */
00146     uint64_t     i_timescale;   /* movie time scale */
00147     uint64_t     i_duration;    /* movie duration */
00148     unsigned int i_tracks;      /* number of tracks */
00149     mp4_track_t *track;    /* array of track */
00150 };
00151 
00152 /*****************************************************************************
00153  * Declaration of local function
00154  *****************************************************************************/
00155 static void MP4_TrackCreate ( demux_t *, mp4_track_t *, MP4_Box_t  *);
00156 static void MP4_TrackDestroy( demux_t *, mp4_track_t * );
00157 
00158 static int  MP4_TrackSelect ( demux_t *, mp4_track_t *, mtime_t );
00159 static void MP4_TrackUnselect(demux_t *, mp4_track_t * );
00160 
00161 static int  MP4_TrackSeek   ( demux_t *, mp4_track_t *, mtime_t );
00162 
00163 static uint64_t MP4_TrackGetPos    ( mp4_track_t * );
00164 static int      MP4_TrackSampleSize( mp4_track_t * );
00165 static int      MP4_TrackNextSample( demux_t *, mp4_track_t * );
00166 static void     MP4_TrackSetELST( demux_t *, mp4_track_t *, int64_t );
00167 
00168 /* Return time in s of a track */
00169 static inline int64_t MP4_TrackGetDTS( demux_t *p_demux, mp4_track_t *p_track )
00170 {
00171 #define chunk p_track->chunk[p_track->i_chunk]
00172 
00173     unsigned int i_index = 0;
00174     unsigned int i_sample = p_track->i_sample - chunk.i_sample_first;
00175     int64_t i_dts = chunk.i_first_dts;
00176 
00177     while( i_sample > 0 )
00178     {
00179         if( i_sample > chunk.p_sample_count_dts[i_index] )
00180         {
00181             i_dts += chunk.p_sample_count_dts[i_index] *
00182                 chunk.p_sample_delta_dts[i_index];
00183             i_sample -= chunk.p_sample_count_dts[i_index];
00184             i_index++;
00185         }
00186         else
00187         {
00188             i_dts += i_sample * chunk.p_sample_delta_dts[i_index];
00189             i_sample = 0;
00190             break;
00191         }
00192     }
00193 
00194 #undef chunk
00195 
00196     /* now handle elst */
00197     if( p_track->p_elst )
00198     {
00199         demux_sys_t         *p_sys = p_demux->p_sys;
00200         MP4_Box_data_elst_t *elst = p_track->p_elst->data.p_elst;
00201 
00202         /* convert to offset */
00203         if( ( elst->i_media_rate_integer[p_track->i_elst] > 0 ||
00204               elst->i_media_rate_fraction[p_track->i_elst] > 0 ) &&
00205             elst->i_media_time[p_track->i_elst] > 0 )
00206         {
00207             i_dts -= elst->i_media_time[p_track->i_elst];
00208         }
00209 
00210         /* add i_elst_time */
00211         i_dts += p_track->i_elst_time * p_track->i_timescale /
00212             p_sys->i_timescale;
00213 
00214         if( i_dts < 0 ) i_dts = 0;
00215     }
00216 
00217     return I64C(1000000) * i_dts / p_track->i_timescale;
00218 }
00219 
00220 static inline int64_t MP4_TrackGetPTSDelta( demux_t *p_demux, mp4_track_t *p_track )
00221 {
00222     mp4_chunk_t *ck = &p_track->chunk[p_track->i_chunk];
00223     unsigned int i_index = 0;
00224     unsigned int i_sample = p_track->i_sample - ck->i_sample_first;
00225 
00226     if( ck->p_sample_count_pts == NULL || ck->p_sample_offset_pts == NULL )
00227         return -1;
00228 
00229     for( i_index = 0;; i_index++ )
00230     {
00231         if( i_sample < ck->p_sample_count_pts[i_index] )
00232             return ck->p_sample_offset_pts[i_index] * I64C(1000000) /
00233                    (int64_t)p_track->i_timescale;
00234 
00235         i_sample -= ck->p_sample_count_pts[i_index];
00236     }
00237 }
00238 
00239 static inline int64_t MP4_GetMoviePTS(demux_sys_t *p_sys )
00240 {
00241     return I64C(1000000) * p_sys->i_time / p_sys->i_timescale;
00242 }
00243 
00244 #define FREE( p ) if( p ) { free( p ); (p) = NULL;}
00245 
00246 /*****************************************************************************
00247  * Open: check file and initializes MP4 structures
00248  *****************************************************************************/
00249 static int Open( vlc_object_t * p_this )
00250 {
00251     demux_t  *p_demux = (demux_t *)p_this;
00252     demux_sys_t     *p_sys;
00253 
00254     uint8_t         *p_peek;
00255 
00256     MP4_Box_t       *p_ftyp;
00257     MP4_Box_t       *p_rmra;
00258     MP4_Box_t       *p_mvhd;
00259     MP4_Box_t       *p_trak;
00260 
00261     unsigned int    i;
00262     vlc_bool_t      b_seekable;
00263 
00264     /* A little test to see if it could be a mp4 */
00265     if( stream_Peek( p_demux->s, &p_peek, 8 ) < 8 ) return VLC_EGENERIC;
00266 
00267     switch( VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] ) )
00268     {
00269         case FOURCC_ftyp:
00270         case FOURCC_moov:
00271         case FOURCC_foov:
00272         case FOURCC_moof:
00273         case FOURCC_mdat:
00274         case FOURCC_udta:
00275         case FOURCC_free:
00276         case FOURCC_skip:
00277         case FOURCC_wide:
00278         case VLC_FOURCC( 'p', 'n', 'o', 't' ):
00279             break;
00280          default:
00281             return VLC_EGENERIC;
00282     }
00283 
00284     /* I need to seek */
00285     stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_seekable );
00286     if( !b_seekable )
00287     {
00288         msg_Warn( p_demux, "MP4 plugin discarded (unseekable)" );
00289         return VLC_EGENERIC;
00290     }
00291 
00292     /*Set exported functions */
00293     p_demux->pf_demux = Demux;
00294     p_demux->pf_control = Control;
00295 
00296     /* create our structure that will contains all data */
00297     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
00298     memset( p_sys, 0, sizeof( demux_sys_t ) );
00299 
00300     /* Now load all boxes ( except raw data ) */
00301     if( ( p_sys->p_root = MP4_BoxGetRoot( p_demux->s ) ) == NULL )
00302     {
00303         msg_Warn( p_demux, "MP4 plugin discarded (not a valid file)" );
00304         goto error;
00305     }
00306 
00307     MP4_BoxDumpStructure( p_demux->s, p_sys->p_root );
00308 
00309     if( ( p_ftyp = MP4_BoxGet( p_sys->p_root, "/ftyp" ) ) )
00310     {
00311         switch( p_ftyp->data.p_ftyp->i_major_brand )
00312         {
00313             case( FOURCC_isom ):
00314                 msg_Dbg( p_demux,
00315                          "ISO Media file (isom) version %d.",
00316                          p_ftyp->data.p_ftyp->i_minor_version );
00317                 break;
00318             default:
00319                 msg_Dbg( p_demux,
00320                          "unrecognized major file specification (%4.4s).",
00321                           (char*)&p_ftyp->data.p_ftyp->i_major_brand );
00322                 break;
00323         }
00324     }
00325     else
00326     {
00327         msg_Dbg( p_demux, "file type box missing (assuming ISO Media file)" );
00328     }
00329 
00330     /* the file need to have one moov box */
00331     if( MP4_BoxCount( p_sys->p_root, "/moov" ) <= 0 )
00332     {
00333         MP4_Box_t *p_foov = MP4_BoxGet( p_sys->p_root, "/foov" );
00334 
00335         if( !p_foov )
00336         {
00337             msg_Err( p_demux, "MP4 plugin discarded (no moov box)" );
00338             goto error;
00339         }
00340         /* we have a free box as a moov, rename it */
00341         p_foov->i_type = FOURCC_moov;
00342     }
00343 
00344     if( ( p_rmra = MP4_BoxGet( p_sys->p_root,  "/moov/rmra" ) ) )
00345     {
00346         playlist_t *p_playlist;
00347         playlist_item_t *p_item;
00348         int        i_count = MP4_BoxCount( p_rmra, "rmda" );
00349         int        i;
00350         vlc_bool_t b_play = VLC_FALSE;
00351 
00352         msg_Dbg( p_demux, "detected playlist mov file (%d ref)", i_count );
00353 
00354         p_playlist =
00355             (playlist_t *)vlc_object_find( p_demux,
00356                                            VLC_OBJECT_PLAYLIST,
00357                                            FIND_ANYWHERE );
00358         if( p_playlist )
00359         {
00360             p_item = playlist_LockItemGetByInput( p_playlist,
00361                       ((input_thread_t *)p_demux->p_parent)->input.p_item );
00362             playlist_ItemToNode( p_playlist, p_item );
00363 
00364             for( i = 0; i < i_count; i++ )
00365             {
00366                 MP4_Box_t *p_rdrf = MP4_BoxGet( p_rmra, "rmda[%d]/rdrf", i );
00367                 char      *psz_ref;
00368                 uint32_t  i_ref_type;
00369 
00370                 if( !p_rdrf || !( psz_ref = p_rdrf->data.p_rdrf->psz_ref ) )
00371                 {
00372                     continue;
00373                 }
00374                 i_ref_type = p_rdrf->data.p_rdrf->i_ref_type;
00375 
00376                 msg_Dbg( p_demux, "new ref=`%s' type=%4.4s",
00377                          psz_ref, (char*)&i_ref_type );
00378 
00379                 if( i_ref_type == VLC_FOURCC( 'u', 'r', 'l', ' ' ) )
00380                 {
00381                     if( strstr( psz_ref, "qt5gateQT" ) )
00382                     {
00383                         msg_Dbg( p_demux, "ignoring pseudo ref =`%s'", psz_ref );
00384                         continue;
00385                     }
00386                     if( !strncmp( psz_ref, "http://", 7 ) ||
00387                         !strncmp( psz_ref, "rtsp://", 7 ) )
00388                     {
00389                         msg_Dbg( p_demux, "adding ref = `%s'", psz_ref );
00390                         if( p_item )
00391                         {
00392                             playlist_item_t *p_child =
00393                                         playlist_ItemNew( p_playlist,
00394                                                           psz_ref, psz_ref );
00395                             if( p_child )
00396                             {
00397                                 playlist_NodeAddItem( p_playlist, p_child,
00398                                                  p_item->pp_parents[0]->i_view,
00399                                                  p_item, PLAYLIST_APPEND,
00400                                                  PLAYLIST_END );
00401                                 playlist_CopyParents( p_item, p_child );
00402                                 b_play = VLC_TRUE;
00403                             }
00404                         }
00405                     }
00406                     else
00407                     {
00408                         /* msg dbg relative ? */
00409                         char *psz_absolute = alloca( strlen( p_demux->psz_access ) + 3 + strlen( p_demux->psz_path ) + strlen( psz_ref ) + 1);
00410                         char *end = strrchr( p_demux->psz_path, '/' );
00411 
00412                         if( end )
00413                         {
00414                             int i_len = end + 1 - p_demux->psz_path;
00415 
00416                             strcpy( psz_absolute, p_demux->psz_access );
00417                             strcat( psz_absolute, "://" );
00418                             strncat( psz_absolute, p_demux->psz_path, i_len);
00419                         }
00420                         else
00421                         {
00422                             strcpy( psz_absolute, "" );
00423                         }
00424                         strcat( psz_absolute, psz_ref );
00425                         msg_Dbg( p_demux, "adding ref = `%s'", psz_absolute );
00426                         if( p_item )
00427                         {
00428                             playlist_item_t *p_child =
00429                                         playlist_ItemNew( p_playlist,
00430                                                           psz_absolute,
00431                                                           psz_absolute );
00432                             if( p_child )
00433                             {
00434                                 playlist_NodeAddItem( p_playlist, p_child,
00435                                                  p_item->pp_parents[0]->i_view,
00436                                                  p_item, PLAYLIST_APPEND,
00437                                                  PLAYLIST_END );
00438                                 playlist_CopyParents( p_item, p_child );
00439                                 b_play = VLC_TRUE;
00440                             }
00441                         }
00442                     }
00443                 }
00444                 else
00445                 {
00446                     msg_Err( p_demux, "unknown ref type=%4.4s FIXME (send a bug report)",
00447                              (char*)&p_rdrf->data.p_rdrf->i_ref_type );
00448                 }
00449             }
00450             if( b_play == VLC_TRUE )
00451             {
00452                  playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
00453                                    p_playlist->status.i_view,
00454                                    p_playlist->status.p_item, NULL );
00455             }
00456             vlc_object_release( p_playlist );
00457         }
00458         else
00459         {
00460             msg_Err( p_demux, "can't find playlist" );
00461         }
00462     }
00463 
00464     if( !(p_mvhd = MP4_BoxGet( p_sys->p_root, "/moov/mvhd" ) ) )
00465     {
00466         if( !p_rmra )
00467         {
00468             msg_Err( p_demux, "cannot find /moov/mvhd" );
00469             goto error;
00470         }
00471         else
00472         {
00473             msg_Warn( p_demux, "cannot find /moov/mvhd (pure ref file)" );
00474             p_demux->pf_demux = DemuxRef;
00475             return VLC_SUCCESS;
00476         }
00477     }
00478     else
00479     {
00480         p_sys->i_timescale = p_mvhd->data.p_mvhd->i_timescale;
00481         p_sys->i_duration = p_mvhd->data.p_mvhd->i_duration;
00482     }
00483 
00484     if( !( p_sys->i_tracks = MP4_BoxCount( p_sys->p_root, "/moov/trak" ) ) )
00485     {
00486         msg_Err( p_demux, "cannot find any /moov/trak" );
00487         goto error;
00488     }
00489     msg_Dbg( p_demux, "find %d track%c",
00490                         p_sys->i_tracks,
00491                         p_sys->i_tracks ? 's':' ' );
00492 
00493     /* allocate memory */
00494     p_sys->track = calloc( p_sys->i_tracks, sizeof( mp4_track_t ) );
00495     memset( p_sys->track, 0, p_sys->i_tracks * sizeof( mp4_track_t ) );
00496 
00497     /* now process each track and extract all usefull information */
00498     for( i = 0; i < p_sys->i_tracks; i++ )
00499     {
00500         p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[%d]", i );
00501         MP4_TrackCreate( p_demux, &p_sys->track[i], p_trak );
00502 
00503         if( p_sys->track[i].b_ok )
00504         {
00505             char *psz_cat;
00506             switch( p_sys->track[i].fmt.i_cat )
00507             {
00508                 case( VIDEO_ES ):
00509                     psz_cat = "video";
00510                     break;
00511                 case( AUDIO_ES ):
00512                     psz_cat = "audio";
00513                     break;
00514                 case( SPU_ES ):
00515                     psz_cat = "subtitle";
00516                     break;
00517 
00518                 default:
00519                     psz_cat = "unknown";
00520                     break;
00521             }
00522 
00523             msg_Dbg( p_demux, "adding track[Id 0x%x] %s (%s) language %s",
00524                      p_sys->track[i].i_track_ID, psz_cat,
00525                      p_sys->track[i].b_enable ? "enable":"disable",
00526                      p_sys->track[i].fmt.psz_language ?
00527                      p_sys->track[i].fmt.psz_language : "undef" );
00528         }
00529         else
00530         {
00531             msg_Dbg( p_demux, "ignoring track[Id 0x%x]",
00532                      p_sys->track[i].i_track_ID );
00533         }
00534 
00535     }
00536     return VLC_SUCCESS;
00537 
00538 error:
00539     if( p_sys->p_root )
00540     {
00541         MP4_BoxFree( p_demux->s, p_sys->p_root );
00542     }
00543     free( p_sys );
00544     return VLC_EGENERIC;
00545 }
00546 
00547 /*****************************************************************************
00548  * Demux: read packet and send them to decoders
00549  *****************************************************************************
00550  * TODO check for newly selected track (ie audio upt to now )
00551  *****************************************************************************/
00552 static int Demux( demux_t *p_demux )
00553 {
00554     demux_sys_t *p_sys = p_demux->p_sys;
00555     unsigned int i_track;
00556 
00557 
00558     unsigned int i_track_selected;
00559 
00560     /* check for newly selected/unselected track */
00561     for( i_track = 0, i_track_selected = 0; i_track < p_sys->i_tracks;
00562          i_track++ )
00563     {
00564         mp4_track_t *tk = &p_sys->track[i_track];
00565         vlc_bool_t b;
00566 
00567         if( !tk->b_ok ||
00568             ( tk->b_selected && tk->i_sample >= tk->i_sample_count ) )
00569         {
00570             continue;
00571         }
00572 
00573         es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
00574 
00575         if( tk->b_selected && !b )
00576         {
00577             MP4_TrackUnselect( p_demux, tk );
00578         }
00579         else if( !tk->b_selected && b)
00580         {
00581             MP4_TrackSelect( p_demux, tk, MP4_GetMoviePTS( p_sys ) );
00582         }
00583 
00584         if( tk->b_selected )
00585         {
00586             i_track_selected++;
00587         }
00588     }
00589 
00590     if( i_track_selected <= 0 )
00591     {
00592         p_sys->i_time += __MAX( p_sys->i_timescale / 10 , 1 );
00593         if( p_sys->i_timescale > 0 )
00594         {
00595             int64_t i_length = (mtime_t)1000000 *
00596                                (mtime_t)p_sys->i_duration /
00597                                (mtime_t)p_sys->i_timescale;
00598             if( MP4_GetMoviePTS( p_sys ) >= i_length )
00599                 return 0;
00600             return 1;
00601         }
00602 
00603         msg_Warn( p_demux, "no track selected, exiting..." );
00604         return 0;
00605     }
00606 
00607     /* first wait for the good time to read a packet */
00608     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr + 1 );
00609 
00610     p_sys->i_pcr = MP4_GetMoviePTS( p_sys );
00611 
00612     /* we will read 100ms for each stream so ...*/
00613     p_sys->i_time += __MAX( p_sys->i_timescale / 10 , 1 );
00614 
00615     for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
00616     {
00617         mp4_track_t *tk = &p_sys->track[i_track];
00618 
00619         if( !tk->b_ok || !tk->b_selected || tk->i_sample >= tk->i_sample_count )
00620         {
00621             continue;
00622         }
00623 
00624         while( MP4_TrackGetDTS( p_demux, tk ) < MP4_GetMoviePTS( p_sys ) )
00625         {
00626 #if 0
00627             msg_Dbg( p_demux, "tk(%i)=%lld mv=%lld", i_track,
00628                      MP4_TrackGetDTS( p_demux, tk ),
00629                      MP4_GetMoviePTS( p_sys ) );
00630 #endif
00631 
00632             if( MP4_TrackSampleSize( tk ) > 0 )
00633             {
00634                 block_t *p_block;
00635                 int64_t i_delta;
00636 
00637                 /* go,go go ! */
00638                 if( stream_Seek( p_demux->s, MP4_TrackGetPos( tk ) ) )
00639                 {
00640                     msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)",
00641                               tk->i_track_ID );
00642                     MP4_TrackUnselect( p_demux, tk );
00643                     break;
00644                 }
00645 
00646                 /* now read pes */
00647                 if( !(p_block =
00648                          stream_Block( p_demux->s, MP4_TrackSampleSize(tk) )) )
00649                 {
00650                     msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)",
00651                               tk->i_track_ID );
00652                     MP4_TrackUnselect( p_demux, tk );
00653                     break;
00654                 }
00655 
00656                 if( tk->b_drms && tk->p_drms )
00657                 {
00658                     drms_decrypt( tk->p_drms, (uint32_t*)p_block->p_buffer,
00659                                   p_block->i_buffer );
00660                 }
00661                 else if( tk->fmt.i_cat == SPU_ES )
00662                 {
00663                     if( tk->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) &&
00664                         p_block->i_buffer >= 2 )
00665                     {
00666                         uint16_t i_size = GetWBE( p_block->p_buffer );
00667 
00668                         if( i_size + 2 <= p_block->i_buffer )
00669                         {
00670                             char *p;
00671                             /* remove the length field, and append a '\0' */
00672                             memmove( &p_block->p_buffer[0],
00673                                      &p_block->p_buffer[2], i_size );
00674                             p_block->p_buffer[i_size] = '\0';
00675                             p_block->i_buffer = i_size + 1;
00676 
00677                             /* convert \r -> \n */
00678                             while( ( p = strchr( p_block->p_buffer, '\r' ) ) )
00679                             {
00680                                 *p = '\n';
00681                             }
00682                         }
00683                         else
00684                         {
00685                             /* Invalid */
00686                             p_block->i_buffer = 0;
00687                         }
00688                     }
00689                 }
00690                 /* dts */
00691                 p_block->i_dts = MP4_TrackGetDTS( p_demux, tk ) + 1;
00692                 /* pts */
00693                 i_delta = MP4_TrackGetPTSDelta( p_demux, tk );
00694                 if( i_delta != -1 )
00695                     p_block->i_pts = p_block->i_dts + i_delta;
00696                 else if( tk->fmt.i_cat != VIDEO_ES )
00697                     p_block->i_pts = p_block->i_dts;
00698                 else
00699                     p_block->i_pts = 0;
00700 
00701                 if( !tk->b_drms || ( tk->b_drms && tk->p_drms ) )
00702                     es_out_Send( p_demux->out, tk->p_es, p_block );
00703             }
00704 
00705             /* Next sample */
00706             if( MP4_TrackNextSample( p_demux, tk ) )
00707             {
00708                 break;
00709             }
00710         }
00711     }
00712 
00713     return 1;
00714 }
00715 /*****************************************************************************
00716  * Seek: Got to i_date
00717 ******************************************************************************/
00718 static int Seek( demux_t *p_demux, mtime_t i_date )
00719 {
00720     demux_sys_t *p_sys = p_demux->p_sys;
00721     unsigned int i_track;
00722 
00723     /* First update update global time */
00724     p_sys->i_time = i_date * p_sys->i_timescale / 1000000;
00725     p_sys->i_pcr  = i_date;
00726 
00727     /* Now for each stream try to go to this time */
00728     for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
00729     {
00730         mp4_track_t *tk = &p_sys->track[i_track];
00731         MP4_TrackSeek( p_demux, tk, i_date );
00732     }
00733     return VLC_SUCCESS;
00734 }
00735 
00736 /*****************************************************************************
00737  * Control:
00738  *****************************************************************************/
00739 static int Control( demux_t *p_demux, int i_query, va_list args )
00740 {
00741     demux_sys_t *p_sys = p_demux->p_sys;
00742 
00743     double f, *pf;
00744     int64_t i64, *pi64;
00745 
00746     switch( i_query )
00747     {
00748         case DEMUX_GET_POSITION:
00749             pf = (double*)va_arg( args, double * );
00750             if( p_sys->i_duration > 0 )
00751             {
00752                 *pf = (double)p_sys->i_time / (double)p_sys->i_duration;
00753             }
00754             else
00755             {
00756                 *pf = 0.0;
00757             }
00758             return VLC_SUCCESS;
00759 
00760         case DEMUX_SET_POSITION:
00761             f = (double)va_arg( args, double );
00762             if( p_sys->i_timescale > 0 )
00763             {
00764                 i64 = (int64_t)( f * (double)1000000 *
00765                                  (double)p_sys->i_duration /
00766                                  (double)p_sys->i_timescale );
00767                 return Seek( p_demux, i64 );
00768             }
00769             else return VLC_SUCCESS;
00770 
00771         case DEMUX_GET_TIME:
00772             pi64 = (int64_t*)va_arg( args, int64_t * );
00773             if( p_sys->i_timescale > 0 )
00774             {
00775                 *pi64 = (mtime_t)1000000 *
00776                         (mtime_t)p_sys->i_time /
00777                         (mtime_t)p_sys->i_timescale;
00778             }
00779             else *pi64 = 0;
00780             return VLC_SUCCESS;
00781 
00782         case DEMUX_SET_TIME:
00783             i64 = (int64_t)va_arg( args, int64_t );
00784             return Seek( p_demux, i64 );
00785 
00786         case DEMUX_GET_LENGTH:
00787             pi64 = (int64_t*)va_arg( args, int64_t * );
00788             if( p_sys->i_timescale > 0 )
00789             {
00790                 *pi64 = (mtime_t)1000000 *
00791                         (mtime_t)p_sys->i_duration /
00792                         (mtime_t)p_sys->i_timescale;
00793             }
00794             else *pi64 = 0;
00795             return VLC_SUCCESS;
00796 
00797         case DEMUX_GET_FPS:
00798             msg_Warn( p_demux, "DEMUX_GET_FPS unimplemented !!" );
00799             return VLC_EGENERIC;
00800 
00801         case DEMUX_GET_META:
00802         {
00803             vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
00804             vlc_meta_t *meta;
00805             MP4_Box_t  *p_udta   = MP4_BoxGet( p_sys->p_root, "/moov/udta" );
00806             MP4_Box_t  *p_0xa9xxx;
00807             if( p_udta == NULL )
00808             {
00809                 return VLC_EGENERIC;
00810             }
00811             *pp_meta = meta = vlc_meta_New();
00812             for( p_0xa9xxx = p_udta->p_first; p_0xa9xxx != NULL;
00813                  p_0xa9xxx = p_0xa9xxx->p_next )
00814             {
00815                 switch( p_0xa9xxx->i_type )
00816                 {
00817                 case FOURCC_0xa9nam: /* Full name */
00818                     vlc_meta_Add( meta, VLC_META_TITLE,
00819                                   p_0xa9xxx->data.p_0xa9xxx->psz_text );
00820                     break;
00821                 case FOURCC_0xa9aut:
00822                     vlc_meta_Add( meta, VLC_META_AUTHOR,
00823                                   p_0xa9xxx->data.p_0xa9xxx->psz_text );
00824                     break;
00825                 case FOURCC_0xa9ART:
00826                     vlc_meta_Add( meta, VLC_META_ARTIST,
00827                                   p_0xa9xxx->data.p_0xa9xxx->psz_text );
00828                     break;
00829                 case FOURCC_0xa9cpy:
00830                     vlc_meta_Add( meta, VLC_META_COPYRIGHT,
00831                                   p_0xa9xxx->data.p_0xa9xxx->psz_text );
00832                     break;
00833                 case FOURCC_0xa9day: /* Creation Date */
00834                     vlc_meta_Add( meta, VLC_META_DATE,
00835                                   p_0xa9xxx->data.p_0xa9xxx->psz_text );
00836                     break;
00837                 case FOURCC_0xa9des: /* Description */
00838                     vlc_meta_Add( meta, VLC_META_DESCRIPTION,
00839                                   p_0xa9xxx->data.p_0xa9xxx->psz_text );
00840                     break;
00841                 case FOURCC_0xa9gen: /* Genre */
00842                     vlc_meta_Add( meta, VLC_META_GENRE,
00843                                   p_0xa9xxx->data.p_0xa9xxx->psz_text );
00844                     break;
00845 
00846                 case FOURCC_0xa9swr:
00847                 case FOURCC_0xa9inf: /* Information */
00848                 case FOURCC_0xa9alb: /* Album */
00849                 case FOURCC_0xa9dir: /* Director */
00850                 case FOURCC_0xa9dis: /* Disclaimer */
00851                 case FOURCC_0xa9enc: /* Encoded By */
00852                 case FOURCC_0xa9trk: /* Track */
00853                 case FOURCC_0xa9cmt: /* Commment */
00854                 case FOURCC_0xa9url: /* URL */
00855                 case FOURCC_0xa9req: /* Requirements */
00856                 case FOURCC_0xa9fmt: /* Original Format */
00857                 case FOURCC_0xa9dsa: /* Display Source As */
00858                 case FOURCC_0xa9hst: /* Host Computer */
00859                 case FOURCC_0xa9prd: /* Producer */
00860                 case FOURCC_0xa9prf: /* Performers */
00861                 case FOURCC_0xa9ope: /* Original Performer */
00862                 case FOURCC_0xa9src: /* Providers Source Content */
00863                 case FOURCC_0xa9wrt: /* Writer */
00864                 case FOURCC_0xa9com: /* Composer */
00865                 case FOURCC_WLOC:    /* Window Location */
00866                     /* TODO one day, but they aren't really meaningfull */
00867                     break;
00868 
00869                 default:
00870                     break;
00871                 }
00872             }
00873             return VLC_SUCCESS;
00874         }
00875 
00876         case DEMUX_GET_TITLE_INFO:
00877         case DEMUX_SET_NEXT_DEMUX_TIME:
00878         case DEMUX_SET_GROUP:
00879             return VLC_EGENERIC;
00880 
00881         default:
00882             msg_Warn( p_demux, "control query unimplemented !!!" );
00883             return VLC_EGENERIC;
00884     }
00885 }
00886 
00887 /*****************************************************************************
00888  * Close: frees unused data
00889  *****************************************************************************/
00890 static void Close ( vlc_object_t * p_this )
00891 {
00892     unsigned int i_track;
00893     demux_t *  p_demux = (demux_t *)p_this;
00894     demux_sys_t *p_sys = p_demux->p_sys;
00895 
00896     msg_Dbg( p_demux, "freeing all memory" );
00897 
00898     MP4_BoxFree( p_demux->s, p_sys->p_root );
00899     for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
00900     {
00901         MP4_TrackDestroy( p_demux, &p_sys->track[i_track] );
00902     }
00903     FREE( p_sys->track );
00904 
00905     free( p_sys );
00906 }
00907 
00908 
00909 
00910 /****************************************************************************
00911  * Local functions, specific to vlc
00912  ****************************************************************************/
00913 
00914 /* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */
00915 static int TrackCreateChunksIndex( demux_t *p_demux,
00916                                    mp4_track_t *p_demux_track )
00917 {
00918     MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */
00919     MP4_Box_t *p_stsc;
00920 
00921     unsigned int i_chunk;
00922     unsigned int i_index, i_last;
00923 
00924     if( ( !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "stco" ) )&&
00925           !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "co64" ) ) )||
00926         ( !(p_stsc = MP4_BoxGet( p_demux_track->p_stbl, "stsc" ) ) ))
00927     {
00928         return( VLC_EGENERIC );
00929     }
00930 
00931     p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count;
00932     if( !p_demux_track->i_chunk_count )
00933     {
00934         msg_Warn( p_demux, "no chunk defined" );
00935         return( VLC_EGENERIC );
00936     }
00937     p_demux_track->chunk = calloc( p_demux_track->i_chunk_count,
00938                                    sizeof( mp4_chunk_t ) );
00939 
00940     /* first we read chunk offset */
00941     for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
00942     {
00943         mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
00944 
00945         ck->i_offset = p_co64->data.p_co64->i_chunk_offset[i_chunk];
00946 
00947         ck->i_first_dts = 0;
00948         ck->p_sample_count_dts = NULL;
00949         ck->p_sample_delta_dts = NULL;
00950         ck->p_sample_count_pts = NULL;
00951         ck->p_sample_offset_pts = NULL;
00952     }
00953 
00954     /* now we read index for SampleEntry( soun vide mp4a mp4v ...)
00955         to be used for the sample XXX begin to 1
00956         We construct it begining at the end */
00957     i_last = p_demux_track->i_chunk_count; /* last chunk proceded */
00958     i_index = p_stsc->data.p_stsc->i_entry_count;
00959     if( !i_index )
00960     {
00961         msg_Warn( p_demux, "cannot read chunk table or table empty" );
00962         return( VLC_EGENERIC );
00963     }
00964 
00965     while( i_index-- )
00966     {
00967         for( i_chunk = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;
00968              i_chunk < i_last; i_chunk++ )
00969         {
00970             p_demux_track->chunk[i_chunk].i_sample_description_index =
00971                     p_stsc->data.p_stsc->i_sample_description_index[i_index];
00972             p_demux_track->chunk[i_chunk].i_sample_count =
00973                     p_stsc->data.p_stsc->i_samples_per_chunk[i_index];
00974         }
00975         i_last = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;
00976     }
00977 
00978     p_demux_track->chunk[0].i_sample_first = 0;
00979     for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
00980     {
00981         p_demux_track->chunk[i_chunk].i_sample_first =
00982             p_demux_track->chunk[i_chunk-1].i_sample_first +
00983                 p_demux_track->chunk[i_chunk-1].i_sample_count;
00984     }
00985 
00986     msg_Dbg( p_demux, "track[Id 0x%x] read %d chunk",
00987              p_demux_track->i_track_ID, p_demux_track->i_chunk_count );
00988 
00989     return VLC_SUCCESS;
00990 }
00991 
00992 static int TrackCreateSamplesIndex( demux_t *p_demux,
00993                                     mp4_track_t *p_demux_track )
00994 {
00995     MP4_Box_t *p_box;
00996     MP4_Box_data_stsz_t *stsz;
00997     MP4_Box_data_stts_t *stts;
00998     /* TODO use also stss and stsh table for seeking */
00999     /* FIXME use edit table */
01000     int64_t i_sample;
01001     int64_t i_chunk;
01002 
01003     int64_t i_index;
01004     int64_t i_index_sample_used;
01005 
01006     int64_t i_last_dts;
01007 
01008     /* Find stsz
01009      *  Gives the sample size for each samples. There is also a stz2 table
01010      *  (compressed form) that we need to implement TODO */
01011     p_box = MP4_BoxGet( p_demux_track->p_stbl, "stsz" );
01012     if( !p_box )
01013     {
01014         /* FIXME and stz2 */
01015         msg_Warn( p_demux, "cannot find STSZ box" );
01016         return VLC_EGENERIC;
01017     }
01018     stsz = p_box->data.p_stsz;
01019 
01020     /* Find stts
01021      *  Gives mapping between sample and decoding time
01022      */
01023     p_box = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
01024     if( !p_box )
01025     {
01026         msg_Warn( p_demux, "cannot find STTS box" );
01027         return VLC_EGENERIC;
01028     }
01029     stts = p_box->data.p_stts;
01030 
01031     /* Use stsz table to create a sample number -> sample size table */
01032     p_demux_track->i_sample_count = stsz->i_sample_count;
01033     if( stsz->i_sample_size )
01034     {
01035         /* 1: all sample have the same size, so no need to construct a table */
01036         p_demux_track->i_sample_size = stsz->i_sample_size;
01037         p_demux_track->p_sample_size = NULL;
01038     }
01039     else
01040     {
01041         /* 2: each sample can have a different size */
01042         p_demux_track->i_sample_size = 0;
01043         p_demux_track->p_sample_size =
01044             calloc( p_demux_track->i_sample_count, sizeof( uint32_t ) );
01045 
01046         for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
01047         {
01048             p_demux_track->p_sample_size[i_sample] =
01049                     stsz->i_entry_size[i_sample];
01050         }
01051     }
01052 
01053     /* Use stts table to create a sample number -> dts table.
01054      * XXX: if we don't want to waste too much memory, we can't expand
01055      *  the box! so each chunk will contain an "extract" of this table
01056      *  for fast research (problem with raw stream where a sample is sometime
01057      *  just channels*bits_per_sample/8 */
01058 
01059     i_last_dts = 0;
01060     i_index = 0; i_index_sample_used = 0;
01061     for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
01062     {
01063         mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
01064         int64_t i_entry, i_sample_count, i;
01065 
01066         /* save last dts */
01067         ck->i_first_dts = i_last_dts;
01068 
01069         /* count how many entries are needed for this chunk
01070          * for p_sample_delta_dts and p_sample_count_dts */
01071         i_sample_count = ck->i_sample_count;
01072 
01073         i_entry = 0;
01074         while( i_sample_count > 0 )
01075         {
01076             i_sample_count -= stts->i_sample_count[i_index+i_entry];
01077             /* don't count already used sample in this entry */
01078             if( i_entry == 0 )
01079                 i_sample_count += i_index_sample_used;
01080 
01081             i_entry++;
01082         }
01083 
01084         /* allocate them */
01085         ck->p_sample_count_dts = calloc( i_entry, sizeof( uint32_t ) );
01086         ck->p_sample_delta_dts = calloc( i_entry, sizeof( uint32_t ) );
01087 
01088         /* now copy */
01089         i_sample_count = ck->i_sample_count;
01090         for( i = 0; i < i_entry; i++ )
01091         {
01092             int64_t i_used;
01093             int64_t i_rest;
01094 
01095             i_rest = stts->i_sample_count[i_index] - i_index_sample_used;
01096 
01097             i_used = __MIN( i_rest, i_sample_count );
01098 
01099             i_index_sample_used += i_used;
01100             i_sample_count -= i_used;
01101 
01102             ck->p_sample_count_dts[i] = i_used;
01103             ck->p_sample_delta_dts[i] = stts->i_sample_delta[i_index];
01104 
01105             i_last_dts += i_used * ck->p_sample_delta_dts[i];
01106 
01107             if( i_index_sample_used >= stts->i_sample_count[i_index] )
01108             {
01109                 i_index++;
01110                 i_index_sample_used = 0;
01111             }
01112         }
01113     }
01114 
01115     /* Find ctts
01116      *  Gives the delta between decoding time (dts) and composition table (pts)
01117      */
01118     p_box = MP4_BoxGet( p_demux_track->p_stbl, "ctts" );
01119     if( p_box )
01120     {
01121         MP4_Box_data_ctts_t *ctts = p_box->data.p_ctts;
01122 
01123         msg_Warn( p_demux, "CTTS table" );
01124 
01125         /* Create pts-dts table per chunk */
01126         i_index = 0; i_index_sample_used = 0;
01127         for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
01128         {
01129             mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
01130             int64_t i_entry, i_sample_count, i;
01131 
01132             /* count how many entries are needed for this chunk
01133              * for p_sample_delta_dts and p_sample_count_dts */
01134             i_sample_count = ck->i_sample_count;
01135 
01136             i_entry = 0;
01137             while( i_sample_count > 0 )
01138             {
01139                 i_sample_count -= ctts->i_sample_count[i_index+i_entry];
01140 
01141                 /* don't count already used sample in this entry */
01142                 if( i_entry == 0 )
01143                     i_sample_count += i_index_sample_used;
01144 
01145                 i_entry++;
01146             }
01147 
01148             /* allocate them */
01149             ck->p_sample_count_pts = calloc( i_entry, sizeof( uint32_t ) );
01150             ck->p_sample_offset_pts = calloc( i_entry, sizeof( int32_t ) );
01151 
01152             /* now copy */
01153             i_sample_count = ck->i_sample_count;
01154             for( i = 0; i < i_entry; i++ )
01155             {
01156                 int64_t i_used;
01157                 int64_t i_rest;
01158 
01159                 i_rest = ctts->i_sample_count[i_index] -
01160                     i_index_sample_used;
01161 
01162                 i_used = __MIN( i_rest, i_sample_count );
01163 
01164                 i_index_sample_used += i_used;
01165                 i_sample_count -= i_used;
01166 
01167                 ck->p_sample_count_pts[i] = i_used;
01168                 ck->p_sample_offset_pts[i] = ctts->i_sample_offset[i_index];
01169 
01170                 if( i_index_sample_used >= ctts->i_sample_count[i_index] )
01171                 {
01172                     i_index++;
01173                     i_index_sample_used = 0;
01174                 }
01175             }
01176         }
01177     }
01178 
01179     msg_Dbg( p_demux, "track[Id 0x%x] read %d samples length:"I64Fd"s",
01180              p_demux_track->i_track_ID, p_demux_track->i_sample_count,
01181              i_last_dts / p_demux_track->i_timescale );
01182 
01183     return VLC_SUCCESS;
01184 }
01185 
01186 /*
01187  * TrackCreateES:
01188  * Create ES and PES to init decoder if needed, for a track starting at i_chunk
01189  */
01190 static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track,
01191                           unsigned int i_chunk, es_out_id_t **pp_es )
01192 {
01193     MP4_Box_t   *p_sample;
01194     MP4_Box_t   *p_esds;
01195     MP4_Box_t   *p_box;
01196 
01197     *pp_es = NULL;
01198 
01199     if( !p_track->chunk[i_chunk].i_sample_description_index )
01200     {
01201         msg_Warn( p_demux, "invalid SampleEntry index (track[Id 0x%x])",
01202                   p_track->i_track_ID );
01203         return VLC_EGENERIC;
01204     }
01205 
01206     p_sample = MP4_BoxGet(  p_track->p_stsd, "[%d]",
01207                 p_track->chunk[i_chunk].i_sample_description_index - 1 );
01208 
01209     if( !p_sample ||
01210         ( !p_sample->data.p_data && p_track->fmt.i_cat != SPU_ES ) )
01211     {
01212         msg_Warn( p_demux, "cannot find SampleEntry (track[Id 0x%x])",
01213                   p_track->i_track_ID );
01214         return VLC_EGENERIC;
01215     }
01216 
01217     p_track->p_sample = p_sample;
01218 
01219     if( p_track->fmt.i_cat == AUDIO_ES && p_track->i_sample_size == 1 )
01220     {
01221         MP4_Box_data_sample_soun_t *p_soun;
01222 
01223         p_soun = p_sample->data.p_sample_soun;
01224 
01225         if( p_soun->i_qt_version == 0 )
01226         {
01227             switch( p_sample->i_type )
01228             {
01229                 case VLC_FOURCC( 'i', 'm', 'a', '4' ):
01230                     p_soun->i_qt_version = 1;
01231                     p_soun->i_sample_per_packet = 64;
01232                     p_soun->i_bytes_per_packet  = 34;
01233                     p_soun->i_bytes_per_frame   = 34 * p_soun->i_channelcount;
01234                     p_soun->i_bytes_per_sample  = 2;
01235                     break;
01236                 case VLC_FOURCC( 'M', 'A', 'C', '3' ):
01237                     p_soun->i_qt_version = 1;
01238                     p_soun->i_sample_per_packet = 6;
01239                     p_soun->i_bytes_per_packet  = 2;
01240                     p_soun->i_bytes_per_frame   = 2 * p_soun->i_channelcount;
01241                     p_soun->i_bytes_per_sample  = 2;
01242                     break;
01243                 case VLC_FOURCC( 'M', 'A', 'C', '6' ):
01244                     p_soun->i_qt_version = 1;
01245                     p_soun->i_sample_per_packet = 12;
01246                     p_soun->i_bytes_per_packet  = 2;
01247                     p_soun->i_bytes_per_frame   = 2 * p_soun->i_channelcount;
01248                     p_soun->i_bytes_per_sample  = 2;
01249                     break;
01250                 case VLC_FOURCC( 'a', 'l', 'a', 'w' ):
01251                 case VLC_FOURCC( 'u', 'l', 'a', 'w' ):
01252                     p_soun->i_samplesize = 8;
01253                     break;
01254                 default:
01255                     break;
01256             }
01257 
01258         }
01259         else if( p_soun->i_qt_version == 1 && p_soun->i_sample_per_packet <= 0 )
01260         {
01261             p_soun->i_qt_version = 0;
01262         }
01263     }
01264 
01265 
01266     /* It's a little ugly but .. there are special cases */
01267     switch( p_sample->i_type )
01268     {
01269         case( VLC_FOURCC( '.', 'm', 'p', '3' ) ):
01270         case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ):
01271             p_track->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
01272             break;
01273 
01274         case( VLC_FOURCC( 'r', 'a', 'w', ' ' ) ):
01275             p_track->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
01276 
01277             /* Buggy files workaround */
01278             if( p_sample->data.p_sample_soun && (p_track->i_timescale !=
01279                 p_sample->data.p_sample_soun->i_sampleratehi) )
01280             {
01281                 MP4_Box_data_sample_soun_t *p_soun =
01282                     p_sample->data.p_sample_soun;
01283 
01284                 msg_Warn( p_demux, "i_timescale ("I64Fu") != i_sampleratehi "
01285                           "(%u), making both equal (report any problem).",
01286                           p_track->i_timescale, p_soun->i_sampleratehi );
01287 
01288                 if( p_soun->i_sampleratehi )
01289                     p_track->i_timescale = p_soun->i_sampleratehi;
01290                 else
01291                     p_soun->i_sampleratehi = p_track->i_timescale;
01292             }
01293             break;
01294 
01295         case( VLC_FOURCC( 's', '2', '6', '3' ) ):
01296             p_track->fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '3' );
01297             break;
01298 
01299         case( VLC_FOURCC( 't', 'e', 'x', 't' ) ):
01300         case( VLC_FOURCC( 't', 'x', '3', 'g' ) ):
01301             p_track->fmt.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
01302             /* FIXME: Not true, could be UTF-16 with a Byte Order Mark (0xfeff) */
01303             /* FIXME UTF-8 doesn't work here ? */
01304             /* p_track->fmt.subs.psz_encoding = strdup( "UTF-8" ); */
01305             break;
01306 
01307         default:
01308             p_track->fmt.i_codec = p_sample->i_type;
01309             break;
01310     }
01311 
01312     /* now see if esds is present and if so create a data packet
01313         with decoder_specific_info  */
01314 #define p_decconfig p_esds->data.p_esds->es_descriptor.p_decConfigDescr
01315     if( ( ( p_esds = MP4_BoxGet( p_sample, "esds" ) ) ||
01316           ( p_esds = MP4_BoxGet( p_sample, "wave/esds" ) ) )&&
01317         ( p_esds->data.p_esds )&&
01318         ( p_decconfig ) )
01319     {
01320         /* First update information based on i_objectTypeIndication */
01321         switch( p_decconfig->i_objectTypeIndication )
01322         {
01323             case( 0x20 ): /* MPEG4 VIDEO */
01324                 p_track->fmt.i_codec = VLC_FOURCC( 'm','p','4','v' );
01325                 break;
01326             case( 0x40):
01327                 p_track->fmt.i_codec = VLC_FOURCC( 'm','p','4','a' );
01328                 break;
01329             case( 0x60):
01330             case( 0x61):
01331             case( 0x62):
01332             case( 0x63):
01333             case( 0x64):
01334             case( 0x65): /* MPEG2 video */
01335                 p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','v' );
01336                 break;
01337             /* Theses are MPEG2-AAC */
01338             case( 0x66): /* main profile */
01339             case( 0x67): /* Low complexity profile */
01340             case( 0x68): /* Scaleable Sampling rate profile */
01341                 p_track->fmt.i_codec = VLC_FOURCC( 'm','p','4','a' );
01342                 break;
01343             /* true MPEG 2 audio */
01344             case( 0x69):
01345                 p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','a' );
01346                 break;
01347             case( 0x6a): /* MPEG1 video */
01348                 p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','v' );
01349                 break;
01350             case( 0x6b): /* MPEG1 audio */
01351                 p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','a' );
01352                 break;
01353             case( 0x6c ): /* jpeg */
01354                 p_track->fmt.i_codec = VLC_FOURCC( 'j','p','e','g' );
01355                 break;
01356 
01357             /* Private ID */
01358             case( 0xe0 ): /* NeroDigital: dvd subs */
01359                 if( p_track->fmt.i_cat == SPU_ES )
01360                 {
01361                     p_track->fmt.i_codec = VLC_FOURCC( 's','p','u',' ' );
01362                     break;
01363                 }
01364             /* Fallback */
01365             default:
01366                 /* Unknown entry, but don't touch i_fourcc */
01367                 msg_Warn( p_demux,
01368                           "unknown objectTypeIndication(0x%x) (Track[ID 0x%x])",
01369                           p_decconfig->i_objectTypeIndication,
01370                           p_track->i_track_ID );
01371                 break;
01372         }
01373         p_track->fmt.i_extra = p_decconfig->i_decoder_specific_info_len;
01374         if( p_track->fmt.i_extra > 0 )
01375         {
01376             p_track->fmt.p_extra = malloc( p_track->fmt.i_extra );
01377             memcpy( p_track->fmt.p_extra, p_decconfig->p_decoder_specific_info,
01378                     p_track->fmt.i_extra );
01379         }
01380     }
01381     else
01382     {
01383         switch( p_sample->i_type )
01384         {
01385             /* qt decoder, send the complete chunk */
01386             case VLC_FOURCC( 'S', 'V', 'Q', '3' ):
01387             case VLC_FOURCC( 'S', 'V', 'Q', '1' ):
01388             case VLC_FOURCC( 'V', 'P', '3', '1' ):
01389             case VLC_FOURCC( '3', 'I', 'V', '1' ):
01390             case VLC_FOURCC( 'Z', 'y', 'G', 'o' ):
01391                 p_track->fmt.i_extra =
01392                     p_sample->data.p_sample_vide->i_qt_image_description;
01393                 if( p_track->fmt.i_extra > 0 )
01394                 {
01395                     p_track->fmt.p_extra = malloc( p_track->fmt.i_extra );
01396                     memcpy( p_track->fmt.p_extra,
01397                             p_sample->data.p_sample_vide->p_qt_image_description,
01398                             p_track->fmt.i_extra);
01399                 }
01400                 break;
01401             case VLC_FOURCC( 'Q', 'D', 'M', 'C' ):
01402             case VLC_FOURCC( 'Q', 'D', 'M', '2' ):
01403             case VLC_FOURCC( 'Q', 'c', 'l', 'p' ):
01404             case VLC_FOURCC( 's', 'a', 'm', 'r' ):
01405             case VLC_FOURCC( 'a', 'l', 'a', 'c' ):
01406                 p_track->fmt.i_extra =
01407                     p_sample->data.p_sample_soun->i_qt_description;
01408                 if( p_track->fmt.i_extra > 0 )
01409                 {
01410                     p_track->fmt.p_extra = malloc( p_track->fmt.i_extra );
01411                     memcpy( p_track->fmt.p_extra,
01412                             p_sample->data.p_sample_soun->p_qt_description,
01413                             p_track->fmt.i_extra);
01414                 }
01415                 break;
01416 
01417             /* avc1: send avcC (h264 without annexe B, ie without start code)*/
01418             case VLC_FOURCC( 'a', 'v', 'c', '1' ):
01419             {
01420                 MP4_Box_t *p_avcC = MP4_BoxGet( p_sample, "avcC" );
01421 
01422                 if( p_avcC )
01423                 {
01424                     p_track->fmt.i_extra = p_avcC->data.p_avcC->i_avcC;
01425                     p_track->fmt.p_extra = malloc( p_avcC->data.p_avcC->i_avcC );
01426                     memcpy( p_track->fmt.p_extra, p_avcC->data.p_avcC->p_avcC,
01427                             p_track->fmt.i_extra );
01428                 }
01429                 else
01430                 {
01431                     msg_Err( p_demux, "missing avcC" );
01432                 }
01433                 break;
01434             }
01435 
01436             default:
01437                 break;
01438         }
01439     }
01440 
01441 #undef p_decconfig
01442 
01443     /* some last initialisation */
01444     switch( p_track->fmt.i_cat )
01445     {
01446     case( VIDEO_ES ):
01447         p_track->fmt.video.i_width = p_sample->data.p_sample_vide->i_width;
01448         p_track->fmt.video.i_height = p_sample->data.p_sample_vide->i_height;
01449         p_track->fmt.video.i_bits_per_pixel =
01450             p_sample->data.p_sample_vide->i_depth;
01451 
01452         /* fall on display size */
01453         if( p_track->fmt.video.i_width <= 0 )
01454             p_track->fmt.video.i_width = p_track->i_width;
01455         if( p_track->fmt.video.i_height <= 0 )
01456             p_track->fmt.video.i_height = p_track->i_height;
01457 
01458         /* Find out apect ratio from display size */
01459         if( p_track->i_width > 0 && p_track->i_height > 0 &&
01460             /* Work-around buggy muxed files */
01461             p_sample->data.p_sample_vide->i_width != p_track->i_width )
01462             p_track->fmt.video.i_aspect =
01463                 VOUT_ASPECT_FACTOR * p_track->i_width / p_track->i_height;
01464 
01465         /* Frame rate */
01466         p_track->fmt.video.i_frame_rate = p_track->i_timescale;
01467         p_track->fmt.video.i_frame_rate_base = 1;
01468 
01469         if( p_track->fmt.video.i_frame_rate &&
01470             (p_box = MP4_BoxGet( p_track->p_stbl, "stts" )) &&
01471             p_box->data.p_stts->i_entry_count >= 1 )
01472         {
01473             p_track->fmt.video.i_frame_rate_base =
01474                 p_box->data.p_stts->i_sample_delta[0];
01475         }
01476 
01477         break;
01478 
01479     case( AUDIO_ES ):
01480         p_track->fmt.audio.i_channels =
01481             p_sample->data.p_sample_soun->i_channelcount;
01482         p_track->fmt.audio.i_rate =
01483             p_sample->data.p_sample_soun->i_sampleratehi;
01484         p_track->fmt.i_bitrate = p_sample->data.p_sample_soun->i_channelcount *
01485             p_sample->data.p_sample_soun->i_sampleratehi *
01486                 p_sample->data.p_sample_soun->i_samplesize;
01487         p_track->fmt.audio.i_bitspersample =
01488             p_sample->data.p_sample_soun->i_samplesize;
01489         break;
01490 
01491     default:
01492         break;
01493     }
01494 
01495     *pp_es = es_out_Add( p_demux->out, &p_track->fmt );
01496 
01497     return VLC_SUCCESS;
01498 }
01499 
01500 /* given a time it return sample/chunk
01501  * it also update elst field of the track
01502  */
01503 static int TrackTimeToSampleChunk( demux_t *p_demux, mp4_track_t *p_track,
01504                                    int64_t i_start, uint32_t *pi_chunk,
01505                                    uint32_t *pi_sample )
01506 {
01507     demux_sys_t *p_sys = p_demux->p_sys;
01508     MP4_Box_t   *p_stss;
01509     uint64_t     i_dts;
01510     unsigned int i_sample;
01511     unsigned int i_chunk;
01512     int          i_index;
01513 
01514     /* FIXME see if it's needed to check p_track->i_chunk_count */
01515     if( !p_track->b_ok || p_track->i_chunk_count == 0 )
01516     {
01517         return( VLC_EGENERIC );
01518     }
01519 
01520     /* handle elst (find the correct one) */
01521     MP4_TrackSetELST( p_demux, p_track, i_start );
01522     if( p_track->p_elst && p_track->p_elst->data.p_elst->i_entry_count > 0 )
01523     {
01524         MP4_Box_data_elst_t *elst = p_track->p_elst->data.p_elst;
01525         int64_t i_mvt= i_start * p_sys->i_timescale / (int64_t)1000000;
01526 
01527         /* now calculate i_start for this elst */
01528         /* offset */
01529         i_start -= p_track->i_elst_time * I64C(1000000) / p_sys->i_timescale;
01530         if( i_start < 0 )
01531         {
01532             *pi_chunk = 0;
01533             *pi_sample= 0;
01534 
01535             return VLC_SUCCESS;
01536         }
01537         /* to track time scale */
01538         i_start  = i_start * p_track->i_timescale / (int64_t)1000000;
01539         /* add elst offset */
01540         if( ( elst->i_media_rate_integer[p_track->i_elst] > 0 ||
01541              elst->i_media_rate_fraction[p_track->i_elst] > 0 ) &&
01542             elst->i_media_time[p_track->i_elst] > 0 )
01543         {
01544             i_start += elst->i_media_time[p_track->i_elst];
01545         }
01546 
01547         msg_Dbg( p_demux, "elst (%d) gives "I64Fd"ms (movie)-> "I64Fd
01548                  "ms (track)", p_track->i_elst,
01549                  i_mvt * 1000 / p_sys->i_timescale,
01550                  i_start * 1000 / p_track->i_timescale );
01551     }
01552     else
01553     {
01554         /* convert absolute time to in timescale unit */
01555         i_start = i_start * p_track->i_timescale / (int64_t)1000000;
01556     }
01557 
01558     /* we start from sample 0/chunk 0, hope it won't take too much time */
01559     /* *** find good chunk *** */
01560     for( i_chunk = 0; ; i_chunk++ )
01561     {
01562         if( i_chunk + 1 >= p_track->i_chunk_count )
01563         {
01564             /* at the end and can't check if i_start in this chunk,
01565                it will be check while searching i_sample */
01566             i_chunk = p_track->i_chunk_count - 1;
01567             break;
01568         }
01569 
01570         if( (uint64_t)i_start >= p_track->chunk[i_chunk].i_first_dts &&
01571             (uint64_t)i_start <  p_track->chunk[i_chunk + 1].i_first_dts )
01572         {
01573             break;
01574         }
01575     }
01576 
01577     /* *** find sample in the chunk *** */
01578     i_sample = p_track->chunk[i_chunk].i_sample_first;
01579     i_dts    = p_track->chunk[i_chunk].i_first_dts;
01580     for( i_index = 0; i_sample < p_track->chunk[i_chunk].i_sample_count; )
01581     {
01582         if( i_dts +
01583             p_track->chunk[i_chunk].p_sample_count_dts[i_index] *
01584             p_track->chunk[i_chunk].p_sample_delta_dts[i_index] < (uint64_t)i_start )
01585         {
01586             i_dts    +=
01587                 p_track->chunk[i_chunk].p_sample_count_dts[i_index] *
01588                 p_track->chunk[i_chunk].p_sample_delta_dts[i_index];
01589 
01590             i_sample += p_track->chunk[i_chunk].p_sample_count_dts[i_index];
01591             i_index++;
01592         }
01593         else
01594         {
01595             if( p_track->chunk[i_chunk].p_sample_delta_dts[i_index] <= 0 )
01596             {
01597                 break;
01598             }
01599             i_sample += ( i_start - i_dts ) /
01600                 p_track->chunk[i_chunk].p_sample_delta_dts[i_index];
01601             break;
01602         }
01603     }
01604 
01605     if( i_sample >= p_track->i_sample_count )
01606     {
01607         msg_Warn( p_demux, "track[Id 0x%x] will be disabled "
01608                   "(seeking too far) chunk=%d sample=%d",
01609                   p_track->i_track_ID, i_chunk, i_sample );
01610         return( VLC_EGENERIC );
01611     }
01612 
01613 
01614     /* *** Try to find nearest sync points *** */
01615     if( ( p_stss = MP4_BoxGet( p_track->p_stbl, "stss" ) ) )
01616     {
01617         unsigned int i_index;
01618         msg_Dbg( p_demux,
01619                     "track[Id 0x%x] using Sync Sample Box (stss)",
01620                     p_track->i_track_ID );
01621         for( i_index = 0; i_index < p_stss->data.p_stss->i_entry_count; i_index++ )
01622         {
01623             if( p_stss->data.p_stss->i_sample_number[i_index] >= i_sample )
01624             {
01625                 if( i_index > 0 )
01626                 {
01627                     msg_Dbg( p_demux, "stts gives %d --> %d (sample number)",
01628                             i_sample,
01629                             p_stss->data.p_stss->i_sample_number[i_index-1] );
01630                     i_sample = p_stss->data.p_stss->i_sample_number[i_index-1];
01631                     /* new i_sample is less than old so i_chunk can only decreased */
01632                     while( i_chunk > 0 &&
01633                             i_sample < p_track->chunk[i_chunk].i_sample_first )
01634                     {
01635                         i_chunk--;
01636                     }
01637                 }
01638                 else
01639                 {
01640                     msg_Dbg( p_demux, "stts gives %d --> %d (sample number)",
01641                             i_sample,
01642                             p_stss->data.p_stss->i_sample_number[i_index] );
01643                     i_sample = p_stss->data.p_stss->i_sample_number[i_index];
01644                     /* new i_sample is more than old so i_chunk can only increased */
01645                     while( i_chunk < p_track->i_chunk_count - 1 &&
01646                            i_sample >= p_track->chunk[i_chunk].i_sample_first +
01647                              p_track->chunk[i_chunk].i_sample_count )
01648                     {
01649                         i_chunk++;
01650                     }
01651                 }
01652                 break;
01653             }
01654         }
01655     }
01656     else
01657     {
01658         msg_Dbg( p_demux, "track[Id 0x%x] does not provide Sync "
01659                  "Sample Box (stss)", p_track->i_track_ID );
01660     }
01661 
01662     *pi_chunk  = i_chunk;
01663     *pi_sample = i_sample;
01664 
01665     return VLC_SUCCESS;
01666 }
01667 
01668 static int TrackGotoChunkSample( demux_t *p_demux, mp4_track_t *p_track,
01669                                  unsigned int i_chunk, unsigned int i_sample )
01670 {
01671     vlc_bool_t b_reselect = VLC_FALSE;
01672 
01673     /* now see if actual es is ok */
01674     if( p_track->i_chunk < 0 ||
01675         p_track->i_chunk >= p_track->i_chunk_count - 1 ||
01676         p_track->chunk[p_track->i_chunk].i_sample_description_index !=
01677             p_track->chunk[i_chunk].i_sample_description_index )
01678     {
01679         msg_Warn( p_demux, "recreate ES for track[Id 0x%x]",
01680                   p_track->i_track_ID );
01681 
01682         es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
01683                         p_track->p_es, &b_reselect );
01684 
01685         es_out_Del( p_demux->out, p_track->p_es );
01686 
01687         p_track->p_es = NULL;
01688 
01689         if( TrackCreateES( p_demux, p_track, i_chunk, &p_track->p_es ) )
01690         {
01691             msg_Err( p_demux, "cannot create es for track[Id 0x%x]",
01692                      p_track->i_track_ID );
01693 
01694             p_track->b_ok       = VLC_FALSE;
01695             p_track->b_selected = VLC_FALSE;
01696             return VLC_EGENERIC;
01697         }
01698     }
01699 
01700     /* select again the new decoder */
01701     if( b_reselect )
01702     {
01703         es_out_Control( p_demux->out, ES_OUT_SET_ES, p_track->p_es );
01704     }
01705 
01706     p_track->i_chunk    = i_chunk;
01707     p_track->i_sample   = i_sample;
01708 
01709     return p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC;
01710 }
01711 
01712 /****************************************************************************
01713  * MP4_TrackCreate:
01714  ****************************************************************************
01715  * Parse track information and create all needed data to run a track
01716  * If it succeed b_ok is set to 1 else to 0
01717  ****************************************************************************/
01718 static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track,
01719                              MP4_Box_t *p_box_trak )
01720 {
01721     demux_sys_t *p_sys = p_demux->p_sys;
01722 
01723     MP4_Box_t *p_tkhd = MP4_BoxGet( p_box_trak, "tkhd" );
01724     MP4_Box_t *p_tref = MP4_BoxGet( p_box_trak, "tref" );
01725     MP4_Box_t *p_elst;
01726 
01727     MP4_Box_t *p_mdhd;
01728     MP4_Box_t *p_udta;
01729     MP4_Box_t *p_hdlr;
01730 
01731     MP4_Box_t *p_vmhd;
01732     MP4_Box_t *p_smhd;
01733 
01734     MP4_Box_t *p_drms;
01735 
01736     unsigned int i;
01737     char language[4];
01738 
01739     /* hint track unsupported */
01740 
01741     /* set default value (-> track unusable) */
01742     p_track->b_ok       = VLC_FALSE;
01743     p_track->b_enable   = VLC_FALSE;
01744     p_track->b_selected = VLC_FALSE;
01745 
01746     es_format_Init( &p_track->fmt, UNKNOWN_ES, 0 );
01747 
01748     if( !p_tkhd )
01749     {
01750         return;
01751     }
01752 
01753     /* do we launch this track by default ? */
01754     p_track->b_enable =
01755         ( ( p_tkhd->data.p_tkhd->i_flags&MP4_TRACK_ENABLED ) != 0 );
01756 
01757     p_track->i_track_ID = p_tkhd->data.p_tkhd->i_track_ID;
01758     p_track->i_width = p_tkhd->data.p_tkhd->i_width / 65536;
01759     p_track->i_height = p_tkhd->data.p_tkhd->i_height / 65536;
01760 
01761     if( p_tref )
01762     {
01763 /*        msg_Warn( p_demux, "unhandled box: tref --> FIXME" ); */
01764     }
01765 
01766     p_mdhd = MP4_BoxGet( p_box_trak, "mdia/mdhd" );
01767     p_hdlr = MP4_BoxGet( p_box_trak, "mdia/hdlr" );
01768 
01769     if( ( !p_mdhd )||( !p_hdlr ) )
01770     {
01771         return;
01772     }
01773 
01774     p_track->i_timescale = p_mdhd->data.p_mdhd->i_timescale;
01775 
01776     for( i = 0; i < 3; i++ )
01777     {
01778         language[i] = p_mdhd->data.p_mdhd->i_language[i];
01779     }
01780     language[3] = '\0';
01781 
01782     switch( p_hdlr->data.p_hdlr->i_handler_type )
01783     {
01784         case( FOURCC_soun ):
01785             if( !( p_smhd = MP4_BoxGet( p_box_trak, "mdia/minf/smhd" ) ) )
01786             {
01787                 return;
01788             }
01789             p_track->fmt.i_cat = AUDIO_ES;
01790             break;
01791 
01792         case( FOURCC_vide ):
01793             if( !( p_vmhd = MP4_BoxGet( p_box_trak, "mdia/minf/vmhd" ) ) )
01794             {
01795                 return;
01796             }
01797             p_track->fmt.i_cat = VIDEO_ES;
01798             break;
01799 
01800         case( FOURCC_text ):
01801         case( FOURCC_subp ):
01802         case( FOURCC_tx3g ):
01803             p_track->fmt.i_cat = SPU_ES;
01804             break;
01805 
01806         default:
01807             return;
01808     }
01809 
01810     p_track->i_elst = 0;
01811     p_track->i_elst_time = 0;
01812     if( ( p_track->p_elst = p_elst = MP4_BoxGet( p_box_trak, "edts/elst" ) ) )
01813     {
01814         MP4_Box_data_elst_t *elst = p_elst->data.p_elst;
01815         unsigned int i;
01816 
01817         msg_Warn( p_demux, "elst box found" );
01818         for( i = 0; i < elst->i_entry_count; i++ )
01819         {
01820             msg_Dbg( p_demux, "   - [%d] duration="I64Fd"ms media time="I64Fd
01821                      "ms) rate=%d.%d", i,
01822                      elst->i_segment_duration[i] * 1000 / p_sys->i_timescale,
01823                      elst->i_media_time[i] >= 0 ?
01824                      (int64_t)(elst->i_media_time[i] * 1000 / p_track->i_timescale) :
01825                      I64C(-1),
01826                      elst->i_media_rate_integer[i],
01827                      elst->i_media_rate_fraction[i] );
01828         }
01829     }
01830 
01831 
01832 /*  TODO
01833     add support for:
01834     p_dinf = MP4_BoxGet( p_minf, "dinf" );
01835 */
01836     if( !( p_track->p_stbl = MP4_BoxGet( p_box_trak,"mdia/minf/stbl" ) ) ||
01837         !( p_track->p_stsd = MP4_BoxGet( p_box_trak,"mdia/minf/stbl/stsd") ) )
01838     {
01839         return;
01840     }
01841 
01842     p_drms = MP4_BoxGet( p_track->p_stsd, "drms" );
01843     p_track->b_drms = p_drms != NULL;
01844     p_track->p_drms = p_track->b_drms ?
01845         p_drms->data.p_sample_soun->p_drms : NULL;
01846 
01847     /* Set language */
01848     if( strcmp( language, "```" ) && strcmp( language, "und" ) )
01849     {
01850         p_track->fmt.psz_language = strdup( language );
01851     }
01852 
01853     p_udta = MP4_BoxGet( p_box_trak, "udta" );
01854     if( p_udta )
01855     {
01856         MP4_Box_t *p_0xa9xxx;
01857         for( p_0xa9xxx = p_udta->p_first; p_0xa9xxx != NULL;
01858                  p_0xa9xxx = p_0xa9xxx->p_next )
01859         {
01860             switch( p_0xa9xxx->i_type )
01861             {
01862                 case FOURCC_0xa9nam:
01863                     p_track->fmt.psz_description =
01864                         strdup( p_0xa9xxx->data.p_0xa9xxx->psz_text );
01865                     break;
01866             }
01867         }
01868     }
01869 
01870     /* Create chunk index table and sample index table */
01871     if( TrackCreateChunksIndex( p_demux,p_track  ) ||
01872         TrackCreateSamplesIndex( p_demux, p_track ) )
01873     {
01874         return; /* cannot create chunks index */
01875     }
01876 
01877     p_track->i_chunk  = 0;
01878     p_track->i_sample = 0;
01879 
01880     /* now create es */
01881     if( TrackCreateES( p_demux,
01882                        p_track, p_track->i_chunk,
01883                        &p_track->p_es ) )
01884     {
01885         msg_Err( p_demux, "cannot create es for track[Id 0x%x]",
01886                  p_track->i_track_ID );
01887         return;
01888     }
01889 
01890 #if 0
01891     {
01892         int i;
01893         for( i = 0; i < p_track->i_chunk_count; i++ )
01894         {
01895             fprintf( stderr, "%-5d sample_count=%d pts=%lld\n",
01896                      i, p_track->chunk[i].i_sample_count,
01897                      p_track->chunk[i].i_first_dts );
01898 
01899         }
01900     }
01901 #endif
01902     p_track->b_ok = VLC_TRUE;
01903 }
01904 
01905 /****************************************************************************
01906  * MP4_TrackDestroy:
01907  ****************************************************************************
01908  * Destroy a track created by MP4_TrackCreate.
01909  ****************************************************************************/
01910 static void MP4_TrackDestroy( demux_t *p_demux, mp4_track_t *p_track )
01911 {
01912     unsigned int i_chunk;
01913 
01914     p_track->b_ok = VLC_FALSE;
01915     p_track->b_enable   = VLC_FALSE;
01916     p_track->b_selected = VLC_FALSE;
01917 
01918     es_format_Clean( &p_track->fmt );
01919 
01920     for( i_chunk = 0; i_chunk < p_track->i_chunk_count; i_chunk++ )
01921     {
01922         if( p_track->chunk )
01923         {
01924            FREE(p_track->chunk[i_chunk].p_sample_count_dts);
01925            FREE(p_track->chunk[i_chunk].p_sample_delta_dts );
01926 
01927            FREE(p_track->chunk[i_chunk].p_sample_count_pts);
01928            FREE(p_track->chunk[i_chunk].p_sample_offset_pts );
01929         }
01930     }
01931     FREE( p_track->chunk );
01932 
01933     if( !p_track->i_sample_size )
01934     {
01935         FREE( p_track->p_sample_size );
01936     }
01937 }
01938 
01939 static int MP4_TrackSelect( demux_t *p_demux, mp4_track_t *p_track,
01940                             mtime_t i_start )
01941 {
01942     if( !p_track->b_ok )
01943     {
01944         return VLC_EGENERIC;
01945     }
01946 
01947     if( p_track->b_selected )
01948     {
01949         msg_Warn( p_demux, "track[Id 0x%x] already selected",
01950                   p_track->i_track_ID );
01951         return VLC_SUCCESS;
01952     }
01953 
01954     return MP4_TrackSeek( p_demux, p_track, i_start );
01955 }
01956 
01957 static void MP4_TrackUnselect( demux_t *p_demux, mp4_track_t *p_track )
01958 {
01959     if( !p_track->b_ok )
01960     {
01961         return;
01962     }
01963 
01964     if( !p_track->b_selected )
01965     {
01966         msg_Warn( p_demux, "track[Id 0x%x] already unselected",
01967                   p_track->i_track_ID );
01968         return;
01969     }
01970     if( p_track->p_es )
01971     {
01972         es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE,
01973                         p_track->p_es, VLC_FALSE );
01974     }
01975 
01976     p_track->b_selected = VLC_FALSE;
01977 }
01978 
01979 static int MP4_TrackSeek( demux_t *p_demux, mp4_track_t *p_track,
01980                           mtime_t i_start )
01981 {
01982     uint32_t i_chunk;
01983     uint32_t i_sample;
01984 
01985     if( !p_track->b_ok )
01986     {
01987         return( VLC_EGENERIC );
01988     }
01989 
01990     p_track->b_selected = VLC_FALSE;
01991 
01992     if( TrackTimeToSampleChunk( p_demux, p_track, i_start,
01993                                 &i_chunk, &i_sample ) )
01994     {
01995         msg_Warn( p_demux, "cannot select track[Id 0x%x]",
01996                   p_track->i_track_ID );
01997         return( VLC_EGENERIC );
01998     }
01999 
02000     p_track->b_selected = VLC_TRUE;
02001 
02002     if( TrackGotoChunkSample( p_demux, p_track, i_chunk, i_sample ) ==
02003         VLC_SUCCESS )
02004     {
02005         p_track->b_selected = VLC_TRUE;
02006 
02007         es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
02008                         p_track->p_es, i_start );
02009     }
02010 
02011     return( p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC );
02012 }
02013 
02014 
02015 /*
02016  * 3 types: for audio
02017  * 
02018  */
02019 #define QT_V0_MAX_SAMPLES 1024
02020 static int MP4_TrackSampleSize( mp4_track_t *p_track )
02021 {
02022     int i_size;
02023     MP4_Box_data_sample_soun_t *p_soun;
02024 
02025     if( p_track->i_sample_size == 0 )
02026     {
02027         /* most simple case */
02028         return p_track->p_sample_size[p_track->i_sample];
02029     }
02030     if( p_track->fmt.i_cat != AUDIO_ES )
02031     {
02032         return p_track->i_sample_size;
02033     }
02034 
02035     p_soun = p_track->p_sample->data.p_sample_soun;
02036 
02037     if( p_soun->i_qt_version == 1 )
02038     {
02039         i_size = p_track->chunk[p_track->i_chunk].i_sample_count /
02040             p_soun->i_sample_per_packet * p_soun->i_bytes_per_frame;
02041     }
02042     else if( p_track->i_sample_size > 256 )
02043     {
02044         /* We do that so we don't read too much data
02045          * (in this case we are likely dealing with compressed data) */
02046         i_size = p_track->i_sample_size;
02047     }
02048     else
02049     {
02050         /* Read a bunch of samples at once */
02051         int i_samples = p_track->chunk[p_track->i_chunk].i_sample_count -
02052             ( p_track->i_sample -
02053               p_track->chunk[p_track->i_chunk].i_sample_first );
02054 
02055         i_samples = __MIN( QT_V0_MAX_SAMPLES, i_samples );
02056         i_size = i_samples * p_track->i_sample_size;
02057     }
02058 
02059     //fprintf( stderr, "size=%d\n", i_size );
02060     return i_size;
02061 }
02062 
02063 static uint64_t MP4_TrackGetPos( mp4_track_t *p_track )
02064 {
02065     unsigned int i_sample;
02066     uint64_t i_pos;
02067 
02068     i_pos = p_track->chunk[p_track->i_chunk].i_offset;
02069 
02070     if( p_track->i_sample_size )
02071     {
02072         MP4_Box_data_sample_soun_t *p_soun =
02073             p_track->p_sample->data.p_sample_soun;
02074 
02075         if( p_soun->i_qt_version == 0 )
02076         {
02077             i_pos += ( p_track->i_sample -
02078                        p_track->chunk[p_track->i_chunk].i_sample_first ) *
02079                      p_track->i_sample_size;
02080         }
02081         else
02082         {
02083             /* we read chunk by chunk */
02084             i_pos += 0;
02085         }
02086     }
02087     else
02088     {
02089         for( i_sample = p_track->chunk[p_track->i_chunk].i_sample_first;
02090              i_sample < p_track->i_sample; i_sample++ )
02091         {
02092             i_pos += p_track->p_sample_size[i_sample];
02093         }
02094     }
02095 
02096     return i_pos;
02097 }
02098 
02099 static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track )
02100 {
02101     if( p_track->fmt.i_cat == AUDIO_ES && p_track->i_sample_size != 0 )
02102     {
02103         MP4_Box_data_sample_soun_t *p_soun;
02104 
02105         p_soun = p_track->p_sample->data.p_sample_soun;
02106 
02107         if( p_soun->i_qt_version == 1 )
02108         {
02109             /* chunk by chunk */
02110             p_track->i_sample =
02111                 p_track->chunk[p_track->i_chunk].i_sample_first +
02112                 p_track->chunk[p_track->i_chunk].i_sample_count;
02113         }
02114         else if( p_track->i_sample_size > 256 )
02115         {
02116             /* We do that so we don't read too much data
02117              * (in this case we are likely dealing with compressed data) */
02118             p_track->i_sample += 1;
02119         }
02120         else
02121         {
02122             /* FIXME */
02123             p_track->i_sample += QT_V0_MAX_SAMPLES;
02124             if( p_track->i_sample >
02125                 p_track->chunk[p_track->i_chunk].i_sample_first +
02126                 p_track->chunk[p_track->i_chunk].i_sample_count )
02127             {
02128                 p_track->i_sample =
02129                     p_track->chunk[p_track->i_chunk].i_sample_first +
02130                     p_track->chunk[p_track->i_chunk].i_sample_count;
02131             }
02132         }
02133     }
02134     else
02135     {
02136         p_track->i_sample++;
02137     }
02138 
02139     if( p_track->i_sample >= p_track->i_sample_count )
02140         return VLC_EGENERIC;
02141 
02142     /* Have we changed chunk ? */
02143     if( p_track->i_sample >=
02144             p_track->chunk[p_track->i_chunk].i_sample_first +
02145             p_track->chunk[p_track->i_chunk].i_sample_count )
02146     {
02147         if( TrackGotoChunkSample( p_demux, p_track, p_track->i_chunk + 1,
02148                                   p_track->i_sample ) )
02149         {
02150             msg_Warn( p_demux, "track[0x%x] will be disabled "
02151                       "(cannot restart decoder)", p_track->i_track_ID );
02152             MP4_TrackUnselect( p_demux, p_track );
02153             return VLC_EGENERIC;
02154         }
02155     }
02156 
02157     /* Have we changed elst */
02158     if( p_track->p_elst && p_track->p_elst->data.p_elst->i_entry_count > 0 )
02159     {
02160         demux_sys_t *p_sys = p_demux->p_sys;
02161         MP4_Box_data_elst_t *elst = p_track->p_elst->data.p_elst;
02162         uint64_t i_mvt = MP4_TrackGetDTS( p_demux, p_track ) *
02163                         p_sys->i_timescale / (int64_t)1000000;
02164 
02165         if( (unsigned int)p_track->i_elst < elst->i_entry_count &&
02166             i_mvt >= p_track->i_elst_time +
02167                      elst->i_segment_duration[p_track->i_elst] )
02168         {
02169             MP4_TrackSetELST( p_demux, p_track,
02170                               MP4_TrackGetDTS( p_demux, p_track ) );
02171         }
02172     }
02173 
02174     return VLC_SUCCESS;
02175 }
02176 
02177 static void MP4_TrackSetELST( demux_t *p_demux, mp4_track_t *tk,
02178                               int64_t i_time )
02179 {
02180     demux_sys_t *p_sys = p_demux->p_sys;
02181     int         i_elst_last = tk->i_elst;
02182 
02183     /* handle elst (find the correct one) */
02184     tk->i_elst      = 0;
02185     tk->i_elst_time = 0;
02186     if( tk->p_elst && tk->p_elst->data.p_elst->i_entry_count > 0 )
02187     {
02188         MP4_Box_data_elst_t *elst = tk->p_elst->data.p_elst;
02189         int64_t i_mvt= i_time * p_sys->i_timescale / (int64_t)1000000;
02190 
02191         for( tk->i_elst = 0; (unsigned int)tk->i_elst < elst->i_entry_count; tk->i_elst++ )
02192         {
02193             mtime_t i_dur = elst->i_segment_duration[tk->i_elst];
02194 
02195             if( tk->i_elst_time <= i_mvt && i_mvt < tk->i_elst_time + i_dur )
02196             {
02197                 break;
02198             }
02199             tk->i_elst_time += i_dur;
02200         }
02201 
02202         if( (unsigned int)tk->i_elst >= elst->i_entry_count )
02203         {
02204             /* msg_Dbg( p_demux, "invalid number of entry in elst" ); */
02205             tk->i_elst = elst->i_entry_count - 1;
02206             tk->i_elst_time -= elst->i_segment_duration[tk->i_elst];
02207         }
02208 
02209         if( elst->i_media_time[tk->i_elst] < 0 )
02210         {
02211             /* track offset */
02212             tk->i_elst_time += elst->i_segment_duration[tk->i_elst];
02213         }
02214     }
02215     if( i_elst_last != tk->i_elst )
02216     {
02217         msg_Warn( p_demux, "elst old=%d new=%d", i_elst_last, tk->i_elst );
02218     }
02219 }

Generated on Tue Dec 20 10:14:34 2005 for vlc-0.8.4a by  doxygen 1.4.2