739ac1ba01
Use a temporary buffer to replace inplace conversion CRs-fixed: 333784 (cherry picked from commit 927542660e4c6106f8062c79bd6461c7fef55b4a) Change-Id: I044bdaa31faea98552e35267bb78318317d68866
264 lines
8.9 KiB
C++
264 lines
8.9 KiB
C++
/*
|
|
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
|
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#define LOG_TAG "copybit"
|
|
#include <cutils/log.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include "software_converter.h"
|
|
|
|
/** Convert YV12 to YCrCb_420_SP */
|
|
int convertYV12toYCrCb420SP(const copybit_image_t *src, private_handle_t *yv12_handle)
|
|
{
|
|
private_handle_t* hnd = (private_handle_t*)src->handle;
|
|
|
|
if(hnd == NULL || yv12_handle == NULL){
|
|
LOGE("Invalid handle");
|
|
return -1;
|
|
}
|
|
|
|
// Please refer to the description of YV12 in hardware.h
|
|
// for the formulae used to calculate buffer sizes and offsets
|
|
|
|
// In a copybit_image_t, w is the stride and
|
|
// stride - horiz_padding is the actual width
|
|
// vertical stride is the same as height, so not considered
|
|
unsigned int stride = src->w;
|
|
unsigned int width = src->w - src->horiz_padding;
|
|
unsigned int height = src->h;
|
|
unsigned int padding = src->horiz_padding;
|
|
unsigned int y_size = stride * src->h;
|
|
unsigned int c_width = ALIGN(stride/2, 16);
|
|
unsigned int c_size = c_width * src->h/2;
|
|
unsigned int chromaSize = c_size * 2;
|
|
unsigned char* newChroma = (unsigned char *)(yv12_handle->base + y_size);
|
|
unsigned char* oldChroma = (unsigned char*)(hnd->base + y_size);
|
|
memcpy((char *)yv12_handle->base,(char *)hnd->base,y_size);
|
|
|
|
#ifdef __ARM_HAVE_NEON
|
|
/* interleave */
|
|
if(!padding) {
|
|
unsigned char * t1 = newChroma;
|
|
unsigned char * t2 = oldChroma;
|
|
unsigned char * t3 = t2 + chromaSize/2;
|
|
for(unsigned int i=0; i < (chromaSize/2)>>3; i++) {
|
|
__asm__ __volatile__ (
|
|
"vld1.u8 d0, [%0]! \n"
|
|
"vld1.u8 d1, [%1]! \n"
|
|
"vst2.u8 {d0, d1}, [%2]! \n"
|
|
:"+r"(t2), "+r"(t3), "+r"(t1)
|
|
:
|
|
:"memory","d0","d1"
|
|
);
|
|
|
|
}
|
|
}
|
|
#else //__ARM_HAVE_NEON
|
|
if(!padding) {
|
|
for(unsigned int i = 0; i< chromaSize/2; i++) {
|
|
newChroma[i*2] = oldChroma[i];
|
|
newChroma[i*2+1] = oldChroma[i+chromaSize/2];
|
|
}
|
|
|
|
}
|
|
#endif
|
|
// If the image is not aligned to 16 pixels,
|
|
// convert using the C routine below
|
|
// r1 tracks the row of the source buffer
|
|
// r2 tracks the row of the destination buffer
|
|
// The width/2 checks are to avoid copying
|
|
// from the padding
|
|
|
|
if(padding) {
|
|
unsigned int r1 = 0, r2 = 0, i = 0, j = 0;
|
|
while(r1 < height/2) {
|
|
if(j == width/2) {
|
|
j = 0;
|
|
r2++;
|
|
continue;
|
|
}
|
|
if (j+1 == width/2) {
|
|
newChroma[r2*c_width + j] = oldChroma[r1*c_width+i];
|
|
r2++;
|
|
newChroma[r2*c_width] = oldChroma[r1*c_width+i+c_size];
|
|
j = 1;
|
|
} else {
|
|
newChroma[r2*c_width + j] = oldChroma[r1*c_width+i];
|
|
newChroma[r2*c_width + j + 1] = oldChroma[r1*c_width+i+c_size];
|
|
j+=2;
|
|
}
|
|
i++;
|
|
if (i == width/2 ) {
|
|
i = 0;
|
|
r1++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct copyInfo{
|
|
int width;
|
|
int height;
|
|
int src_stride;
|
|
int dst_stride;
|
|
int src_plane1_offset;
|
|
int src_plane2_offset;
|
|
int dst_plane1_offset;
|
|
int dst_plane2_offset;
|
|
};
|
|
|
|
/* Internal function to do the actual copy of source to destination */
|
|
static int copy_source_to_destination(const int src_base, const int dst_base,
|
|
copyInfo& info)
|
|
{
|
|
if (!src_base || !dst_base) {
|
|
LOGE("%s: invalid memory src_base = 0x%x dst_base=0x%x",
|
|
__FUNCTION__, src_base, dst_base);
|
|
return COPYBIT_FAILURE;
|
|
}
|
|
|
|
int width = info.width;
|
|
int height = info.height;
|
|
unsigned char *src = (unsigned char*)src_base;
|
|
unsigned char *dst = (unsigned char*)dst_base;
|
|
|
|
// Copy the luma
|
|
for (int i = 0; i < height; i++) {
|
|
memcpy(dst, src, width);
|
|
src += info.src_stride;
|
|
dst += info.dst_stride;
|
|
}
|
|
|
|
// Copy plane 1
|
|
src = (unsigned char*)(src_base + info.src_plane1_offset);
|
|
dst = (unsigned char*)(dst_base + info.dst_plane1_offset);
|
|
width = width/2;
|
|
height = height/2;
|
|
for (int i = 0; i < height; i++) {
|
|
memcpy(dst, src, info.src_stride);
|
|
src += info.src_stride;
|
|
dst += info.dst_stride;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Function to convert the c2d format into an equivalent Android format
|
|
*
|
|
* @param: source buffer handle
|
|
* @param: destination image
|
|
*
|
|
* @return: return status
|
|
*/
|
|
int convert_yuv_c2d_to_yuv_android(private_handle_t *hnd,
|
|
struct copybit_image_t const *rhs)
|
|
{
|
|
LOGD("Enter %s", __FUNCTION__);
|
|
if (!hnd || !rhs) {
|
|
LOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs);
|
|
return COPYBIT_FAILURE;
|
|
}
|
|
|
|
int ret = COPYBIT_SUCCESS;
|
|
private_handle_t *dst_hnd = (private_handle_t *)rhs->handle;
|
|
|
|
copyInfo info;
|
|
info.width = rhs->w;
|
|
info.height = rhs->h;
|
|
info.src_stride = ALIGN(info.width, 32);
|
|
info.dst_stride = ALIGN(info.width, 16);
|
|
switch(rhs->format) {
|
|
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
|
|
case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
|
|
info.src_plane1_offset = info.src_stride*info.height;
|
|
info.dst_plane1_offset = info.dst_stride*info.height;
|
|
} break;
|
|
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: {
|
|
// Chroma is 2K aligned for the NV12 encodeable format.
|
|
info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048);
|
|
info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048);
|
|
} break;
|
|
default:
|
|
LOGE("%s: unsupported format (format=0x%x)", __FUNCTION__,
|
|
rhs->format);
|
|
return COPYBIT_FAILURE;
|
|
}
|
|
|
|
ret = copy_source_to_destination(hnd->base, dst_hnd->base, info);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Function to convert the Android format into an equivalent C2D format
|
|
*
|
|
* @param: source buffer handle
|
|
* @param: destination image
|
|
*
|
|
* @return: return status
|
|
*/
|
|
int convert_yuv_android_to_yuv_c2d(private_handle_t *hnd,
|
|
struct copybit_image_t const *rhs)
|
|
{
|
|
if (!hnd || !rhs) {
|
|
LOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs);
|
|
return COPYBIT_FAILURE;
|
|
}
|
|
|
|
int ret = COPYBIT_SUCCESS;
|
|
private_handle_t *dst_hnd = (private_handle_t *)rhs->handle;
|
|
|
|
copyInfo info;
|
|
info.width = rhs->w;
|
|
info.height = rhs->h;
|
|
info.src_stride = ALIGN(info.width, 16);
|
|
info.dst_stride = ALIGN(info.width, 32);
|
|
switch(rhs->format) {
|
|
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
|
|
case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
|
|
info.src_plane1_offset = info.src_stride*info.height;
|
|
info.dst_plane1_offset = info.dst_stride*info.height;
|
|
} break;
|
|
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: {
|
|
// Chroma is 2K aligned for the NV12 encodeable format.
|
|
info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048);
|
|
info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048);
|
|
} break;
|
|
default:
|
|
LOGE("%s: unsupported format (format=0x%x)", __FUNCTION__,
|
|
rhs->format);
|
|
return -1;
|
|
}
|
|
|
|
ret = copy_source_to_destination(hnd->base, dst_hnd->base, info);
|
|
return ret;
|
|
}
|