blob: 5e05464b85a614333d3de5679d81b14e6b983e25 [file] [log] [blame]
/* INTEL CONFIDENTIAL
* Copyright (c) 2012, 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:
* Nana Guo <nana.n.guo@intel.com>
* Yao Cheng <yao.cheng@intel.com>
*
*/
//#define LOG_NDEBUG 0
#include <va/va.h>
#include <va/va_tpi.h>
#include "JPEGDecoder.h"
#include "JPEGParser.h"
#include "JPEGBlitter.h"
#include "ImageDecoderTrace.h"
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <assert.h>
//#define LOG_TAG "ImageDecoder"
#define JPEG_MAX_SETS_HUFFMAN_TABLES 2
#define TABLE_CLASS_DC 0
#define TABLE_CLASS_AC 1
#define TABLE_CLASS_NUM 2
// for config
#define HW_DECODE_MIN_WIDTH 100 // for JPEG smaller than this, use SW decode
#define HW_DECODE_MIN_HEIGHT 100 // for JPEG smaller than this, use SW decode
typedef uint32_t Display;
#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; \
}
JpegDecoder::JpegDecoder()
:mInitialized(false),
mDisplay(0),
mConfigId(VA_INVALID_ID),
mContextId(VA_INVALID_ID),
mParser(NULL),
mBlitter(NULL)
{
mParser = new CJPEGParse;
mBlitter = new JpegBlitter;
Display dpy;
int va_major_version, va_minor_version;
mDisplay = vaGetDisplay(&dpy);
vaInitialize(mDisplay, &va_major_version, &va_minor_version);
}
JpegDecoder::~JpegDecoder()
{
if (mInitialized) {
WTRACE("Freeing JpegDecoder: not destroyed yet. Force destroy resource");
deinit();
}
delete mBlitter;
vaTerminate(mDisplay);
delete mParser;
}
JpegDecoder::MapHandle JpegDecoder::mapData(RenderTarget &target, void ** data, uint32_t * offsets, uint32_t * pitches)
{
JpegDecoder::MapHandle handle;
handle.img = NULL;
handle.valid = false;
VASurfaceID surf_id = getSurfaceID(target);
if (surf_id != VA_INVALID_ID) {
handle.img = new VAImage();
if (handle.img == NULL) {
ETRACE("%s: create VAImage fail", __FUNCTION__);
return handle;
}
VAStatus st;
st = vaDeriveImage(mDisplay, surf_id, handle.img);
if (st != VA_STATUS_SUCCESS) {
delete handle.img;
handle.img = NULL;
ETRACE("%s: vaDeriveImage fail %d", __FUNCTION__, st);
return handle;
}
st = vaMapBuffer(mDisplay, handle.img->buf, data);
if (st != VA_STATUS_SUCCESS) {
vaDestroyImage(mDisplay, handle.img->image_id);
delete handle.img;
handle.img = NULL;
ETRACE("%s: vaMapBuffer fail %d", __FUNCTION__, st);
return handle;
}
handle.valid = true;
offsets[0] = handle.img->offsets[0];
offsets[1] = handle.img->offsets[1];
offsets[2] = handle.img->offsets[2];
pitches[0] = handle.img->pitches[0];
pitches[1] = handle.img->pitches[1];
pitches[2] = handle.img->pitches[2];
return handle;
}
ETRACE("%s: get Surface ID fail", __FUNCTION__);
return handle;
}
void JpegDecoder::unmapData(RenderTarget &target, JpegDecoder::MapHandle maphandle)
{
if (maphandle.valid == false)
return;
if (maphandle.img != NULL) {
vaUnmapBuffer(mDisplay, maphandle.img->buf);
vaDestroyImage(mDisplay, maphandle.img->image_id);
delete maphandle.img;
}
}
JpegDecodeStatus JpegDecoder::init(int w, int h, RenderTarget **targets, int num)
{
if (mInitialized)
return JD_ALREADY_INITIALIZED;
Mutex::Autolock autoLock(mLock);
mBlitter->setDecoder(*this);
if (!mInitialized) {
mGrallocSurfaceMap.clear();
mDrmSurfaceMap.clear();
mNormalSurfaceMap.clear();
VAStatus st;
VASurfaceID surfid;
for (int i = 0; i < num; ++i) {
JpegDecodeStatus st = createSurfaceFromRenderTarget(*targets[i], &surfid);
if (st != JD_SUCCESS || surfid == VA_INVALID_ID) {
ETRACE("%s failed to create surface from RenderTarget handle 0x%x",
__FUNCTION__, targets[i]->handle);
return JD_RESOURCE_FAILURE;
}
}
VAConfigAttrib attrib;
attrib.type = VAConfigAttribRTFormat;
st = vaGetConfigAttributes(mDisplay, VAProfileJPEGBaseline, VAEntrypointVLD, &attrib, 1);
if (st != VA_STATUS_SUCCESS) {
ETRACE("vaGetConfigAttributes failed. va_status = 0x%x", st);
return JD_INITIALIZATION_ERROR;
}
st = vaCreateConfig(mDisplay, VAProfileJPEGBaseline, VAEntrypointVLD, &attrib, 1, &mConfigId);
if (st != VA_STATUS_SUCCESS) {
ETRACE("vaCreateConfig failed. va_status = 0x%x", st);
return JD_INITIALIZATION_ERROR;
}
mContextId = VA_INVALID_ID;
size_t gmsize = mGrallocSurfaceMap.size();
size_t dmsize = mDrmSurfaceMap.size();
size_t nmsize = mNormalSurfaceMap.size();
VASurfaceID *surfaces = new VASurfaceID[gmsize + dmsize + nmsize];
for (size_t i = 0; i < gmsize + dmsize + nmsize; ++i) {
if (i < gmsize)
surfaces[i] = mGrallocSurfaceMap.valueAt(i);
else if (i < gmsize + dmsize)
surfaces[i] = mDrmSurfaceMap.valueAt(i - gmsize);
else
surfaces[i] = mNormalSurfaceMap.valueAt(i - gmsize - dmsize);
}
st = vaCreateContext(mDisplay, mConfigId,
w, h,
0,
surfaces, gmsize + dmsize + nmsize,
&mContextId);
delete[] surfaces;
if (st != VA_STATUS_SUCCESS) {
ETRACE("vaCreateContext failed. va_status = 0x%x", st);
return JD_INITIALIZATION_ERROR;
}
VTRACE("vaconfig = %u, vacontext = %u", mConfigId, mContextId);
mInitialized = true;
}
return JD_SUCCESS;
}
JpegDecodeStatus JpegDecoder::blit(RenderTarget &src, RenderTarget &dst)
{
return mBlitter->blit(src, dst);
}
JpegDecodeStatus JpegDecoder::parse(JpegInfo &jpginfo)
{
uint32_t component_order = 0 ;
uint32_t dqt_ind = 0;
uint32_t dht_ind = 0;
uint32_t scan_ind = 0;
bool frame_marker_found = false;
int i;
parserInitialize(mParser, jpginfo.buf, jpginfo.bufsize);
uint8_t marker = mParser->getNextMarker(mParser);
while (marker != CODE_EOI &&( !mParser->endOfBuffer(mParser))) {
switch (marker) {
case CODE_SOI: {
jpginfo.soi_offset = mParser->getByteOffset(mParser) - 2;
break;
}
// If the marker is an APP marker skip over the data
case CODE_APP0:
case CODE_APP1:
case CODE_APP2:
case CODE_APP3:
case CODE_APP4:
case CODE_APP5:
case CODE_APP6:
case CODE_APP7:
case CODE_APP8:
case CODE_APP9:
case CODE_APP10:
case CODE_APP11:
case CODE_APP12:
case CODE_APP13:
case CODE_APP14:
case CODE_APP15: {
uint32_t bytes_to_burn = mParser->readBytes(mParser, 2) - 2;
mParser->burnBytes(mParser, bytes_to_burn);
break;
}
// Store offset to DQT data to avoid parsing bitstream in user mode
case CODE_DQT: {
if (dqt_ind < 4) {
jpginfo.dqt_byte_offset[dqt_ind] = mParser->getByteOffset(mParser) - jpginfo.soi_offset;
dqt_ind++;
uint32_t bytes_to_burn = mParser->readBytes(mParser, 2 ) - 2;
mParser->burnBytes( mParser, bytes_to_burn );
} else {
ETRACE("ERROR: Decoder does not support more than 4 Quant Tables\n");
return JD_ERROR_BITSTREAM;
}
break;
}
// Throw exception for all SOF marker other than SOF0
case CODE_SOF1:
case CODE_SOF2:
case CODE_SOF3:
case CODE_SOF5:
case CODE_SOF6:
case CODE_SOF7:
case CODE_SOF8:
case CODE_SOF9:
case CODE_SOF10:
case CODE_SOF11:
case CODE_SOF13:
case CODE_SOF14:
case CODE_SOF15: {
ETRACE("ERROR: unsupport SOF\n");
break;
}
// Parse component information in SOF marker
case CODE_SOF_BASELINE: {
frame_marker_found = true;
mParser->burnBytes(mParser, 2); // Throw away frame header length
uint8_t sample_precision = mParser->readNextByte(mParser);
if (sample_precision != 8) {
ETRACE("sample_precision is not supported\n");
return JD_ERROR_BITSTREAM;
}
// Extract pic width and height
jpginfo.picture_param_buf.picture_height = mParser->readBytes(mParser, 2);
jpginfo.picture_param_buf.picture_width = mParser->readBytes(mParser, 2);
jpginfo.picture_param_buf.num_components = mParser->readNextByte(mParser);
if (jpginfo.picture_param_buf.num_components > JPEG_MAX_COMPONENTS) {
ETRACE("ERROR: reached max components\n");
return JD_ERROR_BITSTREAM;
}
if (jpginfo.picture_param_buf.picture_height < HW_DECODE_MIN_HEIGHT
|| jpginfo.picture_param_buf.picture_width < HW_DECODE_MIN_WIDTH) {
VTRACE("PERFORMANCE: %ux%u JPEG will decode faster with SW\n",
jpginfo.picture_param_buf.picture_width,
jpginfo.picture_param_buf.picture_height);
return JD_ERROR_BITSTREAM;
}
uint8_t comp_ind = 0;
for (comp_ind = 0; comp_ind < jpginfo.picture_param_buf.num_components; comp_ind++) {
jpginfo.picture_param_buf.components[comp_ind].component_id = mParser->readNextByte(mParser);
uint8_t hv_sampling = mParser->readNextByte(mParser);
jpginfo.picture_param_buf.components[comp_ind].h_sampling_factor = hv_sampling >> 4;
jpginfo.picture_param_buf.components[comp_ind].v_sampling_factor = hv_sampling & 0xf;
jpginfo.picture_param_buf.components[comp_ind].quantiser_table_selector = mParser->readNextByte(mParser);
}
break;
}
// Store offset to DHT data to avoid parsing bitstream in user mode
case CODE_DHT: {
if (dht_ind < 4) {
jpginfo.dht_byte_offset[dht_ind] = mParser->getByteOffset(mParser) - jpginfo.soi_offset;
dht_ind++;
uint32_t bytes_to_burn = mParser->readBytes(mParser, 2) - 2;
mParser->burnBytes(mParser, bytes_to_burn );
} else {
ETRACE("ERROR: Decoder does not support more than 4 Huff Tables\n");
return JD_ERROR_BITSTREAM;
}
break;
}
// Parse component information in SOS marker
case CODE_SOS: {
mParser->burnBytes(mParser, 2);
uint32_t component_in_scan = mParser->readNextByte(mParser);
uint8_t comp_ind = 0;
for (comp_ind = 0; comp_ind < component_in_scan; comp_ind++) {
uint8_t comp_id = mParser->readNextByte(mParser);
uint8_t comp_data_ind;
for (comp_data_ind = 0; comp_data_ind < jpginfo.picture_param_buf.num_components; comp_data_ind++) {
if (comp_id == jpginfo.picture_param_buf.components[comp_data_ind].component_id) {
jpginfo.slice_param_buf[scan_ind].components[comp_ind].component_selector = comp_data_ind + 1;
break;
}
}
uint8_t huffman_tables = mParser->readNextByte(mParser);
jpginfo.slice_param_buf[scan_ind].components[comp_ind].dc_table_selector = huffman_tables >> 4;
jpginfo.slice_param_buf[scan_ind].components[comp_ind].ac_table_selector = huffman_tables & 0xf;
}
uint32_t curr_byte = mParser->readNextByte(mParser); // Ss
if (curr_byte != 0) {
ETRACE("ERROR: curr_byte 0x%08x != 0\n", curr_byte);
return JD_ERROR_BITSTREAM;
}
curr_byte = mParser->readNextByte(mParser); // Se
if (curr_byte != 0x3f) {
ETRACE("ERROR: curr_byte 0x%08x != 0x3f\n", curr_byte);
return JD_ERROR_BITSTREAM;
}
curr_byte = mParser->readNextByte(mParser); // Ah, Al
if (curr_byte != 0) {
ETRACE("ERROR: curr_byte 0x%08x != 0\n", curr_byte);
return JD_ERROR_BITSTREAM;
}
// Set slice control variables needed
jpginfo.slice_param_buf[scan_ind].slice_data_offset = mParser->getByteOffset(mParser) - jpginfo.soi_offset;
jpginfo.slice_param_buf[scan_ind].num_components = component_in_scan;
if (scan_ind) {
/* If there is more than one scan, the slice for all but the final scan should only run up to the beginning of the next scan */
jpginfo.slice_param_buf[scan_ind - 1].slice_data_size =
(jpginfo.slice_param_buf[scan_ind].slice_data_offset - jpginfo.slice_param_buf[scan_ind - 1].slice_data_offset );;
}
scan_ind++;
jpginfo.scan_ctrl_count++; // gsDXVA2Globals.uiScanCtrlCount
break;
}
case CODE_DRI: {
uint32_t size = mParser->readBytes(mParser, 2);
jpginfo.slice_param_buf[scan_ind].restart_interval = mParser->readBytes(mParser, 2);
mParser->burnBytes(mParser, (size - 4));
break;
}
default:
break;
}
marker = mParser->getNextMarker(mParser);
// If the EOI code is found, store the byte offset before the parsing finishes
if( marker == CODE_EOI ) {
jpginfo.eoi_offset = mParser->getByteOffset(mParser);
}
}
jpginfo.quant_tables_num = dqt_ind;
jpginfo.huffman_tables_num = dht_ind;
/* The slice for the last scan should run up to the end of the picture */
if (jpginfo.eoi_offset) {
jpginfo.slice_param_buf[scan_ind - 1].slice_data_size = (jpginfo.eoi_offset - jpginfo.slice_param_buf[scan_ind - 1].slice_data_offset);
}
else {
jpginfo.slice_param_buf[scan_ind - 1].slice_data_size = (jpginfo.bufsize - jpginfo.slice_param_buf[scan_ind - 1].slice_data_offset);
}
// throw AppException if SOF0 isn't found
if (!frame_marker_found) {
ETRACE("EEORR: Reached end of bitstream while trying to parse headers\n");
return JD_ERROR_BITSTREAM;
}
JpegDecodeStatus status = parseTableData(jpginfo);
if (status != JD_SUCCESS) {
ETRACE("ERROR: Parsing table data returns %d", status);
return JD_ERROR_BITSTREAM;
}
jpginfo.image_width = jpginfo.picture_param_buf.picture_width;
jpginfo.image_height = jpginfo.picture_param_buf.picture_height;
jpginfo.image_color_fourcc = sampFactor2Fourcc(jpginfo.picture_param_buf.components[0].h_sampling_factor,
jpginfo.picture_param_buf.components[1].h_sampling_factor,
jpginfo.picture_param_buf.components[2].h_sampling_factor,
jpginfo.picture_param_buf.components[0].v_sampling_factor,
jpginfo.picture_param_buf.components[1].v_sampling_factor,
jpginfo.picture_param_buf.components[2].v_sampling_factor);
jpginfo.image_pixel_format = fourcc2PixelFormat(jpginfo.image_color_fourcc);
VTRACE("%s jpg %ux%u, fourcc=%s, pixelformat=0x%x",
__FUNCTION__, jpginfo.image_width, jpginfo.image_height, fourcc2str(NULL, jpginfo.image_color_fourcc),
jpginfo.image_pixel_format);
if (!jpegColorFormatSupported(jpginfo))
return JD_INPUT_FORMAT_UNSUPPORTED;
return JD_SUCCESS;
}
JpegDecodeStatus JpegDecoder::createSurfaceFromRenderTarget(RenderTarget &target, VASurfaceID *surfid)
{
if (target.type == RENDERTARGET_INTERNAL_BUFFER) {
JpegDecodeStatus st = createSurfaceInternal(target.width,
target.height,
target.pixel_format,
target.handle,
surfid);
if (st != JD_SUCCESS)
return st;
mNormalSurfaceMap.add(target.handle, *surfid);
VTRACE("%s added surface %u (internal buffer id %d) to SurfaceList",
__PRETTY_FUNCTION__, *surfid, target.handle);
}
else {
switch (target.type) {
case RenderTarget::KERNEL_DRM:
{
JpegDecodeStatus st = createSurfaceDrm(target.width,
target.height,
target.pixel_format,
(unsigned long)target.handle,
target.stride,
surfid);
if (st != JD_SUCCESS)
return st;
mDrmSurfaceMap.add((unsigned long)target.handle, *surfid);
VTRACE("%s added surface %u (Drm handle %d) to DrmSurfaceMap",
__PRETTY_FUNCTION__, *surfid, target.handle);
}
break;
case RenderTarget::ANDROID_GRALLOC:
{
JpegDecodeStatus st = createSurfaceGralloc(target.width,
target.height,
target.pixel_format,
(buffer_handle_t)target.handle,
target.stride,
surfid);
if (st != JD_SUCCESS)
return st;
mGrallocSurfaceMap.add((buffer_handle_t)target.handle, *surfid);
VTRACE("%s added surface %u (Gralloc handle %d) to DrmSurfaceMap",
__PRETTY_FUNCTION__, *surfid, target.handle);
}
break;
default:
return JD_RENDER_TARGET_TYPE_UNSUPPORTED;
}
}
return JD_SUCCESS;
}
JpegDecodeStatus JpegDecoder::createSurfaceInternal(int width, int height, int pixel_format, int handle, VASurfaceID *surf_id)
{
VAStatus va_status;
VASurfaceAttrib attrib;
attrib.type = VASurfaceAttribPixelFormat;
attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
attrib.value.type = VAGenericValueTypeInteger;
uint32_t fourcc = pixelFormat2Fourcc(pixel_format);
uint32_t vaformat = fourcc2VaFormat(fourcc);
attrib.value.value.i = fourcc;
VTRACE("enter %s, pixel_format 0x%x, fourcc %s", __FUNCTION__, pixel_format, fourcc2str(NULL, fourcc));
va_status = vaCreateSurfaces(mDisplay,
vaformat,
width,
height,
surf_id,
1,
&attrib,
1);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("%s: createSurface (format %u, fourcc %s) returns %d", __PRETTY_FUNCTION__, vaformat, fourcc2str(NULL, fourcc), va_status);
return JD_RESOURCE_FAILURE;
}
return JD_SUCCESS;
}
VASurfaceID JpegDecoder::getSurfaceID(RenderTarget &target) const
{
int index;
if (target.type == RENDERTARGET_INTERNAL_BUFFER) {
index = mNormalSurfaceMap.indexOfKey(target.handle);
if (index < 0)
return VA_INVALID_ID;
else
return mNormalSurfaceMap.valueAt(index);
}
switch (target.type) {
case RenderTarget::KERNEL_DRM:
index = mDrmSurfaceMap.indexOfKey((unsigned long)target.handle);
if (index < 0)
return VA_INVALID_ID;
else
return mDrmSurfaceMap.valueAt(index);
case RenderTarget::ANDROID_GRALLOC:
index = mGrallocSurfaceMap.indexOfKey((buffer_handle_t)target.handle);
if (index < 0)
return VA_INVALID_ID;
else
return mGrallocSurfaceMap.valueAt(index);
default:
assert(false);
}
return VA_INVALID_ID;
}
JpegDecodeStatus JpegDecoder::sync(RenderTarget &target)
{
VASurfaceID surf_id = getSurfaceID(target);
if (surf_id == VA_INVALID_ID)
return JD_INVALID_RENDER_TARGET;
vaSyncSurface(mDisplay, surf_id);
return JD_SUCCESS;
}
bool JpegDecoder::busy(RenderTarget &target) const
{
VASurfaceStatus surf_st;
VASurfaceID surf_id = getSurfaceID(target);
if (surf_id == VA_INVALID_ID)
return false;
VAStatus st = vaQuerySurfaceStatus(mDisplay, surf_id, &surf_st);
if (st != VA_STATUS_SUCCESS)
return false;
return surf_st != VASurfaceReady;
}
JpegDecodeStatus JpegDecoder::decode(JpegInfo &jpginfo, RenderTarget &target)
{
VAStatus va_status = VA_STATUS_SUCCESS;
VASurfaceStatus surf_status;
VABufferID desc_buf[5];
uint32_t bitstream_buffer_size = 0;
uint32_t scan_idx = 0;
uint32_t buf_idx = 0;
uint32_t chopping = VA_SLICE_DATA_FLAG_ALL;
uint32_t bytes_remaining;
VASurfaceID surf_id = getSurfaceID(target);
if (surf_id == VA_INVALID_ID)
return JD_RENDER_TARGET_NOT_INITIALIZED;
va_status = vaQuerySurfaceStatus(mDisplay, surf_id, &surf_status);
if (surf_status != VASurfaceReady)
return JD_RENDER_TARGET_BUSY;
if (jpginfo.eoi_offset)
bytes_remaining = jpginfo.eoi_offset - jpginfo.soi_offset;
else
bytes_remaining = jpginfo.bufsize - jpginfo.soi_offset;
uint32_t src_offset = jpginfo.soi_offset;
uint32_t cpy_row;
bitstream_buffer_size = jpginfo.bufsize;//cinfo->src->bytes_in_buffer;//1024*1024*5;
Vector<VABufferID> buf_list;
va_status = vaBeginPicture(mDisplay, mContextId, surf_id);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaBeginPicture failed. va_status = 0x%x", va_status);
return JD_DECODE_FAILURE;
}
va_status = vaCreateBuffer(mDisplay, mContextId, VAPictureParameterBufferType, sizeof(VAPictureParameterBufferJPEGBaseline), 1, &jpginfo.picture_param_buf, &desc_buf[buf_idx]);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateBuffer VAPictureParameterBufferType failed. va_status = 0x%x", va_status);
return JD_RESOURCE_FAILURE;
}
buf_list.add(desc_buf[buf_idx++]);
va_status = vaCreateBuffer(mDisplay, mContextId, VAIQMatrixBufferType, sizeof(VAIQMatrixBufferJPEGBaseline), 1, &jpginfo.qmatrix_buf, &desc_buf[buf_idx]);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateBuffer VAIQMatrixBufferType failed. va_status = 0x%x", va_status);
return JD_RESOURCE_FAILURE;
}
buf_list.add(desc_buf[buf_idx++]);
va_status = vaCreateBuffer(mDisplay, mContextId, VAHuffmanTableBufferType, sizeof(VAHuffmanTableBufferJPEGBaseline), 1, &jpginfo.hufman_table_buf, &desc_buf[buf_idx]);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateBuffer VAHuffmanTableBufferType failed. va_status = 0x%x", va_status);
return JD_RESOURCE_FAILURE;
}
buf_list.add(desc_buf[buf_idx++]);
do {
/* Get Bitstream Buffer */
uint32_t bytes = ( bytes_remaining < bitstream_buffer_size ) ? bytes_remaining : bitstream_buffer_size;
bytes_remaining -= bytes;
/* Get Slice Control Buffer */
VASliceParameterBufferJPEGBaseline dest_scan_ctrl[JPEG_MAX_COMPONENTS];
uint32_t src_idx = 0;
uint32_t dest_idx = 0;
memset(dest_scan_ctrl, 0, sizeof(dest_scan_ctrl));
for (src_idx = scan_idx; src_idx < jpginfo.scan_ctrl_count ; src_idx++) {
if (jpginfo.slice_param_buf[ src_idx ].slice_data_offset) {
/* new scan, reset state machine */
chopping = VA_SLICE_DATA_FLAG_ALL;
VTRACE("Scan:%i FileOffset:%x Bytes:%x \n", src_idx,
jpginfo.slice_param_buf[ src_idx ].slice_data_offset,
jpginfo.slice_param_buf[ src_idx ].slice_data_size );
/* does the slice end in the buffer */
if (jpginfo.slice_param_buf[ src_idx ].slice_data_offset + jpginfo.slice_param_buf[ src_idx ].slice_data_size > bytes + src_offset) {
chopping = VA_SLICE_DATA_FLAG_BEGIN;
}
} else {
if (jpginfo.slice_param_buf[ src_idx ].slice_data_size > bytes) {
chopping = VA_SLICE_DATA_FLAG_MIDDLE;
} else {
if ((chopping == VA_SLICE_DATA_FLAG_BEGIN) || (chopping == VA_SLICE_DATA_FLAG_MIDDLE)) {
chopping = VA_SLICE_DATA_FLAG_END;
}
}
}
dest_scan_ctrl[dest_idx].slice_data_flag = chopping;
if ((chopping == VA_SLICE_DATA_FLAG_ALL) || (chopping == VA_SLICE_DATA_FLAG_BEGIN))
dest_scan_ctrl[dest_idx].slice_data_offset = jpginfo.slice_param_buf[ src_idx ].slice_data_offset;
else
dest_scan_ctrl[dest_idx].slice_data_offset = 0;
const int32_t bytes_in_seg = bytes - dest_scan_ctrl[dest_idx].slice_data_offset;
const uint32_t scan_data = (bytes_in_seg < jpginfo.slice_param_buf[src_idx].slice_data_size) ? bytes_in_seg : jpginfo.slice_param_buf[src_idx].slice_data_size ;
jpginfo.slice_param_buf[src_idx].slice_data_offset = 0;
jpginfo.slice_param_buf[src_idx].slice_data_size -= scan_data;
dest_scan_ctrl[dest_idx].slice_data_size = scan_data;
dest_scan_ctrl[dest_idx].num_components = jpginfo.slice_param_buf[src_idx].num_components;
dest_scan_ctrl[dest_idx].restart_interval = jpginfo.slice_param_buf[src_idx].restart_interval;
memcpy(&dest_scan_ctrl[dest_idx].components, & jpginfo.slice_param_buf[ src_idx ].components,
sizeof(jpginfo.slice_param_buf[ src_idx ].components) );
dest_idx++;
if ((chopping == VA_SLICE_DATA_FLAG_ALL) || (chopping == VA_SLICE_DATA_FLAG_END)) { /* all good good */
} else {
break;
}
}
scan_idx = src_idx;
/* Get Slice Control Buffer */
va_status = vaCreateBuffer(mDisplay, mContextId, VASliceParameterBufferType, sizeof(VASliceParameterBufferJPEGBaseline) * dest_idx, 1, dest_scan_ctrl, &desc_buf[buf_idx]);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateBuffer VASliceParameterBufferType failed. va_status = 0x%x", va_status);
return JD_RESOURCE_FAILURE;
}
buf_list.add(desc_buf[buf_idx++]);
va_status = vaCreateBuffer(mDisplay, mContextId, VASliceDataBufferType, bytes, 1, &jpginfo.buf[ src_offset ], &desc_buf[buf_idx]);
buf_list.add(desc_buf[buf_idx++]);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateBuffer VASliceDataBufferType (%u bytes) failed. va_status = 0x%x", bytes, va_status);
return JD_RESOURCE_FAILURE;
}
va_status = vaRenderPicture( mDisplay, mContextId, desc_buf, buf_idx);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaRenderPicture failed. va_status = 0x%x", va_status);
return JD_DECODE_FAILURE;
}
buf_idx = 0;
src_offset += bytes;
} while (bytes_remaining);
va_status = vaEndPicture(mDisplay, mContextId);
while(buf_list.size() > 0) {
vaDestroyBuffer(mDisplay, buf_list.top());
buf_list.pop();
}
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaEndPicture failed. va_status = 0x%x", va_status);
return JD_DECODE_FAILURE;
}
return JD_SUCCESS;
}
void JpegDecoder::deinit()
{
if (mInitialized) {
Mutex::Autolock autoLock(mLock);
if (mInitialized) {
vaDestroyContext(mDisplay, mContextId);
vaDestroyConfig(mDisplay, mConfigId);
mInitialized = false;
size_t gralloc_size = mGrallocSurfaceMap.size();
size_t drm_size = mDrmSurfaceMap.size();
size_t internal_surf_size = mNormalSurfaceMap.size();
for (size_t i = 0; i < gralloc_size; ++i) {
VASurfaceID surf_id = mGrallocSurfaceMap.valueAt(i);
vaDestroySurfaces(mDisplay, &surf_id, 1);
}
for (size_t i = 0; i < drm_size; ++i) {
VASurfaceID surf_id = mDrmSurfaceMap.valueAt(i);
vaDestroySurfaces(mDisplay, &surf_id, 1);
}
for (size_t i = 0; i < internal_surf_size; ++i) {
VASurfaceID surf_id = mNormalSurfaceMap.valueAt(i);
vaDestroySurfaces(mDisplay, &surf_id, 1);
}
mGrallocSurfaceMap.clear();
mDrmSurfaceMap.clear();
mNormalSurfaceMap.clear();
}
}
}
JpegDecodeStatus JpegDecoder::parseTableData(JpegInfo &jpginfo) {
parserInitialize(mParser, jpginfo.buf, jpginfo.bufsize);
// Parse Quant tables
memset(&jpginfo.qmatrix_buf, 0, sizeof(jpginfo.qmatrix_buf));
uint32_t dqt_ind = 0;
for (dqt_ind = 0; dqt_ind < jpginfo.quant_tables_num; dqt_ind++) {
if (mParser->setByteOffset(mParser, jpginfo.dqt_byte_offset[dqt_ind])) {
// uint32_t uiTableBytes = mParser->readBytes( 2 ) - 2;
uint32_t table_bytes = mParser->readBytes( mParser, 2 ) - 2;
do {
uint32_t table_info = mParser->readNextByte(mParser);
table_bytes--;
uint32_t table_length = table_bytes > 64 ? 64 : table_bytes;
uint32_t table_precision = table_info >> 4;
if (table_precision != 0) {
ETRACE("%s ERROR: Parsing table data returns %d", __FUNCTION__, JD_ERROR_BITSTREAM);
return JD_ERROR_BITSTREAM;
}
uint32_t table_id = table_info & 0xf;
jpginfo.qmatrix_buf.load_quantiser_table[table_id] = 1;
if (table_id < JPEG_MAX_QUANT_TABLES) {
// Pull Quant table data from bitstream
uint32_t byte_ind;
for (byte_ind = 0; byte_ind < table_length; byte_ind++) {
jpginfo.qmatrix_buf.quantiser_table[table_id][byte_ind] = mParser->readNextByte(mParser);
}
} else {
ETRACE("%s DQT table ID is not supported", __FUNCTION__);
mParser->burnBytes(mParser, table_length);
}
table_bytes -= table_length;
} while (table_bytes);
}
}
// Parse Huffman tables
memset(&jpginfo.hufman_table_buf, 0, sizeof(jpginfo.hufman_table_buf));
uint32_t dht_ind = 0;
for (dht_ind = 0; dht_ind < jpginfo.huffman_tables_num; dht_ind++) {
if (mParser->setByteOffset(mParser, jpginfo.dht_byte_offset[dht_ind])) {
uint32_t table_bytes = mParser->readBytes( mParser, 2 ) - 2;
do {
uint32_t table_info = mParser->readNextByte(mParser);
table_bytes--;
uint32_t table_class = table_info >> 4; // Identifies whether the table is for AC or DC
uint32_t table_id = table_info & 0xf;
jpginfo.hufman_table_buf.load_huffman_table[table_id] = 1;
if ((table_class < TABLE_CLASS_NUM) && (table_id < JPEG_MAX_SETS_HUFFMAN_TABLES)) {
if (table_class == 0) {
uint8_t* bits = mParser->getCurrentIndex(mParser);
// Find out the number of entries in the table
uint32_t table_entries = 0;
uint32_t bit_ind;
for (bit_ind = 0; bit_ind < 16; bit_ind++) {
jpginfo.hufman_table_buf.huffman_table[table_id].num_dc_codes[bit_ind] = bits[bit_ind];
table_entries += jpginfo.hufman_table_buf.huffman_table[table_id].num_dc_codes[bit_ind];
}
// Create table of code values
mParser->burnBytes(mParser, 16);
table_bytes -= 16;
uint32_t tbl_ind;
for (tbl_ind = 0; tbl_ind < table_entries; tbl_ind++) {
jpginfo.hufman_table_buf.huffman_table[table_id].dc_values[tbl_ind] = mParser->readNextByte(mParser);
table_bytes--;
}
} else { // for AC class
uint8_t* bits = mParser->getCurrentIndex(mParser);
// Find out the number of entries in the table
uint32_t table_entries = 0;
uint32_t bit_ind = 0;
for (bit_ind = 0; bit_ind < 16; bit_ind++) {
jpginfo.hufman_table_buf.huffman_table[table_id].num_ac_codes[bit_ind] = bits[bit_ind];
table_entries += jpginfo.hufman_table_buf.huffman_table[table_id].num_ac_codes[bit_ind];
}
// Create table of code values
mParser->burnBytes(mParser, 16);
table_bytes -= 16;
uint32_t tbl_ind = 0;
for (tbl_ind = 0; tbl_ind < table_entries; tbl_ind++) {
jpginfo.hufman_table_buf.huffman_table[table_id].ac_values[tbl_ind] = mParser->readNextByte(mParser);
table_bytes--;
}
}//end of else
} else {
// Find out the number of entries in the table
ETRACE("%s DHT table ID is not supported", __FUNCTION__);
uint32_t table_entries = 0;
uint32_t bit_ind = 0;
for(bit_ind = 0; bit_ind < 16; bit_ind++) {
table_entries += mParser->readNextByte(mParser);
table_bytes--;
}
mParser->burnBytes(mParser, table_entries);
table_bytes -= table_entries;
}
} while (table_bytes);
}
}
return JD_SUCCESS;
}