[vlc-devel] [PATCH 1/2] Support over-under 3D anaglyphs
Tom Murphy
amindfv at gmail.com
Wed Jan 16 04:43:32 CET 2019
---
modules/video_filter/anaglyph.c | 171 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 168 insertions(+), 3 deletions(-)
diff --git a/modules/video_filter/anaglyph.c b/modules/video_filter/anaglyph.c
index 2bfeafb54d..4ec38fc90a 100644
--- a/modules/video_filter/anaglyph.c
+++ b/modules/video_filter/anaglyph.c
@@ -5,6 +5,7 @@
* $Id$
*
* Authors: Antoine Cellerier <dionoea .t videolan d at t org>
+ * Tom Murphy <amindfv .t gmail d at t com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
@@ -34,10 +35,14 @@
static int Create(vlc_object_t *);
static void Destroy(vlc_object_t *);
static picture_t *Filter(filter_t *, picture_t *);
+
static void combine_side_by_side_yuv420(picture_t *, picture_t *, int, int);
+static void combine_over_under_yuv420(picture_t *, picture_t *, int, int);
#define SCHEME_TEXT N_("Color scheme")
#define SCHEME_LONGTEXT N_("Define the glasses' color scheme")
+#define ORIENTATION_TEXT N_("Orientation")
+#define ORIENTATION_LONGTEXT N_("Orientation of the video's two images")
#define FILTER_PREFIX "anaglyph-"
@@ -52,6 +57,12 @@ enum scheme_e
magenta_cyan,
};
+enum orientation_e
+{
+ side_by_side = 1,
+ over_under,
+};
+
static const char *const ppsz_scheme_values[] = {
"red-green",
"red-blue",
@@ -67,6 +78,15 @@ static const char *const ppsz_scheme_descriptions[] = {
"magenta (left) cyan (right)",
};
+static const char *const orientation_values[] = {
+ "side-by-side",
+ "over-under",
+ };
+static const char *const orientation_descriptions[] = {
+ "side-by-side",
+ "over-under",
+ };
+
vlc_module_begin()
set_description(N_("Convert 3D picture to anaglyph image video filter"));
set_shortname(N_("Anaglyph"))
@@ -75,16 +95,20 @@ vlc_module_begin()
set_capability("video filter", 0)
add_string(FILTER_PREFIX "scheme", "red-cyan", SCHEME_TEXT, SCHEME_LONGTEXT, false)
change_string_list(ppsz_scheme_values, ppsz_scheme_descriptions)
+ add_string(FILTER_PREFIX "orientation", "side-by-side", ORIENTATION_TEXT, ORIENTATION_LONGTEXT, false)
+ change_string_list(orientation_values, orientation_descriptions)
set_callbacks(Create, Destroy)
vlc_module_end()
static const char *const ppsz_filter_options[] = {
- "scheme", NULL
+ "scheme", "orientation", NULL
};
+
typedef struct
{
int left, right;
+ enum orientation_e orientation;
} filter_sys_t;
@@ -105,6 +129,8 @@ static int Create(vlc_object_t *p_this)
return VLC_EGENERIC;
}
+
+
p_filter->p_sys = malloc(sizeof(filter_sys_t));
if (!p_filter->p_sys)
return VLC_ENOMEM;
@@ -157,6 +183,20 @@ static int Create(vlc_object_t *p_this)
break;
}
+ char *orientation_choice = var_CreateGetStringCommand(p_filter,
+ FILTER_PREFIX "orientation");
+ p_sys->orientation = side_by_side;
+ if (orientation_choice)
+ {
+ if (!strcmp(orientation_choice, "side-by-side"))
+ p_sys->orientation = side_by_side;
+ else if (!strcmp(orientation_choice, "over-under"))
+ p_sys->orientation = over_under;
+ else
+ msg_Err(p_filter, "Unknown anaglyph orientation '%s'", orientation_choice);
+ }
+ free(orientation_choice);
+
p_filter->pf_video_filter = Filter;
return VLC_SUCCESS;
}
@@ -187,8 +227,22 @@ static picture_t *Filter(filter_t *p_filter, picture_t *p_pic)
case VLC_CODEC_I420:
case VLC_CODEC_J420:
case VLC_CODEC_YV12:
- combine_side_by_side_yuv420(p_pic, p_outpic,
- p_sys->left, p_sys->right);
+ switch (p_sys->orientation)
+ {
+ case side_by_side:
+ combine_side_by_side_yuv420(p_pic, p_outpic,
+ p_sys->left, p_sys->right);
+ break;
+ case over_under:
+ combine_over_under_yuv420(p_pic, p_outpic,
+ p_sys->left, p_sys->right);
+ break;
+ default:
+ msg_Warn(p_filter, "Unsupported orientation (%4.4s)",
+ (char*)&(p_sys->orientation));
+ picture_Release(p_pic);
+ return NULL;
+ }
break;
default:
@@ -303,3 +357,114 @@ static void combine_side_by_side_yuv420(picture_t *p_inpic, picture_t *p_outpic,
}
}
+
+
+
+static void combine_over_under_yuv420(picture_t *p_inpic, picture_t *p_outpic,
+ int left, int right)
+{
+ uint8_t *yino = p_inpic->p[Y_PLANE].p_pixels;
+ uint8_t *uino = p_inpic->p[U_PLANE].p_pixels;
+ uint8_t *vino = p_inpic->p[V_PLANE].p_pixels;
+
+ uint8_t *yout = p_outpic->p[Y_PLANE].p_pixels;
+ uint8_t *uout = p_outpic->p[U_PLANE].p_pixels;
+ uint8_t *vout = p_outpic->p[V_PLANE].p_pixels;
+
+ const int in_pitch = p_inpic->p[Y_PLANE].i_pitch;
+
+ const int y_visible_pitch = p_inpic->p[Y_PLANE].i_visible_pitch;
+ const int y_visible_lines = p_inpic->p[Y_PLANE].i_visible_lines;
+ const int uv_visible_pitch = p_inpic->p[U_PLANE].i_visible_pitch;
+ const int uv_visible_lines = p_inpic->p[U_PLANE].i_visible_lines;
+
+ const int y_half_size = (y_visible_lines * y_visible_pitch) / 2;
+ const int uv_half_size = (uv_visible_lines * uv_visible_pitch) / 2;
+
+ const uint8_t *yend = yino + y_half_size;
+
+ int rshift = !!((0xff0000&left) && (0xff0000&right));
+ int gshift = !!((0x00ff00&left) && (0x00ff00&right));
+ int bshift = !!((0x0000ff&left) && (0x0000ff&right));
+
+ while (yino < yend)
+ {
+ uint8_t *yinu = yino + y_half_size;
+ uint8_t *uinu = uino + uv_half_size;
+ uint8_t *vinu = vino + uv_half_size;
+
+ const uint8_t *yend = yino + in_pitch;
+
+ while (yino < yend)
+ {
+ int ro, go, bo, ru, gu, bu, r, g, b;
+
+ yuv_to_rgb(&ro, &go, &bo, *yino, *uino, *vino);
+ yuv_to_rgb(&ru, &gu, &bu, *yinu, *uinu, *vinu);
+
+ r = ((!!(0xff0000&left))*ro + (!!(0xff0000&right))*ru)>>rshift;
+ g = ((!!(0x00ff00&left))*go + (!!(0x00ff00&right))*gu)>>gshift;
+ b = ((!!(0x0000ff&left))*bo + (!!(0x0000ff&right))*bu)>>bshift;
+ rgb_to_yuv(yout, uout, vout, r, g, b);
+ // Mirroring a second line below, to make up for the fact it's been compresed to half-height:
+ yout[y_visible_pitch] = *yout;
+
+
+ yuv_to_rgb(&ro, &go, &bo, *(yino+y_visible_pitch), *uino, *vino);
+ yuv_to_rgb(&ru, &gu, &bu, *(yinu+y_visible_pitch), *uinu, *vinu);
+
+ r = ((!!(0xff0000&left))*ro + (!!(0xff0000&right))*ru)>>rshift;
+ g = ((!!(0x00ff00&left))*go + (!!(0x00ff00&right))*gu)>>gshift;
+ b = ((!!(0x0000ff&left))*bo + (!!(0x0000ff&right))*bu)>>bshift;
+
+ rgb_to_yuv(yout+(y_visible_pitch*2), uout, vout, r, g, b);
+ yout[y_visible_pitch*3] = *(yout+(y_visible_pitch*2));
+
+ yino++;
+ yinu++;
+ yout++;
+
+
+ yuv_to_rgb(&ro, &go, &bo, *yino, *uino, *vino);
+ yuv_to_rgb(&ru, &gu, &bu, *yinu, *uinu, *vinu);
+
+ r = ((!!(0xff0000&left))*ro + (!!(0xff0000&right))*ru)>>rshift;
+ g = ((!!(0x00ff00&left))*go + (!!(0x00ff00&right))*gu)>>gshift;
+ b = ((!!(0x0000ff&left))*bo + (!!(0x0000ff&right))*bu)>>bshift;
+ rgb_to_yuv(yout, uout, vout, r, g, b);
+ yout[y_visible_pitch] = *yout;
+
+
+ yuv_to_rgb(&ro, &go, &bo, *(yino+y_visible_pitch), *uino, *vino);
+ yuv_to_rgb(&ru, &gu, &bu, *(yinu+y_visible_pitch), *uinu, *vinu);
+
+ r = ((!!(0xff0000&left))*ro + (!!(0xff0000&right))*ru)>>rshift;
+ g = ((!!(0x00ff00&left))*go + (!!(0x00ff00&right))*gu)>>gshift;
+ b = ((!!(0x0000ff&left))*bo + (!!(0x0000ff&right))*bu)>>bshift;
+ rgb_to_yuv(yout+(y_visible_pitch*2), uout+uv_visible_pitch, vout+uv_visible_pitch, r, g, b);
+ yout[y_visible_pitch*3] = *(yout+(y_visible_pitch*2));
+
+ yino++;
+ yinu++;
+ yout++;
+
+ // There are 1/4 as many U & Y pixels so we write them 1/4 as often:
+ uino++;
+ uinu++;
+ uout++;
+ vino++;
+ vinu++;
+ vout++;
+ }
+
+ // We skip these ins because we looked a row below for the Ys already:
+ yino += in_pitch;
+ yinu += in_pitch;
+
+ yout += y_visible_pitch * 3;
+
+ uout += uv_visible_pitch;
+ vout += uv_visible_pitch;
+ }
+}
+
--
2.11.0
More information about the vlc-devel
mailing list