Libav 0.7.1
|
00001 /* 00002 * Copyright (c) 2010 Stefano Sabatini 00003 * Copyright (c) 2008 Vitor Sessak 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00028 #include "libavutil/intreadwrite.h" 00029 #include "libavutil/pixdesc.h" 00030 #include "libavutil/imgutils.h" 00031 #include "avfilter.h" 00032 00033 typedef struct { 00034 int hsub, vsub; 00035 int pixsteps[4]; 00036 00037 /* 0 Rotate by 90 degrees counterclockwise and vflip. */ 00038 /* 1 Rotate by 90 degrees clockwise. */ 00039 /* 2 Rotate by 90 degrees counterclockwise. */ 00040 /* 3 Rotate by 90 degrees clockwise and vflip. */ 00041 int dir; 00042 } TransContext; 00043 00044 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) 00045 { 00046 TransContext *trans = ctx->priv; 00047 trans->dir = 0; 00048 00049 if (args) 00050 sscanf(args, "%d", &trans->dir); 00051 00052 if (trans->dir < 0 || trans->dir > 3) { 00053 av_log(ctx, AV_LOG_ERROR, "Invalid value %d not between 0 and 3.\n", 00054 trans->dir); 00055 return AVERROR(EINVAL); 00056 } 00057 return 0; 00058 } 00059 00060 static int query_formats(AVFilterContext *ctx) 00061 { 00062 enum PixelFormat pix_fmts[] = { 00063 PIX_FMT_ARGB, PIX_FMT_RGBA, 00064 PIX_FMT_ABGR, PIX_FMT_BGRA, 00065 PIX_FMT_RGB24, PIX_FMT_BGR24, 00066 PIX_FMT_RGB565BE, PIX_FMT_RGB565LE, 00067 PIX_FMT_RGB555BE, PIX_FMT_RGB555LE, 00068 PIX_FMT_BGR565BE, PIX_FMT_BGR565LE, 00069 PIX_FMT_BGR555BE, PIX_FMT_BGR555LE, 00070 PIX_FMT_GRAY16BE, PIX_FMT_GRAY16LE, 00071 PIX_FMT_YUV420P16LE, PIX_FMT_YUV420P16BE, 00072 PIX_FMT_YUV422P16LE, PIX_FMT_YUV422P16BE, 00073 PIX_FMT_YUV444P16LE, PIX_FMT_YUV444P16BE, 00074 PIX_FMT_NV12, PIX_FMT_NV21, 00075 PIX_FMT_RGB8, PIX_FMT_BGR8, 00076 PIX_FMT_RGB4_BYTE, PIX_FMT_BGR4_BYTE, 00077 PIX_FMT_YUV444P, PIX_FMT_YUV422P, 00078 PIX_FMT_YUV420P, PIX_FMT_YUVJ420P, 00079 PIX_FMT_YUV411P, PIX_FMT_YUV410P, 00080 PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, 00081 PIX_FMT_YUV440P, PIX_FMT_YUVJ440P, 00082 PIX_FMT_YUVA420P, PIX_FMT_GRAY8, 00083 PIX_FMT_NONE 00084 }; 00085 00086 avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); 00087 return 0; 00088 } 00089 00090 static int config_props_output(AVFilterLink *outlink) 00091 { 00092 AVFilterContext *ctx = outlink->src; 00093 TransContext *trans = ctx->priv; 00094 AVFilterLink *inlink = ctx->inputs[0]; 00095 const AVPixFmtDescriptor *pixdesc = &av_pix_fmt_descriptors[outlink->format]; 00096 00097 trans->hsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_w; 00098 trans->vsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_h; 00099 00100 av_image_fill_max_pixsteps(trans->pixsteps, NULL, pixdesc); 00101 00102 outlink->w = inlink->h; 00103 outlink->h = inlink->w; 00104 00105 if (inlink->sample_aspect_ratio.num){ 00106 outlink->sample_aspect_ratio = av_div_q((AVRational){1,1}, inlink->sample_aspect_ratio); 00107 } else 00108 outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; 00109 00110 av_log(ctx, AV_LOG_INFO, "w:%d h:%d dir:%d -> w:%d h:%d rotation:%s vflip:%d\n", 00111 inlink->w, inlink->h, trans->dir, outlink->w, outlink->h, 00112 trans->dir == 1 || trans->dir == 3 ? "clockwise" : "counterclockwise", 00113 trans->dir == 0 || trans->dir == 3); 00114 return 0; 00115 } 00116 00117 static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) 00118 { 00119 AVFilterLink *outlink = inlink->dst->outputs[0]; 00120 00121 outlink->out_buf = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, 00122 outlink->w, outlink->h); 00123 outlink->out_buf->pts = picref->pts; 00124 00125 if (picref->video->pixel_aspect.num == 0) { 00126 outlink->out_buf->video->pixel_aspect = picref->video->pixel_aspect; 00127 } else { 00128 outlink->out_buf->video->pixel_aspect.num = picref->video->pixel_aspect.den; 00129 outlink->out_buf->video->pixel_aspect.den = picref->video->pixel_aspect.num; 00130 } 00131 00132 avfilter_start_frame(outlink, avfilter_ref_buffer(outlink->out_buf, ~0)); 00133 } 00134 00135 static void end_frame(AVFilterLink *inlink) 00136 { 00137 TransContext *trans = inlink->dst->priv; 00138 AVFilterBufferRef *inpic = inlink->cur_buf; 00139 AVFilterBufferRef *outpic = inlink->dst->outputs[0]->out_buf; 00140 AVFilterLink *outlink = inlink->dst->outputs[0]; 00141 int plane; 00142 00143 for (plane = 0; outpic->data[plane]; plane++) { 00144 int hsub = plane == 1 || plane == 2 ? trans->hsub : 0; 00145 int vsub = plane == 1 || plane == 2 ? trans->vsub : 0; 00146 int pixstep = trans->pixsteps[plane]; 00147 int inh = inpic->video->h>>vsub; 00148 int outw = outpic->video->w>>hsub; 00149 int outh = outpic->video->h>>vsub; 00150 uint8_t *out, *in; 00151 int outlinesize, inlinesize; 00152 int x, y; 00153 00154 out = outpic->data[plane]; outlinesize = outpic->linesize[plane]; 00155 in = inpic ->data[plane]; inlinesize = inpic ->linesize[plane]; 00156 00157 if (trans->dir&1) { 00158 in += inpic->linesize[plane] * (inh-1); 00159 inlinesize *= -1; 00160 } 00161 00162 if (trans->dir&2) { 00163 out += outpic->linesize[plane] * (outh-1); 00164 outlinesize *= -1; 00165 } 00166 00167 for (y = 0; y < outh; y++) { 00168 switch (pixstep) { 00169 case 1: 00170 for (x = 0; x < outw; x++) 00171 out[x] = in[x*inlinesize + y]; 00172 break; 00173 case 2: 00174 for (x = 0; x < outw; x++) 00175 *((uint16_t *)(out + 2*x)) = *((uint16_t *)(in + x*inlinesize + y*2)); 00176 break; 00177 case 3: 00178 for (x = 0; x < outw; x++) { 00179 int32_t v = AV_RB24(in + x*inlinesize + y*3); 00180 AV_WB24(out + 3*x, v); 00181 } 00182 break; 00183 case 4: 00184 for (x = 0; x < outw; x++) 00185 *((uint32_t *)(out + 4*x)) = *((uint32_t *)(in + x*inlinesize + y*4)); 00186 break; 00187 } 00188 out += outlinesize; 00189 } 00190 } 00191 00192 avfilter_unref_buffer(inpic); 00193 avfilter_draw_slice(outlink, 0, outpic->video->h, 1); 00194 avfilter_end_frame(outlink); 00195 avfilter_unref_buffer(outpic); 00196 } 00197 00198 AVFilter avfilter_vf_transpose = { 00199 .name = "transpose", 00200 .description = NULL_IF_CONFIG_SMALL("Transpose input video."), 00201 00202 .init = init, 00203 .priv_size = sizeof(TransContext), 00204 00205 .query_formats = query_formats, 00206 00207 .inputs = (AVFilterPad[]) {{ .name = "default", 00208 .type = AVMEDIA_TYPE_VIDEO, 00209 .start_frame = start_frame, 00210 .end_frame = end_frame, 00211 .min_perms = AV_PERM_READ, }, 00212 { .name = NULL}}, 00213 .outputs = (AVFilterPad[]) {{ .name = "default", 00214 .config_props = config_props_output, 00215 .type = AVMEDIA_TYPE_VIDEO, }, 00216 { .name = NULL}}, 00217 };