Libav
|
00001 /* 00002 * copyright (c) 2007 Bobby Bingham 00003 * 00004 * This file is part of FFmpeg. 00005 * 00006 * FFmpeg 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 * FFmpeg 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 FFmpeg; 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/pixdesc.h" 00028 #include "libswscale/swscale.h" 00029 00030 typedef struct { 00031 struct SwsContext *sws; 00032 00038 int w, h; 00039 00040 int hsub, vsub; 00041 int slice_y; 00042 int input_is_pal; 00043 } ScaleContext; 00044 00045 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) 00046 { 00047 ScaleContext *scale = ctx->priv; 00048 00049 if (args) 00050 sscanf(args, "%d:%d", &scale->w, &scale->h); 00051 00052 /* sanity check params */ 00053 if (scale->w < -1 || scale->h < -1) { 00054 av_log(ctx, AV_LOG_ERROR, "Size values less than -1 are not acceptable.\n"); 00055 return -1; 00056 } 00057 if (scale->w == -1 && scale->h == -1) 00058 scale->w = scale->h = 0; 00059 00060 return 0; 00061 } 00062 00063 static av_cold void uninit(AVFilterContext *ctx) 00064 { 00065 ScaleContext *scale = ctx->priv; 00066 sws_freeContext(scale->sws); 00067 scale->sws = NULL; 00068 } 00069 00070 static int query_formats(AVFilterContext *ctx) 00071 { 00072 AVFilterFormats *formats; 00073 enum PixelFormat pix_fmt; 00074 int ret; 00075 00076 if (ctx->inputs[0]) { 00077 formats = NULL; 00078 for (pix_fmt = 0; pix_fmt < PIX_FMT_NB; pix_fmt++) 00079 if ( sws_isSupportedInput(pix_fmt) 00080 && (ret = avfilter_add_colorspace(&formats, pix_fmt)) < 0) { 00081 avfilter_formats_unref(&formats); 00082 return ret; 00083 } 00084 avfilter_formats_ref(formats, &ctx->inputs[0]->out_formats); 00085 } 00086 if (ctx->outputs[0]) { 00087 formats = NULL; 00088 for (pix_fmt = 0; pix_fmt < PIX_FMT_NB; pix_fmt++) 00089 if ( sws_isSupportedOutput(pix_fmt) 00090 && (ret = avfilter_add_colorspace(&formats, pix_fmt)) < 0) { 00091 avfilter_formats_unref(&formats); 00092 return ret; 00093 } 00094 avfilter_formats_ref(formats, &ctx->outputs[0]->in_formats); 00095 } 00096 00097 return 0; 00098 } 00099 00100 static int config_props(AVFilterLink *outlink) 00101 { 00102 AVFilterContext *ctx = outlink->src; 00103 AVFilterLink *inlink = outlink->src->inputs[0]; 00104 ScaleContext *scale = ctx->priv; 00105 int64_t w, h; 00106 00107 if (!(w = scale->w)) 00108 w = inlink->w; 00109 if (!(h = scale->h)) 00110 h = inlink->h; 00111 if (w == -1) 00112 w = av_rescale(h, inlink->w, inlink->h); 00113 if (h == -1) 00114 h = av_rescale(w, inlink->h, inlink->w); 00115 00116 if (w > INT_MAX || h > INT_MAX || 00117 (h * inlink->w) > INT_MAX || 00118 (w * inlink->h) > INT_MAX) 00119 av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n"); 00120 00121 outlink->w = w; 00122 outlink->h = h; 00123 00124 /* TODO: make algorithm configurable */ 00125 scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format, 00126 outlink->w, outlink->h, outlink->format, 00127 SWS_BILINEAR, NULL, NULL, NULL); 00128 00129 av_log(ctx, AV_LOG_INFO, "w:%d h:%d fmt:%s\n", 00130 outlink->w, outlink->h, av_pix_fmt_descriptors[outlink->format].name); 00131 00132 scale->input_is_pal = av_pix_fmt_descriptors[inlink->format].flags & PIX_FMT_PAL; 00133 00134 return !scale->sws; 00135 } 00136 00137 static void start_frame(AVFilterLink *link, AVFilterPicRef *picref) 00138 { 00139 ScaleContext *scale = link->dst->priv; 00140 AVFilterLink *outlink = link->dst->outputs[0]; 00141 AVFilterPicRef *outpicref; 00142 00143 scale->hsub = av_pix_fmt_descriptors[link->format].log2_chroma_w; 00144 scale->vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h; 00145 00146 outpicref = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); 00147 outpicref->pts = picref->pts; 00148 outpicref->pos = picref->pos; 00149 outlink->outpic = outpicref; 00150 00151 av_reduce(&outpicref->pixel_aspect.num, &outpicref->pixel_aspect.den, 00152 (int64_t)picref->pixel_aspect.num * outlink->h * link->w, 00153 (int64_t)picref->pixel_aspect.den * outlink->w * link->h, 00154 INT_MAX); 00155 00156 scale->slice_y = 0; 00157 avfilter_start_frame(outlink, avfilter_ref_pic(outpicref, ~0)); 00158 } 00159 00160 static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir) 00161 { 00162 ScaleContext *scale = link->dst->priv; 00163 int out_h; 00164 AVFilterPicRef *cur_pic = link->cur_pic; 00165 uint8_t *data[4]; 00166 00167 if (scale->slice_y == 0 && slice_dir == -1) 00168 scale->slice_y = link->dst->outputs[0]->h; 00169 00170 data[0] = cur_pic->data[0] + y * cur_pic->linesize[0]; 00171 data[1] = scale->input_is_pal ? 00172 cur_pic->data[1] : 00173 cur_pic->data[1] + (y>>scale->vsub) * cur_pic->linesize[1]; 00174 data[2] = cur_pic->data[2] + (y>>scale->vsub) * cur_pic->linesize[2]; 00175 data[3] = cur_pic->data[3] + y * cur_pic->linesize[3]; 00176 00177 out_h = sws_scale(scale->sws, data, cur_pic->linesize, y, h, 00178 link->dst->outputs[0]->outpic->data, 00179 link->dst->outputs[0]->outpic->linesize); 00180 00181 if (slice_dir == -1) 00182 scale->slice_y -= out_h; 00183 avfilter_draw_slice(link->dst->outputs[0], scale->slice_y, out_h, slice_dir); 00184 if (slice_dir == 1) 00185 scale->slice_y += out_h; 00186 } 00187 00188 AVFilter avfilter_vf_scale = { 00189 .name = "scale", 00190 .description = "Scale the input video to width:height size and/or convert the image format.", 00191 00192 .init = init, 00193 .uninit = uninit, 00194 00195 .query_formats = query_formats, 00196 00197 .priv_size = sizeof(ScaleContext), 00198 00199 .inputs = (AVFilterPad[]) {{ .name = "default", 00200 .type = AVMEDIA_TYPE_VIDEO, 00201 .start_frame = start_frame, 00202 .draw_slice = draw_slice, 00203 .min_perms = AV_PERM_READ, }, 00204 { .name = NULL}}, 00205 .outputs = (AVFilterPad[]) {{ .name = "default", 00206 .type = AVMEDIA_TYPE_VIDEO, 00207 .config_props = config_props, }, 00208 { .name = NULL}}, 00209 };