优化frame性能及整理代码

This commit is contained in:
xia-chu 2021-02-05 11:51:16 +08:00
parent c5cfbce241
commit 62ba87dd0f
33 changed files with 847 additions and 855 deletions

View File

@ -87,7 +87,7 @@ void DevChannel::inputH264(const char *data, int len, uint32_t dts, uint32_t pts
//由于rtmp/hls/mp4需要缓存时间戳相同的帧 //由于rtmp/hls/mp4需要缓存时间戳相同的帧
//所以使用FrameNoCacheAble类型的帧反而会在转换成FrameCacheAble时多次内存拷贝 //所以使用FrameNoCacheAble类型的帧反而会在转换成FrameCacheAble时多次内存拷贝
//在此处只拷贝一次,性能开销更低 //在此处只拷贝一次,性能开销更低
H264Frame::Ptr frame = std::make_shared<H264Frame>(); auto frame = FrameImp::create<H264Frame>();
frame->_dts = dts; frame->_dts = dts;
frame->_pts = pts; frame->_pts = pts;
frame->_buffer.assign(data, len); 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需要缓存时间戳相同的帧 //由于rtmp/hls/mp4需要缓存时间戳相同的帧
//所以使用FrameNoCacheAble类型的帧反而会在转换成FrameCacheAble时多次内存拷贝 //所以使用FrameNoCacheAble类型的帧反而会在转换成FrameCacheAble时多次内存拷贝
//在此处只拷贝一次,性能开销更低 //在此处只拷贝一次,性能开销更低
H265Frame::Ptr frame = std::make_shared<H265Frame>(); auto frame = FrameImp::create<H265Frame>();
frame->_dts = dts; frame->_dts = dts;
frame->_pts = pts; frame->_pts = pts;
frame->_buffer.assign(data, len); frame->_buffer.assign(data, len);

View File

@ -182,6 +182,136 @@ bool parseAacConfig(const string &config, int &samplerate, int &channels){
#endif #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<FrameInternal<FrameFromPtr> >(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<std::remove_reference<decltype(*this)>::type>(*this);
}
Sdp::Ptr AACTrack::getSdp() { Sdp::Ptr AACTrack::getSdp() {
if(!ready()){ if(!ready()){
WarnL << getCodecName() << " Track未准备好"; WarnL << getCodecName() << " Track未准备好";

View File

@ -27,184 +27,43 @@ bool parseAacConfig(const string &config, int &samplerate, int &channels);
*/ */
class AACTrack : public AudioTrack{ class AACTrack : public AudioTrack{
public: public:
typedef std::shared_ptr<AACTrack> Ptr; using Ptr = std::shared_ptr<AACTrack>;
/** /**
* adts头信息 * adts头信息
* inputFrame中获取adts头信息 * inputFrame中获取adts头信息
*/ */
AACTrack(){} AACTrack() = default;
/** /**
* aac类型的媒体 * aac类型的媒体
* @param aac_cfg aac配置信息 * @param aac_cfg aac配置信息
*/ */
AACTrack(const string &aac_cfg){ 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();
}
/** /**
* aac * aac
*/ */
const string &getAacCfg() const{ const string &getAacCfg() const;
return _cfg;
}
/** bool ready() override;
* CodecId getCodecId() const override;
*/ int getAudioChannel() const override;
CodecId getCodecId() const override{ int getAudioSampleRate() const override;
return CodecAAC; int getAudioSampleBit() const override;
} void inputFrame(const Frame::Ptr &frame) override;
/**
* aac_cfg前是无效的Track
*/
bool ready() override {
return !_cfg.empty();
}
/**
*
*/
int getAudioSampleRate() const override{
return _sampleRate;
}
/**
* 168
*/
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<FrameInternal<FrameFromPtr> >(frame, (char *) ptr, frame_len, ADTS_HEADER_LEN);
ptr += frame_len;
sub_frame->setCodecId(CodecAAC);
inputFrame_l(sub_frame);
}
} else {
inputFrame_l(frame);
}
}
private: private:
void inputFrame_l(const Frame::Ptr &frame) { void onReady();
if (_cfg.empty()) { Sdp::Ptr getSdp() override;
//未获取到aac_cfg信息 Track::Ptr clone() override;
if (frame->prefixSize()) { void inputFrame_l(const Frame::Ptr &frame);
//根据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);
}
}
/**
* 2aac配置
*/
void onReady(){
if (_cfg.size() < 2) {
return;
}
parseAacConfig(_cfg, _sampleRate, _channel);
}
Track::Ptr clone() override {
return std::make_shared<std::remove_reference<decltype(*this)>::type >(*this);
}
//生成sdp
Sdp::Ptr getSdp() override ;
private: private:
string _cfg; string _cfg;
int _channel = 0;
int _sampleRate = 0; int _sampleRate = 0;
int _sampleBit = 16; 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 }//namespace mediakit

View File

@ -42,7 +42,7 @@ void AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
} }
void AACRtmpDecoder::onGetAAC(const char* data, size_t len, uint32_t stamp) { void AACRtmpDecoder::onGetAAC(const char* data, size_t len, uint32_t stamp) {
auto frame = ResourcePoolHelper<FrameImp>::obtainObj(); auto frame = FrameImp::create();
frame->_codec_id = CodecAAC; frame->_codec_id = CodecAAC;
//生成adts头 //生成adts头

View File

@ -19,7 +19,7 @@ namespace mediakit{
/** /**
* aac Rtmp转adts类 * aac Rtmp转adts类
*/ */
class AACRtmpDecoder : public RtmpCodec , public ResourcePoolHelper<FrameImp> { class AACRtmpDecoder : public RtmpCodec{
public: public:
typedef std::shared_ptr<AACRtmpDecoder> Ptr; typedef std::shared_ptr<AACRtmpDecoder> Ptr;

View File

@ -74,9 +74,7 @@ AACRtpDecoder::AACRtpDecoder() {
void AACRtpDecoder::obtainFrame() { void AACRtpDecoder::obtainFrame() {
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
_frame = ResourcePoolHelper<FrameImp>::obtainObj(); _frame = FrameImp::create();
_frame->_prefix_size = 0;
_frame->_buffer.clear();
_frame->_codec_id = CodecAAC; _frame->_codec_id = CodecAAC;
} }

View File

@ -17,7 +17,7 @@ namespace mediakit{
/** /**
* aac rtp转adts类 * aac rtp转adts类
*/ */
class AACRtpDecoder : public RtpCodec , public ResourcePoolHelper<FrameImp> { class AACRtpDecoder : public RtpCodec {
public: public:
typedef std::shared_ptr<AACRtpDecoder> Ptr; typedef std::shared_ptr<AACRtpDecoder> Ptr;

View File

@ -22,11 +22,8 @@ CodecId CommonRtmpDecoder::getCodecId() const {
} }
void CommonRtmpDecoder::obtainFrame() { void CommonRtmpDecoder::obtainFrame() {
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 _frame = FrameImp::create();
_frame = ResourcePoolHelper<FrameImp>::obtainObj();
_frame->_buffer.clear();
_frame->_codec_id = _codec; _frame->_codec_id = _codec;
_frame->_prefix_size = 0;
} }
void CommonRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &rtmp) { void CommonRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &rtmp) {

View File

@ -19,7 +19,7 @@ namespace mediakit{
/** /**
* rtmp解码类 * rtmp解码类
*/ */
class CommonRtmpDecoder : public RtmpCodec , public ResourcePoolHelper<FrameImp> { class CommonRtmpDecoder : public RtmpCodec {
public: public:
typedef std::shared_ptr<CommonRtmpDecoder> Ptr; typedef std::shared_ptr<CommonRtmpDecoder> Ptr;

View File

@ -21,10 +21,7 @@ CodecId CommonRtpDecoder::getCodecId() const {
} }
void CommonRtpDecoder::obtainFrame() { void CommonRtpDecoder::obtainFrame() {
_frame = ResourcePoolHelper<FrameImp>::obtainObj(); _frame = FrameImp::create();
_frame->_buffer.clear();
_frame->_prefix_size = 0;
_frame->_dts = 0;
_frame->_codec_id = _codec; _frame->_codec_id = _codec;
} }

View File

@ -19,7 +19,7 @@ namespace mediakit{
/** /**
* rtp解码类 * rtp解码类
*/ */
class CommonRtpDecoder : public RtpCodec, public ResourcePoolHelper<FrameImp> { class CommonRtpDecoder : public RtpCodec {
public: public:
typedef std::shared_ptr <CommonRtpDecoder> Ptr; typedef std::shared_ptr <CommonRtpDecoder> Ptr;

View File

@ -9,6 +9,8 @@
*/ */
#include "Frame.h" #include "Frame.h"
#include "H264.h"
#include "H265.h"
using namespace std; using namespace std;
using namespace toolkit; using namespace toolkit;
@ -20,6 +22,34 @@ namespace toolkit {
namespace mediakit{ namespace mediakit{
template<typename C>
std::shared_ptr<C> FrameImp::create_l() {
#if 0
static ResourcePool<C> 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<C>(new C());
#endif
}
#define CREATE_FRAME_IMP(C) \
template<> \
std::shared_ptr<C> FrameImp::create<C>() { \
return create_l<C>(); \
}
CREATE_FRAME_IMP(FrameImp);
CREATE_FRAME_IMP(H264Frame);
CREATE_FRAME_IMP(H265Frame);
/** /**
* *
*/ */
@ -32,8 +62,8 @@ public:
_frame = frame; _frame = frame;
_ptr = frame->data(); _ptr = frame->data();
}else{ }else{
_buffer = std::make_shared<BufferRaw>(); _buffer = FrameImp::create();
_buffer->assign(frame->data(),frame->size()); _buffer->_buffer.assign(frame->data(),frame->size());
_ptr = _buffer->data(); _ptr = _buffer->data();
} }
_size = frame->size(); _size = frame->size();
@ -66,7 +96,7 @@ private:
bool _key; bool _key;
bool _config; bool _config;
Frame::Ptr _frame; Frame::Ptr _frame;
BufferRaw::Ptr _buffer; FrameImp::Ptr _buffer;
}; };
Frame::Ptr Frame::getCacheAbleFrame(const Frame::Ptr &frame){ Frame::Ptr Frame::getCacheAbleFrame(const Frame::Ptr &frame){

View File

@ -130,7 +130,10 @@ private:
class FrameImp : public Frame { class FrameImp : public Frame {
public: public:
typedef std::shared_ptr<FrameImp> Ptr; using Ptr = std::shared_ptr<FrameImp>;
template<typename C=FrameImp>
static std::shared_ptr<C> create();
char *data() const override{ char *data() const override{
return (char *)_buffer.data(); return (char *)_buffer.data();
@ -172,6 +175,13 @@ public:
BufferLikeString _buffer; BufferLikeString _buffer;
//对象个数统计 //对象个数统计
ObjectStatistic<FrameImp> _statistic; ObjectStatistic<FrameImp> _statistic;
protected:
friend class ResourcePool_l<FrameImp>;
FrameImp() = default;
template<typename C>
static std::shared_ptr<C> create_l();
}; };
/** /**
@ -195,26 +205,6 @@ private:
Frame::Ptr _parent_frame; Frame::Ptr _parent_frame;
}; };
/**
*
*/
template <typename T>
class ResourcePoolHelper{
public:
ResourcePoolHelper(int size = 0){
if (size > 0) {
_pool.setSize(size);
}
}
virtual ~ResourcePoolHelper(){}
std::shared_ptr<T> obtainObj(){
return _pool.obtain();
}
private:
ResourcePool<T> _pool;
};
/** /**
* *
*/ */

View File

@ -12,6 +12,47 @@
namespace mediakit{ 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<std::remove_reference<decltype(*this)>::type>(*this);
}
Sdp::Ptr G711Track::getSdp() { Sdp::Ptr G711Track::getSdp() {
if(!ready()){ if(!ready()){
WarnL << getCodecName() << " Track未准备好"; WarnL << getCodecName() << " Track未准备好";

View File

@ -21,53 +21,12 @@ namespace mediakit{
*/ */
class G711Track : public AudioTrackImp{ class G711Track : public AudioTrackImp{
public: public:
typedef std::shared_ptr<G711Track> Ptr; using Ptr = std::shared_ptr<G711Track>;
G711Track(CodecId codecId,int sample_rate, int channels, int sample_bit) : AudioTrackImp(codecId,sample_rate,channels,sample_bit){} G711Track(CodecId codecId,int sample_rate, int channels, int sample_bit) : AudioTrackImp(codecId,sample_rate,channels,sample_bit){}
private: private:
//克隆该Track Sdp::Ptr getSdp() override;
Track::Ptr clone() override { Track::Ptr clone() override;
return std::make_shared<std::remove_reference<decltype(*this)>::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;
}; };
}//namespace mediakit }//namespace mediakit

View File

@ -96,6 +96,174 @@ size_t prefixSize(const char *ptr, size_t len){
return 0; 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<H264FrameNoCacheAble>;
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<H264FrameInternal>(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<std::remove_reference<decltype(*this)>::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<H264Frame>();
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<H264Frame>();
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() { Sdp::Ptr H264Track::getSdp() {
if(!ready()){ if(!ready()){
WarnL << getCodecName() << " Track未准备好"; WarnL << getCodecName() << " Track未准备好";
@ -103,6 +271,48 @@ Sdp::Ptr H264Track::getSdp() {
} }
return std::make_shared<H264Sdp>(getSps(), getPps(), getBitRate() / 1024); return std::make_shared<H264Sdp>(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 }//namespace mediakit

View File

@ -14,45 +14,38 @@
#include "Frame.h" #include "Frame.h"
#include "Track.h" #include "Track.h"
#include "Util/base64.h" #include "Util/base64.h"
using namespace toolkit;
#define H264_TYPE(v) ((uint8_t)(v) & 0x1F) #define H264_TYPE(v) ((uint8_t)(v) & 0x1F)
using namespace toolkit;
namespace mediakit{ namespace mediakit{
bool getAVCInfo(const string &strSps,int &iVideoWidth, int &iVideoHeight, float &iVideoFps); 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<void(const char *, size_t, size_t)> &cb); void splitH264(const char *ptr, size_t len, size_t prefix, const std::function<void(const char *, size_t, size_t)> &cb);
size_t prefixSize(const char *ptr, size_t len); size_t prefixSize(const char *ptr, size_t len);
/** /**
* 264 * 264
*/ */
class H264Frame : public FrameImp { class H264Frame : public FrameImp {
public: public:
typedef std::shared_ptr<H264Frame> Ptr; using Ptr = std::shared_ptr<H264Frame>;
typedef enum { enum {
NAL_IDR = 5, NAL_IDR = 5,
NAL_SEI = 6, NAL_SEI = 6,
NAL_SPS = 7, NAL_SPS = 7,
NAL_PPS = 8, NAL_PPS = 8,
NAL_AUD = 9, NAL_AUD = 9,
NAL_B_P = 1, NAL_B_P = 1,
} NalType; };
H264Frame(){ bool keyFrame() const override;
_codec_id = CodecH264; bool configFrame() const override;
}
bool keyFrame() const override { protected:
return H264_TYPE(_buffer[_prefix_size]) == H264Frame::NAL_IDR; friend class FrameImp;
} friend class ResourcePool_l<H264Frame>;
H264Frame();
bool configFrame() const override{
switch(H264_TYPE(_buffer[_prefix_size]) ){
case H264Frame::NAL_SPS:
case H264Frame::NAL_PPS:return true;
default:return false;
}
}
}; };
/** /**
@ -62,44 +55,26 @@ public:
*/ */
class H264FrameNoCacheAble : public FrameFromPtr { class H264FrameNoCacheAble : public FrameFromPtr {
public: public:
typedef std::shared_ptr<H264FrameNoCacheAble> Ptr; using Ptr = std::shared_ptr<H264FrameNoCacheAble>;
H264FrameNoCacheAble(char *ptr,size_t size,uint32_t dts , uint32_t pts ,size_t prefix_size = 4){ H264FrameNoCacheAble(char *ptr,size_t size,uint32_t dts , uint32_t pts ,size_t prefix_size = 4);
_ptr = ptr; bool keyFrame() const override;
_size = size; bool configFrame() const override;
_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;
}
}
}; };
typedef FrameInternal<H264FrameNoCacheAble> H264FrameInternal;
/** /**
* 264 * 264
*/ */
class H264Track : public VideoTrack{ class H264Track : public VideoTrack{
public: public:
typedef std::shared_ptr<H264Track> Ptr; using Ptr = std::shared_ptr<H264Track>;
/** /**
* sps pps构造h264类型的媒体 * sps pps构造h264类型的媒体
* inputFrame中获取sps pps * inputFrame中获取sps pps
*/ */
H264Track(){} H264Track() = default;
/** /**
* h264类型的媒体 * h264类型的媒体
* @param sps sps帧数据 * @param sps sps帧数据
@ -107,230 +82,42 @@ public:
* @param sps_prefix_len 264340x00 00 00 01 * @param sps_prefix_len 264340x00 00 00 01
* @param pps_prefix_len 264340x00 00 00 01 * @param pps_prefix_len 264340x00 00 00 01
*/ */
H264Track(const string &sps,const string &pps,int sps_prefix_len = 4,int pps_prefix_len = 4){ 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();
}
/** /**
* h264类型的媒体 * h264类型的媒体
* @param sps sps帧 * @param sps sps帧
* @param pps pps帧 * @param pps pps帧
*/ */
H264Track(const Frame::Ptr &sps,const Frame::Ptr &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();
}
/** /**
* 0x00 00 00 01sps * 0x00 00 00 01sps/pps
* @return
*/ */
const string &getSps() const{ const string &getSps() const;
return _sps; const string &getPps() const;
}
/** bool ready() override;
* 0x00 00 00 01pps CodecId getCodecId() const override;
* @return int getVideoHeight() const override;
*/ int getVideoWidth() const override;
const string &getPps() const{ float getVideoFps() const override;
return _pps; 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<H264FrameInternal>(frame, (char *)ptr, len, prefix);
inputFrame_l(sub_frame);
});
} else{
inputFrame_l(frame);
}
}
private: private:
/** void onReady();
* sps获取宽高fps Sdp::Ptr getSdp() override;
*/ Track::Ptr clone() override;
void onReady(){ void inputFrame_l(const Frame::Ptr &frame);
getAVCInfo(_sps,_width,_height,_fps); void insertConfigFrame(const Frame::Ptr &frame);
}
Track::Ptr clone() override {
return std::make_shared<std::remove_reference<decltype(*this)>::type >(*this);
}
/**
* ,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: private:
//在idr帧前插入sps pps帧 bool _is_idr = false;
void insertConfigFrame(const Frame::Ptr &frame){
if(_last_frame_is_idr){
return;
}
if(!_sps.empty()){
auto spsFrame = std::make_shared<H264Frame>();
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<H264Frame>();
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;
int _width = 0; int _width = 0;
int _height = 0; int _height = 0;
float _fps = 0; float _fps = 0;
bool _last_frame_is_idr = false; string _sps;
}; string _pps;
/**
* 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;
}; };
}//namespace mediakit }//namespace mediakit

View File

@ -16,9 +16,7 @@ H264RtmpDecoder::H264RtmpDecoder() {
} }
H264Frame::Ptr H264RtmpDecoder::obtainFrame() { H264Frame::Ptr H264RtmpDecoder::obtainFrame() {
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 auto frame = FrameImp::create<H264Frame>();
auto frame = obtainObj();
frame->_buffer.clear();
frame->_prefix_size = 4; frame->_prefix_size = 4;
return frame; return frame;
} }
@ -124,7 +122,7 @@ inline void H264RtmpDecoder::onGetH264(const char* pcData, size_t iLen, uint32_t
#if 1 #if 1
_h264frame->_dts = dts; _h264frame->_dts = dts;
_h264frame->_pts = pts; _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); _h264frame->_buffer.append(pcData, iLen);
//写入环形缓存 //写入环形缓存

View File

@ -22,7 +22,7 @@ namespace mediakit{
* h264 Rtmp解码类 * h264 Rtmp解码类
* h264 over rtmp h264-Frame * h264 over rtmp h264-Frame
*/ */
class H264RtmpDecoder : public RtmpCodec ,public ResourcePoolHelper<H264Frame> { class H264RtmpDecoder : public RtmpCodec {
public: public:
typedef std::shared_ptr<H264RtmpDecoder> Ptr; typedef std::shared_ptr<H264RtmpDecoder> Ptr;

View File

@ -35,9 +35,7 @@ H264RtpDecoder::H264RtpDecoder() {
} }
H264Frame::Ptr H264RtpDecoder::obtainFrame() { H264Frame::Ptr H264RtpDecoder::obtainFrame() {
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 auto frame = FrameImp::create<H264Frame>();
auto frame = ResourcePoolHelper<H264Frame>::obtainObj();
frame->_buffer.clear();
frame->_prefix_size = 4; frame->_prefix_size = 4;
return frame; return frame;
} }
@ -81,7 +79,7 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
if (nal_type >= 0 && nal_type < 24) { if (nal_type >= 0 && nal_type < 24) {
//a full frame //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->_buffer.append((char *) frame, length);
_h264frame->_pts = stamp; _h264frame->_pts = stamp;
auto key = _h264frame->keyFrame(); auto key = _h264frame->keyFrame();
@ -108,7 +106,7 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
} }
if (len > 0) { 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->_buffer.append((char *) ptr, len);
_h264frame->_pts = stamp; _h264frame->_pts = stamp;
if ((ptr[0] & 0x1F) == H264Frame::NAL_IDR) { if ((ptr[0] & 0x1F) == H264Frame::NAL_IDR) {
@ -127,7 +125,7 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
MakeFU(frame[1], fu); MakeFU(frame[1], fu);
if (fu.S) { if (fu.S) {
//该帧的第一个rtp包 FU-A start //该帧的第一个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.push_back(nal_suffix | fu.type);
_h264frame->_buffer.append((char *) frame + 2, length - 2); _h264frame->_buffer.append((char *) frame + 2, length - 2);
_h264frame->_pts = stamp; _h264frame->_pts = stamp;

View File

@ -24,7 +24,7 @@ namespace mediakit{
* h264 over rtsp-rtp h264-Frame * h264 over rtsp-rtp h264-Frame
* rfc3984 * rfc3984
*/ */
class H264RtpDecoder : public RtpCodec , public ResourcePoolHelper<H264Frame> { class H264RtpDecoder : public RtpCodec{
public: public:
typedef std::shared_ptr<H264RtpDecoder> Ptr; typedef std::shared_ptr<H264RtpDecoder> Ptr;

View File

@ -10,7 +10,6 @@
#include "H265.h" #include "H265.h"
#include "SPSParser.h" #include "SPSParser.h"
#include "Util/logger.h"
namespace mediakit{ 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); h265GetWidthHeight(&tH265SpsInfo, &iVideoWidth, &iVideoHeight);
iVideoFps = 0; iVideoFps = 0;
h265GeFramerate(&tH265VpsInfo, &tH265SpsInfo, &iVideoFps); h265GeFramerate(&tH265VpsInfo, &tH265SpsInfo, &iVideoFps);
// ErrorL << iVideoWidth << " " << iVideoHeight << " " << iVideoFps;
return true; 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); 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<H265FrameNoCacheAble>;
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<H265FrameInternal>(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<std::remove_reference<decltype(*this)>::type>(*this);
}
void H265Track::insertConfigFrame(const Frame::Ptr &frame) {
if (_is_idr) {
return;
}
if (!_vps.empty()) {
auto vpsFrame = FrameImp::create<H265Frame>();
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<H265Frame>();
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<H265Frame>();
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() { Sdp::Ptr H265Track::getSdp() {
if(!ready()){ if(!ready()){
WarnL << getCodecName() << " Track未准备好"; WarnL << getCodecName() << " Track未准备好";
@ -57,5 +277,6 @@ Sdp::Ptr H265Track::getSdp() {
} }
return std::make_shared<H265Sdp>(getVps(), getSps(), getPps(), getBitRate() / 1024); return std::make_shared<H265Sdp>(getVps(), getSps(), getPps(), getBitRate() / 1024);
} }
}//namespace mediakit }//namespace mediakit

View File

@ -15,8 +15,8 @@
#include "Track.h" #include "Track.h"
#include "Util/base64.h" #include "Util/base64.h"
#include "H264.h" #include "H264.h"
using namespace toolkit;
#define H265_TYPE(v) (((uint8_t)(v) >> 1) & 0x3f) #define H265_TYPE(v) (((uint8_t)(v) >> 1) & 0x3f)
using namespace toolkit;
namespace mediakit { namespace mediakit {
@ -27,9 +27,8 @@ bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, i
*/ */
class H265Frame : public FrameImp { class H265Frame : public FrameImp {
public: public:
typedef std::shared_ptr<H265Frame> Ptr; using Ptr = std::shared_ptr<H265Frame>;
enum {
typedef enum {
NAL_TRAIL_N = 0, NAL_TRAIL_N = 0,
NAL_TRAIL_R = 1, NAL_TRAIL_R = 1,
NAL_TSA_N = 2, NAL_TSA_N = 2,
@ -58,71 +57,39 @@ public:
NAL_FD_NUT = 38, NAL_FD_NUT = 38,
NAL_SEI_PREFIX = 39, NAL_SEI_PREFIX = 39,
NAL_SEI_SUFFIX = 40, NAL_SEI_SUFFIX = 40,
} NaleType; };
H265Frame(){ bool keyFrame() const override;
_codec_id = CodecH265; bool configFrame() const override;
} static bool isKeyFrame(int type);
bool keyFrame() const override { protected:
return isKeyFrame(H265_TYPE(_buffer[_prefix_size])); friend class FrameImp;
} friend class ResourcePool_l<H265Frame>;
H265Frame();
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;
}
}; };
class H265FrameNoCacheAble : public FrameFromPtr { class H265FrameNoCacheAble : public FrameFromPtr {
public: public:
typedef std::shared_ptr<H265FrameNoCacheAble> Ptr; using Ptr = std::shared_ptr<H265FrameNoCacheAble>;
H265FrameNoCacheAble(char *ptr, size_t size, uint32_t dts,uint32_t pts, size_t prefix_size = 4) { H265FrameNoCacheAble(char *ptr, size_t size, uint32_t dts,uint32_t pts, size_t prefix_size = 4);
_ptr = ptr; bool keyFrame() const override;
_size = size; bool configFrame() const override;
_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;
}
}
}; };
typedef FrameInternal<H265FrameNoCacheAble> H265FrameInternal;
/** /**
* 265 * 265
*/ */
class H265Track : public VideoTrack { class H265Track : public VideoTrack {
public: public:
typedef std::shared_ptr<H265Track> Ptr; using Ptr = std::shared_ptr<H265Track>;
/** /**
* sps pps构造h265类型的媒体 * sps pps构造h265类型的媒体
* inputFrame中获取sps pps * inputFrame中获取sps pps
*/ */
H265Track() {} H265Track() = default;
/** /**
* h265类型的媒体 * h265类型的媒体
@ -133,221 +100,37 @@ public:
* @param sps_prefix_len 265340x00 00 00 01 * @param sps_prefix_len 265340x00 00 00 01
* @param pps_prefix_len 265340x00 00 00 01 * @param pps_prefix_len 265340x00 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) { 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();
}
/** /**
* 0x00 00 00 01vps * 0x00 00 00 01vps/sps/pps
*/ */
const string &getVps() const { const string &getVps() const;
return _vps; const string &getSps() const;
} const string &getPps() const;
/** bool ready() override;
* 0x00 00 00 01sps CodecId getCodecId() const override;
*/ int getVideoWidth() const override;
const string &getSps() const { int getVideoHeight() const override;
return _sps; float getVideoFps() const override;
} void inputFrame(const Frame::Ptr &frame) override;
/**
* 0x00 00 00 01pps
*/
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<H265FrameInternal>(frame, (char*)ptr, len, prefix);
inputFrame_l(sub_frame);
});
} else {
inputFrame_l(frame);
}
}
private: private:
/** void onReady();
* ,sps pps Sdp::Ptr getSdp() override;
* @param frame Track::Ptr clone() override;
*/ void inputFrame_l(const Frame::Ptr &frame);
void inputFrame_l(const Frame::Ptr &frame) { void insertConfigFrame(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;
}
_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<std::remove_reference<decltype(*this)>::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<H265Frame>();
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<H265Frame>();
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<H265Frame>();
ppsFrame->_prefix_size = 4;
ppsFrame->_buffer.assign("\x0\x0\x0\x1", 4);
ppsFrame->_buffer.append(_pps);
ppsFrame->_dts = frame->dts();
VideoTrack::inputFrame(ppsFrame);
}
}
private: private:
string _vps; bool _is_idr = false;
string _sps;
string _pps;
int _width = 0; int _width = 0;
int _height = 0; int _height = 0;
float _fps = 0; float _fps = 0;
bool _last_frame_is_idr = false; string _vps;
}; string _sps;
string _pps;
/**
* 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 }//namespace mediakit

View File

@ -20,9 +20,7 @@ H265RtmpDecoder::H265RtmpDecoder() {
} }
H265Frame::Ptr H265RtmpDecoder::obtainFrame() { H265Frame::Ptr H265RtmpDecoder::obtainFrame() {
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 auto frame = FrameImp::create<H265Frame>();
auto frame = obtainObj();
frame->_buffer.clear();
frame->_prefix_size = 4; frame->_prefix_size = 4;
return frame; return frame;
} }
@ -102,7 +100,7 @@ inline void H265RtmpDecoder::onGetH265(const char* pcData, size_t iLen, uint32_t
#if 1 #if 1
_h265frame->_dts = dts; _h265frame->_dts = dts;
_h265frame->_pts = pts; _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); _h265frame->_buffer.append(pcData, iLen);
//写入环形缓存 //写入环形缓存

View File

@ -22,7 +22,7 @@ namespace mediakit{
* h265 Rtmp解码类 * h265 Rtmp解码类
* h265 over rtmp h265-Frame * h265 over rtmp h265-Frame
*/ */
class H265RtmpDecoder : public RtmpCodec ,public ResourcePoolHelper<H265Frame> { class H265RtmpDecoder : public RtmpCodec {
public: public:
typedef std::shared_ptr<H265RtmpDecoder> Ptr; typedef std::shared_ptr<H265RtmpDecoder> Ptr;

View File

@ -30,9 +30,7 @@ H265RtpDecoder::H265RtpDecoder() {
} }
H265Frame::Ptr H265RtpDecoder::obtainFrame() { H265Frame::Ptr H265RtpDecoder::obtainFrame() {
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 auto frame = FrameImp::create<H265Frame>();
auto frame = ResourcePoolHelper<H265Frame>::obtainObj();
frame->_buffer.clear();
frame->_prefix_size = 4; frame->_prefix_size = 4;
return frame; return frame;
} }

View File

@ -25,7 +25,7 @@ namespace mediakit{
* h265 over rtsp-rtp h265-Frame * h265 over rtsp-rtp h265-Frame
* H265-over-RTPdraft-ietf-payload-rtp-h265-07.pdf * H265-over-RTPdraft-ietf-payload-rtp-h265-07.pdf
*/ */
class H265RtpDecoder : public RtpCodec , public ResourcePoolHelper<H265Frame> { class H265RtpDecoder : public RtpCodec {
public: public:
typedef std::shared_ptr<H265RtpDecoder> Ptr; typedef std::shared_ptr<H265RtpDecoder> Ptr;

View File

@ -12,6 +12,43 @@
namespace mediakit{ 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() { Sdp::Ptr L16Track::getSdp() {
WarnL << "Enter L16Track::getSdp function"; WarnL << "Enter L16Track::getSdp function";
if(!ready()){ if(!ready()){
@ -21,6 +58,10 @@ Sdp::Ptr L16Track::getSdp() {
return std::make_shared<L16Sdp>(getCodecId(), getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024); return std::make_shared<L16Sdp>(getCodecId(), getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
} }
Track::Ptr L16Track::clone() {
return std::make_shared<std::remove_reference<decltype(*this)>::type >(*this);
}
}//namespace mediakit }//namespace mediakit

View File

@ -21,53 +21,12 @@ namespace mediakit{
*/ */
class L16Track : public AudioTrackImp{ class L16Track : public AudioTrackImp{
public: public:
typedef std::shared_ptr<L16Track> Ptr; using Ptr = std::shared_ptr<L16Track>;
L16Track(int sample_rate, int channels) : AudioTrackImp(CodecL16,sample_rate,channels,16){} L16Track(int sample_rate, int channels) : AudioTrackImp(CodecL16,sample_rate,channels,16){}
private: private:
//克隆该Track Sdp::Ptr getSdp() override;
Track::Ptr clone() override { Track::Ptr clone() override;
return std::make_shared<std::remove_reference<decltype(*this)>::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;
}; };
}//namespace mediakit }//namespace mediakit

View File

@ -12,6 +12,40 @@
namespace mediakit{ 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() { Sdp::Ptr OpusTrack::getSdp() {
if(!ready()){ if(!ready()){
WarnL << getCodecName() << " Track未准备好"; WarnL << getCodecName() << " Track未准备好";

View File

@ -33,39 +33,5 @@ private:
Sdp::Ptr getSdp() override ; 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 }//namespace mediakit
#endif //ZLMEDIAKIT_OPUS_H #endif //ZLMEDIAKIT_OPUS_H

View File

@ -221,7 +221,7 @@ Frame::Ptr MP4Demuxer::makeFrame(uint32_t track_id, const Buffer::Ptr &buf, int6
if (frame_len + offset + 4 > bytes) { if (frame_len + offset + 4 > bytes) {
return nullptr; return nullptr;
} }
memcpy(data + offset, "\x0\x0\x0\x1", 4); memcpy(data + offset, "\x00\x00\x00\x01", 4);
offset += (frame_len + 4); offset += (frame_len + 4);
} }
if (codec == CodecH264) { if (codec == CodecH264) {

View File

@ -142,9 +142,7 @@ RtmpPacket::Ptr RtmpPacket::create(){
ret->clear(); ret->clear();
return ret; return ret;
#else #else
auto ret = Ptr(new RtmpPacket); return Ptr(new RtmpPacket);
ret->clear();
return ret;
#endif #endif
} }