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