shithub: openh264

Download patch

ref: cc92c7db21c36e2e3ce9dd62c219f9d2e2a2b9c1
parent: 885b31f2f6986ea7b98cf766c291a3477ce75b62
parent: 4f0b2d17e5169325ab2d5f2cd74765269631bb80
author: huili2 <huili2@cisco.com>
date: Mon Sep 7 05:38:42 EDT 2020

Merge pull request #3315 from xiaotianshi2/issue_3269_b_frame_deblocking

fix issue 3269: Boundary strength is incorrect for P16x16 in B-Frame.

--- a/codec/decoder/core/src/deblocking.cpp
+++ b/codec/decoder/core/src/deblocking.cpp
@@ -62,6 +62,30 @@
     ( WELS_ABS( iMotionVector[iMbXy][iIndex][1] - iMotionVector[iMbBn][iNeighIndex][1] ) >= 4 )\
 )
 
+#define ON_MB_BS_MV_DIFF(iMV_A, iMV_B, iMbXy, iMbBn, iIndex, iNeighIndex) \
+(\
+    (( WELS_ABS( iMV_A[iMbXy][iIndex][0] - iMV_B[iMbBn][iNeighIndex][0] ) >= 4 ) || \
+    ( WELS_ABS( iMV_A[iMbXy][iIndex][1] - iMV_B[iMbBn][iNeighIndex][1] ) >= 4 ))\
+)
+
+#define IN_MB_BS_MV_DIFF(iMV_A, iMV_B, iMbXy, iIndex, iNeighIndex) \
+(\
+    (( WELS_ABS( iMV_A[iMbXy][iIndex][0] - iMV_B[iMbXy][iNeighIndex][0] ) >= 4 ) | \
+    ( WELS_ABS( iMV_A[iMbXy][iIndex][1] - iMV_B[iMbXy][iNeighIndex][1] )  >= 4 )) \
+)
+
+//On MB Boundary strength
+//Apply for B_SLICE
+#define ON_MB_BS(ref_p0, ref_q0, ref_p1, ref_q1, mv0, mv1, iMbXy, iMbBn, iIndex, iNeighIndex) \
+(\
+  (ref_p0 != ref_p1) ? \
+  ((ref_p0 == ref_q0) ? \
+  (ON_MB_BS_MV_DIFF (mv0, mv0, iMbXy, iMbBn, iIndex, iNeighIndex) || ON_MB_BS_MV_DIFF (mv1, mv1, iMbXy, iMbBn, iIndex, iNeighIndex)) : \
+  (ON_MB_BS_MV_DIFF (mv0, mv1, iMbXy, iMbBn, iIndex, iNeighIndex) || ON_MB_BS_MV_DIFF (mv1, mv0, iMbXy, iMbBn, iIndex, iNeighIndex))) : \
+  ((ON_MB_BS_MV_DIFF (mv0, mv0, iMbXy, iMbBn, iIndex, iNeighIndex) || ON_MB_BS_MV_DIFF (mv1, mv1, iMbXy, iMbBn, iIndex, iNeighIndex)) && \
+  (ON_MB_BS_MV_DIFF (mv0, mv1, iMbXy, iMbBn, iIndex, iNeighIndex) || ON_MB_BS_MV_DIFF (mv1, mv0, iMbXy, iMbBn, iIndex, iNeighIndex))) \
+)
+
 #if defined(SAME_MB_DIFF_REFIDX)
 #define SMB_EDGE_MV(pRefPics, iMotionVector, iIndex, iNeighIndex) \
 (\
@@ -76,9 +100,40 @@
 )
 #endif
 
