[FFmpeg-devel] [PATCH] vf_delogo: allow to change the rectangle based on the time
Stefano Sabatini
stefano.sabatini-lala at poste.it
Sat Aug 20 20:37:16 CEST 2011
On date Saturday 2011-08-20 14:17:48 +0200, Nicolas George encoded:
> Thanks for the review.
[...]
> From fc783354adf03019df7a685e3d433b502d481e88 Mon Sep 17 00:00:00 2001
> From: Nicolas George <nicolas.george at normalesup.org>
> Date: Mon, 15 Aug 2011 15:10:57 +0200
> Subject: [PATCH] vf_delogo: allow to change the rectangle based on the time.
>
> This is a port of MPlayer's commit 33488.
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
> doc/filters.texi | 21 +++++++
> libavfilter/vf_delogo.c | 143 +++++++++++++++++++++++++++++++++++++++++++----
> 2 files changed, 152 insertions(+), 12 deletions(-)
>
> diff --git a/doc/filters.texi b/doc/filters.texi
> index ce7d064..2638aca 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -470,6 +470,13 @@ When set to 1, a green rectangle is drawn on the screen to simplify
> finding the right @var{x}, @var{y}, @var{w}, @var{h} parameters, and
> @var{band} is set to 4. The default value is 0.
>
> + at item file
> +Read timestamps and coordinates from @var{file}. @var{file} is a text file
> +with on each line a timestamp (in seconds and in ascending order) and the
> +x:y:w:h:band coordinates (band can be omitted), or just 0.
> +Empty lines and lines beginning with "#" are ignored.
> +If this option is present, the other options are ignored.
> +
> @end table
>
> Some examples follow.
> @@ -489,6 +496,20 @@ As the previous example, but use named options:
> delogo=x=0:y=0:w=100:h=77:band=10
> @end example
>
> + at item
> +As the previous example, but only remove the logo from time 5s to time 10s
> +and from time 1800s to time 1805s:
> + at example
> +delogo=file=top_left_5s.txt
> + at end example
> + at code{top_left_5s.txt} contains:
> + at example
> +5 0:0:100:77:10
> +10 0
> +1800 0:0:100:77:10
> +1805 0
> + at end example
> +
> @end itemize
>
> @section drawbox
> diff --git a/libavfilter/vf_delogo.c b/libavfilter/vf_delogo.c
> index f0852f8..35b1792 100644
> --- a/libavfilter/vf_delogo.c
> +++ b/libavfilter/vf_delogo.c
> @@ -133,6 +133,13 @@ static void apply_delogo(uint8_t *dst, int dst_linesize,
> typedef struct {
> const AVClass *class;
> int x, y, w, h, band, show;
> + const char *file;
> + struct timed_rectangle {
> + double ts;
> + int x, y, w, h, b;
> + } *timed_rects;
> + int nb_timed_rects;
> + int cur_timed_rect;
> } DelogoContext;
>
> #define OFFSET(x) offsetof(DelogoContext, x)
> @@ -145,6 +152,7 @@ static const AVOption delogo_options[]= {
> {"band", "set delogo area band size", OFFSET(band), FF_OPT_TYPE_INT, {.dbl= 4}, -1, INT_MAX },
> {"t", "set delogo area band size", OFFSET(band), FF_OPT_TYPE_INT, {.dbl= 4}, -1, INT_MAX },
> {"show", "show delogo area", OFFSET(show), FF_OPT_TYPE_INT, {.dbl= 0}, 0, 1 },
> + {"file", "read times and coordinates from a file", OFFSET(file), FF_OPT_TYPE_STRING, {.str= NULL}, 0, 0 },
> {NULL},
> };
>
> @@ -172,6 +180,108 @@ static int query_formats(AVFilterContext *ctx)
> return 0;
> }
>
> +static void fix_band(DelogoContext *delogo, int show)
> +{
> + delogo->show = show || delogo->band < 0;
> + if (delogo->show)
> + delogo->band = 4;
> + delogo->w += delogo->band*2;
> + delogo->h += delogo->band*2;
> + delogo->x -= delogo->band;
> + delogo->y -= delogo->band;
> +}
> +
> +static void update_rectangle(DelogoContext *p, double pts)
> +{
> + int tr = p->cur_timed_rect;
> + while (tr < p->nb_timed_rects - 1 && pts >= p->timed_rects[tr + 1].ts)
> + tr++;
> + while (tr >= 0 && pts < p->timed_rects[tr].ts)
> + tr--;
> + if (tr == p->cur_timed_rect)
> + return;
> + p->cur_timed_rect = tr;
> + if (tr >= 0) {
> + p->x = p->timed_rects[tr].x;
> + p->y = p->timed_rects[tr].y;
> + p->w = p->timed_rects[tr].w;
> + p->h = p->timed_rects[tr].h;
> + p->band = p->timed_rects[tr].b;
> + } else {
> + p->x = p->y = p->w = p->h = p->band = 0;
> + }
> + fix_band(p, 0);
> +}
> +
> +static int load_timed_rectangles(AVFilterContext *ctx, DelogoContext *delogo)
> +{
> + FILE *f;
> + char line[2048];
> + int lineno = 0, n_fields;
> + double ts, last_ts = 0;
> + struct timed_rectangle *rects = NULL, *nr;
> + int nb_rects = 0, nb_alloc_rects = 0;
> + int error = AVERROR(EINVAL);
> +
> + f = fopen(delogo->file, "r");
> + if (!f) {
> + av_log(ctx, AV_LOG_ERROR, "unable to load %s: %s\n",
> + delogo->file, strerror(errno));
Nit: "Could not load file '%s': %s\n"
weird indent
> + return AVERROR(errno);
> + }
> + while (fgets(line, sizeof(line), f)) {
> + lineno++;
> + if (*line == '#' || *line == '\n')
> + continue;
> + if (nb_rects == nb_alloc_rects) {
> + if (nb_alloc_rects > INT_MAX / 2 / (int)sizeof(*rects)) {
> + error = AVERROR(errno);
why?
=> AVERROR(EINVAL)
> + av_log(ctx, AV_LOG_ERROR, "too many rectangles\n");
Nit+: "Too many ..."
> + goto load_error;
> + }
> + nb_alloc_rects = nb_alloc_rects ? 2 * nb_alloc_rects : 256;
> + nr = av_realloc(rects, nb_alloc_rects * sizeof(*rects));
> + if (!nr) {
> + error = AVERROR(errno);
shouldn't this be AVERROR(ENOMEM)?
> + av_log(ctx, AV_LOG_ERROR, "out of memory\n");
> + goto load_error;
> + }
> + rects = nr;
> + }
> + nr = rects + nb_rects;
> + memset(nr, 0, sizeof(*nr));
> + n_fields = sscanf(line, "%lf %d:%d:%d:%d:%d",
> + &ts, &nr->x, &nr->y, &nr->w, &nr->h, &nr->b);
> + if ((n_fields == 2 && !nr->x) || n_fields == 5 || n_fields == 6) {
> + if (ts <= last_ts)
> + av_log(ctx, AV_LOG_ERROR,
> + "%s:%d: invalid time, time %f is less than "
> + "time %f in the previous line\n",
> + delogo->file, lineno, ts, last_ts);
> + nr->ts = ts;
> + nb_rects++;
> + } else {
> + av_log(ctx, AV_LOG_ERROR, "%s:%d: syntax error\n",
> + delogo->file, lineno);
> + }
> + }
> + fclose(f);
> + if (!nb_rects) {
> + av_log(ctx, AV_LOG_ERROR, "%s: no rectangles found\n", delogo->file);
Nit++: No rectangles specified in '%s'\b
> + av_free(rects);
> + return AVERROR(EINVAL);
> + }
> + nr = av_realloc(rects, nb_rects * sizeof(*rects));
> + delogo->timed_rects = nr ? nr : rects;
> + delogo->nb_timed_rects = nb_rects;
> + return 0;
> +
> +load_error:
> + av_free(rects);
> + fclose(f);
> + return error;
> +}
> +
> static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
> {
> DelogoContext *delogo = ctx->priv;
> @@ -183,14 +293,19 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
> if (args)
> ret = sscanf(args, "%d:%d:%d:%d:%d",
> &delogo->x, &delogo->y, &delogo->w, &delogo->h, &delogo->band);
> - if (ret == 5) {
> - if (delogo->band < 0)
> - delogo->show = 1;
> - } else if ((ret = (av_set_options_string(delogo, args, "=", ":"))) < 0) {
> + if (ret != 5 &&
> + (ret = (av_set_options_string(delogo, args, "=", ":"))) < 0) {
> av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
> return ret;
> }
>
> + if (delogo->file) {
> + if ((ret = load_timed_rectangles(ctx, delogo)) < 0)
> + return ret;
> + av_log(ctx, AV_LOG_INFO, "%d from %s\n",
> + delogo->nb_timed_rects, delogo->file);
Nit: Read %d rectangles from file '%s'\n
[...]
Also remember to bump micro when committing (added feature, extended
interface).
Looks fine otherwise, thanks.
--
FFmpeg = Fast and Fierce MultiPurpose Erudite Governor
More information about the ffmpeg-devel
mailing list