Home | History | Annotate | Download | only in libcopybit
      1 /*
      2  * Copyright (c) 2011-2014, 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, (unsigned int)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     size_t src_plane1_offset;
    132     size_t src_plane2_offset;
    133     size_t dst_plane1_offset;
    134     size_t 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 uintptr_t src_base,
    139                                       const uintptr_t dst_base,
    140                                       copyInfo& info)
    141 {
    142     if (!src_base || !dst_base) {
    143         ALOGE("%s: invalid memory src_base = 0x%p dst_base=0x%p",
    144              __FUNCTION__, (void*)src_base, (void*)dst_base);
    145          return COPYBIT_FAILURE;
    146     }
    147 
    148     int width = info.width;
    149     int height = info.height;
    150     unsigned char *src = (unsigned char*)src_base;
    151     unsigned char *dst = (unsigned char*)dst_base;
    152 
    153     // Copy the luma
    154     for (int i = 0; i < height; i++) {
    155         memcpy(dst, src, width);
    156         src += info.src_stride;
    157         dst += info.dst_stride;
    158     }
    159 
    160     // Copy plane 1
    161     src = (unsigned char*)(src_base + info.src_plane1_offset);
    162     dst = (unsigned char*)(dst_base + info.dst_plane1_offset);
    163     width = width/2;
    164     height = height/2;
    165     for (int i = 0; i < height; i++) {
    166         memcpy(dst, src, info.src_stride);
    167         src += info.src_stride;
    168         dst += info.dst_stride;
    169     }
    170     return 0;
    171 }
    172 
    173 
    174 /*
    175  * Function to convert the c2d format into an equivalent Android format
    176  *
    177  * @param: source buffer handle
    178  * @param: destination image
    179  *
    180  * @return: return status
    181  */
    182 int convert_yuv_c2d_to_yuv_android(private_handle_t *hnd,
    183                                    struct copybit_image_t const *rhs)
    184 {
    185     ALOGD("Enter %s", __FUNCTION__);
    186     if (!hnd || !rhs) {
    187         ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs);
    188         return COPYBIT_FAILURE;
    189     }
    190 
    191     int ret = COPYBIT_SUCCESS;
    192     private_handle_t *dst_hnd = (private_handle_t *)rhs->handle;
    193 
    194     copyInfo info;
    195     info.width = rhs->w;
    196     info.height = rhs->h;
    197     info.src_stride = ALIGN(info.width, 32);
    198     info.dst_stride = ALIGN(info.width, 16);
    199     switch(rhs->format) {
    200         case HAL_PIXEL_FORMAT_YCbCr_420_SP:
    201         case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
    202             info.src_plane1_offset = info.src_stride*info.height;
    203             info.dst_plane1_offset = info.dst_stride*info.height;
    204         } break;
    205         case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: {
    206             // Chroma is 2K aligned for the NV12 encodeable format.
    207             info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048);
    208             info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048);
    209         } break;
    210         default:
    211             ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__,
    212                  rhs->format);
    213             return COPYBIT_FAILURE;
    214     }
    215 
    216     ret = copy_source_to_destination(hnd->base, dst_hnd->base, info);
    217     return ret;
    218 }
    219 
    220 /*
    221  * Function to convert the Android format into an equivalent C2D format
    222  *
    223  * @param: source buffer handle
    224  * @param: destination image
    225  *
    226  * @return: return status
    227  */
    228 int convert_yuv_android_to_yuv_c2d(private_handle_t *hnd,
    229                                    struct copybit_image_t const *rhs)
    230 {
    231     if (!hnd || !rhs) {
    232         ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs);
    233         return COPYBIT_FAILURE;
    234     }
    235 
    236     int ret = COPYBIT_SUCCESS;
    237     private_handle_t *dst_hnd = (private_handle_t *)rhs->handle;
    238 
    239     copyInfo info;
    240     info.width = rhs->w;
    241     info.height = rhs->h;
    242     info.src_stride = ALIGN(hnd->width, 16);
    243     info.dst_stride = ALIGN(info.width, 32);
    244     switch(rhs->format) {
    245         case HAL_PIXEL_FORMAT_YCbCr_420_SP:
    246         case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
    247             info.src_plane1_offset = info.src_stride*info.height;
    248             info.dst_plane1_offset = info.dst_stride*info.height;
    249         } break;
    250         case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: {
    251             // Chroma is 2K aligned for the NV12 encodeable format.
    252             info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048);
    253             info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048);
    254         } break;
    255         default:
    256             ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__,
    257                  rhs->format);
    258             return -1;
    259     }
    260 
    261     ret = copy_source_to_destination(hnd->base, dst_hnd->base, info);
    262     return ret;
    263 }
    264