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
Hide 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 @@
...
@@ -27,7 +27,6 @@
*****************************************************************************/
*****************************************************************************/
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <errno.h>
#include <vlc/vlc.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/input.h>
...
@@ -37,21 +36,8 @@
...
@@ -37,21 +36,8 @@
#include <time.h>
#include <time.h>
#endif
#endif
#include "codecs.h"
#include "iso_lang.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
* Module descriptor
*****************************************************************************/
*****************************************************************************/
...
@@ -60,6 +46,8 @@ static int Mux ( sout_mux_t * );
...
@@ -60,6 +46,8 @@ static int Mux ( sout_mux_t * );
"When this option is turned on, \"Fast start\" files will be created. " \
"When this option is turned on, \"Fast start\" files will be created. " \
"(\"Fast start\" files are optimized for download, allowing the user " \
"(\"Fast start\" files are optimized for download, allowing the user " \
"to start previewing the file while it is downloading).")
"to start previewing the file while it is downloading).")
static
int
Open
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
vlc_module_begin
();
vlc_module_begin
();
set_description
(
_
(
"MP4/MOV muxer"
)
);
set_description
(
_
(
"MP4/MOV muxer"
)
);
...
@@ -73,6 +61,14 @@ vlc_module_begin();
...
@@ -73,6 +61,14 @@ vlc_module_begin();
set_callbacks
(
Open
,
Close
);
set_callbacks
(
Open
,
Close
);
vlc_module_end
();
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
* Local prototypes
*****************************************************************************/
*****************************************************************************/
...
@@ -89,18 +85,18 @@ typedef struct
...
@@ -89,18 +85,18 @@ typedef struct
typedef
struct
typedef
struct
{
{
es_format_t
*
p_
fmt
;
es_format_t
fmt
;
int
i_track_id
;
int
i_track_id
;
int64_t
i_length_neg
;
/* index */
/* index */
unsigned
int
i_entry_count
;
unsigned
int
i_entry_count
;
unsigned
int
i_entry_max
;
unsigned
int
i_entry_max
;
mp4_entry_t
*
entry
;
mp4_entry_t
*
entry
;
int64_t
i_length_neg
;
/* stats */
/* stats */
mtime_t
i_duration
;
int64_t
i_dts_start
;
int64_t
i_duration
;
/* for later stco fix-up (fast start files) */
/* for later stco fix-up (fast start files) */
uint64_t
i_stco_pos
;
uint64_t
i_stco_pos
;
...
@@ -117,7 +113,7 @@ struct sout_mux_sys_t
...
@@ -117,7 +113,7 @@ struct sout_mux_sys_t
uint64_t
i_mdat_pos
;
uint64_t
i_mdat_pos
;
uint64_t
i_pos
;
uint64_t
i_pos
;
mtime_t
i_start_dts
;
int64_t
i_dts_start
;
int
i_nb_streams
;
int
i_nb_streams
;
mp4_stream_t
**
pp_streams
;
mp4_stream_t
**
pp_streams
;
...
@@ -154,10 +150,10 @@ static void box_gather ( bo_t *box, bo_t *box2 );
...
@@ -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
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
sout_buffer_t
*
bo_to_sout
(
sout_instance_t
*
p_sout
,
bo_t
*
box
);
static
bo_t
*
GetMoovBox
(
sout_mux_t
*
p_mux
);
/*****************************************************************************
/*****************************************************************************
* Open:
* Open:
*****************************************************************************/
*****************************************************************************/
...
@@ -173,7 +169,7 @@ static int Open( vlc_object_t *p_this )
...
@@ -173,7 +169,7 @@ static int Open( vlc_object_t *p_this )
p_sys
->
pp_streams
=
NULL
;
p_sys
->
pp_streams
=
NULL
;
p_sys
->
i_mdat_pos
=
0
;
p_sys
->
i_mdat_pos
=
0
;
p_sys
->
b_mov
=
p_mux
->
psz_mux
&&
!
strcmp
(
p_mux
->
psz_mux
,
"mov"
);
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"
);
msg_Dbg
(
p_mux
,
"Open"
);
...
@@ -213,1210 +209,1256 @@ static int Open( vlc_object_t *p_this )
...
@@ -213,1210 +209,1256 @@ static int Open( vlc_object_t *p_this )
return
VLC_SUCCESS
;
return
VLC_SUCCESS
;
}
}
static
int
GetDescrLength
(
int
i_size
)
/*****************************************************************************
* Close:
*****************************************************************************/
static
void
Close
(
vlc_object_t
*
p_this
)
{
{
if
(
i_size
<
0x00000080
)
sout_mux_t
*
p_mux
=
(
sout_mux_t
*
)
p_this
;
return
2
+
i_size
;
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
else
if
(
i_size
<
0x00004000
)
sout_buffer_t
*
p_hdr
;
return
3
+
i_size
;
bo_t
bo
,
*
moov
;
else
if
(
i_size
<
0x00200000
)
vlc_value_t
val
;
return
4
+
i_size
;
else
return
5
+
i_size
;
}
static
bo_t
*
GetESDS
(
mp4_stream_t
*
p_stream
)
int
i_trak
;
{
uint64_t
i_moov_pos
;
bo_t
*
esds
;
int
i_stream_type
;
msg_Dbg
(
p_mux
,
"Close"
);
int
i_object_type_indication
;
int
i_decoder_specific_info_size
;
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
=
/* Extended size */
GetDescrLength
(
p_stream
->
p_fmt
->
i_extra
);
bo_add_32be
(
&
bo
,
1
);
bo_add_fourcc
(
&
bo
,
"mdat"
);
bo_add_64be
(
&
bo
,
p_sys
->
i_pos
-
p_sys
->
i_mdat_pos
);
}
}
else
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
/* DecoderConfigDescr */
bo_add_descr
(
esds
,
0x04
,
13
+
i_decoder_specific_info_size
);
switch
(
p_stream
->
p_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
->
p_fmt
->
audio
.
i_rate
<
32000
?
0x69
:
0x6b
;
break
;
default:
i_object_type_indication
=
0x00
;
break
;
}
i_stream_type
=
p_stream
->
p_fmt
->
i_cat
==
VIDEO_ES
?
0x04
:
0x05
;
bo_add_8
(
esds
,
i_object_type_indication
);
/* Create MOOV header */
bo_add_8
(
esds
,
(
i_stream_type
<<
2
)
|
1
);
i_moov_pos
=
p_sys
->
i_pos
;
bo_add_24be
(
esds
,
1024
*
1024
);
// bufferSizeDB
moov
=
GetMoovBox
(
p_mux
);
bo_add_32be
(
esds
,
0x7fffffff
);
// maxBitrate
bo_add_32be
(
esds
,
0
);
// avgBitrate
if
(
p_stream
->
p_fmt
->
i_extra
>
0
)
/* 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
)
{
{
int
i
;
/* Move data to the end of the file so we can fit the moov header
* at the start */
/* DecoderSpecificInfo */
sout_buffer_t
*
p_buf
;
bo_add_descr
(
esds
,
0x05
,
p_stream
->
p_fmt
->
i_extra
);
int64_t
i_chunk
,
i_size
=
p_sys
->
i_pos
-
p_sys
->
i_mdat_pos
;
int
i_moov_size
=
moov
->
i_buffer
;
for
(
i
=
0
;
i
<
p_stream
->
p_fmt
->
i_extra
;
i
++
)
while
(
i_size
>
0
)
{
{
bo_add_8
(
esds
,
((
uint8_t
*
)
p_stream
->
p_fmt
->
p_extra
)[
i
]
);
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
;
}
}
}
/* SL_Descr mandatory */
if
(
!
p_sys
->
b_fast_start
)
break
;
bo_add_descr
(
esds
,
0x06
,
1
);
bo_add_8
(
esds
,
0x02
);
// sl_predefined
box_fix
(
esds
);
/* 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
;
return
esds
;
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
);
static
bo_t
*
GetWaveTag
(
mp4_stream_t
*
p_stream
)
while
(
i
<
p_stream
->
i_entry_count
)
{
{
bo_t
*
wave
;
if
(
i
+
1
<
p_stream
->
i_entry_count
&&
bo_t
*
box
;
p_stream
->
entry
[
i
].
i_pos
+
p_stream
->
entry
[
i
].
i_size
!=
p_stream
->
entry
[
i
+
1
].
i_pos
)
{
i
++
;
break
;
}
wave
=
box_new
(
"wave"
);
i
++
;
}
}
}
box
=
box_new
(
"frma"
)
;
moov
->
i_buffer
=
i_moov_size
;
bo_add_fourcc
(
box
,
"mp4a"
)
;
i_moov_pos
=
p_sys
->
i_mdat_pos
;
box_fix
(
box
)
;
p_sys
->
b_fast_start
=
VLC_FALSE
;
box_gather
(
wave
,
box
);
}
box
=
box_new
(
"mp4a"
);
/* Write MOOV header */
bo_add_32be
(
box
,
0
);
sout_AccessOutSeek
(
p_mux
->
p_access
,
i_moov_pos
);
box_fix
(
box
);
box_send
(
p_mux
,
moov
);
box_gather
(
wave
,
box
);
box
=
GetESDS
(
p_stream
);
/* Clean-up */
box_fix
(
box
);
for
(
i_trak
=
0
;
i_trak
<
p_sys
->
i_nb_streams
;
i_trak
++
)
box_gather
(
wave
,
box
);
{
mp4_stream_t
*
p_stream
=
p_sys
->
pp_streams
[
i_trak
];
box
=
box_new
(
"srcq"
);
es_format_Clean
(
&
p_stream
->
fmt
);
bo_add_32be
(
box
,
0x40
);
free
(
p_stream
->
entry
);
box_fix
(
box
);
free
(
p_stream
);
box_gather
(
wave
,
box
);
}
if
(
p_sys
->
i_nb_streams
)
free
(
p_sys
->
pp_streams
);
free
(
p_sys
);
}
/* wazza ? */
/*****************************************************************************
bo_add_32be
(
wave
,
8
);
/* new empty box */
* Capability:
bo_add_32be
(
wave
,
0
);
/* box label */
*****************************************************************************/
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_TRUE
;
return
SOUT_MUX_CAP_ERR_OK
;
box_fix
(
wave
);
case
SOUT_MUX_CAP_GET_ADD_STREAM_WAIT
:
*
(
vlc_bool_t
*
)
p_answer
=
VLC_TRUE
;
return
(
SOUT_MUX_CAP_ERR_OK
);
return
wave
;
default:
return
SOUT_MUX_CAP_ERR_UNIMPLEMENTED
;
}
}
}
/* TODO: No idea about these values */
/*****************************************************************************
static
bo_t
*
GetSVQ3Tag
(
mp4_stream_t
*
p_stream
)
* AddStream:
*****************************************************************************/
static
int
AddStream
(
sout_mux_t
*
p_mux
,
sout_input_t
*
p_input
)
{
{
bo_t
*
smi
=
box_new
(
"SMI "
);
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
mp4_stream_t
*
p_stream
;
if
(
p_stream
->
p_fmt
->
i_extra
>
0x4e
)
switch
(
p_input
->
p_fmt
->
i_codec
)
{
{
uint8_t
*
p_end
=
&
((
uint8_t
*
)
p_stream
->
p_fmt
->
p_extra
)[
p_stream
->
p_fmt
->
i_extra
];
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
):
uint8_t
*
p
=
&
((
uint8_t
*
)
p_stream
->
p_fmt
->
p_extra
)[
0x46
];
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
;
}
while
(
p
+
8
<
p_end
)
p_stream
=
malloc
(
sizeof
(
mp4_stream_t
)
);
{
es_format_Copy
(
&
p_stream
->
fmt
,
p_input
->
p_fmt
);
int
i_size
=
GetDWBE
(
p
);
p_stream
->
i_track_id
=
p_sys
->
i_nb_streams
+
1
;
if
(
i_size
<=
1
)
p_stream
->
i_length_neg
=
0
;
{
p_stream
->
i_entry_count
=
0
;
/* FIXME handle 1 as long size */
p_stream
->
i_entry_max
=
1000
;
break
;
p_stream
->
entry
=
}
calloc
(
p_stream
->
i_entry_max
,
sizeof
(
mp4_entry_t
)
);
if
(
!
strncmp
(
&
p
[
4
],
"SMI "
,
4
)
)
p_stream
->
i_dts_start
=
0
;
{
p_stream
->
i_duration
=
0
;
bo_add_mem
(
smi
,
p_end
-
p
-
8
,
&
p
[
8
]
);
return
smi
;
}
p
+=
i_size
;
}
}
/* Create a dummy one in fallback */
p_input
->
p_sys
=
p_stream
;
bo_add_fourcc
(
smi
,
"SEQH"
);
bo_add_32be
(
smi
,
0x5
);
bo_add_32be
(
smi
,
0xe2c0211d
);
bo_add_8
(
smi
,
0xc0
);
box_fix
(
smi
);
return
smi
;
msg_Dbg
(
p_mux
,
"adding input"
);
TAB_APPEND
(
p_sys
->
i_nb_streams
,
p_sys
->
pp_streams
,
p_stream
);
return
VLC_SUCCESS
;
}
}
static
bo_t
*
GetUdtaTag
(
sout_mux_t
*
p_mux
)
/*****************************************************************************
* DelStream:
*****************************************************************************/
static
int
DelStream
(
sout_mux_t
*
p_mux
,
sout_input_t
*
p_input
)
{
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
msg_Dbg
(
p_mux
,
"removing input"
)
;
bo_t
*
udta
=
box_new
(
"udta"
)
;
return
VLC_SUCCESS
;
int
i_track
;
}
/* Requirements */
static
int
MuxGetStream
(
sout_mux_t
*
p_mux
,
int
*
pi_stream
,
mtime_t
*
pi_dts
)
for
(
i_track
=
0
;
i_track
<
p_sys
->
i_nb_streams
;
i_track
++
)
{
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
++
)
{
{
mp4_stream_t
*
p_stream
=
p_sys
->
pp_streams
[
i_track
];
sout_fifo_t
*
p_fifo
=
p_mux
->
pp_inputs
[
i
]
->
p_fifo
;
sout_buffer_t
*
p_buf
;
if
(
p_stream
->
p_fmt
->
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
)
||
if
(
p_fifo
->
i_depth
<=
1
)
p_stream
->
p_fmt
->
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
{
{
bo_t
*
box
=
box_new
(
"
\251
req"
);
return
-
1
;
// wait that all fifo have at least 2 packets
/* String length */
bo_add_16be
(
box
,
sizeof
(
"QuickTime 6.0 or greater"
)
-
1
);
bo_add_16be
(
box
,
0
);
bo_add_mem
(
box
,
sizeof
(
"QuickTime 6.0 or greater"
)
-
1
,
"QuickTime 6.0 or greater"
);
box_fix
(
box
);
box_gather
(
udta
,
box
);
break
;
}
}
}
/* Encoder */
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
)
{
{
bo_t
*
box
=
box_new
(
"
\251
enc"
);
*
pi_stream
=
i_stream
;
/* String length */
bo_add_16be
(
box
,
sizeof
(
PACKAGE_STRING
" stream output"
)
-
1
);
bo_add_16be
(
box
,
0
);
bo_add_mem
(
box
,
sizeof
(
PACKAGE_STRING
" stream output"
)
-
1
,
PACKAGE_STRING
" stream output"
);
box_fix
(
box
);
box_gather
(
udta
,
box
);
}
}
if
(
pi_dts
)
box_fix
(
udta
);
{
return
udta
;
*
pi_dts
=
i_dts
;
}
return
i_stream
;
}
}
static
bo_t
*
GetSounBox
(
sout_mux_t
*
p_mux
,
mp4_stream_t
*
p_stream
)
/*****************************************************************************
* Mux:
*****************************************************************************/
static
int
Mux
(
sout_mux_t
*
p_mux
)
{
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
vlc_bool_t
b_descr
=
VLC_FALSE
;
bo_t
*
soun
;
char
fcc
[
4
]
=
" "
;
int
i
;
switch
(
p_stream
->
p_fmt
->
i_codec
)
for
(
;;
)
{
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
):
sout_input_t
*
p_input
;
memcpy
(
fcc
,
"mp4a"
,
4
);
int
i_stream
;
b_descr
=
VLC_TRUE
;
mp4_stream_t
*
p_stream
;
break
;
sout_buffer_t
*
p_data
;
mtime_t
i_dts
;
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
):
if
(
MuxGetStream
(
p_mux
,
&
i_stream
,
&
i_dts
)
<
0
)
if
(
p_sys
->
b_mov
)
memcpy
(
fcc
,
".mp3"
,
4
);
else
{
{
memcpy
(
fcc
,
"mp4a"
,
4
);
return
(
VLC_SUCCESS
);
b_descr
=
VLC_TRUE
;
}
}
break
;
default:
memcpy
(
fcc
,
(
char
*
)
&
p_stream
->
p_fmt
->
i_codec
,
4
);
break
;
}
soun
=
box_new
(
fcc
);
p_input
=
p_mux
->
pp_inputs
[
i_stream
];
for
(
i
=
0
;
i
<
6
;
i
++
)
p_stream
=
(
mp4_stream_t
*
)
p_input
->
p_sys
;
{
bo_add_8
(
soun
,
0
);
// reserved;
}
bo_add_16be
(
soun
,
1
);
// data-reference-index
/* SoundDescription */
p_data
=
sout_FifoGet
(
p_input
->
p_fifo
);
if
(
p_sys
->
b_mov
&&
if
(
p_input
->
p_fifo
->
i_depth
>
0
)
p_stream
->
p_fmt
->
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
{
{
sout_buffer_t
*
p_next
=
sout_FifoShow
(
p_input
->
p_fifo
);
bo_add_16be
(
soun
,
1
);
// version 1;
int64_t
i_diff
=
p_next
->
i_dts
-
p_data
->
i_dts
;
}
else
{
bo_add_16be
(
soun
,
0
);
// version 0;
}
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
);
// 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
,
-
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
,
0
);
// sampleratelo
/* Extended data for SoundDescription V1 */
if
(
i_diff
<
I64C
(
1000000
)
)
/* protection */
if
(
p_sys
->
b_mov
&&
{
p_stream
->
p_fmt
->
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
p_data
->
i_length
=
i_diff
;
{
}
/* samples per packet */
}
bo_add_32be
(
soun
,
p_stream
->
p_fmt
->
audio
.
i_frame_length
);
if
(
p_data
->
i_length
<=
0
)
bo_add_32be
(
soun
,
1536
);
/* bytes per packet */
{
bo_add_32be
(
soun
,
2
);
/* bytes per frame */
msg_Warn
(
p_mux
,
"i_length <= 0"
);
/* bytes per sample */
p_stream
->
i_length_neg
+=
p_data
->
i_length
-
1
;
bo_add_32be
(
soun
,
2
/*p_stream->p_fmt->audio.i_bitspersample/8 */
);
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
);
/* Add an ES Descriptor */
p_data
->
i_length
-=
i_recover
;
if
(
b_descr
)
p_stream
->
i_length_neg
+=
i_recover
;
{
}
bo_t
*
box
;
if
(
p_sys
->
b_mov
&&
/* Save starting time */
p_stream
->
p_fmt
->
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
if
(
p_stream
->
i_entry_count
==
0
)
{
{
box
=
GetWaveTag
(
p_stream
);
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
;
}
}
}
else
/* 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
)
{
{
box
=
GetESDS
(
p_stream
);
p_stream
->
i_entry_max
+=
1000
;
p_stream
->
entry
=
realloc
(
p_stream
->
entry
,
p_stream
->
i_entry_max
*
sizeof
(
mp4_entry_t
)
);
}
}
box_fix
(
box
);
box_gather
(
soun
,
box
);
}
box_fix
(
soun
);
/* update */
p_stream
->
i_duration
+=
p_data
->
i_length
;
p_sys
->
i_pos
+=
p_data
->
i_size
;
return
soun
;
/* write data */
sout_AccessOutWrite
(
p_mux
->
p_access
,
p_data
);
}
return
(
VLC_SUCCESS
);
}
}
static
bo_t
*
GetVideBox
(
sout_mux_t
*
p_mux
,
mp4_stream_t
*
p_stream
)
/*****************************************************************************
*
*****************************************************************************/
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
;
}
bo_t
*
vide
;
static
bo_t
*
GetESDS
(
mp4_stream_t
*
p_stream
)
char
fcc
[
4
]
=
" "
;
{
int
i
;
bo_t
*
esds
;
int
i_stream_type
;
int
i_object_type_indication
;
int
i_decoder_specific_info_size
;
switch
(
p_stream
->
p_fmt
->
i_codec
)
if
(
p_stream
->
fmt
.
i_extra
>
0
)
{
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
):
i_decoder_specific_info_size
=
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
):
GetDescrLength
(
p_stream
->
fmt
.
i_extra
);
memcpy
(
fcc
,
"mp4v"
,
4
);
break
;
case
VLC_FOURCC
(
'M'
,
'J'
,
'P'
,
'G'
):
memcpy
(
fcc
,
"mjpa"
,
4
);
break
;
case
VLC_FOURCC
(
'S'
,
'V'
,
'Q'
,
'3'
):
memcpy
(
fcc
,
"SVQ3"
,
4
);
break
;
default:
memcpy
(
fcc
,
(
char
*
)
&
p_stream
->
p_fmt
->
i_codec
,
4
);
break
;
}
}
else
vide
=
box_new
(
fcc
);
for
(
i
=
0
;
i
<
6
;
i
++
)
{
{
bo_add_8
(
vide
,
0
);
// reserved
;
i_decoder_specific_info_size
=
0
;
}
}
bo_add_16be
(
vide
,
1
);
// data-reference-index
bo_add_16be
(
vide
,
0
);
// predefined;
esds
=
box_full_new
(
"esds"
,
0
,
0
);
bo_add_16be
(
vide
,
0
);
// reserved;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
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_32be
(
vide
,
0x00480000
);
// h 72dpi
/* ES_Descr */
bo_add_32be
(
vide
,
0x00480000
);
// v 72dpi
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
bo_add_32be
(
vide
,
0
);
// data size, always 0
/* DecoderConfigDescr */
bo_add_
16be
(
vide
,
1
);
// frames count per sample
bo_add_
descr
(
esds
,
0x04
,
13
+
i_decoder_specific_info_size
);
// compressor name;
switch
(
p_stream
->
fmt
.
i_codec
)
for
(
i
=
0
;
i
<
32
;
i
++
)
{
{
bo_add_8
(
vide
,
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
->
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_16be
(
vide
,
0x18
);
// depth
bo_add_8
(
esds
,
i_object_type_indication
);
bo_add_16be
(
vide
,
0xffff
);
// predefined
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
/* add an ES Descriptor */
if
(
p_stream
->
fmt
.
i_extra
>
0
)
switch
(
p_stream
->
p_fmt
->
i_codec
)
{
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
):
int
i
;
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
):
{
bo_t
*
esds
=
GetESDS
(
p_stream
);
box_fix
(
esds
);
/* DecoderSpecificInfo */
box_gather
(
vide
,
esds
);
bo_add_descr
(
esds
,
0x05
,
p_stream
->
fmt
.
i_extra
);
}
break
;
case
VLC_FOURCC
(
'S'
,
'V'
,
'Q'
,
'3'
):
for
(
i
=
0
;
i
<
p_stream
->
fmt
.
i_extra
;
i
++
)
{
{
bo_t
*
esds
=
GetSVQ3Tag
(
p_stream
);
bo_add_8
(
esds
,
((
uint8_t
*
)
p_stream
->
fmt
.
p_extra
)[
i
]
);
box_fix
(
esds
);
box_gather
(
vide
,
esds
);
}
}
break
;
default:
break
;
}
}
box_fix
(
vide
);
/* SL_Descr mandatory */
bo_add_descr
(
esds
,
0x06
,
1
);
bo_add_8
(
esds
,
0x02
);
// sl_predefined
return
vide
;
box_fix
(
esds
);
return
esds
;
}
}
static
bo_t
*
Get
StblBox
(
sout_mux_t
*
p_mux
,
mp4_stream_t
*
p_stream
)
static
bo_t
*
Get
WaveTag
(
mp4_stream_t
*
p_stream
)
{
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
bo_t
*
wave
;
unsigned
int
i_chunk
,
i_stsc_last_val
,
i_stsc_entries
,
i
,
i_index
;
bo_t
*
box
;
bo_t
*
stbl
,
*
stsd
,
*
stts
,
*
stco
,
*
stsc
,
*
stsz
,
*
stss
;
uint32_t
i_timescale
;
int64_t
i_dts
,
i_dts_q
;
stbl
=
box_new
(
"stbl
"
);
wave
=
box_new
(
"wave
"
);
/* sample description */
box
=
box_new
(
"frma"
);
stsd
=
box_full_new
(
"stsd"
,
0
,
0
);
bo_add_fourcc
(
box
,
"mp4a"
);
bo_add_32be
(
stsd
,
1
);
box_fix
(
box
);
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
box_gather
(
wave
,
box
);
{
bo_t
*
soun
=
GetSounBox
(
p_mux
,
p_stream
);
box_gather
(
stsd
,
soun
);
}
else
if
(
p_stream
->
p_fmt
->
i_cat
==
VIDEO_ES
)
{
bo_t
*
vide
=
GetVideBox
(
p_mux
,
p_stream
);
box_gather
(
stsd
,
vide
);
}
box_fix
(
stsd
);
/* chunk offset table */
box
=
box_new
(
"mp4a"
);
if
(
p_sys
->
i_pos
>=
(((
uint64_t
)
0x1
)
<<
32
)
)
bo_add_32be
(
box
,
0
);
{
box_fix
(
box
);
/* 64 bits version */
box_gather
(
wave
,
box
);
p_stream
->
b_stco64
=
VLC_TRUE
;
stco
=
box_full_new
(
"co64"
,
0
,
0
);
}
else
{
/* 32 bits version */
p_stream
->
b_stco64
=
VLC_FALSE
;
stco
=
box_full_new
(
"stco"
,
0
,
0
);
}
bo_add_32be
(
stco
,
0
);
// entry-count (fixed latter)
/* sample to chunk table */
box
=
GetESDS
(
p_stream
);
stsc
=
box_full_new
(
"stsc"
,
0
,
0
);
box_fix
(
box
);
bo
_add_32be
(
stsc
,
0
);
// entry-count (fixed latter)
bo
x_gather
(
wave
,
box
);
for
(
i_chunk
=
0
,
i_stsc_last_val
=
0
,
i_stsc_entries
=
0
,
i
=
0
;
box
=
box_new
(
"srcq"
)
;
i
<
p_stream
->
i_entry_count
;
i_chunk
++
)
bo_add_32be
(
box
,
0x40
);
{
box_fix
(
box
);
int
i_first
=
i
;
box_gather
(
wave
,
box
)
;
if
(
p_stream
->
b_stco64
)
/* wazza ? */
bo_add_64be
(
stco
,
p_stream
->
entry
[
i
].
i_pos
);
bo_add_32be
(
wave
,
8
);
/* new empty box */
else
bo_add_32be
(
wave
,
0
);
/* box label */
bo_add_32be
(
stco
,
p_stream
->
entry
[
i
].
i_pos
);
while
(
i
<
p_stream
->
i_entry_count
)
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
->
fmt
.
p_extra
)[
p_stream
->
fmt
.
i_extra
];
uint8_t
*
p
=
&
((
uint8_t
*
)
p_stream
->
fmt
.
p_extra
)[
0x46
];
while
(
p
+
8
<
p_end
)
{
{
if
(
i
+
1
<
p_stream
->
i_entry_count
&&
int
i_size
=
GetDWBE
(
p
);
p_stream
->
entry
[
i
].
i_pos
+
p_stream
->
entry
[
i
].
i_size
if
(
i_size
<=
1
)
!=
p_stream
->
entry
[
i
+
1
].
i_pos
)
{
{
i
++
;
/* FIXME handle 1 as long size */
break
;
break
;
}
}
if
(
!
strncmp
(
&
p
[
4
],
"SMI "
,
4
)
)
i
++
;
{
}
bo_add_mem
(
smi
,
p_end
-
p
-
8
,
&
p
[
8
]
);
return
smi
;
/* Add entry to the stsc table */
}
if
(
i_stsc_last_val
!=
i
-
i_first
)
p
+=
i_size
;
{
bo_add_32be
(
stsc
,
1
+
i_chunk
);
// first-chunk
bo_add_32be
(
stsc
,
i
-
i_first
)
;
// samples-per-chunk
bo_add_32be
(
stsc
,
1
);
// sample-descr-index
i_stsc_last_val
=
i
-
i_first
;
i_stsc_entries
++
;
}
}
}
}
/* Fix stco entry count */
/* Create a dummy one in fallback */
bo_fix_32be
(
stco
,
12
,
i_chunk
);
bo_add_fourcc
(
smi
,
"SEQH"
);
msg_Dbg
(
p_mux
,
"created %d chunks (stco)"
,
i_chunk
);
bo_add_32be
(
smi
,
0x5
);
box_fix
(
stco
);
bo_add_32be
(
smi
,
0xe2c0211d
);
bo_add_8
(
smi
,
0xc0
);
/* Fix stsc entry count */
box_fix
(
smi
);
bo_fix_32be
(
stsc
,
12
,
i_stsc_entries
);
box_fix
(
stsc
);
/* add stts */
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
;
else
i_timescale
=
1001
;
/* first, create quantified length */
for
(
i
=
0
,
i_dts
=
0
,
i_dts_q
=
0
;
i
<
p_stream
->
i_entry_count
;
i
++
)
{
int64_t
i_dts_deq
=
i_dts_q
*
I64C
(
1000000
)
/
(
int64_t
)
i_timescale
;
int64_t
i_delta
=
p_stream
->
entry
[
i
].
i_length
+
i_dts
-
i_dts_deq
;
i_dts
+=
p_stream
->
entry
[
i
].
i_length
;
return
smi
;
}
p_stream
->
entry
[
i
].
i_length
=
i_delta
*
(
int64_t
)
i_timescale
/
I64C
(
1000000
);;
static
bo_t
*
GetUdtaTag
(
sout_mux_t
*
p_mux
)
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
bo_t
*
udta
=
box_new
(
"udta"
);
int
i_track
;
i_dts_q
+=
p_stream
->
entry
[
i
].
i_length
;
/* Requirements */
}
for
(
i_track
=
0
;
i_track
<
p_sys
->
i_nb_streams
;
i_track
++
)
/* then write encoded table */
for
(
i
=
0
,
i_index
=
0
;
i
<
p_stream
->
i_entry_count
;
i_index
++
)
{
{
int
i_first
=
i
;
mp4_stream_t
*
p_stream
=
p_sys
->
pp_streams
[
i_track
];
int64_t
i_delta
=
p_stream
->
entry
[
i
].
i_length
;
while
(
i
<
p_stream
->
i_entry_count
)
if
(
p_stream
->
fmt
.
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
)
||
p_stream
->
fmt
.
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
{
{
i
++
;
bo_t
*
box
=
box_new
(
"
\251
req"
);
if
(
i
>=
p_stream
->
i_entry_count
||
/* String length */
p_stream
->
entry
[
i
].
i_length
!=
i_delta
)
bo_add_16be
(
box
,
sizeof
(
"QuickTime 6.0 or greater"
)
-
1
);
{
bo_add_16be
(
box
,
0
);
break
;
bo_add_mem
(
box
,
sizeof
(
"QuickTime 6.0 or greater"
)
-
1
,
}
"QuickTime 6.0 or greater"
);
box_fix
(
box
);
box_gather
(
udta
,
box
);
break
;
}
}
bo_add_32be
(
stts
,
i
-
i_first
);
// sample-count
bo_add_32be
(
stts
,
i_delta
);
// sample-delta
}
}
bo_fix_32be
(
stts
,
12
,
i_index
);
box_fix
(
stts
);
/* FIXME add ctts ?? FIXME */
stsz
=
box_full_new
(
"stsz"
,
0
,
0
);
/* Encoder */
bo_add_32be
(
stsz
,
0
);
// sample-size
bo_add_32be
(
stsz
,
p_stream
->
i_entry_count
);
// sample-count
for
(
i
=
0
;
i
<
p_stream
->
i_entry_count
;
i
++
)
{
{
bo_add_32be
(
stsz
,
p_stream
->
entry
[
i
].
i_size
);
// sample-size
bo_t
*
box
=
box_new
(
"
\251
enc"
);
}
/* String length */
box_fix
(
stsz
);
bo_add_16be
(
box
,
sizeof
(
PACKAGE_STRING
" stream output"
)
-
1
);
bo_add_16be
(
box
,
0
);
/* create stss table */
bo_add_mem
(
box
,
sizeof
(
PACKAGE_STRING
" stream output"
)
-
1
,
stss
=
NULL
;
PACKAGE_STRING
" stream output"
);
for
(
i
=
0
,
i_index
=
0
;
i
<
p_stream
->
i_entry_count
;
i
++
)
box_fix
(
box
);
{
box_gather
(
udta
,
box
);
if
(
p_stream
->
entry
[
i
].
i_flags
&
(
BLOCK_FLAG_TYPE_I
<<
SOUT_BUFFER_FLAGS_BLOCK_SHIFT
)
)
{
if
(
stss
==
NULL
)
{
stss
=
box_full_new
(
"stss"
,
0
,
0
);
bo_add_32be
(
stss
,
0
);
/* fixed later */
}
bo_add_32be
(
stss
,
1
+
i
);
i_index
++
;
}
}
if
(
stss
)
{
bo_fix_32be
(
stss
,
12
,
i_index
);
box_fix
(
stss
);
}
/* Now gather all boxes into stbl */
box_gather
(
stbl
,
stsd
);
box_gather
(
stbl
,
stts
);
if
(
stss
)
{
box_gather
(
stbl
,
stss
);
}
}
box_gather
(
stbl
,
stsc
);
box_gather
(
stbl
,
stsz
);
p_stream
->
i_stco_pos
=
stbl
->
i_buffer
+
16
;
box_gather
(
stbl
,
stco
);
/* finish stbl */
box_fix
(
stbl
);
return
stbl
;
box_fix
(
udta
);
return
udta
;
}
}
static
uint32_t
mvhd_matrix
[
9
]
=
static
bo_t
*
GetSounBox
(
sout_mux_t
*
p_mux
,
mp4_stream_t
*
p_stream
)
{
0x10000
,
0
,
0
,
0
,
0x10000
,
0
,
0
,
0
,
0x40000000
};
static
bo_t
*
GetMoovBox
(
sout_mux_t
*
p_mux
)
{
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
vlc_bool_t
b_descr
=
VLC_FALSE
;
bo_t
*
soun
;
char
fcc
[
4
]
=
" "
;
int
i
;
bo_t
*
moov
,
*
mvhd
;
switch
(
p_stream
->
fmt
.
i_codec
)
int
i_trak
,
i
;
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
):
memcpy
(
fcc
,
"mp4a"
,
4
);
b_descr
=
VLC_TRUE
;
break
;
uint32_t
i_movie_timescale
=
90000
;
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
):
int64_t
i_movie_duration
=
0
;
if
(
p_sys
->
b_mov
)
memcpy
(
fcc
,
".mp3"
,
4
);
else
{
memcpy
(
fcc
,
"mp4a"
,
4
);
b_descr
=
VLC_TRUE
;
}
break
;
moov
=
box_new
(
"moov"
);
default:
memcpy
(
fcc
,
(
char
*
)
&
p_stream
->
fmt
.
i_codec
,
4
);
break
;
}
/* Create general info */
soun
=
box_new
(
fcc
);
for
(
i
_trak
=
0
;
i_trak
<
p_sys
->
i_nb_streams
;
i_trak
++
)
for
(
i
=
0
;
i
<
6
;
i
++
)
{
{
mp4_stream_t
*
p_stream
=
p_sys
->
pp_streams
[
i_trak
];
bo_add_8
(
soun
,
0
);
// reserved;
i_movie_duration
=
__MAX
(
i_movie_duration
,
p_stream
->
i_duration
);
}
}
msg_Dbg
(
p_mux
,
"movie duration %ds"
,
bo_add_16be
(
soun
,
1
);
// data-reference-index
(
uint32_t
)(
i_movie_duration
/
(
mtime_t
)
1000000
)
);
i_movie_duration
=
i_movie_duration
*
i_movie_timescale
/
1000000
;
/* *** add /moov/mvhd *** */
/* SoundDescription */
if
(
!
p_sys
->
b_64_ext
)
if
(
p_sys
->
b_mov
&&
p_stream
->
fmt
.
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
{
{
mvhd
=
box_full_new
(
"mvhd"
,
0
,
0
);
bo_add_16be
(
soun
,
1
);
// version 1;
bo_add_32be
(
mvhd
,
get_timestamp
()
);
// creation time
bo_add_32be
(
mvhd
,
get_timestamp
()
);
// modification time
bo_add_32be
(
mvhd
,
i_movie_timescale
);
// timescale
bo_add_32be
(
mvhd
,
i_movie_duration
);
// duration
}
}
else
else
{
{
mvhd
=
box_full_new
(
"mvhd"
,
1
,
0
);
bo_add_16be
(
soun
,
0
);
// version 0;
bo_add_64be
(
mvhd
,
get_timestamp
()
);
// creation time
bo_add_64be
(
mvhd
,
get_timestamp
()
);
// modification time
bo_add_32be
(
mvhd
,
i_movie_timescale
);
// timescale
bo_add_64be
(
mvhd
,
i_movie_duration
);
// duration
}
}
bo_add_32be
(
mvhd
,
0x10000
);
// rate
bo_add_16be
(
soun
,
0
);
// revision level (0)
bo_add_16be
(
mvhd
,
0x100
);
// volume
bo_add_32be
(
soun
,
0
);
// vendor
bo_add_16be
(
mvhd
,
0
);
// reserved
// channel-count
for
(
i
=
0
;
i
<
2
;
i
++
)
bo_add_16be
(
soun
,
p_stream
->
fmt
.
audio
.
i_channels
);
// sample size
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
->
fmt
.
audio
.
i_rate
);
// sampleratehi
bo_add_16be
(
soun
,
0
);
// sampleratelo
/* Extended data for SoundDescription V1 */
if
(
p_sys
->
b_mov
&&
p_stream
->
fmt
.
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
{
{
bo_add_32be
(
mvhd
,
0
);
// reserved
/* samples per packet */
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->fmt.audio.i_bitspersample/8 */
);
}
}
for
(
i
=
0
;
i
<
9
;
i
++
)
/* Add an ES Descriptor */
if
(
b_descr
)
{
{
bo_add_32be
(
mvhd
,
mvhd_matrix
[
i
]
);
// matrix
bo_t
*
box
;
if
(
p_sys
->
b_mov
&&
p_stream
->
fmt
.
i_codec
==
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
)
)
{
box
=
GetWaveTag
(
p_stream
);
}
else
{
box
=
GetESDS
(
p_stream
);
}
box_fix
(
box
);
box_gather
(
soun
,
box
);
}
}
for
(
i
=
0
;
i
<
6
;
i
++
)
box_fix
(
soun
);
return
soun
;
}
static
bo_t
*
GetVideBox
(
sout_mux_t
*
p_mux
,
mp4_stream_t
*
p_stream
)
{
bo_t
*
vide
;
char
fcc
[
4
]
=
" "
;
int
i
;
switch
(
p_stream
->
fmt
.
i_codec
)
{
{
bo_add_32be
(
mvhd
,
0
);
// pre-defined
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
):
}
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
):
memcpy
(
fcc
,
"mp4v"
,
4
);
break
;
/* Next available track id */
case
VLC_FOURCC
(
'M'
,
'J'
,
'P'
,
'G'
):
bo_add_32be
(
mvhd
,
p_sys
->
i_nb_streams
+
1
);
// next-track-id
memcpy
(
fcc
,
"mjpa"
,
4
);
break
;
box_fix
(
mvhd
);
case
VLC_FOURCC
(
'S'
,
'V'
,
'Q'
,
'3'
):
box_gather
(
moov
,
mvhd
);
memcpy
(
fcc
,
"SVQ3"
,
4
);
break
;
for
(
i_trak
=
0
;
i_trak
<
p_sys
->
i_nb_streams
;
i_trak
++
)
default:
memcpy
(
fcc
,
(
char
*
)
&
p_stream
->
fmt
.
i_codec
,
4
);
break
;
}
vide
=
box_new
(
fcc
);
for
(
i
=
0
;
i
<
6
;
i
++
)
{
{
mp4_stream_t
*
p_stream
;
bo_add_8
(
vide
,
0
);
// reserved;
uint32_t
i_timescale
;
}
bo_add_16be
(
vide
,
1
);
// data-reference-index
bo_t
*
trak
,
*
tkhd
,
*
mdia
,
*
mdhd
,
*
hdlr
;
bo_add_16be
(
vide
,
0
);
// predefined;
bo_t
*
minf
,
*
dinf
,
*
dref
,
*
url
,
*
stbl
;
bo_add_16be
(
vide
,
0
);
// reserved;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
bo_add_32be
(
vide
,
0
);
// predefined;
}
p_stream
=
p_sys
->
pp_streams
[
i_trak
];
bo_add_16be
(
vide
,
p_stream
->
fmt
.
video
.
i_width
);
// i_width
bo_add_16be
(
vide
,
p_stream
->
fmt
.
video
.
i_height
);
// i_height
if
(
p_stream
->
p_fmt
->
i_cat
!=
AUDIO_ES
&&
bo_add_32be
(
vide
,
0x00480000
);
// h 72dpi
p_stream
->
p_fmt
->
i_cat
!=
VIDEO_ES
)
bo_add_32be
(
vide
,
0x00480000
);
// v 72dpi
{
msg_Err
(
p_mux
,
"FIXME ignoring trak (noaudio&&novideo)"
);
continue
;
}
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
bo_add_32be
(
vide
,
0
);
// data size, always 0
i_timescale
=
p_stream
->
p_fmt
->
audio
.
i_rate
;
bo_add_16be
(
vide
,
1
);
// frames count per sample
else
i_timescale
=
1001
;
/* *** add /moov/trak *** */
// compressor name;
trak
=
box_new
(
"trak"
);
for
(
i
=
0
;
i
<
32
;
i
++
)
{
bo_add_8
(
vide
,
0
);
}
/* *** add /moov/trak/tkhd *** */
bo_add_16be
(
vide
,
0x18
);
// depth
if
(
!
p_sys
->
b_64_ext
)
bo_add_16be
(
vide
,
0xffff
);
// predefined
{
if
(
p_sys
->
b_mov
)
tkhd
=
box_full_new
(
"tkhd"
,
0
,
0x0f
);
else
tkhd
=
box_full_new
(
"tkhd"
,
0
,
1
);
bo_add_32be
(
tkhd
,
get_timestamp
()
);
// creation time
/* add an ES Descriptor */
bo_add_32be
(
tkhd
,
get_timestamp
()
);
// modification time
switch
(
p_stream
->
fmt
.
i_codec
)
bo_add_32be
(
tkhd
,
p_stream
->
i_track_id
);
{
bo_add_32be
(
tkhd
,
0
);
// reserved 0
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
):
bo_add_32be
(
tkhd
,
p_stream
->
i_duration
*
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
):
(
int64_t
)
i_movie_timescale
/
(
mtime_t
)
1000000
);
// duration
}
else
{
{
if
(
p_sys
->
b_mov
)
bo_t
*
esds
=
GetESDS
(
p_stream
);
tkhd
=
box_full_new
(
"tkhd"
,
1
,
0x0f
);
else
tkhd
=
box_full_new
(
"tkhd"
,
1
,
1
);
bo_add_64be
(
tkhd
,
get_timestamp
()
);
// creation time
box_fix
(
esds
);
bo_add_64be
(
tkhd
,
get_timestamp
()
);
// modification time
box_gather
(
vide
,
esds
);
bo_add_32be
(
tkhd
,
p_stream
->
i_track_id
);
bo_add_32be
(
tkhd
,
0
);
// reserved 0
bo_add_64be
(
tkhd
,
p_stream
->
i_duration
*
(
int64_t
)
i_movie_timescale
/
(
mtime_t
)
1000000
);
// duration
}
}
break
;
for
(
i
=
0
;
i
<
2
;
i
++
)
case
VLC_FOURCC
(
'S'
,
'V'
,
'Q'
,
'3'
):
{
{
bo_add_32be
(
tkhd
,
0
);
// reserved
bo_t
*
esds
=
GetSVQ3Tag
(
p_stream
);
}
bo_add_16be
(
tkhd
,
0
);
// layer
box_fix
(
esds
);
bo_add_16be
(
tkhd
,
0
);
// pre-defined
box_gather
(
vide
,
esds
);
// volume
bo_add_16be
(
tkhd
,
p_stream
->
p_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
)
{
bo_add_32be
(
tkhd
,
0
);
// width (presentation)
bo_add_32be
(
tkhd
,
0
);
// height(presentation)
}
else
{
// width (presentation)
bo_add_32be
(
tkhd
,
p_stream
->
p_fmt
->
video
.
i_aspect
*
p_stream
->
p_fmt
->
video
.
i_height
/
VOUT_ASPECT_FACTOR
<<
16
);
// height(presentation)
bo_add_32be
(
tkhd
,
p_stream
->
p_fmt
->
video
.
i_height
<<
16
);
}
box_fix
(
tkhd
);
box_gather
(
trak
,
tkhd
);
/* *** 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
}
}
break
;
if
(
p_stream
->
p_fmt
->
psz_language
)
default:
{
break
;
char
*
psz
=
p_stream
->
p_fmt
->
psz_language
;
}
const
iso639_lang_t
*
pl
=
NULL
;
uint16_t
lang
=
0x0
;
if
(
strlen
(
psz
)
==
2
)
box_fix
(
vide
);
{
pl
=
GetLang_1
(
psz
);
}
else
if
(
strlen
(
psz
)
==
3
)
{
pl
=
GetLang_2B
(
psz
);
if
(
!
strcmp
(
pl
->
psz_iso639_1
,
"??"
)
)
{
pl
=
GetLang_2T
(
psz
);
}
}
if
(
pl
&&
strcmp
(
pl
->
psz_iso639_1
,
"??"
)
)
{
lang
=
(
(
pl
->
psz_iso639_2T
[
0
]
-
0x60
)
<<
10
)
|
(
(
pl
->
psz_iso639_2T
[
1
]
-
0x60
)
<<
5
)
|
(
(
pl
->
psz_iso639_2T
[
2
]
-
0x60
)
);
}
bo_add_16be
(
mdhd
,
lang
);
// language
}
else
{
bo_add_16be
(
mdhd
,
0
);
// language
}
bo_add_16be
(
mdhd
,
0
);
// predefined
box_fix
(
mdhd
);
box_gather
(
mdia
,
mdhd
);
/* handler reference */
return
vide
;
hdlr
=
box_full_new
(
"hdlr"
,
0
,
0
);
}
bo_add_fourcc
(
hdlr
,
"mhlr"
);
// media handler
static
bo_t
*
GetStblBox
(
sout_mux_t
*
p_mux
,
mp4_stream_t
*
p_stream
)
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
{
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
bo_add_fourcc
(
hdlr
,
"soun"
);
unsigned
int
i_chunk
,
i_stsc_last_val
,
i_stsc_entries
,
i
,
i_index
;
}
bo_t
*
stbl
,
*
stsd
,
*
stts
,
*
stco
,
*
stsc
,
*
stsz
,
*
stss
;
else
uint32_t
i_timescale
;
{
int64_t
i_dts
,
i_dts_q
;
bo_add_fourcc
(
hdlr
,
"vide"
);
}
bo_add_32be
(
hdlr
,
0
);
// reserved
stbl
=
box_new
(
"stbl"
);
bo_add_32be
(
hdlr
,
0
);
// reserved
bo_add_32be
(
hdlr
,
0
);
// reserved
bo_add_8
(
hdlr
,
12
);
/* sample description */
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
stsd
=
box_full_new
(
"stsd"
,
0
,
0
);
bo_add_mem
(
hdlr
,
12
,
"SoundHandler"
);
bo_add_32be
(
stsd
,
1
);
else
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
bo_add_mem
(
hdlr
,
12
,
"VideoHandler"
);
{
bo_t
*
soun
=
GetSounBox
(
p_mux
,
p_stream
);
box_gather
(
stsd
,
soun
);
}
else
if
(
p_stream
->
fmt
.
i_cat
==
VIDEO_ES
)
{
bo_t
*
vide
=
GetVideBox
(
p_mux
,
p_stream
);
box_gather
(
stsd
,
vide
);
}
box_fix
(
stsd
);
box_fix
(
hdlr
);
/* chunk offset table */
box_gather
(
mdia
,
hdlr
);
if
(
p_sys
->
i_pos
>=
(((
uint64_t
)
0x1
)
<<
32
)
)
{
/* 64 bits version */
p_stream
->
b_stco64
=
VLC_TRUE
;
stco
=
box_full_new
(
"co64"
,
0
,
0
);
}
else
{
/* 32 bits version */
p_stream
->
b_stco64
=
VLC_FALSE
;
stco
=
box_full_new
(
"stco"
,
0
,
0
);
}
bo_add_32be
(
stco
,
0
);
// entry-count (fixed latter)
/* minf*/
/* sample to chunk table */
minf
=
box_new
(
"minf"
);
stsc
=
box_full_new
(
"stsc"
,
0
,
0
);
bo_add_32be
(
stsc
,
0
);
// entry-count (fixed latter)
/* add smhd|vmhd */
for
(
i_chunk
=
0
,
i_stsc_last_val
=
0
,
i_stsc_entries
=
0
,
i
=
0
;
if
(
p_stream
->
p_fmt
->
i_cat
==
AUDIO_ES
)
i
<
p_stream
->
i_entry_count
;
i_chunk
++
)
{
{
bo_t
*
smhd
;
int
i_first
=
i
;
smhd
=
box_full_new
(
"smhd"
,
0
,
0
);
if
(
p_stream
->
b_stco64
)
bo_add_
16be
(
smhd
,
0
);
// balance
bo_add_
64be
(
stco
,
p_stream
->
entry
[
i
].
i_pos
);
bo_add_16be
(
smhd
,
0
);
// reserved
else
bo
x_fix
(
smhd
);
bo
_add_32be
(
stco
,
p_stream
->
entry
[
i
].
i_pos
);
box_gather
(
minf
,
smhd
);
while
(
i
<
p_stream
->
i_entry_count
)
}
else
if
(
p_stream
->
p_fmt
->
i_cat
==
VIDEO_ES
)
{
{
bo_t
*
vmhd
;
if
(
i
+
1
<
p_stream
->
i_entry_count
&&
p_stream
->
entry
[
i
].
i_pos
+
p_stream
->
entry
[
i
].
i_size
vmhd
=
box_full_new
(
"vmhd"
,
0
,
1
);
!=
p_stream
->
entry
[
i
+
1
].
i_pos
)
bo_add_16be
(
vmhd
,
0
);
// graphicsmode
for
(
i
=
0
;
i
<
3
;
i
++
)
{
{
bo_add_16be
(
vmhd
,
0
);
// opcolor
i
++
;
break
;
}
}
box_fix
(
vmhd
);
box_gather
(
minf
,
vmhd
)
;
i
++
;
}
}
/* dinf */
/* Add entry to the stsc table */
dinf
=
box_new
(
"dinf"
);
if
(
i_stsc_last_val
!=
i
-
i_first
)
dref
=
box_full_new
(
"dref"
,
0
,
0
);
{
bo_add_32be
(
dref
,
1
);
bo_add_32be
(
stsc
,
1
+
i_chunk
);
// first-chunk
url
=
box_full_new
(
"url "
,
0
,
0x01
);
bo_add_32be
(
stsc
,
i
-
i_first
)
;
// samples-per-chunk
box_fix
(
url
);
bo_add_32be
(
stsc
,
1
);
// sample-descr-index
box_gather
(
dref
,
url
);
i_stsc_last_val
=
i
-
i_first
;
box_fix
(
dref
);
i_stsc_entries
++
;
box_gather
(
dinf
,
dref
);
}
}
/* append dinf to mdia */
/* Fix stco entry count */
box_fix
(
dinf
);
bo_fix_32be
(
stco
,
12
,
i_chunk
);
box_gather
(
minf
,
dinf
);
msg_Dbg
(
p_mux
,
"created %d chunks (stco)"
,
i_chunk
);
box_fix
(
stco
);
/* add stbl */
/* Fix stsc entry count */
stbl
=
GetStblBox
(
p_mux
,
p_stream
);
bo_fix_32be
(
stsc
,
12
,
i_stsc_entries
);
box_fix
(
stsc
);
/* append stbl to minf
*/
/* add stts
*/
p_stream
->
i_stco_pos
+=
minf
->
i_buffer
;
stts
=
box_full_new
(
"stts"
,
0
,
0
)
;
box_gather
(
minf
,
stbl
);
bo_add_32be
(
stts
,
0
);
// entry-count (fixed latter)
/* append minf to mdia */
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
box_fix
(
minf
)
;
i_timescale
=
p_stream
->
fmt
.
audio
.
i_rate
;
p_stream
->
i_stco_pos
+=
mdia
->
i_buffer
;
else
box_gather
(
mdia
,
minf
)
;
i_timescale
=
1001
;
/* append mdia to trak */
/* first, create quantified length */
box_fix
(
mdia
);
for
(
i
=
0
,
i_dts
=
0
,
i_dts_q
=
0
;
i
<
p_stream
->
i_entry_count
;
i
++
)
p_stream
->
i_stco_pos
+=
trak
->
i_buffer
;
{
box_gather
(
trak
,
mdia
);
int64_t
i_dts_deq
=
i_dts_q
*
I64C
(
1000000
)
/
(
int64_t
)
i_timescale
;
int64_t
i_delta
=
p_stream
->
entry
[
i
].
i_length
+
i_dts
-
i_dts_deq
;
/* append trak to moov */
i_dts
+=
p_stream
->
entry
[
i
].
i_length
;
box_fix
(
trak
);
p_stream
->
i_stco_pos
+=
moov
->
i_buffer
;
box_gather
(
moov
,
trak
);
}
/* Add user data tags */
p_stream
->
entry
[
i
].
i_length
=
i_delta
*
(
int64_t
)
i_timescale
/
I64C
(
1000000
);;
box_gather
(
moov
,
GetUdtaTag
(
p_mux
)
);
box_fix
(
moov
);
i_dts_q
+=
p_stream
->
entry
[
i
].
i_length
;
return
moov
;
}
}
/* then write encoded table */
for
(
i
=
0
,
i_index
=
0
;
i
<
p_stream
->
i_entry_count
;
i_index
++
)
{
int
i_first
=
i
;
int64_t
i_delta
=
p_stream
->
entry
[
i
].
i_length
;
/*****************************************************************************
while
(
i
<
p_stream
->
i_entry_count
)
* Close:
{
*****************************************************************************/
i
++
;
static
void
Close
(
vlc_object_t
*
p_this
)
if
(
i
>=
p_stream
->
i_entry_count
||
{
p_stream
->
entry
[
i
].
i_length
!=
i_delta
)
sout_mux_t
*
p_mux
=
(
sout_mux_t
*
)
p_this
;
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
break
;
sout_buffer_t
*
p_hdr
;
}
bo_t
bo
,
*
moov
;
}
vlc_value_t
val
;
int
i_trak
;
bo_add_32be
(
stts
,
i
-
i_first
);
// sample-count
uint64_t
i_moov_pos
;
bo_add_32be
(
stts
,
i_delta
);
// sample-delta
}
bo_fix_32be
(
stts
,
12
,
i_index
);
box_fix
(
stts
);
msg_Dbg
(
p_mux
,
"Close"
);
/* FIXME add ctts ?? FIXME */
/* Update mdat size */
stsz
=
box_full_new
(
"stsz"
,
0
,
0
);
bo_init
(
&
bo
,
0
,
NULL
,
VLC_TRUE
);
bo_add_32be
(
stsz
,
0
);
// sample-size
if
(
p_sys
->
i_pos
-
p_sys
->
i_mdat_pos
>=
(((
uint64_t
)
1
)
<<
32
)
)
bo_add_32be
(
stsz
,
p_stream
->
i_entry_count
);
// sample-count
{
for
(
i
=
0
;
i
<
p_stream
->
i_entry_count
;
i
++
)
/* 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_32be
(
stsz
,
p_stream
->
entry
[
i
].
i_size
);
// sample-size
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
);
box_fix
(
stsz
);
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 */
/* create stss table */
var_Create
(
p_this
,
"mp4-faststart"
,
VLC_VAR_BOOL
|
VLC_VAR_DOINHERIT
);
stss
=
NULL
;
var_Get
(
p_this
,
"mp4-faststart"
,
&
val
);
for
(
i
=
0
,
i_index
=
0
;
i
<
p_stream
->
i_entry_count
;
i
++
)
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
if
(
p_stream
->
entry
[
i
].
i_flags
&
(
BLOCK_FLAG_TYPE_I
<<
SOUT_BUFFER_FLAGS_BLOCK_SHIFT
)
)
* 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
);
if
(
stss
==
NULL
)
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, "
stss
=
box_full_new
(
"stss"
,
0
,
0
);
"won't create a fast start file"
);
bo_add_32be
(
stss
,
0
);
/* fixed later */
p_sys
->
b_fast_start
=
VLC_FALSE
;
break
;
}
}
sout_AccessOutSeek
(
p_mux
->
p_access
,
p_sys
->
i_mdat_pos
+
i_size
+
bo_add_32be
(
stss
,
1
+
i
);
i_moov_size
-
i_chunk
);
i_index
++
;
sout_AccessOutWrite
(
p_mux
->
p_access
,
p_buf
);
i_size
-=
i_chunk
;
}
}
}
if
(
stss
)
{
bo_fix_32be
(
stss
,
12
,
i_index
);
box_fix
(
stss
);
}
if
(
!
p_sys
->
b_fast_start
)
break
;
/* Now gather all boxes into stbl */
box_gather
(
stbl
,
stsd
);
box_gather
(
stbl
,
stts
);
if
(
stss
)
{
box_gather
(
stbl
,
stss
);
}
box_gather
(
stbl
,
stsc
);
box_gather
(
stbl
,
stsz
);
p_stream
->
i_stco_pos
=
stbl
->
i_buffer
+
16
;
box_gather
(
stbl
,
stco
);
/* Fix-up samples to chunks table in MOOV header */
/* finish stbl */
for
(
i_trak
=
0
;
i_trak
<
p_sys
->
i_nb_streams
;
i_trak
++
)
box_fix
(
stbl
);
{
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
;
return
stbl
;
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
)
static
int64_t
get_timestamp
();
{
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
++
;
static
uint32_t
mvhd_matrix
[
9
]
=
}
{
0x10000
,
0
,
0
,
0
,
0x10000
,
0
,
0
,
0
,
0x40000000
};
}
}
moov
->
i_buffer
=
i_moov_size
;
static
bo_t
*
GetMoovBox
(
sout_mux_t
*
p_mux
)
i_moov_pos
=
p_sys
->
i_mdat_pos
;
{
p_sys
->
b_fast_start
=
VLC_FALSE
;
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
}
/* Write MOOV header */
bo_t
*
moov
,
*
mvhd
;
sout_AccessOutSeek
(
p_mux
->
p_access
,
i_moov_pos
);
int
i_trak
,
i
;
box_send
(
p_mux
,
moov
);
/* Clean-up */
uint32_t
i_movie_timescale
=
90000
;
int64_t
i_movie_duration
=
0
;
moov
=
box_new
(
"moov"
);
/* Create general info */
for
(
i_trak
=
0
;
i_trak
<
p_sys
->
i_nb_streams
;
i_trak
++
)
for
(
i_trak
=
0
;
i_trak
<
p_sys
->
i_nb_streams
;
i_trak
++
)
{
{
mp4_stream_t
*
p_stream
=
p_sys
->
pp_streams
[
i_trak
];
mp4_stream_t
*
p_stream
=
p_sys
->
pp_streams
[
i_trak
];
i_movie_duration
=
__MAX
(
i_movie_duration
,
p_stream
->
i_duration
);
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
);
msg_Dbg
(
p_mux
,
"movie duration %ds"
,
free
(
p_sys
);
(
uint32_t
)(
i_movie_duration
/
(
mtime_t
)
1000000
)
);
}
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
)
i_movie_duration
=
i_movie_duration
*
i_movie_timescale
/
1000000
;
{
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
mp4_stream_t
*
p_stream
;
switch
(
p_input
->
p_fmt
->
i_codec
)
/* *** add /moov/mvhd *** */
if
(
!
p_sys
->
b_64_ext
)
{
{
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
):
mvhd
=
box_full_new
(
"mvhd"
,
0
,
0
);
case
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
):
bo_add_32be
(
mvhd
,
get_timestamp
()
);
// creation time
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
):
bo_add_32be
(
mvhd
,
get_timestamp
()
);
// modification time
case
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
):
bo_add_32be
(
mvhd
,
i_movie_timescale
);
// timescale
case
VLC_FOURCC
(
'M'
,
'J'
,
'P'
,
'G'
):
bo_add_32be
(
mvhd
,
i_movie_duration
);
// duration
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
;
}
}
else
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
=
mvhd
=
box_full_new
(
"mvhd"
,
1
,
0
);
malloc
(
p_stream
->
p_fmt
->
i_extra
);
bo_add_64be
(
mvhd
,
get_timestamp
()
);
// creation time
memcpy
(
p_stream
->
p_fmt
->
p_extra
,
bo_add_64be
(
mvhd
,
get_timestamp
()
);
// modification time
p_input
->
p_fmt
->
p_extra
,
bo_add_32be
(
mvhd
,
i_movie_timescale
);
// timescale
p_input
->
p_fmt
->
i_extra
);
bo_add_64be
(
mvhd
,
i_movie_duration
);
// duration
}
bo_add_32be
(
mvhd
,
0x10000
);
// rate
bo_add_16be
(
mvhd
,
0x100
);
// volume
bo_add_16be
(
mvhd
,
0
);
// reserved
for
(
i
=
0
;
i
<
2
;
i
++
)
{
bo_add_32be
(
mvhd
,
0
);
// reserved
}
for
(
i
=
0
;
i
<
9
;
i
++
)
{
bo_add_32be
(
mvhd
,
mvhd_matrix
[
i
]
);
// matrix
}
for
(
i
=
0
;
i
<
6
;
i
++
)
{
bo_add_32be
(
mvhd
,
0
);
// pre-defined
}
}
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
;
/* Next available track id */
bo_add_32be
(
mvhd
,
p_sys
->
i_nb_streams
+
1
);
// next-track-id
msg_Dbg
(
p_mux
,
"adding input"
);
box_fix
(
mvhd
);
box_gather
(
moov
,
mvhd
);
TAB_APPEND
(
p_sys
->
i_nb_streams
,
p_sys
->
pp_streams
,
p_stream
);
for
(
i_trak
=
0
;
i_trak
<
p_sys
->
i_nb_streams
;
i_trak
++
)
return
VLC_SUCCESS
;
{
}
mp4_stream_t
*
p_stream
;
uint32_t
i_timescale
;
static
int
DelStream
(
sout_mux_t
*
p_mux
,
sout_input_t
*
p_input
)
bo_t
*
trak
,
*
tkhd
,
*
edts
,
*
elst
,
*
mdia
,
*
mdhd
,
*
hdlr
;
{
bo_t
*
minf
,
*
dinf
,
*
dref
,
*
url
,
*
stbl
;
msg_Dbg
(
p_mux
,
"removing input"
);
return
VLC_SUCCESS
;
}
/****************************************************************************/
p_stream
=
p_sys
->
pp_streams
[
i_trak
];
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
->
fmt
.
i_cat
==
AUDIO_ES
)
i_timescale
=
p_stream
->
fmt
.
audio
.
i_rate
;
else
i_timescale
=
1001
;
/* *** add /moov/trak *** */
trak
=
box_new
(
"trak"
);
/* *** add /moov/trak/tkhd *** */
if
(
!
p_sys
->
b_64_ext
)
{
if
(
p_sys
->
b_mov
)
tkhd
=
box_full_new
(
"tkhd"
,
0
,
0x0f
);
else
tkhd
=
box_full_new
(
"tkhd"
,
0
,
1
);
static
int
MuxGetStream
(
sout_mux_t
*
p_mux
,
int
*
pi_stream
,
mtime_t
*
pi_dts
)
bo_add_32be
(
tkhd
,
get_timestamp
()
);
// creation time
{
bo_add_32be
(
tkhd
,
get_timestamp
()
);
// modification time
mtime_t
i_dts
;
bo_add_32be
(
tkhd
,
p_stream
->
i_track_id
);
int
i_stream
;
bo_add_32be
(
tkhd
,
0
);
// reserved 0
int
i
;
bo_add_32be
(
tkhd
,
p_stream
->
i_duration
*
(
int64_t
)
i_movie_timescale
/
(
mtime_t
)
1000000
);
// duration
}
else
{
if
(
p_sys
->
b_mov
)
tkhd
=
box_full_new
(
"tkhd"
,
1
,
0x0f
);
else
tkhd
=
box_full_new
(
"tkhd"
,
1
,
1
);
for
(
i
=
0
,
i_dts
=
0
,
i_stream
=
-
1
;
i
<
p_mux
->
i_nb_inputs
;
i
++
)
bo_add_64be
(
tkhd
,
get_timestamp
()
);
// creation time
{
bo_add_64be
(
tkhd
,
get_timestamp
()
);
// modification time
sout_fifo_t
*
p_fifo
;
bo_add_32be
(
tkhd
,
p_stream
->
i_track_id
);
bo_add_32be
(
tkhd
,
0
);
// reserved 0
bo_add_64be
(
tkhd
,
p_stream
->
i_duration
*
(
int64_t
)
i_movie_timescale
/
(
mtime_t
)
1000000
);
// duration
}
p_fifo
=
p_mux
->
pp_inputs
[
i
]
->
p_fifo
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
bo_add_32be
(
tkhd
,
0
);
// reserved
}
bo_add_16be
(
tkhd
,
0
);
// layer
bo_add_16be
(
tkhd
,
0
);
// pre-defined
// volume
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
->
fmt
.
i_cat
==
AUDIO_ES
)
{
bo_add_32be
(
tkhd
,
0
);
// width (presentation)
bo_add_32be
(
tkhd
,
0
);
// height(presentation)
}
else
{
// width (presentation)
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
->
fmt
.
video
.
i_height
<<
16
);
}
box_fix
(
tkhd
);
box_gather
(
trak
,
tkhd
);
if
(
p_fifo
->
i_depth
>
1
)
/* *** 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
)
{
{
sout_buffer_t
*
p_buf
;
bo_add_32be
(
elst
,
2
)
;
p_buf
=
sout_FifoShow
(
p_fifo
);
if
(
p_sys
->
b_64_ext
)
if
(
i_stream
<
0
||
p_buf
->
i_dts
<
i_dts
)
{
{
i_dts
=
p_buf
->
i_dts
;
bo_add_64be
(
elst
,
(
p_stream
->
i_dts_start
-
p_sys
->
i_dts_start
)
*
i_movie_timescale
/
I64C
(
1000000
)
)
;
i_stream
=
i
;
bo_add_64be
(
elst
,
-
1
)
;
}
}
else
{
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
else
{
{
return
(
-
1
);
// wait that all fifo have at least 2 packets
bo_add_32be
(
elst
,
1
);
}
}
}
if
(
p_sys
->
b_64_ext
)
if
(
pi_stream
)
{
{
bo_add_64be
(
elst
,
p_stream
->
i_duration
*
i_movie_timescale
/
I64C
(
1000000
)
);
*
pi_stream
=
i_stream
;
bo_add_64be
(
elst
,
0
);
}
}
if
(
pi_dts
)
else
{
{
*
pi_dts
=
i_dts
;
bo_add_32be
(
elst
,
p_stream
->
i_duration
*
i_movie_timescale
/
I64C
(
1000000
)
);
}
bo_add_32be
(
elst
,
0
);
return
(
i_stream
);
}
}
bo_add_16be
(
elst
,
1
);
bo_add_16be
(
elst
,
0
);
static
int
Mux
(
sout_mux_t
*
p_mux
)
box_fix
(
elst
);
{
box_gather
(
edts
,
elst
);
sout_mux_sys_t
*
p_sys
=
p_mux
->
p_sys
;
box_fix
(
edts
);
box_gather
(
trak
,
edts
);
for
(
;;
)
/* *** add /moov/trak/mdia *** */
{
mdia
=
box_new
(
"mdia"
);
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
)
/* media header */
if
(
!
p_sys
->
b_64_ext
)
{
{
return
(
VLC_SUCCESS
);
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_sys
->
i_start_dts
)
if
(
p_stream
->
fmt
.
psz_language
)
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
);
char
*
psz
=
p_stream
->
fmt
.
psz_language
;
int64_t
i_diff
=
p_next
->
i_dts
-
p_data
->
i_dts
;
const
iso639_lang_t
*
pl
=
NULL
;
uint16_t
lang
=
0x0
;
if
(
i_diff
<
I64C
(
1000000
)
)
/* protection */
if
(
strlen
(
psz
)
==
2
)
{
{
p_data
->
i_length
=
i_diff
;
pl
=
GetLang_1
(
psz
);
}
else
if
(
strlen
(
psz
)
==
3
)
{
pl
=
GetLang_2B
(
psz
);
if
(
!
strcmp
(
pl
->
psz_iso639_1
,
"??"
)
)
{
pl
=
GetLang_2T
(
psz
);
}
}
if
(
pl
&&
strcmp
(
pl
->
psz_iso639_1
,
"??"
)
)
{
lang
=
(
(
pl
->
psz_iso639_2T
[
0
]
-
0x60
)
<<
10
)
|
(
(
pl
->
psz_iso639_2T
[
1
]
-
0x60
)
<<
5
)
|
(
(
pl
->
psz_iso639_2T
[
2
]
-
0x60
)
);
}
}
bo_add_16be
(
mdhd
,
lang
);
// language
}
}
if
(
p_data
->
i_length
<=
0
)
else
{
{
msg_Warn
(
p_mux
,
"i_length <= 0"
);
bo_add_16be
(
mdhd
,
0
);
// language
p_stream
->
i_length_neg
+=
p_data
->
i_length
-
1
;
p_data
->
i_length
=
1
;
}
}
else
if
(
p_stream
->
i_length_neg
<
0
)
bo_add_16be
(
mdhd
,
0
);
// predefined
{
box_fix
(
mdhd
);
int64_t
i_recover
=
__MIN
(
p_data
->
i_length
/
4
,
-
p_stream
->
i_length_neg
);
box_gather
(
mdia
,
mdhd
);
p_data
->
i_length
-=
i_recover
;
/* handler reference */
p_stream
->
i_length_neg
+=
i_recover
;
hdlr
=
box_full_new
(
"hdlr"
,
0
,
0
);
bo_add_fourcc
(
hdlr
,
"mhlr"
);
// media handler
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
{
bo_add_fourcc
(
hdlr
,
"soun"
);
}
else
{
bo_add_fourcc
(
hdlr
,
"vide"
);
}
}
/* add index entry */
bo_add_32be
(
hdlr
,
0
);
// reserved
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_pos
=
p_sys
->
i_pos
;
bo_add_32be
(
hdlr
,
0
);
// reserved
p_stream
->
entry
[
p_stream
->
i_entry_count
].
i_size
=
p_data
->
i_size
;
bo_add_32be
(
hdlr
,
0
);
// reserved
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
)
bo_add_8
(
hdlr
,
12
);
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
bo_add_mem
(
hdlr
,
12
,
"SoundHandler"
);
else
bo_add_mem
(
hdlr
,
12
,
"VideoHandler"
);
box_fix
(
hdlr
);
box_gather
(
mdia
,
hdlr
);
/* minf*/
minf
=
box_new
(
"minf"
);
/* add smhd|vmhd */
if
(
p_stream
->
fmt
.
i_cat
==
AUDIO_ES
)
{
{
/* Here is another bad hack.
bo_t
*
smhd
;
* 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
++
;
smhd
=
box_full_new
(
"smhd"
,
0
,
0
);
if
(
p_stream
->
i_entry_count
>=
p_stream
->
i_entry_max
)
bo_add_16be
(
smhd
,
0
);
// balance
bo_add_16be
(
smhd
,
0
);
// reserved
box_fix
(
smhd
);
box_gather
(
minf
,
smhd
);
}
else
if
(
p_stream
->
fmt
.
i_cat
==
VIDEO_ES
)
{
{
p_stream
->
i_entry_max
+=
1000
;
bo_t
*
vmhd
;
p_stream
->
entry
=
realloc
(
p_stream
->
entry
,
vmhd
=
box_full_new
(
"vmhd"
,
0
,
1
);
p_stream
->
i_entry_max
*
sizeof
(
mp4_entry_t
)
);
bo_add_16be
(
vmhd
,
0
);
// graphicsmode
for
(
i
=
0
;
i
<
3
;
i
++
)
{
bo_add_16be
(
vmhd
,
0
);
// opcolor
}
box_fix
(
vmhd
);
box_gather
(
minf
,
vmhd
);
}
}
/* update */
/* dinf */
p_stream
->
i_duration
+=
p_data
->
i_length
;
dinf
=
box_new
(
"dinf"
);
p_sys
->
i_pos
+=
p_data
->
i_size
;
dref
=
box_full_new
(
"dref"
,
0
,
0
);
bo_add_32be
(
dref
,
1
);
url
=
box_full_new
(
"url "
,
0
,
0x01
);
box_fix
(
url
);
box_gather
(
dref
,
url
);
box_fix
(
dref
);
box_gather
(
dinf
,
dref
);
/* write data */
/* append dinf to mdia */
sout_AccessOutWrite
(
p_mux
->
p_access
,
p_data
);
box_fix
(
dinf
);
box_gather
(
minf
,
dinf
);
/* add stbl */
stbl
=
GetStblBox
(
p_mux
,
p_stream
);
/* append stbl to minf */
p_stream
->
i_stco_pos
+=
minf
->
i_buffer
;
box_gather
(
minf
,
stbl
);
/* append minf to mdia */
box_fix
(
minf
);
p_stream
->
i_stco_pos
+=
mdia
->
i_buffer
;
box_gather
(
mdia
,
minf
);
/* append mdia to trak */
box_fix
(
mdia
);
p_stream
->
i_stco_pos
+=
trak
->
i_buffer
;
box_gather
(
trak
,
mdia
);
/* append trak to moov */
box_fix
(
trak
);
p_stream
->
i_stco_pos
+=
moov
->
i_buffer
;
box_gather
(
moov
,
trak
);
}
}
return
(
VLC_SUCCESS
);
/* Add user data tags */
box_gather
(
moov
,
GetUdtaTag
(
p_mux
)
);
box_fix
(
moov
);
return
moov
;
}
}
/****************************************************************************/
/****************************************************************************/
static
void
bo_init
(
bo_t
*
p_bo
,
int
i_size
,
uint8_t
*
p_buffer
,
static
void
bo_init
(
bo_t
*
p_bo
,
int
i_size
,
uint8_t
*
p_buffer
,
...
...
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