LGPL
[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     printf("pouet\n");
95     filter_t *p_filter = (filter_t *)p_this;
96
97     switch (p_filter->fmt_in.video.i_chroma)
98     {
99         case VLC_CODEC_I420:
100         case VLC_CODEC_J420:
101         case VLC_CODEC_YV12:
102             break;
103
104         default:
105             msg_Err(p_filter, "Unsupported input chroma (%4.4s)",
106                     (char*)&(p_filter->fmt_in.video.i_chroma));
107             return VLC_EGENERIC;
108     }
109
110     p_filter->p_sys = malloc(sizeof(filter_sys_t));
111     if (!p_filter->p_sys)
112         return VLC_ENOMEM;
113     filter_sys_t *p_sys = p_filter->p_sys;
114
115     config_ChainParse(p_filter, FILTER_PREFIX, ppsz_filter_options,
116                       p_filter->p_cfg);
117
118     char *psz_scheme = var_CreateGetStringCommand(p_filter,
119                                                   FILTER_PREFIX "scheme");
120     enum scheme_e scheme = red_cyan;
121     if (psz_scheme)
122     {
123         if (!strcmp(psz_scheme, "red-green"))
124             scheme = red_green;
125         else if (!strcmp(psz_scheme, "red-blue"))
126             scheme = red_blue;
127         else if (!strcmp(psz_scheme, "red-cyan"))
128             scheme = red_cyan;
129         else if (!strcmp(psz_scheme, "trioscopic"))
130             scheme = trioscopic;
131         else if (!strcmp(psz_scheme, "magenta-cyan"))
132             scheme = magenta_cyan;
133         else
134             msg_Err(p_filter, "Unknown anaglyph color scheme '%s'", psz_scheme);
135     }
136     free(psz_scheme);
137
138     switch (scheme)
139     {
140         case red_green:
141             p_sys->left = 0xff0000;
142             p_sys->right = 0x00ff00;
143             break;
144         case red_blue:
145             p_sys->left = 0xff0000;
146             p_sys->right = 0x0000ff;
147             break;
148         case red_cyan:
149             p_sys->left = 0xff0000;
150             p_sys->right = 0x00ffff;
151             break;
152         case trioscopic:
153             p_sys->left = 0x00ff00;
154             p_sys->right = 0xff00ff;
155             break;
156         case magenta_cyan:
157             p_sys->left = 0xff00ff;
158             p_sys->right = 0x00ffff;
159             break;
160         case unknown:
161             msg_Err(p_filter, "Oops");
162             break;
163     }
164
165     p_filter->pf_video_filter = Filter;
166     return VLC_SUCCESS;
167 }
168
169 static void Destroy(vlc_object_t *p_this)
170 {
171     filter_t *p_filter = (filter_t *)p_this;
172     filter_sys_t *p_sys = p_filter->p_sys;
173     free(p_sys);
174 }
175
176 static picture_t *Filter(filter_t *p_filter, picture_t *p_pic)
177 {
178     filter_sys_t *p_sys = p_filter->p_sys;
179
180     if (!p_pic)
181         return NULL;
182
183     picture_t *p_outpic = filter_NewPicture(p_filter);
184     if (!p_outpic)
185     {
186         picture_Release(p_pic);
187         return NULL;
188     }
189
190     switch (p_pic->format.i_chroma)
191     {
192         case VLC_CODEC_I420:
193         case VLC_CODEC_J420:
194         case VLC_CODEC_YV12:
195             combine_side_by_side_yuv420(p_pic, p_outpic,
196                                         p_sys->left, p_sys->right);
197             break;
198
199         default:
200             msg_Warn(p_filter, "Unsupported input chroma (%4.4s)",
201                      (char*)&(p_pic->format.i_chroma));
202             picture_Release(p_pic);
203             return NULL;
204     }
205
206     return CopyInfoAndRelease(p_outpic, p_pic);
207 }
208
209
210 static void combine_side_by_side_yuv420(picture_t *p_inpic, picture_t *p_outpic,
211                                         int left, int right)
212 {
213     uint8_t *y1inl = p_inpic->p[Y_PLANE].p_pixels;
214     uint8_t *y2inl;
215     uint8_t *uinl = p_inpic->p[U_PLANE].p_pixels;
216     uint8_t *vinl = p_inpic->p[V_PLANE].p_pixels;
217
218     uint8_t *y1out = p_outpic->p[Y_PLANE].p_pixels;
219     uint8_t *y2out;
220     uint8_t *uout = p_outpic->p[U_PLANE].p_pixels;
221     uint8_t *vout = p_outpic->p[V_PLANE].p_pixels;
222
223     const int in_pitch = p_inpic->p[Y_PLANE].i_pitch;
224     const int out_pitch = p_outpic->p[Y_PLANE].i_pitch;
225
226     const int visible_pitch = p_inpic->p[Y_PLANE].i_visible_pitch;
227     const int visible_lines = p_inpic->p[Y_PLANE].i_visible_lines;
228     const int uv_visible_pitch = p_inpic->p[U_PLANE].i_visible_pitch;
229
230     const uint8_t *yend = y1inl + visible_lines * in_pitch;
231
232     while (y1inl < yend)
233     {
234         uint8_t *y1inr = y1inl + visible_pitch/2;
235         uint8_t *y2inr;
236         uint8_t *uinr = uinl + uv_visible_pitch/2;
237         uint8_t *vinr = vinl + uv_visible_pitch/2;
238
239         const uint8_t *y1end = y1inr;
240         y2inl = y1inl + in_pitch;
241         y2inr = y1inr + in_pitch;
242         y2out = y1out + out_pitch;
243
244         while (y1inl < y1end)
245         {
246             int rl, gl, bl, rr, gr, br, r, g, b;
247
248             int rshift = !!((0xff0000&left) && (0xff0000&right));
249             int gshift = !!((0x00ff00&left) && (0x00ff00&right));
250             int bshift = !!((0x0000ff&left) && (0x0000ff&right));
251
252             yuv_to_rgb(&rl, &gl, &bl, *y1inl, *uinl, *vinl);
253             yuv_to_rgb(&rr, &gr, &br, *y1inr, *uinr, *vinr);
254             r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
255             g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
256             b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
257             rgb_to_yuv(y1out, uout++, vout++, r, g, b);
258             y1out[1] = *y1out;
259             y1out+=2;
260             y1inl++;
261             y1inr++;
262
263             yuv_to_rgb(&rl, &gl, &bl, *y1inl, *uinl, *vinl);
264             yuv_to_rgb(&rr, &gr, &br, *y1inr, *uinr, *vinr);
265             r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
266             g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
267             b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
268             rgb_to_yuv(y1out, uout++, vout++, r, g, b);
269             y1out[1] = *y1out;
270             y1out+=2;
271             y1inl++;
272             y1inr++;
273
274             yuv_to_rgb(&rl, &gl, &bl, *y2inl, *uinl, *vinl);
275             yuv_to_rgb(&rr, &gr, &br, *y2inr, *uinr, *vinr);
276             r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
277             g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
278             b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
279             rgb_to_yuv(y2out, uout/*will be overwritten later, as will vout*/, vout, r, g, b);
280             y2out[1] = *y2out;
281             y2out+=2;
282             y2inl++;
283             y2inr++;
284
285             yuv_to_rgb(&rl, &gl, &bl, *y2inl, *uinl, *vinl);
286             yuv_to_rgb(&rr, &gr, &br, *y2inr, *uinr, *vinr);
287             r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
288             g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
289             b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
290             rgb_to_yuv(y2out, uout/*will be overwritten later, as will vout*/, vout, r, g, b);
291             y2out[1] = *y2out;
292             y2out+=2;
293             y2inl++;
294             y2inr++;
295
296             uinl++;
297             vinl++;
298             uinr++;
299             vinr++;
300         }
301
302         y1inl = y1inr + 2*in_pitch - visible_pitch;
303         y1out += 2*out_pitch - visible_pitch;
304         uinl = uinr + p_inpic->p[U_PLANE].i_pitch - uv_visible_pitch;
305         vinl = vinr + p_inpic->p[V_PLANE].i_pitch - uv_visible_pitch;
306         uout += p_outpic->p[U_PLANE].i_pitch - uv_visible_pitch;
307         vout += p_outpic->p[V_PLANE].i_pitch - uv_visible_pitch;
308     }
309 }
310