+ /* Only height specified */
+ f_scale_height = (float)id->p_encoder->fmt_out.video.i_height /
+ p_sys->i_crop_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;
+ }
+
+ /* 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 )
+ {
+ f_scale_width = (float)p_sys->i_maxwidth / p_sys->i_crop_width;
+ }
+ if( p_sys->i_maxheight && f_scale_height > (float)p_sys->i_maxheight /
+ p_sys->i_crop_height )
+ {
+ f_scale_height = (float)p_sys->i_maxheight / p_sys->i_crop_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;
+ }
+ }
+
+ /* 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_in.video.i_width = i_dst_width;
+ id->p_encoder->fmt_in.video.i_height = i_dst_height;
+
+ msg_Dbg( p_stream, "source %ix%i, crop %ix%i, "
+ "destination %ix%i, padding %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
+ );
+
+ /* Handle frame rate conversion */