Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2010 Gordon Schmidt <gordon.schmidt <at> s2000.tu-chemnitz.de> | ||
3 | * Copyright (c) 2013-2015 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/intreadwrite.h" | ||
25 | #include "libavutil/opt.h" | ||
26 | #include "libavutil/parseutils.h" | ||
27 | #include "libavutil/pixdesc.h" | ||
28 | #include "avfilter.h" | ||
29 | #include "drawutils.h" | ||
30 | #include "filters.h" | ||
31 | #include "formats.h" | ||
32 | #include "video.h" | ||
33 | #include "stereo3d.h" | ||
34 | |||
35 | enum StereoCode { | ||
36 | ANAGLYPH_RC_GRAY, // anaglyph red/cyan gray | ||
37 | ANAGLYPH_RC_HALF, // anaglyph red/cyan half colored | ||
38 | ANAGLYPH_RC_COLOR, // anaglyph red/cyan colored | ||
39 | ANAGLYPH_RC_DUBOIS, // anaglyph red/cyan dubois | ||
40 | ANAGLYPH_GM_GRAY, // anaglyph green/magenta gray | ||
41 | ANAGLYPH_GM_HALF, // anaglyph green/magenta half colored | ||
42 | ANAGLYPH_GM_COLOR, // anaglyph green/magenta colored | ||
43 | ANAGLYPH_GM_DUBOIS, // anaglyph green/magenta dubois | ||
44 | ANAGLYPH_YB_GRAY, // anaglyph yellow/blue gray | ||
45 | ANAGLYPH_YB_HALF, // anaglyph yellow/blue half colored | ||
46 | ANAGLYPH_YB_COLOR, // anaglyph yellow/blue colored | ||
47 | ANAGLYPH_YB_DUBOIS, // anaglyph yellow/blue dubois | ||
48 | ANAGLYPH_RB_GRAY, // anaglyph red/blue gray | ||
49 | ANAGLYPH_RG_GRAY, // anaglyph red/green gray | ||
50 | MONO_L, // mono output for debugging (left eye only) | ||
51 | MONO_R, // mono output for debugging (right eye only) | ||
52 | INTERLEAVE_ROWS_LR, // row-interleave (left eye has top row) | ||
53 | INTERLEAVE_ROWS_RL, // row-interleave (right eye has top row) | ||
54 | SIDE_BY_SIDE_LR, // side by side parallel (left eye left, right eye right) | ||
55 | SIDE_BY_SIDE_RL, // side by side crosseye (right eye left, left eye right) | ||
56 | SIDE_BY_SIDE_2_LR, // side by side parallel with half width resolution | ||
57 | SIDE_BY_SIDE_2_RL, // side by side crosseye with half width resolution | ||
58 | ABOVE_BELOW_LR, // above-below (left eye above, right eye below) | ||
59 | ABOVE_BELOW_RL, // above-below (right eye above, left eye below) | ||
60 | ABOVE_BELOW_2_LR, // above-below with half height resolution | ||
61 | ABOVE_BELOW_2_RL, // above-below with half height resolution | ||
62 | ALTERNATING_LR, // alternating frames (left eye first, right eye second) | ||
63 | ALTERNATING_RL, // alternating frames (right eye first, left eye second) | ||
64 | CHECKERBOARD_LR, // checkerboard pattern (left eye first, right eye second) | ||
65 | CHECKERBOARD_RL, // checkerboard pattern (right eye first, left eye second) | ||
66 | INTERLEAVE_COLS_LR, // column-interleave (left eye first, right eye second) | ||
67 | INTERLEAVE_COLS_RL, // column-interleave (right eye first, left eye second) | ||
68 | HDMI, // HDMI frame pack (left eye first, right eye second) | ||
69 | STEREO_CODE_COUNT // TODO: needs autodetection | ||
70 | }; | ||
71 | |||
72 | typedef struct StereoComponent { | ||
73 | int format; ///< StereoCode | ||
74 | int width, height; | ||
75 | int off_left, off_right; | ||
76 | int off_lstep, off_rstep; | ||
77 | int row_left, row_right; | ||
78 | int row_step; | ||
79 | } StereoComponent; | ||
80 | |||
81 | static const int ana_coeff[][3][6] = { | ||
82 | [ANAGLYPH_RB_GRAY] = | ||
83 | {{19595, 38470, 7471, 0, 0, 0}, | ||
84 | { 0, 0, 0, 0, 0, 0}, | ||
85 | { 0, 0, 0, 19595, 38470, 7471}}, | ||
86 | [ANAGLYPH_RG_GRAY] = | ||
87 | {{19595, 38470, 7471, 0, 0, 0}, | ||
88 | { 0, 0, 0, 19595, 38470, 7471}, | ||
89 | { 0, 0, 0, 0, 0, 0}}, | ||
90 | [ANAGLYPH_RC_GRAY] = | ||
91 | {{19595, 38470, 7471, 0, 0, 0}, | ||
92 | { 0, 0, 0, 19595, 38470, 7471}, | ||
93 | { 0, 0, 0, 19595, 38470, 7471}}, | ||
94 | [ANAGLYPH_RC_HALF] = | ||
95 | {{19595, 38470, 7471, 0, 0, 0}, | ||
96 | { 0, 0, 0, 0, 65536, 0}, | ||
97 | { 0, 0, 0, 0, 0, 65536}}, | ||
98 | [ANAGLYPH_RC_COLOR] = | ||
99 | {{65536, 0, 0, 0, 0, 0}, | ||
100 | { 0, 0, 0, 0, 65536, 0}, | ||
101 | { 0, 0, 0, 0, 0, 65536}}, | ||
102 | [ANAGLYPH_RC_DUBOIS] = | ||
103 | {{29884, 32768, 11534, -2818, -5767, -131}, | ||
104 | {-2621, -2490, -1049, 24773, 48103, -1180}, | ||
105 | { -983, -1376, -328, -4719, -7406, 80347}}, | ||
106 | [ANAGLYPH_GM_GRAY] = | ||
107 | {{ 0, 0, 0, 19595, 38470, 7471}, | ||
108 | {19595, 38470, 7471, 0, 0, 0}, | ||
109 | { 0, 0, 0, 19595, 38470, 7471}}, | ||
110 | [ANAGLYPH_GM_HALF] = | ||
111 | {{ 0, 0, 0, 65536, 0, 0}, | ||
112 | {19595, 38470, 7471, 0, 0, 0}, | ||
113 | { 0, 0, 0, 0, 0, 65536}}, | ||
114 | [ANAGLYPH_GM_COLOR] = | ||
115 | {{ 0, 0, 0, 65536, 0, 0}, | ||
116 | { 0, 65536, 0, 0, 0, 0}, | ||
117 | { 0, 0, 0, 0, 0, 65536}}, | ||
118 | [ANAGLYPH_GM_DUBOIS] = | ||
119 | {{-4063,-10354, -2556, 34669, 46203, 1573}, | ||
120 | {18612, 43778, 9372, -1049, -983, -4260}, | ||
121 | { -983, -1769, 1376, 590, 4915, 61407}}, | ||
122 | [ANAGLYPH_YB_GRAY] = | ||
123 | {{ 0, 0, 0, 19595, 38470, 7471}, | ||
124 | { 0, 0, 0, 19595, 38470, 7471}, | ||
125 | {19595, 38470, 7471, 0, 0, 0}}, | ||
126 | [ANAGLYPH_YB_HALF] = | ||
127 | {{ 0, 0, 0, 65536, 0, 0}, | ||
128 | { 0, 0, 0, 0, 65536, 0}, | ||
129 | {19595, 38470, 7471, 0, 0, 0}}, | ||
130 | [ANAGLYPH_YB_COLOR] = | ||
131 | {{ 0, 0, 0, 65536, 0, 0}, | ||
132 | { 0, 0, 0, 0, 65536, 0}, | ||
133 | { 0, 0, 65536, 0, 0, 0}}, | ||
134 | [ANAGLYPH_YB_DUBOIS] = | ||
135 | {{69599,-13435,19595, -1048, -8061, -1114}, | ||
136 | {-1704, 59507, 4456, 393, 4063, -1114}, | ||
137 | {-2490,-11338, 1442, 6160, 12124, 59703}}, | ||
138 | }; | ||
139 | |||
140 | typedef struct Stereo3DContext { | ||
141 | const AVClass *class; | ||
142 | StereoComponent in, out; | ||
143 | int width, height; | ||
144 | const int *ana_matrix[3]; | ||
145 | int nb_planes; | ||
146 | int linesize[4]; | ||
147 | int pheight[4]; | ||
148 | int hsub, vsub; | ||
149 | int pixstep[4]; | ||
150 | AVFrame *prev; | ||
151 | int blanks; | ||
152 | int in_off_left[4], in_off_right[4]; | ||
153 | AVRational aspect; | ||
154 | Stereo3DDSPContext dsp; | ||
155 | } Stereo3DContext; | ||
156 | |||
157 | #define OFFSET(x) offsetof(Stereo3DContext, x) | ||
158 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM | ||
159 | |||
160 | static const AVOption stereo3d_options[] = { | ||
161 | { "in", "set input format", OFFSET(in.format), AV_OPT_TYPE_INT, {.i64=SIDE_BY_SIDE_LR}, INTERLEAVE_ROWS_LR, STEREO_CODE_COUNT-1, FLAGS, .unit = "in"}, | ||
162 | { "ab2l", "above below half height left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_LR}, 0, 0, FLAGS, .unit = "in" }, | ||
163 | { "tb2l", "above below half height left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_LR}, 0, 0, FLAGS, .unit = "in" }, | ||
164 | { "ab2r", "above below half height right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_RL}, 0, 0, FLAGS, .unit = "in" }, | ||
165 | { "tb2r", "above below half height right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_RL}, 0, 0, FLAGS, .unit = "in" }, | ||
166 | { "abl", "above below left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_LR}, 0, 0, FLAGS, .unit = "in" }, | ||
167 | { "tbl", "above below left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_LR}, 0, 0, FLAGS, .unit = "in" }, | ||
168 | { "abr", "above below right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_RL}, 0, 0, FLAGS, .unit = "in" }, | ||
169 | { "tbr", "above below right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_RL}, 0, 0, FLAGS, .unit = "in" }, | ||
170 | { "al", "alternating frames left first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_LR}, 0, 0, FLAGS, .unit = "in" }, | ||
171 | { "ar", "alternating frames right first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_RL}, 0, 0, FLAGS, .unit = "in" }, | ||
172 | { "sbs2l", "side by side half width left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_LR}, 0, 0, FLAGS, .unit = "in" }, | ||
173 | { "sbs2r", "side by side half width right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_RL}, 0, 0, FLAGS, .unit = "in" }, | ||
174 | { "sbsl", "side by side left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_LR}, 0, 0, FLAGS, .unit = "in" }, | ||
175 | { "sbsr", "side by side right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_RL}, 0, 0, FLAGS, .unit = "in" }, | ||
176 | { "irl", "interleave rows left first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_ROWS_LR}, 0, 0, FLAGS, .unit = "in" }, | ||
177 | { "irr", "interleave rows right first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_ROWS_RL}, 0, 0, FLAGS, .unit = "in" }, | ||
178 | { "icl", "interleave columns left first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_COLS_LR}, 0, 0, FLAGS, .unit = "in" }, | ||
179 | { "icr", "interleave columns right first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_COLS_RL}, 0, 0, FLAGS, .unit = "in" }, | ||
180 | { "out", "set output format", OFFSET(out.format), AV_OPT_TYPE_INT, {.i64=ANAGLYPH_RC_DUBOIS}, 0, STEREO_CODE_COUNT-1, FLAGS, .unit = "out"}, | ||
181 | { "ab2l", "above below half height left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_LR}, 0, 0, FLAGS, .unit = "out" }, | ||
182 | { "tb2l", "above below half height left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_LR}, 0, 0, FLAGS, .unit = "out" }, | ||
183 | { "ab2r", "above below half height right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_RL}, 0, 0, FLAGS, .unit = "out" }, | ||
184 | { "tb2r", "above below half height right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_RL}, 0, 0, FLAGS, .unit = "out" }, | ||
185 | { "abl", "above below left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_LR}, 0, 0, FLAGS, .unit = "out" }, | ||
186 | { "tbl", "above below left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_LR}, 0, 0, FLAGS, .unit = "out" }, | ||
187 | { "abr", "above below right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_RL}, 0, 0, FLAGS, .unit = "out" }, | ||
188 | { "tbr", "above below right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_RL}, 0, 0, FLAGS, .unit = "out" }, | ||
189 | { "agmc", "anaglyph green magenta color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_COLOR}, 0, 0, FLAGS, .unit = "out" }, | ||
190 | { "agmd", "anaglyph green magenta dubois", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_DUBOIS}, 0, 0, FLAGS, .unit = "out" }, | ||
191 | { "agmg", "anaglyph green magenta gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_GRAY}, 0, 0, FLAGS, .unit = "out" }, | ||
192 | { "agmh", "anaglyph green magenta half color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_HALF}, 0, 0, FLAGS, .unit = "out" }, | ||
193 | { "al", "alternating frames left first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_LR}, 0, 0, FLAGS, .unit = "out" }, | ||
194 | { "ar", "alternating frames right first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_RL}, 0, 0, FLAGS, .unit = "out" }, | ||
195 | { "arbg", "anaglyph red blue gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RB_GRAY}, 0, 0, FLAGS, .unit = "out" }, | ||
196 | { "arcc", "anaglyph red cyan color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_COLOR}, 0, 0, FLAGS, .unit = "out" }, | ||
197 | { "arcd", "anaglyph red cyan dubois", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_DUBOIS}, 0, 0, FLAGS, .unit = "out" }, | ||
198 | { "arcg", "anaglyph red cyan gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_GRAY}, 0, 0, FLAGS, .unit = "out" }, | ||
199 | { "arch", "anaglyph red cyan half color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_HALF}, 0, 0, FLAGS, .unit = "out" }, | ||
200 | { "argg", "anaglyph red green gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RG_GRAY}, 0, 0, FLAGS, .unit = "out" }, | ||
201 | { "aybc", "anaglyph yellow blue color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_COLOR}, 0, 0, FLAGS, .unit = "out" }, | ||
202 | { "aybd", "anaglyph yellow blue dubois", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_DUBOIS}, 0, 0, FLAGS, .unit = "out" }, | ||
203 | { "aybg", "anaglyph yellow blue gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_GRAY}, 0, 0, FLAGS, .unit = "out" }, | ||
204 | { "aybh", "anaglyph yellow blue half color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_HALF}, 0, 0, FLAGS, .unit = "out" }, | ||
205 | { "irl", "interleave rows left first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_ROWS_LR}, 0, 0, FLAGS, .unit = "out" }, | ||
206 | { "irr", "interleave rows right first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_ROWS_RL}, 0, 0, FLAGS, .unit = "out" }, | ||
207 | { "ml", "mono left", 0, AV_OPT_TYPE_CONST, {.i64=MONO_L}, 0, 0, FLAGS, .unit = "out" }, | ||
208 | { "mr", "mono right", 0, AV_OPT_TYPE_CONST, {.i64=MONO_R}, 0, 0, FLAGS, .unit = "out" }, | ||
209 | { "sbs2l", "side by side half width left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_LR}, 0, 0, FLAGS, .unit = "out" }, | ||
210 | { "sbs2r", "side by side half width right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_RL}, 0, 0, FLAGS, .unit = "out" }, | ||
211 | { "sbsl", "side by side left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_LR}, 0, 0, FLAGS, .unit = "out" }, | ||
212 | { "sbsr", "side by side right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_RL}, 0, 0, FLAGS, .unit = "out" }, | ||
213 | { "chl", "checkerboard left first", 0, AV_OPT_TYPE_CONST, {.i64=CHECKERBOARD_LR}, 0, 0, FLAGS, .unit = "out" }, | ||
214 | { "chr", "checkerboard right first", 0, AV_OPT_TYPE_CONST, {.i64=CHECKERBOARD_RL}, 0, 0, FLAGS, .unit = "out" }, | ||
215 | { "icl", "interleave columns left first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_COLS_LR}, 0, 0, FLAGS, .unit = "out" }, | ||
216 | { "icr", "interleave columns right first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_COLS_RL}, 0, 0, FLAGS, .unit = "out" }, | ||
217 | { "hdmi", "HDMI frame pack", 0, AV_OPT_TYPE_CONST, {.i64=HDMI}, 0, 0, FLAGS, .unit = "out" }, | ||
218 | { NULL } | ||
219 | }; | ||
220 | |||
221 | AVFILTER_DEFINE_CLASS(stereo3d); | ||
222 | |||
223 | static const enum AVPixelFormat anaglyph_pix_fmts[] = { | ||
224 | AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, | ||
225 | AV_PIX_FMT_NONE | ||
226 | }; | ||
227 | |||
228 | static const enum AVPixelFormat other_pix_fmts[] = { | ||
229 | AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, | ||
230 | AV_PIX_FMT_RGB48BE, AV_PIX_FMT_BGR48BE, | ||
231 | AV_PIX_FMT_RGB48LE, AV_PIX_FMT_BGR48LE, | ||
232 | AV_PIX_FMT_RGBA64BE, AV_PIX_FMT_BGRA64BE, | ||
233 | AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_BGRA64LE, | ||
234 | AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, | ||
235 | AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, | ||
236 | AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, | ||
237 | AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR, | ||
238 | AV_PIX_FMT_GBRP, | ||
239 | AV_PIX_FMT_GBRP9BE, AV_PIX_FMT_GBRP9LE, | ||
240 | AV_PIX_FMT_GBRP10BE, AV_PIX_FMT_GBRP10LE, | ||
241 | AV_PIX_FMT_GBRP12BE, AV_PIX_FMT_GBRP12LE, | ||
242 | AV_PIX_FMT_GBRP14BE, AV_PIX_FMT_GBRP14LE, | ||
243 | AV_PIX_FMT_GBRP16BE, AV_PIX_FMT_GBRP16LE, | ||
244 | AV_PIX_FMT_YUV410P, | ||
245 | AV_PIX_FMT_YUV411P, | ||
246 | AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, | ||
247 | AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, | ||
248 | AV_PIX_FMT_YUV440P, | ||
249 | AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, | ||
250 | AV_PIX_FMT_YUVJ411P, | ||
251 | AV_PIX_FMT_YUVJ420P, | ||
252 | AV_PIX_FMT_YUVJ422P, | ||
253 | AV_PIX_FMT_YUVJ440P, | ||
254 | AV_PIX_FMT_YUVJ444P, | ||
255 | AV_PIX_FMT_YUV420P9LE, AV_PIX_FMT_YUVA420P9LE, | ||
256 | AV_PIX_FMT_YUV420P9BE, AV_PIX_FMT_YUVA420P9BE, | ||
257 | AV_PIX_FMT_YUV422P9LE, AV_PIX_FMT_YUVA422P9LE, | ||
258 | AV_PIX_FMT_YUV422P9BE, AV_PIX_FMT_YUVA422P9BE, | ||
259 | AV_PIX_FMT_YUV444P9LE, AV_PIX_FMT_YUVA444P9LE, | ||
260 | AV_PIX_FMT_YUV444P9BE, AV_PIX_FMT_YUVA444P9BE, | ||
261 | AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUVA420P10LE, | ||
262 | AV_PIX_FMT_YUV420P10BE, AV_PIX_FMT_YUVA420P10BE, | ||
263 | AV_PIX_FMT_YUV422P10LE, AV_PIX_FMT_YUVA422P10LE, | ||
264 | AV_PIX_FMT_YUV422P10BE, AV_PIX_FMT_YUVA422P10BE, | ||
265 | AV_PIX_FMT_YUV444P10LE, AV_PIX_FMT_YUVA444P10LE, | ||
266 | AV_PIX_FMT_YUV444P10BE, AV_PIX_FMT_YUVA444P10BE, | ||
267 | AV_PIX_FMT_YUV420P12BE, AV_PIX_FMT_YUV420P12LE, | ||
268 | AV_PIX_FMT_YUV422P12BE, AV_PIX_FMT_YUV422P12LE, | ||
269 | AV_PIX_FMT_YUV444P12BE, AV_PIX_FMT_YUV444P12LE, | ||
270 | AV_PIX_FMT_YUV420P14BE, AV_PIX_FMT_YUV420P14LE, | ||
271 | AV_PIX_FMT_YUV422P14BE, AV_PIX_FMT_YUV422P14LE, | ||
272 | AV_PIX_FMT_YUV444P14BE, AV_PIX_FMT_YUV444P14LE, | ||
273 | AV_PIX_FMT_YUV420P16LE, AV_PIX_FMT_YUVA420P16LE, | ||
274 | AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_YUVA420P16BE, | ||
275 | AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUVA422P16LE, | ||
276 | AV_PIX_FMT_YUV422P16BE, AV_PIX_FMT_YUVA422P16BE, | ||
277 | AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUVA444P16LE, | ||
278 | AV_PIX_FMT_YUV444P16BE, AV_PIX_FMT_YUVA444P16BE, | ||
279 | AV_PIX_FMT_NONE | ||
280 | }; | ||
281 | |||
282 | 22 | static int query_formats(const AVFilterContext *ctx, | |
283 | AVFilterFormatsConfig **cfg_in, | ||
284 | AVFilterFormatsConfig **cfg_out) | ||
285 | { | ||
286 | 22 | const Stereo3DContext *s = ctx->priv; | |
287 | const enum AVPixelFormat *pix_fmts; | ||
288 | |||
289 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 8 times.
|
22 | switch (s->out.format) { |
290 | 14 | case ANAGLYPH_GM_COLOR: | |
291 | case ANAGLYPH_GM_DUBOIS: | ||
292 | case ANAGLYPH_GM_GRAY: | ||
293 | case ANAGLYPH_GM_HALF: | ||
294 | case ANAGLYPH_RB_GRAY: | ||
295 | case ANAGLYPH_RC_COLOR: | ||
296 | case ANAGLYPH_RC_DUBOIS: | ||
297 | case ANAGLYPH_RC_GRAY: | ||
298 | case ANAGLYPH_RC_HALF: | ||
299 | case ANAGLYPH_RG_GRAY: | ||
300 | case ANAGLYPH_YB_COLOR: | ||
301 | case ANAGLYPH_YB_DUBOIS: | ||
302 | case ANAGLYPH_YB_GRAY: | ||
303 | case ANAGLYPH_YB_HALF: | ||
304 | 14 | pix_fmts = anaglyph_pix_fmts; | |
305 | 14 | break; | |
306 | 8 | default: | |
307 | 8 | pix_fmts = other_pix_fmts; | |
308 | } | ||
309 | |||
310 | 22 | return ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, pix_fmts); | |
311 | } | ||
312 | |||
313 | 10644480 | static inline uint8_t ana_convert(const int *coeff, const uint8_t *left, const uint8_t *right) | |
314 | { | ||
315 | int sum; | ||
316 | |||
317 | 10644480 | sum = coeff[0] * left[0] + coeff[3] * right[0]; //red in | |
318 | 10644480 | sum += coeff[1] * left[1] + coeff[4] * right[1]; //green in | |
319 | 10644480 | sum += coeff[2] * left[2] + coeff[5] * right[2]; //blue in | |
320 | |||
321 | 10644480 | return av_clip_uint8(sum >> 16); | |
322 | } | ||
323 | |||
324 | ✗ | static void anaglyph_ic(uint8_t *dst, uint8_t *lsrc, uint8_t *rsrc, | |
325 | ptrdiff_t dst_linesize, ptrdiff_t l_linesize, ptrdiff_t r_linesize, | ||
326 | int width, int height, | ||
327 | const int *ana_matrix_r, const int *ana_matrix_g, const int *ana_matrix_b) | ||
328 | { | ||
329 | int x, y, o; | ||
330 | |||
331 | ✗ | for (y = 0; y < height; y++) { | |
332 | ✗ | for (o = 0, x = 0; x < width; x++, o+= 3) { | |
333 | ✗ | dst[o ] = ana_convert(ana_matrix_r, lsrc + o * 2, rsrc + o * 2); | |
334 | ✗ | dst[o + 1] = ana_convert(ana_matrix_g, lsrc + o * 2, rsrc + o * 2); | |
335 | ✗ | dst[o + 2] = ana_convert(ana_matrix_b, lsrc + o * 2, rsrc + o * 2); | |
336 | } | ||
337 | |||
338 | ✗ | dst += dst_linesize; | |
339 | ✗ | lsrc += l_linesize; | |
340 | ✗ | rsrc += r_linesize; | |
341 | } | ||
342 | ✗ | } | |
343 | |||
344 | 630 | static void anaglyph(uint8_t *dst, uint8_t *lsrc, uint8_t *rsrc, | |
345 | ptrdiff_t dst_linesize, ptrdiff_t l_linesize, ptrdiff_t r_linesize, | ||
346 | int width, int height, | ||
347 | const int *ana_matrix_r, const int *ana_matrix_g, const int *ana_matrix_b) | ||
348 | { | ||
349 | int x, y, o; | ||
350 | |||
351 |
2/2✓ Branch 0 taken 20160 times.
✓ Branch 1 taken 630 times.
|
20790 | for (y = 0; y < height; y++) { |
352 |
2/2✓ Branch 0 taken 3548160 times.
✓ Branch 1 taken 20160 times.
|
3568320 | for (o = 0, x = 0; x < width; x++, o+= 3) { |
353 | 3548160 | dst[o ] = ana_convert(ana_matrix_r, lsrc + o, rsrc + o); | |
354 | 3548160 | dst[o + 1] = ana_convert(ana_matrix_g, lsrc + o, rsrc + o); | |
355 | 3548160 | dst[o + 2] = ana_convert(ana_matrix_b, lsrc + o, rsrc + o); | |
356 | } | ||
357 | |||
358 | 20160 | dst += dst_linesize; | |
359 | 20160 | lsrc += l_linesize; | |
360 | 20160 | rsrc += r_linesize; | |
361 | } | ||
362 | 630 | } | |
363 | |||
364 | 22 | static int config_output(AVFilterLink *outlink) | |
365 | { | ||
366 | 22 | AVFilterContext *ctx = outlink->src; | |
367 | 22 | AVFilterLink *inlink = ctx->inputs[0]; | |
368 | 22 | Stereo3DContext *s = ctx->priv; | |
369 | 22 | FilterLink *il = ff_filter_link(inlink); | |
370 | 22 | FilterLink *ol = ff_filter_link(outlink); | |
371 | 22 | AVRational fps = il->frame_rate; | |
372 | 22 | AVRational tb = inlink->time_base; | |
373 | 22 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); | |
374 | int ret; | ||
375 | 22 | s->aspect = inlink->sample_aspect_ratio; | |
376 | |||
377 |
3/3✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
22 | switch (s->in.format) { |
378 | 18 | case INTERLEAVE_COLS_LR: | |
379 | case INTERLEAVE_COLS_RL: | ||
380 | case SIDE_BY_SIDE_2_LR: | ||
381 | case SIDE_BY_SIDE_LR: | ||
382 | case SIDE_BY_SIDE_2_RL: | ||
383 | case SIDE_BY_SIDE_RL: | ||
384 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (inlink->w & 1) { |
385 | ✗ | av_log(ctx, AV_LOG_ERROR, "width must be even\n"); | |
386 | ✗ | return AVERROR_INVALIDDATA; | |
387 | } | ||
388 | 18 | break; | |
389 | 2 | case INTERLEAVE_ROWS_LR: | |
390 | case INTERLEAVE_ROWS_RL: | ||
391 | case ABOVE_BELOW_2_LR: | ||
392 | case ABOVE_BELOW_LR: | ||
393 | case ABOVE_BELOW_2_RL: | ||
394 | case ABOVE_BELOW_RL: | ||
395 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (inlink->h & 1) { |
396 | ✗ | av_log(ctx, AV_LOG_ERROR, "height must be even\n"); | |
397 | ✗ | return AVERROR_INVALIDDATA; | |
398 | } | ||
399 | 2 | break; | |
400 | } | ||
401 | |||
402 | 22 | s->in.width = | |
403 | 22 | s->width = inlink->w; | |
404 | 22 | s->in.height = | |
405 | 22 | s->height = inlink->h; | |
406 | 22 | s->in.off_lstep = | |
407 | 22 | s->in.off_rstep = | |
408 | 22 | s->in.off_left = | |
409 | 22 | s->in.off_right = | |
410 | 22 | s->in.row_left = | |
411 | 22 | s->in.row_right = 0; | |
412 | 22 | s->in.row_step = 1; | |
413 | |||
414 |
3/12✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
22 | switch (s->in.format) { |
415 | ✗ | case SIDE_BY_SIDE_2_LR: | |
416 | ✗ | s->aspect.num *= 2; | |
417 | 18 | case SIDE_BY_SIDE_LR: | |
418 | 18 | s->width = inlink->w / 2; | |
419 | 18 | s->in.off_right = s->width; | |
420 | 18 | break; | |
421 | ✗ | case SIDE_BY_SIDE_2_RL: | |
422 | ✗ | s->aspect.num *= 2; | |
423 | ✗ | case SIDE_BY_SIDE_RL: | |
424 | ✗ | s->width = inlink->w / 2; | |
425 | ✗ | s->in.off_left = s->width; | |
426 | ✗ | break; | |
427 | ✗ | case ABOVE_BELOW_2_LR: | |
428 | ✗ | s->aspect.den *= 2; | |
429 | ✗ | case ABOVE_BELOW_LR: | |
430 | ✗ | s->in.row_right = | |
431 | ✗ | s->height = inlink->h / 2; | |
432 | ✗ | break; | |
433 | ✗ | case ABOVE_BELOW_2_RL: | |
434 | ✗ | s->aspect.den *= 2; | |
435 | 2 | case ABOVE_BELOW_RL: | |
436 | 2 | s->in.row_left = | |
437 | 2 | s->height = inlink->h / 2; | |
438 | 2 | break; | |
439 | 2 | case ALTERNATING_RL: | |
440 | case ALTERNATING_LR: | ||
441 | 2 | fps.den *= 2; | |
442 | 2 | tb.num *= 2; | |
443 | 2 | break; | |
444 | ✗ | case INTERLEAVE_COLS_RL: | |
445 | case INTERLEAVE_COLS_LR: | ||
446 | ✗ | s->width = inlink->w / 2; | |
447 | ✗ | break; | |
448 | ✗ | case INTERLEAVE_ROWS_LR: | |
449 | case INTERLEAVE_ROWS_RL: | ||
450 | ✗ | s->in.row_step = 2; | |
451 | ✗ | if (s->in.format == INTERLEAVE_ROWS_RL) | |
452 | ✗ | s->in.off_lstep = 1; | |
453 | else | ||
454 | ✗ | s->in.off_rstep = 1; | |
455 | ✗ | if (s->out.format != CHECKERBOARD_LR && | |
456 | ✗ | s->out.format != CHECKERBOARD_RL) | |
457 | ✗ | s->height = inlink->h / 2; | |
458 | ✗ | break; | |
459 | ✗ | default: | |
460 | ✗ | av_log(ctx, AV_LOG_ERROR, "input format %d is not supported\n", s->in.format); | |
461 | ✗ | return AVERROR(EINVAL); | |
462 | } | ||
463 | |||
464 | 22 | s->out.width = s->width; | |
465 | 22 | s->out.height = s->height; | |
466 | 22 | s->out.off_lstep = | |
467 | 22 | s->out.off_rstep = | |
468 | 22 | s->out.off_left = | |
469 | 22 | s->out.off_right = | |
470 | 22 | s->out.row_left = | |
471 | 22 | s->out.row_right = 0; | |
472 | 22 | s->out.row_step = 1; | |
473 | |||
474 |
8/17✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
22 | switch (s->out.format) { |
475 | 14 | case ANAGLYPH_RB_GRAY: | |
476 | case ANAGLYPH_RG_GRAY: | ||
477 | case ANAGLYPH_RC_GRAY: | ||
478 | case ANAGLYPH_RC_HALF: | ||
479 | case ANAGLYPH_RC_COLOR: | ||
480 | case ANAGLYPH_RC_DUBOIS: | ||
481 | case ANAGLYPH_GM_GRAY: | ||
482 | case ANAGLYPH_GM_HALF: | ||
483 | case ANAGLYPH_GM_COLOR: | ||
484 | case ANAGLYPH_GM_DUBOIS: | ||
485 | case ANAGLYPH_YB_GRAY: | ||
486 | case ANAGLYPH_YB_HALF: | ||
487 | case ANAGLYPH_YB_COLOR: | ||
488 | case ANAGLYPH_YB_DUBOIS: { | ||
489 | uint8_t rgba_map[4]; | ||
490 | |||
491 | 14 | ff_fill_rgba_map(rgba_map, outlink->format); | |
492 | 14 | s->ana_matrix[rgba_map[0]] = &ana_coeff[s->out.format][0][0]; | |
493 | 14 | s->ana_matrix[rgba_map[1]] = &ana_coeff[s->out.format][1][0]; | |
494 | 14 | s->ana_matrix[rgba_map[2]] = &ana_coeff[s->out.format][2][0]; | |
495 | 14 | break; | |
496 | } | ||
497 | ✗ | case SIDE_BY_SIDE_2_LR: | |
498 | ✗ | s->aspect.den *= 2; | |
499 | 1 | case SIDE_BY_SIDE_LR: | |
500 | 1 | s->out.width = s->width * 2; | |
501 | 1 | s->out.off_right = s->width; | |
502 | 1 | break; | |
503 | ✗ | case SIDE_BY_SIDE_2_RL: | |
504 | ✗ | s->aspect.den *= 2; | |
505 | 1 | case SIDE_BY_SIDE_RL: | |
506 | 1 | s->out.width = s->width * 2; | |
507 | 1 | s->out.off_left = s->width; | |
508 | 1 | break; | |
509 | ✗ | case ABOVE_BELOW_2_LR: | |
510 | ✗ | s->aspect.num *= 2; | |
511 | 2 | case ABOVE_BELOW_LR: | |
512 | 2 | s->out.height = s->height * 2; | |
513 | 2 | s->out.row_right = s->height; | |
514 | 2 | break; | |
515 | ✗ | case HDMI: | |
516 | ✗ | if (s->height != 720 && s->height != 1080) { | |
517 | ✗ | av_log(ctx, AV_LOG_ERROR, "Only 720 and 1080 height supported\n"); | |
518 | ✗ | return AVERROR(EINVAL); | |
519 | } | ||
520 | |||
521 | ✗ | s->blanks = s->height / 24; | |
522 | ✗ | s->out.height = s->height * 2 + s->blanks; | |
523 | ✗ | s->out.row_right = s->height + s->blanks; | |
524 | ✗ | break; | |
525 | ✗ | case ABOVE_BELOW_2_RL: | |
526 | ✗ | s->aspect.num *= 2; | |
527 | 1 | case ABOVE_BELOW_RL: | |
528 | 1 | s->out.height = s->height * 2; | |
529 | 1 | s->out.row_left = s->height; | |
530 | 1 | break; | |
531 | ✗ | case INTERLEAVE_ROWS_LR: | |
532 | ✗ | s->in.row_step = 1 + (s->in.format == INTERLEAVE_ROWS_RL); | |
533 | ✗ | s->out.row_step = 2; | |
534 | ✗ | s->out.height = s->height * 2; | |
535 | ✗ | s->out.off_rstep = 1; | |
536 | ✗ | break; | |
537 | ✗ | case INTERLEAVE_ROWS_RL: | |
538 | ✗ | s->in.row_step = 1 + (s->in.format == INTERLEAVE_ROWS_LR); | |
539 | ✗ | s->out.row_step = 2; | |
540 | ✗ | s->out.height = s->height * 2; | |
541 | ✗ | s->out.off_lstep = 1; | |
542 | ✗ | break; | |
543 | 1 | case MONO_R: | |
544 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (s->in.format != INTERLEAVE_COLS_LR) { |
545 | 1 | s->in.off_left = s->in.off_right; | |
546 | 1 | s->in.row_left = s->in.row_right; | |
547 | } | ||
548 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (s->in.format == INTERLEAVE_ROWS_LR) |
549 | ✗ | FFSWAP(int, s->in.off_lstep, s->in.off_rstep); | |
550 | 1 | break; | |
551 | 1 | case MONO_L: | |
552 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (s->in.format == INTERLEAVE_ROWS_RL) |
553 | ✗ | FFSWAP(int, s->in.off_lstep, s->in.off_rstep); | |
554 | 1 | break; | |
555 | 1 | case ALTERNATING_RL: | |
556 | case ALTERNATING_LR: | ||
557 | 1 | fps.num *= 2; | |
558 | 1 | tb.den *= 2; | |
559 | 1 | break; | |
560 | ✗ | case CHECKERBOARD_LR: | |
561 | case CHECKERBOARD_RL: | ||
562 | case INTERLEAVE_COLS_LR: | ||
563 | case INTERLEAVE_COLS_RL: | ||
564 | ✗ | s->out.width = s->width * 2; | |
565 | ✗ | break; | |
566 | ✗ | default: | |
567 | ✗ | av_log(ctx, AV_LOG_ERROR, "output format %d is not supported\n", s->out.format); | |
568 | ✗ | return AVERROR(EINVAL); | |
569 | } | ||
570 | |||
571 |
2/4✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
|
22 | if (s->in.format == INTERLEAVE_COLS_LR || s->in.format == INTERLEAVE_COLS_RL) { |
572 | ✗ | if ((s->in.format & 1) != (s->out.format & 1)) { | |
573 | ✗ | FFSWAP(int, s->in.row_left, s->in.row_right); | |
574 | ✗ | FFSWAP(int, s->in.off_lstep, s->in.off_rstep); | |
575 | ✗ | FFSWAP(int, s->in.off_left, s->in.off_right); | |
576 | ✗ | FFSWAP(int, s->out.row_left, s->out.row_right); | |
577 | ✗ | FFSWAP(int, s->out.off_lstep, s->out.off_rstep); | |
578 | ✗ | FFSWAP(int, s->out.off_left, s->out.off_right); | |
579 | } | ||
580 | } | ||
581 | |||
582 | 22 | outlink->w = s->out.width; | |
583 | 22 | outlink->h = s->out.height; | |
584 | 22 | ol->frame_rate = fps; | |
585 | 22 | outlink->time_base = tb; | |
586 | 22 | outlink->sample_aspect_ratio = s->aspect; | |
587 | |||
588 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
|
22 | if ((ret = av_image_fill_linesizes(s->linesize, outlink->format, s->width)) < 0) |
589 | ✗ | return ret; | |
590 | 22 | s->nb_planes = av_pix_fmt_count_planes(outlink->format); | |
591 | 22 | av_image_fill_max_pixsteps(s->pixstep, NULL, desc); | |
592 | 22 | s->pheight[1] = s->pheight[2] = AV_CEIL_RSHIFT(s->height, desc->log2_chroma_h); | |
593 | 22 | s->pheight[0] = s->pheight[3] = s->height; | |
594 | 22 | s->hsub = desc->log2_chroma_w; | |
595 | 22 | s->vsub = desc->log2_chroma_h; | |
596 | |||
597 | 22 | s->dsp.anaglyph = anaglyph; | |
598 | #if ARCH_X86 | ||
599 | 22 | ff_stereo3d_init_x86(&s->dsp); | |
600 | #endif | ||
601 | |||
602 | 22 | return 0; | |
603 | } | ||
604 | |||
605 | typedef struct ThreadData { | ||
606 | AVFrame *ileft, *iright; | ||
607 | AVFrame *out; | ||
608 | } ThreadData; | ||
609 | |||
610 | 630 | static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | |
611 | { | ||
612 | 630 | Stereo3DContext *s = ctx->priv; | |
613 | 630 | ThreadData *td = arg; | |
614 | 630 | AVFrame *ileft = td->ileft; | |
615 | 630 | AVFrame *iright = td->iright; | |
616 | 630 | AVFrame *out = td->out; | |
617 | 630 | int height = s->out.height; | |
618 | 630 | int start = (height * jobnr ) / nb_jobs; | |
619 | 630 | int end = (height * (jobnr+1)) / nb_jobs; | |
620 | 630 | const int **ana_matrix = s->ana_matrix; | |
621 | |||
622 | 630 | s->dsp.anaglyph(out->data[0] + out->linesize[0] * start, | |
623 | 630 | ileft ->data[0] + s->in_off_left [0] + ileft->linesize[0] * start * s->in.row_step, | |
624 | 630 | iright->data[0] + s->in_off_right[0] + iright->linesize[0] * start * s->in.row_step, | |
625 | 630 | out->linesize[0], | |
626 | 630 | ileft->linesize[0] * s->in.row_step, | |
627 | 630 | iright->linesize[0] * s->in.row_step, | |
628 | s->out.width, end - start, | ||
629 | 630 | ana_matrix[0], ana_matrix[1], ana_matrix[2]); | |
630 | |||
631 | 630 | return 0; | |
632 | } | ||
633 | |||
634 | ✗ | static void interleave_cols_to_any(Stereo3DContext *s, int *out_off, int p, AVFrame *in, AVFrame *out, int d) | |
635 | { | ||
636 | int y, x; | ||
637 | |||
638 | ✗ | for (y = 0; y < s->pheight[p]; y++) { | |
639 | ✗ | const uint8_t *src = (const uint8_t*)in->data[p] + y * in->linesize[p] + d * s->pixstep[p]; | |
640 | ✗ | uint8_t *dst = out->data[p] + out_off[p] + y * out->linesize[p] * s->out.row_step; | |
641 | |||
642 | ✗ | switch (s->pixstep[p]) { | |
643 | ✗ | case 1: | |
644 | ✗ | for (x = 0; x < s->linesize[p]; x++) | |
645 | ✗ | dst[x] = src[x * 2]; | |
646 | ✗ | break; | |
647 | ✗ | case 2: | |
648 | ✗ | for (x = 0; x < s->linesize[p]; x+=2) | |
649 | ✗ | AV_WN16(&dst[x], AV_RN16(&src[x * 2])); | |
650 | ✗ | break; | |
651 | ✗ | case 3: | |
652 | ✗ | for (x = 0; x < s->linesize[p]; x+=3) | |
653 | ✗ | AV_WB24(&dst[x], AV_RB24(&src[x * 2])); | |
654 | ✗ | break; | |
655 | ✗ | case 4: | |
656 | ✗ | for (x = 0; x < s->linesize[p]; x+=4) | |
657 | ✗ | AV_WN32(&dst[x], AV_RN32(&src[x * 2])); | |
658 | ✗ | break; | |
659 | ✗ | case 6: | |
660 | ✗ | for (x = 0; x < s->linesize[p]; x+=6) | |
661 | ✗ | AV_WB48(&dst[x], AV_RB48(&src[x * 2])); | |
662 | ✗ | break; | |
663 | ✗ | case 8: | |
664 | ✗ | for (x = 0; x < s->linesize[p]; x+=8) | |
665 | ✗ | AV_WN64(&dst[x], AV_RN64(&src[x * 2])); | |
666 | ✗ | break; | |
667 | } | ||
668 | } | ||
669 | ✗ | } | |
670 | |||
671 | 119 | static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref) | |
672 | { | ||
673 | 119 | AVFilterContext *ctx = inlink->dst; | |
674 | 119 | Stereo3DContext *s = ctx->priv; | |
675 | 119 | AVFilterLink *outlink = ctx->outputs[0]; | |
676 | 119 | AVFrame *out = NULL, *oleft, *oright, *ileft, *iright; | |
677 | int out_off_left[4], out_off_right[4]; | ||
678 | int i, ret; | ||
679 | |||
680 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
|
119 | if (s->in.format == s->out.format) |
681 | ✗ | return ff_filter_frame(outlink, inpicref); | |
682 | |||
683 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 115 times.
|
119 | switch (s->out.format) { |
684 | 4 | case ALTERNATING_LR: | |
685 | case ALTERNATING_RL: | ||
686 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (!s->prev) { |
687 | 1 | s->prev = inpicref; | |
688 | 1 | return 0; | |
689 | } | ||
690 | 3 | break; | |
691 | }; | ||
692 | |||
693 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 98 times.
|
118 | switch (s->in.format) { |
694 | 20 | case ALTERNATING_LR: | |
695 | case ALTERNATING_RL: | ||
696 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | if (!s->prev) { |
697 | 10 | s->prev = inpicref; | |
698 | 10 | return 0; | |
699 | } | ||
700 | 10 | ileft = s->prev; | |
701 | 10 | iright = inpicref; | |
702 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | if (s->in.format == ALTERNATING_RL) |
703 | 5 | FFSWAP(AVFrame *, ileft, iright); | |
704 | 10 | break; | |
705 | 98 | default: | |
706 | 98 | ileft = iright = inpicref; | |
707 | }; | ||
708 | |||
709 |
2/2✓ Branch 0 taken 105 times.
✓ Branch 1 taken 3 times.
|
108 | if ((s->out.format == ALTERNATING_LR || |
710 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
|
105 | s->out.format == ALTERNATING_RL) && |
711 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | (s->in.format == SIDE_BY_SIDE_LR || |
712 | ✗ | s->in.format == SIDE_BY_SIDE_RL || | |
713 | ✗ | s->in.format == SIDE_BY_SIDE_2_LR || | |
714 | ✗ | s->in.format == SIDE_BY_SIDE_2_RL || | |
715 | ✗ | s->in.format == ABOVE_BELOW_LR || | |
716 | ✗ | s->in.format == ABOVE_BELOW_RL || | |
717 | ✗ | s->in.format == ABOVE_BELOW_2_LR || | |
718 | ✗ | s->in.format == ABOVE_BELOW_2_RL || | |
719 | ✗ | s->in.format == INTERLEAVE_ROWS_LR || | |
720 | ✗ | s->in.format == INTERLEAVE_ROWS_RL)) { | |
721 | 3 | oright = av_frame_clone(s->prev); | |
722 | 3 | oleft = av_frame_clone(s->prev); | |
723 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
3 | if (!oright || !oleft) { |
724 | ✗ | av_frame_free(&oright); | |
725 | ✗ | av_frame_free(&oleft); | |
726 | ✗ | av_frame_free(&s->prev); | |
727 | ✗ | av_frame_free(&inpicref); | |
728 | ✗ | return AVERROR(ENOMEM); | |
729 | } | ||
730 |
2/2✓ Branch 0 taken 100 times.
✓ Branch 1 taken 5 times.
|
105 | } else if ((s->out.format == MONO_L || |
731 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 95 times.
|
100 | s->out.format == MONO_R) && |
732 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | (s->in.format == SIDE_BY_SIDE_LR || |
733 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | s->in.format == SIDE_BY_SIDE_RL || |
734 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | s->in.format == SIDE_BY_SIDE_2_LR || |
735 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | s->in.format == SIDE_BY_SIDE_2_RL || |
736 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | s->in.format == ABOVE_BELOW_LR || |
737 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | s->in.format == ABOVE_BELOW_RL || |
738 | ✗ | s->in.format == ABOVE_BELOW_2_LR || | |
739 | ✗ | s->in.format == ABOVE_BELOW_2_RL || | |
740 | ✗ | s->in.format == INTERLEAVE_ROWS_LR || | |
741 | ✗ | s->in.format == INTERLEAVE_ROWS_RL)) { | |
742 | 10 | out = oleft = oright = av_frame_clone(inpicref); | |
743 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!out) { |
744 | ✗ | av_frame_free(&s->prev); | |
745 | ✗ | av_frame_free(&inpicref); | |
746 | ✗ | return AVERROR(ENOMEM); | |
747 | } | ||
748 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
95 | } else if ((s->out.format == MONO_L && s->in.format == ALTERNATING_LR) || |
749 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
95 | (s->out.format == MONO_R && s->in.format == ALTERNATING_RL)) { |
750 | ✗ | s->prev->pts /= 2; | |
751 | ✗ | ret = ff_filter_frame(outlink, s->prev); | |
752 | ✗ | av_frame_free(&inpicref); | |
753 | ✗ | s->prev = NULL; | |
754 | ✗ | return ret; | |
755 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
95 | } else if ((s->out.format == MONO_L && s->in.format == ALTERNATING_RL) || |
756 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
95 | (s->out.format == MONO_R && s->in.format == ALTERNATING_LR)) { |
757 | ✗ | av_frame_free(&s->prev); | |
758 | ✗ | inpicref->pts /= 2; | |
759 | ✗ | return ff_filter_frame(outlink, inpicref); | |
760 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
95 | } else if ((s->out.format == ALTERNATING_LR && s->in.format == ALTERNATING_RL) || |
761 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
95 | (s->out.format == ALTERNATING_RL && s->in.format == ALTERNATING_LR)) { |
762 | ✗ | FFSWAP(int64_t, s->prev->pts, inpicref->pts); | |
763 | ✗ | ff_filter_frame(outlink, inpicref); | |
764 | ✗ | ret = ff_filter_frame(outlink, s->prev); | |
765 | ✗ | s->prev = NULL; | |
766 | ✗ | return ret; | |
767 | } else { | ||
768 | 95 | out = oleft = oright = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |
769 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
|
95 | if (!out) { |
770 | ✗ | av_frame_free(&s->prev); | |
771 | ✗ | av_frame_free(&inpicref); | |
772 | ✗ | return AVERROR(ENOMEM); | |
773 | } | ||
774 | 95 | av_frame_copy_props(out, inpicref); | |
775 | |||
776 |
1/2✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
|
95 | if (s->out.format == ALTERNATING_LR || |
777 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
|
95 | s->out.format == ALTERNATING_RL) { |
778 | ✗ | oright = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |
779 | ✗ | if (!oright) { | |
780 | ✗ | av_frame_free(&oleft); | |
781 | ✗ | av_frame_free(&s->prev); | |
782 | ✗ | av_frame_free(&inpicref); | |
783 | ✗ | return AVERROR(ENOMEM); | |
784 | } | ||
785 | ✗ | av_frame_copy_props(oright, s->prev); | |
786 | } | ||
787 | } | ||
788 | |||
789 |
2/2✓ Branch 0 taken 432 times.
✓ Branch 1 taken 108 times.
|
540 | for (i = 0; i < 4; i++) { |
790 |
4/4✓ Branch 0 taken 324 times.
✓ Branch 1 taken 108 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 216 times.
|
432 | int hsub = i == 1 || i == 2 ? s->hsub : 0; |
791 |
4/4✓ Branch 0 taken 324 times.
✓ Branch 1 taken 108 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 216 times.
|
432 | int vsub = i == 1 || i == 2 ? s->vsub : 0; |
792 | 432 | s->in_off_left[i] = (AV_CEIL_RSHIFT(s->in.row_left, vsub) + s->in.off_lstep) * ileft->linesize[i] + AV_CEIL_RSHIFT(s->in.off_left * s->pixstep[i], hsub); | |
793 | 432 | s->in_off_right[i] = (AV_CEIL_RSHIFT(s->in.row_right, vsub) + s->in.off_rstep) * iright->linesize[i] + AV_CEIL_RSHIFT(s->in.off_right * s->pixstep[i], hsub); | |
794 | 432 | out_off_left[i] = (AV_CEIL_RSHIFT(s->out.row_left, vsub) + s->out.off_lstep) * oleft->linesize[i] + AV_CEIL_RSHIFT(s->out.off_left * s->pixstep[i], hsub); | |
795 | 432 | out_off_right[i] = (AV_CEIL_RSHIFT(s->out.row_right, vsub) + s->out.off_rstep) * oright->linesize[i] + AV_CEIL_RSHIFT(s->out.off_right * s->pixstep[i], hsub); | |
796 | } | ||
797 | |||
798 |
5/9✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 70 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
108 | switch (s->out.format) { |
799 | 3 | case ALTERNATING_LR: | |
800 | case ALTERNATING_RL: | ||
801 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | switch (s->in.format) { |
802 | ✗ | case INTERLEAVE_ROWS_LR: | |
803 | case INTERLEAVE_ROWS_RL: | ||
804 | ✗ | for (i = 0; i < s->nb_planes; i++) { | |
805 | ✗ | oleft->linesize[i] *= 2; | |
806 | ✗ | oright->linesize[i] *= 2; | |
807 | } | ||
808 | case ABOVE_BELOW_LR: | ||
809 | case ABOVE_BELOW_RL: | ||
810 | case ABOVE_BELOW_2_LR: | ||
811 | case ABOVE_BELOW_2_RL: | ||
812 | case SIDE_BY_SIDE_LR: | ||
813 | case SIDE_BY_SIDE_RL: | ||
814 | case SIDE_BY_SIDE_2_LR: | ||
815 | case SIDE_BY_SIDE_2_RL: | ||
816 | 3 | oleft->width = outlink->w; | |
817 | 3 | oright->width = outlink->w; | |
818 | 3 | oleft->height = outlink->h; | |
819 | 3 | oright->height = outlink->h; | |
820 | |||
821 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
|
12 | for (i = 0; i < s->nb_planes; i++) { |
822 | 9 | oleft->data[i] += s->in_off_left[i]; | |
823 | 9 | oright->data[i] += s->in_off_right[i]; | |
824 | } | ||
825 | 3 | break; | |
826 | ✗ | default: | |
827 | ✗ | goto copy; | |
828 | break; | ||
829 | } | ||
830 | 3 | break; | |
831 | ✗ | case HDMI: | |
832 | ✗ | for (i = 0; i < s->nb_planes; i++) { | |
833 | ✗ | int j, h = s->height >> ((i == 1 || i == 2) ? s->vsub : 0); | |
834 | ✗ | int b = (s->blanks) >> ((i == 1 || i == 2) ? s->vsub : 0); | |
835 | |||
836 | ✗ | for (j = h; j < h + b; j++) | |
837 | ✗ | memset(oleft->data[i] + j * s->linesize[i], 0, s->linesize[i]); | |
838 | } | ||
839 | case SIDE_BY_SIDE_LR: | ||
840 | case SIDE_BY_SIDE_RL: | ||
841 | case SIDE_BY_SIDE_2_LR: | ||
842 | case SIDE_BY_SIDE_2_RL: | ||
843 | case ABOVE_BELOW_LR: | ||
844 | case ABOVE_BELOW_RL: | ||
845 | case ABOVE_BELOW_2_LR: | ||
846 | case ABOVE_BELOW_2_RL: | ||
847 | case INTERLEAVE_ROWS_LR: | ||
848 | case INTERLEAVE_ROWS_RL: | ||
849 | ✗ | copy: | |
850 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | if (s->in.format == INTERLEAVE_COLS_LR || |
851 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | s->in.format == INTERLEAVE_COLS_RL) { |
852 | ✗ | for (i = 0; i < s->nb_planes; i++) { | |
853 | ✗ | int d = (s->in.format & 1) != (s->out.format & 1); | |
854 | |||
855 | ✗ | interleave_cols_to_any(s, out_off_left, i, ileft, oleft, d); | |
856 | ✗ | interleave_cols_to_any(s, out_off_right, i, iright, oright, !d); | |
857 | } | ||
858 | } else { | ||
859 |
2/2✓ Branch 0 taken 75 times.
✓ Branch 1 taken 25 times.
|
100 | for (i = 0; i < s->nb_planes; i++) { |
860 | 75 | av_image_copy_plane(oleft->data[i] + out_off_left[i], | |
861 | 75 | oleft->linesize[i] * s->out.row_step, | |
862 | 75 | ileft->data[i] + s->in_off_left[i], | |
863 | 75 | ileft->linesize[i] * s->in.row_step, | |
864 | s->linesize[i], s->pheight[i]); | ||
865 | 75 | av_image_copy_plane(oright->data[i] + out_off_right[i], | |
866 | 75 | oright->linesize[i] * s->out.row_step, | |
867 | 75 | iright->data[i] + s->in_off_right[i], | |
868 | 75 | iright->linesize[i] * s->in.row_step, | |
869 | s->linesize[i], s->pheight[i]); | ||
870 | } | ||
871 | } | ||
872 | 25 | break; | |
873 | 5 | case MONO_L: | |
874 | 5 | iright = ileft; | |
875 | 10 | case MONO_R: | |
876 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
10 | switch (s->in.format) { |
877 | ✗ | case INTERLEAVE_ROWS_LR: | |
878 | case INTERLEAVE_ROWS_RL: | ||
879 | ✗ | for (i = 0; i < s->nb_planes; i++) { | |
880 | ✗ | out->linesize[i] *= 2; | |
881 | } | ||
882 | case ABOVE_BELOW_LR: | ||
883 | case ABOVE_BELOW_RL: | ||
884 | case ABOVE_BELOW_2_LR: | ||
885 | case ABOVE_BELOW_2_RL: | ||
886 | case SIDE_BY_SIDE_LR: | ||
887 | case SIDE_BY_SIDE_RL: | ||
888 | case SIDE_BY_SIDE_2_LR: | ||
889 | case SIDE_BY_SIDE_2_RL: | ||
890 | 10 | out->width = outlink->w; | |
891 | 10 | out->height = outlink->h; | |
892 | |||
893 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 10 times.
|
40 | for (i = 0; i < s->nb_planes; i++) { |
894 | 30 | out->data[i] += s->in_off_left[i]; | |
895 | } | ||
896 | 10 | break; | |
897 | ✗ | case INTERLEAVE_COLS_LR: | |
898 | case INTERLEAVE_COLS_RL: | ||
899 | ✗ | for (i = 0; i < s->nb_planes; i++) { | |
900 | ✗ | const int d = (s->in.format & 1) != (s->out.format & 1); | |
901 | |||
902 | ✗ | interleave_cols_to_any(s, out_off_right, i, iright, out, d); | |
903 | } | ||
904 | ✗ | break; | |
905 | ✗ | default: | |
906 | ✗ | for (i = 0; i < s->nb_planes; i++) { | |
907 | ✗ | av_image_copy_plane(out->data[i], out->linesize[i], | |
908 | ✗ | iright->data[i] + s->in_off_left[i], | |
909 | ✗ | iright->linesize[i] * s->in.row_step, | |
910 | s->linesize[i], s->pheight[i]); | ||
911 | } | ||
912 | ✗ | break; | |
913 | } | ||
914 | 10 | break; | |
915 | 70 | case ANAGLYPH_RB_GRAY: | |
916 | case ANAGLYPH_RG_GRAY: | ||
917 | case ANAGLYPH_RC_GRAY: | ||
918 | case ANAGLYPH_RC_HALF: | ||
919 | case ANAGLYPH_RC_COLOR: | ||
920 | case ANAGLYPH_RC_DUBOIS: | ||
921 | case ANAGLYPH_GM_GRAY: | ||
922 | case ANAGLYPH_GM_HALF: | ||
923 | case ANAGLYPH_GM_COLOR: | ||
924 | case ANAGLYPH_GM_DUBOIS: | ||
925 | case ANAGLYPH_YB_GRAY: | ||
926 | case ANAGLYPH_YB_HALF: | ||
927 | case ANAGLYPH_YB_COLOR: | ||
928 | case ANAGLYPH_YB_DUBOIS: { | ||
929 |
1/2✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
|
70 | if (s->in.format == INTERLEAVE_COLS_LR || |
930 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
|
70 | s->in.format == INTERLEAVE_COLS_RL) { |
931 | ✗ | const int d = (s->in.format & 1); | |
932 | |||
933 | ✗ | anaglyph_ic(out->data[0], | |
934 | ✗ | ileft ->data[0] + s->in_off_left [0] + d * 3, | |
935 | ✗ | iright->data[0] + s->in_off_right[0] + (!d) * 3, | |
936 | ✗ | out->linesize[0], | |
937 | ✗ | ileft->linesize[0] * s->in.row_step, | |
938 | ✗ | iright->linesize[0] * s->in.row_step, | |
939 | s->out.width, s->out.height, | ||
940 | s->ana_matrix[0], s->ana_matrix[1], s->ana_matrix[2]); | ||
941 | } else { | ||
942 | ThreadData td; | ||
943 | |||
944 | 70 | td.ileft = ileft; td.iright = iright; td.out = out; | |
945 | 70 | ff_filter_execute(ctx, filter_slice, &td, NULL, | |
946 |
1/2✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
|
70 | FFMIN(s->out.height, ff_filter_get_nb_threads(ctx))); |
947 | } | ||
948 | 70 | break; | |
949 | } | ||
950 | ✗ | case CHECKERBOARD_RL: | |
951 | case CHECKERBOARD_LR: | ||
952 | ✗ | for (i = 0; i < s->nb_planes; i++) { | |
953 | int x, y; | ||
954 | |||
955 | ✗ | for (y = 0; y < s->pheight[i]; y++) { | |
956 | ✗ | uint8_t *dst = out->data[i] + out->linesize[i] * y; | |
957 | ✗ | const int d1 = (s->in.format == INTERLEAVE_COLS_LR || s->in.format == INTERLEAVE_COLS_RL) && (s->in.format & 1) != (s->out.format & 1); | |
958 | ✗ | const int d2 = (s->in.format == INTERLEAVE_COLS_LR || s->in.format == INTERLEAVE_COLS_RL) ? !d1 : 0; | |
959 | ✗ | const int m = 1 + (s->in.format == INTERLEAVE_COLS_LR || s->in.format == INTERLEAVE_COLS_RL); | |
960 | ✗ | uint8_t *left = ileft->data[i] + ileft->linesize[i] * y + s->in_off_left[i] + d1 * s->pixstep[i]; | |
961 | ✗ | uint8_t *right = iright->data[i] + iright->linesize[i] * y + s->in_off_right[i] + d2 * s->pixstep[i]; | |
962 | int p, b; | ||
963 | |||
964 | ✗ | if (s->out.format == CHECKERBOARD_RL && s->in.format != INTERLEAVE_COLS_LR && s->in.format != INTERLEAVE_COLS_RL) | |
965 | ✗ | FFSWAP(uint8_t*, left, right); | |
966 | ✗ | switch (s->pixstep[i]) { | |
967 | ✗ | case 1: | |
968 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=2, p++, b+=2) { | |
969 | ✗ | dst[x ] = (b&1) == (y&1) ? left[p*m] : right[p*m]; | |
970 | ✗ | dst[x+1] = (b&1) != (y&1) ? left[p*m] : right[p*m]; | |
971 | } | ||
972 | ✗ | break; | |
973 | ✗ | case 2: | |
974 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=4, p+=2, b+=2) { | |
975 | ✗ | AV_WN16(&dst[x ], (b&1) == (y&1) ? AV_RN16(&left[p*m]) : AV_RN16(&right[p*m])); | |
976 | ✗ | AV_WN16(&dst[x+2], (b&1) != (y&1) ? AV_RN16(&left[p*m]) : AV_RN16(&right[p*m])); | |
977 | } | ||
978 | ✗ | break; | |
979 | ✗ | case 3: | |
980 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=6, p+=3, b+=2) { | |
981 | ✗ | AV_WB24(&dst[x ], (b&1) == (y&1) ? AV_RB24(&left[p*m]) : AV_RB24(&right[p*m])); | |
982 | ✗ | AV_WB24(&dst[x+3], (b&1) != (y&1) ? AV_RB24(&left[p*m]) : AV_RB24(&right[p*m])); | |
983 | } | ||
984 | ✗ | break; | |
985 | ✗ | case 4: | |
986 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=8, p+=4, b+=2) { | |
987 | ✗ | AV_WN32(&dst[x ], (b&1) == (y&1) ? AV_RN32(&left[p*m]) : AV_RN32(&right[p*m])); | |
988 | ✗ | AV_WN32(&dst[x+4], (b&1) != (y&1) ? AV_RN32(&left[p*m]) : AV_RN32(&right[p*m])); | |
989 | } | ||
990 | ✗ | break; | |
991 | ✗ | case 6: | |
992 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=12, p+=6, b+=2) { | |
993 | ✗ | AV_WB48(&dst[x ], (b&1) == (y&1) ? AV_RB48(&left[p*m]) : AV_RB48(&right[p*m])); | |
994 | ✗ | AV_WB48(&dst[x+6], (b&1) != (y&1) ? AV_RB48(&left[p*m]) : AV_RB48(&right[p*m])); | |
995 | } | ||
996 | ✗ | break; | |
997 | ✗ | case 8: | |
998 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=16, p+=8, b+=2) { | |
999 | ✗ | AV_WN64(&dst[x ], (b&1) == (y&1) ? AV_RN64(&left[p*m]) : AV_RN64(&right[p*m])); | |
1000 | ✗ | AV_WN64(&dst[x+8], (b&1) != (y&1) ? AV_RN64(&left[p*m]) : AV_RN64(&right[p*m])); | |
1001 | } | ||
1002 | ✗ | break; | |
1003 | } | ||
1004 | } | ||
1005 | } | ||
1006 | ✗ | break; | |
1007 | ✗ | case INTERLEAVE_COLS_LR: | |
1008 | case INTERLEAVE_COLS_RL: | ||
1009 | ✗ | for (i = 0; i < s->nb_planes; i++) { | |
1010 | ✗ | const int d = (s->in.format == INTERLEAVE_COLS_LR || s->in.format == INTERLEAVE_COLS_RL); | |
1011 | ✗ | const int m = 1 + d; | |
1012 | int x, y; | ||
1013 | |||
1014 | ✗ | for (y = 0; y < s->pheight[i]; y++) { | |
1015 | ✗ | uint8_t *dst = out->data[i] + out->linesize[i] * y; | |
1016 | ✗ | uint8_t *left = ileft->data[i] + ileft->linesize[i] * y * s->in.row_step + s->in_off_left[i] + d * s->pixstep[i]; | |
1017 | ✗ | uint8_t *right = iright->data[i] + iright->linesize[i] * y * s->in.row_step + s->in_off_right[i]; | |
1018 | int p, b; | ||
1019 | |||
1020 | ✗ | if (s->out.format == INTERLEAVE_COLS_LR) | |
1021 | ✗ | FFSWAP(uint8_t*, left, right); | |
1022 | |||
1023 | ✗ | switch (s->pixstep[i]) { | |
1024 | ✗ | case 1: | |
1025 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=2, p++, b+=2) { | |
1026 | ✗ | dst[x ] = b&1 ? left[p*m] : right[p*m]; | |
1027 | ✗ | dst[x+1] = !(b&1) ? left[p*m] : right[p*m]; | |
1028 | } | ||
1029 | ✗ | break; | |
1030 | ✗ | case 2: | |
1031 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=4, p+=2, b+=2) { | |
1032 | ✗ | AV_WN16(&dst[x ], b&1 ? AV_RN16(&left[p*m]) : AV_RN16(&right[p*m])); | |
1033 | ✗ | AV_WN16(&dst[x+2], !(b&1) ? AV_RN16(&left[p*m]) : AV_RN16(&right[p*m])); | |
1034 | } | ||
1035 | ✗ | break; | |
1036 | ✗ | case 3: | |
1037 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=6, p+=3, b+=2) { | |
1038 | ✗ | AV_WB24(&dst[x ], b&1 ? AV_RB24(&left[p*m]) : AV_RB24(&right[p*m])); | |
1039 | ✗ | AV_WB24(&dst[x+3], !(b&1) ? AV_RB24(&left[p*m]) : AV_RB24(&right[p*m])); | |
1040 | } | ||
1041 | ✗ | break; | |
1042 | ✗ | case 4: | |
1043 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=8, p+=4, b+=2) { | |
1044 | ✗ | AV_WN32(&dst[x ], b&1 ? AV_RN32(&left[p*m]) : AV_RN32(&right[p*m])); | |
1045 | ✗ | AV_WN32(&dst[x+4], !(b&1) ? AV_RN32(&left[p*m]) : AV_RN32(&right[p*m])); | |
1046 | } | ||
1047 | ✗ | break; | |
1048 | ✗ | case 6: | |
1049 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=12, p+=6, b+=2) { | |
1050 | ✗ | AV_WB48(&dst[x ], b&1 ? AV_RB48(&left[p*m]) : AV_RB48(&right[p*m])); | |
1051 | ✗ | AV_WB48(&dst[x+6], !(b&1) ? AV_RB48(&left[p*m]) : AV_RB48(&right[p*m])); | |
1052 | } | ||
1053 | ✗ | break; | |
1054 | ✗ | case 8: | |
1055 | ✗ | for (x = 0, b = 0, p = 0; x < s->linesize[i] * 2; x+=16, p+=8, b+=2) { | |
1056 | ✗ | AV_WN64(&dst[x ], b&1 ? AV_RN64(&left[p*m]) : AV_RN64(&right[p*m])); | |
1057 | ✗ | AV_WN64(&dst[x+8], !(b&1) ? AV_RN64(&left[p*m]) : AV_RN64(&right[p*m])); | |
1058 | } | ||
1059 | ✗ | break; | |
1060 | } | ||
1061 | } | ||
1062 | } | ||
1063 | ✗ | break; | |
1064 | ✗ | default: | |
1065 | ✗ | av_assert0(0); | |
1066 | } | ||
1067 | |||
1068 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 105 times.
|
108 | if (oright != oleft) { |
1069 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (s->out.format == ALTERNATING_LR) |
1070 | 3 | FFSWAP(AVFrame *, oleft, oright); | |
1071 | 3 | oright->pts = s->prev->pts * 2; | |
1072 | 3 | ff_filter_frame(outlink, oright); | |
1073 | 3 | out = oleft; | |
1074 | 3 | oleft->pts = s->prev->pts + inpicref->pts; | |
1075 | 3 | av_frame_free(&s->prev); | |
1076 | 3 | s->prev = inpicref; | |
1077 |
2/2✓ Branch 0 taken 100 times.
✓ Branch 1 taken 5 times.
|
105 | } else if (s->in.format == ALTERNATING_LR || |
1078 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 95 times.
|
100 | s->in.format == ALTERNATING_RL) { |
1079 | 10 | out->pts = s->prev->pts / 2; | |
1080 | 10 | av_frame_free(&s->prev); | |
1081 | 10 | av_frame_free(&inpicref); | |
1082 | } else { | ||
1083 | 95 | av_frame_free(&s->prev); | |
1084 | 95 | av_frame_free(&inpicref); | |
1085 | } | ||
1086 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
|
108 | av_assert0(out); |
1087 | 108 | out->sample_aspect_ratio = s->aspect; | |
1088 | 108 | return ff_filter_frame(outlink, out); | |
1089 | } | ||
1090 | |||
1091 | 44 | static av_cold void uninit(AVFilterContext *ctx) | |
1092 | { | ||
1093 | 44 | Stereo3DContext *s = ctx->priv; | |
1094 | |||
1095 | 44 | av_frame_free(&s->prev); | |
1096 | 44 | } | |
1097 | |||
1098 | static const AVFilterPad stereo3d_inputs[] = { | ||
1099 | { | ||
1100 | .name = "default", | ||
1101 | .type = AVMEDIA_TYPE_VIDEO, | ||
1102 | .filter_frame = filter_frame, | ||
1103 | }, | ||
1104 | }; | ||
1105 | |||
1106 | static const AVFilterPad stereo3d_outputs[] = { | ||
1107 | { | ||
1108 | .name = "default", | ||
1109 | .type = AVMEDIA_TYPE_VIDEO, | ||
1110 | .config_props = config_output, | ||
1111 | }, | ||
1112 | }; | ||
1113 | |||
1114 | const AVFilter ff_vf_stereo3d = { | ||
1115 | .name = "stereo3d", | ||
1116 | .description = NULL_IF_CONFIG_SMALL("Convert video stereoscopic 3D view."), | ||
1117 | .priv_size = sizeof(Stereo3DContext), | ||
1118 | .uninit = uninit, | ||
1119 | FILTER_INPUTS(stereo3d_inputs), | ||
1120 | FILTER_OUTPUTS(stereo3d_outputs), | ||
1121 | FILTER_QUERY_FUNC2(query_formats), | ||
1122 | .priv_class = &stereo3d_class, | ||
1123 | .flags = AVFILTER_FLAG_SLICE_THREADS, | ||
1124 | }; | ||
1125 |