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 00029 typedef struct { 00030 int x; 00031 int y; 00032 int w; 00033 int h; 00034 00035 int bpp; 00036 int hsub, vsub; 00037 } CropContext; 00038 00039 static int query_formats(AVFilterContext *ctx) 00040 { 00041 static const enum PixelFormat pix_fmts[] = { 00042 PIX_FMT_RGB48BE, PIX_FMT_RGB48LE, 00043 PIX_FMT_ARGB, PIX_FMT_RGBA, 00044 PIX_FMT_ABGR, PIX_FMT_BGRA, 00045 PIX_FMT_RGB24, PIX_FMT_BGR24, 00046 PIX_FMT_RGB565BE, PIX_FMT_RGB565LE, 00047 PIX_FMT_RGB555BE, PIX_FMT_RGB555LE, 00048 PIX_FMT_BGR565BE, PIX_FMT_BGR565LE, 00049 PIX_FMT_BGR555BE, PIX_FMT_BGR555LE, 00050 PIX_FMT_GRAY16BE, PIX_FMT_GRAY16LE, 00051 PIX_FMT_YUV420P16LE, PIX_FMT_YUV420P16BE, 00052 PIX_FMT_YUV422P16LE, PIX_FMT_YUV422P16BE, 00053 PIX_FMT_YUV444P16LE, PIX_FMT_YUV444P16BE, 00054 PIX_FMT_YUV444P, PIX_FMT_YUV422P, 00055 PIX_FMT_YUV420P, PIX_FMT_YUV411P, 00056 PIX_FMT_YUV410P, PIX_FMT_YUV440P, 00057 PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, 00058 PIX_FMT_YUVJ420P, PIX_FMT_YUVJ440P, 00059 PIX_FMT_YUVA420P, 00060 PIX_FMT_RGB8, PIX_FMT_BGR8, 00061 PIX_FMT_RGB4_BYTE, PIX_FMT_BGR4_BYTE, 00062 PIX_FMT_PAL8, PIX_FMT_GRAY8, 00063 PIX_FMT_NONE 00064 }; 00065 00066 avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); 00067 00068 return 0; 00069 } 00070 00071 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) 00072 { 00073 CropContext *crop = ctx->priv; 00074 00075 if (args) 00076 sscanf(args, "%d:%d:%d:%d", &crop->x, &crop->y, &crop->w, &crop->h); 00077 00078 return 0; 00079 } 00080 00081 static int config_input(AVFilterLink *link) 00082 { 00083 AVFilterContext *ctx = link->dst; 00084 CropContext *crop = ctx->priv; 00085 00086 switch (link->format) { 00087 case PIX_FMT_RGB48BE: 00088 case PIX_FMT_RGB48LE: 00089 crop->bpp = 48; 00090 break; 00091 case PIX_FMT_ARGB: 00092 case PIX_FMT_RGBA: 00093 case PIX_FMT_ABGR: 00094 case PIX_FMT_BGRA: 00095 crop->bpp = 32; 00096 break; 00097 case PIX_FMT_RGB24: 00098 case PIX_FMT_BGR24: 00099 crop->bpp = 24; 00100 break; 00101 case PIX_FMT_RGB565BE: 00102 case PIX_FMT_RGB565LE: 00103 case PIX_FMT_RGB555BE: 00104 case PIX_FMT_RGB555LE: 00105 case PIX_FMT_BGR565BE: 00106 case PIX_FMT_BGR565LE: 00107 case PIX_FMT_BGR555BE: 00108 case PIX_FMT_BGR555LE: 00109 case PIX_FMT_GRAY16BE: 00110 case PIX_FMT_GRAY16LE: 00111 case PIX_FMT_YUV420P16LE: 00112 case PIX_FMT_YUV420P16BE: 00113 case PIX_FMT_YUV422P16LE: 00114 case PIX_FMT_YUV422P16BE: 00115 case PIX_FMT_YUV444P16LE: 00116 case PIX_FMT_YUV444P16BE: 00117 crop->bpp = 16; 00118 break; 00119 default: 00120 crop->bpp = 8; 00121 } 00122 00123 avcodec_get_chroma_sub_sample(link->format, &crop->hsub, &crop->vsub); 00124 00125 if (crop->w == 0) 00126 crop->w = link->w - crop->x; 00127 if (crop->h == 0) 00128 crop->h = link->h - crop->y; 00129 00130 crop->x &= ~((1 << crop->hsub) - 1); 00131 crop->y &= ~((1 << crop->vsub) - 1); 00132 00133 av_log(link->dst, AV_LOG_INFO, "x:%d y:%d w:%d h:%d\n", 00134 crop->x, crop->y, crop->w, crop->h); 00135 00136 if (crop->x < 0 || crop->y < 0 || 00137 crop->w <= 0 || crop->h <= 0 || 00138 (unsigned)crop->x + (unsigned)crop->w > link->w || 00139 (unsigned)crop->y + (unsigned)crop->h > link->h) { 00140 av_log(ctx, AV_LOG_ERROR, 00141 "Output area %d:%d:%d:%d not within the input area 0:0:%d:%d or zero-sized\n", 00142 crop->x, crop->y, crop->w, crop->h, link->w, link->h); 00143 return -1; 00144 } 00145 00146 return 0; 00147 } 00148 00149 static int config_output(AVFilterLink *link) 00150 { 00151 CropContext *crop = link->src->priv; 00152 00153 link->w = crop->w; 00154 link->h = crop->h; 00155 00156 return 0; 00157 } 00158 00159 static void start_frame(AVFilterLink *link, AVFilterPicRef *picref) 00160 { 00161 CropContext *crop = link->dst->priv; 00162 AVFilterPicRef *ref2 = avfilter_ref_pic(picref, ~0); 00163 int i; 00164 00165 ref2->w = crop->w; 00166 ref2->h = crop->h; 00167 00168 ref2->data[0] += crop->y * ref2->linesize[0]; 00169 ref2->data[0] += (crop->x * crop->bpp) >> 3; 00170 00171 if (!(av_pix_fmt_descriptors[link->format].flags & PIX_FMT_PAL)) { 00172 for (i = 1; i < 3; i ++) { 00173 if (ref2->data[i]) { 00174 ref2->data[i] += (crop->y >> crop->vsub) * ref2->linesize[i]; 00175 ref2->data[i] += ((crop->x * crop->bpp) >> 3) >> crop->hsub; 00176 } 00177 } 00178 } 00179 00180 /* alpha plane */ 00181 if (ref2->data[3]) { 00182 ref2->data[3] += crop->y * ref2->linesize[3]; 00183 ref2->data[3] += (crop->x * crop->bpp) >> 3; 00184 } 00185 00186 avfilter_start_frame(link->dst->outputs[0], ref2); 00187 } 00188 00189 static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir) 00190 { 00191 AVFilterContext *ctx = link->dst; 00192 CropContext *crop = ctx->priv; 00193 00194 if (y >= crop->y + crop->h || y + h <= crop->y) 00195 return; 00196 00197 if (y < crop->y) { 00198 h -= crop->y - y; 00199 y = crop->y; 00200 } 00201 if (y + h > crop->y + crop->h) 00202 h = crop->y + crop->h - y; 00203 00204 avfilter_draw_slice(ctx->outputs[0], y - crop->y, h, slice_dir); 00205 } 00206 00207 AVFilter avfilter_vf_crop = { 00208 .name = "crop", 00209 .description = NULL_IF_CONFIG_SMALL("Crop the input video to x:y:width:height."), 00210 00211 .priv_size = sizeof(CropContext), 00212 00213 .query_formats = query_formats, 00214 .init = init, 00215 00216 .inputs = (AVFilterPad[]) {{ .name = "default", 00217 .type = AVMEDIA_TYPE_VIDEO, 00218 .start_frame = start_frame, 00219 .draw_slice = draw_slice, 00220 .get_video_buffer = avfilter_null_get_video_buffer, 00221 .config_props = config_input, }, 00222 { .name = NULL}}, 00223 .outputs = (AVFilterPad[]) {{ .name = "default", 00224 .type = AVMEDIA_TYPE_VIDEO, 00225 .config_props = config_output, }, 00226 { .name = NULL}}, 00227 };