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