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(MediaKitApi_EXPORTS)
#define API_EXPORT __declspec(dllexport)
#else
#define API_EXPORT __declspec(dllimport)
#endif
#define API_EXPORT __declspec(dllexport)
#else
#define API_EXPORT __declspec(dllimport)
#endif
#define API_CALL __cdecl
#define API_CALL __cdecl
#else
#define API_EXPORT
#define API_CALL

View File

@ -32,41 +32,41 @@ using namespace toolkit;
using namespace mediakit;
API_EXPORT mk_player API_CALL mk_player_create() {
MediaPlayer::Ptr *obj = new MediaPlayer::Ptr(new MediaPlayer());
return obj;
MediaPlayer::Ptr *obj = new MediaPlayer::Ptr(new MediaPlayer());
return obj;
}
API_EXPORT void API_CALL mk_player_release(mk_player ctx) {
assert(ctx);
MediaPlayer::Ptr *obj = (MediaPlayer::Ptr *)ctx;
delete obj;
assert(ctx);
MediaPlayer::Ptr *obj = (MediaPlayer::Ptr *)ctx;
delete obj;
}
API_EXPORT void API_CALL mk_player_set_option(mk_player ctx,const char* key,const char *val){
assert(ctx && key && val);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
string key_str(key), val_str(val);
player->getPoller()->async([key_str,val_str,player](){
//切换线程后再操作
(*player)[key_str] = val_str;
});
assert(ctx && key && val);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
string key_str(key), val_str(val);
player->getPoller()->async([key_str,val_str,player](){
//切换线程后再操作
(*player)[key_str] = val_str;
});
}
API_EXPORT void API_CALL mk_player_play(mk_player ctx, const char *url) {
assert(ctx && url);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
string url_str(url);
player->getPoller()->async([url_str,player](){
//切换线程后再操作
player->play(url_str);
});
assert(ctx && url);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
string url_str(url);
player->getPoller()->async([url_str,player](){
//切换线程后再操作
player->play(url_str);
});
}
API_EXPORT void API_CALL mk_player_pause(mk_player ctx, int pause) {
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
player->getPoller()->async([pause,player](){
//切换线程后再操作
player->pause(pause);
});
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
player->getPoller()->async([pause,player](){
//切换线程后再操作
player->pause(pause);
});
}
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) {
assert(ctx && cb);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
player->getPoller()->async([cb,user_data,type,player](){
//切换线程后再操作
if(type == 0){
player->setOnPlayResult([cb,user_data](const SockException &ex){
cb(user_data,ex.getErrCode(),ex.what());
});
}else{
player->setOnShutdown([cb,user_data](const SockException &ex){
cb(user_data,ex.getErrCode(),ex.what());
});
}
});
assert(ctx && cb);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
player->getPoller()->async([cb,user_data,type,player](){
//切换线程后再操作
if(type == 0){
player->setOnPlayResult([cb,user_data](const SockException &ex){
cb(user_data,ex.getErrCode(),ex.what());
});
}else{
player->setOnShutdown([cb,user_data](const SockException &ex){
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) {
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) {
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) {
assert(ctx && cb);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
player->getPoller()->async([player,cb,user_data](){
//切换线程后再操作
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());
});
for(auto &track : player->getTracks()){
track->addDelegate(delegate);
}
});
assert(ctx && cb);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
player->getPoller()->async([player,cb,user_data](){
//切换线程后再操作
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());
});
for(auto &track : player->getTracks()){
track->addDelegate(delegate);
}
});
}
API_EXPORT int API_CALL mk_player_video_width(mk_player ctx) {
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo));
return track ? track->getVideoWidth() : 0;
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo));
return track ? track->getVideoWidth() : 0;
}
API_EXPORT int API_CALL mk_player_video_height(mk_player ctx) {
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo));
return track ? track->getVideoHeight() : 0;
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo));
return track ? track->getVideoHeight() : 0;
}
API_EXPORT int API_CALL mk_player_video_fps(mk_player ctx) {
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo));
return track ? track->getVideoFps() : 0;
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<VideoTrack>(player->getTrack(TrackVideo));
return track ? track->getVideoFps() : 0;
}
API_EXPORT int API_CALL mk_player_audio_samplerate(mk_player ctx) {
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio));
return track ? track->getAudioSampleRate() : 0;
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio));
return track ? track->getAudioSampleRate() : 0;
}
API_EXPORT int API_CALL mk_player_audio_bit(mk_player ctx) {
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio));
return track ? track->getAudioSampleBit() : 0;
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio));
return track ? track->getAudioSampleBit() : 0;
}
API_EXPORT int API_CALL mk_player_audio_channel(mk_player ctx) {
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio));
return track ? track->getAudioChannel() : 0;
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
auto track = dynamic_pointer_cast<AudioTrack>(player->getTrack(TrackAudio));
return track ? track->getAudioChannel() : 0;
}
API_EXPORT float API_CALL mk_player_duration(mk_player ctx) {
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
return player->getDuration();
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
return player->getDuration();
}
API_EXPORT float API_CALL mk_player_progress(mk_player ctx) {
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
return player->getProgress();
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
return player->getProgress();
}
API_EXPORT float API_CALL mk_player_loss_rate(mk_player ctx, int track_type) {
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
return player->getPacketLossRate((TrackType)track_type);
assert(ctx);
MediaPlayer::Ptr &player = *((MediaPlayer::Ptr *)ctx);
return player->getPacketLossRate((TrackType)track_type);
}

