]> git.sesse.net Git - vlc/blob - modules/video_filter/anaglyph.c
decoder: fix data race in input_DecoderChangePause()
[vlc] / 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     red_green = 1,
49     red_blue,
50     red_cyan,
51     trioscopic,
52     magenta_cyan,
53 };
54
55 static const char *const ppsz_scheme_values[] = {
56     "red-green",
57     "red-blue",
58     "red-cyan",
59     "trioscopic",
60     "magenta-cyan",
61     };
62 static const char *const ppsz_scheme_descriptions[] = {
63     "pure red (left)  pure green (right)",
64     "pure red (left)  pure blue (right)",
65     "pure red (left)  pure cyan (right)",
66     "pure green (left)  pure magenta (right)",
67     "magenta (left)  cyan (right)",
68     };
69
70 vlc_module_begin()
71     set_description(N_("Convert 3D picture to anaglyph image video filter"));
72     set_shortname(N_("Anaglyph"))
73     set_category(CAT_VIDEO)
74     set_subcategory(SUBCAT_VIDEO_VFILTER)
75     set_capability("video filter2", 0)
76     add_string(FILTER_PREFIX "scheme", "red-cyan", SCHEME_TEXT, SCHEME_LONGTEXT, false)
77         change_string_list(ppsz_scheme_values, ppsz_scheme_descriptions)
78     set_callbacks(Create, Destroy)
79 vlc_module_end()
80
81 static const char *const ppsz_filter_options[] = {
82     "scheme", NULL
83 };
84
85 struct filter_sys_t
86 {
87     int left, right;
88 };
89
90
91 static int Create(vlc_object_t *p_this)
92 {
93     filter_t *p_filter = (filter_t *)p_this;
94
95     switch (p_filter->fmt_in.video.i_chroma)
96     {
97         case VLC_CODEC_I420:
98         case VLC_CODEC_J420:
99         case VLC_CODEC_YV12:
100             break;
101
102         default:
103             msg_Err(p_filter, "Unsupported input chroma (%4.4s)",
104                     (char*)&(p_filter->fmt_in.video.i_chroma));
105             return VLC_EGENERIC;
106     }
107
108     p_filter->p_sys = malloc(sizeof(filter_sys_t));
109     if (!p_filter->p_sys)
110         return VLC_ENOMEM;
111     filter_sys_t *p_sys = p_filter->p_sys;
112
113     config_ChainParse(p_filter, FILTER_PREFIX, ppsz_filter_options,
114                       p_filter->p_cfg);
115
116     char *psz_scheme = var_CreateGetStringCommand(p_filter,
117                                                   FILTER_PREFIX "scheme");
118     enum scheme_e scheme = red_cyan;
119     if (psz_scheme)
120     {
121         if (!strcmp(psz_scheme, "red-green"))
122             scheme = red_green;
123         else if (!strcmp(psz_scheme, "red-blue"))
124             scheme = red_blue;
125         else if (!strcmp(psz_scheme, "red-cyan"))
126             scheme = red_cyan;
127         else if (!strcmp(psz_scheme, "trioscopic"))
128             scheme = trioscopic;
129         else if (!strcmp(psz_scheme, "magenta-cyan"))
130             scheme = magenta_cyan;
131         else
132             msg_Err(p_filter, "Unknown anaglyph color scheme '%s'", psz_scheme);
133     }
134     free(psz_scheme);
135
136     switch (scheme)
137     {
138         case red_green:
139             p_sys->left = 0xff0000;
140             p_sys->right = 0x00ff00;
141             break;
142         case red_blue:
143             p_sys->left = 0xff0000;
144             p_sys->right = 0x0000ff;
145             break;
146         case red_cyan:
147             p_sys->left = 0xff0000;
148             p_sys->right = 0x00ffff;
149             break;
150         case trioscopic:
151             p_sys->left = 0x00ff00;
152             p_sys->right = 0xff00ff;
153             break;
154         case magenta_cyan:
155             p_sys->left = 0xff00ff;
156             p_sys->right = 0x00ffff;
157             break;
158     }
159
160     p_filter->pf_video_filter = Filter;
161     return VLC_SUCCESS;
162 }
163
164 static void Destroy(vlc_object_t *p_this)
165 {
166     filter_t *p_filter = (filter_t *)p_this;
167     filter_sys_t *p_sys = p_filter->p_sys;
168     free(p_sys);
169 }
170
171 static picture_t *Filter(filter_t *p_filter, picture_t *p_pic)
172 {
173     filter_sys_t *p_sys = p_filter->p_sys;
174
175     if (!p_pic)
176         return NULL;
177
178     picture_t *p_outpic = filter_NewPicture(p_filter);
179     if (!p_outpic)
180     {
181         picture_Release(p_pic);
182         return NULL;
183     }
184
185     switch (p_pic->format.i_chroma)
186     {
187         case VLC_CODEC_I420:
188         case VLC_CODEC_J420:
189         case VLC_CODEC_YV12:
190             combine_side_by_side_yuv420(p_pic, p_outpic,
191                                         p_sys->left, p_sys->right);
192             break;
193
194         default:
195             msg_Warn(p_filter, "Unsupported input chroma (%4.4s)",
196                      (char*)&(p_pic->format.i_chroma));
197             picture_Release(p_pic);
198             return NULL;
199     }
200
201     return CopyInfoAndRelease(p_outpic, p_pic);
202 }
203
204
205 static void combine_side_by_side_yuv420(picture_t *p_inpic, picture_t *p_outpic,
206                                         int left, int right)
207 {
208     uint8_t *y1inl = p_inpic->p[Y_PLANE].p_pixels;
209     uint8_t *y2inl;
210     uint8_t *uinl = p_inpic->p[U_PLANE].p_pixels;
211     uint8_t *vinl = p_inpic->p[V_PLANE].p_pixels;
212
213     uint8_t *y1out = p_outpic->p[Y_PLANE].p_pixels;
214     uint8_t *y2out;
215     uint8_t *uout = p_outpic->p[U_PLANE].p_pixels;
216     uint8_t *vout = p_outpic->p[V_PLANE].p_pixels;
217
218     const int in_pitch = p_inpic->p[Y_PLANE].i_pitch;
219     const int out_pitch = p_outpic->p[Y_PLANE].i_pitch;
220
221     const int visible_pitch = p_inpic->p[Y_PLANE].i_visible_pitch;
222     const int visible_lines = p_inpic->p[Y_PLANE].i_visible_lines;
223     const int uv_visible_pitch = p_inpic->p[U_PLANE].i_visible_pitch;
224
225     const uint8_t *yend = y1inl + visible_lines * in_pitch;
226
227     while (y1inl < yend)
228     {
229         uint8_t *y1inr = y1inl + visible_pitch/2;
230         uint8_t *y2inr;
231         uint8_t *uinr = uinl + uv_visible_pitch/2;
232         uint8_t *vinr = vinl + uv_visible_pitch/2;
233
234         const uint8_t *y1end = y1inr;
235         y2inl = y1inl + in_pitch;
236         y2inr = y1inr + in_pitch;
237         y2out = y1out + out_pitch;
238
239         while (y1inl < y1end)
240         {
241             int rl, gl, bl, rr, gr, br, r, g, b;
242
243             int rshift = !!((0xff0000&left) && (0xff0000&right));
244             int gshift = !!((0x00ff00&left) && (0x00ff00&right));
245             int bshift = !!((0x0000ff&left) && (0x0000ff&right));
246
247             yuv_to_rgb(&rl, &gl, &bl, *y1inl, *uinl, *vinl);
248             yuv_to_rgb(&rr, &gr, &br, *y1inr, *uinr, *vinr);
249             r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
250             g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
251             b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
252             rgb_to_yuv(y1out, uout++, vout++, r, g, b);
253             y1out[1] = *y1out;
254             y1out+=2;
255             y1inl++;
256             y1inr++;
257
258             yuv_to_rgb(&rl, &gl, &bl, *y1inl, *uinl, *vinl);
259             yuv_to_rgb(&rr, &gr, &br, *y1inr, *uinr, *vinr);
260             r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
261             g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
262             b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
263             rgb_to_yuv(y1out, uout++, vout++, r, g, b);
264             y1out[1] = *y1out;
265             y1out+=2;
266             y1inl++;
267             y1inr++;
268
269             yuv_to_rgb(&rl, &gl, &bl, *y2inl, *uinl, *vinl);
270             yuv_to_rgb(&rr, &gr, &br, *y2inr, *uinr, *vinr);
271             r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
272             g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
273             b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
274             rgb_to_yuv(y2out, uout/*will be overwritten later, as will vout*/, vout, r, g, b);
275             y2out[1] = *y2out;
276             y2out+=2;
277             y2inl++;
278             y2inr++;
279
280             yuv_to_rgb(&rl, &gl, &bl, *y2inl, *uinl, *vinl);
281             yuv_to_rgb(&rr, &gr, &br, *y2inr, *uinr, *vinr);
282             r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
283             g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
284             b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
285             rgb_to_yuv(y2out, uout/*will be overwritten later, as will vout*/, vout, r, g, b);
286             y2out[1] = *y2out;
287             y2out+=2;
288             y2inl++;
289             y2inr++;
290
291             uinl++;
292             vinl++;
293             uinr++;
294             vinr++;
295         }
296
297         y1inl = y1inr + 2*in_pitch - visible_pitch;
298         y1out += 2*out_pitch - visible_pitch;
299         uinl = uinr + p_inpic->p[U_PLANE].i_pitch - uv_visible_pitch;
300         vinl = vinr + p_inpic->p[V_PLANE].i_pitch - uv_visible_pitch;
301         uout += p_outpic->p[U_PLANE].i_pitch - uv_visible_pitch;
302         vout += p_outpic->p[V_PLANE].i_pitch - uv_visible_pitch;
303     }
304 }
305