/*
* Copyright (c) 2011 Intel Corporation. All Rights Reserved.
* Copyright (c) Imagination Technologies Limited, UK
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Elaine Wang <elaine.wang@intel.com>
*
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "psb_def.h"
#include "psb_drv_debug.h"
#include "psb_surface.h"
#include "psb_cmdbuf.h"
#include "pnw_jpeg.h"
#include "pnw_hostcode.h"
#include "pnw_hostheader.h"
#include "pnw_hostjpeg.h"
#define INIT_CONTEXT_JPEG context_ENC_p ctx = (context_ENC_p) obj_context->format_data
#define SURFACE(id) ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id ))
#define BUFFER(id) ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id ))
/*
Balancing the workloads of executing MTX_CMDID_ISSUEBUFF commands to 2-cores:
1 commands: 0 (0b/0x0)
2 commands: 1-0 (01b/0x1)
3 commands: 1-0-0 (001b/0x1)
4 commands: 1-0-1-0 (0101b/0x5)
5 commands: 1-0-1-0-0 (00101b/0x5)
6 commands: 1-0-1-0-1-0 (010101b/0x15)
7 commands: 1-0-1-0-1-0-0 (0010101b/0x15)
*/
static const uint32_t aui32_jpg_mtx_num[PNW_JPEG_MAX_SCAN_NUM] = {0x0, 0x1, 0x1, 0x5, 0x5, 0x15, 0x15};
static void pnw_jpeg_QueryConfigAttributes(
VAProfile __maybe_unused profile,
VAEntrypoint __maybe_unused entrypoint,
VAConfigAttrib *attrib_list,
int num_attribs)
{
int i;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_QueryConfigAttributes\n");
/* RateControl attributes */
for (i = 0; i < num_attribs; i++) {
switch (attrib_list[i].type) {
case VAConfigAttribRTFormat:
/* Already handled in psb_GetConfigAttributes */
break;
case VAConfigAttribEncJPEG:
/* The below JPEG ENC capabilities are fixed by TopazSC and not changable. */
{
VAConfigAttribValEncJPEG* ptr = (VAConfigAttribValEncJPEG *)&(attrib_list[i].value);
(ptr->bits).arithmatic_coding_mode = 0; /* Unsupported */
(ptr->bits).progressive_dct_mode = 0; /* Unsupported */
(ptr->bits).non_interleaved_mode = 1; /* Supported */
(ptr->bits).differential_mode = 0; /* Unsupported */
(ptr->bits).max_num_components = PNW_JPEG_COMPONENTS_NUM; /* Only 3 is supported */
(ptr->bits).max_num_scans = PNW_JPEG_MAX_SCAN_NUM;
(ptr->bits).max_num_huffman_tables = 4; /* Only 4 is supported */
(ptr->bits).max_num_huffman_tables = 2; /* Only 2 is supported */
}
break;
case VAConfigAttribMaxPictureWidth:
case VAConfigAttribMaxPictureHeight:
/* No pure limitation on an image's width or height seperately,
as long as the image's MCUs need less than max_num_scans rounds of encoding
and a surface of that source size is allocatable. */
attrib_list[i].value = 0; /* No pure limitation */
break;
default:
attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
break;
}
}
return;
}
static VAStatus pnw_jpeg_ValidateConfig(
object_config_p obj_config)
{
int i;
/* Check all attributes */
for (i = 0; i < obj_config->attrib_count; i++) {
switch (obj_config->attrib_list[i].type) {
case VAConfigAttribRTFormat:
/* Ignore */
break;
case VAConfigAttribRateControl:
break;
default:
return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
}
}
return VA_STATUS_SUCCESS;
}
/*Init JPEG context. Ported from IMG_JPEG_EncoderInitialise*/
static VAStatus pnw_jpeg_CreateContext(
object_context_p obj_context,
object_config_p obj_config)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
context_ENC_p ctx;
TOPAZSC_JPEG_ENCODER_CONTEXT *jpeg_ctx_p;
int i;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_CreateContext\n");
vaStatus = pnw_CreateContext(obj_context, obj_config, 1);
if (VA_STATUS_SUCCESS != vaStatus)
return VA_STATUS_ERROR_ALLOCATION_FAILED;
ctx = (context_ENC_p) obj_context->format_data;
ctx->eCodec = IMG_CODEC_JPEG;
for (i = 0; i < obj_config->attrib_count; i++) {
if (VAConfigAttribRTFormat == obj_config->attrib_list[i].type) {
switch (obj_config->attrib_list[i].value) {
case VA_RT_FORMAT_YUV420:
if (obj_context->render_targets != NULL) {
object_surface_p surface_p = SURFACE(obj_context->render_targets[0]);
if (NULL == surface_p) {
ctx->eFormat = IMG_CODEC_PL12;
drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG encoding: Unsupported format and set to NV12\n");
break;
}
if ((surface_p->psb_surface)->extra_info[4] == VA_FOURCC_NV12) {
ctx->eFormat = IMG_CODEC_PL12;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPEG encoding: Choose NV12 format\n");
}
else if ((surface_p->psb_surface)->extra_info[4] == VA_FOURCC_IYUV) {
ctx->eFormat = IMG_CODEC_IYUV;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPEG encoding: Choose IYUV format\n");
}
else {
ctx->eFormat = IMG_CODEC_PL12;
drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG encoding: Unsupported format and set to NV12\n");
}
}
else {
ctx->eFormat = IMG_CODEC_PL12;
drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG encoding: Unsupported format and set to NV12\n");
}
break;
case VA_RT_FORMAT_YUV422:
ctx->eFormat = IMG_CODEC_YV16;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPEG encoding: Choose YUV422 format\n");
break;
default:
ctx->eFormat = IMG_CODEC_PL12;
drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG encoding: Unsupported format and set to NV12\n");
break;
}
break;
}
}
ctx->Slices = 2;
ctx->ParallelCores = 2;
ctx->NumCores = 2;
ctx->jpeg_ctx = (TOPAZSC_JPEG_ENCODER_CONTEXT *)calloc(1, sizeof(TOPAZSC_JPEG_ENCODER_CONTEXT));
CHECK_ALLOCATION(ctx->jpeg_ctx);
jpeg_ctx_p = ctx->jpeg_ctx;
jpeg_ctx_p->eFormat = ctx->eFormat;
/*Chroma sampling step x_step X y_step*/
jpeg_ctx_p->ui8ScanNum = JPEG_SCANNING_COUNT(ctx->Width, ctx->Height, ctx->NumCores, jpeg_ctx_p->eFormat);
if (jpeg_ctx_p->ui8ScanNum < 2 || jpeg_ctx_p->ui8ScanNum > PNW_JPEG_MAX_SCAN_NUM) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG MCU scanning number(%d) is wrong!\n", jpeg_ctx_p->ui8ScanNum);
free(ctx->jpeg_ctx);
ctx->jpeg_ctx = NULL;
return VA_STATUS_ERROR_UNKNOWN;
}
jpeg_ctx_p->sScan_Encode_Info.ui8NumberOfCodedBuffers = jpeg_ctx_p->ui8ScanNum;
drv_debug_msg(VIDEO_DEBUG_GENERAL, " JPEG Scanning Number %d\n", jpeg_ctx_p->ui8ScanNum);
jpeg_ctx_p->sScan_Encode_Info.aBufferTable =
(TOPAZSC_JPEG_BUFFER_INFO *)calloc(1, sizeof(TOPAZSC_JPEG_BUFFER_INFO)
* jpeg_ctx_p->sScan_Encode_Info.ui8NumberOfCodedBuffers);
if (NULL == jpeg_ctx_p->sScan_Encode_Info.aBufferTable)
return VA_STATUS_ERROR_ALLOCATION_FAILED;
/*It will be figured out when known the size of whole coded buffer.*/
jpeg_ctx_p->ui32SizePerCodedBuffer = 0;
jpeg_ctx_p->ctx = (unsigned char *)ctx;
/*Reuse header_mem(76*4 bytes) and pic_params_size(256 bytes)
* as pMemInfoMTXSetup(JPEG_MTX_DMA_SETUP 24x4 bytes) and
* pMemInfoTableBlock JPEG_MTX_QUANT_TABLE(128byes)*/
return vaStatus;
}
static void pnw_jpeg_DestroyContext(
object_context_p obj_context)
{
context_ENC_p ctx;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_DestroyPicture\n");
ctx = (context_ENC_p)(obj_context->format_data);
if (ctx->jpeg_ctx) {
if (ctx->jpeg_ctx->sScan_Encode_Info.aBufferTable) {
free(ctx->jpeg_ctx->sScan_Encode_Info.aBufferTable);
ctx->jpeg_ctx->sScan_Encode_Info.aBufferTable = NULL;
}
free(ctx->jpeg_ctx);
}
pnw_DestroyContext(obj_context);
}
static VAStatus pnw_jpeg_BeginPicture(
object_context_p obj_context)
{
INIT_CONTEXT_JPEG;
VAStatus vaStatus = VA_STATUS_SUCCESS;
int ret;
pnw_cmdbuf_p cmdbuf;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_BeginPicture: Frame %d\n", ctx->obj_context->frame_count);
ctx->src_surface = ctx->obj_context->current_render_target;
/* Initialise the command buffer */
ret = pnw_context_get_next_cmdbuf(ctx->obj_context);
if (ret) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "get next cmdbuf fail\n");
vaStatus = VA_STATUS_ERROR_UNKNOWN;
return vaStatus;
}
cmdbuf = ctx->obj_context->pnw_cmdbuf;
/* map start_pic param */
vaStatus = psb_buffer_map(&cmdbuf->pic_params, &cmdbuf->pic_params_p);
if (vaStatus) {
return vaStatus;
}
vaStatus = psb_buffer_map(&cmdbuf->header_mem, &cmdbuf->header_mem_p);
if (vaStatus) {
psb_buffer_unmap(&cmdbuf->pic_params);
return vaStatus;
}
memset(ctx->jpeg_ctx->sScan_Encode_Info.aBufferTable, 0,
sizeof(TOPAZSC_JPEG_BUFFER_INFO) * ctx->jpeg_ctx->sScan_Encode_Info.ui8NumberOfCodedBuffers);
/*Store the QMatrix data*/
ctx->jpeg_ctx->pMemInfoTableBlock = cmdbuf->pic_params_p;
ctx->jpeg_ctx->psTablesBlock = (JPEG_MTX_QUANT_TABLE *)ctx->jpeg_ctx->pMemInfoTableBlock;
/*Store MTX_SETUP data*/
ctx->jpeg_ctx->pMemInfoMTXSetup = cmdbuf->header_mem_p;
ctx->jpeg_ctx->pMTXSetup = (JPEG_MTX_DMA_SETUP*)ctx->jpeg_ctx->pMemInfoMTXSetup;
ctx->jpeg_ctx->pMTXSetup->ui32ComponentsInScan = PNW_JPEG_COMPONENTS_NUM;
if (ctx->obj_context->frame_count == 0) { /* first picture */
psb_driver_data_p driver_data = ctx->obj_context->driver_data;
*cmdbuf->cmd_idx++ = ((MTX_CMDID_SW_NEW_CODEC & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) |
(((driver_data->drm_context & MTX_CMDWORD_COUNT_MASK) << MTX_CMDWORD_COUNT_SHIFT));
pnw_cmdbuf_insert_command_param(ctx->eCodec);
pnw_cmdbuf_insert_command_param((ctx->Width << 16) | ctx->Height);
}
pnw_jpeg_set_default_qmatix(ctx->jpeg_ctx->pMemInfoTableBlock);
return vaStatus;
}
static VAStatus pnw__jpeg_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
VAEncPictureParameterBufferJPEG *pBuffer;
pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
BUFFER_HEADER *pBufHeader;
//unsigned long *pPictureHeaderMem;
//MTX_HEADER_PARAMS *psPicHeader;
int i;
TOPAZSC_JPEG_ENCODER_CONTEXT *jpeg_ctx = ctx->jpeg_ctx;
JPEG_MTX_QUANT_TABLE* pQMatrix = (JPEG_MTX_QUANT_TABLE *)
(ctx->jpeg_ctx->pMemInfoTableBlock);
IMG_ERRORCODE rc;
ASSERT(obj_buffer->type == VAEncPictureParameterBufferType);
if ((obj_buffer->num_elements != 1) ||
(obj_buffer->size != sizeof(VAEncPictureParameterBufferJPEG))) {
return VA_STATUS_ERROR_UNKNOWN;
}
/* Transfer ownership of VAEncPictureParameterBufferMPEG4 data */
pBuffer = (VAEncPictureParameterBufferJPEG *) obj_buffer->buffer_data;
obj_buffer->buffer_data = NULL;
obj_buffer->size = 0;
/* Parameters checking */
if (((pBuffer->pic_flags).bits.profile != 0) || /* Only "0 - Baseline" is supported */
((pBuffer->pic_flags).bits.progressive != 0) || /* Only "0 - sequential" is supported */
((pBuffer->pic_flags).bits.huffman != 1) || /* Only "1 - huffman" is supported */
((pBuffer->pic_flags).bits.interleaved != 0) || /* Only "0 - non interleaved" is supported */
((pBuffer->pic_flags).bits.differential != 0)) /* Only "0 - non differential" is supported */
return VA_STATUS_ERROR_INVALID_PARAMETER;
if ((pBuffer->sample_bit_depth != 8) || /* Only 8-bits sample depth is supported */
(pBuffer->num_components != PNW_JPEG_COMPONENTS_NUM) || /* Only 3 components setting is supported */
(pBuffer->quality > 100))
return VA_STATUS_ERROR_INVALID_PARAMETER;
/* Set quality */
if (pBuffer->quality != 0) { /* Quality value is set */
customize_quantization_tables(pQMatrix->aui8LumaQuantParams,
pQMatrix->aui8ChromaQuantParams,
pBuffer->quality);
}
/* Get the width and height of encode destination */
jpeg_ctx->ui32OutputWidth = (unsigned short)(~0x1 & (pBuffer->picture_width + 0x1));
jpeg_ctx->ui32OutputHeight = (unsigned short)(~0x1 & (pBuffer->picture_height + 0x1));
ASSERT(ctx->Width >= jpeg_ctx->ui32OutputWidth);
ASSERT(ctx->Height >= jpeg_ctx->ui32OutputHeight);
/*Overwrite the scan info if destination's sizes are different from source's */
if ((ctx->Width!=jpeg_ctx->ui32OutputWidth) || (ctx->Height!=jpeg_ctx->ui32OutputHeight)) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Overwriting the scan info...\n");
jpeg_ctx->ui8ScanNum = JPEG_SCANNING_COUNT(jpeg_ctx->ui32OutputWidth, jpeg_ctx->ui32OutputHeight, ctx->NumCores, jpeg_ctx->eFormat);
if (jpeg_ctx->ui8ScanNum < 2 || jpeg_ctx->ui8ScanNum > PNW_JPEG_MAX_SCAN_NUM) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG MCU scanning number(%d) is wrong!\n", jpeg_ctx->ui8ScanNum);
free(ctx->jpeg_ctx);
ctx->jpeg_ctx = NULL;
return VA_STATUS_ERROR_UNKNOWN;
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPEG Scanning Number %d\n", jpeg_ctx->ui8ScanNum);
jpeg_ctx->sScan_Encode_Info.ui8NumberOfCodedBuffers = jpeg_ctx->ui8ScanNum;
}
ctx->coded_buf = BUFFER(pBuffer->coded_buf);
free(pBuffer);
if (NULL == ctx->coded_buf) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__);
return VA_STATUS_ERROR_INVALID_BUFFER;
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Set Quant Tables\n");
/*Set Quant Tables*/
for (i = ctx->NumCores - 1; i >= 0; i--)
pnw_cmdbuf_insert_command_package(ctx->obj_context,
i,
MTX_CMDID_SETQUANT,
&cmdbuf->pic_params,
0);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Quant Table \n");
for (i=0; i<128; i+=8) {
if (0 == i) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Table 0:\n");
}
else if (64 == i) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Table 1:\n");
}
drv_debug_msg(VIDEO_DEBUG_GENERAL, "%d %d %d %d %d %d %d %d\n",
*((unsigned char *)cmdbuf->pic_params_p+i),
*((unsigned char *)cmdbuf->pic_params_p+i+1),
*((unsigned char *)cmdbuf->pic_params_p+i+2),
*((unsigned char *)cmdbuf->pic_params_p+i+3),
*((unsigned char *)cmdbuf->pic_params_p+i+4),
*((unsigned char *)cmdbuf->pic_params_p+i+5),
*((unsigned char *)cmdbuf->pic_params_p+i+6),
*((unsigned char *)cmdbuf->pic_params_p+i+7));
}
jpeg_ctx->ui32SizePerCodedBuffer =
JPEG_CODED_BUF_SEGMENT_SIZE(ctx->coded_buf->size,
jpeg_ctx->ui32OutputWidth, jpeg_ctx->ui32OutputHeight,
ctx->NumCores, jpeg_ctx->eFormat);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Coded buffer total size is %d,"
"coded segment size per scan is %d\n",
ctx->coded_buf->size, jpeg_ctx->ui32SizePerCodedBuffer);
vaStatus = psb_buffer_map(ctx->coded_buf->psb_buffer, (unsigned char **)&jpeg_ctx->jpeg_coded_buf.pMemInfo);
if (vaStatus) {
drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Map coded_buf failed!");
return vaStatus;
}
jpeg_ctx->jpeg_coded_buf.ui32Size = ctx->coded_buf->size;
jpeg_ctx->jpeg_coded_buf.sLock = BUFFER_FREE;
jpeg_ctx->jpeg_coded_buf.ui32BytesWritten = 0;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Setup JPEG Tables\n");
rc = SetupJPEGTables(ctx->jpeg_ctx, &jpeg_ctx->jpeg_coded_buf, ctx->src_surface);
if (rc != IMG_ERR_OK)
return VA_STATUS_ERROR_UNKNOWN;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Write JPEG Headers to coded buf\n");
pBufHeader = (BUFFER_HEADER *)jpeg_ctx->jpeg_coded_buf.pMemInfo;
pBufHeader->ui32BytesUsed = 0; /* Not include BUFFER_HEADER*/
rc = PrepareHeader(jpeg_ctx, &jpeg_ctx->jpeg_coded_buf, sizeof(BUFFER_HEADER), IMG_TRUE);
if (rc != IMG_ERR_OK)
return VA_STATUS_ERROR_UNKNOWN;
pBufHeader->ui32Reserved3 = PNW_JPEG_HEADER_MAX_SIZE;//Next coded buffer offset
pBufHeader->ui32BytesUsed = jpeg_ctx->jpeg_coded_buf.ui32BytesWritten - sizeof(BUFFER_HEADER);
drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPEG Buffer Header size: %d, File Header size :%d, next codef buffer offset: %d\n",
sizeof(BUFFER_HEADER), pBufHeader->ui32BytesUsed, pBufHeader->ui32Reserved3);
return vaStatus;
}
static VAStatus pnw__jpeg_process_qmatrix_param(context_ENC_p ctx, object_buffer_p obj_buffer)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
VAQMatrixBufferJPEG *pBuffer;
JPEG_MTX_QUANT_TABLE* pQMatrix = (JPEG_MTX_QUANT_TABLE *)
(ctx->jpeg_ctx->pMemInfoTableBlock);
int i;
ASSERT(obj_buffer->type == VAQMatrixBufferType);
pBuffer = (VAQMatrixBufferJPEG *) obj_buffer->buffer_data;
/* Zero value isn't allowed. It will cause JPEG firmware time out */
if (0 != pBuffer->load_lum_quantiser_matrix) {
for (i=0; i<QUANT_TABLE_SIZE_BYTES; ++i)
if (pBuffer->lum_quantiser_matrix[i] != 0)
pQMatrix->aui8LumaQuantParams[i] =
pBuffer->lum_quantiser_matrix[i];
}
if (0 != pBuffer->load_chroma_quantiser_matrix) {
for (i=0; i<QUANT_TABLE_SIZE_BYTES; ++i)
if (pBuffer->chroma_quantiser_matrix[i] != 0)
pQMatrix->aui8ChromaQuantParams[i] =
pBuffer->chroma_quantiser_matrix[i];
}
free(obj_buffer->buffer_data);
obj_buffer->buffer_data = NULL;
return vaStatus;
}
static VAStatus pnw_jpeg_RenderPicture(
object_context_p obj_context,
object_buffer_p *buffers,
int num_buffers)
{
INIT_CONTEXT_JPEG;
VAStatus vaStatus = VA_STATUS_SUCCESS;
int i;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_RenderPicture\n");
for (i = 0; i < num_buffers; i++) {
object_buffer_p obj_buffer = buffers[i];
switch (obj_buffer->type) {
case VAQMatrixBufferType:
drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_RenderPicture got VAQMatrixBufferType\n");
vaStatus = pnw__jpeg_process_qmatrix_param(ctx, obj_buffer);
DEBUG_FAILURE;
break;
case VAEncPictureParameterBufferType:
drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_RenderPicture got VAEncPictureParameterBufferType\n");
vaStatus = pnw__jpeg_process_picture_param(ctx, obj_buffer);
DEBUG_FAILURE;
break;
case VAEncSliceParameterBufferType:
drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_RenderPicture got VAEncSliceParameterBufferJPEG\n");
drv_debug_msg(VIDEO_DEBUG_WARNING, "VAEncSliceParameterBufferJPEG is ignored on TopazSC\n");
vaStatus = VA_STATUS_SUCCESS;
DEBUG_FAILURE;
break;
default:
vaStatus = VA_STATUS_ERROR_UNKNOWN;
DEBUG_FAILURE;
}
}
return vaStatus;
}
/* Add Restart interval termination (RSTm)to coded buf 1 ~ NumCores-1*/
static inline VAStatus pnw_OutputResetIntervalToCB(IMG_UINT8 *pui8Buf, IMG_UINT8 ui8_marker)
{
if (NULL == pui8Buf)
return VA_STATUS_ERROR_UNKNOWN;
/*Refer to CCITT Rec. T.81 (1992 E), B.2.1*/
/*RSTm: Restart marker conditional marker which is placed between
* entropy-coded segments only if restartis enabled. There are 8 unique
* restart markers (m = 0 - 7) which repeat in sequence from 0 to 7, starting with
* zero for each scan, to provide a modulo 8 restart interval count*/
*pui8Buf++ = 0xff;
*pui8Buf = (ui8_marker | 0xd0);
return 0;
}
static VAStatus pnw_jpeg_EndPicture(
object_context_p obj_context)
{
INIT_CONTEXT_JPEG;
IMG_UINT16 ui16BCnt;
TOPAZSC_JPEG_ENCODER_CONTEXT *pContext = ctx->jpeg_ctx;
IMG_UINT32 rc = 0;
pnw_cmdbuf_p cmdbuf = (pnw_cmdbuf_p)ctx->obj_context->pnw_cmdbuf;
VAStatus vaStatus = VA_STATUS_SUCCESS;
IMG_UINT32 ui32NoMCUsToEncode;
IMG_UINT32 ui32RemainMCUs;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_EndPicture\n");
ui32RemainMCUs = pContext->sScan_Encode_Info.ui32NumberMCUsToEncode;
for (ui16BCnt = 0; ui16BCnt < pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers
&& pContext->sScan_Encode_Info.ui16SScan > 0; ui16BCnt++) {
pContext->sScan_Encode_Info.aBufferTable[ui16BCnt].ui16ScanNumber =
pContext->sScan_Encode_Info.ui16SScan--;
if (pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers < 2 ||
pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers > PNW_JPEG_MAX_SCAN_NUM) {
vaStatus = VA_STATUS_ERROR_UNKNOWN;
DEBUG_FAILURE;
return vaStatus;
}
/*i8MTXNumber is the core number.*/
pContext->sScan_Encode_Info.aBufferTable[ui16BCnt].i8MTXNumber =
(aui32_jpg_mtx_num[pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers - 1]
>> ui16BCnt) & 0x1;
if (pContext->sScan_Encode_Info.ui16SScan == 0) {
ui32NoMCUsToEncode = ui32RemainMCUs;
// Final scan, may need fewer MCUs than buffer size, calculate the remainder
} else
ui32NoMCUsToEncode = pContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan;
pContext->sScan_Encode_Info.ui32CurMCUsOffset =
pContext->sScan_Encode_Info.ui32NumberMCUsToEncode - ui32RemainMCUs;
rc = SubmitScanToMTX(pContext, ui16BCnt,
pContext->sScan_Encode_Info.aBufferTable[ui16BCnt].i8MTXNumber, ui32NoMCUsToEncode);
if (rc != IMG_ERR_OK) {
vaStatus = VA_STATUS_ERROR_UNKNOWN;
DEBUG_FAILURE;
return vaStatus;
}
ui32RemainMCUs -= ui32NoMCUsToEncode;
}
pnw_cmdbuf_insert_command_package(ctx->obj_context,
1 ,
MTX_CMDID_NULL,
NULL,
0);
psb_buffer_unmap(&cmdbuf->pic_params);
cmdbuf->pic_params_p = NULL;
psb_buffer_unmap(&cmdbuf->header_mem);
cmdbuf->header_mem_p = NULL;
/*psb_buffer_unmap(&cmdbuf->slice_params);
cmdbuf->slice_params_p = NULL;*/
psb_buffer_unmap(ctx->coded_buf->psb_buffer);
pContext->jpeg_coded_buf.pMemInfo = NULL;
if (pnw_context_flush_cmdbuf(ctx->obj_context)) {
vaStatus = VA_STATUS_ERROR_UNKNOWN;
return vaStatus;
}
ctx->obj_context->frame_count++;
return VA_STATUS_SUCCESS;
}
VAStatus pnw_jpeg_AppendMarkers(object_context_p obj_context, unsigned char *raw_coded_buf)
{
INIT_CONTEXT_JPEG;
IMG_UINT16 ui16BCnt;
TOPAZSC_JPEG_ENCODER_CONTEXT *pContext = ctx->jpeg_ctx;
BUFFER_HEADER* pBufHeader;
STREAMTYPEW s_streamW;
unsigned char *pSegStart = raw_coded_buf;
if (pSegStart == NULL) {
return VA_STATUS_ERROR_UNKNOWN;
}
pBufHeader = (BUFFER_HEADER *)pSegStart;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Number of Coded buffers %d, Per Coded Buffer size : %d\n",
pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers, pContext->ui32SizePerCodedBuffer);
/*The first part of coded buffer contains JPEG headers*/
pBufHeader->ui32Reserved3 = PNW_JPEG_HEADER_MAX_SIZE;
pContext->jpeg_coded_buf.ui32BytesWritten = 0;
for (ui16BCnt = 0;
ui16BCnt < pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers;
ui16BCnt++) {
pBufHeader = (BUFFER_HEADER *)pSegStart;
pBufHeader->ui32Reserved3 =
PNW_JPEG_HEADER_MAX_SIZE + pContext->ui32SizePerCodedBuffer * ui16BCnt ;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Coded Buffer Part %d, size %d, next part offset: %d\n",
ui16BCnt, pBufHeader->ui32BytesUsed, pBufHeader->ui32Reserved3);
if (ui16BCnt > 0 && pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers > 1) {
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Append 2 bytes Reset Interval %d "
"to Coded Buffer Part %d\n", ui16BCnt - 1, ui16BCnt);
while(*(pSegStart +sizeof(BUFFER_HEADER) + pBufHeader->ui32BytesUsed - 1) == 0xff)
pBufHeader->ui32BytesUsed--;
pnw_OutputResetIntervalToCB(
(IMG_UINT8 *)(pSegStart +
sizeof(BUFFER_HEADER) + pBufHeader->ui32BytesUsed),
ui16BCnt - 1);
pBufHeader->ui32BytesUsed += 2;
}
pContext->jpeg_coded_buf.ui32BytesWritten += pBufHeader->ui32BytesUsed;
pSegStart = raw_coded_buf + pBufHeader->ui32Reserved3;
}
pBufHeader = (BUFFER_HEADER *)pSegStart;
pBufHeader->ui32Reserved3 = 0; /*Last Part of Coded Buffer*/
pContext->jpeg_coded_buf.ui32BytesWritten += pBufHeader->ui32BytesUsed;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Coded Buffer Part %d, size %d, next part offset: %d\n",
ui16BCnt, pBufHeader->ui32BytesUsed, pBufHeader->ui32Reserved3);
while(*(pSegStart +sizeof(BUFFER_HEADER) + pBufHeader->ui32BytesUsed - 1) == 0xff)
pBufHeader->ui32BytesUsed--;
s_streamW.Buffer = pSegStart;
s_streamW.Offset = (sizeof(BUFFER_HEADER) + pBufHeader->ui32BytesUsed);
fPutBitsToBuffer(&s_streamW, 2, END_OF_IMAGE);
pBufHeader->ui32BytesUsed += 2;
pContext->jpeg_coded_buf.ui32BytesWritten += 2;
drv_debug_msg(VIDEO_DEBUG_GENERAL, "Add two bytes to last part of coded buffer,"
" total: %d\n", pContext->jpeg_coded_buf.ui32BytesWritten);
return VA_STATUS_SUCCESS;
}
struct format_vtable_s pnw_JPEG_vtable = {
queryConfigAttributes:
pnw_jpeg_QueryConfigAttributes,
validateConfig:
pnw_jpeg_ValidateConfig,
createContext:
pnw_jpeg_CreateContext,
destroyContext:
pnw_jpeg_DestroyContext,
beginPicture:
pnw_jpeg_BeginPicture,
renderPicture:
pnw_jpeg_RenderPicture,
endPicture:
pnw_jpeg_EndPicture
};