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