mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-23 03:10:04 +08:00
截图失败时,返回ffmpeg日志; ffmpeg命令支持相对路径
This commit is contained in:
parent
a3d696d805
commit
63f22ee6f2
@ -91,8 +91,9 @@ void FFmpegSource::play(const string &ffmpeg_cmd_key, const string &src_url,cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
char cmd[1024] = {0};
|
char cmd[1024] = {0};
|
||||||
snprintf(cmd, sizeof(cmd), ffmpeg_cmd.data(), ffmpeg_bin.data(), src_url.data(), dst_url.data());
|
snprintf(cmd, sizeof(cmd), ffmpeg_cmd.data(), File::absolutePath("", ffmpeg_bin).data(), src_url.data(), dst_url.data());
|
||||||
_process.run(cmd,ffmpeg_log.empty() ? "" : File::absolutePath("",ffmpeg_log));
|
auto log_file = ffmpeg_log.empty() ? "" : File::absolutePath("", ffmpeg_log);
|
||||||
|
_process.run(cmd, log_file);
|
||||||
InfoL << cmd;
|
InfoL << cmd;
|
||||||
|
|
||||||
if (is_local_ip(_media_info._host)) {
|
if (is_local_ip(_media_info._host)) {
|
||||||
@ -312,7 +313,7 @@ void FFmpegSource::onGetMediaSource(const MediaSource::Ptr &src) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FFmpegSnap::makeSnap(const string &play_url, const string &save_path, float timeout_sec, const function<void(bool)> &cb) {
|
void FFmpegSnap::makeSnap(const string &play_url, const string &save_path, float timeout_sec, const onSnap &cb) {
|
||||||
GET_CONFIG(string,ffmpeg_bin,FFmpeg::kBin);
|
GET_CONFIG(string,ffmpeg_bin,FFmpeg::kBin);
|
||||||
GET_CONFIG(string,ffmpeg_snap,FFmpeg::kSnap);
|
GET_CONFIG(string,ffmpeg_snap,FFmpeg::kSnap);
|
||||||
GET_CONFIG(string,ffmpeg_log,FFmpeg::kLog);
|
GET_CONFIG(string,ffmpeg_log,FFmpeg::kLog);
|
||||||
@ -321,28 +322,33 @@ void FFmpegSnap::makeSnap(const string &play_url, const string &save_path, float
|
|||||||
auto elapsed_ms = ticker.elapsedTime();
|
auto elapsed_ms = ticker.elapsedTime();
|
||||||
if (elapsed_ms > timeout_sec * 1000) {
|
if (elapsed_ms > timeout_sec * 1000) {
|
||||||
//超时,后台线程负载太高,当代太久才启动该任务
|
//超时,后台线程负载太高,当代太久才启动该任务
|
||||||
cb(false);
|
cb(false, "wait work poller schedule snap task timeout");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char cmd[1024] = {0};
|
char cmd[2048] = { 0 };
|
||||||
snprintf(cmd, sizeof(cmd),ffmpeg_snap.data(),ffmpeg_bin.data(),play_url.data(),save_path.data());
|
snprintf(cmd, sizeof(cmd), ffmpeg_snap.data(), File::absolutePath("", ffmpeg_bin).data(), play_url.data(), save_path.data());
|
||||||
|
|
||||||
std::shared_ptr<Process> process = std::make_shared<Process>();
|
std::shared_ptr<Process> process = std::make_shared<Process>();
|
||||||
process->run(cmd,ffmpeg_log.empty() ? "" : File::absolutePath("",ffmpeg_log));
|
auto log_file = ffmpeg_log.empty() ? ffmpeg_log : File::absolutePath("", ffmpeg_log);
|
||||||
|
process->run(cmd, log_file);
|
||||||
|
|
||||||
//定时器延时应该减去后台任务启动的延时
|
//定时器延时应该减去后台任务启动的延时
|
||||||
auto delayTask = EventPollerPool::Instance().getPoller()->doDelayTask((uint64_t)(timeout_sec * 1000 - elapsed_ms),[process,cb](){
|
auto delayTask = EventPollerPool::Instance().getPoller()->doDelayTask(
|
||||||
if(process->wait(false)){
|
(uint64_t)(timeout_sec * 1000 - elapsed_ms), [process, cb, log_file, save_path]() {
|
||||||
//FFmpeg进程还在运行,超时就关闭它
|
if (process->wait(false)) {
|
||||||
process->kill(2000);
|
// FFmpeg进程还在运行,超时就关闭它
|
||||||
}
|
process->kill(2000);
|
||||||
return 0;
|
}
|
||||||
});
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
//等待FFmpeg进程退出
|
//等待FFmpeg进程退出
|
||||||
process->wait(true);
|
process->wait(true);
|
||||||
//FFmpeg进程退出了可以取消定时器了
|
// FFmpeg进程退出了可以取消定时器了
|
||||||
delayTask->cancel();
|
delayTask->cancel();
|
||||||
//执行回调函数
|
//执行回调函数
|
||||||
cb(process->exit_code() == 0);
|
bool success = process->exit_code() == 0 && File::fileSize(save_path.data());
|
||||||
|
cb(success, (!success && !log_file.empty()) ? File::loadFile(log_file.data()) : "");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,12 +25,14 @@ namespace FFmpeg {
|
|||||||
|
|
||||||
class FFmpegSnap {
|
class FFmpegSnap {
|
||||||
public:
|
public:
|
||||||
|
using onSnap = std::function<void(bool success, const std::string &err_msg)>;
|
||||||
/// 创建截图
|
/// 创建截图
|
||||||
/// \param play_url 播放url地址,只要FFmpeg支持即可
|
/// \param play_url 播放url地址,只要FFmpeg支持即可
|
||||||
/// \param save_path 截图jpeg文件保存路径
|
/// \param save_path 截图jpeg文件保存路径
|
||||||
/// \param timeout_sec 生成截图超时时间(防止阻塞太久)
|
/// \param timeout_sec 生成截图超时时间(防止阻塞太久)
|
||||||
/// \param cb 生成截图成功与否回调
|
/// \param cb 生成截图成功与否回调
|
||||||
static void makeSnap(const std::string &play_url, const std::string &save_path, float timeout_sec, const std::function<void(bool)> &cb);
|
static void makeSnap(const std::string &play_url, const std::string &save_path, float timeout_sec, const onSnap &cb);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FFmpegSnap() = delete;
|
FFmpegSnap() = delete;
|
||||||
~FFmpegSnap() = delete;
|
~FFmpegSnap() = delete;
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
void Process::run(const string &cmd, const string &log_file_tmp) {
|
void Process::run(const string &cmd, string &log_file_tmp) {
|
||||||
kill(2000);
|
kill(2000);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
STARTUPINFO si = {0};
|
STARTUPINFO si = {0};
|
||||||
@ -42,6 +42,7 @@ void Process::run(const string &cmd, const string &log_file_tmp) {
|
|||||||
} else {
|
} else {
|
||||||
log_file = StrPrinter << log_file_tmp << "." << getCurrentMillisecond();
|
log_file = StrPrinter << log_file_tmp << "." << getCurrentMillisecond();
|
||||||
}
|
}
|
||||||
|
log_file_tmp = log_file;
|
||||||
|
|
||||||
//重定向shell日志至文件
|
//重定向shell日志至文件
|
||||||
auto fp = File::create_file(log_file.data(), "ab");
|
auto fp = File::create_file(log_file.data(), "ab");
|
||||||
@ -92,6 +93,8 @@ void Process::run(const string &cmd, const string &log_file_tmp) {
|
|||||||
//在启动子进程时,暂时禁用SIGINT、SIGTERM信号
|
//在启动子进程时,暂时禁用SIGINT、SIGTERM信号
|
||||||
signal(SIGINT, SIG_IGN);
|
signal(SIGINT, SIG_IGN);
|
||||||
signal(SIGTERM, SIG_IGN);
|
signal(SIGTERM, SIG_IGN);
|
||||||
|
signal(SIGSEGV, SIG_IGN);
|
||||||
|
signal(SIGABRT, SIG_IGN);
|
||||||
|
|
||||||
//重定向shell日志至文件
|
//重定向shell日志至文件
|
||||||
auto fp = File::create_file(log_file.data(), "ab");
|
auto fp = File::create_file(log_file.data(), "ab");
|
||||||
@ -148,6 +151,7 @@ void Process::run(const string &cmd, const string &log_file_tmp) {
|
|||||||
} else {
|
} else {
|
||||||
log_file = StrPrinter << log_file_tmp << "." << _pid;
|
log_file = StrPrinter << log_file_tmp << "." << _pid;
|
||||||
}
|
}
|
||||||
|
log_file_tmp = log_file;
|
||||||
InfoL << "start child process " << _pid << ", log file:" << log_file;
|
InfoL << "start child process " << _pid << ", log file:" << log_file;
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class Process {
|
|||||||
public:
|
public:
|
||||||
Process();
|
Process();
|
||||||
~Process();
|
~Process();
|
||||||
void run(const std::string &cmd,const std::string &log_file);
|
void run(const std::string &cmd, std::string &log_file);
|
||||||
void kill(int max_delay,bool force = false);
|
void kill(int max_delay,bool force = false);
|
||||||
bool wait(bool block = true);
|
bool wait(bool block = true);
|
||||||
int exit_code();
|
int exit_code();
|
||||||
|
@ -1251,14 +1251,23 @@ void installWebApi() {
|
|||||||
|
|
||||||
static auto responseSnap = [](const string &snap_path,
|
static auto responseSnap = [](const string &snap_path,
|
||||||
const HttpSession::KeyValue &headerIn,
|
const HttpSession::KeyValue &headerIn,
|
||||||
const HttpSession::HttpResponseInvoker &invoker) {
|
const HttpSession::HttpResponseInvoker &invoker,
|
||||||
|
const string &err_msg = "") {
|
||||||
|
static bool s_snap_success_once = false;
|
||||||
StrCaseMap headerOut;
|
StrCaseMap headerOut;
|
||||||
GET_CONFIG(string, defaultSnap, API::kDefaultSnap);
|
GET_CONFIG(string, defaultSnap, API::kDefaultSnap);
|
||||||
if (!File::fileSize(snap_path.data()) && !defaultSnap.empty()) {
|
if (!File::fileSize(snap_path.data())) {
|
||||||
//空文件且设置了预设图,则返回预设图片(也就是FFmpeg生成截图中空档期的默认图片)
|
if (!err_msg.empty() && (!s_snap_success_once || defaultSnap.empty())) {
|
||||||
const_cast<string&>(snap_path) = File::absolutePath(defaultSnap, "");
|
//重来没截图成功过或者默认截图图片为空,那么直接返回FFmpeg错误日志
|
||||||
|
headerOut["Content-Type"] = HttpFileManager::getContentType(".txt");
|
||||||
|
invoker.responseFile(headerIn, headerOut, err_msg, false, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//截图成功过一次,那么认为配置无错误,截图失败时,返回预设默认图片
|
||||||
|
const_cast<string &>(snap_path) = File::absolutePath("", defaultSnap);
|
||||||
headerOut["Content-Type"] = HttpFileManager::getContentType(snap_path.data());
|
headerOut["Content-Type"] = HttpFileManager::getContentType(snap_path.data());
|
||||||
} else {
|
} else {
|
||||||
|
s_snap_success_once = true;
|
||||||
//之前生成的截图文件,我们默认为jpeg格式
|
//之前生成的截图文件,我们默认为jpeg格式
|
||||||
headerOut["Content-Type"] = HttpFileManager::getContentType(".jpeg");
|
headerOut["Content-Type"] = HttpFileManager::getContentType(".jpeg");
|
||||||
}
|
}
|
||||||
@ -1317,7 +1326,7 @@ void installWebApi() {
|
|||||||
|
|
||||||
//启动FFmpeg进程,开始截图,生成临时文件,截图成功后替换为正式文件
|
//启动FFmpeg进程,开始截图,生成临时文件,截图成功后替换为正式文件
|
||||||
auto new_snap_tmp = new_snap + ".tmp";
|
auto new_snap_tmp = new_snap + ".tmp";
|
||||||
FFmpegSnap::makeSnap(allArgs["url"], new_snap_tmp, allArgs["timeout_sec"], [invoker, allArgs, new_snap, new_snap_tmp](bool success) {
|
FFmpegSnap::makeSnap(allArgs["url"], new_snap_tmp, allArgs["timeout_sec"], [invoker, allArgs, new_snap, new_snap_tmp](bool success, const string &err_msg) {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
//生成截图失败,可能残留空文件
|
//生成截图失败,可能残留空文件
|
||||||
File::delete_file(new_snap_tmp.data());
|
File::delete_file(new_snap_tmp.data());
|
||||||
@ -1326,7 +1335,7 @@ void installWebApi() {
|
|||||||
File::delete_file(new_snap.data());
|
File::delete_file(new_snap.data());
|
||||||
rename(new_snap_tmp.data(), new_snap.data());
|
rename(new_snap_tmp.data(), new_snap.data());
|
||||||
}
|
}
|
||||||
responseSnap(new_snap, allArgs.getParser().getHeader(), invoker);
|
responseSnap(new_snap, allArgs.getParser().getHeader(), invoker, err_msg);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user