2 * This file is part of FFmpeg.
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.
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.
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
21 *@brief IntraX8 frame subdecoder image manipulation routines
24 #include "intrax8dsp.h"
25 #include "libavutil/common.h"
28 * area positions, #3 is 1 pixel only, other are 8 pixels
30 * 3|44444444|55555555|
31 * - -+--------+--------+
46 #define area4 (8 + 8 + 1)
47 #define area5 (8 + 8 + 1 + 8)
48 #define area6 (8 + 8 + 1 + 16)
51 Collect statistics and prepare the edge pixels required by the other spatial compensation functions.
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;
65 static void x8_setup_spatial_compensation(uint8_t *src, uint8_t *dst,
66 int linesize, int *range, int *psum,
75 if ((edges & 3) == 3) {
76 *psum = 0x80 * (8 + 1 + 8 + 2);
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. */
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
97 min_pix = FFMIN(min_pix, c);
98 max_pix = FFMAX(max_pix, c);
105 if (!(edges & 2)) { // (mb_y != 0) // there is row above
106 ptr = src - linesize; // top line
107 for (i = 0; i < 8; i++) {
110 min_pix = FFMIN(min_pix, c);
111 max_pix = FFMAX(max_pix, c);
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);
117 memcpy(dst + area4, ptr, 16); // both area4 and 5
119 // area6 always present in the above block
120 memcpy(dst + area6, ptr - linesize, 8);
122 // now calculate the stuff we need
123 if (edges & 3) { // mb_x ==0 || mb_y == 0) {
124 int avg = (sum + 4) >> 3;
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
133 // the edge pixel, in the top line and left column
134 uint8_t c = *(src - 1 - linesize);
137 // edge pixel is not part of min/max
139 *range = max_pix - min_pix;
140 sum += *(dst + area5) + *(dst + area5 + 1);
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,
163 static void spatial_compensation_0(uint8_t *src, uint8_t *dst, int linesize)
167 unsigned int p; // power divided by 2
169 uint16_t left_sum[2][8] = { { 0 } };
170 uint16_t top_sum[2][8] = { { 0 } };
172 for (i = 0; i < 8; i++) {
173 a = src[area2 + 7 - i] << 4;
174 for (j = 0; j < 8; j++) {
176 left_sum[p & 1][j] += a >> (p >> 1);
180 for (i = 0; i < 8; i++) {
181 a = src[area4 + i] << 4;
182 for (j = 0; j < 8; j++) {
184 top_sum[p & 1][j] += a >> (p >> 1);
187 for (; i < 10; i++) {
188 a = src[area4 + i] << 4;
189 for (j = 5; j < 8; j++) {
191 top_sum[p & 1][j] += a >> (p >> 1);
194 for (; i < 12; i++) {
195 a = src[area4 + i] << 4;
196 for (j = 7; j < 8; j++) {
198 top_sum[p & 1][j] += a >> (p >> 1);
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;
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] +
215 static void spatial_compensation_1(uint8_t *src, uint8_t *dst, int linesize)
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)];
226 static void spatial_compensation_2(uint8_t *src, uint8_t *dst, int linesize)
230 for (y = 0; y < 8; y++) {
231 for (x = 0; x < 8; x++)
232 dst[x] = src[area4 + 1 + y + x];
237 static void spatial_compensation_3(uint8_t *src, uint8_t *dst, int linesize)
241 for (y = 0; y < 8; y++) {
242 for (x = 0; x < 8; x++)
243 dst[x] = src[area4 + ((y + 1) >> 1) + x];
248 static void spatial_compensation_4(uint8_t *src, uint8_t *dst, int linesize)
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;
259 static void spatial_compensation_5(uint8_t *src, uint8_t *dst, int linesize)
263 for (y = 0; y < 8; y++) {
264 for (x = 0; x < 8; x++) {
266 dst[x] = src[area2 + 9 + 2 * x - y];
268 dst[x] = src[area4 + x - ((y + 1) >> 1)];
274 static void spatial_compensation_6(uint8_t *src, uint8_t *dst, int linesize)
278 for (y = 0; y < 8; y++) {
279 for (x = 0; x < 8; x++)
280 dst[x] = src[area3 + x - y];
285 static void spatial_compensation_7(uint8_t *src, uint8_t *dst, int linesize)
289 for (y = 0; y < 8; y++) {
290 for (x = 0; x < 8; x++) {
292 dst[x] = (src[area3 - 1 + x - 2 * y] + src[area3 + x - 2 * y] + 1) >> 1;
294 dst[x] = src[area2 + 8 - y + (x >> 1)];
300 static void spatial_compensation_8(uint8_t *src, uint8_t *dst, int linesize)
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;
311 static void spatial_compensation_9(uint8_t *src, uint8_t *dst, int linesize)
315 for (y = 0; y < 8; y++) {
316 for (x = 0; x < 8; x++)
317 dst[x] = src[area2 + 6 - FFMIN(x + y, 6)];
322 static void spatial_compensation_10(uint8_t *src, uint8_t *dst, int linesize)
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;
333 static void spatial_compensation_11(uint8_t *src, uint8_t *dst, int linesize)
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;
344 static void x8_loop_filter(uint8_t *ptr, const int a_stride, const int b_stride, int quant)
347 int p0, p1, p2, p3, p4, p5, p6, p7, p8, p9;
348 int ql = (quant + 10) >> 3;
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];
357 p6 = ptr[1 * a_stride];
358 p7 = ptr[2 * a_stride];
359 p8 = ptr[3 * a_stride];
360 p9 = ptr[4 * a_stride];
362 t = (FFABS(p1 - p2) <= ql) +
363 (FFABS(p2 - p3) <= ql) +
364 (FFABS(p3 - p4) <= ql) +
365 (FFABS(p4 - p5) <= ql);
367 // You need at least 1 to be able to reach a total score of 6.
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);
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;
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;
412 x = FFABS(x0) - FFMIN(FFABS(x1), FFABS(x2));
415 if (x > 0 && (m ^ x0) < 0) {
419 m = (m ^ sign) - sign; // abs(m)
427 x = (x ^ sign) - sign;
429 ptr[-1 * a_stride] -= x;
437 static void x8_h_loop_filter(uint8_t *src, int stride, int qscale)
439 x8_loop_filter(src, stride, 1, qscale);
442 static void x8_v_loop_filter(uint8_t *src, int stride, int qscale)
444 x8_loop_filter(src, 1, stride, qscale);
447 av_cold void ff_intrax8dsp_init(IntraX8DSPContext *dsp)
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;