vlc/modules/video_filter/mirror.c

585 lines
22 KiB
C
Raw Permalink Normal View History

/*****************************************************************************
* mirror.c : Mirror video plugin for vlc
*****************************************************************************
LGPL Re-license almost all the playback modules to LGPLv2.1+ with authorization from their respective contributors (230+) This includes: - access, codec, packetizers, demux - audio filters, audio mixers, audio output - video filters, video chroma, video output - text renderers - XML parser - ARM NEON and SSE2 optimisations (mostly for chromas and filters) Some modules are not concerned: - BDA and DShow access modules because Manol Manolov is AWOL - Real RTSP, because it is derived from Xine - x264 and t140 because they are encoders only - DLL Loader, because it is derived from MPlayer - DTS packetizer, because Jon Lech Johansen is AWOL - Shine and WMAfixed, because they are derived from Rockbox - Real demuxer, as it is derived from MPlayer and Wang Bo is AWOL - MPC demuxer, as Yavor Doganov is AWOL - Tivo demuxer, because it is derived from an MPlayer fork - Playlist demuxer, (WPL and ZPL parts missing), because suheaven is AWOL - iOS audio output and video display, because author refuses the license change - Equalizer and compressor, because Ronald Wright is AWOL - Mono, Headphone and Dolby, because author refuses the license change - hqdn3d and yadif, because they are from MPlayer/libavfilter - remoteosd, because it derives from RealVNC code - MMX optimisations, because Ollie Lho, from SiS, is AWOL - Rotate, because it depends on GPL motion Nota Bene: - Some modules depend on GPL-only libraries, a LGPL module does not mean that the resulting binary module will be LGPL. Libraries affected would include liba52, libdvdcss, libdvdnav, libdvdread, faad2, libdca, libmad, libmpeg2, libpostproc, SRC, sid, zvbi and probably others.
2012-11-06 17:48:33 +01:00
* Copyright (C) 2009 VLC authors and VideoLAN
*
* Authors: Branko Kokanovic <branko.kokanovic@gmail.com>
*
LGPL Re-license almost all the playback modules to LGPLv2.1+ with authorization from their respective contributors (230+) This includes: - access, codec, packetizers, demux - audio filters, audio mixers, audio output - video filters, video chroma, video output - text renderers - XML parser - ARM NEON and SSE2 optimisations (mostly for chromas and filters) Some modules are not concerned: - BDA and DShow access modules because Manol Manolov is AWOL - Real RTSP, because it is derived from Xine - x264 and t140 because they are encoders only - DLL Loader, because it is derived from MPlayer - DTS packetizer, because Jon Lech Johansen is AWOL - Shine and WMAfixed, because they are derived from Rockbox - Real demuxer, as it is derived from MPlayer and Wang Bo is AWOL - MPC demuxer, as Yavor Doganov is AWOL - Tivo demuxer, because it is derived from an MPlayer fork - Playlist demuxer, (WPL and ZPL parts missing), because suheaven is AWOL - iOS audio output and video display, because author refuses the license change - Equalizer and compressor, because Ronald Wright is AWOL - Mono, Headphone and Dolby, because author refuses the license change - hqdn3d and yadif, because they are from MPlayer/libavfilter - remoteosd, because it derives from RealVNC code - MMX optimisations, because Ollie Lho, from SiS, is AWOL - Rotate, because it depends on GPL motion Nota Bene: - Some modules depend on GPL-only libraries, a LGPL module does not mean that the resulting binary module will be LGPL. Libraries affected would include liba52, libdvdcss, libdvdnav, libdvdread, faad2, libdca, libmad, libmpeg2, libpostproc, SRC, sid, zvbi and probably others.
2012-11-06 17:48:33 +01:00
* 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
* the Free Software Foundation; either version 2.1 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
LGPL Re-license almost all the playback modules to LGPLv2.1+ with authorization from their respective contributors (230+) This includes: - access, codec, packetizers, demux - audio filters, audio mixers, audio output - video filters, video chroma, video output - text renderers - XML parser - ARM NEON and SSE2 optimisations (mostly for chromas and filters) Some modules are not concerned: - BDA and DShow access modules because Manol Manolov is AWOL - Real RTSP, because it is derived from Xine - x264 and t140 because they are encoders only - DLL Loader, because it is derived from MPlayer - DTS packetizer, because Jon Lech Johansen is AWOL - Shine and WMAfixed, because they are derived from Rockbox - Real demuxer, as it is derived from MPlayer and Wang Bo is AWOL - MPC demuxer, as Yavor Doganov is AWOL - Tivo demuxer, because it is derived from an MPlayer fork - Playlist demuxer, (WPL and ZPL parts missing), because suheaven is AWOL - iOS audio output and video display, because author refuses the license change - Equalizer and compressor, because Ronald Wright is AWOL - Mono, Headphone and Dolby, because author refuses the license change - hqdn3d and yadif, because they are from MPlayer/libavfilter - remoteosd, because it derives from RealVNC code - MMX optimisations, because Ollie Lho, from SiS, is AWOL - Rotate, because it depends on GPL motion Nota Bene: - Some modules depend on GPL-only libraries, a LGPL module does not mean that the resulting binary module will be LGPL. Libraries affected would include liba52, libdvdcss, libdvdnav, libdvdread, faad2, libdca, libmad, libmpeg2, libpostproc, SRC, sid, zvbi and probably others.
2012-11-06 17:48:33 +01:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
LGPL Re-license almost all the playback modules to LGPLv2.1+ with authorization from their respective contributors (230+) This includes: - access, codec, packetizers, demux - audio filters, audio mixers, audio output - video filters, video chroma, video output - text renderers - XML parser - ARM NEON and SSE2 optimisations (mostly for chromas and filters) Some modules are not concerned: - BDA and DShow access modules because Manol Manolov is AWOL - Real RTSP, because it is derived from Xine - x264 and t140 because they are encoders only - DLL Loader, because it is derived from MPlayer - DTS packetizer, because Jon Lech Johansen is AWOL - Shine and WMAfixed, because they are derived from Rockbox - Real demuxer, as it is derived from MPlayer and Wang Bo is AWOL - MPC demuxer, as Yavor Doganov is AWOL - Tivo demuxer, because it is derived from an MPlayer fork - Playlist demuxer, (WPL and ZPL parts missing), because suheaven is AWOL - iOS audio output and video display, because author refuses the license change - Equalizer and compressor, because Ronald Wright is AWOL - Mono, Headphone and Dolby, because author refuses the license change - hqdn3d and yadif, because they are from MPlayer/libavfilter - remoteosd, because it derives from RealVNC code - MMX optimisations, because Ollie Lho, from SiS, is AWOL - Rotate, because it depends on GPL motion Nota Bene: - Some modules depend on GPL-only libraries, a LGPL module does not mean that the resulting binary module will be LGPL. Libraries affected would include liba52, libdvdcss, libdvdnav, libdvdread, faad2, libdca, libmad, libmpeg2, libpostproc, SRC, sid, zvbi and probably others.
2012-11-06 17:48:33 +01:00
* You should have received a copy of the GNU Lesser 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
#include <stdatomic.h>
#include <vlc_common.h>
#include <vlc_configuration.h>
#include <vlc_plugin.h>
#include <vlc_filter.h>
#include <vlc_picture.h>
#include "filter_picture.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Create ( filter_t * );
static void VerticalMirror( picture_t *, picture_t *, int plane, bool );
static void HorizontalMirror( picture_t *, picture_t *, int, bool );
static void PlanarVerticalMirror( picture_t *, picture_t *, int plane, bool );
static void YUV422VerticalMirror( picture_t *, picture_t *, int plane, bool, bool );
static void RV24VerticalMirror( picture_t *, picture_t *, int plane, bool );
static void RV32VerticalMirror( picture_t *, picture_t *, int plane, bool );
static void YUV422Mirror2Pixels( uint8_t *, uint8_t *, bool );
VIDEO_FILTER_WRAPPER_CLOSE(Filter, Destroy)
static const char *const ppsz_filter_options[] = {
"split", "direction", NULL
};
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#define ORIENTATION_TEXT N_("Mirror orientation")
#define ORIENTATION_LONGTEXT N_("Defines orientation of the mirror splitting. " \
"Can be vertical or horizontal." )
static const int pi_orientation_values[] = { 0, 1 };
static const char *const ppsz_orientation_descriptions[] = {
N_("Vertical"), N_("Horizontal") };
#define DIRECTION_TEXT N_("Direction")
#define DIRECTION_LONGTEXT N_("Direction of the mirroring." )
static const int pi_direction_values[] = { 0, 1 };
static const char *const ppsz_direction_descriptions[] = {
N_("Left to right/Top to bottom"), N_("Right to left/Bottom to top") };
#define CFG_PREFIX "mirror-"
vlc_module_begin ()
set_description( N_("Mirror video filter") )
set_shortname( N_("Mirror video" ))
set_help( N_("Splits video in two same parts, like in a mirror") )
set_subcategory( SUBCAT_VIDEO_VFILTER )
2010-10-22 20:05:50 +02:00
add_integer( CFG_PREFIX "split", 0, ORIENTATION_TEXT,
ORIENTATION_LONGTEXT )
change_integer_list( pi_orientation_values,
ppsz_orientation_descriptions )
2010-10-22 20:05:50 +02:00
add_integer( CFG_PREFIX "direction", 0, DIRECTION_TEXT,
DIRECTION_LONGTEXT )
change_integer_list( pi_direction_values, ppsz_direction_descriptions )
set_callback_video_filter( Create )
vlc_module_end ()
/*****************************************************************************
* callback prototypes
*****************************************************************************/
static int FilterCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
/*****************************************************************************
* filter_sys_t: adjust filter method descriptor
*****************************************************************************/
typedef struct
{
atomic_int i_split;
atomic_int i_direction;
} filter_sys_t;
/*****************************************************************************
* Create: allocates Mirror video thread output method
*****************************************************************************
* This function allocates and initializes a Mirror vout method.
*****************************************************************************/
static int Create( filter_t *p_filter )
{
filter_sys_t *p_sys;
switch( p_filter->fmt_in.video.i_chroma )
{
CASE_PLANAR_YUV_SQUARE
break;
CASE_PACKED_YUV_422
break;
CASE_PACKED_RGB32
break;
case VLC_CODEC_RGB24:
case VLC_CODEC_BGR24:
break;
default:
msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
(char*)&(p_filter->fmt_in.video.i_chroma) );
return VLC_EGENERIC;
}
if( !video_format_IsSameChroma( &p_filter->fmt_in.video,
&p_filter->fmt_out.video ) )
{
msg_Err( p_filter, "Input and output chromas don't match" );
return VLC_EGENERIC;
}
/* Allocate structure */
p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
if( p_filter->p_sys == NULL )
return VLC_ENOMEM;
config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
p_filter->p_cfg );
atomic_init( &p_sys->i_split,
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "split" ) );
atomic_init( &p_sys->i_direction,
var_CreateGetIntegerCommand( p_filter,
CFG_PREFIX "direction" ) );
var_AddCallback( p_filter, CFG_PREFIX "split", FilterCallback, p_sys );
var_AddCallback( p_filter, CFG_PREFIX "direction", FilterCallback, p_sys );
p_filter->ops = &Filter_ops;
return VLC_SUCCESS;
}
/*****************************************************************************
* Destroy: destroy Mirror video thread output method
*****************************************************************************
* Terminate an output method created by MirrorCreateOutputMethod
*****************************************************************************/
static void Destroy( filter_t *p_filter )
{
filter_sys_t *p_sys = p_filter->p_sys;
var_DelCallback( p_filter, CFG_PREFIX "split", FilterCallback, p_sys );
var_DelCallback( p_filter, CFG_PREFIX "direction", FilterCallback, p_sys );
free( p_sys );
}
/*****************************************************************************
* Render: displays previously rendered output
*****************************************************************************
* This function send the currently rendered image to Mirror image, waits
* until it is displayed and switch the two rendering buffers, preparing next
* frame.
*****************************************************************************/
static void Filter( filter_t *p_filter, picture_t *p_pic, picture_t *p_outpic )
{
bool b_vertical_split, b_left_to_right;
filter_sys_t *p_sys = p_filter->p_sys;
b_vertical_split = !atomic_load( &p_sys->i_split );
b_left_to_right = !atomic_load( &p_sys->i_direction );
for( int i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
{
if ( b_vertical_split )
VerticalMirror( p_pic, p_outpic, i_index, b_left_to_right );
else
HorizontalMirror( p_pic, p_outpic, i_index, b_left_to_right );
}
}
/*****************************************************************************
* VerticalMirror: Mirrors vertically image
*****************************************************************************
* This function is a simple delegate to concrete function for vertical
* mirroring depending on the input format.
*****************************************************************************/
static void VerticalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
bool b_left_to_right )
{
switch( p_pic->format.i_chroma )
{
CASE_PLANAR_YUV_SQUARE
PlanarVerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
break;
case VLC_CODEC_YUYV:
case VLC_CODEC_YVYU:
YUV422VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right,
true );
break;
case VLC_CODEC_UYVY:
break;
case VLC_CODEC_RGB24:
case VLC_CODEC_BGR24:
RV24VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
break;
CASE_PACKED_RGB32
RV32VerticalMirror( p_pic, p_outpic, i_plane, b_left_to_right );
break;
default:
vlc_assert_unreachable();
}
}
/*****************************************************************************
* PlanarVerticalMirror: Mirrors vertically image byte by byte
*****************************************************************************
* This function mirrors image vertically. It iterates for all lines in
* image and for every line, it mirrors byte for byte if needed.
* This function works for planar formats only.
*****************************************************************************/
static void PlanarVerticalMirror( picture_t *p_pic, picture_t *p_outpic,
int i_plane, bool b_left_to_right )
{
uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
p_in = p_pic->p[i_plane].p_pixels;
p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
* p_pic->p[i_plane].i_pitch;
p_out = p_outpic->p[i_plane].p_pixels;
while( p_in < p_in_end ) {
p_line_start = p_in;
p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
while( p_in < p_line_end )
{
/* are we in the left part of the line */
if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
{
if ( b_left_to_right )
*p_out = *p_in;
else
*p_out = *( p_line_end - ( p_in - p_line_start ) );
}
else
{
if ( b_left_to_right )
*p_out = *( p_line_start + ( p_line_end - p_in ) );
else
*p_out = *p_in;
}
p_in++;
p_out++;
}
p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
p_out += p_outpic->p[i_plane].i_pitch
- p_outpic->p[i_plane].i_visible_pitch;
}
}
/*****************************************************************************
* YUV422VerticalMirror: Mirrors vertically image byte by byte for YUV422 format
*****************************************************************************
* This function mirrors image vertically. It iterates for all lines in
LGPL Re-license almost all the playback modules to LGPLv2.1+ with authorization from their respective contributors (230+) This includes: - access, codec, packetizers, demux - audio filters, audio mixers, audio output - video filters, video chroma, video output - text renderers - XML parser - ARM NEON and SSE2 optimisations (mostly for chromas and filters) Some modules are not concerned: - BDA and DShow access modules because Manol Manolov is AWOL - Real RTSP, because it is derived from Xine - x264 and t140 because they are encoders only - DLL Loader, because it is derived from MPlayer - DTS packetizer, because Jon Lech Johansen is AWOL - Shine and WMAfixed, because they are derived from Rockbox - Real demuxer, as it is derived from MPlayer and Wang Bo is AWOL - MPC demuxer, as Yavor Doganov is AWOL - Tivo demuxer, because it is derived from an MPlayer fork - Playlist demuxer, (WPL and ZPL parts missing), because suheaven is AWOL - iOS audio output and video display, because author refuses the license change - Equalizer and compressor, because Ronald Wright is AWOL - Mono, Headphone and Dolby, because author refuses the license change - hqdn3d and yadif, because they are from MPlayer/libavfilter - remoteosd, because it derives from RealVNC code - MMX optimisations, because Ollie Lho, from SiS, is AWOL - Rotate, because it depends on GPL motion Nota Bene: - Some modules depend on GPL-only libraries, a LGPL module does not mean that the resulting binary module will be LGPL. Libraries affected would include liba52, libdvdcss, libdvdnav, libdvdread, faad2, libdca, libmad, libmpeg2, libpostproc, SRC, sid, zvbi and probably others.
2012-11-06 17:48:33 +01:00
* image and for every line, iterates for 4-byte chucks, properly mirroring
* them vertically (swapping Y components and keeping Cb and Cr components).
* This function works only for YUV422 packed formats.
*****************************************************************************/
static void YUV422VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
int i_plane, bool b_left_to_right,
bool b_y_is_odd )
{
uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
p_in = p_pic->p[i_plane].p_pixels;
p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
* p_pic->p[i_plane].i_pitch;
p_out = p_outpic->p[i_plane].p_pixels;
while( p_in < p_in_end )
{
p_line_start = p_in;
p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
while( p_in < p_line_end )
{
/* are we in the left part of the line */
if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
{
if ( b_left_to_right )
{
*p_out++ = *p_in++;
*p_out++ = *p_in++;
*p_out++ = *p_in++;
*p_out++ = *p_in++;
}
else
{
uint8_t *p_start = p_line_end - ( p_in - p_line_start );
YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
p_in += 4;
p_out += 4;
}
}
else
{
if ( b_left_to_right )
{
uint8_t *p_start = p_line_end - ( p_in - p_line_start );
YUV422Mirror2Pixels( p_out, p_start, b_y_is_odd );
p_in += 4;
p_out += 4;
}
else
{
*p_out++ = *p_in++;
*p_out++ = *p_in++;
*p_out++ = *p_in++;
*p_out++ = *p_in++;
}
}
}
p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
p_out += p_outpic->p[i_plane].i_pitch
- p_outpic->p[i_plane].i_visible_pitch;
}
}
/*****************************************************************************
* YUV422Mirror2Pixels: Mirrors 2 consecutive pixels
*****************************************************************************
* This function mirrors two consecutive pixels of 4 byte size. Depending of
* position of Y components (b_y_is_odd is true if Y components are first and
* third (like in YUYV or YVYU), they are properly swapped, and Cb and Cr
* component positions are preserved.
*****************************************************************************/
static void YUV422Mirror2Pixels( uint8_t* p_dst, uint8_t *p_src,
bool b_y_is_odd )
{
if ( b_y_is_odd )
{
/* swap Y components */
*p_dst = *( p_src + 2 );
*( p_dst + 2 ) = *p_src;
/* copy Cb and Cr components */
*( p_dst + 1 ) = *( p_src + 1 );
*( p_dst + 3 ) = *( p_src + 3 );
}
else{
/* swap Y components */
*( p_dst + 1 )= *( p_src + 3 );
*( p_dst + 3 ) = *( p_src + 1);
/* copy Cb and Cr components */
*p_dst = *( p_src + 2 );
*( p_dst + 2 ) = *p_src;
}
}
/*****************************************************************************
* RV24VerticalMirror: Mirrors vertically image byte by byte for RV24 format
*****************************************************************************
* This function mirrors image vertically. It iterates for all lines in
* image and for every line, it iterates for 3-byte chunks.
* This function works only for RV24 formats.
*****************************************************************************/
static void RV24VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
int i_plane, bool b_left_to_right )
{
uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
p_in = p_pic->p[i_plane].p_pixels;
p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
* p_pic->p[i_plane].i_pitch;
p_out = p_outpic->p[i_plane].p_pixels;
while( p_in < p_in_end )
{
p_line_start = p_in;
p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
while( p_in < p_line_end )
{
/* are we in the left part of the line */
if ( p_in < p_line_start + ( p_line_end - p_line_start ) / 2 )
{
if ( b_left_to_right )
{
*p_out++ = *p_in++;
*p_out++ = *p_in++;
*p_out++ = *p_in++;
}
else
{
uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
p_in += 3;
*p_out++ = *p_pixel++;
*p_out++ = *p_pixel++;
*p_out++ = *p_pixel++;
}
}
else
{
if ( b_left_to_right )
{
uint8_t *p_pixel = p_line_end - ( p_in - p_line_start );
p_in += 3;
*p_out++ = *p_pixel++;
*p_out++ = *p_pixel++;
*p_out++ = *p_pixel++;
}
else
{
*p_out++ = *p_in++;
*p_out++ = *p_in++;
*p_out++ = *p_in++;
}
}
}
p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
p_out += p_outpic->p[i_plane].i_pitch
- p_outpic->p[i_plane].i_visible_pitch;
}
}
/*****************************************************************************
* RV32VerticalMirror: Mirrors vertically image byte by byte for RV32 format
*****************************************************************************
* This function mirrors image vertically. It iterates for all lines in
* image and for every line, it iterates for 4-byte chunks as 32-bit pointers.
* This function works only for RV32 formats.
*****************************************************************************/
static void RV32VerticalMirror( picture_t *p_pic, picture_t *p_outpic,
int i_plane, bool b_left_to_right )
{
uint8_t *p_in, *p_in_end, *p_out;
p_in = p_pic->p[i_plane].p_pixels;
p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
* p_pic->p[i_plane].i_pitch;
p_out = p_outpic->p[i_plane].p_pixels;
while( p_in < p_in_end )
{
uint32_t *p_in32, *p_out32, *p_line_start32, *p_line_end32;
p_in32 = (uint32_t*) p_in;
p_out32 = (uint32_t*) p_out;
p_line_start32 = p_in32;
p_line_end32 = (uint32_t*) ( p_in + p_pic->p[i_plane].i_visible_pitch) ;
while( p_in32 < p_line_end32 )
{
/* are we in the left part of the line */
if ( p_in32 < p_line_start32 + ( p_line_end32 - p_line_start32 ) / 2 )
{
if ( b_left_to_right )
{
*p_out32++ = *p_in32++;
}
else
{
uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
p_in32++;
*p_out++ = *p_pixel32;
}
}
else
{
if ( b_left_to_right )
{
uint32_t *p_pixel32 = p_line_end32 - ( p_in32 - p_line_start32 );
p_in32++;
*p_out++ = *p_pixel32;
}
else
{
*p_out32++ = *p_in32++;
}
}
}
p_in = (uint8_t*) p_in32;
p_out = (uint8_t*) p_out32;
p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
p_out += p_outpic->p[i_plane].i_pitch
- p_outpic->p[i_plane].i_visible_pitch;
}
}
/*****************************************************************************
* HorizontalMirror: Mirrors horizontally image byte by byte
*****************************************************************************
* This function mirrors image horizontally. It iterates for all lines in
* image and for every line, determines if it should be copied, and if it does,
* finds opposite line in picture and copies current byte from opposite line.
* This function works both for planar, packed and RV24 formats.
*****************************************************************************/
static void HorizontalMirror( picture_t *p_pic, picture_t *p_outpic, int i_plane,
bool b_top_to_bottom )
{
uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
int i_curr_line = 0;
int i_max_lines = p_pic->p[i_plane].i_visible_lines;
p_in = p_pic->p[i_plane].p_pixels;
p_in_end = p_in + p_pic->p[i_plane].i_visible_lines
* p_pic->p[i_plane].i_pitch;
p_out = p_outpic->p[i_plane].p_pixels;
while( p_in < p_in_end )
{
p_line_start = p_in;
p_line_end = p_in + p_pic->p[i_plane].i_visible_pitch;
while( p_in < p_line_end )
{
uint8_t *p_inverse_line;
/* are we in the upper part of the picture */
if ( i_curr_line < i_max_lines/2 )
{
if ( b_top_to_bottom )
{
*p_out = *p_in;
}
else
{
/* determines line inverse to current line */
p_inverse_line = p_pic->p[i_plane].p_pixels +
( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
*p_out = *( p_inverse_line + ( p_in - p_line_start ) );
}
}
else
{
if ( b_top_to_bottom )
{
/* determines line inverse to current line */
p_inverse_line = p_pic->p[i_plane].p_pixels +
( i_max_lines - i_curr_line - 1 ) * p_pic->p[i_plane].i_pitch;
*p_out = *( p_inverse_line + ( p_in - p_line_start ) );
}
else
{
*p_out = *p_in;
}
}
p_in++;
p_out++;
}
i_curr_line++;
p_in += p_pic->p[i_plane].i_pitch - p_pic->p[i_plane].i_visible_pitch;
p_out += p_outpic->p[i_plane].i_pitch
- p_outpic->p[i_plane].i_visible_pitch;
}
}
static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
(void) p_this; (void)oldval;
filter_sys_t *p_sys = p_data;
if( !strcmp( psz_var, CFG_PREFIX "split" ) )
atomic_store( &p_sys->i_split, newval.i_int );
else /* CFG_PREFIX "direction" */
atomic_store( &p_sys->i_direction, newval.i_int );
return VLC_SUCCESS;
}