Libav 0.7.1
|
00001 /* 00002 * Copyright (c) 2010 Stefano Sabatini 00003 * Copyright (c) 2010 Baptiste Coudurier 00004 * Copyright (c) 2007 Bobby Bingham 00005 * 00006 * This file is part of Libav. 00007 * 00008 * Libav is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * Libav is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with Libav; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00028 #include "avfilter.h" 00029 #include "libavutil/eval.h" 00030 #include "libavutil/avstring.h" 00031 #include "libavutil/pixdesc.h" 00032 #include "libavutil/imgutils.h" 00033 #include "internal.h" 00034 00035 static const char *var_names[] = { 00036 "E", 00037 "PHI", 00038 "PI", 00039 "main_w", "W", 00040 "main_h", "H", 00041 "overlay_w", "w", 00042 "overlay_h", "h", 00043 NULL 00044 }; 00045 00046 enum var_name { 00047 VAR_E, 00048 VAR_PHI, 00049 VAR_PI, 00050 VAR_MAIN_W, VAR_MW, 00051 VAR_MAIN_H, VAR_MH, 00052 VAR_OVERLAY_W, VAR_OW, 00053 VAR_OVERLAY_H, VAR_OH, 00054 VAR_VARS_NB 00055 }; 00056 00057 #define MAIN 0 00058 #define OVERLAY 1 00059 00060 typedef struct { 00061 int x, y; 00062 00063 AVFilterBufferRef *overpicref; 00064 00065 int max_plane_step[4]; 00066 int hsub, vsub; 00067 00068 char x_expr[256], y_expr[256]; 00069 } OverlayContext; 00070 00071 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) 00072 { 00073 OverlayContext *over = ctx->priv; 00074 00075 av_strlcpy(over->x_expr, "0", sizeof(over->x_expr)); 00076 av_strlcpy(over->y_expr, "0", sizeof(over->y_expr)); 00077 00078 if (args) 00079 sscanf(args, "%255[^:]:%255[^:]", over->x_expr, over->y_expr); 00080 00081 return 0; 00082 } 00083 00084 static av_cold void uninit(AVFilterContext *ctx) 00085 { 00086 OverlayContext *over = ctx->priv; 00087 00088 if (over->overpicref) 00089 avfilter_unref_buffer(over->overpicref); 00090 } 00091 00092 static int query_formats(AVFilterContext *ctx) 00093 { 00094 const enum PixelFormat inout_pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE }; 00095 const enum PixelFormat blend_pix_fmts[] = { PIX_FMT_YUVA420P, PIX_FMT_NONE }; 00096 AVFilterFormats *inout_formats = avfilter_make_format_list(inout_pix_fmts); 00097 AVFilterFormats *blend_formats = avfilter_make_format_list(blend_pix_fmts); 00098 00099 avfilter_formats_ref(inout_formats, &ctx->inputs [MAIN ]->out_formats); 00100 avfilter_formats_ref(blend_formats, &ctx->inputs [OVERLAY]->out_formats); 00101 avfilter_formats_ref(inout_formats, &ctx->outputs[MAIN ]->in_formats ); 00102 00103 return 0; 00104 } 00105 00106 static int config_input_main(AVFilterLink *inlink) 00107 { 00108 OverlayContext *over = inlink->dst->priv; 00109 const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[inlink->format]; 00110 00111 av_image_fill_max_pixsteps(over->max_plane_step, NULL, pix_desc); 00112 over->hsub = pix_desc->log2_chroma_w; 00113 over->vsub = pix_desc->log2_chroma_h; 00114 00115 return 0; 00116 } 00117 00118 static int config_input_overlay(AVFilterLink *inlink) 00119 { 00120 AVFilterContext *ctx = inlink->dst; 00121 OverlayContext *over = inlink->dst->priv; 00122 char *expr; 00123 double var_values[VAR_VARS_NB], res; 00124 int ret; 00125 00126 /* Finish the configuration by evaluating the expressions 00127 now when both inputs are configured. */ 00128 var_values[VAR_E ] = M_E; 00129 var_values[VAR_PHI] = M_PHI; 00130 var_values[VAR_PI ] = M_PI; 00131 00132 var_values[VAR_MAIN_W ] = var_values[VAR_MW] = ctx->inputs[MAIN ]->w; 00133 var_values[VAR_MAIN_H ] = var_values[VAR_MH] = ctx->inputs[MAIN ]->h; 00134 var_values[VAR_OVERLAY_W] = var_values[VAR_OW] = ctx->inputs[OVERLAY]->w; 00135 var_values[VAR_OVERLAY_H] = var_values[VAR_OH] = ctx->inputs[OVERLAY]->h; 00136 00137 if ((ret = av_expr_parse_and_eval(&res, (expr = over->x_expr), var_names, var_values, 00138 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) 00139 goto fail; 00140 over->x = res; 00141 if ((ret = av_expr_parse_and_eval(&res, (expr = over->y_expr), var_names, var_values, 00142 NULL, NULL, NULL, NULL, NULL, 0, ctx))) 00143 goto fail; 00144 over->y = res; 00145 /* x may depend on y */ 00146 if ((ret = av_expr_parse_and_eval(&res, (expr = over->x_expr), var_names, var_values, 00147 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) 00148 goto fail; 00149 over->x = res; 00150 00151 av_log(ctx, AV_LOG_INFO, 00152 "main w:%d h:%d fmt:%s overlay x:%d y:%d w:%d h:%d fmt:%s\n", 00153 ctx->inputs[MAIN]->w, ctx->inputs[MAIN]->h, 00154 av_pix_fmt_descriptors[ctx->inputs[MAIN]->format].name, 00155 over->x, over->y, 00156 ctx->inputs[OVERLAY]->w, ctx->inputs[OVERLAY]->h, 00157 av_pix_fmt_descriptors[ctx->inputs[OVERLAY]->format].name); 00158 00159 if (over->x < 0 || over->y < 0 || 00160 over->x + var_values[VAR_OVERLAY_W] > var_values[VAR_MAIN_W] || 00161 over->y + var_values[VAR_OVERLAY_H] > var_values[VAR_MAIN_H]) { 00162 av_log(ctx, AV_LOG_ERROR, 00163 "Overlay area (%d,%d)<->(%d,%d) not within the main area (0,0)<->(%d,%d) or zero-sized\n", 00164 over->x, over->y, 00165 (int)(over->x + var_values[VAR_OVERLAY_W]), 00166 (int)(over->y + var_values[VAR_OVERLAY_H]), 00167 (int)var_values[VAR_MAIN_W], (int)var_values[VAR_MAIN_H]); 00168 return AVERROR(EINVAL); 00169 } 00170 return 0; 00171 00172 fail: 00173 av_log(NULL, AV_LOG_ERROR, 00174 "Error when evaluating the expression '%s'\n", expr); 00175 return ret; 00176 } 00177 00178 static int config_output(AVFilterLink *outlink) 00179 { 00180 AVFilterContext *ctx = outlink->src; 00181 int exact; 00182 // common timebase computation: 00183 AVRational tb1 = ctx->inputs[MAIN ]->time_base; 00184 AVRational tb2 = ctx->inputs[OVERLAY]->time_base; 00185 AVRational *tb = &ctx->outputs[0]->time_base; 00186 exact = av_reduce(&tb->num, &tb->den, 00187 av_gcd((int64_t)tb1.num * tb2.den, 00188 (int64_t)tb2.num * tb1.den), 00189 (int64_t)tb1.den * tb2.den, INT_MAX); 00190 av_log(ctx, AV_LOG_INFO, 00191 "main_tb:%d/%d overlay_tb:%d/%d -> tb:%d/%d exact:%d\n", 00192 tb1.num, tb1.den, tb2.num, tb2.den, tb->num, tb->den, exact); 00193 if (!exact) 00194 av_log(ctx, AV_LOG_WARNING, 00195 "Timestamp conversion inexact, timestamp information loss may occurr\n"); 00196 00197 outlink->w = ctx->inputs[MAIN]->w; 00198 outlink->h = ctx->inputs[MAIN]->h; 00199 00200 return 0; 00201 } 00202 00203 static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms, int w, int h) 00204 { 00205 return avfilter_get_video_buffer(link->dst->outputs[0], perms, w, h); 00206 } 00207 00208 static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref) 00209 { 00210 AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0); 00211 AVFilterContext *ctx = inlink->dst; 00212 OverlayContext *over = ctx->priv; 00213 00214 inlink->dst->outputs[0]->out_buf = outpicref; 00215 outpicref->pts = av_rescale_q(outpicref->pts, ctx->inputs[MAIN]->time_base, 00216 ctx->outputs[0]->time_base); 00217 00218 if (!over->overpicref || over->overpicref->pts < outpicref->pts) { 00219 AVFilterBufferRef *old = over->overpicref; 00220 over->overpicref = NULL; 00221 avfilter_request_frame(ctx->inputs[OVERLAY]); 00222 if (over->overpicref) { 00223 if (old) 00224 avfilter_unref_buffer(old); 00225 } else 00226 over->overpicref = old; 00227 } 00228 00229 avfilter_start_frame(inlink->dst->outputs[0], outpicref); 00230 } 00231 00232 static void start_frame_overlay(AVFilterLink *inlink, AVFilterBufferRef *inpicref) 00233 { 00234 AVFilterContext *ctx = inlink->dst; 00235 OverlayContext *over = ctx->priv; 00236 00237 over->overpicref = inpicref; 00238 over->overpicref->pts = av_rescale_q(inpicref->pts, ctx->inputs[OVERLAY]->time_base, 00239 ctx->outputs[0]->time_base); 00240 } 00241 00242 static void blend_slice(AVFilterContext *ctx, 00243 AVFilterBufferRef *dst, AVFilterBufferRef *src, 00244 int x, int y, int w, int h, 00245 int slice_y, int slice_w, int slice_h) 00246 { 00247 OverlayContext *over = ctx->priv; 00248 int i, j, k; 00249 int width, height; 00250 int overlay_end_y = y+h; 00251 int slice_end_y = slice_y+slice_h; 00252 int end_y, start_y; 00253 00254 width = FFMIN(slice_w - x, w); 00255 end_y = FFMIN(slice_end_y, overlay_end_y); 00256 start_y = FFMAX(y, slice_y); 00257 height = end_y - start_y; 00258 00259 if (dst->format == PIX_FMT_BGR24 || dst->format == PIX_FMT_RGB24) { 00260 uint8_t *dp = dst->data[0] + x * 3 + start_y * dst->linesize[0]; 00261 uint8_t *sp = src->data[0]; 00262 int b = dst->format == PIX_FMT_BGR24 ? 2 : 0; 00263 int r = dst->format == PIX_FMT_BGR24 ? 0 : 2; 00264 if (slice_y > y) 00265 sp += (slice_y - y) * src->linesize[0]; 00266 for (i = 0; i < height; i++) { 00267 uint8_t *d = dp, *s = sp; 00268 for (j = 0; j < width; j++) { 00269 d[r] = (d[r] * (0xff - s[3]) + s[0] * s[3] + 128) >> 8; 00270 d[1] = (d[1] * (0xff - s[3]) + s[1] * s[3] + 128) >> 8; 00271 d[b] = (d[b] * (0xff - s[3]) + s[2] * s[3] + 128) >> 8; 00272 d += 3; 00273 s += 4; 00274 } 00275 dp += dst->linesize[0]; 00276 sp += src->linesize[0]; 00277 } 00278 } else { 00279 for (i = 0; i < 3; i++) { 00280 int hsub = i ? over->hsub : 0; 00281 int vsub = i ? over->vsub : 0; 00282 uint8_t *dp = dst->data[i] + (x >> hsub) + 00283 (start_y >> vsub) * dst->linesize[i]; 00284 uint8_t *sp = src->data[i]; 00285 uint8_t *ap = src->data[3]; 00286 int wp = FFALIGN(width, 1<<hsub) >> hsub; 00287 int hp = FFALIGN(height, 1<<vsub) >> vsub; 00288 if (slice_y > y) { 00289 sp += ((slice_y - y) >> vsub) * src->linesize[i]; 00290 ap += (slice_y - y) * src->linesize[3]; 00291 } 00292 for (j = 0; j < hp; j++) { 00293 uint8_t *d = dp, *s = sp, *a = ap; 00294 for (k = 0; k < wp; k++) { 00295 // average alpha for color components, improve quality 00296 int alpha_v, alpha_h, alpha; 00297 if (hsub && vsub && j+1 < hp && k+1 < wp) { 00298 alpha = (a[0] + a[src->linesize[3]] + 00299 a[1] + a[src->linesize[3]+1]) >> 2; 00300 } else if (hsub || vsub) { 00301 alpha_h = hsub && k+1 < wp ? 00302 (a[0] + a[1]) >> 1 : a[0]; 00303 alpha_v = vsub && j+1 < hp ? 00304 (a[0] + a[src->linesize[3]]) >> 1 : a[0]; 00305 alpha = (alpha_v + alpha_h) >> 1; 00306 } else 00307 alpha = a[0]; 00308 *d = (*d * (0xff - alpha) + *s++ * alpha + 128) >> 8; 00309 d++; 00310 a += 1 << hsub; 00311 } 00312 dp += dst->linesize[i]; 00313 sp += src->linesize[i]; 00314 ap += (1 << vsub) * src->linesize[3]; 00315 } 00316 } 00317 } 00318 } 00319 00320 static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) 00321 { 00322 AVFilterContext *ctx = inlink->dst; 00323 AVFilterLink *outlink = ctx->outputs[0]; 00324 AVFilterBufferRef *outpicref = outlink->out_buf; 00325 OverlayContext *over = ctx->priv; 00326 00327 if (over->overpicref && 00328 !(over->x >= outpicref->video->w || over->y >= outpicref->video->h || 00329 y+h < over->y || y >= over->y + over->overpicref->video->h)) { 00330 blend_slice(ctx, outpicref, over->overpicref, over->x, over->y, 00331 over->overpicref->video->w, over->overpicref->video->h, 00332 y, outpicref->video->w, h); 00333 } 00334 avfilter_draw_slice(outlink, y, h, slice_dir); 00335 } 00336 00337 static void end_frame(AVFilterLink *inlink) 00338 { 00339 avfilter_end_frame(inlink->dst->outputs[0]); 00340 avfilter_unref_buffer(inlink->cur_buf); 00341 } 00342 00343 static void null_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) { } 00344 00345 static void null_end_frame(AVFilterLink *inlink) { } 00346 00347 AVFilter avfilter_vf_overlay = { 00348 .name = "overlay", 00349 .description = NULL_IF_CONFIG_SMALL("Overlay a video source on top of the input."), 00350 00351 .init = init, 00352 .uninit = uninit, 00353 00354 .priv_size = sizeof(OverlayContext), 00355 00356 .query_formats = query_formats, 00357 00358 .inputs = (AVFilterPad[]) {{ .name = "main", 00359 .type = AVMEDIA_TYPE_VIDEO, 00360 .start_frame = start_frame, 00361 .get_video_buffer= get_video_buffer, 00362 .config_props = config_input_main, 00363 .draw_slice = draw_slice, 00364 .end_frame = end_frame, 00365 .min_perms = AV_PERM_READ, 00366 .rej_perms = AV_PERM_REUSE2|AV_PERM_PRESERVE, }, 00367 { .name = "overlay", 00368 .type = AVMEDIA_TYPE_VIDEO, 00369 .start_frame = start_frame_overlay, 00370 .config_props = config_input_overlay, 00371 .draw_slice = null_draw_slice, 00372 .end_frame = null_end_frame, 00373 .min_perms = AV_PERM_READ, 00374 .rej_perms = AV_PERM_REUSE2, }, 00375 { .name = NULL}}, 00376 .outputs = (AVFilterPad[]) {{ .name = "default", 00377 .type = AVMEDIA_TYPE_VIDEO, 00378 .config_props = config_output, }, 00379 { .name = NULL}}, 00380 };