+#if defined(SAME_MB_DIFF_REFIDX)
+#define IN_SMB_EDGE_MV(refs, mv, iMbXy, iIndex, iNeigborIndex) \
+(\
+  (((refs[LIST_0][iIndex] == refs[LIST_0][iNeigborIndex]) && (refs[LIST_1][iIndex] == refs[LIST_1][iNeigborIndex])) || \
+  ((refs[LIST_0][iIndex] == refs[LIST_1][iNeigborIndex]) && (refs[LIST_1][iIndex] == refs[LIST_0][iNeigborIndex]))) ? \
+  ((refs[LIST_0][iIndex] != refs[LIST_1][iIndex]) ? \
+  ((refs[LIST_0][iIndex] == refs[LIST_0][iNeigborIndex]) ? \
+  (IN_MB_BS_MV_DIFF (mv[LIST_0], mv[LIST_0], iMbXy, iIndex, iNeigborIndex) | IN_MB_BS_MV_DIFF (mv[LIST_1], mv[LIST_1], iMbXy, iIndex, iNeigborIndex)) : \
+  (IN_MB_BS_MV_DIFF (mv[LIST_0], mv[LIST_1], iMbXy, iIndex, iNeigborIndex) | IN_MB_BS_MV_DIFF (mv[LIST_1], mv[LIST_0], iMbXy, iIndex, iNeigborIndex))) : \
+  ((IN_MB_BS_MV_DIFF (mv[LIST_0], mv[LIST_0], iMbXy, iIndex, iNeigborIndex) | IN_MB_BS_MV_DIFF (mv[LIST_1], mv[LIST_1], iMbXy, iIndex, iNeigborIndex)) && \
+  (IN_MB_BS_MV_DIFF (mv[LIST_0], mv[LIST_1], iMbXy, iIndex, iNeigborIndex) | IN_MB_BS_MV_DIFF (mv[LIST_1], mv[LIST_0], iMbXy, iIndex, iNeigborIndex)))) : 1 \
+)
+#else
+#define IN_SMB_EDGE_MV(refs, mv, iMbXy, iIndex, iNeigborIndex) \
+(\
+  !!(((refs[LIST_0][iIndex] == refs[LIST_0][iNeigborIndex]) && (refs[LIST_1][iIndex] == refs[LIST_1][iNeigborIndex])) || \
+  ((refs[LIST_0][iIndex] == refs[LIST_1][iNeigborIndex]) && (refs[LIST_1][iIndex] == refs[LIST_0][iNeigborIndex]))) ? \
+  ((refs[LIST_0][iIndex] != refs[LIST_1][iIndex]) ? \
+  ((refs[LIST_0][iIndex] == refs[LIST_0][iNeigborIndex]) ? \
+  (IN_MB_BS_MV_DIFF (mv[LIST_0], mv[LIST_0], iMbXy, iIndex, iNeigborIndex) | IN_MB_BS_MV_DIFF (mv[LIST_1], mv[LIST_1], iMbXy, iIndex, iNeigborIndex)) : \
+  (IN_MB_BS_MV_DIFF (mv[LIST_0], mv[LIST_1], iMbXy, iIndex, iNeigborIndex) | IN_MB_BS_MV_DIFF (mv[LIST_1], mv[LIST_0], iMbXy, iIndex, iNeigborIndex))) : \
+  ((IN_MB_BS_MV_DIFF (mv[LIST_0], mv[LIST_0], iMbXy, iIndex, iNeigborIndex) | IN_MB_BS_MV_DIFF (mv[LIST_1], mv[LIST_1], iMbXy, iIndex, iNeigborIndex)) && \
+  (IN_MB_BS_MV_DIFF (mv[LIST_0], mv[LIST_1], iMbXy, iIndex, iNeigborIndex) | IN_MB_BS_MV_DIFF (mv[LIST_1], mv[LIST_0], iMbXy, iIndex, iNeigborIndex)))) : 1 \
+)
+#endif
+
 #define BS_EDGE(bsx1, pRefPics, iMotionVector, iIndex, iNeighIndex) \
 ( (bsx1|SMB_EDGE_MV(pRefPics, iMotionVector, iIndex, iNeighIndex))<<((uint8_t)(!!bsx1)))
 
+//Inside MB Boundary strength
+//Apply for B_SLICE
+#define IN_BS_EDGE(bsx1, refs, mv, iMbXy, iIndex, iNeigborIndex) \
+( (bsx1|IN_SMB_EDGE_MV(refs, mv, iMbXy, iIndex, iNeigborIndex))<<((uint8_t)(!!bsx1)))
+
 #define GET_ALPHA_BETA_FROM_QP(iQp, iAlphaOffset, iBetaOffset, iIndex, iAlpha, iBeta) \
 {\
   iIndex = (iQp + iAlphaOffset);\
@@ -319,51 +374,23 @@
     //vertical
     int8_t iIndex = g_kuiMbCountScan4Idx[1 << 2];
     int8_t iNeigborIndex = g_kuiMbCountScan4Idx[0];
-    nBS[0][2][0] = nBS[0][2][1] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][iIndex] && iRefs[listIdx][iNeigborIndex]) {
-        nBS[0][2][0] = nBS[0][2][1] = BS_EDGE ((i8x8NnzTab[0] | i8x8NnzTab[1]), iRefs[listIdx],
-                                               pCurDqLayer->pDec->pMv[listIdx][iMbXy],
-                                               iIndex, iNeigborIndex);
-        break;
-      }
-    }
+    nBS[0][2][0] = nBS[0][2][1] = IN_BS_EDGE ((i8x8NnzTab[0] | i8x8NnzTab[1]), iRefs, pCurDqLayer->pDec->pMv, iMbXy,
+                                  iIndex, iNeigborIndex);
     iIndex = g_kuiMbCountScan4Idx[3 << 2];
     iNeigborIndex = g_kuiMbCountScan4Idx[2 << 2];
