1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * This file is part of FFmpeg.
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
8cabdff1aSopenharmony_ci *
9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12cabdff1aSopenharmony_ci * Lesser General Public License for more details.
13cabdff1aSopenharmony_ci *
14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17cabdff1aSopenharmony_ci */
18cabdff1aSopenharmony_ci
19cabdff1aSopenharmony_ci/**
20cabdff1aSopenharmony_ci * @file
21cabdff1aSopenharmony_ci *@brief IntraX8 frame subdecoder image manipulation routines
22cabdff1aSopenharmony_ci */
23cabdff1aSopenharmony_ci
24cabdff1aSopenharmony_ci#include "intrax8dsp.h"
25cabdff1aSopenharmony_ci#include "libavutil/common.h"
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci/*
28cabdff1aSopenharmony_ci * area positions, #3 is 1 pixel only, other are 8 pixels
29cabdff1aSopenharmony_ci *    |66666666|
30cabdff1aSopenharmony_ci *   3|44444444|55555555|
31cabdff1aSopenharmony_ci * - -+--------+--------+
32cabdff1aSopenharmony_ci * 1 2|XXXXXXXX|
33cabdff1aSopenharmony_ci * 1 2|XXXXXXXX|
34cabdff1aSopenharmony_ci * 1 2|XXXXXXXX|
35cabdff1aSopenharmony_ci * 1 2|XXXXXXXX|
36cabdff1aSopenharmony_ci * 1 2|XXXXXXXX|
37cabdff1aSopenharmony_ci * 1 2|XXXXXXXX|
38cabdff1aSopenharmony_ci * 1 2|XXXXXXXX|
39cabdff1aSopenharmony_ci * 1 2|XXXXXXXX|
40cabdff1aSopenharmony_ci * ^-start
41cabdff1aSopenharmony_ci */
42cabdff1aSopenharmony_ci
43cabdff1aSopenharmony_ci#define area1 (0)
44cabdff1aSopenharmony_ci#define area2 (8)
45cabdff1aSopenharmony_ci#define area3 (8 + 8)
46cabdff1aSopenharmony_ci#define area4 (8 + 8 + 1)
47cabdff1aSopenharmony_ci#define area5 (8 + 8 + 1 + 8)
48cabdff1aSopenharmony_ci#define area6 (8 + 8 + 1 + 16)
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_ci/**
51cabdff1aSopenharmony_ci Collect statistics and prepare the edge pixels required by the other spatial compensation functions.
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_ci * @param src pointer to the beginning of the processed block
54cabdff1aSopenharmony_ci * @param dst pointer to emu_edge, edge pixels are stored the way other compensation routines do.
55cabdff1aSopenharmony_ci * @param linesize byte offset between 2 vertical pixels in the source image
56cabdff1aSopenharmony_ci * @param range pointer to the variable where the edge pixel range is to be stored (max-min values)
57cabdff1aSopenharmony_ci * @param psum  pointer to the variable where the edge pixel sum is to be stored
58cabdff1aSopenharmony_ci * @param edges Informs this routine that the block is on an image border, so it has to interpolate the missing edge pixels.
59cabdff1aSopenharmony_ci                and some of the edge pixels should be interpolated, the flag has the following meaning:
60cabdff1aSopenharmony_ci                1   - mb_x==0 - first block in the row, interpolate area #1,#2,#3;
61cabdff1aSopenharmony_ci                2   - mb_y==0 - first row, interpolate area #3,#4,#5,#6;
62cabdff1aSopenharmony_ci        note:   1|2 - mb_x==mb_y==0 - first block, use 0x80 value for all areas;
63cabdff1aSopenharmony_ci                4   - mb_x>= (mb_width-1) last block in the row, interpolate area #5;
64cabdff1aSopenharmony_ci-*/
65cabdff1aSopenharmony_cistatic void x8_setup_spatial_compensation(uint8_t *src, uint8_t *dst,
66cabdff1aSopenharmony_ci                                          ptrdiff_t stride, int *range,
67cabdff1aSopenharmony_ci                                          int *psum, int edges)
68cabdff1aSopenharmony_ci{
69cabdff1aSopenharmony_ci    uint8_t *ptr;
70cabdff1aSopenharmony_ci    int sum;
71cabdff1aSopenharmony_ci    int i;
72cabdff1aSopenharmony_ci    int min_pix, max_pix;
73cabdff1aSopenharmony_ci    uint8_t c;
74cabdff1aSopenharmony_ci
75cabdff1aSopenharmony_ci    if ((edges & 3) == 3) {
76cabdff1aSopenharmony_ci        *psum  = 0x80 * (8 + 1 + 8 + 2);
77cabdff1aSopenharmony_ci        *range = 0;
78cabdff1aSopenharmony_ci        memset(dst, 0x80, 16 + 1 + 16 + 8);
79cabdff1aSopenharmony_ci        /* this triggers flat_dc for sure. flat_dc avoids all (other)
80cabdff1aSopenharmony_ci         * prediction modes, but requires dc_level decoding. */
81cabdff1aSopenharmony_ci        return;
82cabdff1aSopenharmony_ci    }
83cabdff1aSopenharmony_ci
84cabdff1aSopenharmony_ci    min_pix = 256;
85cabdff1aSopenharmony_ci    max_pix = -1;
86cabdff1aSopenharmony_ci
87cabdff1aSopenharmony_ci    sum = 0;
88cabdff1aSopenharmony_ci
89cabdff1aSopenharmony_ci    if (!(edges & 1)) { // (mb_x != 0) // there is previous block on this row
90cabdff1aSopenharmony_ci        ptr = src - 1; // left column, area 2
91cabdff1aSopenharmony_ci        for (i = 7; i >= 0; i--) {
92cabdff1aSopenharmony_ci            c              = *(ptr - 1); // area1, same mb as area2, no need to check
93cabdff1aSopenharmony_ci            dst[area1 + i] = c;
94cabdff1aSopenharmony_ci            c              = *ptr;
95cabdff1aSopenharmony_ci
96cabdff1aSopenharmony_ci            sum           += c;
97cabdff1aSopenharmony_ci            min_pix        = FFMIN(min_pix, c);
98cabdff1aSopenharmony_ci            max_pix        = FFMAX(max_pix, c);
99cabdff1aSopenharmony_ci            dst[area2 + i] = c;
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_ci            ptr += stride;
102cabdff1aSopenharmony_ci        }
103cabdff1aSopenharmony_ci    }
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_ci    if (!(edges & 2)) { // (mb_y != 0) // there is row above
106cabdff1aSopenharmony_ci        ptr = src - stride; // top line
107cabdff1aSopenharmony_ci        for (i = 0; i < 8; i++) {
108cabdff1aSopenharmony_ci            c       = *(ptr + i);
109cabdff1aSopenharmony_ci            sum    += c;
110cabdff1aSopenharmony_ci            min_pix = FFMIN(min_pix, c);
111cabdff1aSopenharmony_ci            max_pix = FFMAX(max_pix, c);
112cabdff1aSopenharmony_ci        }
113cabdff1aSopenharmony_ci        if (edges & 4) { // last block on the row?
114cabdff1aSopenharmony_ci            memset(dst + area5, c, 8); // set with last pixel fr
115cabdff1aSopenharmony_ci            memcpy(dst + area4, ptr, 8);
116cabdff1aSopenharmony_ci        } else {
117cabdff1aSopenharmony_ci            memcpy(dst + area4, ptr, 16); // both area4 and 5
118cabdff1aSopenharmony_ci        }
119cabdff1aSopenharmony_ci        // area6 always present in the above block
120cabdff1aSopenharmony_ci        memcpy(dst + area6, ptr - stride, 8);
121cabdff1aSopenharmony_ci    }
122cabdff1aSopenharmony_ci    // now calculate the stuff we need
123cabdff1aSopenharmony_ci    if (edges & 3) { // mb_x ==0 || mb_y == 0) {
124cabdff1aSopenharmony_ci        int avg = (sum + 4) >> 3;
125cabdff1aSopenharmony_ci
126cabdff1aSopenharmony_ci        if (edges & 1) // (mb_x == 0) { // implies mb_y !=0
127cabdff1aSopenharmony_ci            memset(dst + area1, avg, 8 + 8 + 1); // areas 1, 2, 3 are averaged
128cabdff1aSopenharmony_ci        else // implies y == 0 x != 0
129cabdff1aSopenharmony_ci            memset(dst + area3, avg, 1 + 16 + 8); // areas 3, 4, 5, 6
130cabdff1aSopenharmony_ci
131cabdff1aSopenharmony_ci        sum += avg * 9;
132cabdff1aSopenharmony_ci    } else {
133cabdff1aSopenharmony_ci        // the edge pixel, in the top line and left column
134cabdff1aSopenharmony_ci        uint8_t c = *(src - 1 - stride);
135cabdff1aSopenharmony_ci        dst[area3] = c;
136cabdff1aSopenharmony_ci        sum       += c;
137cabdff1aSopenharmony_ci        // edge pixel is not part of min/max
138cabdff1aSopenharmony_ci    }
139cabdff1aSopenharmony_ci    *range = max_pix - min_pix;
140cabdff1aSopenharmony_ci    sum   += *(dst + area5) + *(dst + area5 + 1);
141cabdff1aSopenharmony_ci    *psum  = sum;
142cabdff1aSopenharmony_ci}
143cabdff1aSopenharmony_ci
144cabdff1aSopenharmony_cistatic const uint16_t zero_prediction_weights[64 * 2] = {
145cabdff1aSopenharmony_ci    640,  640, 669,  480, 708,  354, 748, 257,
146cabdff1aSopenharmony_ci    792,  198, 760,  143, 808,  101, 772,  72,
147cabdff1aSopenharmony_ci    480,  669, 537,  537, 598,  416, 661, 316,
148cabdff1aSopenharmony_ci    719,  250, 707,  185, 768,  134, 745,  97,
149cabdff1aSopenharmony_ci    354,  708, 416,  598, 488,  488, 564, 388,
150cabdff1aSopenharmony_ci    634,  317, 642,  241, 716,  179, 706, 132,
151cabdff1aSopenharmony_ci    257,  748, 316,  661, 388,  564, 469, 469,
152cabdff1aSopenharmony_ci    543,  395, 571,  311, 655,  238, 660, 180,
153cabdff1aSopenharmony_ci    198,  792, 250,  719, 317,  634, 395, 543,
154cabdff1aSopenharmony_ci    469,  469, 507,  380, 597,  299, 616, 231,
155cabdff1aSopenharmony_ci    161,  855, 206,  788, 266,  710, 340, 623,
156cabdff1aSopenharmony_ci    411,  548, 455,  455, 548,  366, 576, 288,
157cabdff1aSopenharmony_ci    122,  972, 159,  914, 211,  842, 276, 758,
158cabdff1aSopenharmony_ci    341,  682, 389,  584, 483,  483, 520, 390,
159cabdff1aSopenharmony_ci    110, 1172, 144, 1107, 193, 1028, 254, 932,
160cabdff1aSopenharmony_ci    317,  846, 366,  731, 458,  611, 499, 499,
161cabdff1aSopenharmony_ci};
162cabdff1aSopenharmony_ci
163cabdff1aSopenharmony_cistatic void spatial_compensation_0(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
164cabdff1aSopenharmony_ci{
165cabdff1aSopenharmony_ci    int i, j;
166cabdff1aSopenharmony_ci    int x, y;
167cabdff1aSopenharmony_ci    unsigned int p; // power divided by 2
168cabdff1aSopenharmony_ci    int a;
169cabdff1aSopenharmony_ci    uint16_t left_sum[2][8] = { { 0 } };
170cabdff1aSopenharmony_ci    uint16_t  top_sum[2][8] = { { 0 } };
171cabdff1aSopenharmony_ci
172cabdff1aSopenharmony_ci    for (i = 0; i < 8; i++) {
173cabdff1aSopenharmony_ci        a = src[area2 + 7 - i] << 4;
174cabdff1aSopenharmony_ci        for (j = 0; j < 8; j++) {
175cabdff1aSopenharmony_ci            p                   = abs(i - j);
176cabdff1aSopenharmony_ci            left_sum[p & 1][j] += a >> (p >> 1);
177cabdff1aSopenharmony_ci        }
178cabdff1aSopenharmony_ci    }
179cabdff1aSopenharmony_ci
180cabdff1aSopenharmony_ci    for (i = 0; i < 8; i++) {
181cabdff1aSopenharmony_ci        a = src[area4 + i] << 4;
182cabdff1aSopenharmony_ci        for (j = 0; j < 8; j++) {
183cabdff1aSopenharmony_ci            p                  = abs(i - j);
184cabdff1aSopenharmony_ci            top_sum[p & 1][j] += a >> (p >> 1);
185cabdff1aSopenharmony_ci        }
186cabdff1aSopenharmony_ci    }
187cabdff1aSopenharmony_ci    for (; i < 10; i++) {
188cabdff1aSopenharmony_ci        a = src[area4 + i] << 4;
189cabdff1aSopenharmony_ci        for (j = 5; j < 8; j++) {
190cabdff1aSopenharmony_ci            p                  = abs(i - j);
191cabdff1aSopenharmony_ci            top_sum[p & 1][j] += a >> (p >> 1);
192cabdff1aSopenharmony_ci        }
193cabdff1aSopenharmony_ci    }
194cabdff1aSopenharmony_ci    for (; i < 12; i++) {
195cabdff1aSopenharmony_ci        a = src[area4 + i] << 4;
196cabdff1aSopenharmony_ci        for (j = 7; j < 8; j++) {
197cabdff1aSopenharmony_ci            p                  = abs(i - j);
198cabdff1aSopenharmony_ci            top_sum[p & 1][j] += a >> (p >> 1);
199cabdff1aSopenharmony_ci        }
200cabdff1aSopenharmony_ci    }
201cabdff1aSopenharmony_ci
202cabdff1aSopenharmony_ci    for (i = 0; i < 8; i++) {
203cabdff1aSopenharmony_ci        top_sum[0][i]  +=  (top_sum[1][i] * 181 + 128) >> 8; // 181 is sqrt(2)/2
204cabdff1aSopenharmony_ci        left_sum[0][i] += (left_sum[1][i] * 181 + 128) >> 8;
205cabdff1aSopenharmony_ci    }
206cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
207cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
208cabdff1aSopenharmony_ci            dst[x] = ((uint32_t)  top_sum[0][x] * zero_prediction_weights[y * 16 + x * 2 + 0] +
209cabdff1aSopenharmony_ci                      (uint32_t) left_sum[0][y] * zero_prediction_weights[y * 16 + x * 2 + 1] +
210cabdff1aSopenharmony_ci                      0x8000) >> 16;
211cabdff1aSopenharmony_ci        dst += stride;
212cabdff1aSopenharmony_ci    }
213cabdff1aSopenharmony_ci}
214cabdff1aSopenharmony_ci
215cabdff1aSopenharmony_cistatic void spatial_compensation_1(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
216cabdff1aSopenharmony_ci{
217cabdff1aSopenharmony_ci    int x, y;
218cabdff1aSopenharmony_ci
219cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
220cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
221cabdff1aSopenharmony_ci            dst[x] = src[area4 + FFMIN(2 * y + x + 2, 15)];
222cabdff1aSopenharmony_ci        dst += stride;
223cabdff1aSopenharmony_ci    }
224cabdff1aSopenharmony_ci}
225cabdff1aSopenharmony_ci
226cabdff1aSopenharmony_cistatic void spatial_compensation_2(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
227cabdff1aSopenharmony_ci{
228cabdff1aSopenharmony_ci    int x, y;
229cabdff1aSopenharmony_ci
230cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
231cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
232cabdff1aSopenharmony_ci            dst[x] = src[area4 + 1 + y + x];
233cabdff1aSopenharmony_ci        dst += stride;
234cabdff1aSopenharmony_ci    }
235cabdff1aSopenharmony_ci}
236cabdff1aSopenharmony_ci
237cabdff1aSopenharmony_cistatic void spatial_compensation_3(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
238cabdff1aSopenharmony_ci{
239cabdff1aSopenharmony_ci    int x, y;
240cabdff1aSopenharmony_ci
241cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
242cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
243cabdff1aSopenharmony_ci            dst[x] = src[area4 + ((y + 1) >> 1) + x];
244cabdff1aSopenharmony_ci        dst += stride;
245cabdff1aSopenharmony_ci    }
246cabdff1aSopenharmony_ci}
247cabdff1aSopenharmony_ci
248cabdff1aSopenharmony_cistatic void spatial_compensation_4(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
249cabdff1aSopenharmony_ci{
250cabdff1aSopenharmony_ci    int x, y;
251cabdff1aSopenharmony_ci
252cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
253cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
254cabdff1aSopenharmony_ci            dst[x] = (src[area4 + x] + src[area6 + x] + 1) >> 1;
255cabdff1aSopenharmony_ci        dst += stride;
256cabdff1aSopenharmony_ci    }
257cabdff1aSopenharmony_ci}
258cabdff1aSopenharmony_ci
259cabdff1aSopenharmony_cistatic void spatial_compensation_5(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
260cabdff1aSopenharmony_ci{
261cabdff1aSopenharmony_ci    int x, y;
262cabdff1aSopenharmony_ci
263cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
264cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++) {
265cabdff1aSopenharmony_ci            if (2 * x - y < 0)
266cabdff1aSopenharmony_ci                dst[x] = src[area2 + 9 + 2 * x - y];
267cabdff1aSopenharmony_ci            else
268cabdff1aSopenharmony_ci                dst[x] = src[area4 + x - ((y + 1) >> 1)];
269cabdff1aSopenharmony_ci        }
270cabdff1aSopenharmony_ci        dst += stride;
271cabdff1aSopenharmony_ci    }
272cabdff1aSopenharmony_ci}
273cabdff1aSopenharmony_ci
274cabdff1aSopenharmony_cistatic void spatial_compensation_6(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
275cabdff1aSopenharmony_ci{
276cabdff1aSopenharmony_ci    int x, y;
277cabdff1aSopenharmony_ci
278cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
279cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
280cabdff1aSopenharmony_ci            dst[x] = src[area3 + x - y];
281cabdff1aSopenharmony_ci        dst += stride;
282cabdff1aSopenharmony_ci    }
283cabdff1aSopenharmony_ci}
284cabdff1aSopenharmony_ci
285cabdff1aSopenharmony_cistatic void spatial_compensation_7(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
286cabdff1aSopenharmony_ci{
287cabdff1aSopenharmony_ci    int x, y;
288cabdff1aSopenharmony_ci
289cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
290cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++) {
291cabdff1aSopenharmony_ci            if (x - 2 * y > 0)
292cabdff1aSopenharmony_ci                dst[x] = (src[area3 - 1 + x - 2 * y] + src[area3 + x - 2 * y] + 1) >> 1;
293cabdff1aSopenharmony_ci            else
294cabdff1aSopenharmony_ci                dst[x] = src[area2 + 8 - y + (x >> 1)];
295cabdff1aSopenharmony_ci        }
296cabdff1aSopenharmony_ci        dst += stride;
297cabdff1aSopenharmony_ci    }
298cabdff1aSopenharmony_ci}
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_cistatic void spatial_compensation_8(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
301cabdff1aSopenharmony_ci{
302cabdff1aSopenharmony_ci    int x, y;
303cabdff1aSopenharmony_ci
304cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
305cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
306cabdff1aSopenharmony_ci            dst[x] = (src[area1 + 7 - y] + src[area2 + 7 - y] + 1) >> 1;
307cabdff1aSopenharmony_ci        dst += stride;
308cabdff1aSopenharmony_ci    }
309cabdff1aSopenharmony_ci}
310cabdff1aSopenharmony_ci
311cabdff1aSopenharmony_cistatic void spatial_compensation_9(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
312cabdff1aSopenharmony_ci{
313cabdff1aSopenharmony_ci    int x, y;
314cabdff1aSopenharmony_ci
315cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
316cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
317cabdff1aSopenharmony_ci            dst[x] = src[area2 + 6 - FFMIN(x + y, 6)];
318cabdff1aSopenharmony_ci        dst += stride;
319cabdff1aSopenharmony_ci    }
320cabdff1aSopenharmony_ci}
321cabdff1aSopenharmony_ci
322cabdff1aSopenharmony_cistatic void spatial_compensation_10(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
323cabdff1aSopenharmony_ci{
324cabdff1aSopenharmony_ci    int x, y;
325cabdff1aSopenharmony_ci
326cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
327cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
328cabdff1aSopenharmony_ci            dst[x] = (src[area2 + 7 - y] * (8 - x) + src[area4 + x] * x + 4) >> 3;
329cabdff1aSopenharmony_ci        dst += stride;
330cabdff1aSopenharmony_ci    }
331cabdff1aSopenharmony_ci}
332cabdff1aSopenharmony_ci
333cabdff1aSopenharmony_cistatic void spatial_compensation_11(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
334cabdff1aSopenharmony_ci{
335cabdff1aSopenharmony_ci    int x, y;
336cabdff1aSopenharmony_ci
337cabdff1aSopenharmony_ci    for (y = 0; y < 8; y++) {
338cabdff1aSopenharmony_ci        for (x = 0; x < 8; x++)
339cabdff1aSopenharmony_ci            dst[x] = (src[area2 + 7 - y] * y + src[area4 + x] * (8 - y) + 4) >> 3;
340cabdff1aSopenharmony_ci        dst += stride;
341cabdff1aSopenharmony_ci    }
342cabdff1aSopenharmony_ci}
343cabdff1aSopenharmony_ci
344cabdff1aSopenharmony_cistatic void x8_loop_filter(uint8_t *ptr, const ptrdiff_t a_stride,
345cabdff1aSopenharmony_ci                           const ptrdiff_t b_stride, int quant)
346cabdff1aSopenharmony_ci{
347cabdff1aSopenharmony_ci    int i, t;
348cabdff1aSopenharmony_ci    int p0, p1, p2, p3, p4, p5, p6, p7, p8, p9;
349cabdff1aSopenharmony_ci    int ql = (quant + 10) >> 3;
350cabdff1aSopenharmony_ci
351cabdff1aSopenharmony_ci    for (i = 0; i < 8; i++, ptr += b_stride) {
352cabdff1aSopenharmony_ci        p0 = ptr[-5 * a_stride];
353cabdff1aSopenharmony_ci        p1 = ptr[-4 * a_stride];
354cabdff1aSopenharmony_ci        p2 = ptr[-3 * a_stride];
355cabdff1aSopenharmony_ci        p3 = ptr[-2 * a_stride];
356cabdff1aSopenharmony_ci        p4 = ptr[-1 * a_stride];
357cabdff1aSopenharmony_ci        p5 = ptr[0];
358cabdff1aSopenharmony_ci        p6 = ptr[1 * a_stride];
359cabdff1aSopenharmony_ci        p7 = ptr[2 * a_stride];
360cabdff1aSopenharmony_ci        p8 = ptr[3 * a_stride];
361cabdff1aSopenharmony_ci        p9 = ptr[4 * a_stride];
362cabdff1aSopenharmony_ci
363cabdff1aSopenharmony_ci        t = (FFABS(p1 - p2) <= ql) +
364cabdff1aSopenharmony_ci            (FFABS(p2 - p3) <= ql) +
365cabdff1aSopenharmony_ci            (FFABS(p3 - p4) <= ql) +
366cabdff1aSopenharmony_ci            (FFABS(p4 - p5) <= ql);
367cabdff1aSopenharmony_ci
368cabdff1aSopenharmony_ci        // You need at least 1 to be able to reach a total score of 6.
369cabdff1aSopenharmony_ci        if (t > 0) {
370cabdff1aSopenharmony_ci            t += (FFABS(p5 - p6) <= ql) +
371cabdff1aSopenharmony_ci                 (FFABS(p6 - p7) <= ql) +
372cabdff1aSopenharmony_ci                 (FFABS(p7 - p8) <= ql) +
373cabdff1aSopenharmony_ci                 (FFABS(p8 - p9) <= ql) +
374cabdff1aSopenharmony_ci                 (FFABS(p0 - p1) <= ql);
375cabdff1aSopenharmony_ci            if (t >= 6) {
376cabdff1aSopenharmony_ci                int min, max;
377cabdff1aSopenharmony_ci
378cabdff1aSopenharmony_ci                min = max = p1;
379cabdff1aSopenharmony_ci                min = FFMIN(min, p3);
380cabdff1aSopenharmony_ci                max = FFMAX(max, p3);
381cabdff1aSopenharmony_ci                min = FFMIN(min, p5);
382cabdff1aSopenharmony_ci                max = FFMAX(max, p5);
383cabdff1aSopenharmony_ci                min = FFMIN(min, p8);
384cabdff1aSopenharmony_ci                max = FFMAX(max, p8);
385cabdff1aSopenharmony_ci                if (max - min < 2 * quant) { // early stop
386cabdff1aSopenharmony_ci                    min = FFMIN(min, p2);
387cabdff1aSopenharmony_ci                    max = FFMAX(max, p2);
388cabdff1aSopenharmony_ci                    min = FFMIN(min, p4);
389cabdff1aSopenharmony_ci                    max = FFMAX(max, p4);
390cabdff1aSopenharmony_ci                    min = FFMIN(min, p6);
391cabdff1aSopenharmony_ci                    max = FFMAX(max, p6);
392cabdff1aSopenharmony_ci                    min = FFMIN(min, p7);
393cabdff1aSopenharmony_ci                    max = FFMAX(max, p7);
394cabdff1aSopenharmony_ci                    if (max - min < 2 * quant) {
395cabdff1aSopenharmony_ci                        ptr[-2 * a_stride] = (4 * p2 + 3 * p3 + 1 * p7 + 4) >> 3;
396cabdff1aSopenharmony_ci                        ptr[-1 * a_stride] = (3 * p2 + 3 * p4 + 2 * p7 + 4) >> 3;
397cabdff1aSopenharmony_ci                        ptr[0]             = (2 * p2 + 3 * p5 + 3 * p7 + 4) >> 3;
398cabdff1aSopenharmony_ci                        ptr[1 * a_stride]  = (1 * p2 + 3 * p6 + 4 * p7 + 4) >> 3;
399cabdff1aSopenharmony_ci                        continue;
400cabdff1aSopenharmony_ci                    }
401cabdff1aSopenharmony_ci                }
402cabdff1aSopenharmony_ci            }
403cabdff1aSopenharmony_ci        }
404cabdff1aSopenharmony_ci        {
405cabdff1aSopenharmony_ci            int x, x0, x1, x2;
406cabdff1aSopenharmony_ci            int m;
407cabdff1aSopenharmony_ci
408cabdff1aSopenharmony_ci            x0 = (2 * p3 - 5 * p4 + 5 * p5 - 2 * p6 + 4) >> 3;
409cabdff1aSopenharmony_ci            if (FFABS(x0) < quant) {
410cabdff1aSopenharmony_ci                x1 = (2 * p1 - 5 * p2 + 5 * p3 - 2 * p4 + 4) >> 3;
411cabdff1aSopenharmony_ci                x2 = (2 * p5 - 5 * p6 + 5 * p7 - 2 * p8 + 4) >> 3;
412cabdff1aSopenharmony_ci
413cabdff1aSopenharmony_ci                x = FFABS(x0) - FFMIN(FFABS(x1), FFABS(x2));
414cabdff1aSopenharmony_ci                m = p4 - p5;
415cabdff1aSopenharmony_ci
416cabdff1aSopenharmony_ci                if (x > 0 && (m ^ x0) < 0) {
417cabdff1aSopenharmony_ci                    int32_t sign;
418cabdff1aSopenharmony_ci
419cabdff1aSopenharmony_ci                    sign = m >> 31;
420cabdff1aSopenharmony_ci                    m    = (m ^ sign) - sign; // abs(m)
421cabdff1aSopenharmony_ci                    m  >>= 1;
422cabdff1aSopenharmony_ci
423cabdff1aSopenharmony_ci                    x = 5 * x >> 3;
424cabdff1aSopenharmony_ci
425cabdff1aSopenharmony_ci                    if (x > m)
426cabdff1aSopenharmony_ci                        x = m;
427cabdff1aSopenharmony_ci
428cabdff1aSopenharmony_ci                    x = (x ^ sign) - sign;
429cabdff1aSopenharmony_ci
430cabdff1aSopenharmony_ci                    ptr[-1 * a_stride] -= x;
431cabdff1aSopenharmony_ci                    ptr[0]             += x;
432cabdff1aSopenharmony_ci                }
433cabdff1aSopenharmony_ci            }
434cabdff1aSopenharmony_ci        }
435cabdff1aSopenharmony_ci    }
436cabdff1aSopenharmony_ci}
437cabdff1aSopenharmony_ci
438cabdff1aSopenharmony_cistatic void x8_h_loop_filter(uint8_t *src, ptrdiff_t stride, int qscale)
439cabdff1aSopenharmony_ci{
440cabdff1aSopenharmony_ci    x8_loop_filter(src, stride, 1, qscale);
441cabdff1aSopenharmony_ci}
442cabdff1aSopenharmony_ci
443cabdff1aSopenharmony_cistatic void x8_v_loop_filter(uint8_t *src, ptrdiff_t stride, int qscale)
444cabdff1aSopenharmony_ci{
445cabdff1aSopenharmony_ci    x8_loop_filter(src, 1, stride, qscale);
446cabdff1aSopenharmony_ci}
447cabdff1aSopenharmony_ci
448cabdff1aSopenharmony_ciav_cold void ff_intrax8dsp_init(IntraX8DSPContext *dsp)
449cabdff1aSopenharmony_ci{
450cabdff1aSopenharmony_ci    dsp->h_loop_filter              = x8_h_loop_filter;
451cabdff1aSopenharmony_ci    dsp->v_loop_filter              = x8_v_loop_filter;
452cabdff1aSopenharmony_ci    dsp->setup_spatial_compensation = x8_setup_spatial_compensation;
453cabdff1aSopenharmony_ci    dsp->spatial_compensation[0]    = spatial_compensation_0;
454cabdff1aSopenharmony_ci    dsp->spatial_compensation[1]    = spatial_compensation_1;
455cabdff1aSopenharmony_ci    dsp->spatial_compensation[2]    = spatial_compensation_2;
456cabdff1aSopenharmony_ci    dsp->spatial_compensation[3]    = spatial_compensation_3;
457cabdff1aSopenharmony_ci    dsp->spatial_compensation[4]    = spatial_compensation_4;
458cabdff1aSopenharmony_ci    dsp->spatial_compensation[5]    = spatial_compensation_5;
459cabdff1aSopenharmony_ci    dsp->spatial_compensation[6]    = spatial_compensation_6;
460cabdff1aSopenharmony_ci    dsp->spatial_compensation[7]    = spatial_compensation_7;
461cabdff1aSopenharmony_ci    dsp->spatial_compensation[8]    = spatial_compensation_8;
462cabdff1aSopenharmony_ci    dsp->spatial_compensation[9]    = spatial_compensation_9;
463cabdff1aSopenharmony_ci    dsp->spatial_compensation[10]   = spatial_compensation_10;
464cabdff1aSopenharmony_ci    dsp->spatial_compensation[11]   = spatial_compensation_11;
465cabdff1aSopenharmony_ci}
466