Coverage Report

Created: 2026-05-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/openh264/codec/processing/src/adaptivequantization/AdaptiveQuantization.cpp
Line
Count
Source
1
/*!
2
 * \copy
3
 *     Copyright (c)  2013, Cisco Systems
4
 *     All rights reserved.
5
 *
6
 *     Redistribution and use in source and binary forms, with or without
7
 *     modification, are permitted provided that the following conditions
8
 *     are met:
9
 *
10
 *        * Redistributions of source code must retain the above copyright
11
 *          notice, this list of conditions and the following disclaimer.
12
 *
13
 *        * Redistributions in binary form must reproduce the above copyright
14
 *          notice, this list of conditions and the following disclaimer in
15
 *          the documentation and/or other materials provided with the
16
 *          distribution.
17
 *
18
 *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
 *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
 *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21
 *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
 *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23
 *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24
 *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25
 *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
 *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28
 *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
 *     POSSIBILITY OF SUCH DAMAGE.
30
 *
31
 */
32
#include "AdaptiveQuantization.h"
33
#include "macros.h"
34
WELSVP_NAMESPACE_BEGIN
35
36
37
38
#define AVERAGE_TIME_MOTION                   (3000) //0.3046875 // 1/4 + 1/16 - 1/128 ~ 0.3 *AQ_TIME_INT_MULTIPLY
39
#define AVERAGE_TIME_TEXTURE_QUALITYMODE  (10000) //0.5 // 1/2 *AQ_TIME_INT_MULTIPLY
40
#define AVERAGE_TIME_TEXTURE_BITRATEMODE  (8750) //0.5 // 1/2 *AQ_TIME_INT_MULTIPLY
41
#define MODEL_ALPHA                           (9910) //1.5 //1.1102 *AQ_TIME_INT_MULTIPLY
42
0
#define MODEL_TIME                            (58185) //9.0 //5.9842 *AQ_TIME_INT_MULTIPLY
43
44
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
45
46
0
CAdaptiveQuantization::CAdaptiveQuantization (int32_t iCpuFlag) {
47
0
  m_CPUFlag = iCpuFlag;
48
0
  m_eMethod   = METHOD_ADAPTIVE_QUANT;
49
0
  m_pfVar   = NULL;
50
0
  WelsMemset (&m_sAdaptiveQuantParam, 0, sizeof (m_sAdaptiveQuantParam));
51
0
  WelsInitVarFunc (m_pfVar, m_CPUFlag);
52
0
}
53
54
0
CAdaptiveQuantization::~CAdaptiveQuantization() {
55
0
}
56
57
0
EResult CAdaptiveQuantization::Process (int32_t iType, SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
58
0
  EResult eReturn = RET_INVALIDPARAM;
59
60
0
  int32_t iWidth     = pSrcPixMap->sRect.iRectWidth;
61
0
  int32_t iHeight    = pSrcPixMap->sRect.iRectHeight;
62
0
  int32_t iMbWidth  = iWidth  >> 4;
63
0
  int32_t iMbHeight = iHeight >> 4;
64
0
  int32_t iMbTotalNum    = iMbWidth * iMbHeight;
65
66
0
  SMotionTextureUnit* pMotionTexture = NULL;
67
0
  SVAACalcResult*     pVaaCalcResults = NULL;
68
0
  int32_t   iMotionTextureIndexToDeltaQp = 0;
69
0
  int32_t iAverMotionTextureIndexToDeltaQp = 0;  // double to uint32
70
0
  int64_t iAverageMotionIndex = 0;      // double to float
71
0
  int64_t iAverageTextureIndex = 0;
72
73
0
  int64_t iQStep = 0;
74
0
  int64_t iLumaMotionDeltaQp = 0;
75
0
  int64_t iLumaTextureDeltaQp = 0;
76
77
0
  uint8_t* pRefFrameY = NULL, *pCurFrameY = NULL;
78
0
  int32_t iRefStride = 0, iCurStride = 0;
79
80
0
  uint8_t* pRefFrameTmp = NULL, *pCurFrameTmp = NULL;
81
0
  int32_t i = 0, j = 0;
82
83
0
  pRefFrameY = (uint8_t*)pRefPixMap->pPixel[0];
84
0
  pCurFrameY = (uint8_t*)pSrcPixMap->pPixel[0];
85
86
0
  iRefStride  = pRefPixMap->iStride[0];
87
0
  iCurStride  = pSrcPixMap->iStride[0];
88
89
  /////////////////////////////////////// motion //////////////////////////////////
90
  //  motion MB residual variance
91
0
  iAverageMotionIndex = 0;
92
0
  iAverageTextureIndex = 0;
93
0
  pMotionTexture = m_sAdaptiveQuantParam.pMotionTextureUnit;
94
0
  pVaaCalcResults = m_sAdaptiveQuantParam.pCalcResult;
95
96
0
  if (pVaaCalcResults->pRefY == pRefFrameY && pVaaCalcResults->pCurY == pCurFrameY) {
97
0
    int32_t iMbIndex = 0;
98
0
    int32_t iSumDiff, iSQDiff, uiSum, iSQSum;
99
0
    for (j = 0; j < iMbHeight; j ++) {
100
0
      pRefFrameTmp  = pRefFrameY;
101
0
      pCurFrameTmp  = pCurFrameY;
102
0
      for (i = 0; i < iMbWidth; i++) {
103
0
        iSumDiff =  pVaaCalcResults->pSad8x8[iMbIndex][0];
104
0
        iSumDiff += pVaaCalcResults->pSad8x8[iMbIndex][1];
105
0
        iSumDiff += pVaaCalcResults->pSad8x8[iMbIndex][2];
106
0
        iSumDiff += pVaaCalcResults->pSad8x8[iMbIndex][3];
107
108
0
        iSQDiff = pVaaCalcResults->pSsd16x16[iMbIndex];
109
0
        uiSum = pVaaCalcResults->pSum16x16[iMbIndex];
110
0
        iSQSum = pVaaCalcResults->pSumOfSquare16x16[iMbIndex];
111
112
0
        iSumDiff = iSumDiff >> 8;
113
0
        pMotionTexture->uiMotionIndex = (iSQDiff >> 8) - (iSumDiff * iSumDiff);
114
115
0
        uiSum = uiSum >> 8;
116
0
        pMotionTexture->uiTextureIndex = (iSQSum >> 8) - (uiSum * uiSum);
117
118
0
        iAverageMotionIndex += pMotionTexture->uiMotionIndex;
119
0
        iAverageTextureIndex += pMotionTexture->uiTextureIndex;
120
0
        pMotionTexture++;
121
0
        ++iMbIndex;
122
0
        pRefFrameTmp += MB_WIDTH_LUMA;
123
0
        pCurFrameTmp += MB_WIDTH_LUMA;
124
0
      }
125
0
      pRefFrameY += (iRefStride) << 4;
126
0
      pCurFrameY += (iCurStride) << 4;
127
0
    }
128
0
  } else {
129
0
    for (j = 0; j < iMbHeight; j ++) {
130
0
      pRefFrameTmp  = pRefFrameY;
131
0
      pCurFrameTmp  = pCurFrameY;
132
0
      for (i = 0; i < iMbWidth; i++) {
133
0
        m_pfVar (pRefFrameTmp, iRefStride, pCurFrameTmp, iCurStride, pMotionTexture);
134
0
        iAverageMotionIndex += pMotionTexture->uiMotionIndex;
135
0
        iAverageTextureIndex += pMotionTexture->uiTextureIndex;
136
0
        pMotionTexture++;
137
0
        pRefFrameTmp += MB_WIDTH_LUMA;
138
0
        pCurFrameTmp += MB_WIDTH_LUMA;
139
140
0
      }
141
0
      pRefFrameY += (iRefStride) << 4;
142
0
      pCurFrameY += (iCurStride) << 4;
143
0
    }
144
0
  }
145
0
  iAverageMotionIndex = WELS_DIV_ROUND64 (iAverageMotionIndex * AQ_INT_MULTIPLY, iMbTotalNum);
146
0
  iAverageTextureIndex = WELS_DIV_ROUND64 (iAverageTextureIndex * AQ_INT_MULTIPLY, iMbTotalNum);
147
0
  if ((iAverageMotionIndex <= AQ_PESN) && (iAverageMotionIndex >= -AQ_PESN)) {
148
0
    iAverageMotionIndex = AQ_INT_MULTIPLY;
149
0
  }
150
0
  if ((iAverageTextureIndex <= AQ_PESN) && (iAverageTextureIndex >= -AQ_PESN)) {
151
0
    iAverageTextureIndex = AQ_INT_MULTIPLY;
152
0
  }
153
  //  motion mb residual map to QP
154
  //  texture mb original map to QP
155
0
  iAverMotionTextureIndexToDeltaQp = 0;
156
0
  iAverageMotionIndex = WELS_DIV_ROUND64 (AVERAGE_TIME_MOTION * iAverageMotionIndex, AQ_TIME_INT_MULTIPLY);
157
158
0
  if (m_sAdaptiveQuantParam.iAdaptiveQuantMode == AQ_QUALITY_MODE) {
159
0
    iAverageTextureIndex = WELS_DIV_ROUND64 (AVERAGE_TIME_TEXTURE_QUALITYMODE * iAverageTextureIndex, AQ_TIME_INT_MULTIPLY);
160
0
  } else {
161
0
    iAverageTextureIndex = WELS_DIV_ROUND64 (AVERAGE_TIME_TEXTURE_BITRATEMODE * iAverageTextureIndex, AQ_TIME_INT_MULTIPLY);
162
0
  }
163
164
0
  int64_t iAQ_EPSN = - ((int64_t)AQ_PESN * AQ_TIME_INT_MULTIPLY * AQ_QSTEP_INT_MULTIPLY / AQ_INT_MULTIPLY);
165
0
  pMotionTexture = m_sAdaptiveQuantParam.pMotionTextureUnit;
166
0
  for (j = 0; j < iMbHeight; j ++) {
167
0
    for (i = 0; i < iMbWidth; i++) {
168
0
      int64_t a = WELS_DIV_ROUND64 ((int64_t) (pMotionTexture->uiTextureIndex) * AQ_INT_MULTIPLY * AQ_TIME_INT_MULTIPLY,
169
0
                                    iAverageTextureIndex);
170
0
      iQStep = WELS_DIV_ROUND64 ((a - AQ_TIME_INT_MULTIPLY) * AQ_QSTEP_INT_MULTIPLY, (a + MODEL_ALPHA));
171
0
      iLumaTextureDeltaQp = MODEL_TIME * iQStep;// range +- 6
172
173
0
      iMotionTextureIndexToDeltaQp = ((int32_t) (iLumaTextureDeltaQp / (AQ_TIME_INT_MULTIPLY)));
174
175
0
      a = WELS_DIV_ROUND64 (((int64_t)pMotionTexture->uiMotionIndex) * AQ_INT_MULTIPLY * AQ_TIME_INT_MULTIPLY,
176
0
                            iAverageMotionIndex);
177
0
      iQStep = WELS_DIV_ROUND64 ((a - AQ_TIME_INT_MULTIPLY) * AQ_QSTEP_INT_MULTIPLY, (a + MODEL_ALPHA));
178
0
      iLumaMotionDeltaQp = MODEL_TIME * iQStep;// range +- 6
179
180
0
      if ((m_sAdaptiveQuantParam.iAdaptiveQuantMode == AQ_QUALITY_MODE && iLumaMotionDeltaQp < iAQ_EPSN)
181
0
          || (m_sAdaptiveQuantParam.iAdaptiveQuantMode == AQ_BITRATE_MODE)) {
182
0
        iMotionTextureIndexToDeltaQp += ((int32_t) (iLumaMotionDeltaQp / (AQ_TIME_INT_MULTIPLY)));
183
0
      }
184
185
0
      m_sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp[j * iMbWidth + i] = (int8_t) (iMotionTextureIndexToDeltaQp /
186
0
          AQ_QSTEP_INT_MULTIPLY);
187
0
      iAverMotionTextureIndexToDeltaQp += iMotionTextureIndexToDeltaQp;
188
0
      pMotionTexture++;
189
0
    }
190
0
  }
191
192
0
  m_sAdaptiveQuantParam.iAverMotionTextureIndexToDeltaQp = iAverMotionTextureIndexToDeltaQp / iMbTotalNum;
193
194
0
  eReturn = RET_SUCCESS;
195
196
0
  return eReturn;
197
0
}
198
199
200
201
0
EResult CAdaptiveQuantization::Set (int32_t iType, void* pParam) {
202
0
  if (pParam == NULL) {
203
0
    return RET_INVALIDPARAM;
204
0
  }
205
206
0
  m_sAdaptiveQuantParam = * (SAdaptiveQuantizationParam*)pParam;
207
208
0
  return RET_SUCCESS;
209
0
}
210
211
0
EResult CAdaptiveQuantization::Get (int32_t iType, void* pParam) {
212
0
  if (pParam == NULL) {
213
0
    return RET_INVALIDPARAM;
214
0
  }
215
216
0
  SAdaptiveQuantizationParam* sAdaptiveQuantParam = (SAdaptiveQuantizationParam*)pParam;
217
218
0
  sAdaptiveQuantParam->iAverMotionTextureIndexToDeltaQp = m_sAdaptiveQuantParam.iAverMotionTextureIndexToDeltaQp;
219
220
0
  return RET_SUCCESS;
221
0
}
222
223
///////////////////////////////////////////////////////////////////////////////////////////////
224
225
0
void CAdaptiveQuantization::WelsInitVarFunc (PVarFunc& pfVar,  int32_t iCpuFlag) {
226
0
  pfVar = SampleVariance16x16_c;
227
228
#ifdef X86_ASM
229
  if (iCpuFlag & WELS_CPU_SSE2) {
230
    pfVar = SampleVariance16x16_sse2;
231
  }
232
#endif
233
#ifdef HAVE_NEON
234
  if (iCpuFlag & WELS_CPU_NEON) {
235
    pfVar = SampleVariance16x16_neon;
236
  }
237
#endif
238
#if defined(HAVE_NEON_AARCH64) && defined(__aarch64__)
239
  if (iCpuFlag & WELS_CPU_NEON) {
240
    pfVar = SampleVariance16x16_AArch64_neon;
241
  }
242
#endif
243
0
}
244
245
void SampleVariance16x16_c (uint8_t* pRefY, int32_t iRefStride, uint8_t* pSrcY, int32_t iSrcStride,
246
0
                            SMotionTextureUnit* pMotionTexture) {
247
0
  uint32_t uiCurSquare = 0,  uiSquare = 0;
248
0
  uint16_t uiCurSum = 0,  uiSum = 0;
249
250
0
  for (int32_t y = 0; y < MB_WIDTH_LUMA; y++) {
251
0
    for (int32_t x = 0; x < MB_WIDTH_LUMA; x++) {
252
0
      uint32_t uiDiff = WELS_ABS (pRefY[x] - pSrcY[x]);
253
0
      uiSum += uiDiff;
254
0
      uiSquare += uiDiff * uiDiff;
255
256
0
      uiCurSum += pSrcY[x];
257
0
      uiCurSquare += pSrcY[x] * pSrcY[x];
258
0
    }
259
0
    pRefY += iRefStride;
260
0
    pSrcY += iSrcStride;
261
0
  }
262
263
0
  uiSum = uiSum >> 8;
264
0
  pMotionTexture->uiMotionIndex = (uiSquare >> 8) - (uiSum * uiSum);
265
266
0
  uiCurSum = uiCurSum >> 8;
267
0
  pMotionTexture->uiTextureIndex = (uiCurSquare >> 8) - (uiCurSum * uiCurSum);
268
0
}
269
270
WELSVP_NAMESPACE_END