Commit bd72a69d by xiongziliang

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

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