Commit e7042bde authored by Rafaël Carré's avatar Rafaël Carré
Browse files

mp4 mux: cosmetics

no functional changes
parent a06942a1
......@@ -44,28 +44,28 @@
* Module descriptor
*****************************************************************************/
#define FASTSTART_TEXT N_("Create \"Fast Start\" files")
#define FASTSTART_LONGTEXT N_( \
#define FASTSTART_LONGTEXT N_(\
"Create \"Fast Start\" files. " \
"\"Fast Start\" files are optimized for downloads and allow the user " \
"to start previewing the file while it is downloading.")
static int Open ( vlc_object_t * );
static void Close ( vlc_object_t * );
static int Open (vlc_object_t *);
static void Close (vlc_object_t *);
#define SOUT_CFG_PREFIX "sout-mp4-"
vlc_module_begin ()
set_description( N_("MP4/MOV muxer") )
set_category( CAT_SOUT )
set_subcategory( SUBCAT_SOUT_MUX )
set_shortname( "MP4" )
set_description(N_("MP4/MOV muxer"))
set_category(CAT_SOUT)
set_subcategory(SUBCAT_SOUT_MUX)
set_shortname("MP4")
add_bool( SOUT_CFG_PREFIX "faststart", true,
add_bool(SOUT_CFG_PREFIX "faststart", true,
FASTSTART_TEXT, FASTSTART_LONGTEXT,
true )
set_capability( "sout mux", 5 )
add_shortcut( "mp4", "mov", "3gp" )
set_callbacks( Open, Close )
true)
set_capability("sout mux", 5)
add_shortcut("mp4", "mov", "3gp")
set_callbacks(Open, Close)
vlc_module_end ()
/*****************************************************************************
......@@ -75,10 +75,10 @@ static const char *const ppsz_sout_options[] = {
"faststart", NULL
};
static int Control( sout_mux_t *, int, va_list );
static int AddStream( sout_mux_t *, sout_input_t * );
static int DelStream( sout_mux_t *, sout_input_t * );
static int Mux ( sout_mux_t * );
static int Control(sout_mux_t *, int, va_list);
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
......@@ -140,75 +140,78 @@ typedef struct bo_t
size_t len;
} bo_t;
static void bo_init ( bo_t * );
static void bo_add_8 ( bo_t *, uint8_t );
static void bo_add_16be ( bo_t *, uint16_t );
static void bo_add_24be ( bo_t *, uint32_t );
static void bo_add_32be ( bo_t *, uint32_t );
static void bo_add_64be ( bo_t *, uint64_t );
static void bo_add_fourcc(bo_t *, const char * );
static void bo_add_mem ( bo_t *, int , uint8_t * );
static void bo_add_descr( bo_t *, uint8_t , uint32_t );
static void bo_init (bo_t *);
static void bo_add_8 (bo_t *, uint8_t);
static void bo_add_16be (bo_t *, uint16_t);
static void bo_add_24be (bo_t *, uint32_t);
static void bo_add_32be (bo_t *, uint32_t);
static void bo_add_64be (bo_t *, uint64_t);
static void bo_add_fourcc(bo_t *, const char *);
static void bo_add_mem (bo_t *, int , uint8_t *);
static void bo_add_descr(bo_t *, uint8_t , uint32_t);
static void bo_fix_32be ( bo_t *, int , uint32_t );
static void bo_fix_32be (bo_t *, int , uint32_t);
static bo_t *box_new ( const char *fcc );
static bo_t *box_full_new( const char *fcc, uint8_t v, uint32_t f );
static void box_fix ( bo_t *box );
static void box_gather ( bo_t *box, bo_t *box2 );
static bo_t *box_new (const char *fcc);
static bo_t *box_full_new(const char *fcc, uint8_t v, uint32_t f);
static void box_fix (bo_t *box);
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 bo_t *GetMoovBox( sout_mux_t *p_mux );
static bo_t *GetMoovBox(sout_mux_t *p_mux);
static block_t *ConvertSUBT( block_t *);
static block_t *ConvertAVC1( block_t * );
static block_t *ConvertSUBT(block_t *);
static block_t *ConvertAVC1(block_t *);
/*****************************************************************************
* Open:
*****************************************************************************/
static int Open( vlc_object_t *p_this )
static int Open(vlc_object_t *p_this)
{
sout_mux_t *p_mux = (sout_mux_t*)p_this;
sout_mux_sys_t *p_sys;
bo_t *box;
msg_Dbg( p_mux, "Mp4 muxer opened" );
config_ChainParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
msg_Dbg(p_mux, "Mp4 muxer opened");
config_ChainParse(p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg);
p_mux->pf_control = Control;
p_mux->pf_addstream = AddStream;
p_mux->pf_delstream = DelStream;
p_mux->pf_mux = Mux;
p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
if( !p_sys )
p_mux->p_sys = p_sys = malloc(sizeof(sout_mux_sys_t));
if (!p_sys)
return VLC_ENOMEM;
p_sys->i_pos = 0;
p_sys->i_nb_streams = 0;
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->b_3gp = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "3gp" );
p_sys->b_mov = p_mux->psz_mux && !strcmp(p_mux->psz_mux, "mov");
p_sys->b_3gp = p_mux->psz_mux && !strcmp(p_mux->psz_mux, "3gp");
p_sys->i_dts_start = 0;
if( !p_sys->b_mov )
{
if (!p_sys->b_mov) {
/* Now add ftyp header */
box = box_new( "ftyp" );
if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp6" );
else bo_add_fourcc( box, "isom" );
bo_add_32be ( box, 0 );
if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
else bo_add_fourcc( box, "mp41" );
bo_add_fourcc( box, "avc1" );
bo_add_fourcc( box, "qt " );
box_fix( box );
box = box_new("ftyp");
if (p_sys->b_3gp)
bo_add_fourcc(box, "3gp6");
else
bo_add_fourcc(box, "isom");
bo_add_32be (box, 0);
if (p_sys->b_3gp)
bo_add_fourcc(box, "3gp4");
else
bo_add_fourcc(box, "mp41");
bo_add_fourcc(box, "avc1");
bo_add_fourcc(box, "qt ");
box_fix(box);
p_sys->i_pos += box->len;
p_sys->i_mdat_pos = p_sys->i_pos;
box_send( p_mux, box );
box_send(p_mux, box);
}
/* FIXME FIXME
......@@ -216,12 +219,12 @@ static int Open( vlc_object_t *p_this )
p_sys->b_64_ext = false;
/* Now add mdat header */
box = box_new( "mdat" );
bo_add_64be ( box, 0 ); // enough to store an extended size
box = box_new("mdat");
bo_add_64be (box, 0); // enough to store an extended size
p_sys->i_pos += box->len;
box_send( p_mux, box );
box_send(p_mux, box);
return VLC_SUCCESS;
}
......@@ -229,7 +232,7 @@ static int Open( vlc_object_t *p_this )
/*****************************************************************************
* Close:
*****************************************************************************/
static void Close( vlc_object_t * p_this )
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;
......@@ -237,91 +240,79 @@ static void Close( vlc_object_t * p_this )
bo_t bo, *moov;
vlc_value_t val;
int i_trak;
uint64_t i_moov_pos;
msg_Dbg( p_mux, "Close" );
msg_Dbg(p_mux, "Close");
/* Update mdat size */
bo_init( &bo );
if( p_sys->i_pos - p_sys->i_mdat_pos >= (((uint64_t)1)<<32) )
{
bo_init(&bo);
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" );
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.b;
p_hdr->i_buffer = bo.len;
sout_AccessOutSeek( p_mux->p_access, p_sys->i_mdat_pos );
sout_AccessOutWrite( p_mux->p_access, p_hdr );
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 );
moov = GetMoovBox(p_mux);
/* Check we need to create "fast start" files */
var_Get( p_this, SOUT_CFG_PREFIX "faststart", &val );
var_Get(p_this, SOUT_CFG_PREFIX "faststart", &val);
p_sys->b_fast_start = val.b_bool;
while( p_sys->b_fast_start )
{
while (p_sys->b_fast_start) {
/* Move data to the end of the file so we can fit the moov header
* at the start */
block_t *p_buf;
int64_t i_chunk, i_size = p_sys->i_pos - p_sys->i_mdat_pos;
int i_moov_size = moov->len;
while( i_size > 0 )
{
i_chunk = __MIN( 32768, i_size );
p_buf = block_Alloc( 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 access output, "
"won't create a fast start file" );
while (i_size > 0) {
i_chunk = __MIN(32768, i_size);
p_buf = block_Alloc(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 access output, "
"won't create a fast start file");
p_sys->b_fast_start = false;
block_Release( p_buf );
block_Release(p_buf);
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 );
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;
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++ )
{
for (int 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->len = 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);
for (unsigned i = 0; i < p_stream->i_entry_count; ) {
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);
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 &&
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 )
{
!= p_stream->entry[i + 1].i_pos) {
i++;
break;
}
......@@ -337,170 +328,157 @@ static void Close( vlc_object_t * p_this )
}
/* Write MOOV header */
sout_AccessOutSeek( p_mux->p_access, i_moov_pos );
box_send( p_mux, moov );
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++ )
{
for (int 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 );
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 );
if (p_sys->i_nb_streams)
free(p_sys->pp_streams);
free(p_sys);
}
/*****************************************************************************
* Control:
*****************************************************************************/
static int Control( sout_mux_t *p_mux, int i_query, va_list args )
static int Control(sout_mux_t *p_mux, int i_query, va_list args)
{
VLC_UNUSED(p_mux);
bool *pb_bool;
switch( i_query )
switch(i_query)
{
case MUX_CAN_ADD_STREAM_WHILE_MUXING:
pb_bool = (bool*)va_arg( args, bool * );
*pb_bool = false;
return VLC_SUCCESS;
case MUX_GET_ADD_STREAM_WAIT:
pb_bool = (bool*)va_arg( args, bool * );
*pb_bool = true;
return VLC_SUCCESS;
case MUX_GET_MIME: /* Not needed, as not streamable */
default:
return VLC_EGENERIC;
case MUX_CAN_ADD_STREAM_WHILE_MUXING:
pb_bool = (bool*)va_arg(args, bool *);
*pb_bool = false;
return VLC_SUCCESS;
case MUX_GET_ADD_STREAM_WAIT:
pb_bool = (bool*)va_arg(args, bool *);
*pb_bool = true;
return VLC_SUCCESS;
case MUX_GET_MIME: /* Not needed, as not streamable */
default:
return VLC_EGENERIC;
}
}
/*****************************************************************************
* AddStream:
*****************************************************************************/
static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
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 )
switch(p_input->p_fmt->i_codec)
{
case VLC_CODEC_MP4A:
case VLC_CODEC_MP4V:
case VLC_CODEC_MPGA:
case VLC_CODEC_MPGV:
case VLC_CODEC_MJPG:
case VLC_CODEC_MJPGB:
case VLC_CODEC_SVQ1:
case VLC_CODEC_SVQ3:
case VLC_CODEC_H263:
case VLC_CODEC_H264:
case VLC_CODEC_AMR_NB:
case VLC_CODEC_AMR_WB:
case VLC_CODEC_YV12:
case VLC_CODEC_YUYV:
break;
case VLC_CODEC_SUBT:
msg_Warn( p_mux, "subtitle track added like in .mov (even when creating .mp4)" );
break;
default:
msg_Err( p_mux, "unsupported codec %4.4s in mp4",
(char*)&p_input->p_fmt->i_codec );
return VLC_EGENERIC;
case VLC_CODEC_MP4A:
case VLC_CODEC_MP4V:
case VLC_CODEC_MPGA:
case VLC_CODEC_MPGV:
case VLC_CODEC_MJPG:
case VLC_CODEC_MJPGB:
case VLC_CODEC_SVQ1:
case VLC_CODEC_SVQ3:
case VLC_CODEC_H263:
case VLC_CODEC_H264:
case VLC_CODEC_AMR_NB:
case VLC_CODEC_AMR_WB:
case VLC_CODEC_YV12:
case VLC_CODEC_YUYV:
break;
case VLC_CODEC_SUBT:
msg_Warn(p_mux, "subtitle track added like in .mov (even when creating .mp4)");
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 ) );
if( !p_stream )
p_stream = malloc(sizeof(mp4_stream_t));
if (!p_stream)
return VLC_ENOMEM;
es_format_Copy( &p_stream->fmt, p_input->p_fmt );
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 ) );
calloc(p_stream->i_entry_max, sizeof(mp4_entry_t));
p_stream->i_dts_start = 0;
p_stream->i_duration = 0;
p_input->p_sys = p_stream;
msg_Dbg( p_mux, "adding input" );
msg_Dbg(p_mux, "adding input");
TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, p_stream );
TAB_APPEND(p_sys->i_nb_streams, p_sys->pp_streams, p_stream);
return VLC_SUCCESS;
}
/*****************************************************************************
* DelStream:
*****************************************************************************/
static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
static int DelStream(sout_mux_t *p_mux, sout_input_t *p_input)
{
VLC_UNUSED(p_input);
msg_Dbg( p_mux, "removing input" );
msg_Dbg(p_mux, "removing input");
return VLC_SUCCESS;
}
/*****************************************************************************
* Mux:
*****************************************************************************/
static int Mux( sout_mux_t *p_mux )
static int Mux(sout_mux_t *p_mux)
{
sout_mux_sys_t *p_sys = p_mux->p_sys;
for( ;; )
{
for (;;) {
sout_input_t *p_input;
mp4_stream_t *p_stream;
block_t *p_data;
mtime_t i_dts;
int i_stream = sout_MuxGetStream( p_mux, 2, &i_dts);
if( i_stream < 0 )
{
return( VLC_SUCCESS );
}
int i_stream = sout_MuxGetStream(p_mux, 2, &i_dts);
if (i_stream < 0)
return(VLC_SUCCESS);
p_input = p_mux->pp_inputs[i_stream];
p_stream = (mp4_stream_t*)p_input->p_sys;
again:
p_data = block_FifoGet( p_input->p_fifo );
if( p_stream->fmt.i_codec == VLC_CODEC_H264 )
{
p_data = ConvertAVC1( p_data );
}
else if( p_stream->fmt.i_codec == VLC_CODEC_SUBT )
{
p_data = ConvertSUBT( p_data );
}
if( p_data == NULL ) goto again;
if( p_stream->fmt.i_cat != SPU_ES )
{
p_data = block_FifoGet(p_input->p_fifo);
if (p_stream->fmt.i_codec == VLC_CODEC_H264)
p_data = ConvertAVC1(p_data);
else if (p_stream->fmt.i_codec == VLC_CODEC_SUBT)
p_data = ConvertSUBT(p_data);
if (p_data == NULL)
goto again;
if (p_stream->fmt.i_cat != SPU_ES) {
/* Fix length of the sample */
if( block_FifoCount( p_input->p_fifo ) > 0 )
{
block_t *p_next = block_FifoShow( p_input->p_fifo );
if (block_FifoCount(p_input->p_fifo) > 0) {
block_t *p_next = block_FifoShow(p_input->p_fifo);
int64_t i_diff = p_next->i_dts - p_data->i_dts;
if( i_diff < INT64_C(1000000 ) ) /* protection */
{
if (i_diff < INT64_C(1000000)) /* protection */
p_data->i_length = i_diff;
}
}
if( p_data->i_length <= 0 )
{
msg_Warn( p_mux, "i_length <= 0" );
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 );
} 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;
......@@ -508,33 +486,23 @@ again:
}
/* Save starting time */
if( p_stream->i_entry_count == 0 )
{
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 )
{
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;
}
}
if( p_stream->fmt.i_cat == SPU_ES && p_stream->i_entry_count > 0 )
{
if (p_stream->fmt.i_cat == SPU_ES && p_stream->i_entry_count > 0) {
int64_t i_length = p_data->i_dts - p_stream->i_last_dts;
if( i_length <= 0 )
{
/* FIXME handle this broken case */
if (i_length <= 0) /* FIXME handle this broken case */
i_length = 1;
}
/* Fix last entry */
if( p_stream->entry[p_stream->i_entry_count-1].i_length <= 0 )
{
if (p_stream->entry[p_stream->i_entry_count-1].i_length <= 0)
p_stream->entry[p_stream->i_entry_count-1].i_length = i_length;
}
}
......@@ -542,17 +510,16 @@ again:
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_buffer;
p_stream->entry[p_stream->i_entry_count].i_pts_dts=