FFmpeg
sw_range_convert.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.h"
24 #include "libavutil/mem_internal.h"
25 
26 #include "libswscale/swscale.h"
28 
29 #include "checkasm.h"
30 
31 static const enum AVPixelFormat pixel_formats[] = {
38 };
39 
40 static void randomize_buffers(int16_t *buf0, int16_t *buf1, int bit_depth, int width)
41 {
42  int32_t *buf0_32 = (int32_t *) buf0;
43  int32_t *buf1_32 = (int32_t *) buf1;
44  int mask = (1 << bit_depth) - 1;
45  int src_shift = bit_depth <= 14 ? 15 - bit_depth : 19 - bit_depth;
46  for (int i = 0; i < width; i++) {
47  int32_t r = rnd() & mask;
48  if (bit_depth == 16) {
49  buf0_32[i] = r << src_shift;
50  buf1_32[i] = r << src_shift;
51  } else {
52  buf0[i] = r << src_shift;
53  buf1[i] = r << src_shift;
54  }
55  }
56 }
57 
58 static void check_lumConvertRange(int from)
59 {
60  const char *func_str = from ? "lumRangeFromJpeg" : "lumRangeToJpeg";
61 #define LARGEST_INPUT_SIZE 1920
62  static const int input_sizes[] = {8, LARGEST_INPUT_SIZE};
63  SwsContext *sws;
64  SwsInternal *c;
65 
66  LOCAL_ALIGNED_32(int16_t, dst0, [LARGEST_INPUT_SIZE * 2]);
67  LOCAL_ALIGNED_32(int16_t, dst1, [LARGEST_INPUT_SIZE * 2]);
68  int32_t *dst0_32 = (int32_t *) dst0;
69  int32_t *dst1_32 = (int32_t *) dst1;
70 
71  declare_func(void, int16_t *dst, int width,
72  uint32_t coeff, int64_t offset);
73 
75  if (sws_init_context(sws, NULL, NULL) < 0)
76  fail();
77 
78  c = sws_internal(sws);
79  sws->src_range = from;
80  sws->dst_range = !from;
81 
82  for (int pfi = 0; pfi < FF_ARRAY_ELEMS(pixel_formats); pfi++) {
85  int bit_depth = desc->comp[0].depth;
86  int sample_size = bit_depth == 16 ? sizeof(int32_t) : sizeof(int16_t);
87  int src_shift = bit_depth <= 14 ? 15 - bit_depth : 19 - bit_depth;
88  int mpeg_min = 16 << (bit_depth - 8);
89  int mpeg_max = 235 << (bit_depth - 8);
90  int jpeg_max = (1 << bit_depth) - 1;
93  c->dstBpc = bit_depth;
95  for (int dstWi = 0; dstWi < FF_ARRAY_ELEMS(input_sizes); dstWi++) {
96  int width = input_sizes[dstWi];
97  if (check_func(c->lumConvertRange, "%s%d_%d", func_str, bit_depth, width)) {
98  randomize_buffers(dst0, dst1, bit_depth, width);
99  if (bit_depth == 16) {
100  if (!from) {
101  dst1_32[0] = dst0_32[0] = mpeg_min << src_shift;
102  dst1_32[1] = dst0_32[1] = mpeg_max << src_shift;
103  }
104  dst1_32[2] = dst0_32[2] = -1;
105  } else {
106  if (!from) {
107  dst1[0] = dst0[0] = mpeg_min << src_shift;
108  dst1[1] = dst0[1] = mpeg_max << src_shift;
109  }
110  dst1[2] = dst0[2] = -1;
111  }
112  call_ref(dst0, width,
113  c->lumConvertRange_coeff, c->lumConvertRange_offset);
114  call_new(dst1, width,
115  c->lumConvertRange_coeff, c->lumConvertRange_offset);
116  if (memcmp(dst0, dst1, width * sample_size))
117  fail();
118  if (!from) {
119  /* check that the mpeg range is respected */
120  if (bit_depth == 16) {
121  if ((dst1_32[0] >> src_shift) > 0 || (dst1_32[1] >> src_shift) != jpeg_max)
122  fail();
123  } else {
124  if ((dst1[0] >> src_shift) > 0 || (dst1[1] >> src_shift) != jpeg_max)
125  fail();
126  }
127  }
128  if (width == LARGEST_INPUT_SIZE && (bit_depth == 8 || bit_depth == 16))
129  bench_new(dst1, width,
130  c->lumConvertRange_coeff, c->lumConvertRange_offset);
131  }
132  }
133  }
134 
136 }
137 #undef LARGEST_INPUT_SIZE
138 
139 static void check_chrConvertRange(int from)
140 {
141  const char *func_str = from ? "chrRangeFromJpeg" : "chrRangeToJpeg";
142 #define LARGEST_INPUT_SIZE 1920
143  static const int input_sizes[] = {8, LARGEST_INPUT_SIZE};
144  SwsContext *sws;
145  SwsInternal *c;
146 
147  LOCAL_ALIGNED_32(int16_t, dstU0, [LARGEST_INPUT_SIZE * 2]);
148  LOCAL_ALIGNED_32(int16_t, dstV0, [LARGEST_INPUT_SIZE * 2]);
149  LOCAL_ALIGNED_32(int16_t, dstU1, [LARGEST_INPUT_SIZE * 2]);
150  LOCAL_ALIGNED_32(int16_t, dstV1, [LARGEST_INPUT_SIZE * 2]);
151  int32_t *dstU0_32 = (int32_t *) dstU0;
152  int32_t *dstU1_32 = (int32_t *) dstU1;
153 
154  declare_func(void, int16_t *dstU, int16_t *dstV, int width,
155  uint32_t coeff, int64_t offset);
156 
158  if (sws_init_context(sws, NULL, NULL) < 0)
159  fail();
160 
161  c = sws_internal(sws);
162  sws->src_range = from;
163  sws->dst_range = !from;
164 
165  for (int pfi = 0; pfi < FF_ARRAY_ELEMS(pixel_formats); pfi++) {
166  enum AVPixelFormat pix_fmt = pixel_formats[pfi];
168  int bit_depth = desc->comp[0].depth;
169  int sample_size = bit_depth == 16 ? sizeof(int32_t) : sizeof(int16_t);
170  int src_shift = bit_depth <= 14 ? 15 - bit_depth : 19 - bit_depth;
171  int mpeg_min = 16 << (bit_depth - 8);
172  int mpeg_max = 240 << (bit_depth - 8);
173  int jpeg_max = (1 << bit_depth) - 1;
176  c->dstBpc = bit_depth;
178  for (int dstWi = 0; dstWi < FF_ARRAY_ELEMS(input_sizes); dstWi++) {
179  int width = input_sizes[dstWi];
180  if (check_func(c->chrConvertRange, "%s%d_%d", func_str, bit_depth, width)) {
181  randomize_buffers(dstU0, dstU1, bit_depth, width);
182  randomize_buffers(dstV0, dstV1, bit_depth, width);
183  if (bit_depth == 16) {
184  if (!from) {
185  dstU1_32[0] = dstU0_32[0] = mpeg_min << src_shift;
186  dstU1_32[1] = dstU0_32[1] = mpeg_max << src_shift;
187  }
188  dstU1_32[2] = dstU0_32[2] = -1;
189  } else {
190  if (!from) {
191  dstU1[0] = dstU0[0] = mpeg_min << src_shift;
192  dstU1[1] = dstU0[1] = mpeg_max << src_shift;
193  }
194  dstU1[2] = dstU0[2] = -1;
195  }
196  call_ref(dstU0, dstV0, width,
197  c->chrConvertRange_coeff, c->chrConvertRange_offset);
198  call_new(dstU1, dstV1, width,
199  c->chrConvertRange_coeff, c->chrConvertRange_offset);
200  if (memcmp(dstU0, dstU1, width * sample_size) ||
201  memcmp(dstV0, dstV1, width * sample_size))
202  fail();
203  if (!from) {
204  /* check that the mpeg range is respected */
205  if (bit_depth == 16) {
206  if ((dstU1_32[0] >> src_shift) > 0 || (dstU1_32[1] >> src_shift) != jpeg_max)
207  fail();
208  } else {
209  if ((dstU1[0] >> src_shift) > 0 || (dstU1[1] >> src_shift) != jpeg_max)
210  fail();
211  }
212  }
213  if (width == LARGEST_INPUT_SIZE && (bit_depth == 8 || bit_depth == 16))
214  bench_new(dstU1, dstV1, width,
215  c->chrConvertRange_coeff, c->chrConvertRange_offset);
216  }
217  }
218  }
219 
221 }
222 #undef LARGEST_INPUT_SIZE
223 
225 {
227  report("lumRangeFromJpeg");
229  report("chrRangeFromJpeg");
231  report("lumRangeToJpeg");
233  report("chrRangeToJpeg");
234 }
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
r
const char * r
Definition: vf_curves.c:127
mem_internal.h
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3170
int64_t
long long int64_t
Definition: coverity.c:34
sws_freeContext
void sws_freeContext(SwsContext *swsContext)
Free the swscaler context swsContext.
Definition: utils.c:2447
mask
int mask
Definition: mediacodecdec_common.c:154
check_func
#define check_func(func,...)
Definition: checkasm.h:184
call_ref
#define call_ref(...)
Definition: checkasm.h:199
bit_depth
static void bit_depth(AudioStatsContext *s, const uint64_t *const mask, uint8_t *depth)
Definition: af_astats.c:246
fail
#define fail()
Definition: checkasm.h:193
checkasm.h
sws_init_context
av_warn_unused_result int sws_init_context(SwsContext *sws_context, SwsFilter *srcFilter, SwsFilter *dstFilter)
Initialize the swscaler context sws_context.
Definition: utils.c:2082
check_chrConvertRange
static void check_chrConvertRange(int from)
Definition: sw_range_convert.c:139
AV_PIX_FMT_YUV444P10
#define AV_PIX_FMT_YUV444P10
Definition: pixfmt.h:505
LARGEST_INPUT_SIZE
#define LARGEST_INPUT_SIZE
rnd
#define rnd()
Definition: checkasm.h:177
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
intreadwrite.h
AV_PIX_FMT_YUV444P16
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:515
pix_fmt
static enum AVPixelFormat pix_fmt
Definition: demux_decode.c:41
input_sizes
static const int input_sizes[]
Definition: sw_rgb.c:347
from
const char * from
Definition: jacosubdec.c:66
call_new
#define call_new(...)
Definition: checkasm.h:302
NULL
#define NULL
Definition: coverity.c:32
LOCAL_ALIGNED_32
#define LOCAL_ALIGNED_32(t, v,...)
Definition: mem_internal.h:132
SwsContext::src_range
int src_range
Source is full range.
Definition: swscale.h:224
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
sws_alloc_context
SwsContext * sws_alloc_context(void)
Allocate an empty SwsContext and set its fields to default values.
Definition: utils.c:1227
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
AV_PIX_FMT_YUV444P12
#define AV_PIX_FMT_YUV444P12
Definition: pixfmt.h:509
offset
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
Definition: writing_filters.txt:86
SwsContext::dst_format
int dst_format
Destination pixel format.
Definition: swscale.h:223
sws
static SwsContext * sws[3]
Definition: swscale.c:69
report
#define report
Definition: checkasm.h:196
randomize_buffers
static void randomize_buffers(int16_t *buf0, int16_t *buf1, int bit_depth, int width)
Definition: sw_range_convert.c:40
bench_new
#define bench_new(...)
Definition: checkasm.h:373
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
ff_sws_init_scale
void ff_sws_init_scale(SwsInternal *c)
Definition: swscale.c:691
common.h
swscale_internal.h
check_lumConvertRange
static void check_lumConvertRange(int from)
Definition: sw_range_convert.c:58
AV_PIX_FMT_YUV444P9
#define AV_PIX_FMT_YUV444P9
Definition: pixfmt.h:501
SwsInternal
Definition: swscale_internal.h:317
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:78
desc
const char * desc
Definition: libsvtav1.c:79
checkasm_check_sw_range_convert
void checkasm_check_sw_range_convert(void)
Definition: sw_range_convert.c:224
mem.h
SwsContext::src_format
int src_format
Source pixel format.
Definition: swscale.h:222
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:188
SwsContext::dst_range
int dst_range
Destination is full range.
Definition: swscale.h:225
int32_t
int32_t
Definition: audioconvert.c:56
coeff
static const double coeff[2][5]
Definition: vf_owdenoise.c:80
sws_internal
static SwsInternal * sws_internal(const SwsContext *sws)
Definition: swscale_internal.h:74
AV_PIX_FMT_YUV444P14
#define AV_PIX_FMT_YUV444P14
Definition: pixfmt.h:512
width
#define width
Definition: dsp.h:85
SwsContext
Main external API structure.
Definition: swscale.h:174
pixel_formats
static enum AVPixelFormat pixel_formats[]
Definition: sw_range_convert.c:31
swscale.h