/** * \brief Initializes our filter. * * \param args The arguments passed in from the command line go here. This * filter expects only a single argument telling it where the PGM * or PPM file that describes the logo region is. * * This sets up our instance variables and parses the arguments to the filter. */ static int vf_open(vf_instance_t *vf, char *args) { vf->priv = safe_malloc(sizeof(vf_priv_s)); vf->uninit = uninit; /* Load our filter image. */ if (args) vf->priv->filter = load_pgm(args); else { mp_msg(MSGT_VFILTER, MSGL_ERR, "[vf]remove_logo usage: remove_logo=/path/to/filter_image_file.pgm\n"); free(vf->priv); return 0; } if (vf->priv->filter == NULL) { /* Error message was displayed by load_pgm(). */ free(vf->priv); return 0; } /* Create the scaled down filter image for the chroma planes. */ convert_mask_to_strength_mask(vf, vf->priv->filter); vf->priv->half_size_filter = generate_half_size_image(vf, vf->priv->filter); /* Now that we know how many masks we need (the info is in vf), we can generate the masks. */ initialize_masks(vf); /* Calculate our bounding rectangles, which determine in what region the logo resides for faster processing. */ calculate_bounding_rectangle(&vf->priv->bounding_rectangle_posx1, &vf->priv->bounding_rectangle_posy1, &vf->priv->bounding_rectangle_posx2, &vf->priv->bounding_rectangle_posy2, vf->priv->filter); calculate_bounding_rectangle(&vf->priv->bounding_rectangle_half_size_posx1, &vf->priv->bounding_rectangle_half_size_posy1, &vf->priv->bounding_rectangle_half_size_posx2, &vf->priv->bounding_rectangle_half_size_posy2, vf->priv->half_size_filter); vf->config=config; vf->put_image=put_image; vf->query_format=query_format; return 1; }
static av_cold int init(AVFilterContext *ctx, const char *args) { RemovelogoContext *removelogo = ctx->priv; int ***mask; int ret = 0; int a, b, c, w, h; int full_max_mask_size, half_max_mask_size; if (!args) { av_log(ctx, AV_LOG_ERROR, "An image file must be specified as argument\n"); return AVERROR(EINVAL); } /* Load our mask image. */ if ((ret = load_mask(&removelogo->full_mask_data, &w, &h, args, ctx)) < 0) return ret; removelogo->mask_w = w; removelogo->mask_h = h; convert_mask_to_strength_mask(removelogo->full_mask_data, w, w, h, 16, &full_max_mask_size); /* Create the scaled down mask image for the chroma planes. */ if (!(removelogo->half_mask_data = av_mallocz(w/2 * h/2))) return AVERROR(ENOMEM); generate_half_size_image(removelogo->full_mask_data, w, removelogo->half_mask_data, w/2, w, h, &half_max_mask_size); removelogo->max_mask_size = FFMAX(full_max_mask_size, half_max_mask_size); /* Create a circular mask for each size up to max_mask_size. When the filter is applied, the mask size is determined on a pixel by pixel basis, with pixels nearer the edge of the logo getting smaller mask sizes. */ mask = (int ***)av_malloc(sizeof(int **) * (removelogo->max_mask_size + 1)); if (!mask) return AVERROR(ENOMEM); for (a = 0; a <= removelogo->max_mask_size; a++) { mask[a] = (int **)av_malloc(sizeof(int *) * ((a * 2) + 1)); if (!mask[a]) return AVERROR(ENOMEM); for (b = -a; b <= a; b++) { mask[a][b + a] = (int *)av_malloc(sizeof(int) * ((a * 2) + 1)); if (!mask[a][b + a]) return AVERROR(ENOMEM); for (c = -a; c <= a; c++) { if ((b * b) + (c * c) <= (a * a)) /* Circular 0/1 mask. */ mask[a][b + a][c + a] = 1; else mask[a][b + a][c + a] = 0; } } } removelogo->mask = mask; /* Calculate our bounding rectangles, which determine in what * region the logo resides for faster processing. */ ff_calculate_bounding_box(&removelogo->full_mask_bbox, removelogo->full_mask_data, w, w, h, 0); ff_calculate_bounding_box(&removelogo->half_mask_bbox, removelogo->half_mask_data, w/2, w/2, h/2, 0); #define SHOW_LOGO_INFO(mask_type) \ av_log(ctx, AV_LOG_VERBOSE, #mask_type " x1:%d x2:%d y1:%d y2:%d max_mask_size:%d\n", \ removelogo->mask_type##_mask_bbox.x1, removelogo->mask_type##_mask_bbox.x2, \ removelogo->mask_type##_mask_bbox.y1, removelogo->mask_type##_mask_bbox.y2, \ mask_type##_max_mask_size); SHOW_LOGO_INFO(full); SHOW_LOGO_INFO(half); return 0; }