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_GM_DUBOIS
, //anaglyph green/magenta dubois
49 ANAGLYPH_YB_GRAY
, //anaglyph yellow/blue gray
50 ANAGLYPH_YB_HALF
, //anaglyph yellow/blue half colored
51 ANAGLYPH_YB_COLOR
, //anaglyph yellow/blue colored
52 ANAGLYPH_YB_DUBOIS
, //anaglyph yellow/blue dubois
53 MONO_L
, //mono output for debugging (left eye only)
54 MONO_R
, //mono output for debugging (right eye only)
55 SIDE_BY_SIDE_LR
, //side by side parallel (left eye left, right eye right)
56 SIDE_BY_SIDE_RL
, //side by side crosseye (right eye left, left eye right)
57 SIDE_BY_SIDE_2_LR
, //side by side parallel with half width resolution
58 SIDE_BY_SIDE_2_RL
, //side by side crosseye with half width resolution
59 ABOVE_BELOW_LR
, //above-below (left eye above, right eye below)
60 ABOVE_BELOW_RL
, //above-below (right eye above, left eye below)
61 ABOVE_BELOW_2_LR
, //above-below with half height resolution
62 ABOVE_BELOW_2_RL
, //above-below with half height resolution
63 INTERLEAVE_ROWS_LR
, //row-interleave (left eye has top row)
64 INTERLEAVE_ROWS_RL
, //row-interleave (right eye has top row)
65 STEREO_CODE_COUNT
//no value set - TODO: needs autodetection
68 typedef struct component
{
72 unsigned int off_left
;
73 unsigned int off_right
;
74 unsigned int row_left
;
75 unsigned int row_right
;
78 //==global variables==//
79 static const int ana_coeff
[][3][6] = {
81 {{19595, 38470, 7471, 0, 0, 0},
82 { 0, 0, 0, 19595, 38470, 7471},
83 { 0, 0, 0, 19595, 38470, 7471}},
85 {{19595, 38470, 7471, 0, 0, 0},
86 { 0, 0, 0, 0, 65536, 0},
87 { 0, 0, 0, 0, 0, 65536}},
89 {{65536, 0, 0, 0, 0, 0},
90 { 0, 0, 0, 0, 65536, 0},
91 { 0, 0, 0, 0, 0, 65536}},
92 [ANAGLYPH_RC_DUBOIS
] =
93 {{29891, 32800, 11559, -2849, -5763, -102},
94 {-2627, -2479, -1033, 24804, 48080, -1209},
95 { -997, -1350, -358, -4729, -7403, 80373}},
97 {{ 0, 0, 0, 19595, 38470, 7471},
98 {19595, 38470, 7471, 0, 0, 0},
99 { 0, 0, 0, 19595, 38470, 7471}},
101 {{ 0, 0, 0, 65536, 0, 0},
102 {19595, 38470, 7471, 0, 0, 0},
103 { 0, 0, 0, 0, 0, 65536}},
104 [ANAGLYPH_GM_COLOR
] =
105 {{ 0, 0, 0, 65536, 0, 0},
106 { 0, 65536, 0, 0, 0, 0},
107 { 0, 0, 0, 0, 0, 65536}},
108 [ANAGLYPH_GM_DUBOIS
] =
109 {{-4063,-10354, -2556, 34669, 46203, 1573},
110 {18612, 43778, 9372, -1049, -983, -4260},
111 { -983, -1769, 1376, 590, 4915, 61407}},
113 {{ 0, 0, 0, 19595, 38470, 7471},
114 { 0, 0, 0, 19595, 38470, 7471},
115 {19595, 38470, 7471, 0, 0, 0}},
117 {{ 0, 0, 0, 65536, 0, 0},
118 { 0, 0, 0, 0, 65536, 0},
119 {19595, 38470, 7471, 0, 0, 0}},
120 [ANAGLYPH_YB_COLOR
] =
121 {{ 0, 0, 0, 65536, 0, 0},
122 { 0, 0, 0, 0, 65536, 0},
123 { 0, 0, 65536, 0, 0, 0}},
124 [ANAGLYPH_YB_DUBOIS
] =
125 {{65535,-12650,18451, -987, -7590, -1049},
126 {-1604, 56032, 4196, 370, 3826, -1049},
127 {-2345,-10676, 1358, 5801, 11416, 56217}},
133 int ana_matrix
[3][6];
136 unsigned int row_step
;
137 } const vf_priv_default
= {
143 static inline uint8_t ana_convert(int coeff
[6], uint8_t left
[3], uint8_t right
[3])
147 sum
= coeff
[0] * left
[0] + coeff
[3] * right
[0]; //red in
148 sum
+= coeff
[1] * left
[1] + coeff
[4] * right
[1]; //green in
149 sum
+= coeff
[2] * left
[2] + coeff
[5] * right
[2]; //blue in
150 return av_clip_uint8(sum
>> 16);
153 static int config(struct vf_instance
*vf
, int width
, int height
, int d_width
,
154 int d_height
, unsigned int flags
, unsigned int outfmt
)
156 struct MPOpts
*opts
= vf
->opts
;
158 if ((width
& 1) || (height
& 1)) {
159 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "[stereo3d] invalid height or width\n");
162 //default input values
163 vf
->priv
->width
= width
;
164 vf
->priv
->height
= height
;
165 vf
->priv
->row_step
= 1;
166 vf
->priv
->in
.width
= width
;
167 vf
->priv
->in
.height
= height
;
168 vf
->priv
->in
.off_left
= 0;
169 vf
->priv
->in
.off_right
= 0;
170 vf
->priv
->in
.row_left
= 0;
171 vf
->priv
->in
.row_right
= 0;
174 switch (vf
->priv
->in
.fmt
) {
175 case SIDE_BY_SIDE_2_LR
:
177 case SIDE_BY_SIDE_LR
:
178 vf
->priv
->width
= width
/ 2;
179 vf
->priv
->in
.off_right
= vf
->priv
->width
* 3;
181 case SIDE_BY_SIDE_2_RL
:
183 case SIDE_BY_SIDE_RL
:
184 vf
->priv
->width
= width
/ 2;
185 vf
->priv
->in
.off_left
= vf
->priv
->width
* 3;
187 case ABOVE_BELOW_2_LR
:
190 vf
->priv
->height
= height
/ 2;
191 vf
->priv
->in
.row_right
= vf
->priv
->height
;
193 case ABOVE_BELOW_2_RL
:
196 vf
->priv
->height
= height
/ 2;
197 vf
->priv
->in
.row_left
= vf
->priv
->height
;
200 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
201 "[stereo3d] stereo format of input is not supported\n");
205 //default output values
206 vf
->priv
->out
.width
= vf
->priv
->width
;
207 vf
->priv
->out
.height
= vf
->priv
->height
;
208 vf
->priv
->out
.off_left
= 0;
209 vf
->priv
->out
.off_right
= 0;
210 vf
->priv
->out
.row_left
= 0;
211 vf
->priv
->out
.row_right
= 0;
213 //check output format
214 switch (vf
->priv
->out
.fmt
) {
215 case ANAGLYPH_RC_GRAY
:
216 case ANAGLYPH_RC_HALF
:
217 case ANAGLYPH_RC_COLOR
:
218 case ANAGLYPH_RC_DUBOIS
:
219 case ANAGLYPH_GM_GRAY
:
220 case ANAGLYPH_GM_HALF
:
221 case ANAGLYPH_GM_COLOR
:
222 case ANAGLYPH_GM_DUBOIS
:
223 case ANAGLYPH_YB_GRAY
:
224 case ANAGLYPH_YB_HALF
:
225 case ANAGLYPH_YB_COLOR
:
226 case ANAGLYPH_YB_DUBOIS
:
227 memcpy(vf
->priv
->ana_matrix
, ana_coeff
[vf
->priv
->out
.fmt
],
228 sizeof(vf
->priv
->ana_matrix
));
230 case SIDE_BY_SIDE_2_LR
:
232 case SIDE_BY_SIDE_LR
:
233 vf
->priv
->out
.width
= vf
->priv
->width
* 2;
234 vf
->priv
->out
.off_right
= vf
->priv
->width
* 3;
236 case SIDE_BY_SIDE_2_RL
:
238 case SIDE_BY_SIDE_RL
:
239 vf
->priv
->out
.width
= vf
->priv
->width
* 2;
240 vf
->priv
->out
.off_left
= vf
->priv
->width
* 3;
242 case ABOVE_BELOW_2_LR
:
245 vf
->priv
->out
.height
= vf
->priv
->height
* 2;
246 vf
->priv
->out
.row_right
= vf
->priv
->height
;
248 case ABOVE_BELOW_2_RL
:
251 vf
->priv
->out
.height
= vf
->priv
->height
* 2;
252 vf
->priv
->out
.row_left
= vf
->priv
->height
;
254 case INTERLEAVE_ROWS_LR
:
255 vf
->priv
->row_step
= 2;
256 vf
->priv
->height
= vf
->priv
->height
/ 2;
257 vf
->priv
->out
.off_right
= vf
->priv
->width
* 3;
258 vf
->priv
->in
.off_right
+= vf
->priv
->in
.width
* 3;
260 case INTERLEAVE_ROWS_RL
:
261 vf
->priv
->row_step
= 2;
262 vf
->priv
->height
= vf
->priv
->height
/ 2;
263 vf
->priv
->out
.off_left
= vf
->priv
->width
* 3;
264 vf
->priv
->in
.off_left
+= vf
->priv
->in
.width
* 3;
267 //same as MONO_L only needs switching of input offsets
268 vf
->priv
->in
.off_left
= vf
->priv
->in
.off_right
;
269 vf
->priv
->in
.row_left
= vf
->priv
->in
.row_right
;
272 //use default settings
275 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
276 "[stereo3d] stereo format of output is not supported\n");
280 if (!opts
->screen_size_x
&& !opts
->screen_size_y
) {
281 d_width
= d_width
* vf
->priv
->out
.width
/ width
;
282 d_height
= d_height
* vf
->priv
->out
.height
/ height
;
284 return vf_next_config(vf
, vf
->priv
->out
.width
, vf
->priv
->out
.height
,
285 d_width
, d_height
, flags
, outfmt
);
288 static int put_image(struct vf_instance
*vf
, mp_image_t
*mpi
, double pts
)
291 if (vf
->priv
->in
.fmt
== vf
->priv
->out
.fmt
) { //nothing to do
294 int out_off_left
, out_off_right
;
295 int in_off_left
= vf
->priv
->in
.row_left
* mpi
->stride
[0] +
296 vf
->priv
->in
.off_left
;
297 int in_off_right
= vf
->priv
->in
.row_right
* mpi
->stride
[0] +
298 vf
->priv
->in
.off_right
;
300 dmpi
= vf_get_image(vf
->next
, IMGFMT_RGB24
, MP_IMGTYPE_TEMP
,
301 MP_IMGFLAG_ACCEPT_STRIDE
,
302 vf
->priv
->out
.width
, vf
->priv
->out
.height
);
303 out_off_left
= vf
->priv
->out
.row_left
* dmpi
->stride
[0] +
304 vf
->priv
->out
.off_left
;
305 out_off_right
= vf
->priv
->out
.row_right
* dmpi
->stride
[0] +
306 vf
->priv
->out
.off_right
;
308 switch (vf
->priv
->out
.fmt
) {
309 case SIDE_BY_SIDE_LR
:
310 case SIDE_BY_SIDE_RL
:
311 case SIDE_BY_SIDE_2_LR
:
312 case SIDE_BY_SIDE_2_RL
:
315 case ABOVE_BELOW_2_LR
:
316 case ABOVE_BELOW_2_RL
:
317 case INTERLEAVE_ROWS_LR
:
318 case INTERLEAVE_ROWS_RL
:
319 memcpy_pic2(dmpi
->planes
[0] + out_off_left
,
320 mpi
->planes
[0] + in_off_left
,
323 dmpi
->stride
[0] * vf
->priv
->row_step
,
324 mpi
->stride
[0] * vf
->priv
->row_step
,
325 vf
->priv
->row_step
!= 1);
326 memcpy_pic2(dmpi
->planes
[0] + out_off_right
,
327 mpi
->planes
[0] + in_off_right
,
330 dmpi
->stride
[0] * vf
->priv
->row_step
,
331 mpi
->stride
[0] * vf
->priv
->row_step
,
332 vf
->priv
->row_step
!= 1);
336 memcpy_pic(dmpi
->planes
[0],
337 mpi
->planes
[0] + in_off_left
,
343 case ANAGLYPH_RC_GRAY
:
344 case ANAGLYPH_RC_HALF
:
345 case ANAGLYPH_RC_COLOR
:
346 case ANAGLYPH_RC_DUBOIS
:
347 case ANAGLYPH_GM_GRAY
:
348 case ANAGLYPH_GM_HALF
:
349 case ANAGLYPH_GM_COLOR
:
350 case ANAGLYPH_GM_DUBOIS
:
351 case ANAGLYPH_YB_GRAY
:
352 case ANAGLYPH_YB_HALF
:
353 case ANAGLYPH_YB_COLOR
:
354 case ANAGLYPH_YB_DUBOIS
: {
356 unsigned char *source
= mpi
->planes
[0];
357 unsigned char *dest
= dmpi
->planes
[0];
358 unsigned int out_width
= vf
->priv
->out
.width
;
361 for(int i
= 0; i
< 3; i
++)
362 ana_matrix
[i
] = vf
->priv
->ana_matrix
[i
];
364 for (y
= 0; y
< vf
->priv
->out
.height
; y
++) {
365 o
= dmpi
->stride
[0] * y
;
366 il
= in_off_left
+ y
* mpi
->stride
[0];
367 ir
= in_off_right
+ y
* mpi
->stride
[0];
368 for (x
= 0; x
< out_width
; x
++) {
369 dest
[o
] = ana_convert(
370 ana_matrix
[0], source
+ il
, source
+ ir
); //red out
371 dest
[o
+ 1] = ana_convert(
372 ana_matrix
[1], source
+ il
, source
+ ir
); //green out
373 dest
[o
+ 2] = ana_convert(
374 ana_matrix
[2], source
+ il
, source
+ ir
); //blue out
383 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
384 "[stereo3d] stereo format of output is not supported\n");
389 return vf_next_put_image(vf
, dmpi
, pts
);
392 static int query_format(struct vf_instance
*vf
, unsigned int fmt
)
396 return vf_next_query_format(vf
, fmt
);
400 static void uninit(vf_instance_t
*vf
)
405 static int vf_open(vf_instance_t
*vf
, char *args
)
409 vf
->put_image
= put_image
;
410 vf
->query_format
= query_format
;
416 static const struct format_preset
{
419 } vf_format_presets_defs
[] = {
420 {"arcg", ANAGLYPH_RC_GRAY
},
421 {"anaglyph_red_cyan_gray", ANAGLYPH_RC_GRAY
},
422 {"arch", ANAGLYPH_RC_HALF
},
423 {"anaglyph_red_cyan_half_color", ANAGLYPH_RC_HALF
},
424 {"arcc", ANAGLYPH_RC_COLOR
},
425 {"anaglyph_red_cyan_color", ANAGLYPH_RC_COLOR
},
426 {"arcd", ANAGLYPH_RC_DUBOIS
},
427 {"anaglyph_red_cyan_dubios", ANAGLYPH_RC_DUBOIS
},
428 {"agmg", ANAGLYPH_GM_GRAY
},
429 {"anaglyph_green_magenta_gray", ANAGLYPH_GM_GRAY
},
430 {"agmh", ANAGLYPH_GM_HALF
},
431 {"anaglyph_green_magenta_half_color",ANAGLYPH_GM_HALF
},
432 {"agmc", ANAGLYPH_GM_COLOR
},
433 {"anaglyph_green_magenta_color", ANAGLYPH_GM_COLOR
},
434 {"agmd", ANAGLYPH_GM_DUBOIS
},
435 {"anaglyph_green_magenta_dubois", ANAGLYPH_GM_DUBOIS
},
436 {"aybg", ANAGLYPH_YB_GRAY
},
437 {"anaglyph_yellow_blue_gray", ANAGLYPH_YB_GRAY
},
438 {"aybh", ANAGLYPH_YB_HALF
},
439 {"anaglyph_yellow_blue_half_color", ANAGLYPH_YB_HALF
},
440 {"aybc", ANAGLYPH_YB_COLOR
},
441 {"anaglyph_yellow_blue_color", ANAGLYPH_YB_COLOR
},
442 {"aybd", ANAGLYPH_YB_DUBOIS
},
443 {"anaglyph_yellow_blue_dubois", ANAGLYPH_YB_DUBOIS
},
445 {"mono_left", MONO_L
},
447 {"mono_right", MONO_R
},
448 {"sbsl", SIDE_BY_SIDE_LR
},
449 {"side_by_side_left_first", SIDE_BY_SIDE_LR
},
450 {"sbsr", SIDE_BY_SIDE_RL
},
451 {"side_by_side_right_first", SIDE_BY_SIDE_RL
},
452 {"sbs2l", SIDE_BY_SIDE_2_LR
},
453 {"side_by_side_half_width_left_first", SIDE_BY_SIDE_2_LR
},
454 {"sbs2r", SIDE_BY_SIDE_2_RL
},
455 {"side_by_side_half_width_right_first",SIDE_BY_SIDE_2_RL
},
456 {"abl", ABOVE_BELOW_LR
},
457 {"above_below_left_first", ABOVE_BELOW_LR
},
458 {"abr", ABOVE_BELOW_RL
},
459 {"above_below_right_first", ABOVE_BELOW_RL
},
460 {"ab2l", ABOVE_BELOW_2_LR
},
461 {"above_below_half_height_left_first", ABOVE_BELOW_2_LR
},
462 {"ab2r", ABOVE_BELOW_2_RL
},
463 {"above_below_half_height_right_first",ABOVE_BELOW_2_RL
},
464 {"irl", INTERLEAVE_ROWS_LR
},
465 {"interleave_rows_left_first", INTERLEAVE_ROWS_LR
},
466 {"irr", INTERLEAVE_ROWS_RL
},
467 {"interleave_rows_right_first", INTERLEAVE_ROWS_RL
},
471 #define ST_OFF(f) M_ST_OFF(struct format_preset,f)
472 static const m_option_t vf_format_preset_fields_in
[] = {
473 {"in", ST_OFF(scode
), CONF_TYPE_INT
, 0,0,0, NULL
},
474 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
476 static const m_option_t vf_format_preset_fields_out
[] = {
477 {"out", ST_OFF(scode
), CONF_TYPE_INT
, 0,0,0, NULL
},
478 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
481 static const m_struct_t vf_format_preset_in
= {
482 "stereo_format_preset_in",
483 sizeof(struct format_preset
),
485 vf_format_preset_fields_in
487 static const m_struct_t vf_format_preset_out
= {
488 "stereo_format_preset_out",
489 sizeof(struct format_preset
),
491 vf_format_preset_fields_out
494 static const m_struct_t vf_opts
;
495 static const m_obj_presets_t format_preset_in
= {
496 (struct m_struct_st
*)&vf_format_preset_in
,
497 (struct m_struct_st
*)&vf_opts
,
498 (struct format_preset
*)vf_format_presets_defs
,
501 static const m_obj_presets_t format_preset_out
= {
502 (struct m_struct_st
*)&vf_format_preset_out
,
503 (struct m_struct_st
*)&vf_opts
,
504 (struct format_preset
*)vf_format_presets_defs
,
510 #define ST_OFF(f) M_ST_OFF(struct vf_priv_s,f)
511 static const m_option_t vf_opts_fields
[] = {
512 {"stereo_in", 0, CONF_TYPE_OBJ_PRESETS
, 0, 0, 0,
513 (m_obj_presets_t
*)&format_preset_in
},
514 {"stereo_out", 0, CONF_TYPE_OBJ_PRESETS
, 0, 0, 0,
515 (m_obj_presets_t
*)&format_preset_out
},
516 {"in", ST_OFF(in
.fmt
), CONF_TYPE_INT
, 0,0,0, NULL
},
517 {"out", ST_OFF(out
.fmt
), CONF_TYPE_INT
, 0,0,0, NULL
},
518 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
521 static const m_struct_t vf_opts
= {
523 sizeof(struct vf_priv_s
),
530 const vf_info_t vf_info_stereo3d
= {
531 "stereoscopic 3d view",
534 "view stereoscopic videos",