static void transcode_video_encoder_init( sout_stream_t *p_stream, sout_stream_id_sys_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; const es_format_t *p_fmt_out = &id->p_decoder->fmt_out; if( id->p_f_chain ) { p_fmt_out = filter_chain_GetFmtOut( id->p_f_chain ); } if( id->p_uf_chain ) { p_fmt_out = filter_chain_GetFmtOut( id->p_uf_chain ); } /* Calculate scaling * width/height of source */ int i_src_visible_width = p_fmt_out->video.i_visible_width; int i_src_visible_height = p_fmt_out->video.i_visible_height; if (i_src_visible_width == 0) i_src_visible_width = p_fmt_out->video.i_width; if (i_src_visible_height == 0) i_src_visible_height = p_fmt_out->video.i_height; /* with/height scaling */ float f_scale_width = 1; float f_scale_height = 1; /* aspect ratio */ float f_aspect = (double)p_fmt_out->video.i_sar_num * p_fmt_out->video.i_width / p_fmt_out->video.i_sar_den / p_fmt_out->video.i_height; msg_Dbg( p_stream, "decoder aspect is %f:1", f_aspect ); /* Change f_aspect from source frame to source pixel */ f_aspect = f_aspect * i_src_visible_height / i_src_visible_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_visible_width <= 0 && id->p_encoder->fmt_out.video.i_visible_height <= 0 && p_sys->f_scale ) { /* Global scaling. Make sure width will remain a factor of 16 */ float f_real_scale; int i_new_height; int i_new_width = i_src_visible_width * p_sys->f_scale; if( i_new_width % 16 <= 7 && i_new_width >= 16 ) i_new_width -= i_new_width % 16; else i_new_width += 16 - i_new_width % 16; f_real_scale = (float)( i_new_width ) / (float) i_src_visible_width; i_new_height = __MAX( 16, i_src_visible_height * (float)f_real_scale ); f_scale_width = f_real_scale; f_scale_height = (float) i_new_height / (float) i_src_visible_height; } else if( id->p_encoder->fmt_out.video.i_visible_width > 0 && id->p_encoder->fmt_out.video.i_visible_height <= 0 ) { /* Only width specified */ f_scale_width = (float)id->p_encoder->fmt_out.video.i_visible_width/i_src_visible_width; f_scale_height = f_scale_width; } else if( id->p_encoder->fmt_out.video.i_visible_width <= 0 && id->p_encoder->fmt_out.video.i_visible_height > 0 ) { /* Only height specified */ f_scale_height = (float)id->p_encoder->fmt_out.video.i_visible_height/i_src_visible_height; f_scale_width = f_scale_height; } else if( id->p_encoder->fmt_out.video.i_visible_width > 0 && id->p_encoder->fmt_out.video.i_visible_height > 0 ) { /* Width and height specified */ f_scale_width = (float)id->p_encoder->fmt_out.video.i_visible_width/i_src_visible_width; f_scale_height = (float)id->p_encoder->fmt_out.video.i_visible_height/i_src_visible_height; } /* check maxwidth and maxheight */ if( p_sys->i_maxwidth && f_scale_width > (float)p_sys->i_maxwidth / i_src_visible_width ) { f_scale_width = (float)p_sys->i_maxwidth / i_src_visible_width; } if( p_sys->i_maxheight && f_scale_height > (float)p_sys->i_maxheight / i_src_visible_height ) { f_scale_height = (float)p_sys->i_maxheight / i_src_visible_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 ); /* f_scale_width and f_scale_height are now final */ /* Calculate width, height from scaling * Make sure its multiple of 2 */ /* width/height of output stream */ int i_dst_visible_width = 2 * (int)(f_scale_width*i_src_visible_width/2+0.5); int i_dst_visible_height = 2 * (int)(f_scale_height*i_src_visible_height/2+0.5); int i_dst_width = 2 * (int)(f_scale_width*p_fmt_out->video.i_width/2+0.5); int i_dst_height = 2 * (int)(f_scale_height*p_fmt_out->video.i_height/2+0.5); /* Change aspect ratio from scaled pixel to output frame */ f_aspect = f_aspect * i_dst_visible_width / i_dst_visible_height; /* Store calculated values */ id->p_encoder->fmt_out.video.i_width = i_dst_width; id->p_encoder->fmt_out.video.i_visible_width = i_dst_visible_width; id->p_encoder->fmt_out.video.i_height = i_dst_height; id->p_encoder->fmt_out.video.i_visible_height = i_dst_visible_height; id->p_encoder->fmt_in.video.i_width = i_dst_width; id->p_encoder->fmt_in.video.i_visible_width = i_dst_visible_width; id->p_encoder->fmt_in.video.i_height = i_dst_height; id->p_encoder->fmt_in.video.i_visible_height = i_dst_visible_height; msg_Dbg( p_stream, "source %ix%i, destination %ix%i", i_src_visible_width, i_src_visible_height, i_dst_visible_width, i_dst_visible_height ); /* Handle frame rate conversion */ if( !id->p_encoder->fmt_out.video.i_frame_rate || !id->p_encoder->fmt_out.video.i_frame_rate_base ) { if( p_fmt_out->video.i_frame_rate && p_fmt_out->video.i_frame_rate_base ) { id->p_encoder->fmt_out.video.i_frame_rate = p_fmt_out->video.i_frame_rate; id->p_encoder->fmt_out.video.i_frame_rate_base = p_fmt_out->video.i_frame_rate_base; } else { /* Pick a sensible default value */ id->p_encoder->fmt_out.video.i_frame_rate = ENC_FRAMERATE; id->p_encoder->fmt_out.video.i_frame_rate_base = ENC_FRAMERATE_BASE; } } id->p_encoder->fmt_in.video.orientation = id->p_encoder->fmt_out.video.orientation = id->p_decoder->fmt_in.video.orientation; id->p_encoder->fmt_in.video.i_frame_rate = id->p_encoder->fmt_out.video.i_frame_rate; id->p_encoder->fmt_in.video.i_frame_rate_base = id->p_encoder->fmt_out.video.i_frame_rate_base; vlc_ureduce( &id->p_encoder->fmt_in.video.i_frame_rate, &id->p_encoder->fmt_in.video.i_frame_rate_base, id->p_encoder->fmt_in.video.i_frame_rate, id->p_encoder->fmt_in.video.i_frame_rate_base, 0 ); msg_Dbg( p_stream, "source fps %d/%d, destination %d/%d", id->p_decoder->fmt_out.video.i_frame_rate, id->p_decoder->fmt_out.video.i_frame_rate_base, id->p_encoder->fmt_in.video.i_frame_rate, id->p_encoder->fmt_in.video.i_frame_rate_base ); id->i_input_frame_interval = id->p_decoder->fmt_out.video.i_frame_rate_base * CLOCK_FREQ / id->p_decoder->fmt_out.video.i_frame_rate; msg_Info( p_stream, "input interval %d (base %d)", id->i_input_frame_interval, id->p_decoder->fmt_out.video.i_frame_rate_base ); id->i_output_frame_interval = id->p_encoder->fmt_in.video.i_frame_rate_base * CLOCK_FREQ / id->p_encoder->fmt_in.video.i_frame_rate; msg_Info( p_stream, "output interval %d (base %d)", id->i_output_frame_interval, id->p_encoder->fmt_in.video.i_frame_rate_base ); date_Init( &id->next_input_pts, id->p_decoder->fmt_out.video.i_frame_rate, 1 ); date_Init( &id->next_output_pts, id->p_encoder->fmt_in.video.i_frame_rate, 1 ); /* Check whether a particular aspect ratio was requested */ if( id->p_encoder->fmt_out.video.i_sar_num <= 0 || id->p_encoder->fmt_out.video.i_sar_den <= 0 ) { vlc_ureduce( &id->p_encoder->fmt_out.video.i_sar_num, &id->p_encoder->fmt_out.video.i_sar_den, (uint64_t)p_fmt_out->video.i_sar_num * i_src_visible_width * i_dst_visible_height, (uint64_t)p_fmt_out->video.i_sar_den * i_src_visible_height * i_dst_visible_width, 0 ); } else { vlc_ureduce( &id->p_encoder->fmt_out.video.i_sar_num, &id->p_encoder->fmt_out.video.i_sar_den, id->p_encoder->fmt_out.video.i_sar_num, id->p_encoder->fmt_out.video.i_sar_den, 0 ); } id->p_encoder->fmt_in.video.i_sar_num = id->p_encoder->fmt_out.video.i_sar_num; id->p_encoder->fmt_in.video.i_sar_den = id->p_encoder->fmt_out.video.i_sar_den; msg_Dbg( p_stream, "encoder aspect is %i:%i", id->p_encoder->fmt_out.video.i_sar_num * id->p_encoder->fmt_out.video.i_width, id->p_encoder->fmt_out.video.i_sar_den * id->p_encoder->fmt_out.video.i_height ); }
static void transcode_video_filter_init( sout_stream_t *p_stream, sout_stream_id_sys_t *id ) { es_format_t *p_fmt_out = &id->p_decoder->fmt_out; id->p_encoder->fmt_in.video.i_chroma = id->p_encoder->fmt_in.i_codec; 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 ); filter_chain_Reset( id->p_f_chain, p_fmt_out, p_fmt_out ); /* Deinterlace */ if( p_stream->p_sys->b_deinterlace ) { filter_chain_AppendFilter( id->p_f_chain, p_stream->p_sys->psz_deinterlace, p_stream->p_sys->p_deinterlace_cfg, &id->p_decoder->fmt_out, &id->p_decoder->fmt_out ); p_fmt_out = filter_chain_GetFmtOut( id->p_f_chain ); } /* Check that we have visible_width/height*/ if( !p_fmt_out->video.i_visible_height ) p_fmt_out->video.i_visible_height = p_fmt_out->video.i_height; if( !p_fmt_out->video.i_visible_width ) p_fmt_out->video.i_visible_width = p_fmt_out->video.i_width; if( p_stream->p_sys->psz_vf2 ) { 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, p_fmt_out, &id->p_encoder->fmt_in ); if( p_fmt_out->video.i_chroma != id->p_encoder->fmt_in.video.i_chroma ) { filter_chain_AppendFilter( id->p_uf_chain, NULL, NULL, p_fmt_out, &id->p_encoder->fmt_in ); } filter_chain_AppendFromString( id->p_uf_chain, p_stream->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_sar_num = id->p_encoder->fmt_in.video.i_sar_num; id->p_encoder->fmt_out.video.i_sar_den = id->p_encoder->fmt_in.video.i_sar_den; } }
int transcode_audio_new( sout_stream_t *p_stream, sout_stream_id_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; es_format_t fmt_last; /* * Open decoder */ /* Initialization of decoder structures */ id->p_decoder->fmt_out = id->p_decoder->fmt_in; id->p_decoder->fmt_out.i_extra = 0; id->p_decoder->fmt_out.p_extra = 0; id->p_decoder->pf_decode_audio = NULL; id->p_decoder->pf_aout_buffer_new = audio_new_buffer; /* id->p_decoder->p_cfg = p_sys->p_audio_cfg; */ id->p_decoder->p_module = module_need( id->p_decoder, "decoder", "$codec", false ); if( !id->p_decoder->p_module ) { msg_Err( p_stream, "cannot find audio decoder" ); return VLC_EGENERIC; } /* decoders don't set audio.i_format, but audio filters use it */ id->p_decoder->fmt_out.audio.i_format = id->p_decoder->fmt_out.i_codec; id->p_decoder->fmt_out.audio.i_bitspersample = 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_CODEC_MP4A && fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate && fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels) ) fmt_last.audio.i_rate = id->p_decoder->fmt_in.audio.i_rate; /* * Open encoder */ /* Initialization of encoder format structures */ es_format_Init( &id->p_encoder->fmt_in, id->p_decoder->fmt_in.i_cat, id->p_decoder->fmt_out.i_codec ); id->p_encoder->fmt_in.audio.i_format = id->p_decoder->fmt_out.i_codec; 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 = id->p_encoder->fmt_out.audio.i_original_channels; id->p_encoder->fmt_in.audio.i_channels = id->p_encoder->fmt_out.audio.i_channels; id->p_encoder->fmt_in.audio.i_bitspersample = 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 audio encoder (module:%s fourcc:%4.4s). Take a look few lines earlier to see possible reason.", 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 = aout_BitsPerSample( id->p_encoder->fmt_in.i_codec ); /* Load user specified audio filters */ if( p_sys->psz_af ) { es_format_t fmt_fl32 = fmt_last; fmt_fl32.i_codec = fmt_fl32.audio.i_format = VLC_CODEC_FL32; id->p_uf_chain = filter_chain_New( p_stream, "audio filter", false, transcode_audio_filter_allocation_init, NULL, NULL ); filter_chain_Reset( id->p_uf_chain, &fmt_last, &fmt_fl32 ); if( transcode_audio_filter_chain_build( p_stream, id->p_uf_chain, &fmt_fl32, &fmt_last ) ) { transcode_audio_close( id ); return VLC_EGENERIC; } fmt_last = fmt_fl32; if( filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_af ) > 0 ) fmt_last = *filter_chain_GetFmtOut( id->p_uf_chain ); } /* Load conversion filters */ id->p_f_chain = filter_chain_New( p_stream, "audio filter", true, transcode_audio_filter_allocation_init, NULL, NULL ); filter_chain_Reset( id->p_f_chain, &fmt_last, &id->p_encoder->fmt_in ); if( transcode_audio_filter_chain_build( p_stream, id->p_f_chain, &id->p_encoder->fmt_in, &fmt_last ) ) { transcode_audio_close( id ); return VLC_EGENERIC; } fmt_last = id->p_encoder->fmt_in; /* */ id->p_encoder->fmt_out.i_codec = vlc_fourcc_GetCodec( AUDIO_ES, id->p_encoder->fmt_out.i_codec ); return VLC_SUCCESS; }
static int transcode_audio_filter_chain_build( sout_stream_t *p_stream, filter_chain_t *p_chain, const es_format_t *p_dst, const es_format_t *p_src ) { if( !transcode_audio_filter_needed( p_dst, p_src ) ) return VLC_SUCCESS; es_format_t current = *p_src; msg_Dbg( p_stream, "Looking for filter " "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)", (const char *)&p_src->i_codec, (const char *)&p_dst->i_codec, p_src->audio.i_channels, p_dst->audio.i_channels, p_src->audio.i_rate, p_dst->audio.i_rate ); /* If any filter is needed, convert to fl32 */ if( current.i_codec != VLC_CODEC_FL32 ) { /* First step, convert to fl32 */ current.i_codec = current.audio.i_format = VLC_CODEC_FL32; aout_FormatPrepare( ¤t.audio ); if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, ¤t ) ) { msg_Err( p_stream, "Failed to find conversion filter to fl32" ); return VLC_EGENERIC; } current = *filter_chain_GetFmtOut( p_chain ); } /* Fix sample rate */ if( current.audio.i_rate != p_dst->audio.i_rate ) { current.audio.i_rate = p_dst->audio.i_rate; aout_FormatPrepare( ¤t.audio ); if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, ¤t ) ) { msg_Err( p_stream, "Failed to find conversion filter for resampling" ); return VLC_EGENERIC; } current = *filter_chain_GetFmtOut( p_chain ); } /* Fix channels */ if( current.audio.i_channels != p_dst->audio.i_channels ) { current.audio.i_channels = p_dst->audio.i_channels; current.audio.i_physical_channels = p_dst->audio.i_physical_channels; current.audio.i_original_channels = p_dst->audio.i_original_channels; if( ( !current.audio.i_physical_channels || !current.audio.i_original_channels ) && current.audio.i_channels < 6 ) current.audio.i_physical_channels = current.audio.i_original_channels = pi_channels_maps[current.audio.i_channels]; aout_FormatPrepare( ¤t.audio ); if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, ¤t ) ) { msg_Err( p_stream, "Failed to find conversion filter for channel mixing" ); return VLC_EGENERIC; } current = *filter_chain_GetFmtOut( p_chain ); } /* And last step, convert to the requested codec */ if( current.i_codec != p_dst->i_codec ) { current.i_codec = p_dst->i_codec; aout_FormatPrepare( ¤t.audio ); if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, ¤t ) ) { msg_Err( p_stream, "Failed to find conversion filter to %4.4s", (const char*)&p_dst->i_codec); return VLC_EGENERIC; } current = *filter_chain_GetFmtOut( p_chain ); } if( transcode_audio_filter_needed( p_dst, ¤t ) ) { /* Weird case, a filter has side effects, doomed */ msg_Err( p_stream, "Failed to create a valid audio filter chain" ); return VLC_EGENERIC; } msg_Dbg( p_stream, "Got complete audio filter chain" ); return VLC_SUCCESS; }
static int Activate( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; unsigned i_canvas_width; /* width of output canvas */ unsigned i_canvas_height; /* height of output canvas */ unsigned i_canvas_aspect; /* canvas PictureAspectRatio */ es_format_t fmt; /* target format after up/down conversion */ char psz_croppadd[100]; int i_padd,i_offset; char *psz_aspect, *psz_parser; bool b_padd; unsigned i_fmt_in_aspect; if( !p_filter->b_allow_fmt_out_change ) { msg_Err( p_filter, "Picture format change isn't allowed" ); return VLC_EGENERIC; } if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma ) { msg_Err( p_filter, "Input and output chromas don't match" ); return VLC_EGENERIC; } config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options, p_filter->p_cfg ); i_canvas_width = var_CreateGetInteger( p_filter, CFG_PREFIX "width" ); i_canvas_height = var_CreateGetInteger( p_filter, CFG_PREFIX "height" ); if( i_canvas_width == 0 || i_canvas_height == 0 ) { msg_Err( p_filter, "Width and height options must be set" ); return VLC_EGENERIC; } if( i_canvas_width & 1 || i_canvas_height & 1 ) { /* If this restriction were ever relaxed, it is very important to * get the field polatiry correct */ msg_Err( p_filter, "Width and height options must be even integers" ); return VLC_EGENERIC; } i_fmt_in_aspect = (int64_t)p_filter->fmt_in.video.i_sar_num * p_filter->fmt_in.video.i_width * VOUT_ASPECT_FACTOR / p_filter->fmt_in.video.i_sar_den / p_filter->fmt_in.video.i_height; psz_aspect = var_CreateGetNonEmptyString( p_filter, CFG_PREFIX "aspect" ); if( psz_aspect ) { psz_parser = strchr( psz_aspect, ':' ); int numerator = atoi( psz_aspect ); int denominator = psz_parser ? atoi( psz_parser+1 ) : 0; denominator = denominator == 0 ? 1 : denominator; i_canvas_aspect = numerator * VOUT_ASPECT_FACTOR / denominator; free( psz_aspect ); if( numerator <= 0 || denominator < 0 ) { msg_Err( p_filter, "Aspect ratio must be strictly positive" ); return VLC_EGENERIC; } } else { /* if there is no user supplied aspect ratio, assume the canvas * has the same sample aspect ratio as the subpicture */ /* aspect = subpic_sar * canvas_width / canvas_height * where subpic_sar = subpic_ph * subpic_par / subpic_pw */ i_canvas_aspect = (uint64_t) p_filter->fmt_in.video.i_height * i_fmt_in_aspect * i_canvas_width / (i_canvas_height * p_filter->fmt_in.video.i_width); } b_padd = var_CreateGetBool( p_filter, CFG_PREFIX "padd" ); filter_sys_t *p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; p_filter->p_sys = p_sys; p_sys->p_chain = filter_chain_New( p_filter, "video filter2", true, alloc_init, NULL, p_filter ); if( !p_sys->p_chain ) { msg_Err( p_filter, "Could not allocate filter chain" ); free( p_sys ); return VLC_EGENERIC; } es_format_Copy( &fmt, &p_filter->fmt_in ); /* one dimension will end up with one of the following: */ fmt.video.i_width = i_canvas_width; fmt.video.i_height = i_canvas_height; if( b_padd ) { /* Padd */ if( i_canvas_aspect > i_fmt_in_aspect ) { /* The canvas has a wider aspect than the subpicture: * ie, pillarbox the [scaled] subpicture */ /* The following is derived form: * width = upconverted_subpic_height * subpic_par / canvas_sar * where canvas_sar = canvas_width / (canvas_height * canvas_par) * then simplify */ fmt.video.i_width = i_canvas_width * i_fmt_in_aspect / i_canvas_aspect; if( fmt.video.i_width & 1 ) fmt.video.i_width -= 1; i_padd = (i_canvas_width - fmt.video.i_width) / 2; i_offset = (i_padd & 1); snprintf( psz_croppadd, 100, "croppadd{paddleft=%d,paddright=%d}", i_padd - i_offset, i_padd + i_offset ); } else { /* The canvas has a taller aspect than the subpicture: * ie, letterbox the [scaled] subpicture */ fmt.video.i_height = i_canvas_height * i_canvas_aspect / i_fmt_in_aspect; if( fmt.video.i_height & 1 ) fmt.video.i_height -= 1; i_padd = (i_canvas_height - fmt.video.i_height ) / 2; i_offset = (i_padd & 1); snprintf( psz_croppadd, 100, "croppadd{paddtop=%d,paddbottom=%d}", i_padd - i_offset, i_padd + i_offset ); } } else { /* Crop */ if( i_canvas_aspect < i_fmt_in_aspect ) { /* The canvas has a narrower aspect than the subpicture: * ie, crop the [scaled] subpicture horizontally */ fmt.video.i_width = i_canvas_width * i_fmt_in_aspect / i_canvas_aspect; if( fmt.video.i_width & 1 ) fmt.video.i_width -= 1; i_padd = (fmt.video.i_width - i_canvas_width) / 2; i_offset = (i_padd & 1); snprintf( psz_croppadd, 100, "croppadd{cropleft=%d,cropright=%d}", i_padd - i_offset, i_padd + i_offset ); } else { /* The canvas has a shorter aspect than the subpicture: * ie, crop the [scaled] subpicture vertically */ fmt.video.i_height = i_canvas_height * i_canvas_aspect / i_fmt_in_aspect; if( fmt.video.i_height & 1 ) fmt.video.i_height -= 1; i_padd = (fmt.video.i_height - i_canvas_height) / 2; i_offset = (i_padd & 1); snprintf( psz_croppadd, 100, "croppadd{croptop=%d,cropbottom=%d}", i_padd - i_offset, i_padd + i_offset ); } } /* xxx, should the clean area include the letter-boxing? * probably not, as some codecs can make use of that information * and it should be a scaled version of the input clean area * -- davidf */ fmt.video.i_visible_width = fmt.video.i_width; fmt.video.i_visible_height = fmt.video.i_height; filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, &fmt ); /* Append scaling module */ filter_chain_AppendFilter( p_sys->p_chain, NULL, NULL, NULL, NULL ); /* Append padding module */ filter_chain_AppendFromString( p_sys->p_chain, psz_croppadd ); fmt = *filter_chain_GetFmtOut( p_sys->p_chain ); es_format_Copy( &p_filter->fmt_out, &fmt ); p_filter->fmt_out.video.i_sar_num = i_canvas_aspect * p_filter->fmt_out.video.i_height; p_filter->fmt_out.video.i_sar_den = VOUT_ASPECT_FACTOR * p_filter->fmt_out.video.i_width; if( p_filter->fmt_out.video.i_width != i_canvas_width || p_filter->fmt_out.video.i_height != i_canvas_height ) { msg_Warn( p_filter, "Looks like something went wrong. " "Output size is %dx%d while we asked for %dx%d", p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height, i_canvas_width, i_canvas_height ); } p_filter->pf_video_filter = Filter; return VLC_SUCCESS; }