Browse code

lavfi: port MP stereo3d filter

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2013/03/02 02:35:52
Showing 8 changed files
... ...
@@ -23,6 +23,7 @@ version <next>:
23 23
 - noise filter ported from libmpcodecs
24 24
 - Subtitles character encoding conversion
25 25
 - blend filter
26
+- stereo3d filter ported from libmpcodecs
26 27
 
27 28
 
28 29
 version 1.1:
... ...
@@ -39,6 +39,7 @@ Specifically, the GPL parts of FFmpeg are
39 39
     - vf_noise.c
40 40
     - vf_pp.c
41 41
     - vf_smartblur.c
42
+    - vf_stereo3d.c
42 43
     - vf_super2xsai.c
43 44
     - vf_tinterlace.c
44 45
     - vf_yadif.c
... ...
@@ -2081,6 +2081,7 @@ removelogo_filter_deps="avcodec avformat swscale"
2081 2081
 scale_filter_deps="swscale"
2082 2082
 smartblur_filter_deps="gpl swscale"
2083 2083
 showspectrum_filter_deps="avcodec rdft"
2084
+stereo3d_filter_deps="gpl"
2084 2085
 subtitles_filter_deps="avformat avcodec libass"
2085 2086
 super2xsai_filter_deps="gpl"
2086 2087
 tinterlace_filter_deps="gpl"
... ...
@@ -4832,6 +4832,127 @@ a pixel should be blurred or not. A value of 0 will filter all the
4832 4832
 image, a value included in [0,30] will filter flat areas and a value
4833 4833
 included in [-30,0] will filter edges.
4834 4834
 
4835
+@section stereo3d
4836
+
4837
+Convert between different stereoscopic image formats.
4838
+
4839
+This filter accepts the following named options, expressed as a
4840
+sequence of @var{key}=@var{value} pairs, separated by ":".
4841
+
4842
+@table @option
4843
+@item in
4844
+Set stereoscopic image format of input.
4845
+
4846
+Available values for input image formats are:
4847
+@table @samp
4848
+@item sbsl
4849
+side by side parallel (left eye left, right eye right)
4850
+
4851
+@item sbsr
4852
+side by side crosseye (right eye left, left eye right)
4853
+
4854
+@item sbs2l
4855
+side by side parallel with half width resolution
4856
+(left eye left, right eye right)
4857
+
4858
+@item sbs2r
4859
+side by side crosseye with half width resolution
4860
+(right eye left, left eye right)
4861
+
4862
+@item abl
4863
+above-below (left eye above, right eye below)
4864
+
4865
+@item abr
4866
+above-below (right eye above, left eye below)
4867
+
4868
+@item ab2l
4869
+above-below with half height resolution
4870
+(left eye above, right eye below)
4871
+
4872
+@item ab2r
4873
+above-below with half height resolution
4874
+(right eye above, left eye below)
4875
+
4876
+Default value is @samp{sbsl}.
4877
+@end table
4878
+
4879
+@item out
4880
+Set stereoscopic image format of output.
4881
+
4882
+Available values for output image formats are all the input formats as well as:
4883
+@table @samp
4884
+@item arbg
4885
+anaglyph red/blue gray
4886
+(red filter on left eye, blue filter on right eye)
4887
+
4888
+@item argg
4889
+anaglyph red/green gray
4890
+(red filter on left eye, green filter on right eye)
4891
+
4892
+@item arcg
4893
+anaglyph red/cyan gray
4894
+(red filter on left eye, cyan filter on right eye)
4895
+
4896
+@item arch
4897
+anaglyph red/cyan half colored
4898
+(red filter on left eye, cyan filter on right eye)
4899
+
4900
+@item arcc
4901
+anaglyph red/cyan color
4902
+(red filter on left eye, cyan filter on right eye)
4903
+
4904
+@item arcd
4905
+anaglyph red/cyan color optimized with the least squares projection of dubois
4906
+(red filter on left eye, cyan filter on right eye)
4907
+
4908
+@item agmg
4909
+anaglyph green/magenta gray
4910
+(green filter on left eye, magenta filter on right eye)
4911
+
4912
+@item agmh
4913
+anaglyph green/magenta half colored
4914
+(green filter on left eye, magenta filter on right eye)
4915
+
4916
+@item agmc
4917
+anaglyph green/magenta colored
4918
+(green filter on left eye, magenta filter on right eye)
4919
+
4920
+@item agmd
4921
+anaglyph green/magenta color optimized with the least squares projection of dubois
4922
+(green filter on left eye, magenta filter on right eye)
4923
+
4924
+@item aybg
4925
+anaglyph yellow/blue gray
4926
+(yellow filter on left eye, blue filter on right eye)
4927
+
4928
+@item aybh
4929
+anaglyph yellow/blue half colored
4930
+(yellow filter on left eye, blue filter on right eye)
4931
+
4932
+@item aybc
4933
+anaglyph yellow/blue colored
4934
+(yellow filter on left eye, blue filter on right eye)
4935
+
4936
+@item aybd
4937
+anaglyph yellow/blue color optimized with the least squares projection of dubois
4938
+(yellow filter on left eye, blue filter on right eye)
4939
+
4940
+@item irl
4941
+interleaved rows (left eye has top row, right eye starts on next row)
4942
+
4943
+@item irr
4944
+interleaved rows (right eye has top row, left eye starts on next row)
4945
+
4946
+@item ml
4947
+mono output (left eye only)
4948
+
4949
+@item mr
4950
+mono output (right eye only)
4951
+@end table
4952
+
4953
+Default value is @samp{arcd}.
4954
+@end table
4955
+
4835 4956
 @anchor{subtitles}
