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