TAV: two-pass GOP slicer

This commit is contained in:
minjaesong
2025-10-25 00:01:37 +09:00
parent 69583e5f1e
commit 52f25f7d04
2 changed files with 914 additions and 61 deletions

View File

@@ -482,11 +482,12 @@ function getVideoRate() {
let FRAME_TIME = 1.0 / header.fps let FRAME_TIME = 1.0 / header.fps
let frameCount = 0 let frameCount = 0
let trueFrameCount = 0 let trueFrameCount = 0
let stopPlay = false let stopPlay = false
let akku = FRAME_TIME let akku = FRAME_TIME
let akku2 = 0.0 let akku2 = 0.0
let firstFrameIssued = false // Track when first frame has been displayed
let nextFrameTime = 0 // Absolute time when next frame should display (nanoseconds) let nextFrameTime = 0 // Absolute time when next frame should display (nanoseconds)
let currentFileIndex = 1 // Track which file we're playing in concatenated stream let currentFileIndex = 1 // Track which file we're playing in concatenated stream
let totalFilesProcessed = 0 let totalFilesProcessed = 0
@@ -825,6 +826,7 @@ try {
frameCount = 0 frameCount = 0
akku = FRAME_TIME akku = FRAME_TIME
akku2 = 0.0 akku2 = 0.0
firstFrameIssued = false
audio.purgeQueue(0) audio.purgeQueue(0)
if (paused) { if (paused) {
audio.play(0) audio.play(0)
@@ -844,6 +846,7 @@ try {
frameCount = 0 frameCount = 0
akku = FRAME_TIME akku = FRAME_TIME
akku2 = 0.0 akku2 = 0.0
firstFrameIssued = false
audio.purgeQueue(0) audio.purgeQueue(0)
if (paused) { if (paused) {
audio.play(0) audio.play(0)
@@ -863,6 +866,7 @@ try {
frameCount = seekTarget.frameNum frameCount = seekTarget.frameNum
akku = FRAME_TIME akku = FRAME_TIME
akku2 -= 5.5 akku2 -= 5.5
firstFrameIssued = false
audio.purgeQueue(0) audio.purgeQueue(0)
if (paused) { if (paused) {
audio.play(0) audio.play(0)
@@ -890,6 +894,7 @@ try {
frameCount = seekTarget.frameNum frameCount = seekTarget.frameNum
akku = FRAME_TIME akku = FRAME_TIME
akku2 += 5.0 akku2 += 5.0
firstFrameIssued = false
audio.purgeQueue(0) audio.purgeQueue(0)
if (paused) { if (paused) {
audio.play(0) audio.play(0)
@@ -925,6 +930,7 @@ try {
frameCount = 0 frameCount = 0
akku = 0.0 akku = 0.0
akku2 = 0.0 akku2 = 0.0
firstFrameIssued = false
FRAME_TIME = 1.0 / header.fps FRAME_TIME = 1.0 / header.fps
audio.purgeQueue(0) audio.purgeQueue(0)
currentFileIndex++ currentFileIndex++
@@ -952,19 +958,16 @@ try {
} }
if (packetType === TAV_PACKET_SYNC || packetType == TAV_PACKET_SYNC_NTSC) { if (packetType === TAV_PACKET_SYNC || packetType == TAV_PACKET_SYNC_NTSC) {
// Sync packet - no additional data (for I/P frames, not GOPs) // SYNC packets are vestigial in TAV's time-based playback model
akku -= FRAME_TIME // (legacy from TEV's synchronous display model)
if (packetType == TAV_PACKET_SYNC) { //
frameCount++ // Frame display timing is controlled by nextFrameTime, not SYNC packets:
} // - I/P frames: Display logic at line 1553-1597
// - GOP frames: Display logic at line 1600-1684
trueFrameCount++ //
// NTSC sync (frame duplication): Handled automatically by audio queue timing
// Swap ping-pong buffers //
let temp = CURRENT_RGB_ADDR // Do nothing - skip to next packet
CURRENT_RGB_ADDR = PREV_RGB_ADDR
PREV_RGB_ADDR = temp
} }
else if (packetType === TAV_PACKET_IFRAME || packetType === TAV_PACKET_PFRAME) { else if (packetType === TAV_PACKET_IFRAME || packetType === TAV_PACKET_PFRAME) {
// Record I-frame position for seeking // Record I-frame position for seeking
@@ -1072,7 +1075,7 @@ try {
const gopSize = seqread.readOneByte() const gopSize = seqread.readOneByte()
const compressedSize = seqread.readInt() const compressedSize = seqread.readInt()
let compressedPtr = seqread.readBytes(compressedSize) let compressedPtr = seqread.readBytes(compressedSize)
updateDataRateBin(compressedSize) updateDataRateBin(compressedSize / gopSize)
// TRIPLE-BUFFERING LOGIC (3 slots: playing, ready, decoding): // TRIPLE-BUFFERING LOGIC (3 slots: playing, ready, decoding):
// - If no GOP playing: decode first GOP to slot 0 // - If no GOP playing: decode first GOP to slot 0
@@ -1456,7 +1459,7 @@ try {
} // end of !paused packet read block } // end of !paused packet read block
let t2 = sys.nanoTime() let t2 = sys.nanoTime()
if (!paused) { if (!paused && firstFrameIssued) {
// Only accumulate time if we have a GOP to play // Only accumulate time if we have a GOP to play
// Don't accumulate during first GOP decode or we'll get fast playback // Don't accumulate during first GOP decode or we'll get fast playback
if (currentGopSize > 0) { if (currentGopSize > 0) {
@@ -1484,8 +1487,12 @@ try {
currentGopBufferSlot = asyncDecodeSlot currentGopBufferSlot = asyncDecodeSlot
asyncDecodeInProgress = false asyncDecodeInProgress = false
// Set first frame time to NOW // Initialize timing ONLY if this is the very first frame of the video
nextFrameTime = sys.nanoTime() // If we're transitioning from I-frames, preserve timing continuity
if (nextFrameTime === 0) {
nextFrameTime = sys.nanoTime()
}
// Otherwise keep existing nextFrameTime from previous I-frame/GOP
// Resume packet reading only if not all 3 buffers are full // Resume packet reading only if not all 3 buffers are full
// (might have buffered GOP 2 and 3 during GOP 1 decode) // (might have buffered GOP 2 and 3 during GOP 1 decode)
@@ -1577,6 +1584,11 @@ try {
audioFired = true audioFired = true
} }
// Mark first frame as issued (starts akku/akku2 timers)
if (!firstFrameIssued) {
firstFrameIssued = true
}
frameCount++ frameCount++
trueFrameCount++ trueFrameCount++
iframeReady = false iframeReady = false
@@ -1586,7 +1598,7 @@ try {
CURRENT_RGB_ADDR = PREV_RGB_ADDR CURRENT_RGB_ADDR = PREV_RGB_ADDR
PREV_RGB_ADDR = temp PREV_RGB_ADDR = temp
// Schedule next frame // Schedule next frame (advance AFTER display, consistent with GOP timing)
nextFrameTime += (frametime) // frametime is in nanoseconds from header nextFrameTime += (frametime) // frametime is in nanoseconds from header
// Log performance data every 60 frames // Log performance data every 60 frames
@@ -1628,6 +1640,11 @@ try {
audioFired = true audioFired = true
} }
// Mark first frame as issued (starts akku/akku2 timers)
if (!firstFrameIssued) {
firstFrameIssued = true
}
currentGopFrameIndex++ currentGopFrameIndex++
frameCount++ frameCount++
trueFrameCount++ trueFrameCount++
@@ -1836,7 +1853,7 @@ try {
con.color_pair(253, 0) con.color_pair(253, 0)
let guiStatus = { let guiStatus = {
fps: header.fps, fps: header.fps,
videoRate: getVideoRate(), videoRate: getVideoRate().toFixed(0),
frameCount: frameCount, frameCount: frameCount,
totalFrames: header.totalFrames, totalFrames: header.totalFrames,
frameMode: decoderDbgInfo.frameMode, frameMode: decoderDbgInfo.frameMode,

File diff suppressed because it is too large Load Diff