FFmpeg
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"
26 #include "libavutil/intreadwrite.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 -*/
66 static 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 
146 static 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 
165 static 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 
217 static 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 
228 static 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 
236 static 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 
244 static 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 
255 static 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 
270 static 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 
278 static 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 
293 static 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 
304 static 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 
315 static 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 
326 static 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 
337 static 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 
431 static void x8_h_loop_filter(uint8_t *src, ptrdiff_t stride, int qscale)
432 {
433  x8_loop_filter(src, stride, 1, qscale);
434 }
435 
436 static void x8_v_loop_filter(uint8_t *src, ptrdiff_t stride, int qscale)
437 {
438  x8_loop_filter(src, 1, stride, qscale);
439 }
440 
442 {
458 }
x8_setup_spatial_compensation
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
IntraX8DSPContext::spatial_compensation
void(* spatial_compensation[12])(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.h:29
spatial_compensation_2
static void spatial_compensation_2(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:228
IntraX8DSPContext
Definition: intrax8dsp.h:25
IntraX8DSPContext::setup_spatial_compensation
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
max
#define max(a, b)
Definition: cuda_runtime.h:33
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
intrax8dsp.h
area6
#define area6
Definition: intrax8dsp.c:49
area5
#define area5
Definition: intrax8dsp.c:48
zero_prediction_weights
static const uint16_t zero_prediction_weights[64 *2]
Definition: intrax8dsp.c:146
area2
#define area2
Definition: intrax8dsp.c:45
quant
static const uint8_t quant[64]
Definition: vmixdec.c:71
av_cold
#define av_cold
Definition: attributes.h:90
intreadwrite.h
area4
#define area4
Definition: intrax8dsp.c:47
IntraX8DSPContext::v_loop_filter
void(* v_loop_filter)(uint8_t *src, ptrdiff_t stride, int qscale)
Definition: intrax8dsp.h:26
x8_v_loop_filter
static void x8_v_loop_filter(uint8_t *src, ptrdiff_t stride, int qscale)
Definition: intrax8dsp.c:436
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:74
area1
#define area1
Definition: intrax8dsp.c:44
abs
#define abs(x)
Definition: cuda_runtime.h:35
x8_h_loop_filter
static void x8_h_loop_filter(uint8_t *src, ptrdiff_t stride, int qscale)
Definition: intrax8dsp.c:431
spatial_compensation_8
static void spatial_compensation_8(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:293
AV_COPY64U
#define AV_COPY64U(d, s)
Definition: intreadwrite.h:611
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
spatial_compensation_6
static void spatial_compensation_6(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:270
area3
#define area3
Definition: intrax8dsp.c:46
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
IntraX8DSPContext::h_loop_filter
void(* h_loop_filter)(uint8_t *src, ptrdiff_t stride, int qscale)
Definition: intrax8dsp.h:27
spatial_compensation_4
static void spatial_compensation_4(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:244
avg
#define avg(a, b, c, d)
Definition: colorspacedsp_template.c:28
range
enum AVColorRange range
Definition: mediacodec_wrapper.c:2594
x8_loop_filter
static void x8_loop_filter(uint8_t *ptr, const ptrdiff_t a_stride, const ptrdiff_t b_stride, int quant)
Definition: intrax8dsp.c:337
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
spatial_compensation_10
static void spatial_compensation_10(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:315
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
spatial_compensation_1
static void spatial_compensation_1(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:217
common.h
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
spatial_compensation_3
static void spatial_compensation_3(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:236
spatial_compensation_11
static void spatial_compensation_11(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:326
stride
#define stride
Definition: h264pred_template.c:536
spatial_compensation_7
static void spatial_compensation_7(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:278
spatial_compensation_5
static void spatial_compensation_5(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:255
spatial_compensation_0
static void spatial_compensation_0(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:165
int32_t
int32_t
Definition: audioconvert.c:56
spatial_compensation_9
static void spatial_compensation_9(const uint8_t *restrict src, uint8_t *restrict dst, ptrdiff_t stride)
Definition: intrax8dsp.c:304
src
#define src
Definition: vp8dsp.c:248
ff_intrax8dsp_init
av_cold void ff_intrax8dsp_init(IntraX8DSPContext *dsp)
Definition: intrax8dsp.c:441
min
float min
Definition: vorbis_enc_data.h:429