mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-13 08:04:03 +09:00
TAV decoder: GOP decoding, GOP grain synthesis
This commit is contained in:
@@ -14,6 +14,7 @@ import net.torvald.tsvm.peripheral.PeriBase
|
|||||||
import net.torvald.tsvm.peripheral.fmod
|
import net.torvald.tsvm.peripheral.fmod
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import kotlin.Any
|
import kotlin.Any
|
||||||
import kotlin.Array
|
import kotlin.Array
|
||||||
import kotlin.Boolean
|
import kotlin.Boolean
|
||||||
@@ -5078,9 +5079,7 @@ class GraphicsJSR223Delegate(private val vm: VM) {
|
|||||||
// Remove grain synthesis from DWT coefficients (decoder subtracts noise)
|
// Remove grain synthesis from DWT coefficients (decoder subtracts noise)
|
||||||
// This must be called AFTER dequantization but BEFORE inverse DWT
|
// This must be called AFTER dequantization but BEFORE inverse DWT
|
||||||
private fun removeGrainSynthesisDecoder(coeffs: FloatArray, width: Int, height: Int,
|
private fun removeGrainSynthesisDecoder(coeffs: FloatArray, width: Int, height: Int,
|
||||||
decompLevels: Int, frameNum: Int, quantiser: Float,
|
frameNum: Int, subbands: List<DWTSubbandInfo>, qYGlobal: Int) {
|
||||||
subbands: List<DWTSubbandInfo>, qIndex: Int = 3, qYGlobal: Int = 0,
|
|
||||||
usePerceptualWeights: Boolean = false) {
|
|
||||||
// Only apply to Y channel, excluding LL band
|
// Only apply to Y channel, excluding LL band
|
||||||
// Noise amplitude = half of quantization step (scaled by perceptual weight if enabled)
|
// Noise amplitude = half of quantization step (scaled by perceptual weight if enabled)
|
||||||
|
|
||||||
@@ -5096,8 +5095,7 @@ class GraphicsJSR223Delegate(private val vm: VM) {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
// Noise amplitude for this subband
|
// Noise amplitude for this subband
|
||||||
// val noiseAmplitude = quantiser.coerceAtMost(32f) * 0.5f
|
val noiseAmplitude = qYGlobal.coerceAtMost(32) * 0.8f // using qYGlobal because quantiser is variable on bitrate-control mode and varying grain amp annoys viewer
|
||||||
val noiseAmplitude = qYGlobal.coerceAtMost(32) * 0.5f // using qYGlobal because quantiser is variable on bitrate-control mode and varying grain amp annoys viewer
|
|
||||||
|
|
||||||
// Remove noise from each coefficient in this subband
|
// Remove noise from each coefficient in this subband
|
||||||
for (i in 0 until subband.coeffCount) {
|
for (i in 0 until subband.coeffCount) {
|
||||||
@@ -5354,7 +5352,7 @@ class GraphicsJSR223Delegate(private val vm: VM) {
|
|||||||
|
|
||||||
// Remove grain synthesis from Y channel (must happen after dequantization, before inverse DWT)
|
// Remove grain synthesis from Y channel (must happen after dequantization, before inverse DWT)
|
||||||
// Use perceptual weights since this is the perceptual quantization path
|
// Use perceptual weights since this is the perceptual quantization path
|
||||||
removeGrainSynthesisDecoder(yTile, tileWidth, tileHeight, decompLevels, frameCount, qY.toFloat(), subbands, qIndex, qYGlobal, true)
|
removeGrainSynthesisDecoder(yTile, tileWidth, tileHeight, frameCount, subbands, qYGlobal)
|
||||||
|
|
||||||
// Apply film grain filter if enabled
|
// Apply film grain filter if enabled
|
||||||
// commented; grain synthesis is now a part of the spec
|
// commented; grain synthesis is now a part of the spec
|
||||||
@@ -5379,7 +5377,7 @@ class GraphicsJSR223Delegate(private val vm: VM) {
|
|||||||
val tileWidth = if (isMonoblock) width else TAV_PADDED_TILE_SIZE_X
|
val tileWidth = if (isMonoblock) width else TAV_PADDED_TILE_SIZE_X
|
||||||
val tileHeight = if (isMonoblock) height else TAV_PADDED_TILE_SIZE_Y
|
val tileHeight = if (isMonoblock) height else TAV_PADDED_TILE_SIZE_Y
|
||||||
val subbands = calculateSubbandLayout(tileWidth, tileHeight, decompLevels)
|
val subbands = calculateSubbandLayout(tileWidth, tileHeight, decompLevels)
|
||||||
removeGrainSynthesisDecoder(yTile, tileWidth, tileHeight, decompLevels, frameCount, qY.toFloat(), subbands)
|
removeGrainSynthesisDecoder(yTile, tileWidth, tileHeight, frameCount, subbands, qYGlobal)
|
||||||
|
|
||||||
// Apply film grain filter if enabled
|
// Apply film grain filter if enabled
|
||||||
// commented; grain synthesis is now a part of the spec
|
// commented; grain synthesis is now a part of the spec
|
||||||
@@ -5830,18 +5828,7 @@ class GraphicsJSR223Delegate(private val vm: VM) {
|
|||||||
// Remove grain synthesis from Y channel (must happen after dequantization, before inverse DWT)
|
// Remove grain synthesis from Y channel (must happen after dequantization, before inverse DWT)
|
||||||
val subbands = calculateSubbandLayout(tileWidth, tileHeight, decompLevels)
|
val subbands = calculateSubbandLayout(tileWidth, tileHeight, decompLevels)
|
||||||
// Delta frames use uniform quantization for the deltas themselves, so no perceptual weights
|
// Delta frames use uniform quantization for the deltas themselves, so no perceptual weights
|
||||||
removeGrainSynthesisDecoder(currentY, tileWidth, tileHeight, decompLevels, frameCount, qY.toFloat(), subbands)
|
removeGrainSynthesisDecoder(currentY, tileWidth, tileHeight, frameCount, subbands, qY)
|
||||||
|
|
||||||
// Apply film grain filter if enabled
|
|
||||||
// commented; grain synthesis is now a part of the spec
|
|
||||||
/*if (filmGrainLevel > 0) {
|
|
||||||
val random = java.util.Random()
|
|
||||||
for (i in 0 until coeffCount) {
|
|
||||||
currentY[i] += (random.nextInt(filmGrainLevel * 2 + 1) - filmGrainLevel).toFloat()
|
|
||||||
// currentCo[i] += (random.nextInt(filmGrainLevel * 2 + 1) - filmGrainLevel).toFloat()
|
|
||||||
// currentCg[i] += (random.nextInt(filmGrainLevel * 2 + 1) - filmGrainLevel).toFloat()
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Store current coefficients as previous for next frame
|
// Store current coefficients as previous for next frame
|
||||||
tavPreviousCoeffsY!![tileIdx] = currentY.clone()
|
tavPreviousCoeffsY!![tileIdx] = currentY.clone()
|
||||||
@@ -6401,6 +6388,8 @@ class GraphicsJSR223Delegate(private val vm: VM) {
|
|||||||
System.arraycopy(output, 0, frameData, 0, frameData.size)
|
System.arraycopy(output, 0, frameData, 0, frameData.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val rngFrameTick = AtomicInteger(0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode GOP frames directly into GraphicsAdapter.videoBuffer (Java heap).
|
* Decode GOP frames directly into GraphicsAdapter.videoBuffer (Java heap).
|
||||||
* This avoids allocating GOP frames in VM user memory, saving ~6 MB for 8-frame GOPs.
|
* This avoids allocating GOP frames in VM user memory, saving ~6 MB for 8-frame GOPs.
|
||||||
@@ -6522,6 +6511,16 @@ class GraphicsJSR223Delegate(private val vm: VM) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Step 5.5: Remove grain synthesis from Y channel for each GOP frame
|
||||||
|
// This must happen after dequantization but before inverse DWT
|
||||||
|
for (t in 0 until gopSize) {
|
||||||
|
removeGrainSynthesisDecoder(
|
||||||
|
gopY[t], width, height,
|
||||||
|
rngFrameTick.getAndAdd(1) + t,
|
||||||
|
subbands, qIndex
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Step 6: Apply inverse 3D DWT
|
// Step 6: Apply inverse 3D DWT
|
||||||
tavApplyInverse3DDWT(gopY, width, height, gopSize, spatialLevels, temporalLevels, spatialFilter)
|
tavApplyInverse3DDWT(gopY, width, height, gopSize, spatialLevels, temporalLevels, spatialFilter)
|
||||||
tavApplyInverse3DDWT(gopCo, width, height, gopSize, spatialLevels, temporalLevels, spatialFilter)
|
tavApplyInverse3DDWT(gopCo, width, height, gopSize, spatialLevels, temporalLevels, spatialFilter)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user