[FFmpeg-soc] [soc]: r5821 - libavfilter/vf_overlay.c

bcoudurier subversion at mplayerhq.hu
Fri Jun 4 22:15:35 CEST 2010


Author: bcoudurier
Date: Fri Jun  4 22:15:35 2010
New Revision: 5821

Log:
Direct rendering in overlay filter.
RGB24 support.
Doesn't work with movie in movie yet, needs loop input feature for logos
either in movie filter or here.

Modified:
   libavfilter/vf_overlay.c

Modified: libavfilter/vf_overlay.c
==============================================================================
--- libavfilter/vf_overlay.c	Fri Jun  4 22:10:23 2010	(r5820)
+++ libavfilter/vf_overlay.c	Fri Jun  4 22:15:35 2010	(r5821)
@@ -1,5 +1,6 @@
 /*
  * copyright (c) 2007 Bobby Bingham
+ * copyright (c) 2010 Baptiste Coudurier
  *
  * This file is part of FFmpeg.
  *
@@ -44,13 +45,9 @@ enum var_name {
 };
 
 typedef struct {
-    int x, y;                   //< position of subpicture
+    unsigned x, y;              //< position of subpicture
 
-    /** pics[0][0..1] are pictures for the main image.
-     *  pics[1][0..1] are pictures for the sub image.
-     *  pics[x][0]    are previously outputted images.
-     *  pics[x][1]    are queued, yet unused frames for each input. */
-    AVFilterPicRef *pics[2][2];
+    AVFilterPicRef *overlay;
 
     int bpp;                    //< bytes per pixel
     int hsub, vsub;             //< chroma subsampling
