Exemplo n.º 1
0
/**
 * Generate a scaled down image with half width, height, and intensity.
 *
 * This function not only scales down an image, but halves the value
 * in each pixel too. The purpose of this is to produce a chroma
 * filter image out of a luma filter image. The pixel values store the
 * distance to the edge of the logo and halving the dimensions halves
 * the distance. This function rounds up, because a downwards rounding
 * error could cause the filter to fail, but an upwards rounding error
 * will only cause a minor amount of excess blur in the chroma planes.
 */
static void generate_half_size_image(const uint8_t *src_data, int src_linesize,
                                     uint8_t *dst_data, int dst_linesize,
                                     int src_w, int src_h,
                                     int *max_mask_size)
{
    int x, y;

    /* Copy over the image data, using the average of 4 pixels for to
     * calculate each downsampled pixel. */
    for (y = 0; y < src_h/2; y++) {
        for (x = 0; x < src_w/2; x++) {
            /* Set the pixel if there exists a non-zero value in the
             * source pixels, else clear it. */
            dst_data[(y * dst_linesize) + x] =
                src_data[((y << 1) * src_linesize) + (x << 1)] ||
                src_data[((y << 1) * src_linesize) + (x << 1) + 1] ||
                src_data[(((y << 1) + 1) * src_linesize) + (x << 1)] ||
                src_data[(((y << 1) + 1) * src_linesize) + (x << 1) + 1];
            dst_data[(y * dst_linesize) + x] = FFMIN(1, dst_data[(y * dst_linesize) + x]);
        }
    }

    convert_mask_to_strength_mask(dst_data, dst_linesize,
                                  src_w/2, src_h/2, 0, max_mask_size);
}
Exemplo n.º 2
0
/**
 * \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;
}
Exemplo n.º 3
0
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;
}