VapourSynth-llvmexpr
Loading...
Searching...
No Matches
8x8dct.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# Forward 8x8 Discrete Cosine Transform (DCT-II)
20#
21# This script computes the DCT for 8x8 blocks of the input source clip ($src0).
22# The output at coordinate (X, Y) is the DCT coefficient (u, v) for the
23# corresponding block.
24#
25# The 2D DCT is implemented as two separable 1D DCTs (one for rows, one for columns).
26
27@ifndef __EXPR__
28@error This expr should be used in Expr mode
29@endif
30
31@if __INPUT_NUM__ != 1
32@error This expr requires exactly one input clip
33@endif
34
35# ==============================================================================
36# 1. SETUP: Determine current block and frequency coordinates (u, v)
37# ==============================================================================
38
39# DCT block size
40@define N 8
41
42# Frequency coordinates (u, v) for the current output pixel within an 8x8 block.
43u = $X % N
44v = $Y % N
45
46# Top-left corner of the current 8x8 source block.
47block_x = trunc($X / N) * N
48block_y = trunc($Y / N) * N
49
50
51# ==============================================================================
52# 2. DATA GATHERING: Load all 64 pixels from the source 8x8 block.
53# `p_xy` corresponds to the pixel at (x, y) relative to the block corner.
54# ==============================================================================
55
56p_00 = dyn($src0, block_x + 0, block_y + 0)
57p_10 = dyn($src0, block_x + 1, block_y + 0)
58p_20 = dyn($src0, block_x + 2, block_y + 0)
59p_30 = dyn($src0, block_x + 3, block_y + 0)
60p_40 = dyn($src0, block_x + 4, block_y + 0)
61p_50 = dyn($src0, block_x + 5, block_y + 0)
62p_60 = dyn($src0, block_x + 6, block_y + 0)
63p_70 = dyn($src0, block_x + 7, block_y + 0)
64
65p_01 = dyn($src0, block_x + 0, block_y + 1)
66p_11 = dyn($src0, block_x + 1, block_y + 1)
67p_21 = dyn($src0, block_x + 2, block_y + 1)
68p_31 = dyn($src0, block_x + 3, block_y + 1)
69p_41 = dyn($src0, block_x + 4, block_y + 1)
70p_51 = dyn($src0, block_x + 5, block_y + 1)
71p_61 = dyn($src0, block_x + 6, block_y + 1)
72p_71 = dyn($src0, block_x + 7, block_y + 1)
73
74p_02 = dyn($src0, block_x + 0, block_y + 2)
75p_12 = dyn($src0, block_x + 1, block_y + 2)
76p_22 = dyn($src0, block_x + 2, block_y + 2)
77p_32 = dyn($src0, block_x + 3, block_y + 2)
78p_42 = dyn($src0, block_x + 4, block_y + 2)
79p_52 = dyn($src0, block_x + 5, block_y + 2)
80p_62 = dyn($src0, block_x + 6, block_y + 2)
81p_72 = dyn($src0, block_x + 7, block_y + 2)
82
83p_03 = dyn($src0, block_x + 0, block_y + 3)
84p_13 = dyn($src0, block_x + 1, block_y + 3)
85p_23 = dyn($src0, block_x + 2, block_y + 3)
86p_33 = dyn($src0, block_x + 3, block_y + 3)
87p_43 = dyn($src0, block_x + 4, block_y + 3)
88p_53 = dyn($src0, block_x + 5, block_y + 3)
89p_63 = dyn($src0, block_x + 6, block_y + 3)
90p_73 = dyn($src0, block_x + 7, block_y + 3)
91
92p_04 = dyn($src0, block_x + 0, block_y + 4)
93p_14 = dyn($src0, block_x + 1, block_y + 4)
94p_24 = dyn($src0, block_x + 2, block_y + 4)
95p_34 = dyn($src0, block_x + 3, block_y + 4)
96p_44 = dyn($src0, block_x + 4, block_y + 4)
97p_54 = dyn($src0, block_x + 5, block_y + 4)
98p_64 = dyn($src0, block_x + 6, block_y + 4)
99p_74 = dyn($src0, block_x + 7, block_y + 4)
100
101p_05 = dyn($src0, block_x + 0, block_y + 5)
102p_15 = dyn($src0, block_x + 1, block_y + 5)
103p_25 = dyn($src0, block_x + 2, block_y + 5)
104p_35 = dyn($src0, block_x + 3, block_y + 5)
105p_45 = dyn($src0, block_x + 4, block_y + 5)
106p_55 = dyn($src0, block_x + 5, block_y + 5)
107p_65 = dyn($src0, block_x + 6, block_y + 5)
108p_75 = dyn($src0, block_x + 7, block_y + 5)
109
110p_06 = dyn($src0, block_x + 0, block_y + 6)
111p_16 = dyn($src0, block_x + 1, block_y + 6)
112p_26 = dyn($src0, block_x + 2, block_y + 6)
113p_36 = dyn($src0, block_x + 3, block_y + 6)
114p_46 = dyn($src0, block_x + 4, block_y + 6)
115p_56 = dyn($src0, block_x + 5, block_y + 6)
116p_66 = dyn($src0, block_x + 6, block_y + 6)
117p_76 = dyn($src0, block_x + 7, block_y + 6)
118
119p_07 = dyn($src0, block_x + 0, block_y + 7)
120p_17 = dyn($src0, block_x + 1, block_y + 7)
121p_27 = dyn($src0, block_x + 2, block_y + 7)
122p_37 = dyn($src0, block_x + 3, block_y + 7)
123p_47 = dyn($src0, block_x + 4, block_y + 7)
124p_57 = dyn($src0, block_x + 5, block_y + 7)
125p_67 = dyn($src0, block_x + 6, block_y + 7)
126p_77 = dyn($src0, block_x + 7, block_y + 7)
127
128
129# ==============================================================================
130# 3. ROW TRANSFORMS: Perform 1D DCT on each row of the 8x8 block.
131# This sums pixels across x for each row y.
132# ==============================================================================
133
134# Pre-calculate cosine terms for the row transform (depends on u).
135# cos_ux = cos((2*x + 1) * u * pi / 16)
136cos_u0 = cos( 1 * u * $pi / 16)
137cos_u1 = cos( 3 * u * $pi / 16)
138cos_u2 = cos( 5 * u * $pi / 16)
139cos_u3 = cos( 7 * u * $pi / 16)
140cos_u4 = cos( 9 * u * $pi / 16)
141cos_u5 = cos(11 * u * $pi / 16)
142cos_u6 = cos(13 * u * $pi / 16)
143cos_u7 = cos(15 * u * $pi / 16)
144
145# Calculate the 8 intermediate values, one for each row.
146row_dct_0 = p_00 * cos_u0 + p_10 * cos_u1 + p_20 * cos_u2 + p_30 * cos_u3 + p_40 * cos_u4 + p_50 * cos_u5 + p_60 * cos_u6 + p_70 * cos_u7
147row_dct_1 = p_01 * cos_u0 + p_11 * cos_u1 + p_21 * cos_u2 + p_31 * cos_u3 + p_41 * cos_u4 + p_51 * cos_u5 + p_61 * cos_u6 + p_71 * cos_u7
148row_dct_2 = p_02 * cos_u0 + p_12 * cos_u1 + p_22 * cos_u2 + p_32 * cos_u3 + p_42 * cos_u4 + p_52 * cos_u5 + p_62 * cos_u6 + p_72 * cos_u7
149row_dct_3 = p_03 * cos_u0 + p_13 * cos_u1 + p_23 * cos_u2 + p_33 * cos_u3 + p_43 * cos_u4 + p_53 * cos_u5 + p_63 * cos_u6 + p_73 * cos_u7
150row_dct_4 = p_04 * cos_u0 + p_14 * cos_u1 + p_24 * cos_u2 + p_34 * cos_u3 + p_44 * cos_u4 + p_54 * cos_u5 + p_64 * cos_u6 + p_74 * cos_u7
151row_dct_5 = p_05 * cos_u0 + p_15 * cos_u1 + p_25 * cos_u2 + p_35 * cos_u3 + p_45 * cos_u4 + p_55 * cos_u5 + p_65 * cos_u6 + p_75 * cos_u7
152row_dct_6 = p_06 * cos_u0 + p_16 * cos_u1 + p_26 * cos_u2 + p_36 * cos_u3 + p_46 * cos_u4 + p_56 * cos_u5 + p_66 * cos_u6 + p_76 * cos_u7
153row_dct_7 = p_07 * cos_u0 + p_17 * cos_u1 + p_27 * cos_u2 + p_37 * cos_u3 + p_47 * cos_u4 + p_57 * cos_u5 + p_67 * cos_u6 + p_77 * cos_u7
154
155
156# ==============================================================================
157# 4. COLUMN TRANSFORM: Perform 1D DCT on the intermediate results.
158# This sums the intermediate row_dct values across y.
159# ==============================================================================
160
161# Pre-calculate cosine terms for the column transform (depends on v).
162# cos_vy = cos((2*y + 1) * v * pi / 16)
163cos_v0 = cos( 1 * v * $pi / 16)
164cos_v1 = cos( 3 * v * $pi / 16)
165cos_v2 = cos( 5 * v * $pi / 16)
166cos_v3 = cos( 7 * v * $pi / 16)
167cos_v4 = cos( 9 * v * $pi / 16)
168cos_v5 = cos(11 * v * $pi / 16)
169cos_v6 = cos(13 * v * $pi / 16)
170cos_v7 = cos(15 * v * $pi / 16)
171
172# Calculate the final un-normalized sum.
173final_sum = row_dct_0 * cos_v0 + row_dct_1 * cos_v1 + row_dct_2 * cos_v2 + row_dct_3 * cos_v3 + row_dct_4 * cos_v4 + row_dct_5 * cos_v5 + row_dct_6 * cos_v6 + row_dct_7 * cos_v7
174
175
176# ==============================================================================
177# 5. NORMALIZATION and FINAL RESULT
178# ==============================================================================
179
180# Define normalization constants.
181# C(k) = 1/sqrt(N) for k=0
182# C(k) = sqrt(2/N) for k>0
183# For N=8, C(k>0) = sqrt(2/8) = sqrt(1/4) = 0.5
184inv_sqrt_N = 1 / sqrt(N)
185sqrt_2_div_N = 0.5
186
187# Determine the normalization factors C(u) and C(v) using the ternary operator.
188norm_u = (u == 0) ? inv_sqrt_N : sqrt_2_div_N
189norm_v = (v == 0) ? inv_sqrt_N : sqrt_2_div_N
190
191# Apply normalization and assign to the final result.
192RESULT = final_sum * norm_u * norm_v