FFmpeg
vf_colorspace.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <string.h>
22 #include "checkasm.h"
24 #include "libavutil/common.h"
25 #include "libavutil/internal.h"
26 #include "libavutil/intreadwrite.h"
27 
28 #define W 64
29 #define H 64
30 
31 #define randomize_buffers() \
32  do { \
33  unsigned mask = bpp_mask[idepth]; \
34  int n, m; \
35  int bpp = 1 + (!!idepth); \
36  int buf_size = W * H * bpp; \
37  for (m = 0; m < 3; m++) { \
38  int ss = m ? ss_w + ss_h : 0; \
39  int plane_sz = buf_size >> ss; \
40  for (n = 0; n < plane_sz; n += 4) { \
41  unsigned r = rnd() & mask; \
42  AV_WN32A(&src[m][n], r); \
43  } \
44  } \
45  } while (0)
46 
47 static const char *format_string[] = {
48  "444", "422", "420"
49 };
50 
51 static const unsigned bpp_mask[] = { 0xffffffff, 0x03ff03ff, 0x0fff0fff };
52 
53 static void check_yuv2yuv(void)
54 {
55  declare_func(void, uint8_t *dst[3], ptrdiff_t dst_stride[3],
56  uint8_t *src[3], ptrdiff_t src_stride[3],
57  int w, int h, const int16_t coeff[3][3][8],
58  const int16_t off[2][8]);
60  int idepth, odepth, fmt, n;
61  LOCAL_ALIGNED_32(uint8_t, src_y, [W * H * 2]);
62  LOCAL_ALIGNED_32(uint8_t, src_u, [W * H * 2]);
63  LOCAL_ALIGNED_32(uint8_t, src_v, [W * H * 2]);
64  uint8_t *src[3] = { src_y, src_u, src_v };
65  LOCAL_ALIGNED_32(uint8_t, dst0_y, [W * H * 2]);
66  LOCAL_ALIGNED_32(uint8_t, dst0_u, [W * H * 2]);
67  LOCAL_ALIGNED_32(uint8_t, dst0_v, [W * H * 2]);
68  LOCAL_ALIGNED_32(uint8_t, dst1_y, [W * H * 2]);
69  LOCAL_ALIGNED_32(uint8_t, dst1_u, [W * H * 2]);
70  LOCAL_ALIGNED_32(uint8_t, dst1_v, [W * H * 2]);
71  uint8_t *dst0[3] = { dst0_y, dst0_u, dst0_v }, *dst1[3] = { dst1_y, dst1_u, dst1_v };
72  LOCAL_ALIGNED_32(int16_t, offset_buf, [16]);
73  LOCAL_ALIGNED_32(int16_t, coeff_buf, [3 * 3 * 8]);
74  int16_t (*offset)[8] = (int16_t(*)[8]) offset_buf;
75  int16_t (*coeff)[3][8] = (int16_t(*)[3][8]) coeff_buf;
76 
78  for (n = 0; n < 8; n++) {
79  offset[0][n] = offset[1][n] = 16;
80 
81  coeff[0][0][n] = (1 << 14) + (1 << 7) + 1;
82  coeff[0][1][n] = (1 << 7) - 1;
83  coeff[0][2][n] = -(1 << 8);
84  coeff[1][0][n] = coeff[2][0][n] = 0;
85  coeff[1][1][n] = (1 << 14) + (1 << 7);
86  coeff[1][2][n] = -(1 << 7);
87  coeff[2][2][n] = (1 << 14) - (1 << 6);
88  coeff[2][1][n] = 1 << 6;
89  }
90  for (idepth = 0; idepth < 3; idepth++) {
91  for (odepth = 0; odepth < 3; odepth++) {
92  for (fmt = 0; fmt < 3; fmt++) {
93  if (check_func(dsp.yuv2yuv[idepth][odepth][fmt],
94  "ff_colorspacedsp_yuv2yuv_%sp%dto%d",
95  format_string[fmt],
96  idepth * 2 + 8, odepth * 2 + 8)) {
97  int ss_w = !!fmt, ss_h = fmt == 2;
98  int y_src_stride = W << !!idepth, y_dst_stride = W << !!odepth;
99  int uv_src_stride = y_src_stride >> ss_w, uv_dst_stride = y_dst_stride >> ss_w;
100 
102  call_ref(dst0, (ptrdiff_t[3]) { y_dst_stride, uv_dst_stride, uv_dst_stride },
103  src, (ptrdiff_t[3]) { y_src_stride, uv_src_stride, uv_src_stride },
104  W, H, coeff, offset);
105  call_new(dst1, (ptrdiff_t[3]) { y_dst_stride, uv_dst_stride, uv_dst_stride },
106  src, (ptrdiff_t[3]) { y_src_stride, uv_src_stride, uv_src_stride },
107  W, H, coeff, offset);
108  if (memcmp(dst0[0], dst1[0], y_dst_stride * H) ||
109  memcmp(dst0[1], dst1[1], uv_dst_stride * H >> ss_h) ||
110  memcmp(dst0[2], dst1[2], uv_dst_stride * H >> ss_h)) {
111  fail();
112  }
113  }
114  }
115  }
116  }
117 
118  report("yuv2yuv");
119 }
120 
121 static void check_yuv2rgb(void)
122 {
123  declare_func(void, int16_t *dst[3], ptrdiff_t dst_stride,
124  uint8_t *src[3], ptrdiff_t src_stride[3],
125  int w, int h, const int16_t coeff[3][3][8],
126  const int16_t off[8]);
128  int idepth, fmt, n;
129  LOCAL_ALIGNED_32(uint8_t, src_y, [W * H * 2]);
130  LOCAL_ALIGNED_32(uint8_t, src_u, [W * H * 2]);
131  LOCAL_ALIGNED_32(uint8_t, src_v, [W * H * 2]);
132  uint8_t *src[3] = { src_y, src_u, src_v };
133  LOCAL_ALIGNED_32(int16_t, dst0_y, [W * H]);
134  LOCAL_ALIGNED_32(int16_t, dst0_u, [W * H]);
135  LOCAL_ALIGNED_32(int16_t, dst0_v, [W * H]);
136  LOCAL_ALIGNED_32(int16_t, dst1_y, [W * H]);
137  LOCAL_ALIGNED_32(int16_t, dst1_u, [W * H]);
138  LOCAL_ALIGNED_32(int16_t, dst1_v, [W * H]);
139  int16_t *dst0[3] = { dst0_y, dst0_u, dst0_v }, *dst1[3] = { dst1_y, dst1_u, dst1_v };
140  LOCAL_ALIGNED_32(int16_t, offset, [8]);
141  LOCAL_ALIGNED_32(int16_t, coeff_buf, [3 * 3 * 8]);
142  int16_t (*coeff)[3][8] = (int16_t(*)[3][8]) coeff_buf;
143 
144  ff_colorspacedsp_init(&dsp);
145  for (n = 0; n < 8; n++) {
146  offset[n] = 16;
147 
148  coeff[0][0][n] = coeff[1][0][n] = coeff[2][0][n] = (1 << 14) | 1;
149  coeff[0][1][n] = coeff[2][2][n] = 0;
150  coeff[0][2][n] = 1 << 13;
151  coeff[1][1][n] = -(1 << 12);
152  coeff[1][2][n] = 1 << 12;
153  coeff[2][1][n] = 1 << 11;
154  }
155  for (idepth = 0; idepth < 3; idepth++) {
156  for (fmt = 0; fmt < 3; fmt++) {
157  if (check_func(dsp.yuv2rgb[idepth][fmt],
158  "ff_colorspacedsp_yuv2rgb_%sp%d",
159  format_string[fmt], idepth * 2 + 8)) {
160  int ss_w = !!fmt, ss_h = fmt == 2;
161  int y_src_stride = W << !!idepth;
162  int uv_src_stride = y_src_stride >> ss_w;
163 
165  call_ref(dst0, W, src,
166  (ptrdiff_t[3]) { y_src_stride, uv_src_stride, uv_src_stride },
167  W, H, coeff, offset);
168  call_new(dst1, W, src,
169  (ptrdiff_t[3]) { y_src_stride, uv_src_stride, uv_src_stride },
170  W, H, coeff, offset);
171  if (memcmp(dst0[0], dst1[0], W * H * sizeof(int16_t)) ||
172  memcmp(dst0[1], dst1[1], W * H * sizeof(int16_t)) ||
173  memcmp(dst0[2], dst1[2], W * H * sizeof(int16_t))) {
174  fail();
175  }
176  }
177  }
178  }
179 
180  report("yuv2rgb");
181 }
182 
183 #undef randomize_buffers
184 #define randomize_buffers() \
185  do { \
186  int y, x, p; \
187  for (p = 0; p < 3; p++) { \
188  for (y = 0; y < H; y++) { \
189  for (x = 0; x < W; x++) { \
190  int r = rnd() & 0x7fff; \
191  r -= (32768 - 28672) >> 1; \
192  src[p][y * W + x] = r; \
193  } \
194  } \
195  } \
196  } while (0)
197 
198 static void check_rgb2yuv(void)
199 {
200  declare_func(void, uint8_t *dst[3], ptrdiff_t dst_stride[3],
201  int16_t *src[3], ptrdiff_t src_stride,
202  int w, int h, const int16_t coeff[3][3][8],
203  const int16_t off[8]);
205  int odepth, fmt, n;
206  LOCAL_ALIGNED_32(int16_t, src_y, [W * H * 2]);
207  LOCAL_ALIGNED_32(int16_t, src_u, [W * H * 2]);
208  LOCAL_ALIGNED_32(int16_t, src_v, [W * H * 2]);
209  int16_t *src[3] = { src_y, src_u, src_v };
210  LOCAL_ALIGNED_32(uint8_t, dst0_y, [W * H * 2]);
211  LOCAL_ALIGNED_32(uint8_t, dst0_u, [W * H * 2]);
212  LOCAL_ALIGNED_32(uint8_t, dst0_v, [W * H * 2]);
213  LOCAL_ALIGNED_32(uint8_t, dst1_y, [W * H * 2]);
214  LOCAL_ALIGNED_32(uint8_t, dst1_u, [W * H * 2]);
215  LOCAL_ALIGNED_32(uint8_t, dst1_v, [W * H * 2]);
216  uint8_t *dst0[3] = { dst0_y, dst0_u, dst0_v }, *dst1[3] = { dst1_y, dst1_u, dst1_v };
217  LOCAL_ALIGNED_32(int16_t, offset, [8]);
218  LOCAL_ALIGNED_32(int16_t, coeff_buf, [3 * 3 * 8]);
219  int16_t (*coeff)[3][8] = (int16_t(*)[3][8]) coeff_buf;
220 
221  ff_colorspacedsp_init(&dsp);
222  for (n = 0; n < 8; n++) {
223  offset[n] = 16;
224 
225  // these somewhat resemble bt601/smpte170m coefficients
226  coeff[0][0][n] = lrint(0.3 * (1 << 14));
227  coeff[0][1][n] = lrint(0.6 * (1 << 14));
228  coeff[0][2][n] = lrint(0.1 * (1 << 14));
229  coeff[1][0][n] = lrint(-0.15 * (1 << 14));
230  coeff[1][1][n] = lrint(-0.35 * (1 << 14));
231  coeff[1][2][n] = lrint(0.5 * (1 << 14));
232  coeff[2][0][n] = lrint(0.5 * (1 << 14));
233  coeff[2][1][n] = lrint(-0.42 * (1 << 14));
234  coeff[2][2][n] = lrint(-0.08 * (1 << 14));
235  }
236  for (odepth = 0; odepth < 3; odepth++) {
237  for (fmt = 0; fmt < 3; fmt++) {
238  if (check_func(dsp.rgb2yuv[odepth][fmt],
239  "ff_colorspacedsp_rgb2yuv_%sp%d",
240  format_string[fmt], odepth * 2 + 8)) {
241  int ss_w = !!fmt, ss_h = fmt == 2;
242  int y_dst_stride = W << !!odepth;
243  int uv_dst_stride = y_dst_stride >> ss_w;
244 
246  call_ref(dst0, (ptrdiff_t[3]) { y_dst_stride, uv_dst_stride, uv_dst_stride },
247  src, W, W, H, coeff, offset);
248  call_new(dst1, (ptrdiff_t[3]) { y_dst_stride, uv_dst_stride, uv_dst_stride },
249  src, W, W, H, coeff, offset);
250  if (memcmp(dst0[0], dst1[0], H * y_dst_stride) ||
251  memcmp(dst0[1], dst1[1], H * uv_dst_stride >> ss_h) ||
252  memcmp(dst0[2], dst1[2], H * uv_dst_stride >> ss_h)) {
253  fail();
254  }
255  }
256  }
257  }
258 
259  report("rgb2yuv");
260 }
261 
262 static void check_multiply3x3(void)
263 {
264  declare_func(void, int16_t *data[3], ptrdiff_t stride,
265  int w, int h, const int16_t coeff[3][3][8]);
267  LOCAL_ALIGNED_32(int16_t, dst0_y, [W * H]);
268  LOCAL_ALIGNED_32(int16_t, dst0_u, [W * H]);
269  LOCAL_ALIGNED_32(int16_t, dst0_v, [W * H]);
270  LOCAL_ALIGNED_32(int16_t, dst1_y, [W * H]);
271  LOCAL_ALIGNED_32(int16_t, dst1_u, [W * H]);
272  LOCAL_ALIGNED_32(int16_t, dst1_v, [W * H]);
273  int16_t *dst0[3] = { dst0_y, dst0_u, dst0_v }, *dst1[3] = { dst1_y, dst1_u, dst1_v };
274  int16_t **src = dst0;
275  LOCAL_ALIGNED_32(int16_t, coeff_buf, [3 * 3 * 8]);
276  int16_t (*coeff)[3][8] = (int16_t(*)[3][8]) coeff_buf;
277  int n;
278 
279  ff_colorspacedsp_init(&dsp);
280  for (n = 0; n < 8; n++) {
281  coeff[0][0][n] = lrint(0.85 * (1 << 14));
282  coeff[0][1][n] = lrint(0.10 * (1 << 14));
283  coeff[0][2][n] = lrint(0.05 * (1 << 14));
284  coeff[1][0][n] = lrint(-0.1 * (1 << 14));
285  coeff[1][1][n] = lrint(0.95 * (1 << 14));
286  coeff[1][2][n] = lrint(0.15 * (1 << 14));
287  coeff[2][0][n] = lrint(-0.2 * (1 << 14));
288  coeff[2][1][n] = lrint(0.30 * (1 << 14));
289  coeff[2][2][n] = lrint(0.90 * (1 << 14));
290  }
291  if (check_func(dsp.multiply3x3, "ff_colorspacedsp_multiply3x3")) {
293  memcpy(dst1_y, dst0_y, W * H * sizeof(*dst1_y));
294  memcpy(dst1_u, dst0_u, W * H * sizeof(*dst1_u));
295  memcpy(dst1_v, dst0_v, W * H * sizeof(*dst1_v));
296  call_ref(dst0, W, W, H, coeff);
297  call_new(dst1, W, W, H, coeff);
298  if (memcmp(dst0[0], dst1[0], H * W * sizeof(*dst0_y)) ||
299  memcmp(dst0[1], dst1[1], H * W * sizeof(*dst0_u)) ||
300  memcmp(dst0[2], dst1[2], H * W * sizeof(*dst0_v))) {
301  fail();
302  }
303  }
304 
305  report("multiply3x3");
306 }
307 
309 {
310  check_yuv2yuv();
311  check_yuv2rgb();
312  check_rgb2yuv();
314 }
#define W
Definition: vf_colorspace.c:28
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
const char * fmt
Definition: avisynth_c.h:861
int src_stride
Definition: vf_unsharp.c:55
#define src
Definition: vp8dsp.c:254
void checkasm_check_colorspace(void)
#define H
Definition: vf_colorspace.c:29
#define report
Definition: checkasm.h:124
void(* multiply3x3)(int16_t *data[3], ptrdiff_t stride, int w, int h, const int16_t m[3][3][8])
Definition: colorspacedsp.h:74
uint8_t
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
static void check_multiply3x3(void)
AVFrame * dst
Definition: vf_blend.c:55
#define randomize_buffers()
#define declare_func(ret,...)
Definition: checkasm.h:116
#define fail()
Definition: checkasm.h:121
common internal API header
uint8_t w
Definition: llviddspenc.c:38
int n
Definition: avisynth_c.h:760
static void check_yuv2rgb(void)
static void check_yuv2yuv(void)
Definition: vf_colorspace.c:53
#define call_ref(...)
Definition: checkasm.h:127
yuv2yuv_fn yuv2yuv[NB_BPP][NB_BPP][NB_SS]
Definition: colorspacedsp.h:70
rgb2yuv_fn rgb2yuv[NB_BPP][NB_SS]
Definition: colorspacedsp.h:65
#define check_func(func,...)
Definition: checkasm.h:112
yuv2rgb_fn yuv2rgb[NB_BPP][NB_SS]
Definition: colorspacedsp.h:62
static const unsigned bpp_mask[]
Definition: vf_colorspace.c:51
#define LOCAL_ALIGNED_32(t, v,...)
Definition: internal.h:137
GLint GLenum GLboolean GLsizei stride
Definition: opengl_enc.c:104
common internal and external API header
void ff_colorspacedsp_init(ColorSpaceDSPContext *dsp)
static void check_rgb2yuv(void)
static const double coeff[2][5]
Definition: vf_owdenoise.c:72
#define lrint
Definition: tablegen.h:53
#define call_new(...)
Definition: checkasm.h:194
int dst_stride
Definition: vf_unsharp.c:54