Browse code

lavfi: add shuffleplanes filter

Anton Khirnov authored on 2014/02/23 23:38:13
Showing 6 changed files
... ...
@@ -3,6 +3,7 @@ releases are sorted from youngest to oldest.
3 3
 
4 4
 version <next>:
5 5
 - compand audio filter
6
+- shuffleplanes filter
6 7
 
7 8
 
8 9
 version 10:
... ...
@@ -2453,6 +2453,36 @@ Adler-32 checksum of each plane of the input frame, expressed in the form
2453 2453
 "[@var{c0} @var{c1} @var{c2} @var{c3}]"
2454 2454
 @end table
2455 2455
 
2456
+@section shuffleplanes
2457
+
2458
+Reorder and/or duplicate video planes.
2459
+
2460
+This filter accepts the following options:
2461
+
2462
+@table @option
2463
+
2464
+@item map0
2465
+The index of the input plane to be used as the first output plane.
2466
+
2467
+@item map1
2468
+The index of the input plane to be used as the second output plane.
2469
+
2470
+@item map2
2471
+The index of the input plane to be used as the third output plane.
2472
+
2473
+@item map3
2474
+The index of the input plane to be used as the fourth output plane.
2475
+
2476
+@end table
2477
+
2478
+The first plane has the index 0. The default is to keep the input unchanged.
2479
+
2480
+E.g.
2481
+@example
2482
+avconv -i INPUT -vf shuffleplanes=0:2:1:3 OUTPUT
2483
+@end example
2484
+swaps the second and third planes of the input.
2485
+
2456 2486
 @section split
2457 2487
 
2458 2488
 Split input video into several identical outputs.
... ...
@@ -78,6 +78,7 @@ OBJS-$(CONFIG_SETPTS_FILTER)                 += setpts.o
78 78
 OBJS-$(CONFIG_SETSAR_FILTER)                 += vf_aspect.o
79 79
 OBJS-$(CONFIG_SETTB_FILTER)                  += vf_settb.o
80 80
 OBJS-$(CONFIG_SHOWINFO_FILTER)               += vf_showinfo.o
81
+OBJS-$(CONFIG_SHUFFLEPLANES_FILTER)          += vf_shuffleplanes.o
81 82
 OBJS-$(CONFIG_SPLIT_FILTER)                  += split.o
82 83
 OBJS-$(CONFIG_TRANSPOSE_FILTER)              += vf_transpose.o
83 84
 OBJS-$(CONFIG_TRIM_FILTER)                   += trim.o
... ...
@@ -98,6 +98,7 @@ void avfilter_register_all(void)
98 98
     REGISTER_FILTER(SETSAR,         setsar,         vf);
99 99
     REGISTER_FILTER(SETTB,          settb,          vf);
100 100
     REGISTER_FILTER(SHOWINFO,       showinfo,       vf);
101
+    REGISTER_FILTER(SHUFFLEPLANES,  shuffleplanes,  vf);
101 102
     REGISTER_FILTER(SPLIT,          split,          vf);
102 103
     REGISTER_FILTER(TRANSPOSE,      transpose,      vf);
103 104
     REGISTER_FILTER(TRIM,           trim,           vf);
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFILTER_VERSION_MAJOR  4
33
-#define LIBAVFILTER_VERSION_MINOR  2
33
+#define LIBAVFILTER_VERSION_MINOR  3
34 34
 #define LIBAVFILTER_VERSION_MICRO  0
35 35
 