View File

@ -42,7 +42,7 @@ onceToken token([]() {
//windows下先关闭FFmpeg日志(目前不支持日志重定向)
mINI::Instance()[kCmd] = "%s -re -i \"%s\" -loglevel quiet -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s ";
#else
string ffmpeg_bin = System::execute("which ffmpeg");
string ffmpeg_bin = System::execute("which ffmpeg");
mINI::Instance()[kCmd] = "%s -re -i \"%s\" -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s ";
#endif
//默认ffmpeg命令路径为环境变量中路径

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -88,24 +88,24 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
* Type==7:SPS 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
Type Packet Type name Section
---------------------------------------------------------
0 undefined -
1-23 NAL unit Single NAL unit packet per H.264 5.6
24 STAP-A 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
27 MTAP24 Multi-time aggregation packet 5.7.2
28 FU-A Fragmentation unit 5.8
29 FU-B Fragmentation unit 5.8
30-31 undefined -
Type Packet Type name Section
---------------------------------------------------------
0 undefined -
1-23 NAL unit Single NAL unit packet per H.264 5.6
24 STAP-A 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
27 MTAP24 Multi-time aggregation packet 5.7.2
28 FU-A Fragmentation unit 5.8
29 FU-B Fragmentation unit 5.8
30-31 undefined -
*/
*/
const uint8_t *frame = (uint8_t *) rtppack->data() + rtppack->offset;
int length = rtppack->size() - rtppack->offset;
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_HEVCSPS tH265SpsInfo;
T_HEVCVPS tH265VpsInfo;
if ( vps_len > 2 ){
memset(&tGetBitBuf,0,sizeof(tGetBitBuf));
memset(&tH265VpsInfo,0,sizeof(tH265VpsInfo));
tGetBitBuf.pu8Buf = (uint8_t*)vps+2;
tGetBitBuf.iBufSize = vps_len-2;
if(0 != h265DecVideoParameterSet((void *) &tGetBitBuf, &tH265VpsInfo)){
return false;
}
}
if ( vps_len > 2 ){
memset(&tGetBitBuf,0,sizeof(tGetBitBuf));
memset(&tH265VpsInfo,0,sizeof(tH265VpsInfo));
tGetBitBuf.pu8Buf = (uint8_t*)vps+2;
tGetBitBuf.iBufSize = vps_len-2;
if(0 != h265DecVideoParameterSet((void *) &tGetBitBuf, &tH265VpsInfo)){
return false;
}
}
if ( sps_len > 2 ){
memset(&tGetBitBuf,0,sizeof(tGetBitBuf));
memset(&tH265SpsInfo,0,sizeof(tH265SpsInfo));
tGetBitBuf.pu8Buf = (uint8_t*)sps+2;
tGetBitBuf.iBufSize = sps_len-2;
if(0 != h265DecSeqParameterSet((void *) &tGetBitBuf, &tH265SpsInfo)){
return false;
}
}
else
return false;
if ( sps_len > 2 ){
memset(&tGetBitBuf,0,sizeof(tGetBitBuf));
memset(&tH265SpsInfo,0,sizeof(tH265SpsInfo));
tGetBitBuf.pu8Buf = (uint8_t*)sps+2;
tGetBitBuf.iBufSize = sps_len-2;
if(0 != h265DecSeqParameterSet((void *) &tGetBitBuf, &tH265SpsInfo)){
return false;
}
}
else
return false;
h265GetWidthHeight(&tH265SpsInfo, &iVideoWidth, &iVideoHeight);
iVideoFps = 0;
iVideoFps = 0;
h265GeFramerate(&tH265VpsInfo, &tH265SpsInfo, &iVideoFps);
// ErrorL << iVideoWidth << " " << iVideoHeight << " " << iVideoFps;
return true;
}
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() {

View File

@ -202,7 +202,7 @@ public:
_vps = vps.substr(vps_prefix_len);
_sps = sps.substr(sps_prefix_len);
_pps = pps.substr(pps_prefix_len);
onReady();
onReady();
}
/**
@ -267,10 +267,10 @@ public:
* @param frame
*/
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){
bool first_frame = true;
splitH264(frame->data() + frame->prefixSize(),
bool first_frame = true;
splitH264(frame->data() + frame->prefixSize(),
frame->size() - frame->prefixSize(),
[&](const char *ptr, int len){
if(first_frame){
@ -288,9 +288,9 @@ public:
inputFrame_l(sub_frame);
}
});
}else{
inputFrame_l(frame);
}
}else{
inputFrame_l(frame);
}
}
private:
@ -336,7 +336,7 @@ private:
}
}
/**
/**
* sps获取宽高fps
*/
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 iVuiPresent;
int iVuiPresent;
}T_HEVCSPS;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -33,30 +33,30 @@ namespace mediakit {
class HttpDownloader: public HttpClientImp {
public:
typedef std::shared_ptr<HttpDownloader> Ptr;
typedef std::function<void(ErrCode code,const string &errMsg,const string &filePath)> onDownloadResult;
HttpDownloader();
virtual ~HttpDownloader();
//开始下载文件,默认断点续传方式下载
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){
setOnResult(cb);
startDownload(url,"",false,timeOutSecond);
}
void setOnResult(const onDownloadResult &cb){
_onResult = cb;
}
typedef std::shared_ptr<HttpDownloader> Ptr;
typedef std::function<void(ErrCode code,const string &errMsg,const string &filePath)> onDownloadResult;
HttpDownloader();
virtual ~HttpDownloader();
//开始下载文件,默认断点续传方式下载
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){
setOnResult(cb);
startDownload(url,"",false,timeOutSecond);
}
void setOnResult(const onDownloadResult &cb){
_onResult = cb;
}
private:
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 onResponseCompleted() override;
void onDisconnect(const SockException &ex) 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 onResponseCompleted() override;
void onDisconnect(const SockException &ex) override;
void closeFile();
private:
FILE *_saveFile = nullptr;
string _filePath;
onDownloadResult _onResult;
bool _bDownloadSuccess = false;
FILE *_saveFile = nullptr;
string _filePath;
onDownloadResult _onResult;
bool _bDownloadSuccess = false;
};
} /* namespace mediakit */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -43,59 +43,59 @@ namespace mediakit {
class DemuxerBase : public TrackSource{
public:
typedef std::shared_ptr<DemuxerBase> Ptr;
typedef std::shared_ptr<DemuxerBase> Ptr;
/**
*
* @return
*/
virtual float getDuration() const { return 0;}
/**
*
* @return
*/
virtual float getDuration() const { return 0;}
/**
* getTrack方法
* @param analysisMs
* @return
*/
virtual bool isInited(int analysisMs) { return true; }
/**
* getTrack方法
* @param analysisMs
* @return
*/
virtual bool isInited(int analysisMs) { return true; }
};
class PlayerBase : public DemuxerBase, public mINI{
public:
typedef std::shared_ptr<PlayerBase> Ptr;
typedef std::shared_ptr<PlayerBase> Ptr;
static Ptr createPlayer(const EventPoller::Ptr &poller,const string &strUrl);
PlayerBase();
virtual ~PlayerBase(){}
PlayerBase();
virtual ~PlayerBase(){}
/**
*
* @param strUrl urlrtsp/rtmp
*/
virtual void play(const string &strUrl) {}
/**
*
* @param strUrl urlrtsp/rtmp
*/
virtual void play(const string &strUrl) {}
/**
*
* @param bPause
*/
virtual void pause(bool bPause) {}
/**
*
* @param bPause
*/
virtual void pause(bool bPause) {}
/**
*
*/
virtual void teardown() {}
/**
*
*/
virtual void teardown() {}
/**
*
* @param cb
*/
virtual void setOnShutdown( const function<void(const SockException &)> &cb) {}
/**
*
* @param cb
*/
virtual void setOnShutdown( const function<void(const SockException &)> &cb) {}
/**
*
* @param cb
*/
virtual void setOnPlayResult( const function<void(const SockException &ex)> &cb) {}
/**
*
* @param cb
*/
virtual void setOnPlayResult( const function<void(const SockException &ex)> &cb) {}
/**
*
@ -103,10 +103,10 @@ public:
*/
virtual void setOnResume( const function<void()> &cb) {}
/**
* 0.0 ~ 1.0
* @return
*/
/**
* 0.0 ~ 1.0
* @return
*/
virtual float getProgress() const { return 0;}
/**
@ -126,7 +126,7 @@ public:
* @param trackType TrackInvalid时为总丢包率
* @return
*/
virtual float getPacketLossRate(TrackType trackType) const {return 0; }
virtual float getPacketLossRate(TrackType trackType) const {return 0; }
/**
* track
@ -146,24 +146,24 @@ protected:
template<typename Parent,typename Delegate>
class PlayerImp : public Parent {
public:
typedef std::shared_ptr<PlayerImp> Ptr;
typedef std::shared_ptr<PlayerImp> Ptr;
template<typename ...ArgsType>
PlayerImp(ArgsType &&...args):Parent(std::forward<ArgsType>(args)...){}
template<typename ...ArgsType>
PlayerImp(ArgsType &&...args):Parent(std::forward<ArgsType>(args)...){}
virtual ~PlayerImp(){}
void setOnShutdown(const function<void(const SockException &)> &cb) override {
if (_delegate) {
_delegate->setOnShutdown(cb);
}
_shutdownCB = cb;
}
void setOnPlayResult(const function<void(const SockException &ex)> &cb) override {
if (_delegate) {
_delegate->setOnPlayResult(cb);
}
_playResultCB = cb;
}
virtual ~PlayerImp(){}
void setOnShutdown(const function<void(const SockException &)> &cb) override {
if (_delegate) {
_delegate->setOnShutdown(cb);
}
_shutdownCB = cb;
}
void setOnPlayResult(const function<void(const SockException &ex)> &cb) override {
if (_delegate) {
_delegate->setOnPlayResult(cb);
}
_playResultCB = cb;
}
void setOnResume(const function<void()> &cb) override {
if (_delegate) {
@ -178,12 +178,12 @@ public:
}
return Parent::isInited(analysisMs);
}
float getDuration() const override {
if (_delegate) {
return _delegate->getDuration();
}
return Parent::getDuration();
}
float getDuration() const override {
if (_delegate) {
return _delegate->getDuration();
}
return Parent::getDuration();
}
float getProgress() const override{
if (_delegate) {
return _delegate->getProgress();
@ -198,95 +198,95 @@ public:
}
void setMediaSouce(const MediaSource::Ptr & src) override {
if (_delegate) {
_delegate->setMediaSouce(src);
}
_pMediaSrc = src;
if (_delegate) {
_delegate->setMediaSouce(src);
}
_pMediaSrc = src;
}
vector<Track::Ptr> getTracks(bool trackReady = true) const override{
if (_delegate) {
return _delegate->getTracks(trackReady);
}
return Parent::getTracks(trackReady);
}
if (_delegate) {
return _delegate->getTracks(trackReady);
}
return Parent::getTracks(trackReady);
}
protected:
void onShutdown(const SockException &ex) override {
if (_shutdownCB) {
_shutdownCB(ex);
_shutdownCB = nullptr;
}
}
void onShutdown(const SockException &ex) override {
if (_shutdownCB) {
_shutdownCB(ex);
_shutdownCB = nullptr;
}
}
void onPlayResult(const SockException &ex) override {
if(_playResultCB) {
_playResultCB(ex);
_playResultCB = nullptr;
}
}
void onPlayResult(const SockException &ex) override {
if(_playResultCB) {
_playResultCB(ex);
_playResultCB = nullptr;
}
}
void onResume() override{
void onResume() override{
if(_resumeCB){
_resumeCB();
}
}
protected:
function<void(const SockException &ex)> _shutdownCB;
function<void(const SockException &ex)> _playResultCB;
function<void(const SockException &ex)> _shutdownCB;
function<void(const SockException &ex)> _playResultCB;
function<void()> _resumeCB;
std::shared_ptr<Delegate> _delegate;
MediaSource::Ptr _pMediaSrc;
MediaSource::Ptr _pMediaSrc;
};
class Demuxer : public PlayerBase{
public:
class Listener{
public:
Listener() = default;
virtual ~Listener() = default;
virtual void onAddTrack(const Track::Ptr &track) = 0;
};
class Listener{
public:
Listener() = default;
virtual ~Listener() = default;
virtual void onAddTrack(const Track::Ptr &track) = 0;
};
Demuxer(){};
virtual ~Demuxer(){};
Demuxer(){};
virtual ~Demuxer(){};
/**
*
* RtspDemuxer对象时有些rtsp的sdp不包含sps pps信息
* sps的rtp包后才能完成
*
* RtmpDemuxer对象时是无法获取sps pps aac_cfg等这些信息
* inputRtmp后才会获取到这些信息
* @param analysisMs
* @return
*/
bool isInited(int analysisMs) override;
/**
*
* RtspDemuxer对象时有些rtsp的sdp不包含sps pps信息
* sps的rtp包后才能完成
*
* RtmpDemuxer对象时是无法获取sps pps aac_cfg等这些信息
* inputRtmp后才会获取到这些信息
* @param analysisMs
* @return
*/
bool isInited(int analysisMs) override;
/**
* Track
* @return Track
*/
vector<Track::Ptr> getTracks(bool trackReady = true) const override;
/**
* Track
* @return Track
*/
vector<Track::Ptr> getTracks(bool trackReady = true) const override;
/**
*
* @return ,
*/
float getDuration() const override;
/**
*
* @return ,
*/
float getDuration() const override;
/**
* track监听器
*/
void setTrackListener(Listener *listener);
/**
* track监听器
*/
void setTrackListener(Listener *listener);
protected:
void onAddTrack(const Track::Ptr &track);
void onAddTrack(const Track::Ptr &track);
protected:
Listener *_listener = nullptr;
AudioTrack::Ptr _audioTrack;
VideoTrack::Ptr _videoTrack;
Ticker _ticker;
float _fDuration = 0;
Listener *_listener = nullptr;
AudioTrack::Ptr _audioTrack;
VideoTrack::Ptr _videoTrack;
Ticker _ticker;
float _fDuration = 0;
};
} /* 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,
const string &strApp,
const string &strSrc,
bool bEnableRtsp,
bool bEnableRtmp,
bool bEnableRtsp,
bool bEnableRtmp,
bool bEnableHls,
bool bEnableMp4,
int iRetryCount,
const EventPoller::Ptr &poller) : MediaPlayer(poller){
_strVhost = strVhost;
_strApp = strApp;
_strSrc = strSrc;
_bEnableRtsp = bEnableRtsp;
_bEnableRtmp = bEnableRtmp;
const EventPoller::Ptr &poller) : MediaPlayer(poller){
_strVhost = strVhost;
_strApp = strApp;
_strSrc = strSrc;
_bEnableRtsp = bEnableRtsp;
_bEnableRtmp = bEnableRtmp;
_bEnableHls = bEnableHls;
_bEnableMp4 = bEnableMp4;
_iRetryCount = iRetryCount;
@ -90,88 +90,88 @@ void PlayerProxy::setOnClose(const function<void()> &cb){
}
void PlayerProxy::play(const string &strUrlTmp) {
weak_ptr<PlayerProxy> weakSelf = shared_from_this();
std::shared_ptr<int> piFailedCnt(new int(0)); //连续播放失败次数
setOnPlayResult([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) {
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
weak_ptr<PlayerProxy> weakSelf = shared_from_this();
std::shared_ptr<int> piFailedCnt(new int(0)); //连续播放失败次数
setOnPlayResult([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) {
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
if(strongSelf->_playCB) {
if(strongSelf->_playCB) {
strongSelf->_playCB(err);
strongSelf->_playCB = nullptr;
}
if(!err) {
// 播放成功
*piFailedCnt = 0;//连续播放失败次数清0
strongSelf->onPlaySuccess();
}else if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) {
// 播放失败,延时重试播放
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
}
});
setOnShutdown([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) {
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
if(strongSelf->_mediaMuxer) {
auto tracks = strongSelf->getTracks(false);
for (auto & track : tracks){
track->delDelegate(strongSelf->_mediaMuxer.get());
}
if(!err) {
// 播放成功
*piFailedCnt = 0;//连续播放失败次数清0
strongSelf->onPlaySuccess();
}else if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) {
// 播放失败,延时重试播放
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
}
});
setOnShutdown([weakSelf,strUrlTmp,piFailedCnt](const SockException &err) {
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return;
}
if(strongSelf->_mediaMuxer) {
auto tracks = strongSelf->getTracks(false);
for (auto & track : tracks){
track->delDelegate(strongSelf->_mediaMuxer.get());
}
GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay);
if (resetWhenRePlay) {
strongSelf->_mediaMuxer.reset();
} else {
strongSelf->_mediaMuxer->resetTracks();
}
}
//播放异常中断,延时重试播放
if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) {
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
}
});
MediaPlayer::play(strUrlTmp);
GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay);
if (resetWhenRePlay) {
strongSelf->_mediaMuxer.reset();
} else {
strongSelf->_mediaMuxer->resetTracks();
}
}
//播放异常中断,延时重试播放
if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) {
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
}
});
MediaPlayer::play(strUrlTmp);
MediaSource::Ptr mediaSource;
if(dynamic_pointer_cast<RtspPlayer>(_delegate)){
//rtsp拉流
GET_CONFIG(bool,directProxy,Rtsp::kDirectProxy);
if(directProxy && _bEnableRtsp){
mediaSource = std::make_shared<RtspMediaSource>(_strVhost,_strApp,_strSrc);
}
} else if(dynamic_pointer_cast<RtmpPlayer>(_delegate)){
//rtmp拉流
if(_bEnableRtmp){
mediaSource = std::make_shared<RtmpMediaSource>(_strVhost,_strApp,_strSrc);
}
}
if(mediaSource){
setMediaSouce(mediaSource);
mediaSource->setListener(shared_from_this());
}
MediaSource::Ptr mediaSource;
if(dynamic_pointer_cast<RtspPlayer>(_delegate)){
//rtsp拉流
GET_CONFIG(bool,directProxy,Rtsp::kDirectProxy);
if(directProxy && _bEnableRtsp){
mediaSource = std::make_shared<RtspMediaSource>(_strVhost,_strApp,_strSrc);
}
} else if(dynamic_pointer_cast<RtmpPlayer>(_delegate)){
//rtmp拉流
if(_bEnableRtmp){
mediaSource = std::make_shared<RtmpMediaSource>(_strVhost,_strApp,_strSrc);
}
}
if(mediaSource){
setMediaSouce(mediaSource);
mediaSource->setListener(shared_from_this());
}
}
PlayerProxy::~PlayerProxy() {
_timer.reset();
_timer.reset();
}
void PlayerProxy::rePlay(const string &strUrl,int iFailedCnt){
auto iDelay = MAX(2 * 1000, MIN(iFailedCnt * 3000, 60*1000));
weak_ptr<PlayerProxy> weakSelf = shared_from_this();
_timer = std::make_shared<Timer>(iDelay / 1000.0f,[weakSelf,strUrl,iFailedCnt]() {
//播放失败次数越多,则延时越长
auto strongPlayer = weakSelf.lock();
if(!strongPlayer) {
return false;
}
WarnL << "重试播放[" << iFailedCnt << "]:" << strUrl;
strongPlayer->MediaPlayer::play(strUrl);
return false;
}, getPoller());
auto iDelay = MAX(2 * 1000, MIN(iFailedCnt * 3000, 60*1000));
weak_ptr<PlayerProxy> weakSelf = shared_from_this();
_timer = std::make_shared<Timer>(iDelay / 1000.0f,[weakSelf,strUrl,iFailedCnt]() {
//播放失败次数越多,则延时越长
auto strongPlayer = weakSelf.lock();
if(!strongPlayer) {
return false;
}
WarnL << "重试播放[" << iFailedCnt << "]:" << strUrl;
strongPlayer->MediaPlayer::play(strUrl);
return false;
}, getPoller());
}
bool PlayerProxy::close(MediaSource &sender,bool force) {
@ -179,19 +179,19 @@ bool PlayerProxy::close(MediaSource &sender,bool force) {
return false;
}
//通知其停止推流
weak_ptr<PlayerProxy> weakSlef = dynamic_pointer_cast<PlayerProxy>(shared_from_this());
getPoller()->async_first([weakSlef]() {
auto stronSelf = weakSlef.lock();
if (stronSelf) {
stronSelf->_mediaMuxer.reset();
stronSelf->setMediaSouce(nullptr);
stronSelf->teardown();
if(stronSelf->_onClose){
//通知其停止推流
weak_ptr<PlayerProxy> weakSlef = dynamic_pointer_cast<PlayerProxy>(shared_from_this());
getPoller()->async_first([weakSlef]() {
auto stronSelf = weakSlef.lock();
if (stronSelf) {
stronSelf->_mediaMuxer.reset();
stronSelf->setMediaSouce(nullptr);
stronSelf->teardown();
if(stronSelf->_onClose){
stronSelf->_onClose();
}
}
});
}
}
});
WarnL << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force;
return true;
}
@ -208,90 +208,90 @@ int PlayerProxy::totalReaderCount(){
}
int PlayerProxy::totalReaderCount(MediaSource &sender) {
return totalReaderCount();
return totalReaderCount();
}
class MuteAudioMaker : public FrameDispatcher{
public:
typedef std::shared_ptr<MuteAudioMaker> Ptr;
typedef std::shared_ptr<MuteAudioMaker> Ptr;
MuteAudioMaker(){};
virtual ~MuteAudioMaker(){}
void inputFrame(const Frame::Ptr &frame) override {
if(frame->getTrackType() == TrackVideo){
auto iAudioIndex = frame->dts() / MUTE_ADTS_DATA_MS;
if(_iAudioIndex != iAudioIndex){
_iAudioIndex = iAudioIndex;
auto aacFrame = std::make_shared<AACFrameCacheAble>((char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS);
FrameDispatcher::inputFrame(aacFrame);
}
}
}
MuteAudioMaker(){};
virtual ~MuteAudioMaker(){}
void inputFrame(const Frame::Ptr &frame) override {
if(frame->getTrackType() == TrackVideo){
auto iAudioIndex = frame->dts() / MUTE_ADTS_DATA_MS;
if(_iAudioIndex != iAudioIndex){
_iAudioIndex = iAudioIndex;
auto aacFrame = std::make_shared<AACFrameCacheAble>((char *)MUTE_ADTS_DATA, MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS);
FrameDispatcher::inputFrame(aacFrame);
}
}
}
private:
class AACFrameCacheAble : public AACFrameNoCacheAble{
public:
template <typename ... ARGS>
AACFrameCacheAble(ARGS && ...args) : AACFrameNoCacheAble(std::forward<ARGS>(args)...){};
virtual ~AACFrameCacheAble() = default;
class AACFrameCacheAble : public AACFrameNoCacheAble{
public:
template <typename ... ARGS>
AACFrameCacheAble(ARGS && ...args) : AACFrameNoCacheAble(std::forward<ARGS>(args)...){};
virtual ~AACFrameCacheAble() = default;
bool cacheAble() const override {
return true;
}
};
bool cacheAble() const override {
return true;
}
};
private:
int _iAudioIndex = 0;
int _iAudioIndex = 0;
};
void PlayerProxy::onPlaySuccess() {
GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay);
if (dynamic_pointer_cast<RtspMediaSource>(_pMediaSrc)) {
//rtsp拉流代理
if (resetWhenRePlay || !_mediaMuxer) {
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), false, _bEnableRtmp, _bEnableHls, _bEnableMp4));
}
} else if (dynamic_pointer_cast<RtmpMediaSource>(_pMediaSrc)) {
//rtmp拉流代理
if (resetWhenRePlay || !_mediaMuxer) {
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, false, _bEnableHls, _bEnableMp4));
}
} else {
//其他拉流代理
if (resetWhenRePlay || !_mediaMuxer) {
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, _bEnableRtmp, _bEnableHls, _bEnableMp4));
}
}
_mediaMuxer->setListener(shared_from_this());
GET_CONFIG(bool,resetWhenRePlay,General::kResetWhenRePlay);
if (dynamic_pointer_cast<RtspMediaSource>(_pMediaSrc)) {
//rtsp拉流代理
if (resetWhenRePlay || !_mediaMuxer) {
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), false, _bEnableRtmp, _bEnableHls, _bEnableMp4));
}
} else if (dynamic_pointer_cast<RtmpMediaSource>(_pMediaSrc)) {
//rtmp拉流代理
if (resetWhenRePlay || !_mediaMuxer) {
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, false, _bEnableHls, _bEnableMp4));
}
} else {
//其他拉流代理
if (resetWhenRePlay || !_mediaMuxer) {
_mediaMuxer.reset(new MultiMediaSourceMuxer(_strVhost, _strApp, _strSrc, getDuration(), _bEnableRtsp, _bEnableRtmp, _bEnableHls, _bEnableMp4));
}
}
_mediaMuxer->setListener(shared_from_this());
auto videoTrack = getTrack(TrackVideo,false);
if(videoTrack){
//添加视频
_mediaMuxer->addTrack(videoTrack);
//视频数据写入_mediaMuxer
videoTrack->addDelegate(_mediaMuxer);
}
auto videoTrack = getTrack(TrackVideo,false);
if(videoTrack){
//添加视频
_mediaMuxer->addTrack(videoTrack);
//视频数据写入_mediaMuxer
videoTrack->addDelegate(_mediaMuxer);
}
//是否添加静音音频
GET_CONFIG(bool,addMuteAudio,General::kAddMuteAudio);
//是否添加静音音频
GET_CONFIG(bool,addMuteAudio,General::kAddMuteAudio);
auto audioTrack = getTrack(TrackAudio, false);
if(audioTrack){
//添加音频
_mediaMuxer->addTrack(audioTrack);
//音频数据写入_mediaMuxer
auto audioTrack = getTrack(TrackAudio, false);
if(audioTrack){
//添加音频
_mediaMuxer->addTrack(audioTrack);
//音频数据写入_mediaMuxer
audioTrack->addDelegate(_mediaMuxer);
}else if(addMuteAudio && videoTrack){
//没有音频信息,产生一个静音音频
MuteAudioMaker::Ptr audioMaker = std::make_shared<MuteAudioMaker>();
//videoTrack把数据写入MuteAudioMaker
videoTrack->addDelegate(audioMaker);
//添加一个静音Track至_mediaMuxer
_mediaMuxer->addTrack(std::make_shared<AACTrack>());
//MuteAudioMaker生成静音音频然后写入_mediaMuxer
audioMaker->addDelegate(_mediaMuxer);
}
//没有音频信息,产生一个静音音频
MuteAudioMaker::Ptr audioMaker = std::make_shared<MuteAudioMaker>();
//videoTrack把数据写入MuteAudioMaker
videoTrack->addDelegate(audioMaker);
//添加一个静音Track至_mediaMuxer
_mediaMuxer->addTrack(std::make_shared<AACTrack>());
//MuteAudioMaker生成静音音频然后写入_mediaMuxer
audioMaker->addDelegate(_mediaMuxer);
}
//添加完毕所有track防止单track情况下最大等待3秒
//添加完毕所有track防止单track情况下最大等待3秒
_mediaMuxer->addTrackCompleted();
if(_pMediaSrc){

View File

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

View File

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

View File

@ -192,7 +192,7 @@ void MP4Muxer::addTrack(const Track::Ptr &track) {
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("\x00\x00\x00\x01", 4) + h264_track->getPps();
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;
}
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("\x00\x00\x00\x01", 4) + h265_track->getSps() +
string("\x00\x00\x00\x01", 4) + h265_track->getPps();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -45,48 +45,48 @@ namespace mediakit{
class MultiCastAddressMaker
{
public:
static MultiCastAddressMaker &Instance();
static MultiCastAddressMaker &Instance();
static bool isMultiCastAddress(uint32_t iAddr){
static uint32_t addrMin = mINI::Instance()[MultiCast::kAddrMin].as<uint32_t>();
static uint32_t addrMax = mINI::Instance()[MultiCast::kAddrMax].as<uint32_t>();
return iAddr >= addrMin && iAddr <= addrMax;
}
static string toString(uint32_t iAddr){
iAddr = htonl(iAddr);
return ::inet_ntoa((struct in_addr &)(iAddr));
}
virtual ~MultiCastAddressMaker(){}
std::shared_ptr<uint32_t> obtain(uint32_t iTry = 10);
static bool isMultiCastAddress(uint32_t iAddr){
static uint32_t addrMin = mINI::Instance()[MultiCast::kAddrMin].as<uint32_t>();
static uint32_t addrMax = mINI::Instance()[MultiCast::kAddrMax].as<uint32_t>();
return iAddr >= addrMin && iAddr <= addrMax;
}
static string toString(uint32_t iAddr){
iAddr = htonl(iAddr);
return ::inet_ntoa((struct in_addr &)(iAddr));
}
virtual ~MultiCastAddressMaker(){}
std::shared_ptr<uint32_t> obtain(uint32_t iTry = 10);
private:
MultiCastAddressMaker(){};
void release(uint32_t iAddr);
uint32_t _iAddr = 0;
recursive_mutex _mtx;
unordered_set<uint32_t> _setBadAddr;
MultiCastAddressMaker(){};
void release(uint32_t iAddr);
uint32_t _iAddr = 0;
recursive_mutex _mtx;
unordered_set<uint32_t> _setBadAddr;
};
class RtpMultiCaster {
public:
typedef std::shared_ptr<RtpMultiCaster> Ptr;
typedef function<void()> onDetach;
virtual ~RtpMultiCaster();
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);
uint16_t getPort(TrackType trackType);
string getIP();
typedef std::shared_ptr<RtpMultiCaster> Ptr;
typedef function<void()> onDetach;
virtual ~RtpMultiCaster();
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);
uint16_t getPort(TrackType trackType);
string getIP();
private:
static recursive_mutex g_mtx;
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 recursive_mutex g_mtx;
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);
std::shared_ptr<uint32_t> _multiAddr;
recursive_mutex _mtx;
unordered_map<void * , onDetach > _mapDetach;
RtspMediaSource::RingType::RingReader::Ptr _pReader;
Socket::Ptr _apUdpSock[2];
struct sockaddr_in _aPeerUdpAddr[2];
std::shared_ptr<uint32_t> _multiAddr;
recursive_mutex _mtx;
unordered_map<void * , onDetach > _mapDetach;
RtspMediaSource::RingType::RingReader::Ptr _pReader;
Socket::Ptr _apUdpSock[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"
#define POP_HEAD(trackidx) \
auto it = _rtp_sort_cache_map[trackidx].begin(); \
onRtpSorted(it->second, trackidx); \
_rtp_sort_cache_map[trackidx].erase(it);
auto it = _rtp_sort_cache_map[trackidx].begin(); \
onRtpSorted(it->second, trackidx); \
_rtp_sort_cache_map[trackidx].erase(it);
#define AV_RB16(x) \
((((const uint8_t*)(x))[0] << 8) | \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -39,12 +39,12 @@ public:
typedef std::shared_ptr<RtspMediaSourceImp> Ptr;
/**
*
* @param vhost
* @param app
* @param id id
* @param ringSize
*/
*
* @param vhost
* @param app
* @param id id
* @param 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->setTrackListener(this);
@ -69,9 +69,9 @@ public:
}
/**
*
* @param listener
*/
*
* @param listener
*/
void setListener(const std::weak_ptr<MediaSourceEvent> &listener) override {
RtspMediaSource::setListener(listener);
if(_muxer){
@ -87,11 +87,11 @@ public:
}
/**
*
* @param enableRtmp rtmp
* @param enableHls hls
* @param enableMP4 mp4录制
*/
*
* @param enableRtmp rtmp
* @param enableHls hls
* @param enableMP4 mp4录制
*/
void setProtocolTranslation(bool enableRtmp,bool enableHls,bool enableMP4){
//不重复生成rtsp
_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 {
if(_muxer){
_muxer->addTrack(track);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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