OpenFec(官网:http://www.openfec.org/)是一个项目,主要处理正向纠错码,在通信中加上一些冗余数据,在网络质量差、丢包的时候,可以根据这些冗余数据恢复出原来的数据。目前OpenFec项目支持以下编码:
(1) Reed-Solomon over GF(28)
(2) Reed-Solomon stable codec over GF(2m)
(3) 1D-2D parity check matrix stable codec
(4) LDPC-staircase stable codec
(5) LDPC from file advanced codec
下面介绍几个比较重要的结构体:
of_codec_id_t
描述编码类型的枚举变量
typedef enum
{
OF_CODEC_NIL = 0,
OF_CODEC_REED_SOLOMON_GF_2_8_STABLE = 1,
OF_CODEC_REED_SOLOMON_GF_2_M_STABLE = 2,
OF_CODEC_LDPC_STAIRCASE_STABLE = 3,
// OF_CODEC_LDPC_TRIANGLE_STABLE = 4,
OF_CODEC_2D_PARITY_MATRIX_STABLE = 5,
OF_CODEC_LDPC_FROM_FILE_ADVANCED = 6
} of_codec_id_t;
of_session_t
指向于当前编解码实例的一个结构体,起标识作用
typedef struct of_session
{
of_codec_id_t codec_id;
of_codec_type_t codec_type;
} of_session_t;
of_parameters
配置FEC 变量相关的结构体,在of_set_fec_parameters中被调用
typedef struct of_parameters
{
UINT32 nb_source_symbols;
UINT32 nb_repair_symbols;
UINT32 encoding_symbol_length;
} of_parameters_t;
主要调用流程:
在FEC 中,一个包必须是4的倍数,一个包由src符号 + repair符号组成, k代表src符号,n代表完整的一个包,n-k代表repair符号。
以下代码是官方例子simple_client.c修改而来
void decode()
{
int ret;
byte **data;
UINT32 esi;
UINT32 k;//源符号数量
UINT32 n;//源符号+ 修复符号 数量
bool done = false;
UINT32 n_received = 0;
of_codec_id_t codec_id;
of_session_t *ses = NULL;
of_parameters_t *params = NULL;
void** recvd_symbols_tab = NULL;//存放指针
void** src_symbols_tab = NULL;//用于存放还原后的数据
int len = sizeof(fec_oti_t);
byte *head = (byte*)malloc(sizeof(byte) * len);
ret = ReceiveUdpData(head, len);//接收指定长度的udp数据包
if (ret != len)
{
printf("接收失败\n");
return;
}
else
{
printf("接收成功\n");
}
fec_oti_t *fec_oti = (fec_oti_t*)head;
codec_id = (of_codec_id_t)ntohl(fec_oti->codec_id);
k = fec_oti->k = ntohl(fec_oti->k);
n = fec_oti->n = ntohl(fec_oti->n);
switch (codec_id)
{
case OF_CODEC_REED_SOLOMON_GF_2_M_STABLE:
{
{
of_rs_2_m_parameters_t *my_params;
my_params = (of_rs_2_m_parameters_t *)calloc(1, sizeof(*my_params) );
my_params->m = 8;
params = (of_parameters_t *)my_params;
}
break;
}
case OF_CODEC_LDPC_STAIRCASE_STABLE:
{
{
of_ldpc_parameters_t *my_params;
my_params = (of_ldpc_parameters_t *)calloc(1, sizeof(*my_params));
my_params->prng_seed = rand();
my_params->N1 = 7;
params = (of_parameters_t *)my_params;
}
break;
}
}
params->nb_source_symbols = k;
params->nb_repair_symbols = n - k;
params->encoding_symbol_length = 1024;
if ((ret = of_create_codec_instance(&ses, codec_id, OF_DECODER, 2)) != OF_STATUS_OK)//打开实例
{
OF_PRINT_ERROR(("of_create_codec_instance() failed\n"))
ret = -1;
goto end;
}
if (of_set_fec_parameters(ses, params) != OF_STATUS_OK)//根据头或到参数,设置参数
{
OF_PRINT_ERROR(("of_set_fec_parameters() failed for codec_id %d\n", codec_id))
ret = -1;
goto end;
}
if (((recvd_symbols_tab = (void**)calloc(n, sizeof(void*))) == NULL) ||
((src_symbols_tab = (void**)calloc(n, sizeof(void*))) == NULL))
{
OF_PRINT_ERROR(("no memory (calloc failed for enc_symbols_tab, n=%u)\n", n))
ret = -1;
goto end;
}
len = 1024 + 4;//前4个字节是fec相关的信息,不参与解码
data = (byte**)malloc(sizeof(byte*) * len * n);
for (size_t i = 0; i < n; i++)
{
data[i] = (byte*)malloc(sizeof(byte) * len);
}
while (ReceiveUdpData(data[n_received], len) > 0)
{
esi = ntohl(*(UINT32*)data[n_received]);
if (esi > n)
{
goto end;
}
recvd_symbols_tab[esi] = (char*)data[n_received] + 4;//保存指针
if (of_decode_with_new_symbol(ses, (char*)data[n_received] + 4, esi) == OF_STATUS_ERROR)
{
OF_PRINT_ERROR(("of_decode_with_new_symbol() failed\n"))
ret = -1;
goto end;
}
if ((n_received >= k) && (of_is_decoding_complete(ses) == true))
{
done = true;
break;
}
n_received++;
}
if (!done && (ret == OF_STATUS_FAILURE) && (n_received >= k))
{
ret = of_finish_decoding(ses);
if (ret == OF_STATUS_ERROR || ret == OF_STATUS_FATAL_ERROR)
{
OF_PRINT_ERROR(("of_finish_decoding() failed with error (%d)\n", ret))
ret = -1;
goto end;
}
else if (ret == OF_STATUS_OK)
{
done = true;
}
}
if (done)
{
if (of_get_source_symbols_tab(ses, src_symbols_tab) != OF_STATUS_OK)
{
OF_PRINT_ERROR(("of_get_source_symbols_tab() failed\n"))
ret = -1;
goto end;
}
printf("\nDone! All source symbols rebuilt after receiving %u packets\n", n_received);
if (2 > 1)
{
for (esi = 0; esi < k; esi++)
{
printf("src[%u]= ", esi);
dump_buffer_32(src_symbols_tab[esi], 1);
}
}
}
else
{
printf("\nFailed to recover all erased source symbols even after receiving %u packets\n", n_received);
}
end:
closesocket(localSocket);
if (ses)
{
of_release_codec_instance(ses);
}
if (params)
{
free(params);
}
if (fec_oti)
{
free(fec_oti);
}
if (recvd_symbols_tab && src_symbols_tab)
{
for (esi = 0; esi < n; esi++)
{
if (recvd_symbols_tab[esi])
{
free((char*)recvd_symbols_tab[esi] - 4);
}
else if (esi < k && src_symbols_tab[esi])
{
ASSERT(recvd_symbols_tab[esi] == NULL);
free(src_symbols_tab[esi]);
}
}
free(recvd_symbols_tab);
free(src_symbols_tab);
}
printf("完成\n");
}