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