blob: b1167d3079056232af2c107fb627dc18bac295bb [file] [log] [blame]
/* INTEL CONFIDENTIAL
* Copyright (c) 2013 Intel Corporation. All rights reserved.
* Copyright (c) Imagination Technologies Limited, UK
*
* The source code contained or described herein and all documents
* related to the source code ("Material") are owned by Intel
* Corporation or its suppliers or licensors. Title to the
* Material remains with Intel Corporation or its suppliers and
* licensors. The Material contains trade secrets and proprietary
* and confidential information of Intel or its suppliers and
* licensors. The Material is protected by worldwide copyright and
* trade secret laws and treaty provisions. No part of the Material
* may be used, copied, reproduced, modified, published, uploaded,
* posted, transmitted, distributed, or disclosed in any way without
* Intel's prior express written permission.
*
* No license under any patent, copyright, trade secret or other
* intellectual property right is granted to or conferred upon you
* by disclosure or delivery of the Materials, either expressly, by
* implication, inducement, estoppel or otherwise. Any license
* under such intellectual property rights must be express and
* approved by Intel in writing.
*
* Authors:
* Yao Cheng <yao.cheng@intel.com>
*
*/
//#define LOG_NDEBUG 0
#include "JPEGBlitter.h"
#include "JPEGCommon_Gen.h"
#include "JPEGDecoder.h"
#include <va/va.h>
#include <va/va_tpi.h>
#include "ImageDecoderTrace.h"
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <assert.h>
#define JD_CHECK(err, label) \
if (err) { \
ETRACE("%s::%d: failed: %d", __PRETTY_FUNCTION__, __LINE__, err); \
goto label; \
}
#define JD_CHECK_RET(err, label, retcode) \
if (err) { \
status = retcode; \
ETRACE("%s::%d: failed: %d", __PRETTY_FUNCTION__, __LINE__, err); \
goto label; \
}
const VAProcColorStandardType fourcc2ColorStandard(uint32_t fourcc)
{
switch(fourcc) {
case VA_FOURCC_NV12:
case VA_FOURCC_YUY2:
case VA_FOURCC_422H:
case VA_FOURCC_422V:
case VA_FOURCC_411P:
case VA_FOURCC_411R:
case VA_FOURCC_IMC3:
case VA_FOURCC_444P:
case VA_FOURCC_YV12:
return VAProcColorStandardBT601;
default:
return VAProcColorStandardNone;
}
}
void write_to_file(const char *file, const VAImage *pImg, const uint8_t *pSrc)
{
FILE *fp = fopen(file, "wb");
if (!fp) {
return;
}
const uint8_t *pY, *pU, *pV, *pYUYV, *pRGBA, *pUV;
float h_samp_factor, v_samp_factor;
int row, col;
char fourccstr[5];
VTRACE("Dumping %s buffer to %s", fourcc2str(fourccstr, pImg->format.fourcc), file);
switch (pImg->format.fourcc) {
case VA_FOURCC_IMC3:
h_samp_factor = 1;
v_samp_factor = 0.5;
break;
case VA_FOURCC_422H:
h_samp_factor = 0.5;
v_samp_factor = 1;
break;
case VA_FOURCC_444P:
h_samp_factor = 1;
v_samp_factor = 1;
break;
case VA_FOURCC_YUY2:
{
pYUYV = pSrc + pImg->offsets[0];
VTRACE("YUY2 output width %u stride %u", pImg->width, pImg->pitches[0]);
for (row = 0; row < pImg->height; ++row) {
fwrite(pYUYV, 2, pImg->width, fp);
pYUYV += pImg->pitches[0];
}
}
fclose(fp);
return;
case VA_FOURCC_NV12:
{
pY = pSrc + pImg->offsets[0];
pUV = pSrc + pImg->offsets[1];
VTRACE("NV12 output width %u stride %u, %u", pImg->width, pImg->pitches[0], pImg->pitches[1]);
for (row = 0; row < pImg->height; ++row) {
fwrite(pY, 1, pImg->width, fp);
pY += pImg->pitches[0];
}
for (row = 0; row < pImg->height/2; ++row) {
fwrite(pUV, 1, pImg->width, fp);
pUV += pImg->pitches[1];
}
}
fclose(fp);
return;
case VA_FOURCC_RGBA:
case VA_FOURCC_BGRA:
case VA_FOURCC_ARGB:
case VA_FOURCC('A', 'B', 'G', 'R'):
{
pRGBA = pSrc + pImg->offsets[0];
VTRACE("RGBA output width %u stride %u", pImg->width, pImg->pitches[0]);
for (row = 0; row < pImg->height; ++row) {
fwrite(pRGBA, 4, pImg->width, fp);
pRGBA += pImg->pitches[0];
}
}
fclose(fp);
return;
default:
// non-supported
{
char fourccstr[5];
ETRACE("%s: Not-supported input YUV format", fourcc2str(fourccstr, pImg->format.fourcc));
}
return;
}
pY = pSrc + pImg->offsets[0];
pU = pSrc + pImg->offsets[1];
pV = pSrc + pImg->offsets[2];
// Y
for (row = 0; row < pImg->height; ++row) {
fwrite(pY, 1, pImg->width, fp);
pY += pImg->pitches[0];
}
// U
for (row = 0; row < pImg->height * v_samp_factor; ++row) {
fwrite(pU, 1, pImg->width * h_samp_factor, fp);
pU += pImg->pitches[1];
}
// V
for (row = 0; row < pImg->height * v_samp_factor; ++row) {
fwrite(pV, 1, pImg->width * h_samp_factor, fp);
pV += pImg->pitches[2];
}
fclose(fp);
}
static void write_to_YUY2(uint8_t *pDst,
uint32_t dst_w,
uint32_t dst_h,
uint32_t dst_stride,
const VAImage *pImg,
const uint8_t *pSrc)
{
const uint8_t *pY, *pU, *pV;
float h_samp_factor, v_samp_factor;
int row, col;
char fourccstr[5];
uint32_t copy_w = (dst_w < pImg->width)? dst_w: pImg->width;
uint32_t copy_h = (dst_h < pImg->height)? dst_h: pImg->height;
switch (pImg->format.fourcc) {
case VA_FOURCC_IMC3:
h_samp_factor = 0.5;
v_samp_factor = 0.5;
break;
case VA_FOURCC_422H:
h_samp_factor = 0.5;
v_samp_factor = 1;
break;
case VA_FOURCC_444P:
h_samp_factor = 1;
v_samp_factor = 1;
break;
default:
// non-supported
ETRACE("%s to YUY2: Not-supported input YUV format", fourcc2str(fourccstr, pImg->format.fourcc));
return;
}
pY = pSrc + pImg->offsets[0];
pU = pSrc + pImg->offsets[1];
pV = pSrc + pImg->offsets[2];
for (row = 0; row < copy_h; ++row) {
for (col = 0; col < copy_w; ++col) {
// Y
*(pDst + 2 * col) = *(pY + col);
uint32_t actual_col = h_samp_factor * col;
if (col % 2 == 1) {
// U
*(pDst + 2 * col + 1) = *(pU + actual_col);
}
else {
// V
*(pDst + 2 * col + 1) = *(pV + actual_col);
}
}
pDst += dst_stride;
pY += pImg->pitches[0];
uint32_t actual_row = row * v_samp_factor;
pU = pSrc + pImg->offsets[1] + actual_row * pImg->pitches[1];
pV = pSrc + pImg->offsets[2] + actual_row * pImg->pitches[2];
}
}
static void dumpSurface(const char* filename, VADisplay display, VASurfaceID surface)
{
VAStatus st;
VAImage img;
uint8_t *buf;
st = vaDeriveImage(display, surface, &img);
if (st) {
ETRACE("vaDeriveImage failed with %d", st);
return;
}
uint32_t in_fourcc = img.format.fourcc;
VTRACE("Start dumping %s surface to %s", fourcc2str(NULL, in_fourcc), filename);
st = vaMapBuffer(display, img.buf, (void **)&buf);
if (st) {
ETRACE("vaMapBuffer failed with %d", st);
vaDestroyImage(display, img.image_id);
return;
}
VTRACE("start write_to_file");
write_to_file(filename, &img, buf);
vaUnmapBuffer(display, img.buf);
vaDestroyImage(display, img.image_id);
}
static void dumpGallocBuffer(const char* filename,
buffer_handle_t handle,
int width,
int height,
uint32_t fourcc)
{
// NOT IMPLEMENTED
}
static JpegDecodeStatus swBlit(VADisplay display, VAContextID context,
VASurfaceID in_surf, VARectangle *in_rect, uint32_t in_fourcc,
VASurfaceID out_surf, VARectangle *out_rect, uint32_t out_fourcc)
{
assert(out_fourcc == VA_FOURCC_YUY2);
assert((in_fourcc == VA_FOURCC_IMC3) || (in_fourcc == VA_FOURCC_422H) || (in_fourcc == VA_FOURCC_444P));
VAStatus st;
char str[10];
JpegDecodeStatus status;
VAImage in_img, out_img;
in_img.image_id = VA_INVALID_ID;
in_img.buf = VA_INVALID_ID;
out_img.image_id = VA_INVALID_ID;
out_img.buf = VA_INVALID_ID;
uint8_t *in_buf, *out_buf;
in_buf = out_buf = NULL;
st = vaDeriveImage(display, in_surf, &in_img);
JD_CHECK_RET(st, cleanup, JD_BLIT_FAILURE);
st = vaDeriveImage(display, out_surf, &out_img);
JD_CHECK_RET(st, cleanup, JD_BLIT_FAILURE);
st = vaMapBuffer(display, in_img.buf, (void **)&in_buf);
JD_CHECK_RET(st, cleanup, JD_BLIT_FAILURE);
st = vaMapBuffer(display, out_img.buf, (void **)&out_buf);
JD_CHECK_RET(st, cleanup, JD_BLIT_FAILURE);
VTRACE("%s in: %s, %ux%u, size %u, offset=%u,%u,%u, pitch=%u,%u,%u", __FUNCTION__,
fourcc2str(NULL, in_fourcc),
in_img.width,
in_img.height,
in_img.data_size,
in_img.offsets[0], in_img.offsets[1], in_img.offsets[2],
in_img.pitches[0], in_img.pitches[1], in_img.pitches[2]);
VTRACE("%s out: %s, %ux%u, size %u, offset=%u,%u,%u, pitch=%u,%u,%u", __FUNCTION__,
fourcc2str(NULL, out_fourcc),
out_img.width,
out_img.height,
out_img.data_size,
out_img.offsets[0], out_img.offsets[1], out_img.offsets[2],
out_img.pitches[0], out_img.pitches[1], out_img.pitches[2]);
write_to_YUY2(out_buf, out_img.width, out_img.height, out_img.pitches[0], &in_img, in_buf);
vaUnmapBuffer(display, in_img.buf);
vaUnmapBuffer(display, out_img.buf);
vaDestroyImage(display, in_img.image_id);
vaDestroyImage(display, out_img.image_id);
VTRACE("%s Finished SW CSC %s=>%s", __FUNCTION__, fourcc2str(str, in_fourcc), fourcc2str(str + 5, out_fourcc));
return JD_SUCCESS;
cleanup:
ETRACE("%s failed to do swBlit %s=>%s", __FUNCTION__, fourcc2str(str, in_fourcc), fourcc2str(str + 5, out_fourcc));
if (in_buf != NULL) vaUnmapBuffer(display, in_img.buf);
if (out_buf != NULL) vaUnmapBuffer(display, out_img.buf);
if (in_img.image_id != VA_INVALID_ID) vaDestroyImage(display, in_img.image_id);
if (out_img.image_id != VA_INVALID_ID) vaDestroyImage(display, out_img.image_id);
return status;
}
static JpegDecodeStatus hwBlit(VADisplay display, VAContextID context,
VASurfaceID in_surf, VARectangle *in_rect, uint32_t in_fourcc,
VASurfaceID out_surf, VARectangle *out_rect, uint32_t out_fourcc)
{
VAProcPipelineCaps vpp_pipeline_cap ;
VABufferID vpp_pipeline_buf = VA_INVALID_ID;
VAProcPipelineParameterBuffer vpp_param;
VAStatus vpp_status;
JpegDecodeStatus status = JD_SUCCESS;
char str[10];
nsecs_t t1, t2;
memset(&vpp_param, 0, sizeof(VAProcPipelineParameterBuffer));
#if PRE_TOUCH_SURFACE
//zeroSurfaces(display, &out_surf, 1);
#endif
t1 = systemTime();
vpp_param.surface = in_surf;
vpp_param.output_region = out_rect;
vpp_param.surface_region = in_rect;
vpp_param.surface_color_standard = fourcc2ColorStandard(in_fourcc);
vpp_param.output_background_color = 0;
vpp_param.output_color_standard = fourcc2ColorStandard(out_fourcc);
vpp_param.filter_flags = VA_FRAME_PICTURE;
vpp_param.filters = NULL;
vpp_param.num_filters = 0;
vpp_param.forward_references = 0;
vpp_param.num_forward_references = 0;
vpp_param.backward_references = 0;
vpp_param.num_backward_references = 0;
vpp_param.blend_state = NULL;
vpp_param.rotation_state = VA_ROTATION_NONE;
vpp_status = vaCreateBuffer(display,
context,
VAProcPipelineParameterBufferType,
sizeof(VAProcPipelineParameterBuffer),
1,
&vpp_param,
&vpp_pipeline_buf);
JD_CHECK_RET(vpp_status, cleanup, JD_RESOURCE_FAILURE);
vpp_status = vaBeginPicture(display,
context,
out_surf);
JD_CHECK_RET(vpp_status, cleanup, JD_BLIT_FAILURE);
//Render the picture
vpp_status = vaRenderPicture(display,
context,
&vpp_pipeline_buf,
1);
JD_CHECK_RET(vpp_status, cleanup, JD_BLIT_FAILURE);
vpp_status = vaEndPicture(display, context);
JD_CHECK_RET(vpp_status, cleanup, JD_BLIT_FAILURE);
vaDestroyBuffer(display, vpp_pipeline_buf);
JD_CHECK_RET(vpp_status, cleanup, JD_BLIT_FAILURE);
t2 = systemTime();
VTRACE("Finished HW CSC %s(%d,%d,%u,%u)=>%s(%d,%d,%u,%u) for %f ms",
fourcc2str(str, in_fourcc),
in_rect->x, in_rect->y, in_rect->width, in_rect->height,
fourcc2str(str + 5, out_fourcc),
out_rect->x, out_rect->y, out_rect->width, out_rect->height,
ns2us(t2 - t1)/1000.0);
return JD_SUCCESS;
cleanup:
if (vpp_pipeline_buf != VA_INVALID_ID)
vaDestroyBuffer(display, vpp_pipeline_buf);
return status;
}
static JpegDecodeStatus vaBlit(VADisplay display, VAContextID context,
VASurfaceID in_surf, VARectangle *in_rect, uint32_t in_fourcc,
VASurfaceID out_surf, VARectangle *out_rect, uint32_t out_fourcc)
{
if (((in_fourcc == VA_FOURCC_422H) ||
(in_fourcc == VA_FOURCC_NV12) ||
(in_fourcc == VA_FOURCC_YUY2) ||
(in_fourcc == VA_FOURCC_YV12) ||
(in_fourcc == VA_FOURCC_RGBA))
&&
((out_fourcc == VA_FOURCC_422H) ||
(out_fourcc == VA_FOURCC_NV12) ||
(out_fourcc == VA_FOURCC_YV12) ||
(out_fourcc == VA_FOURCC_YUY2) ||
(out_fourcc == VA_FOURCC_RGBA))) {
return hwBlit(display, context, in_surf, in_rect, in_fourcc,
out_surf, out_rect, out_fourcc);
}
else {
return swBlit(display, context, in_surf, in_rect, in_fourcc,
out_surf, out_rect, out_fourcc);
}
}
JpegDecodeStatus JpegBlitter::blit(RenderTarget &src, RenderTarget &dst)
{
if (mDecoder == NULL)
return JD_UNINITIALIZED;
JpegDecodeStatus st;
uint32_t src_fourcc, dst_fourcc;
char tmp[10];
src_fourcc = pixelFormat2Fourcc(src.pixel_format);
dst_fourcc = pixelFormat2Fourcc(dst.pixel_format);
VASurfaceID src_surf = mDecoder->getSurfaceID(src);
if (src_surf == VA_INVALID_ID) {
ETRACE("%s invalid src %s target", __FUNCTION__, fourcc2str(NULL, src_fourcc));
return JD_INVALID_RENDER_TARGET;
}
VASurfaceID dst_surf = mDecoder->getSurfaceID(dst);
if (dst_surf == VA_INVALID_ID) {
WTRACE("%s foreign dst target for JpegDecoder, create surface for it, not guaranteed to free it!!!", __FUNCTION__);
st = mDecoder->createSurfaceFromRenderTarget(dst, &dst_surf);
if (st != JD_SUCCESS || dst_surf == VA_INVALID_ID) {
ETRACE("%s failed to create surface for dst target", __FUNCTION__);
return JD_RESOURCE_FAILURE;
}
}
VTRACE("%s blitting from %s to %s", __FUNCTION__, fourcc2str(tmp, src_fourcc), fourcc2str(tmp + 5, dst_fourcc));
st = vaBlit(mDecoder->mDisplay, mContextId, src_surf, &src.rect, src_fourcc,
dst_surf, &dst.rect, dst_fourcc);
return st;
}