blob: 9ba6ce0438c95703b6f79310c3fad0480655372b [file] [log] [blame]
/*
* 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_FORWARD_ERROR_CORRECTION_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_
#include <list>
#include <vector>
#include "webrtc/base/scoped_ref_ptr.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/system_wrappers/include/ref_count.h"
#include "webrtc/typedefs.h"
namespace webrtc {
// Forward declaration.
class FecPacket;
// Performs codec-independent forward error correction (FEC), based on RFC 5109.
// Option exists to enable unequal protection (UEP) across packets.
// This is not to be confused with protection within packets
// (referred to as uneven level protection (ULP) in RFC 5109).
class ForwardErrorCorrection {
public:
// Maximum number of media packets we can protect
static const unsigned int kMaxMediaPackets = 48u;
// TODO(holmer): As a next step all these struct-like packet classes should be
// refactored into proper classes, and their members should be made private.
// This will require parts of the functionality in forward_error_correction.cc
// and receiver_fec.cc to be refactored into the packet classes.
class Packet {
public:
Packet() : length(0), data(), ref_count_(0) {}
virtual ~Packet() {}
// Add a reference.
virtual int32_t AddRef();
// Release a reference. Will delete the object if the reference count
// reaches zero.
virtual int32_t Release();
size_t length; // Length of packet in bytes.
uint8_t data[IP_PACKET_SIZE]; // Packet data.
private:
int32_t ref_count_; // Counts the number of references to a packet.
};
// TODO(holmer): Refactor into a proper class.
class SortablePacket {
public:
// True if first is <= than second.
static bool LessThan(const SortablePacket* first,
const SortablePacket* second);
uint16_t seq_num;
};
// The received list parameter of #DecodeFEC() must reference structs of this
// type. The last_media_pkt_in_frame is not required to be used for correct
// recovery, but will reduce delay by allowing #DecodeFEC() to pre-emptively
// determine frame completion. If set, we assume a FEC stream, and the
// following assumptions must hold:\n
//
// 1. The media packets in a frame have contiguous sequence numbers, i.e. the
// frame's FEC packets have sequence numbers either lower than the first
// media packet or higher than the last media packet.\n
// 2. All FEC packets have a sequence number base equal to the first media
// packet in the corresponding frame.\n
//
// The ssrc member is needed to ensure we can restore the SSRC field of
// recovered packets. In most situations this could be retrieved from other
// media packets, but in the case of an FEC packet protecting a single
// missing media packet, we have no other means of obtaining it.
// TODO(holmer): Refactor into a proper class.
class ReceivedPacket : public SortablePacket {
public:
ReceivedPacket();
~ReceivedPacket();
uint32_t ssrc; // SSRC of the current frame. Must be set for FEC
// packets, but not required for media packets.
bool is_fec; // Set to true if this is an FEC packet and false
// otherwise.
rtc::scoped_refptr<Packet> pkt; // Pointer to the packet storage.
};
// The recovered list parameter of #DecodeFEC() will reference structs of
// this type.
// TODO(holmer): Refactor into a proper class.
class RecoveredPacket : public SortablePacket {
public:
RecoveredPacket();
~RecoveredPacket();
bool was_recovered; // Will be true if this packet was recovered by
// the FEC. Otherwise it was a media packet passed in
// through the received packet list.
bool returned; // True when the packet already has been returned to the
// caller through the callback.
uint8_t length_recovery[2]; // Two bytes used for recovering the packet
// length with XOR operations.
rtc::scoped_refptr<Packet> pkt; // Pointer to the packet storage.
};
typedef std::list<Packet*> PacketList;
typedef std::list<ReceivedPacket*> ReceivedPacketList;
typedef std::list<RecoveredPacket*> RecoveredPacketList;
ForwardErrorCorrection();
virtual ~ForwardErrorCorrection();
/**
* Generates a list of FEC packets from supplied media packets.
*
* \param[in] mediaPacketList List of media packets to protect, of type
* #Packet. All packets must belong to the
* same frame and the list must not be empty.
* \param[in] protectionFactor FEC protection overhead in the [0, 255]
* domain. To obtain 100% overhead, or an
* equal number of FEC packets as media
* packets, use 255.
* \param[in] numImportantPackets The number of "important" packets in the
* frame. These packets may receive greater
* protection than the remaining packets. The
* important packets must be located at the
* start of the media packet list. For codecs
* with data partitioning, the important
* packets may correspond to first partition
* packets.
* \param[in] useUnequalProtection Parameter to enable/disable unequal
* protection (UEP) across packets. Enabling
* 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
* next call to GenerateFEC().
*
* \return 0 on success, -1 on failure.
*/
int32_t GenerateFEC(const PacketList& media_packet_list,
uint8_t protection_factor, int num_important_packets,
bool use_unequal_protection, FecMaskType fec_mask_type,
PacketList* fec_packet_list);
/**
* Decodes a list of media and FEC packets. It will parse the input received
* packet list, storing FEC packets internally and inserting media packets to
* the output recovered packet list. The recovered list will be sorted by
* ascending sequence number and have duplicates removed. The function
* should be called as new packets arrive, with the recovered list being
* progressively assembled with each call. The received packet list will be
* empty at output.\n
*
* The user will allocate packets submitted through the received list. The
* function will handle allocation of recovered packets and optionally
* deleting of all packet memory. The user may delete the recovered list
* packets, in which case they must remove deleted packets from the
* recovered list.\n
*
* \param[in] receivedPacketList List of new received packets, of type
* #ReceivedPacket, belonging to a single
* frame. At output the list will be empty,
* with packets either stored internally,
* or accessible through the recovered list.
* \param[out] recoveredPacketList List of recovered media packets, of type
* #RecoveredPacket, belonging to a single
* frame. The memory available through the
* list will be valid until the next call to
* DecodeFEC().
*
* \return 0 on success, -1 on failure.
*/
int32_t DecodeFEC(ReceivedPacketList* received_packet_list,
RecoveredPacketList* recovered_packet_list);
// Get the number of FEC packets, given the number of media packets and the
// protection factor.
int GetNumberOfFecPackets(int num_media_packets, int protection_factor);
// Gets the size in bytes of the FEC/ULP headers, which must be accounted for
// as packet overhead.
// \return Packet overhead in bytes.
static size_t PacketOverhead();
// Reset internal states from last frame and clear the recovered_packet_list.
// Frees all memory allocated by this class.
void ResetState(RecoveredPacketList* recovered_packet_list);
private:
typedef std::list<FecPacket*> FecPacketList;
void GenerateFecUlpHeaders(const PacketList& media_packet_list,
uint8_t* packet_mask, bool l_bit,
int num_fec_packets);
// Analyzes |media_packets| for holes in the sequence and inserts zero columns
// into the |packet_mask| where those holes are found. Zero columns means that
// those packets will have no protection.
// Returns the number of bits used for one row of the new packet mask.
// Requires that |packet_mask| has at least 6 * |num_fec_packets| bytes
// allocated.
int InsertZerosInBitMasks(const PacketList& media_packets,
uint8_t* packet_mask, int num_mask_bytes,
int num_fec_packets);
// Inserts |num_zeros| zero columns into |new_mask| at position
// |new_bit_index|. If the current byte of |new_mask| can't fit all zeros, the
// byte will be filled with zeros from |new_bit_index|, but the next byte will
// be untouched.
static void InsertZeroColumns(int num_zeros, uint8_t* new_mask,
int new_mask_bytes, int num_fec_packets,
int new_bit_index);
// Copies the left most bit column from the byte pointed to by
// |old_bit_index| in |old_mask| to the right most column of the byte pointed
// to by |new_bit_index| in |new_mask|. |old_mask_bytes| and |new_mask_bytes|
// represent the number of bytes used per row for each mask. |num_fec_packets|
// represent the number of rows of the masks.
// The copied bit is shifted out from |old_mask| and is shifted one step to
// the left in |new_mask|. |new_mask| will contain "xxxx xxn0" after this
// operation, where x are previously inserted bits and n is the new bit.
static void CopyColumn(uint8_t* new_mask, int new_mask_bytes,
uint8_t* old_mask, int old_mask_bytes,
int num_fec_packets, int new_bit_index,
int old_bit_index);
void GenerateFecBitStrings(const PacketList& media_packet_list,
uint8_t* packet_mask, int num_fec_packets,
bool l_bit);
// Insert received packets into FEC or recovered list.
void InsertPackets(ReceivedPacketList* received_packet_list,
RecoveredPacketList* recovered_packet_list);
// Insert media packet into recovered packet list. We delete duplicates.
void InsertMediaPacket(ReceivedPacket* rx_packet,
RecoveredPacketList* recovered_packet_list);
// Assigns pointers to the recovered packet from all FEC packets which cover
// it.
// Note: This reduces the complexity when we want to try to recover a packet
// since we don't have to find the intersection between recovered packets and
// packets covered by the FEC packet.
void UpdateCoveringFECPackets(RecoveredPacket* packet);
// Insert packet into FEC list. We delete duplicates.
void InsertFECPacket(ReceivedPacket* rx_packet,
const RecoveredPacketList* recovered_packet_list);
// Assigns pointers to already recovered packets covered by this FEC packet.
static void AssignRecoveredPackets(
FecPacket* fec_packet, const RecoveredPacketList* recovered_packets);
// Insert into recovered list in correct position.
void InsertRecoveredPacket(RecoveredPacket* rec_packet_to_insert,
RecoveredPacketList* recovered_packet_list);
// Attempt to recover missing packets.
void AttemptRecover(RecoveredPacketList* recovered_packet_list);
// Initializes the packet recovery using the FEC packet.
static bool InitRecovery(const FecPacket* fec_packet,
RecoveredPacket* recovered);
// Performs XOR between |src_packet| and |dst_packet| and stores the result
// in |dst_packet|.
static void XorPackets(const Packet* src_packet, RecoveredPacket* dst_packet);
// Finish up the recovery of a packet.
static bool FinishRecovery(RecoveredPacket* recovered);
// Recover a missing packet.
bool RecoverPacket(const FecPacket* fec_packet,
RecoveredPacket* rec_packet_to_insert);
// Get the number of missing media packets which are covered by this
// FEC packet. An FEC packet can recover at most one packet, and if zero
// packets are missing the FEC packet can be discarded.
// This function returns 2 when two or more packets are missing.
static int NumCoveredPacketsMissing(const FecPacket* fec_packet);
static void DiscardFECPacket(FecPacket* fec_packet);
static void DiscardOldPackets(RecoveredPacketList* recovered_packet_list);
static uint16_t ParseSequenceNumber(uint8_t* packet);
std::vector<Packet> generated_fec_packets_;
FecPacketList fec_packet_list_;
bool fec_packet_received_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_FORWARD_ERROR_CORRECTION_H_