Remove part of the FEC code table that covers FEC code for group of 13-48 media packets, instead generate interleaved FEC code at run time. FEC code masks for protection of group of 1 - 12 media packets is not changed.
Bug: webrtc:9165 Change-Id: I57c8fd032c7a5192d0da8dfde96550b328cf6620 Reviewed-on: https://webrtc-review.googlesource.com/69680 Commit-Queue: Ying Wang <yinwa@webrtc.org> Reviewed-by: Stefan Holmer <stefan@webrtc.org> Cr-Commit-Position: refs/heads/master@{#22921}
This commit is contained in:
@ -15,6 +15,11 @@
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
constexpr uint8_t kMaskRandom15_6[] = {0x82, 0x08, 0x41, 0x04, 0x20, 0x82,
|
||||
0x10, 0x40, 0x08, 0x20, 0x04, 0x10};
|
||||
}
|
||||
|
||||
namespace fec_private_tables {
|
||||
|
||||
using internal::LookUpInFecTable;
|
||||
@ -57,18 +62,20 @@ TEST(FecTable, TestRandomLookup) {
|
||||
EXPECT_EQ(4u, result.size());
|
||||
EXPECT_EQ(0xa8u, result[0]);
|
||||
EXPECT_EQ(0xd0u, result[2]);
|
||||
}
|
||||
|
||||
result = LookUpInFecTable(&kPacketMaskRandomTbl[0], 16, 0);
|
||||
// kMaskRandom17_1.
|
||||
EXPECT_EQ(6u, result.size());
|
||||
EXPECT_EQ(0xffu, result[0]);
|
||||
EXPECT_EQ(0x00u, result[5]);
|
||||
|
||||
result = LookUpInFecTable(&kPacketMaskRandomTbl[0], 47, 47);
|
||||
// kMaskRandom48_48.
|
||||
EXPECT_EQ(6u * 48, result.size());
|
||||
EXPECT_EQ(0x10u, result[0]);
|
||||
EXPECT_EQ(0x02u, result[6]);
|
||||
TEST(FecTable, TestRandomGenerated) {
|
||||
FecMaskType fec_mask_type = webrtc::kFecMaskRandom;
|
||||
int num_media_packets = 15;
|
||||
int num_fec_packets = 6;
|
||||
size_t mask_size = sizeof(kMaskRandom15_6) / sizeof(uint8_t);
|
||||
internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
|
||||
rtc::ArrayView<const uint8_t> mask =
|
||||
mask_table.LookUp(num_media_packets, num_fec_packets);
|
||||
EXPECT_EQ(mask.size(), mask_size);
|
||||
for (size_t i = 0; i < mask_size; i++) {
|
||||
EXPECT_EQ(mask[i], kMaskRandom15_6[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fec_private_tables
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -155,12 +155,12 @@ int ForwardErrorCorrection::EncodeFec(const PacketList& media_packets,
|
||||
fec_packets->push_back(&generated_fec_packets_[i]);
|
||||
}
|
||||
|
||||
const internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
|
||||
internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
|
||||
packet_mask_size_ = internal::PacketMaskSize(num_media_packets);
|
||||
memset(packet_masks_, 0, num_fec_packets * packet_mask_size_);
|
||||
internal::GeneratePacketMasks(num_media_packets, num_fec_packets,
|
||||
num_important_packets, use_unequal_protection,
|
||||
mask_table, packet_masks_);
|
||||
&mask_table, packet_masks_);
|
||||
|
||||
// Adapt packet masks to missing media packets.
|
||||
int num_mask_bits = InsertZerosInPacketMasks(media_packets, num_fec_packets);
|
||||
|
||||
@ -146,9 +146,68 @@ PacketMaskTable::PacketMaskTable(FecMaskType fec_mask_type,
|
||||
|
||||
PacketMaskTable::~PacketMaskTable() = default;
|
||||
|
||||
rtc::ArrayView<const uint8_t> PacketMaskTable::LookUp(int media_packet_index,
|
||||
int fec_index) const {
|
||||
return LookUpInFecTable(table_, media_packet_index, fec_index);
|
||||
rtc::ArrayView<const uint8_t> PacketMaskTable::LookUp(int num_media_packets,
|
||||
int num_fec_packets) {
|
||||
RTC_DCHECK_GT(num_media_packets, 0);
|
||||
RTC_DCHECK_GT(num_fec_packets, 0);
|
||||
RTC_DCHECK_LE(num_media_packets, kUlpfecMaxMediaPackets);
|
||||
RTC_DCHECK_LE(num_fec_packets, num_media_packets);
|
||||
|
||||
if (num_media_packets <= 12) {
|
||||
return LookUpInFecTable(table_, num_media_packets - 1, num_fec_packets - 1);
|
||||
}
|
||||
int mask_length =
|
||||
static_cast<int>(PacketMaskSize(static_cast<size_t>(num_media_packets)));
|
||||
|
||||
// Generate FEC code mask for {num_media_packets(M), num_fec_packets(N)} (use
|
||||
// N FEC packets to protect M media packets) In the mask, each FEC packet
|
||||
// occupies one row, each bit / coloumn represent one media packet. E.g. Row
|
||||
// A, Col/Bit B is set to 1, means FEC packet A will have protection for media
|
||||
// packet B.
|
||||
|
||||
// Loop through each fec packet.
|
||||
for (int row = 0; row < num_fec_packets; row++) {
|
||||
// Loop through each fec code in a row, one code has 8 bits.
|
||||
// Bit X will be set to 1 if media packet X shall be protected by current
|
||||
// FEC packet. In this implementation, the protection is interleaved, thus
|
||||
// media packet X will be protected by FEC packet (X % N)
|
||||
for (int col = 0; col < mask_length; col++) {
|
||||
fec_packet_mask_[row * mask_length + col] =
|
||||
((col * 8) % num_fec_packets == row && (col * 8) < num_media_packets
|
||||
? 0x80
|
||||
: 0x00) |
|
||||
((col * 8 + 1) % num_fec_packets == row &&
|
||||
(col * 8 + 1) < num_media_packets
|
||||
? 0x40
|
||||
: 0x00) |
|
||||
((col * 8 + 2) % num_fec_packets == row &&
|
||||
(col * 8 + 2) < num_media_packets
|
||||
? 0x20
|
||||
: 0x00) |
|
||||
((col * 8 + 3) % num_fec_packets == row &&
|
||||
(col * 8 + 3) < num_media_packets
|
||||
? 0x10
|
||||
: 0x00) |
|
||||
((col * 8 + 4) % num_fec_packets == row &&
|
||||
(col * 8 + 4) < num_media_packets
|
||||
? 0x08
|
||||
: 0x00) |
|
||||
((col * 8 + 5) % num_fec_packets == row &&
|
||||
(col * 8 + 5) < num_media_packets
|
||||
? 0x04
|
||||
: 0x00) |
|
||||
((col * 8 + 6) % num_fec_packets == row &&
|
||||
(col * 8 + 6) < num_media_packets
|
||||
? 0x02
|
||||
: 0x00) |
|
||||
((col * 8 + 7) % num_fec_packets == row &&
|
||||
(col * 8 + 7) < num_media_packets
|
||||
? 0x01
|
||||
: 0x00);
|
||||
}
|
||||
}
|
||||
return {&fec_packet_mask_[0],
|
||||
static_cast<size_t>(num_fec_packets * mask_length)};
|
||||
}
|
||||
|
||||
// If |num_media_packets| is larger than the maximum allowed by |fec_mask_type|
|
||||
@ -157,8 +216,7 @@ rtc::ArrayView<const uint8_t> PacketMaskTable::LookUp(int media_packet_index,
|
||||
const uint8_t* PacketMaskTable::PickTable(FecMaskType fec_mask_type,
|
||||
int num_media_packets) {
|
||||
RTC_DCHECK_GE(num_media_packets, 0);
|
||||
RTC_DCHECK_LE(static_cast<size_t>(num_media_packets),
|
||||
fec_private_tables::kPacketMaskRandomTbl[0]);
|
||||
RTC_DCHECK_LE(static_cast<size_t>(num_media_packets), kUlpfecMaxMediaPackets);
|
||||
|
||||
if (fec_mask_type != kFecMaskRandom &&
|
||||
num_media_packets <=
|
||||
@ -176,7 +234,7 @@ void RemainingPacketProtection(int num_media_packets,
|
||||
int num_mask_bytes,
|
||||
ProtectionMode mode,
|
||||
uint8_t* packet_mask,
|
||||
const PacketMaskTable& mask_table) {
|
||||
PacketMaskTable* mask_table) {
|
||||
if (mode == kModeNoOverlap) {
|
||||
// sub_mask21
|
||||
|
||||
@ -184,8 +242,8 @@ void RemainingPacketProtection(int num_media_packets,
|
||||
PacketMaskSize(num_media_packets - num_fec_for_imp_packets);
|
||||
|
||||
auto end_row = (num_fec_for_imp_packets + num_fec_remaining);
|
||||
rtc::ArrayView<const uint8_t> packet_mask_sub_21 = mask_table.LookUp(
|
||||
num_media_packets - num_fec_for_imp_packets - 1, num_fec_remaining - 1);
|
||||
rtc::ArrayView<const uint8_t> packet_mask_sub_21 = mask_table->LookUp(
|
||||
num_media_packets - num_fec_for_imp_packets, num_fec_remaining);
|
||||
|
||||
ShiftFitSubMask(num_mask_bytes, res_mask_bytes, num_fec_for_imp_packets,
|
||||
end_row, &packet_mask_sub_21[0], packet_mask);
|
||||
@ -193,7 +251,7 @@ void RemainingPacketProtection(int num_media_packets,
|
||||
} else if (mode == kModeOverlap || mode == kModeBiasFirstPacket) {
|
||||
// sub_mask22
|
||||
rtc::ArrayView<const uint8_t> packet_mask_sub_22 =
|
||||
mask_table.LookUp(num_media_packets - 1, num_fec_remaining - 1);
|
||||
mask_table->LookUp(num_media_packets, num_fec_remaining);
|
||||
|
||||
FitSubMask(num_mask_bytes, num_mask_bytes, num_fec_remaining,
|
||||
&packet_mask_sub_22[0],
|
||||
@ -215,12 +273,12 @@ void ImportantPacketProtection(int num_fec_for_imp_packets,
|
||||
int num_imp_packets,
|
||||
int num_mask_bytes,
|
||||
uint8_t* packet_mask,
|
||||
const PacketMaskTable& mask_table) {
|
||||
PacketMaskTable* mask_table) {
|
||||
const int num_imp_mask_bytes = PacketMaskSize(num_imp_packets);
|
||||
|
||||
// Get sub_mask1 from table
|
||||
rtc::ArrayView<const uint8_t> packet_mask_sub_1 =
|
||||
mask_table.LookUp(num_imp_packets - 1, num_fec_for_imp_packets - 1);
|
||||
mask_table->LookUp(num_imp_packets, num_fec_for_imp_packets);
|
||||
|
||||
FitSubMask(num_mask_bytes, num_imp_mask_bytes, num_fec_for_imp_packets,
|
||||
&packet_mask_sub_1[0], packet_mask);
|
||||
@ -300,7 +358,7 @@ void UnequalProtectionMask(int num_media_packets,
|
||||
int num_imp_packets,
|
||||
int num_mask_bytes,
|
||||
uint8_t* packet_mask,
|
||||
const PacketMaskTable& mask_table) {
|
||||
PacketMaskTable* mask_table) {
|
||||
// Set Protection type and allocation
|
||||
// TODO(marpan): test/update for best mode and some combinations thereof.
|
||||
|
||||
@ -352,8 +410,6 @@ void UnequalProtectionMask(int num_media_packets,
|
||||
rtc::ArrayView<const uint8_t> LookUpInFecTable(const uint8_t* table,
|
||||
int media_packet_index,
|
||||
int fec_index) {
|
||||
RTC_DCHECK_GE(media_packet_index, 0);
|
||||
RTC_DCHECK_GE(fec_index, 0);
|
||||
RTC_DCHECK_LT(media_packet_index, table[0]);
|
||||
|
||||
// Skip over the table size.
|
||||
@ -392,7 +448,7 @@ void GeneratePacketMasks(int num_media_packets,
|
||||
int num_fec_packets,
|
||||
int num_imp_packets,
|
||||
bool use_unequal_protection,
|
||||
const PacketMaskTable& mask_table,
|
||||
PacketMaskTable* mask_table,
|
||||
uint8_t* packet_mask) {
|
||||
RTC_DCHECK_GT(num_media_packets, 0);
|
||||
RTC_DCHECK_GT(num_fec_packets, 0);
|
||||
@ -408,7 +464,7 @@ void GeneratePacketMasks(int num_media_packets,
|
||||
// Mask = (k,n-k), with protection factor = (n-k)/k,
|
||||
// where k = num_media_packets, n=total#packets, (n-k)=num_fec_packets.
|
||||
rtc::ArrayView<const uint8_t> mask =
|
||||
mask_table.LookUp(num_media_packets - 1, num_fec_packets - 1);
|
||||
mask_table->LookUp(num_media_packets, num_fec_packets);
|
||||
memcpy(packet_mask, &mask[0], mask.size());
|
||||
} else { // UEP case
|
||||
UnequalProtectionMask(num_media_packets, num_fec_packets, num_imp_packets,
|
||||
|
||||
@ -25,6 +25,9 @@ constexpr size_t kUlpfecMaxMediaPackets = 48;
|
||||
constexpr size_t kUlpfecPacketMaskSizeLBitClear = 2;
|
||||
constexpr size_t kUlpfecPacketMaskSizeLBitSet = 6;
|
||||
|
||||
// Packet code mask maximum length
|
||||
constexpr size_t kFECPacketMaskMaxSize = 288;
|
||||
|
||||
// Convenience constants.
|
||||
constexpr size_t kUlpfecMinPacketMaskSize = kUlpfecPacketMaskSizeLBitClear;
|
||||
constexpr size_t kUlpfecMaxPacketMaskSize = kUlpfecPacketMaskSizeLBitSet;
|
||||
@ -36,13 +39,14 @@ class PacketMaskTable {
|
||||
PacketMaskTable(FecMaskType fec_mask_type, int num_media_packets);
|
||||
~PacketMaskTable();
|
||||
|
||||
rtc::ArrayView<const uint8_t> LookUp(int media_packet_index,
|
||||
int fec_index) const;
|
||||
rtc::ArrayView<const uint8_t> LookUp(int num_media_packets,
|
||||
int num_fec_packets);
|
||||
|
||||
private:
|
||||
static const uint8_t* PickTable(FecMaskType fec_mask_type,
|
||||
int num_media_packets);
|
||||
const uint8_t* table_;
|
||||
uint8_t fec_packet_mask_[kFECPacketMaskMaxSize];
|
||||
};
|
||||
|
||||
rtc::ArrayView<const uint8_t> LookUpInFecTable(const uint8_t* table,
|
||||
@ -70,9 +74,11 @@ rtc::ArrayView<const uint8_t> LookUpInFecTable(const uint8_t* table,
|
||||
// \param[out] packet_mask A pointer to hold the packet mask array,
|
||||
// of size: num_fec_packets *
|
||||
// "number of mask bytes".
|
||||
void GeneratePacketMasks(int num_media_packets, int num_fec_packets,
|
||||
int num_imp_packets, bool use_unequal_protection,
|
||||
const PacketMaskTable& mask_table,
|
||||
void GeneratePacketMasks(int num_media_packets,
|
||||
int num_fec_packets,
|
||||
int num_imp_packets,
|
||||
bool use_unequal_protection,
|
||||
PacketMaskTable* mask_table,
|
||||
uint8_t* packet_mask);
|
||||
|
||||
// Returns the required packet mask size, given the number of sequence numbers
|
||||
|
||||
@ -192,10 +192,9 @@ void RunTest(bool use_flexfec) {
|
||||
num_media_packets * mask_bytes_per_fec_packet);
|
||||
|
||||
// Transfer packet masks from bit-mask to byte-mask.
|
||||
internal::GeneratePacketMasks(num_media_packets, num_fec_packets,
|
||||
num_imp_packets,
|
||||
kUseUnequalProtection,
|
||||
mask_table, packet_mask.get());
|
||||
internal::GeneratePacketMasks(
|
||||
num_media_packets, num_fec_packets, num_imp_packets,
|
||||
kUseUnequalProtection, &mask_table, packet_mask.get());
|
||||
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf(
|
||||
|
||||
@ -741,7 +741,7 @@ class FecPacketMaskMetricsTest : public ::testing::Test {
|
||||
num_fec_packets++) {
|
||||
memset(packet_mask.get(), 0, num_media_packets * mask_bytes_fec_packet);
|
||||
rtc::ArrayView<const uint8_t> mask =
|
||||
mask_table.LookUp(num_media_packets - 1, num_fec_packets - 1);
|
||||
mask_table.LookUp(num_media_packets, num_fec_packets);
|
||||
memcpy(packet_mask.get(), &mask[0], mask.size());
|
||||
// Convert to bit mask.
|
||||
GetPacketMaskConvertToBitMask(packet_mask.get(), num_media_packets,
|
||||
|
||||
Reference in New Issue
Block a user