diff --git a/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt b/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt index e145c19..3217116 100644 --- a/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt @@ -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, quantTable: IntArray, qScale: Int, rateControlFactors: FloatArray, - blocksX: Int, blocksY: Int, - kLinearGradient: IntArray, kAlphaSqrt2: IntArray, kHalfSqrt2: Int - ): Array { - 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(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, 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()) - } - } - } - } - } \ No newline at end of file diff --git a/video_encoder/encoder_tav.c b/video_encoder/encoder_tav.c index 9149f5f..4739360 100644 --- a/video_encoder/encoder_tav.c +++ b/video_encoder/encoder_tav.c @@ -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) {