X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fmux%2Fasf.c;h=332cae87b4475b881b876a7baeae41b543b165d1;hb=6f3cc15c000a11b6c539ee8a77b428fcbec438b4;hp=8ec9a726d572c48e968171eb417809cd9a8a1712;hpb=d3fe7f28797d4dba65ffcdd60bf932e758a48a9e;p=vlc diff --git a/modules/mux/asf.c b/modules/mux/asf.c index 8ec9a726d5..332cae87b4 100644 --- a/modules/mux/asf.c +++ b/modules/mux/asf.c @@ -25,9 +25,13 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include #include #include #include @@ -57,36 +61,42 @@ static void Close ( vlc_object_t * ); #define RATING_LONGTEXT N_("\"Rating\" to put in ASF comments." ) #define PACKETSIZE_TEXT N_("Packet Size") #define PACKETSIZE_LONGTEXT N_("ASF packet size -- default is 4096 bytes") +#define BITRATE_TEXT N_("Bitrate override") +#define BITRATE_LONGTEXT N_("Do not try to guess ASF bitrate. Setting this, allows you to control how Windows Media Player will cache streamed content. Set to audio+video bitrate in bytes") -vlc_module_begin(); - set_description( _("ASF muxer") ); - set_category( CAT_SOUT ); - set_subcategory( SUBCAT_SOUT_MUX ); - set_shortname( "ASF" ); - set_capability( "sout mux", 5 ); - add_shortcut( "asf" ); - add_shortcut( "asfh" ); - set_callbacks( Open, Close ); +vlc_module_begin () + set_description( N_("ASF muxer") ) + set_category( CAT_SOUT ) + set_subcategory( SUBCAT_SOUT_MUX ) + set_shortname( "ASF" ) + + set_capability( "sout mux", 5 ) + add_shortcut( "asf" ) + add_shortcut( "asfh" ) + set_callbacks( Open, Close ) add_string( SOUT_CFG_PREFIX "title", "", NULL, TITLE_TEXT, TITLE_LONGTEXT, - VLC_TRUE ); + true ) add_string( SOUT_CFG_PREFIX "author", "", NULL, AUTHOR_TEXT, - AUTHOR_LONGTEXT, VLC_TRUE ); + AUTHOR_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "copyright","", NULL, COPYRIGHT_TEXT, - COPYRIGHT_LONGTEXT, VLC_TRUE ); + COPYRIGHT_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "comment", "", NULL, COMMENT_TEXT, - COMMENT_LONGTEXT, VLC_TRUE ); + COMMENT_LONGTEXT, true ) add_string( SOUT_CFG_PREFIX "rating", "", NULL, RATING_TEXT, - RATING_LONGTEXT, VLC_TRUE ); - add_integer( "sout-asf-packet-size", 4096, NULL, PACKETSIZE_TEXT, PACKETSIZE_LONGTEXT, VLC_TRUE ); + RATING_LONGTEXT, true ) + add_integer( SOUT_CFG_PREFIX "packet-size", 4096, NULL, PACKETSIZE_TEXT, + PACKETSIZE_LONGTEXT, true ) + add_integer( SOUT_CFG_PREFIX "bitrate-override", 0, NULL, BITRATE_TEXT, + BITRATE_LONGTEXT, true ) -vlc_module_end(); +vlc_module_end () /***************************************************************************** * Locales prototypes *****************************************************************************/ -static const char *ppsz_sout_options[] = { +static const char *const ppsz_sout_options[] = { "title", "author", "copyright", "comment", "rating", NULL }; @@ -103,14 +113,15 @@ typedef struct /* codec information */ uint16_t i_tag; /* for audio */ vlc_fourcc_t i_fourcc; /* for video */ - char *psz_name; /* codec name */ + const char *psz_name; /* codec name */ int i_blockalign; /* for audio only */ - vlc_bool_t b_audio_correction; + bool b_audio_correction; int i_sequence; int i_extra; uint8_t *p_extra; + bool b_extended; es_format_t fmt; @@ -125,18 +136,19 @@ struct sout_mux_sys_t mtime_t i_dts_last; mtime_t i_preroll_time; int64_t i_bitrate; + int64_t i_bitrate_override; int i_track; asf_track_t track[MAX_ASF_TRACKS]; - vlc_bool_t b_write_header; + bool b_write_header; block_t *pk; int i_pk_used; int i_pk_frame; mtime_t i_pk_dts; - vlc_bool_t b_asf_http; + bool b_asf_http; int i_seq; /* meta data */ @@ -149,7 +161,7 @@ struct sout_mux_sys_t static int MuxGetStream( sout_mux_t *, int *pi_stream, mtime_t *pi_dts ); -static block_t *asf_header_create( sout_mux_t *, vlc_bool_t ); +static block_t *asf_header_create( sout_mux_t *, bool ); static block_t *asf_packet_create( sout_mux_t *, asf_track_t *, block_t * ); static block_t *asf_stream_end_create( sout_mux_t *); static block_t *asf_packet_flush( sout_mux_t * ); @@ -169,7 +181,7 @@ static void bo_addle_u32( bo_t *, uint32_t ); static void bo_addle_u64( bo_t *, uint64_t ); static void bo_add_mem ( bo_t *, uint8_t *, int ); -static void bo_addle_str16( bo_t *, char * ); +static void bo_addle_str16( bo_t *, const char * ); /***************************************************************************** * Open: @@ -190,6 +202,8 @@ static int Open( vlc_object_t *p_this ) p_mux->pf_mux = Mux; p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) ); + if( !p_sys ) + return VLC_ENOMEM; p_sys->b_asf_http = p_mux->psz_mux && !strcmp( p_mux->psz_mux, "asfh" ); if( p_sys->b_asf_http ) { @@ -202,12 +216,16 @@ static int Open( vlc_object_t *p_this ) p_sys->i_dts_last = 0; p_sys->i_preroll_time = 2000; p_sys->i_bitrate = 0; + p_sys->i_bitrate_override = 0; p_sys->i_seq = 0; - p_sys->b_write_header = VLC_TRUE; + p_sys->b_write_header = true; p_sys->i_track = 0; p_sys->i_packet_size = config_GetInt( p_mux, "sout-asf-packet-size" ); + p_sys->i_bitrate_override = config_GetInt( p_mux, "sout-asf-bitrate-override" ); msg_Dbg( p_mux, "Packet size %d", p_sys->i_packet_size); + if (p_sys->i_bitrate_override) + msg_Dbg( p_mux, "Bitrate override %"PRId64, p_sys->i_bitrate_override); p_sys->i_packet_count= 0; /* Generate a random fid */ @@ -268,9 +286,9 @@ static void Close( vlc_object_t * p_this ) } /* rewrite header */ - if( !sout_AccessOutSeek( p_mux->p_access, 0 ) ) + if( sout_AccessOutSeek( p_mux->p_access, 0 ) == VLC_SUCCESS ) { - out = asf_header_create( p_mux, VLC_FALSE ); + out = asf_header_create( p_mux, false ); sout_AccessOutWrite( p_mux->p_access, out ); } @@ -279,6 +297,12 @@ static void Close( vlc_object_t * p_this ) free( p_sys->track[i].p_extra ); es_format_Clean( &p_sys->track[i].fmt ); } + + free( p_sys->psz_title ); + free( p_sys->psz_author ); + free( p_sys->psz_copyright ); + free( p_sys->psz_comment ); + free( p_sys->psz_rating ); free( p_sys ); } @@ -288,20 +312,20 @@ static void Close( vlc_object_t * p_this ) static int Control( sout_mux_t *p_mux, int i_query, va_list args ) { sout_mux_sys_t *p_sys = p_mux->p_sys; - vlc_bool_t *pb_bool; + bool *pb_bool; char **ppsz; switch( i_query ) { case MUX_CAN_ADD_STREAM_WHILE_MUXING: - pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * ); - if( p_sys->b_asf_http ) *pb_bool = VLC_TRUE; - else *pb_bool = VLC_FALSE; + pb_bool = (bool*)va_arg( args, bool * ); + if( p_sys->b_asf_http ) *pb_bool = true; + else *pb_bool = false; return VLC_SUCCESS; case MUX_GET_ADD_STREAM_WAIT: - pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * ); - *pb_bool = VLC_TRUE; + pb_bool = (bool*)va_arg( args, bool * ); + *pb_bool = true; return VLC_SUCCESS; case MUX_GET_MIME: @@ -338,6 +362,7 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) tk->i_cat = p_input->p_fmt->i_cat; tk->i_sequence = 0; tk->b_audio_correction = 0; + tk->b_extended = false; switch( tk->i_cat ) { @@ -378,23 +403,23 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) case VLC_FOURCC( 'w', 'm', 'a', '1' ): tk->psz_name = "Windows Media Audio v1"; tk->i_tag = WAVE_FORMAT_WMA1; - tk->b_audio_correction = VLC_TRUE; + tk->b_audio_correction = true; break; case VLC_FOURCC( 'w', 'm', 'a', ' ' ): case VLC_FOURCC( 'w', 'm', 'a', '2' ): tk->psz_name= "Windows Media Audio (v2) 7, 8 and 9 Series"; tk->i_tag = WAVE_FORMAT_WMA2; - tk->b_audio_correction = VLC_TRUE; + tk->b_audio_correction = true; break; case VLC_FOURCC( 'w', 'm', 'a', 'p' ): tk->psz_name = "Windows Media Audio 9 Professional"; tk->i_tag = WAVE_FORMAT_WMAP; - tk->b_audio_correction = VLC_TRUE; + tk->b_audio_correction = true; break; case VLC_FOURCC( 'w', 'm', 'a', 'l' ): tk->psz_name = "Windows Media Audio 9 Lossless"; tk->i_tag = WAVE_FORMAT_WMAL; - tk->b_audio_correction = VLC_TRUE; + tk->b_audio_correction = true; break; /* raw codec */ case VLC_FOURCC( 'u', '8', ' ', ' ' ): @@ -428,6 +453,8 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) tk->i_extra = sizeof( WAVEFORMATEX ) + p_input->p_fmt->i_extra + i_extra; tk->p_extra = malloc( tk->i_extra ); + if( !tk->p_extra ) + return VLC_ENOMEM; bo_init( &bo, tk->p_extra, tk->i_extra ); bo_addle_u16( &bo, tk->i_tag ); bo_addle_u16( &bo, p_input->p_fmt->audio.i_channels ); @@ -474,27 +501,18 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) } else { - p_sys->i_bitrate += 512000; + p_sys->i_bitrate += 128000; } + if (p_sys->i_bitrate_override) + p_sys->i_bitrate = p_sys->i_bitrate_override; break; } case VIDEO_ES: { - tk->i_extra = 11 + sizeof( BITMAPINFOHEADER ) + - p_input->p_fmt->i_extra; - tk->p_extra = malloc( tk->i_extra ); - bo_init( &bo, tk->p_extra, tk->i_extra ); - bo_addle_u32( &bo, p_input->p_fmt->video.i_width ); - bo_addle_u32( &bo, p_input->p_fmt->video.i_height ); - bo_add_u8 ( &bo, 0x02 ); /* flags */ - bo_addle_u16( &bo, sizeof( BITMAPINFOHEADER ) + - p_input->p_fmt->i_extra ); - bo_addle_u32( &bo, sizeof( BITMAPINFOHEADER ) + - p_input->p_fmt->i_extra ); - bo_addle_u32( &bo, p_input->p_fmt->video.i_width ); - bo_addle_u32( &bo, p_input->p_fmt->video.i_height ); - bo_addle_u16( &bo, 1 ); - bo_addle_u16( &bo, 24 ); + const es_format_t *p_fmt = p_input->p_fmt; + uint8_t *p_codec_extra = NULL; + int i_codec_extra = 0; + if( p_input->p_fmt->i_codec == VLC_FOURCC('m','p','4','v') ) { tk->psz_name = "MPEG-4 Video"; @@ -530,6 +548,23 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) tk->psz_name = "Windows Media Video 9"; tk->i_fourcc = VLC_FOURCC( 'W', 'M', 'V', '3' ); } + else if( p_input->p_fmt->i_codec == VLC_FOURCC('W','V','C','1') ) + { + tk->psz_name = "Windows Media Video 9 Advanced Profile"; + tk->i_fourcc = VLC_FOURCC( 'W', 'V', 'C', '1' ); + tk->b_extended = true; + + if( p_fmt->i_extra > 0 ) + { + p_codec_extra = malloc( 1 + p_fmt->i_extra ); + if( p_codec_extra ) + { + i_codec_extra = 1 + p_fmt->i_extra; + p_codec_extra[0] = 0x01; + memcpy( &p_codec_extra[1], p_fmt->p_extra, p_fmt->i_extra ); + } + } + } else if( p_input->p_fmt->i_codec == VLC_FOURCC('h','2','6','4') ) { tk->psz_name = "H.264/MPEG-4 AVC"; @@ -540,16 +575,43 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) tk->psz_name = _("Unknown Video"); tk->i_fourcc = p_input->p_fmt->i_codec; } + if( !i_codec_extra && p_fmt->i_extra > 0 ) + { + p_codec_extra = malloc( p_fmt->i_extra ); + if( p_codec_extra ) + { + i_codec_extra = p_fmt->i_extra; + memcpy( p_codec_extra, p_fmt->p_extra, p_fmt->i_extra ); + } + } + + tk->i_extra = 11 + sizeof( BITMAPINFOHEADER ) + i_codec_extra; + tk->p_extra = malloc( tk->i_extra ); + if( !tk->p_extra ) + { + free( p_codec_extra ); + return VLC_ENOMEM; + } + bo_init( &bo, tk->p_extra, tk->i_extra ); + bo_addle_u32( &bo, p_input->p_fmt->video.i_width ); + bo_addle_u32( &bo, p_input->p_fmt->video.i_height ); + bo_add_u8 ( &bo, 0x02 ); /* flags */ + bo_addle_u16( &bo, sizeof( BITMAPINFOHEADER ) + i_codec_extra ); + bo_addle_u32( &bo, sizeof( BITMAPINFOHEADER ) + i_codec_extra ); + bo_addle_u32( &bo, p_input->p_fmt->video.i_width ); + bo_addle_u32( &bo, p_input->p_fmt->video.i_height ); + bo_addle_u16( &bo, 1 ); + bo_addle_u16( &bo, 24 ); bo_add_mem( &bo, (uint8_t*)&tk->i_fourcc, 4 ); bo_addle_u32( &bo, 0 ); bo_addle_u32( &bo, 0 ); bo_addle_u32( &bo, 0 ); bo_addle_u32( &bo, 0 ); bo_addle_u32( &bo, 0 ); - if( p_input->p_fmt->i_extra > 0 ) + if( i_codec_extra > 0 ) { - bo_add_mem ( &bo, p_input->p_fmt->p_extra, - p_input->p_fmt->i_extra ); + bo_add_mem( &bo, p_codec_extra, i_codec_extra ); + free( p_codec_extra ); } if( p_input->p_fmt->i_bitrate > 50000 ) @@ -558,8 +620,10 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) } else { - p_sys->i_bitrate += 1000000; + p_sys->i_bitrate += 512000; } + if( p_sys->i_bitrate_override ) + p_sys->i_bitrate = p_sys->i_bitrate_override; break; } default: @@ -578,6 +642,27 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) *****************************************************************************/ static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input ) { + /* if bitrate ain't defined in commanline, reduce it when tracks are deleted + */ + sout_mux_sys_t *p_sys = p_mux->p_sys; + asf_track_t *tk = p_input->p_sys; + if(!p_sys->i_bitrate_override) + { + if( tk->i_cat == AUDIO_ES ) + { + if( p_input->p_fmt->i_bitrate > 24000 ) + p_sys->i_bitrate -= p_input->p_fmt->i_bitrate; + else + p_sys->i_bitrate -= 128000; + } + else if(tk->i_cat == VIDEO_ES ) + { + if( p_input->p_fmt->i_bitrate > 50000 ) + p_sys->i_bitrate -= p_input->p_fmt->i_bitrate; + else + p_sys->i_bitrate -= 512000; + } + } msg_Dbg( p_mux, "removing input" ); return VLC_SUCCESS; } @@ -591,12 +676,12 @@ static int Mux( sout_mux_t *p_mux ) if( p_sys->b_write_header ) { - block_t *out = asf_header_create( p_mux, VLC_TRUE ); + block_t *out = asf_header_create( p_mux, true ); out->i_flags |= BLOCK_FLAG_HEADER; sout_AccessOutWrite( p_mux->p_access, out ); - p_sys->b_write_header = VLC_FALSE; + p_sys->b_write_header = false; } for( ;; ) @@ -628,6 +713,24 @@ static int Mux( sout_mux_t *p_mux ) data = block_FifoGet( p_input->p_fifo ); + /* Convert VC1 to ASF special format */ + if( tk->i_fourcc == VLC_FOURCC( 'W', 'V', 'C', '1' ) ) + { + while( data->i_buffer >= 4 && + ( data->p_buffer[0] != 0x00 || data->p_buffer[1] != 0x00 || + data->p_buffer[2] != 0x01 || + ( data->p_buffer[3] != 0x0D && data->p_buffer[3] != 0x0C ) ) ) + { + data->i_buffer--; + data->p_buffer++; + } + if( data->i_buffer >= 4 ) + { + data->i_buffer -= 4; + data->p_buffer += 4; + } + } + if( ( pk = asf_packet_create( p_mux, tk, data ) ) ) { sout_AccessOutWrite( p_mux->p_access, pk ); @@ -648,7 +751,7 @@ static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts ) sout_input_t *p_input = p_mux->pp_inputs[i]; block_t *p_data; - if( p_input->p_fifo->i_depth <= 0 ) + if( block_FifoCount( p_input->p_fifo ) <= 0 ) { if( p_input->p_fmt->i_cat == AUDIO_ES || p_input->p_fmt->i_cat == VIDEO_ES ) @@ -722,7 +825,7 @@ static void bo_add_mem( bo_t *p_bo, uint8_t *p_mem, int i_size ) p_bo->i_buffer += i_size; } -static void bo_addle_str16( bo_t *bo, char *str ) +static void bo_addle_str16( bo_t *bo, const char *str ) { bo_addle_u16( bo, strlen( str ) + 1 ); for( ;; ) @@ -733,7 +836,7 @@ static void bo_addle_str16( bo_t *bo, char *str ) } } -static void bo_addle_str16_nosize( bo_t *bo, char *str ) +static void bo_addle_str16_nosize( bo_t *bo, const char *str ) { for( ;; ) { @@ -790,6 +893,8 @@ static const guid_t asf_object_index_guid = {0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}}; static const guid_t asf_object_metadata_guid = {0xC5F8CBEA, 0x5BAF, 0x4877, {0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA}}; +static const guid_t asf_object_extended_stream_properties_guid = +{0x14E6A5CB, 0xC672, 0x4332, {0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A}}; /**************************************************************************** * Misc @@ -804,7 +909,7 @@ static void asf_chunk_add( bo_t *bo, bo_addle_u16( bo, i_len + 8 ); } -static block_t *asf_header_create( sout_mux_t *p_mux, vlc_bool_t b_broadcast ) +static block_t *asf_header_create( sout_mux_t *p_mux, bool b_broadcast ) { sout_mux_sys_t *p_sys = p_mux->p_sys; asf_track_t *tk; @@ -847,17 +952,24 @@ static block_t *asf_header_create( sout_mux_t *p_mux, vlc_bool_t b_broadcast ) strlen( p_sys->psz_rating ) + 1 ); } + i_header_ext_size = 46; + /* size of the metadata object */ for( i = 0; i < p_sys->i_track; i++ ) { - if( p_sys->track[i].i_cat == VIDEO_ES ) + const asf_track_t *p_track = &p_sys->track[i]; + if( p_track->i_cat == VIDEO_ES && p_track->fmt.video.i_aspect != 0 ) { i_cm_size = 26 + 2 * (16 + 2 * sizeof("AspectRatio?")); break; } + if( p_track->b_extended ) + i_header_ext_size += 88; + } - i_header_ext_size = i_cm_size ? i_cm_size + 46 : 0; + i_header_ext_size += i_cm_size; + i_size += i_ci_size + i_cd_size + i_header_ext_size ; if( p_sys->b_asf_http ) @@ -899,13 +1011,44 @@ static block_t *asf_header_create( sout_mux_t *p_mux, vlc_bool_t b_broadcast ) bo_addle_u32( &bo, p_sys->i_bitrate ); /* maxbitrate */ /* header extension */ - if( i_header_ext_size ) + bo_add_guid ( &bo, &asf_object_header_extension_guid ); + bo_addle_u64( &bo, i_header_ext_size ); + bo_add_guid ( &bo, &asf_guid_reserved_1 ); + bo_addle_u16( &bo, 6 ); + bo_addle_u32( &bo, i_header_ext_size - 46 ); + + /* extended stream properties */ + for( i = 0; i < p_sys->i_track; i++ ) { - bo_add_guid ( &bo, &asf_object_header_extension_guid ); - bo_addle_u64( &bo, i_header_ext_size ); - bo_add_guid ( &bo, &asf_guid_reserved_1 ); - bo_addle_u16( &bo, 6 ); - bo_addle_u32( &bo, i_header_ext_size - 46 ); + const asf_track_t *p_track = &p_sys->track[i]; + const es_format_t *p_fmt = &p_track->fmt; + + if( !p_track->b_extended ) + continue; + + uint64_t i_avg_duration = 0; + if( p_fmt->i_cat == VIDEO_ES && + p_fmt->video.i_frame_rate > 0 && p_fmt->video.i_frame_rate_base > 0 ) + i_avg_duration = ( INT64_C(10000000) * p_fmt->video.i_frame_rate_base + + p_fmt->video.i_frame_rate/2 ) / p_fmt->video.i_frame_rate; + + bo_add_guid ( &bo, &asf_object_extended_stream_properties_guid ); + bo_addle_u64( &bo, 88 ); + bo_addle_u64( &bo, 0 ); + bo_addle_u64( &bo, 0 ); + bo_addle_u32( &bo, p_fmt->i_bitrate ); /* Bitrate */ + bo_addle_u32( &bo, 0 ); /* Buffer size */ + bo_addle_u32( &bo, 0 ); /* Initial buffer fullness */ + bo_addle_u32( &bo, p_fmt->i_bitrate ); /* Alternate Bitrate */ + bo_addle_u32( &bo, 0 ); /* Alternate Buffer size */ + bo_addle_u32( &bo, 0 ); /* Alternate Initial buffer fullness */ + bo_addle_u32( &bo, 0 ); /* Maximum object size (0 = unkown) */ + bo_addle_u32( &bo, 0x02 ); /* Flags (seekable) */ + bo_addle_u16( &bo, i+1 ); /* Stream number */ + bo_addle_u16( &bo, 0 ); /* Stream language index */ + bo_addle_u64( &bo, i_avg_duration ); /* Average time per frame */ + bo_addle_u16( &bo, 0 ); /* Stream name count */ + bo_addle_u16( &bo, 0 ); /* Payload extension system count */ } /* metadata object (part of header extension) */