1/* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18/*
19------------------------------------------------------------------------------
20 INPUT AND OUTPUT DEFINITIONS
21
22 Inputs:
23    xpos = x half-pixel of (x,y) coordinates within a VOP; motion
24           compensated coordinates; native data type
25    ypos = y half-pixel of (x,y) coordinates within a VOP; motion
26           compensated coordinates; native data type
27    comp = pointer to 8-bit compensated prediction values within a VOP;
28           computed by this module (i/o); full-pel resolution; 8-bit data
29    c_prev = pointer to previous 8-bit prediction values within a VOP;
30         values range from (0-255); full-pel resolution; 8-bit data
31    sh_d = pointer to residual values used to compensate the predicted
32           value; values range from (-512 to 511); full-pel resolution;
33           native data type
34    width = width of the VOP in pixels (x axis); full-pel resolution;
35        native data type
36    height = height of the VOP in pixels (y axis); full-pel resolution;
37         native data type
38    rnd1 = rounding value for case when one dimension uses half-pel
39           resolution; native data type
40    rnd2 = rounding value for case when two dimensions uses half-pel
41           resolution; native data type
42
43 Outputs:
44    returns 1
45
46 Local Stores/Buffers/Pointers Needed:
47    None
48
49 Global Stores/Buffers/Pointers Needed:
50    None
51
52 Pointers and Buffers Modified:
53    comp = buffer contains newly computed compensated prediction values
54
55 Local Stores Modified:
56    None
57
58 Global Stores Modified:
59    None
60
61------------------------------------------------------------------------------
62 FUNCTION DESCRIPTION
63
64 Summary:
65
66 This function performs motion compensated prediction for the case where
67 the motion vector points to a block outside the VOP. The function interpolates
68 the pixels that are outside the VOP using the boundary pixels for the block.
69 Once the values are interpolated, the pixel values are computed for a block
70 in the current VOP. The prediction values are generated by averaging pixel
71 values in the previous VOP; the block position in the previous frame is
72 computed from the current block's motion vector. The computed pixel values
73 are calculated by adding the prediction values to the block residual values.
74
75 Details:
76
77 First, this functions determines which VOP boundary(ies) the motion vector
78 is outside, i.e., left, right, top, bottom. xpos is compared to the left and
79 right boundaries; ypos is compared to the top and bottom boundaries. The number
80 of block pixels inside the the boundary in the x and y directions are stored
81 in endx and endy, respectively. If the entire block is inside the x or y
82 boundary, the respectively end is set to 0.
83
84 After the boundaries are tested, any pixels lying outside a boundary are
85 interpolated from the boundary pixels. For example, if the block is outside the
86 bottom boundary, boundary pixels alone the bottom of the VOP as used to
87 interpolated those pixels lying outside the bottom boundary. The interpolation
88 used is a simple column-wise or row-wise copy of the boundary pixels (inside the
89 block) depending on which boundary the block is outside. In our example, each
90 boundary pixel would be copied column-wise to the pixel beneath it. If the
91 block was outside right boundary, the boundary pixels would be copied row-wise
92 to the pixel to the right of it. If the block was outside both an x and y
93 boundary, the boundary pixels would be copied row-wise for the portion of the
94 block outside the x boundary, and column-wise for the portion of the block
95 outside the y boundary. And so on.
96
97 Once the pixel interpolation is complete, the motion compensated output values
98 (comp[]) are calculed from the motion compensated prediction (pred[])values and
99 the residual values (sh_d[]) of the current frame. The prediction values are
100 generated by averaging pixel values in the previous VOP; the block position in
101 the previous frame is computed from the current block's motion vector. The
102 computed pixel values are calculated by adding the prediction values to the
103 block residual values.
104
105*/
106
107/*----------------------------------------------------------------------------
108; INCLUDES
109----------------------------------------------------------------------------*/
110#include "mp4dec_lib.h"
111#include "motion_comp.h"
112
113#define PAD_CORNER {    temp = *prev; \
114            temp |= (temp<<8);  \
115            temp |= (temp<<16); \
116            *((uint32*)ptr) = temp; \
117            *((uint32*)(ptr+4)) = temp;  \
118            *((uint32*)(ptr+=16)) = temp;  \
119            *((uint32*)(ptr+4)) = temp;  \
120            *((uint32*)(ptr+=16)) = temp;  \
121            *((uint32*)(ptr+4)) = temp;  \
122            *((uint32*)(ptr+=16)) = temp;  \
123            *((uint32*)(ptr+4)) = temp;  \
124            *((uint32*)(ptr+=16)) = temp;  \
125            *((uint32*)(ptr+4)) = temp;  \
126            *((uint32*)(ptr+=16)) = temp;  \
127            *((uint32*)(ptr+4)) = temp;  \
128            *((uint32*)(ptr+=16)) = temp;  \
129            *((uint32*)(ptr+4)) = temp;  \
130            *((uint32*)(ptr+=16)) = temp;  \
131            *((uint32*)(ptr+4)) = temp;  }
132
133#define PAD_ROW  {  temp = *((uint32*)prev); \
134                    temp2 = *((uint32*)(prev+4)); \
135            *((uint32*)ptr) =  temp;\
136            *((uint32*)(ptr+4)) =  temp2; \
137            *((uint32*)(ptr+=16)) = temp; \
138            *((uint32*)(ptr+4)) = temp2;\
139            *((uint32*)(ptr+=16)) = temp; \
140            *((uint32*)(ptr+4)) = temp2;\
141            *((uint32*)(ptr+=16)) = temp; \
142            *((uint32*)(ptr+4)) = temp2;\
143            *((uint32*)(ptr+=16)) = temp; \
144            *((uint32*)(ptr+4)) = temp2;\
145            *((uint32*)(ptr+=16)) = temp; \
146            *((uint32*)(ptr+4)) = temp2;\
147            *((uint32*)(ptr+=16)) = temp; \
148            *((uint32*)(ptr+4)) = temp2;\
149            *((uint32*)(ptr+=16)) = temp; \
150            *((uint32*)(ptr+4)) = temp2;}
151
152#define PAD_EXTRA_4x8           {   temp = *((uint32*)(prev+8)); \
153                *((uint32*)ptr) =  temp; \
154                *((uint32*)(ptr+=16)) = temp; \
155                *((uint32*)(ptr+=16)) = temp; \
156                *((uint32*)(ptr+=16)) = temp; \
157                *((uint32*)(ptr+=16)) = temp; \
158                *((uint32*)(ptr+=16)) = temp; \
159                *((uint32*)(ptr+=16)) = temp; \
160                *((uint32*)(ptr+=16)) = temp; }
161
162#define PAD_COL { temp = *prev; \
163            temp|=(temp<<8);  temp|=(temp<<16); \
164            *((uint32*)ptr) = temp; \
165            *((uint32*)(ptr+4)) = temp; \
166            temp = *(prev+=16); \
167            temp|=(temp<<8);  temp|=(temp<<16); \
168            *((uint32*)(ptr+=16)) = temp; \
169            *((uint32*)(ptr+4)) = temp; \
170            temp = *(prev+=16); \
171            temp|=(temp<<8);  temp|=(temp<<16); \
172            *((uint32*)(ptr+=16)) = temp; \
173            *((uint32*)(ptr+4)) = temp; \
174            temp = *(prev+=16); \
175            temp|=(temp<<8);  temp|=(temp<<16); \
176            *((uint32*)(ptr+=16)) = temp; \
177            *((uint32*)(ptr+4)) = temp; \
178            temp = *(prev+=16); \
179            temp|=(temp<<8);  temp|=(temp<<16); \
180            *((uint32*)(ptr+=16)) = temp; \
181            *((uint32*)(ptr+4)) = temp; \
182            temp = *(prev+=16); \
183            temp|=(temp<<8);  temp|=(temp<<16); \
184            *((uint32*)(ptr+=16)) = temp; \
185            *((uint32*)(ptr+4)) = temp; \
186            temp = *(prev+=16); \
187            temp|=(temp<<8);  temp|=(temp<<16); \
188            *((uint32*)(ptr+=16)) = temp; \
189            *((uint32*)(ptr+4)) = temp; \
190            temp = *(prev+=16); \
191            temp|=(temp<<8);  temp|=(temp<<16); \
192            *((uint32*)(ptr+=16)) = temp; \
193            *((uint32*)(ptr+4)) = temp;}
194
195/* copy 8x8 block */
196#define COPY_BLOCK  {           *((uint32*)ptr) = *((uint32*)prev); \
197            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
198            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
199            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
200            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
201            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
202            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
203            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
204            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
205            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
206            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
207            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
208            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
209            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
210            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
211            *((uint32*)(ptr+4)) = *((uint32*)(prev+4));  }
212
213#define COPY_12x8       {       *((uint32*)ptr) = *((uint32*)prev); \
214            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
215            *((uint32*)(ptr+8)) = *((uint32*)(prev+8)); \
216            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
217            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
218            *((uint32*)(ptr+8)) = *((uint32*)(prev+8)); \
219            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
220            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
221            *((uint32*)(ptr+8)) = *((uint32*)(prev+8)); \
222            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
223            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
224            *((uint32*)(ptr+8)) = *((uint32*)(prev+8)); \
225            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
226            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
227            *((uint32*)(ptr+8)) = *((uint32*)(prev+8)); \
228            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
229            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
230            *((uint32*)(ptr+8)) = *((uint32*)(prev+8)); \
231            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
232            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
233            *((uint32*)(ptr+8)) = *((uint32*)(prev+8)); \
234            *((uint32*)(ptr+=16)) = *((uint32*)(prev+=width)); \
235            *((uint32*)(ptr+4)) = *((uint32*)(prev+4)); \
236            *((uint32*)(ptr+8)) = *((uint32*)(prev+8)); }
237
238/*----------------------------------------------------------------------------
239; FUNCTION CODE
240----------------------------------------------------------------------------*/
241int GetPredOutside(
242    int xpos,       /* i */
243    int ypos,       /* i */
244    uint8 *c_prev,      /* i */
245    uint8 *pred_block,      /* i */
246    int width,      /* i */
247    int height,     /* i */
248    int rnd1,       /* i */
249    int pred_width
250)
251{
252    /*----------------------------------------------------------------------------
253    ; Define all local variables
254    ----------------------------------------------------------------------------*/
255    uint8   *prev;      /* pointers to adjacent pixels in the    */
256    uint8   pred[256];  /* storage for padded pixel values, 16x16 */
257    uint8   *ptr;
258    int xoffset;
259    uint32 temp, temp2;
260
261    /*----------------------------------------------------------------------------
262    ; Function body here
263    ----------------------------------------------------------------------------*/
264    /* saturate xpos and ypos */
265    if (xpos < -16) xpos = -16;
266    if (xpos > ((width - 1) << 1)) xpos = (width - 1) << 1;
267    if (ypos < -16) ypos = -16;
268    if (ypos > ((height - 1) << 1)) ypos = (height - 1) << 1;
269
270    if (xpos < 0)
271    {
272        if (ypos < 0) /* pad top left of frame */
273        {
274            /* copy the block */
275            ptr = pred + (8 << 4) + 8;
276            prev = c_prev;
277            COPY_BLOCK
278
279            /* pad the corner */
280            ptr = pred;
281            prev = pred + (8 << 4) + 8;
282            PAD_CORNER
283
284            /* pad top */
285            ptr = pred + 8;
286            prev = pred + (8 << 4) + 8;
287            PAD_ROW
288
289            /* pad left */
290            ptr = pred + (8 << 4);
291            prev = pred + (8 << 4) + 8;
292            PAD_COL
293
294
295            ptr = pred + (((ypos >> 1) + 8) << 4) + (xpos >> 1) + 8;
296
297            GetPredAdvBTable[ypos&1][xpos&1](ptr, pred_block, 16, (pred_width << 1) | rnd1);
298
299            return 1;
300        }
301        else if ((ypos >> 1) < (height - B_SIZE)) /* pad left of frame */
302        {
303            /* copy block */
304            ptr = pred + 8;
305            prev = c_prev + (ypos >> 1) * width;
306            COPY_BLOCK
307            /* copy extra line */
308            *((uint32*)(ptr += 16)) = *((uint32*)(prev += width));
309            *((uint32*)(ptr + 4)) = *((uint32*)(prev + 4));
310
311            /* pad left */
312            ptr = pred;
313            prev = pred + 8;
314            PAD_COL
315            /* pad extra line */
316            temp = *(prev += 16);
317            temp |= (temp << 8);
318            temp |= (temp << 16);
319            *((uint32*)(ptr += 16)) = temp;
320            *((uint32*)(ptr + 4)) = temp;
321
322            ptr = pred + 8 + (xpos >> 1);
323
324            GetPredAdvBTable[ypos&1][xpos&1](ptr, pred_block, 16, (pred_width << 1) | rnd1);
325
326            return 1;
327        }
328        else /* pad bottom left of frame */
329        {
330            /* copy the block */
331            ptr = pred + 8; /* point to the center */
332            prev = c_prev + width * (height - 8);
333            COPY_BLOCK
334
335            /* pad the corner */
336            ptr = pred + (8 << 4);
337            prev = ptr - 8;
338            PAD_CORNER
339
340            /* pad bottom */
341            ptr = pred + (8 << 4) + 8;
342            prev = ptr - 16;
343            PAD_ROW
344
345            /* pad left */
346            ptr = pred ;
347            prev = ptr + 8;
348            PAD_COL
349
350            ptr = pred + 8 + (((ypos >> 1) - (height - 8)) << 4) + (xpos >> 1);
351
352            GetPredAdvBTable[ypos&1][xpos&1](ptr, pred_block, 16, (pred_width << 1) | rnd1);
353
354            return 1;
355        }
356    }
357    else if ((xpos >> 1) < (width - B_SIZE))
358    {
359        if (ypos < 0) /* pad top of frame */
360        {
361            xoffset = xpos >> 1;
362            xoffset = xoffset & 0x3; /* word align ptr */
363
364            /* copy block */
365            ptr = pred + (8 << 4);
366            prev = c_prev + (xpos >> 1) - xoffset;
367
368            if (xoffset || (xpos&1)) /* copy extra 4x8 */
369            {
370                COPY_12x8
371            }
372            else
373            {
374                COPY_BLOCK
375            }
376
377            /* pad top */
378            ptr = pred;
379            prev = pred + (8 << 4);
380            PAD_ROW
381            if (xoffset || (xpos&1)) /* pad extra 4x8 */
382            {
383                ptr = pred + 8;
384                PAD_EXTRA_4x8
385            }
386
387            ptr = pred + (((ypos >> 1) + 8) << 4) + xoffset;
388
389            GetPredAdvBTable[ypos&1][xpos&1](ptr, pred_block, 16, (pred_width << 1) | rnd1);
390
391            return 1;
392        }
393        else /* pad bottom of frame */
394        {
395            xoffset = xpos >> 1;
396            xoffset = xoffset & 0x3; /* word align ptr */
397            /* copy block */
398            ptr = pred ;
399            prev = c_prev + width * (height - 8) + (xpos >> 1) - xoffset;
400            if (xoffset  || (xpos&1))
401            {
402                COPY_12x8
403            }
404            else
405            {
406                COPY_BLOCK
407            }
408
409            /* pad bottom */
410            ptr = pred + (8 << 4);
411            prev = ptr - 16;
412            PAD_ROW
413            if (xoffset || (xpos&1))
414            {
415                ptr = pred + (8 << 4) + 8;
416                PAD_EXTRA_4x8
417            }
418
419            ptr = pred + (((ypos >> 1) - (height - 8)) << 4) + xoffset;
420
421            GetPredAdvBTable[ypos&1][xpos&1](ptr, pred_block, 16, (pred_width << 1) | rnd1);
422
423            return 1;
424        }
425    }
426    else
427    {
428        if (ypos < 0) /* pad top right of frame */
429        {
430            /* copy block */
431            ptr = pred + (8 << 4);
432            prev = c_prev + width - 8;
433            COPY_BLOCK
434
435            /* pad top-right */
436            ptr = pred + 8;
437            prev = pred + (8 << 4) + 7;
438            PAD_CORNER
439
440            /* pad top */
441            ptr = pred ;
442            prev = pred + (8 << 4);
443            PAD_ROW;
444
445            /* pad right */
446            ptr = pred + (8 << 4) + 8;
447            prev = ptr - 1;
448            PAD_COL;
449
450            ptr = pred + ((8 + (ypos >> 1)) << 4) + (8 - (width - (xpos >> 1)));
451
452            GetPredAdvBTable[ypos&1][xpos&1](ptr, pred_block, 16, (pred_width << 1) | rnd1);
453
454            return 1;
455        }
456        else if ((ypos >> 1) < (height - B_SIZE)) /* pad right of frame */
457        {
458            /* copy block */
459            ptr = pred;
460            prev = c_prev + (ypos >> 1) * width + width - 8;
461            COPY_BLOCK
462            /* copy extra line */
463            *((uint32*)(ptr += 16)) = *((uint32*)(prev += width));
464            *((uint32*)(ptr + 4)) = *((uint32*)(prev + 4));
465
466            /* pad right */
467            ptr = pred + 8;
468            prev = ptr - 1;
469            PAD_COL;
470            /* pad extra line */
471            temp = *(prev += 16);
472            temp |= (temp << 8);
473            temp |= (temp << 16);
474            *((uint32*)(ptr += 16)) = temp;
475            *((uint32*)(ptr + 4)) = temp;
476
477
478            ptr = pred + 8 - (width - (xpos >> 1));
479
480            GetPredAdvBTable[ypos&1][xpos&1](ptr, pred_block, 16, (pred_width << 1) | rnd1);
481
482            return 1;
483
484        }
485        else /* pad bottom right of frame */
486        {
487            /* copy block */
488            ptr = pred;
489            prev = c_prev + width * (height - 8) + width - 8;
490            COPY_BLOCK
491
492            /* pad bottom-right */
493            ptr = pred + (8 << 4) + 8;
494            prev = ptr - 17;
495            PAD_CORNER
496
497            /* pad right */
498            ptr = pred + 8;
499            prev = ptr - 1;
500            PAD_COL
501
502            /* pad bottom */
503            ptr = pred + (8 << 4);
504            prev = ptr - 16;
505            PAD_ROW
506
507            ptr = pred + 8 - (width - (xpos >> 1)) + ((8 - (height - (ypos >> 1))) << 4);
508
509            GetPredAdvBTable[ypos&1][xpos&1](ptr, pred_block, 16, (pred_width << 1) | rnd1);
510
511            return 1;
512        }
513    }
514}
515