tab统一替换为4个空格键:#242

This commit is contained in:
xiongziliang 2020-03-20 11:51:24 +08:00
parent 2a0d78fd12
commit 1168174c2b
84 changed files with 6541 additions and 6520 deletions

@ -1 +1 @@
Subproject commit 34b42499ce9ee055b5c7cac9a270239984d0e839 Subproject commit d985d49f28b441216bf50020b7c6587edb5f43dc

View File

@ -31,12 +31,12 @@
#if defined(_WIN32) #if defined(_WIN32)
#if defined(MediaKitApi_EXPORTS) #if defined(MediaKitApi_EXPORTS)
#define API_EXPORT __declspec(dllexport) #define API_EXPORT __declspec(dllexport)
#else #else
#define API_EXPORT __declspec(dllimport) #define API_EXPORT __declspec(dllimport)
#endif #endif
#define API_CALL __cdecl #define API_CALL __cdecl
#else #else
#define API_EXPORT #define API_EXPORT
#define API_CALL #define API_CALL

View File

@ -32,41 +32,41 @@ using namespace toolkit;
using namespace mediakit; using namespace mediakit;
API_EXPORT mk_player API_CALL mk_player_create() { API_EXPORT mk_player API_CALL mk_player_create() {
MediaPlayer::Ptr *obj = new MediaPlayer::Ptr(new MediaPlayer()); MediaPlayer::Ptr *obj = new MediaPlayer::Ptr(new MediaPlayer());
return obj; return obj;
} }
API_EXPORT void API_CALL mk_player_release(mk_player ctx) { API_EXPORT void API_CALL mk_player_release(mk_player ctx) {
assert(ctx); assert(ctx);
MediaPlayer::Ptr *obj = (MediaPlayer::Ptr *)ctx; MediaPlayer::Ptr *obj = (MediaPlayer::Ptr *)ctx;
delete obj; delete obj;
} }
API_EXPORT void API_CALL mk_player_set_option(mk_player ctx,const char* key,const char *val){ API_EXPORT void API_CALL mk_player_set_option(mk_player ctx,const char* key,const char *val){
assert(ctx && key && val); assert(ctx && key && val);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
string key_str(key), val_str(val); string key_str(key), val_str(val);
player->getPoller()->async([key_str,val_str,player](){ player->getPoller()->async([key_str,val_str,player](){
//切换线程后再操作 //切换线程后再操作
(*player)[key_str] = val_str; (*player)[key_str] = val_str;
}); });
} }
API_EXPORT void API_CALL mk_player_play(mk_player ctx, const char *url) { API_EXPORT void API_CALL mk_player_play(mk_player ctx, const char *url) {
assert(ctx && url); assert(ctx && url);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
string url_str(url); string url_str(url);
player->getPoller()->async([url_str,player](){ player->getPoller()->async([url_str,player](){
//切换线程后再操作 //切换线程后再操作
player->play(url_str); player->play(url_str);
}); });
} }
API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause) { API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause) {
assert(ctx); assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
player->getPoller()->async([pause,player](){ player->getPoller()->async([pause,player](){
//切换线程后再操作 //切换线程后再操作
player->pause(pause); player->pause(pause);
}); });
} }
API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress) { API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress) {
@ -79,100 +79,100 @@ API_EXPORT void API_CALL mk_player_seekto(mk_player ctx, float progress) {
} }
static void mk_player_set_on_event(mk_player ctx, on_mk_play_event cb, void *user_data, int type) { static void mk_player_set_on_event(mk_player ctx, on_mk_play_event cb, void *user_data, int type) {
assert(ctx && cb); assert(ctx && cb);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
player->getPoller()->async([cb,user_data,type,player](){ player->getPoller()->async([cb,user_data,type,player](){
//切换线程后再操作 //切换线程后再操作
if(type == 0){ if(type == 0){
player->setOnPlayResult([cb,user_data](const SockException &ex){ player->setOnPlayResult([cb,user_data](const SockException &ex){
cb(user_data,ex.getErrCode(),ex.what()); cb(user_data,ex.getErrCode(),ex.what());
}); });
}else{ }else{
player->setOnShutdown([cb,user_data](const SockException &ex){ player->setOnShutdown([cb,user_data](const SockException &ex){
cb(user_data,ex.getErrCode(),ex.what()); cb(user_data,ex.getErrCode(),ex.what());
}); });
} }
}); });
} }
API_EXPORT void API_CALL mk_player_set_on_result(mk_player ctx, on_mk_play_event cb, void *user_data) { API_EXPORT void API_CALL mk_player_set_on_result(mk_player ctx, on_mk_play_event cb, void *user_data) {
mk_player_set_on_event(ctx,cb,user_data,0); mk_player_set_on_event(ctx,cb,user_data,0);
} }
API_EXPORT void API_CALL mk_player_set_on_shutdown(mk_player ctx, on_mk_play_event cb, void *user_data) { API_EXPORT void API_CALL mk_player_set_on_shutdown(mk_player ctx, on_mk_play_event cb, void *user_data) {
mk_player_set_on_event(ctx,cb,user_data,1); mk_player_set_on_event(ctx,cb,user_data,1);
} }
API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb, void *user_data) { API_EXPORT void API_CALL mk_player_set_on_data(mk_player ctx, on_mk_play_data cb, void *user_data) {
assert(ctx && cb); assert(ctx && cb);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
player->getPoller()->async([player,cb,user_data](){ player->getPoller()->async([player,cb,user_data](){
//切换线程后再操作 //切换线程后再操作
auto delegate = std::make_shared<FrameWriterInterfaceHelper>([cb,user_data](const Frame::Ptr &frame){ auto delegate = std::make_shared<FrameWriterInterfaceHelper>([cb,user_data](const Frame::Ptr &frame){
cb(user_data,frame->getTrackType(),frame->getCodecId(),frame->data(),frame->size(),frame->dts(),frame->pts()); cb(user_data,frame->getTrackType(),frame->getCodecId(),frame->data(),frame->size(),frame->dts(),frame->pts());
}); });
for(auto &track : player->getTracks()){ for(auto &track : player->getTracks()){
track->addDelegate(delegate); track->addDelegate(delegate);
} }
}); });
} }
API_EXPORT int API_CALL mk_player_video_width(mk_player ctx) { API_EXPORT int API_CALL mk_player_video_width(mk_player ctx) {
assert(ctx); assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo)); auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo));
return track ? track->getVideoWidth() : 0; return track ? track->getVideoWidth() : 0;
} }
API_EXPORT int API_CALL mk_player_video_height(mk_player ctx) { API_EXPORT int API_CALL mk_player_video_height(mk_player ctx) {
assert(ctx); assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo)); auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo));
return track ? track->getVideoHeight() : 0; return track ? track->getVideoHeight() : 0;
} }
API_EXPORT int API_CALL mk_player_video_fps(mk_player ctx) { API_EXPORT int API_CALL mk_player_video_fps(mk_player ctx) {
assert(ctx); assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo)); auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo));
return track ? track->getVideoFps() : 0; return track ? track->getVideoFps() : 0;
} }
API_EXPORT int API_CALL mk_player_audio_samplerate(mk_player ctx) { API_EXPORT int API_CALL mk_player_audio_samplerate(mk_player ctx) {
assert(ctx); assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio)); auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio));
return track ? track->getAudioSampleRate() : 0; return track ? track->getAudioSampleRate() : 0;
} }
API_EXPORT int API_CALL mk_player_audio_bit(mk_player ctx) { API_EXPORT int API_CALL mk_player_audio_bit(mk_player ctx) {
assert(ctx); assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio)); auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio));
return track ? track->getAudioSampleBit() : 0; return track ? track->getAudioSampleBit() : 0;
} }
API_EXPORT int API_CALL mk_player_audio_channel(mk_player ctx) { API_EXPORT int API_CALL mk_player_audio_channel(mk_player ctx) {
assert(ctx); assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio)); auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio));
return track ? track->getAudioChannel() : 0; return track ? track->getAudioChannel() : 0;
} }
API_EXPORT float API_CALL mk_player_duration(mk_player ctx) { API_EXPORT float API_CALL mk_player_duration(mk_player ctx) {
assert(ctx); assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
return player->getDuration(); return player->getDuration();
} }
API_EXPORT float API_CALL mk_player_progress(mk_player ctx) { API_EXPORT float API_CALL mk_player_progress(mk_player ctx) {
assert(ctx); assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
return player->getProgress(); return player->getProgress();
} }
API_EXPORT float API_CALL mk_player_loss_rate(mk_player ctx, int track_type) { API_EXPORT float API_CALL mk_player_loss_rate(mk_player ctx, int track_type) {
assert(ctx); assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx); MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
return player->getPacketLossRate((TrackType)track_type); return player->getPacketLossRate((TrackType)track_type);
} }

View File

@ -42,7 +42,7 @@ onceToken token([]() {
//windows下先关闭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 "; 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 #else
string ffmpeg_bin = System::execute("which ffmpeg"); 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 "; mINI::Instance()[kCmd] = "%s -re -i \"%s\" -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s ";
#endif #endif
//默认ffmpeg命令路径为环境变量中路径 //默认ffmpeg命令路径为环境变量中路径

View File

@ -46,92 +46,92 @@
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);
#ifdef _WIN32 #ifdef _WIN32
STARTUPINFO si; STARTUPINFO si;
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si)); //结构体初始化; ZeroMemory(&si, sizeof(si)); //结构体初始化;
ZeroMemory(&pi, sizeof(pi)); ZeroMemory(&pi, sizeof(pi));
LPTSTR lpDir = const_cast<char*>(cmd.data()); LPTSTR lpDir = const_cast<char*>(cmd.data());
if (CreateProcess(NULL, lpDir, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)){ if (CreateProcess(NULL, lpDir, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)){
//下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程 //下面两行关闭句柄,解除本进程和新进程的关系,不然有可能 不小心调用TerminateProcess函数关掉子进程
CloseHandle(pi.hProcess); CloseHandle(pi.hProcess);
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
_pid = pi.dwProcessId; _pid = pi.dwProcessId;
InfoL << "start child proces " << _pid; InfoL << "start child proces " << _pid;
} else { } else {
WarnL << "start child proces fail: " << GetLastError(); WarnL << "start child proces fail: " << GetLastError();
} }
#else #else
_pid = fork(); _pid = fork();
if (_pid < 0) { if (_pid < 0) {
throw std::runtime_error(StrPrinter << "fork child process falied,err:" << get_uv_errmsg()); throw std::runtime_error(StrPrinter << "fork child process falied,err:" << get_uv_errmsg());
} }
if (_pid == 0) { if (_pid == 0) {
//子进程关闭core文件生成 //子进程关闭core文件生成
struct rlimit rlim = { 0,0 }; struct rlimit rlim = { 0,0 };
setrlimit(RLIMIT_CORE, &rlim); setrlimit(RLIMIT_CORE, &rlim);
//在启动子进程时暂时禁用SIGINT、SIGTERM信号 //在启动子进程时暂时禁用SIGINT、SIGTERM信号
// ignore the SIGINT and SIGTERM // ignore the SIGINT and SIGTERM
signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN); signal(SIGTERM, SIG_IGN);
string log_file; string log_file;
if (log_file_tmp.empty()) { if (log_file_tmp.empty()) {
log_file = "/dev/null"; log_file = "/dev/null";
} }
else { else {
log_file = StrPrinter << log_file_tmp << "." << getpid(); log_file = StrPrinter << log_file_tmp << "." << getpid();
} }
int log_fd = -1; int log_fd = -1;
int flags = O_CREAT | O_WRONLY | O_APPEND; 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; 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); File::createfile_path(log_file.data(), mode);
if ((log_fd = ::open(log_file.c_str(), flags, mode)) < 0) { if ((log_fd = ::open(log_file.c_str(), flags, mode)) < 0) {
fprintf(stderr, "open log file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); fprintf(stderr, "open log file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno));
} }
else { else {
// dup to stdout and stderr. // dup to stdout and stderr.
if (dup2(log_fd, STDOUT_FILENO) < 0) { if (dup2(log_fd, STDOUT_FILENO) < 0) {
fprintf(stderr, "dup2 stdout file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); fprintf(stderr, "dup2 stdout file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno));
} }
if (dup2(log_fd, STDERR_FILENO) < 0) { if (dup2(log_fd, STDERR_FILENO) < 0) {
fprintf(stderr, "dup2 stderr file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno)); fprintf(stderr, "dup2 stderr file %s failed:%d(%s)\r\n", log_file.data(), errno, strerror(errno));
} }
// close log fd // close log fd
::close(log_fd); ::close(log_fd);
} }
fprintf(stderr, "\r\n\r\n#### pid=%d,cmd=%s #####\r\n\r\n", getpid(), cmd.data()); fprintf(stderr, "\r\n\r\n#### pid=%d,cmd=%s #####\r\n\r\n", getpid(), cmd.data());
// close other fds // close other fds
// TODO: do in right way. // TODO: do in right way.
for (int i = 3; i < 1024; i++) { for (int i = 3; i < 1024; i++) {
::close(i); ::close(i);
} }
auto params = split(cmd, " "); auto params = split(cmd, " ");
// memory leak in child process, it's ok. // memory leak in child process, it's ok.
char **charpv_params = new char *[params.size() + 1]; char **charpv_params = new char *[params.size() + 1];
for (int i = 0; i < (int)params.size(); i++) { for (int i = 0; i < (int)params.size(); i++) {
std::string &p = params[i]; std::string &p = params[i];
charpv_params[i] = (char *)p.data(); charpv_params[i] = (char *)p.data();
} }
// EOF: NULL // EOF: NULL
charpv_params[params.size()] = NULL; charpv_params[params.size()] = NULL;
// TODO: execv or execvp // TODO: execv or execvp
auto ret = execv(params[0].c_str(), charpv_params); auto ret = execv(params[0].c_str(), charpv_params);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "fork process failed, errno=%d(%s)\r\n", errno, strerror(errno)); fprintf(stderr, "fork process failed, errno=%d(%s)\r\n", errno, strerror(errno));
} }
exit(ret); exit(ret);
} }
InfoL << "start child proces " << _pid; InfoL << "start child proces " << _pid;
#endif // _WIN32 #endif // _WIN32
} }
@ -148,27 +148,27 @@ static bool s_wait(pid_t pid,int *exit_code_ptr,bool block) {
} }
int status = 0; int status = 0;
#ifdef _WIN32 #ifdef _WIN32
HANDLE hProcess = NULL; HANDLE hProcess = NULL;
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程 hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程
if (hProcess == NULL) { if (hProcess == NULL) {
return false; return false;
} }
CloseHandle(hProcess); CloseHandle(hProcess);
#else #else
pid_t p = waitpid(pid, &status, block ? 0 : WNOHANG); pid_t p = waitpid(pid, &status, block ? 0 : WNOHANG);
int exit_code = (status & 0xFF00) >> 8; int exit_code = (status & 0xFF00) >> 8;
if (exit_code_ptr) { if (exit_code_ptr) {
*exit_code_ptr = (status & 0xFF00) >> 8; *exit_code_ptr = (status & 0xFF00) >> 8;
} }
if (p < 0) { if (p < 0) {
WarnL << "waitpid failed, pid=" << pid << ", err=" << get_uv_errmsg(); WarnL << "waitpid failed, pid=" << pid << ", err=" << get_uv_errmsg();
return false; return false;
} }
if (p > 0) { if (p > 0) {
InfoL << "process terminated, pid=" << pid << ", exit code=" << exit_code; InfoL << "process terminated, pid=" << pid << ", exit code=" << exit_code;
return false; return false;
} }
#endif // _WIN32 #endif // _WIN32
return true; return true;
@ -180,22 +180,22 @@ static void s_kill(pid_t pid,int max_delay,bool force){
return; return;
} }
#ifdef _WIN32 #ifdef _WIN32
HANDLE hProcess = NULL; HANDLE hProcess = NULL;
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程 hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid); //打开目标进程
if (hProcess == NULL) { if (hProcess == NULL) {
WarnL << "\nOpen Process fAiled: " << GetLastError(); WarnL << "\nOpen Process fAiled: " << GetLastError();
return; return;
} }
DWORD ret = TerminateProcess(hProcess, 0); //结束目标进程 DWORD ret = TerminateProcess(hProcess, 0); //结束目标进程
if (ret == 0) { if (ret == 0) {
WarnL << GetLastError; WarnL << GetLastError;
} }
#else #else
if (::kill(pid, force ? SIGKILL : SIGTERM) == -1) { if (::kill(pid, force ? SIGKILL : SIGTERM) == -1) {
//进程可能已经退出了 //进程可能已经退出了
WarnL << "kill process " << pid << " failed:" << get_uv_errmsg(); WarnL << "kill process " << pid << " failed:" << get_uv_errmsg();
return; return;
} }
#endif // _WIN32 #endif // _WIN32

View File

@ -774,9 +774,9 @@ void installWebApi() {
val["status"] = (int)status; val["status"] = (int)status;
}); });
//获取录像文件夹列表或mp4文件列表 //获取录像文件夹列表或mp4文件列表
//http://127.0.0.1/index/api/getMp4RecordFile?vhost=__defaultVhost__&app=live&stream=ss&period=2020-01 //http://127.0.0.1/index/api/getMp4RecordFile?vhost=__defaultVhost__&app=live&stream=ss&period=2020-01
api_regist1("/index/api/getMp4RecordFile", [](API_ARGS1){ api_regist1("/index/api/getMp4RecordFile", [](API_ARGS1){
CHECK_SECRET(); CHECK_SECRET();
CHECK_ARGS("vhost", "app", "stream"); CHECK_ARGS("vhost", "app", "stream");
auto record_path = Recorder::getRecordPath(Recorder::type_mp4, allArgs["vhost"], allArgs["app"],allArgs["stream"]); auto record_path = Recorder::getRecordPath(Recorder::type_mp4, allArgs["vhost"], allArgs["app"],allArgs["stream"]);
@ -809,7 +809,7 @@ void installWebApi() {
val["data"]["rootPath"] = record_path; val["data"]["rootPath"] = record_path;
val["data"]["paths"] = paths; val["data"]["paths"] = paths;
}); });
////////////以下是注册的Hook API//////////// ////////////以下是注册的Hook API////////////
api_regist1("/index/hook/on_publish",[](API_ARGS1){ api_regist1("/index/hook/on_publish",[](API_ARGS1){

View File

@ -359,7 +359,7 @@ int start_main(int argc,char *argv[]) {
InfoL << "程序退出中,请等待..."; InfoL << "程序退出中,请等待...";
sleep(1); sleep(1);
InfoL << "程序退出完毕!"; InfoL << "程序退出完毕!";
return 0; return 0;
} }
#ifndef DISABLE_MAIN #ifndef DISABLE_MAIN

View File

@ -47,73 +47,73 @@ AACEncoder::AACEncoder() {
} }
AACEncoder::~AACEncoder() { AACEncoder::~AACEncoder() {
if (_hEncoder != nullptr) { if (_hEncoder != nullptr) {
faacEncClose(_hEncoder); faacEncClose(_hEncoder);
_hEncoder = nullptr; _hEncoder = nullptr;
} }
if (_pucAacBuf != nullptr) { if (_pucAacBuf != nullptr) {
delete[] _pucAacBuf; delete[] _pucAacBuf;
_pucAacBuf = nullptr; _pucAacBuf = nullptr;
} }
if (_pucPcmBuf != nullptr) { if (_pucPcmBuf != nullptr) {
delete[] _pucPcmBuf; delete[] _pucPcmBuf;
_pucPcmBuf = nullptr; _pucPcmBuf = nullptr;
} }
} }
bool AACEncoder::init(int iSampleRate, int iChannels, int iSampleBit) { bool AACEncoder::init(int iSampleRate, int iChannels, int iSampleBit) {
if (iSampleBit != 16) { if (iSampleBit != 16) {
return false; return false;
} }
// (1) Open FAAC engine // (1) Open FAAC engine
_hEncoder = faacEncOpen(iSampleRate, iChannels, &_ulInputSamples, _hEncoder = faacEncOpen(iSampleRate, iChannels, &_ulInputSamples,
&_ulMaxOutputBytes); &_ulMaxOutputBytes);
if (_hEncoder == NULL) { if (_hEncoder == NULL) {
return false; return false;
} }
_pucAacBuf = new unsigned char[_ulMaxOutputBytes]; _pucAacBuf = new unsigned char[_ulMaxOutputBytes];
_ulMaxInputBytes = _ulInputSamples * iSampleBit / 8; _ulMaxInputBytes = _ulInputSamples * iSampleBit / 8;
_pucPcmBuf = new unsigned char[_ulMaxInputBytes * 4]; _pucPcmBuf = new unsigned char[_ulMaxInputBytes * 4];
// (2.1) Get current encoding configuration // (2.1) Get current encoding configuration
faacEncConfigurationPtr pConfiguration = faacEncGetCurrentConfiguration(_hEncoder); faacEncConfigurationPtr pConfiguration = faacEncGetCurrentConfiguration(_hEncoder);
if (pConfiguration == NULL) { if (pConfiguration == NULL) {
faacEncClose(_hEncoder); faacEncClose(_hEncoder);
return false; return false;
} }
pConfiguration->aacObjectType =LOW; pConfiguration->aacObjectType =LOW;
pConfiguration->mpegVersion = 4; pConfiguration->mpegVersion = 4;
pConfiguration->useTns = 1; pConfiguration->useTns = 1;
pConfiguration->shortctl = SHORTCTL_NORMAL; pConfiguration->shortctl = SHORTCTL_NORMAL;
pConfiguration->useLfe = 1; pConfiguration->useLfe = 1;
pConfiguration->allowMidside = 1; pConfiguration->allowMidside = 1;
pConfiguration->bitRate = 0; pConfiguration->bitRate = 0;
pConfiguration->bandWidth = 0; pConfiguration->bandWidth = 0;
pConfiguration->quantqual = 50; pConfiguration->quantqual = 50;
pConfiguration->outputFormat = 1; pConfiguration->outputFormat = 1;
pConfiguration->inputFormat = FAAC_INPUT_16BIT; pConfiguration->inputFormat = FAAC_INPUT_16BIT;
// (2.2) Set encoding configuration // (2.2) Set encoding configuration
if(!faacEncSetConfiguration(_hEncoder, pConfiguration)){ if(!faacEncSetConfiguration(_hEncoder, pConfiguration)){
ErrorL << "faacEncSetConfiguration failed"; ErrorL << "faacEncSetConfiguration failed";
faacEncClose(_hEncoder); faacEncClose(_hEncoder);
return false; return false;
} }
return true; return true;
} }
int AACEncoder::inputData(char *pcPcmBufr, int iLen, unsigned char **ppucOutBuffer) { int AACEncoder::inputData(char *pcPcmBufr, int iLen, unsigned char **ppucOutBuffer) {
memcpy(_pucPcmBuf + _uiPcmLen, pcPcmBufr, iLen); memcpy(_pucPcmBuf + _uiPcmLen, pcPcmBufr, iLen);
_uiPcmLen += iLen; _uiPcmLen += iLen;
if (_uiPcmLen < _ulMaxInputBytes) { if (_uiPcmLen < _ulMaxInputBytes) {
return 0; return 0;
} }
int nRet = faacEncEncode(_hEncoder, (int32_t *) (_pucPcmBuf), _ulInputSamples, _pucAacBuf, _ulMaxOutputBytes); int nRet = faacEncEncode(_hEncoder, (int32_t *) (_pucPcmBuf), _ulInputSamples, _pucAacBuf, _ulMaxOutputBytes);
_uiPcmLen -= _ulMaxInputBytes; _uiPcmLen -= _ulMaxInputBytes;
memmove(_pucPcmBuf, _pucPcmBuf + _ulMaxInputBytes, _uiPcmLen); memmove(_pucPcmBuf, _pucPcmBuf + _ulMaxInputBytes, _uiPcmLen);
*ppucOutBuffer = _pucAacBuf; *ppucOutBuffer = _pucAacBuf;
return nRet; return nRet;
} }
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -32,21 +32,21 @@ namespace mediakit {
class AACEncoder { class AACEncoder {
public: public:
AACEncoder(void); AACEncoder(void);
virtual ~AACEncoder(void); virtual ~AACEncoder(void);
bool init(int iSampleRate, int iAudioChannel, int iAudioSampleBit); bool init(int iSampleRate, int iAudioChannel, int iAudioSampleBit);
int inputData(char *pcData, int iLen, unsigned char **ppucOutBuffer); int inputData(char *pcData, int iLen, unsigned char **ppucOutBuffer);
private: private:
unsigned char *_pucPcmBuf = nullptr; unsigned char *_pucPcmBuf = nullptr;
unsigned int _uiPcmLen = 0; unsigned int _uiPcmLen = 0;
unsigned char *_pucAacBuf = nullptr; unsigned char *_pucAacBuf = nullptr;
void *_hEncoder = nullptr; void *_hEncoder = nullptr;
unsigned long _ulInputSamples = 0; unsigned long _ulInputSamples = 0;
unsigned long _ulMaxInputBytes = 0; unsigned long _ulMaxInputBytes = 0;
unsigned long _ulMaxOutputBytes = 0; unsigned long _ulMaxOutputBytes = 0;
}; };

View File

@ -38,21 +38,21 @@ H264Encoder::H264Encoder() {
} }
H264Encoder::~H264Encoder() { H264Encoder::~H264Encoder() {
//* 清除图像区域 //* 清除图像区域
if (_pPicIn) { if (_pPicIn) {
delete _pPicIn; delete _pPicIn;
_pPicIn = nullptr; _pPicIn = nullptr;
} }
if (_pPicOut) { if (_pPicOut) {
delete _pPicOut; delete _pPicOut;
_pPicOut = nullptr; _pPicOut = nullptr;
} }
//* 关闭编码器句柄 //* 关闭编码器句柄
if (_pX264Handle) { if (_pX264Handle) {
x264_encoder_close(_pX264Handle); x264_encoder_close(_pX264Handle);
_pX264Handle = nullptr; _pX264Handle = nullptr;
} }
} }
@ -229,122 +229,122 @@ Value的值就是fps。
} x264_param_t;*/ } x264_param_t;*/
bool H264Encoder::init(int iWidth, int iHeight, int iFps) { bool H264Encoder::init(int iWidth, int iHeight, int iFps) {
if (_pX264Handle) { if (_pX264Handle) {
return true; return true;
} }
x264_param_t X264Param, *pX264Param = &X264Param; x264_param_t X264Param, *pX264Param = &X264Param;
//* 配置参数 //* 配置参数
//* 使用默认参数 //* 使用默认参数
x264_param_default_preset(pX264Param, "ultrafast", "zerolatency"); x264_param_default_preset(pX264Param, "ultrafast", "zerolatency");
//* cpuFlags //* cpuFlags
pX264Param->i_threads = X264_SYNC_LOOKAHEAD_AUTO; //* 取空缓冲区继续使用不死锁的保证. pX264Param->i_threads = X264_SYNC_LOOKAHEAD_AUTO; //* 取空缓冲区继续使用不死锁的保证.
//* video Properties //* video Properties
pX264Param->i_width = iWidth; //* 宽度. pX264Param->i_width = iWidth; //* 宽度.
pX264Param->i_height = iHeight; //* 高度 pX264Param->i_height = iHeight; //* 高度
pX264Param->i_frame_total = 0; //* 编码总帧数.不知道用0. pX264Param->i_frame_total = 0; //* 编码总帧数.不知道用0.
pX264Param->i_keyint_max = iFps * 3; //ffmpeg:gop_size 关键帧最大间隔 pX264Param->i_keyint_max = iFps * 3; //ffmpeg:gop_size 关键帧最大间隔
pX264Param->i_keyint_min = iFps * 1; //ffmpeg:keyint_min 关键帧最小间隔 pX264Param->i_keyint_min = iFps * 1; //ffmpeg:keyint_min 关键帧最小间隔
//* Rate control Parameters //* Rate control Parameters
pX264Param->rc.i_bitrate = 5000; //* 码率(比特率,单位Kbps) pX264Param->rc.i_bitrate = 5000; //* 码率(比特率,单位Kbps)
pX264Param->rc.i_qp_step = 1; //最大的在帧与帧之间进行切变的量化因子的变化量。ffmpeg:max_qdiff pX264Param->rc.i_qp_step = 1; //最大的在帧与帧之间进行切变的量化因子的变化量。ffmpeg:max_qdiff
pX264Param->rc.i_qp_min = 10; //ffmpeg:qmin;最小的量化因子。取值范围1-51。建议在10-30之间。 pX264Param->rc.i_qp_min = 10; //ffmpeg:qmin;最小的量化因子。取值范围1-51。建议在10-30之间。
pX264Param->rc.i_qp_max = 41; //ffmpeg:qmax;最大的量化因子。取值范围1-51。建议在10-30之间。 pX264Param->rc.i_qp_max = 41; //ffmpeg:qmax;最大的量化因子。取值范围1-51。建议在10-30之间。
pX264Param->rc.f_qcompress = 0.6;//ffmpeg:qcompress 量化器压缩比率0-1.越小则比特率越区域固定,但是越高越使量化器参数越固定 pX264Param->rc.f_qcompress = 0.6;//ffmpeg:qcompress 量化器压缩比率0-1.越小则比特率越区域固定,但是越高越使量化器参数越固定
pX264Param->analyse.i_me_range = 16; //ffmpeg:me_range 运动侦测的半径 pX264Param->analyse.i_me_range = 16; //ffmpeg:me_range 运动侦测的半径
pX264Param->i_frame_reference = 3; //ffmpeg:refsB和P帧向前预测参考的帧数。取值范围1-16。 pX264Param->i_frame_reference = 3; //ffmpeg:refsB和P帧向前预测参考的帧数。取值范围1-16。
//该值不影响解码的速度,但是越大解码 //该值不影响解码的速度,但是越大解码
//所需的内存越大。这个值在一般情况下 //所需的内存越大。这个值在一般情况下
//越大效果越好但是超过6以后效果就 //越大效果越好但是超过6以后效果就
//不明显了。 //不明显了。
pX264Param->analyse.i_trellis = 1; //ffmpeg:trellis pX264Param->analyse.i_trellis = 1; //ffmpeg:trellis
//pX264Param->analyse.i_me_method=X264_ME_DIA;//ffmpeg:me_method ME_ZERO 运动侦测的方式 //pX264Param->analyse.i_me_method=X264_ME_DIA;//ffmpeg:me_method ME_ZERO 运动侦测的方式
pX264Param->rc.f_qblur = 0.5; //ffmpeg:qblur pX264Param->rc.f_qblur = 0.5; //ffmpeg:qblur
//* bitstream parameters //* bitstream parameters
/*open-GOP /*open-GOP
B帧的时候才会出现open-GOP B帧的时候才会出现open-GOP
GOP里面的某一帧在解码时要依赖于前一个GOP的某些帧 GOP里面的某一帧在解码时要依赖于前一个GOP的某些帧
GOP就称为open-GOP GOP就称为open-GOP
open-GOP码流 open-GOP码流
x264里面open-GOP是默认关闭的 x264里面open-GOP是默认关闭的
:I0 B0 B1 P0 B2 B3...open-GOP码流I帧后面紧跟B帧 :I0 B0 B1 P0 B2 B3...open-GOP码流I帧后面紧跟B帧
B0 B1的解码需要用到I0前面一个GOP的数据B0 B1的dts是小于I0的 B0 B1的解码需要用到I0前面一个GOP的数据B0 B1的dts是小于I0的
: I0 P0 B0 B1 P1 B2 B3...close-GOP码流 : I0 P0 B0 B1 P1 B2 B3...close-GOP码流
I0后面所有帧的解码不依赖于I0前面的帧I0后面所有帧的dts都比I0的大 I0后面所有帧的解码不依赖于I0前面的帧I0后面所有帧的dts都比I0的大
IDR0 B0 B1 P0 B2 B3...GOP是close-GOPB0,B1虽然dst比IDR0小 IDR0 B0 B1 P0 B2 B3...GOP是close-GOPB0,B1虽然dst比IDR0小
B0,B1参考不到前向GOP帧 B0,B1参考不到前向GOP帧
: ...P0 B1 B2 P3 B4 B5 I6这就会输出open-Gop码流 P0 P3 B1 B2 I6 B4 B5... : ...P0 B1 B2 P3 B4 B5 I6这就会输出open-Gop码流 P0 P3 B1 B2 I6 B4 B5...
B4 B5的解码依赖P3 B4 B5的解码依赖P3
...P0 B1 B2 P3 B4 P5 I6这样就不会输出open-GOP码流P0 P3 B1 B2 P5 B4 I6... ...P0 B1 B2 P3 B4 P5 I6这样就不会输出open-GOP码流P0 P3 B1 B2 P5 B4 I6...
I6前面的第5帧是设置为B帧还是P帧 I6前面的第5帧是设置为B帧还是P帧
GOP的最后一帧5B帧 GOP的最后一帧5B帧
open-GOP,P帧就是close-GOP open-GOP,P帧就是close-GOP
B帧压缩性能好于P帧open-GOP在编码性能上稍微优于close-GOP B帧压缩性能好于P帧open-GOP在编码性能上稍微优于close-GOP
opne-GOP关闭的好*/ opne-GOP关闭的好*/
pX264Param->b_open_gop = 0; pX264Param->b_open_gop = 0;
pX264Param->i_bframe = 0; //最大B帧数. pX264Param->i_bframe = 0; //最大B帧数.
pX264Param->i_bframe_pyramid = 0; pX264Param->i_bframe_pyramid = 0;
pX264Param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS; pX264Param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS;
//* Log //* Log
pX264Param->i_log_level = X264_LOG_ERROR; pX264Param->i_log_level = X264_LOG_ERROR;
//* muxing parameters //* muxing parameters
pX264Param->i_fps_den = 1; //* 帧率分母 pX264Param->i_fps_den = 1; //* 帧率分母
pX264Param->i_fps_num = iFps; //* 帧率分子 pX264Param->i_fps_num = iFps; //* 帧率分子
pX264Param->i_timebase_den = pX264Param->i_fps_num; pX264Param->i_timebase_den = pX264Param->i_fps_num;
pX264Param->i_timebase_num = pX264Param->i_fps_den; pX264Param->i_timebase_num = pX264Param->i_fps_den;
pX264Param->analyse.i_subpel_refine = 1; //这个参数控制在运动估算过程中质量和速度的权衡。Subq=5可以压缩>10%于subq=1。1-7 pX264Param->analyse.i_subpel_refine = 1; //这个参数控制在运动估算过程中质量和速度的权衡。Subq=5可以压缩>10%于subq=1。1-7
pX264Param->analyse.b_fast_pskip = 1; //在P帧内执行早期快速跳跃探测。这个经常在没有任何损失的前提下提高了速度。 pX264Param->analyse.b_fast_pskip = 1; //在P帧内执行早期快速跳跃探测。这个经常在没有任何损失的前提下提高了速度。
pX264Param->b_annexb = 1; //1前面为0x00000001,0为nal长度 pX264Param->b_annexb = 1; //1前面为0x00000001,0为nal长度
pX264Param->b_repeat_headers = 1; //关键帧前面是否放sps跟pps帧0 否 1 pX264Param->b_repeat_headers = 1; //关键帧前面是否放sps跟pps帧0 否 1
//* 设置Profile.使用baseline //* 设置Profile.使用baseline
x264_param_apply_profile(pX264Param, "high"); x264_param_apply_profile(pX264Param, "high");
//* 打开编码器句柄,通过x264_encoder_parameters得到设置给X264 //* 打开编码器句柄,通过x264_encoder_parameters得到设置给X264
//* 的参数.通过x264_encoder_reconfig更新X264的参数 //* 的参数.通过x264_encoder_reconfig更新X264的参数
_pX264Handle = x264_encoder_open(pX264Param); _pX264Handle = x264_encoder_open(pX264Param);
if (!_pX264Handle) { if (!_pX264Handle) {
return false; return false;
} }
_pPicIn = new x264_picture_t; _pPicIn = new x264_picture_t;
_pPicOut = new x264_picture_t; _pPicOut = new x264_picture_t;
x264_picture_init(_pPicIn); x264_picture_init(_pPicIn);
x264_picture_init(_pPicOut); x264_picture_init(_pPicOut);
_pPicIn->img.i_csp = X264_CSP_I420; _pPicIn->img.i_csp = X264_CSP_I420;
_pPicIn->img.i_plane = 3; _pPicIn->img.i_plane = 3;
return true; return true;
} }
int H264Encoder::inputData(char* apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame** ppFrame) { int H264Encoder::inputData(char* apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame** ppFrame) {
//TimeTicker1(5); //TimeTicker1(5);
_pPicIn->img.i_stride[0] = aiYuvLen[0]; _pPicIn->img.i_stride[0] = aiYuvLen[0];
_pPicIn->img.i_stride[1] = aiYuvLen[1]; _pPicIn->img.i_stride[1] = aiYuvLen[1];
_pPicIn->img.i_stride[2] = aiYuvLen[2]; _pPicIn->img.i_stride[2] = aiYuvLen[2];
_pPicIn->img.plane[0] = (uint8_t *) apcYuv[0]; _pPicIn->img.plane[0] = (uint8_t *) apcYuv[0];
_pPicIn->img.plane[1] = (uint8_t *) apcYuv[1]; _pPicIn->img.plane[1] = (uint8_t *) apcYuv[1];
_pPicIn->img.plane[2] = (uint8_t *) apcYuv[2]; _pPicIn->img.plane[2] = (uint8_t *) apcYuv[2];
_pPicIn->i_pts = i64Pts; _pPicIn->i_pts = i64Pts;
int iNal; int iNal;
x264_nal_t* pNals; x264_nal_t* pNals;
int iResult = x264_encoder_encode(_pX264Handle, &pNals, &iNal, _pPicIn, int iResult = x264_encoder_encode(_pX264Handle, &pNals, &iNal, _pPicIn,
_pPicOut); _pPicOut);
if (iResult <= 0) { if (iResult <= 0) {
return 0; return 0;
} }
for (int i = 0; i < iNal; i++) { for (int i = 0; i < iNal; i++) {
x264_nal_t pNal = pNals[i]; x264_nal_t pNal = pNals[i];
_aFrames[i].iType = pNal.i_type; _aFrames[i].iType = pNal.i_type;
_aFrames[i].iLength = pNal.i_payload; _aFrames[i].iLength = pNal.i_payload;
_aFrames[i].pucData = pNal.p_payload; _aFrames[i].pucData = pNal.p_payload;
} }
*ppFrame = _aFrames; *ppFrame = _aFrames;
return iNal; return iNal;
} }
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -42,21 +42,21 @@ namespace mediakit {
class H264Encoder { class H264Encoder {
public: public:
typedef struct { typedef struct {
int iType; int iType;
int iLength; int iLength;
uint8_t *pucData; uint8_t *pucData;
} H264Frame; } H264Frame;
H264Encoder(void); H264Encoder(void);
virtual ~H264Encoder(void); virtual ~H264Encoder(void);
bool init(int iWidth, int iHeight, int iFps); bool init(int iWidth, int iHeight, int iFps);
int inputData(char *apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame **ppFrame); int inputData(char *apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame **ppFrame);
private: private:
x264_t* _pX264Handle = nullptr; x264_t* _pX264Handle = nullptr;
x264_picture_t* _pPicIn = nullptr; x264_picture_t* _pPicIn = nullptr;
x264_picture_t* _pPicOut = nullptr; x264_picture_t* _pPicOut = nullptr;
H264Frame _aFrames[10]; H264Frame _aFrames[10];
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -42,8 +42,8 @@ DevChannel::DevChannel(const string &strVhost,
const string &strApp, const string &strApp,
const string &strId, const string &strId,
float fDuration, float fDuration,
bool bEanbleRtsp, bool bEanbleRtsp,
bool bEanbleRtmp, bool bEanbleRtmp,
bool bEanbleHls, bool bEanbleHls,
bool bEnableMp4) : bool bEnableMp4) :
MultiMediaSourceMuxer(strVhost, strApp, strId, fDuration, bEanbleRtsp, bEanbleRtmp, bEanbleHls, bEnableMp4) {} MultiMediaSourceMuxer(strVhost, strApp, strId, fDuration, bEanbleRtsp, bEanbleRtmp, bEanbleHls, bEnableMp4) {}
@ -52,50 +52,50 @@ DevChannel::~DevChannel() {}
#ifdef ENABLE_X264 #ifdef ENABLE_X264
void DevChannel::inputYUV(char* apcYuv[3], int aiYuvLen[3], uint32_t uiStamp) { void DevChannel::inputYUV(char* apcYuv[3], int aiYuvLen[3], uint32_t uiStamp) {
//TimeTicker1(50); //TimeTicker1(50);
if (!_pH264Enc) { if (!_pH264Enc) {
_pH264Enc.reset(new H264Encoder()); _pH264Enc.reset(new H264Encoder());
if (!_pH264Enc->init(_video->iWidth, _video->iHeight, _video->iFrameRate)) { if (!_pH264Enc->init(_video->iWidth, _video->iHeight, _video->iFrameRate)) {
_pH264Enc.reset(); _pH264Enc.reset();
WarnL << "H264Encoder init failed!"; WarnL << "H264Encoder init failed!";
} }
} }
if (_pH264Enc) { if (_pH264Enc) {
H264Encoder::H264Frame *pOut; H264Encoder::H264Frame *pOut;
int iFrames = _pH264Enc->inputData(apcYuv, aiYuvLen, uiStamp, &pOut); int iFrames = _pH264Enc->inputData(apcYuv, aiYuvLen, uiStamp, &pOut);
for (int i = 0; i < iFrames; i++) { for (int i = 0; i < iFrames; i++) {
inputH264((char *) pOut[i].pucData, pOut[i].iLength, uiStamp); inputH264((char *) pOut[i].pucData, pOut[i].iLength, uiStamp);
} }
} }
} }
#endif //ENABLE_X264 #endif //ENABLE_X264
#ifdef ENABLE_FAAC #ifdef ENABLE_FAAC
void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) { void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) {
if (!_pAacEnc) { if (!_pAacEnc) {
_pAacEnc.reset(new AACEncoder()); _pAacEnc.reset(new AACEncoder());
if (!_pAacEnc->init(_audio->iSampleRate, _audio->iChannel, _audio->iSampleBit)) { if (!_pAacEnc->init(_audio->iSampleRate, _audio->iChannel, _audio->iSampleBit)) {
_pAacEnc.reset(); _pAacEnc.reset();
WarnL << "AACEncoder init failed!"; WarnL << "AACEncoder init failed!";
} }
} }
if (_pAacEnc) { if (_pAacEnc) {
unsigned char *pucOut; unsigned char *pucOut;
int iRet = _pAacEnc->inputData(pcData, iDataLen, &pucOut); int iRet = _pAacEnc->inputData(pcData, iDataLen, &pucOut);
if (iRet > 0) { if (iRet > 0) {
inputAAC((char *) pucOut, iRet, uiStamp); inputAAC((char *) pucOut, iRet, uiStamp);
} }
} }
} }
#endif //ENABLE_FAAC #endif //ENABLE_FAAC
void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32_t pts) { void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32_t pts) {
if(dts == 0){ if(dts == 0){
dts = (uint32_t)_aTicker[0].elapsedTime(); dts = (uint32_t)_aTicker[0].elapsedTime();
}
if(pts == 0){
pts = dts;
} }
if(pts == 0){
pts = dts;
}
int prefixeSize; int prefixeSize;
if (memcmp("\x00\x00\x00\x01", pcData, 4) == 0) { if (memcmp("\x00\x00\x00\x01", pcData, 4) == 0) {
prefixeSize = 4; prefixeSize = 4;
@ -105,46 +105,46 @@ void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t dts,uint32
prefixeSize = 0; prefixeSize = 0;
} }
H264Frame::Ptr frame = std::make_shared<H264Frame>(); H264Frame::Ptr frame = std::make_shared<H264Frame>();
frame->_dts = dts; frame->_dts = dts;
frame->_pts = pts; frame->_pts = pts;
frame->_buffer.assign("\x00\x00\x00\x01",4); frame->_buffer.assign("\x00\x00\x00\x01",4);
frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize);
frame->_prefix_size = 4; frame->_prefix_size = 4;
inputFrame(frame); inputFrame(frame);
} }
void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32_t pts) { void DevChannel::inputH265(const char* pcData, int iDataLen, uint32_t dts,uint32_t pts) {
if(dts == 0){ if(dts == 0){
dts = (uint32_t)_aTicker[0].elapsedTime(); dts = (uint32_t)_aTicker[0].elapsedTime();
} }
if(pts == 0){ if(pts == 0){
pts = dts; pts = dts;
} }
int prefixeSize; int prefixeSize;
if (memcmp("\x00\x00\x00\x01", pcData, 4) == 0) { if (memcmp("\x00\x00\x00\x01", pcData, 4) == 0) {
prefixeSize = 4; prefixeSize = 4;
} else if (memcmp("\x00\x00\x01", pcData, 3) == 0) { } else if (memcmp("\x00\x00\x01", pcData, 3) == 0) {
prefixeSize = 3; prefixeSize = 3;
} else { } else {
prefixeSize = 0; prefixeSize = 0;
} }
H265Frame::Ptr frame = std::make_shared<H265Frame>(); H265Frame::Ptr frame = std::make_shared<H265Frame>();
frame->_dts = dts; frame->_dts = dts;
frame->_pts = pts; frame->_pts = pts;
frame->_buffer.assign("\x00\x00\x00\x01",4); frame->_buffer.assign("\x00\x00\x00\x01",4);
frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize); frame->_buffer.append(pcData + prefixeSize, iDataLen - prefixeSize);
frame->_prefix_size = 4; frame->_prefix_size = 4;
inputFrame(frame); inputFrame(frame);
} }
void DevChannel::inputAAC(const char* pcData, int iDataLen, uint32_t uiStamp,bool withAdtsHeader) { void DevChannel::inputAAC(const char* pcData, int iDataLen, uint32_t uiStamp,bool withAdtsHeader) {
if(withAdtsHeader){ if(withAdtsHeader){
inputAAC(pcData+7,iDataLen-7,uiStamp,pcData); inputAAC(pcData+7,iDataLen-7,uiStamp,pcData);
} else if(_audio) { } else if(_audio) {
inputAAC(pcData,iDataLen,uiStamp,(char *)_adtsHeader); inputAAC(pcData,iDataLen,uiStamp,(char *)_adtsHeader);
} }
} }
void DevChannel::inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,const char *pcAdtsHeader){ void DevChannel::inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,const char *pcAdtsHeader){
@ -152,54 +152,54 @@ void DevChannel::inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t u
uiStamp = (uint32_t)_aTicker[1].elapsedTime(); uiStamp = (uint32_t)_aTicker[1].elapsedTime();
} }
if(pcAdtsHeader + 7 == pcDataWithoutAdts){ if(pcAdtsHeader + 7 == pcDataWithoutAdts){
inputFrame(std::make_shared<AACFrameNoCacheAble>((char *)pcDataWithoutAdts - 7,iDataLen + 7,uiStamp,7)); inputFrame(std::make_shared<AACFrameNoCacheAble>((char *)pcDataWithoutAdts - 7,iDataLen + 7,uiStamp,7));
} else { } else {
char *dataWithAdts = new char[iDataLen + 7]; char *dataWithAdts = new char[iDataLen + 7];
memcpy(dataWithAdts,pcAdtsHeader,7); memcpy(dataWithAdts,pcAdtsHeader,7);
memcpy(dataWithAdts + 7 , pcDataWithoutAdts , iDataLen); memcpy(dataWithAdts + 7 , pcDataWithoutAdts , iDataLen);
inputFrame(std::make_shared<AACFrameNoCacheAble>(dataWithAdts,iDataLen + 7,uiStamp,7)); inputFrame(std::make_shared<AACFrameNoCacheAble>(dataWithAdts,iDataLen + 7,uiStamp,7));
delete [] dataWithAdts; delete [] dataWithAdts;
} }
} }
void DevChannel::initVideo(const VideoInfo& info) { void DevChannel::initVideo(const VideoInfo& info) {
_video = std::make_shared<VideoInfo>(info); _video = std::make_shared<VideoInfo>(info);
addTrack(std::make_shared<H264Track>()); addTrack(std::make_shared<H264Track>());
} }
void DevChannel::initH265Video(const VideoInfo &info){ void DevChannel::initH265Video(const VideoInfo &info){
_video = std::make_shared<VideoInfo>(info); _video = std::make_shared<VideoInfo>(info);
addTrack(std::make_shared<H265Track>()); addTrack(std::make_shared<H265Track>());
} }
void DevChannel::initAudio(const AudioInfo& info) { void DevChannel::initAudio(const AudioInfo& info) {
_audio = std::make_shared<AudioInfo>(info); _audio = std::make_shared<AudioInfo>(info);
addTrack(std::make_shared<AACTrack>()); addTrack(std::make_shared<AACTrack>());
AACFrame adtsHeader; AACFrame adtsHeader;
adtsHeader.syncword = 0x0FFF; adtsHeader.syncword = 0x0FFF;
adtsHeader.id = 0; adtsHeader.id = 0;
adtsHeader.layer = 0; adtsHeader.layer = 0;
adtsHeader.protection_absent = 1; adtsHeader.protection_absent = 1;
adtsHeader.profile = info.iProfile;//audioObjectType - 1; adtsHeader.profile = info.iProfile;//audioObjectType - 1;
int i = 0; int i = 0;
for(auto rate : samplingFrequencyTable){ for(auto rate : samplingFrequencyTable){
if(rate == info.iSampleRate){ if(rate == info.iSampleRate){
adtsHeader.sf_index = i; adtsHeader.sf_index = i;
}; };
++i; ++i;
} }
adtsHeader.private_bit = 0; adtsHeader.private_bit = 0;
adtsHeader.channel_configuration = info.iChannel; adtsHeader.channel_configuration = info.iChannel;
adtsHeader.original = 0; adtsHeader.original = 0;
adtsHeader.home = 0; adtsHeader.home = 0;
adtsHeader.copyright_identification_bit = 0; adtsHeader.copyright_identification_bit = 0;
adtsHeader.copyright_identification_start = 0; adtsHeader.copyright_identification_start = 0;
adtsHeader.aac_frame_length = 7; adtsHeader.aac_frame_length = 7;
adtsHeader.adts_buffer_fullness = 2047; adtsHeader.adts_buffer_fullness = 2047;
adtsHeader.no_raw_data_blocks_in_frame = 0; adtsHeader.no_raw_data_blocks_in_frame = 0;
writeAdtsHeader(adtsHeader,_adtsHeader); writeAdtsHeader(adtsHeader,_adtsHeader);
} }
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -51,16 +51,16 @@ namespace mediakit {
class VideoInfo { class VideoInfo {
public: public:
int iWidth; int iWidth;
int iHeight; int iHeight;
float iFrameRate; float iFrameRate;
}; };
class AudioInfo { class AudioInfo {
public: public:
int iChannel; int iChannel;
int iSampleBit; int iSampleBit;
int iSampleRate; int iSampleRate;
int iProfile; int iProfile;
}; };
/** /**
@ -68,82 +68,82 @@ public:
*/ */
class DevChannel : public MultiMediaSourceMuxer{ class DevChannel : public MultiMediaSourceMuxer{
public: public:
typedef std::shared_ptr<DevChannel> Ptr; typedef std::shared_ptr<DevChannel> Ptr;
//fDuration<=0为直播否则为点播 //fDuration<=0为直播否则为点播
DevChannel(const string &strVhost, DevChannel(const string &strVhost,
const string &strApp, const string &strApp,
const string &strId, const string &strId,
float fDuration = 0, float fDuration = 0,
bool bEanbleRtsp = true, bool bEanbleRtsp = true,
bool bEanbleRtmp = true, bool bEanbleRtmp = true,
bool bEanbleHls = true, bool bEanbleHls = true,
bool bEnableMp4 = false); bool bEnableMp4 = false);
virtual ~DevChannel(); virtual ~DevChannel();
/** /**
* h264视频Track * h264视频Track
* MultiMediaSourceMuxer::addTrack(H264Track::Ptr ); * MultiMediaSourceMuxer::addTrack(H264Track::Ptr );
* @param info * @param info
*/ */
void initVideo(const VideoInfo &info); void initVideo(const VideoInfo &info);
/** /**
* h265视频Track * h265视频Track
* @param info * @param info
*/ */
void initH265Video(const VideoInfo &info); void initH265Video(const VideoInfo &info);
/** /**
* aac音频Track * aac音频Track
* MultiMediaSourceMuxer::addTrack(AACTrack::Ptr ); * MultiMediaSourceMuxer::addTrack(AACTrack::Ptr );
* @param info * @param info
*/ */
void initAudio(const AudioInfo &info); void initAudio(const AudioInfo &info);
/** /**
* 264 * 264
* @param pcData 264 * @param pcData 264
* @param iDataLen * @param iDataLen
* @param dts 0 * @param dts 0
* @param pts 0dts * @param pts 0dts
*/ */
void inputH264(const char *pcData, int iDataLen, uint32_t dts,uint32_t pts = 0); void inputH264(const char *pcData, int iDataLen, uint32_t dts,uint32_t pts = 0);
/** /**
* 265 * 265
* @param pcData 265 * @param pcData 265
* @param iDataLen * @param iDataLen
* @param dts 0 * @param dts 0
* @param pts 0dts * @param pts 0dts
*/ */
void inputH265(const char *pcData, int iDataLen, uint32_t dts,uint32_t pts = 0); void inputH265(const char *pcData, int iDataLen, uint32_t dts,uint32_t pts = 0);
/** /**
* adts头的aac帧 * adts头的aac帧
* @param pcDataWithAdts adts头的aac帧 * @param pcDataWithAdts adts头的aac帧
* @param iDataLen * @param iDataLen
* @param uiStamp 0 * @param uiStamp 0
* @param withAdtsHeader adts头 * @param withAdtsHeader adts头
*/ */
void inputAAC(const char *pcDataWithAdts, int iDataLen, uint32_t uiStamp, bool withAdtsHeader = true); void inputAAC(const char *pcDataWithAdts, int iDataLen, uint32_t uiStamp, bool withAdtsHeader = true);
/** /**
* adts头的aac帧 * adts头的aac帧
* @param pcDataWithoutAdts adts头的aac帧 * @param pcDataWithoutAdts adts头的aac帧
* @param iDataLen * @param iDataLen
* @param uiStamp * @param uiStamp
* @param pcAdtsHeader adts头 * @param pcAdtsHeader adts头
*/ */
void inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,const char *pcAdtsHeader); void inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,const char *pcAdtsHeader);
#ifdef ENABLE_X264 #ifdef ENABLE_X264
/** /**
* yuv420p视频帧inputH264方法 * yuv420p视频帧inputH264方法
* @param apcYuv * @param apcYuv
* @param aiYuvLen * @param aiYuvLen
* @param uiStamp * @param uiStamp
*/ */
void inputYUV(char *apcYuv[3], int aiYuvLen[3], uint32_t uiStamp); void inputYUV(char *apcYuv[3], int aiYuvLen[3], uint32_t uiStamp);
#endif //ENABLE_X264 #endif //ENABLE_X264
@ -160,11 +160,11 @@ public:
private: private:
#ifdef ENABLE_X264 #ifdef ENABLE_X264
std::shared_ptr<H264Encoder> _pH264Enc; std::shared_ptr<H264Encoder> _pH264Enc;
#endif //ENABLE_X264 #endif //ENABLE_X264
#ifdef ENABLE_FAAC #ifdef ENABLE_FAAC
std::shared_ptr<AACEncoder> _pAacEnc; std::shared_ptr<AACEncoder> _pAacEnc;
#endif //ENABLE_FAAC #endif //ENABLE_FAAC
std::shared_ptr<VideoInfo> _video; std::shared_ptr<VideoInfo> _video;
std::shared_ptr<AudioInfo> _audio; std::shared_ptr<AudioInfo> _audio;

View File

@ -42,15 +42,15 @@ bool loadIniConfig(const char *ini_path){
}else{ }else{
ini = exePath() + ".ini"; ini = exePath() + ".ini";
} }
try{ try{
mINI::Instance().parseFile(ini); mINI::Instance().parseFile(ini);
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastReloadConfig); NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastReloadConfig);
return true; return true;
}catch (std::exception &ex) { }catch (std::exception &ex) {
InfoL << "dump ini file to:" << ini; InfoL << "dump ini file to:" << ini;
mINI::Instance().dumpFile(ini); mINI::Instance().dumpFile(ini);
return false; return false;
} }
} }
////////////广播名称/////////// ////////////广播名称///////////
namespace Broadcast { namespace Broadcast {
@ -90,12 +90,12 @@ onceToken token([](){
mINI::Instance()[kStreamNoneReaderDelayMS] = 20 * 1000; mINI::Instance()[kStreamNoneReaderDelayMS] = 20 * 1000;
mINI::Instance()[kMaxStreamWaitTimeMS] = 15 * 1000; mINI::Instance()[kMaxStreamWaitTimeMS] = 15 * 1000;
mINI::Instance()[kEnableVhost] = 0; mINI::Instance()[kEnableVhost] = 0;
mINI::Instance()[kUltraLowDelay] = 1; mINI::Instance()[kUltraLowDelay] = 1;
mINI::Instance()[kAddMuteAudio] = 1; mINI::Instance()[kAddMuteAudio] = 1;
mINI::Instance()[kResetWhenRePlay] = 1; mINI::Instance()[kResetWhenRePlay] = 1;
mINI::Instance()[kPublishToRtxp] = 1; mINI::Instance()[kPublishToRtxp] = 1;
mINI::Instance()[kPublishToHls] = 1; mINI::Instance()[kPublishToHls] = 1;
mINI::Instance()[kPublishToMP4] = 0; mINI::Instance()[kPublishToMP4] = 0;
},nullptr); },nullptr);
}//namespace General }//namespace General
@ -117,26 +117,26 @@ const string kRootPath = HTTP_FIELD"rootPath";
const string kNotFound = HTTP_FIELD"notFound"; const string kNotFound = HTTP_FIELD"notFound";
onceToken token([](){ onceToken token([](){
mINI::Instance()[kSendBufSize] = 64 * 1024; mINI::Instance()[kSendBufSize] = 64 * 1024;
mINI::Instance()[kMaxReqSize] = 4*1024; mINI::Instance()[kMaxReqSize] = 4*1024;
mINI::Instance()[kKeepAliveSecond] = 15; mINI::Instance()[kKeepAliveSecond] = 15;
#if defined(_WIN32) #if defined(_WIN32)
mINI::Instance()[kCharSet] = "gb2312"; mINI::Instance()[kCharSet] = "gb2312";
#else #else
mINI::Instance()[kCharSet] ="utf-8"; mINI::Instance()[kCharSet] ="utf-8";
#endif #endif
mINI::Instance()[kRootPath] = "./www"; mINI::Instance()[kRootPath] = "./www";
mINI::Instance()[kNotFound] = mINI::Instance()[kNotFound] =
"<html>" "<html>"
"<head><title>404 Not Found</title></head>" "<head><title>404 Not Found</title></head>"
"<body bgcolor=\"white\">" "<body bgcolor=\"white\">"
"<center><h1>您访问的资源不存在!</h1></center>" "<center><h1>您访问的资源不存在!</h1></center>"
"<hr><center>" "<hr><center>"
SERVER_NAME SERVER_NAME
"</center>" "</center>"
"</body>" "</body>"
"</html>"; "</html>";
},nullptr); },nullptr);
}//namespace Http }//namespace Http
@ -147,7 +147,7 @@ namespace Shell {
const string kMaxReqSize = SHELL_FIELD"maxReqSize"; const string kMaxReqSize = SHELL_FIELD"maxReqSize";
onceToken token([](){ onceToken token([](){
mINI::Instance()[kMaxReqSize] = 1024; mINI::Instance()[kMaxReqSize] = 1024;
},nullptr); },nullptr);
} //namespace Shell } //namespace Shell
@ -160,11 +160,11 @@ const string kKeepAliveSecond = RTSP_FIELD"keepAliveSecond";
const string kDirectProxy = RTSP_FIELD"directProxy"; const string kDirectProxy = RTSP_FIELD"directProxy";
onceToken token([](){ onceToken token([](){
//默认Md5方式认证 //默认Md5方式认证
mINI::Instance()[kAuthBasic] = 0; mINI::Instance()[kAuthBasic] = 0;
mINI::Instance()[kHandshakeSecond] = 15; mINI::Instance()[kHandshakeSecond] = 15;
mINI::Instance()[kKeepAliveSecond] = 15; mINI::Instance()[kKeepAliveSecond] = 15;
mINI::Instance()[kDirectProxy] = 1; mINI::Instance()[kDirectProxy] = 1;
},nullptr); },nullptr);
} //namespace Rtsp } //namespace Rtsp
@ -176,7 +176,7 @@ const string kHandshakeSecond = RTMP_FIELD"handshakeSecond";
const string kKeepAliveSecond = RTMP_FIELD"keepAliveSecond"; const string kKeepAliveSecond = RTMP_FIELD"keepAliveSecond";
onceToken token([](){ onceToken token([](){
mINI::Instance()[kModifyStamp] = false; mINI::Instance()[kModifyStamp] = false;
mINI::Instance()[kHandshakeSecond] = 15; mINI::Instance()[kHandshakeSecond] = 15;
mINI::Instance()[kKeepAliveSecond] = 15; mINI::Instance()[kKeepAliveSecond] = 15;
},nullptr); },nullptr);
@ -197,11 +197,11 @@ const string kClearCount = RTP_FIELD"clearCount";
const string kCycleMS = RTP_FIELD"cycleMS"; const string kCycleMS = RTP_FIELD"cycleMS";
onceToken token([](){ onceToken token([](){
mINI::Instance()[kVideoMtuSize] = 1400; mINI::Instance()[kVideoMtuSize] = 1400;
mINI::Instance()[kAudioMtuSize] = 600; mINI::Instance()[kAudioMtuSize] = 600;
mINI::Instance()[kMaxRtpCount] = 50; mINI::Instance()[kMaxRtpCount] = 50;
mINI::Instance()[kClearCount] = 10; mINI::Instance()[kClearCount] = 10;
mINI::Instance()[kCycleMS] = 13*60*60*1000; mINI::Instance()[kCycleMS] = 13*60*60*1000;
},nullptr); },nullptr);
} //namespace Rtsp } //namespace Rtsp
@ -216,9 +216,9 @@ const string kAddrMax = MULTI_FIELD"addrMax";
const string kUdpTTL = MULTI_FIELD"udpTTL"; const string kUdpTTL = MULTI_FIELD"udpTTL";
onceToken token([](){ onceToken token([](){
mINI::Instance()[kAddrMin] = "239.0.0.0"; mINI::Instance()[kAddrMin] = "239.0.0.0";
mINI::Instance()[kAddrMax] = "239.255.255.255"; mINI::Instance()[kAddrMax] = "239.255.255.255";
mINI::Instance()[kUdpTTL] = 64; mINI::Instance()[kUdpTTL] = 64;
},nullptr); },nullptr);
} //namespace MultiCast } //namespace MultiCast
@ -241,13 +241,13 @@ const string kFastStart = RECORD_FIELD"fastStart";
const string kFileRepeat = RECORD_FIELD"fileRepeat"; const string kFileRepeat = RECORD_FIELD"fileRepeat";
onceToken token([](){ onceToken token([](){
mINI::Instance()[kAppName] = "record"; mINI::Instance()[kAppName] = "record";
mINI::Instance()[kSampleMS] = 500; mINI::Instance()[kSampleMS] = 500;
mINI::Instance()[kFileSecond] = 60*60; mINI::Instance()[kFileSecond] = 60*60;
mINI::Instance()[kFilePath] = "./www"; mINI::Instance()[kFilePath] = "./www";
mINI::Instance()[kFileBufSize] = 64 * 1024; mINI::Instance()[kFileBufSize] = 64 * 1024;
mINI::Instance()[kFastStart] = false; mINI::Instance()[kFastStart] = false;
mINI::Instance()[kFileRepeat] = false; mINI::Instance()[kFileRepeat] = false;
},nullptr); },nullptr);
} //namespace Record } //namespace Record
@ -266,11 +266,11 @@ const string kFileBufSize = HLS_FIELD"fileBufSize";
const string kFilePath = HLS_FIELD"filePath"; const string kFilePath = HLS_FIELD"filePath";
onceToken token([](){ onceToken token([](){
mINI::Instance()[kSegmentDuration] = 2; mINI::Instance()[kSegmentDuration] = 2;
mINI::Instance()[kSegmentNum] = 3; mINI::Instance()[kSegmentNum] = 3;
mINI::Instance()[kSegmentRetain] = 5; mINI::Instance()[kSegmentRetain] = 5;
mINI::Instance()[kFileBufSize] = 64 * 1024; mINI::Instance()[kFileBufSize] = 64 * 1024;
mINI::Instance()[kFilePath] = "./www"; mINI::Instance()[kFilePath] = "./www";
},nullptr); },nullptr);
} //namespace Hls } //namespace Hls
@ -286,9 +286,9 @@ const string kCheckSource = RTP_PROXY_FIELD"checkSource";
const string kTimeoutSec = RTP_PROXY_FIELD"timeoutSec"; const string kTimeoutSec = RTP_PROXY_FIELD"timeoutSec";
onceToken token([](){ onceToken token([](){
mINI::Instance()[kDumpDir] = ""; mINI::Instance()[kDumpDir] = "";
mINI::Instance()[kCheckSource] = 1; mINI::Instance()[kCheckSource] = 1;
mINI::Instance()[kTimeoutSec] = 15; mINI::Instance()[kTimeoutSec] = 15;
},nullptr); },nullptr);
} //namespace RtpProxy } //namespace RtpProxy

View File

@ -88,24 +88,24 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
* Type==7:SPS frame * Type==7:SPS frame
* Type==8:PPS frame * Type==8:PPS frame
*/ */
/* /*
RTF3984 5.2 Common Structure of the RTP Payload Format RTF3984 5.2 Common Structure of the RTP Payload Format
Table 1. Summary of NAL unit types and their payload structures Table 1. Summary of NAL unit types and their payload structures
Type Packet Type name Section Type Packet Type name Section
--------------------------------------------------------- ---------------------------------------------------------
0 undefined - 0 undefined -
1-23 NAL unit Single NAL unit packet per H.264 5.6 1-23 NAL unit Single NAL unit packet per H.264 5.6
24 STAP-A Single-time aggregation packet 5.7.1 24 STAP-A Single-time aggregation packet 5.7.1
25 STAP-B Single-time aggregation packet 5.7.1 25 STAP-B Single-time aggregation packet 5.7.1
26 MTAP16 Multi-time aggregation packet 5.7.2 26 MTAP16 Multi-time aggregation packet 5.7.2
27 MTAP24 Multi-time aggregation packet 5.7.2 27 MTAP24 Multi-time aggregation packet 5.7.2
28 FU-A Fragmentation unit 5.8 28 FU-A Fragmentation unit 5.8
29 FU-B Fragmentation unit 5.8 29 FU-B Fragmentation unit 5.8
30-31 undefined - 30-31 undefined -
*/ */
const uint8_t *frame = (uint8_t *) rtppack->data() + rtppack->offset; const uint8_t *frame = (uint8_t *) rtppack->data() + rtppack->offset;
int length = rtppack->size() - rtppack->offset; int length = rtppack->size() - rtppack->offset;
NALU nal; NALU nal;

View File

@ -34,36 +34,36 @@ bool getHEVCInfo(const char * vps, int vps_len,const char * sps,int sps_len,int
T_GetBitContext tGetBitBuf; T_GetBitContext tGetBitBuf;
T_HEVCSPS tH265SpsInfo; T_HEVCSPS tH265SpsInfo;
T_HEVCVPS tH265VpsInfo; T_HEVCVPS tH265VpsInfo;
if ( vps_len > 2 ){ if ( vps_len > 2 ){
memset(&tGetBitBuf,0,sizeof(tGetBitBuf)); memset(&tGetBitBuf,0,sizeof(tGetBitBuf));
memset(&tH265VpsInfo,0,sizeof(tH265VpsInfo)); memset(&tH265VpsInfo,0,sizeof(tH265VpsInfo));
tGetBitBuf.pu8Buf = (uint8_t*)vps+2; tGetBitBuf.pu8Buf = (uint8_t*)vps+2;
tGetBitBuf.iBufSize = vps_len-2; tGetBitBuf.iBufSize = vps_len-2;
if(0 != h265DecVideoParameterSet((void *) &tGetBitBuf, &tH265VpsInfo)){ if(0 != h265DecVideoParameterSet((void *) &tGetBitBuf, &tH265VpsInfo)){
return false; return false;
} }
} }
if ( sps_len > 2 ){ if ( sps_len > 2 ){
memset(&tGetBitBuf,0,sizeof(tGetBitBuf)); memset(&tGetBitBuf,0,sizeof(tGetBitBuf));
memset(&tH265SpsInfo,0,sizeof(tH265SpsInfo)); memset(&tH265SpsInfo,0,sizeof(tH265SpsInfo));
tGetBitBuf.pu8Buf = (uint8_t*)sps+2; tGetBitBuf.pu8Buf = (uint8_t*)sps+2;
tGetBitBuf.iBufSize = sps_len-2; tGetBitBuf.iBufSize = sps_len-2;
if(0 != h265DecSeqParameterSet((void *) &tGetBitBuf, &tH265SpsInfo)){ if(0 != h265DecSeqParameterSet((void *) &tGetBitBuf, &tH265SpsInfo)){
return false; return false;
} }
} }
else else
return false; return false;
h265GetWidthHeight(&tH265SpsInfo, &iVideoWidth, &iVideoHeight); h265GetWidthHeight(&tH265SpsInfo, &iVideoWidth, &iVideoHeight);
iVideoFps = 0; iVideoFps = 0;
h265GeFramerate(&tH265VpsInfo, &tH265SpsInfo, &iVideoFps); h265GeFramerate(&tH265VpsInfo, &tH265SpsInfo, &iVideoFps);
// ErrorL << iVideoWidth << " " << iVideoHeight << " " << iVideoFps; // ErrorL << iVideoWidth << " " << iVideoHeight << " " << iVideoFps;
return true; return true;
} }
bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, int &iVideoHeight, float &iVideoFps) { bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, int &iVideoHeight, float &iVideoFps) {
return getHEVCInfo(strVps.data(),strVps.size(),strSps.data(),strSps.size(),iVideoWidth,iVideoHeight,iVideoFps); return getHEVCInfo(strVps.data(),strVps.size(),strSps.data(),strSps.size(),iVideoWidth,iVideoHeight,iVideoFps);
} }
Sdp::Ptr H265Track::getSdp() { Sdp::Ptr H265Track::getSdp() {

View File

@ -202,7 +202,7 @@ public:
_vps = vps.substr(vps_prefix_len); _vps = vps.substr(vps_prefix_len);
_sps = sps.substr(sps_prefix_len); _sps = sps.substr(sps_prefix_len);
_pps = pps.substr(pps_prefix_len); _pps = pps.substr(pps_prefix_len);
onReady(); onReady();
} }
/** /**
@ -267,10 +267,10 @@ public:
* @param frame * @param frame
*/ */
void inputFrame(const Frame::Ptr &frame) override{ void inputFrame(const Frame::Ptr &frame) override{
int type = H265_TYPE(*((uint8_t *)frame->data() + frame->prefixSize())); int type = H265_TYPE(*((uint8_t *)frame->data() + frame->prefixSize()));
if(type == H265Frame::NAL_VPS){ if(type == H265Frame::NAL_VPS){
bool first_frame = true; bool first_frame = true;
splitH264(frame->data() + frame->prefixSize(), splitH264(frame->data() + frame->prefixSize(),
frame->size() - frame->prefixSize(), frame->size() - frame->prefixSize(),
[&](const char *ptr, int len){ [&](const char *ptr, int len){
if(first_frame){ if(first_frame){
@ -288,9 +288,9 @@ public:
inputFrame_l(sub_frame); inputFrame_l(sub_frame);
} }
}); });
}else{ }else{
inputFrame_l(frame); inputFrame_l(frame);
} }
} }
private: private:
@ -336,7 +336,7 @@ private:
} }
} }
/** /**
* sps获取宽高fps * sps获取宽高fps
*/ */
void onReady(){ void onReady(){

File diff suppressed because it is too large Load Diff

View File

@ -434,7 +434,7 @@ typedef struct T_HEVCSPS {
int iQpBdOffset; int iQpBdOffset;
int iVuiPresent; int iVuiPresent;
}T_HEVCSPS; }T_HEVCSPS;

View File

@ -137,10 +137,10 @@ public:
virtual ~TrackSource(){} virtual ~TrackSource(){}
/** /**
* Track * Track
* @param trackReady Track * @param trackReady Track
* @return * @return
*/ */
virtual vector<Track::Ptr> getTracks(bool trackReady = true) const = 0; virtual vector<Track::Ptr> getTracks(bool trackReady = true) const = 0;
/** /**

View File

@ -148,7 +148,7 @@ protected:
* http回复完毕, * http回复完毕,
*/ */
virtual void onResponseCompleted(){ virtual void onResponseCompleted(){
DebugL; DebugL;
} }
/** /**

View File

@ -29,11 +29,11 @@
namespace mediakit { namespace mediakit {
void HttpClientImp::onConnect(const SockException &ex) { void HttpClientImp::onConnect(const SockException &ex) {
if(!_isHttps){ if(!_isHttps){
HttpClient::onConnect(ex); HttpClient::onConnect(ex);
} else { } else {
TcpClientWithSSL<HttpClient>::onConnect(ex); TcpClientWithSSL<HttpClient>::onConnect(ex);
} }
} }

View File

@ -36,11 +36,11 @@ namespace mediakit {
class HttpClientImp: public TcpClientWithSSL<HttpClient> { class HttpClientImp: public TcpClientWithSSL<HttpClient> {
public: public:
typedef std::shared_ptr<HttpClientImp> Ptr; typedef std::shared_ptr<HttpClientImp> Ptr;
HttpClientImp() {} HttpClientImp() {}
virtual ~HttpClientImp() {} virtual ~HttpClientImp() {}
protected: protected:
void onConnect(const SockException &ex) override ; void onConnect(const SockException &ex) override ;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -36,75 +36,75 @@ HttpDownloader::HttpDownloader() {
} }
HttpDownloader::~HttpDownloader() { HttpDownloader::~HttpDownloader() {
closeFile(); closeFile();
} }
void HttpDownloader::startDownload(const string& url, const string& filePath,bool bAppend,float timeOutSecond) { void HttpDownloader::startDownload(const string& url, const string& filePath,bool bAppend,float timeOutSecond) {
_filePath = filePath; _filePath = filePath;
if(_filePath.empty()){ if(_filePath.empty()){
_filePath = exeDir() + "HttpDownloader/" + MD5(url).hexdigest(); _filePath = exeDir() + "HttpDownloader/" + MD5(url).hexdigest();
} }
_saveFile = File::createfile_file(_filePath.data(),bAppend ? "ab" : "wb"); _saveFile = File::createfile_file(_filePath.data(),bAppend ? "ab" : "wb");
if(!_saveFile){ if(!_saveFile){
auto strErr = StrPrinter << "打开文件失败:" << filePath << endl; auto strErr = StrPrinter << "打开文件失败:" << filePath << endl;
throw std::runtime_error(strErr); throw std::runtime_error(strErr);
} }
_bDownloadSuccess = false; _bDownloadSuccess = false;
if(bAppend){ if(bAppend){
auto currentLen = ftell(_saveFile); auto currentLen = ftell(_saveFile);
if(currentLen){ if(currentLen){
//最少续传一个字节怕遇到http 416的错误 //最少续传一个字节怕遇到http 416的错误
currentLen -= 1; currentLen -= 1;
fseek(_saveFile,-1,SEEK_CUR); fseek(_saveFile,-1,SEEK_CUR);
} }
addHeader("Range", StrPrinter << "bytes=" << currentLen << "-" << endl); addHeader("Range", StrPrinter << "bytes=" << currentLen << "-" << endl);
} }
setMethod("GET"); setMethod("GET");
sendRequest(url,timeOutSecond); sendRequest(url,timeOutSecond);
} }
int64_t HttpDownloader::onResponseHeader(const string& status,const HttpHeader& headers) { int64_t HttpDownloader::onResponseHeader(const string& status,const HttpHeader& headers) {
if(status != "200" && status != "206"){ if(status != "200" && status != "206"){
//失败 //失败
shutdown(SockException(Err_shutdown,StrPrinter << "Http Status:" << status)); shutdown(SockException(Err_shutdown,StrPrinter << "Http Status:" << status));
} }
//后续全部是content //后续全部是content
return -1; return -1;
} }
void HttpDownloader::onResponseBody(const char* buf, int64_t size, int64_t recvedSize, int64_t totalSize) { void HttpDownloader::onResponseBody(const char* buf, int64_t size, int64_t recvedSize, int64_t totalSize) {
if(_saveFile){ if(_saveFile){
fwrite(buf,size,1,_saveFile); fwrite(buf,size,1,_saveFile);
} }
} }
void HttpDownloader::onResponseCompleted() { void HttpDownloader::onResponseCompleted() {
closeFile(); closeFile();
//InfoL << "md5Sum:" << getMd5Sum(_filePath); //InfoL << "md5Sum:" << getMd5Sum(_filePath);
_bDownloadSuccess = true; _bDownloadSuccess = true;
if(_onResult){ if(_onResult){
_onResult(Err_success,"success",_filePath); _onResult(Err_success,"success",_filePath);
_onResult = nullptr; _onResult = nullptr;
} }
} }
void HttpDownloader::onDisconnect(const SockException &ex) { void HttpDownloader::onDisconnect(const SockException &ex) {
closeFile(); closeFile();
if(!_bDownloadSuccess){ if(!_bDownloadSuccess){
File::delete_file(_filePath.data()); File::delete_file(_filePath.data());
} }
if(_onResult){ if(_onResult){
_onResult(ex.getErrCode(),ex.what(),_filePath); _onResult(ex.getErrCode(),ex.what(),_filePath);
_onResult = nullptr; _onResult = nullptr;
} }
} }
void HttpDownloader::closeFile() { void HttpDownloader::closeFile() {
if(_saveFile){ if(_saveFile){
fflush(_saveFile); fflush(_saveFile);
fclose(_saveFile); fclose(_saveFile);
_saveFile = nullptr; _saveFile = nullptr;
} }
} }

View File

@ -33,30 +33,30 @@ namespace mediakit {
class HttpDownloader: public HttpClientImp { class HttpDownloader: public HttpClientImp {
public: public:
typedef std::shared_ptr<HttpDownloader> Ptr; typedef std::shared_ptr<HttpDownloader> Ptr;
typedef std::function<void(ErrCode code,const string &errMsg,const string &filePath)> onDownloadResult; typedef std::function<void(ErrCode code,const string &errMsg,const string &filePath)> onDownloadResult;
HttpDownloader(); HttpDownloader();
virtual ~HttpDownloader(); virtual ~HttpDownloader();
//开始下载文件,默认断点续传方式下载 //开始下载文件,默认断点续传方式下载
void startDownload(const string &url,const string &filePath = "",bool bAppend = false, float timeOutSecond = 10 ); void startDownload(const string &url,const string &filePath = "",bool bAppend = false, float timeOutSecond = 10 );
void startDownload(const string &url,const onDownloadResult &cb,float timeOutSecond = 10){ void startDownload(const string &url,const onDownloadResult &cb,float timeOutSecond = 10){
setOnResult(cb); setOnResult(cb);
startDownload(url,"",false,timeOutSecond); startDownload(url,"",false,timeOutSecond);
} }
void setOnResult(const onDownloadResult &cb){ void setOnResult(const onDownloadResult &cb){
_onResult = cb; _onResult = cb;
} }
private: private:
int64_t onResponseHeader(const string &status,const HttpHeader &headers) override; int64_t onResponseHeader(const string &status,const HttpHeader &headers) override;
void onResponseBody(const char *buf,int64_t size,int64_t recvedSize,int64_t totalSize) override; void onResponseBody(const char *buf,int64_t size,int64_t recvedSize,int64_t totalSize) override;
void onResponseCompleted() override; void onResponseCompleted() override;
void onDisconnect(const SockException &ex) override; void onDisconnect(const SockException &ex) override;
void closeFile(); void closeFile();
private: private:
FILE *_saveFile = nullptr; FILE *_saveFile = nullptr;
string _filePath; string _filePath;
onDownloadResult _onResult; onDownloadResult _onResult;
bool _bDownloadSuccess = false; bool _bDownloadSuccess = false;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -45,8 +45,8 @@ HttpSession::HttpSession(const Socket::Ptr &pSock) : TcpSession(pSock) {
TraceP(this); TraceP(this);
GET_CONFIG(uint32_t,keep_alive_sec,Http::kKeepAliveSecond); GET_CONFIG(uint32_t,keep_alive_sec,Http::kKeepAliveSecond);
pSock->setSendTimeOutSecond(keep_alive_sec); pSock->setSendTimeOutSecond(keep_alive_sec);
//起始接收buffer缓存设置为4K节省内存 //起始接收buffer缓存设置为4K节省内存
pSock->setReadBuffer(std::make_shared<BufferRaw>(4 * 1024)); pSock->setReadBuffer(std::make_shared<BufferRaw>(4 * 1024));
} }
HttpSession::~HttpSession() { HttpSession::~HttpSession() {
@ -61,48 +61,48 @@ void HttpSession::Handle_Req_HEAD(int64_t &content_len){
} }
int64_t HttpSession::onRecvHeader(const char *header,uint64_t len) { int64_t HttpSession::onRecvHeader(const char *header,uint64_t len) {
typedef void (HttpSession::*HttpCMDHandle)(int64_t &); typedef void (HttpSession::*HttpCMDHandle)(int64_t &);
static unordered_map<string, HttpCMDHandle> s_func_map; static unordered_map<string, HttpCMDHandle> s_func_map;
static onceToken token([]() { static onceToken token([]() {
s_func_map.emplace("GET",&HttpSession::Handle_Req_GET); s_func_map.emplace("GET",&HttpSession::Handle_Req_GET);
s_func_map.emplace("POST",&HttpSession::Handle_Req_POST); s_func_map.emplace("POST",&HttpSession::Handle_Req_POST);
s_func_map.emplace("HEAD",&HttpSession::Handle_Req_HEAD); s_func_map.emplace("HEAD",&HttpSession::Handle_Req_HEAD);
}, nullptr); }, nullptr);
_parser.Parse(header); _parser.Parse(header);
urlDecode(_parser); urlDecode(_parser);
string cmd = _parser.Method(); string cmd = _parser.Method();
auto it = s_func_map.find(cmd); auto it = s_func_map.find(cmd);
if (it == s_func_map.end()) { if (it == s_func_map.end()) {
WarnL << "不支持该命令:" << cmd; WarnL << "不支持该命令:" << cmd;
sendResponse("405 Not Allowed", true); sendResponse("405 Not Allowed", true);
return 0; return 0;
} }
//跨域 //跨域
_origin = _parser["Origin"]; _origin = _parser["Origin"];
//默认后面数据不是content而是header //默认后面数据不是content而是header
int64_t content_len = 0; int64_t content_len = 0;
auto &fun = it->second; auto &fun = it->second;
try { try {
(this->*fun)(content_len); (this->*fun)(content_len);
}catch (exception &ex){ }catch (exception &ex){
shutdown(SockException(Err_shutdown,ex.what())); shutdown(SockException(Err_shutdown,ex.what()));
} }
//清空解析器节省内存 //清空解析器节省内存
_parser.Clear(); _parser.Clear();
//返回content长度 //返回content长度
return content_len; return content_len;
} }
void HttpSession::onRecvContent(const char *data,uint64_t len) { void HttpSession::onRecvContent(const char *data,uint64_t len) {
if(_contentCallBack){ if(_contentCallBack){
if(!_contentCallBack(data,len)){ if(!_contentCallBack(data,len)){
_contentCallBack = nullptr; _contentCallBack = nullptr;
} }
} }
} }
void HttpSession::onRecv(const Buffer::Ptr &pBuf) { void HttpSession::onRecv(const Buffer::Ptr &pBuf) {
@ -140,25 +140,25 @@ void HttpSession::onManager() {
GET_CONFIG(uint32_t,keepAliveSec,Http::kKeepAliveSecond); GET_CONFIG(uint32_t,keepAliveSec,Http::kKeepAliveSecond);
if(_ticker.elapsedTime() > keepAliveSec * 1000){ if(_ticker.elapsedTime() > keepAliveSec * 1000){
//1分钟超时 //1分钟超时
shutdown(SockException(Err_timeout,"session timeouted")); shutdown(SockException(Err_timeout,"session timeouted"));
} }
} }
bool HttpSession::checkWebSocket(){ bool HttpSession::checkWebSocket(){
auto Sec_WebSocket_Key = _parser["Sec-WebSocket-Key"]; auto Sec_WebSocket_Key = _parser["Sec-WebSocket-Key"];
if(Sec_WebSocket_Key.empty()){ if(Sec_WebSocket_Key.empty()){
return false; return false;
} }
auto Sec_WebSocket_Accept = encodeBase64(SHA1::encode_bin(Sec_WebSocket_Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); auto Sec_WebSocket_Accept = encodeBase64(SHA1::encode_bin(Sec_WebSocket_Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
KeyValue headerOut; KeyValue headerOut;
headerOut["Upgrade"] = "websocket"; headerOut["Upgrade"] = "websocket";
headerOut["Connection"] = "Upgrade"; headerOut["Connection"] = "Upgrade";
headerOut["Sec-WebSocket-Accept"] = Sec_WebSocket_Accept; headerOut["Sec-WebSocket-Accept"] = Sec_WebSocket_Accept;
if(!_parser["Sec-WebSocket-Protocol"].empty()){ if(!_parser["Sec-WebSocket-Protocol"].empty()){
headerOut["Sec-WebSocket-Protocol"] = _parser["Sec-WebSocket-Protocol"]; headerOut["Sec-WebSocket-Protocol"] = _parser["Sec-WebSocket-Protocol"];
} }
auto res_cb = [this,headerOut](){ auto res_cb = [this,headerOut](){
_flv_over_websocket = true; _flv_over_websocket = true;
@ -177,28 +177,28 @@ bool HttpSession::checkWebSocket(){
return true; return true;
} }
sendResponse("101 Switching Protocols",false, nullptr,headerOut); sendResponse("101 Switching Protocols",false, nullptr,headerOut);
return true; return true;
} }
//http-flv 链接格式:http://vhost-url:port/app/streamid.flv?key1=value1&key2=value2 //http-flv 链接格式:http://vhost-url:port/app/streamid.flv?key1=value1&key2=value2
//如果url(除去?以及后面的参数)后缀是.flv,那么表明该url是一个http-flv直播。 //如果url(除去?以及后面的参数)后缀是.flv,那么表明该url是一个http-flv直播。
bool HttpSession::checkLiveFlvStream(const function<void()> &cb){ bool HttpSession::checkLiveFlvStream(const function<void()> &cb){
auto pos = strrchr(_parser.Url().data(),'.'); auto pos = strrchr(_parser.Url().data(),'.');
if(!pos){ if(!pos){
//未找到".flv"后缀 //未找到".flv"后缀
return false;
}
if(strcasecmp(pos,".flv") != 0){
//未找到".flv"后缀
return false;
}
//这是个.flv的流
_mediaInfo.parse(string(RTMP_SCHEMA) + "://" + _parser["Host"] + _parser.FullUrl());
if(_mediaInfo._app.empty() || _mediaInfo._streamid.size() < 5){
//url不合法
return false; return false;
} }
if(strcasecmp(pos,".flv") != 0){
//未找到".flv"后缀
return false;
}
//这是个.flv的流
_mediaInfo.parse(string(RTMP_SCHEMA) + "://" + _parser["Host"] + _parser.FullUrl());
if(_mediaInfo._app.empty() || _mediaInfo._streamid.size() < 5){
//url不合法
return false;
}
_mediaInfo._streamid.erase(_mediaInfo._streamid.size() - 4);//去除.flv后缀 _mediaInfo._streamid.erase(_mediaInfo._streamid.size() - 4);//去除.flv后缀
bool bClose = !strcasecmp(_parser["Connection"].data(),"close"); bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
@ -270,21 +270,21 @@ void HttpSession::Handle_Req_GET(int64_t &content_len) {
} }
void HttpSession::Handle_Req_GET_l(int64_t &content_len, bool sendBody) { void HttpSession::Handle_Req_GET_l(int64_t &content_len, bool sendBody) {
//先看看是否为WebSocket请求 //先看看是否为WebSocket请求
if(checkWebSocket()){ if(checkWebSocket()){
content_len = -1; content_len = -1;
_contentCallBack = [this](const char *data,uint64_t len){ _contentCallBack = [this](const char *data,uint64_t len){
WebSocketSplitter::decode((uint8_t *)data,len); WebSocketSplitter::decode((uint8_t *)data,len);
//_contentCallBack是可持续的后面还要处理后续数据 //_contentCallBack是可持续的后面还要处理后续数据
return true; return true;
}; };
return; return;
} }
if(emitHttpEvent(false)){ if(emitHttpEvent(false)){
//拦截http api事件 //拦截http api事件
return; return;
} }
if(checkLiveFlvStream()){ if(checkLiveFlvStream()){
//拦截http-flv播放器 //拦截http-flv播放器
@ -498,111 +498,111 @@ void HttpSession::sendResponse(const char *pcStatus,
} }
string HttpSession::urlDecode(const string &str){ string HttpSession::urlDecode(const string &str){
auto ret = strCoding::UrlDecode(str); auto ret = strCoding::UrlDecode(str);
#ifdef _WIN32 #ifdef _WIN32
GET_CONFIG(string,charSet,Http::kCharSet); GET_CONFIG(string,charSet,Http::kCharSet);
bool isGb2312 = !strcasecmp(charSet.data(), "gb2312"); bool isGb2312 = !strcasecmp(charSet.data(), "gb2312");
if (isGb2312) { if (isGb2312) {
ret = strCoding::UTF8ToGB2312(ret); ret = strCoding::UTF8ToGB2312(ret);
} }
#endif // _WIN32 #endif // _WIN32
return ret; return ret;
} }
void HttpSession::urlDecode(Parser &parser){ void HttpSession::urlDecode(Parser &parser){
parser.setUrl(urlDecode(parser.Url())); parser.setUrl(urlDecode(parser.Url()));
for(auto &pr : _parser.getUrlArgs()){ for(auto &pr : _parser.getUrlArgs()){
const_cast<string &>(pr.second) = urlDecode(pr.second); const_cast<string &>(pr.second) = urlDecode(pr.second);
} }
} }
bool HttpSession::emitHttpEvent(bool doInvoke){ bool HttpSession::emitHttpEvent(bool doInvoke){
bool bClose = !strcasecmp(_parser["Connection"].data(),"close"); bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
/////////////////////异步回复Invoker/////////////////////////////// /////////////////////异步回复Invoker///////////////////////////////
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this()); weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
HttpResponseInvoker invoker = [weakSelf,bClose](const string &codeOut, const KeyValue &headerOut, const HttpBody::Ptr &body){ HttpResponseInvoker invoker = [weakSelf,bClose](const string &codeOut, const KeyValue &headerOut, const HttpBody::Ptr &body){
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return; return;
} }
strongSelf->async([weakSelf,bClose,codeOut,headerOut,body]() { strongSelf->async([weakSelf,bClose,codeOut,headerOut,body]() {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
//本对象已经销毁 //本对象已经销毁
return; return;
} }
strongSelf->sendResponse(codeOut.data(), bClose, nullptr, headerOut, body); strongSelf->sendResponse(codeOut.data(), bClose, nullptr, headerOut, body);
}); });
}; };
///////////////////广播HTTP事件/////////////////////////// ///////////////////广播HTTP事件///////////////////////////
bool consumed = false;//该事件是否被消费 bool consumed = false;//该事件是否被消费
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastHttpRequest,_parser,invoker,consumed,*this); NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastHttpRequest,_parser,invoker,consumed,*this);
if(!consumed && doInvoke){ if(!consumed && doInvoke){
//该事件无人消费所以返回404 //该事件无人消费所以返回404
invoker("404 Not Found",KeyValue(), HttpBody::Ptr()); invoker("404 Not Found",KeyValue(), HttpBody::Ptr());
} }
return consumed; return consumed;
} }
void HttpSession::Handle_Req_POST(int64_t &content_len) { void HttpSession::Handle_Req_POST(int64_t &content_len) {
GET_CONFIG(uint64_t,maxReqSize,Http::kMaxReqSize); GET_CONFIG(uint64_t,maxReqSize,Http::kMaxReqSize);
int64_t totalContentLen = _parser["Content-Length"].empty() ? -1 : atoll(_parser["Content-Length"].data()); int64_t totalContentLen = _parser["Content-Length"].empty() ? -1 : atoll(_parser["Content-Length"].data());
if(totalContentLen == 0){ if(totalContentLen == 0){
//content为空 //content为空
//emitHttpEvent内部会选择是否关闭连接 //emitHttpEvent内部会选择是否关闭连接
emitHttpEvent(true); emitHttpEvent(true);
return; return;
} }
//根据Content-Length设置接收缓存大小 //根据Content-Length设置接收缓存大小
if(totalContentLen > 0){ if(totalContentLen > 0){
_sock->setReadBuffer(std::make_shared<BufferRaw>(MIN(totalContentLen + 1,256 * 1024))); _sock->setReadBuffer(std::make_shared<BufferRaw>(MIN(totalContentLen + 1,256 * 1024)));
}else{ }else{
//不定长度的Content-Length //不定长度的Content-Length
_sock->setReadBuffer(std::make_shared<BufferRaw>(256 * 1024)); _sock->setReadBuffer(std::make_shared<BufferRaw>(256 * 1024));
} }
if(totalContentLen > 0 && totalContentLen < maxReqSize ){ if(totalContentLen > 0 && totalContentLen < maxReqSize ){
//返回固定长度的content //返回固定长度的content
content_len = totalContentLen; content_len = totalContentLen;
auto parserCopy = _parser; auto parserCopy = _parser;
_contentCallBack = [this,parserCopy](const char *data,uint64_t len){ _contentCallBack = [this,parserCopy](const char *data,uint64_t len){
//恢复http头 //恢复http头
_parser = parserCopy; _parser = parserCopy;
//设置content //设置content
_parser.setContent(string(data,len)); _parser.setContent(string(data,len));
//触发http事件emitHttpEvent内部会选择是否关闭连接 //触发http事件emitHttpEvent内部会选择是否关闭连接
emitHttpEvent(true); emitHttpEvent(true);
//清空数据,节省内存 //清空数据,节省内存
_parser.Clear(); _parser.Clear();
//content已经接收完毕 //content已经接收完毕
return false; return false;
}; };
}else{ }else{
//返回不固定长度的content //返回不固定长度的content
content_len = -1; content_len = -1;
auto parserCopy = _parser; auto parserCopy = _parser;
std::shared_ptr<uint64_t> recvedContentLen = std::make_shared<uint64_t>(0); std::shared_ptr<uint64_t> recvedContentLen = std::make_shared<uint64_t>(0);
bool bClose = !strcasecmp(_parser["Connection"].data(),"close"); bool bClose = !strcasecmp(_parser["Connection"].data(),"close");
_contentCallBack = [this,parserCopy,totalContentLen,recvedContentLen,bClose](const char *data,uint64_t len){ _contentCallBack = [this,parserCopy,totalContentLen,recvedContentLen,bClose](const char *data,uint64_t len){
*(recvedContentLen) += len; *(recvedContentLen) += len;
onRecvUnlimitedContent(parserCopy,data,len,totalContentLen,*(recvedContentLen)); onRecvUnlimitedContent(parserCopy,data,len,totalContentLen,*(recvedContentLen));
if(*(recvedContentLen) < totalContentLen){ if(*(recvedContentLen) < totalContentLen){
//数据还没接收完毕 //数据还没接收完毕
//_contentCallBack是可持续的后面还要处理后续content数据 //_contentCallBack是可持续的后面还要处理后续content数据
return true; return true;
} }
//数据接收完毕 //数据接收完毕
if(!bClose){ if(!bClose){
//keep-alive类型连接 //keep-alive类型连接
//content接收完毕后续都是http header //content接收完毕后续都是http header
setContentLen(0); setContentLen(0);
//content已经接收完毕 //content已经接收完毕
return false; return false;
} }
@ -611,9 +611,9 @@ void HttpSession::Handle_Req_POST(int64_t &content_len) {
shutdown(SockException(Err_shutdown,"recv http content completed")); shutdown(SockException(Err_shutdown,"recv http content completed"));
//content已经接收完毕 //content已经接收完毕
return false ; return false ;
}; };
} }
//有后续content数据要处理,暂时不关闭连接 //有后续content数据要处理,暂时不关闭连接
} }
void HttpSession::sendNotFound(bool bClose) { void HttpSession::sendNotFound(bool bClose) {
@ -632,7 +632,7 @@ void HttpSession::setSocketFlags(){
} }
void HttpSession::onWrite(const Buffer::Ptr &buffer) { void HttpSession::onWrite(const Buffer::Ptr &buffer) {
_ticker.resetTime(); _ticker.resetTime();
if(!_flv_over_websocket){ if(!_flv_over_websocket){
_ui64TotalBytes += buffer->size(); _ui64TotalBytes += buffer->size();
send(buffer); send(buffer);
@ -653,11 +653,11 @@ void HttpSession::onWebSocketEncodeData(const Buffer::Ptr &buffer){
} }
void HttpSession::onDetach() { void HttpSession::onDetach() {
shutdown(SockException(Err_shutdown,"rtmp ring buffer detached")); shutdown(SockException(Err_shutdown,"rtmp ring buffer detached"));
} }
std::shared_ptr<FlvMuxer> HttpSession::getSharedPtr(){ std::shared_ptr<FlvMuxer> HttpSession::getSharedPtr(){
return dynamic_pointer_cast<FlvMuxer>(shared_from_this()); return dynamic_pointer_cast<FlvMuxer>(shared_from_this());
} }
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -45,51 +45,51 @@ class HttpSession: public TcpSession,
public HttpRequestSplitter, public HttpRequestSplitter,
public WebSocketSplitter { public WebSocketSplitter {
public: public:
typedef StrCaseMap KeyValue; typedef StrCaseMap KeyValue;
typedef HttpResponseInvokerImp HttpResponseInvoker; typedef HttpResponseInvokerImp HttpResponseInvoker;
friend class AsyncSender; friend class AsyncSender;
/** /**
* @param errMsg * @param errMsg
* @param accessPath 访 * @param accessPath 访
* @param cookieLifeSecond cookie有效期 * @param cookieLifeSecond cookie有效期
**/ **/
typedef std::function<void(const string &errMsg,const string &accessPath, int cookieLifeSecond)> HttpAccessPathInvoker; typedef std::function<void(const string &errMsg,const string &accessPath, int cookieLifeSecond)> HttpAccessPathInvoker;
HttpSession(const Socket::Ptr &pSock); HttpSession(const Socket::Ptr &pSock);
virtual ~HttpSession(); virtual ~HttpSession();
virtual void onRecv(const Buffer::Ptr &) override; virtual void onRecv(const Buffer::Ptr &) override;
virtual void onError(const SockException &err) override; virtual void onError(const SockException &err) override;
virtual void onManager() override; virtual void onManager() override;
static string urlDecode(const string &str); static string urlDecode(const string &str);
protected: protected:
//FlvMuxer override //FlvMuxer override
void onWrite(const Buffer::Ptr &data) override ; void onWrite(const Buffer::Ptr &data) override ;
void onDetach() override; void onDetach() override;
std::shared_ptr<FlvMuxer> getSharedPtr() override; std::shared_ptr<FlvMuxer> getSharedPtr() override;
//HttpRequestSplitter override //HttpRequestSplitter override
int64_t onRecvHeader(const char *data,uint64_t len) override; int64_t onRecvHeader(const char *data,uint64_t len) override;
void onRecvContent(const char *data,uint64_t len) override; void onRecvContent(const char *data,uint64_t len) override;
/** /**
* content * content
* http-flv推流 * http-flv推流
* @param header http请求头 * @param header http请求头
* @param data content分片数据 * @param data content分片数据
* @param len content分片数据大小 * @param len content分片数据大小
* @param totalSize content总大小,0content * @param totalSize content总大小,0content
* @param recvedSize * @param recvedSize
*/ */
virtual void onRecvUnlimitedContent(const Parser &header, virtual void onRecvUnlimitedContent(const Parser &header,
const char *data, const char *data,
uint64_t len, uint64_t len,
uint64_t totalSize, uint64_t totalSize,
uint64_t recvedSize){ uint64_t recvedSize){
shutdown(SockException(Err_shutdown,"http post content is too huge,default closed")); shutdown(SockException(Err_shutdown,"http post content is too huge,default closed"));
} }
/** /**
* websocket客户端连接上事件 * websocket客户端连接上事件
* @param header http头 * @param header http头
* @return true代表允许websocket连接 * @return true代表允许websocket连接
@ -99,31 +99,31 @@ protected:
return false; return false;
} }
//WebSocketSplitter override //WebSocketSplitter override
/** /**
* websocket协议打包后回调 * websocket协议打包后回调
* @param buffer websocket协议数据 * @param buffer websocket协议数据
*/ */
void onWebSocketEncodeData(const Buffer::Ptr &buffer) override; void onWebSocketEncodeData(const Buffer::Ptr &buffer) override;
private: private:
void Handle_Req_GET(int64_t &content_len); void Handle_Req_GET(int64_t &content_len);
void Handle_Req_GET_l(int64_t &content_len, bool sendBody); void Handle_Req_GET_l(int64_t &content_len, bool sendBody);
void Handle_Req_POST(int64_t &content_len); void Handle_Req_POST(int64_t &content_len);
void Handle_Req_HEAD(int64_t &content_len); void Handle_Req_HEAD(int64_t &content_len);
bool checkLiveFlvStream(const function<void()> &cb = nullptr); bool checkLiveFlvStream(const function<void()> &cb = nullptr);
bool checkWebSocket(); bool checkWebSocket();
bool emitHttpEvent(bool doInvoke); bool emitHttpEvent(bool doInvoke);
void urlDecode(Parser &parser); void urlDecode(Parser &parser);
void sendNotFound(bool bClose); void sendNotFound(bool bClose);
void sendResponse(const char *pcStatus, bool bClose, const char *pcContentType = nullptr, void sendResponse(const char *pcStatus, bool bClose, const char *pcContentType = nullptr,
const HttpSession::KeyValue &header = HttpSession::KeyValue(), const HttpSession::KeyValue &header = HttpSession::KeyValue(),
const HttpBody::Ptr &body = nullptr,bool is_http_flv = false); const HttpBody::Ptr &body = nullptr,bool is_http_flv = false);
//设置socket标志 //设置socket标志
void setSocketFlags(); void setSocketFlags();
private: private:
string _origin; string _origin;
Parser _parser; Parser _parser;
Ticker _ticker; Ticker _ticker;
//消耗的总流量 //消耗的总流量
@ -132,8 +132,8 @@ private:
MediaInfo _mediaInfo; MediaInfo _mediaInfo;
//处理content数据的callback //处理content数据的callback
function<bool (const char *data,uint64_t len) > _contentCallBack; function<bool (const char *data,uint64_t len) > _contentCallBack;
bool _flv_over_websocket = false; bool _flv_over_websocket = false;
bool _is_flv_stream = false; bool _is_flv_stream = false;
}; };

View File

@ -36,76 +36,76 @@ namespace mediakit {
//////////////////////////通用/////////////////////// //////////////////////////通用///////////////////////
void UTF8ToUnicode(wchar_t* pOut, const char *pText) void UTF8ToUnicode(wchar_t* pOut, const char *pText)
{ {
char* uchar = (char *)pOut; char* uchar = (char *)pOut;
uchar[1] = ((pText[0] & 0x0F) << 4) + ((pText[1] >> 2) & 0x0F); uchar[1] = ((pText[0] & 0x0F) << 4) + ((pText[1] >> 2) & 0x0F);
uchar[0] = ((pText[1] & 0x03) << 6) + (pText[2] & 0x3F); uchar[0] = ((pText[1] & 0x03) << 6) + (pText[2] & 0x3F);
return; return;
} }
void UnicodeToUTF8(char* pOut, const wchar_t* pText) void UnicodeToUTF8(char* pOut, const wchar_t* pText)
{ {
// 注意 WCHAR高低字的顺序,低字节在前,高字节在后 // 注意 WCHAR高低字的顺序,低字节在前,高字节在后
const char* pchar = (const char *)pText; const char* pchar = (const char *)pText;
pOut[0] = (0xE0 | ((pchar[1] & 0xF0) >> 4)); pOut[0] = (0xE0 | ((pchar[1] & 0xF0) >> 4));
pOut[1] = (0x80 | ((pchar[1] & 0x0F) << 2)) + ((pchar[0] & 0xC0) >> 6); pOut[1] = (0x80 | ((pchar[1] & 0x0F) << 2)) + ((pchar[0] & 0xC0) >> 6);
pOut[2] = (0x80 | (pchar[0] & 0x3F)); pOut[2] = (0x80 | (pchar[0] & 0x3F));
return; return;
} }
char CharToInt(char ch) char CharToInt(char ch)
{ {
if (ch >= '0' && ch <= '9')return (char)(ch - '0'); if (ch >= '0' && ch <= '9')return (char)(ch - '0');
if (ch >= 'a' && ch <= 'f')return (char)(ch - 'a' + 10); if (ch >= 'a' && ch <= 'f')return (char)(ch - 'a' + 10);
if (ch >= 'A' && ch <= 'F')return (char)(ch - 'A' + 10); if (ch >= 'A' && ch <= 'F')return (char)(ch - 'A' + 10);
return -1; return -1;
} }
char StrToBin(const char *str) char StrToBin(const char *str)
{ {
char tempWord[2]; char tempWord[2];
char chn; char chn;
tempWord[0] = CharToInt(str[0]); //make the B to 11 -- 00001011 tempWord[0] = CharToInt(str[0]); //make the B to 11 -- 00001011
tempWord[1] = CharToInt(str[1]); //make the 0 to 0 -- 00000000 tempWord[1] = CharToInt(str[1]); //make the 0 to 0 -- 00000000
chn = (tempWord[0] << 4) | tempWord[1]; //to change the BO to 10110000 chn = (tempWord[0] << 4) | tempWord[1]; //to change the BO to 10110000
return chn; return chn;
} }
string strCoding::UrlEncode(const string &str) { string strCoding::UrlEncode(const string &str) {
string out; string out;
size_t len = str.size(); size_t len = str.size();
for (size_t i = 0; i < len; ++i) { for (size_t i = 0; i < len; ++i) {
char ch = str[i]; char ch = str[i];
if (isalnum((uint8_t)ch)) { if (isalnum((uint8_t)ch)) {
out.push_back(ch); out.push_back(ch);
}else { }else {
char buf[4]; char buf[4];
sprintf(buf, "%%%X%X", (uint8_t)ch >> 4,(uint8_t)ch & 0x0F); sprintf(buf, "%%%X%X", (uint8_t)ch >> 4,(uint8_t)ch & 0x0F);
out.append(buf); out.append(buf);
} }
} }
return out; return out;
} }
string strCoding::UrlDecode(const string &str) { string strCoding::UrlDecode(const string &str) {
string output = ""; string output = "";
char tmp[2]; char tmp[2];
int i = 0, len = str.length(); int i = 0, len = str.length();
while (i < len) { while (i < len) {
if (str[i] == '%') { if (str[i] == '%') {
if(i > len - 3){ if(i > len - 3){
//防止内存溢出 //防止内存溢出
break; break;
} }
tmp[0] = str[i + 1]; tmp[0] = str[i + 1];
tmp[1] = str[i + 2]; tmp[1] = str[i + 2];
output += StrToBin(tmp); output += StrToBin(tmp);
i = i + 3; i = i + 3;
} else if (str[i] == '+') { } else if (str[i] == '+') {
output += ' '; output += ' ';
i++; i++;
} else { } else {
output += str[i]; output += str[i];
i++; i++;
} }
} }
return output; return output;
} }
@ -113,73 +113,73 @@ string strCoding::UrlDecode(const string &str) {
#if defined(_WIN32) #if defined(_WIN32)
void UnicodeToGB2312(char* pOut, wchar_t uData) void UnicodeToGB2312(char* pOut, wchar_t uData)
{ {
WideCharToMultiByte(CP_ACP, NULL, &uData, 1, pOut, sizeof(wchar_t), NULL, NULL); WideCharToMultiByte(CP_ACP, NULL, &uData, 1, pOut, sizeof(wchar_t), NULL, NULL);
} }
void Gb2312ToUnicode(wchar_t* pOut, const char *gbBuffer) void Gb2312ToUnicode(wchar_t* pOut, const char *gbBuffer)
{ {
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, gbBuffer, 2, pOut, 1); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, gbBuffer, 2, pOut, 1);
} }
string strCoding::UTF8ToGB2312(const string &str) { string strCoding::UTF8ToGB2312(const string &str) {
auto len = str.size(); auto len = str.size();
auto pText = str.data(); auto pText = str.data();
char Ctemp[4] = {0}; char Ctemp[4] = {0};
char *pOut = new char[len + 1]; char *pOut = new char[len + 1];
memset(pOut, 0, len + 1); memset(pOut, 0, len + 1);
int i = 0, j = 0; int i = 0, j = 0;
while (i < len) while (i < len)
{ {
if (pText[i] >= 0) if (pText[i] >= 0)
{ {
pOut[j++] = pText[i++]; pOut[j++] = pText[i++];
} }
else else
{ {
wchar_t Wtemp; wchar_t Wtemp;
UTF8ToUnicode(&Wtemp, pText + i); UTF8ToUnicode(&Wtemp, pText + i);
UnicodeToGB2312(Ctemp, Wtemp); UnicodeToGB2312(Ctemp, Wtemp);
pOut[j] = Ctemp[0]; pOut[j] = Ctemp[0];
pOut[j + 1] = Ctemp[1]; pOut[j + 1] = Ctemp[1];
i += 3; i += 3;
j += 2; j += 2;
} }
} }
string ret = pOut; string ret = pOut;
delete[] pOut; delete[] pOut;
return ret; return ret;
} }
string strCoding::GB2312ToUTF8(const string &str) { string strCoding::GB2312ToUTF8(const string &str) {
auto len = str.size(); auto len = str.size();
auto pText = str.data(); auto pText = str.data();
char buf[4] = { 0 }; char buf[4] = { 0 };
int nLength = len * 3; int nLength = len * 3;
char* pOut = new char[nLength]; char* pOut = new char[nLength];
memset(pOut, 0, nLength); memset(pOut, 0, nLength);
int i = 0, j = 0; int i = 0, j = 0;
while (i < len) while (i < len)
{ {
//如果是英文直接复制就可以 //如果是英文直接复制就可以
if (*(pText + i) >= 0) if (*(pText + i) >= 0)
{ {
pOut[j++] = pText[i++]; pOut[j++] = pText[i++];
} }
else else
{ {
wchar_t pbuffer; wchar_t pbuffer;
Gb2312ToUnicode(&pbuffer, pText + i); Gb2312ToUnicode(&pbuffer, pText + i);
UnicodeToUTF8(buf, &pbuffer); UnicodeToUTF8(buf, &pbuffer);
pOut[j] = buf[0]; pOut[j] = buf[0];
pOut[j + 1] = buf[1]; pOut[j + 1] = buf[1];
pOut[j + 2] = buf[2]; pOut[j + 2] = buf[2];
j += 3; j += 3;
i += 2; i += 2;
} }
} }
string ret = pOut; string ret = pOut;
delete[] pOut; delete[] pOut;
return ret; return ret;
} }
#endif//defined(_WIN32) #endif//defined(_WIN32)

View File

@ -36,15 +36,15 @@ namespace mediakit {
class strCoding { class strCoding {
public: public:
static string UrlEncode(const string &str); //urlutf8 编码 static string UrlEncode(const string &str); //urlutf8 编码
static string UrlDecode(const string &str); //urlutf8解码 static string UrlDecode(const string &str); //urlutf8解码
#if defined(_WIN32) #if defined(_WIN32)
static string UTF8ToGB2312(const string &str);//utf_8转为gb2312 static string UTF8ToGB2312(const string &str);//utf_8转为gb2312
static string GB2312ToUTF8(const string &str); //gb2312 转utf_8 static string GB2312ToUTF8(const string &str); //gb2312 转utf_8
#endif//defined(_WIN32) #endif//defined(_WIN32)
private: private:
strCoding(void); strCoding(void);
virtual ~strCoding(void); virtual ~strCoding(void);
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -42,29 +42,29 @@ MediaPlayer::MediaPlayer(const EventPoller::Ptr &poller) {
MediaPlayer::~MediaPlayer() { MediaPlayer::~MediaPlayer() {
} }
void MediaPlayer::play(const string &strUrl) { void MediaPlayer::play(const string &strUrl) {
_delegate = PlayerBase::createPlayer(_poller,strUrl); _delegate = PlayerBase::createPlayer(_poller,strUrl);
_delegate->setOnShutdown(_shutdownCB); _delegate->setOnShutdown(_shutdownCB);
_delegate->setOnPlayResult(_playResultCB); _delegate->setOnPlayResult(_playResultCB);
_delegate->setOnResume(_resumeCB); _delegate->setOnResume(_resumeCB);
_delegate->setMediaSouce(_pMediaSrc); _delegate->setMediaSouce(_pMediaSrc);
_delegate->mINI::operator=(*this); _delegate->mINI::operator=(*this);
_delegate->play(strUrl); _delegate->play(strUrl);
} }
EventPoller::Ptr MediaPlayer::getPoller(){ EventPoller::Ptr MediaPlayer::getPoller(){
return _poller; return _poller;
} }
void MediaPlayer::pause(bool bPause) { void MediaPlayer::pause(bool bPause) {
if (_delegate) { if (_delegate) {
_delegate->pause(bPause); _delegate->pause(bPause);
} }
} }
void MediaPlayer::teardown() { void MediaPlayer::teardown() {
if (_delegate) { if (_delegate) {
_delegate->teardown(); _delegate->teardown();
} }
} }

View File

@ -39,16 +39,16 @@ namespace mediakit {
class MediaPlayer : public PlayerImp<PlayerBase,PlayerBase> { class MediaPlayer : public PlayerImp<PlayerBase,PlayerBase> {
public: public:
typedef std::shared_ptr<MediaPlayer> Ptr; typedef std::shared_ptr<MediaPlayer> Ptr;
MediaPlayer(const EventPoller::Ptr &poller = nullptr); MediaPlayer(const EventPoller::Ptr &poller = nullptr);
virtual ~MediaPlayer(); virtual ~MediaPlayer();
void play(const string &strUrl) override; void play(const string &strUrl) override;
void pause(bool bPause) override; void pause(bool bPause) override;
void teardown() override; void teardown() override;
EventPoller::Ptr getPoller(); EventPoller::Ptr getPoller();
private: private:
EventPoller::Ptr _poller; EventPoller::Ptr _poller;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -33,92 +33,92 @@ using namespace toolkit;
namespace mediakit { namespace mediakit {
PlayerBase::Ptr PlayerBase::createPlayer(const EventPoller::Ptr &poller,const string &strUrl) { PlayerBase::Ptr PlayerBase::createPlayer(const EventPoller::Ptr &poller,const string &strUrl) {
static auto releasePlayer = [](PlayerBase *ptr){ static auto releasePlayer = [](PlayerBase *ptr){
onceToken token(nullptr,[&](){ onceToken token(nullptr,[&](){
delete ptr; delete ptr;
}); });
ptr->teardown(); ptr->teardown();
}; };
string prefix = FindField(strUrl.data(), NULL, "://"); string prefix = FindField(strUrl.data(), NULL, "://");
if (strcasecmp("rtsps",prefix.data()) == 0) { if (strcasecmp("rtsps",prefix.data()) == 0) {
return PlayerBase::Ptr(new TcpClientWithSSL<RtspPlayerImp>(poller),releasePlayer); return PlayerBase::Ptr(new TcpClientWithSSL<RtspPlayerImp>(poller),releasePlayer);
} }
if (strcasecmp("rtsp",prefix.data()) == 0) { if (strcasecmp("rtsp",prefix.data()) == 0) {
return PlayerBase::Ptr(new RtspPlayerImp(poller),releasePlayer); return PlayerBase::Ptr(new RtspPlayerImp(poller),releasePlayer);
} }
if (strcasecmp("rtmps",prefix.data()) == 0) { if (strcasecmp("rtmps",prefix.data()) == 0) {
return PlayerBase::Ptr(new TcpClientWithSSL<RtmpPlayerImp>(poller),releasePlayer); return PlayerBase::Ptr(new TcpClientWithSSL<RtmpPlayerImp>(poller),releasePlayer);
} }
if (strcasecmp("rtmp",prefix.data()) == 0) { if (strcasecmp("rtmp",prefix.data()) == 0) {
return PlayerBase::Ptr(new RtmpPlayerImp(poller),releasePlayer); return PlayerBase::Ptr(new RtmpPlayerImp(poller),releasePlayer);
} }
return PlayerBase::Ptr(new RtspPlayerImp(poller),releasePlayer); return PlayerBase::Ptr(new RtspPlayerImp(poller),releasePlayer);
} }
PlayerBase::PlayerBase() { PlayerBase::PlayerBase() {
this->mINI::operator[](kTimeoutMS) = 10000; this->mINI::operator[](kTimeoutMS) = 10000;
this->mINI::operator[](kMediaTimeoutMS) = 5000; this->mINI::operator[](kMediaTimeoutMS) = 5000;
this->mINI::operator[](kBeatIntervalMS) = 5000; this->mINI::operator[](kBeatIntervalMS) = 5000;
this->mINI::operator[](kMaxAnalysisMS) = 5000; this->mINI::operator[](kMaxAnalysisMS) = 5000;
} }
///////////////////////////Demuxer////////////////////////////// ///////////////////////////Demuxer//////////////////////////////
bool Demuxer::isInited(int analysisMs) { bool Demuxer::isInited(int analysisMs) {
if(analysisMs && _ticker.createdTime() > analysisMs){ if(analysisMs && _ticker.createdTime() > analysisMs){
//analysisMs毫秒后强制初始化完毕 //analysisMs毫秒后强制初始化完毕
return true; return true;
} }
if (_videoTrack && !_videoTrack->ready()) { if (_videoTrack && !_videoTrack->ready()) {
//视频未准备好 //视频未准备好
return false; return false;
} }
if (_audioTrack && !_audioTrack->ready()) { if (_audioTrack && !_audioTrack->ready()) {
//音频未准备好 //音频未准备好
return false; return false;
} }
return true; return true;
} }
vector<Track::Ptr> Demuxer::getTracks(bool trackReady) const { vector<Track::Ptr> Demuxer::getTracks(bool trackReady) const {
vector<Track::Ptr> ret; vector<Track::Ptr> ret;
if(_videoTrack){ if(_videoTrack){
if(trackReady){ if(trackReady){
if(_videoTrack->ready()){ if(_videoTrack->ready()){
ret.emplace_back(_videoTrack); ret.emplace_back(_videoTrack);
} }
}else{ }else{
ret.emplace_back(_videoTrack); ret.emplace_back(_videoTrack);
} }
} }
if(_audioTrack){ if(_audioTrack){
if(trackReady){ if(trackReady){
if(_audioTrack->ready()){ if(_audioTrack->ready()){
ret.emplace_back(_audioTrack); ret.emplace_back(_audioTrack);
} }
}else{ }else{
ret.emplace_back(_audioTrack); ret.emplace_back(_audioTrack);
} }
} }
return std::move(ret); return std::move(ret);
} }
float Demuxer::getDuration() const { float Demuxer::getDuration() const {
return _fDuration; return _fDuration;
} }
void Demuxer::onAddTrack(const Track::Ptr &track){ void Demuxer::onAddTrack(const Track::Ptr &track){
if(_listener){ if(_listener){
_listener->onAddTrack(track); _listener->onAddTrack(track);
} }
} }
void Demuxer::setTrackListener(Demuxer::Listener *listener) { void Demuxer::setTrackListener(Demuxer::Listener *listener) {
_listener = listener; _listener = listener;
} }
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -43,59 +43,59 @@ namespace mediakit {
class DemuxerBase : public TrackSource{ class DemuxerBase : public TrackSource{
public: public:
typedef std::shared_ptr<DemuxerBase> Ptr; typedef std::shared_ptr<DemuxerBase> Ptr;
/** /**
* *
* @return * @return
*/ */
virtual float getDuration() const { return 0;} virtual float getDuration() const { return 0;}
/** /**
* getTrack方法 * getTrack方法
* @param analysisMs * @param analysisMs
* @return * @return
*/ */
virtual bool isInited(int analysisMs) { return true; } virtual bool isInited(int analysisMs) { return true; }
}; };
class PlayerBase : public DemuxerBase, public mINI{ class PlayerBase : public DemuxerBase, public mINI{
public: public:
typedef std::shared_ptr<PlayerBase> Ptr; typedef std::shared_ptr<PlayerBase> Ptr;
static Ptr createPlayer(const EventPoller::Ptr &poller,const string &strUrl); static Ptr createPlayer(const EventPoller::Ptr &poller,const string &strUrl);
PlayerBase(); PlayerBase();
virtual ~PlayerBase(){} virtual ~PlayerBase(){}
/** /**
* *
* @param strUrl urlrtsp/rtmp * @param strUrl urlrtsp/rtmp
*/ */
virtual void play(const string &strUrl) {} virtual void play(const string &strUrl) {}
/** /**
* *
* @param bPause * @param bPause
*/ */
virtual void pause(bool bPause) {} virtual void pause(bool bPause) {}
/** /**
* *
*/ */
virtual void teardown() {} virtual void teardown() {}
/** /**
* *
* @param cb * @param cb
*/ */
virtual void setOnShutdown( const function<void(const SockException &)> &cb) {} virtual void setOnShutdown( const function<void(const SockException &)> &cb) {}
/** /**
* *
* @param cb * @param cb
*/ */
virtual void setOnPlayResult( const function<void(const SockException &ex)> &cb) {} virtual void setOnPlayResult( const function<void(const SockException &ex)> &cb) {}
/** /**
* *
@ -103,10 +103,10 @@ public:
*/ */
virtual void setOnResume( const function<void()> &cb) {} virtual void setOnResume( const function<void()> &cb) {}
/** /**
* 0.0 ~ 1.0 * 0.0 ~ 1.0
* @return * @return
*/ */
virtual float getProgress() const { return 0;} virtual float getProgress() const { return 0;}
/** /**
@ -126,7 +126,7 @@ public:
* @param trackType TrackInvalid时为总丢包率 * @param trackType TrackInvalid时为总丢包率
* @return * @return
*/ */
virtual float getPacketLossRate(TrackType trackType) const {return 0; } virtual float getPacketLossRate(TrackType trackType) const {return 0; }
/** /**
* track * track
@ -146,24 +146,24 @@ protected:
template<typename Parent,typename Delegate> template<typename Parent,typename Delegate>
class PlayerImp : public Parent { class PlayerImp : public Parent {
public: public:
typedef std::shared_ptr<PlayerImp> Ptr; typedef std::shared_ptr<PlayerImp> Ptr;
template<typename ...ArgsType> template<typename ...ArgsType>
PlayerImp(ArgsType &&...args):Parent(std::forward<ArgsType>(args)...){} PlayerImp(ArgsType &&...args):Parent(std::forward<ArgsType>(args)...){}
virtual ~PlayerImp(){} virtual ~PlayerImp(){}
void setOnShutdown(const function<void(const SockException &)> &cb) override { void setOnShutdown(const function<void(const SockException &)> &cb) override {
if (_delegate) { if (_delegate) {
_delegate->setOnShutdown(cb); _delegate->setOnShutdown(cb);
} }
_shutdownCB = cb; _shutdownCB = cb;
} }
void setOnPlayResult(const function<void(const SockException &ex)> &cb) override { void setOnPlayResult(const function<void(const SockException &ex)> &cb) override {
if (_delegate) { if (_delegate) {
_delegate->setOnPlayResult(cb); _delegate->setOnPlayResult(cb);
} }
_playResultCB = cb; _playResultCB = cb;
} }
void setOnResume(const function<void()> &cb) override { void setOnResume(const function<void()> &cb) override {
if (_delegate) { if (_delegate) {
@ -178,12 +178,12 @@ public:
} }
return Parent::isInited(analysisMs); return Parent::isInited(analysisMs);
} }
float getDuration() const override { float getDuration() const override {
if (_delegate) { if (_delegate) {
return _delegate->getDuration(); return _delegate->getDuration();
} }
return Parent::getDuration(); return Parent::getDuration();
} }
float getProgress() const override{ float getProgress() const override{
if (_delegate) { if (_delegate) {
return _delegate->getProgress(); return _delegate->getProgress();
@ -198,95 +198,95 @@ public:
} }
void setMediaSouce(const MediaSource::Ptr & src) override { void setMediaSouce(const MediaSource::Ptr & src) override {
if (_delegate) { if (_delegate) {
_delegate->setMediaSouce(src); _delegate->setMediaSouce(src);
} }
_pMediaSrc = src; _pMediaSrc = src;
} }
vector<Track::Ptr> getTracks(bool trackReady = true) const override{ vector<Track::Ptr> getTracks(bool trackReady = true) const override{
if (_delegate) { if (_delegate) {
return _delegate->getTracks(trackReady); return _delegate->getTracks(trackReady);
} }
return Parent::getTracks(trackReady); return Parent::getTracks(trackReady);
} }
protected: protected:
void onShutdown(const SockException &ex) override { void onShutdown(const SockException &ex) override {
if (_shutdownCB) { if (_shutdownCB) {
_shutdownCB(ex); _shutdownCB(ex);
_shutdownCB = nullptr; _shutdownCB = nullptr;
} }
} }
void onPlayResult(const SockException &ex) override { void onPlayResult(const SockException &ex) override {
if(_playResultCB) { if(_playResultCB) {
_playResultCB(ex); _playResultCB(ex);
_playResultCB = nullptr; _playResultCB = nullptr;
} }
} }
void onResume() override{ void onResume() override{
if(_resumeCB){ if(_resumeCB){
_resumeCB(); _resumeCB();
} }
} }
protected: protected:
function<void(const SockException &ex)> _shutdownCB; function<void(const SockException &ex)> _shutdownCB;
function<void(const SockException &ex)> _playResultCB; function<void(const SockException &ex)> _playResultCB;
function<void()> _resumeCB; function<void()> _resumeCB;
std::shared_ptr<Delegate> _delegate; std::shared_ptr<Delegate> _delegate;
MediaSource::Ptr _pMediaSrc; MediaSource::Ptr _pMediaSrc;
}; };
class Demuxer : public PlayerBase{ class Demuxer : public PlayerBase{
public: public:
class Listener{ class Listener{
public: public:
Listener() = default; Listener() = default;
virtual ~Listener() = default; virtual ~Listener() = default;
virtual void onAddTrack(const Track::Ptr &track) = 0; virtual void onAddTrack(const Track::Ptr &track) = 0;
}; };
Demuxer(){}; Demuxer(){};
virtual ~Demuxer(){}; virtual ~Demuxer(){};
/** /**
* *
* RtspDemuxer对象时有些rtsp的sdp不包含sps pps信息 * RtspDemuxer对象时有些rtsp的sdp不包含sps pps信息
* sps的rtp包后才能完成 * sps的rtp包后才能完成
* *
* RtmpDemuxer对象时是无法获取sps pps aac_cfg等这些信息 * RtmpDemuxer对象时是无法获取sps pps aac_cfg等这些信息
* inputRtmp后才会获取到这些信息 * inputRtmp后才会获取到这些信息
* @param analysisMs * @param analysisMs
* @return * @return
*/ */
bool isInited(int analysisMs) override; bool isInited(int analysisMs) override;
/** /**
* Track * Track
* @return Track * @return Track
*/ */
vector<Track::Ptr> getTracks(bool trackReady = true) const override; vector<Track::Ptr> getTracks(bool trackReady = true) const override;
/** /**
* *
* @return , * @return ,
*/ */
float getDuration() const override; float getDuration() const override;
/** /**
* track监听器 * track监听器
*/ */
void setTrackListener(Listener *listener); void setTrackListener(Listener *listener);
protected: protected:
void onAddTrack(const Track::Ptr &track); void onAddTrack(const Track::Ptr &track);
protected: protected:
Listener *_listener = nullptr; Listener *_listener = nullptr;
AudioTrack::Ptr _audioTrack; AudioTrack::Ptr _audioTrack;
VideoTrack::Ptr _videoTrack; VideoTrack::Ptr _videoTrack;
Ticker _ticker; Ticker _ticker;
float _fDuration = 0; float _fDuration = 0;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -65,17 +65,17 @@ static uint8_t s_mute_adts[] = {0xff, 0xf1, 0x6c, 0x40, 0x2d, 0x3f, 0xfc, 0x00,
PlayerProxy::PlayerProxy(const string &strVhost, PlayerProxy::PlayerProxy(const string &strVhost,
const string &strApp, const string &strApp,
const string &strSrc, const string &strSrc,
bool bEnableRtsp, bool bEnableRtsp,
bool bEnableRtmp, bool bEnableRtmp,
bool bEnableHls, bool bEnableHls,
bool bEnableMp4, bool bEnableMp4,
int iRetryCount, int iRetryCount,
const EventPoller::Ptr &poller) : MediaPlayer(poller){ const EventPoller::Ptr &poller) : MediaPlayer(poller){
_strVhost = strVhost; _strVhost = strVhost;
_strApp = strApp; _strApp = strApp;
_strSrc = strSrc; _strSrc = strSrc;
_bEnableRtsp = bEnableRtsp; _bEnableRtsp = bEnableRtsp;
_bEnableRtmp = bEnableRtmp; _bEnableRtmp = bEnableRtmp;
_bEnableHls = bEnableHls; _bEnableHls = bEnableHls;
_bEnableMp4 = bEnableMp4; _bEnableMp4 = bEnableMp4;
_iRetryCount = iRetryCount; _iRetryCount = iRetryCount;
@ -90,88 +90,88 @@ void PlayerProxy::setOnClose(const function<void()> &cb){
} }
void PlayerProxy::play(const string &strUrlTmp) { void PlayerProxy::play(const string &strUrlTmp) {
weak_ptr<PlayerProxy> weakSelf = shared_from_this(); weak_ptr<PlayerProxy> weakSelf = shared_from_this();
std::shared_ptr<int> piFailedCnt(new int(0)); //连续播放失败次数 std::shared_ptr<int> piFailedCnt(new int(0)); //连续播放失败次数
setOnPlayResult([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) { setOnPlayResult([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return; return;
} }
if(strongSelf->_playCB) { if(strongSelf->_playCB) {
strongSelf->_playCB(err); strongSelf->_playCB(err);
strongSelf->_playCB = nullptr; strongSelf->_playCB = nullptr;
} }
if(!err) { if(!err) {
// 播放成功 // 播放成功
*piFailedCnt = 0;//连续播放失败次数清0 *piFailedCnt = 0;//连续播放失败次数清0
strongSelf->onPlaySuccess(); strongSelf->onPlaySuccess();
}else if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) { }else if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) {
// 播放失败,延时重试播放 // 播放失败,延时重试播放
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++); strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
} }
}); });
setOnShutdown([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) { setOnShutdown([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return; return;
} }
if(strongSelf->_mediaMuxer) { if(strongSelf->_mediaMuxer) {
auto tracks = strongSelf->getTracks(false); auto tracks = strongSelf->getTracks(false);
for (auto & track : tracks){ for (auto & track : tracks){
track->delDelegate(strongSelf->_mediaMuxer.get()); track->delDelegate(strongSelf->_mediaMuxer.get());
} }
GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay); GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay);
if (resetWhenRePlay) { if (resetWhenRePlay) {
strongSelf->_mediaMuxer.reset(); strongSelf->_mediaMuxer.reset();
} else { } else {
strongSelf->_mediaMuxer->resetTracks(); strongSelf->_mediaMuxer->resetTracks();
} }
} }
//播放异常中断,延时重试播放 //播放异常中断,延时重试播放
if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) { if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) {
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++); strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
} }
}); });
MediaPlayer::play(strUrlTmp); MediaPlayer::play(strUrlTmp);
MediaSource::Ptr mediaSource; MediaSource::Ptr mediaSource;
if(dynamic_pointer_cast<RtspPlayer>(_delegate)){ if(dynamic_pointer_cast<RtspPlayer>(_delegate)){
//rtsp拉流 //rtsp拉流
GET_CONFIG(bool,directProxy,Rtsp::kDirectProxy); GET_CONFIG(bool,directProxy,Rtsp::kDirectProxy);
if(directProxy && _bEnableRtsp){ if(directProxy && _bEnableRtsp){
mediaSource = std::make_shared<RtspMediaSource>(_strVhost,_strApp,_strSrc); mediaSource = std::make_shared<RtspMediaSource>(_strVhost,_strApp,_strSrc);
} }
} else if(dynamic_pointer_cast<RtmpPlayer>(_delegate)){ } else if(dynamic_pointer_cast<RtmpPlayer>(_delegate)){
//rtmp拉流 //rtmp拉流
if(_bEnableRtmp){ if(_bEnableRtmp){
mediaSource = std::make_shared<RtmpMediaSource>(_strVhost,_strApp,_strSrc); mediaSource = std::make_shared<RtmpMediaSource>(_strVhost,_strApp,_strSrc);
} }
} }
if(mediaSource){ if(mediaSource){
setMediaSouce(mediaSource); setMediaSouce(mediaSource);
mediaSource->setListener(shared_from_this()); mediaSource->setListener(shared_from_this());
} }
} }
PlayerProxy::~PlayerProxy() { PlayerProxy::~PlayerProxy() {
_timer.reset(); _timer.reset();
} }
void PlayerProxy::rePlay(const string &strUrl,int iFailedCnt){ void PlayerProxy::rePlay(const string &strUrl,int iFailedCnt){
auto iDelay = MAX(2 * 1000, MIN(iFailedCnt * 3000, 60*1000)); auto iDelay = MAX(2 * 1000, MIN(iFailedCnt * 3000, 60*1000));
weak_ptr<PlayerProxy> weakSelf = shared_from_this(); weak_ptr<PlayerProxy> weakSelf = shared_from_this();
_timer = std::make_shared<Timer>(iDelay / 1000.0f,[weakSelf,strUrl,iFailedCnt]() { _timer = std::make_shared<Timer>(iDelay / 1000.0f,[weakSelf,strUrl,iFailedCnt]() {
//播放失败次数越多,则延时越长 //播放失败次数越多,则延时越长
auto strongPlayer = weakSelf.lock(); auto strongPlayer = weakSelf.lock();
if(!strongPlayer) { if(!strongPlayer) {
return false; return false;
} }
WarnL << "重试播放[" << iFailedCnt << "]:" << strUrl; WarnL << "重试播放[" << iFailedCnt << "]:" << strUrl;
strongPlayer->MediaPlayer::play(strUrl); strongPlayer->MediaPlayer::play(strUrl);
return false; return false;
}, getPoller()); }, getPoller());
} }
bool PlayerProxy::close(MediaSource &sender,bool force) { bool PlayerProxy::close(MediaSource &sender,bool force) {
@ -179,19 +179,19 @@ bool PlayerProxy::close(MediaSource &sender,bool force) {
return false; return false;
} }
//通知其停止推流 //通知其停止推流
weak_ptr<PlayerProxy> weakSlef = dynamic_pointer_cast<PlayerProxy>(shared_from_this()); weak_ptr<PlayerProxy> weakSlef = dynamic_pointer_cast<PlayerProxy>(shared_from_this());
getPoller()->async_first([weakSlef]() { getPoller()->async_first([weakSlef]() {
auto stronSelf = weakSlef.lock(); auto stronSelf = weakSlef.lock();
if (stronSelf) { if (stronSelf) {
stronSelf->_mediaMuxer.reset(); stronSelf->_mediaMuxer.reset();
stronSelf->setMediaSouce(nullptr); stronSelf->setMediaSouce(nullptr);
stronSelf->teardown(); stronSelf->teardown();
if(stronSelf->_onClose){ if(stronSelf->_onClose){
stronSelf->_onClose(); stronSelf->_onClose();
} }
} }
}); });
WarnL << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; WarnL << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force;
return true; return true;
} }
@ -208,90 +208,90 @@ int PlayerProxy::totalReaderCount(){
} }
int PlayerProxy::totalReaderCount(MediaSource &sender) { int PlayerProxy::totalReaderCount(MediaSource &sender) {
return totalReaderCount(); return totalReaderCount();
} }
class MuteAudioMaker : public FrameDispatcher{ class MuteAudioMaker : public FrameDispatcher{
public: public:
typedef std::shared_ptr<MuteAudioMaker> Ptr; typedef std::shared_ptr<MuteAudioMaker> Ptr;
MuteAudioMaker(){}; MuteAudioMaker(){};
virtual ~MuteAudioMaker(){} virtual ~MuteAudioMaker(){}
void inputFrame(const Frame::Ptr &frame) override { void inputFrame(const Frame::Ptr &frame) override {
if(frame->getTrackType() == TrackVideo){ if(frame->getTrackType() == TrackVideo){
auto iAudioIndex = frame->dts() / MUTE_ADTS_DATA_MS; auto iAudioIndex = frame->dts() / MUTE_ADTS_DATA_MS;
if(_iAudioIndex != iAudioIndex){ if(_iAudioIndex != iAudioIndex){
_iAudioIndex = iAudioIndex; _iAudioIndex = iAudioIndex;
auto aacFrame = std::make_shared<AACFrameCacheAble>((char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS); auto aacFrame = std::make_shared<AACFrameCacheAble>((char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS);
FrameDispatcher::inputFrame(aacFrame); FrameDispatcher::inputFrame(aacFrame);
} }
} }
} }
private: private:
class AACFrameCacheAble : public AACFrameNoCacheAble{ class AACFrameCacheAble : public AACFrameNoCacheAble{
public: public:
template <typename ... ARGS> template <typename ... ARGS>
AACFrameCacheAble(ARGS && ...args) : AACFrameNoCacheAble(std::forward<ARGS>(args)...){}; AACFrameCacheAble(ARGS && ...args) : AACFrameNoCacheAble(std::forward<ARGS>(args)...){};
virtual ~AACFrameCacheAble() = default; virtual ~AACFrameCacheAble() = default;
bool cacheAble() const override { bool cacheAble() const override {
return true; return true;
} }
}; };
private: private:
int _iAudioIndex = 0; int _iAudioIndex = 0;
}; };
void PlayerProxy::onPlaySuccess() { void PlayerProxy::onPlaySuccess() {
GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay); GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay);
if (dynamic_pointer_cast<RtspMediaSource>(_pMediaSrc)) { if (dynamic_pointer_cast<RtspMediaSource>(_pMediaSrc)) {
//rtsp拉流代理 //rtsp拉流代理
if (resetWhenRePlay || !_mediaMuxer) { if (resetWhenRePlay || !_mediaMuxer) {
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), false, _bEnableRtmp, _bEnableHls, _bEnableMp4)); _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), false, _bEnableRtmp, _bEnableHls, _bEnableMp4));
} }
} else if (dynamic_pointer_cast<RtmpMediaSource>(_pMediaSrc)) { } else if (dynamic_pointer_cast<RtmpMediaSource>(_pMediaSrc)) {
//rtmp拉流代理 //rtmp拉流代理
if (resetWhenRePlay || !_mediaMuxer) { if (resetWhenRePlay || !_mediaMuxer) {
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, false, _bEnableHls, _bEnableMp4)); _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, false, _bEnableHls, _bEnableMp4));
} }
} else { } else {
//其他拉流代理 //其他拉流代理
if (resetWhenRePlay || !_mediaMuxer) { if (resetWhenRePlay || !_mediaMuxer) {
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, _bEnableRtmp, _bEnableHls, _bEnableMp4)); _mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, _bEnableRtmp, _bEnableHls, _bEnableMp4));
} }
} }
_mediaMuxer->setListener(shared_from_this()); _mediaMuxer->setListener(shared_from_this());
auto videoTrack = getTrack(TrackVideo,false); auto videoTrack = getTrack(TrackVideo,false);
if(videoTrack){ if(videoTrack){
//添加视频 //添加视频
_mediaMuxer->addTrack(videoTrack); _mediaMuxer->addTrack(videoTrack);
//视频数据写入_mediaMuxer //视频数据写入_mediaMuxer
videoTrack->addDelegate(_mediaMuxer); videoTrack->addDelegate(_mediaMuxer);
} }
//是否添加静音音频 //是否添加静音音频
GET_CONFIG(bool,addMuteAudio,General::kAddMuteAudio); GET_CONFIG(bool,addMuteAudio,General::kAddMuteAudio);
auto audioTrack = getTrack(TrackAudio, false); auto audioTrack = getTrack(TrackAudio, false);
if(audioTrack){ if(audioTrack){
//添加音频 //添加音频
_mediaMuxer->addTrack(audioTrack); _mediaMuxer->addTrack(audioTrack);
//音频数据写入_mediaMuxer //音频数据写入_mediaMuxer
audioTrack->addDelegate(_mediaMuxer); audioTrack->addDelegate(_mediaMuxer);
}else if(addMuteAudio && videoTrack){ }else if(addMuteAudio && videoTrack){
//没有音频信息,产生一个静音音频 //没有音频信息,产生一个静音音频
MuteAudioMaker::Ptr audioMaker = std::make_shared<MuteAudioMaker>(); MuteAudioMaker::Ptr audioMaker = std::make_shared<MuteAudioMaker>();
//videoTrack把数据写入MuteAudioMaker //videoTrack把数据写入MuteAudioMaker
videoTrack->addDelegate(audioMaker); videoTrack->addDelegate(audioMaker);
//添加一个静音Track至_mediaMuxer //添加一个静音Track至_mediaMuxer
_mediaMuxer->addTrack(std::make_shared<AACTrack>()); _mediaMuxer->addTrack(std::make_shared<AACTrack>());
//MuteAudioMaker生成静音音频然后写入_mediaMuxer //MuteAudioMaker生成静音音频然后写入_mediaMuxer
audioMaker->addDelegate(_mediaMuxer); audioMaker->addDelegate(_mediaMuxer);
} }
//添加完毕所有track防止单track情况下最大等待3秒 //添加完毕所有track防止单track情况下最大等待3秒
_mediaMuxer->addTrackCompleted(); _mediaMuxer->addTrackCompleted();
if(_pMediaSrc){ if(_pMediaSrc){

View File

@ -39,24 +39,24 @@ using namespace toolkit;
namespace mediakit { namespace mediakit {
class PlayerProxy :public MediaPlayer, class PlayerProxy :public MediaPlayer,
public std::enable_shared_from_this<PlayerProxy> , public std::enable_shared_from_this<PlayerProxy> ,
public MediaSourceEvent{ public MediaSourceEvent{
public: public:
typedef std::shared_ptr<PlayerProxy> Ptr; typedef std::shared_ptr<PlayerProxy> Ptr;
//如果iRetryCount<0,则一直重试播放否则重试iRetryCount次数 //如果iRetryCount<0,则一直重试播放否则重试iRetryCount次数
//默认一直重试 //默认一直重试
PlayerProxy(const string &strVhost, PlayerProxy(const string &strVhost,
const string &strApp, const string &strApp,
const string &strSrc, const string &strSrc,
bool bEnableRtsp = true, bool bEnableRtsp = true,
bool bEnableRtmp = true, bool bEnableRtmp = true,
bool bEnableHls = true, bool bEnableHls = true,
bool bEnableMp4 = false, bool bEnableMp4 = false,
int iRetryCount = -1, int iRetryCount = -1,
const EventPoller::Ptr &poller = nullptr); const EventPoller::Ptr &poller = nullptr);
virtual ~PlayerProxy(); virtual ~PlayerProxy();
/** /**
* play结果回调play执行之前有效 * play结果回调play执行之前有效
@ -81,19 +81,19 @@ public:
*/ */
int totalReaderCount() ; int totalReaderCount() ;
private: private:
//MediaSourceEvent override //MediaSourceEvent override
bool close(MediaSource &sender,bool force) override; bool close(MediaSource &sender,bool force) override;
void onNoneReader(MediaSource &sender) override; void onNoneReader(MediaSource &sender) override;
int totalReaderCount(MediaSource &sender) override; int totalReaderCount(MediaSource &sender) override;
void rePlay(const string &strUrl,int iFailedCnt); void rePlay(const string &strUrl,int iFailedCnt);
void onPlaySuccess(); void onPlaySuccess();
private: private:
bool _bEnableRtsp; bool _bEnableRtsp;
bool _bEnableRtmp; bool _bEnableRtmp;
bool _bEnableHls; bool _bEnableHls;
bool _bEnableMp4; bool _bEnableMp4;
int _iRetryCount; int _iRetryCount;
MultiMediaSourceMuxer::Ptr _mediaMuxer; MultiMediaSourceMuxer::Ptr _mediaMuxer;
string _strVhost; string _strVhost;
string _strApp; string _strApp;
string _strSrc; string _strSrc;

View File

@ -44,16 +44,16 @@ public:
virtual ~HlsMediaSource() = default; virtual ~HlsMediaSource() = default;
/** /**
* *
*/ */
const RingType::Ptr &getRing() const { const RingType::Ptr &getRing() const {
return _ring; return _ring;
} }
/** /**
* *
* @return * @return
*/ */
int readerCount() override { int readerCount() override {
return _readerCount.load(); return _readerCount.load();
} }

View File

@ -192,7 +192,7 @@ void MP4Muxer::addTrack(const Track::Ptr &track) {
return; return;
} }
struct mpeg4_avc_t avc = {0}; struct mpeg4_avc_t avc = {0};
string sps_pps = string("\x00\x00\x00\x01", 4) + h264_track->getSps() + string sps_pps = string("\x00\x00\x00\x01", 4) + h264_track->getSps() +
string("\x00\x00\x00\x01", 4) + h264_track->getPps(); string("\x00\x00\x00\x01", 4) + h264_track->getPps();
h264_annexbtomp4(&avc, sps_pps.data(), sps_pps.size(), NULL, 0, NULL, NULL); h264_annexbtomp4(&avc, sps_pps.data(), sps_pps.size(), NULL, 0, NULL, NULL);
@ -230,7 +230,7 @@ void MP4Muxer::addTrack(const Track::Ptr &track) {
return; return;
} }
struct mpeg4_hevc_t hevc = {0}; struct mpeg4_hevc_t hevc = {0};
string vps_sps_pps = string("\x00\x00\x00\x01", 4) + h265_track->getVps() + string vps_sps_pps = string("\x00\x00\x00\x01", 4) + h265_track->getVps() +
string("\x00\x00\x00\x01", 4) + h265_track->getSps() + string("\x00\x00\x00\x01", 4) + h265_track->getSps() +
string("\x00\x00\x00\x01", 4) + h265_track->getPps(); string("\x00\x00\x00\x01", 4) + h265_track->getPps();

View File

@ -39,118 +39,118 @@ namespace mediakit {
#ifdef ENABLE_MP4V2 #ifdef ENABLE_MP4V2
MP4Reader::MP4Reader(const string &strVhost,const string &strApp, const string &strId,const string &filePath ) { MP4Reader::MP4Reader(const string &strVhost,const string &strApp, const string &strId,const string &filePath ) {
_poller = WorkThreadPool::Instance().getPoller(); _poller = WorkThreadPool::Instance().getPoller();
auto strFileName = filePath; auto strFileName = filePath;
if(strFileName.empty()){ if(strFileName.empty()){
GET_CONFIG(string,recordPath,Record::kFilePath); GET_CONFIG(string,recordPath,Record::kFilePath);
GET_CONFIG(bool,enableVhost,General::kEnableVhost); GET_CONFIG(bool,enableVhost,General::kEnableVhost);
if(enableVhost){ if(enableVhost){
strFileName = strVhost + "/" + strApp + "/" + strId; strFileName = strVhost + "/" + strApp + "/" + strId;
}else{ }else{
strFileName = strApp + "/" + strId; strFileName = strApp + "/" + strId;
} }
strFileName = File::absolutePath(strFileName,recordPath); strFileName = File::absolutePath(strFileName,recordPath);
} }
_hMP4File = MP4Read(strFileName.data()); _hMP4File = MP4Read(strFileName.data());
if(_hMP4File == MP4_INVALID_FILE_HANDLE){ if(_hMP4File == MP4_INVALID_FILE_HANDLE){
throw runtime_error(StrPrinter << "打开MP4文件失败:" << strFileName << endl); throw runtime_error(StrPrinter << "打开MP4文件失败:" << strFileName << endl);
} }
_video_trId = MP4FindTrackId(_hMP4File, 0, MP4_VIDEO_TRACK_TYPE, 0); _video_trId = MP4FindTrackId(_hMP4File, 0, MP4_VIDEO_TRACK_TYPE, 0);
if(_video_trId != MP4_INVALID_TRACK_ID){ if(_video_trId != MP4_INVALID_TRACK_ID){
if(strcmp(MP4GetTrackMediaDataName(_hMP4File, _video_trId),"avc1") ==0){ if(strcmp(MP4GetTrackMediaDataName(_hMP4File, _video_trId),"avc1") ==0){
auto _video_timescale = MP4GetTrackTimeScale(_hMP4File, _video_trId); auto _video_timescale = MP4GetTrackTimeScale(_hMP4File, _video_trId);
auto _video_duration = MP4GetTrackDuration(_hMP4File, _video_trId); auto _video_duration = MP4GetTrackDuration(_hMP4File, _video_trId);
_video_num_samples = MP4GetTrackNumberOfSamples(_hMP4File, _video_trId); _video_num_samples = MP4GetTrackNumberOfSamples(_hMP4File, _video_trId);
_video_sample_max_size = MP4GetTrackMaxSampleSize(_hMP4File, _video_trId); _video_sample_max_size = MP4GetTrackMaxSampleSize(_hMP4File, _video_trId);
_video_width = MP4GetTrackVideoWidth(_hMP4File, _video_trId); _video_width = MP4GetTrackVideoWidth(_hMP4File, _video_trId);
_video_height = MP4GetTrackVideoHeight(_hMP4File, _video_trId); _video_height = MP4GetTrackVideoHeight(_hMP4File, _video_trId);
_video_framerate = MP4GetTrackVideoFrameRate(_hMP4File, _video_trId); _video_framerate = MP4GetTrackVideoFrameRate(_hMP4File, _video_trId);
_pcVideoSample = std::shared_ptr<uint8_t> (new uint8_t[_video_sample_max_size],[](uint8_t *ptr){ _pcVideoSample = std::shared_ptr<uint8_t> (new uint8_t[_video_sample_max_size],[](uint8_t *ptr){
delete [] ptr; delete [] ptr;
}); });
uint8_t **seqheader; uint8_t **seqheader;
uint8_t **pictheader; uint8_t **pictheader;
uint32_t *pictheadersize; uint32_t *pictheadersize;
uint32_t *seqheadersize; uint32_t *seqheadersize;
uint32_t ix; uint32_t ix;
if(MP4GetTrackH264SeqPictHeaders(_hMP4File, _video_trId, &seqheader, &seqheadersize, &pictheader, &pictheadersize)){ if(MP4GetTrackH264SeqPictHeaders(_hMP4File, _video_trId, &seqheader, &seqheadersize, &pictheader, &pictheadersize)){
for (ix = 0; seqheadersize[ix] != 0; ix++) { for (ix = 0; seqheadersize[ix] != 0; ix++) {
_strSps.assign((char *)(seqheader[ix]), seqheadersize[ix]); _strSps.assign((char *)(seqheader[ix]), seqheadersize[ix]);
float framerate; float framerate;
getAVCInfo(_strSps, (int &)_video_width, (int &)_video_height, framerate); getAVCInfo(_strSps, (int &)_video_width, (int &)_video_height, framerate);
_video_framerate = framerate; _video_framerate = framerate;
_strSps = string("\x0\x0\x0\x1",4) + _strSps; _strSps = string("\x0\x0\x0\x1",4) + _strSps;
MP4Free(seqheader[ix]); MP4Free(seqheader[ix]);
} }
MP4Free(seqheader); MP4Free(seqheader);
MP4Free(seqheadersize); MP4Free(seqheadersize);
for (ix = 0; pictheadersize[ix] != 0; ix++) { for (ix = 0; pictheadersize[ix] != 0; ix++) {
_strPps.assign("\x0\x0\x0\x1",4); _strPps.assign("\x0\x0\x0\x1",4);
_strPps.append((char *)(pictheader[ix]), pictheadersize[ix]); _strPps.append((char *)(pictheader[ix]), pictheadersize[ix]);
MP4Free(pictheader[ix]); MP4Free(pictheader[ix]);
} }
MP4Free(pictheader); MP4Free(pictheader);
MP4Free(pictheadersize); MP4Free(pictheadersize);
} }
_video_ms = 1000.0 * _video_duration / _video_timescale; _video_ms = 1000.0 * _video_duration / _video_timescale;
/*InfoL << "\r\n" /*InfoL << "\r\n"
<< _video_ms << "\r\n" << _video_ms << "\r\n"
<< _video_num_samples << "\r\n" << _video_num_samples << "\r\n"
<< _video_framerate << "\r\n" << _video_framerate << "\r\n"
<< _video_width << "\r\n" << _video_width << "\r\n"
<< _video_height << "\r\n";*/ << _video_height << "\r\n";*/
} else { } else {
//如果不是h264则忽略 //如果不是h264则忽略
_video_trId = MP4_INVALID_TRACK_ID; _video_trId = MP4_INVALID_TRACK_ID;
} }
} }
_audio_trId = MP4FindTrackId(_hMP4File, 0, MP4_AUDIO_TRACK_TYPE, 0); _audio_trId = MP4FindTrackId(_hMP4File, 0, MP4_AUDIO_TRACK_TYPE, 0);
if (_audio_trId != MP4_INVALID_TRACK_ID) { if (_audio_trId != MP4_INVALID_TRACK_ID) {
if (strcmp(MP4GetTrackMediaDataName(_hMP4File, _audio_trId), "mp4a") == 0) { if (strcmp(MP4GetTrackMediaDataName(_hMP4File, _audio_trId), "mp4a") == 0) {
_audio_sample_rate = MP4GetTrackTimeScale(_hMP4File, _audio_trId); _audio_sample_rate = MP4GetTrackTimeScale(_hMP4File, _audio_trId);
auto _audio_duration = MP4GetTrackDuration(_hMP4File, _audio_trId); auto _audio_duration = MP4GetTrackDuration(_hMP4File, _audio_trId);
_audio_num_samples = MP4GetTrackNumberOfSamples(_hMP4File,_audio_trId); _audio_num_samples = MP4GetTrackNumberOfSamples(_hMP4File,_audio_trId);
_audio_num_channels = MP4GetTrackAudioChannels(_hMP4File, _audio_trId); _audio_num_channels = MP4GetTrackAudioChannels(_hMP4File, _audio_trId);
_audio_sample_max_size = MP4GetTrackMaxSampleSize(_hMP4File,_audio_trId); _audio_sample_max_size = MP4GetTrackMaxSampleSize(_hMP4File,_audio_trId);
uint8_t *ppConfig; uint8_t *ppConfig;
uint32_t pConfigSize; uint32_t pConfigSize;
if(MP4GetTrackESConfiguration(_hMP4File,_audio_trId,&ppConfig,&pConfigSize)){ if(MP4GetTrackESConfiguration(_hMP4File,_audio_trId,&ppConfig,&pConfigSize)){
_strAacCfg.assign((char *)ppConfig, pConfigSize); _strAacCfg.assign((char *)ppConfig, pConfigSize);
makeAdtsHeader(_strAacCfg, _adts); makeAdtsHeader(_strAacCfg, _adts);
writeAdtsHeader(_adts,_adts.buffer); writeAdtsHeader(_adts,_adts.buffer);
getAACInfo(_adts, (int &)_audio_sample_rate, (int &)_audio_num_channels); getAACInfo(_adts, (int &)_audio_sample_rate, (int &)_audio_num_channels);
MP4Free(ppConfig); MP4Free(ppConfig);
} }
_audio_ms = 1000.0 * _audio_duration / _audio_sample_rate; _audio_ms = 1000.0 * _audio_duration / _audio_sample_rate;
/*InfoL << "\r\n" /*InfoL << "\r\n"
<< _audio_ms << "\r\n" << _audio_ms << "\r\n"
<< _audio_num_samples << "\r\n" << _audio_num_samples << "\r\n"
<< _audio_num_channels << "\r\n" << _audio_num_channels << "\r\n"
<< _audio_sample_rate << "\r\n";*/ << _audio_sample_rate << "\r\n";*/
}else{ }else{
_audio_trId = MP4_INVALID_TRACK_ID; _audio_trId = MP4_INVALID_TRACK_ID;
} }
} }
if(_audio_trId == MP4_INVALID_TRACK_ID && _video_trId == MP4_INVALID_TRACK_ID){ if(_audio_trId == MP4_INVALID_TRACK_ID && _video_trId == MP4_INVALID_TRACK_ID){
MP4Close(_hMP4File); MP4Close(_hMP4File);
_hMP4File = MP4_INVALID_FILE_HANDLE; _hMP4File = MP4_INVALID_FILE_HANDLE;
throw runtime_error(StrPrinter << "该MP4文件音视频格式不支持:" << strFileName << endl); throw runtime_error(StrPrinter << "该MP4文件音视频格式不支持:" << strFileName << endl);
} }
_iDuration = MAX(_video_ms,_audio_ms); _iDuration = MAX(_video_ms,_audio_ms);
_mediaMuxer.reset(new MultiMediaSourceMuxer(strVhost, strApp, strId, _iDuration / 1000.0, true, true, false, false)); _mediaMuxer.reset(new MultiMediaSourceMuxer(strVhost, strApp, strId, _iDuration / 1000.0, true, true, false, false));
if (_audio_trId != MP4_INVALID_TRACK_ID) { if (_audio_trId != MP4_INVALID_TRACK_ID) {
AACTrack::Ptr track = std::make_shared<AACTrack>(_strAacCfg); AACTrack::Ptr track = std::make_shared<AACTrack>(_strAacCfg);
_mediaMuxer->addTrack(track); _mediaMuxer->addTrack(track);
} }
if (_video_trId != MP4_INVALID_TRACK_ID) { if (_video_trId != MP4_INVALID_TRACK_ID) {
H264Track::Ptr track = std::make_shared<H264Track>(_strSps,_strPps); H264Track::Ptr track = std::make_shared<H264Track>(_strSps,_strPps);
_mediaMuxer->addTrack(track); _mediaMuxer->addTrack(track);
} }
//添加完毕所有track防止单track情况下最大等待3秒 //添加完毕所有track防止单track情况下最大等待3秒
_mediaMuxer->addTrackCompleted(); _mediaMuxer->addTrackCompleted();
@ -158,34 +158,34 @@ MP4Reader::MP4Reader(const string &strVhost,const string &strApp, const string &
MP4Reader::~MP4Reader() { MP4Reader::~MP4Reader() {
if (_hMP4File != MP4_INVALID_FILE_HANDLE) { if (_hMP4File != MP4_INVALID_FILE_HANDLE) {
MP4Close(_hMP4File); MP4Close(_hMP4File);
_hMP4File = MP4_INVALID_FILE_HANDLE; _hMP4File = MP4_INVALID_FILE_HANDLE;
} }
} }
void MP4Reader::startReadMP4() { void MP4Reader::startReadMP4() {
auto strongSelf = shared_from_this(); auto strongSelf = shared_from_this();
GET_CONFIG(uint32_t,sampleMS,Record::kSampleMS); GET_CONFIG(uint32_t,sampleMS,Record::kSampleMS);
_timer = std::make_shared<Timer>(sampleMS / 1000.0f,[strongSelf](){ _timer = std::make_shared<Timer>(sampleMS / 1000.0f,[strongSelf](){
return strongSelf->readSample(0,false); return strongSelf->readSample(0,false);
}, _poller); }, _poller);
//先读sampleMS毫秒的数据用于产生MediaSouce //先读sampleMS毫秒的数据用于产生MediaSouce
readSample(sampleMS, false); readSample(sampleMS, false);
_mediaMuxer->setListener(strongSelf); _mediaMuxer->setListener(strongSelf);
} }
bool MP4Reader::seekTo(MediaSource &sender,uint32_t ui32Stamp){ bool MP4Reader::seekTo(MediaSource &sender,uint32_t ui32Stamp){
seek(ui32Stamp); seek(ui32Stamp);
return true; return true;
} }
bool MP4Reader::close(MediaSource &sender,bool force){ bool MP4Reader::close(MediaSource &sender,bool force){
if(!_mediaMuxer || (!force && _mediaMuxer->totalReaderCount())){ if(!_mediaMuxer || (!force && _mediaMuxer->totalReaderCount())){
return false; return false;
} }
_timer.reset(); _timer.reset();
WarnL << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; WarnL << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force;
return true; return true;
} }
@ -198,145 +198,145 @@ void MP4Reader::onNoneReader(MediaSource &sender) {
} }
int MP4Reader::totalReaderCount(MediaSource &sender) { int MP4Reader::totalReaderCount(MediaSource &sender) {
return _mediaMuxer ? _mediaMuxer->totalReaderCount() : sender.readerCount(); return _mediaMuxer ? _mediaMuxer->totalReaderCount() : sender.readerCount();
} }
bool MP4Reader::readSample(int iTimeInc,bool justSeekSyncFrame) { bool MP4Reader::readSample(int iTimeInc,bool justSeekSyncFrame) {
TimeTicker(); TimeTicker();
lock_guard<recursive_mutex> lck(_mtx); lock_guard<recursive_mutex> lck(_mtx);
auto bFlag0 = readVideoSample(iTimeInc,justSeekSyncFrame);//数据没读完 auto bFlag0 = readVideoSample(iTimeInc,justSeekSyncFrame);//数据没读完
auto bFlag1 = readAudioSample(iTimeInc,justSeekSyncFrame);//数据没读完 auto bFlag1 = readAudioSample(iTimeInc,justSeekSyncFrame);//数据没读完
auto bFlag2 = _mediaMuxer->totalReaderCount() > 0;//读取者大于0 auto bFlag2 = _mediaMuxer->totalReaderCount() > 0;//读取者大于0
if((bFlag0 || bFlag1) && bFlag2){ if((bFlag0 || bFlag1) && bFlag2){
_alive.resetTime(); _alive.resetTime();
} }
//重头开始循环读取 //重头开始循环读取
GET_CONFIG(bool,fileRepeat,Record::kFileRepeat); GET_CONFIG(bool,fileRepeat,Record::kFileRepeat);
if (fileRepeat && !bFlag0 && !bFlag1) { if (fileRepeat && !bFlag0 && !bFlag1) {
seek(0); seek(0);
} }
//DebugL << "alive ..."; //DebugL << "alive ...";
//3秒延时关闭 //3秒延时关闭
return _alive.elapsedTime() < 3 * 1000; return _alive.elapsedTime() < 3 * 1000;
} }
inline bool MP4Reader::readVideoSample(int iTimeInc,bool justSeekSyncFrame) { inline bool MP4Reader::readVideoSample(int iTimeInc,bool justSeekSyncFrame) {
if (_video_trId != MP4_INVALID_TRACK_ID) { if (_video_trId != MP4_INVALID_TRACK_ID) {
auto iNextSample = getVideoSampleId(iTimeInc); auto iNextSample = getVideoSampleId(iTimeInc);
MP4SampleId iIdx = _video_current; MP4SampleId iIdx = _video_current;
for (; iIdx < iNextSample; iIdx++) { for (; iIdx < iNextSample; iIdx++) {
uint8_t *pBytes = _pcVideoSample.get(); uint8_t *pBytes = _pcVideoSample.get();
uint32_t numBytes = _video_sample_max_size; uint32_t numBytes = _video_sample_max_size;
MP4Duration pRenderingOffset; MP4Duration pRenderingOffset;
if(MP4ReadSample(_hMP4File, _video_trId, iIdx + 1, &pBytes, &numBytes,NULL,NULL,&pRenderingOffset,&_bSyncSample)){ if(MP4ReadSample(_hMP4File, _video_trId, iIdx + 1, &pBytes, &numBytes,NULL,NULL,&pRenderingOffset,&_bSyncSample)){
if (!justSeekSyncFrame) { if (!justSeekSyncFrame) {
uint32_t dts = (double) _video_ms * iIdx / _video_num_samples; uint32_t dts = (double) _video_ms * iIdx / _video_num_samples;
uint32_t pts = dts + pRenderingOffset / 90; uint32_t pts = dts + pRenderingOffset / 90;
uint32_t iOffset = 0; uint32_t iOffset = 0;
while (iOffset < numBytes) { while (iOffset < numBytes) {
uint32_t iFrameLen; uint32_t iFrameLen;
memcpy(&iFrameLen,pBytes + iOffset,4); memcpy(&iFrameLen,pBytes + iOffset,4);
iFrameLen = ntohl(iFrameLen); iFrameLen = ntohl(iFrameLen);
if(iFrameLen + iOffset + 4> numBytes){ if(iFrameLen + iOffset + 4> numBytes){
break; break;
} }
memcpy(pBytes + iOffset, "\x0\x0\x0\x1", 4); memcpy(pBytes + iOffset, "\x0\x0\x0\x1", 4);
writeH264(pBytes + iOffset, iFrameLen + 4, dts, pts); writeH264(pBytes + iOffset, iFrameLen + 4, dts, pts);
iOffset += (iFrameLen + 4); iOffset += (iFrameLen + 4);
} }
}else if(_bSyncSample){ }else if(_bSyncSample){
break; break;
} }
}else{ }else{
ErrorL << "读取视频失败:" << iIdx + 1; ErrorL << "读取视频失败:" << iIdx + 1;
} }
} }
_video_current = iIdx; _video_current = iIdx;
return _video_current < _video_num_samples; return _video_current < _video_num_samples;
} }
return false; return false;
} }
inline bool MP4Reader::readAudioSample(int iTimeInc,bool justSeekSyncFrame) { inline bool MP4Reader::readAudioSample(int iTimeInc,bool justSeekSyncFrame) {
if (_audio_trId != MP4_INVALID_TRACK_ID) { if (_audio_trId != MP4_INVALID_TRACK_ID) {
auto iNextSample = getAudioSampleId(iTimeInc); auto iNextSample = getAudioSampleId(iTimeInc);
for (auto i = _audio_current; i < iNextSample; i++) { for (auto i = _audio_current; i < iNextSample; i++) {
uint32_t numBytes = _audio_sample_max_size; uint32_t numBytes = _audio_sample_max_size;
uint8_t *pBytes = _adts.buffer + 7; uint8_t *pBytes = _adts.buffer + 7;
if(MP4ReadSample(_hMP4File, _audio_trId, i + 1, &pBytes, &numBytes)){ if(MP4ReadSample(_hMP4File, _audio_trId, i + 1, &pBytes, &numBytes)){
if (!justSeekSyncFrame) { if (!justSeekSyncFrame) {
uint32_t dts = (double) _audio_ms * i / _audio_num_samples; uint32_t dts = (double) _audio_ms * i / _audio_num_samples;
_adts.aac_frame_length = 7 + numBytes; _adts.aac_frame_length = 7 + numBytes;
writeAdtsHeader(_adts, _adts.buffer); writeAdtsHeader(_adts, _adts.buffer);
writeAAC(_adts.buffer, _adts.aac_frame_length, dts); writeAAC(_adts.buffer, _adts.aac_frame_length, dts);
} }
}else{ }else{
ErrorL << "读取音频失败:" << i+ 1; ErrorL << "读取音频失败:" << i+ 1;
} }
} }
_audio_current = iNextSample; _audio_current = iNextSample;
return _audio_current < _audio_num_samples; return _audio_current < _audio_num_samples;
} }
return false; return false;
} }
inline void MP4Reader::writeH264(uint8_t *pucData,int iLen,uint32_t dts,uint32_t pts) { inline void MP4Reader::writeH264(uint8_t *pucData,int iLen,uint32_t dts,uint32_t pts) {
_mediaMuxer->inputFrame(std::make_shared<H264FrameNoCacheAble>((char*)pucData,iLen,dts,pts)); _mediaMuxer->inputFrame(std::make_shared<H264FrameNoCacheAble>((char*)pucData,iLen,dts,pts));
} }
inline void MP4Reader::writeAAC(uint8_t *pucData,int iLen,uint32_t uiStamp) { inline void MP4Reader::writeAAC(uint8_t *pucData,int iLen,uint32_t uiStamp) {
_mediaMuxer->inputFrame(std::make_shared<AACFrameNoCacheAble>((char*)pucData,iLen,uiStamp)); _mediaMuxer->inputFrame(std::make_shared<AACFrameNoCacheAble>((char*)pucData,iLen,uiStamp));
} }
inline MP4SampleId MP4Reader::getVideoSampleId(int iTimeInc ) { inline MP4SampleId MP4Reader::getVideoSampleId(int iTimeInc ) {
MP4SampleId video_current = (double)_video_num_samples * (_iSeekTime + _ticker.elapsedTime() + iTimeInc) / _video_ms; MP4SampleId video_current = (double)_video_num_samples * (_iSeekTime + _ticker.elapsedTime() + iTimeInc) / _video_ms;
video_current = MAX(0,MIN(_video_num_samples, video_current)); video_current = MAX(0,MIN(_video_num_samples, video_current));
return video_current; return video_current;
} }
inline MP4SampleId MP4Reader::getAudioSampleId(int iTimeInc) { inline MP4SampleId MP4Reader::getAudioSampleId(int iTimeInc) {
MP4SampleId audio_current = (double)_audio_num_samples * (_iSeekTime + _ticker.elapsedTime() + iTimeInc) / _audio_ms ; MP4SampleId audio_current = (double)_audio_num_samples * (_iSeekTime + _ticker.elapsedTime() + iTimeInc) / _audio_ms ;
audio_current = MAX(0,MIN(_audio_num_samples,audio_current)); audio_current = MAX(0,MIN(_audio_num_samples,audio_current));
return audio_current; return audio_current;
} }
inline void MP4Reader::setSeekTime(uint32_t iSeekTime){ inline void MP4Reader::setSeekTime(uint32_t iSeekTime){
_iSeekTime = MAX(0, MIN(iSeekTime,_iDuration)); _iSeekTime = MAX(0, MIN(iSeekTime,_iDuration));
_ticker.resetTime(); _ticker.resetTime();
if (_audio_trId != MP4_INVALID_TRACK_ID) { if (_audio_trId != MP4_INVALID_TRACK_ID) {
_audio_current = getAudioSampleId(); _audio_current = getAudioSampleId();
} }
if (_video_trId != MP4_INVALID_TRACK_ID) { if (_video_trId != MP4_INVALID_TRACK_ID) {
_video_current = getVideoSampleId(); _video_current = getVideoSampleId();
} }
} }
inline uint32_t MP4Reader::getVideoCurrentTime(){ inline uint32_t MP4Reader::getVideoCurrentTime(){
return (double)_video_current * _video_ms /_video_num_samples; return (double)_video_current * _video_ms /_video_num_samples;
} }
void MP4Reader::seek(uint32_t iSeekTime,bool bReStart){ void MP4Reader::seek(uint32_t iSeekTime,bool bReStart){
lock_guard<recursive_mutex> lck(_mtx); lock_guard<recursive_mutex> lck(_mtx);
if(iSeekTime == 0 || _video_trId == MP4_INVALID_TRACK_ID){ if(iSeekTime == 0 || _video_trId == MP4_INVALID_TRACK_ID){
setSeekTime(iSeekTime); setSeekTime(iSeekTime);
}else{ }else{
setSeekTime(iSeekTime - 5000); setSeekTime(iSeekTime - 5000);
//在之后的10秒查找关键帧 //在之后的10秒查找关键帧
readVideoSample(10000, true); readVideoSample(10000, true);
if (_bSyncSample) { if (_bSyncSample) {
//找到关键帧 //找到关键帧
auto iIdr = _video_current; auto iIdr = _video_current;
setSeekTime(getVideoCurrentTime()); setSeekTime(getVideoCurrentTime());
_video_current = iIdr; _video_current = iIdr;
}else{ }else{
//未找到关键帧 //未找到关键帧
setSeekTime(iSeekTime); setSeekTime(iSeekTime);
} }
} }
_mediaMuxer->setTimeStamp(_iSeekTime); _mediaMuxer->setTimeStamp(_iSeekTime);
if(bReStart){ if(bReStart){
_timer.reset(); _timer.reset();
startReadMP4(); startReadMP4();
} }
} }
#endif //ENABLE_MP4V2 #endif //ENABLE_MP4V2
@ -344,26 +344,26 @@ void MP4Reader::seek(uint32_t iSeekTime,bool bReStart){
MediaSource::Ptr MP4Reader::onMakeMediaSource(const string &strSchema, MediaSource::Ptr MP4Reader::onMakeMediaSource(const string &strSchema,
const string &strVhost, const string &strVhost,
const string &strApp, const string &strApp,
const string &strId, const string &strId,
const string &filePath, const string &filePath,
bool checkApp ){ bool checkApp ){
#ifdef ENABLE_MP4V2 #ifdef ENABLE_MP4V2
GET_CONFIG(string,appName,Record::kAppName); GET_CONFIG(string,appName,Record::kAppName);
if (checkApp && strApp != appName) { if (checkApp && strApp != appName) {
return nullptr; return nullptr;
} }
try { try {
MP4Reader::Ptr pReader(new MP4Reader(strVhost,strApp, strId,filePath)); MP4Reader::Ptr pReader(new MP4Reader(strVhost,strApp, strId,filePath));
pReader->startReadMP4(); pReader->startReadMP4();
return MediaSource::find(strSchema,strVhost,strApp, strId, false); return MediaSource::find(strSchema,strVhost,strApp, strId, false);
} catch (std::exception &ex) { } catch (std::exception &ex) {
WarnL << ex.what(); WarnL << ex.what();
return nullptr; return nullptr;
} }
#else #else
return nullptr; return nullptr;
#endif //ENABLE_MP4V2 #endif //ENABLE_MP4V2
} }

View File

@ -39,91 +39,91 @@ namespace mediakit {
class MP4Reader : public std::enable_shared_from_this<MP4Reader> ,public MediaSourceEvent{ class MP4Reader : public std::enable_shared_from_this<MP4Reader> ,public MediaSourceEvent{
public: public:
typedef std::shared_ptr<MP4Reader> Ptr; typedef std::shared_ptr<MP4Reader> Ptr;
virtual ~MP4Reader(); virtual ~MP4Reader();
/** /**
* mp4文件使RtspMediaSource和RtmpMediaSource * mp4文件使RtspMediaSource和RtmpMediaSource
* @param strVhost * @param strVhost
* @param strApp * @param strApp
* @param strId id * @param strId id
* @param filePath 使 * @param filePath 使
*/ */
MP4Reader(const string &strVhost,const string &strApp, const string &strId,const string &filePath = ""); MP4Reader(const string &strVhost,const string &strApp, const string &strId,const string &filePath = "");
/** /**
* MP4文件MP4Reader对象一经过调用startReadMP4方法 * MP4文件MP4Reader对象一经过调用startReadMP4方法
* ,MP4Reader对象是不会被销毁的() * ,MP4Reader对象是不会被销毁的()
*/ */
void startReadMP4(); void startReadMP4();
/** /**
* MP4Reader对象然后查找相关的MediaSource对象 * MP4Reader对象然后查找相关的MediaSource对象
* @param strSchema * @param strSchema
* @param strVhost * @param strVhost
* @param strApp * @param strApp
* @param strId id * @param strId id
* @param filePath 使 * @param filePath 使
* @param checkApp app访 * @param checkApp app访
* @return MediaSource * @return MediaSource
*/ */
static MediaSource::Ptr onMakeMediaSource(const string &strSchema, static MediaSource::Ptr onMakeMediaSource(const string &strSchema,
const string &strVhost, const string &strVhost,
const string &strApp, const string &strApp,
const string &strId, const string &strId,
const string &filePath = "", const string &filePath = "",
bool checkApp = true); bool checkApp = true);
private: private:
//MediaSourceEvent override //MediaSourceEvent override
bool seekTo(MediaSource &sender,uint32_t ui32Stamp) override; bool seekTo(MediaSource &sender,uint32_t ui32Stamp) override;
bool close(MediaSource &sender,bool force) override; bool close(MediaSource &sender,bool force) override;
void onNoneReader(MediaSource &sender) override; void onNoneReader(MediaSource &sender) override;
int totalReaderCount(MediaSource &sender) override; int totalReaderCount(MediaSource &sender) override;
#ifdef ENABLE_MP4V2 #ifdef ENABLE_MP4V2
void seek(uint32_t iSeekTime,bool bReStart = true); void seek(uint32_t iSeekTime,bool bReStart = true);
inline void setSeekTime(uint32_t iSeekTime); inline void setSeekTime(uint32_t iSeekTime);
inline uint32_t getVideoCurrentTime(); inline uint32_t getVideoCurrentTime();
inline MP4SampleId getVideoSampleId(int iTimeInc = 0); inline MP4SampleId getVideoSampleId(int iTimeInc = 0);
inline MP4SampleId getAudioSampleId(int iTimeInc = 0); inline MP4SampleId getAudioSampleId(int iTimeInc = 0);
bool readSample(int iTimeInc, bool justSeekSyncFrame); bool readSample(int iTimeInc, bool justSeekSyncFrame);
inline bool readVideoSample(int iTimeInc,bool justSeekSyncFrame); inline bool readVideoSample(int iTimeInc,bool justSeekSyncFrame);
inline bool readAudioSample(int iTimeInc,bool justSeekSyncFrame); inline bool readAudioSample(int iTimeInc,bool justSeekSyncFrame);
inline void writeH264(uint8_t *pucData,int iLen,uint32_t dts,uint32_t pts); inline void writeH264(uint8_t *pucData,int iLen,uint32_t dts,uint32_t pts);
inline void writeAAC(uint8_t *pucData,int iLen,uint32_t uiStamp); inline void writeAAC(uint8_t *pucData,int iLen,uint32_t uiStamp);
private: private:
MP4FileHandle _hMP4File = MP4_INVALID_FILE_HANDLE; MP4FileHandle _hMP4File = MP4_INVALID_FILE_HANDLE;
MP4TrackId _video_trId = MP4_INVALID_TRACK_ID; MP4TrackId _video_trId = MP4_INVALID_TRACK_ID;
uint32_t _video_ms = 0; uint32_t _video_ms = 0;
uint32_t _video_num_samples = 0; uint32_t _video_num_samples = 0;
uint32_t _video_sample_max_size = 0; uint32_t _video_sample_max_size = 0;
uint32_t _video_width = 0; uint32_t _video_width = 0;
uint32_t _video_height = 0; uint32_t _video_height = 0;
uint32_t _video_framerate = 0; uint32_t _video_framerate = 0;
string _strPps; string _strPps;
string _strSps; string _strSps;
bool _bSyncSample = false; bool _bSyncSample = false;
MP4TrackId _audio_trId = MP4_INVALID_TRACK_ID; MP4TrackId _audio_trId = MP4_INVALID_TRACK_ID;
uint32_t _audio_ms = 0; uint32_t _audio_ms = 0;
uint32_t _audio_num_samples = 0; uint32_t _audio_num_samples = 0;
uint32_t _audio_sample_max_size = 0; uint32_t _audio_sample_max_size = 0;
uint32_t _audio_sample_rate = 0; uint32_t _audio_sample_rate = 0;
uint32_t _audio_num_channels = 0; uint32_t _audio_num_channels = 0;
string _strAacCfg; string _strAacCfg;
AACFrame _adts; AACFrame _adts;
int _iDuration = 0; int _iDuration = 0;
MultiMediaSourceMuxer::Ptr _mediaMuxer; MultiMediaSourceMuxer::Ptr _mediaMuxer;
MP4SampleId _video_current = 0; MP4SampleId _video_current = 0;
MP4SampleId _audio_current = 0; MP4SampleId _audio_current = 0;
std::shared_ptr<uint8_t> _pcVideoSample; std::shared_ptr<uint8_t> _pcVideoSample;
int _iSeekTime = 0 ; int _iSeekTime = 0 ;
Ticker _ticker; Ticker _ticker;
Ticker _alive; Ticker _alive;
recursive_mutex _mtx; recursive_mutex _mtx;
Timer::Ptr _timer; Timer::Ptr _timer;
EventPoller::Ptr _poller; EventPoller::Ptr _poller;
#endif //ENABLE_MP4V2 #endif //ENABLE_MP4V2
}; };

View File

@ -36,31 +36,31 @@ using namespace toolkit;
namespace mediakit { namespace mediakit {
MP4Recorder::MP4Recorder(const string& strPath, MP4Recorder::MP4Recorder(const string& strPath,
const string &strVhost, const string &strVhost,
const string &strApp, const string &strApp,
const string &strStreamId) { const string &strStreamId) {
_strPath = strPath; _strPath = strPath;
/////record 业务逻辑////// /////record 业务逻辑//////
_info.strAppName = strApp; _info.strAppName = strApp;
_info.strStreamId = strStreamId; _info.strStreamId = strStreamId;
_info.strVhost = strVhost; _info.strVhost = strVhost;
_info.strFolder = strPath; _info.strFolder = strPath;
} }
MP4Recorder::~MP4Recorder() { MP4Recorder::~MP4Recorder() {
closeFile(); closeFile();
} }
void MP4Recorder::createFile() { void MP4Recorder::createFile() {
closeFile(); closeFile();
auto strDate = getTimeStr("%Y-%m-%d"); auto strDate = getTimeStr("%Y-%m-%d");
auto strTime = getTimeStr("%H-%M-%S"); auto strTime = getTimeStr("%H-%M-%S");
auto strFileTmp = _strPath + strDate + "/." + strTime + ".mp4"; auto strFileTmp = _strPath + strDate + "/." + strTime + ".mp4";
auto strFile = _strPath + strDate + "/" + strTime + ".mp4"; auto strFile = _strPath + strDate + "/" + strTime + ".mp4";
/////record 业务逻辑////// /////record 业务逻辑//////
_info.ui64StartedTime = ::time(NULL); _info.ui64StartedTime = ::time(NULL);
_info.strFileName = strTime + ".mp4"; _info.strFileName = strTime + ".mp4";
_info.strFilePath = strFile; _info.strFilePath = strFile;
GET_CONFIG(string,appName,Record::kAppName); GET_CONFIG(string,appName,Record::kAppName);
_info.strUrl = appName + "/" _info.strUrl = appName + "/"
+ _info.strAppName + "/" + _info.strAppName + "/"
@ -68,78 +68,78 @@ void MP4Recorder::createFile() {
+ strDate + "/" + strDate + "/"
+ strTime + ".mp4"; + strTime + ".mp4";
try { try {
_muxer = std::make_shared<MP4MuxerFile>(strFileTmp.data()); _muxer = std::make_shared<MP4MuxerFile>(strFileTmp.data());
for(auto &track :_tracks){ for(auto &track :_tracks){
//添加track //添加track
_muxer->addTrack(track); _muxer->addTrack(track);
} }
_strFileTmp = strFileTmp; _strFileTmp = strFileTmp;
_strFile = strFile; _strFile = strFile;
_createFileTicker.resetTime(); _createFileTicker.resetTime();
}catch(std::exception &ex) { }catch(std::exception &ex) {
WarnL << ex.what(); WarnL << ex.what();
} }
} }
void MP4Recorder::asyncClose() { void MP4Recorder::asyncClose() {
auto muxer = _muxer; auto muxer = _muxer;
auto strFileTmp = _strFileTmp; auto strFileTmp = _strFileTmp;
auto strFile = _strFile; auto strFile = _strFile;
auto info = _info; auto info = _info;
WorkThreadPool::Instance().getExecutor()->async([muxer,strFileTmp,strFile,info]() { WorkThreadPool::Instance().getExecutor()->async([muxer,strFileTmp,strFile,info]() {
//获取文件录制时间放在关闭mp4之前是为了忽略关闭mp4执行时间 //获取文件录制时间放在关闭mp4之前是为了忽略关闭mp4执行时间
const_cast<MP4Info&>(info).ui64TimeLen = ::time(NULL) - info.ui64StartedTime; const_cast<MP4Info&>(info).ui64TimeLen = ::time(NULL) - info.ui64StartedTime;
//关闭mp4非常耗时所以要放在后台线程执行 //关闭mp4非常耗时所以要放在后台线程执行
const_cast<MP4MuxerFile::Ptr &>(muxer).reset(); const_cast<MP4MuxerFile::Ptr &>(muxer).reset();
//临时文件名改成正式文件名防止mp4未完成时被访问 //临时文件名改成正式文件名防止mp4未完成时被访问
rename(strFileTmp.data(),strFile.data()); rename(strFileTmp.data(),strFile.data());
//获取文件大小 //获取文件大小
struct stat fileData; struct stat fileData;
stat(strFile.data(), &fileData); stat(strFile.data(), &fileData);
const_cast<MP4Info&>(info).ui64FileSize = fileData.st_size; const_cast<MP4Info&>(info).ui64FileSize = fileData.st_size;
/////record 业务逻辑////// /////record 业务逻辑//////
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,info); NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,info);
}); });
} }
void MP4Recorder::closeFile() { void MP4Recorder::closeFile() {
if (_muxer) { if (_muxer) {
asyncClose(); asyncClose();
_muxer = nullptr; _muxer = nullptr;
} }
} }
void MP4Recorder::inputFrame(const Frame::Ptr &frame) { void MP4Recorder::inputFrame(const Frame::Ptr &frame) {
GET_CONFIG(uint32_t,recordSec,Record::kFileSecond); GET_CONFIG(uint32_t,recordSec,Record::kFileSecond);
if(!_muxer || ((_createFileTicker.elapsedTime() > recordSec * 1000) && if(!_muxer || ((_createFileTicker.elapsedTime() > recordSec * 1000) &&
(!_haveVideo || (_haveVideo && frame->keyFrame()))) ){ (!_haveVideo || (_haveVideo && frame->keyFrame()))) ){
//成立条件 //成立条件
//1、_muxer为空 //1、_muxer为空
//2、到了切片时间并且只有音频 //2、到了切片时间并且只有音频
//3、到了切片时间有视频并且遇到视频的关键帧 //3、到了切片时间有视频并且遇到视频的关键帧
createFile(); createFile();
} }
if(_muxer){ if(_muxer){
//生成mp4文件 //生成mp4文件
_muxer->inputFrame(frame); _muxer->inputFrame(frame);
} }
} }
void MP4Recorder::addTrack(const Track::Ptr & track){ void MP4Recorder::addTrack(const Track::Ptr & track){
//保存所有的track为创建MP4MuxerFile做准备 //保存所有的track为创建MP4MuxerFile做准备
_tracks.emplace_back(track); _tracks.emplace_back(track);
if(track->getTrackType() == TrackVideo){ if(track->getTrackType() == TrackVideo){
_haveVideo = true; _haveVideo = true;
} }
} }
void MP4Recorder::resetTracks() { void MP4Recorder::resetTracks() {
closeFile(); closeFile();
_tracks.clear(); _tracks.clear();
_haveVideo = false; _haveVideo = false;
_createFileTicker.resetTime(); _createFileTicker.resetTime();
} }
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -42,38 +42,38 @@ namespace mediakit {
class MP4Info { class MP4Info {
public: public:
time_t ui64StartedTime; //GMT标准时间单位秒 time_t ui64StartedTime; //GMT标准时间单位秒
time_t ui64TimeLen;//录像长度,单位秒 time_t ui64TimeLen;//录像长度,单位秒
off_t ui64FileSize;//文件大小单位BYTE off_t ui64FileSize;//文件大小单位BYTE
string strFilePath;//文件路径 string strFilePath;//文件路径
string strFileName;//文件名称 string strFileName;//文件名称
string strFolder;//文件夹路径 string strFolder;//文件夹路径
string strUrl;//播放路径 string strUrl;//播放路径
string strAppName;//应用名称 string strAppName;//应用名称
string strStreamId;//流ID string strStreamId;//流ID
string strVhost;//vhost string strVhost;//vhost
}; };
#ifdef ENABLE_MP4RECORD #ifdef ENABLE_MP4RECORD
class MP4Recorder : public MediaSinkInterface{ class MP4Recorder : public MediaSinkInterface{
public: public:
typedef std::shared_ptr<MP4Recorder> Ptr; typedef std::shared_ptr<MP4Recorder> Ptr;
MP4Recorder(const string &strPath, MP4Recorder(const string &strPath,
const string &strVhost, const string &strVhost,
const string &strApp, const string &strApp,
const string &strStreamId); const string &strStreamId);
virtual ~MP4Recorder(); virtual ~MP4Recorder();
/** /**
* Track * Track
*/ */
void resetTracks() override; void resetTracks() override;
/** /**
* frame * frame
*/ */
void inputFrame(const Frame::Ptr &frame) override; void inputFrame(const Frame::Ptr &frame) override;
/** /**
* ready状态的track * ready状态的track
@ -84,14 +84,14 @@ private:
void closeFile(); void closeFile();
void asyncClose(); void asyncClose();
private: private:
string _strPath; string _strPath;
string _strFile; string _strFile;
string _strFileTmp; string _strFileTmp;
Ticker _createFileTicker; Ticker _createFileTicker;
MP4Info _info; MP4Info _info;
bool _haveVideo = false; bool _haveVideo = false;
MP4MuxerFile::Ptr _muxer; MP4MuxerFile::Ptr _muxer;
list<Track::Ptr> _tracks; list<Track::Ptr> _tracks;
}; };
#endif ///ENABLE_MP4RECORD #endif ///ENABLE_MP4RECORD

View File

@ -37,32 +37,32 @@ class MediaSinkInterface;
class Recorder{ class Recorder{
public: public:
typedef enum { typedef enum {
// 未录制 // 未录制
status_not_record = 0, status_not_record = 0,
// 等待MediaSource注册注册成功后立即开始录制 // 等待MediaSource注册注册成功后立即开始录制
status_wait_record = 1, status_wait_record = 1,
// MediaSource已注册并且正在录制 // MediaSource已注册并且正在录制
status_recording = 2, status_recording = 2,
} status; } status;
typedef enum { typedef enum {
// 录制hls // 录制hls
type_hls = 0, type_hls = 0,
// 录制MP4 // 录制MP4
type_mp4 = 1 type_mp4 = 1
} type; } type;
/** /**
* *
* @param type hls还是MP4录制 * @param type hls还是MP4录制
* @param vhost * @param vhost
* @param app * @param app
* @param stream_id id * @param stream_id id
* @param customized_path * @param customized_path
* @return * @return
*/ */
static string getRecordPath(type type, const string &vhost, const string &app, const string &stream_id,const string &customized_path = ""); static string getRecordPath(type type, const string &vhost, const string &app, const string &stream_id,const string &customized_path = "");
/** /**
* *
@ -72,57 +72,57 @@ public:
* @param stream_id id * @param stream_id id
* @return * @return
*/ */
static status getRecordStatus(type type, const string &vhost, const string &app, const string &stream_id); static status getRecordStatus(type type, const string &vhost, const string &app, const string &stream_id);
/** /**
* *
* @param type hls还是MP4录制 * @param type hls还是MP4录制
* @param vhost * @param vhost
* @param app * @param app
* @param stream_id id * @param stream_id id
* @param customized_path * @param customized_path
* @param waitForRecord false将返回失败 * @param waitForRecord false将返回失败
* @param continueRecord * @param continueRecord
* @return 0 * @return 0
*/ */
static int startRecord(type type, const string &vhost, const string &app, const string &stream_id,const string &customized_path,bool waitForRecord, bool continueRecord); static int startRecord(type type, const string &vhost, const string &app, const string &stream_id,const string &customized_path,bool waitForRecord, bool continueRecord);
/** /**
* *
* @param type hls还是MP4录制 * @param type hls还是MP4录制
* @param vhost * @param vhost
* @param app * @param app
* @param stream_id id * @param stream_id id
*/ */
static bool stopRecord(type type, const string &vhost, const string &app, const string &stream_id); static bool stopRecord(type type, const string &vhost, const string &app, const string &stream_id);
/** /**
* 退 * 退
*/ */
static void stopAll(); static void stopAll();
/** /**
* *
* @param type hls还是MP4录制 * @param type hls还是MP4录制
* @param vhost * @param vhost
* @param app * @param app
* @param stream_id id * @param stream_id id
*/ */
static std::shared_ptr<MediaSinkInterface> getRecorder(type type, const string &vhost, const string &app, const string &stream_id); static std::shared_ptr<MediaSinkInterface> getRecorder(type type, const string &vhost, const string &app, const string &stream_id);
/** /**
* *
* @param type hls还是MP4录制 * @param type hls还是MP4录制
* @param vhost * @param vhost
* @param app * @param app
* @param stream_id id * @param stream_id id
* @param customized_path * @param customized_path
* @return nullptr * @return nullptr
*/ */
static std::shared_ptr<MediaSinkInterface> createRecorder(type type, const string &vhost, const string &app, const string &stream_id, const string &customized_path); static std::shared_ptr<MediaSinkInterface> createRecorder(type type, const string &vhost, const string &app, const string &stream_id, const string &customized_path);
private: private:
Recorder() = delete; Recorder() = delete;
~Recorder() = delete; ~Recorder() = delete;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -41,27 +41,27 @@ namespace mediakit {
class RtmpDemuxer : public Demuxer{ class RtmpDemuxer : public Demuxer{
public: public:
typedef std::shared_ptr<RtmpDemuxer> Ptr; typedef std::shared_ptr<RtmpDemuxer> Ptr;
RtmpDemuxer() = default; RtmpDemuxer() = default;
virtual ~RtmpDemuxer() = default; virtual ~RtmpDemuxer() = default;
void loadMetaData(const AMFValue &metadata); void loadMetaData(const AMFValue &metadata);
/** /**
* *
* @param pkt rtmp包 * @param pkt rtmp包
* @return true i帧 * @return true i帧
*/ */
bool inputRtmp(const RtmpPacket::Ptr &pkt); bool inputRtmp(const RtmpPacket::Ptr &pkt);
private: private:
void makeVideoTrack(const AMFValue &val); void makeVideoTrack(const AMFValue &val);
void makeAudioTrack(const AMFValue &val); void makeAudioTrack(const AMFValue &val);
private: private:
bool _tryedGetVideoTrack = false; bool _tryedGetVideoTrack = false;
bool _tryedGetAudioTrack = false; bool _tryedGetAudioTrack = false;
RtmpCodec::Ptr _audioRtmpDecoder; RtmpCodec::Ptr _audioRtmpDecoder;
RtmpCodec::Ptr _videoRtmpDecoder; RtmpCodec::Ptr _videoRtmpDecoder;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -58,163 +58,163 @@ namespace mediakit {
*/ */
class RtmpMediaSource : public MediaSource, public RingDelegate<RtmpPacket::Ptr> { class RtmpMediaSource : public MediaSource, public RingDelegate<RtmpPacket::Ptr> {
public: public:
typedef std::shared_ptr<RtmpMediaSource> Ptr; typedef std::shared_ptr<RtmpMediaSource> Ptr;
typedef RingBuffer<RtmpPacket::Ptr> RingType; typedef RingBuffer<RtmpPacket::Ptr> RingType;
/** /**
* *
* @param vhost * @param vhost
* @param app * @param app
* @param stream_id id * @param stream_id id
* @param ring_size 0 * @param ring_size 0
*/ */
RtmpMediaSource(const string &vhost, RtmpMediaSource(const string &vhost,
const string &app, const string &app,
const string &stream_id, const string &stream_id,
int ring_size = RTMP_GOP_SIZE) : int ring_size = RTMP_GOP_SIZE) :
MediaSource(RTMP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) { MediaSource(RTMP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {
} }
virtual ~RtmpMediaSource() {} virtual ~RtmpMediaSource() {}
/** /**
* *
*/ */
const RingType::Ptr &getRing() const { const RingType::Ptr &getRing() const {
return _ring; return _ring;
} }
/** /**
* *
* @return * @return
*/ */
int readerCount() override { int readerCount() override {
return _ring ? _ring->readerCount() : 0; return _ring ? _ring->readerCount() : 0;
} }
/** /**
* metadata * metadata
*/ */
const AMFValue &getMetaData() const { const AMFValue &getMetaData() const {
lock_guard<recursive_mutex> lock(_mtx); lock_guard<recursive_mutex> lock(_mtx);
return _metadata; return _metadata;
} }
/** /**
* config帧 * config帧
*/ */
template<typename FUNC> template<typename FUNC>
void getConfigFrame(const FUNC &f) { void getConfigFrame(const FUNC &f) {
lock_guard<recursive_mutex> lock(_mtx); lock_guard<recursive_mutex> lock(_mtx);
for (auto &pr : _config_frame_map) { for (auto &pr : _config_frame_map) {
f(pr.second); f(pr.second);
} }
} }
/** /**
* metadata * metadata
*/ */
virtual void setMetaData(const AMFValue &metadata) { virtual void setMetaData(const AMFValue &metadata) {
lock_guard<recursive_mutex> lock(_mtx); lock_guard<recursive_mutex> lock(_mtx);
_metadata = metadata; _metadata = metadata;
if(_ring){ if(_ring){
regist(); regist();
} }
} }
/** /**
* rtmp包 * rtmp包
* @param pkt rtmp包 * @param pkt rtmp包
* @param key * @param key
*/ */
void onWrite(const RtmpPacket::Ptr &pkt, bool key = true) override { void onWrite(const RtmpPacket::Ptr &pkt, bool key = true) override {
lock_guard<recursive_mutex> lock(_mtx); lock_guard<recursive_mutex> lock(_mtx);
if(pkt->typeId == MSG_VIDEO){ if(pkt->typeId == MSG_VIDEO){
//有视频那么启用GOP缓存 //有视频那么启用GOP缓存
_have_video = true; _have_video = true;
} }
if (pkt->isCfgFrame()) { if (pkt->isCfgFrame()) {
_config_frame_map[pkt->typeId] = pkt; _config_frame_map[pkt->typeId] = pkt;
return; return;
} }
if (!_ring) { if (!_ring) {
weak_ptr<RtmpMediaSource> weakSelf = dynamic_pointer_cast<RtmpMediaSource>(shared_from_this()); weak_ptr<RtmpMediaSource> weakSelf = dynamic_pointer_cast<RtmpMediaSource>(shared_from_this());
auto lam = [weakSelf](const EventPoller::Ptr &, int size, bool) { auto lam = [weakSelf](const EventPoller::Ptr &, int size, bool) {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if (!strongSelf) { if (!strongSelf) {
return; return;
} }
strongSelf->onReaderChanged(size); strongSelf->onReaderChanged(size);
}; };
//rtmp包缓存最大允许512个如果是纯视频(25fps)大概为20秒数据 //rtmp包缓存最大允许512个如果是纯视频(25fps)大概为20秒数据
//但是这个是GOP缓存的上限值真实的GOP缓存大小等于两个I帧之间的包数的两倍 //但是这个是GOP缓存的上限值真实的GOP缓存大小等于两个I帧之间的包数的两倍
//而且每次遇到I帧则会清空GOP缓存所以真实的GOP缓存远小于此值 //而且每次遇到I帧则会清空GOP缓存所以真实的GOP缓存远小于此值
_ring = std::make_shared<RingType>(_ring_size,std::move(lam)); _ring = std::make_shared<RingType>(_ring_size,std::move(lam));
onReaderChanged(0); onReaderChanged(0);
if(_metadata){ if(_metadata){
regist(); regist();
} }
} }
_track_stamps_map[pkt->typeId] = pkt->timeStamp; _track_stamps_map[pkt->typeId] = pkt->timeStamp;
//不存在视频为了减少缓存延时那么关闭GOP缓存 //不存在视频为了减少缓存延时那么关闭GOP缓存
_ring->write(pkt, _have_video ? pkt->isVideoKeyFrame() : true); _ring->write(pkt, _have_video ? pkt->isVideoKeyFrame() : true);
checkNoneReader(); checkNoneReader();
} }
/** /**
* *
*/ */
uint32_t getTimeStamp(TrackType trackType) override { uint32_t getTimeStamp(TrackType trackType) override {
lock_guard<recursive_mutex> lock(_mtx); lock_guard<recursive_mutex> lock(_mtx);
switch (trackType) { switch (trackType) {
case TrackVideo: case TrackVideo:
return _track_stamps_map[MSG_VIDEO]; return _track_stamps_map[MSG_VIDEO];
case TrackAudio: case TrackAudio:
return _track_stamps_map[MSG_AUDIO]; return _track_stamps_map[MSG_AUDIO];
default: default:
return MAX(_track_stamps_map[MSG_VIDEO], _track_stamps_map[MSG_AUDIO]); return MAX(_track_stamps_map[MSG_VIDEO], _track_stamps_map[MSG_AUDIO]);
} }
} }
private: private:
/** /**
* *
*/ */
void onReaderChanged(int size) { void onReaderChanged(int size) {
//我们记录最后一次活动时间 //我们记录最后一次活动时间
_reader_changed_ticker.resetTime(); _reader_changed_ticker.resetTime();
if (size != 0 || totalReaderCount() != 0) { if (size != 0 || totalReaderCount() != 0) {
//还有消费者正在观看该流 //还有消费者正在观看该流
_async_emit_none_reader = false; _async_emit_none_reader = false;
return; return;
} }
_async_emit_none_reader = true; _async_emit_none_reader = true;
} }
/** /**
* *
* onNoneReader事件 * onNoneReader事件
*/ */
void checkNoneReader() { void checkNoneReader() {
GET_CONFIG(int, stream_none_reader_delay, General::kStreamNoneReaderDelayMS); GET_CONFIG(int, stream_none_reader_delay, General::kStreamNoneReaderDelayMS);
if (_async_emit_none_reader && _reader_changed_ticker.elapsedTime() > stream_none_reader_delay) { if (_async_emit_none_reader && _reader_changed_ticker.elapsedTime() > stream_none_reader_delay) {
_async_emit_none_reader = false; _async_emit_none_reader = false;
onNoneReader(); onNoneReader();
} }
} }
protected: protected:
int _ring_size; int _ring_size;
bool _async_emit_none_reader = false; bool _async_emit_none_reader = false;
bool _have_video = false; bool _have_video = false;
mutable recursive_mutex _mtx; mutable recursive_mutex _mtx;
Ticker _reader_changed_ticker; Ticker _reader_changed_ticker;
AMFValue _metadata; AMFValue _metadata;
RingBuffer<RtmpPacket::Ptr>::Ptr _ring; RingBuffer<RtmpPacket::Ptr>::Ptr _ring;
unordered_map<int, uint32_t> _track_stamps_map; unordered_map<int, uint32_t> _track_stamps_map;
unordered_map<int, RtmpPacket::Ptr> _config_frame_map; unordered_map<int, RtmpPacket::Ptr> _config_frame_map;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -45,46 +45,46 @@ using namespace toolkit;
namespace mediakit { namespace mediakit {
class RtmpMediaSourceImp: public RtmpMediaSource, public Demuxer::Listener , public MultiMediaSourceMuxer::Listener { class RtmpMediaSourceImp: public RtmpMediaSource, public Demuxer::Listener , public MultiMediaSourceMuxer::Listener {
public: public:
typedef std::shared_ptr<RtmpMediaSourceImp> Ptr; typedef std::shared_ptr<RtmpMediaSourceImp> Ptr;
/** /**
* *
* @param vhost * @param vhost
* @param app * @param app
* @param id id * @param id id
* @param ringSize * @param ringSize
*/ */
RtmpMediaSourceImp(const string &vhost, const string &app, const string &id, int ringSize = RTMP_GOP_SIZE) : RtmpMediaSource(vhost, app, id, ringSize) { RtmpMediaSourceImp(const string &vhost, const string &app, const string &id, int ringSize = RTMP_GOP_SIZE) : RtmpMediaSource(vhost, app, id, ringSize) {
_demuxer = std::make_shared<RtmpDemuxer>(); _demuxer = std::make_shared<RtmpDemuxer>();
_demuxer->setTrackListener(this); _demuxer->setTrackListener(this);
} }
~RtmpMediaSourceImp() = default; ~RtmpMediaSourceImp() = default;
/** /**
* metadata * metadata
*/ */
void setMetaData(const AMFValue &metadata) override{ void setMetaData(const AMFValue &metadata) override{
_demuxer->loadMetaData(metadata); _demuxer->loadMetaData(metadata);
RtmpMediaSource::setMetaData(metadata); RtmpMediaSource::setMetaData(metadata);
} }
/** /**
* rtmp并解析 * rtmp并解析
*/ */
void onWrite(const RtmpPacket::Ptr &pkt,bool key_pos = true) override { void onWrite(const RtmpPacket::Ptr &pkt,bool key_pos = true) override {
key_pos = _demuxer->inputRtmp(pkt); key_pos = _demuxer->inputRtmp(pkt);
RtmpMediaSource::onWrite(pkt,key_pos); RtmpMediaSource::onWrite(pkt,key_pos);
} }
/** /**
* *
* @param listener * @param listener
*/ */
void setListener(const std::weak_ptr<MediaSourceEvent> &listener) override { void setListener(const std::weak_ptr<MediaSourceEvent> &listener) override {
RtmpMediaSource::setListener(listener); RtmpMediaSource::setListener(listener);
if(_muxer){ if(_muxer){
_muxer->setListener(listener); _muxer->setListener(listener);
} }
} }
@ -95,42 +95,42 @@ public:
return readerCount() + (_muxer ? _muxer->totalReaderCount() : 0); return readerCount() + (_muxer ? _muxer->totalReaderCount() : 0);
} }
/** /**
* *
* @param enableRtsp rtsp * @param enableRtsp rtsp
* @param enableHls hls * @param enableHls hls
* @param enableMP4 mp4录制 * @param enableMP4 mp4录制
*/ */
void setProtocolTranslation(bool enableRtsp, bool enableHls, bool enableMP4) { void setProtocolTranslation(bool enableRtsp, bool enableHls, bool enableMP4) {
//不重复生成rtmp //不重复生成rtmp
_muxer = std::make_shared<MultiMediaSourceMuxer>(getVhost(), getApp(), getId(), _demuxer->getDuration(), enableRtsp, false, enableHls, enableMP4); _muxer = std::make_shared<MultiMediaSourceMuxer>(getVhost(), getApp(), getId(), _demuxer->getDuration(), enableRtsp, false, enableHls, enableMP4);
_muxer->setListener(getListener()); _muxer->setListener(getListener());
_muxer->setTrackListener(this); _muxer->setTrackListener(this);
for(auto &track : _demuxer->getTracks(false)){ for(auto &track : _demuxer->getTracks(false)){
_muxer->addTrack(track); _muxer->addTrack(track);
track->addDelegate(_muxer); track->addDelegate(_muxer);
} }
} }
/** /**
* _demuxer触发的添加Track事件 * _demuxer触发的添加Track事件
*/ */
void onAddTrack(const Track::Ptr &track) override { void onAddTrack(const Track::Ptr &track) override {
if(_muxer){ if(_muxer){
_muxer->addTrack(track); _muxer->addTrack(track);
track->addDelegate(_muxer); track->addDelegate(_muxer);
} }
} }
/** /**
* _muxer触发的所有Track就绪的事件 * _muxer触发的所有Track就绪的事件
*/ */
void onAllTrackReady() override{ void onAllTrackReady() override{
setTrackSource(_muxer); setTrackSource(_muxer);
} }
private: private:
RtmpDemuxer::Ptr _demuxer; RtmpDemuxer::Ptr _demuxer;
MultiMediaSourceMuxer::Ptr _muxer; MultiMediaSourceMuxer::Ptr _muxer;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -38,35 +38,35 @@ RtmpPlayer::RtmpPlayer(const EventPoller::Ptr &poller) : TcpClient(poller) {
} }
RtmpPlayer::~RtmpPlayer() { RtmpPlayer::~RtmpPlayer() {
DebugL << endl; DebugL << endl;
} }
void RtmpPlayer::teardown() { void RtmpPlayer::teardown() {
if (alive()) { if (alive()) {
shutdown(SockException(Err_shutdown,"teardown")); shutdown(SockException(Err_shutdown,"teardown"));
} }
_strApp.clear(); _strApp.clear();
_strStream.clear(); _strStream.clear();
_strTcUrl.clear(); _strTcUrl.clear();
_pBeatTimer.reset(); _pBeatTimer.reset();
_pPlayTimer.reset(); _pPlayTimer.reset();
_pMediaTimer.reset(); _pMediaTimer.reset();
_iSeekTo = 0; _iSeekTo = 0;
RtmpProtocol::reset(); RtmpProtocol::reset();
CLEAR_ARR(_aiFistStamp); CLEAR_ARR(_aiFistStamp);
CLEAR_ARR(_aiNowStamp); CLEAR_ARR(_aiNowStamp);
lock_guard<recursive_mutex> lck(_mtxOnResultCB); lock_guard<recursive_mutex> lck(_mtxOnResultCB);
_mapOnResultCB.clear(); _mapOnResultCB.clear();
lock_guard<recursive_mutex> lck2(_mtxOnStatusCB); lock_guard<recursive_mutex> lck2(_mtxOnStatusCB);
_dqOnStatusCB.clear(); _dqOnStatusCB.clear();
} }
void RtmpPlayer::play(const string &strUrl) { void RtmpPlayer::play(const string &strUrl) {
teardown(); teardown();
string strHost = FindField(strUrl.data(), "://", "/"); string strHost = FindField(strUrl.data(), "://", "/");
_strApp = FindField(strUrl.data(), (strHost + "/").data(), "/"); _strApp = FindField(strUrl.data(), (strHost + "/").data(), "/");
_strStream = FindField(strUrl.data(), (strHost + "/" + _strApp + "/").data(), NULL); _strStream = FindField(strUrl.data(), (strHost + "/" + _strApp + "/").data(), NULL);
_strTcUrl = string("rtmp://") + strHost + "/" + _strApp; _strTcUrl = string("rtmp://") + strHost + "/" + _strApp;
@ -74,48 +74,48 @@ void RtmpPlayer::play(const string &strUrl) {
onPlayResult_l(SockException(Err_other,"rtmp url非法"),false); onPlayResult_l(SockException(Err_other,"rtmp url非法"),false);
return; return;
} }
DebugL << strHost << " " << _strApp << " " << _strStream; DebugL << strHost << " " << _strApp << " " << _strStream;
auto iPort = atoi(FindField(strHost.data(), ":", NULL).data()); auto iPort = atoi(FindField(strHost.data(), ":", NULL).data());
if (iPort <= 0) { if (iPort <= 0) {
//rtmp 默认端口1935 //rtmp 默认端口1935
iPort = 1935; iPort = 1935;
} else { } else {
//服务器域名 //服务器域名
strHost = FindField(strHost.data(), NULL, ":"); strHost = FindField(strHost.data(), NULL, ":");
} }
if(!(*this)[kNetAdapter].empty()){ if(!(*this)[kNetAdapter].empty()){
setNetAdapter((*this)[kNetAdapter]); setNetAdapter((*this)[kNetAdapter]);
} }
weak_ptr<RtmpPlayer> weakSelf= dynamic_pointer_cast<RtmpPlayer>(shared_from_this()); weak_ptr<RtmpPlayer> weakSelf= dynamic_pointer_cast<RtmpPlayer>(shared_from_this());
float playTimeOutSec = (*this)[kTimeoutMS].as<int>() / 1000.0; float playTimeOutSec = (*this)[kTimeoutMS].as<int>() / 1000.0;
_pPlayTimer.reset( new Timer(playTimeOutSec, [weakSelf]() { _pPlayTimer.reset( new Timer(playTimeOutSec, [weakSelf]() {
auto strongSelf=weakSelf.lock(); auto strongSelf=weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return false; return false;
} }
strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtmp timeout"),false); strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtmp timeout"),false);
return false; return false;
},getPoller())); },getPoller()));
_metadata_got = false; _metadata_got = false;
startConnect(strHost, iPort , playTimeOutSec); startConnect(strHost, iPort , playTimeOutSec);
} }
void RtmpPlayer::onErr(const SockException &ex){ void RtmpPlayer::onErr(const SockException &ex){
//定时器_pPlayTimer为空后表明握手结束了 //定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l(ex, !_pPlayTimer); onPlayResult_l(ex, !_pPlayTimer);
} }
void RtmpPlayer::onPlayResult_l(const SockException &ex , bool handshakeCompleted) { void RtmpPlayer::onPlayResult_l(const SockException &ex , bool handshakeCompleted) {
WarnL << ex.getErrCode() << " " << ex.what(); WarnL << ex.getErrCode() << " " << ex.what();
if(!ex){ if(!ex){
//播放成功恢复rtmp接收超时定时器 //播放成功恢复rtmp接收超时定时器
_mediaTicker.resetTime(); _mediaTicker.resetTime();
weak_ptr<RtmpPlayer> weakSelf = dynamic_pointer_cast<RtmpPlayer>(shared_from_this()); weak_ptr<RtmpPlayer> weakSelf = dynamic_pointer_cast<RtmpPlayer>(shared_from_this());
int timeoutMS = (*this)[kMediaTimeoutMS].as<int>(); int timeoutMS = (*this)[kMediaTimeoutMS].as<int>();
//创建rtmp数据接收超时检测定时器 //创建rtmp数据接收超时检测定时器
_pMediaTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() { _pMediaTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() {
auto strongSelf=weakSelf.lock(); auto strongSelf=weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
@ -130,110 +130,110 @@ void RtmpPlayer::onPlayResult_l(const SockException &ex , bool handshakeComplete
},getPoller())); },getPoller()));
} }
if (!handshakeCompleted) { if (!handshakeCompleted) {
//开始播放阶段 //开始播放阶段
_pPlayTimer.reset(); _pPlayTimer.reset();
onPlayResult(ex); onPlayResult(ex);
} else if (ex) { } else if (ex) {
//播放成功后异常断开回调 //播放成功后异常断开回调
onShutdown(ex); onShutdown(ex);
} else { } else {
//恢复播放 //恢复播放
onResume(); onResume();
} }
if(ex){ if(ex){
teardown(); teardown();
} }
} }
void RtmpPlayer::onConnect(const SockException &err){ void RtmpPlayer::onConnect(const SockException &err){
if(err.getErrCode() != Err_success) { if(err.getErrCode() != Err_success) {
onPlayResult_l(err, false); onPlayResult_l(err, false);
return; return;
} }
weak_ptr<RtmpPlayer> weakSelf= dynamic_pointer_cast<RtmpPlayer>(shared_from_this()); weak_ptr<RtmpPlayer> weakSelf= dynamic_pointer_cast<RtmpPlayer>(shared_from_this());
startClientSession([weakSelf](){ startClientSession([weakSelf](){
auto strongSelf=weakSelf.lock(); auto strongSelf=weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return; return;
} }
strongSelf->send_connect(); strongSelf->send_connect();
}); });
} }
void RtmpPlayer::onRecv(const Buffer::Ptr &pBuf){ void RtmpPlayer::onRecv(const Buffer::Ptr &pBuf){
try { try {
onParseRtmp(pBuf->data(), pBuf->size()); onParseRtmp(pBuf->data(), pBuf->size());
} catch (exception &e) { } catch (exception &e) {
SockException ex(Err_other, e.what()); SockException ex(Err_other, e.what());
//定时器_pPlayTimer为空后表明握手结束了 //定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l(ex, !_pPlayTimer); onPlayResult_l(ex, !_pPlayTimer);
} }
} }
void RtmpPlayer::pause(bool bPause) { void RtmpPlayer::pause(bool bPause) {
send_pause(bPause); send_pause(bPause);
} }
inline void RtmpPlayer::send_connect() { inline void RtmpPlayer::send_connect() {
AMFValue obj(AMF_OBJECT); AMFValue obj(AMF_OBJECT);
obj.set("app", _strApp); obj.set("app", _strApp);
obj.set("tcUrl", _strTcUrl); obj.set("tcUrl", _strTcUrl);
//未使用代理 //未使用代理
obj.set("fpad", false); obj.set("fpad", false);
//参考librtmp,什么作用? //参考librtmp,什么作用?
obj.set("capabilities", 15); obj.set("capabilities", 15);
//SUPPORT_VID_CLIENT_SEEK 支持seek //SUPPORT_VID_CLIENT_SEEK 支持seek
obj.set("videoFunction", 1); obj.set("videoFunction", 1);
//只支持aac //只支持aac
obj.set("audioCodecs", (double)(0x0400)); obj.set("audioCodecs", (double)(0x0400));
//只支持H264 //只支持H264
obj.set("videoCodecs", (double)(0x0080)); obj.set("videoCodecs", (double)(0x0080));
sendInvoke("connect", obj); sendInvoke("connect", obj);
addOnResultCB([this](AMFDecoder &dec){ addOnResultCB([this](AMFDecoder &dec){
//TraceL << "connect result"; //TraceL << "connect result";
dec.load<AMFValue>(); dec.load<AMFValue>();
auto val = dec.load<AMFValue>(); auto val = dec.load<AMFValue>();
auto level = val["level"].as_string(); auto level = val["level"].as_string();
auto code = val["code"].as_string(); auto code = val["code"].as_string();
if(level != "status"){ if(level != "status"){
throw std::runtime_error(StrPrinter <<"connect 失败:" << level << " " << code << endl); throw std::runtime_error(StrPrinter <<"connect 失败:" << level << " " << code << endl);
} }
send_createStream(); send_createStream();
}); });
} }
inline void RtmpPlayer::send_createStream() { inline void RtmpPlayer::send_createStream() {
AMFValue obj(AMF_NULL); AMFValue obj(AMF_NULL);
sendInvoke("createStream", obj); sendInvoke("createStream", obj);
addOnResultCB([this](AMFDecoder &dec){ addOnResultCB([this](AMFDecoder &dec){
//TraceL << "createStream result"; //TraceL << "createStream result";
dec.load<AMFValue>(); dec.load<AMFValue>();
_ui32StreamId = dec.load<int>(); _ui32StreamId = dec.load<int>();
send_play(); send_play();
}); });
} }
inline void RtmpPlayer::send_play() { inline void RtmpPlayer::send_play() {
AMFEncoder enc; AMFEncoder enc;
enc << "play" << ++_iReqID << nullptr << _strStream << (double)_ui32StreamId; enc << "play" << ++_iReqID << nullptr << _strStream << (double)_ui32StreamId;
sendRequest(MSG_CMD, enc.data()); sendRequest(MSG_CMD, enc.data());
auto fun = [this](AMFValue &val){ auto fun = [this](AMFValue &val){
//TraceL << "play onStatus"; //TraceL << "play onStatus";
auto level = val["level"].as_string(); auto level = val["level"].as_string();
auto code = val["code"].as_string(); auto code = val["code"].as_string();
if(level != "status"){ if(level != "status"){
throw std::runtime_error(StrPrinter <<"play 失败:" << level << " " << code << endl); throw std::runtime_error(StrPrinter <<"play 失败:" << level << " " << code << endl);
} }
}; };
addOnStatusCB(fun); addOnStatusCB(fun);
addOnStatusCB(fun); addOnStatusCB(fun);
} }
inline void RtmpPlayer::send_pause(bool bPause) { inline void RtmpPlayer::send_pause(bool bPause) {
AMFEncoder enc; AMFEncoder enc;
enc << "pause" << ++_iReqID << nullptr << bPause; enc << "pause" << ++_iReqID << nullptr << bPause;
sendRequest(MSG_CMD, enc.data()); sendRequest(MSG_CMD, enc.data());
auto fun = [this,bPause](AMFValue &val){ auto fun = [this,bPause](AMFValue &val){
//TraceL << "pause onStatus"; //TraceL << "pause onStatus";
auto level = val["level"].as_string(); auto level = val["level"].as_string();
auto code = val["code"].as_string(); auto code = val["code"].as_string();
@ -250,147 +250,147 @@ inline void RtmpPlayer::send_pause(bool bPause) {
_pMediaTimer.reset(); _pMediaTimer.reset();
} }
} }
}; };
addOnStatusCB(fun); addOnStatusCB(fun);
_pBeatTimer.reset(); _pBeatTimer.reset();
if(bPause){ if(bPause){
weak_ptr<RtmpPlayer> weakSelf = dynamic_pointer_cast<RtmpPlayer>(shared_from_this()); weak_ptr<RtmpPlayer> weakSelf = dynamic_pointer_cast<RtmpPlayer>(shared_from_this());
_pBeatTimer.reset(new Timer((*this)[kBeatIntervalMS].as<int>() / 1000.0,[weakSelf](){ _pBeatTimer.reset(new Timer((*this)[kBeatIntervalMS].as<int>() / 1000.0,[weakSelf](){
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if (!strongSelf){ if (!strongSelf){
return false; return false;
} }
uint32_t timeStamp = ::time(NULL); uint32_t timeStamp = ::time(NULL);
strongSelf->sendUserControl(CONTROL_PING_REQUEST, timeStamp); strongSelf->sendUserControl(CONTROL_PING_REQUEST, timeStamp);
return true; return true;
},getPoller())); },getPoller()));
} }
} }
void RtmpPlayer::onCmd_result(AMFDecoder &dec){ void RtmpPlayer::onCmd_result(AMFDecoder &dec){
auto iReqId = dec.load<int>(); auto iReqId = dec.load<int>();
lock_guard<recursive_mutex> lck(_mtxOnResultCB); lock_guard<recursive_mutex> lck(_mtxOnResultCB);
auto it = _mapOnResultCB.find(iReqId); auto it = _mapOnResultCB.find(iReqId);
if(it != _mapOnResultCB.end()){ if(it != _mapOnResultCB.end()){
it->second(dec); it->second(dec);
_mapOnResultCB.erase(it); _mapOnResultCB.erase(it);
}else{ }else{
WarnL << "unhandled _result"; WarnL << "unhandled _result";
} }
} }
void RtmpPlayer::onCmd_onStatus(AMFDecoder &dec) { void RtmpPlayer::onCmd_onStatus(AMFDecoder &dec) {
AMFValue val; AMFValue val;
while(true){ while(true){
val = dec.load<AMFValue>(); val = dec.load<AMFValue>();
if(val.type() == AMF_OBJECT){ if(val.type() == AMF_OBJECT){
break; break;
} }
} }
if(val.type() != AMF_OBJECT){ if(val.type() != AMF_OBJECT){
throw std::runtime_error("onStatus:the result object was not found"); throw std::runtime_error("onStatus:the result object was not found");
} }
lock_guard<recursive_mutex> lck(_mtxOnStatusCB); lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
if(_dqOnStatusCB.size()){ if(_dqOnStatusCB.size()){
_dqOnStatusCB.front()(val); _dqOnStatusCB.front()(val);
_dqOnStatusCB.pop_front(); _dqOnStatusCB.pop_front();
}else{ }else{
auto level = val["level"]; auto level = val["level"];
auto code = val["code"].as_string(); auto code = val["code"].as_string();
if(level.type() == AMF_STRING){ if(level.type() == AMF_STRING){
if(level.as_string() != "status"){ if(level.as_string() != "status"){
throw std::runtime_error(StrPrinter <<"onStatus 失败:" << level.as_string() << " " << code << endl); throw std::runtime_error(StrPrinter <<"onStatus 失败:" << level.as_string() << " " << code << endl);
} }
} }
//WarnL << "unhandled onStatus:" << code; //WarnL << "unhandled onStatus:" << code;
} }
} }
void RtmpPlayer::onCmd_onMetaData(AMFDecoder &dec) { void RtmpPlayer::onCmd_onMetaData(AMFDecoder &dec) {
//TraceL; //TraceL;
auto val = dec.load<AMFValue>(); auto val = dec.load<AMFValue>();
if(!onCheckMeta(val)){ if(!onCheckMeta(val)){
throw std::runtime_error("onCheckMeta failed"); throw std::runtime_error("onCheckMeta failed");
} }
_metadata_got = true; _metadata_got = true;
} }
void RtmpPlayer::onStreamDry(uint32_t ui32StreamId) { void RtmpPlayer::onStreamDry(uint32_t ui32StreamId) {
//TraceL << ui32StreamId; //TraceL << ui32StreamId;
onPlayResult_l(SockException(Err_other,"rtmp stream dry"), true); onPlayResult_l(SockException(Err_other,"rtmp stream dry"), true);
} }
void RtmpPlayer::onMediaData_l(const RtmpPacket::Ptr &packet) { void RtmpPlayer::onMediaData_l(const RtmpPacket::Ptr &packet) {
_mediaTicker.resetTime(); _mediaTicker.resetTime();
if(!_pPlayTimer){ if(!_pPlayTimer){
//已经触发了onPlayResult事件直接触发onMediaData事件 //已经触发了onPlayResult事件直接触发onMediaData事件
onMediaData(packet); onMediaData(packet);
return; return;
} }
if(packet->isCfgFrame()){ if(packet->isCfgFrame()){
//输入配置帧以便初始化完成各个track //输入配置帧以便初始化完成各个track
onMediaData(packet); onMediaData(packet);
}else{ }else{
//先触发onPlayResult事件这个时候解码器才能初始化完毕 //先触发onPlayResult事件这个时候解码器才能初始化完毕
onPlayResult_l(SockException(Err_success,"play rtmp success"), false); onPlayResult_l(SockException(Err_success,"play rtmp success"), false);
//触发onPlayResult事件后再把帧数据输入到解码器 //触发onPlayResult事件后再把帧数据输入到解码器
onMediaData(packet); onMediaData(packet);
} }
} }
void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) { void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) {
typedef void (RtmpPlayer::*rtmp_func_ptr)(AMFDecoder &dec); typedef void (RtmpPlayer::*rtmp_func_ptr)(AMFDecoder &dec);
static unordered_map<string, rtmp_func_ptr> s_func_map; static unordered_map<string, rtmp_func_ptr> s_func_map;
static onceToken token([]() { static onceToken token([]() {
s_func_map.emplace("_error",&RtmpPlayer::onCmd_result); s_func_map.emplace("_error",&RtmpPlayer::onCmd_result);
s_func_map.emplace("_result",&RtmpPlayer::onCmd_result); s_func_map.emplace("_result",&RtmpPlayer::onCmd_result);
s_func_map.emplace("onStatus",&RtmpPlayer::onCmd_onStatus); s_func_map.emplace("onStatus",&RtmpPlayer::onCmd_onStatus);
s_func_map.emplace("onMetaData",&RtmpPlayer::onCmd_onMetaData); s_func_map.emplace("onMetaData",&RtmpPlayer::onCmd_onMetaData);
}, []() {}); }, []() {});
switch (chunkData.typeId) { switch (chunkData.typeId) {
case MSG_CMD: case MSG_CMD:
case MSG_CMD3: case MSG_CMD3:
case MSG_DATA: case MSG_DATA:
case MSG_DATA3: { case MSG_DATA3: {
AMFDecoder dec(chunkData.strBuf, 0); AMFDecoder dec(chunkData.strBuf, 0);
std::string type = dec.load<std::string>(); std::string type = dec.load<std::string>();
auto it = s_func_map.find(type); auto it = s_func_map.find(type);
if(it != s_func_map.end()){ if(it != s_func_map.end()){
auto fun = it->second; auto fun = it->second;
(this->*fun)(dec); (this->*fun)(dec);
}else{ }else{
WarnL << "can not support cmd:" << type; WarnL << "can not support cmd:" << type;
} }
} }
break; break;
case MSG_AUDIO: case MSG_AUDIO:
case MSG_VIDEO: { case MSG_VIDEO: {
auto idx = chunkData.typeId%2; auto idx = chunkData.typeId%2;
if (_aNowStampTicker[idx].elapsedTime() > 500) { if (_aNowStampTicker[idx].elapsedTime() > 500) {
//计算播放进度时间轴用 //计算播放进度时间轴用
_aiNowStamp[idx] = chunkData.timeStamp; _aiNowStamp[idx] = chunkData.timeStamp;
} }
if(!_metadata_got){ if(!_metadata_got){
if(!onCheckMeta(TitleMeta().getMetadata())){ if(!onCheckMeta(TitleMeta().getMetadata())){
throw std::runtime_error("onCheckMeta failed"); throw std::runtime_error("onCheckMeta failed");
} }
_metadata_got = true; _metadata_got = true;
} }
onMediaData_l(std::make_shared<RtmpPacket>(std::move(chunkData))); onMediaData_l(std::make_shared<RtmpPacket>(std::move(chunkData)));
} }
break; break;
default: default:
//WarnL << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size()); //WarnL << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size());
break; break;
} }
} }
uint32_t RtmpPlayer::getProgressMilliSecond() const{ uint32_t RtmpPlayer::getProgressMilliSecond() const{
uint32_t iTime[2] = {0,0}; uint32_t iTime[2] = {0,0};
for(auto i = 0 ;i < 2 ;i++){ for(auto i = 0 ;i < 2 ;i++){
iTime[i] = _aiNowStamp[i] - _aiFistStamp[i]; iTime[i] = _aiNowStamp[i] - _aiFistStamp[i];
} }
@ -407,7 +407,7 @@ void RtmpPlayer::seekToMilliSecond(uint32_t seekMS){
//TraceL << "seek result"; //TraceL << "seek result";
_aNowStampTicker[0].resetTime(); _aNowStampTicker[0].resetTime();
_aNowStampTicker[1].resetTime(); _aNowStampTicker[1].resetTime();
int iTimeInc = seekMS - getProgressMilliSecond(); int iTimeInc = seekMS - getProgressMilliSecond();
for(auto i = 0 ;i < 2 ;i++){ for(auto i = 0 ;i < 2 ;i++){
_aiFistStamp[i] = _aiNowStamp[i] + iTimeInc; _aiFistStamp[i] = _aiNowStamp[i] + iTimeInc;
_aiNowStamp[i] = _aiFistStamp[i]; _aiNowStamp[i] = _aiFistStamp[i];

View File

@ -47,77 +47,77 @@ namespace mediakit {
//实现了rtmp播放器协议部分的功能及数据接收功能 //实现了rtmp播放器协议部分的功能及数据接收功能
class RtmpPlayer:public PlayerBase, public TcpClient, public RtmpProtocol{ class RtmpPlayer:public PlayerBase, public TcpClient, public RtmpProtocol{
public: public:
typedef std::shared_ptr<RtmpPlayer> Ptr; typedef std::shared_ptr<RtmpPlayer> Ptr;
RtmpPlayer(const EventPoller::Ptr &poller); RtmpPlayer(const EventPoller::Ptr &poller);
virtual ~RtmpPlayer(); virtual ~RtmpPlayer();
void play(const string &strUrl) override; void play(const string &strUrl) override;
void pause(bool bPause) override; void pause(bool bPause) override;
void teardown() override; void teardown() override;
protected: protected:
virtual bool onCheckMeta(const AMFValue &val) =0; virtual bool onCheckMeta(const AMFValue &val) =0;
virtual void onMediaData(const RtmpPacket::Ptr &chunkData) =0; virtual void onMediaData(const RtmpPacket::Ptr &chunkData) =0;
uint32_t getProgressMilliSecond() const; uint32_t getProgressMilliSecond() const;
void seekToMilliSecond(uint32_t ms); void seekToMilliSecond(uint32_t ms);
protected: protected:
void onMediaData_l(const RtmpPacket::Ptr &chunkData); void onMediaData_l(const RtmpPacket::Ptr &chunkData);
//在获取config帧后才触发onPlayResult_l(而不是收到play命令回复)所以此时所有track都初始化完毕了 //在获取config帧后才触发onPlayResult_l(而不是收到play命令回复)所以此时所有track都初始化完毕了
void onPlayResult_l(const SockException &ex, bool handshakeCompleted); void onPlayResult_l(const SockException &ex, bool handshakeCompleted);
//form Tcpclient //form Tcpclient
void onRecv(const Buffer::Ptr &pBuf) override; void onRecv(const Buffer::Ptr &pBuf) override;
void onConnect(const SockException &err) override; void onConnect(const SockException &err) override;
void onErr(const SockException &ex) override; void onErr(const SockException &ex) override;
//from RtmpProtocol //from RtmpProtocol
void onRtmpChunk(RtmpPacket &chunkData) override; void onRtmpChunk(RtmpPacket &chunkData) override;
void onStreamDry(uint32_t ui32StreamId) override; void onStreamDry(uint32_t ui32StreamId) override;
void onSendRawData(const Buffer::Ptr &buffer) override{ void onSendRawData(const Buffer::Ptr &buffer) override{
send(buffer); send(buffer);
} }
template<typename FUN> template<typename FUN>
inline void addOnResultCB(const FUN &fun) { inline void addOnResultCB(const FUN &fun) {
lock_guard<recursive_mutex> lck(_mtxOnResultCB); lock_guard<recursive_mutex> lck(_mtxOnResultCB);
_mapOnResultCB.emplace(_iReqID, fun); _mapOnResultCB.emplace(_iReqID, fun);
} }
template<typename FUN> template<typename FUN>
inline void addOnStatusCB(const FUN &fun) { inline void addOnStatusCB(const FUN &fun) {
lock_guard<recursive_mutex> lck(_mtxOnStatusCB); lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
_dqOnStatusCB.emplace_back(fun); _dqOnStatusCB.emplace_back(fun);
} }
void onCmd_result(AMFDecoder &dec); void onCmd_result(AMFDecoder &dec);
void onCmd_onStatus(AMFDecoder &dec); void onCmd_onStatus(AMFDecoder &dec);
void onCmd_onMetaData(AMFDecoder &dec); void onCmd_onMetaData(AMFDecoder &dec);
inline void send_connect(); inline void send_connect();
inline void send_createStream(); inline void send_createStream();
inline void send_play(); inline void send_play();
inline void send_pause(bool bPause); inline void send_pause(bool bPause);
private: private:
string _strApp; string _strApp;
string _strStream; string _strStream;
string _strTcUrl; string _strTcUrl;
bool _bPaused = false; bool _bPaused = false;
unordered_map<int, function<void(AMFDecoder &dec)> > _mapOnResultCB; unordered_map<int, function<void(AMFDecoder &dec)> > _mapOnResultCB;
recursive_mutex _mtxOnResultCB; recursive_mutex _mtxOnResultCB;
deque<function<void(AMFValue &dec)> > _dqOnStatusCB; deque<function<void(AMFValue &dec)> > _dqOnStatusCB;
recursive_mutex _mtxOnStatusCB; recursive_mutex _mtxOnStatusCB;
//超时功能实现 //超时功能实现
Ticker _mediaTicker; Ticker _mediaTicker;
std::shared_ptr<Timer> _pMediaTimer; std::shared_ptr<Timer> _pMediaTimer;
std::shared_ptr<Timer> _pPlayTimer; std::shared_ptr<Timer> _pPlayTimer;
//心跳定时器 //心跳定时器
std::shared_ptr<Timer> _pBeatTimer; std::shared_ptr<Timer> _pBeatTimer;
//播放进度控制 //播放进度控制
uint32_t _iSeekTo = 0; uint32_t _iSeekTo = 0;
uint32_t _aiFistStamp[2] = { 0, 0 }; uint32_t _aiFistStamp[2] = { 0, 0 };
uint32_t _aiNowStamp[2] = { 0, 0 }; uint32_t _aiNowStamp[2] = { 0, 0 };
Ticker _aNowStampTicker[2]; Ticker _aNowStampTicker[2];
bool _metadata_got = false; bool _metadata_got = false;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -73,7 +73,7 @@ private:
return true; return true;
} }
void onMediaData(const RtmpPacket::Ptr &chunkData) override { void onMediaData(const RtmpPacket::Ptr &chunkData) override {
if(_pRtmpMediaSrc){ if(_pRtmpMediaSrc){
if(!_set_meta_data && !chunkData->isCfgFrame()){ if(!_set_meta_data && !chunkData->isCfgFrame()){
_set_meta_data = true; _set_meta_data = true;
_pRtmpMediaSrc->setMetaData(TitleMeta().getMetadata()); _pRtmpMediaSrc->setMetaData(TitleMeta().getMetadata());
@ -81,7 +81,7 @@ private:
_pRtmpMediaSrc->onWrite(chunkData); _pRtmpMediaSrc->onWrite(chunkData);
} }
if(!_delegate){ if(!_delegate){
//这个流没有metadata //这个流没有metadata
_delegate.reset(new RtmpDemuxer()); _delegate.reset(new RtmpDemuxer());
} }
_delegate->inputRtmp(chunkData); _delegate->inputRtmp(chunkData);

File diff suppressed because it is too large Load Diff

View File

@ -45,77 +45,77 @@ namespace mediakit {
class RtmpProtocol { class RtmpProtocol {
public: public:
RtmpProtocol(); RtmpProtocol();
virtual ~RtmpProtocol(); virtual ~RtmpProtocol();
//作为客户端发送c0c1等待s0s1s2并且回调 //作为客户端发送c0c1等待s0s1s2并且回调
void startClientSession(const function<void()> &cb); void startClientSession(const function<void()> &cb);
void onParseRtmp(const char *pcRawData,int iSize); void onParseRtmp(const char *pcRawData,int iSize);
void reset(); void reset();
protected: protected:
virtual void onSendRawData(const Buffer::Ptr &buffer) = 0; virtual void onSendRawData(const Buffer::Ptr &buffer) = 0;
virtual void onRtmpChunk(RtmpPacket &chunkData) = 0; virtual void onRtmpChunk(RtmpPacket &chunkData) = 0;
virtual void onStreamBegin(uint32_t ui32StreamId){ virtual void onStreamBegin(uint32_t ui32StreamId){
_ui32StreamId = ui32StreamId; _ui32StreamId = ui32StreamId;
} }
virtual void onStreamEof(uint32_t ui32StreamId){}; virtual void onStreamEof(uint32_t ui32StreamId){};
virtual void onStreamDry(uint32_t ui32StreamId){}; virtual void onStreamDry(uint32_t ui32StreamId){};
protected: protected:
void sendAcknowledgement(uint32_t ui32Size); void sendAcknowledgement(uint32_t ui32Size);
void sendAcknowledgementSize(uint32_t ui32Size); void sendAcknowledgementSize(uint32_t ui32Size);
void sendPeerBandwidth(uint32_t ui32Size); void sendPeerBandwidth(uint32_t ui32Size);
void sendChunkSize(uint32_t ui32Size); void sendChunkSize(uint32_t ui32Size);
void sendPingRequest(uint32_t ui32TimeStamp = ::time(NULL)); void sendPingRequest(uint32_t ui32TimeStamp = ::time(NULL));
void sendPingResponse(uint32_t ui32TimeStamp = ::time(NULL)); void sendPingResponse(uint32_t ui32TimeStamp = ::time(NULL));
void sendSetBufferLength(uint32_t ui32StreamId, uint32_t ui32Length); void sendSetBufferLength(uint32_t ui32StreamId, uint32_t ui32Length);
void sendUserControl(uint16_t ui16EventType, uint32_t ui32EventData); void sendUserControl(uint16_t ui16EventType, uint32_t ui32EventData);
void sendUserControl(uint16_t ui16EventType, const string &strEventData); void sendUserControl(uint16_t ui16EventType, const string &strEventData);
void sendInvoke(const string &strCmd, const AMFValue &val); void sendInvoke(const string &strCmd, const AMFValue &val);
void sendRequest(int iCmd, const string &str); void sendRequest(int iCmd, const string &str);
void sendResponse(int iType, const string &str); void sendResponse(int iType, const string &str);
void sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, const std::string &strBuf, uint32_t ui32TimeStamp, int iChunkID); void sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, const std::string &strBuf, uint32_t ui32TimeStamp, int iChunkID);
void sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, const Buffer::Ptr &buffer, uint32_t ui32TimeStamp, int iChunkID); void sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, const Buffer::Ptr &buffer, uint32_t ui32TimeStamp, int iChunkID);
protected: protected:
int _iReqID = 0; int _iReqID = 0;
uint32_t _ui32StreamId = STREAM_CONTROL; uint32_t _ui32StreamId = STREAM_CONTROL;
int _iNowStreamID = 0; int _iNowStreamID = 0;
int _iNowChunkID = 0; int _iNowChunkID = 0;
bool _bDataStarted = false; bool _bDataStarted = false;
inline BufferRaw::Ptr obtainBuffer(); inline BufferRaw::Ptr obtainBuffer();
inline BufferRaw::Ptr obtainBuffer(const void *data, int len); inline BufferRaw::Ptr obtainBuffer(const void *data, int len);
//ResourcePool<BufferRaw,MAX_SEND_PKT> _bufferPool; //ResourcePool<BufferRaw,MAX_SEND_PKT> _bufferPool;
private: private:
void handle_S0S1S2(const function<void()> &cb); void handle_S0S1S2(const function<void()> &cb);
void handle_C0C1(); void handle_C0C1();
void handle_C1_simple(); void handle_C1_simple();
#ifdef ENABLE_OPENSSL #ifdef ENABLE_OPENSSL
void handle_C1_complex(); void handle_C1_complex();
string get_C1_digest(const uint8_t *ptr,char **digestPos); string get_C1_digest(const uint8_t *ptr,char **digestPos);
string get_C1_key(const uint8_t *ptr); string get_C1_key(const uint8_t *ptr);
void check_C1_Digest(const string &digest,const string &data); void check_C1_Digest(const string &digest,const string &data);
void send_complex_S0S1S2(int schemeType,const string &digest); void send_complex_S0S1S2(int schemeType,const string &digest);
#endif //ENABLE_OPENSSL #endif //ENABLE_OPENSSL
void handle_C2(); void handle_C2();
void handle_rtmp(); void handle_rtmp();
void handle_rtmpChunk(RtmpPacket &chunkData); void handle_rtmpChunk(RtmpPacket &chunkData);
private: private:
////////////ChunkSize//////////// ////////////ChunkSize////////////
size_t _iChunkLenIn = DEFAULT_CHUNK_LEN; size_t _iChunkLenIn = DEFAULT_CHUNK_LEN;
size_t _iChunkLenOut = DEFAULT_CHUNK_LEN; size_t _iChunkLenOut = DEFAULT_CHUNK_LEN;
////////////Acknowledgement//////////// ////////////Acknowledgement////////////
uint32_t _ui32ByteSent = 0; uint32_t _ui32ByteSent = 0;
uint32_t _ui32LastSent = 0; uint32_t _ui32LastSent = 0;
uint32_t _ui32WinSize = 0; uint32_t _ui32WinSize = 0;
///////////PeerBandwidth/////////// ///////////PeerBandwidth///////////
uint32_t _ui32Bandwidth = 2500000; uint32_t _ui32Bandwidth = 2500000;
uint8_t _ui8LimitType = 2; uint8_t _ui8LimitType = 2;
////////////Chunk//////////// ////////////Chunk////////////
unordered_map<int, RtmpPacket> _mapChunkData; unordered_map<int, RtmpPacket> _mapChunkData;
//////////Rtmp parser////////// //////////Rtmp parser//////////
string _strRcvBuf; string _strRcvBuf;
function<void()> _nextHandle; function<void()> _nextHandle;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -34,55 +34,55 @@ using namespace mediakit::Client;
namespace mediakit { namespace mediakit {
RtmpPusher::RtmpPusher(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &src) : TcpClient(poller){ RtmpPusher::RtmpPusher(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &src) : TcpClient(poller){
_pMediaSrc=src; _pMediaSrc=src;
} }
RtmpPusher::~RtmpPusher() { RtmpPusher::~RtmpPusher() {
teardown(); teardown();
DebugL << endl; DebugL << endl;
} }
void RtmpPusher::teardown() { void RtmpPusher::teardown() {
if (alive()) { if (alive()) {
_strApp.clear(); _strApp.clear();
_strStream.clear(); _strStream.clear();
_strTcUrl.clear(); _strTcUrl.clear();
{ {
lock_guard<recursive_mutex> lck(_mtxOnResultCB); lock_guard<recursive_mutex> lck(_mtxOnResultCB);
_mapOnResultCB.clear(); _mapOnResultCB.clear();
} }
{ {
lock_guard<recursive_mutex> lck(_mtxOnStatusCB); lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
_dqOnStatusCB.clear(); _dqOnStatusCB.clear();
} }
_pPublishTimer.reset(); _pPublishTimer.reset();
reset(); reset();
shutdown(SockException(Err_shutdown,"teardown")); shutdown(SockException(Err_shutdown,"teardown"));
} }
} }
void RtmpPusher::onPublishResult(const SockException &ex,bool handshakeCompleted) { void RtmpPusher::onPublishResult(const SockException &ex,bool handshakeCompleted) {
if(!handshakeCompleted){ if(!handshakeCompleted){
//播放结果回调 //播放结果回调
_pPublishTimer.reset(); _pPublishTimer.reset();
if(_onPublished){ if(_onPublished){
_onPublished(ex); _onPublished(ex);
} }
} else { } else {
//播放成功后异常断开回调 //播放成功后异常断开回调
if(_onShutdown){ if(_onShutdown){
_onShutdown(ex); _onShutdown(ex);
} }
} }
if(ex){ if(ex){
teardown(); teardown();
} }
} }
void RtmpPusher::publish(const string &strUrl) { void RtmpPusher::publish(const string &strUrl) {
teardown(); teardown();
string strHost = FindField(strUrl.data(), "://", "/"); string strHost = FindField(strUrl.data(), "://", "/");
_strApp = FindField(strUrl.data(), (strHost + "/").data(), "/"); _strApp = FindField(strUrl.data(), (strHost + "/").data(), "/");
_strStream = FindField(strUrl.data(), (strHost + "/" + _strApp + "/").data(), NULL); _strStream = FindField(strUrl.data(), (strHost + "/" + _strApp + "/").data(), NULL);
_strTcUrl = string("rtmp://") + strHost + "/" + _strApp; _strTcUrl = string("rtmp://") + strHost + "/" + _strApp;
@ -90,16 +90,16 @@ void RtmpPusher::publish(const string &strUrl) {
onPublishResult(SockException(Err_other,"rtmp url非法"),false); onPublishResult(SockException(Err_other,"rtmp url非法"),false);
return; return;
} }
DebugL << strHost << " " << _strApp << " " << _strStream; DebugL << strHost << " " << _strApp << " " << _strStream;
auto iPort = atoi(FindField(strHost.data(), ":", NULL).data()); auto iPort = atoi(FindField(strHost.data(), ":", NULL).data());
if (iPort <= 0) { if (iPort <= 0) {
//rtmp 默认端口1935 //rtmp 默认端口1935
iPort = 1935; iPort = 1935;
} else { } else {
//服务器域名 //服务器域名
strHost = FindField(strHost.data(), NULL, ":"); strHost = FindField(strHost.data(), NULL, ":");
} }
weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this()); weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this());
float publishTimeOutSec = (*this)[kTimeoutMS].as<int>() / 1000.0; float publishTimeOutSec = (*this)[kTimeoutMS].as<int>() / 1000.0;
@ -116,23 +116,23 @@ void RtmpPusher::publish(const string &strUrl) {
setNetAdapter((*this)[kNetAdapter]); setNetAdapter((*this)[kNetAdapter]);
} }
startConnect(strHost, iPort); startConnect(strHost, iPort);
} }
void RtmpPusher::onErr(const SockException &ex){ void RtmpPusher::onErr(const SockException &ex){
//定时器_pPublishTimer为空后表明握手结束了 //定时器_pPublishTimer为空后表明握手结束了
onPublishResult(ex,!_pPublishTimer); onPublishResult(ex,!_pPublishTimer);
} }
void RtmpPusher::onConnect(const SockException &err){ void RtmpPusher::onConnect(const SockException &err){
if(err) { if(err) {
onPublishResult(err,false); onPublishResult(err,false);
return; return;
} }
//推流器不需要多大的接收缓存,节省内存占用 //推流器不需要多大的接收缓存,节省内存占用
_sock->setReadBuffer(std::make_shared<BufferRaw>(1 * 1024)); _sock->setReadBuffer(std::make_shared<BufferRaw>(1 * 1024));
weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this()); weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this());
startClientSession([weakSelf](){ startClientSession([weakSelf](){
auto strongSelf=weakSelf.lock(); auto strongSelf=weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return; return;
@ -140,63 +140,63 @@ void RtmpPusher::onConnect(const SockException &err){
strongSelf->sendChunkSize(60000); strongSelf->sendChunkSize(60000);
strongSelf->send_connect(); strongSelf->send_connect();
}); });
} }
void RtmpPusher::onRecv(const Buffer::Ptr &pBuf){ void RtmpPusher::onRecv(const Buffer::Ptr &pBuf){
try { try {
onParseRtmp(pBuf->data(), pBuf->size()); onParseRtmp(pBuf->data(), pBuf->size());
} catch (exception &e) { } catch (exception &e) {
SockException ex(Err_other, e.what()); SockException ex(Err_other, e.what());
//定时器_pPublishTimer为空后表明握手结束了 //定时器_pPublishTimer为空后表明握手结束了
onPublishResult(ex,!_pPublishTimer); onPublishResult(ex,!_pPublishTimer);
} }
} }
inline void RtmpPusher::send_connect() { inline void RtmpPusher::send_connect() {
AMFValue obj(AMF_OBJECT); AMFValue obj(AMF_OBJECT);
obj.set("app", _strApp); obj.set("app", _strApp);
obj.set("type", "nonprivate"); obj.set("type", "nonprivate");
obj.set("tcUrl", _strTcUrl); obj.set("tcUrl", _strTcUrl);
obj.set("swfUrl", _strTcUrl); obj.set("swfUrl", _strTcUrl);
sendInvoke("connect", obj); sendInvoke("connect", obj);
addOnResultCB([this](AMFDecoder &dec){ addOnResultCB([this](AMFDecoder &dec){
//TraceL << "connect result"; //TraceL << "connect result";
dec.load<AMFValue>(); dec.load<AMFValue>();
auto val = dec.load<AMFValue>(); auto val = dec.load<AMFValue>();
auto level = val["level"].as_string(); auto level = val["level"].as_string();
auto code = val["code"].as_string(); auto code = val["code"].as_string();
if(level != "status"){ if(level != "status"){
throw std::runtime_error(StrPrinter <<"connect 失败:" << level << " " << code << endl); throw std::runtime_error(StrPrinter <<"connect 失败:" << level << " " << code << endl);
} }
send_createStream(); send_createStream();
}); });
} }
inline void RtmpPusher::send_createStream() { inline void RtmpPusher::send_createStream() {
AMFValue obj(AMF_NULL); AMFValue obj(AMF_NULL);
sendInvoke("createStream", obj); sendInvoke("createStream", obj);
addOnResultCB([this](AMFDecoder &dec){ addOnResultCB([this](AMFDecoder &dec){
//TraceL << "createStream result"; //TraceL << "createStream result";
dec.load<AMFValue>(); dec.load<AMFValue>();
_ui32StreamId = dec.load<int>(); _ui32StreamId = dec.load<int>();
send_publish(); send_publish();
}); });
} }
inline void RtmpPusher::send_publish() { inline void RtmpPusher::send_publish() {
AMFEncoder enc; AMFEncoder enc;
enc << "publish" << ++_iReqID << nullptr << _strStream << _strApp ; enc << "publish" << ++_iReqID << nullptr << _strStream << _strApp ;
sendRequest(MSG_CMD, enc.data()); sendRequest(MSG_CMD, enc.data());
addOnStatusCB([this](AMFValue &val) { addOnStatusCB([this](AMFValue &val) {
auto level = val["level"].as_string(); auto level = val["level"].as_string();
auto code = val["code"].as_string(); auto code = val["code"].as_string();
if(level != "status") { if(level != "status") {
throw std::runtime_error(StrPrinter <<"publish 失败:" << level << " " << code << endl); throw std::runtime_error(StrPrinter <<"publish 失败:" << level << " " << code << endl);
} }
//start send media //start send media
send_metaData(); send_metaData();
}); });
} }
inline void RtmpPusher::send_metaData(){ inline void RtmpPusher::send_metaData(){
@ -216,11 +216,11 @@ inline void RtmpPusher::send_metaData(){
_pRtmpReader = src->getRing()->attach(getPoller()); _pRtmpReader = src->getRing()->attach(getPoller());
weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this()); weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this());
_pRtmpReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt){ _pRtmpReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt){
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return; return;
} }
strongSelf->sendRtmp(pkt->typeId, strongSelf->_ui32StreamId, pkt, pkt->timeStamp, pkt->chunkId); strongSelf->sendRtmp(pkt->typeId, strongSelf->_ui32StreamId, pkt, pkt->timeStamp, pkt->chunkId);
}); });
_pRtmpReader->setDetachCB([weakSelf](){ _pRtmpReader->setDetachCB([weakSelf](){
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
@ -229,84 +229,84 @@ inline void RtmpPusher::send_metaData(){
} }
}); });
onPublishResult(SockException(Err_success,"success"), false); onPublishResult(SockException(Err_success,"success"), false);
//提升发送性能 //提升发送性能
setSocketFlags(); setSocketFlags();
} }
void RtmpPusher::setSocketFlags(){ void RtmpPusher::setSocketFlags(){
GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay); GET_CONFIG(bool,ultraLowDelay,General::kUltraLowDelay);
if(!ultraLowDelay) { if(!ultraLowDelay) {
//提高发送性能 //提高发送性能
(*this) << SocketFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE); (*this) << SocketFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE);
SockUtil::setNoDelay(_sock->rawFD(), false); SockUtil::setNoDelay(_sock->rawFD(), false);
} }
} }
void RtmpPusher::onCmd_result(AMFDecoder &dec){ void RtmpPusher::onCmd_result(AMFDecoder &dec){
auto iReqId = dec.load<int>(); auto iReqId = dec.load<int>();
lock_guard<recursive_mutex> lck(_mtxOnResultCB); lock_guard<recursive_mutex> lck(_mtxOnResultCB);
auto it = _mapOnResultCB.find(iReqId); auto it = _mapOnResultCB.find(iReqId);
if(it != _mapOnResultCB.end()){ if(it != _mapOnResultCB.end()){
it->second(dec); it->second(dec);
_mapOnResultCB.erase(it); _mapOnResultCB.erase(it);
}else{ }else{
WarnL << "unhandled _result"; WarnL << "unhandled _result";
} }
} }
void RtmpPusher::onCmd_onStatus(AMFDecoder &dec) { void RtmpPusher::onCmd_onStatus(AMFDecoder &dec) {
AMFValue val; AMFValue val;
while(true){ while(true){
val = dec.load<AMFValue>(); val = dec.load<AMFValue>();
if(val.type() == AMF_OBJECT){ if(val.type() == AMF_OBJECT){
break; break;
} }
} }
if(val.type() != AMF_OBJECT){ if(val.type() != AMF_OBJECT){
throw std::runtime_error("onStatus:the result object was not found"); throw std::runtime_error("onStatus:the result object was not found");
} }
lock_guard<recursive_mutex> lck(_mtxOnStatusCB); lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
if(_dqOnStatusCB.size()){ if(_dqOnStatusCB.size()){
_dqOnStatusCB.front()(val); _dqOnStatusCB.front()(val);
_dqOnStatusCB.pop_front(); _dqOnStatusCB.pop_front();
}else{ }else{
auto level = val["level"]; auto level = val["level"];
auto code = val["code"].as_string(); auto code = val["code"].as_string();
if(level.type() == AMF_STRING){ if(level.type() == AMF_STRING){
if(level.as_string() != "status"){ if(level.as_string() != "status"){
throw std::runtime_error(StrPrinter <<"onStatus 失败:" << level.as_string() << " " << code << endl); throw std::runtime_error(StrPrinter <<"onStatus 失败:" << level.as_string() << " " << code << endl);
} }
} }
} }
} }
void RtmpPusher::onRtmpChunk(RtmpPacket &chunkData) { void RtmpPusher::onRtmpChunk(RtmpPacket &chunkData) {
switch (chunkData.typeId) { switch (chunkData.typeId) {
case MSG_CMD: case MSG_CMD:
case MSG_CMD3: { case MSG_CMD3: {
typedef void (RtmpPusher::*rtmpCMDHandle)(AMFDecoder &dec); typedef void (RtmpPusher::*rtmpCMDHandle)(AMFDecoder &dec);
static unordered_map<string, rtmpCMDHandle> g_mapCmd; static unordered_map<string, rtmpCMDHandle> g_mapCmd;
static onceToken token([]() { static onceToken token([]() {
g_mapCmd.emplace("_error",&RtmpPusher::onCmd_result); g_mapCmd.emplace("_error",&RtmpPusher::onCmd_result);
g_mapCmd.emplace("_result",&RtmpPusher::onCmd_result); g_mapCmd.emplace("_result",&RtmpPusher::onCmd_result);
g_mapCmd.emplace("onStatus",&RtmpPusher::onCmd_onStatus); g_mapCmd.emplace("onStatus",&RtmpPusher::onCmd_onStatus);
}, []() {}); }, []() {});
AMFDecoder dec(chunkData.strBuf, 0); AMFDecoder dec(chunkData.strBuf, 0);
std::string type = dec.load<std::string>(); std::string type = dec.load<std::string>();
auto it = g_mapCmd.find(type); auto it = g_mapCmd.find(type);
if(it != g_mapCmd.end()){ if(it != g_mapCmd.end()){
auto fun = it->second; auto fun = it->second;
(this->*fun)(dec); (this->*fun)(dec);
}else{ }else{
WarnL << "can not support cmd:" << type; WarnL << "can not support cmd:" << type;
} }
} }
break; break;
default: default:
//WarnL << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size()); //WarnL << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size());
break; break;
} }
} }

View File

@ -36,66 +36,66 @@ namespace mediakit {
class RtmpPusher: public RtmpProtocol , public TcpClient , public PusherBase{ class RtmpPusher: public RtmpProtocol , public TcpClient , public PusherBase{
public: public:
typedef std::shared_ptr<RtmpPusher> Ptr; typedef std::shared_ptr<RtmpPusher> Ptr;
RtmpPusher(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &src); RtmpPusher(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr &src);
virtual ~RtmpPusher(); virtual ~RtmpPusher();
void publish(const string &strUrl) override ; void publish(const string &strUrl) override ;
void teardown() override; void teardown() override;
void setOnPublished(const Event &cb) override { void setOnPublished(const Event &cb) override {
_onPublished = cb; _onPublished = cb;
} }
void setOnShutdown(const Event &cb) override{ void setOnShutdown(const Event &cb) override{
_onShutdown = cb; _onShutdown = cb;
} }
protected: protected:
//for Tcpclient override //for Tcpclient override
void onRecv(const Buffer::Ptr &pBuf) override; void onRecv(const Buffer::Ptr &pBuf) override;
void onConnect(const SockException &err) override; void onConnect(const SockException &err) override;
void onErr(const SockException &ex) override; void onErr(const SockException &ex) override;
//for RtmpProtocol override //for RtmpProtocol override
void onRtmpChunk(RtmpPacket &chunkData) override; void onRtmpChunk(RtmpPacket &chunkData) override;
void onSendRawData(const Buffer::Ptr &buffer) override{ void onSendRawData(const Buffer::Ptr &buffer) override{
send(buffer); send(buffer);
} }
private: private:
void onPublishResult(const SockException &ex,bool handshakeCompleted); void onPublishResult(const SockException &ex,bool handshakeCompleted);
template<typename FUN> template<typename FUN>
inline void addOnResultCB(const FUN &fun) { inline void addOnResultCB(const FUN &fun) {
lock_guard<recursive_mutex> lck(_mtxOnResultCB); lock_guard<recursive_mutex> lck(_mtxOnResultCB);
_mapOnResultCB.emplace(_iReqID, fun); _mapOnResultCB.emplace(_iReqID, fun);
} }
template<typename FUN> template<typename FUN>
inline void addOnStatusCB(const FUN &fun) { inline void addOnStatusCB(const FUN &fun) {
lock_guard<recursive_mutex> lck(_mtxOnStatusCB); lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
_dqOnStatusCB.emplace_back(fun); _dqOnStatusCB.emplace_back(fun);
} }
void onCmd_result(AMFDecoder &dec); void onCmd_result(AMFDecoder &dec);
void onCmd_onStatus(AMFDecoder &dec); void onCmd_onStatus(AMFDecoder &dec);
void onCmd_onMetaData(AMFDecoder &dec); void onCmd_onMetaData(AMFDecoder &dec);
inline void send_connect(); inline void send_connect();
inline void send_createStream(); inline void send_createStream();
inline void send_publish(); inline void send_publish();
inline void send_metaData(); inline void send_metaData();
void setSocketFlags(); void setSocketFlags();
private: private:
string _strApp; string _strApp;
string _strStream; string _strStream;
string _strTcUrl; string _strTcUrl;
unordered_map<int, function<void(AMFDecoder &dec)> > _mapOnResultCB; unordered_map<int, function<void(AMFDecoder &dec)> > _mapOnResultCB;
recursive_mutex _mtxOnResultCB; recursive_mutex _mtxOnResultCB;
deque<function<void(AMFValue &dec)> > _dqOnStatusCB; deque<function<void(AMFValue &dec)> > _dqOnStatusCB;
recursive_mutex _mtxOnStatusCB; recursive_mutex _mtxOnStatusCB;
//超时功能实现 //超时功能实现
std::shared_ptr<Timer> _pPublishTimer; std::shared_ptr<Timer> _pPublishTimer;
//源 //源
std::weak_ptr<RtmpMediaSource> _pMediaSrc; std::weak_ptr<RtmpMediaSource> _pMediaSrc;
RtmpMediaSource::RingType::RingReader::Ptr _pRtmpReader; RtmpMediaSource::RingType::RingReader::Ptr _pRtmpReader;

View File

@ -32,7 +32,7 @@
namespace mediakit { namespace mediakit {
RtmpSession::RtmpSession(const Socket::Ptr &pSock) : TcpSession(pSock) { RtmpSession::RtmpSession(const Socket::Ptr &pSock) : TcpSession(pSock) {
DebugP(this); DebugP(this);
GET_CONFIG(uint32_t,keep_alive_sec,Rtmp::kKeepAliveSecond); GET_CONFIG(uint32_t,keep_alive_sec,Rtmp::kKeepAliveSecond);
pSock->setSendTimeOutSecond(keep_alive_sec); pSock->setSendTimeOutSecond(keep_alive_sec);
//起始接收buffer缓存设置为4K节省内存 //起始接收buffer缓存设置为4K节省内存
@ -65,42 +65,42 @@ void RtmpSession::onManager() {
GET_CONFIG(uint32_t,handshake_sec,Rtmp::kHandshakeSecond); GET_CONFIG(uint32_t,handshake_sec,Rtmp::kHandshakeSecond);
GET_CONFIG(uint32_t,keep_alive_sec,Rtmp::kKeepAliveSecond); GET_CONFIG(uint32_t,keep_alive_sec,Rtmp::kKeepAliveSecond);
if (_ticker.createdTime() > handshake_sec * 1000) { if (_ticker.createdTime() > handshake_sec * 1000) {
if (!_pRingReader && !_pPublisherSrc) { if (!_pRingReader && !_pPublisherSrc) {
shutdown(SockException(Err_timeout,"illegal connection")); shutdown(SockException(Err_timeout,"illegal connection"));
} }
} }
if (_pPublisherSrc) { if (_pPublisherSrc) {
//publisher //publisher
if (_ticker.elapsedTime() > keep_alive_sec * 1000) { if (_ticker.elapsedTime() > keep_alive_sec * 1000) {
shutdown(SockException(Err_timeout,"recv data from rtmp pusher timeout")); shutdown(SockException(Err_timeout,"recv data from rtmp pusher timeout"));
} }
} }
} }
void RtmpSession::onRecv(const Buffer::Ptr &pBuf) { void RtmpSession::onRecv(const Buffer::Ptr &pBuf) {
_ticker.resetTime(); _ticker.resetTime();
try { try {
_ui64TotalBytes += pBuf->size(); _ui64TotalBytes += pBuf->size();
onParseRtmp(pBuf->data(), pBuf->size()); onParseRtmp(pBuf->data(), pBuf->size());
} catch (exception &e) { } catch (exception &e) {
shutdown(SockException(Err_shutdown, e.what())); shutdown(SockException(Err_shutdown, e.what()));
} }
} }
void RtmpSession::onCmd_connect(AMFDecoder &dec) { void RtmpSession::onCmd_connect(AMFDecoder &dec) {
auto params = dec.load<AMFValue>(); auto params = dec.load<AMFValue>();
double amfVer = 0; double amfVer = 0;
AMFValue objectEncoding = params["objectEncoding"]; AMFValue objectEncoding = params["objectEncoding"];
if(objectEncoding){ if(objectEncoding){
amfVer = objectEncoding.as_number(); amfVer = objectEncoding.as_number();
} }
///////////set chunk size//////////////// ///////////set chunk size////////////////
sendChunkSize(60000); sendChunkSize(60000);
////////////window Acknowledgement size///// ////////////window Acknowledgement size/////
sendAcknowledgementSize(5000000); sendAcknowledgementSize(5000000);
///////////set peerBandwidth//////////////// ///////////set peerBandwidth////////////////
sendPeerBandwidth(5000000); sendPeerBandwidth(5000000);
_mediaInfo._app = params["app"].as_string(); _mediaInfo._app = params["app"].as_string();
_strTcUrl = params["tcUrl"].as_string(); _strTcUrl = params["tcUrl"].as_string();
@ -108,27 +108,27 @@ void RtmpSession::onCmd_connect(AMFDecoder &dec) {
//defaultVhost:默认vhost //defaultVhost:默认vhost
_strTcUrl = string(RTMP_SCHEMA) + "://" + DEFAULT_VHOST + "/" + _mediaInfo._app; _strTcUrl = string(RTMP_SCHEMA) + "://" + DEFAULT_VHOST + "/" + _mediaInfo._app;
} }
bool ok = true; //(app == APP_NAME); bool ok = true; //(app == APP_NAME);
AMFValue version(AMF_OBJECT); AMFValue version(AMF_OBJECT);
version.set("fmsVer", "FMS/3,0,1,123"); version.set("fmsVer", "FMS/3,0,1,123");
version.set("capabilities", 31.0); version.set("capabilities", 31.0);
AMFValue status(AMF_OBJECT); AMFValue status(AMF_OBJECT);
status.set("level", ok ? "status" : "error"); status.set("level", ok ? "status" : "error");
status.set("code", ok ? "NetConnection.Connect.Success" : "NetConnection.Connect.InvalidApp"); status.set("code", ok ? "NetConnection.Connect.Success" : "NetConnection.Connect.InvalidApp");
status.set("description", ok ? "Connection succeeded." : "InvalidApp."); status.set("description", ok ? "Connection succeeded." : "InvalidApp.");
status.set("objectEncoding", amfVer); status.set("objectEncoding", amfVer);
sendReply(ok ? "_result" : "_error", version, status); sendReply(ok ? "_result" : "_error", version, status);
if (!ok) { if (!ok) {
throw std::runtime_error("Unsupported application: " + _mediaInfo._app); throw std::runtime_error("Unsupported application: " + _mediaInfo._app);
} }
AMFEncoder invoke; AMFEncoder invoke;
invoke << "onBWDone" << 0.0 << nullptr; invoke << "onBWDone" << 0.0 << nullptr;
sendResponse(MSG_CMD, invoke.data()); sendResponse(MSG_CMD, invoke.data());
} }
void RtmpSession::onCmd_createStream(AMFDecoder &dec) { void RtmpSession::onCmd_createStream(AMFDecoder &dec) {
sendReply("_result", nullptr, double(STREAM_MEDIA)); sendReply("_result", nullptr, double(STREAM_MEDIA));
} }
void RtmpSession::onCmd_publish(AMFDecoder &dec) { void RtmpSession::onCmd_publish(AMFDecoder &dec) {
@ -140,7 +140,7 @@ void RtmpSession::onCmd_publish(AMFDecoder &dec) {
DebugP(strongSelf.get()) << "publish 回复时间:" << pTicker->elapsedTime() << "ms"; DebugP(strongSelf.get()) << "publish 回复时间:" << pTicker->elapsedTime() << "ms";
} }
})); }));
dec.load<AMFValue>();/* NULL */ dec.load<AMFValue>();/* NULL */
_mediaInfo.parse(_strTcUrl + "/" + getStreamId(dec.load<std::string>())); _mediaInfo.parse(_strTcUrl + "/" + getStreamId(dec.load<std::string>()));
_mediaInfo._schema = RTMP_SCHEMA; _mediaInfo._schema = RTMP_SCHEMA;
@ -203,12 +203,12 @@ void RtmpSession::onCmd_publish(AMFDecoder &dec) {
} }
void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) { void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) {
AMFValue status(AMF_OBJECT); AMFValue status(AMF_OBJECT);
status.set("level", "status"); status.set("level", "status");
status.set("code", "NetStream.Unpublish.Success"); status.set("code", "NetStream.Unpublish.Success");
status.set("description", "Stop publishing."); status.set("description", "Stop publishing.");
sendReply("onStatus", nullptr, status); sendReply("onStatus", nullptr, status);
throw std::runtime_error(StrPrinter << "Stop publishing" << endl); throw std::runtime_error(StrPrinter << "Stop publishing" << endl);
} }
@ -355,7 +355,7 @@ void RtmpSession::doPlay(AMFDecoder &dec){
} }
} }
void RtmpSession::onCmd_play2(AMFDecoder &dec) { void RtmpSession::onCmd_play2(AMFDecoder &dec) {
doPlay(dec); doPlay(dec);
} }
string RtmpSession::getStreamId(const string &str){ string RtmpSession::getStreamId(const string &str){
@ -390,49 +390,49 @@ string RtmpSession::getStreamId(const string &str){
} }
void RtmpSession::onCmd_play(AMFDecoder &dec) { void RtmpSession::onCmd_play(AMFDecoder &dec) {
dec.load<AMFValue>();/* NULL */ dec.load<AMFValue>();/* NULL */
_mediaInfo.parse(_strTcUrl + "/" + getStreamId(dec.load<std::string>())); _mediaInfo.parse(_strTcUrl + "/" + getStreamId(dec.load<std::string>()));
_mediaInfo._schema = RTMP_SCHEMA; _mediaInfo._schema = RTMP_SCHEMA;
doPlay(dec); doPlay(dec);
} }
void RtmpSession::onCmd_pause(AMFDecoder &dec) { void RtmpSession::onCmd_pause(AMFDecoder &dec) {
dec.load<AMFValue>();/* NULL */ dec.load<AMFValue>();/* NULL */
bool paused = dec.load<bool>(); bool paused = dec.load<bool>();
TraceP(this) << paused; TraceP(this) << paused;
AMFValue status(AMF_OBJECT); AMFValue status(AMF_OBJECT);
status.set("level", "status"); status.set("level", "status");
status.set("code", paused ? "NetStream.Pause.Notify" : "NetStream.Unpause.Notify"); status.set("code", paused ? "NetStream.Pause.Notify" : "NetStream.Unpause.Notify");
status.set("description", paused ? "Paused stream." : "Unpaused stream."); status.set("description", paused ? "Paused stream." : "Unpaused stream.");
sendReply("onStatus", nullptr, status); sendReply("onStatus", nullptr, status);
//streamBegin //streamBegin
sendUserControl(paused ? CONTROL_STREAM_EOF : CONTROL_STREAM_BEGIN, sendUserControl(paused ? CONTROL_STREAM_EOF : CONTROL_STREAM_BEGIN,
STREAM_MEDIA); STREAM_MEDIA);
if (!_pRingReader) { if (!_pRingReader) {
throw std::runtime_error("Rtmp not started yet!"); throw std::runtime_error("Rtmp not started yet!");
} }
if (paused) { if (paused) {
_pRingReader->setReadCB(nullptr); _pRingReader->setReadCB(nullptr);
} else { } else {
weak_ptr<RtmpSession> weakSelf = dynamic_pointer_cast<RtmpSession>(shared_from_this()); weak_ptr<RtmpSession> weakSelf = dynamic_pointer_cast<RtmpSession>(shared_from_this());
_pRingReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt) { _pRingReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt) {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return; return;
} }
strongSelf->onSendMedia(pkt); strongSelf->onSendMedia(pkt);
}); });
} }
} }
void RtmpSession::setMetaData(AMFDecoder &dec) { void RtmpSession::setMetaData(AMFDecoder &dec) {
if (!_pPublisherSrc) { if (!_pPublisherSrc) {
throw std::runtime_error("not a publisher"); throw std::runtime_error("not a publisher");
} }
std::string type = dec.load<std::string>(); std::string type = dec.load<std::string>();
if (type != "onMetaData") { if (type != "onMetaData") {
throw std::runtime_error("can only set metadata"); throw std::runtime_error("can only set metadata");
} }
auto metadata = dec.load<AMFValue>(); auto metadata = dec.load<AMFValue>();
// dumpMetadata(metadata); // dumpMetadata(metadata);
_pPublisherSrc->setMetaData(metadata); _pPublisherSrc->setMetaData(metadata);
@ -453,42 +453,42 @@ void RtmpSession::onProcessCmd(AMFDecoder &dec) {
s_cmd_functions.emplace("pause",&RtmpSession::onCmd_pause);}, []() {}); s_cmd_functions.emplace("pause",&RtmpSession::onCmd_pause);}, []() {});
std::string method = dec.load<std::string>(); std::string method = dec.load<std::string>();
auto it = s_cmd_functions.find(method); auto it = s_cmd_functions.find(method);
if (it == s_cmd_functions.end()) { if (it == s_cmd_functions.end()) {
// TraceP(this) << "can not support cmd:" << method; // TraceP(this) << "can not support cmd:" << method;
return; return;
} }
_dNowReqID = dec.load<double>(); _dNowReqID = dec.load<double>();
auto fun = it->second; auto fun = it->second;
(this->*fun)(dec); (this->*fun)(dec);
} }
void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) { void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) {
switch (chunkData.typeId) { switch (chunkData.typeId) {
case MSG_CMD: case MSG_CMD:
case MSG_CMD3: { case MSG_CMD3: {
AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0); AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0);
onProcessCmd(dec); onProcessCmd(dec);
} }
break; break;
case MSG_DATA: case MSG_DATA:
case MSG_DATA3: { case MSG_DATA3: {
AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0); AMFDecoder dec(chunkData.strBuf, chunkData.typeId == MSG_CMD3 ? 1 : 0);
std::string type = dec.load<std::string>(); std::string type = dec.load<std::string>();
if (type == "@setDataFrame") { if (type == "@setDataFrame") {
setMetaData(dec); setMetaData(dec);
}else{ }else{
TraceP(this) << "unknown notify:" << type; TraceP(this) << "unknown notify:" << type;
} }
} }
break; break;
case MSG_AUDIO: case MSG_AUDIO:
case MSG_VIDEO: { case MSG_VIDEO: {
if (!_pPublisherSrc) { if (!_pPublisherSrc) {
throw std::runtime_error("Not a rtmp publisher!"); throw std::runtime_error("Not a rtmp publisher!");
} }
GET_CONFIG(bool,rtmp_modify_stamp,Rtmp::kModifyStamp); GET_CONFIG(bool,rtmp_modify_stamp,Rtmp::kModifyStamp);
if(rtmp_modify_stamp){ if(rtmp_modify_stamp){
int64_t dts_out; int64_t dts_out;
_stamp[chunkData.typeId % 2].revise(chunkData.timeStamp, chunkData.timeStamp, dts_out, dts_out, true); _stamp[chunkData.typeId % 2].revise(chunkData.timeStamp, chunkData.timeStamp, dts_out, dts_out, true);
@ -500,12 +500,12 @@ void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) {
_pPublisherSrc->setMetaData(TitleMeta().getMetadata()); _pPublisherSrc->setMetaData(TitleMeta().getMetadata());
} }
_pPublisherSrc->onWrite(std::make_shared<RtmpPacket>(std::move(chunkData))); _pPublisherSrc->onWrite(std::make_shared<RtmpPacket>(std::move(chunkData)));
} }
break; break;
default: default:
WarnP(this) << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size()); WarnP(this) << "unhandled message:" << (int) chunkData.typeId << hexdump(chunkData.strBuf.data(), chunkData.strBuf.size());
break; break;
} }
} }
void RtmpSession::onCmd_seek(AMFDecoder &dec) { void RtmpSession::onCmd_seek(AMFDecoder &dec) {
@ -518,12 +518,12 @@ void RtmpSession::onCmd_seek(AMFDecoder &dec) {
_stamp[1].setPlayBack(); _stamp[1].setPlayBack();
stongSrc->seekTo(milliSeconds); stongSrc->seekTo(milliSeconds);
} }
AMFValue status(AMF_OBJECT); AMFValue status(AMF_OBJECT);
AMFEncoder invoke; AMFEncoder invoke;
status.set("level", "status"); status.set("level", "status");
status.set("code", "NetStream.Seek.Notify"); status.set("code", "NetStream.Seek.Notify");
status.set("description", "Seeking."); status.set("description", "Seeking.");
sendReply("onStatus", nullptr, status); sendReply("onStatus", nullptr, status);
} }
void RtmpSession::onSendMedia(const RtmpPacket::Ptr &pkt) { void RtmpSession::onSendMedia(const RtmpPacket::Ptr &pkt) {

View File

@ -45,65 +45,65 @@ namespace mediakit {
class RtmpSession: public TcpSession ,public RtmpProtocol , public MediaSourceEvent{ class RtmpSession: public TcpSession ,public RtmpProtocol , public MediaSourceEvent{
public: public:
typedef std::shared_ptr<RtmpSession> Ptr; typedef std::shared_ptr<RtmpSession> Ptr;
RtmpSession(const Socket::Ptr &_sock); RtmpSession(const Socket::Ptr &_sock);
virtual ~RtmpSession(); virtual ~RtmpSession();
void onRecv(const Buffer::Ptr &pBuf) override; void onRecv(const Buffer::Ptr &pBuf) override;
void onError(const SockException &err) override; void onError(const SockException &err) override;
void onManager() override; void onManager() override;
private: private:
void onProcessCmd(AMFDecoder &dec); void onProcessCmd(AMFDecoder &dec);
void onCmd_connect(AMFDecoder &dec); void onCmd_connect(AMFDecoder &dec);
void onCmd_createStream(AMFDecoder &dec); void onCmd_createStream(AMFDecoder &dec);
void onCmd_publish(AMFDecoder &dec); void onCmd_publish(AMFDecoder &dec);
void onCmd_deleteStream(AMFDecoder &dec); void onCmd_deleteStream(AMFDecoder &dec);
void onCmd_play(AMFDecoder &dec); void onCmd_play(AMFDecoder &dec);
void onCmd_play2(AMFDecoder &dec); void onCmd_play2(AMFDecoder &dec);
void doPlay(AMFDecoder &dec); void doPlay(AMFDecoder &dec);
void doPlayResponse(const string &err,const std::function<void(bool)> &cb); void doPlayResponse(const string &err,const std::function<void(bool)> &cb);
void sendPlayResponse(const string &err,const RtmpMediaSource::Ptr &src); void sendPlayResponse(const string &err,const RtmpMediaSource::Ptr &src);
void onCmd_seek(AMFDecoder &dec); void onCmd_seek(AMFDecoder &dec);
void onCmd_pause(AMFDecoder &dec); void onCmd_pause(AMFDecoder &dec);
void setMetaData(AMFDecoder &dec); void setMetaData(AMFDecoder &dec);
void onSendMedia(const RtmpPacket::Ptr &pkt); void onSendMedia(const RtmpPacket::Ptr &pkt);
void onSendRawData(const Buffer::Ptr &buffer) override{ void onSendRawData(const Buffer::Ptr &buffer) override{
_ui64TotalBytes += buffer->size(); _ui64TotalBytes += buffer->size();
send(buffer); send(buffer);
} }
void onRtmpChunk(RtmpPacket &chunkData) override; void onRtmpChunk(RtmpPacket &chunkData) override;
template<typename first, typename second> template<typename first, typename second>
inline void sendReply(const char *str, const first &reply, const second &status) { inline void sendReply(const char *str, const first &reply, const second &status) {
AMFEncoder invoke; AMFEncoder invoke;
invoke << str << _dNowReqID << reply << status; invoke << str << _dNowReqID << reply << status;
sendResponse(MSG_CMD, invoke.data()); sendResponse(MSG_CMD, invoke.data());
} }
//MediaSourceEvent override //MediaSourceEvent override
bool close(MediaSource &sender,bool force) override ; bool close(MediaSource &sender,bool force) override ;
void onNoneReader(MediaSource &sender) override; void onNoneReader(MediaSource &sender) override;
int totalReaderCount(MediaSource &sender) override; int totalReaderCount(MediaSource &sender) override;
void setSocketFlags(); void setSocketFlags();
string getStreamId(const string &str); string getStreamId(const string &str);
void dumpMetadata(const AMFValue &metadata); void dumpMetadata(const AMFValue &metadata);
private: private:
std::string _strTcUrl; std::string _strTcUrl;
MediaInfo _mediaInfo; MediaInfo _mediaInfo;
double _dNowReqID = 0; double _dNowReqID = 0;
bool _set_meta_data = false; bool _set_meta_data = false;
Ticker _ticker;//数据接收时间 Ticker _ticker;//数据接收时间
RingBuffer<RtmpPacket::Ptr>::RingReader::Ptr _pRingReader; RingBuffer<RtmpPacket::Ptr>::RingReader::Ptr _pRingReader;
std::shared_ptr<RtmpMediaSourceImp> _pPublisherSrc; std::shared_ptr<RtmpMediaSourceImp> _pPublisherSrc;
std::weak_ptr<RtmpMediaSource> _pPlayerSrc; std::weak_ptr<RtmpMediaSource> _pPlayerSrc;
//时间戳修整器 //时间戳修整器
Stamp _stamp[2]; Stamp _stamp[2];
//消耗的总流量 //消耗的总流量
uint64_t _ui64TotalBytes = 0; uint64_t _ui64TotalBytes = 0;
}; };

View File

@ -35,130 +35,130 @@ using namespace toolkit;
/////////////////////AMFValue///////////////////////////// /////////////////////AMFValue/////////////////////////////
inline void AMFValue::destroy() { inline void AMFValue::destroy() {
switch (_type) { switch (_type) {
case AMF_STRING: case AMF_STRING:
if (_value.string) { if (_value.string) {
delete _value.string; delete _value.string;
_value.string = nullptr; _value.string = nullptr;
} }
break; break;
case AMF_OBJECT: case AMF_OBJECT:
case AMF_ECMA_ARRAY: case AMF_ECMA_ARRAY:
if (_value.object) { if (_value.object) {
delete _value.object; delete _value.object;
_value.object = nullptr; _value.object = nullptr;
} }
break; break;
case AMF_STRICT_ARRAY: case AMF_STRICT_ARRAY:
if (_value.array) { if (_value.array) {
delete _value.array; delete _value.array;
_value.array = nullptr; _value.array = nullptr;
} }
break; break;
default: default:
break; break;
} }
} }
inline void AMFValue::init() { inline void AMFValue::init() {
switch (_type) { switch (_type) {
case AMF_OBJECT: case AMF_OBJECT:
case AMF_ECMA_ARRAY: case AMF_ECMA_ARRAY:
_value.object = new mapType; _value.object = new mapType;
break; break;
case AMF_STRING: case AMF_STRING:
_value.string = new std::string; _value.string = new std::string;
break; break;
case AMF_STRICT_ARRAY: case AMF_STRICT_ARRAY:
_value.array = new arrayType; _value.array = new arrayType;
break; break;
default: default:
break; break;
} }
} }
AMFValue::AMFValue(AMFType type) : AMFValue::AMFValue(AMFType type) :
_type(type) { _type(type) {
init(); init();
} }
AMFValue::~AMFValue() { AMFValue::~AMFValue() {
destroy(); destroy();
} }
AMFValue::AMFValue(const char *s) : AMFValue::AMFValue(const char *s) :
_type(AMF_STRING) { _type(AMF_STRING) {
init(); init();
*_value.string = s; *_value.string = s;
} }
AMFValue::AMFValue(const std::string &s) : AMFValue::AMFValue(const std::string &s) :
_type(AMF_STRING) { _type(AMF_STRING) {
init(); init();
*_value.string = s; *_value.string = s;
} }
AMFValue::AMFValue(double n) : AMFValue::AMFValue(double n) :
_type(AMF_NUMBER) { _type(AMF_NUMBER) {
init(); init();
_value.number = n; _value.number = n;
} }
AMFValue::AMFValue(int i) : AMFValue::AMFValue(int i) :
_type(AMF_INTEGER) { _type(AMF_INTEGER) {
init(); init();
_value.integer = i; _value.integer = i;
} }
AMFValue::AMFValue(bool b) : AMFValue::AMFValue(bool b) :
_type(AMF_BOOLEAN) { _type(AMF_BOOLEAN) {
init(); init();
_value.boolean = b; _value.boolean = b;
} }
AMFValue::AMFValue(const AMFValue &from) : AMFValue::AMFValue(const AMFValue &from) :
_type(AMF_NULL) { _type(AMF_NULL) {
*this = from; *this = from;
} }
AMFValue::AMFValue(AMFValue &&from) { AMFValue::AMFValue(AMFValue &&from) {
*this = std::forward<AMFValue>(from); *this = std::forward<AMFValue>(from);
} }
AMFValue& AMFValue::operator =(const AMFValue &from) { AMFValue& AMFValue::operator =(const AMFValue &from) {
return *this = const_cast<AMFValue &&>(from); return *this = const_cast<AMFValue &&>(from);
} }
AMFValue& AMFValue::operator =(AMFValue &&from) { AMFValue& AMFValue::operator =(AMFValue &&from) {
destroy(); destroy();
_type = from._type; _type = from._type;
init(); init();
switch (_type) { switch (_type) {
case AMF_STRING: case AMF_STRING:
*_value.string = (*from._value.string); *_value.string = (*from._value.string);
break; break;
case AMF_OBJECT: case AMF_OBJECT:
case AMF_ECMA_ARRAY: case AMF_ECMA_ARRAY:
*_value.object = (*from._value.object); *_value.object = (*from._value.object);
break; break;
case AMF_STRICT_ARRAY: case AMF_STRICT_ARRAY:
*_value.array = (*from._value.array); *_value.array = (*from._value.array);
break; break;
case AMF_NUMBER: case AMF_NUMBER:
_value.number = from._value.number; _value.number = from._value.number;
break; break;
case AMF_INTEGER: case AMF_INTEGER:
_value.integer = from._value.integer; _value.integer = from._value.integer;
break; break;
case AMF_BOOLEAN: case AMF_BOOLEAN:
_value.boolean = from._value.boolean; _value.boolean = from._value.boolean;
break; break;
default: default:
break; break;
} }
return *this; return *this;
} }
@ -305,156 +305,156 @@ const AMFValue::arrayType &AMFValue::getArr() const {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
enum { enum {
AMF0_NUMBER, AMF0_NUMBER,
AMF0_BOOLEAN, AMF0_BOOLEAN,
AMF0_STRING, AMF0_STRING,
AMF0_OBJECT, AMF0_OBJECT,
AMF0_MOVIECLIP, AMF0_MOVIECLIP,
AMF0_NULL, AMF0_NULL,
AMF0_UNDEFINED, AMF0_UNDEFINED,
AMF0_REFERENCE, AMF0_REFERENCE,
AMF0_ECMA_ARRAY, AMF0_ECMA_ARRAY,
AMF0_OBJECT_END, AMF0_OBJECT_END,
AMF0_STRICT_ARRAY, AMF0_STRICT_ARRAY,
AMF0_DATE, AMF0_DATE,
AMF0_LONG_STRING, AMF0_LONG_STRING,
AMF0_UNSUPPORTED, AMF0_UNSUPPORTED,
AMF0_RECORD_SET, AMF0_RECORD_SET,
AMF0_XML_OBJECT, AMF0_XML_OBJECT,
AMF0_TYPED_OBJECT, AMF0_TYPED_OBJECT,
AMF0_SWITCH_AMF3, AMF0_SWITCH_AMF3,
}; };
enum { enum {
AMF3_UNDEFINED, AMF3_UNDEFINED,
AMF3_NULL, AMF3_NULL,
AMF3_FALSE, AMF3_FALSE,
AMF3_TRUE, AMF3_TRUE,
AMF3_INTEGER, AMF3_INTEGER,
AMF3_NUMBER, AMF3_NUMBER,
AMF3_STRING, AMF3_STRING,
AMF3_LEGACY_XML, AMF3_LEGACY_XML,
AMF3_DATE, AMF3_DATE,
AMF3_ARRAY, AMF3_ARRAY,
AMF3_OBJECT, AMF3_OBJECT,
AMF3_XML, AMF3_XML,
AMF3_BYTE_ARRAY, AMF3_BYTE_ARRAY,
}; };
////////////////////////////////Encoder////////////////////////////////////////// ////////////////////////////////Encoder//////////////////////////////////////////
AMFEncoder & AMFEncoder::operator <<(const char *s) { AMFEncoder & AMFEncoder::operator <<(const char *s) {
if (s) { if (s) {
buf += char(AMF0_STRING); buf += char(AMF0_STRING);
uint16_t str_len = htons(strlen(s)); uint16_t str_len = htons(strlen(s));
buf.append((char *) &str_len, 2); buf.append((char *) &str_len, 2);
buf += s; buf += s;
} else { } else {
buf += char(AMF0_NULL); buf += char(AMF0_NULL);
} }
return *this; return *this;
} }
AMFEncoder & AMFEncoder::operator <<(const std::string &s) { AMFEncoder & AMFEncoder::operator <<(const std::string &s) {
if (!s.empty()) { if (!s.empty()) {
buf += char(AMF0_STRING); buf += char(AMF0_STRING);
uint16_t str_len = htons(s.size()); uint16_t str_len = htons(s.size());
buf.append((char *) &str_len, 2); buf.append((char *) &str_len, 2);
buf += s; buf += s;
} else { } else {
buf += char(AMF0_NULL); buf += char(AMF0_NULL);
} }
return *this; return *this;
} }
AMFEncoder & AMFEncoder::operator <<(std::nullptr_t) { AMFEncoder & AMFEncoder::operator <<(std::nullptr_t) {
buf += char(AMF0_NULL); buf += char(AMF0_NULL);
return *this; return *this;
} }
AMFEncoder & AMFEncoder::write_undefined() { AMFEncoder & AMFEncoder::write_undefined() {
buf += char(AMF0_UNDEFINED); buf += char(AMF0_UNDEFINED);
return *this; return *this;
} }
AMFEncoder & AMFEncoder::operator <<(const int n){ AMFEncoder & AMFEncoder::operator <<(const int n){
return (*this) << (double)n; return (*this) << (double)n;
} }
AMFEncoder & AMFEncoder::operator <<(const double n) { AMFEncoder & AMFEncoder::operator <<(const double n) {
buf += char(AMF0_NUMBER); buf += char(AMF0_NUMBER);
uint64_t encoded = 0; uint64_t encoded = 0;
memcpy(&encoded, &n, 8); memcpy(&encoded, &n, 8);
uint32_t val = htonl(encoded >> 32); uint32_t val = htonl(encoded >> 32);
buf.append((char *) &val, 4); buf.append((char *) &val, 4);
val = htonl(encoded); val = htonl(encoded);
buf.append((char *) &val, 4); buf.append((char *) &val, 4);
return *this; return *this;
} }
AMFEncoder & AMFEncoder::operator <<(const bool b) { AMFEncoder & AMFEncoder::operator <<(const bool b) {
buf += char(AMF0_BOOLEAN); buf += char(AMF0_BOOLEAN);
buf += char(b); buf += char(b);
return *this; return *this;
} }
AMFEncoder & AMFEncoder::operator <<(const AMFValue& value) { AMFEncoder & AMFEncoder::operator <<(const AMFValue& value) {
switch ((int) value.type()) { switch ((int) value.type()) {
case AMF_STRING: case AMF_STRING:
*this << value.as_string(); *this << value.as_string();
break; break;
case AMF_NUMBER: case AMF_NUMBER:
*this << value.as_number(); *this << value.as_number();
break; break;
case AMF_INTEGER: case AMF_INTEGER:
*this << value.as_integer(); *this << value.as_integer();
break; break;
case AMF_BOOLEAN: case AMF_BOOLEAN:
*this << value.as_boolean(); *this << value.as_boolean();
break; break;
case AMF_OBJECT: { case AMF_OBJECT: {
buf += char(AMF0_OBJECT); buf += char(AMF0_OBJECT);
for (auto &pr : value.getMap()) { for (auto &pr : value.getMap()) {
write_key(pr.first); write_key(pr.first);
*this << pr.second; *this << pr.second;
} }
write_key(""); write_key("");
buf += char(AMF0_OBJECT_END); buf += char(AMF0_OBJECT_END);
} }
break; break;
case AMF_ECMA_ARRAY: { case AMF_ECMA_ARRAY: {
buf += char(AMF0_ECMA_ARRAY); buf += char(AMF0_ECMA_ARRAY);
uint32_t sz = htonl(value.getMap().size()); uint32_t sz = htonl(value.getMap().size());
buf.append((char *) &sz, 4); buf.append((char *) &sz, 4);
for (auto &pr : value.getMap()) { for (auto &pr : value.getMap()) {
write_key(pr.first); write_key(pr.first);
*this << pr.second; *this << pr.second;
} }
write_key(""); write_key("");
buf += char(AMF0_OBJECT_END); buf += char(AMF0_OBJECT_END);
} }
break; break;
case AMF_NULL: case AMF_NULL:
*this << nullptr; *this << nullptr;
break; break;
case AMF_UNDEFINED: case AMF_UNDEFINED:
this->write_undefined(); this->write_undefined();
break; break;
case AMF_STRICT_ARRAY: { case AMF_STRICT_ARRAY: {
buf += char(AMF0_STRICT_ARRAY); buf += char(AMF0_STRICT_ARRAY);
uint32_t sz = htonl(value.getArr().size()); uint32_t sz = htonl(value.getArr().size());
buf.append((char *) &sz, 4); buf.append((char *) &sz, 4);
for (auto &val : value.getArr()) { for (auto &val : value.getArr()) {
*this << val; *this << val;
} }
//write_key(""); //write_key("");
//buf += char(AMF0_OBJECT_END); //buf += char(AMF0_OBJECT_END);
} }
break; break;
} }
return *this; return *this;
} }
void AMFEncoder::write_key(const std::string& s) { void AMFEncoder::write_key(const std::string& s) {
uint16_t str_len = htons(s.size()); uint16_t str_len = htons(s.size());
buf.append((char *) &str_len, 2); buf.append((char *) &str_len, 2);
buf += s; buf += s;
} }
void AMFEncoder::clear() { void AMFEncoder::clear() {
@ -468,237 +468,237 @@ const std::string& AMFEncoder::data() const {
//////////////////Decoder////////////////// //////////////////Decoder//////////////////
uint8_t AMFDecoder::front() { uint8_t AMFDecoder::front() {
if (pos >= buf.size()) { if (pos >= buf.size()) {
throw std::runtime_error("Not enough data"); throw std::runtime_error("Not enough data");
} }
return uint8_t(buf[pos]); return uint8_t(buf[pos]);
} }
uint8_t AMFDecoder::pop_front() { uint8_t AMFDecoder::pop_front() {
if (version == 0 && front() == AMF0_SWITCH_AMF3) { if (version == 0 && front() == AMF0_SWITCH_AMF3) {
InfoL << "entering AMF3 mode"; InfoL << "entering AMF3 mode";
pos++; pos++;
version = 3; version = 3;
} }
if (pos >= buf.size()) { if (pos >= buf.size()) {
throw std::runtime_error("Not enough data"); throw std::runtime_error("Not enough data");
} }
return uint8_t(buf[pos++]); return uint8_t(buf[pos++]);
} }
template<> template<>
double AMFDecoder::load<double>() { double AMFDecoder::load<double>() {
if (pop_front() != AMF0_NUMBER) { if (pop_front() != AMF0_NUMBER) {
throw std::runtime_error("Expected a number"); throw std::runtime_error("Expected a number");
} }
if (pos + 8 > buf.size()) { if (pos + 8 > buf.size()) {
throw std::runtime_error("Not enough data"); throw std::runtime_error("Not enough data");
} }
uint64_t val = ((uint64_t) load_be32(&buf[pos]) << 32) uint64_t val = ((uint64_t) load_be32(&buf[pos]) << 32)
| load_be32(&buf[pos + 4]); | load_be32(&buf[pos + 4]);
double n = 0; double n = 0;
memcpy(&n, &val, 8); memcpy(&n, &val, 8);
pos += 8; pos += 8;
return n; return n;
} }
template<> template<>
bool AMFDecoder::load<bool>() { bool AMFDecoder::load<bool>() {
if (pop_front() != AMF0_BOOLEAN) { if (pop_front() != AMF0_BOOLEAN) {
throw std::runtime_error("Expected a boolean"); throw std::runtime_error("Expected a boolean");
} }
return pop_front() != 0; return pop_front() != 0;
} }
template<> template<>
unsigned int AMFDecoder::load<unsigned int>() { unsigned int AMFDecoder::load<unsigned int>() {
unsigned int value = 0; unsigned int value = 0;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
uint8_t b = pop_front(); uint8_t b = pop_front();
if (i == 3) { if (i == 3) {
/* use all bits from 4th byte */ /* use all bits from 4th byte */
value = (value << 8) | b; value = (value << 8) | b;
break; break;
} }
value = (value << 7) | (b & 0x7f); value = (value << 7) | (b & 0x7f);
if ((b & 0x80) == 0) if ((b & 0x80) == 0)
break; break;
} }
return value; return value;
} }
template<> template<>
int AMFDecoder::load<int>() { int AMFDecoder::load<int>() {
if (version == 3) { if (version == 3) {
return load<unsigned int>(); return load<unsigned int>();
} else { } else {
return load<double>(); return load<double>();
} }
} }
template<> template<>
std::string AMFDecoder::load<std::string>() { std::string AMFDecoder::load<std::string>() {
size_t str_len = 0; size_t str_len = 0;
uint8_t type = pop_front(); uint8_t type = pop_front();
if (version == 3) { if (version == 3) {
if (type != AMF3_STRING) { if (type != AMF3_STRING) {
throw std::runtime_error("Expected a string"); throw std::runtime_error("Expected a string");
} }
str_len = load<unsigned int>() / 2; str_len = load<unsigned int>() / 2;
} else { } else {
if (type != AMF0_STRING) { if (type != AMF0_STRING) {
throw std::runtime_error("Expected a string"); throw std::runtime_error("Expected a string");
} }
if (pos + 2 > buf.size()) { if (pos + 2 > buf.size()) {
throw std::runtime_error("Not enough data"); throw std::runtime_error("Not enough data");
} }
str_len = load_be16(&buf[pos]); str_len = load_be16(&buf[pos]);
pos += 2; pos += 2;
} }
if (pos + str_len > buf.size()) { if (pos + str_len > buf.size()) {
throw std::runtime_error("Not enough data"); throw std::runtime_error("Not enough data");
} }
std::string s(buf, pos, str_len); std::string s(buf, pos, str_len);
pos += str_len; pos += str_len;
return s; return s;
} }
template<> template<>
AMFValue AMFDecoder::load<AMFValue>() { AMFValue AMFDecoder::load<AMFValue>() {
uint8_t type = front(); uint8_t type = front();
if (version == 3) { if (version == 3) {
switch (type) { switch (type) {
case AMF3_STRING: case AMF3_STRING:
return load<std::string>(); return load<std::string>();
case AMF3_NUMBER: case AMF3_NUMBER:
return load<double>(); return load<double>();
case AMF3_INTEGER: case AMF3_INTEGER:
return load<int>(); return load<int>();
case AMF3_FALSE: case AMF3_FALSE:
pos++; pos++;
return false; return false;
case AMF3_TRUE: case AMF3_TRUE:
pos++; pos++;
return true; return true;
case AMF3_OBJECT: case AMF3_OBJECT:
return load_object(); return load_object();
case AMF3_ARRAY: case AMF3_ARRAY:
return load_ecma(); return load_ecma();
case AMF3_NULL: case AMF3_NULL:
pos++; pos++;
return AMF_NULL; return AMF_NULL;
case AMF3_UNDEFINED: case AMF3_UNDEFINED:
pos++; pos++;
return AMF_UNDEFINED; return AMF_UNDEFINED;
default: default:
throw std::runtime_error( throw std::runtime_error(
StrPrinter << "Unsupported AMF3 type:" << (int) type << endl); StrPrinter << "Unsupported AMF3 type:" << (int) type << endl);
} }
} else { } else {
switch (type) { switch (type) {
case AMF0_STRING: case AMF0_STRING:
return load<std::string>(); return load<std::string>();
case AMF0_NUMBER: case AMF0_NUMBER:
return load<double>(); return load<double>();
case AMF0_BOOLEAN: case AMF0_BOOLEAN:
return load<bool>(); return load<bool>();
case AMF0_OBJECT: case AMF0_OBJECT:
return load_object(); return load_object();
case AMF0_ECMA_ARRAY: case AMF0_ECMA_ARRAY:
return load_ecma(); return load_ecma();
case AMF0_NULL: case AMF0_NULL:
pos++; pos++;
return AMF_NULL; return AMF_NULL;
case AMF0_UNDEFINED: case AMF0_UNDEFINED:
pos++; pos++;
return AMF_UNDEFINED; return AMF_UNDEFINED;
case AMF0_STRICT_ARRAY: case AMF0_STRICT_ARRAY:
return load_arr(); return load_arr();
default: default:
throw std::runtime_error( throw std::runtime_error(
StrPrinter << "Unsupported AMF type:" << (int) type << endl); StrPrinter << "Unsupported AMF type:" << (int) type << endl);
} }
} }
} }
std::string AMFDecoder::load_key() { std::string AMFDecoder::load_key() {
if (pos + 2 > buf.size()) { if (pos + 2 > buf.size()) {
throw std::runtime_error("Not enough data"); throw std::runtime_error("Not enough data");
} }
size_t str_len = load_be16(&buf[pos]); size_t str_len = load_be16(&buf[pos]);
pos += 2; pos += 2;
if (pos + str_len > buf.size()) { if (pos + str_len > buf.size()) {
throw std::runtime_error("Not enough data"); throw std::runtime_error("Not enough data");
} }
std::string s(buf, pos, str_len); std::string s(buf, pos, str_len);
pos += str_len; pos += str_len;
return s; return s;
} }
AMFValue AMFDecoder::load_object() { AMFValue AMFDecoder::load_object() {
AMFValue object(AMF_OBJECT); AMFValue object(AMF_OBJECT);
if (pop_front() != AMF0_OBJECT) { if (pop_front() != AMF0_OBJECT) {
throw std::runtime_error("Expected an object"); throw std::runtime_error("Expected an object");
} }
while (1) { while (1) {
std::string key = load_key(); std::string key = load_key();
if (key.empty()) if (key.empty())
break; break;
AMFValue value = load<AMFValue>(); AMFValue value = load<AMFValue>();
object.set(key, value); object.set(key, value);
} }
if (pop_front() != AMF0_OBJECT_END) { if (pop_front() != AMF0_OBJECT_END) {
throw std::runtime_error("expected object end"); throw std::runtime_error("expected object end");
} }
return object; return object;
} }
AMFValue AMFDecoder::load_ecma() { AMFValue AMFDecoder::load_ecma() {
/* ECMA array is the same as object, with 4 extra zero bytes */ /* ECMA array is the same as object, with 4 extra zero bytes */
AMFValue object(AMF_ECMA_ARRAY); AMFValue object(AMF_ECMA_ARRAY);
if (pop_front() != AMF0_ECMA_ARRAY) { if (pop_front() != AMF0_ECMA_ARRAY) {
throw std::runtime_error("Expected an ECMA array"); throw std::runtime_error("Expected an ECMA array");
} }
if (pos + 4 > buf.size()) { if (pos + 4 > buf.size()) {
throw std::runtime_error("Not enough data"); throw std::runtime_error("Not enough data");
} }
pos += 4; pos += 4;
while (1) { while (1) {
std::string key = load_key(); std::string key = load_key();
if (key.empty()) if (key.empty())
break; break;
AMFValue value = load<AMFValue>(); AMFValue value = load<AMFValue>();
object.set(key, value); object.set(key, value);
} }
if (pop_front() != AMF0_OBJECT_END) { if (pop_front() != AMF0_OBJECT_END) {
throw std::runtime_error("expected object end"); throw std::runtime_error("expected object end");
} }
return object; return object;
} }
AMFValue AMFDecoder::load_arr() { AMFValue AMFDecoder::load_arr() {
/* ECMA array is the same as object, with 4 extra zero bytes */ /* ECMA array is the same as object, with 4 extra zero bytes */
AMFValue object(AMF_STRICT_ARRAY); AMFValue object(AMF_STRICT_ARRAY);
if (pop_front() != AMF0_STRICT_ARRAY) { if (pop_front() != AMF0_STRICT_ARRAY) {
throw std::runtime_error("Expected an STRICT array"); throw std::runtime_error("Expected an STRICT array");
} }
if (pos + 4 > buf.size()) { if (pos + 4 > buf.size()) {
throw std::runtime_error("Not enough data"); throw std::runtime_error("Not enough data");
} }
int arrSize = load_be32(&buf[pos]); int arrSize = load_be32(&buf[pos]);
pos += 4; pos += 4;
while (arrSize--) { while (arrSize--) {
AMFValue value = load<AMFValue>(); AMFValue value = load<AMFValue>();
object.add(value); object.add(value);
} }
/*pos += 2; /*pos += 2;
if (pop_front() != AMF0_OBJECT_END) { if (pop_front() != AMF0_OBJECT_END) {
throw std::runtime_error("expected object end"); throw std::runtime_error("expected object end");
}*/ }*/
return object; return object;
} }
AMFDecoder::AMFDecoder(const std::string &buf_in, size_t pos_in, int version_in) : AMFDecoder::AMFDecoder(const std::string &buf_in, size_t pos_in, int version_in) :

View File

@ -36,15 +36,15 @@
using namespace std; using namespace std;
enum AMFType { enum AMFType {
AMF_NUMBER, AMF_NUMBER,
AMF_INTEGER, AMF_INTEGER,
AMF_BOOLEAN, AMF_BOOLEAN,
AMF_STRING, AMF_STRING,
AMF_OBJECT, AMF_OBJECT,
AMF_NULL, AMF_NULL,
AMF_UNDEFINED, AMF_UNDEFINED,
AMF_ECMA_ARRAY, AMF_ECMA_ARRAY,
AMF_STRICT_ARRAY, AMF_STRICT_ARRAY,
}; };
class AMFValue; class AMFValue;
@ -55,79 +55,79 @@ public:
typedef std::map<std::string, AMFValue> mapType; typedef std::map<std::string, AMFValue> mapType;
typedef std::vector<AMFValue> arrayType; typedef std::vector<AMFValue> arrayType;
AMFValue(AMFType type = AMF_NULL); AMFValue(AMFType type = AMF_NULL);
AMFValue(const char *s); AMFValue(const char *s);
AMFValue(const std::string &s); AMFValue(const std::string &s);
AMFValue(double n); AMFValue(double n);
AMFValue(int i); AMFValue(int i);
AMFValue(bool b); AMFValue(bool b);
AMFValue(const AMFValue &from); AMFValue(const AMFValue &from);
AMFValue(AMFValue &&from); AMFValue(AMFValue &&from);
AMFValue &operator =(const AMFValue &from); AMFValue &operator =(const AMFValue &from);
AMFValue &operator =(AMFValue &&from); AMFValue &operator =(AMFValue &&from);
~AMFValue(); ~AMFValue();
void clear(); void clear();
AMFType type() const ; AMFType type() const ;
const std::string &as_string() const; const std::string &as_string() const;
double as_number() const; double as_number() const;
int as_integer() const; int as_integer() const;
bool as_boolean() const; bool as_boolean() const;
string to_string() const; string to_string() const;
const AMFValue &operator[](const char *str) const; const AMFValue &operator[](const char *str) const;
void object_for_each(const function<void(const string &key, const AMFValue &val)> &fun) const ; void object_for_each(const function<void(const string &key, const AMFValue &val)> &fun) const ;
operator bool() const; operator bool() const;
void set(const std::string &s, const AMFValue &val); void set(const std::string &s, const AMFValue &val);
void add(const AMFValue &val); void add(const AMFValue &val);
private: private:
const mapType &getMap() const; const mapType &getMap() const;
const arrayType &getArr() const; const arrayType &getArr() const;
void destroy(); void destroy();
void init(); void init();
private: private:
AMFType _type; AMFType _type;
union { union {
std::string *string; std::string *string;
double number; double number;
int integer; int integer;
bool boolean; bool boolean;
mapType *object; mapType *object;
arrayType *array; arrayType *array;
} _value; } _value;
}; };
class AMFDecoder { class AMFDecoder {
public: public:
AMFDecoder(const std::string &buf, size_t pos, int version = 0); AMFDecoder(const std::string &buf, size_t pos, int version = 0);
template<typename TP> template<typename TP>
TP load(); TP load();
private: private:
std::string load_key(); std::string load_key();
AMFValue load_object(); AMFValue load_object();
AMFValue load_ecma(); AMFValue load_ecma();
AMFValue load_arr(); AMFValue load_arr();
uint8_t front(); uint8_t front();
uint8_t pop_front(); uint8_t pop_front();
private: private:
const std::string &buf; const std::string &buf;
size_t pos; size_t pos;
int version; int version;
}; };
class AMFEncoder { class AMFEncoder {
public: public:
AMFEncoder & operator <<(const char *s); AMFEncoder & operator <<(const char *s);
AMFEncoder & operator <<(const std::string &s); AMFEncoder & operator <<(const std::string &s);
AMFEncoder & operator <<(std::nullptr_t); AMFEncoder & operator <<(std::nullptr_t);
AMFEncoder & operator <<(const int n); AMFEncoder & operator <<(const int n);
AMFEncoder & operator <<(const double n); AMFEncoder & operator <<(const double n);
AMFEncoder & operator <<(const bool b); AMFEncoder & operator <<(const bool b);
AMFEncoder & operator <<(const AMFValue &value); AMFEncoder & operator <<(const AMFValue &value);
const std::string& data() const ; const std::string& data() const ;
void clear() ; void clear() ;
private: private:
void write_key(const std::string &s); void write_key(const std::string &s);
AMFEncoder &write_undefined(); AMFEncoder &write_undefined();
private: private:
std::string buf; std::string buf;
}; };

View File

@ -38,54 +38,54 @@ using namespace toolkit;
*/ */
uint32_t load_be32(const void *p) uint32_t load_be32(const void *p)
{ {
uint32_t val; uint32_t val;
memcpy(&val, p, sizeof val); memcpy(&val, p, sizeof val);
return ntohl(val); return ntohl(val);
} }
uint16_t load_be16(const void *p) uint16_t load_be16(const void *p)
{ {
uint16_t val; uint16_t val;
memcpy(&val, p, sizeof val); memcpy(&val, p, sizeof val);
return ntohs(val); return ntohs(val);
} }
uint32_t load_le32(const void *p) uint32_t load_le32(const void *p)
{ {
const uint8_t *data = (const uint8_t *) p; const uint8_t *data = (const uint8_t *) p;
return data[0] | ((uint32_t) data[1] << 8) | return data[0] | ((uint32_t) data[1] << 8) |
((uint32_t) data[2] << 16) | ((uint32_t) data[3] << 24); ((uint32_t) data[2] << 16) | ((uint32_t) data[3] << 24);
} }
uint32_t load_be24(const void *p) uint32_t load_be24(const void *p)
{ {
const uint8_t *data = (const uint8_t *) p; const uint8_t *data = (const uint8_t *) p;
return data[2] | ((uint32_t) data[1] << 8) | ((uint32_t) data[0] << 16); return data[2] | ((uint32_t) data[1] << 8) | ((uint32_t) data[0] << 16);
} }
void set_be24(void *p, uint32_t val) void set_be24(void *p, uint32_t val)
{ {
uint8_t *data = (uint8_t *) p; uint8_t *data = (uint8_t *) p;
data[0] = val >> 16; data[0] = val >> 16;
data[1] = val >> 8; data[1] = val >> 8;
data[2] = val; data[2] = val;
} }
void set_le32(void *p, uint32_t val) void set_le32(void *p, uint32_t val)
{ {
uint8_t *data = (uint8_t *) p; uint8_t *data = (uint8_t *) p;
data[0] = val; data[0] = val;
data[1] = val >> 8; data[1] = val >> 8;
data[2] = val >> 16; data[2] = val >> 16;
data[3] = val >> 24; data[3] = val >> 24;
} }
void set_be32(void *p, uint32_t val) void set_be32(void *p, uint32_t val)
{ {
uint8_t *data = (uint8_t *) p; uint8_t *data = (uint8_t *) p;
data[3] = val; data[3] = val;
data[2] = val >> 8; data[2] = val >> 8;
data[1] = val >> 16; data[1] = val >> 16;
data[0] = val >> 24; data[0] = val >> 24;
} }

View File

@ -37,47 +37,47 @@ using namespace toolkit;
namespace mediakit{ namespace mediakit{
MultiCastAddressMaker &MultiCastAddressMaker::Instance() { MultiCastAddressMaker &MultiCastAddressMaker::Instance() {
static MultiCastAddressMaker instance; static MultiCastAddressMaker instance;
return instance; return instance;
} }
static uint32_t addressToInt(const string &ip){ static uint32_t addressToInt(const string &ip){
struct in_addr addr; struct in_addr addr;
bzero(&addr,sizeof(addr)); bzero(&addr,sizeof(addr));
addr.s_addr = inet_addr(ip.data()); addr.s_addr = inet_addr(ip.data());
return (uint32_t)ntohl((uint32_t &)addr.s_addr); return (uint32_t)ntohl((uint32_t &)addr.s_addr);
} }
std::shared_ptr<uint32_t> MultiCastAddressMaker::obtain(uint32_t iTry) { std::shared_ptr<uint32_t> MultiCastAddressMaker::obtain(uint32_t iTry) {
lock_guard<recursive_mutex> lck(_mtx); lock_guard<recursive_mutex> lck(_mtx);
GET_CONFIG(string,addrMinStr,MultiCast::kAddrMin); GET_CONFIG(string,addrMinStr,MultiCast::kAddrMin);
GET_CONFIG(string,addrMaxStr,MultiCast::kAddrMax); GET_CONFIG(string,addrMaxStr,MultiCast::kAddrMax);
uint32_t addrMin = addressToInt(addrMinStr); uint32_t addrMin = addressToInt(addrMinStr);
uint32_t addrMax = addressToInt(addrMaxStr); uint32_t addrMax = addressToInt(addrMaxStr);
if(_iAddr > addrMax || _iAddr == 0){ if(_iAddr > addrMax || _iAddr == 0){
_iAddr = addrMin; _iAddr = addrMin;
} }
auto iGotAddr = _iAddr++; auto iGotAddr = _iAddr++;
if(_setBadAddr.find(iGotAddr) != _setBadAddr.end()){ if(_setBadAddr.find(iGotAddr) != _setBadAddr.end()){
//已经分配过了 //已经分配过了
if(iTry){ if(iTry){
return obtain(--iTry); return obtain(--iTry);
} }
//分配完了,应该不可能到这里 //分配完了,应该不可能到这里
ErrorL; ErrorL;
return nullptr; return nullptr;
} }
_setBadAddr.emplace(iGotAddr); _setBadAddr.emplace(iGotAddr);
std::shared_ptr<uint32_t> ret(new uint32_t(iGotAddr),[](uint32_t *ptr){ std::shared_ptr<uint32_t> ret(new uint32_t(iGotAddr),[](uint32_t *ptr){
MultiCastAddressMaker::Instance().release(*ptr); MultiCastAddressMaker::Instance().release(*ptr);
delete ptr; delete ptr;
}); });
return ret; return ret;
} }
void MultiCastAddressMaker::release(uint32_t iAddr){ void MultiCastAddressMaker::release(uint32_t iAddr){
lock_guard<recursive_mutex> lck(_mtx); lock_guard<recursive_mutex> lck(_mtx);
_setBadAddr.erase(iAddr); _setBadAddr.erase(iAddr);
} }
@ -85,106 +85,106 @@ recursive_mutex RtpMultiCaster::g_mtx;
unordered_map<string, weak_ptr<RtpMultiCaster> > RtpMultiCaster::g_mapBroadCaster; unordered_map<string, weak_ptr<RtpMultiCaster> > RtpMultiCaster::g_mapBroadCaster;
void RtpMultiCaster::setDetachCB(void* listener, const onDetach& cb) { void RtpMultiCaster::setDetachCB(void* listener, const onDetach& cb) {
lock_guard<recursive_mutex> lck(_mtx); lock_guard<recursive_mutex> lck(_mtx);
if(cb){ if(cb){
_mapDetach.emplace(listener,cb); _mapDetach.emplace(listener,cb);
}else{ }else{
_mapDetach.erase(listener); _mapDetach.erase(listener);
} }
} }
RtpMultiCaster::~RtpMultiCaster() { RtpMultiCaster::~RtpMultiCaster() {
_pReader->setReadCB(nullptr); _pReader->setReadCB(nullptr);
_pReader->setDetachCB(nullptr); _pReader->setDetachCB(nullptr);
DebugL; DebugL;
} }
RtpMultiCaster::RtpMultiCaster(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream) { RtpMultiCaster::RtpMultiCaster(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream) {
auto src = dynamic_pointer_cast<RtspMediaSource>(MediaSource::find(RTSP_SCHEMA,strVhost,strApp, strStream)); auto src = dynamic_pointer_cast<RtspMediaSource>(MediaSource::find(RTSP_SCHEMA,strVhost,strApp, strStream));
if(!src){ if(!src){
auto strErr = StrPrinter << "未找到媒体源:" << strVhost << " " << strApp << " " << strStream << endl; auto strErr = StrPrinter << "未找到媒体源:" << strVhost << " " << strApp << " " << strStream << endl;
throw std::runtime_error(strErr); throw std::runtime_error(strErr);
} }
_multiAddr = MultiCastAddressMaker::Instance().obtain(); _multiAddr = MultiCastAddressMaker::Instance().obtain();
for(auto i = 0; i < 2; i++){ for(auto i = 0; i < 2; i++){
_apUdpSock[i].reset(new Socket(poller)); _apUdpSock[i].reset(new Socket(poller));
if(!_apUdpSock[i]->bindUdpSock(0, strLocalIp.data())){ if(!_apUdpSock[i]->bindUdpSock(0, strLocalIp.data())){
auto strErr = StrPrinter << "绑定UDP端口失败:" << strLocalIp << endl; auto strErr = StrPrinter << "绑定UDP端口失败:" << strLocalIp << endl;
throw std::runtime_error(strErr); throw std::runtime_error(strErr);
} }
auto fd = _apUdpSock[i]->rawFD(); auto fd = _apUdpSock[i]->rawFD();
GET_CONFIG(uint32_t,udpTTL,MultiCast::kUdpTTL); GET_CONFIG(uint32_t,udpTTL,MultiCast::kUdpTTL);
SockUtil::setMultiTTL(fd, udpTTL); SockUtil::setMultiTTL(fd, udpTTL);
SockUtil::setMultiLOOP(fd, false); SockUtil::setMultiLOOP(fd, false);
SockUtil::setMultiIF(fd, strLocalIp.data()); SockUtil::setMultiIF(fd, strLocalIp.data());
struct sockaddr_in &peerAddr = _aPeerUdpAddr[i]; struct sockaddr_in &peerAddr = _aPeerUdpAddr[i];
peerAddr.sin_family = AF_INET; peerAddr.sin_family = AF_INET;
peerAddr.sin_port = htons(_apUdpSock[i]->get_local_port()); peerAddr.sin_port = htons(_apUdpSock[i]->get_local_port());
peerAddr.sin_addr.s_addr = htonl(*_multiAddr); peerAddr.sin_addr.s_addr = htonl(*_multiAddr);
bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero); bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero);
_apUdpSock[i]->setSendPeerAddr((struct sockaddr *)&peerAddr); _apUdpSock[i]->setSendPeerAddr((struct sockaddr *)&peerAddr);
} }
_pReader = src->getRing()->attach(poller); _pReader = src->getRing()->attach(poller);
_pReader->setReadCB([this](const RtpPacket::Ptr &pkt){ _pReader->setReadCB([this](const RtpPacket::Ptr &pkt){
int i = (int)(pkt->type); int i = (int)(pkt->type);
auto &pSock = _apUdpSock[i]; auto &pSock = _apUdpSock[i];
auto &peerAddr = _aPeerUdpAddr[i]; auto &peerAddr = _aPeerUdpAddr[i];
BufferRtp::Ptr buffer(new BufferRtp(pkt,4)); BufferRtp::Ptr buffer(new BufferRtp(pkt,4));
pSock->send(buffer); pSock->send(buffer);
}); });
_pReader->setDetachCB([this](){ _pReader->setDetachCB([this](){
unordered_map<void * , onDetach > _mapDetach_copy; unordered_map<void * , onDetach > _mapDetach_copy;
{ {
lock_guard<recursive_mutex> lck(_mtx); lock_guard<recursive_mutex> lck(_mtx);
_mapDetach_copy = std::move(_mapDetach); _mapDetach_copy = std::move(_mapDetach);
} }
for(auto &pr : _mapDetach_copy){ for(auto &pr : _mapDetach_copy){
pr.second(); pr.second();
} }
}); });
DebugL << MultiCastAddressMaker::toString(*_multiAddr) << " " DebugL << MultiCastAddressMaker::toString(*_multiAddr) << " "
<< _apUdpSock[0]->get_local_port() << " " << _apUdpSock[0]->get_local_port() << " "
<< _apUdpSock[1]->get_local_port() << " " << _apUdpSock[1]->get_local_port() << " "
<< strVhost << " " << strVhost << " "
<< strApp << " " << strStream; << strApp << " " << strStream;
} }
uint16_t RtpMultiCaster::getPort(TrackType trackType){ uint16_t RtpMultiCaster::getPort(TrackType trackType){
return _apUdpSock[trackType]->get_local_port(); return _apUdpSock[trackType]->get_local_port();
} }
string RtpMultiCaster::getIP(){ string RtpMultiCaster::getIP(){
return inet_ntoa(_aPeerUdpAddr[0].sin_addr); return inet_ntoa(_aPeerUdpAddr[0].sin_addr);
} }
RtpMultiCaster::Ptr RtpMultiCaster::make(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream){ RtpMultiCaster::Ptr RtpMultiCaster::make(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream){
try{ try{
auto ret = Ptr(new RtpMultiCaster(poller,strLocalIp,strVhost,strApp,strStream),[poller](RtpMultiCaster *ptr){ auto ret = Ptr(new RtpMultiCaster(poller,strLocalIp,strVhost,strApp,strStream),[poller](RtpMultiCaster *ptr){
poller->async([ptr]() { poller->async([ptr]() {
delete ptr; delete ptr;
}); });
}); });
lock_guard<recursive_mutex> lck(g_mtx); lock_guard<recursive_mutex> lck(g_mtx);
string strKey = StrPrinter << strLocalIp << " " << strVhost << " " << strApp << " " << strStream << endl; string strKey = StrPrinter << strLocalIp << " " << strVhost << " " << strApp << " " << strStream << endl;
weak_ptr<RtpMultiCaster> weakPtr = ret; weak_ptr<RtpMultiCaster> weakPtr = ret;
g_mapBroadCaster.emplace(strKey,weakPtr); g_mapBroadCaster.emplace(strKey,weakPtr);
return ret; return ret;
}catch (std::exception &ex) { }catch (std::exception &ex) {
WarnL << ex.what(); WarnL << ex.what();
return nullptr; return nullptr;
} }
} }
RtpMultiCaster::Ptr RtpMultiCaster::get(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream) { RtpMultiCaster::Ptr RtpMultiCaster::get(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream) {
string strKey = StrPrinter << strLocalIp << " " << strVhost << " " << strApp << " " << strStream << endl; string strKey = StrPrinter << strLocalIp << " " << strVhost << " " << strApp << " " << strStream << endl;
lock_guard<recursive_mutex> lck(g_mtx); lock_guard<recursive_mutex> lck(g_mtx);
auto it = g_mapBroadCaster.find(strKey); auto it = g_mapBroadCaster.find(strKey);
if (it == g_mapBroadCaster.end()) { if (it == g_mapBroadCaster.end()) {
return make(poller,strLocalIp,strVhost,strApp, strStream); return make(poller,strLocalIp,strVhost,strApp, strStream);
} }
auto ret = it->second.lock(); auto ret = it->second.lock();
if (!ret) { if (!ret) {
g_mapBroadCaster.erase(it); g_mapBroadCaster.erase(it);
return make(poller,strLocalIp,strVhost,strApp, strStream); return make(poller,strLocalIp,strVhost,strApp, strStream);
} }
return ret; return ret;
} }

View File

@ -45,48 +45,48 @@ namespace mediakit{
class MultiCastAddressMaker class MultiCastAddressMaker
{ {
public: public:
static MultiCastAddressMaker &Instance(); static MultiCastAddressMaker &Instance();
static bool isMultiCastAddress(uint32_t iAddr){ static bool isMultiCastAddress(uint32_t iAddr){
static uint32_t addrMin = mINI::Instance()[MultiCast::kAddrMin].as<uint32_t>(); static uint32_t addrMin = mINI::Instance()[MultiCast::kAddrMin].as<uint32_t>();
static uint32_t addrMax = mINI::Instance()[MultiCast::kAddrMax].as<uint32_t>(); static uint32_t addrMax = mINI::Instance()[MultiCast::kAddrMax].as<uint32_t>();
return iAddr >= addrMin && iAddr <= addrMax; return iAddr >= addrMin && iAddr <= addrMax;
} }
static string toString(uint32_t iAddr){ static string toString(uint32_t iAddr){
iAddr = htonl(iAddr); iAddr = htonl(iAddr);
return ::inet_ntoa((struct in_addr &)(iAddr)); return ::inet_ntoa((struct in_addr &)(iAddr));
} }
virtual ~MultiCastAddressMaker(){} virtual ~MultiCastAddressMaker(){}
std::shared_ptr<uint32_t> obtain(uint32_t iTry = 10); std::shared_ptr<uint32_t> obtain(uint32_t iTry = 10);
private: private:
MultiCastAddressMaker(){}; MultiCastAddressMaker(){};
void release(uint32_t iAddr); void release(uint32_t iAddr);
uint32_t _iAddr = 0; uint32_t _iAddr = 0;
recursive_mutex _mtx; recursive_mutex _mtx;
unordered_set<uint32_t> _setBadAddr; unordered_set<uint32_t> _setBadAddr;
}; };
class RtpMultiCaster { class RtpMultiCaster {
public: public:
typedef std::shared_ptr<RtpMultiCaster> Ptr; typedef std::shared_ptr<RtpMultiCaster> Ptr;
typedef function<void()> onDetach; typedef function<void()> onDetach;
virtual ~RtpMultiCaster(); virtual ~RtpMultiCaster();
static Ptr get(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream); static Ptr get(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream);
void setDetachCB(void *listener,const onDetach &cb); void setDetachCB(void *listener,const onDetach &cb);
uint16_t getPort(TrackType trackType); uint16_t getPort(TrackType trackType);
string getIP(); string getIP();
private: private:
static recursive_mutex g_mtx; static recursive_mutex g_mtx;
static unordered_map<string , weak_ptr<RtpMultiCaster> > g_mapBroadCaster; static unordered_map<string , weak_ptr<RtpMultiCaster> > g_mapBroadCaster;
static Ptr make(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream); static Ptr make(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream);
std::shared_ptr<uint32_t> _multiAddr; std::shared_ptr<uint32_t> _multiAddr;
recursive_mutex _mtx; recursive_mutex _mtx;
unordered_map<void * , onDetach > _mapDetach; unordered_map<void * , onDetach > _mapDetach;
RtspMediaSource::RingType::RingReader::Ptr _pReader; RtspMediaSource::RingType::RingReader::Ptr _pReader;
Socket::Ptr _apUdpSock[2]; Socket::Ptr _apUdpSock[2];
struct sockaddr_in _aPeerUdpAddr[2]; struct sockaddr_in _aPeerUdpAddr[2];
RtpMultiCaster(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream); RtpMultiCaster(const EventPoller::Ptr &poller,const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream);
}; };

View File

@ -28,9 +28,9 @@
#include "RtpReceiver.h" #include "RtpReceiver.h"
#define POP_HEAD(trackidx) \ #define POP_HEAD(trackidx) \
auto it = _rtp_sort_cache_map[trackidx].begin(); \ auto it = _rtp_sort_cache_map[trackidx].begin(); \
onRtpSorted(it->second, trackidx); \ onRtpSorted(it->second, trackidx); \
_rtp_sort_cache_map[trackidx].erase(it); _rtp_sort_cache_map[trackidx].erase(it);
#define AV_RB16(x) \ #define AV_RB16(x) \
((((const uint8_t*)(x))[0] << 8) | \ ((((const uint8_t*)(x))[0] << 8) | \

View File

@ -31,176 +31,176 @@
namespace mediakit{ namespace mediakit{
static void getAttrSdp(const map<string, string> &attr, _StrPrinter &printer){ static void getAttrSdp(const map<string, string> &attr, _StrPrinter &printer){
const map<string, string>::value_type *ptr = nullptr; const map<string, string>::value_type *ptr = nullptr;
for(auto &pr : attr){ for(auto &pr : attr){
if(pr.first == "control"){ if(pr.first == "control"){
ptr = &pr; ptr = &pr;
continue; continue;
} }
if(pr.second.empty()){ if(pr.second.empty()){
printer << "a=" << pr.first << "\r\n"; printer << "a=" << pr.first << "\r\n";
}else{ }else{
printer << "a=" << pr.first << ":" << pr.second << "\r\n"; printer << "a=" << pr.first << ":" << pr.second << "\r\n";
} }
} }
if(ptr){ if(ptr){
printer << "a=" << ptr->first << ":" << ptr->second << "\r\n"; printer << "a=" << ptr->first << ":" << ptr->second << "\r\n";
} }
} }
string SdpTrack::toString() const { string SdpTrack::toString() const {
_StrPrinter _printer; _StrPrinter _printer;
switch (_type){ switch (_type){
case TrackTitle:{ case TrackTitle:{
_printer << "v=" << 0 << "\r\n"; _printer << "v=" << 0 << "\r\n";
if(!_o.empty()){ if(!_o.empty()){
_printer << "o="<< _o << "\r\n"; _printer << "o="<< _o << "\r\n";
} }
if(!_c.empty()){ if(!_c.empty()){
_printer << "c=" << _c << "\r\n"; _printer << "c=" << _c << "\r\n";
} }
if(!_t.empty()){ if(!_t.empty()){
_printer << "t=" << _t << "\r\n"; _printer << "t=" << _t << "\r\n";
} }
_printer << "s=RTSP Session, streamed by the ZLMediaKit\r\n"; _printer << "s=RTSP Session, streamed by the ZLMediaKit\r\n";
_printer << "i=ZLMediaKit Live Stream\r\n"; _printer << "i=ZLMediaKit Live Stream\r\n";
getAttrSdp(_attr,_printer); getAttrSdp(_attr,_printer);
} }
break; break;
case TrackAudio: case TrackAudio:
case TrackVideo:{ case TrackVideo:{
if(_type == TrackAudio){ if(_type == TrackAudio){
_printer << "m=audio 0 RTP/AVP " << _pt << "\r\n"; _printer << "m=audio 0 RTP/AVP " << _pt << "\r\n";
}else{ }else{
_printer << "m=video 0 RTP/AVP " << _pt << "\r\n"; _printer << "m=video 0 RTP/AVP " << _pt << "\r\n";
} }
if(!_b.empty()){ if(!_b.empty()){
_printer << "b=" <<_b << "\r\n"; _printer << "b=" <<_b << "\r\n";
} }
getAttrSdp(_attr,_printer); getAttrSdp(_attr,_printer);
} }
break; break;
default: default:
break; break;
} }
return _printer; return _printer;
} }
static TrackType toTrackType(const string &str) { static TrackType toTrackType(const string &str) {
if (str == "") { if (str == "") {
return TrackTitle; return TrackTitle;
} }
if (str == "video") { if (str == "video") {
return TrackVideo; return TrackVideo;
} }
if (str == "audio") { if (str == "audio") {
return TrackAudio; return TrackAudio;
} }
return TrackInvalid; return TrackInvalid;
} }
void SdpParser::load(const string &sdp) { void SdpParser::load(const string &sdp) {
{ {
_track_vec.clear(); _track_vec.clear();
string key; string key;
SdpTrack::Ptr track = std::make_shared<SdpTrack>(); SdpTrack::Ptr track = std::make_shared<SdpTrack>();
auto lines = split(sdp, "\n"); auto lines = split(sdp, "\n");
for (auto &line : lines) { for (auto &line : lines) {
trim(line); trim(line);
if (line.size() < 2 || line[1] != '=') { if (line.size() < 2 || line[1] != '=') {
continue; continue;
} }
char opt = line[0]; char opt = line[0];
string opt_val = line.substr(2); string opt_val = line.substr(2);
switch (opt) { switch (opt) {
case 'o': case 'o':
track->_o = opt_val; track->_o = opt_val;
break; break;
case 's': case 's':
track->_s = opt_val; track->_s = opt_val;
break; break;
case 'i': case 'i':
track->_i = opt_val; track->_i = opt_val;
break; break;
case 'c': case 'c':
track->_c = opt_val; track->_c = opt_val;
break; break;
case 't': case 't':
track->_t = opt_val; track->_t = opt_val;
break; break;
case 'b': case 'b':
track->_b = opt_val; track->_b = opt_val;
break; break;
case 'm': { case 'm': {
track->_type = toTrackType(key); track->_type = toTrackType(key);
_track_vec.emplace_back(track); _track_vec.emplace_back(track);
track = std::make_shared<SdpTrack>(); track = std::make_shared<SdpTrack>();
key = FindField(opt_val.data(), nullptr, " "); key = FindField(opt_val.data(), nullptr, " ");
track->_m = opt_val; track->_m = opt_val;
} }
break; break;
case 'a': { case 'a': {
string attr = FindField(opt_val.data(), nullptr, ":"); string attr = FindField(opt_val.data(), nullptr, ":");
if (attr.empty()) { if (attr.empty()) {
track->_attr[opt_val] = ""; track->_attr[opt_val] = "";
} else { } else {
track->_attr[attr] = FindField(opt_val.data(), ":", nullptr); track->_attr[attr] = FindField(opt_val.data(), ":", nullptr);
} }
} }
break; break;
default: default:
track->_other[opt] = opt_val; track->_other[opt] = opt_val;
break; break;
} }
} }
track->_type = toTrackType(key); track->_type = toTrackType(key);
_track_vec.emplace_back(track); _track_vec.emplace_back(track);
} }
for (auto &track_ptr : _track_vec) { for (auto &track_ptr : _track_vec) {
auto &track = *track_ptr; auto &track = *track_ptr;
auto it = track._attr.find("range"); auto it = track._attr.find("range");
if (it != track._attr.end()) { if (it != track._attr.end()) {
char name[16] = {0}, start[16] = {0}, end[16] = {0}; char name[16] = {0}, start[16] = {0}, end[16] = {0};
int ret = sscanf(it->second.data(), "%15[^=]=%15[^-]-%15s", name, start, end); int ret = sscanf(it->second.data(), "%15[^=]=%15[^-]-%15s", name, start, end);
if (3 == ret || 2 == ret) { if (3 == ret || 2 == ret) {
if (strcmp(start, "now") == 0) { if (strcmp(start, "now") == 0) {
strcpy(start, "0"); strcpy(start, "0");
} }
track._start = atof(start); track._start = atof(start);
track._end = atof(end); track._end = atof(end);
track._duration = track._end - track._start; track._duration = track._end - track._start;
} }
} }
it = track._attr.find("rtpmap"); it = track._attr.find("rtpmap");
if(it != track._attr.end()){ if(it != track._attr.end()){
auto rtpmap = it->second; auto rtpmap = it->second;
int pt, samplerate; int pt, samplerate;
char codec[16] = {0}; char codec[16] = {0};
if (3 == sscanf(rtpmap.data(), "%d %15[^/]/%d", &pt, codec, &samplerate)) { if (3 == sscanf(rtpmap.data(), "%d %15[^/]/%d", &pt, codec, &samplerate)) {
track._pt = pt; track._pt = pt;
track._codec = codec; track._codec = codec;
track._samplerate = samplerate; track._samplerate = samplerate;
} }
} }
it = track._attr.find("fmtp"); it = track._attr.find("fmtp");
if(it != track._attr.end()) { if(it != track._attr.end()) {
track._fmtp = it->second; track._fmtp = it->second;
} }
it = track._attr.find("control"); it = track._attr.find("control");
if(it != track._attr.end()) { if(it != track._attr.end()) {
track._control = it->second; track._control = it->second;
auto surffix = string("/") + track._control; auto surffix = string("/") + track._control;
track._control_surffix = surffix.substr(1 + surffix.rfind('/')); track._control_surffix = surffix.substr(1 + surffix.rfind('/'));
} }
} }
} }
bool SdpParser::available() const { bool SdpParser::available() const {
@ -208,112 +208,112 @@ bool SdpParser::available() const {
} }
SdpTrack::Ptr SdpParser::getTrack(TrackType type) const { SdpTrack::Ptr SdpParser::getTrack(TrackType type) const {
for (auto &track : _track_vec){ for (auto &track : _track_vec){
if(track->_type == type){ if(track->_type == type){
return track; return track;
} }
} }
return nullptr; return nullptr;
} }
vector<SdpTrack::Ptr> SdpParser::getAvailableTrack() const { vector<SdpTrack::Ptr> SdpParser::getAvailableTrack() const {
vector<SdpTrack::Ptr> ret; vector<SdpTrack::Ptr> ret;
bool audio_added = false; bool audio_added = false;
bool video_added = false; bool video_added = false;
for (auto &track : _track_vec){ for (auto &track : _track_vec){
if(track->_type == TrackAudio ){ if(track->_type == TrackAudio ){
if(!audio_added){ if(!audio_added){
ret.emplace_back(track); ret.emplace_back(track);
audio_added = true; audio_added = true;
} }
continue; continue;
} }
if(track->_type == TrackVideo ){ if(track->_type == TrackVideo ){
if(!video_added){ if(!video_added){
ret.emplace_back(track); ret.emplace_back(track);
video_added = true; video_added = true;
} }
continue; continue;
} }
} }
return std::move(ret); return std::move(ret);
} }
string SdpParser::toString() const { string SdpParser::toString() const {
string title,audio,video; string title,audio,video;
for(auto &track : _track_vec){ for(auto &track : _track_vec){
switch (track->_type){ switch (track->_type){
case TrackTitle:{ case TrackTitle:{
title = track->toString(); title = track->toString();
} }
break; break;
case TrackVideo:{ case TrackVideo:{
video = track->toString(); video = track->toString();
} }
break; break;
case TrackAudio:{ case TrackAudio:{
audio = track->toString(); audio = track->toString();
} }
break; break;
default: default:
break; break;
} }
} }
return title + video + audio; return title + video + audio;
} }
bool RtspUrl::parse(const string &strUrl) { bool RtspUrl::parse(const string &strUrl) {
auto schema = FindField(strUrl.data(), nullptr, "://"); auto schema = FindField(strUrl.data(), nullptr, "://");
bool isSSL = strcasecmp(schema.data(), "rtsps") == 0; bool isSSL = strcasecmp(schema.data(), "rtsps") == 0;
//查找"://"与"/"之间的字符串,用于提取用户名密码 //查找"://"与"/"之间的字符串,用于提取用户名密码
auto middle_url = FindField(strUrl.data(), "://", "/"); auto middle_url = FindField(strUrl.data(), "://", "/");
if (middle_url.empty()) { if (middle_url.empty()) {
middle_url = FindField(strUrl.data(), "://", nullptr); middle_url = FindField(strUrl.data(), "://", nullptr);
} }
auto pos = middle_url.rfind('@'); auto pos = middle_url.rfind('@');
if (pos == string::npos) { if (pos == string::npos) {
//并没有用户名密码 //并没有用户名密码
return setup(isSSL, strUrl, "", ""); return setup(isSSL, strUrl, "", "");
} }
//包含用户名密码 //包含用户名密码
auto user_pwd = middle_url.substr(0, pos); auto user_pwd = middle_url.substr(0, pos);
auto suffix = strUrl.substr(schema.size() + 3 + pos + 1); auto suffix = strUrl.substr(schema.size() + 3 + pos + 1);
auto url = StrPrinter << "rtsp://" << suffix << endl; auto url = StrPrinter << "rtsp://" << suffix << endl;
if (user_pwd.find(":") == string::npos) { if (user_pwd.find(":") == string::npos) {
return setup(isSSL, url, user_pwd, ""); return setup(isSSL, url, user_pwd, "");
} }
auto user = FindField(user_pwd.data(), nullptr, ":"); auto user = FindField(user_pwd.data(), nullptr, ":");
auto pwd = FindField(user_pwd.data(), ":", nullptr); auto pwd = FindField(user_pwd.data(), ":", nullptr);
return setup(isSSL, url, user, pwd); return setup(isSSL, url, user, pwd);
} }
bool RtspUrl::setup(bool isSSL, const string &strUrl, const string &strUser, const string &strPwd) { bool RtspUrl::setup(bool isSSL, const string &strUrl, const string &strUser, const string &strPwd) {
auto ip = FindField(strUrl.data(), "://", "/"); auto ip = FindField(strUrl.data(), "://", "/");
if (ip.empty()) { if (ip.empty()) {
ip = split(FindField(strUrl.data(), "://", NULL), "?")[0]; ip = split(FindField(strUrl.data(), "://", NULL), "?")[0];
} }
auto port = atoi(FindField(ip.data(), ":", NULL).data()); auto port = atoi(FindField(ip.data(), ":", NULL).data());
if (port <= 0 || port > UINT16_MAX) { if (port <= 0 || port > UINT16_MAX) {
//rtsp 默认端口554 //rtsp 默认端口554
port = isSSL ? 322 : 554; port = isSSL ? 322 : 554;
} else { } else {
//服务器域名 //服务器域名
ip = FindField(ip.data(), NULL, ":"); ip = FindField(ip.data(), NULL, ":");
} }
if (ip.empty()) { if (ip.empty()) {
return false; return false;
} }
_url = std::move(strUrl); _url = std::move(strUrl);
_user = std::move(strUser); _user = std::move(strUser);
_passwd = std::move(strPwd); _passwd = std::move(strPwd);
_host = std::move(ip); _host = std::move(ip);
_port = port; _port = port;
_is_ssl = isSSL; _is_ssl = isSSL;
return true; return true;
} }
}//namespace mediakit }//namespace mediakit

View File

@ -42,87 +42,87 @@ namespace mediakit {
namespace Rtsp { namespace Rtsp {
typedef enum { typedef enum {
RTP_Invalid = -1, RTP_Invalid = -1,
RTP_TCP = 0, RTP_TCP = 0,
RTP_UDP = 1, RTP_UDP = 1,
RTP_MULTICAST = 2, RTP_MULTICAST = 2,
} eRtpType; } eRtpType;
}; };
class RtpPacket : public BufferRaw{ class RtpPacket : public BufferRaw{
public: public:
typedef std::shared_ptr<RtpPacket> Ptr; typedef std::shared_ptr<RtpPacket> Ptr;
uint8_t interleaved; uint8_t interleaved;
uint8_t PT; uint8_t PT;
bool mark; bool mark;
//时间戳,单位毫秒 //时间戳,单位毫秒
uint32_t timeStamp; uint32_t timeStamp;
uint16_t sequence; uint16_t sequence;
uint32_t ssrc; uint32_t ssrc;
uint32_t offset; uint32_t offset;
TrackType type; TrackType type;
}; };
class RtcpCounter { class RtcpCounter {
public: public:
uint32_t pktCnt = 0; uint32_t pktCnt = 0;
uint32_t octCount = 0; uint32_t octCount = 0;
//网络字节序 //网络字节序
uint32_t timeStamp = 0; uint32_t timeStamp = 0;
uint32_t lastTimeStamp = 0; uint32_t lastTimeStamp = 0;
}; };
class SdpTrack { class SdpTrack {
public: public:
typedef std::shared_ptr<SdpTrack> Ptr; typedef std::shared_ptr<SdpTrack> Ptr;
string _m; string _m;
string _o; string _o;
string _s; string _s;
string _i; string _i;
string _c; string _c;
string _t; string _t;
string _b; string _b;
float _duration = 0; float _duration = 0;
float _start = 0; float _start = 0;
float _end = 0; float _end = 0;
map<char, string> _other; map<char, string> _other;
map<string, string> _attr; map<string, string> _attr;
string toString() const; string toString() const;
public: public:
int _pt; int _pt;
string _codec; string _codec;
int _samplerate; int _samplerate;
string _fmtp; string _fmtp;
string _control; string _control;
string _control_surffix; string _control_surffix;
TrackType _type; TrackType _type;
public: public:
uint8_t _interleaved = 0; uint8_t _interleaved = 0;
bool _inited = false; bool _inited = false;
uint32_t _ssrc = 0; uint32_t _ssrc = 0;
uint16_t _seq = 0; uint16_t _seq = 0;
//时间戳,单位毫秒 //时间戳,单位毫秒
uint32_t _time_stamp = 0; uint32_t _time_stamp = 0;
}; };
class SdpParser { class SdpParser {
public: public:
typedef std::shared_ptr<SdpParser> Ptr; typedef std::shared_ptr<SdpParser> Ptr;
SdpParser() {} SdpParser() {}
SdpParser(const string &sdp) { load(sdp); } SdpParser(const string &sdp) { load(sdp); }
~SdpParser() {} ~SdpParser() {}
void load(const string &sdp); void load(const string &sdp);
bool available() const; bool available() const;
SdpTrack::Ptr getTrack(TrackType type) const; SdpTrack::Ptr getTrack(TrackType type) const;
vector<SdpTrack::Ptr> getAvailableTrack() const; vector<SdpTrack::Ptr> getAvailableTrack() const;
string toString() const ; string toString() const ;
private: private:
vector<SdpTrack::Ptr> _track_vec; vector<SdpTrack::Ptr> _track_vec;
}; };
/** /**
@ -130,18 +130,18 @@ private:
*/ */
class RtspUrl{ class RtspUrl{
public: public:
string _url; string _url;
string _user; string _user;
string _passwd; string _passwd;
string _host; string _host;
uint16_t _port; uint16_t _port;
bool _is_ssl; bool _is_ssl;
public: public:
RtspUrl() = default; RtspUrl() = default;
~RtspUrl() = default; ~RtspUrl() = default;
bool parse(const string &url); bool parse(const string &url);
private: private:
bool setup(bool,const string &, const string &, const string &); bool setup(bool,const string &, const string &, const string &);
}; };
/** /**
@ -149,44 +149,44 @@ private:
*/ */
class Sdp : public CodecInfo{ class Sdp : public CodecInfo{
public: public:
typedef std::shared_ptr<Sdp> Ptr; typedef std::shared_ptr<Sdp> Ptr;
/** /**
* sdp * sdp
* @param sample_rate * @param sample_rate
* @param playload_type pt类型 * @param playload_type pt类型
*/ */
Sdp(uint32_t sample_rate, uint8_t playload_type){ Sdp(uint32_t sample_rate, uint8_t playload_type){
_sample_rate = sample_rate; _sample_rate = sample_rate;
_playload_type = playload_type; _playload_type = playload_type;
} }
virtual ~Sdp(){} virtual ~Sdp(){}
/** /**
* sdp字符串 * sdp字符串
* @return * @return
*/ */
virtual string getSdp() const = 0; virtual string getSdp() const = 0;
/** /**
* pt * pt
* @return * @return
*/ */
uint8_t getPlayloadType() const{ uint8_t getPlayloadType() const{
return _playload_type; return _playload_type;
} }
/** /**
* *
* @return * @return
*/ */
uint32_t getSampleRate() const{ uint32_t getSampleRate() const{
return _sample_rate; return _sample_rate;
} }
private: private:
uint8_t _playload_type; uint8_t _playload_type;
uint32_t _sample_rate; uint32_t _sample_rate;
}; };
/** /**
@ -195,56 +195,56 @@ private:
class TitleSdp : public Sdp{ class TitleSdp : public Sdp{
public: public:
/** /**
* title类型sdp * title类型sdp
* @param dur_sec rtsp点播时长0 * @param dur_sec rtsp点播时长0
* @param header sdp描述 * @param header sdp描述
* @param version sdp版本 * @param version sdp版本
*/ */
TitleSdp(float dur_sec = 0, TitleSdp(float dur_sec = 0,
const map<string,string> &header = map<string,string>(), const map<string,string> &header = map<string,string>(),
int version = 0) : Sdp(0,0){ int version = 0) : Sdp(0,0){
_printer << "v=" << version << "\r\n"; _printer << "v=" << version << "\r\n";
if(!header.empty()){ if(!header.empty()){
for (auto &pr : header){ for (auto &pr : header){
_printer << pr.first << "=" << pr.second << "\r\n"; _printer << pr.first << "=" << pr.second << "\r\n";
} }
} else { } else {
_printer << "o=- 1383190487994921 1 IN IP4 0.0.0.0\r\n"; _printer << "o=- 1383190487994921 1 IN IP4 0.0.0.0\r\n";
_printer << "s=RTSP Session, streamed by the ZLMediaKit\r\n"; _printer << "s=RTSP Session, streamed by the ZLMediaKit\r\n";
_printer << "i=ZLMediaKit Live Stream\r\n"; _printer << "i=ZLMediaKit Live Stream\r\n";
_printer << "c=IN IP4 0.0.0.0\r\n"; _printer << "c=IN IP4 0.0.0.0\r\n";
_printer << "t=0 0\r\n"; _printer << "t=0 0\r\n";
} }
if(dur_sec <= 0){ if(dur_sec <= 0){
_printer << "a=range:npt=0-\r\n"; _printer << "a=range:npt=0-\r\n";
}else{ }else{
_printer << "a=range:npt=0-" << dur_sec << "\r\n"; _printer << "a=range:npt=0-" << dur_sec << "\r\n";
} }
_printer << "a=control:*\r\n"; _printer << "a=control:*\r\n";
} }
string getSdp() const override { string getSdp() const override {
return _printer; return _printer;
} }
/** /**
* *
* @return * @return
*/ */
TrackType getTrackType() const override { TrackType getTrackType() const override {
return TrackTitle; return TrackTitle;
} }
/** /**
* id * id
* @return * @return
*/ */
CodecId getCodecId() const override{ CodecId getCodecId() const override{
return CodecInvalid; return CodecInvalid;
} }
private: private:
_StrPrinter _printer; _StrPrinter _printer;
}; };
} //namespace mediakit } //namespace mediakit

View File

@ -35,83 +35,83 @@ using namespace std;
namespace mediakit { namespace mediakit {
void RtspDemuxer::loadSdp(const string &sdp){ void RtspDemuxer::loadSdp(const string &sdp){
loadSdp(SdpParser(sdp)); loadSdp(SdpParser(sdp));
} }
void RtspDemuxer::loadSdp(const SdpParser &attr) { void RtspDemuxer::loadSdp(const SdpParser &attr) {
auto tracks = attr.getAvailableTrack(); auto tracks = attr.getAvailableTrack();
for (auto &track : tracks){ for (auto &track : tracks){
switch (track->_type) { switch (track->_type) {
case TrackVideo: { case TrackVideo: {
makeVideoTrack(track); makeVideoTrack(track);
} }
break; break;
case TrackAudio: { case TrackAudio: {
makeAudioTrack(track); makeAudioTrack(track);
} }
break; break;
default: default:
break; break;
} }
} }
auto titleTrack = attr.getTrack(TrackTitle); auto titleTrack = attr.getTrack(TrackTitle);
if(titleTrack){ if(titleTrack){
_fDuration = titleTrack->_duration; _fDuration = titleTrack->_duration;
} }
} }
bool RtspDemuxer::inputRtp(const RtpPacket::Ptr & rtp) { bool RtspDemuxer::inputRtp(const RtpPacket::Ptr & rtp) {
switch (rtp->type) { switch (rtp->type) {
case TrackVideo:{ case TrackVideo:{
if(_videoRtpDecoder){ if(_videoRtpDecoder){
return _videoRtpDecoder->inputRtp(rtp, true); return _videoRtpDecoder->inputRtp(rtp, true);
} }
return false; return false;
} }
case TrackAudio:{ case TrackAudio:{
if(_audioRtpDecoder){ if(_audioRtpDecoder){
_audioRtpDecoder->inputRtp(rtp, false); _audioRtpDecoder->inputRtp(rtp, false);
return false; return false;
} }
return false; return false;
} }
default: default:
return false; return false;
} }
} }
void RtspDemuxer::makeAudioTrack(const SdpTrack::Ptr &audio) { void RtspDemuxer::makeAudioTrack(const SdpTrack::Ptr &audio) {
//生成Track对象 //生成Track对象
_audioTrack = dynamic_pointer_cast<AudioTrack>(Factory::getTrackBySdp(audio)); _audioTrack = dynamic_pointer_cast<AudioTrack>(Factory::getTrackBySdp(audio));
if(_audioTrack){ if(_audioTrack){
//生成RtpCodec对象以便解码rtp //生成RtpCodec对象以便解码rtp
_audioRtpDecoder = Factory::getRtpDecoderByTrack(_audioTrack); _audioRtpDecoder = Factory::getRtpDecoderByTrack(_audioTrack);
if(_audioRtpDecoder){ if(_audioRtpDecoder){
//设置rtp解码器代理生成的frame写入该Track //设置rtp解码器代理生成的frame写入该Track
_audioRtpDecoder->addDelegate(_audioTrack); _audioRtpDecoder->addDelegate(_audioTrack);
onAddTrack(_audioTrack); onAddTrack(_audioTrack);
} else{ } else{
//找不到相应的rtp解码器该track无效 //找不到相应的rtp解码器该track无效
_audioTrack.reset(); _audioTrack.reset();
} }
} }
} }
void RtspDemuxer::makeVideoTrack(const SdpTrack::Ptr &video) { void RtspDemuxer::makeVideoTrack(const SdpTrack::Ptr &video) {
//生成Track对象 //生成Track对象
_videoTrack = dynamic_pointer_cast<VideoTrack>(Factory::getTrackBySdp(video)); _videoTrack = dynamic_pointer_cast<VideoTrack>(Factory::getTrackBySdp(video));
if(_videoTrack){ if(_videoTrack){
//生成RtpCodec对象以便解码rtp //生成RtpCodec对象以便解码rtp
_videoRtpDecoder = Factory::getRtpDecoderByTrack(_videoTrack); _videoRtpDecoder = Factory::getRtpDecoderByTrack(_videoTrack);
if(_videoRtpDecoder){ if(_videoRtpDecoder){
//设置rtp解码器代理生成的frame写入该Track //设置rtp解码器代理生成的frame写入该Track
_videoRtpDecoder->addDelegate(_videoTrack); _videoRtpDecoder->addDelegate(_videoTrack);
onAddTrack(_videoTrack); onAddTrack(_videoTrack);
}else{ }else{
//找不到相应的rtp解码器该track无效 //找不到相应的rtp解码器该track无效
_videoTrack.reset(); _videoTrack.reset();
} }
} }
} }
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -39,8 +39,8 @@ namespace mediakit {
class RtspDemuxer : public Demuxer{ class RtspDemuxer : public Demuxer{
public: public:
typedef std::shared_ptr<RtspDemuxer> Ptr; typedef std::shared_ptr<RtspDemuxer> Ptr;
RtspDemuxer() = default; RtspDemuxer() = default;
virtual ~RtspDemuxer() = default; virtual ~RtspDemuxer() = default;
/** /**
@ -48,19 +48,19 @@ public:
*/ */
void loadSdp(const string &sdp); void loadSdp(const string &sdp);
/** /**
* *
* @param rtp rtp包 * @param rtp rtp包
* @return true i帧第一个rtp包 * @return true i帧第一个rtp包
*/ */
bool inputRtp(const RtpPacket::Ptr &rtp); bool inputRtp(const RtpPacket::Ptr &rtp);
private: private:
void makeAudioTrack(const SdpTrack::Ptr &audio); void makeAudioTrack(const SdpTrack::Ptr &audio);
void makeVideoTrack(const SdpTrack::Ptr &video); void makeVideoTrack(const SdpTrack::Ptr &video);
void loadSdp(const SdpParser &parser); void loadSdp(const SdpParser &parser);
private: private:
RtpCodec::Ptr _audioRtpDecoder; RtpCodec::Ptr _audioRtpDecoder;
RtpCodec::Ptr _videoRtpDecoder; RtpCodec::Ptr _videoRtpDecoder;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -56,177 +56,177 @@ namespace mediakit {
*/ */
class RtspMediaSource : public MediaSource, public RingDelegate<RtpPacket::Ptr> { class RtspMediaSource : public MediaSource, public RingDelegate<RtpPacket::Ptr> {
public: public:
typedef ResourcePool<RtpPacket> PoolType; typedef ResourcePool<RtpPacket> PoolType;
typedef std::shared_ptr<RtspMediaSource> Ptr; typedef std::shared_ptr<RtspMediaSource> Ptr;
typedef RingBuffer<RtpPacket::Ptr> RingType; typedef RingBuffer<RtpPacket::Ptr> RingType;
/** /**
* *
* @param vhost * @param vhost
* @param app * @param app
* @param stream_id id * @param stream_id id
* @param ring_size 0 * @param ring_size 0
*/ */
RtspMediaSource(const string &vhost, RtspMediaSource(const string &vhost,
const string &app, const string &app,
const string &stream_id, const string &stream_id,
int ring_size = RTP_GOP_SIZE) : int ring_size = RTP_GOP_SIZE) :
MediaSource(RTSP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {} MediaSource(RTSP_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {}
virtual ~RtspMediaSource() {} virtual ~RtspMediaSource() {}
/** /**
* *
*/ */
const RingType::Ptr &getRing() const { const RingType::Ptr &getRing() const {
return _ring; return _ring;
} }
/** /**
* *
*/ */
int readerCount() override { int readerCount() override {
return _ring ? _ring->readerCount() : 0; return _ring ? _ring->readerCount() : 0;
} }
/** /**
* sdp * sdp
*/ */
const string &getSdp() const { const string &getSdp() const {
return _sdp; return _sdp;
} }
/** /**
* ssrc * ssrc
*/ */
virtual uint32_t getSsrc(TrackType trackType) { virtual uint32_t getSsrc(TrackType trackType) {
auto track = _sdp_parser.getTrack(trackType); auto track = _sdp_parser.getTrack(trackType);
if (!track) { if (!track) {
return 0; return 0;
} }
return track->_ssrc; return track->_ssrc;
} }
/** /**
* seqence * seqence
*/ */
virtual uint16_t getSeqence(TrackType trackType) { virtual uint16_t getSeqence(TrackType trackType) {
auto track = _sdp_parser.getTrack(trackType); auto track = _sdp_parser.getTrack(trackType);
if (!track) { if (!track) {
return 0; return 0;
} }
return track->_seq; return track->_seq;
} }
/** /**
* *
*/ */
uint32_t getTimeStamp(TrackType trackType) override { uint32_t getTimeStamp(TrackType trackType) override {
auto track = _sdp_parser.getTrack(trackType); auto track = _sdp_parser.getTrack(trackType);
if (track) { if (track) {
return track->_time_stamp; return track->_time_stamp;
} }
auto tracks = _sdp_parser.getAvailableTrack(); auto tracks = _sdp_parser.getAvailableTrack();
switch (tracks.size()) { switch (tracks.size()) {
case 0: case 0:
return 0; return 0;
case 1: case 1:
return tracks[0]->_time_stamp; return tracks[0]->_time_stamp;
default: default:
return MAX(tracks[0]->_time_stamp, tracks[1]->_time_stamp); return MAX(tracks[0]->_time_stamp, tracks[1]->_time_stamp);
} }
} }
/** /**
* *
*/ */
void setTimeStamp(uint32_t uiStamp) override { void setTimeStamp(uint32_t uiStamp) override {
auto tracks = _sdp_parser.getAvailableTrack(); auto tracks = _sdp_parser.getAvailableTrack();
for (auto &track : tracks) { for (auto &track : tracks) {
track->_time_stamp = uiStamp; track->_time_stamp = uiStamp;
} }
} }
/** /**
* sdp * sdp
*/ */
virtual void setSdp(const string &sdp) { virtual void setSdp(const string &sdp) {
_sdp = sdp; _sdp = sdp;
_sdp_parser.load(sdp); _sdp_parser.load(sdp);
_have_video = (bool)_sdp_parser.getTrack(TrackVideo); _have_video = (bool)_sdp_parser.getTrack(TrackVideo);
if (_ring) { if (_ring) {
regist(); regist();
} }
} }
/** /**
* rtp * rtp
* @param rtp rtp包 * @param rtp rtp包
* @param keyPos * @param keyPos
*/ */
void onWrite(const RtpPacket::Ptr &rtp, bool keyPos) override { void onWrite(const RtpPacket::Ptr &rtp, bool keyPos) override {
auto track = _sdp_parser.getTrack(rtp->type); auto track = _sdp_parser.getTrack(rtp->type);
if (track) { if (track) {
track->_seq = rtp->sequence; track->_seq = rtp->sequence;
track->_time_stamp = rtp->timeStamp; track->_time_stamp = rtp->timeStamp;
track->_ssrc = rtp->ssrc; track->_ssrc = rtp->ssrc;
} }
if (!_ring) { if (!_ring) {
weak_ptr<RtspMediaSource> weakSelf = dynamic_pointer_cast<RtspMediaSource>(shared_from_this()); weak_ptr<RtspMediaSource> weakSelf = dynamic_pointer_cast<RtspMediaSource>(shared_from_this());
auto lam = [weakSelf](const EventPoller::Ptr &, int size, bool) { auto lam = [weakSelf](const EventPoller::Ptr &, int size, bool) {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if (!strongSelf) { if (!strongSelf) {
return; return;
} }
strongSelf->onReaderChanged(size); strongSelf->onReaderChanged(size);
}; };
//rtp包缓存最大允许2048个大概最多3MB数据 //rtp包缓存最大允许2048个大概最多3MB数据
//但是这个是GOP缓存的上限值真实的GOP缓存大小等于两个I帧之间的包数的两倍 //但是这个是GOP缓存的上限值真实的GOP缓存大小等于两个I帧之间的包数的两倍
//而且每次遇到I帧则会清空GOP缓存所以真实的GOP缓存远小于此值 //而且每次遇到I帧则会清空GOP缓存所以真实的GOP缓存远小于此值
_ring = std::make_shared<RingType>(_ring_size, std::move(lam)); _ring = std::make_shared<RingType>(_ring_size, std::move(lam));
onReaderChanged(0); onReaderChanged(0);
if (!_sdp.empty()) { if (!_sdp.empty()) {
regist(); regist();
} }
} }
//不存在视频为了减少缓存延时那么关闭GOP缓存 //不存在视频为了减少缓存延时那么关闭GOP缓存
_ring->write(rtp, _have_video ? keyPos : true); _ring->write(rtp, _have_video ? keyPos : true);
checkNoneReader(); checkNoneReader();
} }
private: private:
/** /**
* *
*/ */
void onReaderChanged(int size) { void onReaderChanged(int size) {
//我们记录最后一次活动时间 //我们记录最后一次活动时间
_reader_changed_ticker.resetTime(); _reader_changed_ticker.resetTime();
if (size != 0 || totalReaderCount() != 0) { if (size != 0 || totalReaderCount() != 0) {
//还有消费者正在观看该流 //还有消费者正在观看该流
_async_emit_none_reader = false; _async_emit_none_reader = false;
return; return;
} }
_async_emit_none_reader = true; _async_emit_none_reader = true;
} }
/** /**
* *
* onNoneReader事件 * onNoneReader事件
*/ */
void checkNoneReader() { void checkNoneReader() {
GET_CONFIG(int, stream_none_reader_delay, General::kStreamNoneReaderDelayMS); GET_CONFIG(int, stream_none_reader_delay, General::kStreamNoneReaderDelayMS);
if (_async_emit_none_reader && _reader_changed_ticker.elapsedTime() > stream_none_reader_delay) { if (_async_emit_none_reader && _reader_changed_ticker.elapsedTime() > stream_none_reader_delay) {
_async_emit_none_reader = false; _async_emit_none_reader = false;
onNoneReader(); onNoneReader();
} }
} }
protected: protected:
int _ring_size; int _ring_size;
bool _async_emit_none_reader = false; bool _async_emit_none_reader = false;
bool _have_video = false; bool _have_video = false;
Ticker _reader_changed_ticker; Ticker _reader_changed_ticker;
SdpParser _sdp_parser; SdpParser _sdp_parser;
string _sdp; string _sdp;
RingType::Ptr _ring; RingType::Ptr _ring;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -39,12 +39,12 @@ public:
typedef std::shared_ptr<RtspMediaSourceImp> Ptr; typedef std::shared_ptr<RtspMediaSourceImp> Ptr;
/** /**
* *
* @param vhost * @param vhost
* @param app * @param app
* @param id id * @param id id
* @param ringSize * @param ringSize
*/ */
RtspMediaSourceImp(const string &vhost, const string &app, const string &id, int ringSize = RTP_GOP_SIZE) : RtspMediaSource(vhost, app, id,ringSize) { RtspMediaSourceImp(const string &vhost, const string &app, const string &id, int ringSize = RTP_GOP_SIZE) : RtspMediaSource(vhost, app, id,ringSize) {
_demuxer = std::make_shared<RtspDemuxer>(); _demuxer = std::make_shared<RtspDemuxer>();
_demuxer->setTrackListener(this); _demuxer->setTrackListener(this);
@ -69,9 +69,9 @@ public:
} }
/** /**
* *
* @param listener * @param listener
*/ */
void setListener(const std::weak_ptr<MediaSourceEvent> &listener) override { void setListener(const std::weak_ptr<MediaSourceEvent> &listener) override {
RtspMediaSource::setListener(listener); RtspMediaSource::setListener(listener);
if(_muxer){ if(_muxer){
@ -87,11 +87,11 @@ public:
} }
/** /**
* *
* @param enableRtmp rtmp * @param enableRtmp rtmp
* @param enableHls hls * @param enableHls hls
* @param enableMP4 mp4录制 * @param enableMP4 mp4录制
*/ */
void setProtocolTranslation(bool enableRtmp,bool enableHls,bool enableMP4){ void setProtocolTranslation(bool enableRtmp,bool enableHls,bool enableMP4){
//不重复生成rtsp //不重复生成rtsp
_muxer = std::make_shared<MultiMediaSourceMuxer>(getVhost(), getApp(), getId(), _demuxer->getDuration(), false, enableRtmp, enableHls, enableMP4); _muxer = std::make_shared<MultiMediaSourceMuxer>(getVhost(), getApp(), getId(), _demuxer->getDuration(), false, enableRtmp, enableHls, enableMP4);
@ -104,8 +104,8 @@ public:
} }
/** /**
* _demuxer触发的添加Track事件 * _demuxer触发的添加Track事件
*/ */
void onAddTrack(const Track::Ptr &track) override { void onAddTrack(const Track::Ptr &track) override {
if(_muxer){ if(_muxer){
_muxer->addTrack(track); _muxer->addTrack(track);

View File

@ -43,29 +43,29 @@ using namespace mediakit::Client;
namespace mediakit { namespace mediakit {
enum PlayType { enum PlayType {
type_play = 0, type_play = 0,
type_pause, type_pause,
type_seek type_seek
}; };
RtspPlayer::RtspPlayer(const EventPoller::Ptr &poller) : TcpClient(poller){ RtspPlayer::RtspPlayer(const EventPoller::Ptr &poller) : TcpClient(poller){
RtpReceiver::setPoolSize(64); RtpReceiver::setPoolSize(64);
} }
RtspPlayer::~RtspPlayer(void) { RtspPlayer::~RtspPlayer(void) {
DebugL << endl; DebugL << endl;
} }
void RtspPlayer::teardown(){ void RtspPlayer::teardown(){
if (alive()) { if (alive()) {
sendRtspRequest("TEARDOWN" ,_strContentBase); sendRtspRequest("TEARDOWN" ,_strContentBase);
shutdown(SockException(Err_shutdown,"teardown")); shutdown(SockException(Err_shutdown,"teardown"));
} }
_rtspMd5Nonce.clear(); _rtspMd5Nonce.clear();
_rtspRealm.clear(); _rtspRealm.clear();
_aTrackInfo.clear(); _aTrackInfo.clear();
_strSession.clear(); _strSession.clear();
_strContentBase.clear(); _strContentBase.clear();
RtpReceiver::clear(); RtpReceiver::clear();
CLEAR_ARR(_apRtpSock); CLEAR_ARR(_apRtpSock);
CLEAR_ARR(_apRtcpSock); CLEAR_ARR(_apRtcpSock);
@ -74,65 +74,65 @@ void RtspPlayer::teardown(){
CLEAR_ARR(_aui64RtpRecv) CLEAR_ARR(_aui64RtpRecv)
CLEAR_ARR(_aui16NowSeq) CLEAR_ARR(_aui16NowSeq)
_pPlayTimer.reset(); _pPlayTimer.reset();
_pRtpTimer.reset(); _pRtpTimer.reset();
_uiCseq = 1; _uiCseq = 1;
_onHandshake = nullptr; _onHandshake = nullptr;
} }
void RtspPlayer::play(const string &strUrl){ void RtspPlayer::play(const string &strUrl){
RtspUrl url; RtspUrl url;
if(!url.parse(strUrl)){ if(!url.parse(strUrl)){
onPlayResult_l(SockException(Err_other,StrPrinter << "illegal rtsp url:" << strUrl),false); onPlayResult_l(SockException(Err_other,StrPrinter << "illegal rtsp url:" << strUrl),false);
return; return;
} }
teardown(); teardown();
if (url._user.size()) { if (url._user.size()) {
(*this)[kRtspUser] = url._user; (*this)[kRtspUser] = url._user;
} }
if (url._passwd.size()) { if (url._passwd.size()) {
(*this)[kRtspPwd] = url._passwd; (*this)[kRtspPwd] = url._passwd;
(*this)[kRtspPwdIsMD5] = false; (*this)[kRtspPwdIsMD5] = false;
} }
_strUrl = url._url; _strUrl = url._url;
_eType = (Rtsp::eRtpType)(int)(*this)[kRtpType]; _eType = (Rtsp::eRtpType)(int)(*this)[kRtpType];
DebugL << url._url << " " << (url._user.size() ? url._user : "null") << " " << (url._passwd.size() ? url._passwd : "null") << " " << _eType; DebugL << url._url << " " << (url._user.size() ? url._user : "null") << " " << (url._passwd.size() ? url._passwd : "null") << " " << _eType;
weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this()); weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
float playTimeOutSec = (*this)[kTimeoutMS].as<int>() / 1000.0; float playTimeOutSec = (*this)[kTimeoutMS].as<int>() / 1000.0;
_pPlayTimer.reset( new Timer(playTimeOutSec, [weakSelf]() { _pPlayTimer.reset( new Timer(playTimeOutSec, [weakSelf]() {
auto strongSelf=weakSelf.lock(); auto strongSelf=weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return false; return false;
} }
strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtsp timeout"),false); strongSelf->onPlayResult_l(SockException(Err_timeout,"play rtsp timeout"),false);
return false; return false;
},getPoller())); },getPoller()));
if(!(*this)[kNetAdapter].empty()){ if(!(*this)[kNetAdapter].empty()){
setNetAdapter((*this)[kNetAdapter]); setNetAdapter((*this)[kNetAdapter]);
} }
startConnect(url._host, url._port, playTimeOutSec); startConnect(url._host, url._port, playTimeOutSec);
} }
void RtspPlayer::onConnect(const SockException &err){ void RtspPlayer::onConnect(const SockException &err){
if(err.getErrCode() != Err_success) { if(err.getErrCode() != Err_success) {
onPlayResult_l(err,false); onPlayResult_l(err,false);
return; return;
} }
sendDescribe(); sendDescribe();
} }
void RtspPlayer::onRecv(const Buffer::Ptr& pBuf) { void RtspPlayer::onRecv(const Buffer::Ptr& pBuf) {
input(pBuf->data(),pBuf->size()); input(pBuf->data(),pBuf->size());
} }
void RtspPlayer::onErr(const SockException &ex) { void RtspPlayer::onErr(const SockException &ex) {
//定时器_pPlayTimer为空后表明握手结束了 //定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l(ex,!_pPlayTimer); onPlayResult_l(ex,!_pPlayTimer);
} }
// from live555 // from live555
bool RtspPlayer::handleAuthenticationFailure(const string &paramsStr) { bool RtspPlayer::handleAuthenticationFailure(const string &paramsStr) {
@ -167,25 +167,25 @@ bool RtspPlayer::handleAuthenticationFailure(const string &paramsStr) {
return false; return false;
} }
void RtspPlayer::handleResDESCRIBE(const Parser& parser) { void RtspPlayer::handleResDESCRIBE(const Parser& parser) {
string authInfo = parser["WWW-Authenticate"]; string authInfo = parser["WWW-Authenticate"];
//发送DESCRIBE命令后的回复 //发送DESCRIBE命令后的回复
if ((parser.Url() == "401") && handleAuthenticationFailure(authInfo)) { if ((parser.Url() == "401") && handleAuthenticationFailure(authInfo)) {
sendDescribe(); sendDescribe();
return; return;
} }
if(parser.Url() == "302" || parser.Url() == "301"){ if(parser.Url() == "302" || parser.Url() == "301"){
auto newUrl = parser["Location"]; auto newUrl = parser["Location"];
if(newUrl.empty()){ if(newUrl.empty()){
throw std::runtime_error("未找到Location字段(跳转url)"); throw std::runtime_error("未找到Location字段(跳转url)");
} }
play(newUrl); play(newUrl);
return; return;
} }
if (parser.Url() != "200") { if (parser.Url() != "200") {
throw std::runtime_error( throw std::runtime_error(
StrPrinter << "DESCRIBE:" << parser.Url() << " " << parser.Tail() << endl); StrPrinter << "DESCRIBE:" << parser.Url() << " " << parser.Tail() << endl);
} }
_strContentBase = parser["Content-Base"]; _strContentBase = parser["Content-Base"];
if(_strContentBase.empty()){ if(_strContentBase.empty()){
_strContentBase = _strUrl; _strContentBase = _strUrl;
@ -194,58 +194,58 @@ void RtspPlayer::handleResDESCRIBE(const Parser& parser) {
_strContentBase.pop_back(); _strContentBase.pop_back();
} }
SdpParser sdpParser(parser.Content()); SdpParser sdpParser(parser.Content());
//解析sdp //解析sdp
_aTrackInfo = sdpParser.getAvailableTrack(); _aTrackInfo = sdpParser.getAvailableTrack();
auto title = sdpParser.getTrack(TrackTitle); auto title = sdpParser.getTrack(TrackTitle);
bool isPlayback = false; bool isPlayback = false;
if(title && title->_duration ){ if(title && title->_duration ){
isPlayback = true; isPlayback = true;
} }
for(auto &stamp : _stamp){ for(auto &stamp : _stamp){
stamp.setPlayBack(isPlayback); stamp.setPlayBack(isPlayback);
stamp.setRelativeStamp(0); stamp.setRelativeStamp(0);
} }
if (_aTrackInfo.empty()) { if (_aTrackInfo.empty()) {
throw std::runtime_error("无有效的Sdp Track"); throw std::runtime_error("无有效的Sdp Track");
} }
if (!onCheckSDP(sdpParser.toString())) { if (!onCheckSDP(sdpParser.toString())) {
throw std::runtime_error("onCheckSDP faied"); throw std::runtime_error("onCheckSDP faied");
} }
sendSetup(0); sendSetup(0);
} }
//有必要的情况下创建udp端口 //有必要的情况下创建udp端口
void RtspPlayer::createUdpSockIfNecessary(int track_idx){ void RtspPlayer::createUdpSockIfNecessary(int track_idx){
auto &rtpSockRef = _apRtpSock[track_idx]; auto &rtpSockRef = _apRtpSock[track_idx];
auto &rtcpSockRef = _apRtcpSock[track_idx]; auto &rtcpSockRef = _apRtcpSock[track_idx];
if(!rtpSockRef){ if(!rtpSockRef){
rtpSockRef.reset(new Socket(getPoller())); rtpSockRef.reset(new Socket(getPoller()));
//rtp随机端口 //rtp随机端口
if (!rtpSockRef->bindUdpSock(0, get_local_ip().data())) { if (!rtpSockRef->bindUdpSock(0, get_local_ip().data())) {
rtpSockRef.reset(); rtpSockRef.reset();
throw std::runtime_error("open rtp sock failed"); throw std::runtime_error("open rtp sock failed");
} }
} }
if(!rtcpSockRef){ if(!rtcpSockRef){
rtcpSockRef.reset(new Socket(getPoller())); rtcpSockRef.reset(new Socket(getPoller()));
//rtcp端口为rtp端口+1目的是为了兼容某些服务器其实更推荐随机端口 //rtcp端口为rtp端口+1目的是为了兼容某些服务器其实更推荐随机端口
if (!rtcpSockRef->bindUdpSock(rtpSockRef->get_local_port() + 1, get_local_ip().data())) { if (!rtcpSockRef->bindUdpSock(rtpSockRef->get_local_port() + 1, get_local_ip().data())) {
rtcpSockRef.reset(); rtcpSockRef.reset();
throw std::runtime_error("open rtcp sock failed"); throw std::runtime_error("open rtcp sock failed");
} }
} }
if(rtpSockRef->get_local_port() % 2 != 0){ if(rtpSockRef->get_local_port() % 2 != 0){
//如果rtp端口不是偶数那么与rtcp端口互换目的是兼容一些要求严格的服务器 //如果rtp端口不是偶数那么与rtcp端口互换目的是兼容一些要求严格的服务器
Socket::Ptr tmp = rtpSockRef; Socket::Ptr tmp = rtpSockRef;
rtpSockRef = rtcpSockRef; rtpSockRef = rtcpSockRef;
rtcpSockRef = tmp; rtcpSockRef = tmp;
} }
} }
@ -253,91 +253,91 @@ void RtspPlayer::createUdpSockIfNecessary(int track_idx){
void RtspPlayer::sendSetup(unsigned int trackIndex) { void RtspPlayer::sendSetup(unsigned int trackIndex) {
_onHandshake = std::bind(&RtspPlayer::handleResSETUP,this, placeholders::_1,trackIndex); _onHandshake = std::bind(&RtspPlayer::handleResSETUP,this, placeholders::_1,trackIndex);
auto &track = _aTrackInfo[trackIndex]; auto &track = _aTrackInfo[trackIndex];
auto baseUrl = _strContentBase + "/" + track->_control_surffix; auto baseUrl = _strContentBase + "/" + track->_control_surffix;
switch (_eType) { switch (_eType) {
case Rtsp::RTP_TCP: { case Rtsp::RTP_TCP: {
sendRtspRequest("SETUP",baseUrl,{"Transport",StrPrinter << "RTP/AVP/TCP;unicast;interleaved=" << track->_type * 2 << "-" << track->_type * 2 + 1}); sendRtspRequest("SETUP",baseUrl,{"Transport",StrPrinter << "RTP/AVP/TCP;unicast;interleaved=" << track->_type * 2 << "-" << track->_type * 2 + 1});
} }
break; break;
case Rtsp::RTP_MULTICAST: { case Rtsp::RTP_MULTICAST: {
sendRtspRequest("SETUP",baseUrl,{"Transport","Transport: RTP/AVP;multicast"}); sendRtspRequest("SETUP",baseUrl,{"Transport","Transport: RTP/AVP;multicast"});
} }
break; break;
case Rtsp::RTP_UDP: { case Rtsp::RTP_UDP: {
createUdpSockIfNecessary(trackIndex); createUdpSockIfNecessary(trackIndex);
sendRtspRequest("SETUP",baseUrl,{"Transport", sendRtspRequest("SETUP",baseUrl,{"Transport",
StrPrinter << "RTP/AVP;unicast;client_port=" StrPrinter << "RTP/AVP;unicast;client_port="
<< _apRtpSock[trackIndex]->get_local_port() << "-" << _apRtpSock[trackIndex]->get_local_port() << "-"
<< _apRtcpSock[trackIndex]->get_local_port()}); << _apRtcpSock[trackIndex]->get_local_port()});
} }
break; break;
default: default:
break; break;
} }
} }
void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex) { void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex) {
if (parser.Url() != "200") { if (parser.Url() != "200") {
throw std::runtime_error( throw std::runtime_error(
StrPrinter << "SETUP:" << parser.Url() << " " << parser.Tail() << endl); StrPrinter << "SETUP:" << parser.Url() << " " << parser.Tail() << endl);
} }
if (uiTrackIndex == 0) { if (uiTrackIndex == 0) {
_strSession = parser["Session"]; _strSession = parser["Session"];
_strSession.append(";"); _strSession.append(";");
_strSession = FindField(_strSession.data(), nullptr, ";"); _strSession = FindField(_strSession.data(), nullptr, ";");
} }
auto strTransport = parser["Transport"]; auto strTransport = parser["Transport"];
if(strTransport.find("TCP") != string::npos || strTransport.find("interleaved") != string::npos){ if(strTransport.find("TCP") != string::npos || strTransport.find("interleaved") != string::npos){
_eType = Rtsp::RTP_TCP; _eType = Rtsp::RTP_TCP;
}else if(strTransport.find("multicast") != string::npos){ }else if(strTransport.find("multicast") != string::npos){
_eType = Rtsp::RTP_MULTICAST; _eType = Rtsp::RTP_MULTICAST;
}else{ }else{
_eType = Rtsp::RTP_UDP; _eType = Rtsp::RTP_UDP;
} }
RtspSplitter::enableRecvRtp(_eType == Rtsp::RTP_TCP); RtspSplitter::enableRecvRtp(_eType == Rtsp::RTP_TCP);
if(_eType == Rtsp::RTP_TCP) { if(_eType == Rtsp::RTP_TCP) {
string interleaved = FindField( FindField((strTransport + ";").data(), "interleaved=", ";").data(), NULL, "-"); string interleaved = FindField( FindField((strTransport + ";").data(), "interleaved=", ";").data(), NULL, "-");
_aTrackInfo[uiTrackIndex]->_interleaved = atoi(interleaved.data()); _aTrackInfo[uiTrackIndex]->_interleaved = atoi(interleaved.data());
}else{ }else{
const char *strPos = (_eType == Rtsp::RTP_MULTICAST ? "port=" : "server_port=") ; const char *strPos = (_eType == Rtsp::RTP_MULTICAST ? "port=" : "server_port=") ;
auto port_str = FindField((strTransport + ";").data(), strPos, ";"); auto port_str = FindField((strTransport + ";").data(), strPos, ";");
uint16_t rtp_port = atoi(FindField(port_str.data(), NULL, "-").data()); uint16_t rtp_port = atoi(FindField(port_str.data(), NULL, "-").data());
uint16_t rtcp_port = atoi(FindField(port_str.data(), "-",NULL).data()); uint16_t rtcp_port = atoi(FindField(port_str.data(), "-",NULL).data());
auto &pRtpSockRef = _apRtpSock[uiTrackIndex]; auto &pRtpSockRef = _apRtpSock[uiTrackIndex];
auto &pRtcpSockRef = _apRtcpSock[uiTrackIndex]; auto &pRtcpSockRef = _apRtcpSock[uiTrackIndex];
if (_eType == Rtsp::RTP_MULTICAST) { if (_eType == Rtsp::RTP_MULTICAST) {
//udp组播 //udp组播
auto multiAddr = FindField((strTransport + ";").data(), "destination=", ";"); auto multiAddr = FindField((strTransport + ";").data(), "destination=", ";");
pRtpSockRef.reset(new Socket(getPoller())); pRtpSockRef.reset(new Socket(getPoller()));
if (!pRtpSockRef->bindUdpSock(rtp_port, multiAddr.data())) { if (!pRtpSockRef->bindUdpSock(rtp_port, multiAddr.data())) {
pRtpSockRef.reset(); pRtpSockRef.reset();
throw std::runtime_error("open udp sock err"); throw std::runtime_error("open udp sock err");
} }
auto fd = pRtpSockRef->rawFD(); auto fd = pRtpSockRef->rawFD();
if (-1 == SockUtil::joinMultiAddrFilter(fd, multiAddr.data(), get_peer_ip().data(),get_local_ip().data())) { if (-1 == SockUtil::joinMultiAddrFilter(fd, multiAddr.data(), get_peer_ip().data(),get_local_ip().data())) {
SockUtil::joinMultiAddr(fd, multiAddr.data(),get_local_ip().data()); SockUtil::joinMultiAddr(fd, multiAddr.data(),get_local_ip().data());
} }
} else { } else {
createUdpSockIfNecessary(uiTrackIndex); createUdpSockIfNecessary(uiTrackIndex);
//udp单播 //udp单播
struct sockaddr_in rtpto; struct sockaddr_in rtpto;
rtpto.sin_port = ntohs(rtp_port); rtpto.sin_port = ntohs(rtp_port);
rtpto.sin_family = AF_INET; rtpto.sin_family = AF_INET;
rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data()); rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data());
pRtpSockRef->setSendPeerAddr((struct sockaddr *)&(rtpto)); pRtpSockRef->setSendPeerAddr((struct sockaddr *)&(rtpto));
//发送rtp打洞包 //发送rtp打洞包
pRtpSockRef->send("\xce\xfa\xed\xfe", 4); pRtpSockRef->send("\xce\xfa\xed\xfe", 4);
//设置rtcp发送目标为后续发送rtcp做准备 //设置rtcp发送目标为后续发送rtcp做准备
rtpto.sin_port = ntohs(rtcp_port); rtpto.sin_port = ntohs(rtcp_port);
rtpto.sin_family = AF_INET; rtpto.sin_family = AF_INET;
rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data()); rtpto.sin_addr.s_addr = inet_addr(get_peer_ip().data());
pRtcpSockRef->setSendPeerAddr((struct sockaddr *)&(rtpto)); pRtcpSockRef->setSendPeerAddr((struct sockaddr *)&(rtpto));
} }
auto srcIP = inet_addr(get_peer_ip().data()); auto srcIP = inet_addr(get_peer_ip().data());
weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this()); weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
@ -368,98 +368,98 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex)
strongSelf->onRtcpPacket(uiTrackIndex, strongSelf->_aTrackInfo[uiTrackIndex], (unsigned char *) buf->data(), buf->size()); strongSelf->onRtcpPacket(uiTrackIndex, strongSelf->_aTrackInfo[uiTrackIndex], (unsigned char *) buf->data(), buf->size());
}); });
} }
} }
if (uiTrackIndex < _aTrackInfo.size() - 1) { if (uiTrackIndex < _aTrackInfo.size() - 1) {
//需要继续发送SETUP命令 //需要继续发送SETUP命令
sendSetup(uiTrackIndex + 1); sendSetup(uiTrackIndex + 1);
return; return;
} }
//所有setup命令发送完毕 //所有setup命令发送完毕
//发送play命令 //发送play命令
sendPause(type_play, 0); sendPause(type_play, 0);
} }
void RtspPlayer::sendDescribe() { void RtspPlayer::sendDescribe() {
//发送DESCRIBE命令后处理函数:handleResDESCRIBE //发送DESCRIBE命令后处理函数:handleResDESCRIBE
_onHandshake = std::bind(&RtspPlayer::handleResDESCRIBE,this, placeholders::_1); _onHandshake = std::bind(&RtspPlayer::handleResDESCRIBE,this, placeholders::_1);
sendRtspRequest("DESCRIBE",_strUrl,{"Accept","application/sdp"}); sendRtspRequest("DESCRIBE",_strUrl,{"Accept","application/sdp"});
} }
void RtspPlayer::sendPause(int type , uint32_t seekMS){ void RtspPlayer::sendPause(int type , uint32_t seekMS){
_onHandshake = std::bind(&RtspPlayer::handleResPAUSE,this, placeholders::_1,type); _onHandshake = std::bind(&RtspPlayer::handleResPAUSE,this, placeholders::_1,type);
//开启或暂停rtsp //开启或暂停rtsp
switch (type){ switch (type){
case type_pause: case type_pause:
sendRtspRequest("PAUSE", _strContentBase); sendRtspRequest("PAUSE", _strContentBase);
break; break;
case type_play: case type_play:
sendRtspRequest("PLAY", _strContentBase); sendRtspRequest("PLAY", _strContentBase);
break; break;
case type_seek: case type_seek:
sendRtspRequest("PLAY", _strContentBase, {"Range",StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << seekMS / 1000.0 << "-"}); sendRtspRequest("PLAY", _strContentBase, {"Range",StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << seekMS / 1000.0 << "-"});
break; break;
default: default:
WarnL << "unknown type : " << type; WarnL << "unknown type : " << type;
_onHandshake = nullptr; _onHandshake = nullptr;
break; break;
} }
} }
void RtspPlayer::pause(bool bPause) { void RtspPlayer::pause(bool bPause) {
sendPause(bPause ? type_pause : type_seek, getProgressMilliSecond()); sendPause(bPause ? type_pause : type_seek, getProgressMilliSecond());
} }
void RtspPlayer::handleResPAUSE(const Parser& parser,int type) { void RtspPlayer::handleResPAUSE(const Parser& parser,int type) {
if (parser.Url() != "200") { if (parser.Url() != "200") {
switch (type) { switch (type) {
case type_pause: case type_pause:
WarnL << "Pause failed:" << parser.Url() << " " << parser.Tail() << endl; WarnL << "Pause failed:" << parser.Url() << " " << parser.Tail() << endl;
break; break;
case type_play: case type_play:
WarnL << "Play failed:" << parser.Url() << " " << parser.Tail() << endl; WarnL << "Play failed:" << parser.Url() << " " << parser.Tail() << endl;
break; break;
case type_seek: case type_seek:
WarnL << "Seek failed:" << parser.Url() << " " << parser.Tail() << endl; WarnL << "Seek failed:" << parser.Url() << " " << parser.Tail() << endl;
break; break;
} }
return; return;
} }
if (type == type_pause) { if (type == type_pause) {
//暂停成功! //暂停成功!
_pRtpTimer.reset(); _pRtpTimer.reset();
return; return;
} }
//play或seek成功 //play或seek成功
uint32_t iSeekTo = 0; uint32_t iSeekTo = 0;
//修正时间轴 //修正时间轴
auto strRange = parser["Range"]; auto strRange = parser["Range"];
if (strRange.size()) { if (strRange.size()) {
auto strStart = FindField(strRange.data(), "npt=", "-"); auto strStart = FindField(strRange.data(), "npt=", "-");
if (strStart == "now") { if (strStart == "now") {
strStart = "0"; strStart = "0";
} }
iSeekTo = 1000 * atof(strStart.data()); iSeekTo = 1000 * atof(strStart.data());
DebugL << "seekTo(ms):" << iSeekTo; DebugL << "seekTo(ms):" << iSeekTo;
} }
//设置相对时间戳 //设置相对时间戳
_stamp[0].setRelativeStamp(iSeekTo); _stamp[0].setRelativeStamp(iSeekTo);
_stamp[1].setRelativeStamp(iSeekTo); _stamp[1].setRelativeStamp(iSeekTo);
onPlayResult_l(SockException(Err_success, type == type_seek ? "resum rtsp success" : "rtsp play success"), type == type_seek); onPlayResult_l(SockException(Err_success, type == type_seek ? "resum rtsp success" : "rtsp play success"), type == type_seek);
} }
void RtspPlayer::onWholeRtspPacket(Parser &parser) { void RtspPlayer::onWholeRtspPacket(Parser &parser) {
try { try {
decltype(_onHandshake) fun; decltype(_onHandshake) fun;
_onHandshake.swap(fun); _onHandshake.swap(fun);
if(fun){ if(fun){
fun(parser); fun(parser);
} }
parser.Clear(); parser.Clear();
} catch (std::exception &err) { } catch (std::exception &err) {
//定时器_pPlayTimer为空后表明握手结束了 //定时器_pPlayTimer为空后表明握手结束了
onPlayResult_l(SockException(Err_other, err.what()),!_pPlayTimer); onPlayResult_l(SockException(Err_other, err.what()),!_pPlayTimer);
} }
} }
@ -610,39 +610,39 @@ void RtspPlayer::sendReceiverReport(bool overTcp,int iTrackIndex){
void RtspPlayer::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx){ void RtspPlayer::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx){
//统计丢包率 //统计丢包率
if (_aui16FirstSeq[trackidx] == 0 || rtppt->sequence < _aui16FirstSeq[trackidx]) { if (_aui16FirstSeq[trackidx] == 0 || rtppt->sequence < _aui16FirstSeq[trackidx]) {
_aui16FirstSeq[trackidx] = rtppt->sequence; _aui16FirstSeq[trackidx] = rtppt->sequence;
_aui64RtpRecv[trackidx] = 0; _aui64RtpRecv[trackidx] = 0;
} }
_aui64RtpRecv[trackidx] ++; _aui64RtpRecv[trackidx] ++;
_aui16NowSeq[trackidx] = rtppt->sequence; _aui16NowSeq[trackidx] = rtppt->sequence;
//计算相对时间戳 //计算相对时间戳
int64_t dts_out; int64_t dts_out;
_stamp[trackidx].revise(rtppt->timeStamp,rtppt->timeStamp,dts_out,dts_out); _stamp[trackidx].revise(rtppt->timeStamp,rtppt->timeStamp,dts_out,dts_out);
rtppt->timeStamp = dts_out; rtppt->timeStamp = dts_out;
onRecvRTP_l(rtppt,_aTrackInfo[trackidx]); onRecvRTP_l(rtppt,_aTrackInfo[trackidx]);
} }
float RtspPlayer::getPacketLossRate(TrackType type) const{ float RtspPlayer::getPacketLossRate(TrackType type) const{
int iTrackIdx = getTrackIndexByTrackType(type); int iTrackIdx = getTrackIndexByTrackType(type);
if(iTrackIdx == -1){ if(iTrackIdx == -1){
uint64_t totalRecv = 0; uint64_t totalRecv = 0;
uint64_t totalSend = 0; uint64_t totalSend = 0;
for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
totalRecv += _aui64RtpRecv[i]; totalRecv += _aui64RtpRecv[i];
totalSend += (_aui16NowSeq[i] - _aui16FirstSeq[i] + 1); totalSend += (_aui16NowSeq[i] - _aui16FirstSeq[i] + 1);
} }
if(totalSend == 0){ if(totalSend == 0){
return 0; return 0;
} }
return 1.0 - (double)totalRecv / totalSend; return 1.0 - (double)totalRecv / totalSend;
} }
if(_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1 == 0){ if(_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1 == 0){
return 0; return 0;
} }
return 1.0 - (double)_aui64RtpRecv[iTrackIdx] / (_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1); return 1.0 - (double)_aui64RtpRecv[iTrackIdx] / (_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1);
} }
uint32_t RtspPlayer::getProgressMilliSecond() const{ uint32_t RtspPlayer::getProgressMilliSecond() const{
@ -653,70 +653,70 @@ void RtspPlayer::seekToMilliSecond(uint32_t ms) {
} }
void RtspPlayer::sendRtspRequest(const string &cmd, const string &url, const std::initializer_list<string> &header) { void RtspPlayer::sendRtspRequest(const string &cmd, const string &url, const std::initializer_list<string> &header) {
string key; string key;
StrCaseMap header_map; StrCaseMap header_map;
int i = 0; int i = 0;
for(auto &val : header){ for(auto &val : header){
if(++i % 2 == 0){ if(++i % 2 == 0){
header_map.emplace(key,val); header_map.emplace(key,val);
}else{ }else{
key = val; key = val;
} }
} }
sendRtspRequest(cmd,url,header_map); sendRtspRequest(cmd,url,header_map);
} }
void RtspPlayer::sendRtspRequest(const string &cmd, const string &url,const StrCaseMap &header_const) { void RtspPlayer::sendRtspRequest(const string &cmd, const string &url,const StrCaseMap &header_const) {
auto header = header_const; auto header = header_const;
header.emplace("CSeq",StrPrinter << _uiCseq++); header.emplace("CSeq",StrPrinter << _uiCseq++);
header.emplace("User-Agent",SERVER_NAME "(build in " __DATE__ " " __TIME__ ")"); header.emplace("User-Agent",SERVER_NAME "(build in " __DATE__ " " __TIME__ ")");
if(!_strSession.empty()){ if(!_strSession.empty()){
header.emplace("Session",_strSession); header.emplace("Session",_strSession);
} }
if(!_rtspRealm.empty() && !(*this)[kRtspUser].empty()){ if(!_rtspRealm.empty() && !(*this)[kRtspUser].empty()){
if(!_rtspMd5Nonce.empty()){ if(!_rtspMd5Nonce.empty()){
//MD5认证 //MD5认证
/* /*
response计算方法如下 response计算方法如下
RTSP客户端应该使用username + password并计算response如下: RTSP客户端应该使用username + password并计算response如下:
(1)password为MD5编码, (1)password为MD5编码,
response = md5( password:nonce:md5(public_method:url) ); response = md5( password:nonce:md5(public_method:url) );
(2)password为ANSI字符串, (2)password为ANSI字符串,
response= md5( md5(username:realm:password):nonce:md5(public_method:url) ); response= md5( md5(username:realm:password):nonce:md5(public_method:url) );
*/ */
string encrypted_pwd = (*this)[kRtspPwd]; string encrypted_pwd = (*this)[kRtspPwd];
if(!(*this)[kRtspPwdIsMD5].as<bool>()){ if(!(*this)[kRtspPwdIsMD5].as<bool>()){
encrypted_pwd = MD5((*this)[kRtspUser]+ ":" + _rtspRealm + ":" + encrypted_pwd).hexdigest(); encrypted_pwd = MD5((*this)[kRtspUser]+ ":" + _rtspRealm + ":" + encrypted_pwd).hexdigest();
} }
auto response = MD5( encrypted_pwd + ":" + _rtspMd5Nonce + ":" + MD5(cmd + ":" + url).hexdigest()).hexdigest(); auto response = MD5( encrypted_pwd + ":" + _rtspMd5Nonce + ":" + MD5(cmd + ":" + url).hexdigest()).hexdigest();
_StrPrinter printer; _StrPrinter printer;
printer << "Digest "; printer << "Digest ";
printer << "username=\"" << (*this)[kRtspUser] << "\", "; printer << "username=\"" << (*this)[kRtspUser] << "\", ";
printer << "realm=\"" << _rtspRealm << "\", "; printer << "realm=\"" << _rtspRealm << "\", ";
printer << "nonce=\"" << _rtspMd5Nonce << "\", "; printer << "nonce=\"" << _rtspMd5Nonce << "\", ";
printer << "uri=\"" << url << "\", "; printer << "uri=\"" << url << "\", ";
printer << "response=\"" << response << "\""; printer << "response=\"" << response << "\"";
header.emplace("Authorization",printer); header.emplace("Authorization",printer);
}else if(!(*this)[kRtspPwdIsMD5].as<bool>()){ }else if(!(*this)[kRtspPwdIsMD5].as<bool>()){
//base64认证 //base64认证
string authStr = StrPrinter << (*this)[kRtspUser] << ":" << (*this)[kRtspPwd]; string authStr = StrPrinter << (*this)[kRtspUser] << ":" << (*this)[kRtspPwd];
char authStrBase64[1024] = {0}; char authStrBase64[1024] = {0};
av_base64_encode(authStrBase64,sizeof(authStrBase64),(uint8_t *)authStr.data(),authStr.size()); av_base64_encode(authStrBase64,sizeof(authStrBase64),(uint8_t *)authStr.data(),authStr.size());
header.emplace("Authorization",StrPrinter << "Basic " << authStrBase64 ); header.emplace("Authorization",StrPrinter << "Basic " << authStrBase64 );
} }
} }
_StrPrinter printer; _StrPrinter printer;
printer << cmd << " " << url << " RTSP/1.0\r\n"; printer << cmd << " " << url << " RTSP/1.0\r\n";
for (auto &pr : header){ for (auto &pr : header){
printer << pr.first << ": " << pr.second << "\r\n"; printer << pr.first << ": " << pr.second << "\r\n";
} }
send(printer << "\r\n"); send(printer << "\r\n");
} }
void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &pkt, const SdpTrack::Ptr &track) { void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &pkt, const SdpTrack::Ptr &track) {
_rtpTicker.resetTime(); _rtpTicker.resetTime();
onRecvRTP(pkt,track); onRecvRTP(pkt,track);
int iTrackIndex = getTrackIndexByInterleaved(pkt->interleaved); int iTrackIndex = getTrackIndexByInterleaved(pkt->interleaved);
@ -740,22 +740,22 @@ void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &pkt, const SdpTrack::Ptr &tra
} }
void RtspPlayer::onPlayResult_l(const SockException &ex , bool handshakeCompleted) { void RtspPlayer::onPlayResult_l(const SockException &ex , bool handshakeCompleted) {
WarnL << ex.getErrCode() << " " << ex.what(); WarnL << ex.getErrCode() << " " << ex.what();
if(!ex){ if(!ex){
//播放成功恢复rtp接收超时定时器 //播放成功恢复rtp接收超时定时器
_rtpTicker.resetTime(); _rtpTicker.resetTime();
weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this()); weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
int timeoutMS = (*this)[kMediaTimeoutMS].as<int>(); int timeoutMS = (*this)[kMediaTimeoutMS].as<int>();
//创建rtp数据接收超时检测定时器 //创建rtp数据接收超时检测定时器
_pRtpTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() { _pRtpTimer.reset( new Timer(timeoutMS / 2000.0, [weakSelf,timeoutMS]() {
auto strongSelf=weakSelf.lock(); auto strongSelf=weakSelf.lock();
if(!strongSelf) { if(!strongSelf) {
return false; return false;
} }
if(strongSelf->_rtpTicker.elapsedTime()> timeoutMS) { if(strongSelf->_rtpTicker.elapsedTime()> timeoutMS) {
//接收rtp媒体数据包超时 //接收rtp媒体数据包超时
strongSelf->onPlayResult_l(SockException(Err_timeout,"receive rtp timeout"), true); strongSelf->onPlayResult_l(SockException(Err_timeout,"receive rtp timeout"), true);
return false; return false;
} }
return true; return true;
@ -780,27 +780,27 @@ void RtspPlayer::onPlayResult_l(const SockException &ex , bool handshakeComplete
} }
int RtspPlayer::getTrackIndexByInterleaved(int interleaved) const{ int RtspPlayer::getTrackIndexByInterleaved(int interleaved) const{
for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
if (_aTrackInfo[i]->_interleaved == interleaved) { if (_aTrackInfo[i]->_interleaved == interleaved) {
return i; return i;
} }
} }
if(_aTrackInfo.size() == 1){ if(_aTrackInfo.size() == 1){
return 0; return 0;
} }
return -1; return -1;
} }
int RtspPlayer::getTrackIndexByTrackType(TrackType trackType) const { int RtspPlayer::getTrackIndexByTrackType(TrackType trackType) const {
for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { for (unsigned int i = 0; i < _aTrackInfo.size(); i++) {
if (_aTrackInfo[i]->_type == trackType) { if (_aTrackInfo[i]->_type == trackType) {
return i; return i;
} }
} }
if(_aTrackInfo.size() == 1){ if(_aTrackInfo.size() == 1){
return 0; return 0;
} }
return -1; return -1;
} }
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -50,18 +50,18 @@ namespace mediakit {
//实现了rtsp播放器协议部分的功能及数据接收功能 //实现了rtsp播放器协议部分的功能及数据接收功能
class RtspPlayer: public PlayerBase,public TcpClient, public RtspSplitter, public RtpReceiver { class RtspPlayer: public PlayerBase,public TcpClient, public RtspSplitter, public RtpReceiver {
public: public:
typedef std::shared_ptr<RtspPlayer> Ptr; typedef std::shared_ptr<RtspPlayer> Ptr;
RtspPlayer(const EventPoller::Ptr &poller) ; RtspPlayer(const EventPoller::Ptr &poller) ;
virtual ~RtspPlayer(void); virtual ~RtspPlayer(void);
void play(const string &strUrl) override; void play(const string &strUrl) override;
void pause(bool bPause) override; void pause(bool bPause) override;
void teardown() override; void teardown() override;
float getPacketLossRate(TrackType type) const override; float getPacketLossRate(TrackType type) const override;
protected: protected:
//派生类回调函数 //派生类回调函数
virtual bool onCheckSDP(const string &strSdp) = 0; virtual bool onCheckSDP(const string &strSdp) = 0;
virtual void onRecvRTP(const RtpPacket::Ptr &pRtppt, const SdpTrack::Ptr &track) = 0; virtual void onRecvRTP(const RtpPacket::Ptr &pRtppt, const SdpTrack::Ptr &track) = 0;
uint32_t getProgressMilliSecond() const; uint32_t getProgressMilliSecond() const;
void seekToMilliSecond(uint32_t ms); void seekToMilliSecond(uint32_t ms);
@ -83,7 +83,7 @@ protected:
* @param rtppt rtp数据包 * @param rtppt rtp数据包
* @param trackidx track索引 * @param trackidx track索引
*/ */
void onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) override; void onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) override;
/** /**
@ -95,61 +95,61 @@ protected:
*/ */
virtual void onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen); virtual void onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen);
/////////////TcpClient override///////////// /////////////TcpClient override/////////////
void onConnect(const SockException &err) override; void onConnect(const SockException &err) override;
void onRecv(const Buffer::Ptr &pBuf) override; void onRecv(const Buffer::Ptr &pBuf) override;
void onErr(const SockException &ex) override; void onErr(const SockException &ex) override;
private: private:
void onRecvRTP_l(const RtpPacket::Ptr &pRtppt, const SdpTrack::Ptr &track); void onRecvRTP_l(const RtpPacket::Ptr &pRtppt, const SdpTrack::Ptr &track);
void onPlayResult_l(const SockException &ex , bool handshakeCompleted); void onPlayResult_l(const SockException &ex , bool handshakeCompleted);
int getTrackIndexByInterleaved(int interleaved) const; int getTrackIndexByInterleaved(int interleaved) const;
int getTrackIndexByTrackType(TrackType trackType) const; int getTrackIndexByTrackType(TrackType trackType) const;
void handleResSETUP(const Parser &parser, unsigned int uiTrackIndex); void handleResSETUP(const Parser &parser, unsigned int uiTrackIndex);
void handleResDESCRIBE(const Parser &parser); void handleResDESCRIBE(const Parser &parser);
bool handleAuthenticationFailure(const string &wwwAuthenticateParamsStr); bool handleAuthenticationFailure(const string &wwwAuthenticateParamsStr);
void handleResPAUSE(const Parser &parser, int type); void handleResPAUSE(const Parser &parser, int type);
//发送SETUP命令 //发送SETUP命令
void sendSetup(unsigned int uiTrackIndex); void sendSetup(unsigned int uiTrackIndex);
void sendPause(int type , uint32_t ms); void sendPause(int type , uint32_t ms);
void sendDescribe(); void sendDescribe();
void sendRtspRequest(const string &cmd, const string &url ,const StrCaseMap &header = StrCaseMap()); void sendRtspRequest(const string &cmd, const string &url ,const StrCaseMap &header = StrCaseMap());
void sendRtspRequest(const string &cmd, const string &url ,const std::initializer_list<string> &header); void sendRtspRequest(const string &cmd, const string &url ,const std::initializer_list<string> &header);
void sendReceiverReport(bool overTcp,int iTrackIndex); void sendReceiverReport(bool overTcp,int iTrackIndex);
void createUdpSockIfNecessary(int track_idx); void createUdpSockIfNecessary(int track_idx);
private: private:
string _strUrl; string _strUrl;
vector<SdpTrack::Ptr> _aTrackInfo; vector<SdpTrack::Ptr> _aTrackInfo;
function<void(const Parser&)> _onHandshake; function<void(const Parser&)> _onHandshake;
Socket::Ptr _apRtpSock[2]; //RTP端口,trackid idx 为数组下标 Socket::Ptr _apRtpSock[2]; //RTP端口,trackid idx 为数组下标
Socket::Ptr _apRtcpSock[2];//RTCP端口,trackid idx 为数组下标 Socket::Ptr _apRtcpSock[2];//RTCP端口,trackid idx 为数组下标
//rtsp鉴权相关 //rtsp鉴权相关
string _rtspMd5Nonce; string _rtspMd5Nonce;
string _rtspRealm; string _rtspRealm;
//rtsp info //rtsp info
string _strSession; string _strSession;
unsigned int _uiCseq = 1; unsigned int _uiCseq = 1;
string _strContentBase; string _strContentBase;
Rtsp::eRtpType _eType = Rtsp::RTP_TCP; Rtsp::eRtpType _eType = Rtsp::RTP_TCP;
/* 丢包率统计需要用到的参数 */ /* 丢包率统计需要用到的参数 */
uint16_t _aui16FirstSeq[2] = { 0 , 0}; uint16_t _aui16FirstSeq[2] = { 0 , 0};
uint16_t _aui16NowSeq[2] = { 0 , 0 }; uint16_t _aui16NowSeq[2] = { 0 , 0 };
uint64_t _aui64RtpRecv[2] = { 0 , 0}; uint64_t _aui64RtpRecv[2] = { 0 , 0};
//超时功能实现 //超时功能实现
Ticker _rtpTicker; Ticker _rtpTicker;
std::shared_ptr<Timer> _pPlayTimer; std::shared_ptr<Timer> _pPlayTimer;
std::shared_ptr<Timer> _pRtpTimer; std::shared_ptr<Timer> _pRtpTimer;
//时间戳 //时间戳
Stamp _stamp[2]; Stamp _stamp[2];
//rtcp相关 //rtcp相关
RtcpCounter _aRtcpCnt[2]; //rtcp统计,trackid idx 为数组下标 RtcpCounter _aRtcpCnt[2]; //rtcp统计,trackid idx 为数组下标
Ticker _aRtcpTicker[2]; //rtcp发送时间,trackid idx 为数组下标 Ticker _aRtcpTicker[2]; //rtcp发送时间,trackid idx 为数组下标
}; };

View File

@ -43,9 +43,9 @@ namespace mediakit {
class RtspPlayerImp: public PlayerImp<RtspPlayer,RtspDemuxer> { class RtspPlayerImp: public PlayerImp<RtspPlayer,RtspDemuxer> {
public: public:
typedef std::shared_ptr<RtspPlayerImp> Ptr; typedef std::shared_ptr<RtspPlayerImp> Ptr;
RtspPlayerImp(const EventPoller::Ptr &poller) : PlayerImp<RtspPlayer,RtspDemuxer>(poller){} RtspPlayerImp(const EventPoller::Ptr &poller) : PlayerImp<RtspPlayer,RtspDemuxer>(poller){}
virtual ~RtspPlayerImp(){ virtual ~RtspPlayerImp(){
DebugL<<endl; DebugL<<endl;
}; };
float getProgress() const override{ float getProgress() const override{
@ -60,17 +60,17 @@ public:
seekToMilliSecond(fProgress * getDuration() * 1000); seekToMilliSecond(fProgress * getDuration() * 1000);
}; };
private: private:
//派生类回调函数 //派生类回调函数
bool onCheckSDP(const string &sdp) override { bool onCheckSDP(const string &sdp) override {
_pRtspMediaSrc = dynamic_pointer_cast<RtspMediaSource>(_pMediaSrc); _pRtspMediaSrc = dynamic_pointer_cast<RtspMediaSource>(_pMediaSrc);
if(_pRtspMediaSrc){ if(_pRtspMediaSrc){
_pRtspMediaSrc->setSdp(sdp); _pRtspMediaSrc->setSdp(sdp);
} }
_delegate.reset(new RtspDemuxer); _delegate.reset(new RtspDemuxer);
_delegate->loadSdp(sdp); _delegate->loadSdp(sdp);
return true; return true;
} }
void onRecvRTP(const RtpPacket::Ptr &rtp, const SdpTrack::Ptr &track) override { void onRecvRTP(const RtpPacket::Ptr &rtp, const SdpTrack::Ptr &track) override {
if(_pRtspMediaSrc){ if(_pRtspMediaSrc){
// rtsp直接代理是无法判断该rtp是否是I帧所以GOP缓存基本是无效的 // rtsp直接代理是无法判断该rtp是否是I帧所以GOP缓存基本是无效的
// 为了减少内存使用那么我们设置为一直关键帧以便清空GOP缓存 // 为了减少内存使用那么我们设置为一直关键帧以便清空GOP缓存
@ -99,7 +99,7 @@ private:
} }
} }
private: private:
RtspMediaSource::Ptr _pRtspMediaSrc; RtspMediaSource::Ptr _pRtspMediaSrc;
int _maxAnalysisMS = 0; int _maxAnalysisMS = 0;
}; };

File diff suppressed because it is too large Load Diff

View File

@ -69,20 +69,20 @@ private:
class RtspSession: public TcpSession, public RtspSplitter, public RtpReceiver , public MediaSourceEvent{ class RtspSession: public TcpSession, public RtspSplitter, public RtpReceiver , public MediaSourceEvent{
public: public:
typedef std::shared_ptr<RtspSession> Ptr; typedef std::shared_ptr<RtspSession> Ptr;
typedef std::function<void(const string &realm)> onGetRealm; typedef std::function<void(const string &realm)> onGetRealm;
//encrypted为true是则表明是md5加密的密码否则是明文密码 //encrypted为true是则表明是md5加密的密码否则是明文密码
//在请求明文密码时如果提供md5密码者则会导致认证失败 //在请求明文密码时如果提供md5密码者则会导致认证失败
typedef std::function<void(bool encrypted,const string &pwd_or_md5)> onAuth; typedef std::function<void(bool encrypted,const string &pwd_or_md5)> onAuth;
RtspSession(const Socket::Ptr &pSock); RtspSession(const Socket::Ptr &pSock);
virtual ~RtspSession(); virtual ~RtspSession();
////TcpSession override//// ////TcpSession override////
void onRecv(const Buffer::Ptr &pBuf) override; void onRecv(const Buffer::Ptr &pBuf) override;
void onError(const SockException &err) override; void onError(const SockException &err) override;
void onManager() override; void onManager() override;
protected: protected:
//RtspSplitter override //RtspSplitter override
/** /**
* rtsp包回调sdp等content数据 * rtsp包回调sdp等content数据
* @param parser rtsp包 * @param parser rtsp包
@ -103,14 +103,14 @@ protected:
*/ */
int64_t getContentLength(Parser &parser) override; int64_t getContentLength(Parser &parser) override;
//RtpReceiver override //RtpReceiver override
void onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) override; void onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) override;
//MediaSourceEvent override //MediaSourceEvent override
bool close(MediaSource &sender,bool force) override ; bool close(MediaSource &sender,bool force) override ;
void onNoneReader(MediaSource &sender) override; void onNoneReader(MediaSource &sender) override;
int totalReaderCount(MediaSource &sender) override; int totalReaderCount(MediaSource &sender) override;
//TcpSession override //TcpSession override
int send(const Buffer::Ptr &pkt) override; int send(const Buffer::Ptr &pkt) override;
/** /**
@ -122,121 +122,121 @@ protected:
*/ */
virtual void onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen); virtual void onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen);
private: private:
//处理options方法,获取服务器能力 //处理options方法,获取服务器能力
void handleReq_Options(const Parser &parser); void handleReq_Options(const Parser &parser);
//处理describe方法请求服务器rtsp sdp信息 //处理describe方法请求服务器rtsp sdp信息
void handleReq_Describe(const Parser &parser); void handleReq_Describe(const Parser &parser);
//处理ANNOUNCE方法请求推流附带sdp //处理ANNOUNCE方法请求推流附带sdp
void handleReq_ANNOUNCE(const Parser &parser); void handleReq_ANNOUNCE(const Parser &parser);
//处理record方法开始推流 //处理record方法开始推流
void handleReq_RECORD(const Parser &parser); void handleReq_RECORD(const Parser &parser);
//处理setup方法播放和推流协商rtp传输方式用 //处理setup方法播放和推流协商rtp传输方式用
void handleReq_Setup(const Parser &parser); void handleReq_Setup(const Parser &parser);
//处理play方法开始或恢复播放 //处理play方法开始或恢复播放
void handleReq_Play(const Parser &parser); void handleReq_Play(const Parser &parser);
//处理pause方法暂停播放 //处理pause方法暂停播放
void handleReq_Pause(const Parser &parser); void handleReq_Pause(const Parser &parser);
//处理teardown方法结束播放 //处理teardown方法结束播放
void handleReq_Teardown(const Parser &parser); void handleReq_Teardown(const Parser &parser);
//处理Get方法,rtp over http才用到 //处理Get方法,rtp over http才用到
void handleReq_Get(const Parser &parser); void handleReq_Get(const Parser &parser);
//处理Post方法rtp over http才用到 //处理Post方法rtp over http才用到
void handleReq_Post(const Parser &parser); void handleReq_Post(const Parser &parser);
//处理SET_PARAMETER、GET_PARAMETER方法一般用于心跳 //处理SET_PARAMETER、GET_PARAMETER方法一般用于心跳
void handleReq_SET_PARAMETER(const Parser &parser); void handleReq_SET_PARAMETER(const Parser &parser);
//rtsp资源未找到 //rtsp资源未找到
void inline send_StreamNotFound(); void inline send_StreamNotFound();
//不支持的传输模式 //不支持的传输模式
void inline send_UnsupportedTransport(); void inline send_UnsupportedTransport();
//会话id错误 //会话id错误
void inline send_SessionNotFound(); void inline send_SessionNotFound();
//一般rtsp服务器打开端口失败时触发 //一般rtsp服务器打开端口失败时触发
void inline send_NotAcceptable(); void inline send_NotAcceptable();
//ssrc转字符串 //ssrc转字符串
inline string printSSRC(uint32_t ui32Ssrc); inline string printSSRC(uint32_t ui32Ssrc);
//获取track下标 //获取track下标
inline int getTrackIndexByTrackType(TrackType type); inline int getTrackIndexByTrackType(TrackType type);
inline int getTrackIndexByControlSuffix(const string &controlSuffix); inline int getTrackIndexByControlSuffix(const string &controlSuffix);
inline int getTrackIndexByInterleaved(int interleaved); inline int getTrackIndexByInterleaved(int interleaved);
//一般用于接收udp打洞包也用于rtsp推流 //一般用于接收udp打洞包也用于rtsp推流
inline void onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr &addr); inline void onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr &addr);
//配合onRcvPeerUdpData使用 //配合onRcvPeerUdpData使用
inline void startListenPeerUdpData(int iTrackIdx); inline void startListenPeerUdpData(int iTrackIdx);
////rtsp专有认证相关//// ////rtsp专有认证相关////
//认证成功 //认证成功
void onAuthSuccess(); void onAuthSuccess();
//认证失败 //认证失败
void onAuthFailed(const string &realm,const string &why,bool close = true); void onAuthFailed(const string &realm,const string &why,bool close = true);
//开始走rtsp专有认证流程 //开始走rtsp专有认证流程
void onAuthUser(const string &realm,const string &authorization); void onAuthUser(const string &realm,const string &authorization);
//校验base64方式的认证加密 //校验base64方式的认证加密
void onAuthBasic(const string &realm,const string &strBase64); void onAuthBasic(const string &realm,const string &strBase64);
//校验md5方式的认证加密 //校验md5方式的认证加密
void onAuthDigest(const string &realm,const string &strMd5); void onAuthDigest(const string &realm,const string &strMd5);
//发送rtp给客户端 //发送rtp给客户端
void sendRtpPacket(const RtpPacket::Ptr &pkt); void sendRtpPacket(const RtpPacket::Ptr &pkt);
//回复客户端 //回复客户端
bool sendRtspResponse(const string &res_code,const std::initializer_list<string> &header, const string &sdp = "" , const char *protocol = "RTSP/1.0"); bool sendRtspResponse(const string &res_code,const std::initializer_list<string> &header, const string &sdp = "" , const char *protocol = "RTSP/1.0");
bool sendRtspResponse(const string &res_code,const StrCaseMap &header = StrCaseMap(), const string &sdp = "",const char *protocol = "RTSP/1.0"); bool sendRtspResponse(const string &res_code,const StrCaseMap &header = StrCaseMap(), const string &sdp = "",const char *protocol = "RTSP/1.0");
//服务器发送rtcp //服务器发送rtcp
void sendSenderReport(bool overTcp,int iTrackIndex); void sendSenderReport(bool overTcp,int iTrackIndex);
//设置socket标志 //设置socket标志
void setSocketFlags(); void setSocketFlags();
private: private:
//用于判断客户端是否超时 //用于判断客户端是否超时
Ticker _ticker; Ticker _ticker;
//收到的seq回复时一致 //收到的seq回复时一致
int _iCseq = 0; int _iCseq = 0;
//ContentBase //ContentBase
string _strContentBase; string _strContentBase;
//Session号 //Session号
string _strSession; string _strSession;
//是否第一次播放,第一次播放需要鉴权,第二次播放属于暂停恢复 //是否第一次播放,第一次播放需要鉴权,第二次播放属于暂停恢复
bool _bFirstPlay = true; bool _bFirstPlay = true;
//url解析后保存的相关信息 //url解析后保存的相关信息
MediaInfo _mediaInfo; MediaInfo _mediaInfo;
//rtsp播放器绑定的直播源 //rtsp播放器绑定的直播源
std::weak_ptr<RtspMediaSource> _pMediaSrc; std::weak_ptr<RtspMediaSource> _pMediaSrc;
//直播源读取器 //直播源读取器
RingBuffer<RtpPacket::Ptr>::RingReader::Ptr _pRtpReader; RingBuffer<RtpPacket::Ptr>::RingReader::Ptr _pRtpReader;
//推流或拉流客户端采用的rtp传输方式 //推流或拉流客户端采用的rtp传输方式
Rtsp::eRtpType _rtpType = Rtsp::RTP_Invalid; Rtsp::eRtpType _rtpType = Rtsp::RTP_Invalid;
//sdp里面有效的track,包含音频或视频 //sdp里面有效的track,包含音频或视频
vector<SdpTrack::Ptr> _aTrackInfo; vector<SdpTrack::Ptr> _aTrackInfo;
////////RTP over udp//////// ////////RTP over udp////////
//RTP端口,trackid idx 为数组下标 //RTP端口,trackid idx 为数组下标
Socket::Ptr _apRtpSock[2]; Socket::Ptr _apRtpSock[2];
//RTCP端口,trackid idx 为数组下标 //RTCP端口,trackid idx 为数组下标
Socket::Ptr _apRtcpSock[2]; Socket::Ptr _apRtcpSock[2];
//标记是否收到播放的udp打洞包,收到播放的udp打洞包后才能知道其外网udp端口号 //标记是否收到播放的udp打洞包,收到播放的udp打洞包后才能知道其外网udp端口号
unordered_set<int> _udpSockConnected; unordered_set<int> _udpSockConnected;
////////RTP over udp_multicast//////// ////////RTP over udp_multicast////////
//共享的rtp组播对象 //共享的rtp组播对象
RtpMultiCaster::Ptr _multicaster; RtpMultiCaster::Ptr _multicaster;
//登录认证 //登录认证
string _strNonce; string _strNonce;
//消耗的总流量 //消耗的总流量
uint64_t _ui64TotalBytes = 0; uint64_t _ui64TotalBytes = 0;
//RTSP over HTTP //RTSP over HTTP
//quicktime 请求rtsp会产生两次tcp连接 //quicktime 请求rtsp会产生两次tcp连接
//一次发送 get 一次发送post需要通过x-sessioncookie关联起来 //一次发送 get 一次发送post需要通过x-sessioncookie关联起来
string _http_x_sessioncookie; string _http_x_sessioncookie;
function<void(const Buffer::Ptr &pBuf)> _onRecv; function<void(const Buffer::Ptr &pBuf)> _onRecv;
//是否开始发送rtp //是否开始发送rtp
bool _enableSendRtp; bool _enableSendRtp;
//rtsp推流相关 //rtsp推流相关
RtspMediaSourceImp::Ptr _pushSrc; RtspMediaSourceImp::Ptr _pushSrc;
//rtcp统计,trackid idx 为数组下标 //rtcp统计,trackid idx 为数组下标
RtcpCounter _aRtcpCnt[2]; RtcpCounter _aRtcpCnt[2];
//rtcp发送时间,trackid idx 为数组下标 //rtcp发送时间,trackid idx 为数组下标
Ticker _aRtcpTicker[2]; Ticker _aRtcpTicker[2];
//时间戳修整器 //时间戳修整器
Stamp _stamp[2]; Stamp _stamp[2];
}; };

View File

@ -38,76 +38,76 @@ UDPServer::UDPServer() {
} }
UDPServer::~UDPServer() { UDPServer::~UDPServer() {
InfoL; InfoL;
} }
Socket::Ptr UDPServer::getSock(const EventPoller::Ptr &poller,const char* strLocalIp, int intervaled,uint16_t iLocalPort) { Socket::Ptr UDPServer::getSock(const EventPoller::Ptr &poller,const char* strLocalIp, int intervaled,uint16_t iLocalPort) {
lock_guard<mutex> lck(_mtxUpdSock); lock_guard<mutex> lck(_mtxUpdSock);
string strKey = StrPrinter << strLocalIp << ":" << intervaled << endl; string strKey = StrPrinter << strLocalIp << ":" << intervaled << endl;
auto it = _mapUpdSock.find(strKey); auto it = _mapUpdSock.find(strKey);
if (it == _mapUpdSock.end()) { if (it == _mapUpdSock.end()) {
Socket::Ptr pSock(new Socket(poller)); Socket::Ptr pSock(new Socket(poller));
//InfoL<<localIp; //InfoL<<localIp;
if (!pSock->bindUdpSock(iLocalPort, strLocalIp)) { if (!pSock->bindUdpSock(iLocalPort, strLocalIp)) {
//分配失败 //分配失败
return nullptr; return nullptr;
} }
pSock->setOnRead(bind(&UDPServer::onRcvData, this, intervaled, placeholders::_1,placeholders::_2)); pSock->setOnRead(bind(&UDPServer::onRcvData, this, intervaled, placeholders::_1,placeholders::_2));
pSock->setOnErr(bind(&UDPServer::onErr, this, strKey, placeholders::_1)); pSock->setOnErr(bind(&UDPServer::onErr, this, strKey, placeholders::_1));
_mapUpdSock[strKey] = pSock; _mapUpdSock[strKey] = pSock;
DebugL << strLocalIp << " " << pSock->get_local_port() << " " << intervaled; DebugL << strLocalIp << " " << pSock->get_local_port() << " " << intervaled;
return pSock; return pSock;
} }
return it->second; return it->second;
} }
void UDPServer::listenPeer(const char* strPeerIp, void* pSelf, const onRecvData& cb) { void UDPServer::listenPeer(const char* strPeerIp, void* pSelf, const onRecvData& cb) {
lock_guard<mutex> lck(_mtxDataHandler); lock_guard<mutex> lck(_mtxDataHandler);
auto &mapRef = _mapDataHandler[strPeerIp]; auto &mapRef = _mapDataHandler[strPeerIp];
mapRef.emplace(pSelf, cb); mapRef.emplace(pSelf, cb);
} }
void UDPServer::stopListenPeer(const char* strPeerIp, void* pSelf) { void UDPServer::stopListenPeer(const char* strPeerIp, void* pSelf) {
lock_guard<mutex> lck(_mtxDataHandler); lock_guard<mutex> lck(_mtxDataHandler);
auto it0 = _mapDataHandler.find(strPeerIp); auto it0 = _mapDataHandler.find(strPeerIp);
if (it0 == _mapDataHandler.end()) { if (it0 == _mapDataHandler.end()) {
return; return;
} }
auto &mapRef = it0->second; auto &mapRef = it0->second;
auto it1 = mapRef.find(pSelf); auto it1 = mapRef.find(pSelf);
if (it1 != mapRef.end()) { if (it1 != mapRef.end()) {
mapRef.erase(it1); mapRef.erase(it1);
} }
if (mapRef.size() == 0) { if (mapRef.size() == 0) {
_mapDataHandler.erase(it0); _mapDataHandler.erase(it0);
} }
} }
void UDPServer::onErr(const string& strKey, const SockException& err) { void UDPServer::onErr(const string& strKey, const SockException& err) {
WarnL << err.what(); WarnL << err.what();
lock_guard<mutex> lck(_mtxUpdSock); lock_guard<mutex> lck(_mtxUpdSock);
_mapUpdSock.erase(strKey); _mapUpdSock.erase(strKey);
} }
void UDPServer::onRcvData(int intervaled, const Buffer::Ptr &pBuf, struct sockaddr* pPeerAddr) { void UDPServer::onRcvData(int intervaled, const Buffer::Ptr &pBuf, struct sockaddr* pPeerAddr) {
//TraceL << trackIndex; //TraceL << trackIndex;
struct sockaddr_in *in = (struct sockaddr_in *) pPeerAddr; struct sockaddr_in *in = (struct sockaddr_in *) pPeerAddr;
string peerIp = inet_ntoa(in->sin_addr); string peerIp = inet_ntoa(in->sin_addr);
lock_guard<mutex> lck(_mtxDataHandler); lock_guard<mutex> lck(_mtxDataHandler);
auto it0 = _mapDataHandler.find(peerIp); auto it0 = _mapDataHandler.find(peerIp);
if (it0 == _mapDataHandler.end()) { if (it0 == _mapDataHandler.end()) {
return; return;
} }
auto &mapRef = it0->second; auto &mapRef = it0->second;
for (auto it1 = mapRef.begin(); it1 != mapRef.end(); ++it1) { for (auto it1 = mapRef.begin(); it1 != mapRef.end(); ++it1) {
onRecvData &funRef = it1->second; onRecvData &funRef = it1->second;
if (!funRef(intervaled, pBuf, pPeerAddr)) { if (!funRef(intervaled, pBuf, pPeerAddr)) {
it1 = mapRef.erase(it1); it1 = mapRef.erase(it1);
} }
} }
if (mapRef.size() == 0) { if (mapRef.size() == 0) {
_mapDataHandler.erase(it0); _mapDataHandler.erase(it0);
} }
} }
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -43,21 +43,21 @@ namespace mediakit {
class UDPServer : public std::enable_shared_from_this<UDPServer> { class UDPServer : public std::enable_shared_from_this<UDPServer> {
public: public:
typedef function< bool(int intervaled, const Buffer::Ptr &buffer, struct sockaddr *peer_addr)> onRecvData; typedef function< bool(int intervaled, const Buffer::Ptr &buffer, struct sockaddr *peer_addr)> onRecvData;
~UDPServer(); ~UDPServer();
static UDPServer &Instance(); static UDPServer &Instance();
Socket::Ptr getSock(const EventPoller::Ptr &poller,const char *strLocalIp, int intervaled,uint16_t iLocalPort = 0); Socket::Ptr getSock(const EventPoller::Ptr &poller,const char *strLocalIp, int intervaled,uint16_t iLocalPort = 0);
void listenPeer(const char *strPeerIp, void *pSelf, const onRecvData &cb); void listenPeer(const char *strPeerIp, void *pSelf, const onRecvData &cb);
void stopListenPeer(const char *strPeerIp, void *pSelf); void stopListenPeer(const char *strPeerIp, void *pSelf);
private: private:
UDPServer(); UDPServer();
void onRcvData(int intervaled, const Buffer::Ptr &pBuf,struct sockaddr *pPeerAddr); void onRcvData(int intervaled, const Buffer::Ptr &pBuf,struct sockaddr *pPeerAddr);
void onErr(const string &strKey,const SockException &err); void onErr(const string &strKey,const SockException &err);
unordered_map<string, Socket::Ptr> _mapUpdSock; unordered_map<string, Socket::Ptr> _mapUpdSock;
mutex _mtxUpdSock; mutex _mtxUpdSock;
unordered_map<string, unordered_map<void *, onRecvData> > _mapDataHandler; unordered_map<string, unordered_map<void *, onRecvData> > _mapDataHandler;
mutex _mtxDataHandler; mutex _mtxDataHandler;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -48,29 +48,29 @@ ShellSession::~ShellSession() {
} }
void ShellSession::onRecv(const Buffer::Ptr&buf) { void ShellSession::onRecv(const Buffer::Ptr&buf) {
//DebugL << hexdump(buf->data(), buf->size()); //DebugL << hexdump(buf->data(), buf->size());
GET_CONFIG(uint32_t,maxReqSize,Shell::kMaxReqSize); GET_CONFIG(uint32_t,maxReqSize,Shell::kMaxReqSize);
if (_strRecvBuf.size() + buf->size() >= maxReqSize) { if (_strRecvBuf.size() + buf->size() >= maxReqSize) {
shutdown(SockException(Err_other,"recv buffer overflow")); shutdown(SockException(Err_other,"recv buffer overflow"));
return; return;
} }
_beatTicker.resetTime(); _beatTicker.resetTime();
_strRecvBuf.append(buf->data(), buf->size()); _strRecvBuf.append(buf->data(), buf->size());
if (_strRecvBuf.find("\xff\xf4\xff\0xfd\x06") != std::string::npos) { if (_strRecvBuf.find("\xff\xf4\xff\0xfd\x06") != std::string::npos) {
send("\033[0m\r\n Bye bye!\r\n"); send("\033[0m\r\n Bye bye!\r\n");
shutdown(SockException(Err_other,"received Ctrl+C")); shutdown(SockException(Err_other,"received Ctrl+C"));
return; return;
} }
size_t index; size_t index;
string line; string line;
while ((index = _strRecvBuf.find("\r\n")) != std::string::npos) { while ((index = _strRecvBuf.find("\r\n")) != std::string::npos) {
line = _strRecvBuf.substr(0, index); line = _strRecvBuf.substr(0, index);
_strRecvBuf.erase(0, index + 2); _strRecvBuf.erase(0, index + 2);
if (!onCommandLine(line)) { if (!onCommandLine(line)) {
shutdown(SockException(Err_other,"exit cmd")); shutdown(SockException(Err_other,"exit cmd"));
return; return;
} }
} }
} }
void ShellSession::onError(const SockException &err){ void ShellSession::onError(const SockException &err){
@ -78,19 +78,19 @@ void ShellSession::onError(const SockException &err){
} }
void ShellSession::onManager() { void ShellSession::onManager() {
if (_beatTicker.elapsedTime() > 1000 * 60 * 5) { if (_beatTicker.elapsedTime() > 1000 * 60 * 5) {
//5 miniutes for alive //5 miniutes for alive
shutdown(SockException(Err_timeout,"session timeout")); shutdown(SockException(Err_timeout,"session timeout"));
return; return;
} }
} }
inline bool ShellSession::onCommandLine(const string& line) { inline bool ShellSession::onCommandLine(const string& line) {
auto loginInterceptor = _loginInterceptor; auto loginInterceptor = _loginInterceptor;
if (loginInterceptor) { if (loginInterceptor) {
bool ret = loginInterceptor(line); bool ret = loginInterceptor(line);
return ret; return ret;
} }
try { try {
std::shared_ptr<stringstream> ss(new stringstream); std::shared_ptr<stringstream> ss(new stringstream);
CMDRegister::Instance()(line,ss); CMDRegister::Instance()(line,ss);
@ -102,21 +102,21 @@ inline bool ShellSession::onCommandLine(const string& line) {
send("\r\n"); send("\r\n");
} }
printShellPrefix(); printShellPrefix();
return true; return true;
} }
inline void ShellSession::pleaseInputUser() { inline void ShellSession::pleaseInputUser() {
send("\033[0m"); send("\033[0m");
send(StrPrinter << SERVER_NAME << " login: " << endl); send(StrPrinter << SERVER_NAME << " login: " << endl);
_loginInterceptor = [this](const string &user_name) { _loginInterceptor = [this](const string &user_name) {
_strUserName=user_name; _strUserName=user_name;
pleaseInputPasswd(); pleaseInputPasswd();
return true; return true;
}; };
} }
inline void ShellSession::pleaseInputPasswd() { inline void ShellSession::pleaseInputPasswd() {
send("Password: \033[8m"); send("Password: \033[8m");
_loginInterceptor = [this](const string &passwd) { _loginInterceptor = [this](const string &passwd) {
auto onAuth = [this](const string &errMessage){ auto onAuth = [this](const string &errMessage){
if(!errMessage.empty()){ if(!errMessage.empty()){
//鉴权失败 //鉴权失败
@ -157,12 +157,12 @@ inline void ShellSession::pleaseInputPasswd() {
//如果无人监听shell登录事件那么默认shell无法登录 //如果无人监听shell登录事件那么默认shell无法登录
onAuth("please listen kBroadcastShellLogin event"); onAuth("please listen kBroadcastShellLogin event");
} }
return true; return true;
}; };
} }
inline void ShellSession::printShellPrefix() { inline void ShellSession::printShellPrefix() {
send(StrPrinter << _strUserName << "@" << SERVER_NAME << "# " << endl); send(StrPrinter << _strUserName << "@" << SERVER_NAME << "# " << endl);
} }
}/* namespace mediakit */ }/* namespace mediakit */

View File

@ -37,23 +37,23 @@ namespace mediakit {
class ShellSession: public TcpSession { class ShellSession: public TcpSession {
public: public:
ShellSession(const Socket::Ptr &_sock); ShellSession(const Socket::Ptr &_sock);
virtual ~ShellSession(); virtual ~ShellSession();
void onRecv(const Buffer::Ptr &) override; void onRecv(const Buffer::Ptr &) override;
void onError(const SockException &err) override; void onError(const SockException &err) override;
void onManager() override; void onManager() override;
private: private:
inline bool onCommandLine(const string &); inline bool onCommandLine(const string &);
inline void pleaseInputUser(); inline void pleaseInputUser();
inline void pleaseInputPasswd(); inline void pleaseInputPasswd();
inline void printShellPrefix(); inline void printShellPrefix();
function<bool(const string &)> _loginInterceptor; function<bool(const string &)> _loginInterceptor;
string _strRecvBuf; string _strRecvBuf;
Ticker _beatTicker; Ticker _beatTicker;
string _strUserName; string _strUserName;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -32,232 +32,232 @@ namespace mediakit {
#define HK_APP_NAME "live" #define HK_APP_NAME "live"
DeviceHK::DeviceHK() { DeviceHK::DeviceHK() {
InfoL << endl; InfoL << endl;
static onceToken token( []() { static onceToken token( []() {
NET_DVR_Init(); NET_DVR_Init();
NET_DVR_SetDVRMessageCallBack_V31([](LONG lCommand,NET_DVR_ALARMER *pAlarmer,char *pAlarmInfo,DWORD dwBufLen,void* pUser){ NET_DVR_SetDVRMessageCallBack_V31([](LONG lCommand,NET_DVR_ALARMER *pAlarmer,char *pAlarmInfo,DWORD dwBufLen,void* pUser){
WarnL<<pAlarmInfo; WarnL<<pAlarmInfo;
return TRUE; return TRUE;
},NULL); },NULL);
}, []() { }, []() {
NET_DVR_Cleanup(); NET_DVR_Cleanup();
}); });
} }
DeviceHK::~DeviceHK() { DeviceHK::~DeviceHK() {
InfoL << endl; InfoL << endl;
} }
void DeviceHK::connectDevice(const connectInfo &info, const connectCB& cb, int iTimeOut) { void DeviceHK::connectDevice(const connectInfo &info, const connectCB& cb, int iTimeOut) {
NET_DVR_USER_LOGIN_INFO loginInfo; NET_DVR_USER_LOGIN_INFO loginInfo;
NET_DVR_DEVICEINFO_V40 loginResult; NET_DVR_DEVICEINFO_V40 loginResult;
//login info //login info
strcpy(loginInfo.sDeviceAddress, info.strDevIp.c_str()); strcpy(loginInfo.sDeviceAddress, info.strDevIp.c_str());
loginInfo.wPort = info.ui16DevPort; loginInfo.wPort = info.ui16DevPort;
strcpy(loginInfo.sUserName, info.strUserName.c_str()); strcpy(loginInfo.sUserName, info.strUserName.c_str());
strcpy(loginInfo.sPassword, info.strPwd.c_str()); strcpy(loginInfo.sPassword, info.strPwd.c_str());
//callback info //callback info
typedef function< void(LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo)> hkLoginCB; typedef function< void(LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo)> hkLoginCB;
loginInfo.bUseAsynLogin = TRUE; loginInfo.bUseAsynLogin = TRUE;
weak_ptr<Device> weakSelf = shared_from_this(); weak_ptr<Device> weakSelf = shared_from_this();
loginInfo.pUser = new hkLoginCB([weakSelf,cb](LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo ) { loginInfo.pUser = new hkLoginCB([weakSelf,cb](LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo ) {
//TraceL<<lUserID<<" "<<dwResult<<" "<<lpDeviceInfo->sSerialNumber; //TraceL<<lUserID<<" "<<dwResult<<" "<<lpDeviceInfo->sSerialNumber;
connectResult result; connectResult result;
if(dwResult==TRUE) { if(dwResult==TRUE) {
result.strDevName=(char *)(lpDeviceInfo->sSerialNumber); result.strDevName=(char *)(lpDeviceInfo->sSerialNumber);
result.ui16ChnStart=lpDeviceInfo->byStartChan; result.ui16ChnStart=lpDeviceInfo->byStartChan;
result.ui16ChnCount=lpDeviceInfo->byChanNum; result.ui16ChnCount=lpDeviceInfo->byChanNum;
auto _strongSelf=weakSelf.lock(); auto _strongSelf=weakSelf.lock();
if(_strongSelf) { if(_strongSelf) {
auto strongSelf=dynamic_pointer_cast<DeviceHK>(_strongSelf); auto strongSelf=dynamic_pointer_cast<DeviceHK>(_strongSelf);
strongSelf->onConnected(lUserID,lpDeviceInfo); strongSelf->onConnected(lUserID,lpDeviceInfo);
} }
} else { } else {
WarnL<<"connect deviceHK failed:"<<NET_DVR_GetLastError(); WarnL<<"connect deviceHK failed:"<<NET_DVR_GetLastError();
} }
cb(dwResult==TRUE,result); cb(dwResult==TRUE,result);
}); });
loginInfo.cbLoginResult = [](LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo , void* pUser) { loginInfo.cbLoginResult = [](LONG lUserID, DWORD dwResult, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo , void* pUser) {
auto *fun=static_cast<hkLoginCB *>(pUser); auto *fun=static_cast<hkLoginCB *>(pUser);
(*fun)(lUserID,dwResult,lpDeviceInfo); (*fun)(lUserID,dwResult,lpDeviceInfo);
delete fun; delete fun;
}; };
NET_DVR_SetConnectTime(iTimeOut * 1000, 3); NET_DVR_SetConnectTime(iTimeOut * 1000, 3);
NET_DVR_Login_V40(&loginInfo, &loginResult); NET_DVR_Login_V40(&loginInfo, &loginResult);
} }
void DeviceHK::disconnect(const relustCB& cb) { void DeviceHK::disconnect(const relustCB& cb) {
m_mapChannels.clear(); m_mapChannels.clear();
if (m_i64LoginId >= 0) { if (m_i64LoginId >= 0) {
NET_DVR_Logout(m_i64LoginId); NET_DVR_Logout(m_i64LoginId);
m_i64LoginId = -1; m_i64LoginId = -1;
Device::onDisconnected(true); Device::onDisconnected(true);
} }
} }
void DeviceHK::addChannel(int iChn, bool bMainStream) { void DeviceHK::addChannel(int iChn, bool bMainStream) {
DevChannel::Ptr channel( new DevChannelHK(m_i64LoginId, (char *) m_deviceInfo.sSerialNumber, iChn, bMainStream)); DevChannel::Ptr channel( new DevChannelHK(m_i64LoginId, (char *) m_deviceInfo.sSerialNumber, iChn, bMainStream));
m_mapChannels[iChn] = channel; m_mapChannels[iChn] = channel;
} }
void DeviceHK::delChannel(int chn) { void DeviceHK::delChannel(int chn) {
m_mapChannels.erase(chn); m_mapChannels.erase(chn);
} }
void DeviceHK::onConnected(LONG lUserID, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo) { void DeviceHK::onConnected(LONG lUserID, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo) {
m_i64LoginId = lUserID; m_i64LoginId = lUserID;
m_deviceInfo = *lpDeviceInfo; m_deviceInfo = *lpDeviceInfo;
Device::onConnected(); Device::onConnected();
} }
void DeviceHK::addAllChannel(bool bMainStream) { void DeviceHK::addAllChannel(bool bMainStream) {
InfoL << endl; InfoL << endl;
for (int i = 0; i < m_deviceInfo.byChanNum; i++) { for (int i = 0; i < m_deviceInfo.byChanNum; i++) {
addChannel(m_deviceInfo.byStartChan + i, bMainStream); addChannel(m_deviceInfo.byStartChan + i, bMainStream);
} }
} }
DevChannelHK::DevChannelHK(int64_t i64LoginId, const char* pcDevName, int iChn, bool bMainStream) : DevChannelHK::DevChannelHK(int64_t i64LoginId, const char* pcDevName, int iChn, bool bMainStream) :
DevChannel(HK_APP_NAME,(StrPrinter<<MD5(pcDevName).hexdigest()<<"_"<<iChn<<endl).data()), DevChannel(HK_APP_NAME,(StrPrinter<<MD5(pcDevName).hexdigest()<<"_"<<iChn<<endl).data()),
m_i64LoginId(i64LoginId) { m_i64LoginId(i64LoginId) {
InfoL << endl; InfoL << endl;
NET_DVR_PREVIEWINFO previewInfo; NET_DVR_PREVIEWINFO previewInfo;
previewInfo.lChannel = iChn; //通道号 previewInfo.lChannel = iChn; //通道号
previewInfo.dwStreamType = bMainStream ? 0 : 1; // 码流类型0-主码流1-子码流2-码流33-码流4 等以此类推 previewInfo.dwStreamType = bMainStream ? 0 : 1; // 码流类型0-主码流1-子码流2-码流33-码流4 等以此类推
previewInfo.dwLinkMode = 1; // 0TCP方式,1UDP方式,2多播方式,3 - RTP方式4-RTP/RTSP,5-RSTP/HTTP previewInfo.dwLinkMode = 1; // 0TCP方式,1UDP方式,2多播方式,3 - RTP方式4-RTP/RTSP,5-RSTP/HTTP
previewInfo.hPlayWnd = 0; //播放窗口的句柄,为NULL表示不播放图象 previewInfo.hPlayWnd = 0; //播放窗口的句柄,为NULL表示不播放图象
previewInfo.byProtoType = 0; //应用层取流协议0-私有协议1-RTSP协议 previewInfo.byProtoType = 0; //应用层取流协议0-私有协议1-RTSP协议
previewInfo.dwDisplayBufNum = 1; //播放库播放缓冲区最大缓冲帧数范围1-50置0时默认为1 previewInfo.dwDisplayBufNum = 1; //播放库播放缓冲区最大缓冲帧数范围1-50置0时默认为1
previewInfo.bBlocked = 0; previewInfo.bBlocked = 0;
m_i64PreviewHandle = NET_DVR_RealPlay_V40(m_i64LoginId, &previewInfo, m_i64PreviewHandle = NET_DVR_RealPlay_V40(m_i64LoginId, &previewInfo,
[](LONG lPlayHandle,DWORD dwDataType,BYTE *pBuffer,DWORD dwBufSize,void* pUser) { [](LONG lPlayHandle,DWORD dwDataType,BYTE *pBuffer,DWORD dwBufSize,void* pUser) {
DevChannelHK *self=reinterpret_cast<DevChannelHK *>(pUser); DevChannelHK *self=reinterpret_cast<DevChannelHK *>(pUser);
if(self->m_i64PreviewHandle!=(int64_t)lPlayHandle) { if(self->m_i64PreviewHandle!=(int64_t)lPlayHandle) {
return; return;
} }
self->onPreview(dwDataType,pBuffer,dwBufSize); self->onPreview(dwDataType,pBuffer,dwBufSize);
}, this); }, this);
if (m_i64PreviewHandle == -1) { if (m_i64PreviewHandle == -1) {
throw std::runtime_error( StrPrinter << "设备[" << pcDevName << "/" << iChn << "]开始实时预览失败:" throw std::runtime_error( StrPrinter << "设备[" << pcDevName << "/" << iChn << "]开始实时预览失败:"
<< NET_DVR_GetLastError() << endl); << NET_DVR_GetLastError() << endl);
} }
} }
DevChannelHK::~DevChannelHK() { DevChannelHK::~DevChannelHK() {
InfoL << endl; InfoL << endl;
if (m_i64PreviewHandle >= 0) { if (m_i64PreviewHandle >= 0) {
NET_DVR_StopRealPlay(m_i64PreviewHandle); NET_DVR_StopRealPlay(m_i64PreviewHandle);
m_i64PreviewHandle = -1; m_i64PreviewHandle = -1;
} }
if (m_iPlayHandle >= 0) { if (m_iPlayHandle >= 0) {
PlayM4_StopSoundShare(m_iPlayHandle); PlayM4_StopSoundShare(m_iPlayHandle);
PlayM4_Stop(m_iPlayHandle); PlayM4_Stop(m_iPlayHandle);
m_iPlayHandle = -1; m_iPlayHandle = -1;
} }
} }
void DevChannelHK::onPreview(DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize) { void DevChannelHK::onPreview(DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize) {
//TimeTicker1(-1); //TimeTicker1(-1);
switch (dwDataType) { switch (dwDataType) {
case NET_DVR_SYSHEAD: { //系统头数据 case NET_DVR_SYSHEAD: { //系统头数据
if (!PlayM4_GetPort(&m_iPlayHandle)) { //获取播放库未使用的通道号 if (!PlayM4_GetPort(&m_iPlayHandle)) { //获取播放库未使用的通道号
WarnL << "PlayM4_GetPort:" << NET_DVR_GetLastError(); WarnL << "PlayM4_GetPort:" << NET_DVR_GetLastError();
break; break;
} }
if (dwBufSize > 0) { if (dwBufSize > 0) {
if (!PlayM4_SetStreamOpenMode(m_iPlayHandle, STREAME_REALTIME)) { //设置实时流播放模式 if (!PlayM4_SetStreamOpenMode(m_iPlayHandle, STREAME_REALTIME)) { //设置实时流播放模式
WarnL << "PlayM4_SetStreamOpenMode:" << NET_DVR_GetLastError(); WarnL << "PlayM4_SetStreamOpenMode:" << NET_DVR_GetLastError();
break; break;
} }
if (!PlayM4_OpenStream(m_iPlayHandle, pBuffer, dwBufSize, if (!PlayM4_OpenStream(m_iPlayHandle, pBuffer, dwBufSize,
1024 * 1024)) { //打开流接口 1024 * 1024)) { //打开流接口
WarnL << "PlayM4_OpenStream:" << NET_DVR_GetLastError(); WarnL << "PlayM4_OpenStream:" << NET_DVR_GetLastError();
break; break;
} }
PlayM4_SetDecCallBackMend(m_iPlayHandle, PlayM4_SetDecCallBackMend(m_iPlayHandle,
[](int nPort,char * pBuf,int nSize,FRAME_INFO * pFrameInfo, void* nUser,int nReserved2) { [](int nPort,char * pBuf,int nSize,FRAME_INFO * pFrameInfo, void* nUser,int nReserved2) {
DevChannelHK *chn=reinterpret_cast<DevChannelHK *>(nUser); DevChannelHK *chn=reinterpret_cast<DevChannelHK *>(nUser);
if(chn->m_iPlayHandle!=nPort) { if(chn->m_iPlayHandle!=nPort) {
return; return;
} }
chn->onGetDecData(pBuf,nSize,pFrameInfo); chn->onGetDecData(pBuf,nSize,pFrameInfo);
}, this); }, this);
if (!PlayM4_Play(m_iPlayHandle, 0)) { //播放开始 if (!PlayM4_Play(m_iPlayHandle, 0)) { //播放开始
WarnL << "PlayM4_Play:" << NET_DVR_GetLastError(); WarnL << "PlayM4_Play:" << NET_DVR_GetLastError();
break; break;
} }
InfoL << "设置解码器成功!" << endl; InfoL << "设置解码器成功!" << endl;
//打开音频解码, 需要码流是复合流 //打开音频解码, 需要码流是复合流
if (!PlayM4_PlaySoundShare(m_iPlayHandle)) { if (!PlayM4_PlaySoundShare(m_iPlayHandle)) {
WarnL << "PlayM4_PlaySound:" << NET_DVR_GetLastError(); WarnL << "PlayM4_PlaySound:" << NET_DVR_GetLastError();
break; break;
} }
} }
} }
break; break;
case NET_DVR_STREAMDATA: { //流数据(包括复合流或音视频分开的视频流数据) case NET_DVR_STREAMDATA: { //流数据(包括复合流或音视频分开的视频流数据)
if (dwBufSize > 0 && m_iPlayHandle != -1) { if (dwBufSize > 0 && m_iPlayHandle != -1) {
if (!PlayM4_InputData(m_iPlayHandle, pBuffer, dwBufSize)) { if (!PlayM4_InputData(m_iPlayHandle, pBuffer, dwBufSize)) {
WarnL << "PlayM4_InputData:" << NET_DVR_GetLastError(); WarnL << "PlayM4_InputData:" << NET_DVR_GetLastError();
break; break;
} }
} }
} }
break; break;
case NET_DVR_AUDIOSTREAMDATA: { //音频数据 case NET_DVR_AUDIOSTREAMDATA: { //音频数据
} }
break; break;
case NET_DVR_PRIVATE_DATA: { //私有数据,包括智能信息 case NET_DVR_PRIVATE_DATA: { //私有数据,包括智能信息
} }
break; break;
default: default:
break; break;
} }
} }
void DevChannelHK::onGetDecData(char* pBuf, int nSize, FRAME_INFO* pFrameInfo) { void DevChannelHK::onGetDecData(char* pBuf, int nSize, FRAME_INFO* pFrameInfo) {
//InfoL << pFrameInfo->nType; //InfoL << pFrameInfo->nType;
switch (pFrameInfo->nType) { switch (pFrameInfo->nType) {
case T_YV12: { case T_YV12: {
if (!m_bVideoSeted) { if (!m_bVideoSeted) {
m_bVideoSeted = true; m_bVideoSeted = true;
VideoInfo video; VideoInfo video;
video.iWidth = pFrameInfo->nWidth; video.iWidth = pFrameInfo->nWidth;
video.iHeight = pFrameInfo->nHeight; video.iHeight = pFrameInfo->nHeight;
video.iFrameRate = pFrameInfo->nFrameRate; video.iFrameRate = pFrameInfo->nFrameRate;
initVideo(video); initVideo(video);
} }
char *yuv[3]; char *yuv[3];
int yuv_len[3]; int yuv_len[3];
yuv_len[0] = pFrameInfo->nWidth; yuv_len[0] = pFrameInfo->nWidth;
yuv_len[1] = pFrameInfo->nWidth / 2; yuv_len[1] = pFrameInfo->nWidth / 2;
yuv_len[2] = pFrameInfo->nWidth / 2; yuv_len[2] = pFrameInfo->nWidth / 2;
int dwOffset_Y = pFrameInfo->nWidth * pFrameInfo->nHeight; int dwOffset_Y = pFrameInfo->nWidth * pFrameInfo->nHeight;
yuv[0] = pBuf; yuv[0] = pBuf;
yuv[2] = yuv[0] + dwOffset_Y; yuv[2] = yuv[0] + dwOffset_Y;
yuv[1] = yuv[2] + dwOffset_Y / 4; yuv[1] = yuv[2] + dwOffset_Y / 4;
inputYUV(yuv, yuv_len, pFrameInfo->nStamp); inputYUV(yuv, yuv_len, pFrameInfo->nStamp);
} }
break; break;
case T_AUDIO16: { case T_AUDIO16: {
if (!m_bAudioSeted) { if (!m_bAudioSeted) {
m_bAudioSeted = true; m_bAudioSeted = true;
AudioInfo audio; AudioInfo audio;
audio.iChannel = pFrameInfo->nWidth; audio.iChannel = pFrameInfo->nWidth;
audio.iSampleBit = pFrameInfo->nHeight; audio.iSampleBit = pFrameInfo->nHeight;
audio.iSampleRate = pFrameInfo->nFrameRate; audio.iSampleRate = pFrameInfo->nFrameRate;
initAudio(audio); initAudio(audio);
} }
inputPCM(pBuf, nSize, pFrameInfo->nStamp); inputPCM(pBuf, nSize, pFrameInfo->nStamp);
} }
break; break;
default: default:
break; break;
} }
} }
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -41,26 +41,26 @@ namespace mediakit {
class connectInfo { class connectInfo {
public: public:
connectInfo(const char *_strDevIp, connectInfo(const char *_strDevIp,
uint16_t _ui16DevPort, uint16_t _ui16DevPort,
const char *_strUserName, const char *_strUserName,
const char *_strPwd) { const char *_strPwd) {
strDevIp = _strDevIp; strDevIp = _strDevIp;
ui16DevPort = _ui16DevPort; ui16DevPort = _ui16DevPort;
strUserName = _strUserName; strUserName = _strUserName;
strPwd = _strPwd; strPwd = _strPwd;
} }
string strDevIp; string strDevIp;
uint16_t ui16DevPort; uint16_t ui16DevPort;
string strUserName; string strUserName;
string strPwd; string strPwd;
}; };
class connectResult { class connectResult {
public: public:
string strDevName; string strDevName;
uint16_t ui16ChnStart; uint16_t ui16ChnStart;
uint16_t ui16ChnCount; uint16_t ui16ChnCount;
}; };
typedef function<void(bool success, const connectResult &)> connectCB; typedef function<void(bool success, const connectResult &)> connectCB;
@ -68,28 +68,28 @@ typedef function<void(bool success)> relustCB;
class Device: public enable_shared_from_this<Device> { class Device: public enable_shared_from_this<Device> {
public: public:
typedef std::shared_ptr<Device> Ptr; typedef std::shared_ptr<Device> Ptr;
Device() { Device() {
} }
virtual ~Device(){ disconnect([](bool bSuccess){ virtual ~Device(){ disconnect([](bool bSuccess){
});}; });};
virtual void connectDevice(const connectInfo &info, const connectCB &cb, int iTimeOut = 3)=0; virtual void connectDevice(const connectInfo &info, const connectCB &cb, int iTimeOut = 3)=0;
virtual void disconnect(const relustCB &cb) { virtual void disconnect(const relustCB &cb) {
} }
virtual void addChannel(int iChnIndex, bool bMainStream = true)=0; virtual void addChannel(int iChnIndex, bool bMainStream = true)=0;
virtual void delChannel(int iChnIndex)=0; virtual void delChannel(int iChnIndex)=0;
virtual void addAllChannel(bool bMainStream = true)=0; virtual void addAllChannel(bool bMainStream = true)=0;
protected: protected:
void onConnected() { void onConnected() {
} }
void onDisconnected(bool bSelfDisconnect) { void onDisconnected(bool bSelfDisconnect) {
} }
}; };
@ -97,36 +97,36 @@ protected:
class DevChannelHK; class DevChannelHK;
class DeviceHK: public Device { class DeviceHK: public Device {
public: public:
typedef std::shared_ptr<DeviceHK> Ptr; typedef std::shared_ptr<DeviceHK> Ptr;
DeviceHK(); DeviceHK();
virtual ~DeviceHK(); virtual ~DeviceHK();
void connectDevice(const connectInfo &info, const connectCB &cb, int iTimeOut = 3) override; void connectDevice(const connectInfo &info, const connectCB &cb, int iTimeOut = 3) override;
void disconnect(const relustCB &cb) override; void disconnect(const relustCB &cb) override;
void addChannel(int iChnIndex, bool bMainStream = true) override; void addChannel(int iChnIndex, bool bMainStream = true) override;
void delChannel(int iChnIndex) override; void delChannel(int iChnIndex) override;
void addAllChannel(bool bMainStream = true) override; void addAllChannel(bool bMainStream = true) override;
private: private:
map<int, std::shared_ptr<DevChannel> > m_mapChannels; map<int, std::shared_ptr<DevChannel> > m_mapChannels;
int64_t m_i64LoginId = -1; int64_t m_i64LoginId = -1;
NET_DVR_DEVICEINFO_V30 m_deviceInfo; NET_DVR_DEVICEINFO_V30 m_deviceInfo;
void onConnected(LONG lUserID, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo); void onConnected(LONG lUserID, LPNET_DVR_DEVICEINFO_V30 lpDeviceInfo);
}; };
class DevChannelHK: public DevChannel { class DevChannelHK: public DevChannel {
public: public:
typedef std::shared_ptr<DevChannel> Ptr; typedef std::shared_ptr<DevChannel> Ptr;
DevChannelHK(int64_t i64LoginId, const char *pcDevName, int iChn, bool bMainStream = true); DevChannelHK(int64_t i64LoginId, const char *pcDevName, int iChn, bool bMainStream = true);
virtual ~DevChannelHK(); virtual ~DevChannelHK();
protected: protected:
int64_t m_i64LoginId = -1; int64_t m_i64LoginId = -1;
int64_t m_i64PreviewHandle = -1; int64_t m_i64PreviewHandle = -1;
int m_iPlayHandle = -1; int m_iPlayHandle = -1;
void onPreview(DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize); void onPreview(DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize);
void onGetDecData(char * pBuf, int nSize, FRAME_INFO * pFrameInfo); void onGetDecData(char * pBuf, int nSize, FRAME_INFO * pFrameInfo);
bool m_bVideoSeted = false; bool m_bVideoSeted = false;
bool m_bAudioSeted = false; bool m_bAudioSeted = false;
}; };
} /* namespace mediakit */ } /* namespace mediakit */

View File

@ -46,51 +46,51 @@ namespace mediakit {
class H264Decoder class H264Decoder
{ {
public: public:
H264Decoder(void){ H264Decoder(void){
avcodec_register_all(); avcodec_register_all();
AVCodec *pCodec = avcodec_find_decoder(AV_CODEC_ID_H264); AVCodec *pCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!pCodec) { if (!pCodec) {
throw std::runtime_error("未找到H264解码器"); throw std::runtime_error("未找到H264解码器");
} }
m_pContext.reset(avcodec_alloc_context3(pCodec), [](AVCodecContext *pCtx) { m_pContext.reset(avcodec_alloc_context3(pCodec), [](AVCodecContext *pCtx) {
avcodec_close(pCtx); avcodec_close(pCtx);
avcodec_free_context(&pCtx); avcodec_free_context(&pCtx);
}); });
if (!m_pContext) { if (!m_pContext) {
throw std::runtime_error("创建解码器失败"); throw std::runtime_error("创建解码器失败");
} }
if (pCodec->capabilities & AV_CODEC_CAP_TRUNCATED) { if (pCodec->capabilities & AV_CODEC_CAP_TRUNCATED) {
/* we do not send complete frames */ /* we do not send complete frames */
m_pContext->flags |= AV_CODEC_FLAG_TRUNCATED; m_pContext->flags |= AV_CODEC_FLAG_TRUNCATED;
} }
if(avcodec_open2(m_pContext.get(), pCodec, NULL)< 0){ if(avcodec_open2(m_pContext.get(), pCodec, NULL)< 0){
throw std::runtime_error("打开编码器失败"); throw std::runtime_error("打开编码器失败");
} }
m_pFrame.reset(av_frame_alloc(),[](AVFrame *pFrame){ m_pFrame.reset(av_frame_alloc(),[](AVFrame *pFrame){
av_frame_free(&pFrame); av_frame_free(&pFrame);
}); });
if (!m_pFrame) { if (!m_pFrame) {
throw std::runtime_error("创建帧缓存失败"); throw std::runtime_error("创建帧缓存失败");
} }
} }
virtual ~H264Decoder(void){} virtual ~H264Decoder(void){}
bool inputVideo(unsigned char* data,unsigned int dataSize,uint32_t ui32Stamp,AVFrame **ppFrame){ bool inputVideo(unsigned char* data,unsigned int dataSize,uint32_t ui32Stamp,AVFrame **ppFrame){
AVPacket pkt; AVPacket pkt;
av_init_packet(&pkt); av_init_packet(&pkt);
pkt.data = data; pkt.data = data;
pkt.size = dataSize; pkt.size = dataSize;
pkt.dts = ui32Stamp; pkt.dts = ui32Stamp;
int iGotPicture ; int iGotPicture ;
auto iLen = avcodec_decode_video2(m_pContext.get(), m_pFrame.get(), &iGotPicture, &pkt); auto iLen = avcodec_decode_video2(m_pContext.get(), m_pFrame.get(), &iGotPicture, &pkt);
if (!iGotPicture || iLen < 0) { if (!iGotPicture || iLen < 0) {
return false; return false;
} }
*ppFrame = m_pFrame.get(); *ppFrame = m_pFrame.get();
return true; return true;
} }
private: private:
std::shared_ptr<AVCodecContext> m_pContext; std::shared_ptr<AVCodecContext> m_pContext;
std::shared_ptr<AVFrame> m_pFrame; std::shared_ptr<AVFrame> m_pFrame;
}; };

View File

@ -65,13 +65,13 @@ public:
SDL_PushEvent(&event); SDL_PushEvent(&event);
} }
void runLoop(){ void runLoop(){
bool flag = true; bool flag = true;
std::function<bool ()> task; std::function<bool ()> task;
SDL_Event event; SDL_Event event;
while(flag){ while(flag){
SDL_WaitEvent(&event); SDL_WaitEvent(&event);
switch (event.type){ switch (event.type){
case REFRESH_EVENT:{ case REFRESH_EVENT:{
{ {
lock_guard<mutex> lck(_mtxTask); lock_guard<mutex> lck(_mtxTask);
@ -91,17 +91,17 @@ public:
default: default:
break; break;
} }
} }
} }
void shutdown(){ void shutdown(){
doTask([](){return false;}); doTask([](){return false;});
} }
private: private:
SDLDisplayerHelper(){ SDLDisplayerHelper(){
}; };
~SDLDisplayerHelper(){ ~SDLDisplayerHelper(){
shutdown(); shutdown();
}; };
private: private:
std::deque<std::function<bool ()> > _taskList; std::deque<std::function<bool ()> > _taskList;
@ -112,7 +112,7 @@ private:
class YuvDisplayer { class YuvDisplayer {
public: public:
YuvDisplayer(void *hwnd = nullptr,const char *title = "untitled"){ YuvDisplayer(void *hwnd = nullptr,const char *title = "untitled"){
static onceToken token([]() { static onceToken token([]() {
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) == -1) { if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) == -1) {
@ -131,39 +131,39 @@ public:
SDL_Quit(); SDL_Quit();
}); });
_title = title; _title = title;
_hwnd = hwnd; _hwnd = hwnd;
} }
virtual ~YuvDisplayer(){ virtual ~YuvDisplayer(){
if (_texture) { if (_texture) {
SDL_DestroyTexture(_texture); SDL_DestroyTexture(_texture);
_texture = nullptr; _texture = nullptr;
} }
if (_render) { if (_render) {
SDL_DestroyRenderer(_render); SDL_DestroyRenderer(_render);
_render = nullptr; _render = nullptr;
} }
if (_win) { if (_win) {
SDL_DestroyWindow(_win); SDL_DestroyWindow(_win);
_win = nullptr; _win = nullptr;
} }
} }
bool displayYUV(AVFrame *pFrame){ bool displayYUV(AVFrame *pFrame){
if (!_win) { if (!_win) {
if (_hwnd) { if (_hwnd) {
_win = SDL_CreateWindowFrom(_hwnd); _win = SDL_CreateWindowFrom(_hwnd);
}else { }else {
_win = SDL_CreateWindow(_title.data(), _win = SDL_CreateWindow(_title.data(),
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
pFrame->width, pFrame->width,
pFrame->height, pFrame->height,
SDL_WINDOW_OPENGL); SDL_WINDOW_OPENGL);
} }
} }
if (_win && ! _render){ if (_win && ! _render){
#if 0 #if 0
SDL_RENDERER_SOFTWARE = 0x00000001, /**< The renderer is a software fallback */ SDL_RENDERER_SOFTWARE = 0x00000001, /**< The renderer is a software fallback */
SDL_RENDERER_ACCELERATED = 0x00000002, /**< The renderer uses hardware SDL_RENDERER_ACCELERATED = 0x00000002, /**< The renderer uses hardware
acceleration */ acceleration */
SDL_RENDERER_PRESENTVSYNC = 0x00000004, /**< Present is synchronized SDL_RENDERER_PRESENTVSYNC = 0x00000004, /**< Present is synchronized
@ -172,34 +172,34 @@ public:
rendering to texture */ rendering to texture */
#endif #endif
_render = SDL_CreateRenderer(_win, -1, SDL_RENDERER_ACCELERATED); _render = SDL_CreateRenderer(_win, -1, SDL_RENDERER_ACCELERATED);
} }
if (_render && !_texture) { if (_render && !_texture) {
_texture = SDL_CreateTexture(_render, SDL_PIXELFORMAT_IYUV, _texture = SDL_CreateTexture(_render, SDL_PIXELFORMAT_IYUV,
SDL_TEXTUREACCESS_STREAMING, SDL_TEXTUREACCESS_STREAMING,
pFrame->width, pFrame->width,
pFrame->height); pFrame->height);
} }
if (_texture) { if (_texture) {
SDL_UpdateYUVTexture(_texture, nullptr, SDL_UpdateYUVTexture(_texture, nullptr,
pFrame->data[0], pFrame->linesize[0], pFrame->data[0], pFrame->linesize[0],
pFrame->data[1], pFrame->linesize[1], pFrame->data[1], pFrame->linesize[1],
pFrame->data[2], pFrame->linesize[2]); pFrame->data[2], pFrame->linesize[2]);
//SDL_UpdateTexture(_texture, nullptr, pFrame->data[0], pFrame->linesize[0]); //SDL_UpdateTexture(_texture, nullptr, pFrame->data[0], pFrame->linesize[0]);
SDL_RenderClear(_render); SDL_RenderClear(_render);
SDL_RenderCopy(_render, _texture, nullptr, nullptr); SDL_RenderCopy(_render, _texture, nullptr, nullptr);
SDL_RenderPresent(_render); SDL_RenderPresent(_render);
return true; return true;
} }
return false; return false;
} }
private: private:
string _title; string _title;
SDL_Window *_win = nullptr; SDL_Window *_win = nullptr;
SDL_Renderer *_render = nullptr; SDL_Renderer *_render = nullptr;
SDL_Texture *_texture = nullptr; SDL_Texture *_texture = nullptr;
void *_hwnd = nullptr; void *_hwnd = nullptr;
}; };
#endif /* YUVDISPLAYER_H_ */ #endif /* YUVDISPLAYER_H_ */

View File

@ -126,6 +126,7 @@ void process_file(const char *file,bool rm_bom){
InfoL << (rm_bom ? "删除" : "添加") << "bom:" << file; InfoL << (rm_bom ? "删除" : "添加") << "bom:" << file;
} }
/// 这个程序是为了统一添加或删除utf-8 bom头
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
CMD_main cmd_main; CMD_main cmd_main;
try { try {
@ -148,7 +149,7 @@ int main(int argc, char *argv[]) {
bool no_filter = filter_set.find("*") != filter_set.end(); bool no_filter = filter_set.find("*") != filter_set.end();
//设置日志 //设置日志
Logger::Instance().add(std::make_shared<ConsoleChannel>()); Logger::Instance().add(std::make_shared<ConsoleChannel>());
path = File::absolutePath(path, "");
for_each_file(path.data(),[&](const char *path){ for_each_file(path.data(),[&](const char *path){
if(!no_filter){ if(!no_filter){
//开启了过滤器 //开启了过滤器

View File

@ -1,18 +1,9 @@
#include <stdlib.h> #include <memory.h>
#include <memory.h>
#if !defined(_WIN32)
#include <dirent.h>
#endif //!defined(_WIN32)
#include <set> #include <set>
#include "Util/CMD.h" #include "Util/CMD.h"
#include "Util/util.h" #include "Util/util.h"
#include "Util/logger.h" #include "Util/logger.h"
#include "Util/File.h" #include "Util/File.h"
#include "Util/uv_errno.h"
using namespace std; using namespace std;
using namespace toolkit; using namespace toolkit;
@ -41,17 +32,40 @@ public:
virtual ~CMD_main() {} virtual ~CMD_main() {}
}; };
vector<string> split(const string& s, const char *delim) {
vector<string> ret;
int last = 0;
int index = s.find(delim, last);
while (index != string::npos) {
if (index - last >= 0) {
ret.push_back(s.substr(last, index - last));
}
last = index + strlen(delim);
index = s.find(delim, last);
}
if (!s.size() || s.size() - last >= 0) {
ret.push_back(s.substr(last));
}
return ret;
}
void process_file(const char *file) { void process_file(const char *file) {
auto str = File::loadFile(file); auto str = File::loadFile(file);
if (str.empty()) { if (str.empty()) {
return; return;
} }
auto lines = split(str, "\n"); auto lines = ::split(str, "\n");
deque<string> lines_copy; deque<string> lines_copy;
for (auto &line : lines) { for (auto &line : lines) {
if(line.empty()){
lines_copy.push_back("");
continue;
}
string line_copy; string line_copy;
bool flag = false; bool flag = false;
int i = 0;
for (auto &ch : line) { for (auto &ch : line) {
++i;
switch (ch) { switch (ch) {
case '\t' : case '\t' :
line_copy.append(" "); line_copy.append(" ");
@ -65,6 +79,7 @@ void process_file(const char *file) {
break; break;
} }
if (flag) { if (flag) {
line_copy.append(line.substr(i));
break; break;
} }
} }
@ -75,9 +90,13 @@ void process_file(const char *file) {
str.append(line); str.append(line);
str.push_back('\n'); str.push_back('\n');
} }
if(!lines_copy.empty()){
str.pop_back();
}
File::saveFile(str, file); File::saveFile(str, file);
} }
/// 这个程序是为了统一替换tab为4个空格
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
CMD_main cmd_main; CMD_main cmd_main;
try { try {
@ -87,10 +106,9 @@ int main(int argc, char *argv[]) {
return -1; return -1;
} }
bool rm_bom = cmd_main.hasKey("rm");
string path = cmd_main["in"]; string path = cmd_main["in"];
string filter = cmd_main["filter"]; string filter = cmd_main["filter"];
auto vec = split(filter, ","); auto vec = ::split(filter, ",");
set<string> filter_set; set<string> filter_set;
for (auto ext : vec) { for (auto ext : vec) {
@ -100,6 +118,8 @@ int main(int argc, char *argv[]) {
bool no_filter = filter_set.find("*") != filter_set.end(); bool no_filter = filter_set.find("*") != filter_set.end();
//设置日志 //设置日志
Logger::Instance().add(std::make_shared<ConsoleChannel>()); Logger::Instance().add(std::make_shared<ConsoleChannel>());
path = File::absolutePath(path, "");
DebugL << path;
File::scanDir(path, [&](const string &path, bool isDir) { File::scanDir(path, [&](const string &path, bool isDir) {
if (isDir) { if (isDir) {
return true; return true;

View File

@ -50,89 +50,89 @@ const char kPort[] = HTTP_FIELD"port";
#define HTTPS_PORT 443 #define HTTPS_PORT 443
extern const char kSSLPort[] = HTTP_FIELD"sslport"; extern const char kSSLPort[] = HTTP_FIELD"sslport";
onceToken token1([](){ onceToken token1([](){
mINI::Instance()[kPort] = HTTP_PORT; mINI::Instance()[kPort] = HTTP_PORT;
mINI::Instance()[kSSLPort] = HTTPS_PORT; mINI::Instance()[kSSLPort] = HTTPS_PORT;
},nullptr); },nullptr);
}//namespace Http }//namespace Http
} // namespace mediakit } // namespace mediakit
void initEventListener(){ void initEventListener(){
static onceToken s_token([](){ static onceToken s_token([](){
NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastHttpRequest,[](BroadcastHttpRequestArgs){ NoticeCenter::Instance().addListener(nullptr,Broadcast::kBroadcastHttpRequest,[](BroadcastHttpRequestArgs){
//const Parser &parser,HttpSession::HttpResponseInvoker &invoker,bool &consumed //const Parser &parser,HttpSession::HttpResponseInvoker &invoker,bool &consumed
if(strstr(parser.Url().data(),"/api/") != parser.Url().data()){ if(strstr(parser.Url().data(),"/api/") != parser.Url().data()){
return; return;
} }
//url以"/api/起始说明是http api" //url以"/api/起始说明是http api"
consumed = true;//该http请求已被消费 consumed = true;//该http请求已被消费
_StrPrinter printer; _StrPrinter printer;
////////////////method//////////////////// ////////////////method////////////////////
printer << "\r\nmethod:\r\n\t" << parser.Method(); printer << "\r\nmethod:\r\n\t" << parser.Method();
////////////////url///////////////// ////////////////url/////////////////
printer << "\r\nurl:\r\n\t" << parser.Url(); printer << "\r\nurl:\r\n\t" << parser.Url();
////////////////protocol///////////////// ////////////////protocol/////////////////
printer << "\r\nprotocol:\r\n\t" << parser.Tail(); printer << "\r\nprotocol:\r\n\t" << parser.Tail();
///////////////args////////////////// ///////////////args//////////////////
printer << "\r\nargs:\r\n"; printer << "\r\nargs:\r\n";
for(auto &pr : parser.getUrlArgs()){ for(auto &pr : parser.getUrlArgs()){
printer << "\t" << pr.first << " : " << pr.second << "\r\n"; printer << "\t" << pr.first << " : " << pr.second << "\r\n";
} }
///////////////header////////////////// ///////////////header//////////////////
printer << "\r\nheader:\r\n"; printer << "\r\nheader:\r\n";
for(auto &pr : parser.getValues()){ for(auto &pr : parser.getValues()){
printer << "\t" << pr.first << " : " << pr.second << "\r\n"; printer << "\t" << pr.first << " : " << pr.second << "\r\n";
} }
////////////////content///////////////// ////////////////content/////////////////
printer << "\r\ncontent:\r\n" << parser.Content(); printer << "\r\ncontent:\r\n" << parser.Content();
auto contentOut = printer << endl; auto contentOut = printer << endl;
////////////////我们测算异步回复,当然你也可以同步回复///////////////// ////////////////我们测算异步回复,当然你也可以同步回复/////////////////
EventPollerPool::Instance().getPoller()->async([invoker,contentOut](){ EventPollerPool::Instance().getPoller()->async([invoker,contentOut](){
HttpSession::KeyValue headerOut; HttpSession::KeyValue headerOut;
//你可以自定义header,如果跟默认header重名则会覆盖之 //你可以自定义header,如果跟默认header重名则会覆盖之
//默认header有:Server,Connection,Date,Content-Type,Content-Length //默认header有:Server,Connection,Date,Content-Type,Content-Length
//请勿覆盖Connection、Content-Length键 //请勿覆盖Connection、Content-Length键
//键名覆盖时不区分大小写 //键名覆盖时不区分大小写
headerOut["TestHeader"] = "HeaderValue"; headerOut["TestHeader"] = "HeaderValue";
invoker("200 OK",headerOut,contentOut); invoker("200 OK",headerOut,contentOut);
}); });
}); });
}, nullptr); }, nullptr);
} }
int main(int argc,char *argv[]){ int main(int argc,char *argv[]){
//设置退出信号处理函数 //设置退出信号处理函数
static semaphore sem; static semaphore sem;
signal(SIGINT, [](int) { sem.post(); });// 设置退出信号 signal(SIGINT, [](int) { sem.post(); });// 设置退出信号
//设置日志 //设置日志
Logger::Instance().add(std::make_shared<ConsoleChannel>()); Logger::Instance().add(std::make_shared<ConsoleChannel>());
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>()); Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
//加载配置文件,如果配置文件不存在就创建一个 //加载配置文件,如果配置文件不存在就创建一个
loadIniConfig(); loadIniConfig();
initEventListener(); initEventListener();
//加载证书,证书包含公钥和私钥 //加载证书,证书包含公钥和私钥
SSL_Initor::Instance().loadCertificate((exeDir() + "ssl.p12").data()); SSL_Initor::Instance().loadCertificate((exeDir() + "ssl.p12").data());
//信任某个自签名证书 //信任某个自签名证书
SSL_Initor::Instance().trustCertificate((exeDir() + "ssl.p12").data()); SSL_Initor::Instance().trustCertificate((exeDir() + "ssl.p12").data());
//不忽略无效证书证书(例如自签名或过期证书) //不忽略无效证书证书(例如自签名或过期证书)
SSL_Initor::Instance().ignoreInvalidCertificate(false); SSL_Initor::Instance().ignoreInvalidCertificate(false);
//开启http服务器 //开启http服务器
TcpServer::Ptr httpSrv(new TcpServer()); TcpServer::Ptr httpSrv(new TcpServer());
httpSrv->start<HttpSession>(mINI::Instance()[Http::kPort]);//默认80 httpSrv->start<HttpSession>(mINI::Instance()[Http::kPort]);//默认80
//如果支持ssl还可以开启https服务器 //如果支持ssl还可以开启https服务器
TcpServer::Ptr httpsSrv(new TcpServer()); TcpServer::Ptr httpsSrv(new TcpServer());
httpsSrv->start<HttpsSession>(mINI::Instance()[Http::kSSLPort]);//默认443 httpsSrv->start<HttpsSession>(mINI::Instance()[Http::kSSLPort]);//默认443
InfoL << "你可以在浏览器输入:http://127.0.0.1/api/my_api?key0=val0&key1=参数1" << endl; InfoL << "你可以在浏览器输入:http://127.0.0.1/api/my_api?key0=val0&key1=参数1" << endl;
sem.wait(); sem.wait();
return 0; return 0;
} }

View File

@ -48,92 +48,92 @@ Timer::Ptr g_timer;
//推流失败或断开延迟2秒后重试推流 //推流失败或断开延迟2秒后重试推流
void rePushDelay(const EventPoller::Ptr &poller, void rePushDelay(const EventPoller::Ptr &poller,
const string &schema, const string &schema,
const string &vhost, const string &vhost,
const string &app, const string &app,
const string &stream, const string &stream,
const string &filePath, const string &filePath,
const string &url) ; const string &url) ;
//创建推流器并开始推流 //创建推流器并开始推流
void createPusher(const EventPoller::Ptr &poller, void createPusher(const EventPoller::Ptr &poller,
const string &schema, const string &schema,
const string &vhost, const string &vhost,
const string &app, const string &app,
const string &stream, const string &stream,
const string &filePath, const string &filePath,
const string &url) { const string &url) {
//不限制APP名并且指定文件绝对路径 //不限制APP名并且指定文件绝对路径
auto src = MP4Reader::onMakeMediaSource(schema,vhost,app,stream,filePath, false); auto src = MP4Reader::onMakeMediaSource(schema,vhost,app,stream,filePath, false);
if(!src){ if(!src){
//文件不存在 //文件不存在
WarnL << "MP4文件不存在:" << filePath; WarnL << "MP4文件不存在:" << filePath;
return; return;
} }
//创建推流器并绑定一个MediaSource //创建推流器并绑定一个MediaSource
pusher.reset(new MediaPusher(src,poller)); pusher.reset(new MediaPusher(src,poller));
//可以指定rtsp推流方式支持tcp和udp方式默认tcp //可以指定rtsp推流方式支持tcp和udp方式默认tcp
// (*pusher)[Client::kRtpType] = Rtsp::RTP_UDP; // (*pusher)[Client::kRtpType] = Rtsp::RTP_UDP;
//设置推流中断处理逻辑 //设置推流中断处理逻辑
pusher->setOnShutdown([poller,schema,vhost,app,stream,filePath, url](const SockException &ex) { pusher->setOnShutdown([poller,schema,vhost,app,stream,filePath, url](const SockException &ex) {
WarnL << "Server connection is closed:" << ex.getErrCode() << " " << ex.what(); WarnL << "Server connection is closed:" << ex.getErrCode() << " " << ex.what();
//重新推流 //重新推流
rePushDelay(poller,schema,vhost,app, stream,filePath, url); rePushDelay(poller,schema,vhost,app, stream,filePath, url);
}); });
//设置发布结果处理逻辑 //设置发布结果处理逻辑
pusher->setOnPublished([poller,schema,vhost,app,stream,filePath, url](const SockException &ex) { pusher->setOnPublished([poller,schema,vhost,app,stream,filePath, url](const SockException &ex) {
if (ex) { if (ex) {
WarnL << "Publish fail:" << ex.getErrCode() << " " << ex.what(); WarnL << "Publish fail:" << ex.getErrCode() << " " << ex.what();
//如果发布失败,就重试 //如果发布失败,就重试
rePushDelay(poller,schema,vhost,app, stream, filePath ,url); rePushDelay(poller,schema,vhost,app, stream, filePath ,url);
}else { }else {
InfoL << "Publish success,Please play with player:" << url; InfoL << "Publish success,Please play with player:" << url;
} }
}); });
pusher->publish(url); pusher->publish(url);
} }
//推流失败或断开延迟2秒后重试推流 //推流失败或断开延迟2秒后重试推流
void rePushDelay(const EventPoller::Ptr &poller, void rePushDelay(const EventPoller::Ptr &poller,
const string &schema, const string &schema,
const string &vhost, const string &vhost,
const string &app, const string &app,
const string &stream, const string &stream,
const string &filePath, const string &filePath,
const string &url) { const string &url) {
g_timer = std::make_shared<Timer>(2,[poller,schema,vhost,app, stream, filePath,url]() { g_timer = std::make_shared<Timer>(2,[poller,schema,vhost,app, stream, filePath,url]() {
InfoL << "Re-Publishing..."; InfoL << "Re-Publishing...";
//重新推流 //重新推流
createPusher(poller,schema,vhost,app, stream, filePath,url); createPusher(poller,schema,vhost,app, stream, filePath,url);
//此任务不重复 //此任务不重复
return false; return false;
}, poller); }, poller);
} }
//这里才是真正执行main函数你可以把函数名(domain)改成main然后就可以输入自定义url了 //这里才是真正执行main函数你可以把函数名(domain)改成main然后就可以输入自定义url了
int domain(const string & filePath,const string & pushUrl){ int domain(const string & filePath,const string & pushUrl){
//设置日志 //设置日志
Logger::Instance().add(std::make_shared<ConsoleChannel>()); Logger::Instance().add(std::make_shared<ConsoleChannel>());
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>()); Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
auto poller = EventPollerPool::Instance().getPoller(); auto poller = EventPollerPool::Instance().getPoller();
//vhost/app/stream可以随便自己填现在不限制app应用名了 //vhost/app/stream可以随便自己填现在不限制app应用名了
createPusher(poller,FindField(pushUrl.data(), nullptr,"://"),DEFAULT_VHOST,"live","stream",filePath,pushUrl); createPusher(poller,FindField(pushUrl.data(), nullptr,"://"),DEFAULT_VHOST,"live","stream",filePath,pushUrl);
//设置退出信号处理函数 //设置退出信号处理函数
static semaphore sem; static semaphore sem;
signal(SIGINT, [](int) { sem.post(); });// 设置退出信号 signal(SIGINT, [](int) { sem.post(); });// 设置退出信号
sem.wait(); sem.wait();
pusher.reset(); pusher.reset();
g_timer.reset(); g_timer.reset();
return 0; return 0;
} }
int main(int argc,char *argv[]){ int main(int argc,char *argv[]){
//可以使用test_server生成的mp4文件 //可以使用test_server生成的mp4文件
//文件使用绝对路径推流url支持rtsp和rtmp //文件使用绝对路径推流url支持rtsp和rtmp
return domain("/Users/xzl/Desktop/bear-1280x720-long.mp4","rtsp://127.0.0.1/live/rtsp_push"); return domain("/Users/xzl/Desktop/bear-1280x720-long.mp4","rtsp://127.0.0.1/live/rtsp_push");
} }

View File

@ -357,6 +357,6 @@ int main(int argc,char *argv[]) {
Recorder::stopAll(); Recorder::stopAll();
lock_guard<mutex> lck(s_mtxFlvRecorder); lock_guard<mutex> lck(s_mtxFlvRecorder);
s_mapFlvRecorder.clear(); s_mapFlvRecorder.clear();
return 0; return 0;
} }