Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Copyright (c) 2010 Gordon Schmidt <gordon.schmidt <at> s2000.tu-chemnitz.de> | |
3 | * Copyright (c) 2013 Paul B Mahol | |
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 General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2 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 | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License along | |
18 | * 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 | #include "libavutil/avassert.h" | |
23 | #include "libavutil/imgutils.h" | |
24 | #include "libavutil/opt.h" | |
25 | #include "libavutil/parseutils.h" | |
26 | #include "libavutil/pixdesc.h" | |
27 | #include "avfilter.h" | |
28 | #include "drawutils.h" | |
29 | #include "formats.h" | |
30 | #include "internal.h" | |
31 | #include "video.h" | |
32 | ||
33 | enum StereoCode { | |
34 | ANAGLYPH_RC_GRAY, // anaglyph red/cyan gray | |
35 | ANAGLYPH_RC_HALF, // anaglyph red/cyan half colored | |
36 | ANAGLYPH_RC_COLOR, // anaglyph red/cyan colored | |
37 | ANAGLYPH_RC_DUBOIS, // anaglyph red/cyan dubois | |
38 | ANAGLYPH_GM_GRAY, // anaglyph green/magenta gray | |
39 | ANAGLYPH_GM_HALF, // anaglyph green/magenta half colored | |
40 | ANAGLYPH_GM_COLOR, // anaglyph green/magenta colored | |
41 | ANAGLYPH_GM_DUBOIS, // anaglyph green/magenta dubois | |
42 | ANAGLYPH_YB_GRAY, // anaglyph yellow/blue gray | |
43 | ANAGLYPH_YB_HALF, // anaglyph yellow/blue half colored | |
44 | ANAGLYPH_YB_COLOR, // anaglyph yellow/blue colored | |
45 | ANAGLYPH_YB_DUBOIS, // anaglyph yellow/blue dubois | |
46 | ANAGLYPH_RB_GRAY, // anaglyph red/blue gray | |
47 | ANAGLYPH_RG_GRAY, // anaglyph red/green gray | |
48 | MONO_L, // mono output for debugging (left eye only) | |
49 | MONO_R, // mono output for debugging (right eye only) | |
50 | INTERLEAVE_ROWS_LR, // row-interleave (left eye has top row) | |
51 | INTERLEAVE_ROWS_RL, // row-interleave (right eye has top row) | |
52 | SIDE_BY_SIDE_LR, // side by side parallel (left eye left, right eye right) | |
53 | SIDE_BY_SIDE_RL, // side by side crosseye (right eye left, left eye right) | |
54 | SIDE_BY_SIDE_2_LR, // side by side parallel with half width resolution | |
55 | SIDE_BY_SIDE_2_RL, // side by side crosseye with half width resolution | |
56 | ABOVE_BELOW_LR, // above-below (left eye above, right eye below) | |
57 | ABOVE_BELOW_RL, // above-below (right eye above, left eye below) | |
58 | ABOVE_BELOW_2_LR, // above-below with half height resolution | |
59 | ABOVE_BELOW_2_RL, // above-below with half height resolution | |
60 | ALTERNATING_LR, // alternating frames (left eye first, right eye second) | |
61 | ALTERNATING_RL, // alternating frames (right eye first, left eye second) | |
62 | STEREO_CODE_COUNT // TODO: needs autodetection | |
63 | }; | |
64 | ||
65 | typedef struct StereoComponent { | |
66 | enum StereoCode format; | |
67 | int width, height; | |
68 | int off_left, off_right; | |
69 | int off_lstep, off_rstep; | |
70 | int row_left, row_right; | |
71 | } StereoComponent; | |
72 | ||
73 | static const int ana_coeff[][3][6] = { | |
74 | [ANAGLYPH_RB_GRAY] = | |
75 | {{19595, 38470, 7471, 0, 0, 0}, | |
76 | { 0, 0, 0, 0, 0, 0}, | |
77 | { 0, 0, 0, 19595, 38470, 7471}}, | |
78 | [ANAGLYPH_RG_GRAY] = | |
79 | {{19595, 38470, 7471, 0, 0, 0}, | |
80 | { 0, 0, 0, 19595, 38470, 7471}, | |
81 | { 0, 0, 0, 0, 0, 0}}, | |
82 | [ANAGLYPH_RC_GRAY] = | |
83 | {{19595, 38470, 7471, 0, 0, 0}, | |
84 | { 0, 0, 0, 19595, 38470, 7471}, | |
85 | { 0, 0, 0, 19595, 38470, 7471}}, | |
86 | [ANAGLYPH_RC_HALF] = | |
87 | {{19595, 38470, 7471, 0, 0, 0}, | |
88 | { 0, 0, 0, 0, 65536, 0}, | |
89 | { 0, 0, 0, 0, 0, 65536}}, | |
90 | [ANAGLYPH_RC_COLOR] = | |
91 | {{65536, 0, 0, 0, 0, 0}, | |
92 | { 0, 0, 0, 0, 65536, 0}, | |
93 | { 0, 0, 0, 0, 0, 65536}}, | |
94 | [ANAGLYPH_RC_DUBOIS] = | |
95 | {{29891, 32800, 11559, -2849, -5763, -102}, | |
96 | {-2627, -2479, -1033, 24804, 48080, -1209}, | |
97 | { -997, -1350, -358, -4729, -7403, 80373}}, | |
98 | [ANAGLYPH_GM_GRAY] = | |
99 | {{ 0, 0, 0, 19595, 38470, 7471}, | |
100 | {19595, 38470, 7471, 0, 0, 0}, | |
101 | { 0, 0, 0, 19595, 38470, 7471}}, | |
102 | [ANAGLYPH_GM_HALF] = | |
103 | {{ 0, 0, 0, 65536, 0, 0}, | |
104 | {19595, 38470, 7471, 0, 0, 0}, | |
105 | { 0, 0, 0, 0, 0, 65536}}, | |
106 | [ANAGLYPH_GM_COLOR] = | |
107 | {{ 0, 0, 0, 65536, 0, 0}, | |
108 | { 0, 65536, 0, 0, 0, 0}, | |
109 | { 0, 0, 0, 0, 0, 65536}}, | |
110 | [ANAGLYPH_GM_DUBOIS] = | |
111 | {{-4063,-10354, -2556, 34669, 46203, 1573}, | |
112 | {18612, 43778, 9372, -1049, -983, -4260}, | |
113 | { -983, -1769, 1376, 590, 4915, 61407}}, | |
114 | [ANAGLYPH_YB_GRAY] = | |
115 | {{ 0, 0, 0, 19595, 38470, 7471}, | |
116 | { 0, 0, 0, 19595, 38470, 7471}, | |
117 | {19595, 38470, 7471, 0, 0, 0}}, | |
118 | [ANAGLYPH_YB_HALF] = | |
119 | {{ 0, 0, 0, 65536, 0, 0}, | |
120 | { 0, 0, 0, 0, 65536, 0}, | |
121 | {19595, 38470, 7471, 0, 0, 0}}, | |
122 | [ANAGLYPH_YB_COLOR] = | |
123 | {{ 0, 0, 0, 65536, 0, 0}, | |
124 | { 0, 0, 0, 0, 65536, 0}, | |
125 | { 0, 0, 65536, 0, 0, 0}}, | |
126 | [ANAGLYPH_YB_DUBOIS] = | |
127 | {{65535,-12650,18451, -987, -7590, -1049}, | |
128 | {-1604, 56032, 4196, 370, 3826, -1049}, | |
129 | {-2345,-10676, 1358, 5801, 11416, 56217}}, | |
130 | }; | |
131 | ||
132 | typedef struct Stereo3DContext { | |
133 | const AVClass *class; | |
134 | StereoComponent in, out; | |
135 | int width, height; | |
136 | int row_step; | |
137 | const int *ana_matrix[3]; | |
138 | int nb_planes; | |
139 | int linesize[4]; | |
140 | int pheight[4]; | |
141 | int hsub, vsub; | |
142 | int pixstep[4]; | |
143 | AVFrame *prev; | |
144 | double ts_unit; | |
145 | } Stereo3DContext; | |
146 | ||
147 | #define OFFSET(x) offsetof(Stereo3DContext, x) | |
148 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM | |
149 | ||
150 | static const AVOption stereo3d_options[] = { | |
151 | { "in", "set input format", OFFSET(in.format), AV_OPT_TYPE_INT, {.i64=SIDE_BY_SIDE_LR}, SIDE_BY_SIDE_LR, STEREO_CODE_COUNT-1, FLAGS, "in"}, | |
152 | { "ab2l", "above below half height left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_LR}, 0, 0, FLAGS, "in" }, | |
153 | { "ab2r", "above below half height right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_RL}, 0, 0, FLAGS, "in" }, | |
154 | { "abl", "above below left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_LR}, 0, 0, FLAGS, "in" }, | |
155 | { "abr", "above below right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_RL}, 0, 0, FLAGS, "in" }, | |
156 | { "al", "alternating frames left first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_LR}, 0, 0, FLAGS, "in" }, | |
157 | { "ar", "alternating frames right first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_RL}, 0, 0, FLAGS, "in" }, | |
158 | { "sbs2l", "side by side half width left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_LR}, 0, 0, FLAGS, "in" }, | |
159 | { "sbs2r", "side by side half width right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_RL}, 0, 0, FLAGS, "in" }, | |
160 | { "sbsl", "side by side left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_LR}, 0, 0, FLAGS, "in" }, | |
161 | { "sbsr", "side by side right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_RL}, 0, 0, FLAGS, "in" }, | |
162 | { "out", "set output format", OFFSET(out.format), AV_OPT_TYPE_INT, {.i64=ANAGLYPH_RC_DUBOIS}, 0, STEREO_CODE_COUNT-1, FLAGS, "out"}, | |
163 | { "ab2l", "above below half height left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_LR}, 0, 0, FLAGS, "out" }, | |
164 | { "ab2r", "above below half height right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_RL}, 0, 0, FLAGS, "out" }, | |
165 | { "abl", "above below left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_LR}, 0, 0, FLAGS, "out" }, | |
166 | { "abr", "above below right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_RL}, 0, 0, FLAGS, "out" }, | |
167 | { "agmc", "anaglyph green magenta color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_COLOR}, 0, 0, FLAGS, "out" }, | |
168 | { "agmd", "anaglyph green magenta dubois", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_DUBOIS}, 0, 0, FLAGS, "out" }, | |
169 | { "agmg", "anaglyph green magenta gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_GRAY}, 0, 0, FLAGS, "out" }, | |
170 | { "agmh", "anaglyph green magenta half color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_HALF}, 0, 0, FLAGS, "out" }, | |
171 | { "al", "alternating frames left first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_LR}, 0, 0, FLAGS, "out" }, | |
172 | { "ar", "alternating frames right first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_RL}, 0, 0, FLAGS, "out" }, | |
173 | { "arbg", "anaglyph red blue gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RB_GRAY}, 0, 0, FLAGS, "out" }, | |
174 | { "arcc", "anaglyph red cyan color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_COLOR}, 0, 0, FLAGS, "out" }, | |
175 | { "arcd", "anaglyph red cyan dubois", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_DUBOIS}, 0, 0, FLAGS, "out" }, | |
176 | { "arcg", "anaglyph red cyan gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_GRAY}, 0, 0, FLAGS, "out" }, | |
177 | { "arch", "anaglyph red cyan half color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_HALF}, 0, 0, FLAGS, "out" }, | |
178 | { "argg", "anaglyph red green gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RG_GRAY}, 0, 0, FLAGS, "out" }, | |
179 | { "aybc", "anaglyph yellow blue color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_COLOR}, 0, 0, FLAGS, "out" }, | |
180 | { "aybd", "anaglyph yellow blue dubois", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_DUBOIS}, 0, 0, FLAGS, "out" }, | |
181 | { "aybg", "anaglyph yellow blue gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_GRAY}, 0, 0, FLAGS, "out" }, | |
182 | { "aybh", "anaglyph yellow blue half color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_HALF}, 0, 0, FLAGS, "out" }, | |
183 | { "irl", "interleave rows left first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_ROWS_LR}, 0, 0, FLAGS, "out" }, | |
184 | { "irr", "interleave rows right first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_ROWS_RL}, 0, 0, FLAGS, "out" }, | |
185 | { "ml", "mono left", 0, AV_OPT_TYPE_CONST, {.i64=MONO_L}, 0, 0, FLAGS, "out" }, | |
186 | { "mr", "mono right", 0, AV_OPT_TYPE_CONST, {.i64=MONO_R}, 0, 0, FLAGS, "out" }, | |
187 | { "sbs2l", "side by side half width left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_LR}, 0, 0, FLAGS, "out" }, | |
188 | { "sbs2r", "side by side half width right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_RL}, 0, 0, FLAGS, "out" }, | |
189 | { "sbsl", "side by side left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_LR}, 0, 0, FLAGS, "out" }, | |
190 | { "sbsr", "side by side right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_RL}, 0, 0, FLAGS, "out" }, | |
191 | { NULL } | |
192 | }; | |
193 | ||
194 | AVFILTER_DEFINE_CLASS(stereo3d); | |
195 | ||
196 | static const enum AVPixelFormat anaglyph_pix_fmts[] = { | |
197 | AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, | |
198 | AV_PIX_FMT_NONE | |
199 | }; | |
200 | ||
201 | static const enum AVPixelFormat other_pix_fmts[] = { | |
202 | AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, | |
203 | AV_PIX_FMT_RGB48BE, AV_PIX_FMT_BGR48BE, | |
204 | AV_PIX_FMT_RGB48LE, AV_PIX_FMT_BGR48LE, | |
205 | AV_PIX_FMT_RGBA64BE, AV_PIX_FMT_BGRA64BE, | |
206 | AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_BGRA64LE, | |
207 | AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, | |
208 | AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, | |
209 | AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, | |
210 | AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR, | |
211 | AV_PIX_FMT_GBRP, | |
212 | AV_PIX_FMT_GBRP9BE, AV_PIX_FMT_GBRP9LE, | |
213 | AV_PIX_FMT_GBRP10BE, AV_PIX_FMT_GBRP10LE, | |
214 | AV_PIX_FMT_GBRP12BE, AV_PIX_FMT_GBRP12LE, | |
215 | AV_PIX_FMT_GBRP14BE, AV_PIX_FMT_GBRP14LE, | |
216 | AV_PIX_FMT_GBRP16BE, AV_PIX_FMT_GBRP16LE, | |
217 | AV_PIX_FMT_YUV410P, | |
218 | AV_PIX_FMT_YUV411P, | |
219 | AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, | |
220 | AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, | |
221 | AV_PIX_FMT_YUV440P, | |
222 | AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, | |
223 | AV_PIX_FMT_YUVJ411P, | |
224 | AV_PIX_FMT_YUVJ420P, | |
225 | AV_PIX_FMT_YUVJ422P, | |
226 | AV_PIX_FMT_YUVJ440P, | |
227 | AV_PIX_FMT_YUVJ444P, | |
228 | AV_PIX_FMT_YUV420P9LE, AV_PIX_FMT_YUVA420P9LE, | |
229 | AV_PIX_FMT_YUV420P9BE, AV_PIX_FMT_YUVA420P9BE, | |
230 | AV_PIX_FMT_YUV422P9LE, AV_PIX_FMT_YUVA422P9LE, | |
231 | AV_PIX_FMT_YUV422P9BE, AV_PIX_FMT_YUVA422P9BE, | |
232 | AV_PIX_FMT_YUV444P9LE, AV_PIX_FMT_YUVA444P9LE, | |
233 | AV_PIX_FMT_YUV444P9BE, AV_PIX_FMT_YUVA444P9BE, | |
234 | AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUVA420P10LE, | |
235 | AV_PIX_FMT_YUV420P10BE, AV_PIX_FMT_YUVA420P10BE, | |
236 | AV_PIX_FMT_YUV422P10LE, AV_PIX_FMT_YUVA422P10LE, | |
237 | AV_PIX_FMT_YUV422P10BE, AV_PIX_FMT_YUVA422P10BE, | |
238 | AV_PIX_FMT_YUV444P10LE, AV_PIX_FMT_YUVA444P10LE, | |
239 | AV_PIX_FMT_YUV444P10BE, AV_PIX_FMT_YUVA444P10BE, | |
240 | AV_PIX_FMT_YUV420P12BE, AV_PIX_FMT_YUV420P12LE, | |
241 | AV_PIX_FMT_YUV422P12BE, AV_PIX_FMT_YUV422P12LE, | |
242 | AV_PIX_FMT_YUV444P12BE, AV_PIX_FMT_YUV444P12LE, | |
243 | AV_PIX_FMT_YUV420P14BE, AV_PIX_FMT_YUV420P14LE, | |
244 | AV_PIX_FMT_YUV422P14BE, AV_PIX_FMT_YUV422P14LE, | |
245 | AV_PIX_FMT_YUV444P14BE, AV_PIX_FMT_YUV444P14LE, | |
246 | AV_PIX_FMT_YUV420P16LE, AV_PIX_FMT_YUVA420P16LE, | |
247 | AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_YUVA420P16BE, | |
248 | AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUVA422P16LE, | |
249 | AV_PIX_FMT_YUV422P16BE, AV_PIX_FMT_YUVA422P16BE, | |
250 | AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUVA444P16LE, | |
251 | AV_PIX_FMT_YUV444P16BE, AV_PIX_FMT_YUVA444P16BE, | |
252 | AV_PIX_FMT_NONE | |
253 | }; | |
254 | ||
255 | static int query_formats(AVFilterContext *ctx) | |
256 | { | |
257 | Stereo3DContext *s = ctx->priv; | |
258 | const enum AVPixelFormat *pix_fmts; | |
259 | ||
260 | switch (s->out.format) { | |
261 | case ANAGLYPH_GM_COLOR: | |
262 | case ANAGLYPH_GM_DUBOIS: | |
263 | case ANAGLYPH_GM_GRAY: | |
264 | case ANAGLYPH_GM_HALF: | |
265 | case ANAGLYPH_RB_GRAY: | |
266 | case ANAGLYPH_RC_COLOR: | |
267 | case ANAGLYPH_RC_DUBOIS: | |
268 | case ANAGLYPH_RC_GRAY: | |
269 | case ANAGLYPH_RC_HALF: | |
270 | case ANAGLYPH_RG_GRAY: | |
271 | case ANAGLYPH_YB_COLOR: | |
272 | case ANAGLYPH_YB_DUBOIS: | |
273 | case ANAGLYPH_YB_GRAY: | |
274 | case ANAGLYPH_YB_HALF: | |
275 | pix_fmts = anaglyph_pix_fmts; | |
276 | break; | |
277 | default: | |
278 | pix_fmts = other_pix_fmts; | |
279 | } | |
280 | ||
281 | ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); | |
282 | ||
283 | return 0; | |
284 | } | |
285 | ||
286 | static int config_output(AVFilterLink *outlink) | |
287 | { | |
288 | AVFilterContext *ctx = outlink->src; | |
289 | AVFilterLink *inlink = ctx->inputs[0]; | |
290 | Stereo3DContext *s = ctx->priv; | |
291 | AVRational aspect = inlink->sample_aspect_ratio; | |
292 | AVRational fps = inlink->frame_rate; | |
293 | AVRational tb = inlink->time_base; | |
294 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); | |
295 | int ret; | |
296 | ||
297 | switch (s->in.format) { | |
298 | case SIDE_BY_SIDE_2_LR: | |
299 | case SIDE_BY_SIDE_LR: | |
300 | case SIDE_BY_SIDE_2_RL: | |
301 | case SIDE_BY_SIDE_RL: | |
302 | if (inlink->w & 1) { | |
303 | av_log(ctx, AV_LOG_ERROR, "width must be even\n"); | |
304 | return AVERROR_INVALIDDATA; | |
305 | } | |
306 | break; | |
307 | case ABOVE_BELOW_2_LR: | |
308 | case ABOVE_BELOW_LR: | |
309 | case ABOVE_BELOW_2_RL: | |
310 | case ABOVE_BELOW_RL: | |
311 | if (s->out.format == INTERLEAVE_ROWS_LR || | |
312 | s->out.format == INTERLEAVE_ROWS_RL) { | |
313 | if (inlink->h & 3) { | |
314 | av_log(ctx, AV_LOG_ERROR, "height must be multiple of 4\n"); | |
315 | return AVERROR_INVALIDDATA; | |
316 | } | |
317 | } | |
318 | if (inlink->h & 1) { | |
319 | av_log(ctx, AV_LOG_ERROR, "height must be even\n"); | |
320 | return AVERROR_INVALIDDATA; | |
321 | } | |
322 | break; | |
323 | } | |
324 | ||
325 | s->in.width = | |
326 | s->width = inlink->w; | |
327 | s->in.height = | |
328 | s->height = inlink->h; | |
329 | s->row_step = 1; | |
330 | s->in.off_lstep = | |
331 | s->in.off_rstep = | |
332 | s->in.off_left = | |
333 | s->in.off_right = | |
334 | s->in.row_left = | |
335 | s->in.row_right = 0; | |
336 | ||
337 | switch (s->in.format) { | |
338 | case SIDE_BY_SIDE_2_LR: | |
339 | aspect.num *= 2; | |
340 | case SIDE_BY_SIDE_LR: | |
341 | s->width = inlink->w / 2; | |
342 | s->in.off_right = s->width; | |
343 | break; | |
344 | case SIDE_BY_SIDE_2_RL: | |
345 | aspect.num *= 2; | |
346 | case SIDE_BY_SIDE_RL: | |
347 | s->width = inlink->w / 2; | |
348 | s->in.off_left = s->width; | |
349 | break; | |
350 | case ABOVE_BELOW_2_LR: | |
351 | aspect.den *= 2; | |
352 | case ABOVE_BELOW_LR: | |
353 | s->in.row_right = | |
354 | s->height = inlink->h / 2; | |
355 | break; | |
356 | case ABOVE_BELOW_2_RL: | |
357 | aspect.den *= 2; | |
358 | case ABOVE_BELOW_RL: | |
359 | s->in.row_left = | |
360 | s->height = inlink->h / 2; | |
361 | break; | |
362 | case ALTERNATING_RL: | |
363 | case ALTERNATING_LR: | |
364 | outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP; | |
365 | fps.den *= 2; | |
366 | tb.num *= 2; | |
367 | break; | |
368 | default: | |
369 | av_log(ctx, AV_LOG_ERROR, "input format %d is not supported\n", s->in.format); | |
370 | return AVERROR(EINVAL); | |
371 | } | |
372 | ||
373 | s->out.width = s->width; | |
374 | s->out.height = s->height; | |
375 | s->out.off_lstep = | |
376 | s->out.off_rstep = | |
377 | s->out.off_left = | |
378 | s->out.off_right = | |
379 | s->out.row_left = | |
380 | s->out.row_right = 0; | |
381 | ||
382 | switch (s->out.format) { | |
383 | case ANAGLYPH_RB_GRAY: | |
384 | case ANAGLYPH_RG_GRAY: | |
385 | case ANAGLYPH_RC_GRAY: | |
386 | case ANAGLYPH_RC_HALF: | |
387 | case ANAGLYPH_RC_COLOR: | |
388 | case ANAGLYPH_RC_DUBOIS: | |
389 | case ANAGLYPH_GM_GRAY: | |
390 | case ANAGLYPH_GM_HALF: | |
391 | case ANAGLYPH_GM_COLOR: | |
392 | case ANAGLYPH_GM_DUBOIS: | |
393 | case ANAGLYPH_YB_GRAY: | |
394 | case ANAGLYPH_YB_HALF: | |
395 | case ANAGLYPH_YB_COLOR: | |
396 | case ANAGLYPH_YB_DUBOIS: { | |
397 | uint8_t rgba_map[4]; | |
398 | ||
399 | ff_fill_rgba_map(rgba_map, outlink->format); | |
400 | s->ana_matrix[rgba_map[0]] = &ana_coeff[s->out.format][0][0]; | |
401 | s->ana_matrix[rgba_map[1]] = &ana_coeff[s->out.format][1][0]; | |
402 | s->ana_matrix[rgba_map[2]] = &ana_coeff[s->out.format][2][0]; | |
403 | break; | |
404 | } | |
405 | case SIDE_BY_SIDE_2_LR: | |
406 | aspect.den *= 2; | |
407 | case SIDE_BY_SIDE_LR: | |
408 | s->out.width = s->width * 2; | |
409 | s->out.off_right = s->width; | |
410 | break; | |
411 | case SIDE_BY_SIDE_2_RL: | |
412 | aspect.den *= 2; | |
413 | case SIDE_BY_SIDE_RL: | |
414 | s->out.width = s->width * 2; | |
415 | s->out.off_left = s->width; | |
416 | break; | |
417 | case ABOVE_BELOW_2_LR: | |
418 | aspect.num *= 2; | |
419 | case ABOVE_BELOW_LR: | |
420 | s->out.height = s->height * 2; | |
421 | s->out.row_right = s->height; | |
422 | break; | |
423 | case ABOVE_BELOW_2_RL: | |
424 | aspect.num *= 2; | |
425 | case ABOVE_BELOW_RL: | |
426 | s->out.height = s->height * 2; | |
427 | s->out.row_left = s->height; | |
428 | break; | |
429 | case INTERLEAVE_ROWS_LR: | |
430 | s->row_step = 2; | |
431 | s->height = s->height / 2; | |
432 | s->out.off_rstep = | |
433 | s->in.off_rstep = 1; | |
434 | break; | |
435 | case INTERLEAVE_ROWS_RL: | |
436 | s->row_step = 2; | |
437 | s->height = s->height / 2; | |
438 | s->out.off_lstep = | |
439 | s->in.off_lstep = 1; | |
440 | break; | |
441 | case MONO_R: | |
442 | s->in.off_left = s->in.off_right; | |
443 | s->in.row_left = s->in.row_right; | |
444 | case MONO_L: | |
445 | break; | |
446 | case ALTERNATING_RL: | |
447 | case ALTERNATING_LR: | |
448 | fps.num *= 2; | |
449 | tb.den *= 2; | |
450 | break; | |
451 | default: | |
452 | av_log(ctx, AV_LOG_ERROR, "output format %d is not supported\n", s->out.format); | |
453 | return AVERROR(EINVAL); | |
454 | } | |
455 | ||
456 | outlink->w = s->out.width; | |
457 | outlink->h = s->out.height; | |
458 | outlink->frame_rate = fps; | |
459 | outlink->time_base = tb; | |
460 | outlink->sample_aspect_ratio = aspect; | |
461 | ||
462 | if ((ret = av_image_fill_linesizes(s->linesize, outlink->format, s->width)) < 0) | |
463 | return ret; | |
464 | s->nb_planes = av_pix_fmt_count_planes(outlink->format); | |
465 | av_image_fill_max_pixsteps(s->pixstep, NULL, desc); | |
466 | s->ts_unit = av_q2d(av_inv_q(av_mul_q(outlink->frame_rate, outlink->time_base))); | |
467 | s->pheight[1] = s->pheight[2] = FF_CEIL_RSHIFT(s->height, desc->log2_chroma_h); | |
468 | s->pheight[0] = s->pheight[3] = s->height; | |
469 | s->hsub = desc->log2_chroma_w; | |
470 | s->vsub = desc->log2_chroma_h; | |
471 | ||
472 | return 0; | |
473 | } | |
474 | ||
475 | static inline uint8_t ana_convert(const int *coeff, const uint8_t *left, const uint8_t *right) | |
476 | { | |
477 | int sum; | |
478 | ||
479 | sum = coeff[0] * left[0] + coeff[3] * right[0]; //red in | |
480 | sum += coeff[1] * left[1] + coeff[4] * right[1]; //green in | |
481 | sum += coeff[2] * left[2] + coeff[5] * right[2]; //blue in | |
482 | ||
483 | return av_clip_uint8(sum >> 16); | |
484 | } | |
485 | ||
486 | static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref) | |
487 | { | |
488 | AVFilterContext *ctx = inlink->dst; | |
489 | Stereo3DContext *s = ctx->priv; | |
490 | AVFilterLink *outlink = ctx->outputs[0]; | |
491 | AVFrame *out, *oleft, *oright, *ileft, *iright; | |
492 | int out_off_left[4], out_off_right[4]; | |
493 | int in_off_left[4], in_off_right[4]; | |
494 | int i; | |
495 | ||
496 | switch (s->in.format) { | |
497 | case ALTERNATING_LR: | |
498 | case ALTERNATING_RL: | |
499 | if (!s->prev) { | |
500 | s->prev = inpicref; | |
501 | return 0; | |
502 | } | |
503 | ileft = s->prev; | |
504 | iright = inpicref; | |
505 | if (s->in.format == ALTERNATING_RL) | |
506 | FFSWAP(AVFrame *, ileft, iright); | |
507 | break; | |
508 | default: | |
509 | ileft = iright = inpicref; | |
510 | }; | |
511 | ||
512 | out = oleft = oright = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |
513 | if (!out) { | |
514 | av_frame_free(&s->prev); | |
515 | av_frame_free(&inpicref); | |
516 | return AVERROR(ENOMEM); | |
517 | } | |
518 | av_frame_copy_props(out, inpicref); | |
519 | ||
520 | if (s->out.format == ALTERNATING_LR || | |
521 | s->out.format == ALTERNATING_RL) { | |
522 | oright = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |
523 | if (!oright) { | |
524 | av_frame_free(&oleft); | |
525 | av_frame_free(&s->prev); | |
526 | av_frame_free(&inpicref); | |
527 | return AVERROR(ENOMEM); | |
528 | } | |
529 | av_frame_copy_props(oright, inpicref); | |
530 | } | |
531 | ||
532 | for (i = 0; i < 4; i++) { | |
533 | int hsub = i == 1 || i == 2 ? s->hsub : 0; | |
534 | int vsub = i == 1 || i == 2 ? s->vsub : 0; | |
535 | in_off_left[i] = (FF_CEIL_RSHIFT(s->in.row_left, vsub) + s->in.off_lstep) * ileft->linesize[i] + FF_CEIL_RSHIFT(s->in.off_left * s->pixstep[i], hsub); | |
536 | in_off_right[i] = (FF_CEIL_RSHIFT(s->in.row_right, vsub) + s->in.off_rstep) * iright->linesize[i] + FF_CEIL_RSHIFT(s->in.off_right * s->pixstep[i], hsub); | |
537 | out_off_left[i] = (FF_CEIL_RSHIFT(s->out.row_left, vsub) + s->out.off_lstep) * oleft->linesize[i] + FF_CEIL_RSHIFT(s->out.off_left * s->pixstep[i], hsub); | |
538 | out_off_right[i] = (FF_CEIL_RSHIFT(s->out.row_right, vsub) + s->out.off_rstep) * oright->linesize[i] + FF_CEIL_RSHIFT(s->out.off_right * s->pixstep[i], hsub); | |
539 | } | |
540 | ||
541 | switch (s->out.format) { | |
542 | case ALTERNATING_LR: | |
543 | case ALTERNATING_RL: | |
544 | case SIDE_BY_SIDE_LR: | |
545 | case SIDE_BY_SIDE_RL: | |
546 | case SIDE_BY_SIDE_2_LR: | |
547 | case SIDE_BY_SIDE_2_RL: | |
548 | case ABOVE_BELOW_LR: | |
549 | case ABOVE_BELOW_RL: | |
550 | case ABOVE_BELOW_2_LR: | |
551 | case ABOVE_BELOW_2_RL: | |
552 | case INTERLEAVE_ROWS_LR: | |
553 | case INTERLEAVE_ROWS_RL: | |
554 | for (i = 0; i < s->nb_planes; i++) { | |
555 | av_image_copy_plane(oleft->data[i] + out_off_left[i], | |
556 | oleft->linesize[i] * s->row_step, | |
557 | ileft->data[i] + in_off_left[i], | |
558 | ileft->linesize[i] * s->row_step, | |
559 | s->linesize[i], s->pheight[i]); | |
560 | av_image_copy_plane(oright->data[i] + out_off_right[i], | |
561 | oright->linesize[i] * s->row_step, | |
562 | iright->data[i] + in_off_right[i], | |
563 | iright->linesize[i] * s->row_step, | |
564 | s->linesize[i], s->pheight[i]); | |
565 | } | |
566 | break; | |
567 | case MONO_L: | |
568 | iright = ileft; | |
569 | case MONO_R: | |
570 | for (i = 0; i < s->nb_planes; i++) { | |
571 | av_image_copy_plane(out->data[i], out->linesize[i], | |
572 | iright->data[i] + in_off_left[i], | |
573 | iright->linesize[i], | |
574 | s->linesize[i], s->pheight[i]); | |
575 | } | |
576 | break; | |
577 | case ANAGLYPH_RB_GRAY: | |
578 | case ANAGLYPH_RG_GRAY: | |
579 | case ANAGLYPH_RC_GRAY: | |
580 | case ANAGLYPH_RC_HALF: | |
581 | case ANAGLYPH_RC_COLOR: | |
582 | case ANAGLYPH_RC_DUBOIS: | |
583 | case ANAGLYPH_GM_GRAY: | |
584 | case ANAGLYPH_GM_HALF: | |
585 | case ANAGLYPH_GM_COLOR: | |
586 | case ANAGLYPH_GM_DUBOIS: | |
587 | case ANAGLYPH_YB_GRAY: | |
588 | case ANAGLYPH_YB_HALF: | |
589 | case ANAGLYPH_YB_COLOR: | |
590 | case ANAGLYPH_YB_DUBOIS: { | |
591 | int x, y, il, ir, o; | |
592 | const uint8_t *lsrc = ileft->data[0]; | |
593 | const uint8_t *rsrc = iright->data[0]; | |
594 | uint8_t *dst = out->data[0]; | |
595 | int out_width = s->out.width; | |
596 | const int **ana_matrix = s->ana_matrix; | |
597 | ||
598 | for (y = 0; y < s->out.height; y++) { | |
599 | o = out->linesize[0] * y; | |
600 | il = in_off_left[0] + y * ileft->linesize[0]; | |
601 | ir = in_off_right[0] + y * iright->linesize[0]; | |
602 | for (x = 0; x < out_width; x++, il += 3, ir += 3, o+= 3) { | |
603 | dst[o ] = ana_convert(ana_matrix[0], lsrc + il, rsrc + ir); | |
604 | dst[o + 1] = ana_convert(ana_matrix[1], lsrc + il, rsrc + ir); | |
605 | dst[o + 2] = ana_convert(ana_matrix[2], lsrc + il, rsrc + ir); | |
606 | } | |
607 | } | |
608 | break; | |
609 | } | |
610 | default: | |
611 | av_assert0(0); | |
612 | } | |
613 | ||
614 | av_frame_free(&inpicref); | |
615 | av_frame_free(&s->prev); | |
616 | if (oright != oleft) { | |
617 | if (s->out.format == ALTERNATING_LR) | |
618 | FFSWAP(AVFrame *, oleft, oright); | |
619 | oright->pts = outlink->frame_count * s->ts_unit; | |
620 | ff_filter_frame(outlink, oright); | |
621 | out = oleft; | |
622 | oleft->pts = outlink->frame_count * s->ts_unit; | |
623 | } else if (s->in.format == ALTERNATING_LR || | |
624 | s->in.format == ALTERNATING_RL) { | |
625 | out->pts = outlink->frame_count * s->ts_unit; | |
626 | } | |
627 | return ff_filter_frame(outlink, out); | |
628 | } | |
629 | ||
630 | static av_cold void uninit(AVFilterContext *ctx) | |
631 | { | |
632 | Stereo3DContext *s = ctx->priv; | |
633 | ||
634 | av_frame_free(&s->prev); | |
635 | } | |
636 | ||
637 | static const AVFilterPad stereo3d_inputs[] = { | |
638 | { | |
639 | .name = "default", | |
640 | .type = AVMEDIA_TYPE_VIDEO, | |
641 | .filter_frame = filter_frame, | |
642 | }, | |
643 | { NULL } | |
644 | }; | |
645 | ||
646 | static const AVFilterPad stereo3d_outputs[] = { | |
647 | { | |
648 | .name = "default", | |
649 | .type = AVMEDIA_TYPE_VIDEO, | |
650 | .config_props = config_output, | |
651 | }, | |
652 | { NULL } | |
653 | }; | |
654 | ||
655 | AVFilter ff_vf_stereo3d = { | |
656 | .name = "stereo3d", | |
657 | .description = NULL_IF_CONFIG_SMALL("Convert video stereoscopic 3D view."), | |
658 | .priv_size = sizeof(Stereo3DContext), | |
659 | .uninit = uninit, | |
660 | .query_formats = query_formats, | |
661 | .inputs = stereo3d_inputs, | |
662 | .outputs = stereo3d_outputs, | |
663 | .priv_class = &stereo3d_class, | |
664 | }; |