annotate ffmpeg/libavfilter/vf_transpose.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * Copyright (c) 2010 Stefano Sabatini
yading@11 3 * Copyright (c) 2008 Vitor Sessak
yading@11 4 *
yading@11 5 * This file is part of FFmpeg.
yading@11 6 *
yading@11 7 * FFmpeg is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * FFmpeg is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with FFmpeg; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 /**
yading@11 23 * @file
yading@11 24 * transposition filter
yading@11 25 * Based on MPlayer libmpcodecs/vf_rotate.c.
yading@11 26 */
yading@11 27
yading@11 28 #include <stdio.h>
yading@11 29
yading@11 30 #include "libavutil/intreadwrite.h"
yading@11 31 #include "libavutil/opt.h"
yading@11 32 #include "libavutil/pixdesc.h"
yading@11 33 #include "libavutil/imgutils.h"
yading@11 34 #include "libavutil/internal.h"
yading@11 35 #include "libavutil/opt.h"
yading@11 36 #include "avfilter.h"
yading@11 37 #include "formats.h"
yading@11 38 #include "internal.h"
yading@11 39 #include "video.h"
yading@11 40
yading@11 41 typedef enum {
yading@11 42 TRANSPOSE_PT_TYPE_NONE,
yading@11 43 TRANSPOSE_PT_TYPE_LANDSCAPE,
yading@11 44 TRANSPOSE_PT_TYPE_PORTRAIT,
yading@11 45 } PassthroughType;
yading@11 46
yading@11 47 enum TransposeDir {
yading@11 48 TRANSPOSE_CCLOCK_FLIP,
yading@11 49 TRANSPOSE_CLOCK,
yading@11 50 TRANSPOSE_CCLOCK,
yading@11 51 TRANSPOSE_CLOCK_FLIP,
yading@11 52 };
yading@11 53
yading@11 54 typedef struct {
yading@11 55 const AVClass *class;
yading@11 56 int hsub, vsub;
yading@11 57 int pixsteps[4];
yading@11 58
yading@11 59 PassthroughType passthrough; ///< landscape passthrough mode enabled
yading@11 60 enum TransposeDir dir;
yading@11 61 } TransContext;
yading@11 62
yading@11 63 static int query_formats(AVFilterContext *ctx)
yading@11 64 {
yading@11 65 AVFilterFormats *pix_fmts = NULL;
yading@11 66 int fmt;
yading@11 67
yading@11 68 for (fmt = 0; fmt < AV_PIX_FMT_NB; fmt++) {
yading@11 69 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
yading@11 70 if (!(desc->flags & PIX_FMT_PAL ||
yading@11 71 desc->flags & PIX_FMT_HWACCEL ||
yading@11 72 desc->flags & PIX_FMT_BITSTREAM ||
yading@11 73 desc->log2_chroma_w != desc->log2_chroma_h))
yading@11 74 ff_add_format(&pix_fmts, fmt);
yading@11 75 }
yading@11 76
yading@11 77
yading@11 78 ff_set_common_formats(ctx, pix_fmts);
yading@11 79 return 0;
yading@11 80 }
yading@11 81
yading@11 82 static int config_props_output(AVFilterLink *outlink)
yading@11 83 {
yading@11 84 AVFilterContext *ctx = outlink->src;
yading@11 85 TransContext *trans = ctx->priv;
yading@11 86 AVFilterLink *inlink = ctx->inputs[0];
yading@11 87 const AVPixFmtDescriptor *desc_out = av_pix_fmt_desc_get(outlink->format);
yading@11 88 const AVPixFmtDescriptor *desc_in = av_pix_fmt_desc_get(inlink->format);
yading@11 89
yading@11 90 if (trans->dir&4) {
yading@11 91 av_log(ctx, AV_LOG_WARNING,
yading@11 92 "dir values greater than 3 are deprecated, use the passthrough option instead\n");
yading@11 93 trans->dir &= 3;
yading@11 94 trans->passthrough = TRANSPOSE_PT_TYPE_LANDSCAPE;
yading@11 95 }
yading@11 96
yading@11 97 if ((inlink->w >= inlink->h && trans->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) ||
yading@11 98 (inlink->w <= inlink->h && trans->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) {
yading@11 99 av_log(ctx, AV_LOG_VERBOSE,
yading@11 100 "w:%d h:%d -> w:%d h:%d (passthrough mode)\n",
yading@11 101 inlink->w, inlink->h, inlink->w, inlink->h);
yading@11 102 return 0;
yading@11 103 } else {
yading@11 104 trans->passthrough = TRANSPOSE_PT_TYPE_NONE;
yading@11 105 }
yading@11 106
yading@11 107 trans->hsub = desc_in->log2_chroma_w;
yading@11 108 trans->vsub = desc_in->log2_chroma_h;
yading@11 109
yading@11 110 av_image_fill_max_pixsteps(trans->pixsteps, NULL, desc_out);
yading@11 111
yading@11 112 outlink->w = inlink->h;
yading@11 113 outlink->h = inlink->w;
yading@11 114
yading@11 115 if (inlink->sample_aspect_ratio.num){
yading@11 116 outlink->sample_aspect_ratio = av_div_q((AVRational){1,1}, inlink->sample_aspect_ratio);
yading@11 117 } else
yading@11 118 outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
yading@11 119
yading@11 120 av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d dir:%d -> w:%d h:%d rotation:%s vflip:%d\n",
yading@11 121 inlink->w, inlink->h, trans->dir, outlink->w, outlink->h,
yading@11 122 trans->dir == 1 || trans->dir == 3 ? "clockwise" : "counterclockwise",
yading@11 123 trans->dir == 0 || trans->dir == 3);
yading@11 124 return 0;
yading@11 125 }
yading@11 126
yading@11 127 static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
yading@11 128 {
yading@11 129 TransContext *trans = inlink->dst->priv;
yading@11 130
yading@11 131 return trans->passthrough ?
yading@11 132 ff_null_get_video_buffer (inlink, w, h) :
yading@11 133 ff_default_get_video_buffer(inlink, w, h);
yading@11 134 }
yading@11 135
yading@11 136 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
yading@11 137 {
yading@11 138 TransContext *trans = inlink->dst->priv;
yading@11 139 AVFilterLink *outlink = inlink->dst->outputs[0];
yading@11 140 AVFrame *out;
yading@11 141 int plane;
yading@11 142
yading@11 143 if (trans->passthrough)
yading@11 144 return ff_filter_frame(outlink, in);
yading@11 145
yading@11 146 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
yading@11 147 if (!out) {
yading@11 148 av_frame_free(&in);
yading@11 149 return AVERROR(ENOMEM);
yading@11 150 }
yading@11 151
yading@11 152 out->pts = in->pts;
yading@11 153
yading@11 154 if (in->sample_aspect_ratio.num == 0) {
yading@11 155 out->sample_aspect_ratio = in->sample_aspect_ratio;
yading@11 156 } else {
yading@11 157 out->sample_aspect_ratio.num = in->sample_aspect_ratio.den;
yading@11 158 out->sample_aspect_ratio.den = in->sample_aspect_ratio.num;
yading@11 159 }
yading@11 160
yading@11 161 for (plane = 0; out->data[plane]; plane++) {
yading@11 162 int hsub = plane == 1 || plane == 2 ? trans->hsub : 0;
yading@11 163 int vsub = plane == 1 || plane == 2 ? trans->vsub : 0;
yading@11 164 int pixstep = trans->pixsteps[plane];
yading@11 165 int inh = in->height >> vsub;
yading@11 166 int outw = out->width >> hsub;
yading@11 167 int outh = out->height >> vsub;
yading@11 168 uint8_t *dst, *src;
yading@11 169 int dstlinesize, srclinesize;
yading@11 170 int x, y;
yading@11 171
yading@11 172 dst = out->data[plane];
yading@11 173 dstlinesize = out->linesize[plane];
yading@11 174 src = in->data[plane];
yading@11 175 srclinesize = in->linesize[plane];
yading@11 176
yading@11 177 if (trans->dir&1) {
yading@11 178 src += in->linesize[plane] * (inh-1);
yading@11 179 srclinesize *= -1;
yading@11 180 }
yading@11 181
yading@11 182 if (trans->dir&2) {
yading@11 183 dst += out->linesize[plane] * (outh-1);
yading@11 184 dstlinesize *= -1;
yading@11 185 }
yading@11 186
yading@11 187 for (y = 0; y < outh; y++) {
yading@11 188 switch (pixstep) {
yading@11 189 case 1:
yading@11 190 for (x = 0; x < outw; x++)
yading@11 191 dst[x] = src[x*srclinesize + y];
yading@11 192 break;
yading@11 193 case 2:
yading@11 194 for (x = 0; x < outw; x++)
yading@11 195 *((uint16_t *)(dst + 2*x)) = *((uint16_t *)(src + x*srclinesize + y*2));
yading@11 196 break;
yading@11 197 case 3:
yading@11 198 for (x = 0; x < outw; x++) {
yading@11 199 int32_t v = AV_RB24(src + x*srclinesize + y*3);
yading@11 200 AV_WB24(dst + 3*x, v);
yading@11 201 }
yading@11 202 break;
yading@11 203 case 4:
yading@11 204 for (x = 0; x < outw; x++)
yading@11 205 *((uint32_t *)(dst + 4*x)) = *((uint32_t *)(src + x*srclinesize + y*4));
yading@11 206 break;
yading@11 207 case 6:
yading@11 208 for (x = 0; x < outw; x++) {
yading@11 209 int64_t v = AV_RB48(src + x*srclinesize + y*6);
yading@11 210 AV_WB48(dst + 6*x, v);
yading@11 211 }
yading@11 212 break;
yading@11 213 case 8:
yading@11 214 for (x = 0; x < outw; x++)
yading@11 215 *((uint64_t *)(dst + 8*x)) = *((uint64_t *)(src + x*srclinesize + y*8));
yading@11 216 break;
yading@11 217 }
yading@11 218 dst += dstlinesize;
yading@11 219 }
yading@11 220 }
yading@11 221
yading@11 222 av_frame_free(&in);
yading@11 223 return ff_filter_frame(outlink, out);
yading@11 224 }
yading@11 225
yading@11 226 #define OFFSET(x) offsetof(TransContext, x)
yading@11 227 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
yading@11 228
yading@11 229 static const AVOption transpose_options[] = {
yading@11 230 { "dir", "Transpose direction", OFFSET(dir), AV_OPT_TYPE_INT, { .i64 = TRANSPOSE_CCLOCK_FLIP },
yading@11 231 TRANSPOSE_CCLOCK_FLIP, TRANSPOSE_CLOCK_FLIP, FLAGS, "dir" },
yading@11 232 { "cclock_flip", "counter-clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK_FLIP }, .unit = "dir" },
yading@11 233 { "clock", "clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK }, .unit = "dir" },
yading@11 234 { "cclock", "counter-clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK }, .unit = "dir" },
yading@11 235 { "clock_flip", "clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK_FLIP }, .unit = "dir" },
yading@11 236
yading@11 237 { "passthrough", "do not apply transposition if the input matches the specified geometry",
yading@11 238 OFFSET(passthrough), AV_OPT_TYPE_INT, {.i64=TRANSPOSE_PT_TYPE_NONE}, 0, INT_MAX, FLAGS, "passthrough" },
yading@11 239 { "none", "always apply transposition", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_NONE}, INT_MIN, INT_MAX, FLAGS, "passthrough" },
yading@11 240 { "portrait", "preserve portrait geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_PORTRAIT}, INT_MIN, INT_MAX, FLAGS, "passthrough" },
yading@11 241 { "landscape", "preserve landscape geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_LANDSCAPE}, INT_MIN, INT_MAX, FLAGS, "passthrough" },
yading@11 242
yading@11 243 { NULL },
yading@11 244 };
yading@11 245
yading@11 246 AVFILTER_DEFINE_CLASS(transpose);
yading@11 247
yading@11 248 static const AVFilterPad avfilter_vf_transpose_inputs[] = {
yading@11 249 {
yading@11 250 .name = "default",
yading@11 251 .type = AVMEDIA_TYPE_VIDEO,
yading@11 252 .get_video_buffer= get_video_buffer,
yading@11 253 .filter_frame = filter_frame,
yading@11 254 },
yading@11 255 { NULL }
yading@11 256 };
yading@11 257
yading@11 258 static const AVFilterPad avfilter_vf_transpose_outputs[] = {
yading@11 259 {
yading@11 260 .name = "default",
yading@11 261 .config_props = config_props_output,
yading@11 262 .type = AVMEDIA_TYPE_VIDEO,
yading@11 263 },
yading@11 264 { NULL }
yading@11 265 };
yading@11 266
yading@11 267 AVFilter avfilter_vf_transpose = {
yading@11 268 .name = "transpose",
yading@11 269 .description = NULL_IF_CONFIG_SMALL("Transpose input video."),
yading@11 270
yading@11 271 .priv_size = sizeof(TransContext),
yading@11 272 .priv_class = &transpose_class,
yading@11 273
yading@11 274 .query_formats = query_formats,
yading@11 275
yading@11 276 .inputs = avfilter_vf_transpose_inputs,
yading@11 277 .outputs = avfilter_vf_transpose_outputs,
yading@11 278 };