2 * Copyright (C) 2010 Gordon Schmidt <gordon.schmidt <at> s2000.tu-chemnitz.de>
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "img_format.h"
36 #include "libavutil/common.h"
37 #include "libvo/fastmemcpy.h"
40 typedef enum stereo_code
{
41 ANAGLYPH_RC_GRAY
, //anaglyph red/cyan gray
42 ANAGLYPH_RC_HALF
, //anaglyph red/cyan half colored
43 ANAGLYPH_RC_COLOR
, //anaglyph red/cyan colored
44 ANAGLYPH_RC_DUBOIS
, //anaglyph red/cyan dubois
45 ANAGLYPH_GM_GRAY
, //anaglyph green/magenta gray
46 ANAGLYPH_GM_HALF
, //anaglyph green/magenta half colored
47 ANAGLYPH_GM_COLOR
, //anaglyph green/magenta colored
48 ANAGLYPH_YB_GRAY
, //anaglyph yellow/blue gray
49 ANAGLYPH_YB_HALF
, //anaglyph yellow/blue half colored
50 ANAGLYPH_YB_COLOR
, //anaglyph yellow/blue colored
51 MONO_L
, //mono output for debugging (left eye only)
52 MONO_R
, //mono output for debugging (right eye only)
53 SIDE_BY_SIDE_LR
, //side by side parallel (left eye left, right eye right)
54 SIDE_BY_SIDE_RL
, //side by side crosseye (right eye left, left eye right)
55 ABOVE_BELOW_LR
, //above-below (left eye above, right eye below)
56 ABOVE_BELOW_RL
, //above-below (right eye above, left eye below)
57 ABOVE_BELOW_2_LR
, //above-below with half height resolution
58 ABOVE_BELOW_2_RL
, //above-below with half height resolution
59 STEREO_CODE_COUNT
//no value set - TODO: needs autodetection
62 typedef struct component
{
66 unsigned int off_left
;
67 unsigned int off_right
;
72 //==global variables==//
73 static const int ana_coeff
[10][3][6] = {
74 {{19595, 38470, 7471, 0, 0, 0}, //ANAGLYPH_RC_GRAY
75 { 0, 0, 0, 19595, 38470, 7471},
76 { 0, 0, 0, 19595, 38470, 7471}},
77 {{19595, 38470, 7471, 0, 0, 0}, //ANAGLYPH_RC_HALF
78 { 0, 0, 0, 0, 65536, 0},
79 { 0, 0, 0, 0, 0, 65536}},
80 {{65536, 0, 0, 0, 0, 0}, //ANAGLYPH_RC_COLOR
81 { 0, 0, 0, 0, 65536, 0},
82 { 0, 0, 0, 0, 0, 65536}},
83 {{29891, 32800, 11559, -2849, -5763, -102}, //ANAGLYPH_RC_DUBOIS
84 {-2627, -2479, -1033, 24804, 48080, -1209},
85 { -997, -1350, -358, -4729, -7403, 80373}},
86 {{ 0, 0, 0, 19595, 38470, 7471}, //ANAGLYPH_GM_GRAY
87 {19595, 38470, 7471, 0, 0, 0},
88 { 0, 0, 0, 19595, 38470, 7471}},
89 {{ 0, 0, 0, 65536, 0, 0}, //ANAGLYPH_GM_HALF
90 {19595, 38470, 7471, 0, 0, 0},
91 { 0, 0, 0, 0, 0, 65536}},
92 {{ 0, 0, 0, 65536, 0, 0}, //ANAGLYPH_GM_COLOR
93 { 0, 65536, 0, 0, 0, 0},
94 { 0, 0, 0, 0, 0, 65536}},
95 {{ 0, 0, 0, 19595, 38470, 7471}, //ANAGLYPH_YB_GRAY
96 { 0, 0, 0, 19595, 38470, 7471},
97 {19595, 38470, 7471, 0, 0, 0}},
98 {{ 0, 0, 0, 65536, 0, 0}, //ANAGLYPH_YB_HALF
99 { 0, 0, 0, 0, 65536, 0},
100 {19595, 38470, 7471, 0, 0, 0}},
101 {{ 0, 0, 0, 65536, 0, 0}, //ANAGLYPH_YB_COLOR
102 { 0, 0, 0, 0, 65536, 0},
103 { 0, 0, 65536, 0, 0, 0}}
109 int ana_matrix
[3][6];
112 } const vf_priv_default
= {
118 static inline uint8_t ana_convert(int coeff
[6], uint8_t left
[3], uint8_t right
[3])
122 sum
= coeff
[0] * left
[0] + coeff
[3] * right
[0]; //red in
123 sum
+= coeff
[1] * left
[1] + coeff
[4] * right
[1]; //green in
124 sum
+= coeff
[2] * left
[2] + coeff
[5] * right
[2]; //blue in
125 return av_clip_uint8(sum
>> 16);
128 static int config(struct vf_instance
*vf
, int width
, int height
, int d_width
,
129 int d_height
, unsigned int flags
, unsigned int outfmt
)
131 struct MPOpts
*opts
= vf
->opts
;
133 if ((width
& 1) || (height
& 1)) {
134 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "[stereo3d] invalid height or width\n");
137 //default input values
138 vf
->priv
->width
= width
;
139 vf
->priv
->height
= height
;
140 vf
->priv
->in
.width
= width
;
141 vf
->priv
->in
.height
= height
;
142 vf
->priv
->in
.hres
= 1;
143 vf
->priv
->in
.off_left
= 0;
144 vf
->priv
->in
.off_right
= 0;
145 vf
->priv
->in
.stride
= vf
->priv
->width
* 3;
148 switch (vf
->priv
->in
.fmt
) {
149 case SIDE_BY_SIDE_LR
:
150 vf
->priv
->width
= width
/ 2;
151 vf
->priv
->in
.off_right
= vf
->priv
->width
* 3;
152 vf
->priv
->in
.stride
= vf
->priv
->width
* 6;
154 case SIDE_BY_SIDE_RL
:
155 vf
->priv
->width
= width
/ 2;
156 vf
->priv
->in
.off_left
= vf
->priv
->width
* 3;
157 vf
->priv
->in
.stride
= vf
->priv
->width
* 6;
160 vf
->priv
->height
= height
/ 2;
161 vf
->priv
->in
.off_right
= vf
->priv
->width
* vf
->priv
->height
* 3;
164 vf
->priv
->height
= height
/ 2;
165 vf
->priv
->in
.off_left
= vf
->priv
->width
* vf
->priv
->height
* 3;
167 case ABOVE_BELOW_2_LR
:
168 vf
->priv
->in
.hres
= 2;
169 vf
->priv
->in
.off_right
= vf
->priv
->width
* vf
->priv
->height
/ 2 * 3;
171 case ABOVE_BELOW_2_RL
:
172 vf
->priv
->in
.hres
= 2;
173 vf
->priv
->in
.off_left
= vf
->priv
->width
* vf
->priv
->height
/ 2 * 3;
176 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
177 "[stereo3d] stereo format of input is not supported\n");
181 //default output values
182 vf
->priv
->out
.width
= vf
->priv
->width
;
183 vf
->priv
->out
.height
= vf
->priv
->height
;
184 vf
->priv
->out
.hres
= 1;
185 vf
->priv
->out
.off_left
= 0;
186 vf
->priv
->out
.off_right
= 0;
187 vf
->priv
->out
.stride
= vf
->priv
->width
* 3;
189 //check output format
190 switch (vf
->priv
->out
.fmt
) {
191 case ANAGLYPH_RC_GRAY
:
192 case ANAGLYPH_RC_HALF
:
193 case ANAGLYPH_RC_COLOR
:
194 case ANAGLYPH_RC_DUBOIS
:
195 case ANAGLYPH_GM_GRAY
:
196 case ANAGLYPH_GM_HALF
:
197 case ANAGLYPH_GM_COLOR
:
198 case ANAGLYPH_YB_GRAY
:
199 case ANAGLYPH_YB_HALF
:
200 case ANAGLYPH_YB_COLOR
:
201 memcpy(vf
->priv
->ana_matrix
, ana_coeff
[vf
->priv
->out
.fmt
],
202 sizeof(vf
->priv
->ana_matrix
));
204 case SIDE_BY_SIDE_LR
:
205 vf
->priv
->out
.width
= vf
->priv
->width
* 2;
206 vf
->priv
->out
.off_right
= vf
->priv
->width
* 3;
207 vf
->priv
->out
.stride
= vf
->priv
->width
* 6;
209 case SIDE_BY_SIDE_RL
:
210 vf
->priv
->out
.width
= vf
->priv
->width
* 2;
211 vf
->priv
->out
.off_left
= vf
->priv
->width
* 3;
212 vf
->priv
->out
.stride
= vf
->priv
->width
* 6;
215 vf
->priv
->out
.height
= vf
->priv
->height
* 2;
216 vf
->priv
->out
.off_right
= vf
->priv
->width
* vf
->priv
->height
* 3;
219 vf
->priv
->out
.height
= vf
->priv
->height
* 2;
220 vf
->priv
->out
.off_left
= vf
->priv
->width
* vf
->priv
->height
* 3;
222 case ABOVE_BELOW_2_LR
:
223 vf
->priv
->out
.hres
= 2;
224 vf
->priv
->out
.off_right
= vf
->priv
->width
* vf
->priv
->height
/ 2 * 3;
226 case ABOVE_BELOW_2_RL
:
227 vf
->priv
->out
.hres
= 2;
228 vf
->priv
->out
.off_left
= vf
->priv
->width
* vf
->priv
->height
/ 2 * 3;
231 //same as MONO_L only needs switching of input offsets
232 vf
->priv
->in
.off_left
= vf
->priv
->in
.off_right
;
235 //use default settings
238 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
239 "[stereo3d] stereo format of output is not supported\n");
243 if (!opts
->screen_size_x
&& !opts
->screen_size_y
) {
244 d_width
= d_width
* vf
->priv
->out
.width
/ width
;
245 d_height
= d_height
* vf
->priv
->out
.height
/ height
;
247 return vf_next_config(vf
, vf
->priv
->out
.width
, vf
->priv
->out
.height
,
248 d_width
, d_height
, flags
, outfmt
);
251 static int put_image(struct vf_instance
*vf
, mp_image_t
*mpi
, double pts
)
254 if (vf
->priv
->in
.fmt
== vf
->priv
->out
.fmt
) { //nothing to do
257 dmpi
= vf_get_image(vf
->next
, IMGFMT_RGB24
, MP_IMGTYPE_TEMP
, 0,
258 vf
->priv
->out
.width
, vf
->priv
->out
.height
);
259 dmpi
->h
= vf
->priv
->out
.height
;
260 dmpi
->width
= vf
->priv
->out
.width
;
261 switch (vf
->priv
->out
.fmt
) {
262 case SIDE_BY_SIDE_LR
:
263 case SIDE_BY_SIDE_RL
:
266 case ABOVE_BELOW_2_LR
:
267 case ABOVE_BELOW_2_RL
:
268 for (int i
= 0; i
< vf
->priv
->in
.hres
; i
++) {
269 memcpy_pic(dmpi
->planes
[0] + vf
->priv
->out
.off_left
+
270 (i
* vf
->priv
->out
.stride
), mpi
->planes
[0] +
271 vf
->priv
->in
.off_left
, 3 * vf
->priv
->width
,
272 vf
->priv
->height
/ (vf
->priv
->in
.hres
*
273 vf
->priv
->out
.hres
), vf
->priv
->out
.stride
*
274 vf
->priv
->in
.hres
, vf
->priv
->in
.stride
*
276 memcpy_pic(dmpi
->planes
[0] + vf
->priv
->out
.off_right
+
277 (i
* vf
->priv
->out
.stride
), mpi
->planes
[0] +
278 vf
->priv
->in
.off_right
, 3 * vf
->priv
->width
,
279 vf
->priv
->height
/ (vf
->priv
->in
.hres
*
280 vf
->priv
->out
.hres
), vf
->priv
->out
.stride
*
281 vf
->priv
->in
.hres
, vf
->priv
->in
.stride
*
287 for (int i
= 0; i
< vf
->priv
->in
.hres
; i
++) {
288 memcpy_pic(dmpi
->planes
[0] + (i
* vf
->priv
->out
.stride
),
289 mpi
->planes
[0] + vf
->priv
->in
.off_left
, 3 *
290 vf
->priv
->width
, vf
->priv
->height
/
291 vf
->priv
->in
.hres
, vf
->priv
->out
.stride
*
292 vf
->priv
->in
.hres
, vf
->priv
->in
.stride
);
295 case ANAGLYPH_RC_GRAY
:
296 case ANAGLYPH_RC_HALF
:
297 case ANAGLYPH_RC_COLOR
:
298 case ANAGLYPH_RC_DUBOIS
:
299 case ANAGLYPH_GM_GRAY
:
300 case ANAGLYPH_GM_HALF
:
301 case ANAGLYPH_GM_COLOR
:
302 case ANAGLYPH_YB_GRAY
:
303 case ANAGLYPH_YB_HALF
:
304 case ANAGLYPH_YB_COLOR
: {
306 unsigned char *source
= mpi
->planes
[0];
307 unsigned char *dest
= dmpi
->planes
[0];
308 unsigned int out_width
= vf
->priv
->out
.width
;
311 for(int i
= 0; i
< 3; i
++)
312 ana_matrix
[i
] = vf
->priv
->ana_matrix
[i
];
314 for (y
= 0; y
< vf
->priv
->out
.height
; y
++) {
315 o
= vf
->priv
->out
.stride
* y
;
316 il
= vf
->priv
->in
.off_left
+ (y
/ vf
->priv
->in
.hres
) *
318 ir
= vf
->priv
->in
.off_right
+ (y
/ vf
->priv
->in
.hres
) *
320 for (x
= 0; x
< out_width
; x
++) {
321 dest
[o
] = ana_convert(
322 ana_matrix
[0], source
+ il
, source
+ ir
); //red out
323 dest
[o
+ 1] = ana_convert(
324 ana_matrix
[1], source
+ il
, source
+ ir
); //green out
325 dest
[o
+ 2] = ana_convert(
326 ana_matrix
[2], source
+ il
, source
+ ir
); //blue out
335 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
336 "[stereo3d] stereo format of output is not supported\n");
341 return vf_next_put_image(vf
, dmpi
, pts
);
344 static int query_format(struct vf_instance
*vf
, unsigned int fmt
)
348 return vf_next_query_format(vf
, fmt
);
352 static void uninit(vf_instance_t
*vf
)
357 static int vf_open(vf_instance_t
*vf
, char *args
)
361 vf
->put_image
= put_image
;
362 vf
->query_format
= query_format
;
363 vf
->default_reqs
= VFCAP_ACCEPT_STRIDE
;
369 static const struct format_preset
{
372 } vf_format_presets_defs
[] = {
373 {"arcg", ANAGLYPH_RC_GRAY
},
374 {"anaglyph_red_cyan_gray", ANAGLYPH_RC_GRAY
},
375 {"arch", ANAGLYPH_RC_HALF
},
376 {"anaglyph_red_cyan_half_color", ANAGLYPH_RC_HALF
},
377 {"arcc", ANAGLYPH_RC_COLOR
},
378 {"anaglyph_red_cyan_color", ANAGLYPH_RC_COLOR
},
379 {"arcd", ANAGLYPH_RC_DUBOIS
},
380 {"anaglyph_red_cyan_dubios", ANAGLYPH_RC_DUBOIS
},
381 {"agmg", ANAGLYPH_GM_GRAY
},
382 {"anaglyph_green_magenta_gray", ANAGLYPH_GM_GRAY
},
383 {"agmh", ANAGLYPH_GM_HALF
},
384 {"anaglyph_green_magenta_half_color",ANAGLYPH_GM_HALF
},
385 {"agmc", ANAGLYPH_GM_COLOR
},
386 {"anaglyph_green_magenta_color", ANAGLYPH_GM_COLOR
},
387 {"aybg", ANAGLYPH_YB_GRAY
},
388 {"anaglyph_yellow_blue_gray", ANAGLYPH_YB_GRAY
},
389 {"aybh", ANAGLYPH_YB_HALF
},
390 {"anaglyph_yellow_blue_half_color", ANAGLYPH_YB_HALF
},
391 {"aybc", ANAGLYPH_YB_COLOR
},
392 {"anaglyph_yellow_blue_color", ANAGLYPH_YB_COLOR
},
394 {"mono_left", MONO_L
},
396 {"mono_right", MONO_R
},
397 {"sbsl", SIDE_BY_SIDE_LR
},
398 {"side_by_side_left_first", SIDE_BY_SIDE_LR
},
399 {"sbsr", SIDE_BY_SIDE_RL
},
400 {"side_by_side_right_first", SIDE_BY_SIDE_RL
},
401 {"abl", ABOVE_BELOW_LR
},
402 {"above_below_left_first", ABOVE_BELOW_LR
},
403 {"abr", ABOVE_BELOW_RL
},
404 {"above_below_right_first", ABOVE_BELOW_RL
},
405 {"ab2l", ABOVE_BELOW_2_LR
},
406 {"above_below_half_height_left_first", ABOVE_BELOW_2_LR
},
407 {"ab2r", ABOVE_BELOW_2_RL
},
408 {"above_below_half_height_right_first",ABOVE_BELOW_2_RL
},
412 #define ST_OFF(f) M_ST_OFF(struct format_preset,f)
413 static const m_option_t vf_format_preset_fields_in
[] = {
414 {"in", ST_OFF(scode
), CONF_TYPE_INT
, 0,0,0, NULL
},
415 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
417 static const m_option_t vf_format_preset_fields_out
[] = {
418 {"out", ST_OFF(scode
), CONF_TYPE_INT
, 0,0,0, NULL
},
419 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
422 static const m_struct_t vf_format_preset_in
= {
423 "stereo_format_preset_in",
424 sizeof(struct format_preset
),
426 vf_format_preset_fields_in
428 static const m_struct_t vf_format_preset_out
= {
429 "stereo_format_preset_out",
430 sizeof(struct format_preset
),
432 vf_format_preset_fields_out
435 static const m_struct_t vf_opts
;
436 static const m_obj_presets_t format_preset_in
= {
437 (struct m_struct_st
*)&vf_format_preset_in
,
438 (struct m_struct_st
*)&vf_opts
,
439 (struct format_preset
*)vf_format_presets_defs
,
442 static const m_obj_presets_t format_preset_out
= {
443 (struct m_struct_st
*)&vf_format_preset_out
,
444 (struct m_struct_st
*)&vf_opts
,
445 (struct format_preset
*)vf_format_presets_defs
,
451 #define ST_OFF(f) M_ST_OFF(struct vf_priv_s,f)
452 static const m_option_t vf_opts_fields
[] = {
453 {"stereo_in", 0, CONF_TYPE_OBJ_PRESETS
, 0, 0, 0,
454 (m_obj_presets_t
*)&format_preset_in
},
455 {"stereo_out", 0, CONF_TYPE_OBJ_PRESETS
, 0, 0, 0,
456 (m_obj_presets_t
*)&format_preset_out
},
457 {"in", ST_OFF(in
.fmt
), CONF_TYPE_INT
, 0,0,0, NULL
},
458 {"out", ST_OFF(out
.fmt
), CONF_TYPE_INT
, 0,0,0, NULL
},
459 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
462 static const m_struct_t vf_opts
= {
464 sizeof(struct vf_priv_s
),
471 const vf_info_t vf_info_stereo3d
= {
472 "stereoscopic 3d view",
475 "view stereoscopic videos",