]> git.sesse.net Git - ffmpeg/blob - libavcodec/intrax8dsp.c
cbs_h265: read/write HEVC PREFIX SEI
[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                                           ptrdiff_t stride, int *range,
67                                           int *psum, 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 += stride;
102         }
103     }
104
105     if (!(edges & 2)) { // (mb_y != 0) // there is row above
106         ptr = src - stride; // 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 - stride, 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 - stride);
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, ptrdiff_t stride)
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 += stride;
212     }
213 }
214
215 static void spatial_compensation_1(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
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 += stride;
223     }
224 }
225
226 static void spatial_compensation_2(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
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 += stride;
234     }
235 }
236
237 static void spatial_compensation_3(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
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 += stride;
245     }
246 }
247
248 static void spatial_compensation_4(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
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 += stride;
256     }
257 }
258
259 static void spatial_compensation_5(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
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 += stride;
271     }
272 }
273
274 static void spatial_compensation_6(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
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 += stride;
282     }
283 }
284
285 static void spatial_compensation_7(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
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 += stride;
297     }
298 }
299
300 static void spatial_compensation_8(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
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 += stride;
308     }
309 }
310
311 static void spatial_compensation_9(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
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 += stride;
319     }
320 }
321
322 static void spatial_compensation_10(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
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 += stride;
330     }
331 }
332
333 static void spatial_compensation_11(uint8_t *src, uint8_t *dst, ptrdiff_t stride)
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 += stride;
341     }
342 }
343
344 static void x8_loop_filter(uint8_t *ptr, const ptrdiff_t a_stride,
345                            const ptrdiff_t b_stride, int quant)
346 {
347     int i, t;
348     int p0, p1, p2, p3, p4, p5, p6, p7, p8, p9;
349     int ql = (quant + 10) >> 3;
350
351     for (i = 0; i < 8; i++, ptr += b_stride) {
352         p0 = ptr[-5 * a_stride];
353         p1 = ptr[-4 * a_stride];
354         p2 = ptr[-3 * a_stride];
355         p3 = ptr[-2 * a_stride];
356         p4 = ptr[-1 * a_stride];
357         p5 = ptr[0];
358         p6 = ptr[1 * a_stride];
359         p7 = ptr[2 * a_stride];
360         p8 = ptr[3 * a_stride];
361         p9 = ptr[4 * a_stride];
362
363         t = (FFABS(p1 - p2) <= ql) +
364             (FFABS(p2 - p3) <= ql) +
365             (FFABS(p3 - p4) <= ql) +
366             (FFABS(p4 - p5) <= ql);
367
368         // You need at least 1 to be able to reach a total score of 6.
369         if (t > 0) {
370             t += (FFABS(p5 - p6) <= ql) +
371                  (FFABS(p6 - p7) <= ql) +
372                  (FFABS(p7 - p8) <= ql) +
373                  (FFABS(p8 - p9) <= ql) +
374                  (FFABS(p0 - p1) <= ql);
375             if (t >= 6) {
376                 int min, max;
377
378                 min = max = p1;
379                 min = FFMIN(min, p3);
380                 max = FFMAX(max, p3);
381                 min = FFMIN(min, p5);
382                 max = FFMAX(max, p5);
383                 min = FFMIN(min, p8);
384                 max = FFMAX(max, p8);
385                 if (max - min < 2 * quant) { // early stop
386                     min = FFMIN(min, p2);
387                     max = FFMAX(max, p2);
388                     min = FFMIN(min, p4);
389                     max = FFMAX(max, p4);
390                     min = FFMIN(min, p6);
391                     max = FFMAX(max, p6);
392                     min = FFMIN(min, p7);
393                     max = FFMAX(max, p7);
394                     if (max - min < 2 * quant) {
395                         ptr[-2 * a_stride] = (4 * p2 + 3 * p3 + 1 * p7 + 4) >> 3;
396                         ptr[-1 * a_stride] = (3 * p2 + 3 * p4 + 2 * p7 + 4) >> 3;
397                         ptr[0]             = (2 * p2 + 3 * p5 + 3 * p7 + 4) >> 3;
398                         ptr[1 * a_stride]  = (1 * p2 + 3 * p6 + 4 * p7 + 4) >> 3;
399                         continue;
400                     }
401                 }
402             }
403         }
404         {
405             int x, x0, x1, x2;
406             int m;
407
408             x0 = (2 * p3 - 5 * p4 + 5 * p5 - 2 * p6 + 4) >> 3;
409             if (FFABS(x0) < quant) {
410                 x1 = (2 * p1 - 5 * p2 + 5 * p3 - 2 * p4 + 4) >> 3;
411                 x2 = (2 * p5 - 5 * p6 + 5 * p7 - 2 * p8 + 4) >> 3;
412
413                 x = FFABS(x0) - FFMIN(FFABS(x1), FFABS(x2));
414                 m = p4 - p5;
415
416                 if (x > 0 && (m ^ x0) < 0) {
417                     int32_t sign;
418
419                     sign = m >> 31;
420                     m    = (m ^ sign) - sign; // abs(m)
421                     m  >>= 1;
422
423                     x = 5 * x >> 3;
424
425                     if (x > m)
426                         x = m;
427
428                     x = (x ^ sign) - sign;
429
430                     ptr[-1 * a_stride] -= x;
431                     ptr[0]             += x;
432                 }
433             }
434         }
435     }
436 }
437
438 static void x8_h_loop_filter(uint8_t *src, ptrdiff_t stride, int qscale)
439 {
440     x8_loop_filter(src, stride, 1, qscale);
441 }
442
443 static void x8_v_loop_filter(uint8_t *src, ptrdiff_t stride, int qscale)
444 {
445     x8_loop_filter(src, 1, stride, qscale);
446 }
447
448 av_cold void ff_intrax8dsp_init(IntraX8DSPContext *dsp)
449 {
450     dsp->h_loop_filter              = x8_h_loop_filter;
451     dsp->v_loop_filter              = x8_v_loop_filter;
452     dsp->setup_spatial_compensation = x8_setup_spatial_compensation;
453     dsp->spatial_compensation[0]    = spatial_compensation_0;
454     dsp->spatial_compensation[1]    = spatial_compensation_1;
455     dsp->spatial_compensation[2]    = spatial_compensation_2;
456     dsp->spatial_compensation[3]    = spatial_compensation_3;
457     dsp->spatial_compensation[4]    = spatial_compensation_4;
458     dsp->spatial_compensation[5]    = spatial_compensation_5;
459     dsp->spatial_compensation[6]    = spatial_compensation_6;
460     dsp->spatial_compensation[7]    = spatial_compensation_7;
461     dsp->spatial_compensation[8]    = spatial_compensation_8;
462     dsp->spatial_compensation[9]    = spatial_compensation_9;
463     dsp->spatial_compensation[10]   = spatial_compensation_10;
464     dsp->spatial_compensation[11]   = spatial_compensation_11;
465 }