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 <errno.h> 31 #include <stdlib.h> 32 33 #include <log/log.h> 34 35 #include "software_converter.h" 36 37 /** Convert YV12 to YCrCb_420_SP */ 38 int convertYV12toYCrCb420SP(const copybit_image_t *src, private_handle_t *yv12_handle) 39 { 40 private_handle_t* hnd = (private_handle_t*)src->handle; 41 42 if(hnd == NULL || yv12_handle == NULL){ 43 ALOGE("Invalid handle"); 44 return -1; 45 } 46 47 // Please refer to the description of YV12 in hardware.h 48 // for the formulae used to calculate buffer sizes and offsets 49 50 // In a copybit_image_t, w is the stride and 51 // stride - horiz_padding is the actual width 52 // vertical stride is the same as height, so not considered 53 unsigned int stride = src->w; 54 unsigned int width = src->w - src->horiz_padding; 55 unsigned int height = src->h; 56 unsigned int y_size = stride * src->h; 57 unsigned int c_width = ALIGN(stride/2, (unsigned int)16); 58 unsigned int c_size = c_width * src->h/2; 59 unsigned int chromaPadding = c_width - width/2; 60 unsigned int chromaSize = c_size * 2; 61 unsigned char* newChroma = (unsigned char *)(yv12_handle->base + y_size); 62 unsigned char* oldChroma = (unsigned char*)(hnd->base + y_size); 63 memcpy((char *)yv12_handle->base,(char *)hnd->base,y_size); 64 65 #if defined(__ARM_HAVE_NEON) && !defined(__aarch64__) 66 /* interleave */ 67 if(!chromaPadding) { 68 unsigned char * t1 = newChroma; 69 unsigned char * t2 = oldChroma; 70 unsigned char * t3 = t2 + chromaSize/2; 71 for(unsigned int i=0; i < (chromaSize/2)>>3; i++) { 72 __asm__ __volatile__ ( 73 "vld1.u8 d0, [%0]! \n" 74 "vld1.u8 d1, [%1]! \n" 75 "vst2.u8 {d0, d1}, [%2]! \n" 76 :"+r"(t2), "+r"(t3), "+r"(t1) 77 : 78 :"memory","d0","d1" 79 ); 80 81 } 82 } 83 #else //__ARM_HAVE_NEON 84 if(!chromaPadding) { 85 for(unsigned int i = 0; i< chromaSize/2; i++) { 86 newChroma[i*2] = oldChroma[i]; 87 newChroma[i*2+1] = oldChroma[i+chromaSize/2]; 88 } 89 90 } 91 #endif 92 // If the image is not aligned to 16 pixels, 93 // convert using the C routine below 94 // r1 tracks the row of the source buffer 95 // r2 tracks the row of the destination buffer 96 // The width/2 checks are to avoid copying 97 // from the padding 98 99 if(chromaPadding) { 100 unsigned int r1 = 0, r2 = 0, i = 0, j = 0; 101 while(r1 < height/2) { 102 if(j == width) { 103 j = 0; 104 r2++; 105 continue; 106 } 107 if (j+1 == width) { 108 newChroma[r2*width + j] = oldChroma[r1*c_width+i]; 109 r2++; 110 newChroma[r2*width] = oldChroma[r1*c_width+i+c_size]; 111 j = 1; 112 } else { 113 newChroma[r2*width + j] = oldChroma[r1*c_width+i]; 114 newChroma[r2*width + j + 1] = oldChroma[r1*c_width+i+c_size]; 115 j+=2; 116 } 117 i++; 118 if (i == width/2 ) { 119 i = 0; 120 r1++; 121 } 122 } 123 } 124 125 return 0; 126 } 127 128 struct copyInfo{ 129 int width; 130 int height; 131 int src_stride; 132 int dst_stride; 133 size_t src_plane1_offset; 134 size_t src_plane2_offset; 135 size_t dst_plane1_offset; 136 size_t dst_plane2_offset; 137 }; 138 139 /* Internal function to do the actual copy of source to destination */ 140 static int copy_source_to_destination(const uintptr_t src_base, 141 const uintptr_t dst_base, 142 copyInfo& info) 143 { 144 if (!src_base || !dst_base) { 145 ALOGE("%s: invalid memory src_base = 0x%p dst_base=0x%p", 146 __FUNCTION__, (void*)src_base, (void*)dst_base); 147 return COPYBIT_FAILURE; 148 } 149 150 int width = info.width; 151 int height = info.height; 152 unsigned char *src = (unsigned char*)src_base; 153 unsigned char *dst = (unsigned char*)dst_base; 154 155 // Copy the luma 156 for (int i = 0; i < height; i++) { 157 memcpy(dst, src, width); 158 src += info.src_stride; 159 dst += info.dst_stride; 160 } 161 162 // Copy plane 1 163 src = (unsigned char*)(src_base + info.src_plane1_offset); 164 dst = (unsigned char*)(dst_base + info.dst_plane1_offset); 165 width = width/2; 166 height = height/2; 167 for (int i = 0; i < height; i++) { 168 memcpy(dst, src, info.src_stride); 169 src += info.src_stride; 170 dst += info.dst_stride; 171 } 172 return 0; 173 } 174 175 176 /* 177 * Function to convert the c2d format into an equivalent Android format 178 * 179 * @param: source buffer handle 180 * @param: destination image 181 * 182 * @return: return status 183 */ 184 int convert_yuv_c2d_to_yuv_android(private_handle_t *hnd, 185 struct copybit_image_t const *rhs) 186 { 187 ALOGD("Enter %s", __FUNCTION__); 188 if (!hnd || !rhs) { 189 ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs); 190 return COPYBIT_FAILURE; 191 } 192 193 int ret = COPYBIT_SUCCESS; 194 private_handle_t *dst_hnd = (private_handle_t *)rhs->handle; 195 196 copyInfo info; 197 info.width = rhs->w; 198 info.height = rhs->h; 199 info.src_stride = ALIGN(info.width, 32); 200 info.dst_stride = ALIGN(info.width, 16); 201 switch(rhs->format) { 202 case HAL_PIXEL_FORMAT_YCbCr_420_SP: 203 case HAL_PIXEL_FORMAT_YCrCb_420_SP: { 204 info.src_plane1_offset = info.src_stride*info.height; 205 info.dst_plane1_offset = info.dst_stride*info.height; 206 } break; 207 case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: { 208 // Chroma is 2K aligned for the NV12 encodeable format. 209 info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048); 210 info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048); 211 } break; 212 default: 213 ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__, 214 rhs->format); 215 return COPYBIT_FAILURE; 216 } 217 218 ret = copy_source_to_destination((uintptr_t) hnd->base, (uintptr_t) dst_hnd->base, info); 219 return ret; 220 } 221 222 /* 223 * Function to convert the Android format into an equivalent C2D format 224 * 225 * @param: source buffer handle 226 * @param: destination image 227 * 228 * @return: return status 229 */ 230 int convert_yuv_android_to_yuv_c2d(private_handle_t *hnd, 231 struct copybit_image_t const *rhs) 232 { 233 if (!hnd || !rhs) { 234 ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs); 235 return COPYBIT_FAILURE; 236 } 237 238 int ret = COPYBIT_SUCCESS; 239 private_handle_t *dst_hnd = (private_handle_t *)rhs->handle; 240 241 copyInfo info; 242 info.width = rhs->w; 243 info.height = rhs->h; 244 info.src_stride = ALIGN(hnd->width, 16); 245 info.dst_stride = ALIGN(info.width, 32); 246 switch(rhs->format) { 247 case HAL_PIXEL_FORMAT_YCbCr_420_SP: 248 case HAL_PIXEL_FORMAT_YCrCb_420_SP: { 249 info.src_plane1_offset = info.src_stride*info.height; 250 info.dst_plane1_offset = info.dst_stride*info.height; 251 } break; 252 case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: { 253 // Chroma is 2K aligned for the NV12 encodeable format. 254 info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048); 255 info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048); 256 } break; 257 default: 258 ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__, 259 rhs->format); 260 return -1; 261 } 262 263 ret = copy_source_to_destination((uintptr_t) hnd->base, (uintptr_t) dst_hnd->base, info); 264 return ret; 265 } 266