Implementation for av1 codec

This commit is contained in:
dijunkun
2024-04-19 17:35:19 +08:00
parent a309627ca3
commit f5586a7922
17 changed files with 1037 additions and 67 deletions

View File

@@ -9,6 +9,16 @@
#define FU_A 28
#define FU_B 29
constexpr int kObuTypeSequenceHeader = 1;
constexpr int kObuTypeTemporalDelimiter = 2;
constexpr int kObuTypeFrameHeader = 3;
constexpr int kObuTypeTileGroup = 4;
constexpr int kObuTypeMetadata = 5;
constexpr int kObuTypeFrame = 6;
constexpr int kObuTypeRedundantFrameHeader = 7;
constexpr int kObuTypeTileList = 8;
constexpr int kObuTypePadding = 15;
RtpCodec ::RtpCodec(RtpPacket::PAYLOAD_TYPE payload_type)
: version_(RTP_VERSION),
has_padding_(false),
@@ -216,6 +226,84 @@ void RtpCodec::Encode(uint8_t* buffer, size_t size,
packets.emplace_back(rtp_packet);
}
}
} else if (RtpPacket::PAYLOAD_TYPE::AV1 == payload_type_) {
if (size <= MAX_NALU_LEN) {
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.SetSequenceNumber(sequence_number_++);
timestamp_ =
std::chrono::high_resolution_clock::now().time_since_epoch().count();
rtp_packet.SetTimestamp(timestamp_);
rtp_packet.SetSsrc(ssrc_);
if (!csrcs_.empty()) {
rtp_packet.SetCsrcs(csrcs_);
}
if (has_extension_) {
rtp_packet.SetExtensionProfile(extension_profile_);
rtp_packet.SetExtensionData(extension_data_, extension_len_);
}
// int obu_header;
// memcpy(&obu_header, buffer, sizeof(char));
// int obu_type = (obu_header & 0b0'1111'000) >> 3;
// LOG_ERROR("OBU type {}", obu_type);
// if (obu_type == kObuTypeTemporalDelimiter ||
// obu_type == kObuTypeTileList || obu_type == kObuTypePadding) {
// LOG_ERROR("Unsupported OBU type", obu_type);
// }
RtpPacket::AV1_AGGR_HEADER av1_aggr_header;
av1_aggr_header.z = av1_aggr_header.z;
av1_aggr_header.y = av1_aggr_header.y;
av1_aggr_header.w = av1_aggr_header.w;
av1_aggr_header.n = av1_aggr_header.n;
rtp_packet.SetAv1AggrHeader(av1_aggr_header);
rtp_packet.EncodeAv1(buffer, size);
packets.emplace_back(rtp_packet);
} else {
size_t last_packet_size = size % MAX_NALU_LEN;
size_t packet_num = size / MAX_NALU_LEN + (last_packet_size ? 1 : 0);
timestamp_ =
std::chrono::high_resolution_clock::now().time_since_epoch().count();
for (size_t index = 0; index < packet_num; index++) {
RtpPacket rtp_packet;
rtp_packet.SetVerion(version_);
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.SetSequenceNumber(sequence_number_++);
rtp_packet.SetTimestamp(timestamp_);
rtp_packet.SetSsrc(ssrc_);
if (!csrcs_.empty()) {
rtp_packet.SetCsrcs(csrcs_);
}
if (has_extension_) {
rtp_packet.SetExtensionProfile(extension_profile_);
rtp_packet.SetExtensionData(extension_data_, extension_len_);
}
if (index == packet_num - 1 && last_packet_size > 0) {
rtp_packet.EncodeAv1(buffer + index * MAX_NALU_LEN, last_packet_size);
} else {
rtp_packet.EncodeAv1(buffer + index * MAX_NALU_LEN, MAX_NALU_LEN);
}
packets.emplace_back(rtp_packet);
}
}
} else if (RtpPacket::PAYLOAD_TYPE::OPUS == payload_type_) {
RtpPacket rtp_packet;
rtp_packet.SetVerion(version_);

View File

@@ -17,6 +17,8 @@ void RtpPacket::TryToDecodeRtpPacket() {
DecodeH264FecSource();
} else if (PAYLOAD_TYPE::H264_FEC_REPAIR == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
DecodeH264FecRepair();
} else if (PAYLOAD_TYPE::AV1 == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
DecodeAv1();
} else if (PAYLOAD_TYPE::OPUS == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
DecodeOpus();
} else if (PAYLOAD_TYPE::DATA == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
@@ -389,6 +391,55 @@ const uint8_t *RtpPacket::EncodeH264FecRepair(
return buffer_;
}
const uint8_t *RtpPacket::EncodeAv1(uint8_t *payload, size_t payload_size) {
buffer_[0] = (version_ << 6) | (has_padding_ << 5) | (has_extension_ << 4) |
total_csrc_number_;
buffer_[1] = (marker_ << 7) | payload_type_;
buffer_[2] = (sequence_number_ >> 8) & 0xFF;
buffer_[3] = sequence_number_ & 0xFF;
buffer_[4] = (timestamp_ >> 24) & 0xFF;
buffer_[5] = (timestamp_ >> 16) & 0xFF;
buffer_[6] = (timestamp_ >> 8) & 0xFF;
buffer_[7] = timestamp_ & 0xFF;
buffer_[8] = (ssrc_ >> 24) & 0xFF;
buffer_[9] = (ssrc_ >> 16) & 0xFF;
buffer_[10] = (ssrc_ >> 8) & 0xFF;
buffer_[11] = ssrc_ & 0xFF;
for (uint32_t index = 0; index < total_csrc_number_ && !csrcs_.empty();
index++) {
buffer_[12 + index] = (csrcs_[index] >> 24) & 0xFF;
buffer_[13 + index] = (csrcs_[index] >> 16) & 0xFF;
buffer_[14 + index] = (csrcs_[index] >> 8) & 0xFF;
buffer_[15 + index] = csrcs_[index] & 0xFF;
}
uint32_t extension_offset =
total_csrc_number_ && !csrcs_.empty() ? total_csrc_number_ * 4 : 0;
if (has_extension_ && extension_data_) {
buffer_[12 + extension_offset] = extension_profile_ >> 8;
buffer_[13 + extension_offset] = extension_profile_ & 0xff;
buffer_[14 + extension_offset] = (extension_len_ >> 8) & 0xFF;
buffer_[15 + extension_offset] = extension_len_ & 0xFF;
memcpy(buffer_ + 16 + extension_offset, extension_data_, extension_len_);
}
uint32_t payload_offset =
(has_extension_ && extension_data_ ? extension_len_ : 0) +
extension_offset;
buffer_[12 + payload_offset] = fu_indicator_.forbidden_bit << 7 |
fu_indicator_.nal_reference_idc << 6 |
fu_indicator_.nal_unit_type;
memcpy(buffer_ + 13 + payload_offset, payload, payload_size);
size_ = payload_size + (13 + payload_offset);
return buffer_;
}
// ----------------------------------------------------------------------------
size_t RtpPacket::DecodeOpus(uint8_t *payload) {
version_ = (buffer_[0] >> 6) & 0x03;
has_padding_ = (buffer_[0] >> 5) & 0x01;
@@ -672,4 +723,47 @@ size_t RtpPacket::DecodeH264FecRepair(uint8_t *payload) {
memcpy(payload, payload_, payload_size_);
}
return payload_size_;
}
size_t RtpPacket::DecodeAv1(uint8_t *payload) {
version_ = (buffer_[0] >> 6) & 0x03;
has_padding_ = (buffer_[0] >> 5) & 0x01;
has_extension_ = (buffer_[0] >> 4) & 0x01;
total_csrc_number_ = buffer_[0] & 0x0f;
marker_ = (buffer_[1] >> 7) & 0x01;
payload_type_ = buffer_[1] & 0x7f;
sequence_number_ = (buffer_[2] << 8) | buffer_[3];
timestamp_ =
(buffer_[4] << 24) | (buffer_[5] << 16) | (buffer_[6] << 8) | buffer_[7];
ssrc_ = (buffer_[8] << 24) | (buffer_[9] << 16) | (buffer_[10] << 8) |
buffer_[11];
for (uint32_t index = 0; index < total_csrc_number_; index++) {
uint32_t csrc = (buffer_[12 + index] << 24) | (buffer_[13 + index] << 16) |
(buffer_[14 + index] << 8) | buffer_[15 + index];
csrcs_.push_back(csrc);
}
uint32_t extension_offset = total_csrc_number_ * 4;
if (has_extension_) {
extension_profile_ =
(buffer_[12 + extension_offset] << 8) | buffer_[13 + extension_offset];
extension_len_ =
(buffer_[14 + extension_offset] << 8) | buffer_[15 + extension_offset];
// extension_data_ = new uint8_t[extension_len_];
// memcpy(extension_data_, buffer_ + 16 + extension_offset,
// extension_len_);
extension_data_ = buffer_ + 16 + extension_offset;
}
uint32_t payload_offset =
(has_extension_ ? extension_len_ : 0) + extension_offset;
payload_size_ = size_ - (13 + payload_offset);
payload_ = buffer_ + 13 + payload_offset;
if (payload) {
memcpy(payload, payload_, payload_size_);
}
return payload_size_;
}

View File

@@ -115,6 +115,44 @@
// | padding | Padding size |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// AV1
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P|X| CC |M| PT | sequence number |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | timestamp |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | synchronization source (SSRC) identifier |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | contributing source (CSRC) identifiers |x
// | .... |x
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | 0x100 | 0x0 | extensions length |x
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | ID | hdr_length | |x
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |x
// | |x
// | dependency descriptor (hdr_length #bytes) |x
// | |x
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | | Other rtp header extensions...|x
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// | AV1 aggr hdr | |
// +-+-+-+-+-+-+-+-+ |
// | |
// | Bytes 2..N of AV1 payload |
// | |
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | : OPTIONAL RTP padding |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | AV1 aggr hdr |
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// |Z|Y| W |N|-|-|-|
// +-+-+-+-+-+-+-+-+
#define DEFAULT_MTU 1500
#define MAX_NALU_LEN 1400
@@ -124,6 +162,7 @@ class RtpPacket {
H264 = 96,
H264_FEC_SOURCE = 97,
H264_FEC_REPAIR = 98,
AV1 = 99,
OPUS = 111,
DATA = 127
} PAYLOAD_TYPE;
@@ -179,6 +218,20 @@ class RtpPacket {
uint8_t nal_unit_type : 5;
} FU_HEADER;
typedef struct {
uint8_t z : 1;
uint8_t y : 1;
uint8_t w : 2;
uint8_t n : 1;
} AV1_AGGR_HEADER;
// typedef struct Obu {
// uint8_t header;
// uint8_t extension_header; // undefined if (header & kXbit) == 0
// rtc::ArrayView<const uint8_t> payload;
// int size; // size of the header and payload combined.
// } OBU;
void SetFuIndicator(FU_INDICATOR fu_indicator) {
fu_indicator_.forbidden_bit = fu_indicator.forbidden_bit;
fu_indicator_.nal_reference_idc = fu_indicator.nal_reference_idc;
@@ -192,6 +245,13 @@ class RtpPacket {
fu_header_.nal_unit_type = fu_header.nal_unit_type;
}
void SetAv1AggrHeader(AV1_AGGR_HEADER av1_aggr_header) {
av1_aggr_header_.z = av1_aggr_header.z;
av1_aggr_header_.y = av1_aggr_header.y;
av1_aggr_header_.w = av1_aggr_header.w;
av1_aggr_header_.n = av1_aggr_header.n;
}
void SetFecSymbolId(uint8_t fec_symbol_id) { fec_symbol_id_ = fec_symbol_id; }
public:
@@ -204,11 +264,14 @@ class RtpPacket {
const uint8_t *EncodeH264FecRepair(uint8_t *payload, size_t payload_size,
unsigned int fec_symbol_id,
unsigned int fec_source_symbol_num);
const uint8_t *EncodeAv1(uint8_t *payload, size_t payload_size);
size_t DecodeData(uint8_t *payload = nullptr);
size_t DecodeH264Nalu(uint8_t *payload = nullptr);
size_t DecodeH264Fua(uint8_t *payload = nullptr);
size_t DecodeH264FecSource(uint8_t *payload = nullptr);
size_t DecodeH264FecRepair(uint8_t *payload = nullptr);
size_t DecodeAv1(uint8_t *payload = nullptr);
size_t DecodeOpus(uint8_t *payload = nullptr);
public:
@@ -314,6 +377,7 @@ class RtpPacket {
FU_HEADER fu_header_;
uint8_t fec_symbol_id_ = 0;
uint8_t fec_source_symbol_num_ = 0;
AV1_AGGR_HEADER av1_aggr_header_;
// Payload
uint8_t *payload_ = nullptr;