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