aboutsummaryrefslogtreecommitdiff
path: root/src/dsp/motion_field_projection.cc
blob: b51ec8f72706c39bd7c29f289d95d456fe297bdc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2020 The libgav1 Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "src/dsp/motion_field_projection.h"

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>

#include "src/dsp/dsp.h"
#include "src/utils/common.h"
#include "src/utils/constants.h"
#include "src/utils/reference_info.h"
#include "src/utils/types.h"

namespace libgav1 {
namespace dsp {
namespace {

// Silence unused function warnings when MotionFieldProjectionKernel_C is
// not used.
#if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS ||                      \
    !defined(LIBGAV1_Dsp8bpp_MotionFieldProjectionKernel) || \
    (LIBGAV1_MAX_BITDEPTH >= 10 &&                           \
     !defined(LIBGAV1_Dsp10bpp_MotionFieldProjectionKernel))

// 7.9.2.
void MotionFieldProjectionKernel_C(const ReferenceInfo& reference_info,
                                   int reference_to_current_with_sign,
                                   int dst_sign, int y8_start, int y8_end,
                                   int x8_start, int x8_end,
                                   TemporalMotionField* motion_field) {
  const ptrdiff_t stride = motion_field->mv.columns();
  // The column range has to be offset by kProjectionMvMaxHorizontalOffset since
  // coordinates in that range could end up being position_x8 because of
  // projection.
  const int adjusted_x8_start =
      std::max(x8_start - kProjectionMvMaxHorizontalOffset, 0);
  const int adjusted_x8_end = std::min(
      x8_end + kProjectionMvMaxHorizontalOffset, static_cast<int>(stride));
  const int8_t* const reference_offsets =
      reference_info.relative_distance_to.data();
  const bool* const skip_references = reference_info.skip_references.data();
  const int16_t* const projection_divisions =
      reference_info.projection_divisions.data();
  const ReferenceFrameType* source_reference_types =
      &reference_info.motion_field_reference_frame[y8_start][0];
  const MotionVector* mv = &reference_info.motion_field_mv[y8_start][0];
  int8_t* dst_reference_offset = motion_field->reference_offset[y8_start];
  MotionVector* dst_mv = motion_field->mv[y8_start];
  assert(stride == motion_field->reference_offset.columns());
  assert((y8_start & 7) == 0);

  int y8 = y8_start;
  do {
    const int y8_floor = (y8 & ~7) - y8;
    const int y8_ceiling = std::min(y8_end - y8, y8_floor + 8);
    int x8 = adjusted_x8_start;
    do {
      const int source_reference_type = source_reference_types[x8];
      if (skip_references[source_reference_type]) continue;
      MotionVector projection_mv;
      // reference_to_current_with_sign could be 0.
      GetMvProjection(mv[x8], reference_to_current_with_sign,
                      projection_divisions[source_reference_type],
                      &projection_mv);
      // Do not update the motion vector if the block position is not valid or
      // if position_x8 is outside the current range of x8_start and x8_end.
      // Note that position_y8 will always be within the range of y8_start and
      // y8_end.
      const int position_y8 = Project(0, projection_mv.mv[0], dst_sign);
      if (position_y8 < y8_floor || position_y8 >= y8_ceiling) continue;
      const int x8_base = x8 & ~7;
      const int x8_floor =
          std::max(x8_start, x8_base - kProjectionMvMaxHorizontalOffset);
      const int x8_ceiling =
          std::min(x8_end, x8_base + 8 + kProjectionMvMaxHorizontalOffset);
      const int position_x8 = Project(x8, projection_mv.mv[1], dst_sign);
      if (position_x8 < x8_floor || position_x8 >= x8_ceiling) continue;
      dst_mv[position_y8 * stride + position_x8] = mv[x8];
      dst_reference_offset[position_y8 * stride + position_x8] =
          reference_offsets[source_reference_type];
    } while (++x8 < adjusted_x8_end);
    source_reference_types += stride;
    mv += stride;
    dst_reference_offset += stride;
    dst_mv += stride;
  } while (++y8 < y8_end);
}

#endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS ||
        // !defined(LIBGAV1_Dsp8bpp_MotionFieldProjectionKernel) ||
        // (LIBGAV1_MAX_BITDEPTH >= 10 &&
        //  !defined(LIBGAV1_Dsp10bpp_MotionFieldProjectionKernel))

void Init8bpp() {
#if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS || \
    !defined(LIBGAV1_Dsp8bpp_MotionFieldProjectionKernel)
  Dsp* const dsp = dsp_internal::GetWritableDspTable(8);
  assert(dsp != nullptr);
  dsp->motion_field_projection_kernel = MotionFieldProjectionKernel_C;
#endif
}

#if LIBGAV1_MAX_BITDEPTH >= 10
void Init10bpp() {
#if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS || \
    !defined(LIBGAV1_Dsp10bpp_MotionFieldProjectionKernel)
  Dsp* const dsp = dsp_internal::GetWritableDspTable(10);
  assert(dsp != nullptr);
  dsp->motion_field_projection_kernel = MotionFieldProjectionKernel_C;
#endif
}
#endif

}  // namespace

void MotionFieldProjectionInit_C() {
  Init8bpp();
#if LIBGAV1_MAX_BITDEPTH >= 10
  Init10bpp();
#endif
}

}  // namespace dsp
}  // namespace libgav1