[cvs] / xvidcore / src / motion / gmc.c Repository:
ViewVC logotype

Diff of /xvidcore/src/motion/gmc.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1, Sat Jun 28 15:54:10 2003 UTC revision 1.1.2.2, Sun Jul 13 09:58:35 2003 UTC
# Line 0  Line 1 
1    /**************************************************************************
2     *
3     *      XVID MPEG-4 VIDEO CODEC
4     *      GMC interpolation module
5     *
6     *      This program is free software; you can redistribute it and/or modify
7     *      it under the terms of the GNU General Public License as published by
8     *      the Free Software Foundation; either version 2 of the License, or
9     *      (at your option) any later version.
10     *
11     *      This program is distributed in the hope that it will be useful,
12     *      but WITHOUT ANY WARRANTY; without even the implied warranty of
13     *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
14     *      GNU General Public License for more details.
15     *
16     *      You should have received a copy of the GNU General Public License
17     *      along with this program; if not, write to the Free Software
18     *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19     *
20     *************************************************************************/
21    
22    #include "../portab.h"
23    #include "../global.h"
24    #include "../encoder.h"
25    #include "gmc.h"
26    
27    #include <stdio.h>
28    
29    /* These are mainly the new GMC routines by -Skal- (C) 2003 */
30    
31    //////////////////////////////////////////////////////////
32    // Pts = 2 or 3
33    
34    // Warning! *src is the global frame pointer (that is: adress
35    // of pixel 0,0), not the macroblock one.
36    // Conversely, *dst is the macroblock top-left adress.
37    
38    
39    void Predict_16x16_C(const NEW_GMC_DATA * const This,
40                                             uint8_t *dst, const uint8_t *src,
41                                             int dststride, int srcstride, int x, int y, int rounding)
42    {
43            const int W = This->sW;
44            const int H     = This->sH;
45            const int rho = 3 - This->accuracy;
46            const int Rounder = ( (1<<7) - (rounding<<(2*rho)) ) << 16;
47    
48            const int dUx = This->dU[0];
49            const int dVx = This->dV[0];
50            const int dUy = This->dU[1];
51            const int dVy = This->dV[1];
52    
53            int Uo = This->Uo + 16*(dUy*y + dUx*x);
54            int Vo = This->Vo + 16*(dVy*y + dVx*x);
55    
56            int i, j;
57    
58            dst += 16;
59            for (j=16; j>0; --j)
60            {
61            int U = Uo, V = Vo;
62            Uo += dUy; Vo += dVy;
63            for (i=-16; i<0; ++i)
64            {
65                    unsigned int f0, f1, ri, rj;
66                    int Offset;
67    
68                    int u = ( U >> 16 ) << rho;
69                    int v = ( V >> 16 ) << rho;
70                    U += dUx; V += dVx;
71    
72                    ri = 16;
73                    if ((uint32_t)u<=(uint32_t)W) { ri = MTab[u&15]; Offset = u>>4; }
74                    else if (u>W) Offset = W>>4;
75                    else Offset = -1;
76    
77                    rj = 16;
78                    if ((uint32_t)v<=(uint32_t)H) { rj = MTab[v&15]; Offset += (v>>4)*srcstride; }
79                    else if (v>H) Offset += (H>>4)*srcstride;
80                    else Offset -= srcstride;
81    
82                    f0      = src[ Offset    +0 ];
83                    f0 |= src[ Offset        +1 ] << 16;
84                    f1      = src[ Offset+srcstride +0 ];
85                    f1 |= src[ Offset+srcstride +1 ] << 16;
86                    f0 = (ri*f0)>>16;
87                    f1 = (ri*f1) & 0x0fff0000;
88                    f0 |= f1;
89                    f0 = ( rj*f0 + Rounder ) >> 24;
90    
91                    dst[i] = (uint8_t)f0;
92            }
93            dst += dststride;
94            }
95    }
96    
97    
98    void Predict_8x8_C(const NEW_GMC_DATA * const This,
99                                             uint8_t *uDst, const uint8_t *uSrc,
100                                             uint8_t *vDst, const uint8_t *vSrc,
101                                             int dststride, int srcstride, int x, int y, int rounding)
102    {
103            const int W      = This->sW >> 1;
104            const int H      = This->sH >> 1;
105            const int rho = 3-This->accuracy;
106            const int32_t Rounder = ( 128 - (rounding<<(2*rho)) ) << 16;
107    
108            const int32_t dUx = This->dU[0];
109            const int32_t dVx = This->dV[0];
110            const int32_t dUy = This->dU[1];
111            const int32_t dVy = This->dV[1];
112    
113            int32_t Uo = This->Uco + 8*(dUy*y + dUx*x);
114            int32_t Vo = This->Vco + 8*(dVy*y + dVx*x);
115    
116            int i, j;
117    
118            uDst += 8;
119            vDst += 8;
120            for (j=8; j>0; --j)
121            {
122            int32_t U = Uo, V = Vo;
123            Uo += dUy; Vo += dVy;
124    
125            for (i=-8; i<0; ++i)
126            {
127                    int Offset;
128                    uint32_t f0, f1, ri, rj;
129                    int32_t u, v;
130    
131                    u = ( U >> 16 ) << rho;
132                    v = ( V >> 16 ) << rho;
133                    U += dUx; V += dVx;
134    
135                    if ((uint32_t)u<=(uint32_t)W) {
136                    ri = MTab[u&15];
137                    Offset = u>>4;
138                    }
139                    else {
140                    ri = 16;
141                    if (u>W) Offset = W>>4;
142                    else Offset = -1;
143                    }
144                    if ((uint32_t)v<=(uint32_t)H) {
145                    rj = MTab[v&15];
146                    Offset += (v>>4)*srcstride;
147                    }
148                    else {
149                    rj = 16;
150                    if (v>H) Offset += (H>>4)*srcstride;
151                    else Offset -= srcstride;
152                    }
153    
154                    f0      = uSrc[ Offset          +0 ];
155                    f0 |= uSrc[ Offset              +1 ] << 16;
156                    f1      = uSrc[ Offset+srcstride +0 ];
157                    f1 |= uSrc[ Offset+srcstride +1 ] << 16;
158                    f0 = (ri*f0)>>16;
159                    f1 = (ri*f1) & 0x0fff0000;
160                    f0 |= f1;
161                    f0 = ( rj*f0 + Rounder ) >> 24;
162    
163                    uDst[i] = (uint8_t)f0;
164    
165                    f0      = vSrc[ Offset          +0 ];
166                    f0 |= vSrc[ Offset              +1 ] << 16;
167                    f1      = vSrc[ Offset+srcstride +0 ];
168                    f1 |= vSrc[ Offset+srcstride +1 ] << 16;
169                    f0 = (ri*f0)>>16;
170                    f1 = (ri*f1) & 0x0fff0000;
171                    f0 |= f1;
172                    f0 = ( rj*f0 + Rounder ) >> 24;
173    
174                    vDst[i] = (uint8_t)f0;
175            }
176            uDst += dststride;
177            vDst += dststride;
178            }
179    }
180    
181    
182    void get_average_mv_C(const NEW_GMC_DATA * const Dsp, VECTOR * const mv,
183                                                    int x, int y, int qpel)
184    {
185            int i, j;
186            int vx = 0, vy = 0;
187            int32_t uo = Dsp->Uo + 16*(Dsp->dU[1]*y + Dsp->dU[0]*x);
188            int32_t vo = Dsp->Vo + 16*(Dsp->dV[1]*y + Dsp->dV[0]*x);
189            for (j=16; j>0; --j)
190            {
191            int32_t U, V;
192            U = uo; uo += Dsp->dU[1];
193            V = vo; vo += Dsp->dV[1];
194            for (i=16; i>0; --i)
195            {
196                    int32_t u,v;
197                    u = U >> 16; U += Dsp->dU[0]; vx += u;
198                    v = V >> 16; V += Dsp->dV[0]; vy += v;
199            }
200            }
201            vx -= (256*x+120) << (5+Dsp->accuracy); // 120 = 15*16/2
202            vy -= (256*y+120) << (5+Dsp->accuracy);
203    
204            mv->x = RSHIFT( vx, 8+Dsp->accuracy - qpel );
205            mv->y = RSHIFT( vy, 8+Dsp->accuracy - qpel );
206    }
207    
208    //////////////////////////////////////////////////////////
209    // simplified version for 1 warp point
210    
211    
212    void Predict_1pt_16x16_C(const NEW_GMC_DATA * const This,
213                                                     uint8_t *Dst, const uint8_t *Src,
214                                                     int dststride, int srcstride, int x, int y, int rounding)
215    {
216            const int W      = This->sW;
217            const int H      = This->sH;
218            const int rho = 3-This->accuracy;
219            const int32_t Rounder = ( 128 - (rounding<<(2*rho)) ) << 16;
220    
221    
222            int32_t uo = This->Uo + (x<<8);  // ((16*x)<<4)
223            int32_t vo = This->Vo + (y<<8);
224            const uint32_t ri = MTab[uo & 15];
225            const uint32_t rj = MTab[vo & 15];
226            int i, j;
227    
228            int32_t Offset;
229            if ((uint32_t)vo<=(uint32_t)H) Offset   = (vo>>4)*srcstride;
230            else if (vo>H)                           Offset = ( H>>4)*srcstride;
231            else                                                     Offset =-16*srcstride;
232            if ((uint32_t)uo<=(uint32_t)W) Offset += (uo>>4);
233            else if (uo>W)                           Offset += ( W>>4);
234            else                                                     Offset -= 16;
235    
236            Dst += 16;
237    
238            for(j=16; j>0; --j, Offset+=srcstride-16)
239            {
240            for(i=-16; i<0; ++i, ++Offset)
241            {
242                    uint32_t f0, f1;
243                    f0      = Src[ Offset           +0 ];
244                    f0 |= Src[ Offset               +1 ] << 16;
245                    f1      = Src[ Offset+srcstride +0 ];
246                    f1 |= Src[ Offset+srcstride +1 ] << 16;
247                    f0 = (ri*f0)>>16;
248                    f1 = (ri*f1) & 0x0fff0000;
249                    f0 |= f1;
250                    f0 = ( rj*f0 + Rounder ) >> 24;
251                    Dst[i] = (uint8_t)f0;
252            }
253            Dst += dststride;
254            }
255    }
256    
257    
258    void Predict_1pt_8x8_C(const NEW_GMC_DATA * const This,
259                                                     uint8_t *uDst, const uint8_t *uSrc,
260                                                     uint8_t *vDst, const uint8_t *vSrc,
261                                                     int dststride, int srcstride, int x, int y, int rounding)
262    {
263            const int W      = This->sW >> 1;
264            const int H      = This->sH >> 1;
265            const int rho = 3-This->accuracy;
266            const int32_t Rounder = ( 128 - (rounding<<(2*rho)) ) << 16;
267    
268            int32_t uo = This->Uco + (x<<7);
269            int32_t vo = This->Vco + (y<<7);
270            const uint32_t rri = MTab[uo & 15];
271            const uint32_t rrj = MTab[vo & 15];
272            int i, j;
273    
274            int32_t Offset;
275            if ((uint32_t)vo<=(uint32_t)H) Offset = (vo>>4)*srcstride;
276            else if (vo>H) Offset = ( H>>4)*srcstride;
277            else Offset =-8*srcstride;
278            if ((uint32_t)uo<=(uint32_t)W) Offset += (uo>>4);
279            else if (uo>W) Offset += (W>>4);
280            else Offset -= 8;
281    
282            uDst += 8;
283            vDst += 8;
284            for(j=8; j>0; --j, Offset+=srcstride-8)
285            {
286            for(i=-8; i<0; ++i, Offset++)
287            {
288                    uint32_t f0, f1;
289                    f0      = uSrc[ Offset + 0 ];
290                    f0 |= uSrc[ Offset + 1 ] << 16;
291                    f1      = uSrc[ Offset + srcstride + 0 ];
292                    f1 |= uSrc[ Offset + srcstride + 1 ] << 16;
293                    f0 = (rri*f0)>>16;
294                    f1 = (rri*f1) & 0x0fff0000;
295                    f0 |= f1;
296                    f0 = ( rrj*f0 + Rounder ) >> 24;
297                    uDst[i] = (uint8_t)f0;
298    
299                    f0      = vSrc[ Offset + 0 ];
300                    f0 |= vSrc[ Offset + 1 ] << 16;
301                    f1      = vSrc[ Offset + srcstride + 0 ];
302                    f1 |= vSrc[ Offset + srcstride + 1 ] << 16;
303                    f0 = (rri*f0)>>16;
304                    f1 = (rri*f1) & 0x0fff0000;
305                    f0 |= f1;
306                    f0 = ( rrj*f0 + Rounder ) >> 24;
307                    vDst[i] = (uint8_t)f0;
308            }
309            uDst += dststride;
310            vDst += dststride;
311            }
312    }
313    
314    
315    void get_average_mv_1pt_C(const NEW_GMC_DATA * const Dsp, VECTOR * const mv,
316                                                            int x, int y, int qpel)
317    {
318            mv->x = RSHIFT(Dsp->Uo<<qpel, 3);
319            mv->y = RSHIFT(Dsp->Vo<<qpel, 3);
320    }
321    
322    //////////////////////////////////////////////////////////
323    
324    
325            // Warning! It's Accuracy being passed, not 'resolution'!
326    
327    void generate_GMCparameters( int nb_pts, const int accuracy,
328                                                                     const WARPPOINTS *const pts,
329                                                                     const int width, const int height,
330                                                                     NEW_GMC_DATA *const gmc)
331    {
332            gmc->sW = width << 4;
333            gmc->sH = height << 4;
334            gmc->accuracy = accuracy;
335            gmc->num_wp = nb_pts;
336    
337            // reduce the number of points, if possible
338            if (nb_pts<3 || (pts->duv[2].x==-pts->duv[1].y && pts->duv[2].y==pts->duv[1].x)) {
339            if (nb_pts<2 || (pts->duv[1].x==0 && pts->duv[1].y==0)) {
340                    if (nb_pts<1 || (pts->duv[0].x==0 && pts->duv[0].y==0)) {
341                    nb_pts = 0;
342                    }
343                    else nb_pts = 1;
344            }
345            else nb_pts = 2;
346            }
347            else nb_pts = 3;
348    
349            // now, nb_pts stores the actual number of points required for interpolation
350    
351            if (nb_pts<=1)
352            {
353            if (nb_pts==1) {
354                    // store as 4b fixed point
355                    gmc->Uo = pts->duv[0].x << accuracy;
356                    gmc->Vo = pts->duv[0].y << accuracy;
357                    gmc->Uco = ((pts->duv[0].x>>1) | (pts->duv[0].x&1)) << accuracy;         // DIV2RND()
358                    gmc->Vco = ((pts->duv[0].y>>1) | (pts->duv[0].y&1)) << accuracy;         // DIV2RND()
359            }
360            else {  // zero points?!
361                    gmc->Uo = gmc->Vo       = 0;
362                    gmc->Uco = gmc->Vco = 0;
363            }
364    
365            gmc->predict_16x16      = Predict_1pt_16x16_C;
366            gmc->predict_8x8        = Predict_1pt_8x8_C;
367            gmc->get_average_mv = get_average_mv_1pt_C;
368            }
369            else {          // 2 or 3 points
370            const int rho    = 3 - accuracy;        // = {3,2,1,0} for Acc={0,1,2,3}
371            int Alpha = log2bin(width-1);
372            int Ws = 1 << Alpha;
373    
374            gmc->dU[0] = 16*Ws + RDIV( 8*Ws*pts->duv[1].x, width );  // dU/dx
375            gmc->dV[0] =             RDIV( 8*Ws*pts->duv[1].y, width );      // dV/dx
376    
377    /*       disabled, because possibly buggy? */
378    
379    /* if (nb_pts==2) {
380                    gmc->dU[1] = -gmc->dV[0];       // -Sin
381                    gmc->dV[1] =    gmc->dU[0] ;    //      Cos
382            }
383            else */
384            {
385                    const int Beta = log2bin(height-1);
386                    const int Hs = 1<<Beta;
387                    gmc->dU[1] =             RDIV( 8*Hs*pts->duv[2].x, height );     // dU/dy
388                    gmc->dV[1] = 16*Hs + RDIV( 8*Hs*pts->duv[2].y, height );         // dV/dy
389                    if (Beta>Alpha) {
390                    gmc->dU[0] <<= (Beta-Alpha);
391                    gmc->dV[0] <<= (Beta-Alpha);
392                    Alpha = Beta;
393                    Ws = Hs;
394                    }
395                    else {
396                    gmc->dU[1] <<= Alpha - Beta;
397                    gmc->dV[1] <<= Alpha - Beta;
398                    }
399            }
400                    // upscale to 16b fixed-point
401            gmc->dU[0] <<= (16-Alpha - rho);
402            gmc->dU[1] <<= (16-Alpha - rho);
403            gmc->dV[0] <<= (16-Alpha - rho);
404            gmc->dV[1] <<= (16-Alpha - rho);
405    
406            gmc->Uo = ( pts->duv[0].x        <<(16+ accuracy)) + (1<<15);
407            gmc->Vo = ( pts->duv[0].y        <<(16+ accuracy)) + (1<<15);
408            gmc->Uco = ((pts->duv[0].x-1)<<(17+ accuracy)) + (1<<17);
409            gmc->Vco = ((pts->duv[0].y-1)<<(17+ accuracy)) + (1<<17);
410            gmc->Uco = (gmc->Uco + gmc->dU[0] + gmc->dU[1])>>2;
411            gmc->Vco = (gmc->Vco + gmc->dV[0] + gmc->dV[1])>>2;
412    
413            gmc->predict_16x16      = Predict_16x16_C;
414            gmc->predict_8x8        = Predict_8x8_C;
415            gmc->get_average_mv = get_average_mv_C;
416            }
417    }
418    
419    //////////////////////////////////////////////////////////
420    
421    
422    /* quick and dirty routine to generate the full warped image (pGMC != NULL)
423            or just all average Motion Vectors (pGMC == NULL) */
424    
425    void
426    generate_GMCimage(      const NEW_GMC_DATA *const gmc_data, // [input] precalculated data
427                                            const IMAGE *const pRef,                // [input]
428                                            const int mb_width,
429                                            const int mb_height,
430                                            const int stride,
431                                            const int stride2,
432                                            const int fcode,                                // [input] some parameters...
433                                                    const int32_t quarterpel,               // [input] for rounding avgMV
434                                            const int reduced_resolution,   // [input] ignored
435                                            const int32_t rounding,                 // [input] for rounding image data
436                                            MACROBLOCK *const pMBs,                 // [output] average motion vectors
437                                            IMAGE *const pGMC)                              // [output] full warped image
438    {
439    
440            unsigned int mj,mi;
441            VECTOR avgMV;
442    
443            for (mj = 0; mj < (unsigned int)mb_height; mj++)
444                    for (mi = 0; mi < (unsigned int)mb_width; mi++) {
445                            const int mbnum = mj*mb_width+mi;
446                            if (pGMC)
447                            {
448                                    gmc_data->predict_16x16(gmc_data,
449                                                            pGMC->y + mj*16*stride + mi*16, pRef->y,
450                                                            stride, stride, mi, mj, rounding);
451    
452                                    gmc_data->predict_8x8(gmc_data,
453                                            pGMC->u + mj*8*stride2 + mi*8, pRef->u,
454                                            pGMC->v + mj*8*stride2 + mi*8, pRef->v,
455                                            stride2, stride2, mi, mj, rounding);
456                            }
457                            gmc_data->get_average_mv(gmc_data, &avgMV, mi, mj, quarterpel);
458    
459                            pMBs[mbnum].amv.x = gmc_sanitize(avgMV.x, quarterpel, fcode);
460                            pMBs[mbnum].amv.y = gmc_sanitize(avgMV.y, quarterpel, fcode);
461    
462                            pMBs[mbnum].mcsel = 0; /* until mode decision */
463            }
464    }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.1.2.2

No admin address has been configured
ViewVC Help
Powered by ViewVC 1.0.4