blob: b1ecb49a8c4475d7cce060b7092696fec3446573 [file] [log] [blame]
/* INTEL CONFIDENTIAL
* Copyright (c) 2012 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>
*
*/
#include "va/va_tpi.h"
#include "JPEGDecoder.h"
#include "ImageDecoderTrace.h"
#include "JPEGParser.h"
#include <string.h>
#define JPEG_MAX_SETS_HUFFMAN_TABLES 2
#define TABLE_CLASS_DC 0
#define TABLE_CLASS_AC 1
#define TABLE_CLASS_NUM 2
/*
* Initialize VA API related stuff
*
* We will check the return value of jva_initialize
* to determine which path will be use (SW or HW)
*
*/
Decode_Status jdva_initialize (jd_libva_struct * jd_libva_ptr) {
/*
* Please note that we won't check the input parameters to follow the
* convention of libjpeg duo to we need these parameters to do error handling,
* and if these parameters are invalid, means the whole stack is crashed, so check
* them here and return false is meaningless, same situation for all internal methods
* related to VA API
*/
int va_major_version;
int va_minor_version;
#if 0
int va_max_num_profiles, va_max_num_entrypoints, va_max_num_attribs;
int va_num_profiles, va_num_entrypoints;
VAProfile *va_profiles = NULL;
VAEntrypoint *va_entrypoints = NULL;
#endif
VAStatus va_status = VA_STATUS_SUCCESS;
Decode_Status status = DECODE_SUCCESS;
int index;
if (jd_libva_ptr->initialized)
return DECODE_NOT_STARTED;
jd_libva_ptr->android_display = (Display*)malloc(sizeof(Display));
if (jd_libva_ptr->android_display == NULL) {
return DECODE_MEMORY_FAIL;
}
jd_libva_ptr->va_display = vaGetDisplay (jd_libva_ptr->android_display);
if (jd_libva_ptr->va_display == NULL) {
ETRACE("vaGetDisplay failed.");
free (jd_libva_ptr->android_display);
return DECODE_DRIVER_FAIL;
}
va_status = vaInitialize(jd_libva_ptr->va_display, &va_major_version, &va_minor_version);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaInitialize failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
goto cleanup;
}
#if 0
/*get the max number for profiles/entrypoints/attribs*/
va_max_num_profiles = vaMaxNumProfiles(jd_libva_ptr->va_display);
va_max_num_entrypoints = vaMaxNumEntrypoints(jd_libva_ptr->va_display);
va_max_num_attribs = vaMaxNumConfigAttributes(jd_libva_ptr->va_display);
va_profiles = malloc (sizeof(VAProfile)*va_max_num_profiles);
va_entrypoints = malloc(sizeof(VAEntrypoint)*va_max_num_entrypoints);
if (va_profiles == NULL || va_entrypoints ==NULL) {
jd_libva_ptr->initialized = TRUE; // make sure we can call into jva_deinitialize()
jdva_deinitialize (jd_libva_ptr);
return DECODE_MEMORY_FAIL;
}
va_status = vaQueryConfigProfiles (jd_libva_ptr->va_display, va_profiles, &va_num_profiles);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaQueryConfigProfiles failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
goto cleanup;
}
/*check whether profile is supported*/
for(index= 0; index < va_num_profiles; index++) {
if(VAProfileJPEGBaseline == va_profiles[index])
break;
}
if(index == va_num_profiles) {
WTRACE("Profile not surportted\n");
status = DECODE_FAIL;
goto cleanup;
}
va_status = vaQueryConfigEntrypoints(jd_libva_ptr->va_display, VAProfileJPEGBaseline, va_entrypoints, &va_num_entrypoints);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaQueryConfigProfiles failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
goto cleanup;
}
/* traverse entrypoints arrary to see whether VLD is there */
for (index = 0; index < va_num_entrypoints; index ++) {
if (va_entrypoints[index] == VAEntrypointVLD)
break;
}
#endif
VAConfigAttrib attrib;
attrib.type = VAConfigAttribRTFormat;
va_status = vaGetConfigAttributes(jd_libva_ptr->va_display, VAProfileJPEGBaseline, VAEntrypointVLD, &attrib, 1);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaGetConfigAttributes failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
goto cleanup;
}
if ((VA_RT_FORMAT_YUV444 & attrib.value) == 0) {
WTRACE("Format not surportted\n");
status = DECODE_FAIL;
goto cleanup;
}
va_status = vaCreateConfig(jd_libva_ptr->va_display, VAProfileJPEGBaseline, VAEntrypointVLD, &attrib, 1, &(jd_libva_ptr->va_config));
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateConfig failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
goto cleanup;
}
jd_libva_ptr->initialized = TRUE;
status = DECODE_SUCCESS;
cleanup:
#if 0
/*free profiles and entrypoints*/
if (va_profiles)
free(va_profiles);
if (va_entrypoints)
free (va_entrypoints);
#endif
if (!status) {
jd_libva_ptr->initialized = TRUE; // make sure we can call into jva_deinitialize()
jdva_deinitialize (jd_libva_ptr);
return status;
}
return status;
}
void jdva_deinitialize (jd_libva_struct * jd_libva_ptr) {
if (!(jd_libva_ptr->initialized)) {
return;
}
if (jd_libva_ptr->JPEGParser) {
free(jd_libva_ptr->JPEGParser);
jd_libva_ptr->JPEGParser = NULL;
}
if (jd_libva_ptr->va_display) {
vaTerminate(jd_libva_ptr->va_display);
jd_libva_ptr->va_display = NULL;
}
if (jd_libva_ptr->android_display) {
free(jd_libva_ptr->android_display);
jd_libva_ptr->android_display = NULL;
}
jd_libva_ptr->initialized = FALSE;
return;
}
Decode_Status jdva_create_resource (jd_libva_struct * jd_libva_ptr) {
VAStatus va_status = VA_STATUS_SUCCESS;
Decode_Status status;
jd_libva_ptr->image_width = jd_libva_ptr->picture_param_buf.picture_width;
jd_libva_ptr->image_height = jd_libva_ptr->picture_param_buf.picture_height;
jd_libva_ptr->surface_count = 1;
jd_libva_ptr->va_surfaces = (VASurfaceID *) malloc(sizeof(VASurfaceID)*jd_libva_ptr->surface_count);
if (jd_libva_ptr->va_surfaces == NULL) {
return DECODE_MEMORY_FAIL;
}
va_status = vaCreateSurfaces(jd_libva_ptr->va_display, VA_RT_FORMAT_YUV444,
(((jd_libva_ptr->image_width + 7) & (~7)) + 15) & (~15),
(((jd_libva_ptr->image_width + 7) & (~7)) + 15) & (~15),
jd_libva_ptr->va_surfaces,
jd_libva_ptr->surface_count, NULL, 0);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateSurfaces failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
goto cleanup;
}
va_status = vaCreateContext(jd_libva_ptr->va_display, jd_libva_ptr->va_config,
(( ( jd_libva_ptr->image_width + 7 ) & ( ~7 )) + 15 ) & ( ~15 ),
((( jd_libva_ptr->image_height + 7 ) & ( ~7 )) + 15 ) & ( ~15 ),
0, //VA_PROGRESSIVE
jd_libva_ptr->va_surfaces,
jd_libva_ptr->surface_count, &(jd_libva_ptr->va_context));
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateContext failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
goto cleanup;
}
jd_libva_ptr->resource_allocated = TRUE;
return status;
cleanup:
if (jd_libva_ptr->va_surfaces) {
free (jd_libva_ptr->va_surfaces);
jd_libva_ptr->va_surfaces = NULL;
}
jdva_deinitialize (jd_libva_ptr);
return status;
}
Decode_Status jdva_release_resource (jd_libva_struct * jd_libva_ptr) {
Decode_Status status = DECODE_SUCCESS;
VAStatus va_status = VA_STATUS_SUCCESS;
if (!(jd_libva_ptr->resource_allocated)) {
return status;
}
if (!(jd_libva_ptr->va_display)) {
return status; //most likely the resource are already released and HW jpeg is deinitialize, return directly
}
/*
* It is safe to destroy Surface/Config/Context severl times
* and it is also safe even their value is NULL
*/
va_status = vaDestroySurfaces(jd_libva_ptr->va_display, jd_libva_ptr->va_surfaces, jd_libva_ptr->surface_count);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaDestroySurfaces failed. va_status = 0x%x", va_status);
return DECODE_DRIVER_FAIL;
}
if (jd_libva_ptr->va_surfaces) {
free (jd_libva_ptr->va_surfaces);
jd_libva_ptr->va_surfaces = NULL;
}
va_status = vaDestroyConfig(jd_libva_ptr->va_display, jd_libva_ptr->va_config);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaDestroyConfig failed. va_status = 0x%x", va_status);
return DECODE_DRIVER_FAIL;
}
jd_libva_ptr->va_config = NULL;
va_status = vaDestroyContext(jd_libva_ptr->va_display, jd_libva_ptr->va_context);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaDestroyContext failed. va_status = 0x%x", va_status);
return DECODE_DRIVER_FAIL;
}
jd_libva_ptr->va_context = NULL;
jd_libva_ptr->resource_allocated = FALSE;
return va_status;
}
Decode_Status jdva_decode (jd_libva_struct * jd_libva_ptr, uint8_t* buf) {
Decode_Status status = DECODE_SUCCESS;
VAStatus va_status = VA_STATUS_SUCCESS;
VABufferID desc_buf[5];
uint32_t bitstream_buffer_size;
uint32_t scan_idx = 0;
uint32_t buf_idx = 0;
uint32_t chopping = VA_SLICE_DATA_FLAG_ALL;
uint32_t bytes_remaining = jd_libva_ptr->file_size;
uint32_t src_offset = 0;
bitstream_buffer_size = 1024*512*5;
va_status = vaBeginPicture(jd_libva_ptr->va_display, jd_libva_ptr->va_context, jd_libva_ptr->va_surfaces[0]);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaBeginPicture failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
return status;
}
va_status = vaCreateBuffer(jd_libva_ptr->va_display, jd_libva_ptr->va_context, VAPictureParameterBufferType, sizeof(VAPictureParameterBufferJPEG), 1, &jd_libva_ptr->picture_param_buf, &desc_buf[buf_idx]);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateBuffer failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
return status;
}
buf_idx++;
va_status = vaCreateBuffer(jd_libva_ptr->va_display, jd_libva_ptr->va_context, VAIQMatrixBufferType, sizeof(VAIQMatrixParameterBufferJPEG), 1, &jd_libva_ptr->qmatrix_buf, &desc_buf[buf_idx]);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateBuffer failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
return status;
}
buf_idx++;
va_status = vaCreateBuffer(jd_libva_ptr->va_display, jd_libva_ptr->va_context, VAHuffmanTableBufferType, sizeof(VAHuffmanTableParameterBufferJPEG), 1, &jd_libva_ptr->hufman_table_buf, &desc_buf[buf_idx]);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateBuffer failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
return status;
}
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 */
VASliceParameterBufferJPEG dest_scan_ctrl[JPEG_MAX_COMPONENTS];
uint32_t src_idx;
uint32_t dest_idx = 0;
memset(dest_scan_ctrl, 0, sizeof(dest_scan_ctrl));
for (src_idx = scan_idx; src_idx < jd_libva_ptr->scan_ctrl_count ; src_idx++) {
if (jd_libva_ptr->slice_param_buf[ src_idx ].slice_data_offset) {
/* new scan, reset state machine */
chopping = VA_SLICE_DATA_FLAG_ALL;
fprintf(stderr,"Scan:%i FileOffset:%x Bytes:%x \n", src_idx,
jd_libva_ptr->slice_param_buf[ src_idx ].slice_data_offset,
jd_libva_ptr->slice_param_buf[ src_idx ].slice_data_size );
/* does the slice end in the buffer */
if (jd_libva_ptr->slice_param_buf[ src_idx ].slice_data_offset + jd_libva_ptr->slice_param_buf[ src_idx ].slice_data_size > bytes + src_offset) {
chopping = VA_SLICE_DATA_FLAG_BEGIN;
}
} else {
if (jd_libva_ptr->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;
dest_scan_ctrl[dest_idx].slice_data_offset = ((chopping == VA_SLICE_DATA_FLAG_ALL) || (chopping == VA_SLICE_DATA_FLAG_BEGIN) )?
jd_libva_ptr->slice_param_buf[ src_idx ].slice_data_offset - src_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 < jd_libva_ptr->slice_param_buf[src_idx].slice_data_size) ? bytes_in_seg : jd_libva_ptr->slice_param_buf[src_idx].slice_data_size ;
jd_libva_ptr->slice_param_buf[src_idx].slice_data_offset = 0;
jd_libva_ptr->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 = jd_libva_ptr->slice_param_buf[src_idx].num_components;
dest_scan_ctrl[dest_idx].restart_interval = jd_libva_ptr->slice_param_buf[src_idx].restart_interval;
memcpy(&dest_scan_ctrl[dest_idx].components, & jd_libva_ptr->slice_param_buf[ src_idx ].components,
sizeof(jd_libva_ptr->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(jd_libva_ptr->va_display, jd_libva_ptr->va_context, VASliceParameterBufferType, sizeof(VASliceParameterBufferJPEG) * dest_idx, 1, dest_scan_ctrl, &desc_buf[buf_idx]);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateBuffer failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
return status;
}
buf_idx++;
va_status = vaCreateBuffer(jd_libva_ptr->va_display, jd_libva_ptr->va_context, VASliceDataBufferType, bytes, 1, &jd_libva_ptr->bitstream_buf[ src_offset ], &desc_buf[buf_idx]);
buf_idx++;
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaCreateBuffer failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
return status;
}
va_status = vaRenderPicture( jd_libva_ptr->va_display, jd_libva_ptr->va_context, desc_buf, buf_idx);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaRenderPicture failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
return status;
}
buf_idx = 0;
src_offset += bytes;
} while (bytes_remaining);
va_status = vaEndPicture(jd_libva_ptr->va_display, jd_libva_ptr->va_context);
if (va_status != VA_STATUS_SUCCESS) {
ETRACE("vaRenderPicture failed. va_status = 0x%x", va_status);
status = DECODE_DRIVER_FAIL;
return status;
}
va_status = vaSyncSurface(jd_libva_ptr->va_display, jd_libva_ptr->va_surfaces[0]);
if (va_status != VA_STATUS_SUCCESS) {
WTRACE("vaSyncSurface failed. va_status = 0x%x", va_status);
}
#if 0
uint8_t* rgb_buf;
int32_t data_len = 0;
uint32_t surface_width, surface_height;
surface_width = (( ( jd_libva_ptr->image_width + 7 ) & ( ~7 )) + 15 ) & ( ~15 );
surface_height = (( ( jd_libva_ptr->image_height + 7 ) & ( ~7 )) + 15 ) & ( ~15 );
rgb_buf = (uint8_t*) malloc((surface_width * surface_height) << 2);
if(rgb_buf == NULL){
return DECODE_MEMORY_FAIL;
}
va_status = vaPutSurfaceBuf(jd_libva_ptr->va_display, jd_libva_ptr->va_surfaces[0], rgb_buf, &data_len, 0, 0, surface_width, surface_height, 0, 0, surface_width, surface_height, NULL, 0, 0);
buf = rgb_buf;
// dump RGB data
{
FILE *pf_tmp = fopen("img_out.rgb", "wb");
if(pf_tmp == NULL)
ETRACE("Open file error");
fwrite(rgb_buf, 1, surface_width * surface_height * 4, pf_tmp);
fclose(pf_tmp);
}
#endif
#if 0
va_status = vaDeriveImage(jd_libva_ptr->va_display, jd_libva_ptr->va_surfaces[0], &(jd_libva_ptr->surface_image));
if (va_status != VA_STATUS_SUCCESS) {
ERREXIT1 (cinfo, JERR_VA_DRIVEIMAGE, va_status);
}
va_status = vaMapBuffer(jd_libva_ptr->va_display, jd_libva_ptr->surface_image.buf, (void **)& (jd_libva_ptr->image_buf));
if (va_status != VA_STATUS_SUCCESS) {
ERREXIT1 (cinfo, JERR_VA_MAPBUFFER, va_status);
}
va_status = vaUnmapBuffer(jd_libva_ptr->va_display, jd_libva_ptr->surface_image.buf);
if (va_status != VA_STATUS_SUCCESS) {
ERREXIT1(cinfo, JERR_VA_MAPBUFFER, va_status);
}
va_status = vaDestroyImage(jd_libva_ptr->va_display, jd_libva_ptr->surface_image.image_id);
if (va_status != VA_STATUS_SUCCESS) {
ERREXIT1 (cinfo, JERR_VA_MAPBUFFER, va_status);
}
#endif
return status;
}
Decode_Status parseBitstream(jd_libva_struct * jd_libva_ptr) {
uint32_t component_order = 0 ;
uint32_t dqt_ind = 0;
uint32_t dht_ind = 0;
uint32_t scan_ind = 0;
boolean frame_marker_found = FALSE;
uint8_t marker = jd_libva_ptr->JPEGParser->getNextMarker(jd_libva_ptr->JPEGParser);
while (marker != CODE_EOI) {
switch (marker) {
// 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 = jd_libva_ptr->JPEGParser->readBytes(jd_libva_ptr->JPEGParser, 2) - 2;
jd_libva_ptr->JPEGParser->burnBytes(jd_libva_ptr->JPEGParser, bytes_to_burn);
break;
}
// Store offset to DQT data to avoid parsing bitstream in user mode
case CODE_DQT: {
jd_libva_ptr->dqt_byte_offset[dqt_ind] = jd_libva_ptr->JPEGParser->getByteOffset(jd_libva_ptr->JPEGParser);
dqt_ind++;
uint32_t bytes_to_burn = jd_libva_ptr->JPEGParser->readBytes( jd_libva_ptr->JPEGParser, 2 ) - 2;
jd_libva_ptr->JPEGParser->burnBytes( jd_libva_ptr->JPEGParser, bytes_to_burn );
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: {
fprintf(stderr, "ERROR: unsupport SOF\n");
break;
}
// Parse component information in SOF marker
case CODE_SOF_BASELINE: {
frame_marker_found = TRUE;
jd_libva_ptr->JPEGParser->burnBytes(jd_libva_ptr->JPEGParser, 2); // Throw away frame header length
jd_libva_ptr->picture_param_buf.sample_precision = jd_libva_ptr->JPEGParser->readNextByte(jd_libva_ptr->JPEGParser);
if (jd_libva_ptr->picture_param_buf.sample_precision != 8) {
return DECODE_PARSER_FAIL;
}
// Extract pic width and height
jd_libva_ptr->picture_param_buf.picture_height = jd_libva_ptr->JPEGParser->readBytes(jd_libva_ptr->JPEGParser, 2);
jd_libva_ptr->picture_param_buf.picture_width = jd_libva_ptr->JPEGParser->readBytes(jd_libva_ptr->JPEGParser, 2);
jd_libva_ptr->picture_param_buf.num_components = jd_libva_ptr->JPEGParser->readNextByte(jd_libva_ptr->JPEGParser);
if (jd_libva_ptr->picture_param_buf.num_components > JPEG_MAX_COMPONENTS) {
return DECODE_PARSER_FAIL;
}
uint8_t comp_ind;
for (comp_ind = 0; comp_ind < jd_libva_ptr->picture_param_buf.num_components; comp_ind++) {
jd_libva_ptr->picture_param_buf.components[comp_ind].component_id = jd_libva_ptr->JPEGParser->readNextByte(jd_libva_ptr->JPEGParser);
uint8_t hv_sampling = jd_libva_ptr->JPEGParser->readNextByte(jd_libva_ptr->JPEGParser);
jd_libva_ptr->picture_param_buf.components[comp_ind].h_sampling_factor = hv_sampling >> 4;
jd_libva_ptr->picture_param_buf.components[comp_ind].v_sampling_factor = hv_sampling & 0xf;
jd_libva_ptr->picture_param_buf.components[comp_ind].quantiser_table_selector = jd_libva_ptr->JPEGParser->readNextByte(jd_libva_ptr->JPEGParser);
}
break;
}
// Store offset to DHT data to avoid parsing bitstream in user mode
case CODE_DHT: {
jd_libva_ptr->dht_byte_offset[dht_ind] = jd_libva_ptr->JPEGParser->getByteOffset(jd_libva_ptr->JPEGParser);
dht_ind++;
uint32_t bytes_to_burn = jd_libva_ptr->JPEGParser->readBytes(jd_libva_ptr->JPEGParser, 2) - 2;
jd_libva_ptr->JPEGParser->burnBytes(jd_libva_ptr->JPEGParser, bytes_to_burn );
break;
}
// Parse component information in SOS marker
case CODE_SOS: {
jd_libva_ptr->JPEGParser->burnBytes(jd_libva_ptr->JPEGParser, 2);
uint32_t component_in_scan = jd_libva_ptr->JPEGParser->readNextByte(jd_libva_ptr->JPEGParser);
uint8_t comp_ind;
for (comp_ind = 0; comp_ind < component_in_scan; comp_ind++) {
uint8_t comp_id = jd_libva_ptr->JPEGParser->readNextByte(jd_libva_ptr->JPEGParser);
uint8_t comp_data_ind;
for (comp_data_ind = 0; comp_data_ind < jd_libva_ptr->picture_param_buf.num_components; comp_data_ind++) {
if (comp_id == jd_libva_ptr->picture_param_buf.components[comp_data_ind].component_id) {
jd_libva_ptr->slice_param_buf[scan_ind].components[comp_ind].component_selector = comp_data_ind;
break;
}
}
uint8_t huffman_tables = jd_libva_ptr->JPEGParser->readNextByte(jd_libva_ptr->JPEGParser);
jd_libva_ptr->slice_param_buf[scan_ind].components[comp_ind].dc_table_selector = huffman_tables >> 4;
jd_libva_ptr->slice_param_buf[scan_ind].components[comp_ind].ac_table_selector = huffman_tables & 0xf;
}
uint32_t curr_byte = jd_libva_ptr->JPEGParser->readNextByte(jd_libva_ptr->JPEGParser); // Ss
if (curr_byte != 0) {
return DECODE_PARSER_FAIL;
}
curr_byte = jd_libva_ptr->JPEGParser->readNextByte(jd_libva_ptr->JPEGParser); // Se
if (curr_byte != 0x3f) {
return DECODE_PARSER_FAIL;
}
curr_byte = jd_libva_ptr->JPEGParser->readNextByte(jd_libva_ptr->JPEGParser); // Ah, Al
if (curr_byte != 0) {
return DECODE_PARSER_FAIL;
}
// Set slice control variables needed
jd_libva_ptr->slice_param_buf[scan_ind].slice_data_offset = jd_libva_ptr->JPEGParser->getByteOffset(jd_libva_ptr->JPEGParser);
jd_libva_ptr->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 */
jd_libva_ptr->slice_param_buf[scan_ind - 1].slice_data_size =
(jd_libva_ptr->slice_param_buf[scan_ind].slice_data_offset - jd_libva_ptr->slice_param_buf[scan_ind - 1].slice_data_offset );;
}
scan_ind++;
jd_libva_ptr->scan_ctrl_count++; // gsDXVA2Globals.uiScanCtrlCount
break;
}
case CODE_DRI: {
uint32_t size = jd_libva_ptr->JPEGParser->readBytes(jd_libva_ptr->JPEGParser, 2);
jd_libva_ptr->slice_param_buf[scan_ind].restart_interval = jd_libva_ptr->JPEGParser->readBytes(jd_libva_ptr->JPEGParser, 2);
jd_libva_ptr->JPEGParser->burnBytes(jd_libva_ptr->JPEGParser, (size - 4));
break;
}
default:
break;
}
marker = jd_libva_ptr->JPEGParser->getNextMarker(jd_libva_ptr->JPEGParser);
}
jd_libva_ptr->quant_tables_num = dqt_ind;
jd_libva_ptr->huffman_tables_num = dht_ind;
/* The slice for the last scan should run up to the end of the picture */
jd_libva_ptr->slice_param_buf[scan_ind - 1].slice_data_size = (jd_libva_ptr->file_size - jd_libva_ptr->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 DECODE_PARSER_FAIL;
}
parseTableData(jd_libva_ptr);
return DECODE_SUCCESS;
}
Decode_Status parseTableData(jd_libva_struct * jd_libva_ptr) {
Decode_Status status;
CJPEGParse* parser = (CJPEGParse*)malloc(sizeof(CJPEGParse));
if (parser == NULL)
return DECODE_MEMORY_FAIL;
parserInitialize(parser, jd_libva_ptr->bitstream_buf, jd_libva_ptr->file_size);
// Parse Quant tables
memset(&jd_libva_ptr->qmatrix_buf, 0, sizeof(jd_libva_ptr->qmatrix_buf));
uint32_t dqt_ind;
for (dqt_ind = 0; dqt_ind < jd_libva_ptr->quant_tables_num; dqt_ind++) {
if (parser->setByteOffset(parser, jd_libva_ptr->dqt_byte_offset[dqt_ind])) {
// uint32_t uiTableBytes = parser->readBytes( 2 ) - 2;
uint32_t table_bytes = parser->readBytes( parser, 2 ) - 2;
do {
uint32_t table_info = parser->readNextByte(parser);
table_bytes--;
uint32_t table_length = table_bytes > 64 ? 64 : table_bytes;
uint32_t table_precision = table_info >> 4;
if (table_precision != 0) {
return DECODE_PARSER_FAIL;
}
uint32_t table_id = table_info & 0xf;
if (table_id >= JPEG_MAX_QUANT_TABLES) {
return DECODE_PARSER_FAIL;
}
jd_libva_ptr->qmatrix_buf.load_quantiser_table[dqt_ind] = table_id;
// Pull Quant table data from bitstream
uint32_t byte_ind;
for (byte_ind = 0; byte_ind < table_length; byte_ind++) {
jd_libva_ptr->qmatrix_buf.quantiser_table[table_id][byte_ind] = parser->readNextByte(parser);
}
table_bytes -= table_length;
} while (table_bytes);
}
}
// Parse Huffman tables
memset(&jd_libva_ptr->hufman_table_buf, 0, sizeof(jd_libva_ptr->hufman_table_buf));
uint32_t dht_ind;
for (dht_ind = 0; dht_ind < jd_libva_ptr->huffman_tables_num; dht_ind++) {
if (parser->setByteOffset(parser, jd_libva_ptr->dht_byte_offset[dht_ind])) {
uint32_t table_bytes = parser->readBytes( parser, 2 ) - 2;
do {
uint32_t table_info = parser->readNextByte(parser);
table_bytes--;
uint32_t table_class = table_info >> 4; // Identifies whether the table is for AC or DC
if (table_class >= TABLE_CLASS_NUM) {
return DECODE_PARSER_FAIL;
}
uint32_t table_id = table_info & 0xf;
if (table_id >= JPEG_MAX_SETS_HUFFMAN_TABLES) {
return DECODE_PARSER_FAIL;
}
if (table_class == 0) {
uint8_t* bits = parser->getCurrentIndex(parser);
// 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++) {
jd_libva_ptr->hufman_table_buf.huffman_table[table_id].num_dc_codes[bit_ind] = bits[bit_ind];
table_entries += jd_libva_ptr->hufman_table_buf.huffman_table[table_id].num_dc_codes[bit_ind];
}
// Create table of code values
parser->burnBytes(parser, 16);
table_bytes -= 16;
uint32_t tbl_ind;
for (tbl_ind = 0; tbl_ind < table_entries; tbl_ind++) {
jd_libva_ptr->hufman_table_buf.huffman_table[table_id].dc_values[tbl_ind] = parser->readNextByte(parser);
table_bytes--;
}
} else { // for AC class
uint8_t* bits = parser->getCurrentIndex(parser);
// 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++) {
jd_libva_ptr->hufman_table_buf.huffman_table[table_id].num_ac_codes[bit_ind] = bits[bit_ind];
table_entries += jd_libva_ptr->hufman_table_buf.huffman_table[table_id].num_ac_codes[bit_ind];
}
// Create table of code values
parser->burnBytes(parser, 16);
table_bytes -= 16;
uint32_t tbl_ind;
for (tbl_ind = 0; tbl_ind < table_entries; tbl_ind++) {
jd_libva_ptr->hufman_table_buf.huffman_table[table_id].ac_values[tbl_ind] = parser->readNextByte(parser);
table_bytes--;
}
}//end of else
} while (table_bytes);
}
}
if (parser) {
free(parser);
parser = NULL;
}
return DECODE_SUCCESS;
}