4836 4957
 @section subtitles
4837 4958
 
... ...
@@ -154,6 +154,7 @@ OBJS-$(CONFIG_SETTB_FILTER)                  += f_settb.o
154 154
 OBJS-$(CONFIG_SHOWINFO_FILTER)               += vf_showinfo.o
155 155
 OBJS-$(CONFIG_SMARTBLUR_FILTER)              += vf_smartblur.o
156 156
 OBJS-$(CONFIG_SPLIT_FILTER)                  += split.o
157
+OBJS-$(CONFIG_STEREO3D_FILTER)               += vf_stereo3d.o
157 158
 OBJS-$(CONFIG_SUBTITLES_FILTER)              += vf_subtitles.o
158 159
 OBJS-$(CONFIG_SUPER2XSAI_FILTER)             += vf_super2xsai.o
159 160
 OBJS-$(CONFIG_SWAPUV_FILTER)                 += vf_swapuv.o
... ...
@@ -148,6 +148,7 @@ void avfilter_register_all(void)
148 148
     REGISTER_FILTER(SHOWINFO,       showinfo,       vf);
149 149
     REGISTER_FILTER(SMARTBLUR,      smartblur,      vf);
150 150
     REGISTER_FILTER(SPLIT,          split,          vf);
151
+    REGISTER_FILTER(STEREO3D,       stereo3d,       vf);
151 152
     REGISTER_FILTER(SUBTITLES,      subtitles,      vf);
152 153
     REGISTER_FILTER(SUPER2XSAI,     super2xsai,     vf);
153 154
     REGISTER_FILTER(SWAPUV,         swapuv,         vf);
... ...
@@ -29,7 +29,7 @@
29 29
 #include "libavutil/avutil.h"
30 30
 
31 31
 #define LIBAVFILTER_VERSION_MAJOR  3
32
-#define LIBAVFILTER_VERSION_MINOR  41
32
+#define LIBAVFILTER_VERSION_MINOR  42
33 33
 #define LIBAVFILTER_VERSION_MICRO 100
34 34
 
35 35
 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
