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