Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2010 Stefano Sabatini | ||
3 | * Copyright (c) 2008 Vitor Sessak | ||
4 | * | ||
5 | * This file is part of FFmpeg. | ||
6 | * | ||
7 | * FFmpeg 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 | * FFmpeg 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 FFmpeg; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
20 | */ | ||
21 | |||
22 | /** | ||
23 | * @file | ||
24 | * transposition filter | ||
25 | * Based on MPlayer libmpcodecs/vf_rotate.c. | ||
26 | */ | ||
27 | |||
28 | #include <stdio.h> | ||
29 | |||
30 | #include "libavutil/avassert.h" | ||
31 | #include "libavutil/imgutils.h" | ||
32 | #include "libavutil/internal.h" | ||
33 | #include "libavutil/intreadwrite.h" | ||
34 | #include "libavutil/opt.h" | ||
35 | #include "libavutil/pixdesc.h" | ||
36 | |||
37 | #include "avfilter.h" | ||
38 | #include "formats.h" | ||
39 | #include "internal.h" | ||
40 | #include "video.h" | ||
41 | #include "transpose.h" | ||
42 | |||
43 | typedef struct TransContext { | ||
44 | const AVClass *class; | ||
45 | int hsub, vsub; | ||
46 | int planes; | ||
47 | int pixsteps[4]; | ||
48 | |||
49 | int passthrough; ///< PassthroughType, landscape passthrough mode enabled | ||
50 | int dir; ///< TransposeDir | ||
51 | |||
52 | TransVtable vtables[4]; | ||
53 | } TransContext; | ||
54 | |||
55 | 143 | static int query_formats(AVFilterContext *ctx) | |
56 | { | ||
57 | 143 | AVFilterFormats *pix_fmts = NULL; | |
58 | const AVPixFmtDescriptor *desc; | ||
59 | int fmt, ret; | ||
60 | |||
61 |
2/2✓ Branch 1 taken 32604 times.
✓ Branch 2 taken 143 times.
|
32747 | for (fmt = 0; desc = av_pix_fmt_desc_get(fmt); fmt++) { |
62 |
2/2✓ Branch 0 taken 32461 times.
✓ Branch 1 taken 143 times.
|
32604 | if (!(desc->flags & AV_PIX_FMT_FLAG_PAL || |
63 |
2/2✓ Branch 0 taken 30459 times.
✓ Branch 1 taken 2002 times.
|
32461 | desc->flags & AV_PIX_FMT_FLAG_HWACCEL || |
64 |
2/2✓ Branch 0 taken 29744 times.
✓ Branch 1 taken 715 times.
|
30459 | desc->flags & AV_PIX_FMT_FLAG_BITSTREAM || |
65 |
3/4✓ Branch 0 taken 23166 times.
✓ Branch 1 taken 6578 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23166 times.
|
52910 | desc->log2_chroma_w != desc->log2_chroma_h) && |
66 | 23166 | (ret = ff_add_format(&pix_fmts, fmt)) < 0) | |
67 | ✗ | return ret; | |
68 | } | ||
69 | |||
70 | |||
71 | 143 | return ff_set_common_formats(ctx, pix_fmts); | |
72 | } | ||
73 | |||
74 | 473278 | static inline void transpose_block_8_c(uint8_t *src, ptrdiff_t src_linesize, | |
75 | uint8_t *dst, ptrdiff_t dst_linesize, | ||
76 | int w, int h) | ||
77 | { | ||
78 | int x, y; | ||
79 |
2/2✓ Branch 0 taken 3781824 times.
✓ Branch 1 taken 473278 times.
|
4255102 | for (y = 0; y < h; y++, dst += dst_linesize, src++) |
80 |
2/2✓ Branch 0 taken 31473792 times.
✓ Branch 1 taken 3781824 times.
|
35255616 | for (x = 0; x < w; x++) |
81 | 31473792 | dst[x] = src[x*src_linesize]; | |
82 | 473278 | } | |
83 | |||
84 | 471978 | static void transpose_8x8_8_c(uint8_t *src, ptrdiff_t src_linesize, | |
85 | uint8_t *dst, ptrdiff_t dst_linesize) | ||
86 | { | ||
87 | 471978 | transpose_block_8_c(src, src_linesize, dst, dst_linesize, 8, 8); | |
88 | 471978 | } | |
89 | |||
90 | 303336 | static inline void transpose_block_16_c(uint8_t *src, ptrdiff_t src_linesize, | |
91 | uint8_t *dst, ptrdiff_t dst_linesize, | ||
92 | int w, int h) | ||
93 | { | ||
94 | int x, y; | ||
95 |
2/2✓ Branch 0 taken 2426688 times.
✓ Branch 1 taken 303336 times.
|
2730024 | for (y = 0; y < h; y++, dst += dst_linesize, src += 2) |
96 |
2/2✓ Branch 0 taken 19413504 times.
✓ Branch 1 taken 2426688 times.
|
21840192 | for (x = 0; x < w; x++) |
97 | 19413504 | *((uint16_t *)(dst + 2*x)) = *((uint16_t *)(src + x*src_linesize)); | |
98 | 303336 | } | |
99 | |||
100 | 303336 | static void transpose_8x8_16_c(uint8_t *src, ptrdiff_t src_linesize, | |
101 | uint8_t *dst, ptrdiff_t dst_linesize) | ||
102 | { | ||
103 | 303336 | transpose_block_16_c(src, src_linesize, dst, dst_linesize, 8, 8); | |
104 | 303336 | } | |
105 | |||
106 | 3168 | static inline void transpose_block_24_c(uint8_t *src, ptrdiff_t src_linesize, | |
107 | uint8_t *dst, ptrdiff_t dst_linesize, | ||
108 | int w, int h) | ||
109 | { | ||
110 | int x, y; | ||
111 |
2/2✓ Branch 0 taken 25344 times.
✓ Branch 1 taken 3168 times.
|
28512 | for (y = 0; y < h; y++, dst += dst_linesize) { |
112 |
2/2✓ Branch 0 taken 202752 times.
✓ Branch 1 taken 25344 times.
|
228096 | for (x = 0; x < w; x++) { |
113 | 202752 | int32_t v = AV_RB24(src + x*src_linesize + y*3); | |
114 | 202752 | AV_WB24(dst + 3*x, v); | |
115 | } | ||
116 | } | ||
117 | 3168 | } | |
118 | |||
119 | 3168 | static void transpose_8x8_24_c(uint8_t *src, ptrdiff_t src_linesize, | |
120 | uint8_t *dst, ptrdiff_t dst_linesize) | ||
121 | { | ||
122 | 3168 | transpose_block_24_c(src, src_linesize, dst, dst_linesize, 8, 8); | |
123 | 3168 | } | |
124 | |||
125 | 60984 | static inline void transpose_block_32_c(uint8_t *src, ptrdiff_t src_linesize, | |
126 | uint8_t *dst, ptrdiff_t dst_linesize, | ||
127 | int w, int h) | ||
128 | { | ||
129 | int x, y; | ||
130 |
2/2✓ Branch 0 taken 487872 times.
✓ Branch 1 taken 60984 times.
|
548856 | for (y = 0; y < h; y++, dst += dst_linesize, src += 4) { |
131 |
2/2✓ Branch 0 taken 3902976 times.
✓ Branch 1 taken 487872 times.
|
4390848 | for (x = 0; x < w; x++) |
132 | 3902976 | *((uint32_t *)(dst + 4*x)) = *((uint32_t *)(src + x*src_linesize)); | |
133 | } | ||
134 | 60984 | } | |
135 | |||
136 | 60984 | static void transpose_8x8_32_c(uint8_t *src, ptrdiff_t src_linesize, | |
137 | uint8_t *dst, ptrdiff_t dst_linesize) | ||
138 | { | ||
139 | 60984 | transpose_block_32_c(src, src_linesize, dst, dst_linesize, 8, 8); | |
140 | 60984 | } | |
141 | |||
142 | 9504 | static inline void transpose_block_48_c(uint8_t *src, ptrdiff_t src_linesize, | |
143 | uint8_t *dst, ptrdiff_t dst_linesize, | ||
144 | int w, int h) | ||
145 | { | ||
146 | int x, y; | ||
147 |
2/2✓ Branch 0 taken 76032 times.
✓ Branch 1 taken 9504 times.
|
85536 | for (y = 0; y < h; y++, dst += dst_linesize, src += 6) { |
148 |
2/2✓ Branch 0 taken 608256 times.
✓ Branch 1 taken 76032 times.
|
684288 | for (x = 0; x < w; x++) { |
149 | 608256 | int64_t v = AV_RB48(src + x*src_linesize); | |
150 | 608256 | AV_WB48(dst + 6*x, v); | |
151 | } | ||
152 | } | ||
153 | 9504 | } | |
154 | |||
155 | 9504 | static void transpose_8x8_48_c(uint8_t *src, ptrdiff_t src_linesize, | |
156 | uint8_t *dst, ptrdiff_t dst_linesize) | ||
157 | { | ||
158 | 9504 | transpose_block_48_c(src, src_linesize, dst, dst_linesize, 8, 8); | |
159 | 9504 | } | |
160 | |||
161 | 9504 | static inline void transpose_block_64_c(uint8_t *src, ptrdiff_t src_linesize, | |
162 | uint8_t *dst, ptrdiff_t dst_linesize, | ||
163 | int w, int h) | ||
164 | { | ||
165 | int x, y; | ||
166 |
2/2✓ Branch 0 taken 76032 times.
✓ Branch 1 taken 9504 times.
|
85536 | for (y = 0; y < h; y++, dst += dst_linesize, src += 8) |
167 |
2/2✓ Branch 0 taken 608256 times.
✓ Branch 1 taken 76032 times.
|
684288 | for (x = 0; x < w; x++) |
168 | 608256 | *((uint64_t *)(dst + 8*x)) = *((uint64_t *)(src + x*src_linesize)); | |
169 | 9504 | } | |
170 | |||
171 | 9504 | static void transpose_8x8_64_c(uint8_t *src, ptrdiff_t src_linesize, | |
172 | uint8_t *dst, ptrdiff_t dst_linesize) | ||
173 | { | ||
174 | 9504 | transpose_block_64_c(src, src_linesize, dst, dst_linesize, 8, 8); | |
175 | 9504 | } | |
176 | |||
177 | 142 | static int config_props_output(AVFilterLink *outlink) | |
178 | { | ||
179 | 142 | AVFilterContext *ctx = outlink->src; | |
180 | 142 | TransContext *s = ctx->priv; | |
181 | 142 | AVFilterLink *inlink = ctx->inputs[0]; | |
182 | 142 | const AVPixFmtDescriptor *desc_out = av_pix_fmt_desc_get(outlink->format); | |
183 | 142 | const AVPixFmtDescriptor *desc_in = av_pix_fmt_desc_get(inlink->format); | |
184 | |||
185 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
|
142 | if (s->dir&4) { |
186 | ✗ | av_log(ctx, AV_LOG_WARNING, | |
187 | "dir values greater than 3 are deprecated, use the passthrough option instead\n"); | ||
188 | ✗ | s->dir &= 3; | |
189 | ✗ | s->passthrough = TRANSPOSE_PT_TYPE_LANDSCAPE; | |
190 | } | ||
191 | |||
192 |
2/4✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 142 times.
✗ Branch 3 not taken.
|
142 | if ((inlink->w >= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) || |
193 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
142 | (inlink->w <= inlink->h && s->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) { |
194 | ✗ | av_log(ctx, AV_LOG_VERBOSE, | |
195 | "w:%d h:%d -> w:%d h:%d (passthrough mode)\n", | ||
196 | inlink->w, inlink->h, inlink->w, inlink->h); | ||
197 | ✗ | return 0; | |
198 | } else { | ||
199 | 142 | s->passthrough = TRANSPOSE_PT_TYPE_NONE; | |
200 | } | ||
201 | |||
202 | 142 | s->hsub = desc_in->log2_chroma_w; | |
203 | 142 | s->vsub = desc_in->log2_chroma_h; | |
204 | 142 | s->planes = av_pix_fmt_count_planes(outlink->format); | |
205 | |||
206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
|
142 | av_assert0(desc_in->nb_components == desc_out->nb_components); |
207 | |||
208 | |||
209 | 142 | av_image_fill_max_pixsteps(s->pixsteps, NULL, desc_out); | |
210 | |||
211 | 142 | outlink->w = inlink->h; | |
212 | 142 | outlink->h = inlink->w; | |
213 | |||
214 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
|
142 | if (inlink->sample_aspect_ratio.num) |
215 | ✗ | outlink->sample_aspect_ratio = av_div_q((AVRational) { 1, 1 }, | |
216 | inlink->sample_aspect_ratio); | ||
217 | else | ||
218 | 142 | outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; | |
219 | |||
220 |
2/2✓ Branch 0 taken 568 times.
✓ Branch 1 taken 142 times.
|
710 | for (int i = 0; i < 4; i++) { |
221 | 568 | TransVtable *v = &s->vtables[i]; | |
222 |
7/7✓ Branch 0 taken 45 times.
✓ Branch 1 taken 217 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 43 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 249 times.
|
568 | switch (s->pixsteps[i]) { |
223 | 45 | case 1: v->transpose_block = transpose_block_8_c; | |
224 | 45 | v->transpose_8x8 = transpose_8x8_8_c; break; | |
225 | 217 | case 2: v->transpose_block = transpose_block_16_c; | |
226 | 217 | v->transpose_8x8 = transpose_8x8_16_c; break; | |
227 | 2 | case 3: v->transpose_block = transpose_block_24_c; | |
228 | 2 | v->transpose_8x8 = transpose_8x8_24_c; break; | |
229 | 43 | case 4: v->transpose_block = transpose_block_32_c; | |
230 | 43 | v->transpose_8x8 = transpose_8x8_32_c; break; | |
231 | 6 | case 6: v->transpose_block = transpose_block_48_c; | |
232 | 6 | v->transpose_8x8 = transpose_8x8_48_c; break; | |
233 | 6 | case 8: v->transpose_block = transpose_block_64_c; | |
234 | 6 | v->transpose_8x8 = transpose_8x8_64_c; break; | |
235 | } | ||
236 | } | ||
237 | |||
238 | #if ARCH_X86 | ||
239 |
2/2✓ Branch 0 taken 568 times.
✓ Branch 1 taken 142 times.
|
710 | for (int i = 0; i < 4; i++) { |
240 | 568 | TransVtable *v = &s->vtables[i]; | |
241 | |||
242 | 568 | ff_transpose_init_x86(v, s->pixsteps[i]); | |
243 | } | ||
244 | #endif | ||
245 | |||
246 | 284 | av_log(ctx, AV_LOG_VERBOSE, | |
247 | "w:%d h:%d dir:%d -> w:%d h:%d rotation:%s vflip:%d\n", | ||
248 | inlink->w, inlink->h, s->dir, outlink->w, outlink->h, | ||
249 |
3/4✓ Branch 0 taken 141 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 141 times.
|
142 | s->dir == 1 || s->dir == 3 ? "clockwise" : "counterclockwise", |
250 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
142 | s->dir == 0 || s->dir == 3); |
251 | 142 | return 0; | |
252 | } | ||
253 | |||
254 | 139 | static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h) | |
255 | { | ||
256 | 139 | TransContext *s = inlink->dst->priv; | |
257 | |||
258 | 139 | return s->passthrough ? | |
259 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
|
278 | ff_null_get_video_buffer (inlink, w, h) : |
260 | 139 | ff_default_get_video_buffer(inlink, w, h); | |
261 | } | ||
262 | |||
263 | typedef struct ThreadData { | ||
264 | AVFrame *in, *out; | ||
265 | } ThreadData; | ||
266 | |||
267 | 695 | static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, | |
268 | int nb_jobs) | ||
269 | { | ||
270 | 695 | TransContext *s = ctx->priv; | |
271 | 695 | ThreadData *td = arg; | |
272 | 695 | AVFrame *out = td->out; | |
273 | 695 | AVFrame *in = td->in; | |
274 | int plane; | ||
275 | |||
276 |
2/2✓ Branch 0 taken 1978 times.
✓ Branch 1 taken 695 times.
|
2673 | for (plane = 0; plane < s->planes; plane++) { |
277 |
4/4✓ Branch 0 taken 1342 times.
✓ Branch 1 taken 636 times.
✓ Branch 2 taken 620 times.
✓ Branch 3 taken 722 times.
|
1978 | int hsub = plane == 1 || plane == 2 ? s->hsub : 0; |
278 |
4/4✓ Branch 0 taken 1342 times.
✓ Branch 1 taken 636 times.
✓ Branch 2 taken 620 times.
✓ Branch 3 taken 722 times.
|
1978 | int vsub = plane == 1 || plane == 2 ? s->vsub : 0; |
279 | 1978 | int pixstep = s->pixsteps[plane]; | |
280 | 1978 | int inh = AV_CEIL_RSHIFT(in->height, vsub); | |
281 | 1978 | int outw = AV_CEIL_RSHIFT(out->width, hsub); | |
282 | 1978 | int outh = AV_CEIL_RSHIFT(out->height, vsub); | |
283 | 1978 | int start = (outh * jobnr ) / nb_jobs; | |
284 | 1978 | int end = (outh * (jobnr+1)) / nb_jobs; | |
285 | uint8_t *dst, *src; | ||
286 | int dstlinesize, srclinesize; | ||
287 | int x, y; | ||
288 | 1978 | TransVtable *v = &s->vtables[plane]; | |
289 | |||
290 | 1978 | dstlinesize = out->linesize[plane]; | |
291 | 1978 | dst = out->data[plane] + start * dstlinesize; | |
292 | 1978 | src = in->data[plane]; | |
293 | 1978 | srclinesize = in->linesize[plane]; | |
294 | |||
295 |
2/2✓ Branch 0 taken 315 times.
✓ Branch 1 taken 1663 times.
|
1978 | if (s->dir & 1) { |
296 | 315 | src += in->linesize[plane] * (inh - 1); | |
297 | 315 | srclinesize *= -1; | |
298 | } | ||
299 | |||
300 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1978 times.
|
1978 | if (s->dir & 2) { |
301 | ✗ | dst = out->data[plane] + dstlinesize * (outh - start - 1); | |
302 | ✗ | dstlinesize *= -1; | |
303 | } | ||
304 | |||
305 |
2/2✓ Branch 0 taken 28944 times.
✓ Branch 1 taken 1978 times.
|
30922 | for (y = start; y < end - 7; y += 8) { |
306 |
2/2✓ Branch 0 taken 858474 times.
✓ Branch 1 taken 28944 times.
|
887418 | for (x = 0; x < outw - 7; x += 8) { |
307 | 858474 | v->transpose_8x8(src + x * srclinesize + y * pixstep, | |
308 | srclinesize, | ||
309 | 858474 | dst + (y - start) * dstlinesize + x * pixstep, | |
310 | dstlinesize); | ||
311 | } | ||
312 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 28944 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
28944 | if (outw - x > 0 && end - y > 0) |
313 | ✗ | v->transpose_block(src + x * srclinesize + y * pixstep, | |
314 | srclinesize, | ||
315 | ✗ | dst + (y - start) * dstlinesize + x * pixstep, | |
316 | dstlinesize, outw - x, end - y); | ||
317 | } | ||
318 | |||
319 |
2/2✓ Branch 0 taken 1300 times.
✓ Branch 1 taken 678 times.
|
1978 | if (end - y > 0) |
320 | 1300 | v->transpose_block(src + 0 * srclinesize + y * pixstep, | |
321 | srclinesize, | ||
322 | 1300 | dst + (y - start) * dstlinesize + 0 * pixstep, | |
323 | dstlinesize, outw, end - y); | ||
324 | } | ||
325 | |||
326 | 695 | return 0; | |
327 | } | ||
328 | |||
329 | 295 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |
330 | { | ||
331 | 295 | int err = 0; | |
332 | 295 | AVFilterContext *ctx = inlink->dst; | |
333 | 295 | TransContext *s = ctx->priv; | |
334 | 295 | AVFilterLink *outlink = ctx->outputs[0]; | |
335 | ThreadData td; | ||
336 | AVFrame *out; | ||
337 | |||
338 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 295 times.
|
295 | if (s->passthrough) |
339 | ✗ | return ff_filter_frame(outlink, in); | |
340 | |||
341 | 295 | out = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |
342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 295 times.
|
295 | if (!out) { |
343 | ✗ | err = AVERROR(ENOMEM); | |
344 | ✗ | goto fail; | |
345 | } | ||
346 | |||
347 | 295 | err = av_frame_copy_props(out, in); | |
348 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 295 times.
|
295 | if (err < 0) |
349 | ✗ | goto fail; | |
350 | |||
351 |
1/2✓ Branch 0 taken 295 times.
✗ Branch 1 not taken.
|
295 | if (in->sample_aspect_ratio.num == 0) { |
352 | 295 | out->sample_aspect_ratio = in->sample_aspect_ratio; | |
353 | } else { | ||
354 | ✗ | out->sample_aspect_ratio.num = in->sample_aspect_ratio.den; | |
355 | ✗ | out->sample_aspect_ratio.den = in->sample_aspect_ratio.num; | |
356 | } | ||
357 | |||
358 | 295 | td.in = in, td.out = out; | |
359 | 295 | ff_filter_execute(ctx, filter_slice, &td, NULL, | |
360 |
1/2✓ Branch 0 taken 295 times.
✗ Branch 1 not taken.
|
295 | FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); |
361 | 295 | av_frame_free(&in); | |
362 | 295 | return ff_filter_frame(outlink, out); | |
363 | |||
364 | ✗ | fail: | |
365 | ✗ | av_frame_free(&in); | |
366 | ✗ | av_frame_free(&out); | |
367 | ✗ | return err; | |
368 | } | ||
369 | |||
370 | #define OFFSET(x) offsetof(TransContext, x) | ||
371 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM | ||
372 | |||
373 | static const AVOption transpose_options[] = { | ||
374 | { "dir", "set transpose direction", OFFSET(dir), AV_OPT_TYPE_INT, { .i64 = TRANSPOSE_CCLOCK_FLIP }, 0, 7, FLAGS, .unit = "dir" }, | ||
375 | { "cclock_flip", "rotate counter-clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK_FLIP }, .flags=FLAGS, .unit = "dir" }, | ||
376 | { "clock", "rotate clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK }, .flags=FLAGS, .unit = "dir" }, | ||
377 | { "cclock", "rotate counter-clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK }, .flags=FLAGS, .unit = "dir" }, | ||
378 | { "clock_flip", "rotate clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK_FLIP }, .flags=FLAGS, .unit = "dir" }, | ||
379 | |||
380 | { "passthrough", "do not apply transposition if the input matches the specified geometry", | ||
381 | OFFSET(passthrough), AV_OPT_TYPE_INT, {.i64=TRANSPOSE_PT_TYPE_NONE}, 0, INT_MAX, FLAGS, .unit = "passthrough" }, | ||
382 | { "none", "always apply transposition", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_NONE}, INT_MIN, INT_MAX, FLAGS, .unit = "passthrough" }, | ||
383 | { "portrait", "preserve portrait geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_PORTRAIT}, INT_MIN, INT_MAX, FLAGS, .unit = "passthrough" }, | ||
384 | { "landscape", "preserve landscape geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_LANDSCAPE}, INT_MIN, INT_MAX, FLAGS, .unit = "passthrough" }, | ||
385 | |||
386 | { NULL } | ||
387 | }; | ||
388 | |||
389 | AVFILTER_DEFINE_CLASS(transpose); | ||
390 | |||
391 | static const AVFilterPad avfilter_vf_transpose_inputs[] = { | ||
392 | { | ||
393 | .name = "default", | ||
394 | .type = AVMEDIA_TYPE_VIDEO, | ||
395 | .get_buffer.video = get_video_buffer, | ||
396 | .filter_frame = filter_frame, | ||
397 | }, | ||
398 | }; | ||
399 | |||
400 | static const AVFilterPad avfilter_vf_transpose_outputs[] = { | ||
401 | { | ||
402 | .name = "default", | ||
403 | .config_props = config_props_output, | ||
404 | .type = AVMEDIA_TYPE_VIDEO, | ||
405 | }, | ||
406 | }; | ||
407 | |||
408 | const AVFilter ff_vf_transpose = { | ||
409 | .name = "transpose", | ||
410 | .description = NULL_IF_CONFIG_SMALL("Transpose input video."), | ||
411 | .priv_size = sizeof(TransContext), | ||
412 | .priv_class = &transpose_class, | ||
413 | FILTER_INPUTS(avfilter_vf_transpose_inputs), | ||
414 | FILTER_OUTPUTS(avfilter_vf_transpose_outputs), | ||
415 | FILTER_QUERY_FUNC(query_formats), | ||
416 | .flags = AVFILTER_FLAG_SLICE_THREADS, | ||
417 | }; | ||
418 |