-    nBS[0][2][2] = nBS[0][2][3] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][iIndex] && iRefs[listIdx][iNeigborIndex]) {
-        nBS[0][2][2] = nBS[0][2][3] = BS_EDGE ((i8x8NnzTab[2] | i8x8NnzTab[3]), iRefs[listIdx],
-                                               pCurDqLayer->pDec->pMv[listIdx][iMbXy],
-                                               iIndex, iNeigborIndex);
-        break;
-      }
-    }
+    nBS[0][2][2] = nBS[0][2][3] = IN_BS_EDGE ((i8x8NnzTab[2] | i8x8NnzTab[3]), iRefs, pCurDqLayer->pDec->pMv, iMbXy,
+                                  iIndex, iNeigborIndex);
 
     //horizontal
     iIndex = g_kuiMbCountScan4Idx[2 << 2];
     iNeigborIndex = g_kuiMbCountScan4Idx[0];
-    nBS[1][2][0] = nBS[1][2][1] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][iIndex] && iRefs[listIdx][iNeigborIndex]) {
-        nBS[1][2][0] = nBS[1][2][1] = BS_EDGE ((i8x8NnzTab[0] | i8x8NnzTab[2]), iRefs[listIdx],
-                                               pCurDqLayer->pDec->pMv[listIdx][iMbXy],
-                                               iIndex, iNeigborIndex);
-        break;
-      }
-    }
+    nBS[1][2][0] = nBS[1][2][1] = IN_BS_EDGE ((i8x8NnzTab[0] | i8x8NnzTab[2]), iRefs, pCurDqLayer->pDec->pMv, iMbXy,
+                                  iIndex, iNeigborIndex);
 
     iIndex = g_kuiMbCountScan4Idx[3 << 2];
     iNeigborIndex = g_kuiMbCountScan4Idx[1 << 2];
-    nBS[1][2][2] = nBS[1][2][3] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][iIndex] && iRefs[listIdx][iNeigborIndex]) {
-        nBS[1][2][2] = nBS[1][2][3] = BS_EDGE ((i8x8NnzTab[1] | i8x8NnzTab[3]), iRefs[listIdx],
-                                               pCurDqLayer->pDec->pMv[listIdx][iMbXy],
-                                               iIndex, iNeigborIndex);
-        break;
-      }
-    }
+    nBS[1][2][2] = nBS[1][2][3] = IN_BS_EDGE ((i8x8NnzTab[1] | i8x8NnzTab[3]), iRefs, pCurDqLayer->pDec->pMv, iMbXy,
+                                  iIndex, iNeigborIndex);
   } else {
     uiNnz32b0 = * (uint32_t*) (pNnzTab + 0);
     uiNnz32b1 = * (uint32_t*) (pNnzTab + 4);
@@ -372,190 +399,51 @@
 
     for (int i = 0; i < 3; i++)
       uiBsx4[i] = pNnzTab[i] | pNnzTab[i + 1];
-    nBS[0][1][0] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][1] && iRefs[listIdx][0]) {
-        nBS[0][1][0] = BS_EDGE (uiBsx4[0], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 1, 0);
-        break;
-      }
-    }
-    nBS[0][2][0] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][2] && iRefs[listIdx][1]) {
-        nBS[0][2][0] = BS_EDGE (uiBsx4[1], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 2, 1);
-        break;
-      }
-    }
-    nBS[0][3][0] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][3] && iRefs[listIdx][2]) {
-        nBS[0][3][0] = BS_EDGE (uiBsx4[2], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 3, 2);
-        break;
-      }
-    }
+    nBS[0][1][0] = IN_BS_EDGE (uiBsx4[0], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 1, 0);
+    nBS[0][2][0] = IN_BS_EDGE (uiBsx4[1], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 2, 1);
+    nBS[0][3][0] = IN_BS_EDGE (uiBsx4[2], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 3, 2);
 
     for (int i = 0; i < 3; i++)
       uiBsx4[i] = pNnzTab[4 + i] | pNnzTab[4 + i + 1];
