anaglyph: remove spurious printf
[vlc.git] / modules / video_filter / anaglyph.c
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
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea .t videolan d@t org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 #   include "config.h"
26 #endif
27
28 #include <vlc_common.h>
29 #include <vlc_plugin.h>
30
31 #include <vlc_filter.h>
32 #include "filter_picture.h"
33
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);
38
39 #define SCHEME_TEXT N_("Color scheme")
40 #define SCHEME_LONGTEXT N_("Define the glasses' color scheme")
41
42 #define FILTER_PREFIX "anaglyph-"
43
44 /* See http://en.wikipedia.org/wiki/Anaglyph_image for a list of known
45  * color schemes */
46 enum scheme_e
47 {
48     unknown = 0,
49     red_green,
50     red_blue,
51     red_cyan,
52     trioscopic,
53     magenta_cyan,
54 };
55
56 static const char *const ppsz_scheme_values[] = {
57     "red-green",
58     "red-blue",
59     "red-cyan",
60     "trioscopic",
61     "magenta-cyan",
62     };
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)",
69     };
70
71 vlc_module_begin()
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)
80 vlc_module_end()
81
82 static const char *const ppsz_filter_options[] = {
83     "scheme", NULL
84 };
85
86 struct filter_sys_t
87 {
88     int left, right;
89 };
90
91
92 static int Create(vlc_object_t *p_this)
93 {
94     filter_t *p_filter = (filter_t *)p_this;
95
96     switch (p_filter->fmt_in.video.i_chroma)
97     {
98         case VLC_CODEC_I420:
99         case VLC_CODEC_J420:
100         case VLC_CODEC_YV12:
101             break;
102
103         default:
104             msg_Err(p_filter, "Unsupported input chroma (%4.4s)",
105                     (char*)&(p_filter->fmt_in.video.i_chroma));
106             return VLC_EGENERIC;
107     }
108
109     p_filter->p_sys = malloc(sizeof(filter_sys_t));
110     if (!p_filter->p_sys)
111         return VLC_ENOMEM;
112     filter_sys_t *p_sys = p_filter->p_sys;
113
114     config_ChainParse(p_filter, FILTER_PREFIX, ppsz_filter_options,
115                       p_filter->p_cfg);
116
117     char *psz_scheme = var_CreateGetStringCommand(p_filter,
118                                                   FILTER_PREFIX "scheme");
119     enum scheme_e scheme = red_cyan;
120     if (psz_scheme)
121     {
122         if (!strcmp(psz_scheme, "red-green"))
123             scheme = red_green;
124         else if (!strcmp(psz_scheme, "red-blue"))
125             scheme = red_blue;
126         else if (!strcmp(psz_scheme, "red-cyan"))
127             scheme = red_cyan;
128         else if (!strcmp(psz_scheme, "trioscopic"))
129             scheme = trioscopic;
130         else if (!strcmp(psz_scheme, "magenta-cyan"))
131             scheme = magenta_cyan;
132         else
133             msg_Err(p_filter, "Unknown anaglyph color scheme '%s'", psz_scheme);
134     }
135     free(psz_scheme);
136
137     switch (scheme)
138     {
139         case red_green:
140             p_sys->left = 0xff0000;
141             p_sys->right = 0x00ff00;
142             break;
143         case red_blue:
144             p_sys->left = 0xff0000;
145             p_sys->right = 0x0000ff;
146             break;
147         case red_cyan:
148             p_sys->left = 0xff0000;
149             p_sys->right = 0x00ffff;
150             break;
151         case trioscopic:
152             p_sys->left = 0x00ff00;
153             p_sys->right = 0xff00ff;
154             break;
155         case magenta_cyan:
156             p_sys->left = 0xff00ff;
157             p_sys->right = 0x00ffff;
158             break;
159         case unknown:
160             msg_Err(p_filter, "Oops");
161             break;
162     }
163
164     p_filter->pf_video_filter = Filter;
165     return VLC_SUCCESS;
166 }
167
168 static void Destroy(vlc_object_t *p_this)
169 {
170     filter_t *p_filter = (filter_t *)p_this;
171     filter_sys_t *p_sys = p_filter->p_sys;
172     free(p_sys);
173 }
174
175 static picture_t *Filter(filter_t *p_filter, picture_t *p_pic)
176 {
177     filter_sys_t *p_sys = p_filter->p_sys;
178
179     if (!p_pic)
180         return NULL;
181
182     picture_t *p_outpic = filter_NewPicture(p_filter);
183     if (!p_outpic)
184     {
185         picture_Release(p_pic);
186         return NULL;
187     }
188
189     switch (p_pic->format.i_chroma)
190     {
191         case VLC_CODEC_I420:
192         case VLC_CODEC_J420:
193         case VLC_CODEC_YV12:
194             combine_side_by_side_yuv420(p_pic, p_outpic,
195                                         p_sys->left, p_sys->right);
196             break;
197
198         default:
199             msg_Warn(p_filter, "Unsupported input chroma (%4.4s)",
200                      (char*)&(p_pic->format.i_chroma));
201             picture_Release(p_pic);
202             return NULL;
203     }
204
205     return CopyInfoAndRelease(p_outpic, p_pic);
206 }
207
208
209 static void combine_side_by_side_yuv420(picture_t *p_inpic, picture_t *p_outpic,
210                                         int left, int right)
211 {
212     uint8_t *y1inl = p_inpic->p[Y_PLANE].p_pixels;
213     uint8_t *y2inl;
214     uint8_t *uinl = p_inpic->p[U_PLANE].p_pixels;
215     uint8_t *vinl = p_inpic->p[V_PLANE].p_pixels;
216
217     uint8_t *y1out = p_outpic->p[Y_PLANE].p_pixels;
218     uint8_t *y2out;
219     uint8_t *uout = p_outpic->p[U_PLANE].p_pixels;
220     uint8_t *vout = p_outpic->p[V_PLANE].p_pixels;
221
222     const int in_pitch = p_inpic->p[Y_PLANE].i_pitch;
223     const int out_pitch = p_outpic->p[Y_PLANE].i_pitch;
224
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;
228
229     const uint8_t *yend = y1inl + visible_lines * in_pitch;
230
231     while (y1inl < yend)
232     {
233         uint8_t *y1inr = y1inl + visible_pitch/2;
234         uint8_t *y2inr;
235         uint8_t *uinr = uinl + uv_visible_pitch/2;
236         uint8_t *vinr = vinl + uv_visible_pitch/2;
237
238         const uint8_t *y1end = y1inr;
239         y2inl = y1inl + in_pitch;
240         y2inr = y1inr + in_pitch;
241         y2out = y1out + out_pitch;
242
243         while (y1inl < y1end)
244         {
245             int rl, gl, bl, rr, gr, br, r, g, b;
246
247             int rshift = !!((0xff0000&left) && (0xff0000&right));
248             int gshift = !!((0x00ff00&left) && (0x00ff00&right));
249             int bshift = !!((0x0000ff&left) && (0x0000ff&right));
250
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);
257             y1out[1] = *y1out;
258             y1out+=2;
259             y1inl++;
260             y1inr++;
261
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);
268             y1out[1] = *y1out;
269             y1out+=2;
270             y1inl++;
271             y1inr++;
272
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);
279             y2out[1] = *y2out;
280             y2out+=2;
281             y2inl++;
282             y2inr++;
283
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);
290             y2out[1] = *y2out;
291             y2out+=2;
292             y2inl++;
293             y2inr++;
294
295             uinl++;
296             vinl++;
297             uinr++;
298             vinr++;
299         }
300
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;
307     }
308 }
309