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 */
37int 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
127struct 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 */
139static 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 */
182int 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 */
228int 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