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 */
36int 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
126struct 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 */
138static 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 */
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