mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-06-30 06:42:22 +08:00
统一成员变量命名风格
This commit is contained in:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user