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
;
68 unsigned int row_left
;
69 unsigned int row_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
.off_left
= 0;
143 vf
->priv
->in
.off_right
= 0;
144 vf
->priv
->in
.row_left
= 0;
145 vf
->priv
->in
.row_right
= 0;
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;
153 case SIDE_BY_SIDE_RL
:
154 vf
->priv
->width
= width
/ 2;
155 vf
->priv
->in
.off_left
= vf
->priv
->width
* 3;
157 case ABOVE_BELOW_2_LR
:
160 vf
->priv
->height
= height
/ 2;
161 vf
->priv
->in
.row_right
= vf
->priv
->height
;
163 case ABOVE_BELOW_2_RL
:
166 vf
->priv
->height
= height
/ 2;
167 vf
->priv
->in
.row_left
= vf
->priv
->height
;
170 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
171 "[stereo3d] stereo format of input is not supported\n");
175 //default output values
176 vf
->priv
->out
.width
= vf
->priv
->width
;
177 vf
->priv
->out
.height
= vf
->priv
->height
;
178 vf
->priv
->out
.off_left
= 0;
179 vf
->priv
->out
.off_right
= 0;
180 vf
->priv
->out
.row_left
= 0;
181 vf
->priv
->out
.row_right
= 0;
183 //check output format
184 switch (vf
->priv
->out
.fmt
) {
185 case ANAGLYPH_RC_GRAY
:
186 case ANAGLYPH_RC_HALF
:
187 case ANAGLYPH_RC_COLOR
:
188 case ANAGLYPH_RC_DUBOIS
:
189 case ANAGLYPH_GM_GRAY
:
190 case ANAGLYPH_GM_HALF
:
191 case ANAGLYPH_GM_COLOR
:
192 case ANAGLYPH_YB_GRAY
:
193 case ANAGLYPH_YB_HALF
:
194 case ANAGLYPH_YB_COLOR
:
195 memcpy(vf
->priv
->ana_matrix
, ana_coeff
[vf
->priv
->out
.fmt
],
196 sizeof(vf
->priv
->ana_matrix
));
198 case SIDE_BY_SIDE_LR
:
199 vf
->priv
->out
.width
= vf
->priv
->width
* 2;
200 vf
->priv
->out
.off_right
= vf
->priv
->width
* 3;
202 case SIDE_BY_SIDE_RL
:
203 vf
->priv
->out
.width
= vf
->priv
->width
* 2;
204 vf
->priv
->out
.off_left
= vf
->priv
->width
* 3;
206 case ABOVE_BELOW_2_LR
:
209 vf
->priv
->out
.height
= vf
->priv
->height
* 2;
210 vf
->priv
->out
.row_right
= vf
->priv
->height
;
212 case ABOVE_BELOW_2_RL
:
215 vf
->priv
->out
.height
= vf
->priv
->height
* 2;
216 vf
->priv
->out
.row_left
= vf
->priv
->height
;
219 //same as MONO_L only needs switching of input offsets
220 vf
->priv
->in
.off_left
= vf
->priv
->in
.off_right
;
221 vf
->priv
->in
.row_left
= vf
->priv
->in
.row_right
;
224 //use default settings
227 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
228 "[stereo3d] stereo format of output is not supported\n");
232 if (!opts
->screen_size_x
&& !opts
->screen_size_y
) {
233 d_width
= d_width
* vf
->priv
->out
.width
/ width
;
234 d_height
= d_height
* vf
->priv
->out
.height
/ height
;
236 return vf_next_config(vf
, vf
->priv
->out
.width
, vf
->priv
->out
.height
,
237 d_width
, d_height
, flags
, outfmt
);
240 static int put_image(struct vf_instance
*vf
, mp_image_t
*mpi
, double pts
)
243 if (vf
->priv
->in
.fmt
== vf
->priv
->out
.fmt
) { //nothing to do
246 int out_off_left
, out_off_right
;
247 int in_off_left
= vf
->priv
->in
.row_left
* mpi
->stride
[0] +
248 vf
->priv
->in
.off_left
;
249 int in_off_right
= vf
->priv
->in
.row_right
* mpi
->stride
[0] +
250 vf
->priv
->in
.off_right
;
252 dmpi
= vf_get_image(vf
->next
, IMGFMT_RGB24
, MP_IMGTYPE_TEMP
,
253 MP_IMGFLAG_ACCEPT_STRIDE
,
254 vf
->priv
->out
.width
, vf
->priv
->out
.height
);
255 out_off_left
= vf
->priv
->out
.row_left
* dmpi
->stride
[0] +
256 vf
->priv
->out
.off_left
;
257 out_off_right
= vf
->priv
->out
.row_right
* dmpi
->stride
[0] +
258 vf
->priv
->out
.off_right
;
260 switch (vf
->priv
->out
.fmt
) {
261 case SIDE_BY_SIDE_LR
:
262 case SIDE_BY_SIDE_RL
:
265 case ABOVE_BELOW_2_LR
:
266 case ABOVE_BELOW_2_RL
:
267 memcpy_pic(dmpi
->planes
[0] + out_off_left
,
268 mpi
->planes
[0] + in_off_left
,
273 memcpy_pic(dmpi
->planes
[0] + out_off_right
,
274 mpi
->planes
[0] + in_off_right
,
282 memcpy_pic(dmpi
->planes
[0],
283 mpi
->planes
[0] + in_off_left
,
289 case ANAGLYPH_RC_GRAY
:
290 case ANAGLYPH_RC_HALF
:
291 case ANAGLYPH_RC_COLOR
:
292 case ANAGLYPH_RC_DUBOIS
:
293 case ANAGLYPH_GM_GRAY
:
294 case ANAGLYPH_GM_HALF
:
295 case ANAGLYPH_GM_COLOR
:
296 case ANAGLYPH_YB_GRAY
:
297 case ANAGLYPH_YB_HALF
:
298 case ANAGLYPH_YB_COLOR
: {
300 unsigned char *source
= mpi
->planes
[0];
301 unsigned char *dest
= dmpi
->planes
[0];
302 unsigned int out_width
= vf
->priv
->out
.width
;
305 for(int i
= 0; i
< 3; i
++)
306 ana_matrix
[i
] = vf
->priv
->ana_matrix
[i
];
308 for (y
= 0; y
< vf
->priv
->out
.height
; y
++) {
309 o
= dmpi
->stride
[0] * y
;
310 il
= in_off_left
+ y
* mpi
->stride
[0];
311 ir
= in_off_right
+ y
* mpi
->stride
[0];
312 for (x
= 0; x
< out_width
; x
++) {
313 dest
[o
] = ana_convert(
314 ana_matrix
[0], source
+ il
, source
+ ir
); //red out
315 dest
[o
+ 1] = ana_convert(
316 ana_matrix
[1], source
+ il
, source
+ ir
); //green out
317 dest
[o
+ 2] = ana_convert(
318 ana_matrix
[2], source
+ il
, source
+ ir
); //blue out
327 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
328 "[stereo3d] stereo format of output is not supported\n");
333 return vf_next_put_image(vf
, dmpi
, pts
);
336 static int query_format(struct vf_instance
*vf
, unsigned int fmt
)
340 return vf_next_query_format(vf
, fmt
);
344 static void uninit(vf_instance_t
*vf
)
349 static int vf_open(vf_instance_t
*vf
, char *args
)
353 vf
->put_image
= put_image
;
354 vf
->query_format
= query_format
;
360 static const struct format_preset
{
363 } vf_format_presets_defs
[] = {
364 {"arcg", ANAGLYPH_RC_GRAY
},
365 {"anaglyph_red_cyan_gray", ANAGLYPH_RC_GRAY
},
366 {"arch", ANAGLYPH_RC_HALF
},
367 {"anaglyph_red_cyan_half_color", ANAGLYPH_RC_HALF
},
368 {"arcc", ANAGLYPH_RC_COLOR
},
369 {"anaglyph_red_cyan_color", ANAGLYPH_RC_COLOR
},
370 {"arcd", ANAGLYPH_RC_DUBOIS
},
371 {"anaglyph_red_cyan_dubios", ANAGLYPH_RC_DUBOIS
},
372 {"agmg", ANAGLYPH_GM_GRAY
},
373 {"anaglyph_green_magenta_gray", ANAGLYPH_GM_GRAY
},
374 {"agmh", ANAGLYPH_GM_HALF
},
375 {"anaglyph_green_magenta_half_color",ANAGLYPH_GM_HALF
},
376 {"agmc", ANAGLYPH_GM_COLOR
},
377 {"anaglyph_green_magenta_color", ANAGLYPH_GM_COLOR
},
378 {"aybg", ANAGLYPH_YB_GRAY
},
379 {"anaglyph_yellow_blue_gray", ANAGLYPH_YB_GRAY
},
380 {"aybh", ANAGLYPH_YB_HALF
},
381 {"anaglyph_yellow_blue_half_color", ANAGLYPH_YB_HALF
},
382 {"aybc", ANAGLYPH_YB_COLOR
},
383 {"anaglyph_yellow_blue_color", ANAGLYPH_YB_COLOR
},
385 {"mono_left", MONO_L
},
387 {"mono_right", MONO_R
},
388 {"sbsl", SIDE_BY_SIDE_LR
},
389 {"side_by_side_left_first", SIDE_BY_SIDE_LR
},
390 {"sbsr", SIDE_BY_SIDE_RL
},
391 {"side_by_side_right_first", SIDE_BY_SIDE_RL
},
392 {"abl", ABOVE_BELOW_LR
},
393 {"above_below_left_first", ABOVE_BELOW_LR
},
394 {"abr", ABOVE_BELOW_RL
},
395 {"above_below_right_first", ABOVE_BELOW_RL
},
396 {"ab2l", ABOVE_BELOW_2_LR
},
397 {"above_below_half_height_left_first", ABOVE_BELOW_2_LR
},
398 {"ab2r", ABOVE_BELOW_2_RL
},
399 {"above_below_half_height_right_first",ABOVE_BELOW_2_RL
},
403 #define ST_OFF(f) M_ST_OFF(struct format_preset,f)
404 static const m_option_t vf_format_preset_fields_in
[] = {
405 {"in", ST_OFF(scode
), CONF_TYPE_INT
, 0,0,0, NULL
},
406 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
408 static const m_option_t vf_format_preset_fields_out
[] = {
409 {"out", ST_OFF(scode
), CONF_TYPE_INT
, 0,0,0, NULL
},
410 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
413 static const m_struct_t vf_format_preset_in
= {
414 "stereo_format_preset_in",
415 sizeof(struct format_preset
),
417 vf_format_preset_fields_in
419 static const m_struct_t vf_format_preset_out
= {
420 "stereo_format_preset_out",
421 sizeof(struct format_preset
),
423 vf_format_preset_fields_out
426 static const m_struct_t vf_opts
;
427 static const m_obj_presets_t format_preset_in
= {
428 (struct m_struct_st
*)&vf_format_preset_in
,
429 (struct m_struct_st
*)&vf_opts
,
430 (struct format_preset
*)vf_format_presets_defs
,
433 static const m_obj_presets_t format_preset_out
= {
434 (struct m_struct_st
*)&vf_format_preset_out
,
435 (struct m_struct_st
*)&vf_opts
,
436 (struct format_preset
*)vf_format_presets_defs
,
442 #define ST_OFF(f) M_ST_OFF(struct vf_priv_s,f)
443 static const m_option_t vf_opts_fields
[] = {
444 {"stereo_in", 0, CONF_TYPE_OBJ_PRESETS
, 0, 0, 0,
445 (m_obj_presets_t
*)&format_preset_in
},
446 {"stereo_out", 0, CONF_TYPE_OBJ_PRESETS
, 0, 0, 0,
447 (m_obj_presets_t
*)&format_preset_out
},
448 {"in", ST_OFF(in
.fmt
), CONF_TYPE_INT
, 0,0,0, NULL
},
449 {"out", ST_OFF(out
.fmt
), CONF_TYPE_INT
, 0,0,0, NULL
},
450 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
453 static const m_struct_t vf_opts
= {
455 sizeof(struct vf_priv_s
),
462 const vf_info_t vf_info_stereo3d
= {
463 "stereoscopic 3d view",
466 "view stereoscopic videos",