FEC: Added another set of packet masks for the FEC.
These FEC codes perform better for bursty (consecutive loss) than the existing set (which were designed for random loss). Updates to the unittests and test_fec accordingly. Review URL: https://webrtc-codereview.appspot.com/581005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2369 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
20e13edede
commit
8866bb1132
761
src/modules/rtp_rtcp/source/fec_private_tables_bursty.h
Normal file
761
src/modules/rtp_rtcp/source/fec_private_tables_bursty.h
Normal file
@ -0,0 +1,761 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_BURSTY_H_
|
||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_BURSTY_H_
|
||||
|
||||
// This file contains a set of packets masks for the FEC code. The masks in
|
||||
// this table are specifically designed to favor recovery of bursty/consecutive
|
||||
// loss network conditions. The tradeoff is worse recovery for random losses.
|
||||
// These packet masks are currently defined to protect up to 12 media packets.
|
||||
// They have the following property: for any packet mask defined by the
|
||||
// parameters (k,m), where k = number of media packets, m = number of FEC
|
||||
// packets, all "consecutive" losses of size <= m are completely recoverable.
|
||||
// By consecutive losses we mean consecutive with respect to the sequence
|
||||
// number ordering of the list (media and FEC) of packets. The difference
|
||||
// between these masks (|kFecMaskBursty|) and |kFecMaskRandom| type, defined
|
||||
// in fec_private_tables.h, is more significant for longer codes
|
||||
// (i.e., more packets/symbols in the code, so larger (k,m), i.e., k > 4,
|
||||
// m > 3).
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const uint8_t kMaskBursty1_1[2] = {
|
||||
0x80, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty2_1[2] = {
|
||||
0xc0, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty2_2[4] = {
|
||||
0x80, 0x00,
|
||||
0xc0, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty3_1[2] = {
|
||||
0xe0, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty3_2[4] = {
|
||||
0xc0, 0x00,
|
||||
0xa0, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty3_3[6] = {
|
||||
0x80, 0x00,
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty4_1[2] = {
|
||||
0xf0, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty4_2[4] = {
|
||||
0xa0, 0x00,
|
||||
0xd0, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty4_3[6] = {
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x90, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty4_4[8] = {
|
||||
0x80, 0x00,
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty5_1[2] = {
|
||||
0xf8, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty5_2[4] = {
|
||||
0xd0, 0x00,
|
||||
0xa8, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty5_3[6] = {
|
||||
0x70, 0x00,
|
||||
0x90, 0x00,
|
||||
0xc8, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty5_4[8] = {
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x88, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty5_5[10] = {
|
||||
0x80, 0x00,
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty6_1[2] = {
|
||||
0xfc, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty6_2[4] = {
|
||||
0xa8, 0x00,
|
||||
0xd4, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty6_3[6] = {
|
||||
0x94, 0x00,
|
||||
0xc8, 0x00,
|
||||
0x64, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty6_4[8] = {
|
||||
0x60, 0x00,
|
||||
0x38, 0x00,
|
||||
0x88, 0x00,
|
||||
0xc4, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty6_5[10] = {
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x84, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty6_6[12] = {
|
||||
0x80, 0x00,
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty7_1[2] = {
|
||||
0xfe, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty7_2[4] = {
|
||||
0xd4, 0x00,
|
||||
0xaa, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty7_3[6] = {
|
||||
0xc8, 0x00,
|
||||
0x74, 0x00,
|
||||
0x92, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty7_4[8] = {
|
||||
0x38, 0x00,
|
||||
0x8a, 0x00,
|
||||
0xc4, 0x00,
|
||||
0x62, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty7_5[10] = {
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x1c, 0x00,
|
||||
0x84, 0x00,
|
||||
0xc2, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty7_6[12] = {
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x82, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty7_7[14] = {
|
||||
0x80, 0x00,
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty8_1[2] = {
|
||||
0xff, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty8_2[4] = {
|
||||
0xaa, 0x00,
|
||||
0xd5, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty8_3[6] = {
|
||||
0x74, 0x00,
|
||||
0x92, 0x00,
|
||||
0xc9, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty8_4[8] = {
|
||||
0x8a, 0x00,
|
||||
0xc5, 0x00,
|
||||
0x62, 0x00,
|
||||
0x31, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty8_5[10] = {
|
||||
0x30, 0x00,
|
||||
0x1c, 0x00,
|
||||
0x85, 0x00,
|
||||
0xc2, 0x00,
|
||||
0x61, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty8_6[12] = {
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0e, 0x00,
|
||||
0x82, 0x00,
|
||||
0xc1, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty8_7[14] = {
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x81, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty8_8[16] = {
|
||||
0x80, 0x00,
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty9_1[2] = {
|
||||
0xff, 0x80
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty9_2[4] = {
|
||||
0xd5, 0x00,
|
||||
0xaa, 0x80
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty9_3[6] = {
|
||||
0x92, 0x00,
|
||||
0xc9, 0x00,
|
||||
0x74, 0x80
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty9_4[8] = {
|
||||
0xc5, 0x00,
|
||||
0x62, 0x00,
|
||||
0x39, 0x00,
|
||||
0x8a, 0x80
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty9_5[10] = {
|
||||
0x1c, 0x00,
|
||||
0x85, 0x00,
|
||||
0xc2, 0x80,
|
||||
0x61, 0x00,
|
||||
0x30, 0x80
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty9_6[12] = {
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0e, 0x00,
|
||||
0x82, 0x80,
|
||||
0xc1, 0x00,
|
||||
0x60, 0x80
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty9_7[14] = {
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x07, 0x00,
|
||||
0x81, 0x00,
|
||||
0xc0, 0x80
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty9_8[16] = {
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x80, 0x80
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty9_9[18] = {
|
||||
0x80, 0x00,
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x01, 0x80
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty10_1[2] = {
|
||||
0xff, 0xc0
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty10_2[4] = {
|
||||
0xaa, 0x80,
|
||||
0xd5, 0x40
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty10_3[6] = {
|
||||
0xc9, 0x00,
|
||||
0x74, 0x80,
|
||||
0x92, 0x40
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty10_4[8] = {
|
||||
0x62, 0x00,
|
||||
0x39, 0x00,
|
||||
0x8a, 0x80,
|
||||
0xc5, 0x40
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty10_5[10] = {
|
||||
0x85, 0x00,
|
||||
0xc2, 0x80,
|
||||
0x61, 0x40,
|
||||
0x30, 0x80,
|
||||
0x18, 0x40
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty10_6[12] = {
|
||||
0x18, 0x00,
|
||||
0x0e, 0x00,
|
||||
0x82, 0x80,
|
||||
0xc1, 0x40,
|
||||
0x60, 0x80,
|
||||
0x30, 0x40
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty10_7[14] = {
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x07, 0x00,
|
||||
0x81, 0x40,
|
||||
0xc0, 0x80,
|
||||
0x60, 0x40
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty10_8[16] = {
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x80, 0x80,
|
||||
0xc0, 0x40
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty10_9[18] = {
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x01, 0x80,
|
||||
0x80, 0x40
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty10_10[20] = {
|
||||
0x80, 0x00,
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x01, 0x80,
|
||||
0x00, 0xc0
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty11_1[2] = {
|
||||
0xff, 0xe0
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty11_2[4] = {
|
||||
0xd5, 0x40,
|
||||
0xaa, 0xa0
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty11_3[6] = {
|
||||
0x74, 0x80,
|
||||
0x92, 0x40,
|
||||
0xc9, 0x20
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty11_4[8] = {
|
||||
0x39, 0x00,
|
||||
0x8a, 0x80,
|
||||
0xc5, 0x40,
|
||||
0x62, 0x20
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty11_5[10] = {
|
||||
0xc2, 0xc0,
|
||||
0x61, 0x00,
|
||||
0x30, 0xa0,
|
||||
0x1c, 0x40,
|
||||
0x85, 0x20
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty11_6[12] = {
|
||||
0x0e, 0x00,
|
||||
0x82, 0x80,
|
||||
0xc1, 0x40,
|
||||
0x60, 0xa0,
|
||||
0x30, 0x40,
|
||||
0x18, 0x20
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty11_7[14] = {
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x07, 0x00,
|
||||
0x81, 0x40,
|
||||
0xc0, 0xa0,
|
||||
0x60, 0x40,
|
||||
0x30, 0x20
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty11_8[16] = {
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x40,
|
||||
0x80, 0xa0,
|
||||
0xc0, 0x40,
|
||||
0x60, 0x20
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty11_9[18] = {
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x01, 0x80,
|
||||
0x80, 0x40,
|
||||
0xc0, 0x20
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty11_10[20] = {
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x01, 0x80,
|
||||
0x00, 0xc0,
|
||||
0x80, 0x20
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty11_11[22] = {
|
||||
0x80, 0x00,
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x01, 0x80,
|
||||
0x00, 0xc0,
|
||||
0x00, 0x60
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_1[2] = {
|
||||
0xff, 0xf0
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_2[4] = {
|
||||
0xaa, 0xa0,
|
||||
0xd5, 0x50
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_3[6] = {
|
||||
0x92, 0x40,
|
||||
0xc9, 0x20,
|
||||
0x74, 0x90
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_4[8] = {
|
||||
0x8a, 0x80,
|
||||
0xc5, 0x40,
|
||||
0x62, 0x20,
|
||||
0x39, 0x10
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_5[10] = {
|
||||
0x61, 0x00,
|
||||
0x30, 0xa0,
|
||||
0x1c, 0x50,
|
||||
0x85, 0x20,
|
||||
0xc2, 0x90
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_6[12] = {
|
||||
0x82, 0x90,
|
||||
0xc1, 0x40,
|
||||
0x60, 0xa0,
|
||||
0x30, 0x50,
|
||||
0x18, 0x20,
|
||||
0x0c, 0x10
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_7[14] = {
|
||||
0x0c, 0x00,
|
||||
0x07, 0x00,
|
||||
0x81, 0x40,
|
||||
0xc0, 0xa0,
|
||||
0x60, 0x50,
|
||||
0x30, 0x20,
|
||||
0x18, 0x10
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_8[16] = {
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x80, 0xa0,
|
||||
0xc0, 0x50,
|
||||
0x60, 0x20,
|
||||
0x30, 0x10
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_9[18] = {
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x01, 0x80,
|
||||
0x80, 0x50,
|
||||
0xc0, 0x20,
|
||||
0x60, 0x10
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_10[20] = {
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x01, 0x80,
|
||||
0x00, 0xc0,
|
||||
0x80, 0x20,
|
||||
0xc0, 0x10
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_11[22] = {
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x01, 0x80,
|
||||
0x00, 0xc0,
|
||||
0x00, 0x60,
|
||||
0x80, 0x10
|
||||
};
|
||||
|
||||
const uint8_t kMaskBursty12_12[24] = {
|
||||
0x80, 0x00,
|
||||
0xc0, 0x00,
|
||||
0x60, 0x00,
|
||||
0x30, 0x00,
|
||||
0x18, 0x00,
|
||||
0x0c, 0x00,
|
||||
0x06, 0x00,
|
||||
0x03, 0x00,
|
||||
0x01, 0x80,
|
||||
0x00, 0xc0,
|
||||
0x00, 0x60,
|
||||
0x00, 0x30
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty1[1] = {
|
||||
kMaskBursty1_1
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty2[2] = {
|
||||
kMaskBursty2_1,
|
||||
kMaskBursty2_2
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty3[3] = {
|
||||
kMaskBursty3_1,
|
||||
kMaskBursty3_2,
|
||||
kMaskBursty3_3
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty4[4] = {
|
||||
kMaskBursty4_1,
|
||||
kMaskBursty4_2,
|
||||
kMaskBursty4_3,
|
||||
kMaskBursty4_4
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty5[5] = {
|
||||
kMaskBursty5_1,
|
||||
kMaskBursty5_2,
|
||||
kMaskBursty5_3,
|
||||
kMaskBursty5_4,
|
||||
kMaskBursty5_5
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty6[6] = {
|
||||
kMaskBursty6_1,
|
||||
kMaskBursty6_2,
|
||||
kMaskBursty6_3,
|
||||
kMaskBursty6_4,
|
||||
kMaskBursty6_5,
|
||||
kMaskBursty6_6
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty7[7] = {
|
||||
kMaskBursty7_1,
|
||||
kMaskBursty7_2,
|
||||
kMaskBursty7_3,
|
||||
kMaskBursty7_4,
|
||||
kMaskBursty7_5,
|
||||
kMaskBursty7_6,
|
||||
kMaskBursty7_7
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty8[8] = {
|
||||
kMaskBursty8_1,
|
||||
kMaskBursty8_2,
|
||||
kMaskBursty8_3,
|
||||
kMaskBursty8_4,
|
||||
kMaskBursty8_5,
|
||||
kMaskBursty8_6,
|
||||
kMaskBursty8_7,
|
||||
kMaskBursty8_8
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty9[9] = {
|
||||
kMaskBursty9_1,
|
||||
kMaskBursty9_2,
|
||||
kMaskBursty9_3,
|
||||
kMaskBursty9_4,
|
||||
kMaskBursty9_5,
|
||||
kMaskBursty9_6,
|
||||
kMaskBursty9_7,
|
||||
kMaskBursty9_8,
|
||||
kMaskBursty9_9
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty10[10] = {
|
||||
kMaskBursty10_1,
|
||||
kMaskBursty10_2,
|
||||
kMaskBursty10_3,
|
||||
kMaskBursty10_4,
|
||||
kMaskBursty10_5,
|
||||
kMaskBursty10_6,
|
||||
kMaskBursty10_7,
|
||||
kMaskBursty10_8,
|
||||
kMaskBursty10_9,
|
||||
kMaskBursty10_10
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty11[11] = {
|
||||
kMaskBursty11_1,
|
||||
kMaskBursty11_2,
|
||||
kMaskBursty11_3,
|
||||
kMaskBursty11_4,
|
||||
kMaskBursty11_5,
|
||||
kMaskBursty11_6,
|
||||
kMaskBursty11_7,
|
||||
kMaskBursty11_8,
|
||||
kMaskBursty11_9,
|
||||
kMaskBursty11_10,
|
||||
kMaskBursty11_11
|
||||
};
|
||||
|
||||
const uint8_t* kPacketMaskBursty12[12] = {
|
||||
kMaskBursty12_1,
|
||||
kMaskBursty12_2,
|
||||
kMaskBursty12_3,
|
||||
kMaskBursty12_4,
|
||||
kMaskBursty12_5,
|
||||
kMaskBursty12_6,
|
||||
kMaskBursty12_7,
|
||||
kMaskBursty12_8,
|
||||
kMaskBursty12_9,
|
||||
kMaskBursty12_10,
|
||||
kMaskBursty12_11,
|
||||
kMaskBursty12_12
|
||||
};
|
||||
|
||||
const uint8_t** kPacketMaskBurstyTbl[12] = {
|
||||
kPacketMaskBursty1,
|
||||
kPacketMaskBursty2,
|
||||
kPacketMaskBursty3,
|
||||
kPacketMaskBursty4,
|
||||
kPacketMaskBursty5,
|
||||
kPacketMaskBursty6,
|
||||
kPacketMaskBursty7,
|
||||
kPacketMaskBursty8,
|
||||
kPacketMaskBursty9,
|
||||
kPacketMaskBursty10,
|
||||
kPacketMaskBursty11,
|
||||
kPacketMaskBursty12
|
||||
};
|
||||
|
||||
} // namespace
|
||||
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_FEC_PRIVATE_TABLES_BURSTY_H_
|
||||
|
@ -97,6 +97,7 @@ int32_t ForwardErrorCorrection::GenerateFEC(
|
||||
uint8_t protectionFactor,
|
||||
int numImportantPackets,
|
||||
bool useUnequalProtection,
|
||||
FecMaskType fec_mask_type,
|
||||
PacketList* fecPacketList) {
|
||||
if (mediaPacketList.empty()) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
|
||||
@ -171,13 +172,15 @@ int32_t ForwardErrorCorrection::GenerateFEC(
|
||||
fecPacketList->push_back(&_generatedFecPackets[i]);
|
||||
}
|
||||
|
||||
const internal::PacketMaskTable mask_table(fec_mask_type, numMediaPackets);
|
||||
|
||||
// -- Generate packet masks --
|
||||
// Always allocate space for a large mask.
|
||||
uint8_t* packetMask = new uint8_t[numFecPackets * kMaskSizeLBitSet];
|
||||
memset(packetMask, 0, numFecPackets * numMaskBytes);
|
||||
internal::GeneratePacketMasks(numMediaPackets, numFecPackets,
|
||||
numImportantPackets, useUnequalProtection,
|
||||
packetMask);
|
||||
mask_table, packetMask);
|
||||
|
||||
int numMaskBits = InsertZerosInBitMasks(mediaPacketList, packetMask,
|
||||
numMaskBytes, numFecPackets);
|
||||
@ -199,8 +202,8 @@ int32_t ForwardErrorCorrection::GenerateFEC(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ForwardErrorCorrection::GetNumberOfFecPackets(uint16_t numMediaPackets,
|
||||
uint8_t protectionFactor) {
|
||||
int ForwardErrorCorrection::GetNumberOfFecPackets(int numMediaPackets,
|
||||
int protectionFactor) {
|
||||
// Result in Q0 with an unsigned round.
|
||||
int numFecPackets = (numMediaPackets * protectionFactor + (1 << 7)) >> 8;
|
||||
// Generate at least one FEC packet if we need protection.
|
||||
|
@ -21,6 +21,16 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Types for the FEC packet masks.
|
||||
// The type |kFecMaskRandom| selects the mask defined in fec_private_tables.h,
|
||||
// and is based on a random loss model. The type |kFecMaskBursty| selects the
|
||||
// mask defined in fec_private_tables_bursty.h, and is based on a bursty loss
|
||||
// model. Please refer to those files for a more detailed description.
|
||||
enum FecMaskType {
|
||||
kFecMaskRandom,
|
||||
kFecMaskBursty,
|
||||
};
|
||||
|
||||
// Forward declaration.
|
||||
class FecPacket;
|
||||
|
||||
@ -155,6 +165,12 @@ class ForwardErrorCorrection {
|
||||
* UEP will allocate more protection to the
|
||||
* numImportantPackets from the start of the
|
||||
* mediaPacketList.
|
||||
* \param[in] fec_mask_type The type of packet mask used in the FEC.
|
||||
* Random or bursty type may be selected. The
|
||||
* bursty type is only defined up to 12 media
|
||||
* packets. If the number of media packets is
|
||||
* above 12, the packets masks from the
|
||||
* random table will be selected.
|
||||
* \param[out] fecPacketList List of FEC packets, of type #Packet. Must
|
||||
* be empty on entry. The memory available
|
||||
* through the list will be valid until the
|
||||
@ -166,6 +182,7 @@ class ForwardErrorCorrection {
|
||||
uint8_t protectionFactor,
|
||||
int numImportantPackets,
|
||||
bool useUnequalProtection,
|
||||
FecMaskType fec_mask_type,
|
||||
PacketList* fecPacketList);
|
||||
|
||||
/**
|
||||
@ -201,8 +218,8 @@ class ForwardErrorCorrection {
|
||||
|
||||
// Get the number of FEC packets, given the number of media packets and the
|
||||
// protection factor.
|
||||
int GetNumberOfFecPackets(uint16_t numMediaPackets,
|
||||
uint8_t protectionFactor);
|
||||
int GetNumberOfFecPackets(int numMediaPackets,
|
||||
int protectionFactor);
|
||||
|
||||
/**
|
||||
* Gets the size in bytes of the FEC/ULP headers, which must be accounted for
|
||||
|
@ -8,12 +8,14 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "forward_error_correction_internal.h"
|
||||
#include "fec_private_tables.h"
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "modules/rtp_rtcp/source/fec_private_tables.h"
|
||||
#include "modules/rtp_rtcp/source/fec_private_tables_bursty.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Allow for different modes of protection for packets in UEP case.
|
||||
@ -149,19 +151,69 @@ void ShiftFitSubMask(int numMaskBytes,
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace
|
||||
} // namespace
|
||||
|
||||
namespace webrtc {
|
||||
namespace internal {
|
||||
|
||||
PacketMaskTable::PacketMaskTable(FecMaskType fec_mask_type,
|
||||
int num_media_packets)
|
||||
: fec_mask_type_(InitMaskType(fec_mask_type, num_media_packets)),
|
||||
fec_packet_mask_table_(InitMaskTable(fec_mask_type_)) {
|
||||
}
|
||||
|
||||
// Sets |fec_mask_type_| to the type of packet mask selected. The type of
|
||||
// packet mask selected is based on |fec_mask_type| and |numMediaPackets|.
|
||||
// If |numMediaPackets| is larger than the maximum allowed by |fec_mask_type|
|
||||
// for the bursty type, then the random type is selected.
|
||||
FecMaskType PacketMaskTable::InitMaskType(FecMaskType fec_mask_type,
|
||||
int num_media_packets) {
|
||||
// The mask should not be bigger than |packetMaskTbl|.
|
||||
assert(num_media_packets <= static_cast<int>(sizeof(packetMaskTbl) /
|
||||
sizeof(*packetMaskTbl)));
|
||||
switch (fec_mask_type) {
|
||||
case kFecMaskRandom: {
|
||||
// TODO(marpan): in separate CL rename the fec_private_tables.h file and
|
||||
// its packet masks to indicate "random" loss case.
|
||||
return kFecMaskRandom;
|
||||
}
|
||||
case kFecMaskBursty: {
|
||||
int max_media_packets = static_cast<int>(sizeof(kPacketMaskBurstyTbl) /
|
||||
sizeof(*kPacketMaskBurstyTbl));
|
||||
if (num_media_packets > max_media_packets) {
|
||||
return kFecMaskRandom;
|
||||
} else {
|
||||
return kFecMaskBursty;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return kFecMaskRandom;
|
||||
}
|
||||
|
||||
// Returns the pointer to the packet mask tables corresponding to type
|
||||
// |fec_mask_type|.
|
||||
const uint8_t*** PacketMaskTable::InitMaskTable(FecMaskType fec_mask_type) {
|
||||
switch (fec_mask_type) {
|
||||
case kFecMaskRandom: {
|
||||
return packetMaskTbl;
|
||||
}
|
||||
case kFecMaskBursty: {
|
||||
return kPacketMaskBurstyTbl;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return packetMaskTbl;
|
||||
}
|
||||
|
||||
// Remaining protection after important (first partition) packet protection
|
||||
void RemainingPacketProtection(int numMediaPackets,
|
||||
int numFecRemaining,
|
||||
int numFecForImpPackets,
|
||||
int numMaskBytes,
|
||||
ProtectionMode mode,
|
||||
uint8_t* packetMask)
|
||||
uint8_t* packetMask,
|
||||
const PacketMaskTable& mask_table)
|
||||
{
|
||||
if (mode == kModeNoOverlap)
|
||||
{
|
||||
@ -174,8 +226,9 @@ void RemainingPacketProtection(int numMediaPackets,
|
||||
(lBit == 1) ? kMaskSizeLBitSet : kMaskSizeLBitClear;
|
||||
|
||||
const uint8_t* packetMaskSub21 =
|
||||
packetMaskTbl[numMediaPackets - numFecForImpPackets - 1]
|
||||
[numFecRemaining - 1];
|
||||
mask_table.fec_packet_mask_table()
|
||||
[numMediaPackets - numFecForImpPackets - 1]
|
||||
[numFecRemaining - 1];
|
||||
|
||||
ShiftFitSubMask(numMaskBytes, resMaskBytes, numFecForImpPackets,
|
||||
(numFecForImpPackets + numFecRemaining),
|
||||
@ -187,7 +240,8 @@ void RemainingPacketProtection(int numMediaPackets,
|
||||
// subMask22
|
||||
|
||||
const uint8_t* packetMaskSub22 =
|
||||
packetMaskTbl[numMediaPackets - 1][numFecRemaining - 1];
|
||||
mask_table.fec_packet_mask_table()
|
||||
[numMediaPackets - 1][numFecRemaining - 1];
|
||||
|
||||
FitSubMask(numMaskBytes, numMaskBytes, numFecRemaining, packetMaskSub22,
|
||||
&packetMask[numFecForImpPackets * numMaskBytes]);
|
||||
@ -212,7 +266,8 @@ void RemainingPacketProtection(int numMediaPackets,
|
||||
void ImportantPacketProtection(int numFecForImpPackets,
|
||||
int numImpPackets,
|
||||
int numMaskBytes,
|
||||
uint8_t* packetMask)
|
||||
uint8_t* packetMask,
|
||||
const PacketMaskTable& mask_table)
|
||||
{
|
||||
const int lBit = numImpPackets > 16 ? 1 : 0;
|
||||
const int numImpMaskBytes =
|
||||
@ -220,7 +275,8 @@ void ImportantPacketProtection(int numFecForImpPackets,
|
||||
|
||||
// Get subMask1 from table
|
||||
const uint8_t* packetMaskSub1 =
|
||||
packetMaskTbl[numImpPackets - 1][numFecForImpPackets - 1];
|
||||
mask_table.fec_packet_mask_table()
|
||||
[numImpPackets - 1][numFecForImpPackets - 1];
|
||||
|
||||
FitSubMask(numMaskBytes, numImpMaskBytes,
|
||||
numFecForImpPackets, packetMaskSub1, packetMask);
|
||||
@ -302,7 +358,8 @@ void UnequalProtectionMask(int numMediaPackets,
|
||||
int numFecPackets,
|
||||
int numImpPackets,
|
||||
int numMaskBytes,
|
||||
uint8_t* packetMask)
|
||||
uint8_t* packetMask,
|
||||
const PacketMaskTable& mask_table)
|
||||
{
|
||||
|
||||
// Set Protection type and allocation
|
||||
@ -327,7 +384,8 @@ void UnequalProtectionMask(int numMediaPackets,
|
||||
if (numFecForImpPackets > 0)
|
||||
{
|
||||
ImportantPacketProtection(numFecForImpPackets, numImpPackets,
|
||||
numMaskBytes, packetMask);
|
||||
numMaskBytes, packetMask,
|
||||
mask_table);
|
||||
}
|
||||
|
||||
//
|
||||
@ -337,7 +395,7 @@ void UnequalProtectionMask(int numMediaPackets,
|
||||
{
|
||||
RemainingPacketProtection(numMediaPackets, numFecRemaining,
|
||||
numFecForImpPackets, numMaskBytes,
|
||||
mode, packetMask);
|
||||
mode, packetMask, mask_table);
|
||||
}
|
||||
|
||||
}
|
||||
@ -346,10 +404,9 @@ void GeneratePacketMasks(int numMediaPackets,
|
||||
int numFecPackets,
|
||||
int numImpPackets,
|
||||
bool useUnequalProtection,
|
||||
const PacketMaskTable& mask_table,
|
||||
uint8_t* packetMask)
|
||||
{
|
||||
assert(numMediaPackets <= static_cast<int>(sizeof(packetMaskTbl) /
|
||||
sizeof(*packetMaskTbl)));
|
||||
assert(numMediaPackets > 0);
|
||||
assert(numFecPackets <= numMediaPackets && numFecPackets > 0);
|
||||
assert(numImpPackets <= numMediaPackets && numImpPackets >= 0);
|
||||
@ -365,16 +422,16 @@ void GeneratePacketMasks(int numMediaPackets,
|
||||
// Mask = (k,n-k), with protection factor = (n-k)/k,
|
||||
// where k = numMediaPackets, n=total#packets, (n-k)=numFecPackets.
|
||||
memcpy(packetMask,
|
||||
packetMaskTbl[numMediaPackets - 1][numFecPackets - 1],
|
||||
mask_table.fec_packet_mask_table()[numMediaPackets - 1]
|
||||
[numFecPackets - 1],
|
||||
numFecPackets * numMaskBytes);
|
||||
}
|
||||
else //UEP case
|
||||
{
|
||||
UnequalProtectionMask(numMediaPackets, numFecPackets, numImpPackets,
|
||||
numMaskBytes, packetMask);
|
||||
numMaskBytes, packetMask, mask_table);
|
||||
|
||||
} // End of UEP modification
|
||||
|
||||
} //End of GetPacketMasks
|
||||
|
||||
} // namespace internal
|
||||
|
@ -8,6 +8,7 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -19,6 +20,23 @@ static const int kMaskSizeLBitClear = 2;
|
||||
|
||||
namespace internal {
|
||||
|
||||
class PacketMaskTable {
|
||||
public:
|
||||
PacketMaskTable(FecMaskType fec_mask_type, int num_media_packets);
|
||||
~PacketMaskTable() {
|
||||
}
|
||||
FecMaskType fec_mask_type() const { return fec_mask_type_; }
|
||||
const uint8_t*** fec_packet_mask_table() const {
|
||||
return fec_packet_mask_table_;
|
||||
}
|
||||
private:
|
||||
FecMaskType InitMaskType(FecMaskType fec_mask_type,
|
||||
int num_media_packets);
|
||||
const uint8_t*** InitMaskTable(FecMaskType fec_mask_type_);
|
||||
const FecMaskType fec_mask_type_;
|
||||
const uint8_t*** fec_packet_mask_table_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array of packet masks. The mask of a single FEC packet
|
||||
* corresponds to a number of mask bytes. The mask indicates which
|
||||
@ -34,6 +52,10 @@ namespace internal {
|
||||
* protection scenario.
|
||||
* \param[in] useUnequalProtection Enables unequal protection: allocates
|
||||
* more protection to the numImpPackets.
|
||||
* \param[in] mask_table An instance of the |PacketMaskTable|
|
||||
* class, which contains the type of FEC
|
||||
* packet mask used, and a pointer to the
|
||||
* corresponding packet masks.
|
||||
* \param[out] packetMask A pointer to hold the packet mask array,
|
||||
* of size:
|
||||
* numFecPackets * "number of mask bytes".
|
||||
@ -42,6 +64,7 @@ void GeneratePacketMasks(int numMediaPackets,
|
||||
int numFecPackets,
|
||||
int numImpPackets,
|
||||
bool useUnequalProtection,
|
||||
const PacketMaskTable& mask_table,
|
||||
uint8_t* packetMask);
|
||||
|
||||
} // namespace internal
|
||||
|
@ -164,10 +164,14 @@ int ProducerFec::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
|
||||
(ExcessOverheadBelowMax() && MinimumMediaPacketsReached()))) {
|
||||
assert(num_first_partition_ <=
|
||||
static_cast<int>(ForwardErrorCorrection::kMaxMediaPackets));
|
||||
// TODO(marpan): The setting of the mask type (|kFecMaskRandom| or
|
||||
// |kFecMaskBursty|) should be part of FecProtectionParams and passed
|
||||
// in from the VCM.
|
||||
int ret = fec_->GenerateFEC(media_packets_fec_,
|
||||
params_.fec_rate,
|
||||
num_first_partition_,
|
||||
params_.use_uep_protection,
|
||||
kFecMaskBursty,
|
||||
&fec_packets_);
|
||||
if (fec_packets_.empty()) {
|
||||
num_frames_ = 0;
|
||||
|
@ -47,6 +47,7 @@ class ReceiverFecTest : public ::testing::Test {
|
||||
num_fec_packets * 255 / media_packets->size(),
|
||||
0,
|
||||
false,
|
||||
kFecMaskBursty,
|
||||
fec_packets));
|
||||
ASSERT_EQ(num_fec_packets, fec_packets->size());
|
||||
}
|
||||
@ -246,6 +247,7 @@ TEST_F(ReceiverFecTest, TooManyFrames) {
|
||||
kNumFecPackets * 255 / kNumMediaPackets,
|
||||
0,
|
||||
false,
|
||||
kFecMaskBursty,
|
||||
&fec_packets));
|
||||
|
||||
DeletePackets(&media_packets);
|
||||
|
@ -93,61 +93,68 @@ class RtpFecTest : public ::testing::Test {
|
||||
void TearDown();
|
||||
};
|
||||
|
||||
// TODO(marpan): Consider adding table for input/output to simplify tests.
|
||||
|
||||
TEST_F(RtpFecTest, HandleIncorrectInputs) {
|
||||
int num_important_packets = 0;
|
||||
bool use_unequal_protection = false;
|
||||
uint8_t protection_factor = 60;
|
||||
int kNumImportantPackets = 0;
|
||||
bool kUseUnequalProtection = false;
|
||||
uint8_t kProtectionFactor = 60;
|
||||
|
||||
// Media packet list is empty.
|
||||
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
|
||||
int num_media_packets = 10;
|
||||
ConstructMediaPackets(num_media_packets);
|
||||
|
||||
num_important_packets = -1;
|
||||
kNumImportantPackets = -1;
|
||||
// Number of important packets below 0.
|
||||
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
|
||||
num_important_packets = 12;
|
||||
kNumImportantPackets = 12;
|
||||
// Number of important packets greater than number of media packets.
|
||||
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
|
||||
num_media_packets = kMaxNumberMediaPackets + 1;
|
||||
ConstructMediaPackets(num_media_packets);
|
||||
|
||||
num_important_packets = 0;
|
||||
kNumImportantPackets = 0;
|
||||
// Number of media packet is above maximum allowed (kMaxNumberMediaPackets).
|
||||
EXPECT_EQ(-1, fec_->GenerateFEC(media_packet_list_,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
}
|
||||
|
||||
TEST_F(RtpFecTest, FecRecoveryNoLoss) {
|
||||
const int num_important_packets = 0;
|
||||
const bool use_unequal_protection = false;
|
||||
const int num_media_packets = 4;
|
||||
uint8_t protection_factor = 60;
|
||||
const int kNumImportantPackets = 0;
|
||||
const bool kUseUnequalProtection = false;
|
||||
const int kNumMediaPackets = 4;
|
||||
uint8_t kProtectionFactor = 60;
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(num_media_packets);
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
|
||||
// Expect 1 FEC packet.
|
||||
@ -166,17 +173,18 @@ TEST_F(RtpFecTest, FecRecoveryNoLoss) {
|
||||
}
|
||||
|
||||
TEST_F(RtpFecTest, FecRecoveryWithLoss) {
|
||||
const int num_important_packets = 0;
|
||||
const bool use_unequal_protection = false;
|
||||
const int num_media_packets = 4;
|
||||
uint8_t protection_factor = 60;
|
||||
const int kNumImportantPackets = 0;
|
||||
const bool kUseUnequalProtection = false;
|
||||
const int kNumMediaPackets = 4;
|
||||
uint8_t kProtectionFactor = 60;
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(num_media_packets);
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
|
||||
// Expect 1 FEC packet.
|
||||
@ -209,59 +217,141 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss) {
|
||||
EXPECT_FALSE(IsRecoveryComplete());
|
||||
}
|
||||
|
||||
TEST_F(RtpFecTest, FecRecoveryWithLoss50perc) {
|
||||
const int num_important_packets = 0;
|
||||
const bool use_unequal_protection = false;
|
||||
const int num_media_packets = 4;
|
||||
const uint8_t protection_factor = 255;
|
||||
// Test 50% protection with random mask type: Two cases are considered:
|
||||
// a 50% non-consecutive loss which can be fully recovered, and a 50%
|
||||
// consecutive loss which cannot be fully recovered.
|
||||
TEST_F(RtpFecTest, FecRecoveryWithLoss50percRandomMask) {
|
||||
const int kNumImportantPackets = 0;
|
||||
const bool kUseUnequalProtection = false;
|
||||
const int kNumMediaPackets = 4;
|
||||
const uint8_t kProtectionFactor = 255;
|
||||
|
||||
// Packet Mask for (4,4,0) code:
|
||||
// (num_media_packets = 4; num_fec_packets = 4, num_important_packets = 0)
|
||||
// Packet Mask for (4,4,0) code, from random mask table.
|
||||
// (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
|
||||
|
||||
// media#0 media#1 media#2 media#3
|
||||
// fec#0: 1 1 0 0
|
||||
// fec#1: 1 0 1 0
|
||||
// fec#2: 0 1 0 1
|
||||
// fec#3: 0 0 1 1
|
||||
// fec#2: 0 0 1 1
|
||||
// fec#3: 0 1 0 1
|
||||
//
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(num_media_packets);
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskRandom,
|
||||
&fec_packet_list_));
|
||||
|
||||
// Expect 4 FEC packets.
|
||||
EXPECT_EQ(4, static_cast<int>(fec_packet_list_.size()));
|
||||
|
||||
// 4 packets lost: 3 media packets and one FEC packet#2 lost.
|
||||
// 4 packets lost: 3 media packets (0, 2, 3), and one FEC packet (0) lost.
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
fec_loss_mask_[2] = 1;
|
||||
fec_loss_mask_[0] = 1;
|
||||
media_loss_mask_[0] = 1;
|
||||
media_loss_mask_[2] = 1;
|
||||
media_loss_mask_[3] = 1;
|
||||
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// With media packet#1 and FEC packets #0, #1, #3, expect complete recovery.
|
||||
// With media packet#1 and FEC packets #1, #2, #3, expect complete recovery.
|
||||
EXPECT_TRUE(IsRecoveryComplete());
|
||||
FreeRecoveredPacketList();
|
||||
|
||||
// 4 packets lost: all media packets
|
||||
// 4 consecutive packets lost: media packets 0, 1, 2, 3.
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 1, sizeof(fec_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
media_loss_mask_[0] = 1;
|
||||
media_loss_mask_[1] = 1;
|
||||
media_loss_mask_[2] = 1;
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// Cannot get complete recovery for this loss configuration with random mask.
|
||||
EXPECT_FALSE(IsRecoveryComplete());
|
||||
}
|
||||
|
||||
// Test 50% protection with bursty type: Three cases are considered:
|
||||
// two 50% consecutive losses which can be fully recovered, and one
|
||||
// non-consecutive which cannot be fully recovered.
|
||||
TEST_F(RtpFecTest, FecRecoveryWithLoss50percBurstyMask) {
|
||||
const int kNumImportantPackets = 0;
|
||||
const bool kUseUnequalProtection = false;
|
||||
const int kNumMediaPackets = 4;
|
||||
const uint8_t kProtectionFactor = 255;
|
||||
|
||||
// Packet Mask for (4,4,0) code, from bursty mask table.
|
||||
// (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 0)
|
||||
|
||||
// media#0 media#1 media#2 media#3
|
||||
// fec#0: 1 0 0 0
|
||||
// fec#1: 1 1 0 0
|
||||
// fec#2: 0 1 1 0
|
||||
// fec#3: 0 0 1 1
|
||||
//
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
|
||||
// Expect 4 FEC packets.
|
||||
EXPECT_EQ(4, static_cast<int>(fec_packet_list_.size()));
|
||||
|
||||
// 4 consecutive packets lost: media packets 0,1,2,3.
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
media_loss_mask_[0] = 1;
|
||||
media_loss_mask_[1] = 1;
|
||||
media_loss_mask_[2] = 1;
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// Expect complete recovery for consecutive packet loss <= 50%.
|
||||
EXPECT_TRUE(IsRecoveryComplete());
|
||||
FreeRecoveredPacketList();
|
||||
|
||||
// 4 consecutive packets lost: media packets 1,2, 3, and FEC packet 0.
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
fec_loss_mask_[0] = 1;
|
||||
media_loss_mask_[1] = 1;
|
||||
media_loss_mask_[2] = 1;
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// Expect complete recovery for consecutive packet loss <= 50%.
|
||||
EXPECT_TRUE(IsRecoveryComplete());
|
||||
FreeRecoveredPacketList();
|
||||
|
||||
// 4 packets lost (non-consecutive loss): media packets 0, 3, and FEC# 0, 3.
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
fec_loss_mask_[0] = 1;
|
||||
fec_loss_mask_[3] = 1;
|
||||
media_loss_mask_[0] = 1;
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
|
||||
&recovered_packet_list_));
|
||||
|
||||
@ -270,17 +360,18 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50perc) {
|
||||
}
|
||||
|
||||
TEST_F(RtpFecTest, FecRecoveryNoLossUep) {
|
||||
const int num_important_packets = 2;
|
||||
const bool use_unequal_protection = true;
|
||||
const int num_media_packets = 4;
|
||||
const uint8_t protection_factor = 60;
|
||||
const int kNumImportantPackets = 2;
|
||||
const bool kUseUnequalProtection = true;
|
||||
const int kNumMediaPackets = 4;
|
||||
const uint8_t kProtectionFactor = 60;
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(num_media_packets);
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
|
||||
// Expect 1 FEC packet.
|
||||
@ -299,17 +390,18 @@ TEST_F(RtpFecTest, FecRecoveryNoLossUep) {
|
||||
}
|
||||
|
||||
TEST_F(RtpFecTest, FecRecoveryWithLossUep) {
|
||||
const int num_important_packets = 2;
|
||||
const bool use_unequal_protection = true;
|
||||
const int num_media_packets = 4;
|
||||
const uint8_t protection_factor = 60;
|
||||
const int kNumImportantPackets = 2;
|
||||
const bool kUseUnequalProtection = true;
|
||||
const int kNumMediaPackets = 4;
|
||||
const uint8_t kProtectionFactor = 60;
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(num_media_packets);
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
|
||||
// Expect 1 FEC packet.
|
||||
@ -342,14 +434,15 @@ TEST_F(RtpFecTest, FecRecoveryWithLossUep) {
|
||||
EXPECT_FALSE(IsRecoveryComplete());
|
||||
}
|
||||
|
||||
TEST_F(RtpFecTest, FecRecoveryWithLoss50percUep) {
|
||||
const int num_important_packets = 1;
|
||||
const bool use_unequal_protection = true;
|
||||
const int num_media_packets = 4;
|
||||
const uint8_t protection_factor = 255;
|
||||
// Test 50% protection with random mask type for UEP on.
|
||||
TEST_F(RtpFecTest, FecRecoveryWithLoss50percUepRandomMask) {
|
||||
const int kNumImportantPackets = 1;
|
||||
const bool kUseUnequalProtection = true;
|
||||
const int kNumMediaPackets = 4;
|
||||
const uint8_t kProtectionFactor = 255;
|
||||
|
||||
// Packet Mask for (4,4,1) code:
|
||||
// (num_media_packets = 4; num_fec_packets = 4, num_important_packets = 2)
|
||||
// Packet Mask for (4,4,1) code, from random mask table.
|
||||
// (kNumMediaPackets = 4; num_fec_packets = 4, kNumImportantPackets = 1)
|
||||
|
||||
// media#0 media#1 media#2 media#3
|
||||
// fec#0: 1 0 0 0
|
||||
@ -358,12 +451,13 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percUep) {
|
||||
// fec#3: 0 1 1 0
|
||||
//
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(num_media_packets);
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(media_packet_list_,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskRandom,
|
||||
&fec_packet_list_));
|
||||
|
||||
// Expect 4 FEC packets.
|
||||
@ -381,15 +475,16 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percUep) {
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
|
||||
&recovered_packet_list_));
|
||||
|
||||
// With media packet#1 and FEC packets #0, #2, #3, expect complete recovery.
|
||||
// With media packet#3 and FEC packets #0, #1, #3, expect complete recovery.
|
||||
EXPECT_TRUE(IsRecoveryComplete());
|
||||
FreeRecoveredPacketList();
|
||||
|
||||
// 4 packets lost: 3 media packets and one FEC packet#2 lost.
|
||||
// 5 packets lost: 4 media packets and one FEC packet#2 lost.
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
fec_loss_mask_[2] = 1;
|
||||
media_loss_mask_[0] = 1;
|
||||
media_loss_mask_[1] = 1;
|
||||
media_loss_mask_[2] = 1;
|
||||
media_loss_mask_[3] = 1;
|
||||
NetworkReceivedPackets();
|
||||
@ -402,12 +497,12 @@ TEST_F(RtpFecTest, FecRecoveryWithLoss50percUep) {
|
||||
}
|
||||
|
||||
TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
|
||||
const int num_important_packets = 0;
|
||||
const bool use_unequal_protection = false;
|
||||
const int num_media_packets = 5;
|
||||
uint8_t protection_factor = 60;
|
||||
const int kNumImportantPackets = 0;
|
||||
const bool kUseUnequalProtection = false;
|
||||
const int kNumMediaPackets = 5;
|
||||
uint8_t kProtectionFactor = 60;
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(num_media_packets);
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
// Create a new temporary packet list for generating FEC packets.
|
||||
// This list should have every other packet removed.
|
||||
@ -420,9 +515,10 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
|
||||
// Expect 1 FEC packet.
|
||||
@ -469,12 +565,12 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePackets) {
|
||||
}
|
||||
|
||||
TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
|
||||
const int num_important_packets = 0;
|
||||
const bool use_unequal_protection = false;
|
||||
const int num_media_packets = 21;
|
||||
uint8_t protection_factor = 127;
|
||||
const int kNumImportantPackets = 0;
|
||||
const bool kUseUnequalProtection = false;
|
||||
const int kNumMediaPackets = 21;
|
||||
uint8_t kProtectionFactor = 127;
|
||||
|
||||
fec_seq_num_ = ConstructMediaPackets(num_media_packets);
|
||||
fec_seq_num_ = ConstructMediaPackets(kNumMediaPackets);
|
||||
|
||||
// Create a new temporary packet list for generating FEC packets.
|
||||
// This list should have every other packet removed.
|
||||
@ -490,9 +586,10 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
|
||||
// mask since the number of actual packets are 21, while the number
|
||||
// of protected packets are 11.
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
|
||||
// Expect 5 FEC packet.
|
||||
@ -501,7 +598,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
|
||||
// Last protected media packet lost
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
media_loss_mask_[num_media_packets - 1] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 1] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
|
||||
@ -514,7 +611,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
|
||||
// Last unprotected packet lost.
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
media_loss_mask_[num_media_packets - 2] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 2] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
|
||||
@ -527,12 +624,12 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
|
||||
// 6 media packets lost.
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
media_loss_mask_[num_media_packets - 11] = 1;
|
||||
media_loss_mask_[num_media_packets - 9] = 1;
|
||||
media_loss_mask_[num_media_packets - 7] = 1;
|
||||
media_loss_mask_[num_media_packets - 5] = 1;
|
||||
media_loss_mask_[num_media_packets - 3] = 1;
|
||||
media_loss_mask_[num_media_packets - 1] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 11] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 9] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 7] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 5] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 3] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 1] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
|
||||
@ -543,12 +640,12 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsExtension) {
|
||||
}
|
||||
|
||||
TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
|
||||
const int num_important_packets = 0;
|
||||
const bool use_unequal_protection = false;
|
||||
const int num_media_packets = 21;
|
||||
uint8_t protection_factor = 127;
|
||||
const int kNumImportantPackets = 0;
|
||||
const bool kUseUnequalProtection = false;
|
||||
const int kNumMediaPackets = 21;
|
||||
uint8_t kProtectionFactor = 127;
|
||||
|
||||
fec_seq_num_ = ConstructMediaPacketsSeqNum(num_media_packets, 0xFFFF - 5);
|
||||
fec_seq_num_ = ConstructMediaPacketsSeqNum(kNumMediaPackets, 0xFFFF - 5);
|
||||
|
||||
// Create a new temporary packet list for generating FEC packets.
|
||||
// This list should have every other packet removed.
|
||||
@ -564,9 +661,10 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
|
||||
// mask since the number of actual packets are 21, while the number
|
||||
// of protected packets are 11.
|
||||
EXPECT_EQ(0, fec_->GenerateFEC(protected_media_packets,
|
||||
protection_factor,
|
||||
num_important_packets,
|
||||
use_unequal_protection,
|
||||
kProtectionFactor,
|
||||
kNumImportantPackets,
|
||||
kUseUnequalProtection,
|
||||
webrtc::kFecMaskBursty,
|
||||
&fec_packet_list_));
|
||||
|
||||
// Expect 5 FEC packet.
|
||||
@ -575,7 +673,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
|
||||
// Last protected media packet lost
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
media_loss_mask_[num_media_packets - 1] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 1] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
|
||||
@ -588,7 +686,7 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
|
||||
// Last unprotected packet lost.
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
media_loss_mask_[num_media_packets - 2] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 2] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
|
||||
@ -601,12 +699,12 @@ TEST_F(RtpFecTest, FecRecoveryNonConsecutivePacketsWrap) {
|
||||
// 6 media packets lost.
|
||||
memset(media_loss_mask_, 0, sizeof(media_loss_mask_));
|
||||
memset(fec_loss_mask_, 0, sizeof(fec_loss_mask_));
|
||||
media_loss_mask_[num_media_packets - 11] = 1;
|
||||
media_loss_mask_[num_media_packets - 9] = 1;
|
||||
media_loss_mask_[num_media_packets - 7] = 1;
|
||||
media_loss_mask_[num_media_packets - 5] = 1;
|
||||
media_loss_mask_[num_media_packets - 3] = 1;
|
||||
media_loss_mask_[num_media_packets - 1] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 11] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 9] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 7] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 5] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 3] = 1;
|
||||
media_loss_mask_[kNumMediaPackets - 1] = 1;
|
||||
NetworkReceivedPackets();
|
||||
|
||||
EXPECT_EQ(0, fec_->DecodeFEC(&received_packet_list_ ,
|
||||
|
@ -63,6 +63,7 @@
|
||||
# Video Files
|
||||
'bwe_defines.h',
|
||||
'fec_private_tables.h',
|
||||
'fec_private_tables_bursty.h',
|
||||
'forward_error_correction.cc',
|
||||
'forward_error_correction.h',
|
||||
'forward_error_correction_internal.cc',
|
||||
|
@ -20,8 +20,9 @@
|
||||
#include <ctime>
|
||||
#include <list>
|
||||
|
||||
#include "forward_error_correction.h"
|
||||
#include "forward_error_correction_internal.h"
|
||||
#include "modules/rtp_rtcp/source/fec_private_tables_bursty.h"
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction.h"
|
||||
#include "modules/rtp_rtcp/source/forward_error_correction_internal.h"
|
||||
|
||||
#include "rtp_utility.h"
|
||||
#include "testsupport/fileutils.h"
|
||||
@ -36,6 +37,7 @@ void ReceivePackets(
|
||||
WebRtc_UWord32 numPacketsToDecode, float reorderRate, float duplicateRate);
|
||||
|
||||
int main() {
|
||||
// TODO(marpan): Split this function into subroutines/helper functions.
|
||||
enum { kMaxNumberMediaPackets = 48 };
|
||||
enum { kMaxNumberFecPackets = 48 };
|
||||
|
||||
@ -45,6 +47,17 @@ int main() {
|
||||
// FOR UEP
|
||||
const bool kUseUnequalProtection = true;
|
||||
|
||||
// FEC mask types.
|
||||
const FecMaskType kMaskTypes[] = {kFecMaskRandom, kFecMaskBursty};
|
||||
const int kNumFecMaskTypes = sizeof(kMaskTypes) / sizeof(*kMaskTypes);
|
||||
// Maximum number of media packets allowed for the mask type.
|
||||
const uint16_t kMaxMediaPackets[] = {kMaxNumberMediaPackets,
|
||||
sizeof(kPacketMaskBurstyTbl) / sizeof(*kPacketMaskBurstyTbl)};
|
||||
if (kMaxMediaPackets[1] != 12) {
|
||||
printf("ERROR: max media packets for bursty mode not equal to 12 \n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtc_UWord32 id = 0;
|
||||
ForwardErrorCorrection fec(id);
|
||||
|
||||
@ -80,365 +93,381 @@ int main() {
|
||||
WebRtc_UWord32 timeStamp = static_cast<WebRtc_UWord32>(rand());
|
||||
const WebRtc_UWord32 ssrc = static_cast<WebRtc_UWord32>(rand());
|
||||
|
||||
for (WebRtc_UWord32 lossRateIdx = 0; lossRateIdx < lossRateSize;
|
||||
lossRateIdx++) {
|
||||
WebRtc_UWord8* packetMask =
|
||||
new WebRtc_UWord8[kMaxNumberMediaPackets * kNumMaskBytesL1];
|
||||
// Loop over the mask types: random and bursty.
|
||||
for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes;
|
||||
++mask_type_idx) {
|
||||
|
||||
printf("Loss rate: %.2f\n", lossRate[lossRateIdx]);
|
||||
for (WebRtc_UWord32 numMediaPackets = 1;
|
||||
numMediaPackets <= kMaxNumberMediaPackets;
|
||||
numMediaPackets++) {
|
||||
for (WebRtc_UWord32 lossRateIdx = 0; lossRateIdx < lossRateSize;
|
||||
++lossRateIdx) {
|
||||
|
||||
for (WebRtc_UWord32 numFecPackets = 1;
|
||||
numFecPackets <= numMediaPackets &&
|
||||
numFecPackets <= kMaxNumberFecPackets;
|
||||
numFecPackets++) {
|
||||
printf("Loss rate: %.2f, Mask type %d \n", lossRate[lossRateIdx],
|
||||
mask_type_idx);
|
||||
|
||||
// Loop over numImpPackets: these are usually <= (0.3*numMediaPackets).
|
||||
// For this test we check up to ~ (0.5*numMediaPackets).
|
||||
WebRtc_UWord32 maxNumImpPackets = numMediaPackets / 2 + 1;
|
||||
for (WebRtc_UWord32 numImpPackets = 0;
|
||||
numImpPackets <= maxNumImpPackets &&
|
||||
numImpPackets <= kMaxNumberMediaPackets;
|
||||
numImpPackets++) {
|
||||
const WebRtc_UWord32 packetMaskMax = kMaxMediaPackets[mask_type_idx];
|
||||
WebRtc_UWord8* packetMask =
|
||||
new WebRtc_UWord8[packetMaskMax * kNumMaskBytesL1];
|
||||
|
||||
WebRtc_UWord8 protectionFactor = static_cast<WebRtc_UWord8>
|
||||
(numFecPackets * 255 / numMediaPackets);
|
||||
FecMaskType fec_mask_type = kMaskTypes[mask_type_idx];
|
||||
|
||||
const WebRtc_UWord32 maskBytesPerFecPacket =
|
||||
(numMediaPackets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0;
|
||||
for (WebRtc_UWord32 numMediaPackets = 1;
|
||||
numMediaPackets <= packetMaskMax;
|
||||
numMediaPackets++) {
|
||||
internal::PacketMaskTable mask_table(fec_mask_type, numMediaPackets);
|
||||
|
||||
memset(packetMask, 0, numMediaPackets * maskBytesPerFecPacket);
|
||||
for (WebRtc_UWord32 numFecPackets = 1;
|
||||
numFecPackets <= numMediaPackets &&
|
||||
numFecPackets <= packetMaskMax;
|
||||
numFecPackets++) {
|
||||
|
||||
// Transfer packet masks from bit-mask to byte-mask.
|
||||
internal::GeneratePacketMasks(numMediaPackets,
|
||||
numFecPackets,
|
||||
numImpPackets,
|
||||
kUseUnequalProtection,
|
||||
packetMask);
|
||||
// Loop over numImpPackets: usually <= (0.3*numMediaPackets).
|
||||
// For this test we check up to ~ (0.5*numMediaPackets).
|
||||
WebRtc_UWord32 maxNumImpPackets = numMediaPackets / 2 + 1;
|
||||
for (WebRtc_UWord32 numImpPackets = 0;
|
||||
numImpPackets <= maxNumImpPackets &&
|
||||
numImpPackets <= packetMaskMax;
|
||||
numImpPackets++) {
|
||||
|
||||
WebRtc_UWord8 protectionFactor = static_cast<WebRtc_UWord8>
|
||||
(numFecPackets * 255 / numMediaPackets);
|
||||
|
||||
const WebRtc_UWord32 maskBytesPerFecPacket =
|
||||
(numMediaPackets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0;
|
||||
|
||||
memset(packetMask, 0, numMediaPackets * maskBytesPerFecPacket);
|
||||
|
||||
// Transfer packet masks from bit-mask to byte-mask.
|
||||
internal::GeneratePacketMasks(numMediaPackets,
|
||||
numFecPackets,
|
||||
numImpPackets,
|
||||
kUseUnequalProtection,
|
||||
mask_table,
|
||||
packetMask);
|
||||
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("%u media packets, %u FEC packets, %u numImpPackets, "
|
||||
"loss rate = %.2f \n",
|
||||
numMediaPackets, numFecPackets, numImpPackets, lossRate[lossRateIdx]);
|
||||
printf("Packet mask matrix \n");
|
||||
printf("%u media packets, %u FEC packets, %u numImpPackets, "
|
||||
"loss rate = %.2f \n",
|
||||
numMediaPackets, numFecPackets, numImpPackets,
|
||||
lossRate[lossRateIdx]);
|
||||
printf("Packet mask matrix \n");
|
||||
#endif
|
||||
|
||||
for (WebRtc_UWord32 i = 0; i < numFecPackets; i++) {
|
||||
for (WebRtc_UWord32 j = 0; j < numMediaPackets; j++) {
|
||||
const WebRtc_UWord8 byteMask =
|
||||
packetMask[i * maskBytesPerFecPacket + j / 8];
|
||||
const WebRtc_UWord32 bitPosition = (7 - j % 8);
|
||||
fecPacketMasks[i][j] =
|
||||
(byteMask & (1 << bitPosition)) >> bitPosition;
|
||||
for (WebRtc_UWord32 i = 0; i < numFecPackets; i++) {
|
||||
for (WebRtc_UWord32 j = 0; j < numMediaPackets; j++) {
|
||||
const WebRtc_UWord8 byteMask =
|
||||
packetMask[i * maskBytesPerFecPacket + j / 8];
|
||||
const WebRtc_UWord32 bitPosition = (7 - j % 8);
|
||||
fecPacketMasks[i][j] =
|
||||
(byteMask & (1 << bitPosition)) >> bitPosition;
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("%u ", fecPacketMasks[i][j]);
|
||||
printf("%u ", fecPacketMasks[i][j]);
|
||||
#endif
|
||||
}
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("\n");
|
||||
#endif
|
||||
// Check for all zero rows or columns: indicates incorrect mask
|
||||
WebRtc_UWord32 rowLimit = numMediaPackets;
|
||||
for (WebRtc_UWord32 i = 0; i < numFecPackets; i++) {
|
||||
WebRtc_UWord32 rowSum = 0;
|
||||
for (WebRtc_UWord32 j = 0; j < rowLimit; j++) {
|
||||
rowSum += fecPacketMasks[i][j];
|
||||
}
|
||||
if (rowSum == 0) {
|
||||
printf("ERROR: row is all zero %d \n",i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
for (WebRtc_UWord32 j = 0; j < rowLimit; j++) {
|
||||
WebRtc_UWord32 columnSum = 0;
|
||||
for (WebRtc_UWord32 i = 0; i < numFecPackets; i++) {
|
||||
columnSum += fecPacketMasks[i][j];
|
||||
}
|
||||
if (columnSum == 0) {
|
||||
printf("ERROR: column is all zero %d \n",j);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// Construct media packets.
|
||||
for (WebRtc_UWord32 i = 0; i < numMediaPackets; i++) {
|
||||
mediaPacket = new ForwardErrorCorrection::Packet;
|
||||
mediaPacketList.push_back(mediaPacket);
|
||||
mediaPacket->length =
|
||||
static_cast<WebRtc_UWord16>((static_cast<float>(rand()) /
|
||||
RAND_MAX) * (IP_PACKET_SIZE - 12 - 28 -
|
||||
ForwardErrorCorrection::PacketOverhead()));
|
||||
if (mediaPacket->length < 12) {
|
||||
mediaPacket->length = 12;
|
||||
}
|
||||
// Generate random values for the first 2 bytes
|
||||
mediaPacket->data[0] = static_cast<WebRtc_UWord8>(rand() % 256);
|
||||
mediaPacket->data[1] = static_cast<WebRtc_UWord8>(rand() % 256);
|
||||
|
||||
// The first two bits are assumed to be 10 by the
|
||||
// FEC encoder. In fact the FEC decoder will set the
|
||||
// two first bits to 10 regardless of what they
|
||||
// actually were. Set the first two bits to 10
|
||||
// so that a memcmp can be performed for the
|
||||
// whole restored packet.
|
||||
mediaPacket->data[0] |= 0x80;
|
||||
mediaPacket->data[0] &= 0xbf;
|
||||
|
||||
// FEC is applied to a whole frame.
|
||||
// A frame is signaled by multiple packets without
|
||||
// the marker bit set followed by the last packet of
|
||||
// the frame for which the marker bit is set.
|
||||
// Only push one (fake) frame to the FEC.
|
||||
mediaPacket->data[1] &= 0x7f;
|
||||
|
||||
ModuleRTPUtility::AssignUWord16ToBuffer(&mediaPacket->data[2],
|
||||
seqNum);
|
||||
ModuleRTPUtility::AssignUWord32ToBuffer(&mediaPacket->data[4],
|
||||
timeStamp);
|
||||
ModuleRTPUtility::AssignUWord32ToBuffer(&mediaPacket->data[8],
|
||||
ssrc);
|
||||
// Generate random values for payload
|
||||
for (WebRtc_Word32 j = 12; j < mediaPacket->length; j++) {
|
||||
mediaPacket->data[j] =
|
||||
static_cast<WebRtc_UWord8> (rand() % 256);
|
||||
}
|
||||
seqNum++;
|
||||
}
|
||||
mediaPacket->data[1] |= 0x80;
|
||||
|
||||
if (fec.GenerateFEC(mediaPacketList, protectionFactor,
|
||||
numImpPackets, kUseUnequalProtection,
|
||||
&fecPacketList) != 0) {
|
||||
printf("Error: GenerateFEC() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fecPacketList.size() != numFecPackets) {
|
||||
printf("Error: we requested %u FEC packets, "
|
||||
"but GenerateFEC() produced %u\n",
|
||||
numFecPackets,
|
||||
static_cast<WebRtc_UWord32>(fecPacketList.size()));
|
||||
return -1;
|
||||
}
|
||||
memset(mediaLossMask, 0, sizeof(mediaLossMask));
|
||||
ForwardErrorCorrection::PacketList::iterator
|
||||
mediaPacketListItem = mediaPacketList.begin();
|
||||
ForwardErrorCorrection::ReceivedPacket* receivedPacket;
|
||||
WebRtc_UWord32 mediaPacketIdx = 0;
|
||||
|
||||
while (mediaPacketListItem != mediaPacketList.end()) {
|
||||
mediaPacket = *mediaPacketListItem;
|
||||
const float lossRandomVariable = (static_cast<float>(rand()) /
|
||||
(RAND_MAX));
|
||||
|
||||
if (lossRandomVariable >= lossRate[lossRateIdx])
|
||||
{
|
||||
mediaLossMask[mediaPacketIdx] = 1;
|
||||
receivedPacket =
|
||||
new ForwardErrorCorrection::ReceivedPacket;
|
||||
receivedPacket->pkt = new ForwardErrorCorrection::Packet;
|
||||
receivedPacketList.push_back(receivedPacket);
|
||||
|
||||
receivedPacket->pkt->length = mediaPacket->length;
|
||||
memcpy(receivedPacket->pkt->data, mediaPacket->data,
|
||||
mediaPacket->length);
|
||||
receivedPacket->seqNum =
|
||||
ModuleRTPUtility::BufferToUWord16(&mediaPacket->data[2]);
|
||||
receivedPacket->isFec = false;
|
||||
}
|
||||
mediaPacketIdx++;
|
||||
++mediaPacketListItem;
|
||||
}
|
||||
memset(fecLossMask, 0, sizeof(fecLossMask));
|
||||
ForwardErrorCorrection::PacketList::iterator
|
||||
fecPacketListItem = fecPacketList.begin();
|
||||
ForwardErrorCorrection::Packet* fecPacket;
|
||||
WebRtc_UWord32 fecPacketIdx = 0;
|
||||
while (fecPacketListItem != fecPacketList.end()) {
|
||||
fecPacket = *fecPacketListItem;
|
||||
const float lossRandomVariable =
|
||||
(static_cast<float>(rand()) / (RAND_MAX));
|
||||
if (lossRandomVariable >= lossRate[lossRateIdx]) {
|
||||
fecLossMask[fecPacketIdx] = 1;
|
||||
receivedPacket =
|
||||
new ForwardErrorCorrection::ReceivedPacket;
|
||||
receivedPacket->pkt = new ForwardErrorCorrection::Packet;
|
||||
|
||||
receivedPacketList.push_back(receivedPacket);
|
||||
|
||||
receivedPacket->pkt->length = fecPacket->length;
|
||||
memcpy(receivedPacket->pkt->data, fecPacket->data,
|
||||
fecPacket->length);
|
||||
|
||||
receivedPacket->seqNum = seqNum;
|
||||
receivedPacket->isFec = true;
|
||||
receivedPacket->ssrc = ssrc;
|
||||
|
||||
fecMaskList.push_back(fecPacketMasks[fecPacketIdx]);
|
||||
}
|
||||
fecPacketIdx++;
|
||||
seqNum++;
|
||||
++fecPacketListItem;
|
||||
}
|
||||
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("Media loss mask:\n");
|
||||
for (WebRtc_UWord32 i = 0; i < numMediaPackets; i++) {
|
||||
printf("%u ", mediaLossMask[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
printf("FEC loss mask:\n");
|
||||
for (WebRtc_UWord32 i = 0; i < numFecPackets; i++) {
|
||||
printf("%u ", fecLossMask[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
#endif
|
||||
|
||||
std::list<WebRtc_UWord8*>::iterator fecMaskIt = fecMaskList.begin();
|
||||
WebRtc_UWord8* fecMask;
|
||||
while (fecMaskIt != fecMaskList.end()) {
|
||||
fecMask = *fecMaskIt;
|
||||
WebRtc_UWord32 hammingDist = 0;
|
||||
WebRtc_UWord32 recoveryPosition = 0;
|
||||
for (WebRtc_UWord32 i = 0; i < numMediaPackets; i++) {
|
||||
if (mediaLossMask[i] == 0 && fecMask[i] == 1) {
|
||||
recoveryPosition = i;
|
||||
hammingDist++;
|
||||
// Check for all zero rows or columns: indicates incorrect mask.
|
||||
WebRtc_UWord32 rowLimit = numMediaPackets;
|
||||
for (WebRtc_UWord32 i = 0; i < numFecPackets; ++i) {
|
||||
WebRtc_UWord32 rowSum = 0;
|
||||
for (WebRtc_UWord32 j = 0; j < rowLimit; ++j) {
|
||||
rowSum += fecPacketMasks[i][j];
|
||||
}
|
||||
}
|
||||
std::list<WebRtc_UWord8*>::iterator itemToDelete = fecMaskIt;
|
||||
++fecMaskIt;
|
||||
|
||||
if (hammingDist == 1) {
|
||||
// Recovery possible. Restart search.
|
||||
mediaLossMask[recoveryPosition] = 1;
|
||||
fecMaskIt = fecMaskList.begin();
|
||||
} else if (hammingDist == 0) {
|
||||
// FEC packet cannot provide further recovery.
|
||||
fecMaskList.erase(itemToDelete);
|
||||
}
|
||||
}
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("Recovery mask:\n");
|
||||
for (WebRtc_UWord32 i = 0; i < numMediaPackets; i++) {
|
||||
printf("%u ", mediaLossMask[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
#endif
|
||||
bool fecPacketReceived = false; // For error-checking frame completion.
|
||||
while (!receivedPacketList.empty()) {
|
||||
WebRtc_UWord32 numPacketsToDecode = static_cast<WebRtc_UWord32>
|
||||
((static_cast<float>(rand()) / RAND_MAX) *
|
||||
receivedPacketList.size() + 0.5);
|
||||
if (numPacketsToDecode < 1) {
|
||||
numPacketsToDecode = 1;
|
||||
}
|
||||
ReceivePackets(&toDecodeList, &receivedPacketList,
|
||||
numPacketsToDecode, reorderRate, duplicateRate);
|
||||
|
||||
if (fecPacketReceived == false) {
|
||||
ForwardErrorCorrection::ReceivedPacketList::iterator
|
||||
toDecodeIt = toDecodeList.begin();
|
||||
while (toDecodeIt != toDecodeList.end()) {
|
||||
receivedPacket = *toDecodeIt;
|
||||
if (receivedPacket->isFec) {
|
||||
fecPacketReceived = true;
|
||||
}
|
||||
++toDecodeIt;
|
||||
}
|
||||
}
|
||||
if (fec.DecodeFEC(&toDecodeList, &recoveredPacketList)
|
||||
!= 0) {
|
||||
printf("Error: DecodeFEC() failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (!toDecodeList.empty()) {
|
||||
printf("Error: received packet list is not empty\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
mediaPacketListItem = mediaPacketList.begin();
|
||||
mediaPacketIdx = 0;
|
||||
while (mediaPacketListItem != mediaPacketList.end()) {
|
||||
if (mediaLossMask[mediaPacketIdx] == 1) {
|
||||
// Should have recovered this packet.
|
||||
ForwardErrorCorrection::RecoveredPacketList::iterator
|
||||
recoveredPacketListItem = recoveredPacketList.begin();
|
||||
|
||||
if (recoveredPacketListItem == recoveredPacketList.end()) {
|
||||
printf("Error: insufficient number of recovered packets.\n");
|
||||
if (rowSum == 0) {
|
||||
printf("ERROR: row is all zero %d \n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
for (WebRtc_UWord32 j = 0; j < rowLimit; ++j) {
|
||||
WebRtc_UWord32 columnSum = 0;
|
||||
for (WebRtc_UWord32 i = 0; i < numFecPackets; ++i) {
|
||||
columnSum += fecPacketMasks[i][j];
|
||||
}
|
||||
if (columnSum == 0) {
|
||||
printf("ERROR: column is all zero %d \n", j);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Construct media packets.
|
||||
for (WebRtc_UWord32 i = 0; i < numMediaPackets; ++i) {
|
||||
mediaPacket = new ForwardErrorCorrection::Packet;
|
||||
mediaPacketList.push_back(mediaPacket);
|
||||
mediaPacket->length =
|
||||
static_cast<WebRtc_UWord16>((static_cast<float>(rand()) /
|
||||
RAND_MAX) * (IP_PACKET_SIZE - 12 -
|
||||
28 - ForwardErrorCorrection::PacketOverhead()));
|
||||
if (mediaPacket->length < 12) {
|
||||
mediaPacket->length = 12;
|
||||
}
|
||||
// Generate random values for the first 2 bytes.
|
||||
mediaPacket->data[0] = static_cast<WebRtc_UWord8>(rand() % 256);
|
||||
mediaPacket->data[1] = static_cast<WebRtc_UWord8>(rand() % 256);
|
||||
|
||||
// The first two bits are assumed to be 10 by the
|
||||
// FEC encoder. In fact the FEC decoder will set the
|
||||
// two first bits to 10 regardless of what they
|
||||
// actually were. Set the first two bits to 10
|
||||
// so that a memcmp can be performed for the
|
||||
// whole restored packet.
|
||||
mediaPacket->data[0] |= 0x80;
|
||||
mediaPacket->data[0] &= 0xbf;
|
||||
|
||||
// FEC is applied to a whole frame.
|
||||
// A frame is signaled by multiple packets without
|
||||
// the marker bit set followed by the last packet of
|
||||
// the frame for which the marker bit is set.
|
||||
// Only push one (fake) frame to the FEC.
|
||||
mediaPacket->data[1] &= 0x7f;
|
||||
|
||||
ModuleRTPUtility::AssignUWord16ToBuffer(&mediaPacket->data[2],
|
||||
seqNum);
|
||||
ModuleRTPUtility::AssignUWord32ToBuffer(&mediaPacket->data[4],
|
||||
timeStamp);
|
||||
ModuleRTPUtility::AssignUWord32ToBuffer(&mediaPacket->data[8],
|
||||
ssrc);
|
||||
// Generate random values for payload
|
||||
for (WebRtc_Word32 j = 12; j < mediaPacket->length; ++j) {
|
||||
mediaPacket->data[j] =
|
||||
static_cast<WebRtc_UWord8> (rand() % 256);
|
||||
}
|
||||
seqNum++;
|
||||
}
|
||||
mediaPacket->data[1] |= 0x80;
|
||||
|
||||
if (fec.GenerateFEC(mediaPacketList, protectionFactor,
|
||||
numImpPackets, kUseUnequalProtection,
|
||||
fec_mask_type, &fecPacketList) != 0) {
|
||||
printf("Error: GenerateFEC() failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fecPacketList.size() != numFecPackets) {
|
||||
printf("Error: we requested %u FEC packets, "
|
||||
"but GenerateFEC() produced %u\n",
|
||||
numFecPackets,
|
||||
static_cast<WebRtc_UWord32>(fecPacketList.size()));
|
||||
return -1;
|
||||
}
|
||||
memset(mediaLossMask, 0, sizeof(mediaLossMask));
|
||||
ForwardErrorCorrection::PacketList::iterator
|
||||
mediaPacketListItem = mediaPacketList.begin();
|
||||
ForwardErrorCorrection::ReceivedPacket* receivedPacket;
|
||||
WebRtc_UWord32 mediaPacketIdx = 0;
|
||||
|
||||
while (mediaPacketListItem != mediaPacketList.end()) {
|
||||
mediaPacket = *mediaPacketListItem;
|
||||
ForwardErrorCorrection::RecoveredPacket* recoveredPacket =
|
||||
*recoveredPacketListItem;
|
||||
// We want a value between 0 and 1.
|
||||
const float lossRandomVariable = (static_cast<float>(rand()) /
|
||||
(RAND_MAX));
|
||||
|
||||
if (recoveredPacket->pkt->length != mediaPacket->length) {
|
||||
printf("Error: recovered packet length not identical to "
|
||||
"original media packet\n");
|
||||
return -1;
|
||||
if (lossRandomVariable >= lossRate[lossRateIdx]) {
|
||||
mediaLossMask[mediaPacketIdx] = 1;
|
||||
receivedPacket =
|
||||
new ForwardErrorCorrection::ReceivedPacket;
|
||||
receivedPacket->pkt = new ForwardErrorCorrection::Packet;
|
||||
receivedPacketList.push_back(receivedPacket);
|
||||
|
||||
receivedPacket->pkt->length = mediaPacket->length;
|
||||
memcpy(receivedPacket->pkt->data, mediaPacket->data,
|
||||
mediaPacket->length);
|
||||
receivedPacket->seqNum =
|
||||
ModuleRTPUtility::BufferToUWord16(&mediaPacket->data[2]);
|
||||
receivedPacket->isFec = false;
|
||||
}
|
||||
if (memcmp(recoveredPacket->pkt->data, mediaPacket->data,
|
||||
mediaPacket->length) != 0) {
|
||||
printf("Error: recovered packet payload not identical to "
|
||||
"original media packet\n");
|
||||
return -1;
|
||||
}
|
||||
delete recoveredPacket;
|
||||
recoveredPacketList.pop_front();
|
||||
mediaPacketIdx++;
|
||||
++mediaPacketListItem;
|
||||
}
|
||||
mediaPacketIdx++;
|
||||
++mediaPacketListItem;
|
||||
}
|
||||
fec.ResetState(&recoveredPacketList);
|
||||
if (!recoveredPacketList.empty()) {
|
||||
printf("Error: excessive number of recovered packets.\n");
|
||||
printf("\t size is:%u\n",
|
||||
static_cast<WebRtc_UWord32>(recoveredPacketList.size()));
|
||||
return -1;
|
||||
}
|
||||
// -- Teardown --
|
||||
mediaPacketListItem = mediaPacketList.begin();
|
||||
while (mediaPacketListItem != mediaPacketList.end()) {
|
||||
delete *mediaPacketListItem;
|
||||
++mediaPacketListItem;
|
||||
mediaPacketList.pop_front();
|
||||
}
|
||||
assert(mediaPacketList.empty());
|
||||
memset(fecLossMask, 0, sizeof(fecLossMask));
|
||||
ForwardErrorCorrection::PacketList::iterator
|
||||
fecPacketListItem = fecPacketList.begin();
|
||||
ForwardErrorCorrection::Packet* fecPacket;
|
||||
WebRtc_UWord32 fecPacketIdx = 0;
|
||||
while (fecPacketListItem != fecPacketList.end()) {
|
||||
fecPacket = *fecPacketListItem;
|
||||
const float lossRandomVariable =
|
||||
(static_cast<float>(rand()) / (RAND_MAX));
|
||||
if (lossRandomVariable >= lossRate[lossRateIdx]) {
|
||||
fecLossMask[fecPacketIdx] = 1;
|
||||
receivedPacket =
|
||||
new ForwardErrorCorrection::ReceivedPacket;
|
||||
receivedPacket->pkt = new ForwardErrorCorrection::Packet;
|
||||
|
||||
fecPacketListItem = fecPacketList.begin();
|
||||
while (fecPacketListItem != fecPacketList.end()) {
|
||||
++fecPacketListItem;
|
||||
fecPacketList.pop_front();
|
||||
}
|
||||
receivedPacketList.push_back(receivedPacket);
|
||||
|
||||
// Delete received packets we didn't pass to DecodeFEC(), due to early
|
||||
// frame completion.
|
||||
ForwardErrorCorrection::ReceivedPacketList::iterator
|
||||
receivedPacketIt = receivedPacketList.begin();
|
||||
while (receivedPacketIt != receivedPacketList.end()) {
|
||||
receivedPacket = *receivedPacketIt;
|
||||
delete receivedPacket;
|
||||
++receivedPacketIt;
|
||||
receivedPacketList.pop_front();
|
||||
}
|
||||
assert(receivedPacketList.empty());
|
||||
receivedPacket->pkt->length = fecPacket->length;
|
||||
memcpy(receivedPacket->pkt->data, fecPacket->data,
|
||||
fecPacket->length);
|
||||
|
||||
while (!fecMaskList.empty()) {
|
||||
fecMaskList.pop_front();
|
||||
}
|
||||
timeStamp += 90000 / 30;
|
||||
} //loop over numImpPackets
|
||||
} //loop over FecPackets
|
||||
} //loop over numMediaPackets
|
||||
delete [] packetMask;
|
||||
} // loop over loss rates
|
||||
receivedPacket->seqNum = seqNum;
|
||||
receivedPacket->isFec = true;
|
||||
receivedPacket->ssrc = ssrc;
|
||||
|
||||
fecMaskList.push_back(fecPacketMasks[fecPacketIdx]);
|
||||
}
|
||||
++fecPacketIdx;
|
||||
++seqNum;
|
||||
++fecPacketListItem;
|
||||
}
|
||||
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("Media loss mask:\n");
|
||||
for (WebRtc_UWord32 i = 0; i < numMediaPackets; i++) {
|
||||
printf("%u ", mediaLossMask[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
printf("FEC loss mask:\n");
|
||||
for (WebRtc_UWord32 i = 0; i < numFecPackets; i++) {
|
||||
printf("%u ", fecLossMask[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
#endif
|
||||
|
||||
std::list<WebRtc_UWord8*>::iterator fecMaskIt = fecMaskList.begin();
|
||||
WebRtc_UWord8* fecMask;
|
||||
while (fecMaskIt != fecMaskList.end()) {
|
||||
fecMask = *fecMaskIt;
|
||||
WebRtc_UWord32 hammingDist = 0;
|
||||
WebRtc_UWord32 recoveryPosition = 0;
|
||||
for (WebRtc_UWord32 i = 0; i < numMediaPackets; i++) {
|
||||
if (mediaLossMask[i] == 0 && fecMask[i] == 1) {
|
||||
recoveryPosition = i;
|
||||
++hammingDist;
|
||||
}
|
||||
}
|
||||
std::list<WebRtc_UWord8*>::iterator itemToDelete = fecMaskIt;
|
||||
++fecMaskIt;
|
||||
|
||||
if (hammingDist == 1) {
|
||||
// Recovery possible. Restart search.
|
||||
mediaLossMask[recoveryPosition] = 1;
|
||||
fecMaskIt = fecMaskList.begin();
|
||||
} else if (hammingDist == 0) {
|
||||
// FEC packet cannot provide further recovery.
|
||||
fecMaskList.erase(itemToDelete);
|
||||
}
|
||||
}
|
||||
#ifdef VERBOSE_OUTPUT
|
||||
printf("Recovery mask:\n");
|
||||
for (WebRtc_UWord32 i = 0; i < numMediaPackets; ++i) {
|
||||
printf("%u ", mediaLossMask[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
#endif
|
||||
// For error-checking frame completion.
|
||||
bool fecPacketReceived = false;
|
||||
while (!receivedPacketList.empty()) {
|
||||
WebRtc_UWord32 numPacketsToDecode = static_cast<WebRtc_UWord32>
|
||||
((static_cast<float>(rand()) / RAND_MAX) *
|
||||
receivedPacketList.size() + 0.5);
|
||||
if (numPacketsToDecode < 1) {
|
||||
numPacketsToDecode = 1;
|
||||
}
|
||||
ReceivePackets(&toDecodeList, &receivedPacketList,
|
||||
numPacketsToDecode, reorderRate, duplicateRate);
|
||||
|
||||
if (fecPacketReceived == false) {
|
||||
ForwardErrorCorrection::ReceivedPacketList::iterator
|
||||
toDecodeIt = toDecodeList.begin();
|
||||
while (toDecodeIt != toDecodeList.end()) {
|
||||
receivedPacket = *toDecodeIt;
|
||||
if (receivedPacket->isFec) {
|
||||
fecPacketReceived = true;
|
||||
}
|
||||
++toDecodeIt;
|
||||
}
|
||||
}
|
||||
if (fec.DecodeFEC(&toDecodeList, &recoveredPacketList)
|
||||
!= 0) {
|
||||
printf("Error: DecodeFEC() failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (!toDecodeList.empty()) {
|
||||
printf("Error: received packet list is not empty\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
mediaPacketListItem = mediaPacketList.begin();
|
||||
mediaPacketIdx = 0;
|
||||
while (mediaPacketListItem != mediaPacketList.end()) {
|
||||
if (mediaLossMask[mediaPacketIdx] == 1) {
|
||||
// Should have recovered this packet.
|
||||
ForwardErrorCorrection::RecoveredPacketList::iterator
|
||||
recoveredPacketListItem = recoveredPacketList.begin();
|
||||
|
||||
if (recoveredPacketListItem == recoveredPacketList.end()) {
|
||||
printf("Error: insufficient number of recovered packets.\n");
|
||||
return -1;
|
||||
}
|
||||
mediaPacket = *mediaPacketListItem;
|
||||
ForwardErrorCorrection::RecoveredPacket* recoveredPacket =
|
||||
*recoveredPacketListItem;
|
||||
|
||||
if (recoveredPacket->pkt->length != mediaPacket->length) {
|
||||
printf("Error: recovered packet length not identical to "
|
||||
"original media packet\n");
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(recoveredPacket->pkt->data, mediaPacket->data,
|
||||
mediaPacket->length) != 0) {
|
||||
printf("Error: recovered packet payload not identical to "
|
||||
"original media packet\n");
|
||||
return -1;
|
||||
}
|
||||
delete recoveredPacket;
|
||||
recoveredPacketList.pop_front();
|
||||
}
|
||||
++mediaPacketIdx;
|
||||
++mediaPacketListItem;
|
||||
}
|
||||
fec.ResetState(&recoveredPacketList);
|
||||
if (!recoveredPacketList.empty()) {
|
||||
printf("Error: excessive number of recovered packets.\n");
|
||||
printf("\t size is:%u\n",
|
||||
static_cast<WebRtc_UWord32>(recoveredPacketList.size()));
|
||||
return -1;
|
||||
}
|
||||
// -- Teardown --
|
||||
mediaPacketListItem = mediaPacketList.begin();
|
||||
while (mediaPacketListItem != mediaPacketList.end()) {
|
||||
delete *mediaPacketListItem;
|
||||
++mediaPacketListItem;
|
||||
mediaPacketList.pop_front();
|
||||
}
|
||||
assert(mediaPacketList.empty());
|
||||
|
||||
fecPacketListItem = fecPacketList.begin();
|
||||
while (fecPacketListItem != fecPacketList.end()) {
|
||||
++fecPacketListItem;
|
||||
fecPacketList.pop_front();
|
||||
}
|
||||
|
||||
// Delete received packets we didn't pass to DecodeFEC(), due to
|
||||
// early frame completion.
|
||||
ForwardErrorCorrection::ReceivedPacketList::iterator
|
||||
receivedPacketIt = receivedPacketList.begin();
|
||||
while (receivedPacketIt != receivedPacketList.end()) {
|
||||
receivedPacket = *receivedPacketIt;
|
||||
delete receivedPacket;
|
||||
++receivedPacketIt;
|
||||
receivedPacketList.pop_front();
|
||||
}
|
||||
assert(receivedPacketList.empty());
|
||||
|
||||
while (!fecMaskList.empty()) {
|
||||
fecMaskList.pop_front();
|
||||
}
|
||||
timeStamp += 90000 / 30;
|
||||
} // loop over numImpPackets
|
||||
} // loop over FecPackets
|
||||
} // loop over numMediaPackets
|
||||
delete [] packetMask;
|
||||
} // loop over loss rates
|
||||
} // loop over mask types
|
||||
|
||||
// Have DecodeFEC free allocated memory.
|
||||
fec.ResetState(&recoveredPacketList);
|
||||
|
Loading…
Reference in New Issue
Block a user