[vlc-devel] [PATCH 1/1] Add support for top-bottom anaglyph 3D

amindfv amindfv at mailbox.org
Tue Dec 22 06:13:39 UTC 2020


---
 modules/video_filter/anaglyph.c | 170 +++++++++++++++++++++++++++++++-
 1 file changed, 167 insertions(+), 3 deletions(-)

diff --git a/modules/video_filter/anaglyph.c b/modules/video_filter/anaglyph.c
index b29dfda528..98abbcaa2f 100644
--- a/modules/video_filter/anaglyph.c
+++ b/modules/video_filter/anaglyph.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2000-2012 VLC authors and VideoLAN
  *
  * Authors: Antoine Cellerier <dionoea .t videolan d at t org>
+ *          Tom Murphy <amindfv .t mailbox d at t org>
  *
  * 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
@@ -32,9 +33,12 @@
 
 static int Create(filter_t *);
 static void combine_side_by_side_yuv420(picture_t *, picture_t *, int, int);
+static void combine_top_bottom_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-"
 
@@ -49,6 +53,12 @@ enum scheme_e
     magenta_cyan,
 };
 
+enum orientation_e
+{
+    side_by_side = 1,
+    top_bottom,
+};
+
 static const char *const ppsz_scheme_values[] = {
     "red-green",
     "red-blue",
@@ -64,6 +74,15 @@ static const char *const ppsz_scheme_descriptions[] = {
     "magenta (left)  cyan (right)",
     };
 
+static const char *const orientation_values[] = {
+    "side-by-side",
+    "top-bottom",
+    };
+static const char *const orientation_descriptions[] = {
+    "side-by-side",
+    "top-bottom",
+    };
+
 vlc_module_begin()
     set_description(N_("Convert 3D picture to anaglyph image video filter"));
     set_shortname(N_("Anaglyph"))
@@ -71,16 +90,19 @@ vlc_module_begin()
     set_subcategory(SUBCAT_VIDEO_VFILTER)
     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_callback_video_filter(Create)
 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;
 
 VIDEO_FILTER_WRAPPER(Filter)
@@ -100,6 +122,8 @@ static int Create(filter_t *p_filter)
             return VLC_EGENERIC;
     }
 
+
+
     p_filter->p_sys = vlc_obj_malloc(VLC_OBJECT(p_filter), sizeof(filter_sys_t));
     if (unlikely(!p_filter->p_sys))
         return VLC_ENOMEM;
@@ -152,6 +176,23 @@ static int Create(filter_t *p_filter)
             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, "top-bottom"))
+            p_sys->orientation = top_bottom;
+        else
+            msg_Err(p_filter, "Unknown anaglyph orientation '%s'", orientation_choice);
+    }
+    free(orientation_choice);
+
+
+
+
     p_filter->ops = &Filter_ops;
     return VLC_SUCCESS;
 }
@@ -165,8 +206,23 @@ static void Filter(filter_t *p_filter, picture_t *p_pic, picture_t *p_outpic)
         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 top_bottom:
+                    combine_top_bottom_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:
@@ -275,3 +331,111 @@ static void combine_side_by_side_yuv420(picture_t *p_inpic, picture_t *p_outpic,
         vout += p_outpic->p[V_PLANE].i_pitch - uv_visible_pitch;
     }
 }
+
+static void combine_top_bottom_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.20.1



More information about the vlc-devel mailing list