blob: 3dde5b4fe75a7f5d2d57635945a582faf1f716aa [file] [log] [blame]
#include "JPEGDecoder.h"
#include "JPEGBlitter.h"
#include "JPEGCommon_Gen.h"
#include <utils/threads.h>
#include <utils/Timers.h>
#include <stdio.h>
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <assert.h>
#include <hardware/gralloc.h>
static char jpgfile[100];
RenderTarget& init_render_target_drm(RenderTarget &target, int width, int height, uint32_t fourcc, buffer_handle_t *handle)
{
hw_module_t const* module = NULL;
alloc_device_t *allocdev = NULL;
struct gralloc_module_t *gralloc_module = NULL;
int stride, bpp, err;
bpp = fourcc2LumaBitsPerPixel(fourcc);
err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
if (err || !module) {
printf("%s failed to get gralloc module\n", __PRETTY_FUNCTION__);
assert(false);
}
gralloc_module = (struct gralloc_module_t *)module;
err = gralloc_open(module, &allocdev);
if (err || !allocdev) {
printf("%s failed to open alloc device\n", __PRETTY_FUNCTION__);
assert(false);
}
err = allocdev->alloc(allocdev,
width,
height,
fourcc2PixelFormat(fourcc),
GRALLOC_USAGE_HW_RENDER,
handle,
&stride);
if (err) {
gralloc_close(allocdev);
printf("%s failed to allocate surface %d, %dx%d, pixelformat %x\n", __PRETTY_FUNCTION__, err,
width, height, fourcc2PixelFormat(fourcc));
assert(false);
}
unsigned long boname;
err = gralloc_module->perform(gralloc_module,
INTEL_UFO_GRALLOC_MODULE_PERFORM_GET_BO_NAME,
*handle,
&boname);
assert(!err);
target.type = RenderTarget::KERNEL_DRM;
target.handle = (int)boname;
switch(fourcc) {
case VA_FOURCC_NV12:
case VA_FOURCC_422H:
case VA_FOURCC_422V:
case VA_FOURCC_IMC3:
case VA_FOURCC_444P:
case VA_FOURCC_411P:
case VA_FOURCC('4','0','0','P'):
target.width = aligned_width(width, SURF_TILING_Y);
target.height = aligned_height(height, SURF_TILING_Y);
break;
default:
target.width = aligned_width(width, SURF_TILING_NONE);
target.height = aligned_height(height, SURF_TILING_NONE);
break;
}
target.format = fourcc2VaFormat(fourcc);
target.pixel_format = fourcc;
target.rect.x = target.rect.y = 0;
target.rect.width = width;
target.rect.height = height;
target.stride = stride * bpp;
gralloc_close(allocdev);
return target;
}
RenderTarget& init_render_target_gralloc(RenderTarget &target, int width, int height, uint32_t fourcc)
{
hw_module_t const* module = NULL;
alloc_device_t *allocdev = NULL;
struct gralloc_module_t *gralloc_module = NULL;
buffer_handle_t handle;
int stride, bpp, err;
bpp = fourcc2LumaBitsPerPixel(fourcc);
err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
if (err || !module) {
printf("%s failed to get gralloc module\n", __PRETTY_FUNCTION__);
assert(false);
}
gralloc_module = (struct gralloc_module_t *)module;
err = gralloc_open(module, &allocdev);
if (err || !allocdev) {
printf("%s failed to open alloc device\n", __PRETTY_FUNCTION__);
assert(false);
}
err = allocdev->alloc(allocdev,
width,
height,
fourcc2PixelFormat(fourcc),
GRALLOC_USAGE_HW_RENDER,
&handle,
&stride);
if (err) {
gralloc_close(allocdev);
printf("%s failed to allocate surface %d, %dx%d, pixelformat %x\n", __PRETTY_FUNCTION__, err,
width, height, fourcc2PixelFormat(fourcc));
assert(false);
}
target.type = RenderTarget::ANDROID_GRALLOC;
target.handle = (int)handle;
switch(fourcc) {
case VA_FOURCC_NV12:
case VA_FOURCC_YUY2:
case VA_FOURCC_UYVY:
case VA_FOURCC_422H:
case VA_FOURCC_422V:
case VA_FOURCC_IMC3:
case VA_FOURCC_444P:
case VA_FOURCC_411P:
case VA_FOURCC('4','0','0','P'):
target.width = aligned_width(width, SURF_TILING_Y);
target.height = aligned_height(height, SURF_TILING_Y);
break;
default:
target.width = aligned_width(width, SURF_TILING_NONE);
target.height = aligned_height(height, SURF_TILING_NONE);
break;
}
target.format = fourcc2VaFormat(fourcc);
target.pixel_format = fourcc;
target.rect.x = target.rect.y = 0;
target.rect.width = width;
target.rect.height = height;
target.stride = stride * bpp;
gralloc_close(allocdev);
return target;
}
RenderTarget& init_render_target_userptr(RenderTarget &target, int width, int height, uint32_t fourcc)
{
hw_module_t const* module = NULL;
alloc_device_t *allocdev = NULL;
static int surf_hnd = 0;
int stride, bpp, err;
void * userptr = NULL;
size_t mallocsize;
bpp = fourcc2LumaBitsPerPixel(fourcc);
target.type = RenderTarget::USER_PTR;
// all linear, no alignment
switch(fourcc) {
case VA_FOURCC_NV12:
mallocsize = width * height * 3 / 2;
break;
case VA_FOURCC_YUY2:
case VA_FOURCC_UYVY:
mallocsize = width * height * 2;
break;
case VA_FOURCC_422H:
mallocsize = width * height * 3;
break;
case VA_FOURCC_422V:
mallocsize = width * height * 2;
break;
case VA_FOURCC_IMC3:
mallocsize = width * height * 2;
break;
case VA_FOURCC_444P:
mallocsize = width * height * 3;
break;
case VA_FOURCC_411P:
mallocsize = width * height * 3;
break;
case VA_FOURCC_411R:
mallocsize = width * height * 3 / 2;
break;
case VA_FOURCC('4','0','0','P'):
mallocsize = width * height;
break;
case VA_FOURCC_RGBA:
case VA_FOURCC_BGRA:
mallocsize = width * height * 4;
break;
default:
mallocsize = width * height * 3;
break;
}
userptr = memalign(0x1000, mallocsize);
target.width = width;
target.height = height;
target.pixel_format = fourcc;
target.rect.x = target.rect.y = 0;
target.rect.width = target.width;
target.rect.height = target.height;
target.handle = (int)userptr;
//target.stride = stride * bpp;
return target;
}
RenderTarget& init_render_target(RenderTarget &target, int width, int height, uint32_t fourcc)
{
hw_module_t const* module = NULL;
alloc_device_t *allocdev = NULL;
static int surf_hnd = 0;
int stride, bpp, err;
bpp = fourcc2LumaBitsPerPixel(fourcc);
target.type = RenderTarget::INTERNAL_BUF;
target.handle = generateHandle();
switch(fourcc) {
case VA_FOURCC_NV12:
case VA_FOURCC_YUY2:
case VA_FOURCC_UYVY:
case VA_FOURCC_422H:
case VA_FOURCC_422V:
case VA_FOURCC_IMC3:
case VA_FOURCC_444P:
case VA_FOURCC_411P:
case VA_FOURCC('4','0','0','P'):
target.width = aligned_width(width, SURF_TILING_Y);
target.height = aligned_height(height, SURF_TILING_Y);
break;
default:
target.width = aligned_width(width, SURF_TILING_NONE);
target.height = aligned_height(height, SURF_TILING_NONE);
break;
}
target.pixel_format = fourcc;
target.rect.x = target.rect.y = 0;
target.rect.width = target.width;
target.rect.height = target.height;
//target.stride = stride * bpp;
return target;
}
void deinit_render_target(RenderTarget &target, buffer_handle_t *handle = NULL)
{
hw_module_t const* module = NULL;
alloc_device_t *allocdev = NULL;
struct gralloc_module_t *gralloc_module = NULL;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
if (err || !module) {
printf("%s failed to get gralloc module\n", __PRETTY_FUNCTION__);
return;
}
gralloc_module = (struct gralloc_module_t *)module;
err = gralloc_open(module, &allocdev);
if (err || !allocdev) {
printf("%s failed to get gralloc module\n", __PRETTY_FUNCTION__);
return;
}
if (handle && target.type == RenderTarget::KERNEL_DRM)
allocdev->free(allocdev, *handle);
else if (target.type == RenderTarget::ANDROID_GRALLOC)
allocdev->free(allocdev, (buffer_handle_t)target.handle);
else if (target.type == RenderTarget::USER_PTR)
free((void*)target.handle);
gralloc_close(allocdev);
}
void decode_blit_functionality_test(RenderTarget::bufType type, uint32_t format, int scale_factor)
{
JpegDecodeStatus st;
VAStatus vast;
JpegInfo jpginfo;
hw_module_t const* module = NULL;
alloc_device_t *allocdev = NULL;
struct gralloc_module_t *gralloc_module = NULL;
VAStatus vret;
char decdumpfile[100];
char origdecdumpfile[100];
char nv12dumpfile[100];
char nv21dumpfile[100];
char yuy2dumpfile[100];
char yv12dumpfile[100];
char rgbadumpfile[100];
FILE* fpdump = NULL;
memset(&jpginfo, 0, sizeof(JpegInfo));
memset(decdumpfile, 0, sizeof(decdumpfile));
memset(origdecdumpfile, 0, sizeof(origdecdumpfile));
memset(nv12dumpfile, 0, sizeof(nv12dumpfile));
memset(nv21dumpfile, 0, sizeof(nv21dumpfile));
memset(yuy2dumpfile, 0, sizeof(yuy2dumpfile));
memset(yv12dumpfile, 0, sizeof(yv12dumpfile));
memset(rgbadumpfile, 0, sizeof(rgbadumpfile));
VADisplay display = NULL;
VAConfigID vpCfgId = VA_INVALID_ID;
VAContextID vpCtxId = VA_INVALID_ID;
typedef uint32_t Display;
Display dpy;
int va_major_version, va_minor_version;
VAConfigAttrib vpp_attrib;
display = vaGetDisplay(&dpy);
vast = vaInitialize(display, &va_major_version, &va_minor_version);
assert(vast == VA_STATUS_SUCCESS);
vpp_attrib.type = VAConfigAttribRTFormat;
vpp_attrib.value = VA_RT_FORMAT_YUV420;
vast = vaCreateConfig(display, VAProfileNone,
VAEntrypointVideoProc,
&vpp_attrib,
1, &vpCfgId);
assert(vast == VA_STATUS_SUCCESS);
vast = vaCreateContext(display, vpCfgId, 1920, 1080, 0, NULL, 0, &vpCtxId);
assert(vast == VA_STATUS_SUCCESS);
JpegDecoder decoder(display, vpCfgId, vpCtxId, true);
RenderTarget dec_target;
buffer_handle_t dec_handle, nv12_handle, yuy2_handle;
uint8_t *nv12_mem, *yuy2_mem, *nv21_mem, *yv12_mem, *rgba_mem;
int stride;
FILE* fp = fopen(jpgfile, "rb");
assert(fp);
fseek(fp, 0, SEEK_END);
jpginfo.bufsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
jpginfo.buf = new uint8_t[jpginfo.bufsize];
fread(jpginfo.buf, 1, jpginfo.bufsize, fp);
fclose(fp);
printf("finished loading src file: size %u\n", jpginfo.bufsize);
jpginfo.need_header_only = false;
jpginfo.use_vector_input = false;
st = decoder.parse(jpginfo);
assert(st == JD_SUCCESS);
printf("parse succeeded: %ux%u\n", jpginfo.image_width, jpginfo.image_height);
if (format == 0)
format = jpginfo.image_color_fourcc;
char buftypename[100];
switch(type) {
case RenderTarget::KERNEL_DRM:
sprintf(buftypename, "DRM");
init_render_target_drm(dec_target, jpginfo.image_width, jpginfo.image_height, format, &dec_handle);
break;
case RenderTarget::ANDROID_GRALLOC:
sprintf(buftypename, "GRALLOC");
init_render_target_gralloc(dec_target, jpginfo.image_width, jpginfo.image_height, format);
break;
case RenderTarget::INTERNAL_BUF:
sprintf(buftypename, "DRIVER");
init_render_target(dec_target, jpginfo.image_width, jpginfo.image_height, format);
break;
default:
assert(0);
break;
}
uint32_t aligned_w = aligned_width(jpginfo.image_width, SURF_TILING_Y);
uint32_t aligned_h = aligned_height(jpginfo.image_height, SURF_TILING_Y);
uint32_t aligned_scaled_w = aligned_width(jpginfo.image_width / scale_factor, SURF_TILING_Y);
uint32_t aligned_scaled_h = aligned_width(jpginfo.image_height / scale_factor, SURF_TILING_Y);
int err;
err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
if (err || !module) {
printf("%s failed to get gralloc module\n", __PRETTY_FUNCTION__);
assert(false);
}
gralloc_module = (struct gralloc_module_t *)module;
err = gralloc_open(module, &allocdev);
if (err || !allocdev) {
printf("%s failed to open alloc device\n", __PRETTY_FUNCTION__);
assert(false);
}
err = allocdev->alloc(allocdev,
aligned_w,
aligned_h,
fourcc2PixelFormat(VA_FOURCC_NV12),
GRALLOC_USAGE_HW_RENDER,
&nv12_handle,
&stride);
if (err) {
printf("%s failed to allocate surface %d, %dx%d, pixelformat %x\n", __PRETTY_FUNCTION__, err,
aligned_w, aligned_h, fourcc2PixelFormat(VA_FOURCC_NV12));
assert(false);
}
err = allocdev->alloc(allocdev,
aligned_w,
aligned_h,
fourcc2PixelFormat(VA_FOURCC_YUY2),
GRALLOC_USAGE_HW_RENDER,
&yuy2_handle,
&stride);
if (err) {
printf("%s failed to allocate surface %d, %dx%d, pixelformat %x\n", __PRETTY_FUNCTION__, err,
aligned_w, aligned_h, fourcc2PixelFormat(VA_FOURCC_YUY2));
assert(false);
}
nv21_mem = (uint8_t*)memalign(0x1000, aligned_w * aligned_h * 3 / 2);
yv12_mem = (uint8_t*)memalign(0x1000, aligned_w * aligned_h * 3 / 2);
rgba_mem = (uint8_t*)memalign(0x1000, aligned_scaled_w * aligned_scaled_h * 4);
assert(nv21_mem && yv12_mem && rgba_mem);
sprintf(decdumpfile, "/sdcard/jpeg_%s_dec_%dx%d.%s", buftypename, jpginfo.image_width, jpginfo.image_height, fourcc2str(format));
sprintf(origdecdumpfile, "/sdcard/jpeg_%s_dec_orig_%dx%d.yuv", buftypename, aligned_w, aligned_h);
sprintf(nv12dumpfile, "/sdcard/jpeg_%s_out_%dx%d.nv12", buftypename, aligned_w, aligned_h);
sprintf(nv21dumpfile, "/sdcard/jpeg_%s_out_%dx%d.nv21", buftypename, aligned_w, aligned_h);
sprintf(yuy2dumpfile, "/sdcard/jpeg_%s_out_%dx%d.yuy2", buftypename, aligned_w, aligned_h);
sprintf(yv12dumpfile, "/sdcard/jpeg_%s_out_%dx%d.yv12", buftypename, aligned_w, aligned_h);
sprintf(rgbadumpfile, "/sdcard/jpeg_%s_out_%dx%d.rgba", buftypename, aligned_scaled_w, aligned_scaled_h);
RenderTarget* targetlist[1] = {&dec_target};
st = decoder.init(jpginfo.image_width, jpginfo.image_height, targetlist, 1);
assert(st == JD_SUCCESS);
st = decoder.decode(jpginfo, dec_target);
printf("decode returns %d\n", st);
assert(st == JD_SUCCESS);
uint8_t *data;
uint32_t offsets[3];
uint32_t pitches[3];
JpegDecoder::MapHandle maphandle = decoder.mapData(dec_target, (void**) &data, offsets, pitches);
assert (maphandle);
fpdump = fopen(decdumpfile, "wb");
assert(fpdump);
int hs, vs, nv12, yuy2, uyvy;
hs = vs = nv12 = yuy2 = uyvy = 0;
switch(format) {
case VA_FOURCC_NV12:
nv12 = 1;
break;
case VA_FOURCC_YUY2:
yuy2 = 1;
break;
case VA_FOURCC_UYVY:
uyvy = 1;
break;
case VA_FOURCC('4','0','0','P'):
hs = vs = 0;
break;
case VA_FOURCC_411P:
hs = 4;
vs = 1;
break;
case VA_FOURCC_411R:
hs = 1;
vs = 4;
break;
case VA_FOURCC_IMC3:
hs = 2;
vs = 2;
break;
case VA_FOURCC_422H:
hs = 2;
vs = 1;
break;
case VA_FOURCC_422V:
hs = 1;
vs = 2;
break;
case VA_FOURCC_444P:
hs = vs = 1;
break;
default:
printf("Invalid format %x\n", format);
assert(false);
break;
}
if (nv12) {
for (int i = 0; i < jpginfo.image_height; ++i) {
fwrite(data + offsets[0] + i * pitches[0], 1, jpginfo.image_width, fpdump);
}
for (int i = 0; i < jpginfo.image_height/2; ++i) {
fwrite(data + offsets[1] + i * pitches[1], 1, jpginfo.image_width, fpdump);
}
}
else if (yuy2 || uyvy) {
for (int i = 0; i < jpginfo.image_height; ++i) {
fwrite(data + offsets[0] + i * pitches[0], 2, jpginfo.image_width, fpdump);
}
}
else { // yuv planar
// Y
for (int i = 0; i < jpginfo.image_height; ++i) {
fwrite(data + offsets[0] + i * pitches[0], 1, jpginfo.image_width, fpdump);
}
if (hs != 0 && vs != 0) {
// U
for (int i = 0; i < jpginfo.image_height / vs; ++i) {
fwrite(data + offsets[1] + i * pitches[1], 1, jpginfo.image_width/hs, fpdump);
}
// V
for (int i = 0; i < jpginfo.image_height / vs; ++i) {
fwrite(data + offsets[2] + i * pitches[2], 1, jpginfo.image_width/hs, fpdump);
}
}
}
fclose(fpdump);
printf("Dumped decoded YUV to %s\n", decdumpfile);
decoder.unmapData(dec_target, maphandle);
BlitEvent ev;
st = decoder.blitToLinearRgba(dec_target, rgba_mem, aligned_w, aligned_h, ev, scale_factor);
assert(st == JD_SUCCESS);
decoder.syncBlit(ev);
fpdump = fopen(rgbadumpfile, "wb");
assert(fpdump);
fwrite(rgba_mem, 4, aligned_scaled_w * aligned_scaled_h, fpdump);
fclose(fpdump);
printf("Dumped RGBA into %s\n", rgbadumpfile);
// test blit_to_camera_surfaces
if (format == VA_FOURCC_422H) {
RenderTarget nv12_dst, yuy2_dst;
nsecs_t t1, t2;
init_render_target_gralloc(nv12_dst, aligned_w, aligned_h, VA_FOURCC_NV12);
init_render_target_gralloc(yuy2_dst, aligned_w, aligned_h, VA_FOURCC_YUY2);
t1 = systemTime();
st = decoder.blit(dec_target, nv12_dst, 1);
st = decoder.blit(dec_target, yuy2_dst, 1);
t2 = systemTime();
printf("422H->NV12+YUY2 VA took %.2f ms\n", (t2-t1)/1000000.0);
deinit_render_target(nv12_dst);
deinit_render_target(yuy2_dst);
t1 = systemTime();
st = decoder.blitToCameraSurfaces(dec_target, nv12_handle, yuy2_handle,
NULL, NULL,
aligned_w, aligned_h,
ev);
t2 = systemTime();
decoder.syncBlit(ev);
printf("422H->NV12+YUY2 CM took %.2f ms\n", (t2-t1)/1000000.0);
t1 = systemTime();
st = decoder.blitToCameraSurfaces(dec_target, nv12_handle, yuy2_handle,
nv21_mem, yv12_mem,
aligned_w, aligned_h,
ev);
t2 = systemTime();
decoder.syncBlit(ev);
printf("422H->NV12+YUY2+NV21+YV12 CM took %.2f ms\n", (t2-t1)/1000000.0);
assert(st == JD_SUCCESS);
fpdump = fopen(nv21dumpfile, "wb");
assert(fpdump);
fwrite(nv21_mem, 1, aligned_w * aligned_h* 3 /2, fpdump);
fclose(fpdump);
printf("Dumped NV21 into %s\n", nv21dumpfile);
fpdump = fopen(yv12dumpfile, "wb");
assert(fpdump);
fwrite(yv12_mem, 1, aligned_w * aligned_h * 3 / 2, fpdump);
fclose(fpdump);
printf("Dumped YV12 into %s\n", yv12dumpfile);
gralloc_module->lock(gralloc_module, nv12_handle, GRALLOC_USAGE_SW_READ_OFTEN, 0, 0, aligned_w, aligned_h, (void**)&nv12_mem);
fpdump = fopen(nv12dumpfile, "wb");
assert(fpdump);
fwrite(nv12_mem, 1, aligned_w * aligned_h * 3 / 2, fpdump);
fclose(fpdump);
gralloc_module->unlock(gralloc_module, nv12_handle);
printf("Dumped NV12 into %s\n", nv12dumpfile);
gralloc_module->lock(gralloc_module, yuy2_handle, GRALLOC_USAGE_SW_READ_OFTEN, 0, 0, aligned_w, aligned_h, (void**)&yuy2_mem);
fpdump = fopen(yuy2dumpfile, "wb");
assert(fpdump);
fwrite(yuy2_mem, 2, aligned_w * aligned_h, fpdump);
fclose(fpdump);
gralloc_module->unlock(gralloc_module, yuy2_handle);
printf("Dumped YUY2 into %s\n", yuy2dumpfile);
}
decoder.deinit();
allocdev->free(allocdev, nv12_handle);
allocdev->free(allocdev, yuy2_handle);
free(nv21_mem);
free(yv12_mem);
free(rgba_mem);
switch(type) {
case RenderTarget::KERNEL_DRM:
deinit_render_target(dec_target, &dec_handle);
break;
default:
deinit_render_target(dec_target);
break;
}
delete[] jpginfo.buf;
gralloc_close(allocdev);
vaDestroyContext(display, vpCtxId);
vaDestroyConfig(display, vpCfgId);
vaTerminate(display);
}
int main(int argc, char ** argv)
{
int res, scale;
uint32_t format = 0;
scale = 1;
memset(jpgfile, 0, sizeof(jpgfile));
while ((res = getopt(argc, argv, "i:f:s:")) >= 0) {
switch (res) {
case 'i':
{
strcpy(jpgfile, optarg);
break;
}
case 's':
{
scale = atoi(optarg);
break;
}
case 'f':
{
if (strcmp(optarg, "NV12") == 0) {
format = VA_FOURCC_NV12;
}
else if (strcmp(optarg, "YUY2") == 0) {
format = VA_FOURCC_YUY2;
}
else if (strcmp(optarg, "UYVY") == 0) {
format = VA_FOURCC_UYVY;
}
else {
format = 0;
printf("INVALID output decode format, using YUV planar\n");
}
break;
}
default:
printf("usage: testjpegdec -i <filename> [-w <width> -h <height>]\n");
exit(-1);
}
}
if (strcmp(jpgfile, "") == 0) {
printf("usage: testjpegdec -i <filename> [-f <decode output format FOURCC>] [-s <scaling_factor>]\n");
printf(" available output FOURCC: NV12, YUY2, UYVY, 0. 0 by default (YUV planar)\n");
printf(" available scaling_factor: 1, 2, 4, 8. 1 by default (no down-scale)\n");
exit(-1);
}
printf("----- DRM surface type test -----\n");
//decode_blit_functionality_test(RenderTarget::KERNEL_DRM, 0);
printf("----- GRALLOC surface type test -----\n");
//decode_blit_functionality_test(RenderTarget::ANDROID_GRALLOC, 0);
printf("----- Normal surface type test, scale %d-----\n", scale);
decode_blit_functionality_test(RenderTarget::INTERNAL_BUF, format, scale);
printf("----- Userptr surface type test -----\n");
//decode_blit_functionality_test(RenderTarget::USER_PTR, format);
return 0;
}