]> git.sesse.net Git - vlc/blob - modules/arm_neon/yuv_rgb.c
LGPL
[vlc] / modules / arm_neon / yuv_rgb.c
1 /*****************************************************************************
2  * yuv_rgb.c : ARM NEONv1 YUV to RGB32 chroma conversion for VLC
3  *****************************************************************************
4  * Copyright (C) 2011 Sébastien Toque
5  *                    Rémi Denis-Courmont
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20  *****************************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #include <vlc_common.h>
27 #include <vlc_plugin.h>
28 #include <vlc_filter.h>
29 #include <vlc_cpu.h>
30 #include "chroma_neon.h"
31
32 static int Open (vlc_object_t *);
33
34 vlc_module_begin ()
35     set_description (N_("ARM NEON video chroma YUV->RGBA"))
36     set_capability ("video filter2", 250)
37     set_callbacks (Open, NULL)
38 vlc_module_end ()
39
40 /*
41 static int CoefY[256];
42 static int CoefRV[256];
43 static int CoefGU[256];
44 static int CoefGV[256];
45 static int CoefBU[256];
46
47 // C reference version of the converter
48 static void I420_RGBA_C (filter_t *filter, picture_t *src, picture_t *dst)
49 {
50     const uint8_t *const out = dst->p->p_pixels;
51     const size_t width = src->p[Y_PLANE].i_visible_pitch;
52     const size_t height = src->p[Y_PLANE].i_visible_lines;
53
54     const int ypitch = src->p[Y_PLANE].i_pitch;
55     const int uvpitch = src->p[U_PLANE].i_pitch;
56     const int dpitch = dst->p->i_pitch / dst->p->i_pixel_pitch;
57
58     for (size_t j = 0; j <  height; ++j)
59     {
60         const int y = j * ypitch;
61         const int u = (j>>1) * uvpitch;
62         const int d = j * dpitch;
63
64         for (size_t i = 0; i < width; ++i)
65         {
66             uint8_t Y = src->Y_PIXELS[y + i];
67             uint8_t U = src->U_PIXELS[u + (i>>1)];
68             uint8_t V = src->V_PIXELS[u + (i>>1)];
69
70             //coef = float * Precision + .5 (Precision=32768)
71             int R = CoefY[Y] + CoefRV[V];
72             int G = CoefY[Y] + CoefGU[U] + CoefGV[V];
73             int B = CoefY[Y] + CoefBU[U];
74
75             //rgb = (rgb+Precision/2) / Precision (Precision=32768)
76             R = R >> 15;
77             G = G >> 15;
78             B = B >> 15;
79
80             if (unlikely(R < 0)) R = 0;
81             if (unlikely(G < 0)) G = 0;
82             if (unlikely(B < 0)) B = 0;
83             if (unlikely(R > 255)) R = 255;
84             if (unlikely(G > 255)) G = 255;
85             if (unlikely(B > 255)) B = 255;
86
87             ((uint32_t*)out)[d + i] = R | (G<<8) | (B<<16) | (0xff<<24);
88         }
89     }
90 }*/
91
92 static void I420_RGBA (filter_t *filter, picture_t *src, picture_t *dst)
93 {
94     struct yuv_pack out = { dst->p->p_pixels, dst->p->i_pitch };
95     struct yuv_planes in = { src->Y_PIXELS, src->U_PIXELS, src->V_PIXELS, src->Y_PITCH };
96     i420_rgb_neon (&out, &in, filter->fmt_in.video.i_width, filter->fmt_in.video.i_height);
97 }
98 static void YV12_RGBA (filter_t *filter, picture_t *src, picture_t *dst)
99 {
100     struct yuv_pack out = { dst->p->p_pixels, dst->p->i_pitch };
101     struct yuv_planes in = { src->Y_PIXELS, src->V_PIXELS, src->U_PIXELS, src->Y_PITCH };
102     i420_rgb_neon (&out, &in, filter->fmt_in.video.i_width, filter->fmt_in.video.i_height);
103 }
104
105 static void NV21_RGBA (filter_t *filter, picture_t *src, picture_t *dst)
106 {
107     struct yuv_pack out = { dst->p->p_pixels, dst->p->i_pitch };
108     struct yuv_planes in = { src->Y_PIXELS, src->U_PIXELS, src->V_PIXELS, src->Y_PITCH };
109     nv21_rgb_neon (&out, &in, filter->fmt_in.video.i_width, filter->fmt_in.video.i_height);
110 }
111
112 static void NV12_RGBA (filter_t *filter, picture_t *src, picture_t *dst)
113 {
114     struct yuv_pack out = { dst->p->p_pixels, dst->p->i_pitch };
115     struct yuv_planes in = { src->Y_PIXELS, src->U_PIXELS, src->V_PIXELS, src->Y_PITCH };
116     nv12_rgb_neon (&out, &in, filter->fmt_in.video.i_width, filter->fmt_in.video.i_height);
117 }
118
119 VIDEO_FILTER_WRAPPER (I420_RGBA)
120 VIDEO_FILTER_WRAPPER (YV12_RGBA)
121 VIDEO_FILTER_WRAPPER (NV21_RGBA)
122 VIDEO_FILTER_WRAPPER (NV12_RGBA)
123
124 static int Open (vlc_object_t *obj)
125 {
126     filter_t *filter = (filter_t *)obj;
127
128     if (!vlc_CPU_ARM_NEON())
129         return VLC_EGENERIC;
130
131     if (((filter->fmt_in.video.i_width | filter->fmt_in.video.i_height) & 1)
132      || (filter->fmt_in.video.i_width != filter->fmt_out.video.i_width)
133      || (filter->fmt_in.video.i_height != filter->fmt_out.video.i_height))
134         return VLC_EGENERIC;
135
136     switch (filter->fmt_out.video.i_chroma)
137     {
138         case VLC_CODEC_RGB32:
139             if(        filter->fmt_out.video.i_rmask != 0x000000ff
140                     || filter->fmt_out.video.i_gmask != 0x0000ff00
141                     || filter->fmt_out.video.i_bmask != 0x00ff0000 )
142                 return VLC_EGENERIC;
143
144             switch (filter->fmt_in.video.i_chroma)
145             {
146                 case VLC_CODEC_I420:
147                     filter->pf_video_filter = I420_RGBA_Filter;
148                     break;
149                 case VLC_CODEC_YV12:
150                     filter->pf_video_filter = YV12_RGBA_Filter;
151                     break;
152                 case VLC_CODEC_NV21:
153                     filter->pf_video_filter = NV21_RGBA_Filter;
154                     break;
155                 case VLC_CODEC_NV12:
156                     filter->pf_video_filter = NV12_RGBA_Filter;
157                     break;
158                 default:
159                     return VLC_EGENERIC;
160             }
161             break;
162
163         default:
164             return VLC_EGENERIC;
165     }
166
167     //precompute some values for the C version
168     /*const int coefY  = (int)(1.164 * 32768 + 0.5);
169     const int coefRV = (int)(1.793 * 32768 + 0.5);
170     const int coefGU = (int)(0.213 * 32768 + 0.5);
171     const int coefGV = (int)(0.533 * 32768 + 0.5);
172     const int coefBU = (int)(2.113 * 32768 + 0.5);
173     for (int i=0; i<256; ++i)
174     {
175         CoefY[i] = coefY * (i-16) + 16384;
176         CoefRV[i] = coefRV*(i-128);
177         CoefGU[i] = -coefGU*(i-128);
178         CoefGV[i] = -coefGV*(i-128);
179         CoefBU[i] = coefBU*(i-128);
180     }*/
181
182     msg_Dbg(filter, "%4.4s(%dx%d) to %4.4s(%dx%d)",
183             (char*)&filter->fmt_in.video.i_chroma, filter->fmt_in.video.i_width, filter->fmt_in.video.i_height,
184             (char*)&filter->fmt_out.video.i_chroma, filter->fmt_out.video.i_width, filter->fmt_out.video.i_height);
185
186     return VLC_SUCCESS;
187 }