36 36
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
37 37
new file mode 100644
... ...
@@ -0,0 +1,172 @@
0
+/*
1
+ * This file is part of Libav.
2
+ *
3
+ * Libav is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * Libav is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with Libav; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#include "libavutil/avstring.h"
19
+#include "libavutil/common.h"
20
+#include "libavutil/internal.h"
21
+#include "libavutil/opt.h"
22
+#include "libavutil/pixdesc.h"
23
+#include "libavutil/pixfmt.h"
24
+
25
+#include "avfilter.h"
26
+#include "internal.h"
27
+#include "video.h"
28
+
29
+typedef struct ShufflePlanesContext {
30
+    const AVClass *class;
31
+
32
+    /* number of planes in the selected pixel format */
33
+    int planes;
34
+
35
+    /* mapping indices */
36
+    uint8_t map[4];
37
+
38
+    /* set to 1 if some plane is used more than once, so we need to make a copy */
39
+    int copy;
40
+} ShufflePlanesContext;
41
+
42
+static av_cold int shuffleplanes_config_input(AVFilterLink *inlink)
43
+{
44
+    AVFilterContext    *ctx = inlink->dst;
45
+    ShufflePlanesContext *s = ctx->priv;
46
+    const AVPixFmtDescriptor *desc;
47
+    int used[4] = { 0 };
48
+    int i;
49
+
50
+    s->copy   = 0;
51
+    s->planes = av_pix_fmt_count_planes(inlink->format);
52
+    desc      = av_pix_fmt_desc_get(inlink->format);
53
+
54
+    for (i = 0; i < s->planes; i++) {
55
+        if (s->map[i] >= s->planes) {
56
+            av_log(ctx, AV_LOG_ERROR,
57
+                   "Non-existing input plane #%d mapped to output plane #%d.\n",
58
+                   s->map[i], i);
59
+            return AVERROR(EINVAL);
60
+        }
61
+
62
+        if ((desc->log2_chroma_h || desc->log2_chroma_w) &&
63
+            (i == 1 || i == 2) != (s->map[i] == 1 || s->map[i] == 2)) {
64
+            av_log(ctx, AV_LOG_ERROR,
65
+                   "Cannot map between a subsampled chroma plane and a luma "
66
+                   "or alpha plane.\n");
67
+            return AVERROR(EINVAL);
68
+        }
69
+
70
+        if ((desc->flags & AV_PIX_FMT_FLAG_PAL ||
71
+             desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) &&
72
+            (i == 1) != (s->map[i] == 1)) {
73
+            av_log(ctx, AV_LOG_ERROR,
74
+                   "Cannot map between a palette plane and a data plane.\n");
75
+            return AVERROR(EINVAL);
76
+        }
77
+        if (used[s->map[i]])
78
+            s->copy = 1;
79
+        used[s->map[i]]++;
80
+    }
81
+
82
+    return 0;
83
+}
84
+
85
+static int shuffleplanes_filter_frame(AVFilterLink *inlink, AVFrame *frame)
86
+{
87
+    AVFilterContext          *ctx = inlink->dst;
88
+    ShufflePlanesContext       *s = ctx->priv;
89
+    uint8_t *shuffled_data[4]     = { NULL };
90
+    int      shuffled_linesize[4] = { 0 };
91
+    int i, ret;
92
+
93
+    for (i = 0; i < s->planes; i++) {
94
+        shuffled_data[i]     = frame->data[s->map[i]];
95
+        shuffled_linesize[i] = frame->linesize[s->map[i]];
96
+    }
97
+    memcpy(frame->data,     shuffled_data,     sizeof(shuffled_data));
98
+    memcpy(frame->linesize, shuffled_linesize, sizeof(shuffled_linesize));
99
+
100
+    if (s->copy) {
101
+        AVFrame *copy = ff_get_video_buffer(ctx->outputs[0], frame->width, frame->height);
102
+
103
+        if (!copy) {
104
+            ret = AVERROR(ENOMEM);
105
+            goto fail;
106
+        }
107
+
108
+        av_frame_copy(copy, frame);
109
+
110
+        ret = av_frame_copy_props(copy, frame);
111
+        if (ret < 0) {
112
+            av_frame_free(&copy);
113
+            goto fail;
114
+        }
115
+
116
+        av_frame_free(&frame);
117
+        frame = copy;
118
+    }
119
+
120
+    return ff_filter_frame(ctx->outputs[0], frame);
121
+fail:
122
+    av_frame_free(&frame);
123
+    return ret;
124
+}
125
+
126
+#define OFFSET(x) offsetof(ShufflePlanesContext, x)
127
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
128
+static const AVOption shuffleplanes_options[] = {
129
+    { "map0", "Index of the input plane to be used as the first output plane ",  OFFSET(map[0]), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 4, FLAGS },
130
+    { "map1", "Index of the input plane to be used as the second output plane ", OFFSET(map[1]), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 4, FLAGS },
131
+    { "map2", "Index of the input plane to be used as the third output plane ",  OFFSET(map[2]), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 4, FLAGS },
132
+    { "map3", "Index of the input plane to be used as the fourth output plane ", OFFSET(map[3]), AV_OPT_TYPE_INT, { .i64 = 3 }, 0, 4, FLAGS },
133
+    { NULL },
134
+};
135
+
136
+static const AVClass shuffleplanes_class = {
137
+    .class_name = "shuffleplanes",
138
+    .item_name  = av_default_item_name,
139
+    .option     = shuffleplanes_options,
140
+    .version    = LIBAVUTIL_VERSION_INT,
141
+};
142
+
143
+static const AVFilterPad shuffleplanes_inputs[] = {
144
+    {
145
+        .name             = "default",
146
+        .type             = AVMEDIA_TYPE_VIDEO,
147
+        .config_props     = shuffleplanes_config_input,
148
+        .filter_frame     = shuffleplanes_filter_frame,
149
+        .get_video_buffer = ff_null_get_video_buffer,
150
+    },
151
+    { NULL },
152
+};
153
+
154
+static const AVFilterPad shuffleplanes_outputs[] = {
155
+    {
156
+        .name = "default",
157
+        .type = AVMEDIA_TYPE_VIDEO,
158
+    },
159
+    { NULL },
160
+};
161
+
162
+AVFilter ff_vf_shuffleplanes = {
163
+    .name         = "shuffleplanes",
164
+    .description  = NULL_IF_CONFIG_SMALL("Shuffle video planes"),
165
+
166
+    .priv_size    = sizeof(ShufflePlanesContext),
167
+    .priv_class   = &shuffleplanes_class,
168
+
169
+    .inputs       = shuffleplanes_inputs,
170
+    .outputs      = shuffleplanes_outputs,
171
+};