36 36
new file mode 100644
... ...
@@ -0,0 +1,478 @@
0
+/*
1
+ * Copyright (c) 2010 Gordon Schmidt <gordon.schmidt <at> s2000.tu-chemnitz.de>
2
+ * Copyright (c) 2013 Paul B Mahol
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 General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2 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
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License along
17
+ * 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
+#include "libavutil/avassert.h"
22
+#include "libavutil/imgutils.h"
23
+#include "libavutil/opt.h"
24
+#include "libavutil/parseutils.h"
25
+#include "libavutil/pixdesc.h"
26
+#include "avfilter.h"
27
+#include "formats.h"
28
+#include "internal.h"
29
+#include "video.h"
30
+
31
+enum StereoCode {
32
+    ANAGLYPH_RC_GRAY,   // anaglyph red/cyan gray
33
+    ANAGLYPH_RC_HALF,   // anaglyph red/cyan half colored
34
+    ANAGLYPH_RC_COLOR,  // anaglyph red/cyan colored
35
+    ANAGLYPH_RC_DUBOIS, // anaglyph red/cyan dubois
36
+    ANAGLYPH_GM_GRAY,   // anaglyph green/magenta gray
37
+    ANAGLYPH_GM_HALF,   // anaglyph green/magenta half colored
38
+    ANAGLYPH_GM_COLOR,  // anaglyph green/magenta colored
39
+    ANAGLYPH_GM_DUBOIS, // anaglyph green/magenta dubois
40
+    ANAGLYPH_YB_GRAY,   // anaglyph yellow/blue gray
41
+    ANAGLYPH_YB_HALF,   // anaglyph yellow/blue half colored
42
+    ANAGLYPH_YB_COLOR,  // anaglyph yellow/blue colored
43
+    ANAGLYPH_YB_DUBOIS, // anaglyph yellow/blue dubois
44
+    ANAGLYPH_RB_GRAY,   // anaglyph red/blue gray
45
+    ANAGLYPH_RG_GRAY,   // anaglyph red/green gray
46
+    MONO_L,             // mono output for debugging (left eye only)
47
+    MONO_R,             // mono output for debugging (right eye only)
48
+    INTERLEAVE_ROWS_LR, // row-interleave (left eye has top row)
49
+    INTERLEAVE_ROWS_RL, // row-interleave (right eye has top row)
50
+    SIDE_BY_SIDE_LR,    // side by side parallel (left eye left, right eye right)
51
+    SIDE_BY_SIDE_RL,    // side by side crosseye (right eye left, left eye right)
52
+    SIDE_BY_SIDE_2_LR,  // side by side parallel with half width resolution
53
+    SIDE_BY_SIDE_2_RL,  // side by side crosseye with half width resolution
54
+    ABOVE_BELOW_LR,     // above-below (left eye above, right eye below)
55
+    ABOVE_BELOW_RL,     // above-below (right eye above, left eye below)
56
+    ABOVE_BELOW_2_LR,   // above-below with half height resolution
57
+    ABOVE_BELOW_2_RL,   // above-below with half height resolution
58
+    STEREO_CODE_COUNT   // TODO: needs autodetection
59
+};
60
+
61
+typedef struct StereoComponent {
62
+    enum StereoCode format;
63
+    int width, height;
64
+    int off_left, off_right;
65
+    int row_left, row_right;
66
+} StereoComponent;
67
+
68
+static const int ana_coeff[][3][6] = {
69
+  [ANAGLYPH_RB_GRAY]   =
70
+    {{19595, 38470,  7471,     0,     0,     0},
71
+     {    0,     0,     0,     0,     0,     0},
72
+     {    0,     0,     0, 19595, 38470,  7471}},
73
+  [ANAGLYPH_RG_GRAY]   =
74
+    {{19595, 38470,  7471,     0,     0,     0},
75
+     {    0,     0,     0, 19595, 38470,  7471},
76
+     {    0,     0,     0,     0,     0,     0}},
77
+  [ANAGLYPH_RC_GRAY]   =
78
+    {{19595, 38470,  7471,     0,     0,     0},
79
+     {    0,     0,     0, 19595, 38470,  7471},
80
+     {    0,     0,     0, 19595, 38470,  7471}},
81
+  [ANAGLYPH_RC_HALF]   =
82
+    {{19595, 38470,  7471,     0,     0,     0},
83
+     {    0,     0,     0,     0, 65536,     0},
84
+     {    0,     0,     0,     0,     0, 65536}},
85
+  [ANAGLYPH_RC_COLOR]  =
86
+    {{65536,     0,     0,     0,     0,     0},
87
+     {    0,     0,     0,     0, 65536,     0},
88
+     {    0,     0,     0,     0,     0, 65536}},
89
+  [ANAGLYPH_RC_DUBOIS] =
90
+    {{29891, 32800, 11559, -2849, -5763,  -102},
91
+     {-2627, -2479, -1033, 24804, 48080, -1209},
92
+     { -997, -1350,  -358, -4729, -7403, 80373}},
93
+  [ANAGLYPH_GM_GRAY]   =
94
+    {{    0,     0,     0, 19595, 38470,  7471},
95
+     {19595, 38470,  7471,     0,     0,     0},
96
+     {    0,     0,     0, 19595, 38470,  7471}},
97
+  [ANAGLYPH_GM_HALF]   =
98
+    {{    0,     0,     0, 65536,     0,     0},
99
+     {19595, 38470,  7471,     0,     0,     0},
100
+     {    0,     0,     0,     0,     0, 65536}},
101
+  [ANAGLYPH_GM_COLOR]  =
102
+    {{    0,     0,     0, 65536,     0,     0},
103
+     {    0, 65536,     0,     0,     0,     0},
104
+     {    0,     0,     0,     0,     0, 65536}},
105
+  [ANAGLYPH_GM_DUBOIS]  =
106
+    {{-4063,-10354, -2556, 34669, 46203,  1573},
107
+     {18612, 43778,  9372, -1049,  -983, -4260},
108
+     { -983, -1769,  1376,   590,  4915, 61407}},
109
+  [ANAGLYPH_YB_GRAY]   =
110
+    {{    0,     0,     0, 19595, 38470,  7471},
111
+     {    0,     0,     0, 19595, 38470,  7471},
112
+     {19595, 38470,  7471,     0,     0,     0}},
113
+  [ANAGLYPH_YB_HALF]   =
114
+    {{    0,     0,     0, 65536,     0,     0},
115
+     {    0,     0,     0,     0, 65536,     0},
116
+     {19595, 38470,  7471,     0,     0,     0}},
117
+  [ANAGLYPH_YB_COLOR]  =
118
+    {{    0,     0,     0, 65536,     0,     0},
119
+     {    0,     0,     0,     0, 65536,     0},
120
+     {    0,     0, 65536,     0,     0,     0}},
121
+  [ANAGLYPH_YB_DUBOIS] =
122
+    {{65535,-12650,18451,   -987, -7590, -1049},
123
+     {-1604, 56032, 4196,    370,  3826, -1049},
124
+     {-2345,-10676, 1358,   5801, 11416, 56217}},
125
+};
126
+
127
+typedef struct Stereo3DContext {
128
+    const AVClass *class;
129
+    StereoComponent in, out;
130
+    int width, height;
131
+    int row_step;
132
+    int ana_matrix[3][6];
133
+} Stereo3DContext;
134
+
135
+#define OFFSET(x) offsetof(Stereo3DContext, x)
136
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
137
+
138
+static const AVOption stereo3d_options[] = {
139
+    { "in",    "set input format",  OFFSET(in.format),  AV_OPT_TYPE_INT, {.i64=SIDE_BY_SIDE_LR}, SIDE_BY_SIDE_LR, ABOVE_BELOW_2_RL, FLAGS, "in"},
140
+    { "ab2l",  "above below half height left first",  0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_LR},  0, 0, FLAGS, "in" },
141
+    { "ab2r",  "above below half height right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_RL},  0, 0, FLAGS, "in" },
142
+    { "abl",   "above below left first",              0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_LR},    0, 0, FLAGS, "in" },
143
+    { "abr",   "above below right first",             0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_RL},    0, 0, FLAGS, "in" },
144
+    { "sbs2l", "side by side half width left first",  0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_LR}, 0, 0, FLAGS, "in" },
145
+    { "sbs2r", "side by side half width right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_RL}, 0, 0, FLAGS, "in" },
146
+    { "sbsl",  "side by side left first",             0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_LR},   0, 0, FLAGS, "in" },
147
+    { "sbsr",  "side by side right first",            0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_RL},   0, 0, FLAGS, "in" },
148
+    { "out",   "set output format", OFFSET(out.format), AV_OPT_TYPE_INT, {.i64=ANAGLYPH_RC_DUBOIS}, 0, STEREO_CODE_COUNT-1, FLAGS, "out"},
149
+    { "ab2l",  "above below half height left first",  0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_LR},   0, 0, FLAGS, "out" },
150
+    { "ab2r",  "above below half height right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_RL},   0, 0, FLAGS, "out" },
151
+    { "abl",   "above below left first",              0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_LR},     0, 0, FLAGS, "out" },
152
+    { "abr",   "above below right first",             0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_RL},     0, 0, FLAGS, "out" },
153
+    { "agmc",  "anaglyph green magenta color",        0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_COLOR},  0, 0, FLAGS, "out" },
154
+    { "agmd",  "anaglyph green magenta dubois",       0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_DUBOIS}, 0, 0, FLAGS, "out" },
155
+    { "agmg",  "anaglyph green magenta gray",         0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_GRAY},   0, 0, FLAGS, "out" },
156
+    { "agmh",  "anaglyph green magenta half color",   0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_HALF},   0, 0, FLAGS, "out" },
157
+    { "arbg",  "anaglyph red blue gray",              0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RB_GRAY},   0, 0, FLAGS, "out" },
158
+    { "arcc",  "anaglyph red cyan color",             0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_COLOR},  0, 0, FLAGS, "out" },
159
+    { "arcd",  "anaglyph red cyan dubois",            0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_DUBOIS}, 0, 0, FLAGS, "out" },
160
+    { "arcg",  "anaglyph red cyan gray",              0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_GRAY},   0, 0, FLAGS, "out" },
161
+    { "arch",  "anaglyph red cyan half color",        0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_HALF},   0, 0, FLAGS, "out" },
162
+    { "argg",  "anaglyph red green gray",             0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RG_GRAY},   0, 0, FLAGS, "out" },
163
+    { "aybc",  "anaglyph yellow blue color",          0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_COLOR},  0, 0, FLAGS, "out" },
164
+    { "aybd",  "anaglyph yellow blue dubois",         0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_DUBOIS}, 0, 0, FLAGS, "out" },
165
+    { "aybg",  "anaglyph yellow blue gray",           0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_GRAY},   0, 0, FLAGS, "out" },
166
+    { "aybh",  "anaglyph yellow blue half color",     0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_HALF},   0, 0, FLAGS, "out" },
167
+    { "irl",   "interleave rows left first",          0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_ROWS_LR}, 0, 0, FLAGS, "out" },
168
+    { "irr",   "interleave rows right first",         0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_ROWS_RL}, 0, 0, FLAGS, "out" },
169
+    { "ml",    "mono left",                           0, AV_OPT_TYPE_CONST, {.i64=MONO_L},             0, 0, FLAGS, "out" },
170
+    { "mr",    "mono right",                          0, AV_OPT_TYPE_CONST, {.i64=MONO_R},             0, 0, FLAGS, "out" },
171
+    { "sbs2l", "side by side half width left first",  0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_LR},  0, 0, FLAGS, "out" },
172
+    { "sbs2r", "side by side half width right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_RL},  0, 0, FLAGS, "out" },
173
+    { "sbsl",  "side by side left first",             0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_LR},    0, 0, FLAGS, "out" },
174
+    { "sbsr",  "side by side right first",            0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_RL},    0, 0, FLAGS, "out" },
175
+};
176
+
177
+AVFILTER_DEFINE_CLASS(stereo3d);
178
+
179
+static av_cold int init(AVFilterContext *ctx, const char *args)
180
+{
181
+    Stereo3DContext *s = ctx->priv;
182
+    static const char *shorthand[] = { "in", "out", NULL };
183
+    int ret;
184
+
185
+    s->class = &stereo3d_class;
186
+    av_opt_set_defaults(s);
187
+
188
+    if ((ret = av_opt_set_from_string(s, args, shorthand, "=", ":")) < 0)
189
+        return ret;
190
+
191
+    return 0;
192
+}
193
+
194
+static int query_formats(AVFilterContext *ctx)
195
+{
196
+    static const enum AVPixelFormat pix_fmts[] = {
197
+        AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE
198
+    };
199
+
200
+    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
201
+
202
+    return 0;
203
+}
204
+
205
+static int config_output(AVFilterLink *outlink)
206
+{
207
+    AVFilterContext *ctx = outlink->src;
208
+    AVFilterLink *inlink = ctx->inputs[0];
209
+    Stereo3DContext *s = ctx->priv;
210
+    AVRational aspect = inlink->sample_aspect_ratio;
211
+
212
+    s->in.width     =
213
+    s->width        = inlink->w;
214
+    s->in.height    =
215
+    s->height       = inlink->h;
216
+    s->row_step     = 1;
217
+    s->in.off_left  =
218
+    s->in.off_right =
219
+    s->in.row_left  =
220
+    s->in.row_right = 0;
221
+
222
+    switch (s->in.format) {
223
+    case SIDE_BY_SIDE_2_LR:
224
+        aspect.num     *= 2;
225
+    case SIDE_BY_SIDE_LR:
226
+        s->width        = inlink->w / 2;
227
+        s->in.off_right = s->width * 3;
228
+        break;
229
+    case SIDE_BY_SIDE_2_RL:
230
+        aspect.num     *= 2;
231
+    case SIDE_BY_SIDE_RL:
232
+        s->width        = inlink->w / 2;
233
+        s->in.off_left  = s->width * 3;
234
+        break;
235
+    case ABOVE_BELOW_2_LR:
236
+        aspect.den     *= 2;
237
+    case ABOVE_BELOW_LR:
238
+        s->in.row_right =
239
+        s->height       = inlink->h / 2;
240
+        break;
241
+    case ABOVE_BELOW_2_RL:
242
+        aspect.den     *= 2;
243
+    case ABOVE_BELOW_RL:
244
+        s->in.row_left  =
245
+        s->height       = inlink->h / 2;
246
+        break;
247
+    default:
248
+        av_log(ctx, AV_LOG_ERROR, "input format %d is not supported\n", s->in.format);
249
+        return AVERROR(EINVAL);
250
+    }
251
+
252
+    s->out.width     = s->width;
253
+    s->out.height    = s->height;
254
+    s->out.off_left  =
255
+    s->out.off_right =
256
+    s->out.row_left  =
257
+    s->out.row_right = 0;
258
+
259
+    switch (s->out.format) {
260
+    case ANAGLYPH_RB_GRAY:
261
+    case ANAGLYPH_RG_GRAY:
262
+    case ANAGLYPH_RC_GRAY:
263
+    case ANAGLYPH_RC_HALF:
264
+    case ANAGLYPH_RC_COLOR:
265
+    case ANAGLYPH_RC_DUBOIS:
266
+    case ANAGLYPH_GM_GRAY:
267
+    case ANAGLYPH_GM_HALF:
268
+    case ANAGLYPH_GM_COLOR:
269
+    case ANAGLYPH_GM_DUBOIS:
270
+    case ANAGLYPH_YB_GRAY:
271
+    case ANAGLYPH_YB_HALF:
272
+    case ANAGLYPH_YB_COLOR:
273
+    case ANAGLYPH_YB_DUBOIS:
274
+        memcpy(s->ana_matrix, ana_coeff[s->out.format], sizeof(s->ana_matrix));
275
+        break;
276
+    case SIDE_BY_SIDE_2_LR:
277
+        aspect.num      /= 2;
278
+    case SIDE_BY_SIDE_LR:
279
+        s->out.width     =
280
+        s->out.off_right = s->width * 3;
281
+        break;
282
+    case SIDE_BY_SIDE_2_RL:
283
+        aspect.num      /= 2;
284
+    case SIDE_BY_SIDE_RL:
285
+        s->out.width     = s->width * 2;
286
+        s->out.off_left  = s->width * 3;
287
+        break;
288
+    case ABOVE_BELOW_2_LR:
289
+        aspect.den      /= 2;
290
+    case ABOVE_BELOW_LR:
291
+        s->out.height    = s->height * 2;
292
+        s->out.row_right = s->height;
293
+        break;
294
+    case ABOVE_BELOW_2_RL:
295
+        aspect.den      /= 2;
296
+    case ABOVE_BELOW_RL:
297
+        s->out.height    = s->height * 2;
298
+        s->out.row_left  = s->height;
299
+        break;
300
+    case INTERLEAVE_ROWS_LR:
301
+        s->row_step      = 2;
302
+        s->height        = s->height / 2;
303
+        s->out.off_right = s->width * 3;
304
+        s->in.off_right += s->in.width * 3;
305
+        break;
306
+    case INTERLEAVE_ROWS_RL:
307
+        s->row_step      = 2;
308
+        s->height        = s->height / 2;
309
+        s->out.off_left  = s->width * 3;
310
+        s->in.off_left  += s->in.width * 3;
311
+        break;
312
+    case MONO_R:
313
+        s->in.off_left   = s->in.off_right;
314
+        s->in.row_left   = s->in.row_right;
315
+    case MONO_L:
316
+        break;
317
+    default:
318
+        av_log(ctx, AV_LOG_ERROR, "output format is not supported\n");
319
+        return AVERROR(EINVAL);
320
+    }
321
+
322
+    outlink->w = s->out.width;
323
+    outlink->h = s->out.height;
324
+    outlink->sample_aspect_ratio = aspect;
325
+
326
+    return 0;
327
+}
328
+
329
+static inline uint8_t ana_convert(const int *coeff, uint8_t *left, uint8_t *right)
330
+{
331
+    int sum;
332
+
333
+    sum  = coeff[0] * left[0] + coeff[3] * right[0]; //red in
334
+    sum += coeff[1] * left[1] + coeff[4] * right[1]; //green in
335
+    sum += coeff[2] * left[2] + coeff[5] * right[2]; //blue in
336
+
337
+    return av_clip_uint8(sum >> 16);
338
+}
339
+
340
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
341
+{
342
+    AVFilterContext *ctx  = inlink->dst;
343
+    Stereo3DContext *s = ctx->priv;
344
+    AVFilterLink *outlink = ctx->outputs[0];
345
+    AVFilterBufferRef *out;
346
+    int out_off_left, out_off_right;
347
+    int in_off_left, in_off_right;
348
+    int ret;
349
+
350
+    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
351
+    if (!out) {
352
+        avfilter_unref_bufferp(&inpicref);
353
+        return AVERROR(ENOMEM);
354
+    }
355
+
356
+    out->pts = inpicref->pts;
357
+    out->pos = inpicref->pos;
358
+
359
+    in_off_left   = s->in.row_left  * inpicref->linesize[0] + s->in.off_left;
360
+    in_off_right  = s->in.row_right * inpicref->linesize[0] + s->in.off_right;
361
+    out_off_left  = s->out.row_left  * out->linesize[0] + s->out.off_left;
362
+    out_off_right = s->out.row_right * out->linesize[0] + s->out.off_right;
363
+
364
+    switch (s->out.format) {
365
+    case SIDE_BY_SIDE_LR:
366
+    case SIDE_BY_SIDE_RL:
367
+    case SIDE_BY_SIDE_2_LR:
368
+    case SIDE_BY_SIDE_2_RL:
369
+    case ABOVE_BELOW_LR:
370
+    case ABOVE_BELOW_RL:
371
+    case ABOVE_BELOW_2_LR:
372
+    case ABOVE_BELOW_2_RL:
373
+    case INTERLEAVE_ROWS_LR:
374
+    case INTERLEAVE_ROWS_RL:
375
+        av_image_copy_plane(out->data[0] + out_off_left,
376
+                            out->linesize[0] * s->row_step,
377
+                            inpicref->data[0] + in_off_left,
378
+                            inpicref->linesize[0] * s->row_step,
379
+                            3 * s->width, s->height);
380
+        av_image_copy_plane(out->data[0] + out_off_right,
381
+                            out->linesize[0] * s->row_step,
382
+                            inpicref->data[0] + in_off_right,
383
+                            inpicref->linesize[0] * s->row_step,
384
+                            3 * s->width, s->height);
385
+        break;
386
+    case MONO_L:
387
+    case MONO_R:
388
+        av_image_copy_plane(out->data[0], out->linesize[0],
389
+                            inpicref->data[0] + in_off_left,
390
+                            inpicref->linesize[0],
391
+                            3 * s->width, s->height);
392
+        break;
393
+    case ANAGLYPH_RB_GRAY:
394
+    case ANAGLYPH_RG_GRAY:
395
+    case ANAGLYPH_RC_GRAY:
396
+    case ANAGLYPH_RC_HALF:
397
+    case ANAGLYPH_RC_COLOR:
398
+    case ANAGLYPH_RC_DUBOIS:
399
+    case ANAGLYPH_GM_GRAY:
400
+    case ANAGLYPH_GM_HALF:
401
+    case ANAGLYPH_GM_COLOR:
402
+    case ANAGLYPH_GM_DUBOIS:
403
+    case ANAGLYPH_YB_GRAY:
404
+    case ANAGLYPH_YB_HALF:
405
+    case ANAGLYPH_YB_COLOR:
406
+    case ANAGLYPH_YB_DUBOIS: {
407
+        int i, x, y, il, ir, o;
408
+        uint8_t *src = inpicref->data[0];
409
+        uint8_t *dst = out->data[0];
410
+        int out_width = s->out.width;
411
+        int *ana_matrix[3];
412
+
413
+        for (i = 0; i < 3; i++)
414
+            ana_matrix[i] = s->ana_matrix[i];
415
+
416
+        for (y = 0; y < s->out.height; y++) {
417
+            o   = out->linesize[0] * y;
418
+            il  = in_off_left  + y * inpicref->linesize[0];
419
+            ir  = in_off_right + y * inpicref->linesize[0];
420
+            for (x = 0; x < out_width; x++, il += 3, ir += 3, o+= 3) {
421
+                dst[o    ] = ana_convert(ana_matrix[0], src + il, src + ir);
422
+                dst[o + 1] = ana_convert(ana_matrix[1], src + il, src + ir);
423
+                dst[o + 2] = ana_convert(ana_matrix[2], src + il, src + ir);
424
+            }
425
+        }
426
+        break;
427
+    }
428
+    default:
429
+        av_assert0(0);
430
+    }
431
+
432
+    ret = ff_filter_frame(outlink, out);
433
+    avfilter_unref_bufferp(&inpicref);
434
+    if (ret < 0)
435
+        return ret;
436
+    return 0;
437
+}
438
+
439
+static av_cold void uninit(AVFilterContext *ctx)
440
+{
441
+    Stereo3DContext *s = ctx->priv;
442
+
443
+    av_opt_free(s);
444
+}
445
+
446
+static const AVFilterPad stereo3d_inputs[] = {
447
+    {
448
+        .name             = "default",
449
+        .type             = AVMEDIA_TYPE_VIDEO,
450
+        .get_video_buffer = ff_null_get_video_buffer,
451
+        .filter_frame     = filter_frame,
452
+        .min_perms        = AV_PERM_READ,
453
+    },
454
+    { NULL }
455
+};
456
+
457
+static const AVFilterPad stereo3d_outputs[] = {
458
+    {
459
+        .name         = "default",
460
+        .type         = AVMEDIA_TYPE_VIDEO,
461
+        .config_props = config_output,
462
+        .min_perms    = AV_PERM_WRITE,
463
+    },
464
+    { NULL }
465
+};
466
+
467
+AVFilter avfilter_vf_stereo3d = {
468
+    .name          = "stereo3d",
469
+    .description   = NULL_IF_CONFIG_SMALL("Convert video stereoscopic 3D view."),
470
+    .priv_size     = sizeof(Stereo3DContext),
471
+    .init          = init,
472
+    .uninit        = uninit,
473
+    .query_formats = query_formats,
474
+    .inputs        = stereo3d_inputs,
475
+    .outputs       = stereo3d_outputs,
476
+    .priv_class    = &stereo3d_class,
477
+};