]> git.sesse.net Git - ffmpeg/blob - libavcodec/intrax8dsp.c
Merge commit '0b6e5d6b32b91c6da79cd919a3c2ede9d682f838'
[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, 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
140 static 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
151 static 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 }
204 static 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 }
214 static 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 }
224 static 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 }
234 static 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 }
244 static 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 }
258 static 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 }
268 static 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 }
282 static 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 }
292 static 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 }
302 static 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 }
312 static 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
323 static 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
407 static void x8_h_loop_filter(uint8_t *src, int stride, int qscale){
408     x8_loop_filter(src, stride, 1, qscale);
409 }
410
411 static void x8_v_loop_filter(uint8_t *src, int stride, int qscale){
412     x8_loop_filter(src, 1, stride, qscale);
413 }
414
415 av_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 }