| /* 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> |
| * |
| */ |
| |
| #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 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; \ |
| } |
| |
| static int handlectr = 0; |
| int generateHandle() |
| { |
| return handlectr++; |
| } |
| |
| JpegDecoder::JpegDecoder(VADisplay display, VAConfigID vpCfgId, VAContextID vpCtxId, bool use_blitter) |
| :mInitialized(false), |
| mDisplay(display), |
| mConfigId(VA_INVALID_ID), |
| mContextId(VA_INVALID_ID), |
| mParser(NULL), |
| mBlitter(NULL), |
| mParserInitialized(false), |
| mDispCreated(false) |
| { |
| mParser = new CJPEGParse; |
| mBsParser = new JpegBitstreamParser; |
| if (!display) { |
| assert(vpCfgId == VA_INVALID_ID); |
| assert(vpCtxId == VA_INVALID_ID); |
| assert(use_blitter == false); |
| Display dpy; |
| int va_major_version, va_minor_version; |
| mDisplay = vaGetDisplay(&dpy); |
| vaInitialize(mDisplay, &va_major_version, &va_minor_version); |
| mDispCreated = true; |
| } |
| if (use_blitter) { |
| assert(display != NULL); |
| assert(vpCfgId != VA_INVALID_ID); |
| assert(vpCtxId != VA_INVALID_ID); |
| mBlitter = new JpegBlitter(display, vpCfgId,vpCtxId); |
| } |
| VTRACE("%s CTOR succeded", __FUNCTION__); |
| } |
| JpegDecoder::~JpegDecoder() |
| { |
| if (mInitialized) { |
| WTRACE("Freeing JpegDecoder: not destroyed yet. Force destroy resource"); |
| deinit(); |
| } |
| if (mBlitter) |
| mBlitter->deinit(); |
| delete mBlitter; |
| if (mDispCreated) |
| vaTerminate(mDisplay); |
| delete mParser; |
| delete mBsParser; |
| VTRACE("%s DTOR succeded", __FUNCTION__); |
| } |
| |
| JpegDecoder::MapHandle JpegDecoder::mapData(RenderTarget &target, void ** data, uint32_t * offsets, uint32_t * pitches) |
| { |
| VAImage *img = NULL; |
| VASurfaceID surf_id = getSurfaceID(target); |
| if (surf_id != VA_INVALID_ID) { |
| img = new VAImage(); |
| if (img == NULL) { |
| ETRACE("%s: create VAImage fail", __FUNCTION__); |
| return 0; |
| } |
| VAStatus st; |
| st = vaDeriveImage(mDisplay, surf_id, img); |
| if (st != VA_STATUS_SUCCESS) { |
| delete img; |
| img = NULL; |
| ETRACE("%s: vaDeriveImage fail %d", __FUNCTION__, st); |
| return 0; |
| } |
| st = vaMapBuffer(mDisplay, img->buf, data); |
| if (st != VA_STATUS_SUCCESS) { |
| vaDestroyImage(mDisplay, img->image_id); |
| delete img; |
| img = NULL; |
| ETRACE("%s: vaMapBuffer fail %d", __FUNCTION__, st); |
| return 0; |
| } |
| offsets[0] = img->offsets[0]; |
| offsets[1] = img->offsets[1]; |
| offsets[2] = img->offsets[2]; |
| pitches[0] = img->pitches[0]; |
| pitches[1] = img->pitches[1]; |
| pitches[2] = img->pitches[2]; |
| VTRACE("%s: successfully mapped RenderTarget %p, handle %d, data=%p, offsets=[%u,%u,%u], pitches=[%u,%u,%u], size=%u, %ux%u, to handle.img %p", |
| __FUNCTION__, &target, target.handle, *data, offsets[0], offsets[1], offsets[2], |
| pitches[0], pitches[1], pitches[2], img->data_size, |
| img->width, img->height, img); |
| |
| return (uint32_t)img; |
| } |
| ETRACE("%s: get Surface ID fail", __FUNCTION__); |
| return 0; |
| } |
| |
| void JpegDecoder::unmapData(RenderTarget &target, JpegDecoder::MapHandle maphandle) |
| { |
| if (maphandle != 0) { |
| vaUnmapBuffer(mDisplay, ((VAImage*)maphandle)->buf); |
| vaDestroyImage(mDisplay, ((VAImage*)maphandle)->image_id); |
| VTRACE("%s deleting VAImage %p", __FUNCTION__, ((VAImage*)maphandle)); |
| delete ((VAImage*)maphandle); |
| } |
| } |
| |
| JpegDecodeStatus JpegDecoder::init(int w, int h, RenderTarget **targets, int num) |
| { |
| if (mInitialized) { |
| VTRACE("%s already initialized", __FUNCTION__); |
| return JD_ALREADY_INITIALIZED; |
| } |
| Mutex::Autolock autoLock(mLock); |
| if (!mInitialized) { |
| nsecs_t now = systemTime(); |
| mGrallocSurfaceMap.clear(); |
| mDrmSurfaceMap.clear(); |
| mNormalSurfaceMap.clear(); |
| mUserptrSurfaceMap.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; |
| } |
| VTRACE("%s successfully created surface %u for renderTarget %p, handle %d", |
| __FUNCTION__, surfid, targets[i], targets[i]->handle); |
| } |
| 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(); |
| size_t umsize = mUserptrSurfaceMap.size(); |
| VASurfaceID *surfaces = new VASurfaceID[gmsize + dmsize + nmsize]; |
| for (size_t i = 0; i < gmsize + dmsize + nmsize + umsize; ++i) { |
| if (i < gmsize) |
| surfaces[i] = mGrallocSurfaceMap.valueAt(i); |
| else if (i < gmsize + dmsize) |
| surfaces[i] = mDrmSurfaceMap.valueAt(i - gmsize); |
| else if (i < gmsize + dmsize + nmsize) |
| surfaces[i] = mNormalSurfaceMap.valueAt(i - gmsize - dmsize); |
| else |
| surfaces[i] = mUserptrSurfaceMap.valueAt(i - gmsize - dmsize - nmsize); |
| } |
| 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("JpegDecoder::init took %.2f ms", (systemTime() - now)/1000000.0); |
| mInitialized = true; |
| } |
| return JD_SUCCESS; |
| } |
| |
| JpegDecodeStatus JpegDecoder::blit(RenderTarget &src, RenderTarget &dst, int scale_factor) |
| { |
| if (mBlitter) { |
| mBlitter->init(*this); |
| return mBlitter->blit(src, dst, scale_factor); |
| } |
| else |
| return JD_BLIT_FAILURE; |
| } |
| |
| JpegDecodeStatus JpegDecoder::getRgbaTile(RenderTarget &src, |
| uint8_t *sysmem, |
| int left, int top, int width, int height, int scale_factor) |
| { |
| if (mBlitter) { |
| nsecs_t now = systemTime(); |
| mBlitter->init(*this); |
| nsecs_t t1 = systemTime(); |
| JpegDecodeStatus st = mBlitter->getRgbaTile(src, sysmem, left, top, width, height, scale_factor); |
| VTRACE("Decoder::%s took %.2f + %.2f ms", __FUNCTION__, |
| (t1-now)/1000000.0, (systemTime()-t1)/1000000.0); |
| return st; |
| } |
| else |
| return JD_BLIT_FAILURE; |
| |
| } |
| |
| JpegDecodeStatus JpegDecoder::blitToLinearRgba(RenderTarget &src, uint8_t *sysmem, uint32_t width, uint32_t height, BlitEvent &event, int scale_factor) |
| { |
| if (mBlitter) { |
| nsecs_t now = systemTime(); |
| mBlitter->init(*this); |
| nsecs_t t1 = systemTime(); |
| JpegDecodeStatus st = mBlitter->blitToLinearRgba(src, sysmem, width, height, event, scale_factor); |
| VTRACE("Decoder::%s took %.2f + %.2f ms", __FUNCTION__, |
| (t1-now)/1000000.0, (systemTime()-t1)/1000000.0); |
| return st; |
| } |
| else |
| return JD_BLIT_FAILURE; |
| } |
| |
| JpegDecodeStatus JpegDecoder::blitToCameraSurfaces(RenderTarget &src, |
| buffer_handle_t dst_nv12, |
| buffer_handle_t dst_yuy2, |
| uint8_t *dst_nv21, |
| uint8_t *dst_yv12, |
| uint32_t width, uint32_t height, BlitEvent &event) |
| { |
| if (mBlitter) { |
| nsecs_t now = systemTime(); |
| mBlitter->init(*this); |
| nsecs_t t1 = systemTime(); |
| JpegDecodeStatus st = mBlitter->blitToCameraSurfaces(src, dst_nv12, dst_yuy2, dst_nv21, dst_yv12, width, height, event); |
| VTRACE("Decoder::%s took %.2f + %.2f ms", __FUNCTION__, |
| (t1-now)/1000000.0, (systemTime()-t1)/1000000.0); |
| return st; |
| } |
| else |
| return JD_BLIT_FAILURE; |
| } |
| |
| void JpegDecoder::syncBlit(BlitEvent &event) |
| { |
| assert(mBlitter); |
| mBlitter->syncBlit(event); |
| } |
| |
| JpegDecodeStatus JpegDecoder::parseHeader(JpegInfo &jpginfo) |
| { |
| #define ROLLBACK_IF_FAIL(stmt) \ |
| do { \ |
| if (!stmt) { \ |
| VTRACE("%s::%d, parser failed at offset %u, remaining bytes %u, total bytes %zu", \ |
| __FUNCTION__, __LINE__, mBsParser->getByteOffset(), mBsParser->getRemainingBytes(), \ |
| bufsize); \ |
| goto rollback; \ |
| } \ |
| } while(0); |
| |
| int i; |
| uint32_t bufsize; |
| if (!mParserInitialized) { |
| Mutex::Autolock autoLock(mLock); |
| if (!mParserInitialized) { |
| if (jpginfo.use_vector_input) |
| mBsParser->set(jpginfo.inputs); |
| else |
| mBsParser->set(jpginfo.buf, jpginfo.bufsize); |
| mParserInitialized = true; |
| } |
| } |
| if (jpginfo.use_vector_input) |
| bufsize = jpginfo.inputs->size(); |
| else |
| bufsize = jpginfo.bufsize; |
| |
| uint8_t marker; |
| uint32_t rollbackoff; |
| rollbackoff = mBsParser->getByteOffset(); |
| ROLLBACK_IF_FAIL(mBsParser->tryGetNextMarker(&marker)); |
| |
| while (marker != CODE_EOI &&( !mBsParser->endOfBuffer())) { |
| switch (marker) { |
| case CODE_SOI: { |
| VTRACE("%s SOI at 0x%08x", __FUNCTION__, mBsParser->getByteOffset()); |
| jpginfo.soi_offset = mBsParser->getByteOffset() - 2; |
| jpginfo.soi_parsed = true; |
| 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: { |
| VTRACE("%s APP %x at 0x%08x", __FUNCTION__, marker, mBsParser->getByteOffset()); |
| uint32_t bytes_to_burn; |
| ROLLBACK_IF_FAIL(mBsParser->tryReadBytes(&bytes_to_burn, 2)); |
| bytes_to_burn -= 2; |
| ROLLBACK_IF_FAIL(mBsParser->tryBurnBytes(bytes_to_burn)); |
| break; |
| } |
| // Store offset to DQT data to avoid parsing bitstream in user mode |
| case CODE_DQT: { |
| VTRACE("%s DQT at 0x%08x", __FUNCTION__, mBsParser->getByteOffset()); |
| if (jpginfo.dqt_ind < 4) { |
| jpginfo.dqt_byte_offset[jpginfo.dqt_ind] = mBsParser->getByteOffset() - jpginfo.soi_offset; |
| jpginfo.dqt_ind++; |
| uint32_t bytes_to_burn; |
| ROLLBACK_IF_FAIL(mBsParser->tryReadBytes(&bytes_to_burn, 2)); |
| bytes_to_burn -= 2; |
| ROLLBACK_IF_FAIL(mBsParser->tryBurnBytes(bytes_to_burn)); |
| } else { |
| ETRACE("ERROR: Decoder does not support more than 4 Quant Tables\n"); |
| return JD_CODEC_UNSUPPORTED; |
| } |
| jpginfo.dqt_parsed = true; |
| 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; |
| } |
| case CODE_SOF_BASELINE: { |
| VTRACE("%s SOF_BASELINE at 0x%08x", __FUNCTION__, mBsParser->getByteOffset()); |
| ROLLBACK_IF_FAIL((mBsParser->getRemainingBytes() >= 10)); |
| jpginfo.frame_marker_found = true; |
| bool r; |
| ROLLBACK_IF_FAIL(mBsParser->tryBurnBytes(2)); // Throw away frame header length |
| uint8_t sample_precision; |
| ROLLBACK_IF_FAIL(mBsParser->tryReadNextByte(&sample_precision)); |
| if (sample_precision != 8) { |
| ETRACE("sample_precision is not supported\n"); |
| return JD_INPUT_FORMAT_UNSUPPORTED; |
| } |
| // Extract pic width and height |
| uint32_t w, h; |
| ROLLBACK_IF_FAIL(mBsParser->tryReadBytes(&h, 2)); |
| ROLLBACK_IF_FAIL(mBsParser->tryReadBytes(&w, 2)); |
| ROLLBACK_IF_FAIL(mBsParser->tryReadNextByte(&jpginfo.picture_param_buf.num_components)); |
| jpginfo.picture_param_buf.picture_width = w; |
| jpginfo.picture_param_buf.picture_height = h; |
| VTRACE("%s pic wxh=%ux%u, %u components", __FUNCTION__, |
| jpginfo.picture_param_buf.picture_width, |
| jpginfo.picture_param_buf.picture_height, |
| jpginfo.picture_param_buf.num_components); |
| |
| ROLLBACK_IF_FAIL((mBsParser->getRemainingBytes() >= jpginfo.picture_param_buf.num_components * 3)); |
| |
| 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_IMAGE_TOO_SMALL; |
| } |
| uint8_t comp_ind = 0; |
| for (comp_ind = 0; comp_ind < jpginfo.picture_param_buf.num_components; comp_ind++) { |
| ROLLBACK_IF_FAIL(mBsParser->tryReadNextByte(&jpginfo.picture_param_buf.components[comp_ind].component_id)); |
| uint8_t hv_sampling; |
| ROLLBACK_IF_FAIL(mBsParser->tryReadNextByte(&hv_sampling)); |
| 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; |
| ROLLBACK_IF_FAIL(mBsParser->tryReadNextByte(&jpginfo.picture_param_buf.components[comp_ind].quantiser_table_selector)); |
| } |
| 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); |
| |
| VTRACE("%s jpg %ux%u, fourcc=%s", |
| __FUNCTION__, jpginfo.image_width, jpginfo.image_height, fourcc2str(jpginfo.image_color_fourcc)); |
| |
| if (!jpegColorFormatSupported(jpginfo)) { |
| ETRACE("%s color format not supported", fourcc2str(jpginfo.image_color_fourcc)); |
| return JD_INPUT_FORMAT_UNSUPPORTED; |
| } |
| jpginfo.sof_parsed = true; |
| break; |
| } |
| case CODE_DHT: { |
| VTRACE("%s DHT at 0x%08x", __FUNCTION__, mBsParser->getByteOffset()); |
| if (jpginfo.dht_ind < 4) { |
| jpginfo.dht_byte_offset[jpginfo.dht_ind] = mBsParser->getByteOffset() - jpginfo.soi_offset; |
| jpginfo.dht_ind++; |
| uint32_t bytes_to_burn; |
| if (!mBsParser->tryReadBytes(&bytes_to_burn, 2)) { |
| VTRACE("%s failed to read 2 bytes from 0x%08x, remaining 0x%08x, total 0x%08x", |
| __FUNCTION__, mBsParser->getByteOffset(), |
| mBsParser->getRemainingBytes(), bufsize); |
| jpginfo.dht_ind--; |
| goto rollback; |
| } |
| bytes_to_burn -= 2; |
| if (!mBsParser->tryBurnBytes(bytes_to_burn)) { |
| VTRACE("%s failed to burn %x bytes from 0x%08x, remaining 0x%08x, total 0x%08x", |
| __FUNCTION__, bytes_to_burn, mBsParser->getByteOffset(), |
| mBsParser->getRemainingBytes(), bufsize); |
| jpginfo.dht_ind--; |
| goto rollback; |
| } |
| } else { |
| ETRACE("ERROR: Decoder does not support more than 4 Huff Tables\n"); |
| return JD_ERROR_BITSTREAM; |
| } |
| jpginfo.dht_parsed = true; |
| break; |
| } |
| // Parse component information in SOS marker |
| case CODE_SOS: { |
| VTRACE("%s SOS at 0x%08x", __FUNCTION__, mBsParser->getByteOffset()); |
| ROLLBACK_IF_FAIL(mBsParser->tryBurnBytes(2)); |
| uint8_t component_in_scan; |
| ROLLBACK_IF_FAIL(mBsParser->tryReadNextByte(&component_in_scan)); |
| uint8_t comp_ind = 0; |
| ROLLBACK_IF_FAIL((mBsParser->getRemainingBytes() >= 2 * component_in_scan + 3)); |
| for (comp_ind = 0; comp_ind < component_in_scan; comp_ind++) { |
| uint8_t comp_id; |
| mBsParser->tryReadNextByte(&comp_id); |
| 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[jpginfo.scan_ind].components[comp_ind].component_selector = comp_data_ind + 1; |
| break; |
| } |
| } |
| uint8_t huffman_tables; |
| ROLLBACK_IF_FAIL(mBsParser->tryReadNextByte(&huffman_tables)); |
| jpginfo.slice_param_buf[jpginfo.scan_ind].components[comp_ind].dc_table_selector = huffman_tables >> 4; |
| jpginfo.slice_param_buf[jpginfo.scan_ind].components[comp_ind].ac_table_selector = huffman_tables & 0xf; |
| } |
| uint8_t curr_byte; |
| ROLLBACK_IF_FAIL(mBsParser->tryReadNextByte(&curr_byte)); // Ss |
| if (curr_byte != 0) { |
| ETRACE("ERROR: curr_byte 0x%08x (position 0x%08x) != 0\n", curr_byte, mBsParser->getByteOffset()); |
| return JD_ERROR_BITSTREAM; |
| } |
| ROLLBACK_IF_FAIL(mBsParser->tryReadNextByte(&curr_byte)); // Se |
| if (curr_byte != 0x3f) { |
| ETRACE("ERROR: curr_byte 0x%08x (position 0x%08x) != 0x3f\n", curr_byte, mBsParser->getByteOffset()); |
| return JD_ERROR_BITSTREAM; |
| } |
| ROLLBACK_IF_FAIL(mBsParser->tryReadNextByte(&curr_byte)); // Ah, Al |
| if (curr_byte != 0) { |
| ETRACE("ERROR: curr_byte 0x%08x (position 0x%08x) != 0\n", curr_byte, mBsParser->getByteOffset()); |
| return JD_ERROR_BITSTREAM; |
| } |
| // Set slice control variables needed |
| jpginfo.slice_param_buf[jpginfo.scan_ind].slice_data_offset = mBsParser->getByteOffset() - jpginfo.soi_offset; |
| jpginfo.slice_param_buf[jpginfo.scan_ind].num_components = component_in_scan; |
| jpginfo.sos_parsed = true; |
| if (jpginfo.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[jpginfo.scan_ind - 1].slice_data_size = |
| (jpginfo.slice_param_buf[jpginfo.scan_ind].slice_data_offset - jpginfo.slice_param_buf[jpginfo.scan_ind - 1].slice_data_offset );; |
| } |
| jpginfo.scan_ind++; |
| jpginfo.scan_ctrl_count++; // gsDXVA2Globals.uiScanCtrlCount |
| break; |
| } |
| case CODE_DRI: { |
| rollbackoff = mBsParser->getByteOffset() - 2; |
| VTRACE("%s DRI at 0x%08x", __FUNCTION__, mBsParser->getByteOffset()); |
| uint32_t size; |
| ROLLBACK_IF_FAIL(mBsParser->tryReadBytes(&size, 2)); |
| uint32_t ri; |
| ROLLBACK_IF_FAIL(mBsParser->tryReadBytes(&ri, 2)); |
| jpginfo.slice_param_buf[jpginfo.scan_ind].restart_interval = ri; |
| ROLLBACK_IF_FAIL(mBsParser->tryBurnBytes(size - 4)); |
| jpginfo.dri_parsed = true; |
| break; |
| } |
| default: |
| break; |
| } |
| if (jpginfo.need_header_only && |
| jpginfo.soi_parsed && jpginfo.sos_parsed && |
| jpginfo.sof_parsed && jpginfo.dqt_parsed && |
| jpginfo.dht_parsed) { |
| VTRACE("%s: for header_only, we've got all what we need. return now", __FUNCTION__); |
| return JD_SUCCESS; |
| } |
| else { |
| VTRACE("%s: soi %d, sos %d, sof %d, dqt %d, dht %d, dri %d, remaining %u", __FUNCTION__, |
| jpginfo.soi_parsed, |
| jpginfo.sos_parsed, |
| jpginfo.sof_parsed, |
| jpginfo.dqt_parsed, |
| jpginfo.dht_parsed, |
| jpginfo.dri_parsed, |
| mBsParser->getRemainingBytes()); |
| } |
| rollbackoff = mBsParser->getByteOffset(); |
| if (!mBsParser->tryGetNextMarker(&marker)) { |
| VTRACE("%s: can't get next marker, offset 0x%08x, need_header_only=%d", |
| __FUNCTION__, |
| mBsParser->getByteOffset(), |
| jpginfo.need_header_only); |
| if (jpginfo.need_header_only) { |
| mBsParser->trySetByteOffset(rollbackoff); |
| return JD_INSUFFICIENT_BYTE; |
| } |
| else { |
| return JD_SUCCESS; |
| } |
| } |
| else if (marker == 0) { |
| VTRACE("%s: got non-marker %x at offset 0x%08x", __FUNCTION__, marker, mBsParser->getByteOffset()); |
| return JD_SUCCESS; |
| } |
| |
| // If the EOI code is found, store the byte offset before the parsing finishes |
| if( marker == CODE_EOI ) { |
| jpginfo.eoi_offset = mBsParser->getByteOffset(); |
| VTRACE("%s: got EOI at 0x%08x, stop parsing now", __FUNCTION__, jpginfo.eoi_offset); |
| return JD_SUCCESS; |
| } |
| } |
| return JD_SUCCESS; |
| rollback: |
| mBsParser->trySetByteOffset(rollbackoff); |
| return JD_INSUFFICIENT_BYTE; |
| } |
| |
| JpegDecodeStatus JpegDecoder::parse(JpegInfo &jpginfo) |
| { |
| if (!mParserInitialized) { |
| Mutex::Autolock autoLock(mLock); |
| if (!mParserInitialized) { |
| if (jpginfo.use_vector_input) |
| mBsParser->set(jpginfo.inputs); |
| else |
| mBsParser->set(jpginfo.buf, jpginfo.bufsize); |
| mParserInitialized = true; |
| } |
| } |
| JpegDecodeStatus st = parseHeader(jpginfo); |
| if (st) { |
| if (st != JD_INSUFFICIENT_BYTE) |
| ETRACE("%s header parsing failure: %d", __FUNCTION__, st); |
| return st; |
| } |
| if (jpginfo.need_header_only) |
| return JD_SUCCESS; |
| uint32_t bufsize; |
| if (jpginfo.use_vector_input) { |
| mBsParser->set(jpginfo.inputs); |
| bufsize = jpginfo.inputs->size(); |
| } |
| else { |
| mBsParser->set(jpginfo.buf, jpginfo.bufsize); |
| bufsize = jpginfo.bufsize; |
| } |
| assert(mParserInitialized); |
| assert (jpginfo.soi_parsed && jpginfo.sos_parsed && |
| jpginfo.sof_parsed && jpginfo.dqt_parsed && |
| jpginfo.dht_parsed); |
| jpginfo.quant_tables_num = jpginfo.dqt_ind; |
| jpginfo.huffman_tables_num = jpginfo.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[jpginfo.scan_ind - 1].slice_data_size = (jpginfo.eoi_offset - jpginfo.slice_param_buf[jpginfo.scan_ind - 1].slice_data_offset); |
| } |
| else { |
| jpginfo.slice_param_buf[jpginfo.scan_ind - 1].slice_data_size = (bufsize - jpginfo.slice_param_buf[jpginfo.scan_ind - 1].slice_data_offset); |
| } |
| // throw AppException if SOF0 isn't found |
| if (!jpginfo.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 status; |
| } |
| |
| 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); |
| |
| VTRACE("%s jpg %ux%u, fourcc=%s", |
| __FUNCTION__, jpginfo.image_width, jpginfo.image_height, fourcc2str(jpginfo.image_color_fourcc)); |
| |
| if (!jpegColorFormatSupported(jpginfo)) { |
| ETRACE("%s color format not supported", fourcc2str(jpginfo.image_color_fourcc)); |
| return JD_INPUT_FORMAT_UNSUPPORTED; |
| } |
| return JD_SUCCESS; |
| } |
| |
| JpegDecodeStatus JpegDecoder::createSurfaceFromRenderTarget(RenderTarget &target, VASurfaceID *surfid) |
| { |
| 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; |
| case RenderTarget::INTERNAL_BUF: |
| { |
| 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); |
| } |
| break; |
| case RenderTarget::USER_PTR: |
| { |
| JpegDecodeStatus st = createSurfaceUserptr(target.width, |
| target.height, |
| target.pixel_format, |
| (uint8_t*)target.handle, |
| surfid); |
| if (st != JD_SUCCESS) |
| return st; |
| mUserptrSurfaceMap.add(target.handle, *surfid); |
| VTRACE("%s added surface %u (internal buffer id %d) to SurfaceList", |
| __PRETTY_FUNCTION__, *surfid, target.handle); |
| } |
| break; |
| default: |
| return JD_RENDER_TARGET_TYPE_UNSUPPORTED; |
| } |
| return JD_SUCCESS; |
| } |
| |
| JpegDecodeStatus JpegDecoder::createSurfaceInternal(int width, int height, uint32_t fourcc, 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 vaformat = fourcc2VaFormat(fourcc); |
| attrib.value.value.i = fourcc; |
| VTRACE("enter %s, fourcc 0x%x, fourcc %s", __FUNCTION__, fourcc, fourcc2str(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(fourcc), va_status); |
| return JD_RESOURCE_FAILURE; |
| } |
| return JD_SUCCESS; |
| } |
| |
| JpegDecodeStatus JpegDecoder::destroySurface(RenderTarget &target) |
| { |
| Mutex::Autolock autoLock(mLock); |
| VASurfaceID surf = getSurfaceID(target); |
| if (surf == VA_INVALID_ID) { |
| ETRACE("%s: failed to destroy surface type %d, handle %d", __FUNCTION__, target.type, target.handle); |
| return JD_INVALID_RENDER_TARGET; |
| } |
| switch(target.type) { |
| case RenderTarget::KERNEL_DRM: |
| mDrmSurfaceMap.removeItem((unsigned long)target.handle); |
| break; |
| case RenderTarget::ANDROID_GRALLOC: |
| mGrallocSurfaceMap.removeItem((buffer_handle_t)target.handle); |
| break; |
| case RenderTarget::INTERNAL_BUF: |
| mNormalSurfaceMap.removeItem(target.handle); |
| break; |
| case RenderTarget::USER_PTR: |
| mUserptrSurfaceMap.removeItem(target.handle); |
| break; |
| default: |
| break; |
| } |
| VTRACE("%s: succeeded destroying surface type %d, handle %d", __FUNCTION__, target.type, target.handle); |
| return JD_SUCCESS; |
| } |
| |
| JpegDecodeStatus JpegDecoder::destroySurface(VASurfaceID surf) |
| { |
| return JD_UNIMPLEMENTED; |
| } |
| |
| VASurfaceID JpegDecoder::getSurfaceID(RenderTarget &target) const |
| { |
| int 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); |
| case RenderTarget::INTERNAL_BUF: |
| index = mNormalSurfaceMap.indexOfKey(target.handle); |
| if (index < 0) |
| return VA_INVALID_ID; |
| else |
| return mNormalSurfaceMap.valueAt(index); |
| case RenderTarget::USER_PTR: |
| index = mUserptrSurfaceMap.indexOfKey(target.handle); |
| if (index < 0) |
| return VA_INVALID_ID; |
| else |
| return mUserptrSurfaceMap.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; |
| uint8_t* bufaddr = NULL; |
| 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); |
| nsecs_t now = systemTime(); |
| if (surf_id == VA_INVALID_ID) { |
| ETRACE("%s render_target %p, handle %d is not initailized by JpegDecoder", __FUNCTION__, &target, target.handle); |
| return JD_RENDER_TARGET_NOT_INITIALIZED; |
| } |
| va_status = vaQuerySurfaceStatus(mDisplay, surf_id, &surf_status); |
| if (surf_status != VASurfaceReady) { |
| ETRACE("%s render_target %p, handle %d is still busy", __FUNCTION__, &target, target.handle); |
| return JD_RENDER_TARGET_BUSY; |
| } |
| |
| if (jpginfo.use_vector_input) { |
| bitstream_buffer_size = jpginfo.inputs->size(); |
| bufaddr = const_cast<uint8_t*>(jpginfo.inputs->array()); |
| } |
| else { |
| bitstream_buffer_size = jpginfo.bufsize; |
| bufaddr = jpginfo.buf; |
| } |
| |
| if (jpginfo.eoi_offset) |
| bytes_remaining = jpginfo.eoi_offset - jpginfo.soi_offset; |
| else |
| bytes_remaining = bitstream_buffer_size - jpginfo.soi_offset; |
| |
| uint32_t src_offset = jpginfo.soi_offset; |
| uint32_t cpy_row; |
| |
| 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; |
| } |
| VTRACE("%s begin decode render target %p, handle %d", __FUNCTION__, &target, target.handle); |
| 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; |
| } |
| VTRACE("%s successfully created PicParamBuf, id=%u", __FUNCTION__, desc_buf[buf_idx]); |
| 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; |
| } |
| VTRACE("%s successfully created IQMatrixBuf, id=%u", __FUNCTION__, desc_buf[buf_idx]); |
| 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; |
| } |
| VTRACE("%s successfully created HuffmanTableBuf, id=%u", __FUNCTION__, desc_buf[buf_idx]); |
| 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, dest_idx=%d, buf_idx=%d", va_status, dest_idx, buf_idx); |
| return JD_RESOURCE_FAILURE; |
| } |
| VTRACE("vaCreateBuffer VASliceParameterBufferType succeeded. va_status = 0x%x, dest_idx=%d, buf_idx=%d", va_status, dest_idx, buf_idx); |
| buf_list.add(desc_buf[buf_idx++]); |
| va_status = vaCreateBuffer(mDisplay, mContextId, VASliceDataBufferType, bytes, 1, bufaddr + src_offset, &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; |
| } |
| VTRACE("%s successfully created SliceDataBuf, id=%u", __FUNCTION__, desc_buf[buf_idx]); |
| buf_list.add(desc_buf[buf_idx++]); |
| 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; |
| } |
| |
| VTRACE("%s successfully ended picture, rendertarget %p, handle %d", __FUNCTION__, &target, target.handle); |
| VTRACE("JpegDecoder decode took %.2f ms", (systemTime() - now)/1000000.0); |
| 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(); |
| size_t up_surf_size = mUserptrSurfaceMap.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); |
| } |
| for (size_t i = 0; i < up_surf_size; ++i) { |
| VASurfaceID surf_id = mUserptrSurfaceMap.valueAt(i); |
| vaDestroySurfaces(mDisplay, &surf_id, 1); |
| } |
| mGrallocSurfaceMap.clear(); |
| mDrmSurfaceMap.clear(); |
| mNormalSurfaceMap.clear(); |
| mUserptrSurfaceMap.clear(); |
| mBsParser->reset(); |
| } |
| } |
| } |
| |
| JpegDecodeStatus JpegDecoder::parseTableData(JpegInfo &jpginfo) { |
| #define REPORT_BS_ERR_IF_FAIL(stmt) \ |
| do { \ |
| if (!stmt) { \ |
| ETRACE("%s::%d, bitstream error at offset %u, remaining bytes %u, total bytes %zu", \ |
| __FUNCTION__, __LINE__, mBsParser->getByteOffset(), mBsParser->getRemainingBytes(), \ |
| bufsize); \ |
| return JD_ERROR_BITSTREAM; \ |
| } \ |
| } while(0); |
| |
| assert(mParserInitialized); |
| memset(&jpginfo.qmatrix_buf, 0, sizeof(jpginfo.qmatrix_buf)); |
| uint32_t dqt_ind = 0; |
| uint32_t bufsize; |
| |
| if (jpginfo.use_vector_input) |
| bufsize = jpginfo.inputs->size(); |
| else |
| bufsize = jpginfo.bufsize; |
| |
| for (dqt_ind = 0; dqt_ind < jpginfo.quant_tables_num; dqt_ind++) { |
| REPORT_BS_ERR_IF_FAIL(mBsParser->trySetByteOffset(jpginfo.dqt_byte_offset[dqt_ind])); |
| uint32_t table_bytes; |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryReadBytes(&table_bytes, 2 )); |
| table_bytes -= 2; |
| do { |
| uint8_t table_info; |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryReadNextByte(&table_info)); |
| table_bytes--; |
| uint32_t table_length = table_bytes > 64 ? 64 : table_bytes; |
| uint32_t table_precision = table_info >> 4; |
| REPORT_BS_ERR_IF_FAIL ((table_precision == 0)); |
| 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++) { |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryReadNextByte(&jpginfo.qmatrix_buf.quantiser_table[table_id][byte_ind])); |
| } |
| } else { |
| ETRACE("%s DQT table ID is not supported", __FUNCTION__); |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryBurnBytes(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++) { |
| REPORT_BS_ERR_IF_FAIL(mBsParser->trySetByteOffset(jpginfo.dht_byte_offset[dht_ind])); |
| uint32_t table_bytes; |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryReadBytes( &table_bytes, 2 )); |
| table_bytes -= 2; |
| do { |
| uint8_t table_info; |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryReadNextByte(&table_info)); |
| 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) { |
| //const uint8_t* bits = mBsParser->getCurrentIndex(); |
| // 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] = mBsParser->itemAt(mBsParser->getByteOffset() + bit_ind); |
| table_entries += jpginfo.hufman_table_buf.huffman_table[table_id].num_dc_codes[bit_ind]; |
| } |
| |
| // Create table of code values |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryBurnBytes(16)); |
| table_bytes -= 16; |
| uint32_t tbl_ind; |
| for (tbl_ind = 0; tbl_ind < table_entries; tbl_ind++) { |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryReadNextByte(&jpginfo.hufman_table_buf.huffman_table[table_id].dc_values[tbl_ind])); |
| table_bytes--; |
| } |
| |
| } else { // for AC class |
| //const uint8_t* bits = mBsParser->getCurrentIndex(); |
| // 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] = mBsParser->itemAt(mBsParser->getByteOffset() + 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 |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryBurnBytes(16)); |
| table_bytes -= 16; |
| uint32_t tbl_ind = 0; |
| for (tbl_ind = 0; tbl_ind < table_entries; tbl_ind++) { |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryReadNextByte(&jpginfo.hufman_table_buf.huffman_table[table_id].ac_values[tbl_ind])); |
| 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++) { |
| uint8_t tmp; |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryReadNextByte(&tmp)); |
| table_entries += tmp; |
| table_bytes--; |
| } |
| REPORT_BS_ERR_IF_FAIL(mBsParser->tryBurnBytes(table_entries)); |
| table_bytes -= table_entries; |
| } |
| |
| } while (table_bytes); |
| } |
| |
| return JD_SUCCESS; |
| } |
| |