]> git.sesse.net Git - fjl/blob - idct_test.c
Commit initial reference implementation of IDCT.
[fjl] / idct_test.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <assert.h>
6 #include <time.h>
7 #include <sys/time.h>
8
9 #include "idct.h"
10
11 // Generate random coefficients in the range [-15..15].
12 void gen_random_coeffs(int16_t* dst, size_t len)
13 {
14         // Standard NR LCG (we avoid rand() to get consistent behavior across platforms).
15         static uint32_t seed = 1234;
16         for (unsigned i = 0; i < len; ++i) {
17                 seed = seed * 1664525U + 1013904223U;
18                 if (seed >> 31) {
19                         dst[i] = (uint8_t)(seed >> 27) & 0x7;
20                 } else {
21                         dst[i] = -((uint8_t)(seed >> 27) & 0x7);
22                 }
23         }
24 }
25
26 // Test that the input is pretty close to the reference for random inputs. 
27 // (If the reference funtion is given in, this becomes a simple test of its
28 // determinism.)
29 void test_random_inputs(idct_func_t* idct)
30 {
31         int16_t coeff[DCTSIZE2]; 
32         uint32_t quant[DCTSIZE2];
33         uint8_t output[DCTSIZE2];
34         uint8_t reference[DCTSIZE2];
35                 
36         // Unit quantization (ie., no scaling).
37         for (unsigned i = 0; i < DCTSIZE2; ++i) {
38                 quant[i] = 1;
39         }
40
41         for (unsigned i = 0; i < 1000; ++i) {   
42                 gen_random_coeffs(coeff, DCTSIZE2);
43
44                 (*idct)(coeff, quant, output);
45                 (idct_reference)(coeff, quant, reference);
46
47                 // Find the RMS difference.
48                 int diff_squared = 0;
49                 for (unsigned i = 0; i < DCTSIZE2; ++i) {
50                         diff_squared += (output[i] - reference[i]) * (output[i] - reference[i]);
51                 }
52
53                 assert(diff_squared <= 5);
54         }
55 }
56
57 // Test that a single DC coefficient becomes spread out to all blocks.
58 void test_dc_becomes_spread_out(idct_func_t* idct)
59 {
60         int16_t coeff[DCTSIZE2] = { 0 }; 
61         uint32_t quant[DCTSIZE2];
62         uint8_t output[DCTSIZE2];
63
64         // Unit quantization (ie., no scaling).
65         for (unsigned i = 0; i < DCTSIZE2; ++i) {
66                 quant[i] = 1;
67         }
68
69         for (unsigned i = 0; i < 255*8; ++i) {  
70                 uint32_t reference_value = i / 8;
71                 coeff[0] = i;
72
73                 (*idct)(coeff, quant, output);
74
75                 for (unsigned i = 0; i < DCTSIZE2; ++i) {
76                         assert(abs(output[i] - reference_value) <= 1);
77                 }
78         }
79 }
80
81 double timediff(const struct timeval* a, const struct timeval* b)
82 {
83         return (double)(b->tv_sec - a->tv_sec) +
84                 (double)(b->tv_usec - a->tv_usec) * 1e-6;
85 }
86
87 void test_performance(idct_func_t* idct)
88 {
89         const unsigned num_runs = (idct == idct_reference) ? 5000 : 5000000;
90
91         int16_t coeff[DCTSIZE2]; 
92         uint32_t quant[DCTSIZE2];
93         uint8_t output[DCTSIZE2];
94                 
95         gen_random_coeffs(coeff, DCTSIZE2);
96
97         struct timeval start, now;
98         gettimeofday(&start, NULL);
99
100         for (unsigned i = 0; i < num_runs; ++i) {
101                 (*idct)(coeff, quant, output);
102         }
103         
104         gettimeofday(&now, NULL);
105
106         double diff = timediff(&start, &now);
107         printf("%u runs in %.2f seconds = %.2f DCTs/sec\n",
108                 num_runs, diff, num_runs / diff);
109 }
110
111 void test_all_idct(idct_func_t* idct)
112 {
113         printf("  test_dc_becomes_spread_out()\n");
114         test_dc_becomes_spread_out(idct);       
115
116         printf("  test_random_inputs()\n");
117         test_random_inputs(idct);       
118
119         printf("  performance test: ");
120         test_performance(idct);
121 }
122
123 int main(void)
124 {
125         printf("idct_reference:\n");
126         test_all_idct(idct_reference);
127
128         printf("All tests pass.\n");
129         return 0;
130 }