Libav
float_dsp.c
Go to the documentation of this file.
1 /*
2  * This file is part of Libav.
3  *
4  * Libav is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * Libav 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with Libav; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "config.h"
20 #include "attributes.h"
21 #include "float_dsp.h"
22 
23 static void vector_fmul_c(float *dst, const float *src0, const float *src1,
24  int len)
25 {
26  int i;
27  for (i = 0; i < len; i++)
28  dst[i] = src0[i] * src1[i];
29 }
30 
31 static void vector_fmac_scalar_c(float *dst, const float *src, float mul,
32  int len)
33 {
34  int i;
35  for (i = 0; i < len; i++)
36  dst[i] += src[i] * mul;
37 }
38 
39 static void vector_fmul_scalar_c(float *dst, const float *src, float mul,
40  int len)
41 {
42  int i;
43  for (i = 0; i < len; i++)
44  dst[i] = src[i] * mul;
45 }
46 
47 static void vector_dmul_scalar_c(double *dst, const double *src, double mul,
48  int len)
49 {
50  int i;
51  for (i = 0; i < len; i++)
52  dst[i] = src[i] * mul;
53 }
54 
55 static void vector_fmul_window_c(float *dst, const float *src0,
56  const float *src1, const float *win, int len)
57 {
58  int i, j;
59 
60  dst += len;
61  win += len;
62  src0 += len;
63 
64  for (i = -len, j = len - 1; i < 0; i++, j--) {
65  float s0 = src0[i];
66  float s1 = src1[j];
67  float wi = win[i];
68  float wj = win[j];
69  dst[i] = s0 * wj - s1 * wi;
70  dst[j] = s0 * wi + s1 * wj;
71  }
72 }
73 
74 static void vector_fmul_add_c(float *dst, const float *src0, const float *src1,
75  const float *src2, int len){
76  int i;
77 
78  for (i = 0; i < len; i++)
79  dst[i] = src0[i] * src1[i] + src2[i];
80 }
81 
82 static void vector_fmul_reverse_c(float *dst, const float *src0,
83  const float *src1, int len)
84 {
85  int i;
86 
87  src1 += len-1;
88  for (i = 0; i < len; i++)
89  dst[i] = src0[i] * src1[-i];
90 }
91 
92 static void butterflies_float_c(float *restrict v1, float *restrict v2,
93  int len)
94 {
95  int i;
96 
97  for (i = 0; i < len; i++) {
98  float t = v1[i] - v2[i];
99  v1[i] += v2[i];
100  v2[i] = t;
101  }
102 }
103 
104 float avpriv_scalarproduct_float_c(const float *v1, const float *v2, int len)
105 {
106  float p = 0.0;
107  int i;
108 
109  for (i = 0; i < len; i++)
110  p += v1[i] * v2[i];
111 
112  return p;
113 }
114 
116 {
117  fdsp->vector_fmul = vector_fmul_c;
126 
127  if (ARCH_AARCH64)
129  if (ARCH_ARM)
130  ff_float_dsp_init_arm(fdsp);
131  if (ARCH_PPC)
132  ff_float_dsp_init_ppc(fdsp, bit_exact);
133  if (ARCH_X86)
134  ff_float_dsp_init_x86(fdsp);
135 }
136 
137 #ifdef TEST
138 
139 #include <float.h>
140 #include <math.h>
141 #include <stdint.h>
142 #include <stdlib.h>
143 #include <string.h>
144 
145 #include "common.h"
146 #include "cpu.h"
147 #include "internal.h"
148 #include "lfg.h"
149 #include "log.h"
150 #include "mem.h"
151 #include "random_seed.h"
152 
153 #define LEN 240
154 
155 static void fill_float_array(AVLFG *lfg, float *a, int len)
156 {
157  int i;
158  double bmg[2], stddev = 10.0, mean = 0.0;
159 
160  for (i = 0; i < len; i += 2) {
161  av_bmg_get(lfg, bmg);
162  a[i] = bmg[0] * stddev + mean;
163  a[i + 1] = bmg[1] * stddev + mean;
164  }
165 }
166 static int compare_floats(const float *a, const float *b, int len,
167  float max_diff)
168 {
169  int i;
170  for (i = 0; i < len; i++) {
171  if (fabsf(a[i] - b[i]) > max_diff) {
172  av_log(NULL, AV_LOG_ERROR, "%d: %- .12f - %- .12f = % .12g\n",
173  i, a[i], b[i], a[i] - b[i]);
174  return -1;
175  }
176  }
177  return 0;
178 }
179 
180 static void fill_double_array(AVLFG *lfg, double *a, int len)
181 {
182  int i;
183  double bmg[2], stddev = 10.0, mean = 0.0;
184 
185  for (i = 0; i < len; i += 2) {
186  av_bmg_get(lfg, bmg);
187  a[i] = bmg[0] * stddev + mean;
188  a[i + 1] = bmg[1] * stddev + mean;
189  }
190 }
191 
192 static int compare_doubles(const double *a, const double *b, int len,
193  double max_diff)
194 {
195  int i;
196 
197  for (i = 0; i < len; i++) {
198  if (fabs(a[i] - b[i]) > max_diff) {
199  av_log(NULL, AV_LOG_ERROR, "%d: %- .12f - %- .12f = % .12g\n",
200  i, a[i], b[i], a[i] - b[i]);
201  return -1;
202  }
203  }
204  return 0;
205 }
206 
207 static int test_vector_fmul(AVFloatDSPContext *fdsp, AVFloatDSPContext *cdsp,
208  const float *v1, const float *v2)
209 {
210  LOCAL_ALIGNED(32, float, cdst, [LEN]);
211  LOCAL_ALIGNED(32, float, odst, [LEN]);
212  int ret;
213 
214  cdsp->vector_fmul(cdst, v1, v2, LEN);
215  fdsp->vector_fmul(odst, v1, v2, LEN);
216 
217  if (ret = compare_floats(cdst, odst, LEN, FLT_EPSILON))
218  av_log(NULL, AV_LOG_ERROR, "vector_fmul failed\n");
219 
220  return ret;
221 }
222 
223 #define ARBITRARY_FMAC_SCALAR_CONST 0.005
224 static int test_vector_fmac_scalar(AVFloatDSPContext *fdsp, AVFloatDSPContext *cdsp,
225  const float *v1, const float *src0, float scale)
226 {
227  LOCAL_ALIGNED(32, float, cdst, [LEN]);
228  LOCAL_ALIGNED(32, float, odst, [LEN]);
229  int ret;
230 
231  memcpy(cdst, v1, LEN * sizeof(*v1));
232  memcpy(odst, v1, LEN * sizeof(*v1));
233 
234  cdsp->vector_fmac_scalar(cdst, src0, scale, LEN);
235  fdsp->vector_fmac_scalar(odst, src0, scale, LEN);
236 
237  if (ret = compare_floats(cdst, odst, LEN, ARBITRARY_FMAC_SCALAR_CONST))
238  av_log(NULL, AV_LOG_ERROR, "vector_fmac_scalar failed\n");
239 
240  return ret;
241 }
242 
243 static int test_vector_fmul_scalar(AVFloatDSPContext *fdsp, AVFloatDSPContext *cdsp,
244  const float *v1, float scale)
245 {
246  LOCAL_ALIGNED(32, float, cdst, [LEN]);
247  LOCAL_ALIGNED(32, float, odst, [LEN]);
248  int ret;
249 
250  cdsp->vector_fmul_scalar(cdst, v1, scale, LEN);
251  fdsp->vector_fmul_scalar(odst, v1, scale, LEN);
252 
253  if (ret = compare_floats(cdst, odst, LEN, FLT_EPSILON))
254  av_log(NULL, AV_LOG_ERROR, "vector_fmul_scalar failed\n");
255 
256  return ret;
257 }
258 
259 static int test_vector_dmul_scalar(AVFloatDSPContext *fdsp, AVFloatDSPContext *cdsp,
260  const double *v1, double scale)
261 {
262  LOCAL_ALIGNED(32, double, cdst, [LEN]);
263  LOCAL_ALIGNED(32, double, odst, [LEN]);
264  int ret;
265 
266  cdsp->vector_dmul_scalar(cdst, v1, scale, LEN);
267  fdsp->vector_dmul_scalar(odst, v1, scale, LEN);
268 
269  if (ret = compare_doubles(cdst, odst, LEN, DBL_EPSILON))
270  av_log(NULL, AV_LOG_ERROR, "vector_dmul_scalar failed\n");
271 
272  return ret;
273 }
274 
275 #define ARBITRARY_FMUL_WINDOW_CONST 0.008
276 static int test_vector_fmul_window(AVFloatDSPContext *fdsp, AVFloatDSPContext *cdsp,
277  const float *v1, const float *v2, const float *v3)
278 {
279  LOCAL_ALIGNED(32, float, cdst, [LEN]);
280  LOCAL_ALIGNED(32, float, odst, [LEN]);
281  int ret;
282 
283  cdsp->vector_fmul_window(cdst, v1, v2, v3, LEN / 2);
284  fdsp->vector_fmul_window(odst, v1, v2, v3, LEN / 2);
285 
286  if (ret = compare_floats(cdst, odst, LEN, ARBITRARY_FMUL_WINDOW_CONST))
287  av_log(NULL, AV_LOG_ERROR, "vector_fmul_window failed\n");
288 
289  return ret;
290 }
291 
292 #define ARBITRARY_FMUL_ADD_CONST 0.005
293 static int test_vector_fmul_add(AVFloatDSPContext *fdsp, AVFloatDSPContext *cdsp,
294  const float *v1, const float *v2, const float *v3)
295 {
296  LOCAL_ALIGNED(32, float, cdst, [LEN]);
297  LOCAL_ALIGNED(32, float, odst, [LEN]);
298  int ret;
299 
300  cdsp->vector_fmul_add(cdst, v1, v2, v3, LEN);
301  fdsp->vector_fmul_add(odst, v1, v2, v3, LEN);
302 
303  if (ret = compare_floats(cdst, odst, LEN, ARBITRARY_FMUL_ADD_CONST))
304  av_log(NULL, AV_LOG_ERROR, "vector_fmul_add failed\n");
305 
306  return ret;
307 }
308 
309 static int test_vector_fmul_reverse(AVFloatDSPContext *fdsp, AVFloatDSPContext *cdsp,
310  const float *v1, const float *v2)
311 {
312  LOCAL_ALIGNED(32, float, cdst, [LEN]);
313  LOCAL_ALIGNED(32, float, odst, [LEN]);
314  int ret;
315 
316  cdsp->vector_fmul_reverse(cdst, v1, v2, LEN);
317  fdsp->vector_fmul_reverse(odst, v1, v2, LEN);
318 
319  if (ret = compare_floats(cdst, odst, LEN, FLT_EPSILON))
320  av_log(NULL, AV_LOG_ERROR, "vector_fmul_reverse failed\n");
321 
322  return ret;
323 }
324 
325 static int test_butterflies_float(AVFloatDSPContext *fdsp, AVFloatDSPContext *cdsp,
326  const float *v1, const float *v2)
327 {
328  LOCAL_ALIGNED(32, float, cv1, [LEN]);
329  LOCAL_ALIGNED(32, float, cv2, [LEN]);
330  LOCAL_ALIGNED(32, float, ov1, [LEN]);
331  LOCAL_ALIGNED(32, float, ov2, [LEN]);
332  int ret;
333 
334  memcpy(cv1, v1, LEN * sizeof(*v1));
335  memcpy(cv2, v2, LEN * sizeof(*v2));
336  memcpy(ov1, v1, LEN * sizeof(*v1));
337  memcpy(ov2, v2, LEN * sizeof(*v2));
338 
339  cdsp->butterflies_float(cv1, cv2, LEN);
340  fdsp->butterflies_float(ov1, ov2, LEN);
341 
342  if ((ret = compare_floats(cv1, ov1, LEN, FLT_EPSILON)) ||
343  (ret = compare_floats(cv2, ov2, LEN, FLT_EPSILON)))
344  av_log(NULL, AV_LOG_ERROR, "butterflies_float failed\n");
345 
346  return ret;
347 }
348 
349 #define ARBITRARY_SCALARPRODUCT_CONST 0.2
350 static int test_scalarproduct_float(AVFloatDSPContext *fdsp, AVFloatDSPContext *cdsp,
351  const float *v1, const float *v2)
352 {
353  float cprod, oprod;
354  int ret;
355 
356  cprod = cdsp->scalarproduct_float(v1, v2, LEN);
357  oprod = fdsp->scalarproduct_float(v1, v2, LEN);
358 
359  if (ret = compare_floats(&cprod, &oprod, 1, ARBITRARY_SCALARPRODUCT_CONST))
360  av_log(NULL, AV_LOG_ERROR, "scalarproduct_float failed\n");
361 
362  return ret;
363 }
364 
365 int main(int argc, char **argv)
366 {
367  int ret = 0;
368  uint32_t seed;
369  AVFloatDSPContext fdsp, cdsp;
370  AVLFG lfg;
371 
372  LOCAL_ALIGNED(32, float, src0, [LEN]);
373  LOCAL_ALIGNED(32, float, src1, [LEN]);
374  LOCAL_ALIGNED(32, float, src2, [LEN]);
375  LOCAL_ALIGNED(32, double, dbl_src0, [LEN]);
376  LOCAL_ALIGNED(32, double, dbl_src1, [LEN]);
377 
378  if (argc > 2 && !strcmp(argv[1], "-s"))
379  seed = strtoul(argv[2], NULL, 10);
380  else
381  seed = av_get_random_seed();
382 
383  av_log(NULL, AV_LOG_INFO, "float_dsp-test: random seed %u\n", seed);
384 
385  av_lfg_init(&lfg, seed);
386 
387  fill_float_array(&lfg, src0, LEN);
388  fill_float_array(&lfg, src1, LEN);
389  fill_float_array(&lfg, src2, LEN);
390 
391  fill_double_array(&lfg, dbl_src0, LEN);
392  fill_double_array(&lfg, dbl_src1, LEN);
393 
394  avpriv_float_dsp_init(&fdsp, 1);
396  avpriv_float_dsp_init(&cdsp, 1);
397 
398  if (test_vector_fmul(&fdsp, &cdsp, src0, src1))
399  ret -= 1 << 0;
400  if (test_vector_fmac_scalar(&fdsp, &cdsp, src2, src0, src1[0]))
401  ret -= 1 << 1;
402  if (test_vector_fmul_scalar(&fdsp, &cdsp, src0, src1[0]))
403  ret -= 1 << 2;
404  if (test_vector_fmul_window(&fdsp, &cdsp, src0, src1, src2))
405  ret -= 1 << 3;
406  if (test_vector_fmul_add(&fdsp, &cdsp, src0, src1, src2))
407  ret -= 1 << 4;
408  if (test_vector_fmul_reverse(&fdsp, &cdsp, src0, src1))
409  ret -= 1 << 5;
410  if (test_butterflies_float(&fdsp, &cdsp, src0, src1))
411  ret -= 1 << 6;
412  if (test_scalarproduct_float(&fdsp, &cdsp, src0, src1))
413  ret -= 1 << 7;
414  if (test_vector_dmul_scalar(&fdsp, &cdsp, dbl_src0, dbl_src1[0]))
415  ret -= 1 << 8;
416 
417  return ret;
418 }
419 
420 #endif /* TEST */
Definition: lfg.h:25
float(* scalarproduct_float)(const float *v1, const float *v2, int len)
Calculate the scalar product of two vectors of floats.
Definition: float_dsp.h:159
#define ARCH_ARM
Definition: config.h:14
void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp)
static void vector_fmul_scalar_c(float *dst, const float *src, float mul, int len)
Definition: float_dsp.c:39
memory handling functions
#define ARCH_X86
Definition: config.h:33
void av_set_cpu_flags_mask(int mask)
Set a mask on flags returned by av_get_cpu_flags().
Definition: cpu.c:69
Macro definitions for various function/variable attributes.
void(* vector_fmac_scalar)(float *dst, const float *src, float mul, int len)
Multiply a vector of floats by a scalar float and add to destination vector.
Definition: float_dsp.h:54
float avpriv_scalarproduct_float_c(const float *v1, const float *v2, int len)
Return the scalar product of two vectors.
Definition: float_dsp.c:104
av_cold void ff_float_dsp_init_aarch64(AVFloatDSPContext *fdsp)
#define ARCH_AARCH64
Definition: config.h:12
av_cold void ff_float_dsp_init_arm(AVFloatDSPContext *fdsp)
#define av_cold
Definition: attributes.h:66
void(* vector_fmul)(float *dst, const float *src0, const float *src1, int len)
Calculate the product of two vectors of floats and store the result in a vector of floats...
Definition: float_dsp.h:38
#define b
Definition: input.c:52
void av_bmg_get(AVLFG *lfg, double out[2])
Get the next two numbers generated by a Box-Muller Gaussian generator using the random numbers issued...
Definition: lfg.c:47
void(* vector_fmul_window)(float *dst, const float *src0, const float *src1, const float *win, int len)
Overlap/add with window function.
Definition: float_dsp.h:103
void(* vector_dmul_scalar)(double *dst, const double *src, double mul, int len)
Multiply a vector of double by a scalar double.
Definition: float_dsp.h:84
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:123
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:169
int main(int argc, char **argv)
Definition: avconv.c:2609
static void vector_fmul_add_c(float *dst, const float *src0, const float *src1, const float *src2, int len)
Definition: float_dsp.c:74
static void vector_dmul_scalar_c(double *dst, const double *src, double mul, int len)
Definition: float_dsp.c:47
NULL
Definition: eval.c:55
#define AV_LOG_INFO
Standard information.
Definition: log.h:134
void ff_float_dsp_init_ppc(AVFloatDSPContext *fdsp, int strict)
static unsigned int seed
Definition: videogen.c:78
void(* vector_fmul_scalar)(float *dst, const float *src, float mul, int len)
Multiply a vector of floats by a scalar float.
Definition: float_dsp.h:69
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
Definition: lfg.c:30
#define ARCH_PPC
Definition: config.h:24
av_cold void avpriv_float_dsp_init(AVFloatDSPContext *fdsp, int bit_exact)
Initialize a float DSP context.
Definition: float_dsp.c:115
static void vector_fmul_window_c(float *dst, const float *src0, const float *src1, const float *win, int len)
Definition: float_dsp.c:55
common internal and external API header
#define LOCAL_ALIGNED(a, t, v,...)
Definition: internal.h:103
#define restrict
Definition: config.h:8
static void vector_fmul_c(float *dst, const float *src0, const float *src1, int len)
Definition: float_dsp.c:23
void(* vector_fmul_add)(float *dst, const float *src0, const float *src1, const float *src2, int len)
Calculate the product of two vectors of floats, add a third vector of floats and store the result in ...
Definition: float_dsp.h:121
static void butterflies_float_c(float *restrict v1, float *restrict v2, int len)
Definition: float_dsp.c:92
static void vector_fmac_scalar_c(float *dst, const float *src, float mul, int len)
Definition: float_dsp.c:31
int len
void(* butterflies_float)(float *restrict v1, float *restrict v2, int len)
Calculate the sum and difference of two vectors of floats.
Definition: float_dsp.h:148
uint32_t av_get_random_seed(void)
Get random data.
Definition: random_seed.c:95
static void vector_fmul_reverse_c(float *dst, const float *src0, const float *src1, int len)
Definition: float_dsp.c:82
void(* vector_fmul_reverse)(float *dst, const float *src0, const float *src1, int len)
Calculate the product of two vectors of floats, and store the result in a vector of floats...
Definition: float_dsp.h:138