X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=modules%2Fdemux%2Fmp4%2Fmp4.c;h=61c67852fc10259202dd66a1bfa67c82cdc640b8;hb=a757f6af6b811b094ffce8f070c5dff7b09d6f25;hp=1877b837309ba1c981851781c2d85c6d9dd9c6cd;hpb=9439468128c890005ba80828174597b48cd3ea6f;p=vlc diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c index 1877b83730..61c67852fc 100644 --- a/modules/demux/mp4/mp4.c +++ b/modules/demux/mp4/mp4.c @@ -17,7 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -28,6 +28,7 @@ #include #include #include +#include #include "iso_lang.h" #include "vlc_meta.h" @@ -164,7 +165,7 @@ static int MP4_TrackSampleSize( mp4_track_t * ); static int MP4_TrackNextSample( demux_t *, mp4_track_t * ); static void MP4_TrackSetELST( demux_t *, mp4_track_t *, int64_t ); -/* Return time in µs of a track */ +/* Return time in s of a track */ static inline int64_t MP4_TrackGetDTS( demux_t *p_demux, mp4_track_t *p_track ) { #define chunk p_track->chunk[p_track->i_chunk] @@ -240,7 +241,9 @@ static inline int64_t MP4_GetMoviePTS(demux_sys_t *p_sys ) return I64C(1000000) * p_sys->i_time / p_sys->i_timescale; } -#define FREE( p ) if( p ) { free( p ); (p) = NULL;} +/* Function to lookup the currently playing item */ +static vlc_bool_t FindItem( demux_t *p_demux, playlist_t *p_playlist, + playlist_item_t **pp_item ); /***************************************************************************** * Open: check file and initializes MP4 structures @@ -343,7 +346,7 @@ static int Open( vlc_object_t * p_this ) if( ( p_rmra = MP4_BoxGet( p_sys->p_root, "/moov/rmra" ) ) ) { playlist_t *p_playlist; - playlist_item_t *p_item; + playlist_item_t *p_current, *p_item_in_category; int i_count = MP4_BoxCount( p_rmra, "rmda" ); int i; vlc_bool_t b_play = VLC_FALSE; @@ -356,9 +359,9 @@ static int Open( vlc_object_t * p_this ) FIND_ANYWHERE ); if( p_playlist ) { - p_item = playlist_LockItemGetByInput( p_playlist, - ((input_thread_t *)p_demux->p_parent)->input.p_item ); - playlist_ItemToNode( p_playlist, p_item ); + b_play = FindItem( p_demux, p_playlist, &p_current ); + p_item_in_category = playlist_ItemToNode( p_playlist, p_current ); + p_current->p_input->i_type = ITEM_TYPE_PLAYLIST; for( i = 0; i < i_count; i++ ) { @@ -366,7 +369,7 @@ static int Open( vlc_object_t * p_this ) char *psz_ref; uint32_t i_ref_type; - if( !p_rdrf || !( psz_ref = p_rdrf->data.p_rdrf->psz_ref ) ) + if( !p_rdrf || !( psz_ref = strdup( p_rdrf->data.p_rdrf->psz_ref ) ) ) { continue; } @@ -385,59 +388,31 @@ static int Open( vlc_object_t * p_this ) if( !strncmp( psz_ref, "http://", 7 ) || !strncmp( psz_ref, "rtsp://", 7 ) ) { - msg_Dbg( p_demux, "adding ref = `%s'", psz_ref ); - if( p_item ) - { - playlist_item_t *p_child = - playlist_ItemNew( p_playlist, - psz_ref, psz_ref ); - if( p_child ) - { - playlist_NodeAddItem( p_playlist, p_child, - p_item->pp_parents[0]->i_view, - p_item, PLAYLIST_APPEND, - PLAYLIST_END ); - playlist_CopyParents( p_item, p_child ); - b_play = VLC_TRUE; - } - } + ; } else { - /* msg dbg relative ? */ - char *psz_absolute = alloca( strlen( p_demux->psz_access ) + 3 + strlen( p_demux->psz_path ) + strlen( psz_ref ) + 1); - char *end = strrchr( p_demux->psz_path, '/' ); + char *psz_absolute; + char *psz_path = strdup( p_demux->psz_path ); + char *end = strrchr( psz_path, '/' ); + if( end ) end[1] = '\0'; + else *psz_path = '\0'; - if( end ) - { - int i_len = end + 1 - p_demux->psz_path; + asprintf( &psz_absolute, "%s://%s%s", + p_demux->psz_access, psz_path, psz_ref ); - strcpy( psz_absolute, p_demux->psz_access ); - strcat( psz_absolute, "://" ); - strncat( psz_absolute, p_demux->psz_path, i_len); - } - else - { - strcpy( psz_absolute, "" ); - } - strcat( psz_absolute, psz_ref ); - msg_Dbg( p_demux, "adding ref = `%s'", psz_absolute ); - if( p_item ) - { - playlist_item_t *p_child = - playlist_ItemNew( p_playlist, - psz_absolute, - psz_absolute ); - if( p_child ) - { - playlist_NodeAddItem( p_playlist, p_child, - p_item->pp_parents[0]->i_view, - p_item, PLAYLIST_APPEND, - PLAYLIST_END ); - playlist_CopyParents( p_item, p_child ); - b_play = VLC_TRUE; - } - } + psz_ref = psz_absolute; + free( psz_path ); + } + if( p_current ) + { + input_item_t *p_input; + msg_Dbg( p_demux, "adding ref = `%s'", psz_ref ); + p_input = input_ItemNewExt( p_playlist, psz_ref, NULL, + 0, NULL, -1 ); + vlc_input_item_CopyOptions( p_current->p_input, p_input ); + playlist_AddWhereverNeeded( p_playlist, p_input, p_current, + p_item_in_category, VLC_FALSE, PLAYLIST_APPEND ); } } else @@ -445,12 +420,13 @@ static int Open( vlc_object_t * p_this ) msg_Err( p_demux, "unknown ref type=%4.4s FIXME (send a bug report)", (char*)&p_rdrf->data.p_rdrf->i_ref_type ); } + if( psz_ref ) free( psz_ref ); } - if( b_play == VLC_TRUE ) + if( b_play && p_playlist->status.p_item && + p_playlist->status.p_item->i_children > 0) { - playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, - p_playlist->status.i_view, - p_playlist->status.p_item, NULL ); + playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, + p_playlist->status.p_item, NULL ); } vlc_object_release( p_playlist ); } @@ -799,47 +775,48 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) case DEMUX_GET_META: { - vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** ); - vlc_meta_t *meta; + vlc_meta_t *p_meta = (vlc_meta_t *)va_arg( args, vlc_meta_t*); MP4_Box_t *p_udta = MP4_BoxGet( p_sys->p_root, "/moov/udta" ); MP4_Box_t *p_0xa9xxx; if( p_udta == NULL ) { return VLC_EGENERIC; } - *pp_meta = meta = vlc_meta_New(); for( p_0xa9xxx = p_udta->p_first; p_0xa9xxx != NULL; p_0xa9xxx = p_0xa9xxx->p_next ) { + char *psz_utf; + if( !p_0xa9xxx || !p_0xa9xxx->data.p_0xa9xxx ) + continue; + psz_utf = strdup( p_0xa9xxx->data.p_0xa9xxx->psz_text ); + if( psz_utf == NULL ) + continue; + /* FIXME FIXME: should convert from whatever the character + * encoding of MP4 meta data is to UTF-8. */ + EnsureUTF8( psz_utf ); + switch( p_0xa9xxx->i_type ) { case FOURCC_0xa9nam: /* Full name */ - vlc_meta_Add( meta, VLC_META_TITLE, - p_0xa9xxx->data.p_0xa9xxx->psz_text ); + vlc_meta_SetArtist( p_meta, psz_utf ); break; case FOURCC_0xa9aut: - vlc_meta_Add( meta, VLC_META_AUTHOR, - p_0xa9xxx->data.p_0xa9xxx->psz_text ); + vlc_meta_SetAuthor( p_meta, psz_utf ); break; case FOURCC_0xa9ART: - vlc_meta_Add( meta, VLC_META_ARTIST, - p_0xa9xxx->data.p_0xa9xxx->psz_text ); + vlc_meta_SetArtist( p_meta, psz_utf ); break; case FOURCC_0xa9cpy: - vlc_meta_Add( meta, VLC_META_COPYRIGHT, - p_0xa9xxx->data.p_0xa9xxx->psz_text ); + vlc_meta_SetCopyright( p_meta, psz_utf ); break; case FOURCC_0xa9day: /* Creation Date */ - vlc_meta_Add( meta, VLC_META_DATE, - p_0xa9xxx->data.p_0xa9xxx->psz_text ); + vlc_meta_SetDate( p_meta, psz_utf ); break; case FOURCC_0xa9des: /* Description */ - vlc_meta_Add( meta, VLC_META_DESCRIPTION, - p_0xa9xxx->data.p_0xa9xxx->psz_text ); + vlc_meta_SetDescription( p_meta, psz_utf ); break; case FOURCC_0xa9gen: /* Genre */ - vlc_meta_Add( meta, VLC_META_GENRE, - p_0xa9xxx->data.p_0xa9xxx->psz_text ); + vlc_meta_SetGenre( p_meta, psz_utf ); break; case FOURCC_0xa9swr: @@ -868,6 +845,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) default: break; } + free( psz_utf ); } return VLC_SUCCESS; } @@ -878,7 +856,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) return VLC_EGENERIC; default: - msg_Warn( p_demux, "control query unimplemented !!!" ); + msg_Warn( p_demux, "control query %u unimplemented", i_query ); return VLC_EGENERIC; } } @@ -899,7 +877,7 @@ static void Close ( vlc_object_t * p_this ) { MP4_TrackDestroy( p_demux, &p_sys->track[i_track] ); } - FREE( p_sys->track ); + FREENULL( p_sys->track ); free( p_sys ); } @@ -1269,18 +1247,38 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ): p_track->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' ); break; + case( VLC_FOURCC( 'r', 'a', 'w', ' ' ) ): p_track->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' ); + + /* Buggy files workaround */ + if( p_sample->data.p_sample_soun && (p_track->i_timescale != + p_sample->data.p_sample_soun->i_sampleratehi) ) + { + MP4_Box_data_sample_soun_t *p_soun = + p_sample->data.p_sample_soun; + + msg_Warn( p_demux, "i_timescale ("I64Fu") != i_sampleratehi " + "(%u), making both equal (report any problem).", + p_track->i_timescale, p_soun->i_sampleratehi ); + + if( p_soun->i_sampleratehi ) + p_track->i_timescale = p_soun->i_sampleratehi; + else + p_soun->i_sampleratehi = p_track->i_timescale; + } break; + case( VLC_FOURCC( 's', '2', '6', '3' ) ): p_track->fmt.i_codec = VLC_FOURCC( 'h', '2', '6', '3' ); 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' ); /* FIXME: Not true, could be UTF-16 with a Byte Order Mark (0xfeff) */ /* FIXME UTF-8 doesn't work here ? */ - /* p_track->fmt.subs.psz_encoding = strdup( "UTF-8" ); */ + p_track->fmt.subs.psz_encoding = strdup( "UTF-8" ); break; default: @@ -1338,6 +1336,10 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, if( p_track->fmt.i_cat == SPU_ES ) { p_track->fmt.i_codec = VLC_FOURCC( 's','p','u',' ' ); + if( p_track->i_width > 0 ) + p_track->fmt.subs.spu.i_original_frame_width = p_track->i_width; + if( p_track->i_height > 0 ) + p_track->fmt.subs.spu.i_original_frame_height = p_track->i_height; break; } /* Fallback */ @@ -1425,6 +1427,8 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, case( VIDEO_ES ): p_track->fmt.video.i_width = p_sample->data.p_sample_vide->i_width; p_track->fmt.video.i_height = p_sample->data.p_sample_vide->i_height; + p_track->fmt.video.i_bits_per_pixel = + p_sample->data.p_sample_vide->i_depth; /* fall on display size */ if( p_track->fmt.video.i_width <= 0 ) @@ -1439,6 +1443,10 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track, p_track->fmt.video.i_aspect = VOUT_ASPECT_FACTOR * p_track->i_width / p_track->i_height; + /* 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; @@ -1544,8 +1552,8 @@ static int TrackTimeToSampleChunk( demux_t *p_demux, mp4_track_t *p_track, break; } - if( i_start >= p_track->chunk[i_chunk].i_first_dts && - i_start < p_track->chunk[i_chunk + 1].i_first_dts ) + if( (uint64_t)i_start >= p_track->chunk[i_chunk].i_first_dts && + (uint64_t)i_start < p_track->chunk[i_chunk + 1].i_first_dts ) { break; } @@ -1558,7 +1566,7 @@ static int TrackTimeToSampleChunk( demux_t *p_demux, mp4_track_t *p_track, { if( i_dts + p_track->chunk[i_chunk].p_sample_count_dts[i_index] * - p_track->chunk[i_chunk].p_sample_delta_dts[i_index] < i_start ) + p_track->chunk[i_chunk].p_sample_delta_dts[i_index] < (uint64_t)i_start ) { i_dts += p_track->chunk[i_chunk].p_sample_count_dts[i_index] * @@ -1776,6 +1784,7 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, case( FOURCC_text ): case( FOURCC_subp ): + case( FOURCC_tx3g ): p_track->fmt.i_cat = SPU_ES; break; @@ -1788,7 +1797,7 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, if( ( p_track->p_elst = p_elst = MP4_BoxGet( p_box_trak, "edts/elst" ) ) ) { MP4_Box_data_elst_t *elst = p_elst->data.p_elst; - int i; + unsigned int i; msg_Warn( p_demux, "elst box found" ); for( i = 0; i < elst->i_entry_count; i++ ) @@ -1797,7 +1806,8 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, "ms) rate=%d.%d", i, elst->i_segment_duration[i] * 1000 / p_sys->i_timescale, elst->i_media_time[i] >= 0 ? - elst->i_media_time[i] * 1000 / p_track->i_timescale : -1, + (int64_t)(elst->i_media_time[i] * 1000 / p_track->i_timescale) : + I64C(-1), elst->i_media_rate_integer[i], elst->i_media_rate_fraction[i] ); } @@ -1842,32 +1852,6 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, } } - /* fxi i_timescale for AUDIO_ES with i_qt_version == 0 */ - if( p_track->fmt.i_cat == AUDIO_ES ) //&& p_track->i_sample_size == 1 ) - { - MP4_Box_t *p_sample; - - p_sample = MP4_BoxGet( p_track->p_stsd, "[0]" ); - if( p_sample && p_sample->data.p_sample_soun) - { - MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun; - if( p_soun->i_qt_version == 0 && - p_track->i_timescale != p_soun->i_sampleratehi ) - { - msg_Warn( p_demux, - "i_timescale ("I64Fu") != i_sampleratehi (%u) with " - "qt_version == 0\n" - "Making both equal. (report any problem)", - p_track->i_timescale, p_soun->i_sampleratehi ); - - if( p_soun->i_sampleratehi ) - p_track->i_timescale = p_soun->i_sampleratehi; - else - p_soun->i_sampleratehi = p_track->i_timescale; - } - } - } - /* Create chunk index table and sample index table */ if( TrackCreateChunksIndex( p_demux,p_track ) || TrackCreateSamplesIndex( p_demux, p_track ) ) @@ -1922,18 +1906,18 @@ static void MP4_TrackDestroy( demux_t *p_demux, mp4_track_t *p_track ) { if( p_track->chunk ) { - FREE(p_track->chunk[i_chunk].p_sample_count_dts); - FREE(p_track->chunk[i_chunk].p_sample_delta_dts ); + FREENULL(p_track->chunk[i_chunk].p_sample_count_dts); + FREENULL(p_track->chunk[i_chunk].p_sample_delta_dts ); - FREE(p_track->chunk[i_chunk].p_sample_count_pts); - FREE(p_track->chunk[i_chunk].p_sample_offset_pts ); + FREENULL(p_track->chunk[i_chunk].p_sample_count_pts); + FREENULL(p_track->chunk[i_chunk].p_sample_offset_pts ); } } - FREE( p_track->chunk ); + FREENULL( p_track->chunk ); if( !p_track->i_sample_size ) { - FREE( p_track->p_sample_size ); + FREENULL( p_track->p_sample_size ); } } @@ -2004,7 +1988,11 @@ static int MP4_TrackSeek( demux_t *p_demux, mp4_track_t *p_track, VLC_SUCCESS ) { p_track->b_selected = VLC_TRUE; + + es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, + p_track->p_es, i_start ); } + return( p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC ); } @@ -2156,10 +2144,10 @@ static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track ) { demux_sys_t *p_sys = p_demux->p_sys; MP4_Box_data_elst_t *elst = p_track->p_elst->data.p_elst; - int64_t i_mvt = MP4_TrackGetDTS( p_demux, p_track ) * + uint64_t i_mvt = MP4_TrackGetDTS( p_demux, p_track ) * p_sys->i_timescale / (int64_t)1000000; - if( p_track->i_elst < elst->i_entry_count && + if( (unsigned int)p_track->i_elst < elst->i_entry_count && i_mvt >= p_track->i_elst_time + elst->i_segment_duration[p_track->i_elst] ) { @@ -2185,7 +2173,7 @@ static void MP4_TrackSetELST( demux_t *p_demux, mp4_track_t *tk, MP4_Box_data_elst_t *elst = tk->p_elst->data.p_elst; int64_t i_mvt= i_time * p_sys->i_timescale / (int64_t)1000000; - for( tk->i_elst = 0; tk->i_elst < elst->i_entry_count; tk->i_elst++ ) + for( tk->i_elst = 0; (unsigned int)tk->i_elst < elst->i_entry_count; tk->i_elst++ ) { mtime_t i_dur = elst->i_segment_duration[tk->i_elst]; @@ -2196,7 +2184,7 @@ static void MP4_TrackSetELST( demux_t *p_demux, mp4_track_t *tk, tk->i_elst_time += i_dur; } - if( tk->i_elst >= elst->i_entry_count ) + if( (unsigned int)tk->i_elst >= elst->i_entry_count ) { /* msg_Dbg( p_demux, "invalid number of entry in elst" ); */ tk->i_elst = elst->i_entry_count - 1; @@ -2214,3 +2202,33 @@ static void MP4_TrackSetELST( demux_t *p_demux, mp4_track_t *tk, msg_Warn( p_demux, "elst old=%d new=%d", i_elst_last, tk->i_elst ); } } + +static vlc_bool_t FindItem( demux_t *p_demux, playlist_t *p_playlist, + playlist_item_t **pp_item ) +{ + vlc_bool_t b_play = var_CreateGetBool( p_demux, "playlist-autostart" ); + + if( b_play && p_playlist->status.p_item && + p_playlist->status.p_item->p_input == + ((input_thread_t *)p_demux->p_parent)->input.p_item ) + { + msg_Dbg( p_playlist, "starting playlist playback" ); + *pp_item = p_playlist->status.p_item; + b_play = VLC_TRUE; + } + else + { + input_item_t *p_current = ( (input_thread_t*)p_demux->p_parent)-> + input.p_item; + *pp_item = playlist_LockItemGetByInput( p_playlist, p_current ); + if( !*pp_item ) + { + msg_Dbg( p_playlist, "unable to find item in playlist"); + } + msg_Dbg( p_playlist, "not starting playlist playback"); + b_play = VLC_FALSE; + } + return b_play; +} + +