mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-26 20:25:34 +08:00
[feat] rewrite rtp module
This commit is contained in:
46
src/common/copy_on_write_buffer.h
Normal file
46
src/common/copy_on_write_buffer.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* @Author: DI JUNKUN
|
||||||
|
* @Date: 2025-01-22
|
||||||
|
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _COPY_ON_WRITE_BUFFER_H_
|
||||||
|
#define _COPY_ON_WRITE_BUFFER_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class CopyOnWriteBuffer {
|
||||||
|
public:
|
||||||
|
CopyOnWriteBuffer() = default;
|
||||||
|
CopyOnWriteBuffer(const CopyOnWriteBuffer& other) = default;
|
||||||
|
CopyOnWriteBuffer(CopyOnWriteBuffer&& other) noexcept = default;
|
||||||
|
CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& other) = default;
|
||||||
|
CopyOnWriteBuffer& operator=(CopyOnWriteBuffer&& other) noexcept = default;
|
||||||
|
|
||||||
|
void SetData(const uint8_t* data, size_t size) {
|
||||||
|
buffer_ = std::make_shared<std::vector<uint8_t>>(data, data + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* data() const { return buffer_ ? buffer_->data() : nullptr; }
|
||||||
|
|
||||||
|
size_t size() const { return buffer_ ? buffer_->size() : 0; }
|
||||||
|
|
||||||
|
uint8_t& operator[](size_t index) {
|
||||||
|
EnsureUnique();
|
||||||
|
return (*buffer_)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t& operator[](size_t index) const { return (*buffer_)[index]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void EnsureUnique() {
|
||||||
|
if (!buffer_.unique()) {
|
||||||
|
buffer_ = std::make_shared<std::vector<uint8_t>>(*buffer_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<std::vector<uint8_t>> buffer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -36,7 +36,7 @@ class RtpCodec {
|
|||||||
uint8_t version_ = 0;
|
uint8_t version_ = 0;
|
||||||
bool has_padding_ = false;
|
bool has_padding_ = false;
|
||||||
bool has_extension_ = false;
|
bool has_extension_ = false;
|
||||||
uint32_t total_csrc_number_ = 0;
|
uint32_t csrc_count_ = 0;
|
||||||
bool marker_ = false;
|
bool marker_ = false;
|
||||||
uint32_t payload_type_ = 0;
|
uint32_t payload_type_ = 0;
|
||||||
uint16_t sequence_number_ = 0;
|
uint16_t sequence_number_ = 0;
|
||||||
|
|||||||
@@ -7,40 +7,58 @@
|
|||||||
#ifndef _RTP_HEADER_H_
|
#ifndef _RTP_HEADER_H_
|
||||||
#define _RTP_HEADER_H_
|
#define _RTP_HEADER_H_
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "api/units/timestamp.h"
|
static constexpr int kMaxRtpCsrcSize = 15;
|
||||||
|
static constexpr uint8_t kRtpVersion = 2;
|
||||||
|
|
||||||
static constexpr int kAbsSendTimeFraction = 18;
|
struct RTPHeaderExtension {
|
||||||
|
RTPHeaderExtension();
|
||||||
|
RTPHeaderExtension(const RTPHeaderExtension& other);
|
||||||
|
RTPHeaderExtension& operator=(const RTPHeaderExtension& other);
|
||||||
|
|
||||||
enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13
|
static constexpr int kAbsSendTimeFraction = 18;
|
||||||
|
|
||||||
|
bool hasAbsoluteSendTime;
|
||||||
|
uint32_t absoluteSendTime;
|
||||||
|
};
|
||||||
|
|
||||||
struct RTPHeader {
|
struct RTPHeader {
|
||||||
RTPHeader()
|
RTPHeader()
|
||||||
: markerBit(false),
|
: version_(kRtpVersion),
|
||||||
payloadType(0),
|
has_padding_(false),
|
||||||
sequenceNumber(0),
|
has_extension_(false),
|
||||||
timestamp(0),
|
csrc_count_(0),
|
||||||
ssrc(0),
|
marker_(false),
|
||||||
numCSRCs(0),
|
payload_type_(0),
|
||||||
arrOfCSRCs(),
|
sequence_number_(1),
|
||||||
paddingLength(0),
|
timestamp_(0),
|
||||||
headerLength(0){};
|
ssrc_(0),
|
||||||
|
csrcs_(),
|
||||||
|
padding_len(0),
|
||||||
|
header_len(0){};
|
||||||
|
|
||||||
RTPHeader(const RTPHeader& other) = default;
|
RTPHeader(const RTPHeader& other) = default;
|
||||||
RTPHeader& operator=(const RTPHeader& other) = default;
|
RTPHeader& operator=(const RTPHeader& other) = default;
|
||||||
|
|
||||||
bool markerBit;
|
uint8_t version_ = 0;
|
||||||
uint8_t payloadType;
|
bool has_padding_ = false;
|
||||||
uint16_t sequenceNumber;
|
bool has_extension_ = false;
|
||||||
uint32_t timestamp;
|
uint8_t csrc_count_ = 0;
|
||||||
uint32_t ssrc;
|
bool marker_ = false;
|
||||||
uint8_t numCSRCs;
|
uint8_t payload_type_ = 0;
|
||||||
uint32_t arrOfCSRCs[kRtpCsrcSize];
|
uint16_t sequence_number_ = 1;
|
||||||
size_t paddingLength;
|
uint64_t timestamp_ = 0;
|
||||||
size_t headerLength;
|
uint32_t ssrc_ = 0;
|
||||||
|
uint32_t csrcs_[kRtpCsrcSize];
|
||||||
|
size_t padding_len;
|
||||||
|
size_t header_len;
|
||||||
|
|
||||||
|
RTPHeaderExtension extension;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
787
src/rtp/rtp_packet/rtp_packet.cc
Normal file
787
src/rtp/rtp_packet/rtp_packet.cc
Normal file
@@ -0,0 +1,787 @@
|
|||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rtp_packet.h"
|
||||||
|
|
||||||
|
void RtpPacket::TryToDecodeRtpPacket() {
|
||||||
|
if (PAYLOAD_TYPE::H264 == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
|
||||||
|
nal_unit_type_ = NAL_UNIT_TYPE(buffer_[12] & 0x1F);
|
||||||
|
if (NAL_UNIT_TYPE::NALU == nal_unit_type_) {
|
||||||
|
DecodeH264Nalu();
|
||||||
|
} else if (NAL_UNIT_TYPE::FU_A == nal_unit_type_) {
|
||||||
|
DecodeH264Fua();
|
||||||
|
}
|
||||||
|
} else if (PAYLOAD_TYPE::H264_FEC_SOURCE == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
|
||||||
|
nal_unit_type_ = NAL_UNIT_TYPE::FU_A;
|
||||||
|
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)) {
|
||||||
|
DecodeData();
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Unknown pt: {}", (int)PAYLOAD_TYPE(buffer_[1] & 0x7F));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtpPacket::ParseRtpData() {
|
||||||
|
if (!parsed_) {
|
||||||
|
TryToDecodeRtpPacket();
|
||||||
|
parsed_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpPacket::RtpPacket() : buffer_(new uint8_t[DEFAULT_MTU]), size_(DEFAULT_MTU) {
|
||||||
|
memset(buffer_, 0, DEFAULT_MTU);
|
||||||
|
// ParseRtpData();
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpPacket::RtpPacket(uint32_t size) : buffer_(new uint8_t[size]), size_(size) {}
|
||||||
|
|
||||||
|
RtpPacket::RtpPacket(const uint8_t *buffer, uint32_t size) {
|
||||||
|
if (size > 0) {
|
||||||
|
buffer_ = (uint8_t *)malloc(size);
|
||||||
|
if (NULL == buffer_) {
|
||||||
|
LOG_ERROR("Malloc failed");
|
||||||
|
} else {
|
||||||
|
memcpy(buffer_, buffer, size);
|
||||||
|
}
|
||||||
|
size_ = size;
|
||||||
|
|
||||||
|
// TryToDecodeH264RtpPacket(buffer_);
|
||||||
|
ParseRtpData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpPacket::RtpPacket(const RtpPacket &rtp_packet) {
|
||||||
|
if (rtp_packet.size_ > 0) {
|
||||||
|
buffer_ = (uint8_t *)malloc(rtp_packet.size_);
|
||||||
|
if (NULL == buffer_) {
|
||||||
|
LOG_ERROR("Malloc failed");
|
||||||
|
} else {
|
||||||
|
memcpy(buffer_, rtp_packet.buffer_, rtp_packet.size_);
|
||||||
|
}
|
||||||
|
size_ = rtp_packet.size_;
|
||||||
|
|
||||||
|
// TryToDecodeH264RtpPacket(buffer_);
|
||||||
|
ParseRtpData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpPacket::RtpPacket(RtpPacket &&rtp_packet)
|
||||||
|
: buffer_((uint8_t *)std::move(rtp_packet.buffer_)),
|
||||||
|
size_(rtp_packet.size_) {
|
||||||
|
rtp_packet.buffer_ = nullptr;
|
||||||
|
rtp_packet.size_ = 0;
|
||||||
|
|
||||||
|
// TryToDecodeH264RtpPacket(buffer_);
|
||||||
|
ParseRtpData();
|
||||||
|
}
|
||||||
|
|
||||||
|
// RtpPacket &RtpPacket::operator=(const RtpPacket &rtp_packet) {
|
||||||
|
// if (&rtp_packet != this) {
|
||||||
|
// if (buffer_) {
|
||||||
|
// delete[] buffer_;
|
||||||
|
// buffer_ = nullptr;
|
||||||
|
// }
|
||||||
|
// buffer_ = new uint8_t[rtp_packet.size_];
|
||||||
|
// memcpy(buffer_, rtp_packet.buffer_, rtp_packet.size_);
|
||||||
|
// size_ = rtp_packet.size_;
|
||||||
|
|
||||||
|
// // TryToDecodeH264RtpPacket(buffer_);
|
||||||
|
// }
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
|
||||||
|
RtpPacket &RtpPacket::operator=(const RtpPacket &rtp_packet) {
|
||||||
|
if (&rtp_packet != this) {
|
||||||
|
buffer_ = (uint8_t *)realloc(buffer_, rtp_packet.size_);
|
||||||
|
memcpy(buffer_, rtp_packet.buffer_, rtp_packet.size_);
|
||||||
|
size_ = rtp_packet.size_;
|
||||||
|
|
||||||
|
// TryToDecodeH264RtpPacket(buffer_);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpPacket &RtpPacket::operator=(RtpPacket &&rtp_packet) {
|
||||||
|
if (&rtp_packet != this) {
|
||||||
|
buffer_ = std::move(rtp_packet.buffer_);
|
||||||
|
rtp_packet.buffer_ = nullptr;
|
||||||
|
size_ = rtp_packet.size_;
|
||||||
|
rtp_packet.size_ = 0;
|
||||||
|
|
||||||
|
// TryToDecodeH264RtpPacket(buffer_);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpPacket::~RtpPacket() {
|
||||||
|
if (buffer_) {
|
||||||
|
free(buffer_);
|
||||||
|
buffer_ = nullptr;
|
||||||
|
}
|
||||||
|
size_ = 0;
|
||||||
|
|
||||||
|
if (extension_data_) {
|
||||||
|
free(extension_data_);
|
||||||
|
extension_data_ = nullptr;
|
||||||
|
}
|
||||||
|
extension_len_ = 0;
|
||||||
|
payload_size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtpPacket::Build(const uint8_t *buffer, uint32_t size) {
|
||||||
|
if (size > 0) {
|
||||||
|
buffer_ = (uint8_t *)malloc(size);
|
||||||
|
if (NULL == buffer_) {
|
||||||
|
LOG_ERROR("Malloc failed");
|
||||||
|
} else {
|
||||||
|
memcpy(buffer_, buffer, size);
|
||||||
|
}
|
||||||
|
size_ = size;
|
||||||
|
|
||||||
|
// TryToDecodeH264RtpPacket(buffer_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *RtpPacket::Encode(uint8_t *payload, size_t payload_size) {
|
||||||
|
buffer_[0] = (version_ << 6) | (has_padding_ << 5) | (has_extension_ << 4) |
|
||||||
|
csrc_count_;
|
||||||
|
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 < csrc_count_ && !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 =
|
||||||
|
csrc_count_ && !csrcs_.empty() ? csrc_count_ * 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;
|
||||||
|
|
||||||
|
memcpy(buffer_ + 12 + payload_offset, payload, payload_size);
|
||||||
|
size_ = payload_size + (12 + payload_offset);
|
||||||
|
|
||||||
|
return buffer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *RtpPacket::EncodeH264Nalu(uint8_t *payload,
|
||||||
|
size_t payload_size) {
|
||||||
|
buffer_[0] = (version_ << 6) | (has_padding_ << 5) | (has_extension_ << 4) |
|
||||||
|
csrc_count_;
|
||||||
|
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 < csrc_count_ && !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 =
|
||||||
|
csrc_count_ && !csrcs_.empty() ? csrc_count_ * 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_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *RtpPacket::EncodeH264Fua(uint8_t *payload, size_t payload_size) {
|
||||||
|
buffer_[0] = (version_ << 6) | (has_padding_ << 5) | (has_extension_ << 4) |
|
||||||
|
csrc_count_;
|
||||||
|
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 < csrc_count_ && !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 =
|
||||||
|
csrc_count_ && !csrcs_.empty() ? csrc_count_ * 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;
|
||||||
|
|
||||||
|
buffer_[13 + payload_offset] = fu_header_.start << 7 | fu_header_.end << 6 |
|
||||||
|
fu_header_.remain_bit << 1 |
|
||||||
|
fu_header_.nal_unit_type;
|
||||||
|
|
||||||
|
memcpy(buffer_ + 14 + payload_offset, payload, payload_size);
|
||||||
|
size_ = payload_size + (14 + payload_offset);
|
||||||
|
|
||||||
|
return buffer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *RtpPacket::EncodeH264FecSource(uint8_t *payload,
|
||||||
|
size_t payload_size,
|
||||||
|
uint8_t fec_symbol_id,
|
||||||
|
uint8_t fec_source_symbol_num) {
|
||||||
|
buffer_[0] = (version_ << 6) | (has_padding_ << 5) | (has_extension_ << 4) |
|
||||||
|
csrc_count_;
|
||||||
|
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 < csrc_count_ && !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 =
|
||||||
|
csrc_count_ && !csrcs_.empty() ? csrc_count_ * 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 fec_symbol_id_offset =
|
||||||
|
(has_extension_ && extension_data_ ? extension_len_ : 0) +
|
||||||
|
extension_offset;
|
||||||
|
|
||||||
|
buffer_[12 + fec_symbol_id_offset] = fec_symbol_id;
|
||||||
|
|
||||||
|
uint32_t fec_source_symbol_num_offset = fec_symbol_id_offset + 1;
|
||||||
|
buffer_[12 + fec_source_symbol_num_offset] = fec_source_symbol_num;
|
||||||
|
|
||||||
|
uint32_t payload_offset = fec_source_symbol_num_offset + 1;
|
||||||
|
|
||||||
|
buffer_[12 + payload_offset] = fu_indicator_.forbidden_bit << 7 |
|
||||||
|
fu_indicator_.nal_reference_idc << 6 |
|
||||||
|
fu_indicator_.nal_unit_type;
|
||||||
|
|
||||||
|
buffer_[13 + payload_offset] = fu_header_.start << 7 | fu_header_.end << 6 |
|
||||||
|
fu_header_.remain_bit << 1 |
|
||||||
|
fu_header_.nal_unit_type;
|
||||||
|
|
||||||
|
memcpy(buffer_ + 14 + payload_offset, payload, payload_size);
|
||||||
|
size_ = payload_size + (14 + payload_offset);
|
||||||
|
|
||||||
|
return buffer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *RtpPacket::EncodeH264FecRepair(uint8_t *payload,
|
||||||
|
size_t payload_size,
|
||||||
|
uint8_t fec_symbol_id,
|
||||||
|
uint8_t fec_source_symbol_num) {
|
||||||
|
buffer_[0] = (version_ << 6) | (has_padding_ << 5) | (has_extension_ << 4) |
|
||||||
|
csrc_count_;
|
||||||
|
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 < csrc_count_ && !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 =
|
||||||
|
csrc_count_ && !csrcs_.empty() ? csrc_count_ * 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 fec_symbol_id_offset =
|
||||||
|
(has_extension_ && extension_data_ ? extension_len_ : 0) +
|
||||||
|
extension_offset;
|
||||||
|
|
||||||
|
buffer_[12 + fec_symbol_id_offset] = fec_symbol_id;
|
||||||
|
|
||||||
|
uint32_t fec_source_symbol_num_offset = fec_symbol_id_offset + 1;
|
||||||
|
buffer_[12 + fec_source_symbol_num_offset] = fec_source_symbol_num;
|
||||||
|
|
||||||
|
uint32_t payload_offset = fec_source_symbol_num_offset + 1;
|
||||||
|
|
||||||
|
buffer_[12 + payload_offset] = fu_indicator_.forbidden_bit << 7 |
|
||||||
|
fu_indicator_.nal_reference_idc << 6 |
|
||||||
|
fu_indicator_.nal_unit_type;
|
||||||
|
|
||||||
|
buffer_[13 + payload_offset] = fu_header_.start << 7 | fu_header_.end << 6 |
|
||||||
|
fu_header_.remain_bit << 1 |
|
||||||
|
fu_header_.nal_unit_type;
|
||||||
|
|
||||||
|
memcpy(buffer_ + 14 + payload_offset, payload, payload_size);
|
||||||
|
size_ = payload_size + (14 + payload_offset);
|
||||||
|
|
||||||
|
return buffer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *RtpPacket::EncodeAv1(uint8_t *payload, size_t payload_size) {
|
||||||
|
buffer_[0] = (version_ << 6) | (has_padding_ << 5) | (has_extension_ << 4) |
|
||||||
|
csrc_count_;
|
||||||
|
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 < csrc_count_ && !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 =
|
||||||
|
csrc_count_ && !csrcs_.empty() ? csrc_count_ * 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 aggr_header_offset =
|
||||||
|
(has_extension_ && extension_data_ ? extension_len_ : 0) +
|
||||||
|
extension_offset;
|
||||||
|
memcpy(buffer_ + 12 + aggr_header_offset, &av1_aggr_header_, 1);
|
||||||
|
|
||||||
|
uint32_t payload_offset = aggr_header_offset;
|
||||||
|
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;
|
||||||
|
has_extension_ = (buffer_[0] >> 4) & 0x01;
|
||||||
|
csrc_count_ = 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 < csrc_count_; 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 = csrc_count_ * 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_ - (12 + payload_offset);
|
||||||
|
payload_ = buffer_ + 12 + payload_offset;
|
||||||
|
if (payload) {
|
||||||
|
memcpy(payload, payload_, payload_size_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RtpPacket::DecodeData(uint8_t *payload) {
|
||||||
|
version_ = (buffer_[0] >> 6) & 0x03;
|
||||||
|
has_padding_ = (buffer_[0] >> 5) & 0x01;
|
||||||
|
has_extension_ = (buffer_[0] >> 4) & 0x01;
|
||||||
|
csrc_count_ = 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 < csrc_count_; 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 = csrc_count_ * 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_ - (12 + payload_offset);
|
||||||
|
payload_ = buffer_ + 12 + payload_offset;
|
||||||
|
if (payload) {
|
||||||
|
memcpy(payload, payload_, payload_size_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RtpPacket::DecodeH264Nalu(uint8_t *payload) {
|
||||||
|
version_ = (buffer_[0] >> 6) & 0x03;
|
||||||
|
has_padding_ = (buffer_[0] >> 5) & 0x01;
|
||||||
|
has_extension_ = (buffer_[0] >> 4) & 0x01;
|
||||||
|
csrc_count_ = 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 < csrc_count_; 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 = csrc_count_ * 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;
|
||||||
|
|
||||||
|
fu_indicator_.forbidden_bit = (buffer_[12 + payload_offset] >> 7) & 0x01;
|
||||||
|
fu_indicator_.nal_reference_idc = (buffer_[12 + payload_offset] >> 5) & 0x03;
|
||||||
|
fu_indicator_.nal_unit_type = buffer_[12 + payload_offset] & 0x1F;
|
||||||
|
|
||||||
|
payload_size_ = size_ - (13 + payload_offset);
|
||||||
|
payload_ = buffer_ + 13 + payload_offset;
|
||||||
|
if (payload) {
|
||||||
|
memcpy(payload, payload_, payload_size_);
|
||||||
|
}
|
||||||
|
return payload_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RtpPacket::DecodeH264Fua(uint8_t *payload) {
|
||||||
|
version_ = (buffer_[0] >> 6) & 0x03;
|
||||||
|
has_padding_ = (buffer_[0] >> 5) & 0x01;
|
||||||
|
has_extension_ = (buffer_[0] >> 4) & 0x01;
|
||||||
|
csrc_count_ = 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 < csrc_count_; 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 = csrc_count_ * 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_ = buffer_ + 16 + extension_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t payload_offset =
|
||||||
|
(has_extension_ ? extension_len_ : 0) + extension_offset;
|
||||||
|
|
||||||
|
fu_indicator_.forbidden_bit = (buffer_[12 + payload_offset] >> 7) & 0x01;
|
||||||
|
fu_indicator_.nal_reference_idc = (buffer_[12 + payload_offset] >> 5) & 0x03;
|
||||||
|
fu_indicator_.nal_unit_type = buffer_[12 + payload_offset] & 0x1F;
|
||||||
|
|
||||||
|
fu_header_.start = (buffer_[13 + payload_offset] >> 7) & 0x01;
|
||||||
|
fu_header_.end = (buffer_[13 + payload_offset] >> 6) & 0x01;
|
||||||
|
fu_header_.remain_bit = (buffer_[13 + payload_offset] >> 5) & 0x01;
|
||||||
|
fu_header_.nal_unit_type = buffer_[13 + payload_offset] & 0x1F;
|
||||||
|
|
||||||
|
payload_size_ = size_ - (14 + payload_offset);
|
||||||
|
payload_ = buffer_ + 14 + payload_offset;
|
||||||
|
if (payload) {
|
||||||
|
memcpy(payload, payload_, payload_size_);
|
||||||
|
}
|
||||||
|
return payload_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RtpPacket::DecodeH264FecSource(uint8_t *payload) {
|
||||||
|
version_ = (buffer_[0] >> 6) & 0x03;
|
||||||
|
has_padding_ = (buffer_[0] >> 5) & 0x01;
|
||||||
|
has_extension_ = (buffer_[0] >> 4) & 0x01;
|
||||||
|
csrc_count_ = 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 < csrc_count_; 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 = csrc_count_ * 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_ = buffer_ + 16 + extension_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fec_symbol_id_offset =
|
||||||
|
extension_offset + (has_extension_ ? extension_len_ : 0);
|
||||||
|
fec_symbol_id_ = buffer_[12 + fec_symbol_id_offset];
|
||||||
|
|
||||||
|
uint32_t fec_source_symbol_num_offset = fec_symbol_id_offset + 1;
|
||||||
|
fec_source_symbol_num_ = buffer_[12 + fec_source_symbol_num_offset];
|
||||||
|
|
||||||
|
uint32_t payload_offset = fec_source_symbol_num_offset + 1;
|
||||||
|
|
||||||
|
fu_indicator_.forbidden_bit = (buffer_[12 + payload_offset] >> 7) & 0x01;
|
||||||
|
fu_indicator_.nal_reference_idc = (buffer_[12 + payload_offset] >> 5) & 0x03;
|
||||||
|
fu_indicator_.nal_unit_type = buffer_[12 + payload_offset] & 0x1F;
|
||||||
|
|
||||||
|
fu_header_.start = (buffer_[13 + payload_offset] >> 7) & 0x01;
|
||||||
|
fu_header_.end = (buffer_[13 + payload_offset] >> 6) & 0x01;
|
||||||
|
fu_header_.remain_bit = (buffer_[13 + payload_offset] >> 5) & 0x01;
|
||||||
|
fu_header_.nal_unit_type = buffer_[13 + payload_offset] & 0x1F;
|
||||||
|
|
||||||
|
payload_size_ = size_ - (14 + payload_offset);
|
||||||
|
payload_ = buffer_ + 14 + payload_offset;
|
||||||
|
if (payload) {
|
||||||
|
memcpy(payload, payload_, payload_size_);
|
||||||
|
}
|
||||||
|
return payload_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t RtpPacket::DecodeH264FecRepair(uint8_t *payload) {
|
||||||
|
version_ = (buffer_[0] >> 6) & 0x03;
|
||||||
|
has_padding_ = (buffer_[0] >> 5) & 0x01;
|
||||||
|
has_extension_ = (buffer_[0] >> 4) & 0x01;
|
||||||
|
csrc_count_ = 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 < csrc_count_; 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 = csrc_count_ * 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_ = buffer_ + 16 + extension_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fec_symbol_id_offset =
|
||||||
|
extension_offset + (has_extension_ ? extension_len_ : 0);
|
||||||
|
fec_symbol_id_ = buffer_[12 + fec_symbol_id_offset];
|
||||||
|
|
||||||
|
uint32_t fec_source_symbol_num_offset = fec_symbol_id_offset + 1;
|
||||||
|
fec_source_symbol_num_ = buffer_[12 + fec_source_symbol_num_offset];
|
||||||
|
|
||||||
|
uint32_t payload_offset = fec_source_symbol_num_offset + 1;
|
||||||
|
|
||||||
|
payload_size_ = size_ - (14 + payload_offset);
|
||||||
|
payload_ = buffer_ + 14 + payload_offset;
|
||||||
|
if (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;
|
||||||
|
csrc_count_ = 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 < csrc_count_; 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 = csrc_count_ * 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 aggr_header_offset =
|
||||||
|
(has_extension_ ? extension_len_ : 0) + extension_offset;
|
||||||
|
|
||||||
|
av1_aggr_header_ = buffer_[12 + aggr_header_offset];
|
||||||
|
|
||||||
|
uint32_t payload_offset = aggr_header_offset;
|
||||||
|
|
||||||
|
payload_size_ = size_ - (13 + payload_offset);
|
||||||
|
payload_ = buffer_ + 13 + payload_offset;
|
||||||
|
if (payload) {
|
||||||
|
memcpy(payload, payload_, payload_size_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload_size_;
|
||||||
|
}
|
||||||
@@ -2,792 +2,133 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
void RtpPacket::TryToDecodeRtpPacket() {
|
RtpPacket::RtpPacket() {}
|
||||||
if (PAYLOAD_TYPE::H264 == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
|
|
||||||
nal_unit_type_ = NAL_UNIT_TYPE(buffer_[12] & 0x1F);
|
|
||||||
if (NAL_UNIT_TYPE::NALU == nal_unit_type_) {
|
|
||||||
DecodeH264Nalu();
|
|
||||||
} else if (NAL_UNIT_TYPE::FU_A == nal_unit_type_) {
|
|
||||||
DecodeH264Fua();
|
|
||||||
}
|
|
||||||
} else if (PAYLOAD_TYPE::H264_FEC_SOURCE == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
|
|
||||||
nal_unit_type_ = NAL_UNIT_TYPE::FU_A;
|
|
||||||
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)) {
|
|
||||||
DecodeData();
|
|
||||||
} else {
|
|
||||||
LOG_ERROR("Unknown pt: {}", (int)PAYLOAD_TYPE(buffer_[1] & 0x7F));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RtpPacket::ParseRtpData() {
|
RtpPacket::RtpPacket(const RtpPacket &rtp_packet) = default;
|
||||||
if (!parsed_) {
|
|
||||||
TryToDecodeRtpPacket();
|
|
||||||
parsed_ = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpPacket::RtpPacket() : buffer_(new uint8_t[DEFAULT_MTU]), size_(DEFAULT_MTU) {
|
RtpPacket::RtpPacket(RtpPacket &&rtp_packet) = default;
|
||||||
memset(buffer_, 0, DEFAULT_MTU);
|
|
||||||
// ParseRtpData();
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpPacket::RtpPacket(uint32_t size) : buffer_(new uint8_t[size]), size_(size) {}
|
RtpPacket &RtpPacket::operator=(const RtpPacket &rtp_packet) = default;
|
||||||
|
|
||||||
RtpPacket::RtpPacket(const uint8_t *buffer, uint32_t size) {
|
RtpPacket &RtpPacket::operator=(RtpPacket &&rtp_packet) = default;
|
||||||
if (size > 0) {
|
|
||||||
buffer_ = (uint8_t *)malloc(size);
|
|
||||||
if (NULL == buffer_) {
|
|
||||||
LOG_ERROR("Malloc failed");
|
|
||||||
} else {
|
|
||||||
memcpy(buffer_, buffer, size);
|
|
||||||
}
|
|
||||||
size_ = size;
|
|
||||||
|
|
||||||
// TryToDecodeH264RtpPacket(buffer_);
|
RtpPacket::~RtpPacket() = default;
|
||||||
ParseRtpData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpPacket::RtpPacket(const RtpPacket &rtp_packet) {
|
|
||||||
if (rtp_packet.size_ > 0) {
|
|
||||||
buffer_ = (uint8_t *)malloc(rtp_packet.size_);
|
|
||||||
if (NULL == buffer_) {
|
|
||||||
LOG_ERROR("Malloc failed");
|
|
||||||
} else {
|
|
||||||
memcpy(buffer_, rtp_packet.buffer_, rtp_packet.size_);
|
|
||||||
}
|
|
||||||
size_ = rtp_packet.size_;
|
|
||||||
|
|
||||||
// TryToDecodeH264RtpPacket(buffer_);
|
|
||||||
ParseRtpData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpPacket::RtpPacket(RtpPacket &&rtp_packet)
|
|
||||||
: buffer_((uint8_t *)std::move(rtp_packet.buffer_)),
|
|
||||||
size_(rtp_packet.size_) {
|
|
||||||
rtp_packet.buffer_ = nullptr;
|
|
||||||
rtp_packet.size_ = 0;
|
|
||||||
|
|
||||||
// TryToDecodeH264RtpPacket(buffer_);
|
|
||||||
ParseRtpData();
|
|
||||||
}
|
|
||||||
|
|
||||||
// RtpPacket &RtpPacket::operator=(const RtpPacket &rtp_packet) {
|
|
||||||
// if (&rtp_packet != this) {
|
|
||||||
// if (buffer_) {
|
|
||||||
// delete[] buffer_;
|
|
||||||
// buffer_ = nullptr;
|
|
||||||
// }
|
|
||||||
// buffer_ = new uint8_t[rtp_packet.size_];
|
|
||||||
// memcpy(buffer_, rtp_packet.buffer_, rtp_packet.size_);
|
|
||||||
// size_ = rtp_packet.size_;
|
|
||||||
|
|
||||||
// // TryToDecodeH264RtpPacket(buffer_);
|
|
||||||
// }
|
|
||||||
// return *this;
|
|
||||||
// }
|
|
||||||
|
|
||||||
RtpPacket &RtpPacket::operator=(const RtpPacket &rtp_packet) {
|
|
||||||
if (&rtp_packet != this) {
|
|
||||||
buffer_ = (uint8_t *)realloc(buffer_, rtp_packet.size_);
|
|
||||||
memcpy(buffer_, rtp_packet.buffer_, rtp_packet.size_);
|
|
||||||
size_ = rtp_packet.size_;
|
|
||||||
|
|
||||||
// TryToDecodeH264RtpPacket(buffer_);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpPacket &RtpPacket::operator=(RtpPacket &&rtp_packet) {
|
|
||||||
if (&rtp_packet != this) {
|
|
||||||
buffer_ = std::move(rtp_packet.buffer_);
|
|
||||||
rtp_packet.buffer_ = nullptr;
|
|
||||||
size_ = rtp_packet.size_;
|
|
||||||
rtp_packet.size_ = 0;
|
|
||||||
|
|
||||||
// TryToDecodeH264RtpPacket(buffer_);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
RtpPacket::~RtpPacket() {
|
|
||||||
if (buffer_) {
|
|
||||||
free(buffer_);
|
|
||||||
buffer_ = nullptr;
|
|
||||||
}
|
|
||||||
size_ = 0;
|
|
||||||
|
|
||||||
if (extension_data_) {
|
|
||||||
free(extension_data_);
|
|
||||||
extension_data_ = nullptr;
|
|
||||||
}
|
|
||||||
extension_len_ = 0;
|
|
||||||
payload_size_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpPacket::Build(const uint8_t *buffer, uint32_t size) {
|
bool RtpPacket::Build(const uint8_t *buffer, uint32_t size) {
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
buffer_ = (uint8_t *)malloc(size);
|
buffer_.SetData(buffer, size);
|
||||||
if (NULL == buffer_) {
|
|
||||||
LOG_ERROR("Malloc failed");
|
|
||||||
} else {
|
|
||||||
memcpy(buffer_, buffer, size);
|
|
||||||
}
|
|
||||||
size_ = size;
|
size_ = size;
|
||||||
|
|
||||||
// TryToDecodeH264RtpPacket(buffer_);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t *RtpPacket::Encode(uint8_t *payload, size_t payload_size) {
|
bool RtpPacket::Parse(const uint8_t *buffer, uint32_t size) {
|
||||||
buffer_[0] = (version_ << 6) | (has_padding_ << 5) | (has_extension_ << 4) |
|
if (size < kFixedHeaderSize) {
|
||||||
total_csrc_number_;
|
LOG_WARN("RtpPacket::Parse: size is too small");
|
||||||
buffer_[1] = (marker_ << 7) | payload_type_;
|
return false;
|
||||||
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 =
|
// 1st byte
|
||||||
total_csrc_number_ && !csrcs_.empty() ? total_csrc_number_ * 4 : 0;
|
version_ = (buffer_[payload_offset_] >> 6) & 0x03;
|
||||||
if (has_extension_ && extension_data_) {
|
if (version_ != kRtpVersion) {
|
||||||
buffer_[12 + extension_offset] = extension_profile_ >> 8;
|
LOG_WARN("RtpPacket::Parse: version is not qual to kRtpVersion");
|
||||||
buffer_[13 + extension_offset] = extension_profile_ & 0xff;
|
return false;
|
||||||
buffer_[14 + extension_offset] = (extension_len_ >> 8) & 0xFF;
|
}
|
||||||
buffer_[15 + extension_offset] = extension_len_ & 0xFF;
|
has_padding_ = (buffer_[payload_offset_] >> 5) & 0x01;
|
||||||
memcpy(buffer_ + 16 + extension_offset, extension_data_, extension_len_);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t payload_offset =
|
// 2nd byte
|
||||||
(has_extension_ && extension_data_ ? extension_len_ : 0) +
|
marker_ = (buffer_[payload_offset_] >> 7) & 0x01;
|
||||||
extension_offset;
|
payload_type_ = buffer_[payload_offset_] & 0x7f;
|
||||||
|
|
||||||
memcpy(buffer_ + 12 + payload_offset, payload, payload_size);
|
// 3rd byte and 4th byte
|
||||||
size_ = payload_size + (12 + payload_offset);
|
sequence_number_ =
|
||||||
|
(buffer_[payload_offset_] << 8) | buffer_[payload_offset_ + 1];
|
||||||
|
|
||||||
return buffer_;
|
// 5th byte to 8th byte
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t *RtpPacket::EncodeH264Nalu(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_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t *RtpPacket::EncodeH264Fua(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;
|
|
||||||
|
|
||||||
buffer_[13 + payload_offset] = fu_header_.start << 7 | fu_header_.end << 6 |
|
|
||||||
fu_header_.remain_bit << 1 |
|
|
||||||
fu_header_.nal_unit_type;
|
|
||||||
|
|
||||||
memcpy(buffer_ + 14 + payload_offset, payload, payload_size);
|
|
||||||
size_ = payload_size + (14 + payload_offset);
|
|
||||||
|
|
||||||
return buffer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t *RtpPacket::EncodeH264FecSource(uint8_t *payload,
|
|
||||||
size_t payload_size,
|
|
||||||
uint8_t fec_symbol_id,
|
|
||||||
uint8_t fec_source_symbol_num) {
|
|
||||||
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 fec_symbol_id_offset =
|
|
||||||
(has_extension_ && extension_data_ ? extension_len_ : 0) +
|
|
||||||
extension_offset;
|
|
||||||
|
|
||||||
buffer_[12 + fec_symbol_id_offset] = fec_symbol_id;
|
|
||||||
|
|
||||||
uint32_t fec_source_symbol_num_offset = fec_symbol_id_offset + 1;
|
|
||||||
buffer_[12 + fec_source_symbol_num_offset] = fec_source_symbol_num;
|
|
||||||
|
|
||||||
uint32_t payload_offset = fec_source_symbol_num_offset + 1;
|
|
||||||
|
|
||||||
buffer_[12 + payload_offset] = fu_indicator_.forbidden_bit << 7 |
|
|
||||||
fu_indicator_.nal_reference_idc << 6 |
|
|
||||||
fu_indicator_.nal_unit_type;
|
|
||||||
|
|
||||||
buffer_[13 + payload_offset] = fu_header_.start << 7 | fu_header_.end << 6 |
|
|
||||||
fu_header_.remain_bit << 1 |
|
|
||||||
fu_header_.nal_unit_type;
|
|
||||||
|
|
||||||
memcpy(buffer_ + 14 + payload_offset, payload, payload_size);
|
|
||||||
size_ = payload_size + (14 + payload_offset);
|
|
||||||
|
|
||||||
return buffer_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t *RtpPacket::EncodeH264FecRepair(uint8_t *payload,
|
|
||||||
size_t payload_size,
|
|
||||||
uint8_t fec_symbol_id,
|
|
||||||
uint8_t fec_source_symbol_num) {
|
|
||||||
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 fec_symbol_id_offset =
|
|
||||||
(has_extension_ && extension_data_ ? extension_len_ : 0) +
|
|
||||||
extension_offset;
|
|
||||||
|
|
||||||
buffer_[12 + fec_symbol_id_offset] = fec_symbol_id;
|
|
||||||
|
|
||||||
uint32_t fec_source_symbol_num_offset = fec_symbol_id_offset + 1;
|
|
||||||
buffer_[12 + fec_source_symbol_num_offset] = fec_source_symbol_num;
|
|
||||||
|
|
||||||
uint32_t payload_offset = fec_source_symbol_num_offset + 1;
|
|
||||||
|
|
||||||
buffer_[12 + payload_offset] = fu_indicator_.forbidden_bit << 7 |
|
|
||||||
fu_indicator_.nal_reference_idc << 6 |
|
|
||||||
fu_indicator_.nal_unit_type;
|
|
||||||
|
|
||||||
buffer_[13 + payload_offset] = fu_header_.start << 7 | fu_header_.end << 6 |
|
|
||||||
fu_header_.remain_bit << 1 |
|
|
||||||
fu_header_.nal_unit_type;
|
|
||||||
|
|
||||||
memcpy(buffer_ + 14 + payload_offset, payload, payload_size);
|
|
||||||
size_ = payload_size + (14 + payload_offset);
|
|
||||||
|
|
||||||
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 aggr_header_offset =
|
|
||||||
(has_extension_ && extension_data_ ? extension_len_ : 0) +
|
|
||||||
extension_offset;
|
|
||||||
memcpy(buffer_ + 12 + aggr_header_offset, &av1_aggr_header_, 1);
|
|
||||||
|
|
||||||
uint32_t payload_offset = aggr_header_offset;
|
|
||||||
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;
|
|
||||||
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_ =
|
timestamp_ =
|
||||||
(buffer_[4] << 24) | (buffer_[5] << 16) | (buffer_[6] << 8) | buffer_[7];
|
(buffer_[payload_offset_] << 24) | (buffer_[payload_offset_ + 1] << 16) |
|
||||||
ssrc_ = (buffer_[8] << 24) | (buffer_[9] << 16) | (buffer_[10] << 8) |
|
(buffer_[payload_offset_ + 2] << 8) | buffer_[payload_offset_ + 3];
|
||||||
buffer_[11];
|
|
||||||
|
|
||||||
for (uint32_t index = 0; index < total_csrc_number_; index++) {
|
// 9th byte to 12th byte
|
||||||
uint32_t csrc = (buffer_[12 + index] << 24) | (buffer_[13 + index] << 16) |
|
ssrc_ = (buffer_[payload_offset_] << 24) |
|
||||||
(buffer_[14 + index] << 8) | buffer_[15 + index];
|
(buffer_[payload_offset_ + 1] << 16) |
|
||||||
|
(buffer_[payload_offset_ + 2] << 8) | buffer_[payload_offset_ + 3];
|
||||||
|
|
||||||
|
payload_offset_ = kFixedHeaderSize;
|
||||||
|
|
||||||
|
if (kFixedHeaderSize + csrc_count_ * 4 > size) {
|
||||||
|
LOG_WARN("RtpPacket::Parse: csrc count is too large");
|
||||||
|
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];
|
||||||
csrcs_.push_back(csrc);
|
csrcs_.push_back(csrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t extension_offset = total_csrc_number_ * 4;
|
payload_offset_ = kFixedHeaderSize + csrc_count_ * 4;
|
||||||
|
if (payload_offset_ > size) {
|
||||||
|
LOG_WARN("RtpPacket::Parse: payload offset is too large");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extensions
|
||||||
if (has_extension_) {
|
if (has_extension_) {
|
||||||
|
if (payload_offset_ + 4 > size) {
|
||||||
|
LOG_WARN("RtpPacket::Parse: extension profile is too large");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
extension_profile_ =
|
extension_profile_ =
|
||||||
(buffer_[12 + extension_offset] << 8) | buffer_[13 + extension_offset];
|
(buffer_[payload_offset_] << 8) | buffer_[payload_offset_ + 1];
|
||||||
extension_len_ =
|
extension_len_ =
|
||||||
(buffer_[14 + extension_offset] << 8) | buffer_[15 + extension_offset];
|
(buffer_[payload_offset_ + 2] << 8) | buffer_[payload_offset_ + 3];
|
||||||
|
|
||||||
// extension_data_ = new uint8_t[extension_len_];
|
if (payload_offset_ + 4 + extension_len_ > size) {
|
||||||
// memcpy(extension_data_, buffer_ + 16 + extension_offset,
|
LOG_WARN("RtpPacket::Parse: extension len is too large");
|
||||||
// extension_len_);
|
return false;
|
||||||
extension_data_ = buffer_ + 16 + extension_offset;
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (offset + 1 + len > size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extensions_.push_back(
|
||||||
|
{id, std::vector<uint8_t>(buffer_ + offset + 1,
|
||||||
|
buffer_ + offset + 1 + len)});
|
||||||
|
offset += 1 + len;
|
||||||
|
}
|
||||||
|
payload_offset_ += (4 + extension_len_);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t payload_offset =
|
if (has_padding_ && payload_offset_ < size) {
|
||||||
(has_extension_ ? extension_len_ : 0) + extension_offset;
|
padding_size_ = buffer[size - 1];
|
||||||
|
if (padding_size_ == 0) {
|
||||||
payload_size_ = size_ - (12 + payload_offset);
|
LOG_WARN("Padding was set, but padding size is zero");
|
||||||
payload_ = buffer_ + 12 + payload_offset;
|
return false;
|
||||||
if (payload) {
|
}
|
||||||
memcpy(payload, payload_, payload_size_);
|
} else {
|
||||||
|
padding_size_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return payload_size_;
|
// payload
|
||||||
}
|
if (payload_offset_ + padding_size_ > size) {
|
||||||
|
LOG_WARN("RtpPacket::Parse: payload size is too large");
|
||||||
size_t RtpPacket::DecodeData(uint8_t *payload) {
|
return false;
|
||||||
version_ = (buffer_[0] >> 6) & 0x03;
|
}
|
||||||
has_padding_ = (buffer_[0] >> 5) & 0x01;
|
payload_size_ = size - payload_offset_ - padding_size_;
|
||||||
has_extension_ = (buffer_[0] >> 4) & 0x01;
|
|
||||||
total_csrc_number_ = buffer_[0] & 0x0f;
|
return true;
|
||||||
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_ - (12 + payload_offset);
|
|
||||||
payload_ = buffer_ + 12 + payload_offset;
|
|
||||||
if (payload) {
|
|
||||||
memcpy(payload, payload_, payload_size_);
|
|
||||||
}
|
|
||||||
|
|
||||||
return payload_size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t RtpPacket::DecodeH264Nalu(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;
|
|
||||||
|
|
||||||
fu_indicator_.forbidden_bit = (buffer_[12 + payload_offset] >> 7) & 0x01;
|
|
||||||
fu_indicator_.nal_reference_idc = (buffer_[12 + payload_offset] >> 5) & 0x03;
|
|
||||||
fu_indicator_.nal_unit_type = buffer_[12 + payload_offset] & 0x1F;
|
|
||||||
|
|
||||||
payload_size_ = size_ - (13 + payload_offset);
|
|
||||||
payload_ = buffer_ + 13 + payload_offset;
|
|
||||||
if (payload) {
|
|
||||||
memcpy(payload, payload_, payload_size_);
|
|
||||||
}
|
|
||||||
return payload_size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t RtpPacket::DecodeH264Fua(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_ = buffer_ + 16 + extension_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t payload_offset =
|
|
||||||
(has_extension_ ? extension_len_ : 0) + extension_offset;
|
|
||||||
|
|
||||||
fu_indicator_.forbidden_bit = (buffer_[12 + payload_offset] >> 7) & 0x01;
|
|
||||||
fu_indicator_.nal_reference_idc = (buffer_[12 + payload_offset] >> 5) & 0x03;
|
|
||||||
fu_indicator_.nal_unit_type = buffer_[12 + payload_offset] & 0x1F;
|
|
||||||
|
|
||||||
fu_header_.start = (buffer_[13 + payload_offset] >> 7) & 0x01;
|
|
||||||
fu_header_.end = (buffer_[13 + payload_offset] >> 6) & 0x01;
|
|
||||||
fu_header_.remain_bit = (buffer_[13 + payload_offset] >> 5) & 0x01;
|
|
||||||
fu_header_.nal_unit_type = buffer_[13 + payload_offset] & 0x1F;
|
|
||||||
|
|
||||||
payload_size_ = size_ - (14 + payload_offset);
|
|
||||||
payload_ = buffer_ + 14 + payload_offset;
|
|
||||||
if (payload) {
|
|
||||||
memcpy(payload, payload_, payload_size_);
|
|
||||||
}
|
|
||||||
return payload_size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t RtpPacket::DecodeH264FecSource(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_ = buffer_ + 16 + extension_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t fec_symbol_id_offset =
|
|
||||||
extension_offset + (has_extension_ ? extension_len_ : 0);
|
|
||||||
fec_symbol_id_ = buffer_[12 + fec_symbol_id_offset];
|
|
||||||
|
|
||||||
uint32_t fec_source_symbol_num_offset = fec_symbol_id_offset + 1;
|
|
||||||
fec_source_symbol_num_ = buffer_[12 + fec_source_symbol_num_offset];
|
|
||||||
|
|
||||||
uint32_t payload_offset = fec_source_symbol_num_offset + 1;
|
|
||||||
|
|
||||||
fu_indicator_.forbidden_bit = (buffer_[12 + payload_offset] >> 7) & 0x01;
|
|
||||||
fu_indicator_.nal_reference_idc = (buffer_[12 + payload_offset] >> 5) & 0x03;
|
|
||||||
fu_indicator_.nal_unit_type = buffer_[12 + payload_offset] & 0x1F;
|
|
||||||
|
|
||||||
fu_header_.start = (buffer_[13 + payload_offset] >> 7) & 0x01;
|
|
||||||
fu_header_.end = (buffer_[13 + payload_offset] >> 6) & 0x01;
|
|
||||||
fu_header_.remain_bit = (buffer_[13 + payload_offset] >> 5) & 0x01;
|
|
||||||
fu_header_.nal_unit_type = buffer_[13 + payload_offset] & 0x1F;
|
|
||||||
|
|
||||||
payload_size_ = size_ - (14 + payload_offset);
|
|
||||||
payload_ = buffer_ + 14 + payload_offset;
|
|
||||||
if (payload) {
|
|
||||||
memcpy(payload, payload_, payload_size_);
|
|
||||||
}
|
|
||||||
return payload_size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t RtpPacket::DecodeH264FecRepair(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_ = buffer_ + 16 + extension_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t fec_symbol_id_offset =
|
|
||||||
extension_offset + (has_extension_ ? extension_len_ : 0);
|
|
||||||
fec_symbol_id_ = buffer_[12 + fec_symbol_id_offset];
|
|
||||||
|
|
||||||
uint32_t fec_source_symbol_num_offset = fec_symbol_id_offset + 1;
|
|
||||||
fec_source_symbol_num_ = buffer_[12 + fec_source_symbol_num_offset];
|
|
||||||
|
|
||||||
uint32_t payload_offset = fec_source_symbol_num_offset + 1;
|
|
||||||
|
|
||||||
payload_size_ = size_ - (14 + payload_offset);
|
|
||||||
payload_ = buffer_ + 14 + payload_offset;
|
|
||||||
if (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 aggr_header_offset =
|
|
||||||
(has_extension_ ? extension_len_ : 0) + extension_offset;
|
|
||||||
|
|
||||||
av1_aggr_header_ = buffer_[12 + aggr_header_offset];
|
|
||||||
|
|
||||||
uint32_t payload_offset = aggr_header_offset;
|
|
||||||
|
|
||||||
payload_size_ = size_ - (13 + payload_offset);
|
|
||||||
payload_ = buffer_ + 13 + payload_offset;
|
|
||||||
if (payload) {
|
|
||||||
memcpy(payload, payload_, payload_size_);
|
|
||||||
}
|
|
||||||
|
|
||||||
return payload_size_;
|
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,9 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "copy_on_write_buffer.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "rtp_header.h"
|
||||||
|
|
||||||
// Common
|
// Common
|
||||||
// 0 1 2 3
|
// 0 1 2 3
|
||||||
@@ -180,12 +182,13 @@ class RtpPacket {
|
|||||||
DATA = 127
|
DATA = 127
|
||||||
} PAYLOAD_TYPE;
|
} PAYLOAD_TYPE;
|
||||||
|
|
||||||
typedef enum { UNKNOWN = 0, NALU = 1, FU_A = 28, FU_B = 29 } NAL_UNIT_TYPE;
|
constexpr uint16_t kOneByteExtensionProfileId = 0xBEDE;
|
||||||
|
constexpr uint16_t kTwoByteExtensionProfileId = 0x1000;
|
||||||
|
|
||||||
|
constexpr size_t kFixedHeaderSize = 12;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RtpPacket();
|
RtpPacket();
|
||||||
RtpPacket(uint32_t size);
|
|
||||||
RtpPacket(const uint8_t *buffer, uint32_t size);
|
|
||||||
RtpPacket(const RtpPacket &rtp_packet);
|
RtpPacket(const RtpPacket &rtp_packet);
|
||||||
RtpPacket(RtpPacket &&rtp_packet);
|
RtpPacket(RtpPacket &&rtp_packet);
|
||||||
RtpPacket &operator=(const RtpPacket &rtp_packet);
|
RtpPacket &operator=(const RtpPacket &rtp_packet);
|
||||||
@@ -212,15 +215,6 @@ class RtpPacket {
|
|||||||
void SetSsrc(uint32_t ssrc) { ssrc_ = ssrc; }
|
void SetSsrc(uint32_t ssrc) { ssrc_ = ssrc; }
|
||||||
void SetCsrcs(std::vector<uint32_t> &csrcs) { csrcs_ = csrcs; }
|
void SetCsrcs(std::vector<uint32_t> &csrcs) { csrcs_ = csrcs; }
|
||||||
|
|
||||||
void SetExtensionProfile(uint16_t extension_profile) {
|
|
||||||
// extension_profile_ = extension_profile;
|
|
||||||
}
|
|
||||||
void SetExtensionData(uint8_t *extension_data, uint16_t extension_len) {
|
|
||||||
// extension_len_ = extension_len;
|
|
||||||
// extension_data_ = new uint8_t[extension_len_];
|
|
||||||
// memcpy(extension_data_, extension_data, extension_len_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetAbsoluteSendTimestamp(uint32_t abs_send_time) {
|
void SetAbsoluteSendTimestamp(uint32_t abs_send_time) {
|
||||||
// Absolute Send Time is a 24-bit field, we need to ensure it fits in 24
|
// Absolute Send Time is a 24-bit field, we need to ensure it fits in 24
|
||||||
// bits
|
// bits
|
||||||
@@ -235,7 +229,7 @@ class RtpPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the extension profile to 0xBEDE (one-byte header)
|
// Set the extension profile to 0xBEDE (one-byte header)
|
||||||
extension_profile_ = 0xBEDE;
|
extension_profile_ = kOneByteExtensionProfileId;
|
||||||
|
|
||||||
// Set the length of the extension data (in 32-bit words minus one)
|
// Set the length of the extension data (in 32-bit words minus one)
|
||||||
extension_data_[0] = 0x00;
|
extension_data_[0] = 0x00;
|
||||||
@@ -247,238 +241,74 @@ class RtpPacket {
|
|||||||
extension_data_[4] = abs_send_time & 0xFF;
|
extension_data_[4] = abs_send_time & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
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;
|
|
||||||
|
|
||||||
void SetFuIndicator(FU_INDICATOR fu_indicator) {
|
|
||||||
fu_indicator_.forbidden_bit = fu_indicator.forbidden_bit;
|
|
||||||
fu_indicator_.nal_reference_idc = fu_indicator.nal_reference_idc;
|
|
||||||
fu_indicator_.nal_unit_type = fu_indicator.nal_unit_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFuHeader(FU_HEADER fu_header) {
|
|
||||||
fu_header_.start = fu_header.start;
|
|
||||||
fu_header_.end = fu_header.end;
|
|
||||||
fu_header_.remain_bit = fu_header.remain_bit;
|
|
||||||
fu_header_.nal_unit_type = fu_header.nal_unit_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetAv1AggrHeader(int z, int y, int w, int n) {
|
|
||||||
if (z) av1_aggr_header_ |= (1 << 7);
|
|
||||||
if (y) av1_aggr_header_ |= (1 << 6);
|
|
||||||
if (w) av1_aggr_header_ |= w << 4;
|
|
||||||
if (n) av1_aggr_header_ |= (1 << 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFecSymbolId(uint8_t fec_symbol_id) { fec_symbol_id_ = fec_symbol_id; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
const uint8_t *Encode(uint8_t *payload, size_t payload_size);
|
|
||||||
const uint8_t *EncodeH264Nalu(uint8_t *payload, size_t payload_size);
|
|
||||||
const uint8_t *EncodeH264Fua(uint8_t *payload, size_t payload_size);
|
|
||||||
const uint8_t *EncodeH264FecSource(uint8_t *payload, size_t payload_size,
|
|
||||||
uint8_t fec_symbol_id,
|
|
||||||
uint8_t fec_source_symbol_num);
|
|
||||||
const uint8_t *EncodeH264FecRepair(uint8_t *payload, size_t payload_size,
|
|
||||||
uint8_t fec_symbol_id,
|
|
||||||
uint8_t 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:
|
public:
|
||||||
// Get Header
|
// Get Header
|
||||||
uint32_t Verion() const {
|
uint32_t Verion() const { return version_; }
|
||||||
// // ParseRtpData();
|
bool HasPadding() const { return has_padding_; }
|
||||||
return version_;
|
bool HasExtension() const { return has_extension_; }
|
||||||
}
|
bool Marker() const { return marker_; }
|
||||||
bool HasPadding() const {
|
PAYLOAD_TYPE PayloadType() const { return PAYLOAD_TYPE(payload_type_); }
|
||||||
// ParseRtpData();
|
uint16_t SequenceNumber() const { return sequence_number_; }
|
||||||
return has_padding_;
|
uint64_t Timestamp() const { return timestamp_; }
|
||||||
}
|
uint32_t Ssrc() const { return ssrc_; }
|
||||||
bool HasExtension() const {
|
std::vector<uint32_t> Csrcs() const { return csrcs_; };
|
||||||
// ParseRtpData();
|
uint16_t ExtensionProfile() const { return extension_profile_; }
|
||||||
return has_extension_;
|
const uint8_t *ExtensionData() { return extension_data_; }
|
||||||
}
|
|
||||||
bool Marker() const {
|
|
||||||
// // ParseRtpData();
|
|
||||||
return marker_;
|
|
||||||
}
|
|
||||||
PAYLOAD_TYPE PayloadType() const {
|
|
||||||
// ParseRtpData();
|
|
||||||
return PAYLOAD_TYPE(payload_type_);
|
|
||||||
}
|
|
||||||
uint16_t SequenceNumber() const {
|
|
||||||
// ParseRtpData();
|
|
||||||
return sequence_number_;
|
|
||||||
}
|
|
||||||
uint64_t Timestamp() const {
|
|
||||||
// ParseRtpData();
|
|
||||||
return timestamp_;
|
|
||||||
}
|
|
||||||
uint32_t Ssrc() const {
|
|
||||||
// ParseRtpData();
|
|
||||||
return ssrc_;
|
|
||||||
}
|
|
||||||
std::vector<uint32_t> Csrcs() const {
|
|
||||||
// ParseRtpData();
|
|
||||||
return csrcs_;
|
|
||||||
};
|
|
||||||
uint16_t ExtensionProfile() const {
|
|
||||||
// ParseRtpData();
|
|
||||||
return extension_profile_;
|
|
||||||
}
|
|
||||||
const uint8_t *ExtensionData() {
|
|
||||||
// ParseRtpData();
|
|
||||||
return extension_data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t GetAbsoluteSendTimestamp(uint32_t *abs_send_time) const {
|
|
||||||
if (extension_data_ == nullptr || extension_len_ < 4) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Absolute Send Time is a 24-bit field
|
|
||||||
*abs_send_time = (extension_data_[2] << 16) | (extension_data_[3] << 8) |
|
|
||||||
extension_data_[4];
|
|
||||||
|
|
||||||
return *abs_send_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t FecSymbolId() { return fec_symbol_id_; }
|
|
||||||
|
|
||||||
uint8_t FecSourceSymbolNum() { return fec_source_symbol_num_; }
|
|
||||||
|
|
||||||
void GetAv1AggrHeader(int &z, int &y, int &w, int &n) {
|
|
||||||
z = av1_aggr_header_ >> 7;
|
|
||||||
y = av1_aggr_header_ >> 6 & 0x01;
|
|
||||||
w = av1_aggr_header_ >> 4 & 0x03;
|
|
||||||
n = av1_aggr_header_ >> 3 & 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Payload
|
// Payload
|
||||||
const uint8_t *Payload() {
|
const uint8_t *Payload() { return Buffer() + payload_offset_; };
|
||||||
// ParseRtpData();
|
size_t PayloadSize() { return payload_size_; }
|
||||||
return payload_;
|
|
||||||
};
|
|
||||||
size_t PayloadSize() {
|
|
||||||
// ParseRtpData();
|
|
||||||
return payload_size_;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t headers_size() const { return 12; }
|
|
||||||
|
|
||||||
size_t payload_size() const { return payload_size_; }
|
|
||||||
|
|
||||||
bool has_padding() const { return buffer_[0] & 0x20; }
|
|
||||||
|
|
||||||
size_t padding_size() const { return padding_size_; }
|
|
||||||
|
|
||||||
// Entire RTP buffer
|
// Entire RTP buffer
|
||||||
const uint8_t *Buffer() const { return buffer_; }
|
const uint8_t *Buffer() const { return buffer_; }
|
||||||
size_t Size() const { return size_; }
|
size_t Size() const { return size_; }
|
||||||
|
|
||||||
|
// For webrtc module use
|
||||||
|
size_t headers_size() const { return payload_offset_; }
|
||||||
|
size_t payload_size() const { return payload_size_; }
|
||||||
|
bool has_padding() const { return buffer_[0] & 0x20; }
|
||||||
|
size_t padding_size() const { return padding_size_; }
|
||||||
size_t size() const { return size_; }
|
size_t size() const { return size_; }
|
||||||
|
|
||||||
// NAL
|
|
||||||
NAL_UNIT_TYPE NalUnitType() {
|
|
||||||
// ParseRtpData();
|
|
||||||
return nal_unit_type_;
|
|
||||||
}
|
|
||||||
bool FuAStart() {
|
|
||||||
// ParseRtpData();
|
|
||||||
return fu_header_.start;
|
|
||||||
}
|
|
||||||
bool FuAEnd() {
|
|
||||||
// ParseRtpData();
|
|
||||||
return fu_header_.end;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Av1FrameStart() {
|
|
||||||
// ParseRtpData();
|
|
||||||
int z, y, w, n;
|
|
||||||
GetAv1AggrHeader(z, y, w, n);
|
|
||||||
// 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() {
|
|
||||||
// ParseRtpData();
|
|
||||||
int z, y, w, n;
|
|
||||||
GetAv1AggrHeader(z, y, w, n);
|
|
||||||
// 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:
|
private:
|
||||||
void TryToDecodeRtpPacket();
|
// Common header
|
||||||
void ParseRtpData();
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Header
|
|
||||||
uint8_t version_ = 0;
|
uint8_t version_ = 0;
|
||||||
bool has_padding_ = false;
|
bool has_padding_ = false;
|
||||||
bool has_extension_ = false;
|
bool has_extension_ = false;
|
||||||
uint8_t total_csrc_number_ = 0;
|
uint8_t csrc_count_ = 0;
|
||||||
bool marker_ = false;
|
bool marker_ = false;
|
||||||
uint8_t payload_type_ = 0;
|
uint8_t payload_type_ = 0;
|
||||||
uint16_t sequence_number_ = 1;
|
uint16_t sequence_number_ = 1;
|
||||||
uint64_t timestamp_ = 0;
|
uint64_t timestamp_ = 0;
|
||||||
uint32_t ssrc_ = 0;
|
uint32_t ssrc_ = 0;
|
||||||
std::vector<uint32_t> csrcs_;
|
std::vector<uint32_t> csrcs_;
|
||||||
uint16_t profile_ = 0;
|
|
||||||
|
// Extension header
|
||||||
uint16_t extension_profile_ = 0;
|
uint16_t extension_profile_ = 0;
|
||||||
uint16_t extension_len_ = 0;
|
uint16_t extension_len_ = 0;
|
||||||
uint8_t *extension_data_ = nullptr;
|
struct Extension {
|
||||||
|
uint8_t id;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
};
|
||||||
|
std::vector<Extension> extensions_;
|
||||||
|
|
||||||
|
// Payload
|
||||||
|
size_t payload_offset_ = 0;
|
||||||
|
size_t payload_size_ = 0;
|
||||||
|
|
||||||
|
// Padding
|
||||||
|
size_t padding_size_ = 0;
|
||||||
|
|
||||||
|
// Entire rtp buffer
|
||||||
|
CopyOnWriteBuffer buffer_ = nullptr;
|
||||||
|
size_t size_ = 0;
|
||||||
|
|
||||||
|
// H.264 header
|
||||||
FU_INDICATOR fu_indicator_;
|
FU_INDICATOR fu_indicator_;
|
||||||
FU_HEADER fu_header_;
|
FU_HEADER fu_header_;
|
||||||
uint8_t fec_symbol_id_ = 0;
|
uint8_t fec_symbol_id_ = 0;
|
||||||
uint8_t fec_source_symbol_num_ = 0;
|
uint8_t fec_source_symbol_num_ = 0;
|
||||||
uint8_t av1_aggr_header_ = 0;
|
uint8_t av1_aggr_header_ = 0;
|
||||||
|
|
||||||
// Payload
|
|
||||||
uint8_t *payload_ = nullptr;
|
|
||||||
size_t payload_size_ = 0;
|
|
||||||
size_t padding_size_ = 0;
|
|
||||||
|
|
||||||
// Entire RTP buffer
|
|
||||||
uint8_t *buffer_ = nullptr;
|
|
||||||
size_t size_ = 0;
|
|
||||||
|
|
||||||
// NAL
|
|
||||||
NAL_UNIT_TYPE nal_unit_type_ = NAL_UNIT_TYPE::UNKNOWN;
|
|
||||||
|
|
||||||
bool parsed_ = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
484
src/rtp/rtp_packet/rtp_packet.hxx
Normal file
484
src/rtp/rtp_packet/rtp_packet.hxx
Normal file
@@ -0,0 +1,484 @@
|
|||||||
|
#ifndef _RTP_PACKET_H_
|
||||||
|
#define _RTP_PACKET_H_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
// Common
|
||||||
|
// 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
|
||||||
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
// | defined by profile | length |x
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | Extensions |x
|
||||||
|
// | .... |x
|
||||||
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
// | Payload |
|
||||||
|
// | .... : padding... |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | padding | Padding size |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
// H264
|
||||||
|
// 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
|
||||||
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
// | defined by profile | length |x
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | Extensions |x
|
||||||
|
// | .... |x
|
||||||
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
// | FU indicator | FU header | |
|
||||||
|
// | |
|
||||||
|
// | FU Payload |
|
||||||
|
// | |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | padding | Padding size |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
// | FU indicator | FU header |
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// |F|NRI| Type |S|E|R| Type |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
// H264 FEC source symbol
|
||||||
|
// 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
|
||||||
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
// | defined by profile | length |x
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | Extensions |x
|
||||||
|
// | .... |x
|
||||||
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
// | FEC symbol id | src sym num | FU indicator | FU header |
|
||||||
|
// | |
|
||||||
|
// | FU Payload |
|
||||||
|
// | |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | padding | Padding size |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
// H264 FEC repair symbol
|
||||||
|
// 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
|
||||||
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
// | defined by profile | length |x
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | Extensions |x
|
||||||
|
// | .... |x
|
||||||
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||||
|
// | FEC symbol id | src sym num | |
|
||||||
|
// | |
|
||||||
|
// | Fec Payload |
|
||||||
|
// | |
|
||||||
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
// | 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 |
|
||||||
|
//
|
||||||
|
// Z=1: first obu element is an obu fragment that is a continuation of an OBU
|
||||||
|
// fragment from the previous packet.
|
||||||
|
//
|
||||||
|
// Y=1: the last OBU element is an OBU fragment that will continue in the next
|
||||||
|
// packet.
|
||||||
|
//
|
||||||
|
// W=1: two bit field that describes the number of OBU elements in the packet.
|
||||||
|
//
|
||||||
|
// N=1: the packet is the first packet of a coded video sequence.
|
||||||
|
//
|
||||||
|
// 0 1 2 3 4 5 6 7
|
||||||
|
// +-+-+-+-+-+-+-+-+
|
||||||
|
// |Z|Y| W |N|-|-|-|
|
||||||
|
// +-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
#define DEFAULT_MTU 1500
|
||||||
|
#define MAX_NALU_LEN 1400
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
typedef enum { UNKNOWN = 0, NALU = 1, FU_A = 28, FU_B = 29 } NAL_UNIT_TYPE;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RtpPacket();
|
||||||
|
RtpPacket(uint32_t size);
|
||||||
|
RtpPacket(const uint8_t *buffer, uint32_t size);
|
||||||
|
RtpPacket(const RtpPacket &rtp_packet);
|
||||||
|
RtpPacket(RtpPacket &&rtp_packet);
|
||||||
|
RtpPacket &operator=(const RtpPacket &rtp_packet);
|
||||||
|
RtpPacket &operator=(RtpPacket &&rtp_packet);
|
||||||
|
|
||||||
|
virtual ~RtpPacket();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool Build(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) {
|
||||||
|
payload_type_ = (uint8_t)payload_type;
|
||||||
|
}
|
||||||
|
void SetSequenceNumber(uint16_t sequence_number) {
|
||||||
|
sequence_number_ = sequence_number;
|
||||||
|
}
|
||||||
|
void SetTimestamp(uint64_t timestamp) { timestamp_ = timestamp; }
|
||||||
|
void SetSsrc(uint32_t ssrc) { ssrc_ = ssrc; }
|
||||||
|
void SetCsrcs(std::vector<uint32_t> &csrcs) { csrcs_ = csrcs; }
|
||||||
|
|
||||||
|
void SetExtensionProfile(uint16_t extension_profile) {
|
||||||
|
// extension_profile_ = extension_profile;
|
||||||
|
}
|
||||||
|
void SetExtensionData(uint8_t *extension_data, uint16_t extension_len) {
|
||||||
|
// extension_len_ = extension_len;
|
||||||
|
// extension_data_ = new uint8_t[extension_len_];
|
||||||
|
// memcpy(extension_data_, extension_data, extension_len_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetAbsoluteSendTimestamp(uint32_t abs_send_time) {
|
||||||
|
// Absolute Send Time is a 24-bit field, we need to ensure it fits in 24
|
||||||
|
// 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_ = 0xBEDE;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
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;
|
||||||
|
|
||||||
|
void SetFuIndicator(FU_INDICATOR fu_indicator) {
|
||||||
|
fu_indicator_.forbidden_bit = fu_indicator.forbidden_bit;
|
||||||
|
fu_indicator_.nal_reference_idc = fu_indicator.nal_reference_idc;
|
||||||
|
fu_indicator_.nal_unit_type = fu_indicator.nal_unit_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetFuHeader(FU_HEADER fu_header) {
|
||||||
|
fu_header_.start = fu_header.start;
|
||||||
|
fu_header_.end = fu_header.end;
|
||||||
|
fu_header_.remain_bit = fu_header.remain_bit;
|
||||||
|
fu_header_.nal_unit_type = fu_header.nal_unit_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetAv1AggrHeader(int z, int y, int w, int n) {
|
||||||
|
if (z) av1_aggr_header_ |= (1 << 7);
|
||||||
|
if (y) av1_aggr_header_ |= (1 << 6);
|
||||||
|
if (w) av1_aggr_header_ |= w << 4;
|
||||||
|
if (n) av1_aggr_header_ |= (1 << 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetFecSymbolId(uint8_t fec_symbol_id) { fec_symbol_id_ = fec_symbol_id; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
const uint8_t *Encode(uint8_t *payload, size_t payload_size);
|
||||||
|
const uint8_t *EncodeH264Nalu(uint8_t *payload, size_t payload_size);
|
||||||
|
const uint8_t *EncodeH264Fua(uint8_t *payload, size_t payload_size);
|
||||||
|
const uint8_t *EncodeH264FecSource(uint8_t *payload, size_t payload_size,
|
||||||
|
uint8_t fec_symbol_id,
|
||||||
|
uint8_t fec_source_symbol_num);
|
||||||
|
const uint8_t *EncodeH264FecRepair(uint8_t *payload, size_t payload_size,
|
||||||
|
uint8_t fec_symbol_id,
|
||||||
|
uint8_t 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:
|
||||||
|
// Get Header
|
||||||
|
uint32_t Verion() const {
|
||||||
|
// // ParseRtpData();
|
||||||
|
return version_;
|
||||||
|
}
|
||||||
|
bool HasPadding() const {
|
||||||
|
// ParseRtpData();
|
||||||
|
return has_padding_;
|
||||||
|
}
|
||||||
|
bool HasExtension() const {
|
||||||
|
// ParseRtpData();
|
||||||
|
return has_extension_;
|
||||||
|
}
|
||||||
|
bool Marker() const {
|
||||||
|
// // ParseRtpData();
|
||||||
|
return marker_;
|
||||||
|
}
|
||||||
|
PAYLOAD_TYPE PayloadType() const {
|
||||||
|
// ParseRtpData();
|
||||||
|
return PAYLOAD_TYPE(payload_type_);
|
||||||
|
}
|
||||||
|
uint16_t SequenceNumber() const {
|
||||||
|
// ParseRtpData();
|
||||||
|
return sequence_number_;
|
||||||
|
}
|
||||||
|
uint64_t Timestamp() const {
|
||||||
|
// ParseRtpData();
|
||||||
|
return timestamp_;
|
||||||
|
}
|
||||||
|
uint32_t Ssrc() const {
|
||||||
|
// ParseRtpData();
|
||||||
|
return ssrc_;
|
||||||
|
}
|
||||||
|
std::vector<uint32_t> Csrcs() const {
|
||||||
|
// ParseRtpData();
|
||||||
|
return csrcs_;
|
||||||
|
};
|
||||||
|
uint16_t ExtensionProfile() const {
|
||||||
|
// ParseRtpData();
|
||||||
|
return extension_profile_;
|
||||||
|
}
|
||||||
|
const uint8_t *ExtensionData() {
|
||||||
|
// ParseRtpData();
|
||||||
|
return extension_data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetAbsoluteSendTimestamp(uint32_t *abs_send_time) const {
|
||||||
|
if (extension_data_ == nullptr || extension_len_ < 4) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Absolute Send Time is a 24-bit field
|
||||||
|
*abs_send_time = (extension_data_[2] << 16) | (extension_data_[3] << 8) |
|
||||||
|
extension_data_[4];
|
||||||
|
|
||||||
|
return *abs_send_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t FecSymbolId() { return fec_symbol_id_; }
|
||||||
|
|
||||||
|
uint8_t FecSourceSymbolNum() { return fec_source_symbol_num_; }
|
||||||
|
|
||||||
|
void GetAv1AggrHeader(int &z, int &y, int &w, int &n) {
|
||||||
|
z = av1_aggr_header_ >> 7;
|
||||||
|
y = av1_aggr_header_ >> 6 & 0x01;
|
||||||
|
w = av1_aggr_header_ >> 4 & 0x03;
|
||||||
|
n = av1_aggr_header_ >> 3 & 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payload
|
||||||
|
const uint8_t *Payload() {
|
||||||
|
// ParseRtpData();
|
||||||
|
return payload_;
|
||||||
|
};
|
||||||
|
size_t PayloadSize() {
|
||||||
|
// ParseRtpData();
|
||||||
|
return payload_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t headers_size() const { return 12; }
|
||||||
|
|
||||||
|
size_t payload_size() const { return payload_size_; }
|
||||||
|
|
||||||
|
bool has_padding() const { return buffer_[0] & 0x20; }
|
||||||
|
|
||||||
|
size_t padding_size() const { return padding_size_; }
|
||||||
|
|
||||||
|
// Entire RTP buffer
|
||||||
|
const uint8_t *Buffer() const { return buffer_; }
|
||||||
|
size_t Size() const { return size_; }
|
||||||
|
size_t size() const { return size_; }
|
||||||
|
|
||||||
|
// NAL
|
||||||
|
NAL_UNIT_TYPE NalUnitType() {
|
||||||
|
// ParseRtpData();
|
||||||
|
return nal_unit_type_;
|
||||||
|
}
|
||||||
|
bool FuAStart() {
|
||||||
|
// ParseRtpData();
|
||||||
|
return fu_header_.start;
|
||||||
|
}
|
||||||
|
bool FuAEnd() {
|
||||||
|
// ParseRtpData();
|
||||||
|
return fu_header_.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Av1FrameStart() {
|
||||||
|
// ParseRtpData();
|
||||||
|
int z, y, w, n;
|
||||||
|
GetAv1AggrHeader(z, y, w, n);
|
||||||
|
// 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() {
|
||||||
|
// ParseRtpData();
|
||||||
|
int z, y, w, n;
|
||||||
|
GetAv1AggrHeader(z, y, w, n);
|
||||||
|
// 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:
|
||||||
|
void TryToDecodeRtpPacket();
|
||||||
|
void ParseRtpData();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Header
|
||||||
|
uint8_t version_ = 0;
|
||||||
|
bool has_padding_ = false;
|
||||||
|
bool has_extension_ = false;
|
||||||
|
uint8_t csrc_count_ = 0;
|
||||||
|
bool marker_ = false;
|
||||||
|
uint8_t payload_type_ = 0;
|
||||||
|
uint16_t sequence_number_ = 1;
|
||||||
|
uint64_t timestamp_ = 0;
|
||||||
|
uint32_t ssrc_ = 0;
|
||||||
|
std::vector<uint32_t> csrcs_;
|
||||||
|
uint16_t profile_ = 0;
|
||||||
|
uint16_t extension_profile_ = 0;
|
||||||
|
uint16_t extension_len_ = 0;
|
||||||
|
uint8_t *extension_data_ = nullptr;
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Payload
|
||||||
|
uint8_t *payload_ = nullptr;
|
||||||
|
size_t payload_size_ = 0;
|
||||||
|
size_t padding_size_ = 0;
|
||||||
|
|
||||||
|
// Entire RTP buffer
|
||||||
|
uint8_t *buffer_ = nullptr;
|
||||||
|
size_t size_ = 0;
|
||||||
|
|
||||||
|
// NAL
|
||||||
|
NAL_UNIT_TYPE nal_unit_type_ = NAL_UNIT_TYPE::UNKNOWN;
|
||||||
|
|
||||||
|
bool parsed_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -33,18 +33,21 @@ RtpPacketReceived& RtpPacketReceived::operator=(RtpPacketReceived&& packet) =
|
|||||||
RtpPacketReceived::~RtpPacketReceived() {}
|
RtpPacketReceived::~RtpPacketReceived() {}
|
||||||
|
|
||||||
void RtpPacketReceived::GetHeader(RTPHeader* header) const {
|
void RtpPacketReceived::GetHeader(RTPHeader* header) const {
|
||||||
header->markerBit = Marker();
|
header->version = Version();
|
||||||
header->payloadType = PayloadType();
|
header->has_padding_ = HasPadding();
|
||||||
header->sequenceNumber = SequenceNumber();
|
header->has_extension_ = HasExtension();
|
||||||
header->timestamp = Timestamp();
|
header->csrc_count_ = Csrcs().size();
|
||||||
header->ssrc = Ssrc();
|
header->marker_ = Marker();
|
||||||
|
header->payload_type_ = PayloadType();
|
||||||
|
header->sequence_number_ = SequenceNumber();
|
||||||
|
header->timestamp_ = Timestamp();
|
||||||
|
header->ssrc_ = Ssrc();
|
||||||
std::vector<uint32_t> csrcs = Csrcs();
|
std::vector<uint32_t> csrcs = Csrcs();
|
||||||
header->numCSRCs = rtc::dchecked_cast<uint8_t>(csrcs.size());
|
|
||||||
for (size_t i = 0; i < csrcs.size(); ++i) {
|
for (size_t i = 0; i < csrcs.size(); ++i) {
|
||||||
header->arrOfCSRCs[i] = csrcs[i];
|
header->csrc_[i] = csrcs[i];
|
||||||
}
|
}
|
||||||
header->paddingLength = padding_size();
|
header->padding_len = padding_size();
|
||||||
header->headerLength = headers_size();
|
header->header_len = headers_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
11
src/rtp/rtp_packetizer/rtp_packetizer.cpp
Normal file
11
src/rtp/rtp_packetizer/rtp_packetizer.cpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include "rtp_packetizer.h"
|
||||||
|
|
||||||
|
std::unique_ptr<RtpPacketizer> Create(uint32_t payload_type, uint8_t* payload,
|
||||||
|
size_t payload_size) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/rtp/rtp_packetizer/rtp_packetizer.h
Normal file
25
src/rtp/rtp_packetizer/rtp_packetizer.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* @Author: DI JUNKUN
|
||||||
|
* @Date: 2025-01-22
|
||||||
|
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RTP_PACKETIZER_H_
|
||||||
|
#define _RTP_PACKETIZER_H_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "rtp_packet.h"
|
||||||
|
|
||||||
|
class RtpPacketizer {
|
||||||
|
public:
|
||||||
|
static std::unique_ptr<RtpPacketizer> Create(uint32_t payload_type);
|
||||||
|
|
||||||
|
virtual ~RtpPacketizer() = default;
|
||||||
|
|
||||||
|
bool Build(uint8_t* payload, uint32_t payload_size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
0
src/rtp/rtp_packetizer/rtp_packetizer_av1.cpp
Normal file
0
src/rtp/rtp_packetizer/rtp_packetizer_av1.cpp
Normal file
0
src/rtp/rtp_packetizer/rtp_packetizer_av1.h
Normal file
0
src/rtp/rtp_packetizer/rtp_packetizer_av1.h
Normal file
0
src/rtp/rtp_packetizer/rtp_packetizer_generic.cpp
Normal file
0
src/rtp/rtp_packetizer/rtp_packetizer_generic.cpp
Normal file
0
src/rtp/rtp_packetizer/rtp_packetizer_generic.h
Normal file
0
src/rtp/rtp_packetizer/rtp_packetizer_generic.h
Normal file
266
src/rtp/rtp_packetizer/rtp_packetizer_h264.cpp
Normal file
266
src/rtp/rtp_packetizer/rtp_packetizer_h264.cpp
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
#include "rtp_packetizer_h264.h"
|
||||||
|
|
||||||
|
RtpPacketizerH264::RtpPacketizerH264()
|
||||||
|
: version_(kRtpVersion),
|
||||||
|
has_padding_(false),
|
||||||
|
has_extension_(true),
|
||||||
|
csrc_count_(0),
|
||||||
|
marker_(false),
|
||||||
|
payload_type_(RtpPacket::PAYLOAD_TYPE::H264),
|
||||||
|
sequence_number_(1),
|
||||||
|
timestamp_(0),
|
||||||
|
ssrc_(0),
|
||||||
|
profile_(0),
|
||||||
|
extension_profile_(0),
|
||||||
|
extension_len_(0),
|
||||||
|
extension_data_(nullptr) {}
|
||||||
|
|
||||||
|
RtpPacketizerH264::~RtpPacketizerH264() {}
|
||||||
|
|
||||||
|
std::vector<RtpPacket> RtpPacketizerH264::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();
|
||||||
|
|
||||||
|
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_);
|
||||||
|
sequence_number_++;
|
||||||
|
timestamp_ = timestamp_;
|
||||||
|
ssrc_ = ssrc_;
|
||||||
|
|
||||||
|
if (!csrc_count_) {
|
||||||
|
csrcs_ = csrcs_;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpPacket::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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
uint32_t abs_send_time =
|
||||||
|
std::chrono::duration_cast<std::chrono::microseconds>(
|
||||||
|
std::chrono::system_clock::now().time_since_epoch())
|
||||||
|
.count();
|
||||||
|
|
||||||
|
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((abs_send_time >> 16) & 0xFF);
|
||||||
|
rtp_packet_frame_.push_back((abs_send_time >> 8) & 0xFF);
|
||||||
|
rtp_packet_frame_.push_back(abs_send_time & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtp_packet_frame_.push_back(fu_indicator.forbidden_bit << 7 |
|
||||||
|
fu_indicator.nal_reference_idc << 6 |
|
||||||
|
fu_indicator.nal_unit_type);
|
||||||
|
|
||||||
|
rtp_packet_frame_.push_back(fu_header.start << 7 | fu_header.end << 6 |
|
||||||
|
fu_header.remain_bit << 1 |
|
||||||
|
fu_header.nal_unit_type);
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
packets.emplace_back(rtp_packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bool BuildFec(uint8_t* payload, uint32_t payload_size) {
|
||||||
|
// uint8_t** fec_packets =
|
||||||
|
// fec_encoder_.Encode((const char*)payload, payload_size);
|
||||||
|
// if (nullptr == fec_packets) {
|
||||||
|
// LOG_ERROR("Invalid fec_packets");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// uint8_t num_of_total_packets = 0;
|
||||||
|
// uint8_t num_of_source_packets = 0;
|
||||||
|
// unsigned int last_packet_size = 0;
|
||||||
|
// fec_encoder_.GetFecPacketsParams(payload_size, num_of_total_packets,
|
||||||
|
// num_of_source_packets, last_packet_size);
|
||||||
|
|
||||||
|
// timestamp_ = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||||
|
// std::chrono::system_clock::now().time_since_epoch())
|
||||||
|
// .count();
|
||||||
|
|
||||||
|
// for (uint8_t index = 0; index < num_of_total_packets; index++) {
|
||||||
|
// RtpPacket rtp_packet;
|
||||||
|
// if (index < num_of_source_packets) {
|
||||||
|
// rtp_packet.SetVerion(kRtpVersion);
|
||||||
|
// 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.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_);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// RtpPacket::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;
|
||||||
|
// fu_header.start = index == 0 ? 1 : 0;
|
||||||
|
// fu_header.end = index == num_of_source_packets - 1 ? 1 : 0;
|
||||||
|
// fu_header.remain_bit = 0;
|
||||||
|
// fu_header.nal_unit_type = FU_A;
|
||||||
|
|
||||||
|
// rtp_packet.SetFuIndicator(fu_indicator);
|
||||||
|
// rtp_packet.SetFuHeader(fu_header);
|
||||||
|
|
||||||
|
// if (index == num_of_source_packets - 1) {
|
||||||
|
// if (last_packet_size > 0) {
|
||||||
|
// rtp_packet.EncodeH264FecSource(fec_packets[index],
|
||||||
|
// last_packet_size,
|
||||||
|
// index, num_of_source_packets);
|
||||||
|
// } else {
|
||||||
|
// rtp_packet.EncodeH264FecSource(fec_packets[index], MAX_NALU_LEN,
|
||||||
|
// index, num_of_source_packets);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// rtp_packet.EncodeH264FecSource(fec_packets[index], MAX_NALU_LEN,
|
||||||
|
// index,
|
||||||
|
// num_of_source_packets);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// } else if (index >= num_of_source_packets && index <
|
||||||
|
// num_of_total_packets) {
|
||||||
|
// rtp_packet.SetVerion(kRtpVersion);
|
||||||
|
// 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.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_);
|
||||||
|
// }
|
||||||
|
// rtp_packet.EncodeH264FecRepair(fec_packets[index], MAX_NALU_LEN, index,
|
||||||
|
// num_of_source_packets);
|
||||||
|
// }
|
||||||
|
// packets.emplace_back(rtp_packet);
|
||||||
|
|
||||||
|
// // if (index < num_of_source_packets) {
|
||||||
|
// // rtp_packet.EncodeH264Fua(fec_packets[index], MAX_NALU_LEN);
|
||||||
|
// // packets.emplace_back(rtp_packet);
|
||||||
|
// // }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fec_encoder_.ReleaseFecPackets(fec_packets, payload_size);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (payload_size <= MAX_NALU_LEN) {
|
||||||
|
// RtpPacket rtp_packet;
|
||||||
|
// rtp_packet.SetVerion(kRtpVersion);
|
||||||
|
// rtp_packet.SetHasPadding(false);
|
||||||
|
|
||||||
|
// has_extension_ = true;
|
||||||
|
// uint32_t abs_send_time =
|
||||||
|
// std::chrono::duration_cast<std::chrono::microseconds>(
|
||||||
|
// std::chrono::system_clock::now().time_since_epoch())
|
||||||
|
// .count();
|
||||||
|
// rtp_packet.SetAbsoluteSendTimestamp(abs_send_time);
|
||||||
|
|
||||||
|
// 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::duration_cast<std::chrono::microseconds>(
|
||||||
|
// std::chrono::system_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_);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// RtpPacket::FU_INDICATOR fu_indicator;
|
||||||
|
// fu_indicator.forbidden_bit = 0;
|
||||||
|
// fu_indicator.nal_reference_idc = 1;
|
||||||
|
// fu_indicator.nal_unit_type = NALU;
|
||||||
|
// rtp_packet.SetFuIndicator(fu_indicator);
|
||||||
|
|
||||||
|
// rtp_packet.EncodeH264Nalu(payload, payload_size);
|
||||||
|
// packets.emplace_back(rtp_packet);
|
||||||
|
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
45
src/rtp/rtp_packetizer/rtp_packetizer_h264.h
Normal file
45
src/rtp/rtp_packetizer/rtp_packetizer_h264.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* @Author: DI JUNKUN
|
||||||
|
* @Date: 2025-01-22
|
||||||
|
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _RTP_PACKETIZER_H264_H_
|
||||||
|
#define _RTP_PACKETIZER_H264_H_
|
||||||
|
|
||||||
|
#include "rtp_packetizer.h"
|
||||||
|
|
||||||
|
class RtpPacketizerH264 : public RtpPacketizer {
|
||||||
|
public:
|
||||||
|
RtpPacketizerH264();
|
||||||
|
|
||||||
|
virtual ~RtpPacketizerH264();
|
||||||
|
|
||||||
|
std::vector<RtpPacket> Build(uint8_t* payload,
|
||||||
|
uint32_t payload_size) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool RtpPacketizerH264::EncodeH264Fua(RtpPacket& rtp_packet, uint8_t* payload,
|
||||||
|
size_t payload_size);
|
||||||
|
|
||||||
|
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
|
||||||
Reference in New Issue
Block a user