Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-1.1
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-1.1
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