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 <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, (unsigned int)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     size_t src_plane1_offset;
132     size_t src_plane2_offset;
133     size_t dst_plane1_offset;
134     size_t dst_plane2_offset;
135 };
136 
137 /* 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)138 static int copy_source_to_destination(const uintptr_t src_base,
139                                       const uintptr_t dst_base,
140                                       copyInfo& info)
141 {
142     if (!src_base || !dst_base) {
143         ALOGE("%s: invalid memory src_base = 0x%p dst_base=0x%p",
144              __FUNCTION__, (void*)src_base, (void*)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  */
convert_yuv_c2d_to_yuv_android(private_handle_t * hnd,struct copybit_image_t const * rhs)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  */
convert_yuv_android_to_yuv_c2d(private_handle_t * hnd,struct copybit_image_t const * rhs)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 }
264