From ff622ec0d8e444b2146bc3e4baaae739efd672eb Mon Sep 17 00:00:00 2001 From: Yggdrasil75 Date: Fri, 14 Nov 2025 13:20:13 -0500 Subject: [PATCH] video compression and such --- tests/g2chromatic2.cpp | 70 ++++++++++++++++----------------------- util/output/aviwriter.hpp | 38 ++++++++++++--------- 2 files changed, 51 insertions(+), 57 deletions(-) diff --git a/tests/g2chromatic2.cpp b/tests/g2chromatic2.cpp index fb82c02..be1ccc7 100644 --- a/tests/g2chromatic2.cpp +++ b/tests/g2chromatic2.cpp @@ -10,6 +10,7 @@ #include "../util/output/bmpwriter.hpp" #include "../util/timing_decorator.cpp" #include "../util/output/frame.hpp" +#include "../util/output/video.hpp" struct AnimationConfig { int width = 1024; @@ -71,7 +72,6 @@ void expandPixel(Grid2& grid, AnimationConfig config, std::vector> newseeds; - std::unordered_set visitedThisFrame; for (const auto& seed : seeds) { visitedThisFrame.insert(std::get<0>(seed)); @@ -89,7 +89,6 @@ void expandPixel(Grid2& grid, AnimationConfig config, std::vector> frames, AnimationConfig config) { - TIME_FUNCTION; - std::string filename = "output/chromatic_transformation.avi"; - - std::cout << "Frame count: " << frames.size() << std::endl; - std::cout << "Frame size: " << (frames.empty() ? 0 : frames[0].size()) << std::endl; - std::cout << "Width: " << config.width << ", Height: " << config.height << std::endl; - - std::filesystem::path dir = "output"; - if (!std::filesystem::exists(dir)) { - if (!std::filesystem::create_directories(dir)) { - std::cout << "Failed to create output directory!" << std::endl; - return false; - } - } - - bool success = AVIWriter::saveAVI(filename, frames, config.width+1, config.height+1, config.fps); - - if (success) { - // Check if file actually exists - if (std::filesystem::exists(filename)) { - auto file_size = std::filesystem::file_size(filename); - } - } else { - std::cout << "Failed to save AVI file!" << std::endl; - } - - return success; -} - int main() { AnimationConfig config; Grid2 grid = setup(config); Preview(grid); std::vector> seeds = pickSeeds(grid,config); - std::vector frames; // Change to vector of frame objects + + // Create video object with BGR channels and configured FPS + video vid(config.width+1, config.height+1, {'B', 'G', 'R'}, config.fps, true); for (int i = 0; i < config.totalFrames; ++i){ std::cout << "Processing frame " << i + 1 << "/" << config.totalFrames << std::endl; expandPixel(grid,config,seeds); frame outputFrame; - grid.getGridAsFrame(outputFrame, {'B', 'G', 'R'}); // Directly get as BGR frame + grid.getGridAsFrame(outputFrame, {'B', 'G', 'R'}); - // Alternative: Use the dedicated BGR method - // int width, height; - // grid.getGridAsBGRFrame(width, height, outputFrame); + // Add frame to video (this will compress it using RLE + differential encoding) + vid.add_frame(outputFrame); - frames.push_back(outputFrame); + // Optional: Print compression stats every 50 frames + // if ((i + 1) % 50 == 0) { + // auto stats = vid.get_compression_stats(); + // std::cout << "Frame " << (i + 1) << " - Compression ratio: " << stats.overall_ratio + // << ", Total compressed: " << stats.total_compressed_bytes << " bytes" << std::endl; + // } } - // Use the frame-based AVIWriter overload - bool success = AVIWriter::saveAVI("output/chromatic_transformation.avi", frames, config.fps); + // Use the video-based AVIWriter overload + bool success = AVIWriter::saveAVI("output/chromatic_transformation.avi", vid, config.fps); if (success) { - std::cout << "Successfully saved AVI with " << frames.size() << " frames" << std::endl; + // Print final compression statistics + auto final_stats = vid.get_compression_stats(); + std::cout << "Successfully saved AVI with " << vid.frame_count() << " frames" << std::endl; + std::cout << "Final compression statistics:" << std::endl; + std::cout << " Total frames: " << final_stats.total_frames << std::endl; + std::cout << " Video duration: " << final_stats.video_duration << " seconds" << std::endl; + std::cout << " Uncompressed size: " << final_stats.total_uncompressed_bytes << " bytes" << std::endl; + std::cout << " Compressed size: " << final_stats.total_compressed_bytes << " bytes" << std::endl; + std::cout << " Overall compression ratio: " << final_stats.overall_ratio << std::endl; + std::cout << " Average frame compression ratio: " << final_stats.average_frame_ratio << std::endl; + + // Optional: Save compressed video data for later use + auto serialized_data = vid.serialize(); + std::cout << "Serialized video data size: " << serialized_data.size() << " bytes" << std::endl; } else { std::cout << "Failed to save AVI file!" << std::endl; } diff --git a/util/output/aviwriter.hpp b/util/output/aviwriter.hpp index 7295ffb..a469e57 100644 --- a/util/output/aviwriter.hpp +++ b/util/output/aviwriter.hpp @@ -178,6 +178,28 @@ private: } public: + // New method for video objects + static bool saveAVI(const std::string& filename, + const video& vid, + float fps = 0.0f) { + if (vid.empty()) { + return false; + } + + // Use video's FPS if not overridden, otherwise use provided FPS + float actualFps = (fps > 0.0f) ? fps : static_cast(vid.fps()); + + if (actualFps <= 0.0f) { + return false; + } + + // Get all frames from the video + std::vector frames = vid.get_all_frames(); + + // Use the existing frame-based implementation + return saveAVI(filename, frames, actualFps); + } + // Original method for vector of raw frame data static bool saveAVI(const std::string& filename, const std::vector>& frames, @@ -186,9 +208,6 @@ public: return false; } - // std::cout << "1" << "width: " << width << - // "height: " << height << "frame count: " << fps << std::endl; - // Validate frame sizes size_t expectedFrameSize = width * height * 3; for (const auto& frame : frames) { @@ -197,13 +216,11 @@ public: } } - // std::cout << "2" << std::endl; // Create directory if needed if (!createDirectoryIfNeeded(filename)) { return false; } - // std::cout << "3" << std::endl; std::ofstream file(filename, std::ios::binary); if (!file) { return false; @@ -217,7 +234,6 @@ public: uint32_t frameSize = rowSize * height; uint32_t totalDataSize = frameCount * frameSize; - // std::cout << "4" << std::endl; // RIFF AVI header RIFFChunk riffHeader; riffHeader.chunkId = 0x46464952; // 'RIFF' @@ -231,7 +247,6 @@ public: uint32_t hdrlListStart = static_cast(file.tellp()); writeList(file, 0x6C726468, nullptr, 0); // 'hdrl' - we'll fill size later - // std::cout << "5" << std::endl; // avih chunk AVIMainHeader mainHeader; mainHeader.microSecPerFrame = microSecPerFrame; @@ -251,7 +266,6 @@ public: writeChunk(file, 0x68697661, &mainHeader, sizeof(mainHeader)); // 'avih' - // std::cout << "6" << std::endl; // strl list uint32_t strlListStart = static_cast(file.tellp()); writeList(file, 0x6C727473, nullptr, 0); // 'strl' - we'll fill size later @@ -294,7 +308,6 @@ public: writeChunk(file, 0x66727473, &bitmapInfo, sizeof(bitmapInfo)); // 'strf' - // std::cout << "7" << std::endl; // Update strl list size uint32_t strlListEnd = static_cast(file.tellp()); file.seekp(strlListStart + 4); @@ -302,7 +315,6 @@ public: file.write(reinterpret_cast(&strlListSize), 4); file.seekp(strlListEnd); - // std::cout << "8" << std::endl; // Update hdrl list size uint32_t hdrlListEnd = static_cast(file.tellp()); file.seekp(hdrlListStart + 4); @@ -310,7 +322,6 @@ public: file.write(reinterpret_cast(&hdrlListSize), 4); file.seekp(hdrlListEnd); - // std::cout << "9" << std::endl; // movi list uint32_t moviListStart = static_cast(file.tellp()); writeList(file, 0x69766F6D, nullptr, 0); // 'movi' - we'll fill size later @@ -322,7 +333,6 @@ public: for (uint32_t i = 0; i < frameCount; ++i) { uint32_t frameStart = static_cast(file.tellp()) - moviListStart - 4; - // std::cout << "10-" << i << std::endl; // Create padded frame data (BMP-style bottom-to-top with padding) std::vector paddedFrame(frameSize, 0); const auto& frame = frames[i]; @@ -336,7 +346,6 @@ public: // Padding bytes remain zeros } - // std::cout << "11-" << i << std::endl; // Write frame as '00db' chunk writeChunk(file, 0x62643030, paddedFrame.data(), frameSize); // '00db' @@ -349,7 +358,6 @@ public: indexEntries.push_back(entry); } - // std::cout << "12" << std::endl; // Update movi list size uint32_t moviListEnd = static_cast(file.tellp()); file.seekp(moviListStart + 4); @@ -357,7 +365,6 @@ public: file.write(reinterpret_cast(&moviListSize), 4); file.seekp(moviListEnd); - // std::cout << "13" << std::endl; // idx1 chunk - index uint32_t idx1Size = static_cast(indexEntries.size() * sizeof(AVIIndexEntry)); writeChunk(file, 0x31786469, indexEntries.data(), idx1Size); // 'idx1' @@ -368,7 +375,6 @@ public: uint32_t riffSize = fileEnd - riffStartPos - 8; file.write(reinterpret_cast(&riffSize), 4); - // std::cout << "14" << std::endl; return true; }