Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
GSoC
GSoC2018
macOS
vlc
Commits
86e8c9d5
Commit
86e8c9d5
authored
Jul 18, 2012
by
Frédéric Yhuel
Committed by
Jean-Baptiste Kempf
Sep 21, 2012
Browse files
demux/mp4: Add fragmented MP4 support
Signed-off-by:
Jean-Baptiste Kempf
<
jb@videolan.org
>
parent
2f1fe72f
Changes
3
Hide whitespace changes
Inline
Side-by-side
modules/demux/mp4/libmp4.c
View file @
86e8c9d5
...
...
@@ -159,15 +159,20 @@ static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box )
if
(
p_box
->
p_father
)
{
const
off_t
i_box_end
=
p_box
->
i_size
+
p_box
->
i_pos
;
const
off_t
i_father_end
=
p_box
->
p_father
->
i_size
+
p_box
->
p_father
->
i_pos
;
/* check if it's within p-father */
if
(
i_box_end
>=
i_father_end
)
/* if father's size == 0, it means unknown or infinite size,
* and we skip the followong check */
if
(
p_box
->
p_father
->
i_size
>
0
)
{
if
(
i_box_end
>
i_father_end
)
msg_Dbg
(
p_stream
,
"out of bound child"
);
return
0
;
/* out of bound */
const
off_t
i_box_end
=
p_box
->
i_size
+
p_box
->
i_pos
;
const
off_t
i_father_end
=
p_box
->
p_father
->
i_size
+
p_box
->
p_father
->
i_pos
;
/* check if it's within p-father */
if
(
i_box_end
>=
i_father_end
)
{
if
(
i_box_end
>
i_father_end
)
msg_Dbg
(
p_stream
,
"out of bound child"
);
return
0
;
/* out of bound */
}
}
}
if
(
stream_Seek
(
p_stream
,
p_box
->
i_size
+
p_box
->
i_pos
)
)
...
...
@@ -184,12 +189,17 @@ static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box )
* after called one of theses functions, file position is unknown
* you need to call MP4_GotoBox to go where you want
*****************************************************************************/
static
int
MP4_ReadBoxContainerRaw
(
stream_t
*
p_stream
,
MP4_Box_t
*
p_container
)
static
int
MP4_ReadBoxContainerChildren
(
stream_t
*
p_stream
,
MP4_Box_t
*
p_container
,
uint32_t
i_last_child
)
{
MP4_Box_t
*
p_box
;
if
(
stream_Tell
(
p_stream
)
+
8
>
/* Size of root container is set to 0 when unknown, for exemple
* with a DASH stream. In that case, we skip the following check */
if
(
p_container
->
i_size
&&
(
stream_Tell
(
p_stream
)
+
8
>
(
off_t
)(
p_container
->
i_pos
+
p_container
->
i_size
)
)
)
{
/* there is no box to load */
return
0
;
...
...
@@ -204,14 +214,23 @@ static int MP4_ReadBoxContainerRaw( stream_t *p_stream, MP4_Box_t *p_container )
else
p_container
->
p_last
->
p_next
=
p_box
;
p_container
->
p_last
=
p_box
;
if
(
p_box
->
i_type
==
i_last_child
)
break
;
}
while
(
MP4_NextBox
(
p_stream
,
p_box
)
==
1
);
return
1
;
}
static
int
MP4_ReadBoxContainerRaw
(
stream_t
*
p_stream
,
MP4_Box_t
*
p_container
)
{
return
MP4_ReadBoxContainerChildren
(
p_stream
,
p_container
,
0
);
}
static
int
MP4_ReadBoxContainer
(
stream_t
*
p_stream
,
MP4_Box_t
*
p_container
)
{
if
(
p_container
->
i_size
<=
(
size_t
)
mp4_box_headersize
(
p_container
)
+
8
)
if
(
p_container
->
i_size
&&
(
p_container
->
i_size
<=
(
size_t
)
mp4_box_headersize
(
p_container
)
+
8
)
)
{
/* container is empty, 8 stand for the first header in this box */
return
1
;
...
...
@@ -497,22 +516,23 @@ static int MP4_ReadBox_stra( stream_t *p_stream, MP4_Box_t *p_box )
MP4_GET4BYTES
(
p_stra
->
BitsPerSample
);
MP4_GET4BYTES
(
p_stra
->
PacketSize
);
MP4_GET4BYTES
(
p_stra
->
AudioTag
);
MP4_GET4BYTES
(
p_stra
->
AvgBytesPerSec
);
MP4_GET2BYTES
(
p_stra
->
nBlockAlign
);
MP4_GET1BYTE
(
i_reserved
);
MP4_GET1BYTE
(
i_reserved
);
MP4_GET1BYTE
(
i_reserved
);
uint8_t
codec_data_length
;
MP4_GET1BYTE
(
codec_data_length
);
p_stra
->
CodecPrivateData
=
malloc
(
codec_data_length
+
1
);
MP4_GET1BYTE
(
p_stra
->
cpd_len
);
if
(
p_stra
->
cpd_len
>
i_read
)
goto
error
;
p_stra
->
CodecPrivateData
=
malloc
(
p_stra
->
cpd_len
);
if
(
unlikely
(
p_stra
->
CodecPrivateData
==
NULL
)
)
goto
error
;
MP4_GETSTRINGZ
(
p_stra
->
CodecPrivateData
);
memcpy
(
p_stra
->
CodecPrivateData
,
p_peek
,
p_stra
->
cpd_len
);
#ifdef MP4_VERBOSE
msg_Dbg
(
p_stream
,
"es_cat is %"
PRIu8
", birate is %"
PRIu32
", "
\
"CodecPrivateData is %s"
,
p_stra
->
i_es_cat
,
p_stra
->
Bitrate
,
p_stra
->
CodecPrivateData
);
msg_Dbg
(
p_stream
,
"es_cat is %"
PRIu8
", birate is %"
PRIu32
,
p_stra
->
i_es_cat
,
p_stra
->
Bitrate
);
#endif
MP4_READBOX_EXIT
(
1
);
...
...
@@ -3474,57 +3494,7 @@ error:
return
NULL
;
}
MP4_Box_t
*
MP4_BoxGetInitFrag
(
stream_t
*
s
)
{
/* p_chunk is a virtual root container for the ftyp and moov boxes */
MP4_Box_t
*
p_chunk
;
MP4_Box_t
*
p_ftyp
;
MP4_Box_t
*
p_moov
;
p_chunk
=
calloc
(
1
,
sizeof
(
MP4_Box_t
)
);
if
(
unlikely
(
p_chunk
==
NULL
)
)
return
NULL
;
p_chunk
->
i_type
=
ATOM_root
;
p_chunk
->
i_shortsize
=
1
;
p_ftyp
=
MP4_ReadBox
(
s
,
p_chunk
);
if
(
!
p_ftyp
)
{
msg_Warn
(
s
,
"no ftyp box found!"
);
goto
error
;
}
/* there may be some boxes between ftyp and moov,
* we skip them, but put a reasonable limit */
#define MAX_SKIP 8
for
(
int
i
=
0
;
i
<
MAX_SKIP
;
i
++
)
{
p_moov
=
MP4_ReadBox
(
s
,
p_chunk
);
if
(
!
p_moov
)
goto
error
;
if
(
p_moov
->
i_type
!=
ATOM_moov
)
{
if
(
i
==
MAX_SKIP
-
1
)
return
NULL
;
stream_Read
(
s
,
NULL
,
p_moov
->
i_size
);
MP4_BoxFree
(
s
,
p_moov
);
}
else
break
;
}
p_chunk
->
p_first
=
p_ftyp
;
p_ftyp
->
p_next
=
p_moov
;
p_chunk
->
p_last
=
p_moov
;
return
p_chunk
;
error:
free
(
p_chunk
);
return
NULL
;
}
MP4_Box_t
*
MP4_BoxGetNextChunk
(
stream_t
*
s
)
{
/* p_chunk is a virtual root container for the moof and mdat boxes */
...
...
@@ -3546,7 +3516,7 @@ MP4_Box_t *MP4_BoxGetNextChunk( stream_t *s )
}
else
if
(
p_tmp_box
->
i_type
==
ATOM_ftyp
)
{
return
MP4_BoxGet
InitFrag
(
s
);
return
MP4_BoxGet
Root
(
s
);
}
free
(
p_tmp_box
);
...
...
@@ -3620,7 +3590,8 @@ MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
p_root
->
i_pos
=
0
;
p_root
->
i_type
=
ATOM_root
;
p_root
->
i_shortsize
=
1
;
p_root
->
i_size
=
stream_Size
(
s
);
/* could be a DASH stream for exemple, 0 means unknown or infinite size */
p_root
->
i_size
=
0
;
CreateUUID
(
&
p_root
->
i_uuid
,
p_root
->
i_type
);
p_root
->
data
.
p_data
=
NULL
;
...
...
@@ -3631,37 +3602,52 @@ MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
p_stream
=
s
;
/* First get the moov */
i_result
=
MP4_ReadBoxContainerChildren
(
p_stream
,
p_root
,
ATOM_moov
);
if
(
!
i_result
)
goto
error
;
/* If there is a mvex box, it means fragmented MP4, and we're done */
else
if
(
MP4_BoxCount
(
p_root
,
"moov/mvex"
)
>
0
)
return
p_root
;
p_root
->
i_size
=
stream_Size
(
s
);
/* Get the rest of the file */
i_result
=
MP4_ReadBoxContainerRaw
(
p_stream
,
p_root
);
if
(
i_result
)
{
MP4_Box_t
*
p_moov
;
MP4_Box_t
*
p_cmov
;
if
(
!
i_result
)
goto
error
;
/* check if there is a cmov, if so replace
compressed moov by uncompressed one */
if
(
(
(
p_moov
=
MP4_BoxGet
(
p_root
,
"moov"
)
)
&&
(
p_cmov
=
MP4_BoxGet
(
p_root
,
"moov/cmov"
)
)
)
||
(
(
p_moov
=
MP4_BoxGet
(
p_root
,
"foov"
)
)
&&
(
p_cmov
=
MP4_BoxGet
(
p_root
,
"foov/cmov"
)
)
)
)
{
/* rename the compressed moov as a box to skip */
p_moov
->
i_type
=
ATOM_skip
;
MP4_Box_t
*
p_moov
;
MP4_Box_t
*
p_cmov
;
/* check if there is a cmov, if so replace
compressed moov by uncompressed one */
if
(
(
(
p_moov
=
MP4_BoxGet
(
p_root
,
"moov"
)
)
&&
(
p_cmov
=
MP4_BoxGet
(
p_root
,
"moov/cmov"
)
)
)
||
(
(
p_moov
=
MP4_BoxGet
(
p_root
,
"foov"
)
)
&&
(
p_cmov
=
MP4_BoxGet
(
p_root
,
"foov/cmov"
)
)
)
)
{
/* rename the compressed moov as a box to skip */
p_moov
->
i_type
=
ATOM_skip
;
/* get uncompressed p_moov */
p_moov
=
p_cmov
->
data
.
p_cmov
->
p_moov
;
p_cmov
->
data
.
p_cmov
->
p_moov
=
NULL
;
/* get uncompressed p_moov */
p_moov
=
p_cmov
->
data
.
p_cmov
->
p_moov
;
p_cmov
->
data
.
p_cmov
->
p_moov
=
NULL
;
/* make p_root father of this new moov */
p_moov
->
p_father
=
p_root
;
/* make p_root father of this new moov */
p_moov
->
p_father
=
p_root
;
/* insert this new moov box as first child of p_root */
p_moov
->
p_next
=
p_root
->
p_first
;
p_root
->
p_first
=
p_moov
;
}
/* insert this new moov box as first child of p_root */
p_moov
->
p_next
=
p_root
->
p_first
;
p_root
->
p_first
=
p_moov
;
}
return
p_root
;
error:
free
(
p_root
);
return
NULL
;
}
...
...
modules/demux/mp4/libmp4.h
View file @
86e8c9d5
...
...
@@ -1140,12 +1140,14 @@ typedef struct
uint32_t
MaxWidth
;
uint32_t
MaxHeight
;
uint32_t
SamplingRate
;
uint32_t
AvgBytesPerSec
;
uint32_t
Channels
;
uint32_t
BitsPerSample
;
uint32_t
PacketSize
;
uint32_t
AudioTag
;
uint16_t
nBlockAlign
;
char
*
CodecPrivateData
;
uint8_t
cpd_len
;
uint8_t
*
CodecPrivateData
;
}
MP4_Box_data_stra_t
;
/*
...
...
@@ -1346,7 +1348,8 @@ typedef struct
MP4_Box_t
*
p_sample
;
/* point on actual sdsd */
bool
b_drms
;
bool
b_end_of_chunk
;
bool
b_has_non_empty_cchunk
;
bool
b_codec_need_restart
;
void
*
p_drms
;
MP4_Box_t
*
p_skcr
;
...
...
@@ -1477,13 +1480,6 @@ static const UUID_t StraBoxUUID = {
0x96
,
0xc7
,
0xbf
,
0x25
,
0xf9
,
0x7e
,
0x24
,
0x47
}
};
MP4_Box_t
*
MP4_BoxGetSmooBox
(
stream_t
*
);
/*****************************************************************************
* MP4_BoxGetInitFrag : Parse the initialization segment.
*****************************************************************************
* The first box is a virtual box "root", and is the father of the boxes
* 'ftyp' and 'moov'.
*****************************************************************************/
MP4_Box_t
*
MP4_BoxGetInitFrag
(
stream_t
*
);
/*****************************************************************************
* MP4_BoxGetNextChunk : Parse the entire moof box.
...
...
modules/demux/mp4/mp4.c
View file @
86e8c9d5
...
...
@@ -35,6 +35,7 @@
#include
<vlc_charset.h>
/* EnsureUTF8 */
#include
<vlc_meta.h>
/* vlc_meta_t, vlc_meta_ */
#include
<vlc_input.h>
#include
<assert.h>
#include
"libmp4.h"
#include
"id3genres.h"
/* for ATOM_gnre */
...
...
@@ -59,6 +60,7 @@ vlc_module_end ()
*****************************************************************************/
static
int
Demux
(
demux_t
*
);
static
int
DemuxRef
(
demux_t
*
p_demux
){
(
void
)
p_demux
;
return
0
;}
static
int
DemuxFrg
(
demux_t
*
);
static
int
Seek
(
demux_t
*
,
mtime_t
);
static
int
Control
(
demux_t
*
,
int
,
va_list
);
...
...
@@ -76,6 +78,8 @@ struct demux_sys_t
mp4_track_t
*
track
;
/* array of track */
float
f_fps
;
/* number of frame per seconds */
bool
b_fragmented
;
/* fMP4 */
/* */
MP4_Box_t
*
p_tref_chap
;
...
...
@@ -87,6 +91,7 @@ struct demux_sys_t
* Declaration of local function
*****************************************************************************/
static
void
MP4_TrackCreate
(
demux_t
*
,
mp4_track_t
*
,
MP4_Box_t
*
,
bool
b_force_enable
);
static
int
MP4_frg_TrackCreate
(
demux_t
*
,
mp4_track_t
*
,
MP4_Box_t
*
);
static
void
MP4_TrackDestroy
(
mp4_track_t
*
);
static
int
MP4_TrackSelect
(
demux_t
*
,
mp4_track_t
*
,
mtime_t
);
...
...
@@ -102,10 +107,15 @@ static void MP4_TrackSetELST( demux_t *, mp4_track_t *, int64_t );
static
void
MP4_UpdateSeekpoint
(
demux_t
*
);
static
const
char
*
MP4_ConvertMacCode
(
uint16_t
);
/* Return time in
s
of a track */
/* Return time in
microsecond
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]
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
mp4_chunk_t
chunk
;
if
(
p_sys
->
b_fragmented
)
chunk
=
*
p_track
->
cchunk
;
else
chunk
=
p_track
->
chunk
[
p_track
->
i_chunk
];
unsigned
int
i_index
=
0
;
unsigned
int
i_sample
=
p_track
->
i_sample
-
chunk
.
i_sample_first
;
...
...
@@ -127,8 +137,6 @@ static inline int64_t MP4_TrackGetDTS( demux_t *p_demux, mp4_track_t *p_track )
}
}
#undef chunk
/* now handle elst */
if
(
p_track
->
p_elst
)
{
...
...
@@ -153,9 +161,15 @@ static inline int64_t MP4_TrackGetDTS( demux_t *p_demux, mp4_track_t *p_track )
return
INT64_C
(
1000000
)
*
i_dts
/
p_track
->
i_timescale
;
}
static
inline
int64_t
MP4_TrackGetPTSDelta
(
mp4_track_t
*
p_track
)
static
inline
int64_t
MP4_TrackGetPTSDelta
(
demux_t
*
p_demux
,
mp4_track_t
*
p_track
)
{
mp4_chunk_t
*
ck
=
&
p_track
->
chunk
[
p_track
->
i_chunk
];
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
mp4_chunk_t
*
ck
;
if
(
p_sys
->
b_fragmented
)
ck
=
p_track
->
cchunk
;
else
ck
=
&
p_track
->
chunk
[
p_track
->
i_chunk
];
unsigned
int
i_index
=
0
;
unsigned
int
i_sample
=
p_track
->
i_sample
-
ck
->
i_sample_first
;
...
...
@@ -179,6 +193,98 @@ static inline int64_t MP4_GetMoviePTS(demux_sys_t *p_sys )
static
void
LoadChapter
(
demux_t
*
p_demux
);
static
int
LoadInitFrag
(
demux_t
*
p_demux
,
const
bool
b_smooth
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
if
(
b_smooth
)
/* Smooth Streaming */
{
if
(
(
p_sys
->
p_root
=
MP4_BoxGetSmooBox
(
p_demux
->
s
)
)
==
NULL
)
{
goto
LoadInitFragError
;
}
else
{
MP4_Box_t
*
p_smoo
=
MP4_BoxGet
(
p_sys
->
p_root
,
"uuid"
);
if
(
!
p_smoo
||
CmpUUID
(
&
p_smoo
->
i_uuid
,
&
SmooBoxUUID
)
)
goto
LoadInitFragError
;
/* Get number of tracks */
p_sys
->
i_tracks
=
0
;
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
MP4_Box_t
*
p_stra
=
MP4_BoxGet
(
p_smoo
,
"uuid[%d]"
,
i
);
if
(
p_stra
&&
p_stra
->
data
.
p_stra
->
i_track_ID
)
p_sys
->
i_tracks
++
;
/* Get timescale and duration of the video track; */
if
(
i
==
0
)
{
p_sys
->
i_timescale
=
p_stra
->
data
.
p_stra
->
i_timescale
;
p_sys
->
i_duration
=
p_stra
->
data
.
p_stra
->
i_duration
;
}
}
}
}
else
{
/* Load all boxes ( except raw data ) */
if
(
(
p_sys
->
p_root
=
MP4_BoxGetRoot
(
p_demux
->
s
)
)
==
NULL
)
{
goto
LoadInitFragError
;
}
}
return
VLC_SUCCESS
;
LoadInitFragError:
msg_Warn
(
p_demux
,
"MP4 plugin discarded (not a valid initialization chunk)"
);
return
VLC_EGENERIC
;
}
static
int
InitTracks
(
demux_t
*
p_demux
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
p_sys
->
track
=
calloc
(
p_sys
->
i_tracks
,
sizeof
(
mp4_track_t
)
);
if
(
p_sys
->
track
==
NULL
)
return
VLC_EGENERIC
;
if
(
p_sys
->
b_fragmented
)
{
mp4_track_t
*
p_track
;
for
(
uint16_t
i
=
0
;
i
<
p_sys
->
i_tracks
;
i
++
)
{
p_track
=
&
p_sys
->
track
[
i
];
p_track
->
cchunk
=
calloc
(
1
,
sizeof
(
mp4_chunk_t
)
);
if
(
unlikely
(
!
p_track
->
cchunk
)
)
{
free
(
p_sys
->
track
);
return
VLC_EGENERIC
;
}
}
}
return
VLC_SUCCESS
;
}
static
void
CreateTracksFromSmooBox
(
demux_t
*
p_demux
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
MP4_Box_t
*
p_smoo
=
MP4_BoxGet
(
p_sys
->
p_root
,
"uuid"
);
mp4_track_t
*
p_track
;
int
j
=
0
;
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
MP4_Box_t
*
p_stra
=
MP4_BoxGet
(
p_smoo
,
"uuid[%d]"
,
i
);
if
(
!
p_stra
||
p_stra
->
data
.
p_stra
->
i_track_ID
==
0
)
continue
;
else
{
p_track
=
&
p_sys
->
track
[
j
];
j
++
;
MP4_frg_TrackCreate
(
p_demux
,
p_track
,
p_stra
);
p_track
->
p_es
=
es_out_Add
(
p_demux
->
out
,
&
p_track
->
fmt
);
}
}
}
/*****************************************************************************
* Open: check file and initializes MP4 structures
*****************************************************************************/
...
...
@@ -211,6 +317,7 @@ static int Open( vlc_object_t * p_this )
case
ATOM_free
:
case
ATOM_skip
:
case
ATOM_wide
:
case
ATOM_uuid
:
case
VLC_FOURCC
(
'p'
,
'n'
,
'o'
,
't'
):
break
;
case
ATOM_ftyp
:
...
...
@@ -223,10 +330,10 @@ static int Open( vlc_object_t * p_this )
}
/* I need to seek */
stream_Control
(
p_demux
->
s
,
STREAM_CAN_
FAST
SEEK
,
&
b_seekable
);
stream_Control
(
p_demux
->
s
,
STREAM_CAN_SEEK
,
&
b_seekable
);
if
(
!
b_seekable
)
{
msg_Warn
(
p_demux
,
"MP4 plugin discarded (not
fast
seekable)"
);
msg_Warn
(
p_demux
,
"MP4 plugin discarded (not seekable)"
);
return
VLC_EGENERIC
;
}
...
...
@@ -237,10 +344,49 @@ static int Open( vlc_object_t * p_this )
/* create our structure that will contains all data */
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
)
/* Is it Smooth Streaming? */
bool
b_smooth
=
false
;
if
(
stream_Peek
(
p_demux
->
s
,
&
p_peek
,
24
)
<
24
)
return
VLC_EGENERIC
;
if
(
!
CmpUUID
(
(
UUID_t
*
)(
p_peek
+
8
),
&
SmooBoxUUID
)
)
{
b_smooth
=
true
;
p_sys
->
b_fragmented
=
true
;
}
if
(
LoadInitFrag
(
p_demux
,
b_smooth
)
!=
VLC_SUCCESS
)
goto
error
;
if
(
MP4_BoxCount
(
p_sys
->
p_root
,
"/moov/mvex"
)
>
0
)
{
p_sys
->
b_fragmented
=
true
;
}
if
(
p_sys
->
b_fragmented
)
{
p_demux
->
pf_demux
=
DemuxFrg
;
}
stream_Control
(
p_demux
->
s
,
STREAM_CAN_FASTSEEK
,
&
b_seekable
);
if
(
b_smooth
)
{
if
(
InitTracks
(
p_demux
)
!=
VLC_SUCCESS
)
goto
error
;
CreateTracksFromSmooBox
(
p_demux
);
return
VLC_SUCCESS
;
}
else
if
(
p_sys
->
b_fragmented
&&
b_seekable
)
{
/* We are not yet able to demux a fragmented MP4 file, using the 'mfra'
* box. So if STREAM_CAN_FASTSEEK is true, we're assuming we've got such
* a file, and we let avformat do the job. */
msg_Warn
(
p_demux
,
"MP4 plugin discarded "
\
"(fast-seekable and fragmented, let avformat demux it)"
);
stream_Seek
(
p_demux
->
s
,
0
);
/* rewind, for other demux */
goto
error
;
}
else
if
(
!
p_sys
->
b_fragmented
&&
!
b_seekable
)
{
msg_Warn
(
p_demux
,
"MP4 plugin discarded (not a valid file)"
);
msg_Warn
(
p_demux
,
"MP4 plugin discarded (not fast-seekable)"
);
stream_Seek
(
p_demux
->
s
,
0
);
/* rewind, for other demux */
goto
error
;
}
...
...
@@ -292,13 +438,8 @@ static int Open( vlc_object_t * p_this )
if
(
!
p_foov
)
{
/* 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
;
}
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
=
ATOM_moov
;
...
...
@@ -415,9 +556,7 @@ static int Open( vlc_object_t * p_this )
p_sys
->
i_tracks
,
p_sys
->
i_tracks
?
's'
:
' '
);
/* allocate memory */
p_sys
->
track
=
calloc
(
p_sys
->
i_tracks
,
sizeof
(
mp4_track_t
)
);
if
(
p_sys
->
track
==
NULL
)
if
(
InitTracks
(
p_demux
)
!=
VLC_SUCCESS
)
goto
error
;
/* Search the first chap reference (like quicktime) and
...
...
@@ -640,7 +779,7 @@ static int Demux( demux_t *p_demux )
/* dts */
p_block
->
i_dts
=
VLC_TS_0
+
MP4_TrackGetDTS
(
p_demux
,
tk
);
/* pts */
i_delta
=
MP4_TrackGetPTSDelta
(
tk
);
i_delta
=
MP4_TrackGetPTSDelta
(
p_demux
,
tk
);
if
(
i_delta
!=
-
1
)
p_block
->
i_pts
=
p_block
->
i_dts
+
i_delta
;
else
if
(
tk
->
fmt
.
i_cat
!=
VIDEO_ES
)
...
...
@@ -706,6 +845,40 @@ static int Seek( demux_t *p_demux, mtime_t i_date )
return
VLC_SUCCESS
;
}
static
int
MP4_frg_Seek
(
demux_t
*
p_demux
,
double
f
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
int64_t
i64
=
stream_Size
(
p_demux
->
s
);
if
(
stream_Seek
(
p_demux
->
s
,
(
int64_t
)(
i64
*
f
)
)
)
{
return
VLC_EGENERIC
;
}
else
{
/* update global time */
p_sys
->
i_time
=
(
uint64_t
)(
f
*
(
double
)
p_sys
->
i_duration
);
p_sys
->
i_pcr
=
MP4_GetMoviePTS
(
p_sys
);
for
(
unsigned
i_track
=
0
;
i_track
<
p_sys
->
i_tracks
;
i_track
++
)
{
mp4_track_t
*
tk
=
&
p_sys
->
track
[
i_track
];
/* We don't want the current chunk to be flushed */
tk
->
cchunk
->
i_sample
=
tk
->
cchunk
->
i_sample_count
;
/* reset/update some values */
tk
->
i_sample
=
tk
->
i_sample_first
=
0
;
tk
->
i_first_dts
=
p_sys
->
i_time
;
/* We want to discard the current chunk and get the next one at once */
tk
->
b_has_non_empty_cchunk
=
false
;
}
es_out_Control
(
p_demux
->
out
,
ES_OUT_SET_NEXT_DISPLAY_TIME
,
p_sys
->
i_pcr
);
return
VLC_SUCCESS
;
}
}
/*****************************************************************************
* Control:
*****************************************************************************/
...
...
@@ -732,7 +905,11 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
case
DEMUX_SET_POSITION
:
f
=
(
double
)
va_arg
(
args
,
double
);
if
(
p_sys
->
i_timescale
>
0
)
if
(
p_sys
->
b_fragmented
)