vf_transpose.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010 Stefano Sabatini
3  * Copyright (c) 2008 Vitor Sessak
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
28 #include <stdio.h>
29 
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/pixdesc.h"
32 #include "libavutil/imgutils.h"
33 #include "libavutil/internal.h"
34 #include "avfilter.h"
35 #include "formats.h"
36 #include "internal.h"
37 #include "video.h"
38 
39 typedef struct {
40  int hsub, vsub;
41  int pixsteps[4];
42 
43  /* 0 Rotate by 90 degrees counterclockwise and vflip. */
44  /* 1 Rotate by 90 degrees clockwise. */
45  /* 2 Rotate by 90 degrees counterclockwise. */
46  /* 3 Rotate by 90 degrees clockwise and vflip. */
47  int dir;
48 } TransContext;
49 
50 static av_cold int init(AVFilterContext *ctx, const char *args)
51 {
52  TransContext *trans = ctx->priv;
53  trans->dir = 0;
54 
55  if (args)
56  sscanf(args, "%d", &trans->dir);
57 
58  if (trans->dir < 0 || trans->dir > 3) {
59  av_log(ctx, AV_LOG_ERROR, "Invalid value %d not between 0 and 3.\n",
60  trans->dir);
61  return AVERROR(EINVAL);
62  }
63  return 0;
64 }
65 
67 {
68  enum AVPixelFormat pix_fmts[] = {
90  };
91 
93  return 0;
94 }
95 
96 static int config_props_output(AVFilterLink *outlink)
97 {
98  AVFilterContext *ctx = outlink->src;
99  TransContext *trans = ctx->priv;
100  AVFilterLink *inlink = ctx->inputs[0];
101  const AVPixFmtDescriptor *desc_out = av_pix_fmt_desc_get(outlink->format);
102  const AVPixFmtDescriptor *desc_in = av_pix_fmt_desc_get(inlink->format);
103 
104  trans->hsub = desc_in->log2_chroma_w;
105  trans->vsub = desc_in->log2_chroma_h;
106 
107  av_image_fill_max_pixsteps(trans->pixsteps, NULL, desc_out);
108 
109  outlink->w = inlink->h;
110  outlink->h = inlink->w;
111 
112  if (inlink->sample_aspect_ratio.num){
113  outlink->sample_aspect_ratio = av_div_q((AVRational){1,1}, inlink->sample_aspect_ratio);
114  } else
115  outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
116 
117  av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d dir:%d -> w:%d h:%d rotation:%s vflip:%d\n",
118  inlink->w, inlink->h, trans->dir, outlink->w, outlink->h,
119  trans->dir == 1 || trans->dir == 3 ? "clockwise" : "counterclockwise",
120  trans->dir == 0 || trans->dir == 3);
121  return 0;
122 }
123 
125 {
126  AVFilterLink *outlink = inlink->dst->outputs[0];
127  TransContext *trans = inlink->dst->priv;
128  AVFilterBufferRef *out;
129  int plane;
130 
131  out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
132  if (!out) {
134  return AVERROR(ENOMEM);
135  }
136 
137  out->pts = in->pts;
138 
139  if (in->video->pixel_aspect.num == 0) {
140  out->video->pixel_aspect = in->video->pixel_aspect;
141  } else {
144  }
145 
146  for (plane = 0; out->data[plane]; plane++) {
147  int hsub = plane == 1 || plane == 2 ? trans->hsub : 0;
148  int vsub = plane == 1 || plane == 2 ? trans->vsub : 0;
149  int pixstep = trans->pixsteps[plane];
150  int inh = in->video->h>>vsub;
151  int outw = out->video->w>>hsub;
152  int outh = out->video->h>>vsub;
153  uint8_t *dst, *src;
154  int dstlinesize, srclinesize;
155  int x, y;
156 
157  dst = out->data[plane];
158  dstlinesize = out->linesize[plane];
159  src = in->data[plane];
160  srclinesize = in->linesize[plane];
161 
162  if (trans->dir&1) {
163  src += in->linesize[plane] * (inh-1);
164  srclinesize *= -1;
165  }
166 
167  if (trans->dir&2) {
168  dst += out->linesize[plane] * (outh-1);
169  dstlinesize *= -1;
170  }
171 
172  for (y = 0; y < outh; y++) {
173  switch (pixstep) {
174  case 1:
175  for (x = 0; x < outw; x++)
176  dst[x] = src[x*srclinesize + y];
177  break;
178  case 2:
179  for (x = 0; x < outw; x++)
180  *((uint16_t *)(dst + 2*x)) = *((uint16_t *)(src + x*srclinesize + y*2));
181  break;
182  case 3:
183  for (x = 0; x < outw; x++) {
184  int32_t v = AV_RB24(src + x*srclinesize + y*3);
185  AV_WB24(dst + 3*x, v);
186  }
187  break;
188  case 4:
189  for (x = 0; x < outw; x++)
190  *((uint32_t *)(dst + 4*x)) = *((uint32_t *)(src + x*srclinesize + y*4));
191  break;
192  }
193  dst += dstlinesize;
194  }
195  }
196 
198  return ff_filter_frame(outlink, out);
199 }
200 
202  {
203  .name = "default",
204  .type = AVMEDIA_TYPE_VIDEO,
205  .filter_frame = filter_frame,
206  .min_perms = AV_PERM_READ,
207  },
208  { NULL }
209 };
210 
212  {
213  .name = "default",
214  .config_props = config_props_output,
215  .type = AVMEDIA_TYPE_VIDEO,
216  },
217  { NULL }
218 };
219 
221  .name = "transpose",
222  .description = NULL_IF_CONFIG_SMALL("Transpose input video."),
223 
224  .init = init,
225  .priv_size = sizeof(TransContext),
226 
228 
229  .inputs = avfilter_vf_transpose_inputs,
230  .outputs = avfilter_vf_transpose_outputs,
231 };