diff --git a/assets/disk0/tvdos/bin/playtav.js b/assets/disk0/tvdos/bin/playtav.js index b085d18..174e6e7 100644 --- a/assets/disk0/tvdos/bin/playtav.js +++ b/assets/disk0/tvdos/bin/playtav.js @@ -553,7 +553,6 @@ let FRAME_TIME = 1.0 / header.fps let frameCount = 0 let trueFrameCount = 0 -let frameDuped = false let stopPlay = false let akku = FRAME_TIME let akku2 = 0.0 @@ -613,38 +612,29 @@ try { try { // serial.println(actualSize) - // Duplicate every 1000th frame if NTSC (same as TEV) - if (!isNTSC || frameCount % 1000 != 501 || frameDuped) { - frameDuped = false + let decodeStart = sys.nanoTime() - let decodeStart = sys.nanoTime() + // Call TAV hardware decoder (like TEV's tevDecode but with RGB buffer outputs) + graphics.tavDecode( + blockDataPtr, + CURRENT_RGB_ADDR, PREV_RGB_ADDR, // RGB buffer pointers (not float arrays!) + header.width, header.height, + header.qualityY, header.qualityCo, header.qualityCg, + frameCount, + debugMotionVectors, + header.waveletFilter, // TAV-specific parameter + header.decompLevels, // TAV-specific parameter + enableDeblocking, + isLossless, + header.version // TAV version for colour space detection + ) - // Call TAV hardware decoder (like TEV's tevDecode but with RGB buffer outputs) - graphics.tavDecode( - blockDataPtr, - CURRENT_RGB_ADDR, PREV_RGB_ADDR, // RGB buffer pointers (not float arrays!) - header.width, header.height, - header.qualityY, header.qualityCo, header.qualityCg, - frameCount, - debugMotionVectors, - header.waveletFilter, // TAV-specific parameter - header.decompLevels, // TAV-specific parameter - enableDeblocking, - isLossless, - header.version // TAV version for colour space detection - ) + decodeTime = (sys.nanoTime() - decodeStart) / 1000000.0 - decodeTime = (sys.nanoTime() - decodeStart) / 1000000.0 - - // Upload RGB buffer to display framebuffer (like TEV) - let uploadStart = sys.nanoTime() - graphics.uploadRGBToFramebuffer(CURRENT_RGB_ADDR, header.width, header.height, frameCount, true) - uploadTime = (sys.nanoTime() - uploadStart) / 1000000.0 - } else { - frameCount -= 1 - frameDuped = true - console.log(`Frame ${frameCount}: Duplicating previous frame`) - } + // Upload RGB buffer to display framebuffer (like TEV) + let uploadStart = sys.nanoTime() + graphics.uploadRGBToFramebuffer(CURRENT_RGB_ADDR, header.width, header.height, frameCount, true) + uploadTime = (sys.nanoTime() - uploadStart) / 1000000.0 // Defer audio playback until a first frame is sent if (isInterlaced) { diff --git a/terranmon.txt b/terranmon.txt index dd67b50..774fef0 100644 --- a/terranmon.txt +++ b/terranmon.txt @@ -793,6 +793,10 @@ The format is designed to be compatible with SubRip and SAMI (without markups). text argument may be terminated by 0x00 BEFORE the entire arguments being terminated by 0x00, leaving extra 0x00 on the byte stream. A decoder must be able to handle the extra zeros. +## NTSC Framerate handling +The encoder encodes the frames as-is. The decoder must duplicate every 1000th frame to keep the decoding +in-sync. + -------------------------------------------------------------------------------- TSVM Advanced Video (TAV) Format @@ -947,6 +951,10 @@ Reuses existing MP2 audio infrastructure from TEV/MOV formats for compatibility. ## Subtitle Support Uses same Simple Subtitle Format (SSF) as TEV for text overlay functionality. +## NTSC Framerate handling +Unlike the TEV format, TAV emits extra sync packet for every 1000th frames. Decoder can just play the video +without any special treatment. + -------------------------------------------------------------------------------- Sound Adapter diff --git a/video_encoder/encoder_tav.c b/video_encoder/encoder_tav.c index b3e5020..2d247fa 100644 --- a/video_encoder/encoder_tav.c +++ b/video_encoder/encoder_tav.c @@ -2089,6 +2089,12 @@ int main(int argc, char *argv[]) { uint8_t sync_packet = TAV_PACKET_SYNC; fwrite(&sync_packet, 1, 1, enc->output_fp); + // NTSC frame duplication: emit extra sync packet for every 1000n+500 frames + if (enc->is_ntsc_framerate && (frame_count % 1000 == 500)) { + fwrite(&sync_packet, 1, 1, enc->output_fp); + printf("Frame %d: NTSC duplication - extra sync packet emitted\n", frame_count); + } + if (is_keyframe) count_iframe++; else