84 lines
2.8 KiB
C++
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;
|
|
}
|