X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=modules%2Fstream_out%2Ftranscode.c;h=d889dc12211220eabed90666c2356faa650a0fcf;hb=5b63839284565821b5aff349378eddbb9d7f1ee0;hp=947fb519725c30211a9d63c1479dd9e4d5227fb8;hpb=cf4026c9f3377830fa1b234362c73c6f7f85930a;p=vlc diff --git a/modules/stream_out/transcode.c b/modules/stream_out/transcode.c index 947fb51972..d889dc1221 100644 --- a/modules/stream_out/transcode.c +++ b/modules/stream_out/transcode.c @@ -7,6 +7,7 @@ * Authors: Laurent Aimar * Gildas Bazin * Jean-Paul Saman + * Antoine Cellerier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +31,7 @@ # include "config.h" #endif -#include +#include #include #include #include @@ -45,6 +46,8 @@ #define MASTER_SYNC_MAX_DRIFT 100000 +#include + /***************************************************************************** * Module descriptor *****************************************************************************/ @@ -87,43 +90,6 @@ "Video filters will be applied to the video streams (after overlays " \ "are applied). You must enter a comma-separated list of filters." ) -#define CROPTOP_TEXT N_("Video crop (top)") -#define CROPTOP_LONGTEXT N_( \ - "Number of pixels to crop at the top of the video." ) -#define CROPLEFT_TEXT N_("Video crop (left)") -#define CROPLEFT_LONGTEXT N_( \ - "Number of pixels to crop at the left of the video." ) -#define CROPBOTTOM_TEXT N_("Video crop (bottom)") -#define CROPBOTTOM_LONGTEXT N_( \ - "Number of pixels to crop at the bottom of the video." ) -#define CROPRIGHT_TEXT N_("Video crop (right)") -#define CROPRIGHT_LONGTEXT N_( \ - "Number of pixels to crop at the right of the video." ) - -#define PADDTOP_TEXT N_("Video padding (top)") -#define PADDTOP_LONGTEXT N_( \ - "Size of the black border to add at the top of the video." ) -#define PADDLEFT_TEXT N_("Video padding (left)") -#define PADDLEFT_LONGTEXT N_( \ - "Size of the black border to add at the left of the video." ) -#define PADDBOTTOM_TEXT N_("Video padding (bottom)") -#define PADDBOTTOM_LONGTEXT N_( \ - "Size of the black border to add at the bottom of the video." ) -#define PADDRIGHT_TEXT N_("Video padding (right)") -#define PADDRIGHT_LONGTEXT N_( \ - "Size of the black border to add at the right of the video." ) - -#define CANVAS_WIDTH_TEXT N_("Video canvas width") -#define CANVAS_WIDTH_LONGTEXT N_( \ - "This will automatically crod and pad the video to a specified width." ) -#define CANVAS_HEIGHT_TEXT N_("Video canvas height") -#define CANVAS_HEIGHT_LONGTEXT N_( \ - "This will automatically crod and pad the video to a specified height." ) -#define CANVAS_ASPECT_TEXT N_("Video canvas aspect ratio") -#define CANVAS_ASPECT_LONGTEXT N_( \ - "This sets aspect (like 4:3) of the video canvas and letterbox the video "\ - "accordingly." ) - #define AENC_TEXT N_("Audio encoder") #define AENC_LONGTEXT N_( \ "This is the audio encoder module that will be used (and its associated "\ @@ -181,7 +147,7 @@ #define HURRYUP_LONGTEXT N_( "The transcoder will drop frames if your CPU " \ "can't keep up with the encoding rate." ) -static const char *ppsz_deinterlace_type[] = +static const char *const ppsz_deinterlace_type[] = { "deinterlace", "ffmpeg-deinterlace" }; @@ -230,31 +196,6 @@ vlc_module_begin(); NULL, NULL, VFILTER_TEXT, VFILTER_LONGTEXT, false ); - add_integer( SOUT_CFG_PREFIX "croptop", 0, NULL, CROPTOP_TEXT, - CROPTOP_LONGTEXT, true ); - add_integer( SOUT_CFG_PREFIX "cropleft", 0, NULL, CROPLEFT_TEXT, - CROPLEFT_LONGTEXT, true ); - add_integer( SOUT_CFG_PREFIX "cropbottom", 0, NULL, CROPBOTTOM_TEXT, - CROPBOTTOM_LONGTEXT, true ); - add_integer( SOUT_CFG_PREFIX "cropright", 0, NULL, CROPRIGHT_TEXT, - CROPRIGHT_LONGTEXT, true ); - - add_integer( SOUT_CFG_PREFIX "paddtop", 0, NULL, PADDTOP_TEXT, - PADDTOP_LONGTEXT, true ); - add_integer( SOUT_CFG_PREFIX "paddleft", 0, NULL, PADDLEFT_TEXT, - PADDLEFT_LONGTEXT, true ); - add_integer( SOUT_CFG_PREFIX "paddbottom", 0, NULL, PADDBOTTOM_TEXT, - PADDBOTTOM_LONGTEXT, true ); - add_integer( SOUT_CFG_PREFIX "paddright", 0, NULL, PADDRIGHT_TEXT, - PADDRIGHT_LONGTEXT, true ); - - add_integer( SOUT_CFG_PREFIX "canvas-width", 0, NULL, CANVAS_WIDTH_TEXT, - CANVAS_WIDTH_LONGTEXT, true ); - add_integer( SOUT_CFG_PREFIX "canvas-height", 0, NULL, CANVAS_HEIGHT_TEXT, - CANVAS_HEIGHT_LONGTEXT, true ); - add_string( SOUT_CFG_PREFIX "canvas-aspect", NULL, NULL, CANVAS_ASPECT_TEXT, - CANVAS_ASPECT_LONGTEXT, false ); - set_section( N_("Audio"), NULL ); add_string( SOUT_CFG_PREFIX "aenc", NULL, NULL, AENC_TEXT, AENC_LONGTEXT, false ); @@ -295,10 +236,8 @@ vlc_module_begin(); vlc_module_end(); -static const char *ppsz_sout_options[] = { - "venc", "vcodec", "vb", "croptop", "cropbottom", "cropleft", "cropright", - "paddtop", "paddbottom", "paddleft", "paddright", - "canvas-width", "canvas-height", "canvas-aspect", +static const char *const ppsz_sout_options[] = { + "venc", "vcodec", "vb", "scale", "fps", "width", "height", "vfilter", "deinterlace", "deinterlace-module", "threads", "hurry-up", "aenc", "acodec", "ab", "afilter", "samplerate", "channels", "senc", "scodec", "soverlay", @@ -323,6 +262,7 @@ static void audio_del_buffer( decoder_t *, aout_buffer_t * ); static int transcode_video_new ( sout_stream_t *, sout_stream_id_t * ); static void transcode_video_close ( sout_stream_t *, sout_stream_id_t * ); +static void transcode_video_encoder_init( sout_stream_t *, sout_stream_id_t *); static int transcode_video_encoder_open( sout_stream_t *, sout_stream_id_t *); static int transcode_video_process( sout_stream_t *, sout_stream_id_t *, block_t *, block_t ** ); @@ -345,9 +285,9 @@ static void transcode_osd_close ( sout_stream_t *, sout_stream_id_t * ); static int transcode_osd_process( sout_stream_t *, sout_stream_id_t *, block_t *, block_t ** ); -static int EncoderThread( struct sout_stream_sys_t * p_sys ); +static void* EncoderThread( vlc_object_t * p_this ); -static int pi_channels_maps[6] = +static const int pi_channels_maps[6] = { 0, AOUT_CHAN_CENTER, AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT, @@ -360,7 +300,6 @@ static int pi_channels_maps[6] = #define PICTURE_RING_SIZE 64 #define SUBPICTURE_RING_SIZE 20 -#define TRANSCODE_FILTERS 10 #define ENC_FRAMERATE (25 * 1000 + .5) #define ENC_FRAMERATE_BASE 1000 @@ -384,9 +323,8 @@ struct sout_stream_sys_t uint32_t i_sample_rate; uint32_t i_channels; int i_abitrate; - char *psz_afilters[TRANSCODE_FILTERS]; - config_chain_t *p_afilters_cfg[TRANSCODE_FILTERS]; - int i_afilters; + + char *psz_af2; /* Video */ vlc_fourcc_t i_vcodec; /* codec video (0 if not transcode) */ @@ -397,45 +335,19 @@ struct sout_stream_sys_t double f_fps; unsigned int i_width, i_maxwidth; unsigned int i_height, i_maxheight; - bool b_deinterlace; + bool b_deinterlace; char *psz_deinterlace; config_chain_t *p_deinterlace_cfg; int i_threads; - bool b_high_priority; - bool b_hurry_up; - char *psz_vfilters[TRANSCODE_FILTERS]; - config_chain_t *p_vfilters_cfg[TRANSCODE_FILTERS]; - int i_vfilters; - - int i_crop_top; - int i_crop_bottom; - int i_crop_right; - int i_crop_left; - - int i_padd_top; - int i_padd_bottom; - int i_padd_right; - int i_padd_left; - - int i_canvas_width; - int i_canvas_height; - int i_canvas_aspect; - - /* Video, calculated */ - int i_src_x_offset; - int i_src_y_offset; - int i_crop_width; - int i_crop_height; - - int i_dst_x_offset; - int i_dst_y_offset; - int i_nopadd_width; - int i_nopadd_height; + bool b_high_priority; + bool b_hurry_up; + + char *psz_vf2; /* SPU */ vlc_fourcc_t i_scodec; /* codec spu (0 if not transcode) */ char *psz_senc; - bool b_soverlay; + bool b_soverlay; config_chain_t *p_spu_cfg; spu_t *p_spu; @@ -443,10 +355,10 @@ struct sout_stream_sys_t vlc_fourcc_t i_osdcodec; /* codec osd menu (0 if not transcode) */ char *psz_osdenc; config_chain_t *p_osd_cfg; - bool b_osd; /* true when osd es is registered */ + bool b_osd; /* true when osd es is registered */ /* Sync */ - bool b_master_sync; + bool b_master_sync; mtime_t i_master_drift; }; @@ -533,27 +445,12 @@ static int Open( vlc_object_t *p_this ) } var_Get( p_stream, SOUT_CFG_PREFIX "afilter", &val ); - p_sys->i_afilters = 0; if( val.psz_string && *val.psz_string ) + p_sys->psz_af2 = val.psz_string; + else { - char *psz_parser = val.psz_string; - - while( (psz_parser != NULL) && (*psz_parser != '\0') - && (p_sys->i_afilters < TRANSCODE_FILTERS) ) - { - psz_parser = config_ChainCreate( - &p_sys->psz_afilters[p_sys->i_afilters], - &p_sys->p_afilters_cfg[p_sys->i_afilters], - psz_parser ); - p_sys->i_afilters++; - if( (psz_parser != NULL) && (*psz_parser != '\0') ) psz_parser++; - } - } - free( val.psz_string ); - if( p_sys->i_afilters < TRANSCODE_FILTERS-1 ) - { - p_sys->psz_afilters[p_sys->i_afilters] = NULL; - p_sys->p_afilters_cfg[p_sys->i_afilters] = NULL; + free( val.psz_string ); + p_sys->psz_af2 = NULL; } /* Video transcoding parameters */ @@ -605,27 +502,12 @@ static int Open( vlc_object_t *p_this ) p_sys->i_maxheight = val.i_int; var_Get( p_stream, SOUT_CFG_PREFIX "vfilter", &val ); - p_sys->i_vfilters = 0; if( val.psz_string && *val.psz_string ) + p_sys->psz_vf2 = val.psz_string; + else { - char *psz_parser = val.psz_string; - - while( (psz_parser != NULL) && (*psz_parser != '\0') - && (p_sys->i_vfilters < TRANSCODE_FILTERS) ) - { - psz_parser = config_ChainCreate( - &p_sys->psz_vfilters[p_sys->i_vfilters], - &p_sys->p_vfilters_cfg[p_sys->i_vfilters], - psz_parser ); - p_sys->i_vfilters++; - if( psz_parser != NULL && *psz_parser != '\0' ) psz_parser++; - } - } - free( val.psz_string ); - if( p_sys->i_vfilters < TRANSCODE_FILTERS-1 ) - { - p_sys->psz_vfilters[p_sys->i_vfilters] = NULL; - p_sys->p_vfilters_cfg[p_sys->i_vfilters] = NULL; + free( val.psz_string ); + p_sys->psz_vf2 = NULL; } var_Get( p_stream, SOUT_CFG_PREFIX "deinterlace", &val ); @@ -644,45 +526,6 @@ static int Open( vlc_object_t *p_this ) } free( val.psz_string ); - var_Get( p_stream, SOUT_CFG_PREFIX "croptop", &val ); - p_sys->i_crop_top = val.i_int; - var_Get( p_stream, SOUT_CFG_PREFIX "cropbottom", &val ); - p_sys->i_crop_bottom = val.i_int; - var_Get( p_stream, SOUT_CFG_PREFIX "cropleft", &val ); - p_sys->i_crop_left = val.i_int; - var_Get( p_stream, SOUT_CFG_PREFIX "cropright", &val ); - p_sys->i_crop_right = val.i_int; - - var_Get( p_stream, SOUT_CFG_PREFIX "paddtop", &val ); - p_sys->i_padd_top = val.i_int; - var_Get( p_stream, SOUT_CFG_PREFIX "paddbottom", &val ); - p_sys->i_padd_bottom = val.i_int; - var_Get( p_stream, SOUT_CFG_PREFIX "paddleft", &val ); - p_sys->i_padd_left = val.i_int; - var_Get( p_stream, SOUT_CFG_PREFIX "paddright", &val ); - p_sys->i_padd_right = val.i_int; - - var_Get( p_stream, SOUT_CFG_PREFIX "canvas-width", &val ); - p_sys->i_canvas_width = val.i_int; - var_Get( p_stream, SOUT_CFG_PREFIX "canvas-height", &val ); - p_sys->i_canvas_height = val.i_int; - - var_Get( p_stream, SOUT_CFG_PREFIX "canvas-aspect", &val ); - p_sys->i_canvas_aspect = 0; - if( val.psz_string && *val.psz_string ) - { - char *psz_parser = strchr( val.psz_string, ':' ); - if( psz_parser ) - { - *psz_parser++ = '\0'; - p_sys->i_canvas_aspect = atoi( val.psz_string ) * - VOUT_ASPECT_FACTOR / atoi( psz_parser ); - } - else msg_Warn( p_stream, "bad aspect ratio %s", val.psz_string ); - - } - free( val.psz_string ); - var_Get( p_stream, SOUT_CFG_PREFIX "threads", &val ); p_sys->i_threads = val.i_int; var_Get( p_stream, SOUT_CFG_PREFIX "high-priority", &val ); @@ -798,12 +641,7 @@ static void Close( vlc_object_t * p_this ) sout_StreamDelete( p_sys->p_out ); - while( p_sys->i_afilters ) - { - p_sys->i_afilters--; - free( p_sys->psz_afilters[p_sys->i_afilters] ); - free( p_sys->p_afilters_cfg[p_sys->i_afilters] ); - } + free( p_sys->psz_af2 ); while( p_sys->p_audio_cfg != NULL ) { @@ -817,12 +655,7 @@ static void Close( vlc_object_t * p_this ) } free( p_sys->psz_aenc ); - while( p_sys->i_vfilters ) - { - p_sys->i_vfilters--; - free( p_sys->psz_vfilters[p_sys->i_vfilters] ); - free( p_sys->p_vfilters_cfg[p_sys->i_vfilters] ); - } + free( p_sys->psz_vf2 ); while( p_sys->p_video_cfg != NULL ) { @@ -888,11 +721,9 @@ struct sout_stream_id_t decoder_t *p_decoder; /* Filters */ - filter_t *pp_filter[TRANSCODE_FILTERS]; - int i_filter; + filter_chain_t *p_f_chain; /* User specified filters */ - filter_t *pp_ufilter[TRANSCODE_FILTERS]; - int i_ufilter; + filter_chain_t *p_uf_chain; /* Encoder */ encoder_t *p_encoder; @@ -908,10 +739,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) id = malloc( sizeof( sout_stream_id_t ) ); if( !id ) - { - msg_Err( p_stream, "out of memory" ); goto error; - } memset( id, 0, sizeof(sout_stream_id_t) ); id->id = NULL; @@ -921,10 +749,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) /* Create decoder object */ id->p_decoder = vlc_object_create( p_stream, VLC_OBJECT_DECODER ); if( !id->p_decoder ) - { - msg_Err( p_stream, "out of memory" ); goto error; - } vlc_object_attach( id->p_decoder, p_stream ); id->p_decoder->p_module = NULL; id->p_decoder->fmt_in = *p_fmt; @@ -933,10 +758,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) /* Create encoder object */ id->p_encoder = vlc_object_create( p_stream, VLC_OBJECT_ENCODER ); if( !id->p_encoder ) - { - msg_Err( p_stream, "out of memory" ); goto error; - } vlc_object_attach( id->p_encoder, p_stream ); id->p_encoder->p_module = NULL; @@ -1100,23 +922,26 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) return id; - error: - if( id->p_decoder ) +error: + if( id ) { - vlc_object_detach( id->p_decoder ); - vlc_object_release( id->p_decoder ); - id->p_decoder = NULL; - } + if( id->p_decoder ) + { + vlc_object_detach( id->p_decoder ); + vlc_object_release( id->p_decoder ); + id->p_decoder = NULL; + } - if( id->p_encoder ) - { - vlc_object_detach( id->p_encoder ); - es_format_Clean( &id->p_encoder->fmt_out ); - vlc_object_release( id->p_encoder ); - id->p_encoder = NULL; - } + if( id->p_encoder ) + { + vlc_object_detach( id->p_encoder ); + es_format_Clean( &id->p_encoder->fmt_out ); + vlc_object_release( id->p_encoder ); + id->p_encoder = NULL; + } - free( id ); + free( id ); + } return NULL; } @@ -1262,79 +1087,18 @@ static inline void audio_timer_close( encoder_t * p_encoder ) * decoder reencoder part ****************************************************************************/ -static int audio_BitsPerSample( vlc_fourcc_t i_format ) +static block_t *transcode_audio_alloc( filter_t *p_filter, int size ) { - switch( i_format ) - { - case VLC_FOURCC('u','8',' ',' '): - case VLC_FOURCC('s','8',' ',' '): - return 8; - - case VLC_FOURCC('u','1','6','l'): - case VLC_FOURCC('s','1','6','l'): - case VLC_FOURCC('u','1','6','b'): - case VLC_FOURCC('s','1','6','b'): - return 16; - - case VLC_FOURCC('u','2','4','l'): - case VLC_FOURCC('s','2','4','l'): - case VLC_FOURCC('u','2','4','b'): - case VLC_FOURCC('s','2','4','b'): - return 24; - - case VLC_FOURCC('u','3','2','l'): - case VLC_FOURCC('s','3','2','l'): - case VLC_FOURCC('u','3','2','b'): - case VLC_FOURCC('s','3','2','b'): - case VLC_FOURCC('f','l','3','2'): - case VLC_FOURCC('f','i','3','2'): - return 32; - - case VLC_FOURCC('f','l','6','4'): - return 64; - } - - return 0; + VLC_UNUSED( p_filter ); + return block_Alloc( size ); } -static block_t *transcode_audio_alloc (filter_t *filter, int size) +static int transcode_audio_filter_allocation_init( filter_t *p_filter, + void *data ) { - return block_New (filter, size); -} - -static filter_t *transcode_audio_filter_new( sout_stream_t *p_stream, - sout_stream_id_t *id, - es_format_t *p_fmt_in, - es_format_t *p_fmt_out, - char *psz_name ) -{ - sout_stream_sys_t *p_sys = p_stream->p_sys; - filter_t *p_filter = vlc_object_create( p_stream, VLC_OBJECT_FILTER ); - - vlc_object_attach( p_filter, p_stream ); + VLC_UNUSED(data); p_filter->pf_audio_buffer_new = transcode_audio_alloc; - - p_filter->fmt_in = *p_fmt_in; - p_filter->fmt_out = *p_fmt_out; - if( psz_name ) - p_filter->p_cfg = p_sys->p_afilters_cfg[id->i_ufilter]; - - p_filter->p_module = module_Need( p_filter, "audio filter2", psz_name, - true ); - if( p_filter->p_module ) - { - p_filter->fmt_out.audio.i_bitspersample = - audio_BitsPerSample( p_filter->fmt_out.i_codec ); - *p_fmt_in = p_filter->fmt_out; - } - else - { - vlc_object_detach( p_filter ); - vlc_object_release( p_filter ); - p_filter = 0; - } - - return p_filter; + return VLC_SUCCESS; } static int transcode_audio_new( sout_stream_t *p_stream, @@ -1361,11 +1125,11 @@ static int transcode_audio_new( sout_stream_t *p_stream, module_Need( id->p_decoder, "decoder", "$codec", 0 ); if( !id->p_decoder->p_module ) { - msg_Err( p_stream, "cannot find decoder" ); + msg_Err( p_stream, "cannot find audio decoder" ); return VLC_EGENERIC; } id->p_decoder->fmt_out.audio.i_bitspersample = - audio_BitsPerSample( id->p_decoder->fmt_out.i_codec ); + aout_BitsPerSample( id->p_decoder->fmt_out.i_codec ); fmt_last = id->p_decoder->fmt_out; /* Fix AAC SBR changing number of channels and sampling rate */ if( !(id->p_decoder->fmt_in.i_codec == VLC_FOURCC('m','p','4','a') && @@ -1382,11 +1146,7 @@ static int transcode_audio_new( sout_stream_t *p_stream, id->p_decoder->fmt_out.i_codec ); id->p_encoder->fmt_in.audio.i_format = id->p_decoder->fmt_out.i_codec; - if( ( id->p_encoder->fmt_out.i_codec == VLC_FOURCC('s','a','m','r') ) || - ( id->p_encoder->fmt_out.i_codec == VLC_FOURCC('s','a','w','b') ) ) - id->p_encoder->fmt_in.audio.i_rate = id->p_encoder->fmt_out.audio.i_rate; - else - id->p_encoder->fmt_in.audio.i_rate = fmt_last.audio.i_rate; + id->p_encoder->fmt_in.audio.i_rate = id->p_encoder->fmt_out.audio.i_rate; id->p_encoder->fmt_in.audio.i_physical_channels = id->p_encoder->fmt_out.audio.i_physical_channels; id->p_encoder->fmt_in.audio.i_original_channels = @@ -1394,77 +1154,85 @@ static int transcode_audio_new( sout_stream_t *p_stream, id->p_encoder->fmt_in.audio.i_channels = id->p_encoder->fmt_out.audio.i_channels; id->p_encoder->fmt_in.audio.i_bitspersample = - audio_BitsPerSample( id->p_encoder->fmt_in.i_codec ); + aout_BitsPerSample( id->p_encoder->fmt_in.i_codec ); id->p_encoder->p_cfg = p_stream->p_sys->p_audio_cfg; id->p_encoder->p_module = module_Need( id->p_encoder, "encoder", p_sys->psz_aenc, true ); if( !id->p_encoder->p_module ) { - msg_Err( p_stream, "cannot find encoder (%s)", p_sys->psz_aenc ); + msg_Err( p_stream, "cannot find audio encoder (module:%s fourcc:%4.4s)", + p_sys->psz_aenc ? p_sys->psz_aenc : "any", + (char *)&p_sys->i_acodec ); module_Unneed( id->p_decoder, id->p_decoder->p_module ); id->p_decoder->p_module = NULL; return VLC_EGENERIC; } id->p_encoder->fmt_in.audio.i_format = id->p_encoder->fmt_in.i_codec; id->p_encoder->fmt_in.audio.i_bitspersample = - audio_BitsPerSample( id->p_encoder->fmt_in.i_codec ); + aout_BitsPerSample( id->p_encoder->fmt_in.i_codec ); + + /* Init filter chain */ + id->p_f_chain = filter_chain_New( p_stream, "audio filter2", true, + transcode_audio_filter_allocation_init, NULL, NULL ); + filter_chain_Reset( id->p_f_chain, &fmt_last, &id->p_encoder->fmt_in ); /* Load conversion filters */ if( fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels || fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate ) { /* We'll have to go through fl32 first */ - es_format_t fmt_out = id->p_encoder->fmt_in; - fmt_out.i_codec = fmt_out.audio.i_format = VLC_FOURCC('f','l','3','2'); - - id->pp_filter[id->i_filter] = - transcode_audio_filter_new( p_stream, id, &fmt_last, &fmt_out, NULL ); - - if( id->pp_filter[id->i_filter] ) id->i_filter++; + fmt_last.i_codec = fmt_last.audio.i_format = VLC_FOURCC('f','l','3','2'); + fmt_last.audio.i_bitspersample = aout_BitsPerSample( fmt_last.i_codec ); + filter_chain_AppendFilter( id->p_f_chain, NULL, NULL, NULL, &fmt_last ); + fmt_last = *filter_chain_GetFmtOut( id->p_f_chain ); } - for( i = 0; i < TRANSCODE_FILTERS; i++ ) + for( i = 0; i < 4; i++ ) { if( (fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels) || (fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate) || (fmt_last.i_codec != id->p_encoder->fmt_in.i_codec) ) { - id->pp_filter[id->i_filter] = - transcode_audio_filter_new( p_stream, id, &fmt_last, - &id->p_encoder->fmt_in, NULL ); - - if( id->pp_filter[id->i_filter] ) - id->i_filter++; - else - break; + msg_Dbg( p_stream, "Looking for filter " + "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)", + (char *)&fmt_last.i_codec, + (char *)&id->p_encoder->fmt_in.i_codec, + fmt_last.audio.i_channels, + id->p_encoder->fmt_in.audio.i_channels, + fmt_last.audio.i_rate, + id->p_encoder->fmt_in.audio.i_rate ); + filter_chain_AppendFilter( id->p_f_chain, NULL, NULL, + &fmt_last, &id->p_encoder->fmt_in ); + fmt_last = *filter_chain_GetFmtOut( id->p_f_chain ); } + else break; } /* Final checks to see if conversions were successful */ if( fmt_last.i_codec != id->p_encoder->fmt_in.i_codec ) { - msg_Err( p_stream, "no audio filter found (%4.4s->%4.4s)", + msg_Err( p_stream, "no audio filter found " + "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)", (char *)&fmt_last.i_codec, - (char *)&id->p_encoder->fmt_in.i_codec ); + (char *)&id->p_encoder->fmt_in.i_codec, + fmt_last.audio.i_channels, + id->p_encoder->fmt_in.audio.i_channels, + fmt_last.audio.i_rate, + id->p_encoder->fmt_in.audio.i_rate ); transcode_audio_close( id ); return VLC_EGENERIC; } /* Load user specified audio filters now */ - for( i = 0; (i < p_sys->i_afilters) && - (id->i_ufilter < TRANSCODE_FILTERS); i++ ) + if( p_sys->psz_af2 ) { - id->pp_ufilter[id->i_ufilter] = - transcode_audio_filter_new( p_stream, id, &fmt_last, - &id->p_encoder->fmt_in, - p_sys->psz_afilters[i] ); - - if( id->pp_ufilter[id->i_ufilter] ) - id->i_ufilter++; - else - break; + id->p_uf_chain = filter_chain_New( p_stream, "audio filter2", false, + transcode_audio_filter_allocation_init, NULL, NULL ); + filter_chain_Reset( id->p_uf_chain, &fmt_last, &id->p_encoder->fmt_in ); + filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_af2 ); + fmt_last = *filter_chain_GetFmtOut( id->p_uf_chain ); } if( fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels ) @@ -1493,15 +1261,24 @@ static int transcode_audio_new( sout_stream_t *p_stream, id->p_encoder->p_cfg = p_stream->p_sys->p_audio_cfg; id->p_encoder->p_module = module_Need( id->p_encoder, "encoder", p_sys->psz_aenc, true ); - if( !id->p_encoder->p_module ) + if( !id->p_encoder->p_module || + fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels || + fmt_last.i_codec != id->p_encoder->fmt_in.i_codec ) { - msg_Err( p_stream, "cannot find encoder (%s)", p_sys->psz_aenc ); + if( id->p_encoder->p_module ) + { + module_Unneed( id->p_encoder, id->p_encoder->p_module ); + id->p_encoder->p_module = NULL; + } + msg_Err( p_stream, "cannot find audio encoder (module:%s fourcc:%4.4s)", + p_sys->psz_aenc ? p_sys->psz_aenc : "any", + (char *)&p_sys->i_acodec ); transcode_audio_close( id ); return VLC_EGENERIC; } id->p_encoder->fmt_in.audio.i_format = id->p_encoder->fmt_in.i_codec; id->p_encoder->fmt_in.audio.i_bitspersample = - audio_BitsPerSample( id->p_encoder->fmt_in.i_codec ); + aout_BitsPerSample( id->p_encoder->fmt_in.i_codec ); #else msg_Err( p_stream, "no audio filter found for mixing from" " %i to %i channels", fmt_last.audio.i_channels, @@ -1536,8 +1313,6 @@ static int transcode_audio_new( sout_stream_t *p_stream, static void transcode_audio_close( sout_stream_id_t *id ) { - int i; - audio_timer_close( id->p_encoder ); /* Close decoder */ @@ -1551,23 +1326,10 @@ static void transcode_audio_close( sout_stream_id_t *id ) id->p_encoder->p_module = NULL; /* Close filters */ - for( i = 0; i < id->i_filter; i++ ) - { - vlc_object_detach( id->pp_filter[i] ); - if( id->pp_filter[i]->p_module ) - module_Unneed( id->pp_filter[i], id->pp_filter[i]->p_module ); - vlc_object_release( id->pp_filter[i] ); - } - id->i_filter = 0; - - for( i = 0; i < id->i_ufilter; i++ ) - { - vlc_object_detach( id->pp_ufilter[i] ); - if( id->pp_ufilter[i]->p_module ) - module_Unneed( id->pp_ufilter[i], id->pp_ufilter[i]->p_module ); - vlc_object_release( id->pp_ufilter[i] ); - } - id->i_ufilter = 0; + if( id->p_f_chain ) + filter_chain_Delete( id->p_f_chain ); + if( id->p_uf_chain ) + filter_chain_Delete( id->p_uf_chain ); } static int transcode_audio_process( sout_stream_t *p_stream, @@ -1577,7 +1339,6 @@ static int transcode_audio_process( sout_stream_t *p_stream, sout_stream_sys_t *p_sys = p_stream->p_sys; aout_buffer_t *p_audio_buf; block_t *p_block, *p_audio_block; - int i; *out = NULL; while( (p_audio_buf = id->p_decoder->pf_decode_audio( id->p_decoder, @@ -1609,21 +1370,9 @@ static int transcode_audio_process( sout_stream_t *p_stream, p_audio_block->i_samples = p_audio_buf->i_nb_samples; /* Run filter chain */ - for( i = 0; i < id->i_filter; i++ ) - { - p_audio_block = - id->pp_filter[i]->pf_audio_filter( id->pp_filter[i], - p_audio_block ); - } - - /* Run user specified filter chain */ - for( i = 0; i < id->i_ufilter; i++ ) - { - p_audio_block = - id->pp_ufilter[i]->pf_audio_filter( id->pp_ufilter[i], - p_audio_block ); - } - + p_audio_block = filter_chain_AudioFilter( id->p_f_chain, p_audio_block ); + if( id->p_uf_chain ) + p_audio_block = filter_chain_AudioFilter( id->p_uf_chain, p_audio_block ); assert( p_audio_block ); p_audio_buf->p_buffer = p_audio_block->p_buffer; @@ -1697,65 +1446,30 @@ static void audio_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer ) * video */ -static filter_t *transcode_video_filter_new( sout_stream_t *p_stream, - es_format_t *p_fmt_in, - es_format_t *p_fmt_out, - config_chain_t *p_cfg, - const char *psz_name ) +static int transcode_video_filter_allocation_init( filter_t *p_filter, + void *p_data ) { - sout_stream_sys_t *p_sys = p_stream->p_sys; - filter_t *p_filter; + sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_data; int i; - if( !p_stream || !p_fmt_in || !p_fmt_out ) return NULL; - - p_filter = vlc_object_create( p_stream, VLC_OBJECT_FILTER ); - vlc_object_attach( p_filter, p_stream ); - p_filter->pf_vout_buffer_new = video_new_buffer_filter; p_filter->pf_vout_buffer_del = video_del_buffer_filter; - es_format_Copy( &p_filter->fmt_in, p_fmt_in ); - es_format_Copy( &p_filter->fmt_out, p_fmt_out ); - p_filter->p_cfg = p_cfg; - - p_filter->p_module = module_Need( p_filter, "video filter2", - psz_name, true ); - if( !p_filter->p_module ) - { - msg_Dbg( p_stream, "no video filter found" ); - vlc_object_detach( p_filter ); - vlc_object_release( p_filter ); - return NULL; - } - p_filter->p_owner = malloc( sizeof(filter_owner_sys_t) ); if( !p_filter->p_owner ) - { - module_Unneed( p_filter,p_filter->p_module ); - vlc_object_detach( p_filter ); - vlc_object_release( p_filter ); - return NULL; - } + return VLC_EGENERIC; for( i = 0; i < PICTURE_RING_SIZE; i++ ) p_filter->p_owner->pp_pics[i] = 0; p_filter->p_owner->p_sys = p_sys; - return p_filter; + return VLC_SUCCESS; } -static void transcode_video_filter_close( sout_stream_t *p_stream, - filter_t *p_filter ) +static void transcode_video_filter_allocation_clear( filter_t *p_filter ) { int j; - if( !p_stream || !p_filter ) return; - - vlc_object_detach( p_filter ); - if( p_filter->p_module ) - module_Unneed( p_filter, p_filter->p_module ); - /* Clean-up pictures ring buffer */ for( j = 0; j < PICTURE_RING_SIZE; j++ ) { @@ -1764,8 +1478,6 @@ static void transcode_video_filter_close( sout_stream_t *p_stream, p_filter->p_owner->pp_pics[j] ); } free( p_filter->p_owner ); - vlc_object_release( p_filter ); - p_filter = NULL; } static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) @@ -1787,6 +1499,9 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) id->p_decoder->pf_picture_link = video_link_picture_decoder; id->p_decoder->pf_picture_unlink = video_unlink_picture_decoder; id->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) ); + if( !id->p_decoder->p_owner ) + return VLC_EGENERIC; + for( i = 0; i < PICTURE_RING_SIZE; i++ ) id->p_decoder->p_owner->pp_pics[i] = 0; id->p_decoder->p_owner->p_sys = p_sys; @@ -1797,7 +1512,8 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) if( !id->p_decoder->p_module ) { - msg_Err( p_stream, "cannot find decoder" ); + msg_Err( p_stream, "cannot find video decoder" ); + free( id->p_decoder->p_owner ); return VLC_EGENERIC; } @@ -1816,15 +1532,11 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) /* The dimensions will be set properly later on. * Just put sensible values so we can test an encoder is available. */ id->p_encoder->fmt_in.video.i_width = - id->p_encoder->fmt_out.video.i_width ? - id->p_encoder->fmt_out.video.i_width : - id->p_decoder->fmt_in.video.i_width ? - id->p_decoder->fmt_in.video.i_width : 16; + id->p_encoder->fmt_out.video.i_width ?: + id->p_decoder->fmt_in.video.i_width ?: 16; id->p_encoder->fmt_in.video.i_height = - id->p_encoder->fmt_out.video.i_height ? - id->p_encoder->fmt_out.video.i_height : - id->p_decoder->fmt_in.video.i_height ? - id->p_decoder->fmt_in.video.i_height : 16; + id->p_encoder->fmt_out.video.i_height ?: + id->p_decoder->fmt_in.video.i_height ?: 16; id->p_encoder->fmt_in.video.i_frame_rate = ENC_FRAMERATE; id->p_encoder->fmt_in.video.i_frame_rate_base = ENC_FRAMERATE_BASE; @@ -1835,9 +1547,12 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) module_Need( id->p_encoder, "encoder", p_sys->psz_venc, true ); if( !id->p_encoder->p_module ) { - msg_Err( p_stream, "cannot find encoder (%s)", p_sys->psz_venc ); + msg_Err( p_stream, "cannot find video encoder (module:%s fourcc:%4.4s)", + p_sys->psz_venc ? p_sys->psz_venc : "any", + (char *)&p_sys->i_vcodec ); module_Unneed( id->p_decoder, id->p_decoder->p_module ); id->p_decoder->p_module = 0; + free( id->p_decoder->p_owner ); return VLC_EGENERIC; } @@ -1858,7 +1573,7 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) VLC_THREAD_PRIORITY_VIDEO; p_sys->id_video = id; vlc_mutex_init( &p_sys->lock_out ); - vlc_cond_init( p_stream, &p_sys->cond ); + vlc_cond_init( &p_sys->cond ); memset( p_sys->pp_pics, 0, sizeof(p_sys->pp_pics) ); p_sys->i_first_pic = 0; p_sys->i_last_pic = 0; @@ -1870,6 +1585,7 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) msg_Err( p_stream, "cannot spawn encoder thread" ); module_Unneed( id->p_decoder, id->p_decoder->p_module ); id->p_decoder->p_module = 0; + free( id->p_decoder->p_owner ); return VLC_EGENERIC; } } @@ -1877,42 +1593,34 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id ) return VLC_SUCCESS; } -static int transcode_video_encoder_open( sout_stream_t *p_stream, - sout_stream_id_t *id ) +static void transcode_video_encoder_init( sout_stream_t *p_stream, + sout_stream_id_t *id ) { - sout_stream_sys_t *p_sys = p_stream->p_sys; - - /* Calculate scaling, padding, cropping etc. - * width/height of source */ - int i_src_width = id->p_decoder->fmt_out.video.i_width; - int i_src_height = id->p_decoder->fmt_out.video.i_height; + sout_stream_sys_t *p_sys = p_stream->p_sys; - /* with/height scaling */ - float f_scale_width = 1; - float f_scale_height = 1; + /* Calculate scaling + * width/height of source */ + int i_src_width = id->p_decoder->fmt_out.video.i_width; + int i_src_height = id->p_decoder->fmt_out.video.i_height; - /* width/height of output stream */ - int i_dst_width; - int i_dst_height; + /* with/height scaling */ + float f_scale_width = 1; + float f_scale_height = 1; - /* aspect ratio */ - float f_aspect = (float)id->p_decoder->fmt_out.video.i_aspect / - VOUT_ASPECT_FACTOR; + /* width/height of output stream */ + int i_dst_width; + int i_dst_height; - msg_Dbg( p_stream, "decoder aspect is %i:%i", - id->p_decoder->fmt_out.video.i_aspect, VOUT_ASPECT_FACTOR ); + /* aspect ratio */ + float f_aspect = (float)id->p_decoder->fmt_out.video.i_aspect / + VOUT_ASPECT_FACTOR; - /* Change f_aspect from source frame to source pixel */ - f_aspect = f_aspect * i_src_height / i_src_width; - msg_Dbg( p_stream, "source pixel aspect is %f:1", f_aspect ); + msg_Dbg( p_stream, "decoder aspect is %i:%i", + id->p_decoder->fmt_out.video.i_aspect, VOUT_ASPECT_FACTOR ); - /* width/height after cropping */ - p_sys->i_src_x_offset = p_sys->i_crop_left & ~1; - p_sys->i_src_y_offset = p_sys->i_crop_top & ~1; - p_sys->i_crop_width = i_src_width - ( p_sys->i_crop_left & ~1 ) - - ( p_sys->i_crop_right & ~1 ); - p_sys->i_crop_height = i_src_height - ( p_sys->i_crop_top & ~1 ) - - ( p_sys->i_crop_bottom & ~1 ); + /* Change f_aspect from source frame to source pixel */ + f_aspect = f_aspect * i_src_height / i_src_width; + msg_Dbg( p_stream, "source pixel aspect is %f:1", f_aspect ); /* Calculate scaling factor for specified parameters */ if( id->p_encoder->fmt_out.video.i_width <= 0 && @@ -1939,168 +1647,66 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream, id->p_encoder->fmt_out.video.i_height <= 0 ) { /* Only width specified */ - f_scale_width = (float)id->p_encoder->fmt_out.video.i_width / - p_sys->i_crop_width; + f_scale_width = (float)id->p_encoder->fmt_out.video.i_width/i_src_width; f_scale_height = f_scale_width; } else if( id->p_encoder->fmt_out.video.i_width <= 0 && id->p_encoder->fmt_out.video.i_height > 0 ) { /* Only height specified */ - f_scale_height = (float)id->p_encoder->fmt_out.video.i_height / - p_sys->i_crop_height; + f_scale_height = (float)id->p_encoder->fmt_out.video.i_height/i_src_height; f_scale_width = f_scale_height; } else if( id->p_encoder->fmt_out.video.i_width > 0 && id->p_encoder->fmt_out.video.i_height > 0 ) { /* Width and height specified */ - f_scale_width = (float)id->p_encoder->fmt_out.video.i_width - / p_sys->i_crop_width; - f_scale_height = (float)id->p_encoder->fmt_out.video.i_height - / p_sys->i_crop_height; + f_scale_width = (float)id->p_encoder->fmt_out.video.i_width/i_src_width; + f_scale_height = (float)id->p_encoder->fmt_out.video.i_height/i_src_height; } /* check maxwidth and maxheight - * note: maxwidth and maxheight currently does not handle - * canvas and padding, just scaling and cropping. */ if( p_sys->i_maxwidth && f_scale_width > (float)p_sys->i_maxwidth / - p_sys->i_crop_width ) + i_src_width ) { - f_scale_width = (float)p_sys->i_maxwidth / p_sys->i_crop_width; + f_scale_width = (float)p_sys->i_maxwidth / i_src_width; } if( p_sys->i_maxheight && f_scale_height > (float)p_sys->i_maxheight / - p_sys->i_crop_height ) + i_src_height ) { - f_scale_height = (float)p_sys->i_maxheight / p_sys->i_crop_height; + f_scale_height = (float)p_sys->i_maxheight / i_src_height; } + /* Change aspect ratio from source pixel to scaled pixel */ f_aspect = f_aspect * f_scale_height / f_scale_width; msg_Dbg( p_stream, "scaled pixel aspect is %f:1", f_aspect ); - /* Correct scaling for target aspect ratio - * Shrink video if necessary - */ - if ( p_sys->i_canvas_aspect > 0 ) - { - float f_target_aspect = (float)p_sys->i_canvas_aspect / - VOUT_ASPECT_FACTOR; - - if( p_sys->i_canvas_width > 0 && p_sys->i_canvas_height > 0) - { - /* Calculate pixel aspect of canvas */ - f_target_aspect = f_target_aspect / p_sys->i_canvas_width * - p_sys->i_canvas_height; - } - if( f_target_aspect > f_aspect ) - { - /* Reduce width scale to increase aspect */ - f_scale_width = f_scale_width * f_aspect / f_target_aspect; - } - else - { - /* Reduce height scale to decrease aspect */ - f_scale_height = f_scale_height * f_target_aspect / f_aspect; - } - f_aspect = f_target_aspect; - msg_Dbg( p_stream, "canvas scaled pixel aspect is %f:1", f_aspect ); - } - /* f_scale_width and f_scale_height are now final */ /* Calculate width, height from scaling * Make sure its multiple of 2 */ - i_dst_width = 2 * (int)( p_sys->i_crop_width * f_scale_width / 2 + 0.5 ); - i_dst_height = 2 * - (int)( p_sys->i_crop_height * f_scale_height / 2 + 0.5 ); - - p_sys->i_nopadd_width = i_dst_width; - p_sys->i_nopadd_height = i_dst_height; - p_sys->i_dst_x_offset = 0; - p_sys->i_dst_y_offset = 0; - - /* Handle canvas and padding */ - if( p_sys->i_canvas_width <= 0 ) - { - /* No canvas width set, add explicit padding border */ - i_dst_width = p_sys->i_nopadd_width + ( p_sys->i_padd_left & ~1 ) + - ( p_sys->i_padd_right & ~1 ); - p_sys->i_dst_x_offset = ( p_sys->i_padd_left & ~1 ); - } - else - { - /* Canvas set, check if we have to padd or crop */ - if( p_sys->i_canvas_width < p_sys->i_nopadd_width ) - { - /* need to crop more, but keep same scaling */ - int i_crop = 2 * (int)( ( p_sys->i_canvas_width & ~1 ) / - f_scale_width / 2 + 0.5 ); - - p_sys->i_src_x_offset += ( ( p_sys->i_crop_width - i_crop ) / 2 ) - & ~1; - p_sys->i_crop_width = i_crop; - i_dst_width = p_sys->i_canvas_width & ~1; - p_sys->i_nopadd_width = i_dst_width; - } - else if( p_sys->i_canvas_width > p_sys->i_nopadd_width ) - { - /* need to padd */ - i_dst_width = p_sys->i_canvas_width & ~1; - p_sys->i_dst_x_offset = ( i_dst_width - p_sys->i_nopadd_width )/2; - p_sys->i_dst_x_offset = p_sys->i_dst_x_offset & ~1; - } - } - - if( p_sys->i_canvas_height <= 0 ) - { - /* No canvas set, add padding border */ - i_dst_height = p_sys->i_nopadd_height + ( p_sys->i_padd_top & ~1 ) + - ( p_sys->i_padd_bottom & ~1 ); - p_sys->i_dst_y_offset = ( p_sys->i_padd_top & ~1 ); - } - else - { - /* Canvas set, check if we have to padd or crop */ - if( p_sys->i_canvas_height < p_sys->i_nopadd_height ) - { - /* need to crop more, but keep same scaling */ - int i_crop = 2 * (int)( ( p_sys->i_canvas_height & ~1 ) / - f_scale_height / 2 + 0.5 ); - - p_sys->i_src_y_offset += ( ( p_sys->i_crop_height - i_crop ) / 2 ) - & ~1; - p_sys->i_crop_height = i_crop; - i_dst_height = p_sys->i_canvas_height & ~1; - p_sys->i_nopadd_height = i_dst_height; - } - else if( p_sys->i_canvas_height > p_sys->i_nopadd_height ) - { - /* need to padd */ - i_dst_height = p_sys->i_canvas_height & ~1; - p_sys->i_dst_y_offset = ( i_dst_height - p_sys->i_nopadd_height ) - /2; - p_sys->i_dst_y_offset = p_sys->i_dst_y_offset & ~1; - } - } + i_dst_width = 2 * (int)(f_scale_width*i_src_width/2+0.5); + i_dst_height = 2 * (int)(f_scale_height*i_src_height/2+0.5); /* Change aspect ratio from scaled pixel to output frame */ f_aspect = f_aspect * i_dst_width / i_dst_height; /* Store calculated values */ - id->p_encoder->fmt_out.video.i_width = i_dst_width; - id->p_encoder->fmt_out.video.i_height = i_dst_height; + id->p_encoder->fmt_out.video.i_width = + id->p_encoder->fmt_out.video.i_visible_width = i_dst_width; + id->p_encoder->fmt_out.video.i_height = + id->p_encoder->fmt_out.video.i_visible_height = i_dst_height; - id->p_encoder->fmt_in.video.i_width = i_dst_width; - id->p_encoder->fmt_in.video.i_height = i_dst_height; + id->p_encoder->fmt_in.video.i_width = + id->p_encoder->fmt_in.video.i_visible_width = i_dst_width; + id->p_encoder->fmt_in.video.i_height = + id->p_encoder->fmt_in.video.i_visible_height = i_dst_height; - msg_Dbg( p_stream, "source %ix%i, crop %ix%i, " - "destination %ix%i, padding %ix%i", + msg_Dbg( p_stream, "source %ix%i, destination %ix%i", i_src_width, i_src_height, - p_sys->i_crop_width, p_sys->i_crop_height, - p_sys->i_nopadd_width, p_sys->i_nopadd_height, i_dst_width, i_dst_height ); @@ -2145,11 +1751,26 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream, msg_Dbg( p_stream, "encoder aspect is %i:%i", id->p_encoder->fmt_out.video.i_aspect, VOUT_ASPECT_FACTOR ); + id->p_encoder->fmt_in.video.i_chroma = id->p_encoder->fmt_in.i_codec; +} + +static int transcode_video_encoder_open( sout_stream_t *p_stream, + sout_stream_id_t *id ) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + + + msg_Dbg( p_stream, "destination (after video filters) %ix%i", + id->p_encoder->fmt_in.video.i_width, + id->p_encoder->fmt_in.video.i_height ); + id->p_encoder->p_module = module_Need( id->p_encoder, "encoder", p_sys->psz_venc, true ); if( !id->p_encoder->p_module ) { - msg_Err( p_stream, "cannot find encoder (%s)", p_sys->psz_venc ); + msg_Err( p_stream, "cannot find video encoder (module:%s fourcc:%4.4s)", + p_sys->psz_venc ? p_sys->psz_venc : "any", + (char *)&p_sys->i_vcodec ); return VLC_EGENERIC; } @@ -2212,19 +1833,10 @@ static void transcode_video_close( sout_stream_t *p_stream, module_Unneed( id->p_encoder, id->p_encoder->p_module ); /* Close filters */ - for( i = 0; i < id->i_filter; i++ ) - { - transcode_video_filter_close( p_stream, id->pp_filter[i] ); - id->pp_filter[i] = NULL; - } - id->i_filter = 0; - - for( i = 0; i < id->i_ufilter; i++ ) - { - transcode_video_filter_close( p_stream, id->pp_ufilter[i] ); - id->pp_ufilter[i] = NULL; - } - id->i_ufilter = 0; + if( id->p_f_chain ) + filter_chain_Delete( id->p_f_chain ); + if( id->p_uf_chain ) + filter_chain_Delete( id->p_uf_chain ); } static int transcode_video_process( sout_stream_t *p_stream, @@ -2232,7 +1844,7 @@ static int transcode_video_process( sout_stream_t *p_stream, block_t *in, block_t **out ) { sout_stream_sys_t *p_sys = p_stream->p_sys; - int i_duplicate = 1, i; + int i_duplicate = 1; picture_t *p_pic, *p_pic2 = NULL; *out = NULL; @@ -2295,29 +1907,25 @@ static int transcode_video_process( sout_stream_t *p_stream, if( !id->p_encoder->p_module ) { - if( transcode_video_encoder_open( p_stream, id ) != VLC_SUCCESS ) - { - p_pic->pf_release( p_pic ); - transcode_video_close( p_stream, id ); - id->b_transcode = false; - return VLC_EGENERIC; - } + transcode_video_encoder_init( p_stream, id ); + + id->p_f_chain = filter_chain_New( p_stream, "video filter2", + false, + transcode_video_filter_allocation_init, + transcode_video_filter_allocation_clear, + p_stream->p_sys ); /* Deinterlace */ if( p_stream->p_sys->b_deinterlace ) { - id->pp_filter[id->i_filter] = - transcode_video_filter_new( p_stream, - &id->p_decoder->fmt_out, - &id->p_decoder->fmt_out, - p_sys->p_deinterlace_cfg, - p_sys->psz_deinterlace ); - - if( id->pp_filter[id->i_filter] ) - id->i_filter++; + filter_chain_AppendFilter( id->p_f_chain, + p_sys->psz_deinterlace, + p_sys->p_deinterlace_cfg, + &id->p_decoder->fmt_out, + &id->p_decoder->fmt_out ); } -#if (defined(HAVE_FFMPEG_SWSCALE_H) || defined(HAVE_LIBSWSCALE_TREE)) || defined(HAVE_LIBSWSCALE_SWSCALE_H) + /* Take care of the scaling and chroma conversions */ if( ( id->p_decoder->fmt_out.video.i_chroma != id->p_encoder->fmt_in.video.i_chroma ) || ( id->p_decoder->fmt_out.video.i_width != @@ -2325,121 +1933,45 @@ static int transcode_video_process( sout_stream_t *p_stream, ( id->p_decoder->fmt_out.video.i_height != id->p_encoder->fmt_in.video.i_height ) ) { - id->pp_filter[id->i_filter] = - transcode_video_filter_new( p_stream, - &id->p_decoder->fmt_out, - &id->p_encoder->fmt_in, - NULL, "scale" ); - if( !id->pp_filter[id->i_filter] ) - { - p_pic->pf_release( p_pic ); - transcode_video_close( p_stream, id ); - id->b_transcode = false; - return VLC_EGENERIC; - } - id->i_filter++; - } -#if 0 /* FIXME: */ - /* we don't do chroma conversion or scaling in croppad */ -// es_format_t fmt_in, fmt_out; -// es_format_Copy( &fmt_out, &id->p_encoder->fmt_in ); -// es_format_Copy( &fmt_in, &id->p_encoder->fmt_in ); - - if( ( id->p_decoder->fmt_out.video.i_chroma == - id->p_encoder->fmt_in.video.i_chroma ) && - - ( ( (int)id->p_decoder->fmt_out.video.i_width != - p_sys->i_crop_width ) || - ( p_sys->i_crop_width != p_sys->i_nopadd_width ) || - ( p_sys->i_nopadd_width != - (int)id->p_encoder->fmt_out.video.i_width ) || - - ( (int)id->p_decoder->fmt_out.video.i_height != - p_sys->i_crop_height ) || - ( p_sys->i_crop_height != p_sys->i_nopadd_height ) || - ( p_sys->i_nopadd_height != - (int)id->p_encoder->fmt_out.video.i_height ) ) ) - { - id->pp_filter[id->i_filter] = - transcode_video_filter_new( p_stream, - &id->p_decoder->fmt_out, - &id->p_encoder->fmt_in, - NULL, "croppadd" ); - if( id->pp_filter[id->i_filter] ) - { - /* Set crop and padding information */ - id->pp_filter[id->i_filter]->fmt_in.video.i_x_offset = p_sys->i_src_x_offset; - id->pp_filter[id->i_filter]->fmt_in.video.i_y_offset = p_sys->i_src_y_offset; - id->pp_filter[id->i_filter]->fmt_in.video.i_visible_width = p_sys->i_crop_width; - id->pp_filter[id->i_filter]->fmt_in.video.i_visible_height = p_sys->i_crop_height; - - id->pp_filter[id->i_filter]->fmt_out.video.i_x_offset = p_sys->i_dst_x_offset; - id->pp_filter[id->i_filter]->fmt_out.video.i_y_offset = p_sys->i_dst_y_offset; - id->pp_filter[id->i_filter]->fmt_out.video.i_visible_width = p_sys->i_nopadd_width; - id->pp_filter[id->i_filter]->fmt_out.video.i_visible_height = p_sys->i_nopadd_height; - - id->i_filter++; - } + filter_chain_AppendFilter( id->p_f_chain, + NULL, NULL, + &id->p_decoder->fmt_out, + &id->p_encoder->fmt_in ); } -#endif -#else - /* Check if we need a filter for chroma conversion or resizing */ - if( id->p_decoder->fmt_out.video.i_chroma != - id->p_encoder->fmt_in.video.i_chroma || - - (int)id->p_decoder->fmt_out.video.i_width != p_sys->i_crop_width || - p_sys->i_crop_width != p_sys->i_nopadd_width || - p_sys->i_nopadd_width != (int)id->p_encoder->fmt_out.video.i_width || - (int)id->p_decoder->fmt_out.video.i_height != p_sys->i_crop_height || - p_sys->i_crop_height != p_sys->i_nopadd_height || - p_sys->i_nopadd_height != (int)id->p_encoder->fmt_out.video.i_height) + if( p_sys->psz_vf2 ) { - id->pp_filter[id->i_filter] = - transcode_video_filter_new( p_stream, - &id->p_decoder->fmt_out, - &id->p_encoder->fmt_in, - NULL, "crop padd" ); - if( !id->pp_filter[id->i_filter] ) - { - p_pic->pf_release( p_pic ); - transcode_video_close( p_stream, id ); - id->b_transcode = false; - return VLC_EGENERIC; - } - - /* Set crop and padding information */ - id->pp_filter[id->i_filter]->fmt_in.video.i_x_offset = p_sys->i_src_x_offset; - id->pp_filter[id->i_filter]->fmt_in.video.i_y_offset = p_sys->i_src_y_offset; - id->pp_filter[id->i_filter]->fmt_in.video.i_visible_width = p_sys->i_crop_width; - id->pp_filter[id->i_filter]->fmt_in.video.i_visible_height = p_sys->i_crop_height; - - id->pp_filter[id->i_filter]->fmt_out.video.i_x_offset = p_sys->i_dst_x_offset; - id->pp_filter[id->i_filter]->fmt_out.video.i_y_offset = p_sys->i_dst_y_offset; - id->pp_filter[id->i_filter]->fmt_out.video.i_visible_width = p_sys->i_nopadd_width; - id->pp_filter[id->i_filter]->fmt_out.video.i_visible_height = p_sys->i_nopadd_height; - - id->i_filter++; + const es_format_t *p_fmt_out; + id->p_uf_chain = filter_chain_New( p_stream, "video filter2", + true, + transcode_video_filter_allocation_init, + transcode_video_filter_allocation_clear, + p_stream->p_sys ); + filter_chain_Reset( id->p_uf_chain, &id->p_encoder->fmt_in, + &id->p_encoder->fmt_in ); + filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_vf2 ); + p_fmt_out = filter_chain_GetFmtOut( id->p_uf_chain ); + es_format_Copy( &id->p_encoder->fmt_in, p_fmt_out ); + id->p_encoder->fmt_out.video.i_width = + id->p_encoder->fmt_in.video.i_width; + id->p_encoder->fmt_out.video.i_height = + id->p_encoder->fmt_in.video.i_height; + id->p_encoder->fmt_out.video.i_aspect = + id->p_encoder->fmt_in.video.i_aspect; } -#endif - for( i = 0; (i < p_sys->i_vfilters) && (id->i_ufilter < TRANSCODE_FILTERS); i++ ) + + if( transcode_video_encoder_open( p_stream, id ) != VLC_SUCCESS ) { - id->pp_ufilter[id->i_ufilter] = - transcode_video_filter_new( p_stream, - &id->p_decoder->fmt_out, &id->p_encoder->fmt_in, - p_sys->p_vfilters_cfg[i], p_sys->psz_vfilters[i] ); - if( id->pp_ufilter[id->i_filter] ) - id->i_ufilter++; - else - id->pp_ufilter[id->i_ufilter] = NULL; + p_pic->pf_release( p_pic ); + transcode_video_close( p_stream, id ); + id->b_transcode = false; + return VLC_EGENERIC; } } /* Run filter chain */ - for( i = 0; i < id->i_filter; i++ ) - { - p_pic = id->pp_filter[i]->pf_video_filter(id->pp_filter[i], p_pic); - } + if( id->p_f_chain ) + p_pic = filter_chain_VideoFilter( id->p_f_chain, p_pic ); /* * Encoding @@ -2457,14 +1989,14 @@ static int transcode_video_process( sout_stream_t *p_stream, if( p_subpic ) { int i_scale_width, i_scale_height; - video_format_t *p_fmt; + video_format_t fmt; i_scale_width = id->p_encoder->fmt_in.video.i_width * 1000 / id->p_decoder->fmt_out.video.i_width; i_scale_height = id->p_encoder->fmt_in.video.i_height * 1000 / id->p_decoder->fmt_out.video.i_height; - if( p_pic->i_refcount && !id->i_filter ) + if( p_pic->i_refcount && !filter_chain_GetLength( id->p_f_chain ) ) { /* We can't modify the picture, we need to duplicate it */ picture_t *p_tmp = video_new_buffer_decoder( id->p_decoder ); @@ -2476,26 +2008,22 @@ static int transcode_video_process( sout_stream_t *p_stream, } } - if( id->i_filter ) - p_fmt = &id->pp_filter[id->i_filter -1]->fmt_out.video; + if( filter_chain_GetLength( id->p_f_chain ) > 0 ) + fmt = filter_chain_GetFmtOut( id->p_f_chain )->video; else - p_fmt = &id->p_decoder->fmt_out.video; + fmt = id->p_decoder->fmt_out.video; /* FIXME (shouldn't have to be done here) */ - p_fmt->i_sar_num = p_fmt->i_aspect * - p_fmt->i_height / p_fmt->i_width; - p_fmt->i_sar_den = VOUT_ASPECT_FACTOR; + fmt.i_sar_num = fmt.i_aspect * fmt.i_height / fmt.i_width; + fmt.i_sar_den = VOUT_ASPECT_FACTOR; - spu_RenderSubpictures( p_sys->p_spu, p_fmt, p_pic, p_pic, p_subpic, + spu_RenderSubpictures( p_sys->p_spu, &fmt, p_pic, p_subpic, i_scale_width, i_scale_height ); } /* Run user specified filter chain */ - for( i = 0; i < id->i_ufilter; i++ ) - { - p_pic = id->pp_ufilter[i]->pf_video_filter( id->pp_ufilter[i], - p_pic ); - } + if( id->p_uf_chain ) + p_pic = filter_chain_VideoFilter( id->p_uf_chain, p_pic ); if( p_sys->i_threads == 0 ) { @@ -2578,12 +2106,14 @@ static int transcode_video_process( sout_stream_t *p_stream, return VLC_SUCCESS; } -static int EncoderThread( sout_stream_sys_t *p_sys ) +static void* EncoderThread( vlc_object_t* p_this ) { + sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_this; sout_stream_id_t *id = p_sys->id_video; picture_t *p_pic; + int canc = vlc_savecancel (); - while( !p_sys->b_die && !p_sys->b_error ) + while( vlc_object_alive (p_sys) && !p_sys->b_error ) { block_t *p_block; @@ -2591,9 +2121,9 @@ static int EncoderThread( sout_stream_sys_t *p_sys ) while( p_sys->i_last_pic == p_sys->i_first_pic ) { vlc_cond_wait( &p_sys->cond, &p_sys->lock_out ); - if( p_sys->b_die || p_sys->b_error ) break; + if( !vlc_object_alive (p_sys) || p_sys->b_error ) break; } - if( p_sys->b_die || p_sys->b_error ) + if( !vlc_object_alive (p_sys) || p_sys->b_error ) { vlc_mutex_unlock( &p_sys->lock_out ); break; @@ -2622,7 +2152,8 @@ static int EncoderThread( sout_stream_sys_t *p_sys ) } block_ChainRelease( p_sys->p_buffers ); - return 0; + vlc_restorecancel (canc); + return NULL; } struct picture_sys_t @@ -2747,6 +2278,7 @@ static void video_del_buffer( vlc_object_t *p_this, picture_t *p_pic ) VLC_UNUSED(p_this); if( p_pic ) { + free( p_pic->p_q ); free( p_pic->p_data_orig ); free( p_pic->p_sys ); free( p_pic ); @@ -2758,6 +2290,7 @@ static void video_del_buffer_decoder( decoder_t *p_decoder, picture_t *p_pic ) VLC_UNUSED(p_decoder); p_pic->i_refcount = 0; p_pic->i_status = DESTROYED_PICTURE; + picture_CleanupQuant( p_pic ); } static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic ) @@ -2765,6 +2298,7 @@ static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic ) VLC_UNUSED(p_filter); p_pic->i_refcount = 0; p_pic->i_status = DESTROYED_PICTURE; + picture_CleanupQuant( p_pic ); } static void video_link_picture_decoder( decoder_t *p_dec, picture_t *p_pic ) @@ -2805,7 +2339,7 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id ) if( !id->p_decoder->p_module ) { - msg_Err( p_stream, "cannot find decoder" ); + msg_Err( p_stream, "cannot find spu decoder" ); return VLC_EGENERIC; } @@ -2824,7 +2358,7 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id ) if( !id->p_encoder->p_module ) { module_Unneed( id->p_decoder, id->p_decoder->p_module ); - msg_Err( p_stream, "cannot find encoder (%s)", p_sys->psz_senc ); + msg_Err( p_stream, "cannot find spu encoder (%s)", p_sys->psz_senc ); return VLC_EGENERIC; } } @@ -2932,7 +2466,7 @@ static int transcode_osd_new( sout_stream_t *p_stream, sout_stream_id_t *id ) if( !id->p_encoder->p_module ) { - msg_Err( p_stream, "cannot find encoder (%s)", p_sys->psz_osdenc ); + msg_Err( p_stream, "cannot find spu encoder (%s)", p_sys->psz_osdenc ); goto error; } @@ -2973,7 +2507,7 @@ static void transcode_osd_close( sout_stream_t *p_stream, sout_stream_id_t *id) sout_stream_sys_t *p_sys = p_stream->p_sys; /* Close encoder */ - if( p_sys->b_osd && id ) + if( id ) { if( id->p_encoder->p_module ) module_Unneed( id->p_encoder, id->p_encoder->p_module );