初步提交2.0版本,支持虚拟主机

This commit is contained in:
xiongziliang 2018-02-02 18:06:08 +08:00
parent 1262c4c51d
commit bd72a69d33
44 changed files with 354 additions and 730 deletions

View File

@ -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,...){ 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); LogInfoMaker info((LogLevel)level,file,function,line);

View File

@ -75,39 +75,6 @@ API_EXPORT int API_CALL initRtspServer(unsigned short port);
*/ */
API_EXPORT int API_CALL initRtmpServer(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);
/////////////////////////日志//////////////////////////////// /////////////////////////日志////////////////////////////////

View File

@ -50,7 +50,7 @@ static onceToken s_token([](){
//////////////////////////Rtsp media/////////////////////////// //////////////////////////Rtsp media///////////////////////////
API_EXPORT MediaContext API_CALL createMedia(const char *appName,const char *mediaName) { 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); lock_guard<recursive_mutex> lck(s_mtxMapMedia);
s_mapMedia.emplace((void *) (ret.get()), ret); s_mapMedia.emplace((void *) (ret.get()), ret);
return ret.get(); return ret.get();

View File

@ -43,7 +43,7 @@ static onceToken s_token([](){
},nullptr); },nullptr);
API_EXPORT ProxyPlayerContext API_CALL createProxyPlayer(const char *app,const char *stream,int rtp_type){ 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; (*ret)[RtspPlayer::kRtpType] = rtp_type;
lock_guard<recursive_mutex> lck(s_mtxMapProxyPlayer); lock_guard<recursive_mutex> lck(s_mtxMapProxyPlayer);

View File

@ -34,7 +34,7 @@ using namespace ZL::Thread;
class MediaSender { class MediaSender {
public: public:
static ThreadPool & sendThread() { static ThreadPool & sendThread() {
static ThreadPool pool(1); static ThreadPool pool(1,ThreadPool::PRIORITY_HIGHEST);
return pool; return pool;
} }
private: private:

View File

@ -47,9 +47,8 @@ void loadIniConfig(){
} }
////////////广播名称/////////// ////////////广播名称///////////
namespace Broadcast { namespace Broadcast {
const char kBroadcastRtspSessionPlay[] = "kBroadcastRtspSessionPlay"; const char kBroadcastMediaPlayed[] = "kBroadcastMediaPlayed";
const char kBroadcastRtspSrcRegisted[] = "kBroadcastRtspSrcRegisted"; const char kBroadcastMediaChanged[] = "kBroadcastMediaChanged";
const char kBroadcastRtmpSrcRegisted[] = "kBroadcastRtmpSrcRegisted";
const char kBroadcastRecordMP4[] = "kBroadcastRecordMP4"; const char kBroadcastRecordMP4[] = "kBroadcastRecordMP4";
const char kBroadcastHttpRequest[] = "kBroadcastHttpRequest"; const char kBroadcastHttpRequest[] = "kBroadcastHttpRequest";
const char kBroadcastOnGetRtspRealm[] = "kBroadcastOnGetRtspRealm"; const char kBroadcastOnGetRtspRealm[] = "kBroadcastOnGetRtspRealm";
@ -105,10 +104,6 @@ const char kMaxReqCount[] = HTTP_FIELD"maxReqCount";
#endif #endif
const char kCharSet[] = HTTP_FIELD"charSet"; const char kCharSet[] = HTTP_FIELD"charSet";
//http 服务器名称
#define HTTP_SERVER_NAME "ZLServer"
const char kServerName[] = HTTP_FIELD"serverName";
//http 服务器根目录 //http 服务器根目录
#define HTTP_ROOT_PATH (exeDir() + "httpRoot") #define HTTP_ROOT_PATH (exeDir() + "httpRoot")
const char kRootPath[] = HTTP_FIELD"rootPath"; const char kRootPath[] = HTTP_FIELD"rootPath";
@ -119,17 +114,12 @@ const char kRootPath[] = HTTP_FIELD"rootPath";
"<body bgcolor=\"white\">"\ "<body bgcolor=\"white\">"\
"<center><h1>您访问的资源不存在!</h1></center>"\ "<center><h1>您访问的资源不存在!</h1></center>"\
"<hr><center>"\ "<hr><center>"\
HTTP_SERVER_NAME\ SERVER_NAME\
"</center>"\ "</center>"\
"</body>"\ "</body>"\
"</html>" "</html>"
const char kNotFound[] = HTTP_FIELD"notFound"; 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([](){ onceToken token([](){
mINI::Instance()[kPort] = HTTP_PORT; mINI::Instance()[kPort] = HTTP_PORT;
@ -139,10 +129,8 @@ onceToken token([](){
mINI::Instance()[kKeepAliveSecond] = HTTP_KEEP_ALIVE_SECOND; mINI::Instance()[kKeepAliveSecond] = HTTP_KEEP_ALIVE_SECOND;
mINI::Instance()[kMaxReqCount] = HTTP_MAX_REQ_CNT; mINI::Instance()[kMaxReqCount] = HTTP_MAX_REQ_CNT;
mINI::Instance()[kCharSet] = HTTP_CHAR_SET; mINI::Instance()[kCharSet] = HTTP_CHAR_SET;
mINI::Instance()[kServerName] = HTTP_SERVER_NAME;
mINI::Instance()[kRootPath] = HTTP_ROOT_PATH; mINI::Instance()[kRootPath] = HTTP_ROOT_PATH;
mINI::Instance()[kNotFound] = HTTP_NOT_FOUND; mINI::Instance()[kNotFound] = HTTP_NOT_FOUND;
mINI::Instance()[kHttpPrefix] = HTTP_PREFIX;
},nullptr); },nullptr);
}//namespace Http }//namespace Http
@ -154,15 +142,11 @@ namespace Shell {
#define SHELL_PORT 9000 #define SHELL_PORT 9000
const char kPort[] = SHELL_FIELD"port"; const char kPort[] = SHELL_FIELD"port";
#define SHELL_SERVER_NAME "ZLServer"
const char kServerName[] = SHELL_FIELD"serverName";
#define SHELL_MAX_REQ_SIZE 1024 #define SHELL_MAX_REQ_SIZE 1024
const char kMaxReqSize[] = SHELL_FIELD"maxReqSize"; const char kMaxReqSize[] = SHELL_FIELD"maxReqSize";
onceToken token([](){ onceToken token([](){
mINI::Instance()[kPort] = SHELL_PORT; mINI::Instance()[kPort] = SHELL_PORT;
mINI::Instance()[kServerName] = SHELL_SERVER_NAME;
mINI::Instance()[kMaxReqSize] = SHELL_MAX_REQ_SIZE; mINI::Instance()[kMaxReqSize] = SHELL_MAX_REQ_SIZE;
},nullptr); },nullptr);
} //namespace Shell } //namespace Shell
@ -174,14 +158,10 @@ namespace Rtsp {
#define RTSP_PORT 554 #define RTSP_PORT 554
const char kPort[] = RTSP_FIELD"port"; const char kPort[] = RTSP_FIELD"port";
#define RTSP_SERVER_NAME "ZLServer"
const char kServerName[] = RTSP_FIELD"serverName";
const char kAuthBasic[] = RTSP_FIELD"authBasic"; const char kAuthBasic[] = RTSP_FIELD"authBasic";
onceToken token([](){ onceToken token([](){
mINI::Instance()[kPort] = RTSP_PORT; mINI::Instance()[kPort] = RTSP_PORT;
mINI::Instance()[kServerName] = RTSP_SERVER_NAME;
//默认Md5方式认证 //默认Md5方式认证
mINI::Instance()[kAuthBasic] = 0; mINI::Instance()[kAuthBasic] = 0;
},nullptr); },nullptr);
@ -278,12 +258,6 @@ const char kSampleMS[] = RECORD_FIELD"sampleMS";
#define RECORD_FILE_SECOND (10*60) #define RECORD_FILE_SECOND (10*60)
const char kFileSecond[] = RECORD_FIELD"fileSecond"; 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 #define RECORD_FILE_PATH HTTP_ROOT_PATH
const char kFilePath[] = RECORD_FIELD"filePath"; const char kFilePath[] = RECORD_FIELD"filePath";
@ -293,7 +267,6 @@ onceToken token([](){
mINI::Instance()[kSampleMS] = RECORD_SAMPLE_MS; mINI::Instance()[kSampleMS] = RECORD_SAMPLE_MS;
mINI::Instance()[kFileSecond] = RECORD_FILE_SECOND; mINI::Instance()[kFileSecond] = RECORD_FILE_SECOND;
mINI::Instance()[kFilePath] = RECORD_FILE_PATH; mINI::Instance()[kFilePath] = RECORD_FILE_PATH;
mINI::Instance()[kRtspPrefix] = RECORD_RTSP_PREFIX;
},nullptr); },nullptr);
} //namespace Record } //namespace Record
@ -318,11 +291,21 @@ const char kFileBufSize[] = HLS_FIELD"fileBufSize";
#define HLS_FILE_PATH (HTTP_ROOT_PATH) #define HLS_FILE_PATH (HTTP_ROOT_PATH)
const char kFilePath[] = HLS_FIELD"filePath"; 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([](){ onceToken token([](){
mINI::Instance()[kSegmentDuration] = HLS_SEGMENT_DURATION; mINI::Instance()[kSegmentDuration] = HLS_SEGMENT_DURATION;
mINI::Instance()[kSegmentNum] = HLS_SEGMENT_NUM; mINI::Instance()[kSegmentNum] = HLS_SEGMENT_NUM;
mINI::Instance()[kFileBufSize] = HLS_FILE_BUF_SIZE; mINI::Instance()[kFileBufSize] = HLS_FILE_BUF_SIZE;
mINI::Instance()[kFilePath] = HLS_FILE_PATH; mINI::Instance()[kFilePath] = HLS_FILE_PATH;
mINI::Instance()[kHttpPrefix] = HTTP_PREFIX;
mINI::Instance()[kHttpPrefixDefaultVhost] = HTTP_PREFIX_DEFAULT_VHOST;
},nullptr); },nullptr);
} //namespace Hls } //namespace Hls

View File

@ -25,8 +25,8 @@
*/ */
#ifndef appConfig_h #ifndef COMMON_CONFIG_H
#define appConfig_h #define COMMON_CONFIG_H
#include "Util/mini.h" #include "Util/mini.h"
using namespace ZL::Util; using namespace ZL::Util;
@ -35,12 +35,7 @@ namespace Config {
void loadIniConfig(); void loadIniConfig();
////////////TCP最大连接数/////////// ////////////TCP最大连接数///////////
#ifdef __x86_64__
#define MAX_TCP_SESSION 100000 #define MAX_TCP_SESSION 100000
#else
#define MAX_TCP_SESSION 128
#endif
////////////其他宏定义/////////// ////////////其他宏定义///////////
#ifndef MAX #ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b) ) #define MAX(a,b) ((a) > (b) ? (a) : (b) )
@ -54,17 +49,21 @@ void loadIniConfig();
#define CLEAR_ARR(arr) for(auto &item : arr){ item = 0;} #define CLEAR_ARR(arr) for(auto &item : arr){ item = 0;}
#endif //CLEAR_ARR #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 { namespace Broadcast {
extern const char kBroadcastRtspSessionPlay[]; extern const char kBroadcastMediaPlayed[];
#define BroadcastRtspSessionPlayArgs const char *app,const char *stream #define BroadcastMediaPlayedArgs const char *schema,const char *vhost,const char *app,const char *stream
extern const char kBroadcastRtspSrcRegisted[]; extern const char kBroadcastMediaChanged[];
#define BroadcastRtspSrcRegistedArgs const char *app,const char *stream #define BroadcastMediaChangedArgs bool bRegist, const char *schema,const char *vhost,const char *app,const char *stream
extern const char kBroadcastRtmpSrcRegisted[];
#define BroadcastRtmpSrcRegistedArgs const char *app,const char *stream
extern const char kBroadcastRecordMP4[]; extern const char kBroadcastRecordMP4[];
#define BroadcastRecordMP4Args const Mp4Info &info #define BroadcastRecordMP4Args const Mp4Info &info
@ -103,29 +102,22 @@ extern const char kKeepAliveSecond[];
extern const char kMaxReqCount[]; extern const char kMaxReqCount[];
//http 字符编码 //http 字符编码
extern const char kCharSet[]; extern const char kCharSet[];
//http 服务器名称
extern const char kServerName[];
//http 服务器根目录 //http 服务器根目录
extern const char kRootPath[]; extern const char kRootPath[];
//http 404错误提示内容 //http 404错误提示内容
extern const char kNotFound[]; extern const char kNotFound[];
//HTTP访问url前缀
extern const char kHttpPrefix[];
}//namespace Http }//namespace Http
////////////SHELL配置/////////// ////////////SHELL配置///////////
namespace Shell { namespace Shell {
extern const char kServerName[];
extern const char kMaxReqSize[]; extern const char kMaxReqSize[];
extern const char kPort[]; extern const char kPort[];
} //namespace Shell } //namespace Shell
////////////RTSP服务器配置/////////// ////////////RTSP服务器配置///////////
namespace Rtsp { namespace Rtsp {
#define RTSP_VERSION 1.30
#define RTSP_BUILDTIME __DATE__" CST"
extern const char kServerName[];
extern const char kPort[]; extern const char kPort[];
//是否优先base64方式认证默认Md5方式认证 //是否优先base64方式认证默认Md5方式认证
extern const char kAuthBasic[]; extern const char kAuthBasic[];
@ -171,8 +163,6 @@ extern const char kAppName[];
extern const char kSampleMS[]; extern const char kSampleMS[];
//MP4文件录制大小,不能太大,否则MP4Close函数执行事件太长 //MP4文件录制大小,不能太大,否则MP4Close函数执行事件太长
extern const char kFileSecond[]; extern const char kFileSecond[];
//Rtsp访问url前缀
extern const char kRtspPrefix[];
//录制文件路径 //录制文件路径
extern const char kFilePath[]; extern const char kFilePath[];
} //namespace Record } //namespace Record
@ -187,8 +177,12 @@ extern const char kSegmentNum[];
extern const char kFileBufSize[]; extern const char kFileBufSize[];
//录制文件路径 //录制文件路径
extern const char kFilePath[]; extern const char kFilePath[];
//HTTP访问url前缀
extern const char kHttpPrefix[];
//HTTP默认vhost访问url前缀
extern const char kHttpPrefixDefaultVhost[];
} //namespace Hls } //namespace Hls
} // namespace Config } // namespace Config
#endif /* appConfig_h */ #endif /* COMMON_CONFIG_H */

View File

@ -36,28 +36,22 @@ using namespace ZL::Util;
namespace ZL { namespace ZL {
namespace DEV { namespace DEV {
DevChannel::DevChannel(const char *strVhost,const char *strApp, const char *strId,float fDuration,bool bLiveStream ) :
RtspToRtmpMediaSource(strVhost,strApp,strId , bLiveStream) {
///////////////////////////////////////////////////////////////////////////////// m_strSdp = "v=0\r\n";
#ifdef ENABLE_RTSP2RTMP m_strSdp += "o=- 1383190487994921 1 IN IP4 0.0.0.0\r\n";
DevChannel::DevChannel(const char *strApp, const char *strId,float fDuration,bool bLiveStream ) : m_strSdp += "s=RTSP Session, streamed by the ZL\r\n";
m_mediaSrc(new RtspToRtmpMediaSource(strApp,strId , bLiveStream)) { m_strSdp += "i=ZL Live Stream\r\n";
#else m_strSdp += "c=IN IP4 0.0.0.0\r\n";
DevChannel::DevChannel(const char *strApp, const char *strId,float fDuration,bool bLiveStream ) : m_strSdp += "t=0 0\r\n";
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";
//直播,时间长度永远 //直播,时间长度永远
if(fDuration <= 0 || bLiveStream){ if(fDuration <= 0 || bLiveStream){
m_strSDP += "a=range:npt=0-\r\n"; m_strSdp += "a=range:npt=0-\r\n";
}else{ }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() { DevChannel::~DevChannel() {
} }
@ -110,7 +104,7 @@ void DevChannel::inputH264(char* pcData, int iDataLen, uint32_t uiStamp) {
uint32_t ui32Ssrc; uint32_t ui32Ssrc;
memcpy(&ui32Ssrc, makeRandStr(4, false).data(), 4); memcpy(&ui32Ssrc, makeRandStr(4, false).data(), 4);
auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) { 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>(); static uint32_t videoMtu = mINI::Instance()[Config::Rtp::kVideoMtuSize].as<uint32_t>();
m_pRtpMaker_h264.reset(new RtpMaker_H264(lam, ui32Ssrc,videoMtu)); 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; uint32_t ssrc;
memcpy(&ssrc, makeRandStr(8, false).data() + 4, 4); memcpy(&ssrc, makeRandStr(8, false).data() + 4, 4);
auto lam = [this](const RtpPacket::Ptr &pkt, bool keyPos) { 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>(); 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)); 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_pRtpMaker_h264->getPlayloadType() << "\r\n" << endl;
m_strSDP += "b=AS:5100\r\n"; m_strSdp += "b=AS:5100\r\n";
m_strSDP += StrPrinter << "a=rtpmap:" << m_pRtpMaker_h264->getPlayloadType() m_strSdp += StrPrinter << "a=rtpmap:" << m_pRtpMaker_h264->getPlayloadType()
<< " H264/" << m_pRtpMaker_h264->getSampleRate() << "\r\n" << endl; << " 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; << " packetization-mode=1;profile-level-id=" << endl;
memset(acTmp, 0, sizeof(acTmp)); memset(acTmp, 0, sizeof(acTmp));
sprintf(acTmp, "%06X", profile_level_id); sprintf(acTmp, "%06X", profile_level_id);
m_strSDP += acTmp; m_strSdp += acTmp;
m_strSDP += ";sprop-parameter-sets="; m_strSdp += ";sprop-parameter-sets=";
memset(acTmp, 0, sizeof(acTmp)); memset(acTmp, 0, sizeof(acTmp));
av_base64_encode(acTmp, sizeof(acTmp), (uint8_t *) m_aucSPS, m_uiSPSLen); av_base64_encode(acTmp, sizeof(acTmp), (uint8_t *) m_aucSPS, m_uiSPSLen);
//WarnL<<"SPS base64:"<<strTemp; //WarnL<<"SPS base64:"<<strTemp;
//WarnL<<"SPS hexdump:"<<hexdump(SPS_BUF, SPS_LEN); //WarnL<<"SPS hexdump:"<<hexdump(SPS_BUF, SPS_LEN);
m_strSDP += acTmp; m_strSdp += acTmp;
m_strSDP += ","; m_strSdp += ",";
memset(acTmp, 0, sizeof(acTmp)); memset(acTmp, 0, sizeof(acTmp));
av_base64_encode(acTmp, sizeof(acTmp), (uint8_t *) m_aucPPS, m_uiPPSLen); av_base64_encode(acTmp, sizeof(acTmp), (uint8_t *) m_aucPPS, m_uiPPSLen);
m_strSDP += acTmp; m_strSdp += acTmp;
m_strSDP += "\r\n"; m_strSdp += "\r\n";
if (m_video->iFrameRate > 0 && m_video->iHeight > 0 && m_video->iWidth > 0) { if (m_video->iFrameRate > 0 && m_video->iHeight > 0 && m_video->iWidth > 0) {
m_strSDP += "a=framerate:"; m_strSdp += "a=framerate:";
m_strSDP += StrPrinter << m_video->iFrameRate << endl; m_strSdp += StrPrinter << m_video->iFrameRate << endl;
m_strSDP += StrPrinter << "\r\na=framesize:" m_strSdp += StrPrinter << "\r\na=framesize:"
<< m_pRtpMaker_h264->getPlayloadType() << " " << endl; << m_pRtpMaker_h264->getPlayloadType() << " " << endl;
m_strSDP += StrPrinter << m_video->iWidth << endl; m_strSdp += StrPrinter << m_video->iWidth << endl;
m_strSDP += "-"; m_strSdp += "-";
m_strSDP += StrPrinter << m_video->iHeight << endl; m_strSdp += StrPrinter << m_video->iHeight << endl;
m_strSDP += "\r\n"; 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_pRtpMaker_h264->getInterleaved() / 2 << "\r\n" << endl;
m_bSdp_gotH264 = true; m_bSdp_gotH264 = true;
if (m_audio) { if (m_audio) {
if (m_bSdp_gotAAC) { if (m_bSdp_gotAAC) {
makeSDP(m_strSDP); makeSDP(m_strSdp);
} }
} else { } else {
makeSDP(m_strSDP); makeSDP(m_strSdp);
} }
} }
@ -237,33 +231,33 @@ inline void DevChannel::makeSDP_AAC(unsigned char *fixedHeader) {
char fConfigStr[5] = { 0 }; char fConfigStr[5] = { 0 };
sprintf(fConfigStr, "%02X%02x", (uint8_t)audioSpecificConfig[0],(uint8_t)audioSpecificConfig[1]); 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_pRtpMaker_aac->getPlayloadType() << "\r\n" << endl;
m_strSDP += "b=AS:96\r\n"; m_strSdp += "b=AS:96\r\n";
m_strSDP += StrPrinter << "a=rtpmap:" << m_pRtpMaker_aac->getPlayloadType() m_strSdp += StrPrinter << "a=rtpmap:" << m_pRtpMaker_aac->getPlayloadType()
<< " MPEG4-GENERIC/" << m_pRtpMaker_aac->getSampleRate() << "\r\n" << " MPEG4-GENERIC/" << m_pRtpMaker_aac->getSampleRate() << "\r\n"
<< endl; << 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=" << " streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config="
<< endl; << endl;
m_strSDP += fConfigStr; m_strSdp += fConfigStr;
m_strSDP += "\r\n"; m_strSdp += "\r\n";
m_strSDP += StrPrinter << "a=control:trackID=" m_strSdp += StrPrinter << "a=control:trackID="
<< m_pRtpMaker_aac->getInterleaved() / 2 << "\r\n" << endl; << m_pRtpMaker_aac->getInterleaved() / 2 << "\r\n" << endl;
m_bSdp_gotAAC = true; m_bSdp_gotAAC = true;
if (m_video) { if (m_video) {
if (m_bSdp_gotH264) { if (m_bSdp_gotH264) {
makeSDP(m_strSDP); makeSDP(m_strSdp);
} }
} else { } else {
makeSDP(m_strSDP); makeSDP(m_strSdp);
} }
} }
void DevChannel::makeSDP(const string& strSdp) { void DevChannel::makeSDP(const string& strSdp) {
m_mediaSrc->onGetSDP(strSdp); onGetSDP(strSdp);
m_mediaSrc->regist(); regist();
} }
void DevChannel::initVideo(const VideoInfo& info) { void DevChannel::initVideo(const VideoInfo& info) {

View File

@ -49,6 +49,7 @@ using namespace ZL::Codec;
using namespace ZL::Codec; using namespace ZL::Codec;
#endif //ENABLE_X264 #endif //ENABLE_X264
namespace ZL { namespace ZL {
namespace DEV { namespace DEV {
@ -65,10 +66,10 @@ public:
int iSampleRate; int iSampleRate;
}; };
class DevChannel { class DevChannel : public RtspToRtmpMediaSource{
public: public:
typedef std::shared_ptr<DevChannel> Ptr; 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(); virtual ~DevChannel();
void initVideo(const VideoInfo &info); void initVideo(const VideoInfo &info);
@ -80,20 +81,6 @@ public:
void inputH264(char *pcData, int iDataLen, uint32_t uiStamp); void inputH264(char *pcData, int iDataLen, uint32_t uiStamp);
void inputAAC(char *pcDataWithAdts, 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); 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: private:
inline void makeSDP_264(unsigned char *pucData, int iDataLen); inline void makeSDP_264(unsigned char *pucData, int iDataLen);
inline void makeSDP_AAC(unsigned char *pucData); inline void makeSDP_AAC(unsigned char *pucData);
@ -107,8 +94,6 @@ private:
#endif //ENABLE_FAAC #endif //ENABLE_FAAC
RtpMaker_AAC::Ptr m_pRtpMaker_aac; RtpMaker_AAC::Ptr m_pRtpMaker_aac;
RtpMaker_H264::Ptr m_pRtpMaker_h264; RtpMaker_H264::Ptr m_pRtpMaker_h264;
RtspToRtmpMediaSource::Ptr m_mediaSrc;
string m_strSDP;
bool m_bSdp_gotH264 = false; bool m_bSdp_gotH264 = false;
bool m_bSdp_gotAAC = false; bool m_bSdp_gotAAC = false;

View File

@ -39,7 +39,8 @@ namespace DEV {
const char PlayerProxy::kAliveSecond[] = "alive_second"; 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_strApp = strApp;
m_strSrc = strSrc; m_strSrc = strSrc;
} }
@ -133,7 +134,7 @@ void PlayerProxy::initMedia() {
if (!isInited()) { if (!isInited()) {
return; 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()) { if (containVideo()) {
VideoInfo info; VideoInfo info;
info.iFrameRate = getVideoFps(); info.iFrameRate = getVideoFps();

View File

@ -45,7 +45,7 @@ public:
//设置方法proxy[PlayerProxy::kAliveSecond] = 100; //设置方法proxy[PlayerProxy::kAliveSecond] = 100;
static const char kAliveSecond[]; static const char kAliveSecond[];
PlayerProxy(const char *strApp, const char *strSrc); PlayerProxy(const char *strVhost, const char *strApp, const char *strSrc);
virtual ~PlayerProxy(); virtual ~PlayerProxy();
void play(const char* strUrl) override; void play(const char* strUrl) override;
void setOnExpired(const function<void()> &cb){ void setOnExpired(const function<void()> &cb){
@ -56,6 +56,7 @@ private :
Ticker m_aliveTicker; Ticker m_aliveTicker;
uint32_t m_aliveSecond = 0; uint32_t m_aliveSecond = 0;
function<void()> onExpired; function<void()> onExpired;
string m_strVhost;
string m_strApp; string m_strApp;
string m_strSrc; string m_strSrc;
void initMedia(); void initMedia();

View File

@ -182,14 +182,13 @@ inline bool HttpSession::checkLiveFlvStream(){
//未找到".flv"后缀 //未找到".flv"后缀
return false; return false;
} }
auto app = FindField(m_parser.Url().data(),"/","/"); auto fullUrl = string("http://") + m_parser["Host"] + FindField(m_parser.Url().data(),NULL,pos);
auto stream = FindField(m_parser.Url().data(),(string("/") + app + "/").data(),"."); MediaInfo info(fullUrl);
if(app.empty() || stream.empty()){ if(!m_parser.getUrlArgs()[VHOST_KEY].empty()){
//不能拆分成2级url info.m_vhost = m_parser.getUrlArgs()[VHOST_KEY];
return false;
} }
//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){ if(!mediaSrc){
//该rtmp源不存在 //该rtmp源不存在
return false; return false;
@ -274,7 +273,13 @@ inline HttpSession::HttpCode HttpSession::Handle_Req_GET() {
return Http_success; return Http_success;
} }
//事件未被拦截则认为是http下载请求 //事件未被拦截则认为是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连接是否需要被关闭//////////////// /////////////HTTP连接是否需要被关闭////////////////
static uint32_t reqCnt = mINI::Instance()[Config::Http::kMaxReqCount].as<uint32_t>(); static uint32_t reqCnt = mINI::Instance()[Config::Http::kMaxReqCount].as<uint32_t>();
bool bClose = (strcasecmp(m_parser["Connection"].data(),"close") == 0) && ( ++m_iReqCnt < reqCnt); 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() == '/') { if (strFile.back() == '/') {
//生成文件夹菜单索引 //生成文件夹菜单索引
string strMeun; string strMeun;
if (!makeMeun(strFile, strMeun)) { if (!makeMeun(strFile,info.m_vhost, strMeun)) {
//文件夹不存在 //文件夹不存在
sendNotFound(bClose); sendNotFound(bClose);
return eHttpCode; return eHttpCode;
@ -372,7 +377,7 @@ inline HttpSession::HttpCode HttpSession::Handle_Req_GET() {
//文件读完 //文件读完
//InfoL << "send complete!" << iRead << " " << iReq << " " << *piLeft; //InfoL << "send complete!" << iRead << " " << iReq << " " << *piLeft;
if(iRead>0) { if(iRead>0) {
sendBuf->setSize(iRead); sendBuf->setSize(iRead);
strongSelf->sock->setSendPktSize(3);//强制写入socket缓存 strongSelf->sock->setSendPktSize(3);//强制写入socket缓存
strongSelf->sock->send(sendBuf,SOCKET_DEFAULE_FLAGS | FLAG_MORE); strongSelf->sock->send(sendBuf,SOCKET_DEFAULE_FLAGS | FLAG_MORE);
} }
@ -409,7 +414,7 @@ inline HttpSession::HttpCode HttpSession::Handle_Req_GET() {
return Http_success; 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); string strPathPrefix(strFullPath);
strPathPrefix = strPathPrefix.substr(0, strPathPrefix.length() - 1); strPathPrefix = strPathPrefix.substr(0, strPathPrefix.length() - 1);
if (!File::is_dir(strPathPrefix.data())) { if (!File::is_dir(strPathPrefix.data())) {
@ -423,7 +428,7 @@ inline bool HttpSession::makeMeun(const string &strFullPath, string &strRet) {
"<h1>文件索引:"; "<h1>文件索引:";
string strPath = strFullPath; 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 += strPath;
strRet += "</h1>\r\n"; strRet += "</h1>\r\n";
if (strPath != "/") { 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) { inline HttpSession::KeyValue HttpSession::makeHttpHeader(bool bClose, int64_t iContentSize,const char* pcContentType) {
KeyValue headerOut; KeyValue headerOut;
static string serverName = mINI::Instance()[Config::Http::kServerName];
static string charSet = mINI::Instance()[Config::Http::kCharSet]; static string charSet = mINI::Instance()[Config::Http::kCharSet];
static uint32_t keepAliveSec = mINI::Instance()[Config::Http::kKeepAliveSecond].as<uint32_t>(); static uint32_t keepAliveSec = mINI::Instance()[Config::Http::kKeepAliveSecond].as<uint32_t>();
static uint32_t reqCnt = mINI::Instance()[Config::Http::kMaxReqCount].as<uint32_t>(); static uint32_t reqCnt = mINI::Instance()[Config::Http::kMaxReqCount].as<uint32_t>();
headerOut.emplace("Date", dateStr()); headerOut.emplace("Date", dateStr());
headerOut.emplace("Server", serverName); headerOut.emplace("Server", SERVER_NAME);
headerOut.emplace("Connection", bClose ? "close" : "keep-alive"); headerOut.emplace("Connection", bClose ? "close" : "keep-alive");
if(!bClose){ if(!bClose){
headerOut.emplace("Keep-Alive",StrPrinter << "timeout=" << keepAliveSec << ", max=" << reqCnt << endl); headerOut.emplace("Keep-Alive",StrPrinter << "timeout=" << keepAliveSec << ", max=" << reqCnt << endl);

View File

@ -87,7 +87,7 @@ private:
inline bool checkLiveFlvStream(); inline bool checkLiveFlvStream();
inline bool emitHttpEvent(bool doInvoke); inline bool emitHttpEvent(bool doInvoke);
inline void urlDecode(Parser &parser); 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 sendNotFound(bool bClose);
inline void sendResponse(const char *pcStatus,const KeyValue &header,const string &strContent); 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"); inline static KeyValue makeHttpHeader(bool bClose=false,int64_t iContentSize=-1,const char *pcContentType="text/html");

View File

@ -38,10 +38,6 @@ HLSMaker::HLSMaker(const string& strM3u8File, const string& strHttpUrl,
if (ui32BufSize < 16 * 1024) { if (ui32BufSize < 16 * 1024) {
ui32BufSize = 16 * 1024; ui32BufSize = 16 * 1024;
} }
if(ui32Duration < 0){
ui32Duration = 0;
}
if(ui32Num < 1){ if(ui32Num < 1){
ui32Num = 1; ui32Num = 1;
} }

View File

@ -36,9 +36,9 @@ namespace ZL {
namespace MediaFile { namespace MediaFile {
#ifdef ENABLE_MP4V2 #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]; static string recordPath = mINI::Instance()[Config::Record::kFilePath];
auto strFileName = recordPath + "/" + strApp + "/" + strId; auto strFileName = recordPath + "/" + strVhost + "/" + strApp + "/" + strId;
m_hMP4File = MP4Read(strFileName.data()); m_hMP4File = MP4Read(strFileName.data());
if(m_hMP4File == MP4_INVALID_FILE_HANDLE){ 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_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) { if (m_audio_trId != MP4_INVALID_TRACK_ID) {
AudioInfo info; AudioInfo info;
info.iChannel = m_audio_num_channels; info.iChannel = m_audio_num_channels;
@ -169,26 +169,17 @@ MediaReader::~MediaReader() {
void MediaReader::startReadMP4() { void MediaReader::startReadMP4() {
auto strongSelf = shared_from_this(); auto strongSelf = shared_from_this();
static uint32_t sampleMS = mINI::Instance()[Config::Record::kSampleMS].as<uint32_t>(); static uint32_t sampleMS = mINI::Instance()[Config::Record::kSampleMS].as<uint32_t>();
AsyncTaskThread::Instance().DoTaskDelay(reinterpret_cast<uint64_t>(this), sampleMS, [strongSelf](){ AsyncTaskThread::Instance().DoTaskDelay(reinterpret_cast<uint64_t>(this), sampleMS, [strongSelf](){
return strongSelf->readSample(); return strongSelf->readSample();
}); });
weak_ptr<MediaReader> weakSelf = strongSelf; m_pChn->setListener(strongSelf);
m_pChn->setOnSeek([weakSelf](uint32_t ui32Stamp){ }
auto strongSelf = weakSelf.lock(); bool MediaReader::seekTo(uint32_t ui32Stamp){
if(!strongSelf){ seek(ui32Stamp);
return false; return true;
} }
strongSelf->seek(ui32Stamp); uint32_t MediaReader::getStamp() {
return true; return m_iSeekTime + m_ticker.elapsedTime();
});
m_pChn->setOnStamp([weakSelf]() -> uint32_t {
auto strongSelf = weakSelf.lock();
if(!strongSelf) {
return 0;
}
return strongSelf-> m_iSeekTime + strongSelf->m_ticker.elapsedTime();
});
} }
bool MediaReader::readSample(int iTimeInc) { bool MediaReader::readSample(int iTimeInc) {
@ -322,36 +313,18 @@ void MediaReader::seek(int iSeekTime,bool bReStart){
#endif //ENABLE_MP4V2 #endif //ENABLE_MP4V2
RtspMediaSource::Ptr MediaReader::onMakeRtsp(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 RtspMediaSource::find(strApp, strId, false);
}catch (std::exception &ex) {
WarnL << ex.what();
return nullptr;
}
#else
return nullptr;
#endif //ENABLE_MP4V2
}
RtmpMediaSource::Ptr MediaReader::onMakeRtmp(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 #ifdef ENABLE_MP4V2
static string appName = mINI::Instance()[Config::Record::kAppName]; static string appName = mINI::Instance()[Config::Record::kAppName];
if (strApp != appName) { if (strApp != appName) {
return nullptr; return nullptr;
} }
try { try {
MediaReader::Ptr pReader(new MediaReader(strApp, strId)); MediaReader::Ptr pReader(new MediaReader(strVhost,strApp, strId));
pReader->startReadMP4(); pReader->startReadMP4();
return RtmpMediaSource::find(strApp, strId, false); return MediaSource::find(strSchema,strVhost,strApp, strId, false);
} catch (std::exception &ex) { } catch (std::exception &ex) {
WarnL << ex.what(); WarnL << ex.what();
return nullptr; return nullptr;
@ -359,7 +332,6 @@ RtmpMediaSource::Ptr MediaReader::onMakeRtmp(const string &strApp, const string
#else #else
return nullptr; return nullptr;
#endif //ENABLE_MP4V2 #endif //ENABLE_MP4V2
} }

View File

@ -42,13 +42,15 @@ using namespace ZL::Rtmp;
namespace ZL { namespace ZL {
namespace MediaFile { namespace MediaFile {
class MediaReader : public std::enable_shared_from_this<MediaReader>{ class MediaReader : public std::enable_shared_from_this<MediaReader> ,public MediaSourceEvent{
public: public:
typedef std::shared_ptr<MediaReader> Ptr; 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(); virtual ~MediaReader();
static RtspMediaSource::Ptr onMakeRtsp(const string &strApp, const string &strId); static MediaSource::Ptr onMakeMediaSource(const string &strSchema,const string &strVhost,const string &strApp, const string &strId);
static RtmpMediaSource::Ptr onMakeRtmp(const string &strApp, const string &strId); public:
bool seekTo(uint32_t ui32Stamp) override;
uint32_t getStamp() override;
private: private:
#ifdef ENABLE_MP4V2 #ifdef ENABLE_MP4V2
@ -95,6 +97,8 @@ private:
inline bool readAudioSample(int iTimeInc = 0); inline bool readAudioSample(int iTimeInc = 0);
inline void writeH264(uint8_t *pucData,int iLen,uint32_t uiStamp); inline void writeH264(uint8_t *pucData,int iLen,uint32_t uiStamp);
inline void writeAAC(uint8_t *pucData,int iLen,uint32_t uiStamp); inline void writeAAC(uint8_t *pucData,int iLen,uint32_t uiStamp);
#endif //ENABLE_MP4V2 #endif //ENABLE_MP4V2
}; };

View File

@ -37,24 +37,39 @@ using namespace ZL::Network;
namespace ZL { namespace ZL {
namespace MediaFile { namespace MediaFile {
MediaRecorder::MediaRecorder(const string &strApp,const string &strId,const std::shared_ptr<PlayerBase> &pPlayer) { MediaRecorder::MediaRecorder(const string &strVhost ,const string &strApp,const string &strId,const std::shared_ptr<PlayerBase> &pPlayer) {
#ifdef ENABLE_HLS static string hlsPrefix = mINI::Instance()[Config::Hls::kHttpPrefix];
static string hlsPrefix = mINI::Instance()[Config::Http::kHttpPrefix]; static string hlsPrefixDefaultVhost = mINI::Instance()[Config::Hls::kHttpPrefixDefaultVhost];
static string hlsPath = mINI::Instance()[Config::Hls::kFilePath]; static string hlsPath = mINI::Instance()[Config::Hls::kFilePath];
static uint32_t hlsBufSize = mINI::Instance()[Config::Hls::kFileBufSize].as<uint32_t>(); 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 hlsDuration = mINI::Instance()[Config::Hls::kSegmentDuration].as<uint32_t>();
static uint32_t hlsNum = mINI::Instance()[Config::Hls::kSegmentNum].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", string hlsPrefixVhost = hlsPrefix;
hlsPrefix + "/" + strApp + "/" + strId + "/", do{
hlsBufSize,hlsDuration,hlsNum)); //生成hls http前缀
#endif //ENABLE_HLS 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));
#ifdef ENABLE_MP4V2 #ifdef ENABLE_MP4V2
static string recordPath = mINI::Instance()[Config::Record::kFilePath]; static string recordPath = mINI::Instance()[Config::Record::kFilePath];
static string recordAppName = mINI::Instance()[Config::Record::kAppName]; static string recordAppName = mINI::Instance()[Config::Record::kAppName];
m_mp4Maker.reset(new Mp4Maker(recordPath + "/" + recordAppName + "/" + strApp + "/" + strId + "/", m_mp4Maker.reset(new Mp4Maker(recordPath + "/" + strVhost + "/" + recordAppName + "/" + strApp + "/" + strId + "/",
strApp,strId,pPlayer)); strVhost,strApp,strId,pPlayer));
#endif //ENABLE_MP4V2 #endif //ENABLE_MP4V2
} }
@ -62,20 +77,14 @@ MediaRecorder::~MediaRecorder() {
} }
void MediaRecorder::inputH264(void* pData, uint32_t ui32Length, uint32_t ui32TimeStamp, int iType) { void MediaRecorder::inputH264(void* pData, uint32_t ui32Length, uint32_t ui32TimeStamp, int iType) {
#ifdef ENABLE_HLS
m_hlsMaker->inputH264(pData, ui32Length, ui32TimeStamp * 90, iType); m_hlsMaker->inputH264(pData, ui32Length, ui32TimeStamp * 90, iType);
#endif //ENABLE_HLS
#ifdef ENABLE_MP4V2 #ifdef ENABLE_MP4V2
m_mp4Maker->inputH264(pData, ui32Length, ui32TimeStamp, iType); m_mp4Maker->inputH264(pData, ui32Length, ui32TimeStamp, iType);
#endif //ENABLE_MP4V2 #endif //ENABLE_MP4V2
} }
void MediaRecorder::inputAAC(void* pData, uint32_t ui32Length, uint32_t ui32TimeStamp) { void MediaRecorder::inputAAC(void* pData, uint32_t ui32Length, uint32_t ui32TimeStamp) {
#ifdef ENABLE_HLS
m_hlsMaker->inputAAC(pData, ui32Length, ui32TimeStamp * 90); m_hlsMaker->inputAAC(pData, ui32Length, ui32TimeStamp * 90);
#endif //ENABLE_HLS
#ifdef ENABLE_MP4V2 #ifdef ENABLE_MP4V2
m_mp4Maker->inputAAC(pData, ui32Length, ui32TimeStamp); m_mp4Maker->inputAAC(pData, ui32Length, ui32TimeStamp);
#endif //ENABLE_MP4V2 #endif //ENABLE_MP4V2

View File

@ -34,9 +34,7 @@
#include "Mp4Maker.h" #include "Mp4Maker.h"
#endif //ENABLE_MP4V2 #endif //ENABLE_MP4V2
#ifdef ENABLE_HLS
#include "HLSMaker.h" #include "HLSMaker.h"
#endif //ENABLE_HLS
using namespace std; using namespace std;
using namespace ZL::Player; using namespace ZL::Player;
@ -48,7 +46,7 @@ namespace MediaFile {
class MediaRecorder { class MediaRecorder {
public: public:
typedef std::shared_ptr<MediaRecorder> Ptr; 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(); virtual ~MediaRecorder();
void inputH264( void *pData, void inputH264( void *pData,
@ -60,11 +58,7 @@ public:
uint32_t ui32Length, uint32_t ui32Length,
uint32_t ui32TimeStamp); uint32_t ui32TimeStamp);
private: private:
#ifdef ENABLE_HLS
std::shared_ptr<HLSMaker> m_hlsMaker; std::shared_ptr<HLSMaker> m_hlsMaker;
#endif //ENABLE_HLS
#ifdef ENABLE_MP4V2 #ifdef ENABLE_MP4V2
std::shared_ptr<Mp4Maker> m_mp4Maker; std::shared_ptr<Mp4Maker> m_mp4Maker;
#endif //ENABLE_MP4V2 #endif //ENABLE_MP4V2

View File

@ -59,7 +59,11 @@ string timeStr(const char *fmt) {
#endif #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; DebugL << strPath;
m_pPlayer = pPlayer; m_pPlayer = pPlayer;
m_strPath = strPath; m_strPath = strPath;
@ -67,6 +71,7 @@ Mp4Maker::Mp4Maker(const string& strPath,const string &strApp,const string &strS
/////record 业务逻辑////// /////record 业务逻辑//////
m_info.strAppName = strApp; m_info.strAppName = strApp;
m_info.strStreamId = strStreamId; m_info.strStreamId = strStreamId;
m_info.strVhost = strVhost;
m_info.strFolder = strPath; m_info.strFolder = strPath;
//----record 业务逻辑----// //----record 业务逻辑----//
} }
@ -144,7 +149,6 @@ void Mp4Maker::createFile() {
} }
closeFile(); closeFile();
auto strDate = timeStr("%Y-%m-%d"); auto strDate = timeStr("%Y-%m-%d");
auto strTime = timeStr("%H-%M-%S"); auto strTime = timeStr("%H-%M-%S");
auto strFileTmp = m_strPath + strDate + "/." + strTime + ".mp4"; auto strFileTmp = m_strPath + strDate + "/." + strTime + ".mp4";
@ -155,7 +159,8 @@ void Mp4Maker::createFile() {
m_info.strFileName = strTime + ".mp4"; m_info.strFileName = strTime + ".mp4";
m_info.strFilePath = strFile; m_info.strFilePath = strFile;
static string appName = mINI::Instance()[Config::Record::kAppName]; static string appName = mINI::Instance()[Config::Record::kAppName];
m_info.strUrl = appName + "/" m_info.strUrl = m_info.strVhost + "/"
+ appName + "/"
+ m_info.strAppName + "/" + m_info.strAppName + "/"
+ m_info.strStreamId + "/" + m_info.strStreamId + "/"
+ strDate + "/" + strDate + "/"

View File

@ -57,11 +57,16 @@ public:
string strUrl;//播放路径 string strUrl;//播放路径
string strAppName;//应用名称 string strAppName;//应用名称
string strStreamId;//流ID string strStreamId;//流ID
string strVhost;//vhost
}; };
class Mp4Maker { class Mp4Maker {
public: public:
typedef std::shared_ptr<Mp4Maker> Ptr; 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(); virtual ~Mp4Maker();
//时间戳参考频率1000 //时间戳参考频率1000
void inputH264(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp, int iType); void inputH264(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp, int iType);

View File

@ -32,30 +32,6 @@ using namespace ZL::MediaFile;
namespace ZL { namespace ZL {
namespace Rtmp { 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 Rtmp */
} /* namespace ZL */ } /* namespace ZL */

View File

@ -36,6 +36,7 @@
#include "Rtmp.h" #include "Rtmp.h"
#include "Common/config.h" #include "Common/config.h"
#include "Common/MediaSender.h" #include "Common/MediaSender.h"
#include "Common/MediaSource.h"
#include "Util/util.h" #include "Util/util.h"
#include "Util/logger.h" #include "Util/logger.h"
#include "Util/RingBuffer.h" #include "Util/RingBuffer.h"
@ -47,72 +48,28 @@
using namespace std; using namespace std;
using namespace ZL::Util; using namespace ZL::Util;
using namespace ZL::Thread; using namespace ZL::Thread;
using namespace ZL::Media;
namespace ZL { namespace ZL {
namespace Rtmp { namespace Rtmp {
class RtmpMediaSource: public MediaSource {
class RtmpMediaSource: public enable_shared_from_this<RtmpMediaSource> {
public: public:
typedef std::shared_ptr<RtmpMediaSource> Ptr; typedef std::shared_ptr<RtmpMediaSource> Ptr;
typedef RingBuffer<RtmpPacket::Ptr> RingType; typedef RingBuffer<RtmpPacket::Ptr> RingType;
RtmpMediaSource(const string &strApp, const string &strId) :
m_strApp(strApp), RtmpMediaSource(const string &vhost,const string &strApp, const string &strId) :
m_strId(strId), MediaSource(RTMP_SCHEMA,vhost,strApp,strId),
m_pRing(new RingBuffer<RtmpPacket::Ptr>()), m_pRing(new RingBuffer<RtmpPacket::Ptr>()),
m_thPool( MediaSender::sendThread()) { m_thPool( MediaSender::sendThread()) {
} }
virtual ~RtmpMediaSource() { virtual ~RtmpMediaSource() {}
unregist();
}
const RingType::Ptr &getRing() const { const RingType::Ptr &getRing() const {
//获取媒体源的rtp环形缓冲 //获取媒体源的rtp环形缓冲
return m_pRing; 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 { const AMFValue &getMetaData() const {
return m_metadata; return m_metadata;
} }
@ -140,37 +97,12 @@ public:
_ring->write(pkt,pkt->isVideoKeyFrame()); _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: protected:
function<bool(uint32_t)> m_onSeek;
function<uint32_t()> m_onStamp;
private:
AMFValue m_metadata; AMFValue m_metadata;
unordered_map<int, RtmpPacket::Ptr> m_mapCfgFrame; unordered_map<int, RtmpPacket::Ptr> m_mapCfgFrame;
mutable recursive_mutex m_mtxMap; mutable recursive_mutex m_mtxMap;
string m_strApp; //媒体app
string m_strId; //媒体id
RingBuffer<RtmpPacket::Ptr>::Ptr m_pRing; //rtp环形缓冲 RingBuffer<RtmpPacket::Ptr>::Ptr m_pRing; //rtp环形缓冲
ThreadPool &m_thPool; ThreadPool &m_thPool;
static unordered_map<string, unordered_map<string,weak_ptr<RtmpMediaSource> > > g_mapMediaSrc; //静态的媒体源表
static recursive_mutex g_mtxMediaSrc; ///访问静态的媒体源表的互斥锁
}; };
} /* namespace Rtmp */ } /* namespace Rtmp */

View File

@ -36,10 +36,10 @@ namespace ZL {
namespace Rtmp { namespace Rtmp {
unordered_map<string, RtmpPusher::rtmpCMDHandle> RtmpPusher::g_mapCmd; unordered_map<string, RtmpPusher::rtmpCMDHandle> RtmpPusher::g_mapCmd;
RtmpPusher::RtmpPusher(const char *strApp,const char *strStream) { RtmpPusher::RtmpPusher(const char *strVhost,const char *strApp,const char *strStream) {
auto src = RtmpMediaSource::find(strApp,strStream); auto src = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,strVhost,strApp,strStream));
if (!src) { 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); throw std::runtime_error(strErr);
} }
init(src); init(src);

View File

@ -38,7 +38,7 @@ class RtmpPusher: public RtmpProtocol , public TcpClient{
public: public:
typedef std::shared_ptr<RtmpPusher> Ptr; typedef std::shared_ptr<RtmpPusher> Ptr;
typedef std::function<void(const SockException &ex)> Event; 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); RtmpPusher(const RtmpMediaSource::Ptr &src);
virtual ~RtmpPusher(); virtual ~RtmpPusher();

View File

@ -97,7 +97,12 @@ void RtmpSession::onCmd_connect(AMFDecoder &dec) {
///////////set peerBandwidth//////////////// ///////////set peerBandwidth////////////////
sendPeerBandwidth(5000000); 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); bool ok = true; //(app == APP_NAME);
AMFValue version(AMF_OBJECT); AMFValue version(AMF_OBJECT);
version.set("fmsVer", "FMS/3,0,1,123"); version.set("fmsVer", "FMS/3,0,1,123");
@ -109,7 +114,7 @@ void RtmpSession::onCmd_connect(AMFDecoder &dec) {
status.set("objectEncoding", amfVer); status.set("objectEncoding", amfVer);
sendReply(ok ? "_result" : "_error", version, status); sendReply(ok ? "_result" : "_error", version, status);
if (!ok) { if (!ok) {
throw std::runtime_error("Unsupported application: " + m_strApp); throw std::runtime_error("Unsupported application: " + m_mediaInfo.m_app);
} }
AMFEncoder invoke; AMFEncoder invoke;
@ -123,12 +128,12 @@ void RtmpSession::onCmd_createStream(AMFDecoder &dec) {
void RtmpSession::onCmd_publish(AMFDecoder &dec) { void RtmpSession::onCmd_publish(AMFDecoder &dec) {
dec.load<AMFValue>();/* NULL */ dec.load<AMFValue>();/* NULL */
m_strId = dec.load<std::string>(); m_mediaInfo.parse(m_strTcUrl + "/" + dec.load<std::string>());
auto iPos = m_strId.find('?'); auto src = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,
if (iPos != string::npos) { m_mediaInfo.m_vhost,
m_strId.erase(iPos); m_mediaInfo.m_app,
} m_mediaInfo.m_streamid,
auto src = RtmpMediaSource::find(m_strApp,m_strId,false); false));
bool ok = (!src && !m_pPublisherSrc); bool ok = (!src && !m_pPublisherSrc);
AMFValue status(AMF_OBJECT); AMFValue status(AMF_OBJECT);
status.set("level", ok ? "status" : "error"); status.set("level", ok ? "status" : "error");
@ -137,10 +142,13 @@ void RtmpSession::onCmd_publish(AMFDecoder &dec) {
status.set("clientid", "0"); status.set("clientid", "0");
sendReply("onStatus", nullptr, status); sendReply("onStatus", nullptr, status);
if (!ok) { 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_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) { void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) {
@ -152,11 +160,15 @@ void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) {
throw std::runtime_error(StrPrinter << "Stop publishing." << endl); throw std::runtime_error(StrPrinter << "Stop publishing." << endl);
} }
void RtmpSession::doPlay(){ void RtmpSession::doPlay(AMFDecoder &dec){
auto src = RtmpMediaSource::find(m_strApp,m_strId,true); 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()); bool ok = (src.operator bool());
ok = ok && src->ready(); ok = ok && src->ready();
//stream begin //stream begin
sendUserControl(CONTROL_STREAM_BEGIN, STREAM_MEDIA); sendUserControl(CONTROL_STREAM_BEGIN, STREAM_MEDIA);
@ -165,11 +177,15 @@ void RtmpSession::doPlay(){
status.set("level", ok ? "status" : "error"); status.set("level", ok ? "status" : "error");
status.set("code", ok ? "NetStream.Play.Reset" : "NetStream.Play.StreamNotFound"); status.set("code", ok ? "NetStream.Play.Reset" : "NetStream.Play.StreamNotFound");
status.set("description", ok ? "Resetting and playing." : "No such stream."); 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"); status.set("clientid", "0");
sendReply("onStatus", nullptr, status); sendReply("onStatus", nullptr, status);
if (!ok) { 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) // onStatus(NetStream.Play.Start)
@ -177,7 +193,7 @@ void RtmpSession::doPlay(){
status.set("level", "status"); status.set("level", "status");
status.set("code", "NetStream.Play.Start"); status.set("code", "NetStream.Play.Start");
status.set("description", "Started playing."); status.set("description", "Started playing.");
status.set("details", m_strId); status.set("details", m_mediaInfo.m_streamid);
status.set("clientid", "0"); status.set("clientid", "0");
sendReply("onStatus", nullptr, status); sendReply("onStatus", nullptr, status);
@ -198,7 +214,7 @@ void RtmpSession::doPlay(){
status.set("level", "status"); status.set("level", "status");
status.set("code", "NetStream.Play.PublishNotify"); status.set("code", "NetStream.Play.PublishNotify");
status.set("description", "Now published."); status.set("description", "Now published.");
status.set("details", m_strId); status.set("details", m_mediaInfo.m_streamid);
status.set("clientid", "0"); status.set("clientid", "0");
sendReply("onStatus", nullptr, status); sendReply("onStatus", nullptr, status);
@ -239,18 +255,19 @@ void RtmpSession::doPlay(){
if(src->getRing()->readerCount() == 1){ if(src->getRing()->readerCount() == 1){
src->seekTo(0); 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) { void RtmpSession::onCmd_play2(AMFDecoder &dec) {
doPlay(); doPlay(dec);
} }
void RtmpSession::onCmd_play(AMFDecoder &dec) { void RtmpSession::onCmd_play(AMFDecoder &dec) {
dec.load<AMFValue>();/* NULL */ dec.load<AMFValue>();/* NULL */
m_strId = dec.load<std::string>(); doPlay(dec);
auto iPos = m_strId.find('?');
if (iPos != string::npos) {
m_strId.erase(iPos);
}
doPlay();
} }
void RtmpSession::onCmd_pause(AMFDecoder &dec) { void RtmpSession::onCmd_pause(AMFDecoder &dec) {

View File

@ -53,8 +53,8 @@ public:
void onError(const SockException &err) override; void onError(const SockException &err) override;
void onManager() override; void onManager() override;
private: private:
std::string m_strApp; std::string m_strTcUrl;
std::string m_strId; MediaInfo m_mediaInfo;
double m_dNowReqID = 0; double m_dNowReqID = 0;
Ticker m_ticker;//数据接收时间 Ticker m_ticker;//数据接收时间
typedef void (RtmpSession::*rtmpCMDHandle)(AMFDecoder &dec); typedef void (RtmpSession::*rtmpCMDHandle)(AMFDecoder &dec);
@ -75,7 +75,7 @@ private:
void onCmd_play(AMFDecoder &dec); void onCmd_play(AMFDecoder &dec);
void onCmd_play2(AMFDecoder &dec); void onCmd_play2(AMFDecoder &dec);
void doPlay(); void doPlay(AMFDecoder &dec);
void onCmd_seek(AMFDecoder &dec); void onCmd_seek(AMFDecoder &dec);
void onCmd_pause(AMFDecoder &dec); void onCmd_pause(AMFDecoder &dec);
void setMetaData(AMFDecoder &dec); void setMetaData(AMFDecoder &dec);

View File

@ -36,25 +36,23 @@ using namespace ZL::Network;
namespace ZL { namespace ZL {
namespace Rtmp { namespace Rtmp {
#ifdef ENABLE_RTMP2RTSP RtmpToRtspMediaSource::RtmpToRtspMediaSource(const string &vhost,const string &app, const string &id) :
RtmpToRtspMediaSource::RtmpToRtspMediaSource(const string &_app, const string &_id) : RtmpMediaSource(vhost,app,id) {
RtmpMediaSource(_app,_id) {
}
RtmpToRtspMediaSource::~RtmpToRtspMediaSource() {
} }
RtmpToRtspMediaSource::~RtmpToRtspMediaSource() {}
void RtmpToRtspMediaSource::regist() { bool RtmpToRtspMediaSource::regist() {
RtmpMediaSource::regist();
if (m_pRtspSrc) { if (m_pRtspSrc) {
m_pRtspSrc->regist(); m_pRtspSrc->regist();
} }
return MediaSource::regist();
} }
void RtmpToRtspMediaSource::unregist() { bool RtmpToRtspMediaSource::unregist() {
RtmpMediaSource::unregist();
if(m_pRtspSrc){ if(m_pRtspSrc){
m_pRtspSrc->unregist(); m_pRtspSrc->unregist();
} }
return MediaSource::unregist();
} }
void RtmpToRtspMediaSource::onGetH264(const H264Frame &frame) { void RtmpToRtspMediaSource::onGetH264(const H264Frame &frame) {
@ -156,14 +154,12 @@ void RtmpToRtspMediaSource::makeSDP() {
<< "\r\n" << endl; << "\r\n" << endl;
} }
m_pRtspSrc.reset(new RtspMediaSource(getApp(),getId())); m_pRtspSrc.reset(new RtspMediaSource(getVhost(),getApp(),getId()));
m_pRtspSrc->setOnSeek(m_onSeek); m_pRtspSrc->setListener(m_listener);
m_pRtspSrc->setOnStamp(m_onStamp);
m_pRtspSrc->onGetSDP(strSDP); m_pRtspSrc->onGetSDP(strSDP);
m_pRtspSrc->regist(); m_pRtspSrc->regist();
} }
#endif // ENABLE_RTMP2RTSP
} /* namespace Rtmp */ } /* namespace Rtmp */
} /* namespace ZL */ } /* namespace ZL */

View File

@ -52,19 +52,20 @@ using namespace ZL::MediaFile;
namespace ZL { namespace ZL {
namespace Rtmp { namespace Rtmp {
#ifdef ENABLE_RTMP2RTSP
class RtmpToRtspMediaSource: public RtmpMediaSource { class RtmpToRtspMediaSource: public RtmpMediaSource {
public: public:
typedef std::shared_ptr<RtmpToRtspMediaSource> Ptr; 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 { try {
m_pParser.reset(new RtmpParser(_metadata)); 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->setOnAudioCB(std::bind(&RtmpToRtspMediaSource::onGetAdts, this, placeholders::_1));
m_pParser->setOnVideoCB(std::bind(&RtmpToRtspMediaSource::onGetH264, this, placeholders::_1)); m_pParser->setOnVideoCB(std::bind(&RtmpToRtspMediaSource::onGetH264, this, placeholders::_1));
} catch (exception &ex) { } catch (exception &ex) {
@ -73,7 +74,7 @@ public:
RtmpMediaSource::onGetMetaData(_metadata); RtmpMediaSource::onGetMetaData(_metadata);
} }
virtual void onGetMedia(const RtmpPacket::Ptr &pkt) override { void onGetMedia(const RtmpPacket::Ptr &pkt) override {
if (m_pParser) { if (m_pParser) {
if (!m_pRtspSrc && m_pParser->isInited()) { if (!m_pRtspSrc && m_pParser->isInited()) {
makeSDP(); makeSDP();
@ -82,18 +83,7 @@ public:
} }
RtmpMediaSource::onGetMedia(pkt); 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: private:
RtmpParser::Ptr m_pParser; RtmpParser::Ptr m_pParser;
RtspMediaSource::Ptr m_pRtspSrc; RtspMediaSource::Ptr m_pRtspSrc;
@ -105,9 +95,6 @@ private:
void onGetAdts(const AdtsFrame &frame); void onGetAdts(const AdtsFrame &frame);
void makeSDP(); void makeSDP();
}; };
#else
typedef RtmpMediaSource RtmpToRtspMediaSource;
#endif //ENABLE_RTMP2RTSP
} /* namespace Rtmp */ } /* namespace Rtmp */
} /* namespace ZL */ } /* namespace ZL */

View File

@ -84,10 +84,10 @@ RtpBroadCaster::~RtpBroadCaster() {
m_pReader->setDetachCB(nullptr); m_pReader->setDetachCB(nullptr);
DebugL; DebugL;
} }
RtpBroadCaster::RtpBroadCaster(const string &strLocalIp,const string &strApp,const string &strStream) { RtpBroadCaster::RtpBroadCaster(const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream) {
auto src = RtspMediaSource::find(strApp, strStream); auto src = dynamic_pointer_cast<RtspMediaSource>(MediaSource::find(RTSP_SCHEMA,strVhost,strApp, strStream));
if(!src){ if(!src){
auto strErr = StrPrinter << "未找到媒体源:" << strApp << " " << strStream << endl; auto strErr = StrPrinter << "未找到媒体源:" << strVhost << " " << strApp << " " << strStream << endl;
throw std::runtime_error(strErr); throw std::runtime_error(strErr);
} }
m_multiAddr = MultiCastAddressMaker::Instance().obtain(); m_multiAddr = MultiCastAddressMaker::Instance().obtain();
@ -130,6 +130,7 @@ RtpBroadCaster::RtpBroadCaster(const string &strLocalIp,const string &strApp,con
DebugL << MultiCastAddressMaker::toString(*m_multiAddr) << " " DebugL << MultiCastAddressMaker::toString(*m_multiAddr) << " "
<< m_apUdpSock[0]->get_local_port() << " " << m_apUdpSock[0]->get_local_port() << " "
<< m_apUdpSock[1]->get_local_port() << " " << m_apUdpSock[1]->get_local_port() << " "
<< strVhost << " "
<< strApp << " " << strStream; << strApp << " " << strStream;
} }
uint16_t RtpBroadCaster::getPort(int iTrackId){ uint16_t RtpBroadCaster::getPort(int iTrackId){
@ -139,11 +140,11 @@ uint16_t RtpBroadCaster::getPort(int iTrackId){
string RtpBroadCaster::getIP(){ string RtpBroadCaster::getIP(){
return inet_ntoa(m_aPeerUdpAddr[0].sin_addr); 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{ 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); 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; weak_ptr<RtpBroadCaster> weakPtr = ret;
g_mapBroadCaster.emplace(strKey,weakPtr); g_mapBroadCaster.emplace(strKey,weakPtr);
return ret; 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) { RtpBroadCaster::Ptr RtpBroadCaster::get(const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream) {
string strKey = StrPrinter << strLocalIp << " " << strApp << " " << strStream << endl; string strKey = StrPrinter << strLocalIp << " " << strVhost << " " << strApp << " " << strStream << endl;
lock_guard<recursive_mutex> lck(g_mtx); lock_guard<recursive_mutex> lck(g_mtx);
auto it = g_mapBroadCaster.find(strKey); auto it = g_mapBroadCaster.find(strKey);
if (it == g_mapBroadCaster.end()) { if (it == g_mapBroadCaster.end()) {
return make(strLocalIp,strApp, strStream); return make(strLocalIp,strVhost,strApp, strStream);
} }
auto ret = it->second.lock(); auto ret = it->second.lock();
if (!ret) { if (!ret) {
g_mapBroadCaster.erase(it); g_mapBroadCaster.erase(it);
return make(strLocalIp,strApp, strStream); return make(strLocalIp,strVhost,strApp, strStream);
} }
return ret; return ret;
} }

View File

@ -74,14 +74,14 @@ public:
typedef std::shared_ptr<RtpBroadCaster> Ptr; typedef std::shared_ptr<RtpBroadCaster> Ptr;
typedef function<void()> onDetach; typedef function<void()> onDetach;
virtual ~RtpBroadCaster(); 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); void setDetachCB(void *listener,const onDetach &cb);
uint16_t getPort(int iTrackId); uint16_t getPort(int iTrackId);
string getIP(); string getIP();
private: private:
static recursive_mutex g_mtx; static recursive_mutex g_mtx;
static unordered_map<string , weak_ptr<RtpBroadCaster> > g_mapBroadCaster; 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; std::shared_ptr<uint32_t> m_multiAddr;
recursive_mutex m_mtx; recursive_mutex m_mtx;
@ -90,7 +90,7 @@ private:
Socket::Ptr m_apUdpSock[2]; Socket::Ptr m_apUdpSock[2];
struct sockaddr_in m_aPeerUdpAddr[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);
}; };

View File

@ -163,36 +163,18 @@ public:
this->m_strContent = content; this->m_strContent = content;
} }
const StrCaseMap& getValues() const { StrCaseMap& getValues() const {
return m_mapValues; return m_mapValues;
} }
const StrCaseMap& getUrlArgs() const { StrCaseMap& getUrlArgs() const {
return m_mapUrlArgs; 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 = "="){ static StrCaseMap parseArgs(const string &str,const char *pair_delim = "&", const char *key_delim = "="){
StrCaseMap ret; StrCaseMap ret;
auto arg_vec = split(str, pair_delim); auto arg_vec = split(str, pair_delim);
for (string &key_val : arg_vec) { for (string &key_val : arg_vec) {
if (!key_val.size()) {
continue;
}
auto key_val_vec = split(key_val, key_delim); auto key_val_vec = split(key_val, key_delim);
if (key_val_vec.size() >= 2) { if (key_val_vec.size() >= 2) {
ret[key_val_vec[0]] = key_val_vec[1]; ret[key_val_vec[0]] = key_val_vec[1];
@ -207,8 +189,8 @@ private:
string m_strTail; string m_strTail;
string m_strContent; string m_strContent;
string m_strNull; string m_strNull;
StrCaseMap m_mapValues; mutable StrCaseMap m_mapValues;
StrCaseMap m_mapUrlArgs; mutable StrCaseMap m_mapUrlArgs;
}; };
typedef struct { typedef struct {

View File

@ -32,30 +32,5 @@ using namespace ZL::MediaFile;
namespace ZL { namespace ZL {
namespace Rtsp { 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 Rtsp */
} /* namespace ZL */ } /* namespace ZL */

View File

@ -35,6 +35,8 @@
#include "Rtsp.h" #include "Rtsp.h"
#include "Common/config.h" #include "Common/config.h"
#include "Common/MediaSender.h" #include "Common/MediaSender.h"
#include "Common/MediaSource.h"
#include "Util/logger.h" #include "Util/logger.h"
#include "Util/RingBuffer.h" #include "Util/RingBuffer.h"
#include "Util/TimeTicker.h" #include "Util/TimeTicker.h"
@ -45,80 +47,33 @@
using namespace std; using namespace std;
using namespace ZL::Util; using namespace ZL::Util;
using namespace ZL::Thread; using namespace ZL::Thread;
using namespace ZL::Media;
namespace ZL { namespace ZL {
namespace Rtsp { namespace Rtsp {
class RtspMediaSource: public MediaSource {
class RtspMediaSource: public enable_shared_from_this<RtspMediaSource> {
public: public:
typedef ResourcePool<RtpPacket, 64> PoolType; typedef ResourcePool<RtpPacket, 64> PoolType;
typedef std::shared_ptr<RtspMediaSource> Ptr; typedef std::shared_ptr<RtspMediaSource> Ptr;
typedef RingBuffer<RtpPacket::Ptr> RingType; typedef RingBuffer<RtpPacket::Ptr> RingType;
RtspMediaSource(const string &strApp, const string &strId) :
m_strApp(strApp), RtspMediaSource(const string &strVhost,const string &strApp, const string &strId) :
m_strId(strId), MediaSource(RTSP_SCHEMA,strVhost,strApp,strId),
m_pRing(new RingBuffer<RtpPacket::Ptr>()), m_pRing(new RingBuffer<RtpPacket::Ptr>()),
m_thPool(MediaSender::sendThread()) { m_thPool(MediaSender::sendThread()) {
} }
virtual ~RtspMediaSource() { virtual ~RtspMediaSource() {}
unregist();
}
const RingType::Ptr &getRing() const { const RingType::Ptr &getRing() const {
//获取媒体源的rtp环形缓冲 //获取媒体源的rtp环形缓冲
return m_pRing; return m_pRing;
} }
const string& getSdp() const { const string& getSdp() const {
//获取该源的媒体描述信息 //获取该源的媒体描述信息
return m_strSdp; 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) { virtual uint32_t getSsrc(int trackId) {
return m_mapTracks[trackId].ssrc; return m_mapTracks[trackId].ssrc;
} }
@ -131,7 +86,7 @@ public:
virtual void onGetSDP(const string& sdp) { virtual void onGetSDP(const string& sdp) {
//派生类设置该媒体源媒体描述信息 //派生类设置该媒体源媒体描述信息
this->m_strSdp = sdp; m_strSdp = sdp;
} }
virtual void onGetRTP(const RtpPacket::Ptr &rtppt, bool keyPos) { virtual void onGetRTP(const RtpPacket::Ptr &rtppt, bool keyPos) {
auto &trackRef = m_mapTracks[rtppt->interleaved / 2]; auto &trackRef = m_mapTracks[rtppt->interleaved / 2];
@ -144,36 +99,11 @@ public:
_outRing->write(rtppt,keyPos); _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: protected:
function<bool(uint32_t)> m_onSeek;
function<uint32_t()> m_onStamp;
unordered_map<int, RtspTrack> m_mapTracks; unordered_map<int, RtspTrack> m_mapTracks;
private: string m_strSdp; //媒体描述信息
string m_strSdp; //媒体描述信息 RingType::Ptr m_pRing; //rtp环形缓冲
string m_strApp; //媒体app
string m_strId; //媒体id
RingType::Ptr m_pRing; //rtp环形缓冲
ThreadPool &m_thPool; ThreadPool &m_thPool;
static unordered_map<string, unordered_map<string, weak_ptr<RtspMediaSource> > > g_mapMediaSrc; //静态的媒体源表
static recursive_mutex g_mtxMediaSrc; ///访问静态的媒体源表的互斥锁
}; };
} /* namespace Rtsp */ } /* namespace Rtsp */

View File

@ -427,19 +427,6 @@ void RtspPlayer::pause(bool bPause) {
sendPause(bPause,getProgressTime()); 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) { void RtspPlayer::HandleResPAUSE(const Parser& parser, bool bPause) {
if (parser.Url() != "200") { if (parser.Url() != "200") {
WarnL <<(bPause ? "Pause" : "Play") << " failed:" << parser.Url() << " " << parser.Tail() << endl; WarnL <<(bPause ? "Pause" : "Play") << " failed:" << parser.Url() << " " << parser.Tail() << endl;
@ -461,18 +448,15 @@ void RtspPlayer::HandleResPAUSE(const Parser& parser, bool bPause) {
auto strRtpInfo = parser["RTP-Info"]; auto strRtpInfo = parser["RTP-Info"];
if (strRtpInfo.size()) { if (strRtpInfo.size()) {
strRtpInfo.append(","); strRtpInfo.append(",");
vector<string> vec; vector<string> vec = split(strRtpInfo, ",");
split(strRtpInfo, ",", vec);
for(auto &strTrack : vec){ for(auto &strTrack : vec){
if (strTrack.size()) { strTrack.append(";");
strTrack.append(";"); auto strTrackId = FindField(strTrack.data(), m_aTrackInfo[0].trackStyle.data(), ";");
auto strTrackId = FindField(strTrack.data(), m_aTrackInfo[0].trackStyle.data(), ";"); auto strRtpTime = FindField(strTrack.data(), "rtptime=", ";");
auto strRtpTime = FindField(strTrack.data(), "rtptime=", ";"); auto iIdx = getTrackIndex(atoi(strTrackId.data()));
auto iIdx = getTrackIndex(atoi(strTrackId.data())); m_adFistStamp[iIdx] = atoll(strRtpTime.data());
m_adFistStamp[iIdx] = atoll(strRtpTime.data()); m_adNowStamp[iIdx] = m_adFistStamp[iIdx];
m_adNowStamp[iIdx] = m_adFistStamp[iIdx]; DebugL << "rtptime:" << strTrackId <<" " << strRtpTime;
DebugL << "rtptime:" << strTrackId <<" " << strRtpTime;
}
} }
} }
_onPlayResult(SockException(Err_success, "rtsp play success")); _onPlayResult(SockException(Err_success, "rtsp play success"));

View File

@ -55,7 +55,6 @@ unordered_map<void *, std::shared_ptr<RtspSession> > RtspSession::g_mapPostter;
recursive_mutex RtspSession::g_mtxGetter; //对quicktime上锁保护 recursive_mutex RtspSession::g_mtxGetter; //对quicktime上锁保护
recursive_mutex RtspSession::g_mtxPostter; //对quicktime上锁保护 recursive_mutex RtspSession::g_mtxPostter; //对quicktime上锁保护
unordered_map<string, RtspSession::rtspCMDHandle> RtspSession::g_mapCmd; unordered_map<string, RtspSession::rtspCMDHandle> RtspSession::g_mapCmd;
string RtspSession::g_serverName;
RtspSession::RtspSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock) : RtspSession::RtspSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock) :
TcpLimitedSession(pTh, pSock), m_pSender(pSock) { TcpLimitedSession(pTh, pSock), m_pSender(pSock) {
static onceToken token( []() { 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("POST",&RtspSession::handleReq_Post);
g_mapCmd.emplace("SET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER); g_mapCmd.emplace("SET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER);
g_mapCmd.emplace("GET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER); g_mapCmd.emplace("GET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER);
g_serverName = mINI::Instance()[Config::Rtsp::kServerName];
}, []() {}); }, []() {});
#ifndef __x86_64__ #ifndef __x86_64__
@ -184,7 +182,7 @@ bool RtspSession::handleReq_Options() {
"%s" "%s"
"Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY," "Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY,"
" PAUSE, SET_PARAMETER, GET_PARAMETER\r\n\r\n", " PAUSE, SET_PARAMETER, GET_PARAMETER\r\n\r\n",
m_iCseq, g_serverName.data(), m_iCseq, SERVER_NAME,
RTSP_VERSION, RTSP_BUILDTIME, RTSP_VERSION, RTSP_BUILDTIME,
dateHeader().data()); dateHeader().data());
send(m_pcBuf, n); send(m_pcBuf, n);
@ -192,7 +190,15 @@ bool RtspSession::handleReq_Options() {
} }
bool RtspSession::handleReq_Describe() { bool RtspSession::handleReq_Describe() {
m_strUrl = m_parser.Url(); {
//解析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()) { if (!findStream()) {
//未找到相应的MediaSource //未找到相应的MediaSource
send_StreamNotFound(); 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(""); invoker("");
} }
@ -242,7 +251,7 @@ void RtspSession::onAuthSuccess(const weak_ptr<RtspSession> &weakSelf) {
"Content-Base: %s/\r\n" "Content-Base: %s/\r\n"
"Content-Type: application/sdp\r\n" "Content-Type: application/sdp\r\n"
"Content-Length: %d\r\n\r\n%s", "Content-Length: %d\r\n\r\n%s",
strongSelf->m_iCseq, strongSelf->g_serverName.data(), strongSelf->m_iCseq, SERVER_NAME,
RTSP_VERSION, RTSP_BUILDTIME, RTSP_VERSION, RTSP_BUILDTIME,
dateHeader().data(), strongSelf->m_strUrl.data(), dateHeader().data(), strongSelf->m_strUrl.data(),
(int) strongSelf->m_strSdp.length(), strongSelf->m_strSdp.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" "Server: %s-%0.2f(build in %s)\r\n"
"%s" "%s"
"WWW-Authenticate:Digest realm=\"%s\",nonce=\"%s\"\r\n\r\n", "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, RTSP_VERSION, RTSP_BUILDTIME,
dateHeader().data(), realm.data(), strongSelf->m_strNonce.data()); dateHeader().data(), realm.data(), strongSelf->m_strNonce.data());
}else { }else {
@ -285,7 +294,7 @@ void RtspSession::onAuthFailed(const weak_ptr<RtspSession> &weakSelf,const strin
"Server: %s-%0.2f(build in %s)\r\n" "Server: %s-%0.2f(build in %s)\r\n"
"%s" "%s"
"WWW-Authenticate:Basic realm=\"%s\"\r\n\r\n", "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, RTSP_VERSION, RTSP_BUILDTIME,
dateHeader().data(), realm.data()); dateHeader().data(), realm.data());
} }
@ -297,7 +306,7 @@ void RtspSession::onAuthBasic(const weak_ptr<RtspSession> &weakSelf,const string
//base64认证 //base64认证
char user_pwd_buf[512]; char user_pwd_buf[512];
av_base64_decode((uint8_t *)user_pwd_buf,strBase64.data(),strBase64.size()); 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){ if(user_pwd_vec.size() < 2){
//认证信息格式不合法回复401 Unauthorized //认证信息格式不合法回复401 Unauthorized
onAuthFailed(weakSelf,realm); onAuthFailed(weakSelf,realm);
@ -324,23 +333,7 @@ void RtspSession::onAuthBasic(const weak_ptr<RtspSession> &weakSelf,const string
invoker(false,pwd); 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){ void RtspSession::onAuthDigest(const weak_ptr<RtspSession> &weakSelf,const string &realm,const string &strMd5){
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf){ if(!strongSelf){
@ -351,7 +344,7 @@ void RtspSession::onAuthDigest(const weak_ptr<RtspSession> &weakSelf,const strin
auto mapTmp = Parser::parseArgs(strMd5,",","="); auto mapTmp = Parser::parseArgs(strMd5,",","=");
decltype(mapTmp) map; decltype(mapTmp) map;
for(auto &pr : mapTmp){ for(auto &pr : mapTmp){
map[trim(pr.first)] = trim(pr.second); map[trim(string(pr.first)," \"")] = trim(pr.second," \"");
} }
//check realm //check realm
if(realm != map["realm"]){ if(realm != map["realm"]){
@ -448,7 +441,7 @@ inline void RtspSession::send_StreamNotFound() {
"Server: %s-%0.2f(build in %s)\r\n" "Server: %s-%0.2f(build in %s)\r\n"
"%s" "%s"
"Connection: Close\r\n\r\n", "Connection: Close\r\n\r\n",
m_iCseq, g_serverName.data(), m_iCseq, SERVER_NAME,
RTSP_VERSION, RTSP_BUILDTIME, RTSP_VERSION, RTSP_BUILDTIME,
dateHeader().data()); dateHeader().data());
send(m_pcBuf, n); send(m_pcBuf, n);
@ -459,7 +452,7 @@ inline void RtspSession::send_UnsupportedTransport() {
"Server: %s-%0.2f(build in %s)\r\n" "Server: %s-%0.2f(build in %s)\r\n"
"%s" "%s"
"Connection: Close\r\n\r\n", "Connection: Close\r\n\r\n",
m_iCseq, g_serverName.data(), m_iCseq, SERVER_NAME,
RTSP_VERSION, RTSP_BUILDTIME, RTSP_VERSION, RTSP_BUILDTIME,
dateHeader().data()); dateHeader().data());
send(m_pcBuf, n); send(m_pcBuf, n);
@ -471,7 +464,7 @@ inline void RtspSession::send_SessionNotFound() {
"Server: %s-%0.2f(build in %s)\r\n" "Server: %s-%0.2f(build in %s)\r\n"
"%s" "%s"
"Connection: Close\r\n\r\n", "Connection: Close\r\n\r\n",
m_iCseq, g_serverName.data(), m_iCseq, SERVER_NAME,
RTSP_VERSION, RTSP_BUILDTIME, RTSP_VERSION, RTSP_BUILDTIME,
dateHeader().data()); dateHeader().data());
send(m_pcBuf, n); send(m_pcBuf, n);
@ -539,7 +532,7 @@ bool RtspSession::handleReq_Setup() {
"Session: %s\r\n" "Session: %s\r\n"
"x-Transport-Options: late-tolerance=1.400000\r\n" "x-Transport-Options: late-tolerance=1.400000\r\n"
"x-Dynamic-Rate: 1\r\n\r\n", "x-Dynamic-Rate: 1\r\n\r\n",
m_iCseq, g_serverName.data(), m_iCseq, SERVER_NAME,
RTSP_VERSION, RTSP_BUILDTIME, RTSP_VERSION, RTSP_BUILDTIME,
dateHeader().data(), trackid * 2, dateHeader().data(), trackid * 2,
trackid * 2 + 1, trackid * 2 + 1,
@ -584,7 +577,7 @@ bool RtspSession::handleReq_Setup() {
"Transport: RTP/AVP/UDP;unicast;" "Transport: RTP/AVP/UDP;unicast;"
"client_port=%s;server_port=%d-%d;ssrc=%s;mode=play\r\n" "client_port=%s;server_port=%d-%d;ssrc=%s;mode=play\r\n"
"Session: %s\r\n\r\n", "Session: %s\r\n\r\n",
m_iCseq, g_serverName.data(), m_iCseq, SERVER_NAME,
RTSP_VERSION, RTSP_BUILDTIME, RTSP_VERSION, RTSP_BUILDTIME,
dateHeader().data(), strClientPort.data(), dateHeader().data(), strClientPort.data(),
pSockRtp->get_local_port(), pSockRtcp->get_local_port(), pSockRtp->get_local_port(), pSockRtcp->get_local_port(),
@ -595,7 +588,7 @@ bool RtspSession::handleReq_Setup() {
break; break;
case PlayerBase::RTP_MULTICAST: { case PlayerBase::RTP_MULTICAST: {
if(!m_pBrdcaster){ 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) { if (!m_pBrdcaster) {
send_NotAcceptable(); send_NotAcceptable();
return false; return false;
@ -627,7 +620,7 @@ bool RtspSession::handleReq_Setup() {
"Transport: RTP/AVP;multicast;destination=%s;" "Transport: RTP/AVP;multicast;destination=%s;"
"source=%s;port=%d-%d;ttl=%d;ssrc=%s\r\n" "source=%s;port=%d-%d;ttl=%d;ssrc=%s\r\n"
"Session: %s\r\n\r\n", "Session: %s\r\n\r\n",
m_iCseq, g_serverName.data(), m_iCseq, SERVER_NAME,
RTSP_VERSION, RTSP_BUILDTIME, RTSP_VERSION, RTSP_BUILDTIME,
dateHeader().data(), m_pBrdcaster->getIP().data(), dateHeader().data(), m_pBrdcaster->getIP().data(),
getLocalIp().data(), iSrvPort, pSockRtcp->get_local_port(), getLocalIp().data(), iSrvPort, pSockRtcp->get_local_port(),
@ -705,7 +698,7 @@ bool RtspSession::handleReq_Play() {
"%s" "%s"
"Session: %s\r\n" "Session: %s\r\n"
"Range: npt=%.2f-\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); dateHeader().data(), m_strSession.data(),iStamp/1000.0);
for (unsigned int i = 0; i < m_uiTrackCnt; i++) { for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
@ -722,7 +715,11 @@ bool RtspSession::handleReq_Play() {
(m_pcBuf)[iLen] = '\0'; (m_pcBuf)[iLen] = '\0';
iLen += sprintf(m_pcBuf + iLen, "\r\n\r\n"); iLen += sprintf(m_pcBuf + iLen, "\r\n\r\n");
send(m_pcBuf, iLen); 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; return true;
} }
@ -735,7 +732,7 @@ bool RtspSession::handleReq_Pause() {
"CSeq: %d\r\n" "CSeq: %d\r\n"
"Server: %s-%0.2f(build in %s)\r\n" "Server: %s-%0.2f(build in %s)\r\n"
"%s" "%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()); dateHeader().data(), m_strSession.data());
send(m_pcBuf, n); send(m_pcBuf, n);
if(m_pRtpReader){ if(m_pRtpReader){
@ -750,7 +747,7 @@ bool RtspSession::handleReq_Teardown() {
"CSeq: %d\r\n" "CSeq: %d\r\n"
"Server: %s-%0.2f(build in %s)\r\n" "Server: %s-%0.2f(build in %s)\r\n"
"%s" "%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()); dateHeader().data(), m_strSession.data());
send(m_pcBuf, n); send(m_pcBuf, n);
@ -801,7 +798,7 @@ bool RtspSession::handleReq_SET_PARAMETER() {
"CSeq: %d\r\n" "CSeq: %d\r\n"
"Server: %s-%0.2f(build in %s)\r\n" "Server: %s-%0.2f(build in %s)\r\n"
"%s" "%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()); dateHeader().data(), m_strSession.data());
send(m_pcBuf, n); send(m_pcBuf, n);
return true; return true;
@ -812,21 +809,17 @@ inline void RtspSession::send_NotAcceptable() {
"CSeq: %d\r\n" "CSeq: %d\r\n"
"Server: %s-%0.2f(build in %s)\r\n" "Server: %s-%0.2f(build in %s)\r\n"
"%s" "%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()); dateHeader().data());
send(m_pcBuf, n); 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() { inline bool RtspSession::findStream() {
splitRtspUrl(m_strUrl,m_strApp,m_strStream); RtspMediaSource::Ptr pMediaSrc =
RtspMediaSource::Ptr pMediaSrc = RtspMediaSource::find(m_strApp,m_strStream); dynamic_pointer_cast<RtspMediaSource>( MediaSource::find(RTSP_SCHEMA,m_mediaInfo.m_vhost, m_mediaInfo.m_app,m_mediaInfo.m_streamid) );
if (!pMediaSrc) { 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; return false;
} }
m_strSdp = pMediaSrc->getSdp(); m_strSdp = pMediaSrc->getSdp();

View File

@ -109,7 +109,6 @@ private:
void inline send_UnsupportedTransport(); //不支持的传输模式 void inline send_UnsupportedTransport(); //不支持的传输模式
void inline send_SessionNotFound(); //会话id错误 void inline send_SessionNotFound(); //会话id错误
void inline send_NotAcceptable(); //rtsp同时播放数限制 void inline send_NotAcceptable(); //rtsp同时播放数限制
void splitRtspUrl(const string &url,string &app,string &stream);
inline bool findStream(); //根据rtsp url查找 MediaSource实例 inline bool findStream(); //根据rtsp url查找 MediaSource实例
inline void initSender(const std::shared_ptr<RtspSession> &pSession); //处理rtsp over httpquicktime使用的 inline void initSender(const std::shared_ptr<RtspSession> &pSession); //处理rtsp over httpquicktime使用的
@ -148,8 +147,7 @@ private:
string m_strSdp; string m_strSdp;
string m_strSession; string m_strSession;
bool m_bFirstPlay = true; bool m_bFirstPlay = true;
string m_strApp; MediaInfo m_mediaInfo;
string m_strStream;
std::weak_ptr<RtspMediaSource> m_pMediaSrc; std::weak_ptr<RtspMediaSource> m_pMediaSrc;
static unordered_map<string, rtspCMDHandle> g_mapCmd; static unordered_map<string, rtspCMDHandle> g_mapCmd;
@ -191,7 +189,6 @@ private:
static recursive_mutex g_mtxPostter; //对quicktime上锁保护 static recursive_mutex g_mtxPostter; //对quicktime上锁保护
static unordered_map<string, weak_ptr<RtspSession> > g_mapGetter; static unordered_map<string, weak_ptr<RtspSession> > g_mapGetter;
static unordered_map<void *, std::shared_ptr<RtspSession> > g_mapPostter; static unordered_map<void *, std::shared_ptr<RtspSession> > g_mapPostter;
static string g_serverName;
}; };

View File

@ -37,28 +37,27 @@ using namespace ZL::Network;
namespace ZL { namespace ZL {
namespace Rtsp { namespace Rtsp {
#ifdef ENABLE_RTSP2RTMP
RtspToRtmpMediaSource::RtspToRtmpMediaSource(const string &_app,const string &_id,bool bEnableFile) : RtspToRtmpMediaSource::RtspToRtmpMediaSource(const string &vhost,const string &app,const string &id,bool bEnableFile) :
RtspMediaSource(_app,_id),m_bEnableFile(bEnableFile) { RtspMediaSource(vhost,app,id),m_bEnableFile(bEnableFile) {
} }
RtspToRtmpMediaSource::~RtspToRtmpMediaSource() { RtspToRtmpMediaSource::~RtspToRtmpMediaSource() {
} }
void RtspToRtmpMediaSource::regist() { bool RtspToRtmpMediaSource::regist() {
RtspMediaSource::regist();
if (m_pRtmpSrc) { if (m_pRtmpSrc) {
m_pRtmpSrc->regist(); m_pRtmpSrc->regist();
} }
return MediaSource::regist();
} }
void RtspToRtmpMediaSource::unregist() { bool RtspToRtmpMediaSource::unregist() {
RtspMediaSource::unregist();
if (m_pRtmpSrc) { if (m_pRtmpSrc) {
m_pRtmpSrc->unregist(); m_pRtmpSrc->unregist();
} }
return MediaSource::unregist();
} }
void RtspToRtmpMediaSource::makeVideoConfigPkt() { void RtspToRtmpMediaSource::makeVideoConfigPkt() {
@ -196,9 +195,8 @@ void RtspToRtmpMediaSource::makeAudioConfigPkt() {
} }
void RtspToRtmpMediaSource::makeMetaData() { void RtspToRtmpMediaSource::makeMetaData() {
m_pRtmpSrc.reset(new RtmpMediaSource(getApp(),getId())); m_pRtmpSrc.reset(new RtmpMediaSource(getVhost(),getApp(),getId()));
m_pRtmpSrc->setOnSeek(m_onSeek); m_pRtmpSrc->setListener(m_listener);
m_pRtmpSrc->setOnStamp(m_onStamp);
AMFValue metaData(AMF_OBJECT); AMFValue metaData(AMF_OBJECT);
metaData.set("duration", m_pParser->getDuration()); metaData.set("duration", m_pParser->getDuration());
metaData.set("fileSize", 0); metaData.set("fileSize", 0);
@ -222,6 +220,5 @@ void RtspToRtmpMediaSource::makeMetaData() {
m_pRtmpSrc->onGetMetaData(metaData); m_pRtmpSrc->onGetMetaData(metaData);
} }
#endif //ENABLE_RTSP2RTMP
} /* namespace Rtsp */ } /* namespace Rtsp */
} /* namespace ZL */ } /* namespace ZL */

View File

@ -38,18 +38,17 @@ using namespace ZL::MediaFile;
namespace ZL { namespace ZL {
namespace Rtsp { namespace Rtsp {
#ifdef ENABLE_RTSP2RTMP
class RtspToRtmpMediaSource: public RtspMediaSource { class RtspToRtmpMediaSource: public RtspMediaSource {
public: public:
typedef std::shared_ptr<RtspToRtmpMediaSource> Ptr; 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 ~RtspToRtmpMediaSource();
virtual void onGetSDP(const string& strSdp) override{ virtual void onGetSDP(const string& strSdp) override{
try { try {
m_pParser.reset(new RtpParser(strSdp)); m_pParser.reset(new RtpParser(strSdp));
if(m_bEnableFile){ 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->setOnAudioCB( std::bind(&RtspToRtmpMediaSource::onGetAdts, this, placeholders::_1));
m_pParser->setOnVideoCB( std::bind(&RtspToRtmpMediaSource::onGetH264, this, placeholders::_1)); m_pParser->setOnVideoCB( std::bind(&RtspToRtmpMediaSource::onGetH264, this, placeholders::_1));
@ -65,23 +64,13 @@ public:
} }
RtspMediaSource::onGetRTP(pRtppkt, bKeyPos); RtspMediaSource::onGetRTP(pRtppkt, bKeyPos);
} }
virtual void regist() override ; virtual bool regist() override ;
virtual void unregist() override; virtual bool unregist() override;
int readerCount(){ int readerCount(){
return getRing()->readerCount() + (m_pRtmpSrc ? m_pRtmpSrc->getRing()->readerCount() : 0); 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) { void updateTimeStamp(uint32_t uiStamp) {
for (auto &pr : m_mapTracks) { for (auto &pr : m_mapTracks) {
switch (pr.second.type) { switch (pr.second.type) {
@ -111,9 +100,6 @@ private:
void makeMetaData(); void makeMetaData();
}; };
#else
typedef RtspMediaSource RtspToRtmpMediaSource;
#endif //ENABLE_RTSP2RTMP
} /* namespace Rtsp */ } /* namespace Rtsp */
} /* namespace ZL */ } /* namespace ZL */

View File

@ -19,10 +19,10 @@ public:
_parser.reset(new OptionParser(nullptr)); _parser.reset(new OptionParser(nullptr));
(*_parser) << Option('l', "list", Option::ArgNone, nullptr,false, "list all media source of rtsp", (*_parser) << Option('l', "list", Option::ArgNone, nullptr,false, "list all media source of rtsp",
[](const std::shared_ptr<ostream> &stream, const string &arg) { [](const std::shared_ptr<ostream> &stream, const string &arg) {
auto mediaSet = RtspMediaSource::getMediaSet(); // auto mediaSet = RtspMediaSource::getMediaSet();
for (auto &src : mediaSet) { // for (auto &src : mediaSet) {
(*stream) << "\t" << src << "\r\n"; // (*stream) << "\t" << src << "\r\n";
} // }
return false; return false;
}); });
} }
@ -37,10 +37,10 @@ public:
_parser.reset(new OptionParser(nullptr)); _parser.reset(new OptionParser(nullptr));
(*_parser) << Option('l', "list", Option::ArgNone,nullptr,false, "list all media source of rtmp", (*_parser) << Option('l', "list", Option::ArgNone,nullptr,false, "list all media source of rtmp",
[](const std::shared_ptr<ostream> &stream, const string &arg) { [](const std::shared_ptr<ostream> &stream, const string &arg) {
auto mediaSet = RtmpMediaSource::getMediaSet(); // auto mediaSet = RtmpMediaSource::getMediaSet();
for (auto &src : mediaSet) { // for (auto &src : mediaSet) {
(*stream) << "\t" << src << "\r\n"; // (*stream) << "\t" << src << "\r\n";
} // }
return false; return false;
}); });
} }

View File

@ -35,15 +35,10 @@ namespace ZL {
namespace Shell { namespace Shell {
unordered_map<string, string> ShellSession::g_mapUser; unordered_map<string, string> ShellSession::g_mapUser;
string ShellSession::g_serverName;
ShellSession::ShellSession(const std::shared_ptr<ThreadPool> &_th, ShellSession::ShellSession(const std::shared_ptr<ThreadPool> &_th,
const Socket::Ptr &_sock) : const Socket::Ptr &_sock) :
TcpLimitedSession(_th, _sock) { TcpLimitedSession(_th, _sock) {
static onceToken token([]() {
g_serverName = mINI::Instance()[Config::Shell::kServerName];
}, nullptr);
pleaseInputUser(); pleaseInputUser();
} }
@ -107,7 +102,7 @@ inline bool ShellSession::onCommandLine(const string& line) {
inline void ShellSession::pleaseInputUser() { inline void ShellSession::pleaseInputUser() {
send("\033[0m"); send("\033[0m");
send(StrPrinter << g_serverName << " login: " << endl); send(StrPrinter << SERVER_NAME << " login: " << endl);
m_requestCB = [this](const string &line) { m_requestCB = [this](const string &line) {
m_strUserName=line; m_strUserName=line;
pleaseInputPasswd(); pleaseInputPasswd();
@ -121,14 +116,14 @@ inline void ShellSession::pleaseInputPasswd() {
send(StrPrinter send(StrPrinter
<<"\033[0mPermission denied," <<"\033[0mPermission denied,"
<<" please try again.\r\n" <<" please try again.\r\n"
<<m_strUserName<<"@"<<g_serverName <<m_strUserName<<"@"<<SERVER_NAME
<<"'s password: \033[8m" <<"'s password: \033[8m"
<<endl); <<endl);
return true; return true;
} }
send("\033[0m"); send("\033[0m");
send("-----------------------------------------\r\n"); send("-----------------------------------------\r\n");
send(StrPrinter<<"欢迎来到"<<g_serverName<<", 你可输入\"help\"查看帮助.\r\n"<<endl); send(StrPrinter<<"欢迎来到"<<SERVER_NAME<<", 你可输入\"help\"查看帮助.\r\n"<<endl);
send("-----------------------------------------\r\n"); send("-----------------------------------------\r\n");
printShellPrefix(); printShellPrefix();
m_requestCB=nullptr; m_requestCB=nullptr;
@ -137,7 +132,7 @@ inline void ShellSession::pleaseInputPasswd() {
} }
inline void ShellSession::printShellPrefix() { 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) { inline bool ShellSession::onAuth(const string &user, const string &pwd) {

View File

@ -64,7 +64,6 @@ private:
string m_strUserName; string m_strUserName;
static unordered_map<string, string> g_mapUser; static unordered_map<string, string> g_mapUser;
static string g_serverName;
}; };
} /* namespace Shell */ } /* namespace Shell */

View File

@ -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){ void createPusher(const string &app,const string &stream,const string &url){
//创建推流器并绑定一个RtmpMediaSource //创建推流器并绑定一个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) { pusher->setOnShutdown([app,stream, url](const SockException &ex) {
WarnL << "Server connection is closed:" << ex.getErrCode() << " " << ex.what(); WarnL << "Server connection is closed:" << ex.getErrCode() << " " << ex.what();
@ -95,11 +95,11 @@ int domain(int argc, const char *argv[]) {
//拉一个流生成一个RtmpMediaSource源的名称是"app/stream" //拉一个流生成一个RtmpMediaSource源的名称是"app/stream"
//你也可以以其他方式生成RtmpMediaSource比如说MP4文件请查看test_rtmpPusherMp4.cpp代码 //你也可以以其他方式生成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()); player->play(playUrl.data());
//监听RtmpMediaSource注册事件,在PlayerProxy播放成功后触发 //监听RtmpMediaSource注册事件,在PlayerProxy播放成功后触发
NoticeCenter::Instance().addListener(nullptr, Config::Broadcast::kBroadcastRtmpSrcRegisted, [pushUrl](BroadcastRtmpSrcRegistedArgs) { NoticeCenter::Instance().addListener(nullptr, Config::Broadcast::kBroadcastMediaChanged, [pushUrl](BroadcastMediaChangedArgs) {
//媒体源"app/stream"已经注册这时方可新建一个RtmpPusher对象并绑定该媒体源 //媒体源"app/stream"已经注册这时方可新建一个RtmpPusher对象并绑定该媒体源
createPusher(app,stream,pushUrl); createPusher(app,stream,pushUrl);
}); });

View File

@ -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){ 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){ if(!rtmpSrc){
//文件不存在 //文件不存在
WarnL << "MP4 file not exited!"; WarnL << "MP4 file not exited!";

View File

@ -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 //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 //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 //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时有效) //指定RTP over TCP(播放rtsp时有效)
(*player)[RtspPlayer::kRtpType] = PlayerBase::RTP_TCP; (*player)[RtspPlayer::kRtpType] = PlayerBase::RTP_TCP;
//开始播放,如果播放失败或者播放中止,将会自动重试若干次,重试次数在配置文件中配置,默认一直重试 //开始播放,如果播放失败或者播放中止,将会自动重试若干次,重试次数在配置文件中配置,默认一直重试