-    nBS[0][1][1] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][5] && iRefs[listIdx][4]) {
-        nBS[0][1][1] = BS_EDGE (uiBsx4[0], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 5, 4);
-        break;
-      }
-    }
-    nBS[0][2][1] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][6] && iRefs[listIdx][5]) {
-        nBS[0][2][1] = BS_EDGE (uiBsx4[1], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 6, 5);
-        break;
-      }
-    }
-    nBS[0][3][1] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][7] && iRefs[listIdx][6]) {
-        nBS[0][3][1] = BS_EDGE (uiBsx4[2], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 7, 6);
-        break;
-      }
-    }
+    nBS[0][1][1] = IN_BS_EDGE (uiBsx4[0], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 5, 4);
+    nBS[0][2][1] = IN_BS_EDGE (uiBsx4[1], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 6, 5);
+    nBS[0][3][1] = IN_BS_EDGE (uiBsx4[2], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 7, 6);
 
     for (int i = 0; i < 3; i++)
       uiBsx4[i] = pNnzTab[8 + i] | pNnzTab[8 + i + 1];
-    nBS[0][1][2] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][9] && iRefs[listIdx][8]) {
-        nBS[0][1][2] = BS_EDGE (uiBsx4[0], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 9, 8);
-        break;
-      }
-    }
-    nBS[0][2][2] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][10] && iRefs[listIdx][9]) {
-        nBS[0][2][2] = BS_EDGE (uiBsx4[1], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 10, 9);
-        break;
-      }
-    }
-    nBS[0][3][2] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][11] && iRefs[listIdx][10]) {
-        nBS[0][3][2] = BS_EDGE (uiBsx4[2], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 11, 10);
-        break;
-      }
-    }
+    nBS[0][1][2] = IN_BS_EDGE (uiBsx4[0], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 9, 8);
+    nBS[0][2][2] = IN_BS_EDGE (uiBsx4[1], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 10, 9);
+    nBS[0][3][2] = IN_BS_EDGE (uiBsx4[2], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 11, 10);
 
     for (int i = 0; i < 3; i++)
       uiBsx4[i] = pNnzTab[12 + i] | pNnzTab[12 + i + 1];
-    nBS[0][1][3] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][13] && iRefs[listIdx][12]) {
-        nBS[0][1][3] = BS_EDGE (uiBsx4[0], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 13, 12);
-        break;
-      }
-    }
-    nBS[0][2][3] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][14] && iRefs[listIdx][13]) {
-        nBS[0][2][3] = BS_EDGE (uiBsx4[1], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 14, 13);
-        break;
-      }
-    }
-    nBS[0][3][3] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][15] && iRefs[listIdx][14]) {
-        nBS[0][3][3] = BS_EDGE (uiBsx4[2], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 15, 14);
-        break;
-      }
-    }
+    nBS[0][1][3] = IN_BS_EDGE (uiBsx4[0], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 13, 12);
+    nBS[0][2][3] = IN_BS_EDGE (uiBsx4[1], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 14, 13);
+    nBS[0][3][3] = IN_BS_EDGE (uiBsx4[2], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 15, 14);
 
     // horizontal
     * (uint32_t*)uiBsx4 = (uiNnz32b0 | uiNnz32b1);
-    nBS[1][1][0] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][4] && iRefs[listIdx][0]) {
-        nBS[1][1][0] = BS_EDGE (uiBsx4[0], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 4, 0);
-        break;
-      }
-    }
-    nBS[1][1][1] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][5] && iRefs[listIdx][1]) {
-        nBS[1][1][1] = BS_EDGE (uiBsx4[1], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 5, 1);
-        break;
-      }
-    }
-    nBS[1][1][2] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][6] && iRefs[listIdx][2]) {
-        nBS[1][1][2] = BS_EDGE (uiBsx4[2], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 6, 2);
-        break;
-      }
-    }
-    nBS[1][1][3] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][7] && iRefs[listIdx][3]) {
-        nBS[1][1][3] = BS_EDGE (uiBsx4[3], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 7, 3);
-        break;
-      }
-    }
+    nBS[1][1][0] = IN_BS_EDGE (uiBsx4[0], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 4, 0);
+    nBS[1][1][1] = IN_BS_EDGE (uiBsx4[1], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 5, 1);
+    nBS[1][1][2] = IN_BS_EDGE (uiBsx4[2], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 6, 2);
+    nBS[1][1][3] = IN_BS_EDGE (uiBsx4[3], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 7, 3);
 
     * (uint32_t*)uiBsx4 = (uiNnz32b1 | uiNnz32b2);
