[vlc-devel] [PATCH 3/4] chroma: add a converter from I420/YV12 to NV12

Steve Lhomme robux4 at videolabs.io
Wed May 11 16:01:23 CEST 2016


---
 modules/video_chroma/Makefile.am |   5 ++
 modules/video_chroma/i420_nv12.c | 190 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 195 insertions(+)
 create mode 100644 modules/video_chroma/i420_nv12.c

diff --git a/modules/video_chroma/Makefile.am b/modules/video_chroma/Makefile.am
index 7bcbf5a..7e04b37 100644
--- a/modules/video_chroma/Makefile.am
+++ b/modules/video_chroma/Makefile.am
@@ -21,6 +21,10 @@ 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
+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 +42,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 \
diff --git a/modules/video_chroma/i420_nv12.c b/modules/video_chroma/i420_nv12.c
new file mode 100644
index 0000000..de791e3
--- /dev/null
+++ b/modules/video_chroma/i420_nv12.c
@@ -0,0 +1,190 @@
+/*****************************************************************************
+ * 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 at 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 <assert.h>
+
+#define SRC_FOURCC  "I420,YV12"
+#define DEST_FOURCC "NV12"
+
+/*****************************************************************************
+ * Local and extern prototypes.
+ *****************************************************************************/
+static int  Activate ( vlc_object_t * );
+
+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 * );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin ()
+    set_description( N_("Conversions from " SRC_FOURCC " to " DEST_FOURCC) )
+    set_capability( "video filter2", 160 )
+    set_callbacks( Activate, NULL )
+vlc_module_end ()
+
+/*****************************************************************************
+ * Activate: allocate a chroma function
+ *****************************************************************************
+ * This function allocates and initializes a chroma function
+ *****************************************************************************/
+static int Activate( 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;
+    }
+    return 0;
+}
+
+/* Following functions are local */
+VIDEO_FILTER_WRAPPER( I420_NV12 )
+VIDEO_FILTER_WRAPPER( YV12_NV12 )
+
+#define UVPLANE 1
+
+/*****************************************************************************
+ * 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 )
+{
+    VLC_UNUSED(p_filter);
+    p_dst->format.i_x_offset = p_src->format.i_x_offset;
+    p_dst->format.i_y_offset = p_src->format.i_y_offset;
+
+    // copy Y plane
+    unsigned int copy_lines = __MAX( (unsigned int) p_dst->p[Y_PLANE].i_visible_lines,
+                            p_src->format.i_y_offset + p_src->format.i_visible_height );
+    memcpy( p_dst->p[Y_PLANE].p_pixels,
+            p_src->p[Y_PLANE].p_pixels,
+            copy_lines * p_dst->p[Y_PLANE].i_pitch );
+
+    // copy the U and V planes into UV
+    copy_lines = __MIN( __MAX( (unsigned int) p_dst->p[UVPLANE].i_visible_lines,
+                               ( p_src->format.i_y_offset + p_src->format.i_visible_height) / 2 ),
+                        (unsigned int) p_src->p[U_PLANE].i_lines );
+    const unsigned int copy_pitch = __MIN( __MAX( (unsigned int) p_dst->p[UVPLANE].i_visible_pitch,
+                                                  p_src->format.i_x_offset + p_src->format.i_visible_width ) / 2,
+                                           (unsigned int) p_src->p[U_PLANE].i_pitch );
+
+    const int i_extra_pitch_uv = p_dst->p[UVPLANE].i_pitch - 2 * copy_pitch;
+    const int i_extra_pitch_u  = p_src->p[U_PLANE].i_pitch - copy_pitch;
+    const int i_extra_pitch_v  = p_src->p[V_PLANE].i_pitch - copy_pitch;
+
+    uint8_t *dstUV = p_dst->p[UVPLANE].p_pixels;
+    uint8_t *srcU  = p_src->p[U_PLANE].p_pixels;
+    uint8_t *srcV  = p_src->p[V_PLANE].p_pixels;
+    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;
+    }
+}
+
+/*****************************************************************************
+ * 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 )
+{
+    VLC_UNUSED(p_filter);
+    p_dst->format.i_x_offset = p_src->format.i_x_offset;
+    p_dst->format.i_y_offset = p_src->format.i_y_offset;
+
+    // copy Y plane
+    unsigned int copy_lines = __MAX( (unsigned int) p_dst->p[Y_PLANE].i_visible_lines,
+                            p_src->format.i_y_offset + p_src->format.i_visible_height );
+    memcpy( p_dst->p[Y_PLANE].p_pixels,
+            p_src->p[Y_PLANE].p_pixels,
+            copy_lines * p_dst->p[Y_PLANE].i_pitch );
+
+    // copy the U and V planes into UV
+    copy_lines = __MIN( __MAX( (unsigned int) p_dst->p[UVPLANE].i_visible_lines,
+                               ( p_src->format.i_y_offset + p_src->format.i_visible_height) / 2 ),
+                        (unsigned int) p_src->p[U_PLANE].i_lines );
+    const unsigned int copy_pitch = __MIN( __MAX( (unsigned int) p_dst->p[UVPLANE].i_visible_pitch,
+                                                  p_src->format.i_x_offset + p_src->format.i_visible_width ) / 2,
+                                           (unsigned int) p_src->p[U_PLANE].i_pitch );
+
+    const int i_extra_pitch_uv = p_dst->p[UVPLANE].i_pitch - 2 * copy_pitch;
+    const int i_extra_pitch_u  = p_src->p[U_PLANE].i_pitch - copy_pitch;
+    const int i_extra_pitch_v  = p_src->p[V_PLANE].i_pitch - copy_pitch;
+
+    uint8_t *dstUV = p_dst->p[UVPLANE].p_pixels;
+    uint8_t *srcU  = p_src->p[U_PLANE].p_pixels;
+    uint8_t *srcV  = p_src->p[V_PLANE].p_pixels;
+    for ( unsigned int line = 0; line < copy_lines; line++ )
+    {
+        for ( unsigned int col = 0; col < copy_pitch; col++ )
+        {
+            *dstUV++ = *srcV++;
+            *dstUV++ = *srcU++;
+        }
+        dstUV += i_extra_pitch_uv;
+        srcU  += i_extra_pitch_u;
+        srcV  += i_extra_pitch_v;
+    }
+}
-- 
2.8.1



More information about the vlc-devel mailing list