Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-2-2
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-2-2
Commits
86e8c9d5
Commit
86e8c9d5
authored
Jul 18, 2012
by
Frédéric Yhuel
Committed by
Jean-Baptiste Kempf
Sep 21, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
demux/mp4: Add fragmented MP4 support
Signed-off-by:
Jean-Baptiste Kempf
<
jb@videolan.org
>
parent
2f1fe72f
Changes
3
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1014 additions
and
127 deletions
+1014
-127
modules/demux/mp4/libmp4.c
modules/demux/mp4/libmp4.c
+78
-92
modules/demux/mp4/libmp4.h
modules/demux/mp4/libmp4.h
+5
-9
modules/demux/mp4/mp4.c
modules/demux/mp4/mp4.c
+931
-26
No files found.
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 )
...
@@ -159,15 +159,20 @@ static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box )
if
(
p_box
->
p_father
)
if
(
p_box
->
p_father
)
{
{
const
off_t
i_box_end
=
p_box
->
i_size
+
p_box
->
i_pos
;
/* if father's size == 0, it means unknown or infinite size,
const
off_t
i_father_end
=
p_box
->
p_father
->
i_size
+
p_box
->
p_father
->
i_pos
;
* and we skip the followong check */
if
(
p_box
->
p_father
->
i_size
>
0
)
/* check if it's within p-father */
if
(
i_box_end
>=
i_father_end
)
{
{
if
(
i_box_end
>
i_father_end
)
const
off_t
i_box_end
=
p_box
->
i_size
+
p_box
->
i_pos
;
msg_Dbg
(
p_stream
,
"out of bound child"
);
const
off_t
i_father_end
=
p_box
->
p_father
->
i_size
+
p_box
->
p_father
->
i_pos
;
return
0
;
/* out of bound */
/* 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
)
)
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 )
...
@@ -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
* after called one of theses functions, file position is unknown
* you need to call MP4_GotoBox to go where you want
* 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
;
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
)
)
(
off_t
)(
p_container
->
i_pos
+
p_container
->
i_size
)
)
)
{
{
/* there is no box to load */
/* there is no box to load */
return
0
;
return
0
;
...
@@ -204,14 +214,23 @@ static int MP4_ReadBoxContainerRaw( stream_t *p_stream, MP4_Box_t *p_container )
...
@@ -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
;
else
p_container
->
p_last
->
p_next
=
p_box
;
p_container
->
p_last
=
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
);
}
while
(
MP4_NextBox
(
p_stream
,
p_box
)
==
1
);
return
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
)
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 */
/* container is empty, 8 stand for the first header in this box */
return
1
;
return
1
;
...
@@ -497,22 +516,23 @@ static int MP4_ReadBox_stra( stream_t *p_stream, MP4_Box_t *p_box )
...
@@ -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
->
BitsPerSample
);
MP4_GET4BYTES
(
p_stra
->
PacketSize
);
MP4_GET4BYTES
(
p_stra
->
PacketSize
);
MP4_GET4BYTES
(
p_stra
->
AudioTag
);
MP4_GET4BYTES
(
p_stra
->
AudioTag
);
MP4_GET4BYTES
(
p_stra
->
AvgBytesPerSec
);
MP4_GET2BYTES
(
p_stra
->
nBlockAlign
);
MP4_GET2BYTES
(
p_stra
->
nBlockAlign
);
MP4_GET1BYTE
(
i_reserved
);
MP4_GET1BYTE
(
i_reserved
);
MP4_GET1BYTE
(
i_reserved
);
MP4_GET1BYTE
(
i_reserved
);
MP4_GET1BYTE
(
i_reserved
);
MP4_GET1BYTE
(
i_reserved
);
uint8_t
codec_data_length
;
MP4_GET1BYTE
(
p_stra
->
cpd_len
);
MP4_GET1BYTE
(
codec_data_length
);
if
(
p_stra
->
cpd_len
>
i_read
)
p_stra
->
CodecPrivateData
=
malloc
(
codec_data_length
+
1
);
goto
error
;
p_stra
->
CodecPrivateData
=
malloc
(
p_stra
->
cpd_len
);
if
(
unlikely
(
p_stra
->
CodecPrivateData
==
NULL
)
)
if
(
unlikely
(
p_stra
->
CodecPrivateData
==
NULL
)
)
goto
error
;
goto
error
;
MP4_GETSTRINGZ
(
p_stra
->
CodecPrivateData
);
memcpy
(
p_stra
->
CodecPrivateData
,
p_peek
,
p_stra
->
cpd_len
);
#ifdef MP4_VERBOSE
#ifdef MP4_VERBOSE
msg_Dbg
(
p_stream
,
"es_cat is %"
PRIu8
", birate is %"
PRIu32
", "
\
msg_Dbg
(
p_stream
,
"es_cat is %"
PRIu8
", birate is %"
PRIu32
,
"CodecPrivateData is %s"
,
p_stra
->
i_es_cat
,
p_stra
->
i_es_cat
,
p_stra
->
Bitrate
);
p_stra
->
Bitrate
,
p_stra
->
CodecPrivateData
);
#endif
#endif
MP4_READBOX_EXIT
(
1
);
MP4_READBOX_EXIT
(
1
);
...
@@ -3474,57 +3494,7 @@ error:
...
@@ -3474,57 +3494,7 @@ error:
return
NULL
;
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
#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
)
MP4_Box_t
*
MP4_BoxGetNextChunk
(
stream_t
*
s
)
{
{
/* p_chunk is a virtual root container for the moof and mdat boxes */
/* 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 )
...
@@ -3546,7 +3516,7 @@ MP4_Box_t *MP4_BoxGetNextChunk( stream_t *s )
}
}
else
if
(
p_tmp_box
->
i_type
==
ATOM_ftyp
)
else
if
(
p_tmp_box
->
i_type
==
ATOM_ftyp
)
{
{
return
MP4_BoxGet
InitFrag
(
s
);
return
MP4_BoxGet
Root
(
s
);
}
}
free
(
p_tmp_box
);
free
(
p_tmp_box
);
...
@@ -3620,7 +3590,8 @@ MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
...
@@ -3620,7 +3590,8 @@ MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
p_root
->
i_pos
=
0
;
p_root
->
i_pos
=
0
;
p_root
->
i_type
=
ATOM_root
;
p_root
->
i_type
=
ATOM_root
;
p_root
->
i_shortsize
=
1
;
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
);
CreateUUID
(
&
p_root
->
i_uuid
,
p_root
->
i_type
);
p_root
->
data
.
p_data
=
NULL
;
p_root
->
data
.
p_data
=
NULL
;
...
@@ -3631,37 +3602,52 @@ MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
...
@@ -3631,37 +3602,52 @@ MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
p_stream
=
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
);
i_result
=
MP4_ReadBoxContainerRaw
(
p_stream
,
p_root
);
if
(
i_result
)
if
(
!
i_result
)
{
goto
error
;
MP4_Box_t
*
p_moov
;
MP4_Box_t
*
p_cmov
;
/* check if there is a cmov, if so replace
MP4_Box_t
*
p_moov
;
compressed moov by uncompressed one */
MP4_Box_t
*
p_cmov
;
if
(
(
(
p_moov
=
MP4_BoxGet
(
p_root
,
"moov"
)
)
&&
(
p_cmov
=
MP4_BoxGet
(
p_root
,
"moov/cmov"
)
)
)
||
/* check if there is a cmov, if so replace
(
(
p_moov
=
MP4_BoxGet
(
p_root
,
"foov"
)
)
&&
compressed moov by uncompressed one */
(
p_cmov
=
MP4_BoxGet
(
p_root
,
"foov/cmov"
)
)
)
)
if
(
(
(
p_moov
=
MP4_BoxGet
(
p_root
,
"moov"
)
)
&&
{
(
p_cmov
=
MP4_BoxGet
(
p_root
,
"moov/cmov"
)
)
)
||
/* rename the compressed moov as a box to skip */
(
(
p_moov
=
MP4_BoxGet
(
p_root
,
"foov"
)
)
&&
p_moov
->
i_type
=
ATOM_skip
;
(
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 */
/* get uncompressed p_moov */
p_moov
=
p_cmov
->
data
.
p_cmov
->
p_moov
;
p_moov
=
p_cmov
->
data
.
p_cmov
->
p_moov
;
p_cmov
->
data
.
p_cmov
->
p_moov
=
NULL
;
p_cmov
->
data
.
p_cmov
->
p_moov
=
NULL
;
/* make p_root father of this new moov */
/* make p_root father of this new moov */
p_moov
->
p_father
=
p_root
;
p_moov
->
p_father
=
p_root
;
/* insert this new moov box as first child of p_root */
/* insert this new moov box as first child of p_root */
p_moov
->
p_next
=
p_root
->
p_first
;
p_moov
->
p_next
=
p_root
->
p_first
;
p_root
->
p_first
=
p_moov
;
p_root
->
p_first
=
p_moov
;
}
}
}
return
p_root
;
return
p_root
;
error:
free
(
p_root
);
return
NULL
;
}
}
...
...
modules/demux/mp4/libmp4.h
View file @
86e8c9d5
...
@@ -1140,12 +1140,14 @@ typedef struct
...
@@ -1140,12 +1140,14 @@ typedef struct
uint32_t
MaxWidth
;
uint32_t
MaxWidth
;
uint32_t
MaxHeight
;
uint32_t
MaxHeight
;
uint32_t
SamplingRate
;
uint32_t
SamplingRate
;
uint32_t
AvgBytesPerSec
;
uint32_t
Channels
;
uint32_t
Channels
;
uint32_t
BitsPerSample
;
uint32_t
BitsPerSample
;
uint32_t
PacketSize
;
uint32_t
PacketSize
;
uint32_t
AudioTag
;
uint32_t
AudioTag
;
uint16_t
nBlockAlign
;
uint16_t
nBlockAlign
;
char
*
CodecPrivateData
;
uint8_t
cpd_len
;
uint8_t
*
CodecPrivateData
;
}
MP4_Box_data_stra_t
;
}
MP4_Box_data_stra_t
;
/*
/*
...
@@ -1346,7 +1348,8 @@ typedef struct
...
@@ -1346,7 +1348,8 @@ typedef struct
MP4_Box_t
*
p_sample
;
/* point on actual sdsd */
MP4_Box_t
*
p_sample
;
/* point on actual sdsd */
bool
b_drms
;
bool
b_drms
;
bool
b_end_of_chunk
;
bool
b_has_non_empty_cchunk
;
bool
b_codec_need_restart
;
void
*
p_drms
;
void
*
p_drms
;
MP4_Box_t
*
p_skcr
;
MP4_Box_t
*
p_skcr
;
...
@@ -1477,13 +1480,6 @@ static const UUID_t StraBoxUUID = {
...
@@ -1477,13 +1480,6 @@ static const UUID_t StraBoxUUID = {
0x96
,
0xc7
,
0xbf
,
0x25
,
0xf9
,
0x7e
,
0x24
,
0x47
}
};
0x96
,
0xc7
,
0xbf
,
0x25
,
0xf9
,
0x7e
,
0x24
,
0x47
}
};
MP4_Box_t
*
MP4_BoxGetSmooBox
(
stream_t
*
);
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.
* MP4_BoxGetNextChunk : Parse the entire moof box.
...
...
modules/demux/mp4/mp4.c
View file @
86e8c9d5
This diff is collapsed.
Click to expand it.
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