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 */
convertYV12toYCrCb420SP(const copybit_image_t * src,private_handle_t * yv12_handle)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 */
copy_source_to_destination(const uintptr_t src_base,const uintptr_t dst_base,copyInfo & info)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 */
convert_yuv_c2d_to_yuv_android(private_handle_t * hnd,struct copybit_image_t const * rhs)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 */
convert_yuv_android_to_yuv_c2d(private_handle_t * hnd,struct copybit_image_t const * rhs)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