|  | /* | 
|  | * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions are | 
|  | * met: | 
|  | *     * Redistributions of source code must retain the above copyright | 
|  | *       notice, this list of conditions and the following disclaimer. | 
|  | *     * Redistributions in binary form must reproduce the above | 
|  | *       copyright notice, this list of conditions and the following | 
|  | *       disclaimer in the documentation and/or other materials provided | 
|  | *       with the distribution. | 
|  | *     * Neither the name of The Linux Foundation nor the names of its | 
|  | *       contributors may be used to endorse or promote products derived | 
|  | *       from this software without specific prior written permission. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED | 
|  | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 
|  | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT | 
|  | * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS | 
|  | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 
|  | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 
|  | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | 
|  | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | 
|  | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | 
|  | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | 
|  | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | #include <log/log.h> | 
|  | #include <stdlib.h> | 
|  | #include <errno.h> | 
|  | #include "software_converter.h" | 
|  |  | 
|  | /** Convert YV12 to YCrCb_420_SP */ | 
|  | int convertYV12toYCrCb420SP(const copybit_image_t *src, private_handle_t *yv12_handle) | 
|  | { | 
|  | private_handle_t* hnd = (private_handle_t*)src->handle; | 
|  |  | 
|  | if(hnd == NULL || yv12_handle == NULL){ | 
|  | ALOGE("Invalid handle"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Please refer to the description of YV12 in hardware.h | 
|  | // for the formulae used to calculate buffer sizes and offsets | 
|  |  | 
|  | // In a copybit_image_t, w is the stride and | 
|  | // stride - horiz_padding is the actual width | 
|  | // vertical stride is the same as height, so not considered | 
|  | unsigned int   stride  = src->w; | 
|  | unsigned int   width   = src->w - src->horiz_padding; | 
|  | unsigned int   height  = src->h; | 
|  | unsigned int   y_size  = stride * src->h; | 
|  | unsigned int   c_width = ALIGN(stride/2, (unsigned int)16); | 
|  | unsigned int   c_size  = c_width * src->h/2; | 
|  | unsigned int   chromaPadding = c_width - width/2; | 
|  | unsigned int   chromaSize = c_size * 2; | 
|  | unsigned char* newChroma = (unsigned char *)(yv12_handle->base + y_size); | 
|  | unsigned char* oldChroma = (unsigned char*)(hnd->base + y_size); | 
|  | memcpy((char *)yv12_handle->base,(char *)hnd->base,y_size); | 
|  |  | 
|  | #if defined(__ARM_HAVE_NEON) && !defined(__aarch64__) | 
|  | /* interleave */ | 
|  | if(!chromaPadding) { | 
|  | unsigned char * t1 = newChroma; | 
|  | unsigned char * t2 = oldChroma; | 
|  | unsigned char * t3 = t2 + chromaSize/2; | 
|  | for(unsigned int i=0; i < (chromaSize/2)>>3; i++) { | 
|  | __asm__ __volatile__ ( | 
|  | "vld1.u8 d0, [%0]! \n" | 
|  | "vld1.u8 d1, [%1]! \n" | 
|  | "vst2.u8 {d0, d1}, [%2]! \n" | 
|  | :"+r"(t2), "+r"(t3), "+r"(t1) | 
|  | : | 
|  | :"memory","d0","d1" | 
|  | ); | 
|  |  | 
|  | } | 
|  | } | 
|  | #else  //__ARM_HAVE_NEON | 
|  | if(!chromaPadding) { | 
|  | for(unsigned int i = 0; i< chromaSize/2; i++) { | 
|  | newChroma[i*2]   = oldChroma[i]; | 
|  | newChroma[i*2+1] = oldChroma[i+chromaSize/2]; | 
|  | } | 
|  |  | 
|  | } | 
|  | #endif | 
|  | // If the image is not aligned to 16 pixels, | 
|  | // convert using the C routine below | 
|  | // r1 tracks the row of the source buffer | 
|  | // r2 tracks the row of the destination buffer | 
|  | // The width/2 checks are to avoid copying | 
|  | // from the padding | 
|  |  | 
|  | if(chromaPadding) { | 
|  | unsigned int r1 = 0, r2 = 0, i = 0, j = 0; | 
|  | while(r1 < height/2) { | 
|  | if(j == width) { | 
|  | j = 0; | 
|  | r2++; | 
|  | continue; | 
|  | } | 
|  | if (j+1 == width) { | 
|  | newChroma[r2*width + j] = oldChroma[r1*c_width+i]; | 
|  | r2++; | 
|  | newChroma[r2*width] = oldChroma[r1*c_width+i+c_size]; | 
|  | j = 1; | 
|  | } else { | 
|  | newChroma[r2*width + j] = oldChroma[r1*c_width+i]; | 
|  | newChroma[r2*width + j + 1] = oldChroma[r1*c_width+i+c_size]; | 
|  | j+=2; | 
|  | } | 
|  | i++; | 
|  | if (i == width/2 ) { | 
|  | i = 0; | 
|  | r1++; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | struct copyInfo{ | 
|  | int width; | 
|  | int height; | 
|  | int src_stride; | 
|  | int dst_stride; | 
|  | size_t src_plane1_offset; | 
|  | size_t src_plane2_offset; | 
|  | size_t dst_plane1_offset; | 
|  | size_t dst_plane2_offset; | 
|  | }; | 
|  |  | 
|  | /* Internal function to do the actual copy of source to destination */ | 
|  | static int copy_source_to_destination(const uintptr_t src_base, | 
|  | const uintptr_t dst_base, | 
|  | copyInfo& info) | 
|  | { | 
|  | if (!src_base || !dst_base) { | 
|  | ALOGE("%s: invalid memory src_base = 0x%p dst_base=0x%p", | 
|  | __FUNCTION__, (void*)src_base, (void*)dst_base); | 
|  | return COPYBIT_FAILURE; | 
|  | } | 
|  |  | 
|  | int width = info.width; | 
|  | int height = info.height; | 
|  | unsigned char *src = (unsigned char*)src_base; | 
|  | unsigned char *dst = (unsigned char*)dst_base; | 
|  |  | 
|  | // Copy the luma | 
|  | for (int i = 0; i < height; i++) { | 
|  | memcpy(dst, src, width); | 
|  | src += info.src_stride; | 
|  | dst += info.dst_stride; | 
|  | } | 
|  |  | 
|  | // Copy plane 1 | 
|  | src = (unsigned char*)(src_base + info.src_plane1_offset); | 
|  | dst = (unsigned char*)(dst_base + info.dst_plane1_offset); | 
|  | width = width/2; | 
|  | height = height/2; | 
|  | for (int i = 0; i < height; i++) { | 
|  | memcpy(dst, src, info.src_stride); | 
|  | src += info.src_stride; | 
|  | dst += info.dst_stride; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Function to convert the c2d format into an equivalent Android format | 
|  | * | 
|  | * @param: source buffer handle | 
|  | * @param: destination image | 
|  | * | 
|  | * @return: return status | 
|  | */ | 
|  | int convert_yuv_c2d_to_yuv_android(private_handle_t *hnd, | 
|  | struct copybit_image_t const *rhs) | 
|  | { | 
|  | ALOGD("Enter %s", __FUNCTION__); | 
|  | if (!hnd || !rhs) { | 
|  | ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs); | 
|  | return COPYBIT_FAILURE; | 
|  | } | 
|  |  | 
|  | int ret = COPYBIT_SUCCESS; | 
|  | private_handle_t *dst_hnd = (private_handle_t *)rhs->handle; | 
|  |  | 
|  | copyInfo info; | 
|  | info.width = rhs->w; | 
|  | info.height = rhs->h; | 
|  | info.src_stride = ALIGN(info.width, 32); | 
|  | info.dst_stride = ALIGN(info.width, 16); | 
|  | switch(rhs->format) { | 
|  | case HAL_PIXEL_FORMAT_YCbCr_420_SP: | 
|  | case HAL_PIXEL_FORMAT_YCrCb_420_SP: { | 
|  | info.src_plane1_offset = info.src_stride*info.height; | 
|  | info.dst_plane1_offset = info.dst_stride*info.height; | 
|  | } break; | 
|  | case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: { | 
|  | // Chroma is 2K aligned for the NV12 encodeable format. | 
|  | info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048); | 
|  | info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048); | 
|  | } break; | 
|  | default: | 
|  | ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__, | 
|  | rhs->format); | 
|  | return COPYBIT_FAILURE; | 
|  | } | 
|  |  | 
|  | ret = copy_source_to_destination((uintptr_t) hnd->base, (uintptr_t) dst_hnd->base, info); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Function to convert the Android format into an equivalent C2D format | 
|  | * | 
|  | * @param: source buffer handle | 
|  | * @param: destination image | 
|  | * | 
|  | * @return: return status | 
|  | */ | 
|  | int convert_yuv_android_to_yuv_c2d(private_handle_t *hnd, | 
|  | struct copybit_image_t const *rhs) | 
|  | { | 
|  | if (!hnd || !rhs) { | 
|  | ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs); | 
|  | return COPYBIT_FAILURE; | 
|  | } | 
|  |  | 
|  | int ret = COPYBIT_SUCCESS; | 
|  | private_handle_t *dst_hnd = (private_handle_t *)rhs->handle; | 
|  |  | 
|  | copyInfo info; | 
|  | info.width = rhs->w; | 
|  | info.height = rhs->h; | 
|  | info.src_stride = ALIGN(hnd->width, 16); | 
|  | info.dst_stride = ALIGN(info.width, 32); | 
|  | switch(rhs->format) { | 
|  | case HAL_PIXEL_FORMAT_YCbCr_420_SP: | 
|  | case HAL_PIXEL_FORMAT_YCrCb_420_SP: { | 
|  | info.src_plane1_offset = info.src_stride*info.height; | 
|  | info.dst_plane1_offset = info.dst_stride*info.height; | 
|  | } break; | 
|  | case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: { | 
|  | // Chroma is 2K aligned for the NV12 encodeable format. | 
|  | info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048); | 
|  | info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048); | 
|  | } break; | 
|  | default: | 
|  | ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__, | 
|  | rhs->format); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | ret = copy_source_to_destination((uintptr_t) hnd->base, (uintptr_t) dst_hnd->base, info); | 
|  | return ret; | 
|  | } |