-    nBS[1][2][0] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][8] && iRefs[listIdx][4]) {
-        nBS[1][2][0] = BS_EDGE (uiBsx4[0], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 8, 4);
-        break;
-      }
-    }
-    nBS[1][2][1] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][9] && iRefs[listIdx][5]) {
-        nBS[1][2][1] = BS_EDGE (uiBsx4[1], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 9, 5);
-        break;
-      }
-    }
-    nBS[1][2][2] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][10] && iRefs[listIdx][6]) {
-        nBS[1][2][2] = BS_EDGE (uiBsx4[2], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 10, 6);
-        break;
-      }
-    }
-    nBS[1][2][3] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][11] && iRefs[listIdx][7]) {
-        nBS[1][2][3] = BS_EDGE (uiBsx4[3], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 11, 7);
-        break;
-      }
-    }
+    nBS[1][2][0] = IN_BS_EDGE (uiBsx4[0], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 8, 4);
+    nBS[1][2][1] = IN_BS_EDGE (uiBsx4[1], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 9, 5);
+    nBS[1][2][2] = IN_BS_EDGE (uiBsx4[2], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 10, 6);
+    nBS[1][2][3] = IN_BS_EDGE (uiBsx4[3], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 11, 7);
 
     * (uint32_t*)uiBsx4 = (uiNnz32b2 | uiNnz32b3);
-    nBS[1][3][0] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][12] && iRefs[listIdx][8]) {
-        nBS[1][3][0] = BS_EDGE (uiBsx4[0], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 12, 8);
-        break;
-      }
-    }
-    nBS[1][3][1] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][13] && iRefs[listIdx][9]) {
-        nBS[1][3][1] = BS_EDGE (uiBsx4[1], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 13, 9);
-        break;
-      }
-    }
-    nBS[1][3][2] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][14] && iRefs[listIdx][10]) {
-        nBS[1][3][2] = BS_EDGE (uiBsx4[2], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 14, 10);
-        break;
-      }
-    }
-    nBS[1][3][3] = 1;
-    for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-      if (iRefs[listIdx][15] && iRefs[listIdx][11]) {
-        nBS[1][3][3] = BS_EDGE (uiBsx4[3], iRefs[listIdx], pCurDqLayer->pDec->pMv[listIdx][iMbXy], 15, 11);
-        break;
-      }
-    }
+    nBS[1][3][0] = IN_BS_EDGE (uiBsx4[0], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 12, 8);
+    nBS[1][3][1] = IN_BS_EDGE (uiBsx4[1], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 13, 9);
+    nBS[1][3][2] = IN_BS_EDGE (uiBsx4[2], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 14, 10);
+    nBS[1][3][3] = IN_BS_EDGE (uiBsx4[3], iRefs, pCurDqLayer->pDec->pMv, iMbXy, 15, 11);
+    for (int ii = 0; ii < 2; ii++)
+      for (int jj = 1; jj < 4; jj++)
+        for (int kk = 0; kk < 4; kk++)
+          if (nBS[ii][jj][kk] > 1)
+            nBS[ii][jj][kk] = nBS[ii][jj][kk];
   }
 }
 
@@ -662,7 +550,9 @@
   const uint8_t* pBnIdx = &g_kuiTableBIdx[iEdge][4];
   const uint8_t* pB8x8Idx = &g_kuiTableB8x8Idx[iEdge][0];
   const uint8_t* pBn8x8Idx = &g_kuiTableB8x8Idx[iEdge][8];
