diff --git a/assets/disk0/tvdos/bin/playtav.js b/assets/disk0/tvdos/bin/playtav.js index d52b85d..d160e73 100644 --- a/assets/disk0/tvdos/bin/playtav.js +++ b/assets/disk0/tvdos/bin/playtav.js @@ -562,13 +562,117 @@ let trueFrameCount = 0 let stopPlay = false let akku = FRAME_TIME let akku2 = 0.0 +let currentFileIndex = 1 // Track which file we're playing in concatenated stream let blockDataPtr = sys.malloc(2377744) -// Playback loop - properly adapted from TEV +// Function to try reading next TAV file header at current position +function tryReadNextTAVHeader() { + // Save current position + let currentPos = seqread.getReadCount() + + // Try to read magic number + let newMagic = new Array(8) + try { + for (let i = 0; i < 8; i++) { + newMagic[i] = seqread.readOneByte() + } + + // compensating the old encoder emitting extra sync packets + while (newMagic[0] == 255) { + newMagic.shift(); newMagic[7] = seqread.readOneByte() + } + + // Check if it matches TAV magic + let isValidTAV = true + for (let i = 0; i < 8; i++) { + if (newMagic[i] !== TAV_MAGIC[i]) { + isValidTAV = false + serial.printerr("Header mismatch: got "+newMagic.join()) + break + } + } + + if (isValidTAV) { + // Read the rest of the header + let newHeader = { + magic: newMagic, + version: seqread.readOneByte(), + width: seqread.readShort(), + height: seqread.readShort(), + fps: seqread.readOneByte(), + totalFrames: seqread.readInt(), + waveletFilter: seqread.readOneByte(), + decompLevels: seqread.readOneByte(), + qualityY: seqread.readOneByte(), + qualityCo: seqread.readOneByte(), + qualityCg: seqread.readOneByte(), + extraFlags: seqread.readOneByte(), + videoFlags: seqread.readOneByte(), + reserved: new Array(7) + } + + // Skip reserved bytes + for (let i = 0; i < 7; i++) { + seqread.readOneByte() + } + + return newHeader + } + } catch (e) { + serial.printerr(e) + // EOF or read error - restore position and return null + // Note: seqread doesn't have seek, so we can't restore position + // This is okay since we're at EOF anyway + } + + return null +} + +// Playback loop - properly adapted from TEV with multi-file support try { let t1 = sys.nanoTime() - while (!stopPlay && seqread.getReadCount() < FILE_LENGTH && (header.totalFrames == 0 || header.totalFrames > 0 && frameCount < header.totalFrames)) { + let totalFilesProcessed = 0 + + while (!stopPlay && seqread.getReadCount() < FILE_LENGTH) { + // Check if we've finished the current file + if (header.totalFrames > 0 && frameCount >= header.totalFrames) { + console.log(`Completed file ${currentFileIndex}: ${frameCount} frames`) + + // Try to read next TAV file header + let nextHeader = tryReadNextTAVHeader() + if (nextHeader) { + // Found another TAV file - update header and reset counters + header = nextHeader + frameCount = 0 + currentFileIndex++ + totalFilesProcessed++ + + console.log(`\nStarting file ${currentFileIndex}:`) + console.log(`Resolution: ${header.width}x${header.height}`) + console.log(`FPS: ${header.fps}`) + console.log(`Total frames: ${header.totalFrames}`) + console.log(`Wavelet filter: ${header.waveletFilter === WAVELET_5_3_REVERSIBLE ? "5/3 reversible" : "9/7 irreversible"}`) + console.log(`Quality: Y=${header.qualityY}, Co=${header.qualityCo}, Cg=${header.qualityCg}`) + + // Reset motion vectors for new file + for (let i = 0; i < numTiles; i++) { + motionVectors[i] = { mvX: 0, mvY: 0, rcf: 1.0 } + } + + // Continue with new file + continue + } else { + // No more TAV files found + console.log(`\nNo more TAV files found. Total files processed: ${currentFileIndex}`) + break + } + } + + // Original playback loop condition (but without totalFrames check since we handle it above) + if (seqread.getReadCount() >= FILE_LENGTH) { + break + } // Handle interactive controls if (interactive) { @@ -713,7 +817,11 @@ try { if (!hasSubtitles) { con.move(31, 1) con.color_pair(253, 0) - print(`Frame: ${frameCount}/${header.totalFrames} (${((frameCount / akku2 * 100)|0) / 100}f) `) + if (currentFileIndex > 1) { + print(`File ${currentFileIndex}: ${frameCount}/${header.totalFrames} (${((frameCount / akku2 * 100)|0) / 100}f) `) + } else { + print(`Frame: ${frameCount}/${header.totalFrames} (${((frameCount / akku2 * 100)|0) / 100}f) `) + } con.move(32, 1) con.color_pair(253, 0) print(`VRate: ${(getVideoRate() / 1024 * 8)|0} kbps `) @@ -738,7 +846,11 @@ finally { con.clear() if (errorlevel === 0) { - console.log(`Playback completed: ${frameCount} frames`) + if (currentFileIndex > 1) { + console.log(`Playback completed: ${currentFileIndex} files processed`) + } else { + console.log(`Playback completed: ${frameCount} frames`) + } } else { console.log(`Playback failed with error ${errorlevel}`) } diff --git a/terranmon.txt b/terranmon.txt index 47d1080..9fa80d7 100644 --- a/terranmon.txt +++ b/terranmon.txt @@ -971,12 +971,17 @@ A universal, simle cue designed to work as both playlist to cue up external file uint8 Magic[8]: "\x1F TSVM UCF" uint8 Version: 1 uint16 Number of cue elements - unit8 Reserved[5] + uint32 (Optional) Size of the cue file, useful for allocating fixed length for future expansion; 0 when not used + unit8 Reserved ## Cue Element - uint8 Addressing Mode + uint8 Addressing Mode (low nybble) and Role Flags (high nybble) - 0x01: External - 0x02: Internal + - 0x10: Intended for machine interaction (GOP indices, frame indices, etc.) + - 0x20: Intended for human interaction (playlist, chapter markers, etc.) + - 0x30: Intended for both machine and human interaction + Role flags must be unset to assign no roles uint16 String Length for name * Name of the element in UTF-8 diff --git a/video_encoder/encoder_tav.c b/video_encoder/encoder_tav.c index 93a3a39..74b9b13 100644 --- a/video_encoder/encoder_tav.c +++ b/video_encoder/encoder_tav.c @@ -2940,10 +2940,6 @@ int main(int argc, char *argv[]) { // Update actual frame count in encoder struct enc->total_frames = frame_count; - // Write final sync packet - uint8_t sync_packet = TAV_PACKET_SYNC; - fwrite(&sync_packet, 1, 1, enc->output_fp); - // Update header with actual frame count (seek back to header position) if (enc->output_fp != stdout) { long current_pos = ftell(enc->output_fp); diff --git a/video_encoder/encoder_tev.c b/video_encoder/encoder_tev.c index dfff49f..2b88eef 100644 --- a/video_encoder/encoder_tev.c +++ b/video_encoder/encoder_tev.c @@ -2994,11 +2994,6 @@ int main(int argc, char *argv[]) { // Update actual frame count in encoder struct enc->total_frames = frame_count; - - // Write final sync packet - uint8_t sync_packet = TEV_PACKET_SYNC; - fwrite(&sync_packet, 1, 1, output); - sync_packet_count++; // Update header with actual frame count (seek back to header position) if (!enc->output_to_stdout) {