Browse code

Add transpose filter.

Originally committed as revision 25525 to svn://svn.ffmpeg.org/ffmpeg/trunk

Stefano Sabatini authored on 2010/10/19 06:29:37
Showing 6 changed files
... ...
@@ -47,6 +47,7 @@ version <next>:
47 47
 - SAP (Session Announcement Protocol, RFC 2974) muxer and demuxer
48 48
 - cropdetect filter
49 49
 - ffmpeg -crop* options removed
50
+- transpose filter added
50 51
 
51 52
 
52 53
 version 0.6:
... ...
@@ -508,6 +508,47 @@ not specified it will use the default value of 16.
508 508
 Adding this in the beginning of filter chains should make filtering
509 509
 faster due to better use of the memory cache.
510 510
 
511
+@section transpose
512
+
513
+Transpose rows with columns in the input video and optionally flip it.
514
+
515
+It accepts a parameter representing an integer, which can assume the
516
+values:
517
+
518
+@table @samp
519
+@item 0
520
+Rotate by 90 degrees counterclockwise and vertically flip (default), that is:
521
+@example
522
+L.R     L.l
523
+. . ->  . .
524
+l.r     R.r
525
+@end example
526
+
527
+@item 1
528
+Rotate by 90 degrees clockwise, that is:
529
+@example
530
+L.R     l.L
531
+. . ->  . .
532
+l.r     r.R
533
+@end example
534
+
535
+@item 2
536
+Rotate by 90 degrees counterclockwise, that is:
537
+@example
538
+L.R     R.r
539
+. . ->  . .
540
+l.r     L.l
541
+@end example
542
+
543
+@item 3
544
+Rotate by 90 degrees clockwise and vertically flip, that is:
545
+@example
546
+L.R     r.R
547
+. . ->  . .
548
+l.r     l.L
549
+@end example
550
+@end table
551
+
511 552
 @section unsharp
512 553
 
513 554
 Sharpen or blur the input video.
... ...
@@ -38,6 +38,7 @@ OBJS-$(CONFIG_PIXELASPECT_FILTER)            += vf_aspect.o
38 38
 OBJS-$(CONFIG_SCALE_FILTER)                  += vf_scale.o
39 39
 OBJS-$(CONFIG_SETTB_FILTER)                  += vf_settb.o
40 40
 OBJS-$(CONFIG_SLICIFY_FILTER)                += vf_slicify.o
41
+OBJS-$(CONFIG_TRANSPOSE_FILTER)              += vf_transpose.o
41 42
 OBJS-$(CONFIG_UNSHARP_FILTER)                += vf_unsharp.o
42 43
 OBJS-$(CONFIG_VFLIP_FILTER)                  += vf_vflip.o
43 44
 OBJS-$(CONFIG_YADIF_FILTER)                  += vf_yadif.o
... ...
@@ -58,6 +58,7 @@ void avfilter_register_all(void)
58 58
     REGISTER_FILTER (SCALE,       scale,       vf);
59 59
     REGISTER_FILTER (SETTB,       settb,       vf);
60 60
     REGISTER_FILTER (SLICIFY,     slicify,     vf);
61
+    REGISTER_FILTER (TRANSPOSE,   transpose,   vf);
61 62
     REGISTER_FILTER (UNSHARP,     unsharp,     vf);
62 63
     REGISTER_FILTER (VFLIP,       vflip,       vf);
63 64
     REGISTER_FILTER (YADIF,       yadif,       vf);
... ...
@@ -25,7 +25,7 @@
25 25
 #include "libavutil/avutil.h"
26 26
 
27 27
 #define LIBAVFILTER_VERSION_MAJOR  1
28
-#define LIBAVFILTER_VERSION_MINOR 52
28
+#define LIBAVFILTER_VERSION_MINOR 53
29 29
 #define LIBAVFILTER_VERSION_MICRO  0
30 30
 