-  PPicture ref0, ref1;
+  PPicture ref_p0, ref_p1, ref_q0, ref_q1;
+  int8_t (*iRefIdx0)[MB_BLOCK4x4_NUM] = pCurDqLayer->pDec->pRefIndex[LIST_0];
+  int8_t (*iRefIdx1)[MB_BLOCK4x4_NUM] = pCurDqLayer->pDec->pRefIndex[LIST_1];
 
   if (pCurDqLayer->pTransformSize8x8Flag[iMbXy] && pCurDqLayer->pTransformSize8x8Flag[iNeighMb]) {
     for (i = 0; i < 2; i++) {
@@ -674,16 +564,19 @@
         pBS[i << 1] = pBS[1 + (i << 1)] = 2;
       } else {
         pBS[i << 1] = pBS[1 + (i << 1)] = 1;
-        for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-          if (pCurDqLayer->pDec->pRefIndex[listIdx][iMbXy][*pB8x8Idx] > REF_NOT_IN_LIST
-              && pCurDqLayer->pDec->pRefIndex[listIdx][iMbXy][*pBn8x8Idx] > REF_NOT_IN_LIST) {
-            int8_t (*iRefIdx)[MB_BLOCK4x4_NUM] = pCurDqLayer->pDec->pRefIndex[listIdx];
-            ref0 = pFilter->pRefPics[listIdx][iRefIdx[iMbXy][*pB8x8Idx]];
-            ref1 = pFilter->pRefPics[listIdx][iRefIdx[iNeighMb][*pBn8x8Idx]];
-            pBS[i << 1] = pBS[1 + (i << 1)] = MB_BS_MV (ref0, ref1, pCurDqLayer->pDec->pMv[listIdx], iMbXy, iNeighMb,
-                                              *pB8x8Idx, *pBn8x8Idx);
-            break;
-          }
+        ref_p0 = iRefIdx0[iMbXy][*pB8x8Idx] > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_0][iRefIdx0[iMbXy][*pB8x8Idx]] : NULL;
+        ref_q0 = iRefIdx0[iNeighMb][*pBn8x8Idx]  > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_0][iRefIdx0[iNeighMb][*pBn8x8Idx]] :
+                 NULL;
+        ref_p1 = iRefIdx1[iMbXy][*pB8x8Idx] > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_1][iRefIdx1[iMbXy][*pB8x8Idx]] : NULL;
+        ref_q1 = iRefIdx1[iNeighMb][*pBn8x8Idx]  > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_1][iRefIdx1[iNeighMb][*pBn8x8Idx]] :
+                 NULL;
+        if (((ref_p0 == ref_q0) && (ref_p1 == ref_q1)) || ((ref_p0 == ref_q1) && (ref_p1 == ref_q0))) {
+          int16_t (*pMv0)[MB_BLOCK4x4_NUM][MV_A] = pCurDqLayer->pDec != NULL ? pCurDqLayer->pDec->pMv[LIST_0] :
+              pCurDqLayer->pMv[LIST_0];
+          int16_t (*pMv1)[MB_BLOCK4x4_NUM][MV_A] = pCurDqLayer->pDec != NULL ? pCurDqLayer->pDec->pMv[LIST_1] :
+              pCurDqLayer->pMv[LIST_1];
+          pBS[i << 1] = pBS[1 + (i << 1)] = ON_MB_BS (ref_p0, ref_q0, ref_p1, ref_q1, pMv0, pMv1, iMbXy, iNeighMb, *pB8x8Idx,
+                                            *pBn8x8Idx);
         }
       }
       pB8x8Idx += 4;
@@ -700,16 +593,18 @@
           pBS[j + (i << 1)] = 2;
         } else {
           pBS[j + (i << 1)] = 1;
-          for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-            if (pCurDqLayer->pDec->pRefIndex[listIdx][iMbXy][*pB8x8Idx] > REF_NOT_IN_LIST
-                && pCurDqLayer->pDec->pRefIndex[listIdx][iMbXy][*pBnIdx] > REF_NOT_IN_LIST) {
-              int8_t (*iRefIdx)[MB_BLOCK4x4_NUM] = pCurDqLayer->pDec->pRefIndex[listIdx];
-              ref0 = pFilter->pRefPics[listIdx][iRefIdx[iMbXy][*pB8x8Idx]];
-              ref1 = pFilter->pRefPics[listIdx][iRefIdx[iNeighMb][*pBnIdx]];
-              pBS[j + (i << 1)] = MB_BS_MV (ref0, ref1, pCurDqLayer->pDec->pMv[listIdx], iMbXy, iNeighMb, *pB8x8Idx,
-                                            *pBnIdx);
-              break;
-            }
+          ref_p0 = iRefIdx0[iMbXy][*pB8x8Idx] > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_0][iRefIdx0[iMbXy][*pB8x8Idx]] : NULL;
+          ref_q0 = iRefIdx0[iNeighMb][*pBnIdx]  > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_0][iRefIdx0[iNeighMb][*pBnIdx]] :
+                   NULL;
+          ref_p1 = iRefIdx1[iMbXy][*pB8x8Idx] > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_1][iRefIdx1[iMbXy][*pB8x8Idx]] : NULL;
+          ref_q1 = iRefIdx1[iNeighMb][*pBnIdx]  > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_1][iRefIdx1[iNeighMb][*pBnIdx]] :
+                   NULL;
+          if (((ref_p0 == ref_q0) && (ref_p1 == ref_q1)) || ((ref_p0 == ref_q1) && (ref_p1 == ref_q0))) {
+            int16_t (*pMv0)[MB_BLOCK4x4_NUM][MV_A] = pCurDqLayer->pDec != NULL ? pCurDqLayer->pDec->pMv[LIST_0] :
+                pCurDqLayer->pMv[LIST_0];
+            int16_t (*pMv1)[MB_BLOCK4x4_NUM][MV_A] = pCurDqLayer->pDec != NULL ? pCurDqLayer->pDec->pMv[LIST_1] :
+                pCurDqLayer->pMv[LIST_1];
+            pBS[j + (i << 1)] = ON_MB_BS (ref_p0, ref_q0, ref_p1, ref_q1, pMv0, pMv1, iMbXy, iNeighMb, *pB8x8Idx, *pBnIdx);
           }
         }
         pBnIdx++;
