1 /*****************************************************************************
2 * anaglyph.c : Create an image compatible with anaglyph glasses from a 3D video
3 *****************************************************************************
4 * Copyright (C) 2000-2012 VLC authors and VideoLAN
7 * Authors: Antoine Cellerier <dionoea .t videolan d@t org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
28 #include <vlc_common.h>
29 #include <vlc_plugin.h>
31 #include <vlc_filter.h>
32 #include "filter_picture.h"
34 static int Create(vlc_object_t *);
35 static void Destroy(vlc_object_t *);
36 static picture_t *Filter(filter_t *, picture_t *);
37 static void combine_side_by_side_yuv420(picture_t *, picture_t *, int, int);
39 #define SCHEME_TEXT N_("Color scheme")
40 #define SCHEME_LONGTEXT N_("Define the glasses' color scheme")
42 #define FILTER_PREFIX "anaglyph-"
44 /* See http://en.wikipedia.org/wiki/Anaglyph_image for a list of known
56 static const char *const ppsz_scheme_values[] = {
63 static const char *const ppsz_scheme_descriptions[] = {
64 "pure red (left) pure green (right)",
65 "pure red (left) pure blue (right)",
66 "pure red (left) pure cyan (right)",
67 "pure green (left) pure magenta (right)",
68 "magenta (left) cyan (right)",
72 set_description(N_("Convert 3D picture to anaglyph image video filter"));
73 set_shortname(N_("Anaglyph"))
74 set_category(CAT_VIDEO)
75 set_subcategory(SUBCAT_VIDEO_VFILTER)
76 set_capability("video filter2", 0)
77 add_string(FILTER_PREFIX "scheme", "red-cyan", SCHEME_TEXT, SCHEME_LONGTEXT, false)
78 change_string_list(ppsz_scheme_values, ppsz_scheme_descriptions)
79 set_callbacks(Create, Destroy)
82 static const char *const ppsz_filter_options[] = {
92 static int Create(vlc_object_t *p_this)
94 filter_t *p_filter = (filter_t *)p_this;
96 switch (p_filter->fmt_in.video.i_chroma)
104 msg_Err(p_filter, "Unsupported input chroma (%4.4s)",
105 (char*)&(p_filter->fmt_in.video.i_chroma));
109 p_filter->p_sys = malloc(sizeof(filter_sys_t));
110 if (!p_filter->p_sys)
112 filter_sys_t *p_sys = p_filter->p_sys;
114 config_ChainParse(p_filter, FILTER_PREFIX, ppsz_filter_options,
117 char *psz_scheme = var_CreateGetStringCommand(p_filter,
118 FILTER_PREFIX "scheme");
119 enum scheme_e scheme = red_cyan;
122 if (!strcmp(psz_scheme, "red-green"))
124 else if (!strcmp(psz_scheme, "red-blue"))
126 else if (!strcmp(psz_scheme, "red-cyan"))
128 else if (!strcmp(psz_scheme, "trioscopic"))
130 else if (!strcmp(psz_scheme, "magenta-cyan"))
131 scheme = magenta_cyan;
133 msg_Err(p_filter, "Unknown anaglyph color scheme '%s'", psz_scheme);
140 p_sys->left = 0xff0000;
141 p_sys->right = 0x00ff00;
144 p_sys->left = 0xff0000;
145 p_sys->right = 0x0000ff;
148 p_sys->left = 0xff0000;
149 p_sys->right = 0x00ffff;
152 p_sys->left = 0x00ff00;
153 p_sys->right = 0xff00ff;
156 p_sys->left = 0xff00ff;
157 p_sys->right = 0x00ffff;
160 msg_Err(p_filter, "Oops");
164 p_filter->pf_video_filter = Filter;
168 static void Destroy(vlc_object_t *p_this)
170 filter_t *p_filter = (filter_t *)p_this;
171 filter_sys_t *p_sys = p_filter->p_sys;
175 static picture_t *Filter(filter_t *p_filter, picture_t *p_pic)
177 filter_sys_t *p_sys = p_filter->p_sys;
182 picture_t *p_outpic = filter_NewPicture(p_filter);
185 picture_Release(p_pic);
189 switch (p_pic->format.i_chroma)
194 combine_side_by_side_yuv420(p_pic, p_outpic,
195 p_sys->left, p_sys->right);
199 msg_Warn(p_filter, "Unsupported input chroma (%4.4s)",
200 (char*)&(p_pic->format.i_chroma));
201 picture_Release(p_pic);
205 return CopyInfoAndRelease(p_outpic, p_pic);
209 static void combine_side_by_side_yuv420(picture_t *p_inpic, picture_t *p_outpic,
212 uint8_t *y1inl = p_inpic->p[Y_PLANE].p_pixels;
214 uint8_t *uinl = p_inpic->p[U_PLANE].p_pixels;
215 uint8_t *vinl = p_inpic->p[V_PLANE].p_pixels;
217 uint8_t *y1out = p_outpic->p[Y_PLANE].p_pixels;
219 uint8_t *uout = p_outpic->p[U_PLANE].p_pixels;
220 uint8_t *vout = p_outpic->p[V_PLANE].p_pixels;
222 const int in_pitch = p_inpic->p[Y_PLANE].i_pitch;
223 const int out_pitch = p_outpic->p[Y_PLANE].i_pitch;
225 const int visible_pitch = p_inpic->p[Y_PLANE].i_visible_pitch;
226 const int visible_lines = p_inpic->p[Y_PLANE].i_visible_lines;
227 const int uv_visible_pitch = p_inpic->p[U_PLANE].i_visible_pitch;
229 const uint8_t *yend = y1inl + visible_lines * in_pitch;
233 uint8_t *y1inr = y1inl + visible_pitch/2;
235 uint8_t *uinr = uinl + uv_visible_pitch/2;
236 uint8_t *vinr = vinl + uv_visible_pitch/2;
238 const uint8_t *y1end = y1inr;
239 y2inl = y1inl + in_pitch;
240 y2inr = y1inr + in_pitch;
241 y2out = y1out + out_pitch;
243 while (y1inl < y1end)
245 int rl, gl, bl, rr, gr, br, r, g, b;
247 int rshift = !!((0xff0000&left) && (0xff0000&right));
248 int gshift = !!((0x00ff00&left) && (0x00ff00&right));
249 int bshift = !!((0x0000ff&left) && (0x0000ff&right));
251 yuv_to_rgb(&rl, &gl, &bl, *y1inl, *uinl, *vinl);
252 yuv_to_rgb(&rr, &gr, &br, *y1inr, *uinr, *vinr);
253 r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
254 g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
255 b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
256 rgb_to_yuv(y1out, uout++, vout++, r, g, b);
262 yuv_to_rgb(&rl, &gl, &bl, *y1inl, *uinl, *vinl);
263 yuv_to_rgb(&rr, &gr, &br, *y1inr, *uinr, *vinr);
264 r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
265 g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
266 b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
267 rgb_to_yuv(y1out, uout++, vout++, r, g, b);
273 yuv_to_rgb(&rl, &gl, &bl, *y2inl, *uinl, *vinl);
274 yuv_to_rgb(&rr, &gr, &br, *y2inr, *uinr, *vinr);
275 r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
276 g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
277 b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
278 rgb_to_yuv(y2out, uout/*will be overwritten later, as will vout*/, vout, r, g, b);
284 yuv_to_rgb(&rl, &gl, &bl, *y2inl, *uinl, *vinl);
285 yuv_to_rgb(&rr, &gr, &br, *y2inr, *uinr, *vinr);
286 r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
287 g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
288 b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
289 rgb_to_yuv(y2out, uout/*will be overwritten later, as will vout*/, vout, r, g, b);
301 y1inl = y1inr + 2*in_pitch - visible_pitch;
302 y1out += 2*out_pitch - visible_pitch;
303 uinl = uinr + p_inpic->p[U_PLANE].i_pitch - uv_visible_pitch;
304 vinl = vinr + p_inpic->p[V_PLANE].i_pitch - uv_visible_pitch;
305 uout += p_outpic->p[U_PLANE].i_pitch - uv_visible_pitch;
306 vout += p_outpic->p[V_PLANE].i_pitch - uv_visible_pitch;