mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-27 04:35: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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class OpenH264Encoder : public VideoEncoder {
|
|||||||
private:
|
private:
|
||||||
int frame_width_ = 1280;
|
int frame_width_ = 1280;
|
||||||
int frame_height_ = 720;
|
int frame_height_ = 720;
|
||||||
int key_frame_interval_ = 3000;
|
int key_frame_interval_ = 1;
|
||||||
int target_bitrate_ = 1000;
|
int target_bitrate_ = 1000;
|
||||||
int max_bitrate_ = 500000;
|
int max_bitrate_ = 500000;
|
||||||
int max_payload_size_ = 1400;
|
int max_payload_size_ = 1400;
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ int PeerConnection::SendVideoData(const char *data, size_t size) {
|
|||||||
int ret = video_encoder_->Encode(
|
int ret = video_encoder_->Encode(
|
||||||
(uint8_t *)data, size, [this](char *encoded_frame, size_t size) -> int {
|
(uint8_t *)data, size, [this](char *encoded_frame, size_t size) -> int {
|
||||||
for (auto &ice_trans : ice_transmission_list_) {
|
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,
|
ice_trans.second->SendData(IceTransmission::DATA_TYPE::VIDEO,
|
||||||
encoded_frame, size);
|
encoded_frame, size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,14 +52,14 @@ void RtpCodec::Encode(uint8_t* buffer, size_t size,
|
|||||||
timestamp_ =
|
timestamp_ =
|
||||||
std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
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;
|
RtpPacket rtp_packet;
|
||||||
if (index < num_of_source_packets) {
|
if (index < num_of_source_packets) {
|
||||||
rtp_packet.SetVerion(version_);
|
rtp_packet.SetVerion(version_);
|
||||||
rtp_packet.SetHasPadding(has_padding_);
|
rtp_packet.SetHasPadding(has_padding_);
|
||||||
rtp_packet.SetHasExtension(has_extension_);
|
rtp_packet.SetHasExtension(has_extension_);
|
||||||
rtp_packet.SetMarker(index == num_of_source_packets - 1 ? 1 : 0);
|
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.SetSequenceNumber(sequence_number_++);
|
||||||
rtp_packet.SetTimestamp(timestamp_);
|
rtp_packet.SetTimestamp(timestamp_);
|
||||||
rtp_packet.SetSsrc(ssrc_);
|
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 (index == num_of_source_packets - 1) {
|
||||||
if (last_packet_size > 0) {
|
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 {
|
} 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 {
|
} 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 &&
|
} 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.SetHasPadding(has_padding_);
|
||||||
rtp_packet.SetHasExtension(has_extension_);
|
rtp_packet.SetHasExtension(has_extension_);
|
||||||
rtp_packet.SetMarker(index == num_of_total_packets - 1 ? 1 : 0);
|
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.SetSequenceNumber(sequence_number_++);
|
||||||
rtp_packet.SetTimestamp(timestamp_);
|
rtp_packet.SetTimestamp(timestamp_);
|
||||||
rtp_packet.SetSsrc(ssrc_);
|
rtp_packet.SetSsrc(ssrc_);
|
||||||
@@ -116,7 +120,8 @@ void RtpCodec::Encode(uint8_t* buffer, size_t size,
|
|||||||
rtp_packet.SetExtensionProfile(extension_profile_);
|
rtp_packet.SetExtensionProfile(extension_profile_);
|
||||||
rtp_packet.SetExtensionData(extension_data_, extension_len_);
|
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);
|
packets.emplace_back(rtp_packet);
|
||||||
|
|
||||||
@@ -238,6 +243,7 @@ size_t RtpCodec::Decode(RtpPacket& packet, uint8_t* payload) {
|
|||||||
// if ((packet.Buffer()[13] >> 7) & 0x01) {
|
// if ((packet.Buffer()[13] >> 7) & 0x01) {
|
||||||
// LOG_ERROR("Start bit!!!!!!!!!!!!!!!");
|
// LOG_ERROR("Start bit!!!!!!!!!!!!!!!");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
auto nal_unit_type = packet.Buffer()[12] & 0x1F;
|
auto nal_unit_type = packet.Buffer()[12] & 0x1F;
|
||||||
|
|
||||||
if (NALU == nal_unit_type) {
|
if (NALU == nal_unit_type) {
|
||||||
|
|||||||
@@ -12,8 +12,11 @@ void RtpPacket::TryToDecodeRtpPacket() {
|
|||||||
} else if (NAL_UNIT_TYPE::FU_A == nal_unit_type_) {
|
} else if (NAL_UNIT_TYPE::FU_A == nal_unit_type_) {
|
||||||
DecodeH264Fua();
|
DecodeH264Fua();
|
||||||
}
|
}
|
||||||
} else if (PAYLOAD_TYPE::H264_FEC == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
|
} else if (PAYLOAD_TYPE::H264_FEC_SOURCE == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
|
||||||
DecodeH264Fec();
|
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)) {
|
} else if (PAYLOAD_TYPE::DATA == PAYLOAD_TYPE(buffer_[1] & 0x7F)) {
|
||||||
DecodeData();
|
DecodeData();
|
||||||
} else {
|
} else {
|
||||||
@@ -245,7 +248,9 @@ const uint8_t *RtpPacket::EncodeH264Fua(uint8_t *payload, size_t payload_size) {
|
|||||||
return buffer_;
|
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) |
|
buffer_[0] = (version_ << 6) | (has_padding_ << 5) | (has_extension_ << 4) |
|
||||||
total_csrc_number_;
|
total_csrc_number_;
|
||||||
buffer_[1] = (marker_ << 7) | payload_type_;
|
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 =
|
uint32_t fec_symbol_id_offset =
|
||||||
extension_offset + (has_extension_ && extension_data_ ? 4 : 0);
|
(has_extension_ && extension_data_ ? extension_len_ : 0) +
|
||||||
buffer_[12 + fec_symbol_id_offset] = fec_symbol_id_;
|
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 |
|
buffer_[12 + payload_offset] = fu_indicator_.forbidden_bit << 7 |
|
||||||
fu_indicator_.nal_reference_idc << 6 |
|
fu_indicator_.nal_reference_idc << 6 |
|
||||||
@@ -438,7 +508,7 @@ size_t RtpPacket::DecodeH264Fua(uint8_t *payload) {
|
|||||||
return payload_size_;
|
return payload_size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RtpPacket::DecodeH264Fec(uint8_t *payload) {
|
size_t RtpPacket::DecodeH264FecSource(uint8_t *payload) {
|
||||||
version_ = (buffer_[0] >> 6) & 0x03;
|
version_ = (buffer_[0] >> 6) & 0x03;
|
||||||
has_padding_ = (buffer_[0] >> 5) & 0x01;
|
has_padding_ = (buffer_[0] >> 5) & 0x01;
|
||||||
has_extension_ = (buffer_[0] >> 4) & 0x01;
|
has_extension_ = (buffer_[0] >> 4) & 0x01;
|
||||||
@@ -467,10 +537,69 @@ size_t RtpPacket::DecodeH264Fec(uint8_t *payload) {
|
|||||||
extension_data_ = buffer_ + 16 + extension_offset;
|
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];
|
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_size_ = size_ - (14 + payload_offset);
|
||||||
payload_ = buffer_ + 14 + payload_offset;
|
payload_ = buffer_ + 14 + payload_offset;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
// |F|NRI| Type |S|E|R| Type |
|
// |F|NRI| Type |S|E|R| Type |
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
// H264 FEC
|
// H264 FEC source symbol
|
||||||
// 0 1 2 3
|
// 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
|
// 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
|
// | Extensions |x
|
||||||
// | .... |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 |
|
// | Fec Payload |
|
||||||
// | |
|
// | |
|
||||||
@@ -96,7 +122,8 @@ class RtpPacket {
|
|||||||
public:
|
public:
|
||||||
typedef enum {
|
typedef enum {
|
||||||
H264 = 96,
|
H264 = 96,
|
||||||
H264_FEC = 97,
|
H264_FEC_SOURCE = 97,
|
||||||
|
H264_FEC_REPAIR = 98,
|
||||||
OPUS = 111,
|
OPUS = 111,
|
||||||
DATA = 127
|
DATA = 127
|
||||||
} PAYLOAD_TYPE;
|
} PAYLOAD_TYPE;
|
||||||
@@ -171,11 +198,17 @@ class RtpPacket {
|
|||||||
const uint8_t *Encode(uint8_t *payload, size_t payload_size);
|
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 *EncodeH264Nalu(uint8_t *payload, size_t payload_size);
|
||||||
const uint8_t *EncodeH264Fua(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 DecodeData(uint8_t *payload = nullptr);
|
||||||
size_t DecodeH264Nalu(uint8_t *payload = nullptr);
|
size_t DecodeH264Nalu(uint8_t *payload = nullptr);
|
||||||
size_t DecodeH264Fua(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:
|
public:
|
||||||
// Get Header
|
// Get Header
|
||||||
@@ -226,6 +259,8 @@ class RtpPacket {
|
|||||||
|
|
||||||
const uint8_t FecSymbolId() { return fec_symbol_id_; }
|
const uint8_t FecSymbolId() { return fec_symbol_id_; }
|
||||||
|
|
||||||
|
const uint8_t FecSourceSymbolNum() { return fec_source_symbol_num_; }
|
||||||
|
|
||||||
// Payload
|
// Payload
|
||||||
const uint8_t *Payload() {
|
const uint8_t *Payload() {
|
||||||
ParseRtpData();
|
ParseRtpData();
|
||||||
@@ -277,6 +312,7 @@ class RtpPacket {
|
|||||||
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;
|
||||||
|
|
||||||
// Payload
|
// Payload
|
||||||
uint8_t *payload_ = nullptr;
|
uint8_t *payload_ = nullptr;
|
||||||
|
|||||||
@@ -48,9 +48,11 @@ void RtpVideoReceiver::InsertRtpPacket(RtpPacket& rtp_packet) {
|
|||||||
|
|
||||||
rtcp_rr.Encode();
|
rtcp_rr.Encode();
|
||||||
|
|
||||||
SendRtcpRR(rtcp_rr);
|
// SendRtcpRR(rtcp_rr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!fec_enable_) {
|
||||||
|
if (RtpPacket::PAYLOAD_TYPE::H264 == rtp_packet.PayloadType()) {
|
||||||
if (RtpPacket::NAL_UNIT_TYPE::NALU == rtp_packet.NalUnitType()) {
|
if (RtpPacket::NAL_UNIT_TYPE::NALU == rtp_packet.NalUnitType()) {
|
||||||
compelete_video_frame_queue_.push(
|
compelete_video_frame_queue_.push(
|
||||||
VideoFrame(rtp_packet.Payload(), rtp_packet.Size()));
|
VideoFrame(rtp_packet.Payload(), rtp_packet.Size()));
|
||||||
@@ -58,6 +60,107 @@ void RtpVideoReceiver::InsertRtpPacket(RtpPacket& rtp_packet) {
|
|||||||
incomplete_frame_list_[rtp_packet.SequenceNumber()] = rtp_packet;
|
incomplete_frame_list_[rtp_packet.SequenceNumber()] = rtp_packet;
|
||||||
bool complete = CheckIsFrameCompleted(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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RtpVideoReceiver::CheckIsFrameCompleted(RtpPacket& rtp_packet) {
|
bool RtpVideoReceiver::CheckIsFrameCompleted(RtpPacket& rtp_packet) {
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "fec_decoder.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "rtcp_receiver_report.h"
|
#include "rtcp_receiver_report.h"
|
||||||
@@ -46,6 +48,16 @@ class RtpVideoReceiver : public ThreadBase {
|
|||||||
std::unique_ptr<RtpStatistics> rtp_statistics_ = nullptr;
|
std::unique_ptr<RtpStatistics> rtp_statistics_ = nullptr;
|
||||||
uint32_t last_send_rtcp_rr_packet_ts_ = 0;
|
uint32_t last_send_rtcp_rr_packet_ts_ = 0;
|
||||||
std::function<int(const char*, size_t)> data_send_func_ = nullptr;
|
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
|
#endif
|
||||||
|
|||||||
@@ -313,7 +313,9 @@ uint8_t IceTransmission::CheckIsVideoPacket(const char *buffer, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t pt = buffer[1] & 0x7F;
|
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;
|
return pt;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -33,20 +33,17 @@
|
|||||||
|
|
||||||
#include "of_reed-solomon_gf_2_m_includes.h"
|
#include "of_reed-solomon_gf_2_m_includes.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef OF_USE_REED_SOLOMON_2_M_CODEC
|
#ifdef OF_USE_REED_SOLOMON_2_M_CODEC
|
||||||
|
|
||||||
|
of_status_t of_rs_2_m_create_codec_instance(of_rs_2_m_cb_t** of_cb) {
|
||||||
of_status_t of_rs_2_m_create_codec_instance (of_rs_2_m_cb_t** of_cb)
|
|
||||||
{
|
|
||||||
of_codec_type_t codec_type; /* temporary value */
|
of_codec_type_t codec_type; /* temporary value */
|
||||||
of_rs_2_m_cb_t *cb;
|
of_rs_2_m_cb_t* cb;
|
||||||
|
|
||||||
OF_ENTER_FUNCTION
|
OF_ENTER_FUNCTION
|
||||||
cb = (of_rs_2_m_cb_t*) of_realloc (*of_cb, sizeof (of_rs_2_m_cb_t));
|
cb = (of_rs_2_m_cb_t*)of_realloc(*of_cb, sizeof(of_rs_2_m_cb_t));
|
||||||
*of_cb = cb;
|
*of_cb = cb;
|
||||||
/* realloc does not initialize the additional buffer space, so do that manually,
|
/* realloc does not initialize the additional buffer space, so do that
|
||||||
* then re-initialize a few parameters */
|
* manually, then re-initialize a few parameters */
|
||||||
codec_type = cb->codec_type;
|
codec_type = cb->codec_type;
|
||||||
memset(cb, 0, sizeof(*cb));
|
memset(cb, 0, sizeof(*cb));
|
||||||
cb->codec_type = codec_type;
|
cb->codec_type = codec_type;
|
||||||
@@ -60,32 +57,35 @@ of_status_t of_rs_2_m_create_codec_instance (of_rs_2_m_cb_t** of_cb)
|
|||||||
return OF_STATUS_OK;
|
return OF_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
of_status_t of_rs_2_m_release_codec_instance(of_rs_2_m_cb_t* ofcb) {
|
||||||
of_status_t of_rs_2_m_release_codec_instance (of_rs_2_m_cb_t* ofcb)
|
|
||||||
{
|
|
||||||
OF_ENTER_FUNCTION
|
OF_ENTER_FUNCTION
|
||||||
of_rs_2m_release((of_galois_field_code_cb_t*)ofcb);
|
of_rs_2m_release((of_galois_field_code_cb_t*)ofcb);
|
||||||
#ifdef OF_USE_DECODER
|
#ifdef OF_USE_DECODER
|
||||||
if (ofcb->available_symbols_tab != NULL)
|
if (ofcb->available_symbols_tab != NULL) {
|
||||||
{
|
|
||||||
of_free(ofcb->available_symbols_tab);
|
of_free(ofcb->available_symbols_tab);
|
||||||
ofcb->available_symbols_tab = NULL;
|
ofcb->available_symbols_tab = NULL;
|
||||||
}
|
}
|
||||||
#endif /* OF_USE_DECODER */
|
#endif /* OF_USE_DECODER */
|
||||||
#ifdef OF_DEBUG /* { */
|
#ifdef OF_DEBUG /* { */
|
||||||
OF_TRACE_LVL(1, ("\tTo be added: Reed-Solomon GF(2^4): total of %ld bytes for precalculated tables (incl. %ld for the optimized mult table)\n",
|
OF_TRACE_LVL(
|
||||||
sizeof(of_gf_2_4_log) + sizeof(of_gf_2_4_exp) + sizeof(of_gf_2_4_inv) + sizeof(of_gf_2_4_mul_table) + sizeof(of_gf_2_4_opt_mul_table), sizeof(of_gf_2_4_opt_mul_table)))
|
1,
|
||||||
OF_TRACE_LVL(1, ("\tTo be added: Reed-Solomon GF(2^8): total of %ld bytes for precalculated tables (incl. %ld for mult table)\n",
|
("\tTo be added: Reed-Solomon GF(2^4): total of %ld bytes for "
|
||||||
sizeof(of_gf_2_8_log) + sizeof(of_gf_2_8_exp) + sizeof(of_gf_2_8_inv) + sizeof(of_gf_2_8_mul_table), sizeof(of_gf_2_8_mul_table)))
|
"precalculated tables (incl. %ld for the optimized mult table)\n",
|
||||||
|
sizeof(of_gf_2_4_log) + sizeof(of_gf_2_4_exp) + sizeof(of_gf_2_4_inv) +
|
||||||
|
sizeof(of_gf_2_4_mul_table) + sizeof(of_gf_2_4_opt_mul_table),
|
||||||
|
sizeof(of_gf_2_4_opt_mul_table)))
|
||||||
|
OF_TRACE_LVL(1, ("\tTo be added: Reed-Solomon GF(2^8): total of %ld bytes "
|
||||||
|
"for precalculated tables (incl. %ld for mult table)\n",
|
||||||
|
sizeof(of_gf_2_8_log) + sizeof(of_gf_2_8_exp) +
|
||||||
|
sizeof(of_gf_2_8_inv) + sizeof(of_gf_2_8_mul_table),
|
||||||
|
sizeof(of_gf_2_8_mul_table)))
|
||||||
#endif /* } OF_DEBUG */
|
#endif /* } OF_DEBUG */
|
||||||
OF_EXIT_FUNCTION
|
OF_EXIT_FUNCTION
|
||||||
return OF_STATUS_OK;
|
return OF_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
of_status_t of_rs_2_m_set_fec_parameters(of_rs_2_m_cb_t* ofcb,
|
||||||
of_status_t of_rs_2_m_set_fec_parameters (of_rs_2_m_cb_t* ofcb,
|
of_rs_2_m_parameters_t* params) {
|
||||||
of_rs_2_m_parameters_t* params)
|
|
||||||
{
|
|
||||||
OF_ENTER_FUNCTION
|
OF_ENTER_FUNCTION
|
||||||
ofcb->m = params->m;
|
ofcb->m = params->m;
|
||||||
if ((ofcb->m != 4) && (ofcb->m != 8)) {
|
if ((ofcb->m != 4) && (ofcb->m != 8)) {
|
||||||
@@ -93,9 +93,12 @@ of_status_t of_rs_2_m_set_fec_parameters (of_rs_2_m_cb_t* ofcb,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
ofcb->field_size = (1 << ofcb->m) - 1;
|
ofcb->field_size = (1 << ofcb->m) - 1;
|
||||||
ofcb->max_nb_encoding_symbols = ofcb->max_nb_source_symbols = ofcb->field_size;
|
ofcb->max_nb_encoding_symbols = ofcb->max_nb_source_symbols =
|
||||||
if ((ofcb->nb_source_symbols = params->nb_source_symbols) > ofcb->max_nb_source_symbols) {
|
ofcb->field_size;
|
||||||
OF_PRINT_ERROR(("ERROR: invalid nb_source_symbols parameter (got %d, maximum is %d)",
|
if ((ofcb->nb_source_symbols = params->nb_source_symbols) >
|
||||||
|
ofcb->max_nb_source_symbols) {
|
||||||
|
OF_PRINT_ERROR(
|
||||||
|
("ERROR: invalid nb_source_symbols parameter (got %d, maximum is %d)",
|
||||||
ofcb->nb_source_symbols, ofcb->max_nb_source_symbols))
|
ofcb->nb_source_symbols, ofcb->max_nb_source_symbols))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -104,7 +107,8 @@ of_status_t of_rs_2_m_set_fec_parameters (of_rs_2_m_cb_t* ofcb,
|
|||||||
ofcb->encoding_symbol_length = params->encoding_symbol_length;
|
ofcb->encoding_symbol_length = params->encoding_symbol_length;
|
||||||
ofcb->nb_encoding_symbols = ofcb->nb_source_symbols + ofcb->nb_repair_symbols;
|
ofcb->nb_encoding_symbols = ofcb->nb_source_symbols + ofcb->nb_repair_symbols;
|
||||||
#ifdef OF_USE_DECODER
|
#ifdef OF_USE_DECODER
|
||||||
ofcb->available_symbols_tab = (void**) of_calloc (ofcb->nb_encoding_symbols, sizeof (void*));
|
ofcb->available_symbols_tab =
|
||||||
|
(void**)of_calloc(ofcb->nb_encoding_symbols, sizeof(void*));
|
||||||
ofcb->nb_available_symbols = 0;
|
ofcb->nb_available_symbols = 0;
|
||||||
ofcb->nb_available_source_symbols = 0;
|
ofcb->nb_available_source_symbols = 0;
|
||||||
#endif /* OF_USE_DECODER */
|
#endif /* OF_USE_DECODER */
|
||||||
@@ -116,59 +120,56 @@ error:
|
|||||||
return OF_STATUS_FATAL_ERROR;
|
return OF_STATUS_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
of_status_t of_rs_2_m_set_callback_functions(
|
||||||
of_status_t of_rs_2_m_set_callback_functions (of_rs_2_m_cb_t* ofcb,
|
of_rs_2_m_cb_t* ofcb,
|
||||||
void* (*decoded_source_symbol_callback) (void *context,
|
void* (*decoded_source_symbol_callback)(
|
||||||
_UINT32 size, /* size of decoded source symbol */
|
void* context, _UINT32 size, /* size of decoded source symbol */
|
||||||
_UINT32 esi), /* encoding symbol ID in {0..k-1} */
|
_UINT32 esi), /* encoding symbol ID in {0..k-1} */
|
||||||
void* (*decoded_repair_symbol_callback) (void *context,
|
void* (*decoded_repair_symbol_callback)(
|
||||||
_UINT32 size, /* size of decoded repair symbol */
|
void* context, _UINT32 size, /* size of decoded repair symbol */
|
||||||
_UINT32 esi), /* encoding symbol ID in {0..k-1} */
|
_UINT32 esi), /* encoding symbol ID in {0..k-1} */
|
||||||
void* context_4_callback)
|
void* context_4_callback) {
|
||||||
{
|
|
||||||
ofcb->decoded_source_symbol_callback = decoded_source_symbol_callback;
|
ofcb->decoded_source_symbol_callback = decoded_source_symbol_callback;
|
||||||
ofcb->decoded_repair_symbol_callback = decoded_repair_symbol_callback;
|
ofcb->decoded_repair_symbol_callback = decoded_repair_symbol_callback;
|
||||||
ofcb->context_4_callback = context_4_callback;
|
ofcb->context_4_callback = context_4_callback;
|
||||||
if (ofcb->decoded_repair_symbol_callback != NULL)
|
if (ofcb->decoded_repair_symbol_callback != NULL) {
|
||||||
{
|
OF_PRINT_ERROR(
|
||||||
OF_PRINT_ERROR(("WARNING, the decoded repair symbol callback is never called with Reed-Solomon codes, since those repair symbols are never decoded\n"))
|
("WARNING, the decoded repair symbol callback is never called with "
|
||||||
|
"Reed-Solomon codes, since those repair symbols are never decoded\n"))
|
||||||
}
|
}
|
||||||
return OF_STATUS_OK;
|
return OF_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef OF_USE_ENCODER
|
#ifdef OF_USE_ENCODER
|
||||||
|
|
||||||
of_status_t of_rs_2_m_build_repair_symbol (of_rs_2_m_cb_t* ofcb,
|
of_status_t of_rs_2_m_build_repair_symbol(of_rs_2_m_cb_t* ofcb,
|
||||||
void* encoding_symbols_tab[],
|
void* encoding_symbols_tab[],
|
||||||
_UINT32 esi_of_symbol_to_build)
|
_UINT32 esi_of_symbol_to_build) {
|
||||||
{
|
|
||||||
OF_ENTER_FUNCTION
|
OF_ENTER_FUNCTION
|
||||||
if (esi_of_symbol_to_build < ofcb->nb_source_symbols || esi_of_symbol_to_build >= ofcb->nb_encoding_symbols)
|
if (esi_of_symbol_to_build < ofcb->nb_source_symbols ||
|
||||||
{
|
esi_of_symbol_to_build >= ofcb->nb_encoding_symbols) {
|
||||||
OF_PRINT_ERROR(("ERROR: bad esi of encoding symbol (%d)\n", esi_of_symbol_to_build))
|
OF_PRINT_ERROR(
|
||||||
|
("ERROR: bad esi of encoding symbol (%d)\n", esi_of_symbol_to_build))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (encoding_symbols_tab[esi_of_symbol_to_build] == NULL)
|
if (encoding_symbols_tab[esi_of_symbol_to_build] == NULL) {
|
||||||
{
|
if ((encoding_symbols_tab[esi_of_symbol_to_build] =
|
||||||
if ((encoding_symbols_tab[esi_of_symbol_to_build] = of_calloc (1, ofcb->encoding_symbol_length)) == NULL)
|
of_calloc(1, ofcb->encoding_symbol_length)) == NULL) {
|
||||||
{
|
|
||||||
OF_PRINT_ERROR(("ERROR: no memory\n"))
|
OF_PRINT_ERROR(("ERROR: no memory\n"))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ofcb->enc_matrix == NULL)
|
if (ofcb->enc_matrix == NULL) {
|
||||||
{
|
if (of_rs_2m_build_encoding_matrix((of_galois_field_code_cb_t*)ofcb) !=
|
||||||
if (of_rs_2m_build_encoding_matrix((of_galois_field_code_cb_t*)ofcb) != OF_STATUS_OK)
|
OF_STATUS_OK) {
|
||||||
{
|
|
||||||
OF_PRINT_ERROR(("ERROR: creating encoding matrix failed\n"))
|
OF_PRINT_ERROR(("ERROR: creating encoding matrix failed\n"))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (of_rs_2m_encode((of_galois_field_code_cb_t*) ofcb, (gf**)encoding_symbols_tab,
|
if (of_rs_2m_encode(
|
||||||
|
(of_galois_field_code_cb_t*)ofcb, (gf**)encoding_symbols_tab,
|
||||||
encoding_symbols_tab[esi_of_symbol_to_build], esi_of_symbol_to_build,
|
encoding_symbols_tab[esi_of_symbol_to_build], esi_of_symbol_to_build,
|
||||||
ofcb->encoding_symbol_length) != OF_STATUS_OK)
|
ofcb->encoding_symbol_length) != OF_STATUS_OK) {
|
||||||
{
|
|
||||||
OF_PRINT_ERROR(("ERROR: of_rs_encode failed\n"))
|
OF_PRINT_ERROR(("ERROR: of_rs_encode failed\n"))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -179,47 +180,41 @@ error:
|
|||||||
OF_EXIT_FUNCTION
|
OF_EXIT_FUNCTION
|
||||||
return OF_STATUS_ERROR;
|
return OF_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
#endif //OF_USE_ENCODER
|
#endif // OF_USE_ENCODER
|
||||||
|
|
||||||
|
|
||||||
#ifdef OF_USE_DECODER
|
#ifdef OF_USE_DECODER
|
||||||
of_status_t of_rs_2_m_decode_with_new_symbol (of_rs_2_m_cb_t* ofcb,
|
of_status_t of_rs_2_m_decode_with_new_symbol(of_rs_2_m_cb_t* ofcb,
|
||||||
void* new_symbol,
|
void* new_symbol,
|
||||||
_UINT32 new_symbol_esi)
|
_UINT32 new_symbol_esi) {
|
||||||
{
|
|
||||||
OF_ENTER_FUNCTION
|
OF_ENTER_FUNCTION
|
||||||
if (ofcb->decoding_finished)
|
if (ofcb->decoding_finished) {
|
||||||
{
|
|
||||||
OF_TRACE_LVL(2, ("%s: decoding already done\n", __FUNCTION__));
|
OF_TRACE_LVL(2, ("%s: decoding already done\n", __FUNCTION__));
|
||||||
return OF_STATUS_OK;
|
return OF_STATUS_OK;
|
||||||
}
|
}
|
||||||
if (ofcb->available_symbols_tab[new_symbol_esi] != NULL)
|
if (ofcb->available_symbols_tab[new_symbol_esi] != NULL) {
|
||||||
{
|
|
||||||
/* duplicated symbol, ignore */
|
/* duplicated symbol, ignore */
|
||||||
OF_TRACE_LVL(2, ("%s: symbol (esi=%d) duplicated\n", __FUNCTION__, new_symbol_esi));
|
OF_TRACE_LVL(
|
||||||
|
2, ("%s: symbol (esi=%d) duplicated\n", __FUNCTION__, new_symbol_esi));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
ofcb->available_symbols_tab[new_symbol_esi] = new_symbol;
|
ofcb->available_symbols_tab[new_symbol_esi] = new_symbol;
|
||||||
ofcb->nb_available_symbols++;
|
ofcb->nb_available_symbols++;
|
||||||
if (new_symbol_esi < ofcb->nb_source_symbols)
|
if (new_symbol_esi < ofcb->nb_source_symbols) {
|
||||||
{
|
|
||||||
/* remember a new source symbol is available */
|
/* remember a new source symbol is available */
|
||||||
ofcb->nb_available_source_symbols++;
|
ofcb->nb_available_source_symbols++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ofcb->nb_available_source_symbols == ofcb->nb_source_symbols)
|
if (ofcb->nb_available_source_symbols == ofcb->nb_source_symbols) {
|
||||||
{
|
|
||||||
/* we received all the k source symbols, so it's finished */
|
/* we received all the k source symbols, so it's finished */
|
||||||
ofcb->decoding_finished = true;
|
ofcb->decoding_finished = true;
|
||||||
OF_TRACE_LVL(2, ("%s: done, all source symbols have been received\n", __FUNCTION__));
|
OF_TRACE_LVL(
|
||||||
|
2, ("%s: done, all source symbols have been received\n", __FUNCTION__));
|
||||||
OF_EXIT_FUNCTION
|
OF_EXIT_FUNCTION
|
||||||
return OF_STATUS_OK;
|
return OF_STATUS_OK;
|
||||||
}
|
}
|
||||||
if (ofcb->nb_available_symbols >= ofcb->nb_source_symbols)
|
if (ofcb->nb_available_symbols >= ofcb->nb_source_symbols) {
|
||||||
{
|
|
||||||
/* we received a sufficient number of symbols, so let's decode */
|
/* we received a sufficient number of symbols, so let's decode */
|
||||||
if (of_rs_2_m_finish_decoding(ofcb) != OF_STATUS_OK)
|
if (of_rs_2_m_finish_decoding(ofcb) != OF_STATUS_OK) {
|
||||||
{
|
|
||||||
OF_PRINT_ERROR(("ERROR: of_rs_decode failure\n"))
|
OF_PRINT_ERROR(("ERROR: of_rs_decode failure\n"))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -237,23 +232,18 @@ error:
|
|||||||
return OF_STATUS_ERROR;
|
return OF_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
of_status_t of_rs_2_m_set_available_symbols(
|
||||||
of_status_t of_rs_2_m_set_available_symbols (of_rs_2_m_cb_t* ofcb,
|
of_rs_2_m_cb_t* ofcb, void* const encoding_symbols_tab[]) {
|
||||||
void* const encoding_symbols_tab[])
|
|
||||||
{
|
|
||||||
_UINT32 i;
|
_UINT32 i;
|
||||||
|
|
||||||
OF_ENTER_FUNCTION
|
OF_ENTER_FUNCTION
|
||||||
ofcb->nb_available_symbols = 0;
|
ofcb->nb_available_symbols = 0;
|
||||||
ofcb->nb_available_source_symbols = 0;
|
ofcb->nb_available_source_symbols = 0;
|
||||||
for (i = 0; i < ofcb->nb_encoding_symbols; i++)
|
for (i = 0; i < ofcb->nb_encoding_symbols; i++) {
|
||||||
{
|
if ((ofcb->available_symbols_tab[i] = encoding_symbols_tab[i]) == NULL) {
|
||||||
if ((ofcb->available_symbols_tab[i] = encoding_symbols_tab[i]) == NULL)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (i < ofcb->nb_source_symbols)
|
if (i < ofcb->nb_source_symbols) {
|
||||||
{
|
|
||||||
ofcb->nb_available_source_symbols++;
|
ofcb->nb_available_source_symbols++;
|
||||||
}
|
}
|
||||||
ofcb->nb_available_symbols++;
|
ofcb->nb_available_symbols++;
|
||||||
@@ -262,7 +252,6 @@ of_status_t of_rs_2_m_set_available_symbols (of_rs_2_m_cb_t* ofcb,
|
|||||||
return OF_STATUS_OK;
|
return OF_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0 /* new */
|
#if 0 /* new */
|
||||||
of_status_t of_rs_2_m_finish_decoding (of_rs_2_m_cb_t* ofcb)
|
of_status_t of_rs_2_m_finish_decoding (of_rs_2_m_cb_t* ofcb)
|
||||||
{
|
{
|
||||||
@@ -370,43 +359,44 @@ error:
|
|||||||
|
|
||||||
#else /* old follows */
|
#else /* old follows */
|
||||||
|
|
||||||
of_status_t of_rs_2_m_finish_decoding (of_rs_2_m_cb_t* ofcb)
|
of_status_t of_rs_2_m_finish_decoding(of_rs_2_m_cb_t* ofcb) {
|
||||||
{
|
|
||||||
_UINT32 k;
|
_UINT32 k;
|
||||||
_UINT32 n;
|
_UINT32 n;
|
||||||
// char *tmp_buf[ofcb->nb_source_symbols];/* keep available source/repair symbol buffers here... */
|
// char *tmp_buf[ofcb->nb_source_symbols];/* keep available
|
||||||
// int tmp_esi[ofcb->nb_source_symbols]; /* ...and their esi here. In fact we only need k entries
|
// source/repair symbol buffers here... */ int
|
||||||
|
// tmp_esi[ofcb->nb_source_symbols]; /* ...and their esi here. In fact we only
|
||||||
|
// need k entries
|
||||||
// * in these tables, but in order to avoid using malloc (time
|
// * in these tables, but in order to avoid using malloc (time
|
||||||
// * consumming), we use an automatic table of maximum size for
|
// * consumming), we use an automatic table of maximum size for
|
||||||
// * both tmp_buf[] and tmp_esi[]. */
|
// * both tmp_buf[] and tmp_esi[]. */
|
||||||
_INT32 tmp_idx; /* index in tmp_buf[] and tmp_esi[] tabs */
|
_INT32 tmp_idx; /* index in tmp_buf[] and tmp_esi[] tabs */
|
||||||
char *large_buf = NULL; /* single large buffer where to copy all source/repair symbols */
|
char* large_buf =
|
||||||
|
NULL; /* single large buffer where to copy all source/repair symbols */
|
||||||
_UINT32 off; /* offset, in unit of characters, in large_buf */
|
_UINT32 off; /* offset, in unit of characters, in large_buf */
|
||||||
void **ass_buf; /* tmp pointer to the current available source symbol entry in available_symbols_tab[] */
|
void** ass_buf; /* tmp pointer to the current available source symbol entry in
|
||||||
|
available_symbols_tab[] */
|
||||||
_UINT32 ass_esi; /* corresponding available source symbol ESI */
|
_UINT32 ass_esi; /* corresponding available source symbol ESI */
|
||||||
void **ars_buf; /* tmp pointer to the current available repair symbol entry in available_symbols_tab[] */
|
void** ars_buf; /* tmp pointer to the current available repair symbol entry in
|
||||||
|
available_symbols_tab[] */
|
||||||
_UINT32 ars_esi; /* corresponding available repair symbol ESI */
|
_UINT32 ars_esi; /* corresponding available repair symbol ESI */
|
||||||
|
|
||||||
OF_ENTER_FUNCTION
|
OF_ENTER_FUNCTION
|
||||||
if (ofcb->decoding_finished)
|
if (ofcb->decoding_finished) {
|
||||||
{
|
|
||||||
return OF_STATUS_OK;
|
return OF_STATUS_OK;
|
||||||
}
|
}
|
||||||
k = ofcb->nb_source_symbols;
|
k = ofcb->nb_source_symbols;
|
||||||
n = ofcb->nb_encoding_symbols;
|
n = ofcb->nb_encoding_symbols;
|
||||||
int *tmp_esi = (int*)malloc(ofcb->field_size*sizeof(int));
|
int* tmp_esi = (int*)malloc(ofcb->field_size * sizeof(int));
|
||||||
char ** tmp_buf = (char**)malloc(n*sizeof(char*)); // ???? WRT RS(255)
|
char** tmp_buf = (char**)malloc(n * sizeof(char*)); // ???? WRT RS(255)
|
||||||
for(int i=0; i<n; i++){
|
for (int i = 0; i < n; i++) {
|
||||||
tmp_buf[i] = NULL;
|
tmp_buf[i] = NULL;
|
||||||
}
|
}
|
||||||
if (ofcb->nb_available_symbols < k)
|
if (ofcb->nb_available_symbols < k) {
|
||||||
{
|
|
||||||
OF_PRINT_ERROR(("ERROR: nb received symbols < nb source symbols\n"))
|
OF_PRINT_ERROR(("ERROR: nb received symbols < nb source symbols\n"))
|
||||||
OF_EXIT_FUNCTION
|
OF_EXIT_FUNCTION
|
||||||
return OF_STATUS_FAILURE;
|
return OF_STATUS_FAILURE;
|
||||||
}
|
}
|
||||||
if (ofcb->nb_available_source_symbols == k)
|
if (ofcb->nb_available_source_symbols == k) {
|
||||||
{
|
|
||||||
/* we received all the k source symbols, so it's finished */
|
/* we received all the k source symbols, so it's finished */
|
||||||
ofcb->decoding_finished = true;
|
ofcb->decoding_finished = true;
|
||||||
OF_EXIT_FUNCTION
|
OF_EXIT_FUNCTION
|
||||||
@@ -417,51 +407,48 @@ of_status_t of_rs_2_m_finish_decoding (of_rs_2_m_cb_t* ofcb)
|
|||||||
* NB: this is required by the current FEC codec which modifies
|
* NB: this is required by the current FEC codec which modifies
|
||||||
* the tmp_buf buffers!!!
|
* the tmp_buf buffers!!!
|
||||||
*/
|
*/
|
||||||
large_buf = (char *) of_malloc(k * ofcb->encoding_symbol_length);
|
large_buf = (char*)of_malloc(k * ofcb->encoding_symbol_length);
|
||||||
if (large_buf == NULL)
|
if (large_buf == NULL) {
|
||||||
{
|
|
||||||
goto no_mem;
|
goto no_mem;
|
||||||
}
|
}
|
||||||
/* Then remember the location of each symbol buffer */
|
/* Then remember the location of each symbol buffer */
|
||||||
for (tmp_idx = 0, off = 0; tmp_idx < k; tmp_idx++, off += ofcb->encoding_symbol_length) {
|
for (tmp_idx = 0, off = 0; tmp_idx < k;
|
||||||
|
tmp_idx++, off += ofcb->encoding_symbol_length) {
|
||||||
tmp_buf[tmp_idx] = large_buf + off;
|
tmp_buf[tmp_idx] = large_buf + off;
|
||||||
}
|
}
|
||||||
tmp_idx = 0; /* index in tmp_buf and tmp_esi tables */
|
tmp_idx = 0; /* index in tmp_buf and tmp_esi tables */
|
||||||
/*
|
/*
|
||||||
* Copy all the available source symbols (it's essential for decoding speed purposes) and
|
* Copy all the available source symbols (it's essential for decoding speed
|
||||||
* a sufficient number of repair symbols to the tmp_buf array. Copy data as well in the
|
* purposes) and a sufficient number of repair symbols to the tmp_buf array.
|
||||||
* large_buf buffer.
|
* Copy data as well in the large_buf buffer. Because of of_rs_decode internal
|
||||||
* Because of of_rs_decode internal details, we put source symbols at their right location
|
* details, we put source symbols at their right location and fill in the gaps
|
||||||
* and fill in the gaps (i.e. erased source symbols) with repair symbols.
|
* (i.e. erased source symbols) with repair symbols.
|
||||||
*/
|
*/
|
||||||
ass_esi = 0;
|
ass_esi = 0;
|
||||||
ars_esi = k;
|
ars_esi = k;
|
||||||
ass_buf = ofcb->available_symbols_tab;
|
ass_buf = ofcb->available_symbols_tab;
|
||||||
ars_buf = ofcb->available_symbols_tab + k;
|
ars_buf = ofcb->available_symbols_tab + k;
|
||||||
for (tmp_idx = 0; tmp_idx < k; tmp_idx++)
|
for (tmp_idx = 0; tmp_idx < k; tmp_idx++) {
|
||||||
{
|
if (*ass_buf == NULL) {
|
||||||
if (*ass_buf == NULL)
|
|
||||||
{
|
|
||||||
/* this source symbol is not available, replace it with a repair */
|
/* this source symbol is not available, replace it with a repair */
|
||||||
while (*ars_buf == NULL)
|
while (*ars_buf == NULL) {
|
||||||
{
|
|
||||||
ars_esi++;
|
ars_esi++;
|
||||||
ars_buf++;
|
ars_buf++;
|
||||||
}
|
}
|
||||||
OF_TRACE_LVL(2, ("of_rs_finish_decoding: copy repair with esi=%d in tmp_buf[%d]\n",
|
OF_TRACE_LVL(
|
||||||
|
2, ("of_rs_finish_decoding: copy repair with esi=%d in tmp_buf[%d]\n",
|
||||||
ars_esi, tmp_idx))
|
ars_esi, tmp_idx))
|
||||||
memcpy(tmp_buf[tmp_idx], *ars_buf, ofcb->encoding_symbol_length);
|
memcpy(tmp_buf[tmp_idx], *ars_buf, ofcb->encoding_symbol_length);
|
||||||
tmp_esi[tmp_idx] = ars_esi;
|
tmp_esi[tmp_idx] = ars_esi;
|
||||||
ars_esi++;
|
ars_esi++;
|
||||||
ars_buf++;
|
ars_buf++;
|
||||||
}
|
} else {
|
||||||
else
|
OF_TRACE_LVL(
|
||||||
{
|
2, ("of_rs_finish_decoding: copy source with esi=%d in tmp_buf[%d]\n",
|
||||||
OF_TRACE_LVL(2, ("of_rs_finish_decoding: copy source with esi=%d in tmp_buf[%d]\n",
|
|
||||||
ars_esi, tmp_idx))
|
ars_esi, tmp_idx))
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i=0;i<ofcb->encoding_symbol_length;i++) {
|
for (i = 0; i < ofcb->encoding_symbol_length; i++) {
|
||||||
}
|
}
|
||||||
memcpy(tmp_buf[tmp_idx], *ass_buf, ofcb->encoding_symbol_length);
|
memcpy(tmp_buf[tmp_idx], *ass_buf, ofcb->encoding_symbol_length);
|
||||||
tmp_esi[tmp_idx] = ass_esi;
|
tmp_esi[tmp_idx] = ass_esi;
|
||||||
@@ -475,16 +462,16 @@ of_status_t of_rs_2_m_finish_decoding (of_rs_2_m_cb_t* ofcb)
|
|||||||
OF_TRACE_LVL(2, ("Before of_rs_decode: esi=%d, k=%d, tmp_idx=%d\n", tmp_esi[tmp_idx], k, tmp_idx))
|
OF_TRACE_LVL(2, ("Before of_rs_decode: esi=%d, k=%d, tmp_idx=%d\n", tmp_esi[tmp_idx], k, tmp_idx))
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (ofcb->enc_matrix == NULL)
|
if (ofcb->enc_matrix == NULL) {
|
||||||
{
|
if (of_rs_2m_build_encoding_matrix((of_galois_field_code_cb_t*)ofcb) !=
|
||||||
if (of_rs_2m_build_encoding_matrix((of_galois_field_code_cb_t*)ofcb) != OF_STATUS_OK)
|
OF_STATUS_OK) {
|
||||||
{
|
|
||||||
OF_PRINT_ERROR(("ERROR: creating encoding matrix failed\n"))
|
OF_PRINT_ERROR(("ERROR: creating encoding matrix failed\n"))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (of_rs_2m_decode ((of_galois_field_code_cb_t*)ofcb, (gf**)tmp_buf, (int*)tmp_esi, ofcb->encoding_symbol_length) != OF_STATUS_OK)
|
if (of_rs_2m_decode((of_galois_field_code_cb_t*)ofcb, (gf**)tmp_buf,
|
||||||
{
|
(int*)tmp_esi,
|
||||||
|
ofcb->encoding_symbol_length) != OF_STATUS_OK) {
|
||||||
OF_PRINT_ERROR(("ERROR: of_rs_decode failure\n"))
|
OF_PRINT_ERROR(("ERROR: of_rs_decode failure\n"))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@@ -496,14 +483,13 @@ of_status_t of_rs_2_m_finish_decoding (of_rs_2_m_cb_t* ofcb)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
* finally update the source_symbols_tab table with the decoded source symbols.
|
* finally update the source_symbols_tab table with the decoded source
|
||||||
|
* symbols.
|
||||||
*/
|
*/
|
||||||
for (tmp_idx = 0; tmp_idx < k; tmp_idx++)
|
for (tmp_idx = 0; tmp_idx < k; tmp_idx++) {
|
||||||
{
|
|
||||||
ASSERT(tmp_idx < k);
|
ASSERT(tmp_idx < k);
|
||||||
ass_buf = &(ofcb->available_symbols_tab[tmp_idx]);
|
ass_buf = &(ofcb->available_symbols_tab[tmp_idx]);
|
||||||
if (*ass_buf != NULL)
|
if (*ass_buf != NULL) {
|
||||||
{
|
|
||||||
/* nothing to do, this source symbol has already been received. */
|
/* nothing to do, this source symbol has already been received. */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -513,58 +499,48 @@ of_status_t of_rs_2_m_finish_decoding (of_rs_2_m_cb_t* ofcb)
|
|||||||
* Call either the associated callback or allocate memory, and then
|
* Call either the associated callback or allocate memory, and then
|
||||||
* copy the symbol content in it.
|
* copy the symbol content in it.
|
||||||
*/
|
*/
|
||||||
if (ofcb->decoded_source_symbol_callback != NULL)
|
if (ofcb->decoded_source_symbol_callback != NULL) {
|
||||||
{
|
*ass_buf = ofcb->decoded_source_symbol_callback(
|
||||||
*ass_buf = ofcb->decoded_source_symbol_callback (ofcb->context_4_callback,
|
ofcb->context_4_callback, ofcb->encoding_symbol_length, tmp_idx);
|
||||||
ofcb->encoding_symbol_length, tmp_idx);
|
} else {
|
||||||
|
*ass_buf = (void*)of_malloc(ofcb->encoding_symbol_length);
|
||||||
}
|
}
|
||||||
else
|
if (*ass_buf == NULL) {
|
||||||
{
|
|
||||||
*ass_buf = (void *) of_malloc (ofcb->encoding_symbol_length);
|
|
||||||
}
|
|
||||||
if (*ass_buf == NULL)
|
|
||||||
{
|
|
||||||
goto no_mem;
|
goto no_mem;
|
||||||
}
|
}
|
||||||
memcpy(*ass_buf, tmp_buf[tmp_idx], ofcb->encoding_symbol_length);
|
memcpy(*ass_buf, tmp_buf[tmp_idx], ofcb->encoding_symbol_length);
|
||||||
OF_TRACE_LVL(2, ("of_rs_finish_decoding: decoded source symbol esi=%d from tmp_buf[%d]\n",
|
OF_TRACE_LVL(2, ("of_rs_finish_decoding: decoded source symbol esi=%d from "
|
||||||
|
"tmp_buf[%d]\n",
|
||||||
tmp_idx, tmp_idx))
|
tmp_idx, tmp_idx))
|
||||||
}
|
}
|
||||||
of_free(large_buf);
|
of_free(large_buf);
|
||||||
free(tmp_esi);
|
free(tmp_esi);
|
||||||
for(int i=0;i<n;i++){
|
free(tmp_buf);
|
||||||
free(tmp_buf[i]);
|
|
||||||
}
|
|
||||||
OF_EXIT_FUNCTION
|
OF_EXIT_FUNCTION
|
||||||
return OF_STATUS_OK;
|
return OF_STATUS_OK;
|
||||||
|
|
||||||
no_mem:
|
no_mem:
|
||||||
OF_PRINT_ERROR(("ERROR: out of memory.\n"))
|
OF_PRINT_ERROR(("ERROR: out of memory.\n"))
|
||||||
free(tmp_esi);
|
free(tmp_esi);
|
||||||
for(int i=0;i<n;i++){
|
free(tmp_buf);
|
||||||
free(tmp_buf[i]);
|
|
||||||
}
|
error:
|
||||||
error:
|
|
||||||
OF_EXIT_FUNCTION
|
OF_EXIT_FUNCTION
|
||||||
return OF_STATUS_ERROR;
|
return OF_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool of_rs_2_m_is_decoding_complete(of_rs_2_m_cb_t* ofcb) {
|
||||||
bool of_rs_2_m_is_decoding_complete (of_rs_2_m_cb_t* ofcb)
|
|
||||||
{
|
|
||||||
OF_ENTER_FUNCTION
|
OF_ENTER_FUNCTION
|
||||||
OF_EXIT_FUNCTION
|
OF_EXIT_FUNCTION
|
||||||
return ofcb->decoding_finished;
|
return ofcb->decoding_finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
of_status_t of_rs_2_m_get_source_symbols_tab(of_rs_2_m_cb_t* ofcb,
|
||||||
of_status_t of_rs_2_m_get_source_symbols_tab (of_rs_2_m_cb_t* ofcb,
|
void* source_symbols_tab[]) {
|
||||||
void* source_symbols_tab[])
|
|
||||||
{
|
|
||||||
OF_ENTER_FUNCTION
|
OF_ENTER_FUNCTION
|
||||||
if (of_rs_2_m_is_decoding_complete(ofcb) == false)
|
if (of_rs_2_m_is_decoding_complete(ofcb) == false) {
|
||||||
{
|
|
||||||
OF_PRINT_ERROR(("ERROR: decoding not complete.\n"))
|
OF_PRINT_ERROR(("ERROR: decoding not complete.\n"))
|
||||||
OF_EXIT_FUNCTION
|
OF_EXIT_FUNCTION
|
||||||
return OF_STATUS_ERROR;
|
return OF_STATUS_ERROR;
|
||||||
@@ -579,27 +555,27 @@ of_status_t of_rs_2_m_get_source_symbols_tab (of_rs_2_m_cb_t* ofcb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
memcpy(source_symbols_tab, ofcb->available_symbols_tab, ofcb->nb_source_symbols * sizeof(void*));
|
memcpy(source_symbols_tab, ofcb->available_symbols_tab,
|
||||||
|
ofcb->nb_source_symbols * sizeof(void*));
|
||||||
#endif
|
#endif
|
||||||
OF_EXIT_FUNCTION
|
OF_EXIT_FUNCTION
|
||||||
return OF_STATUS_OK;
|
return OF_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // OF_USE_DECODER
|
||||||
|
|
||||||
#endif //OF_USE_DECODER
|
of_status_t of_rs_2_m_set_control_parameter(of_rs_2_m_cb_t* ofcb, _UINT32 type,
|
||||||
|
void* value, _UINT32 length) {
|
||||||
of_status_t of_rs_2_m_set_control_parameter (of_rs_2_m_cb_t* ofcb,
|
|
||||||
_UINT32 type,
|
|
||||||
void* value,
|
|
||||||
_UINT32 length)
|
|
||||||
{
|
|
||||||
_UINT16 m;
|
_UINT16 m;
|
||||||
|
|
||||||
OF_ENTER_FUNCTION
|
OF_ENTER_FUNCTION
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OF_RS_CTRL_SET_FIELD_SIZE:
|
case OF_RS_CTRL_SET_FIELD_SIZE:
|
||||||
if (value == NULL || length != sizeof(_UINT16)) {
|
if (value == NULL || length != sizeof(_UINT16)) {
|
||||||
OF_PRINT_ERROR(("OF_CTRL_SET_FIELD_SIZE ERROR: null value or bad length (got %d, expected %zu)\n", length, sizeof(_UINT16)))
|
OF_PRINT_ERROR(
|
||||||
|
("OF_CTRL_SET_FIELD_SIZE ERROR: null value or bad length (got %d, "
|
||||||
|
"expected %zu)\n",
|
||||||
|
length, sizeof(_UINT16)))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
m = *(_UINT16*)value;
|
m = *(_UINT16*)value;
|
||||||
@@ -609,7 +585,8 @@ of_status_t of_rs_2_m_set_control_parameter (of_rs_2_m_cb_t* ofcb,
|
|||||||
}
|
}
|
||||||
ofcb->m = m;
|
ofcb->m = m;
|
||||||
ofcb->field_size = (1 << ofcb->m) - 1;
|
ofcb->field_size = (1 << ofcb->m) - 1;
|
||||||
ofcb->max_nb_encoding_symbols = ofcb->max_nb_source_symbols = ofcb->field_size;
|
ofcb->max_nb_encoding_symbols = ofcb->max_nb_source_symbols =
|
||||||
|
ofcb->field_size;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -624,38 +601,48 @@ error:
|
|||||||
return OF_STATUS_ERROR;
|
return OF_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
of_status_t of_rs_2_m_get_control_parameter(of_rs_2_m_cb_t* ofcb, _UINT32 type,
|
||||||
of_status_t of_rs_2_m_get_control_parameter (of_rs_2_m_cb_t* ofcb,
|
void* value, _UINT32 length) {
|
||||||
_UINT32 type,
|
|
||||||
void* value,
|
|
||||||
_UINT32 length)
|
|
||||||
{
|
|
||||||
OF_ENTER_FUNCTION
|
OF_ENTER_FUNCTION
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OF_CTRL_GET_MAX_K:
|
case OF_CTRL_GET_MAX_K:
|
||||||
if (value == NULL || length != sizeof(_UINT32)) {
|
if (value == NULL || length != sizeof(_UINT32)) {
|
||||||
OF_PRINT_ERROR(("OF_CTRL_GET_MAX_K ERROR: null value or bad length (got %d, expected %zu)\n", length, sizeof(_UINT32)))
|
OF_PRINT_ERROR(
|
||||||
|
("OF_CTRL_GET_MAX_K ERROR: null value or bad length (got %d, "
|
||||||
|
"expected %zu)\n",
|
||||||
|
length, sizeof(_UINT32)))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (ofcb->max_nb_source_symbols == 0) {
|
if (ofcb->max_nb_source_symbols == 0) {
|
||||||
OF_PRINT_ERROR(("OF_CTRL_GET_MAX_K ERROR: this parameter is not initialized. Use the of_rs_2_m_set_fec_parameters function to initialize it or of_rs_2_m_set_control_parameter.\n"))
|
OF_PRINT_ERROR(
|
||||||
|
("OF_CTRL_GET_MAX_K ERROR: this parameter is not initialized. Use "
|
||||||
|
"the of_rs_2_m_set_fec_parameters function to initialize it or "
|
||||||
|
"of_rs_2_m_set_control_parameter.\n"))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
*(_UINT32*)value = ofcb->max_nb_source_symbols;
|
*(_UINT32*)value = ofcb->max_nb_source_symbols;
|
||||||
OF_TRACE_LVL(1, ("%s: OF_CTRL_GET_MAX_K (%d)\n", __FUNCTION__, *(_UINT32*)value))
|
OF_TRACE_LVL(
|
||||||
|
1, ("%s: OF_CTRL_GET_MAX_K (%d)\n", __FUNCTION__, *(_UINT32*)value))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OF_CTRL_GET_MAX_N:
|
case OF_CTRL_GET_MAX_N:
|
||||||
if (value == NULL || length != sizeof(_UINT32)) {
|
if (value == NULL || length != sizeof(_UINT32)) {
|
||||||
OF_PRINT_ERROR(("OF_CTRL_GET_MAX_N ERROR: null value or bad length (got %d, expected %zu)\n", length, sizeof(_UINT32)))
|
OF_PRINT_ERROR(
|
||||||
|
("OF_CTRL_GET_MAX_N ERROR: null value or bad length (got %d, "
|
||||||
|
"expected %zu)\n",
|
||||||
|
length, sizeof(_UINT32)))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (ofcb->max_nb_encoding_symbols == 0) {
|
if (ofcb->max_nb_encoding_symbols == 0) {
|
||||||
OF_PRINT_ERROR(("OF_CTRL_GET_MAX_N ERROR: this parameter is not initialized. Use the of_rs_2_m_set_fec_parameters function to initialize it or of_rs_2_m_set_control_parameter.\n"))
|
OF_PRINT_ERROR(
|
||||||
|
("OF_CTRL_GET_MAX_N ERROR: this parameter is not initialized. Use "
|
||||||
|
"the of_rs_2_m_set_fec_parameters function to initialize it or "
|
||||||
|
"of_rs_2_m_set_control_parameter.\n"))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
*(_UINT32*)value = ofcb->max_nb_encoding_symbols;
|
*(_UINT32*)value = ofcb->max_nb_encoding_symbols;
|
||||||
OF_TRACE_LVL(1, ("%s: OF_CTRL_GET_MAX_N (%d)\n", __FUNCTION__, *(_UINT32*)value))
|
OF_TRACE_LVL(
|
||||||
|
1, ("%s: OF_CTRL_GET_MAX_N (%d)\n", __FUNCTION__, *(_UINT32*)value))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user