@@ -727,15 +622,18 @@
           pBS[j + (i << 1)] = 2;
         } else {
           pBS[j + (i << 1)] = 1;
-          for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-            if (pCurDqLayer->pDec->pRefIndex[listIdx][iMbXy][*pBIdx] > REF_NOT_IN_LIST
-                && pCurDqLayer->pDec->pRefIndex[listIdx][iMbXy][*pBn8x8Idx] > REF_NOT_IN_LIST) {
-              int8_t (*iRefIdx)[MB_BLOCK4x4_NUM] = pCurDqLayer->pDec->pRefIndex[listIdx];
-              ref0 = pFilter->pRefPics[listIdx][iRefIdx[iMbXy][*pBIdx]];
-              ref1 = pFilter->pRefPics[listIdx][iRefIdx[iNeighMb][*pBn8x8Idx]];
-              pBS[j + (i << 1)] = MB_BS_MV (ref0, ref1, pCurDqLayer->pDec->pMv[listIdx], iMbXy, iNeighMb, *pBIdx, *pBn8x8Idx);
-              break;
-            }
+          ref_p0 = iRefIdx0[iMbXy][*pBIdx] > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_0][iRefIdx0[iMbXy][*pBIdx]] : NULL;
+          ref_q0 = iRefIdx0[iNeighMb][*pBn8x8Idx]  > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_0][iRefIdx0[iNeighMb][*pBn8x8Idx]] :
+                   NULL;
+          ref_p1 = iRefIdx1[iMbXy][*pBIdx] > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_1][iRefIdx1[iMbXy][*pBIdx]] : NULL;
+          ref_q1 = iRefIdx1[iNeighMb][*pBn8x8Idx]  > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_1][iRefIdx1[iNeighMb][*pBn8x8Idx]] :
+                   NULL;
+          if (((ref_p0 == ref_q0) && (ref_p1 == ref_q1)) || ((ref_p0 == ref_q1) && (ref_p1 == ref_q0))) {
+            int16_t (*pMv0)[MB_BLOCK4x4_NUM][MV_A] = pCurDqLayer->pDec != NULL ? pCurDqLayer->pDec->pMv[LIST_0] :
+                pCurDqLayer->pMv[LIST_0];
+            int16_t (*pMv1)[MB_BLOCK4x4_NUM][MV_A] = pCurDqLayer->pDec != NULL ? pCurDqLayer->pDec->pMv[LIST_1] :
+                pCurDqLayer->pMv[LIST_1];
+            pBS[j + (i << 1)] = ON_MB_BS (ref_p0, ref_q0, ref_p1, ref_q1, pMv0, pMv1, iMbXy, iNeighMb, *pBIdx, *pBn8x8Idx);
           }
         }
         pBIdx++;
@@ -749,15 +647,18 @@
         pBS[i] = 2;
       } else {
         pBS[i] = 1;
-        for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
-          if (pCurDqLayer->pDec->pRefIndex[listIdx][iMbXy][*pBIdx] > REF_NOT_IN_LIST
-              && pCurDqLayer->pDec->pRefIndex[listIdx][iMbXy][*pBnIdx] > REF_NOT_IN_LIST) {
-            int8_t (*iRefIdx)[MB_BLOCK4x4_NUM] = pCurDqLayer->pDec->pRefIndex[listIdx];
-            ref0 = pFilter->pRefPics[listIdx][iRefIdx[iMbXy][*pBIdx]];
-            ref1 = pFilter->pRefPics[listIdx][iRefIdx[iNeighMb][*pBnIdx]];
-            pBS[i] = MB_BS_MV (ref0, ref1, pCurDqLayer->pDec->pMv[listIdx], iMbXy, iNeighMb, *pBIdx, *pBnIdx);
-            break;
-          }
+        ref_p0 = iRefIdx0[iMbXy][*pBIdx] > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_0][iRefIdx0[iMbXy][*pBIdx]] : NULL;
+        ref_q0 = iRefIdx0[iNeighMb][*pBnIdx]  > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_0][iRefIdx0[iNeighMb][*pBnIdx]] :
+                 NULL;
+        ref_p1 = iRefIdx1[iMbXy][*pBIdx] > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_1][iRefIdx1[iMbXy][*pBIdx]] : NULL;
+        ref_q1 = iRefIdx1[iNeighMb][*pBnIdx]  > REF_NOT_IN_LIST ? pFilter->pRefPics[LIST_1][iRefIdx1[iNeighMb][*pBnIdx]] :
+                 NULL;
+        if (((ref_p0 == ref_q0) && (ref_p1 == ref_q1)) || ((ref_p0 == ref_q1) && (ref_p1 == ref_q0))) {
+          int16_t (*pMv0)[MB_BLOCK4x4_NUM][MV_A] = pCurDqLayer->pDec != NULL ? pCurDqLayer->pDec->pMv[LIST_0] :
+              pCurDqLayer->pMv[LIST_0];
+          int16_t (*pMv1)[MB_BLOCK4x4_NUM][MV_A] = pCurDqLayer->pDec != NULL ? pCurDqLayer->pDec->pMv[LIST_1] :
+              pCurDqLayer->pMv[LIST_1];
+          pBS[i] = ON_MB_BS (ref_p0, ref_q0, ref_p1, ref_q1, pMv0, pMv1, iMbXy, iNeighMb, *pBIdx, *pBnIdx);
         }
       }
       pBIdx++;
