diff --git a/src/Common/Device.cpp b/src/Common/Device.cpp index 5e7073dc..189c0757 100644 --- a/src/Common/Device.cpp +++ b/src/Common/Device.cpp @@ -87,7 +87,7 @@ void DevChannel::inputH264(const char *data, int len, uint32_t dts, uint32_t pts //由于rtmp/hls/mp4需要缓存时间戳相同的帧, //所以使用FrameNoCacheAble类型的帧反而会在转换成FrameCacheAble时多次内存拷贝 //在此处只拷贝一次,性能开销更低 - H264Frame::Ptr frame = std::make_shared(); + auto frame = FrameImp::create(); frame->_dts = dts; frame->_pts = pts; frame->_buffer.assign(data, len); @@ -106,7 +106,7 @@ void DevChannel::inputH265(const char *data, int len, uint32_t dts, uint32_t pts //由于rtmp/hls/mp4需要缓存时间戳相同的帧, //所以使用FrameNoCacheAble类型的帧反而会在转换成FrameCacheAble时多次内存拷贝 //在此处只拷贝一次,性能开销更低 - H265Frame::Ptr frame = std::make_shared(); + auto frame = FrameImp::create(); frame->_dts = dts; frame->_pts = pts; frame->_buffer.assign(data, len); diff --git a/src/Extension/AAC.cpp b/src/Extension/AAC.cpp index 2f1691ec..d29ccc59 100644 --- a/src/Extension/AAC.cpp +++ b/src/Extension/AAC.cpp @@ -182,6 +182,136 @@ bool parseAacConfig(const string &config, int &samplerate, int &channels){ #endif } +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * aac类型SDP + */ +class AACSdp : public Sdp { +public: + /** + * 构造函数 + * @param aac_cfg aac两个字节的配置描述 + * @param sample_rate 音频采样率 + * @param payload_type rtp payload type 默认98 + * @param bitrate 比特率 + */ + AACSdp(const string &aac_cfg, + int sample_rate, + int channels, + int bitrate = 128, + int payload_type = 98) : Sdp(sample_rate,payload_type){ + _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; + if (bitrate) { + _printer << "b=AS:" << bitrate << "\r\n"; + } + _printer << "a=rtpmap:" << payload_type << " MPEG4-GENERIC/" << sample_rate << "/" << channels << "\r\n"; + + string configStr; + char buf[4] = {0}; + for(auto &ch : aac_cfg){ + snprintf(buf, sizeof(buf), "%02X", (uint8_t)ch); + configStr.append(buf); + } + _printer << "a=fmtp:" << payload_type << " streamtype=5;profile-level-id=1;mode=AAC-hbr;" + << "sizelength=13;indexlength=3;indexdeltalength=3;config=" << configStr << "\r\n"; + _printer << "a=control:trackID=" << (int)TrackAudio << "\r\n"; + } + + string getSdp() const override { + return _printer; + } + + CodecId getCodecId() const override { + return CodecAAC; + } +private: + _StrPrinter _printer; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +AACTrack::AACTrack(const string &aac_cfg) { + if (aac_cfg.size() < 2) { + throw std::invalid_argument("adts配置必须最少2个字节"); + } + _cfg = aac_cfg; + onReady(); +} + +const string &AACTrack::getAacCfg() const { + return _cfg; +} + +CodecId AACTrack::getCodecId() const { + return CodecAAC; +} + +bool AACTrack::ready() { + return !_cfg.empty(); +} + +int AACTrack::getAudioSampleRate() const { + return _sampleRate; +} + +int AACTrack::getAudioSampleBit() const { + return _sampleBit; +} + +int AACTrack::getAudioChannel() const { + return _channel; +} + +void AACTrack::inputFrame(const Frame::Ptr &frame) { + if (frame->prefixSize()) { + //有adts头,尝试分帧 + auto ptr = frame->data(); + auto end = frame->data() + frame->size(); + while (ptr < end) { + auto frame_len = getAacFrameLength((uint8_t *) ptr, end - ptr); + if (frame_len < ADTS_HEADER_LEN) { + break; + } + auto sub_frame = std::make_shared >(frame, (char *) ptr, frame_len, ADTS_HEADER_LEN); + ptr += frame_len; + sub_frame->setCodecId(CodecAAC); + inputFrame_l(sub_frame); + } + } else { + inputFrame_l(frame); + } +} + +void AACTrack::inputFrame_l(const Frame::Ptr &frame) { + if (_cfg.empty()) { + //未获取到aac_cfg信息 + if (frame->prefixSize()) { + //根据7个字节的adts头生成aac config + _cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize()); + onReady(); + } else { + WarnL << "无法获取adts头!"; + } + } + + if (frame->size() > frame->prefixSize()) { + //除adts头外,有实际负载 + AudioTrack::inputFrame(frame); + } +} + +void AACTrack::onReady() { + if (_cfg.size() < 2) { + return; + } + parseAacConfig(_cfg, _sampleRate, _channel); +} + +Track::Ptr AACTrack::clone() { + return std::make_shared::type>(*this); +} + Sdp::Ptr AACTrack::getSdp() { if(!ready()){ WarnL << getCodecName() << " Track未准备好"; diff --git a/src/Extension/AAC.h b/src/Extension/AAC.h index 61ff4b66..609b2f4f 100644 --- a/src/Extension/AAC.h +++ b/src/Extension/AAC.h @@ -27,184 +27,43 @@ bool parseAacConfig(const string &config, int &samplerate, int &channels); */ class AACTrack : public AudioTrack{ public: - typedef std::shared_ptr Ptr; + using Ptr = std::shared_ptr; /** * 延后获取adts头信息 * 在随后的inputFrame中获取adts头信息 */ - AACTrack(){} + AACTrack() = default; /** * 构造aac类型的媒体 * @param aac_cfg aac配置信息 */ - AACTrack(const string &aac_cfg){ - setAacCfg(aac_cfg); - } - - /** - * 设置aac 配置信息 - */ - void setAacCfg(const string &aac_cfg){ - if (aac_cfg.size() < 2) { - throw std::invalid_argument("adts配置必须最少2个字节"); - } - _cfg = aac_cfg; - onReady(); - } + AACTrack(const string &aac_cfg); /** * 获取aac 配置信息 */ - const string &getAacCfg() const{ - return _cfg; - } + const string &getAacCfg() const; - /** - * 返回编码类型 - */ - CodecId getCodecId() const override{ - return CodecAAC; - } - - /** - * 在获取aac_cfg前是无效的Track - */ - bool ready() override { - return !_cfg.empty(); - } - - /** - * 返回音频采样率 - */ - int getAudioSampleRate() const override{ - return _sampleRate; - } - - /** - * 返回音频采样位数,一般为16或8 - */ - int getAudioSampleBit() const override{ - return _sampleBit; - } - - /** - * 返回音频通道数 - */ - int getAudioChannel() const override{ - return _channel; - } - - /** - * 输入数据帧,并获取aac_cfg - * @param frame 数据帧 - */ - void inputFrame(const Frame::Ptr &frame) override{ - if (frame->prefixSize()) { - //有adts头,尝试分帧 - auto ptr = frame->data(); - auto end = frame->data() + frame->size(); - while (ptr < end) { - auto frame_len = getAacFrameLength((uint8_t *) ptr, end - ptr); - if (frame_len < ADTS_HEADER_LEN) { - break; - } - - auto sub_frame = std::make_shared >(frame, (char *) ptr, frame_len, ADTS_HEADER_LEN); - ptr += frame_len; - sub_frame->setCodecId(CodecAAC); - inputFrame_l(sub_frame); - } - } else { - inputFrame_l(frame); - } - } + bool ready() override; + CodecId getCodecId() const override; + int getAudioChannel() const override; + int getAudioSampleRate() const override; + int getAudioSampleBit() const override; + void inputFrame(const Frame::Ptr &frame) override; private: - void inputFrame_l(const Frame::Ptr &frame) { - if (_cfg.empty()) { - //未获取到aac_cfg信息 - if (frame->prefixSize()) { - //根据7个字节的adts头生成aac config - _cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize()); - onReady(); - } else { - WarnL << "无法获取adts头!"; - } - } + void onReady(); + Sdp::Ptr getSdp() override; + Track::Ptr clone() override; + void inputFrame_l(const Frame::Ptr &frame); - if (frame->size() > frame->prefixSize()) { - //除adts头外,有实际负载 - AudioTrack::inputFrame(frame); - } - } - /** - * 解析2个字节的aac配置 - */ - void onReady(){ - if (_cfg.size() < 2) { - return; - } - parseAacConfig(_cfg, _sampleRate, _channel); - } - - Track::Ptr clone() override { - return std::make_shared::type >(*this); - } - - //生成sdp - Sdp::Ptr getSdp() override ; private: string _cfg; + int _channel = 0; int _sampleRate = 0; int _sampleBit = 16; - int _channel = 0; -}; - -/** - * aac类型SDP - */ -class AACSdp : public Sdp { -public: - /** - * 构造函数 - * @param aac_cfg aac两个字节的配置描述 - * @param sample_rate 音频采样率 - * @param payload_type rtp payload type 默认98 - * @param bitrate 比特率 - */ - AACSdp(const string &aac_cfg, - int sample_rate, - int channels, - int bitrate = 128, - int payload_type = 98) : Sdp(sample_rate,payload_type){ - _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - _printer << "a=rtpmap:" << payload_type << " MPEG4-GENERIC/" << sample_rate << "/" << channels << "\r\n"; - - string configStr; - char buf[4] = {0}; - for(auto &ch : aac_cfg){ - snprintf(buf, sizeof(buf), "%02X", (uint8_t)ch); - configStr.append(buf); - } - _printer << "a=fmtp:" << payload_type << " streamtype=5;profile-level-id=1;mode=AAC-hbr;" - << "sizelength=13;indexlength=3;indexdeltalength=3;config=" << configStr << "\r\n"; - _printer << "a=control:trackID=" << (int)TrackAudio << "\r\n"; - } - - string getSdp() const override { - return _printer; - } - - CodecId getCodecId() const override { - return CodecAAC; - } -private: - _StrPrinter _printer; }; }//namespace mediakit diff --git a/src/Extension/AACRtmp.cpp b/src/Extension/AACRtmp.cpp index e9bb8699..14ed202e 100644 --- a/src/Extension/AACRtmp.cpp +++ b/src/Extension/AACRtmp.cpp @@ -42,7 +42,7 @@ void AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) { } void AACRtmpDecoder::onGetAAC(const char* data, size_t len, uint32_t stamp) { - auto frame = ResourcePoolHelper::obtainObj(); + auto frame = FrameImp::create(); frame->_codec_id = CodecAAC; //生成adts头 diff --git a/src/Extension/AACRtmp.h b/src/Extension/AACRtmp.h index cc574bed..9b017ad2 100644 --- a/src/Extension/AACRtmp.h +++ b/src/Extension/AACRtmp.h @@ -19,7 +19,7 @@ namespace mediakit{ /** * aac Rtmp转adts类 */ -class AACRtmpDecoder : public RtmpCodec , public ResourcePoolHelper { +class AACRtmpDecoder : public RtmpCodec{ public: typedef std::shared_ptr Ptr; diff --git a/src/Extension/AACRtp.cpp b/src/Extension/AACRtp.cpp index 002ba8c2..890c41ac 100644 --- a/src/Extension/AACRtp.cpp +++ b/src/Extension/AACRtp.cpp @@ -74,9 +74,7 @@ AACRtpDecoder::AACRtpDecoder() { void AACRtpDecoder::obtainFrame() { //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 - _frame = ResourcePoolHelper::obtainObj(); - _frame->_prefix_size = 0; - _frame->_buffer.clear(); + _frame = FrameImp::create(); _frame->_codec_id = CodecAAC; } diff --git a/src/Extension/AACRtp.h b/src/Extension/AACRtp.h index da56f89e..dcb769f4 100644 --- a/src/Extension/AACRtp.h +++ b/src/Extension/AACRtp.h @@ -17,7 +17,7 @@ namespace mediakit{ /** * aac rtp转adts类 */ -class AACRtpDecoder : public RtpCodec , public ResourcePoolHelper { +class AACRtpDecoder : public RtpCodec { public: typedef std::shared_ptr Ptr; diff --git a/src/Extension/CommonRtmp.cpp b/src/Extension/CommonRtmp.cpp index 2a881854..c15f6a1d 100644 --- a/src/Extension/CommonRtmp.cpp +++ b/src/Extension/CommonRtmp.cpp @@ -22,11 +22,8 @@ CodecId CommonRtmpDecoder::getCodecId() const { } void CommonRtmpDecoder::obtainFrame() { - //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 - _frame = ResourcePoolHelper::obtainObj(); - _frame->_buffer.clear(); + _frame = FrameImp::create(); _frame->_codec_id = _codec; - _frame->_prefix_size = 0; } void CommonRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &rtmp) { diff --git a/src/Extension/CommonRtmp.h b/src/Extension/CommonRtmp.h index 465c893f..d1277dc6 100644 --- a/src/Extension/CommonRtmp.h +++ b/src/Extension/CommonRtmp.h @@ -19,7 +19,7 @@ namespace mediakit{ /** * 通用 rtmp解码类 */ -class CommonRtmpDecoder : public RtmpCodec , public ResourcePoolHelper { +class CommonRtmpDecoder : public RtmpCodec { public: typedef std::shared_ptr Ptr; diff --git a/src/Extension/CommonRtp.cpp b/src/Extension/CommonRtp.cpp index 3dbf421b..039bf93d 100644 --- a/src/Extension/CommonRtp.cpp +++ b/src/Extension/CommonRtp.cpp @@ -21,10 +21,7 @@ CodecId CommonRtpDecoder::getCodecId() const { } void CommonRtpDecoder::obtainFrame() { - _frame = ResourcePoolHelper::obtainObj(); - _frame->_buffer.clear(); - _frame->_prefix_size = 0; - _frame->_dts = 0; + _frame = FrameImp::create(); _frame->_codec_id = _codec; } diff --git a/src/Extension/CommonRtp.h b/src/Extension/CommonRtp.h index f03189cd..40828dc9 100644 --- a/src/Extension/CommonRtp.h +++ b/src/Extension/CommonRtp.h @@ -19,7 +19,7 @@ namespace mediakit{ /** * 通用 rtp解码类 */ -class CommonRtpDecoder : public RtpCodec, public ResourcePoolHelper { +class CommonRtpDecoder : public RtpCodec { public: typedef std::shared_ptr Ptr; diff --git a/src/Extension/Frame.cpp b/src/Extension/Frame.cpp index ec5bb3b6..39e04a45 100644 --- a/src/Extension/Frame.cpp +++ b/src/Extension/Frame.cpp @@ -9,6 +9,8 @@ */ #include "Frame.h" +#include "H264.h" +#include "H265.h" using namespace std; using namespace toolkit; @@ -20,6 +22,34 @@ namespace toolkit { namespace mediakit{ +template +std::shared_ptr FrameImp::create_l() { +#if 0 + static ResourcePool packet_pool; + static onceToken token([]() { + packet_pool.setSize(1024); + }); + auto ret = packet_pool.obtain(); + ret->_buffer.clear(); + ret->_prefix_size = 0; + ret->_dts = 0; + ret->_pts = 0; + return ret; +#else + return std::shared_ptr(new C()); +#endif +} + +#define CREATE_FRAME_IMP(C) \ +template<> \ +std::shared_ptr FrameImp::create() { \ + return create_l(); \ +} + +CREATE_FRAME_IMP(FrameImp); +CREATE_FRAME_IMP(H264Frame); +CREATE_FRAME_IMP(H265Frame); + /** * 该对象的功能是把一个不可缓存的帧转换成可缓存的帧 */ @@ -32,8 +62,8 @@ public: _frame = frame; _ptr = frame->data(); }else{ - _buffer = std::make_shared(); - _buffer->assign(frame->data(),frame->size()); + _buffer = FrameImp::create(); + _buffer->_buffer.assign(frame->data(),frame->size()); _ptr = _buffer->data(); } _size = frame->size(); @@ -66,7 +96,7 @@ private: bool _key; bool _config; Frame::Ptr _frame; - BufferRaw::Ptr _buffer; + FrameImp::Ptr _buffer; }; Frame::Ptr Frame::getCacheAbleFrame(const Frame::Ptr &frame){ diff --git a/src/Extension/Frame.h b/src/Extension/Frame.h index e7b87035..4da57732 100644 --- a/src/Extension/Frame.h +++ b/src/Extension/Frame.h @@ -130,7 +130,10 @@ private: class FrameImp : public Frame { public: - typedef std::shared_ptr Ptr; + using Ptr = std::shared_ptr; + + template + static std::shared_ptr create(); char *data() const override{ return (char *)_buffer.data(); @@ -172,6 +175,13 @@ public: BufferLikeString _buffer; //对象个数统计 ObjectStatistic _statistic; + +protected: + friend class ResourcePool_l; + FrameImp() = default; + + template + static std::shared_ptr create_l(); }; /** @@ -195,26 +205,6 @@ private: Frame::Ptr _parent_frame; }; -/** - * 循环池辅助类 - */ -template -class ResourcePoolHelper{ -public: - ResourcePoolHelper(int size = 0){ - if (size > 0) { - _pool.setSize(size); - } - } - virtual ~ResourcePoolHelper(){} - - std::shared_ptr obtainObj(){ - return _pool.obtain(); - } -private: - ResourcePool _pool; -}; - /** * 写帧接口的抽象接口类 */ diff --git a/src/Extension/G711.cpp b/src/Extension/G711.cpp index 9f3e8ec5..da86d5a2 100644 --- a/src/Extension/G711.cpp +++ b/src/Extension/G711.cpp @@ -12,6 +12,47 @@ namespace mediakit{ +/** + * G711类型SDP + */ +class G711Sdp : public Sdp { +public: + /** + * G711采样率固定为8000 + * @param codecId G711A G711U + * @param sample_rate 音频采样率 + * @param payload_type rtp payload + * @param bitrate 比特率 + */ + G711Sdp(CodecId codecId, + int sample_rate, + int channels, + int bitrate = 128, + int payload_type = 98) : Sdp(sample_rate,payload_type), _codecId(codecId){ + _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; + if (bitrate) { + _printer << "b=AS:" << bitrate << "\r\n"; + } + _printer << "a=rtpmap:" << payload_type << (codecId == CodecG711A ? " PCMA/" : " PCMU/") << sample_rate << "/" << channels << "\r\n"; + _printer << "a=control:trackID=" << (int)TrackAudio << "\r\n"; + } + + string getSdp() const override { + return _printer; + } + + CodecId getCodecId() const override { + return _codecId; + } +private: + _StrPrinter _printer; + CodecId _codecId; +}; + +Track::Ptr G711Track::clone() { + return std::make_shared::type>(*this); +} + Sdp::Ptr G711Track::getSdp() { if(!ready()){ WarnL << getCodecName() << " Track未准备好"; diff --git a/src/Extension/G711.h b/src/Extension/G711.h index 69f87764..bcf5f677 100644 --- a/src/Extension/G711.h +++ b/src/Extension/G711.h @@ -21,53 +21,12 @@ namespace mediakit{ */ class G711Track : public AudioTrackImp{ public: - typedef std::shared_ptr Ptr; + using Ptr = std::shared_ptr; G711Track(CodecId codecId,int sample_rate, int channels, int sample_bit) : AudioTrackImp(codecId,sample_rate,channels,sample_bit){} private: - //克隆该Track - Track::Ptr clone() override { - return std::make_shared::type >(*this); - } - //生成sdp - Sdp::Ptr getSdp() override ; -}; - -/** - * G711类型SDP - */ -class G711Sdp : public Sdp { -public: - /** - * G711采样率固定为8000 - * @param codecId G711A G711U - * @param sample_rate 音频采样率 - * @param payload_type rtp payload - * @param bitrate 比特率 - */ - G711Sdp(CodecId codecId, - int sample_rate, - int channels, - int bitrate = 128, - int payload_type = 98) : Sdp(sample_rate,payload_type), _codecId(codecId){ - _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - _printer << "a=rtpmap:" << payload_type << (codecId == CodecG711A ? " PCMA/" : " PCMU/") << sample_rate << "/" << channels << "\r\n"; - _printer << "a=control:trackID=" << (int)TrackAudio << "\r\n"; - } - - string getSdp() const override { - return _printer; - } - - CodecId getCodecId() const override { - return _codecId; - } -private: - _StrPrinter _printer; - CodecId _codecId; + Sdp::Ptr getSdp() override; + Track::Ptr clone() override; }; }//namespace mediakit diff --git a/src/Extension/H264.cpp b/src/Extension/H264.cpp index 7ed5cda2..7a7acd33 100644 --- a/src/Extension/H264.cpp +++ b/src/Extension/H264.cpp @@ -96,6 +96,174 @@ size_t prefixSize(const char *ptr, size_t len){ return 0; } +//////////////////////////////////////////////////////////////////////////////////////////////////// + +H264Track::H264Track(const string &sps,const string &pps,int sps_prefix_len,int pps_prefix_len){ + _sps = sps.substr(sps_prefix_len); + _pps = pps.substr(pps_prefix_len); + onReady(); +} + +H264Track::H264Track(const Frame::Ptr &sps,const Frame::Ptr &pps){ + if(sps->getCodecId() != CodecH264 || pps->getCodecId() != CodecH264 ){ + throw std::invalid_argument("必须输入H264类型的帧"); + } + _sps = string(sps->data() + sps->prefixSize(),sps->size() - sps->prefixSize()); + _pps = string(pps->data() + pps->prefixSize(),pps->size() - pps->prefixSize()); + onReady(); +} + +const string &H264Track::getSps() const{ + return _sps; +} + +const string &H264Track::getPps() const{ + return _pps; +} + +CodecId H264Track::getCodecId() const { + return CodecH264; +} + +int H264Track::getVideoHeight() const { + return _height; +} + +int H264Track::getVideoWidth() const { + return _width; +} + +float H264Track::getVideoFps() const { + return _fps; +} + +bool H264Track::ready() { + return !_sps.empty() && !_pps.empty(); +} + +void H264Track::inputFrame(const Frame::Ptr &frame) { + using H264FrameInternal = FrameInternal; + + int type = H264_TYPE(*((uint8_t *) frame->data() + frame->prefixSize())); + if (type != H264Frame::NAL_B_P && type != H264Frame::NAL_IDR) { + //非I/B/P帧情况下,split一下,防止多个帧粘合在一起 + splitH264(frame->data(), frame->size(), frame->prefixSize(), [&](const char *ptr, size_t len, size_t prefix) { + H264FrameInternal::Ptr sub_frame = std::make_shared(frame, (char *) ptr, len, prefix); + inputFrame_l(sub_frame); + }); + } else { + inputFrame_l(frame); + } +} + +void H264Track::onReady(){ + getAVCInfo(_sps,_width,_height,_fps); +} + +Track::Ptr H264Track::clone() { + return std::make_shared::type >(*this); +} + +void H264Track::inputFrame_l(const Frame::Ptr &frame){ + int type = H264_TYPE(*((uint8_t *) frame->data() + frame->prefixSize())); + switch (type) { + case H264Frame::NAL_SPS: { + _sps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); + break; + } + case H264Frame::NAL_PPS: { + _pps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); + break; + } + case H264Frame::NAL_IDR: { + insertConfigFrame(frame); + VideoTrack::inputFrame(frame); + break; + } + case H264Frame::NAL_AUD: { + //忽略AUD帧; + break; + } + + default: + VideoTrack::inputFrame(frame); + break; + } + + _is_idr = type == H264Frame::NAL_IDR; + if (_width == 0 && ready()) { + onReady(); + } +} + +void H264Track::insertConfigFrame(const Frame::Ptr &frame){ + if(_is_idr){ + return; + } + + if(!_sps.empty()){ + auto spsFrame = FrameImp::create(); + spsFrame->_prefix_size = 4; + spsFrame->_buffer.assign("\x00\x00\x00\x01",4); + spsFrame->_buffer.append(_sps); + spsFrame->_dts = frame->dts(); + VideoTrack::inputFrame(spsFrame); + } + + if(!_pps.empty()){ + auto ppsFrame = FrameImp::create(); + ppsFrame->_prefix_size = 4; + ppsFrame->_buffer.assign("\x00\x00\x00\x01",4); + ppsFrame->_buffer.append(_pps); + ppsFrame->_dts = frame->dts(); + VideoTrack::inputFrame(ppsFrame); + } +} + +class H264Sdp : public Sdp { +public: + H264Sdp(const string &strSPS, const string &strPPS, int bitrate, int payload_type = 96) + : Sdp(90000, payload_type) { + //视频通道 + _printer << "m=video 0 RTP/AVP " << payload_type << "\r\n"; + if (bitrate) { + _printer << "b=AS:" << bitrate << "\r\n"; + } + _printer << "a=rtpmap:" << payload_type << " H264/" << 90000 << "\r\n"; + _printer << "a=fmtp:" << payload_type << " packetization-mode=1; profile-level-id="; + + char strTemp[100]; + uint32_t profile_level_id = 0; + if (strSPS.length() >= 4) { // sanity check + profile_level_id = (uint8_t(strSPS[1]) << 16) | + (uint8_t(strSPS[2]) << 8) | + (uint8_t(strSPS[3])); // profile_idc|constraint_setN_flag|level_idc + } + memset(strTemp, 0, 100); + snprintf(strTemp, sizeof(strTemp), "%06X", profile_level_id); + _printer << strTemp; + _printer << "; sprop-parameter-sets="; + memset(strTemp, 0, 100); + av_base64_encode(strTemp, 100, (uint8_t *) strSPS.data(), (int) strSPS.size()); + _printer << strTemp << ","; + memset(strTemp, 0, 100); + av_base64_encode(strTemp, 100, (uint8_t *) strPPS.data(), (int) strPPS.size()); + _printer << strTemp << "\r\n"; + _printer << "a=control:trackID=" << (int) TrackVideo << "\r\n"; + } + + string getSdp() const { + return _printer; + } + + CodecId getCodecId() const { + return CodecH264; + } + +private: + _StrPrinter _printer; +}; + Sdp::Ptr H264Track::getSdp() { if(!ready()){ WarnL << getCodecName() << " Track未准备好"; @@ -103,6 +271,48 @@ Sdp::Ptr H264Track::getSdp() { } return std::make_shared(getSps(), getPps(), getBitRate() / 1024); } + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +bool H264Frame::keyFrame() const { + return H264_TYPE(_buffer[_prefix_size]) == H264Frame::NAL_IDR; +} + +bool H264Frame::configFrame() const { + switch (H264_TYPE(_buffer[_prefix_size])) { + case H264Frame::NAL_SPS: + case H264Frame::NAL_PPS: return true; + default: return false; + } +} + +H264Frame::H264Frame() { + _codec_id = CodecH264; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +H264FrameNoCacheAble::H264FrameNoCacheAble(char *ptr,size_t size,uint32_t dts , uint32_t pts ,size_t prefix_size){ + _ptr = ptr; + _size = size; + _dts = dts; + _pts = pts; + _prefix_size = prefix_size; + _codec_id = CodecH264; +} + +bool H264FrameNoCacheAble::keyFrame() const { + return H264_TYPE(_ptr[_prefix_size]) == H264Frame::NAL_IDR; +} + +bool H264FrameNoCacheAble::configFrame() const { + switch (H264_TYPE(_ptr[_prefix_size])) { + case H264Frame::NAL_SPS: + case H264Frame::NAL_PPS: return true; + default: return false; + } +} + }//namespace mediakit diff --git a/src/Extension/H264.h b/src/Extension/H264.h index 471dc4cb..395b0ea8 100644 --- a/src/Extension/H264.h +++ b/src/Extension/H264.h @@ -14,45 +14,38 @@ #include "Frame.h" #include "Track.h" #include "Util/base64.h" -using namespace toolkit; #define H264_TYPE(v) ((uint8_t)(v) & 0x1F) +using namespace toolkit; namespace mediakit{ bool getAVCInfo(const string &strSps,int &iVideoWidth, int &iVideoHeight, float &iVideoFps); void splitH264(const char *ptr, size_t len, size_t prefix, const std::function &cb); size_t prefixSize(const char *ptr, size_t len); + /** * 264帧类 */ class H264Frame : public FrameImp { public: - typedef std::shared_ptr Ptr; + using Ptr = std::shared_ptr; - typedef enum { + enum { NAL_IDR = 5, NAL_SEI = 6, NAL_SPS = 7, NAL_PPS = 8, NAL_AUD = 9, NAL_B_P = 1, - } NalType; + }; - H264Frame(){ - _codec_id = CodecH264; - } + bool keyFrame() const override; + bool configFrame() const override; - bool keyFrame() const override { - return H264_TYPE(_buffer[_prefix_size]) == H264Frame::NAL_IDR; - } - - bool configFrame() const override{ - switch(H264_TYPE(_buffer[_prefix_size]) ){ - case H264Frame::NAL_SPS: - case H264Frame::NAL_PPS:return true; - default:return false; - } - } +protected: + friend class FrameImp; + friend class ResourcePool_l; + H264Frame(); }; /** @@ -62,44 +55,26 @@ public: */ class H264FrameNoCacheAble : public FrameFromPtr { public: - typedef std::shared_ptr Ptr; + using Ptr = std::shared_ptr; - H264FrameNoCacheAble(char *ptr,size_t size,uint32_t dts , uint32_t pts ,size_t prefix_size = 4){ - _ptr = ptr; - _size = size; - _dts = dts; - _pts = pts; - _prefix_size = prefix_size; - _codec_id = CodecH264; - } - - bool keyFrame() const override { - return H264_TYPE(_ptr[_prefix_size]) == H264Frame::NAL_IDR; - } - - bool configFrame() const override{ - switch(H264_TYPE(_ptr[_prefix_size])){ - case H264Frame::NAL_SPS: - case H264Frame::NAL_PPS:return true; - default:return false; - } - } + H264FrameNoCacheAble(char *ptr,size_t size,uint32_t dts , uint32_t pts ,size_t prefix_size = 4); + bool keyFrame() const override; + bool configFrame() const override; }; -typedef FrameInternal H264FrameInternal; - /** * 264视频通道 */ class H264Track : public VideoTrack{ public: - typedef std::shared_ptr Ptr; + using Ptr = std::shared_ptr; /** * 不指定sps pps构造h264类型的媒体 * 在随后的inputFrame中获取sps pps */ - H264Track(){} + H264Track() = default; + /** * 构造h264类型的媒体 * @param sps sps帧数据 @@ -107,230 +82,42 @@ public: * @param sps_prefix_len 264头长度,可以为3个或4个字节,一般为0x00 00 00 01 * @param pps_prefix_len 264头长度,可以为3个或4个字节,一般为0x00 00 00 01 */ - H264Track(const string &sps,const string &pps,int sps_prefix_len = 4,int pps_prefix_len = 4){ - _sps = sps.substr(sps_prefix_len); - _pps = pps.substr(pps_prefix_len); - onReady(); - } + H264Track(const string &sps,const string &pps,int sps_prefix_len = 4,int pps_prefix_len = 4); /** * 构造h264类型的媒体 * @param sps sps帧 * @param pps pps帧 */ - H264Track(const Frame::Ptr &sps,const Frame::Ptr &pps){ - if(sps->getCodecId() != CodecH264 || pps->getCodecId() != CodecH264 ){ - throw std::invalid_argument("必须输入H264类型的帧"); - } - _sps = string(sps->data() + sps->prefixSize(),sps->size() - sps->prefixSize()); - _pps = string(pps->data() + pps->prefixSize(),pps->size() - pps->prefixSize()); - onReady(); - } + H264Track(const Frame::Ptr &sps,const Frame::Ptr &pps); /** - * 返回不带0x00 00 00 01头的sps - * @return + * 返回不带0x00 00 00 01头的sps/pps */ - const string &getSps() const{ - return _sps; - } + const string &getSps() const; + const string &getPps() const; - /** - * 返回不带0x00 00 00 01头的pps - * @return - */ - const string &getPps() const{ - return _pps; - } + bool ready() override; + CodecId getCodecId() const override; + int getVideoHeight() const override; + int getVideoWidth() const override; + float getVideoFps() const override; + void inputFrame(const Frame::Ptr &frame) override; - CodecId getCodecId() const override { - return CodecH264; - } - - /** - * 返回视频高度 - * @return - */ - int getVideoHeight() const override{ - return _height ; - } - - /** - * 返回视频宽度 - * @return - */ - int getVideoWidth() const override{ - return _width; - } - - /** - * 返回视频fps - * @return - */ - float getVideoFps() const override{ - return _fps; - } - - bool ready() override { - return !_sps.empty() && !_pps.empty(); - } - - /** - * 输入数据帧,并获取sps pps - * @param frame 数据帧 - */ - void inputFrame(const Frame::Ptr &frame) override{ - int type = H264_TYPE(*((uint8_t *)frame->data() + frame->prefixSize())); - if(type != H264Frame::NAL_B_P && type != H264Frame::NAL_IDR){ - //非I/B/P帧情况下,split一下,防止多个帧粘合在一起 - splitH264(frame->data(), frame->size(), frame->prefixSize(), [&](const char *ptr, size_t len, size_t prefix) { - H264FrameInternal::Ptr sub_frame = std::make_shared(frame, (char *)ptr, len, prefix); - inputFrame_l(sub_frame); - }); - } else{ - inputFrame_l(frame); - } - } private: - /** - * 解析sps获取宽高fps - */ - void onReady(){ - getAVCInfo(_sps,_width,_height,_fps); - } - Track::Ptr clone() override { - return std::make_shared::type >(*this); - } + void onReady(); + Sdp::Ptr getSdp() override; + Track::Ptr clone() override; + void inputFrame_l(const Frame::Ptr &frame); + void insertConfigFrame(const Frame::Ptr &frame); - /** - * 输入数据帧,并获取sps pps - * @param frame 数据帧 - */ - void inputFrame_l(const Frame::Ptr &frame){ - int type = H264_TYPE(*((uint8_t *)frame->data() + frame->prefixSize())); - switch (type){ - case H264Frame::NAL_SPS:{ - //sps - _sps = string(frame->data() + frame->prefixSize(),frame->size() - frame->prefixSize()); - } - break; - case H264Frame::NAL_PPS:{ - //pps - _pps = string(frame->data() + frame->prefixSize(),frame->size() - frame->prefixSize()); - } - break; - - case H264Frame::NAL_IDR:{ - //I - insertConfigFrame(frame); - VideoTrack::inputFrame(frame); - } - break; - case H264Frame::NAL_AUD:{ - //忽略AUD帧; - } - break; - - default: - VideoTrack::inputFrame(frame); - break; - } - - _last_frame_is_idr = type == H264Frame::NAL_IDR; - if(_width == 0 && ready()){ - onReady(); - } - } - - //生成sdp - Sdp::Ptr getSdp() override ; private: - //在idr帧前插入sps pps帧 - void insertConfigFrame(const Frame::Ptr &frame){ - if(_last_frame_is_idr){ - return; - } - - if(!_sps.empty()){ - auto spsFrame = std::make_shared(); - spsFrame->_prefix_size = 4; - spsFrame->_buffer.assign("\x0\x0\x0\x1",4); - spsFrame->_buffer.append(_sps); - spsFrame->_dts = frame->dts(); - VideoTrack::inputFrame(spsFrame); - } - - if(!_pps.empty()){ - auto ppsFrame = std::make_shared(); - ppsFrame->_prefix_size = 4; - ppsFrame->_buffer.assign("\x0\x0\x0\x1",4); - ppsFrame->_buffer.append(_pps); - ppsFrame->_dts = frame->dts(); - VideoTrack::inputFrame(ppsFrame); - } - } -private: - string _sps; - string _pps; + bool _is_idr = false; int _width = 0; int _height = 0; float _fps = 0; - bool _last_frame_is_idr = false; -}; - -/** -* h264类型sdp -*/ -class H264Sdp : public Sdp { -public: - /** - * - * @param sps 264 sps,不带0x00000001头 - * @param pps 264 pps,不带0x00000001头 - * @param payload_type rtp payload type 默认96 - * @param bitrate 比特率 - */ - H264Sdp(const string &strSPS, - const string &strPPS, - int bitrate = 4000, - int payload_type = 96) : Sdp(90000,payload_type) { - //视频通道 - _printer << "m=video 0 RTP/AVP " << payload_type << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - _printer << "a=rtpmap:" << payload_type << " H264/" << 90000 << "\r\n"; - _printer << "a=fmtp:" << payload_type << " packetization-mode=1; profile-level-id="; - - char strTemp[100]; - uint32_t profile_level_id = 0; - if (strSPS.length() >= 4) { // sanity check - profile_level_id = (uint8_t(strSPS[1]) << 16) | - (uint8_t(strSPS[2]) << 8) | - (uint8_t(strSPS[3])); // profile_idc|constraint_setN_flag|level_idc - } - memset(strTemp, 0, 100); - snprintf(strTemp, sizeof(strTemp), "%06X", profile_level_id); - _printer << strTemp; - _printer << "; sprop-parameter-sets="; - memset(strTemp, 0, 100); - av_base64_encode(strTemp, 100, (uint8_t *) strSPS.data(), (int)strSPS.size()); - _printer << strTemp << ","; - memset(strTemp, 0, 100); - av_base64_encode(strTemp, 100, (uint8_t *) strPPS.data(), (int)strPPS.size()); - _printer << strTemp << "\r\n"; - _printer << "a=control:trackID=" << (int)TrackVideo << "\r\n"; - } - - string getSdp() const override { - return _printer; - } - - CodecId getCodecId() const override { - return CodecH264; - } -private: - _StrPrinter _printer; + string _sps; + string _pps; }; }//namespace mediakit diff --git a/src/Extension/H264Rtmp.cpp b/src/Extension/H264Rtmp.cpp index 88e926b2..3cd4d04f 100644 --- a/src/Extension/H264Rtmp.cpp +++ b/src/Extension/H264Rtmp.cpp @@ -15,10 +15,8 @@ H264RtmpDecoder::H264RtmpDecoder() { _h264frame = obtainFrame(); } -H264Frame::Ptr H264RtmpDecoder::obtainFrame() { - //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 - auto frame = obtainObj(); - frame->_buffer.clear(); +H264Frame::Ptr H264RtmpDecoder::obtainFrame() { + auto frame = FrameImp::create(); frame->_prefix_size = 4; return frame; } @@ -124,7 +122,7 @@ inline void H264RtmpDecoder::onGetH264(const char* pcData, size_t iLen, uint32_t #if 1 _h264frame->_dts = dts; _h264frame->_pts = pts; - _h264frame->_buffer.assign("\x0\x0\x0\x1", 4); //添加264头 + _h264frame->_buffer.assign("\x00\x00\x00\x01", 4); //添加264头 _h264frame->_buffer.append(pcData, iLen); //写入环形缓存 diff --git a/src/Extension/H264Rtmp.h b/src/Extension/H264Rtmp.h index cc20d98d..a7c243ca 100644 --- a/src/Extension/H264Rtmp.h +++ b/src/Extension/H264Rtmp.h @@ -22,7 +22,7 @@ namespace mediakit{ * h264 Rtmp解码类 * 将 h264 over rtmp 解复用出 h264-Frame */ -class H264RtmpDecoder : public RtmpCodec ,public ResourcePoolHelper { +class H264RtmpDecoder : public RtmpCodec { public: typedef std::shared_ptr Ptr; diff --git a/src/Extension/H264Rtp.cpp b/src/Extension/H264Rtp.cpp index f9e33fb0..e749fa1b 100644 --- a/src/Extension/H264Rtp.cpp +++ b/src/Extension/H264Rtp.cpp @@ -34,10 +34,8 @@ H264RtpDecoder::H264RtpDecoder() { _h264frame = obtainFrame(); } -H264Frame::Ptr H264RtpDecoder::obtainFrame() { - //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 - auto frame = ResourcePoolHelper::obtainObj(); - frame->_buffer.clear(); +H264Frame::Ptr H264RtpDecoder::obtainFrame() { + auto frame = FrameImp::create(); frame->_prefix_size = 4; return frame; } @@ -81,7 +79,7 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) { if (nal_type >= 0 && nal_type < 24) { //a full frame - _h264frame->_buffer.assign("\x0\x0\x0\x1", 4); + _h264frame->_buffer.assign("\x00\x00\x00\x01", 4); _h264frame->_buffer.append((char *) frame, length); _h264frame->_pts = stamp; auto key = _h264frame->keyFrame(); @@ -108,7 +106,7 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) { } if (len > 0) { //有有效数据 - _h264frame->_buffer.assign("\x0\x0\x0\x1", 4); + _h264frame->_buffer.assign("\x00\x00\x00\x01", 4); _h264frame->_buffer.append((char *) ptr, len); _h264frame->_pts = stamp; if ((ptr[0] & 0x1F) == H264Frame::NAL_IDR) { @@ -127,7 +125,7 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) { MakeFU(frame[1], fu); if (fu.S) { //该帧的第一个rtp包 FU-A start - _h264frame->_buffer.assign("\x0\x0\x0\x1", 4); + _h264frame->_buffer.assign("\x00\x00\x00\x01", 4); _h264frame->_buffer.push_back(nal_suffix | fu.type); _h264frame->_buffer.append((char *) frame + 2, length - 2); _h264frame->_pts = stamp; diff --git a/src/Extension/H264Rtp.h b/src/Extension/H264Rtp.h index 51b9aaaf..303c77a5 100644 --- a/src/Extension/H264Rtp.h +++ b/src/Extension/H264Rtp.h @@ -24,7 +24,7 @@ namespace mediakit{ * 将 h264 over rtsp-rtp 解复用出 h264-Frame * rfc3984 */ -class H264RtpDecoder : public RtpCodec , public ResourcePoolHelper { +class H264RtpDecoder : public RtpCodec{ public: typedef std::shared_ptr Ptr; diff --git a/src/Extension/H265.cpp b/src/Extension/H265.cpp index 179b09d8..db670bc5 100644 --- a/src/Extension/H265.cpp +++ b/src/Extension/H265.cpp @@ -10,7 +10,6 @@ #include "H265.h" #include "SPSParser.h" -#include "Util/logger.h" namespace mediakit{ @@ -42,7 +41,6 @@ bool getHEVCInfo(const char * vps, size_t vps_len,const char * sps,size_t sps_le h265GetWidthHeight(&tH265SpsInfo, &iVideoWidth, &iVideoHeight); iVideoFps = 0; h265GeFramerate(&tH265VpsInfo, &tH265SpsInfo, &iVideoFps); -// ErrorL << iVideoWidth << " " << iVideoHeight << " " << iVideoFps; return true; } @@ -50,6 +48,228 @@ bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, i return getHEVCInfo(strVps.data(), strVps.size(), strSps.data(), strSps.size(), iVideoWidth, iVideoHeight,iVideoFps); } +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bool H265Frame::keyFrame() const { + return isKeyFrame(H265_TYPE(_buffer[_prefix_size])); +} + +bool H265Frame::configFrame() const { + switch (H265_TYPE(_buffer[_prefix_size])) { + case H265Frame::NAL_VPS: + case H265Frame::NAL_SPS: + case H265Frame::NAL_PPS : return true; + default : return false; + } +} + +bool H265Frame::isKeyFrame(int type) { + return type >= NAL_BLA_W_LP && type <= NAL_RSV_IRAP_VCL23; +} + +H265Frame::H265Frame(){ + _codec_id = CodecH265; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +H265FrameNoCacheAble::H265FrameNoCacheAble(char *ptr, size_t size, uint32_t dts, uint32_t pts, size_t prefix_size) { + _ptr = ptr; + _size = size; + _dts = dts; + _pts = pts; + _prefix_size = prefix_size; + _codec_id = CodecH265; +} + +bool H265FrameNoCacheAble::keyFrame() const { + return H265Frame::isKeyFrame(H265_TYPE(((uint8_t *) _ptr)[_prefix_size])); +} + +bool H265FrameNoCacheAble::configFrame() const { + switch (H265_TYPE(((uint8_t *) _ptr)[_prefix_size])) { + case H265Frame::NAL_VPS: + case H265Frame::NAL_SPS: + case H265Frame::NAL_PPS: return true; + default: return false; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +H265Track::H265Track(const string &vps,const string &sps, const string &pps,int vps_prefix_len, int sps_prefix_len, int pps_prefix_len) { + _vps = vps.substr(vps_prefix_len); + _sps = sps.substr(sps_prefix_len); + _pps = pps.substr(pps_prefix_len); + onReady(); +} + +const string &H265Track::getVps() const { + return _vps; +} + +const string &H265Track::getSps() const { + return _sps; +} + +const string &H265Track::getPps() const { + return _pps; +} + +CodecId H265Track::getCodecId() const { + return CodecH265; +} + +int H265Track::getVideoHeight() const { + return _height; +} + +int H265Track::getVideoWidth() const { + return _width; +} + +float H265Track::getVideoFps() const { + return _fps; +} + +bool H265Track::ready() { + return !_vps.empty() && !_sps.empty() && !_pps.empty(); +} + +void H265Track::inputFrame(const Frame::Ptr &frame) { + using H265FrameInternal = FrameInternal; + + int type = H265_TYPE(*((uint8_t *) frame->data() + frame->prefixSize())); + if (frame->configFrame() || type == H265Frame::NAL_SEI_PREFIX) { + splitH264(frame->data(), frame->size(), frame->prefixSize(), [&](const char *ptr, size_t len, size_t prefix) { + H265FrameInternal::Ptr sub_frame = std::make_shared(frame, (char *) ptr, len, prefix); + inputFrame_l(sub_frame); + }); + } else { + inputFrame_l(frame); + } +} + +void H265Track::inputFrame_l(const Frame::Ptr &frame) { + int type = H265_TYPE(((uint8_t *) frame->data() + frame->prefixSize())[0]); + if (H265Frame::isKeyFrame(type)) { + insertConfigFrame(frame); + VideoTrack::inputFrame(frame); + _is_idr = true; + return; + } + + _is_idr = false; + + //非idr帧 + switch (type) { + case H265Frame::NAL_VPS: { + _vps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); + break; + } + case H265Frame::NAL_SPS: { + _sps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); + break; + } + case H265Frame::NAL_PPS: { + _pps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); + break; + } + default: { + VideoTrack::inputFrame(frame); + break; + } + } + if (_width == 0 && ready()) { + onReady(); + } +} + +void H265Track::onReady() { + getHEVCInfo(_vps, _sps, _width, _height, _fps); +} + +Track::Ptr H265Track::clone() { + return std::make_shared::type>(*this); +} + +void H265Track::insertConfigFrame(const Frame::Ptr &frame) { + if (_is_idr) { + return; + } + if (!_vps.empty()) { + auto vpsFrame = FrameImp::create(); + vpsFrame->_prefix_size = 4; + vpsFrame->_buffer.assign("\x00\x00\x00\x01", 4); + vpsFrame->_buffer.append(_vps); + vpsFrame->_dts = frame->dts(); + VideoTrack::inputFrame(vpsFrame); + } + if (!_sps.empty()) { + auto spsFrame = FrameImp::create(); + spsFrame->_prefix_size = 4; + spsFrame->_buffer.assign("\x00\x00\x00\x01", 4); + spsFrame->_buffer.append(_sps); + spsFrame->_dts = frame->dts(); + VideoTrack::inputFrame(spsFrame); + } + + if (!_pps.empty()) { + auto ppsFrame = FrameImp::create(); + ppsFrame->_prefix_size = 4; + ppsFrame->_buffer.assign("\x00\x00\x00\x01", 4); + ppsFrame->_buffer.append(_pps); + ppsFrame->_dts = frame->dts(); + VideoTrack::inputFrame(ppsFrame); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * h265类型sdp + */ +class H265Sdp : public Sdp { +public: + /** + * 构造函数 + * @param sps 265 sps,不带0x00000001头 + * @param pps 265 pps,不带0x00000001头 + * @param payload_type rtp payload type 默认96 + * @param bitrate 比特率 + */ + H265Sdp(const string &strVPS, + const string &strSPS, + const string &strPPS, + int bitrate = 4000, + int payload_type = 96) : Sdp(90000,payload_type) { + //视频通道 + _printer << "m=video 0 RTP/AVP " << payload_type << "\r\n"; + if (bitrate) { + _printer << "b=AS:" << bitrate << "\r\n"; + } + _printer << "a=rtpmap:" << payload_type << " H265/" << 90000 << "\r\n"; + _printer << "a=fmtp:" << payload_type << " "; + _printer << "sprop-vps="; + _printer << encodeBase64(strVPS) << "; "; + _printer << "sprop-sps="; + _printer << encodeBase64(strSPS) << "; "; + _printer << "sprop-pps="; + _printer << encodeBase64(strPPS) << "\r\n"; + _printer << "a=control:trackID=" << (int)TrackVideo << "\r\n"; + } + + string getSdp() const override { + return _printer; + } + + CodecId getCodecId() const override { + return CodecH265; + } +private: + _StrPrinter _printer; +}; + Sdp::Ptr H265Track::getSdp() { if(!ready()){ WarnL << getCodecName() << " Track未准备好"; @@ -57,5 +277,6 @@ Sdp::Ptr H265Track::getSdp() { } return std::make_shared(getVps(), getSps(), getPps(), getBitRate() / 1024); } + }//namespace mediakit diff --git a/src/Extension/H265.h b/src/Extension/H265.h index 1f94e06e..c9dc671a 100644 --- a/src/Extension/H265.h +++ b/src/Extension/H265.h @@ -15,8 +15,8 @@ #include "Track.h" #include "Util/base64.h" #include "H264.h" -using namespace toolkit; #define H265_TYPE(v) (((uint8_t)(v) >> 1) & 0x3f) +using namespace toolkit; namespace mediakit { @@ -27,9 +27,8 @@ bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, i */ class H265Frame : public FrameImp { public: - typedef std::shared_ptr Ptr; - - typedef enum { + using Ptr = std::shared_ptr; + enum { NAL_TRAIL_N = 0, NAL_TRAIL_R = 1, NAL_TSA_N = 2, @@ -58,71 +57,39 @@ public: NAL_FD_NUT = 38, NAL_SEI_PREFIX = 39, NAL_SEI_SUFFIX = 40, - } NaleType; + }; - H265Frame(){ - _codec_id = CodecH265; - } + bool keyFrame() const override; + bool configFrame() const override; + static bool isKeyFrame(int type); - bool keyFrame() const override { - return isKeyFrame(H265_TYPE(_buffer[_prefix_size])); - } - - bool configFrame() const override{ - switch(H265_TYPE(_buffer[_prefix_size])){ - case H265Frame::NAL_VPS: - case H265Frame::NAL_SPS: - case H265Frame::NAL_PPS : return true; - default : return false; - } - } - - static bool isKeyFrame(int type) { - return type >= NAL_BLA_W_LP && type <= NAL_RSV_IRAP_VCL23; - } +protected: + friend class FrameImp; + friend class ResourcePool_l; + H265Frame(); }; class H265FrameNoCacheAble : public FrameFromPtr { public: - typedef std::shared_ptr Ptr; + using Ptr = std::shared_ptr; - H265FrameNoCacheAble(char *ptr, size_t size, uint32_t dts,uint32_t pts, size_t prefix_size = 4) { - _ptr = ptr; - _size = size; - _dts = dts; - _pts = pts; - _prefix_size = prefix_size; - _codec_id = CodecH265; - } - - bool keyFrame() const override { - return H265Frame::isKeyFrame(H265_TYPE(((uint8_t *) _ptr)[_prefix_size])); - } - - bool configFrame() const override{ - switch(H265_TYPE(((uint8_t *) _ptr)[_prefix_size])){ - case H265Frame::NAL_VPS: - case H265Frame::NAL_SPS: - case H265Frame::NAL_PPS:return true; - default:return false; - } - } + H265FrameNoCacheAble(char *ptr, size_t size, uint32_t dts,uint32_t pts, size_t prefix_size = 4); + bool keyFrame() const override; + bool configFrame() const override; }; -typedef FrameInternal H265FrameInternal; - /** * 265视频通道 */ class H265Track : public VideoTrack { public: - typedef std::shared_ptr Ptr; + using Ptr = std::shared_ptr; /** * 不指定sps pps构造h265类型的媒体 * 在随后的inputFrame中获取sps pps */ - H265Track() {} + H265Track() = default; /** * 构造h265类型的媒体 @@ -133,221 +100,37 @@ public: * @param sps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01 * @param pps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01 */ - H265Track(const string &vps,const string &sps, const string &pps,int vps_prefix_len = 4, int sps_prefix_len = 4, int pps_prefix_len = 4) { - _vps = vps.substr(vps_prefix_len); - _sps = sps.substr(sps_prefix_len); - _pps = pps.substr(pps_prefix_len); - onReady(); - } + H265Track(const string &vps,const string &sps, const string &pps,int vps_prefix_len = 4, int sps_prefix_len = 4, int pps_prefix_len = 4); /** - * 返回不带0x00 00 00 01头的vps + * 返回不带0x00 00 00 01头的vps/sps/pps */ - const string &getVps() const { - return _vps; - } + const string &getVps() const; + const string &getSps() const; + const string &getPps() const; - /** - * 返回不带0x00 00 00 01头的sps - */ - const string &getSps() const { - return _sps; - } - - /** - * 返回不带0x00 00 00 01头的pps - */ - const string &getPps() const { - return _pps; - } - - CodecId getCodecId() const override { - return CodecH265; - } - - /** - * 返回视频高度 - */ - int getVideoHeight() const override{ - return _height ; - } - - /** - * 返回视频宽度 - */ - int getVideoWidth() const override{ - return _width; - } - - /** - * 返回视频fps - */ - float getVideoFps() const override{ - return _fps; - } - - bool ready() override { - return !_vps.empty() && !_sps.empty() && !_pps.empty(); - } - - /** - * 输入数据帧,并获取sps pps - * @param frame 数据帧 - */ - void inputFrame(const Frame::Ptr &frame) override{ - int type = H265_TYPE(*((uint8_t *)frame->data() + frame->prefixSize())); - if(frame->configFrame() || type == H265Frame::NAL_SEI_PREFIX){ - splitH264(frame->data(), frame->size(), frame->prefixSize(), [&](const char *ptr, size_t len, size_t prefix){ - H265FrameInternal::Ptr sub_frame = std::make_shared(frame, (char*)ptr, len, prefix); - inputFrame_l(sub_frame); - }); - } else { - inputFrame_l(frame); - } - } + bool ready() override; + CodecId getCodecId() const override; + int getVideoWidth() const override; + int getVideoHeight() const override; + float getVideoFps() const override; + void inputFrame(const Frame::Ptr &frame) override; private: - /** - * 输入数据帧,并获取sps pps - * @param frame 数据帧 - */ - void inputFrame_l(const Frame::Ptr &frame) { - int type = H265_TYPE(((uint8_t *) frame->data() + frame->prefixSize())[0]); - if (H265Frame::isKeyFrame(type)) { - insertConfigFrame(frame); - VideoTrack::inputFrame(frame); - _last_frame_is_idr = true; - return; - } + void onReady(); + Sdp::Ptr getSdp() override; + Track::Ptr clone() override; + void inputFrame_l(const Frame::Ptr &frame); + void insertConfigFrame(const Frame::Ptr &frame); - _last_frame_is_idr = false; - - //非idr帧 - switch (type) { - case H265Frame::NAL_VPS: { - //vps - _vps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); - } - break; - - case H265Frame::NAL_SPS: { - //sps - _sps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); - } - break; - case H265Frame::NAL_PPS: { - //pps - _pps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); - } - break; - - default: { - //other frames - VideoTrack::inputFrame(frame); - } - break; - } - if (_width == 0 && ready()) { - onReady(); - } - } - - /** - * 解析sps获取宽高fps - */ - void onReady(){ - getHEVCInfo(_vps, _sps, _width, _height, _fps); - } - Track::Ptr clone() override { - return std::make_shared::type>(*this); - } - - //生成sdp - Sdp::Ptr getSdp() override ; - - //在idr帧前插入vps sps pps帧 - void insertConfigFrame(const Frame::Ptr &frame){ - if(_last_frame_is_idr){ - return; - } - if(!_vps.empty()){ - auto vpsFrame = std::make_shared(); - vpsFrame->_prefix_size = 4; - vpsFrame->_buffer.assign("\x0\x0\x0\x1", 4); - vpsFrame->_buffer.append(_vps); - vpsFrame->_dts = frame->dts(); - VideoTrack::inputFrame(vpsFrame); - } - if (!_sps.empty()) { - auto spsFrame = std::make_shared(); - spsFrame->_prefix_size = 4; - spsFrame->_buffer.assign("\x0\x0\x0\x1", 4); - spsFrame->_buffer.append(_sps); - spsFrame->_dts = frame->dts(); - VideoTrack::inputFrame(spsFrame); - } - - if (!_pps.empty()) { - auto ppsFrame = std::make_shared(); - ppsFrame->_prefix_size = 4; - ppsFrame->_buffer.assign("\x0\x0\x0\x1", 4); - ppsFrame->_buffer.append(_pps); - ppsFrame->_dts = frame->dts(); - VideoTrack::inputFrame(ppsFrame); - } - } private: + bool _is_idr = false; + int _width = 0; + int _height = 0; + float _fps = 0; string _vps; string _sps; string _pps; - int _width = 0; - int _height = 0; - float _fps = 0; - bool _last_frame_is_idr = false; -}; - -/** -* h265类型sdp -*/ -class H265Sdp : public Sdp { -public: - /** - * 构造函数 - * @param sps 265 sps,不带0x00000001头 - * @param pps 265 pps,不带0x00000001头 - * @param payload_type rtp payload type 默认96 - * @param bitrate 比特率 - */ - H265Sdp(const string &strVPS, - const string &strSPS, - const string &strPPS, - int bitrate = 4000, - int payload_type = 96) : Sdp(90000,payload_type) { - //视频通道 - _printer << "m=video 0 RTP/AVP " << payload_type << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - _printer << "a=rtpmap:" << payload_type << " H265/" << 90000 << "\r\n"; - _printer << "a=fmtp:" << payload_type << " "; - _printer << "sprop-vps="; - _printer << encodeBase64(strVPS) << "; "; - _printer << "sprop-sps="; - _printer << encodeBase64(strSPS) << "; "; - _printer << "sprop-pps="; - _printer << encodeBase64(strPPS) << "\r\n"; - _printer << "a=control:trackID=" << (int)TrackVideo << "\r\n"; - } - - string getSdp() const override { - return _printer; - } - - CodecId getCodecId() const override { - return CodecH265; - } -private: - _StrPrinter _printer; }; }//namespace mediakit diff --git a/src/Extension/H265Rtmp.cpp b/src/Extension/H265Rtmp.cpp index 38842fe7..b3ae4fa9 100644 --- a/src/Extension/H265Rtmp.cpp +++ b/src/Extension/H265Rtmp.cpp @@ -19,10 +19,8 @@ H265RtmpDecoder::H265RtmpDecoder() { _h265frame = obtainFrame(); } -H265Frame::Ptr H265RtmpDecoder::obtainFrame() { - //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 - auto frame = obtainObj(); - frame->_buffer.clear(); +H265Frame::Ptr H265RtmpDecoder::obtainFrame() { + auto frame = FrameImp::create(); frame->_prefix_size = 4; return frame; } @@ -102,7 +100,7 @@ inline void H265RtmpDecoder::onGetH265(const char* pcData, size_t iLen, uint32_t #if 1 _h265frame->_dts = dts; _h265frame->_pts = pts; - _h265frame->_buffer.assign("\x0\x0\x0\x1", 4); //添加265头 + _h265frame->_buffer.assign("\x00\x00\x00\x01", 4); //添加265头 _h265frame->_buffer.append(pcData, iLen); //写入环形缓存 diff --git a/src/Extension/H265Rtmp.h b/src/Extension/H265Rtmp.h index 59ba842f..e4f97a08 100644 --- a/src/Extension/H265Rtmp.h +++ b/src/Extension/H265Rtmp.h @@ -22,7 +22,7 @@ namespace mediakit{ * h265 Rtmp解码类 * 将 h265 over rtmp 解复用出 h265-Frame */ -class H265RtmpDecoder : public RtmpCodec ,public ResourcePoolHelper { +class H265RtmpDecoder : public RtmpCodec { public: typedef std::shared_ptr Ptr; diff --git a/src/Extension/H265Rtp.cpp b/src/Extension/H265Rtp.cpp index 82e0142e..262ba347 100644 --- a/src/Extension/H265Rtp.cpp +++ b/src/Extension/H265Rtp.cpp @@ -29,10 +29,8 @@ H265RtpDecoder::H265RtpDecoder() { _frame = obtainFrame(); } -H265Frame::Ptr H265RtpDecoder::obtainFrame() { - //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 - auto frame = ResourcePoolHelper::obtainObj(); - frame->_buffer.clear(); +H265Frame::Ptr H265RtpDecoder::obtainFrame() { + auto frame = FrameImp::create(); frame->_prefix_size = 4; return frame; } diff --git a/src/Extension/H265Rtp.h b/src/Extension/H265Rtp.h index dec81dfe..4bbacea0 100644 --- a/src/Extension/H265Rtp.h +++ b/src/Extension/H265Rtp.h @@ -25,7 +25,7 @@ namespace mediakit{ * 将 h265 over rtsp-rtp 解复用出 h265-Frame * 《草案(H265-over-RTP)draft-ietf-payload-rtp-h265-07.pdf》 */ -class H265RtpDecoder : public RtpCodec , public ResourcePoolHelper { +class H265RtpDecoder : public RtpCodec { public: typedef std::shared_ptr Ptr; diff --git a/src/Extension/L16.cpp b/src/Extension/L16.cpp index 1ae5f265..e6c778ac 100644 --- a/src/Extension/L16.cpp +++ b/src/Extension/L16.cpp @@ -12,6 +12,43 @@ namespace mediakit{ +/** + * L16类型SDP + */ +class L16Sdp : public Sdp { +public: + /** + * L16采样位数固定为16位 + * @param codecId CodecL16 + * @param sample_rate 音频采样率 + * @param payload_type rtp payload + * @param bitrate 比特率 + */ + L16Sdp(CodecId codecId, + int sample_rate, + int channels, + int bitrate = 128, + int payload_type = 98) : Sdp(sample_rate,payload_type), _codecId(codecId){ + _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; + if (bitrate) { + _printer << "b=AS:" << bitrate << "\r\n"; + } + _printer << "a=rtpmap:" << payload_type << " L16/" << sample_rate << "/" << channels << "\r\n"; + _printer << "a=control:trackID=" << (int)TrackAudio << "\r\n"; + } + + string getSdp() const override { + return _printer; + } + + CodecId getCodecId() const override { + return _codecId; + } +private: + _StrPrinter _printer; + CodecId _codecId; +}; + Sdp::Ptr L16Track::getSdp() { WarnL << "Enter L16Track::getSdp function"; if(!ready()){ @@ -21,6 +58,10 @@ Sdp::Ptr L16Track::getSdp() { return std::make_shared(getCodecId(), getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024); } +Track::Ptr L16Track::clone() { + return std::make_shared::type >(*this); +} + }//namespace mediakit diff --git a/src/Extension/L16.h b/src/Extension/L16.h index ed19f6dd..ca58ab8f 100644 --- a/src/Extension/L16.h +++ b/src/Extension/L16.h @@ -21,53 +21,12 @@ namespace mediakit{ */ class L16Track : public AudioTrackImp{ public: - typedef std::shared_ptr Ptr; + using Ptr = std::shared_ptr; L16Track(int sample_rate, int channels) : AudioTrackImp(CodecL16,sample_rate,channels,16){} private: - //克隆该Track - Track::Ptr clone() override { - return std::make_shared::type >(*this); - } - //生成sdp - Sdp::Ptr getSdp() override ; -}; - -/** - * L16类型SDP - */ -class L16Sdp : public Sdp { -public: - /** - * L16采样位数固定为16位 - * @param codecId CodecL16 - * @param sample_rate 音频采样率 - * @param payload_type rtp payload - * @param bitrate 比特率 - */ - L16Sdp(CodecId codecId, - int sample_rate, - int channels, - int bitrate = 128, - int payload_type = 98) : Sdp(sample_rate,payload_type), _codecId(codecId){ - _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - _printer << "a=rtpmap:" << payload_type << " L16/" << sample_rate << "/" << channels << "\r\n"; - _printer << "a=control:trackID=" << (int)TrackAudio << "\r\n"; - } - - string getSdp() const override { - return _printer; - } - - CodecId getCodecId() const override { - return _codecId; - } -private: - _StrPrinter _printer; - CodecId _codecId; + Sdp::Ptr getSdp() override; + Track::Ptr clone() override; }; }//namespace mediakit diff --git a/src/Extension/Opus.cpp b/src/Extension/Opus.cpp index 64777d28..275354cb 100644 --- a/src/Extension/Opus.cpp +++ b/src/Extension/Opus.cpp @@ -12,6 +12,40 @@ namespace mediakit{ +/** + * Opus类型SDP + */ +class OpusSdp : public Sdp { +public: + /** + * 构造opus sdp + * @param sample_rate 音频采样率 + * @param payload_type rtp payload + * @param bitrate 比特率 + */ + OpusSdp(int sample_rate, + int channels, + int bitrate = 128, + int payload_type = 98) : Sdp(sample_rate,payload_type){ + _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; + if (bitrate) { + _printer << "b=AS:" << bitrate << "\r\n"; + } + _printer << "a=rtpmap:" << payload_type << " opus/" << sample_rate << "/" << channels << "\r\n"; + _printer << "a=control:trackID=" << (int)TrackAudio << "\r\n"; + } + + string getSdp() const override { + return _printer; + } + + CodecId getCodecId() const override { + return CodecOpus; + } +private: + _StrPrinter _printer; +}; + Sdp::Ptr OpusTrack::getSdp() { if(!ready()){ WarnL << getCodecName() << " Track未准备好"; diff --git a/src/Extension/Opus.h b/src/Extension/Opus.h index 382ee8c8..88b19a1a 100644 --- a/src/Extension/Opus.h +++ b/src/Extension/Opus.h @@ -33,39 +33,5 @@ private: Sdp::Ptr getSdp() override ; }; -/** - * Opus类型SDP - */ -class OpusSdp : public Sdp { -public: - /** - * 构造opus sdp - * @param sample_rate 音频采样率 - * @param payload_type rtp payload - * @param bitrate 比特率 - */ - OpusSdp(int sample_rate, - int channels, - int bitrate = 128, - int payload_type = 98) : Sdp(sample_rate,payload_type){ - _printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n"; - if (bitrate) { - _printer << "b=AS:" << bitrate << "\r\n"; - } - _printer << "a=rtpmap:" << payload_type << " opus/" << sample_rate << "/" << channels << "\r\n"; - _printer << "a=control:trackID=" << (int)TrackAudio << "\r\n"; - } - - string getSdp() const override { - return _printer; - } - - CodecId getCodecId() const override { - return CodecOpus; - } -private: - _StrPrinter _printer; -}; - }//namespace mediakit #endif //ZLMEDIAKIT_OPUS_H diff --git a/src/Record/MP4Demuxer.cpp b/src/Record/MP4Demuxer.cpp index 1b38dac2..f44265f4 100644 --- a/src/Record/MP4Demuxer.cpp +++ b/src/Record/MP4Demuxer.cpp @@ -221,7 +221,7 @@ Frame::Ptr MP4Demuxer::makeFrame(uint32_t track_id, const Buffer::Ptr &buf, int6 if (frame_len + offset + 4 > bytes) { return nullptr; } - memcpy(data + offset, "\x0\x0\x0\x1", 4); + memcpy(data + offset, "\x00\x00\x00\x01", 4); offset += (frame_len + 4); } if (codec == CodecH264) { diff --git a/src/Rtmp/Rtmp.cpp b/src/Rtmp/Rtmp.cpp index 4be4f77d..272e1c91 100644 --- a/src/Rtmp/Rtmp.cpp +++ b/src/Rtmp/Rtmp.cpp @@ -142,9 +142,7 @@ RtmpPacket::Ptr RtmpPacket::create(){ ret->clear(); return ret; #else - auto ret = Ptr(new RtmpPacket); - ret->clear(); - return ret; + return Ptr(new RtmpPacket); #endif }