]> git.sesse.net Git - fjl/blob - idct_float.c
Add the missing benchmarking files.
[fjl] / idct_float.c
1 #include <math.h>
2 #include <string.h>
3 #include <stdlib.h>
4
5 #include "idct.h"
6
7 // AA&N (Arai, Agui and Nakajima) floating-point IDCT.
8 // This IDCT is based on the same DCT that libjpeg uses -- in fact, exactly the
9 // same figure from the same book ("JPEG: Still Image Data Compression Standard",
10 // page 52, figure 4-8). However, it is coded from scratch, and uses the
11 // transposition method for converting DCT -> IDCT suggested in the book.
12 // (libjpeg seems to use some other method that yields similar, but not
13 // the same, code.) 
14
15 // As this is generally meant as a reference and not useful code (we expect
16 // a SIMD fixed-point algorithm to be used in most cases), it has not been
17 // attempted significantly optimized. We assume the compiler will be smart
18 // enough to do all the variable propagation for us anyway.
19
20 // Scale factors; 1.0 / (sqrt(2.0) * cos(k * M_PI / 16.0)), except for the first which is 1.
21 static const double scalefac[] = {
22         1.0, 0.7209598220069479, 0.765366864730180, 0.8504300947672564,
23         1.0, 1.2727585805728336, 1.847759065022573, 3.6245097854115502
24 };
25
26 // Premultiply the scale factors and the overall 1/8 factor into the quantization
27 // table entries (and convert to double).
28 void* idct_float_alloc(const uint32_t* quant_table)
29 {
30         double* qt_copy = (double*)malloc(DCTSIZE2 * sizeof(double));
31
32         for (unsigned y = 0; y < DCTSIZE; ++y) {
33                 for (unsigned x = 0; x < DCTSIZE; ++x) {
34                         qt_copy[y * DCTSIZE + x] = (1.0/DCTSIZE) * quant_table[y * DCTSIZE + x] *
35                                 scalefac[x] * scalefac[y];
36                 }
37         }
38
39         return qt_copy;
40 }
41
42 void idct_float_free(void* userdata)
43 {
44         free(userdata);
45 }
46
47 // 1D 8-point DCT.
48 static inline void idct1d_float(double y0, double y1, double y2, double y3, double y4, double y5, double y6, double y7, double *x)
49 {
50         // constants
51         static const double a1 = 0.7071067811865474;   // sqrt(2)
52         static const double a2 = 0.5411961001461971;   // cos(3/8 pi) * sqrt(2)
53         static const double a3 = a1;
54         static const double a4 = 1.3065629648763766;   // cos(pi/8) * sqrt(2)
55         static const double a5 = 0.5 * (a4 - a2);
56
57         // phase 1
58         const double p1_0 = y0;
59         const double p1_1 = y4;
60         const double p1_2 = y2;
61         const double p1_3 = y6;
62         const double p1_4 = y5;
63         const double p1_5 = y1;
64         const double p1_6 = y7;
65         const double p1_7 = y3;
66
67         // phase 2
68         const double p2_0 = p1_0;
69         const double p2_1 = p1_1;
70         const double p2_2 = p1_2;
71         const double p2_3 = p1_3;
72         const double p2_4 = p1_4 - p1_7;
73         const double p2_5 = p1_5 + p1_6;
74         const double p2_6 = p1_5 - p1_6;
75         const double p2_7 = p1_4 + p1_7;
76
77         // phase 3
78         const double p3_0 = p2_0;
79         const double p3_1 = p2_1;
80         const double p3_2 = p2_2 - p2_3;
81         const double p3_3 = p2_2 + p2_3;
82         const double p3_4 = p2_4;
83         const double p3_5 = p2_5 - p2_7;
84         const double p3_6 = p2_6;
85         const double p3_7 = p2_5 + p2_7;
86         
87         // phase 4
88         const double p4_0 = p3_0;
89         const double p4_1 = p3_1;
90         const double p4_2 = a1 * p3_2;
91         const double p4_3 = p3_3;
92         const double p4_4 = p3_4 * -a2 + (p3_4 + p3_6) * -a5;
93         const double p4_5 = a3 * p3_5;
94         const double p4_6 = p3_6 * a4 + (p3_4 + p3_6) * -a5;
95         const double p4_7 = p3_7;
96
97         // phase 5
98         const double p5_0 = p4_0 + p4_1;
99         const double p5_1 = p4_0 - p4_1;
100         const double p5_2 = p4_2;
101         const double p5_3 = p4_2 + p4_3;
102         const double p5_4 = p4_4;
103         const double p5_5 = p4_5;
104         const double p5_6 = p4_6;
105         const double p5_7 = p4_7;
106
107         // phase 6
108         const double p6_0 = p5_0 + p5_3;
109         const double p6_1 = p5_1 + p5_2;
110         const double p6_2 = p5_1 - p5_2;
111         const double p6_3 = p5_0 - p5_3;
112         const double p6_4 = -p5_4;
113         const double p6_5 = p5_5 - p5_4;
114         const double p6_6 = p5_5 + p5_6;
115         const double p6_7 = p5_6 + p5_7;
116
117         // phase 7
118         x[0] = p6_0 + p6_7;
119         x[1] = p6_1 + p6_6;
120         x[2] = p6_2 + p6_5;
121         x[3] = p6_3 + p6_4;
122         x[4] = p6_3 - p6_4;
123         x[5] = p6_2 - p6_5;
124         x[6] = p6_1 - p6_6;
125         x[7] = p6_0 - p6_7;
126 }
127
128 void idct_float(const int16_t* input, const void* userdata, uint8_t* output)
129 {
130         const double* quant_table = (const double*)userdata;
131         double temp[DCTSIZE2];
132
133         // IDCT columns.
134         for (unsigned x = 0; x < DCTSIZE; ++x) {
135                 idct1d_float(input[DCTSIZE * 0 + x] * quant_table[DCTSIZE * 0 + x],
136                              input[DCTSIZE * 1 + x] * quant_table[DCTSIZE * 1 + x],
137                              input[DCTSIZE * 2 + x] * quant_table[DCTSIZE * 2 + x],
138                              input[DCTSIZE * 3 + x] * quant_table[DCTSIZE * 3 + x],
139                              input[DCTSIZE * 4 + x] * quant_table[DCTSIZE * 4 + x],
140                              input[DCTSIZE * 5 + x] * quant_table[DCTSIZE * 5 + x],
141                              input[DCTSIZE * 6 + x] * quant_table[DCTSIZE * 6 + x],
142                              input[DCTSIZE * 7 + x] * quant_table[DCTSIZE * 7 + x],
143                              temp + x * DCTSIZE);
144         }
145         
146         // IDCT rows.
147         for (unsigned y = 0; y < DCTSIZE; ++y) {
148                 double temp2[DCTSIZE];
149                 idct1d_float(temp[DCTSIZE * 0 + y],
150                              temp[DCTSIZE * 1 + y],
151                              temp[DCTSIZE * 2 + y],
152                              temp[DCTSIZE * 3 + y],
153                              temp[DCTSIZE * 4 + y],
154                              temp[DCTSIZE * 5 + y],
155                              temp[DCTSIZE * 6 + y],
156                              temp[DCTSIZE * 7 + y],
157                              temp2);
158                 for (unsigned x = 0; x < DCTSIZE; ++x) {
159                         const double val = temp2[x];
160                         if (val < 0.0) {
161                                 output[y * DCTSIZE + x] = 0;
162                         } else if (val >= 255.0) {
163                                 output[y * DCTSIZE + x] = 255;
164                         } else {
165                                 output[y * DCTSIZE + x] = (uint8_t)(val + 0.5);
166                         }
167                 }
168         }
169 }