Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
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
Commits
58eeab0e
Commit
58eeab0e
authored
Mar 07, 2004
by
Laurent Aimar
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
* mp4.c: - accept adding ES at any time
- proper implementation of starting time (edts/elst).
parent
c40cb8b8
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1010 additions
and
968 deletions
+1010
-968
modules/mux/mp4.c
modules/mux/mp4.c
+1010
-968
No files found.
modules/mux/mp4.c
View file @
58eeab0e
...
...
@@ -27,7 +27,6 @@
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
...
...
@@ -37,21 +36,8 @@
#include <time.h>
#endif
#include "codecs.h"
#include "iso_lang.h"
/*****************************************************************************
* Exported prototypes
*****************************************************************************/
static
int
Open
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
static
int
Capability
(
sout_mux_t
*
,
int
,
void
*
,
void
*
);
static
int
AddStream
(
sout_mux_t
*
,
sout_input_t
*
);
static
int
DelStream
(
sout_mux_t
*
,
sout_input_t
*
);
static
int
Mux
(
sout_mux_t
*
);
/*****************************************************************************
* Module descriptor
*****************************************************************************/
...
...
@@ -60,6 +46,8 @@ static int Mux ( sout_mux_t * );
"When this option is turned on, \"Fast start\" files will be created. " \
"(\"Fast start\" files are optimized for download, allowing the user " \
"to start previewing the file while it is downloading).")
static
int
Open
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
vlc_module_begin
();
set_description
(
_
(
"MP4/MOV muxer"
)
);
...
...
@@ -73,6 +61,14 @@ vlc_module_begin();
set_callbacks
(
Open
,
Close
);
vlc_module_end
();
/*****************************************************************************
* Exported prototypes
*****************************************************************************/
static
int
Capability
(
sout_mux_t
*
,
int
,
void
*
,
void
*
);
static
int
AddStream
(
sout_mux_t
*
,
sout_input_t
*
);
static
int
DelStream
(
sout_mux_t
*
,
sout_input_t
*
);
static
int
Mux
(
sout_mux_t
*
);
/*****************************************************************************
* Local prototypes
*****************************************************************************/
...
...
@@ -89,18 +85,18 @@ typedef struct
typedef
struct
{
es_format_t
*
p_
fmt
;
es_format_t
fmt
;
int
i_track_id
;
int64_t
i_length_neg
;
/* index */
unsigned
int
i_entry_count
;
unsigned
int
i_entry_max
;
mp4_entry_t
*
entry
;
int64_t
i_length_neg
;
/* stats */
mtime_t
i_duration
;
int64_t
i_dts_start
;
int64_t
i_duration
;
/* for later stco fix-up (fast start files) */
uint64_t
i_stco_pos
;
...
...
@@ -117,7 +113,7 @@ struct sout_mux_sys_t
uint64_t
i_mdat_pos
;
uint64_t
i_pos
;
mtime_t
i_start_dts
;
int64_t
i_dts_start
;
int
i_nb_streams
;
mp4_stream_t
**
pp_streams
;
...
...
@@ -154,10 +150,10 @@ static void box_gather ( bo_t *box, bo_t *box2 );
static
void
box_send
(
sout_mux_t
*
p_mux
,
bo_t
*
box
);
static
int64_t
get_timestamp
();
static
sout_buffer_t
*
bo_to_sout
(
sout_instance_t
*
p_sout
,
bo_t
*
box
);
static
bo_t
*
GetMoovBox
(
sout_mux_t
*
p_mux
);
/*****************************************************************************
* Open:
*****************************************************************************/
...
...
@@ -173,7 +169,7 @@ static int Open( vlc_object_t *p_this )
p_sys
->
pp_streams
=
NULL
;
p_sys
->
i_mdat_pos
=
0
;
p_sys
->
b_mov
=
p_mux
->
psz_mux
&&
!
strcmp
(
p_mux
->
psz_mux
,
"mov"
);
p_sys
->
i_
start_dts
=
0
;
p_sys
->
i_
dts_start
=
0
;
msg_Dbg
(
p_mux
,
"Open"
);
...
...
@@ -213,142 +209,467 @@ static int Open( vlc_object_t *p_this )
return
VLC_SUCCESS
;
}
static
int
GetDescrLength
(
int
i_size
)
/*****************************************************************************
* Close:
*****************************************************************************/
static
void
Close
(
vlc_object_t
*
p_this
)
{
if
(
i_size
<
0x00000080
)
return
2
+
i_size
;
else
if
(
i_size
<
0x00004000
)
return
3
+
i_size
;
else
if
(
i_size
<
0x00200000
)
return
4
+
i_size
;
else
return
5
+
i_size
;
}
sout_mux_t
*
p_mux
=
(
sout_mux_t
*
)
p_this
;
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
sout_buffer_t
*
p_hdr
;
bo_t
bo
,
*
moov
;
vlc_value_t
val
;
static
bo_t
*
GetESDS
(
mp4_stream_t
*
p_stream
)
{
bo_t
*
esds
;
int
i_stream_type
;
int
i_object_type_indication
;
int
i_decoder_specific_info_size
;
int
i_trak
;
uint64_t
i_moov_pos
;
msg_Dbg
(
p_mux
,
"Close"
);
if
(
p_stream
->
p_fmt
->
i_extra
>
0
)
/* Update mdat size */
bo_init
(
&
bo
,
0
,
NULL
,
VLC_TRUE
);
if
(
p_sys
->
i_pos
-
p_sys
->
i_mdat_pos
>=
(((
uint64_t
)
1
)
<<
32
)
)
{
i_decoder_specific_info_size
=
GetDescrLength
(
p_stream
->
p_fmt
->
i_extra
);
/* Extended size */
bo_add_32be
(
&
bo
,
1
);
bo_add_fourcc
(
&
bo
,
"mdat"
);
bo_add_64be
(
&
bo
,
p_sys
->
i_pos
-
p_sys
->
i_mdat_pos
);
}
else
{
i_decoder_specific_info_size
=
0
;
bo_add_32be
(
&
bo
,
8
);
bo_add_fourcc
(
&
bo
,
"wide"
);
bo_add_32be
(
&
bo
,
p_sys
->
i_pos
-
p_sys
->
i_mdat_pos
-
8
);
bo_add_fourcc
(
&
bo
,
"mdat"
);
}
p_hdr
=
bo_to_sout
(
p_mux
->
p_sout
,
&
bo
);
free
(
bo
.
p_buffer
);
esds
=
box_full_new
(
"esds"
,
0
,
0
);
sout_AccessOutSeek
(
p_mux
->
p_access
,
p_sys
->
i_mdat_pos
);
sout_AccessOutWrite
(
p_mux
->
p_access
,
p_hdr
);
/* ES_Descr */
bo_add_descr
(
esds
,
0x03
,
3
+
GetDescrLength
(
13
+
i_decoder_specific_info_size
)
+
GetDescrLength
(
1
)
);
bo_add_16be
(
esds
,
p_stream
->
i_track_id
);
bo_add_8
(
esds
,
0x1f
);
// flags=0|streamPriority=0x1f
/* Create MOOV header */
i_moov_pos
=
p_sys
->
i_pos
;
moov
=
GetMoovBox
(
p_mux
);
/* DecoderConfigDescr */
bo_add_descr
(
esds
,
0x04
,
13
+
i_decoder_specific_info_size
);
/* Check we need to create "fast start" files */
var_Create
(
p_this
,
"mp4-faststart"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
var_Get
(
p_this
,
"mp4-faststart"
,
&
val
);
p_sys
->
b_fast_start
=
val
.
b_bool
;
while
(
p_sys
->
b_fast_start
)
{
/* Move data to the end of the file so we can fit the moov header
* at the start */
sout_buffer_t
*
p_buf
;
int64_t
i_chunk
,
i_size
=
p_sys
->
i_pos
-
p_sys
->
i_mdat_pos
;
int
i_moov_size
=
moov
->
i_buffer
;
switch
(
p_stream
->
p_fmt
->
i_codec
)
while
(
i_size
>
0
)
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
):
i_object_type_indication
=
0x20
;
break
;
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
):
/* FIXME MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
i_object_type_indication
=
0x60
;
break
;
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
):
/* FIXME for mpeg2-aac == 0x66->0x68 */
i_object_type_indication
=
0x40
;
break
;
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
):
i_object_type_indication
=
p_stream
->
p_fmt
->
audio
.
i_rate
<
32000
?
0x69
:
0x6b
;
break
;
default:
i_object_type_indication
=
0x00
;
i_chunk
=
__MIN
(
32768
,
i_size
);
p_buf
=
sout_BufferNew
(
p_mux
->
p_sout
,
i_chunk
);
sout_AccessOutSeek
(
p_mux
->
p_access
,
p_sys
->
i_mdat_pos
+
i_size
-
i_chunk
);
if
(
sout_AccessOutRead
(
p_mux
->
p_access
,
p_buf
)
<
i_chunk
)
{
msg_Warn
(
p_this
,
"read() not supported by acces output, "
"won't create a fast start file"
);
p_sys
->
b_fast_start
=
VLC_FALSE
;
break
;
}
i_stream_type
=
p_stream
->
p_fmt
->
i_cat
==
VIDEO_ES
?
0x04
:
0x05
;
sout_AccessOutSeek
(
p_mux
->
p_access
,
p_sys
->
i_mdat_pos
+
i_size
+
i_moov_size
-
i_chunk
);
sout_AccessOutWrite
(
p_mux
->
p_access
,
p_buf
);
i_size
-=
i_chunk
;
}
bo_add_8
(
esds
,
i_object_type_indication
);
bo_add_8
(
esds
,
(
i_stream_type
<<
2
)
|
1
);
bo_add_24be
(
esds
,
1024
*
1024
);
// bufferSizeDB
bo_add_32be
(
esds
,
0x7fffffff
);
// maxBitrate
bo_add_32be
(
esds
,
0
);
// avgBitrate
if
(
!
p_sys
->
b_fast_start
)
break
;
if
(
p_stream
->
p_fmt
->
i_extra
>
0
)
/* Fix-up samples to chunks table in MOOV header */
for
(
i_trak
=
0
;
i_trak
<
p_sys
->
i_nb_streams
;
i_trak
++
)
{
int
i
;
mp4_stream_t
*
p_stream
=
p_sys
->
pp_streams
[
i_trak
];
unsigned
int
i
;
int
i_chunk
;
/* DecoderSpecificInfo */
bo_add_descr
(
esds
,
0x05
,
p_stream
->
p_fmt
->
i_extra
);
moov
->
i_buffer
=
p_stream
->
i_stco_pos
;
for
(
i_chunk
=
0
,
i
=
0
;
i
<
p_stream
->
i_entry_count
;
i_chunk
++
)
{
if
(
p_stream
->
b_stco64
)
bo_add_64be
(
moov
,
p_stream
->
entry
[
i
].
i_pos
+
i_moov_size
);
else
bo_add_32be
(
moov
,
p_stream
->
entry
[
i
].
i_pos
+
i_moov_size
);
for
(
i
=
0
;
i
<
p_stream
->
p_fmt
->
i_extra
;
i
++
)
while
(
i
<
p_stream
->
i_entry_count
)
{
if
(
i
+
1
<
p_stream
->
i_entry_count
&&
p_stream
->
entry
[
i
].
i_pos
+
p_stream
->
entry
[
i
].
i_size
!=
p_stream
->
entry
[
i
+
1
].
i_pos
)
{
bo_add_8
(
esds
,
((
uint8_t
*
)
p_stream
->
p_fmt
->
p_extra
)[
i
]
);
i
++
;
break
;
}
i
++
;
}
}
}
/* SL_Descr mandatory */
bo_add_descr
(
esds
,
0x06
,
1
);
bo_add_8
(
esds
,
0x02
);
// sl_predefined
moov
->
i_buffer
=
i_moov_size
;
i_moov_pos
=
p_sys
->
i_mdat_pos
;
p_sys
->
b_fast_start
=
VLC_FALSE
;
}
box_fix
(
esds
);
/* Write MOOV header */
sout_AccessOutSeek
(
p_mux
->
p_access
,
i_moov_pos
);
box_send
(
p_mux
,
moov
);
return
esds
;
/* Clean-up */
for
(
i_trak
=
0
;
i_trak
<
p_sys
->
i_nb_streams
;
i_trak
++
)
{
mp4_stream_t
*
p_stream
=
p_sys
->
pp_streams
[
i_trak
];
es_format_Clean
(
&
p_stream
->
fmt
);
free
(
p_stream
->
entry
);
free
(
p_stream
);
}
if
(
p_sys
->
i_nb_streams
)
free
(
p_sys
->
pp_streams
);
free
(
p_sys
);
}
static
bo_t
*
GetWaveTag
(
mp4_stream_t
*
p_stream
)
/*****************************************************************************
* Capability:
*****************************************************************************/
static
int
Capability
(
sout_mux_t
*
p_mux
,
int
i_query
,
void
*
p_args
,
void
*
p_answer
)
{
bo_t
*
wave
;
bo_t
*
box
;
switch
(
i_query
)
{
case
SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME
:
*
(
vlc_bool_t
*
)
p_answer
=
VLC_TRUE
;
return
SOUT_MUX_CAP_ERR_OK
;
wave
=
box_new
(
"wave"
);
case
SOUT_MUX_CAP_GET_ADD_STREAM_WAIT
:
*
(
vlc_bool_t
*
)
p_answer
=
VLC_TRUE
;
return
(
SOUT_MUX_CAP_ERR_OK
);
box
=
box_new
(
"frma"
);
bo_add_fourcc
(
box
,
"mp4a"
)
;
box_fix
(
box
);
box_gather
(
wave
,
box
);
default:
return
SOUT_MUX_CAP_ERR_UNIMPLEMENTED
;
}
}
box
=
box_new
(
"mp4a"
);
bo_add_32be
(
box
,
0
);
box_fix
(
box
);
box_gather
(
wave
,
box
);
/*****************************************************************************
* AddStream:
*****************************************************************************/
static
int
AddStream
(
sout_mux_t
*
p_mux
,
sout_input_t
*
p_input
)
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
mp4_stream_t
*
p_stream
;
box
=
GetESDS
(
p_stream
);
box_fix
(
box
);
box_gather
(
wave
,
box
);
switch
(
p_input
->
p_fmt
->
i_codec
)
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
):
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
):
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
):
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
):
case
VLC_FOURCC
(
'M'
,
'J'
,
'P'
,
'G'
):
case
VLC_FOURCC
(
'm'
,
'j'
,
'p'
,
'b'
):
case
VLC_FOURCC
(
'S'
,
'V'
,
'Q'
,
'3'
):
break
;
default:
msg_Err
(
p_mux
,
"unsupported codec %4.4s in mp4"
,
(
char
*
)
&
p_input
->
p_fmt
->
i_codec
);
return
VLC_EGENERIC
;
}
box
=
box_new
(
"srcq"
);
bo_add_32be
(
box
,
0x40
);
box_fix
(
box
);
box_gather
(
wave
,
box
);
p_stream
=
malloc
(
sizeof
(
mp4_stream_t
)
);
es_format_Copy
(
&
p_stream
->
fmt
,
p_input
->
p_fmt
);
p_stream
->
i_track_id
=
p_sys
->
i_nb_streams
+
1
;
p_stream
->
i_length_neg
=
0
;
p_stream
->
i_entry_count
=
0
;
p_stream
->
i_entry_max
=
1000
;
p_stream
->
entry
=
calloc
(
p_stream
->
i_entry_max
,
sizeof
(
mp4_entry_t
)
);
p_stream
->
i_dts_start
=
0
;
p_stream
->
i_duration
=
0
;
/* wazza ? */
bo_add_32be
(
wave
,
8
);
/* new empty box */
bo_add_32be
(
wave
,
0
);
/* box label */
p_input
->
p_sys
=
p_stream
;
box_fix
(
wave
);
msg_Dbg
(
p_mux
,
"adding input"
);
return
wave
;
TAB_APPEND
(
p_sys
->
i_nb_streams
,
p_sys
->
pp_streams
,
p_stream
);
return
VLC_SUCCESS
;
}
/* TODO: No idea about these values */
static
bo_t
*
GetSVQ3Tag
(
mp4_stream_t
*
p_stream
)
/*****************************************************************************
* DelStream:
*****************************************************************************/
static
int
DelStream
(
sout_mux_t
*
p_mux
,
sout_input_t
*
p_input
)
{
bo_t
*
smi
=
box_new
(
"SMI "
);
if
(
p_stream
->
p_fmt
->
i_extra
>
0x4e
)
msg_Dbg
(
p_mux
,
"removing input"
);
return
VLC_SUCCESS
;
}
static
int
MuxGetStream
(
sout_mux_t
*
p_mux
,
int
*
pi_stream
,
mtime_t
*
pi_dts
)
{
mtime_t
i_dts
;
int
i_stream
;
int
i
;
for
(
i
=
0
,
i_dts
=
0
,
i_stream
=
-
1
;
i
<
p_mux
->
i_nb_inputs
;
i
++
)
{
sout_fifo_t
*
p_fifo
=
p_mux
->
pp_inputs
[
i
]
->
p_fifo
;
sout_buffer_t
*
p_buf
;
if
(
p_fifo
->
i_depth
<=
1
)
{
return
-
1
;
// wait that all fifo have at least 2 packets
}
p_buf
=
sout_FifoShow
(
p_fifo
);
if
(
i_stream
<
0
||
p_buf
->
i_dts
<
i_dts
)
{
i_dts
=
p_buf
->
i_dts
;
i_stream
=
i
;
}
}
if
(
pi_stream
)
{
*
pi_stream
=
i_stream
;
}
if
(
pi_dts
)
{
*
pi_dts
=
i_dts
;
}
return
i_stream
;
}
/*****************************************************************************
* Mux:
*****************************************************************************/
static
int
Mux
(
sout_mux_t
*
p_mux
)
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
for
(
;;
)
{
sout_input_t
*
p_input
;
int
i_stream
;
mp4_stream_t
*
p_stream
;
sout_buffer_t
*
p_data
;
mtime_t
i_dts
;
if
(
MuxGetStream
(
p_mux
,
&
i_stream
,
&
i_dts
)
<
0
)
{
return
(
VLC_SUCCESS
);
}
p_input
=
p_mux
->
pp_inputs
[
i_stream
];
p_stream
=
(
mp4_stream_t
*
)
p_input
->
p_sys
;
p_data
=
sout_FifoGet
(
p_input
->
p_fifo
);
if
(
p_input
->
p_fifo
->
i_depth
>
0
)
{
sout_buffer_t
*
p_next
=
sout_FifoShow
(
p_input
->
p_fifo
);
int64_t
i_diff
=
p_next
->
i_dts
-
p_data
->
i_dts
;
if
(
i_diff
<
I64C
(
1000000
)
)
/* protection */
{
p_data
->
i_length
=
i_diff
;
}
}
if
(
p_data
->
i_length
<=
0
)
{
msg_Warn
(
p_mux
,
"i_length <= 0"
);
p_stream
->
i_length_neg
+=
p_data
->
i_length
-
1
;
p_data
->
i_length
=
1
;
}
else
if
(
p_stream
->
i_length_neg
<
0
)
{
int64_t
i_recover
=
__MIN
(
p_data
->
i_length
/
4
,
-
p_stream
->
i_length_neg
);
p_data
->
i_length
-=
i_recover
;
p_stream
->
i_length_neg
+=
i_recover
;
}
/* Save starting time */
if
(
p_stream
->
i_entry_count
==
0
)
{
p_stream
->
i_dts_start
=
p_data
->
i_dts
;
/* Update global dts_start */
if
(
p_sys
->
i_dts_start
<=
0
||
p_stream
->
i_dts_start
<
p_sys
->
i_dts_start
)
{
p_sys
->
i_dts_start
=
p_stream
->
i_dts_start
;
}
}
/* add index entry */
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_pos
=
p_sys
->
i_pos
;
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_size
=
p_data
->
i_size
;
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_pts_dts
=
__MAX
(
p_data
->
i_pts
-
p_data
->
i_dts
,
0
);
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_length
=
p_data
->
i_length
;
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_flags
=
p_data
->
i_flags
;
p_stream
->
i_entry_count
++
;
if
(
p_stream
->
i_entry_count
>=
p_stream
->
i_entry_max
)
{
p_stream
->
i_entry_max
+=
1000
;
p_stream
->
entry
=
realloc
(
p_stream
->
entry
,
p_stream
->
i_entry_max
*
sizeof
(
mp4_entry_t
)
);
}
/* update */
p_stream
->
i_duration
+=
p_data
->
i_length
;
p_sys
->
i_pos
+=
p_data
->
i_size
;
/* write data */
sout_AccessOutWrite
(
p_mux
->
p_access
,
p_data
);
}
return
(
VLC_SUCCESS
);
}
/*****************************************************************************
*
*****************************************************************************/
static
int
GetDescrLength
(
int
i_size
)
{
if
(
i_size
<
0x00000080
)
return
2
+
i_size
;
else
if
(
i_size
<
0x00004000
)
return
3
+
i_size
;
else
if
(
i_size
<
0x00200000
)
return
4
+
i_size
;
else
return
5
+
i_size
;
}
static
bo_t
*
GetESDS
(
mp4_stream_t
*
p_stream
)
{
bo_t
*
esds
;
int
i_stream_type
;
int
i_object_type_indication
;
int
i_decoder_specific_info_size
;
if
(
p_stream
->
fmt
.
i_extra
>
0
)
{
i_decoder_specific_info_size
=
GetDescrLength
(
p_stream
->
fmt
.
i_extra
);
}
else
{
i_decoder_specific_info_size
=
0
;
}
esds
=
box_full_new
(
"esds"
,
0
,
0
);
/* ES_Descr */
bo_add_descr
(
esds
,
0x03
,
3
+
GetDescrLength
(
13
+
i_decoder_specific_info_size
)
+
GetDescrLength
(
1
)
);
bo_add_16be
(
esds
,
p_stream
->
i_track_id
);
bo_add_8
(
esds
,
0x1f
);
// flags=0|streamPriority=0x1f
/* DecoderConfigDescr */
bo_add_descr
(
esds
,
0x04
,
13
+
i_decoder_specific_info_size
);
switch
(
p_stream
->
fmt
.
i_codec
)
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
):
i_object_type_indication
=
0x20
;
break
;
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
):
/* FIXME MPEG-I=0x6b, MPEG-II = 0x60 -> 0x65 */
i_object_type_indication
=
0x60
;
break
;
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
):
/* FIXME for mpeg2-aac == 0x66->0x68 */
i_object_type_indication
=
0x40
;
break
;
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
):
i_object_type_indication
=
p_stream
->
fmt
.
audio
.
i_rate
<
32000
?
0x69
:
0x6b
;
break
;
default:
i_object_type_indication
=
0x00
;
break
;
}
i_stream_type
=
p_stream
->
fmt
.
i_cat
==
VIDEO_ES
?
0x04
:
0x05
;
bo_add_8
(
esds
,
i_object_type_indication
);
bo_add_8
(
esds
,
(
i_stream_type
<<
2
)
|
1
);
bo_add_24be
(
esds
,
1024
*
1024
);
// bufferSizeDB
bo_add_32be
(
esds
,
0x7fffffff
);
// maxBitrate
bo_add_32be
(
esds
,
0
);
// avgBitrate
if
(
p_stream
->
fmt
.
i_extra
>
0
)
{
int
i
;
/* DecoderSpecificInfo */
bo_add_descr
(
esds
,
0x05
,
p_stream
->
fmt
.
i_extra
);
for
(
i
=
0
;
i
<
p_stream
->
fmt
.
i_extra
;
i
++
)
{
bo_add_8
(
esds
,
((
uint8_t
*
)
p_stream
->
fmt
.
p_extra
)[
i
]
);
}
}
/* SL_Descr mandatory */
bo_add_descr
(
esds
,
0x06
,
1
);
bo_add_8
(
esds
,
0x02
);
// sl_predefined
box_fix
(
esds
);
return
esds
;
}
static
bo_t
*
GetWaveTag
(
mp4_stream_t
*
p_stream
)
{
bo_t
*
wave
;
bo_t
*
box
;
wave
=
box_new
(
"wave"
);
box
=
box_new
(
"frma"
);
bo_add_fourcc
(
box
,
"mp4a"
);
box_fix
(
box
);
box_gather
(
wave
,
box
);
box
=
box_new
(
"mp4a"
);
bo_add_32be
(
box
,
0
);
box_fix
(
box
);
box_gather
(
wave
,
box
);
box
=
GetESDS
(
p_stream
);
box_fix
(
box
);
box_gather
(
wave
,
box
);
box
=
box_new
(
"srcq"
);
bo_add_32be
(
box
,
0x40
);
box_fix
(
box
);
box_gather
(
wave
,
box
);
/* wazza ? */
bo_add_32be
(
wave
,
8
);
/* new empty box */
bo_add_32be
(
wave
,
0
);
/* box label */
box_fix
(
wave
);
return
wave
;
}
/* TODO: No idea about these values */
static
bo_t
*
GetSVQ3Tag
(
mp4_stream_t
*
p_stream
)
{
bo_t
*
smi
=
box_new
(
"SMI "
);
if
(
p_stream
->
fmt
.
i_extra
>
0x4e
)
{
uint8_t
*
p_end
=
&
((
uint8_t
*
)
p_stream
->
p_fmt
->
p_extra
)[
p_stream
->
p_fmt
->
i_extra
];
uint8_t
*
p
=
&
((
uint8_t
*
)
p_stream
->
p_fmt
->
p_extra
)[
0x46
];
uint8_t
*
p_end
=
&
((
uint8_t
*
)
p_stream
->
fmt
.
p_extra
)[
p_stream
->
fmt
.
i_extra
];
uint8_t
*
p
=
&
((
uint8_t
*
)
p_stream
->
fmt
.
p_extra
)[
0x46
];
while
(
p
+
8
<
p_end
)
{
...
...
@@ -388,8 +709,8 @@ static bo_t *GetUdtaTag( sout_mux_t *p_mux )
{
mp4_stream_t
*
p_stream
=
p_sys
->
pp_streams
[
i_track
];
if
(
p_stream
->
p_fmt
->
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
)
||
p_stream
->
p_fmt
->
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
if
(
p_stream
->
fmt
.
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
)
||
p_stream
->
fmt
.
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
{
bo_t
*
box
=
box_new
(
"
\251
req"
);
/* String length */
...
...
@@ -427,7 +748,7 @@ static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
char
fcc
[
4
]
=
" "
;
int
i
;
switch
(
p_stream
->
p_fmt
->
i_codec
)
switch
(
p_stream
->
fmt
.
i_codec
)
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
):
memcpy
(
fcc
,
"mp4a"
,
4
);
...
...
@@ -445,7 +766,7 @@ static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
break
;
default:
memcpy
(
fcc
,
(
char
*
)
&
p_stream
->
p_fmt
->
i_codec
,
4
);
memcpy
(
fcc
,
(
char
*
)
&
p_stream
->
fmt
.
i_codec
,
4
);
break
;
}
...
...
@@ -458,7 +779,7 @@ static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
/* SoundDescription */
if
(
p_sys
->
b_mov
&&
p_stream
->
p_fmt
->
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
p_stream
->
fmt
.
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
{
bo_add_16be
(
soun
,
1
);
// version 1;
}
...
...
@@ -469,25 +790,25 @@ static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
bo_add_16be
(
soun
,
0
);
// revision level (0)
bo_add_32be
(
soun
,
0
);
// vendor
// channel-count
bo_add_16be
(
soun
,
p_stream
->
p_fmt
->
audio
.
i_channels
);
bo_add_16be
(
soun
,
p_stream
->
fmt
.
audio
.
i_channels
);
// sample size
bo_add_16be
(
soun
,
p_stream
->
p_fmt
->
audio
.
i_bitspersample
?
p_stream
->
p_fmt
->
audio
.
i_bitspersample
:
16
);
bo_add_16be
(
soun
,
p_stream
->
fmt
.
audio
.
i_bitspersample
?
p_stream
->
fmt
.
audio
.
i_bitspersample
:
16
);
bo_add_16be
(
soun
,
-
2
);
// compression id
bo_add_16be
(
soun
,
0
);
// packet size (0)
bo_add_16be
(
soun
,
p_stream
->
p_fmt
->
audio
.
i_rate
);
// sampleratehi
bo_add_16be
(
soun
,
p_stream
->
fmt
.
audio
.
i_rate
);
// sampleratehi
bo_add_16be
(
soun
,
0
);
// sampleratelo
/* Extended data for SoundDescription V1 */
if
(
p_sys
->
b_mov
&&
p_stream
->
p_fmt
->
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
p_stream
->
fmt
.
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
{
/* samples per packet */
bo_add_32be
(
soun
,
p_stream
->
p_fmt
->
audio
.
i_frame_length
);
bo_add_32be
(
soun
,
p_stream
->
fmt
.
audio
.
i_frame_length
);
bo_add_32be
(
soun
,
1536
);
/* bytes per packet */
bo_add_32be
(
soun
,
2
);
/* bytes per frame */
/* bytes per sample */
bo_add_32be
(
soun
,
2
/*p_stream->
p_fmt->
audio.i_bitspersample/8 */
);
bo_add_32be
(
soun
,
2
/*p_stream->
fmt.
audio.i_bitspersample/8 */
);
}
/* Add an ES Descriptor */
...
...
@@ -496,7 +817,7 @@ static bo_t *GetSounBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
bo_t
*
box
;
if
(
p_sys
->
b_mov
&&
p_stream
->
p_fmt
->
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
p_stream
->
fmt
.
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
{
box
=
GetWaveTag
(
p_stream
);
}
...
...
@@ -520,7 +841,7 @@ static bo_t *GetVideBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
char
fcc
[
4
]
=
" "
;
int
i
;
switch
(
p_stream
->
p_fmt
->
i_codec
)
switch
(
p_stream
->
fmt
.
i_codec
)
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
):
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
):
...
...
@@ -536,7 +857,7 @@ static bo_t *GetVideBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
break
;
default:
memcpy
(
fcc
,
(
char
*
)
&
p_stream
->
p_fmt
->
i_codec
,
4
);
memcpy
(
fcc
,
(
char
*
)
&
p_stream
->
fmt
.
i_codec
,
4
);
break
;
}
...
...
@@ -554,8 +875,8 @@ static bo_t *GetVideBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
bo_add_32be
(
vide
,
0
);
// predefined;
}
bo_add_16be
(
vide
,
p_stream
->
p_fmt
->
video
.
i_width
);
// i_width
bo_add_16be
(
vide
,
p_stream
->
p_fmt
->
video
.
i_height
);
// i_height
bo_add_16be
(
vide
,
p_stream
->
fmt
.
video
.
i_width
);
// i_width
bo_add_16be
(
vide
,
p_stream
->
fmt
.
video
.
i_height
);
// i_height
bo_add_32be
(
vide
,
0x00480000
);
// h 72dpi
bo_add_32be
(
vide
,
0x00480000
);
// v 72dpi
...
...
@@ -573,7 +894,7 @@ static bo_t *GetVideBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
bo_add_16be
(
vide
,
0xffff
);
// predefined
/* add an ES Descriptor */
switch
(
p_stream
->
p_fmt
->
i_codec
)
switch
(
p_stream
->
fmt
.
i_codec
)
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
):
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
):
...
...
@@ -616,12 +937,12 @@ static bo_t *GetStblBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
/* sample description */
stsd
=
box_full_new
(
"stsd"
,
0
,
0
);
bo_add_32be
(
stsd
,
1
);
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
{
bo_t
*
soun
=
GetSounBox
(
p_mux
,
p_stream
);
box_gather
(
stsd
,
soun
);
}
else
if
(
p_stream
->
p_fmt
->
i_cat
==
VIDEO_ES
)
else
if
(
p_stream
->
fmt
.
i_cat
==
VIDEO_ES
)
{
bo_t
*
vide
=
GetVideBox
(
p_mux
,
p_stream
);
box_gather
(
stsd
,
vide
);
...
...
@@ -694,8 +1015,8 @@ static bo_t *GetStblBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
stts
=
box_full_new
(
"stts"
,
0
,
0
);
bo_add_32be
(
stts
,
0
);
// entry-count (fixed latter)
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
i_timescale
=
p_stream
->
p_fmt
->
audio
.
i_rate
;
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
i_timescale
=
p_stream
->
fmt
.
audio
.
i_rate
;
else
i_timescale
=
1001
;
...
...
@@ -783,6 +1104,8 @@ static bo_t *GetStblBox( sout_mux_t *p_mux, mp4_stream_t *p_stream )
return
stbl
;
}
static
int64_t
get_timestamp
();
static
uint32_t
mvhd_matrix
[
9
]
=
{
0x10000
,
0
,
0
,
0
,
0x10000
,
0
,
0
,
0
,
0x40000000
};
...
...
@@ -853,20 +1176,20 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
mp4_stream_t
*
p_stream
;
uint32_t
i_timescale
;
bo_t
*
trak
,
*
tkhd
,
*
mdia
,
*
mdhd
,
*
hdlr
;
bo_t
*
trak
,
*
tkhd
,
*
edts
,
*
elst
,
*
mdia
,
*
mdhd
,
*
hdlr
;
bo_t
*
minf
,
*
dinf
,
*
dref
,
*
url
,
*
stbl
;
p_stream
=
p_sys
->
pp_streams
[
i_trak
];
if
(
p_stream
->
p_fmt
->
i_cat
!=
AUDIO_ES
&&
p_stream
->
p_fmt
->
i_cat
!=
VIDEO_ES
)
if
(
p_stream
->
fmt
.
i_cat
!=
AUDIO_ES
&&
p_stream
->
fmt
.
i_cat
!=
VIDEO_ES
)
{
msg_Err
(
p_mux
,
"FIXME ignoring trak (noaudio&&novideo)"
);
continue
;
}
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
i_timescale
=
p_stream
->
p_fmt
->
audio
.
i_rate
;
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
i_timescale
=
p_stream
->
fmt
.
audio
.
i_rate
;
else
i_timescale
=
1001
;
...
...
@@ -912,13 +1235,13 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
bo_add_16be
(
tkhd
,
0
);
// layer
bo_add_16be
(
tkhd
,
0
);
// pre-defined
// volume
bo_add_16be
(
tkhd
,
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
?
0x100
:
0
);
bo_add_16be
(
tkhd
,
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
?
0x100
:
0
);
bo_add_16be
(
tkhd
,
0
);
// reserved
for
(
i
=
0
;
i
<
9
;
i
++
)
{
bo_add_32be
(
tkhd
,
mvhd_matrix
[
i
]
);
// matrix
}
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
{
bo_add_32be
(
tkhd
,
0
);
// width (presentation)
bo_add_32be
(
tkhd
,
0
);
// height(presentation)
...
...
@@ -926,41 +1249,83 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
else
{
// width (presentation)
bo_add_32be
(
tkhd
,
p_stream
->
p_fmt
->
video
.
i_aspect
*
p_stream
->
p_fmt
->
video
.
i_height
/
bo_add_32be
(
tkhd
,
p_stream
->
fmt
.
video
.
i_aspect
*
p_stream
->
fmt
.
video
.
i_height
/
VOUT_ASPECT_FACTOR
<<
16
);
// height(presentation)
bo_add_32be
(
tkhd
,
p_stream
->
p_fmt
->
video
.
i_height
<<
16
);
bo_add_32be
(
tkhd
,
p_stream
->
fmt
.
video
.
i_height
<<
16
);
}
box_fix
(
tkhd
);
box_gather
(
trak
,
tkhd
);
/* *** add /moov/trak/mdia *** */
mdia
=
box_new
(
"mdia"
);
/* *** add /moov/trak/edts and elst */
edts
=
box_new
(
"edts"
);
elst
=
box_full_new
(
"elst"
,
p_sys
->
b_64_ext
?
1
:
0
,
0
);
if
(
p_stream
->
i_dts_start
>
p_sys
->
i_dts_start
)
{
bo_add_32be
(
elst
,
2
);
/* media header */
if
(
!
p_sys
->
b_64_ext
)
if
(
p_sys
->
b_64_ext
)
{
mdhd
=
box_full_new
(
"mdhd"
,
0
,
0
);
bo_add_32be
(
mdhd
,
get_timestamp
()
);
// creation time
bo_add_32be
(
mdhd
,
get_timestamp
()
);
// modification time
bo_add_32be
(
mdhd
,
i_timescale
);
// timescale
bo_add_32be
(
mdhd
,
p_stream
->
i_duration
*
(
int64_t
)
i_timescale
/
(
mtime_t
)
1000000
);
// duration
bo_add_64be
(
elst
,
(
p_stream
->
i_dts_start
-
p_sys
->
i_dts_start
)
*
i_movie_timescale
/
I64C
(
1000000
)
);
bo_add_64be
(
elst
,
-
1
);
}
else
{
mdhd
=
box_full_new
(
"mdhd"
,
1
,
0
);
bo_add_64be
(
mdhd
,
get_timestamp
()
);
// creation time
bo_add_32be
(
elst
,
(
p_stream
->
i_dts_start
-
p_sys
->
i_dts_start
)
*
i_movie_timescale
/
I64C
(
1000000
)
);
bo_add_32be
(
elst
,
-
1
);
}
bo_add_16be
(
elst
,
1
);
bo_add_16be
(
elst
,
0
);
}
else
{
bo_add_32be
(
elst
,
1
);
}
if
(
p_sys
->
b_64_ext
)
{
bo_add_64be
(
elst
,
p_stream
->
i_duration
*
i_movie_timescale
/
I64C
(
1000000
)
);
bo_add_64be
(
elst
,
0
);
}
else
{
bo_add_32be
(
elst
,
p_stream
->
i_duration
*
i_movie_timescale
/
I64C
(
1000000
)
);
bo_add_32be
(
elst
,
0
);
}
bo_add_16be
(
elst
,
1
);
bo_add_16be
(
elst
,
0
);
box_fix
(
elst
);
box_gather
(
edts
,
elst
);
box_fix
(
edts
);
box_gather
(
trak
,
edts
);
/* *** add /moov/trak/mdia *** */
mdia
=
box_new
(
"mdia"
);
/* media header */
if
(
!
p_sys
->
b_64_ext
)
{
mdhd
=
box_full_new
(
"mdhd"
,
0
,
0
);
bo_add_32be
(
mdhd
,
get_timestamp
()
);
// creation time
bo_add_32be
(
mdhd
,
get_timestamp
()
);
// modification time
bo_add_32be
(
mdhd
,
i_timescale
);
// timescale
bo_add_32be
(
mdhd
,
p_stream
->
i_duration
*
(
int64_t
)
i_timescale
/
(
mtime_t
)
1000000
);
// duration
}
else
{
mdhd
=
box_full_new
(
"mdhd"
,
1
,
0
);
bo_add_64be
(
mdhd
,
get_timestamp
()
);
// creation time
bo_add_64be
(
mdhd
,
get_timestamp
()
);
// modification time
bo_add_32be
(
mdhd
,
i_timescale
);
// timescale
bo_add_64be
(
mdhd
,
p_stream
->
i_duration
*
(
int64_t
)
i_timescale
/
(
mtime_t
)
1000000
);
// duration
}
if
(
p_stream
->
p_fmt
->
psz_language
)
if
(
p_stream
->
fmt
.
psz_language
)
{
char
*
psz
=
p_stream
->
p_fmt
->
psz_language
;
char
*
psz
=
p_stream
->
fmt
.
psz_language
;
const
iso639_lang_t
*
pl
=
NULL
;
uint16_t
lang
=
0x0
;
...
...
@@ -996,7 +1361,7 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
hdlr
=
box_full_new
(
"hdlr"
,
0
,
0
);
bo_add_fourcc
(
hdlr
,
"mhlr"
);
// media handler
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
{
bo_add_fourcc
(
hdlr
,
"soun"
);
}
...
...
@@ -1010,7 +1375,7 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
bo_add_32be
(
hdlr
,
0
);
// reserved
bo_add_8
(
hdlr
,
12
);
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
bo_add_mem
(
hdlr
,
12
,
"SoundHandler"
);
else
bo_add_mem
(
hdlr
,
12
,
"VideoHandler"
);
...
...
@@ -1022,7 +1387,7 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
minf
=
box_new
(
"minf"
);
/* add smhd|vmhd */
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
{
bo_t
*
smhd
;
...
...
@@ -1033,7 +1398,7 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
box_gather
(
minf
,
smhd
);
}
else
if
(
p_stream
->
p_fmt
->
i_cat
==
VIDEO_ES
)
else
if
(
p_stream
->
fmt
.
i_cat
==
VIDEO_ES
)
{
bo_t
*
vmhd
;
...
...
@@ -1092,329 +1457,6 @@ static bo_t *GetMoovBox( sout_mux_t *p_mux )
return
moov
;
}
/*****************************************************************************
* Close:
*****************************************************************************/
static
void
Close
(
vlc_object_t
*
p_this
)
{
sout_mux_t
*
p_mux
=
(
sout_mux_t
*
)
p_this
;
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
sout_buffer_t
*
p_hdr
;
bo_t
bo
,
*
moov
;
vlc_value_t
val
;
int
i_trak
;
uint64_t
i_moov_pos
;
msg_Dbg
(
p_mux
,
"Close"
);
/* Update mdat size */
bo_init
(
&
bo
,
0
,
NULL
,
VLC_TRUE
);
if
(
p_sys
->
i_pos
-
p_sys
->
i_mdat_pos
>=
(((
uint64_t
)
1
)
<<
32
)
)
{
/* Extended size */
bo_add_32be
(
&
bo
,
1
);
bo_add_fourcc
(
&
bo
,
"mdat"
);
bo_add_64be
(
&
bo
,
p_sys
->
i_pos
-
p_sys
->
i_mdat_pos
);
}
else
{
bo_add_32be
(
&
bo
,
8
);
bo_add_fourcc
(
&
bo
,
"wide"
);
bo_add_32be
(
&
bo
,
p_sys
->
i_pos
-
p_sys
->
i_mdat_pos
-
8
);
bo_add_fourcc
(
&
bo
,
"mdat"
);
}
p_hdr
=
bo_to_sout
(
p_mux
->
p_sout
,
&
bo
);
free
(
bo
.
p_buffer
);
sout_AccessOutSeek
(
p_mux
->
p_access
,
p_sys
->
i_mdat_pos
);
sout_AccessOutWrite
(
p_mux
->
p_access
,
p_hdr
);
/* Create MOOV header */
i_moov_pos
=
p_sys
->
i_pos
;
moov
=
GetMoovBox
(
p_mux
);
/* Check we need to create "fast start" files */
var_Create
(
p_this
,
"mp4-faststart"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
var_Get
(
p_this
,
"mp4-faststart"
,
&
val
);
p_sys
->
b_fast_start
=
val
.
b_bool
;
while
(
p_sys
->
b_fast_start
)
{
/* Move data to the end of the file so we can fit the moov header
* at the start */
sout_buffer_t
*
p_buf
;
int64_t
i_chunk
,
i_size
=
p_sys
->
i_pos
-
p_sys
->
i_mdat_pos
;
int
i_moov_size
=
moov
->
i_buffer
;
while
(
i_size
>
0
)
{
i_chunk
=
__MIN
(
32768
,
i_size
);
p_buf
=
sout_BufferNew
(
p_mux
->
p_sout
,
i_chunk
);
sout_AccessOutSeek
(
p_mux
->
p_access
,
p_sys
->
i_mdat_pos
+
i_size
-
i_chunk
);
if
(
sout_AccessOutRead
(
p_mux
->
p_access
,
p_buf
)
<
i_chunk
)
{
msg_Warn
(
p_this
,
"read() not supported by acces output, "
"won't create a fast start file"
);
p_sys
->
b_fast_start
=
VLC_FALSE
;
break
;
}
sout_AccessOutSeek
(
p_mux
->
p_access
,
p_sys
->
i_mdat_pos
+
i_size
+
i_moov_size
-
i_chunk
);
sout_AccessOutWrite
(
p_mux
->
p_access
,
p_buf
);
i_size
-=
i_chunk
;
}
if
(
!
p_sys
->
b_fast_start
)
break
;
/* Fix-up samples to chunks table in MOOV header */
for
(
i_trak
=
0
;
i_trak
<
p_sys
->
i_nb_streams
;
i_trak
++
)
{
mp4_stream_t
*
p_stream
=
p_sys
->
pp_streams
[
i_trak
];
unsigned
int
i
;
int
i_chunk
;
moov
->
i_buffer
=
p_stream
->
i_stco_pos
;
for
(
i_chunk
=
0
,
i
=
0
;
i
<
p_stream
->
i_entry_count
;
i_chunk
++
)
{
if
(
p_stream
->
b_stco64
)
bo_add_64be
(
moov
,
p_stream
->
entry
[
i
].
i_pos
+
i_moov_size
);
else
bo_add_32be
(
moov
,
p_stream
->
entry
[
i
].
i_pos
+
i_moov_size
);
while
(
i
<
p_stream
->
i_entry_count
)
{
if
(
i
+
1
<
p_stream
->
i_entry_count
&&
p_stream
->
entry
[
i
].
i_pos
+
p_stream
->
entry
[
i
].
i_size
!=
p_stream
->
entry
[
i
+
1
].
i_pos
)
{
i
++
;
break
;
}
i
++
;
}
}
}
moov
->
i_buffer
=
i_moov_size
;
i_moov_pos
=
p_sys
->
i_mdat_pos
;
p_sys
->
b_fast_start
=
VLC_FALSE
;
}
/* Write MOOV header */
sout_AccessOutSeek
(
p_mux
->
p_access
,
i_moov_pos
);
box_send
(
p_mux
,
moov
);
/* Clean-up */
for
(
i_trak
=
0
;
i_trak
<
p_sys
->
i_nb_streams
;
i_trak
++
)
{
mp4_stream_t
*
p_stream
=
p_sys
->
pp_streams
[
i_trak
];
if
(
p_stream
->
p_fmt
->
p_extra
)
{
free
(
p_stream
->
p_fmt
->
p_extra
);
}
free
(
p_stream
->
p_fmt
);
free
(
p_stream
->
entry
);
free
(
p_stream
);
}
if
(
p_sys
->
i_nb_streams
)
free
(
p_sys
->
pp_streams
);
free
(
p_sys
);
}
static
int
Capability
(
sout_mux_t
*
p_mux
,
int
i_query
,
void
*
p_args
,
void
*
p_answer
)
{
switch
(
i_query
)
{
case
SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME
:
*
(
vlc_bool_t
*
)
p_answer
=
VLC_FALSE
;
return
(
SOUT_MUX_CAP_ERR_OK
);
default:
return
(
SOUT_MUX_CAP_ERR_UNIMPLEMENTED
);
}
}
static
int
AddStream
(
sout_mux_t
*
p_mux
,
sout_input_t
*
p_input
)
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
mp4_stream_t
*
p_stream
;
switch
(
p_input
->
p_fmt
->
i_codec
)
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
):
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
):
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
):
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
):
case
VLC_FOURCC
(
'M'
,
'J'
,
'P'
,
'G'
):
case
VLC_FOURCC
(
'm'
,
'j'
,
'p'
,
'b'
):
case
VLC_FOURCC
(
'S'
,
'V'
,
'Q'
,
'3'
):
break
;
default:
msg_Err
(
p_mux
,
"unsupported codec %4.4s in mp4"
,
(
char
*
)
&
p_input
->
p_fmt
->
i_codec
);
return
VLC_EGENERIC
;
}
p_stream
=
malloc
(
sizeof
(
mp4_stream_t
)
);
p_stream
->
p_fmt
=
malloc
(
sizeof
(
es_format_t
)
);
memcpy
(
p_stream
->
p_fmt
,
p_input
->
p_fmt
,
sizeof
(
es_format_t
)
);
if
(
p_stream
->
p_fmt
->
i_extra
)
{
p_stream
->
p_fmt
->
p_extra
=
malloc
(
p_stream
->
p_fmt
->
i_extra
);
memcpy
(
p_stream
->
p_fmt
->
p_extra
,
p_input
->
p_fmt
->
p_extra
,
p_input
->
p_fmt
->
i_extra
);
}
p_stream
->
i_track_id
=
p_sys
->
i_nb_streams
+
1
;
p_stream
->
i_length_neg
=
0
;
p_stream
->
i_entry_count
=
0
;
p_stream
->
i_entry_max
=
1000
;
p_stream
->
entry
=
calloc
(
p_stream
->
i_entry_max
,
sizeof
(
mp4_entry_t
)
);
p_stream
->
i_duration
=
0
;
p_input
->
p_sys
=
p_stream
;
msg_Dbg
(
p_mux
,
"adding input"
);
TAB_APPEND
(
p_sys
->
i_nb_streams
,
p_sys
->
pp_streams
,
p_stream
);
return
VLC_SUCCESS
;
}
static
int
DelStream
(
sout_mux_t
*
p_mux
,
sout_input_t
*
p_input
)
{
msg_Dbg
(
p_mux
,
"removing input"
);
return
VLC_SUCCESS
;
}
/****************************************************************************/
static
int
MuxGetStream
(
sout_mux_t
*
p_mux
,
int
*
pi_stream
,
mtime_t
*
pi_dts
)
{
mtime_t
i_dts
;
int
i_stream
;
int
i
;
for
(
i
=
0
,
i_dts
=
0
,
i_stream
=
-
1
;
i
<
p_mux
->
i_nb_inputs
;
i
++
)
{
sout_fifo_t
*
p_fifo
;
p_fifo
=
p_mux
->
pp_inputs
[
i
]
->
p_fifo
;
if
(
p_fifo
->
i_depth
>
1
)
{
sout_buffer_t
*
p_buf
;
p_buf
=
sout_FifoShow
(
p_fifo
);
if
(
i_stream
<
0
||
p_buf
->
i_dts
<
i_dts
)
{
i_dts
=
p_buf
->
i_dts
;
i_stream
=
i
;
}
}
else
{
return
(
-
1
);
// wait that all fifo have at least 2 packets
}
}
if
(
pi_stream
)
{
*
pi_stream
=
i_stream
;
}
if
(
pi_dts
)
{
*
pi_dts
=
i_dts
;
}
return
(
i_stream
);
}
static
int
Mux
(
sout_mux_t
*
p_mux
)
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
for
(
;;
)
{
sout_input_t
*
p_input
;
int
i_stream
;
mp4_stream_t
*
p_stream
;
sout_buffer_t
*
p_data
;
mtime_t
i_dts
;
if
(
MuxGetStream
(
p_mux
,
&
i_stream
,
&
i_dts
)
<
0
)
{
return
(
VLC_SUCCESS
);
}
if
(
!
p_sys
->
i_start_dts
)
p_sys
->
i_start_dts
=
i_dts
;
p_input
=
p_mux
->
pp_inputs
[
i_stream
];
p_stream
=
(
mp4_stream_t
*
)
p_input
->
p_sys
;
p_data
=
sout_FifoGet
(
p_input
->
p_fifo
);
if
(
p_input
->
p_fifo
->
i_depth
>
0
)
{
sout_buffer_t
*
p_next
=
sout_FifoShow
(
p_input
->
p_fifo
);
int64_t
i_diff
=
p_next
->
i_dts
-
p_data
->
i_dts
;
if
(
i_diff
<
I64C
(
1000000
)
)
/* protection */
{
p_data
->
i_length
=
i_diff
;
}
}
if
(
p_data
->
i_length
<=
0
)
{
msg_Warn
(
p_mux
,
"i_length <= 0"
);
p_stream
->
i_length_neg
+=
p_data
->
i_length
-
1
;
p_data
->
i_length
=
1
;
}
else
if
(
p_stream
->
i_length_neg
<
0
)
{
int64_t
i_recover
=
__MIN
(
p_data
->
i_length
/
4
,
-
p_stream
->
i_length_neg
);
p_data
->
i_length
-=
i_recover
;
p_stream
->
i_length_neg
+=
i_recover
;
}
/* add index entry */
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_pos
=
p_sys
->
i_pos
;
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_size
=
p_data
->
i_size
;
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_pts_dts
=
__MAX
(
p_data
->
i_pts
-
p_data
->
i_dts
,
0
);
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_length
=
p_data
->
i_length
;
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_flags
=
p_data
->
i_flags
;
if
(
p_stream
->
i_entry_count
==
0
)
{
/* Here is another bad hack.
* To make sure audio/video are in sync, we report a corrected
* length for the 1st sample. */
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_length
=
p_data
->
i_length
+
p_data
->
i_pts
-
p_sys
->
i_start_dts
;
}
p_stream
->
i_entry_count
++
;
if
(
p_stream
->
i_entry_count
>=
p_stream
->
i_entry_max
)
{
p_stream
->
i_entry_max
+=
1000
;
p_stream
->
entry
=
realloc
(
p_stream
->
entry
,
p_stream
->
i_entry_max
*
sizeof
(
mp4_entry_t
)
);
}
/* update */
p_stream
->
i_duration
+=
p_data
->
i_length
;
p_sys
->
i_pos
+=
p_data
->
i_size
;
/* write data */
sout_AccessOutWrite
(
p_mux
->
p_access
,
p_data
);
}
return
(
VLC_SUCCESS
);
}
/****************************************************************************/
...
...
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