Implementation for FEC decoder module

This commit is contained in:
dijunkun
2023-11-15 22:01:05 -08:00
parent 31b5d7f2e3
commit b0bee226d1
12 changed files with 940 additions and 484 deletions

127
src/fec/fec_decoder.cpp Normal file
View 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
View 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

View File

@@ -40,6 +40,10 @@ int FecEncoder::Release() {
} }
} }
if (fec_rs_params_) {
free(fec_rs_params_);
}
return 0; return 0;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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