@@ -74,18 +71,15 @@ static av_cold int init(AVFilterContext 
 static av_cold void uninit(AVFilterContext *ctx)
 {
     OverlayContext *over = ctx->priv;
-    int i, j;
 
-    for(i = 0; i < 2; i ++)
-        for(j = 0; j < 2; j ++)
-            if(over->pics[i][j])
-                avfilter_unref_pic(over->pics[i][j]);
+    if (over->overlay)
+        avfilter_unref_pic(over->overlay);
 }
 
 static int query_formats(AVFilterContext *ctx)
 {
-  //const enum PixelFormat inout_pix_fmts[] = { PIX_FMT_BGR24, PIX_FMT_NONE };
-  //const enum PixelFormat blend_pix_fmts[] = { PIX_FMT_BGRA, PIX_FMT_NONE };
+    //const enum PixelFormat inout_pix_fmts[] = { PIX_FMT_BGR24, PIX_FMT_RGB24, PIX_FMT_NONE };
+    //const enum PixelFormat blend_pix_fmts[] = { PIX_FMT_BGRA, PIX_FMT_NONE };
     const enum PixelFormat inout_pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
     const enum PixelFormat blend_pix_fmts[] = { PIX_FMT_YUVA420P, PIX_FMT_NONE };
     AVFilterFormats *inout_formats = avfilter_make_format_list(inout_pix_fmts);
@@ -133,7 +127,7 @@ static int config_input_overlay(AVFilter
     AVFilterContext *ctx  = link->dst;
     OverlayContext  *over = link->dst->priv;
     const char *error = NULL, *expr;
-    double var_values[VARS_NB];
+    double var_values[VARS_NB], ret;
 
     /* Finish the configuration by evaluating the expressions
        now when both inputs are configured. */
@@ -142,14 +136,26 @@ static int config_input_overlay(AVFilter
     var_values[OVERLAY_W] = ctx->inputs[1]->w;
     var_values[OVERLAY_H] = ctx->inputs[1]->h;
 
-    over->x = ff_parse_and_eval_expr((expr = over->x_expr), var_values, var_names,
-                       NULL, NULL, NULL, NULL, NULL, &error);
-    if (error)
+    av_log(ctx, AV_LOG_INFO, "main %dx%d overlay %dx%d\n", ctx->inputs[0]->w, ctx->inputs[0]->h,
+           ctx->inputs[1]->w, ctx->inputs[1]->h);
+
+    if (ff_parse_and_eval_expr(&ret, (expr = over->x_expr),
+                               var_names, var_values,
+                               NULL, NULL, NULL, NULL,
+                               NULL, 0, ctx) < 0)
         goto fail;
-    over->y = ff_parse_and_eval_expr((expr = over->y_expr), var_values, var_names,
-                       NULL, NULL, NULL, NULL, NULL, &error);
-    if (error)
+    over->x = ret;
+    if (ff_parse_and_eval_expr(&ret, (expr = over->y_expr),
+                               var_names, var_values,
+                               NULL, NULL, NULL, NULL,
+                               NULL, 0, ctx) < 0)
         goto fail;
+    over->y = ret;
+
+    over->x &= ~((1 << over->hsub) - 1);
+    over->y &= ~((1 << over->vsub) - 1);
+
+    av_log(ctx, AV_LOG_INFO, "overlaying at %d,%d\n", over->x, over->y);
 
     return 0;
 
@@ -159,209 +165,147 @@ fail:
     return -1;
 }
 
-static void shift_input(OverlayContext *over, int idx)
+static AVFilterPicRef *get_video_buffer(AVFilterLink *link, int perms, int w, int h)
 {
-    assert(over->pics[idx][0]);
-    assert(over->pics[idx][1]);
-    avfilter_unref_pic(over->pics[idx][0]);
-    over->pics[idx][0] = over->pics[idx][1];
-    over->pics[idx][1] = NULL;
+    AVFilterPicRef *picref = avfilter_get_video_buffer(link->dst->outputs[0],
+                                                       perms, w, h);
+    return picref;
 }
 
 static void start_frame(AVFilterLink *link, AVFilterPicRef *picref)
 {
-    OverlayContext *over = link->dst->priv;
-    /* There shouldn't be any previous queued frame in this queue */
-    assert(!over->pics[link->dstpad][1]);
-    if (over->pics[link->dstpad][0]) {
-        /* Queue the new frame */
-        over->pics[link->dstpad][1] = picref;
-    } else {
-        /* No previous unused frame, take this one into use directly */
-        over->pics[link->dstpad][0] = picref;
-    }
-}
+    AVFilterPicRef *outpicref = avfilter_ref_pic(picref, ~0);
 
-static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-}
+    link->dst->outputs[0]->outpic = outpicref;
 
-static void end_frame(AVFilterLink *link)
-{
+    avfilter_start_frame(link->dst->outputs[0], outpicref);
 }
 
-static int lower_timestamp(OverlayContext *over)
+static void start_frame_overlay(AVFilterLink *link, AVFilterPicRef *picref)
 {
-    if(!over->pics[0][0] &&
-       !over->pics[1][0]) return 2;
-    if(!over->pics[0][1]) return 0;
-    if(!over->pics[1][1]) return 1;
+    AVFilterContext *ctx = link->dst;
+    OverlayContext *over = ctx->priv;
 
-    if(over->pics[0][1]->pts == over->pics[1][1]->pts) return 2;
-    return (over->pics[0][1]->pts > over->pics[1][1]->pts);
+    over->overlay = picref;
 }
 
-static void copy_image_rgb(AVFilterPicRef *dst, int x, int y,
-                           AVFilterPicRef *src, int w, int h, int bpp)
+static void blend_slice(AVFilterContext *ctx,
+                        AVFilterPicRef *dst, AVFilterPicRef *src,
+                        int x, int y, int w, int h,
+                        int slice_y, int slice_w, int slice_h)
 {
-    AVPicture pic;
+    OverlayContext *over = ctx->priv;
+    int i, j, k;
+    int width, height;
+    int overlay_end_y = y+h;
+    int slice_end_y = slice_y+slice_h;
+    int end_y, start_y;
 
-    memcpy(&pic, &dst->data, sizeof(AVPicture));
-    pic.data[0] += x * bpp;
-    pic.data[0] += y * pic.linesize[0];
+    width = FFMIN(slice_w - x, w);
+    end_y = FFMIN(slice_end_y, overlay_end_y);
+    start_y = FFMAX(y, slice_y);
+    height = end_y - start_y;
 
-    if (src->pic->format == PIX_FMT_BGRA) {
-        for (y = 0; y < h; y++) {
-                  uint8_t *optr = pic.data[0]  + y * pic.linesize[0];
-            const uint8_t *iptr = src->data[0] + y * src->linesize[0];
-            for (x = 0; x < w; x++) {
-                uint8_t a = iptr[3];
-                optr[0] = (optr[0] * (0xff - a) + iptr[0] * a + 128) >> 8;
-                optr[1] = (optr[1] * (0xff - a) + iptr[1] * a + 128) >> 8;
-                optr[2] = (optr[2] * (0xff - a) + iptr[2] * a + 128) >> 8;
-                iptr += bpp+1;
-                optr += bpp;
+    if (dst->pic->format == PIX_FMT_BGR24 || dst->pic->format == PIX_FMT_RGB24) {
+        uint8_t *dp = dst->data[0] + x * 3 + start_y * dst->linesize[0];
+        uint8_t *sp = src->data[0];
+        int b = dst->pic->format == PIX_FMT_BGR24 ? 2 : 0;
+        int r = dst->pic->format == PIX_FMT_BGR24 ? 0 : 2;
+        if (slice_y > y)
+            sp += (slice_y - y) * src->linesize[0];
+        for (i = 0; i < height; i++) {
+            uint8_t *d = dp, *s = sp;
+            for (j = 0; j < width; j++) {
+                d[r] = (d[r] * (0xff - s[3]) + s[0] * s[3] + 128) >> 8;
+                d[1] = (d[1] * (0xff - s[3]) + s[1] * s[3] + 128) >> 8;
+                d[b] = (d[b] * (0xff - s[3]) + s[2] * s[3] + 128) >> 8;
+                d += 3;
+                s += 4;
             }
+            dp += dst->linesize[0];
+            sp += src->linesize[0];
         }
     } else {
-        av_picture_copy(&pic, (AVPicture *)src->data, dst->pic->format, w, h);
-    }
-}
-
-static void copy_blended(uint8_t* out, int out_linesize,
-    const uint8_t* in, int in_linesize,
-    const uint8_t* alpha, int alpha_linesize,
-    int w, int h, int hsub, int vsub)
-{
-    int y;
-    for (y = 0; y < h; y++) {
-        int x;
-              uint8_t *optr = out   + y         * out_linesize;
-        const uint8_t *iptr = in    + y         * in_linesize;
-        const uint8_t *aptr = alpha + (y<<vsub) * alpha_linesize;
-        for (x = 0; x < w; x++) {
-            uint8_t a = *aptr;
-            *optr = (*optr * (0xff - a) + *iptr * a + 128) >> 8;
-            optr++;
-            iptr++;
-            aptr += 1 << hsub;
+        for (i = 0; i < 3; i++) {
+            int hsub = i ? over->hsub : 0;
+            int vsub = i ? over->vsub : 0;
+            uint8_t *dp = dst->data[i] + (x >> hsub) +
+                (start_y >> vsub) * dst->linesize[i];
+            uint8_t *sp = src->data[i];
+            uint8_t *ap = src->data[3];
+            int wp = FFALIGN(width, 1<<hsub) >> hsub;
+            int hp = FFALIGN(height, 1<<vsub) >> vsub;
+            if (slice_y > y) {
+                sp += ((slice_y - y) >> vsub) * src->linesize[i];
+                ap += (slice_y - y) * src->linesize[3];
+            }
+            for (j = 0; j < hp; j++) {
+                uint8_t *d = dp, *s = sp, *a = ap;
+                for (k = 0; k < wp; k++) {
+                    // average alpha for color components, improve quality
+                    int alpha_v, alpha_h, alpha;
+                    if (hsub && vsub && j+1 < hp && k+1 < wp) {
+                        alpha = (a[0] + a[src->linesize[3]] +
+                                 a[1] + a[src->linesize[3]+1]) >> 2;
+                    } else if (hsub || vsub) {
+                        alpha_h = hsub && k+1 < wp ?
+                            (a[0] + a[1]) >> 1 : a[0];
+                        alpha_v = vsub && j+1 < hp ?
+                            (a[0] + a[src->linesize[3]]) >> 1 : a[0];
+                        alpha = (alpha_v + alpha_h) >> 1;
+                    } else
+                        alpha = a[0];
+                    *d = (*d * (0xff - alpha) + *s++ * alpha + 128) >> 8;
+                    d++;
+                    a += 1 << hsub;
+                }
+                dp += dst->linesize[i];
+                sp += src->linesize[i];
+                ap += (1 << vsub) * src->linesize[3];
+            }
         }
     }
 }
 
-static void copy_image_yuv(AVFilterPicRef *dst, int x, int y,
-                           AVFilterPicRef *src, int w, int h,
-                           int bpp, int hsub, int vsub)
+static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
 {
-    AVPicture pic;
-    int i;
+    AVFilterContext *ctx = link->dst;
+    AVFilterPicRef *pic = ctx->outputs[0]->outpic;
+    OverlayContext *over = ctx->priv;
 
-    memcpy(&pic, &dst->data, sizeof(AVPicture));
-    for(i = 0; i < 4; i ++) {
-        if(pic.data[i]) {
-            int x_off = x;
-            int y_off = y;
-            if (i == 1 || i == 2) {
-                x_off >>= hsub;
-                y_off >>= vsub;
-            }
-            pic.data[i] += x_off * bpp;
-            pic.data[i] += y_off * pic.linesize[i];
+    if (!over->overlay) {// || over->overlay->pts < pic->pts) {
+        if (over->overlay) {
+            avfilter_unref_pic(over->overlay);
+            over->overlay = NULL;
+        }
+        if (avfilter_request_frame(ctx->inputs[1]))
+            goto out;
+        if (!over->overlay) {
+            av_log(ctx, AV_LOG_ERROR, "error getting overlay frame\n");
+            goto out;
         }
     }
-
-    if (src->pic->format == PIX_FMT_YUVA420P) {
-        int chroma_w = w>>hsub;
-        int chroma_h = h>>vsub;
-        assert(dst->pic->format == PIX_FMT_YUV420P);
-        copy_blended(pic.data[0], pic.linesize[0], src->data[0], src->linesize[0], src->data[3], src->linesize[3], w, h, 0, 0);
-        copy_blended(pic.data[1], pic.linesize[1], src->data[1], src->linesize[1], src->data[3], src->linesize[3], chroma_w, chroma_h, hsub, vsub);
-        copy_blended(pic.data[2], pic.linesize[2], src->data[2], src->linesize[2], src->data[3], src->linesize[3], chroma_w, chroma_h, hsub, vsub);
-    } else {
-        av_picture_copy(&pic, (AVPicture *)src->data, dst->pic->format, w, h);
+    if (!(over->x >= pic->w || over->y >= pic->h ||
+          y+h < over->y || y >= over->y+over->overlay->h)) {
+        blend_slice(ctx, pic, over->overlay, over->x, over->y,
+                    over->overlay->w, over->overlay->h, y, pic->w, h);
     }
+ out:
+    avfilter_draw_slice(ctx->outputs[0], y, h, slice_dir);
 }
 
-static void copy_image(AVFilterPicRef *dst, int x, int y,
-                       AVFilterPicRef *src, int w, int h,
-                       int bpp, int hsub, int vsub)
+static void end_frame(AVFilterLink *link)
 {
-    if (dst->pic->format == PIX_FMT_YUV420P)
-        return copy_image_yuv(dst, x, y, src, w, h, bpp, hsub, vsub);
-    else
-        return copy_image_rgb(dst, x, y, src, w, h, bpp);
+    avfilter_end_frame(link->dst->outputs[0]);
+    avfilter_unref_pic(link->cur_pic);
 }
 
-static int request_frame(AVFilterLink *link)
+static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
 {
-    AVFilterPicRef *pic;
-    OverlayContext *over = link->src->priv;
-    int idx;
-    int x, y, w, h;
-
-    if (!over->pics[0][0] || !over->pics[1][0]) {
-        /* No frame output yet, we need one frame from each input */
-        if (!over->pics[0][0] && avfilter_request_frame(link->src->inputs[0]))
-            return AVERROR_EOF;
-        if (!over->pics[1][0] && avfilter_request_frame(link->src->inputs[1]))
-            return AVERROR_EOF;
-    } else {
-        int eof = 0;
-
-        /* Try pulling a new candidate from each input unless we already
-           have one */
-        for (idx = 0; idx < 2; idx++) {
-            if (!over->pics[idx][1] &&
-                 avfilter_request_frame(link->src->inputs[idx]))
-                eof++;
-        }
-        if (eof == 2)
-            return AVERROR_EOF; /* No new candidates in any input; EOF */
-
-        /* At least one new frame */
-        assert(over->pics[0][1] || over->pics[1][1]);
-
-        if (over->pics[0][1] && over->pics[1][1]) {
-            /* Neither one of the inputs has finished */
-            if ((idx = lower_timestamp(over)) == 2) {
-                shift_input(over, 0);
-                shift_input(over, 1);
-            } else
-                shift_input(over, idx);
-        } else if (over->pics[0][1]) {
-            /* Use the single new input frame */
-            shift_input(over, 0);
-        } else {
-            assert(over->pics[1][1]);
-            shift_input(over, 1);
-        }
-    }
-
-    /* we draw the output frame */
-    pic = avfilter_get_video_buffer(link, AV_PERM_WRITE, link->w, link->h);
-    if(over->pics[0][0]) {
-        pic->pixel_aspect = over->pics[0][0]->pixel_aspect;
-        copy_image(pic, 0, 0, over->pics[0][0], link->w, link->h,
-                   over->bpp, over->hsub, over->vsub);
-    }
-    x = FFMIN(over->x, link->w-1);
-    y = FFMIN(over->y, link->h-1);
-    w = FFMIN(link->w-x, over->pics[1][0]->w);
-    h = FFMIN(link->h-y, over->pics[1][0]->h);
-    if(over->pics[1][0])
-        copy_image(pic, x, y, over->pics[1][0], w, h,
-                   over->bpp, over->hsub, over->vsub);
-
-    /* we give the output frame the higher of the two current pts values */
-    pic->pts = FFMAX(over->pics[0][0]->pts, over->pics[1][0]->pts);
-
-    /* and send it to the next filter */
-    avfilter_start_frame(link, avfilter_ref_pic(pic, ~0));
-    avfilter_draw_slice (link, 0, pic->h, 1);
-    avfilter_end_frame  (link);
-    avfilter_unref_pic(pic);
+}
 
-    return 0;
+static void null_end_frame(AVFilterLink *link)
+{
 }
 
 AVFilter avfilter_vf_overlay =
@@ -379,23 +323,18 @@ AVFilter avfilter_vf_overlay =
     .inputs    = (AVFilterPad[]) {{ .name            = "default",
                                     .type            = AVMEDIA_TYPE_VIDEO,
                                     .start_frame     = start_frame,
+                                    .get_video_buffer= get_video_buffer,
                                     .config_props    = config_input_main,
                                     .draw_slice      = draw_slice,
-                                    .end_frame       = end_frame,
-                                    .min_perms       = AV_PERM_READ,
-                                    .rej_perms       = AV_PERM_REUSE2, },
+                                    .end_frame       = end_frame },
                                   { .name            = "sub",
                                     .type            = AVMEDIA_TYPE_VIDEO,
-                                    .start_frame     = start_frame,
+                                    .start_frame     = start_frame_overlay,
                                     .config_props    = config_input_overlay,
-                                    .draw_slice      = draw_slice,
-                                    .end_frame       = end_frame,
-                                    .min_perms       = AV_PERM_READ,
-                                    .rej_perms       = AV_PERM_REUSE2, },
+                                    .draw_slice      = null_draw_slice,
+                                    .end_frame       = null_end_frame },
                                   { .name = NULL}},
     .outputs   = (AVFilterPad[]) {{ .name            = "default",
-                                    .type            = AVMEDIA_TYPE_VIDEO,
-                                    .request_frame   = request_frame, },
+                                    .type            = AVMEDIA_TYPE_VIDEO },
                                   { .name = NULL}},
 };
-


More information about the FFmpeg-soc mailing list