forked from zakaria/chicken-counting-sukawarna-det
Create C++ version
This commit is contained in:
1 parent
1a3242f611
commit
f34eaa3af4
25 files changed
+3353
-24
No files matched your search
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <opencv2/videoio.hpp>
|
||||
|
||||
namespace cc {
|
||||
|
||||
inline double video_duration_seconds(const std::string& path) {
|
||||
cv::VideoCapture cap(path);
|
||||
if (!cap.isOpened())
|
||||
throw std::runtime_error("Unable to open video for duration probe: " + path);
|
||||
double fc = cap.get(cv::CAP_PROP_FRAME_COUNT);
|
||||
double fps = cap.get(cv::CAP_PROP_FPS);
|
||||
cap.release();
|
||||
if (fps > 0 && fc > 0) return fc / fps;
|
||||
throw std::runtime_error("Unable to determine duration for video: " + path);
|
||||
}
|
||||
|
||||
inline double file_size_mb(const std::string& path) {
|
||||
return static_cast<double>(std::filesystem::file_size(path)) / (1024.0 * 1024.0);
|
||||
}
|
||||
|
||||
inline void run_ffmpeg(const std::vector<std::string>& command) {
|
||||
std::string cmd;
|
||||
for (const auto& arg : command) cmd += arg + " ";
|
||||
cmd = cmd.substr(0, cmd.size() - 1) + " 2>&1";
|
||||
int ret = std::system(cmd.c_str());
|
||||
if (ret != 0)
|
||||
throw std::runtime_error("ffmpeg failed with code " + std::to_string(ret));
|
||||
}
|
||||
|
||||
inline double compress_video_to_target(
|
||||
const std::string& input_path,
|
||||
const std::string& output_path,
|
||||
int max_mb = 200,
|
||||
int max_attempts = 3)
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
if (!fs::is_regular_file(input_path))
|
||||
throw std::runtime_error("Input video not found: " + input_path);
|
||||
|
||||
fs::create_directories(fs::path(output_path).parent_path());
|
||||
|
||||
double duration = video_duration_seconds(input_path);
|
||||
if (duration <= 0)
|
||||
throw std::runtime_error("Invalid video duration for " + input_path);
|
||||
|
||||
int target_kbps = std::max(300, static_cast<int>((max_mb * 8192) / duration * 0.92));
|
||||
|
||||
for (int attempt = 0; attempt < max_attempts; ++attempt) {
|
||||
int attempt_kbps = std::max(300,
|
||||
static_cast<int>(target_kbps * std::pow(0.85, attempt)));
|
||||
|
||||
if (fs::exists(output_path)) fs::remove(output_path);
|
||||
|
||||
std::vector<std::vector<std::string>> codec_attempts = {
|
||||
{"-c:v", "h264_nvmpi", "-b:v", std::to_string(attempt_kbps) + "k",
|
||||
"-maxrate", std::to_string(attempt_kbps) + "k",
|
||||
"-bufsize", std::to_string(attempt_kbps * 2) + "k"},
|
||||
{"-c:v", "libx264", "-preset", "fast",
|
||||
"-b:v", std::to_string(attempt_kbps) + "k",
|
||||
"-maxrate", std::to_string(attempt_kbps) + "k",
|
||||
"-bufsize", std::to_string(attempt_kbps * 2) + "k"}
|
||||
};
|
||||
|
||||
bool succeeded = false;
|
||||
for (const auto& cargs : codec_attempts) {
|
||||
std::vector<std::string> cmd = {"ffmpeg", "-y", "-i", input_path};
|
||||
cmd.insert(cmd.end(), cargs.begin(), cargs.end());
|
||||
cmd.push_back("-c:a");
|
||||
cmd.push_back("copy");
|
||||
cmd.push_back(output_path);
|
||||
try {
|
||||
run_ffmpeg(cmd);
|
||||
succeeded = true;
|
||||
break;
|
||||
} catch (const std::runtime_error&) {
|
||||
if (fs::exists(output_path)) fs::remove(output_path);
|
||||
}
|
||||
}
|
||||
if (!succeeded)
|
||||
throw std::runtime_error("Unable to compress video: " + input_path);
|
||||
|
||||
double size_mb = file_size_mb(output_path);
|
||||
std::cerr << "[compress] " << fs::path(output_path).filename().string()
|
||||
<< ": " << size_mb << " MB (attempt " << (attempt + 1)
|
||||
<< ", target " << attempt_kbps << " kbps)\n";
|
||||
|
||||
if (size_mb <= max_mb) return size_mb;
|
||||
}
|
||||
|
||||
double final_size = file_size_mb(output_path);
|
||||
if (final_size > max_mb)
|
||||
throw std::runtime_error("Compressed video exceeds " + std::to_string(max_mb)
|
||||
+ " MB: " + output_path);
|
||||
return final_size;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
Reference in new issue
Block a user