From cd079331b9d03803f20d5e5e5cae23348731941c Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Mon, 7 Apr 2008 16:47:49 +0200 Subject: [PATCH] Fix transform plugin 90-degree rotations on I422. I422 is a planar chroma with non-square pixels. It requires some pixel play when rotating the image at a 90-degree angle. For other transformations we just fall back to the original function. --- modules/video_filter/filter_picture.h | 13 +- modules/video_filter/transform.c | 182 +++++++++++++++++++++++--- 2 files changed, 172 insertions(+), 23 deletions(-) diff --git a/modules/video_filter/filter_picture.h b/modules/video_filter/filter_picture.h index 98069034aa..73ef0d59f8 100644 --- a/modules/video_filter/filter_picture.h +++ b/modules/video_filter/filter_picture.h @@ -21,7 +21,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ -#define CASE_PLANAR_YUV \ +/* FIXME: do all of these really have square pixels? */ +#define CASE_PLANAR_YUV_SQUARE \ case VLC_FOURCC('I','4','2','0'): \ case VLC_FOURCC('I','Y','U','V'): \ case VLC_FOURCC('J','4','2','0'): \ @@ -29,12 +30,18 @@ case VLC_FOURCC('I','4','1','1'): \ case VLC_FOURCC('I','4','1','0'): \ case VLC_FOURCC('Y','V','U','9'): \ - case VLC_FOURCC('I','4','2','2'): \ - case VLC_FOURCC('J','4','2','2'): \ case VLC_FOURCC('I','4','4','4'): \ case VLC_FOURCC('J','4','4','4'): \ case VLC_FOURCC('Y','U','V','A'): +#define CASE_PLANAR_YUV_NONSQUARE \ + case VLC_FOURCC('I','4','2','2'): \ + case VLC_FOURCC('J','4','2','2'): + +#define CASE_PLANAR_YUV \ + CASE_PLANAR_YUV_SQUARE \ + CASE_PLANAR_YUV_NONSQUARE \ + #define CASE_PACKED_YUV_422 \ case VLC_FOURCC('U','Y','V','Y'): \ case VLC_FOURCC('U','Y','N','V'): \ diff --git a/modules/video_filter/transform.c b/modules/video_filter/transform.c index b658ffe39b..e8377454da 100644 --- a/modules/video_filter/transform.c +++ b/modules/video_filter/transform.c @@ -52,6 +52,7 @@ static void End ( vout_thread_t * ); static void Render ( vout_thread_t *, picture_t * ); static void FilterPlanar( vout_thread_t *, const picture_t *, picture_t * ); +static void FilterI422( vout_thread_t *, const picture_t *, picture_t * ); static void FilterYUYV( vout_thread_t *, const picture_t *, picture_t * ); static int SendEvents( vlc_object_t *, char const *, @@ -145,11 +146,16 @@ static int Create( vlc_object_t *p_this ) switch( p_vout->fmt_in.i_chroma ) { - CASE_PLANAR_YUV + CASE_PLANAR_YUV_SQUARE case VLC_FOURCC('G','R','E','Y'): p_vout->p_sys->pf_filter = FilterPlanar; break; + case VLC_FOURCC('I','4','2','2'): + case VLC_FOURCC('J','4','2','2'): + p_vout->p_sys->pf_filter = FilterI422; + break; + CASE_PACKED_YUV_422 p_vout->p_sys->pf_filter = FilterYUYV; break; @@ -551,6 +557,156 @@ static void FilterPlanar( vout_thread_t *p_vout, } } +static void FilterI422( vout_thread_t *p_vout, + const picture_t *p_pic, picture_t *p_outpic ) +{ + int i_index; + switch( p_vout->p_sys->i_mode ) + { + case TRANSFORM_MODE_180: + case TRANSFORM_MODE_HFLIP: + case TRANSFORM_MODE_VFLIP: + /* Fall back on the default implementation */ + FilterPlanar( p_vout, p_pic, p_outpic ); + return; + + case TRANSFORM_MODE_90: + for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) + { + int i_pitch = p_pic->p[i_index].i_pitch; + + uint8_t *p_in = p_pic->p[i_index].p_pixels; + + uint8_t *p_out = p_outpic->p[i_index].p_pixels; + uint8_t *p_out_end = p_out + + p_outpic->p[i_index].i_visible_lines * + p_outpic->p[i_index].i_pitch; + + if( i_index == 0 ) + { + for( ; p_out < p_out_end ; ) + { + uint8_t *p_line_end; + + p_out_end -= p_outpic->p[i_index].i_pitch + - p_outpic->p[i_index].i_visible_pitch; + p_line_end = p_in + p_pic->p[i_index].i_visible_lines * + i_pitch; + + for( ; p_in < p_line_end ; ) + { + p_line_end -= i_pitch; + *(--p_out_end) = *p_line_end; + } + + p_in++; + } + } + else /* i_index == 1 or 2 */ + { + for( ; p_out < p_out_end ; ) + { + uint8_t *p_line_end, *p_out_end2; + + p_out_end -= p_outpic->p[i_index].i_pitch + - p_outpic->p[i_index].i_visible_pitch; + p_out_end2 = p_out_end - p_outpic->p[i_index].i_pitch; + p_line_end = p_in + p_pic->p[i_index].i_visible_lines * + i_pitch; + + for( ; p_in < p_line_end ; ) + { + uint8_t p1, p2; + + p_line_end -= i_pitch; + p1 = *p_line_end; + p_line_end -= i_pitch; + p2 = *p_line_end; + + /* Trick for (x+y)/2 without overflow, based on + * x + y == (x ^ y) + 2 * (x & y) */ + *(--p_out_end) = (p1 & p2) + ((p1 ^ p2) / 2); + *(--p_out_end2) = (p1 & p2) + ((p1 ^ p2) / 2); + } + + p_out_end = p_out_end2; + p_in++; + } + } + } + break; + + case TRANSFORM_MODE_270: + for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) + { + int i_pitch = p_pic->p[i_index].i_pitch; + + uint8_t *p_in = p_pic->p[i_index].p_pixels; + + uint8_t *p_out = p_outpic->p[i_index].p_pixels; + uint8_t *p_out_end = p_out + + p_outpic->p[i_index].i_visible_lines * + p_outpic->p[i_index].i_pitch; + + if( i_index == 0 ) + { + for( ; p_out < p_out_end ; ) + { + uint8_t *p_in_end; + + p_in_end = p_in + p_pic->p[i_index].i_visible_lines * + i_pitch; + + for( ; p_in < p_in_end ; ) + { + p_in_end -= i_pitch; + *p_out++ = *p_in_end; + } + + p_out += p_outpic->p[i_index].i_pitch + - p_outpic->p[i_index].i_visible_pitch; + p_in++; + } + } + else /* i_index == 1 or 2 */ + { + for( ; p_out < p_out_end ; ) + { + uint8_t *p_in_end, *p_out2; + + p_in_end = p_in + p_pic->p[i_index].i_visible_lines * + i_pitch; + p_out2 = p_out + p_outpic->p[i_index].i_pitch; + + for( ; p_in < p_in_end ; ) + { + uint8_t p1, p2; + + p_in_end -= i_pitch; + p1 = *p_in_end; + p_in_end -= i_pitch; + p2 = *p_in_end; + + /* Trick for (x+y)/2 without overflow, based on + * x + y == (x ^ y) + 2 * (x & y) */ + *p_out++ = (p1 & p2) + ((p1 ^ p2) / 2); + *p_out2++ = (p1 & p2) + ((p1 ^ p2) / 2); + } + + p_out2 += p_outpic->p[i_index].i_pitch + - p_outpic->p[i_index].i_visible_pitch; + p_out = p_out2; + p_in++; + } + } + } + break; + + default: + break; + } +} + static void FilterYUYV( vout_thread_t *p_vout, const picture_t *p_pic, picture_t *p_outpic ) { @@ -562,6 +718,11 @@ static void FilterYUYV( vout_thread_t *p_vout, switch( p_vout->p_sys->i_mode ) { + case TRANSFORM_MODE_HFLIP: + /* Fall back on the default implementation */ + FilterPlanar( p_vout, p_pic, p_outpic ); + return; + case TRANSFORM_MODE_90: for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) { @@ -684,25 +845,6 @@ static void FilterYUYV( vout_thread_t *p_vout, } break; - case TRANSFORM_MODE_HFLIP: - for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) - { - uint8_t *p_in = p_pic->p[i_index].p_pixels; - uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines - * p_pic->p[i_index].i_pitch; - - uint8_t *p_out = p_outpic->p[i_index].p_pixels; - - for( ; p_in < p_in_end ; ) - { - p_in_end -= p_pic->p[i_index].i_pitch; - p_vout->p_libvlc->pf_memcpy( p_out, p_in_end, - p_pic->p[i_index].i_visible_pitch ); - p_out += p_pic->p[i_index].i_pitch; - } - } - break; - case TRANSFORM_MODE_VFLIP: for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) { -- 2.39.2