Commit 9c42c5ed by xiongziliang

windows视频FFmpeg拉流代理

parent 01bae24f
...@@ -3,12 +3,7 @@ file(GLOB jsoncpp_src_list ../3rdpart/jsoncpp/*.cpp ../3rdpart/jsoncpp/*.h ) ...@@ -3,12 +3,7 @@ file(GLOB jsoncpp_src_list ../3rdpart/jsoncpp/*.cpp ../3rdpart/jsoncpp/*.h )
add_library(jsoncpp STATIC ${jsoncpp_src_list}) add_library(jsoncpp STATIC ${jsoncpp_src_list})
if (CMAKE_SYSTEM_NAME MATCHES "Windows") file(GLOB MediaServer_src_list ./*.cpp ./*.h)
set(MediaServer_src_list ./WebApi.cpp ./WebHook.cpp main.cpp)
else()
file(GLOB MediaServer_src_list ./*.cpp ./*.h)
endif()
#message(STATUS ${MediaServer_src_list}) #message(STATUS ${MediaServer_src_list})
add_executable(MediaServer ${MediaServer_src_list}) add_executable(MediaServer ${MediaServer_src_list})
......
...@@ -32,13 +32,22 @@ ...@@ -32,13 +32,22 @@
namespace FFmpeg { namespace FFmpeg {
#define FFmpeg_FIELD "ffmpeg." #define FFmpeg_FIELD "ffmpeg."
const char kBin[] = FFmpeg_FIELD"bin"; const string kBin = FFmpeg_FIELD"bin";
const char kCmd[] = FFmpeg_FIELD"cmd"; const string kCmd = FFmpeg_FIELD"cmd";
const char kLog[] = FFmpeg_FIELD"log"; const string kLog = FFmpeg_FIELD"log";
onceToken token([]() { onceToken token([]() {
mINI::Instance()[kBin] = trim(System::execute("which ffmpeg")); #ifdef _WIN32
mINI::Instance()[kCmd] = "%s -re -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s"; string ffmpeg_bin = System::execute("where ffmpeg");
//windows下先关闭FFmpeg日志(目前不支持日志重定向)
mINI::Instance()[kCmd] = "%s -re -i \"%s\" -loglevel quiet -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s ";
#else
string ffmpeg_bin = System::execute("which ffmpeg");
mINI::Instance()[kCmd] = "%s -re -i \"%s\" -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s ";
#endif
//默认ffmpeg命令路径为环境变量中路径
mINI::Instance()[kBin] = ffmpeg_bin.empty() ? "ffmpeg" : ffmpeg_bin;
//ffmpeg日志保存路径
mINI::Instance()[kLog] = "./ffmpeg/ffmpeg.log"; mINI::Instance()[kLog] = "./ffmpeg/ffmpeg.log";
}); });
} }
......
...@@ -26,8 +26,15 @@ ...@@ -26,8 +26,15 @@
#include <limits.h> #include <limits.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifndef _WIN32
#include <sys/resource.h> #include <sys/resource.h>
#include <unistd.h> #include <unistd.h>
#else
//#include <TlHelp32.h>
#include <windows.h>
#endif
#include <stdexcept> #include <stdexcept>
#include <signal.h> #include <signal.h>
#include "Util/util.h" #include "Util/util.h"
...@@ -39,75 +46,95 @@ ...@@ -39,75 +46,95 @@
using namespace toolkit; using namespace toolkit;
void Process::run(const string &cmd, const string &log_file_tmp) { void Process::run(const string &cmd, const string &log_file_tmp) {
kill(2000); kill(2000);
_pid = fork(); #ifdef _WIN32
if (_pid < 0) { STARTUPINFO si;
throw std::runtime_error(StrPrinter << "fork child process falied,err:" << get_uv_errmsg()); PROCESS_INFORMATION pi;
} ZeroMemory(&si, sizeof(si)); //结构体初始化;
if (_pid == 0) { ZeroMemory(&pi, sizeof(pi));
//子进程关闭core文件生成
struct rlimit rlim = {0,0}; LPTSTR lpDir = const_cast<char*>(cmd .data());
setrlimit(RLIMIT_CORE, &rlim);
if (CreateProcess(NULL, lpDir, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)){
//在启动子进程时,暂时禁用SIGINT、SIGTERM信号 //下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程
// ignore the SIGINT and SIGTERM CloseHandle(pi.hProcess);
signal(SIGINT, SIG_IGN); CloseHandle(pi.hThread);
signal(SIGTERM, SIG_IGN);
_pid = pi.dwProcessId;
string log_file ; InfoL << "start child proces " << _pid;
if(log_file_tmp.empty()){ } else {
log_file = "/dev/null"; WarnL << "start child proces fail: " << GetLastError();
}else{ }
log_file = StrPrinter << log_file_tmp << "." << getpid(); #else
} _pid = fork();
if (_pid < 0) {
int log_fd = -1; throw std::runtime_error(StrPrinter << "fork child process falied,err:" << get_uv_errmsg());
int flags = O_CREAT | O_WRONLY | O_APPEND; }
mode_t mode = S_IRWXO | S_IRWXG | S_IRWXU;// S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; if (_pid == 0) {
File::createfile_path(log_file.data(), mode); //子进程关闭core文件生成
if ((log_fd = ::open(log_file.c_str(), flags, mode)) < 0) { struct rlimit rlim = { 0,0 };
fprintf(stderr, "open log file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); setrlimit(RLIMIT_CORE, &rlim);
} else {
// dup to stdout and stderr. //在启动子进程时,暂时禁用SIGINT、SIGTERM信号
if (dup2(log_fd, STDOUT_FILENO) < 0) { // ignore the SIGINT and SIGTERM
fprintf(stderr, "dup2 stdout file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); signal(SIGINT, SIG_IGN);
} signal(SIGTERM, SIG_IGN);
if (dup2(log_fd, STDERR_FILENO) < 0) {
fprintf(stderr, "dup2 stderr file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); string log_file;
} if (log_file_tmp.empty()) {
// close log fd log_file = "/dev/null";
::close(log_fd); }
} else {
fprintf(stderr, "\r\n\r\n#### pid=%d,cmd=%s #####\r\n\r\n", getpid(), cmd.data()); log_file = StrPrinter << log_file_tmp << "." << getpid();
}
// close other fds
// TODO: do in right way. int log_fd = -1;
for (int i = 3; i < 1024; i++) { int flags = O_CREAT | O_WRONLY | O_APPEND;
::close(i); mode_t mode = S_IRWXO | S_IRWXG | S_IRWXU;// S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
} File::createfile_path(log_file.data(), mode);
if ((log_fd = ::open(log_file.c_str(), flags, mode)) < 0) {
auto params = split(cmd, " "); fprintf(stderr, "open log file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno));
// memory leak in child process, it's ok. }
char **charpv_params = new char *[params.size() + 1]; else {
for (int i = 0; i < (int) params.size(); i++) { // dup to stdout and stderr.
std::string &p = params[i]; if (dup2(log_fd, STDOUT_FILENO) < 0) {
charpv_params[i] = (char *) p.data(); fprintf(stderr, "dup2 stdout file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno));
} }
// EOF: NULL if (dup2(log_fd, STDERR_FILENO) < 0) {
charpv_params[params.size()] = NULL; fprintf(stderr, "dup2 stderr file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno));
}
// TODO: execv or execvp // close log fd
auto ret = execv(params[0].c_str(), charpv_params); ::close(log_fd);
if (ret < 0) { }
fprintf(stderr, "fork process failed, errno=%d(%s)\r\n", errno, strerror(errno)); fprintf(stderr, "\r\n\r\n#### pid=%d,cmd=%s #####\r\n\r\n", getpid(), cmd.data());
}
exit(ret); // close other fds
} // TODO: do in right way.
for (int i = 3; i < 1024; i++) {
InfoL << "start child proces " << _pid; ::close(i);
}
auto params = split(cmd, " ");
// memory leak in child process, it's ok.
char **charpv_params = new char *[params.size() + 1];
for (int i = 0; i < (int)params.size(); i++) {
std::string &p = params[i];
charpv_params[i] = (char *)p.data();
}
// EOF: NULL
charpv_params[params.size()] = NULL;
// TODO: execv or execvp
auto ret = execv(params[0].c_str(), charpv_params);
if (ret < 0) {
fprintf(stderr, "fork process failed, errno=%d(%s)\r\n", errno, strerror(errno));
}
exit(ret);
}
InfoL << "start child proces " << _pid;
#endif // _WIN32
} }
/** /**
* 获取进程是否存活状态 * 获取进程是否存活状态
* @param pid 进程号 * @param pid 进程号
...@@ -120,20 +147,30 @@ static bool s_wait(pid_t pid,int *exit_code_ptr,bool block) { ...@@ -120,20 +147,30 @@ static bool s_wait(pid_t pid,int *exit_code_ptr,bool block) {
return false; return false;
} }
int status = 0; int status = 0;
pid_t p = waitpid(pid, &status, block ? 0 : WNOHANG); #ifdef _WIN32
int exit_code = (status & 0xFF00) >> 8; HANDLE hProcess = NULL;
if(exit_code_ptr){ hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程
*exit_code_ptr = (status & 0xFF00) >> 8; if (hProcess == NULL) {
} return false;
if (p < 0) { }
WarnL << "waitpid failed, pid=" << pid << ", err=" << get_uv_errmsg();
return false; CloseHandle(hProcess);
} #else
if (p > 0) { pid_t p = waitpid(pid, &status, block ? 0 : WNOHANG);
InfoL << "process terminated, pid=" << pid << ", exit code=" << exit_code; int exit_code = (status & 0xFF00) >> 8;
return false; if (exit_code_ptr) {
} *exit_code_ptr = (status & 0xFF00) >> 8;
//WarnL << "process is running, pid=" << _pid; }
if (p < 0) {
WarnL << "waitpid failed, pid=" << pid << ", err=" << get_uv_errmsg();
return false;
}
if (p > 0) {
InfoL << "process terminated, pid=" << pid << ", exit code=" << exit_code;
return false;
}
#endif // _WIN32
return true; return true;
} }
...@@ -142,12 +179,25 @@ static void s_kill(pid_t pid,int max_delay,bool force){ ...@@ -142,12 +179,25 @@ static void s_kill(pid_t pid,int max_delay,bool force){
//pid无效 //pid无效
return; return;
} }
#ifdef _WIN32
HANDLE hProcess = NULL;
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程
if (hProcess == NULL) {
WarnL << "\nOpen Process fAiled: " << GetLastError();
return;
}
DWORD ret = TerminateProcess(hProcess, 0); //结束目标进程
if (ret == 0) {
WarnL << GetLastError;
}
#else
if (::kill(pid, force ? SIGKILL : SIGTERM) == -1) {
//进程可能已经退出了
WarnL << "kill process " << pid << " failed:" << get_uv_errmsg();
return;
}
#endif // _WIN32
if (::kill(pid, force ? SIGKILL : SIGTERM) == -1) {
//进程可能已经退出了
WarnL << "kill process " << pid << " failed:" << get_uv_errmsg();
return;
}
if(force){ if(force){
//发送SIGKILL信号后,阻塞等待退出 //发送SIGKILL信号后,阻塞等待退出
......
...@@ -23,10 +23,15 @@ ...@@ -23,10 +23,15 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
#ifndef IPTV_PROCESS_H #ifndef ZLMEDIAKIT_PROCESS_H
#define IPTV_PROCESS_H #define ZLMEDIAKIT_PROCESS_H
#ifdef _WIN32
typedef int pid_t;
#else
#include <sys/wait.h> #include <sys/wait.h>
#endif // _WIN32
#include <fcntl.h> #include <fcntl.h>
#include <string> #include <string>
using namespace std; using namespace std;
...@@ -45,4 +50,4 @@ private: ...@@ -45,4 +50,4 @@ private:
}; };
#endif //IPTV_PROCESS_H #endif //ZLMEDIAKIT_PROCESS_H
...@@ -24,67 +24,17 @@ ...@@ -24,67 +24,17 @@
* SOFTWARE. * SOFTWARE.
*/ */
#ifndef IPTV_BASH_H #ifndef ZLMEDIAKIT_SYSTEM_H
#define IPTV_BASH_H #define ZLMEDIAKIT_SYSTEM_H
#include <cstdint>
#include <string> #include <string>
#include <vector>
#include <map>
#include "Util/NoticeCenter.h"
using namespace std; using namespace std;
using namespace toolkit;
class System { class System {
public: public:
typedef struct {
uint32_t task_total;
uint32_t task_running;
uint32_t task_sleeping;
uint32_t task_stopped;
uint64_t mem_total;
uint64_t mem_free;
uint64_t mem_used;
float cpu_user;
float cpu_sys;
float cpu_idle;
} SystemUsage;
typedef struct {
uint64_t recv_bytes;
uint64_t recv_packets;
uint64_t snd_bytes;
uint64_t snd_packets;
string interface;
} NetworkUsage;
typedef struct {
uint64_t available;
uint64_t used;
float used_per;
string mounted_on;
string filesystem;
bool mounted;
} DiskUsage;
typedef struct {
uint32_t established;
uint32_t syn_recv;
uint32_t time_wait;
uint32_t close_wait;
} TcpUsage;
static bool getSystemUsage(SystemUsage &usage);
static bool getNetworkUsage(vector<NetworkUsage> &usage);
static bool getTcpUsage(TcpUsage &usage);
static string execute(const string &cmd); static string execute(const string &cmd);
static void startDaemon(); static void startDaemon();
static void systemSetup(); static void systemSetup();
}; };
#endif //ZLMEDIAKIT_SYSTEM_H
#endif //IPTV_BASH_H
...@@ -47,10 +47,7 @@ ...@@ -47,10 +47,7 @@
#include "WebHook.h" #include "WebHook.h"
#include "Thread/WorkThreadPool.h" #include "Thread/WorkThreadPool.h"
#include "Rtp/RtpSelector.h" #include "Rtp/RtpSelector.h"
#if !defined(_WIN32)
#include "FFmpegSource.h" #include "FFmpegSource.h"
#endif//!defined(_WIN32)
using namespace Json; using namespace Json;
using namespace toolkit; using namespace toolkit;
...@@ -268,10 +265,8 @@ static inline string getProxyKey(const string &vhost,const string &app,const str ...@@ -268,10 +265,8 @@ static inline string getProxyKey(const string &vhost,const string &app,const str
return vhost + "/" + app + "/" + stream; return vhost + "/" + app + "/" + stream;
} }
#if !defined(_WIN32)
static unordered_map<string ,FFmpegSource::Ptr> s_ffmpegMap; static unordered_map<string ,FFmpegSource::Ptr> s_ffmpegMap;
static recursive_mutex s_ffmpegMapMtx; static recursive_mutex s_ffmpegMapMtx;
#endif//#if !defined(_WIN32)
/** /**
* 安装api接口 * 安装api接口
...@@ -646,7 +641,6 @@ void installWebApi() { ...@@ -646,7 +641,6 @@ void installWebApi() {
val["data"]["flag"] = s_proxyMap.erase(allArgs["key"]) == 1; val["data"]["flag"] = s_proxyMap.erase(allArgs["key"]) == 1;
}); });
#if !defined(_WIN32)
static auto addFFmpegSource = [](const string &src_url, static auto addFFmpegSource = [](const string &src_url,
const string &dst_url, const string &dst_url,
int timeout_ms, int timeout_ms,
...@@ -713,7 +707,6 @@ void installWebApi() { ...@@ -713,7 +707,6 @@ void installWebApi() {
API_REGIST(api,delFFmepgSource,{ API_REGIST(api,delFFmepgSource,{
api_delFFmpegSource(API_ARGS_VALUE); api_delFFmpegSource(API_ARGS_VALUE);
}); });
#endif
//新增http api下载可执行程序文件接口 //新增http api下载可执行程序文件接口
//测试url http://127.0.0.1/index/api/downloadBin //测试url http://127.0.0.1/index/api/downloadBin
...@@ -932,10 +925,8 @@ void unInstallWebApi(){ ...@@ -932,10 +925,8 @@ void unInstallWebApi(){
s_proxyMap.clear(); s_proxyMap.clear();
} }
#if !defined(_WIN32)
{ {
lock_guard<recursive_mutex> lck(s_ffmpegMapMtx); lock_guard<recursive_mutex> lck(s_ffmpegMapMtx);
s_ffmpegMap.clear(); s_ffmpegMap.clear();
} }
#endif
} }
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论