mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-10-30 16:27:36 +08:00
统一成员变量命名风格
This commit is contained in:
parent
97567ec36d
commit
39baaebc55
@ -48,17 +48,17 @@ AACEncoder::AACEncoder() {
|
||||
}
|
||||
|
||||
AACEncoder::~AACEncoder() {
|
||||
if (m_hEncoder != nullptr) {
|
||||
faacEncClose(m_hEncoder);
|
||||
m_hEncoder = nullptr;
|
||||
if (_hEncoder != nullptr) {
|
||||
faacEncClose(_hEncoder);
|
||||
_hEncoder = nullptr;
|
||||
}
|
||||
if (m_pucAacBuf != nullptr) {
|
||||
delete[] m_pucAacBuf;
|
||||
m_pucAacBuf = nullptr;
|
||||
if (_pucAacBuf != nullptr) {
|
||||
delete[] _pucAacBuf;
|
||||
_pucAacBuf = nullptr;
|
||||
}
|
||||
if (m_pucPcmBuf != nullptr) {
|
||||
delete[] m_pucPcmBuf;
|
||||
m_pucPcmBuf = nullptr;
|
||||
if (_pucPcmBuf != nullptr) {
|
||||
delete[] _pucPcmBuf;
|
||||
_pucPcmBuf = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,19 +67,19 @@ bool AACEncoder::init(int iSampleRate, int iChannels, int iSampleBit) {
|
||||
return false;
|
||||
}
|
||||
// (1) Open FAAC engine
|
||||
m_hEncoder = faacEncOpen(iSampleRate, iChannels, &m_ulInputSamples,
|
||||
&m_ulMaxOutputBytes);
|
||||
if (m_hEncoder == NULL) {
|
||||
_hEncoder = faacEncOpen(iSampleRate, iChannels, &_ulInputSamples,
|
||||
&_ulMaxOutputBytes);
|
||||
if (_hEncoder == NULL) {
|
||||
return false;
|
||||
}
|
||||
m_pucAacBuf = new unsigned char[m_ulMaxOutputBytes];
|
||||
m_ulMaxInputBytes = m_ulInputSamples * iSampleBit / 8;
|
||||
m_pucPcmBuf = new unsigned char[m_ulMaxInputBytes * 4];
|
||||
_pucAacBuf = new unsigned char[_ulMaxOutputBytes];
|
||||
_ulMaxInputBytes = _ulInputSamples * iSampleBit / 8;
|
||||
_pucPcmBuf = new unsigned char[_ulMaxInputBytes * 4];
|
||||
|
||||
// (2.1) Get current encoding configuration
|
||||
faacEncConfigurationPtr pConfiguration = faacEncGetCurrentConfiguration(m_hEncoder);
|
||||
faacEncConfigurationPtr pConfiguration = faacEncGetCurrentConfiguration(_hEncoder);
|
||||
if (pConfiguration == NULL) {
|
||||
faacEncClose(m_hEncoder);
|
||||
faacEncClose(_hEncoder);
|
||||
return false;
|
||||
}
|
||||
pConfiguration->aacObjectType =LOW;
|
||||
@ -95,25 +95,25 @@ bool AACEncoder::init(int iSampleRate, int iChannels, int iSampleBit) {
|
||||
pConfiguration->inputFormat = FAAC_INPUT_16BIT;
|
||||
|
||||
// (2.2) Set encoding configuration
|
||||
if(!faacEncSetConfiguration(m_hEncoder, pConfiguration)){
|
||||
if(!faacEncSetConfiguration(_hEncoder, pConfiguration)){
|
||||
ErrorL << "faacEncSetConfiguration failed";
|
||||
faacEncClose(m_hEncoder);
|
||||
faacEncClose(_hEncoder);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int AACEncoder::inputData(char *pcPcmBufr, int iLen, unsigned char **ppucOutBuffer) {
|
||||
memcpy(m_pucPcmBuf + m_uiPcmLen, pcPcmBufr, iLen);
|
||||
m_uiPcmLen += iLen;
|
||||
if (m_uiPcmLen < m_ulMaxInputBytes) {
|
||||
memcpy(_pucPcmBuf + _uiPcmLen, pcPcmBufr, iLen);
|
||||
_uiPcmLen += iLen;
|
||||
if (_uiPcmLen < _ulMaxInputBytes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nRet = faacEncEncode(m_hEncoder, (int32_t *) (m_pucPcmBuf), m_ulInputSamples, m_pucAacBuf, m_ulMaxOutputBytes);
|
||||
m_uiPcmLen -= m_ulMaxInputBytes;
|
||||
memmove(m_pucPcmBuf, m_pucPcmBuf + m_ulMaxInputBytes, m_uiPcmLen);
|
||||
*ppucOutBuffer = m_pucAacBuf;
|
||||
int nRet = faacEncEncode(_hEncoder, (int32_t *) (_pucPcmBuf), _ulInputSamples, _pucAacBuf, _ulMaxOutputBytes);
|
||||
_uiPcmLen -= _ulMaxInputBytes;
|
||||
memmove(_pucPcmBuf, _pucPcmBuf + _ulMaxInputBytes, _uiPcmLen);
|
||||
*ppucOutBuffer = _pucAacBuf;
|
||||
return nRet;
|
||||
}
|
||||
|
||||
|
@ -39,15 +39,15 @@ public:
|
||||
int inputData(char *pcData, int iLen, unsigned char **ppucOutBuffer);
|
||||
|
||||
private:
|
||||
unsigned char *m_pucPcmBuf = nullptr;
|
||||
unsigned int m_uiPcmLen = 0;
|
||||
unsigned char *_pucPcmBuf = nullptr;
|
||||
unsigned int _uiPcmLen = 0;
|
||||
|
||||
unsigned char *m_pucAacBuf = nullptr;
|
||||
void *m_hEncoder = nullptr;
|
||||
unsigned char *_pucAacBuf = nullptr;
|
||||
void *_hEncoder = nullptr;
|
||||
|
||||
unsigned long m_ulInputSamples = 0;
|
||||
unsigned long m_ulMaxInputBytes = 0;
|
||||
unsigned long m_ulMaxOutputBytes = 0;
|
||||
unsigned long _ulInputSamples = 0;
|
||||
unsigned long _ulMaxInputBytes = 0;
|
||||
unsigned long _ulMaxOutputBytes = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -39,19 +39,19 @@ H264Encoder::H264Encoder() {
|
||||
|
||||
H264Encoder::~H264Encoder() {
|
||||
//* 清除图像区域
|
||||
if (m_pPicIn) {
|
||||
delete m_pPicIn;
|
||||
m_pPicIn = nullptr;
|
||||
if (_pPicIn) {
|
||||
delete _pPicIn;
|
||||
_pPicIn = nullptr;
|
||||
}
|
||||
if (m_pPicOut) {
|
||||
delete m_pPicOut;
|
||||
m_pPicOut = nullptr;
|
||||
if (_pPicOut) {
|
||||
delete _pPicOut;
|
||||
_pPicOut = nullptr;
|
||||
}
|
||||
|
||||
//* 关闭编码器句柄
|
||||
if (m_pX264Handle) {
|
||||
x264_encoder_close(m_pX264Handle);
|
||||
m_pX264Handle = nullptr;
|
||||
if (_pX264Handle) {
|
||||
x264_encoder_close(_pX264Handle);
|
||||
_pX264Handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +229,7 @@ Value的值就是fps。
|
||||
} x264_param_t;*/
|
||||
|
||||
bool H264Encoder::init(int iWidth, int iHeight, int iFps) {
|
||||
if (m_pX264Handle) {
|
||||
if (_pX264Handle) {
|
||||
return true;
|
||||
}
|
||||
x264_param_t X264Param, *pX264Param = &X264Param;
|
||||
@ -307,43 +307,43 @@ bool H264Encoder::init(int iWidth, int iHeight, int iFps) {
|
||||
|
||||
//* 打开编码器句柄,通过x264_encoder_parameters得到设置给X264
|
||||
//* 的参数.通过x264_encoder_reconfig更新X264的参数
|
||||
m_pX264Handle = x264_encoder_open(pX264Param);
|
||||
if (!m_pX264Handle) {
|
||||
_pX264Handle = x264_encoder_open(pX264Param);
|
||||
if (!_pX264Handle) {
|
||||
return false;
|
||||
}
|
||||
m_pPicIn = new x264_picture_t;
|
||||
m_pPicOut = new x264_picture_t;
|
||||
x264_picture_init(m_pPicIn);
|
||||
x264_picture_init(m_pPicOut);
|
||||
m_pPicIn->img.i_csp = X264_CSP_I420;
|
||||
m_pPicIn->img.i_plane = 3;
|
||||
_pPicIn = new x264_picture_t;
|
||||
_pPicOut = new x264_picture_t;
|
||||
x264_picture_init(_pPicIn);
|
||||
x264_picture_init(_pPicOut);
|
||||
_pPicIn->img.i_csp = X264_CSP_I420;
|
||||
_pPicIn->img.i_plane = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
int H264Encoder::inputData(char* apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame** ppFrame) {
|
||||
//TimeTicker1(5);
|
||||
m_pPicIn->img.i_stride[0] = aiYuvLen[0];
|
||||
m_pPicIn->img.i_stride[1] = aiYuvLen[1];
|
||||
m_pPicIn->img.i_stride[2] = aiYuvLen[2];
|
||||
m_pPicIn->img.plane[0] = (uint8_t *) apcYuv[0];
|
||||
m_pPicIn->img.plane[1] = (uint8_t *) apcYuv[1];
|
||||
m_pPicIn->img.plane[2] = (uint8_t *) apcYuv[2];
|
||||
m_pPicIn->i_pts = i64Pts;
|
||||
_pPicIn->img.i_stride[0] = aiYuvLen[0];
|
||||
_pPicIn->img.i_stride[1] = aiYuvLen[1];
|
||||
_pPicIn->img.i_stride[2] = aiYuvLen[2];
|
||||
_pPicIn->img.plane[0] = (uint8_t *) apcYuv[0];
|
||||
_pPicIn->img.plane[1] = (uint8_t *) apcYuv[1];
|
||||
_pPicIn->img.plane[2] = (uint8_t *) apcYuv[2];
|
||||
_pPicIn->i_pts = i64Pts;
|
||||
int iNal;
|
||||
x264_nal_t* pNals;
|
||||
|
||||
int iResult = x264_encoder_encode(m_pX264Handle, &pNals, &iNal, m_pPicIn,
|
||||
m_pPicOut);
|
||||
int iResult = x264_encoder_encode(_pX264Handle, &pNals, &iNal, _pPicIn,
|
||||
_pPicOut);
|
||||
if (iResult <= 0) {
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < iNal; i++) {
|
||||
x264_nal_t pNal = pNals[i];
|
||||
m_aFrames[i].iType = pNal.i_type;
|
||||
m_aFrames[i].iLength = pNal.i_payload;
|
||||
m_aFrames[i].pucData = pNal.p_payload;
|
||||
_aFrames[i].iType = pNal.i_type;
|
||||
_aFrames[i].iLength = pNal.i_payload;
|
||||
_aFrames[i].pucData = pNal.p_payload;
|
||||
}
|
||||
*ppFrame = m_aFrames;
|
||||
*ppFrame = _aFrames;
|
||||
return iNal;
|
||||
}
|
||||
|
||||
|
@ -54,10 +54,10 @@ public:
|
||||
bool init(int iWidth, int iHeight, int iFps);
|
||||
int inputData(char *apcYuv[3], int aiYuvLen[3], int64_t i64Pts, H264Frame **ppFrame);
|
||||
private:
|
||||
x264_t* m_pX264Handle = nullptr;
|
||||
x264_picture_t* m_pPicIn = nullptr;
|
||||
x264_picture_t* m_pPicOut = nullptr;
|
||||
H264Frame m_aFrames[10];
|
||||
x264_t* _pX264Handle = nullptr;
|
||||
x264_picture_t* _pPicIn = nullptr;
|
||||
x264_picture_t* _pPicOut = nullptr;
|
||||
H264Frame _aFrames[10];
|
||||
};
|
||||
|
||||
} /* namespace Codec */
|
||||
|
@ -77,16 +77,16 @@ MediaSource::Ptr MediaSource::find(
|
||||
bool MediaSource::regist() {
|
||||
//注册该源,注册后服务器才能找到该源
|
||||
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
|
||||
auto pr = g_mapMediaSrc[m_strSchema][m_strVhost][m_strApp].emplace(m_strId,shared_from_this());
|
||||
auto pr = g_mapMediaSrc[_strSchema][_strVhost][_strApp].emplace(_strId,shared_from_this());
|
||||
auto success = pr.second;
|
||||
if(success){
|
||||
InfoL << m_strSchema << " " << m_strVhost << " " << m_strApp << " " << m_strId;
|
||||
InfoL << _strSchema << " " << _strVhost << " " << _strApp << " " << _strId;
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaChanged,
|
||||
true,
|
||||
m_strSchema,
|
||||
m_strVhost,
|
||||
m_strApp,
|
||||
m_strId,
|
||||
_strSchema,
|
||||
_strVhost,
|
||||
_strApp,
|
||||
_strId,
|
||||
*this);
|
||||
}
|
||||
return success;
|
||||
@ -94,7 +94,7 @@ bool MediaSource::regist() {
|
||||
bool MediaSource::unregist() {
|
||||
//反注册该源
|
||||
lock_guard<recursive_mutex> lock(g_mtxMediaSrc);
|
||||
return searchMedia(m_strSchema, m_strVhost, m_strApp, m_strId, [&](SchemaVhostAppStreamMap::iterator &it0 ,
|
||||
return searchMedia(_strSchema, _strVhost, _strApp, _strId, [&](SchemaVhostAppStreamMap::iterator &it0 ,
|
||||
VhostAppStreamMap::iterator &it1,
|
||||
AppStreamMap::iterator &it2,
|
||||
StreamMap::iterator &it3){
|
||||
@ -110,13 +110,13 @@ bool MediaSource::unregist() {
|
||||
});
|
||||
}
|
||||
void MediaSource::unregisted(){
|
||||
InfoL << "" << m_strSchema << " " << m_strVhost << " " << m_strApp << " " << m_strId;
|
||||
InfoL << "" << _strSchema << " " << _strVhost << " " << _strApp << " " << _strId;
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaChanged,
|
||||
false,
|
||||
m_strSchema,
|
||||
m_strVhost,
|
||||
m_strApp,
|
||||
m_strId,
|
||||
_strSchema,
|
||||
_strVhost,
|
||||
_strApp,
|
||||
_strId,
|
||||
*this);
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ void MediaInfo::parse(const string &url){
|
||||
//string url = "rtsp://127.0.0.1:8554/live/id?key=val&a=1&&b=2&vhost=vhost.com";
|
||||
auto schema_pos = url.find("://");
|
||||
if(schema_pos != string::npos){
|
||||
m_schema = url.substr(0,schema_pos);
|
||||
_schema = url.substr(0,schema_pos);
|
||||
}else{
|
||||
schema_pos = -3;
|
||||
}
|
||||
@ -133,14 +133,14 @@ void MediaInfo::parse(const string &url){
|
||||
auto vhost = split_vec[0];
|
||||
auto pos = vhost.find(":");
|
||||
if(pos != string::npos){
|
||||
m_host = m_vhost = vhost.substr(0,pos);
|
||||
m_port = vhost.substr(pos + 1);
|
||||
_host = _vhost = vhost.substr(0,pos);
|
||||
_port = vhost.substr(pos + 1);
|
||||
} else{
|
||||
m_host = m_vhost = vhost;
|
||||
_host = _vhost = vhost;
|
||||
}
|
||||
}
|
||||
if(split_vec.size() > 1){
|
||||
m_app = split_vec[1];
|
||||
_app = split_vec[1];
|
||||
}
|
||||
if(split_vec.size() > 2){
|
||||
string steamid;
|
||||
@ -152,23 +152,23 @@ void MediaInfo::parse(const string &url){
|
||||
}
|
||||
auto pos = steamid.find("?");
|
||||
if(pos != string::npos){
|
||||
m_streamid = steamid.substr(0,pos);
|
||||
m_param_strs = steamid.substr(pos + 1);
|
||||
m_params = Parser::parseArgs(m_param_strs);
|
||||
if(m_params.find(VHOST_KEY) != m_params.end()){
|
||||
m_vhost = m_params[VHOST_KEY];
|
||||
_streamid = steamid.substr(0,pos);
|
||||
_para_strs = steamid.substr(pos + 1);
|
||||
_params = Parser::parseArgs(_para_strs);
|
||||
if(_params.find(VHOST_KEY) != _params.end()){
|
||||
_vhost = _params[VHOST_KEY];
|
||||
}
|
||||
} else{
|
||||
m_streamid = steamid;
|
||||
_streamid = steamid;
|
||||
}
|
||||
}
|
||||
if(m_vhost.empty()){
|
||||
if(_vhost.empty()){
|
||||
//无效vhost
|
||||
m_vhost = DEFAULT_VHOST;
|
||||
_vhost = DEFAULT_VHOST;
|
||||
}else{
|
||||
if(INADDR_NONE != inet_addr(m_vhost.data())){
|
||||
if(INADDR_NONE != inet_addr(_vhost.data())){
|
||||
//这是ip,未指定vhost;使用默认vhost
|
||||
m_vhost = DEFAULT_VHOST;
|
||||
_vhost = DEFAULT_VHOST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,17 +77,17 @@ public:
|
||||
void parse(const string &url);
|
||||
|
||||
string &operator[](const string &key){
|
||||
return m_params[key];
|
||||
return _params[key];
|
||||
}
|
||||
public:
|
||||
string m_schema;
|
||||
string m_host;
|
||||
string m_port;
|
||||
string m_vhost;
|
||||
string m_app;
|
||||
string m_streamid;
|
||||
StrCaseMap m_params;
|
||||
string m_param_strs;
|
||||
string _schema;
|
||||
string _host;
|
||||
string _port;
|
||||
string _vhost;
|
||||
string _app;
|
||||
string _streamid;
|
||||
StrCaseMap _params;
|
||||
string _para_strs;
|
||||
|
||||
};
|
||||
|
||||
@ -104,13 +104,13 @@ public:
|
||||
const string &strVhost,
|
||||
const string &strApp,
|
||||
const string &strId) :
|
||||
m_strSchema(strSchema),
|
||||
m_strApp(strApp),
|
||||
m_strId(strId) {
|
||||
_strSchema(strSchema),
|
||||
_strApp(strApp),
|
||||
_strId(strId) {
|
||||
if(strVhost.empty()){
|
||||
m_strVhost = DEFAULT_VHOST;
|
||||
_strVhost = DEFAULT_VHOST;
|
||||
}else{
|
||||
m_strVhost = strVhost;
|
||||
_strVhost = strVhost;
|
||||
}
|
||||
}
|
||||
virtual ~MediaSource() {
|
||||
@ -124,21 +124,21 @@ public:
|
||||
bool bMake = true) ;
|
||||
|
||||
const string& getSchema() const {
|
||||
return m_strSchema;
|
||||
return _strSchema;
|
||||
}
|
||||
const string& getVhost() const {
|
||||
return m_strVhost;
|
||||
return _strVhost;
|
||||
}
|
||||
const string& getApp() const {
|
||||
//获取该源的id
|
||||
return m_strApp;
|
||||
return _strApp;
|
||||
}
|
||||
const string& getId() const {
|
||||
return m_strId;
|
||||
return _strId;
|
||||
}
|
||||
|
||||
bool seekTo(uint32_t ui32Stamp) {
|
||||
auto listener = m_listener.lock();
|
||||
auto listener = _listener.lock();
|
||||
if(!listener){
|
||||
return false;
|
||||
}
|
||||
@ -146,21 +146,21 @@ public:
|
||||
}
|
||||
|
||||
uint32_t getStamp() {
|
||||
auto listener = m_listener.lock();
|
||||
auto listener = _listener.lock();
|
||||
if(!listener){
|
||||
return 0;
|
||||
}
|
||||
return listener->getStamp();
|
||||
}
|
||||
bool shutDown() {
|
||||
auto listener = m_listener.lock();
|
||||
auto listener = _listener.lock();
|
||||
if(!listener){
|
||||
return false;
|
||||
}
|
||||
return listener->shutDown();
|
||||
}
|
||||
void setListener(const std::weak_ptr<MediaSourceEvent> &listener){
|
||||
m_listener = listener;
|
||||
_listener = listener;
|
||||
}
|
||||
|
||||
template <typename FUN>
|
||||
@ -224,12 +224,12 @@ private:
|
||||
|
||||
void unregisted();
|
||||
protected:
|
||||
std::weak_ptr<MediaSourceEvent> m_listener;
|
||||
std::weak_ptr<MediaSourceEvent> _listener;
|
||||
private:
|
||||
string m_strSchema;//协议类型
|
||||
string m_strVhost; //vhost
|
||||
string m_strApp; //媒体app
|
||||
string m_strId; //媒体id
|
||||
string _strSchema;//协议类型
|
||||
string _strVhost; //vhost
|
||||
string _strApp; //媒体app
|
||||
string _strId; //媒体id
|
||||
static SchemaVhostAppStreamMap g_mapMediaSrc; //静态的媒体源表
|
||||
static recursive_mutex g_mtxMediaSrc; //访问静态的媒体源表的互斥锁
|
||||
};
|
||||
|
@ -44,19 +44,19 @@ DevChannel::DevChannel(const char *strVhost,
|
||||
bool bEnableMp4 ) :
|
||||
RtspToRtmpMediaSource(strVhost,strApp,strId,bEanbleHls,bEnableMp4) {
|
||||
|
||||
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";
|
||||
_strSdp = "v=0\r\n";
|
||||
_strSdp += "o=- 1383190487994921 1 IN IP4 0.0.0.0\r\n";
|
||||
_strSdp += "s=RTSP Session, streamed by the ZL\r\n";
|
||||
_strSdp += "i=ZL Live Stream\r\n";
|
||||
_strSdp += "c=IN IP4 0.0.0.0\r\n";
|
||||
_strSdp += "t=0 0\r\n";
|
||||
//直播,时间长度永远
|
||||
if(fDuration <= 0){
|
||||
m_strSdp += "a=range:npt=0-\r\n";
|
||||
_strSdp += "a=range:npt=0-\r\n";
|
||||
}else{
|
||||
m_strSdp += StrPrinter <<"a=range:npt=0-" << fDuration << "\r\n" << endl;
|
||||
_strSdp += StrPrinter <<"a=range:npt=0-" << fDuration << "\r\n" << endl;
|
||||
}
|
||||
m_strSdp += "a=control:*\r\n";
|
||||
_strSdp += "a=control:*\r\n";
|
||||
}
|
||||
DevChannel::~DevChannel() {
|
||||
}
|
||||
@ -64,16 +64,16 @@ DevChannel::~DevChannel() {
|
||||
#ifdef ENABLE_X264
|
||||
void DevChannel::inputYUV(char* apcYuv[3], int aiYuvLen[3], uint32_t uiStamp) {
|
||||
//TimeTicker1(50);
|
||||
if (!m_pH264Enc) {
|
||||
m_pH264Enc.reset(new H264Encoder());
|
||||
if (!m_pH264Enc->init(m_video->iWidth, m_video->iHeight, m_video->iFrameRate)) {
|
||||
m_pH264Enc.reset();
|
||||
if (!_pH264Enc) {
|
||||
_pH264Enc.reset(new H264Encoder());
|
||||
if (!_pH264Enc->init(_video->iWidth, _video->iHeight, _video->iFrameRate)) {
|
||||
_pH264Enc.reset();
|
||||
WarnL << "H264Encoder init failed!";
|
||||
}
|
||||
}
|
||||
if (m_pH264Enc) {
|
||||
if (_pH264Enc) {
|
||||
H264Encoder::H264Frame *pOut;
|
||||
int iFrames = m_pH264Enc->inputData(apcYuv, aiYuvLen, uiStamp, &pOut);
|
||||
int iFrames = _pH264Enc->inputData(apcYuv, aiYuvLen, uiStamp, &pOut);
|
||||
for (int i = 0; i < iFrames; i++) {
|
||||
inputH264((char *) pOut[i].pucData, pOut[i].iLength, uiStamp);
|
||||
}
|
||||
@ -83,16 +83,16 @@ void DevChannel::inputYUV(char* apcYuv[3], int aiYuvLen[3], uint32_t uiStamp) {
|
||||
|
||||
#ifdef ENABLE_FAAC
|
||||
void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) {
|
||||
if (!m_pAacEnc) {
|
||||
m_pAacEnc.reset(new AACEncoder());
|
||||
if (!m_pAacEnc->init(m_audio->iSampleRate, m_audio->iChannel, m_audio->iSampleBit)) {
|
||||
m_pAacEnc.reset();
|
||||
if (!_pAacEnc) {
|
||||
_pAacEnc.reset(new AACEncoder());
|
||||
if (!_pAacEnc->init(_audio->iSampleRate, _audio->iChannel, _audio->iSampleBit)) {
|
||||
_pAacEnc.reset();
|
||||
WarnL << "AACEncoder init failed!";
|
||||
}
|
||||
}
|
||||
if (m_pAacEnc) {
|
||||
if (_pAacEnc) {
|
||||
unsigned char *pucOut;
|
||||
int iRet = m_pAacEnc->inputData(pcData, iDataLen, &pucOut);
|
||||
int iRet = _pAacEnc->inputData(pcData, iDataLen, &pucOut);
|
||||
if (iRet > 0) {
|
||||
inputAAC((char *) pucOut, iRet, uiStamp);
|
||||
}
|
||||
@ -101,16 +101,16 @@ void DevChannel::inputPCM(char* pcData, int iDataLen, uint32_t uiStamp) {
|
||||
#endif //ENABLE_FAAC
|
||||
|
||||
void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t uiStamp) {
|
||||
if (!m_pRtpMaker_h264) {
|
||||
if (!_pRtpMaker_h264) {
|
||||
uint32_t ui32Ssrc;
|
||||
memcpy(&ui32Ssrc, makeRandStr(4, false).data(), 4);
|
||||
auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) {
|
||||
onGetRTP(pkt,bKeyPos);
|
||||
};
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,videoMtu,Config::Rtp::kVideoMtuSize);
|
||||
m_pRtpMaker_h264.reset(new RtpMaker_H264(lam, ui32Ssrc,videoMtu));
|
||||
_pRtpMaker_h264.reset(new RtpMaker_H264(lam, ui32Ssrc,videoMtu));
|
||||
}
|
||||
if (!m_bSdp_gotH264 && m_video) {
|
||||
if (!_bSdp_gotH264 && _video) {
|
||||
makeSDP_264((unsigned char*) pcData, iDataLen);
|
||||
}
|
||||
int iOffset = 4;
|
||||
@ -118,38 +118,38 @@ void DevChannel::inputH264(const char* pcData, int iDataLen, uint32_t uiStamp) {
|
||||
iOffset = 3;
|
||||
}
|
||||
if(uiStamp == 0){
|
||||
uiStamp = (uint32_t)m_aTicker[0].elapsedTime();
|
||||
uiStamp = (uint32_t)_aTicker[0].elapsedTime();
|
||||
}
|
||||
m_pRtpMaker_h264->makeRtp(pcData + iOffset, iDataLen - iOffset, uiStamp);
|
||||
_pRtpMaker_h264->makeRtp(pcData + iOffset, iDataLen - iOffset, uiStamp);
|
||||
}
|
||||
|
||||
void DevChannel::inputAAC(const char* pcData, int iDataLen, uint32_t uiStamp,bool withAdtsHeader) {
|
||||
if(withAdtsHeader){
|
||||
inputAAC(pcData+7,iDataLen-7,uiStamp,pcData);
|
||||
} else if(m_pAdtsHeader){
|
||||
m_pAdtsHeader->aac_frame_length = iDataLen;
|
||||
writeAdtsHeader(*m_pAdtsHeader,(uint8_t *)m_pAdtsHeader->buffer);
|
||||
inputAAC(pcData,iDataLen,uiStamp,(const char *)m_pAdtsHeader->buffer);
|
||||
} else if(_pAdtsHeader){
|
||||
_pAdtsHeader->aac_frame_length = iDataLen;
|
||||
writeAdtsHeader(*_pAdtsHeader,(uint8_t *)_pAdtsHeader->buffer);
|
||||
inputAAC(pcData,iDataLen,uiStamp,(const char *)_pAdtsHeader->buffer);
|
||||
}
|
||||
}
|
||||
void DevChannel::inputAAC(const char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp,const char *pcAdtsHeader){
|
||||
if (!m_pRtpMaker_aac) {
|
||||
if (!_pRtpMaker_aac) {
|
||||
uint32_t ssrc;
|
||||
memcpy(&ssrc, makeRandStr(8, false).data() + 4, 4);
|
||||
auto lam = [this](const RtpPacket::Ptr &pkt, bool keyPos) {
|
||||
onGetRTP(pkt,keyPos);
|
||||
};
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,audioMtu,Config::Rtp::kAudioMtuSize);
|
||||
m_pRtpMaker_aac.reset(new RtpMaker_AAC(lam, ssrc, audioMtu,m_audio->iSampleRate));
|
||||
_pRtpMaker_aac.reset(new RtpMaker_AAC(lam, ssrc, audioMtu,_audio->iSampleRate));
|
||||
}
|
||||
if (!m_bSdp_gotAAC && m_audio && pcAdtsHeader) {
|
||||
if (!_bSdp_gotAAC && _audio && pcAdtsHeader) {
|
||||
makeSDP_AAC((unsigned char*) pcAdtsHeader);
|
||||
}
|
||||
if(uiStamp == 0){
|
||||
uiStamp = (uint32_t)m_aTicker[1].elapsedTime();
|
||||
uiStamp = (uint32_t)_aTicker[1].elapsedTime();
|
||||
}
|
||||
if(pcDataWithoutAdts && iDataLen){
|
||||
m_pRtpMaker_aac->makeRtp(pcDataWithoutAdts, iDataLen, uiStamp);
|
||||
_pRtpMaker_aac->makeRtp(pcDataWithoutAdts, iDataLen, uiStamp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,77 +161,77 @@ inline void DevChannel::makeSDP_264(unsigned char *pcData, int iDataLen) {
|
||||
switch (pcData[offset] & 0x1F) {
|
||||
case 7:/*SPS frame*/
|
||||
{
|
||||
if (m_uiSPSLen != 0) {
|
||||
if (_uiSPSLen != 0) {
|
||||
break;
|
||||
}
|
||||
memcpy(m_aucSPS, pcData + offset, iDataLen - offset);
|
||||
m_uiSPSLen = iDataLen - offset;
|
||||
memcpy(_aucSPS, pcData + offset, iDataLen - offset);
|
||||
_uiSPSLen = iDataLen - offset;
|
||||
}
|
||||
break;
|
||||
case 8:/*PPS frame*/
|
||||
{
|
||||
if (m_uiPPSLen != 0) {
|
||||
if (_uiPPSLen != 0) {
|
||||
break;
|
||||
}
|
||||
memcpy(m_aucPPS, pcData + offset, iDataLen - offset);
|
||||
m_uiPPSLen = iDataLen - offset;
|
||||
memcpy(_aucPPS, pcData + offset, iDataLen - offset);
|
||||
_uiPPSLen = iDataLen - offset;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!m_uiSPSLen || !m_uiPPSLen) {
|
||||
if (!_uiSPSLen || !_uiPPSLen) {
|
||||
return;
|
||||
}
|
||||
|
||||
char acTmp[256];
|
||||
int profile_level_id = 0;
|
||||
if (m_uiSPSLen >= 4) { // sanity check
|
||||
profile_level_id = (m_aucSPS[1] << 16) | (m_aucSPS[2] << 8) | m_aucSPS[3]; // profile_idc|constraint_setN_flag|level_idc
|
||||
if (_uiSPSLen >= 4) { // sanity check
|
||||
profile_level_id = (_aucSPS[1] << 16) | (_aucSPS[2] << 8) | _aucSPS[3]; // profile_idc|constraint_setN_flag|level_idc
|
||||
}
|
||||
|
||||
//视频通道
|
||||
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()
|
||||
<< " H264/" << m_pRtpMaker_h264->getSampleRate() << "\r\n" << endl;
|
||||
m_strSdp += StrPrinter << "a=fmtp:" << m_pRtpMaker_h264->getPlayloadType()
|
||||
_strSdp += StrPrinter << "m=video 0 RTP/AVP "
|
||||
<< _pRtpMaker_h264->getPlayloadType() << "\r\n" << endl;
|
||||
_strSdp += "b=AS:5100\r\n";
|
||||
_strSdp += StrPrinter << "a=rtpmap:" << _pRtpMaker_h264->getPlayloadType()
|
||||
<< " H264/" << _pRtpMaker_h264->getSampleRate() << "\r\n" << endl;
|
||||
_strSdp += StrPrinter << "a=fmtp:" << _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=";
|
||||
_strSdp += acTmp;
|
||||
_strSdp += ";sprop-parameter-sets=";
|
||||
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 *) _aucSPS, _uiSPSLen);
|
||||
//WarnL<<"SPS base64:"<<strTemp;
|
||||
//WarnL<<"SPS hexdump:"<<hexdump(SPS_BUF, SPS_LEN);
|
||||
m_strSdp += acTmp;
|
||||
m_strSdp += ",";
|
||||
_strSdp += acTmp;
|
||||
_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";
|
||||
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_pRtpMaker_h264->getPlayloadType() << " " << endl;
|
||||
m_strSdp += StrPrinter << m_video->iWidth << endl;
|
||||
m_strSdp += "-";
|
||||
m_strSdp += StrPrinter << m_video->iHeight << endl;
|
||||
m_strSdp += "\r\n";
|
||||
av_base64_encode(acTmp, sizeof(acTmp), (uint8_t *) _aucPPS, _uiPPSLen);
|
||||
_strSdp += acTmp;
|
||||
_strSdp += "\r\n";
|
||||
if (_video->iFrameRate > 0 && _video->iHeight > 0 && _video->iWidth > 0) {
|
||||
_strSdp += "a=framerate:";
|
||||
_strSdp += StrPrinter << _video->iFrameRate << endl;
|
||||
_strSdp += StrPrinter << "\r\na=framesize:"
|
||||
<< _pRtpMaker_h264->getPlayloadType() << " " << endl;
|
||||
_strSdp += StrPrinter << _video->iWidth << endl;
|
||||
_strSdp += "-";
|
||||
_strSdp += StrPrinter << _video->iHeight << endl;
|
||||
_strSdp += "\r\n";
|
||||
}
|
||||
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);
|
||||
_strSdp += StrPrinter << "a=control:trackID="
|
||||
<< _pRtpMaker_h264->getInterleaved() / 2 << "\r\n" << endl;
|
||||
_bSdp_gotH264 = true;
|
||||
if (_audio) {
|
||||
if (_bSdp_gotAAC) {
|
||||
makeSDP(_strSdp);
|
||||
}
|
||||
} else {
|
||||
makeSDP(m_strSdp);
|
||||
makeSDP(_strSdp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,27 +244,27 @@ 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_pRtpMaker_aac->getPlayloadType() << "\r\n" << endl;
|
||||
m_strSdp += "b=AS:96\r\n";
|
||||
m_strSdp += StrPrinter << "a=rtpmap:" << m_pRtpMaker_aac->getPlayloadType()
|
||||
<< " MPEG4-GENERIC/" << m_pRtpMaker_aac->getSampleRate() << "\r\n"
|
||||
_strSdp += StrPrinter << "m=audio 0 RTP/AVP "
|
||||
<< _pRtpMaker_aac->getPlayloadType() << "\r\n" << endl;
|
||||
_strSdp += "b=AS:96\r\n";
|
||||
_strSdp += StrPrinter << "a=rtpmap:" << _pRtpMaker_aac->getPlayloadType()
|
||||
<< " MPEG4-GENERIC/" << _pRtpMaker_aac->getSampleRate() << "\r\n"
|
||||
<< endl;
|
||||
m_strSdp += StrPrinter << "a=fmtp:" << m_pRtpMaker_aac->getPlayloadType()
|
||||
_strSdp += StrPrinter << "a=fmtp:" << _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_pRtpMaker_aac->getInterleaved() / 2 << "\r\n" << endl;
|
||||
_strSdp += fConfigStr;
|
||||
_strSdp += "\r\n";
|
||||
_strSdp += StrPrinter << "a=control:trackID="
|
||||
<< _pRtpMaker_aac->getInterleaved() / 2 << "\r\n" << endl;
|
||||
|
||||
m_bSdp_gotAAC = true;
|
||||
if (m_video) {
|
||||
if (m_bSdp_gotH264) {
|
||||
makeSDP(m_strSdp);
|
||||
_bSdp_gotAAC = true;
|
||||
if (_video) {
|
||||
if (_bSdp_gotH264) {
|
||||
makeSDP(_strSdp);
|
||||
}
|
||||
} else {
|
||||
makeSDP(m_strSdp);
|
||||
makeSDP(_strSdp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,35 +273,35 @@ void DevChannel::makeSDP(const string& strSdp) {
|
||||
}
|
||||
|
||||
void DevChannel::initVideo(const VideoInfo& info) {
|
||||
m_video.reset(new VideoInfo(info));
|
||||
_video.reset(new VideoInfo(info));
|
||||
}
|
||||
|
||||
void DevChannel::initAudio(const AudioInfo& info) {
|
||||
m_audio.reset(new AudioInfo(info));
|
||||
m_pAdtsHeader = std::make_shared<AACFrame>();
|
||||
_audio.reset(new AudioInfo(info));
|
||||
_pAdtsHeader = std::make_shared<AACFrame>();
|
||||
|
||||
m_pAdtsHeader->syncword = 0x0FFF;
|
||||
m_pAdtsHeader->id = 0;
|
||||
m_pAdtsHeader->layer = 0;
|
||||
m_pAdtsHeader->protection_absent = 1;
|
||||
m_pAdtsHeader->profile = info.iProfile;//audioObjectType - 1;
|
||||
_pAdtsHeader->syncword = 0x0FFF;
|
||||
_pAdtsHeader->id = 0;
|
||||
_pAdtsHeader->layer = 0;
|
||||
_pAdtsHeader->protection_absent = 1;
|
||||
_pAdtsHeader->profile = info.iProfile;//audioObjectType - 1;
|
||||
int i = 0;
|
||||
for(auto rate : samplingFrequencyTable){
|
||||
if(rate == info.iSampleRate){
|
||||
m_pAdtsHeader->sf_index = i;
|
||||
_pAdtsHeader->sf_index = i;
|
||||
};
|
||||
++i;
|
||||
}
|
||||
|
||||
m_pAdtsHeader->private_bit = 0;
|
||||
m_pAdtsHeader->channel_configuration = info.iChannel;
|
||||
m_pAdtsHeader->original = 0;
|
||||
m_pAdtsHeader->home = 0;
|
||||
m_pAdtsHeader->copyright_identification_bit = 0;
|
||||
m_pAdtsHeader->copyright_identification_start = 0;
|
||||
m_pAdtsHeader->aac_frame_length = 7;
|
||||
m_pAdtsHeader->adts_buffer_fullness = 2047;
|
||||
m_pAdtsHeader->no_raw_data_blocks_in_frame = 0;
|
||||
_pAdtsHeader->private_bit = 0;
|
||||
_pAdtsHeader->channel_configuration = info.iChannel;
|
||||
_pAdtsHeader->original = 0;
|
||||
_pAdtsHeader->home = 0;
|
||||
_pAdtsHeader->copyright_identification_bit = 0;
|
||||
_pAdtsHeader->copyright_identification_start = 0;
|
||||
_pAdtsHeader->aac_frame_length = 7;
|
||||
_pAdtsHeader->adts_buffer_fullness = 2047;
|
||||
_pAdtsHeader->no_raw_data_blocks_in_frame = 0;
|
||||
|
||||
}
|
||||
} /* namespace DEV */
|
||||
|
@ -102,25 +102,25 @@ private:
|
||||
inline void makeSDP_AAC(unsigned char *pucData);
|
||||
inline void makeSDP(const string& strSdp);
|
||||
#ifdef ENABLE_X264
|
||||
std::shared_ptr<H264Encoder> m_pH264Enc;
|
||||
std::shared_ptr<H264Encoder> _pH264Enc;
|
||||
#endif //ENABLE_X264
|
||||
|
||||
#ifdef ENABLE_FAAC
|
||||
std::shared_ptr<AACEncoder> m_pAacEnc;
|
||||
std::shared_ptr<AACEncoder> _pAacEnc;
|
||||
#endif //ENABLE_FAAC
|
||||
RtpMaker_AAC::Ptr m_pRtpMaker_aac;
|
||||
RtpMaker_H264::Ptr m_pRtpMaker_h264;
|
||||
bool m_bSdp_gotH264 = false;
|
||||
bool m_bSdp_gotAAC = false;
|
||||
RtpMaker_AAC::Ptr _pRtpMaker_aac;
|
||||
RtpMaker_H264::Ptr _pRtpMaker_h264;
|
||||
bool _bSdp_gotH264 = false;
|
||||
bool _bSdp_gotAAC = false;
|
||||
|
||||
unsigned char m_aucSPS[256];
|
||||
unsigned int m_uiSPSLen = 0;
|
||||
unsigned char m_aucPPS[256];
|
||||
unsigned int m_uiPPSLen = 0;
|
||||
std::shared_ptr<VideoInfo> m_video;
|
||||
std::shared_ptr<AudioInfo> m_audio;
|
||||
SmoothTicker m_aTicker[2];
|
||||
std::shared_ptr<AACFrame> m_pAdtsHeader;
|
||||
unsigned char _aucSPS[256];
|
||||
unsigned int _uiSPSLen = 0;
|
||||
unsigned char _aucPPS[256];
|
||||
unsigned int _uiPPSLen = 0;
|
||||
std::shared_ptr<VideoInfo> _video;
|
||||
std::shared_ptr<AudioInfo> _audio;
|
||||
SmoothTicker _aTicker[2];
|
||||
std::shared_ptr<AACFrame> _pAdtsHeader;
|
||||
};
|
||||
|
||||
|
||||
|
@ -74,12 +74,12 @@ PlayerProxy::PlayerProxy(const char *strVhost,
|
||||
bool bEnableHls,
|
||||
bool bEnableMp4,
|
||||
int iRetryCount){
|
||||
m_strVhost = strVhost;
|
||||
m_strApp = strApp;
|
||||
m_strSrc = strSrc;
|
||||
m_bEnableHls = bEnableHls;
|
||||
m_bEnableMp4 = bEnableMp4;
|
||||
m_iRetryCount = iRetryCount;
|
||||
_strVhost = strVhost;
|
||||
_strApp = strApp;
|
||||
_strSrc = strSrc;
|
||||
_bEnableHls = bEnableHls;
|
||||
_bEnableMp4 = bEnableMp4;
|
||||
_iRetryCount = iRetryCount;
|
||||
}
|
||||
void PlayerProxy::play(const char* strUrl) {
|
||||
weak_ptr<PlayerProxy> weakSelf = shared_from_this();
|
||||
@ -90,9 +90,9 @@ void PlayerProxy::play(const char* strUrl) {
|
||||
// if(!strongSelf){
|
||||
// return;
|
||||
// }
|
||||
// if(strongSelf->m_pChn){
|
||||
// strongSelf->m_pChn->inputH264((char *)data.data(), data.size(), data.timeStamp);
|
||||
// if(!strongSelf->m_haveAudio){
|
||||
// if(strongSelf->_pChn){
|
||||
// strongSelf->_pChn->inputH264((char *)data.data(), data.size(), data.timeStamp);
|
||||
// if(!strongSelf->_haveAudio){
|
||||
// strongSelf->makeMuteAudio(data.timeStamp);
|
||||
// }
|
||||
// }else{
|
||||
@ -104,8 +104,8 @@ void PlayerProxy::play(const char* strUrl) {
|
||||
// if(!strongSelf){
|
||||
// return;
|
||||
// }
|
||||
// if(strongSelf->m_pChn){
|
||||
// strongSelf->m_pChn->inputAAC((char *)data.data(), data.size(), data.timeStamp);
|
||||
// if(strongSelf->_pChn){
|
||||
// strongSelf->_pChn->inputAAC((char *)data.data(), data.size(), data.timeStamp);
|
||||
// }else{
|
||||
// strongSelf->initMedia();
|
||||
// }
|
||||
@ -121,7 +121,7 @@ void PlayerProxy::play(const char* strUrl) {
|
||||
if(!err) {
|
||||
// 播放成功
|
||||
*piFailedCnt = 0;//连续播放失败次数清0
|
||||
}else if(*piFailedCnt < strongSelf->m_iRetryCount || strongSelf->m_iRetryCount < 0) {
|
||||
}else if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) {
|
||||
// 播放失败,延时重试播放
|
||||
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
|
||||
}
|
||||
@ -131,11 +131,11 @@ void PlayerProxy::play(const char* strUrl) {
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
}
|
||||
if(strongSelf->m_pChn) {
|
||||
strongSelf->m_pChn.reset();
|
||||
if(strongSelf->_pChn) {
|
||||
strongSelf->_pChn.reset();
|
||||
}
|
||||
//播放异常中断,延时重试播放
|
||||
if(*piFailedCnt < strongSelf->m_iRetryCount || strongSelf->m_iRetryCount < 0) {
|
||||
if(*piFailedCnt < strongSelf->_iRetryCount || strongSelf->_iRetryCount < 0) {
|
||||
strongSelf->rePlay(strUrlTmp,(*piFailedCnt)++);
|
||||
}
|
||||
});
|
||||
@ -166,8 +166,8 @@ void PlayerProxy::initMedia() {
|
||||
if (!isInited()) {
|
||||
return;
|
||||
}
|
||||
m_pChn.reset(new DevChannel(m_strVhost.data(),m_strApp.data(),m_strSrc.data(),getDuration(),m_bEnableHls,m_bEnableMp4));
|
||||
m_pChn->setListener(shared_from_this());
|
||||
_pChn.reset(new DevChannel(_strVhost.data(),_strApp.data(),_strSrc.data(),getDuration(),_bEnableHls,_bEnableMp4));
|
||||
_pChn->setListener(shared_from_this());
|
||||
|
||||
//todo(xzl) 修复此处
|
||||
|
||||
@ -176,22 +176,22 @@ void PlayerProxy::initMedia() {
|
||||
// info.iFrameRate = getVideoFps();
|
||||
// info.iWidth = getVideoWidth();
|
||||
// info.iHeight = getVideoHeight();
|
||||
// m_pChn->initVideo(info);
|
||||
// _pChn->initVideo(info);
|
||||
// }
|
||||
//
|
||||
// m_haveAudio = containAudio();
|
||||
// _haveAudio = containAudio();
|
||||
// if (containAudio()) {
|
||||
// AudioInfo info;
|
||||
// info.iSampleRate = getAudioSampleRate();
|
||||
// info.iChannel = getAudioChannel();
|
||||
// info.iSampleBit = getAudioSampleBit();
|
||||
// m_pChn->initAudio(info);
|
||||
// _pChn->initAudio(info);
|
||||
// }else{
|
||||
// AudioInfo info;
|
||||
// info.iSampleRate = MUTE_ADTS_SAMPLE_RATE;
|
||||
// info.iChannel = MUTE_ADTS_CHN_CNT;
|
||||
// info.iSampleBit = MUTE_ADTS_SAMPLE_BIT;
|
||||
// m_pChn->initAudio(info);
|
||||
// _pChn->initAudio(info);
|
||||
// }
|
||||
}
|
||||
bool PlayerProxy::shutDown() {
|
||||
@ -202,7 +202,7 @@ bool PlayerProxy::shutDown() {
|
||||
executor->async_first([weakSlef]() {
|
||||
auto stronSelf = weakSlef.lock();
|
||||
if (stronSelf) {
|
||||
stronSelf->m_pChn.reset();
|
||||
stronSelf->_pChn.reset();
|
||||
stronSelf->teardown();
|
||||
}
|
||||
});
|
||||
@ -212,10 +212,10 @@ bool PlayerProxy::shutDown() {
|
||||
|
||||
void PlayerProxy::makeMuteAudio(uint32_t stamp) {
|
||||
auto iAudioIndex = stamp / MUTE_ADTS_DATA_MS;
|
||||
if(m_iAudioIndex != iAudioIndex){
|
||||
m_iAudioIndex = iAudioIndex;
|
||||
m_pChn->inputAAC((char *)MUTE_ADTS_DATA,MUTE_ADTS_DATA_LEN, m_iAudioIndex * MUTE_ADTS_DATA_MS);
|
||||
//DebugL << m_iAudioIndex * MUTE_ADTS_DATA_MS << " " << stamp;
|
||||
if(_iAudioIndex != iAudioIndex){
|
||||
_iAudioIndex = iAudioIndex;
|
||||
_pChn->inputAAC((char *)MUTE_ADTS_DATA,MUTE_ADTS_DATA_LEN, _iAudioIndex * MUTE_ADTS_DATA_MS);
|
||||
//DebugL << _iAudioIndex * MUTE_ADTS_DATA_MS << " " << stamp;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,15 +60,15 @@ private:
|
||||
void rePlay(const string &strUrl,int iFailedCnt);
|
||||
void makeMuteAudio(uint32_t stamp);
|
||||
private:
|
||||
bool m_bEnableHls;
|
||||
bool m_bEnableMp4;
|
||||
int m_iRetryCount;
|
||||
DevChannel::Ptr m_pChn;
|
||||
string m_strVhost;
|
||||
string m_strApp;
|
||||
string m_strSrc;
|
||||
bool m_haveAudio = false;
|
||||
int m_iAudioIndex = 0;
|
||||
bool _bEnableHls;
|
||||
bool _bEnableMp4;
|
||||
int _iRetryCount;
|
||||
DevChannel::Ptr _pChn;
|
||||
string _strVhost;
|
||||
string _strApp;
|
||||
string _strSrc;
|
||||
bool _haveAudio = false;
|
||||
int _iAudioIndex = 0;
|
||||
};
|
||||
|
||||
} /* namespace Player */
|
||||
|
@ -37,19 +37,19 @@ H264Parser::~H264Parser(){
|
||||
}
|
||||
void H264Parser::inputH264(const string &h264,uint32_t dts){
|
||||
|
||||
m_parser.SetStream((const uint8_t *)h264.data(), h264.size());
|
||||
_parser.SetStream((const uint8_t *)h264.data(), h264.size());
|
||||
while (true) {
|
||||
if(media::H264Parser::kOk != m_parser.AdvanceToNextNALU(&m_nalu)){
|
||||
if(media::H264Parser::kOk != _parser.AdvanceToNextNALU(&_nalu)){
|
||||
break;
|
||||
}
|
||||
|
||||
switch (m_nalu.nal_unit_type) {
|
||||
switch (_nalu.nal_unit_type) {
|
||||
case media::H264NALU::kNonIDRSlice:
|
||||
case media::H264NALU::kIDRSlice:{
|
||||
if(media::H264Parser::kOk == m_parser.ParseSliceHeader(m_nalu, &m_shdr)){
|
||||
const media::H264SPS *pPps = m_parser.GetSPS(m_shdr.pic_parameter_set_id);
|
||||
if(media::H264Parser::kOk == _parser.ParseSliceHeader(_nalu, &_shdr)){
|
||||
const media::H264SPS *pPps = _parser.GetSPS(_shdr.pic_parameter_set_id);
|
||||
if (pPps) {
|
||||
m_poc.ComputePicOrderCnt(pPps, m_shdr, &m_iNowPOC);
|
||||
_poc.ComputePicOrderCnt(pPps, _shdr, &_iNowPOC);
|
||||
computePts(dts);
|
||||
}
|
||||
}
|
||||
@ -57,12 +57,12 @@ void H264Parser::inputH264(const string &h264,uint32_t dts){
|
||||
break;
|
||||
case media::H264NALU::kSPS:{
|
||||
int sps_id;
|
||||
m_parser.ParseSPS(&sps_id);
|
||||
_parser.ParseSPS(&sps_id);
|
||||
}
|
||||
break;
|
||||
case media::H264NALU::kPPS:{
|
||||
int pps_id;
|
||||
m_parser.ParsePPS(&pps_id);
|
||||
_parser.ParsePPS(&pps_id);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -72,33 +72,33 @@ void H264Parser::inputH264(const string &h264,uint32_t dts){
|
||||
}
|
||||
|
||||
void H264Parser::computePts(uint32_t iNowDTS) {
|
||||
auto iPOCInc = m_iNowPOC - m_iLastPOC;
|
||||
if (m_shdr.slice_type % 5 == 1) {
|
||||
auto iPOCInc = _iNowPOC - _iLastPOC;
|
||||
if (_shdr.slice_type % 5 == 1) {
|
||||
//这是B帧
|
||||
m_iNowPTS = m_iLastPTS + m_iMsPerPOC * (iPOCInc);
|
||||
_iNowPTS = _iLastPTS + _iMsPerPOC * (iPOCInc);
|
||||
} else {
|
||||
//这是I帧或者P帧
|
||||
m_iNowPTS = iNowDTS;
|
||||
_iNowPTS = iNowDTS;
|
||||
//计算每一POC的时间
|
||||
if(iPOCInc == 0){
|
||||
WarnL << "iPOCInc = 0," << m_iNowPOC << " " << m_iLastPOC;
|
||||
WarnL << "iPOCInc = 0," << _iNowPOC << " " << _iLastPOC;
|
||||
}else{
|
||||
m_iMsPerPOC = (m_iNowPTS - m_iLastPTS) / iPOCInc;
|
||||
_iMsPerPOC = (_iNowPTS - _iLastPTS) / iPOCInc;
|
||||
}
|
||||
m_iLastPTS = m_iNowPTS;
|
||||
m_iLastPOC = m_iNowPOC;
|
||||
_iLastPTS = _iNowPTS;
|
||||
_iLastPOC = _iNowPOC;
|
||||
}
|
||||
|
||||
|
||||
// DebugL << m_shdr.slice_type
|
||||
// DebugL << _shdr.slice_type
|
||||
// <<"\r\nNOW:"
|
||||
// << m_iNowPOC << " "
|
||||
// << m_iNowPTS << " "
|
||||
// << _iNowPOC << " "
|
||||
// << _iNowPTS << " "
|
||||
// << iNowDTS << " "
|
||||
// << "\r\nLST:"
|
||||
// << m_iLastPOC << " "
|
||||
// << m_iLastPTS << " "
|
||||
// << m_iMsPerPOC << endl;
|
||||
// << _iLastPOC << " "
|
||||
// << _iLastPTS << " "
|
||||
// << _iMsPerPOC << endl;
|
||||
|
||||
}
|
||||
|
||||
|
@ -44,29 +44,29 @@ public:
|
||||
void inputH264(const string &h264,uint32_t dts);
|
||||
|
||||
int32_t getPOC() const{
|
||||
return m_iNowPOC;
|
||||
return _iNowPOC;
|
||||
}
|
||||
int getSliceType() const{
|
||||
return m_shdr.slice_type;
|
||||
return _shdr.slice_type;
|
||||
}
|
||||
int getNaluType() const{
|
||||
return m_nalu.nal_unit_type;
|
||||
return _nalu.nal_unit_type;
|
||||
}
|
||||
uint32_t getPts() const{
|
||||
return m_iNowPTS;
|
||||
return _iNowPTS;
|
||||
}
|
||||
private:
|
||||
media::H264Parser m_parser;
|
||||
media::H264POC m_poc;
|
||||
media::H264NALU m_nalu;
|
||||
media::H264SliceHeader m_shdr;
|
||||
media::H264Parser _parser;
|
||||
media::H264POC _poc;
|
||||
media::H264NALU _nalu;
|
||||
media::H264SliceHeader _shdr;
|
||||
|
||||
int32_t m_iNowPOC = INT32_MAX;
|
||||
int32_t m_iLastPOC = INT32_MAX;
|
||||
int32_t _iNowPOC = INT32_MAX;
|
||||
int32_t _iLastPOC = INT32_MAX;
|
||||
|
||||
uint32_t m_iNowPTS = INT32_MAX;
|
||||
uint32_t m_iLastPTS = INT32_MAX;
|
||||
int32_t m_iMsPerPOC = 30;
|
||||
uint32_t _iNowPTS = INT32_MAX;
|
||||
uint32_t _iLastPTS = INT32_MAX;
|
||||
int32_t _iMsPerPOC = 30;
|
||||
|
||||
void computePts(uint32_t dts);
|
||||
|
||||
|
@ -110,7 +110,7 @@ HttpSession::HttpSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::P
|
||||
pSock->setSendTimeOutSecond(15);
|
||||
|
||||
GET_CONFIG_AND_REGISTER(string,rootPath,Config::Http::kRootPath);
|
||||
m_strPath = rootPath;
|
||||
_strPath = rootPath;
|
||||
}
|
||||
|
||||
HttpSession::~HttpSession() {
|
||||
@ -125,9 +125,9 @@ int64_t HttpSession::onRecvHeader(const char *header,uint64_t len) {
|
||||
g_mapCmdIndex.emplace("POST",&HttpSession::Handle_Req_POST);
|
||||
}, nullptr);
|
||||
|
||||
m_parser.Parse(header);
|
||||
urlDecode(m_parser);
|
||||
string cmd = m_parser.Method();
|
||||
_parser.Parse(header);
|
||||
urlDecode(_parser);
|
||||
string cmd = _parser.Method();
|
||||
auto it = g_mapCmdIndex.find(cmd);
|
||||
if (it == g_mapCmdIndex.end()) {
|
||||
WarnL << cmd;
|
||||
@ -143,15 +143,15 @@ int64_t HttpSession::onRecvHeader(const char *header,uint64_t len) {
|
||||
shutdown();
|
||||
}
|
||||
//清空解析器节省内存
|
||||
m_parser.Clear();
|
||||
_parser.Clear();
|
||||
//返回content长度
|
||||
return content_len;
|
||||
}
|
||||
|
||||
void HttpSession::onRecvContent(const char *data,uint64_t len) {
|
||||
if(m_contentCallBack){
|
||||
if(!m_contentCallBack(data,len)){
|
||||
m_contentCallBack = nullptr;
|
||||
if(_contentCallBack){
|
||||
if(!_contentCallBack(data,len)){
|
||||
_contentCallBack = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,7 +160,7 @@ void HttpSession::onRecv(const Buffer::Ptr &pBuf) {
|
||||
onRecv(pBuf->data(),pBuf->size());
|
||||
}
|
||||
void HttpSession::onRecv(const char *data,int size){
|
||||
m_ticker.resetTime();
|
||||
_ticker.resetTime();
|
||||
input(data,size);
|
||||
}
|
||||
|
||||
@ -168,11 +168,11 @@ void HttpSession::onError(const SockException& err) {
|
||||
//WarnL << err.what();
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,iFlowThreshold,Broadcast::kFlowThreshold);
|
||||
|
||||
if(m_ui64TotalBytes > iFlowThreshold * 1024){
|
||||
if(_ui64TotalBytes > iFlowThreshold * 1024){
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,
|
||||
m_mediaInfo,
|
||||
m_ui64TotalBytes,
|
||||
m_ticker.createdTime()/1000,
|
||||
_mediaInfo,
|
||||
_ui64TotalBytes,
|
||||
_ticker.createdTime()/1000,
|
||||
*this);
|
||||
}
|
||||
}
|
||||
@ -180,7 +180,7 @@ void HttpSession::onError(const SockException& err) {
|
||||
void HttpSession::onManager() {
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,keepAliveSec,Config::Http::kKeepAliveSecond);
|
||||
|
||||
if(m_ticker.elapsedTime() > keepAliveSec * 1000){
|
||||
if(_ticker.elapsedTime() > keepAliveSec * 1000){
|
||||
//1分钟超时
|
||||
WarnL<<"HttpSession timeouted!";
|
||||
shutdown();
|
||||
@ -189,7 +189,7 @@ void HttpSession::onManager() {
|
||||
|
||||
|
||||
inline bool HttpSession::checkWebSocket(){
|
||||
auto Sec_WebSocket_Key = m_parser["Sec-WebSocket-Key"];
|
||||
auto Sec_WebSocket_Key = _parser["Sec-WebSocket-Key"];
|
||||
if(Sec_WebSocket_Key.empty()){
|
||||
return false;
|
||||
}
|
||||
@ -205,7 +205,7 @@ inline bool HttpSession::checkWebSocket(){
|
||||
//http-flv 链接格式:http://vhost-url:port/app/streamid.flv?key1=value1&key2=value2
|
||||
//如果url(除去?以及后面的参数)后缀是.flv,那么表明该url是一个http-flv直播。
|
||||
inline bool HttpSession::checkLiveFlvStream(){
|
||||
auto pos = strrchr(m_parser.Url().data(),'.');
|
||||
auto pos = strrchr(_parser.Url().data(),'.');
|
||||
if(!pos){
|
||||
//未找到".flv"后缀
|
||||
return false;
|
||||
@ -215,11 +215,11 @@ inline bool HttpSession::checkLiveFlvStream(){
|
||||
return false;
|
||||
}
|
||||
//拼接成完整url
|
||||
auto fullUrl = string(HTTP_SCHEMA) + "://" + m_parser["Host"] + m_parser.FullUrl();
|
||||
m_mediaInfo.parse(fullUrl);
|
||||
m_mediaInfo.m_streamid.erase(m_mediaInfo.m_streamid.size() - 4);//去除.flv后缀
|
||||
auto fullUrl = string(HTTP_SCHEMA) + "://" + _parser["Host"] + _parser.FullUrl();
|
||||
_mediaInfo.parse(fullUrl);
|
||||
_mediaInfo._streamid.erase(_mediaInfo._streamid.size() - 4);//去除.flv后缀
|
||||
|
||||
auto mediaSrc = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,m_mediaInfo.m_vhost,m_mediaInfo.m_app,m_mediaInfo.m_streamid));
|
||||
auto mediaSrc = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,_mediaInfo._vhost,_mediaInfo._app,_mediaInfo._streamid));
|
||||
if(!mediaSrc){
|
||||
//该rtmp源不存在
|
||||
return false;
|
||||
@ -262,7 +262,7 @@ inline bool HttpSession::checkLiveFlvStream(){
|
||||
onRes(err);
|
||||
});
|
||||
};
|
||||
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,m_mediaInfo,invoker,*this);
|
||||
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,_mediaInfo,invoker,*this);
|
||||
if(!flag){
|
||||
//该事件无人监听,默认不鉴权
|
||||
onRes("");
|
||||
@ -273,10 +273,10 @@ inline bool HttpSession::Handle_Req_GET(int64_t &content_len) {
|
||||
//先看看是否为WebSocket请求
|
||||
if(checkWebSocket()){
|
||||
content_len = -1;
|
||||
auto parserCopy = m_parser;
|
||||
m_contentCallBack = [this,parserCopy](const char *data,uint64_t len){
|
||||
auto parserCopy = _parser;
|
||||
_contentCallBack = [this,parserCopy](const char *data,uint64_t len){
|
||||
onRecvWebSocketData(parserCopy,data,len);
|
||||
//m_contentCallBack是可持续的,后面还要处理后续数据
|
||||
//_contentCallBack是可持续的,后面还要处理后续数据
|
||||
return true;
|
||||
};
|
||||
return true;
|
||||
@ -293,19 +293,19 @@ inline bool HttpSession::Handle_Req_GET(int64_t &content_len) {
|
||||
}
|
||||
|
||||
//事件未被拦截,则认为是http下载请求
|
||||
auto fullUrl = string(HTTP_SCHEMA) + "://" + m_parser["Host"] + m_parser.FullUrl();
|
||||
m_mediaInfo.parse(fullUrl);
|
||||
auto fullUrl = string(HTTP_SCHEMA) + "://" + _parser["Host"] + _parser.FullUrl();
|
||||
_mediaInfo.parse(fullUrl);
|
||||
|
||||
string strFile = m_strPath + "/" + m_mediaInfo.m_vhost + m_parser.Url();
|
||||
string strFile = _strPath + "/" + _mediaInfo._vhost + _parser.Url();
|
||||
/////////////HTTP连接是否需要被关闭////////////////
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,reqCnt,Config::Http::kMaxReqCount);
|
||||
|
||||
bool bClose = (strcasecmp(m_parser["Connection"].data(),"close") == 0) || ( ++m_iReqCnt > reqCnt);
|
||||
bool bClose = (strcasecmp(_parser["Connection"].data(),"close") == 0) || ( ++_iReqCnt > reqCnt);
|
||||
//访问的是文件夹
|
||||
if (strFile.back() == '/') {
|
||||
//生成文件夹菜单索引
|
||||
string strMeun;
|
||||
if (!makeMeun(strFile,m_mediaInfo.m_vhost, strMeun)) {
|
||||
if (!makeMeun(strFile,_mediaInfo._vhost, strMeun)) {
|
||||
//文件夹不存在
|
||||
sendNotFound(bClose);
|
||||
return !bClose;
|
||||
@ -334,7 +334,7 @@ inline bool HttpSession::Handle_Req_GET(int64_t &content_len) {
|
||||
}
|
||||
|
||||
//判断是不是分节下载
|
||||
auto &strRange = m_parser["Range"];
|
||||
auto &strRange = _parser["Range"];
|
||||
int64_t iRangeStart = 0, iRangeEnd = 0;
|
||||
iRangeStart = atoll(FindField(strRange.data(), "bytes=", "-").data());
|
||||
iRangeEnd = atoll(FindField(strRange.data(), "-", "\r\n").data());
|
||||
@ -355,7 +355,7 @@ inline bool HttpSession::Handle_Req_GET(int64_t &content_len) {
|
||||
//分节下载返回Content-Range头
|
||||
httpHeader.emplace("Content-Range",StrPrinter<<"bytes " << iRangeStart << "-" << iRangeEnd << "/" << tFileStat.st_size<< endl);
|
||||
}
|
||||
auto Origin = m_parser["Origin"];
|
||||
auto Origin = _parser["Origin"];
|
||||
if(!Origin.empty()){
|
||||
httpHeader["Access-Control-Allow-Origin"] = Origin;
|
||||
httpHeader["Access-Control-Allow-Credentials"] = "true";
|
||||
@ -377,7 +377,7 @@ inline bool HttpSession::Handle_Req_GET(int64_t &content_len) {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
while(*piLeft && strongSelf){
|
||||
//更新超时定时器
|
||||
strongSelf->m_ticker.resetTime();
|
||||
strongSelf->_ticker.resetTime();
|
||||
//从循环池获取一个内存片
|
||||
auto sendBuf = strongSelf->obtainBuffer();
|
||||
sendBuf->setCapacity(sendBufSize);
|
||||
@ -449,7 +449,7 @@ inline bool HttpSession::makeMeun(const string &strFullPath,const string &vhost,
|
||||
"<h1>文件索引:";
|
||||
|
||||
string strPath = strFullPath;
|
||||
strPath = strPath.substr(m_strPath.length() + vhost.length() + 1);
|
||||
strPath = strPath.substr(_strPath.length() + vhost.length() + 1);
|
||||
strRet += strPath;
|
||||
strRet += "</h1>\r\n";
|
||||
if (strPath != "/") {
|
||||
@ -525,7 +525,7 @@ inline void HttpSession::sendResponse(const char* pcStatus, const KeyValue& head
|
||||
auto strSend = printer << endl;
|
||||
//DebugL << strSend;
|
||||
send(strSend);
|
||||
m_ticker.resetTime();
|
||||
_ticker.resetTime();
|
||||
}
|
||||
inline HttpSession::KeyValue HttpSession::makeHttpHeader(bool bClose, int64_t iContentSize,const char* pcContentType) {
|
||||
KeyValue headerOut;
|
||||
@ -563,7 +563,7 @@ string HttpSession::urlDecode(const string &str){
|
||||
|
||||
inline void HttpSession::urlDecode(Parser &parser){
|
||||
parser.setUrl(urlDecode(parser.Url()));
|
||||
for(auto &pr : m_parser.getUrlArgs()){
|
||||
for(auto &pr : _parser.getUrlArgs()){
|
||||
const_cast<string &>(pr.second) = urlDecode(pr.second);
|
||||
}
|
||||
}
|
||||
@ -572,8 +572,8 @@ inline bool HttpSession::emitHttpEvent(bool doInvoke){
|
||||
///////////////////是否断开本链接///////////////////////
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,reqCnt,Config::Http::kMaxReqCount);
|
||||
|
||||
bool bClose = (strcasecmp(m_parser["Connection"].data(),"close") == 0) || ( ++m_iReqCnt > reqCnt);
|
||||
auto Origin = m_parser["Origin"];
|
||||
bool bClose = (strcasecmp(_parser["Connection"].data(),"close") == 0) || ( ++_iReqCnt > reqCnt);
|
||||
auto Origin = _parser["Origin"];
|
||||
/////////////////////异步回复Invoker///////////////////////////////
|
||||
weak_ptr<HttpSession> weakSelf = dynamic_pointer_cast<HttpSession>(shared_from_this());
|
||||
HttpResponseInvoker invoker = [weakSelf,bClose,Origin](const string &codeOut, const KeyValue &headerOut, const string &contentOut){
|
||||
@ -594,7 +594,7 @@ inline bool HttpSession::emitHttpEvent(bool doInvoke){
|
||||
};
|
||||
///////////////////广播HTTP事件///////////////////////////
|
||||
bool consumed = false;//该事件是否被消费
|
||||
NoticeCenter::Instance().emitEvent(Config::Broadcast::kBroadcastHttpRequest,m_parser,invoker,consumed,*this);
|
||||
NoticeCenter::Instance().emitEvent(Config::Broadcast::kBroadcastHttpRequest,_parser,invoker,consumed,*this);
|
||||
if(!consumed && doInvoke){
|
||||
//该事件无人消费,所以返回404
|
||||
invoker("404 Not Found",KeyValue(),"");
|
||||
@ -609,7 +609,7 @@ inline bool HttpSession::Handle_Req_POST(int64_t &content_len) {
|
||||
GET_CONFIG_AND_REGISTER(uint64_t,maxReqSize,Config::Http::kMaxReqSize);
|
||||
GET_CONFIG_AND_REGISTER(int,maxReqCnt,Config::Http::kMaxReqCount);
|
||||
|
||||
int64_t totalContentLen = m_parser["Content-Length"].empty() ? -1 : atoll(m_parser["Content-Length"].data());
|
||||
int64_t totalContentLen = _parser["Content-Length"].empty() ? -1 : atoll(_parser["Content-Length"].data());
|
||||
|
||||
if(totalContentLen == 0){
|
||||
//content为空
|
||||
@ -621,34 +621,34 @@ inline bool HttpSession::Handle_Req_POST(int64_t &content_len) {
|
||||
if(totalContentLen > 0 && totalContentLen < maxReqSize ){
|
||||
//返回固定长度的content
|
||||
content_len = totalContentLen;
|
||||
auto parserCopy = m_parser;
|
||||
m_contentCallBack = [this,parserCopy](const char *data,uint64_t len){
|
||||
auto parserCopy = _parser;
|
||||
_contentCallBack = [this,parserCopy](const char *data,uint64_t len){
|
||||
//恢复http头
|
||||
m_parser = parserCopy;
|
||||
_parser = parserCopy;
|
||||
//设置content
|
||||
m_parser.setContent(string(data,len));
|
||||
_parser.setContent(string(data,len));
|
||||
//触发http事件,emitHttpEvent内部会选择是否关闭连接
|
||||
emitHttpEvent(true);
|
||||
//清空数据,节省内存
|
||||
m_parser.Clear();
|
||||
_parser.Clear();
|
||||
//content已经接收完毕
|
||||
return false;
|
||||
};
|
||||
}else{
|
||||
//返回不固定长度的content
|
||||
content_len = -1;
|
||||
auto parserCopy = m_parser;
|
||||
auto parserCopy = _parser;
|
||||
std::shared_ptr<uint64_t> recvedContentLen = std::make_shared<uint64_t>(0);
|
||||
bool bClose = (strcasecmp(m_parser["Connection"].data(),"close") == 0) || ( ++m_iReqCnt > maxReqCnt);
|
||||
bool bClose = (strcasecmp(_parser["Connection"].data(),"close") == 0) || ( ++_iReqCnt > maxReqCnt);
|
||||
|
||||
m_contentCallBack = [this,parserCopy,totalContentLen,recvedContentLen,bClose](const char *data,uint64_t len){
|
||||
_contentCallBack = [this,parserCopy,totalContentLen,recvedContentLen,bClose](const char *data,uint64_t len){
|
||||
*(recvedContentLen) += len;
|
||||
|
||||
onRecvUnlimitedContent(parserCopy,data,len,totalContentLen,*(recvedContentLen));
|
||||
|
||||
if(*(recvedContentLen) < totalContentLen){
|
||||
//数据还没接收完毕
|
||||
//m_contentCallBack是可持续的,后面还要处理后续content数据
|
||||
//_contentCallBack是可持续的,后面还要处理后续content数据
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -698,8 +698,8 @@ void HttpSession::onWrite(const Buffer::Ptr &buffer) {
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
}
|
||||
strongSelf->m_ticker.resetTime();
|
||||
strongSelf->m_ui64TotalBytes += buffer->size();
|
||||
strongSelf->_ticker.resetTime();
|
||||
strongSelf->_ui64TotalBytes += buffer->size();
|
||||
strongSelf->send(buffer);
|
||||
});
|
||||
}
|
||||
@ -714,8 +714,8 @@ void HttpSession::onWrite(const char *data, int len) {
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
}
|
||||
strongSelf->m_ticker.resetTime();
|
||||
strongSelf->m_ui64TotalBytes += buffer->size();
|
||||
strongSelf->_ticker.resetTime();
|
||||
strongSelf->_ui64TotalBytes += buffer->size();
|
||||
strongSelf->send(buffer);
|
||||
});
|
||||
}
|
||||
|
@ -101,16 +101,16 @@ protected:
|
||||
WebSocketSplitter::decode((uint8_t *)data,len);
|
||||
}
|
||||
private:
|
||||
Parser m_parser;
|
||||
string m_strPath;
|
||||
Ticker m_ticker;
|
||||
uint32_t m_iReqCnt = 0;
|
||||
Parser _parser;
|
||||
string _strPath;
|
||||
Ticker _ticker;
|
||||
uint32_t _iReqCnt = 0;
|
||||
//消耗的总流量
|
||||
uint64_t m_ui64TotalBytes = 0;
|
||||
uint64_t _ui64TotalBytes = 0;
|
||||
//flv over http
|
||||
MediaInfo m_mediaInfo;
|
||||
MediaInfo _mediaInfo;
|
||||
//处理content数据的callback
|
||||
function<bool (const char *data,uint64_t len) > m_contentCallBack;
|
||||
function<bool (const char *data,uint64_t len) > _contentCallBack;
|
||||
private:
|
||||
inline bool Handle_Req_GET(int64_t &content_len);
|
||||
inline bool Handle_Req_POST(int64_t &content_len);
|
||||
|
@ -40,14 +40,14 @@ class HttpsSession: public HttpSession {
|
||||
public:
|
||||
HttpsSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock):
|
||||
HttpSession(pTh,pSock){
|
||||
m_sslBox.setOnEncData([&](const char *data, uint32_t len){
|
||||
_sslBox.setOnEncData([&](const char *data, uint32_t len){
|
||||
#if defined(__GNUC__) && (__GNUC__ < 5)
|
||||
public_send(data,len);
|
||||
#else//defined(__GNUC__) && (__GNUC__ < 5)
|
||||
HttpSession::send(obtainBuffer(data,len));
|
||||
#endif//defined(__GNUC__) && (__GNUC__ < 5)
|
||||
});
|
||||
m_sslBox.setOnDecData([&](const char *data, uint32_t len){
|
||||
_sslBox.setOnDecData([&](const char *data, uint32_t len){
|
||||
#if defined(__GNUC__) && (__GNUC__ < 5)
|
||||
public_onRecv(data,len);
|
||||
#else//defined(__GNUC__) && (__GNUC__ < 5)
|
||||
@ -56,11 +56,11 @@ public:
|
||||
});
|
||||
}
|
||||
virtual ~HttpsSession(){
|
||||
//m_sslBox.shutdown();
|
||||
//_sslBox.shutdown();
|
||||
}
|
||||
void onRecv(const Buffer::Ptr &pBuf) override{
|
||||
TimeTicker();
|
||||
m_sslBox.onRecv(pBuf->data(), pBuf->size());
|
||||
_sslBox.onRecv(pBuf->data(), pBuf->size());
|
||||
}
|
||||
#if defined(__GNUC__) && (__GNUC__ < 5)
|
||||
int public_send(const char *data, uint32_t len){
|
||||
@ -73,10 +73,10 @@ public:
|
||||
protected:
|
||||
virtual int send(const Buffer::Ptr &buf) override{
|
||||
TimeTicker();
|
||||
m_sslBox.onSend(buf->data(), buf->size());
|
||||
_sslBox.onSend(buf->data(), buf->size());
|
||||
return buf->size();
|
||||
}
|
||||
SSL_Box m_sslBox;
|
||||
SSL_Box _sslBox;
|
||||
};
|
||||
|
||||
|
||||
|
@ -43,35 +43,35 @@ HLSMaker::HLSMaker(const string& strM3u8File,
|
||||
if(ui32Num < 1){
|
||||
ui32Num = 1;
|
||||
}
|
||||
m_ui32BufSize = ui32BufSize;
|
||||
m_ui64TsCnt = 0;
|
||||
m_strM3u8File = strM3u8File;
|
||||
m_ui32NumSegments = ui32Num;
|
||||
m_ui32SegmentDuration = ui32Duration;
|
||||
m_ui32LastStamp = 0;
|
||||
_ui32BufSize = ui32BufSize;
|
||||
_ui64TsCnt = 0;
|
||||
_strM3u8File = strM3u8File;
|
||||
_ui32NumSegments = ui32Num;
|
||||
_ui32SegmentDuration = ui32Duration;
|
||||
_ui32LastStamp = 0;
|
||||
|
||||
m_strOutputPrefix = strM3u8File.substr(0, strM3u8File.rfind('.'));
|
||||
m_strFileName = m_strOutputPrefix.substr(m_strOutputPrefix.rfind('/') + 1);
|
||||
m_ts.init(m_strOutputPrefix + "-0.ts", m_ui32BufSize);
|
||||
_strOutputPrefix = strM3u8File.substr(0, strM3u8File.rfind('.'));
|
||||
_strFileName = _strOutputPrefix.substr(_strOutputPrefix.rfind('/') + 1);
|
||||
_ts.init(_strOutputPrefix + "-0.ts", _ui32BufSize);
|
||||
}
|
||||
|
||||
|
||||
HLSMaker::~HLSMaker() {
|
||||
m_ts.clear();
|
||||
string strDir = m_strOutputPrefix.substr(0,m_strOutputPrefix.rfind('/'));
|
||||
_ts.clear();
|
||||
string strDir = _strOutputPrefix.substr(0,_strOutputPrefix.rfind('/'));
|
||||
File::delete_file(strDir.data());
|
||||
}
|
||||
|
||||
bool HLSMaker::write_index_file(int iFirstSegment, unsigned int uiLastSegment, int iEnd) {
|
||||
char acWriteBuf[1024];
|
||||
std::shared_ptr<FILE> pM3u8File(File::createfile_file(m_strM3u8File.data(), "w"),[](FILE *fp){
|
||||
std::shared_ptr<FILE> pM3u8File(File::createfile_file(_strM3u8File.data(), "w"),[](FILE *fp){
|
||||
if(fp){
|
||||
fflush(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
});
|
||||
if (!pM3u8File) {
|
||||
WarnL << "Could not open temporary m3u8 index file (" << m_strM3u8File << "), no index file will be created";
|
||||
WarnL << "Could not open temporary m3u8 index file (" << _strM3u8File << "), no index file will be created";
|
||||
return false;
|
||||
}
|
||||
if (iFirstSegment < 0) {
|
||||
@ -80,13 +80,13 @@ bool HLSMaker::write_index_file(int iFirstSegment, unsigned int uiLastSegment, i
|
||||
|
||||
//最少1秒
|
||||
int maxSegmentDuration = 0;
|
||||
for (auto dur : m_iDurations) {
|
||||
for (auto dur : _iDurations) {
|
||||
dur /=1000;
|
||||
if(dur > maxSegmentDuration){
|
||||
maxSegmentDuration = dur;
|
||||
}
|
||||
}
|
||||
if (m_ui32NumSegments) {
|
||||
if (_ui32NumSegments) {
|
||||
snprintf(acWriteBuf,
|
||||
sizeof(acWriteBuf),
|
||||
"#EXTM3U\r\n"
|
||||
@ -114,8 +114,8 @@ bool HLSMaker::write_index_file(int iFirstSegment, unsigned int uiLastSegment, i
|
||||
snprintf(acWriteBuf,
|
||||
sizeof(acWriteBuf),
|
||||
"#EXTINF:%.3f,\r\n%s-%u.ts\r\n",
|
||||
m_iDurations[i-iFirstSegment]/1000.0,
|
||||
m_strFileName.c_str(),
|
||||
_iDurations[i-iFirstSegment]/1000.0,
|
||||
_strFileName.c_str(),
|
||||
i);
|
||||
if (fwrite(acWriteBuf, strlen(acWriteBuf), 1, pM3u8File.get()) != 1) {
|
||||
WarnL << "Could not write to m3u8 index file, will not continue writing to index file";
|
||||
@ -134,36 +134,36 @@ bool HLSMaker::write_index_file(int iFirstSegment, unsigned int uiLastSegment, i
|
||||
}
|
||||
|
||||
void HLSMaker::inputH264(void *data, uint32_t length, uint32_t timeStamp, int type) {
|
||||
if(m_ui32LastStamp == 0){
|
||||
m_ui32LastStamp = timeStamp;
|
||||
if(_ui32LastStamp == 0){
|
||||
_ui32LastStamp = timeStamp;
|
||||
}
|
||||
int stampInc = timeStamp - m_ui32LastStamp;
|
||||
int stampInc = timeStamp - _ui32LastStamp;
|
||||
|
||||
switch (type) {
|
||||
case 7: //SPS
|
||||
if (stampInc >= m_ui32SegmentDuration * 1000) {
|
||||
m_ui32LastStamp = timeStamp;
|
||||
if (stampInc >= _ui32SegmentDuration * 1000) {
|
||||
_ui32LastStamp = timeStamp;
|
||||
//关闭文件
|
||||
m_ts.clear();
|
||||
auto strTmpFileName = StrPrinter << m_strOutputPrefix << '-' << (++m_ui64TsCnt) << ".ts" << endl;
|
||||
if (!m_ts.init(strTmpFileName, m_ui32BufSize)) {
|
||||
_ts.clear();
|
||||
auto strTmpFileName = StrPrinter << _strOutputPrefix << '-' << (++_ui64TsCnt) << ".ts" << endl;
|
||||
if (!_ts.init(strTmpFileName, _ui32BufSize)) {
|
||||
//创建文件失败
|
||||
return;
|
||||
}
|
||||
//记录切片时间
|
||||
m_iDurations.push_back(stampInc);
|
||||
_iDurations.push_back(stampInc);
|
||||
if(removets()){
|
||||
//删除老的时间戳
|
||||
m_iDurations.pop_front();
|
||||
_iDurations.pop_front();
|
||||
}
|
||||
write_index_file(m_ui64TsCnt - m_ui32NumSegments, m_ui64TsCnt, 0);
|
||||
write_index_file(_ui64TsCnt - _ui32NumSegments, _ui64TsCnt, 0);
|
||||
}
|
||||
case 1: //P
|
||||
//insert aud frame before p and SPS frame
|
||||
m_ts.inputH264("\x0\x0\x0\x1\x9\xf0", 6, timeStamp * 90);
|
||||
_ts.inputH264("\x0\x0\x0\x1\x9\xf0", 6, timeStamp * 90);
|
||||
case 5: //IDR
|
||||
case 8: //PPS
|
||||
m_ts.inputH264((char *) data, length, timeStamp * 90);
|
||||
_ts.inputH264((char *) data, length, timeStamp * 90);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -171,15 +171,15 @@ void HLSMaker::inputH264(void *data, uint32_t length, uint32_t timeStamp, int ty
|
||||
}
|
||||
|
||||
void HLSMaker::inputAAC(void *data, uint32_t length, uint32_t timeStamp) {
|
||||
m_ts.inputAAC((char *) data, length, timeStamp * 90);
|
||||
_ts.inputAAC((char *) data, length, timeStamp * 90);
|
||||
}
|
||||
|
||||
bool HLSMaker::removets() {
|
||||
if (m_ui64TsCnt < m_ui32NumSegments + 2) {
|
||||
if (_ui64TsCnt < _ui32NumSegments + 2) {
|
||||
return false;
|
||||
}
|
||||
File::delete_file((StrPrinter << m_strOutputPrefix << "-"
|
||||
<< m_ui64TsCnt - m_ui32NumSegments - 2
|
||||
File::delete_file((StrPrinter << _strOutputPrefix << "-"
|
||||
<< _ui64TsCnt - _ui32NumSegments - 2
|
||||
<< ".ts" << endl).data());
|
||||
return true;
|
||||
}
|
||||
|
@ -60,16 +60,16 @@ public:
|
||||
uint32_t ui32Length,
|
||||
uint32_t ui32TimeStamp);
|
||||
private:
|
||||
TSMaker m_ts;
|
||||
string m_strM3u8File;
|
||||
string m_strFileName;
|
||||
string m_strOutputPrefix;
|
||||
uint32_t m_ui32SegmentDuration;
|
||||
uint32_t m_ui32NumSegments;
|
||||
uint64_t m_ui64TsCnt;
|
||||
uint32_t m_ui32BufSize;
|
||||
uint32_t m_ui32LastStamp;
|
||||
std::deque<int> m_iDurations;
|
||||
TSMaker _ts;
|
||||
string _strM3u8File;
|
||||
string _strFileName;
|
||||
string _strOutputPrefix;
|
||||
uint32_t _ui32SegmentDuration;
|
||||
uint32_t _ui32NumSegments;
|
||||
uint64_t _ui64TsCnt;
|
||||
uint32_t _ui32BufSize;
|
||||
uint32_t _ui32LastStamp;
|
||||
std::deque<int> _iDurations;
|
||||
|
||||
bool write_index_file(int iFirstSegment, unsigned int uiLastSegment, int iEnd);
|
||||
bool removets();
|
||||
|
@ -41,21 +41,21 @@ MediaReader::MediaReader(const string &strVhost,const string &strApp, const stri
|
||||
|
||||
auto strFileName = recordPath + "/" + strVhost + "/" + strApp + "/" + strId;
|
||||
|
||||
m_hMP4File = MP4Read(strFileName.data());
|
||||
if(m_hMP4File == MP4_INVALID_FILE_HANDLE){
|
||||
_hMP4File = MP4Read(strFileName.data());
|
||||
if(_hMP4File == MP4_INVALID_FILE_HANDLE){
|
||||
throw runtime_error(StrPrinter << "打开MP4文件失败:" << strFileName << endl);
|
||||
}
|
||||
m_video_trId = MP4FindTrackId(m_hMP4File, 0, MP4_VIDEO_TRACK_TYPE, 0);
|
||||
if(m_video_trId != MP4_INVALID_TRACK_ID){
|
||||
if(strcmp(MP4GetTrackMediaDataName(m_hMP4File, m_video_trId),"avc1") ==0){
|
||||
auto m_video_timescale = MP4GetTrackTimeScale(m_hMP4File, m_video_trId);
|
||||
auto m_video_duration = MP4GetTrackDuration(m_hMP4File, m_video_trId);
|
||||
m_video_num_samples = MP4GetTrackNumberOfSamples(m_hMP4File, m_video_trId);
|
||||
m_video_sample_max_size = MP4GetTrackMaxSampleSize(m_hMP4File, m_video_trId);
|
||||
m_video_width = MP4GetTrackVideoWidth(m_hMP4File, m_video_trId);
|
||||
m_video_height = MP4GetTrackVideoHeight(m_hMP4File, m_video_trId);
|
||||
m_video_framerate = MP4GetTrackVideoFrameRate(m_hMP4File, m_video_trId);
|
||||
m_pcVideoSample = std::shared_ptr<uint8_t> (new uint8_t[m_video_sample_max_size],[](uint8_t *ptr){
|
||||
_video_trId = MP4FindTrackId(_hMP4File, 0, MP4_VIDEO_TRACK_TYPE, 0);
|
||||
if(_video_trId != MP4_INVALID_TRACK_ID){
|
||||
if(strcmp(MP4GetTrackMediaDataName(_hMP4File, _video_trId),"avc1") ==0){
|
||||
auto _video_timescale = MP4GetTrackTimeScale(_hMP4File, _video_trId);
|
||||
auto _video_duration = MP4GetTrackDuration(_hMP4File, _video_trId);
|
||||
_video_num_samples = MP4GetTrackNumberOfSamples(_hMP4File, _video_trId);
|
||||
_video_sample_max_size = MP4GetTrackMaxSampleSize(_hMP4File, _video_trId);
|
||||
_video_width = MP4GetTrackVideoWidth(_hMP4File, _video_trId);
|
||||
_video_height = MP4GetTrackVideoHeight(_hMP4File, _video_trId);
|
||||
_video_framerate = MP4GetTrackVideoFrameRate(_hMP4File, _video_trId);
|
||||
_pcVideoSample = std::shared_ptr<uint8_t> (new uint8_t[_video_sample_max_size],[](uint8_t *ptr){
|
||||
delete [] ptr;
|
||||
});
|
||||
uint8_t **seqheader;
|
||||
@ -63,106 +63,106 @@ MediaReader::MediaReader(const string &strVhost,const string &strApp, const stri
|
||||
uint32_t *pictheadersize;
|
||||
uint32_t *seqheadersize;
|
||||
uint32_t ix;
|
||||
if(MP4GetTrackH264SeqPictHeaders(m_hMP4File, m_video_trId, &seqheader, &seqheadersize, &pictheader, &pictheadersize)){
|
||||
if(MP4GetTrackH264SeqPictHeaders(_hMP4File, _video_trId, &seqheader, &seqheadersize, &pictheader, &pictheadersize)){
|
||||
for (ix = 0; seqheadersize[ix] != 0; ix++) {
|
||||
m_strSps.assign((char *)(seqheader[ix]), seqheadersize[ix]);
|
||||
_strSps.assign((char *)(seqheader[ix]), seqheadersize[ix]);
|
||||
float framerate;
|
||||
getAVCInfo(m_strSps, (int &)m_video_width, (int &)m_video_height, framerate);
|
||||
m_video_framerate = framerate;
|
||||
m_strSps = string("\x0\x0\x0\x1",4) + m_strSps;
|
||||
getAVCInfo(_strSps, (int &)_video_width, (int &)_video_height, framerate);
|
||||
_video_framerate = framerate;
|
||||
_strSps = string("\x0\x0\x0\x1",4) + _strSps;
|
||||
MP4Free(seqheader[ix]);
|
||||
}
|
||||
MP4Free(seqheader);
|
||||
MP4Free(seqheadersize);
|
||||
for (ix = 0; pictheadersize[ix] != 0; ix++) {
|
||||
m_strPps.assign("\x0\x0\x0\x1",4);
|
||||
m_strPps.append((char *)(pictheader[ix]), pictheadersize[ix]);
|
||||
_strPps.assign("\x0\x0\x0\x1",4);
|
||||
_strPps.append((char *)(pictheader[ix]), pictheadersize[ix]);
|
||||
MP4Free(pictheader[ix]);
|
||||
}
|
||||
MP4Free(pictheader);
|
||||
MP4Free(pictheadersize);
|
||||
}
|
||||
m_video_ms = 1000.0 * m_video_duration / m_video_timescale;
|
||||
_video_ms = 1000.0 * _video_duration / _video_timescale;
|
||||
/*InfoL << "\r\n"
|
||||
<< m_video_ms << "\r\n"
|
||||
<< m_video_num_samples << "\r\n"
|
||||
<< m_video_framerate << "\r\n"
|
||||
<< m_video_width << "\r\n"
|
||||
<< m_video_height << "\r\n";*/
|
||||
<< _video_ms << "\r\n"
|
||||
<< _video_num_samples << "\r\n"
|
||||
<< _video_framerate << "\r\n"
|
||||
<< _video_width << "\r\n"
|
||||
<< _video_height << "\r\n";*/
|
||||
} else {
|
||||
//如果不是h264,则忽略
|
||||
m_video_trId = MP4_INVALID_TRACK_ID;
|
||||
_video_trId = MP4_INVALID_TRACK_ID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_audio_trId = MP4FindTrackId(m_hMP4File, 0, MP4_AUDIO_TRACK_TYPE, 0);
|
||||
if (m_audio_trId != MP4_INVALID_TRACK_ID) {
|
||||
if (strcmp(MP4GetTrackMediaDataName(m_hMP4File, m_audio_trId), "mp4a") == 0) {
|
||||
m_audio_sample_rate = MP4GetTrackTimeScale(m_hMP4File, m_audio_trId);
|
||||
auto m_audio_duration = MP4GetTrackDuration(m_hMP4File, m_audio_trId);
|
||||
m_audio_num_samples = MP4GetTrackNumberOfSamples(m_hMP4File,m_audio_trId);
|
||||
m_audio_num_channels = MP4GetTrackAudioChannels(m_hMP4File, m_audio_trId);
|
||||
m_audio_sample_max_size = MP4GetTrackMaxSampleSize(m_hMP4File,m_audio_trId);
|
||||
_audio_trId = MP4FindTrackId(_hMP4File, 0, MP4_AUDIO_TRACK_TYPE, 0);
|
||||
if (_audio_trId != MP4_INVALID_TRACK_ID) {
|
||||
if (strcmp(MP4GetTrackMediaDataName(_hMP4File, _audio_trId), "mp4a") == 0) {
|
||||
_audio_sample_rate = MP4GetTrackTimeScale(_hMP4File, _audio_trId);
|
||||
auto _audio_duration = MP4GetTrackDuration(_hMP4File, _audio_trId);
|
||||
_audio_num_samples = MP4GetTrackNumberOfSamples(_hMP4File,_audio_trId);
|
||||
_audio_num_channels = MP4GetTrackAudioChannels(_hMP4File, _audio_trId);
|
||||
_audio_sample_max_size = MP4GetTrackMaxSampleSize(_hMP4File,_audio_trId);
|
||||
uint8_t *ppConfig;
|
||||
uint32_t pConfigSize;
|
||||
if(MP4GetTrackESConfiguration(m_hMP4File,m_audio_trId,&ppConfig,&pConfigSize)){
|
||||
m_strAacCfg.assign((char *)ppConfig, pConfigSize);
|
||||
makeAdtsHeader(m_strAacCfg, m_adts);
|
||||
writeAdtsHeader(m_adts,m_adts.buffer);
|
||||
getAACInfo(m_adts, (int &)m_audio_sample_rate, (int &)m_audio_num_channels);
|
||||
if(MP4GetTrackESConfiguration(_hMP4File,_audio_trId,&ppConfig,&pConfigSize)){
|
||||
_strAacCfg.assign((char *)ppConfig, pConfigSize);
|
||||
makeAdtsHeader(_strAacCfg, _adts);
|
||||
writeAdtsHeader(_adts,_adts.buffer);
|
||||
getAACInfo(_adts, (int &)_audio_sample_rate, (int &)_audio_num_channels);
|
||||
MP4Free(ppConfig);
|
||||
}
|
||||
m_audio_ms = 1000.0 * m_audio_duration / m_audio_sample_rate;
|
||||
_audio_ms = 1000.0 * _audio_duration / _audio_sample_rate;
|
||||
/*InfoL << "\r\n"
|
||||
<< m_audio_ms << "\r\n"
|
||||
<< m_audio_num_samples << "\r\n"
|
||||
<< m_audio_num_channels << "\r\n"
|
||||
<< m_audio_sample_rate << "\r\n";*/
|
||||
<< _audio_ms << "\r\n"
|
||||
<< _audio_num_samples << "\r\n"
|
||||
<< _audio_num_channels << "\r\n"
|
||||
<< _audio_sample_rate << "\r\n";*/
|
||||
}else{
|
||||
m_audio_trId = MP4_INVALID_TRACK_ID;
|
||||
_audio_trId = MP4_INVALID_TRACK_ID;
|
||||
}
|
||||
}
|
||||
if(m_audio_trId == MP4_INVALID_TRACK_ID && m_video_trId == MP4_INVALID_TRACK_ID){
|
||||
MP4Close(m_hMP4File);
|
||||
m_hMP4File = MP4_INVALID_FILE_HANDLE;
|
||||
if(_audio_trId == MP4_INVALID_TRACK_ID && _video_trId == MP4_INVALID_TRACK_ID){
|
||||
MP4Close(_hMP4File);
|
||||
_hMP4File = MP4_INVALID_FILE_HANDLE;
|
||||
throw runtime_error(StrPrinter << "该MP4文件音视频格式不支持:" << strFileName << endl);
|
||||
}
|
||||
|
||||
m_iDuration = MAX(m_video_ms,m_audio_ms);
|
||||
m_pChn.reset(new DevChannel(strVhost.data(),strApp.data(),strId.data(),m_iDuration/1000.0,false, false));
|
||||
if (m_audio_trId != MP4_INVALID_TRACK_ID) {
|
||||
_iDuration = MAX(_video_ms,_audio_ms);
|
||||
_pChn.reset(new DevChannel(strVhost.data(),strApp.data(),strId.data(),_iDuration/1000.0,false, false));
|
||||
if (_audio_trId != MP4_INVALID_TRACK_ID) {
|
||||
AudioInfo info;
|
||||
info.iChannel = m_audio_num_channels;
|
||||
info.iChannel = _audio_num_channels;
|
||||
info.iSampleBit = 16;
|
||||
info.iSampleRate = m_audio_sample_rate;
|
||||
m_pChn->initAudio(info);
|
||||
info.iSampleRate = _audio_sample_rate;
|
||||
_pChn->initAudio(info);
|
||||
}
|
||||
|
||||
if (m_video_trId != MP4_INVALID_TRACK_ID) {
|
||||
if (_video_trId != MP4_INVALID_TRACK_ID) {
|
||||
VideoInfo info;
|
||||
info.iFrameRate = m_video_framerate;
|
||||
info.iWidth = m_video_width;
|
||||
info.iHeight = m_video_height;
|
||||
m_pChn->initVideo(info);
|
||||
info.iFrameRate = _video_framerate;
|
||||
info.iWidth = _video_width;
|
||||
info.iHeight = _video_height;
|
||||
_pChn->initVideo(info);
|
||||
}
|
||||
|
||||
if (m_audio_trId != MP4_INVALID_TRACK_ID) {
|
||||
m_pChn->inputAAC((char *)m_adts.buffer, 7, 0);
|
||||
if (_audio_trId != MP4_INVALID_TRACK_ID) {
|
||||
_pChn->inputAAC((char *)_adts.buffer, 7, 0);
|
||||
}
|
||||
|
||||
if (m_video_trId != MP4_INVALID_TRACK_ID) {
|
||||
//m_pChn->initVideo(info);
|
||||
m_pChn->inputH264((char *) m_strSps.data(), m_strSps.size(), 0);
|
||||
m_pChn->inputH264((char *) m_strPps.data(), m_strPps.size(), 0);
|
||||
if (_video_trId != MP4_INVALID_TRACK_ID) {
|
||||
//_pChn->initVideo(info);
|
||||
_pChn->inputH264((char *) _strSps.data(), _strSps.size(), 0);
|
||||
_pChn->inputH264((char *) _strPps.data(), _strPps.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MediaReader::~MediaReader() {
|
||||
if (m_hMP4File != MP4_INVALID_FILE_HANDLE) {
|
||||
MP4Close(m_hMP4File);
|
||||
m_hMP4File = MP4_INVALID_FILE_HANDLE;
|
||||
if (_hMP4File != MP4_INVALID_FILE_HANDLE) {
|
||||
MP4Close(_hMP4File);
|
||||
_hMP4File = MP4_INVALID_FILE_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,14 +174,14 @@ void MediaReader::startReadMP4() {
|
||||
AsyncTaskThread::Instance().DoTaskDelay(reinterpret_cast<uint64_t>(this), sampleMS, [strongSelf](){
|
||||
return strongSelf->readSample();
|
||||
});
|
||||
m_pChn->setListener(strongSelf);
|
||||
_pChn->setListener(strongSelf);
|
||||
}
|
||||
bool MediaReader::seekTo(uint32_t ui32Stamp){
|
||||
seek(ui32Stamp);
|
||||
return true;
|
||||
}
|
||||
uint32_t MediaReader::getStamp() {
|
||||
return m_iSeekTime + m_ticker.elapsedTime();
|
||||
return _iSeekTime + _ticker.elapsedTime();
|
||||
}
|
||||
bool MediaReader::shutDown(){
|
||||
AsyncTaskThread::Instance().CancelTask(reinterpret_cast<uint64_t>(this));
|
||||
@ -190,25 +190,25 @@ bool MediaReader::shutDown(){
|
||||
|
||||
bool MediaReader::readSample(int iTimeInc) {
|
||||
TimeTicker();
|
||||
lock_guard<recursive_mutex> lck(m_mtx);
|
||||
lock_guard<recursive_mutex> lck(_mtx);
|
||||
auto bFlag0 = readVideoSample(iTimeInc);//数据没读完
|
||||
auto bFlag1 = readAudioSample(iTimeInc);//数据没读完
|
||||
auto bFlag2 = m_pChn->readerCount() > 0;//读取者大于0
|
||||
auto bFlag2 = _pChn->readerCount() > 0;//读取者大于0
|
||||
if((bFlag0 || bFlag1) && bFlag2){
|
||||
m_alive.resetTime();
|
||||
_alive.resetTime();
|
||||
}
|
||||
//DebugL << "alive ...";
|
||||
//3秒延时关闭
|
||||
return m_alive.elapsedTime() < 3 * 1000;
|
||||
return _alive.elapsedTime() < 3 * 1000;
|
||||
}
|
||||
inline bool MediaReader::readVideoSample(int iTimeInc) {
|
||||
if (m_video_trId != MP4_INVALID_TRACK_ID) {
|
||||
if (_video_trId != MP4_INVALID_TRACK_ID) {
|
||||
auto iNextSample = getVideoSampleId(iTimeInc);
|
||||
MP4SampleId iIdx = m_video_current;
|
||||
for (iIdx = m_video_current; iIdx < iNextSample; iIdx++) {
|
||||
uint8_t *pBytes = m_pcVideoSample.get();
|
||||
uint32_t numBytes = m_video_sample_max_size;
|
||||
if(MP4ReadSample(m_hMP4File, m_video_trId, iIdx + 1, &pBytes, &numBytes,NULL,NULL,NULL,&m_bSyncSample)){
|
||||
MP4SampleId iIdx = _video_current;
|
||||
for (iIdx = _video_current; iIdx < iNextSample; iIdx++) {
|
||||
uint8_t *pBytes = _pcVideoSample.get();
|
||||
uint32_t numBytes = _video_sample_max_size;
|
||||
if(MP4ReadSample(_hMP4File, _video_trId, iIdx + 1, &pBytes, &numBytes,NULL,NULL,NULL,&_bSyncSample)){
|
||||
if (!iTimeInc) {
|
||||
uint32_t iOffset = 0;
|
||||
while (iOffset < numBytes) {
|
||||
@ -219,97 +219,97 @@ inline bool MediaReader::readVideoSample(int iTimeInc) {
|
||||
break;
|
||||
}
|
||||
memcpy(pBytes + iOffset, "\x0\x0\x0\x1", 4);
|
||||
writeH264(pBytes + iOffset, iFrameLen + 4, (double) m_video_ms * iIdx / m_video_num_samples);
|
||||
writeH264(pBytes + iOffset, iFrameLen + 4, (double) _video_ms * iIdx / _video_num_samples);
|
||||
iOffset += (iFrameLen + 4);
|
||||
}
|
||||
}else if(m_bSyncSample){
|
||||
}else if(_bSyncSample){
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
ErrorL << "读取视频失败:" << iIdx + 1;
|
||||
}
|
||||
}
|
||||
m_video_current = iIdx;
|
||||
return m_video_current < m_video_num_samples;
|
||||
_video_current = iIdx;
|
||||
return _video_current < _video_num_samples;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool MediaReader::readAudioSample(int iTimeInc) {
|
||||
if (m_audio_trId != MP4_INVALID_TRACK_ID) {
|
||||
if (_audio_trId != MP4_INVALID_TRACK_ID) {
|
||||
auto iNextSample = getAudioSampleId(iTimeInc);
|
||||
for (auto i = m_audio_current; i < iNextSample; i++) {
|
||||
uint32_t numBytes = m_audio_sample_max_size;
|
||||
uint8_t *pBytes = m_adts.buffer + 7;
|
||||
if(MP4ReadSample(m_hMP4File, m_audio_trId, i + 1, &pBytes, &numBytes)){
|
||||
for (auto i = _audio_current; i < iNextSample; i++) {
|
||||
uint32_t numBytes = _audio_sample_max_size;
|
||||
uint8_t *pBytes = _adts.buffer + 7;
|
||||
if(MP4ReadSample(_hMP4File, _audio_trId, i + 1, &pBytes, &numBytes)){
|
||||
if (!iTimeInc) {
|
||||
m_adts.aac_frame_length = 7 + numBytes;
|
||||
writeAdtsHeader(m_adts, m_adts.buffer);
|
||||
writeAAC(m_adts.buffer, m_adts.aac_frame_length, (double) m_audio_ms * i / m_audio_num_samples);
|
||||
_adts.aac_frame_length = 7 + numBytes;
|
||||
writeAdtsHeader(_adts, _adts.buffer);
|
||||
writeAAC(_adts.buffer, _adts.aac_frame_length, (double) _audio_ms * i / _audio_num_samples);
|
||||
}
|
||||
}else{
|
||||
ErrorL << "读取音频失败:" << i+ 1;
|
||||
}
|
||||
}
|
||||
m_audio_current = iNextSample;
|
||||
return m_audio_current < m_audio_num_samples;
|
||||
_audio_current = iNextSample;
|
||||
return _audio_current < _audio_num_samples;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void MediaReader::writeH264(uint8_t *pucData,int iLen,uint32_t uiStamp) {
|
||||
m_pChn->inputH264((char *)pucData, iLen, uiStamp);
|
||||
_pChn->inputH264((char *)pucData, iLen, uiStamp);
|
||||
}
|
||||
|
||||
inline void MediaReader::writeAAC(uint8_t *pucData,int iLen,uint32_t uiStamp) {
|
||||
m_pChn->inputAAC((char *)pucData, iLen, uiStamp);
|
||||
_pChn->inputAAC((char *)pucData, iLen, uiStamp);
|
||||
}
|
||||
|
||||
inline MP4SampleId MediaReader::getVideoSampleId(int iTimeInc ) {
|
||||
MP4SampleId video_current = (double)m_video_num_samples * (m_iSeekTime + m_ticker.elapsedTime() + iTimeInc) / m_video_ms;
|
||||
video_current = MAX(0,MIN(m_video_num_samples, video_current));
|
||||
MP4SampleId video_current = (double)_video_num_samples * (_iSeekTime + _ticker.elapsedTime() + iTimeInc) / _video_ms;
|
||||
video_current = MAX(0,MIN(_video_num_samples, video_current));
|
||||
return video_current;
|
||||
|
||||
}
|
||||
|
||||
inline MP4SampleId MediaReader::getAudioSampleId(int iTimeInc) {
|
||||
MP4SampleId audio_current = (double)m_audio_num_samples * (m_iSeekTime + m_ticker.elapsedTime() + iTimeInc) / m_audio_ms ;
|
||||
audio_current = MAX(0,MIN(m_audio_num_samples,audio_current));
|
||||
MP4SampleId audio_current = (double)_audio_num_samples * (_iSeekTime + _ticker.elapsedTime() + iTimeInc) / _audio_ms ;
|
||||
audio_current = MAX(0,MIN(_audio_num_samples,audio_current));
|
||||
return audio_current;
|
||||
}
|
||||
inline void MediaReader::setSeekTime(int iSeekTime){
|
||||
m_iSeekTime = MAX(0, MIN(iSeekTime,m_iDuration));
|
||||
m_ticker.resetTime();
|
||||
if (m_audio_trId != MP4_INVALID_TRACK_ID) {
|
||||
m_audio_current = getAudioSampleId();
|
||||
_iSeekTime = MAX(0, MIN(iSeekTime,_iDuration));
|
||||
_ticker.resetTime();
|
||||
if (_audio_trId != MP4_INVALID_TRACK_ID) {
|
||||
_audio_current = getAudioSampleId();
|
||||
}
|
||||
if (m_video_trId != MP4_INVALID_TRACK_ID) {
|
||||
m_video_current = getVideoSampleId();
|
||||
if (_video_trId != MP4_INVALID_TRACK_ID) {
|
||||
_video_current = getVideoSampleId();
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t MediaReader::getVideoCurrentTime(){
|
||||
return (double)m_video_current * m_video_ms /m_video_num_samples;
|
||||
return (double)_video_current * _video_ms /_video_num_samples;
|
||||
}
|
||||
void MediaReader::seek(int iSeekTime,bool bReStart){
|
||||
lock_guard<recursive_mutex> lck(m_mtx);
|
||||
if(iSeekTime == 0 || m_video_trId == MP4_INVALID_TRACK_ID){
|
||||
lock_guard<recursive_mutex> lck(_mtx);
|
||||
if(iSeekTime == 0 || _video_trId == MP4_INVALID_TRACK_ID){
|
||||
setSeekTime(iSeekTime);
|
||||
}else{
|
||||
setSeekTime(iSeekTime - 5000);
|
||||
//在之后的10秒查找关键帧
|
||||
readVideoSample(10000);
|
||||
if (m_bSyncSample) {
|
||||
if (_bSyncSample) {
|
||||
//找到关键帧
|
||||
auto iIdr = m_video_current;
|
||||
auto iIdr = _video_current;
|
||||
setSeekTime(getVideoCurrentTime());
|
||||
m_video_current = iIdr;
|
||||
_video_current = iIdr;
|
||||
}else{
|
||||
//未找到关键帧
|
||||
setSeekTime(iSeekTime);
|
||||
}
|
||||
}
|
||||
m_pChn->updateTimeStamp(m_iSeekTime);
|
||||
_pChn->updateTimeStamp(_iSeekTime);
|
||||
|
||||
if(bReStart){
|
||||
AsyncTaskThread::Instance().CancelTask(reinterpret_cast<uint64_t>(this));
|
||||
|
@ -55,37 +55,37 @@ public:
|
||||
private:
|
||||
|
||||
#ifdef ENABLE_MP4V2
|
||||
MP4FileHandle m_hMP4File = MP4_INVALID_FILE_HANDLE;
|
||||
MP4TrackId m_video_trId = MP4_INVALID_TRACK_ID;
|
||||
uint32_t m_video_ms = 0;
|
||||
uint32_t m_video_num_samples = 0;
|
||||
uint32_t m_video_sample_max_size = 0;
|
||||
uint32_t m_video_width = 0;
|
||||
uint32_t m_video_height = 0;
|
||||
uint32_t m_video_framerate = 0;
|
||||
string m_strPps;
|
||||
string m_strSps;
|
||||
bool m_bSyncSample = false;
|
||||
MP4FileHandle _hMP4File = MP4_INVALID_FILE_HANDLE;
|
||||
MP4TrackId _video_trId = MP4_INVALID_TRACK_ID;
|
||||
uint32_t _video_ms = 0;
|
||||
uint32_t _video_num_samples = 0;
|
||||
uint32_t _video_sample_max_size = 0;
|
||||
uint32_t _video_width = 0;
|
||||
uint32_t _video_height = 0;
|
||||
uint32_t _video_framerate = 0;
|
||||
string _strPps;
|
||||
string _strSps;
|
||||
bool _bSyncSample = false;
|
||||
|
||||
MP4TrackId m_audio_trId = MP4_INVALID_TRACK_ID;
|
||||
uint32_t m_audio_ms = 0;
|
||||
uint32_t m_audio_num_samples = 0;
|
||||
uint32_t m_audio_sample_max_size = 0;
|
||||
uint32_t m_audio_sample_rate = 0;
|
||||
uint32_t m_audio_num_channels = 0;
|
||||
string m_strAacCfg;
|
||||
AACFrame m_adts;
|
||||
MP4TrackId _audio_trId = MP4_INVALID_TRACK_ID;
|
||||
uint32_t _audio_ms = 0;
|
||||
uint32_t _audio_num_samples = 0;
|
||||
uint32_t _audio_sample_max_size = 0;
|
||||
uint32_t _audio_sample_rate = 0;
|
||||
uint32_t _audio_num_channels = 0;
|
||||
string _strAacCfg;
|
||||
AACFrame _adts;
|
||||
|
||||
int m_iDuration = 0;
|
||||
DevChannel::Ptr m_pChn;
|
||||
MP4SampleId m_video_current = 0;
|
||||
MP4SampleId m_audio_current = 0;
|
||||
std::shared_ptr<uint8_t> m_pcVideoSample;
|
||||
int _iDuration = 0;
|
||||
DevChannel::Ptr _pChn;
|
||||
MP4SampleId _video_current = 0;
|
||||
MP4SampleId _audio_current = 0;
|
||||
std::shared_ptr<uint8_t> _pcVideoSample;
|
||||
|
||||
int m_iSeekTime = 0 ;
|
||||
Ticker m_ticker;
|
||||
Ticker m_alive;
|
||||
recursive_mutex m_mtx;
|
||||
int _iSeekTime = 0 ;
|
||||
Ticker _ticker;
|
||||
Ticker _alive;
|
||||
recursive_mutex _mtx;
|
||||
|
||||
void seek(int iSeekTime,bool bReStart = true);
|
||||
inline void setSeekTime(int iSeekTime);
|
||||
|
@ -57,7 +57,7 @@ MediaRecorder::MediaRecorder(const string &strVhost_tmp,
|
||||
|
||||
if(enableHls) {
|
||||
auto m3u8FilePath = hlsPath + "/" + strVhost + "/" + strApp + "/" + strId + "/hls.m3u8";
|
||||
m_hlsMaker.reset(new HLSMaker(m3u8FilePath,hlsBufSize, hlsDuration, hlsNum));
|
||||
_hlsMaker.reset(new HLSMaker(m3u8FilePath,hlsBufSize, hlsDuration, hlsNum));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MP4V2
|
||||
@ -66,7 +66,7 @@ MediaRecorder::MediaRecorder(const string &strVhost_tmp,
|
||||
|
||||
if(enableMp4){
|
||||
auto mp4FilePath = recordPath + "/" + strVhost + "/" + recordAppName + "/" + strApp + "/" + strId + "/";
|
||||
m_mp4Maker.reset(new Mp4Maker(mp4FilePath,strVhost,strApp,strId,pPlayer));
|
||||
_mp4Maker.reset(new Mp4Maker(mp4FilePath,strVhost,strApp,strId,pPlayer));
|
||||
}
|
||||
#endif //ENABLE_MP4V2
|
||||
}
|
||||
@ -75,23 +75,23 @@ MediaRecorder::~MediaRecorder() {
|
||||
}
|
||||
|
||||
void MediaRecorder::inputH264(void* pData, uint32_t ui32Length, uint32_t ui32TimeStamp, int iType) {
|
||||
if(m_hlsMaker){
|
||||
m_hlsMaker->inputH264(pData, ui32Length, ui32TimeStamp, iType);
|
||||
if(_hlsMaker){
|
||||
_hlsMaker->inputH264(pData, ui32Length, ui32TimeStamp, iType);
|
||||
}
|
||||
#ifdef ENABLE_MP4V2
|
||||
if(m_mp4Maker){
|
||||
m_mp4Maker->inputH264(pData, ui32Length, ui32TimeStamp, iType);
|
||||
if(_mp4Maker){
|
||||
_mp4Maker->inputH264(pData, ui32Length, ui32TimeStamp, iType);
|
||||
}
|
||||
#endif //ENABLE_MP4V2
|
||||
}
|
||||
|
||||
void MediaRecorder::inputAAC(void* pData, uint32_t ui32Length, uint32_t ui32TimeStamp) {
|
||||
if(m_hlsMaker){
|
||||
m_hlsMaker->inputAAC(pData, ui32Length, ui32TimeStamp);
|
||||
if(_hlsMaker){
|
||||
_hlsMaker->inputAAC(pData, ui32Length, ui32TimeStamp);
|
||||
}
|
||||
#ifdef ENABLE_MP4V2
|
||||
if(m_mp4Maker){
|
||||
m_mp4Maker->inputAAC(pData, ui32Length, ui32TimeStamp);
|
||||
if(_mp4Maker){
|
||||
_mp4Maker->inputAAC(pData, ui32Length, ui32TimeStamp);
|
||||
}
|
||||
#endif //ENABLE_MP4V2
|
||||
}
|
||||
|
@ -50,8 +50,8 @@ public:
|
||||
const string &strApp,
|
||||
const string &strId,
|
||||
const std::shared_ptr<PlayerBase> &pPlayer,
|
||||
bool m_enableHls = true,
|
||||
bool m_enableMp4 = false);
|
||||
bool enableHls = true,
|
||||
bool enableMp4 = false);
|
||||
virtual ~MediaRecorder();
|
||||
|
||||
void inputH264( void *pData,
|
||||
@ -63,9 +63,9 @@ public:
|
||||
uint32_t ui32Length,
|
||||
uint32_t ui32TimeStamp);
|
||||
private:
|
||||
std::shared_ptr<HLSMaker> m_hlsMaker;
|
||||
std::shared_ptr<HLSMaker> _hlsMaker;
|
||||
#ifdef ENABLE_MP4V2
|
||||
std::shared_ptr<Mp4Maker> m_mp4Maker;
|
||||
std::shared_ptr<Mp4Maker> _mp4Maker;
|
||||
#endif //ENABLE_MP4V2
|
||||
|
||||
};
|
||||
|
@ -62,14 +62,14 @@ Mp4Maker::Mp4Maker(const string& strPath,
|
||||
const string &strStreamId,
|
||||
const PlayerBase::Ptr &pPlayer) {
|
||||
DebugL << strPath;
|
||||
m_pPlayer = pPlayer;
|
||||
m_strPath = strPath;
|
||||
_pPlayer = pPlayer;
|
||||
_strPath = strPath;
|
||||
|
||||
/////record 业务逻辑//////
|
||||
m_info.strAppName = strApp;
|
||||
m_info.strStreamId = strStreamId;
|
||||
m_info.strVhost = strVhost;
|
||||
m_info.strFolder = strPath;
|
||||
_info.strAppName = strApp;
|
||||
_info.strStreamId = strStreamId;
|
||||
_info.strVhost = strVhost;
|
||||
_info.strFolder = strPath;
|
||||
//----record 业务逻辑----//
|
||||
}
|
||||
Mp4Maker::~Mp4Maker() {
|
||||
@ -80,22 +80,22 @@ void Mp4Maker::inputH264(void *pData, uint32_t ui32Length, uint32_t ui32TimeStam
|
||||
switch (iType) {
|
||||
case 1: //P
|
||||
case 5: { //IDR
|
||||
if (m_strLastVideo.size()) {
|
||||
int64_t iTimeInc = (int64_t)ui32TimeStamp - (int64_t)m_ui32LastVideoTime;
|
||||
if (_strLastVideo.size()) {
|
||||
int64_t iTimeInc = (int64_t)ui32TimeStamp - (int64_t)_ui32LastVideoTime;
|
||||
iTimeInc = MAX(0,MIN(iTimeInc,500));
|
||||
if(iTimeInc == 0 || iTimeInc == 500){
|
||||
WarnL << "abnormal time stamp increment:" << ui32TimeStamp << " " << m_ui32LastVideoTime;
|
||||
WarnL << "abnormal time stamp increment:" << ui32TimeStamp << " " << _ui32LastVideoTime;
|
||||
}
|
||||
_inputH264((char *) m_strLastVideo.data(), m_strLastVideo.size(), iTimeInc, m_iLastVideoType);
|
||||
_inputH264((char *) _strLastVideo.data(), _strLastVideo.size(), iTimeInc, _iLastVideoType);
|
||||
}
|
||||
//m_strLastVideo.assign(("\x0\x0\x0\x2\x9\xf0"), 6);
|
||||
//_strLastVideo.assign(("\x0\x0\x0\x2\x9\xf0"), 6);
|
||||
uint32_t *p = (uint32_t *) pData;
|
||||
*p = htonl(ui32Length - 4);
|
||||
m_strLastVideo.assign((char *) pData, ui32Length);
|
||||
_strLastVideo.assign((char *) pData, ui32Length);
|
||||
memcpy(pData, "\x00\x00\x00\x01", 4);
|
||||
|
||||
m_ui32LastVideoTime = ui32TimeStamp;
|
||||
m_iLastVideoType = iType;
|
||||
_ui32LastVideoTime = ui32TimeStamp;
|
||||
_iLastVideoType = iType;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -103,28 +103,28 @@ void Mp4Maker::inputH264(void *pData, uint32_t ui32Length, uint32_t ui32TimeStam
|
||||
}
|
||||
}
|
||||
void Mp4Maker::inputAAC(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp){
|
||||
if (m_strLastAudio.size()) {
|
||||
int64_t iTimeInc = (int64_t)ui32TimeStamp - (int64_t)m_ui32LastAudioTime;
|
||||
if (_strLastAudio.size()) {
|
||||
int64_t iTimeInc = (int64_t)ui32TimeStamp - (int64_t)_ui32LastAudioTime;
|
||||
iTimeInc = MAX(0,MIN(iTimeInc,500));
|
||||
if(iTimeInc == 0 || iTimeInc == 500){
|
||||
WarnL << "abnormal time stamp increment:" << ui32TimeStamp << " " << m_ui32LastAudioTime;
|
||||
WarnL << "abnormal time stamp increment:" << ui32TimeStamp << " " << _ui32LastAudioTime;
|
||||
}
|
||||
_inputAAC((char *)m_strLastAudio.data(), m_strLastAudio.size(), iTimeInc);
|
||||
_inputAAC((char *)_strLastAudio.data(), _strLastAudio.size(), iTimeInc);
|
||||
}
|
||||
m_strLastAudio.assign((char *)pData, ui32Length);
|
||||
m_ui32LastAudioTime = ui32TimeStamp;
|
||||
_strLastAudio.assign((char *)pData, ui32Length);
|
||||
_ui32LastAudioTime = ui32TimeStamp;
|
||||
}
|
||||
|
||||
void Mp4Maker::_inputH264(void* pData, uint32_t ui32Length, uint32_t ui32Duration, int iType) {
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,recordSec,Config::Record::kFileSecond);
|
||||
|
||||
if(iType == 5 && (m_hMp4 == MP4_INVALID_FILE_HANDLE || m_ticker.elapsedTime() > recordSec * 1000)){
|
||||
if(iType == 5 && (_hMp4 == MP4_INVALID_FILE_HANDLE || _ticker.elapsedTime() > recordSec * 1000)){
|
||||
//在I帧率处新建MP4文件
|
||||
//如果文件未创建或者文件超过10分钟则创建新文件
|
||||
createFile();
|
||||
}
|
||||
if (m_hVideo != MP4_INVALID_TRACK_ID) {
|
||||
MP4WriteSample(m_hMp4, m_hVideo, (uint8_t *) pData, ui32Length,ui32Duration * 90,0,iType == 5);
|
||||
if (_hVideo != MP4_INVALID_TRACK_ID) {
|
||||
MP4WriteSample(_hMp4, _hVideo, (uint8_t *) pData, ui32Length,ui32Duration * 90,0,iType == 5);
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,39 +134,39 @@ void Mp4Maker::_inputAAC(void* pData, uint32_t ui32Length, uint32_t ui32Duration
|
||||
//todo(xzl) 修复此处
|
||||
|
||||
//
|
||||
// if (!m_pPlayer->containVideo() && (m_hMp4 == MP4_INVALID_FILE_HANDLE || m_ticker.elapsedTime() > recordSec * 1000)) {
|
||||
// if (!_pPlayer->containVideo() && (_hMp4 == MP4_INVALID_FILE_HANDLE || _ticker.elapsedTime() > recordSec * 1000)) {
|
||||
// //在I帧率处新建MP4文件
|
||||
// //如果文件未创建或者文件超过10分钟则创建新文件
|
||||
// createFile();
|
||||
// }
|
||||
// if (m_hAudio != MP4_INVALID_TRACK_ID) {
|
||||
// auto duration = ui32Duration * m_pPlayer->getAudioSampleRate() /1000.0;
|
||||
// MP4WriteSample(m_hMp4, m_hAudio, (uint8_t*)pData + 7, ui32Length - 7,duration,0,false);
|
||||
// if (_hAudio != MP4_INVALID_TRACK_ID) {
|
||||
// auto duration = ui32Duration * _pPlayer->getAudioSampleRate() /1000.0;
|
||||
// MP4WriteSample(_hMp4, _hAudio, (uint8_t*)pData + 7, ui32Length - 7,duration,0,false);
|
||||
// }
|
||||
}
|
||||
|
||||
void Mp4Maker::createFile() {
|
||||
if(!m_pPlayer->isInited()){
|
||||
if(!_pPlayer->isInited()){
|
||||
return;
|
||||
}
|
||||
closeFile();
|
||||
|
||||
auto strDate = timeStr("%Y-%m-%d");
|
||||
auto strTime = timeStr("%H-%M-%S");
|
||||
auto strFileTmp = m_strPath + strDate + "/." + strTime + ".mp4";
|
||||
auto strFile = m_strPath + strDate + "/" + strTime + ".mp4";
|
||||
auto strFileTmp = _strPath + strDate + "/." + strTime + ".mp4";
|
||||
auto strFile = _strPath + strDate + "/" + strTime + ".mp4";
|
||||
|
||||
/////record 业务逻辑//////
|
||||
m_info.ui64StartedTime = ::time(NULL);
|
||||
m_info.strFileName = strTime + ".mp4";
|
||||
m_info.strFilePath = strFile;
|
||||
_info.ui64StartedTime = ::time(NULL);
|
||||
_info.strFileName = strTime + ".mp4";
|
||||
_info.strFilePath = strFile;
|
||||
|
||||
GET_CONFIG_AND_REGISTER(string,appName,Config::Record::kAppName);
|
||||
|
||||
m_info.strUrl = m_info.strVhost + "/"
|
||||
_info.strUrl = _info.strVhost + "/"
|
||||
+ appName + "/"
|
||||
+ m_info.strAppName + "/"
|
||||
+ m_info.strStreamId + "/"
|
||||
+ _info.strAppName + "/"
|
||||
+ _info.strStreamId + "/"
|
||||
+ strDate + "/"
|
||||
+ strTime + ".mp4";
|
||||
//----record 业务逻辑----//
|
||||
@ -176,36 +176,36 @@ void Mp4Maker::createFile() {
|
||||
#else
|
||||
File::createfile_path(strFileTmp.data(), 0);
|
||||
#endif
|
||||
m_hMp4 = MP4Create(strFileTmp.data());
|
||||
if (m_hMp4 == MP4_INVALID_FILE_HANDLE) {
|
||||
_hMp4 = MP4Create(strFileTmp.data());
|
||||
if (_hMp4 == MP4_INVALID_FILE_HANDLE) {
|
||||
WarnL << "创建MP4文件失败:" << strFileTmp;
|
||||
return;
|
||||
}
|
||||
//MP4SetTimeScale(m_hMp4, 90000);
|
||||
m_strFileTmp = strFileTmp;
|
||||
m_strFile = strFile;
|
||||
m_ticker.resetTime();
|
||||
//MP4SetTimeScale(_hMp4, 90000);
|
||||
_strFileTmp = strFileTmp;
|
||||
_strFile = strFile;
|
||||
_ticker.resetTime();
|
||||
|
||||
//todo(xzl) 修复此处
|
||||
|
||||
// if(m_pPlayer->containVideo()){
|
||||
// auto &sps = m_pPlayer->getSps();
|
||||
// auto &pps = m_pPlayer->getPps();
|
||||
// m_hVideo = MP4AddH264VideoTrack(m_hMp4, 90000, MP4_INVALID_DURATION,
|
||||
// m_pPlayer->getVideoWidth(), m_pPlayer->getVideoHeight(),
|
||||
// if(_pPlayer->containVideo()){
|
||||
// auto &sps = _pPlayer->getSps();
|
||||
// auto &pps = _pPlayer->getPps();
|
||||
// _hVideo = MP4AddH264VideoTrack(_hMp4, 90000, MP4_INVALID_DURATION,
|
||||
// _pPlayer->getVideoWidth(), _pPlayer->getVideoHeight(),
|
||||
// sps[5], sps[6], sps[7], 3);
|
||||
// if(m_hVideo !=MP4_INVALID_TRACK_ID){
|
||||
// MP4AddH264SequenceParameterSet(m_hMp4, m_hVideo, (uint8_t *)sps.data() + 4, sps.size() - 4);
|
||||
// MP4AddH264PictureParameterSet(m_hMp4, m_hVideo, (uint8_t *)pps.data() + 4, pps.size() - 4);
|
||||
// if(_hVideo !=MP4_INVALID_TRACK_ID){
|
||||
// MP4AddH264SequenceParameterSet(_hMp4, _hVideo, (uint8_t *)sps.data() + 4, sps.size() - 4);
|
||||
// MP4AddH264PictureParameterSet(_hMp4, _hVideo, (uint8_t *)pps.data() + 4, pps.size() - 4);
|
||||
// }else{
|
||||
// WarnL << "添加视频通道失败:" << strFileTmp;
|
||||
// }
|
||||
// }
|
||||
// if(m_pPlayer->containAudio()){
|
||||
// m_hAudio = MP4AddAudioTrack(m_hMp4, m_pPlayer->getAudioSampleRate(), MP4_INVALID_DURATION, MP4_MPEG4_AUDIO_TYPE);
|
||||
// if (m_hAudio != MP4_INVALID_TRACK_ID) {
|
||||
// auto &cfg = m_pPlayer->getAudioCfg();
|
||||
// MP4SetTrackESConfiguration(m_hMp4, m_hAudio,(uint8_t *)cfg.data(), cfg.size());
|
||||
// if(_pPlayer->containAudio()){
|
||||
// _hAudio = MP4AddAudioTrack(_hMp4, _pPlayer->getAudioSampleRate(), MP4_INVALID_DURATION, MP4_MPEG4_AUDIO_TYPE);
|
||||
// if (_hAudio != MP4_INVALID_TRACK_ID) {
|
||||
// auto &cfg = _pPlayer->getAudioCfg();
|
||||
// MP4SetTrackESConfiguration(_hMp4, _hAudio,(uint8_t *)cfg.data(), cfg.size());
|
||||
// }else{
|
||||
// WarnL << "添加音频通道失败:" << strFileTmp;
|
||||
// }
|
||||
@ -213,24 +213,24 @@ void Mp4Maker::createFile() {
|
||||
}
|
||||
|
||||
void Mp4Maker::closeFile() {
|
||||
if (m_hMp4 != MP4_INVALID_FILE_HANDLE) {
|
||||
if (_hMp4 != MP4_INVALID_FILE_HANDLE) {
|
||||
{
|
||||
TimeTicker();
|
||||
MP4Close(m_hMp4,MP4_CLOSE_DO_NOT_COMPUTE_BITRATE);
|
||||
MP4Close(_hMp4,MP4_CLOSE_DO_NOT_COMPUTE_BITRATE);
|
||||
}
|
||||
rename(m_strFileTmp.data(),m_strFile.data());
|
||||
m_hMp4 = MP4_INVALID_FILE_HANDLE;
|
||||
m_hVideo = MP4_INVALID_TRACK_ID;
|
||||
m_hAudio = MP4_INVALID_TRACK_ID;
|
||||
rename(_strFileTmp.data(),_strFile.data());
|
||||
_hMp4 = MP4_INVALID_FILE_HANDLE;
|
||||
_hVideo = MP4_INVALID_TRACK_ID;
|
||||
_hAudio = MP4_INVALID_TRACK_ID;
|
||||
|
||||
/////record 业务逻辑//////
|
||||
m_info.ui64TimeLen = ::time(NULL) - m_info.ui64StartedTime;
|
||||
_info.ui64TimeLen = ::time(NULL) - _info.ui64StartedTime;
|
||||
//获取文件大小
|
||||
struct stat fileData;
|
||||
stat(m_strFile.data(), &fileData);
|
||||
m_info.ui64FileSize = fileData.st_size;
|
||||
stat(_strFile.data(), &fileData);
|
||||
_info.ui64FileSize = fileData.st_size;
|
||||
//----record 业务逻辑----//
|
||||
NoticeCenter::Instance().emitEvent(Config::Broadcast::kBroadcastRecordMP4,m_info,*this);
|
||||
NoticeCenter::Instance().emitEvent(Config::Broadcast::kBroadcastRecordMP4,_info,*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,29 +73,29 @@ public:
|
||||
//时间戳:参考频率1000
|
||||
void inputAAC(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp);
|
||||
private:
|
||||
MP4FileHandle m_hMp4 = MP4_INVALID_FILE_HANDLE;
|
||||
MP4TrackId m_hVideo = MP4_INVALID_TRACK_ID;
|
||||
MP4TrackId m_hAudio = MP4_INVALID_TRACK_ID;
|
||||
PlayerBase::Ptr m_pPlayer;
|
||||
string m_strPath;
|
||||
string m_strFile;
|
||||
string m_strFileTmp;
|
||||
Ticker m_ticker;
|
||||
SmoothTicker m_mediaTicker[2];
|
||||
MP4FileHandle _hMp4 = MP4_INVALID_FILE_HANDLE;
|
||||
MP4TrackId _hVideo = MP4_INVALID_TRACK_ID;
|
||||
MP4TrackId _hAudio = MP4_INVALID_TRACK_ID;
|
||||
PlayerBase::Ptr _pPlayer;
|
||||
string _strPath;
|
||||
string _strFile;
|
||||
string _strFileTmp;
|
||||
Ticker _ticker;
|
||||
SmoothTicker _mediaTicker[2];
|
||||
|
||||
void createFile();
|
||||
void closeFile();
|
||||
void _inputH264(void *pData, uint32_t ui32Length, uint32_t ui64Duration, int iType);
|
||||
void _inputAAC(void *pData, uint32_t ui32Length, uint32_t ui64Duration);
|
||||
|
||||
string m_strLastVideo;
|
||||
string m_strLastAudio;
|
||||
string _strLastVideo;
|
||||
string _strLastAudio;
|
||||
|
||||
uint32_t m_ui32LastVideoTime = 0;
|
||||
uint32_t m_ui32LastAudioTime = 0;
|
||||
int m_iLastVideoType = 0;
|
||||
uint32_t _ui32LastVideoTime = 0;
|
||||
uint32_t _ui32LastAudioTime = 0;
|
||||
int _iLastVideoType = 0;
|
||||
|
||||
Mp4Info m_info;
|
||||
Mp4Info _info;
|
||||
};
|
||||
|
||||
} /* namespace MediaFile */
|
||||
|
@ -43,22 +43,22 @@ MediaPlayer::~MediaPlayer() {
|
||||
}
|
||||
void MediaPlayer::play(const char* strUrl) {
|
||||
string strPrefix = FindField(strUrl, NULL, "://");
|
||||
if ((strcasecmp(m_strPrefix.data(),strPrefix.data()) != 0) || strPrefix.empty()) {
|
||||
if ((strcasecmp(_strPrefix.data(),strPrefix.data()) != 0) || strPrefix.empty()) {
|
||||
//协议切换
|
||||
m_strPrefix = strPrefix;
|
||||
m_parser = PlayerBase::createPlayer(strUrl);
|
||||
m_parser->setOnShutdown(m_shutdownCB);
|
||||
_strPrefix = strPrefix;
|
||||
_parser = PlayerBase::createPlayer(strUrl);
|
||||
_parser->setOnShutdown(_shutdownCB);
|
||||
//todo(xzl) 修复此处
|
||||
// m_parser->setOnVideoCB(m_onGetVideoCB);
|
||||
// m_parser->setOnAudioCB(m_onGetAudioCB);
|
||||
// _parser->setOnVideoCB(_onGetVideoCB);
|
||||
// _parser->setOnAudioCB(_onGetAudioCB);
|
||||
}
|
||||
m_parser->setOnPlayResult(m_playResultCB);
|
||||
m_parser->mINI::operator=(*this);
|
||||
m_parser->play(strUrl);
|
||||
_parser->setOnPlayResult(_playResultCB);
|
||||
_parser->mINI::operator=(*this);
|
||||
_parser->play(strUrl);
|
||||
}
|
||||
|
||||
TaskExecutor::Ptr MediaPlayer::getExecutor(){
|
||||
auto parser = dynamic_pointer_cast<SocketHelper>(m_parser);
|
||||
auto parser = dynamic_pointer_cast<SocketHelper>(_parser);
|
||||
if(!parser){
|
||||
return nullptr;
|
||||
}
|
||||
@ -66,14 +66,14 @@ TaskExecutor::Ptr MediaPlayer::getExecutor(){
|
||||
}
|
||||
|
||||
void MediaPlayer::pause(bool bPause) {
|
||||
if (m_parser) {
|
||||
m_parser->pause(bPause);
|
||||
if (_parser) {
|
||||
_parser->pause(bPause);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayer::teardown() {
|
||||
if (m_parser) {
|
||||
m_parser->teardown();
|
||||
if (_parser) {
|
||||
_parser->teardown();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ public:
|
||||
void teardown() override;
|
||||
TaskExecutor::Ptr getExecutor();
|
||||
private:
|
||||
string m_strPrefix;
|
||||
string _strPrefix;
|
||||
|
||||
};
|
||||
|
||||
|
@ -101,73 +101,73 @@ public:
|
||||
PlayerImp(){}
|
||||
virtual ~PlayerImp(){}
|
||||
void setOnShutdown(const function<void(const SockException &)> &cb) override {
|
||||
if (m_parser) {
|
||||
m_parser->setOnShutdown(cb);
|
||||
if (_parser) {
|
||||
_parser->setOnShutdown(cb);
|
||||
}
|
||||
m_shutdownCB = cb;
|
||||
_shutdownCB = cb;
|
||||
}
|
||||
void setOnPlayResult(const function<void(const SockException &ex)> &cb) override {
|
||||
if (m_parser) {
|
||||
m_parser->setOnPlayResult(cb);
|
||||
if (_parser) {
|
||||
_parser->setOnPlayResult(cb);
|
||||
}
|
||||
m_playResultCB = cb;
|
||||
_playResultCB = cb;
|
||||
}
|
||||
|
||||
bool isInited() const override{
|
||||
if (m_parser) {
|
||||
return m_parser->isInited();
|
||||
if (_parser) {
|
||||
return _parser->isInited();
|
||||
}
|
||||
return PlayerBase::isInited();
|
||||
}
|
||||
float getDuration() const override {
|
||||
if (m_parser) {
|
||||
return m_parser->getDuration();
|
||||
if (_parser) {
|
||||
return _parser->getDuration();
|
||||
}
|
||||
return PlayerBase::getDuration();
|
||||
}
|
||||
float getProgress() const override{
|
||||
if (m_parser) {
|
||||
return m_parser->getProgress();
|
||||
if (_parser) {
|
||||
return _parser->getProgress();
|
||||
}
|
||||
return PlayerBase::getProgress();
|
||||
}
|
||||
void seekTo(float fProgress) override{
|
||||
if (m_parser) {
|
||||
return m_parser->seekTo(fProgress);
|
||||
if (_parser) {
|
||||
return _parser->seekTo(fProgress);
|
||||
}
|
||||
return PlayerBase::seekTo(fProgress);
|
||||
}
|
||||
|
||||
void setMediaSouce(const MediaSource::Ptr & src) override {
|
||||
if (m_parser) {
|
||||
return m_parser->setMediaSouce(src);
|
||||
if (_parser) {
|
||||
return _parser->setMediaSouce(src);
|
||||
}
|
||||
m_pMediaSrc = src;
|
||||
_pMediaSrc = src;
|
||||
}
|
||||
|
||||
vector<Track::Ptr> getTracks() const override{
|
||||
if (m_parser) {
|
||||
return m_parser->getTracks();
|
||||
if (_parser) {
|
||||
return _parser->getTracks();
|
||||
}
|
||||
return PlayerBase::getTracks();
|
||||
}
|
||||
protected:
|
||||
void onShutdown(const SockException &ex) override {
|
||||
if (m_shutdownCB) {
|
||||
m_shutdownCB(ex);
|
||||
if (_shutdownCB) {
|
||||
_shutdownCB(ex);
|
||||
}
|
||||
}
|
||||
void onPlayResult(const SockException &ex) override {
|
||||
if (m_playResultCB) {
|
||||
m_playResultCB(ex);
|
||||
m_playResultCB = nullptr;
|
||||
if (_playResultCB) {
|
||||
_playResultCB(ex);
|
||||
_playResultCB = nullptr;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
function<void(const SockException &ex)> m_shutdownCB;
|
||||
function<void(const SockException &ex)> m_playResultCB;
|
||||
std::shared_ptr<Parser> m_parser;
|
||||
MediaSource::Ptr m_pMediaSrc;
|
||||
function<void(const SockException &ex)> _shutdownCB;
|
||||
function<void(const SockException &ex)> _playResultCB;
|
||||
std::shared_ptr<Parser> _parser;
|
||||
MediaSource::Ptr _pMediaSrc;
|
||||
};
|
||||
|
||||
} /* namespace Player */
|
||||
|
@ -29,41 +29,41 @@ void AACRtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
char *ptr = (char *) pcData;
|
||||
int iSize = iLen;
|
||||
while (iSize > 0) {
|
||||
if (iSize <= m_ui32MtuSize - 20) {
|
||||
m_aucSectionBuf[0] = 0;
|
||||
m_aucSectionBuf[1] = 16;
|
||||
m_aucSectionBuf[2] = iLen >> 5;
|
||||
m_aucSectionBuf[3] = (iLen & 0x1F) << 3;
|
||||
memcpy(m_aucSectionBuf + 4, ptr, iSize);
|
||||
makeAACRtp(m_aucSectionBuf, iSize + 4, true, uiStamp);
|
||||
if (iSize <= _ui32MtuSize - 20) {
|
||||
_aucSectionBuf[0] = 0;
|
||||
_aucSectionBuf[1] = 16;
|
||||
_aucSectionBuf[2] = iLen >> 5;
|
||||
_aucSectionBuf[3] = (iLen & 0x1F) << 3;
|
||||
memcpy(_aucSectionBuf + 4, ptr, iSize);
|
||||
makeAACRtp(_aucSectionBuf, iSize + 4, true, uiStamp);
|
||||
break;
|
||||
}
|
||||
m_aucSectionBuf[0] = 0;
|
||||
m_aucSectionBuf[1] = 16;
|
||||
m_aucSectionBuf[2] = (iLen) >> 5;
|
||||
m_aucSectionBuf[3] = (iLen & 0x1F) << 3;
|
||||
memcpy(m_aucSectionBuf + 4, ptr, m_ui32MtuSize - 20);
|
||||
makeAACRtp(m_aucSectionBuf, m_ui32MtuSize - 16, false, uiStamp);
|
||||
ptr += (m_ui32MtuSize - 20);
|
||||
iSize -= (m_ui32MtuSize - 20);
|
||||
_aucSectionBuf[0] = 0;
|
||||
_aucSectionBuf[1] = 16;
|
||||
_aucSectionBuf[2] = (iLen) >> 5;
|
||||
_aucSectionBuf[3] = (iLen & 0x1F) << 3;
|
||||
memcpy(_aucSectionBuf + 4, ptr, _ui32MtuSize - 20);
|
||||
makeAACRtp(_aucSectionBuf, _ui32MtuSize - 16, false, uiStamp);
|
||||
ptr += (_ui32MtuSize - 20);
|
||||
iSize -= (_ui32MtuSize - 20);
|
||||
}
|
||||
}
|
||||
|
||||
void AACRtpEncoder::makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp) {
|
||||
uint16_t u16RtpLen = uiLen + 12;
|
||||
m_ui32TimeStamp = (m_ui32SampleRate / 1000) * uiStamp;
|
||||
uint32_t ts = htonl(m_ui32TimeStamp);
|
||||
uint16_t sq = htons(m_ui16Sequence);
|
||||
uint32_t sc = htonl(m_ui32Ssrc);
|
||||
_ui32TimeStamp = (_ui32SampleRate / 1000) * uiStamp;
|
||||
uint32_t ts = htonl(_ui32TimeStamp);
|
||||
uint16_t sq = htons(_ui16Sequence);
|
||||
uint32_t sc = htonl(_ui32Ssrc);
|
||||
auto pRtppkt = ResourcePoolHelper<RtpPacket>::obtainObj();
|
||||
auto &rtppkt = *pRtppkt;
|
||||
unsigned char *pucRtp = rtppkt.payload;
|
||||
pucRtp[0] = '$';
|
||||
pucRtp[1] = m_ui8Interleaved;
|
||||
pucRtp[1] = _ui8Interleaved;
|
||||
pucRtp[2] = u16RtpLen >> 8;
|
||||
pucRtp[3] = u16RtpLen & 0x00FF;
|
||||
pucRtp[4] = 0x80;
|
||||
pucRtp[5] = (bMark << 7) | m_ui8PlayloadType;
|
||||
pucRtp[5] = (bMark << 7) | _ui8PlayloadType;
|
||||
memcpy(&pucRtp[6], &sq, 2);
|
||||
memcpy(&pucRtp[8], &ts, 4);
|
||||
//ssrc
|
||||
@ -71,24 +71,24 @@ void AACRtpEncoder::makeAACRtp(const void *pData, unsigned int uiLen, bool bMark
|
||||
//playload
|
||||
memcpy(&pucRtp[16], pData, uiLen);
|
||||
|
||||
rtppkt.PT = m_ui8PlayloadType;
|
||||
rtppkt.interleaved = m_ui8Interleaved;
|
||||
rtppkt.PT = _ui8PlayloadType;
|
||||
rtppkt.interleaved = _ui8Interleaved;
|
||||
rtppkt.mark = bMark;
|
||||
rtppkt.length = uiLen + 16;
|
||||
rtppkt.sequence = m_ui16Sequence;
|
||||
rtppkt.timeStamp = m_ui32TimeStamp;
|
||||
rtppkt.ssrc = m_ui32Ssrc;
|
||||
rtppkt.sequence = _ui16Sequence;
|
||||
rtppkt.timeStamp = _ui32TimeStamp;
|
||||
rtppkt.ssrc = _ui32Ssrc;
|
||||
rtppkt.type = TrackAudio;
|
||||
rtppkt.offset = 16;
|
||||
|
||||
RtpCodec::inputRtp(pRtppkt, false);
|
||||
m_ui16Sequence++;
|
||||
_ui16Sequence++;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
AACRtpDecoder::AACRtpDecoder(uint32_t ui32SampleRate) {
|
||||
m_adts = obtainFrame();
|
||||
m_sampleRate = ui32SampleRate;
|
||||
_adts = obtainFrame();
|
||||
_sampleRate = ui32SampleRate;
|
||||
}
|
||||
|
||||
AACFrame::Ptr AACRtpDecoder::obtainFrame() {
|
||||
@ -103,18 +103,18 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) {
|
||||
RtpCodec::inputRtp(rtppack, false);
|
||||
|
||||
int length = rtppack->length - rtppack->offset;
|
||||
if (m_adts->aac_frame_length + length - 4 > sizeof(AACFrame::buffer)) {
|
||||
m_adts->aac_frame_length = 7;
|
||||
if (_adts->aac_frame_length + length - 4 > sizeof(AACFrame::buffer)) {
|
||||
_adts->aac_frame_length = 7;
|
||||
WarnL << "aac负载数据太长";
|
||||
return false;
|
||||
}
|
||||
memcpy(m_adts->buffer + m_adts->aac_frame_length, rtppack->payload + rtppack->offset + 4, length - 4);
|
||||
m_adts->aac_frame_length += (length - 4);
|
||||
memcpy(_adts->buffer + _adts->aac_frame_length, rtppack->payload + rtppack->offset + 4, length - 4);
|
||||
_adts->aac_frame_length += (length - 4);
|
||||
if (rtppack->mark == true) {
|
||||
m_adts->sequence = rtppack->sequence;
|
||||
m_adts->timeStamp = rtppack->timeStamp * (1000.0 / m_sampleRate);
|
||||
writeAdtsHeader(*m_adts, m_adts->buffer);
|
||||
onGetAAC(m_adts);
|
||||
_adts->sequence = rtppack->sequence;
|
||||
_adts->timeStamp = rtppack->timeStamp * (1000.0 / _sampleRate);
|
||||
writeAdtsHeader(*_adts, _adts->buffer);
|
||||
onGetAAC(_adts);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -122,7 +122,7 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) {
|
||||
void AACRtpDecoder::onGetAAC(const AACFrame::Ptr &frame) {
|
||||
//写入环形缓存
|
||||
RtpCodec::inputFrame(frame);
|
||||
m_adts = obtainFrame();
|
||||
_adts = obtainFrame();
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,8 +38,8 @@ private:
|
||||
void onGetAAC(const AACFrame::Ptr &frame);
|
||||
AACFrame::Ptr obtainFrame();
|
||||
private:
|
||||
AACFrame::Ptr m_adts;
|
||||
uint32_t m_sampleRate;
|
||||
AACFrame::Ptr _adts;
|
||||
uint32_t _sampleRate;
|
||||
};
|
||||
|
||||
|
||||
@ -72,7 +72,7 @@ public:
|
||||
private:
|
||||
void makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp);
|
||||
private:
|
||||
unsigned char m_aucSectionBuf[1600];
|
||||
unsigned char _aucSectionBuf[1600];
|
||||
};
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
|
||||
H264RtpDecoder::H264RtpDecoder() {
|
||||
m_h264frame = obtainFrame();
|
||||
_h264frame = obtainFrame();
|
||||
}
|
||||
|
||||
H264Frame::Ptr H264RtpDecoder::obtainFrame() {
|
||||
@ -40,13 +40,13 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
||||
|
||||
if (nal.type >= 0 && nal.type < 24) {
|
||||
//a full frame
|
||||
m_h264frame->buffer.assign("\x0\x0\x0\x1", 4);
|
||||
m_h264frame->buffer.append((char *)frame, length);
|
||||
m_h264frame->type = nal.type;
|
||||
m_h264frame->timeStamp = rtppack->timeStamp / 90;
|
||||
m_h264frame->sequence = rtppack->sequence;
|
||||
auto isIDR = m_h264frame->type == 5;
|
||||
onGetH264(m_h264frame);
|
||||
_h264frame->buffer.assign("\x0\x0\x0\x1", 4);
|
||||
_h264frame->buffer.append((char *)frame, length);
|
||||
_h264frame->type = nal.type;
|
||||
_h264frame->timeStamp = rtppack->timeStamp / 90;
|
||||
_h264frame->sequence = rtppack->sequence;
|
||||
auto isIDR = _h264frame->type == 5;
|
||||
onGetH264(_h264frame);
|
||||
return (isIDR); //i frame
|
||||
}
|
||||
|
||||
@ -57,31 +57,31 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
||||
if (fu.S == 1) {
|
||||
//FU-A start
|
||||
char tmp = (nal.forbidden_zero_bit << 7 | nal.nal_ref_idc << 5 | fu.type);
|
||||
m_h264frame->buffer.assign("\x0\x0\x0\x1", 4);
|
||||
m_h264frame->buffer.push_back(tmp);
|
||||
m_h264frame->buffer.append((char *)frame + 2, length - 2);
|
||||
m_h264frame->type = fu.type;
|
||||
m_h264frame->timeStamp = rtppack->timeStamp / 90;
|
||||
m_h264frame->sequence = rtppack->sequence;
|
||||
return (m_h264frame->type == 5); //i frame
|
||||
_h264frame->buffer.assign("\x0\x0\x0\x1", 4);
|
||||
_h264frame->buffer.push_back(tmp);
|
||||
_h264frame->buffer.append((char *)frame + 2, length - 2);
|
||||
_h264frame->type = fu.type;
|
||||
_h264frame->timeStamp = rtppack->timeStamp / 90;
|
||||
_h264frame->sequence = rtppack->sequence;
|
||||
return (_h264frame->type == 5); //i frame
|
||||
}
|
||||
|
||||
if (rtppack->sequence != (uint16_t)(m_h264frame->sequence + 1)) {
|
||||
m_h264frame->buffer.clear();
|
||||
WarnL << "丢包,帧废弃:" << rtppack->sequence << "," << m_h264frame->sequence;
|
||||
if (rtppack->sequence != (uint16_t)(_h264frame->sequence + 1)) {
|
||||
_h264frame->buffer.clear();
|
||||
WarnL << "丢包,帧废弃:" << rtppack->sequence << "," << _h264frame->sequence;
|
||||
return false;
|
||||
}
|
||||
m_h264frame->sequence = rtppack->sequence;
|
||||
_h264frame->sequence = rtppack->sequence;
|
||||
if (fu.E == 1) {
|
||||
//FU-A end
|
||||
m_h264frame->buffer.append((char *)frame + 2, length - 2);
|
||||
m_h264frame->timeStamp = rtppack->timeStamp / 90;
|
||||
auto isIDR = m_h264frame->type == 5;
|
||||
onGetH264(m_h264frame);
|
||||
_h264frame->buffer.append((char *)frame + 2, length - 2);
|
||||
_h264frame->timeStamp = rtppack->timeStamp / 90;
|
||||
auto isIDR = _h264frame->type == 5;
|
||||
onGetH264(_h264frame);
|
||||
return isIDR;
|
||||
}
|
||||
//FU-A mid
|
||||
m_h264frame->buffer.append((char *)frame + 2, length - 2);
|
||||
_h264frame->buffer.append((char *)frame + 2, length - 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -100,7 +100,7 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
||||
void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) {
|
||||
//写入环形缓存
|
||||
RtpCodec::inputFrame(frame);
|
||||
m_h264frame = obtainFrame();
|
||||
_h264frame = obtainFrame();
|
||||
}
|
||||
|
||||
|
||||
@ -127,7 +127,7 @@ void H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
auto iLen = frame->size() - frame->prefixSize();
|
||||
|
||||
uiStamp %= cycleMS;
|
||||
int iSize = m_ui32MtuSize - 2;
|
||||
int iSize = _ui32MtuSize - 2;
|
||||
if (iLen > iSize) { //超过MTU
|
||||
const unsigned char s_e_r_Start = 0x80;
|
||||
const unsigned char s_e_r_Mid = 0x00;
|
||||
@ -156,11 +156,11 @@ void H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
s_e_r_type = s_e_r_Mid + naluType;
|
||||
}
|
||||
}
|
||||
memcpy(m_aucSectionBuf, &f_nri_type, 1);
|
||||
memcpy(m_aucSectionBuf + 1, &s_e_r_type, 1);
|
||||
memcpy(m_aucSectionBuf + 2, (unsigned char *) pcData + nOffset, iSize);
|
||||
memcpy(_aucSectionBuf, &f_nri_type, 1);
|
||||
memcpy(_aucSectionBuf + 1, &s_e_r_type, 1);
|
||||
memcpy(_aucSectionBuf + 2, (unsigned char *) pcData + nOffset, iSize);
|
||||
nOffset += iSize;
|
||||
makeH264Rtp(m_aucSectionBuf, iSize + 2, mark, uiStamp);
|
||||
makeH264Rtp(_aucSectionBuf, iSize + 2, mark, uiStamp);
|
||||
}
|
||||
} else {
|
||||
makeH264Rtp(pcData, iLen, true, uiStamp);
|
||||
@ -169,19 +169,19 @@ void H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
|
||||
void H264RtpEncoder::makeH264Rtp(const void* data, unsigned int len, bool mark, uint32_t uiStamp) {
|
||||
uint16_t ui16RtpLen = len + 12;
|
||||
m_ui32TimeStamp = (m_ui32SampleRate / 1000) * uiStamp;
|
||||
uint32_t ts = htonl(m_ui32TimeStamp);
|
||||
uint16_t sq = htons(m_ui16Sequence);
|
||||
uint32_t sc = htonl(m_ui32Ssrc);
|
||||
_ui32TimeStamp = (_ui32SampleRate / 1000) * uiStamp;
|
||||
uint32_t ts = htonl(_ui32TimeStamp);
|
||||
uint16_t sq = htons(_ui16Sequence);
|
||||
uint32_t sc = htonl(_ui32Ssrc);
|
||||
|
||||
auto rtppkt = ResourcePoolHelper<RtpPacket>::obtainObj();
|
||||
unsigned char *pucRtp = rtppkt->payload;
|
||||
pucRtp[0] = '$';
|
||||
pucRtp[1] = m_ui8Interleaved;
|
||||
pucRtp[1] = _ui8Interleaved;
|
||||
pucRtp[2] = ui16RtpLen >> 8;
|
||||
pucRtp[3] = ui16RtpLen & 0x00FF;
|
||||
pucRtp[4] = 0x80;
|
||||
pucRtp[5] = (mark << 7) | m_ui8PlayloadType;
|
||||
pucRtp[5] = (mark << 7) | _ui8PlayloadType;
|
||||
memcpy(&pucRtp[6], &sq, 2);
|
||||
memcpy(&pucRtp[8], &ts, 4);
|
||||
//ssrc
|
||||
@ -189,17 +189,17 @@ void H264RtpEncoder::makeH264Rtp(const void* data, unsigned int len, bool mark,
|
||||
//playload
|
||||
memcpy(&pucRtp[16], data, len);
|
||||
|
||||
rtppkt->PT = m_ui8PlayloadType;
|
||||
rtppkt->interleaved = m_ui8Interleaved;
|
||||
rtppkt->PT = _ui8PlayloadType;
|
||||
rtppkt->interleaved = _ui8Interleaved;
|
||||
rtppkt->mark = mark;
|
||||
rtppkt->length = len + 16;
|
||||
rtppkt->sequence = m_ui16Sequence;
|
||||
rtppkt->timeStamp = m_ui32TimeStamp;
|
||||
rtppkt->ssrc = m_ui32Ssrc;
|
||||
rtppkt->sequence = _ui16Sequence;
|
||||
rtppkt->timeStamp = _ui32TimeStamp;
|
||||
rtppkt->ssrc = _ui32Ssrc;
|
||||
rtppkt->type = TrackVideo;
|
||||
rtppkt->offset = 16;
|
||||
|
||||
uint8_t type = ((uint8_t *) (data))[0] & 0x1F;
|
||||
RtpCodec::inputRtp(rtppkt,type == 5);
|
||||
m_ui16Sequence++;
|
||||
_ui16Sequence++;
|
||||
}
|
@ -39,7 +39,7 @@ private:
|
||||
void onGetH264(const H264Frame::Ptr &frame);
|
||||
H264Frame::Ptr obtainFrame();
|
||||
private:
|
||||
H264Frame::Ptr m_h264frame;
|
||||
H264Frame::Ptr _h264frame;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -71,7 +71,7 @@ public:
|
||||
private:
|
||||
void makeH264Rtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp);
|
||||
private:
|
||||
unsigned char m_aucSectionBuf[1600];
|
||||
unsigned char _aucSectionBuf[1600];
|
||||
};
|
||||
|
||||
|
||||
|
@ -105,48 +105,48 @@ public:
|
||||
if(ui32Ssrc == 0){
|
||||
ui32Ssrc = ((uint64_t)this) & 0xFFFFFFFF;
|
||||
}
|
||||
m_ui32Ssrc = ui32Ssrc;
|
||||
m_ui32SampleRate = ui32SampleRate;
|
||||
m_ui32MtuSize = ui32MtuSize;
|
||||
m_ui8PlayloadType = ui8PlayloadType;
|
||||
m_ui8Interleaved = ui8Interleaved;
|
||||
_ui32Ssrc = ui32Ssrc;
|
||||
_ui32SampleRate = ui32SampleRate;
|
||||
_ui32MtuSize = ui32MtuSize;
|
||||
_ui8PlayloadType = ui8PlayloadType;
|
||||
_ui8Interleaved = ui8Interleaved;
|
||||
}
|
||||
|
||||
virtual ~RtpInfo(){}
|
||||
|
||||
int getInterleaved() const {
|
||||
return m_ui8Interleaved;
|
||||
return _ui8Interleaved;
|
||||
}
|
||||
|
||||
int getPlayloadType() const {
|
||||
return m_ui8PlayloadType;
|
||||
return _ui8PlayloadType;
|
||||
}
|
||||
|
||||
int getSampleRate() const {
|
||||
return m_ui32SampleRate;
|
||||
return _ui32SampleRate;
|
||||
}
|
||||
|
||||
uint32_t getSsrc() const {
|
||||
return m_ui32Ssrc;
|
||||
return _ui32Ssrc;
|
||||
}
|
||||
|
||||
uint16_t getSeqence() const {
|
||||
return m_ui16Sequence;
|
||||
return _ui16Sequence;
|
||||
}
|
||||
uint32_t getTimestamp() const {
|
||||
return m_ui32TimeStamp;
|
||||
return _ui32TimeStamp;
|
||||
}
|
||||
uint32_t getMtuSize() const {
|
||||
return m_ui32MtuSize;
|
||||
return _ui32MtuSize;
|
||||
}
|
||||
protected:
|
||||
uint32_t m_ui32Ssrc;
|
||||
uint32_t m_ui32SampleRate;
|
||||
uint32_t m_ui32MtuSize;
|
||||
uint8_t m_ui8PlayloadType;
|
||||
uint8_t m_ui8Interleaved;
|
||||
uint16_t m_ui16Sequence = 0;
|
||||
uint32_t m_ui32TimeStamp = 0;
|
||||
uint32_t _ui32Ssrc;
|
||||
uint32_t _ui32SampleRate;
|
||||
uint32_t _ui32MtuSize;
|
||||
uint8_t _ui8PlayloadType;
|
||||
uint8_t _ui8Interleaved;
|
||||
uint16_t _ui16Sequence = 0;
|
||||
uint32_t _ui32TimeStamp = 0;
|
||||
};
|
||||
|
||||
class RtpCodec : public RtpRing, public FrameRingInterfaceDelegate , public CodecInfo , public ResourcePoolHelper<RtpPacket>{
|
||||
|
@ -49,12 +49,12 @@ public:
|
||||
RtpMaker(const onGetRTP &cb, uint32_t ui32Ssrc, int iMtuSize,int iSampleRate,
|
||||
uint8_t ui8PlayloadType, uint8_t ui8Interleaved) {
|
||||
callBack = cb;
|
||||
m_ui32Ssrc = ui32Ssrc;
|
||||
m_ui32SampleRate = iSampleRate;
|
||||
m_iMtuSize = iMtuSize;
|
||||
m_ui8PlayloadType = ui8PlayloadType;
|
||||
m_ui8Interleaved = ui8Interleaved;
|
||||
m_pktPool.setSize(64);
|
||||
_ui32Ssrc = ui32Ssrc;
|
||||
_ui32SampleRate = iSampleRate;
|
||||
_iMtuSize = iMtuSize;
|
||||
_ui8PlayloadType = ui8PlayloadType;
|
||||
_ui8Interleaved = ui8Interleaved;
|
||||
_pktPool.setSize(64);
|
||||
}
|
||||
virtual ~RtpMaker() {
|
||||
}
|
||||
@ -62,43 +62,43 @@ public:
|
||||
virtual void makeRtp(const char *pcData, int iDataLen, uint32_t uiStamp)=0;
|
||||
|
||||
int getInterleaved() const {
|
||||
return m_ui8Interleaved;
|
||||
return _ui8Interleaved;
|
||||
}
|
||||
|
||||
int getPlayloadType() const {
|
||||
return m_ui8PlayloadType;
|
||||
return _ui8PlayloadType;
|
||||
}
|
||||
|
||||
int getSampleRate() const {
|
||||
return m_ui32SampleRate;
|
||||
return _ui32SampleRate;
|
||||
}
|
||||
|
||||
uint32_t getSsrc() const {
|
||||
return m_ui32Ssrc;
|
||||
return _ui32Ssrc;
|
||||
}
|
||||
|
||||
uint16_t getSeqence() const {
|
||||
return m_ui16Sequence;
|
||||
return _ui16Sequence;
|
||||
}
|
||||
uint32_t getTimestamp() const {
|
||||
return m_ui32TimeStamp;
|
||||
return _ui32TimeStamp;
|
||||
}
|
||||
protected:
|
||||
uint32_t m_ui32Ssrc;
|
||||
uint32_t m_ui32SampleRate;
|
||||
int m_iMtuSize;
|
||||
uint8_t m_ui8PlayloadType;
|
||||
uint8_t m_ui8Interleaved;
|
||||
uint16_t m_ui16Sequence = 0;
|
||||
uint32_t m_ui32TimeStamp = 0;
|
||||
uint32_t _ui32Ssrc;
|
||||
uint32_t _ui32SampleRate;
|
||||
int _iMtuSize;
|
||||
uint8_t _ui8PlayloadType;
|
||||
uint8_t _ui8Interleaved;
|
||||
uint16_t _ui16Sequence = 0;
|
||||
uint32_t _ui32TimeStamp = 0;
|
||||
virtual void onMakeRtp(const RtpPacket::Ptr &pkt, bool bKeyPos = true) {
|
||||
callBack(pkt, bKeyPos);
|
||||
}
|
||||
inline RtpPacket::Ptr obtainPkt() {
|
||||
return m_pktPool.obtain();
|
||||
return _pktPool.obtain();
|
||||
}
|
||||
private:
|
||||
RtspMediaSource::PoolType m_pktPool;
|
||||
RtspMediaSource::PoolType _pktPool;
|
||||
onGetRTP callBack;
|
||||
};
|
||||
|
||||
|
@ -42,42 +42,42 @@ void RtpMaker_AAC::makeRtp(const char *pcData, int iLen, uint32_t uiStamp) {
|
||||
char *ptr = (char *) pcData;
|
||||
int iSize = iLen;
|
||||
while (iSize > 0 ) {
|
||||
if (iSize <= m_iMtuSize - 20) {
|
||||
m_aucSectionBuf[0] = 0;
|
||||
m_aucSectionBuf[1] = 16;
|
||||
m_aucSectionBuf[2] = iLen >> 5;
|
||||
m_aucSectionBuf[3] = (iLen & 0x1F) << 3;
|
||||
memcpy(m_aucSectionBuf + 4, ptr, iSize);
|
||||
makeAACRtp(m_aucSectionBuf, iSize + 4, true, uiStamp);
|
||||
if (iSize <= _iMtuSize - 20) {
|
||||
_aucSectionBuf[0] = 0;
|
||||
_aucSectionBuf[1] = 16;
|
||||
_aucSectionBuf[2] = iLen >> 5;
|
||||
_aucSectionBuf[3] = (iLen & 0x1F) << 3;
|
||||
memcpy(_aucSectionBuf + 4, ptr, iSize);
|
||||
makeAACRtp(_aucSectionBuf, iSize + 4, true, uiStamp);
|
||||
break;
|
||||
}
|
||||
m_aucSectionBuf[0] = 0;
|
||||
m_aucSectionBuf[1] = 16;
|
||||
m_aucSectionBuf[2] = (iLen) >> 5;
|
||||
m_aucSectionBuf[3] = (iLen & 0x1F) << 3;
|
||||
memcpy(m_aucSectionBuf + 4, ptr, m_iMtuSize - 20);
|
||||
makeAACRtp(m_aucSectionBuf, m_iMtuSize - 16, false, uiStamp);
|
||||
ptr += (m_iMtuSize - 20);
|
||||
iSize -= (m_iMtuSize - 20);
|
||||
_aucSectionBuf[0] = 0;
|
||||
_aucSectionBuf[1] = 16;
|
||||
_aucSectionBuf[2] = (iLen) >> 5;
|
||||
_aucSectionBuf[3] = (iLen & 0x1F) << 3;
|
||||
memcpy(_aucSectionBuf + 4, ptr, _iMtuSize - 20);
|
||||
makeAACRtp(_aucSectionBuf, _iMtuSize - 16, false, uiStamp);
|
||||
ptr += (_iMtuSize - 20);
|
||||
iSize -= (_iMtuSize - 20);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inline void RtpMaker_AAC::makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp) {
|
||||
uint16_t u16RtpLen = uiLen + 12;
|
||||
m_ui32TimeStamp = (m_ui32SampleRate / 1000) * uiStamp;
|
||||
uint32_t ts = htonl(m_ui32TimeStamp);
|
||||
uint16_t sq = htons(m_ui16Sequence);
|
||||
uint32_t sc = htonl(m_ui32Ssrc);
|
||||
_ui32TimeStamp = (_ui32SampleRate / 1000) * uiStamp;
|
||||
uint32_t ts = htonl(_ui32TimeStamp);
|
||||
uint16_t sq = htons(_ui16Sequence);
|
||||
uint32_t sc = htonl(_ui32Ssrc);
|
||||
auto pRtppkt = obtainPkt();
|
||||
auto &rtppkt = *(pRtppkt.get());
|
||||
unsigned char *pucRtp = rtppkt.payload;
|
||||
pucRtp[0] = '$';
|
||||
pucRtp[1] = m_ui8Interleaved;
|
||||
pucRtp[1] = _ui8Interleaved;
|
||||
pucRtp[2] = u16RtpLen >> 8;
|
||||
pucRtp[3] = u16RtpLen & 0x00FF;
|
||||
pucRtp[4] = 0x80;
|
||||
pucRtp[5] = (bMark << 7) | m_ui8PlayloadType;
|
||||
pucRtp[5] = (bMark << 7) | _ui8PlayloadType;
|
||||
memcpy(&pucRtp[6], &sq, 2);
|
||||
memcpy(&pucRtp[8], &ts, 4);
|
||||
//ssrc
|
||||
@ -85,18 +85,18 @@ inline void RtpMaker_AAC::makeAACRtp(const void *pData, unsigned int uiLen, bool
|
||||
//playload
|
||||
memcpy(&pucRtp[16], pData, uiLen);
|
||||
|
||||
rtppkt.PT = m_ui8PlayloadType;
|
||||
rtppkt.interleaved = m_ui8Interleaved;
|
||||
rtppkt.PT = _ui8PlayloadType;
|
||||
rtppkt.interleaved = _ui8Interleaved;
|
||||
rtppkt.mark = bMark;
|
||||
rtppkt.length = uiLen + 16;
|
||||
rtppkt.sequence = m_ui16Sequence;
|
||||
rtppkt.timeStamp = m_ui32TimeStamp;
|
||||
rtppkt.ssrc = m_ui32Ssrc;
|
||||
rtppkt.sequence = _ui16Sequence;
|
||||
rtppkt.timeStamp = _ui32TimeStamp;
|
||||
rtppkt.ssrc = _ui32Ssrc;
|
||||
rtppkt.type = TrackAudio;
|
||||
rtppkt.offset = 16;
|
||||
|
||||
onMakeRtp(pRtppkt, false);
|
||||
m_ui16Sequence++;
|
||||
_ui16Sequence++;
|
||||
}
|
||||
|
||||
} /* namespace RTP */
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
void makeRtp(const char *pcData, int iDataLen, uint32_t uiStamp) override;
|
||||
private:
|
||||
inline void makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp);
|
||||
unsigned char m_aucSectionBuf[1600];
|
||||
unsigned char _aucSectionBuf[1600];
|
||||
};
|
||||
|
||||
} /* namespace RTP */
|
||||
|
@ -39,7 +39,7 @@ void RtpMaker_H264::makeRtp(const char* pcData, int iLen, uint32_t uiStamp) {
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,cycleMS,Config::Rtp::kCycleMS);
|
||||
|
||||
uiStamp %= cycleMS;
|
||||
int iSize = m_iMtuSize - 2;
|
||||
int iSize = _iMtuSize - 2;
|
||||
if (iLen > iSize) { //超过MTU
|
||||
const unsigned char s_e_r_Start = 0x80;
|
||||
const unsigned char s_e_r_Mid = 0x00;
|
||||
@ -81,20 +81,20 @@ void RtpMaker_H264::makeRtp(const char* pcData, int iLen, uint32_t uiStamp) {
|
||||
|
||||
inline void RtpMaker_H264::makeH264Rtp(const void* data, unsigned int len, bool mark, uint32_t uiStamp) {
|
||||
uint16_t ui16RtpLen = len + 12;
|
||||
m_ui32TimeStamp = (m_ui32SampleRate / 1000) * uiStamp;
|
||||
uint32_t ts = htonl(m_ui32TimeStamp);
|
||||
uint16_t sq = htons(m_ui16Sequence);
|
||||
uint32_t sc = htonl(m_ui32Ssrc);
|
||||
_ui32TimeStamp = (_ui32SampleRate / 1000) * uiStamp;
|
||||
uint32_t ts = htonl(_ui32TimeStamp);
|
||||
uint16_t sq = htons(_ui16Sequence);
|
||||
uint32_t sc = htonl(_ui32Ssrc);
|
||||
|
||||
auto pRtppkt = obtainPkt();
|
||||
auto &rtppkt = *(pRtppkt.get());
|
||||
unsigned char *pucRtp = rtppkt.payload;
|
||||
pucRtp[0] = '$';
|
||||
pucRtp[1] = m_ui8Interleaved;
|
||||
pucRtp[1] = _ui8Interleaved;
|
||||
pucRtp[2] = ui16RtpLen >> 8;
|
||||
pucRtp[3] = ui16RtpLen & 0x00FF;
|
||||
pucRtp[4] = 0x80;
|
||||
pucRtp[5] = (mark << 7) | m_ui8PlayloadType;
|
||||
pucRtp[5] = (mark << 7) | _ui8PlayloadType;
|
||||
memcpy(&pucRtp[6], &sq, 2);
|
||||
memcpy(&pucRtp[8], &ts, 4);
|
||||
//ssrc
|
||||
@ -102,19 +102,19 @@ inline void RtpMaker_H264::makeH264Rtp(const void* data, unsigned int len, bool
|
||||
//playload
|
||||
memcpy(&pucRtp[16], data, len);
|
||||
|
||||
rtppkt.PT = m_ui8PlayloadType;
|
||||
rtppkt.interleaved = m_ui8Interleaved;
|
||||
rtppkt.PT = _ui8PlayloadType;
|
||||
rtppkt.interleaved = _ui8Interleaved;
|
||||
rtppkt.mark = mark;
|
||||
rtppkt.length = len + 16;
|
||||
rtppkt.sequence = m_ui16Sequence;
|
||||
rtppkt.timeStamp = m_ui32TimeStamp;
|
||||
rtppkt.ssrc = m_ui32Ssrc;
|
||||
rtppkt.sequence = _ui16Sequence;
|
||||
rtppkt.timeStamp = _ui32TimeStamp;
|
||||
rtppkt.ssrc = _ui32Ssrc;
|
||||
rtppkt.type = TrackVideo;
|
||||
rtppkt.offset = 16;
|
||||
|
||||
uint8_t type = ((uint8_t *) (data))[0] & 0x1F;
|
||||
onMakeRtp(pRtppkt, type == 5);
|
||||
m_ui16Sequence++;
|
||||
_ui16Sequence++;
|
||||
//InfoL<<timeStamp<<" "<<time<<" "<<sampleRate;
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,8 @@ void FlvMuxer::start(const RtmpMediaSource::Ptr &media) {
|
||||
}
|
||||
|
||||
void FlvMuxer::onWriteFlvHeader(const RtmpMediaSource::Ptr &mediaSrc) {
|
||||
m_previousTagSize = 0;
|
||||
CLEAR_ARR(m_aui32FirstStamp);
|
||||
_previousTagSize = 0;
|
||||
CLEAR_ARR(_aui32FirstStamp);
|
||||
|
||||
//发送flv文件头
|
||||
char flv_file_header[] = "FLV\x1\x5\x0\x0\x0\x9"; // have audio and have video
|
||||
@ -118,7 +118,7 @@ private:
|
||||
|
||||
|
||||
void FlvMuxer::onWriteFlvTag(const RtmpPacket::Ptr &pkt, uint32_t ui32TimeStamp) {
|
||||
auto size = htonl(m_previousTagSize);
|
||||
auto size = htonl(_previousTagSize);
|
||||
onWrite((char *)&size,4);//onWrite PreviousTagSize
|
||||
RtmpTagHeader header;
|
||||
header.type = pkt->typeId;
|
||||
@ -127,11 +127,11 @@ void FlvMuxer::onWriteFlvTag(const RtmpPacket::Ptr &pkt, uint32_t ui32TimeStamp)
|
||||
set_be24(header.timestamp,ui32TimeStamp & 0xFFFFFF);
|
||||
onWrite((char *)&header, sizeof(header));//onWrite tag header
|
||||
onWrite(std::make_shared<BufferRtmp>(pkt));//onWrite tag data
|
||||
m_previousTagSize += (pkt->strBuf.size() + sizeof(header));
|
||||
_previousTagSize += (pkt->strBuf.size() + sizeof(header));
|
||||
}
|
||||
|
||||
void FlvMuxer::onWriteFlvTag(uint8_t ui8Type, const std::string &strBuf, uint32_t ui32TimeStamp) {
|
||||
auto size = htonl(m_previousTagSize);
|
||||
auto size = htonl(_previousTagSize);
|
||||
onWrite((char *)&size,4);//onWrite PreviousTagSize
|
||||
RtmpTagHeader header;
|
||||
header.type = ui8Type;
|
||||
@ -140,12 +140,12 @@ void FlvMuxer::onWriteFlvTag(uint8_t ui8Type, const std::string &strBuf, uint32_
|
||||
set_be24(header.timestamp,ui32TimeStamp & 0xFFFFFF);
|
||||
onWrite((char *)&header, sizeof(header));//onWrite tag header
|
||||
onWrite(std::make_shared<BufferString>(strBuf));//onWrite tag data
|
||||
m_previousTagSize += (strBuf.size() + sizeof(header));
|
||||
_previousTagSize += (strBuf.size() + sizeof(header));
|
||||
}
|
||||
|
||||
void FlvMuxer::onWriteRtmp(const RtmpPacket::Ptr &pkt) {
|
||||
auto modifiedStamp = pkt->timeStamp;
|
||||
auto &firstStamp = m_aui32FirstStamp[pkt->typeId % 2];
|
||||
auto &firstStamp = _aui32FirstStamp[pkt->typeId % 2];
|
||||
if(!firstStamp){
|
||||
firstStamp = modifiedStamp;
|
||||
}
|
||||
@ -154,7 +154,7 @@ void FlvMuxer::onWriteRtmp(const RtmpPacket::Ptr &pkt) {
|
||||
modifiedStamp -= firstStamp;
|
||||
}else{
|
||||
//发生回环,重新计算时间戳增量
|
||||
CLEAR_ARR(m_aui32FirstStamp);
|
||||
CLEAR_ARR(_aui32FirstStamp);
|
||||
modifiedStamp = 0;
|
||||
}
|
||||
onWriteFlvTag(pkt, modifiedStamp);
|
||||
|
@ -33,8 +33,8 @@ private:
|
||||
void onWriteFlvTag(uint8_t ui8Type, const std::string &strBuf, uint32_t ui32TimeStamp);
|
||||
private:
|
||||
RtmpMediaSource::RingType::RingReader::Ptr _ring_reader;
|
||||
uint32_t m_aui32FirstStamp[2] = {0};
|
||||
uint32_t m_previousTagSize = 0;
|
||||
uint32_t _aui32FirstStamp[2] = {0};
|
||||
uint32_t _previousTagSize = 0;
|
||||
};
|
||||
|
||||
class FlvRecorder : public FlvMuxer , public std::enable_shared_from_this<FlvRecorder>{
|
||||
|
@ -60,66 +60,66 @@ public:
|
||||
|
||||
RtmpMediaSource(const string &vhost,const string &strApp, const string &strId) :
|
||||
MediaSource(RTMP_SCHEMA,vhost,strApp,strId),
|
||||
m_pRing(new RingBuffer<RtmpPacket::Ptr>()) {
|
||||
_pRing(new RingBuffer<RtmpPacket::Ptr>()) {
|
||||
}
|
||||
virtual ~RtmpMediaSource() {}
|
||||
|
||||
const RingType::Ptr &getRing() const {
|
||||
//获取媒体源的rtp环形缓冲
|
||||
return m_pRing;
|
||||
return _pRing;
|
||||
}
|
||||
|
||||
const AMFValue &getMetaData() const {
|
||||
lock_guard<recursive_mutex> lock(m_mtxMap);
|
||||
return m_metadata;
|
||||
lock_guard<recursive_mutex> lock(_mtxMap);
|
||||
return _metadata;
|
||||
}
|
||||
template<typename FUN>
|
||||
void getConfigFrame(const FUN &f) {
|
||||
lock_guard<recursive_mutex> lock(m_mtxMap);
|
||||
for (auto &pr : m_mapCfgFrame) {
|
||||
lock_guard<recursive_mutex> lock(_mtxMap);
|
||||
for (auto &pr : _mapCfgFrame) {
|
||||
f(pr.second);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void onGetMetaData(const AMFValue &_metadata) {
|
||||
lock_guard<recursive_mutex> lock(m_mtxMap);
|
||||
m_metadata = _metadata;
|
||||
RtmpParser parser(_metadata);
|
||||
m_iCfgFrameSize = parser.getTracks().size();
|
||||
virtual void onGetMetaData(const AMFValue &metadata) {
|
||||
lock_guard<recursive_mutex> lock(_mtxMap);
|
||||
_metadata = metadata;
|
||||
RtmpParser parser(metadata);
|
||||
_iCfgFrameSize = parser.getTracks().size();
|
||||
if(ready()){
|
||||
MediaSource::regist();
|
||||
m_bRegisted = true;
|
||||
_bRegisted = true;
|
||||
} else{
|
||||
m_bAsyncRegist = true;
|
||||
_bAsyncRegist = true;
|
||||
}
|
||||
}
|
||||
virtual void onGetMedia(const RtmpPacket::Ptr &pkt) {
|
||||
lock_guard<recursive_mutex> lock(m_mtxMap);
|
||||
lock_guard<recursive_mutex> lock(_mtxMap);
|
||||
if (pkt->isCfgFrame()) {
|
||||
m_mapCfgFrame.emplace(pkt->typeId, pkt);
|
||||
_mapCfgFrame.emplace(pkt->typeId, pkt);
|
||||
|
||||
if(m_bAsyncRegist && !m_bRegisted && m_mapCfgFrame.size() == m_iCfgFrameSize){
|
||||
m_bAsyncRegist = false;
|
||||
if(_bAsyncRegist && !_bRegisted && _mapCfgFrame.size() == _iCfgFrameSize){
|
||||
_bAsyncRegist = false;
|
||||
MediaSource::regist();
|
||||
m_bRegisted = true;
|
||||
_bRegisted = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_pRing->write(pkt,pkt->isVideoKeyFrame());
|
||||
_pRing->write(pkt,pkt->isVideoKeyFrame());
|
||||
}
|
||||
private:
|
||||
bool ready(){
|
||||
lock_guard<recursive_mutex> lock(m_mtxMap);
|
||||
return m_iCfgFrameSize != -1 && m_iCfgFrameSize == m_mapCfgFrame.size();
|
||||
lock_guard<recursive_mutex> lock(_mtxMap);
|
||||
return _iCfgFrameSize != -1 && _iCfgFrameSize == _mapCfgFrame.size();
|
||||
}
|
||||
protected:
|
||||
AMFValue m_metadata;
|
||||
unordered_map<int, RtmpPacket::Ptr> m_mapCfgFrame;
|
||||
mutable recursive_mutex m_mtxMap;
|
||||
RingBuffer<RtmpPacket::Ptr>::Ptr m_pRing; //rtp环形缓冲
|
||||
int m_iCfgFrameSize = -1;
|
||||
bool m_bAsyncRegist = false;
|
||||
bool m_bRegisted = false;
|
||||
AMFValue _metadata;
|
||||
unordered_map<int, RtmpPacket::Ptr> _mapCfgFrame;
|
||||
mutable recursive_mutex _mtxMap;
|
||||
RingBuffer<RtmpPacket::Ptr>::Ptr _pRing; //rtp环形缓冲
|
||||
int _iCfgFrameSize = -1;
|
||||
bool _bAsyncRegist = false;
|
||||
bool _bRegisted = false;
|
||||
};
|
||||
|
||||
} /* namespace Rtmp */
|
||||
|
@ -36,13 +36,13 @@ RtmpParser::RtmpParser(const AMFValue &val) {
|
||||
if (videoCodec.type() == AMF_STRING) {
|
||||
if (videoCodec.as_string() == "avc1") {
|
||||
//h264
|
||||
m_iVideoCodecID = H264_CODEC_ID;
|
||||
_iVideoCodecID = H264_CODEC_ID;
|
||||
} else {
|
||||
InfoL << "不支持RTMP视频格式:" << videoCodec.as_string();
|
||||
}
|
||||
}else if (videoCodec.type() != AMF_NULL){
|
||||
m_iVideoCodecID = videoCodec.as_integer();
|
||||
if (m_iVideoCodecID != H264_CODEC_ID) {
|
||||
_iVideoCodecID = videoCodec.as_integer();
|
||||
if (_iVideoCodecID != H264_CODEC_ID) {
|
||||
InfoL << "不支持RTMP视频格式:" << videoCodec.as_integer();
|
||||
}
|
||||
}
|
||||
@ -50,13 +50,13 @@ RtmpParser::RtmpParser(const AMFValue &val) {
|
||||
if (audioCodec.type() == AMF_STRING) {
|
||||
if (audioCodec.as_string() == "mp4a") {
|
||||
//aac
|
||||
m_iAudioCodecID = AAC_CODEC_ID;
|
||||
_iAudioCodecID = AAC_CODEC_ID;
|
||||
} else {
|
||||
InfoL << "不支持RTMP音频格式:" << audioCodec.as_string();
|
||||
}
|
||||
}else if (audioCodec.type() != AMF_NULL) {
|
||||
m_iAudioCodecID = audioCodec.as_integer();
|
||||
if (m_iAudioCodecID != AAC_CODEC_ID) {
|
||||
_iAudioCodecID = audioCodec.as_integer();
|
||||
if (_iAudioCodecID != AAC_CODEC_ID) {
|
||||
InfoL << "不支持RTMP音频格式:" << audioCodec.as_integer();
|
||||
}
|
||||
}
|
||||
@ -69,28 +69,28 @@ RtmpParser::~RtmpParser() {
|
||||
bool RtmpParser::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
||||
switch (pkt->typeId) {
|
||||
case MSG_VIDEO:{
|
||||
if(m_iVideoCodecID == 0){
|
||||
if(_iVideoCodecID == 0){
|
||||
//未初始化视频
|
||||
m_iVideoCodecID = pkt->getMediaType();
|
||||
if(m_iVideoCodecID != H264_CODEC_ID){
|
||||
InfoL << "不支持RTMP视频格式:" << m_iVideoCodecID;
|
||||
_iVideoCodecID = pkt->getMediaType();
|
||||
if(_iVideoCodecID != H264_CODEC_ID){
|
||||
InfoL << "不支持RTMP视频格式:" << _iVideoCodecID;
|
||||
}
|
||||
}
|
||||
if(m_iVideoCodecID == H264_CODEC_ID){
|
||||
if(_iVideoCodecID == H264_CODEC_ID){
|
||||
return inputVideo(pkt);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
case MSG_AUDIO: {
|
||||
if(m_iAudioCodecID == 0){
|
||||
if(_iAudioCodecID == 0){
|
||||
//未初始化音频
|
||||
m_iAudioCodecID = pkt->getMediaType();
|
||||
if(m_iAudioCodecID != AAC_CODEC_ID){
|
||||
InfoL << "不支持RTMP音频格式:" << m_iAudioCodecID;
|
||||
_iAudioCodecID = pkt->getMediaType();
|
||||
if(_iAudioCodecID != AAC_CODEC_ID){
|
||||
InfoL << "不支持RTMP音频格式:" << _iAudioCodecID;
|
||||
}
|
||||
}
|
||||
if (m_iAudioCodecID == AAC_CODEC_ID) {
|
||||
if (_iAudioCodecID == AAC_CODEC_ID) {
|
||||
return inputAudio(pkt);
|
||||
}
|
||||
return false;
|
||||
@ -104,20 +104,20 @@ bool RtmpParser::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
||||
inline bool RtmpParser::inputVideo(const RtmpPacket::Ptr &pkt) {
|
||||
if (pkt->isCfgFrame()) {
|
||||
//WarnL << " got h264 cfg";
|
||||
if (m_strSPS.size()) {
|
||||
if (_strSPS.size()) {
|
||||
return false;
|
||||
}
|
||||
m_strSPS.assign("\x00\x00\x00\x01", 4);
|
||||
m_strSPS.append(pkt->getH264SPS());
|
||||
_strSPS.assign("\x00\x00\x00\x01", 4);
|
||||
_strSPS.append(pkt->getH264SPS());
|
||||
|
||||
m_strPPS.assign("\x00\x00\x00\x01", 4);
|
||||
m_strPPS.append(pkt->getH264PPS());
|
||||
_strPPS.assign("\x00\x00\x00\x01", 4);
|
||||
_strPPS.append(pkt->getH264PPS());
|
||||
|
||||
getAVCInfo(pkt->getH264SPS(), m_iVideoWidth, m_iVideoHeight, m_fVideoFps);
|
||||
getAVCInfo(pkt->getH264SPS(), _iVideoWidth, _iVideoHeight, _fVideoFps);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_strSPS.size()) {
|
||||
if (_strSPS.size()) {
|
||||
uint32_t iTotalLen = pkt->strBuf.size();
|
||||
uint32_t iOffset = 5;
|
||||
while(iOffset + 4 < iTotalLen){
|
||||
@ -137,8 +137,8 @@ inline bool RtmpParser::inputVideo(const RtmpPacket::Ptr &pkt) {
|
||||
inline void RtmpParser::_onGetH264(const char* pcData, int iLen, uint32_t ui32TimeStamp) {
|
||||
switch (pcData[0] & 0x1F) {
|
||||
case 5: {
|
||||
onGetH264(m_strSPS.data() + 4, m_strSPS.length() - 4, ui32TimeStamp);
|
||||
onGetH264(m_strPPS.data() + 4, m_strPPS.length() - 4, ui32TimeStamp);
|
||||
onGetH264(_strSPS.data() + 4, _strSPS.length() - 4, ui32TimeStamp);
|
||||
onGetH264(_strPPS.data() + 4, _strPPS.length() - 4, ui32TimeStamp);
|
||||
}
|
||||
case 1: {
|
||||
onGetH264(pcData, iLen, ui32TimeStamp);
|
||||
@ -150,82 +150,82 @@ inline void RtmpParser::_onGetH264(const char* pcData, int iLen, uint32_t ui32Ti
|
||||
}
|
||||
}
|
||||
inline void RtmpParser::onGetH264(const char* pcData, int iLen, uint32_t ui32TimeStamp) {
|
||||
m_h264frame.type = pcData[0] & 0x1F;
|
||||
m_h264frame.timeStamp = ui32TimeStamp;
|
||||
m_h264frame.buffer.assign("\x0\x0\x0\x1", 4); //添加264头
|
||||
m_h264frame.buffer.append(pcData, iLen);
|
||||
_h264frame.type = pcData[0] & 0x1F;
|
||||
_h264frame.timeStamp = ui32TimeStamp;
|
||||
_h264frame.buffer.assign("\x0\x0\x0\x1", 4); //添加264头
|
||||
_h264frame.buffer.append(pcData, iLen);
|
||||
{
|
||||
lock_guard<recursive_mutex> lck(m_mtxCB);
|
||||
lock_guard<recursive_mutex> lck(_mtxCB);
|
||||
if (onVideo) {
|
||||
onVideo(m_h264frame);
|
||||
onVideo(_h264frame);
|
||||
}
|
||||
}
|
||||
m_h264frame.buffer.clear();
|
||||
_h264frame.buffer.clear();
|
||||
}
|
||||
|
||||
inline bool RtmpParser::inputAudio(const RtmpPacket::Ptr &pkt) {
|
||||
if (pkt->isCfgFrame()) {
|
||||
if (m_strAudioCfg.size()) {
|
||||
if (_strAudioCfg.size()) {
|
||||
return false;
|
||||
}
|
||||
m_strAudioCfg = pkt->getAacCfg();
|
||||
m_iSampleBit = pkt->getAudioSampleBit();
|
||||
makeAdtsHeader(m_strAudioCfg,m_adts);
|
||||
getAACInfo(m_adts, m_iSampleRate, m_iChannel);
|
||||
_strAudioCfg = pkt->getAacCfg();
|
||||
_iSampleBit = pkt->getAudioSampleBit();
|
||||
makeAdtsHeader(_strAudioCfg,_adts);
|
||||
getAACInfo(_adts, _iSampleRate, _iChannel);
|
||||
return false;
|
||||
}
|
||||
if (m_strAudioCfg.size()) {
|
||||
if (_strAudioCfg.size()) {
|
||||
onGetAAC(pkt->strBuf.data() + 2, pkt->strBuf.size() - 2, pkt->timeStamp);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline void RtmpParser::onGetAAC(const char* pcData, int iLen, uint32_t ui32TimeStamp) {
|
||||
if(iLen + 7 > sizeof(m_adts.buffer)){
|
||||
if(iLen + 7 > sizeof(_adts.buffer)){
|
||||
WarnL << "Illegal adts data, exceeding the length limit.";
|
||||
return;
|
||||
}
|
||||
//添加adts头
|
||||
memcpy(m_adts.buffer + 7, pcData, iLen);
|
||||
m_adts.aac_frame_length = 7 + iLen;
|
||||
m_adts.timeStamp = ui32TimeStamp;
|
||||
writeAdtsHeader(m_adts, m_adts.buffer);
|
||||
memcpy(_adts.buffer + 7, pcData, iLen);
|
||||
_adts.aac_frame_length = 7 + iLen;
|
||||
_adts.timeStamp = ui32TimeStamp;
|
||||
writeAdtsHeader(_adts, _adts.buffer);
|
||||
{
|
||||
lock_guard<recursive_mutex> lck(m_mtxCB);
|
||||
lock_guard<recursive_mutex> lck(_mtxCB);
|
||||
if (onAudio) {
|
||||
onAudio(m_adts);
|
||||
onAudio(_adts);
|
||||
}
|
||||
}
|
||||
m_adts.aac_frame_length = 7;
|
||||
_adts.aac_frame_length = 7;
|
||||
|
||||
}
|
||||
inline void RtmpParser::onCheckMedia(const AMFValue& obj) {
|
||||
obj.object_for_each([&](const string &key ,const AMFValue& val) {
|
||||
if(key == "duration") {
|
||||
m_fDuration = val.as_number();
|
||||
_fDuration = val.as_number();
|
||||
return;
|
||||
}
|
||||
if(key == "width") {
|
||||
m_iVideoWidth = val.as_number();
|
||||
_iVideoWidth = val.as_number();
|
||||
return;
|
||||
}
|
||||
if(key == "height") {
|
||||
m_iVideoHeight = val.as_number();
|
||||
_iVideoHeight = val.as_number();
|
||||
return;
|
||||
}
|
||||
if(key == "framerate") {
|
||||
m_fVideoFps = val.as_number();
|
||||
_fVideoFps = val.as_number();
|
||||
return;
|
||||
}
|
||||
if(key == "audiosamplerate") {
|
||||
m_iSampleRate = val.as_number();
|
||||
_iSampleRate = val.as_number();
|
||||
return;
|
||||
}
|
||||
if(key == "audiosamplesize") {
|
||||
m_iSampleBit = val.as_number();
|
||||
_iSampleBit = val.as_number();
|
||||
return;
|
||||
}
|
||||
if(key == "stereo") {
|
||||
m_iChannel = val.as_boolean() ? 2 :1;
|
||||
_iChannel = val.as_boolean() ? 2 :1;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
@ -54,19 +54,19 @@ public:
|
||||
bool inputRtmp(const RtmpPacket::Ptr &pkt);
|
||||
|
||||
bool isInited() const override{
|
||||
if((m_iAudioCodecID | m_iVideoCodecID) == 0){
|
||||
if((_iAudioCodecID | _iVideoCodecID) == 0){
|
||||
//音视频codec_id都未获取到,说明还未初始化成功
|
||||
return false;
|
||||
}
|
||||
if((m_iAudioCodecID & m_iVideoCodecID) == 0 && m_ticker.elapsedTime() < 300){
|
||||
if((_iAudioCodecID & _iVideoCodecID) == 0 && _ticker.elapsedTime() < 300){
|
||||
//音视频codec_id有其一未获取到,且最少分析300ms才能断定没有音频或视频
|
||||
return false;
|
||||
}
|
||||
if (m_iAudioCodecID && !m_strAudioCfg.size()) {
|
||||
if (_iAudioCodecID && !_strAudioCfg.size()) {
|
||||
//如果音频是aac但是还未获取aac config ,则未初始化成功
|
||||
return false;
|
||||
}
|
||||
if (m_iVideoCodecID && !m_strSPS.size()) {
|
||||
if (_iVideoCodecID && !_strSPS.size()) {
|
||||
//如果视频是h264但是还未获取sps ,则未初始化成功
|
||||
return false;
|
||||
}
|
||||
@ -74,7 +74,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
float getDuration() const override{
|
||||
return m_fDuration;
|
||||
return _fDuration;
|
||||
}
|
||||
private:
|
||||
inline void onCheckMedia(const AMFValue &obj);
|
||||
@ -86,28 +86,28 @@ private:
|
||||
inline void onGetH264(const char *pcData, int iLen, uint32_t ui32TimeStamp);
|
||||
inline void onGetAAC(const char *pcData, int iLen, uint32_t ui32TimeStamp);
|
||||
//video
|
||||
H264Frame m_h264frame;
|
||||
H264Frame _h264frame;
|
||||
//aduio
|
||||
AACFrame m_adts;
|
||||
AACFrame _adts;
|
||||
|
||||
int m_iSampleRate = 44100;
|
||||
int m_iSampleBit = 16;
|
||||
int m_iChannel = 1;
|
||||
int _iSampleRate = 44100;
|
||||
int _iSampleBit = 16;
|
||||
int _iChannel = 1;
|
||||
|
||||
string m_strSPS;
|
||||
string m_strPPS;
|
||||
string m_strAudioCfg;
|
||||
int m_iVideoWidth = 0;
|
||||
int m_iVideoHeight = 0;
|
||||
float m_fVideoFps = 0;
|
||||
string _strSPS;
|
||||
string _strPPS;
|
||||
string _strAudioCfg;
|
||||
int _iVideoWidth = 0;
|
||||
int _iVideoHeight = 0;
|
||||
float _fVideoFps = 0;
|
||||
//音视频codec_id初始为0代表尚未获取到
|
||||
int m_iAudioCodecID = 0;
|
||||
int m_iVideoCodecID = 0;
|
||||
float m_fDuration = 0;
|
||||
mutable Ticker m_ticker;
|
||||
int _iAudioCodecID = 0;
|
||||
int _iVideoCodecID = 0;
|
||||
float _fDuration = 0;
|
||||
mutable Ticker _ticker;
|
||||
function<void(const H264Frame &frame)> onVideo;
|
||||
function<void(const AACFrame &frame)> onAudio;
|
||||
recursive_mutex m_mtxCB;
|
||||
recursive_mutex _mtxCB;
|
||||
|
||||
|
||||
};
|
||||
|
@ -53,24 +53,24 @@ RtmpPlayer::~RtmpPlayer() {
|
||||
}
|
||||
void RtmpPlayer::teardown() {
|
||||
if (alive()) {
|
||||
m_strApp.clear();
|
||||
m_strStream.clear();
|
||||
m_strTcUrl.clear();
|
||||
_strApp.clear();
|
||||
_strStream.clear();
|
||||
_strTcUrl.clear();
|
||||
|
||||
{
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnResultCB);
|
||||
m_mapOnResultCB.clear();
|
||||
lock_guard<recursive_mutex> lck(_mtxOnResultCB);
|
||||
_mapOnResultCB.clear();
|
||||
}
|
||||
{
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnStatusCB);
|
||||
m_dqOnStatusCB.clear();
|
||||
lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
|
||||
_dqOnStatusCB.clear();
|
||||
}
|
||||
m_pBeatTimer.reset();
|
||||
m_pPlayTimer.reset();
|
||||
m_pMediaTimer.reset();
|
||||
m_fSeekTo = 0;
|
||||
CLEAR_ARR(m_adFistStamp);
|
||||
CLEAR_ARR(m_adNowStamp);
|
||||
_pBeatTimer.reset();
|
||||
_pPlayTimer.reset();
|
||||
_pMediaTimer.reset();
|
||||
_fSeekTo = 0;
|
||||
CLEAR_ARR(_adFistStamp);
|
||||
CLEAR_ARR(_adNowStamp);
|
||||
reset();
|
||||
shutdown();
|
||||
}
|
||||
@ -78,15 +78,15 @@ void RtmpPlayer::teardown() {
|
||||
void RtmpPlayer::play(const char* strUrl) {
|
||||
teardown();
|
||||
string strHost = FindField(strUrl, "://", "/");
|
||||
m_strApp = FindField(strUrl, (strHost + "/").data(), "/");
|
||||
m_strStream = FindField(strUrl, (strHost + "/" + m_strApp + "/").data(), NULL);
|
||||
m_strTcUrl = string("rtmp://") + strHost + "/" + m_strApp;
|
||||
_strApp = FindField(strUrl, (strHost + "/").data(), "/");
|
||||
_strStream = FindField(strUrl, (strHost + "/" + _strApp + "/").data(), NULL);
|
||||
_strTcUrl = string("rtmp://") + strHost + "/" + _strApp;
|
||||
|
||||
if (!m_strApp.size() || !m_strStream.size()) {
|
||||
if (!_strApp.size() || !_strStream.size()) {
|
||||
_onPlayResult(SockException(Err_other,"rtmp url非法"));
|
||||
return;
|
||||
}
|
||||
DebugL << strHost << " " << m_strApp << " " << m_strStream;
|
||||
DebugL << strHost << " " << _strApp << " " << _strStream;
|
||||
|
||||
auto iPort = atoi(FindField(strHost.c_str(), ":", NULL).c_str());
|
||||
if (iPort <= 0) {
|
||||
@ -111,7 +111,7 @@ void RtmpPlayer::onConnect(const SockException &err){
|
||||
}
|
||||
|
||||
weak_ptr<RtmpPlayer> weakSelf= dynamic_pointer_cast<RtmpPlayer>(shared_from_this());
|
||||
m_pPlayTimer.reset( new Timer(10, [weakSelf]() {
|
||||
_pPlayTimer.reset( new Timer(10, [weakSelf]() {
|
||||
auto strongSelf=weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return false;
|
||||
@ -145,8 +145,8 @@ void RtmpPlayer::pause(bool bPause) {
|
||||
|
||||
inline void RtmpPlayer::send_connect() {
|
||||
AMFValue obj(AMF_OBJECT);
|
||||
obj.set("app", m_strApp);
|
||||
obj.set("tcUrl", m_strTcUrl);
|
||||
obj.set("app", _strApp);
|
||||
obj.set("tcUrl", _strTcUrl);
|
||||
//未使用代理
|
||||
obj.set("fpad", false);
|
||||
//参考librtmp,什么作用?
|
||||
@ -177,14 +177,14 @@ inline void RtmpPlayer::send_createStream() {
|
||||
addOnResultCB([this](AMFDecoder &dec){
|
||||
//TraceL << "createStream result";
|
||||
dec.load<AMFValue>();
|
||||
m_ui32StreamId = dec.load<int>();
|
||||
_ui32StreamId = dec.load<int>();
|
||||
send_play();
|
||||
});
|
||||
}
|
||||
|
||||
inline void RtmpPlayer::send_play() {
|
||||
AMFEncoder enc;
|
||||
enc << "play" << ++m_iReqID << nullptr << m_strStream << (double)m_ui32StreamId;
|
||||
enc << "play" << ++_iReqID << nullptr << _strStream << (double)_ui32StreamId;
|
||||
sendRequest(MSG_CMD, enc.data());
|
||||
auto fun = [this](AMFValue &val){
|
||||
//TraceL << "play onStatus";
|
||||
@ -200,7 +200,7 @@ inline void RtmpPlayer::send_play() {
|
||||
|
||||
inline void RtmpPlayer::send_pause(bool bPause) {
|
||||
AMFEncoder enc;
|
||||
enc << "pause" << ++m_iReqID << nullptr << bPause;
|
||||
enc << "pause" << ++_iReqID << nullptr << bPause;
|
||||
sendRequest(MSG_CMD, enc.data());
|
||||
auto fun = [this,bPause](AMFValue &val){
|
||||
//TraceL << "pause onStatus";
|
||||
@ -211,21 +211,21 @@ inline void RtmpPlayer::send_pause(bool bPause) {
|
||||
throw std::runtime_error(StrPrinter <<"pause 恢复播放失败:" << level << " " << code << endl);
|
||||
}
|
||||
}else{
|
||||
m_bPaused = bPause;
|
||||
_bPaused = bPause;
|
||||
if(!bPause){
|
||||
_onPlayResult(SockException(Err_success, "rtmp resum success"));
|
||||
}else{
|
||||
//暂停播放
|
||||
m_pMediaTimer.reset();
|
||||
_pMediaTimer.reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
addOnStatusCB(fun);
|
||||
|
||||
m_pBeatTimer.reset();
|
||||
_pBeatTimer.reset();
|
||||
if(bPause){
|
||||
weak_ptr<RtmpPlayer> weakSelf = dynamic_pointer_cast<RtmpPlayer>(shared_from_this());
|
||||
m_pBeatTimer.reset(new Timer(3,[weakSelf](){
|
||||
_pBeatTimer.reset(new Timer(3,[weakSelf](){
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if (!strongSelf){
|
||||
return false;
|
||||
@ -239,11 +239,11 @@ inline void RtmpPlayer::send_pause(bool bPause) {
|
||||
|
||||
void RtmpPlayer::onCmd_result(AMFDecoder &dec){
|
||||
auto iReqId = dec.load<int>();
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnResultCB);
|
||||
auto it = m_mapOnResultCB.find(iReqId);
|
||||
if(it != m_mapOnResultCB.end()){
|
||||
lock_guard<recursive_mutex> lck(_mtxOnResultCB);
|
||||
auto it = _mapOnResultCB.find(iReqId);
|
||||
if(it != _mapOnResultCB.end()){
|
||||
it->second(dec);
|
||||
m_mapOnResultCB.erase(it);
|
||||
_mapOnResultCB.erase(it);
|
||||
}else{
|
||||
WarnL << "unhandled _result";
|
||||
}
|
||||
@ -260,10 +260,10 @@ void RtmpPlayer::onCmd_onStatus(AMFDecoder &dec) {
|
||||
throw std::runtime_error("onStatus:the result object was not found");
|
||||
}
|
||||
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnStatusCB);
|
||||
if(m_dqOnStatusCB.size()){
|
||||
m_dqOnStatusCB.front()(val);
|
||||
m_dqOnStatusCB.pop_front();
|
||||
lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
|
||||
if(_dqOnStatusCB.size()){
|
||||
_dqOnStatusCB.front()(val);
|
||||
_dqOnStatusCB.pop_front();
|
||||
}else{
|
||||
auto level = val["level"];
|
||||
auto code = val["code"].as_string();
|
||||
@ -311,8 +311,8 @@ void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) {
|
||||
case MSG_AUDIO:
|
||||
case MSG_VIDEO: {
|
||||
auto idx = chunkData.typeId%2;
|
||||
if (m_aNowStampTicker[idx].elapsedTime() > 500) {
|
||||
m_adNowStamp[idx] = chunkData.timeStamp;
|
||||
if (_aNowStampTicker[idx].elapsedTime() > 500) {
|
||||
_adNowStamp[idx] = chunkData.timeStamp;
|
||||
}
|
||||
_onMediaData(std::make_shared<RtmpPacket>(chunkData));
|
||||
}
|
||||
@ -326,27 +326,27 @@ void RtmpPlayer::onRtmpChunk(RtmpPacket &chunkData) {
|
||||
float RtmpPlayer::getProgressTime() const{
|
||||
double iTime[2] = {0,0};
|
||||
for(auto i = 0 ;i < 2 ;i++){
|
||||
iTime[i] = (m_adNowStamp[i] - m_adFistStamp[i]) / 1000.0;
|
||||
iTime[i] = (_adNowStamp[i] - _adFistStamp[i]) / 1000.0;
|
||||
}
|
||||
return m_fSeekTo + MAX(iTime[0],iTime[1]);
|
||||
return _fSeekTo + MAX(iTime[0],iTime[1]);
|
||||
}
|
||||
void RtmpPlayer::seekToTime(float fTime){
|
||||
if (m_bPaused) {
|
||||
if (_bPaused) {
|
||||
pause(false);
|
||||
}
|
||||
AMFEncoder enc;
|
||||
enc << "seek" << ++m_iReqID << nullptr << fTime * 1000.0;
|
||||
enc << "seek" << ++_iReqID << nullptr << fTime * 1000.0;
|
||||
sendRequest(MSG_CMD, enc.data());
|
||||
addOnStatusCB([this,fTime](AMFValue &val) {
|
||||
//TraceL << "seek result";
|
||||
m_aNowStampTicker[0].resetTime();
|
||||
m_aNowStampTicker[1].resetTime();
|
||||
_aNowStampTicker[0].resetTime();
|
||||
_aNowStampTicker[1].resetTime();
|
||||
float iTimeInc = fTime - getProgressTime();
|
||||
for(auto i = 0 ;i < 2 ;i++){
|
||||
m_adFistStamp[i] = m_adNowStamp[i] + iTimeInc * 1000.0;
|
||||
m_adNowStamp[i] = m_adFistStamp[i];
|
||||
_adFistStamp[i] = _adNowStamp[i] + iTimeInc * 1000.0;
|
||||
_adNowStamp[i] = _adFistStamp[i];
|
||||
}
|
||||
m_fSeekTo = fTime;
|
||||
_fSeekTo = fTime;
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -65,28 +65,28 @@ protected:
|
||||
private:
|
||||
void _onShutdown(const SockException &ex) {
|
||||
WarnL << ex.getErrCode() << " " << ex.what();
|
||||
m_pPlayTimer.reset();
|
||||
m_pMediaTimer.reset();
|
||||
m_pBeatTimer.reset();
|
||||
_pPlayTimer.reset();
|
||||
_pMediaTimer.reset();
|
||||
_pBeatTimer.reset();
|
||||
onShutdown(ex);
|
||||
}
|
||||
void _onMediaData(const RtmpPacket::Ptr &chunkData) {
|
||||
m_mediaTicker.resetTime();
|
||||
_mediaTicker.resetTime();
|
||||
onMediaData(chunkData);
|
||||
}
|
||||
void _onPlayResult(const SockException &ex) {
|
||||
WarnL << ex.getErrCode() << " " << ex.what();
|
||||
m_pPlayTimer.reset();
|
||||
m_pMediaTimer.reset();
|
||||
_pPlayTimer.reset();
|
||||
_pMediaTimer.reset();
|
||||
if (!ex) {
|
||||
m_mediaTicker.resetTime();
|
||||
_mediaTicker.resetTime();
|
||||
weak_ptr<RtmpPlayer> weakSelf = dynamic_pointer_cast<RtmpPlayer>(shared_from_this());
|
||||
m_pMediaTimer.reset( new Timer(5, [weakSelf]() {
|
||||
_pMediaTimer.reset( new Timer(5, [weakSelf]() {
|
||||
auto strongSelf=weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return false;
|
||||
}
|
||||
if(strongSelf->m_mediaTicker.elapsedTime()>10000) {
|
||||
if(strongSelf->_mediaTicker.elapsedTime()>10000) {
|
||||
//recv media timeout!
|
||||
strongSelf->_onShutdown(SockException(Err_timeout,"recv rtmp timeout"));
|
||||
strongSelf->teardown();
|
||||
@ -111,13 +111,13 @@ private:
|
||||
|
||||
template<typename FUN>
|
||||
inline void addOnResultCB(const FUN &fun) {
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnResultCB);
|
||||
m_mapOnResultCB.emplace(m_iReqID, fun);
|
||||
lock_guard<recursive_mutex> lck(_mtxOnResultCB);
|
||||
_mapOnResultCB.emplace(_iReqID, fun);
|
||||
}
|
||||
template<typename FUN>
|
||||
inline void addOnStatusCB(const FUN &fun) {
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnStatusCB);
|
||||
m_dqOnStatusCB.emplace_back(fun);
|
||||
lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
|
||||
_dqOnStatusCB.emplace_back(fun);
|
||||
}
|
||||
|
||||
void onCmd_result(AMFDecoder &dec);
|
||||
@ -129,31 +129,31 @@ private:
|
||||
inline void send_play();
|
||||
inline void send_pause(bool bPause);
|
||||
|
||||
string m_strApp;
|
||||
string m_strStream;
|
||||
string m_strTcUrl;
|
||||
bool m_bPaused = false;
|
||||
string _strApp;
|
||||
string _strStream;
|
||||
string _strTcUrl;
|
||||
bool _bPaused = false;
|
||||
|
||||
unordered_map<int, function<void(AMFDecoder &dec)> > m_mapOnResultCB;
|
||||
recursive_mutex m_mtxOnResultCB;
|
||||
deque<function<void(AMFValue &dec)> > m_dqOnStatusCB;
|
||||
recursive_mutex m_mtxOnStatusCB;
|
||||
unordered_map<int, function<void(AMFDecoder &dec)> > _mapOnResultCB;
|
||||
recursive_mutex _mtxOnResultCB;
|
||||
deque<function<void(AMFValue &dec)> > _dqOnStatusCB;
|
||||
recursive_mutex _mtxOnStatusCB;
|
||||
|
||||
typedef void (RtmpPlayer::*rtmpCMDHandle)(AMFDecoder &dec);
|
||||
static unordered_map<string, rtmpCMDHandle> g_mapCmd;
|
||||
|
||||
//超时功能实现
|
||||
Ticker m_mediaTicker;
|
||||
std::shared_ptr<Timer> m_pMediaTimer;
|
||||
std::shared_ptr<Timer> m_pPlayTimer;
|
||||
Ticker _mediaTicker;
|
||||
std::shared_ptr<Timer> _pMediaTimer;
|
||||
std::shared_ptr<Timer> _pPlayTimer;
|
||||
//心跳定时器
|
||||
std::shared_ptr<Timer> m_pBeatTimer;
|
||||
std::shared_ptr<Timer> _pBeatTimer;
|
||||
|
||||
//播放进度控制
|
||||
float m_fSeekTo = 0;
|
||||
double m_adFistStamp[2] = { 0, 0 };
|
||||
double m_adNowStamp[2] = { 0, 0 };
|
||||
Ticker m_aNowStampTicker[2];
|
||||
float _fSeekTo = 0;
|
||||
double _adFistStamp[2] = { 0, 0 };
|
||||
double _adNowStamp[2] = { 0, 0 };
|
||||
Ticker _aNowStampTicker[2];
|
||||
};
|
||||
|
||||
} /* namespace Rtmp */
|
||||
|
@ -63,32 +63,32 @@ public:
|
||||
private:
|
||||
//派生类回调函数
|
||||
bool onCheckMeta(AMFValue &val) override {
|
||||
m_pRtmpMediaSrc = dynamic_pointer_cast<RtmpMediaSource>(m_pMediaSrc);
|
||||
if(m_pRtmpMediaSrc){
|
||||
m_pRtmpMediaSrc->onGetMetaData(val);
|
||||
_pRtmpMediaSrc = dynamic_pointer_cast<RtmpMediaSource>(_pMediaSrc);
|
||||
if(_pRtmpMediaSrc){
|
||||
_pRtmpMediaSrc->onGetMetaData(val);
|
||||
}
|
||||
try {
|
||||
m_parser.reset(new RtmpParser(val));
|
||||
_parser.reset(new RtmpParser(val));
|
||||
//todo(xzl) 修复此处
|
||||
// m_parser->setOnVideoCB(m_onGetVideoCB);
|
||||
// m_parser->setOnAudioCB(m_onGetAudioCB);
|
||||
// _parser->setOnVideoCB(_onGetVideoCB);
|
||||
// _parser->setOnAudioCB(_onGetAudioCB);
|
||||
return true;
|
||||
} catch (std::exception &ex) {
|
||||
WarnL << ex.what();
|
||||
return m_pRtmpMediaSrc ? true : false;
|
||||
return _pRtmpMediaSrc ? true : false;
|
||||
}
|
||||
}
|
||||
void onMediaData(const RtmpPacket::Ptr &chunkData) override {
|
||||
if(m_parser){
|
||||
m_parser->inputRtmp(chunkData);
|
||||
if(_parser){
|
||||
_parser->inputRtmp(chunkData);
|
||||
}
|
||||
if(m_pRtmpMediaSrc){
|
||||
m_pRtmpMediaSrc->onGetMedia(chunkData);
|
||||
if(_pRtmpMediaSrc){
|
||||
_pRtmpMediaSrc->onGetMedia(chunkData);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
RtmpMediaSource::Ptr m_pRtmpMediaSrc;
|
||||
RtmpMediaSource::Ptr _pRtmpMediaSrc;
|
||||
};
|
||||
|
||||
|
||||
|
@ -76,7 +76,7 @@ namespace ZL {
|
||||
namespace Rtmp {
|
||||
|
||||
RtmpProtocol::RtmpProtocol() {
|
||||
m_nextHandle = [this](){
|
||||
_nextHandle = [this](){
|
||||
handle_C0C1();
|
||||
};
|
||||
}
|
||||
@ -85,25 +85,25 @@ RtmpProtocol::~RtmpProtocol() {
|
||||
}
|
||||
void RtmpProtocol::reset() {
|
||||
////////////ChunkSize////////////
|
||||
m_iChunkLenIn = DEFAULT_CHUNK_LEN;
|
||||
m_iChunkLenOut = DEFAULT_CHUNK_LEN;
|
||||
_iChunkLenIn = DEFAULT_CHUNK_LEN;
|
||||
_iChunkLenOut = DEFAULT_CHUNK_LEN;
|
||||
////////////Acknowledgement////////////
|
||||
m_ui32ByteSent = 0;
|
||||
m_ui32LastSent = 0;
|
||||
m_ui32WinSize = 0;
|
||||
_ui32ByteSent = 0;
|
||||
_ui32LastSent = 0;
|
||||
_ui32WinSize = 0;
|
||||
///////////PeerBandwidth///////////
|
||||
m_ui32Bandwidth = 2500000;
|
||||
m_ui8LimitType = 2;
|
||||
_ui32Bandwidth = 2500000;
|
||||
_ui8LimitType = 2;
|
||||
////////////Chunk////////////
|
||||
m_mapChunkData.clear();
|
||||
m_iNowStreamID = 0;
|
||||
m_iNowChunkID = 0;
|
||||
_mapChunkData.clear();
|
||||
_iNowStreamID = 0;
|
||||
_iNowChunkID = 0;
|
||||
//////////Invoke Request//////////
|
||||
m_iReqID = 0;
|
||||
_iReqID = 0;
|
||||
//////////Rtmp parser//////////
|
||||
m_strRcvBuf.clear();
|
||||
m_ui32StreamId = STREAM_CONTROL;
|
||||
m_nextHandle = [this]() {
|
||||
_strRcvBuf.clear();
|
||||
_ui32StreamId = STREAM_CONTROL;
|
||||
_nextHandle = [this]() {
|
||||
handle_C0C1();
|
||||
};
|
||||
}
|
||||
@ -132,7 +132,7 @@ void RtmpProtocol::sendChunkSize(uint32_t ui32Size) {
|
||||
uint32_t len = htonl(ui32Size);
|
||||
std::string set_chunk((char *) &len, 4);
|
||||
sendRequest(MSG_SET_CHUNK, set_chunk);
|
||||
m_iChunkLenOut = ui32Size;
|
||||
_iChunkLenOut = ui32Size;
|
||||
}
|
||||
|
||||
void RtmpProtocol::sendPingRequest(uint32_t ui32TimeStamp) {
|
||||
@ -173,20 +173,20 @@ void RtmpProtocol::sendUserControl(uint16_t ui16EventType,
|
||||
}
|
||||
|
||||
void RtmpProtocol::sendResponse(int iType, const string& str) {
|
||||
if(!m_bDataStarted && (iType == MSG_DATA)){
|
||||
m_bDataStarted = true;
|
||||
if(!_bDataStarted && (iType == MSG_DATA)){
|
||||
_bDataStarted = true;
|
||||
}
|
||||
sendRtmp(iType, m_iNowStreamID, str, 0, m_bDataStarted ? CHUNK_CLIENT_REQUEST_AFTER : CHUNK_CLIENT_REQUEST_BEFORE);
|
||||
sendRtmp(iType, _iNowStreamID, str, 0, _bDataStarted ? CHUNK_CLIENT_REQUEST_AFTER : CHUNK_CLIENT_REQUEST_BEFORE);
|
||||
}
|
||||
|
||||
void RtmpProtocol::sendInvoke(const string& strCmd, const AMFValue& val) {
|
||||
AMFEncoder enc;
|
||||
enc << strCmd << ++m_iReqID << val;
|
||||
enc << strCmd << ++_iReqID << val;
|
||||
sendRequest(MSG_CMD, enc.data());
|
||||
}
|
||||
|
||||
void RtmpProtocol::sendRequest(int iCmd, const string& str) {
|
||||
sendRtmp(iCmd, m_ui32StreamId, str, 0, CHUNK_SERVER_REQUEST);
|
||||
sendRtmp(iCmd, _ui32StreamId, str, 0, CHUNK_SERVER_REQUEST);
|
||||
}
|
||||
|
||||
void RtmpProtocol::sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId,
|
||||
@ -205,7 +205,7 @@ void RtmpProtocol::sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId,
|
||||
set_le32(header.streamId, ui32StreamId);
|
||||
|
||||
//估算rtmp包数据大小
|
||||
uint32_t capacity = ((bExtStamp ? 5 : 1) * (1 + (strBuf.size() / m_iChunkLenOut))) + strBuf.size() + sizeof(header);
|
||||
uint32_t capacity = ((bExtStamp ? 5 : 1) * (1 + (strBuf.size() / _iChunkLenOut))) + strBuf.size() + sizeof(header);
|
||||
uint32_t totalSize = 0;
|
||||
BufferRaw::Ptr buffer = obtainBuffer();
|
||||
buffer->setCapacity(capacity);
|
||||
@ -229,23 +229,23 @@ void RtmpProtocol::sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId,
|
||||
memcpy(buffer->data() + totalSize,acExtStamp, 4);
|
||||
totalSize += 4;
|
||||
}
|
||||
size_t chunk = min(m_iChunkLenOut, strBuf.size() - pos);
|
||||
size_t chunk = min(_iChunkLenOut, strBuf.size() - pos);
|
||||
memcpy(buffer->data() + totalSize,strBuf.data() + pos, chunk);
|
||||
totalSize += chunk;
|
||||
pos += chunk;
|
||||
}
|
||||
buffer->setSize(totalSize);
|
||||
onSendRawData(buffer);
|
||||
m_ui32ByteSent += totalSize;
|
||||
if (m_ui32WinSize > 0 && m_ui32ByteSent - m_ui32LastSent >= m_ui32WinSize) {
|
||||
m_ui32LastSent = m_ui32ByteSent;
|
||||
sendAcknowledgement(m_ui32ByteSent);
|
||||
_ui32ByteSent += totalSize;
|
||||
if (_ui32WinSize > 0 && _ui32ByteSent - _ui32LastSent >= _ui32WinSize) {
|
||||
_ui32LastSent = _ui32ByteSent;
|
||||
sendAcknowledgement(_ui32ByteSent);
|
||||
}
|
||||
}
|
||||
|
||||
void RtmpProtocol::onParseRtmp(const char *pcRawData, int iSize) {
|
||||
m_strRcvBuf.append(pcRawData, iSize);
|
||||
auto cb = m_nextHandle;
|
||||
_strRcvBuf.append(pcRawData, iSize);
|
||||
auto cb = _nextHandle;
|
||||
cb();
|
||||
}
|
||||
|
||||
@ -256,25 +256,25 @@ void RtmpProtocol::startClientSession(const function<void()> &callBack) {
|
||||
onSendRawData(obtainBuffer(&handshake_head, 1));
|
||||
RtmpHandshake c1(0);
|
||||
onSendRawData(obtainBuffer((char *) (&c1), sizeof(c1)));
|
||||
m_nextHandle = [this,callBack]() {
|
||||
_nextHandle = [this,callBack]() {
|
||||
//等待 S0+S1+S2
|
||||
handle_S0S1S2(callBack);
|
||||
};
|
||||
}
|
||||
void RtmpProtocol::handle_S0S1S2(const function<void()> &callBack) {
|
||||
if (m_strRcvBuf.size() < 1 + 2 * C1_HANDSHARK_SIZE) {
|
||||
if (_strRcvBuf.size() < 1 + 2 * C1_HANDSHARK_SIZE) {
|
||||
//数据不够
|
||||
return;
|
||||
}
|
||||
if (m_strRcvBuf[0] != HANDSHAKE_PLAINTEXT) {
|
||||
if (_strRcvBuf[0] != HANDSHAKE_PLAINTEXT) {
|
||||
throw std::runtime_error("only plaintext[0x03] handshake supported");
|
||||
}
|
||||
//发送 C2
|
||||
const char *pcC2 = m_strRcvBuf.data() + 1;
|
||||
const char *pcC2 = _strRcvBuf.data() + 1;
|
||||
onSendRawData(obtainBuffer(pcC2, C1_HANDSHARK_SIZE));
|
||||
m_strRcvBuf.erase(0, 1 + 2 * C1_HANDSHARK_SIZE);
|
||||
_strRcvBuf.erase(0, 1 + 2 * C1_HANDSHARK_SIZE);
|
||||
//握手结束
|
||||
m_nextHandle = [this]() {
|
||||
_nextHandle = [this]() {
|
||||
//握手结束并且开始进入解析命令模式
|
||||
handle_rtmp();
|
||||
};
|
||||
@ -282,14 +282,14 @@ void RtmpProtocol::handle_S0S1S2(const function<void()> &callBack) {
|
||||
}
|
||||
////for server ////
|
||||
void RtmpProtocol::handle_C0C1() {
|
||||
if (m_strRcvBuf.size() < 1 + C1_HANDSHARK_SIZE) {
|
||||
if (_strRcvBuf.size() < 1 + C1_HANDSHARK_SIZE) {
|
||||
//need more data!
|
||||
return;
|
||||
}
|
||||
if (m_strRcvBuf[0] != HANDSHAKE_PLAINTEXT) {
|
||||
if (_strRcvBuf[0] != HANDSHAKE_PLAINTEXT) {
|
||||
throw std::runtime_error("only plaintext[0x03] handshake supported");
|
||||
}
|
||||
if(memcmp(m_strRcvBuf.c_str() + 5,"\x00\x00\x00\x00",4) ==0 ){
|
||||
if(memcmp(_strRcvBuf.c_str() + 5,"\x00\x00\x00\x00",4) ==0 ){
|
||||
//simple handsharke
|
||||
handle_C1_simple();
|
||||
}else{
|
||||
@ -301,7 +301,7 @@ void RtmpProtocol::handle_C0C1() {
|
||||
handle_C1_simple();
|
||||
#endif//ENABLE_OPENSSL
|
||||
}
|
||||
m_strRcvBuf.erase(0, 1 + C1_HANDSHARK_SIZE);
|
||||
_strRcvBuf.erase(0, 1 + C1_HANDSHARK_SIZE);
|
||||
}
|
||||
void RtmpProtocol::handle_C1_simple(){
|
||||
//发送S0
|
||||
@ -311,9 +311,9 @@ void RtmpProtocol::handle_C1_simple(){
|
||||
RtmpHandshake s1(0);
|
||||
onSendRawData(obtainBuffer((char *) &s1, C1_HANDSHARK_SIZE));
|
||||
//发送S2
|
||||
onSendRawData(obtainBuffer(m_strRcvBuf.c_str() + 1, C1_HANDSHARK_SIZE));
|
||||
onSendRawData(obtainBuffer(_strRcvBuf.c_str() + 1, C1_HANDSHARK_SIZE));
|
||||
//等待C2
|
||||
m_nextHandle = [this]() {
|
||||
_nextHandle = [this]() {
|
||||
handle_C2();
|
||||
};
|
||||
}
|
||||
@ -321,7 +321,7 @@ void RtmpProtocol::handle_C1_simple(){
|
||||
void RtmpProtocol::handle_C1_complex(){
|
||||
//参考自:http://blog.csdn.net/win_lin/article/details/13006803
|
||||
//skip c0,time,version
|
||||
const char *c1_start = m_strRcvBuf.data() + 1;
|
||||
const char *c1_start = _strRcvBuf.data() + 1;
|
||||
const char *schema_start = c1_start + 8;
|
||||
char *digest_start;
|
||||
try{
|
||||
@ -470,57 +470,57 @@ void RtmpProtocol::send_complex_S0S1S2(int schemeType,const string &digest){
|
||||
memcpy((char *)&s2 + C1_HANDSHARK_SIZE - C1_DIGEST_SIZE,s2_digest.data(),C1_DIGEST_SIZE);
|
||||
onSendRawData(obtainBuffer((char *)&s2, sizeof(s2)));
|
||||
//等待C2
|
||||
m_nextHandle = [this]() {
|
||||
_nextHandle = [this]() {
|
||||
handle_C2();
|
||||
};
|
||||
}
|
||||
#endif //ENABLE_OPENSSL
|
||||
void RtmpProtocol::handle_C2() {
|
||||
if (m_strRcvBuf.size() < C1_HANDSHARK_SIZE) {
|
||||
if (_strRcvBuf.size() < C1_HANDSHARK_SIZE) {
|
||||
//need more data!
|
||||
return;
|
||||
}
|
||||
m_strRcvBuf.erase(0, C1_HANDSHARK_SIZE);
|
||||
_strRcvBuf.erase(0, C1_HANDSHARK_SIZE);
|
||||
//握手结束,进入命令模式
|
||||
if (!m_strRcvBuf.empty()) {
|
||||
if (!_strRcvBuf.empty()) {
|
||||
handle_rtmp();
|
||||
}
|
||||
m_nextHandle = [this]() {
|
||||
_nextHandle = [this]() {
|
||||
handle_rtmp();
|
||||
};
|
||||
}
|
||||
|
||||
void RtmpProtocol::handle_rtmp() {
|
||||
while (!m_strRcvBuf.empty()) {
|
||||
uint8_t flags = m_strRcvBuf[0];
|
||||
while (!_strRcvBuf.empty()) {
|
||||
uint8_t flags = _strRcvBuf[0];
|
||||
int iOffset = 0;
|
||||
static const size_t HEADER_LENGTH[] = { 12, 8, 4, 1 };
|
||||
size_t iHeaderLen = HEADER_LENGTH[flags >> 6];
|
||||
m_iNowChunkID = flags & 0x3f;
|
||||
if(m_iNowChunkID >10){
|
||||
_iNowChunkID = flags & 0x3f;
|
||||
if(_iNowChunkID >10){
|
||||
int i=0;
|
||||
i++;
|
||||
}
|
||||
switch (m_iNowChunkID) {
|
||||
switch (_iNowChunkID) {
|
||||
case 0: {
|
||||
//0 值表示二字节形式,并且 ID 范围 64 - 319
|
||||
//(第二个字节 + 64)。
|
||||
if (m_strRcvBuf.size() < 2) {
|
||||
if (_strRcvBuf.size() < 2) {
|
||||
//need more data
|
||||
return;
|
||||
}
|
||||
m_iNowChunkID = 64 + (uint8_t) (m_strRcvBuf[1]);
|
||||
_iNowChunkID = 64 + (uint8_t) (_strRcvBuf[1]);
|
||||
iOffset = 1;
|
||||
}
|
||||
break;
|
||||
case 1: {
|
||||
//1 值表示三字节形式,并且 ID 范围为 64 - 65599
|
||||
//((第三个字节) * 256 + 第二个字节 + 64)。
|
||||
if (m_strRcvBuf.size() < 3) {
|
||||
if (_strRcvBuf.size() < 3) {
|
||||
//need more data
|
||||
return;
|
||||
}
|
||||
m_iNowChunkID = 64 + ((uint8_t) (m_strRcvBuf[2]) << 8) + (uint8_t) (m_strRcvBuf[1]);
|
||||
_iNowChunkID = 64 + ((uint8_t) (_strRcvBuf[2]) << 8) + (uint8_t) (_strRcvBuf[1]);
|
||||
iOffset = 2;
|
||||
}
|
||||
break;
|
||||
@ -529,13 +529,13 @@ void RtmpProtocol::handle_rtmp() {
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_strRcvBuf.size() < iHeaderLen + iOffset) {
|
||||
if (_strRcvBuf.size() < iHeaderLen + iOffset) {
|
||||
//need more data
|
||||
return;
|
||||
}
|
||||
RtmpHeader &header = *((RtmpHeader *) (m_strRcvBuf.data() + iOffset));
|
||||
auto &chunkData = m_mapChunkData[m_iNowChunkID];
|
||||
chunkData.chunkId = m_iNowChunkID;
|
||||
RtmpHeader &header = *((RtmpHeader *) (_strRcvBuf.data() + iOffset));
|
||||
auto &chunkData = _mapChunkData[_iNowChunkID];
|
||||
chunkData.chunkId = _iNowChunkID;
|
||||
switch (iHeaderLen) {
|
||||
case 12:
|
||||
chunkData.hasAbsStamp = true;
|
||||
@ -549,11 +549,11 @@ void RtmpProtocol::handle_rtmp() {
|
||||
}
|
||||
|
||||
if (chunkData.hasExtStamp) {
|
||||
if (m_strRcvBuf.size() < iHeaderLen + iOffset + 4) {
|
||||
if (_strRcvBuf.size() < iHeaderLen + iOffset + 4) {
|
||||
//need more data
|
||||
return;
|
||||
}
|
||||
chunkData.deltaStamp = load_be32(m_strRcvBuf.data() + iOffset + iHeaderLen);
|
||||
chunkData.deltaStamp = load_be32(_strRcvBuf.data() + iOffset + iHeaderLen);
|
||||
iOffset += 4;
|
||||
}
|
||||
|
||||
@ -561,18 +561,18 @@ void RtmpProtocol::handle_rtmp() {
|
||||
throw std::runtime_error("非法的bodySize");
|
||||
}
|
||||
|
||||
auto iMore = min(m_iChunkLenIn, chunkData.bodySize - chunkData.strBuf.size());
|
||||
if (m_strRcvBuf.size() < iHeaderLen + iOffset + iMore) {
|
||||
auto iMore = min(_iChunkLenIn, chunkData.bodySize - chunkData.strBuf.size());
|
||||
if (_strRcvBuf.size() < iHeaderLen + iOffset + iMore) {
|
||||
//need more data
|
||||
return;
|
||||
}
|
||||
|
||||
chunkData.strBuf.append(m_strRcvBuf, iHeaderLen + iOffset, iMore);
|
||||
m_strRcvBuf.erase(0, iHeaderLen + iOffset + iMore);
|
||||
chunkData.strBuf.append(_strRcvBuf, iHeaderLen + iOffset, iMore);
|
||||
_strRcvBuf.erase(0, iHeaderLen + iOffset + iMore);
|
||||
|
||||
if (chunkData.strBuf.size() == chunkData.bodySize) {
|
||||
//frame is ready
|
||||
m_iNowStreamID = chunkData.streamId;
|
||||
_iNowStreamID = chunkData.streamId;
|
||||
chunkData.timeStamp = chunkData.deltaStamp + (chunkData.hasAbsStamp ? 0 : chunkData.timeStamp);
|
||||
|
||||
if(chunkData.bodySize){
|
||||
@ -600,8 +600,8 @@ void RtmpProtocol::handle_rtmpChunk(RtmpPacket& chunkData) {
|
||||
if (chunkData.strBuf.size() < 4) {
|
||||
throw std::runtime_error("MSG_SET_CHUNK :Not enough data");
|
||||
}
|
||||
m_iChunkLenIn = load_be32(&chunkData.strBuf[0]);
|
||||
TraceL << "MSG_SET_CHUNK:" << m_iChunkLenIn;
|
||||
_iChunkLenIn = load_be32(&chunkData.strBuf[0]);
|
||||
TraceL << "MSG_SET_CHUNK:" << _iChunkLenIn;
|
||||
}
|
||||
break;
|
||||
case MSG_USER_CONTROL: {
|
||||
@ -668,14 +668,14 @@ void RtmpProtocol::handle_rtmpChunk(RtmpPacket& chunkData) {
|
||||
break;
|
||||
|
||||
case MSG_WIN_SIZE: {
|
||||
m_ui32WinSize = load_be32(&chunkData.strBuf[0]);
|
||||
TraceL << "MSG_WIN_SIZE:" << m_ui32WinSize;
|
||||
_ui32WinSize = load_be32(&chunkData.strBuf[0]);
|
||||
TraceL << "MSG_WIN_SIZE:" << _ui32WinSize;
|
||||
}
|
||||
break;
|
||||
case MSG_SET_PEER_BW: {
|
||||
m_ui32Bandwidth = load_be32(&chunkData.strBuf[0]);
|
||||
m_ui8LimitType = chunkData.strBuf[4];
|
||||
TraceL << "MSG_SET_PEER_BW:" << m_ui32WinSize;
|
||||
_ui32Bandwidth = load_be32(&chunkData.strBuf[0]);
|
||||
_ui8LimitType = chunkData.strBuf[4];
|
||||
TraceL << "MSG_SET_PEER_BW:" << _ui32WinSize;
|
||||
}
|
||||
break;
|
||||
case MSG_AGGREGATE:
|
||||
|
@ -57,7 +57,7 @@ protected:
|
||||
virtual void onSendRawData(const Buffer::Ptr &buffer) = 0;
|
||||
virtual void onRtmpChunk(RtmpPacket &chunkData) = 0;
|
||||
virtual void onStreamBegin(uint32_t ui32StreamId){
|
||||
m_ui32StreamId = ui32StreamId;
|
||||
_ui32StreamId = ui32StreamId;
|
||||
}
|
||||
virtual void onStreamEof(uint32_t ui32StreamId){};
|
||||
virtual void onStreamDry(uint32_t ui32StreamId){};
|
||||
@ -77,14 +77,14 @@ protected:
|
||||
void sendResponse(int iType, const string &str);
|
||||
void sendRtmp(uint8_t ui8Type, uint32_t ui32StreamId, const std::string &strBuf, uint32_t ui32TimeStamp, int iChunkID);
|
||||
protected:
|
||||
int m_iReqID = 0;
|
||||
uint32_t m_ui32StreamId = STREAM_CONTROL;
|
||||
int m_iNowStreamID = 0;
|
||||
int m_iNowChunkID = 0;
|
||||
bool m_bDataStarted = false;
|
||||
int _iReqID = 0;
|
||||
uint32_t _ui32StreamId = STREAM_CONTROL;
|
||||
int _iNowStreamID = 0;
|
||||
int _iNowChunkID = 0;
|
||||
bool _bDataStarted = false;
|
||||
inline BufferRaw::Ptr obtainBuffer();
|
||||
inline BufferRaw::Ptr obtainBuffer(const void *data, int len);
|
||||
//ResourcePool<BufferRaw,MAX_SEND_PKT> m_bufferPool;
|
||||
//ResourcePool<BufferRaw,MAX_SEND_PKT> _bufferPool;
|
||||
private:
|
||||
void handle_S0S1S2(const function<void()> &cb);
|
||||
void handle_C0C1();
|
||||
@ -103,20 +103,20 @@ private:
|
||||
|
||||
private:
|
||||
////////////ChunkSize////////////
|
||||
size_t m_iChunkLenIn = DEFAULT_CHUNK_LEN;
|
||||
size_t m_iChunkLenOut = DEFAULT_CHUNK_LEN;
|
||||
size_t _iChunkLenIn = DEFAULT_CHUNK_LEN;
|
||||
size_t _iChunkLenOut = DEFAULT_CHUNK_LEN;
|
||||
////////////Acknowledgement////////////
|
||||
uint32_t m_ui32ByteSent = 0;
|
||||
uint32_t m_ui32LastSent = 0;
|
||||
uint32_t m_ui32WinSize = 0;
|
||||
uint32_t _ui32ByteSent = 0;
|
||||
uint32_t _ui32LastSent = 0;
|
||||
uint32_t _ui32WinSize = 0;
|
||||
///////////PeerBandwidth///////////
|
||||
uint32_t m_ui32Bandwidth = 2500000;
|
||||
uint8_t m_ui8LimitType = 2;
|
||||
uint32_t _ui32Bandwidth = 2500000;
|
||||
uint8_t _ui8LimitType = 2;
|
||||
////////////Chunk////////////
|
||||
unordered_map<int, RtmpPacket> m_mapChunkData;
|
||||
unordered_map<int, RtmpPacket> _mapChunkData;
|
||||
//////////Rtmp parser//////////
|
||||
string m_strRcvBuf;
|
||||
function<void()> m_nextHandle;
|
||||
string _strRcvBuf;
|
||||
function<void()> _nextHandle;
|
||||
};
|
||||
|
||||
} /* namespace Rtmp */
|
||||
|
@ -56,7 +56,7 @@ void RtmpPusher::init(const RtmpMediaSource::Ptr &src){
|
||||
g_mapCmd.emplace("_result",&RtmpPusher::onCmd_result);
|
||||
g_mapCmd.emplace("onStatus",&RtmpPusher::onCmd_onStatus);
|
||||
}, []() {});
|
||||
m_pMediaSrc=src;
|
||||
_pMediaSrc=src;
|
||||
}
|
||||
|
||||
RtmpPusher::~RtmpPusher() {
|
||||
@ -65,18 +65,18 @@ RtmpPusher::~RtmpPusher() {
|
||||
}
|
||||
void RtmpPusher::teardown() {
|
||||
if (alive()) {
|
||||
m_strApp.clear();
|
||||
m_strStream.clear();
|
||||
m_strTcUrl.clear();
|
||||
_strApp.clear();
|
||||
_strStream.clear();
|
||||
_strTcUrl.clear();
|
||||
{
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnResultCB);
|
||||
m_mapOnResultCB.clear();
|
||||
lock_guard<recursive_mutex> lck(_mtxOnResultCB);
|
||||
_mapOnResultCB.clear();
|
||||
}
|
||||
{
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnStatusCB);
|
||||
m_dqOnStatusCB.clear();
|
||||
lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
|
||||
_dqOnStatusCB.clear();
|
||||
}
|
||||
m_pPublishTimer.reset();
|
||||
_pPublishTimer.reset();
|
||||
reset();
|
||||
shutdown();
|
||||
}
|
||||
@ -85,15 +85,15 @@ void RtmpPusher::teardown() {
|
||||
void RtmpPusher::publish(const char* strUrl) {
|
||||
teardown();
|
||||
string strHost = FindField(strUrl, "://", "/");
|
||||
m_strApp = FindField(strUrl, (strHost + "/").data(), "/");
|
||||
m_strStream = FindField(strUrl, (strHost + "/" + m_strApp + "/").data(), NULL);
|
||||
m_strTcUrl = string("rtmp://") + strHost + "/" + m_strApp;
|
||||
_strApp = FindField(strUrl, (strHost + "/").data(), "/");
|
||||
_strStream = FindField(strUrl, (strHost + "/" + _strApp + "/").data(), NULL);
|
||||
_strTcUrl = string("rtmp://") + strHost + "/" + _strApp;
|
||||
|
||||
if (!m_strApp.size() || !m_strStream.size()) {
|
||||
if (!_strApp.size() || !_strStream.size()) {
|
||||
onPublishResult(SockException(Err_other,"rtmp url非法"));
|
||||
return;
|
||||
}
|
||||
DebugL << strHost << " " << m_strApp << " " << m_strStream;
|
||||
DebugL << strHost << " " << _strApp << " " << _strStream;
|
||||
|
||||
auto iPort = atoi(FindField(strHost.c_str(), ":", NULL).c_str());
|
||||
if (iPort <= 0) {
|
||||
@ -115,7 +115,7 @@ void RtmpPusher::onConnect(const SockException &err){
|
||||
return;
|
||||
}
|
||||
weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this());
|
||||
m_pPublishTimer.reset( new Timer(10, [weakSelf]() {
|
||||
_pPublishTimer.reset( new Timer(10, [weakSelf]() {
|
||||
auto strongSelf=weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return false;
|
||||
@ -147,10 +147,10 @@ void RtmpPusher::onRecv(const Buffer::Ptr &pBuf){
|
||||
|
||||
inline void RtmpPusher::send_connect() {
|
||||
AMFValue obj(AMF_OBJECT);
|
||||
obj.set("app", m_strApp);
|
||||
obj.set("app", _strApp);
|
||||
obj.set("type", "nonprivate");
|
||||
obj.set("tcUrl", m_strTcUrl);
|
||||
obj.set("swfUrl", m_strTcUrl);
|
||||
obj.set("tcUrl", _strTcUrl);
|
||||
obj.set("swfUrl", _strTcUrl);
|
||||
sendInvoke("connect", obj);
|
||||
addOnResultCB([this](AMFDecoder &dec){
|
||||
//TraceL << "connect result";
|
||||
@ -171,13 +171,13 @@ inline void RtmpPusher::send_createStream() {
|
||||
addOnResultCB([this](AMFDecoder &dec){
|
||||
//TraceL << "createStream result";
|
||||
dec.load<AMFValue>();
|
||||
m_ui32StreamId = dec.load<int>();
|
||||
_ui32StreamId = dec.load<int>();
|
||||
send_publish();
|
||||
});
|
||||
}
|
||||
inline void RtmpPusher::send_publish() {
|
||||
AMFEncoder enc;
|
||||
enc << "publish" << ++m_iReqID << nullptr << m_strStream << m_strApp ;
|
||||
enc << "publish" << ++_iReqID << nullptr << _strStream << _strApp ;
|
||||
sendRequest(MSG_CMD, enc.data());
|
||||
|
||||
addOnStatusCB([this](AMFValue &val) {
|
||||
@ -192,7 +192,7 @@ inline void RtmpPusher::send_publish() {
|
||||
}
|
||||
|
||||
inline void RtmpPusher::send_metaData(){
|
||||
auto src = m_pMediaSrc.lock();
|
||||
auto src = _pMediaSrc.lock();
|
||||
if (!src) {
|
||||
throw std::runtime_error("the media source was released");
|
||||
}
|
||||
@ -202,19 +202,19 @@ inline void RtmpPusher::send_metaData(){
|
||||
sendRequest(MSG_DATA, enc.data());
|
||||
|
||||
src->getConfigFrame([&](const RtmpPacket::Ptr &pkt){
|
||||
sendRtmp(pkt->typeId, m_ui32StreamId, pkt->strBuf, pkt->timeStamp, pkt->chunkId );
|
||||
sendRtmp(pkt->typeId, _ui32StreamId, pkt->strBuf, pkt->timeStamp, pkt->chunkId );
|
||||
});
|
||||
|
||||
m_pRtmpReader = src->getRing()->attach();
|
||||
_pRtmpReader = src->getRing()->attach();
|
||||
weak_ptr<RtmpPusher> weakSelf = dynamic_pointer_cast<RtmpPusher>(shared_from_this());
|
||||
m_pRtmpReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt){
|
||||
_pRtmpReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt){
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
}
|
||||
strongSelf->sendRtmp(pkt->typeId, strongSelf->m_ui32StreamId, pkt->strBuf, pkt->timeStamp, pkt->chunkId);
|
||||
strongSelf->sendRtmp(pkt->typeId, strongSelf->_ui32StreamId, pkt->strBuf, pkt->timeStamp, pkt->chunkId);
|
||||
});
|
||||
m_pRtmpReader->setDetachCB([weakSelf](){
|
||||
_pRtmpReader->setDetachCB([weakSelf](){
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(strongSelf){
|
||||
strongSelf->onShutdown(SockException(Err_other,"媒体源被释放"));
|
||||
@ -228,11 +228,11 @@ inline void RtmpPusher::send_metaData(){
|
||||
}
|
||||
void RtmpPusher::onCmd_result(AMFDecoder &dec){
|
||||
auto iReqId = dec.load<int>();
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnResultCB);
|
||||
auto it = m_mapOnResultCB.find(iReqId);
|
||||
if(it != m_mapOnResultCB.end()){
|
||||
lock_guard<recursive_mutex> lck(_mtxOnResultCB);
|
||||
auto it = _mapOnResultCB.find(iReqId);
|
||||
if(it != _mapOnResultCB.end()){
|
||||
it->second(dec);
|
||||
m_mapOnResultCB.erase(it);
|
||||
_mapOnResultCB.erase(it);
|
||||
}else{
|
||||
WarnL << "unhandled _result";
|
||||
}
|
||||
@ -249,10 +249,10 @@ void RtmpPusher::onCmd_onStatus(AMFDecoder &dec) {
|
||||
throw std::runtime_error("onStatus:the result object was not found");
|
||||
}
|
||||
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnStatusCB);
|
||||
if(m_dqOnStatusCB.size()){
|
||||
m_dqOnStatusCB.front()(val);
|
||||
m_dqOnStatusCB.pop_front();
|
||||
lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
|
||||
if(_dqOnStatusCB.size()){
|
||||
_dqOnStatusCB.front()(val);
|
||||
_dqOnStatusCB.pop_front();
|
||||
}else{
|
||||
auto level = val["level"];
|
||||
auto code = val["code"].as_string();
|
||||
|
@ -46,11 +46,11 @@ public:
|
||||
void teardown();
|
||||
|
||||
void setOnPublished(Event onPublished) {
|
||||
m_onPublished = onPublished;
|
||||
_onPublished = onPublished;
|
||||
}
|
||||
|
||||
void setOnShutdown(Event onShutdown) {
|
||||
m_onShutdown = onShutdown;
|
||||
_onShutdown = onShutdown;
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -67,28 +67,28 @@ protected:
|
||||
private:
|
||||
void init(const RtmpMediaSource::Ptr &src);
|
||||
void onShutdown(const SockException &ex) {
|
||||
m_pPublishTimer.reset();
|
||||
if(m_onShutdown){
|
||||
m_onShutdown(ex);
|
||||
_pPublishTimer.reset();
|
||||
if(_onShutdown){
|
||||
_onShutdown(ex);
|
||||
}
|
||||
m_pRtmpReader.reset();
|
||||
_pRtmpReader.reset();
|
||||
}
|
||||
void onPublishResult(const SockException &ex) {
|
||||
m_pPublishTimer.reset();
|
||||
if(m_onPublished){
|
||||
m_onPublished(ex);
|
||||
_pPublishTimer.reset();
|
||||
if(_onPublished){
|
||||
_onPublished(ex);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FUN>
|
||||
inline void addOnResultCB(const FUN &fun) {
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnResultCB);
|
||||
m_mapOnResultCB.emplace(m_iReqID, fun);
|
||||
lock_guard<recursive_mutex> lck(_mtxOnResultCB);
|
||||
_mapOnResultCB.emplace(_iReqID, fun);
|
||||
}
|
||||
template<typename FUN>
|
||||
inline void addOnStatusCB(const FUN &fun) {
|
||||
lock_guard<recursive_mutex> lck(m_mtxOnStatusCB);
|
||||
m_dqOnStatusCB.emplace_back(fun);
|
||||
lock_guard<recursive_mutex> lck(_mtxOnStatusCB);
|
||||
_dqOnStatusCB.emplace_back(fun);
|
||||
}
|
||||
|
||||
void onCmd_result(AMFDecoder &dec);
|
||||
@ -100,27 +100,27 @@ private:
|
||||
inline void send_publish();
|
||||
inline void send_metaData();
|
||||
|
||||
string m_strApp;
|
||||
string m_strStream;
|
||||
string m_strTcUrl;
|
||||
string _strApp;
|
||||
string _strStream;
|
||||
string _strTcUrl;
|
||||
|
||||
unordered_map<int, function<void(AMFDecoder &dec)> > m_mapOnResultCB;
|
||||
recursive_mutex m_mtxOnResultCB;
|
||||
deque<function<void(AMFValue &dec)> > m_dqOnStatusCB;
|
||||
recursive_mutex m_mtxOnStatusCB;
|
||||
unordered_map<int, function<void(AMFDecoder &dec)> > _mapOnResultCB;
|
||||
recursive_mutex _mtxOnResultCB;
|
||||
deque<function<void(AMFValue &dec)> > _dqOnStatusCB;
|
||||
recursive_mutex _mtxOnStatusCB;
|
||||
|
||||
typedef void (RtmpPusher::*rtmpCMDHandle)(AMFDecoder &dec);
|
||||
static unordered_map<string, rtmpCMDHandle> g_mapCmd;
|
||||
|
||||
//超时功能实现
|
||||
std::shared_ptr<Timer> m_pPublishTimer;
|
||||
std::shared_ptr<Timer> _pPublishTimer;
|
||||
|
||||
//源
|
||||
std::weak_ptr<RtmpMediaSource> m_pMediaSrc;
|
||||
RtmpMediaSource::RingType::RingReader::Ptr m_pRtmpReader;
|
||||
std::weak_ptr<RtmpMediaSource> _pMediaSrc;
|
||||
RtmpMediaSource::RingType::RingReader::Ptr _pRtmpReader;
|
||||
//事件监听
|
||||
Event m_onShutdown;
|
||||
Event m_onPublished;
|
||||
Event _onShutdown;
|
||||
Event _onPublished;
|
||||
};
|
||||
|
||||
} /* namespace Rtmp */
|
||||
|
@ -45,9 +45,9 @@ RtmpSession::RtmpSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::P
|
||||
|
||||
RtmpSession::~RtmpSession() {
|
||||
DebugL << get_peer_ip();
|
||||
if(m_delayTask){
|
||||
m_delayTask();
|
||||
m_delayTask = nullptr;
|
||||
if(_delayTask){
|
||||
_delayTask();
|
||||
_delayTask = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,41 +57,41 @@ void RtmpSession::onError(const SockException& err) {
|
||||
//流量统计事件广播
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,iFlowThreshold,Broadcast::kFlowThreshold);
|
||||
|
||||
if(m_ui64TotalBytes > iFlowThreshold * 1024){
|
||||
if(_ui64TotalBytes > iFlowThreshold * 1024){
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,
|
||||
m_mediaInfo,
|
||||
m_ui64TotalBytes,
|
||||
m_ticker.createdTime()/1000,
|
||||
_mediaInfo,
|
||||
_ui64TotalBytes,
|
||||
_ticker.createdTime()/1000,
|
||||
*this);
|
||||
}
|
||||
}
|
||||
|
||||
void RtmpSession::onManager() {
|
||||
if (m_ticker.createdTime() > 15 * 1000) {
|
||||
if (!m_pRingReader && !m_pPublisherSrc) {
|
||||
if (_ticker.createdTime() > 15 * 1000) {
|
||||
if (!_pRingReader && !_pPublisherSrc) {
|
||||
WarnL << "非法链接:" << get_peer_ip();
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
if (m_pPublisherSrc) {
|
||||
if (_pPublisherSrc) {
|
||||
//publisher
|
||||
if (m_ticker.elapsedTime() > 15 * 1000) {
|
||||
if (_ticker.elapsedTime() > 15 * 1000) {
|
||||
WarnL << "数据接收超时:" << get_peer_ip();
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
if(m_delayTask){
|
||||
if(time(NULL) > m_iTaskTimeLine){
|
||||
m_delayTask();
|
||||
m_delayTask = nullptr;
|
||||
if(_delayTask){
|
||||
if(time(NULL) > _iTaskTimeLine){
|
||||
_delayTask();
|
||||
_delayTask = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RtmpSession::onRecv(const Buffer::Ptr &pBuf) {
|
||||
m_ticker.resetTime();
|
||||
_ticker.resetTime();
|
||||
try {
|
||||
m_ui64TotalBytes += pBuf->size();
|
||||
_ui64TotalBytes += pBuf->size();
|
||||
onParseRtmp(pBuf->data(), pBuf->size());
|
||||
} catch (exception &e) {
|
||||
WarnL << e.what();
|
||||
@ -113,11 +113,11 @@ void RtmpSession::onCmd_connect(AMFDecoder &dec) {
|
||||
///////////set peerBandwidth////////////////
|
||||
sendPeerBandwidth(5000000);
|
||||
|
||||
m_mediaInfo.m_app = params["app"].as_string();
|
||||
m_strTcUrl = params["tcUrl"].as_string();
|
||||
if(m_strTcUrl.empty()){
|
||||
_mediaInfo._app = params["app"].as_string();
|
||||
_strTcUrl = params["tcUrl"].as_string();
|
||||
if(_strTcUrl.empty()){
|
||||
//defaultVhost:默认vhost
|
||||
m_strTcUrl = string(RTMP_SCHEMA) + "://" + DEFAULT_VHOST + "/" + m_mediaInfo.m_app;
|
||||
_strTcUrl = string(RTMP_SCHEMA) + "://" + DEFAULT_VHOST + "/" + _mediaInfo._app;
|
||||
}
|
||||
bool ok = true; //(app == APP_NAME);
|
||||
AMFValue version(AMF_OBJECT);
|
||||
@ -130,7 +130,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_mediaInfo.m_app);
|
||||
throw std::runtime_error("Unsupported application: " + _mediaInfo._app);
|
||||
}
|
||||
|
||||
AMFEncoder invoke;
|
||||
@ -148,16 +148,16 @@ void RtmpSession::onCmd_publish(AMFDecoder &dec) {
|
||||
DebugL << "publish 回复时间:" << pTicker->elapsedTime() << "ms";
|
||||
}));
|
||||
dec.load<AMFValue>();/* NULL */
|
||||
m_mediaInfo.parse(m_strTcUrl + "/" + dec.load<std::string>());
|
||||
_mediaInfo.parse(_strTcUrl + "/" + dec.load<std::string>());
|
||||
|
||||
auto onRes = [this,pToken](const string &err){
|
||||
auto src = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,
|
||||
m_mediaInfo.m_vhost,
|
||||
m_mediaInfo.m_app,
|
||||
m_mediaInfo.m_streamid,
|
||||
_mediaInfo._vhost,
|
||||
_mediaInfo._app,
|
||||
_mediaInfo._streamid,
|
||||
false));
|
||||
bool authSuccess = err.empty();
|
||||
bool ok = (!src && !m_pPublisherSrc && authSuccess);
|
||||
bool ok = (!src && !_pPublisherSrc && authSuccess);
|
||||
AMFValue status(AMF_OBJECT);
|
||||
status.set("level", ok ? "status" : "error");
|
||||
status.set("code", ok ? "NetStream.Publish.Start" : (authSuccess ? "NetStream.Publish.BadName" : "NetStream.Publish.BadAuth"));
|
||||
@ -167,14 +167,14 @@ void RtmpSession::onCmd_publish(AMFDecoder &dec) {
|
||||
if (!ok) {
|
||||
WarnL << "onPublish:"
|
||||
<< (authSuccess ? "Already publishing:" : err.data()) << " "
|
||||
<< m_mediaInfo.m_vhost << " "
|
||||
<< m_mediaInfo.m_app << " "
|
||||
<< m_mediaInfo.m_streamid << endl;
|
||||
<< _mediaInfo._vhost << " "
|
||||
<< _mediaInfo._app << " "
|
||||
<< _mediaInfo._streamid << endl;
|
||||
shutdown();
|
||||
return;
|
||||
}
|
||||
m_pPublisherSrc.reset(new RtmpToRtspMediaSource(m_mediaInfo.m_vhost,m_mediaInfo.m_app,m_mediaInfo.m_streamid));
|
||||
m_pPublisherSrc->setListener(dynamic_pointer_cast<MediaSourceEvent>(shared_from_this()));
|
||||
_pPublisherSrc.reset(new RtmpToRtspMediaSource(_mediaInfo._vhost,_mediaInfo._app,_mediaInfo._streamid));
|
||||
_pPublisherSrc->setListener(dynamic_pointer_cast<MediaSourceEvent>(shared_from_this()));
|
||||
};
|
||||
|
||||
weak_ptr<RtmpSession> weakSelf = dynamic_pointer_cast<RtmpSession>(shared_from_this());
|
||||
@ -192,7 +192,7 @@ void RtmpSession::onCmd_publish(AMFDecoder &dec) {
|
||||
});
|
||||
};
|
||||
auto flag = NoticeCenter::Instance().emitEvent(Config::Broadcast::kBroadcastRtmpPublish,
|
||||
m_mediaInfo,
|
||||
_mediaInfo,
|
||||
invoker,
|
||||
*this);
|
||||
if(!flag){
|
||||
@ -213,9 +213,9 @@ void RtmpSession::onCmd_deleteStream(AMFDecoder &dec) {
|
||||
void RtmpSession::doPlayResponse(const string &err,bool tryDelay,const std::shared_ptr<onceToken> &pToken) {
|
||||
//获取流对象
|
||||
auto src = dynamic_pointer_cast<RtmpMediaSource>(MediaSource::find(RTMP_SCHEMA,
|
||||
m_mediaInfo.m_vhost,
|
||||
m_mediaInfo.m_app,
|
||||
m_mediaInfo.m_streamid,
|
||||
_mediaInfo._vhost,
|
||||
_mediaInfo._app,
|
||||
_mediaInfo._streamid,
|
||||
true));
|
||||
//是否鉴权成功
|
||||
bool authSuccess = err.empty();
|
||||
@ -223,17 +223,17 @@ void RtmpSession::doPlayResponse(const string &err,bool tryDelay,const std::shar
|
||||
//校验成功,但是流不存在而导致的不能播放
|
||||
//所以我们注册rtmp注册事件,等rtmp推流端推流成功后再告知播放器开始播放
|
||||
auto task_id = this;
|
||||
auto media_info = m_mediaInfo;
|
||||
auto media_info = _mediaInfo;
|
||||
weak_ptr<RtmpSession> weakSelf = dynamic_pointer_cast<RtmpSession>(shared_from_this());
|
||||
|
||||
NoticeCenter::Instance().addListener(task_id,Broadcast::kBroadcastMediaChanged,
|
||||
[task_id,weakSelf,media_info,pToken](BroadcastMediaChangedArgs){
|
||||
|
||||
if(bRegist &&
|
||||
schema == media_info.m_schema &&
|
||||
vhost == media_info.m_vhost &&
|
||||
app == media_info.m_app &&
|
||||
stream == media_info.m_streamid){
|
||||
schema == media_info._schema &&
|
||||
vhost == media_info._vhost &&
|
||||
app == media_info._app &&
|
||||
stream == media_info._streamid){
|
||||
//播发器请求的rtmp流终于注册上了
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
@ -249,7 +249,7 @@ void RtmpSession::doPlayResponse(const string &err,bool tryDelay,const std::shar
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
}
|
||||
DebugL << "收到rtmp注册事件,回复播放器:" << media_info.m_schema << "/" << media_info.m_vhost << "/" << media_info.m_app << "/" << media_info.m_streamid;
|
||||
DebugL << "收到rtmp注册事件,回复播放器:" << media_info._schema << "/" << media_info._vhost << "/" << media_info._app << "/" << media_info._streamid;
|
||||
//回复播放器
|
||||
strongSelf->doPlayResponse("",false,pToken);
|
||||
//取消延时任务,防止多次回复
|
||||
@ -291,15 +291,15 @@ void RtmpSession::doPlayResponse(const string &err,bool tryDelay,const std::shar
|
||||
status.set("level", ok ? "status" : "error");
|
||||
status.set("code", ok ? "NetStream.Play.Reset" : (authSuccess ? "NetStream.Play.StreamNotFound" : "NetStream.Play.BadAuth"));
|
||||
status.set("description", ok ? "Resetting and playing." : (authSuccess ? "No such stream." : err.data()));
|
||||
status.set("details", m_mediaInfo.m_streamid);
|
||||
status.set("details", _mediaInfo._streamid);
|
||||
status.set("clientid", "0");
|
||||
sendReply("onStatus", nullptr, status);
|
||||
if (!ok) {
|
||||
WarnL << "onPlayed:"
|
||||
<< (authSuccess ? "No such stream:" : err.data()) << " "
|
||||
<< m_mediaInfo.m_vhost << " "
|
||||
<< m_mediaInfo.m_app << " "
|
||||
<< m_mediaInfo.m_streamid
|
||||
<< _mediaInfo._vhost << " "
|
||||
<< _mediaInfo._app << " "
|
||||
<< _mediaInfo._streamid
|
||||
<< endl;
|
||||
shutdown();
|
||||
return;
|
||||
@ -310,7 +310,7 @@ void RtmpSession::doPlayResponse(const string &err,bool tryDelay,const std::shar
|
||||
status.set("level", "status");
|
||||
status.set("code", "NetStream.Play.Start");
|
||||
status.set("description", "Started playing.");
|
||||
status.set("details", m_mediaInfo.m_streamid);
|
||||
status.set("details", _mediaInfo._streamid);
|
||||
status.set("clientid", "0");
|
||||
sendReply("onStatus", nullptr, status);
|
||||
|
||||
@ -331,7 +331,7 @@ void RtmpSession::doPlayResponse(const string &err,bool tryDelay,const std::shar
|
||||
status.set("level", "status");
|
||||
status.set("code", "NetStream.Play.PublishNotify");
|
||||
status.set("description", "Now published.");
|
||||
status.set("details", m_mediaInfo.m_streamid);
|
||||
status.set("details", _mediaInfo._streamid);
|
||||
status.set("clientid", "0");
|
||||
sendReply("onStatus", nullptr, status);
|
||||
|
||||
@ -345,10 +345,10 @@ void RtmpSession::doPlayResponse(const string &err,bool tryDelay,const std::shar
|
||||
onSendMedia(pkt);
|
||||
});
|
||||
|
||||
m_pRingReader = src->getRing()->attach();
|
||||
_pRingReader = src->getRing()->attach();
|
||||
weak_ptr<RtmpSession> weakSelf = dynamic_pointer_cast<RtmpSession>(shared_from_this());
|
||||
SockUtil::setNoDelay(_sock->rawFD(), false);
|
||||
m_pRingReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt) {
|
||||
_pRingReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt) {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if (!strongSelf) {
|
||||
return;
|
||||
@ -361,14 +361,14 @@ void RtmpSession::doPlayResponse(const string &err,bool tryDelay,const std::shar
|
||||
strongSelf->onSendMedia(pkt);
|
||||
});
|
||||
});
|
||||
m_pRingReader->setDetachCB([weakSelf]() {
|
||||
_pRingReader->setDetachCB([weakSelf]() {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if (!strongSelf) {
|
||||
return;
|
||||
}
|
||||
strongSelf->safeShutdown();
|
||||
});
|
||||
m_pPlayerSrc = src;
|
||||
_pPlayerSrc = src;
|
||||
if (src->getRing()->readerCount() == 1) {
|
||||
src->seekTo(0);
|
||||
}
|
||||
@ -397,7 +397,7 @@ void RtmpSession::doPlay(AMFDecoder &dec){
|
||||
strongSelf->doPlayResponse(err,true,pToken);
|
||||
});
|
||||
};
|
||||
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,m_mediaInfo,invoker,*this);
|
||||
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,_mediaInfo,invoker,*this);
|
||||
if(!flag){
|
||||
//该事件无人监听,默认不鉴权
|
||||
doPlayResponse("",true,pToken);
|
||||
@ -408,7 +408,7 @@ void RtmpSession::onCmd_play2(AMFDecoder &dec) {
|
||||
}
|
||||
void RtmpSession::onCmd_play(AMFDecoder &dec) {
|
||||
dec.load<AMFValue>();/* NULL */
|
||||
m_mediaInfo.parse(m_strTcUrl + "/" + dec.load<std::string>());
|
||||
_mediaInfo.parse(_strTcUrl + "/" + dec.load<std::string>());
|
||||
doPlay(dec);
|
||||
}
|
||||
|
||||
@ -424,14 +424,14 @@ void RtmpSession::onCmd_pause(AMFDecoder &dec) {
|
||||
//streamBegin
|
||||
sendUserControl(paused ? CONTROL_STREAM_EOF : CONTROL_STREAM_BEGIN,
|
||||
STREAM_MEDIA);
|
||||
if (!m_pRingReader) {
|
||||
if (!_pRingReader) {
|
||||
throw std::runtime_error("Rtmp not started yet!");
|
||||
}
|
||||
if (paused) {
|
||||
m_pRingReader->setReadCB(nullptr);
|
||||
_pRingReader->setReadCB(nullptr);
|
||||
} else {
|
||||
weak_ptr<RtmpSession> weakSelf = dynamic_pointer_cast<RtmpSession>(shared_from_this());
|
||||
m_pRingReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt) {
|
||||
_pRingReader->setReadCB([weakSelf](const RtmpPacket::Ptr &pkt) {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
@ -448,14 +448,14 @@ void RtmpSession::onCmd_pause(AMFDecoder &dec) {
|
||||
}
|
||||
|
||||
void RtmpSession::setMetaData(AMFDecoder &dec) {
|
||||
if (!m_pPublisherSrc) {
|
||||
if (!_pPublisherSrc) {
|
||||
throw std::runtime_error("not a publisher");
|
||||
}
|
||||
std::string type = dec.load<std::string>();
|
||||
if (type != "onMetaData") {
|
||||
throw std::runtime_error("can only set metadata");
|
||||
}
|
||||
m_pPublisherSrc->onGetMetaData(dec.load<AMFValue>());
|
||||
_pPublisherSrc->onGetMetaData(dec.load<AMFValue>());
|
||||
}
|
||||
|
||||
void RtmpSession::onProcessCmd(AMFDecoder &dec) {
|
||||
@ -477,7 +477,7 @@ void RtmpSession::onProcessCmd(AMFDecoder &dec) {
|
||||
TraceL << "can not support cmd:" << method;
|
||||
return;
|
||||
}
|
||||
m_dNowReqID = dec.load<double>();
|
||||
_dNowReqID = dec.load<double>();
|
||||
auto fun = it->second;
|
||||
(this->*fun)(dec);
|
||||
}
|
||||
@ -503,14 +503,14 @@ void RtmpSession::onRtmpChunk(RtmpPacket &chunkData) {
|
||||
break;
|
||||
case MSG_AUDIO:
|
||||
case MSG_VIDEO: {
|
||||
if (!m_pPublisherSrc) {
|
||||
if (!_pPublisherSrc) {
|
||||
throw std::runtime_error("Not a rtmp publisher!");
|
||||
}
|
||||
GET_CONFIG_AND_REGISTER(bool,rtmp_modify_stamp,Config::Rtmp::kModifyStamp);
|
||||
if(rtmp_modify_stamp){
|
||||
chunkData.timeStamp = m_stampTicker[chunkData.typeId % 2].elapsedTime();
|
||||
chunkData.timeStamp = _stampTicker[chunkData.typeId % 2].elapsedTime();
|
||||
}
|
||||
m_pPublisherSrc->onGetMedia(std::make_shared<RtmpPacket>(chunkData));
|
||||
_pPublisherSrc->onGetMedia(std::make_shared<RtmpPacket>(chunkData));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -523,7 +523,7 @@ void RtmpSession::onCmd_seek(AMFDecoder &dec) {
|
||||
dec.load<AMFValue>();/* NULL */
|
||||
auto milliSeconds = dec.load<AMFValue>().as_number();
|
||||
InfoL << "rtmp seekTo:" << milliSeconds/1000.0;
|
||||
auto stongSrc = m_pPlayerSrc.lock();
|
||||
auto stongSrc = _pPlayerSrc.lock();
|
||||
if (stongSrc) {
|
||||
stongSrc->seekTo(milliSeconds);
|
||||
}
|
||||
@ -537,7 +537,7 @@ void RtmpSession::onCmd_seek(AMFDecoder &dec) {
|
||||
|
||||
void RtmpSession::onSendMedia(const RtmpPacket::Ptr &pkt) {
|
||||
auto modifiedStamp = pkt->timeStamp;
|
||||
auto &firstStamp = m_aui32FirstStamp[pkt->typeId % 2];
|
||||
auto &firstStamp = _aui32FirstStamp[pkt->typeId % 2];
|
||||
if(!firstStamp){
|
||||
firstStamp = modifiedStamp;
|
||||
}
|
||||
@ -546,22 +546,22 @@ void RtmpSession::onSendMedia(const RtmpPacket::Ptr &pkt) {
|
||||
modifiedStamp -= firstStamp;
|
||||
}else{
|
||||
//发生回环,重新计算时间戳增量
|
||||
CLEAR_ARR(m_aui32FirstStamp);
|
||||
CLEAR_ARR(_aui32FirstStamp);
|
||||
modifiedStamp = 0;
|
||||
}
|
||||
sendRtmp(pkt->typeId, pkt->streamId, pkt->strBuf, modifiedStamp, pkt->chunkId);
|
||||
}
|
||||
|
||||
void RtmpSession::doDelay(int delaySec, const std::function<void()> &fun) {
|
||||
if(m_delayTask){
|
||||
m_delayTask();
|
||||
if(_delayTask){
|
||||
_delayTask();
|
||||
}
|
||||
m_delayTask = fun;
|
||||
m_iTaskTimeLine = time(NULL) + delaySec;
|
||||
_delayTask = fun;
|
||||
_iTaskTimeLine = time(NULL) + delaySec;
|
||||
}
|
||||
|
||||
void RtmpSession::cancelDelyaTask(){
|
||||
m_delayTask = nullptr;
|
||||
_delayTask = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -70,7 +70,7 @@ private:
|
||||
|
||||
void onSendMedia(const RtmpPacket::Ptr &pkt);
|
||||
void onSendRawData(const Buffer::Ptr &buffer) override{
|
||||
m_ui64TotalBytes += buffer->size();
|
||||
_ui64TotalBytes += buffer->size();
|
||||
send(buffer);
|
||||
}
|
||||
void onRtmpChunk(RtmpPacket &chunkData) override;
|
||||
@ -78,12 +78,12 @@ private:
|
||||
template<typename first, typename second>
|
||||
inline void sendReply(const char *str, const first &reply, const second &status) {
|
||||
AMFEncoder invoke;
|
||||
invoke << str << m_dNowReqID << reply << status;
|
||||
invoke << str << _dNowReqID << reply << status;
|
||||
sendResponse(MSG_CMD, invoke.data());
|
||||
}
|
||||
|
||||
bool shutDown() override {
|
||||
InfoL << "kick out:" << m_mediaInfo.m_vhost << " " << m_mediaInfo.m_app << " " << m_mediaInfo.m_streamid;
|
||||
InfoL << "kick out:" << _mediaInfo._vhost << " " << _mediaInfo._app << " " << _mediaInfo._streamid;
|
||||
safeShutdown();
|
||||
return true;
|
||||
}
|
||||
@ -91,19 +91,19 @@ private:
|
||||
void doDelay(int delaySec,const std::function<void()> &fun);
|
||||
void cancelDelyaTask();
|
||||
private:
|
||||
std::string m_strTcUrl;
|
||||
MediaInfo m_mediaInfo;
|
||||
double m_dNowReqID = 0;
|
||||
Ticker m_ticker;//数据接收时间
|
||||
SmoothTicker m_stampTicker[2];//时间戳生产器
|
||||
RingBuffer<RtmpPacket::Ptr>::RingReader::Ptr m_pRingReader;
|
||||
std::shared_ptr<RtmpMediaSource> m_pPublisherSrc;
|
||||
std::weak_ptr<RtmpMediaSource> m_pPlayerSrc;
|
||||
uint32_t m_aui32FirstStamp[2] = {0};
|
||||
std::string _strTcUrl;
|
||||
MediaInfo _mediaInfo;
|
||||
double _dNowReqID = 0;
|
||||
Ticker _ticker;//数据接收时间
|
||||
SmoothTicker _stampTicker[2];//时间戳生产器
|
||||
RingBuffer<RtmpPacket::Ptr>::RingReader::Ptr _pRingReader;
|
||||
std::shared_ptr<RtmpMediaSource> _pPublisherSrc;
|
||||
std::weak_ptr<RtmpMediaSource> _pPlayerSrc;
|
||||
uint32_t _aui32FirstStamp[2] = {0};
|
||||
//消耗的总流量
|
||||
uint64_t m_ui64TotalBytes = 0;
|
||||
std::function<void()> m_delayTask;
|
||||
uint32_t m_iTaskTimeLine = 0;
|
||||
uint64_t _ui64TotalBytes = 0;
|
||||
std::function<void()> _delayTask;
|
||||
uint32_t _iTaskTimeLine = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -41,27 +41,27 @@ RtmpToRtspMediaSource::RtmpToRtspMediaSource(const string &vhost,
|
||||
const string &id,
|
||||
bool bEnableHls,
|
||||
bool bEnableMp4) :
|
||||
RtmpMediaSource(vhost,app,id),m_bEnableHls(bEnableHls),m_bEnableMp4(bEnableMp4) {
|
||||
RtmpMediaSource(vhost,app,id),_bEnableHls(bEnableHls),_bEnableMp4(bEnableMp4) {
|
||||
}
|
||||
RtmpToRtspMediaSource::~RtmpToRtspMediaSource() {}
|
||||
|
||||
|
||||
void RtmpToRtspMediaSource::onGetH264(const H264Frame &frame) {
|
||||
if(m_pRecorder){
|
||||
m_pRecorder->inputH264((char *) frame.data(), frame.size(), frame.timeStamp, frame.type);
|
||||
if(_pRecorder){
|
||||
_pRecorder->inputH264((char *) frame.data(), frame.size(), frame.timeStamp, frame.type);
|
||||
}
|
||||
|
||||
if(m_pRtpMaker_h264){
|
||||
m_pRtpMaker_h264->makeRtp(frame.data() + 4, frame.size() - 4, frame.timeStamp);
|
||||
if(_pRtpMaker_h264){
|
||||
_pRtpMaker_h264->makeRtp(frame.data() + 4, frame.size() - 4, frame.timeStamp);
|
||||
}
|
||||
}
|
||||
inline void RtmpToRtspMediaSource::onGetAAC(const AACFrame &frame) {
|
||||
if(m_pRecorder){
|
||||
m_pRecorder->inputAAC((char *) frame.buffer, frame.aac_frame_length, frame.timeStamp);
|
||||
if(_pRecorder){
|
||||
_pRecorder->inputAAC((char *) frame.buffer, frame.aac_frame_length, frame.timeStamp);
|
||||
}
|
||||
|
||||
if (m_pRtpMaker_aac) {
|
||||
m_pRtpMaker_aac->makeRtp((char *) frame.buffer + 7, frame.aac_frame_length - 7, frame.timeStamp);
|
||||
if (_pRtpMaker_aac) {
|
||||
_pRtpMaker_aac->makeRtp((char *) frame.buffer + 7, frame.aac_frame_length - 7, frame.timeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,40 +73,40 @@ void RtmpToRtspMediaSource::makeSDP() {
|
||||
strSDP += "i=ZL Live Stream\r\n";
|
||||
strSDP += "c=IN IP4 0.0.0.0\r\n";
|
||||
strSDP += "t=0 0\r\n";
|
||||
if(m_pParser->getDuration() <= 0){
|
||||
if(_pParser->getDuration() <= 0){
|
||||
strSDP += "a=range:npt=0-\r\n";
|
||||
}else{
|
||||
strSDP += StrPrinter << "0-"<< m_pParser->getDuration()<< "\r\n" << endl;
|
||||
strSDP += StrPrinter << "0-"<< _pParser->getDuration()<< "\r\n" << endl;
|
||||
}
|
||||
strSDP += "a=control:*\r\n";
|
||||
|
||||
//todo(xzl) 修复此处
|
||||
|
||||
// if (m_pParser->containVideo()) {
|
||||
// if (_pParser->containVideo()) {
|
||||
// uint32_t ssrc0;
|
||||
// memcpy(&ssrc0, makeRandStr(4, false).data(), 4);
|
||||
// auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) {
|
||||
// m_pRtspSrc->onGetRTP(pkt,bKeyPos);
|
||||
// _pRtspSrc->onGetRTP(pkt,bKeyPos);
|
||||
// };
|
||||
//
|
||||
// GET_CONFIG_AND_REGISTER(uint32_t,videoMtu,Config::Rtp::kVideoMtuSize);
|
||||
// m_pRtpMaker_h264.reset(new RtpMaker_H264(lam, ssrc0,videoMtu));
|
||||
// _pRtpMaker_h264.reset(new RtpMaker_H264(lam, ssrc0,videoMtu));
|
||||
//
|
||||
// char strTemp[100];
|
||||
// int profile_level_id = 0;
|
||||
// string strSPS =m_pParser->getSps().substr(4);
|
||||
// string strPPS =m_pParser->getPps().substr(4);
|
||||
// string strSPS =_pParser->getSps().substr(4);
|
||||
// string strPPS =_pParser->getPps().substr(4);
|
||||
// if (strSPS.length() >= 4) { // sanity check
|
||||
// profile_level_id = (strSPS[1] << 16) | (strSPS[2] << 8) | strSPS[3]; // profile_idc|constraint_setN_flag|level_idc
|
||||
// }
|
||||
//
|
||||
// //视频通道
|
||||
// strSDP += StrPrinter << "m=video 0 RTP/AVP " << m_pRtpMaker_h264->getPlayloadType()
|
||||
// strSDP += StrPrinter << "m=video 0 RTP/AVP " << _pRtpMaker_h264->getPlayloadType()
|
||||
// << "\r\n" << endl;
|
||||
// strSDP += "b=AS:5100\r\n";
|
||||
// strSDP += StrPrinter << "a=rtpmap:" << m_pRtpMaker_h264->getPlayloadType()
|
||||
// << " H264/" << m_pRtpMaker_h264->getSampleRate() << "\r\n" << endl;
|
||||
// strSDP += StrPrinter << "a=fmtp:" << m_pRtpMaker_h264->getPlayloadType()
|
||||
// strSDP += StrPrinter << "a=rtpmap:" << _pRtpMaker_h264->getPlayloadType()
|
||||
// << " H264/" << _pRtpMaker_h264->getSampleRate() << "\r\n" << endl;
|
||||
// strSDP += StrPrinter << "a=fmtp:" << _pRtpMaker_h264->getPlayloadType()
|
||||
// << " packetization-mode=1;profile-level-id=" << endl;
|
||||
//
|
||||
// memset(strTemp, 0, 100);
|
||||
@ -121,41 +121,41 @@ void RtmpToRtspMediaSource::makeSDP() {
|
||||
// av_base64_encode(strTemp, 100, (uint8_t *) strPPS.data(), strPPS.size());
|
||||
// strSDP += strTemp;
|
||||
// strSDP += "\r\n";
|
||||
// strSDP += StrPrinter << "a=control:trackID=" << m_pRtpMaker_h264->getInterleaved() / 2
|
||||
// strSDP += StrPrinter << "a=control:trackID=" << _pRtpMaker_h264->getInterleaved() / 2
|
||||
// << "\r\n" << endl;
|
||||
// }
|
||||
//
|
||||
// if (m_pParser->containAudio()) {
|
||||
// if (_pParser->containAudio()) {
|
||||
// uint32_t ssrc1;
|
||||
// memcpy(&ssrc1, makeRandStr(8, false).data() + 4, 4);
|
||||
// auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) {
|
||||
// m_pRtspSrc->onGetRTP(pkt,bKeyPos);
|
||||
// _pRtspSrc->onGetRTP(pkt,bKeyPos);
|
||||
// };
|
||||
// GET_CONFIG_AND_REGISTER(uint32_t,audioMtu,Config::Rtp::kAudioMtuSize);
|
||||
// m_pRtpMaker_aac.reset(new RtpMaker_AAC(lam, ssrc1, audioMtu,m_pParser->getAudioSampleRate()));
|
||||
// _pRtpMaker_aac.reset(new RtpMaker_AAC(lam, ssrc1, audioMtu,_pParser->getAudioSampleRate()));
|
||||
//
|
||||
// char configStr[32];
|
||||
// const string & strAacCfg = m_pParser->getAudioCfg();
|
||||
// const string & strAacCfg = _pParser->getAudioCfg();
|
||||
// snprintf(configStr, sizeof(configStr), "%02X%02x", strAacCfg[0], strAacCfg[1]);
|
||||
// strSDP += StrPrinter << "m=audio 0 RTP/AVP " << m_pRtpMaker_aac->getPlayloadType()
|
||||
// strSDP += StrPrinter << "m=audio 0 RTP/AVP " << _pRtpMaker_aac->getPlayloadType()
|
||||
// << "\r\n" << endl;
|
||||
// strSDP += "b=AS:96\r\n";
|
||||
// strSDP += StrPrinter << "a=rtpmap:" << m_pRtpMaker_aac->getPlayloadType()
|
||||
// << " MPEG4-GENERIC/" << m_pRtpMaker_aac->getSampleRate() << "\r\n"
|
||||
// strSDP += StrPrinter << "a=rtpmap:" << _pRtpMaker_aac->getPlayloadType()
|
||||
// << " MPEG4-GENERIC/" << _pRtpMaker_aac->getSampleRate() << "\r\n"
|
||||
// << endl;
|
||||
// strSDP += StrPrinter << "a=fmtp:" << m_pRtpMaker_aac->getPlayloadType()
|
||||
// strSDP += StrPrinter << "a=fmtp:" << _pRtpMaker_aac->getPlayloadType()
|
||||
// << " streamtype=5;profile-level-id=1;mode=AAC-hbr;"
|
||||
// << "sizelength=13;indexlength=3;indexdeltalength=3;config="
|
||||
// << endl;
|
||||
// strSDP.append(configStr, 4);
|
||||
// strSDP += "\r\n";
|
||||
// strSDP += StrPrinter << "a=control:trackID=" << m_pRtpMaker_aac->getInterleaved() / 2
|
||||
// strSDP += StrPrinter << "a=control:trackID=" << _pRtpMaker_aac->getInterleaved() / 2
|
||||
// << "\r\n" << endl;
|
||||
// }
|
||||
|
||||
m_pRtspSrc.reset(new RtspMediaSource(getVhost(),getApp(),getId()));
|
||||
m_pRtspSrc->setListener(m_listener);
|
||||
m_pRtspSrc->onGetSDP(strSDP);
|
||||
_pRtspSrc.reset(new RtspMediaSource(getVhost(),getApp(),getId()));
|
||||
_pRtspSrc->setListener(_listener);
|
||||
_pRtspSrc->onGetSDP(strSDP);
|
||||
}
|
||||
|
||||
|
||||
|
@ -65,12 +65,12 @@ public:
|
||||
|
||||
void onGetMetaData(const AMFValue &_metadata) override {
|
||||
try {
|
||||
m_pParser.reset(new RtmpParser(_metadata));
|
||||
m_pRecorder.reset(new MediaRecorder(getVhost(),getApp(),getId(),m_pParser,m_bEnableHls,m_bEnableMp4));
|
||||
_pParser.reset(new RtmpParser(_metadata));
|
||||
_pRecorder.reset(new MediaRecorder(getVhost(),getApp(),getId(),_pParser,_bEnableHls,_bEnableMp4));
|
||||
//todo(xzl) 修复此处
|
||||
|
||||
// m_pParser->setOnAudioCB(std::bind(&RtmpToRtspMediaSource::onGetAAC, this, placeholders::_1));
|
||||
// m_pParser->setOnVideoCB(std::bind(&RtmpToRtspMediaSource::onGetH264, this, placeholders::_1));
|
||||
// _pParser->setOnAudioCB(std::bind(&RtmpToRtspMediaSource::onGetAAC, this, placeholders::_1));
|
||||
// _pParser->setOnVideoCB(std::bind(&RtmpToRtspMediaSource::onGetH264, this, placeholders::_1));
|
||||
} catch (exception &ex) {
|
||||
WarnL << ex.what();
|
||||
}
|
||||
@ -78,23 +78,23 @@ public:
|
||||
}
|
||||
|
||||
void onGetMedia(const RtmpPacket::Ptr &pkt) override {
|
||||
if (m_pParser) {
|
||||
if (!m_pRtspSrc && m_pParser->isInited()) {
|
||||
if (_pParser) {
|
||||
if (!_pRtspSrc && _pParser->isInited()) {
|
||||
makeSDP();
|
||||
}
|
||||
m_pParser->inputRtmp(pkt);
|
||||
_pParser->inputRtmp(pkt);
|
||||
}
|
||||
RtmpMediaSource::onGetMedia(pkt);
|
||||
}
|
||||
|
||||
private:
|
||||
RtmpParser::Ptr m_pParser;
|
||||
RtspMediaSource::Ptr m_pRtspSrc;
|
||||
RtpMaker_AAC::Ptr m_pRtpMaker_aac;
|
||||
RtpMaker_H264::Ptr m_pRtpMaker_h264;
|
||||
MediaRecorder::Ptr m_pRecorder;
|
||||
bool m_bEnableHls;
|
||||
bool m_bEnableMp4;
|
||||
RtmpParser::Ptr _pParser;
|
||||
RtspMediaSource::Ptr _pRtspSrc;
|
||||
RtpMaker_AAC::Ptr _pRtpMaker_aac;
|
||||
RtpMaker_H264::Ptr _pRtpMaker_h264;
|
||||
MediaRecorder::Ptr _pRecorder;
|
||||
bool _bEnableHls;
|
||||
bool _bEnableMp4;
|
||||
void onGetH264(const H264Frame &frame);
|
||||
void onGetAAC(const AACFrame &frame);
|
||||
void makeSDP();
|
||||
|
@ -36,24 +36,24 @@ using namespace ZL::Network;
|
||||
|
||||
/////////////////////AMFValue/////////////////////////////
|
||||
inline void AMFValue::destroy() {
|
||||
switch (m_type) {
|
||||
switch (_type) {
|
||||
case AMF_STRING:
|
||||
if (m_value.string) {
|
||||
delete m_value.string;
|
||||
m_value.string = nullptr;
|
||||
if (_value.string) {
|
||||
delete _value.string;
|
||||
_value.string = nullptr;
|
||||
}
|
||||
break;
|
||||
case AMF_OBJECT:
|
||||
case AMF_ECMA_ARRAY:
|
||||
if (m_value.object) {
|
||||
delete m_value.object;
|
||||
m_value.object = nullptr;
|
||||
if (_value.object) {
|
||||
delete _value.object;
|
||||
_value.object = nullptr;
|
||||
}
|
||||
break;
|
||||
case AMF_STRICT_ARRAY:
|
||||
if (m_value.array) {
|
||||
delete m_value.array;
|
||||
m_value.array = nullptr;
|
||||
if (_value.array) {
|
||||
delete _value.array;
|
||||
_value.array = nullptr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -61,16 +61,16 @@ inline void AMFValue::destroy() {
|
||||
}
|
||||
}
|
||||
inline void AMFValue::init() {
|
||||
switch (m_type) {
|
||||
switch (_type) {
|
||||
case AMF_OBJECT:
|
||||
case AMF_ECMA_ARRAY:
|
||||
m_value.object = new mapType;
|
||||
_value.object = new mapType;
|
||||
break;
|
||||
case AMF_STRING:
|
||||
m_value.string = new std::string;
|
||||
_value.string = new std::string;
|
||||
break;
|
||||
case AMF_STRICT_ARRAY:
|
||||
m_value.array = new arrayType;
|
||||
_value.array = new arrayType;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -79,7 +79,7 @@ inline void AMFValue::init() {
|
||||
|
||||
}
|
||||
AMFValue::AMFValue(AMFType type) :
|
||||
m_type(type) {
|
||||
_type(type) {
|
||||
init();
|
||||
}
|
||||
|
||||
@ -89,38 +89,38 @@ AMFValue::~AMFValue() {
|
||||
}
|
||||
|
||||
AMFValue::AMFValue(const char *s) :
|
||||
m_type(AMF_STRING) {
|
||||
_type(AMF_STRING) {
|
||||
init();
|
||||
*m_value.string = s;
|
||||
*_value.string = s;
|
||||
}
|
||||
|
||||
|
||||
AMFValue::AMFValue(const std::string &s) :
|
||||
m_type(AMF_STRING) {
|
||||
_type(AMF_STRING) {
|
||||
init();
|
||||
*m_value.string = s;
|
||||
*_value.string = s;
|
||||
}
|
||||
|
||||
AMFValue::AMFValue(double n) :
|
||||
m_type(AMF_NUMBER) {
|
||||
_type(AMF_NUMBER) {
|
||||
init();
|
||||
m_value.number = n;
|
||||
_value.number = n;
|
||||
}
|
||||
|
||||
AMFValue::AMFValue(int i) :
|
||||
m_type(AMF_INTEGER) {
|
||||
_type(AMF_INTEGER) {
|
||||
init();
|
||||
m_value.integer = i;
|
||||
_value.integer = i;
|
||||
}
|
||||
|
||||
AMFValue::AMFValue(bool b) :
|
||||
m_type(AMF_BOOLEAN) {
|
||||
_type(AMF_BOOLEAN) {
|
||||
init();
|
||||
m_value.boolean = b;
|
||||
_value.boolean = b;
|
||||
}
|
||||
|
||||
AMFValue::AMFValue(const AMFValue &from) :
|
||||
m_type(AMF_NULL) {
|
||||
_type(AMF_NULL) {
|
||||
*this = from;
|
||||
}
|
||||
|
||||
@ -134,27 +134,27 @@ AMFValue& AMFValue::operator =(const AMFValue &from) {
|
||||
}
|
||||
AMFValue& AMFValue::operator =(AMFValue &&from) {
|
||||
destroy();
|
||||
m_type = from.m_type;
|
||||
_type = from._type;
|
||||
init();
|
||||
switch (m_type) {
|
||||
switch (_type) {
|
||||
case AMF_STRING:
|
||||
*m_value.string = (*from.m_value.string);
|
||||
*_value.string = (*from._value.string);
|
||||
break;
|
||||
case AMF_OBJECT:
|
||||
case AMF_ECMA_ARRAY:
|
||||
*m_value.object = (*from.m_value.object);
|
||||
*_value.object = (*from._value.object);
|
||||
break;
|
||||
case AMF_STRICT_ARRAY:
|
||||
*m_value.array = (*from.m_value.array);
|
||||
*_value.array = (*from._value.array);
|
||||
break;
|
||||
case AMF_NUMBER:
|
||||
m_value.number = from.m_value.number;
|
||||
_value.number = from._value.number;
|
||||
break;
|
||||
case AMF_INTEGER:
|
||||
m_value.integer = from.m_value.integer;
|
||||
_value.integer = from._value.integer;
|
||||
break;
|
||||
case AMF_BOOLEAN:
|
||||
m_value.boolean = from.m_value.boolean;
|
||||
_value.boolean = from._value.boolean;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -61,13 +61,13 @@ public:
|
||||
~AMFValue();
|
||||
|
||||
void clear() {
|
||||
switch (m_type) {
|
||||
switch (_type) {
|
||||
case AMF_STRING:
|
||||
m_value.string->clear();
|
||||
_value.string->clear();
|
||||
break;
|
||||
case AMF_OBJECT:
|
||||
case AMF_ECMA_ARRAY:
|
||||
m_value.object->clear();
|
||||
_value.object->clear();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -75,23 +75,23 @@ public:
|
||||
}
|
||||
|
||||
AMFType type() const {
|
||||
return m_type;
|
||||
return _type;
|
||||
}
|
||||
|
||||
const std::string &as_string() const {
|
||||
if(m_type != AMF_STRING){
|
||||
if(_type != AMF_STRING){
|
||||
throw std::runtime_error("AMF not a string");
|
||||
}
|
||||
return *m_value.string;
|
||||
return *_value.string;
|
||||
}
|
||||
double as_number() const {
|
||||
switch (m_type) {
|
||||
switch (_type) {
|
||||
case AMF_NUMBER:
|
||||
return m_value.number;
|
||||
return _value.number;
|
||||
case AMF_INTEGER:
|
||||
return m_value.integer;
|
||||
return _value.integer;
|
||||
case AMF_BOOLEAN:
|
||||
return m_value.boolean;
|
||||
return _value.boolean;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("AMF not a number");
|
||||
@ -99,13 +99,13 @@ public:
|
||||
}
|
||||
}
|
||||
int as_integer() const {
|
||||
switch (m_type) {
|
||||
switch (_type) {
|
||||
case AMF_NUMBER:
|
||||
return m_value.number;
|
||||
return _value.number;
|
||||
case AMF_INTEGER:
|
||||
return m_value.integer;
|
||||
return _value.integer;
|
||||
case AMF_BOOLEAN:
|
||||
return m_value.boolean;
|
||||
return _value.boolean;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("AMF not a integer");
|
||||
@ -113,13 +113,13 @@ public:
|
||||
}
|
||||
}
|
||||
bool as_boolean() const {
|
||||
switch (m_type) {
|
||||
switch (_type) {
|
||||
case AMF_NUMBER:
|
||||
return m_value.number;
|
||||
return _value.number;
|
||||
case AMF_INTEGER:
|
||||
return m_value.integer;
|
||||
return _value.integer;
|
||||
case AMF_BOOLEAN:
|
||||
return m_value.boolean;
|
||||
return _value.boolean;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("AMF not a boolean");
|
||||
@ -128,11 +128,11 @@ public:
|
||||
}
|
||||
|
||||
const AMFValue &operator[](const char *str) const {
|
||||
if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) {
|
||||
if (_type != AMF_OBJECT && _type != AMF_ECMA_ARRAY) {
|
||||
throw std::runtime_error("AMF not a object");
|
||||
}
|
||||
auto i = m_value.object->find(str);
|
||||
if (i == m_value.object->end()) {
|
||||
auto i = _value.object->find(str);
|
||||
if (i == _value.object->end()) {
|
||||
static AMFValue val(AMF_NULL);
|
||||
return val;
|
||||
}
|
||||
@ -140,36 +140,36 @@ public:
|
||||
}
|
||||
template<typename FUN>
|
||||
void object_for_each(const FUN &fun) const {
|
||||
if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) {
|
||||
if (_type != AMF_OBJECT && _type != AMF_ECMA_ARRAY) {
|
||||
throw std::runtime_error("AMF not a object");
|
||||
}
|
||||
for (auto & pr : *(m_value.object)) {
|
||||
for (auto & pr : *(_value.object)) {
|
||||
fun(pr.first, pr.second);
|
||||
}
|
||||
}
|
||||
|
||||
operator bool() const{
|
||||
return m_type != AMF_NULL;
|
||||
return _type != AMF_NULL;
|
||||
}
|
||||
void set(const std::string &s, const AMFValue &val) {
|
||||
if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) {
|
||||
if (_type != AMF_OBJECT && _type != AMF_ECMA_ARRAY) {
|
||||
throw std::runtime_error("AMF not a object");
|
||||
}
|
||||
m_value.object->emplace(s, val);
|
||||
_value.object->emplace(s, val);
|
||||
}
|
||||
void add(const AMFValue &val) {
|
||||
if (m_type != AMF_STRICT_ARRAY) {
|
||||
if (_type != AMF_STRICT_ARRAY) {
|
||||
throw std::runtime_error("AMF not a array");
|
||||
}
|
||||
assert(m_type == AMF_STRICT_ARRAY);
|
||||
m_value.array->push_back(val);
|
||||
assert(_type == AMF_STRICT_ARRAY);
|
||||
_value.array->push_back(val);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, AMFValue> mapType;
|
||||
typedef std::vector<AMFValue> arrayType;
|
||||
|
||||
AMFType m_type;
|
||||
AMFType _type;
|
||||
union {
|
||||
std::string *string;
|
||||
double number;
|
||||
@ -177,20 +177,20 @@ private:
|
||||
bool boolean;
|
||||
mapType *object;
|
||||
arrayType *array;
|
||||
} m_value;
|
||||
} _value;
|
||||
|
||||
friend class AMFEncoder;
|
||||
const mapType &getMap() const {
|
||||
if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) {
|
||||
if (_type != AMF_OBJECT && _type != AMF_ECMA_ARRAY) {
|
||||
throw std::runtime_error("AMF not a object");
|
||||
}
|
||||
return *m_value.object;
|
||||
return *_value.object;
|
||||
}
|
||||
const arrayType &getArr() const {
|
||||
if (m_type != AMF_STRICT_ARRAY) {
|
||||
if (_type != AMF_STRICT_ARRAY) {
|
||||
throw std::runtime_error("AMF not a array");
|
||||
}
|
||||
return *m_value.array;
|
||||
return *_value.array;
|
||||
}
|
||||
inline void destroy();
|
||||
inline void init();
|
||||
|
@ -67,7 +67,7 @@ void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
RtmpPacket::Ptr rtmpPkt = ResourcePoolHelper<RtmpPacket>::obtainObj();
|
||||
//////////header
|
||||
uint8_t is_config = false;
|
||||
rtmpPkt->strBuf.push_back(m_ui8AudioFlags);
|
||||
rtmpPkt->strBuf.push_back(_ui8AudioFlags);
|
||||
rtmpPkt->strBuf.push_back(!is_config);
|
||||
rtmpPkt->strBuf.append(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize());
|
||||
|
||||
@ -108,12 +108,12 @@ void AACRtmpEncoder::makeAudioConfigPkt() {
|
||||
uint8_t flvSampleBit = iSampleBit == 16;
|
||||
uint8_t flvAudioType = 10; //aac
|
||||
|
||||
m_ui8AudioFlags = (flvAudioType << 4) | (flvSampleRate << 2) | (flvSampleBit << 1) | flvStereoOrMono;
|
||||
_ui8AudioFlags = (flvAudioType << 4) | (flvSampleRate << 2) | (flvSampleBit << 1) | flvStereoOrMono;
|
||||
|
||||
RtmpPacket::Ptr rtmpPkt = ResourcePoolHelper<RtmpPacket>::obtainObj();
|
||||
//////////header
|
||||
uint8_t is_config = true;
|
||||
rtmpPkt->strBuf.push_back(m_ui8AudioFlags);
|
||||
rtmpPkt->strBuf.push_back(_ui8AudioFlags);
|
||||
rtmpPkt->strBuf.push_back(!is_config);
|
||||
rtmpPkt->strBuf.append(_aac_cfg);
|
||||
|
||||
|
@ -61,7 +61,7 @@ public:
|
||||
|
||||
private:
|
||||
void makeAudioConfigPkt();
|
||||
uint8_t m_ui8AudioFlags;
|
||||
uint8_t _ui8AudioFlags;
|
||||
};
|
||||
|
||||
}//namespace Rtmp
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
|
||||
H264RtmpDecoder::H264RtmpDecoder() {
|
||||
m_h264frame = obtainFrame();
|
||||
_h264frame = obtainFrame();
|
||||
}
|
||||
|
||||
H264Frame::Ptr H264RtmpDecoder::obtainFrame() {
|
||||
@ -26,12 +26,12 @@ bool H264RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &rtmp, bool key_pos) {
|
||||
bool H264RtmpDecoder::decodeRtmp(const RtmpPacket::Ptr &pkt) {
|
||||
if (pkt->isCfgFrame()) {
|
||||
//缓存sps pps,后续插入到I帧之前
|
||||
m_sps = pkt->getH264SPS();
|
||||
m_pps = pkt->getH264PPS();
|
||||
_sps = pkt->getH264SPS();
|
||||
_pps = pkt->getH264PPS();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_sps.size()) {
|
||||
if (_sps.size()) {
|
||||
uint32_t iTotalLen = pkt->strBuf.size();
|
||||
uint32_t iOffset = 5;
|
||||
while(iOffset + 4 < iTotalLen){
|
||||
@ -54,8 +54,8 @@ inline void H264RtmpDecoder::onGetH264_l(const char* pcData, int iLen, uint32_t
|
||||
switch (pcData[0] & 0x1F) {
|
||||
case 5: {
|
||||
//I frame
|
||||
onGetH264(m_sps.data(), m_sps.length(), ui32TimeStamp);
|
||||
onGetH264(m_pps.data(), m_pps.length(), ui32TimeStamp);
|
||||
onGetH264(_sps.data(), _sps.length(), ui32TimeStamp);
|
||||
onGetH264(_pps.data(), _pps.length(), ui32TimeStamp);
|
||||
}
|
||||
case 1: {
|
||||
//I or P or B frame
|
||||
@ -68,14 +68,14 @@ inline void H264RtmpDecoder::onGetH264_l(const char* pcData, int iLen, uint32_t
|
||||
}
|
||||
}
|
||||
inline void H264RtmpDecoder::onGetH264(const char* pcData, int iLen, uint32_t ui32TimeStamp) {
|
||||
m_h264frame->type = pcData[0] & 0x1F;
|
||||
m_h264frame->timeStamp = ui32TimeStamp;
|
||||
m_h264frame->buffer.assign("\x0\x0\x0\x1", 4); //添加264头
|
||||
m_h264frame->buffer.append(pcData, iLen);
|
||||
_h264frame->type = pcData[0] & 0x1F;
|
||||
_h264frame->timeStamp = ui32TimeStamp;
|
||||
_h264frame->buffer.assign("\x0\x0\x0\x1", 4); //添加264头
|
||||
_h264frame->buffer.append(pcData, iLen);
|
||||
|
||||
//写入环形缓存
|
||||
RtmpCodec::inputFrame(m_h264frame);
|
||||
m_h264frame = obtainFrame();
|
||||
RtmpCodec::inputFrame(_h264frame);
|
||||
_h264frame = obtainFrame();
|
||||
}
|
||||
|
||||
|
||||
@ -95,9 +95,9 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
switch (type){
|
||||
case 7:{
|
||||
//sps
|
||||
if(m_sps.empty()){
|
||||
m_sps = string(pcData,iLen);
|
||||
if(!m_pps.empty()){
|
||||
if(_sps.empty()){
|
||||
_sps = string(pcData,iLen);
|
||||
if(!_pps.empty()){
|
||||
makeVideoConfigPkt();
|
||||
}
|
||||
}
|
||||
@ -105,9 +105,9 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
break;
|
||||
case 8:{
|
||||
//pps
|
||||
if(m_pps.empty()){
|
||||
m_pps = string(pcData,iLen);
|
||||
if(!m_sps.empty()){
|
||||
if(_pps.empty()){
|
||||
_pps = string(pcData,iLen);
|
||||
if(!_sps.empty()){
|
||||
makeVideoConfigPkt();
|
||||
}
|
||||
}
|
||||
@ -158,23 +158,23 @@ void H264RtmpEncoder::makeVideoConfigPkt() {
|
||||
////////////sps
|
||||
rtmpPkt->strBuf.push_back(1); // version
|
||||
|
||||
//DebugL<<hexdump(m_sps.data(), m_sps.size());
|
||||
rtmpPkt->strBuf.push_back(m_sps[1]); // profile
|
||||
rtmpPkt->strBuf.push_back(m_sps[2]); // compat
|
||||
rtmpPkt->strBuf.push_back(m_sps[3]); // level
|
||||
//DebugL<<hexdump(_sps.data(), _sps.size());
|
||||
rtmpPkt->strBuf.push_back(_sps[1]); // profile
|
||||
rtmpPkt->strBuf.push_back(_sps[2]); // compat
|
||||
rtmpPkt->strBuf.push_back(_sps[3]); // level
|
||||
rtmpPkt->strBuf.push_back(0xff); // 6 bits reserved + 2 bits nal size length - 1 (11)
|
||||
rtmpPkt->strBuf.push_back(0xe1); // 3 bits reserved + 5 bits number of sps (00001)
|
||||
uint16_t size = m_sps.size();
|
||||
uint16_t size = _sps.size();
|
||||
size = htons(size);
|
||||
rtmpPkt->strBuf.append((char *) &size, 2);
|
||||
rtmpPkt->strBuf.append(m_sps);
|
||||
rtmpPkt->strBuf.append(_sps);
|
||||
|
||||
/////////////pps
|
||||
rtmpPkt->strBuf.push_back(1); // version
|
||||
size = m_pps.size();
|
||||
size = _pps.size();
|
||||
size = htons(size);
|
||||
rtmpPkt->strBuf.append((char *) &size, 2);
|
||||
rtmpPkt->strBuf.append(m_pps);
|
||||
rtmpPkt->strBuf.append(_pps);
|
||||
|
||||
rtmpPkt->bodySize = rtmpPkt->strBuf.size();
|
||||
rtmpPkt->chunkId = CHUNK_VIDEO;
|
||||
|
@ -40,9 +40,9 @@ protected:
|
||||
void onGetH264(const char *pcData, int iLen, uint32_t ui32TimeStamp);
|
||||
H264Frame::Ptr obtainFrame();
|
||||
protected:
|
||||
H264Frame::Ptr m_h264frame;
|
||||
string m_sps;
|
||||
string m_pps;
|
||||
H264Frame::Ptr _h264frame;
|
||||
string _sps;
|
||||
string _pps;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -50,17 +50,17 @@ static uint32_t addressToInt(const string &ip){
|
||||
}
|
||||
|
||||
std::shared_ptr<uint32_t> MultiCastAddressMaker::obtain(uint32_t iTry) {
|
||||
lock_guard<recursive_mutex> lck(m_mtx);
|
||||
lock_guard<recursive_mutex> lck(_mtx);
|
||||
GET_CONFIG_AND_REGISTER(string,addrMinStr,Config::MultiCast::kAddrMin);
|
||||
GET_CONFIG_AND_REGISTER(string,addrMaxStr,Config::MultiCast::kAddrMax);
|
||||
uint32_t addrMin = addressToInt(addrMinStr);
|
||||
uint32_t addrMax = addressToInt(addrMaxStr);
|
||||
|
||||
if(m_iAddr > addrMax || m_iAddr == 0){
|
||||
m_iAddr = addrMin;
|
||||
if(_iAddr > addrMax || _iAddr == 0){
|
||||
_iAddr = addrMin;
|
||||
}
|
||||
auto iGotAddr = m_iAddr++;
|
||||
if(m_setBadAddr.find(iGotAddr) != m_setBadAddr.end()){
|
||||
auto iGotAddr = _iAddr++;
|
||||
if(_setBadAddr.find(iGotAddr) != _setBadAddr.end()){
|
||||
//已经分配过了
|
||||
if(iTry){
|
||||
return obtain(--iTry);
|
||||
@ -69,7 +69,7 @@ std::shared_ptr<uint32_t> MultiCastAddressMaker::obtain(uint32_t iTry) {
|
||||
ErrorL;
|
||||
return nullptr;
|
||||
}
|
||||
m_setBadAddr.emplace(iGotAddr);
|
||||
_setBadAddr.emplace(iGotAddr);
|
||||
std::shared_ptr<uint32_t> ret(new uint32_t(iGotAddr),[](uint32_t *ptr){
|
||||
MultiCastAddressMaker::Instance().release(*ptr);
|
||||
delete ptr;
|
||||
@ -77,8 +77,8 @@ std::shared_ptr<uint32_t> MultiCastAddressMaker::obtain(uint32_t iTry) {
|
||||
return ret;
|
||||
}
|
||||
void MultiCastAddressMaker::release(uint32_t iAddr){
|
||||
lock_guard<recursive_mutex> lck(m_mtx);
|
||||
m_setBadAddr.erase(iAddr);
|
||||
lock_guard<recursive_mutex> lck(_mtx);
|
||||
_setBadAddr.erase(iAddr);
|
||||
}
|
||||
|
||||
|
||||
@ -86,16 +86,16 @@ recursive_mutex RtpBroadCaster::g_mtx;
|
||||
unordered_map<string, weak_ptr<RtpBroadCaster> > RtpBroadCaster::g_mapBroadCaster;
|
||||
|
||||
void RtpBroadCaster::setDetachCB(void* listener, const onDetach& cb) {
|
||||
lock_guard<recursive_mutex> lck(m_mtx);
|
||||
lock_guard<recursive_mutex> lck(_mtx);
|
||||
if(cb){
|
||||
m_mapDetach.emplace(listener,cb);
|
||||
_mapDetach.emplace(listener,cb);
|
||||
}else{
|
||||
m_mapDetach.erase(listener);
|
||||
_mapDetach.erase(listener);
|
||||
}
|
||||
}
|
||||
RtpBroadCaster::~RtpBroadCaster() {
|
||||
m_pReader->setReadCB(nullptr);
|
||||
m_pReader->setDetachCB(nullptr);
|
||||
_pReader->setReadCB(nullptr);
|
||||
_pReader->setDetachCB(nullptr);
|
||||
DebugL;
|
||||
}
|
||||
RtpBroadCaster::RtpBroadCaster(const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream) {
|
||||
@ -104,55 +104,55 @@ RtpBroadCaster::RtpBroadCaster(const string &strLocalIp,const string &strVhost,c
|
||||
auto strErr = StrPrinter << "未找到媒体源:" << strVhost << " " << strApp << " " << strStream << endl;
|
||||
throw std::runtime_error(strErr);
|
||||
}
|
||||
m_multiAddr = MultiCastAddressMaker::Instance().obtain();
|
||||
_multiAddr = MultiCastAddressMaker::Instance().obtain();
|
||||
for(auto i = 0; i < 2; i++){
|
||||
m_apUdpSock[i].reset(new Socket());
|
||||
if(!m_apUdpSock[i]->bindUdpSock(0, strLocalIp.data())){
|
||||
_apUdpSock[i].reset(new Socket());
|
||||
if(!_apUdpSock[i]->bindUdpSock(0, strLocalIp.data())){
|
||||
auto strErr = StrPrinter << "绑定UDP端口失败:" << strLocalIp << endl;
|
||||
throw std::runtime_error(strErr);
|
||||
}
|
||||
auto fd = m_apUdpSock[i]->rawFD();
|
||||
auto fd = _apUdpSock[i]->rawFD();
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,udpTTL,Config::MultiCast::kUdpTTL);
|
||||
|
||||
SockUtil::setMultiTTL(fd, udpTTL);
|
||||
SockUtil::setMultiLOOP(fd, false);
|
||||
SockUtil::setMultiIF(fd, strLocalIp.data());
|
||||
|
||||
struct sockaddr_in &peerAddr = m_aPeerUdpAddr[i];
|
||||
struct sockaddr_in &peerAddr = _aPeerUdpAddr[i];
|
||||
peerAddr.sin_family = AF_INET;
|
||||
peerAddr.sin_port = htons(m_apUdpSock[i]->get_local_port());
|
||||
peerAddr.sin_addr.s_addr = htonl(*m_multiAddr);
|
||||
peerAddr.sin_port = htons(_apUdpSock[i]->get_local_port());
|
||||
peerAddr.sin_addr.s_addr = htonl(*_multiAddr);
|
||||
bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero);
|
||||
}
|
||||
m_pReader = src->getRing()->attach();
|
||||
m_pReader->setReadCB([this](const RtpPacket::Ptr &pkt){
|
||||
_pReader = src->getRing()->attach();
|
||||
_pReader->setReadCB([this](const RtpPacket::Ptr &pkt){
|
||||
int i = (int)(pkt->type);
|
||||
auto &pSock = m_apUdpSock[i];
|
||||
auto &peerAddr = m_aPeerUdpAddr[i];
|
||||
auto &pSock = _apUdpSock[i];
|
||||
auto &peerAddr = _aPeerUdpAddr[i];
|
||||
BufferRtp::Ptr buffer(new BufferRtp(pkt,4));
|
||||
pSock->send(buffer,SOCKET_DEFAULE_FLAGS | FLAG_MORE,(struct sockaddr *)(&peerAddr));
|
||||
});
|
||||
m_pReader->setDetachCB([this](){
|
||||
unordered_map<void * , onDetach > m_mapDetach_copy;
|
||||
_pReader->setDetachCB([this](){
|
||||
unordered_map<void * , onDetach > _mapDetach_copy;
|
||||
{
|
||||
lock_guard<recursive_mutex> lck(m_mtx);
|
||||
m_mapDetach_copy = std::move(m_mapDetach);
|
||||
lock_guard<recursive_mutex> lck(_mtx);
|
||||
_mapDetach_copy = std::move(_mapDetach);
|
||||
}
|
||||
for(auto &pr : m_mapDetach_copy){
|
||||
for(auto &pr : _mapDetach_copy){
|
||||
pr.second();
|
||||
}
|
||||
});
|
||||
DebugL << MultiCastAddressMaker::toString(*m_multiAddr) << " "
|
||||
<< m_apUdpSock[0]->get_local_port() << " "
|
||||
<< m_apUdpSock[1]->get_local_port() << " "
|
||||
DebugL << MultiCastAddressMaker::toString(*_multiAddr) << " "
|
||||
<< _apUdpSock[0]->get_local_port() << " "
|
||||
<< _apUdpSock[1]->get_local_port() << " "
|
||||
<< strVhost << " "
|
||||
<< strApp << " " << strStream;
|
||||
}
|
||||
uint16_t RtpBroadCaster::getPort(TrackType trackType){
|
||||
return m_apUdpSock[trackType]->get_local_port();
|
||||
return _apUdpSock[trackType]->get_local_port();
|
||||
}
|
||||
string RtpBroadCaster::getIP(){
|
||||
return inet_ntoa(m_aPeerUdpAddr[0].sin_addr);
|
||||
return inet_ntoa(_aPeerUdpAddr[0].sin_addr);
|
||||
}
|
||||
RtpBroadCaster::Ptr RtpBroadCaster::make(const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream){
|
||||
try{
|
||||
|
@ -64,9 +64,9 @@ public:
|
||||
private:
|
||||
MultiCastAddressMaker(){};
|
||||
void release(uint32_t iAddr);
|
||||
uint32_t m_iAddr = 0;
|
||||
recursive_mutex m_mtx;
|
||||
unordered_set<uint32_t> m_setBadAddr;
|
||||
uint32_t _iAddr = 0;
|
||||
recursive_mutex _mtx;
|
||||
unordered_set<uint32_t> _setBadAddr;
|
||||
};
|
||||
class RtpBroadCaster {
|
||||
public:
|
||||
@ -82,12 +82,12 @@ private:
|
||||
static unordered_map<string , weak_ptr<RtpBroadCaster> > g_mapBroadCaster;
|
||||
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;
|
||||
unordered_map<void * , onDetach > m_mapDetach;
|
||||
RtspMediaSource::RingType::RingReader::Ptr m_pReader;
|
||||
Socket::Ptr m_apUdpSock[2];
|
||||
struct sockaddr_in m_aPeerUdpAddr[2];
|
||||
std::shared_ptr<uint32_t> _multiAddr;
|
||||
recursive_mutex _mtx;
|
||||
unordered_map<void * , onDetach > _mapDetach;
|
||||
RtspMediaSource::RingType::RingReader::Ptr _pReader;
|
||||
Socket::Ptr _apUdpSock[2];
|
||||
struct sockaddr_in _aPeerUdpAddr[2];
|
||||
|
||||
RtpBroadCaster(const string &strLocalIp,const string &strVhost,const string &strApp,const string &strStream);
|
||||
|
||||
|
@ -68,7 +68,7 @@ RtpParser::RtpParser(const string& sdp) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_fDuration = getTimeInSDP(sdp);
|
||||
_fDuration = getTimeInSDP(sdp);
|
||||
}
|
||||
|
||||
bool RtpParser::inputRtp(const RtpPacket::Ptr & rtp) {
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp);
|
||||
|
||||
float getDuration() const override {
|
||||
return m_fDuration;
|
||||
return _fDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,7 +76,7 @@ private:
|
||||
inline void onGetAudioTrack(const RtspTrack &audio);
|
||||
inline void onGetVideoTrack(const RtspTrack &video);
|
||||
private:
|
||||
float m_fDuration = 0;
|
||||
float _fDuration = 0;
|
||||
AudioTrack::Ptr _audioTrack;
|
||||
VideoTrack::Ptr _videoTrack;
|
||||
RtpCodec::Ptr _audioRtpDecoder;
|
||||
|
@ -83,79 +83,79 @@ public:
|
||||
break;
|
||||
}
|
||||
if (start == buf) {
|
||||
m_strMethod = FindField(line.c_str(), NULL, " ");
|
||||
m_strFullUrl = FindField(line.c_str(), " ", " ");
|
||||
auto args_pos = m_strFullUrl.find('?');
|
||||
_strMethod = FindField(line.c_str(), NULL, " ");
|
||||
_strFullUrl = FindField(line.c_str(), " ", " ");
|
||||
auto args_pos = _strFullUrl.find('?');
|
||||
if(args_pos != string::npos){
|
||||
m_strUrl = m_strFullUrl.substr(0,args_pos);
|
||||
m_mapUrlArgs = parseArgs(m_strFullUrl.substr(args_pos + 1 ));
|
||||
_strUrl = _strFullUrl.substr(0,args_pos);
|
||||
_mapUrlArgs = parseArgs(_strFullUrl.substr(args_pos + 1 ));
|
||||
}else{
|
||||
m_strUrl = m_strFullUrl;
|
||||
_strUrl = _strFullUrl;
|
||||
}
|
||||
m_strTail = FindField(line.c_str(), (m_strFullUrl + " ").c_str(), NULL);
|
||||
_strTail = FindField(line.c_str(), (_strFullUrl + " ").c_str(), NULL);
|
||||
} else {
|
||||
auto field = FindField(line.c_str(), NULL, ": ");
|
||||
auto value = FindField(line.c_str(), ": ", NULL);
|
||||
if (field.size() != 0) {
|
||||
m_mapHeaders[field] = value;
|
||||
_mapHeaders[field] = value;
|
||||
}
|
||||
}
|
||||
start = start + line.size() + 2;
|
||||
if (strncmp(start, "\r\n", 2) == 0) { //协议解析完毕
|
||||
m_strContent = FindField(start, "\r\n", NULL);
|
||||
_strContent = FindField(start, "\r\n", NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const string& Method() const {
|
||||
//rtsp方法
|
||||
return m_strMethod;
|
||||
return _strMethod;
|
||||
}
|
||||
const string& Url() const {
|
||||
//rtsp url
|
||||
return m_strUrl;
|
||||
return _strUrl;
|
||||
}
|
||||
const string& FullUrl() const {
|
||||
//rtsp url with args
|
||||
return m_strFullUrl;
|
||||
return _strFullUrl;
|
||||
}
|
||||
const string& Tail() const {
|
||||
//RTSP/1.0
|
||||
return m_strTail;
|
||||
return _strTail;
|
||||
}
|
||||
const string& operator[](const char *name) const {
|
||||
//rtsp field
|
||||
auto it = m_mapHeaders.find(name);
|
||||
if (it == m_mapHeaders.end()) {
|
||||
return m_strNull;
|
||||
auto it = _mapHeaders.find(name);
|
||||
if (it == _mapHeaders.end()) {
|
||||
return _strNull;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
const string& Content() const {
|
||||
return m_strContent;
|
||||
return _strContent;
|
||||
}
|
||||
void Clear() {
|
||||
m_strMethod.clear();
|
||||
m_strUrl.clear();
|
||||
m_strFullUrl.clear();
|
||||
m_strTail.clear();
|
||||
m_strContent.clear();
|
||||
m_mapHeaders.clear();
|
||||
m_mapUrlArgs.clear();
|
||||
_strMethod.clear();
|
||||
_strUrl.clear();
|
||||
_strFullUrl.clear();
|
||||
_strTail.clear();
|
||||
_strContent.clear();
|
||||
_mapHeaders.clear();
|
||||
_mapUrlArgs.clear();
|
||||
}
|
||||
|
||||
void setUrl(const string& url) {
|
||||
this->m_strUrl = url;
|
||||
this->_strUrl = url;
|
||||
}
|
||||
void setContent(const string& content) {
|
||||
this->m_strContent = content;
|
||||
this->_strContent = content;
|
||||
}
|
||||
|
||||
StrCaseMap& getValues() const {
|
||||
return m_mapHeaders;
|
||||
return _mapHeaders;
|
||||
}
|
||||
StrCaseMap& getUrlArgs() const {
|
||||
return m_mapUrlArgs;
|
||||
return _mapUrlArgs;
|
||||
}
|
||||
|
||||
static StrCaseMap parseArgs(const string &str,const char *pair_delim = "&", const char *key_delim = "="){
|
||||
@ -170,14 +170,14 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
string m_strMethod;
|
||||
string m_strUrl;
|
||||
string m_strTail;
|
||||
string m_strContent;
|
||||
string m_strNull;
|
||||
string m_strFullUrl;
|
||||
mutable StrCaseMap m_mapHeaders;
|
||||
mutable StrCaseMap m_mapUrlArgs;
|
||||
string _strMethod;
|
||||
string _strUrl;
|
||||
string _strTail;
|
||||
string _strContent;
|
||||
string _strNull;
|
||||
string _strFullUrl;
|
||||
mutable StrCaseMap _mapHeaders;
|
||||
mutable StrCaseMap _mapUrlArgs;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -60,46 +60,46 @@ public:
|
||||
|
||||
RtspMediaSource(const string &strVhost,const string &strApp, const string &strId) :
|
||||
MediaSource(RTSP_SCHEMA,strVhost,strApp,strId),
|
||||
m_pRing(new RingBuffer<RtpPacket::Ptr>()) {
|
||||
_pRing(new RingBuffer<RtpPacket::Ptr>()) {
|
||||
}
|
||||
virtual ~RtspMediaSource() {}
|
||||
|
||||
const RingType::Ptr &getRing() const {
|
||||
//获取媒体源的rtp环形缓冲
|
||||
return m_pRing;
|
||||
return _pRing;
|
||||
}
|
||||
const string& getSdp() const {
|
||||
//获取该源的媒体描述信息
|
||||
return m_strSdp;
|
||||
return _strSdp;
|
||||
}
|
||||
|
||||
virtual uint32_t getSsrc(TrackType trackType) {
|
||||
return m_mapTracks[trackType].ssrc;
|
||||
return _mapTracks[trackType].ssrc;
|
||||
}
|
||||
virtual uint16_t getSeqence(TrackType trackType) {
|
||||
return m_mapTracks[trackType].seq;
|
||||
return _mapTracks[trackType].seq;
|
||||
}
|
||||
virtual uint32_t getTimestamp(TrackType trackType) {
|
||||
return m_mapTracks[trackType].timeStamp;
|
||||
return _mapTracks[trackType].timeStamp;
|
||||
}
|
||||
|
||||
virtual void onGetSDP(const string& sdp) {
|
||||
//派生类设置该媒体源媒体描述信息
|
||||
m_strSdp = sdp;
|
||||
_strSdp = sdp;
|
||||
regist();
|
||||
}
|
||||
virtual void onGetRTP(const RtpPacket::Ptr &rtppt, bool keyPos) {
|
||||
auto &trackRef = m_mapTracks[rtppt->type];
|
||||
auto &trackRef = _mapTracks[rtppt->type];
|
||||
trackRef.seq = rtppt->sequence;
|
||||
trackRef.timeStamp = rtppt->timeStamp;
|
||||
trackRef.ssrc = rtppt->ssrc;
|
||||
trackRef.type = rtppt->type;
|
||||
m_pRing->write(rtppt,keyPos);
|
||||
_pRing->write(rtppt,keyPos);
|
||||
}
|
||||
protected:
|
||||
unordered_map<int, RtspTrack> m_mapTracks;
|
||||
string m_strSdp; //媒体描述信息
|
||||
RingType::Ptr m_pRing; //rtp环形缓冲
|
||||
unordered_map<int, RtspTrack> _mapTracks;
|
||||
string _strSdp; //媒体描述信息
|
||||
RingType::Ptr _pRing; //rtp环形缓冲
|
||||
};
|
||||
|
||||
} /* namespace Rtsp */
|
||||
|
@ -44,9 +44,9 @@ namespace ZL {
|
||||
namespace Rtsp {
|
||||
|
||||
#define POP_HEAD(trackidx) \
|
||||
auto it = m_amapRtpSort[trackidx].begin(); \
|
||||
auto it = _amapRtpSort[trackidx].begin(); \
|
||||
onRecvRTP_l(it->second, trackidx); \
|
||||
m_amapRtpSort[trackidx].erase(it);
|
||||
_amapRtpSort[trackidx].erase(it);
|
||||
|
||||
#define RTP_BUF_SIZE (4 * 1024)
|
||||
|
||||
@ -54,48 +54,48 @@ const char kRtspMd5Nonce[] = "rtsp_md5_nonce";
|
||||
const char kRtspRealm[] = "rtsp_realm";
|
||||
|
||||
RtspPlayer::RtspPlayer(void){
|
||||
m_pktPool.setSize(64);
|
||||
_pktPool.setSize(64);
|
||||
}
|
||||
RtspPlayer::~RtspPlayer(void) {
|
||||
teardown();
|
||||
if (m_pucRtpBuf) {
|
||||
delete[] m_pucRtpBuf;
|
||||
m_pucRtpBuf = nullptr;
|
||||
if (_pucRtpBuf) {
|
||||
delete[] _pucRtpBuf;
|
||||
_pucRtpBuf = nullptr;
|
||||
}
|
||||
DebugL<<endl;
|
||||
}
|
||||
void RtspPlayer::teardown(){
|
||||
if (alive()) {
|
||||
sendRtspRequest("TEARDOWN" ,m_strContentBase);
|
||||
sendRtspRequest("TEARDOWN" ,_strContentBase);
|
||||
shutdown();
|
||||
}
|
||||
|
||||
erase(kRtspMd5Nonce);
|
||||
erase(kRtspRealm);
|
||||
m_uiTrackCnt = 0;
|
||||
m_onHandshake = nullptr;
|
||||
m_uiRtpBufLen = 0;
|
||||
m_strSession.clear();
|
||||
m_uiCseq = 1;
|
||||
m_strContentBase.clear();
|
||||
CLEAR_ARR(m_apUdpSock);
|
||||
CLEAR_ARR(m_aui16LastSeq)
|
||||
CLEAR_ARR(m_aui16FirstSeq)
|
||||
CLEAR_ARR(m_aui32SsrcErrorCnt)
|
||||
CLEAR_ARR(m_aui64RtpRecv)
|
||||
CLEAR_ARR(m_aui64SeqOkCnt)
|
||||
CLEAR_ARR(m_abSortStarted)
|
||||
CLEAR_ARR(m_aui64RtpRecv)
|
||||
CLEAR_ARR(m_aui16NowSeq)
|
||||
m_amapRtpSort[0].clear();
|
||||
m_amapRtpSort[1].clear();
|
||||
_uiTrackCnt = 0;
|
||||
_onHandshake = nullptr;
|
||||
_uiRtpBufLen = 0;
|
||||
_strSession.clear();
|
||||
_uiCseq = 1;
|
||||
_strContentBase.clear();
|
||||
CLEAR_ARR(_apUdpSock);
|
||||
CLEAR_ARR(_aui16LastSeq)
|
||||
CLEAR_ARR(_aui16FirstSeq)
|
||||
CLEAR_ARR(_aui32SsrcErrorCnt)
|
||||
CLEAR_ARR(_aui64RtpRecv)
|
||||
CLEAR_ARR(_aui64SeqOkCnt)
|
||||
CLEAR_ARR(_abSortStarted)
|
||||
CLEAR_ARR(_aui64RtpRecv)
|
||||
CLEAR_ARR(_aui16NowSeq)
|
||||
_amapRtpSort[0].clear();
|
||||
_amapRtpSort[1].clear();
|
||||
|
||||
m_pBeatTimer.reset();
|
||||
m_pPlayTimer.reset();
|
||||
m_pRtpTimer.reset();
|
||||
m_fSeekTo = 0;
|
||||
CLEAR_ARR(m_adFistStamp);
|
||||
CLEAR_ARR(m_adNowStamp);
|
||||
_pBeatTimer.reset();
|
||||
_pPlayTimer.reset();
|
||||
_pRtpTimer.reset();
|
||||
_fSeekTo = 0;
|
||||
CLEAR_ARR(_adFistStamp);
|
||||
CLEAR_ARR(_adNowStamp);
|
||||
}
|
||||
|
||||
void RtspPlayer::play(const char* strUrl){
|
||||
@ -131,9 +131,9 @@ void RtspPlayer::play(const char* strUrl, const char *strUser, const char *strPw
|
||||
(*this)[kRtspPwdIsMD5] = false;
|
||||
}
|
||||
|
||||
m_eType = eType;
|
||||
if (m_eType == RTP_TCP && !m_pucRtpBuf) {
|
||||
m_pucRtpBuf = new uint8_t[RTP_BUF_SIZE];
|
||||
_eType = eType;
|
||||
if (_eType == RTP_TCP && !_pucRtpBuf) {
|
||||
_pucRtpBuf = new uint8_t[RTP_BUF_SIZE];
|
||||
}
|
||||
auto ip = FindField(strUrl, "://", "/");
|
||||
if (!ip.size()) {
|
||||
@ -148,7 +148,7 @@ void RtspPlayer::play(const char* strUrl, const char *strUser, const char *strPw
|
||||
ip = FindField(ip.c_str(), NULL, ":");
|
||||
}
|
||||
|
||||
m_strUrl = strUrl;
|
||||
_strUrl = strUrl;
|
||||
if(!(*this)[PlayerBase::kNetAdapter].empty()){
|
||||
setNetAdapter((*this)[PlayerBase::kNetAdapter]);
|
||||
}
|
||||
@ -164,7 +164,7 @@ void RtspPlayer::onConnect(const SockException &err){
|
||||
sendDescribe();
|
||||
|
||||
weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
|
||||
m_pPlayTimer.reset( new Timer(10, [weakSelf]() {
|
||||
_pPlayTimer.reset( new Timer(10, [weakSelf]() {
|
||||
auto strongSelf=weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return false;
|
||||
@ -178,7 +178,7 @@ void RtspPlayer::onConnect(const SockException &err){
|
||||
void RtspPlayer::onRecv(const Buffer::Ptr& pBuf) {
|
||||
const char *buf = pBuf->data();
|
||||
int size = pBuf->size();
|
||||
if (m_onHandshake) {
|
||||
if (_onHandshake) {
|
||||
//rtsp回复
|
||||
int offset = 0;
|
||||
while(offset < size - 4){
|
||||
@ -203,16 +203,16 @@ void RtspPlayer::onRecv(const Buffer::Ptr& pBuf) {
|
||||
}
|
||||
}
|
||||
|
||||
if (m_eType == RTP_TCP && m_pucRtpBuf) {
|
||||
if (_eType == RTP_TCP && _pucRtpBuf) {
|
||||
//RTP data
|
||||
while (size > 0) {
|
||||
int added = RTP_BUF_SIZE - m_uiRtpBufLen;
|
||||
int added = RTP_BUF_SIZE - _uiRtpBufLen;
|
||||
added = (added > size ? size : added);
|
||||
memcpy(m_pucRtpBuf + m_uiRtpBufLen, buf, added);
|
||||
m_uiRtpBufLen += added;
|
||||
memcpy(_pucRtpBuf + _uiRtpBufLen, buf, added);
|
||||
_uiRtpBufLen += added;
|
||||
size -= added;
|
||||
buf += added;
|
||||
splitRtp(m_pucRtpBuf, m_uiRtpBufLen);
|
||||
splitRtp(_pucRtpBuf, _uiRtpBufLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -263,13 +263,13 @@ void RtspPlayer::handleResDESCRIBE(const Parser& parser) {
|
||||
StrPrinter << "DESCRIBE:" << parser.Url() << " " << parser.Tail() << endl);
|
||||
}
|
||||
auto strSdp = parser.Content();
|
||||
m_strContentBase = parser["Content-Base"];
|
||||
_strContentBase = parser["Content-Base"];
|
||||
|
||||
if(m_strContentBase.empty()){
|
||||
m_strContentBase = m_strUrl;
|
||||
if(_strContentBase.empty()){
|
||||
_strContentBase = _strUrl;
|
||||
}
|
||||
if (m_strContentBase.back() == '/') {
|
||||
m_strContentBase.pop_back();
|
||||
if (_strContentBase.back() == '/') {
|
||||
_strContentBase.pop_back();
|
||||
}
|
||||
|
||||
auto iLen = atoi(parser["Content-Length"].data());
|
||||
@ -278,26 +278,26 @@ void RtspPlayer::handleResDESCRIBE(const Parser& parser) {
|
||||
}
|
||||
|
||||
//解析sdp
|
||||
m_uiTrackCnt = parserSDP(strSdp, m_aTrackInfo);
|
||||
for (unsigned int i=0; i<m_uiTrackCnt; i++) {
|
||||
m_aTrackInfo[i].ssrc=0;
|
||||
m_aui32SsrcErrorCnt[i]=0;
|
||||
_uiTrackCnt = parserSDP(strSdp, _aTrackInfo);
|
||||
for (unsigned int i=0; i<_uiTrackCnt; i++) {
|
||||
_aTrackInfo[i].ssrc=0;
|
||||
_aui32SsrcErrorCnt[i]=0;
|
||||
}
|
||||
if (!m_uiTrackCnt) {
|
||||
if (!_uiTrackCnt) {
|
||||
throw std::runtime_error("解析SDP失败");
|
||||
}
|
||||
if (!onCheckSDP(strSdp, m_aTrackInfo, m_uiTrackCnt)) {
|
||||
if (!onCheckSDP(strSdp, _aTrackInfo, _uiTrackCnt)) {
|
||||
throw std::runtime_error("onCheckSDP faied");
|
||||
}
|
||||
sendSetup(0);
|
||||
}
|
||||
//发送SETUP命令
|
||||
bool RtspPlayer::sendSetup(unsigned int trackIndex) {
|
||||
m_onHandshake = std::bind(&RtspPlayer::handleResSETUP,this, placeholders::_1,trackIndex);
|
||||
_onHandshake = std::bind(&RtspPlayer::handleResSETUP,this, placeholders::_1,trackIndex);
|
||||
|
||||
auto &track = m_aTrackInfo[trackIndex];
|
||||
auto baseUrl = m_strContentBase + "/" + track.controlSuffix;
|
||||
switch (m_eType) {
|
||||
auto &track = _aTrackInfo[trackIndex];
|
||||
auto baseUrl = _strContentBase + "/" + track.controlSuffix;
|
||||
switch (_eType) {
|
||||
case RTP_TCP: {
|
||||
StrCaseMap header;
|
||||
header["Transport"] = StrPrinter << "RTP/AVP/TCP;unicast;interleaved=" << track.type * 2 << "-" << track.type * 2 + 1;
|
||||
@ -311,12 +311,12 @@ bool RtspPlayer::sendSetup(unsigned int trackIndex) {
|
||||
}
|
||||
break;
|
||||
case RTP_UDP: {
|
||||
m_apUdpSock[trackIndex].reset(new Socket());
|
||||
if (!m_apUdpSock[trackIndex]->bindUdpSock(0, get_local_ip().data())) {
|
||||
m_apUdpSock[trackIndex].reset();
|
||||
_apUdpSock[trackIndex].reset(new Socket());
|
||||
if (!_apUdpSock[trackIndex]->bindUdpSock(0, get_local_ip().data())) {
|
||||
_apUdpSock[trackIndex].reset();
|
||||
throw std::runtime_error("open udp sock err");
|
||||
}
|
||||
int port = m_apUdpSock[trackIndex]->get_local_port();
|
||||
int port = _apUdpSock[trackIndex]->get_local_port();
|
||||
StrCaseMap header;
|
||||
header["Transport"] = StrPrinter << "RTP/AVP;unicast;client_port=" << port << "-" << port + 1;
|
||||
return sendRtspRequest("SETUP",baseUrl,header);
|
||||
@ -334,33 +334,33 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex)
|
||||
StrPrinter << "SETUP:" << parser.Url() << " " << parser.Tail() << endl);
|
||||
}
|
||||
if (uiTrackIndex == 0) {
|
||||
m_strSession = parser["Session"];
|
||||
m_strSession.append(";");
|
||||
m_strSession = FindField(m_strSession.data(), nullptr, ";");
|
||||
_strSession = parser["Session"];
|
||||
_strSession.append(";");
|
||||
_strSession = FindField(_strSession.data(), nullptr, ";");
|
||||
}
|
||||
|
||||
auto strTransport = parser["Transport"];
|
||||
if(strTransport.find("TCP") != string::npos){
|
||||
m_eType = RTP_TCP;
|
||||
_eType = RTP_TCP;
|
||||
}else if(strTransport.find("multicast") != string::npos){
|
||||
m_eType = RTP_MULTICAST;
|
||||
_eType = RTP_MULTICAST;
|
||||
}else{
|
||||
m_eType = RTP_UDP;
|
||||
_eType = RTP_UDP;
|
||||
}
|
||||
|
||||
if(m_eType == RTP_TCP) {
|
||||
if(_eType == RTP_TCP) {
|
||||
string interleaved = FindField( FindField((strTransport + ";").c_str(), "interleaved=", ";").c_str(), NULL, "-");
|
||||
m_aTrackInfo[uiTrackIndex].interleaved = atoi(interleaved.c_str());
|
||||
_aTrackInfo[uiTrackIndex].interleaved = atoi(interleaved.c_str());
|
||||
}else{
|
||||
const char *strPos = (m_eType == RTP_MULTICAST ? "port=" : "server_port=") ;
|
||||
const char *strPos = (_eType == RTP_MULTICAST ? "port=" : "server_port=") ;
|
||||
auto port_str = FindField((strTransport + ";").c_str(), strPos, ";");
|
||||
uint16_t port = atoi(FindField(port_str.c_str(), NULL, "-").c_str());
|
||||
auto &pUdpSockRef = m_apUdpSock[uiTrackIndex];
|
||||
auto &pUdpSockRef = _apUdpSock[uiTrackIndex];
|
||||
if(!pUdpSockRef){
|
||||
pUdpSockRef.reset(new Socket());
|
||||
}
|
||||
|
||||
if (m_eType == RTP_MULTICAST) {
|
||||
if (_eType == RTP_MULTICAST) {
|
||||
auto multiAddr = FindField((strTransport + ";").c_str(), "destination=", ";");
|
||||
if (!pUdpSockRef->bindUdpSock(port, "0.0.0.0")) {
|
||||
pUdpSockRef.reset();
|
||||
@ -379,14 +379,14 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex)
|
||||
}
|
||||
}
|
||||
|
||||
if (uiTrackIndex < m_uiTrackCnt - 1) {
|
||||
if (uiTrackIndex < _uiTrackCnt - 1) {
|
||||
//需要继续发送SETUP命令
|
||||
sendSetup(uiTrackIndex + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt && m_eType != RTP_TCP; i++) {
|
||||
auto &pUdpSockRef = m_apUdpSock[i];
|
||||
for (unsigned int i = 0; i < _uiTrackCnt && _eType != RTP_TCP; i++) {
|
||||
auto &pUdpSockRef = _apUdpSock[i];
|
||||
if(!pUdpSockRef){
|
||||
continue;
|
||||
}
|
||||
@ -406,7 +406,7 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex)
|
||||
}
|
||||
/////////////////////////心跳/////////////////////////////////
|
||||
weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
|
||||
m_pBeatTimer.reset(new Timer(5, [weakSelf](){
|
||||
_pBeatTimer.reset(new Timer(5, [weakSelf](){
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if (!strongSelf){
|
||||
return false;
|
||||
@ -417,47 +417,47 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex)
|
||||
}
|
||||
|
||||
bool RtspPlayer::sendOptions() {
|
||||
m_onHandshake = [](const Parser& parser){
|
||||
_onHandshake = [](const Parser& parser){
|
||||
return true;
|
||||
};
|
||||
return sendRtspRequest("OPTIONS",m_strContentBase);
|
||||
return sendRtspRequest("OPTIONS",_strContentBase);
|
||||
}
|
||||
|
||||
bool RtspPlayer::sendDescribe() {
|
||||
//发送DESCRIBE命令后处理函数:handleResDESCRIBE
|
||||
m_onHandshake = std::bind(&RtspPlayer::handleResDESCRIBE,this, placeholders::_1);
|
||||
_onHandshake = std::bind(&RtspPlayer::handleResDESCRIBE,this, placeholders::_1);
|
||||
StrCaseMap header;
|
||||
header["Accept"] = "application/sdp";
|
||||
return sendRtspRequest("DESCRIBE",m_strUrl,header);
|
||||
return sendRtspRequest("DESCRIBE",_strUrl,header);
|
||||
}
|
||||
|
||||
|
||||
bool RtspPlayer::sendPause(bool bPause,float fTime){
|
||||
if(!bPause){
|
||||
//修改时间轴
|
||||
m_aNowStampTicker[0].resetTime();
|
||||
m_aNowStampTicker[1].resetTime();
|
||||
_aNowStampTicker[0].resetTime();
|
||||
_aNowStampTicker[1].resetTime();
|
||||
float iTimeInc = fTime - getProgressTime();
|
||||
for(unsigned int i = 0 ;i < m_uiTrackCnt ;i++){
|
||||
if (m_aTrackInfo[i].type == TrackVideo) {
|
||||
m_adFistStamp[i] = m_adNowStamp[i] + iTimeInc * 90000.0;
|
||||
}else if (m_aTrackInfo[i].type == TrackAudio){
|
||||
for(unsigned int i = 0 ;i < _uiTrackCnt ;i++){
|
||||
if (_aTrackInfo[i].type == TrackVideo) {
|
||||
_adFistStamp[i] = _adNowStamp[i] + iTimeInc * 90000.0;
|
||||
}else if (_aTrackInfo[i].type == TrackAudio){
|
||||
//todo(xzl) 修复此处
|
||||
// m_adFistStamp[i] = m_adNowStamp[i] + iTimeInc * getAudioSampleRate();
|
||||
// _adFistStamp[i] = _adNowStamp[i] + iTimeInc * getAudioSampleRate();
|
||||
}
|
||||
m_adNowStamp[i] = m_adFistStamp[i];
|
||||
_adNowStamp[i] = _adFistStamp[i];
|
||||
}
|
||||
m_fSeekTo = fTime;
|
||||
_fSeekTo = fTime;
|
||||
}
|
||||
|
||||
//开启或暂停rtsp
|
||||
m_onHandshake = std::bind(&RtspPlayer::handleResPAUSE,this, placeholders::_1,bPause);
|
||||
_onHandshake = std::bind(&RtspPlayer::handleResPAUSE,this, placeholders::_1,bPause);
|
||||
|
||||
StrCaseMap header;
|
||||
char buf[8];
|
||||
sprintf(buf,"%.2f",fTime);
|
||||
header["Range"] = StrPrinter << "npt=" << buf << "-";
|
||||
return sendRtspRequest(bPause ? "PAUSE" : "PLAY",m_strContentBase,header);
|
||||
return sendRtspRequest(bPause ? "PAUSE" : "PLAY",_strContentBase,header);
|
||||
}
|
||||
void RtspPlayer::pause(bool bPause) {
|
||||
sendPause(bPause,getProgressTime());
|
||||
@ -470,16 +470,16 @@ void RtspPlayer::handleResPAUSE(const Parser& parser, bool bPause) {
|
||||
}
|
||||
if (!bPause) {
|
||||
//修正时间轴
|
||||
m_aNowStampTicker[0].resetTime();
|
||||
m_aNowStampTicker[1].resetTime();
|
||||
_aNowStampTicker[0].resetTime();
|
||||
_aNowStampTicker[1].resetTime();
|
||||
auto strRange = parser["Range"];
|
||||
if (strRange.size()) {
|
||||
auto strStart = FindField(strRange.data(), "npt=", "-");
|
||||
if (strStart == "now") {
|
||||
strStart = "0";
|
||||
}
|
||||
m_fSeekTo = atof(strStart.data());
|
||||
DebugL << "Range:" << m_fSeekTo << " " << strStart ;
|
||||
_fSeekTo = atof(strStart.data());
|
||||
DebugL << "Range:" << _fSeekTo << " " << strStart ;
|
||||
}
|
||||
auto strRtpInfo = parser["RTP-Info"];
|
||||
if (strRtpInfo.size()) {
|
||||
@ -490,14 +490,14 @@ void RtspPlayer::handleResPAUSE(const Parser& parser, bool bPause) {
|
||||
auto strControlSuffix = strTrack.substr(1 + strTrack.rfind('/'),strTrack.find(';') - strTrack.rfind('/') - 1);
|
||||
auto strRtpTime = FindField(strTrack.data(), "rtptime=", ";");
|
||||
auto iIdx = getTrackIndexByControlSuffix(strControlSuffix);
|
||||
m_adFistStamp[iIdx] = atoll(strRtpTime.data());
|
||||
m_adNowStamp[iIdx] = m_adFistStamp[iIdx];
|
||||
_adFistStamp[iIdx] = atoll(strRtpTime.data());
|
||||
_adNowStamp[iIdx] = _adFistStamp[iIdx];
|
||||
DebugL << "rtptime:" << strControlSuffix <<" " << strRtpTime;
|
||||
}
|
||||
}
|
||||
onPlayResult_l(SockException(Err_success, "rtsp play success"));
|
||||
} else {
|
||||
m_pRtpTimer.reset();
|
||||
_pRtpTimer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@ -518,8 +518,8 @@ int RtspPlayer::onProcess(const char* pcBuf) {
|
||||
parser.setContent(strContent);
|
||||
}
|
||||
}
|
||||
auto fun = m_onHandshake;
|
||||
m_onHandshake = nullptr;
|
||||
auto fun = _onHandshake;
|
||||
_onHandshake = nullptr;
|
||||
if(fun){
|
||||
fun(parser);
|
||||
}
|
||||
@ -576,7 +576,7 @@ void RtspPlayer::splitRtp(unsigned char* pucRtp, unsigned int uiLen) {
|
||||
uiLen -= (pos - rtp_ptr);
|
||||
rtp_ptr = pos;
|
||||
}
|
||||
m_uiRtpBufLen = uiLen;
|
||||
_uiRtpBufLen = uiLen;
|
||||
if (rtp_ptr != pucRtp) {
|
||||
memmove(pucRtp, rtp_ptr, uiLen);
|
||||
}
|
||||
@ -589,8 +589,8 @@ void RtspPlayer::splitRtp(unsigned char* pucRtp, unsigned int uiLen) {
|
||||
|
||||
|
||||
bool RtspPlayer::handleOneRtp(int iTrackidx, unsigned char *pucData, unsigned int uiLen) {
|
||||
auto &track = m_aTrackInfo[iTrackidx];
|
||||
auto pt_ptr=m_pktPool.obtain();
|
||||
auto &track = _aTrackInfo[iTrackidx];
|
||||
auto pt_ptr=_pktPool.obtain();
|
||||
auto &rtppt=*pt_ptr;
|
||||
rtppt.interleaved = track.interleaved;
|
||||
rtppt.length = uiLen + 4;
|
||||
@ -613,13 +613,13 @@ bool RtspPlayer::handleOneRtp(int iTrackidx, unsigned char *pucData, unsigned in
|
||||
} else if (track.ssrc != rtppt.ssrc) {
|
||||
//ssrc错误
|
||||
WarnL << "ssrc错误";
|
||||
if (m_aui32SsrcErrorCnt[iTrackidx]++ > 10) {
|
||||
if (_aui32SsrcErrorCnt[iTrackidx]++ > 10) {
|
||||
track.ssrc = rtppt.ssrc;
|
||||
WarnL << "ssrc更换!";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
m_aui32SsrcErrorCnt[iTrackidx] = 0;
|
||||
_aui32SsrcErrorCnt[iTrackidx] = 0;
|
||||
|
||||
rtppt.payload[0] = '$';
|
||||
rtppt.payload[1] = rtppt.interleaved;
|
||||
@ -642,30 +642,30 @@ bool RtspPlayer::handleOneRtp(int iTrackidx, unsigned char *pucData, unsigned in
|
||||
memcpy(rtppt.payload + 4, pucData, uiLen);
|
||||
|
||||
/////////////////////////////////RTP排序逻辑///////////////////////////////////
|
||||
if(rtppt.sequence != (uint16_t)(m_aui16LastSeq[iTrackidx] + 1) && m_aui16LastSeq[iTrackidx] != 0){
|
||||
if(rtppt.sequence != (uint16_t)(_aui16LastSeq[iTrackidx] + 1) && _aui16LastSeq[iTrackidx] != 0){
|
||||
//包乱序或丢包
|
||||
m_aui64SeqOkCnt[iTrackidx] = 0;
|
||||
m_abSortStarted[iTrackidx] = true;
|
||||
//WarnL << "包乱序或丢包:" << trackidx <<" " << rtppt.sequence << " " << m_aui16LastSeq[trackidx];
|
||||
_aui64SeqOkCnt[iTrackidx] = 0;
|
||||
_abSortStarted[iTrackidx] = true;
|
||||
//WarnL << "包乱序或丢包:" << trackidx <<" " << rtppt.sequence << " " << _aui16LastSeq[trackidx];
|
||||
}else{
|
||||
//正确序列的包
|
||||
m_aui64SeqOkCnt[iTrackidx]++;
|
||||
_aui64SeqOkCnt[iTrackidx]++;
|
||||
}
|
||||
m_aui16LastSeq[iTrackidx] = rtppt.sequence;
|
||||
_aui16LastSeq[iTrackidx] = rtppt.sequence;
|
||||
|
||||
//开始排序缓存
|
||||
if (m_abSortStarted[iTrackidx]) {
|
||||
m_amapRtpSort[iTrackidx].emplace(rtppt.sequence, pt_ptr);
|
||||
if (_abSortStarted[iTrackidx]) {
|
||||
_amapRtpSort[iTrackidx].emplace(rtppt.sequence, pt_ptr);
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,clearCount,Config::Rtp::kClearCount);
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,maxRtpCount,Config::Rtp::kMaxRtpCount);
|
||||
if (m_aui64SeqOkCnt[iTrackidx] >= clearCount) {
|
||||
if (_aui64SeqOkCnt[iTrackidx] >= clearCount) {
|
||||
//网络环境改善,需要清空排序缓存
|
||||
m_aui64SeqOkCnt[iTrackidx] = 0;
|
||||
m_abSortStarted[iTrackidx] = false;
|
||||
while (m_amapRtpSort[iTrackidx].size()) {
|
||||
_aui64SeqOkCnt[iTrackidx] = 0;
|
||||
_abSortStarted[iTrackidx] = false;
|
||||
while (_amapRtpSort[iTrackidx].size()) {
|
||||
POP_HEAD(iTrackidx)
|
||||
}
|
||||
} else if (m_amapRtpSort[iTrackidx].size() >= maxRtpCount) {
|
||||
} else if (_amapRtpSort[iTrackidx].size() >= maxRtpCount) {
|
||||
//排序缓存溢出
|
||||
POP_HEAD(iTrackidx)
|
||||
}
|
||||
@ -678,27 +678,27 @@ bool RtspPlayer::handleOneRtp(int iTrackidx, unsigned char *pucData, unsigned in
|
||||
}
|
||||
void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &rtppt, int trackidx){
|
||||
//统计丢包率
|
||||
if (m_aui16FirstSeq[trackidx] == 0 || rtppt->sequence < m_aui16FirstSeq[trackidx]) {
|
||||
m_aui16FirstSeq[trackidx] = rtppt->sequence;
|
||||
m_aui64RtpRecv[trackidx] = 0;
|
||||
if (_aui16FirstSeq[trackidx] == 0 || rtppt->sequence < _aui16FirstSeq[trackidx]) {
|
||||
_aui16FirstSeq[trackidx] = rtppt->sequence;
|
||||
_aui64RtpRecv[trackidx] = 0;
|
||||
}
|
||||
m_aui64RtpRecv[trackidx] ++;
|
||||
m_aui16NowSeq[trackidx] = rtppt->sequence;
|
||||
_aui64RtpRecv[trackidx] ++;
|
||||
_aui16NowSeq[trackidx] = rtppt->sequence;
|
||||
|
||||
if (m_aNowStampTicker[trackidx].elapsedTime() > 500) {
|
||||
m_adNowStamp[trackidx] = rtppt->timeStamp;
|
||||
if (_aNowStampTicker[trackidx].elapsedTime() > 500) {
|
||||
_adNowStamp[trackidx] = rtppt->timeStamp;
|
||||
}
|
||||
|
||||
onRecvRTP_l(rtppt,m_aTrackInfo[trackidx]);
|
||||
onRecvRTP_l(rtppt,_aTrackInfo[trackidx]);
|
||||
}
|
||||
float RtspPlayer::getRtpLossRate(int iTrackType) const{
|
||||
int iTrackIdx = getTrackIndexByTrackType((TrackType)iTrackType);
|
||||
if(iTrackIdx == -1){
|
||||
uint64_t totalRecv = 0;
|
||||
uint64_t totalSend = 0;
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
|
||||
totalRecv += m_aui64RtpRecv[i];
|
||||
totalSend += (m_aui16NowSeq[i] - m_aui16FirstSeq[i] + 1);
|
||||
for (unsigned int i = 0; i < _uiTrackCnt; i++) {
|
||||
totalRecv += _aui64RtpRecv[i];
|
||||
totalSend += (_aui16NowSeq[i] - _aui16FirstSeq[i] + 1);
|
||||
}
|
||||
if(totalSend == 0){
|
||||
return 0;
|
||||
@ -707,25 +707,25 @@ float RtspPlayer::getRtpLossRate(int iTrackType) const{
|
||||
}
|
||||
|
||||
|
||||
if(m_aui16NowSeq[iTrackIdx] - m_aui16FirstSeq[iTrackIdx] + 1 == 0){
|
||||
if(_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1 == 0){
|
||||
return 0;
|
||||
}
|
||||
return 1.0 - (double)m_aui64RtpRecv[iTrackIdx] / (m_aui16NowSeq[iTrackIdx] - m_aui16FirstSeq[iTrackIdx] + 1);
|
||||
return 1.0 - (double)_aui64RtpRecv[iTrackIdx] / (_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1);
|
||||
}
|
||||
|
||||
float RtspPlayer::getProgressTime() const{
|
||||
double iTime[2] = {0,0};
|
||||
for(unsigned int i = 0 ;i < m_uiTrackCnt ;i++){
|
||||
if (m_aTrackInfo[i].type == TrackVideo) {
|
||||
iTime[i] = (m_adNowStamp[i] - m_adFistStamp[i]) / 90000.0;
|
||||
}else if (m_aTrackInfo[i].type == TrackAudio){
|
||||
for(unsigned int i = 0 ;i < _uiTrackCnt ;i++){
|
||||
if (_aTrackInfo[i].type == TrackVideo) {
|
||||
iTime[i] = (_adNowStamp[i] - _adFistStamp[i]) / 90000.0;
|
||||
}else if (_aTrackInfo[i].type == TrackAudio){
|
||||
//todo(xzl) 修复此处
|
||||
#if 0
|
||||
iTime[i] = (m_adNowStamp[i] - m_adFistStamp[i]) / getAudioSampleRate();
|
||||
iTime[i] = (_adNowStamp[i] - _adFistStamp[i]) / getAudioSampleRate();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return m_fSeekTo + MAX(iTime[0],iTime[1]);
|
||||
return _fSeekTo + MAX(iTime[0],iTime[1]);
|
||||
}
|
||||
void RtspPlayer::seekToTime(float fTime) {
|
||||
sendPause(false,fTime);
|
||||
@ -733,9 +733,9 @@ void RtspPlayer::seekToTime(float fTime) {
|
||||
|
||||
bool RtspPlayer::sendRtspRequest(const string &cmd, const string &url,const StrCaseMap &header_const) {
|
||||
auto header = header_const;
|
||||
header.emplace("CSeq",StrPrinter << m_uiCseq++);
|
||||
if(!m_strSession.empty()){
|
||||
header.emplace("Session",m_strSession);
|
||||
header.emplace("CSeq",StrPrinter << _uiCseq++);
|
||||
if(!_strSession.empty()){
|
||||
header.emplace("Session",_strSession);
|
||||
}
|
||||
|
||||
if(!(*this)[kRtspRealm].empty() && !(*this)[PlayerBase::kRtspUser].empty()){
|
||||
@ -782,28 +782,28 @@ bool RtspPlayer::sendRtspRequest(const string &cmd, const string &url,const StrC
|
||||
|
||||
void RtspPlayer::onShutdown_l(const SockException &ex) {
|
||||
WarnL << ex.getErrCode() << " " << ex.what();
|
||||
m_pPlayTimer.reset();
|
||||
m_pRtpTimer.reset();
|
||||
m_pBeatTimer.reset();
|
||||
_pPlayTimer.reset();
|
||||
_pRtpTimer.reset();
|
||||
_pBeatTimer.reset();
|
||||
onShutdown(ex);
|
||||
}
|
||||
void RtspPlayer::onRecvRTP_l(const RtpPacket::Ptr &pRtppt, const RtspTrack &track) {
|
||||
m_rtpTicker.resetTime();
|
||||
_rtpTicker.resetTime();
|
||||
onRecvRTP(pRtppt,track);
|
||||
}
|
||||
void RtspPlayer::onPlayResult_l(const SockException &ex) {
|
||||
WarnL << ex.getErrCode() << " " << ex.what();
|
||||
m_pPlayTimer.reset();
|
||||
m_pRtpTimer.reset();
|
||||
_pPlayTimer.reset();
|
||||
_pRtpTimer.reset();
|
||||
if (!ex) {
|
||||
m_rtpTicker.resetTime();
|
||||
_rtpTicker.resetTime();
|
||||
weak_ptr<RtspPlayer> weakSelf = dynamic_pointer_cast<RtspPlayer>(shared_from_this());
|
||||
m_pRtpTimer.reset( new Timer(5, [weakSelf]() {
|
||||
_pRtpTimer.reset( new Timer(5, [weakSelf]() {
|
||||
auto strongSelf=weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return false;
|
||||
}
|
||||
if(strongSelf->m_rtpTicker.elapsedTime()>10000) {
|
||||
if(strongSelf->_rtpTicker.elapsedTime()>10000) {
|
||||
//recv rtp timeout!
|
||||
strongSelf->onShutdown_l(SockException(Err_timeout,"recv rtp timeout"));
|
||||
strongSelf->teardown();
|
||||
@ -816,16 +816,16 @@ void RtspPlayer::onPlayResult_l(const SockException &ex) {
|
||||
}
|
||||
|
||||
int RtspPlayer::getTrackIndexByControlSuffix(const string &controlSuffix) const{
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
|
||||
if (m_aTrackInfo[i].controlSuffix == controlSuffix) {
|
||||
for (unsigned int i = 0; i < _uiTrackCnt; i++) {
|
||||
if (_aTrackInfo[i].controlSuffix == controlSuffix) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int RtspPlayer::getTrackIndexByInterleaved(int interleaved) const{
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
|
||||
if (m_aTrackInfo[i].interleaved == interleaved) {
|
||||
for (unsigned int i = 0; i < _uiTrackCnt; i++) {
|
||||
if (_aTrackInfo[i].interleaved == interleaved) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -833,8 +833,8 @@ int RtspPlayer::getTrackIndexByInterleaved(int interleaved) const{
|
||||
}
|
||||
|
||||
int RtspPlayer::getTrackIndexByTrackType(TrackType trackType) const {
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
|
||||
if (m_aTrackInfo[i].type == trackType) {
|
||||
for (unsigned int i = 0; i < _uiTrackCnt; i++) {
|
||||
if (_aTrackInfo[i].type == trackType) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -101,45 +101,45 @@ private:
|
||||
bool sendDescribe();
|
||||
bool sendRtspRequest(const string &cmd, const string &url ,const StrCaseMap &header = StrCaseMap());
|
||||
private:
|
||||
string m_strUrl;
|
||||
unsigned int m_uiTrackCnt = 0;
|
||||
RtspTrack m_aTrackInfo[2];
|
||||
string _strUrl;
|
||||
unsigned int _uiTrackCnt = 0;
|
||||
RtspTrack _aTrackInfo[2];
|
||||
|
||||
function<void(const Parser&)> m_onHandshake;
|
||||
RtspMediaSource::PoolType m_pktPool;
|
||||
function<void(const Parser&)> _onHandshake;
|
||||
RtspMediaSource::PoolType _pktPool;
|
||||
|
||||
uint8_t *m_pucRtpBuf = nullptr;
|
||||
unsigned int m_uiRtpBufLen = 0;
|
||||
Socket::Ptr m_apUdpSock[2];
|
||||
uint8_t *_pucRtpBuf = nullptr;
|
||||
unsigned int _uiRtpBufLen = 0;
|
||||
Socket::Ptr _apUdpSock[2];
|
||||
//rtsp info
|
||||
string m_strSession;
|
||||
unsigned int m_uiCseq = 1;
|
||||
uint32_t m_aui32SsrcErrorCnt[2] = { 0, 0 };
|
||||
string m_strContentBase;
|
||||
eRtpType m_eType = RTP_TCP;
|
||||
string _strSession;
|
||||
unsigned int _uiCseq = 1;
|
||||
uint32_t _aui32SsrcErrorCnt[2] = { 0, 0 };
|
||||
string _strContentBase;
|
||||
eRtpType _eType = RTP_TCP;
|
||||
/* RTP包排序所用参数 */
|
||||
uint16_t m_aui16LastSeq[2] = { 0 , 0 };
|
||||
uint64_t m_aui64SeqOkCnt[2] = { 0 , 0};
|
||||
bool m_abSortStarted[2] = { 0 , 0};
|
||||
map<uint32_t , RtpPacket::Ptr> m_amapRtpSort[2];
|
||||
uint16_t _aui16LastSeq[2] = { 0 , 0 };
|
||||
uint64_t _aui64SeqOkCnt[2] = { 0 , 0};
|
||||
bool _abSortStarted[2] = { 0 , 0};
|
||||
map<uint32_t , RtpPacket::Ptr> _amapRtpSort[2];
|
||||
|
||||
/* 丢包率统计需要用到的参数 */
|
||||
uint16_t m_aui16FirstSeq[2] = { 0 , 0};
|
||||
uint16_t m_aui16NowSeq[2] = { 0 , 0 };
|
||||
uint64_t m_aui64RtpRecv[2] = { 0 , 0};
|
||||
uint16_t _aui16FirstSeq[2] = { 0 , 0};
|
||||
uint16_t _aui16NowSeq[2] = { 0 , 0 };
|
||||
uint64_t _aui64RtpRecv[2] = { 0 , 0};
|
||||
|
||||
//超时功能实现
|
||||
Ticker m_rtpTicker;
|
||||
std::shared_ptr<Timer> m_pPlayTimer;
|
||||
std::shared_ptr<Timer> m_pRtpTimer;
|
||||
Ticker _rtpTicker;
|
||||
std::shared_ptr<Timer> _pPlayTimer;
|
||||
std::shared_ptr<Timer> _pRtpTimer;
|
||||
//心跳定时器
|
||||
std::shared_ptr<Timer> m_pBeatTimer;
|
||||
std::shared_ptr<Timer> _pBeatTimer;
|
||||
|
||||
//播放进度控制
|
||||
float m_fSeekTo = 0;
|
||||
double m_adFistStamp[2] = {0,0};
|
||||
double m_adNowStamp[2] = {0,0};
|
||||
Ticker m_aNowStampTicker[2];
|
||||
float _fSeekTo = 0;
|
||||
double _adFistStamp[2] = {0,0};
|
||||
double _adNowStamp[2] = {0,0};
|
||||
Ticker _aNowStampTicker[2];
|
||||
};
|
||||
|
||||
} /* namespace Rtsp */
|
||||
|
@ -65,33 +65,33 @@ public:
|
||||
private:
|
||||
//派生类回调函数
|
||||
bool onCheckSDP(const string &sdp, const RtspTrack *track, int trackCnt) override {
|
||||
m_pRtspMediaSrc = dynamic_pointer_cast<RtspMediaSource>(m_pMediaSrc);
|
||||
if(m_pRtspMediaSrc){
|
||||
m_pRtspMediaSrc->onGetSDP(sdp);
|
||||
_pRtspMediaSrc = dynamic_pointer_cast<RtspMediaSource>(_pMediaSrc);
|
||||
if(_pRtspMediaSrc){
|
||||
_pRtspMediaSrc->onGetSDP(sdp);
|
||||
}
|
||||
try {
|
||||
m_parser.reset(new RtpParser(sdp));
|
||||
_parser.reset(new RtpParser(sdp));
|
||||
//todo(xzl) 修复此处
|
||||
// m_parser->setOnVideoCB(m_onGetVideoCB);
|
||||
// m_parser->setOnAudioCB(m_onGetAudioCB);
|
||||
// _parser->setOnVideoCB(_onGetVideoCB);
|
||||
// _parser->setOnAudioCB(_onGetAudioCB);
|
||||
return true;
|
||||
} catch (std::exception &ex) {
|
||||
WarnL << ex.what();
|
||||
return m_pRtspMediaSrc ? true : false;
|
||||
return _pRtspMediaSrc ? true : false;
|
||||
}
|
||||
}
|
||||
void onRecvRTP(const RtpPacket::Ptr &rtppt, const RtspTrack &track) override {
|
||||
if(m_parser){
|
||||
m_parser->inputRtp(rtppt);
|
||||
if(_parser){
|
||||
_parser->inputRtp(rtppt);
|
||||
}
|
||||
|
||||
if(m_pRtspMediaSrc){
|
||||
m_pRtspMediaSrc->onGetRTP(rtppt,true);
|
||||
if(_pRtspMediaSrc){
|
||||
_pRtspMediaSrc->onGetRTP(rtppt,true);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
RtspMediaSource::Ptr m_pRtspMediaSrc;
|
||||
RtspMediaSource::Ptr _pRtspMediaSrc;
|
||||
|
||||
};
|
||||
|
||||
|
@ -57,7 +57,7 @@ unordered_map<void *, std::shared_ptr<RtspSession> > RtspSession::g_mapPostter;
|
||||
recursive_mutex RtspSession::g_mtxGetter; //对quicktime上锁保护
|
||||
recursive_mutex RtspSession::g_mtxPostter; //对quicktime上锁保护
|
||||
RtspSession::RtspSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock) :
|
||||
TcpSession(pTh, pSock), m_pSender(pSock) {
|
||||
TcpSession(pTh, pSock), _pSender(pSock) {
|
||||
//设置10秒发送缓存
|
||||
pSock->setSendBufSecond(10);
|
||||
//设置15秒发送超时时间
|
||||
@ -67,8 +67,8 @@ RtspSession::RtspSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::P
|
||||
}
|
||||
|
||||
RtspSession::~RtspSession() {
|
||||
if (m_onDestory) {
|
||||
m_onDestory();
|
||||
if (_onDestory) {
|
||||
_onDestory();
|
||||
}
|
||||
DebugL << get_peer_ip();
|
||||
}
|
||||
@ -80,34 +80,34 @@ void RtspSession::shutdown_l(bool close){
|
||||
if (_sock) {
|
||||
_sock->emitErr(SockException(Err_other, "self shutdown"),close);
|
||||
}
|
||||
if (m_bBase64need && !_sock) {
|
||||
if (_bBase64need && !_sock) {
|
||||
//quickTime http postter,and self is detached from tcpServer
|
||||
lock_guard<recursive_mutex> lock(g_mtxPostter);
|
||||
g_mapPostter.erase(this);
|
||||
}
|
||||
if (m_pBrdcaster) {
|
||||
m_pBrdcaster->setDetachCB(this, nullptr);
|
||||
m_pBrdcaster.reset();
|
||||
if (_pBrdcaster) {
|
||||
_pBrdcaster->setDetachCB(this, nullptr);
|
||||
_pBrdcaster.reset();
|
||||
}
|
||||
if (m_pRtpReader) {
|
||||
m_pRtpReader.reset();
|
||||
if (_pRtpReader) {
|
||||
_pRtpReader.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void RtspSession::onError(const SockException& err) {
|
||||
TraceL << err.getErrCode() << " " << err.what();
|
||||
if (m_bListenPeerUdpData) {
|
||||
if (_bListenPeerUdpData) {
|
||||
//取消UDP端口监听
|
||||
UDPServer::Instance().stopListenPeer(get_peer_ip().data(), this);
|
||||
m_bListenPeerUdpData = false;
|
||||
_bListenPeerUdpData = false;
|
||||
}
|
||||
if (!m_bBase64need && m_strSessionCookie.size() != 0) {
|
||||
if (!_bBase64need && _strSessionCookie.size() != 0) {
|
||||
//quickTime http getter
|
||||
lock_guard<recursive_mutex> lock(g_mtxGetter);
|
||||
g_mapGetter.erase(m_strSessionCookie);
|
||||
g_mapGetter.erase(_strSessionCookie);
|
||||
}
|
||||
|
||||
if (m_bBase64need && err.getErrCode() == Err_eof) {
|
||||
if (_bBase64need && err.getErrCode() == Err_eof) {
|
||||
//quickTime http postter,正在发送rtp; QuickTime只是断开了请求连接,请继续发送rtp
|
||||
_sock = nullptr;
|
||||
lock_guard<recursive_mutex> lock(g_mtxPostter);
|
||||
@ -121,24 +121,24 @@ void RtspSession::onError(const SockException& err) {
|
||||
|
||||
//流量统计事件广播
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,iFlowThreshold,Broadcast::kFlowThreshold);
|
||||
if(m_ui64TotalBytes > iFlowThreshold * 1024){
|
||||
if(_ui64TotalBytes > iFlowThreshold * 1024){
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,
|
||||
m_mediaInfo,
|
||||
m_ui64TotalBytes,
|
||||
m_ticker.createdTime()/1000,
|
||||
_mediaInfo,
|
||||
_ui64TotalBytes,
|
||||
_ticker.createdTime()/1000,
|
||||
*this);
|
||||
}
|
||||
}
|
||||
|
||||
void RtspSession::onManager() {
|
||||
if (m_ticker.createdTime() > 15 * 1000) {
|
||||
if (m_strSession.size() == 0) {
|
||||
if (_ticker.createdTime() > 15 * 1000) {
|
||||
if (_strSession.size() == 0) {
|
||||
WarnL << "非法链接:" << get_peer_ip();
|
||||
shutdown();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_rtpType != PlayerBase::RTP_TCP && m_ticker.elapsedTime() > 15 * 1000) {
|
||||
if (_rtpType != PlayerBase::RTP_TCP && _ticker.elapsedTime() > 15 * 1000) {
|
||||
WarnL << "RTSP会话超时:" << get_peer_ip();
|
||||
shutdown();
|
||||
return;
|
||||
@ -148,11 +148,11 @@ void RtspSession::onManager() {
|
||||
|
||||
int64_t RtspSession::onRecvHeader(const char *header,uint64_t len) {
|
||||
char tmp[2 * 1024];
|
||||
m_pcBuf = tmp;
|
||||
_pcBuf = tmp;
|
||||
|
||||
m_parser.Parse(header); //rtsp请求解析
|
||||
string strCmd = m_parser.Method(); //提取出请求命令字
|
||||
m_iCseq = atoi(m_parser["CSeq"].data());
|
||||
_parser.Parse(header); //rtsp请求解析
|
||||
string strCmd = _parser.Method(); //提取出请求命令字
|
||||
_iCseq = atoi(_parser["CSeq"].data());
|
||||
|
||||
typedef bool (RtspSession::*rtspCMDHandle)();
|
||||
static unordered_map<string, rtspCMDHandle> g_mapCmd;
|
||||
@ -180,15 +180,15 @@ int64_t RtspSession::onRecvHeader(const char *header,uint64_t len) {
|
||||
WarnL << "cmd=" << strCmd;
|
||||
}
|
||||
|
||||
m_parser.Clear();
|
||||
_parser.Clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void RtspSession::onRecv(const Buffer::Ptr &pBuf) {
|
||||
m_ticker.resetTime();
|
||||
m_ui64TotalBytes += pBuf->size();
|
||||
if (m_bBase64need) {
|
||||
_ticker.resetTime();
|
||||
_ui64TotalBytes += pBuf->size();
|
||||
if (_bBase64need) {
|
||||
//quicktime 加密后的rtsp请求,需要解密
|
||||
auto str = decodeBase64(string(pBuf->data(),pBuf->size()));
|
||||
inputRtspOrRtcp(str.data(),str.size());
|
||||
@ -198,7 +198,7 @@ void RtspSession::onRecv(const Buffer::Ptr &pBuf) {
|
||||
}
|
||||
|
||||
void RtspSession::inputRtspOrRtcp(const char *data,uint64_t len) {
|
||||
if(data[0] == '$' && m_rtpType == PlayerBase::RTP_TCP){
|
||||
if(data[0] == '$' && _rtpType == PlayerBase::RTP_TCP){
|
||||
//这是rtcp
|
||||
return;
|
||||
}
|
||||
@ -207,24 +207,24 @@ void RtspSession::inputRtspOrRtcp(const char *data,uint64_t len) {
|
||||
|
||||
bool RtspSession::handleReq_Options() {
|
||||
//支持这些命令
|
||||
int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY,"
|
||||
" PAUSE, SET_PARAMETER, GET_PARAMETER\r\n\r\n",
|
||||
m_iCseq, SERVER_NAME,
|
||||
_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data());
|
||||
SocketHelper::send(m_pcBuf, n);
|
||||
SocketHelper::send(_pcBuf, n);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RtspSession::handleReq_Describe() {
|
||||
{
|
||||
//解析url获取媒体名称
|
||||
m_strUrl = m_parser.Url();
|
||||
m_mediaInfo.parse(m_parser.FullUrl());
|
||||
_strUrl = _parser.Url();
|
||||
_mediaInfo.parse(_parser.FullUrl());
|
||||
}
|
||||
|
||||
if (!findStream()) {
|
||||
@ -235,7 +235,7 @@ bool RtspSession::handleReq_Describe() {
|
||||
|
||||
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||
//该请求中的认证信息
|
||||
auto authorization = m_parser["Authorization"];
|
||||
auto authorization = _parser["Authorization"];
|
||||
onGetRealm invoker = [weakSelf,authorization](const string &realm){
|
||||
if(realm.empty()){
|
||||
//无需认证,回复sdp
|
||||
@ -248,7 +248,7 @@ bool RtspSession::handleReq_Describe() {
|
||||
|
||||
//广播是否需要认证事件
|
||||
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm,
|
||||
m_mediaInfo,
|
||||
_mediaInfo,
|
||||
invoker,
|
||||
*this)){
|
||||
//无人监听此事件,说明无需认证
|
||||
@ -279,10 +279,10 @@ void RtspSession::onAuthSuccess(const weak_ptr<RtspSession> &weakSelf) {
|
||||
"Content-Base: %s/\r\n"
|
||||
"Content-Type: application/sdp\r\n"
|
||||
"Content-Length: %d\r\n\r\n%s",
|
||||
strongSelf->m_iCseq, SERVER_NAME,
|
||||
strongSelf->_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), strongSelf->m_strUrl.data(),
|
||||
(int) strongSelf->m_strSdp.length(), strongSelf->m_strSdp.data());
|
||||
dateHeader().data(), strongSelf->_strUrl.data(),
|
||||
(int) strongSelf->_strSdp.length(), strongSelf->_strSdp.data());
|
||||
strongSelf->SocketHelper::send(response, n);
|
||||
});
|
||||
}
|
||||
@ -304,16 +304,16 @@ void RtspSession::onAuthFailed(const weak_ptr<RtspSession> &weakSelf,const strin
|
||||
GET_CONFIG_AND_REGISTER(bool,authBasic,Config::Rtsp::kAuthBasic);
|
||||
if (!authBasic) {
|
||||
//我们需要客户端优先以md5方式认证
|
||||
strongSelf->m_strNonce = makeRandStr(32);
|
||||
strongSelf->_strNonce = makeRandStr(32);
|
||||
n = sprintf(response,
|
||||
"RTSP/1.0 401 Unauthorized\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"WWW-Authenticate: Digest realm=\"%s\",nonce=\"%s\"\r\n\r\n",
|
||||
strongSelf->m_iCseq, SERVER_NAME,
|
||||
strongSelf->_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), realm.data(), strongSelf->m_strNonce.data());
|
||||
dateHeader().data(), realm.data(), strongSelf->_strNonce.data());
|
||||
}else {
|
||||
//当然我们也支持base64认证,但是我们不建议这样做
|
||||
n = sprintf(response,
|
||||
@ -322,7 +322,7 @@ void RtspSession::onAuthFailed(const weak_ptr<RtspSession> &weakSelf,const strin
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"WWW-Authenticate: Basic realm=\"%s\"\r\n\r\n",
|
||||
strongSelf->m_iCseq, SERVER_NAME,
|
||||
strongSelf->_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), realm.data());
|
||||
}
|
||||
@ -359,7 +359,7 @@ void RtspSession::onAuthBasic(const weak_ptr<RtspSession> &weakSelf,const string
|
||||
}
|
||||
|
||||
//此时必须提供明文密码
|
||||
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,strongSelf->m_mediaInfo,user, true,invoker,*strongSelf)){
|
||||
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,strongSelf->_mediaInfo,user, true,invoker,*strongSelf)){
|
||||
//表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之
|
||||
WarnL << "请监听kBroadcastOnRtspAuth事件!";
|
||||
//但是我们还是忽略认证以便完成播放
|
||||
@ -388,8 +388,8 @@ void RtspSession::onAuthDigest(const weak_ptr<RtspSession> &weakSelf,const strin
|
||||
}
|
||||
//check nonce
|
||||
auto nonce = map["nonce"];
|
||||
if(strongSelf->m_strNonce != nonce){
|
||||
TraceL << "nonce not mached:" << nonce << "," << strongSelf->m_strNonce;
|
||||
if(strongSelf->_strNonce != nonce){
|
||||
TraceL << "nonce not mached:" << nonce << "," << strongSelf->_strNonce;
|
||||
onAuthFailed(weakSelf,realm);
|
||||
return ;
|
||||
}
|
||||
@ -440,7 +440,7 @@ void RtspSession::onAuthDigest(const weak_ptr<RtspSession> &weakSelf,const strin
|
||||
};
|
||||
|
||||
//此时可以提供明文或md5加密的密码
|
||||
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,strongSelf->m_mediaInfo,username, false,invoker,*strongSelf)){
|
||||
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,strongSelf->_mediaInfo,username, false,invoker,*strongSelf)){
|
||||
//表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之
|
||||
WarnL << "请监听kBroadcastOnRtspAuth事件!";
|
||||
//但是我们还是忽略认证以便完成播放
|
||||
@ -469,80 +469,80 @@ void RtspSession::onAuthUser(const weak_ptr<RtspSession> &weakSelf,const string
|
||||
}
|
||||
}
|
||||
inline void RtspSession::send_StreamNotFound() {
|
||||
int n = sprintf(m_pcBuf, "RTSP/1.0 404 Stream Not Found\r\n"
|
||||
int n = sprintf(_pcBuf, "RTSP/1.0 404 Stream Not Found\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Connection: Close\r\n\r\n",
|
||||
m_iCseq, SERVER_NAME,
|
||||
_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data());
|
||||
SocketHelper::send(m_pcBuf, n);
|
||||
SocketHelper::send(_pcBuf, n);
|
||||
}
|
||||
inline void RtspSession::send_UnsupportedTransport() {
|
||||
int n = sprintf(m_pcBuf, "RTSP/1.0 461 Unsupported Transport\r\n"
|
||||
int n = sprintf(_pcBuf, "RTSP/1.0 461 Unsupported Transport\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Connection: Close\r\n\r\n",
|
||||
m_iCseq, SERVER_NAME,
|
||||
_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data());
|
||||
SocketHelper::send(m_pcBuf, n);
|
||||
SocketHelper::send(_pcBuf, n);
|
||||
}
|
||||
|
||||
inline void RtspSession::send_SessionNotFound() {
|
||||
int n = sprintf(m_pcBuf, "RTSP/1.0 454 Session Not Found\r\n"
|
||||
int n = sprintf(_pcBuf, "RTSP/1.0 454 Session Not Found\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Connection: Close\r\n\r\n",
|
||||
m_iCseq, SERVER_NAME,
|
||||
_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data());
|
||||
SocketHelper::send(m_pcBuf, n);
|
||||
SocketHelper::send(_pcBuf, n);
|
||||
|
||||
/*40 Method Not Allowed*/
|
||||
|
||||
}
|
||||
bool RtspSession::handleReq_Setup() {
|
||||
//处理setup命令,该函数可能进入多次
|
||||
auto controlSuffix = m_parser.FullUrl().substr(1 + m_parser.FullUrl().rfind('/'));
|
||||
auto controlSuffix = _parser.FullUrl().substr(1 + _parser.FullUrl().rfind('/'));
|
||||
int trackIdx = getTrackIndexByControlSuffix(controlSuffix);
|
||||
if (trackIdx == -1) {
|
||||
//未找到相应track
|
||||
return false;
|
||||
}
|
||||
RtspTrack &trackRef = m_aTrackInfo[trackIdx];
|
||||
RtspTrack &trackRef = _aTrackInfo[trackIdx];
|
||||
if (trackRef.inited) {
|
||||
//已经初始化过该Track
|
||||
return false;
|
||||
}
|
||||
trackRef.inited = true; //现在初始化
|
||||
|
||||
auto strongRing = m_pWeakRing.lock();
|
||||
auto strongRing = _pWeakRing.lock();
|
||||
if (!strongRing) {
|
||||
//the media source is released!
|
||||
send_NotAcceptable();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_bSetUped){
|
||||
m_bSetUped = true;
|
||||
auto strTransport = m_parser["Transport"];
|
||||
if(!_bSetUped){
|
||||
_bSetUped = true;
|
||||
auto strTransport = _parser["Transport"];
|
||||
if(strTransport.find("TCP") != string::npos){
|
||||
m_rtpType = PlayerBase::RTP_TCP;
|
||||
_rtpType = PlayerBase::RTP_TCP;
|
||||
}else if(strTransport.find("multicast") != string::npos){
|
||||
m_rtpType = PlayerBase::RTP_MULTICAST;
|
||||
_rtpType = PlayerBase::RTP_MULTICAST;
|
||||
}else{
|
||||
m_rtpType = PlayerBase::RTP_UDP;
|
||||
_rtpType = PlayerBase::RTP_UDP;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_pRtpReader && m_rtpType != PlayerBase::RTP_MULTICAST) {
|
||||
m_pRtpReader = strongRing->attach();
|
||||
if (!_pRtpReader && _rtpType != PlayerBase::RTP_MULTICAST) {
|
||||
_pRtpReader = strongRing->attach();
|
||||
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||
m_pRtpReader->setDetachCB([weakSelf]() {
|
||||
_pRtpReader->setDetachCB([weakSelf]() {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
@ -551,9 +551,9 @@ bool RtspSession::handleReq_Setup() {
|
||||
});
|
||||
}
|
||||
|
||||
switch (m_rtpType) {
|
||||
switch (_rtpType) {
|
||||
case PlayerBase::RTP_TCP: {
|
||||
int iLen = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
int iLen = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
@ -562,13 +562,13 @@ bool RtspSession::handleReq_Setup() {
|
||||
"Session: %s\r\n"
|
||||
"x-Transport-Options: late-tolerance=1.400000\r\n"
|
||||
"x-Dynamic-Rate: 1\r\n\r\n",
|
||||
m_iCseq, SERVER_NAME,
|
||||
_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), trackRef.type * 2,
|
||||
trackRef.type * 2 + 1,
|
||||
printSSRC(trackRef.ssrc).data(),
|
||||
m_strSession.data());
|
||||
SocketHelper::send(m_pcBuf, iLen);
|
||||
_strSession.data());
|
||||
SocketHelper::send(_pcBuf, iLen);
|
||||
}
|
||||
break;
|
||||
case PlayerBase::RTP_UDP: {
|
||||
@ -587,44 +587,44 @@ bool RtspSession::handleReq_Setup() {
|
||||
send_NotAcceptable();
|
||||
return false;
|
||||
}
|
||||
m_apUdpSock[trackIdx] = pSockRtp;
|
||||
_apUdpSock[trackIdx] = pSockRtp;
|
||||
//设置客户端内网端口信息
|
||||
string strClientPort = FindField(m_parser["Transport"].data(), "client_port=", NULL);
|
||||
string strClientPort = FindField(_parser["Transport"].data(), "client_port=", NULL);
|
||||
uint16_t ui16PeerPort = atoi( FindField(strClientPort.data(), NULL, "-").data());
|
||||
struct sockaddr_in peerAddr;
|
||||
peerAddr.sin_family = AF_INET;
|
||||
peerAddr.sin_port = htons(ui16PeerPort);
|
||||
peerAddr.sin_addr.s_addr = inet_addr(get_peer_ip().data());
|
||||
bzero(&(peerAddr.sin_zero), sizeof peerAddr.sin_zero);
|
||||
m_apPeerUdpAddr[trackIdx].reset((struct sockaddr *) (new struct sockaddr_in(peerAddr)));
|
||||
_apPeerUdpAddr[trackIdx].reset((struct sockaddr *) (new struct sockaddr_in(peerAddr)));
|
||||
//尝试获取客户端nat映射地址
|
||||
startListenPeerUdpData();
|
||||
//InfoL << "分配端口:" << srv_port;
|
||||
int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Transport: RTP/AVP/UDP;unicast;"
|
||||
"client_port=%s;server_port=%d-%d;ssrc=%s;mode=play\r\n"
|
||||
"Session: %s\r\n\r\n",
|
||||
m_iCseq, SERVER_NAME,
|
||||
_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), strClientPort.data(),
|
||||
pSockRtp->get_local_port(), pSockRtcp->get_local_port(),
|
||||
printSSRC(trackRef.ssrc).data(),
|
||||
m_strSession.data());
|
||||
SocketHelper::send(m_pcBuf, n);
|
||||
_strSession.data());
|
||||
SocketHelper::send(_pcBuf, n);
|
||||
}
|
||||
break;
|
||||
case PlayerBase::RTP_MULTICAST: {
|
||||
if(!m_pBrdcaster){
|
||||
m_pBrdcaster = RtpBroadCaster::get(get_local_ip(),m_mediaInfo.m_vhost, m_mediaInfo.m_app, m_mediaInfo.m_streamid);
|
||||
if (!m_pBrdcaster) {
|
||||
if(!_pBrdcaster){
|
||||
_pBrdcaster = RtpBroadCaster::get(get_local_ip(),_mediaInfo._vhost, _mediaInfo._app, _mediaInfo._streamid);
|
||||
if (!_pBrdcaster) {
|
||||
send_NotAcceptable();
|
||||
return false;
|
||||
}
|
||||
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||
m_pBrdcaster->setDetachCB(this, [weakSelf]() {
|
||||
_pBrdcaster->setDetachCB(this, [weakSelf]() {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
@ -632,7 +632,7 @@ bool RtspSession::handleReq_Setup() {
|
||||
strongSelf->safeShutdown();
|
||||
});
|
||||
}
|
||||
int iSrvPort = m_pBrdcaster->getPort(trackRef.type);
|
||||
int iSrvPort = _pBrdcaster->getPort(trackRef.type);
|
||||
//我们用trackIdx区分rtp和rtcp包
|
||||
auto pSockRtcp = UDPServer::Instance().getSock(get_local_ip().data(),2*trackIdx + 1,iSrvPort + 1);
|
||||
if (!pSockRtcp) {
|
||||
@ -643,20 +643,20 @@ bool RtspSession::handleReq_Setup() {
|
||||
}
|
||||
startListenPeerUdpData();
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,udpTTL,MultiCast::kUdpTTL);
|
||||
int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Transport: RTP/AVP;multicast;destination=%s;"
|
||||
"source=%s;port=%d-%d;ttl=%d;ssrc=%s\r\n"
|
||||
"Session: %s\r\n\r\n",
|
||||
m_iCseq, SERVER_NAME,
|
||||
_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), m_pBrdcaster->getIP().data(),
|
||||
dateHeader().data(), _pBrdcaster->getIP().data(),
|
||||
get_local_ip().data(), iSrvPort, pSockRtcp->get_local_port(),
|
||||
udpTTL,printSSRC(trackRef.ssrc).data(),
|
||||
m_strSession.data());
|
||||
SocketHelper::send(m_pcBuf, n);
|
||||
_strSession.data());
|
||||
SocketHelper::send(_pcBuf, n);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -666,39 +666,39 @@ bool RtspSession::handleReq_Setup() {
|
||||
}
|
||||
|
||||
bool RtspSession::handleReq_Play() {
|
||||
if (m_uiTrackCnt == 0) {
|
||||
if (_uiTrackCnt == 0) {
|
||||
//还没有Describe
|
||||
return false;
|
||||
}
|
||||
if (m_parser["Session"] != m_strSession) {
|
||||
if (_parser["Session"] != _strSession) {
|
||||
send_SessionNotFound();
|
||||
return false;
|
||||
}
|
||||
auto strRange = m_parser["Range"];
|
||||
auto strRange = _parser["Range"];
|
||||
auto onRes = [this,strRange](const string &err){
|
||||
bool authSuccess = err.empty();
|
||||
char response[2 * 1024];
|
||||
m_pcBuf = response;
|
||||
if(!authSuccess && m_bFirstPlay){
|
||||
_pcBuf = response;
|
||||
if(!authSuccess && _bFirstPlay){
|
||||
//第一次play是播放,否则是恢复播放。只对播放鉴权
|
||||
int n = sprintf(m_pcBuf,
|
||||
int n = sprintf(_pcBuf,
|
||||
"RTSP/1.0 401 Unauthorized\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"Content-Length: %d\r\n\r\n%s",
|
||||
m_iCseq, SERVER_NAME,
|
||||
_iCseq, SERVER_NAME,
|
||||
RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(),(int)err.size(),err.data());
|
||||
SocketHelper::send(m_pcBuf,n);
|
||||
SocketHelper::send(_pcBuf,n);
|
||||
shutdown();
|
||||
return;
|
||||
}
|
||||
if(m_pRtpReader){
|
||||
if(_pRtpReader){
|
||||
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||
SockUtil::setNoDelay(m_pSender->rawFD(), false);
|
||||
m_pRtpReader->setReadCB([weakSelf](const RtpPacket::Ptr &pack) {
|
||||
SockUtil::setNoDelay(_pSender->rawFD(), false);
|
||||
_pRtpReader->setReadCB([weakSelf](const RtpPacket::Ptr &pack) {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
@ -714,10 +714,10 @@ bool RtspSession::handleReq_Play() {
|
||||
});
|
||||
}
|
||||
|
||||
auto pMediaSrc = m_pMediaSrc.lock();
|
||||
auto pMediaSrc = _pMediaSrc.lock();
|
||||
uint32_t iStamp = 0;
|
||||
if(pMediaSrc){
|
||||
if (strRange.size() && !m_bFirstPlay) {
|
||||
if (strRange.size() && !_bFirstPlay) {
|
||||
auto strStart = FindField(strRange.data(), "npt=", "-");
|
||||
if (strStart == "now") {
|
||||
strStart = "0";
|
||||
@ -733,41 +733,41 @@ bool RtspSession::handleReq_Play() {
|
||||
}else{
|
||||
iStamp = pMediaSrc->getStamp();
|
||||
}
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
|
||||
auto &track = m_aTrackInfo[i];
|
||||
for (unsigned int i = 0; i < _uiTrackCnt; i++) {
|
||||
auto &track = _aTrackInfo[i];
|
||||
track.ssrc = pMediaSrc->getSsrc(track.type);
|
||||
track.seq = pMediaSrc->getSeqence(track.type);
|
||||
track.timeStamp = pMediaSrc->getTimestamp(track.type);
|
||||
}
|
||||
}
|
||||
m_bFirstPlay = false;
|
||||
int iLen = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
_bFirstPlay = false;
|
||||
int iLen = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Session: %s\r\n"
|
||||
"Range: npt=%.2f-\r\n"
|
||||
"RTP-Info: ", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), m_strSession.data(),iStamp/1000.0);
|
||||
"RTP-Info: ", _iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), _strSession.data(),iStamp/1000.0);
|
||||
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
|
||||
auto &track = m_aTrackInfo[i];
|
||||
for (unsigned int i = 0; i < _uiTrackCnt; i++) {
|
||||
auto &track = _aTrackInfo[i];
|
||||
if (track.inited == false) {
|
||||
//还有track没有setup
|
||||
shutdown();
|
||||
return;
|
||||
}
|
||||
iLen += sprintf(m_pcBuf + iLen, "url=%s/%s;seq=%d;rtptime=%u,",
|
||||
m_strUrl.data(), track.controlSuffix.data(), track.seq,track.timeStamp);
|
||||
iLen += sprintf(_pcBuf + iLen, "url=%s/%s;seq=%d;rtptime=%u,",
|
||||
_strUrl.data(), track.controlSuffix.data(), track.seq,track.timeStamp);
|
||||
}
|
||||
iLen -= 1;
|
||||
(m_pcBuf)[iLen] = '\0';
|
||||
iLen += sprintf(m_pcBuf + iLen, "\r\n\r\n");
|
||||
SocketHelper::send(m_pcBuf, iLen);
|
||||
(_pcBuf)[iLen] = '\0';
|
||||
iLen += sprintf(_pcBuf + iLen, "\r\n\r\n");
|
||||
SocketHelper::send(_pcBuf, iLen);
|
||||
|
||||
//提高发送性能
|
||||
(*this) << SocketFlags(kSockFlags);
|
||||
SockUtil::setNoDelay(m_pSender->rawFD(),false);
|
||||
SockUtil::setNoDelay(_pSender->rawFD(),false);
|
||||
};
|
||||
|
||||
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||
@ -784,7 +784,7 @@ bool RtspSession::handleReq_Play() {
|
||||
onRes(err);
|
||||
});
|
||||
};
|
||||
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,m_mediaInfo,invoker,*this);
|
||||
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,_mediaInfo,invoker,*this);
|
||||
if(!flag){
|
||||
//该事件无人监听,默认不鉴权
|
||||
onRes("");
|
||||
@ -793,40 +793,40 @@ bool RtspSession::handleReq_Play() {
|
||||
}
|
||||
|
||||
bool RtspSession::handleReq_Pause() {
|
||||
if (m_parser["Session"] != m_strSession) {
|
||||
if (_parser["Session"] != _strSession) {
|
||||
send_SessionNotFound();
|
||||
return false;
|
||||
}
|
||||
int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Session: %s\r\n\r\n", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), m_strSession.data());
|
||||
SocketHelper::send(m_pcBuf, n);
|
||||
if(m_pRtpReader){
|
||||
m_pRtpReader->setReadCB(nullptr);
|
||||
"Session: %s\r\n\r\n", _iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), _strSession.data());
|
||||
SocketHelper::send(_pcBuf, n);
|
||||
if(_pRtpReader){
|
||||
_pRtpReader->setReadCB(nullptr);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool RtspSession::handleReq_Teardown() {
|
||||
int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Session: %s\r\n\r\n", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), m_strSession.data());
|
||||
"Session: %s\r\n\r\n", _iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), _strSession.data());
|
||||
|
||||
SocketHelper::send(m_pcBuf, n);
|
||||
SocketHelper::send(_pcBuf, n);
|
||||
TraceL << "播放器断开连接!";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RtspSession::handleReq_Get() {
|
||||
m_strSessionCookie = m_parser["x-sessioncookie"];
|
||||
int n = sprintf(m_pcBuf, "HTTP/1.0 200 OK\r\n"
|
||||
_strSessionCookie = _parser["x-sessioncookie"];
|
||||
int n = sprintf(_pcBuf, "HTTP/1.0 200 OK\r\n"
|
||||
"%s"
|
||||
"Connection: close\r\n"
|
||||
"Cache-Control: no-store\r\n"
|
||||
@ -835,23 +835,23 @@ bool RtspSession::handleReq_Get() {
|
||||
dateHeader().data());
|
||||
//注册GET
|
||||
lock_guard<recursive_mutex> lock(g_mtxGetter);
|
||||
g_mapGetter[m_strSessionCookie] = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||
//InfoL << m_strSessionCookie;
|
||||
SocketHelper::send(m_pcBuf, n);
|
||||
g_mapGetter[_strSessionCookie] = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||
//InfoL << _strSessionCookie;
|
||||
SocketHelper::send(_pcBuf, n);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool RtspSession::handleReq_Post() {
|
||||
lock_guard<recursive_mutex> lock(g_mtxGetter);
|
||||
string sessioncookie = m_parser["x-sessioncookie"];
|
||||
string sessioncookie = _parser["x-sessioncookie"];
|
||||
//Poster 找到 Getter
|
||||
auto it = g_mapGetter.find(sessioncookie);
|
||||
if (it == g_mapGetter.end()) {
|
||||
//WarnL << sessioncookie;
|
||||
return false;
|
||||
}
|
||||
m_bBase64need = true;
|
||||
_bBase64need = true;
|
||||
//Poster 找到Getter的SOCK
|
||||
auto strongSession = it->second.lock();
|
||||
g_mapGetter.erase(sessioncookie);
|
||||
@ -866,46 +866,46 @@ bool RtspSession::handleReq_Post() {
|
||||
|
||||
bool RtspSession::handleReq_SET_PARAMETER() {
|
||||
//TraceL<<endl;
|
||||
int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
int n = sprintf(_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Session: %s\r\n\r\n", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), m_strSession.data());
|
||||
SocketHelper::send(m_pcBuf, n);
|
||||
"Session: %s\r\n\r\n", _iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data(), _strSession.data());
|
||||
SocketHelper::send(_pcBuf, n);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void RtspSession::send_NotAcceptable() {
|
||||
int n = sprintf(m_pcBuf, "RTSP/1.0 406 Not Acceptable\r\n"
|
||||
int n = sprintf(_pcBuf, "RTSP/1.0 406 Not Acceptable\r\n"
|
||||
"CSeq: %d\r\n"
|
||||
"Server: %s-%0.2f(build in %s)\r\n"
|
||||
"%s"
|
||||
"Connection: Close\r\n\r\n", m_iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
"Connection: Close\r\n\r\n", _iCseq, SERVER_NAME, RTSP_VERSION, RTSP_BUILDTIME,
|
||||
dateHeader().data());
|
||||
SocketHelper::send(m_pcBuf, n);
|
||||
SocketHelper::send(_pcBuf, n);
|
||||
|
||||
}
|
||||
|
||||
inline bool RtspSession::findStream() {
|
||||
RtspMediaSource::Ptr pMediaSrc =
|
||||
dynamic_pointer_cast<RtspMediaSource>( MediaSource::find(RTSP_SCHEMA,m_mediaInfo.m_vhost, m_mediaInfo.m_app,m_mediaInfo.m_streamid) );
|
||||
dynamic_pointer_cast<RtspMediaSource>( MediaSource::find(RTSP_SCHEMA,_mediaInfo._vhost, _mediaInfo._app,_mediaInfo._streamid) );
|
||||
if (!pMediaSrc) {
|
||||
WarnL << "No such stream:" << m_mediaInfo.m_vhost << " " << m_mediaInfo.m_app << " " << m_mediaInfo.m_streamid;
|
||||
WarnL << "No such stream:" << _mediaInfo._vhost << " " << _mediaInfo._app << " " << _mediaInfo._streamid;
|
||||
return false;
|
||||
}
|
||||
m_strSdp = pMediaSrc->getSdp();
|
||||
m_pWeakRing = pMediaSrc->getRing();
|
||||
_strSdp = pMediaSrc->getSdp();
|
||||
_pWeakRing = pMediaSrc->getRing();
|
||||
|
||||
m_uiTrackCnt = parserSDP(m_strSdp, m_aTrackInfo);
|
||||
if (m_uiTrackCnt == 0 || m_uiTrackCnt > 2) {
|
||||
_uiTrackCnt = parserSDP(_strSdp, _aTrackInfo);
|
||||
if (_uiTrackCnt == 0 || _uiTrackCnt > 2) {
|
||||
return false;
|
||||
}
|
||||
m_strSession = makeRandStr(12);
|
||||
m_pMediaSrc = pMediaSrc;
|
||||
_strSession = makeRandStr(12);
|
||||
_pMediaSrc = pMediaSrc;
|
||||
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
|
||||
auto &track = m_aTrackInfo[i];
|
||||
for (unsigned int i = 0; i < _uiTrackCnt; i++) {
|
||||
auto &track = _aTrackInfo[i];
|
||||
track.ssrc = pMediaSrc->getSsrc(track.type);
|
||||
track.seq = pMediaSrc->getSeqence(track.type);
|
||||
track.timeStamp = pMediaSrc->getTimestamp(track.type);
|
||||
@ -917,19 +917,19 @@ inline bool RtspSession::findStream() {
|
||||
|
||||
inline void RtspSession::sendRtpPacket(const RtpPacket::Ptr & pkt) {
|
||||
//InfoL<<(int)pkt.Interleaved;
|
||||
switch (m_rtpType) {
|
||||
switch (_rtpType) {
|
||||
case PlayerBase::RTP_TCP: {
|
||||
BufferRtp::Ptr buffer(new BufferRtp(pkt));
|
||||
send(buffer);
|
||||
#ifdef RTSP_SEND_RTCP
|
||||
int iTrackIndex = getTrackIndexByTrackId(pkt.interleaved / 2);
|
||||
RtcpCounter &counter = m_aRtcpCnt[iTrackIndex];
|
||||
RtcpCounter &counter = _aRtcpCnt[iTrackIndex];
|
||||
counter.pktCnt += 1;
|
||||
counter.octCount += (pkt.length - 12);
|
||||
auto &m_ticker = m_aRtcpTicker[iTrackIndex];
|
||||
if (m_ticker.elapsedTime() > 5 * 1000) {
|
||||
auto &_ticker = _aRtcpTicker[iTrackIndex];
|
||||
if (_ticker.elapsedTime() > 5 * 1000) {
|
||||
//send rtcp every 5 second
|
||||
m_ticker.resetTime();
|
||||
_ticker.resetTime();
|
||||
counter.timeStamp = pkt.timeStamp;
|
||||
sendRTCP();
|
||||
}
|
||||
@ -938,17 +938,17 @@ inline void RtspSession::sendRtpPacket(const RtpPacket::Ptr & pkt) {
|
||||
break;
|
||||
case PlayerBase::RTP_UDP: {
|
||||
int iTrackIndex = getTrackIndexByTrackType(pkt->type);
|
||||
auto pSock = m_apUdpSock[iTrackIndex].lock();
|
||||
auto pSock = _apUdpSock[iTrackIndex].lock();
|
||||
if (!pSock) {
|
||||
shutdown();
|
||||
return;
|
||||
}
|
||||
auto peerAddr = m_apPeerUdpAddr[iTrackIndex];
|
||||
auto peerAddr = _apPeerUdpAddr[iTrackIndex];
|
||||
if (!peerAddr) {
|
||||
return;
|
||||
}
|
||||
BufferRtp::Ptr buffer(new BufferRtp(pkt,4));
|
||||
m_ui64TotalBytes += buffer->size();
|
||||
_ui64TotalBytes += buffer->size();
|
||||
pSock->send(buffer,kSockFlags, peerAddr.get());
|
||||
}
|
||||
break;
|
||||
@ -960,35 +960,35 @@ inline void RtspSession::sendRtpPacket(const RtpPacket::Ptr & pkt) {
|
||||
inline void RtspSession::onRcvPeerUdpData(int iTrackIdx, const Buffer::Ptr &pBuf, const struct sockaddr& addr) {
|
||||
if(iTrackIdx % 2 == 0){
|
||||
//这是rtp探测包
|
||||
if(!m_bGotAllPeerUdp){
|
||||
if(!_bGotAllPeerUdp){
|
||||
//还没有获取完整的rtp探测包
|
||||
if(SockUtil::in_same_lan(get_local_ip().data(),get_peer_ip().data())){
|
||||
//在内网中,客户端上报的端口号是真实的,所以我们忽略udp打洞包
|
||||
m_bGotAllPeerUdp = true;
|
||||
_bGotAllPeerUdp = true;
|
||||
return;
|
||||
}
|
||||
//设置真实的客户端nat映射端口号
|
||||
m_apPeerUdpAddr[iTrackIdx / 2].reset(new struct sockaddr(addr));
|
||||
m_abGotPeerUdp[iTrackIdx / 2] = true;
|
||||
m_bGotAllPeerUdp = true;//先假设获取到完整的rtp探测包
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
|
||||
if (!m_abGotPeerUdp[i]) {
|
||||
_apPeerUdpAddr[iTrackIdx / 2].reset(new struct sockaddr(addr));
|
||||
_abGotPeerUdp[iTrackIdx / 2] = true;
|
||||
_bGotAllPeerUdp = true;//先假设获取到完整的rtp探测包
|
||||
for (unsigned int i = 0; i < _uiTrackCnt; i++) {
|
||||
if (!_abGotPeerUdp[i]) {
|
||||
//还有track没获取到rtp探测包
|
||||
m_bGotAllPeerUdp = false;
|
||||
_bGotAllPeerUdp = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
//这是rtcp心跳包,说明播放器还存活
|
||||
m_ticker.resetTime();
|
||||
_ticker.resetTime();
|
||||
//TraceL << "rtcp:" << (iTrackIdx-1)/2 ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void RtspSession::startListenPeerUdpData() {
|
||||
m_bListenPeerUdpData = true;
|
||||
_bListenPeerUdpData = true;
|
||||
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||
UDPServer::Instance().listenPeer(get_peer_ip().data(), this,
|
||||
[weakSelf](int iTrackIdx,const Buffer::Ptr &pBuf,struct sockaddr *pPeerAddr)->bool {
|
||||
@ -1009,15 +1009,15 @@ inline void RtspSession::startListenPeerUdpData() {
|
||||
}
|
||||
|
||||
inline void RtspSession::initSender(const std::shared_ptr<RtspSession>& session) {
|
||||
m_pSender = session->_sock;
|
||||
_pSender = session->_sock;
|
||||
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
|
||||
session->m_onDestory = [weakSelf]() {
|
||||
session->_onDestory = [weakSelf]() {
|
||||
auto strongSelf=weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
}
|
||||
//DebugL;
|
||||
strongSelf->m_pSender->setOnErr([weakSelf](const SockException &err) {
|
||||
strongSelf->_pSender->setOnErr([weakSelf](const SockException &err) {
|
||||
auto strongSelf=weakSelf.lock();
|
||||
if(!strongSelf) {
|
||||
return;
|
||||
@ -1033,9 +1033,9 @@ inline void RtspSession::sendRTCP() {
|
||||
//DebugL;
|
||||
uint8_t aui8Rtcp[60] = {0};
|
||||
uint8_t *pui8Rtcp_SR = aui8Rtcp + 4, *pui8Rtcp_SDES = pui8Rtcp_SR + 28;
|
||||
for (uint8_t i = 0; i < m_uiTrackCnt; i++) {
|
||||
auto &track = m_aTrackInfo[i];
|
||||
auto &counter = m_aRtcpCnt[i];
|
||||
for (uint8_t i = 0; i < _uiTrackCnt; i++) {
|
||||
auto &track = _aTrackInfo[i];
|
||||
auto &counter = _aRtcpCnt[i];
|
||||
|
||||
aui8Rtcp[0] = '$';
|
||||
aui8Rtcp[1] = track.trackId * 2 + 1;
|
||||
|
@ -90,8 +90,8 @@ protected:
|
||||
private:
|
||||
void inputRtspOrRtcp(const char *data,uint64_t len);
|
||||
int send(const Buffer::Ptr &pkt) override{
|
||||
m_ui64TotalBytes += pkt->size();
|
||||
return m_pSender->send(pkt,_flags);
|
||||
_ui64TotalBytes += pkt->size();
|
||||
return _pSender->send(pkt,_flags);
|
||||
}
|
||||
void shutdown() override ;
|
||||
void shutdown_l(bool close);
|
||||
@ -123,16 +123,16 @@ private:
|
||||
return tmp;
|
||||
}
|
||||
inline int getTrackIndexByTrackType(TrackType type) {
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
|
||||
if (type == m_aTrackInfo[i].type) {
|
||||
for (unsigned int i = 0; i < _uiTrackCnt; i++) {
|
||||
if (type == _aTrackInfo[i].type) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
inline int getTrackIndexByControlSuffix(const string &controlSuffix) {
|
||||
for (unsigned int i = 0; i < m_uiTrackCnt; i++) {
|
||||
if (controlSuffix == m_aTrackInfo[i].controlSuffix) {
|
||||
for (unsigned int i = 0; i < _uiTrackCnt; i++) {
|
||||
if (controlSuffix == _aTrackInfo[i].controlSuffix) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -150,53 +150,53 @@ private:
|
||||
static void onAuthDigest(const weak_ptr<RtspSession> &weakSelf,const string &realm,const string &strMd5);
|
||||
|
||||
private:
|
||||
char *m_pcBuf = nullptr;
|
||||
Ticker m_ticker;
|
||||
Parser m_parser; //rtsp解析类
|
||||
string m_strUrl;
|
||||
string m_strSdp;
|
||||
string m_strSession;
|
||||
bool m_bFirstPlay = true;
|
||||
MediaInfo m_mediaInfo;
|
||||
std::weak_ptr<RtspMediaSource> m_pMediaSrc;
|
||||
char *_pcBuf = nullptr;
|
||||
Ticker _ticker;
|
||||
Parser _parser; //rtsp解析类
|
||||
string _strUrl;
|
||||
string _strSdp;
|
||||
string _strSession;
|
||||
bool _bFirstPlay = true;
|
||||
MediaInfo _mediaInfo;
|
||||
std::weak_ptr<RtspMediaSource> _pMediaSrc;
|
||||
|
||||
//RTP缓冲
|
||||
weak_ptr<RingBuffer<RtpPacket::Ptr> > m_pWeakRing;
|
||||
RingBuffer<RtpPacket::Ptr>::RingReader::Ptr m_pRtpReader;
|
||||
weak_ptr<RingBuffer<RtpPacket::Ptr> > _pWeakRing;
|
||||
RingBuffer<RtpPacket::Ptr>::RingReader::Ptr _pRtpReader;
|
||||
|
||||
PlayerBase::eRtpType m_rtpType = PlayerBase::RTP_UDP;
|
||||
bool m_bSetUped = false;
|
||||
int m_iCseq = 0;
|
||||
unsigned int m_uiTrackCnt = 0; //媒体track个数
|
||||
RtspTrack m_aTrackInfo[2]; //媒体track信息,trackid idx 为数组下标
|
||||
bool m_bGotAllPeerUdp = false;
|
||||
PlayerBase::eRtpType _rtpType = PlayerBase::RTP_UDP;
|
||||
bool _bSetUped = false;
|
||||
int _iCseq = 0;
|
||||
unsigned int _uiTrackCnt = 0; //媒体track个数
|
||||
RtspTrack _aTrackInfo[2]; //媒体track信息,trackid idx 为数组下标
|
||||
bool _bGotAllPeerUdp = false;
|
||||
|
||||
#ifdef RTSP_SEND_RTCP
|
||||
RtcpCounter m_aRtcpCnt[2]; //rtcp统计,trackid idx 为数组下标
|
||||
Ticker m_aRtcpTicker[2]; //rtcp发送时间,trackid idx 为数组下标
|
||||
RtcpCounter _aRtcpCnt[2]; //rtcp统计,trackid idx 为数组下标
|
||||
Ticker _aRtcpTicker[2]; //rtcp发送时间,trackid idx 为数组下标
|
||||
inline void sendRTCP();
|
||||
#endif
|
||||
|
||||
//RTP over UDP
|
||||
bool m_abGotPeerUdp[2] = { false, false }; //获取客户端udp端口计数
|
||||
weak_ptr<Socket> m_apUdpSock[2]; //发送RTP的UDP端口,trackid idx 为数组下标
|
||||
std::shared_ptr<struct sockaddr> m_apPeerUdpAddr[2]; //播放器接收RTP的地址,trackid idx 为数组下标
|
||||
bool m_bListenPeerUdpData = false;
|
||||
RtpBroadCaster::Ptr m_pBrdcaster;
|
||||
bool _abGotPeerUdp[2] = { false, false }; //获取客户端udp端口计数
|
||||
weak_ptr<Socket> _apUdpSock[2]; //发送RTP的UDP端口,trackid idx 为数组下标
|
||||
std::shared_ptr<struct sockaddr> _apPeerUdpAddr[2]; //播放器接收RTP的地址,trackid idx 为数组下标
|
||||
bool _bListenPeerUdpData = false;
|
||||
RtpBroadCaster::Ptr _pBrdcaster;
|
||||
|
||||
//登录认证
|
||||
string m_strNonce;
|
||||
string _strNonce;
|
||||
|
||||
//RTSP over HTTP
|
||||
function<void(void)> m_onDestory;
|
||||
bool m_bBase64need = false; //是否需要base64解码
|
||||
Socket::Ptr m_pSender; //回复rtsp时走的tcp通道,供quicktime用
|
||||
function<void(void)> _onDestory;
|
||||
bool _bBase64need = false; //是否需要base64解码
|
||||
Socket::Ptr _pSender; //回复rtsp时走的tcp通道,供quicktime用
|
||||
//quicktime 请求rtsp会产生两次tcp连接,
|
||||
//一次发送 get 一次发送post,需要通过sessioncookie关联起来
|
||||
string m_strSessionCookie;
|
||||
string _strSessionCookie;
|
||||
|
||||
//消耗的总流量
|
||||
uint64_t m_ui64TotalBytes = 0;
|
||||
uint64_t _ui64TotalBytes = 0;
|
||||
|
||||
static recursive_mutex g_mtxGetter; //对quicktime上锁保护
|
||||
static recursive_mutex g_mtxPostter; //对quicktime上锁保护
|
||||
|
@ -43,7 +43,7 @@ RtspToRtmpMediaSource::RtspToRtmpMediaSource(const string &vhost,
|
||||
const string &id,
|
||||
bool bEnableHls,
|
||||
bool bEnableMp4) :
|
||||
RtspMediaSource(vhost,app,id),m_bEnableHls(bEnableHls),m_bEnableMp4(bEnableMp4) {
|
||||
RtspMediaSource(vhost,app,id),_bEnableHls(bEnableHls),_bEnableMp4(bEnableMp4) {
|
||||
}
|
||||
|
||||
RtspToRtmpMediaSource::~RtspToRtmpMediaSource() {
|
||||
@ -65,36 +65,36 @@ void RtspToRtmpMediaSource::makeVideoConfigPkt() {
|
||||
rtmpPkt->strBuf.push_back(1); // version
|
||||
|
||||
//todo(xzl) 修复此处
|
||||
string m_sps ;//= m_pParser->getSps().substr(4);
|
||||
string m_pps ;//= m_pParser->getPps().substr(4);
|
||||
//DebugL<<hexdump(m_sps.data(), m_sps.size());
|
||||
rtmpPkt->strBuf.push_back(m_sps[1]); // profile
|
||||
rtmpPkt->strBuf.push_back(m_sps[2]); // compat
|
||||
rtmpPkt->strBuf.push_back(m_sps[3]); // level
|
||||
string _sps ;//= _pParser->getSps().substr(4);
|
||||
string _pps ;//= _pParser->getPps().substr(4);
|
||||
//DebugL<<hexdump(_sps.data(), _sps.size());
|
||||
rtmpPkt->strBuf.push_back(_sps[1]); // profile
|
||||
rtmpPkt->strBuf.push_back(_sps[2]); // compat
|
||||
rtmpPkt->strBuf.push_back(_sps[3]); // level
|
||||
rtmpPkt->strBuf.push_back(0xff); // 6 bits reserved + 2 bits nal size length - 1 (11)
|
||||
rtmpPkt->strBuf.push_back(0xe1); // 3 bits reserved + 5 bits number of sps (00001)
|
||||
uint16_t size = m_sps.size();
|
||||
uint16_t size = _sps.size();
|
||||
size = htons(size);
|
||||
rtmpPkt->strBuf.append((char *) &size, 2);
|
||||
rtmpPkt->strBuf.append(m_sps);
|
||||
rtmpPkt->strBuf.append(_sps);
|
||||
|
||||
/////////////pps
|
||||
rtmpPkt->strBuf.push_back(1); // version
|
||||
size = m_pps.size();
|
||||
size = _pps.size();
|
||||
size = htons(size);
|
||||
rtmpPkt->strBuf.append((char *) &size, 2);
|
||||
rtmpPkt->strBuf.append(m_pps);
|
||||
rtmpPkt->strBuf.append(_pps);
|
||||
|
||||
rtmpPkt->bodySize = rtmpPkt->strBuf.size();
|
||||
rtmpPkt->chunkId = CHUNK_VIDEO;
|
||||
rtmpPkt->streamId = STREAM_MEDIA;
|
||||
rtmpPkt->timeStamp = 0;
|
||||
rtmpPkt->typeId = MSG_VIDEO;
|
||||
m_pRtmpSrc->onGetMedia(rtmpPkt);
|
||||
_pRtmpSrc->onGetMedia(rtmpPkt);
|
||||
}
|
||||
void RtspToRtmpMediaSource::onGetH264(const H264Frame& frame) {
|
||||
if(m_pRecorder){
|
||||
m_pRecorder->inputH264((char *) frame.data(), frame.size(), frame.timeStamp, frame.type);
|
||||
if(_pRecorder){
|
||||
_pRecorder->inputH264((char *) frame.data(), frame.size(), frame.timeStamp, frame.type);
|
||||
}
|
||||
uint8_t nal_type = frame.data()[4] & 0x1F;
|
||||
int8_t flags = 7; //h.264
|
||||
@ -124,17 +124,17 @@ void RtspToRtmpMediaSource::onGetH264(const H264Frame& frame) {
|
||||
rtmpPkt->streamId = STREAM_MEDIA;
|
||||
rtmpPkt->timeStamp = frame.timeStamp;
|
||||
rtmpPkt->typeId = MSG_VIDEO;
|
||||
m_pRtmpSrc->onGetMedia(rtmpPkt);
|
||||
_pRtmpSrc->onGetMedia(rtmpPkt);
|
||||
}
|
||||
void RtspToRtmpMediaSource::onGetAAC(const AACFrame& frame) {
|
||||
if(m_pRecorder){
|
||||
m_pRecorder->inputAAC((char *) frame.buffer, frame.aac_frame_length, frame.timeStamp);
|
||||
if(_pRecorder){
|
||||
_pRecorder->inputAAC((char *) frame.buffer, frame.aac_frame_length, frame.timeStamp);
|
||||
}
|
||||
|
||||
RtmpPacket::Ptr rtmpPkt(new RtmpPacket);
|
||||
//////////header
|
||||
uint8_t is_config = false;
|
||||
rtmpPkt->strBuf.push_back(m_ui8AudioFlags);
|
||||
rtmpPkt->strBuf.push_back(_ui8AudioFlags);
|
||||
rtmpPkt->strBuf.push_back(!is_config);
|
||||
rtmpPkt->strBuf.append((char *) frame.buffer + 7, frame.aac_frame_length - 7);
|
||||
|
||||
@ -143,15 +143,15 @@ void RtspToRtmpMediaSource::onGetAAC(const AACFrame& frame) {
|
||||
rtmpPkt->streamId = STREAM_MEDIA;
|
||||
rtmpPkt->timeStamp = frame.timeStamp;
|
||||
rtmpPkt->typeId = MSG_AUDIO;
|
||||
m_pRtmpSrc->onGetMedia(rtmpPkt);
|
||||
_pRtmpSrc->onGetMedia(rtmpPkt);
|
||||
}
|
||||
|
||||
void RtspToRtmpMediaSource::makeAudioConfigPkt() {
|
||||
//todo(xzl) 修复此处
|
||||
#if 0
|
||||
uint8_t flvStereoOrMono = (m_pParser->getAudioChannel() > 1);
|
||||
uint8_t flvStereoOrMono = (_pParser->getAudioChannel() > 1);
|
||||
uint8_t flvSampleRate;
|
||||
switch (m_pParser->getAudioSampleRate()) {
|
||||
switch (_pParser->getAudioSampleRate()) {
|
||||
case 48000:
|
||||
case 44100:
|
||||
flvSampleRate = 3;
|
||||
@ -168,57 +168,57 @@ void RtspToRtmpMediaSource::makeAudioConfigPkt() {
|
||||
flvSampleRate = 0;
|
||||
break;
|
||||
}
|
||||
uint8_t flvSampleBit = m_pParser->getAudioSampleBit() == 16;
|
||||
uint8_t flvSampleBit = _pParser->getAudioSampleBit() == 16;
|
||||
uint8_t flvAudioType = 10; //aac
|
||||
|
||||
m_ui8AudioFlags = (flvAudioType << 4) | (flvSampleRate << 2) | (flvSampleBit << 1) | flvStereoOrMono;
|
||||
_ui8AudioFlags = (flvAudioType << 4) | (flvSampleRate << 2) | (flvSampleBit << 1) | flvStereoOrMono;
|
||||
|
||||
RtmpPacket::Ptr rtmpPkt(new RtmpPacket);
|
||||
//////////header
|
||||
uint8_t is_config = true;
|
||||
rtmpPkt->strBuf.push_back(m_ui8AudioFlags);
|
||||
rtmpPkt->strBuf.push_back(_ui8AudioFlags);
|
||||
rtmpPkt->strBuf.push_back(!is_config);
|
||||
rtmpPkt->strBuf.append(m_pParser->getAudioCfg());
|
||||
rtmpPkt->strBuf.append(_pParser->getAudioCfg());
|
||||
|
||||
rtmpPkt->bodySize = rtmpPkt->strBuf.size();
|
||||
rtmpPkt->chunkId = CHUNK_AUDIO;
|
||||
rtmpPkt->streamId = STREAM_MEDIA;
|
||||
rtmpPkt->timeStamp = 0;
|
||||
rtmpPkt->typeId = MSG_AUDIO;
|
||||
m_pRtmpSrc->onGetMedia(rtmpPkt);
|
||||
_pRtmpSrc->onGetMedia(rtmpPkt);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void RtspToRtmpMediaSource::makeMetaData() {
|
||||
m_pRtmpSrc.reset(new RtmpMediaSource(getVhost(),getApp(),getId()));
|
||||
m_pRtmpSrc->setListener(m_listener);
|
||||
_pRtmpSrc.reset(new RtmpMediaSource(getVhost(),getApp(),getId()));
|
||||
_pRtmpSrc->setListener(_listener);
|
||||
AMFValue metaData(AMF_OBJECT);
|
||||
metaData.set("duration", m_pParser->getDuration());
|
||||
metaData.set("duration", _pParser->getDuration());
|
||||
metaData.set("fileSize", 0);
|
||||
//todo(xzl) 修复此处
|
||||
#if 0
|
||||
|
||||
if (m_pParser->containVideo()) {
|
||||
metaData.set("width", m_pParser->getVideoWidth());
|
||||
metaData.set("height", m_pParser->getVideoHeight());
|
||||
if (_pParser->containVideo()) {
|
||||
metaData.set("width", _pParser->getVideoWidth());
|
||||
metaData.set("height", _pParser->getVideoHeight());
|
||||
metaData.set("videocodecid", "avc1"); //h.264
|
||||
metaData.set("videodatarate", 5000);
|
||||
metaData.set("framerate", m_pParser->getVideoFps());
|
||||
metaData.set("framerate", _pParser->getVideoFps());
|
||||
makeVideoConfigPkt();
|
||||
}
|
||||
if (m_pParser->containAudio()) {
|
||||
if (_pParser->containAudio()) {
|
||||
metaData.set("audiocodecid", "mp4a"); //aac
|
||||
metaData.set("audiodatarate", 160);
|
||||
metaData.set("audiosamplerate", m_pParser->getAudioSampleRate());
|
||||
metaData.set("audiosamplesize", m_pParser->getAudioSampleBit());
|
||||
metaData.set("audiochannels", m_pParser->getAudioChannel());
|
||||
metaData.set("stereo", m_pParser->getAudioChannel() > 1);
|
||||
metaData.set("audiosamplerate", _pParser->getAudioSampleRate());
|
||||
metaData.set("audiosamplesize", _pParser->getAudioSampleBit());
|
||||
metaData.set("audiochannels", _pParser->getAudioChannel());
|
||||
metaData.set("stereo", _pParser->getAudioChannel() > 1);
|
||||
makeAudioConfigPkt();
|
||||
}
|
||||
|
||||
#endif
|
||||
m_pRtmpSrc->onGetMetaData(metaData);
|
||||
_pRtmpSrc->onGetMetaData(metaData);
|
||||
}
|
||||
} /* namespace Rtsp */
|
||||
} /* namespace ZL */
|
||||
|
@ -52,11 +52,11 @@ public:
|
||||
|
||||
virtual void onGetSDP(const string& strSdp) override{
|
||||
try {
|
||||
m_pParser.reset(new RtpParser(strSdp));
|
||||
m_pRecorder.reset(new MediaRecorder(getVhost(),getApp(),getId(),m_pParser,m_bEnableHls,m_bEnableMp4));
|
||||
_pParser.reset(new RtpParser(strSdp));
|
||||
_pRecorder.reset(new MediaRecorder(getVhost(),getApp(),getId(),_pParser,_bEnableHls,_bEnableMp4));
|
||||
//todo(xzl) 修复此处
|
||||
// m_pParser->setOnAudioCB( std::bind(&RtspToRtmpMediaSource::onGetAAC, this, placeholders::_1));
|
||||
// m_pParser->setOnVideoCB( std::bind(&RtspToRtmpMediaSource::onGetH264, this, placeholders::_1));
|
||||
// _pParser->setOnAudioCB( std::bind(&RtspToRtmpMediaSource::onGetAAC, this, placeholders::_1));
|
||||
// _pParser->setOnVideoCB( std::bind(&RtspToRtmpMediaSource::onGetH264, this, placeholders::_1));
|
||||
makeMetaData();
|
||||
} catch (exception &ex) {
|
||||
WarnL << ex.what();
|
||||
@ -64,22 +64,22 @@ public:
|
||||
RtspMediaSource::onGetSDP(strSdp);
|
||||
}
|
||||
virtual void onGetRTP(const RtpPacket::Ptr &pRtppkt, bool bKeyPos) override{
|
||||
if (m_pParser) {
|
||||
bKeyPos = m_pParser->inputRtp(pRtppkt);
|
||||
if (_pParser) {
|
||||
bKeyPos = _pParser->inputRtp(pRtppkt);
|
||||
}
|
||||
RtspMediaSource::onGetRTP(pRtppkt, bKeyPos);
|
||||
}
|
||||
|
||||
int readerCount(){
|
||||
return getRing()->readerCount() + (m_pRtmpSrc ? m_pRtmpSrc->getRing()->readerCount() : 0);
|
||||
return getRing()->readerCount() + (_pRtmpSrc ? _pRtmpSrc->getRing()->readerCount() : 0);
|
||||
}
|
||||
|
||||
void updateTimeStamp(uint32_t uiStamp) {
|
||||
for (auto &pr : m_mapTracks) {
|
||||
for (auto &pr : _mapTracks) {
|
||||
switch (pr.second.type) {
|
||||
case TrackAudio: {
|
||||
//todo(xzl) 修复此处
|
||||
// pr.second.timeStamp = uiStamp * (m_pParser->getAudioSampleRate() / 1000.0);
|
||||
// pr.second.timeStamp = uiStamp * (_pParser->getAudioSampleRate() / 1000.0);
|
||||
}
|
||||
break;
|
||||
case TrackVideo: {
|
||||
@ -100,12 +100,12 @@ private:
|
||||
void makeAudioConfigPkt();
|
||||
void makeMetaData();
|
||||
private:
|
||||
RtpParser::Ptr m_pParser;
|
||||
RtmpMediaSource::Ptr m_pRtmpSrc;
|
||||
uint8_t m_ui8AudioFlags = 0;
|
||||
MediaRecorder::Ptr m_pRecorder;
|
||||
bool m_bEnableHls;
|
||||
bool m_bEnableMp4;
|
||||
RtpParser::Ptr _pParser;
|
||||
RtmpMediaSource::Ptr _pRtmpSrc;
|
||||
uint8_t _ui8AudioFlags = 0;
|
||||
MediaRecorder::Ptr _pRecorder;
|
||||
bool _bEnableHls;
|
||||
bool _bEnableMp4;
|
||||
|
||||
};
|
||||
|
||||
|
@ -48,10 +48,10 @@ UDPServer::~UDPServer() {
|
||||
}
|
||||
|
||||
Socket::Ptr UDPServer::getSock(const char* strLocalIp, int iTrackIndex,uint16_t iLocalPort) {
|
||||
lock_guard<mutex> lck(m_mtxUpdSock);
|
||||
lock_guard<mutex> lck(_mtxUpdSock);
|
||||
string strKey = StrPrinter << strLocalIp << ":" << iTrackIndex << endl;
|
||||
auto it = m_mapUpdSock.find(strKey);
|
||||
if (it == m_mapUpdSock.end()) {
|
||||
auto it = _mapUpdSock.find(strKey);
|
||||
if (it == _mapUpdSock.end()) {
|
||||
Socket::Ptr pSock(new Socket());
|
||||
//InfoL<<localIp;
|
||||
if (!pSock->bindUdpSock(iLocalPort, strLocalIp)) {
|
||||
@ -61,7 +61,7 @@ Socket::Ptr UDPServer::getSock(const char* strLocalIp, int iTrackIndex,uint16_t
|
||||
|
||||
pSock->setOnRead(bind(&UDPServer::onRcvData, this, iTrackIndex, placeholders::_1,placeholders::_2));
|
||||
pSock->setOnErr(bind(&UDPServer::onErr, this, strKey, placeholders::_1));
|
||||
m_mapUpdSock[strKey] = pSock;
|
||||
_mapUpdSock[strKey] = pSock;
|
||||
DebugL << strLocalIp << " " << pSock->get_local_port() << " " << iTrackIndex;
|
||||
return pSock;
|
||||
}
|
||||
@ -69,15 +69,15 @@ Socket::Ptr UDPServer::getSock(const char* strLocalIp, int iTrackIndex,uint16_t
|
||||
}
|
||||
|
||||
void UDPServer::listenPeer(const char* strPeerIp, void* pSelf, const onRecvData& cb) {
|
||||
lock_guard<mutex> lck(m_mtxDataHandler);
|
||||
auto &mapRef = m_mapDataHandler[strPeerIp];
|
||||
lock_guard<mutex> lck(_mtxDataHandler);
|
||||
auto &mapRef = _mapDataHandler[strPeerIp];
|
||||
mapRef.emplace(pSelf, cb);
|
||||
}
|
||||
|
||||
void UDPServer::stopListenPeer(const char* strPeerIp, void* pSelf) {
|
||||
lock_guard<mutex> lck(m_mtxDataHandler);
|
||||
auto it0 = m_mapDataHandler.find(strPeerIp);
|
||||
if (it0 == m_mapDataHandler.end()) {
|
||||
lock_guard<mutex> lck(_mtxDataHandler);
|
||||
auto it0 = _mapDataHandler.find(strPeerIp);
|
||||
if (it0 == _mapDataHandler.end()) {
|
||||
return;
|
||||
}
|
||||
auto &mapRef = it0->second;
|
||||
@ -86,22 +86,22 @@ void UDPServer::stopListenPeer(const char* strPeerIp, void* pSelf) {
|
||||
mapRef.erase(it1);
|
||||
}
|
||||
if (mapRef.size() == 0) {
|
||||
m_mapDataHandler.erase(it0);
|
||||
_mapDataHandler.erase(it0);
|
||||
}
|
||||
|
||||
}
|
||||
void UDPServer::onErr(const string& strKey, const SockException& err) {
|
||||
WarnL << err.what();
|
||||
lock_guard<mutex> lck(m_mtxUpdSock);
|
||||
m_mapUpdSock.erase(strKey);
|
||||
lock_guard<mutex> lck(_mtxUpdSock);
|
||||
_mapUpdSock.erase(strKey);
|
||||
}
|
||||
void UDPServer::onRcvData(int iTrackIndex, const Buffer::Ptr &pBuf, struct sockaddr* pPeerAddr) {
|
||||
//TraceL << trackIndex;
|
||||
struct sockaddr_in *in = (struct sockaddr_in *) pPeerAddr;
|
||||
string peerIp = inet_ntoa(in->sin_addr);
|
||||
lock_guard<mutex> lck(m_mtxDataHandler);
|
||||
auto it0 = m_mapDataHandler.find(peerIp);
|
||||
if (it0 == m_mapDataHandler.end()) {
|
||||
lock_guard<mutex> lck(_mtxDataHandler);
|
||||
auto it0 = _mapDataHandler.find(peerIp);
|
||||
if (it0 == _mapDataHandler.end()) {
|
||||
return;
|
||||
}
|
||||
auto &mapRef = it0->second;
|
||||
@ -112,7 +112,7 @@ void UDPServer::onRcvData(int iTrackIndex, const Buffer::Ptr &pBuf, struct socka
|
||||
}
|
||||
}
|
||||
if (mapRef.size() == 0) {
|
||||
m_mapDataHandler.erase(it0);
|
||||
_mapDataHandler.erase(it0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,11 +56,11 @@ public:
|
||||
private:
|
||||
void onRcvData(int iTrackId, const Buffer::Ptr &pBuf,struct sockaddr *pPeerAddr);
|
||||
void onErr(const string &strKey,const SockException &err);
|
||||
unordered_map<string, Socket::Ptr> m_mapUpdSock;
|
||||
mutex m_mtxUpdSock;
|
||||
unordered_map<string, Socket::Ptr> _mapUpdSock;
|
||||
mutex _mtxUpdSock;
|
||||
|
||||
unordered_map<string, unordered_map<void *, onRecvData> > m_mapDataHandler;
|
||||
mutex m_mtxDataHandler;
|
||||
unordered_map<string, unordered_map<void *, onRecvData> > _mapDataHandler;
|
||||
mutex _mtxDataHandler;
|
||||
};
|
||||
|
||||
} /* namespace Rtsp */
|
||||
|
@ -48,14 +48,14 @@ ShellSession::~ShellSession() {
|
||||
void ShellSession::onRecv(const Buffer::Ptr&buf) {
|
||||
//DebugL << hexdump(buf->data(), buf->size());
|
||||
GET_CONFIG_AND_REGISTER(uint32_t,maxReqSize,Config::Shell::kMaxReqSize);
|
||||
if (m_strRecvBuf.size() + buf->size() >= maxReqSize) {
|
||||
if (_strRecvBuf.size() + buf->size() >= maxReqSize) {
|
||||
WarnL << "接收缓冲区溢出!";
|
||||
shutdown();
|
||||
return;
|
||||
}
|
||||
m_beatTicker.resetTime();
|
||||
m_strRecvBuf.append(buf->data(), buf->size());
|
||||
if (m_strRecvBuf.find("\xff\xf4\xff\0xfd\x06") != std::string::npos) {
|
||||
_beatTicker.resetTime();
|
||||
_strRecvBuf.append(buf->data(), buf->size());
|
||||
if (_strRecvBuf.find("\xff\xf4\xff\0xfd\x06") != std::string::npos) {
|
||||
WarnL << "收到Ctrl+C.";
|
||||
send("\033[0m\r\n Bye bye!\r\n");
|
||||
shutdown();
|
||||
@ -63,9 +63,9 @@ void ShellSession::onRecv(const Buffer::Ptr&buf) {
|
||||
}
|
||||
size_t index;
|
||||
string line;
|
||||
while ((index = m_strRecvBuf.find("\r\n")) != std::string::npos) {
|
||||
line = m_strRecvBuf.substr(0, index);
|
||||
m_strRecvBuf.erase(0, index + 2);
|
||||
while ((index = _strRecvBuf.find("\r\n")) != std::string::npos) {
|
||||
line = _strRecvBuf.substr(0, index);
|
||||
_strRecvBuf.erase(0, index + 2);
|
||||
if (!onCommandLine(line)) {
|
||||
shutdown();
|
||||
return;
|
||||
@ -74,7 +74,7 @@ void ShellSession::onRecv(const Buffer::Ptr&buf) {
|
||||
}
|
||||
|
||||
void ShellSession::onManager() {
|
||||
if (m_beatTicker.elapsedTime() > 1000 * 60 * 5) {
|
||||
if (_beatTicker.elapsedTime() > 1000 * 60 * 5) {
|
||||
//5 miniutes for alive
|
||||
shutdown();
|
||||
return;
|
||||
@ -82,7 +82,7 @@ void ShellSession::onManager() {
|
||||
}
|
||||
|
||||
inline bool ShellSession::onCommandLine(const string& line) {
|
||||
auto loginInterceptor = m_loginInterceptor;
|
||||
auto loginInterceptor = _loginInterceptor;
|
||||
if (loginInterceptor) {
|
||||
bool ret = loginInterceptor(line);
|
||||
return ret;
|
||||
@ -104,15 +104,15 @@ inline bool ShellSession::onCommandLine(const string& line) {
|
||||
inline void ShellSession::pleaseInputUser() {
|
||||
send("\033[0m");
|
||||
send(StrPrinter << SERVER_NAME << " login: " << endl);
|
||||
m_loginInterceptor = [this](const string &user_name) {
|
||||
m_strUserName=user_name;
|
||||
_loginInterceptor = [this](const string &user_name) {
|
||||
_strUserName=user_name;
|
||||
pleaseInputPasswd();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
inline void ShellSession::pleaseInputPasswd() {
|
||||
send("Password: \033[8m");
|
||||
m_loginInterceptor = [this](const string &passwd) {
|
||||
_loginInterceptor = [this](const string &passwd) {
|
||||
auto onAuth = [this](const string &errMessage){
|
||||
if(!errMessage.empty()){
|
||||
//鉴权失败
|
||||
@ -120,7 +120,7 @@ inline void ShellSession::pleaseInputPasswd() {
|
||||
<<"\033[0mAuth failed("
|
||||
<< errMessage
|
||||
<<"), please try again.\r\n"
|
||||
<<m_strUserName<<"@"<<SERVER_NAME
|
||||
<<_strUserName<<"@"<<SERVER_NAME
|
||||
<<"'s password: \033[8m"
|
||||
<<endl);
|
||||
return;
|
||||
@ -130,7 +130,7 @@ inline void ShellSession::pleaseInputPasswd() {
|
||||
send(StrPrinter<<"欢迎来到"<<SERVER_NAME<<", 你可输入\"help\"查看帮助.\r\n"<<endl);
|
||||
send("-----------------------------------------\r\n");
|
||||
printShellPrefix();
|
||||
m_loginInterceptor=nullptr;
|
||||
_loginInterceptor=nullptr;
|
||||
};
|
||||
|
||||
weak_ptr<ShellSession> weakSelf = dynamic_pointer_cast<ShellSession>(shared_from_this());
|
||||
@ -148,7 +148,7 @@ inline void ShellSession::pleaseInputPasswd() {
|
||||
});
|
||||
};
|
||||
|
||||
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastShellLogin,m_strUserName,passwd,invoker,*this);
|
||||
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastShellLogin,_strUserName,passwd,invoker,*this);
|
||||
if(!flag){
|
||||
//如果无人监听shell登录事件,那么默认shell无法登录
|
||||
onAuth("please listen kBroadcastShellLogin event");
|
||||
@ -158,7 +158,7 @@ inline void ShellSession::pleaseInputPasswd() {
|
||||
}
|
||||
|
||||
inline void ShellSession::printShellPrefix() {
|
||||
send(StrPrinter << m_strUserName << "@" << SERVER_NAME << "# " << endl);
|
||||
send(StrPrinter << _strUserName << "@" << SERVER_NAME << "# " << endl);
|
||||
}
|
||||
|
||||
}/* namespace Shell */
|
||||
|
@ -54,10 +54,10 @@ private:
|
||||
inline void pleaseInputPasswd();
|
||||
inline void printShellPrefix();
|
||||
|
||||
function<bool(const string &)> m_loginInterceptor;
|
||||
string m_strRecvBuf;
|
||||
Ticker m_beatTicker;
|
||||
string m_strUserName;
|
||||
function<bool(const string &)> _loginInterceptor;
|
||||
string _strRecvBuf;
|
||||
Ticker _beatTicker;
|
||||
string _strUserName;
|
||||
};
|
||||
|
||||
} /* namespace Shell */
|
||||
|
Loading…
Reference in New Issue
Block a user