--- a/test/api/decoder_test.cpp
+++ b/test/api/decoder_test.cpp
@@ -76,9 +76,9 @@
   FileParam p = GetParam();
 #if defined(ANDROID_NDK)
   std::string filename = std::string ("/sdcard/") + p.fileName;
-  ASSERT_TRUE ( DecodeFile (filename.c_str(), this));
+  ASSERT_TRUE (DecodeFile (filename.c_str(), this));
 #else
-  ASSERT_TRUE (DecodeFile(p.fileName, this));
+  ASSERT_TRUE (DecodeFile (p.fileName, this));
 #endif
 
   unsigned char digest[SHA_DIGEST_LENGTH];
@@ -130,15 +130,15 @@
   {"res/test_scalinglist_jm.264", "f690a3af2896a53360215fb5d35016bfd41499b3"},
   {"res/test_vd_1d.264", "5827d2338b79ff82cd091c707823e466197281d3"},
   {"res/test_vd_rc.264", "eea02e97bfec89d0418593a8abaaf55d02eaa1ca"},
-  {"res/Cisco_Men_whisper_640x320_CABAC_Bframe_9.264", "88b8864a69cee7656202bc54d2ffa8b7b6f1f6c5"},
-  {"res/Cisco_Men_whisper_640x320_CAVLC_Bframe_9.264", "270a500d2f91c9e2c8ffabc03f62e0dc0b3a24ed"},
-  {"res/Cisco_Adobe_PDF_sample_a_1024x768_CAVLC_Bframe_9.264", "d3b2b986178ce3eafa806cd984543d0da830f408"},
-  {"res/VID_1280x544_cabac_temporal_direct.264", "8d946d46a8cb248269c4294203397daed8dace1d"},
-  {"res/VID_1280x720_cabac_temporal_direct.264", "419faadd8362918e6d908addd3e92fddb925624a"},
-  {"res/VID_1920x1080_cabac_temporal_direct.264", "2c93dc4ea4617636d2554c68896ce3ba16d678e7"},
-  {"res/VID_1280x544_cavlc_temporal_direct.264", "c89756e76e57c6a84cc55146b18845d4d24e4cd5"},
-  {"res/VID_1280x720_cavlc_temporal_direct.264", "be1af190f5eba34102a9de42917c8ec50073c5a0"},
-  {"res/VID_1920x1080_cavlc_temporal_direct.264", "6c58378bc51beb909381e634700706737fd17be2"},
+  {"res/Cisco_Men_whisper_640x320_CABAC_Bframe_9.264", "931ba1caf075e7b47445c1f4410ade77a46048f6"},
+  {"res/Cisco_Men_whisper_640x320_CAVLC_Bframe_9.264", "9819c0345abdd4faedbaf8f8c4dadb7749515e4d"},
+  {"res/Cisco_Adobe_PDF_sample_a_1024x768_CAVLC_Bframe_9.264", "9d758d9e6f4dead0d7b361f3ddf2ee009d0ea190"},
+  {"res/VID_1280x544_cabac_temporal_direct.264", "b7f04399f38a90c866f0b518d1dd93c823d5d91f"},
+  {"res/VID_1280x720_cabac_temporal_direct.264", "dabc1d0d44921a5c72ed2d4fde1d602465249c97"},
+  {"res/VID_1920x1080_cabac_temporal_direct.264", "6e719adb650cee4ca99a45242685d261257c04cc"},
+  {"res/VID_1280x544_cavlc_temporal_direct.264", "33bfa44b4a3c87fe28354cace1d4b99a03d2967d"},
+  {"res/VID_1280x720_cavlc_temporal_direct.264", "4face6b5d73a378b6e564a831b49311c230158e4"},
+  {"res/VID_1920x1080_cavlc_temporal_direct.264", "b35dc99604ea2a1fda5b84d1b9098cb7565dec8f"},
 };
 
 INSTANTIATE_TEST_CASE_P (DecodeFile, DecoderOutputTest,