X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Fmp4%2Fmp4.c;h=df99e727f01b7cbb457ab4694f042c31e7d27007;hb=597e34b81febddfabf45e5d821e99abd109fa94b;hp=76aa37c06d37e4aa1125ccdd32ce09f337eac28c;hpb=8ebcdb5e7b5826d139d4fde9a40b31b1590aebaf;p=vlc diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c index 76aa37c06d..df99e727f0 100644 --- a/modules/demux/mp4/mp4.c +++ b/modules/demux/mp4/mp4.c @@ -1,8 +1,8 @@ /***************************************************************************** * mp4.c : MP4 file input module for vlc ***************************************************************************** - * Copyright (C) 2001-2004 the VideoLAN team - * $Id$ + * Copyright (C) 2001-2004, 2010 the VideoLAN team + * * Authors: Laurent Aimar * * This program is free software; you can redistribute it and/or modify @@ -31,16 +31,13 @@ #include #include - #include -#include -#include -#include -#include +#include /* EnsureUTF8 */ +#include /* vlc_meta_t, vlc_meta_ */ #include #include "libmp4.h" -#include "drms.h" +#include "id3genres.h" /* for ATOM_gnre */ /***************************************************************************** * Module descriptor @@ -53,7 +50,7 @@ vlc_module_begin () set_subcategory( SUBCAT_INPUT_DEMUX ) set_description( N_("MP4 stream demuxer") ) set_shortname( N_("MP4") ) - set_capability( "demux", 242 ) + set_capability( "demux", 240 ) set_callbacks( Open, Close ) vlc_module_end () @@ -65,84 +62,6 @@ static int DemuxRef( demux_t *p_demux ){ (void)p_demux; return 0;} static int Seek ( demux_t *, mtime_t ); static int Control ( demux_t *, int, va_list ); -/* Contain all information about a chunk */ -typedef struct -{ - uint64_t i_offset; /* absolute position of this chunk in the file */ - uint32_t i_sample_description_index; /* index for SampleEntry to use */ - uint32_t i_sample_count; /* how many samples in this chunk */ - uint32_t i_sample_first; /* index of the first sample in this chunk */ - - /* now provide way to calculate pts, dts, and offset without too - much memory and with fast access */ - - /* with this we can calculate dts/pts without waste memory */ - uint64_t i_first_dts; - uint32_t *p_sample_count_dts; - uint32_t *p_sample_delta_dts; /* dts delta */ - - uint32_t *p_sample_count_pts; - int32_t *p_sample_offset_pts; /* pts-dts */ - - /* TODO if needed add pts - but quickly *add* support for edts and seeking */ - -} mp4_chunk_t; - - /* Contain all needed information for read all track with vlc */ -typedef struct -{ - unsigned int i_track_ID;/* this should be unique */ - - int b_ok; /* The track is usable */ - int b_enable; /* is the trak enable by default */ - bool b_selected; /* is the trak being played */ - bool b_chapter; /* True when used for chapter only */ - - bool b_mac_encoding; - - es_format_t fmt; - es_out_id_t *p_es; - - /* display size only ! */ - int i_width; - int i_height; - - /* more internal data */ - uint64_t i_timescale; /* time scale for this track only */ - - /* elst */ - int i_elst; /* current elst */ - int64_t i_elst_time; /* current elst start time (in movie time scale)*/ - MP4_Box_t *p_elst; /* elst (could be NULL) */ - - /* give the next sample to read, i_chunk is to find quickly where - the sample is located */ - uint32_t i_sample; /* next sample to read */ - uint32_t i_chunk; /* chunk where next sample is stored */ - /* total count of chunk and sample */ - uint32_t i_chunk_count; - uint32_t i_sample_count; - - mp4_chunk_t *chunk; /* always defined for each chunk */ - - /* sample size, p_sample_size defined only if i_sample_size == 0 - else i_sample_size is size for all sample */ - uint32_t i_sample_size; - uint32_t *p_sample_size; /* XXX perhaps add file offset if take - too much time to do sumations each time*/ - - MP4_Box_t *p_stbl; /* will contain all timing information */ - MP4_Box_t *p_stsd; /* will contain all data to initialize decoder */ - MP4_Box_t *p_sample;/* point on actual sdsd */ - - bool b_drms; - void *p_drms; - MP4_Box_t *p_skcr; - -} mp4_track_t; - - struct demux_sys_t { MP4_Box_t *p_root; /* container for the whole file */ @@ -155,6 +74,7 @@ struct demux_sys_t uint64_t i_duration; /* movie duration */ unsigned int i_tracks; /* number of tracks */ mp4_track_t *track; /* array of track */ + float f_fps; /* number of frame per seconds */ /* */ MP4_Box_t *p_tref_chap; @@ -279,30 +199,34 @@ static int Open( vlc_object_t * p_this ) bool b_enabled_es; /* A little test to see if it could be a mp4 */ - if( stream_Peek( p_demux->s, &p_peek, 8 ) < 8 ) return VLC_EGENERIC; + if( stream_Peek( p_demux->s, &p_peek, 11 ) < 11 ) return VLC_EGENERIC; switch( VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] ) ) { - case FOURCC_ftyp: - case FOURCC_moov: - case FOURCC_foov: - case FOURCC_moof: - case FOURCC_mdat: - case FOURCC_udta: - case FOURCC_free: - case FOURCC_skip: - case FOURCC_wide: + case ATOM_moov: + case ATOM_foov: + case ATOM_moof: + case ATOM_mdat: + case ATOM_udta: + case ATOM_free: + case ATOM_skip: + case ATOM_wide: case VLC_FOURCC( 'p', 'n', 'o', 't' ): break; + case ATOM_ftyp: + /* We don't yet support f4v, but avformat does. */ + if( p_peek[8] == 'f' && p_peek[9] == '4' && p_peek[10] == 'v' ) + return VLC_EGENERIC; + break; default: return VLC_EGENERIC; } /* I need to seek */ - stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_seekable ); + stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_seekable ); if( !b_seekable ) { - msg_Warn( p_demux, "MP4 plugin discarded (unseekable)" ); + msg_Warn( p_demux, "MP4 plugin discarded (not fastseekable)" ); return VLC_EGENERIC; } @@ -311,8 +235,7 @@ static int Open( vlc_object_t * p_this ) p_demux->pf_control = Control; /* create our structure that will contains all data */ - p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); - memset( p_sys, 0, sizeof( demux_sys_t ) ); + p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) ); /* Now load all boxes ( except raw data ) */ if( ( p_sys->p_root = MP4_BoxGetRoot( p_demux->s ) ) == NULL ) @@ -327,11 +250,29 @@ static int Open( vlc_object_t * p_this ) { switch( p_ftyp->data.p_ftyp->i_major_brand ) { - case( FOURCC_isom ): + case( ATOM_isom ): msg_Dbg( p_demux, "ISO Media file (isom) version %d.", p_ftyp->data.p_ftyp->i_minor_version ); break; + case( ATOM_3gp4 ): + case( VLC_FOURCC( '3', 'g', 'p', '5' ) ): + case( VLC_FOURCC( '3', 'g', 'p', '6' ) ): + case( VLC_FOURCC( '3', 'g', 'p', '7' ) ): + msg_Dbg( p_demux, "3GPP Media file Release: %c", +#ifdef WORDS_BIGENDIAN + p_ftyp->data.p_ftyp->i_major_brand +#else + p_ftyp->data.p_ftyp->i_major_brand >> 24 +#endif + ); + break; + case( VLC_FOURCC( 'q', 't', ' ', ' ') ): + msg_Dbg( p_demux, "Apple QuickTime file" ); + break; + case( VLC_FOURCC( 'i', 's', 'm', 'l') ): + msg_Dbg( p_demux, "PIFF (= isml = fMP4) file" ); + break; default: msg_Dbg( p_demux, "unrecognized major file specification (%4.4s).", @@ -351,11 +292,16 @@ static int Open( vlc_object_t * p_this ) if( !p_foov ) { - msg_Err( p_demux, "MP4 plugin discarded (no moov box)" ); - goto error; + /* search also for moof box used by smoothstreaming */ + p_foov = MP4_BoxGet( p_sys->p_root, "/moof" ); + if( !p_foov ) + { + msg_Err( p_demux, "MP4 plugin discarded (no moov,foov,moof box)" ); + goto error; + } } /* we have a free box as a moov, rename it */ - p_foov->i_type = FOURCC_moov; + p_foov->i_type = ATOM_moov; } if( ( p_rmra = MP4_BoxGet( p_sys->p_root, "/moov/rmra" ) ) ) @@ -368,6 +314,8 @@ static int Open( vlc_object_t * p_this ) input_thread_t *p_input = demux_GetParentInput( p_demux ); input_item_t *p_current = input_GetItem( p_input ); + input_item_node_t *p_subitems = input_item_node_Create( p_current ); + for( i = 0; i < i_count; i++ ) { MP4_Box_t *p_rdrf = MP4_BoxGet( p_rmra, "rmda[%d]/rdrf", i ); @@ -398,24 +346,29 @@ static int Open( vlc_object_t * p_this ) else { char *psz_absolute; - char *psz_path = strdup( p_demux->psz_path ); + char *psz_path = strdup( p_demux->psz_location ); char *end = strrchr( psz_path, '/' ); if( end ) end[1] = '\0'; else *psz_path = '\0'; if( asprintf( &psz_absolute, "%s://%s%s", p_demux->psz_access, psz_path, psz_ref ) < 0 ) + { + free( psz_ref ); + free( psz_path ); + vlc_object_release( p_input) ; return VLC_ENOMEM; + } free( psz_ref ); psz_ref = psz_absolute; free( psz_path ); } msg_Dbg( p_demux, "adding ref = `%s'", psz_ref ); - input_item_t *p_input = input_item_New( p_demux, psz_ref, NULL ); - input_item_CopyOptions( p_current, p_input ); - input_item_AddSubItem( p_current, p_input ); - vlc_gc_decref( p_input ); + input_item_t *p_item = input_item_New( psz_ref, NULL ); + input_item_CopyOptions( p_current, p_item ); + input_item_node_AppendItem( p_subitems, p_item ); + vlc_gc_decref( p_item ); } else { @@ -424,6 +377,7 @@ static int Open( vlc_object_t * p_this ) } free( psz_ref ); } + input_item_node_PostAndDelete( p_subitems ); vlc_object_release( p_input ); } @@ -465,7 +419,6 @@ static int Open( vlc_object_t * p_this ) p_sys->track = calloc( p_sys->i_tracks, sizeof( mp4_track_t ) ); if( p_sys->track == NULL ) goto error; - memset( p_sys->track, 0, p_sys->i_tracks * sizeof( mp4_track_t ) ); /* Search the first chap reference (like quicktime) and * check that at least 1 stream is enabled */ @@ -485,7 +438,7 @@ static int Open( vlc_object_t * p_this ) p_sys->p_tref_chap = p_chap; } - /* now process each track and extract all usefull information */ + /* now process each track and extract all useful information */ for( i = 0; i < p_sys->i_tracks; i++ ) { p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[%d]", i ); @@ -609,7 +562,7 @@ static int Demux( demux_t *p_demux ) MP4_UpdateSeekpoint( p_demux ); /* first wait for the good time to read a packet */ - es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr + 1 ); + es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_pcr ); p_sys->i_pcr = MP4_GetMoviePTS( p_sys ); @@ -655,33 +608,12 @@ static int Demux( demux_t *p_demux ) break; } - if( tk->b_drms && tk->p_drms ) - { - if( tk->p_skcr ) - { - uint32_t p_key[4]; - drms_get_p_key( tk->p_drms, p_key ); - - for( size_t i_pos = tk->p_skcr->data.p_skcr->i_init; i_pos < p_block->i_buffer; ) - { - int n = __MIN( tk->p_skcr->data.p_skcr->i_encr, p_block->i_buffer - i_pos ); - drms_decrypt( tk->p_drms, (uint32_t*)&p_block->p_buffer[i_pos], n, p_key ); - i_pos += n; - i_pos += __MIN( tk->p_skcr->data.p_skcr->i_decr, p_block->i_buffer - i_pos ); - } - } - else - { - drms_decrypt( tk->p_drms, (uint32_t*)p_block->p_buffer, - p_block->i_buffer, NULL ); - } - } else if( tk->fmt.i_cat == SPU_ES ) { - if( tk->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) && + if( tk->fmt.i_codec == VLC_CODEC_SUBT && p_block->i_buffer >= 2 ) { - uint16_t i_size = GetWBE( p_block->p_buffer ); + size_t i_size = GetWBE( p_block->p_buffer ); if( i_size + 2 <= p_block->i_buffer ) { @@ -706,7 +638,7 @@ static int Demux( demux_t *p_demux ) } } /* dts */ - p_block->i_dts = MP4_TrackGetDTS( p_demux, tk ) + 1; + p_block->i_dts = VLC_TS_0 + MP4_TrackGetDTS( p_demux, tk ); /* pts */ i_delta = MP4_TrackGetPTSDelta( tk ); if( i_delta != -1 ) @@ -714,10 +646,9 @@ static int Demux( demux_t *p_demux ) else if( tk->fmt.i_cat != VIDEO_ES ) p_block->i_pts = p_block->i_dts; else - p_block->i_pts = 0; + p_block->i_pts = VLC_TS_INVALID; - if( !tk->b_drms || ( tk->b_drms && tk->p_drms ) ) - es_out_Send( p_demux->out, tk->p_es, p_block ); + es_out_Send( p_demux->out, tk->p_es, p_block ); } /* Next sample */ @@ -758,7 +689,7 @@ static int Seek( demux_t *p_demux, mtime_t i_date ) demux_sys_t *p_sys = p_demux->p_sys; unsigned int i_track; - /* First update update global time */ + /* First update global time */ p_sys->i_time = i_date * p_sys->i_timescale / 1000000; p_sys->i_pcr = i_date; @@ -837,8 +768,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) return VLC_SUCCESS; case DEMUX_GET_FPS: - msg_Warn( p_demux, "DEMUX_GET_FPS unimplemented !!" ); - return VLC_EGENERIC; + pf = (double*)va_arg( args, double* ); + *pf = p_sys->f_fps; + return VLC_SUCCESS; case DEMUX_GET_META: { @@ -871,70 +803,124 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) /* XXX Becarefull p_udta can have box that are not 0xa9xx */ switch( p_0xa9xxx->i_type ) { - case FOURCC_0xa9nam: /* Full name */ + case ATOM_0xa9nam: /* Full name */ SET( vlc_meta_SetTitle ); break; - case FOURCC_0xa9aut: + case ATOM_0xa9aut: SET( vlc_meta_SetArtist ); break; - case FOURCC_0xa9ART: + case ATOM_0xa9ART: SET( vlc_meta_SetArtist ); break; - case FOURCC_0xa9cpy: + case ATOM_0xa9cpy: SET( vlc_meta_SetCopyright ); break; - case FOURCC_0xa9day: /* Creation Date */ + case ATOM_0xa9day: /* Creation Date */ SET( vlc_meta_SetDate ); break; - case FOURCC_0xa9des: /* Description */ + case ATOM_0xa9des: /* Description */ SET( vlc_meta_SetDescription ); break; - case FOURCC_0xa9gen: /* Genre */ + case ATOM_0xa9gen: /* Genre */ SET( vlc_meta_SetGenre ); break; - case FOURCC_0xa9alb: /* Album */ + case ATOM_gnre: + if( p_0xa9xxx->data.p_gnre->i_genre <= NUM_GENRES ) + vlc_meta_SetGenre( p_meta, ppsz_genres[p_0xa9xxx->data.p_gnre->i_genre - 1] ); + break; + + case ATOM_0xa9alb: /* Album */ SET( vlc_meta_SetAlbum ); break; - case FOURCC_0xa9trk: /* Track */ + case ATOM_0xa9trk: /* Track */ SET( vlc_meta_SetTrackNum ); break; - - case FOURCC_0xa9cmt: /* Commment */ + case ATOM_trkn: + { + char psz_trck[11]; + snprintf( psz_trck, sizeof( psz_trck ), "%i", + p_0xa9xxx->data.p_trkn->i_track_number ); + vlc_meta_SetTrackNum( p_meta, psz_trck ); + snprintf( psz_trck, sizeof( psz_trck ), "%i", + p_0xa9xxx->data.p_trkn->i_track_total ); + vlc_meta_Set( p_meta, vlc_meta_TrackTotal, psz_trck ); + break; + } + case ATOM_0xa9cmt: /* Commment */ SET( vlc_meta_SetDescription ); break; - case FOURCC_0xa9url: /* URL */ + case ATOM_0xa9url: /* URL */ SET( vlc_meta_SetURL ); break; - case FOURCC_0xa9enc: /* Encoded By */ + case ATOM_0xa9too: /* Encoder Tool */ + case ATOM_0xa9enc: /* Encoded By */ SET( vlc_meta_SetEncodedBy ); break; - - case FOURCC_0xa9swr: - case FOURCC_0xa9inf: /* Information */ - case FOURCC_0xa9dir: /* Director */ - case FOURCC_0xa9dis: /* Disclaimer */ - case FOURCC_0xa9req: /* Requirements */ - case FOURCC_0xa9fmt: /* Original Format */ - case FOURCC_0xa9dsa: /* Display Source As */ - case FOURCC_0xa9hst: /* Host Computer */ - case FOURCC_0xa9prd: /* Producer */ - case FOURCC_0xa9prf: /* Performers */ - case FOURCC_0xa9ope: /* Original Performer */ - case FOURCC_0xa9src: /* Providers Source Content */ - case FOURCC_0xa9wrt: /* Writer */ - case FOURCC_0xa9com: /* Composer */ - case FOURCC_WLOC: /* Window Location */ - /* TODO one day, but they aren't really meaningfull */ + + case ATOM_0xa9pub: + SET( vlc_meta_SetPublisher ); break; -#undef SET default: break; } +#undef SET + static const struct { uint32_t xa9_type; char metadata[25]; } xa9typetoextrameta[] = + { + { ATOM_0xa9wrt, N_("Writer") }, + { ATOM_0xa9com, N_("Composer") }, + { ATOM_0xa9prd, N_("Producer") }, + { ATOM_0xa9inf, N_("Information") }, + { ATOM_0xa9dir, N_("Director") }, + { ATOM_0xa9dis, N_("Disclaimer") }, + { ATOM_0xa9req, N_("Requirements") }, + { ATOM_0xa9fmt, N_("Original Format") }, + { ATOM_0xa9dsa, N_("Display Source As") }, + { ATOM_0xa9hst, N_("Host Computer") }, + { ATOM_0xa9prf, N_("Performers") }, + { ATOM_0xa9ope, N_("Original Performer") }, + { ATOM_0xa9src, N_("Providers Source Content") }, + { ATOM_0xa9wrn, N_("Warning") }, + { ATOM_0xa9swr, N_("Software") }, + { ATOM_0xa9lyr, N_("Lyrics") }, + { ATOM_0xa9mak, N_("Record Company") }, + { ATOM_0xa9mod, N_("Model") }, + { ATOM_0xa9PRD, N_("Product") }, + { ATOM_0xa9grp, N_("Grouping") }, + { ATOM_0xa9gen, N_("Genre") }, + { ATOM_0xa9st3, N_("Sub-Title") }, + { ATOM_0xa9arg, N_("Arranger") }, + { ATOM_0xa9ard, N_("Art Director") }, + { ATOM_0xa9cak, N_("Copyright Acknowledgement") }, + { ATOM_0xa9con, N_("Conductor") }, + { ATOM_0xa9des, N_("Song Description") }, + { ATOM_0xa9lnt, N_("Liner Notes") }, + { ATOM_0xa9phg, N_("Phonogram Rights") }, + { ATOM_0xa9pub, N_("Publisher") }, + { ATOM_0xa9sne, N_("Sound Engineer") }, + { ATOM_0xa9sol, N_("Soloist") }, + { ATOM_0xa9thx, N_("Thanks") }, + { ATOM_0xa9xpd, N_("Executive Producer") }, + { 0, "" }, + }; + for( unsigned i = 0; xa9typetoextrameta[i].xa9_type; i++ ) + { + if( p_0xa9xxx->i_type == xa9typetoextrameta[i].xa9_type ) + { + char *psz_utf = strdup( p_0xa9xxx->data.p_0xa9xxx->psz_text ? p_0xa9xxx->data.p_0xa9xxx->psz_text : "" ); + if( psz_utf ) + { + EnsureUTF8( psz_utf ); + vlc_meta_AddExtra( p_meta, _(xa9typetoextrameta[i].metadata), psz_utf ); + free( psz_utf ); + } + break; + } + } } return VLC_SUCCESS; } @@ -975,6 +961,8 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) case DEMUX_SET_GROUP: case DEMUX_HAS_UNSUPPORTED_META: case DEMUX_GET_ATTACHMENTS: + case DEMUX_GET_PTS_DELAY: + case DEMUX_CAN_RECORD: return VLC_EGENERIC; default: @@ -1085,7 +1073,7 @@ static void LoadChapter( demux_t *p_demux ) { mp4_track_t *tk = &p_sys->track[j]; if( tk->b_ok && tk->i_track_ID == p_chap->i_track_ID[i] && - tk->fmt.i_cat == SPU_ES && tk->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) ) + tk->fmt.i_cat == SPU_ES && tk->fmt.i_codec == VLC_CODEC_SUBT ) break; } if( j < p_sys->i_tracks ) @@ -1095,6 +1083,13 @@ static void LoadChapter( demux_t *p_demux ) } } } + + /* Add duration if titles are enabled */ + if( p_sys->p_title ) + { + p_sys->p_title->i_length = (uint64_t)1000000 * + (uint64_t)p_sys->i_duration / (uint64_t)p_sys->i_timescale; + } } /* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */ @@ -1199,7 +1194,7 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, int64_t i_index; int64_t i_index_sample_used; - int64_t i_last_dts; + int64_t i_next_dts; /* Find stsz * Gives the sample size for each samples. There is also a stz2 table @@ -1254,15 +1249,16 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, * for fast research (problem with raw stream where a sample is sometime * just channels*bits_per_sample/8 */ - i_last_dts = 0; + i_next_dts = 0; i_index = 0; i_index_sample_used = 0; for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ ) { mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk]; int64_t i_entry, i_sample_count, i; - /* save last dts */ - ck->i_first_dts = i_last_dts; + /* save first dts */ + ck->i_first_dts = i_next_dts; + ck->i_last_dts = i_next_dts; /* count how many entries are needed for this chunk * for p_sample_delta_dts and p_sample_count_dts */ @@ -1299,11 +1295,12 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, i_index_sample_used += i_used; i_sample_count -= i_used; + i_next_dts += i_used * stts->i_sample_delta[i_index]; ck->p_sample_count_dts[i] = i_used; ck->p_sample_delta_dts[i] = stts->i_sample_delta[i_index]; - - i_last_dts += i_used * ck->p_sample_delta_dts[i]; + if( i_used > 0 ) + ck->i_last_dts = i_next_dts - ck->p_sample_delta_dts[i]; if( i_index_sample_used >= stts->i_sample_count[i_index] ) { @@ -1381,11 +1378,53 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, msg_Dbg( p_demux, "track[Id 0x%x] read %d samples length:%"PRId64"s", p_demux_track->i_track_ID, p_demux_track->i_sample_count, - i_last_dts / p_demux_track->i_timescale ); + i_next_dts / p_demux_track->i_timescale ); return VLC_SUCCESS; } +/** + * It computes the sample rate for a video track using the given sample + * description index + */ +static void TrackGetESSampleRate( unsigned *pi_num, unsigned *pi_den, + const mp4_track_t *p_track, + unsigned i_sd_index, + unsigned i_chunk ) +{ + *pi_num = 0; + *pi_den = 0; + + if( p_track->i_chunk_count <= 0 ) + return; + + /* */ + const mp4_chunk_t *p_chunk = &p_track->chunk[i_chunk]; + while( p_chunk > &p_track->chunk[0] && + p_chunk[-1].i_sample_description_index == i_sd_index ) + { + p_chunk--; + } + + uint64_t i_sample = 0; + uint64_t i_first_dts = p_chunk->i_first_dts; + uint64_t i_last_dts; + do + { + i_sample += p_chunk->i_sample_count; + i_last_dts = p_chunk->i_last_dts; + p_chunk++; + } + while( p_chunk < &p_track->chunk[p_track->i_chunk_count] && + p_chunk->i_sample_description_index == i_sd_index ); + + if( i_sample > 1 && i_first_dts < i_last_dts ) + vlc_ureduce( pi_num, pi_den, + ( i_sample - 1) * p_track->i_timescale, + i_last_dts - i_first_dts, + UINT16_MAX); +} + /* * TrackCreateES: * Create ES and PES to init decoder if needed, for a track starting at i_chunk @@ -1393,15 +1432,18 @@ static int TrackCreateSamplesIndex( demux_t *p_demux, static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, unsigned int i_chunk, es_out_id_t **pp_es ) { + const unsigned i_sample_description_index = + p_track->chunk[i_chunk].i_sample_description_index; MP4_Box_t *p_sample; MP4_Box_t *p_esds; - MP4_Box_t *p_box; MP4_Box_t *p_frma; + MP4_Box_t *p_enda; + MP4_Box_t *p_pasp; if( pp_es ) *pp_es = NULL; - if( !p_track->chunk[i_chunk].i_sample_description_index ) + if( !i_sample_description_index ) { msg_Warn( p_demux, "invalid SampleEntry index (track[Id 0x%x])", p_track->i_track_ID ); @@ -1409,7 +1451,7 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, } p_sample = MP4_BoxGet( p_track->p_stsd, "[%d]", - p_track->chunk[i_chunk].i_sample_description_index - 1 ); + i_sample_description_index - 1 ); if( !p_sample || ( !p_sample->data.p_data && p_track->fmt.i_cat != SPU_ES ) ) @@ -1428,58 +1470,11 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, p_sample->i_type = p_frma->data.p_frma->i_type; } - if( p_track->fmt.i_cat == AUDIO_ES && ( p_track->i_sample_size == 1 || p_track->i_sample_size == 2 ) ) - { - MP4_Box_data_sample_soun_t *p_soun; - - p_soun = p_sample->data.p_sample_soun; + p_enda = MP4_BoxGet( p_sample, "wave/enda" ); + if( !p_enda ) + p_enda = MP4_BoxGet( p_sample, "enda" ); - if( p_soun->i_qt_version == 0 ) - { - switch( p_sample->i_type ) - { - case VLC_FOURCC( 'i', 'm', 'a', '4' ): - p_soun->i_qt_version = 1; - p_soun->i_sample_per_packet = 64; - p_soun->i_bytes_per_packet = 34; - p_soun->i_bytes_per_frame = 34 * p_soun->i_channelcount; - p_soun->i_bytes_per_sample = 2; - break; - case VLC_FOURCC( 'M', 'A', 'C', '3' ): - p_soun->i_qt_version = 1; - p_soun->i_sample_per_packet = 6; - p_soun->i_bytes_per_packet = 2; - p_soun->i_bytes_per_frame = 2 * p_soun->i_channelcount; - p_soun->i_bytes_per_sample = 2; - break; - case VLC_FOURCC( 'M', 'A', 'C', '6' ): - p_soun->i_qt_version = 1; - p_soun->i_sample_per_packet = 12; - p_soun->i_bytes_per_packet = 2; - p_soun->i_bytes_per_frame = 2 * p_soun->i_channelcount; - p_soun->i_bytes_per_sample = 2; - break; - case VLC_FOURCC( 'a', 'l', 'a', 'w' ): - case VLC_FOURCC( 'u', 'l', 'a', 'w' ): - p_soun->i_samplesize = 8; - break; - case VLC_FOURCC( 'N', 'O', 'N', 'E' ): - case VLC_FOURCC( 'r', 'a', 'w', ' ' ): - case VLC_FOURCC( 't', 'w', 'o', 's' ): - case VLC_FOURCC( 's', 'o', 'w', 't' ): - /* What would be the fun if you could trust the .mov */ - p_track->i_sample_size = ((p_soun->i_samplesize+7)/8) * p_soun->i_channelcount; - break; - default: - break; - } - - } - else if( p_soun->i_qt_version == 1 && p_soun->i_sample_per_packet <= 0 ) - { - p_soun->i_qt_version = 0; - } - } + p_pasp = MP4_BoxGet( p_sample, "pasp" ); /* */ switch( p_track->fmt.i_cat ) @@ -1500,23 +1495,39 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, if( p_track->i_width > 0 && p_track->i_height > 0 && /* Work-around buggy muxed files */ p_sample->data.p_sample_vide->i_width != p_track->i_width ) - p_track->fmt.video.i_aspect = - VOUT_ASPECT_FACTOR * p_track->i_width / p_track->i_height; + { + p_track->fmt.video.i_sar_num = p_track->i_width * p_track->fmt.video.i_height; + p_track->fmt.video.i_sar_den = p_track->i_height * p_track->fmt.video.i_width; + } + if( p_pasp && p_pasp->data.p_pasp->i_horizontal_spacing > 0 && + p_pasp->data.p_pasp->i_vertical_spacing > 0 ) + { + p_track->fmt.video.i_sar_num = p_pasp->data.p_pasp->i_horizontal_spacing; + p_track->fmt.video.i_sar_den = p_pasp->data.p_pasp->i_vertical_spacing; + } /* Support for cropping (eg. in H263 files) */ p_track->fmt.video.i_visible_width = p_track->fmt.video.i_width; p_track->fmt.video.i_visible_height = p_track->fmt.video.i_height; /* Frame rate */ - p_track->fmt.video.i_frame_rate = p_track->i_timescale; - p_track->fmt.video.i_frame_rate_base = 1; - - if( p_track->fmt.video.i_frame_rate && - (p_box = MP4_BoxGet( p_track->p_stbl, "stts" )) && - p_box->data.p_stts->i_entry_count >= 1 ) - { - p_track->fmt.video.i_frame_rate_base = - p_box->data.p_stts->i_sample_delta[0]; + TrackGetESSampleRate( &p_track->fmt.video.i_frame_rate, + &p_track->fmt.video.i_frame_rate_base, + p_track, i_sample_description_index, i_chunk ); + p_demux->p_sys->f_fps = (float)p_track->fmt.video.i_frame_rate / + (float)p_track->fmt.video.i_frame_rate_base; + + /* Rotation */ + switch( (int)p_track->f_rotation ) { + case 90: + p_track->fmt.video.orientation = ORIENT_ROTATED_90; + break; + case 180: + p_track->fmt.video.orientation = ORIENT_ROTATED_180; + break; + case 270: + p_track->fmt.video.orientation = ORIENT_ROTATED_270; + break; } break; @@ -1532,11 +1543,87 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, p_track->fmt.audio.i_bitspersample = p_sample->data.p_sample_soun->i_samplesize; + if( ( p_track->i_sample_size == 1 || p_track->i_sample_size == 2 ) ) + { + MP4_Box_data_sample_soun_t *p_soun; + p_soun = p_sample->data.p_sample_soun; + + if( p_soun->i_qt_version == 0 ) + { + switch( p_sample->i_type ) + { + case VLC_FOURCC( 'i', 'm', 'a', '4' ): + p_soun->i_qt_version = 1; + p_soun->i_sample_per_packet = 64; + p_soun->i_bytes_per_packet = 34; + p_soun->i_bytes_per_frame = 34 * p_soun->i_channelcount; + p_soun->i_bytes_per_sample = 2; + break; + case VLC_FOURCC( 'M', 'A', 'C', '3' ): + p_soun->i_qt_version = 1; + p_soun->i_sample_per_packet = 6; + p_soun->i_bytes_per_packet = 2; + p_soun->i_bytes_per_frame = 2 * p_soun->i_channelcount; + p_soun->i_bytes_per_sample = 2; + break; + case VLC_FOURCC( 'M', 'A', 'C', '6' ): + p_soun->i_qt_version = 1; + p_soun->i_sample_per_packet = 12; + p_soun->i_bytes_per_packet = 2; + p_soun->i_bytes_per_frame = 2 * p_soun->i_channelcount; + p_soun->i_bytes_per_sample = 2; + break; + case VLC_FOURCC( 'a', 'l', 'a', 'w' ): + case VLC_FOURCC( 'u', 'l', 'a', 'w' ): + p_soun->i_samplesize = 8; + p_track->i_sample_size = p_soun->i_channelcount; + break; + case VLC_FOURCC( 'N', 'O', 'N', 'E' ): + case VLC_FOURCC( 'r', 'a', 'w', ' ' ): + case VLC_FOURCC( 't', 'w', 'o', 's' ): + case VLC_FOURCC( 's', 'o', 'w', 't' ): + /* What would be the fun if you could trust the .mov */ + p_track->i_sample_size = ((p_soun->i_samplesize+7)/8) * p_soun->i_channelcount; + break; + default: + break; + } + + } + else if( p_soun->i_qt_version == 1 && p_soun->i_sample_per_packet <= 0 ) + { + p_soun->i_qt_version = 0; + } + } + else if( p_sample->data.p_sample_soun->i_qt_version == 1 ) + { + MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun; + + switch( p_sample->i_type ) + { + case( VLC_FOURCC( '.', 'm', 'p', '3' ) ): + case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ): + { + if( p_track->i_sample_size > 1 ) + p_soun->i_qt_version = 0; + break; + } + case( VLC_FOURCC( 'a', 'c', '-', '3' ) ): + case( VLC_FOURCC( 'e', 'c', '-', '3' ) ): + case( VLC_FOURCC( 'm', 's', 0x20, 0x00 ) ): + p_soun->i_qt_version = 0; + break; + default: + break; + } + } + if( p_track->i_sample_size != 0 && - p_sample->data.p_sample_soun->i_qt_version == 1 && p_sample->data.p_sample_soun->i_sample_per_packet <= 0 ) + p_sample->data.p_sample_soun->i_qt_version == 1 && + p_sample->data.p_sample_soun->i_sample_per_packet <= 0 ) { - msg_Err( p_demux, "Invalid sample per packet value for qt_version 1" ); - return VLC_EGENERIC; + msg_Err( p_demux, "Invalid sample per packet value for qt_version 1. Broken muxer!" ); + p_sample->data.p_sample_soun->i_qt_version = 0; } break; @@ -1551,17 +1638,14 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, case( VLC_FOURCC( '.', 'm', 'p', '3' ) ): case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ): { - MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun; - p_track->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' ); - if( p_track->i_sample_size > 1 ) - p_soun->i_qt_version = 0; + p_track->fmt.i_codec = VLC_CODEC_MPGA; break; } case( VLC_FOURCC( 'a', 'c', '-', '3' ) ): { MP4_Box_t *p_dac3_box = MP4_BoxGet( p_sample, "dac3", 0 ); - p_track->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' ); + p_track->fmt.i_codec = VLC_CODEC_A52; if( p_dac3_box ) { static const int pi_bitrate[] = { @@ -1582,7 +1666,7 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, } case( VLC_FOURCC( 'e', 'c', '-', '3' ) ): { - p_track->fmt.i_codec = VLC_FOURCC( 'e', 'a', 'c', '3' ); + p_track->fmt.i_codec = VLC_CODEC_EAC3; break; } @@ -1616,12 +1700,12 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, } case( VLC_FOURCC( 's', '2', '6', '3' ) ): - p_track->fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '3' ); + p_track->fmt.i_codec = VLC_CODEC_H263; break; case( VLC_FOURCC( 't', 'e', 'x', 't' ) ): case( VLC_FOURCC( 't', 'x', '3', 'g' ) ): - p_track->fmt.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' ); + p_track->fmt.i_codec = VLC_CODEC_SUBT; /* FIXME: Not true, could be UTF-16 with a Byte Order Mark (0xfeff) */ /* FIXME UTF-8 doesn't work here ? */ if( p_track->b_mac_encoding ) @@ -1631,23 +1715,86 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, break; case VLC_FOURCC('y','v','1','2'): - p_track->fmt.i_codec = VLC_FOURCC('Y','V','1','2'); + p_track->fmt.i_codec = VLC_CODEC_YV12; break; case VLC_FOURCC('y','u','v','2'): p_track->fmt.i_codec = VLC_FOURCC('Y','U','Y','2'); break; case VLC_FOURCC('i','n','2','4'): - /* in in24/in32 there's enda-atom to tell it's little-endian (if present) */ - if( ( MP4_BoxGet( p_sample, "wave/enda" ) ) || - ( MP4_BoxGet( p_sample, "enda" ) ) ) + p_track->fmt.i_codec = p_enda && p_enda->data.p_enda->i_little_endian == 1 ? + VLC_FOURCC('4','2','n','i') : VLC_FOURCC('i','n','2','4'); + break; + case VLC_FOURCC('f','l','3','2'): + p_track->fmt.i_codec = p_enda && p_enda->data.p_enda->i_little_endian == 1 ? + VLC_CODEC_F32L : VLC_CODEC_F32B; + break; + case VLC_FOURCC('f','l','6','4'): + p_track->fmt.i_codec = p_enda && p_enda->data.p_enda->i_little_endian == 1 ? + VLC_CODEC_F64L : VLC_CODEC_F64B; + break; + case VLC_FOURCC( 'l', 'p', 'c', 'm' ): + { + MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun; + if( p_soun->i_qt_version == 2 && + p_soun->i_qt_description > 20 + 28 ) { - p_track->fmt.i_codec = VLC_FOURCC('4','2','n','i'); - } else { - p_track->fmt.i_codec = p_sample->i_type; + /* Flags: + * 0x01: IsFloat + * 0x02: IsBigEndian + * 0x04: IsSigned + */ + static const struct { + unsigned i_flags; + unsigned i_mask; + unsigned i_bits; + vlc_fourcc_t i_codec; + } p_formats[] = { + { 0x01, 0x03, 32, VLC_CODEC_F32L }, + { 0x01, 0x03, 64, VLC_CODEC_F64L }, + { 0x01|0x02, 0x03, 32, VLC_CODEC_F32B }, + { 0x01|0x02, 0x03, 64, VLC_CODEC_F64B }, + + { 0x00, 0x05, 8, VLC_CODEC_U8 }, + { 0x00| 0x04, 0x05, 8, VLC_CODEC_S8 }, + + { 0x00, 0x07, 16, VLC_CODEC_U16L }, + { 0x00|0x02, 0x07, 16, VLC_CODEC_U16B }, + { 0x00 |0x04, 0x07, 16, VLC_CODEC_S16L }, + { 0x00|0x02|0x04, 0x07, 16, VLC_CODEC_S16B }, + + { 0x00, 0x07, 24, VLC_CODEC_U24L }, + { 0x00|0x02, 0x07, 24, VLC_CODEC_U24B }, + { 0x00 |0x04, 0x07, 24, VLC_CODEC_S24L }, + { 0x00|0x02|0x04, 0x07, 24, VLC_CODEC_S24B }, + + { 0x00, 0x07, 32, VLC_CODEC_U32L }, + { 0x00|0x02, 0x07, 32, VLC_CODEC_U32B }, + { 0x00 |0x04, 0x07, 32, VLC_CODEC_S32L }, + { 0x00|0x02|0x04, 0x07, 32, VLC_CODEC_S32B }, + + {0, 0, 0, 0} + }; + uint32_t i_bits = GetDWBE(&p_soun->p_qt_description[20 + 20]); + uint32_t i_flags = GetDWBE(&p_soun->p_qt_description[20 + 24]); + + for( int i = 0; p_formats[i].i_codec; i++ ) + { + if( p_formats[i].i_bits == i_bits && + (i_flags & p_formats[i].i_mask) == p_formats[i].i_flags ) + { + p_track->fmt.i_codec = p_formats[i].i_codec; + p_track->fmt.audio.i_bitspersample = i_bits; + p_track->fmt.audio.i_blockalign = p_soun->i_channelcount * i_bits / 8; + p_track->i_sample_size = p_track->fmt.audio.i_blockalign; + + p_soun->i_qt_version = 0; + break; + } + } } break; - + } default: p_track->fmt.i_codec = p_sample->i_type; break; @@ -1665,10 +1812,19 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, switch( p_decconfig->i_objectTypeIndication ) { case( 0x20 ): /* MPEG4 VIDEO */ - p_track->fmt.i_codec = VLC_FOURCC( 'm','p','4','v' ); + p_track->fmt.i_codec = VLC_CODEC_MP4V; + break; + case( 0x21 ): /* H.264 */ + p_track->fmt.i_codec = VLC_CODEC_H264; break; case( 0x40): - p_track->fmt.i_codec = VLC_FOURCC( 'm','p','4','a' ); + p_track->fmt.i_codec = VLC_CODEC_MP4A; + if( p_decconfig->i_decoder_specific_info_len >= 2 && + p_decconfig->p_decoder_specific_info[0] == 0xF8 && + (p_decconfig->p_decoder_specific_info[1]&0xE0) == 0x80 ) + { + p_track->fmt.i_codec = VLC_CODEC_ALS; + } break; case( 0x60): case( 0x61): @@ -1676,23 +1832,23 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, case( 0x63): case( 0x64): case( 0x65): /* MPEG2 video */ - p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','v' ); + p_track->fmt.i_codec = VLC_CODEC_MPGV; break; /* Theses are MPEG2-AAC */ case( 0x66): /* main profile */ case( 0x67): /* Low complexity profile */ case( 0x68): /* Scaleable Sampling rate profile */ - p_track->fmt.i_codec = VLC_FOURCC( 'm','p','4','a' ); + p_track->fmt.i_codec = VLC_CODEC_MP4A; break; - /* true MPEG 2 audio */ + /* True MPEG 2 audio */ case( 0x69): - p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','a' ); + p_track->fmt.i_codec = VLC_CODEC_MPGA; break; case( 0x6a): /* MPEG1 video */ p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','v' ); break; case( 0x6b): /* MPEG1 audio */ - p_track->fmt.i_codec = VLC_FOURCC( 'm','p','g','a' ); + p_track->fmt.i_codec = VLC_CODEC_MPGA; break; case( 0x6c ): /* jpeg */ p_track->fmt.i_codec = VLC_FOURCC( 'j','p','e','g' ); @@ -1700,11 +1856,28 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, case( 0x6d ): /* png */ p_track->fmt.i_codec = VLC_FOURCC( 'p','n','g',' ' ); break; - case( 0x6e ): /* jpeg200 */ + case( 0x6e ): /* jpeg2000 */ p_track->fmt.i_codec = VLC_FOURCC( 'M','J','2','C' ); break; case( 0xa3 ): /* vc1 */ - p_track->fmt.i_codec = VLC_FOURCC( 'W','V','C','1' ); + p_track->fmt.i_codec = VLC_CODEC_VC1; + break; + case( 0xa4 ): + p_track->fmt.i_codec = VLC_CODEC_DIRAC; + break; + case( 0xa5 ): + p_track->fmt.i_codec = VLC_CODEC_A52; + break; + case( 0xa6 ): + p_track->fmt.i_codec = VLC_CODEC_EAC3; + break; + case( 0xa9 ): /* dts */ + case( 0xaa ): /* DTS-HD HRA */ + case( 0xab ): /* DTS-HD Master Audio */ + p_track->fmt.i_codec = VLC_CODEC_DTS; + break; + case( 0xDD ): + p_track->fmt.i_codec = VLC_CODEC_VORBIS; break; /* Private ID */ @@ -1777,10 +1950,16 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, p_track->fmt.i_extra); } break; + + case VLC_CODEC_AMR_NB: + p_track->fmt.audio.i_rate = 8000; + break; + case VLC_CODEC_AMR_WB: + p_track->fmt.audio.i_rate = 16000; + break; case VLC_FOURCC( 'Q', 'D', 'M', 'C' ): - case VLC_FOURCC( 'Q', 'D', 'M', '2' ): - case VLC_FOURCC( 's', 'a', 'm', 'r' ): - case VLC_FOURCC( 'a', 'l', 'a', 'c' ): + case VLC_CODEC_QDM2: + case VLC_CODEC_ALAC: p_track->fmt.i_extra = p_sample->data.p_sample_soun->i_qt_description; if( p_track->fmt.i_extra > 0 ) @@ -1790,7 +1969,32 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, p_sample->data.p_sample_soun->p_qt_description, p_track->fmt.i_extra); } + if( p_track->fmt.i_extra >= 56 && p_sample->i_type == VLC_CODEC_ALAC ) + { + p_track->fmt.audio.i_channels = *((uint8_t*)p_track->fmt.p_extra + 41); + p_track->fmt.audio.i_rate = GetDWBE((uint8_t*)p_track->fmt.p_extra + 52); + } + break; + + case VLC_FOURCC( 'v', 'c', '-', '1' ): + { + MP4_Box_t *p_dvc1 = MP4_BoxGet( p_sample, "dvc1" ); + if( p_dvc1 ) + { + p_track->fmt.i_extra = p_dvc1->data.p_dvc1->i_vc1; + if( p_track->fmt.i_extra > 0 ) + { + p_track->fmt.p_extra = malloc( p_dvc1->data.p_dvc1->i_vc1 ); + memcpy( p_track->fmt.p_extra, p_dvc1->data.p_dvc1->p_vc1, + p_track->fmt.i_extra ); + } + } + else + { + msg_Err( p_demux, "missing dvc1" ); + } break; + } /* avc1: send avcC (h264 without annexe B, ie without start code)*/ case VLC_FOURCC( 'a', 'v', 'c', '1' ): @@ -1814,13 +2018,14 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, break; } - case VLC_FOURCC('m','s',0x00,0x02): - case VLC_FOURCC('m','s',0x00,0x11): - case VLC_FOURCC('Q','c','l','p'): + case VLC_CODEC_ADPCM_MS: + case VLC_CODEC_ADPCM_IMA_WAV: + case VLC_CODEC_QCELP: p_track->fmt.audio.i_blockalign = p_sample->data.p_sample_soun->i_bytes_per_frame; break; default: + msg_Dbg( p_demux, "Unrecognized FourCC %4.4s", (char *)&p_sample->i_type ); break; } } @@ -1841,7 +2046,7 @@ static int TrackTimeToSampleChunk( demux_t *p_demux, mp4_track_t *p_track, uint32_t *pi_sample ) { demux_sys_t *p_sys = p_demux->p_sys; - MP4_Box_t *p_stss; + MP4_Box_t *p_box_stss; uint64_t i_dts; unsigned int i_sample; unsigned int i_chunk; @@ -1946,43 +2151,34 @@ static int TrackTimeToSampleChunk( demux_t *p_demux, mp4_track_t *p_track, /* *** Try to find nearest sync points *** */ - if( ( p_stss = MP4_BoxGet( p_track->p_stbl, "stss" ) ) ) + if( ( p_box_stss = MP4_BoxGet( p_track->p_stbl, "stss" ) ) ) { - unsigned int i_index; - msg_Dbg( p_demux, - "track[Id 0x%x] using Sync Sample Box (stss)", - p_track->i_track_ID ); - for( i_index = 0; i_index < p_stss->data.p_stss->i_entry_count; i_index++ ) + MP4_Box_data_stss_t *p_stss = p_box_stss->data.p_stss; + msg_Dbg( p_demux, "track[Id 0x%x] using Sync Sample Box (stss)", + p_track->i_track_ID ); + for( unsigned i_index = 0; i_index < p_stss->i_entry_count; i_index++ ) { - if( p_stss->data.p_stss->i_sample_number[i_index] >= i_sample ) + if( i_index >= p_stss->i_entry_count - 1 || + i_sample < p_stss->i_sample_number[i_index+1] ) { - if( i_index > 0 ) + unsigned i_sync_sample = p_stss->i_sample_number[i_index]; + msg_Dbg( p_demux, "stts gives %d --> %d (sample number)", + i_sample, i_sync_sample ); + + if( i_sync_sample <= i_sample ) { - msg_Dbg( p_demux, "stts gives %d --> %d (sample number)", - i_sample, - p_stss->data.p_stss->i_sample_number[i_index-1] ); - i_sample = p_stss->data.p_stss->i_sample_number[i_index-1]; - /* new i_sample is less than old so i_chunk can only decreased */ while( i_chunk > 0 && - i_sample < p_track->chunk[i_chunk].i_sample_first ) - { + i_sync_sample < p_track->chunk[i_chunk].i_sample_first ) i_chunk--; - } } else { - msg_Dbg( p_demux, "stts gives %d --> %d (sample number)", - i_sample, - p_stss->data.p_stss->i_sample_number[i_index] ); - i_sample = p_stss->data.p_stss->i_sample_number[i_index]; - /* new i_sample is more than old so i_chunk can only increased */ while( i_chunk < p_track->i_chunk_count - 1 && - i_sample >= p_track->chunk[i_chunk].i_sample_first + - p_track->chunk[i_chunk].i_sample_count ) - { + i_sync_sample >= p_track->chunk[i_chunk].i_sample_first + + p_track->chunk[i_chunk].i_sample_count ) i_chunk++; - } } + i_sample = i_sync_sample; break; } } @@ -2065,9 +2261,6 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, MP4_Box_t *p_vmhd; MP4_Box_t *p_smhd; - MP4_Box_t *p_drms; - - unsigned int i; char language[4]; /* hint track unsupported */ @@ -2093,8 +2286,10 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, p_track->fmt.i_priority = -1; p_track->i_track_ID = p_tkhd->data.p_tkhd->i_track_ID; + p_track->i_width = p_tkhd->data.p_tkhd->i_width / 65536; p_track->i_height = p_tkhd->data.p_tkhd->i_height / 65536; + p_track->f_rotation = p_tkhd->data.p_tkhd->f_rotation; if( p_tref ) { @@ -2122,14 +2317,14 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, } else { - for( i = 0; i < 3; i++ ) + for( unsigned i = 0; i < 3; i++ ) language[i] = p_mdhd->data.p_mdhd->i_language[i]; language[3] = '\0'; } switch( p_hdlr->data.p_hdlr->i_handler_type ) { - case( FOURCC_soun ): + case( ATOM_soun ): if( !( p_smhd = MP4_BoxGet( p_box_trak, "mdia/minf/smhd" ) ) ) { return; @@ -2137,7 +2332,7 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, p_track->fmt.i_cat = AUDIO_ES; break; - case( FOURCC_vide ): + case( ATOM_vide ): if( !( p_vmhd = MP4_BoxGet( p_box_trak, "mdia/minf/vmhd" ) ) ) { return; @@ -2145,10 +2340,10 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, p_track->fmt.i_cat = VIDEO_ES; break; - case( FOURCC_text ): - case( FOURCC_subp ): - case( FOURCC_tx3g ): - case( FOURCC_sbtl ): + case( ATOM_text ): + case( ATOM_subp ): + case( ATOM_tx3g ): + case( ATOM_sbtl ): p_track->fmt.i_cat = SPU_ES; break; @@ -2188,22 +2383,6 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, return; } - p_drms = MP4_BoxGet( p_track->p_stsd, "drms" ); - p_track->b_drms = p_drms != NULL; - p_track->p_drms = p_track->b_drms ? - p_drms->data.p_sample_soun->p_drms : NULL; - - if ( !p_drms ) - { - p_drms = MP4_BoxGet( p_track->p_stsd, "drmi" ); - p_track->b_drms = p_drms != NULL; - p_track->p_drms = p_track->b_drms ? - p_drms->data.p_sample_vide->p_drms : NULL; - } - - if( p_drms ) - p_track->p_skcr = MP4_BoxGet( p_drms, "sinf/skcr" ); - /* Set language */ if( *language && strcmp( language, "```" ) && strcmp( language, "und" ) ) { @@ -2213,15 +2392,19 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, p_udta = MP4_BoxGet( p_box_trak, "udta" ); if( p_udta ) { - MP4_Box_t *p_0xa9xxx; - for( p_0xa9xxx = p_udta->p_first; p_0xa9xxx != NULL; - p_0xa9xxx = p_0xa9xxx->p_next ) + MP4_Box_t *p_box_iter; + for( p_box_iter = p_udta->p_first; p_box_iter != NULL; + p_box_iter = p_box_iter->p_next ) { - switch( p_0xa9xxx->i_type ) + switch( p_box_iter->i_type ) { - case FOURCC_0xa9nam: + case ATOM_0xa9nam: + p_track->fmt.psz_description = + strdup( p_box_iter->data.p_0xa9xxx->psz_text ); + break; + case ATOM_name: p_track->fmt.psz_description = - strdup( p_0xa9xxx->data.p_0xa9xxx->psz_text ); + strdup( p_box_iter->data.p_name->psz_text ); break; } } @@ -2453,7 +2636,7 @@ static uint64_t MP4_TrackGetPos( mp4_track_t *p_track ) MP4_Box_data_sample_soun_t *p_soun = p_track->p_sample->data.p_sample_soun; - if( p_soun->i_qt_version == 0 ) + if( p_track->fmt.i_cat != AUDIO_ES || p_soun->i_qt_version == 0 ) { i_pos += ( p_track->i_sample - p_track->chunk[p_track->i_chunk].i_sample_first ) * @@ -2605,7 +2788,7 @@ static void MP4_TrackSetELST( demux_t *p_demux, mp4_track_t *tk, /* */ static const char *MP4_ConvertMacCode( uint16_t i_code ) { - static const struct { const char *psz_iso639_1; uint16_t i_code; } p_cvt[] = { + static const struct { const char psz_iso639_1[3]; uint16_t i_code; } p_cvt[] = { { "en", 0 }, { "fr", 1 }, { "de", 2 }, { "it", 3 }, { "nl", 4 }, { "sv", 5 }, { "es", 6 }, { "da", 7 }, { "pt", 8 }, { "no", 9 }, { "he", 10 }, { "ja", 11 }, { "ar", 12 }, { "fi", 13 }, { "el", 14 }, @@ -2632,10 +2815,10 @@ static const char *MP4_ConvertMacCode( uint16_t i_code ) { "gl", 140 }, { "af", 141 }, { "br", 142 }, { "iu", 143 }, { "gd", 144 }, { "gv", 145 }, { "ga", 146 }, { "to", 147 }, { "el", 148 }, /* */ - { NULL, 0 } + { "", 0 } }; int i; - for( i = 0; p_cvt[i].psz_iso639_1 != NULL; i++ ) + for( i = 0; *p_cvt[i].psz_iso639_1; i++ ) { if( p_cvt[i].i_code == i_code ) return p_cvt[i].psz_iso639_1;