Libav 0.7.1
|
00001 /* 00002 * Copyright (c) 2007 Bobby Bingham 00003 * 00004 * This file is part of Libav. 00005 * 00006 * Libav is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * Libav is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with Libav; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00026 #include "avfilter.h" 00027 #include "libavutil/avstring.h" 00028 #include "libavutil/eval.h" 00029 #include "libavutil/pixdesc.h" 00030 #include "libswscale/swscale.h" 00031 00032 static const char *var_names[] = { 00033 "PI", 00034 "PHI", 00035 "E", 00036 "in_w", "iw", 00037 "in_h", "ih", 00038 "out_w", "ow", 00039 "out_h", "oh", 00040 "a", 00041 "hsub", 00042 "vsub", 00043 NULL 00044 }; 00045 00046 enum var_name { 00047 VAR_PI, 00048 VAR_PHI, 00049 VAR_E, 00050 VAR_IN_W, VAR_IW, 00051 VAR_IN_H, VAR_IH, 00052 VAR_OUT_W, VAR_OW, 00053 VAR_OUT_H, VAR_OH, 00054 VAR_A, 00055 VAR_HSUB, 00056 VAR_VSUB, 00057 VARS_NB 00058 }; 00059 00060 typedef struct { 00061 struct SwsContext *sws; 00062 00068 int w, h; 00069 unsigned int flags; 00070 00071 int hsub, vsub; 00072 int slice_y; 00073 int input_is_pal; 00074 00075 char w_expr[256]; 00076 char h_expr[256]; 00077 } ScaleContext; 00078 00079 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) 00080 { 00081 ScaleContext *scale = ctx->priv; 00082 const char *p; 00083 00084 av_strlcpy(scale->w_expr, "iw", sizeof(scale->w_expr)); 00085 av_strlcpy(scale->h_expr, "ih", sizeof(scale->h_expr)); 00086 00087 scale->flags = SWS_BILINEAR; 00088 if (args) { 00089 sscanf(args, "%255[^:]:%255[^:]", scale->w_expr, scale->h_expr); 00090 p = strstr(args,"flags="); 00091 if (p) scale->flags = strtoul(p+6, NULL, 0); 00092 } 00093 00094 return 0; 00095 } 00096 00097 static av_cold void uninit(AVFilterContext *ctx) 00098 { 00099 ScaleContext *scale = ctx->priv; 00100 sws_freeContext(scale->sws); 00101 scale->sws = NULL; 00102 } 00103 00104 static int query_formats(AVFilterContext *ctx) 00105 { 00106 AVFilterFormats *formats; 00107 enum PixelFormat pix_fmt; 00108 int ret; 00109 00110 if (ctx->inputs[0]) { 00111 formats = NULL; 00112 for (pix_fmt = 0; pix_fmt < PIX_FMT_NB; pix_fmt++) 00113 if ( sws_isSupportedInput(pix_fmt) 00114 && (ret = avfilter_add_format(&formats, pix_fmt)) < 0) { 00115 avfilter_formats_unref(&formats); 00116 return ret; 00117 } 00118 avfilter_formats_ref(formats, &ctx->inputs[0]->out_formats); 00119 } 00120 if (ctx->outputs[0]) { 00121 formats = NULL; 00122 for (pix_fmt = 0; pix_fmt < PIX_FMT_NB; pix_fmt++) 00123 if ( sws_isSupportedOutput(pix_fmt) 00124 && (ret = avfilter_add_format(&formats, pix_fmt)) < 0) { 00125 avfilter_formats_unref(&formats); 00126 return ret; 00127 } 00128 avfilter_formats_ref(formats, &ctx->outputs[0]->in_formats); 00129 } 00130 00131 return 0; 00132 } 00133 00134 static int config_props(AVFilterLink *outlink) 00135 { 00136 AVFilterContext *ctx = outlink->src; 00137 AVFilterLink *inlink = outlink->src->inputs[0]; 00138 ScaleContext *scale = ctx->priv; 00139 int64_t w, h; 00140 double var_values[VARS_NB], res; 00141 char *expr; 00142 int ret; 00143 00144 var_values[VAR_PI] = M_PI; 00145 var_values[VAR_PHI] = M_PHI; 00146 var_values[VAR_E] = M_E; 00147 var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w; 00148 var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h; 00149 var_values[VAR_OUT_W] = var_values[VAR_OW] = NAN; 00150 var_values[VAR_OUT_H] = var_values[VAR_OH] = NAN; 00151 var_values[VAR_A] = (float) inlink->w / inlink->h; 00152 var_values[VAR_HSUB] = 1<<av_pix_fmt_descriptors[inlink->format].log2_chroma_w; 00153 var_values[VAR_VSUB] = 1<<av_pix_fmt_descriptors[inlink->format].log2_chroma_h; 00154 00155 /* evaluate width and height */ 00156 av_expr_parse_and_eval(&res, (expr = scale->w_expr), 00157 var_names, var_values, 00158 NULL, NULL, NULL, NULL, NULL, 0, ctx); 00159 scale->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res; 00160 if ((ret = av_expr_parse_and_eval(&res, (expr = scale->h_expr), 00161 var_names, var_values, 00162 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) 00163 goto fail; 00164 scale->h = var_values[VAR_OUT_H] = var_values[VAR_OH] = res; 00165 /* evaluate again the width, as it may depend on the output height */ 00166 if ((ret = av_expr_parse_and_eval(&res, (expr = scale->w_expr), 00167 var_names, var_values, 00168 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) 00169 goto fail; 00170 scale->w = res; 00171 00172 w = scale->w; 00173 h = scale->h; 00174 00175 /* sanity check params */ 00176 if (w < -1 || h < -1) { 00177 av_log(ctx, AV_LOG_ERROR, "Size values less than -1 are not acceptable.\n"); 00178 return AVERROR(EINVAL); 00179 } 00180 if (w == -1 && h == -1) 00181 scale->w = scale->h = 0; 00182 00183 if (!(w = scale->w)) 00184 w = inlink->w; 00185 if (!(h = scale->h)) 00186 h = inlink->h; 00187 if (w == -1) 00188 w = av_rescale(h, inlink->w, inlink->h); 00189 if (h == -1) 00190 h = av_rescale(w, inlink->h, inlink->w); 00191 00192 if (w > INT_MAX || h > INT_MAX || 00193 (h * inlink->w) > INT_MAX || 00194 (w * inlink->h) > INT_MAX) 00195 av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n"); 00196 00197 outlink->w = w; 00198 outlink->h = h; 00199 00200 /* TODO: make algorithm configurable */ 00201 av_log(ctx, AV_LOG_INFO, "w:%d h:%d fmt:%s -> w:%d h:%d fmt:%s flags:0x%0x\n", 00202 inlink ->w, inlink ->h, av_pix_fmt_descriptors[ inlink->format].name, 00203 outlink->w, outlink->h, av_pix_fmt_descriptors[outlink->format].name, 00204 scale->flags); 00205 00206 scale->input_is_pal = av_pix_fmt_descriptors[inlink->format].flags & PIX_FMT_PAL; 00207 00208 if (scale->sws) 00209 sws_freeContext(scale->sws); 00210 scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format, 00211 outlink->w, outlink->h, outlink->format, 00212 scale->flags, NULL, NULL, NULL); 00213 if (!scale->sws) 00214 return AVERROR(EINVAL); 00215 00216 00217 if (inlink->sample_aspect_ratio.num) 00218 outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w, 00219 outlink->w*inlink->h}, 00220 inlink->sample_aspect_ratio); 00221 else 00222 outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; 00223 00224 return 0; 00225 00226 fail: 00227 av_log(NULL, AV_LOG_ERROR, 00228 "Error when evaluating the expression '%s'\n", expr); 00229 return ret; 00230 } 00231 00232 static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref) 00233 { 00234 ScaleContext *scale = link->dst->priv; 00235 AVFilterLink *outlink = link->dst->outputs[0]; 00236 AVFilterBufferRef *outpicref; 00237 00238 scale->hsub = av_pix_fmt_descriptors[link->format].log2_chroma_w; 00239 scale->vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h; 00240 00241 outpicref = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); 00242 avfilter_copy_buffer_ref_props(outpicref, picref); 00243 outpicref->video->w = outlink->w; 00244 outpicref->video->h = outlink->h; 00245 00246 outlink->out_buf = outpicref; 00247 00248 av_reduce(&outpicref->video->pixel_aspect.num, &outpicref->video->pixel_aspect.den, 00249 (int64_t)picref->video->pixel_aspect.num * outlink->h * link->w, 00250 (int64_t)picref->video->pixel_aspect.den * outlink->w * link->h, 00251 INT_MAX); 00252 00253 scale->slice_y = 0; 00254 avfilter_start_frame(outlink, avfilter_ref_buffer(outpicref, ~0)); 00255 } 00256 00257 static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir) 00258 { 00259 ScaleContext *scale = link->dst->priv; 00260 int out_h; 00261 AVFilterBufferRef *cur_pic = link->cur_buf; 00262 const uint8_t *data[4]; 00263 00264 if (scale->slice_y == 0 && slice_dir == -1) 00265 scale->slice_y = link->dst->outputs[0]->h; 00266 00267 data[0] = cur_pic->data[0] + y * cur_pic->linesize[0]; 00268 data[1] = scale->input_is_pal ? 00269 cur_pic->data[1] : 00270 cur_pic->data[1] + (y>>scale->vsub) * cur_pic->linesize[1]; 00271 data[2] = cur_pic->data[2] + (y>>scale->vsub) * cur_pic->linesize[2]; 00272 data[3] = cur_pic->data[3] + y * cur_pic->linesize[3]; 00273 00274 out_h = sws_scale(scale->sws, data, cur_pic->linesize, y, h, 00275 link->dst->outputs[0]->out_buf->data, 00276 link->dst->outputs[0]->out_buf->linesize); 00277 00278 if (slice_dir == -1) 00279 scale->slice_y -= out_h; 00280 avfilter_draw_slice(link->dst->outputs[0], scale->slice_y, out_h, slice_dir); 00281 if (slice_dir == 1) 00282 scale->slice_y += out_h; 00283 } 00284 00285 AVFilter avfilter_vf_scale = { 00286 .name = "scale", 00287 .description = NULL_IF_CONFIG_SMALL("Scale the input video to width:height size and/or convert the image format."), 00288 00289 .init = init, 00290 .uninit = uninit, 00291 00292 .query_formats = query_formats, 00293 00294 .priv_size = sizeof(ScaleContext), 00295 00296 .inputs = (AVFilterPad[]) {{ .name = "default", 00297 .type = AVMEDIA_TYPE_VIDEO, 00298 .start_frame = start_frame, 00299 .draw_slice = draw_slice, 00300 .min_perms = AV_PERM_READ, }, 00301 { .name = NULL}}, 00302 .outputs = (AVFilterPad[]) {{ .name = "default", 00303 .type = AVMEDIA_TYPE_VIDEO, 00304 .config_props = config_props, }, 00305 { .name = NULL}}, 00306 };