mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-27 04:35:34 +08:00
[fix] fix h264 rtp packet packetization and depacketization
This commit is contained in:
11
src/rtp/rtp_depacketizer/rtp_depacketizer.cpp
Normal file
11
src/rtp/rtp_depacketizer/rtp_depacketizer.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "rtp_depacketizer.h"
|
||||
|
||||
std::shared_ptr<RtpDepacketizer> Create(uint32_t payload_type, uint8_t* payload,
|
||||
size_t payload_size) {
|
||||
switch (payload_type) {
|
||||
case rtp::PAYLOAD_TYPE::H264:
|
||||
return std::make_shared<RtpDepacketizerH264>(payload, payload_size);
|
||||
case rtp::PAYLOAD_TYPE::AV1:
|
||||
return std::make_shared<RtpDepacketizerAv1>(payload, payload_size);
|
||||
}
|
||||
}
|
||||
25
src/rtp/rtp_depacketizer/rtp_depacketizer.h
Normal file
25
src/rtp/rtp_depacketizer/rtp_depacketizer.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-01-23
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _RTP_DEPACKETIZER_H_
|
||||
#define _RTP_DEPACKETIZER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "rtp_packet.h"
|
||||
|
||||
class RtpDepacketizer {
|
||||
public:
|
||||
static std::shared_ptr<RtpDepacketizer> Create(uint32_t payload_type);
|
||||
|
||||
virtual ~RtpDepacketizer() = default;
|
||||
|
||||
bool Build(uint8_t* payload, uint32_t payload_size) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
9
src/rtp/rtp_depacketizer/rtp_depacketizer_h264.cpp
Normal file
9
src/rtp/rtp_depacketizer/rtp_depacketizer_h264.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "rtp_depacketizer_h264.h"
|
||||
|
||||
RtpDepacketizerH264::RtpDepacketizerH264() {}
|
||||
|
||||
RtpDepacketizerH264::~RtpDepacketizerH264() {}
|
||||
|
||||
bool RtpDepacketizerH264::Parse(uint8_t* payload, uint32_t payload_size) {
|
||||
return true;
|
||||
}
|
||||
25
src/rtp/rtp_depacketizer/rtp_depacketizer_h264.h
Normal file
25
src/rtp/rtp_depacketizer/rtp_depacketizer_h264.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-01-23
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _RTP_DEPACKETIZER_H_
|
||||
#define _RTP_DEPACKETIZER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "rtp_packet.h"
|
||||
|
||||
class RtpDepacketizerH264 {
|
||||
public:
|
||||
RtpDepacketizerH264();
|
||||
|
||||
virtual ~RtpDepacketizerH264() = default;
|
||||
|
||||
bool Parse(uint8_t* payload, uint32_t payload_size);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -15,7 +15,7 @@ constexpr int kObuTypeSequenceHeader = 1;
|
||||
|
||||
using namespace obu;
|
||||
|
||||
RtpCodec::RtpCodec(RtpPacket::PAYLOAD_TYPE payload_type)
|
||||
RtpCodec::RtpCodec(rtp::PAYLOAD_TYPE payload_type)
|
||||
: version_(RTP_VERSION),
|
||||
has_padding_(false),
|
||||
has_extension_(false),
|
||||
@@ -41,7 +41,7 @@ RtpCodec::~RtpCodec() {
|
||||
|
||||
// void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
// std::vector<RtpPacket>& packets) {
|
||||
// if (RtpPacket::PAYLOAD_TYPE::H264 == payload_type_) {
|
||||
// if (rtp::PAYLOAD_TYPE::H264 == payload_type_) {
|
||||
// if (fec_enable_ && IsKeyFrame((const uint8_t*)buffer, size)) {
|
||||
// uint8_t** fec_packets = fec_encoder_.Encode((const char*)buffer, size);
|
||||
// if (nullptr == fec_packets) {
|
||||
@@ -67,7 +67,7 @@ RtpCodec::~RtpCodec() {
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker((index == (num_of_source_packets - 1)) ? 1 :
|
||||
// 0);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_SOURCE);
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE::H264_FEC_SOURCE);
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
// rtp_packet.SetTimestamp(timestamp_);
|
||||
// rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -116,7 +116,7 @@ RtpCodec::~RtpCodec() {
|
||||
// rtp_packet.SetHasPadding(has_padding_);
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(index == num_of_total_packets - 1 ? 1 : 0);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_REPAIR);
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE::H264_FEC_REPAIR);
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
// rtp_packet.SetTimestamp(timestamp_);
|
||||
// rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -149,7 +149,7 @@ RtpCodec::~RtpCodec() {
|
||||
// rtp_packet.SetHasPadding(has_padding_);
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(1);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
|
||||
// timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
@@ -189,7 +189,7 @@ RtpCodec::~RtpCodec() {
|
||||
// rtp_packet.SetHasPadding(has_padding_);
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(index == packet_num - 1 ? 1 : 0);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
// rtp_packet.SetTimestamp(timestamp_);
|
||||
// rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -227,7 +227,7 @@ RtpCodec::~RtpCodec() {
|
||||
// packets.emplace_back(rtp_packet);
|
||||
// }
|
||||
// }
|
||||
// } else if (RtpPacket::PAYLOAD_TYPE::AV1 == payload_type_) {
|
||||
// } else if (rtp::PAYLOAD_TYPE::AV1 == payload_type_) {
|
||||
// std::vector<Obu> obus = ParseObus(buffer, size);
|
||||
// LOG_ERROR("Total size = [{}]", size);
|
||||
// for (int i = 0; i < obus.size(); i++) {
|
||||
@@ -239,7 +239,7 @@ RtpCodec::~RtpCodec() {
|
||||
// rtp_packet.SetHasPadding(has_padding_);
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(1);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
|
||||
// timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
@@ -275,7 +275,7 @@ RtpCodec::~RtpCodec() {
|
||||
// rtp_packet.SetHasPadding(has_padding_);
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(index == packet_num - 1 ? 1 : 0);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
// rtp_packet.SetTimestamp(timestamp_);
|
||||
// rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -306,13 +306,13 @@ RtpCodec::~RtpCodec() {
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else if (RtpPacket::PAYLOAD_TYPE::OPUS == payload_type_) {
|
||||
// } else if (rtp::PAYLOAD_TYPE::OPUS == payload_type_) {
|
||||
// RtpPacket rtp_packet;
|
||||
// rtp_packet.SetVerion(version_);
|
||||
// rtp_packet.SetHasPadding(has_padding_);
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(1);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
|
||||
// timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
@@ -323,13 +323,13 @@ RtpCodec::~RtpCodec() {
|
||||
|
||||
// rtp_packet.Encode(buffer, size);
|
||||
// packets.emplace_back(rtp_packet);
|
||||
// } else if (RtpPacket::PAYLOAD_TYPE::DATA == payload_type_) {
|
||||
// } else if (rtp::PAYLOAD_TYPE::DATA == payload_type_) {
|
||||
// RtpPacket rtp_packet;
|
||||
// rtp_packet.SetVerion(version_);
|
||||
// rtp_packet.SetHasPadding(has_padding_);
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(1);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
|
||||
// timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
@@ -345,7 +345,7 @@ RtpCodec::~RtpCodec() {
|
||||
|
||||
void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
std::vector<RtpPacket>& packets) {
|
||||
if (RtpPacket::PAYLOAD_TYPE::H264 == payload_type_) {
|
||||
if (rtp::PAYLOAD_TYPE::H264 == payload_type_) {
|
||||
if (fec_enable_ && IsKeyFrame((const uint8_t*)buffer, size)) {
|
||||
uint8_t** fec_packets = fec_encoder_.Encode((const char*)buffer, size);
|
||||
if (nullptr == fec_packets) {
|
||||
@@ -369,7 +369,7 @@ void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
rtp_packet.SetHasPadding(has_padding_);
|
||||
rtp_packet.SetHasExtension(has_extension_);
|
||||
rtp_packet.SetMarker(index == num_of_source_packets - 1 ? 1 : 0);
|
||||
rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_SOURCE);
|
||||
rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE::H264_FEC_SOURCE);
|
||||
rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
rtp_packet.SetTimestamp(timestamp_);
|
||||
rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -383,12 +383,12 @@ void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
rtp_packet.SetExtensionData(extension_data_, extension_len_);
|
||||
}
|
||||
|
||||
RtpPacket::FU_INDICATOR fu_indicator;
|
||||
rtp::FU_INDICATOR fu_indicator;
|
||||
fu_indicator.forbidden_bit = 0;
|
||||
fu_indicator.nal_reference_idc = 0;
|
||||
fu_indicator.nal_unit_type = FU_A;
|
||||
|
||||
RtpPacket::FU_HEADER fu_header;
|
||||
rtp::FU_HEADER fu_header;
|
||||
fu_header.start = index == 0 ? 1 : 0;
|
||||
fu_header.end = index == num_of_source_packets - 1 ? 1 : 0;
|
||||
fu_header.remain_bit = 0;
|
||||
@@ -417,7 +417,7 @@ void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
rtp_packet.SetHasPadding(has_padding_);
|
||||
rtp_packet.SetHasExtension(has_extension_);
|
||||
rtp_packet.SetMarker(index == num_of_total_packets - 1 ? 1 : 0);
|
||||
rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_REPAIR);
|
||||
rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE::H264_FEC_REPAIR);
|
||||
rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
rtp_packet.SetTimestamp(timestamp_);
|
||||
rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -459,7 +459,7 @@ void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
|
||||
rtp_packet.SetHasExtension(has_extension_);
|
||||
rtp_packet.SetMarker(1);
|
||||
rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
|
||||
timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
@@ -478,7 +478,7 @@ void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
rtp_packet.SetExtensionData(extension_data_, extension_len_);
|
||||
}
|
||||
|
||||
RtpPacket::FU_INDICATOR fu_indicator;
|
||||
rtp::FU_INDICATOR fu_indicator;
|
||||
fu_indicator.forbidden_bit = 0;
|
||||
fu_indicator.nal_reference_idc = 1;
|
||||
fu_indicator.nal_unit_type = NALU;
|
||||
@@ -508,7 +508,7 @@ void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
|
||||
rtp_packet.SetHasExtension(has_extension_);
|
||||
rtp_packet.SetMarker(index == packet_num - 1 ? 1 : 0);
|
||||
rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
rtp_packet.SetTimestamp(timestamp_);
|
||||
rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -522,12 +522,12 @@ void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
rtp_packet.SetExtensionData(extension_data_, extension_len_);
|
||||
}
|
||||
|
||||
RtpPacket::FU_INDICATOR fu_indicator;
|
||||
rtp::FU_INDICATOR fu_indicator;
|
||||
fu_indicator.forbidden_bit = 0;
|
||||
fu_indicator.nal_reference_idc = 0;
|
||||
fu_indicator.nal_unit_type = FU_A;
|
||||
|
||||
RtpPacket::FU_HEADER fu_header;
|
||||
rtp::FU_HEADER fu_header;
|
||||
fu_header.start = index == 0 ? 1 : 0;
|
||||
fu_header.end = index == packet_num - 1 ? 1 : 0;
|
||||
fu_header.remain_bit = 0;
|
||||
@@ -545,7 +545,7 @@ void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
packets.emplace_back(rtp_packet);
|
||||
}
|
||||
}
|
||||
} else if (RtpPacket::PAYLOAD_TYPE::AV1 == payload_type_) {
|
||||
} else if (rtp::PAYLOAD_TYPE::AV1 == payload_type_) {
|
||||
std::vector<Obu> obus = ParseObus(buffer, size);
|
||||
uint64_t timestamp =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
@@ -567,7 +567,7 @@ void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
|
||||
rtp_packet.SetHasExtension(has_extension_);
|
||||
rtp_packet.SetMarker(1);
|
||||
rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
rtp_packet.SetTimestamp(timestamp);
|
||||
rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -603,7 +603,7 @@ void RtpCodec::Encode(uint8_t* buffer, uint32_t size,
|
||||
|
||||
rtp_packet.SetHasExtension(has_extension_);
|
||||
rtp_packet.SetMarker(index == packet_num - 1 ? 1 : 0);
|
||||
rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
rtp_packet.SetTimestamp(timestamp);
|
||||
rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -17,7 +17,7 @@ class RtpCodec {
|
||||
};
|
||||
|
||||
public:
|
||||
RtpCodec(RtpPacket::PAYLOAD_TYPE payload_type);
|
||||
RtpCodec(rtp::PAYLOAD_TYPE payload_type);
|
||||
~RtpCodec();
|
||||
|
||||
public:
|
||||
@@ -29,7 +29,7 @@
|
||||
// rtp_packet.SetHasPadding(has_padding_);
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(1);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
// rtp_packet.SetTimestamp(timestamp);
|
||||
// rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -58,7 +58,7 @@
|
||||
// rtp_packet.SetHasPadding(has_padding_);
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(index == packet_num - 1 ? 1 : 0);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
// rtp_packet.SetTimestamp(timestamp);
|
||||
// rtp_packet.SetSsrc(ssrc_);
|
||||
43
src/rtp/rtp_packet/rtp_defines.h
Normal file
43
src/rtp/rtp_packet/rtp_defines.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-01-23
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _RTP_DEFINES_H_
|
||||
#define _RTP_DEFINES_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#define DEFAULT_MTU 1500
|
||||
#define MAX_NALU_LEN 1400
|
||||
|
||||
namespace rtp {
|
||||
|
||||
typedef enum {
|
||||
UNDEFINED = 0,
|
||||
H264 = 96,
|
||||
H264_FEC_SOURCE = 97,
|
||||
H264_FEC_REPAIR = 98,
|
||||
AV1 = 99,
|
||||
OPUS = 111,
|
||||
DATA = 127
|
||||
} PAYLOAD_TYPE;
|
||||
|
||||
typedef struct {
|
||||
uint8_t forbidden_bit : 1;
|
||||
uint8_t nal_reference_idc : 2;
|
||||
uint8_t nal_unit_type : 5;
|
||||
} FU_INDICATOR;
|
||||
|
||||
typedef struct {
|
||||
uint8_t start : 1;
|
||||
uint8_t end : 1;
|
||||
uint8_t remain_bit : 1;
|
||||
uint8_t nal_unit_type : 5;
|
||||
} FU_HEADER;
|
||||
|
||||
typedef enum { UNKNOWN = 0, NALU = 1, FU_A = 28, FU_B = 29 } NAL_UNIT_TYPE;
|
||||
} // namespace rtp
|
||||
#endif
|
||||
@@ -54,7 +54,7 @@ struct RTPHeader {
|
||||
uint16_t sequence_number_ = 1;
|
||||
uint64_t timestamp_ = 0;
|
||||
uint32_t ssrc_ = 0;
|
||||
uint32_t csrcs_[kRtpCsrcSize];
|
||||
uint32_t csrcs_[kMaxRtpCsrcSize];
|
||||
size_t padding_len;
|
||||
size_t header_len;
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
RtpPacket::RtpPacket() {}
|
||||
|
||||
RtpPacket::RtpPacket(size_t size) : buffer_(size) {}
|
||||
|
||||
RtpPacket::RtpPacket(const RtpPacket &rtp_packet) = default;
|
||||
|
||||
RtpPacket::RtpPacket(RtpPacket &&rtp_packet) = default;
|
||||
@@ -15,12 +17,13 @@ RtpPacket &RtpPacket::operator=(RtpPacket &&rtp_packet) = default;
|
||||
RtpPacket::~RtpPacket() = default;
|
||||
|
||||
bool RtpPacket::Build(const uint8_t *buffer, uint32_t size) {
|
||||
if (size > 0) {
|
||||
buffer_.SetData(buffer, size);
|
||||
size_ = size;
|
||||
return true;
|
||||
if (!Parse(buffer, size)) {
|
||||
LOG_WARN("RtpPacket::Build: parse failed");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
buffer_.SetData(buffer, size);
|
||||
size_ = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RtpPacket::Parse(const uint8_t *buffer, uint32_t size) {
|
||||
@@ -30,36 +33,40 @@ bool RtpPacket::Parse(const uint8_t *buffer, uint32_t size) {
|
||||
}
|
||||
|
||||
// 1st byte
|
||||
version_ = (buffer_[payload_offset_] >> 6) & 0x03;
|
||||
version_ = (buffer[payload_offset_] >> 6) & 0x03;
|
||||
if (version_ != kRtpVersion) {
|
||||
LOG_WARN("RtpPacket::Parse: version is not qual to kRtpVersion");
|
||||
return false;
|
||||
}
|
||||
has_padding_ = (buffer_[payload_offset_] >> 5) & 0x01;
|
||||
has_extension_ = (buffer_[payload_offset_] >> 4) & 0x01;
|
||||
csrc_count_ = buffer_[payload_offset_] & 0x0f;
|
||||
has_padding_ = (buffer[payload_offset_] >> 5) & 0x01;
|
||||
has_extension_ = (buffer[payload_offset_] >> 4) & 0x01;
|
||||
csrc_count_ = buffer[payload_offset_] & 0x0f;
|
||||
if (csrc_count_ > kMaxRtpCsrcSize) {
|
||||
LOG_WARN("RtpPacket::Parse: csrc count is too large");
|
||||
return false;
|
||||
}
|
||||
payload_offset_++;
|
||||
|
||||
// 2nd byte
|
||||
marker_ = (buffer_[payload_offset_] >> 7) & 0x01;
|
||||
payload_type_ = buffer_[payload_offset_] & 0x7f;
|
||||
marker_ = (buffer[payload_offset_] >> 7) & 0x01;
|
||||
payload_type_ = buffer[payload_offset_] & 0x7f;
|
||||
payload_offset_ += 1;
|
||||
|
||||
// 3rd byte and 4th byte
|
||||
sequence_number_ =
|
||||
(buffer_[payload_offset_] << 8) | buffer_[payload_offset_ + 1];
|
||||
(buffer[payload_offset_] << 8) | buffer[payload_offset_ + 1];
|
||||
payload_offset_ += 2;
|
||||
|
||||
// 5th byte to 8th byte
|
||||
timestamp_ =
|
||||
(buffer_[payload_offset_] << 24) | (buffer_[payload_offset_ + 1] << 16) |
|
||||
(buffer_[payload_offset_ + 2] << 8) | buffer_[payload_offset_ + 3];
|
||||
timestamp_ = (buffer[payload_offset_] << 24) |
|
||||
(buffer[payload_offset_ + 1] << 16) |
|
||||
(buffer[payload_offset_ + 2] << 8) | buffer[payload_offset_ + 3];
|
||||
payload_offset_ += 4;
|
||||
|
||||
// 9th byte to 12th byte
|
||||
ssrc_ = (buffer_[payload_offset_] << 24) |
|
||||
(buffer_[payload_offset_ + 1] << 16) |
|
||||
(buffer_[payload_offset_ + 2] << 8) | buffer_[payload_offset_ + 3];
|
||||
ssrc_ = (buffer[payload_offset_] << 24) |
|
||||
(buffer[payload_offset_ + 1] << 16) |
|
||||
(buffer[payload_offset_ + 2] << 8) | buffer[payload_offset_ + 3];
|
||||
|
||||
payload_offset_ = kFixedHeaderSize;
|
||||
|
||||
@@ -68,11 +75,11 @@ bool RtpPacket::Parse(const uint8_t *buffer, uint32_t size) {
|
||||
return false;
|
||||
}
|
||||
// csrc
|
||||
for (uint32_t csrc_index = 0; i < csrc_count_; i++) {
|
||||
uint32_t csrc = (buffer_[payload_offset_ + csrc_index * 4] << 24) |
|
||||
(buffer_[payload_offset_ + 1 + csrc_index * 4] << 16) |
|
||||
(buffer_[payload_offset_ + 2 + csrc_index * 4] << 8) |
|
||||
buffer_[payload_offset_ + 3 + csrc_index * 4];
|
||||
for (uint32_t csrc_index = 0; csrc_index < csrc_count_; csrc_index++) {
|
||||
uint32_t csrc = (buffer[payload_offset_ + csrc_index * 4] << 24) |
|
||||
(buffer[payload_offset_ + 1 + csrc_index * 4] << 16) |
|
||||
(buffer[payload_offset_ + 2 + csrc_index * 4] << 8) |
|
||||
buffer[payload_offset_ + 3 + csrc_index * 4];
|
||||
csrcs_.push_back(csrc);
|
||||
}
|
||||
|
||||
@@ -89,28 +96,30 @@ bool RtpPacket::Parse(const uint8_t *buffer, uint32_t size) {
|
||||
return false;
|
||||
}
|
||||
extension_profile_ =
|
||||
(buffer_[payload_offset_] << 8) | buffer_[payload_offset_ + 1];
|
||||
(buffer[payload_offset_] << 8) | buffer[payload_offset_ + 1];
|
||||
extension_len_ =
|
||||
(buffer_[payload_offset_ + 2] << 8) | buffer_[payload_offset_ + 3];
|
||||
(buffer[payload_offset_ + 2] << 8) | buffer[payload_offset_ + 3];
|
||||
|
||||
if (payload_offset_ + 4 + extension_len_ > size) {
|
||||
if (payload_offset_ + extension_len_ > size) {
|
||||
LOG_WARN("RtpPacket::Parse: extension len is too large");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t offset = payload_offset_ + 4;
|
||||
while (offset < size && extension_len_ > 0) {
|
||||
uint8_t id = buffer_[offset] >> 4;
|
||||
uint8_t len = (buffer_[offset] & 0x0F) + 1;
|
||||
uint8_t id = buffer[offset] >> 4;
|
||||
uint8_t len = (buffer[offset] & 0x0F) + 1;
|
||||
if (offset + 1 + len > size) {
|
||||
break;
|
||||
}
|
||||
extensions_.push_back(
|
||||
{id, std::vector<uint8_t>(buffer_ + offset + 1,
|
||||
buffer_ + offset + 1 + len)});
|
||||
Extension extension;
|
||||
extension.id = id;
|
||||
extension.data =
|
||||
std::vector<uint8_t>(buffer + offset + 1, buffer + offset + 1 + len);
|
||||
extensions_.push_back(extension);
|
||||
offset += 1 + len;
|
||||
}
|
||||
payload_offset_ += (4 + extension_len_);
|
||||
payload_offset_ += extension_len_;
|
||||
}
|
||||
|
||||
if (has_padding_ && payload_offset_ < size) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "copy_on_write_buffer.h"
|
||||
#include "log.h"
|
||||
#include "rtp_defines.h"
|
||||
#include "rtp_header.h"
|
||||
|
||||
// Common
|
||||
@@ -170,25 +171,14 @@
|
||||
#define DEFAULT_MTU 1500
|
||||
#define MAX_NALU_LEN 1400
|
||||
|
||||
constexpr uint16_t kOneByteExtensionProfileId = 0xBEDE;
|
||||
constexpr uint16_t kTwoByteExtensionProfileId = 0x1000;
|
||||
constexpr size_t kFixedHeaderSize = 12;
|
||||
|
||||
class RtpPacket {
|
||||
public:
|
||||
typedef enum {
|
||||
UNDEFINED = 0,
|
||||
H264 = 96,
|
||||
H264_FEC_SOURCE = 97,
|
||||
H264_FEC_REPAIR = 98,
|
||||
AV1 = 99,
|
||||
OPUS = 111,
|
||||
DATA = 127
|
||||
} PAYLOAD_TYPE;
|
||||
|
||||
constexpr uint16_t kOneByteExtensionProfileId = 0xBEDE;
|
||||
constexpr uint16_t kTwoByteExtensionProfileId = 0x1000;
|
||||
|
||||
constexpr size_t kFixedHeaderSize = 12;
|
||||
|
||||
public:
|
||||
RtpPacket();
|
||||
RtpPacket(size_t size);
|
||||
RtpPacket(const RtpPacket &rtp_packet);
|
||||
RtpPacket(RtpPacket &&rtp_packet);
|
||||
RtpPacket &operator=(const RtpPacket &rtp_packet);
|
||||
@@ -199,13 +189,16 @@ class RtpPacket {
|
||||
public:
|
||||
bool Build(const uint8_t *buffer, uint32_t size);
|
||||
|
||||
private:
|
||||
bool Parse(const uint8_t *buffer, uint32_t size);
|
||||
|
||||
public:
|
||||
// Set Header
|
||||
void SetVerion(uint8_t version) { version_ = version; }
|
||||
void SetHasPadding(bool has_padding) { has_padding_ = has_padding; }
|
||||
void SetHasExtension(bool has_extension) { has_extension_ = has_extension; }
|
||||
void SetMarker(bool marker) { marker_ = marker; }
|
||||
void SetPayloadType(PAYLOAD_TYPE payload_type) {
|
||||
void SetPayloadType(rtp::PAYLOAD_TYPE payload_type) {
|
||||
payload_type_ = (uint8_t)payload_type;
|
||||
}
|
||||
void SetSequenceNumber(uint16_t sequence_number) {
|
||||
@@ -220,47 +213,54 @@ class RtpPacket {
|
||||
// bits
|
||||
abs_send_time &= 0x00FFFFFF;
|
||||
|
||||
// Allocate memory for the extension data if not already allocated
|
||||
if (extension_data_ == nullptr) {
|
||||
extension_data_ =
|
||||
(uint8_t *)malloc(5); // 2 bytes for profile, 2 bytes for length, 3
|
||||
// bytes for abs_send_time
|
||||
extension_len_ = 5;
|
||||
}
|
||||
|
||||
// Set the extension profile to 0xBEDE (one-byte header)
|
||||
extension_profile_ = kOneByteExtensionProfileId;
|
||||
extension_len_ = 5; // 2 bytes for profile, 2 bytes for length, 3 bytes for
|
||||
// abs_send_time
|
||||
|
||||
// Set the length of the extension data (in 32-bit words minus one)
|
||||
extension_data_[0] = 0x00;
|
||||
extension_data_[1] = 0x02; // 2 words (8 bytes)
|
||||
|
||||
// Set the absolute send time in the extension data
|
||||
extension_data_[2] = (abs_send_time >> 16) & 0xFF;
|
||||
extension_data_[3] = (abs_send_time >> 8) & 0xFF;
|
||||
extension_data_[4] = abs_send_time & 0xFF;
|
||||
Extension extension;
|
||||
extension.id = 0;
|
||||
extension.len = 2;
|
||||
extension.data.push_back(extension.id << 4 | extension.len);
|
||||
extension.data.push_back((abs_send_time >> 16) & 0xFF);
|
||||
extension.data.push_back((abs_send_time >> 8) & 0xFF);
|
||||
extension.data.push_back(abs_send_time & 0xFF);
|
||||
}
|
||||
|
||||
public:
|
||||
// Get Header
|
||||
uint32_t Verion() const { return version_; }
|
||||
uint32_t Version() const { return version_; }
|
||||
bool HasPadding() const { return has_padding_; }
|
||||
bool HasExtension() const { return has_extension_; }
|
||||
bool Marker() const { return marker_; }
|
||||
PAYLOAD_TYPE PayloadType() const { return PAYLOAD_TYPE(payload_type_); }
|
||||
rtp::PAYLOAD_TYPE PayloadType() const {
|
||||
return rtp::PAYLOAD_TYPE(payload_type_);
|
||||
}
|
||||
uint16_t SequenceNumber() const { return sequence_number_; }
|
||||
uint64_t Timestamp() const { return timestamp_; }
|
||||
uint32_t Ssrc() const { return ssrc_; }
|
||||
std::vector<uint32_t> Csrcs() const { return csrcs_; };
|
||||
uint16_t ExtensionProfile() const { return extension_profile_; }
|
||||
const uint8_t *ExtensionData() { return extension_data_; }
|
||||
|
||||
uint32_t GetAbsoluteSendTimestamp(uint32_t *abs_send_time) const {
|
||||
if (!extensions_.empty()) {
|
||||
for (auto &ext : extensions_) {
|
||||
if (ext.id == 1) {
|
||||
*abs_send_time = (ext.data[0] << 16) | (ext.data[1] << 8) |
|
||||
ext.data[2]; // 24-bit value
|
||||
return *abs_send_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Payload
|
||||
const uint8_t *Payload() { return Buffer() + payload_offset_; };
|
||||
const uint8_t *Payload() { return Buffer().data() + payload_offset_; };
|
||||
size_t PayloadSize() { return payload_size_; }
|
||||
|
||||
// Entire RTP buffer
|
||||
const uint8_t *Buffer() const { return buffer_; }
|
||||
CopyOnWriteBuffer Buffer() const { return buffer_; }
|
||||
size_t Size() const { return size_; }
|
||||
|
||||
// For webrtc module use
|
||||
@@ -288,6 +288,7 @@ class RtpPacket {
|
||||
uint16_t extension_len_ = 0;
|
||||
struct Extension {
|
||||
uint8_t id;
|
||||
uint8_t len;
|
||||
std::vector<uint8_t> data;
|
||||
};
|
||||
std::vector<Extension> extensions_;
|
||||
@@ -300,15 +301,8 @@ class RtpPacket {
|
||||
size_t padding_size_ = 0;
|
||||
|
||||
// Entire rtp buffer
|
||||
CopyOnWriteBuffer buffer_ = nullptr;
|
||||
CopyOnWriteBuffer buffer_;
|
||||
size_t size_ = 0;
|
||||
|
||||
// H.264 header
|
||||
FU_INDICATOR fu_indicator_;
|
||||
FU_HEADER fu_header_;
|
||||
uint8_t fec_symbol_id_ = 0;
|
||||
uint8_t fec_source_symbol_num_ = 0;
|
||||
uint8_t av1_aggr_header_ = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
16
src/rtp/rtp_packet/rtp_packet_av1.cpp
Normal file
16
src/rtp/rtp_packet/rtp_packet_av1.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "rtp_packet_av1.h"
|
||||
|
||||
RtpPacketAv1::RtpPacketAv1() {}
|
||||
|
||||
RtpPacketAv1::~RtpPacketAv1() {}
|
||||
|
||||
bool RtpPacketAv1::GetFrameHeaderInfo() {
|
||||
const uint8_t* frame_buffer = Payload();
|
||||
av1_aggr_header_ = frame_buffer[0];
|
||||
z_ = av1_aggr_header_ >> 7;
|
||||
y_ = av1_aggr_header_ >> 6 & 0x01;
|
||||
w_ = av1_aggr_header_ >> 4 & 0x03;
|
||||
n_ = av1_aggr_header_ >> 3 & 0x01;
|
||||
|
||||
return true;
|
||||
}
|
||||
52
src/rtp/rtp_packet/rtp_packet_av1.h
Normal file
52
src/rtp/rtp_packet/rtp_packet_av1.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-01-23
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _RTP_PACKET_AV1_H_
|
||||
#define _RTP_PACKET_AV1_H_
|
||||
|
||||
#include "rtp_packet.h"
|
||||
|
||||
class RtpPacketAv1 : public RtpPacket {
|
||||
public:
|
||||
RtpPacketAv1();
|
||||
virtual ~RtpPacketAv1();
|
||||
|
||||
public:
|
||||
bool GetFrameHeaderInfo();
|
||||
|
||||
bool Av1FrameStart() {
|
||||
// return !z_ && !y_;
|
||||
|
||||
if (z_ == 0 && y_ == 0 && w_ == 1) {
|
||||
return true;
|
||||
} else if (z_ == 0 && y_ == 1 && w_ == 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Av1FrameEnd() {
|
||||
// return z_ && !y_;
|
||||
|
||||
if (z_ == 0 && y_ == 0 && w_ == 1) {
|
||||
return true;
|
||||
} else if (z_ == 1 && y_ == 0 && w_ == 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t av1_aggr_header_ = 0;
|
||||
uint8_t z_ = 0;
|
||||
uint8_t y_ = 0;
|
||||
uint8_t w_ = 0;
|
||||
uint8_t n_ = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
20
src/rtp/rtp_packet/rtp_packet_h264.cpp
Normal file
20
src/rtp/rtp_packet/rtp_packet_h264.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "rtp_packet_h264.h"
|
||||
|
||||
RtpPacketH264::RtpPacketH264() {}
|
||||
|
||||
RtpPacketH264::~RtpPacketH264() {}
|
||||
|
||||
bool RtpPacketH264::GetFrameHeaderInfo() {
|
||||
const uint8_t* frame_buffer = Payload();
|
||||
|
||||
fu_indicator_.forbidden_bit = (frame_buffer[0] >> 7) & 0x01;
|
||||
fu_indicator_.nal_reference_idc = (frame_buffer[0] >> 5) & 0x03;
|
||||
fu_indicator_.nal_unit_type = frame_buffer[0] & 0x1F;
|
||||
|
||||
fu_header_.start = (frame_buffer[1] >> 7) & 0x01;
|
||||
fu_header_.end = (frame_buffer[1] >> 6) & 0x01;
|
||||
fu_header_.remain_bit = (frame_buffer[1] >> 5) & 0x01;
|
||||
fu_header_.nal_unit_type = frame_buffer[1] & 0x1F;
|
||||
|
||||
return true;
|
||||
}
|
||||
31
src/rtp/rtp_packet/rtp_packet_h264.h
Normal file
31
src/rtp/rtp_packet/rtp_packet_h264.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-01-23
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _RTP_PACKET_H264_H_
|
||||
#define _RTP_PACKET_H264_H_
|
||||
|
||||
#include "rtp_packet.h"
|
||||
|
||||
class RtpPacketH264 : public RtpPacket {
|
||||
public:
|
||||
RtpPacketH264();
|
||||
virtual ~RtpPacketH264();
|
||||
|
||||
public:
|
||||
bool GetFrameHeaderInfo();
|
||||
// NAL
|
||||
rtp::NAL_UNIT_TYPE NalUnitType() {
|
||||
return rtp::NAL_UNIT_TYPE(fu_indicator_.nal_unit_type);
|
||||
}
|
||||
bool FuAStart() { return fu_header_.start; }
|
||||
bool FuAEnd() { return fu_header_.end; }
|
||||
|
||||
private:
|
||||
rtp::FU_INDICATOR fu_indicator_;
|
||||
rtp::FU_HEADER fu_header_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -33,7 +33,7 @@ RtpPacketReceived& RtpPacketReceived::operator=(RtpPacketReceived&& packet) =
|
||||
RtpPacketReceived::~RtpPacketReceived() {}
|
||||
|
||||
void RtpPacketReceived::GetHeader(RTPHeader* header) const {
|
||||
header->version = Version();
|
||||
header->version_ = Version();
|
||||
header->has_padding_ = HasPadding();
|
||||
header->has_extension_ = HasExtension();
|
||||
header->csrc_count_ = Csrcs().size();
|
||||
@@ -44,7 +44,7 @@ void RtpPacketReceived::GetHeader(RTPHeader* header) const {
|
||||
header->ssrc_ = Ssrc();
|
||||
std::vector<uint32_t> csrcs = Csrcs();
|
||||
for (size_t i = 0; i < csrcs.size(); ++i) {
|
||||
header->csrc_[i] = csrcs[i];
|
||||
header->csrcs_[i] = csrcs[i];
|
||||
}
|
||||
header->padding_len = padding_size();
|
||||
header->header_len = headers_size();
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
#include "rtp_packetizer.h"
|
||||
|
||||
std::unique_ptr<RtpPacketizer> Create(uint32_t payload_type, uint8_t* payload,
|
||||
size_t payload_size) {
|
||||
#include "rtp_packetizer_av1.h"
|
||||
#include "rtp_packetizer_generic.h"
|
||||
#include "rtp_packetizer_h264.h"
|
||||
|
||||
std::unique_ptr<RtpPacketizer> RtpPacketizer::Create(uint32_t payload_type) {
|
||||
switch (payload_type) {
|
||||
case RtpPacket::PAYLOAD_TYPE::H264:
|
||||
return std::make_unique<RtpPacketizerH264>(payload, payload_size);
|
||||
case RtpPacket::PAYLOAD_TYPE::AV1:
|
||||
return std::make_unique<RtpPacketizerAv1>(payload, payload_size);
|
||||
case rtp::PAYLOAD_TYPE::H264:
|
||||
return std::make_unique<RtpPacketizerH264>();
|
||||
case rtp::PAYLOAD_TYPE::AV1:
|
||||
return std::make_unique<RtpPacketizerAv1>();
|
||||
default:
|
||||
return std::make_unique<RtpPacketizerGeneric>();
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,8 @@ class RtpPacketizer {
|
||||
|
||||
virtual ~RtpPacketizer() = default;
|
||||
|
||||
bool Build(uint8_t* payload, uint32_t payload_size) = 0;
|
||||
virtual std::vector<RtpPacket> Build(uint8_t* payload,
|
||||
uint32_t payload_size) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "rtp_packetizer_av1.h"
|
||||
|
||||
RtpPacketizerAv1::RtpPacketizerAv1() {}
|
||||
|
||||
RtpPacketizerAv1::~RtpPacketizerAv1() {}
|
||||
|
||||
std::vector<RtpPacket> RtpPacketizerAv1::Build(uint8_t* payload,
|
||||
uint32_t payload_size) {
|
||||
std::vector<RtpPacket> rtp_packets;
|
||||
return rtp_packets;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-01-23
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _RTP_PACKETIZER_AV1_H_
|
||||
#define _RTP_PACKETIZER_AV1_H_
|
||||
|
||||
#include "rtp_packetizer.h"
|
||||
|
||||
class RtpPacketizerAv1 : public RtpPacketizer {
|
||||
public:
|
||||
RtpPacketizerAv1();
|
||||
|
||||
virtual ~RtpPacketizerAv1();
|
||||
|
||||
std::vector<RtpPacket> Build(uint8_t* payload,
|
||||
uint32_t payload_size) override;
|
||||
|
||||
private:
|
||||
uint8_t version_;
|
||||
bool has_padding_;
|
||||
bool has_extension_;
|
||||
uint32_t csrc_count_;
|
||||
bool marker_;
|
||||
uint32_t payload_type_;
|
||||
uint16_t sequence_number_;
|
||||
uint64_t timestamp_;
|
||||
uint32_t ssrc_;
|
||||
std::vector<uint32_t> csrcs_;
|
||||
uint16_t profile_;
|
||||
uint16_t extension_profile_;
|
||||
uint16_t extension_len_;
|
||||
uint8_t* extension_data_;
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> rtp_packet_frame_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
#include "rtp_packetizer_generic.h"
|
||||
|
||||
RtpPacketizerGeneric::RtpPacketizerGeneric()
|
||||
: version_(kRtpVersion),
|
||||
has_padding_(false),
|
||||
has_extension_(true),
|
||||
csrc_count_(0),
|
||||
marker_(false),
|
||||
payload_type_(rtp::PAYLOAD_TYPE::DATA),
|
||||
sequence_number_(1),
|
||||
timestamp_(0),
|
||||
ssrc_(0),
|
||||
profile_(0),
|
||||
extension_profile_(0),
|
||||
extension_len_(0),
|
||||
extension_data_(nullptr) {}
|
||||
|
||||
RtpPacketizerGeneric::~RtpPacketizerGeneric() {}
|
||||
|
||||
std::vector<RtpPacket> RtpPacketizerGeneric::Build(uint8_t* payload,
|
||||
uint32_t payload_size) {
|
||||
uint32_t last_packet_size = payload_size % MAX_NALU_LEN;
|
||||
uint32_t packet_num =
|
||||
payload_size / MAX_NALU_LEN + (last_packet_size ? 1 : 0);
|
||||
|
||||
// TODO: use frame timestamp
|
||||
timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
|
||||
std::vector<RtpPacket> rtp_packets;
|
||||
for (uint32_t index = 0; index < packet_num; index++) {
|
||||
version_ = kRtpVersion;
|
||||
has_padding_ = false;
|
||||
has_extension_ = true;
|
||||
csrc_count_ = 0;
|
||||
marker_ = index == packet_num - 1 ? 1 : 0;
|
||||
payload_type_ = rtp::PAYLOAD_TYPE(payload_type_);
|
||||
sequence_number_++;
|
||||
timestamp_ = timestamp_;
|
||||
ssrc_ = ssrc_;
|
||||
|
||||
if (!csrc_count_) {
|
||||
csrcs_ = csrcs_;
|
||||
}
|
||||
|
||||
rtp_packet_frame_.clear();
|
||||
rtp_packet_frame_.push_back((version_ << 6) | (has_padding_ << 5) |
|
||||
(has_extension_ << 4) | csrc_count_);
|
||||
rtp_packet_frame_.push_back((marker_ << 7) | payload_type_);
|
||||
rtp_packet_frame_.push_back((sequence_number_ >> 8) & 0xFF);
|
||||
rtp_packet_frame_.push_back(sequence_number_ & 0xFF);
|
||||
rtp_packet_frame_.push_back((timestamp_ >> 24) & 0xFF);
|
||||
rtp_packet_frame_.push_back((timestamp_ >> 16) & 0xFF);
|
||||
rtp_packet_frame_.push_back((timestamp_ >> 8) & 0xFF);
|
||||
rtp_packet_frame_.push_back(timestamp_ & 0xFF);
|
||||
rtp_packet_frame_.push_back((ssrc_ >> 24) & 0xFF);
|
||||
rtp_packet_frame_.push_back((ssrc_ >> 16) & 0xFF);
|
||||
rtp_packet_frame_.push_back((ssrc_ >> 8) & 0xFF);
|
||||
rtp_packet_frame_.push_back(ssrc_ & 0xFF);
|
||||
|
||||
for (uint32_t index = 0; index < csrc_count_ && !csrcs_.empty(); index++) {
|
||||
rtp_packet_frame_.push_back((csrcs_[index] >> 24) & 0xFF);
|
||||
rtp_packet_frame_.push_back((csrcs_[index] >> 16) & 0xFF);
|
||||
rtp_packet_frame_.push_back((csrcs_[index] >> 8) & 0xFF);
|
||||
rtp_packet_frame_.push_back(csrcs_[index] & 0xFF);
|
||||
}
|
||||
|
||||
if (has_extension_) {
|
||||
extension_profile_ = kOneByteExtensionProfileId;
|
||||
extension_len_ = 5; // 2 bytes for profile, 2 bytes for length, 3 bytes
|
||||
// for abs_send_time
|
||||
|
||||
uint32_t abs_send_time =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
|
||||
abs_send_time &= 0x00FFFFFF;
|
||||
|
||||
uint8_t sub_extension_id = 0;
|
||||
uint8_t sub_extension_len = 2;
|
||||
|
||||
rtp_packet_frame_.push_back(extension_profile_ >> 8);
|
||||
rtp_packet_frame_.push_back(extension_profile_ & 0xff);
|
||||
rtp_packet_frame_.push_back((extension_len_ >> 8) & 0xFF);
|
||||
rtp_packet_frame_.push_back(extension_len_ & 0xFF);
|
||||
rtp_packet_frame_.push_back(sub_extension_id << 4 | sub_extension_len);
|
||||
rtp_packet_frame_.push_back((abs_send_time >> 16) & 0xFF);
|
||||
rtp_packet_frame_.push_back((abs_send_time >> 8) & 0xFF);
|
||||
rtp_packet_frame_.push_back(abs_send_time & 0xFF);
|
||||
}
|
||||
|
||||
if (index == packet_num - 1 && last_packet_size > 0) {
|
||||
rtp_packet_frame_.insert(rtp_packet_frame_.end(), payload,
|
||||
payload + last_packet_size);
|
||||
} else {
|
||||
rtp_packet_frame_.insert(rtp_packet_frame_.end(), payload,
|
||||
payload + MAX_NALU_LEN);
|
||||
}
|
||||
|
||||
RtpPacket rtp_packet;
|
||||
rtp_packet.Build(rtp_packet_frame_.data(), rtp_packet_frame_.size());
|
||||
|
||||
rtp_packets.emplace_back(rtp_packet);
|
||||
}
|
||||
|
||||
return rtp_packets;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2025-01-23
|
||||
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _RTP_PACKETIZER_GENERIC_H_
|
||||
#define _RTP_PACKETIZER_GENERIC_H_
|
||||
|
||||
#include "rtp_packetizer.h"
|
||||
|
||||
class RtpPacketizerGeneric : public RtpPacketizer {
|
||||
public:
|
||||
RtpPacketizerGeneric();
|
||||
|
||||
virtual ~RtpPacketizerGeneric();
|
||||
|
||||
std::vector<RtpPacket> Build(uint8_t* payload,
|
||||
uint32_t payload_size) override;
|
||||
|
||||
private:
|
||||
uint8_t version_;
|
||||
bool has_padding_;
|
||||
bool has_extension_;
|
||||
uint32_t csrc_count_;
|
||||
bool marker_;
|
||||
uint32_t payload_type_;
|
||||
uint16_t sequence_number_;
|
||||
uint64_t timestamp_;
|
||||
uint32_t ssrc_;
|
||||
std::vector<uint32_t> csrcs_;
|
||||
uint16_t profile_;
|
||||
uint16_t extension_profile_;
|
||||
uint16_t extension_len_;
|
||||
uint8_t* extension_data_;
|
||||
|
||||
private:
|
||||
private:
|
||||
std::vector<uint8_t> rtp_packet_frame_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -6,7 +6,7 @@ RtpPacketizerH264::RtpPacketizerH264()
|
||||
has_extension_(true),
|
||||
csrc_count_(0),
|
||||
marker_(false),
|
||||
payload_type_(RtpPacket::PAYLOAD_TYPE::H264),
|
||||
payload_type_(rtp::PAYLOAD_TYPE::H264),
|
||||
sequence_number_(1),
|
||||
timestamp_(0),
|
||||
ssrc_(0),
|
||||
@@ -28,13 +28,14 @@ std::vector<RtpPacket> RtpPacketizerH264::Build(uint8_t* payload,
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
|
||||
std::vector<RtpPacket> rtp_packets;
|
||||
for (uint32_t index = 0; index < packet_num; index++) {
|
||||
version_ = kRtpVersion;
|
||||
has_padding_ = false;
|
||||
has_extension_ = true;
|
||||
csrc_count_ = 0;
|
||||
marker_ = index == packet_num - 1 ? 1 : 0;
|
||||
payload_type_ = RtpPacket::PAYLOAD_TYPE(payload_type_);
|
||||
payload_type_ = rtp::PAYLOAD_TYPE(payload_type_);
|
||||
sequence_number_++;
|
||||
timestamp_ = timestamp_;
|
||||
ssrc_ = ssrc_;
|
||||
@@ -43,16 +44,16 @@ std::vector<RtpPacket> RtpPacketizerH264::Build(uint8_t* payload,
|
||||
csrcs_ = csrcs_;
|
||||
}
|
||||
|
||||
RtpPacket::FU_INDICATOR fu_indicator;
|
||||
rtp::FU_INDICATOR fu_indicator;
|
||||
fu_indicator.forbidden_bit = 0;
|
||||
fu_indicator.nal_reference_idc = 0;
|
||||
fu_indicator.nal_unit_type = FU_A;
|
||||
fu_indicator.nal_unit_type = rtp::NAL_UNIT_TYPE::FU_A;
|
||||
|
||||
RtpPacket::FU_HEADER fu_header;
|
||||
rtp::FU_HEADER fu_header;
|
||||
fu_header.start = index == 0 ? 1 : 0;
|
||||
fu_header.end = index == packet_num - 1 ? 1 : 0;
|
||||
fu_header.remain_bit = 0;
|
||||
fu_header.nal_unit_type = FU_A;
|
||||
fu_header.nal_unit_type = rtp::NAL_UNIT_TYPE::FU_A;
|
||||
|
||||
rtp_packet_frame_.clear();
|
||||
rtp_packet_frame_.push_back((version_ << 6) | (has_padding_ << 5) |
|
||||
@@ -77,20 +78,38 @@ std::vector<RtpPacket> RtpPacketizerH264::Build(uint8_t* payload,
|
||||
}
|
||||
|
||||
if (has_extension_) {
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | ID | L=2 | Absolute Send Time |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// ID (4 bits): The identifier of the extension header field. In WebRTC,
|
||||
// the ID for Absolute Send Time is typically 3.
|
||||
// L (4 bits): The length of the extension data in bytes minus 1. For
|
||||
// Absolute Send Time: the length is 2 (indicating 3 bytes of data).
|
||||
// Absolute Send Time (24 bits): The absolute send time, with a unit of
|
||||
// 1/65536 seconds (approximately 15.258 microseconds).
|
||||
|
||||
extension_profile_ = kOneByteExtensionProfileId;
|
||||
extension_len_ = 5;
|
||||
// 2 bytes for profile, 2 bytes for length, 3 bytes for abs_send_time, 1
|
||||
// byte for id and sub extension length
|
||||
extension_len_ = 8;
|
||||
|
||||
uint32_t abs_send_time =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
|
||||
abs_send_time &= 0x00FFFFFF;
|
||||
|
||||
uint8_t sub_extension_id = 0;
|
||||
uint8_t sub_extension_len = 2;
|
||||
|
||||
rtp_packet_frame_.push_back(extension_profile_ >> 8);
|
||||
rtp_packet_frame_.push_back(extension_profile_ & 0xff);
|
||||
rtp_packet_frame_.push_back((extension_len_ >> 8) & 0xFF);
|
||||
rtp_packet_frame_.push_back(extension_len_ & 0xFF);
|
||||
rtp_packet_frame_.push_back(0x00);
|
||||
rtp_packet_frame_.push_back(0x02);
|
||||
rtp_packet_frame_.push_back(sub_extension_id << 4 | sub_extension_len);
|
||||
rtp_packet_frame_.push_back((abs_send_time >> 16) & 0xFF);
|
||||
rtp_packet_frame_.push_back((abs_send_time >> 8) & 0xFF);
|
||||
rtp_packet_frame_.push_back(abs_send_time & 0xFF);
|
||||
@@ -115,8 +134,9 @@ std::vector<RtpPacket> RtpPacketizerH264::Build(uint8_t* payload,
|
||||
RtpPacket rtp_packet;
|
||||
rtp_packet.Build(rtp_packet_frame_.data(), rtp_packet_frame_.size());
|
||||
|
||||
packets.emplace_back(rtp_packet);
|
||||
rtp_packets.emplace_back(rtp_packet);
|
||||
}
|
||||
return rtp_packets;
|
||||
}
|
||||
|
||||
// bool BuildFec(uint8_t* payload, uint32_t payload_size) {
|
||||
@@ -143,7 +163,7 @@ std::vector<RtpPacket> RtpPacketizerH264::Build(uint8_t* payload,
|
||||
// rtp_packet.SetHasPadding(false);
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(index == num_of_source_packets - 1 ? 1 : 0);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_SOURCE);
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE::H264_FEC_SOURCE);
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
// rtp_packet.SetTimestamp(timestamp_);
|
||||
// rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -192,7 +212,7 @@ std::vector<RtpPacket> RtpPacketizerH264::Build(uint8_t* payload,
|
||||
// rtp_packet.SetHasPadding(false);
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(index == num_of_total_packets - 1 ? 1 : 0);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_REPAIR);
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE::H264_FEC_REPAIR);
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
// rtp_packet.SetTimestamp(timestamp_);
|
||||
// rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -234,7 +254,7 @@ std::vector<RtpPacket> RtpPacketizerH264::Build(uint8_t* payload,
|
||||
|
||||
// rtp_packet.SetHasExtension(has_extension_);
|
||||
// rtp_packet.SetMarker(1);
|
||||
// rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetPayloadType(rtp::PAYLOAD_TYPE(payload_type_));
|
||||
// rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
|
||||
// timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
|
||||
@@ -38,6 +38,14 @@ class RtpPacketizerH264 : public RtpPacketizer {
|
||||
uint16_t extension_len_;
|
||||
uint8_t* extension_data_;
|
||||
|
||||
private:
|
||||
// H.264 header
|
||||
rtp::FU_INDICATOR fu_indicator_;
|
||||
rtp::FU_HEADER fu_header_;
|
||||
uint8_t fec_symbol_id_ = 0;
|
||||
uint8_t fec_source_symbol_num_ = 0;
|
||||
uint8_t av1_aggr_header_ = 0;
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> rtp_packet_frame_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user