vlc_module_begin();
set_description( _("MP4/MOV muxer") );
+ set_category( CAT_SOUT );
+ set_subcategory( SUBCAT_SOUT_MUX );
+ set_shortname( "MP4" );
add_bool( SOUT_CFG_PREFIX "faststart", 1, NULL, FASTSTART_TEXT, FASTSTART_LONGTEXT,
VLC_TRUE );
set_capability( "sout mux", 5 );
add_shortcut( "mp4" );
add_shortcut( "mov" );
+ add_shortcut( "3gp" );
set_callbacks( Open, Close );
vlc_module_end();
"faststart", NULL
};
-static int Capability(sout_mux_t *, int, void *, void * );
+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 * );
struct sout_mux_sys_t
{
vlc_bool_t b_mov;
+ vlc_bool_t b_3gp;
vlc_bool_t b_64_ext;
vlc_bool_t b_fast_start;
bo_t *box;
msg_Dbg( p_mux, "Mp4 muxer opend" );
- sout_ParseCfg( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
+ sout_CfgParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
- p_mux->pf_capacity = Capability;
+ p_mux->pf_control = Control;
p_mux->pf_addstream = AddStream;
p_mux->pf_delstream = DelStream;
p_mux->pf_mux = Mux;
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->i_dts_start = 0;
{
/* Now add ftyp header */
box = box_new( "ftyp" );
- bo_add_fourcc( box, "isom" );
+ if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
+ else bo_add_fourcc( box, "isom" );
bo_add_32be ( box, 0 );
- bo_add_fourcc( box, "mp41" );
+ if( p_sys->b_3gp ) bo_add_fourcc( box, "3gp4" );
+ else bo_add_fourcc( box, "mp41" );
box_fix( box );
p_sys->i_pos += box->i_buffer;
}
/*****************************************************************************
- * Capability:
+ * Control:
*****************************************************************************/
-static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
- void *p_answer )
+static int Control( sout_mux_t *p_mux, int i_query, va_list args )
{
+ vlc_bool_t *pb_bool;
+
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;
+ case MUX_CAN_ADD_STREAM_WHILE_MUXING:
+ pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
+ *pb_bool = VLC_FALSE;
+ return VLC_SUCCESS;
- case SOUT_MUX_CAP_GET_ADD_STREAM_WAIT:
- *(vlc_bool_t*)p_answer = VLC_TRUE;
- return( SOUT_MUX_CAP_ERR_OK );
+ case MUX_GET_ADD_STREAM_WAIT:
+ pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
+ *pb_bool = VLC_TRUE;
+ return VLC_SUCCESS;
+ case MUX_GET_MIME: /* Not needed, as not streamable */
default:
- return SOUT_MUX_CAP_ERR_UNIMPLEMENTED;
+ return VLC_EGENERIC;
}
}
last[2] = ( i_size >> 8 )&0xff;
last[3] = ( i_size )&0xff;
- if( last[4] == 7 && tk->avc.i_sps <= 0 ) /* SPS */
+ if( (last[4]&0x1f) == 7 && tk->avc.i_sps <= 0 ) /* SPS */
{
tk->avc.i_sps = i_size;
tk->avc.sps = malloc( i_size );
tk->avc.i_profile = tk->avc.sps[1];
tk->avc.i_level = tk->avc.sps[3];
}
- else if( last[4] == 8 && tk->avc.i_pps <= 0 ) /* PPS */
+ else if( (last[4]&0x1f) == 8 && tk->avc.i_pps <= 0 ) /* PPS */
{
tk->avc.i_pps = i_size;
tk->avc.pps = malloc( i_size );
int i_stream_type;
int i_object_type_indication;
int i_decoder_specific_info_size;
+ unsigned int i;
+ int64_t i_bitrate_avg = 0;
+ int64_t i_bitrate_max = 0;
+ /* Compute avg/max bitrate */
+ for( i = 0; i < p_stream->i_entry_count; i++ )
+ {
+ i_bitrate_avg += p_stream->entry[i].i_size;
+ if( p_stream->entry[i].i_length > 0)
+ {
+ int64_t i_bitrate = I64C(8000000) * p_stream->entry[i].i_size / p_stream->entry[i].i_length;
+ if( i_bitrate > i_bitrate_max )
+ i_bitrate_max = i_bitrate;
+ }
+ }
+
+ if( p_stream->i_duration > 0 )
+ i_bitrate_avg = I64C(8000000) * i_bitrate_avg / p_stream->i_duration;
+ else
+ i_bitrate_avg = 0;
+ if( i_bitrate_max <= 1 )
+ i_bitrate_max = 0x7fffffff;
+
+ /* */
if( p_stream->fmt.i_extra > 0 )
{
i_decoder_specific_info_size =
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
+ bo_add_32be( esds, i_bitrate_max ); // maxBitrate
+ bo_add_32be( esds, i_bitrate_avg ); // avgBitrate
if( p_stream->fmt.i_extra > 0 )
{
}
else if( p_stream->fmt.i_cat == VIDEO_ES )
{
- int i_width = p_stream->fmt.video.i_width;
+ int i_width = p_stream->fmt.video.i_width << 16;
if( p_stream->fmt.video.i_aspect > 0 )
{
- i_width = p_stream->fmt.video.i_aspect *
- p_stream->fmt.video.i_height /
- VOUT_ASPECT_FACTOR << 16;
+ i_width = (int64_t)p_stream->fmt.video.i_aspect *
+ ((int64_t)p_stream->fmt.video.i_height << 16) /
+ VOUT_ASPECT_FACTOR;
}
// width (presentation)
bo_add_32be( tkhd, i_width );
}
else
{
- int i_width = 320;
+ int i_width = 320 << 16;
int i_height = 200;
int i;
for( i = 0; i < p_sys->i_nb_streams; i++ )
if( tk->fmt.i_cat == VIDEO_ES )
{
if( p_stream->fmt.video.i_aspect )
- i_width = p_stream->fmt.video.i_aspect *
- p_stream->fmt.video.i_height / VOUT_ASPECT_FACTOR;
+ i_width = (int64_t)p_stream->fmt.video.i_aspect *
+ ((int64_t)p_stream->fmt.video.i_height<<16) / VOUT_ASPECT_FACTOR;
else
- i_width = p_stream->fmt.video.i_width;
+ i_width = p_stream->fmt.video.i_width << 16;
i_height = p_stream->fmt.video.i_height;
break;
}
}
- bo_add_32be( tkhd, i_width << 16 ); // width (presentation)
+ bo_add_32be( tkhd, i_width ); // width (presentation)
bo_add_32be( tkhd, i_height << 16 ); // height(presentation)
}
/* handler reference */
hdlr = box_full_new( "hdlr", 0, 0 );
- bo_add_fourcc( hdlr, "mhlr" ); // media handler
+ if( p_sys->b_mov )
+ bo_add_fourcc( hdlr, "mhlr" ); // media handler
+ else
+ bo_add_32be( hdlr, 0 );
+
if( p_stream->fmt.i_cat == AUDIO_ES )
- {
bo_add_fourcc( hdlr, "soun" );
- }
else if( p_stream->fmt.i_cat == VIDEO_ES )
- {
bo_add_fourcc( hdlr, "vide" );
- }
else if( p_stream->fmt.i_cat == SPU_ES )
- {
bo_add_fourcc( hdlr, "text" );
- }
bo_add_32be( hdlr, 0 ); // reserved
bo_add_32be( hdlr, 0 ); // reserved
bo_add_32be( hdlr, 0 ); // reserved
- bo_add_8( hdlr, 12 );
+ if( p_sys->b_mov )
+ bo_add_8( hdlr, 12 ); /* Pascal string for .mov */
+
if( p_stream->fmt.i_cat == AUDIO_ES )
bo_add_mem( hdlr, 12, "SoundHandler" );
else if( p_stream->fmt.i_cat == VIDEO_ES )
else
bo_add_mem( hdlr, 12, "Text Handler" );
+ if( !p_sys->b_mov )
+ bo_add_8( hdlr, 0 ); /* asciiz string for .mp4, yes that's BRAIN DAMAGED F**K MP4 */
+
box_fix( hdlr );
box_gather( mdia, hdlr );