Some re-organization of the fec-uep code: updated protection modes, comments, and some variable/function re-naming.
Review URL: http://webrtc-codereview.appspot.com/231001

git-svn-id: http://webrtc.googlecode.com/svn/trunk@752 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/src/modules/rtp_rtcp/source/forward_error_correction_internal.cc b/src/modules/rtp_rtcp/source/forward_error_correction_internal.cc
index a134593..0217c16 100644
--- a/src/modules/rtp_rtcp/source/forward_error_correction_internal.cc
+++ b/src/modules/rtp_rtcp/source/forward_error_correction_internal.cc
@@ -16,15 +16,14 @@
 
 namespace {
 
-// Allow for two different modes of protection for residual packets.
-// The residual packets are the remaining packets beyond the important ones.
-enum ResidualProtectionMode
+// Allow for different modes of protection for packets in UEP case.
+enum ProtectionMode
 {
     kModeNoOverlap,
     kModeOverlap,
+    kModeBiasFirstPacket,
 };
 
-
 /**
   * Fits an input mask (subMask) to an output mask.
   * The mask is a matrix where the rows are the FEC packets,
@@ -158,47 +157,51 @@
 namespace webrtc {
 namespace internal {
 
-// Residual protection for remaining packets
-void ResidualPacketProtection(WebRtc_UWord16 numMediaPackets,
-                              WebRtc_UWord16 numFecPackets,
-                              WebRtc_UWord16 numImpPackets,
-                              WebRtc_UWord16 numMaskBytes,
-                              ResidualProtectionMode mode,
-                              WebRtc_UWord8* packetMask)
+// Remaining protection after important (first partition) packet protection
+void RemainingPacketProtection(WebRtc_UWord16 numMediaPackets,
+                               WebRtc_UWord16 numFecRemaining,
+                               WebRtc_UWord16 numFecForImpPackets,
+                               WebRtc_UWord16 numMaskBytes,
+                               ProtectionMode mode,
+                               WebRtc_UWord8* packetMask)
 {
     if (mode == kModeNoOverlap)
     {
         // subMask21
 
         const WebRtc_UWord8 lBit =
-            (numMediaPackets - numImpPackets) > 16 ? 1 : 0;
+            (numMediaPackets - numFecForImpPackets) > 16 ? 1 : 0;
 
         const WebRtc_UWord16 resMaskBytes =
             (lBit == 1)? kMaskSizeLBitSet : kMaskSizeLBitClear;
 
         const WebRtc_UWord8* packetMaskSub21 =
-            packetMaskTbl[numMediaPackets - numImpPackets - 1]
-                         [numFecPackets - numImpPackets - 1];
+            packetMaskTbl[numMediaPackets - numFecForImpPackets - 1]
+                         [numFecRemaining - 1];
 
-        ShiftFitSubMask(numMaskBytes, resMaskBytes,
-                        numImpPackets, numFecPackets,
+        ShiftFitSubMask(numMaskBytes, resMaskBytes, numFecForImpPackets,
+                        (numFecForImpPackets + numFecRemaining),
                         packetMaskSub21, packetMask);
+
     }
-    else if (mode == kModeOverlap)
+    else if (mode == kModeOverlap || mode == kModeBiasFirstPacket)
     {
         // subMask22
 
-        const WebRtc_UWord16 numFecForResidual =
-            numFecPackets - numImpPackets;
-
         const WebRtc_UWord8* packetMaskSub22 =
-            packetMaskTbl[numMediaPackets - 1]
-                             [numFecForResidual - 1];
+            packetMaskTbl[numMediaPackets - 1][numFecRemaining - 1];
 
-        FitSubMask(numMaskBytes, numMaskBytes,
-                   numFecForResidual,
-                   packetMaskSub22,
-                   &packetMask[numImpPackets * numMaskBytes]);
+        FitSubMask(numMaskBytes, numMaskBytes, numFecRemaining, packetMaskSub22,
+                   &packetMask[numFecForImpPackets * numMaskBytes]);
+
+        if (mode == kModeBiasFirstPacket)
+        {
+            for (WebRtc_UWord32 i = 0; i < numFecRemaining; i++)
+            {
+                WebRtc_UWord32 pktMaskIdx = i * numMaskBytes;
+                packetMask[pktMaskIdx] = packetMask[pktMaskIdx] | (1 << 7);
+            }
+        }
     }
     else
     {
@@ -207,8 +210,8 @@
 
 }
 
-// Higher protection for numImpPackets
-void ImportantPacketProtection(WebRtc_UWord16 numFecPackets,
+// Protection for important (first partition) packets
+void ImportantPacketProtection(WebRtc_UWord16 numFecForImpPackets,
                                WebRtc_UWord16 numImpPackets,
                                WebRtc_UWord16 numMaskBytes,
                                WebRtc_UWord8* packetMask)
@@ -217,73 +220,128 @@
     const WebRtc_UWord16 numImpMaskBytes =
     (lBit == 1)? kMaskSizeLBitSet : kMaskSizeLBitClear;
 
-    WebRtc_UWord32 numFecForImpPackets = numImpPackets;
-    if (numFecPackets < numImpPackets)
-    {
-        numFecForImpPackets = numFecPackets;
-    }
 
     // Get subMask1 from table
     const WebRtc_UWord8* packetMaskSub1 =
     packetMaskTbl[numImpPackets - 1][numFecForImpPackets - 1];
 
     FitSubMask(numMaskBytes, numImpMaskBytes,
-               numFecForImpPackets,
-               packetMaskSub1,
-               packetMask);
+               numFecForImpPackets, packetMaskSub1, packetMask);
 
 }
 
-// Modification for UEP: reuse the tables (designed for equal protection).
-// First version is to build mask from two sub-masks.
-// Longer-term, may add another set of tables for UEP cases for more
-// flexibility in protection between important and residual packets.
+// This function sets the protection allocation: i.e., how many FEC packets
+// to use for numImp (1st partition) packets, given the: number of media
+// packets, number of FEC packets, and number of 1st partition packets.
+WebRtc_UWord32 SetProtectionAllocation(const WebRtc_UWord16 numMediaPackets,
+                                       const WebRtc_UWord16 numFecPackets,
+                                       const WebRtc_UWord16 numImpPackets)
+{
 
-// UEP scheme:
-// First subMask is for higher protection for important packets.
-// Other subMask is the residual protection for remaining packets.
+    // TODO (marpan): test different cases for protection allocation:
+
+    // Use at most (allocPar * numFecPackets) for important packets.
+    float allocPar = 0.5;
+    WebRtc_UWord16 maxNumFecForImp =  static_cast<WebRtc_UWord16>
+                                      (allocPar * numFecPackets);
+
+    WebRtc_UWord16 numFecForImpPackets = (numImpPackets < maxNumFecForImp) ?
+                                          numImpPackets : maxNumFecForImp;
+
+    // Fall back to equal protection in this case
+    if (numFecPackets == 1 && (numMediaPackets > 2 * numImpPackets))
+    {
+        numFecForImpPackets = 0;
+    }
+
+    return numFecForImpPackets;
+}
+
+// Modification for UEP: reuse the off-line tables for the packet masks.
+// Note: these masks were designed for equal packet protection case,
+// assuming random packet loss.
+
+// Current version has 3 modes (options) to build UEP mask from existing ones.
+// Various other combinations may be added in future versions.
+// Longer-term, we may add another set of tables specifically for UEP cases.
+// TODO (marpan): also consider modification of masks for bursty loss cases.
 
 // Mask is characterized as (#packets_to_protect, #fec_for_protection).
-// Protection defined as: (#fec_for_protection / #packets_to_protect).
+// Protection factor defined as: (#fec_for_protection / #packets_to_protect).
 
-// So if k = numMediaPackets, n=total#packets, (n-k)=numFecPackets,
-// and m=numImpPackets, then we will have the following:
+// Let k=numMediaPackets, n=total#packets, (n-k)=numFecPackets, m=numImpPackets.
 
-// For important packets:
-// subMask1 = (m, t): protection = m/(t), where t=min(m,n-k).
+// For ProtectionMode 0 and 1:
+// one mask (subMask1) is used for 1st partition packets,
+// the other mask (subMask21/22, for 0/1) is for the remaining FEC packets.
 
-// For the residual protection, we currently have two options:
+// In both mode 0 and 1, the packets of 1st partition (numImpPackets) are
+// treated equally important, and are afforded more protection than the
+// residual partition packets.
 
-// Mode 0: subMask21 = (k-m,n-k-m): protection = (n-k-m)/(k-m):
-// no protection overlap between the two partitions.
+// For numImpPackets:
+// subMask1 = (m, t): protection = t/(m), where t=F(k,n-k,m).
+// t=F(k,n-k,m) is the number of packets used to protect first partition in
+// subMask1. This is determined from the function SetProtectionAllocation().
 
-// Mode 1: subMask22 = (k, n-k-m), with protection (n-k-m)/(k):
-// some protection overlap between the two partitions.
+// For the left-over protection:
+// Mode 0: subMask21 = (k-m,n-k-t): protection = (n-k-t)/(k-m)
+// mode 0 has no protection overlap between the two partitions.
+// For mode 0, we would typically set t = min(m, n-k).
+
+
+// Mode 1: subMask22 = (k, n-k-t), with protection (n-k-t)/(k)
+// mode 1 has protection overlap between the two partitions (preferred).
+
+// For ProtectionMode 2:
+// This gives 1st packet of list (which is 1st packet of 1st partition) more
+// protection. In mode 2, the equal protection mask (which is obtained from
+// mode 1 for t=0) is modified (more "1s" added in 1st column of packet mask)
+// to bias higher protection for the 1st source packet.
+
+// Protection Mode 2 may be extended for a sort of sliding protection
+// (i.e., vary the number/density of "1s" across columns) across packets.
 
 void UnequalProtectionMask(const WebRtc_UWord16 numMediaPackets,
                            const WebRtc_UWord16 numFecPackets,
                            const WebRtc_UWord16 numImpPackets,
                            const WebRtc_UWord16 numMaskBytes,
-                           const ResidualProtectionMode mode,
                            WebRtc_UWord8* packetMask)
 {
 
-    //
-    // Generate subMask1: higher protection for numImpPackets:
-    //
-    ImportantPacketProtection(numFecPackets, numImpPackets,
-                              numMaskBytes, packetMask);
+    // Set Protection type and allocation
+    // TODO (marpan): test/update for best mode and some combinations thereof.
 
-    //
-    // Generate subMask2: left-over protection (for remaining partition data),
-    // if we still have some some FEC packets
-    //
-    if (numFecPackets > numImpPackets)
+    ProtectionMode mode = kModeOverlap;
+    WebRtc_UWord16 numFecForImpPackets = 0;
+
+    if (mode != kModeBiasFirstPacket)
     {
+        numFecForImpPackets = SetProtectionAllocation(numMediaPackets,
+                                                      numFecPackets,
+                                                      numImpPackets);
+    }
 
-        ResidualPacketProtection(numMediaPackets,numFecPackets,
-                                 numImpPackets, numMaskBytes,
-                                 mode, packetMask);
+    WebRtc_UWord16 numFecRemaining = numFecPackets - numFecForImpPackets;
+    // Done with setting protection type and allocation
+
+    //
+    // Generate subMask1
+    //
+    if (numFecForImpPackets > 0)
+    {
+        ImportantPacketProtection(numFecForImpPackets, numImpPackets,
+                                  numMaskBytes, packetMask);
+    }
+
+    //
+    // Generate subMask2
+    //
+    if (numFecRemaining > 0)
+    {
+        RemainingPacketProtection(numMediaPackets, numFecRemaining,
+                                  numFecForImpPackets, numMaskBytes,
+                                  mode, packetMask);
     }
 
 }
@@ -304,17 +362,10 @@
     const WebRtc_UWord16 numMaskBytes =
         (lBit == 1)? kMaskSizeLBitSet : kMaskSizeLBitClear;
 
-    // Default: use overlap mode for residual protection.
-    const ResidualProtectionMode kResidualProtectionMode = kModeOverlap;
-
-    // Force equal-protection for these cases.
-    // Equal protection is also used for: (numImpPackets == 1 && numFecPackets == 1).
-    // UEP=off would generally be more efficient than the UEP=on for this case.
-    // TODO (marpan): check/test this condition.
-    if (!useUnequalProtection || numImpPackets == 0 ||
-        (numImpPackets == 1 && numFecPackets == 1))
+    // Equal-protection for these cases
+    if (!useUnequalProtection || numImpPackets == 0)
     {
-        // Retrieve corresponding mask table directly: for equal-protection case.
+        // Retrieve corresponding mask table directly:for equal-protection case.
         // 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],
@@ -323,8 +374,7 @@
     else  //UEP case
     {
         UnequalProtectionMask(numMediaPackets, numFecPackets, numImpPackets,
-                              numMaskBytes, kResidualProtectionMode,
-                              packetMask);
+                              numMaskBytes, packetMask);
 
     } // End of UEP modification