func: static void pred_spatial_direct_motion(const H264Context *const h, H264SliceContext *sl,
  
                                         int *mb_type)
  
  {
  
      int b8_stride = 2;
  
      int b4_stride = h->b_stride;
  
      int mb_xy = sl->mb_xy, mb_y = sl->mb_y;
  
      int mb_type_col[2];
  
      const int16_t (*l1mv0)[2], (*l1mv1)[2];
  
      const int8_t *l1ref0, *l1ref1;
  
      const int is_b8x8 = IS_8X8(*mb_type);
  
      unsigned int sub_mb_type = MB_TYPE_L0L1;
  
      int i8, i4;
  
      int ref[2];
  
      int mv[2];
  
      int list;
  
  
  
      assert(sl->ref_list[1][0].reference & 3);
  
  
  
      await_reference_mb_row(h, sl->ref_list[1][0].parent,
  
                             sl->mb_y + !!IS_INTERLACED(*mb_type));
  
  
  
  #define MB_TYPE_16x16_OR_INTRA (MB_TYPE_16x16 | MB_TYPE_INTRA4x4 | \
  
                                  MB_TYPE_INTRA16x16 | MB_TYPE_INTRA_PCM)
  
  
  
      /* ref = min(neighbors) */
  
      for (list = 0; list < 2; list++) {
  
          int left_ref     = sl->ref_cache[list][scan8[0] - 1];
  
          int top_ref      = sl->ref_cache[list][scan8[0] - 8];
  
          int refc         = sl->ref_cache[list][scan8[0] - 8 + 4];
  
          const int16_t *C = sl->mv_cache[list][scan8[0]  - 8 + 4];
  
          if (refc == PART_NOT_AVAILABLE) {
  
              refc = sl->ref_cache[list][scan8[0] - 8 - 1];
  
              C    = sl->mv_cache[list][scan8[0]  - 8 - 1];
  
          }
  
          ref[list] = FFMIN3((unsigned)left_ref,
  
                             (unsigned)top_ref,
  
                             (unsigned)refc);
  
          if (ref[list] >= 0) {
  
              /* This is just pred_motion() but with the cases removed that
  
               * cannot happen for direct blocks. */
  
              const int16_t *const A = sl->mv_cache[list][scan8[0] - 1];
  
              const int16_t *const B = sl->mv_cache[list][scan8[0] - 8];
  
  
  
              int match_count = (left_ref == ref[list]) +
  
                                (top_ref  == ref[list]) +
  
                                (refc     == ref[list]);
  
  
  
              if (match_count > 1) { // most common
  
                  mv[list] = pack16to32(mid_pred(A[0], B[0], C[0]),
  
                                        mid_pred(A[1], B[1], C[1]));
  
              } else {
  
                  assert(match_count == 1);
  
                  if (left_ref == ref[list])
  
                      mv[list] = AV_RN32A(A);
  
                  else if (top_ref == ref[list])
  
                      mv[list] = AV_RN32A(B);
  
                  else
  
                      mv[list] = AV_RN32A(C);
  
              }
  
          } else {
  
              int mask = ~(MB_TYPE_L0 << (2 * list));
  
              mv[list]  = 0;
  
              ref[list] = -1;
  
              if (!is_b8x8)
  
                  *mb_type &= mask;
  
              sub_mb_type &= mask;
  
          }
  
      }
  
      if (ref[0] < 0 && ref[1] < 0) {
  
          ref[0] = ref[1] = 0;
  
          if (!is_b8x8)
  
              *mb_type |= MB_TYPE_L0L1;
  
          sub_mb_type |= MB_TYPE_L0L1;
  
      }
  
  
  
      if (!(is_b8x8 | mv[0] | mv[1])) {
  
          fill_rectangle(&sl->ref_cache[0][scan8[0]], 4, 4, 8, (uint8_t)ref[0], 1);
  
          fill_rectangle(&sl->ref_cache[1][scan8[0]], 4, 4, 8, (uint8_t)ref[1], 1);
  
          fill_rectangle(&sl->mv_cache[0][scan8[0]], 4, 4, 8, 0, 4);
  
          fill_rectangle(&sl->mv_cache[1][scan8[0]], 4, 4, 8, 0, 4);
  
          *mb_type = (*mb_type & ~(MB_TYPE_8x8 | MB_TYPE_16x8 | MB_TYPE_8x16 |
  
                                   MB_TYPE_P1L0 | MB_TYPE_P1L1)) |
  
                     MB_TYPE_16x16 | MB_TYPE_DIRECT2;
  
          return;
  
      }
  
  
  
      if (IS_INTERLACED(sl->ref_list[1][0].parent->mb_type[mb_xy])) { // AFL/AFR/FR/FL -> AFL/FL
  
          if (!IS_INTERLACED(*mb_type)) {                    //     AFR/FR    -> AFL/FL
  
              mb_y  = (sl->mb_y & ~1) + sl->col_parity;
  
              mb_xy = sl->mb_x +
  
                      ((sl->mb_y & ~1) + sl->col_parity) * h->mb_stride;
  
              b8_stride = 0;
  
          } else {
  
              mb_y  += sl->col_fieldoff;
  
              mb_xy += h->mb_stride * sl->col_fieldoff; // non-zero for FL -> FL & differ parity
  
          }
  
          goto single_col;
  
      } else {                                             // AFL/AFR/FR/FL -> AFR/FR
  
          if (IS_INTERLACED(*mb_type)) {                   // AFL       /FL -> AFR/FR
  
              mb_y           =  sl->mb_y & ~1;
  
              mb_xy          = (sl->mb_y & ~1) * h->mb_stride + sl->mb_x;
  
              mb_type_col[0] = sl->ref_list[1][0].parent->mb_type[mb_xy];
  
              mb_type_col[1] = sl->ref_list[1][0].parent->mb_type[mb_xy + h->mb_stride];
  
              b8_stride      = 2 + 4 * h->mb_stride;
  
              b4_stride     *= 6;
  
              if (IS_INTERLACED(mb_type_col[0]) !=
  
                  IS_INTERLACED(mb_type_col[1])) {
  
                  mb_type_col[0] &= ~MB_TYPE_INTERLACED;
  
                  mb_type_col[1] &= ~MB_TYPE_INTERLACED;
  
              }
  
  
  
              sub_mb_type |= MB_TYPE_16x16 | MB_TYPE_DIRECT2; /* B_SUB_8x8 */
  
              if ((mb_type_col[0] & MB_TYPE_16x16_OR_INTRA) &&
  
                  (mb_type_col[1] & MB_TYPE_16x16_OR_INTRA) &&
  
                  !is_b8x8) {
  
                  *mb_type |= MB_TYPE_16x8 | MB_TYPE_DIRECT2;  /* B_16x8 */
  
              } else {
  
                  *mb_type |= MB_TYPE_8x8;
  
              }
  
          } else {                                         //     AFR/FR    -> AFR/FR
  
  single_col:
  
              mb_type_col[0] =
  
              mb_type_col[1] = sl->ref_list[1][0].parent->mb_type[mb_xy];
  
  
  
              sub_mb_type |= MB_TYPE_16x16 | MB_TYPE_DIRECT2; /* B_SUB_8x8 */
  
              if (!is_b8x8 && (mb_type_col[0] & MB_TYPE_16x16_OR_INTRA)) {
  
                  *mb_type |= MB_TYPE_16x16 | MB_TYPE_DIRECT2; /* B_16x16 */
  
              } else if (!is_b8x8 &&
  
                         (mb_type_col[0] & (MB_TYPE_16x8 | MB_TYPE_8x16))) {
  
                  *mb_type |= MB_TYPE_DIRECT2 |
  
                              (mb_type_col[0] & (MB_TYPE_16x8 | MB_TYPE_8x16));
  
              } else {
  
                  if (!h->sps.direct_8x8_inference_flag) {
  
                      /* FIXME: Save sub mb types from previous frames (or derive
  
                       * from MVs) so we know exactly what block size to use. */
  
                      sub_mb_type += (MB_TYPE_8x8 - MB_TYPE_16x16); /* B_SUB_4x4 */
  
                  }
  
                  *mb_type |= MB_TYPE_8x8;
  
              }
  
          }
  
      }
  
  
  
      await_reference_mb_row(h, sl->ref_list[1][0].parent, mb_y);
  
  
  
      l1mv0  = &sl->ref_list[1][0].parent->motion_val[0][h->mb2b_xy[mb_xy]];
  
      l1mv1  = &sl->ref_list[1][0].parent->motion_val[1][h->mb2b_xy[mb_xy]];
  
      l1ref0 = &sl->ref_list[1][0].parent->ref_index[0][4 * mb_xy];
  
      l1ref1 = &sl->ref_list[1][0].parent->ref_index[1][4 * mb_xy];
  
      if (!b8_stride) {
  
          if (sl->mb_y & 1) {
  
              l1ref0 += 2;
  
              l1ref1 += 2;
  
              l1mv0  += 2 * b4_stride;
  
              l1mv1  += 2 * b4_stride;
  
          }
  
      }
  
  
  
      if (IS_INTERLACED(*mb_type) != IS_INTERLACED(mb_type_col[0])) {
  
          int n = 0;
  
          for (i8 = 0; i8 < 4; i8++) {
  
              int x8  = i8 & 1;
  
              int y8  = i8 >> 1;
  
              int xy8 = x8     + y8 * b8_stride;
  
              int xy4 = x8 * 3 + y8 * b4_stride;
  
              int a, b;
  
  
  
              if (is_b8x8 && !IS_DIRECT(sl->sub_mb_type[i8]))
  
                  continue;
  
              sl->sub_mb_type[i8] = sub_mb_type;
  
  
  
              fill_rectangle(&sl->ref_cache[0][scan8[i8 * 4]], 2, 2, 8,
  
                             (uint8_t)ref[0], 1);
  
              fill_rectangle(&sl->ref_cache[1][scan8[i8 * 4]], 2, 2, 8,
  
                             (uint8_t)ref[1], 1);
  
              if (!IS_INTRA(mb_type_col[y8]) && !sl->ref_list[1][0].parent->long_ref &&
  
                  ((l1ref0[xy8] == 0 &&
  
                    FFABS(l1mv0[xy4][0]) <= 1 &&
  
                    FFABS(l1mv0[xy4][1]) <= 1) ||
  
                   (l1ref0[xy8] < 0 &&
  
                    l1ref1[xy8] == 0 &&
  
                    FFABS(l1mv1[xy4][0]) <= 1 &&
  
                    FFABS(l1mv1[xy4][1]) <= 1))) {
  
                  a =
  
                  b = 0;
  
                  if (ref[0] > 0)
  
                      a = mv[0];
  
                  if (ref[1] > 0)
  
                      b = mv[1];
  
                  n++;
  
              } else {
  
                  a = mv[0];
  
                  b = mv[1];
  
              }
  
              fill_rectangle(&sl->mv_cache[0][scan8[i8 * 4]], 2, 2, 8, a, 4);
  
              fill_rectangle(&sl->mv_cache[1][scan8[i8 * 4]], 2, 2, 8, b, 4);
  
          }
  
          if (!is_b8x8 && !(n & 3))
  
              *mb_type = (*mb_type & ~(MB_TYPE_8x8 | MB_TYPE_16x8 | MB_TYPE_8x16 |
  
                                       MB_TYPE_P1L0 | MB_TYPE_P1L1)) |
  
                         MB_TYPE_16x16 | MB_TYPE_DIRECT2;
  
      } else if (IS_16X16(*mb_type)) {
  
          int a, b;
  
  
  
          fill_rectangle(&sl->ref_cache[0][scan8[0]], 4, 4, 8, (uint8_t)ref[0], 1);
  
          fill_rectangle(&sl->ref_cache[1][scan8[0]], 4, 4, 8, (uint8_t)ref[1], 1);
  
          if (!IS_INTRA(mb_type_col[0]) && !sl->ref_list[1][0].parent->long_ref &&
  
              ((l1ref0[0] == 0 &&
  
                FFABS(l1mv0[0][0]) <= 1 &&
  
                FFABS(l1mv0[0][1]) <= 1) ||
  
               (l1ref0[0] < 0 && !l1ref1[0] &&
  
                FFABS(l1mv1[0][0]) <= 1 &&
  
                FFABS(l1mv1[0][1]) <= 1 &&
  
                h->x264_build > 33U))) {
  
              a = b = 0;
  
              if (ref[0] > 0)
  
                  a = mv[0];
  
              if (ref[1] > 0)
  
                  b = mv[1];
  
          } else {
  
              a = mv[0];
  
              b = mv[1];
  
          }
  
          fill_rectangle(&sl->mv_cache[0][scan8[0]], 4, 4, 8, a, 4);
  
          fill_rectangle(&sl->mv_cache[1][scan8[0]], 4, 4, 8, b, 4);
  
      } else {
  
          int n = 0;
  
          for (i8 = 0; i8 < 4; i8++) {
  
              const int x8 = i8 & 1;
  
              const int y8 = i8 >> 1;
  
  
  
              if (is_b8x8 && !IS_DIRECT(sl->sub_mb_type[i8]))
  
                  continue;
  
              sl->sub_mb_type[i8] = sub_mb_type;
  
  
  
              fill_rectangle(&sl->mv_cache[0][scan8[i8 * 4]], 2, 2, 8, mv[0], 4);
  
              fill_rectangle(&sl->mv_cache[1][scan8[i8 * 4]], 2, 2, 8, mv[1], 4);
  
              fill_rectangle(&sl->ref_cache[0][scan8[i8 * 4]], 2, 2, 8,
  
                             (uint8_t)ref[0], 1);
  
              fill_rectangle(&sl->ref_cache[1][scan8[i8 * 4]], 2, 2, 8,
  
                             (uint8_t)ref[1], 1);
  
  
  
              assert(b8_stride == 2);
  
              /* col_zero_flag */
  
              if (!IS_INTRA(mb_type_col[0]) && !sl->ref_list[1][0].parent->long_ref &&
  
                  (l1ref0[i8] == 0 ||
  
                   (l1ref0[i8] < 0 &&
  
                    l1ref1[i8] == 0 &&
  
                    h->x264_build > 33U))) {
  
                  const int16_t (*l1mv)[2] = l1ref0[i8] == 0 ? l1mv0 : l1mv1;
  
                  if (IS_SUB_8X8(sub_mb_type)) {
  
                      const int16_t *mv_col = l1mv[x8 * 3 + y8 * 3 * b4_stride];
  
                      if (FFABS(mv_col[0]) <= 1 && FFABS(mv_col[1]) <= 1) {
  
                          if (ref[0] == 0)
  
                              fill_rectangle(&sl->mv_cache[0][scan8[i8 * 4]], 2, 2,
  
                                             8, 0, 4);
  
                          if (ref[1] == 0)
  
                              fill_rectangle(&sl->mv_cache[1][scan8[i8 * 4]], 2, 2,
  
                                             8, 0, 4);
  
                          n += 4;
  
                      }
  
                  } else {
  
                      int m = 0;
  
                      for (i4 = 0; i4 < 4; i4++) {
  
                          const int16_t *mv_col = l1mv[x8 * 2 + (i4 & 1) +
  
                                                       (y8 * 2 + (i4 >> 1)) * b4_stride];
  
                          if (FFABS(mv_col[0]) <= 1 && FFABS(mv_col[1]) <= 1) {
  
                              if (ref[0] == 0)
  
                                  AV_ZERO32(sl->mv_cache[0][scan8[i8 * 4 + i4]]);
  
                              if (ref[1] == 0)
  
                                  AV_ZERO32(sl->mv_cache[1][scan8[i8 * 4 + i4]]);
  
                              m++;
  
                          }
  
                      }
  
                      if (!(m & 3))
  
                          sl->sub_mb_type[i8] += MB_TYPE_16x16 - MB_TYPE_8x8;
  
                      n += m;
  
                  }
  
              }
  
          }
  
          if (!is_b8x8 && !(n & 15))
  
              *mb_type = (*mb_type & ~(MB_TYPE_8x8 | MB_TYPE_16x8 | MB_TYPE_8x16 |
  
                                       MB_TYPE_P1L0 | MB_TYPE_P1L1)) |
  
                         MB_TYPE_16x16 | MB_TYPE_DIRECT2;
  
      }
  
  }
  