VapourSynth-llvmexpr
Loading...
Searching...
No Matches
8x8idct.expr
Go to the documentation of this file.
1# Copyright (C) 2025 yuygfgg
2#
3# This file is part of Vapoursynth-llvmexpr.
4#
5# Vapoursynth-llvmexpr is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Vapoursynth-llvmexpr is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Vapoursynth-llvmexpr. If not, see <https://www.gnu.org/licenses/>.
17
18
19# Inverse 8x8 Discrete Cosine Transform (IDCT)
20#
21# This script reconstructs pixel values from 8x8 blocks of DCT coefficients
22# provided by the input source clip ($src0). The output at coordinate (X, Y)
23# is the reconstructed pixel value (x, y) for the corresponding block.
24
25@ifndef __EXPR__
26@error This expr should be used in Expr mode
27@endif
28
29@if __INPUT_NUM__ != 1
30@error This expr requires exactly one input clip
31@endif
32
33# ==============================================================================
34# 1. SETUP: Determine current block and spatial coordinates (x, y)
35# ==============================================================================
36
37# DCT block size
38@define N 8
39
40# Spatial coordinates (x, y) for the current output pixel within an 8x8 block.
41x = $X % N
42y = $Y % N
43
44# Top-left corner of the current 8x8 source block of DCT coefficients.
45block_x = trunc($X / N) * N
46block_y = trunc($Y / N) * N
47
48
49# ==============================================================================
50# 2. DATA GATHERING: Load all 64 DCT coefficients from the source 8x8 block.
51# `g_uv` corresponds to the coefficient at frequency (u, v).
52# ==============================================================================
53
54g_00 = dyn($src0, block_x + 0, block_y + 0)
55g_10 = dyn($src0, block_x + 1, block_y + 0)
56g_20 = dyn($src0, block_x + 2, block_y + 0)
57g_30 = dyn($src0, block_x + 3, block_y + 0)
58g_40 = dyn($src0, block_x + 4, block_y + 0)
59g_50 = dyn($src0, block_x + 5, block_y + 0)
60g_60 = dyn($src0, block_x + 6, block_y + 0)
61g_70 = dyn($src0, block_x + 7, block_y + 0)
62
63g_01 = dyn($src0, block_x + 0, block_y + 1)
64g_11 = dyn($src0, block_x + 1, block_y + 1)
65g_21 = dyn($src0, block_x + 2, block_y + 1)
66g_31 = dyn($src0, block_x + 3, block_y + 1)
67g_41 = dyn($src0, block_x + 4, block_y + 1)
68g_51 = dyn($src0, block_x + 5, block_y + 1)
69g_61 = dyn($src0, block_x + 6, block_y + 1)
70g_71 = dyn($src0, block_x + 7, block_y + 1)
71
72g_02 = dyn($src0, block_x + 0, block_y + 2)
73g_12 = dyn($src0, block_x + 1, block_y + 2)
74g_22 = dyn($src0, block_x + 2, block_y + 2)
75g_32 = dyn($src0, block_x + 3, block_y + 2)
76g_42 = dyn($src0, block_x + 4, block_y + 2)
77g_52 = dyn($src0, block_x + 5, block_y + 2)
78g_62 = dyn($src0, block_x + 6, block_y + 2)
79g_72 = dyn($src0, block_x + 7, block_y + 2)
80
81g_03 = dyn($src0, block_x + 0, block_y + 3)
82g_13 = dyn($src0, block_x + 1, block_y + 3)
83g_23 = dyn($src0, block_x + 2, block_y + 3)
84g_33 = dyn($src0, block_x + 3, block_y + 3)
85g_43 = dyn($src0, block_x + 4, block_y + 3)
86g_53 = dyn($src0, block_x + 5, block_y + 3)
87g_63 = dyn($src0, block_x + 6, block_y + 3)
88g_73 = dyn($src0, block_x + 7, block_y + 3)
89
90g_04 = dyn($src0, block_x + 0, block_y + 4)
91g_14 = dyn($src0, block_x + 1, block_y + 4)
92g_24 = dyn($src0, block_x + 2, block_y + 4)
93g_34 = dyn($src0, block_x + 3, block_y + 4)
94g_44 = dyn($src0, block_x + 4, block_y + 4)
95g_54 = dyn($src0, block_x + 5, block_y + 4)
96g_64 = dyn($src0, block_x + 6, block_y + 4)
97g_74 = dyn($src0, block_x + 7, block_y + 4)
98
99g_05 = dyn($src0, block_x + 0, block_y + 5)
100g_15 = dyn($src0, block_x + 1, block_y + 5)
101g_25 = dyn($src0, block_x + 2, block_y + 5)
102g_35 = dyn($src0, block_x + 3, block_y + 5)
103g_45 = dyn($src0, block_x + 4, block_y + 5)
104g_55 = dyn($src0, block_x + 5, block_y + 5)
105g_65 = dyn($src0, block_x + 6, block_y + 5)
106g_75 = dyn($src0, block_x + 7, block_y + 5)
107
108g_06 = dyn($src0, block_x + 0, block_y + 6)
109g_16 = dyn($src0, block_x + 1, block_y + 6)
110g_26 = dyn($src0, block_x + 2, block_y + 6)
111g_36 = dyn($src0, block_x + 3, block_y + 6)
112g_46 = dyn($src0, block_x + 4, block_y + 6)
113g_56 = dyn($src0, block_x + 5, block_y + 6)
114g_66 = dyn($src0, block_x + 6, block_y + 6)
115g_76 = dyn($src0, block_x + 7, block_y + 6)
116
117g_07 = dyn($src0, block_x + 0, block_y + 7)
118g_17 = dyn($src0, block_x + 1, block_y + 7)
119g_27 = dyn($src0, block_x + 2, block_y + 7)
120g_37 = dyn($src0, block_x + 3, block_y + 7)
121g_47 = dyn($src0, block_x + 4, block_y + 7)
122g_57 = dyn($src0, block_x + 5, block_y + 7)
123g_67 = dyn($src0, block_x + 6, block_y + 7)
124g_77 = dyn($src0, block_x + 7, block_y + 7)
125
126
127# ==============================================================================
128# 3. PRE-NORMALIZATION: Apply normalization factors C(u) and C(v) to each
129# coefficient before the summation.
130# ==============================================================================
131
132# Define normalization constants.
133inv_sqrt_N = 1 / sqrt(N)
134sqrt_2_div_N = 0.5
135
136# C(k) is inv_sqrt_N for k=0, and sqrt_2_div_N for k>0.
137norm_u0 = inv_sqrt_N
138norm_u1 = sqrt_2_div_N
139norm_u2 = sqrt_2_div_N
140norm_u3 = sqrt_2_div_N
141norm_u4 = sqrt_2_div_N
142norm_u5 = sqrt_2_div_N
143norm_u6 = sqrt_2_div_N
144norm_u7 = sqrt_2_div_N
145
146norm_v0 = inv_sqrt_N
147norm_v1 = sqrt_2_div_N
148norm_v2 = sqrt_2_div_N
149norm_v3 = sqrt_2_div_N
150norm_v4 = sqrt_2_div_N
151norm_v5 = sqrt_2_div_N
152norm_v6 = sqrt_2_div_N
153norm_v7 = sqrt_2_div_N
154
155# Create normalized coefficient variables `ng_uv`.
156ng_00 = g_00 * norm_u0 * norm_v0
157ng_10 = g_10 * norm_u1 * norm_v0
158ng_20 = g_20 * norm_u2 * norm_v0
159ng_30 = g_30 * norm_u3 * norm_v0
160ng_40 = g_40 * norm_u4 * norm_v0
161ng_50 = g_50 * norm_u5 * norm_v0
162ng_60 = g_60 * norm_u6 * norm_v0
163ng_70 = g_70 * norm_u7 * norm_v0
164ng_01 = g_01 * norm_u0 * norm_v1
165ng_11 = g_11 * norm_u1 * norm_v1
166ng_21 = g_21 * norm_u2 * norm_v1
167ng_31 = g_31 * norm_u3 * norm_v1
168ng_41 = g_41 * norm_u4 * norm_v1
169ng_51 = g_51 * norm_u5 * norm_v1
170ng_61 = g_61 * norm_u6 * norm_v1
171ng_71 = g_71 * norm_u7 * norm_v1
172ng_02 = g_02 * norm_u0 * norm_v2
173ng_12 = g_12 * norm_u1 * norm_v2
174ng_22 = g_22 * norm_u2 * norm_v2
175ng_32 = g_32 * norm_u3 * norm_v2
176ng_42 = g_42 * norm_u4 * norm_v2
177ng_52 = g_52 * norm_u5 * norm_v2
178ng_62 = g_62 * norm_u6 * norm_v2
179ng_72 = g_72 * norm_u7 * norm_v2
180ng_03 = g_03 * norm_u0 * norm_v3
181ng_13 = g_13 * norm_u1 * norm_v3
182ng_23 = g_23 * norm_u2 * norm_v3
183ng_33 = g_33 * norm_u3 * norm_v3
184ng_43 = g_43 * norm_u4 * norm_v3
185ng_53 = g_53 * norm_u5 * norm_v3
186ng_63 = g_63 * norm_u6 * norm_v3
187ng_73 = g_73 * norm_u7 * norm_v3
188ng_04 = g_04 * norm_u0 * norm_v4
189ng_14 = g_14 * norm_u1 * norm_v4
190ng_24 = g_24 * norm_u2 * norm_v4
191ng_34 = g_34 * norm_u3 * norm_v4
192ng_44 = g_44 * norm_u4 * norm_v4
193ng_54 = g_54 * norm_u5 * norm_v4
194ng_64 = g_64 * norm_u6 * norm_v4
195ng_74 = g_74 * norm_u7 * norm_v4
196ng_05 = g_05 * norm_u0 * norm_v5
197ng_15 = g_15 * norm_u1 * norm_v5
198ng_25 = g_25 * norm_u2 * norm_v5
199ng_35 = g_35 * norm_u3 * norm_v5
200ng_45 = g_45 * norm_u4 * norm_v5
201ng_55 = g_55 * norm_u5 * norm_v5
202ng_65 = g_65 * norm_u6 * norm_v5
203ng_75 = g_75 * norm_u7 * norm_v5
204ng_06 = g_06 * norm_u0 * norm_v6
205ng_16 = g_16 * norm_u1 * norm_v6
206ng_26 = g_26 * norm_u2 * norm_v6
207ng_36 = g_36 * norm_u3 * norm_v6
208ng_46 = g_46 * norm_u4 * norm_v6
209ng_56 = g_56 * norm_u5 * norm_v6
210ng_66 = g_66 * norm_u6 * norm_v6
211ng_76 = g_76 * norm_u7 * norm_v6
212ng_07 = g_07 * norm_u0 * norm_v7
213ng_17 = g_17 * norm_u1 * norm_v7
214ng_27 = g_27 * norm_u2 * norm_v7
215ng_37 = g_37 * norm_u3 * norm_v7
216ng_47 = g_47 * norm_u4 * norm_v7
217ng_57 = g_57 * norm_u5 * norm_v7
218ng_67 = g_67 * norm_u6 * norm_v7
219ng_77 = g_77 * norm_u7 * norm_v7
220
221
222# ==============================================================================
223# 4. COLUMN TRANSFORMS: Sum over frequency v for each column u.
224# This produces 8 intermediate values.
225# ==============================================================================
226
227# Pre-calculate cosine terms for the column transform (depends on y).
228# cos_yv = cos((2 * y + 1) * v * pi / 16)
229cos_y0 = cos((2 * y + 1) * 0 * $pi / 16) # This is always 1
230cos_y1 = cos((2 * y + 1) * 1 * $pi / 16)
231cos_y2 = cos((2 * y + 1) * 2 * $pi / 16)
232cos_y3 = cos((2 * y + 1) * 3 * $pi / 16)
233cos_y4 = cos((2 * y + 1) * 4 * $pi / 16)
234cos_y5 = cos((2 * y + 1) * 5 * $pi / 16)
235cos_y6 = cos((2 * y + 1) * 6 * $pi / 16)
236cos_y7 = cos((2 * y + 1) * 7 * $pi / 16)
237
238# Calculate the 8 intermediate sums.
239col_sum_0 = ng_00 * cos_y0 + ng_01 * cos_y1 + ng_02 * cos_y2 + ng_03 * cos_y3 + ng_04 * cos_y4 + ng_05 * cos_y5 + ng_06 * cos_y6 + ng_07 * cos_y7
240col_sum_1 = ng_10 * cos_y0 + ng_11 * cos_y1 + ng_12 * cos_y2 + ng_13 * cos_y3 + ng_14 * cos_y4 + ng_15 * cos_y5 + ng_16 * cos_y6 + ng_17 * cos_y7
241col_sum_2 = ng_20 * cos_y0 + ng_21 * cos_y1 + ng_22 * cos_y2 + ng_23 * cos_y3 + ng_24 * cos_y4 + ng_25 * cos_y5 + ng_26 * cos_y6 + ng_27 * cos_y7
242col_sum_3 = ng_30 * cos_y0 + ng_31 * cos_y1 + ng_32 * cos_y2 + ng_33 * cos_y3 + ng_34 * cos_y4 + ng_35 * cos_y5 + ng_36 * cos_y6 + ng_37 * cos_y7
243col_sum_4 = ng_40 * cos_y0 + ng_41 * cos_y1 + ng_42 * cos_y2 + ng_43 * cos_y3 + ng_44 * cos_y4 + ng_45 * cos_y5 + ng_46 * cos_y6 + ng_47 * cos_y7
244col_sum_5 = ng_50 * cos_y0 + ng_51 * cos_y1 + ng_52 * cos_y2 + ng_53 * cos_y3 + ng_54 * cos_y4 + ng_55 * cos_y5 + ng_56 * cos_y6 + ng_57 * cos_y7
245col_sum_6 = ng_60 * cos_y0 + ng_61 * cos_y1 + ng_62 * cos_y2 + ng_63 * cos_y3 + ng_64 * cos_y4 + ng_65 * cos_y5 + ng_66 * cos_y6 + ng_67 * cos_y7
246col_sum_7 = ng_70 * cos_y0 + ng_71 * cos_y1 + ng_72 * cos_y2 + ng_73 * cos_y3 + ng_74 * cos_y4 + ng_75 * cos_y5 + ng_76 * cos_y6 + ng_77 * cos_y7
247
248
249# ==============================================================================
250# 5. ROW TRANSFORM: Sum the intermediate results over frequency u to get the
251# final pixel value.
252# ==============================================================================
253
254# Pre-calculate cosine terms for the row transform (depends on x).
255# cos_xu = cos((2 * x + 1) * u * pi / 16)
256cos_x0 = cos((2 * x + 1) * 0 * $pi / 16) # This is always 1
257cos_x1 = cos((2 * x + 1) * 1 * $pi / 16)
258cos_x2 = cos((2 * x + 1) * 2 * $pi / 16)
259cos_x3 = cos((2 * x + 1) * 3 * $pi / 16)
260cos_x4 = cos((2 * x + 1) * 4 * $pi / 16)
261cos_x5 = cos((2 * x + 1) * 5 * $pi / 16)
262cos_x6 = cos((2 * x + 1) * 6 * $pi / 16)
263cos_x7 = cos((2 * x + 1) * 7 * $pi / 16)
264
265# The final summation gives the reconstructed pixel value.
266RESULT = col_sum_0 * cos_x0 + col_sum_1 * cos_x1 + col_sum_2 * cos_x2 + col_sum_3 * cos_x3 + col_sum_4 * cos_x4 + col_sum_5 * cos_x5 + col_sum_6 * cos_x6 + col_sum_7 * cos_x7