]> git.sesse.net Git - fjl/blob - idct_float.c
Make idct_float.c compile without optimization.
[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 a3 = 0.7071067811865474;
55         static const double a4 = 1.3065629648763766;   // cos(pi/8) * sqrt(2)
56         // static const double a5 = 0.5 * (a4 - a2);
57         static const double a5 = 0.3826834323650897;
58
59         // phase 1
60         const double p1_0 = y0;
61         const double p1_1 = y4;
62         const double p1_2 = y2;
63         const double p1_3 = y6;
64         const double p1_4 = y5;
65         const double p1_5 = y1;
66         const double p1_6 = y7;
67         const double p1_7 = y3;
68
69         // phase 2
70         const double p2_0 = p1_0;
71         const double p2_1 = p1_1;
72         const double p2_2 = p1_2;
73         const double p2_3 = p1_3;
74         const double p2_4 = p1_4 - p1_7;
75         const double p2_5 = p1_5 + p1_6;
76         const double p2_6 = p1_5 - p1_6;
77         const double p2_7 = p1_4 + p1_7;
78
79         // phase 3
80         const double p3_0 = p2_0;
81         const double p3_1 = p2_1;
82         const double p3_2 = p2_2 - p2_3;
83         const double p3_3 = p2_2 + p2_3;
84         const double p3_4 = p2_4;
85         const double p3_5 = p2_5 - p2_7;
86         const double p3_6 = p2_6;
87         const double p3_7 = p2_5 + p2_7;
88         
89         // phase 4
90         const double p4_0 = p3_0;
91         const double p4_1 = p3_1;
92         const double p4_2 = a1 * p3_2;
93         const double p4_3 = p3_3;
94         const double p4_4 = p3_4 * -a2 + (p3_4 + p3_6) * -a5;
95         const double p4_5 = a3 * p3_5;
96         const double p4_6 = p3_6 * a4 + (p3_4 + p3_6) * -a5;
97         const double p4_7 = p3_7;
98
99         // phase 5
100         const double p5_0 = p4_0 + p4_1;
101         const double p5_1 = p4_0 - p4_1;
102         const double p5_2 = p4_2;
103         const double p5_3 = p4_2 + p4_3;
104         const double p5_4 = p4_4;
105         const double p5_5 = p4_5;
106         const double p5_6 = p4_6;
107         const double p5_7 = p4_7;
108
109         // phase 6
110         const double p6_0 = p5_0 + p5_3;
111         const double p6_1 = p5_1 + p5_2;
112         const double p6_2 = p5_1 - p5_2;
113         const double p6_3 = p5_0 - p5_3;
114         const double p6_4 = -p5_4;
115         const double p6_5 = p5_5 - p5_4;
116         const double p6_6 = p5_5 + p5_6;
117         const double p6_7 = p5_6 + p5_7;
118
119         // phase 7
120         x[0] = p6_0 + p6_7;
121         x[1] = p6_1 + p6_6;
122         x[2] = p6_2 + p6_5;
123         x[3] = p6_3 + p6_4;
124         x[4] = p6_3 - p6_4;
125         x[5] = p6_2 - p6_5;
126         x[6] = p6_1 - p6_6;
127         x[7] = p6_0 - p6_7;
128 }
129
130 void idct_float(const int16_t* input, const void* userdata, uint8_t* output)
131 {
132         const double* quant_table = (const double*)userdata;
133         double temp[DCTSIZE2];
134
135         // IDCT columns.
136         for (unsigned x = 0; x < DCTSIZE; ++x) {
137                 idct1d_float(input[DCTSIZE * 0 + x] * quant_table[DCTSIZE * 0 + x],
138                              input[DCTSIZE * 1 + x] * quant_table[DCTSIZE * 1 + x],
139                              input[DCTSIZE * 2 + x] * quant_table[DCTSIZE * 2 + x],
140                              input[DCTSIZE * 3 + x] * quant_table[DCTSIZE * 3 + x],
141                              input[DCTSIZE * 4 + x] * quant_table[DCTSIZE * 4 + x],
142                              input[DCTSIZE * 5 + x] * quant_table[DCTSIZE * 5 + x],
143                              input[DCTSIZE * 6 + x] * quant_table[DCTSIZE * 6 + x],
144                              input[DCTSIZE * 7 + x] * quant_table[DCTSIZE * 7 + x],
145                              temp + x * DCTSIZE);
146         }
147         
148         // IDCT rows.
149         for (unsigned y = 0; y < DCTSIZE; ++y) {
150                 double temp2[DCTSIZE];
151                 idct1d_float(temp[DCTSIZE * 0 + y],
152                              temp[DCTSIZE * 1 + y],
153                              temp[DCTSIZE * 2 + y],
154                              temp[DCTSIZE * 3 + y],
155                              temp[DCTSIZE * 4 + y],
156                              temp[DCTSIZE * 5 + y],
157                              temp[DCTSIZE * 6 + y],
158                              temp[DCTSIZE * 7 + y],
159                              temp2);
160                 for (unsigned x = 0; x < DCTSIZE; ++x) {
161                         const double val = temp2[x];
162                         if (val < -128.0) {
163                                 output[y * DCTSIZE + x] = 0;
164                         } else if (val >= 127.0) {
165                                 output[y * DCTSIZE + x] = 255;
166                         } else {
167                                 output[y * DCTSIZE + x] = (uint8_t)(val + 128.5);
168                         }
169                 }
170         }
171 }