[fix] fix h264 rtp packet packetization and depacketization

This commit is contained in:
dijunkun
2025-01-23 17:28:17 +08:00
parent cd349cd98d
commit 7b839ab773
50 changed files with 871 additions and 422 deletions

View File

@@ -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>();
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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>(

View File

@@ -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_;
};