mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-26 12:37:09 +08:00
初步实现265 rtp解包
This commit is contained in:
parent
9511a9fe03
commit
946b00f453
@ -29,6 +29,7 @@
|
|||||||
#include "RtmpMuxer/AACRtmpCodec.h"
|
#include "RtmpMuxer/AACRtmpCodec.h"
|
||||||
#include "RtspMuxer/H264RtpCodec.h"
|
#include "RtspMuxer/H264RtpCodec.h"
|
||||||
#include "RtspMuxer/AACRtpCodec.h"
|
#include "RtspMuxer/AACRtpCodec.h"
|
||||||
|
#include "RtspMuxer/H265RtpCodec.h"
|
||||||
|
|
||||||
namespace mediakit{
|
namespace mediakit{
|
||||||
|
|
||||||
@ -107,11 +108,83 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
|
|||||||
return std::make_shared<H264Track>(sps,pps,0,0);
|
return std::make_shared<H264Track>(sps,pps,0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcasestr(track->_codec.data(), "h265") != nullptr) {
|
||||||
|
//a=fmtp:96 sprop-sps=QgEBAWAAAAMAsAAAAwAAAwBdoAKAgC0WNrkky/AIAAADAAgAAAMBlQg=; sprop-pps=RAHA8vA8kAA=
|
||||||
|
int pt;
|
||||||
|
char sprop_sps[128] = {0},sprop_pps[128] = {0};
|
||||||
|
if (3 != sscanf(track->_fmtp.c_str(), "%d sprop-sps=%127[^;]; sprop-pps=%127[^;]", &pt, sprop_sps, sprop_pps)) {
|
||||||
|
return std::make_shared<H265Track>();
|
||||||
|
}
|
||||||
|
return std::make_shared<H265Track>("",sprop_sps,sprop_pps,0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
WarnL << "暂不支持该sdp:" << track->_codec << " " << track->_fmtp;
|
WarnL << "暂不支持该sdp:" << track->_codec << " " << track->_fmtp;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Track::Ptr Factory::getTrackByCodecId(CodecId codecId) {
|
||||||
|
switch (codecId){
|
||||||
|
case CodecH264:{
|
||||||
|
return std::make_shared<H264Track>();
|
||||||
|
}
|
||||||
|
case CodecH265:{
|
||||||
|
return std::make_shared<H265Track>();
|
||||||
|
}
|
||||||
|
case CodecAAC:{
|
||||||
|
return std::make_shared<AACTrack>();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
WarnL << "暂不支持该CodecId:" << codecId;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpCodec::Ptr Factory::getRtpEncoderById(CodecId codecId,
|
||||||
|
uint32_t ui32Ssrc,
|
||||||
|
uint32_t ui32MtuSize,
|
||||||
|
uint32_t ui32SampleRate,
|
||||||
|
uint8_t ui8PlayloadType,
|
||||||
|
uint8_t ui8Interleaved) {
|
||||||
|
switch (codecId){
|
||||||
|
case CodecH264:
|
||||||
|
return std::make_shared<H264RtpEncoder>(ui32Ssrc,ui32MtuSize,ui32SampleRate,ui8PlayloadType,ui8Interleaved);
|
||||||
|
case CodecH265:
|
||||||
|
return std::make_shared<H265RtpEncoder>(ui32Ssrc,ui32MtuSize,ui32SampleRate,ui8PlayloadType,ui8Interleaved);
|
||||||
|
case CodecAAC:
|
||||||
|
return std::make_shared<AACRtpEncoder>(ui32Ssrc,ui32MtuSize,ui32SampleRate,ui8PlayloadType,ui8Interleaved);
|
||||||
|
default:
|
||||||
|
WarnL << "暂不支持该CodecId:" << codecId;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpCodec::Ptr Factory::getRtpDecoderById(CodecId codecId) {
|
||||||
|
switch (codecId){
|
||||||
|
case CodecH264:
|
||||||
|
return std::make_shared<H264RtpDecoder>();
|
||||||
|
case CodecH265:
|
||||||
|
return std::make_shared<H265RtpDecoder>();
|
||||||
|
case CodecAAC:
|
||||||
|
return std::make_shared<AACRtpDecoder>();
|
||||||
|
default:
|
||||||
|
WarnL << "暂不支持该CodecId:" << codecId;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////rtmp相关///////////////////////////////////////////
|
||||||
|
|
||||||
|
Track::Ptr Factory::getTrackByAmf(const AMFValue &amf) {
|
||||||
|
CodecId codecId = getCodecIdByAmf(amf);
|
||||||
|
if(codecId == CodecInvalid){
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return getTrackByCodecId(codecId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CodecId Factory::getCodecIdByAmf(const AMFValue &val){
|
CodecId Factory::getCodecIdByAmf(const AMFValue &val){
|
||||||
if (val.type() == AMF_STRING){
|
if (val.type() == AMF_STRING){
|
||||||
auto str = val.as_string();
|
auto str = val.as_string();
|
||||||
@ -143,58 +216,6 @@ CodecId Factory::getCodecIdByAmf(const AMFValue &val){
|
|||||||
return CodecInvalid;
|
return CodecInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Track::Ptr Factory::getTrackByCodecId(CodecId codecId) {
|
|
||||||
switch (codecId){
|
|
||||||
case CodecH264:{
|
|
||||||
return std::make_shared<H264Track>();
|
|
||||||
}
|
|
||||||
case CodecAAC:{
|
|
||||||
return std::make_shared<AACTrack>();
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
WarnL << "暂不支持该CodecId:" << codecId;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Track::Ptr Factory::getTrackByAmf(const AMFValue &amf) {
|
|
||||||
CodecId codecId = getCodecIdByAmf(amf);
|
|
||||||
if(codecId == CodecInvalid){
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return getTrackByCodecId(codecId);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RtpCodec::Ptr Factory::getRtpEncoderById(CodecId codecId,
|
|
||||||
uint32_t ui32Ssrc,
|
|
||||||
uint32_t ui32MtuSize,
|
|
||||||
uint32_t ui32SampleRate,
|
|
||||||
uint8_t ui8PlayloadType,
|
|
||||||
uint8_t ui8Interleaved) {
|
|
||||||
switch (codecId){
|
|
||||||
case CodecH264:
|
|
||||||
return std::make_shared<H264RtpEncoder>(ui32Ssrc,ui32MtuSize,ui32SampleRate,ui8PlayloadType,ui8Interleaved);
|
|
||||||
case CodecAAC:
|
|
||||||
return std::make_shared<AACRtpEncoder>(ui32Ssrc,ui32MtuSize,ui32SampleRate,ui8PlayloadType,ui8Interleaved);
|
|
||||||
default:
|
|
||||||
WarnL << "暂不支持该CodecId:" << codecId;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpCodec::Ptr Factory::getRtpDecoderById(CodecId codecId) {
|
|
||||||
switch (codecId){
|
|
||||||
case CodecH264:
|
|
||||||
return std::make_shared<H264RtpDecoder>();
|
|
||||||
case CodecAAC:
|
|
||||||
return std::make_shared<AACRtpDecoder>();
|
|
||||||
default:
|
|
||||||
WarnL << "暂不支持该CodecId:" << codecId;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track) {
|
RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track) {
|
||||||
switch (track->getCodecId()){
|
switch (track->getCodecId()){
|
||||||
|
@ -435,9 +435,11 @@ void RtspPlayer::handleResPAUSE(const Parser& parser, bool bPause) {
|
|||||||
auto strControlSuffix = strTrack.substr(1 + strTrack.rfind('/'),strTrack.find(';') - strTrack.rfind('/') - 1);
|
auto strControlSuffix = strTrack.substr(1 + strTrack.rfind('/'),strTrack.find(';') - strTrack.rfind('/') - 1);
|
||||||
auto strRtpTime = FindField(strTrack.data(), "rtptime=", ";");
|
auto strRtpTime = FindField(strTrack.data(), "rtptime=", ";");
|
||||||
auto idx = getTrackIndexByControlSuffix(strControlSuffix);
|
auto idx = getTrackIndexByControlSuffix(strControlSuffix);
|
||||||
_aiFistStamp[idx] = atoll(strRtpTime.data()) * 1000 / _aTrackInfo[idx]->_samplerate;
|
if(idx != -1){
|
||||||
_aiNowStamp[idx] = _aiFistStamp[idx];
|
_aiFistStamp[idx] = atoll(strRtpTime.data()) * 1000 / _aTrackInfo[idx]->_samplerate;
|
||||||
DebugL << "rtptime(ms):" << strControlSuffix <<" " << strRtpTime;
|
_aiNowStamp[idx] = _aiFistStamp[idx];
|
||||||
|
DebugL << "rtptime(ms):" << strControlSuffix <<" " << strRtpTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onPlayResult_l(SockException(Err_success, "rtsp play success"));
|
onPlayResult_l(SockException(Err_success, "rtsp play success"));
|
||||||
|
@ -42,7 +42,7 @@ typedef struct {
|
|||||||
unsigned type :5;
|
unsigned type :5;
|
||||||
} FU;
|
} FU;
|
||||||
|
|
||||||
bool MakeNalu(uint8_t in, NALU &nal) {
|
static bool MakeNalu(uint8_t in, NALU &nal) {
|
||||||
nal.forbidden_zero_bit = in >> 7;
|
nal.forbidden_zero_bit = in >> 7;
|
||||||
if (nal.forbidden_zero_bit) {
|
if (nal.forbidden_zero_bit) {
|
||||||
return false;
|
return false;
|
||||||
@ -51,7 +51,7 @@ bool MakeNalu(uint8_t in, NALU &nal) {
|
|||||||
nal.type = in & 0x1f;
|
nal.type = in & 0x1f;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool MakeFU(uint8_t in, FU &fu) {
|
static bool MakeFU(uint8_t in, FU &fu) {
|
||||||
fu.S = in >> 7;
|
fu.S = in >> 7;
|
||||||
fu.E = (in >> 6) & 0x01;
|
fu.E = (in >> 6) & 0x01;
|
||||||
fu.R = (in >> 5) & 0x01;
|
fu.R = (in >> 5) & 0x01;
|
||||||
@ -62,7 +62,6 @@ bool MakeFU(uint8_t in, FU &fu) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
H264RtpDecoder::H264RtpDecoder() {
|
H264RtpDecoder::H264RtpDecoder() {
|
||||||
_h264frame = obtainFrame();
|
_h264frame = obtainFrame();
|
||||||
}
|
}
|
||||||
@ -157,8 +156,10 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
|
|
||||||
void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) {
|
void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) {
|
||||||
//写入环形缓存
|
//写入环形缓存
|
||||||
|
auto lastSeq = _h264frame->sequence;
|
||||||
RtpCodec::inputFrame(frame);
|
RtpCodec::inputFrame(frame);
|
||||||
_h264frame = obtainFrame();
|
_h264frame = obtainFrame();
|
||||||
|
_h264frame->sequence = lastSeq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,41 +28,41 @@
|
|||||||
|
|
||||||
namespace mediakit{
|
namespace mediakit{
|
||||||
|
|
||||||
|
//41
|
||||||
typedef struct {
|
//42 0 1
|
||||||
unsigned forbidden_zero_bit :1;
|
//43 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||||
unsigned nal_ref_idc :2;
|
//44 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
unsigned type :5;
|
//45 |F| Type | LayerId | TID |
|
||||||
} NALU;
|
//46 +-------------+-----------------+
|
||||||
|
//48 F = 0
|
||||||
|
//49 Type = 49 (fragmentation unit (FU))
|
||||||
|
//50 LayerId = 0
|
||||||
|
//51 TID = 1
|
||||||
|
//56 /*
|
||||||
|
//57 create the FU header
|
||||||
|
//58
|
||||||
|
//59 0 1 2 3 4 5 6 7
|
||||||
|
//60 +-+-+-+-+-+-+-+-+
|
||||||
|
//61 |S|E| FuType |
|
||||||
|
//62 +---------------+
|
||||||
|
//63
|
||||||
|
//64 S = variable
|
||||||
|
//65 E = variable
|
||||||
|
//66 FuType = NAL unit type
|
||||||
|
//67
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned S :1;
|
unsigned S :1;
|
||||||
unsigned E :1;
|
unsigned E :1;
|
||||||
unsigned R :1;
|
unsigned type :6;
|
||||||
unsigned type :5;
|
|
||||||
} FU;
|
} FU;
|
||||||
|
|
||||||
bool MakeNalu(uint8_t in, NALU &nal) {
|
static void MakeFU(uint8_t in, FU &fu) {
|
||||||
nal.forbidden_zero_bit = in >> 7;
|
|
||||||
if (nal.forbidden_zero_bit) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
nal.nal_ref_idc = (in & 0x60) >> 5;
|
|
||||||
nal.type = in & 0x1f;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool MakeFU(uint8_t in, FU &fu) {
|
|
||||||
fu.S = in >> 7;
|
fu.S = in >> 7;
|
||||||
fu.E = (in >> 6) & 0x01;
|
fu.E = (in >> 6) & 0x01;
|
||||||
fu.R = (in >> 5) & 0x01;
|
fu.type = in & 0x3f;
|
||||||
fu.type = in & 0x1f;
|
|
||||||
if (fu.R != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
H265RtpDecoder::H265RtpDecoder() {
|
H265RtpDecoder::H265RtpDecoder() {
|
||||||
_h265frame = obtainFrame();
|
_h265frame = obtainFrame();
|
||||||
}
|
}
|
||||||
@ -93,72 +93,72 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
|
|
||||||
const uint8_t *frame = (uint8_t *) rtppack->payload + rtppack->offset;
|
const uint8_t *frame = (uint8_t *) rtppack->payload + rtppack->offset;
|
||||||
int length = rtppack->length - rtppack->offset;
|
int length = rtppack->length - rtppack->offset;
|
||||||
NALU nal;
|
|
||||||
MakeNalu(*frame, nal);
|
|
||||||
|
|
||||||
if (nal.type >= 0 && nal.type < 24) {
|
int nal = H265_TYPE(frame[0]);
|
||||||
//a full frame
|
|
||||||
_h265frame->buffer.assign("\x0\x0\x0\x1", 4);
|
if (nal > 50){
|
||||||
_h265frame->buffer.append((char *)frame, length);
|
WarnL << "不支持该类型的265 RTP包" << nal;
|
||||||
_h265frame->type = nal.type;
|
return false; // packet discard, Unsupported (HEVC) NAL type
|
||||||
_h265frame->timeStamp = rtppack->timeStamp;
|
|
||||||
_h265frame->sequence = rtppack->sequence;
|
|
||||||
auto isIDR = _h265frame->type == 5;
|
|
||||||
onGetH265(_h265frame);
|
|
||||||
return (isIDR); //i frame
|
|
||||||
}
|
}
|
||||||
|
switch (nal) {
|
||||||
|
case 50:
|
||||||
|
case 48: // aggregated packet (AP) - with two or more NAL units
|
||||||
|
WarnL << "不支持该类型的265 RTP包" << nal;
|
||||||
|
return false;
|
||||||
|
case 49: {
|
||||||
|
// fragmentation unit (FU)
|
||||||
|
FU fu;
|
||||||
|
MakeFU(frame[1], fu);
|
||||||
|
if (fu.S == 1) {
|
||||||
|
//FU-A start
|
||||||
|
_h265frame->buffer.assign("\x0\x0\x0\x1", 4);
|
||||||
|
_h265frame->buffer.push_back(fu.type << 1);
|
||||||
|
_h265frame->buffer.push_back(0x01);
|
||||||
|
_h265frame->buffer.append((char *) frame + 2, length - 2);
|
||||||
|
_h265frame->type = fu.type;
|
||||||
|
_h265frame->timeStamp = rtppack->timeStamp;
|
||||||
|
_h265frame->sequence = rtppack->sequence;
|
||||||
|
return (_h265frame->keyFrame()); //i frame
|
||||||
|
}
|
||||||
|
|
||||||
if (nal.type == 28) {
|
if (rtppack->sequence != (uint16_t) (_h265frame->sequence + 1)) {
|
||||||
//FU-A
|
_h265frame->buffer.clear();
|
||||||
FU fu;
|
WarnL << "丢包,帧废弃:" << rtppack->sequence << "," << _h265frame->sequence;
|
||||||
MakeFU(frame[1], fu);
|
return false;
|
||||||
if (fu.S == 1) {
|
}
|
||||||
//FU-A start
|
|
||||||
char tmp = (nal.forbidden_zero_bit << 7 | nal.nal_ref_idc << 5 | fu.type);
|
|
||||||
_h265frame->buffer.assign("\x0\x0\x0\x1", 4);
|
|
||||||
_h265frame->buffer.push_back(tmp);
|
|
||||||
_h265frame->buffer.append((char *)frame + 2, length - 2);
|
|
||||||
_h265frame->type = fu.type;
|
|
||||||
_h265frame->timeStamp = rtppack->timeStamp;
|
|
||||||
_h265frame->sequence = rtppack->sequence;
|
_h265frame->sequence = rtppack->sequence;
|
||||||
return (_h265frame->type == 5); //i frame
|
if (fu.E == 1) {
|
||||||
}
|
//FU-A end
|
||||||
|
_h265frame->buffer.append((char *) frame + 2, length - 2);
|
||||||
if (rtppack->sequence != (uint16_t)(_h265frame->sequence + 1)) {
|
_h265frame->timeStamp = rtppack->timeStamp;
|
||||||
_h265frame->buffer.clear();
|
auto isIDR = _h265frame->keyFrame();
|
||||||
WarnL << "丢包,帧废弃:" << rtppack->sequence << "," << _h265frame->sequence;
|
onGetH265(_h265frame);
|
||||||
|
return isIDR;
|
||||||
|
}
|
||||||
|
//FU-A mid
|
||||||
|
_h265frame->buffer.append((char *) frame + 2, length - 2);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_h265frame->sequence = rtppack->sequence;
|
|
||||||
if (fu.E == 1) {
|
|
||||||
//FU-A end
|
|
||||||
_h265frame->buffer.append((char *)frame + 2, length - 2);
|
|
||||||
_h265frame->timeStamp = rtppack->timeStamp;
|
|
||||||
auto isIDR = _h265frame->type == 5;
|
|
||||||
onGetH265(_h265frame);
|
|
||||||
return isIDR;
|
|
||||||
}
|
|
||||||
//FU-A mid
|
|
||||||
_h265frame->buffer.append((char *)frame + 2, length - 2);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
WarnL << "不支持的rtp类型:" << nal.type << " " << rtppack->sequence;
|
default: // 4.4.1. Single NAL Unit Packets (p24)
|
||||||
return false;
|
//a full frame
|
||||||
// 29 FU-B 单NAL单元B模式
|
_h265frame->buffer.assign("\x0\x0\x0\x1", 4);
|
||||||
// 24 STAP-A 单一时间的组合包
|
_h265frame->buffer.append((char *)frame, length);
|
||||||
// 25 STAP-B 单一时间的组合包
|
_h265frame->type = nal;
|
||||||
// 26 MTAP16 多个时间的组合包
|
_h265frame->timeStamp = rtppack->timeStamp;
|
||||||
// 27 MTAP24 多个时间的组合包
|
_h265frame->sequence = rtppack->sequence;
|
||||||
// 0 udef
|
auto isIDR = _h265frame->keyFrame();
|
||||||
// 30 udef
|
onGetH265(_h265frame);
|
||||||
// 31 udef
|
return (isIDR); //i frame
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void H265RtpDecoder::onGetH265(const H265Frame::Ptr &frame) {
|
void H265RtpDecoder::onGetH265(const H265Frame::Ptr &frame) {
|
||||||
//写入环形缓存
|
//写入环形缓存
|
||||||
|
auto lastSeq = _h265frame->sequence;
|
||||||
RtpCodec::inputFrame(frame);
|
RtpCodec::inputFrame(frame);
|
||||||
_h265frame = obtainFrame();
|
_h265frame = obtainFrame();
|
||||||
|
_h265frame->sequence = lastSeq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user