提交 5db828eb 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!97 gralloc:yuv support

Merge pull request !97 from 赵鹏元/master
......@@ -5,9 +5,10 @@ $(call emugl-import,libGLESv1_enc libGLESv2_enc lib_renderControl_enc)
LOCAL_SRC_FILES := \
HostConnection.cpp \
FormatConversions.cpp \
QemuPipeStream.cpp \
ThreadInfo.cpp
$(call emugl-export,C_INCLUDES,$(LOCAL_PATH) bionic/libc/private)
$(call emugl-export,SHARED_LIBRARIES,libcutils libutils liblog)
$(call emugl-end-module)
/*
* Copyright (C) 2016 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "FormatConversions.h"
#include <cutils/log.h>
#include <string.h>
#define DEBUG 0
#if DEBUG
#define DD(...) ALOGD(...)
#else
#define DD(...)
#endif
void get_yv12_offsets(int width, int height, uint32_t *yStride_out, uint32_t *cStride_out, uint32_t *totalSz_out) {
uint32_t align = 16;
uint32_t yStride = (width + (align - 1)) & ~(align - 1);
uint32_t uvStride = (yStride / 2 + (align - 1)) & ~(align - 1);
uint32_t uvHeight = height / 2;
uint32_t sz = yStride * height + 2 * (uvHeight * uvStride);
if (yStride_out) {
*yStride_out = yStride;
}
if (cStride_out) {
*cStride_out = uvStride;
}
if (totalSz_out) {
*totalSz_out = sz;
}
}
void get_yuv420p_offsets(int width, int height, uint32_t *yStride_out, uint32_t *cStride_out, uint32_t *totalSz_out) {
uint32_t align = 1;
uint32_t yStride = (width + (align - 1)) & ~(align - 1);
uint32_t uvStride = (yStride / 2 + (align - 1)) & ~(align - 1);
uint32_t uvHeight = height / 2;
uint32_t sz = yStride * height + 2 * (uvHeight * uvStride);
if (yStride_out) { *yStride_out = yStride; }
if (cStride_out) { *cStride_out = uvStride; }
if (totalSz_out) { *totalSz_out = sz; }
}
signed clamp_rgb(signed value) {
if (value > 255) {
value = 255;
} else if (value < 0) {
value = 0;
}
return value;
}
void rgb565_to_yv12(char *dest, char *src, int width, int height, int left, int top, int right, int bottom) {
int align = 16;
int yStride = (width + (align - 1)) & ~(align - 1);
int cStride = (yStride / 2 + (align - 1)) & ~(align - 1);
int yOffset = 0;
int cSize = cStride * height / 2;
uint16_t *rgb_ptr0 = (uint16_t *) src;
uint8_t *yv12_y0 = (uint8_t *) dest;
uint8_t *yv12_v0 = yv12_y0 + yStride * height;
uint8_t *yv12_u0 = yv12_v0 + cSize;
for (int j = top; j <= bottom; ++j) {
uint8_t *yv12_y = yv12_y0 + j * yStride;
uint8_t *yv12_v = yv12_v0 + (j / 2) * cStride;
uint8_t *yv12_u = yv12_v + cSize;
uint16_t *rgb_ptr = rgb_ptr0 + j * width;
bool jeven = (j & 1) == 0;
for (int i = left; i <= right; ++i) {
uint8_t r = ((rgb_ptr[i]) >> 11) & 0x01f;
uint8_t g = ((rgb_ptr[i]) >> 5) & 0x03f;
uint8_t b = (rgb_ptr[i]) & 0x01f;
// convert to 8bits
// http://stackoverflow.com/questions/2442576/how-does-one-convert-16-bit-rgb565-to-24-bit-rgb888
uint8_t R = (r * 527 + 23) >> 6;
uint8_t G = (g * 259 + 33) >> 6;
uint8_t B = (b * 527 + 23) >> 6;
// convert to YV12
// frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8);
bool ieven = (i & 1) == 0;
if (jeven && ieven) {
yv12_u[i] = clamp_rgb(((-43 * R - 85 * G + 128 * B) >> 8) + 128);
yv12_v[i] = clamp_rgb(((128 * R - 107 * G - 21 * B) >> 8) + 128);
}
}
}
}
void rgb888_to_yv12(char *dest, char *src, int width, int height, int left, int top, int right, int bottom) {
DD("%s convert %d by %d", __func__, width, height);
int align = 16;
int yStride = (width + (align - 1)) & ~(align - 1);
int cStride = (yStride / 2 + (align - 1)) & ~(align - 1);
int yOffset = 0;
int cSize = cStride * height / 2;
int rgb_stride = 3;
uint8_t *rgb_ptr0 = (uint8_t *) src;
uint8_t *yv12_y0 = (uint8_t *) dest;
uint8_t *yv12_v0 = yv12_y0 + yStride * height;
uint8_t *yv12_u0 = yv12_v0 + cSize;
for (int j = top; j <= bottom; ++j) {
uint8_t *yv12_y = yv12_y0 + j * yStride;
uint8_t *yv12_v = yv12_v0 + (j / 2) * cStride;
uint8_t *yv12_u = yv12_v + cSize;
uint8_t *rgb_ptr = rgb_ptr0 + j * width * rgb_stride;
bool jeven = (j & 1) == 0;
for (int i = left; i <= right; ++i) {
uint8_t R = rgb_ptr[i * rgb_stride];
uint8_t G = rgb_ptr[i * rgb_stride + 1];
uint8_t B = rgb_ptr[i * rgb_stride + 2];
// convert to YV12
// frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8);
bool ieven = (i & 1) == 0;
if (jeven && ieven) {
yv12_u[i] = clamp_rgb(((-43 * R - 85 * G + 128 * B) >> 8) + 128);
yv12_v[i] = clamp_rgb(((128 * R - 107 * G - 21 * B) >> 8) + 128);
}
}
}
}
void rgb888_to_yuv420p(char *dest, char *src, int width, int height, int left, int top, int right, int bottom) {
DD("%s convert %d by %d", __func__, width, height);
int yStride = width;
int cStride = yStride / 2;
int yOffset = 0;
int cSize = cStride * height / 2;
int rgb_stride = 3;
uint8_t *rgb_ptr0 = (uint8_t *) src;
uint8_t *yv12_y0 = (uint8_t *) dest;
uint8_t *yv12_u0 = yv12_y0 + yStride * height;
uint8_t *yv12_v0 = yv12_u0 + cSize;
for (int j = top; j <= bottom; ++j) {
uint8_t *yv12_y = yv12_y0 + j * yStride;
uint8_t *yv12_u = yv12_u0 + (j / 2) * cStride;
uint8_t *yv12_v = yv12_u + cStride;
uint8_t *rgb_ptr = rgb_ptr0 + j * width * rgb_stride;
bool jeven = (j & 1) == 0;
for (int i = left; i <= right; ++i) {
uint8_t R = rgb_ptr[i * rgb_stride];
uint8_t G = rgb_ptr[i * rgb_stride + 1];
uint8_t B = rgb_ptr[i * rgb_stride + 2];
// convert to YV12
// frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8);
bool ieven = (i & 1) == 0;
if (jeven && ieven) {
yv12_u[i] = clamp_rgb(((-43 * R - 85 * G + 128 * B) >> 8) + 128);
yv12_v[i] = clamp_rgb(((128 * R - 107 * G - 21 * B) >> 8) + 128);
}
}
}
}
// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
// certain stride requirements for Y and UV respectively.
void yv12_to_rgb565(char *dest, char *src, int width, int height, int left, int top, int right, int bottom) {
DD("%s convert %d by %d", __func__, width, height);
int align = 16;
int yStride = (width + (align - 1)) & ~(align - 1);
int cStride = (yStride / 2 + (align - 1)) & ~(align - 1);
int yOffset = 0;
int cSize = cStride * height / 2;
uint16_t *rgb_ptr0 = (uint16_t *) dest;
uint8_t *yv12_y0 = (uint8_t *) src;
uint8_t *yv12_v0 = yv12_y0 + yStride * height;
uint8_t *yv12_u0 = yv12_v0 + cSize;
for (int j = top; j <= bottom; ++j) {
uint8_t *yv12_y = yv12_y0 + j * yStride;
uint8_t *yv12_v = yv12_v0 + (j / 2) * cStride;
uint8_t *yv12_u = yv12_v + cSize;
uint16_t *rgb_ptr = rgb_ptr0 + (j - top) * (right - left + 1);
for (int i = left; i <= right; ++i) {
// convert to rgb
// frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
signed y1 = (signed) yv12_y[i] - 16;
signed u = (signed) yv12_u[i / 2] - 128;
signed v = (signed) yv12_v[i / 2] - 128;
signed u_b = u * 517;
signed u_g = -u * 100;
signed v_g = -v * 208;
signed v_r = v * 409;
signed tmp1 = y1 * 298;
signed b1 = clamp_rgb((tmp1 + u_b) / 256);
signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
signed r1 = clamp_rgb((tmp1 + v_r) / 256);
uint16_t rgb1 = ((r1 >> 3) << 11) | ((g1 >> 2) << 5) | (b1 >> 3);
rgb_ptr[i - left] = rgb1;
}
}
}
// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
// certain stride requirements for Y and UV respectively.
void yv12_to_rgb888(char *dest, char *src, int width, int height, int left, int top, int right, int bottom) {
DD("%s convert %d by %d", __func__, width, height);
int align = 16;
int yStride = (width + (align - 1)) & ~(align - 1);
int cStride = (yStride / 2 + (align - 1)) & ~(align - 1);
int yOffset = 0;
int cSize = cStride * height / 2;
int rgb_stride = 3;
uint8_t *rgb_ptr0 = (uint8_t *) dest;
uint8_t *yv12_y0 = (uint8_t *) src;
uint8_t *yv12_v0 = yv12_y0 + yStride * height;
uint8_t *yv12_u0 = yv12_v0 + cSize;
for (int j = top; j <= bottom; ++j) {
uint8_t *yv12_y = yv12_y0 + j * yStride;
uint8_t *yv12_v = yv12_v0 + (j / 2) * cStride;
uint8_t *yv12_u = yv12_v + cSize;
uint8_t *rgb_ptr = rgb_ptr0 + (j - top) * (right - left + 1) * rgb_stride;
for (int i = left; i <= right; ++i) {
// convert to rgb
// frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
signed y1 = (signed) yv12_y[i] - 16;
signed u = (signed) yv12_u[i / 2] - 128;
signed v = (signed) yv12_v[i / 2] - 128;
signed u_b = u * 517;
signed u_g = -u * 100;
signed v_g = -v * 208;
signed v_r = v * 409;
signed tmp1 = y1 * 298;
signed b1 = clamp_rgb((tmp1 + u_b) / 256);
signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
signed r1 = clamp_rgb((tmp1 + v_r) / 256);
rgb_ptr[(i - left) * rgb_stride] = r1;
rgb_ptr[(i - left) * rgb_stride + 1] = g1;
rgb_ptr[(i - left) * rgb_stride + 2] = b1;
}
}
}
// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
// certain stride requirements for Y and UV respectively.
void yuv420p_to_rgb888(char *dest, char *src, int width, int height, int left, int top, int right, int bottom) {
DD("%s convert %d by %d", __func__, width, height);
int yStride = width;
int cStride = yStride / 2;
int yOffset = 0;
int cSize = cStride * height / 2;
int rgb_stride = 3;
uint8_t *rgb_ptr0 = (uint8_t *) dest;
uint8_t *yv12_y0 = (uint8_t *) src;
uint8_t *yv12_u0 = yv12_y0 + yStride * height;
uint8_t *yv12_v0 = yv12_u0 + cSize;
for (int j = top; j <= bottom; ++j) {
uint8_t *yv12_y = yv12_y0 + j * yStride;
uint8_t *yv12_u = yv12_u0 + (j / 2) * cStride;
uint8_t *yv12_v = yv12_u + cSize;
uint8_t *rgb_ptr = rgb_ptr0 + (j - top) * (right - left + 1) * rgb_stride;
for (int i = left; i <= right; ++i) {
// convert to rgb
// frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
signed y1 = (signed) yv12_y[i] - 16;
signed u = (signed) yv12_u[i / 2] - 128;
signed v = (signed) yv12_v[i / 2] - 128;
signed u_b = u * 517;
signed u_g = -u * 100;
signed v_g = -v * 208;
signed v_r = v * 409;
signed tmp1 = y1 * 298;
signed b1 = clamp_rgb((tmp1 + u_b) / 256);
signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
signed r1 = clamp_rgb((tmp1 + v_r) / 256);
rgb_ptr[(i - left) * rgb_stride] = r1;
rgb_ptr[(i - left) * rgb_stride + 1] = g1;
rgb_ptr[(i - left) * rgb_stride + 2] = b1;
}
}
}
void
copy_rgb_buffer_from_unlocked(char *_dst, char *raw_data, int unlockedWidth, int width, int height, int top, int left,
int bpp) {
char *dst = _dst;
int dst_line_len = width * bpp;
int src_line_len = unlockedWidth * bpp;
char *src = (char *) raw_data + top * src_line_len + left * bpp;
for (int y = 0; y < height; y++) {
memcpy(dst, src, dst_line_len);
src += src_line_len;
dst += dst_line_len;
}
}
/*
* Copyright (C) 2016 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __GOLDFISH_FORMATCONVERSIONS_H__
#define __GOLDFISH_FORMATCONVERSIONS_H__
#include <inttypes.h>
// format conversions and helper functions
void get_yv12_offsets(int width, int height,
uint32_t* yStride_out,
uint32_t* cStride_out,
uint32_t* totalSz_out);
void get_yuv420p_offsets(int width, int height,
uint32_t* yStride_out,
uint32_t* cStride_out,
uint32_t* totalSz_out);
signed clamp_rgb(signed value);
void rgb565_to_yv12(char* dest, char* src, int width, int height,
int left, int top, int right, int bottom);
void rgb888_to_yv12(char* dest, char* src, int width, int height,
int left, int top, int right, int bottom);
void rgb888_to_yuv420p(char* dest, char* src, int width, int height,
int left, int top, int right, int bottom);
void yv12_to_rgb565(char* dest, char* src, int width, int height,
int left, int top, int right, int bottom);
void yv12_to_rgb888(char* dest, char* src, int width, int height,
int left, int top, int right, int bottom);
void yuv420p_to_rgb888(char* dest, char* src, int width, int height,
int left, int top, int right, int bottom);
void copy_rgb_buffer_from_unlocked(char* _dst, char* raw_data,
int unlockedWidth,
int width, int height, int top, int left,
int bpp);
#endif
......@@ -1230,6 +1230,7 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EG
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_RGB_888:
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_YV12:
case HAL_PIXEL_FORMAT_BGRA_8888:
break;
default:
......
......@@ -21,6 +21,7 @@
#include <errno.h>
#include <dlfcn.h>
#include <sys/mman.h>
#include "FormatConversions.h"
#include "gralloc_cb.h"
#include "HostConnection.h"
#include "glUtils.h"
......@@ -243,6 +244,9 @@ static int gralloc_alloc(alloc_device_t* dev,
align = 16;
bpp = 1; // per-channel bpp
yuv_format = true;
// rgb2yuv in gralloc_lock(), yuv2rgb in gralloc_unlock()
glFormat = GL_RGB;
glType = GL_UNSIGNED_BYTE;
// Not expecting to actually create any GL surfaces for this
break;
default:
......@@ -614,12 +618,6 @@ static int gralloc_lock(gralloc_module_t const* module,
return -EINVAL;
}
// validate format
if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
ALOGE("gralloc_lock can't be used with YCbCr_420_888 format");
return -EINVAL;
}
// Validate usage,
// 1. cannot be locked for hw access
// 2. lock for either sw read or write.
......@@ -686,9 +684,26 @@ static int gralloc_lock(gralloc_module_t const* module,
}
if (sw_read) {
D("gralloc_lock read back color buffer %d %d\n", cb->width, cb->height);
void* rgb_addr = cpu_addr;
char* tmpBuf = 0;
if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12 ||
cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
// We are using RGB888
tmpBuf = new char[cb->width * cb->height * 3];
rgb_addr = tmpBuf;
}
D("gralloc_lock read back color buffer %d %d ashmem base %p sz %d\n",
cb->width, cb->height, cb->ashmemBase, cb->ashmemSize);
rcEnc->rcReadColorBuffer(rcEnc, cb->hostHandle,
0, 0, cb->width, cb->height, cb->glFormat, cb->glType, cpu_addr);
0, 0, cb->width, cb->height, cb->glFormat, cb->glType, rgb_addr);
if (tmpBuf) {
if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
rgb888_to_yv12((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
} else if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
rgb888_to_yuv420p((char*)cpu_addr, tmpBuf, cb->width, cb->height, l, t, l+w-1, t+h-1);
}
delete [] tmpBuf;
}
}
}
......@@ -715,6 +730,56 @@ static int gralloc_lock(gralloc_module_t const* module,
return 0;
}
static void updateHostColorBuffer(cb_handle_t* cb,
bool doLocked,
char* pixels) {
D("%s: call. doLocked=%d", __FUNCTION__, doLocked);
DEFINE_HOST_CONNECTION;
int bpp = glUtilsPixelBitSize(cb->glFormat, cb->glType) >> 3;
int left = doLocked ? cb->lockedLeft : 0;
int top = doLocked ? cb->lockedTop : 0;
int width = doLocked ? cb->lockedWidth : cb->width;
int height = doLocked ? cb->lockedHeight : cb->height;
char* to_send = pixels;
uint32_t rgbSz = width * height * bpp;
uint32_t send_buffer_size = rgbSz;
bool is_rgb_format =
cb->frameworkFormat != HAL_PIXEL_FORMAT_YV12 &&
cb->frameworkFormat != HAL_PIXEL_FORMAT_YCbCr_420_888;
char* convertedBuf = NULL;
if ((doLocked && is_rgb_format) ||
((doLocked || !is_rgb_format))) {
convertedBuf = new char[rgbSz];
to_send = convertedBuf;
send_buffer_size = rgbSz;
}
if (doLocked && is_rgb_format) {
copy_rgb_buffer_from_unlocked(
to_send, pixels,
cb->width,
width, height, top, left, bpp);
}
if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
yv12_to_rgb888(to_send, pixels,
width, height, left, top,
left + width - 1, top + height - 1);
}
if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
yuv420p_to_rgb888(to_send, pixels,
width, height, left, top,
left + width - 1, top + height - 1);
}
rcEnc->rcUpdateColorBuffer(rcEnc, cb->hostHandle,
left, top, width, height,
cb->glFormat, cb->glType, to_send);
if (convertedBuf) delete [] convertedBuf;
}
static int gralloc_unlock(gralloc_module_t const* module,
buffer_handle_t handle)
{
......@@ -736,43 +801,23 @@ static int gralloc_unlock(gralloc_module_t const* module,
// Make sure we have host connection
DEFINE_AND_VALIDATE_HOST_CONNECTION;
void *cpu_addr;
void *cpu_addr = nullptr;
if (cb->canBePosted()) {
cpu_addr = (void *)(cb->ashmemBase + sizeof(int));
}
else {
cpu_addr = (void *)(cb->ashmemBase + sizeof(intptr_t));
} else {
cpu_addr = (void *)(cb->ashmemBase);
}
char* rgb_addr = (char *)cpu_addr;
if (cb->lockedWidth < cb->width || cb->lockedHeight < cb->height) {
int bpp = glUtilsPixelBitSize(cb->glFormat, cb->glType) >> 3;
char *tmpBuf = new char[cb->lockedWidth * cb->lockedHeight * bpp];
int dst_line_len = cb->lockedWidth * bpp;
int src_line_len = cb->width * bpp;
char *src = (char *)cpu_addr + cb->lockedTop*src_line_len + cb->lockedLeft*bpp;
char *dst = tmpBuf;
for (int y=0; y<cb->lockedHeight; y++) {
memcpy(dst, src, dst_line_len);
src += src_line_len;
dst += dst_line_len;
}
rcEnc->rcUpdateColorBuffer(rcEnc, cb->hostHandle,
cb->lockedLeft, cb->lockedTop,
cb->lockedWidth, cb->lockedHeight,
cb->glFormat, cb->glType,
tmpBuf);
delete [] tmpBuf;
updateHostColorBuffer(cb, true, rgb_addr);
}
else {
rcEnc->rcUpdateColorBuffer(rcEnc, cb->hostHandle, 0, 0,
cb->width, cb->height,
cb->glFormat, cb->glType,
cpu_addr);
updateHostColorBuffer(cb, false, rgb_addr);
}
DD("gralloc_unlock success. cpu_addr: %p", cpu_addr);
}
cb->lockedWidth = cb->lockedHeight = 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册