mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-10-31 00:37:39 +08:00
初步完成H264 的 RTMP打包解包
This commit is contained in:
parent
3850ecec96
commit
6c9d50b04b
@ -65,6 +65,21 @@ public:
|
||||
virtual bool keyFrame() const = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ResourcePoolHelper{
|
||||
public:
|
||||
ResourcePoolHelper(int size = 8){
|
||||
_pool.setSize(size);
|
||||
}
|
||||
virtual ~ResourcePoolHelper(){}
|
||||
|
||||
std::shared_ptr<T> obtainObj(){
|
||||
return _pool.obtain();
|
||||
}
|
||||
private:
|
||||
ResourcePool<T> _pool;
|
||||
};
|
||||
|
||||
/**
|
||||
* 帧环形缓存接口类
|
||||
*/
|
||||
|
@ -55,8 +55,8 @@ void AACRtpEncoder::makeAACRtp(const void *pData, unsigned int uiLen, bool bMark
|
||||
uint32_t ts = htonl(m_ui32TimeStamp);
|
||||
uint16_t sq = htons(m_ui16Sequence);
|
||||
uint32_t sc = htonl(m_ui32Ssrc);
|
||||
auto pRtppkt = obtainRtp();
|
||||
auto &rtppkt = *(pRtppkt.get());
|
||||
auto pRtppkt = ResourcePoolHelper<RtpPacket>::obtainObj();
|
||||
auto &rtppkt = *pRtppkt;
|
||||
unsigned char *pucRtp = rtppkt.payload;
|
||||
pucRtp[0] = '$';
|
||||
pucRtp[1] = m_ui8Interleaved;
|
||||
@ -93,7 +93,7 @@ AACRtpDecoder::AACRtpDecoder(uint32_t ui32SampleRate) {
|
||||
|
||||
AACFrame::Ptr AACRtpDecoder::obtainFrame() {
|
||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||
auto frame = m_framePool.obtain();
|
||||
auto frame = ResourcePoolHelper<AACFrame>::obtainObj();
|
||||
frame->aac_frame_length = 7;
|
||||
frame->iPrefixSize = 7;
|
||||
return frame;
|
||||
|
@ -10,7 +10,7 @@
|
||||
/**
|
||||
* aac rtp转adts类
|
||||
*/
|
||||
class AACRtpDecoder : public RtpCodec {
|
||||
class AACRtpDecoder : public RtpCodec , public ResourcePoolHelper<AACFrame> {
|
||||
public:
|
||||
typedef std::shared_ptr<AACRtpDecoder> Ptr;
|
||||
|
||||
@ -39,7 +39,6 @@ private:
|
||||
AACFrame::Ptr obtainFrame();
|
||||
private:
|
||||
AACFrame::Ptr m_adts;
|
||||
ResourcePool<AACFrame> m_framePool;
|
||||
uint32_t m_sampleRate;
|
||||
};
|
||||
|
||||
|
@ -11,7 +11,7 @@ H264RtpDecoder::H264RtpDecoder() {
|
||||
|
||||
H264Frame::Ptr H264RtpDecoder::obtainFrame() {
|
||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||
auto frame = m_framePool.obtain();
|
||||
auto frame = ResourcePoolHelper<H264Frame>::obtainObj();
|
||||
frame->buffer.clear();
|
||||
frame->iPrefixSize = 4;
|
||||
return frame;
|
||||
@ -174,7 +174,7 @@ void H264RtpEncoder::makeH264Rtp(const void* data, unsigned int len, bool mark,
|
||||
uint16_t sq = htons(m_ui16Sequence);
|
||||
uint32_t sc = htonl(m_ui32Ssrc);
|
||||
|
||||
auto rtppkt = obtainRtp();
|
||||
auto rtppkt = ResourcePoolHelper<RtpPacket>::obtainObj();
|
||||
unsigned char *pucRtp = rtppkt->payload;
|
||||
pucRtp[0] = '$';
|
||||
pucRtp[1] = m_ui8Interleaved;
|
||||
|
@ -13,7 +13,7 @@ using namespace ZL::Util;
|
||||
/**
|
||||
* h264 rtp解码类
|
||||
*/
|
||||
class H264RtpDecoder : public RtpCodec {
|
||||
class H264RtpDecoder : public RtpCodec , public ResourcePoolHelper<H264Frame> {
|
||||
public:
|
||||
typedef std::shared_ptr<H264RtpDecoder> Ptr;
|
||||
|
||||
@ -40,7 +40,6 @@ private:
|
||||
H264Frame::Ptr obtainFrame();
|
||||
private:
|
||||
H264Frame::Ptr m_h264frame;
|
||||
ResourcePool<H264Frame> m_framePool;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,6 @@ public:
|
||||
typedef std::shared_ptr<RtpRing> Ptr;
|
||||
|
||||
RtpRing(){
|
||||
//禁用缓存
|
||||
_rtpRing = std::make_shared<RingType>();
|
||||
}
|
||||
virtual ~RtpRing(){}
|
||||
@ -111,7 +110,6 @@ public:
|
||||
m_ui32MtuSize = ui32MtuSize;
|
||||
m_ui8PlayloadType = ui8PlayloadType;
|
||||
m_ui8Interleaved = ui8Interleaved;
|
||||
m_rtpPool.setSize(32);
|
||||
}
|
||||
|
||||
virtual ~RtpInfo(){}
|
||||
@ -141,10 +139,6 @@ public:
|
||||
uint32_t getMtuSize() const {
|
||||
return m_ui32MtuSize;
|
||||
}
|
||||
protected:
|
||||
RtpPacket::Ptr obtainRtp(){
|
||||
return m_rtpPool.obtain();
|
||||
}
|
||||
protected:
|
||||
uint32_t m_ui32Ssrc;
|
||||
uint32_t m_ui32SampleRate;
|
||||
@ -153,10 +147,9 @@ protected:
|
||||
uint8_t m_ui8Interleaved;
|
||||
uint16_t m_ui16Sequence = 0;
|
||||
uint32_t m_ui32TimeStamp = 0;
|
||||
ResourcePool<RtpPacket> m_rtpPool;
|
||||
};
|
||||
|
||||
class RtpCodec : public RtpRing, public FrameRingInterfaceDelegate , public CodecInfo{
|
||||
class RtpCodec : public RtpRing, public FrameRingInterfaceDelegate , public CodecInfo , public ResourcePoolHelper<RtpPacket>{
|
||||
public:
|
||||
typedef std::shared_ptr<RtpCodec> Ptr;
|
||||
RtpCodec(){}
|
||||
|
@ -188,6 +188,11 @@ public:
|
||||
const static int channel[] = { 1, 2 };
|
||||
return channel[flvStereoOrMono];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回不带0x00 00 00 01头的sps
|
||||
* @return
|
||||
*/
|
||||
string getH264SPS() const {
|
||||
string ret;
|
||||
if (getMediaType() != 7) {
|
||||
@ -210,6 +215,11 @@ public:
|
||||
ret.assign(strBuf.data() + 13, sps_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回不带0x00 00 00 01头的pps
|
||||
* @return
|
||||
*/
|
||||
string getH264PPS() const {
|
||||
string ret;
|
||||
if (getMediaType() != 7) {
|
||||
@ -258,4 +268,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
206
src/RtmpCodec/H264RtmpCodec.cpp
Normal file
206
src/RtmpCodec/H264RtmpCodec.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
//
|
||||
// Created by xzl on 2018/10/18.
|
||||
//
|
||||
|
||||
#include "H264RtmpCodec.h"
|
||||
|
||||
|
||||
H264RtmpDecoder::H264RtmpDecoder() {
|
||||
m_h264frame = obtainFrame();
|
||||
}
|
||||
|
||||
H264Frame::Ptr H264RtmpDecoder::obtainFrame() {
|
||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||
auto frame = obtainObj();
|
||||
frame->buffer.clear();
|
||||
frame->iPrefixSize = 4;
|
||||
return frame;
|
||||
}
|
||||
|
||||
bool H264RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &rtmp, bool key_pos) {
|
||||
key_pos = decodeRtmp(rtmp);
|
||||
RtmpCodec::inputRtmp(rtmp, key_pos);
|
||||
return key_pos;
|
||||
}
|
||||
|
||||
bool H264RtmpDecoder::decodeRtmp(const RtmpPacket::Ptr &pkt) {
|
||||
if (pkt->isCfgFrame()) {
|
||||
//缓存sps pps,后续插入到I帧之前
|
||||
m_strSPS = pkt->getH264SPS();
|
||||
m_strPPS = pkt->getH264PPS();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_strSPS.size()) {
|
||||
uint32_t iTotalLen = pkt->strBuf.size();
|
||||
uint32_t iOffset = 5;
|
||||
while(iOffset + 4 < iTotalLen){
|
||||
uint32_t iFrameLen;
|
||||
memcpy(&iFrameLen, pkt->strBuf.data() + iOffset, 4);
|
||||
iFrameLen = ntohl(iFrameLen);
|
||||
iOffset += 4;
|
||||
if(iFrameLen + iOffset > iTotalLen){
|
||||
break;
|
||||
}
|
||||
onGetH264_l(pkt->strBuf.data() + iOffset, iFrameLen, pkt->timeStamp);
|
||||
iOffset += iFrameLen;
|
||||
}
|
||||
}
|
||||
return pkt->isVideoKeyFrame();
|
||||
}
|
||||
|
||||
|
||||
inline void H264RtmpDecoder::onGetH264_l(const char* pcData, int iLen, uint32_t ui32TimeStamp) {
|
||||
switch (pcData[0] & 0x1F) {
|
||||
case 5: {
|
||||
//I frame
|
||||
onGetH264(m_strSPS.data(), m_strSPS.length(), ui32TimeStamp);
|
||||
onGetH264(m_strPPS.data(), m_strPPS.length(), ui32TimeStamp);
|
||||
}
|
||||
case 1: {
|
||||
//I or P or B frame
|
||||
onGetH264(pcData, iLen, ui32TimeStamp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//WarnL <<(int)(pcData[0] & 0x1F);
|
||||
break;
|
||||
}
|
||||
}
|
||||
inline void H264RtmpDecoder::onGetH264(const char* pcData, int iLen, uint32_t ui32TimeStamp) {
|
||||
m_h264frame->type = pcData[0] & 0x1F;
|
||||
m_h264frame->timeStamp = ui32TimeStamp;
|
||||
m_h264frame->buffer.assign("\x0\x0\x0\x1", 4); //添加264头
|
||||
m_h264frame->buffer.append(pcData, iLen);
|
||||
|
||||
//写入环形缓存
|
||||
RtmpCodec::inputFrame(m_h264frame);
|
||||
m_h264frame = obtainFrame();
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
H264RtmpEncoder::H264RtmpEncoder() {
|
||||
}
|
||||
|
||||
void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
RtmpCodec::inputFrame(frame);
|
||||
|
||||
auto pcData = frame->data() + frame->prefixSize();
|
||||
auto iLen = frame->size() - frame->prefixSize();
|
||||
auto type = ((uint8_t*)pcData)[0] & 0x1F;
|
||||
|
||||
switch (type){
|
||||
case 7:{
|
||||
//sps
|
||||
if(m_sps.empty()){
|
||||
m_sps = string(pcData,iLen);
|
||||
if(!m_pps.empty()){
|
||||
makeVideoConfigPkt();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 8:{
|
||||
//pps
|
||||
if(m_pps.empty()){
|
||||
m_pps = string(pcData,iLen);
|
||||
if(!m_sps.empty()){
|
||||
makeVideoConfigPkt();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 5:{
|
||||
//I or P or B frame
|
||||
int8_t flags = 7; //h.264
|
||||
bool is_config = false;
|
||||
bool keyFrame = frame->keyFrame();
|
||||
flags |= ((keyFrame ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4);
|
||||
|
||||
RtmpPacket::Ptr rtmpPkt = ResourcePoolHelper<RtmpPacket>::obtainObj();
|
||||
rtmpPkt->strBuf.push_back(flags);
|
||||
rtmpPkt->strBuf.push_back(!is_config);
|
||||
rtmpPkt->strBuf.append("\x0\x0\x0", 3);
|
||||
auto size = htonl(iLen);
|
||||
rtmpPkt->strBuf.append((char *) &size, 4);
|
||||
rtmpPkt->strBuf.append(pcData, iLen);
|
||||
|
||||
rtmpPkt->bodySize = rtmpPkt->strBuf.size();
|
||||
rtmpPkt->chunkId = CHUNK_VIDEO;
|
||||
rtmpPkt->streamId = STREAM_MEDIA;
|
||||
rtmpPkt->timeStamp = frame->stamp();
|
||||
rtmpPkt->typeId = MSG_VIDEO;
|
||||
RtmpCodec::inputRtmp(rtmpPkt,keyFrame);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void H264RtmpEncoder::makeVideoConfigPkt() {
|
||||
int8_t flags = 7; //h.264
|
||||
flags |= (FLV_KEY_FRAME << 4);
|
||||
bool is_config = true;
|
||||
|
||||
RtmpPacket::Ptr rtmpPkt = ResourcePoolHelper<RtmpPacket>::obtainObj();
|
||||
//////////header
|
||||
rtmpPkt->strBuf.push_back(flags);
|
||||
rtmpPkt->strBuf.push_back(!is_config);
|
||||
rtmpPkt->strBuf.append("\x0\x0\x0", 3);
|
||||
|
||||
////////////sps
|
||||
rtmpPkt->strBuf.push_back(1); // version
|
||||
|
||||
//DebugL<<hexdump(m_sps.data(), m_sps.size());
|
||||
rtmpPkt->strBuf.push_back(m_sps[1]); // profile
|
||||
rtmpPkt->strBuf.push_back(m_sps[2]); // compat
|
||||
rtmpPkt->strBuf.push_back(m_sps[3]); // level
|
||||
rtmpPkt->strBuf.push_back(0xff); // 6 bits reserved + 2 bits nal size length - 1 (11)
|
||||
rtmpPkt->strBuf.push_back(0xe1); // 3 bits reserved + 5 bits number of sps (00001)
|
||||
uint16_t size = m_sps.size();
|
||||
size = htons(size);
|
||||
rtmpPkt->strBuf.append((char *) &size, 2);
|
||||
rtmpPkt->strBuf.append(m_sps);
|
||||
|
||||
/////////////pps
|
||||
rtmpPkt->strBuf.push_back(1); // version
|
||||
size = m_pps.size();
|
||||
size = htons(size);
|
||||
rtmpPkt->strBuf.append((char *) &size, 2);
|
||||
rtmpPkt->strBuf.append(m_pps);
|
||||
|
||||
rtmpPkt->bodySize = rtmpPkt->strBuf.size();
|
||||
rtmpPkt->chunkId = CHUNK_VIDEO;
|
||||
rtmpPkt->streamId = STREAM_MEDIA;
|
||||
rtmpPkt->timeStamp = 0;
|
||||
rtmpPkt->typeId = MSG_VIDEO;
|
||||
RtmpCodec::inputRtmp(rtmpPkt, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
70
src/RtmpCodec/H264RtmpCodec.h
Normal file
70
src/RtmpCodec/H264RtmpCodec.h
Normal file
@ -0,0 +1,70 @@
|
||||
//
|
||||
// Created by xzl on 2018/10/24.
|
||||
//
|
||||
|
||||
#ifndef ZLMEDIAKIT_H264RTMPCODEC_H
|
||||
#define ZLMEDIAKIT_H264RTMPCODEC_H
|
||||
|
||||
#include "RtmpCodec.h"
|
||||
#include "Util/ResourcePool.h"
|
||||
|
||||
using namespace ZL::Rtmp;
|
||||
|
||||
/**
|
||||
* h264 Rtmp解码类
|
||||
*/
|
||||
class H264RtmpDecoder : public RtmpCodec ,public ResourcePoolHelper<H264Frame> {
|
||||
public:
|
||||
typedef std::shared_ptr<H264RtmpDecoder> Ptr;
|
||||
|
||||
H264RtmpDecoder();
|
||||
~H264RtmpDecoder() {}
|
||||
|
||||
/**
|
||||
* 输入264 Rtmp包
|
||||
* @param rtmp Rtmp包
|
||||
* @param key_pos 此参数忽略之
|
||||
*/
|
||||
bool inputRtmp(const RtmpPacket::Ptr &rtmp, bool key_pos = true) override;
|
||||
|
||||
TrackType getTrackType() const override{
|
||||
return TrackVideo;
|
||||
}
|
||||
|
||||
CodecId getCodecId() const override{
|
||||
return CodecH264;
|
||||
}
|
||||
private:
|
||||
bool decodeRtmp(const RtmpPacket::Ptr &Rtmp);
|
||||
void onGetH264_l(const char *pcData, int iLen, uint32_t ui32TimeStamp);
|
||||
void onGetH264(const char *pcData, int iLen, uint32_t ui32TimeStamp);
|
||||
H264Frame::Ptr obtainFrame();
|
||||
private:
|
||||
H264Frame::Ptr m_h264frame;
|
||||
string m_strSPS;
|
||||
string m_strPPS;
|
||||
};
|
||||
|
||||
/**
|
||||
* 264 Rtmp打包类
|
||||
*/
|
||||
class H264RtmpEncoder : public H264RtmpDecoder, public ResourcePoolHelper<RtmpPacket> {
|
||||
public:
|
||||
typedef std::shared_ptr<H264RtmpEncoder> Ptr;
|
||||
|
||||
H264RtmpEncoder();
|
||||
~H264RtmpEncoder() {}
|
||||
|
||||
/**
|
||||
* 输入264帧,需要指出的是,必须输入sps pps帧
|
||||
* @param frame 帧数据
|
||||
*/
|
||||
void inputFrame(const Frame::Ptr &frame) override;
|
||||
private:
|
||||
void makeVideoConfigPkt();
|
||||
private:
|
||||
string m_sps;
|
||||
string m_pps;
|
||||
};
|
||||
|
||||
#endif //ZLMEDIAKIT_H264RTMPCODEC_H
|
5
src/RtmpCodec/RtmpCodec.cpp
Normal file
5
src/RtmpCodec/RtmpCodec.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by xzl on 2018/10/24.
|
||||
//
|
||||
|
||||
#include "RtmpCodec.h"
|
86
src/RtmpCodec/RtmpCodec.h
Normal file
86
src/RtmpCodec/RtmpCodec.h
Normal file
@ -0,0 +1,86 @@
|
||||
//
|
||||
// Created by xzl on 2018/10/24.
|
||||
//
|
||||
|
||||
#ifndef ZLMEDIAKIT_RTMPCODEC_H
|
||||
#define ZLMEDIAKIT_RTMPCODEC_H
|
||||
|
||||
#include "Rtmp/Rtmp.h"
|
||||
#include "Player/Frame.h"
|
||||
#include "Util/RingBuffer.h"
|
||||
|
||||
using namespace ZL::Util;
|
||||
|
||||
namespace ZL{
|
||||
namespace Rtmp {
|
||||
|
||||
|
||||
class RtmpRingInterface {
|
||||
public:
|
||||
typedef RingBuffer<RtmpPacket::Ptr> RingType;
|
||||
typedef std::shared_ptr<RtmpRingInterface> Ptr;
|
||||
|
||||
RtmpRingInterface(){}
|
||||
virtual ~RtmpRingInterface(){}
|
||||
|
||||
/**
|
||||
* 获取rtmp环形缓存
|
||||
* @return
|
||||
*/
|
||||
virtual RingType::Ptr getRtmpRing() const = 0;
|
||||
|
||||
/**
|
||||
* 设置rtmp环形缓存
|
||||
* @param ring
|
||||
*/
|
||||
virtual void setRtmpRing(const RingType::Ptr &ring) = 0;
|
||||
|
||||
/**
|
||||
* 输入rtmp包
|
||||
* @param rtmp rtmp包
|
||||
* @param key_pos 是否为关键帧
|
||||
* @return 是否为关键帧
|
||||
*/
|
||||
virtual bool inputRtmp(const RtmpPacket::Ptr &rtmp, bool key_pos) = 0;
|
||||
};
|
||||
|
||||
class RtmpRing : public RtmpRingInterface {
|
||||
public:
|
||||
typedef std::shared_ptr<RtmpRing> Ptr;
|
||||
|
||||
RtmpRing(){
|
||||
_rtmpRing = std::make_shared<RingType>();
|
||||
}
|
||||
virtual ~RtmpRing(){}
|
||||
|
||||
RingType::Ptr getRtmpRing() const override {
|
||||
return _rtmpRing;
|
||||
}
|
||||
|
||||
void setRtmpRing(const RingType::Ptr &ring) override {
|
||||
_rtmpRing = ring;
|
||||
}
|
||||
|
||||
bool inputRtmp(const RtmpPacket::Ptr &rtmp, bool key_pos) override{
|
||||
_rtmpRing->write(rtmp,key_pos);
|
||||
return key_pos;
|
||||
}
|
||||
protected:
|
||||
RingType::Ptr _rtmpRing;
|
||||
};
|
||||
|
||||
|
||||
class RtmpCodec : public RtmpRing, public FrameRingInterfaceDelegate , public CodecInfo{
|
||||
public:
|
||||
typedef std::shared_ptr<RtmpCodec> Ptr;
|
||||
RtmpCodec(){}
|
||||
virtual ~RtmpCodec(){}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}//namespace Rtmp
|
||||
}//namespace ZL
|
||||
|
||||
#endif //ZLMEDIAKIT_RTMPCODEC_H
|
Loading…
Reference in New Issue
Block a user