2 * Copyright (c) 2010 Gordon Schmidt <gordon.schmidt <at> s2000.tu-chemnitz.de>
3 * Copyright (c) 2013 Paul B Mahol
5 * This file is part of FFmpeg.
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.
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.
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
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"
28 #include "drawutils.h"
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
65 typedef struct StereoComponent
{
66 enum StereoCode format
;
68 int off_left
, off_right
;
69 int off_lstep
, off_rstep
;
70 int row_left
, row_right
;
73 static const int ana_coeff
[][3][6] = {
75 {{19595, 38470, 7471, 0, 0, 0},
77 { 0, 0, 0, 19595, 38470, 7471}},
79 {{19595, 38470, 7471, 0, 0, 0},
80 { 0, 0, 0, 19595, 38470, 7471},
83 {{19595, 38470, 7471, 0, 0, 0},
84 { 0, 0, 0, 19595, 38470, 7471},
85 { 0, 0, 0, 19595, 38470, 7471}},
87 {{19595, 38470, 7471, 0, 0, 0},
88 { 0, 0, 0, 0, 65536, 0},
89 { 0, 0, 0, 0, 0, 65536}},
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}},
99 {{ 0, 0, 0, 19595, 38470, 7471},
100 {19595, 38470, 7471, 0, 0, 0},
101 { 0, 0, 0, 19595, 38470, 7471}},
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}},
115 {{ 0, 0, 0, 19595, 38470, 7471},
116 { 0, 0, 0, 19595, 38470, 7471},
117 {19595, 38470, 7471, 0, 0, 0}},
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}},
132 typedef struct Stereo3DContext
{
133 const AVClass
*class;
134 StereoComponent in
, out
;
137 const int *ana_matrix
[3];
147 #define OFFSET(x) offsetof(Stereo3DContext, x)
148 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
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" },
194 AVFILTER_DEFINE_CLASS(stereo3d
);
196 static const enum AVPixelFormat anaglyph_pix_fmts
[] = {
197 AV_PIX_FMT_RGB24
, AV_PIX_FMT_BGR24
,
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
,
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
,
219 AV_PIX_FMT_YUV420P
, AV_PIX_FMT_YUVA420P
,
220 AV_PIX_FMT_YUV422P
, AV_PIX_FMT_YUVA422P
,
222 AV_PIX_FMT_YUV444P
, AV_PIX_FMT_YUVA444P
,
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
,
255 static int query_formats(AVFilterContext
*ctx
)
257 Stereo3DContext
*s
= ctx
->priv
;
258 const enum AVPixelFormat
*pix_fmts
;
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
;
278 pix_fmts
= other_pix_fmts
;
281 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
286 static int config_output(AVFilterLink
*outlink
)
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
);
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
:
303 av_log(ctx
, AV_LOG_ERROR
, "width must be even\n");
304 return AVERROR_INVALIDDATA
;
307 case ABOVE_BELOW_2_LR
:
309 case ABOVE_BELOW_2_RL
:
311 if (s
->out
.format
== INTERLEAVE_ROWS_LR
||
312 s
->out
.format
== INTERLEAVE_ROWS_RL
) {
314 av_log(ctx
, AV_LOG_ERROR
, "height must be multiple of 4\n");
315 return AVERROR_INVALIDDATA
;
319 av_log(ctx
, AV_LOG_ERROR
, "height must be even\n");
320 return AVERROR_INVALIDDATA
;
326 s
->width
= inlink
->w
;
328 s
->height
= inlink
->h
;
337 switch (s
->in
.format
) {
338 case SIDE_BY_SIDE_2_LR
:
340 case SIDE_BY_SIDE_LR
:
341 s
->width
= inlink
->w
/ 2;
342 s
->in
.off_right
= s
->width
;
344 case SIDE_BY_SIDE_2_RL
:
346 case SIDE_BY_SIDE_RL
:
347 s
->width
= inlink
->w
/ 2;
348 s
->in
.off_left
= s
->width
;
350 case ABOVE_BELOW_2_LR
:
354 s
->height
= inlink
->h
/ 2;
356 case ABOVE_BELOW_2_RL
:
360 s
->height
= inlink
->h
/ 2;
364 outlink
->flags
|= FF_LINK_FLAG_REQUEST_LOOP
;
369 av_log(ctx
, AV_LOG_ERROR
, "input format %d is not supported\n", s
->in
.format
);
370 return AVERROR(EINVAL
);
373 s
->out
.width
= s
->width
;
374 s
->out
.height
= s
->height
;
380 s
->out
.row_right
= 0;
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
: {
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];
405 case SIDE_BY_SIDE_2_LR
:
407 case SIDE_BY_SIDE_LR
:
408 s
->out
.width
= s
->width
* 2;
409 s
->out
.off_right
= s
->width
;
411 case SIDE_BY_SIDE_2_RL
:
413 case SIDE_BY_SIDE_RL
:
414 s
->out
.width
= s
->width
* 2;
415 s
->out
.off_left
= s
->width
;
417 case ABOVE_BELOW_2_LR
:
420 s
->out
.height
= s
->height
* 2;
421 s
->out
.row_right
= s
->height
;
423 case ABOVE_BELOW_2_RL
:
426 s
->out
.height
= s
->height
* 2;
427 s
->out
.row_left
= s
->height
;
429 case INTERLEAVE_ROWS_LR
:
431 s
->height
= s
->height
/ 2;
435 case INTERLEAVE_ROWS_RL
:
437 s
->height
= s
->height
/ 2;
442 s
->in
.off_left
= s
->in
.off_right
;
443 s
->in
.row_left
= s
->in
.row_right
;
452 av_log(ctx
, AV_LOG_ERROR
, "output format %d is not supported\n", s
->out
.format
);
453 return AVERROR(EINVAL
);
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
;
462 if ((ret
= av_image_fill_linesizes(s
->linesize
, outlink
->format
, s
->width
)) < 0)
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
;
475 static inline uint8_t ana_convert(const int *coeff
, const uint8_t *left
, const uint8_t *right
)
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
483 return av_clip_uint8(sum
>> 16);
486 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*inpicref
)
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];
496 switch (s
->in
.format
) {
505 if (s
->in
.format
== ALTERNATING_RL
)
506 FFSWAP(AVFrame
*, ileft
, iright
);
509 ileft
= iright
= inpicref
;
512 out
= oleft
= oright
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
514 av_frame_free(&s
->prev
);
515 av_frame_free(&inpicref
);
516 return AVERROR(ENOMEM
);
518 av_frame_copy_props(out
, inpicref
);
520 if (s
->out
.format
== ALTERNATING_LR
||
521 s
->out
.format
== ALTERNATING_RL
) {
522 oright
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
524 av_frame_free(&oleft
);
525 av_frame_free(&s
->prev
);
526 av_frame_free(&inpicref
);
527 return AVERROR(ENOMEM
);
529 av_frame_copy_props(oright
, inpicref
);
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
);
541 switch (s
->out
.format
) {
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
:
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
]);
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
],
574 s
->linesize
[i
], s
->pheight
[i
]);
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
: {
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
;
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
);
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
);
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
;
627 return ff_filter_frame(outlink
, out
);
630 static av_cold
void uninit(AVFilterContext
*ctx
)
632 Stereo3DContext
*s
= ctx
->priv
;
634 av_frame_free(&s
->prev
);
637 static const AVFilterPad stereo3d_inputs
[] = {
640 .type
= AVMEDIA_TYPE_VIDEO
,
641 .filter_frame
= filter_frame
,
646 static const AVFilterPad stereo3d_outputs
[] = {
649 .type
= AVMEDIA_TYPE_VIDEO
,
650 .config_props
= config_output
,
655 AVFilter ff_vf_stereo3d
= {
657 .description
= NULL_IF_CONFIG_SMALL("Convert video stereoscopic 3D view."),
658 .priv_size
= sizeof(Stereo3DContext
),
660 .query_formats
= query_formats
,
661 .inputs
= stereo3d_inputs
,
662 .outputs
= stereo3d_outputs
,
663 .priv_class
= &stereo3d_class
,