mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-10 06:54:04 +09:00
tav: ictcp decoding fix
This commit is contained in:
@@ -657,6 +657,8 @@ try {
|
|||||||
akku: akku2,
|
akku: akku2,
|
||||||
fileName: fullFilePathStr,
|
fileName: fullFilePathStr,
|
||||||
fileOrd: currentFileIndex,
|
fileOrd: currentFileIndex,
|
||||||
|
resolution: `${header.width}x${header.height}`,
|
||||||
|
colourSpace: header.version % 2 == 0 ? "ICtCp" : "YCoCg",
|
||||||
currentStatus: 1
|
currentStatus: 1
|
||||||
}
|
}
|
||||||
gui.printBottomBar(guiStatus)
|
gui.printBottomBar(guiStatus)
|
||||||
|
|||||||
@@ -74,18 +74,17 @@ let notifHideTimer = 0
|
|||||||
const NOTIF_SHOWUPTIME = 3000000000
|
const NOTIF_SHOWUPTIME = 3000000000
|
||||||
let [cy, cx] = con.getyx()
|
let [cy, cx] = con.getyx()
|
||||||
|
|
||||||
let seqreadserial = require("seqread")
|
let gui = require("playgui")
|
||||||
let seqreadtape = require("seqreadtape")
|
|
||||||
let seqread = undefined
|
let seqread = undefined
|
||||||
let fullFilePathStr = fullFilePath.full
|
let fullFilePathStr = fullFilePath.full
|
||||||
|
|
||||||
// Select seqread driver to use
|
// Select seqread driver to use
|
||||||
if (fullFilePathStr.startsWith('$:/TAPE') || fullFilePathStr.startsWith('$:\\TAPE')) {
|
if (fullFilePathStr.startsWith('$:/TAPE') || fullFilePathStr.startsWith('$:\\TAPE')) {
|
||||||
seqread = seqreadtape
|
seqread = require("seqreadtape")
|
||||||
seqread.prepare(fullFilePathStr)
|
seqread.prepare(fullFilePathStr)
|
||||||
seqread.seek(0)
|
seqread.seek(0)
|
||||||
} else {
|
} else {
|
||||||
seqread = seqreadserial
|
seqread = require("seqread")
|
||||||
seqread.prepare(fullFilePathStr)
|
seqread.prepare(fullFilePathStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -746,20 +745,29 @@ try {
|
|||||||
if (interactive) {
|
if (interactive) {
|
||||||
notifHideTimer += (t2 - t1)
|
notifHideTimer += (t2 - t1)
|
||||||
if (!notifHidden && notifHideTimer > (NOTIF_SHOWUPTIME + FRAME_TIME)) {
|
if (!notifHidden && notifHideTimer > (NOTIF_SHOWUPTIME + FRAME_TIME)) {
|
||||||
con.move(1, 1)
|
// clearing function here
|
||||||
print(' '.repeat(79))
|
|
||||||
notifHidden = true
|
notifHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasSubtitle) {
|
|
||||||
con.move(31, 1)
|
con.color_pair(253, 0)
|
||||||
con.color_pair(253, 0)
|
let guiStatus = {
|
||||||
print(`Frame: ${frameCount}/${totalFrames} (${((frameCount / akku2 * 100)|0) / 100}f) `)
|
fps: fps,
|
||||||
con.move(32, 1)
|
videoRate: getVideoRate(),
|
||||||
con.color_pair(253, 0)
|
frameCount: frameCount,
|
||||||
print(`VRate: ${(getVideoRate() / 1024 * 8)|0} kbps `)
|
totalFrames: totalFrames,
|
||||||
con.move(1, 1)
|
qY: qualityY,
|
||||||
|
qCo: qualityCo,
|
||||||
|
qCg: qualityCg,
|
||||||
|
akku: akku2,
|
||||||
|
fileName: fullFilePathStr,
|
||||||
|
fileOrd: 1,
|
||||||
|
resolution: `${width}x${height}${(isInterlaced) ? 'i' : ''}`,
|
||||||
|
colourSpace: colorSpace,
|
||||||
|
currentStatus: 1
|
||||||
}
|
}
|
||||||
|
gui.printBottomBar(guiStatus)
|
||||||
|
gui.printTopBar(guiStatus, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
t1 = t2
|
t1 = t2
|
||||||
|
|||||||
@@ -218,7 +218,9 @@ status = {
|
|||||||
akku: float,
|
akku: float,
|
||||||
fileName: String,
|
fileName: String,
|
||||||
fileOrd: int,
|
fileOrd: int,
|
||||||
currentStatus: int (0: stop/init, 1: play, 2: pause)
|
currentStatus: int (0: stop/init, 1: play, 2: pause),
|
||||||
|
resolution: string,
|
||||||
|
colourSpace: string
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
@@ -258,8 +260,10 @@ function printTopBar(status, moreInfo) {
|
|||||||
let sF = `F ${(''+status.frameCount).padStart((''+status.totalFrames).length, ' ')}/${status.totalFrames}`
|
let sF = `F ${(''+status.frameCount).padStart((''+status.totalFrames).length, ' ')}/${status.totalFrames}`
|
||||||
let sQ = `Q${(''+status.qY).padStart(4,' ')},${(''+status.qCo).padStart(2,' ')},${(''+status.qCg).padStart(2,' ')}`
|
let sQ = `Q${(''+status.qY).padStart(4,' ')},${(''+status.qCo).padStart(2,' ')},${(''+status.qCg).padStart(2,' ')}`
|
||||||
let sFPS = `${(status.frameCount / status.akku).toFixed(2)}f`
|
let sFPS = `${(status.frameCount / status.akku).toFixed(2)}f`
|
||||||
|
let sRes = `${status.resolution}`
|
||||||
|
let sCol = `${status.colourSpace}`
|
||||||
|
|
||||||
let sLeft = sF + BAR + sQ + BAR + sFPS + BAR
|
let sLeft = sF + BAR + sQ + BAR + sFPS + BAR + sRes + BAR + sCol + BAR
|
||||||
let filenameSpace = 80 - sLeft.length
|
let filenameSpace = 80 - sLeft.length
|
||||||
if (filename.length > filenameSpace) {
|
if (filename.length > filenameSpace) {
|
||||||
filename = filename.slice(0, filenameSpace - 1) + '~'
|
filename = filename.slice(0, filenameSpace - 1) + '~'
|
||||||
|
|||||||
@@ -4965,24 +4965,34 @@ class GraphicsJSR223Delegate(private val vm: VM) {
|
|||||||
for (x in 0 until width) {
|
for (x in 0 until width) {
|
||||||
val idx = y * width + x
|
val idx = y * width + x
|
||||||
|
|
||||||
// ICtCp to RGB conversion (BT.2100 -> sRGB)
|
// ICtCp to sRGB conversion (adapted from encoder ICtCp functions)
|
||||||
val I = iData[idx]
|
val I = iData[idx].toDouble() / 255.0
|
||||||
val Ct = ctData[idx]
|
val Ct = (ctData[idx].toDouble() - 127.5) / 255.0
|
||||||
val Cp = cpData[idx]
|
val Cp = (cpData[idx].toDouble() - 127.5) / 255.0
|
||||||
|
|
||||||
// ICtCp to LMS
|
// ICtCp -> L'M'S' (inverse matrix)
|
||||||
val L = I + 0.00975f * Ct + 0.20524f * Cp
|
val Lp = I + 0.015718580108730416 * Ct + 0.2095810681164055 * Cp
|
||||||
val M = I - 0.11387f * Ct + 0.13321f * Cp
|
val Mp = I - 0.015718580108730416 * Ct - 0.20958106811640548 * Cp
|
||||||
val S = I + 0.03259f * Ct - 0.67851f * Cp
|
val Sp = I + 1.0212710798422344 * Ct - 0.6052744909924316 * Cp
|
||||||
|
|
||||||
// LMS to RGB (simplified conversion)
|
// HLG decode: L'M'S' -> linear LMS
|
||||||
val r = 3.2406f * L - 1.5372f * M - 0.4986f * S
|
val L = HLG_EOTF(Lp)
|
||||||
val g = -0.9689f * L + 1.8758f * M + 0.0415f * S
|
val M = HLG_EOTF(Mp)
|
||||||
val b = 0.0557f * L - 0.2040f * M + 1.0570f * S
|
val S = HLG_EOTF(Sp)
|
||||||
|
|
||||||
rowRgbBuffer[bufferIdx++] = (r * 255f).toInt().coerceIn(0, 255).toByte()
|
// LMS -> linear sRGB (inverse matrix)
|
||||||
rowRgbBuffer[bufferIdx++] = (g * 255f).toInt().coerceIn(0, 255).toByte()
|
val rLin = 6.1723815689243215 * L -5.319534979827695 * M + 0.14699442094633924 * S
|
||||||
rowRgbBuffer[bufferIdx++] = (b * 255f).toInt().coerceIn(0, 255).toByte()
|
val gLin = -1.3243428148026244 * L + 2.560286104841917 * M -0.2359203727576164 * S
|
||||||
|
val bLin = -0.011819739235953752 * L -0.26473549971186555 * M + 1.2767952602537955 * S
|
||||||
|
|
||||||
|
// Gamma encode to sRGB
|
||||||
|
val rSrgb = srgbUnlinearise(rLin)
|
||||||
|
val gSrgb = srgbUnlinearise(gLin)
|
||||||
|
val bSrgb = srgbUnlinearise(bLin)
|
||||||
|
|
||||||
|
rowRgbBuffer[bufferIdx++] = (rSrgb * 255.0).toInt().coerceIn(0, 255).toByte()
|
||||||
|
rowRgbBuffer[bufferIdx++] = (gSrgb * 255.0).toInt().coerceIn(0, 255).toByte()
|
||||||
|
rowRgbBuffer[bufferIdx++] = (bSrgb * 255.0).toInt().coerceIn(0, 255).toByte()
|
||||||
}
|
}
|
||||||
|
|
||||||
// OPTIMISATION: Bulk copy entire row at once
|
// OPTIMISATION: Bulk copy entire row at once
|
||||||
|
|||||||
Reference in New Issue
Block a user