FFmpeg
sw_yuv2rgb.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #include <string.h>
20 
21 #include "libavutil/common.h"
22 #include "libavutil/intreadwrite.h"
23 #include "libavutil/mem_internal.h"
24 #include "libavutil/pixdesc.h"
25 
26 #include "libswscale/swscale.h"
28 
29 #include "checkasm.h"
30 
31 #define randomize_buffers(buf, size) \
32  do { \
33  for (int j = 0; j < size; j += 4) \
34  AV_WN32(buf + j, rnd()); \
35  } while (0)
36 
37 static const int dst_fmts[] = {
38 // AV_PIX_FMT_BGR48BE,
39 // AV_PIX_FMT_BGR48LE,
40 // AV_PIX_FMT_RGB48BE,
41 // AV_PIX_FMT_RGB48LE,
52 // AV_PIX_FMT_RGB444,
53 // AV_PIX_FMT_BGR444,
54 // AV_PIX_FMT_RGB8,
55 // AV_PIX_FMT_BGR8,
56 // AV_PIX_FMT_RGB4,
57 // AV_PIX_FMT_BGR4,
58 // AV_PIX_FMT_RGB4_BYTE,
59 // AV_PIX_FMT_BGR4_BYTE,
60 // AV_PIX_FMT_MONOBLACK,
62 };
63 
64 static int cmp_off_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy)
65 {
66  for (size_t i = 0; i < n; i++) {
67  if (abs(ref[i] - test[i]) > accuracy)
68  return 1;
69  }
70  return 0;
71 }
72 
73 static int cmp_555_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy)
74 {
75  const uint16_t *ref16 = (const uint16_t *) ref;
76  const uint16_t *test16 = (const uint16_t *) test;
77  for (size_t i = 0; i < n; i++) {
78  if (abs(( ref16[i] & 0x1f) - ( test16[i] & 0x1f)) > accuracy)
79  return 1;
80  if (abs(((ref16[i] >> 5) & 0x1f) - ((test16[i] >> 5) & 0x1f)) > accuracy)
81  return 1;
82  if (abs(((ref16[i] >> 10) & 0x1f) - ((test16[i] >> 10) & 0x1f)) > accuracy)
83  return 1;
84  }
85  return 0;
86 }
87 
88 static int cmp_565_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy)
89 {
90  const uint16_t *ref16 = (const uint16_t *) ref;
91  const uint16_t *test16 = (const uint16_t *) test;
92  for (size_t i = 0; i < n; i++) {
93  if (abs(( ref16[i] & 0x1f) - ( test16[i] & 0x1f)) > accuracy)
94  return 1;
95  if (abs(((ref16[i] >> 5) & 0x3f) - ((test16[i] >> 5) & 0x3f)) > accuracy)
96  return 1;
97  if (abs(((ref16[i] >> 11) & 0x1f) - ((test16[i] >> 11) & 0x1f)) > accuracy)
98  return 1;
99  }
100  return 0;
101 }
102 
103 static void check_yuv2rgb(int src_pix_fmt)
104 {
105  const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt);
106 #define MAX_LINE_SIZE 1920
107 #define SRC_STRIDE_PAD 32
108 #define NUM_LINES 4
109  static const int input_sizes[] = {8, 128, 1080, MAX_LINE_SIZE};
110 
111  declare_func(int, SwsInternal *c, const uint8_t *const src[],
112  const int srcStride[], int srcSliceY, int srcSliceH,
113  uint8_t *const dst[], const int dstStride[]);
114 
115  LOCAL_ALIGNED_8(uint8_t, src_y, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]);
116  LOCAL_ALIGNED_8(uint8_t, src_u, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]);
117  LOCAL_ALIGNED_8(uint8_t, src_v, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]);
118  LOCAL_ALIGNED_8(uint8_t, src_a, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]);
119  const uint8_t *src[4] = { src_y, src_u, src_v, src_a };
120 
121  LOCAL_ALIGNED_8(uint8_t, dst0_0, [NUM_LINES * MAX_LINE_SIZE * 6]);
122  LOCAL_ALIGNED_8(uint8_t, dst0_1, [NUM_LINES * MAX_LINE_SIZE]);
123  LOCAL_ALIGNED_8(uint8_t, dst0_2, [NUM_LINES * MAX_LINE_SIZE]);
124  uint8_t *dst0[4] = { dst0_0, dst0_1, dst0_2 };
125 
126  LOCAL_ALIGNED_8(uint8_t, dst1_0, [NUM_LINES * MAX_LINE_SIZE * 6]);
127  LOCAL_ALIGNED_8(uint8_t, dst1_1, [NUM_LINES * MAX_LINE_SIZE]);
128  LOCAL_ALIGNED_8(uint8_t, dst1_2, [NUM_LINES * MAX_LINE_SIZE]);
129  uint8_t *dst1[4] = { dst1_0, dst1_1, dst1_2 };
130 
135 
136  for (int dfi = 0; dfi < FF_ARRAY_ELEMS(dst_fmts); dfi++) {
137  int dst_pix_fmt = dst_fmts[dfi];
138  const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt);
139  int sample_size = av_get_padded_bits_per_pixel(dst_desc) >> 3;
140  for (int isi = 0; isi < FF_ARRAY_ELEMS(input_sizes); isi++) {
141  SwsContext *sws;
142  SwsInternal *c;
143  int log_level;
144  int width = input_sizes[isi];
145  int srcSliceY = 0;
146  int srcSliceH = NUM_LINES;
147  int srcStride[4] = {
149  (width >> src_desc->log2_chroma_w) + SRC_STRIDE_PAD,
150  (width >> src_desc->log2_chroma_w) + SRC_STRIDE_PAD,
152  };
153  int dstStride[4] = {
154  MAX_LINE_SIZE * 6,
157  };
158 
159  // override log level to prevent spamming of the message
160  // "No accelerated colorspace conversion found from %s to %s"
161  log_level = av_log_get_level();
163  sws = sws_getContext(width, srcSliceH, src_pix_fmt,
164  width, srcSliceH, dst_pix_fmt,
165  0, NULL, NULL, NULL);
166  av_log_set_level(log_level);
167  if (!sws)
168  fail();
169 
170  c = sws_internal(sws);
171  if (check_func(c->convert_unscaled, "%s_%s_%d", src_desc->name, dst_desc->name, width)) {
172  memset(dst0_0, 0xFF, NUM_LINES * MAX_LINE_SIZE * 6);
173  memset(dst1_0, 0xFF, NUM_LINES * MAX_LINE_SIZE * 6);
174  if (dst_pix_fmt == AV_PIX_FMT_GBRP) {
175  memset(dst0_1, 0xFF, NUM_LINES * MAX_LINE_SIZE);
176  memset(dst0_2, 0xFF, NUM_LINES * MAX_LINE_SIZE);
177  memset(dst1_1, 0xFF, NUM_LINES * MAX_LINE_SIZE);
178  memset(dst1_2, 0xFF, NUM_LINES * MAX_LINE_SIZE);
179  }
180 
181  call_ref(c, src, srcStride, srcSliceY,
182  srcSliceH, dst0, dstStride);
183  call_new(c, src, srcStride, srcSliceY,
184  srcSliceH, dst1, dstStride);
185 
186  if (dst_pix_fmt == AV_PIX_FMT_ARGB ||
187  dst_pix_fmt == AV_PIX_FMT_ABGR ||
188  dst_pix_fmt == AV_PIX_FMT_RGBA ||
189  dst_pix_fmt == AV_PIX_FMT_BGRA ||
190  dst_pix_fmt == AV_PIX_FMT_RGB24 ||
191  dst_pix_fmt == AV_PIX_FMT_BGR24) {
192  for (int row = 0; row < srcSliceH; row++)
193  if (cmp_off_by_n(dst0_0 + row * dstStride[0],
194  dst1_0 + row * dstStride[0],
195  width * sample_size, 3))
196  fail();
197  } else if (dst_pix_fmt == AV_PIX_FMT_RGB565 ||
198  dst_pix_fmt == AV_PIX_FMT_BGR565) {
199  for (int row = 0; row < srcSliceH; row++)
200  if (cmp_565_by_n(dst0_0 + row * dstStride[0],
201  dst1_0 + row * dstStride[0],
202  width, 2))
203  fail();
204  } else if (dst_pix_fmt == AV_PIX_FMT_RGB555 ||
205  dst_pix_fmt == AV_PIX_FMT_BGR555) {
206  for (int row = 0; row < srcSliceH; row++)
207  if (cmp_555_by_n(dst0_0 + row * dstStride[0],
208  dst1_0 + row * dstStride[0],
209  width, 2))
210  fail();
211  } else if (dst_pix_fmt == AV_PIX_FMT_GBRP) {
212  for (int p = 0; p < 3; p++)
213  for (int row = 0; row < srcSliceH; row++)
214  if (cmp_off_by_n(dst0[p] + row * dstStride[p],
215  dst1[p] + row * dstStride[p],
216  width, 3))
217  fail();
218  } else {
219  fail();
220  }
221 
222  bench_new(c, src, srcStride, srcSliceY,
223  srcSliceH, dst0, dstStride);
224  }
225  sws_freeContext(sws);
226  }
227  }
228 }
229 
230 #undef NUM_LINES
231 #undef SRC_STRIDE_PAD
232 #undef MAX_LINE_SIZE
233 
235 {
237  report("yuv420p");
239  report("yuv422p");
241  report("yuva420p");
242 }
mem_internal.h
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3456
sws_freeContext
void sws_freeContext(SwsContext *swsContext)
Free the swscaler context swsContext.
Definition: utils.c:2285
pixdesc.h
AVPixFmtDescriptor::name
const char * name
Definition: pixdesc.h:70
check_func
#define check_func(func,...)
Definition: checkasm.h:214
test
Definition: idctdsp.c:35
AV_PIX_FMT_BGR24
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:76
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:102
call_ref
#define call_ref(...)
Definition: checkasm.h:230
randomize_buffers
#define randomize_buffers(buf, size)
Definition: sw_yuv2rgb.c:31
cmp_565_by_n
static int cmp_565_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy)
Definition: sw_yuv2rgb.c:88
fail
#define fail()
Definition: checkasm.h:224
checkasm.h
MAX_LINE_SIZE
#define MAX_LINE_SIZE
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
cmp_555_by_n
static int cmp_555_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy)
Definition: sw_yuv2rgb.c:73
intreadwrite.h
AV_PIX_FMT_YUVA420P
@ AV_PIX_FMT_YUVA420P
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition: pixfmt.h:108
input_sizes
static const int input_sizes[]
Definition: sw_rgb.c:347
check_yuv2rgb
static void check_yuv2rgb(int src_pix_fmt)
Definition: sw_yuv2rgb.c:103
AVPixFmtDescriptor::log2_chroma_w
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:80
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:73
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
LOCAL_ALIGNED_8
#define LOCAL_ALIGNED_8(t, v,...)
Definition: mem_internal.h:128
SRC_STRIDE_PAD
#define SRC_STRIDE_PAD
av_log_get_level
int av_log_get_level(void)
Get the current log level.
Definition: log.c:472
call_new
#define call_new(...)
Definition: checkasm.h:238
NULL
#define NULL
Definition: coverity.c:32
abs
#define abs(x)
Definition: cuda_runtime.h:35
cmp_off_by_n
static int cmp_off_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy)
Definition: sw_yuv2rgb.c:64
AV_PIX_FMT_ABGR
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:101
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:75
av_get_padded_bits_per_pixel
int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc)
Return the number of bits per pixel for the pixel format described by pixdesc, including any padding ...
Definition: pixdesc.c:3421
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
checkasm_check_sw_yuv2rgb
void checkasm_check_sw_yuv2rgb(void)
Definition: sw_yuv2rgb.c:234
AV_PIX_FMT_BGR555
#define AV_PIX_FMT_BGR555
Definition: pixfmt.h:532
AV_PIX_FMT_ARGB
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:99
report
#define report
Definition: checkasm.h:227
av_log_set_level
void av_log_set_level(int level)
Set the log level.
Definition: log.c:477
bench_new
#define bench_new(...)
Definition: checkasm.h:429
common.h
AV_PIX_FMT_RGB555
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:527
swscale_internal.h
NUM_LINES
#define NUM_LINES
AV_PIX_FMT_BGR565
#define AV_PIX_FMT_BGR565
Definition: pixfmt.h:531
AV_PIX_FMT_RGB565
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:526
SwsInternal
Definition: swscale_internal.h:335
sws_getContext
SwsContext * sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param)
Allocate and return an SwsContext.
Definition: utils.c:1954
ref
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:117
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
AV_PIX_FMT_GBRP
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
Definition: pixfmt.h:165
AV_PIX_FMT_YUV422P
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:77
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
declare_func
#define declare_func(ret,...)
Definition: checkasm.h:219
dst_fmts
static const int dst_fmts[]
Definition: sw_yuv2rgb.c:37
sws_internal
static SwsInternal * sws_internal(const SwsContext *sws)
Definition: swscale_internal.h:79
width
#define width
Definition: dsp.h:89
SwsContext
Main external API structure.
Definition: swscale.h:206
src
#define src
Definition: vp8dsp.c:248
swscale.h