145
uint64_t i_time; /* time position of the presentation
146
* in movie timescale */
147
uint64_t i_timescale; /* movie time scale */
148
uint64_t i_duration; /* movie duration */
149
unsigned int i_tracks; /* number of tracks */
150
mp4_track_t *track; /* array of track */
154
uint64_t i_time; /* time position of the presentation
155
* in movie timescale */
156
uint64_t i_timescale; /* movie time scale */
157
uint64_t i_duration; /* movie duration */
158
unsigned int i_tracks; /* number of tracks */
159
mp4_track_t *track; /* array of track */
162
MP4_Box_t *p_tref_chap;
165
input_title_t *p_title;
153
168
/*****************************************************************************
154
169
* Declaration of local function
155
170
*****************************************************************************/
156
static void MP4_TrackCreate ( demux_t *, mp4_track_t *, MP4_Box_t *);
157
static void MP4_TrackDestroy( demux_t *, mp4_track_t * );
171
static void MP4_TrackCreate ( demux_t *, mp4_track_t *, MP4_Box_t *, bool b_force_enable );
172
static void MP4_TrackDestroy( mp4_track_t * );
159
174
static int MP4_TrackSelect ( demux_t *, mp4_track_t *, mtime_t );
160
175
static void MP4_TrackUnselect(demux_t *, mp4_track_t * );
345
364
if( ( p_rmra = MP4_BoxGet( p_sys->p_root, "/moov/rmra" ) ) )
347
playlist_t *p_playlist;
348
playlist_item_t *p_item;
349
366
int i_count = MP4_BoxCount( p_rmra, "rmda" );
351
vlc_bool_t b_play = VLC_FALSE;
353
369
msg_Dbg( p_demux, "detected playlist mov file (%d ref)", i_count );
356
(playlist_t *)vlc_object_find( p_demux,
371
input_thread_t * p_input = vlc_object_find( p_demux, VLC_OBJECT_INPUT, FIND_PARENT );
372
input_item_t * p_current = input_GetItem( p_input );
373
p_current->i_type = ITEM_TYPE_PLAYLIST;
375
for( i = 0; i < i_count; i++ )
361
p_item = playlist_LockItemGetByInput( p_playlist,
362
((input_thread_t *)p_demux->p_parent)->input.p_item );
363
playlist_ItemToNode( p_playlist, p_item );
365
for( i = 0; i < i_count; i++ )
367
MP4_Box_t *p_rdrf = MP4_BoxGet( p_rmra, "rmda[%d]/rdrf", i );
371
if( !p_rdrf || !( psz_ref = strdup( p_rdrf->data.p_rdrf->psz_ref ) ) )
377
MP4_Box_t *p_rdrf = MP4_BoxGet( p_rmra, "rmda[%d]/rdrf", i );
381
if( !p_rdrf || !( psz_ref = strdup( p_rdrf->data.p_rdrf->psz_ref ) ) )
385
i_ref_type = p_rdrf->data.p_rdrf->i_ref_type;
387
msg_Dbg( p_demux, "new ref=`%s' type=%4.4s",
388
psz_ref, (char*)&i_ref_type );
390
if( i_ref_type == VLC_FOURCC( 'u', 'r', 'l', ' ' ) )
392
if( strstr( psz_ref, "qt5gateQT" ) )
394
msg_Dbg( p_demux, "ignoring pseudo ref =`%s'", psz_ref );
375
i_ref_type = p_rdrf->data.p_rdrf->i_ref_type;
377
msg_Dbg( p_demux, "new ref=`%s' type=%4.4s",
378
psz_ref, (char*)&i_ref_type );
380
if( i_ref_type == VLC_FOURCC( 'u', 'r', 'l', ' ' ) )
397
if( !strncmp( psz_ref, "http://", 7 ) ||
398
!strncmp( psz_ref, "rtsp://", 7 ) )
382
if( strstr( psz_ref, "qt5gateQT" ) )
384
msg_Dbg( p_demux, "ignoring pseudo ref =`%s'", psz_ref );
387
if( !strncmp( psz_ref, "http://", 7 ) ||
388
!strncmp( psz_ref, "rtsp://", 7 ) )
395
char *psz_path = strdup( p_demux->psz_path );
396
char *end = strrchr( psz_path, '/' );
398
if( end ) end[1] = '\0';
399
else *psz_path = '\0';
401
asprintf( &psz_absolute, "%s://%s%s",
402
p_demux->psz_access, psz_path, psz_ref );
404
if( psz_ref ) free( psz_ref );
405
psz_ref = psz_absolute;
408
msg_Dbg( p_demux, "adding ref = `%s'", psz_ref );
411
playlist_item_t *p_child =
412
playlist_ItemNew( p_playlist,
416
playlist_NodeAddItem( p_playlist, p_child,
417
p_item->pp_parents[0]->i_view,
418
p_item, PLAYLIST_APPEND,
420
playlist_CopyParents( p_item, p_child );
427
msg_Err( p_demux, "unknown ref type=%4.4s FIXME (send a bug report)",
428
(char*)&p_rdrf->data.p_rdrf->i_ref_type );
405
char *psz_path = strdup( p_demux->psz_path );
406
char *end = strrchr( psz_path, '/' );
407
if( end ) end[1] = '\0';
408
else *psz_path = '\0';
410
if( asprintf( &psz_absolute, "%s://%s%s",
411
p_demux->psz_access, psz_path, psz_ref ) < 0 )
415
psz_ref = psz_absolute;
430
if( psz_ref ) free( psz_ref );
418
input_item_t *p_input;
419
msg_Dbg( p_demux, "adding ref = `%s'", psz_ref );
420
p_input = input_item_NewExt( p_demux, psz_ref, NULL,
422
input_item_CopyOptions( p_current, p_input );
423
input_item_AddSubItem( p_current, p_input );
424
vlc_gc_decref( p_input );
432
if( b_play == VLC_TRUE )
434
playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
435
p_playlist->status.i_view,
436
p_playlist->status.p_item, NULL );
428
msg_Err( p_demux, "unknown ref type=%4.4s FIXME (send a bug report)",
429
(char*)&p_rdrf->data.p_rdrf->i_ref_type );
438
vlc_object_release( p_playlist );
442
msg_Err( p_demux, "can't find playlist" );
433
vlc_object_release( p_input );
446
436
if( !(p_mvhd = MP4_BoxGet( p_sys->p_root, "/moov/mvhd" ) ) )
484
474
memset( p_sys->track, 0, p_sys->i_tracks * sizeof( mp4_track_t ) );
476
/* Search the first chap reference (like quicktime) and
477
* check that at least 1 stream is enabled */
478
p_sys->p_tref_chap = NULL;
479
b_enabled_es = false;
480
for( i = 0; i < p_sys->i_tracks; i++ )
482
MP4_Box_t *p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[%d]", i );
485
MP4_Box_t *p_tkhd = MP4_BoxGet( p_trak, "tkhd" );
486
if( p_tkhd && (p_tkhd->data.p_tkhd->i_flags&MP4_TRACK_ENABLED) )
489
MP4_Box_t *p_chap = MP4_BoxGet( p_trak, "tref/chap", i );
490
if( p_chap && p_chap->data.p_tref_generic->i_entry_count > 0 && !p_sys->p_tref_chap )
491
p_sys->p_tref_chap = p_chap;
486
494
/* now process each track and extract all usefull information */
487
495
for( i = 0; i < p_sys->i_tracks; i++ )
489
497
p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[%d]", i );
490
MP4_TrackCreate( p_demux, &p_sys->track[i], p_trak );
498
MP4_TrackCreate( p_demux, &p_sys->track[i], p_trak, !b_enabled_es );
492
if( p_sys->track[i].b_ok )
500
if( p_sys->track[i].b_ok && !p_sys->track[i].b_chapter )
495
503
switch( p_sys->track[i].fmt.i_cat )
497
505
case( VIDEO_ES ):
790
830
case DEMUX_GET_META:
792
vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
794
MP4_Box_t *p_udta = MP4_BoxGet( p_sys->p_root, "/moov/udta" );
832
vlc_meta_t *p_meta = (vlc_meta_t *)va_arg( args, vlc_meta_t*);
795
833
MP4_Box_t *p_0xa9xxx;
835
MP4_Box_t *p_udta = MP4_BoxGet( p_sys->p_root, "/moov/udta/meta/ilst" );
796
836
if( p_udta == NULL )
838
p_udta = MP4_BoxGet( p_sys->p_root, "/moov/udta" );
800
*pp_meta = meta = vlc_meta_New();
801
845
for( p_0xa9xxx = p_udta->p_first; p_0xa9xxx != NULL;
802
846
p_0xa9xxx = p_0xa9xxx->p_next )
805
849
if( !p_0xa9xxx || !p_0xa9xxx->data.p_0xa9xxx )
807
psz_utf = strdup( p_0xa9xxx->data.p_0xa9xxx->psz_text );
808
if( psz_utf == NULL )
810
852
/* FIXME FIXME: should convert from whatever the character
811
853
* encoding of MP4 meta data is to UTF-8. */
812
EnsureUTF8( psz_utf );
854
#define SET(fct) do { char *psz_utf = strdup( p_0xa9xxx->data.p_0xa9xxx->psz_text ? p_0xa9xxx->data.p_0xa9xxx->psz_text : "" ); \
855
if( psz_utf ) { EnsureUTF8( psz_utf ); \
856
fct( p_meta, psz_utf ); free( psz_utf ); } } while(0)
858
/* XXX Becarefull p_udta can have box that are not 0xa9xx */
814
859
switch( p_0xa9xxx->i_type )
816
861
case FOURCC_0xa9nam: /* Full name */
817
vlc_meta_Add( meta, VLC_META_TITLE, psz_utf );
862
SET( vlc_meta_SetTitle );
819
864
case FOURCC_0xa9aut:
820
vlc_meta_Add( meta, VLC_META_AUTHOR, psz_utf );
865
SET( vlc_meta_SetArtist );
822
867
case FOURCC_0xa9ART:
823
vlc_meta_Add( meta, VLC_META_ARTIST, psz_utf );
868
SET( vlc_meta_SetArtist );
825
870
case FOURCC_0xa9cpy:
826
vlc_meta_Add( meta, VLC_META_COPYRIGHT, psz_utf );
871
SET( vlc_meta_SetCopyright );
828
873
case FOURCC_0xa9day: /* Creation Date */
829
vlc_meta_Add( meta, VLC_META_DATE, psz_utf );
874
SET( vlc_meta_SetDate );
831
876
case FOURCC_0xa9des: /* Description */
832
vlc_meta_Add( meta, VLC_META_DESCRIPTION, psz_utf );
877
SET( vlc_meta_SetDescription );
834
879
case FOURCC_0xa9gen: /* Genre */
835
vlc_meta_Add( meta, VLC_META_GENRE, psz_utf );
880
SET( vlc_meta_SetGenre );
883
case FOURCC_0xa9alb: /* Album */
884
SET( vlc_meta_SetAlbum );
887
case FOURCC_0xa9trk: /* Track */
888
SET( vlc_meta_SetTracknum );
891
case FOURCC_0xa9cmt: /* Commment */
892
SET( vlc_meta_SetDescription );
895
case FOURCC_0xa9url: /* URL */
896
SET( vlc_meta_SetURL );
899
case FOURCC_0xa9enc: /* Encoded By */
900
SET( vlc_meta_SetEncodedBy );
838
903
case FOURCC_0xa9swr:
839
904
case FOURCC_0xa9inf: /* Information */
840
case FOURCC_0xa9alb: /* Album */
841
905
case FOURCC_0xa9dir: /* Director */
842
906
case FOURCC_0xa9dis: /* Disclaimer */
843
case FOURCC_0xa9enc: /* Encoded By */
844
case FOURCC_0xa9trk: /* Track */
845
case FOURCC_0xa9cmt: /* Commment */
846
case FOURCC_0xa9url: /* URL */
847
907
case FOURCC_0xa9req: /* Requirements */
848
908
case FOURCC_0xa9fmt: /* Original Format */
849
909
case FOURCC_0xa9dsa: /* Display Source As */
903
999
/****************************************************************************
904
1000
* Local functions, specific to vlc
905
1001
****************************************************************************/
1003
static void LoadChapterGpac( demux_t *p_demux, MP4_Box_t *p_chpl )
1005
demux_sys_t *p_sys = p_demux->p_sys;
1008
p_sys->p_title = vlc_input_title_New();
1009
for( i = 0; i < p_chpl->data.p_chpl->i_chapter; i++ )
1011
seekpoint_t *s = vlc_seekpoint_New();
1013
s->psz_name = strdup( p_chpl->data.p_chpl->chapter[i].psz_name );
1014
EnsureUTF8( s->psz_name );
1015
s->i_time_offset = p_chpl->data.p_chpl->chapter[i].i_start / 10;
1016
TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s );
1019
static void LoadChapterApple( demux_t *p_demux, mp4_track_t *tk )
1021
demux_sys_t *p_sys = p_demux->p_sys;
1023
for( tk->i_sample = 0; tk->i_sample < tk->i_sample_count; tk->i_sample++ )
1025
const int64_t i_dts = MP4_TrackGetDTS( p_demux, tk );
1026
const int64_t i_pts_delta = MP4_TrackGetPTSDelta( tk );
1027
const unsigned int i_size = MP4_TrackSampleSize( tk );
1029
if( i_size > 0 && !stream_Seek( p_demux->s, MP4_TrackGetPos( tk ) ) )
1032
const int i_read = stream_Read( p_demux->s, p_buffer, __MIN( sizeof(p_buffer), i_size ) );
1033
const int i_len = __MIN( GetWBE(p_buffer), i_read-2 );
1037
seekpoint_t *s = vlc_seekpoint_New();
1039
s->psz_name = strndup( &p_buffer[2], i_len );
1040
EnsureUTF8( s->psz_name );
1042
s->i_time_offset = i_dts + __MAX( i_pts_delta, 0 );
1044
if( !p_sys->p_title )
1045
p_sys->p_title = vlc_input_title_New();
1046
TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s );
1049
if( tk->i_sample+1 >= tk->chunk[tk->i_chunk].i_sample_first +
1050
tk->chunk[tk->i_chunk].i_sample_count )
1054
static void LoadChapter( demux_t *p_demux )
1056
demux_sys_t *p_sys = p_demux->p_sys;
1059
if( ( p_chpl = MP4_BoxGet( p_sys->p_root, "/moov/udta/chpl" ) ) && p_chpl->data.p_chpl->i_chapter > 0 )
1061
LoadChapterGpac( p_demux, p_chpl );
1063
else if( p_sys->p_tref_chap )
1065
MP4_Box_data_tref_generic_t *p_chap = p_sys->p_tref_chap->data.p_tref_generic;
1068
/* Load the first subtitle track like quicktime */
1069
for( i = 0; i < p_chap->i_entry_count; i++ )
1071
for( j = 0; j < p_sys->i_tracks; j++ )
1073
mp4_track_t *tk = &p_sys->track[j];
1074
if( tk->b_ok && tk->i_track_ID == p_chap->i_track_ID[i] &&
1075
tk->fmt.i_cat == SPU_ES && tk->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) )
1078
if( j < p_sys->i_tracks )
1080
LoadChapterApple( p_demux, &p_sys->track[j] );
907
1087
/* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */
908
1088
static int TrackCreateChunksIndex( demux_t *p_demux,
1271
1463
/* It's a little ugly but .. there are special cases */
1272
1464
switch( p_sample->i_type )
1274
1466
case( VLC_FOURCC( '.', 'm', 'p', '3' ) ):
1275
1467
case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ):
1469
MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun;
1276
1470
p_track->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
1471
if( p_track->i_sample_size > 1 )
1472
p_soun->i_qt_version = 0;
1279
1476
case( VLC_FOURCC( 'r', 'a', 'w', ' ' ) ):
1280
p_track->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
1477
case( VLC_FOURCC( 'N', 'O', 'N', 'E' ) ):
1479
MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun;
1481
if(p_soun && (p_soun->i_samplesize+7)/8 == 1 )
1482
p_track->fmt.i_codec = VLC_FOURCC( 'u', '8', ' ', ' ' );
1484
p_track->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
1282
1486
/* Buggy files workaround */
1283
1487
if( p_sample->data.p_sample_soun && (p_track->i_timescale !=
1306
1511
p_track->fmt.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
1307
1512
/* FIXME: Not true, could be UTF-16 with a Byte Order Mark (0xfeff) */
1308
1513
/* FIXME UTF-8 doesn't work here ? */
1309
p_track->fmt.subs.psz_encoding = strdup( "UTF-8" );
1514
if( p_track->b_mac_encoding )
1515
p_track->fmt.subs.psz_encoding = strdup( "MAC" );
1517
p_track->fmt.subs.psz_encoding = strdup( "UTF-8" );
1520
case VLC_FOURCC('y','v','1','2'):
1521
p_track->fmt.i_codec = VLC_FOURCC('Y','V','1','2');
1523
case VLC_FOURCC('y','u','v','2'):
1524
p_track->fmt.i_codec = VLC_FOURCC('Y','U','Y','2');
1527
case VLC_FOURCC('i','n','2','4'):
1528
/* in in24/in32 there's enda-atom to tell it's little-endian (if present) */
1529
if( ( MP4_BoxGet( p_sample, "wave/enda" ) ) ||
1530
( MP4_BoxGet( p_sample, "enda" ) ) )
1532
p_track->fmt.i_codec = VLC_FOURCC('4','2','n','i');
1534
p_track->fmt.i_codec = p_sample->i_type;
2247
2536
msg_Warn( p_demux, "elst old=%d new=%d", i_elst_last, tk->i_elst );
2541
static const char *MP4_ConvertMacCode( uint16_t i_code )
2543
static const struct { const char *psz_iso639_1; uint16_t i_code; } p_cvt[] = {
2544
{ "en", 0 }, { "fr", 1 }, { "de", 2 }, { "it", 3 }, { "nl", 4 },
2545
{ "sv", 5 }, { "es", 6 }, { "da", 7 }, { "pt", 8 }, { "no", 9 },
2546
{ "he", 10 }, { "ja", 11 }, { "ar", 12 }, { "fi", 13 }, { "el", 14 },
2547
{ "is", 15 }, { "mt", 16 }, { "tr", 17 }, { "hr", 18 }, { "zh", 19 },
2548
{ "ur", 20 }, { "hi", 21 }, { "th", 22 }, { "ko", 23 }, { "lt", 24 },
2549
{ "pl", 25 }, { "hu", 26 }, { "et", 27 }, { "lv", 28 }, //{ "??", 29 },
2550
{ "fo", 30 }, { "fa", 31 }, { "ru", 32 }, { "zh", 33 }, { "nl", 34 },
2551
{ "ga", 35 }, { "sq", 36 }, { "ro", 37 }, { "cs", 38 }, { "sk", 39 },
2552
{ "sl", 40 }, { "yi", 41 }, { "sr", 42 }, { "mk", 43 }, { "bg", 44 },
2553
{ "uk", 45 }, { "be", 46 }, { "uz", 47 }, { "az", 48 }, { "kk", 48 },
2554
{ "az", 50 }, { "hy", 51 }, { "ka", 52 }, { "mo", 53 }, { "ky", 54 },
2555
{ "tg", 55 }, { "tk", 56 }, { "mn", 57 }, { "mn", 58 }, { "ps", 59 },
2556
{ "ku", 60 }, { "ks", 61 }, { "sd", 62 }, { "bo", 63 }, { "ne", 64 },
2557
{ "sa", 65 }, { "mr", 66 }, { "bn", 67 }, { "as", 68 }, { "gu", 69 },
2558
{ "pa", 70 }, { "or", 71 }, { "ml", 72 }, { "kn", 73 }, { "ta", 74 },
2559
{ "te", 75 }, { "si", 76 }, { "my", 77 }, { "km", 78 }, { "lo", 79 },
2560
{ "vi", 80 }, { "id", 81 }, { "tl", 82 }, { "ms", 83 }, { "ms", 84 },
2561
{ "am", 85 }, { "ti", 86 }, { "om", 87 }, { "so", 88 }, { "sw", 89 },
2562
{ "rw", 90 }, { "rn", 91 }, { "ny", 92 }, { "mg", 93 }, { "eo", 94 },
2564
{ "cy", 128 }, { "eu", 129 },
2565
{ "ca", 130 }, { "la", 131 }, { "qu", 132 }, { "gn", 133 }, { "ay", 134 },
2566
{ "tt", 135 }, { "ug", 136 }, { "dz", 137 }, { "jv", 138 }, { "su", 139 },
2567
{ "gl", 140 }, { "af", 141 }, { "br", 142 }, { "iu", 143 }, { "gd", 144 },
2568
{ "gv", 145 }, { "ga", 146 }, { "to", 147 }, { "el", 148 },
2573
for( i = 0; p_cvt[i].psz_iso639_1 != NULL; i++ )
2575
if( p_cvt[i].i_code == i_code )
2576
return p_cvt[i].psz_iso639_1;