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