mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-23 11:17:09 +08:00
优化frame性能及整理代码
This commit is contained in:
parent
c5cfbce241
commit
62ba87dd0f
@ -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);
|
||||||
|
@ -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未准备好";
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回音频采样位数,一般为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<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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 解析2个字节的aac配置
|
|
||||||
*/
|
|
||||||
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
|
||||||
|
@ -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头
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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){
|
||||||
|
@ -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;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写帧接口的抽象接口类
|
* 写帧接口的抽象接口类
|
||||||
*/
|
*/
|
||||||
|
@ -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未准备好";
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 264头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
* @param sps_prefix_len 264头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||||
* @param pps_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){
|
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 01头的sps
|
* 返回不带0x00 00 00 01头的sps/pps
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
const string &getSps() const{
|
const string &getSps() const;
|
||||||
return _sps;
|
const string &getPps() const;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
bool ready() override;
|
||||||
* 返回不带0x00 00 00 01头的pps
|
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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
//写入环形缓存
|
//写入环形缓存
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
* @param sps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||||
* @param pps_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) {
|
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 01头的vps
|
* 返回不带0x00 00 00 01头的vps/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 01头的sps
|
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 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<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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
//写入环形缓存
|
//写入环形缓存
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ namespace mediakit{
|
|||||||
* 将 h265 over rtsp-rtp 解复用出 h265-Frame
|
* 将 h265 over rtsp-rtp 解复用出 h265-Frame
|
||||||
* 《草案(H265-over-RTP)draft-ietf-payload-rtp-h265-07.pdf》
|
* 《草案(H265-over-RTP)draft-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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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未准备好";
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user