Naseer Ahmed | 29a2681 | 2012-06-14 00:56:20 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2011, Code Aurora Forum. 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 Code Aurora Forum, Inc. 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 | #define LOG_TAG "copybit" |
| 31 | #include <cutils/log.h> |
| 32 | #include <stdlib.h> |
| 33 | #include <errno.h> |
| 34 | #include "software_converter.h" |
| 35 | |
| 36 | /** Convert YV12 to YCrCb_420_SP */ |
| 37 | int convertYV12toYCrCb420SP(const copybit_image_t *src, private_handle_t *yv12_handle) |
| 38 | { |
| 39 | private_handle_t* hnd = (private_handle_t*)src->handle; |
| 40 | |
| 41 | if(hnd == NULL || yv12_handle == NULL){ |
| 42 | ALOGE("Invalid handle"); |
| 43 | return -1; |
| 44 | } |
| 45 | |
| 46 | // Please refer to the description of YV12 in hardware.h |
| 47 | // for the formulae used to calculate buffer sizes and offsets |
| 48 | |
| 49 | // In a copybit_image_t, w is the stride and |
| 50 | // stride - horiz_padding is the actual width |
| 51 | // vertical stride is the same as height, so not considered |
| 52 | unsigned int stride = src->w; |
| 53 | unsigned int width = src->w - src->horiz_padding; |
| 54 | unsigned int height = src->h; |
| 55 | unsigned int y_size = stride * src->h; |
| 56 | unsigned int c_width = ALIGN(stride/2, 16); |
| 57 | unsigned int c_size = c_width * src->h/2; |
| 58 | unsigned int chromaPadding = c_width - width/2; |
| 59 | unsigned int chromaSize = c_size * 2; |
| 60 | unsigned char* newChroma = (unsigned char *)(yv12_handle->base + y_size); |
| 61 | unsigned char* oldChroma = (unsigned char*)(hnd->base + y_size); |
| 62 | memcpy((char *)yv12_handle->base,(char *)hnd->base,y_size); |
| 63 | |
| 64 | #ifdef __ARM_HAVE_NEON |
| 65 | /* interleave */ |
| 66 | if(!chromaPadding) { |
| 67 | unsigned char * t1 = newChroma; |
| 68 | unsigned char * t2 = oldChroma; |
| 69 | unsigned char * t3 = t2 + chromaSize/2; |
| 70 | for(unsigned int i=0; i < (chromaSize/2)>>3; i++) { |
| 71 | __asm__ __volatile__ ( |
| 72 | "vld1.u8 d0, [%0]! \n" |
| 73 | "vld1.u8 d1, [%1]! \n" |
| 74 | "vst2.u8 {d0, d1}, [%2]! \n" |
| 75 | :"+r"(t2), "+r"(t3), "+r"(t1) |
| 76 | : |
| 77 | :"memory","d0","d1" |
| 78 | ); |
| 79 | |
| 80 | } |
| 81 | } |
| 82 | #else //__ARM_HAVE_NEON |
| 83 | if(!chromaPadding) { |
| 84 | for(unsigned int i = 0; i< chromaSize/2; i++) { |
| 85 | newChroma[i*2] = oldChroma[i]; |
| 86 | newChroma[i*2+1] = oldChroma[i+chromaSize/2]; |
| 87 | } |
| 88 | |
| 89 | } |
| 90 | #endif |
| 91 | // If the image is not aligned to 16 pixels, |
| 92 | // convert using the C routine below |
| 93 | // r1 tracks the row of the source buffer |
| 94 | // r2 tracks the row of the destination buffer |
| 95 | // The width/2 checks are to avoid copying |
| 96 | // from the padding |
| 97 | |
| 98 | if(chromaPadding) { |
| 99 | unsigned int r1 = 0, r2 = 0, i = 0, j = 0; |
| 100 | while(r1 < height/2) { |
| 101 | if(j == width) { |
| 102 | j = 0; |
| 103 | r2++; |
| 104 | continue; |
| 105 | } |
| 106 | if (j+1 == width) { |
| 107 | newChroma[r2*width + j] = oldChroma[r1*c_width+i]; |
| 108 | r2++; |
| 109 | newChroma[r2*width] = oldChroma[r1*c_width+i+c_size]; |
| 110 | j = 1; |
| 111 | } else { |
| 112 | newChroma[r2*width + j] = oldChroma[r1*c_width+i]; |
| 113 | newChroma[r2*width + j + 1] = oldChroma[r1*c_width+i+c_size]; |
| 114 | j+=2; |
| 115 | } |
| 116 | i++; |
| 117 | if (i == width/2 ) { |
| 118 | i = 0; |
| 119 | r1++; |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | return 0; |
| 125 | } |
| 126 | |
| 127 | struct copyInfo{ |
| 128 | int width; |
| 129 | int height; |
| 130 | int src_stride; |
| 131 | int dst_stride; |
| 132 | int src_plane1_offset; |
| 133 | int src_plane2_offset; |
| 134 | int dst_plane1_offset; |
| 135 | int dst_plane2_offset; |
| 136 | }; |
| 137 | |
| 138 | /* Internal function to do the actual copy of source to destination */ |
| 139 | static int copy_source_to_destination(const int src_base, const int dst_base, |
| 140 | copyInfo& info) |
| 141 | { |
| 142 | if (!src_base || !dst_base) { |
| 143 | ALOGE("%s: invalid memory src_base = 0x%x dst_base=0x%x", |
| 144 | __FUNCTION__, src_base, 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 | } |