Commit 2e3d187a authored by Antoine Cellerier's avatar Antoine Cellerier

Add video filter to convert side by side 3D streams to anaglyph images.

This can be tested on Wild Earth 3D on freebox streams in France.
parent d5da2712
......@@ -618,7 +618,7 @@ AC_CHECK_FUNC(getopt_long,, [
AC_SUBST(GNUGETOPT_LIBS)
AC_CHECK_LIB(m,cos,[
VLC_ADD_LIBS([adjust wave ripple psychedelic gradient a52tofloat32 dtstofloat32 x264 goom visual panoramix rotate noise grain scene kate flac lua chorus_flanger freetype avcodec avformat access_avio swscale postproc i420_rgb faad twolame equalizer spatializer param_eq samplerate freetype mod mpc dmo mp4 quicktime realvideo qt4 compressor headphone_channel_mixer normvol audiobargraph_a speex mono colorthres extract ball access_imem hotkeys mosaic gaussianblur dbus x264 hqdn3d],[-lm])
VLC_ADD_LIBS([adjust wave ripple psychedelic gradient a52tofloat32 dtstofloat32 x264 goom visual panoramix rotate noise grain scene kate flac lua chorus_flanger freetype avcodec avformat access_avio swscale postproc i420_rgb faad twolame equalizer spatializer param_eq samplerate freetype mod mpc dmo mp4 quicktime realvideo qt4 compressor headphone_channel_mixer normvol audiobargraph_a speex mono colorthres extract ball access_imem hotkeys mosaic gaussianblur dbus x264 hqdn3d anaglyph],[-lm])
LIBM="-lm"
], [
LIBM=""
......
......@@ -97,6 +97,7 @@ SOURCES_atmo = atmo/atmo.cpp \
SOURCES_gradfun = gradfun.c gradfun.h
SOURCES_subsdelay = subsdelay.c
SOURCES_hqdn3d = hqdn3d.c hqdn3d.h
SOURCES_anaglyph = anaglyph.c
noinst_HEADERS = filter_picture.h
libvlc_LTLIBRARIES += \
......@@ -143,4 +144,5 @@ libvlc_LTLIBRARIES += \
libgradfun_plugin.la \
libyuvp_plugin.la \
libantiflicker_plugin.la \
libhqdn3d_plugin.la
libhqdn3d_plugin.la \
libanaglyph_plugin.la
/*****************************************************************************
* anaglyph.c : Create an image compatible with anaglyph glasses from a 3D video
*****************************************************************************
* Copyright (C) 2000-2012 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea .t videolan d@t org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_filter.h>
#include "filter_picture.h"
static int Create(vlc_object_t *);
static void Destroy(vlc_object_t *);
static picture_t *Filter(filter_t *, picture_t *);
static void make_projection_matrix(filter_t *, int, int *);
static void combine_side_by_side_yuv420(picture_t *, picture_t *, int, int);
#define SCHEME_TEXT N_("Color scheme")
#define SCHEME_LONGTEXT N_("Define the glasse's color scheme")
#define FILTER_PREFIX "anaglyph-"
/* See http://en.wikipedia.org/wiki/Anaglyph_image for a list of known
* color schemes */
enum scheme_e
{
unknown = 0,
red_green,
red_blue,
red_cyan,
trioscopic,
magenta_cyan,
};
static const char *const ppsz_scheme_values[] = {
"red-green",
"red-blue",
"red-cyan",
"trioscopic",
"magenta-cyan",
};
static const char *const ppsz_scheme_descriptions[] = {
"pure red (left) pure green (right)",
"pure red (left) pure blue (right)",
"pure red (left) pure cyan (right)",
"pure green (left) pure magenta (right)",
"magenta (left) cyan (right)",
};
vlc_module_begin()
set_description(N_("Convert 3D picture to anaglyph image video filter"));
set_shortname(N_("Anaglyph"))
set_category(CAT_VIDEO)
set_subcategory(SUBCAT_VIDEO_VFILTER)
set_capability("video filter2", 0)
add_string(FILTER_PREFIX "scheme", "red-cyan", SCHEME_TEXT, SCHEME_LONGTEXT, false)
change_string_list(ppsz_scheme_values, ppsz_scheme_descriptions, 0)
set_callbacks(Create, Destroy)
vlc_module_end()
static const char *const ppsz_filter_options[] = {
"scheme", NULL
};
struct filter_sys_t
{
int left, right;
};
static int Create(vlc_object_t *p_this)
{
printf("pouet\n");
filter_t *p_filter = (filter_t *)p_this;
switch (p_filter->fmt_in.video.i_chroma)
{
case VLC_CODEC_I420:
case VLC_CODEC_J420:
case VLC_CODEC_YV12:
break;
default:
msg_Err(p_filter, "Unsupported input chroma (%4.4s)",
(char*)&(p_filter->fmt_in.video.i_chroma));
return VLC_EGENERIC;
}
p_filter->p_sys = malloc(sizeof(filter_sys_t));
if (!p_filter->p_sys)
return VLC_ENOMEM;
filter_sys_t *p_sys = p_filter->p_sys;
config_ChainParse(p_filter, FILTER_PREFIX, ppsz_filter_options,
p_filter->p_cfg);
char *psz_scheme = var_CreateGetStringCommand(p_filter,
FILTER_PREFIX "scheme");
enum scheme_e scheme = red_cyan;
if (psz_scheme)
{
if (!strcmp(psz_scheme, "red-green"))
scheme = red_green;
else if (!strcmp(psz_scheme, "red-blue"))
scheme = red_blue;
else if (!strcmp(psz_scheme, "red-cyan"))
scheme = red_cyan;
else if (!strcmp(psz_scheme, "trioscopic"))
scheme = trioscopic;
else if (!strcmp(psz_scheme, "magenta-cyan"))
scheme = magenta_cyan;
else
msg_Err(p_filter, "Unknown anaglyph color scheme '%s'", psz_scheme);
}
free(psz_scheme);
switch (scheme)
{
case red_green:
p_sys->left = 0xff0000;
p_sys->right = 0x00ff00;
break;
case red_blue:
p_sys->left = 0xff0000;
p_sys->right = 0x0000ff;
break;
case red_cyan:
p_sys->left = 0xff0000;
p_sys->right = 0x00ffff;
break;
case trioscopic:
p_sys->left = 0x00ff00;
p_sys->right = 0xff00ff;
break;
case magenta_cyan:
p_sys->left = 0xff00ff;
p_sys->right = 0x00ffff;
break;
case unknown:
msg_Err(p_filter, "Oops");
break;
}
p_filter->pf_video_filter = Filter;
return VLC_SUCCESS;
}
static void Destroy(vlc_object_t *p_this)
{
filter_t *p_filter = (filter_t *)p_this;
filter_sys_t *p_sys = p_filter->p_sys;
free(p_sys);
}
static picture_t *Filter(filter_t *p_filter, picture_t *p_pic)
{
filter_sys_t *p_sys = p_filter->p_sys;
if (!p_pic)
return NULL;
picture_t *p_outpic = filter_NewPicture(p_filter);
if (!p_outpic)
{
picture_Release(p_pic);
return NULL;
}
switch (p_pic->format.i_chroma)
{
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);
break;
default:
msg_Warn(p_filter, "Unsupported input chroma (%4.4s)",
(char*)&(p_pic->format.i_chroma));
picture_Release(p_pic);
return NULL;
}
return CopyInfoAndRelease(p_outpic, p_pic);
}
static void combine_side_by_side_yuv420(picture_t *p_inpic, picture_t *p_outpic,
int left, int right)
{
uint8_t *y1inl = p_inpic->p[Y_PLANE].p_pixels;
uint8_t *y2inl;
uint8_t *uinl = p_inpic->p[U_PLANE].p_pixels;
uint8_t *vinl = p_inpic->p[V_PLANE].p_pixels;
uint8_t *y1out = p_outpic->p[Y_PLANE].p_pixels;
uint8_t *y2out;
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 out_pitch = p_outpic->p[Y_PLANE].i_pitch;
const int visible_pitch = p_inpic->p[Y_PLANE].i_visible_pitch;
const int visible_lines = p_inpic->p[Y_PLANE].i_visible_lines;
const int uv_visible_pitch = p_inpic->p[U_PLANE].i_visible_pitch;
const uint8_t *yend = y1inl + visible_lines * in_pitch;
while (y1inl < yend)
{
uint8_t *y1inr = y1inl + visible_pitch/2;
uint8_t *y2inr;
uint8_t *uinr = uinl + uv_visible_pitch/2;
uint8_t *vinr = vinl + uv_visible_pitch/2;
const uint8_t *y1end = y1inr;
y2inl = y1inl + in_pitch;
y2inr = y1inr + in_pitch;
y2out = y1out + out_pitch;
while (y1inl < y1end)
{
int rl, gl, bl, rr, gr, br, r, g, b;
int rshift = !!((0xff0000&left) && (0xff0000&right));
int gshift = !!((0x00ff00&left) && (0x00ff00&right));
int bshift = !!((0x0000ff&left) && (0x0000ff&right));
yuv_to_rgb(&rl, &gl, &bl, *y1inl, *uinl, *vinl);
yuv_to_rgb(&rr, &gr, &br, *y1inr, *uinr, *vinr);
r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
rgb_to_yuv(y1out, uout++, vout++, r, g, b);
y1out[1] = *y1out;
y1out+=2;
y1inl++;
y1inr++;
yuv_to_rgb(&rl, &gl, &bl, *y1inl, *uinl, *vinl);
yuv_to_rgb(&rr, &gr, &br, *y1inr, *uinr, *vinr);
r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
rgb_to_yuv(y1out, uout++, vout++, r, g, b);
y1out[1] = *y1out;
y1out+=2;
y1inl++;
y1inr++;
yuv_to_rgb(&rl, &gl, &bl, *y2inl, *uinl, *vinl);
yuv_to_rgb(&rr, &gr, &br, *y2inr, *uinr, *vinr);
r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
rgb_to_yuv(y2out, uout/*will be overwritten later, as will vout*/, vout, r, g, b);
y2out[1] = *y2out;
y2out+=2;
y2inl++;
y2inr++;
yuv_to_rgb(&rl, &gl, &bl, *y2inl, *uinl, *vinl);
yuv_to_rgb(&rr, &gr, &br, *y2inr, *uinr, *vinr);
r = ((!!(0xff0000&left))*rl + (!!(0xff0000&right))*rr)>>rshift;
g = ((!!(0x00ff00&left))*gl + (!!(0x00ff00&right))*gr)>>gshift;
b = ((!!(0x0000ff&left))*bl + (!!(0x0000ff&right))*br)>>bshift;
rgb_to_yuv(y2out, uout/*will be overwritten later, as will vout*/, vout, r, g, b);
y2out[1] = *y2out;
y2out+=2;
y2inl++;
y2inr++;
uinl++;
vinl++;
uinr++;
vinr++;
}
y1inl = y1inr + 2*in_pitch - visible_pitch;
y1out += 2*out_pitch - visible_pitch;
uinl = uinr + p_inpic->p[U_PLANE].i_pitch - uv_visible_pitch;
vinl = vinr + p_inpic->p[V_PLANE].i_pitch - uv_visible_pitch;
uout += p_outpic->p[U_PLANE].i_pitch - uv_visible_pitch;
vout += p_outpic->p[V_PLANE].i_pitch - uv_visible_pitch;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment