code cleanup

This commit is contained in:
minjaesong
2025-09-16 10:26:03 +09:00
parent a5da200507
commit 3011c73168
2 changed files with 3 additions and 768 deletions

View File

@@ -25,78 +25,6 @@ class GraphicsJSR223Delegate(private val vm: VM) {
private val idct8TempBuffer = FloatArray(64)
private val idct16TempBuffer = FloatArray(256) // For 16x16 IDCT
private val idct16SeparableBuffer = FloatArray(256) // For separable 16x16 IDCT
// Lossless IDCT functions for float16 coefficients (no quantization)
private fun tevIdct8x8_lossless(coeffs: FloatArray): IntArray {
val result = IntArray(64)
// Fast separable IDCT (row-column decomposition) for lossless coefficients
// First pass: Process rows (8 1D IDCTs)
for (row in 0 until 8) {
for (col in 0 until 8) {
var sum = 0f
for (u in 0 until 8) {
sum += dctBasis8[u][col] * coeffs[row * 8 + u]
}
idct8TempBuffer[row * 8 + col] = sum * 0.5f
}
}
// Second pass: Process columns (8 1D IDCTs)
for (col in 0 until 8) {
for (row in 0 until 8) {
var sum = 0f
for (v in 0 until 8) {
sum += dctBasis8[v][row] * idct8TempBuffer[v * 8 + col]
}
val finalValue = sum * 0.5f + 128f
result[row * 8 + col] = if (finalValue.isNaN() || finalValue.isInfinite()) {
println("NaN/Inf detected in 8x8 IDCT at ($row,$col): sum=$sum, finalValue=$finalValue")
128 // Default to middle gray
} else {
finalValue.roundToInt().coerceIn(0, 255)
}
}
}
return result
}
private fun tevIdct16x16_lossless(coeffs: FloatArray): IntArray {
val result = IntArray(256)
// Fast separable IDCT (row-column decomposition) for 16x16 lossless coefficients
// First pass: Process rows (16 1D IDCTs)
for (row in 0 until 16) {
for (col in 0 until 16) {
var sum = 0f
for (u in 0 until 16) {
sum += dctBasis16[u][col] * coeffs[row * 16 + u]
}
idct16TempBuffer[row * 16 + col] = sum * 0.25f
}
}
// Second pass: Process columns (16 1D IDCTs)
for (col in 0 until 16) {
for (row in 0 until 16) {
var sum = 0f
for (v in 0 until 16) {
sum += dctBasis16[v][row] * idct16TempBuffer[v * 16 + col]
}
val finalValue = sum * 0.25f + 128f
result[row * 16 + col] = if (finalValue.isNaN() || finalValue.isInfinite()) {
println("NaN/Inf detected in 16x16 IDCT at ($row,$col): sum=$sum, finalValue=$finalValue")
128 // Default to middle gray
} else {
finalValue.roundToInt().coerceIn(0, 255)
}
}
}
return result
}
private fun getFirstGPU(): GraphicsAdapter? {
return vm.findPeribyType(VM.PERITYPE_GPU_AND_TERM)?.peripheral as? GraphicsAdapter
@@ -3665,52 +3593,6 @@ class GraphicsJSR223Delegate(private val vm: VM) {
}
}
private fun convertAndDoNothing(
blocks: Array<ShortArray?>, quantTable: IntArray, qScale: Int, rateControlFactors: FloatArray,
blocksX: Int, blocksY: Int,
kLinearGradient: IntArray, kAlphaSqrt2: IntArray, kHalfSqrt2: Int
): Array<FloatArray?> {
val coeffsSize = 16 * 16
val numBlocks = blocksX * blocksY
val blocksMid = Array(numBlocks) { IntArray(coeffsSize) }
for (blockIndex in 0 until numBlocks) {
val block = blocks[blockIndex]
if (block != null) {
val rateControlFactor = rateControlFactors[blockIndex]
for (i in 0 until coeffsSize) {
val quantIdx = i.coerceIn(0, quantTable.size - 1)
if (i == 0) {
// DC coefficient: lossless (no quantization)
val dcValue = block[i].toInt()
blocksMid[blockIndex][i] = dcValue
} else {
// AC coefficients: use quantization intervals
val quant = (quantTable[quantIdx] * jpeg_quality_to_mult(qScale * rateControlFactor)).coerceIn(1f, 255f).toInt()
// Standard dequantized value (midpoint)
blocksMid[blockIndex][i] = block[i].toInt() * quant
}
}
}
}
val result = Array<FloatArray?>(blocks.size) { null }
for (blockIndex in 0 until numBlocks) {
val block = blocks[blockIndex]
if (block != null) {
result[blockIndex] = FloatArray(coeffsSize) { i ->
blocksMid[blockIndex][i].toFloat()
}
}
}
return result
}
private fun convertAndOptimize8x8Blocks(
blocks: Array<ShortArray?>, quantTable: IntArray, qScale: Int, rateControlFactors: FloatArray,
blocksX: Int, blocksY: Int,
@@ -3982,10 +3864,6 @@ class GraphicsJSR223Delegate(private val vm: VM) {
} catch (e: Exception) {
println("TAV decode error: ${e.message}")
}
// if (enableDeblocking) {
// tavAdaptiveDeblockingFilter(currentRGBAddr, width, height)
// }
}
private fun decodeDWTIntraTileRGB(readPtr: Long, tileX: Int, tileY: Int, currentRGBAddr: Long,
@@ -4310,51 +4188,6 @@ class GraphicsJSR223Delegate(private val vm: VM) {
)
}
private fun applyDWT53Forward(data: FloatArray, width: Int, height: Int) {
// TODO: Implement 5/3 forward DWT
// Lifting scheme implementation for 5/3 reversible filter
}
private fun applyDWT53Inverse(data: FloatArray, width: Int, height: Int) {
// 5/3 reversible DWT inverse using lifting scheme
// First apply horizontal inverse DWT on all rows
val tempRow = FloatArray(width)
for (y in 0 until height) {
for (x in 0 until width) {
tempRow[x] = data[y * width + x]
}
applyLift53InverseHorizontal(tempRow, width)
for (x in 0 until width) {
data[y * width + x] = tempRow[x]
}
}
// Then apply vertical inverse DWT on all columns
val tempCol = FloatArray(height)
for (x in 0 until width) {
for (y in 0 until height) {
tempCol[y] = data[y * width + x]
}
applyLift53InverseVertical(tempCol, height)
for (y in 0 until height) {
data[y * width + x] = tempCol[y]
}
}
}
private fun applyDWT97Forward(data: FloatArray, width: Int, height: Int) {
// TODO: Implement 9/7 forward DWT
// Lifting scheme implementation for 9/7 irreversible filter
}
private fun generateWindowFunction(window: FloatArray, size: Int) {
// Raised cosine (Hann) window for smooth blending
for (i in 0 until size) {
val t = i.toFloat() / (size - 1)
window[i] = 0.5f * (1.0f - kotlin.math.cos(PI * t))
}
}
private fun applyDWTInverseMultiLevel(data: FloatArray, width: Int, height: Int, levels: Int, filterType: Int) {
// Multi-level inverse DWT - reconstruct from smallest to largest (reverse of encoder)
val size = width // Full tile size (112 for TAV)
@@ -4411,84 +4244,6 @@ class GraphicsJSR223Delegate(private val vm: VM) {
}
}
private fun applyDWT97Inverse(data: FloatArray, width: Int, height: Int) {
// 9/7 irreversible DWT inverse using lifting scheme
// First apply horizontal inverse DWT on all rows
val tempRow = FloatArray(width)
for (y in 0 until height) {
for (x in 0 until width) {
tempRow[x] = data[y * width + x]
}
applyLift97InverseHorizontal(tempRow, width)
for (x in 0 until width) {
data[y * width + x] = tempRow[x]
}
}
// Then apply vertical inverse DWT on all columns
val tempCol = FloatArray(height)
for (x in 0 until width) {
for (y in 0 until height) {
tempCol[y] = data[y * width + x]
}
applyLift97InverseVertical(tempCol, height)
for (y in 0 until height) {
data[y * width + x] = tempCol[y]
}
}
}
private fun applyLift97InverseHorizontal(row: FloatArray, width: Int) { TODO() }
private fun applyLift97InverseVertical(col: FloatArray, height: Int) { TODO() }
// 1D lifting scheme implementations for 5/3 filter
private fun applyLift53InverseHorizontal(data: FloatArray, length: Int) {
if (length < 2) return
val temp = FloatArray(length)
val half = (length + 1) / 2
// Separate even and odd samples (inverse interleaving)
for (i in 0 until half) {
temp[i] = data[2 * i] // Even samples (low-pass)
}
for (i in 0 until length / 2) {
temp[half + i] = data[2 * i + 1] // Odd samples (high-pass)
}
// Inverse lifting steps for 5/3 filter
// Step 2: Undo update step - even[i] -= (odd[i-1] + odd[i] + 2) >> 2
for (i in 1 until half) {
val oddPrev = if (i - 1 >= 0) temp[half + i - 1] else 0.0f
val oddCurr = if (i < length / 2) temp[half + i] else 0.0f
temp[i] += (oddPrev + oddCurr + 2.0f) / 4.0f
}
if (half > 0) {
val oddCurr = if (0 < length / 2) temp[half] else 0.0f
temp[0] += oddCurr / 2.0f
}
// Step 1: Undo predict step - odd[i] += (even[i] + even[i+1]) >> 1
for (i in 0 until length / 2) {
val evenCurr = temp[i]
val evenNext = if (i + 1 < half) temp[i + 1] else temp[half - 1]
temp[half + i] -= (evenCurr + evenNext) / 2.0f
}
// Interleave back
for (i in 0 until half) {
data[2 * i] = temp[i]
}
for (i in 0 until length / 2) {
data[2 * i + 1] = temp[half + i]
}
}
private fun applyLift53InverseVertical(data: FloatArray, length: Int) {
// Same as horizontal but for vertical direction
applyLift53InverseHorizontal(data, length)
}
// 1D lifting scheme implementations for 9/7 irreversible filter
private fun applyDWT97Inverse1D(data: FloatArray, length: Int) {
if (length < 2) return
@@ -4643,426 +4398,4 @@ class GraphicsJSR223Delegate(private val vm: VM) {
}
}
private fun tavAdaptiveDeblockingFilter(rgbAddr: Long, width: Int, height: Int) {
val tileSize = 112
val tilesX = (width + tileSize - 1) / tileSize
val tilesY = (height + tileSize - 1) / tileSize
// Process vertical seams (between horizontally adjacent tiles)
for (tileY in 0 until tilesY) {
for (tileX in 0 until tilesX - 1) {
val seamX = (tileX + 1) * tileSize // Actual boundary between tiles
deblockVerticalSeamStrong(rgbAddr, width, height, seamX, tileY * tileSize, tileSize)
}
}
// Process horizontal seams (between vertically adjacent tiles)
for (tileY in 0 until tilesY - 1) {
for (tileX in 0 until tilesX) {
val seamY = (tileY + 1) * tileSize // Actual boundary between tiles
deblockHorizontalSeamStrong(rgbAddr, width, height, tileX * tileSize, seamY, tileSize)
}
}
}
private fun deblockVerticalSeamStrong(rgbAddr: Long, width: Int, height: Int, seamX: Int, startY: Int, tileHeight: Int) {
if (seamX >= width) return
val endY = minOf(startY + tileHeight, height)
for (y in startY until endY) {
if (y >= height) break
// Check for discontinuity across the seam
val leftX = seamX - 1
val rightX = seamX
if (leftX >= 0 && rightX < width) {
val leftOffset = (y * width + leftX) * 3L
val rightOffset = (y * width + rightX) * 3L
val leftR = vm.peek(rgbAddr + leftOffset).toInt() and 0xFF
val leftG = vm.peek(rgbAddr + leftOffset + 1).toInt() and 0xFF
val leftB = vm.peek(rgbAddr + leftOffset + 2).toInt() and 0xFF
val rightR = vm.peek(rgbAddr + rightOffset).toInt() and 0xFF
val rightG = vm.peek(rgbAddr + rightOffset + 1).toInt() and 0xFF
val rightB = vm.peek(rgbAddr + rightOffset + 2).toInt() and 0xFF
// Calculate discontinuity strength
val diffR = abs(leftR - rightR)
val diffG = abs(leftG - rightG)
val diffB = abs(leftB - rightB)
val maxDiff = maxOf(diffR, diffG, diffB)
// Only apply deblocking if there's a significant discontinuity
if (maxDiff in 2 until 120) {
// Adaptive filter radius: wider for smooth gradients, narrower for sharp edges
val filterRadius = when {
maxDiff <= 15 -> 6 // Very smooth gradients: wide filter (13 pixels)
maxDiff <= 30 -> 4 // Moderate gradients: medium filter (9 pixels)
maxDiff <= 60 -> 3 // Sharp transitions: narrow filter (7 pixels)
else -> 2 // Very sharp edges: minimal filter (5 pixels)
}
for (dx in -filterRadius..filterRadius) {
val x = seamX + dx
if (x in 0 until width) {
val offset = (y * width + x) * 3L
val currentR = vm.peek(rgbAddr + offset).toInt() and 0xFF
val currentG = vm.peek(rgbAddr + offset + 1).toInt() and 0xFF
val currentB = vm.peek(rgbAddr + offset + 2).toInt() and 0xFF
var sumR = 0.0f
var sumG = 0.0f
var sumB = 0.0f
var weightSum = 0.0f
// Bilateral filtering with spatial and intensity weights
for (sx in maxOf(0, x-filterRadius)..minOf(width-1, x+filterRadius)) {
val sOffset = (y * width + sx) * 3L
val sR = vm.peek(rgbAddr + sOffset).toInt() and 0xFF
val sG = vm.peek(rgbAddr + sOffset + 1).toInt() and 0xFF
val sB = vm.peek(rgbAddr + sOffset + 2).toInt() and 0xFF
// Spatial weight (distance from current pixel)
val spatialWeight = 1.0f / (1.0f + abs(sx - x))
// Intensity weight (color similarity)
val colorDiff = sqrt(((sR - currentR) * (sR - currentR) +
(sG - currentG) * (sG - currentG) +
(sB - currentB) * (sB - currentB)).toFloat())
val intensityWeight = exp(-colorDiff / 30.0f)
val totalWeight = spatialWeight * intensityWeight
sumR += sR * totalWeight
sumG += sG * totalWeight
sumB += sB * totalWeight
weightSum += totalWeight
}
if (weightSum > 0) {
val filteredR = (sumR / weightSum).toInt()
val filteredG = (sumG / weightSum).toInt()
val filteredB = (sumB / weightSum).toInt()
// Concentrate blur heavily at the seam boundary
val distance = abs(dx).toFloat()
val blendWeight = when {
distance == 0.0f -> 0.95f // Maximum blur at exact seam
distance == 1.0f -> 0.8f // Strong blur adjacent to seam
distance == 2.0f -> 0.5f // Medium blur 2 pixels away
else -> exp(-distance * distance / 1.5f) * 0.3f // Gentle falloff beyond
}
val finalR = (currentR * (1 - blendWeight) + filteredR * blendWeight).toInt().coerceIn(0, 255)
val finalG = (currentG * (1 - blendWeight) + filteredG * blendWeight).toInt().coerceIn(0, 255)
val finalB = (currentB * (1 - blendWeight) + filteredB * blendWeight).toInt().coerceIn(0, 255)
vm.poke(rgbAddr + offset, finalR.toByte())
vm.poke(rgbAddr + offset + 1, finalG.toByte())
vm.poke(rgbAddr + offset + 2, finalB.toByte())
}
}
}
}
}
}
}
private fun deblockHorizontalSeamStrong(rgbAddr: Long, width: Int, height: Int, startX: Int, seamY: Int, tileWidth: Int) {
if (seamY >= height) return
val endX = minOf(startX + tileWidth, width)
for (x in startX until endX) {
if (x >= width) break
// Check for discontinuity across the seam
val topY = seamY - 1
val bottomY = seamY
if (topY >= 0 && bottomY < height) {
val topOffset = (topY * width + x) * 3L
val bottomOffset = (bottomY * width + x) * 3L
val topR = vm.peek(rgbAddr + topOffset).toInt() and 0xFF
val topG = vm.peek(rgbAddr + topOffset + 1).toInt() and 0xFF
val topB = vm.peek(rgbAddr + topOffset + 2).toInt() and 0xFF
val bottomR = vm.peek(rgbAddr + bottomOffset).toInt() and 0xFF
val bottomG = vm.peek(rgbAddr + bottomOffset + 1).toInt() and 0xFF
val bottomB = vm.peek(rgbAddr + bottomOffset + 2).toInt() and 0xFF
// Calculate discontinuity strength
val diffR = abs(topR - bottomR)
val diffG = abs(topG - bottomG)
val diffB = abs(topB - bottomB)
val maxDiff = maxOf(diffR, diffG, diffB)
// Only apply deblocking if there's a significant discontinuity
if (maxDiff in 2 until 120) {
// Adaptive filter radius: wider for smooth gradients, narrower for sharp edges
val filterRadius = when {
maxDiff <= 15 -> 6 // Very smooth gradients: wide filter (13 pixels)
maxDiff <= 30 -> 4 // Moderate gradients: medium filter (9 pixels)
maxDiff <= 60 -> 3 // Sharp transitions: narrow filter (7 pixels)
else -> 2 // Very sharp edges: minimal filter (5 pixels)
}
for (dy in -filterRadius..filterRadius) {
val y = seamY + dy
if (y in 0 until height) {
val offset = (y * width + x) * 3L
val currentR = vm.peek(rgbAddr + offset).toInt() and 0xFF
val currentG = vm.peek(rgbAddr + offset + 1).toInt() and 0xFF
val currentB = vm.peek(rgbAddr + offset + 2).toInt() and 0xFF
var sumR = 0.0f
var sumG = 0.0f
var sumB = 0.0f
var weightSum = 0.0f
// Bilateral filtering with spatial and intensity weights
for (sy in maxOf(0, y-filterRadius)..minOf(height-1, y+filterRadius)) {
val sOffset = (sy * width + x) * 3L
val sR = vm.peek(rgbAddr + sOffset).toInt() and 0xFF
val sG = vm.peek(rgbAddr + sOffset + 1).toInt() and 0xFF
val sB = vm.peek(rgbAddr + sOffset + 2).toInt() and 0xFF
// Spatial weight (distance from current pixel)
val spatialWeight = 1.0f / (1.0f + abs(sy - y))
// Intensity weight (color similarity)
val colorDiff = sqrt(((sR - currentR) * (sR - currentR) +
(sG - currentG) * (sG - currentG) +
(sB - currentB) * (sB - currentB)).toFloat())
val intensityWeight = exp(-colorDiff / 30.0f)
val totalWeight = spatialWeight * intensityWeight
sumR += sR * totalWeight
sumG += sG * totalWeight
sumB += sB * totalWeight
weightSum += totalWeight
}
if (weightSum > 0) {
val filteredR = (sumR / weightSum).toInt()
val filteredG = (sumG / weightSum).toInt()
val filteredB = (sumB / weightSum).toInt()
// Concentrate blur heavily at the seam boundary
val distance = abs(dy).toFloat()
val blendWeight = when {
distance == 0.0f -> 0.95f // Maximum blur at exact seam
distance == 1.0f -> 0.8f // Strong blur adjacent to seam
distance == 2.0f -> 0.5f // Medium blur 2 pixels away
else -> exp(-distance * distance / 1.5f) * 0.3f // Gentle falloff beyond
}
val finalR = (currentR * (1 - blendWeight) + filteredR * blendWeight).toInt().coerceIn(0, 255)
val finalG = (currentG * (1 - blendWeight) + filteredG * blendWeight).toInt().coerceIn(0, 255)
val finalB = (currentB * (1 - blendWeight) + filteredB * blendWeight).toInt().coerceIn(0, 255)
vm.poke(rgbAddr + offset, finalR.toByte())
vm.poke(rgbAddr + offset + 1, finalG.toByte())
vm.poke(rgbAddr + offset + 2, finalB.toByte())
}
}
}
}
}
}
}
private fun analyzeTextureComplexity(rgbAddr: Long, width: Int, height: Int, centerX: Int, centerY: Int, isVerticalSeam: Boolean): Float {
val radius = 4
var totalVariance = 0.0f
var count = 0
// Calculate variance in a small window around the seam
for (dy in -radius..radius) {
for (dx in -radius..radius) {
val x = centerX + dx
val y = centerY + dy
if (x >= 0 && x < width && y >= 0 && y < height) {
val offset = (y * width + x) * 3L
val r = vm.peek(rgbAddr + offset).toInt() and 0xFF
val g = vm.peek(rgbAddr + offset + 1).toInt() and 0xFF
val b = vm.peek(rgbAddr + offset + 2).toInt() and 0xFF
val luma = 0.299f * r + 0.587f * g + 0.114f * b
// Compare with adjacent pixels to measure local variance
if (x > 0) {
val leftOffset = (y * width + (x-1)) * 3L
val leftR = vm.peek(rgbAddr + leftOffset).toInt() and 0xFF
val leftG = vm.peek(rgbAddr + leftOffset + 1).toInt() and 0xFF
val leftB = vm.peek(rgbAddr + leftOffset + 2).toInt() and 0xFF
val leftLuma = 0.299f * leftR + 0.587f * leftG + 0.114f * leftB
totalVariance += abs(luma - leftLuma)
count++
}
if (y > 0) {
val topOffset = ((y-1) * width + x) * 3L
val topR = vm.peek(rgbAddr + topOffset).toInt() and 0xFF
val topG = vm.peek(rgbAddr + topOffset + 1).toInt() and 0xFF
val topB = vm.peek(rgbAddr + topOffset + 2).toInt() and 0xFF
val topLuma = 0.299f * topR + 0.587f * topG + 0.114f * topB
totalVariance += abs(luma - topLuma)
count++
}
}
}
}
return if (count > 0) totalVariance / count else 0.0f
}
private fun bilinearInterpolate(
dataPtr: Long, width: Int, height: Int,
x: Float, y: Float
): Float {
val x0 = floor(x).toInt()
val y0 = floor(y).toInt()
val x1 = x0 + 1
val y1 = y0 + 1
if (x0 < 0 || y0 < 0 || x1 >= width || y1 >= height) {
return 0.0f // Out of bounds
}
val fx = x - x0
val fy = y - y0
val p00 = vm.peekFloat(dataPtr + (y0 * width + x0) * 4L)!!
val p10 = vm.peekFloat(dataPtr + (y0 * width + x1) * 4L)!!
val p01 = vm.peekFloat(dataPtr + (y1 * width + x0) * 4L)!!
val p11 = vm.peekFloat(dataPtr + (y1 * width + x1) * 4L)!!
return p00 * (1 - fx) * (1 - fy) +
p10 * fx * (1 - fy) +
p01 * (1 - fx) * fy +
p11 * fx * fy
}
/**
* TAV deblocking filter - reduces DWT quantization artifacts and tile boundary artifacts
* Applies a gentle smoothing filter across tile boundaries and high-frequency areas
*/
private fun tavDeblockingFilter(rgbAddr: Long, width: Int, height: Int) {
val tileSize = 112 // TAV uses 112x112 tiles
val tilesX = (width + tileSize - 1) / tileSize
val tilesY = (height + tileSize - 1) / tileSize
val thisAddrIncVec: Long = if (rgbAddr < 0) -1 else 1
// Process tile boundaries (horizontal and vertical)
for (tileY in 0 until tilesY) {
for (tileX in 0 until tilesX) {
val startX = tileX * tileSize
val startY = tileY * tileSize
val endX = kotlin.math.min(startX + tileSize, width)
val endY = kotlin.math.min(startY + tileSize, height)
// Smooth vertical tile boundaries
if (tileX > 0 && startX < width) {
for (y in startY until endY) {
smoothVerticalBoundary(rgbAddr, width, height, startX - 1, y, thisAddrIncVec)
}
}
// Smooth horizontal tile boundaries
if (tileY > 0 && startY < height) {
for (x in startX until endX) {
smoothHorizontalBoundary(rgbAddr, width, height, x, startY - 1, thisAddrIncVec)
}
}
}
}
// Apply gentle smoothing to reduce DWT quantization artifacts
applyDWTSmoothing(rgbAddr, width, height, thisAddrIncVec)
}
private fun smoothVerticalBoundary(rgbAddr: Long, width: Int, height: Int, x: Int, y: Int, addrInc: Long) {
if (x < 1 || x >= width - 1 || y < 0 || y >= height) return
for (channel in 0 until 3) {
val leftOffset = (y.toLong() * width + (x - 1)) * 3 + channel
val centerOffset = (y.toLong() * width + x) * 3 + channel
val rightOffset = (y.toLong() * width + (x + 1)) * 3 + channel
val left = vm.peek(rgbAddr + leftOffset * addrInc)?.toUint()?.toInt() ?: 0
val center = vm.peek(rgbAddr + centerOffset * addrInc)?.toUint()?.toInt() ?: 0
val right = vm.peek(rgbAddr + rightOffset * addrInc)?.toUint()?.toInt() ?: 0
// Apply gentle 3-tap filter: [0.25, 0.5, 0.25]
val smoothed = ((left + 2 * center + right) / 4).coerceIn(0, 255)
vm.poke(rgbAddr + centerOffset * addrInc, smoothed.toByte())
}
}
private fun smoothHorizontalBoundary(rgbAddr: Long, width: Int, height: Int, x: Int, y: Int, addrInc: Long) {
if (x < 0 || x >= width || y < 1 || y >= height - 1) return
for (channel in 0 until 3) {
val topOffset = ((y - 1).toLong() * width + x) * 3 + channel
val centerOffset = (y.toLong() * width + x) * 3 + channel
val bottomOffset = ((y + 1).toLong() * width + x) * 3 + channel
val top = vm.peek(rgbAddr + topOffset * addrInc)?.toUint()?.toInt() ?: 0
val center = vm.peek(rgbAddr + centerOffset * addrInc)?.toUint()?.toInt() ?: 0
val bottom = vm.peek(rgbAddr + bottomOffset * addrInc)?.toUint()?.toInt() ?: 0
// Apply gentle 3-tap filter: [0.25, 0.5, 0.25]
val smoothed = ((top + 2 * center + bottom) / 4).coerceIn(0, 255)
vm.poke(rgbAddr + centerOffset * addrInc, smoothed.toByte())
}
}
private fun applyDWTSmoothing(rgbAddr: Long, width: Int, height: Int, addrInc: Long) {
// Apply very gentle smoothing to reduce DWT quantization artifacts
// Uses a 3x3 Gaussian-like kernel with low strength
val kernel = arrayOf(
arrayOf(1, 2, 1),
arrayOf(2, 4, 2),
arrayOf(1, 2, 1)
)
val kernelSum = 16
// Process inner pixels only to avoid boundary issues
for (y in 1 until height - 1) {
for (x in 1 until width - 1) {
for (channel in 0 until 3) {
var sum = 0
for (ky in -1..1) {
for (kx in -1..1) {
val pixelOffset = ((y + ky).toLong() * width + (x + kx)) * 3 + channel
val pixelValue = vm.peek(rgbAddr + pixelOffset * addrInc)?.toUint()?.toInt() ?: 0
sum += pixelValue * kernel[ky + 1][kx + 1]
}
}
val centerOffset = (y.toLong() * width + x) * 3 + channel
val originalValue = vm.peek(rgbAddr + centerOffset * addrInc)?.toUint()?.toInt() ?: 0
// Blend original with smoothed (low strength: 75% original, 25% smoothed)
val smoothedValue = sum / kernelSum
val blendedValue = ((originalValue * 3 + smoothedValue) / 4).coerceIn(0, 255)
vm.poke(rgbAddr + centerOffset * addrInc, blendedValue.toByte())
}
}
}
}
}

View File

@@ -203,19 +203,7 @@ typedef struct {
} tav_encoder_t;
// 5/3 Wavelet filter coefficients (reversible)
static const float WAVELET_5_3_LP[] = {0.5f, 1.0f, 0.5f};
static const float WAVELET_5_3_HP[] = {-0.125f, -0.25f, 0.75f, -0.25f, -0.125f};
// 9/7 Wavelet filter coefficients (irreversible - Daubechies)
static const float WAVELET_9_7_LP[] = {
0.037828455507f, -0.023849465020f, -0.110624404418f, 0.377402855613f,
0.852698679009f, 0.377402855613f, -0.110624404418f, -0.023849465020f, 0.037828455507f
};
static const float WAVELET_9_7_HP[] = {
0.064538882629f, -0.040689417609f, -0.418092273222f, 0.788485616406f,
-0.418092273222f, -0.040689417609f, 0.064538882629f
};
// Wavelet filter constants removed - using lifting scheme implementation instead
// Function prototypes
static void show_usage(const char *program_name);
@@ -223,15 +211,9 @@ static tav_encoder_t* create_encoder(void);
static void cleanup_encoder(tav_encoder_t *enc);
static int initialize_encoder(tav_encoder_t *enc);
static void rgb_to_ycocg(const uint8_t *rgb, float *y, float *co, float *cg, int width, int height);
static void dwt_2d_forward(float *tile_data, int levels, int filter_type);
static void dwt_2d_inverse(dwt_tile_t *tile, float *output, int filter_type);
static void quantize_subbands(dwt_tile_t *tile, int q_y, int q_co, int q_cg, float rcf);
static int estimate_motion_112x112(const float *current, const float *reference,
int width, int height, int tile_x, int tile_y,
motion_vector_t *mv);
static size_t compress_tile_data(tav_encoder_t *enc, const dwt_tile_t *tiles,
const motion_vector_t *mvs, int num_tiles,
uint8_t packet_type);
// Audio and subtitle processing prototypes (from TEV)
static int start_audio_conversion(tav_encoder_t *enc);
@@ -393,32 +375,6 @@ static void dwt_53_forward_1d(float *data, int length) {
free(temp);
}
static void dwt_53_inverse_1d(float *data, int length) {
if (length < 2) return;
float *temp = malloc(length * sizeof(float));
int half = (length + 1) / 2; // Handle odd lengths properly
// Inverse update step
for (int i = 0; i < half; i++) {
float update = 0.25f * ((i > 0 ? data[half + i - 1] : 0) +
(i < half - 1 ? data[half + i] : 0));
temp[2 * i] = data[i] - update;
}
// Inverse predict step
for (int i = 0; i < half; i++) {
int idx = 2 * i + 1;
if (idx < length) {
float pred = 0.5f * (temp[2 * i] + (2 * i + 2 < length ? temp[2 * i + 2] : temp[2 * i]));
temp[idx] = data[half + i] + pred;
}
}
// Copy back
memcpy(data, temp, length * sizeof(float));
free(temp);
}
// 1D DWT using lifting scheme for 9/7 irreversible filter
static void dwt_97_forward_1d(float *data, int length) {
@@ -574,59 +530,6 @@ static void dwt_2d_forward_padded(float *tile_data, int levels, int filter_type)
// 2D DWT forward transform for 112x112 tile
static void dwt_2d_forward(float *tile_data, int levels, int filter_type) {
const int size = TILE_SIZE;
float *temp_row = malloc(size * sizeof(float));
float *temp_col = malloc(size * sizeof(float));
for (int level = 0; level < levels; level++) {
int current_size = size >> level;
if (current_size < 1) break;
if (current_size == 1) {
// Level 6: 1x1 - single DC coefficient, no DWT needed
// The single coefficient is already in the correct position
continue;
}
// Row transform
for (int y = 0; y < current_size; y++) {
for (int x = 0; x < current_size; x++) {
temp_row[x] = tile_data[y * size + x];
}
if (filter_type == WAVELET_5_3_REVERSIBLE) {
dwt_53_forward_1d(temp_row, current_size);
} else {
dwt_97_forward_1d(temp_row, current_size);
}
for (int x = 0; x < current_size; x++) {
tile_data[y * size + x] = temp_row[x];
}
}
// Column transform
for (int x = 0; x < current_size; x++) {
for (int y = 0; y < current_size; y++) {
temp_col[y] = tile_data[y * size + x];
}
if (filter_type == WAVELET_5_3_REVERSIBLE) {
dwt_53_forward_1d(temp_col, current_size);
} else {
dwt_97_forward_1d(temp_col, current_size);
}
for (int y = 0; y < current_size; y++) {
tile_data[y * size + x] = temp_col[y];
}
}
}
free(temp_row);
free(temp_col);
}
// Quantization for DWT subbands with rate control
static void quantize_dwt_coefficients(float *coeffs, int16_t *quantized, int size, int quantizer, float rcf) {
@@ -1802,7 +1705,6 @@ int main(int argc, char *argv[]) {
printf("Starting encoding...\n");
// Main encoding loop - process frames until EOF or frame limit
int keyframe_interval = 30; // I-frame every 30 frames
int frame_count = 0;
int continue_encoding = 1;
@@ -1871,8 +1773,8 @@ int main(int argc, char *argv[]) {
// Frame parity: even frames (0,2,4...) = bottom fields, odd frames (1,3,5...) = top fields
}
// Determine frame type
int is_keyframe = 1;//(frame_count % keyframe_interval == 0);
// Determine frame type (all frames are keyframes in current implementation)
int is_keyframe = 1;
// Debug: check RGB input data
/*if (frame_count < 3) {