framerip/main.cpp

84 lines
2.8 KiB
C++

/**
* video_frame_extractor
*
* Extracts every frame from a video file and writes them as raw TIFF images.
* Compiles on macOS, Linux, and Windows.
*
* Usage:
* video_frame_extractor <video_file> [output_dir]
*
* If output_dir is omitted, a unique temporary directory is created and its
* path is printed. If output_dir is provided it must already exist.
*
* Dependencies: FFmpeg (libavcodec, libavformat, libavutil, libswscale)
*
* Build:
* See CMakeLists.txt
*/
#include "frame_extractor.h"
#include "tiff_writer.h"
#include "platform_utils.h"
#include <iostream>
#include <string>
int main(int argc, char* argv[])
{
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <video_file> [output_dir]\n";
return 1;
}
const std::string inputPath = argv[1];
// Determine output directory: use the supplied path or create a temp dir.
std::string outputDir;
if (argc >= 3) {
outputDir = argv[2];
if (!platform::directoryExists(outputDir)) {
std::cerr << "{ \"error\" : \"Output directory does not exist: " << outputDir << "\" }\n";
return 1;
}
std::cout << "{ \"output\" : \"" << outputDir << "\" }\n";
} else {
if (!platform::createTempDirectory("vfe_frames_", outputDir)) {
std::cerr << "{ \"error\" : \"Failed to create temporary directory.\" }\n";
return 1;
}
std::cout << "{ \"output\" : \"" << outputDir << "\", \"temporary\" : true }\n";
}
// Open video
FrameExtractor extractor(inputPath);
if (!extractor.open()) {
std::cerr << "{ \"error\" : \"Failed to open video: " << inputPath << "\" }\n";
return 1;
}
std::cout << "{ \"video\" : \"" << inputPath << "\" }\n"
<< "{ \"duration\" : " << extractor.durationSeconds() << " }\n"
<< "{ \"framerate\" : " << extractor.framerate() << " } \n"
<< "{ \"resolution\" : { \"w\" :" << extractor.width() << ", \"h\" : " << extractor.height() << " } }\n"
<< "{ \"started\" : true, \"video\" : \"" << inputPath << "\" }\n";
TiffWriter writer(outputDir);
uint64_t frameCount = 0;
extractor.forEachFrame([&](const FrameData& frame) {
const std::string filename = writer.write(frame, frameCount);
if (filename.empty()) {
std::cerr << "{ \"warning\" : \"Failed to write frame " << frameCount << "\" }\n";
} else if (frameCount % 100 == 0) {
std::cout << "{ \"progress\" : " << frameCount
<< ", \"file\" : " << filename << "\" }\n";
}
++frameCount;
return true; // return false to stop early
});
std::cout << "{ \"completed\" : true, \"frames\" : " << frameCount << ", \"output\" : \""
<< outputDir << "\", \"video\" : \"" << inputPath << "\" }\n";
return 0;
}