[vlc-devel] [PATCH 1/1] Support over-under 3D anaglyphs

Steve Lhomme robux4 at ycbcr.xyz
Mon Jan 14 08:26:20 CET 2019


Can you rename over-under to Top-Bottom ? That's the technical term used 
everywhere else.

You may also have a look at video_multiview_mode_t. It should be 
possible to have an auto mode so that depending on the source 
(MULTIVIEW_STEREO_SBS / MULTIVIEW_STEREO_TB) you pick the right 
algorithm. Auto should probably be the default, the other ones being 
used to force the filter when the source is not tagged properly. But all 
this can be a separate patch.

On 13/01/2019 21:09, Tom Murphy wrote:
> If anyone could take a look at this it'd be a big help for a movie
> night I'm hosting next weekend :)
>
> You can find an example file to try it with here:
>
> http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_stereo_abl.mp4
>
> (From the "Stereoscopic 3d" section here:
> http://bbb3d.renderfarming.net/download.html)
>
> Note, though, that unlike most videos which are half-OU, this is
> full-OU so the image will be vertically stretched.
>
> The way it works is pretty simple (and modeled after the side-by-side
> version): it reads one line at a time from both the beginning and
> midpoint of the file, merging them with the anaglyph calculation.
> Because it's YUV420, we read and write 4 Y pixels for every 1 U or V
> pixel. Because it's for half-OU, we produce a duplicate of each line
> to preserve the aspect ratio (this is what the existing side-by-side
> version does, only vertically).
>
> Thanks,
> Tom
>
>
> On 1/12/19, Tom Murphy <amindfv at gmail.com> wrote:
>> ---
>>   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
>>
>>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel



More information about the vlc-devel mailing list