876bd398cdae0313584c3978130bfe03771b3c1d
[ffmpeg.git] / 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 intrax8dsp.c
21  *@brief IntraX8 frame sub-decoder image manipulation routines
22  *
23  */
24
25 #include "dsputil.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 spacial 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 in way other compensation routines use.
55  * @param linesize byte offset between 2 vertical pixels in the source image
56  * @param range pointer to the variable where the range of edge pixels is to be stored (max-min values)
57  * @param psum  pointer to the variable where the sum of edge pixels is to be stored
58  * @param edges informs this routine that the block is on image border, so it have to interpolate the missing edge pixels.
59                 and some of the edge pixels should be interpolated, flag have 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 on the row, interpolate area #5;
64 */
65 static void x8_setup_spacial_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 calc the stuff we need
120     if(edges&3){//mb_x==0 || mb_y==0){
121         if(edges&1){ //(mb_x==0) {//implies mb_y!=0
122             int avg=(sum+4)>>3;
123             memset(dst+area1,avg,8+8+1);//areas 1,2 and 3 are averaged
124             sum+=avg*9;//8+1(egde pixel)
125         }else{//implies y==0 x!=0
126             int avg=(sum+4)>>3;
127             memset(dst+area3,avg, 1+16+8);//areas 3, 4,5,6
128             sum+=avg*9;
129         }
130     }else{
131         uint8_t c;
132         c=*(src-1-linesize);//the edge pixel,in the top line and left column
133         dst[area3]=c;
134         sum+=c;
135         //edge pixel is not part of min/max
136     }
137     (*range) = max_pix - min_pix;
138     sum += *(dst+area5) + *(dst+area5+1);
139     *psum = sum;
140 }
141
142
143 static const uint16_t zero_prediction_weights[64*2] = {
144     640,  640,  669,  480,  708,  354,  748, 257,  792, 198,  760, 143,  808, 101,  772,  72,
145     480,  669,  537,  537,  598,  416,  661, 316,  719, 250,  707, 185,  768, 134,  745,  97,
146     354,  708,  416,  598,  488,  488,  564, 388,  634, 317,  642, 241,  716, 179,  706, 132,
147     257,  748,  316,  661,  388,  564,  469, 469,  543, 395,  571, 311,  655, 238,  660, 180,
148     198,  792,  250,  719,  317,  634,  395, 543,  469, 469,  507, 380,  597, 299,  616, 231,
149     161,  855,  206,  788,  266,  710,  340, 623,  411, 548,  455, 455,  548, 366,  576, 288,
150     122,  972,  159,  914,  211,  842,  276, 758,  341, 682,  389, 584,  483, 483,  520, 390,
151     110, 1172,  144, 1107,  193, 1028,  254, 932,  317, 846,  366, 731,  458, 611,  499, 499
152 };
153
154 static void spacial_compensation_0(uint8_t *src , uint8_t *dst, int linesize){
155     int i,j;
156     int x,y;
157     unsigned int p;//power divided by 2
158     int a;
159     uint16_t left_sum[2][8];
160     uint16_t  top_sum[2][8];
161     memset(left_sum,0,2*8*sizeof(uint16_t));
162     memset( top_sum,0,2*8*sizeof(uint16_t));
163
164     for(i=0;i<8;i++){
165         a=src[area2+7-i]<<4;
166         for(j=0;j<8;j++){
167             p=abs(i-j);
168             left_sum[p&1][j]+= a>>(p>>1);
169         }
170     }
171
172     for(i=0;i<8;i++){
173         a=src[area4+i]<<4;
174         for(j=0;j<8;j++){
175             p=abs(i-j);
176             top_sum[p&1][j]+=   a>>(p>>1);
177         }
178     }
179     for(;i<10;i++){
180         a=src[area4+i]<<4;
181         for(j=5;j<8;j++){
182             p=abs(i-j);
183             top_sum[p&1][j]+=   a>>(p>>1);
184         }
185     }
186     for(;i<12;i++){
187         a=src[area4+i]<<4;
188         for(j=7;j<8;j++){
189             p=abs(i-j);
190             top_sum[p&1][j]+=   a>>(p>>1);
191         }
192     }
193
194     for(i=0;i<8;i++){
195         top_sum [0][i]+=(top_sum [1][i]*181 + 128 )>>8;//181 is sqrt(2)/2
196         left_sum[0][i]+=(left_sum[1][i]*181 + 128 )>>8;
197     }
198     for(y=0;y<8;y++){
199         for(x=0;x<8;x++){
200             dst[x] = (
201                       (uint32_t)top_sum [0][x]*zero_prediction_weights[y*16+x*2+0] +
202                       (uint32_t)left_sum[0][y]*zero_prediction_weights[y*16+x*2+1] +
203                        0x8000
204                       )>>16;
205         }
206         dst+=linesize;
207     }
208 }
209 static void spacial_compensation_1(uint8_t *src , uint8_t *dst, int linesize){
210     int x,y;
211
212     for(y=0;y<8;y++){
213         for(x=0;x<8;x++){
214             dst[x]=src[area4 + FFMIN(2*y+x+2, 15) ];
215         }
216         dst+=linesize;
217     }
218 }
219 static void spacial_compensation_2(uint8_t *src , uint8_t *dst, int linesize){
220     int x,y;
221
222     for(y=0;y<8;y++){
223         for(x=0;x<8;x++){
224             dst[x]=src[area4 +1+y+x];
225         }
226         dst+=linesize;
227     }
228 }
229 static void spacial_compensation_3(uint8_t *src , uint8_t *dst, int linesize){
230     int x,y;
231
232     for(y=0;y<8;y++){
233         for(x=0;x<8;x++){
234             dst[x]=src[area4 +((y+1)>>1)+x];
235         }
236         dst+=linesize;
237     }
238 }
239 static void spacial_compensation_4(uint8_t *src , uint8_t *dst, int linesize){
240     int x,y;
241
242     for(y=0;y<8;y++){
243         for(x=0;x<8;x++){
244             dst[x]=( src[area4+x] + src[area6+x] + 1 )>>1;
245         }
246         dst+=linesize;
247     }
248 }
249 static void spacial_compensation_5(uint8_t *src , uint8_t *dst, int linesize){
250     int x,y;
251
252     for(y=0;y<8;y++){
253         for(x=0;x<8;x++){
254             if(2*x-y<0){
255                 dst[x]=src[area2+9+2*x-y];
256             }else{
257                 dst[x]=src[area4 +x-((y+1)>>1)];
258             }
259         }
260         dst+=linesize;
261     }
262 }
263 static void spacial_compensation_6(uint8_t *src , uint8_t *dst, int linesize){
264     int x,y;
265
266     for(y=0;y<8;y++){
267         for(x=0;x<8;x++){
268             dst[x]=src[area3+x-y];
269         }
270         dst+=linesize;
271     }
272 }
273 static void spacial_compensation_7(uint8_t *src , uint8_t *dst, int linesize){
274     int x,y;
275
276     for(y=0;y<8;y++){
277         for(x=0;x<8;x++){
278             if(x-2*y>0){
279                 dst[x]=( src[area3-1+x-2*y] + src[area3+x-2*y] + 1)>>1;
280             }else{
281                 dst[x]=src[area2+8-y +(x>>1)];
282             }
283         }
284         dst+=linesize;
285     }
286 }
287 static void spacial_compensation_8(uint8_t *src , uint8_t *dst, int linesize){
288     int x,y;
289
290     for(y=0;y<8;y++){
291         for(x=0;x<8;x++){
292             dst[x]=( src[area1+7-y] + src[area2+7-y] + 1 )>>1;
293         }
294         dst+=linesize;
295     }
296 }
297 static void spacial_compensation_9(uint8_t *src , uint8_t *dst, int linesize){
298     int x,y;
299
300     for(y=0;y<8;y++){
301         for(x=0;x<8;x++){
302             dst[x]=src[area2+6-FFMIN(x+y,6)];
303         }
304         dst+=linesize;
305     }
306 }
307 static void spacial_compensation_10(uint8_t *src , uint8_t *dst, int linesize){
308     int x,y;
309
310     for(y=0;y<8;y++){
311         for(x=0;x<8;x++){
312             dst[x]=(src[area2+7-y]*(8-x)+src[area4+x]*x+4)>>3;
313         }
314         dst+=linesize;
315     }
316 }
317 static void spacial_compensation_11(uint8_t *src , uint8_t *dst, int linesize){
318     int x,y;
319
320     for(y=0;y<8;y++){
321         for(x=0;x<8;x++){
322             dst[x]=(src[area2+7-y]*y+src[area4+x]*(8-y)+4)>>3;
323         }
324         dst+=linesize;
325     }
326 }
327
328 static void x8_loop_filter(uint8_t * ptr, const int a_stride, const int b_stride, int quant){
329     int i,t;
330     int p0,p1,p2,p3,p4,p5,p6,p7,p8,p9;
331     int ql=(quant+10)>>3;
332
333     for(i=0; i<8; i++,ptr+=b_stride){
334         p0=ptr[-5*a_stride];
335         p1=ptr[-4*a_stride];
336         p2=ptr[-3*a_stride];
337         p3=ptr[-2*a_stride];
338         p4=ptr[-1*a_stride];
339         p5=ptr[ 0         ];
340         p6=ptr[ 1*a_stride];
341         p7=ptr[ 2*a_stride];
342         p8=ptr[ 3*a_stride];
343         p9=ptr[ 4*a_stride];
344
345         t=
346             (FFABS(p1-p2) <= ql) +
347             (FFABS(p2-p3) <= ql) +
348             (FFABS(p3-p4) <= ql) +
349             (FFABS(p4-p5) <= ql);
350         if(t>0){//you need at least 1 to be able to reach total score of 6.
351             t+=
352                 (FFABS(p5-p6) <= ql) +
353                 (FFABS(p6-p7) <= ql) +
354                 (FFABS(p7-p8) <= ql) +
355                 (FFABS(p8-p9) <= ql) +
356                 (FFABS(p0-p1) <= ql);
357             if(t>=6){
358                 int min,max;
359
360                 min=max=p1;
361                 min=FFMIN(min,p3); max=FFMAX(max,p3);
362                 min=FFMIN(min,p5); max=FFMAX(max,p5);
363                 min=FFMIN(min,p8); max=FFMAX(max,p8);
364                 if(max-min<2*quant){//early stop
365                     min=FFMIN(min,p2); max=FFMAX(max,p2);
366                     min=FFMIN(min,p4); max=FFMAX(max,p4);
367                     min=FFMIN(min,p6); max=FFMAX(max,p6);
368                     min=FFMIN(min,p7); max=FFMAX(max,p7);
369                     if(max-min<2*quant){
370                         ptr[-2*a_stride]=(4*p2 + 3*p3 + 1*p7 + 4)>>3;
371                         ptr[-1*a_stride]=(3*p2 + 3*p4 + 2*p7 + 4)>>3;
372                         ptr[ 0         ]=(2*p2 + 3*p5 + 3*p7 + 4)>>3;
373                         ptr[ 1*a_stride]=(1*p2 + 3*p6 + 4*p7 + 4)>>3;
374                         continue;
375                     };
376                 }
377             }
378         }
379         {
380             int x,x0,x1,x2;
381             int m;
382
383             x0 =   (2*p3 - 5*p4 + 5*p5 - 2*p6 + 4)>>3;
384             if(FFABS(x0) < quant){
385                 x1=(2*p1 - 5*p2 + 5*p3 - 2*p4 + 4)>>3;
386                 x2=(2*p5 - 5*p6 + 5*p7 - 2*p8 + 4)>>3;
387
388                 x=FFABS(x0) - FFMIN( FFABS(x1), FFABS(x2) );
389                 m=p4-p5;
390
391                 if( x > 0 && (m^x0) <0){
392                     int32_t sign;
393
394                     sign=m>>31;
395                     m=(m^sign)-sign;//abs(m)
396                     m>>=1;
397
398                     x=(5*x)>>3;
399
400                     if(x>m) x=m;
401
402                     x=(x^sign)-sign;
403
404                     ptr[-1*a_stride] -= x;
405                     ptr[ 0]          += x;
406                 }
407             }
408         }
409     }
410 }
411
412 static void x8_h_loop_filter(uint8_t *src, int stride, int qscale){
413     x8_loop_filter(src, stride, 1, qscale);
414 }
415
416 static void x8_v_loop_filter(uint8_t *src, int stride, int qscale){
417     x8_loop_filter(src, 1, stride, qscale);
418 }
419
420 void ff_intrax8dsp_init(DSPContext* dsp, AVCodecContext *avctx) {
421     dsp->x8_h_loop_filter=x8_h_loop_filter;
422     dsp->x8_v_loop_filter=x8_v_loop_filter;
423     dsp->x8_setup_spacial_compensation=x8_setup_spacial_compensation;
424     dsp->x8_spacial_compensation[0]=spacial_compensation_0;
425     dsp->x8_spacial_compensation[1]=spacial_compensation_1;
426     dsp->x8_spacial_compensation[2]=spacial_compensation_2;
427     dsp->x8_spacial_compensation[3]=spacial_compensation_3;
428     dsp->x8_spacial_compensation[4]=spacial_compensation_4;
429     dsp->x8_spacial_compensation[5]=spacial_compensation_5;
430     dsp->x8_spacial_compensation[6]=spacial_compensation_6;
431     dsp->x8_spacial_compensation[7]=spacial_compensation_7;
432     dsp->x8_spacial_compensation[8]=spacial_compensation_8;
433     dsp->x8_spacial_compensation[9]=spacial_compensation_9;
434     dsp->x8_spacial_compensation[10]=spacial_compensation_10;
435     dsp->x8_spacial_compensation[11]=spacial_compensation_11;
436 }
437
438 #if 0
439 static void wmv2_loop_filter(uint8_t * ptr, const int a_stride, const int b_stride, int quant){
440     int i,t;
441     int p0,p1,p2,p3,p4,p5,p6,p7,p8,p9;
442
443     for(i=0; i<8; i++,ptr+=b_stride){
444         p1=ptr[-4*a_stride];
445         p2=ptr[-3*a_stride];
446         p3=ptr[-2*a_stride];
447         p4=ptr[-1*a_stride];
448         p5=ptr[ 0         ];
449         p6=ptr[ 1*a_stride];
450         p7=ptr[ 2*a_stride];
451         p8=ptr[ 3*a_stride];
452
453         {
454             int x,x0,x1,x2;
455             int m;
456
457             x0 =   (2*p3 - 5*p4 + 5*p5 - 2*p6 + 4)>>3;
458             if(abs(x0) < quant){
459                 x1=(2*p1 - 5*p2 + 5*p3 - 2*p4 + 4)>>3;
460                 x2=(2*p5 - 5*p6 + 5*p7 - 2*p8 + 4)>>3;
461
462                 x=abs(x0) - FFMIN( abs(x1), abs(x2) );
463                 m=p4-p5;
464
465                 if( x > 0 && (m^x0) < 0){
466                     int32_t sign;
467
468                     sign=m>>31;
469                     m=(m^sign)-sign;//abs(m)
470                     m>>=1;
471
472                     x=(5*x)>>3;
473
474                     if(x>m) x=m;
475
476                     x=(x^sign)-sign;
477
478                     ptr[-1*a_stride] -= x;
479                     ptr[ 0]          += x;
480                 }
481             }
482         }
483     }
484 }
485 #endif