Commit ad8cbfd6 authored by Steve Lhomme's avatar Steve Lhomme Committed by Jean-Baptiste Kempf

chroma: add a converter from I420/YV12 to NV12

Signed-off-by: Jean-Baptiste Kempf's avatarJean-Baptiste Kempf <jb@videolan.org>
parent 89521258
......@@ -181,6 +181,7 @@ $Id$
* hqdn3d: High Quality denoising filter
* http: HTTP Network access module
* https: HTTP/TLS access module for HTTP 2.0 support
* i420_nv12: planar YUV to semi-planar YUV conversion functions
* i420_rgb: planar YUV to packed RGB conversion functions
* i420_rgb_mmx: MMX accelerated version of i420_rgb
* i420_rgb_sse2: sse2 accelerated version of i420_rgb
......
......@@ -21,6 +21,11 @@ libi420_yuy2_plugin_la_SOURCES = video_chroma/i420_yuy2.c video_chroma/i420_yuy2
libi420_yuy2_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
-DMODULE_NAME_IS_i420_yuy2
libi420_nv12_plugin_la_SOURCES = video_chroma/i420_nv12.c \
video_chroma/copy.c video_chroma/copy.h
libi420_nv12_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
-DMODULE_NAME_IS_i420_nv12
libi422_i420_plugin_la_SOURCES = video_chroma/i422_i420.c
libi422_yuy2_plugin_la_SOURCES = video_chroma/i422_yuy2.c video_chroma/i422_yuy2.h
......@@ -38,6 +43,7 @@ libyuvp_plugin_la_SOURCES = video_chroma/yuvp.c
chroma_LTLIBRARIES = \
libi420_rgb_plugin.la \
libi420_yuy2_plugin.la \
libi420_nv12_plugin.la \
libi422_i420_plugin.la \
libi422_yuy2_plugin.la \
libgrey_yuv_plugin.la \
......
......@@ -365,6 +365,41 @@ static void SSE_CopyFromNv12ToNv12(picture_t *dst,
width, height/2, cpu);
asm volatile ("emms");
}
static void SSE_CopyFromI420ToNv12(picture_t *dst,
uint8_t *src[2], size_t src_pitch[2],
unsigned width, unsigned height,
copy_cache_t *cache, unsigned cpu)
{
SSE_CopyPlane(dst->p[0].p_pixels, dst->p[0].i_pitch,
src[0], src_pitch[0],
cache->buffer, cache->size,
width, height, cpu);
/* TODO optimise the plane merging */
const unsigned copy_lines = height / 2;
const unsigned copy_pitch = width / 2;
const int i_extra_pitch_uv = dst->p[1].i_pitch - 2 * copy_pitch;
const int i_extra_pitch_u = src_pitch[U_PLANE] - copy_pitch;
const int i_extra_pitch_v = src_pitch[V_PLANE] - copy_pitch;
uint8_t *dstUV = dst->p[1].p_pixels;
uint8_t *srcU = src[U_PLANE];
uint8_t *srcV = src[V_PLANE];
for ( unsigned int line = 0; line < copy_lines; line++ )
{
for ( unsigned int col = 0; col < copy_pitch; col++ )
{
*dstUV++ = *srcU++;
*dstUV++ = *srcV++;
}
dstUV += i_extra_pitch_uv;
srcU += i_extra_pitch_u;
srcV += i_extra_pitch_v;
}
asm volatile ("emms");
}
#undef COPY64
#endif /* CAN_COMPILE_SSE2 */
......@@ -450,6 +485,47 @@ void CopyFromNv12ToI420(picture_t *dst, uint8_t *src[2], size_t src_pitch[2],
width/2, height/2);
}
void CopyFromI420ToNv12(picture_t *dst, uint8_t *src[3], size_t src_pitch[3],
unsigned width, unsigned height,
copy_cache_t *cache)
{
#ifdef CAN_COMPILE_SSE2
unsigned cpu = vlc_CPU();
if (vlc_CPU_SSE2())
return SSE_CopyFromI420ToNv12(dst, src, src_pitch, width, height,
cache, cpu);
#else
(void) cache;
#endif
CopyPlane(dst->p[0].p_pixels, dst->p[0].i_pitch,
src[0], src_pitch[0],
width, height);
const unsigned copy_lines = height / 2;
const unsigned copy_pitch = width / 2;
const int i_extra_pitch_uv = dst->p[1].i_pitch - 2 * copy_pitch;
const int i_extra_pitch_u = src_pitch[U_PLANE] - copy_pitch;
const int i_extra_pitch_v = src_pitch[V_PLANE] - copy_pitch;
uint8_t *dstUV = dst->p[1].p_pixels;
uint8_t *srcU = src[U_PLANE];
uint8_t *srcV = src[V_PLANE];
for ( unsigned int line = 0; line < copy_lines; line++ )
{
for ( unsigned int col = 0; col < copy_pitch; col++ )
{
*dstUV++ = *srcU++;
*dstUV++ = *srcV++;
}
dstUV += i_extra_pitch_uv;
srcU += i_extra_pitch_u;
srcV += i_extra_pitch_v;
}
}
void CopyFromYv12(picture_t *dst, uint8_t *src[3], size_t src_pitch[3],
unsigned width, unsigned height,
copy_cache_t *cache)
......
......@@ -50,4 +50,8 @@ void CopyFromNv12ToNv12(picture_t *dst, uint8_t *src[2], size_t src_pitch[2],
void CopyFromNv12ToI420(picture_t *dst, uint8_t *src[2], size_t src_pitch[2],
unsigned width, unsigned height);
void CopyFromI420ToNv12(picture_t *dst, uint8_t *src[3], size_t src_pitch[3],
unsigned width, unsigned height,
copy_cache_t *cache);
#endif
/*****************************************************************************
* i420_nv12.c : Planar YUV 4:2:0 to Planar NV12 4:2:0 to conversion module for vlc
*****************************************************************************
* Copyright (C) 2016 VLC authors and VideoLAN
*
* Authors: Steve Lhomme <robux4@videolabs.io>
*
* 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
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* 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 <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_filter.h>
#include "copy.h"
#include <assert.h>
#define SRC_FOURCC "I420,YV12"
#define DEST_FOURCC "NV12"
/*****************************************************************************
* Local and extern prototypes.
*****************************************************************************/
static void I420_NV12( filter_t *, picture_t *, picture_t * );
static void YV12_NV12( filter_t *, picture_t *, picture_t * );
static picture_t *I420_NV12_Filter( filter_t *, picture_t * );
static picture_t *YV12_NV12_Filter( filter_t *, picture_t * );
struct filter_sys_t
{
copy_cache_t cache;
};
/*****************************************************************************
* Create: allocate a chroma function
*****************************************************************************
* This function allocates and initializes a chroma function
*****************************************************************************/
static int Create( vlc_object_t *p_this )
{
filter_t *p_filter = (filter_t *)p_this;
if( p_filter->fmt_in.video.i_width & 1
|| p_filter->fmt_in.video.i_height & 1 )
{
return -1;
}
if( p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width
|| p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height
|| p_filter->fmt_in.video.orientation != p_filter->fmt_out.video.orientation )
return -1;
switch( p_filter->fmt_in.video.i_chroma )
{
case VLC_CODEC_I420:
case VLC_CODEC_J420:
p_filter->pf_video_filter = I420_NV12_Filter;
break;
case VLC_CODEC_YV12:
p_filter->pf_video_filter = YV12_NV12_Filter;
break;
default:
return -1;
}
filter_sys_t *p_sys = calloc(1, sizeof(filter_sys_t));
if (!p_sys)
return VLC_ENOMEM;
CopyInitCache( &p_sys->cache, p_filter->fmt_in.video.i_x_offset +
p_filter->fmt_in.video.i_visible_width );
p_filter->p_sys = p_sys;
return 0;
}
static void Delete(vlc_object_t *p_this)
{
filter_t *p_filter = (filter_t *)p_this;
filter_sys_t *p_sys = p_filter->p_sys;
CopyCleanCache( &p_sys->cache );
}
/* Following functions are local */
VIDEO_FILTER_WRAPPER( I420_NV12 )
VIDEO_FILTER_WRAPPER( YV12_NV12 )
#define UVPLANE 1
static void I420_YUV( filter_sys_t *p_sys, picture_t *p_src, picture_t *p_dst, bool invertUV )
{
p_dst->format.i_x_offset = p_src->format.i_x_offset;
p_dst->format.i_y_offset = p_src->format.i_y_offset;
const size_t u_plane = invertUV ? V_PLANE : U_PLANE;
const size_t v_plane = invertUV ? U_PLANE : V_PLANE;
size_t pitch[3] = {
p_src->p[Y_PLANE].i_pitch,
p_src->p[u_plane].i_pitch,
p_src->p[v_plane].i_pitch,
};
uint8_t *plane[3] = {
(uint8_t*)p_src->p[Y_PLANE].p_pixels,
(uint8_t*)p_src->p[u_plane].p_pixels,
(uint8_t*)p_src->p[v_plane].p_pixels,
};
CopyFromI420ToNv12( p_dst, plane, pitch,
p_src->format.i_x_offset + p_src->format.i_visible_width,
p_src->format.i_y_offset + p_src->format.i_visible_height,
&p_sys->cache );
}
/*****************************************************************************
* planar I420 4:2:0 Y:U:V to planar NV12 4:2:0 Y:UV
*****************************************************************************/
static void I420_NV12( filter_t *p_filter, picture_t *p_src,
picture_t *p_dst )
{
I420_YUV( p_filter->p_sys, p_src, p_dst, false );
}
/*****************************************************************************
* planar YV12 4:2:0 Y:V:U to planar NV12 4:2:0 Y:UV
*****************************************************************************/
static void YV12_NV12( filter_t *p_filter, picture_t *p_src,
picture_t *p_dst )
{
I420_YUV( p_filter->p_sys, p_src, p_dst, true );
}
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin ()
set_description( N_("Conversions from " SRC_FOURCC " to " DEST_FOURCC) )
set_capability( "video filter2", 160 )
set_callbacks( Create, Delete )
vlc_module_end ()
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