also looking at this
feat(media): implement native JPEG coding and bounded MJPEG streaming
#912
5 files
+442
-263
| @@ -0,0 +1,39 @@ | ||
| 1 | //! Shared orthonormal JPEG DCT basis and inverse transform (Home, MIT). | |
| 2 | const std = ; | |
| 3 | pub const BASIS: [8]@Vector(8, f32) = blk: { | |
| 4 | @setEvalBranchQuota(10000); | |
| 5 | var b: [8]@Vector(8, f32) = undefined; | |
| 6 | for (0..8) |u| for (0..8) |x| { | |
| 7 | const scale: f64 = if (u == 0) 0.3535533905932738 else 0.5; | |
| 8 | b[u][x] = @floatCast(scale * @cos((@as(f64, @floatFromInt(x)) * 2 + 1) * @as(f64, @floatFromInt(u)) * std.math.pi / 16)); | |
| 9 | }; | |
| 10 | break :blk b; | |
| 11 | }; | |
| 12 | ||
| 13 | pub fn inverse(block: *[64]i32, quant: *const [64]u16) void { | |
| 14 | var work: [8][8]f32 = undefined; | |
| 15 | for (0..8) |v| { | |
| 16 | var coefficients: @Vector(8, f32) = undefined; | |
| 17 | inline for (0..8) |u| coefficients[u] = @as(f32, @floatFromInt(block[v * 8 + u])) * @as(f32, @floatFromInt(quant[v * 8 + u])); | |
| 18 | for (0..8) |x| { | |
| 19 | var basis: @Vector(8, f32) = undefined; | |
| 20 | inline for (0..8) |u| basis[u] = BASIS[u][x]; | |
| 21 | work[v][x] = @reduce(.Add, coefficients * basis); | |
| 22 | } | |
| 23 | } | |
| 24 | for (0..8) |y| for (0..8) |x| { | |
| 25 | var values: @Vector(8, f32) = undefined; | |
| 26 | var basis: @Vector(8, f32) = undefined; | |
| 27 | inline for (0..8) |v| { | |
| 28 | values[v] = work[v][x]; | |
| 29 | basis[v] = BASIS[v][y]; | |
| 30 | } | |
| 31 | block[y * 8 + x] = @intFromFloat(std.math.clamp(@round(@reduce(.Add, values * basis)) + 128, 0, 255)); | |
| 32 | }; | |
| 33 | } | |
| 34 | test "inverse JPEG DC scale and zero AC are exact" { | |
| 35 | var block: [64]i32 = @splat(0); | |
| 36 | block[0] = 80; | |
| 37 | inverse(&block, &@as([64]u16, @splat(1))); | |
| 38 | for (block) |v| try std.testing.expectEqual(@as(i32, 138), v); | |
| 39 | } | |