Ensure the threadsafe for video upload
This commit is contained in:
@@ -2114,24 +2114,6 @@ namespace ANSCENTER
|
||||
constexpr const char* kX264WriterOpts =
|
||||
"video_codec;libx264|crf;26|preset;slow|tune;stillimage|movflags;+faststart";
|
||||
|
||||
std::string prevWriterOpts;
|
||||
bool hadPrevWriterOpts = false;
|
||||
if (const char* prev = std::getenv(kWriterOptsEnv)) {
|
||||
prevWriterOpts = prev;
|
||||
hadPrevWriterOpts = true;
|
||||
}
|
||||
|
||||
auto setX264Opts = [&]() {
|
||||
_putenv_s(kWriterOptsEnv, kX264WriterOpts);
|
||||
};
|
||||
auto restoreOpts = [&]() {
|
||||
if (hadPrevWriterOpts) {
|
||||
_putenv_s(kWriterOptsEnv, prevWriterOpts.c_str());
|
||||
} else {
|
||||
_putenv_s(kWriterOptsEnv, "");
|
||||
}
|
||||
};
|
||||
|
||||
// Try codecs in order of preference.
|
||||
// avc1 / H264 / x264 route to libx264 via FFmpeg when forced via the
|
||||
// video_codec option above. MP4V and MJPG are last-resort fallbacks —
|
||||
@@ -2146,34 +2128,68 @@ namespace ANSCENTER
|
||||
|
||||
bool codecFound = false;
|
||||
std::string usedCodec;
|
||||
for (const auto& [name, fourcc] : codecs) {
|
||||
const bool isH264Family =
|
||||
(name == "avc1" || name == "H264" || name == "x264");
|
||||
|
||||
if (isH264Family) {
|
||||
setX264Opts();
|
||||
} else {
|
||||
restoreOpts();
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
// PARALLEL-SAFETY: OPENCV_FFMPEG_WRITER_OPTIONS is process-wide.
|
||||
// Two workers racing through this block would clobber each
|
||||
// other's env var between setX264Opts() and VideoWriter::open(),
|
||||
// silently mis-tuning or mis-picking a codec for one of them.
|
||||
// Serialize the env-var + open() window with a function-local
|
||||
// static mutex. The frame-write loop after this block is fully
|
||||
// parallel because `videoWriter` is self-contained once opened.
|
||||
// ──────────────────────────────────────────────────────────────
|
||||
{
|
||||
static std::mutex g_writerOptsMutex;
|
||||
std::lock_guard<std::mutex> optsLock(g_writerOptsMutex);
|
||||
|
||||
std::string prevWriterOpts;
|
||||
bool hadPrevWriterOpts = false;
|
||||
if (const char* prev = std::getenv(kWriterOptsEnv)) {
|
||||
prevWriterOpts = prev;
|
||||
hadPrevWriterOpts = true;
|
||||
}
|
||||
|
||||
videoWriter.open(mp4OutputPath, fourcc, fps,
|
||||
cv::Size(videoWidth, videoHeight), true);
|
||||
auto setX264Opts = [&]() {
|
||||
_putenv_s(kWriterOptsEnv, kX264WriterOpts);
|
||||
};
|
||||
auto restoreOpts = [&]() {
|
||||
if (hadPrevWriterOpts) {
|
||||
_putenv_s(kWriterOptsEnv, prevWriterOpts.c_str());
|
||||
} else {
|
||||
_putenv_s(kWriterOptsEnv, "");
|
||||
}
|
||||
};
|
||||
|
||||
if (videoWriter.isOpened()) {
|
||||
std::cout << "Using codec: " << name
|
||||
<< (isH264Family ? " (libx264 forced, crf=26, preset=slow, tune=stillimage)" : "")
|
||||
<< std::endl;
|
||||
usedCodec = name;
|
||||
codecFound = true;
|
||||
break;
|
||||
for (const auto& [name, fourcc] : codecs) {
|
||||
const bool isH264Family =
|
||||
(name == "avc1" || name == "H264" || name == "x264");
|
||||
|
||||
if (isH264Family) {
|
||||
setX264Opts();
|
||||
} else {
|
||||
restoreOpts();
|
||||
}
|
||||
|
||||
videoWriter.open(mp4OutputPath, fourcc, fps,
|
||||
cv::Size(videoWidth, videoHeight), true);
|
||||
|
||||
if (videoWriter.isOpened()) {
|
||||
std::cout << "Using codec: " << name
|
||||
<< (isH264Family ? " (libx264 forced, crf=26, preset=slow, tune=stillimage)" : "")
|
||||
<< std::endl;
|
||||
usedCodec = name;
|
||||
codecFound = true;
|
||||
break;
|
||||
}
|
||||
videoWriter.release();
|
||||
}
|
||||
videoWriter.release();
|
||||
|
||||
// Always restore the env var before releasing the mutex
|
||||
// — don't leak the libx264 override into the rest of the
|
||||
// process.
|
||||
restoreOpts();
|
||||
}
|
||||
|
||||
// Always restore the env var after we're done — don't leak the
|
||||
// libx264 override into the rest of the process.
|
||||
restoreOpts();
|
||||
|
||||
if (!codecFound) {
|
||||
std::cerr << "Error: Could not open video writer with any codec!" << std::endl;
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user