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 INTERLEAVE_ROWS_LR
, //row-interleave (left eye has top row)
60 INTERLEAVE_ROWS_RL
, //row-interleave (right eye has top row)
61 STEREO_CODE_COUNT
//no value set - TODO: needs autodetection
64 typedef struct component
{
68 unsigned int off_left
;
69 unsigned int off_right
;
70 unsigned int row_left
;
71 unsigned int row_right
;
74 //==global variables==//
75 static const int ana_coeff
[10][3][6] = {
76 {{19595, 38470, 7471, 0, 0, 0}, //ANAGLYPH_RC_GRAY
77 { 0, 0, 0, 19595, 38470, 7471},
78 { 0, 0, 0, 19595, 38470, 7471}},
79 {{19595, 38470, 7471, 0, 0, 0}, //ANAGLYPH_RC_HALF
80 { 0, 0, 0, 0, 65536, 0},
81 { 0, 0, 0, 0, 0, 65536}},
82 {{65536, 0, 0, 0, 0, 0}, //ANAGLYPH_RC_COLOR
83 { 0, 0, 0, 0, 65536, 0},
84 { 0, 0, 0, 0, 0, 65536}},
85 {{29891, 32800, 11559, -2849, -5763, -102}, //ANAGLYPH_RC_DUBOIS
86 {-2627, -2479, -1033, 24804, 48080, -1209},
87 { -997, -1350, -358, -4729, -7403, 80373}},
88 {{ 0, 0, 0, 19595, 38470, 7471}, //ANAGLYPH_GM_GRAY
89 {19595, 38470, 7471, 0, 0, 0},
90 { 0, 0, 0, 19595, 38470, 7471}},
91 {{ 0, 0, 0, 65536, 0, 0}, //ANAGLYPH_GM_HALF
92 {19595, 38470, 7471, 0, 0, 0},
93 { 0, 0, 0, 0, 0, 65536}},
94 {{ 0, 0, 0, 65536, 0, 0}, //ANAGLYPH_GM_COLOR
95 { 0, 65536, 0, 0, 0, 0},
96 { 0, 0, 0, 0, 0, 65536}},
97 {{ 0, 0, 0, 19595, 38470, 7471}, //ANAGLYPH_YB_GRAY
98 { 0, 0, 0, 19595, 38470, 7471},
99 {19595, 38470, 7471, 0, 0, 0}},
100 {{ 0, 0, 0, 65536, 0, 0}, //ANAGLYPH_YB_HALF
101 { 0, 0, 0, 0, 65536, 0},
102 {19595, 38470, 7471, 0, 0, 0}},
103 {{ 0, 0, 0, 65536, 0, 0}, //ANAGLYPH_YB_COLOR
104 { 0, 0, 0, 0, 65536, 0},
105 { 0, 0, 65536, 0, 0, 0}}
111 int ana_matrix
[3][6];
114 unsigned int row_step
;
115 } const vf_priv_default
= {
121 static inline uint8_t ana_convert(int coeff
[6], uint8_t left
[3], uint8_t right
[3])
125 sum
= coeff
[0] * left
[0] + coeff
[3] * right
[0]; //red in
126 sum
+= coeff
[1] * left
[1] + coeff
[4] * right
[1]; //green in
127 sum
+= coeff
[2] * left
[2] + coeff
[5] * right
[2]; //blue in
128 return av_clip_uint8(sum
>> 16);
131 static int config(struct vf_instance
*vf
, int width
, int height
, int d_width
,
132 int d_height
, unsigned int flags
, unsigned int outfmt
)
134 struct MPOpts
*opts
= vf
->opts
;
136 if ((width
& 1) || (height
& 1)) {
137 mp_msg(MSGT_VFILTER
, MSGL_WARN
, "[stereo3d] invalid height or width\n");
140 //default input values
141 vf
->priv
->width
= width
;
142 vf
->priv
->height
= height
;
143 vf
->priv
->row_step
= 1;
144 vf
->priv
->in
.width
= width
;
145 vf
->priv
->in
.height
= height
;
146 vf
->priv
->in
.off_left
= 0;
147 vf
->priv
->in
.off_right
= 0;
148 vf
->priv
->in
.row_left
= 0;
149 vf
->priv
->in
.row_right
= 0;
152 switch (vf
->priv
->in
.fmt
) {
153 case SIDE_BY_SIDE_LR
:
154 vf
->priv
->width
= width
/ 2;
155 vf
->priv
->in
.off_right
= vf
->priv
->width
* 3;
157 case SIDE_BY_SIDE_RL
:
158 vf
->priv
->width
= width
/ 2;
159 vf
->priv
->in
.off_left
= vf
->priv
->width
* 3;
161 case ABOVE_BELOW_2_LR
:
164 vf
->priv
->height
= height
/ 2;
165 vf
->priv
->in
.row_right
= vf
->priv
->height
;
167 case ABOVE_BELOW_2_RL
:
170 vf
->priv
->height
= height
/ 2;
171 vf
->priv
->in
.row_left
= vf
->priv
->height
;
174 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
175 "[stereo3d] stereo format of input is not supported\n");
179 //default output values
180 vf
->priv
->out
.width
= vf
->priv
->width
;
181 vf
->priv
->out
.height
= vf
->priv
->height
;
182 vf
->priv
->out
.off_left
= 0;
183 vf
->priv
->out
.off_right
= 0;
184 vf
->priv
->out
.row_left
= 0;
185 vf
->priv
->out
.row_right
= 0;
187 //check output format
188 switch (vf
->priv
->out
.fmt
) {
189 case ANAGLYPH_RC_GRAY
:
190 case ANAGLYPH_RC_HALF
:
191 case ANAGLYPH_RC_COLOR
:
192 case ANAGLYPH_RC_DUBOIS
:
193 case ANAGLYPH_GM_GRAY
:
194 case ANAGLYPH_GM_HALF
:
195 case ANAGLYPH_GM_COLOR
:
196 case ANAGLYPH_YB_GRAY
:
197 case ANAGLYPH_YB_HALF
:
198 case ANAGLYPH_YB_COLOR
:
199 memcpy(vf
->priv
->ana_matrix
, ana_coeff
[vf
->priv
->out
.fmt
],
200 sizeof(vf
->priv
->ana_matrix
));
202 case SIDE_BY_SIDE_LR
:
203 vf
->priv
->out
.width
= vf
->priv
->width
* 2;
204 vf
->priv
->out
.off_right
= vf
->priv
->width
* 3;
206 case SIDE_BY_SIDE_RL
:
207 vf
->priv
->out
.width
= vf
->priv
->width
* 2;
208 vf
->priv
->out
.off_left
= vf
->priv
->width
* 3;
210 case ABOVE_BELOW_2_LR
:
213 vf
->priv
->out
.height
= vf
->priv
->height
* 2;
214 vf
->priv
->out
.row_right
= vf
->priv
->height
;
216 case ABOVE_BELOW_2_RL
:
219 vf
->priv
->out
.height
= vf
->priv
->height
* 2;
220 vf
->priv
->out
.row_left
= vf
->priv
->height
;
222 case INTERLEAVE_ROWS_LR
:
223 vf
->priv
->row_step
= 2;
224 vf
->priv
->height
= vf
->priv
->height
/ 2;
225 vf
->priv
->out
.off_right
= vf
->priv
->width
* 3;
226 vf
->priv
->in
.off_right
+= vf
->priv
->in
.width
* 3;
228 case INTERLEAVE_ROWS_RL
:
229 vf
->priv
->row_step
= 2;
230 vf
->priv
->height
= vf
->priv
->height
/ 2;
231 vf
->priv
->out
.off_left
= vf
->priv
->width
* 3;
232 vf
->priv
->in
.off_left
+= vf
->priv
->in
.width
* 3;
235 //same as MONO_L only needs switching of input offsets
236 vf
->priv
->in
.off_left
= vf
->priv
->in
.off_right
;
237 vf
->priv
->in
.row_left
= vf
->priv
->in
.row_right
;
240 //use default settings
243 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
244 "[stereo3d] stereo format of output is not supported\n");
248 if (!opts
->screen_size_x
&& !opts
->screen_size_y
) {
249 d_width
= d_width
* vf
->priv
->out
.width
/ width
;
250 d_height
= d_height
* vf
->priv
->out
.height
/ height
;
252 return vf_next_config(vf
, vf
->priv
->out
.width
, vf
->priv
->out
.height
,
253 d_width
, d_height
, flags
, outfmt
);
256 static int put_image(struct vf_instance
*vf
, mp_image_t
*mpi
, double pts
)
259 if (vf
->priv
->in
.fmt
== vf
->priv
->out
.fmt
) { //nothing to do
262 int out_off_left
, out_off_right
;
263 int in_off_left
= vf
->priv
->in
.row_left
* mpi
->stride
[0] +
264 vf
->priv
->in
.off_left
;
265 int in_off_right
= vf
->priv
->in
.row_right
* mpi
->stride
[0] +
266 vf
->priv
->in
.off_right
;
268 dmpi
= vf_get_image(vf
->next
, IMGFMT_RGB24
, MP_IMGTYPE_TEMP
,
269 MP_IMGFLAG_ACCEPT_STRIDE
,
270 vf
->priv
->out
.width
, vf
->priv
->out
.height
);
271 out_off_left
= vf
->priv
->out
.row_left
* dmpi
->stride
[0] +
272 vf
->priv
->out
.off_left
;
273 out_off_right
= vf
->priv
->out
.row_right
* dmpi
->stride
[0] +
274 vf
->priv
->out
.off_right
;
276 switch (vf
->priv
->out
.fmt
) {
277 case SIDE_BY_SIDE_LR
:
278 case SIDE_BY_SIDE_RL
:
281 case ABOVE_BELOW_2_LR
:
282 case ABOVE_BELOW_2_RL
:
283 case INTERLEAVE_ROWS_LR
:
284 case INTERLEAVE_ROWS_RL
:
285 memcpy_pic2(dmpi
->planes
[0] + out_off_left
,
286 mpi
->planes
[0] + in_off_left
,
289 dmpi
->stride
[0] * vf
->priv
->row_step
,
290 mpi
->stride
[0] * vf
->priv
->row_step
,
291 vf
->priv
->row_step
!= 1);
292 memcpy_pic2(dmpi
->planes
[0] + out_off_right
,
293 mpi
->planes
[0] + in_off_right
,
296 dmpi
->stride
[0] * vf
->priv
->row_step
,
297 mpi
->stride
[0] * vf
->priv
->row_step
,
298 vf
->priv
->row_step
!= 1);
302 memcpy_pic(dmpi
->planes
[0],
303 mpi
->planes
[0] + in_off_left
,
309 case ANAGLYPH_RC_GRAY
:
310 case ANAGLYPH_RC_HALF
:
311 case ANAGLYPH_RC_COLOR
:
312 case ANAGLYPH_RC_DUBOIS
:
313 case ANAGLYPH_GM_GRAY
:
314 case ANAGLYPH_GM_HALF
:
315 case ANAGLYPH_GM_COLOR
:
316 case ANAGLYPH_YB_GRAY
:
317 case ANAGLYPH_YB_HALF
:
318 case ANAGLYPH_YB_COLOR
: {
320 unsigned char *source
= mpi
->planes
[0];
321 unsigned char *dest
= dmpi
->planes
[0];
322 unsigned int out_width
= vf
->priv
->out
.width
;
325 for(int i
= 0; i
< 3; i
++)
326 ana_matrix
[i
] = vf
->priv
->ana_matrix
[i
];
328 for (y
= 0; y
< vf
->priv
->out
.height
; y
++) {
329 o
= dmpi
->stride
[0] * y
;
330 il
= in_off_left
+ y
* mpi
->stride
[0];
331 ir
= in_off_right
+ y
* mpi
->stride
[0];
332 for (x
= 0; x
< out_width
; x
++) {
333 dest
[o
] = ana_convert(
334 ana_matrix
[0], source
+ il
, source
+ ir
); //red out
335 dest
[o
+ 1] = ana_convert(
336 ana_matrix
[1], source
+ il
, source
+ ir
); //green out
337 dest
[o
+ 2] = ana_convert(
338 ana_matrix
[2], source
+ il
, source
+ ir
); //blue out
347 mp_msg(MSGT_VFILTER
, MSGL_WARN
,
348 "[stereo3d] stereo format of output is not supported\n");
353 return vf_next_put_image(vf
, dmpi
, pts
);
356 static int query_format(struct vf_instance
*vf
, unsigned int fmt
)
360 return vf_next_query_format(vf
, fmt
);
364 static void uninit(vf_instance_t
*vf
)
369 static int vf_open(vf_instance_t
*vf
, char *args
)
373 vf
->put_image
= put_image
;
374 vf
->query_format
= query_format
;
380 static const struct format_preset
{
383 } vf_format_presets_defs
[] = {
384 {"arcg", ANAGLYPH_RC_GRAY
},
385 {"anaglyph_red_cyan_gray", ANAGLYPH_RC_GRAY
},
386 {"arch", ANAGLYPH_RC_HALF
},
387 {"anaglyph_red_cyan_half_color", ANAGLYPH_RC_HALF
},
388 {"arcc", ANAGLYPH_RC_COLOR
},
389 {"anaglyph_red_cyan_color", ANAGLYPH_RC_COLOR
},
390 {"arcd", ANAGLYPH_RC_DUBOIS
},
391 {"anaglyph_red_cyan_dubios", ANAGLYPH_RC_DUBOIS
},
392 {"agmg", ANAGLYPH_GM_GRAY
},
393 {"anaglyph_green_magenta_gray", ANAGLYPH_GM_GRAY
},
394 {"agmh", ANAGLYPH_GM_HALF
},
395 {"anaglyph_green_magenta_half_color",ANAGLYPH_GM_HALF
},
396 {"agmc", ANAGLYPH_GM_COLOR
},
397 {"anaglyph_green_magenta_color", ANAGLYPH_GM_COLOR
},
398 {"aybg", ANAGLYPH_YB_GRAY
},
399 {"anaglyph_yellow_blue_gray", ANAGLYPH_YB_GRAY
},
400 {"aybh", ANAGLYPH_YB_HALF
},
401 {"anaglyph_yellow_blue_half_color", ANAGLYPH_YB_HALF
},
402 {"aybc", ANAGLYPH_YB_COLOR
},
403 {"anaglyph_yellow_blue_color", ANAGLYPH_YB_COLOR
},
405 {"mono_left", MONO_L
},
407 {"mono_right", MONO_R
},
408 {"sbsl", SIDE_BY_SIDE_LR
},
409 {"side_by_side_left_first", SIDE_BY_SIDE_LR
},
410 {"sbsr", SIDE_BY_SIDE_RL
},
411 {"side_by_side_right_first", SIDE_BY_SIDE_RL
},
412 {"abl", ABOVE_BELOW_LR
},
413 {"above_below_left_first", ABOVE_BELOW_LR
},
414 {"abr", ABOVE_BELOW_RL
},
415 {"above_below_right_first", ABOVE_BELOW_RL
},
416 {"ab2l", ABOVE_BELOW_2_LR
},
417 {"above_below_half_height_left_first", ABOVE_BELOW_2_LR
},
418 {"ab2r", ABOVE_BELOW_2_RL
},
419 {"above_below_half_height_right_first",ABOVE_BELOW_2_RL
},
420 {"irl", INTERLEAVE_ROWS_LR
},
421 {"interleave_rows_left_first", INTERLEAVE_ROWS_LR
},
422 {"irr", INTERLEAVE_ROWS_RL
},
423 {"interleave_rows_right_first", INTERLEAVE_ROWS_RL
},
427 #define ST_OFF(f) M_ST_OFF(struct format_preset,f)
428 static const m_option_t vf_format_preset_fields_in
[] = {
429 {"in", ST_OFF(scode
), CONF_TYPE_INT
, 0,0,0, NULL
},
430 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
432 static const m_option_t vf_format_preset_fields_out
[] = {
433 {"out", ST_OFF(scode
), CONF_TYPE_INT
, 0,0,0, NULL
},
434 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
437 static const m_struct_t vf_format_preset_in
= {
438 "stereo_format_preset_in",
439 sizeof(struct format_preset
),
441 vf_format_preset_fields_in
443 static const m_struct_t vf_format_preset_out
= {
444 "stereo_format_preset_out",
445 sizeof(struct format_preset
),
447 vf_format_preset_fields_out
450 static const m_struct_t vf_opts
;
451 static const m_obj_presets_t format_preset_in
= {
452 (struct m_struct_st
*)&vf_format_preset_in
,
453 (struct m_struct_st
*)&vf_opts
,
454 (struct format_preset
*)vf_format_presets_defs
,
457 static const m_obj_presets_t format_preset_out
= {
458 (struct m_struct_st
*)&vf_format_preset_out
,
459 (struct m_struct_st
*)&vf_opts
,
460 (struct format_preset
*)vf_format_presets_defs
,
466 #define ST_OFF(f) M_ST_OFF(struct vf_priv_s,f)
467 static const m_option_t vf_opts_fields
[] = {
468 {"stereo_in", 0, CONF_TYPE_OBJ_PRESETS
, 0, 0, 0,
469 (m_obj_presets_t
*)&format_preset_in
},
470 {"stereo_out", 0, CONF_TYPE_OBJ_PRESETS
, 0, 0, 0,
471 (m_obj_presets_t
*)&format_preset_out
},
472 {"in", ST_OFF(in
.fmt
), CONF_TYPE_INT
, 0,0,0, NULL
},
473 {"out", ST_OFF(out
.fmt
), CONF_TYPE_INT
, 0,0,0, NULL
},
474 { NULL
, NULL
, 0, 0, 0, 0, NULL
}
477 static const m_struct_t vf_opts
= {
479 sizeof(struct vf_priv_s
),
486 const vf_info_t vf_info_stereo3d
= {
487 "stereoscopic 3d view",
490 "view stereoscopic videos",