Home | History | Annotate | Download | only in libcopybit
      1 /*
      2  * Copyright (c) 2011, The Linux Foundation. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *     * Redistributions of source code must retain the above copyright
      8  *       notice, this list of conditions and the following disclaimer.
      9  *     * Redistributions in binary form must reproduce the above
     10  *       copyright notice, this list of conditions and the following
     11  *       disclaimer in the documentation and/or other materials provided
     12  *       with the distribution.
     13  *     * Neither the name of The Linux Foundation nor the names of its
     14  *       contributors may be used to endorse or promote products derived
     15  *       from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include <cutils/log.h>
     31 #include <stdlib.h>
     32 #include <errno.h>
     33 #include "software_converter.h"
     34 
     35 /** Convert YV12 to YCrCb_420_SP */
     36 int convertYV12toYCrCb420SP(const copybit_image_t *src, private_handle_t *yv12_handle)
     37 {
     38     private_handle_t* hnd = (private_handle_t*)src->handle;
     39 
     40     if(hnd == NULL || yv12_handle == NULL){
     41         ALOGE("Invalid handle");
     42         return -1;
     43     }
     44 
     45     // Please refer to the description of YV12 in hardware.h
     46     // for the formulae used to calculate buffer sizes and offsets
     47 
     48     // In a copybit_image_t, w is the stride and
     49     // stride - horiz_padding is the actual width
     50     // vertical stride is the same as height, so not considered
     51     unsigned int   stride  = src->w;
     52     unsigned int   width   = src->w - src->horiz_padding;
     53     unsigned int   height  = src->h;
     54     unsigned int   y_size  = stride * src->h;
     55     unsigned int   c_width = ALIGN(stride/2, 16);
     56     unsigned int   c_size  = c_width * src->h/2;
     57     unsigned int   chromaPadding = c_width - width/2;
     58     unsigned int   chromaSize = c_size * 2;
     59     unsigned char* newChroma = (unsigned char *)(yv12_handle->base + y_size);
     60     unsigned char* oldChroma = (unsigned char*)(hnd->base + y_size);
     61     memcpy((char *)yv12_handle->base,(char *)hnd->base,y_size);
     62 
     63 #ifdef __ARM_HAVE_NEON
     64    /* interleave */
     65     if(!chromaPadding) {
     66         unsigned char * t1 = newChroma;
     67         unsigned char * t2 = oldChroma;
     68         unsigned char * t3 = t2 + chromaSize/2;
     69         for(unsigned int i=0; i < (chromaSize/2)>>3; i++) {
     70             __asm__ __volatile__ (
     71                                     "vld1.u8 d0, [%0]! \n"
     72                                     "vld1.u8 d1, [%1]! \n"
     73                                     "vst2.u8 {d0, d1}, [%2]! \n"
     74                                     :"+r"(t2), "+r"(t3), "+r"(t1)
     75                                     :
     76                                     :"memory","d0","d1"
     77                                  );
     78 
     79         }
     80     }
     81 #else  //__ARM_HAVE_NEON
     82     if(!chromaPadding) {
     83         for(unsigned int i = 0; i< chromaSize/2; i++) {
     84             newChroma[i*2]   = oldChroma[i];
     85             newChroma[i*2+1] = oldChroma[i+chromaSize/2];
     86         }
     87 
     88     }
     89 #endif
     90     // If the image is not aligned to 16 pixels,
     91     // convert using the C routine below
     92     // r1 tracks the row of the source buffer
     93     // r2 tracks the row of the destination buffer
     94     // The width/2 checks are to avoid copying
     95     // from the padding
     96 
     97     if(chromaPadding) {
     98         unsigned int r1 = 0, r2 = 0, i = 0, j = 0;
     99         while(r1 < height/2) {
    100             if(j == width) {
    101                 j = 0;
    102                 r2++;
    103                 continue;
    104             }
    105             if (j+1 == width) {
    106                 newChroma[r2*width + j] = oldChroma[r1*c_width+i];
    107                 r2++;
    108                 newChroma[r2*width] = oldChroma[r1*c_width+i+c_size];
    109                 j = 1;
    110             } else {
    111                 newChroma[r2*width + j] = oldChroma[r1*c_width+i];
    112                 newChroma[r2*width + j + 1] = oldChroma[r1*c_width+i+c_size];
    113                 j+=2;
    114             }
    115             i++;
    116             if (i == width/2 ) {
    117                 i = 0;
    118                 r1++;
    119             }
    120         }
    121     }
    122 
    123   return 0;
    124 }
    125 
    126 struct copyInfo{
    127     int width;
    128     int height;
    129     int src_stride;
    130     int dst_stride;
    131     int src_plane1_offset;
    132     int src_plane2_offset;
    133     int dst_plane1_offset;
    134     int dst_plane2_offset;
    135 };
    136 
    137 /* Internal function to do the actual copy of source to destination */
    138 static int copy_source_to_destination(const int src_base, const int dst_base,
    139                                       copyInfo& info)
    140 {
    141     if (!src_base || !dst_base) {
    142         ALOGE("%s: invalid memory src_base = 0x%x dst_base=0x%x",
    143              __FUNCTION__, src_base, dst_base);
    144          return COPYBIT_FAILURE;
    145     }
    146 
    147     int width = info.width;
    148     int height = info.height;
    149     unsigned char *src = (unsigned char*)src_base;
    150     unsigned char *dst = (unsigned char*)dst_base;
    151 
    152     // Copy the luma
    153     for (int i = 0; i < height; i++) {
    154         memcpy(dst, src, width);
    155         src += info.src_stride;
    156         dst += info.dst_stride;
    157     }
    158 
    159     // Copy plane 1
    160     src = (unsigned char*)(src_base + info.src_plane1_offset);
    161     dst = (unsigned char*)(dst_base + info.dst_plane1_offset);
    162     width = width/2;
    163     height = height/2;
    164     for (int i = 0; i < height; i++) {
    165         memcpy(dst, src, info.src_stride);
    166         src += info.src_stride;
    167         dst += info.dst_stride;
    168     }
    169     return 0;
    170 }
    171 
    172 
    173 /*
    174  * Function to convert the c2d format into an equivalent Android format
    175  *
    176  * @param: source buffer handle
    177  * @param: destination image
    178  *
    179  * @return: return status
    180  */
    181 int convert_yuv_c2d_to_yuv_android(private_handle_t *hnd,
    182                                    struct copybit_image_t const *rhs)
    183 {
    184     ALOGD("Enter %s", __FUNCTION__);
    185     if (!hnd || !rhs) {
    186         ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs);
    187         return COPYBIT_FAILURE;
    188     }
    189 
    190     int ret = COPYBIT_SUCCESS;
    191     private_handle_t *dst_hnd = (private_handle_t *)rhs->handle;
    192 
    193     copyInfo info;
    194     info.width = rhs->w;
    195     info.height = rhs->h;
    196     info.src_stride = ALIGN(info.width, 32);
    197     info.dst_stride = ALIGN(info.width, 16);
    198     switch(rhs->format) {
    199         case HAL_PIXEL_FORMAT_YCbCr_420_SP:
    200         case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
    201             info.src_plane1_offset = info.src_stride*info.height;
    202             info.dst_plane1_offset = info.dst_stride*info.height;
    203         } break;
    204         case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: {
    205             // Chroma is 2K aligned for the NV12 encodeable format.
    206             info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048);
    207             info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048);
    208         } break;
    209         default:
    210             ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__,
    211                  rhs->format);
    212             return COPYBIT_FAILURE;
    213     }
    214 
    215     ret = copy_source_to_destination(hnd->base, dst_hnd->base, info);
    216     return ret;
    217 }
    218 
    219 /*
    220  * Function to convert the Android format into an equivalent C2D format
    221  *
    222  * @param: source buffer handle
    223  * @param: destination image
    224  *
    225  * @return: return status
    226  */
    227 int convert_yuv_android_to_yuv_c2d(private_handle_t *hnd,
    228                                    struct copybit_image_t const *rhs)
    229 {
    230     if (!hnd || !rhs) {
    231         ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs);
    232         return COPYBIT_FAILURE;
    233     }
    234 
    235     int ret = COPYBIT_SUCCESS;
    236     private_handle_t *dst_hnd = (private_handle_t *)rhs->handle;
    237 
    238     copyInfo info;
    239     info.width = rhs->w;
    240     info.height = rhs->h;
    241     info.src_stride = ALIGN(hnd->width, 16);
    242     info.dst_stride = ALIGN(info.width, 32);
    243     switch(rhs->format) {
    244         case HAL_PIXEL_FORMAT_YCbCr_420_SP:
    245         case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
    246             info.src_plane1_offset = info.src_stride*info.height;
    247             info.dst_plane1_offset = info.dst_stride*info.height;
    248         } break;
    249         case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: {
    250             // Chroma is 2K aligned for the NV12 encodeable format.
    251             info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048);
    252             info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048);
    253         } break;
    254         default:
    255             ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__,
    256                  rhs->format);
    257             return -1;
    258     }
    259 
    260     ret = copy_source_to_destination(hnd->base, dst_hnd->base, info);
    261     return ret;
    262 }
    263