31 31
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
32 32
new file mode 100644
... ...
@@ -0,0 +1,212 @@
0
+/*
1
+ * Copyright (C) 2010 Stefano Sabatini
2
+ * Copyright (C) 2008 Vitor Sessak
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+/**
22
+ * @file
23
+ * transposition filter
24
+ * Based on MPlayer libmpcodecs/vf_rotate.c.
25
+ */
26
+
27
+#include "libavutil/intreadwrite.h"
28
+#include "libavutil/pixdesc.h"
29
+#include "libavcore/imgutils.h"
30
+#include "avfilter.h"
31
+
32
+typedef struct {
33
+    int hsub, vsub;
34
+    int pixsteps[4];
35
+
36
+    /* 0    Rotate by 90 degrees counterclockwise and vflip. */
37
+    /* 1    Rotate by 90 degrees clockwise.                  */
38
+    /* 2    Rotate by 90 degrees counterclockwise.           */
39
+    /* 3    Rotate by 90 degrees clockwise and vflip.        */
40
+    int dir;
41
+} TransContext;
42
+
43
+static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
44
+{
45
+    TransContext *trans = ctx->priv;
46
+    trans->dir = 0;
47
+
48
+    if (args)
49
+        sscanf(args, "%d", &trans->dir);
50
+
51
+    if (trans->dir < 0 || trans->dir > 3) {
52
+        av_log(ctx, AV_LOG_ERROR, "Invalid value %d not between 0 and 3.\n",
53
+               trans->dir);
54
+        return AVERROR(EINVAL);
55
+    }
56
+    return 0;
57
+}
58
+
59
+static int query_formats(AVFilterContext *ctx)
60
+{
61
+    enum PixelFormat pix_fmts[] = {
62
+        PIX_FMT_ARGB,         PIX_FMT_RGBA,
63
+        PIX_FMT_ABGR,         PIX_FMT_BGRA,
64
+        PIX_FMT_RGB24,        PIX_FMT_BGR24,
65
+        PIX_FMT_RGB565BE,     PIX_FMT_RGB565LE,
66
+        PIX_FMT_RGB555BE,     PIX_FMT_RGB555LE,
67
+        PIX_FMT_BGR565BE,     PIX_FMT_BGR565LE,
68
+        PIX_FMT_BGR555BE,     PIX_FMT_BGR555LE,
69
+        PIX_FMT_GRAY16BE,     PIX_FMT_GRAY16LE,
70
+        PIX_FMT_YUV420P16LE,  PIX_FMT_YUV420P16BE,
71
+        PIX_FMT_YUV422P16LE,  PIX_FMT_YUV422P16BE,
72
+        PIX_FMT_YUV444P16LE,  PIX_FMT_YUV444P16BE,
73
+        PIX_FMT_NV12,         PIX_FMT_NV21,
74
+        PIX_FMT_RGB8,         PIX_FMT_BGR8,
75
+        PIX_FMT_RGB4_BYTE,    PIX_FMT_BGR4_BYTE,
76
+        PIX_FMT_YUV444P,      PIX_FMT_YUV422P,
77
+        PIX_FMT_YUV420P,      PIX_FMT_YUVJ420P,
78
+        PIX_FMT_YUV411P,      PIX_FMT_YUV410P,
79
+        PIX_FMT_YUVJ444P,     PIX_FMT_YUVJ422P,
80
+        PIX_FMT_YUV440P,      PIX_FMT_YUVJ440P,
81
+        PIX_FMT_YUVA420P,     PIX_FMT_GRAY8,
82
+        PIX_FMT_NONE
83
+    };
84
+
85
+    avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
86
+    return 0;
87
+}
88
+
89
+static int config_props_output(AVFilterLink *outlink)
90
+{
91
+    AVFilterContext *ctx = outlink->src;
92
+    TransContext *trans = ctx->priv;
93
+    AVFilterLink *inlink = ctx->inputs[0];
94
+    const AVPixFmtDescriptor *pixdesc = &av_pix_fmt_descriptors[outlink->format];
95
+
96
+    trans->hsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_w;
97
+    trans->vsub = av_pix_fmt_descriptors[inlink->format].log2_chroma_h;
98
+
99
+    av_image_fill_max_pixsteps(trans->pixsteps, NULL, pixdesc);
100
+
101
+    outlink->w = inlink->h;
102
+    outlink->h = inlink->w;
103
+
104
+    av_log(ctx, AV_LOG_INFO, "w:%d h:%d dir:%d -> w:%d h:%d rotation:%s vflip:%d\n",
105
+           inlink->w, inlink->h, trans->dir, outlink->w, outlink->h,
106
+           trans->dir == 1 || trans->dir == 3 ? "clockwise" : "counterclockwise",
107
+           trans->dir == 0 || trans->dir == 3);
108
+    return 0;
109
+}
110
+
111
+static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
112
+{
113
+    AVFilterLink *outlink = inlink->dst->outputs[0];
114
+
115
+    outlink->out_buf = avfilter_get_video_buffer(outlink, AV_PERM_WRITE,
116
+                                                 outlink->w, outlink->h);
117
+    outlink->out_buf->pts = picref->pts;
118
+
119
+    if (picref->video->pixel_aspect.num == 0) {
120
+        outlink->out_buf->video->pixel_aspect = picref->video->pixel_aspect;
121
+    } else {
122
+        outlink->out_buf->video->pixel_aspect.num = picref->video->pixel_aspect.den;
123
+        outlink->out_buf->video->pixel_aspect.den = picref->video->pixel_aspect.num;
124
+    }
125
+
126
+    avfilter_start_frame(outlink, avfilter_ref_buffer(outlink->out_buf, ~0));
127
+}
128
+
129
+static void end_frame(AVFilterLink *inlink)
130
+{
131
+    TransContext *trans = inlink->dst->priv;
132
+    AVFilterBufferRef *inpic  = inlink->cur_buf;
133
+    AVFilterBufferRef *outpic = inlink->dst->outputs[0]->out_buf;
134
+    AVFilterLink *outlink = inlink->dst->outputs[0];
135
+    int plane;
136
+
137
+    for (plane = 0; outpic->data[plane]; plane++) {
138
+        int hsub = plane == 1 || plane == 2 ? trans->hsub : 0;
139
+        int vsub = plane == 1 || plane == 2 ? trans->vsub : 0;
140
+        int pixstep = trans->pixsteps[plane];
141
+        int inh  = inpic->video->h>>vsub;
142
+        int outw = outpic->video->w>>hsub;
143
+        int outh = outpic->video->h>>vsub;
144
+        uint8_t *out, *in;
145
+        int outlinesize, inlinesize;
146
+        int x, y;
147
+
148
+        out = outpic->data[plane]; outlinesize = outpic->linesize[plane];
149
+        in  = inpic ->data[plane]; inlinesize  = inpic ->linesize[plane];
150
+
151
+        if (trans->dir&1) {
152
+            in +=  inpic->linesize[plane] * (inh-1);
153
+            inlinesize *= -1;
154
+        }
155
+
156
+        if (trans->dir&2) {
157
+            out += outpic->linesize[plane] * (outh-1);
158
+            outlinesize *= -1;
159
+        }
160
+
161
+        for (y = 0; y < outh; y++) {
162
+            switch (pixstep) {
163
+            case 1:
164
+                for (x = 0; x < outw; x++)
165
+                    out[x] = in[x*inlinesize + y];
166
+                break;
167
+            case 2:
168
+                for (x = 0; x < outw; x++)
169
+                    *((uint16_t *)(out + 2*x)) = *((uint16_t *)(in + x*inlinesize + y*2));
170
+                break;
171
+            case 3:
172
+                for (x = 0; x < outw; x++) {
173
+                    int32_t v = AV_RB24(in + x*inlinesize + y*3);
174
+                    AV_WB24(out + 3*x, v);
175
+                }
176
+                break;
177
+            case 4:
178
+                for (x = 0; x < outw; x++)
179
+                    *((uint32_t *)(out + 4*x)) = *((uint32_t *)(in + x*inlinesize + y*4));
180
+                break;
181
+            }
182
+            out += outlinesize;
183
+        }
184
+    }
185
+
186
+    avfilter_unref_buffer(inpic);
187
+    avfilter_draw_slice(outlink, 0, outpic->video->h, 1);
188
+    avfilter_end_frame(outlink);
189
+    avfilter_unref_buffer(outpic);
190
+}
191
+
192
+AVFilter avfilter_vf_transpose = {
193
+    .name      = "transpose",
194
+    .description = NULL_IF_CONFIG_SMALL("Transpose input video."),
195
+
196
+    .init = init,
197
+    .priv_size = sizeof(TransContext),
198
+
199
+    .query_formats = query_formats,
200
+
201
+    .inputs    = (AVFilterPad[]) {{ .name            = "default",
202
+                                    .type            = AVMEDIA_TYPE_VIDEO,
203
+                                    .start_frame     = start_frame,
204
+                                    .end_frame       = end_frame,
205
+                                    .min_perms       = AV_PERM_READ, },
206
+                                  { .name = NULL}},
207
+    .outputs   = (AVFilterPad[]) {{ .name            = "default",
208
+                                    .config_props    = config_props_output,
209
+                                    .type            = AVMEDIA_TYPE_VIDEO, },
210
+                                  { .name = NULL}},
211
+};