mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-26 04:31:37 +08:00
初步提交2.0版本,支持虚拟主机
This commit is contained in:
parent
1262c4c51d
commit
bd72a69d33
@ -111,43 +111,6 @@ API_EXPORT int API_CALL initRtmpServer(unsigned short port) {
|
||||
}
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL listenEvent_onPlay(onEventPlay cb,void *userData){
|
||||
NoticeCenter::Instance().addListener((void *)(cb),Config::Broadcast::kBroadcastRtspSessionPlay,
|
||||
[cb,userData](BroadcastRtspSessionPlayArgs){
|
||||
static unordered_map<string, void *> s_timerKeyMap;
|
||||
static mutex s_mtx;
|
||||
uint64_t tag;
|
||||
{
|
||||
lock_guard<mutex> lck(s_mtx);
|
||||
//每个stream随机分配一个内存地址并且不重复
|
||||
tag = (uint64_t)&s_timerKeyMap[stream];
|
||||
}
|
||||
string appTmp(app);
|
||||
string streamTmp(stream);
|
||||
AsyncTaskThread::Instance().CancelTask(tag);
|
||||
int i = 2;
|
||||
AsyncTaskThread::Instance().DoTaskDelay(tag,50,[cb,userData,appTmp,streamTmp,i](){
|
||||
InfoL << "listenEvent_onPlay:" << appTmp << " " << streamTmp << " " << i;
|
||||
cb(userData,appTmp.data(),streamTmp.data());
|
||||
return (--const_cast<int &>(i)) > 0;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL listenEvent_onRegistRtsp(onEventRegistMediaSrc cb,void *userData){
|
||||
NoticeCenter::Instance().addListener((void *)(cb),Config::Broadcast::kBroadcastRtspSrcRegisted,
|
||||
[cb,userData](BroadcastRtspSrcRegistedArgs){
|
||||
cb(userData,app,stream);
|
||||
});
|
||||
}
|
||||
|
||||
API_EXPORT void API_CALL listenEvent_onRegistRtmp(onEventRegistMediaSrc cb,void *userData){
|
||||
NoticeCenter::Instance().addListener((void *)(cb),Config::Broadcast::kBroadcastRtmpSrcRegisted,
|
||||
[cb,userData](BroadcastRtmpSrcRegistedArgs){
|
||||
cb(userData,app,stream);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
API_EXPORT void API_CALL log_printf(LogType level,const char* file, const char* function, int line,const char *fmt,...){
|
||||
LogInfoMaker info((LogLevel)level,file,function,line);
|
||||
|
@ -75,39 +75,6 @@ API_EXPORT int API_CALL initRtspServer(unsigned short port);
|
||||
*/
|
||||
API_EXPORT int API_CALL initRtmpServer(unsigned short port);
|
||||
|
||||
/*
|
||||
* 描述:播放事件回调函数定义
|
||||
* 参数:userData:用户数据指针strApp:应用名,strStream:流名称
|
||||
*/
|
||||
typedef void (API_CALL *onEventPlay)(void *userData,const char *strApp,const char *strStream);
|
||||
|
||||
/*
|
||||
* 描述:监听事件
|
||||
* 参数:cb:回调函数指针,userData:用户数据指针
|
||||
* 返回值:无
|
||||
*/
|
||||
API_EXPORT void API_CALL listenEvent_onPlay(onEventPlay cb,void *userData);
|
||||
|
||||
/*
|
||||
* 描述:注册RTSP事件
|
||||
* 参数:userData:用户数据指针strApp:应用名,strStream:流名称
|
||||
*/
|
||||
typedef void (API_CALL *onEventRegistMediaSrc)(void *userData,const char *strApp,const char *strStream);
|
||||
|
||||
/*
|
||||
* 描述:监听事件
|
||||
* 参数:cb:回调函数指针,userData:用户数据指针
|
||||
* 返回值:无
|
||||
*/
|
||||
API_EXPORT void API_CALL listenEvent_onRegistRtsp(onEventRegistMediaSrc cb,void *userData);
|
||||
|
||||
/*
|
||||
* 描述:监听事件
|
||||
* 参数:cb:回调函数指针,userData:用户数据指针
|
||||
* 返回值:无
|
||||
*/
|
||||
API_EXPORT void API_CALL listenEvent_onRegistRtmp(onEventRegistMediaSrc cb,void *userData);
|
||||
|
||||
|
||||
/////////////////////////日志////////////////////////////////
|
||||
|
||||
|
@ -50,7 +50,7 @@ static onceToken s_token([](){
|
||||
|
||||
//////////////////////////Rtsp media///////////////////////////
|
||||
API_EXPORT MediaContext API_CALL createMedia(const char *appName,const char *mediaName) {
|
||||
DevChannel::Ptr ret(new DevChannel(appName,mediaName));
|
||||
DevChannel::Ptr ret(new DevChannel(DEFAULT_VHOST,appName,mediaName));
|
||||
lock_guard<recursive_mutex> lck(s_mtxMapMedia);
|
||||
s_mapMedia.emplace((void *) (ret.get()), ret);
|
||||
return ret.get();
|
||||
|
@ -43,7 +43,7 @@ static onceToken s_token([](){
|
||||
},nullptr);
|
||||
|
||||
API_EXPORT ProxyPlayerContext API_CALL createProxyPlayer(const char *app,const char *stream,int rtp_type){
|
||||
PlayerProxy::Ptr ret(new PlayerProxy(app,stream));
|
||||
PlayerProxy::Ptr ret(new PlayerProxy(DEFAULT_VHOST,app,stream));
|
||||
(*ret)[RtspPlayer::kRtpType] = rtp_type;
|
||||
|
||||
lock_guard<recursive_mutex> lck(s_mtxMapProxyPlayer);
|
||||
|
@ -34,7 +34,7 @@ using namespace ZL::Thread;
|
||||
class MediaSender {
|
||||
public:
|
||||
static ThreadPool & sendThread() {
|
||||
static ThreadPool pool(1);
|
||||
static ThreadPool pool(1,ThreadPool::PRIORITY_HIGHEST);
|
||||
return pool;
|
||||
}
|
||||
private:
|
||||
|
@ -47,9 +47,8 @@ void loadIniConfig(){
|
||||
}
|
||||
////////////广播名称///////////
|
||||
namespace Broadcast {
|
||||
const char kBroadcastRtspSessionPlay[] = "kBroadcastRtspSessionPlay";
|
||||
const char kBroadcastRtspSrcRegisted[] = "kBroadcastRtspSrcRegisted";
|
||||
const char kBroadcastRtmpSrcRegisted[] = "kBroadcastRtmpSrcRegisted";
|
||||
const char kBroadcastMediaPlayed[] = "kBroadcastMediaPlayed";
|
||||
const char kBroadcastMediaChanged[] = "kBroadcastMediaChanged";
|
||||
const char kBroadcastRecordMP4[] = "kBroadcastRecordMP4";
|
||||
const char kBroadcastHttpRequest[] = "kBroadcastHttpRequest";
|
||||
const char kBroadcastOnGetRtspRealm[] = "kBroadcastOnGetRtspRealm";
|
||||
@ -105,10 +104,6 @@ const char kMaxReqCount[] = HTTP_FIELD"maxReqCount";
|
||||
#endif
|
||||
const char kCharSet[] = HTTP_FIELD"charSet";
|
||||
|
||||
//http 服务器名称
|
||||
#define HTTP_SERVER_NAME "ZLServer"
|
||||
const char kServerName[] = HTTP_FIELD"serverName";
|
||||
|
||||
//http 服务器根目录
|
||||
#define HTTP_ROOT_PATH (exeDir() + "httpRoot")
|
||||
const char kRootPath[] = HTTP_FIELD"rootPath";
|
||||
@ -119,17 +114,12 @@ const char kRootPath[] = HTTP_FIELD"rootPath";
|
||||
"<body bgcolor=\"white\">"\
|
||||
"<center><h1>您访问的资源不存在!</h1></center>"\
|
||||
"<hr><center>"\
|
||||
HTTP_SERVER_NAME\
|
||||
SERVER_NAME\
|
||||
"</center>"\
|
||||
"</body>"\
|
||||
"</html>"
|
||||
const char kNotFound[] = HTTP_FIELD"notFound";
|
||||
|
||||
//HTTP访问url前缀
|
||||
#define HTTP_PREFIX (StrPrinter << "http://" \
|
||||
<< SockUtil::get_local_ip() \
|
||||
<< ":" << HTTP_PORT << endl)
|
||||
const char kHttpPrefix[] = HTTP_FIELD"httpPrefix";
|
||||
|
||||
onceToken token([](){
|
||||
mINI::Instance()[kPort] = HTTP_PORT;
|
||||
@ -139,10 +129,8 @@ onceToken token([](){
|
||||
mINI::Instance()[kKeepAliveSecond] = HTTP_KEEP_ALIVE_SECOND;
|
||||
mINI::Instance()[kMaxReqCount] = HTTP_MAX_REQ_CNT;
|
||||
mINI::Instance()[kCharSet] = HTTP_CHAR_SET;
|
||||
mINI::Instance()[kServerName] = HTTP_SERVER_NAME;
|
||||
mINI::Instance()[kRootPath] = HTTP_ROOT_PATH;
|
||||
mINI::Instance()[kNotFound] = HTTP_NOT_FOUND;
|
||||
mINI::Instance()[kHttpPrefix] = HTTP_PREFIX;
|
||||
},nullptr);
|
||||
|
||||
}//namespace Http
|
||||
@ -154,15 +142,11 @@ namespace Shell {
|
||||
#define SHELL_PORT 9000
|
||||
const char kPort[] = SHELL_FIELD"port";
|
||||
|
||||
#define SHELL_SERVER_NAME "ZLServer"
|
||||
const char kServerName[] = SHELL_FIELD"serverName";
|
||||
|
||||
#define SHELL_MAX_REQ_SIZE 1024
|
||||
const char kMaxReqSize[] = SHELL_FIELD"maxReqSize";
|
||||
|
||||
onceToken token([](){
|
||||
mINI::Instance()[kPort] = SHELL_PORT;
|
||||
mINI::Instance()[kServerName] = SHELL_SERVER_NAME;
|
||||
mINI::Instance()[kMaxReqSize] = SHELL_MAX_REQ_SIZE;
|
||||
},nullptr);
|
||||
} //namespace Shell
|
||||
@ -174,14 +158,10 @@ namespace Rtsp {
|
||||
#define RTSP_PORT 554
|
||||
const char kPort[] = RTSP_FIELD"port";
|
||||
|
||||
#define RTSP_SERVER_NAME "ZLServer"
|
||||
const char kServerName[] = RTSP_FIELD"serverName";
|
||||
|
||||
const char kAuthBasic[] = RTSP_FIELD"authBasic";
|
||||
|
||||
onceToken token([](){
|
||||
mINI::Instance()[kPort] = RTSP_PORT;
|
||||
mINI::Instance()[kServerName] = RTSP_SERVER_NAME;
|
||||
//默认Md5方式认证
|
||||
mINI::Instance()[kAuthBasic] = 0;
|
||||
},nullptr);
|
||||
@ -278,12 +258,6 @@ const char kSampleMS[] = RECORD_FIELD"sampleMS";
|
||||
#define RECORD_FILE_SECOND (10*60)
|
||||
const char kFileSecond[] = RECORD_FIELD"fileSecond";
|
||||
|
||||
//Rtsp访问url前缀
|
||||
#define RECORD_RTSP_PREFIX (StrPrinter << "rtsp://" \
|
||||
<< SockUtil::get_local_ip() \
|
||||
<< ":" << RTSP_PORT << endl)
|
||||
const char kRtspPrefix[] = RECORD_FIELD"rtspPrefix";
|
||||
|
||||
//录制文件路径
|
||||
#define RECORD_FILE_PATH HTTP_ROOT_PATH
|
||||
const char kFilePath[] = RECORD_FIELD"filePath";
|
||||
@ -293,7 +267,6 @@ onceToken token([](){
|
||||
mINI::Instance()[kSampleMS] = RECORD_SAMPLE_MS;
|
||||
mINI::Instance()[kFileSecond] = RECORD_FILE_SECOND;
|
||||
mINI::Instance()[kFilePath] = RECORD_FILE_PATH;
|
||||
mINI::Instance()[kRtspPrefix] = RECORD_RTSP_PREFIX;
|
||||
},nullptr);
|
||||
|
||||
} //namespace Record
|
||||
@ -318,11 +291,21 @@ const char kFileBufSize[] = HLS_FIELD"fileBufSize";
|
||||
#define HLS_FILE_PATH (HTTP_ROOT_PATH)
|
||||
const char kFilePath[] = HLS_FIELD"filePath";
|
||||
|
||||
//HTTP访问url前缀
|
||||
#define HTTP_PREFIX (StrPrinter << "http://${" << VHOST_KEY << "}:" << HTTP_PORT << endl)
|
||||
const char kHttpPrefix[] = HLS_FIELD"httpPrefix";
|
||||
|
||||
#define HTTP_PREFIX_DEFAULT_VHOST (StrPrinter << "http://" << SockUtil::get_local_ip() << ":" << HTTP_PORT << endl)
|
||||
const char kHttpPrefixDefaultVhost[] = HLS_FIELD"httpPrefixDefaultVhost";
|
||||
|
||||
onceToken token([](){
|
||||
mINI::Instance()[kSegmentDuration] = HLS_SEGMENT_DURATION;
|
||||
mINI::Instance()[kSegmentNum] = HLS_SEGMENT_NUM;
|
||||
mINI::Instance()[kFileBufSize] = HLS_FILE_BUF_SIZE;
|
||||
mINI::Instance()[kFilePath] = HLS_FILE_PATH;
|
||||
mINI::Instance()[kHttpPrefix] = HTTP_PREFIX;
|
||||
mINI::Instance()[kHttpPrefixDefaultVhost] = HTTP_PREFIX_DEFAULT_VHOST;
|
||||
|
||||
},nullptr);
|
||||
|
||||
} //namespace Hls
|
||||
|
@ -25,8 +25,8 @@
|
||||
*/
|
||||
|
||||
|
||||
#ifndef appConfig_h
|
||||
#define appConfig_h
|
||||
#ifndef COMMON_CONFIG_H
|
||||
#define COMMON_CONFIG_H
|
||||
|
||||
#include "Util/mini.h"
|
||||
using namespace ZL::Util;
|
||||
@ -35,12 +35,7 @@ namespace Config {
|
||||
|
||||
void loadIniConfig();
|
||||
////////////TCP最大连接数///////////
|
||||
#ifdef __x86_64__
|
||||
#define MAX_TCP_SESSION 100000
|
||||
#else
|
||||
#define MAX_TCP_SESSION 128
|
||||
#endif
|
||||
|
||||
////////////其他宏定义///////////
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b) )
|
||||
@ -54,17 +49,21 @@ void loadIniConfig();
|
||||
#define CLEAR_ARR(arr) for(auto &item : arr){ item = 0;}
|
||||
#endif //CLEAR_ARR
|
||||
|
||||
#define SERVER_NAME "ZLMediaKit"
|
||||
#define VHOST_KEY "vhost"
|
||||
#define RTSP_SCHEMA "rtsp"
|
||||
#define RTMP_SCHEMA "rtmp"
|
||||
#define DEFAULT_VHOST "__defaultVhost__"
|
||||
#define RTSP_VERSION 1.30
|
||||
#define RTSP_BUILDTIME __DATE__" CST"
|
||||
|
||||
////////////广播名称///////////
|
||||
namespace Broadcast {
|
||||
extern const char kBroadcastRtspSessionPlay[];
|
||||
#define BroadcastRtspSessionPlayArgs const char *app,const char *stream
|
||||
extern const char kBroadcastMediaPlayed[];
|
||||
#define BroadcastMediaPlayedArgs const char *schema,const char *vhost,const char *app,const char *stream
|
||||
|
||||
extern const char kBroadcastRtspSrcRegisted[];
|
||||
#define BroadcastRtspSrcRegistedArgs const char *app,const char *stream
|
||||
|
||||
extern const char kBroadcastRtmpSrcRegisted[];
|
||||
#define BroadcastRtmpSrcRegistedArgs const char *app,const char *stream
|
||||
extern const char kBroadcastMediaChanged[];
|
||||
#define BroadcastMediaChangedArgs bool bRegist, const char *schema,const char *vhost,const char *app,const char *stream
|
||||
|
||||
extern const char kBroadcastRecordMP4[];
|
||||
#define BroadcastRecordMP4Args const Mp4Info &info
|
||||
@ -103,29 +102,22 @@ extern const char kKeepAliveSecond[];
|
||||
extern const char kMaxReqCount[];
|
||||
//http 字符编码
|
||||
extern const char kCharSet[];
|
||||
//http 服务器名称
|
||||
extern const char kServerName[];
|
||||
//http 服务器根目录
|
||||
extern const char kRootPath[];
|
||||
//http 404错误提示内容
|
||||
extern const char kNotFound[];
|
||||
//HTTP访问url前缀
|
||||
extern const char kHttpPrefix[];
|
||||
|
||||
}//namespace Http
|
||||
|
||||
////////////SHELL配置///////////
|
||||
namespace Shell {
|
||||
extern const char kServerName[];
|
||||
extern const char kMaxReqSize[];
|
||||
extern const char kPort[];
|
||||
} //namespace Shell
|
||||
|
||||
////////////RTSP服务器配置///////////
|
||||
namespace Rtsp {
|
||||
#define RTSP_VERSION 1.30
|
||||
#define RTSP_BUILDTIME __DATE__" CST"
|
||||
|
||||
extern const char kServerName[];
|
||||
extern const char kPort[];
|
||||
//是否优先base64方式认证?默认Md5方式认证
|
||||
extern const char kAuthBasic[];
|
||||
@ -171,8 +163,6 @@ extern const char kAppName[];
|
||||
extern const char kSampleMS[];
|
||||
//MP4文件录制大小,不能太大,否则MP4Close函数执行事件太长
|
||||
extern const char kFileSecond[];
|
||||
//Rtsp访问url前缀
|
||||
extern const char kRtspPrefix[];
|
||||
//录制文件路径
|
||||
extern const char kFilePath[];
|
||||
} //namespace Record
|
||||
@ -187,8 +177,12 @@ extern const char kSegmentNum[];
|
||||
extern const char kFileBufSize[];
|
||||
//录制文件路径
|
||||
extern const char kFilePath[];
|
||||
//HTTP访问url前缀
|
||||
extern const char kHttpPrefix[];
|
||||
//HTTP默认vhost访问url前缀
|
||||
extern const char kHttpPrefixDefaultVhost[];
|
||||
} //namespace Hls
|
||||
|
||||
} // namespace Config
|
||||
|
||||
#endif /* appConfig_h */
|
||||
#endif /* COMMON_CONFIG_H */
|
||||
|
@ -36,28 +36,22 @@ using namespace ZL::Util;
|
||||
namespace ZL {
|
||||
namespace DEV {
|
||||
|
||||
DevChannel::DevChannel(const char *strVhost,const char *strApp, const char *strId,float fDuration,bool bLiveStream ) :
|
||||
RtspToRtmpMediaSource(strVhost,strApp,strId , bLiveStream) {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef ENABLE_RTSP2RTMP
|
||||
DevChannel::DevChannel(const char *strApp, const char *strId,float fDuration,bool bLiveStream ) :
|
||||
m_mediaSrc(new RtspToRtmpMediaSource(strApp,strId , bLiveStream)) {
|
||||
#else
|
||||
DevChannel::DevChannel(const char *strApp, const char *strId,float fDuration,bool bLiveStream ) :
|
||||
m_mediaSrc(new RtspToRtmpMediaSource(strApp,strId )) {
|
||||
#endif //ENABLE_RTSP2RTMP
|
||||
m_strSDP = "v=0\r\n";
|
||||
m_strSDP += "o=- 1383190487994921 1 IN IP4 0.0.0.0\r\n";
|
||||
m_strSDP += "s=RTSP Session, streamed by the ZL\r\n";
|
||||
m_strSDP += "i=ZL Live Stream\r\n";
|
||||
m_strSDP += "c=IN IP4 0.0.0.0\r\n";
|
||||
m_strSDP += "t=0 0\r\n";
|
||||
m_strSdp = "v=0\r\n";
|
||||
m_strSdp += "o=- 1383190487994921 1 IN IP4 0.0.0.0\r\n";
|
||||
m_strSdp += "s=RTSP Session, streamed by the ZL\r\n";
|
||||
m_strSdp += "i=ZL Live Stream\r\n";
|
||||
m_strSdp += "c=IN IP4 0.0.0.0\r\n";
|
||||
m_strSdp += "t=0 0\r\n";
|
||||
//直播,时间长度永远
|
||||
if(fDuration <= 0 || bLiveStream){
|
||||
m_strSDP += "a=range:npt=0-\r\n";
|
||||
m_strSdp += "a=range:npt=0-\r\n";
|
||||
}else{
|
||||
m_strSDP += StrPrinter <<"a=range:npt=0-" << fDuration << "\r\n" << endl;
|
||||
m_strSdp += StrPrinter <<"a=range:npt=0-" << fDuration << "\r\n" << endl;
|
||||
}
|
||||
m_strSDP += "a=control:*\r\n";
|
||||
m_strSdp += "a=control:*\r\n";
|
||||
}
|
||||
DevChannel::~DevChannel() {
|
||||
}
|
||||
@ -110,7 +104,7 @@ void DevChannel::inputH264(char* pcData, int iDataLen, uint32_t uiStamp) {
|
||||
uint32_t ui32Ssrc;
|
||||
memcpy(&ui32Ssrc, makeRandStr(4, false).data(), 4);
|
||||
auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) {
|
||||
m_mediaSrc->onGetRTP(pkt,bKeyPos);
|
||||
onGetRTP(pkt,bKeyPos);
|
||||
};
|
||||
static uint32_t videoMtu = mINI::Instance()[Config::Rtp::kVideoMtuSize].as<uint32_t>();
|
||||
m_pRtpMaker_h264.reset(new RtpMaker_H264(lam, ui32Ssrc,videoMtu));
|
||||
@ -133,7 +127,7 @@ void DevChannel::inputAAC(char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp
|
||||
uint32_t ssrc;
|
||||
memcpy(&ssrc, makeRandStr(8, false).data() + 4, 4);
|
||||
auto lam = [this](const RtpPacket::Ptr &pkt, bool keyPos) {
|
||||
m_mediaSrc->onGetRTP(pkt,keyPos);
|
||||
onGetRTP(pkt,keyPos);
|
||||
};
|
||||
static uint32_t audioMtu = mINI::Instance()[Config::Rtp::kAudioMtuSize].as<uint32_t>();
|
||||
m_pRtpMaker_aac.reset(new RtpMaker_AAC(lam, ssrc, audioMtu,m_audio->iSampleRate));
|
||||
@ -184,47 +178,47 @@ inline void DevChannel::makeSDP_264(unsigned char *pcData, int iDataLen) {
|
||||
}
|
||||
|
||||
//视频通道
|
||||
m_strSDP += StrPrinter << "m=video 0 RTP/AVP "
|
||||
m_strSdp += StrPrinter << "m=video 0 RTP/AVP "
|
||||
<< m_pRtpMaker_h264->getPlayloadType() << "\r\n" << endl;
|
||||
m_strSDP += "b=AS:5100\r\n";
|
||||
m_strSDP += StrPrinter << "a=rtpmap:" << m_pRtpMaker_h264->getPlayloadType()
|
||||
m_strSdp += "b=AS:5100\r\n";
|
||||
m_strSdp += StrPrinter << "a=rtpmap:" << m_pRtpMaker_h264->getPlayloadType()
|
||||
<< " H264/" << m_pRtpMaker_h264->getSampleRate() << "\r\n" << endl;
|
||||
m_strSDP += StrPrinter << "a=fmtp:" << m_pRtpMaker_h264->getPlayloadType()
|
||||
m_strSdp += StrPrinter << "a=fmtp:" << m_pRtpMaker_h264->getPlayloadType()
|
||||
<< " packetization-mode=1;profile-level-id=" << endl;
|
||||
|
||||
memset(acTmp, 0, sizeof(acTmp));
|
||||
sprintf(acTmp, "%06X", profile_level_id);
|
||||
m_strSDP += acTmp;
|
||||
m_strSDP += ";sprop-parameter-sets=";
|
||||
m_strSdp += acTmp;
|
||||
m_strSdp += ";sprop-parameter-sets=";
|
||||
memset(acTmp, 0, sizeof(acTmp));
|
||||
av_base64_encode(acTmp, sizeof(acTmp), (uint8_t *) m_aucSPS, m_uiSPSLen);
|
||||
//WarnL<<"SPS base64:"<<strTemp;
|
||||
//WarnL<<"SPS hexdump:"<<hexdump(SPS_BUF, SPS_LEN);
|
||||
m_strSDP += acTmp;
|
||||
m_strSDP += ",";
|
||||
m_strSdp += acTmp;
|
||||
m_strSdp += ",";
|
||||
memset(acTmp, 0, sizeof(acTmp));
|
||||
av_base64_encode(acTmp, sizeof(acTmp), (uint8_t *) m_aucPPS, m_uiPPSLen);
|
||||
m_strSDP += acTmp;
|
||||
m_strSDP += "\r\n";
|
||||
m_strSdp += acTmp;
|
||||
m_strSdp += "\r\n";
|
||||
if (m_video->iFrameRate > 0 && m_video->iHeight > 0 && m_video->iWidth > 0) {
|
||||
m_strSDP += "a=framerate:";
|
||||
m_strSDP += StrPrinter << m_video->iFrameRate << endl;
|
||||
m_strSDP += StrPrinter << "\r\na=framesize:"
|
||||
m_strSdp += "a=framerate:";
|
||||
m_strSdp += StrPrinter << m_video->iFrameRate << endl;
|
||||
m_strSdp += StrPrinter << "\r\na=framesize:"
|
||||
<< m_pRtpMaker_h264->getPlayloadType() << " " << endl;
|
||||
m_strSDP += StrPrinter << m_video->iWidth << endl;
|
||||
m_strSDP += "-";
|
||||
m_strSDP += StrPrinter << m_video->iHeight << endl;
|
||||
m_strSDP += "\r\n";
|
||||
m_strSdp += StrPrinter << m_video->iWidth << endl;
|
||||
m_strSdp += "-";
|
||||
m_strSdp += StrPrinter << m_video->iHeight << endl;
|
||||
m_strSdp += "\r\n";
|
||||
}
|
||||
m_strSDP += StrPrinter << "a=control:trackID="
|
||||
m_strSdp += StrPrinter << "a=control:trackID="
|
||||
<< m_pRtpMaker_h264->getInterleaved() / 2 << "\r\n" << endl;
|
||||
m_bSdp_gotH264 = true;
|
||||
if (m_audio) {
|
||||
if (m_bSdp_gotAAC) {
|
||||
makeSDP(m_strSDP);
|
||||
makeSDP(m_strSdp);
|
||||
}
|
||||
} else {
|
||||
makeSDP(m_strSDP);
|
||||
makeSDP(m_strSdp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,33 +231,33 @@ inline void DevChannel::makeSDP_AAC(unsigned char *fixedHeader) {
|
||||
char fConfigStr[5] = { 0 };
|
||||
sprintf(fConfigStr, "%02X%02x", (uint8_t)audioSpecificConfig[0],(uint8_t)audioSpecificConfig[1]);
|
||||
|
||||
m_strSDP += StrPrinter << "m=audio 0 RTP/AVP "
|
||||
m_strSdp += StrPrinter << "m=audio 0 RTP/AVP "
|
||||
<< m_pRtpMaker_aac->getPlayloadType() << "\r\n" << endl;
|
||||
m_strSDP += "b=AS:96\r\n";
|
||||
m_strSDP += StrPrinter << "a=rtpmap:" << m_pRtpMaker_aac->getPlayloadType()
|
||||
m_strSdp += "b=AS:96\r\n";
|
||||
m_strSdp += StrPrinter << "a=rtpmap:" << m_pRtpMaker_aac->getPlayloadType()
|
||||
<< " MPEG4-GENERIC/" << m_pRtpMaker_aac->getSampleRate() << "\r\n"
|
||||
<< endl;
|
||||
m_strSDP += StrPrinter << "a=fmtp:" << m_pRtpMaker_aac->getPlayloadType()
|
||||
m_strSdp += StrPrinter << "a=fmtp:" << m_pRtpMaker_aac->getPlayloadType()
|
||||
<< " streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config="
|
||||
<< endl;
|
||||
m_strSDP += fConfigStr;
|
||||
m_strSDP += "\r\n";
|
||||
m_strSDP += StrPrinter << "a=control:trackID="
|
||||
m_strSdp += fConfigStr;
|
||||
m_strSdp += "\r\n";
|
||||
m_strSdp += StrPrinter << "a=control:trackID="
|
||||
<< m_pRtpMaker_aac->getInterleaved() / 2 << "\r\n" << endl;
|
||||
|
||||
m_bSdp_gotAAC = true;
|
||||
if (m_video) {
|
||||
if (m_bSdp_gotH264) {
|
||||
makeSDP(m_strSDP);
|
||||
makeSDP(m_strSdp);
|
||||
}
|
||||
} else {
|
||||
makeSDP(m_strSDP);
|
||||
makeSDP(m_strSdp);
|
||||
}
|
||||
}
|
||||
|
||||
void DevChannel::makeSDP(const string& strSdp) {
|
||||
m_mediaSrc->onGetSDP(strSdp);
|
||||
m_mediaSrc->regist();
|
||||
onGetSDP(strSdp);
|
||||
regist();
|
||||
}
|
||||
|
||||
void DevChannel::initVideo(const VideoInfo& info) {
|
||||
|
@ -49,6 +49,7 @@ using namespace ZL::Codec;
|
||||
using namespace ZL::Codec;
|
||||
#endif //ENABLE_X264
|
||||
|
||||
|
||||
namespace ZL {
|
||||
namespace DEV {
|
||||
|
||||
@ -65,10 +66,10 @@ public:
|
||||
int iSampleRate;
|
||||
};
|
||||
|
||||
class DevChannel {
|
||||
class DevChannel : public RtspToRtmpMediaSource{
|
||||
public:
|
||||
typedef std::shared_ptr<DevChannel> Ptr;
|
||||
DevChannel(const char *strApp, const char *strId,float fDuration = 0,bool bLiveStream = true);
|
||||
DevChannel(const char *strVhost,const char *strApp, const char *strId,float fDuration = 0,bool bLiveStream = true);
|
||||
virtual ~DevChannel();
|
||||
|
||||
void initVideo(const VideoInfo &info);
|
||||
@ -80,20 +81,6 @@ public:
|
||||
void inputH264(char *pcData, int iDataLen, uint32_t uiStamp);
|
||||
void inputAAC(char *pcDataWithAdts, int iDataLen, uint32_t uiStamp);
|
||||
void inputAAC(char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,char *pcAdtsHeader);
|
||||
#ifdef ENABLE_RTSP2RTMP
|
||||
int readerCount() {
|
||||
return m_mediaSrc ? m_mediaSrc->readerCount() : 0;
|
||||
}
|
||||
void updateTimeStamp(uint32_t uiStamp){
|
||||
m_mediaSrc->updateTimeStamp(uiStamp);
|
||||
}
|
||||
#endif //ENABLE_RTSP2RTMP
|
||||
void setOnSeek(const function<bool(uint32_t)> &onSeek){
|
||||
m_mediaSrc->setOnSeek(onSeek);
|
||||
}
|
||||
void setOnStamp(const function<uint32_t()> &cb) {
|
||||
m_mediaSrc->setOnStamp(cb);
|
||||
}
|
||||
private:
|
||||
inline void makeSDP_264(unsigned char *pucData, int iDataLen);
|
||||
inline void makeSDP_AAC(unsigned char *pucData);
|
||||
@ -107,8 +94,6 @@ private:
|
||||
#endif //ENABLE_FAAC
|
||||
RtpMaker_AAC::Ptr m_pRtpMaker_aac;
|
||||
RtpMaker_H264::Ptr m_pRtpMaker_h264;
|
||||
RtspToRtmpMediaSource::Ptr m_mediaSrc;
|
||||
string m_strSDP;
|
||||
bool m_bSdp_gotH264 = false;
|
||||
bool m_bSdp_gotAAC = false;
|
||||
|
||||
|
@ -39,7 +39,8 @@ namespace DEV {
|
||||
|
||||
const char PlayerProxy::kAliveSecond[] = "alive_second";
|
||||
|
||||
PlayerProxy::PlayerProxy(const char *strApp,const char *strSrc){
|
||||
PlayerProxy::PlayerProxy(const char *strVhost,const char *strApp,const char *strSrc){
|
||||
m_strVhost = strVhost;
|
||||
m_strApp = strApp;
|
||||
m_strSrc = strSrc;
|
||||
}
|
||||
@ -133,7 +134,7 @@ void PlayerProxy::initMedia() {
|
||||
if (!isInited()) {
|
||||
return;
|
||||
}
|
||||
m_pChn.reset(new DevChannel(m_strApp.data(),m_strSrc.data(),getDuration()));
|
||||
m_pChn.reset(new DevChannel(m_strVhost.data(),m_strApp.data(),m_strSrc.data(),getDuration()));
|
||||
if (containVideo()) {
|
||||
VideoInfo info;
|
||||
info.iFrameRate = getVideoFps();
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
//设置方法:proxy[PlayerProxy::kAliveSecond] = 100;
|
||||
static const char kAliveSecond[];
|
||||
|
||||
PlayerProxy(const char *strApp, const char *strSrc);
|
||||
PlayerProxy(const char *strVhost, const char *strApp, const char *strSrc);
|
||||
virtual ~PlayerProxy();
|
||||
void play(const char* strUrl) override;
|
||||
void setOnExpired(const function<void()> &cb){
|
||||
@ -56,6 +56,7 @@ private :
|
||||
Ticker m_aliveTicker;
|
||||
uint32_t m_aliveSecond = 0;
|
||||
function<void()> onExpired;
|
||||
string m_strVhost;
|
||||
string m_strApp;
|
||||
string m_strSrc;
|
||||
void initMedia();
|
||||
|
@ -182,14 +182,13 @@ inline bool HttpSession::checkLiveFlvStream(){
|
||||
//未找到".flv"后缀
|
||||
return false;
|
||||
}
|
||||
auto app = FindField(m_parser.Url().data(),"/","/");
|
||||
auto stream = FindField(m_parser.Url().data(),(string("/") + app + "/").data(),".");
|
||||
if(app.empty() || stream.empty()){
|
||||
//不能拆分成2级url
|
||||
return false;
|
||||
auto fullUrl = string("http://") + m_parser["Host"] + FindField(m_parser.Url().data(),NULL,pos);
|
||||
MediaInfo info(fullUrl);
|
||||
if(!m_parser.getUrlArgs()[VHOST_KEY].empty()){
|
||||
info.m_vhost = m_parser.getUrlArgs()[VHOST_KEY];
|
||||
}
|
||||
//TO-DO
|
||||
auto mediaSrc = RtmpMediaSource::find(app,stream);
|
||||
|
||||
auto mediaSrc = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,info.m_vhost,info.m_app,info.m_streamid));
|
||||
if(!mediaSrc){
|
||||
//该rtmp源不存在
|
||||
return false;
|
||||
@ -274,7 +273,13 @@ inline HttpSession::HttpCode HttpSession::Handle_Req_GET() {
|
||||
return Http_success;
|
||||
}
|
||||
//事件未被拦截,则认为是http下载请求
|
||||
string strFile = m_strPath + m_parser.Url();
|
||||
|
||||
auto fullUrl = string("http://") + m_parser["Host"] + m_parser.Url();
|
||||
MediaInfo info(fullUrl);
|
||||
if(!m_parser.getUrlArgs()[VHOST_KEY].empty()){
|
||||
info.m_vhost = m_parser.getUrlArgs()[VHOST_KEY];
|
||||
}
|
||||
string strFile = m_strPath + "/" + info.m_vhost + m_parser.Url();
|
||||
/////////////HTTP连接是否需要被关闭////////////////
|
||||
static uint32_t reqCnt = mINI::Instance()[Config::Http::kMaxReqCount].as<uint32_t>();
|
||||
bool bClose = (strcasecmp(m_parser["Connection"].data(),"close") == 0) && ( ++m_iReqCnt < reqCnt);
|
||||
@ -283,7 +288,7 @@ inline HttpSession::HttpCode HttpSession::Handle_Req_GET() {
|
||||
if (strFile.back() == '/') {
|
||||
//生成文件夹菜单索引
|
||||
string strMeun;
|
||||
if (!makeMeun(strFile, strMeun)) {
|
||||
if (!makeMeun(strFile,info.m_vhost, strMeun)) {
|
||||
//文件夹不存在
|
||||
sendNotFound(bClose);
|
||||
return eHttpCode;
|
||||
@ -409,7 +414,7 @@ inline HttpSession::HttpCode HttpSession::Handle_Req_GET() {
|
||||
return Http_success;
|
||||
}
|
||||
|
||||
inline bool HttpSession::makeMeun(const string &strFullPath, string &strRet) {
|
||||
inline bool HttpSession::makeMeun(const string &strFullPath,const string &vhost, string &strRet) {
|
||||
string strPathPrefix(strFullPath);
|
||||
strPathPrefix = strPathPrefix.substr(0, strPathPrefix.length() - 1);
|
||||
if (!File::is_dir(strPathPrefix.data())) {
|
||||
@ -423,7 +428,7 @@ inline bool HttpSession::makeMeun(const string &strFullPath, string &strRet) {
|
||||
"<h1>文件索引:";
|
||||
|
||||
string strPath = strFullPath;
|
||||
strPath = strPath.substr(m_strPath.length(), strFullPath.length() - m_strPath.length());
|
||||
strPath = strPath.substr(m_strPath.length() + vhost.length() + 1);
|
||||
strRet += strPath;
|
||||
strRet += "</h1>\r\n";
|
||||
if (strPath != "/") {
|
||||
@ -503,13 +508,12 @@ inline void HttpSession::sendResponse(const char* pcStatus, const KeyValue& head
|
||||
}
|
||||
inline HttpSession::KeyValue HttpSession::makeHttpHeader(bool bClose, int64_t iContentSize,const char* pcContentType) {
|
||||
KeyValue headerOut;
|
||||
static string serverName = mINI::Instance()[Config::Http::kServerName];
|
||||
static string charSet = mINI::Instance()[Config::Http::kCharSet];
|
||||
static uint32_t keepAliveSec = mINI::Instance()[Config::Http::kKeepAliveSecond].as<uint32_t>();
|
||||
static uint32_t reqCnt = mINI::Instance()[Config::Http::kMaxReqCount].as<uint32_t>();
|
||||
|
||||
headerOut.emplace("Date", dateStr());
|
||||
headerOut.emplace("Server", serverName);
|
||||
headerOut.emplace("Server", SERVER_NAME);
|
||||
headerOut.emplace("Connection", bClose ? "close" : "keep-alive");
|
||||
if(!bClose){
|
||||
headerOut.emplace("Keep-Alive",StrPrinter << "timeout=" << keepAliveSec << ", max=" << reqCnt << endl);
|
||||
|
@ -87,7 +87,7 @@ private:
|
||||
inline bool checkLiveFlvStream();
|
||||
inline bool emitHttpEvent(bool doInvoke);
|
||||
inline void urlDecode(Parser &parser);
|
||||
inline bool makeMeun(const string &strFullPath, string &strRet);
|
||||
inline bool makeMeun(const string &strFullPath,const string &vhost, string &strRet);
|
||||
inline void sendNotFound(bool bClose);
|
||||
inline void sendResponse(const char *pcStatus,const KeyValue &header,const string &strContent);
|
||||
inline static KeyValue makeHttpHeader(bool bClose=false,int64_t iContentSize=-1,const char *pcContentType="text/html");
|
||||
|
@ -38,10 +38,6 @@ HLSMaker::HLSMaker(const string& strM3u8File, const string& strHttpUrl,
|
||||
if (ui32BufSize < 16 * 1024) {
|
||||
ui32BufSize = 16 * 1024;
|
||||
}
|
||||
|
||||
if(ui32Duration < 0){
|
||||
ui32Duration = 0;
|
||||
}
|
||||
if(ui32Num < 1){
|
||||
ui32Num = 1;
|
||||
}
|
||||
|
@ -36,9 +36,9 @@ namespace ZL {
|
||||
namespace MediaFile {
|
||||
|
||||
#ifdef ENABLE_MP4V2
|
||||
MediaReader::MediaReader(const string &strApp, const string &strId) {
|
||||
MediaReader::MediaReader(const string &strVhost,const string &strApp, const string &strId) {
|
||||
static string recordPath = mINI::Instance()[Config::Record::kFilePath];
|
||||
auto strFileName = recordPath + "/" + strApp + "/" + strId;
|
||||
auto strFileName = recordPath + "/" + strVhost + "/" + strApp + "/" + strId;
|
||||
|
||||
m_hMP4File = MP4Read(strFileName.data());
|
||||
if(m_hMP4File == MP4_INVALID_FILE_HANDLE){
|
||||
@ -129,7 +129,7 @@ MediaReader::MediaReader(const string &strApp, const string &strId) {
|
||||
}
|
||||
|
||||
m_iDuration = MAX(m_video_ms,m_audio_ms);
|
||||
m_pChn.reset(new DevChannel(strApp.data(),strId.data(),m_iDuration/1000.0,false));
|
||||
m_pChn.reset(new DevChannel(strVhost.data(),strApp.data(),strId.data(),m_iDuration/1000.0,false));
|
||||
if (m_audio_trId != MP4_INVALID_TRACK_ID) {
|
||||
AudioInfo info;
|
||||
info.iChannel = m_audio_num_channels;
|
||||
@ -169,26 +169,17 @@ MediaReader::~MediaReader() {
|
||||
void MediaReader::startReadMP4() {
|
||||
auto strongSelf = shared_from_this();
|
||||
static uint32_t sampleMS = mINI::Instance()[Config::Record::kSampleMS].as<uint32_t>();
|
||||
|
||||
AsyncTaskThread::Instance().DoTaskDelay(reinterpret_cast<uint64_t>(this), sampleMS, [strongSelf](){
|
||||
return strongSelf->readSample();
|
||||
});
|
||||
weak_ptr<MediaReader> weakSelf = strongSelf;
|
||||
m_pChn->setOnSeek([weakSelf](uint32_t ui32Stamp){
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf){
|
||||
return false;
|
||||
m_pChn->setListener(strongSelf);
|
||||
}
|
||||
strongSelf->seek(ui32Stamp);
|
||||
bool MediaReader::seekTo(uint32_t ui32Stamp){
|
||||
seek(ui32Stamp);
|
||||
return true;
|
||||
});
|
||||
m_pChn->setOnStamp([weakSelf]() -> uint32_t {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return 0;
|
||||
}
|
||||
return strongSelf-> m_iSeekTime + strongSelf->m_ticker.elapsedTime();
|
||||
});
|
||||
uint32_t MediaReader::getStamp() {
|
||||
return m_iSeekTime + m_ticker.elapsedTime();
|
||||
}
|
||||
|
||||
bool MediaReader::readSample(int iTimeInc) {
|
||||
@ -322,16 +313,18 @@ void MediaReader::seek(int iSeekTime,bool bReStart){
|
||||
|
||||
#endif //ENABLE_MP4V2
|
||||
|
||||
RtspMediaSource::Ptr MediaReader::onMakeRtsp(const string &strApp, const string &strId) {
|
||||
|
||||
|
||||
MediaSource::Ptr MediaReader::onMakeMediaSource(const string &strSchema,const string &strVhost,const string &strApp, const string &strId){
|
||||
#ifdef ENABLE_MP4V2
|
||||
static string appName = mINI::Instance()[Config::Record::kAppName];
|
||||
if (strApp != appName) {
|
||||
return nullptr;
|
||||
}
|
||||
try {
|
||||
MediaReader::Ptr pReader(new MediaReader(strApp,strId));
|
||||
MediaReader::Ptr pReader(new MediaReader(strVhost,strApp, strId));
|
||||
pReader->startReadMP4();
|
||||
return RtspMediaSource::find(strApp, strId, false);
|
||||
return MediaSource::find(strSchema,strVhost,strApp, strId, false);
|
||||
} catch (std::exception &ex) {
|
||||
WarnL << ex.what();
|
||||
return nullptr;
|
||||
@ -339,27 +332,6 @@ RtspMediaSource::Ptr MediaReader::onMakeRtsp(const string &strApp, const string
|
||||
#else
|
||||
return nullptr;
|
||||
#endif //ENABLE_MP4V2
|
||||
|
||||
}
|
||||
|
||||
RtmpMediaSource::Ptr MediaReader::onMakeRtmp(const string &strApp, const string &strId) {
|
||||
#ifdef ENABLE_MP4V2
|
||||
static string appName = mINI::Instance()[Config::Record::kAppName];
|
||||
if (strApp != appName) {
|
||||
return nullptr;
|
||||
}
|
||||
try {
|
||||
MediaReader::Ptr pReader(new MediaReader(strApp, strId));
|
||||
pReader->startReadMP4();
|
||||
return RtmpMediaSource::find(strApp, strId, false);
|
||||
} catch (std::exception &ex) {
|
||||
WarnL << ex.what();
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
return nullptr;
|
||||
#endif //ENABLE_MP4V2
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,13 +42,15 @@ using namespace ZL::Rtmp;
|
||||
namespace ZL {
|
||||
namespace MediaFile {
|
||||
|
||||
class MediaReader : public std::enable_shared_from_this<MediaReader>{
|
||||
class MediaReader : public std::enable_shared_from_this<MediaReader> ,public MediaSourceEvent{
|
||||
public:
|
||||
typedef std::shared_ptr<MediaReader> Ptr;
|
||||
MediaReader(const string &strApp, const string &strId);
|
||||
MediaReader(const string &strVhost,const string &strApp, const string &strId);
|
||||
virtual ~MediaReader();
|
||||
static RtspMediaSource::Ptr onMakeRtsp(const string &strApp, const string &strId);
|
||||
static RtmpMediaSource::Ptr onMakeRtmp(const string &strApp, const string &strId);
|
||||
static MediaSource::Ptr onMakeMediaSource(const string &strSchema,const string &strVhost,const string &strApp, const string &strId);
|
||||
public:
|
||||
bool seekTo(uint32_t ui32Stamp) override;
|
||||
uint32_t getStamp() override;
|
||||
private:
|
||||
|
||||
#ifdef ENABLE_MP4V2
|
||||
@ -95,6 +97,8 @@ private:
|
||||
inline bool readAudioSample(int iTimeInc = 0);
|
||||
inline void writeH264(uint8_t *pucData,int iLen,uint32_t uiStamp);
|
||||
inline void writeAAC(uint8_t *pucData,int iLen,uint32_t uiStamp);
|
||||
|
||||
|
||||
#endif //ENABLE_MP4V2
|
||||
};
|
||||
|
||||
|
@ -37,24 +37,39 @@ using namespace ZL::Network;
|
||||
namespace ZL {
|
||||
namespace MediaFile {
|
||||
|
||||
MediaRecorder::MediaRecorder(const string &strApp,const string &strId,const std::shared_ptr<PlayerBase> &pPlayer) {
|
||||
#ifdef ENABLE_HLS
|
||||
static string hlsPrefix = mINI::Instance()[Config::Http::kHttpPrefix];
|
||||
MediaRecorder::MediaRecorder(const string &strVhost ,const string &strApp,const string &strId,const std::shared_ptr<PlayerBase> &pPlayer) {
|
||||
static string hlsPrefix = mINI::Instance()[Config::Hls::kHttpPrefix];
|
||||
static string hlsPrefixDefaultVhost = mINI::Instance()[Config::Hls::kHttpPrefixDefaultVhost];
|
||||
static string hlsPath = mINI::Instance()[Config::Hls::kFilePath];
|
||||
static uint32_t hlsBufSize = mINI::Instance()[Config::Hls::kFileBufSize].as<uint32_t>();
|
||||
static uint32_t hlsDuration = mINI::Instance()[Config::Hls::kSegmentDuration].as<uint32_t>();
|
||||
static uint32_t hlsNum = mINI::Instance()[Config::Hls::kSegmentNum].as<uint32_t>();
|
||||
|
||||
m_hlsMaker.reset(new HLSMaker(hlsPath + "/" + strApp + "/" + strId + "/hls.m3u8",
|
||||
hlsPrefix + "/" + strApp + "/" + strId + "/",
|
||||
string hlsPrefixVhost = hlsPrefix;
|
||||
do{
|
||||
//生成hls http前缀
|
||||
if (strVhost.empty() || strVhost == DEFAULT_VHOST) {
|
||||
hlsPrefixVhost = hlsPrefixDefaultVhost;
|
||||
break;
|
||||
}
|
||||
auto pos_start = hlsPrefixVhost.find("${");
|
||||
auto pos_end = hlsPrefixVhost.find("}");
|
||||
if (pos_start != string::npos && pos_end != string::npos && pos_end - pos_start - 2 > 0 ) {
|
||||
auto key = hlsPrefixVhost.substr(pos_start + 2, pos_end - pos_start - 2);
|
||||
trim(key);
|
||||
if (key == VHOST_KEY) {
|
||||
hlsPrefixVhost.replace(pos_start, pos_end - pos_start + 1, strVhost);
|
||||
}
|
||||
}
|
||||
}while(0);
|
||||
m_hlsMaker.reset(new HLSMaker(hlsPath + "/" + strVhost + "/" + strApp + "/" + strId + "/hls.m3u8",
|
||||
hlsPrefixVhost + "/" + strApp + "/" + strId + "/",
|
||||
hlsBufSize,hlsDuration,hlsNum));
|
||||
#endif //ENABLE_HLS
|
||||
|
||||
#ifdef ENABLE_MP4V2
|
||||
static string recordPath = mINI::Instance()[Config::Record::kFilePath];
|
||||
static string recordAppName = mINI::Instance()[Config::Record::kAppName];
|
||||
m_mp4Maker.reset(new Mp4Maker(recordPath + "/" + recordAppName + "/" + strApp + "/" + strId + "/",
|
||||
strApp,strId,pPlayer));
|
||||
m_mp4Maker.reset(new Mp4Maker(recordPath + "/" + strVhost + "/" + recordAppName + "/" + strApp + "/" + strId + "/",
|
||||
strVhost,strApp,strId,pPlayer));
|
||||
#endif //ENABLE_MP4V2
|
||||
}
|
||||
|
||||
@ -62,20 +77,14 @@ MediaRecorder::~MediaRecorder() {
|
||||
}
|
||||
|
||||
void MediaRecorder::inputH264(void* pData, uint32_t ui32Length, uint32_t ui32TimeStamp, int iType) {
|
||||
#ifdef ENABLE_HLS
|
||||
m_hlsMaker->inputH264(pData, ui32Length, ui32TimeStamp * 90, iType);
|
||||
#endif //ENABLE_HLS
|
||||
|
||||
#ifdef ENABLE_MP4V2
|
||||
m_mp4Maker->inputH264(pData, ui32Length, ui32TimeStamp, iType);
|
||||
#endif //ENABLE_MP4V2
|
||||
}
|
||||
|
||||
void MediaRecorder::inputAAC(void* pData, uint32_t ui32Length, uint32_t ui32TimeStamp) {
|
||||
#ifdef ENABLE_HLS
|
||||
m_hlsMaker->inputAAC(pData, ui32Length, ui32TimeStamp * 90);
|
||||
#endif //ENABLE_HLS
|
||||
|
||||
#ifdef ENABLE_MP4V2
|
||||
m_mp4Maker->inputAAC(pData, ui32Length, ui32TimeStamp);
|
||||
#endif //ENABLE_MP4V2
|
||||
|
@ -34,9 +34,7 @@
|
||||
#include "Mp4Maker.h"
|
||||
#endif //ENABLE_MP4V2
|
||||
|
||||
#ifdef ENABLE_HLS
|
||||
#include "HLSMaker.h"
|
||||
#endif //ENABLE_HLS
|
||||
|
||||
using namespace std;
|
||||
using namespace ZL::Player;
|
||||
@ -48,7 +46,7 @@ namespace MediaFile {
|
||||
class MediaRecorder {
|
||||
public:
|
||||
typedef std::shared_ptr<MediaRecorder> Ptr;
|
||||
MediaRecorder(const string &strApp,const string &strId,const std::shared_ptr<PlayerBase> &pPlayer);
|
||||
MediaRecorder(const string &strVhost,const string &strApp,const string &strId,const std::shared_ptr<PlayerBase> &pPlayer);
|
||||
virtual ~MediaRecorder();
|
||||
|
||||
void inputH264( void *pData,
|
||||
@ -60,11 +58,7 @@ public:
|
||||
uint32_t ui32Length,
|
||||
uint32_t ui32TimeStamp);
|
||||
private:
|
||||
|
||||
#ifdef ENABLE_HLS
|
||||
std::shared_ptr<HLSMaker> m_hlsMaker;
|
||||
#endif //ENABLE_HLS
|
||||
|
||||
#ifdef ENABLE_MP4V2
|
||||
std::shared_ptr<Mp4Maker> m_mp4Maker;
|
||||
#endif //ENABLE_MP4V2
|
||||
|
@ -59,7 +59,11 @@ string timeStr(const char *fmt) {
|
||||
#endif
|
||||
}
|
||||
|
||||
Mp4Maker::Mp4Maker(const string& strPath,const string &strApp,const string &strStreamId, const PlayerBase::Ptr &pPlayer) {
|
||||
Mp4Maker::Mp4Maker(const string& strPath,
|
||||
const string &strVhost,
|
||||
const string &strApp,
|
||||
const string &strStreamId,
|
||||
const PlayerBase::Ptr &pPlayer) {
|
||||
DebugL << strPath;
|
||||
m_pPlayer = pPlayer;
|
||||
m_strPath = strPath;
|
||||
@ -67,6 +71,7 @@ Mp4Maker::Mp4Maker(const string& strPath,const string &strApp,const string &strS
|
||||
/////record 业务逻辑//////
|
||||
m_info.strAppName = strApp;
|
||||
m_info.strStreamId = strStreamId;
|
||||
m_info.strVhost = strVhost;
|
||||
m_info.strFolder = strPath;
|
||||
//----record 业务逻辑----//
|
||||
}
|
||||
@ -144,7 +149,6 @@ void Mp4Maker::createFile() {
|
||||
}
|
||||
closeFile();
|
||||
|
||||
|
||||
auto strDate = timeStr("%Y-%m-%d");
|
||||
auto strTime = timeStr("%H-%M-%S");
|
||||
auto strFileTmp = m_strPath + strDate + "/." + strTime + ".mp4";
|
||||
@ -155,7 +159,8 @@ void Mp4Maker::createFile() {
|
||||
m_info.strFileName = strTime + ".mp4";
|
||||
m_info.strFilePath = strFile;
|
||||
static string appName = mINI::Instance()[Config::Record::kAppName];
|
||||
m_info.strUrl = appName + "/"
|
||||
m_info.strUrl = m_info.strVhost + "/"
|
||||
+ appName + "/"
|
||||
+ m_info.strAppName + "/"
|
||||
+ m_info.strStreamId + "/"
|
||||
+ strDate + "/"
|
||||
|
@ -57,11 +57,16 @@ public:
|
||||
string strUrl;//播放路径
|
||||
string strAppName;//应用名称
|
||||
string strStreamId;//流ID
|
||||
string strVhost;//vhost
|
||||
};
|
||||
class Mp4Maker {
|
||||
public:
|
||||
typedef std::shared_ptr<Mp4Maker> Ptr;
|
||||
Mp4Maker(const string &strPath,const string &strApp,const string &strStreamId, const PlayerBase::Ptr &pPlayer);
|
||||
Mp4Maker(const string &strPath,
|
||||
const string &strVhost ,
|
||||
const string &strApp,
|
||||
const string &strStreamId,
|
||||
const PlayerBase::Ptr &pPlayer);
|
||||
virtual ~Mp4Maker();
|
||||
//时间戳:参考频率1000
|
||||
void inputH264(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp, int iType);
|
||||
|
@ -32,30 +32,6 @@ using namespace ZL::MediaFile;
|
||||
namespace ZL {
|
||||
namespace Rtmp {
|
||||
|
||||
recursive_mutex RtmpMediaSource::g_mtxMediaSrc;
|
||||
unordered_map<string, unordered_map<string,weak_ptr<RtmpMediaSource> > > RtmpMediaSource::g_mapMediaSrc;
|
||||
|
||||
RtmpMediaSource::Ptr RtmpMediaSource::find(const string &strApp, const string &strId, bool bMake) {
|
||||
//查找某一媒体源,找到后返回
|
||||
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
|
||||
auto itApp = g_mapMediaSrc.find(strApp);
|
||||
if (itApp == g_mapMediaSrc.end()) {
|
||||
return bMake ? MediaReader::onMakeRtmp(strApp, strId) : nullptr;
|
||||
}
|
||||
auto itId = itApp->second.find(strId);
|
||||
if (itId == itApp->second.end()) {
|
||||
return bMake ? MediaReader::onMakeRtmp(strApp, strId) : nullptr;
|
||||
}
|
||||
auto ret = itId->second.lock();
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
itApp->second.erase(itId);
|
||||
if (itApp->second.size() == 0) {
|
||||
g_mapMediaSrc.erase(itApp);
|
||||
}
|
||||
return bMake ? MediaReader::onMakeRtmp(strApp, strId) : nullptr;
|
||||
}
|
||||
|
||||
} /* namespace Rtmp */
|
||||
} /* namespace ZL */
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "Rtmp.h"
|
||||
#include "Common/config.h"
|
||||
#include "Common/MediaSender.h"
|
||||
#include "Common/MediaSource.h"
|
||||
#include "Util/util.h"
|
||||
#include "Util/logger.h"
|
||||
#include "Util/RingBuffer.h"
|
||||
@ -47,72 +48,28 @@
|
||||
using namespace std;
|
||||
using namespace ZL::Util;
|
||||
using namespace ZL::Thread;
|
||||
using namespace ZL::Media;
|
||||
|
||||
namespace ZL {
|
||||
namespace Rtmp {
|
||||
|
||||
|
||||
class RtmpMediaSource: public enable_shared_from_this<RtmpMediaSource> {
|
||||
class RtmpMediaSource: public MediaSource {
|
||||
public:
|
||||
typedef std::shared_ptr<RtmpMediaSource> Ptr;
|
||||
typedef RingBuffer<RtmpPacket::Ptr> RingType;
|
||||
RtmpMediaSource(const string &strApp, const string &strId) :
|
||||
m_strApp(strApp),
|
||||
m_strId(strId),
|
||||
|
||||
RtmpMediaSource(const string &vhost,const string &strApp, const string &strId) :
|
||||
MediaSource(RTMP_SCHEMA,vhost,strApp,strId),
|
||||
m_pRing(new RingBuffer<RtmpPacket::Ptr>()),
|
||||
m_thPool( MediaSender::sendThread()) {
|
||||
}
|
||||
virtual ~RtmpMediaSource() {
|
||||
unregist();
|
||||
}
|
||||
virtual ~RtmpMediaSource() {}
|
||||
|
||||
const RingType::Ptr &getRing() const {
|
||||
//获取媒体源的rtp环形缓冲
|
||||
return m_pRing;
|
||||
}
|
||||
virtual void regist() {
|
||||
//注册该源,注册后rtmp服务器才能找到该源
|
||||
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
|
||||
if (!g_mapMediaSrc[m_strApp].erase(m_strId)) {
|
||||
InfoL << "Rtmp src:" << m_strApp << " " << m_strId;
|
||||
}
|
||||
g_mapMediaSrc[m_strApp].emplace(m_strId, shared_from_this());
|
||||
NoticeCenter::Instance().emitEvent(Config::Broadcast::kBroadcastRtmpSrcRegisted,m_strApp.data(),m_strId.data());
|
||||
}
|
||||
virtual void unregist() {
|
||||
//反注册该源
|
||||
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
|
||||
auto it = g_mapMediaSrc.find(m_strApp);
|
||||
if (it == g_mapMediaSrc.end()) {
|
||||
return;
|
||||
}
|
||||
if (it->second.erase(m_strId)) {
|
||||
if (it->second.size() == 0) {
|
||||
g_mapMediaSrc.erase(it);
|
||||
}
|
||||
InfoL << "Rtmp src:" << m_strApp << " " << m_strId;
|
||||
}
|
||||
}
|
||||
static set<string> getMediaSet() {
|
||||
set<string> ret;
|
||||
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
|
||||
for (auto &pr0 : g_mapMediaSrc) {
|
||||
for (auto &pr1 : pr0.second) {
|
||||
if (pr1.second.lock()) {
|
||||
ret.emplace(pr0.first + "/" + pr1.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static Ptr find(const string &strApp, const string &strId, bool bMake = true) ;
|
||||
const string& getApp() const {
|
||||
//获取该源的id
|
||||
return m_strApp;
|
||||
}
|
||||
const string& getId() const {
|
||||
//获取该源的id
|
||||
return m_strId;
|
||||
}
|
||||
|
||||
const AMFValue &getMetaData() const {
|
||||
return m_metadata;
|
||||
}
|
||||
@ -140,37 +97,12 @@ public:
|
||||
_ring->write(pkt,pkt->isVideoKeyFrame());
|
||||
});
|
||||
}
|
||||
bool seekTo(uint32_t ui32Stamp) {
|
||||
if (!m_onSeek) {
|
||||
return false;
|
||||
}
|
||||
return m_onSeek(ui32Stamp);
|
||||
}
|
||||
virtual void setOnSeek(const function<bool(uint32_t)> &cb) {
|
||||
m_onSeek = cb;
|
||||
}
|
||||
uint32_t getStamp() {
|
||||
if (!m_onStamp) {
|
||||
return 0;
|
||||
}
|
||||
return m_onStamp();
|
||||
}
|
||||
virtual void setOnStamp(const function<uint32_t()> &cb) {
|
||||
m_onStamp = cb;
|
||||
}
|
||||
protected:
|
||||
function<bool(uint32_t)> m_onSeek;
|
||||
function<uint32_t()> m_onStamp;
|
||||
private:
|
||||
AMFValue m_metadata;
|
||||
unordered_map<int, RtmpPacket::Ptr> m_mapCfgFrame;
|
||||
mutable recursive_mutex m_mtxMap;
|
||||
string m_strApp; //媒体app
|
||||
string m_strId; //媒体id
|
||||
RingBuffer<RtmpPacket::Ptr>::Ptr m_pRing; //rtp环形缓冲
|
||||
ThreadPool &m_thPool;
|
||||
static unordered_map<string, unordered_map<string,weak_ptr<RtmpMediaSource> > > g_mapMediaSrc; //静态的媒体源表
|
||||
static recursive_mutex g_mtxMediaSrc; ///访问静态的媒体源表的互斥锁
|
||||
};
|
||||
|
||||
} /* namespace Rtmp */
|
||||
|
@ -36,10 +36,10 @@ namespace ZL {
|
||||
namespace Rtmp {
|
||||
|
||||
unordered_map<string, RtmpPusher::rtmpCMDHandle> RtmpPusher::g_mapCmd;
|
||||
RtmpPusher::RtmpPusher(const char *strApp,const char *strStream) {
|
||||
auto src = RtmpMediaSource::find(strApp,strStream);
|
||||
RtmpPusher::RtmpPusher(const char *strVhost,const char *strApp,const char *strStream) {
|
||||
auto src = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,strVhost,strApp,strStream));
|
||||
if (!src) {
|
||||
auto strErr = StrPrinter << "media source:" << strApp << "/" << strStream << "not found!" << endl;
|
||||
auto strErr = StrPrinter << "media source:" << strVhost << "/" << strApp << "/" << strStream << "not found!" << endl;
|
||||
throw std::runtime_error(strErr);
|
||||
}
|
||||
init(src);
|
||||
|
@ -38,7 +38,7 @@ class RtmpPusher: public RtmpProtocol , public TcpClient{
|
||||
public:
|
||||
typedef std::shared_ptr<RtmpPusher> Ptr;
|
||||
typedef std::function<void(const SockException &ex)> Event;
|
||||
RtmpPusher(const char *strApp,const char *strStream);
|
||||
RtmpPusher(const char *strVhost,const char *strApp,const char *strStream);
|
||||
RtmpPusher(const RtmpMediaSource::Ptr &src);
|
||||
virtual ~RtmpPusher();
|
||||
|
||||
|
@ -97,7 +97,12 @@ void RtmpSession::onCmd_connect(AMFDecoder &dec) {
|
||||
///////////set peerBandwidth////////////////
|
||||
sendPeerBandwidth(5000000);
|
||||
|
||||
m_strApp = params["app"].as_string();
|
||||
m_mediaInfo.m_app = params["app"].as_string();
|
||||
m_strTcUrl = params["tcUrl"].as_string();
|
||||
if(m_strTcUrl.empty()){
|
||||
//defaultVhost:默认vhost
|
||||
m_strTcUrl = "rtmp://127.0.0.1/" + m_mediaInfo.m_app;
|
||||
}
|
||||
bool ok = true; //(app == APP_NAME);
|
||||
AMFValue version(AMF_OBJECT);
|
||||
version.set("fmsVer", "FMS/3,0,1,123");
|
||||
@ -109,7 +114,7 @@ void RtmpSession::onCmd_connect(AMFDecoder &dec) {
|
||||
status.set("objectEncoding", amfVer);
|
||||
sendReply(ok ? "_result" : "_error", version, status);
|
||||
if (!ok) {
|
||||
throw std::runtime_error("Unsupported application: " + m_strApp);
|
||||
throw std::runtime_error("Unsupported application: " + m_mediaInfo.m_app);
|
||||
}
|
||||
|
||||
AMFEncoder invoke;
|
||||
@ -123,12 +128,12 @@ void RtmpSession::onCmd_createStream(AMFDecoder &dec) {
|
||||
|
||||
void RtmpSession::onCmd_publish(AMFDecoder &dec) {
|
||||
dec.load<AMFValue>();/* NULL */
|
||||
m_strId = dec.load<std::string>();
|
||||
auto iPos = m_strId.find('?');
|
||||
if (iPos != string::npos) {
|
||||
m_strId.erase(iPos);
|
||||
}
|
||||
auto src = RtmpMediaSource::find(m_strApp,m_strId,false);
|
||||
m_mediaInfo.parse(m_strTcUrl + "/" + dec.load<std::string>());
|
||||
auto src = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,
|
||||
m_mediaInfo.m_vhost,
|
||||
m_mediaInfo.m_app,
|
||||
m_mediaInfo.m_streamid,
|
||||
false));
|
||||
bool ok = (!src && !m_pPublisherSrc);
|
||||
AMFValue status(AMF_OBJECT);
|
||||
status.set("level", ok ? "status" : "error");
|
||||
@ -137,10 +142,13 @@ void RtmpSession::onCmd_publish(AMFDecoder &dec) {
|
||||
status.set("clientid", "0");
|
||||
sendReply("onStatus", nullptr, status);
|
||||
if (!ok) {
|
||||
throw std::runtime_error( StrPrinter << "Already publishing:" << m_strApp << "/" << m_strId << endl);
|
||||
throw std::runtime_error( StrPrinter << "Already publishing:"
|
||||
<< m_mediaInfo.m_vhost << " "
|
||||
<< m_mediaInfo.m_app << " "
|
||||
<< m_mediaInfo.m_streamid << endl);
|
||||
}
|
||||
m_bPublisherSrcRegisted = false;
|
||||
m_pPublisherSrc.reset(new RtmpToRtspMediaSource(m_strApp,m_strId));
|
||||
m_pPublisherSrc.reset(new RtmpToRtspMediaSource(m_mediaInfo.m_vhost,m_mediaInfo.m_app,m_mediaInfo.m_streamid));
|
||||
}
|
||||
|
||||
void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) {
|
||||
@ -152,11 +160,15 @@ void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) {
|
||||
throw std::runtime_error(StrPrinter << "Stop publishing." << endl);
|
||||
}
|
||||
|
||||
void RtmpSession::doPlay(){
|
||||
auto src = RtmpMediaSource::find(m_strApp,m_strId,true);
|
||||
void RtmpSession::doPlay(AMFDecoder &dec){
|
||||
m_mediaInfo.parse(m_strTcUrl + "/" + dec.load<std::string>());
|
||||
auto src = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,
|
||||
m_mediaInfo.m_vhost,
|
||||
m_mediaInfo.m_app,
|
||||
m_mediaInfo.m_streamid,
|
||||
true));
|
||||
bool ok = (src.operator bool());
|
||||
ok = ok && src->ready();
|
||||
|
||||
//stream begin
|
||||
sendUserControl(CONTROL_STREAM_BEGIN, STREAM_MEDIA);
|
||||
|
||||
@ -165,11 +177,15 @@ void RtmpSession::doPlay(){
|
||||
status.set("level", ok ? "status" : "error");
|
||||
status.set("code", ok ? "NetStream.Play.Reset" : "NetStream.Play.StreamNotFound");
|
||||
status.set("description", ok ? "Resetting and playing." : "No such stream.");
|
||||
status.set("details", m_strId);
|
||||
status.set("details", m_mediaInfo.m_streamid);
|
||||
status.set("clientid", "0");
|
||||
sendReply("onStatus", nullptr, status);
|
||||
if (!ok) {
|
||||
throw std::runtime_error( StrPrinter << "No such stream:" << m_strApp << " " << m_strId << endl);
|
||||
throw std::runtime_error( StrPrinter << "No such stream:"
|
||||
<< m_mediaInfo.m_vhost << " "
|
||||
<< m_mediaInfo.m_app << " "
|
||||
<< m_mediaInfo.m_streamid
|
||||
<< endl);
|
||||
}
|
||||
|
||||
// onStatus(NetStream.Play.Start)
|
||||
@ -177,7 +193,7 @@ void RtmpSession::doPlay(){
|
||||
status.set("level", "status");
|
||||
status.set("code", "NetStream.Play.Start");
|
||||
status.set("description", "Started playing.");
|
||||
status.set("details", m_strId);
|
||||
status.set("details", m_mediaInfo.m_streamid);
|
||||
status.set("clientid", "0");
|
||||
sendReply("onStatus", nullptr, status);
|
||||
|
||||
@ -198,7 +214,7 @@ void RtmpSession::doPlay(){
|
||||
status.set("level", "status");
|
||||
status.set("code", "NetStream.Play.PublishNotify");
|
||||
status.set("description", "Now published.");
|
||||
status.set("details", m_strId);
|
||||
status.set("details", m_mediaInfo.m_streamid);
|
||||
status.set("clientid", "0");
|
||||
sendReply("onStatus", nullptr, status);
|
||||
|
||||
@ -239,18 +255,19 @@ void RtmpSession::doPlay(){
|
||||
if(src->getRing()->readerCount() == 1){
|
||||
src->seekTo(0);
|
||||
}
|
||||
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,
|
||||
RTMP_SCHEMA,
|
||||
m_mediaInfo.m_vhost.data(),
|
||||
m_mediaInfo.m_app.data(),
|
||||
m_mediaInfo.m_streamid.data());
|
||||
}
|
||||
void RtmpSession::onCmd_play2(AMFDecoder &dec) {
|
||||
doPlay();
|
||||
doPlay(dec);
|
||||
}
|
||||
void RtmpSession::onCmd_play(AMFDecoder &dec) {
|
||||
dec.load<AMFValue>();/* NULL */
|
||||
m_strId = dec.load<std::string>();
|
||||
auto iPos = m_strId.find('?');
|
||||
if (iPos != string::npos) {
|
||||
m_strId.erase(iPos);
|
||||
}
|
||||
doPlay();
|
||||
doPlay(dec);
|
||||
}
|
||||
|
||||
void RtmpSession::onCmd_pause(AMFDecoder &dec) {
|
||||
|
@ -53,8 +53,8 @@ public:
|
||||
void onError(const SockException &err) override;
|
||||
void onManager() override;
|
||||
private:
|
||||
std::string m_strApp;
|
||||
std::string m_strId;
|
||||
std::string m_strTcUrl;
|
||||
MediaInfo m_mediaInfo;
|
||||
double m_dNowReqID = 0;
|
||||
Ticker m_ticker;//数据接收时间
|
||||
typedef void (RtmpSession::*rtmpCMDHandle)(AMFDecoder &dec);
|
||||
@ -75,7 +75,7 @@ private:
|
||||
|
||||
void onCmd_play(AMFDecoder &dec);
|
||||
void onCmd_play2(AMFDecoder &dec);
|
||||
void doPlay();
|
||||
void doPlay(AMFDecoder &dec);
|
||||
void onCmd_seek(AMFDecoder &dec);
|
||||
void onCmd_pause(AMFDecoder &dec);
|
||||
void setMetaData(AMFDecoder &dec);
|
||||
|
@ -36,25 +36,23 @@ using namespace ZL::Network;
|
||||
namespace ZL {
|
||||
namespace Rtmp {
|
||||
|
||||
#ifdef ENABLE_RTMP2RTSP
|
||||
RtmpToRtspMediaSource::RtmpToRtspMediaSource(const string &_app, const string &_id) :
|
||||
RtmpMediaSource(_app,_id) {
|
||||
}
|
||||
RtmpToRtspMediaSource::~RtmpToRtspMediaSource() {
|
||||
RtmpToRtspMediaSource::RtmpToRtspMediaSource(const string &vhost,const string &app, const string &id) :
|
||||
RtmpMediaSource(vhost,app,id) {
|
||||
}
|
||||
RtmpToRtspMediaSource::~RtmpToRtspMediaSource() {}
|
||||
|
||||
void RtmpToRtspMediaSource::regist() {
|
||||
RtmpMediaSource::regist();
|
||||
bool RtmpToRtspMediaSource::regist() {
|
||||
if (m_pRtspSrc) {
|
||||
m_pRtspSrc->regist();
|
||||
}
|
||||
return MediaSource::regist();
|
||||
}
|
||||
|
||||
void RtmpToRtspMediaSource::unregist() {
|
||||
RtmpMediaSource::unregist();
|
||||
bool RtmpToRtspMediaSource::unregist() {
|
||||
if(m_pRtspSrc){
|
||||
m_pRtspSrc->unregist();
|
||||
}
|
||||
return MediaSource::unregist();
|
||||
}
|
||||
|
||||
void RtmpToRtspMediaSource::onGetH264(const H264Frame &frame) {
|
||||
@ -156,14 +154,12 @@ void RtmpToRtspMediaSource::makeSDP() {
|
||||
<< "\r\n" << endl;
|
||||
}
|
||||
|
||||
m_pRtspSrc.reset(new RtspMediaSource(getApp(),getId()));
|
||||
m_pRtspSrc->setOnSeek(m_onSeek);
|
||||
m_pRtspSrc->setOnStamp(m_onStamp);
|
||||
m_pRtspSrc.reset(new RtspMediaSource(getVhost(),getApp(),getId()));
|
||||
m_pRtspSrc->setListener(m_listener);
|
||||
m_pRtspSrc->onGetSDP(strSDP);
|
||||
m_pRtspSrc->regist();
|
||||
}
|
||||
|
||||
#endif // ENABLE_RTMP2RTSP
|
||||
|
||||
} /* namespace Rtmp */
|
||||
} /* namespace ZL */
|
||||
|
@ -52,19 +52,20 @@ using namespace ZL::MediaFile;
|
||||
namespace ZL {
|
||||
namespace Rtmp {
|
||||
|
||||
#ifdef ENABLE_RTMP2RTSP
|
||||
class RtmpToRtspMediaSource: public RtmpMediaSource {
|
||||
public:
|
||||
typedef std::shared_ptr<RtmpToRtspMediaSource> Ptr;
|
||||
RtmpToRtspMediaSource(const string &_app, const string &_id);
|
||||
virtual ~RtmpToRtspMediaSource();
|
||||
virtual void regist() override;
|
||||
virtual void unregist() override;
|
||||
|
||||
virtual void onGetMetaData(const AMFValue &_metadata) override {
|
||||
RtmpToRtspMediaSource(const string &vhost,const string &app, const string &id);
|
||||
virtual ~RtmpToRtspMediaSource();
|
||||
|
||||
bool regist() override;
|
||||
bool unregist() override;
|
||||
|
||||
void onGetMetaData(const AMFValue &_metadata) override {
|
||||
try {
|
||||
m_pParser.reset(new RtmpParser(_metadata));
|
||||
m_pRecorder.reset(new MediaRecorder(getApp(),getId(),m_pParser));
|
||||
m_pRecorder.reset(new MediaRecorder(getVhost(),getApp(),getId(),m_pParser));
|
||||
m_pParser->setOnAudioCB(std::bind(&RtmpToRtspMediaSource::onGetAdts, this, placeholders::_1));
|
||||
m_pParser->setOnVideoCB(std::bind(&RtmpToRtspMediaSource::onGetH264, this, placeholders::_1));
|
||||
} catch (exception &ex) {
|
||||
@ -73,7 +74,7 @@ public:
|
||||
RtmpMediaSource::onGetMetaData(_metadata);
|
||||
}
|
||||
|
||||
virtual void onGetMedia(const RtmpPacket::Ptr &pkt) override {
|
||||
void onGetMedia(const RtmpPacket::Ptr &pkt) override {
|
||||
if (m_pParser) {
|
||||
if (!m_pRtspSrc && m_pParser->isInited()) {
|
||||
makeSDP();
|
||||
@ -82,18 +83,7 @@ public:
|
||||
}
|
||||
RtmpMediaSource::onGetMedia(pkt);
|
||||
}
|
||||
void setOnSeek(const function<bool(uint32_t)> &cb) override {
|
||||
RtmpMediaSource::setOnSeek(cb);
|
||||
if (m_pRtspSrc) {
|
||||
m_pRtspSrc->setOnSeek(cb);
|
||||
}
|
||||
}
|
||||
void setOnStamp(const function<uint32_t()> &cb) override{
|
||||
RtmpMediaSource::setOnStamp(cb);
|
||||
if (m_pRtspSrc) {
|
||||
m_pRtspSrc->setOnStamp(cb);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
RtmpParser::Ptr m_pParser;
|
||||
RtspMediaSource::Ptr m_pRtspSrc;
|
||||
@ -105,9 +95,6 @@ private:
|
||||
void onGetAdts(const AdtsFrame &frame);
|
||||
void makeSDP();
|
||||
};
|
||||
#else
|
||||
typedef RtmpMediaSource RtmpToRtspMediaSource;
|
||||
#endif //ENABLE_RTMP2RTSP
|
||||
|
||||
} /* namespace Rtmp */
|
||||
} /* namespace ZL */
|
||||
|
@ -84,10 +84,10 @@ RtpBroadCaster::~RtpBroadCaster() {
|
||||
m_pReader->setDetachCB(nullptr);
|
||||
DebugL;
|
||||
}
|
||||
RtpBroadCaster::RtpBroadCaster(const string &strLocalIp,const string &strApp,const string &strStream) {
|
||||
auto src = RtspMediaSource::find(strApp, strStream);
|
||||
RtpBroadCaster::RtpBroadCaster(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 << "未找到媒体源:" << strApp << " " << strStream << endl;
|
||||
auto strErr = StrPrinter << "未找到媒体源:" << strVhost << " " << strApp << " " << strStream << endl;
|
||||
throw std::runtime_error(strErr);
|
||||
}
|
||||
m_multiAddr = MultiCastAddressMaker::Instance().obtain();
|
||||
@ -130,6 +130,7 @@ RtpBroadCaster::RtpBroadCaster(const string &strLocalIp,const string &strApp,con
|
||||
DebugL << MultiCastAddressMaker::toString(*m_multiAddr) << " "
|
||||
<< m_apUdpSock[0]->get_local_port() << " "
|
||||
<< m_apUdpSock[1]->get_local_port() << " "
|
||||
<< strVhost << " "
|
||||
<< strApp << " " << strStream;
|
||||
}
|
||||
uint16_t RtpBroadCaster::getPort(int iTrackId){
|
||||
@ -139,11 +140,11 @@ uint16_t RtpBroadCaster::getPort(int iTrackId){
|
||||
string RtpBroadCaster::getIP(){
|
||||
return inet_ntoa(m_aPeerUdpAddr[0].sin_addr);
|
||||
}
|
||||
RtpBroadCaster::Ptr RtpBroadCaster::make(const string &strLocalIp,const string &strApp,const string &strStream){
|
||||
RtpBroadCaster::Ptr RtpBroadCaster::make(const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream){
|
||||
try{
|
||||
auto ret = Ptr(new RtpBroadCaster(strLocalIp,strApp,strStream));
|
||||
auto ret = Ptr(new RtpBroadCaster(strLocalIp,strVhost,strApp,strStream));
|
||||
lock_guard<recursive_mutex> lck(g_mtx);
|
||||
string strKey = StrPrinter << strLocalIp << " " << strApp << " " << strStream << endl;
|
||||
string strKey = StrPrinter << strLocalIp << " " << strVhost << " " << strApp << " " << strStream << endl;
|
||||
weak_ptr<RtpBroadCaster> weakPtr = ret;
|
||||
g_mapBroadCaster.emplace(strKey,weakPtr);
|
||||
return ret;
|
||||
@ -153,17 +154,17 @@ RtpBroadCaster::Ptr RtpBroadCaster::make(const string &strLocalIp,const string &
|
||||
}
|
||||
}
|
||||
|
||||
RtpBroadCaster::Ptr RtpBroadCaster::get(const string &strLocalIp,const string& strApp, const string& strStream) {
|
||||
string strKey = StrPrinter << strLocalIp << " " << strApp << " " << strStream << endl;
|
||||
RtpBroadCaster::Ptr RtpBroadCaster::get(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(strLocalIp,strApp, strStream);
|
||||
return make(strLocalIp,strVhost,strApp, strStream);
|
||||
}
|
||||
auto ret = it->second.lock();
|
||||
if (!ret) {
|
||||
g_mapBroadCaster.erase(it);
|
||||
return make(strLocalIp,strApp, strStream);
|
||||
return make(strLocalIp,strVhost,strApp, strStream);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -74,14 +74,14 @@ public:
|
||||
typedef std::shared_ptr<RtpBroadCaster> Ptr;
|
||||
typedef function<void()> onDetach;
|
||||
virtual ~RtpBroadCaster();
|
||||
static Ptr get(const string &strLocalIp,const string &strApp,const string &strStream);
|
||||
static Ptr get(const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream);
|
||||
void setDetachCB(void *listener,const onDetach &cb);
|
||||
uint16_t getPort(int iTrackId);
|
||||
string getIP();
|
||||
private:
|
||||
static recursive_mutex g_mtx;
|
||||
static unordered_map<string , weak_ptr<RtpBroadCaster> > g_mapBroadCaster;
|
||||
static Ptr make(const string &strLocalIp,const string &strApp,const string &strStream);
|
||||
static Ptr make(const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream);
|
||||
|
||||
std::shared_ptr<uint32_t> m_multiAddr;
|
||||
recursive_mutex m_mtx;
|
||||
@ -90,7 +90,7 @@ private:
|
||||
Socket::Ptr m_apUdpSock[2];
|
||||
struct sockaddr_in m_aPeerUdpAddr[2];
|
||||
|
||||
RtpBroadCaster(const string &strLocalIp,const string &strApp,const string &strStream);
|
||||
RtpBroadCaster(const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream);
|
||||
|
||||
};
|
||||
|
||||
|
@ -163,36 +163,18 @@ public:
|
||||
this->m_strContent = content;
|
||||
}
|
||||
|
||||
const StrCaseMap& getValues() const {
|
||||
StrCaseMap& getValues() const {
|
||||
return m_mapValues;
|
||||
}
|
||||
const StrCaseMap& getUrlArgs() const {
|
||||
StrCaseMap& getUrlArgs() const {
|
||||
return m_mapUrlArgs;
|
||||
}
|
||||
|
||||
//注意:当字符串为空时,也会返回一个空字符串
|
||||
static vector<string> split(const string& s, const char *delim) {
|
||||
size_t last = 0;
|
||||
size_t index = s.find_first_of(delim, last);
|
||||
vector<string> ret;
|
||||
while (index != string::npos) {
|
||||
ret.push_back(s.substr(last, index - last));
|
||||
last = index + 1;
|
||||
index = s.find_first_of(delim, last);
|
||||
}
|
||||
if (index - last > 0) {
|
||||
ret.push_back(s.substr(last, index - last));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static StrCaseMap parseArgs(const string &str,const char *pair_delim = "&", const char *key_delim = "="){
|
||||
StrCaseMap ret;
|
||||
auto arg_vec = split(str, pair_delim);
|
||||
for (string &key_val : arg_vec) {
|
||||
if (!key_val.size()) {
|
||||
continue;
|
||||
}
|
||||
auto key_val_vec = split(key_val, key_delim);
|
||||
if (key_val_vec.size() >= 2) {
|
||||
ret[key_val_vec[0]] = key_val_vec[1];
|
||||
@ -207,8 +189,8 @@ private:
|
||||
string m_strTail;
|
||||
string m_strContent;
|
||||
string m_strNull;
|
||||
StrCaseMap m_mapValues;
|
||||
StrCaseMap m_mapUrlArgs;
|
||||
mutable StrCaseMap m_mapValues;
|
||||
mutable StrCaseMap m_mapUrlArgs;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -32,30 +32,5 @@ using namespace ZL::MediaFile;
|
||||
namespace ZL {
|
||||
namespace Rtsp {
|
||||
|
||||
recursive_mutex RtspMediaSource::g_mtxMediaSrc;
|
||||
unordered_map<string, unordered_map<string, weak_ptr<RtspMediaSource> > > RtspMediaSource::g_mapMediaSrc;
|
||||
|
||||
RtspMediaSource::Ptr RtspMediaSource::find(const string &strApp, const string &strId,bool bMake) {
|
||||
//查找某一媒体源,找到后返回
|
||||
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
|
||||
auto itApp = g_mapMediaSrc.find(strApp);
|
||||
if (itApp == g_mapMediaSrc.end()) {
|
||||
return bMake ? MediaReader::onMakeRtsp(strApp, strId) : nullptr;
|
||||
}
|
||||
auto itId = itApp->second.find(strId);
|
||||
if (itId == itApp->second.end()) {
|
||||
return bMake ? MediaReader::onMakeRtsp(strApp, strId) : nullptr;
|
||||
}
|
||||
auto ret = itId->second.lock();
|
||||
if(ret){
|
||||
return ret;
|
||||
}
|
||||
itApp->second.erase(itId);
|
||||
if (itApp->second.size() == 0) {
|
||||
g_mapMediaSrc.erase(itApp);
|
||||
}
|
||||
return bMake ? MediaReader::onMakeRtsp(strApp, strId) : nullptr;
|
||||
}
|
||||
|
||||
} /* namespace Rtsp */
|
||||
} /* namespace ZL */
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include "Rtsp.h"
|
||||
#include "Common/config.h"
|
||||
#include "Common/MediaSender.h"
|
||||
#include "Common/MediaSource.h"
|
||||
|
||||
#include "Util/logger.h"
|
||||
#include "Util/RingBuffer.h"
|
||||
#include "Util/TimeTicker.h"
|
||||
@ -45,80 +47,33 @@
|
||||
using namespace std;
|
||||
using namespace ZL::Util;
|
||||
using namespace ZL::Thread;
|
||||
using namespace ZL::Media;
|
||||
|
||||
namespace ZL {
|
||||
namespace Rtsp {
|
||||
|
||||
|
||||
|
||||
class RtspMediaSource: public enable_shared_from_this<RtspMediaSource> {
|
||||
class RtspMediaSource: public MediaSource {
|
||||
public:
|
||||
typedef ResourcePool<RtpPacket, 64> PoolType;
|
||||
typedef std::shared_ptr<RtspMediaSource> Ptr;
|
||||
typedef RingBuffer<RtpPacket::Ptr> RingType;
|
||||
RtspMediaSource(const string &strApp, const string &strId) :
|
||||
m_strApp(strApp),
|
||||
m_strId(strId),
|
||||
|
||||
RtspMediaSource(const string &strVhost,const string &strApp, const string &strId) :
|
||||
MediaSource(RTSP_SCHEMA,strVhost,strApp,strId),
|
||||
m_pRing(new RingBuffer<RtpPacket::Ptr>()),
|
||||
m_thPool(MediaSender::sendThread()) {
|
||||
}
|
||||
virtual ~RtspMediaSource() {
|
||||
unregist();
|
||||
}
|
||||
virtual ~RtspMediaSource() {}
|
||||
|
||||
const RingType::Ptr &getRing() const {
|
||||
//获取媒体源的rtp环形缓冲
|
||||
return m_pRing;
|
||||
}
|
||||
|
||||
const string& getSdp() const {
|
||||
//获取该源的媒体描述信息
|
||||
return m_strSdp;
|
||||
}
|
||||
virtual void regist() {
|
||||
//注册该源,注册后rtsp服务器才能找到该源
|
||||
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
|
||||
if (!g_mapMediaSrc[m_strApp].erase(m_strId)) {
|
||||
InfoL << "Rtsp src:" << m_strApp << " " << m_strId;
|
||||
}
|
||||
g_mapMediaSrc[m_strApp].emplace(m_strId, shared_from_this());
|
||||
NoticeCenter::Instance().emitEvent(Config::Broadcast::kBroadcastRtspSrcRegisted,m_strApp.data(),m_strId.data());
|
||||
}
|
||||
virtual void unregist() {
|
||||
//反注册该源
|
||||
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
|
||||
auto it = g_mapMediaSrc.find(m_strApp);
|
||||
if (it == g_mapMediaSrc.end()) {
|
||||
return;
|
||||
}
|
||||
if (it->second.erase(m_strId)) {
|
||||
if(it->second.size() == 0){
|
||||
g_mapMediaSrc.erase(it);
|
||||
}
|
||||
InfoL << "Rtsp src:" << m_strApp << " " << m_strId;
|
||||
}
|
||||
}
|
||||
static set<string> getMediaSet() {
|
||||
set<string> ret;
|
||||
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
|
||||
for (auto &pr0 : g_mapMediaSrc) {
|
||||
for (auto &pr1 : pr0.second) {
|
||||
if(pr1.second.lock()){
|
||||
ret.emplace(pr0.first + "/" + pr1.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static Ptr find(const string &_app, const string &_id,bool bMake = true) ;
|
||||
|
||||
const string& getApp() const {
|
||||
//获取该源的id
|
||||
return m_strApp;
|
||||
}
|
||||
const string& getId() const {
|
||||
return m_strId;
|
||||
}
|
||||
virtual uint32_t getSsrc(int trackId) {
|
||||
return m_mapTracks[trackId].ssrc;
|
||||
}
|
||||
@ -131,7 +86,7 @@ public:
|
||||
|
||||
virtual void onGetSDP(const string& sdp) {
|
||||
//派生类设置该媒体源媒体描述信息
|
||||
this->m_strSdp = sdp;
|
||||
m_strSdp = sdp;
|
||||
}
|
||||
virtual void onGetRTP(const RtpPacket::Ptr &rtppt, bool keyPos) {
|
||||
auto &trackRef = m_mapTracks[rtppt->interleaved / 2];
|
||||
@ -144,36 +99,11 @@ public:
|
||||
_outRing->write(rtppt,keyPos);
|
||||
});
|
||||
}
|
||||
bool seekTo(uint32_t ui32Stamp) {
|
||||
if (!m_onSeek) {
|
||||
return false;
|
||||
}
|
||||
return m_onSeek(ui32Stamp);
|
||||
}
|
||||
virtual void setOnSeek(const function<bool(uint32_t)> &cb){
|
||||
m_onSeek = cb;
|
||||
}
|
||||
uint32_t getStamp() {
|
||||
if (!m_onStamp) {
|
||||
return 0;
|
||||
}
|
||||
return m_onStamp();
|
||||
}
|
||||
virtual void setOnStamp(const function<uint32_t()> &cb) {
|
||||
m_onStamp = cb;
|
||||
}
|
||||
protected:
|
||||
function<bool(uint32_t)> m_onSeek;
|
||||
function<uint32_t()> m_onStamp;
|
||||
unordered_map<int, RtspTrack> m_mapTracks;
|
||||
private:
|
||||
string m_strSdp; //媒体描述信息
|
||||
string m_strApp; //媒体app
|
||||
string m_strId; //媒体id
|
||||
RingType::Ptr m_pRing; //rtp环形缓冲
|
||||
ThreadPool &m_thPool;
|
||||
static unordered_map<string, unordered_map<string, weak_ptr<RtspMediaSource> > > g_mapMediaSrc; //静态的媒体源表
|
||||
static recursive_mutex g_mtxMediaSrc; ///访问静态的媒体源表的互斥锁
|
||||
};
|
||||
|
||||
} /* namespace Rtsp */
|
||||
|
@ -427,19 +427,6 @@ void RtspPlayer::pause(bool bPause) {
|
||||
sendPause(bPause,getProgressTime());
|
||||
}
|
||||
|
||||
//注意:当字符串为空时,也会返回一个空字符串
|
||||
static void split(const string& s, const char *delim, vector<string> &ret) {
|
||||
size_t last = 0;
|
||||
size_t index = s.find_first_of(delim, last);
|
||||
while (index != string::npos) {
|
||||
ret.push_back(s.substr(last, index - last));
|
||||
last = index + 1;
|
||||
index = s.find_first_of(delim, last);
|
||||
}
|
||||
if (index - last > 0) {
|
||||
ret.push_back(s.substr(last, index - last));
|
||||
}
|
||||
}
|
||||
void RtspPlayer::HandleResPAUSE(const Parser& parser, bool bPause) {
|
||||
if (parser.Url() != "200") {
|
||||
WarnL <<(bPause ? "Pause" : "Play") << " failed:" << parser.Url() << " " << parser.Tail() << endl;
|
||||
@ -461,10 +448,8 @@ void RtspPlayer::HandleResPAUSE(const Parser& parser, bool bPause) {
|
||||
auto strRtpInfo = parser["RTP-Info"];
|
||||
if (strRtpInfo.size()) {
|
||||
strRtpInfo.append(",");
|
||||
vector<string> vec;
|
||||
split(strRtpInfo, ",", vec);
|
||||
vector<string> vec = split(strRtpInfo, ",");
|
||||
for(auto &strTrack : vec){
|
||||
if (strTrack.size()) {
|
||||
strTrack.append(";");
|
||||
auto strTrackId = FindField(strTrack.data(), m_aTrackInfo[0].trackStyle.data(), ";");
|
||||
auto strRtpTime = FindField(strTrack.data(), "rtptime=", ";");
|
||||
@ -473,7 +458,6 @@ void RtspPlayer::HandleResPAUSE(const Parser& parser, bool bPause) {
|
||||
m_adNowStamp[iIdx] = m_adFistStamp[iIdx];
|
||||
DebugL << "rtptime:" << strTrackId <<" " << strRtpTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
_onPlayResult(SockException(Err_success, "rtsp play success"));
|
||||
} else {
|
||||
|
@ -55,7 +55,6 @@ unordered_map<void *, std::shared_ptr<RtspSession> > RtspSession::g_mapPostter;
|
||||
recursive_mutex RtspSession::g_mtxGetter; //对quicktime上锁保护
|
||||
recursive_mutex RtspSession::g_mtxPostter; //对quicktime上锁保护
|
||||
unordered_map<string, RtspSession::rtspCMDHandle> RtspSession::g_mapCmd;
|
||||
string RtspSession::g_serverName;
|
||||
RtspSession::RtspSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock) :
|
||||
TcpLimitedSession(pTh, pSock), m_pSender(pSock) {
|
||||
static onceToken token( []() {
|
||||
@ -69,7 +68,6 @@ RtspSession::RtspSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::P
|
||||
g_mapCmd.emplace("POST",&RtspSession::handleReq_Post);
|
||||
g_mapCmd.emplace("SET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER);
|
||||
g_mapCmd.emplace("GET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER);
|
||||
g_serverName = mINI::Instance()[Config::Rtsp::kServerName];
|
||||
}, []() {});
|
||||
|
||||
#ifndef __x86_64__
|
||||
@ -184,7 +182,7 @@ bool RtspSession::handleReq_Options() {
|
||||
"%s"
|
||||
"Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY,"
|
||||
" PAUSE, SET_PARAMETER, GET_PARAMETER\r\n\r\n",
|
||||
m_iCseq, g_serverName.data(),
|
||||
m_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data());
|
||||
send(m_pcBuf, n);
|
||||
@ -192,7 +190,15 @@ bool RtspSession::handleReq_Options() {
|
||||
}
|
||||
|
||||
bool RtspSession::handleReq_Describe() {
|
||||
{
|
||||
//解析url获取媒体名称
|
||||
m_strUrl = m_parser.Url();
|
||||
m_mediaInfo.parse(m_strUrl);
|
||||
if(!m_parser.getUrlArgs()[VHOST_KEY].empty()){
|
||||
m_mediaInfo.m_vhost = m_parser.getUrlArgs()[VHOST_KEY];
|
||||
}
|
||||
}
|
||||
|
||||
if (!findStream()) {
|
||||
//未找到相应的MediaSource
|
||||
send_StreamNotFound();
|
||||
@ -213,7 +219,10 @@ bool RtspSession::handleReq_Describe() {
|
||||
};
|
||||
|
||||
//广播是否需要认证事件
|
||||
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm,m_strApp.data(),m_strStream.data(),invoker)){
|
||||
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm,
|
||||
m_mediaInfo.m_app.data(),
|
||||
m_mediaInfo.m_streamid.data(),
|
||||
invoker)){
|
||||
//无人监听此事件,说明无需认证
|
||||
invoker("");
|
||||
}
|
||||
@ -242,7 +251,7 @@ void RtspSession::onAuthSuccess(const weak_ptr<RtspSession> &weakSelf) {
|
||||
"Content-Base: %s/\r\n"
|
||||
"Content-Type: application/sdp\r\n"
|
||||
"Content-Length: %d\r\n\r\n%s",
|
||||
strongSelf->m_iCseq, strongSelf->g_serverName.data(),
|
||||
strongSelf->m_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), strongSelf->m_strUrl.data(),
|
||||
(int) strongSelf->m_strSdp.length(), strongSelf->m_strSdp.data());
|
||||
@ -274,7 +283,7 @@ void RtspSession::onAuthFailed(const weak_ptr<RtspSession> &weakSelf,const strin
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"WWW-Authenticate:Digest realm=\"%s\",nonce=\"%s\"\r\n\r\n",
|
||||
strongSelf->m_iCseq, strongSelf->g_serverName.data(),
|
||||
strongSelf->m_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), realm.data(), strongSelf->m_strNonce.data());
|
||||
}else {
|
||||
@ -285,7 +294,7 @@ void RtspSession::onAuthFailed(const weak_ptr<RtspSession> &weakSelf,const strin
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"WWW-Authenticate:Basic realm=\"%s\"\r\n\r\n",
|
||||
strongSelf->m_iCseq, strongSelf->g_serverName.data(),
|
||||
strongSelf->m_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), realm.data());
|
||||
}
|
||||
@ -297,7 +306,7 @@ void RtspSession::onAuthBasic(const weak_ptr<RtspSession> &weakSelf,const string
|
||||
//base64认证
|
||||
char user_pwd_buf[512];
|
||||
av_base64_decode((uint8_t *)user_pwd_buf,strBase64.data(),strBase64.size());
|
||||
auto user_pwd_vec = Parser::split(user_pwd_buf,":");
|
||||
auto user_pwd_vec = split(user_pwd_buf,":");
|
||||
if(user_pwd_vec.size() < 2){
|
||||
//认证信息格式不合法,回复401 Unauthorized
|
||||
onAuthFailed(weakSelf,realm);
|
||||
@ -324,23 +333,7 @@ void RtspSession::onAuthBasic(const weak_ptr<RtspSession> &weakSelf,const string
|
||||
invoker(false,pwd);
|
||||
}
|
||||
}
|
||||
static string trim(string str){
|
||||
while(!str.empty()){
|
||||
if(str.front()==' ' || str.front()=='"'){
|
||||
str.erase(0,1);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while(!str.empty()){
|
||||
if(str.back()==' ' || str.back()=='"'){
|
||||
str.pop_back();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void RtspSession::onAuthDigest(const weak_ptr<RtspSession> &weakSelf,const string &realm,const string &strMd5){
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf){
|
||||
@ -351,7 +344,7 @@ void RtspSession::onAuthDigest(const weak_ptr<RtspSession> &weakSelf,const strin
|
||||
auto mapTmp = Parser::parseArgs(strMd5,",","=");
|
||||
decltype(mapTmp) map;
|
||||
for(auto &pr : mapTmp){
|
||||
map[trim(pr.first)] = trim(pr.second);
|
||||
map[trim(string(pr.first)," \"")] = trim(pr.second," \"");
|
||||
}
|
||||
//check realm
|
||||
if(realm != map["realm"]){
|
||||
@ -448,7 +441,7 @@ inline void RtspSession::send_StreamNotFound() {
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Connection: Close\r\n\r\n",
|
||||
m_iCseq, g_serverName.data(),
|
||||
m_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data());
|
||||
send(m_pcBuf, n);
|
||||
@ -459,7 +452,7 @@ inline void RtspSession::send_UnsupportedTransport() {
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Connection: Close\r\n\r\n",
|
||||
m_iCseq, g_serverName.data(),
|
||||
m_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data());
|
||||
send(m_pcBuf, n);
|
||||
@ -471,7 +464,7 @@ inline void RtspSession::send_SessionNotFound() {
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Connection: Close\r\n\r\n",
|
||||
m_iCseq, g_serverName.data(),
|
||||
m_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data());
|
||||
send(m_pcBuf, n);
|
||||
@ -539,7 +532,7 @@ bool RtspSession::handleReq_Setup() {
|
||||
"Session: %s\r\n"
|
||||
"x-Transport-Options: late-tolerance=1.400000\r\n"
|
||||
"x-Dynamic-Rate: 1\r\n\r\n",
|
||||
m_iCseq, g_serverName.data(),
|
||||
m_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), trackid * 2,
|
||||
trackid * 2 + 1,
|
||||
@ -584,7 +577,7 @@ bool RtspSession::handleReq_Setup() {
|
||||
"Transport: RTP/AVP/UDP;unicast;"
|
||||
"client_port=%s;server_port=%d-%d;ssrc=%s;mode=play\r\n"
|
||||
"Session: %s\r\n\r\n",
|
||||
m_iCseq, g_serverName.data(),
|
||||
m_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), strClientPort.data(),
|
||||
pSockRtp->get_local_port(), pSockRtcp->get_local_port(),
|
||||
@ -595,7 +588,7 @@ bool RtspSession::handleReq_Setup() {
|
||||
break;
|
||||
case PlayerBase::RTP_MULTICAST: {
|
||||
if(!m_pBrdcaster){
|
||||
m_pBrdcaster = RtpBroadCaster::get(getLocalIp(), m_strApp, m_strStream);
|
||||
m_pBrdcaster = RtpBroadCaster::get(getLocalIp(),m_mediaInfo.m_vhost, m_mediaInfo.m_app, m_mediaInfo.m_streamid);
|
||||
if (!m_pBrdcaster) {
|
||||
send_NotAcceptable();
|
||||
return false;
|
||||
@ -627,7 +620,7 @@ bool RtspSession::handleReq_Setup() {
|
||||
"Transport: RTP/AVP;multicast;destination=%s;"
|
||||
"source=%s;port=%d-%d;ttl=%d;ssrc=%s\r\n"
|
||||
"Session: %s\r\n\r\n",
|
||||
m_iCseq, g_serverName.data(),
|
||||
m_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), m_pBrdcaster->getIP().data(),
|
||||
getLocalIp().data(), iSrvPort, pSockRtcp->get_local_port(),
|
||||
@ -705,7 +698,7 @@ bool RtspSession::handleReq_Play() {
|
||||
"%s"
|
||||
"Session: %s\r\n"
|
||||
"Range: npt=%.2f-\r\n"
|
||||
"RTP-Info: ", m_iCseq, g_serverName.data(), RTSP_VERSION, RTSP_BUILDTIME,
|
||||
"RTP-Info: ", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), m_strSession.data(),iStamp/1000.0);
|
||||
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
|
||||
@ -722,7 +715,11 @@ bool RtspSession::handleReq_Play() {
|
||||
(m_pcBuf)[iLen] = '\0';
|
||||
iLen += sprintf(m_pcBuf + iLen, "\r\n\r\n");
|
||||
send(m_pcBuf, iLen);
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRtspSessionPlay, m_strApp.data(),m_strStream.data());
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,
|
||||
RTSP_SCHEMA,
|
||||
m_mediaInfo.m_vhost.data(),
|
||||
m_mediaInfo.m_app.data(),
|
||||
m_mediaInfo.m_streamid.data());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -735,7 +732,7 @@ bool RtspSession::handleReq_Pause() {
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Session: %s\r\n\r\n", m_iCseq, g_serverName.data(), RTSP_VERSION, RTSP_BUILDTIME,
|
||||
"Session: %s\r\n\r\n", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), m_strSession.data());
|
||||
send(m_pcBuf, n);
|
||||
if(m_pRtpReader){
|
||||
@ -750,7 +747,7 @@ bool RtspSession::handleReq_Teardown() {
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Session: %s\r\n\r\n", m_iCseq, g_serverName.data(), RTSP_VERSION, RTSP_BUILDTIME,
|
||||
"Session: %s\r\n\r\n", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), m_strSession.data());
|
||||
|
||||
send(m_pcBuf, n);
|
||||
@ -801,7 +798,7 @@ bool RtspSession::handleReq_SET_PARAMETER() {
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Session: %s\r\n\r\n", m_iCseq, g_serverName.data(), RTSP_VERSION, RTSP_BUILDTIME,
|
||||
"Session: %s\r\n\r\n", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), m_strSession.data());
|
||||
send(m_pcBuf, n);
|
||||
return true;
|
||||
@ -812,21 +809,17 @@ inline void RtspSession::send_NotAcceptable() {
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Connection: Close\r\n\r\n", m_iCseq, g_serverName.data(), RTSP_VERSION, RTSP_BUILDTIME,
|
||||
"Connection: Close\r\n\r\n", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data());
|
||||
send(m_pcBuf, n);
|
||||
|
||||
}
|
||||
void RtspSession::splitRtspUrl(const string &url,string &app,string &stream){
|
||||
string strHost = FindField(url.data(), "://", "/");
|
||||
app = FindField(url.data(), (strHost + "/").data(), "/");
|
||||
stream = FindField(url.data(), (strHost + "/" + app + "/").data(), NULL);
|
||||
}
|
||||
|
||||
inline bool RtspSession::findStream() {
|
||||
splitRtspUrl(m_strUrl,m_strApp,m_strStream);
|
||||
RtspMediaSource::Ptr pMediaSrc = RtspMediaSource::find(m_strApp,m_strStream);
|
||||
RtspMediaSource::Ptr pMediaSrc =
|
||||
dynamic_pointer_cast<RtspMediaSource>( MediaSource::find(RTSP_SCHEMA,m_mediaInfo.m_vhost, m_mediaInfo.m_app,m_mediaInfo.m_streamid) );
|
||||
if (!pMediaSrc) {
|
||||
WarnL << "No such stream:" << m_strApp << " " << m_strStream;
|
||||
WarnL << "No such stream:" << m_mediaInfo.m_vhost << " " << m_mediaInfo.m_app << " " << m_mediaInfo.m_streamid;
|
||||
return false;
|
||||
}
|
||||
m_strSdp = pMediaSrc->getSdp();
|
||||
|
@ -109,7 +109,6 @@ private:
|
||||
void inline send_UnsupportedTransport(); //不支持的传输模式
|
||||
void inline send_SessionNotFound(); //会话id错误
|
||||
void inline send_NotAcceptable(); //rtsp同时播放数限制
|
||||
void splitRtspUrl(const string &url,string &app,string &stream);
|
||||
inline bool findStream(); //根据rtsp url查找 MediaSource实例
|
||||
|
||||
inline void initSender(const std::shared_ptr<RtspSession> &pSession); //处理rtsp over http,quicktime使用的
|
||||
@ -148,8 +147,7 @@ private:
|
||||
string m_strSdp;
|
||||
string m_strSession;
|
||||
bool m_bFirstPlay = true;
|
||||
string m_strApp;
|
||||
string m_strStream;
|
||||
MediaInfo m_mediaInfo;
|
||||
std::weak_ptr<RtspMediaSource> m_pMediaSrc;
|
||||
static unordered_map<string, rtspCMDHandle> g_mapCmd;
|
||||
|
||||
@ -191,7 +189,6 @@ private:
|
||||
static recursive_mutex g_mtxPostter; //对quicktime上锁保护
|
||||
static unordered_map<string, weak_ptr<RtspSession> > g_mapGetter;
|
||||
static unordered_map<void *, std::shared_ptr<RtspSession> > g_mapPostter;
|
||||
static string g_serverName;
|
||||
|
||||
};
|
||||
|
||||
|
@ -37,28 +37,27 @@ using namespace ZL::Network;
|
||||
namespace ZL {
|
||||
namespace Rtsp {
|
||||
|
||||
#ifdef ENABLE_RTSP2RTMP
|
||||
|
||||
RtspToRtmpMediaSource::RtspToRtmpMediaSource(const string &_app,const string &_id,bool bEnableFile) :
|
||||
RtspMediaSource(_app,_id),m_bEnableFile(bEnableFile) {
|
||||
RtspToRtmpMediaSource::RtspToRtmpMediaSource(const string &vhost,const string &app,const string &id,bool bEnableFile) :
|
||||
RtspMediaSource(vhost,app,id),m_bEnableFile(bEnableFile) {
|
||||
}
|
||||
|
||||
RtspToRtmpMediaSource::~RtspToRtmpMediaSource() {
|
||||
|
||||
}
|
||||
|
||||
void RtspToRtmpMediaSource::regist() {
|
||||
RtspMediaSource::regist();
|
||||
bool RtspToRtmpMediaSource::regist() {
|
||||
if (m_pRtmpSrc) {
|
||||
m_pRtmpSrc->regist();
|
||||
}
|
||||
return MediaSource::regist();
|
||||
}
|
||||
|
||||
void RtspToRtmpMediaSource::unregist() {
|
||||
RtspMediaSource::unregist();
|
||||
bool RtspToRtmpMediaSource::unregist() {
|
||||
if (m_pRtmpSrc) {
|
||||
m_pRtmpSrc->unregist();
|
||||
}
|
||||
return MediaSource::unregist();
|
||||
}
|
||||
|
||||
void RtspToRtmpMediaSource::makeVideoConfigPkt() {
|
||||
@ -196,9 +195,8 @@ void RtspToRtmpMediaSource::makeAudioConfigPkt() {
|
||||
}
|
||||
|
||||
void RtspToRtmpMediaSource::makeMetaData() {
|
||||
m_pRtmpSrc.reset(new RtmpMediaSource(getApp(),getId()));
|
||||
m_pRtmpSrc->setOnSeek(m_onSeek);
|
||||
m_pRtmpSrc->setOnStamp(m_onStamp);
|
||||
m_pRtmpSrc.reset(new RtmpMediaSource(getVhost(),getApp(),getId()));
|
||||
m_pRtmpSrc->setListener(m_listener);
|
||||
AMFValue metaData(AMF_OBJECT);
|
||||
metaData.set("duration", m_pParser->getDuration());
|
||||
metaData.set("fileSize", 0);
|
||||
@ -222,6 +220,5 @@ void RtspToRtmpMediaSource::makeMetaData() {
|
||||
|
||||
m_pRtmpSrc->onGetMetaData(metaData);
|
||||
}
|
||||
#endif //ENABLE_RTSP2RTMP
|
||||
} /* namespace Rtsp */
|
||||
} /* namespace ZL */
|
||||
|
@ -38,18 +38,17 @@ using namespace ZL::MediaFile;
|
||||
|
||||
namespace ZL {
|
||||
namespace Rtsp {
|
||||
#ifdef ENABLE_RTSP2RTMP
|
||||
class RtspToRtmpMediaSource: public RtspMediaSource {
|
||||
public:
|
||||
typedef std::shared_ptr<RtspToRtmpMediaSource> Ptr;
|
||||
RtspToRtmpMediaSource(const string &_app,const string &_id,bool bEnableFile = true);
|
||||
RtspToRtmpMediaSource(const string &vhost,const string &app,const string &id,bool bEnableFile = true);
|
||||
virtual ~RtspToRtmpMediaSource();
|
||||
|
||||
virtual void onGetSDP(const string& strSdp) override{
|
||||
try {
|
||||
m_pParser.reset(new RtpParser(strSdp));
|
||||
if(m_bEnableFile){
|
||||
m_pRecorder.reset(new MediaRecorder(getApp(),getId(),m_pParser));
|
||||
m_pRecorder.reset(new MediaRecorder(getVhost(),getApp(),getId(),m_pParser));
|
||||
}
|
||||
m_pParser->setOnAudioCB( std::bind(&RtspToRtmpMediaSource::onGetAdts, this, placeholders::_1));
|
||||
m_pParser->setOnVideoCB( std::bind(&RtspToRtmpMediaSource::onGetH264, this, placeholders::_1));
|
||||
@ -65,23 +64,13 @@ public:
|
||||
}
|
||||
RtspMediaSource::onGetRTP(pRtppkt, bKeyPos);
|
||||
}
|
||||
virtual void regist() override ;
|
||||
virtual void unregist() override;
|
||||
virtual bool regist() override ;
|
||||
virtual bool unregist() override;
|
||||
|
||||
int readerCount(){
|
||||
return getRing()->readerCount() + (m_pRtmpSrc ? m_pRtmpSrc->getRing()->readerCount() : 0);
|
||||
}
|
||||
void setOnSeek(const function<bool(uint32_t)> &cb) override{
|
||||
RtspMediaSource::setOnSeek(cb);
|
||||
if(m_pRtmpSrc){
|
||||
m_pRtmpSrc->setOnSeek(cb);
|
||||
}
|
||||
}
|
||||
void setOnStamp(const function<uint32_t()> &cb) override{
|
||||
RtspMediaSource::setOnStamp(cb);
|
||||
if (m_pRtmpSrc) {
|
||||
m_pRtmpSrc->setOnStamp(cb);
|
||||
}
|
||||
}
|
||||
|
||||
void updateTimeStamp(uint32_t uiStamp) {
|
||||
for (auto &pr : m_mapTracks) {
|
||||
switch (pr.second.type) {
|
||||
@ -111,9 +100,6 @@ private:
|
||||
void makeMetaData();
|
||||
};
|
||||
|
||||
#else
|
||||
typedef RtspMediaSource RtspToRtmpMediaSource;
|
||||
#endif //ENABLE_RTSP2RTMP
|
||||
} /* namespace Rtsp */
|
||||
} /* namespace ZL */
|
||||
|
||||
|
@ -19,10 +19,10 @@ public:
|
||||
_parser.reset(new OptionParser(nullptr));
|
||||
(*_parser) << Option('l', "list", Option::ArgNone, nullptr,false, "list all media source of rtsp",
|
||||
[](const std::shared_ptr<ostream> &stream, const string &arg) {
|
||||
auto mediaSet = RtspMediaSource::getMediaSet();
|
||||
for (auto &src : mediaSet) {
|
||||
(*stream) << "\t" << src << "\r\n";
|
||||
}
|
||||
// auto mediaSet = RtspMediaSource::getMediaSet();
|
||||
// for (auto &src : mediaSet) {
|
||||
// (*stream) << "\t" << src << "\r\n";
|
||||
// }
|
||||
return false;
|
||||
});
|
||||
}
|
||||
@ -37,10 +37,10 @@ public:
|
||||
_parser.reset(new OptionParser(nullptr));
|
||||
(*_parser) << Option('l', "list", Option::ArgNone,nullptr,false, "list all media source of rtmp",
|
||||
[](const std::shared_ptr<ostream> &stream, const string &arg) {
|
||||
auto mediaSet = RtmpMediaSource::getMediaSet();
|
||||
for (auto &src : mediaSet) {
|
||||
(*stream) << "\t" << src << "\r\n";
|
||||
}
|
||||
// auto mediaSet = RtmpMediaSource::getMediaSet();
|
||||
// for (auto &src : mediaSet) {
|
||||
// (*stream) << "\t" << src << "\r\n";
|
||||
// }
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
@ -35,15 +35,10 @@ namespace ZL {
|
||||
namespace Shell {
|
||||
|
||||
unordered_map<string, string> ShellSession::g_mapUser;
|
||||
string ShellSession::g_serverName;
|
||||
|
||||
ShellSession::ShellSession(const std::shared_ptr<ThreadPool> &_th,
|
||||
const Socket::Ptr &_sock) :
|
||||
TcpLimitedSession(_th, _sock) {
|
||||
|
||||
static onceToken token([]() {
|
||||
g_serverName = mINI::Instance()[Config::Shell::kServerName];
|
||||
}, nullptr);
|
||||
pleaseInputUser();
|
||||
}
|
||||
|
||||
@ -107,7 +102,7 @@ inline bool ShellSession::onCommandLine(const string& line) {
|
||||
|
||||
inline void ShellSession::pleaseInputUser() {
|
||||
send("\033[0m");
|
||||
send(StrPrinter << g_serverName << " login: " << endl);
|
||||
send(StrPrinter << SERVER_NAME << " login: " << endl);
|
||||
m_requestCB = [this](const string &line) {
|
||||
m_strUserName=line;
|
||||
pleaseInputPasswd();
|
||||
@ -121,14 +116,14 @@ inline void ShellSession::pleaseInputPasswd() {
|
||||
send(StrPrinter
|
||||
<<"\033[0mPermission denied,"
|
||||
<<" please try again.\r\n"
|
||||
<<m_strUserName<<"@"<<g_serverName
|
||||
<<m_strUserName<<"@"<<SERVER_NAME
|
||||
<<"'s password: \033[8m"
|
||||
<<endl);
|
||||
return true;
|
||||
}
|
||||
send("\033[0m");
|
||||
send("-----------------------------------------\r\n");
|
||||
send(StrPrinter<<"欢迎来到"<<g_serverName<<", 你可输入\"help\"查看帮助.\r\n"<<endl);
|
||||
send(StrPrinter<<"欢迎来到"<<SERVER_NAME<<", 你可输入\"help\"查看帮助.\r\n"<<endl);
|
||||
send("-----------------------------------------\r\n");
|
||||
printShellPrefix();
|
||||
m_requestCB=nullptr;
|
||||
@ -137,7 +132,7 @@ inline void ShellSession::pleaseInputPasswd() {
|
||||
}
|
||||
|
||||
inline void ShellSession::printShellPrefix() {
|
||||
send(StrPrinter << m_strUserName << "@" << g_serverName << "# " << endl);
|
||||
send(StrPrinter << m_strUserName << "@" << SERVER_NAME << "# " << endl);
|
||||
}
|
||||
|
||||
inline bool ShellSession::onAuth(const string &user, const string &pwd) {
|
||||
|
@ -64,7 +64,6 @@ private:
|
||||
string m_strUserName;
|
||||
|
||||
static unordered_map<string, string> g_mapUser;
|
||||
static string g_serverName;
|
||||
};
|
||||
|
||||
} /* namespace Shell */
|
||||
|
@ -48,7 +48,7 @@ void rePushDelay(const string &app,const string &stream,const string &url);
|
||||
//创建推流器并开始推流
|
||||
void createPusher(const string &app,const string &stream,const string &url){
|
||||
//创建推流器并绑定一个RtmpMediaSource
|
||||
pusher.reset(new RtmpPusher(app.data(), stream.data()));
|
||||
pusher.reset(new RtmpPusher(DEFAULT_VHOST,app.data(), stream.data()));
|
||||
//设置推流中断处理逻辑
|
||||
pusher->setOnShutdown([app,stream, url](const SockException &ex) {
|
||||
WarnL << "Server connection is closed:" << ex.getErrCode() << " " << ex.what();
|
||||
@ -95,11 +95,11 @@ int domain(int argc, const char *argv[]) {
|
||||
|
||||
//拉一个流,生成一个RtmpMediaSource,源的名称是"app/stream"
|
||||
//你也可以以其他方式生成RtmpMediaSource,比如说MP4文件(请查看test_rtmpPusherMp4.cpp代码)
|
||||
PlayerProxy::Ptr player(new PlayerProxy("app", "stream"));
|
||||
PlayerProxy::Ptr player(new PlayerProxy(DEFAULT_VHOST,"app", "stream"));
|
||||
player->play(playUrl.data());
|
||||
|
||||
//监听RtmpMediaSource注册事件,在PlayerProxy播放成功后触发
|
||||
NoticeCenter::Instance().addListener(nullptr, Config::Broadcast::kBroadcastRtmpSrcRegisted, [pushUrl](BroadcastRtmpSrcRegistedArgs) {
|
||||
NoticeCenter::Instance().addListener(nullptr, Config::Broadcast::kBroadcastMediaChanged, [pushUrl](BroadcastMediaChangedArgs) {
|
||||
//媒体源"app/stream"已经注册,这时方可新建一个RtmpPusher对象并绑定该媒体源
|
||||
createPusher(app,stream,pushUrl);
|
||||
});
|
||||
|
@ -51,7 +51,7 @@ void createPusher(const string &app,const string &stream,const string &url);
|
||||
|
||||
//创建推流器并开始推流
|
||||
void createPusher(const string &app,const string &stream,const string &url){
|
||||
auto rtmpSrc = MediaReader::onMakeRtmp(app,stream);
|
||||
auto rtmpSrc = dynamic_pointer_cast<RtmpMediaSource>(MediaReader::onMakeMediaSource(RTMP_SCHEMA,DEFAULT_VHOST,app,stream));
|
||||
if(!rtmpSrc){
|
||||
//文件不存在
|
||||
WarnL << "MP4 file not exited!";
|
||||
|
@ -135,7 +135,7 @@ int main(int argc,char *argv[]){
|
||||
//http://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
|
||||
//rtsp://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
|
||||
//rtmp://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
|
||||
PlayerProxy::Ptr player(new PlayerProxy("live",to_string(i).data()));
|
||||
PlayerProxy::Ptr player(new PlayerProxy(DEFAULT_VHOST,"live",to_string(i).data()));
|
||||
//指定RTP over TCP(播放rtsp时有效)
|
||||
(*player)[RtspPlayer::kRtpType] = PlayerBase::RTP_TCP;
|
||||
//开始播放,如果播放失败或者播放中止,将会自动重试若干次,重试次数在配置文件中配置,默认一直重试
|
||||
|
Loading…
Reference in New Issue
Block a user