Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      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 express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 /**
     17  ******************************************************************************
     18  * @file     M4VIFI_ResizeYUV420toRGB565RotatedRight.c
     19  * @brief    Contain video library function
     20  * @note     This file has a Combo filter function
     21  *           -# Resizes YUV420 and converts to RGR565 with rotation
     22  * @date
     23  *           - 2004/08/11: Creation
     24  ******************************************************************************
     25 */
     26 
     27 /* Prototypes of functions, and type definitions */
     28 #include    "M4VIFI_FiltersAPI.h"
     29 /* Macro definitions */
     30 #include    "M4VIFI_Defines.h"
     31 /* Clip table declaration */
     32 #include    "M4VIFI_Clip.h"
     33 
     34 /**
     35  ********************************************************************************************
     36  * M4VIFI_UInt8 M4VIFI_ResizeBilinearYUV420toRGB565RotatedRight(void *pContext,
     37  *                                                              M4VIFI_ImagePlane *pPlaneIn,
     38  *                                                              M4VIFI_ImagePlane *pPlaneOut)
     39  * @brief   Resize YUV420 plane and converts to RGB565 with +90 rotation.
     40  * @note    Basic sturture of the function
     41  *          Loop on each row (step 2)
     42  *              Loop on each column (step 2)
     43  *                  Get four Y samples and 1 u & V sample
     44  *                  Resize the Y with corresponing U and V samples
     45  *                  Compute the four corresponding R G B values
     46  *                  Place the R G B in the ouput plane in rotated fashion
     47  *              end loop column
     48  *          end loop row
     49  *          For resizing bilinear interpolation linearly interpolates along
     50  *          each row, and then uses that result in a linear interpolation down each column.
     51  *          Each estimated pixel in the output image is a weighted
     52  *          combination of its four neighbours. The ratio of compression
     53  *          or dilatation is estimated using input and output sizes.
     54  * @param   pPlaneIn: (IN) Pointer to YUV plane buffer
     55  * @param   pContext: (IN) Context Pointer
     56  * @param   pPlaneOut: (OUT) Pointer to BGR565 Plane
     57  * @return  M4VIFI_OK: there is no error
     58  * @return  M4VIFI_ILLEGAL_FRAME_HEIGHT: YUV Plane height is ODD
     59  * @return  M4VIFI_ILLEGAL_FRAME_WIDTH:  YUV Plane width is ODD
     60  ********************************************************************************************
     61 */
     62 M4VIFI_UInt8    M4VIFI_ResizeBilinearYUV420toRGB565(void* pContext,
     63                                                     M4VIFI_ImagePlane *pPlaneIn,
     64                                                     M4VIFI_ImagePlane *pPlaneOut)
     65 {
     66     M4VIFI_UInt8    *pu8_data_in[PLANES], *pu8_data_in1[PLANES],*pu8_data_out;
     67     M4VIFI_UInt32   *pu32_rgb_data_current, *pu32_rgb_data_next, *pu32_rgb_data_start;
     68 
     69     M4VIFI_UInt32   u32_width_in[PLANES], u32_width_out, u32_height_in[PLANES], u32_height_out;
     70     M4VIFI_UInt32   u32_stride_in[PLANES];
     71     M4VIFI_UInt32   u32_stride_out, u32_stride2_out, u32_width2_RGB, u32_height2_RGB;
     72     M4VIFI_UInt32   u32_x_inc[PLANES], u32_y_inc[PLANES];
     73     M4VIFI_UInt32   u32_x_accum_Y, u32_x_accum_U, u32_x_accum_start;
     74     M4VIFI_UInt32   u32_y_accum_Y, u32_y_accum_U;
     75     M4VIFI_UInt32   u32_x_frac_Y, u32_x_frac_U, u32_y_frac_Y,u32_y_frac_U;
     76     M4VIFI_Int32    U_32, V_32, Y_32, Yval_32;
     77     M4VIFI_UInt8    u8_Red, u8_Green, u8_Blue;
     78     M4VIFI_UInt32   u32_row, u32_col;
     79 
     80     M4VIFI_UInt32   u32_plane;
     81     M4VIFI_UInt32   u32_rgb_temp1, u32_rgb_temp2;
     82     M4VIFI_UInt32   u32_rgb_temp3,u32_rgb_temp4;
     83     M4VIFI_UInt32   u32_check_size;
     84 
     85     M4VIFI_UInt8    *pu8_src_top_Y,*pu8_src_top_U,*pu8_src_top_V ;
     86     M4VIFI_UInt8    *pu8_src_bottom_Y, *pu8_src_bottom_U, *pu8_src_bottom_V;
     87 
     88     /* Check for the  width and height are even */
     89     u32_check_size = IS_EVEN(pPlaneIn[0].u_height);
     90     if( u32_check_size == FALSE )
     91     {
     92         return M4VIFI_ILLEGAL_FRAME_HEIGHT;
     93     }
     94     u32_check_size = IS_EVEN(pPlaneIn[0].u_width);
     95     if (u32_check_size == FALSE )
     96     {
     97         return M4VIFI_ILLEGAL_FRAME_WIDTH;
     98 
     99     }
    100     /* Make the ouput width and height as even */
    101     pPlaneOut->u_height = pPlaneOut->u_height & 0xFFFFFFFE;
    102     pPlaneOut->u_width = pPlaneOut->u_width & 0xFFFFFFFE;
    103     pPlaneOut->u_stride = pPlaneOut->u_stride & 0xFFFFFFFC;
    104 
    105     /* Assignment of output pointer */
    106     pu8_data_out    = pPlaneOut->pac_data + pPlaneOut->u_topleft;
    107     /* Assignment of output width(rotated) */
    108     u32_width_out   = pPlaneOut->u_width;
    109     /* Assignment of output height(rotated) */
    110     u32_height_out  = pPlaneOut->u_height;
    111 
    112     /* Set the bounds of the active image */
    113     u32_width2_RGB  = pPlaneOut->u_width >> 1;
    114     u32_height2_RGB = pPlaneOut->u_height >> 1;
    115     /* Get the memory jump corresponding to a row jump */
    116     u32_stride_out = pPlaneOut->u_stride >> 1;
    117     u32_stride2_out = pPlaneOut->u_stride >> 2;
    118 
    119     for(u32_plane = 0; u32_plane < PLANES; u32_plane++)
    120     {
    121         /* Set the working pointers at the beginning of the input/output data field */
    122         pu8_data_in[u32_plane] = pPlaneIn[u32_plane].pac_data + pPlaneIn[u32_plane].u_topleft;
    123 
    124         /* Get the memory jump corresponding to a row jump */
    125         u32_stride_in[u32_plane] = pPlaneIn[u32_plane].u_stride;
    126 
    127         /* Set the bounds of the active image */
    128         u32_width_in[u32_plane] = pPlaneIn[u32_plane].u_width;
    129         u32_height_in[u32_plane] = pPlaneIn[u32_plane].u_height;
    130     }
    131     /* Compute horizontal ratio between src and destination width for Y Plane.*/
    132     if (u32_width_out >= u32_width_in[YPlane])
    133     {
    134         u32_x_inc[YPlane]   = ((u32_width_in[YPlane]-1) * MAX_SHORT) / (u32_width_out-1);
    135     }
    136     else
    137     {
    138         u32_x_inc[YPlane]   = (u32_width_in[YPlane] * MAX_SHORT) / (u32_width_out);
    139     }
    140 
    141     /* Compute vertical ratio between src and destination height for Y Plane.*/
    142     if (u32_height_out >= u32_height_in[YPlane])
    143     {
    144         u32_y_inc[YPlane]   = ((u32_height_in[YPlane]-1) * MAX_SHORT) / (u32_height_out-1);
    145     }
    146     else
    147     {
    148         u32_y_inc[YPlane] = (u32_height_in[YPlane] * MAX_SHORT) / (u32_height_out);
    149     }
    150 
    151     /* Compute horizontal ratio between src and destination width for U and V Planes.*/
    152     if (u32_width2_RGB >= u32_width_in[UPlane])
    153     {
    154         u32_x_inc[UPlane]   = ((u32_width_in[UPlane]-1) * MAX_SHORT) / (u32_width2_RGB-1);
    155     }
    156     else
    157     {
    158         u32_x_inc[UPlane]   = (u32_width_in[UPlane] * MAX_SHORT) / (u32_width2_RGB);
    159     }
    160 
    161     /* Compute vertical ratio between src and destination height for U and V Planes.*/
    162 
    163     if (u32_height2_RGB >= u32_height_in[UPlane])
    164     {
    165         u32_y_inc[UPlane]   = ((u32_height_in[UPlane]-1) * MAX_SHORT) / (u32_height2_RGB-1);
    166     }
    167     else
    168     {
    169         u32_y_inc[UPlane]  = (u32_height_in[UPlane] * MAX_SHORT) / (u32_height2_RGB);
    170     }
    171 
    172     u32_y_inc[VPlane] = u32_y_inc[UPlane];
    173     u32_x_inc[VPlane] = u32_x_inc[UPlane];
    174 
    175     /*
    176     Calculate initial accumulator value : u32_y_accum_start.
    177     u32_y_accum_start is coded on 15 bits, and represents a value between 0 and 0.5
    178     */
    179     if (u32_y_inc[YPlane] > MAX_SHORT)
    180     {
    181         /*
    182         Keep the fractionnal part, assimung that integer  part is coded on the 16 high bits,
    183         and the fractionnal on the 15 low bits
    184         */
    185         u32_y_accum_Y = u32_y_inc[YPlane] & 0xffff;
    186         u32_y_accum_U = u32_y_inc[UPlane] & 0xffff;
    187 
    188         if (!u32_y_accum_Y)
    189         {
    190             u32_y_accum_Y = MAX_SHORT;
    191             u32_y_accum_U = MAX_SHORT;
    192         }
    193         u32_y_accum_Y >>= 1;
    194         u32_y_accum_U >>= 1;
    195     }
    196     else
    197     {
    198         u32_y_accum_Y = 0;
    199         u32_y_accum_U = 0;
    200 
    201     }
    202 
    203     /*
    204     Calculate initial accumulator value : u32_x_accum_start.
    205     u32_x_accum_start is coded on 15 bits, and represents a value between 0 and 0.5
    206     */
    207     if (u32_x_inc[YPlane] > MAX_SHORT)
    208     {
    209         u32_x_accum_start = u32_x_inc[YPlane] & 0xffff;
    210 
    211         if (!u32_x_accum_start)
    212         {
    213             u32_x_accum_start = MAX_SHORT;
    214         }
    215 
    216         u32_x_accum_start >>= 1;
    217     }
    218     else
    219     {
    220         u32_x_accum_start = 0;
    221     }
    222     /* Intialise the RGB pointer */
    223     pu32_rgb_data_start = (M4VIFI_UInt32*)pu8_data_out;
    224 
    225     /*
    226         Bilinear interpolation linearly interpolates along each row, and then uses that
    227         result in a linear interpolation donw each column. Each estimated pixel in the
    228         output image is a weighted combination of its four neighbours according to the formula :
    229         F(p',q')=f(p,q)R(-a)R(b)+f(p,q-1)R(-a)R(b-1)+f(p+1,q)R(1-a)R(b)+f(p+&,q+1)R(1-a)R(b-1)
    230         with  R(x) = / x+1  -1 =< x =< 0 \ 1-x  0 =< x =< 1 and a (resp. b) weighting coefficient
    231         is the distance from the nearest neighbor in the p (resp. q) direction
    232     */
    233     for (u32_row = u32_height_out; u32_row != 0; u32_row -= 2)
    234     {
    235         u32_x_accum_Y = u32_x_accum_start;
    236         u32_x_accum_U = u32_x_accum_start;
    237 
    238         /* Vertical weight factor */
    239         u32_y_frac_Y = (u32_y_accum_Y >> 12) & 15;
    240         u32_y_frac_U = (u32_y_accum_U >> 12) & 15;
    241 
    242         /* RGB current line Position Pointer */
    243         pu32_rgb_data_current = pu32_rgb_data_start ;
    244 
    245         /* RGB next line position pointer */
    246         pu32_rgb_data_next    = pu32_rgb_data_current + (u32_stride2_out);
    247 
    248         /* Y Plane next row pointer */
    249         pu8_data_in1[YPlane] = pu8_data_in[YPlane];
    250 
    251         u32_rgb_temp3 = u32_y_accum_Y + (u32_y_inc[YPlane]);
    252         if (u32_rgb_temp3 >> 16)
    253         {
    254             pu8_data_in1[YPlane] =  pu8_data_in[YPlane] +
    255                                                 (u32_rgb_temp3 >> 16) * (u32_stride_in[YPlane]);
    256             u32_rgb_temp3 &= 0xffff;
    257         }
    258         u32_rgb_temp4 = (u32_rgb_temp3 >> 12) & 15;
    259 
    260         for (u32_col = u32_width_out; u32_col != 0; u32_col -= 2)
    261         {
    262 
    263             /* Input Y plane elements */
    264             pu8_src_top_Y = pu8_data_in[YPlane] + (u32_x_accum_Y >> 16);
    265             pu8_src_bottom_Y = pu8_src_top_Y + u32_stride_in[YPlane];
    266 
    267             /* Input U Plane elements */
    268             pu8_src_top_U = pu8_data_in[UPlane] + (u32_x_accum_U >> 16);
    269             pu8_src_bottom_U = pu8_src_top_U + u32_stride_in[UPlane];
    270 
    271             pu8_src_top_V = pu8_data_in[VPlane] + (u32_x_accum_U >> 16);
    272             pu8_src_bottom_V = pu8_src_top_V + u32_stride_in[VPlane];
    273 
    274             /* Horizontal weight factor for Y Plane */
    275             u32_x_frac_Y = (u32_x_accum_Y >> 12)&15;
    276             /* Horizontal weight factor for U and V Planes */
    277             u32_x_frac_U = (u32_x_accum_U >> 12)&15;
    278 
    279             /* Weighted combination */
    280             U_32 = (((pu8_src_top_U[0]*(16-u32_x_frac_U) + pu8_src_top_U[1]*u32_x_frac_U)
    281                     *(16-u32_y_frac_U) + (pu8_src_bottom_U[0]*(16-u32_x_frac_U)
    282                     + pu8_src_bottom_U[1]*u32_x_frac_U)*u32_y_frac_U ) >> 8);
    283 
    284             V_32 = (((pu8_src_top_V[0]*(16-u32_x_frac_U) + pu8_src_top_V[1]*u32_x_frac_U)
    285                     *(16-u32_y_frac_U) + (pu8_src_bottom_V[0]*(16-u32_x_frac_U)
    286                     + pu8_src_bottom_V[1]*u32_x_frac_U)*u32_y_frac_U ) >> 8);
    287 
    288             Y_32 = (((pu8_src_top_Y[0]*(16-u32_x_frac_Y) + pu8_src_top_Y[1]*u32_x_frac_Y)
    289                     *(16-u32_y_frac_Y) + (pu8_src_bottom_Y[0]*(16-u32_x_frac_Y)
    290                     + pu8_src_bottom_Y[1]*u32_x_frac_Y)*u32_y_frac_Y ) >> 8);
    291 
    292             u32_x_accum_U += (u32_x_inc[UPlane]);
    293 
    294             /* YUV to RGB */
    295             #ifdef __RGB_V1__
    296                     Yval_32 = Y_32*37;
    297             #else   /* __RGB_V1__v */
    298                     Yval_32 = Y_32*0x2568;
    299             #endif /* __RGB_V1__v */
    300 
    301                     DEMATRIX(u8_Red,u8_Green,u8_Blue,Yval_32,U_32,V_32);
    302 
    303             /* Pack 8 bit R,G,B to RGB565 */
    304             #ifdef  LITTLE_ENDIAN
    305                     u32_rgb_temp1 = PACK_RGB565(0,u8_Red,u8_Green,u8_Blue);
    306             #else   /* LITTLE_ENDIAN */
    307                     u32_rgb_temp1 = PACK_RGB565(16,u8_Red,u8_Green,u8_Blue);
    308             #endif  /* LITTLE_ENDIAN */
    309 
    310 
    311             pu8_src_top_Y = pu8_data_in1[YPlane]+(u32_x_accum_Y >> 16);
    312             pu8_src_bottom_Y = pu8_src_top_Y + u32_stride_in[YPlane];
    313 
    314             /* Weighted combination */
    315             Y_32 = (((pu8_src_top_Y[0]*(16-u32_x_frac_Y) + pu8_src_top_Y[1]*u32_x_frac_Y)
    316                     *(16-u32_rgb_temp4) + (pu8_src_bottom_Y[0]*(16-u32_x_frac_Y)
    317                     + pu8_src_bottom_Y[1]*u32_x_frac_Y)*u32_rgb_temp4 ) >> 8);
    318 
    319             u32_x_accum_Y += u32_x_inc[YPlane];
    320             /* Horizontal weight factor */
    321             u32_x_frac_Y = (u32_x_accum_Y >> 12)&15;
    322             /* YUV to RGB */
    323             #ifdef __RGB_V1__
    324                     Yval_32 = Y_32*37;
    325             #else   /* __RGB_V1__v */
    326                     Yval_32 = Y_32*0x2568;
    327             #endif  /* __RGB_V1__v */
    328 
    329             DEMATRIX(u8_Red,u8_Green,u8_Blue,Yval_32,U_32,V_32);
    330 
    331             /* Pack 8 bit R,G,B to RGB565 */
    332             #ifdef  LITTLE_ENDIAN
    333                     u32_rgb_temp2 = PACK_RGB565(0,u8_Red,u8_Green,u8_Blue);
    334             #else   /* LITTLE_ENDIAN */
    335                     u32_rgb_temp2 = PACK_RGB565(16,u8_Red,u8_Green,u8_Blue);
    336             #endif  /* LITTLE_ENDIAN */
    337 
    338 
    339             pu8_src_top_Y = pu8_data_in[YPlane] + (u32_x_accum_Y >> 16) ;
    340             pu8_src_bottom_Y = pu8_src_top_Y + u32_stride_in[YPlane];
    341 
    342             /* Weighted combination */
    343             Y_32 = (((pu8_src_top_Y[0]*(16-u32_x_frac_Y) + pu8_src_top_Y[1]*u32_x_frac_Y)
    344                     *(16-u32_y_frac_Y) + (pu8_src_bottom_Y[0]*(16-u32_x_frac_Y)
    345                     + pu8_src_bottom_Y[1]*u32_x_frac_Y)*u32_y_frac_Y ) >> 8);
    346             /* YUV to RGB */
    347             #ifdef __RGB_V1__
    348                     Yval_32 = Y_32*37;
    349             #else   /* __RGB_V1__v */
    350                     Yval_32 = Y_32*0x2568;
    351             #endif  /* __RGB_V1__v */
    352 
    353             DEMATRIX(u8_Red,u8_Green,u8_Blue,Yval_32,U_32,V_32);
    354 
    355             /* Pack 8 bit R,G,B to RGB565 */
    356             #ifdef  LITTLE_ENDIAN
    357                     *(pu32_rgb_data_current)++ = u32_rgb_temp1 |
    358                                                         PACK_RGB565(16,u8_Red,u8_Green,u8_Blue);
    359             #else   /* LITTLE_ENDIAN */
    360                     *(pu32_rgb_data_current)++ = u32_rgb_temp1 |
    361                                                         PACK_RGB565(0,u8_Red,u8_Green,u8_Blue);
    362             #endif  /* LITTLE_ENDIAN */
    363 
    364 
    365             pu8_src_top_Y = pu8_data_in1[YPlane]+ (u32_x_accum_Y >> 16);
    366             pu8_src_bottom_Y = pu8_src_top_Y + u32_stride_in[YPlane];
    367 
    368             /* Weighted combination */
    369             Y_32 = (((pu8_src_top_Y[0]*(16-u32_x_frac_Y) + pu8_src_top_Y[1]*u32_x_frac_Y)
    370                     *(16-u32_rgb_temp4) + (pu8_src_bottom_Y[0]*(16-u32_x_frac_Y)
    371                     + pu8_src_bottom_Y[1]*u32_x_frac_Y)*u32_rgb_temp4 )>>8);
    372 
    373             u32_x_accum_Y += u32_x_inc[YPlane];
    374             /* YUV to RGB */
    375             #ifdef __RGB_V1__
    376                     Yval_32=Y_32*37;
    377             #else   /* __RGB_V1__v */
    378                     Yval_32=Y_32*0x2568;
    379             #endif  /* __RGB_V1__v */
    380 
    381             DEMATRIX(u8_Red,u8_Green,u8_Blue,Yval_32,U_32,V_32);
    382 
    383             /* Pack 8 bit R,G,B to RGB565 */
    384             #ifdef  LITTLE_ENDIAN
    385                     *(pu32_rgb_data_next)++ = u32_rgb_temp2 |
    386                                                         PACK_RGB565(16,u8_Red,u8_Green,u8_Blue);
    387             #else   /* LITTLE_ENDIAN */
    388                     *(pu32_rgb_data_next)++ = u32_rgb_temp2 |
    389                                                         PACK_RGB565(0,u8_Red,u8_Green,u8_Blue);
    390             #endif  /* LITTLE_ENDIAN */
    391 
    392         }   /* End of horizontal scanning */
    393 
    394         u32_y_accum_Y  =  u32_rgb_temp3 + (u32_y_inc[YPlane]);
    395         u32_y_accum_U += (u32_y_inc[UPlane]);
    396 
    397         /* Y plane row update */
    398         if (u32_y_accum_Y >> 16)
    399         {
    400             pu8_data_in[YPlane] =  pu8_data_in1[YPlane] +
    401                                                 ((u32_y_accum_Y >> 16) * (u32_stride_in[YPlane]));
    402             u32_y_accum_Y &= 0xffff;
    403         }
    404         else
    405         {
    406             pu8_data_in[YPlane] = pu8_data_in1[YPlane];
    407         }
    408         /* U and V planes row update */
    409         if (u32_y_accum_U >> 16)
    410         {
    411             pu8_data_in[UPlane] =  pu8_data_in[UPlane] +
    412                                                 (u32_y_accum_U >> 16) * (u32_stride_in[UPlane]);
    413             pu8_data_in[VPlane] =  pu8_data_in[VPlane] +
    414                                                 (u32_y_accum_U >> 16) * (u32_stride_in[VPlane]);
    415             u32_y_accum_U &= 0xffff;
    416         }
    417 
    418         pu32_rgb_data_start += u32_stride_out;
    419 
    420     }   /* End of vertical scanning */
    421     return M4VIFI_OK;
    422 }
    423 
    424