Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-gpu
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc-gpu
Commits
6211bb6c
Commit
6211bb6c
authored
Jun 15, 2007
by
Laurent Aimar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added apple chapter support (used by HandBrake, close #808)
parent
9acaa4b2
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
200 additions
and
53 deletions
+200
-53
modules/demux/mp4/libmp4.c
modules/demux/mp4/libmp4.c
+33
-3
modules/demux/mp4/libmp4.h
modules/demux/mp4/libmp4.h
+10
-0
modules/demux/mp4/mp4.c
modules/demux/mp4/mp4.c
+157
-50
No files found.
modules/demux/mp4/libmp4.c
View file @
6211bb6c
...
...
@@ -238,11 +238,14 @@ static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box )
if
(
p_box
->
p_father
)
{
const
int
i_box_end
=
p_box
->
i_size
+
p_box
->
i_pos
;
const
int
i_father_end
=
p_box
->
p_father
->
i_size
+
p_box
->
p_father
->
i_pos
;
/* check if it's within p-father */
if
(
p_box
->
i_size
+
p_box
->
i_pos
>=
p_box
->
p_father
->
i_size
+
p_box
->
p_father
->
i_pos
)
if
(
i_box_end
>=
i_father_end
)
{
msg_Dbg
(
p_stream
,
"out of bound child"
);
if
(
i_box_end
>
i_father_end
)
msg_Dbg
(
p_stream
,
"out of bound child"
);
return
0
;
/* out of bound */
}
}
...
...
@@ -2220,6 +2223,32 @@ static void MP4_FreeBox_chpl( MP4_Box_t *p_box )
free
(
p_chpl
->
chapter
[
i
].
psz_name
);
}
static
int
MP4_ReadBox_tref_generic
(
stream_t
*
p_stream
,
MP4_Box_t
*
p_box
)
{
unsigned
int
i
;
MP4_READBOX_ENTER
(
MP4_Box_data_tref_generic_t
);
p_box
->
data
.
p_tref_generic
->
i_track_ID
=
NULL
;
p_box
->
data
.
p_tref_generic
->
i_entry_count
=
i_read
/
sizeof
(
uint32_t
);
if
(
p_box
->
data
.
p_tref_generic
->
i_entry_count
>
0
)
p_box
->
data
.
p_tref_generic
->
i_track_ID
=
malloc
(
p_box
->
data
.
p_tref_generic
->
i_entry_count
*
sizeof
(
uint32_t
)
);
for
(
i
=
0
;
i
<
p_box
->
data
.
p_tref_generic
->
i_entry_count
;
i
++
)
{
MP4_GET4BYTES
(
p_box
->
data
.
p_tref_generic
->
i_track_ID
[
i
]
);
}
#ifdef MP4_VERBOSE
msg_Dbg
(
p_stream
,
"read box:
\"
chap
\"
%d references"
,
p_box
->
data
.
p_tref_generic
->
i_entry_count
);
#endif
MP4_READBOX_EXIT
(
1
);
}
static
void
MP4_FreeBox_tref_generic
(
MP4_Box_t
*
p_box
)
{
FREENULL
(
p_box
->
data
.
p_tref_generic
->
i_track_ID
);
}
static
int
MP4_ReadBox_meta
(
stream_t
*
p_stream
,
MP4_Box_t
*
p_box
)
{
uint8_t
meta_data
[
8
];
...
...
@@ -2421,6 +2450,7 @@ static struct
{
FOURCC_dpnd
,
MP4_ReadBox_default
,
NULL
},
{
FOURCC_ipir
,
MP4_ReadBox_default
,
NULL
},
{
FOURCC_mpod
,
MP4_ReadBox_default
,
NULL
},
{
FOURCC_chap
,
MP4_ReadBox_tref_generic
,
MP4_FreeBox_tref_generic
},
/* found in hnti */
{
FOURCC_rtp
,
MP4_ReadBox_default
,
NULL
},
...
...
modules/demux/mp4/libmp4.h
View file @
6211bb6c
...
...
@@ -215,6 +215,8 @@
#define FOURCC_meta VLC_FOURCC( 'm', 'e', 't', 'a' )
#define FOURCC_ilst VLC_FOURCC( 'i', 'l', 's', 't' )
#define FOURCC_chap VLC_FOURCC( 'c', 'h', 'a', 'p' )
/* Do you want some debug information on all read boxes ? */
#define MP4_VERBOSE 1
...
...
@@ -791,6 +793,13 @@ typedef struct
}
MP4_Box_data_0xa9xxx_t
;
typedef
struct
{
uint32_t
i_entry_count
;
uint32_t
*
i_track_ID
;
}
MP4_Box_data_tref_generic_t
;
typedef
struct
{
uint8_t
i_version
;
...
...
@@ -887,6 +896,7 @@ typedef union MP4_Box_data_s
MP4_Box_data_0xa9xxx_t
*
p_0xa9xxx
;
MP4_Box_data_chpl_t
*
p_chpl
;
MP4_Box_data_tref_generic_t
*
p_tref_generic
;
void
*
p_data
;
/* for unknow type */
}
MP4_Box_data_t
;
...
...
modules/demux/mp4/mp4.c
View file @
6211bb6c
...
...
@@ -92,11 +92,12 @@ typedef struct
/* Contain all needed information for read all track with vlc */
typedef
struct
{
int
i_track_ID
;
/* this should be unique */
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 */
vlc_bool_t
b_selected
;
/* is the trak being played */
int
b_ok
;
/* The track is usable */
int
b_enable
;
/* is the trak enable by default */
vlc_bool_t
b_selected
;
/* is the trak being played */
vlc_bool_t
b_chapter
;
/* True when used for chapter only */
es_format_t
fmt
;
es_out_id_t
*
p_es
;
...
...
@@ -145,12 +146,15 @@ struct demux_sys_t
mtime_t
i_pcr
;
uint64_t
i_time
;
/* time position of the presentation
* in movie timescale */
uint64_t
i_timescale
;
/* movie time scale */
uint64_t
i_duration
;
/* movie duration */
unsigned
int
i_tracks
;
/* number of tracks */
mp4_track_t
*
track
;
/* array of track */
uint64_t
i_time
;
/* time position of the presentation
* in movie timescale */
uint64_t
i_timescale
;
/* movie time scale */
uint64_t
i_duration
;
/* movie duration */
unsigned
int
i_tracks
;
/* number of tracks */
mp4_track_t
*
track
;
/* array of track */
/* */
MP4_Box_t
*
p_tref_chap
;
/* */
input_title_t
*
p_title
;
...
...
@@ -254,6 +258,8 @@ static inline int64_t MP4_GetMoviePTS(demux_sys_t *p_sys )
static
vlc_bool_t
FindItem
(
demux_t
*
p_demux
,
playlist_t
*
p_playlist
,
playlist_item_t
**
pp_item
);
static
void
LoadChapter
(
demux_t
*
p_demux
);
/*****************************************************************************
* Open: check file and initializes MP4 structures
*****************************************************************************/
...
...
@@ -268,7 +274,6 @@ static int Open( vlc_object_t * p_this )
MP4_Box_t
*
p_rmra
;
MP4_Box_t
*
p_mvhd
;
MP4_Box_t
*
p_trak
;
MP4_Box_t
*
p_chpl
;
unsigned
int
i
;
vlc_bool_t
b_seekable
;
...
...
@@ -479,13 +484,26 @@ static int Open( vlc_object_t * p_this )
p_sys
->
track
=
calloc
(
p_sys
->
i_tracks
,
sizeof
(
mp4_track_t
)
);
memset
(
p_sys
->
track
,
0
,
p_sys
->
i_tracks
*
sizeof
(
mp4_track_t
)
);
/* Search the first chap reference (like quicktime) */
p_sys
->
p_tref_chap
=
NULL
;
for
(
i
=
0
;
i
<
p_sys
->
i_tracks
;
i
++
)
{
MP4_Box_t
*
p_trak
=
MP4_BoxGet
(
p_sys
->
p_root
,
"/moov/trak[%d]"
,
i
);
MP4_Box_t
*
p_chap
=
MP4_BoxGet
(
p_trak
,
"tref/chap"
,
i
);
if
(
!
p_chap
||
p_chap
->
data
.
p_tref_generic
->
i_entry_count
<=
0
)
continue
;
p_sys
->
p_tref_chap
=
p_chap
;
break
;
}
/* now process each track and extract all usefull information */
for
(
i
=
0
;
i
<
p_sys
->
i_tracks
;
i
++
)
{
p_trak
=
MP4_BoxGet
(
p_sys
->
p_root
,
"/moov/trak[%d]"
,
i
);
MP4_TrackCreate
(
p_demux
,
&
p_sys
->
track
[
i
],
p_trak
);
if
(
p_sys
->
track
[
i
].
b_ok
)
if
(
p_sys
->
track
[
i
].
b_ok
&&
!
p_sys
->
track
[
i
].
b_chapter
)
{
const
char
*
psz_cat
;
switch
(
p_sys
->
track
[
i
].
fmt
.
i_cat
)
...
...
@@ -511,29 +529,23 @@ static int Open( vlc_object_t * p_this )
p_sys
->
track
[
i
].
fmt
.
psz_language
?
p_sys
->
track
[
i
].
fmt
.
psz_language
:
"undef"
);
}
else
if
(
p_sys
->
track
[
i
].
b_ok
&&
p_sys
->
track
[
i
].
b_chapter
)
{
msg_Dbg
(
p_demux
,
"using track[Id 0x%x] for chapter language %s"
,
p_sys
->
track
[
i
].
i_track_ID
,
p_sys
->
track
[
i
].
fmt
.
psz_language
?
p_sys
->
track
[
i
].
fmt
.
psz_language
:
"undef"
);
}
else
{
msg_Dbg
(
p_demux
,
"ignoring track[Id 0x%x]"
,
p_sys
->
track
[
i
].
i_track_ID
);
}
}
/* Process chapter if any */
if
(
(
p_chpl
=
MP4_BoxGet
(
p_sys
->
p_root
,
"/moov/udta/chpl"
)
)
&&
p_chpl
->
data
.
p_chpl
->
i_chapter
>
0
)
{
int
i
;
p_sys
->
p_title
=
vlc_input_title_New
();
for
(
i
=
0
;
i
<
p_chpl
->
data
.
p_chpl
->
i_chapter
;
i
++
)
{
seekpoint_t
*
s
=
vlc_seekpoint_New
();
/* */
LoadChapter
(
p_demux
);
s
->
psz_name
=
strdup
(
p_chpl
->
data
.
p_chpl
->
chapter
[
i
].
psz_name
);
EnsureUTF8
(
s
->
psz_name
);
s
->
i_time_offset
=
p_chpl
->
data
.
p_chpl
->
chapter
[
i
].
i_start
/
10
;
TAB_APPEND
(
p_sys
->
p_title
->
i_seekpoint
,
p_sys
->
p_title
->
seekpoint
,
s
);
}
}
return
VLC_SUCCESS
;
error:
...
...
@@ -565,7 +577,7 @@ static int Demux( demux_t *p_demux )
mp4_track_t
*
tk
=
&
p_sys
->
track
[
i_track
];
vlc_bool_t
b
;
if
(
!
tk
->
b_ok
||
if
(
!
tk
->
b_ok
||
tk
->
b_chapter
||
(
tk
->
b_selected
&&
tk
->
i_sample
>=
tk
->
i_sample_count
)
)
{
continue
;
...
...
@@ -620,10 +632,8 @@ static int Demux( demux_t *p_demux )
{
mp4_track_t
*
tk
=
&
p_sys
->
track
[
i_track
];
if
(
!
tk
->
b_ok
||
!
tk
->
b_selected
||
tk
->
i_sample
>=
tk
->
i_sample_count
)
{
if
(
!
tk
->
b_ok
||
tk
->
b_chapter
||
!
tk
->
b_selected
||
tk
->
i_sample
>=
tk
->
i_sample_count
)
continue
;
}
while
(
MP4_TrackGetDTS
(
p_demux
,
tk
)
<
MP4_GetMoviePTS
(
p_sys
)
)
{
...
...
@@ -708,9 +718,7 @@ static int Demux( demux_t *p_demux )
/* Next sample */
if
(
MP4_TrackNextSample
(
p_demux
,
tk
)
)
{
break
;
}
}
}
...
...
@@ -959,9 +967,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
*****************************************************************************/
static
void
Close
(
vlc_object_t
*
p_this
)
{
unsigned
int
i_track
;
demux_t
*
p_demux
=
(
demux_t
*
)
p_this
;
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
unsigned
int
i_track
;
msg_Dbg
(
p_demux
,
"freeing all memory"
);
...
...
@@ -983,6 +991,90 @@ static void Close ( vlc_object_t * p_this )
/****************************************************************************
* Local functions, specific to vlc
****************************************************************************/
/* Chapters */
static
void
LoadChapterGpac
(
demux_t
*
p_demux
,
MP4_Box_t
*
p_chpl
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
int
i
;
p_sys
->
p_title
=
vlc_input_title_New
();
for
(
i
=
0
;
i
<
p_chpl
->
data
.
p_chpl
->
i_chapter
;
i
++
)
{
seekpoint_t
*
s
=
vlc_seekpoint_New
();
s
->
psz_name
=
strdup
(
p_chpl
->
data
.
p_chpl
->
chapter
[
i
].
psz_name
);
EnsureUTF8
(
s
->
psz_name
);
s
->
i_time_offset
=
p_chpl
->
data
.
p_chpl
->
chapter
[
i
].
i_start
/
10
;
TAB_APPEND
(
p_sys
->
p_title
->
i_seekpoint
,
p_sys
->
p_title
->
seekpoint
,
s
);
}
}
static
void
LoadChapterApple
(
demux_t
*
p_demux
,
mp4_track_t
*
tk
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
for
(
tk
->
i_sample
=
0
;
tk
->
i_sample
<
tk
->
i_sample_count
;
tk
->
i_sample
++
)
{
const
int64_t
i_dts
=
MP4_TrackGetDTS
(
p_demux
,
tk
);
const
int64_t
i_pts_delta
=
MP4_TrackGetPTSDelta
(
p_demux
,
tk
);
const
unsigned
int
i_size
=
MP4_TrackSampleSize
(
tk
);
if
(
i_size
>
0
&&
!
stream_Seek
(
p_demux
->
s
,
MP4_TrackGetPos
(
tk
)
)
)
{
char
p_buffer
[
256
];
const
int
i_read
=
stream_Read
(
p_demux
->
s
,
p_buffer
,
__MIN
(
sizeof
(
p_buffer
),
i_size
)
);
const
int
i_len
=
__MIN
(
GetWBE
(
p_buffer
),
i_read
-
2
);
if
(
i_len
>
0
)
{
seekpoint_t
*
s
=
vlc_seekpoint_New
();
s
->
psz_name
=
strndup
(
&
p_buffer
[
2
],
i_len
);
EnsureUTF8
(
s
->
psz_name
);
s
->
i_time_offset
=
i_dts
+
__MAX
(
i_pts_delta
,
0
);
if
(
!
p_sys
->
p_title
)
p_sys
->
p_title
=
vlc_input_title_New
();
TAB_APPEND
(
p_sys
->
p_title
->
i_seekpoint
,
p_sys
->
p_title
->
seekpoint
,
s
);
}
}
if
(
tk
->
i_sample
+
1
>=
tk
->
chunk
[
tk
->
i_chunk
].
i_sample_first
+
tk
->
chunk
[
tk
->
i_chunk
].
i_sample_count
)
tk
->
i_chunk
++
;
}
}
static
void
LoadChapter
(
demux_t
*
p_demux
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
MP4_Box_t
*
p_chpl
;
if
(
(
p_chpl
=
MP4_BoxGet
(
p_sys
->
p_root
,
"/moov/udta/chpl"
)
)
&&
p_chpl
->
data
.
p_chpl
->
i_chapter
>
0
)
{
LoadChapterGpac
(
p_demux
,
p_chpl
);
}
else
if
(
p_sys
->
p_tref_chap
)
{
MP4_Box_data_tref_generic_t
*
p_chap
=
p_sys
->
p_tref_chap
->
data
.
p_tref_generic
;
unsigned
int
i
,
j
;
/* Load the first subtitle track like quicktime */
for
(
i
=
0
;
i
<
p_chap
->
i_entry_count
;
i
++
)
{
for
(
j
=
0
;
j
<
p_sys
->
i_tracks
;
j
++
)
{
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'
)
)
break
;
}
if
(
j
<
p_sys
->
i_tracks
)
{
LoadChapterApple
(
p_demux
,
&
p_sys
->
track
[
i
]
);
break
;
}
}
}
}
/* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */
static
int
TrackCreateChunksIndex
(
demux_t
*
p_demux
,
...
...
@@ -1267,7 +1359,8 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track,
MP4_Box_t
*
p_esds
;
MP4_Box_t
*
p_box
;
*
pp_es
=
NULL
;
if
(
pp_es
)
*
pp_es
=
NULL
;
if
(
!
p_track
->
chunk
[
i_chunk
].
i_sample_description_index
)
{
...
...
@@ -1580,7 +1673,8 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track,
break
;
}
*
pp_es
=
es_out_Add
(
p_demux
->
out
,
&
p_track
->
fmt
);
if
(
pp_es
)
*
pp_es
=
es_out_Add
(
p_demux
->
out
,
&
p_track
->
fmt
);
return
VLC_SUCCESS
;
}
...
...
@@ -1600,10 +1694,8 @@ static int TrackTimeToSampleChunk( demux_t *p_demux, mp4_track_t *p_track,
int
i_index
;
/* FIXME see if it's needed to check p_track->i_chunk_count */
if
(
!
p_track
->
b_ok
||
p_track
->
i_chunk_count
==
0
)
{
if
(
p_track
->
i_chunk_count
==
0
)
return
(
VLC_EGENERIC
);
}
/* handle elst (find the correct one) */
MP4_TrackSetELST
(
p_demux
,
p_track
,
i_start
);
...
...
@@ -1829,6 +1921,7 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track,
p_track
->
b_ok
=
VLC_FALSE
;
p_track
->
b_enable
=
VLC_FALSE
;
p_track
->
b_selected
=
VLC_FALSE
;
p_track
->
b_chapter
=
VLC_FALSE
;
es_format_Init
(
&
p_track
->
fmt
,
UNKNOWN_ES
,
0
);
...
...
@@ -1964,16 +2057,33 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track,
p_track
->
i_chunk
=
0
;
p_track
->
i_sample
=
0
;
/* Mark chapter only track */
if
(
!
p_track
->
b_enable
&&
p_sys
->
p_tref_chap
)
{
MP4_Box_data_tref_generic_t
*
p_chap
=
p_sys
->
p_tref_chap
->
data
.
p_tref_generic
;
unsigned
int
i
;
for
(
i
=
0
;
i
<
p_chap
->
i_entry_count
;
i
++
)
{
if
(
p_track
->
i_track_ID
==
p_chap
->
i_track_ID
[
i
]
)
{
p_track
->
b_chapter
=
VLC_TRUE
;
break
;
}
}
}
/* now create es */
p_track
->
p_es
=
NULL
;
if
(
TrackCreateES
(
p_demux
,
p_track
,
p_track
->
i_chunk
,
&
p_track
->
p_es
)
)
p_track
->
b_chapter
?
NULL
:
&
p_track
->
p_es
)
)
{
msg_Err
(
p_demux
,
"cannot create es for track[Id 0x%x]"
,
p_track
->
i_track_ID
);
return
;
}
p_track
->
b_ok
=
VLC_TRUE
;
#if 0
{
int i;
...
...
@@ -1986,7 +2096,6 @@ static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track,
}
}
#endif
p_track
->
b_ok
=
VLC_TRUE
;
}
/****************************************************************************
...
...
@@ -2026,7 +2135,7 @@ static void MP4_TrackDestroy( demux_t *p_demux, mp4_track_t *p_track )
static
int
MP4_TrackSelect
(
demux_t
*
p_demux
,
mp4_track_t
*
p_track
,
mtime_t
i_start
)
{
if
(
!
p_track
->
b_ok
)
if
(
!
p_track
->
b_ok
||
p_track
->
b_chapter
)
{
return
VLC_EGENERIC
;
}
...
...
@@ -2043,7 +2152,7 @@ static int MP4_TrackSelect( demux_t *p_demux, mp4_track_t *p_track,
static
void
MP4_TrackUnselect
(
demux_t
*
p_demux
,
mp4_track_t
*
p_track
)
{
if
(
!
p_track
->
b_ok
)
if
(
!
p_track
->
b_ok
||
p_track
->
b_chapter
)
{
return
;
}
...
...
@@ -2069,10 +2178,8 @@ static int MP4_TrackSeek( demux_t *p_demux, mp4_track_t *p_track,
uint32_t
i_chunk
;
uint32_t
i_sample
;
if
(
!
p_track
->
b_ok
)
{
return
(
VLC_EGENERIC
);
}
if
(
!
p_track
->
b_ok
||
p_track
->
b_chapter
)
return
VLC_EGENERIC
;
p_track
->
b_selected
=
VLC_FALSE
;
...
...
@@ -2081,7 +2188,7 @@ static int MP4_TrackSeek( demux_t *p_demux, mp4_track_t *p_track,
{
msg_Warn
(
p_demux
,
"cannot select track[Id 0x%x]"
,
p_track
->
i_track_ID
);
return
(
VLC_EGENERIC
)
;
return
VLC_EGENERIC
;
}
p_track
->
b_selected
=
VLC_TRUE
;
...
...
@@ -2095,7 +2202,7 @@ static int MP4_TrackSeek( demux_t *p_demux, mp4_track_t *p_track,
p_track
->
p_es
,
i_start
);
}
return
(
p_track
->
b_selected
?
VLC_SUCCESS
:
VLC_EGENERIC
)
;
return
p_track
->
b_selected
?
VLC_SUCCESS
:
VLC_EGENERIC
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment