mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-26 20:25:34 +08:00
Implementation for FEC decoder module
This commit is contained in:
127
src/fec/fec_decoder.cpp
Normal file
127
src/fec/fec_decoder.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "fec_decoder.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
FecDecoder::FecDecoder() {}
|
||||
|
||||
FecDecoder::~FecDecoder() {}
|
||||
|
||||
int FecDecoder::Init() {
|
||||
fec_codec_id_ = OF_CODEC_REED_SOLOMON_GF_2_M_STABLE;
|
||||
|
||||
fec_rs_params_ = (of_rs_2_m_parameters_t *)calloc(1, sizeof(*fec_params_));
|
||||
if (nullptr == fec_rs_params_) {
|
||||
LOG_ERROR("Create FEC decoder params failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fec_rs_params_->m = 8;
|
||||
fec_params_ = (of_parameters_t *)fec_rs_params_;
|
||||
|
||||
if (OF_STATUS_OK !=
|
||||
of_create_codec_instance(&fec_session_, fec_codec_id_, OF_DECODER, 2)) {
|
||||
LOG_ERROR("Create FEC decoder instance failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FecDecoder::Release() {
|
||||
if (!fec_session_) {
|
||||
LOG_ERROR("Invalid FEC decoder instance");
|
||||
return -1;
|
||||
}
|
||||
|
||||
{
|
||||
if (OF_STATUS_OK != of_release_codec_instance(fec_session_)) {
|
||||
LOG_ERROR("Release FEC decoder instance failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fec_rs_params_) {
|
||||
free(fec_rs_params_);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FecDecoder::ResetParams(unsigned int source_symbol_num) {
|
||||
if (!fec_session_) {
|
||||
LOG_ERROR("Invalid FEC decoder instance");
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_of_received_symbols_ = 0;
|
||||
num_of_source_packets_ = source_symbol_num;
|
||||
num_of_total_packets_ =
|
||||
(unsigned int)floor((double)source_symbol_num / (double)code_rate_);
|
||||
|
||||
LOG_ERROR("Set s[{}] r[{}]", num_of_source_packets_,
|
||||
num_of_total_packets_ - source_symbol_num);
|
||||
|
||||
fec_params_->nb_source_symbols = source_symbol_num;
|
||||
fec_params_->nb_repair_symbols = num_of_total_packets_ - source_symbol_num;
|
||||
fec_params_->encoding_symbol_length = max_size_of_packet_;
|
||||
|
||||
if (OF_STATUS_OK != of_set_fec_parameters(fec_session_, fec_params_)) {
|
||||
LOG_ERROR("Set FEC params failed for codec_id {}", fec_codec_id_);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t **FecDecoder::DecodeWithNewSymbol(const char *fec_symbol,
|
||||
unsigned int fec_symbol_id) {
|
||||
if (!fec_session_) {
|
||||
LOG_ERROR("Invalid FEC decoder instance");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
num_of_received_symbols_++;
|
||||
if (OF_STATUS_ERROR == of_decode_with_new_symbol(
|
||||
fec_session_, (char *)fec_symbol, fec_symbol_id)) {
|
||||
LOG_ERROR("Decode wit new symbol failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ((num_of_received_symbols_ >= fec_params_->nb_source_symbols) &&
|
||||
(true == of_is_decoding_complete(fec_session_))) {
|
||||
uint8_t **source_packets =
|
||||
(uint8_t **)calloc(num_of_total_packets_, sizeof(uint8_t *));
|
||||
if (!source_packets) {
|
||||
LOG_ERROR("Calloc failed for source_packets with size [{}])",
|
||||
num_of_total_packets_);
|
||||
}
|
||||
|
||||
if (OF_STATUS_OK !=
|
||||
of_get_source_symbols_tab(fec_session_, (void **)source_packets)) {
|
||||
LOG_ERROR("Get source symbols failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return source_packets;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int FecDecoder::ReleaseSourcePackets(uint8_t **source_packets) {
|
||||
if (nullptr == source_packets) {
|
||||
LOG_ERROR(
|
||||
"Release source packets failed, due to source_packets is nullptr");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// for (unsigned int index = 0; index < num_of_source_packets_; index++) {
|
||||
// if (source_packets[index]) {
|
||||
// LOG_ERROR("Free [{}]", index);
|
||||
// free(source_packets[index]);
|
||||
// }
|
||||
// }
|
||||
free(source_packets);
|
||||
|
||||
return 0;
|
||||
}
|
||||
50
src/fec/fec_decoder.h
Normal file
50
src/fec/fec_decoder.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2023-11-15
|
||||
* Copyright (c) 2023 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _FEC_DECODER_H_
|
||||
#define _FEC_DECODER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "lib_common/of_openfec_api.h"
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
class FecDecoder {
|
||||
public:
|
||||
FecDecoder();
|
||||
~FecDecoder();
|
||||
|
||||
public:
|
||||
int Init();
|
||||
int Release();
|
||||
int ResetParams(unsigned int source_symbol_num);
|
||||
uint8_t **DecodeWithNewSymbol(const char *fec_symbol,
|
||||
unsigned int fec_symbol_id);
|
||||
int ReleaseSourcePackets(uint8_t **source_packets);
|
||||
|
||||
private:
|
||||
double code_rate_ = 0.667;
|
||||
int max_size_of_packet_ = 1400;
|
||||
|
||||
private:
|
||||
of_codec_id_t fec_codec_id_ = OF_CODEC_REED_SOLOMON_GF_2_M_STABLE;
|
||||
of_session_t *fec_session_ = nullptr;
|
||||
of_parameters_t *fec_params_ = nullptr;
|
||||
of_rs_2_m_parameters_t *fec_rs_params_ = nullptr;
|
||||
of_ldpc_parameters_t *fec_ldpc_params_ = nullptr;
|
||||
|
||||
unsigned int num_of_received_symbols_ = 0;
|
||||
unsigned int num_of_source_packets_ = 0;
|
||||
unsigned int num_of_total_packets_ = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -40,6 +40,10 @@ int FecEncoder::Release() {
|
||||
}
|
||||
}
|
||||
|
||||
if (fec_rs_params_) {
|
||||
free(fec_rs_params_);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class OpenH264Encoder : public VideoEncoder {
|
||||
private:
|
||||
int frame_width_ = 1280;
|
||||
int frame_height_ = 720;
|
||||
int key_frame_interval_ = 3000;
|
||||
int key_frame_interval_ = 1;
|
||||
int target_bitrate_ = 1000;
|
||||
int max_bitrate_ = 500000;
|
||||
int max_payload_size_ = 1400;
|
||||
|
||||
@@ -425,7 +425,7 @@ int PeerConnection::SendVideoData(const char *data, size_t size) {
|
||||
int ret = video_encoder_->Encode(
|
||||
(uint8_t *)data, size, [this](char *encoded_frame, size_t size) -> int {
|
||||
for (auto &ice_trans : ice_transmission_list_) {
|
||||
// LOG_ERROR("H264 frame size: [{}]", size);
|
||||
LOG_ERROR("H264 frame size: [{}]", size);
|
||||
ice_trans.second->SendData(IceTransmission::DATA_TYPE::VIDEO,
|
||||
encoded_frame, size);
|
||||
}
|
||||
|
||||
@@ -52,14 +52,14 @@ void RtpCodec::Encode(uint8_t* buffer, size_t size,
|
||||
timestamp_ =
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
|
||||
for (size_t index = 0; index < num_of_total_packets; index++) {
|
||||
for (unsigned int index = 0; index < num_of_total_packets; index++) {
|
||||
RtpPacket rtp_packet;
|
||||
if (index < num_of_source_packets) {
|
||||
rtp_packet.SetVerion(version_);
|
||||
rtp_packet.SetHasPadding(has_padding_);
|
||||
rtp_packet.SetHasExtension(has_extension_);
|
||||
rtp_packet.SetMarker(index == num_of_source_packets - 1 ? 1 : 0);
|
||||
rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264);
|
||||
rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_SOURCE);
|
||||
rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
rtp_packet.SetTimestamp(timestamp_);
|
||||
rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -89,12 +89,16 @@ void RtpCodec::Encode(uint8_t* buffer, size_t size,
|
||||
|
||||
if (index == num_of_source_packets - 1) {
|
||||
if (last_packet_size > 0) {
|
||||
rtp_packet.EncodeH264Fua(fec_packets[index], last_packet_size);
|
||||
rtp_packet.EncodeH264FecSource(fec_packets[index],
|
||||
last_packet_size, index,
|
||||
num_of_source_packets);
|
||||
} else {
|
||||
rtp_packet.EncodeH264Fua(fec_packets[index], MAX_NALU_LEN);
|
||||
rtp_packet.EncodeH264FecSource(fec_packets[index], MAX_NALU_LEN,
|
||||
index, num_of_source_packets);
|
||||
}
|
||||
} else {
|
||||
rtp_packet.EncodeH264Fua(fec_packets[index], MAX_NALU_LEN);
|
||||
rtp_packet.EncodeH264FecSource(fec_packets[index], MAX_NALU_LEN,
|
||||
index, num_of_source_packets);
|
||||
}
|
||||
|
||||
} else if (index >= num_of_source_packets &&
|
||||
@@ -103,7 +107,7 @@ void RtpCodec::Encode(uint8_t* buffer, size_t size,
|
||||
rtp_packet.SetHasPadding(has_padding_);
|
||||
rtp_packet.SetHasExtension(has_extension_);
|
||||
rtp_packet.SetMarker(index == num_of_total_packets - 1 ? 1 : 0);
|
||||
rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC);
|
||||
rtp_packet.SetPayloadType(RtpPacket::PAYLOAD_TYPE::H264_FEC_REPAIR);
|
||||
rtp_packet.SetSequenceNumber(sequence_number_++);
|
||||
rtp_packet.SetTimestamp(timestamp_);
|
||||
rtp_packet.SetSsrc(ssrc_);
|
||||
@@ -116,7 +120,8 @@ void RtpCodec::Encode(uint8_t* buffer, size_t size,
|
||||
rtp_packet.SetExtensionProfile(extension_profile_);
|
||||
rtp_packet.SetExtensionData(extension_data_, extension_len_);
|
||||
}
|
||||
rtp_packet.EncodeH264Fec(fec_packets[index], MAX_NALU_LEN);
|
||||
rtp_packet.EncodeH264FecRepair(fec_packets[index], MAX_NALU_LEN,
|
||||
index, num_of_source_packets);
|
||||
}
|
||||
packets.emplace_back(rtp_packet);
|
||||
|
||||
@@ -238,6 +243,7 @@ size_t RtpCodec::Decode(RtpPacket& packet, uint8_t* payload) {
|
||||
// if ((packet.Buffer()[13] >> 7) & 0x01) {
|
||||
// LOG_ERROR("Start bit!!!!!!!!!!!!!!!");
|
||||
// }
|
||||
|
||||
auto nal_unit_type = packet.Buffer()[12] & 0x1F;
|
||||
|
||||
if (NALU == nal_unit_type) {
|
||||
|
||||
@@ -12,8 +12,11 @@ void RtpPacket::TryToDecodeRtpPacket() {
|
||||
} else if (NAL_UNIT_TYPE::FU_A == nal_unit_type_) {
|
||||
DecodeH264Fua();
|
||||
}
|
||||
} else if (PAYLOAD_TYPE::H264_FEC == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
|
||||
DecodeH264Fec();
|
||||
} 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::DATA == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
|
||||
DecodeData();
|
||||
} else {
|
||||
@@ -245,7 +248,9 @@ const uint8_t *RtpPacket::EncodeH264Fua(uint8_t *payload, size_t payload_size) {
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
const uint8_t *RtpPacket::EncodeH264Fec(uint8_t *payload, size_t payload_size) {
|
||||
const uint8_t *RtpPacket::EncodeH264FecSource(
|
||||
uint8_t *payload, size_t payload_size, unsigned int fec_symbol_id,
|
||||
unsigned int fec_source_symbol_num) {
|
||||
buffer_[0] = (version_ << 6) | (has_padding_ << 5) | (has_extension_ << 4) |
|
||||
total_csrc_number_;
|
||||
buffer_[1] = (marker_ << 7) | payload_type_;
|
||||
@@ -279,10 +284,75 @@ const uint8_t *RtpPacket::EncodeH264Fec(uint8_t *payload, size_t payload_size) {
|
||||
}
|
||||
|
||||
uint32_t fec_symbol_id_offset =
|
||||
extension_offset + (has_extension_ && extension_data_ ? 4 : 0);
|
||||
buffer_[12 + fec_symbol_id_offset] = fec_symbol_id_;
|
||||
(has_extension_ && extension_data_ ? extension_len_ : 0) +
|
||||
extension_offset;
|
||||
|
||||
uint32_t payload_offset = fec_symbol_id_offset + 1;
|
||||
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, unsigned int fec_symbol_id,
|
||||
unsigned int 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 |
|
||||
@@ -438,7 +508,7 @@ size_t RtpPacket::DecodeH264Fua(uint8_t *payload) {
|
||||
return payload_size_;
|
||||
}
|
||||
|
||||
size_t RtpPacket::DecodeH264Fec(uint8_t *payload) {
|
||||
size_t RtpPacket::DecodeH264FecSource(uint8_t *payload) {
|
||||
version_ = (buffer_[0] >> 6) & 0x03;
|
||||
has_padding_ = (buffer_[0] >> 5) & 0x01;
|
||||
has_extension_ = (buffer_[0] >> 4) & 0x01;
|
||||
@@ -467,10 +537,69 @@ size_t RtpPacket::DecodeH264Fec(uint8_t *payload) {
|
||||
extension_data_ = buffer_ + 16 + extension_offset;
|
||||
}
|
||||
|
||||
uint32_t fec_symbol_id_offset = extension_offset + (has_extension_ ? 4 : 0);
|
||||
uint32_t fec_symbol_id_offset =
|
||||
extension_offset + (has_extension_ ? extension_len_ : 0);
|
||||
fec_symbol_id_ = buffer_[12 + fec_symbol_id_offset];
|
||||
|
||||
uint32_t payload_offset = fec_symbol_id_offset + 1;
|
||||
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;
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
// |F|NRI| Type |S|E|R| Type |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
// H264 FEC
|
||||
// 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
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@@ -81,7 +81,33 @@
|
||||
// | Extensions |x
|
||||
// | .... |x
|
||||
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
// | FEC symbol id | |
|
||||
// | 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 |
|
||||
// | |
|
||||
@@ -96,7 +122,8 @@ class RtpPacket {
|
||||
public:
|
||||
typedef enum {
|
||||
H264 = 96,
|
||||
H264_FEC = 97,
|
||||
H264_FEC_SOURCE = 97,
|
||||
H264_FEC_REPAIR = 98,
|
||||
OPUS = 111,
|
||||
DATA = 127
|
||||
} PAYLOAD_TYPE;
|
||||
@@ -171,11 +198,17 @@ class RtpPacket {
|
||||
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 *EncodeH264Fec(uint8_t *payload, size_t payload_size);
|
||||
const uint8_t *EncodeH264FecSource(uint8_t *payload, size_t payload_size,
|
||||
unsigned int fec_symbol_id,
|
||||
unsigned int fec_source_symbol_num);
|
||||
const uint8_t *EncodeH264FecRepair(uint8_t *payload, size_t payload_size,
|
||||
unsigned int fec_symbol_id,
|
||||
unsigned int fec_source_symbol_num);
|
||||
size_t DecodeData(uint8_t *payload = nullptr);
|
||||
size_t DecodeH264Nalu(uint8_t *payload = nullptr);
|
||||
size_t DecodeH264Fua(uint8_t *payload = nullptr);
|
||||
size_t DecodeH264Fec(uint8_t *payload = nullptr);
|
||||
size_t DecodeH264FecSource(uint8_t *payload = nullptr);
|
||||
size_t DecodeH264FecRepair(uint8_t *payload = nullptr);
|
||||
|
||||
public:
|
||||
// Get Header
|
||||
@@ -226,6 +259,8 @@ class RtpPacket {
|
||||
|
||||
const uint8_t FecSymbolId() { return fec_symbol_id_; }
|
||||
|
||||
const uint8_t FecSourceSymbolNum() { return fec_source_symbol_num_; }
|
||||
|
||||
// Payload
|
||||
const uint8_t *Payload() {
|
||||
ParseRtpData();
|
||||
@@ -277,6 +312,7 @@ class RtpPacket {
|
||||
FU_INDICATOR fu_indicator_;
|
||||
FU_HEADER fu_header_;
|
||||
uint8_t fec_symbol_id_ = 0;
|
||||
uint8_t fec_source_symbol_num_ = 0;
|
||||
|
||||
// Payload
|
||||
uint8_t *payload_ = nullptr;
|
||||
|
||||
@@ -48,15 +48,118 @@ void RtpVideoReceiver::InsertRtpPacket(RtpPacket& rtp_packet) {
|
||||
|
||||
rtcp_rr.Encode();
|
||||
|
||||
SendRtcpRR(rtcp_rr);
|
||||
// SendRtcpRR(rtcp_rr);
|
||||
}
|
||||
|
||||
if (RtpPacket::NAL_UNIT_TYPE::NALU == rtp_packet.NalUnitType()) {
|
||||
compelete_video_frame_queue_.push(
|
||||
VideoFrame(rtp_packet.Payload(), rtp_packet.Size()));
|
||||
} else if (RtpPacket::NAL_UNIT_TYPE::FU_A == rtp_packet.NalUnitType()) {
|
||||
incomplete_frame_list_[rtp_packet.SequenceNumber()] = rtp_packet;
|
||||
bool complete = CheckIsFrameCompleted(rtp_packet);
|
||||
if (!fec_enable_) {
|
||||
if (RtpPacket::PAYLOAD_TYPE::H264 == rtp_packet.PayloadType()) {
|
||||
if (RtpPacket::NAL_UNIT_TYPE::NALU == rtp_packet.NalUnitType()) {
|
||||
compelete_video_frame_queue_.push(
|
||||
VideoFrame(rtp_packet.Payload(), rtp_packet.Size()));
|
||||
} else if (RtpPacket::NAL_UNIT_TYPE::FU_A == rtp_packet.NalUnitType()) {
|
||||
incomplete_frame_list_[rtp_packet.SequenceNumber()] = rtp_packet;
|
||||
bool complete = CheckIsFrameCompleted(rtp_packet);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (RtpPacket::PAYLOAD_TYPE::H264 == rtp_packet.PayloadType()) {
|
||||
if (RtpPacket::NAL_UNIT_TYPE::NALU == rtp_packet.NalUnitType()) {
|
||||
compelete_video_frame_queue_.push(
|
||||
VideoFrame(rtp_packet.Payload(), rtp_packet.Size()));
|
||||
} else if (RtpPacket::NAL_UNIT_TYPE::FU_A == rtp_packet.NalUnitType()) {
|
||||
incomplete_frame_list_[rtp_packet.SequenceNumber()] = rtp_packet;
|
||||
bool complete = CheckIsFrameCompleted(rtp_packet);
|
||||
}
|
||||
} else if (RtpPacket::PAYLOAD_TYPE::H264_FEC_SOURCE ==
|
||||
rtp_packet.PayloadType()) {
|
||||
if (last_packet_ts_ != rtp_packet.Timestamp()) {
|
||||
fec_decoder_.Init();
|
||||
fec_decoder_.ResetParams(rtp_packet.FecSourceSymbolNum());
|
||||
last_packet_ts_ = rtp_packet.Timestamp();
|
||||
}
|
||||
|
||||
incomplete_fec_packet_list_[rtp_packet.Timestamp()]
|
||||
[rtp_packet.SequenceNumber()] = rtp_packet;
|
||||
|
||||
uint8_t** complete_frame = fec_decoder_.DecodeWithNewSymbol(
|
||||
(const char*)incomplete_fec_packet_list_[rtp_packet.Timestamp()]
|
||||
[rtp_packet.SequenceNumber()]
|
||||
.Payload(),
|
||||
rtp_packet.FecSymbolId());
|
||||
|
||||
if (nullptr != complete_frame) {
|
||||
if (!nv12_data_) {
|
||||
nv12_data_ = new uint8_t[NV12_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
size_t complete_frame_size = 0;
|
||||
for (int index = 0; index < rtp_packet.FecSourceSymbolNum(); index++) {
|
||||
if (nullptr == complete_frame[index]) {
|
||||
LOG_ERROR("Invalid complete_frame[{}]", index);
|
||||
}
|
||||
memcpy(nv12_data_ + complete_frame_size, complete_frame[index], 1400);
|
||||
complete_frame_size += 1400;
|
||||
}
|
||||
|
||||
fec_decoder_.ReleaseSourcePackets(complete_frame);
|
||||
fec_decoder_.Release();
|
||||
LOG_ERROR("Release incomplete_fec_packet_list_");
|
||||
incomplete_fec_packet_list_.erase(rtp_packet.Timestamp());
|
||||
|
||||
if (incomplete_fec_frame_list_.end() !=
|
||||
incomplete_fec_frame_list_.find(rtp_packet.Timestamp())) {
|
||||
incomplete_fec_frame_list_.erase(rtp_packet.Timestamp());
|
||||
}
|
||||
|
||||
compelete_video_frame_queue_.push(
|
||||
VideoFrame(nv12_data_, complete_frame_size));
|
||||
} else {
|
||||
incomplete_fec_frame_list_.insert(rtp_packet.Timestamp());
|
||||
}
|
||||
} else if (RtpPacket::PAYLOAD_TYPE::H264_FEC_REPAIR ==
|
||||
rtp_packet.PayloadType()) {
|
||||
if (incomplete_fec_frame_list_.end() ==
|
||||
incomplete_fec_frame_list_.find(rtp_packet.Timestamp())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_packet_ts_ != rtp_packet.Timestamp()) {
|
||||
fec_decoder_.Init();
|
||||
fec_decoder_.ResetParams(rtp_packet.FecSourceSymbolNum());
|
||||
last_packet_ts_ = rtp_packet.Timestamp();
|
||||
}
|
||||
|
||||
incomplete_fec_packet_list_[rtp_packet.Timestamp()]
|
||||
[rtp_packet.SequenceNumber()] = rtp_packet;
|
||||
|
||||
uint8_t** complete_frame = fec_decoder_.DecodeWithNewSymbol(
|
||||
(const char*)incomplete_fec_packet_list_[rtp_packet.Timestamp()]
|
||||
[rtp_packet.SequenceNumber()]
|
||||
.Payload(),
|
||||
rtp_packet.FecSymbolId());
|
||||
|
||||
if (nullptr != complete_frame) {
|
||||
if (!nv12_data_) {
|
||||
nv12_data_ = new uint8_t[NV12_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
size_t complete_frame_size = 0;
|
||||
for (int index = 0; index < rtp_packet.FecSourceSymbolNum(); index++) {
|
||||
if (nullptr == complete_frame[index]) {
|
||||
LOG_ERROR("Invalid complete_frame[{}]", index);
|
||||
}
|
||||
memcpy(nv12_data_ + complete_frame_size, complete_frame[index], 1400);
|
||||
complete_frame_size += 1400;
|
||||
}
|
||||
|
||||
fec_decoder_.ReleaseSourcePackets(complete_frame);
|
||||
fec_decoder_.Release();
|
||||
incomplete_fec_packet_list_.erase(rtp_packet.Timestamp());
|
||||
|
||||
compelete_video_frame_queue_.push(
|
||||
VideoFrame(nv12_data_, complete_frame_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
|
||||
#include "fec_decoder.h"
|
||||
#include "frame.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "rtcp_receiver_report.h"
|
||||
@@ -46,6 +48,16 @@ class RtpVideoReceiver : public ThreadBase {
|
||||
std::unique_ptr<RtpStatistics> rtp_statistics_ = nullptr;
|
||||
uint32_t last_send_rtcp_rr_packet_ts_ = 0;
|
||||
std::function<int(const char*, size_t)> data_send_func_ = nullptr;
|
||||
|
||||
private:
|
||||
bool fec_enable_ = true;
|
||||
FecDecoder fec_decoder_;
|
||||
uint32_t last_packet_ts_ = 0;
|
||||
// std::map<uint16_t, RtpPacket> incomplete_fec_frame_list_;
|
||||
// std::map<uint32_t, std::map<uint16_t, RtpPacket>> fec_source_symbol_list_;
|
||||
// std::map<uint32_t, std::map<uint16_t, RtpPacket>> fec_repair_symbol_list_;
|
||||
std::set<uint32_t> incomplete_fec_frame_list_;
|
||||
std::map<uint32_t, std::map<uint16_t, RtpPacket>> incomplete_fec_packet_list_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -313,7 +313,9 @@ uint8_t IceTransmission::CheckIsVideoPacket(const char *buffer, size_t size) {
|
||||
}
|
||||
|
||||
uint8_t pt = buffer[1] & 0x7F;
|
||||
if (RtpPacket::PAYLOAD_TYPE::H264 == pt) {
|
||||
if (RtpPacket::PAYLOAD_TYPE::H264 == pt ||
|
||||
RtpPacket::PAYLOAD_TYPE::H264_FEC_SOURCE == pt ||
|
||||
RtpPacket::PAYLOAD_TYPE::H264_FEC_REPAIR == pt) {
|
||||
return pt;
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user