static void set_rectangles(cropscale_priv_t * vp) { float zoom_factor; gavl_rectangle_f_t in_rect; gavl_rectangle_i_t out_rect; /* Crop input */ gavl_rectangle_f_set_all(&in_rect, &vp->in_format); gavl_rectangle_f_crop_left(&in_rect, vp->crop_left); gavl_rectangle_f_crop_right(&in_rect, vp->crop_right); gavl_rectangle_f_crop_top(&in_rect, vp->crop_top); gavl_rectangle_f_crop_bottom(&in_rect, vp->crop_bottom); zoom_factor = vp->zoom * 0.01; if(vp->maintain_aspect) { gavl_rectangle_fit_aspect(&out_rect, // gavl_rectangle_t * r, &vp->in_format, // gavl_video_format_t * src_format, &in_rect, // gavl_rectangle_t * src_rect, &vp->out_format, // gavl_video_format_t * dst_format, zoom_factor, // float zoom, vp->squeeze // float squeeze ); gavl_rectangle_crop_to_format_scale(&in_rect, &out_rect, &vp->in_format, &vp->out_format); } else { gavl_rectangle_i_set_all(&out_rect, &vp->out_format); } /* Set rectangles */ gavl_video_options_set_rectangles(vp->opt, &in_rect, &out_rect); }
int gavl_video_scaler_init_convolve(gavl_video_scaler_t * scaler, const gavl_video_format_t * format, int h_radius, const float * h_coeffs, int v_radius, const float * v_coeffs) { gavl_rectangle_f_t src_rect; gavl_rectangle_i_t dst_rect; gavl_video_options_t opt; int field, plane; /* Copy options because we want to change them */ gavl_video_options_copy(&opt, &scaler->opt); /* Copy formats */ gavl_video_format_copy(&scaler->src_format, format); gavl_video_format_copy(&scaler->dst_format, format); gavl_rectangle_f_set_all(&src_rect, &scaler->src_format); gavl_rectangle_i_set_all(&dst_rect, &scaler->dst_format); gavl_video_options_set_rectangles(&opt, &src_rect, &dst_rect); /* Check how many fields we must handle */ if(format->interlace_mode != GAVL_INTERLACE_NONE) { scaler->src_fields = 2; scaler->dst_fields = 2; } else { scaler->src_fields = 1; scaler->dst_fields = 1; } /* Copy destination rectangle so we know, which subframe to take */ gavl_rectangle_i_copy(&scaler->dst_rect, &opt.dst_rect); /* Check how many planes we have */ if((scaler->src_format.pixelformat == GAVL_YUY2) || (scaler->src_format.pixelformat == GAVL_UYVY)) scaler->num_planes = 3; else scaler->num_planes = gavl_pixelformat_num_planes(scaler->src_format.pixelformat); if((scaler->src_fields == 2) && (!scaler->src_field)) scaler->src_field = gavl_video_frame_create(NULL); if((scaler->dst_fields == 2) && (!scaler->dst_field)) scaler->dst_field = gavl_video_frame_create(NULL); /* Now, initialize all fields and planes */ for(field = 0; field < scaler->src_fields; field++) { for(plane = 0; plane < scaler->num_planes; plane++) { gavl_video_scale_context_init_convolve(&scaler->contexts[field][plane], &opt, plane, format, scaler->src_fields, h_radius, h_coeffs, v_radius, v_coeffs); } if(scaler->src_format.interlace_mode == GAVL_INTERLACE_MIXED) { for(plane = 0; plane < scaler->num_planes; plane++) { gavl_video_scale_context_init_convolve(&scaler->contexts[2][plane], &opt, plane, format, 1, h_radius, h_coeffs, v_radius, v_coeffs); } } } return 1; }
static void update_scaler( scale0tilt_instance_t* inst ) { float dst_x, dst_y, dst_w, dst_h; float src_x, src_y, src_w, src_h; inst->do_scale = 1; src_x = inst->w * inst->cl; src_y = inst->h * inst->ct; src_w = inst->w * (1.0 - inst->cl - inst->cr ); src_h = inst->h * (1.0 - inst->ct - inst->cb ); dst_x = inst->w * inst->cl * inst->sx + inst->tx * inst->w; dst_y = inst->h * inst->ct * inst->sy + inst->ty * inst->h; dst_w = inst->w * (1.0 - inst->cl - inst->cr) * inst->sx; dst_h = inst->h * (1.0 - inst->ct - inst->cb) * inst->sy; if((dst_w < EPSILON) || (dst_h < EPSILON) || (src_w < EPSILON) || (src_h < EPSILON)) { inst->do_scale = 0; return; } if ( dst_x + dst_w > inst->w ) { src_w = src_w * ( (inst->w-dst_x) / dst_w ); dst_w = inst->w - dst_x; } if ( dst_y + dst_h > inst->h ) { src_h = src_h * ( (inst->h-dst_y) / dst_h ); dst_h = inst->h - dst_y; } if ( dst_x < 0 ) { src_x = src_x - dst_x * ( src_w / dst_w ); src_w = src_w * ( (dst_w+dst_x) / dst_w ); dst_w = dst_w + dst_x; dst_x = 0; } if ( dst_y < 0 ) { src_y = src_y - dst_y * ( src_h / dst_h ); src_h = src_h * ( (dst_h+dst_y) / dst_h ); dst_h = dst_h + dst_y; dst_y = 0; } if((dst_w < EPSILON) || (dst_h < EPSILON) || (src_w < EPSILON) || (src_h < EPSILON)) { inst->do_scale = 0; return; } gavl_video_options_t* options = gavl_video_scaler_get_options( inst->video_scaler ); gavl_video_format_t format_dst; livido_memset(&format_dst, 0, sizeof(format_dst)); format_dst.frame_width = inst->w; format_dst.frame_height = inst->h; format_dst.image_width = inst->w; format_dst.image_height = inst->h; format_dst.pixel_width = 1; format_dst.pixel_height = 1; format_dst.pixelformat = GAVL_YUVJ_444_P; gavl_rectangle_f_t src_rect; gavl_rectangle_i_t dst_rect; src_rect.x = src_x; src_rect.y = src_y; src_rect.w = src_w; src_rect.h = src_h; dst_rect.x = lroundf(dst_x); dst_rect.y = lroundf(dst_y); dst_rect.w = lroundf(dst_w); dst_rect.h = lroundf(dst_h); gavl_video_options_set_rectangles( options, &src_rect, &dst_rect ); gavl_video_scaler_init( inst->video_scaler, &inst->format_src, &format_dst ); }
int gavl_video_scaler_init(gavl_video_scaler_t * scaler, const gavl_video_format_t * src_format, const gavl_video_format_t * dst_format) { gavl_rectangle_f_t src_rect; gavl_rectangle_i_t dst_rect; gavl_video_options_t opt; int field, plane; int sub_h_out = 1, sub_v_out = 1; /* Copy options because we want to change them */ gavl_video_options_copy(&opt, &scaler->opt); /* TODO: If the image is smaller than the number of filter taps, reduce scaling algorithm */ /* Copy formats */ gavl_video_format_copy(&scaler->src_format, src_format); gavl_video_format_copy(&scaler->dst_format, dst_format); /* Check if we have rectangles */ if(!opt.have_rectangles) { gavl_rectangle_f_set_all(&src_rect, &scaler->src_format); gavl_rectangle_i_set_all(&dst_rect, &scaler->dst_format); gavl_video_options_set_rectangles(&opt, &src_rect, &dst_rect); } /* Check how many fields we must handle */ if((opt.deinterlace_mode == GAVL_DEINTERLACE_SCALE) && (opt.conversion_flags & GAVL_FORCE_DEINTERLACE)) { /* Deinterlacing mode */ scaler->src_fields = 2; scaler->dst_fields = 1; /* Fake formats for scale context */ if(scaler->src_format.interlace_mode == GAVL_INTERLACE_NONE) scaler->src_format.interlace_mode = GAVL_INTERLACE_TOP_FIRST; scaler->dst_format.interlace_mode = GAVL_INTERLACE_NONE; } else if((opt.deinterlace_mode == GAVL_DEINTERLACE_SCALE) && (scaler->dst_format.interlace_mode == GAVL_INTERLACE_NONE) && (scaler->src_format.interlace_mode != GAVL_INTERLACE_NONE)) { /* Deinterlacing mode */ scaler->src_fields = 2; scaler->dst_fields = 1; } else if(scaler->src_format.interlace_mode != GAVL_INTERLACE_NONE) { /* Interlaced scaling */ scaler->src_fields = 2; scaler->dst_fields = 2; } else { /* Progressive scaling */ scaler->src_fields = 1; scaler->dst_fields = 1; } /* Copy destination rectangle so we know, which subframe to take */ gavl_rectangle_i_copy(&scaler->dst_rect, &opt.dst_rect); #if 0 fprintf(stderr, "gavl_video_scaler_init:\n"); gavl_rectangle_f_dump(&scaler->opt.src_rect); fprintf(stderr, "\n"); gavl_rectangle_i_dump(&scaler->dst_rect); fprintf(stderr, "\n"); #endif /* Crop source and destination rectangles to the formats */ /* Align the destination rectangle to the output formtat */ gavl_pixelformat_chroma_sub(scaler->dst_format.pixelformat, &sub_h_out, &sub_v_out); gavl_rectangle_i_align(&opt.dst_rect, sub_h_out, sub_v_out); #if 0 fprintf(stderr, "Initializing scaler:\n"); fprintf(stderr, "Src format:\n"); gavl_video_format_dump(&scaler->src_format); fprintf(stderr, "Dst format:\n"); gavl_video_format_dump(&scaler->dst_format); fprintf(stderr, "Src rectangle:\n"); gavl_rectangle_f_dump(&opt.src_rect); fprintf(stderr, "\nDst rectangle:\n"); gavl_rectangle_i_dump(&scaler->dst_rect); fprintf(stderr, "\n"); #endif /* Check how many planes we have */ if((scaler->src_format.pixelformat == GAVL_YUY2) || (scaler->src_format.pixelformat == GAVL_UYVY)) scaler->num_planes = 3; else scaler->num_planes = gavl_pixelformat_num_planes(scaler->src_format.pixelformat); if((scaler->src_fields == 2) && (!scaler->src_field)) scaler->src_field = gavl_video_frame_create(NULL); if((scaler->dst_fields == 2) && (!scaler->dst_field)) scaler->dst_field = gavl_video_frame_create(NULL); #if 0 fprintf(stderr, "src_fields: %d, dst_fields: %d, planes: %d\n", scaler->src_fields, scaler->dst_fields, scaler->num_planes); #endif /* Handle automatic mode selection */ if(opt.scale_mode == GAVL_SCALE_AUTO) { if(opt.quality < 2) opt.scale_mode = GAVL_SCALE_NEAREST; else if(opt.quality <= 3) opt.scale_mode = GAVL_SCALE_BILINEAR; else opt.scale_mode = GAVL_SCALE_CUBIC_BSPLINE; } /* Now, initialize all fields and planes */ if(scaler->src_fields > scaler->dst_fields) { /* Deinterlace mode */ field = (scaler->opt.deinterlace_drop_mode == GAVL_DEINTERLACE_DROP_BOTTOM) ? 0 : 1; for(plane = 0; plane < scaler->num_planes; plane++) { if(!gavl_video_scale_context_init(&scaler->contexts[field][plane], &opt, plane, &scaler->src_format, &scaler->dst_format, field, 0, scaler->src_fields, scaler->dst_fields)) return 0; } if(scaler->src_format.interlace_mode == GAVL_INTERLACE_MIXED) { for(plane = 0; plane < scaler->num_planes; plane++) { if(!gavl_video_scale_context_init(&scaler->contexts[2][plane], &opt, plane, &scaler->src_format, &scaler->dst_format, 0, 0, 1, 1)) return 0; } } } else { /* src_fields == dst_fields */ for(field = 0; field < scaler->src_fields; field++) { for(plane = 0; plane < scaler->num_planes; plane++) { if(!gavl_video_scale_context_init(&scaler->contexts[field][plane], &opt, plane, &scaler->src_format, &scaler->dst_format, field, field, scaler->src_fields, scaler->dst_fields)) return 0; } } if(scaler->src_format.interlace_mode == GAVL_INTERLACE_MIXED) { for(plane = 0; plane < scaler->num_planes; plane++) { if(!gavl_video_scale_context_init(&scaler->contexts[2][plane], &opt, plane, &scaler->src_format, &scaler->dst_format, 0, 0, 1, 1)) return 0; } } } return 1; }