blob: cddcdb2ac8081b545cd779eb812ff72bdf8bf19b [file] [log] [blame]
/*
* Copyright (c) 2009-2017, Intel Corporation
*
* 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, sublicense,
* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*/
//!
//! \file media_ddi_decode_jpeg.cpp
//! \brief The class implementation of DdiDecodeJPEG for JPEG decode
//!
//!
#include <va/va_dec_jpeg.h>
#include "media_libva_decoder.h"
#include "media_libva_util.h"
#include "media_ddi_decode_jpeg.h"
#include "mos_solo_generic.h"
#include "codechal_decode_jpeg.h"
#include "media_ddi_decode_const.h"
#include "media_ddi_factory.h"
typedef enum _DDI_DECODE_JPEG_BUFFER_STATE
{
BUFFER_UNLOADED = 0,
BUFFER_LOADED = 1,
} DDI_DECODE_JPEG_BUFFER_STATE;
#define DDI_DECODE_JPEG_MAXIMUM_HUFFMAN_TABLE 2
#define DDI_DECODE_JPEG_MAXIMUM_QMATRIX_NUM 4
#define DDI_DECODE_JPEG_MAXIMUM_QMATRIX_ENTRIES 64
#define DDI_DECODE_JPEG_SLICE_PARAM_BUF_NUM 0x4 //According to JPEG SPEC, max slice per frame is 4
static const uint32_t zigzag_order[64] =
{
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63
};
VAStatus DdiDecodeJPEG::ParseSliceParams(
DDI_MEDIA_CONTEXT *mediaCtx,
VASliceParameterBufferJPEGBaseline *slcParam,
uint32_t numSlices)
{
CodecDecodeJpegScanParameter *jpegSliceParam =
(CodecDecodeJpegScanParameter *)(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
CodecDecodeJpegPicParams *picParam = (CodecDecodeJpegPicParams *)(m_ddiDecodeCtx->DecodeParams.m_picParams);
if ((jpegSliceParam == nullptr) ||
(picParam == nullptr) ||
(slcParam == nullptr))
{
DDI_ASSERTMESSAGE("Invalid Parameter for Parsing JPEG Slice parameter\n");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
jpegSliceParam->NumScans += numSlices;
picParam->m_totalScans += numSlices;
if (picParam->m_totalScans == 1 && slcParam[0].num_components > 1)
{
picParam->m_interleavedData = 1;
}
uint32_t j, i;
int32_t startIdx = m_numScans;
for (j = 0; j < numSlices; j++)
{
for (i = 0; i < slcParam[j].num_components; i++)
{
jpegSliceParam->ScanHeader[j + startIdx].ComponentSelector[i] = slcParam[j].components[i].component_selector;
jpegSliceParam->ScanHeader[j + startIdx].DcHuffTblSelector[i] = slcParam[j].components[i].dc_table_selector;
jpegSliceParam->ScanHeader[j + startIdx].AcHuffTblSelector[i] = slcParam[j].components[i].ac_table_selector;
}
jpegSliceParam->ScanHeader[j + startIdx].NumComponents = slcParam[j].num_components;
jpegSliceParam->ScanHeader[j + startIdx].RestartInterval = slcParam[j].restart_interval;
jpegSliceParam->ScanHeader[j + startIdx].MCUCount = slcParam[j].num_mcus;
jpegSliceParam->ScanHeader[j + startIdx].ScanHoriPosition = slcParam[j].slice_horizontal_position;
jpegSliceParam->ScanHeader[j + startIdx].ScanVertPosition = slcParam[j].slice_vertical_position;
jpegSliceParam->ScanHeader[j + startIdx].DataOffset = slcParam[j].slice_data_offset;
jpegSliceParam->ScanHeader[j + startIdx].DataLength = slcParam[j].slice_data_size;
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiDecodeJPEG::ParsePicParams(
DDI_MEDIA_CONTEXT *mediaCtx,
VAPictureParameterBufferJPEGBaseline *picParam)
{
CodecDecodeJpegPicParams *jpegPicParam = (CodecDecodeJpegPicParams *)(m_ddiDecodeCtx->DecodeParams.m_picParams);
if ((jpegPicParam == nullptr) ||
(picParam == nullptr))
{
DDI_ASSERTMESSAGE("Null Parameter for Parsing JPEG Picture parameter\n");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
jpegPicParam->m_frameWidth = picParam->picture_width;
jpegPicParam->m_frameHeight = picParam->picture_height;
jpegPicParam->m_numCompInFrame = picParam->num_components;
switch (picParam->rotation)
{
case VA_ROTATION_NONE:
jpegPicParam->m_rotation = jpegRotation0;
break;
case VA_ROTATION_90:
jpegPicParam->m_rotation = jpegRotation90;
break;
case VA_ROTATION_180:
jpegPicParam->m_rotation = jpegRotation180;
break;
case VA_ROTATION_270:
jpegPicParam->m_rotation = jpegRotation270;
break;
default:
/* For the other rotation type, the rotation is disabled. */
jpegPicParam->m_rotation = jpegRotation0;
break;
;
}
if (jpegPicParam->m_numCompInFrame == 1)
{
jpegPicParam->m_chromaType = jpegYUV400;
}
else if (jpegPicParam->m_numCompInFrame == 3)
{
int32_t h1 = picParam->components[0].h_sampling_factor;
int32_t h2 = picParam->components[1].h_sampling_factor;
int32_t h3 = picParam->components[2].h_sampling_factor;
int32_t v1 = picParam->components[0].v_sampling_factor;
int32_t v2 = picParam->components[1].v_sampling_factor;
int32_t v3 = picParam->components[2].v_sampling_factor;
if (h1 == 2 && h2 == 1 && h3 == 1 &&
v1 == 2 && v2 == 1 && v3 == 1)
{
jpegPicParam->m_chromaType = jpegYUV420;
}
else if (h1 == 2 && h2 == 1 && h3 == 1 &&
v1 == 1 && v2 == 1 && v3 == 1)
{
jpegPicParam->m_chromaType = jpegYUV422H2Y;
}
else if (h1 == 1 && h2 == 1 && h3 == 1 &&
v1 == 1 && v2 == 1 && v3 == 1)
{
switch (picParam->color_space)
{
case 0: //YUV
jpegPicParam->m_chromaType = jpegYUV444;
break;
case 1: //RGB
jpegPicParam->m_chromaType = jpegRGB;
break;
case 2: //BGR
jpegPicParam->m_chromaType = jpegBGR;
break;
default:
/* For the other type, the default YUV444 is used */
jpegPicParam->m_chromaType = jpegYUV444;
break;
;
}
}
else if (h1 == 4 && h2 == 1 && h3 == 1 &&
v1 == 1 && v2 == 1 && v3 == 1)
{
jpegPicParam->m_chromaType = jpegYUV411;
}
else if (h1 == 1 && h2 == 1 && h3 == 1 &&
v1 == 2 && v2 == 1 && v3 == 1)
{
jpegPicParam->m_chromaType = jpegYUV422V2Y;
}
else if (h1 == 2 && h2 == 1 && h3 == 1 &&
v1 == 2 && v2 == 2 && v3 == 2)
{
jpegPicParam->m_chromaType = jpegYUV422H4Y;
}
else if (h1 == 2 && h2 == 2 && h3 == 2 &&
v1 == 2 && v2 == 1 && v3 == 1)
{
jpegPicParam->m_chromaType = jpegYUV422V4Y;
}
else
{
DDI_NORMALMESSAGE("Unsupported sampling factor in JPEG Picture parameter\n");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
}
memset(jpegPicParam->m_componentIdentifier, 0, jpegNumComponent);
memset(jpegPicParam->m_quantTableSelector, 0, jpegNumComponent);
if (picParam->num_components > jpegNumComponent)
{
DDI_NORMALMESSAGE("Unsupported component num in JPEG Picture parameter\n");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
for (int32_t i = 0; i < picParam->num_components; i++)
{
jpegPicParam->m_componentIdentifier[i] = picParam->components[i].component_id;
jpegPicParam->m_quantTableSelector[i] = picParam->components[i].quantiser_table_selector;
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiDecodeJPEG::ParseHuffmanTbl(
DDI_MEDIA_CONTEXT * mediaCtx,
VAHuffmanTableBufferJPEGBaseline *huffmanTbl)
{
PCODECHAL_DECODE_JPEG_HUFFMAN_TABLE jpegHuffTbl = (PCODECHAL_DECODE_JPEG_HUFFMAN_TABLE)(m_ddiDecodeCtx->DecodeParams.m_huffmanTable);
int32_t sumBITS = 0;
if ((jpegHuffTbl == nullptr) ||
(huffmanTbl == nullptr))
{
DDI_ASSERTMESSAGE("Null Parameter for Parsing JPEG Huffman Tableparameter\n");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
memset(jpegHuffTbl, 0, sizeof(CODECHAL_DECODE_JPEG_HUFFMAN_TABLE));
for (int32_t i = 0; i < DDI_DECODE_JPEG_MAXIMUM_HUFFMAN_TABLE; i++)
{
if (huffmanTbl->load_huffman_table[i] == BUFFER_LOADED)
{
sumBITS = 0;
for (int32_t j = 0; j < JPEG_NUM_HUFF_TABLE_DC_BITS; j++)
{
sumBITS += huffmanTbl->huffman_table[i].num_dc_codes[j];
}
if (sumBITS > JPEG_NUM_HUFF_TABLE_DC_HUFFVAL)
{
DDI_ASSERTMESSAGE("Huffman table DC entries number is out of HW limitation.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
//the size of jpegHuffTbl->HuffTable[i].DC_BITS is 12 (defined in driver)
//the size of huffmanTbl->huffman_table[i].num_dc_codes is 16 (defined in libva)
//it is using the size of "DC_BITS" for solve the overflow
MOS_SecureMemcpy(jpegHuffTbl->HuffTable[i].DC_BITS,
sizeof(jpegHuffTbl->HuffTable[i].DC_BITS),
huffmanTbl->huffman_table[i].num_dc_codes,
sizeof(jpegHuffTbl->HuffTable[i].DC_BITS));
MOS_SecureMemcpy(jpegHuffTbl->HuffTable[i].DC_HUFFVAL,
sizeof(jpegHuffTbl->HuffTable[i].DC_HUFFVAL),
huffmanTbl->huffman_table[i].dc_values,
sizeof(huffmanTbl->huffman_table[i].dc_values));
MOS_SecureMemcpy(jpegHuffTbl->HuffTable[i].AC_BITS,
sizeof(jpegHuffTbl->HuffTable[i].AC_BITS),
huffmanTbl->huffman_table[i].num_ac_codes,
sizeof(huffmanTbl->huffman_table[i].num_ac_codes));
MOS_SecureMemcpy(jpegHuffTbl->HuffTable[i].AC_HUFFVAL,
sizeof(jpegHuffTbl->HuffTable[i].AC_HUFFVAL),
huffmanTbl->huffman_table[i].ac_values,
sizeof(huffmanTbl->huffman_table[i].ac_values));
}
}
return VA_STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// Function: JpegQMatrixDecode
// Description: Parse the QMatrix table from VAAPI, and load the valid Qmatrix to the Buffer used by
// CodecHal
//
/////////////////////////////////////////////////////////////////////////////////////////
VAStatus DdiDecodeJPEG::ParseIQMatrix(
DDI_MEDIA_CONTEXT *mediaCtx,
VAIQMatrixBufferJPEGBaseline *matrix)
{
CodecJpegQuantMatrix *jpegQMatrix = (CodecJpegQuantMatrix *)(m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer);
if ((matrix == nullptr) || (jpegQMatrix == nullptr))
{
DDI_ASSERTMESSAGE("Null Parameter for Parsing JPEG IQMatrix \n");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
memset(jpegQMatrix, 0, sizeof(CodecJpegQuantMatrix));
int32_t idx, idx2;
for (idx = 0; idx < DDI_DECODE_JPEG_MAXIMUM_QMATRIX_NUM; idx++)
{
if (matrix->load_quantiser_table[idx] == BUFFER_LOADED)
{
for (idx2 = 0; idx2 < DDI_DECODE_JPEG_MAXIMUM_QMATRIX_ENTRIES; idx2++)
{
jpegQMatrix->m_quantMatrix[idx][zigzag_order[idx2]] = matrix->quantiser_table[idx][idx2];
}
}
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiDecodeJPEG::SetBufferRendered(VABufferID bufferID)
{
DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
if (bufMgr == nullptr)
{
DDI_ASSERTMESSAGE("Null Parameter for Parsing Data buffer for JPEG\n");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
bool renderFlag = false;
for (uint32_t i = 0; i < bufMgr->dwNumSliceData; i++)
{
// Depend on the ID we tracked, if application want to rendered one of them
// we set some flags
if (bufMgr->pSliceData[i].vaBufferId == bufferID)
{
if (bufMgr->pSliceData[i].bRendered == false)
{
// set the rendered flags. which will be used when EndPicture.
bufMgr->pSliceData[i].bRendered = true;
// calculate the size of a bunch of rendered buffers. for endpicture to allocate appropriate memory size of GPU.
bufMgr->dwSizeOfRenderedSliceData += bufMgr->pSliceData[i].uiLength;
// keep record the render order, so that we can calculate the offset correctly when endpicture.
// in this array we save the buffer index in pSliceData which render in sequence. if application create buffers like: 4,3,5,1,2.
// but only render 2,3,5. the content in this array is: [4,1,2], which is the index of created buffer.
bufMgr->pRenderedOrder[bufMgr->dwNumOfRenderedSliceData] = i;
bufMgr->dwNumOfRenderedSliceData++;
}
renderFlag = true;
break;
}
}
if (renderFlag)
{
return VA_STATUS_SUCCESS;
}
else
{
return VA_STATUS_ERROR_INVALID_BUFFER;
}
}
VAStatus DdiDecodeJPEG::RenderPicture(
VADriverContextP ctx,
VAContextID context,
VABufferID *buffers,
int32_t numBuffers)
{
DDI_FUNCTION_ENTER();
VAStatus va = VA_STATUS_SUCCESS;
PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
void *data = nullptr;
for (int32_t i = 0; i < numBuffers; i++)
{
if (!buffers || (buffers[i] == VA_INVALID_ID))
{
return VA_STATUS_ERROR_INVALID_BUFFER;
}
DDI_MEDIA_BUFFER *buf = DdiMedia_GetBufferFromVABufferID(mediaCtx, buffers[i]);
if (nullptr == buf)
{
return VA_STATUS_ERROR_INVALID_BUFFER;
}
uint32_t dataSize = buf->iSize;
DdiMedia_MapBuffer(ctx, buffers[i], &data);
if (data == nullptr)
{
return VA_STATUS_ERROR_INVALID_BUFFER;
}
switch ((int32_t)buf->uiType)
{
case VASliceDataBufferType:
{
DDI_CHK_RET(SetBufferRendered(buffers[i]),"SetBufferRendered failed!");
m_ddiDecodeCtx->DecodeParams.m_dataSize += dataSize;
break;
}
case VASliceParameterBufferType:
{
if (buf->uiNumElements == 0)
{
return VA_STATUS_ERROR_INVALID_BUFFER;
}
uint32_t numSlices = buf->uiNumElements;
if ((m_numScans + numSlices) > jpegNumComponent)
{
DDI_NORMALMESSAGE("the total number of JPEG scans are beyond the supported num(4)\n");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
DDI_CHK_RET(AllocSliceParamContext(numSlices),"AllocSliceParamContext failed!");
VASliceParameterBufferJPEGBaseline *slcInfo = (VASliceParameterBufferJPEGBaseline *)data;
DDI_CHK_RET(ParseSliceParams(mediaCtx, slcInfo, numSlices),"ParseSliceParams failed!");
m_ddiDecodeCtx->BufMgr.pNumOfRenderedSliceParaForOneBuffer[m_ddiDecodeCtx->BufMgr.dwNumOfRenderedSlicePara] = numSlices;
m_ddiDecodeCtx->BufMgr.dwNumOfRenderedSlicePara ++;
m_ddiDecodeCtx->DecodeParams.m_numSlices += numSlices;
m_numScans += numSlices;
m_groupIndex++;
break;
}
case VAIQMatrixBufferType:
{
VAIQMatrixBufferJPEGBaseline *imxBuf = (VAIQMatrixBufferJPEGBaseline *)data;
DDI_CHK_RET(ParseIQMatrix(mediaCtx, imxBuf),"ParseIQMatrix failed!");
break;
}
case VAPictureParameterBufferType:
{
VAPictureParameterBufferJPEGBaseline *picParam = (VAPictureParameterBufferJPEGBaseline *)data;
DDI_CHK_RET(ParsePicParams(mediaCtx, picParam),"ParsePicParams failed!");
break;
}
case VAHuffmanTableBufferType:
{
VAHuffmanTableBufferJPEGBaseline *huffTbl = (VAHuffmanTableBufferJPEGBaseline *)data;
DDI_CHK_RET(ParseHuffmanTbl(mediaCtx, huffTbl),"ParseHuffmanTbl failed!");
break;
}
case VAProcPipelineParameterBufferType:
{
DDI_NORMALMESSAGE("ProcPipeline is not supported for JPEGBaseline decoding\n");
break;
}
case VADecodeStreamoutBufferType:
{
DdiMedia_MediaBufferToMosResource(buf, &m_ddiDecodeCtx->BufMgr.resExternalStreamOutBuffer);
m_streamOutEnabled = true;
break;
}
default:
va = VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
break;
}
DdiMedia_UnmapBuffer(ctx, buffers[i]);
}
DDI_FUNCTION_EXIT(va);
return va;
}
VAStatus DdiDecodeJPEG::BeginPicture(
VADriverContextP ctx,
VAContextID context,
VASurfaceID renderTarget)
{
VAStatus vaStatus = DdiMediaDecode::BeginPicture(ctx, context, renderTarget);
if (vaStatus != VA_STATUS_SUCCESS)
{
return vaStatus;
}
if (m_jpegBitstreamBuf)
{
DdiMediaUtil_FreeBuffer(m_jpegBitstreamBuf);
MOS_FreeMemory(m_jpegBitstreamBuf);
m_jpegBitstreamBuf = nullptr;
}
CodecDecodeJpegScanParameter *jpegSliceParam =
(CodecDecodeJpegScanParameter *)(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
jpegSliceParam->NumScans = 0;
CodecDecodeJpegPicParams *picParam = (CodecDecodeJpegPicParams *)(m_ddiDecodeCtx->DecodeParams.m_picParams);
picParam->m_totalScans = 0;
m_numScans = 0;
return vaStatus;
}
VAStatus DdiDecodeJPEG::InitDecodeParams(
VADriverContextP ctx,
VAContextID context)
{
/* skip the mediaCtx check as it is checked in caller */
PDDI_MEDIA_CONTEXT mediaCtx;
mediaCtx = DdiMedia_GetMediaContext(ctx);
DDI_CHK_RET(DecodeCombineBitstream(mediaCtx),"DecodeCombineBitstream failed!");
DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
bufMgr->dwNumSliceControl = 0;
memset(&m_destSurface, 0, sizeof(MOS_SURFACE));
m_destSurface.dwOffset = 0;
DDI_CODEC_RENDER_TARGET_TABLE *rtTbl = &(m_ddiDecodeCtx->RTtbl);
if ((rtTbl == nullptr) || (rtTbl->pCurrentRT == nullptr))
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiDecodeJPEG::SetDecodeParams()
{
DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
// we do not support mismatched usecase.
if ((bufMgr->dwNumOfRenderedSlicePara != bufMgr->dwNumOfRenderedSliceData) ||
(bufMgr->dwNumOfRenderedSlicePara == 0))
{
DDI_NORMALMESSAGE("DDI: Unsupported buffer mismatch usage!\n");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
// Allocate GPU Buffer description keeper.
m_jpegBitstreamBuf = (DDI_MEDIA_BUFFER *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_BUFFER));
if (m_jpegBitstreamBuf == nullptr)
{
DDI_ASSERTMESSAGE("DDI: Allocate Jpeg Media Buffer Failed!\n");
return VA_STATUS_ERROR_UNKNOWN;
}
m_jpegBitstreamBuf->iSize = bufMgr->dwSizeOfRenderedSliceData;
m_jpegBitstreamBuf->uiNumElements = bufMgr->dwNumOfRenderedSliceData;
m_jpegBitstreamBuf->uiType = VASliceDataBufferType;
m_jpegBitstreamBuf->format = Media_Format_Buffer;
m_jpegBitstreamBuf->uiOffset = 0;
m_jpegBitstreamBuf->bCFlushReq = false;
m_jpegBitstreamBuf->pMediaCtx = m_ddiDecodeCtx->pMediaCtx;
// Create GPU buffer
VAStatus va = DdiMediaUtil_CreateBuffer(m_jpegBitstreamBuf, m_ddiDecodeCtx->pMediaCtx->pDrmBufMgr);
if (va != VA_STATUS_SUCCESS)
{
DdiMediaUtil_FreeBuffer(m_jpegBitstreamBuf);
MOS_FreeMemory(m_jpegBitstreamBuf);
m_jpegBitstreamBuf = nullptr;
return va;
}
// For the first time you call DdiMediaUtil_LockBuffer for a fresh GPU memory, it will map GPU address to a virtual address.
// and then, DdiMediaUtil_LockBuffer is acutally to increase the reference count. so we used here for 2 resaons:
//
// 1. Map GPU address to virtual at the beginning when we combine the CPU -> GPU.
uint8_t *mappedBuf = (uint8_t *)DdiMediaUtil_LockBuffer(m_jpegBitstreamBuf, MOS_LOCKFLAG_WRITEONLY);
if (mappedBuf == nullptr)
{
DdiMediaUtil_FreeBuffer(m_jpegBitstreamBuf);
MOS_FreeMemory(m_jpegBitstreamBuf);
m_jpegBitstreamBuf = nullptr;
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
// get the JPEG Slice Header Params for offset recaculated.
CodecDecodeJpegScanParameter *sliceParam =
(CodecDecodeJpegScanParameter *)(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
uint32_t bufOffset = 0;
int32_t orderSlicePara = 0;
int32_t orderSliceData = 0;
for (uint32_t i = 0; i < bufMgr->dwNumOfRenderedSliceData; i++)
{
// get the rendered slice data index in rendered order.
int32_t renderedBufIdx = bufMgr->pRenderedOrder[i];
if (bufMgr->pSliceData[renderedBufIdx].bRendered)
{
MOS_SecureMemcpy((void *)(mappedBuf + bufOffset),
bufMgr->pSliceData[renderedBufIdx].uiLength,
bufMgr->pSliceData[renderedBufIdx].pBaseAddress,
bufMgr->pSliceData[renderedBufIdx].uiLength);
// since we assume application must make sure ONE slice parameter buffer ONE slice data buffer, so we recaculate header offset here.
for (int32_t j = 0; j < bufMgr->pNumOfRenderedSliceParaForOneBuffer[orderSliceData]; j++)
{
sliceParam->ScanHeader[orderSlicePara].DataOffset += bufOffset;
orderSlicePara++;
}
bufOffset += bufMgr->pSliceData[renderedBufIdx].uiLength;
bufMgr->pNumOfRenderedSliceParaForOneBuffer[orderSliceData] = 0;
orderSliceData++;
bufMgr->pSliceData[renderedBufIdx].bRendered = false;
}
}
DdiMediaUtil_UnlockBuffer(m_jpegBitstreamBuf);
DdiMedia_MediaBufferToMosResource(m_jpegBitstreamBuf, &(bufMgr->resBitstreamBuffer));
bufMgr->dwNumOfRenderedSliceData = 0;
bufMgr->dwNumOfRenderedSlicePara = 0;
bufMgr->dwSizeOfRenderedSliceData = 0;
m_destSurface.dwOffset = 0;
m_destSurface.Format = Format_NV12;
CodecDecodeJpegPicParams *jpegPicParam = (CodecDecodeJpegPicParams *)(m_ddiDecodeCtx->DecodeParams.m_picParams);
if((m_ddiDecodeCtx->RTtbl.pCurrentRT->format == Media_Format_NV12)
&&(jpegPicParam->m_chromaType == jpegYUV444))
{
m_ddiDecodeCtx->RTtbl.pCurrentRT = DdiMedia_ReplaceSurfaceWithNewFormat(m_ddiDecodeCtx->RTtbl.pCurrentRT, Media_Format_444P);
}
if(m_ddiDecodeCtx->RTtbl.pCurrentRT != nullptr)
{
DdiMedia_MediaSurfaceToMosResource((&(m_ddiDecodeCtx->RTtbl))->pCurrentRT, &(m_destSurface.OsResource));
}
(&m_ddiDecodeCtx->DecodeParams)->m_destSurface = &m_destSurface;
(&m_ddiDecodeCtx->DecodeParams)->m_deblockSurface = nullptr;
(&m_ddiDecodeCtx->DecodeParams)->m_dataBuffer = &bufMgr->resBitstreamBuffer;
(&m_ddiDecodeCtx->DecodeParams)->m_bitStreamBufData = bufMgr->pBitstreamBuffer;
Mos_Solo_OverrideBufferSize((&m_ddiDecodeCtx->DecodeParams)->m_dataSize, (&m_ddiDecodeCtx->DecodeParams)->m_dataBuffer);
(&m_ddiDecodeCtx->DecodeParams)->m_bitplaneBuffer = nullptr;
if (m_streamOutEnabled)
{
(&m_ddiDecodeCtx->DecodeParams)->m_streamOutEnabled = true;
(&m_ddiDecodeCtx->DecodeParams)->m_externalStreamOutBuffer = &bufMgr->resExternalStreamOutBuffer;
}
else
{
(&m_ddiDecodeCtx->DecodeParams)->m_streamOutEnabled = false;
(&m_ddiDecodeCtx->DecodeParams)->m_externalStreamOutBuffer = nullptr;
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiDecodeJPEG::AllocSliceParamContext(
uint32_t numSlices)
{
uint32_t baseSize = sizeof(CodecDecodeJpegScanParameter);
if (m_sliceParamBufNum < (m_ddiDecodeCtx->DecodeParams.m_numSlices + numSlices))
{
// in order to avoid that the buffer is reallocated multi-times,
// extra 10 slices are added.
uint32_t extraSlices = numSlices + 10;
m_ddiDecodeCtx->DecodeParams.m_sliceParams = realloc(m_ddiDecodeCtx->DecodeParams.m_sliceParams,
baseSize * (m_sliceParamBufNum + extraSlices));
if (m_ddiDecodeCtx->DecodeParams.m_sliceParams == nullptr)
{
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
memset((void *)((uint8_t *)m_ddiDecodeCtx->DecodeParams.m_sliceParams + baseSize * m_sliceParamBufNum), 0, baseSize * extraSlices);
m_sliceParamBufNum += extraSlices;
}
return VA_STATUS_SUCCESS;
}
void DdiDecodeJPEG::DestroyContext(
VADriverContextP ctx)
{
FreeResourceBuffer();
// explicitly call the base function to do the further clean-up
DdiMediaDecode::DestroyContext(ctx);
}
uint8_t* DdiDecodeJPEG::GetPicParamBuf(
DDI_CODEC_COM_BUFFER_MGR *bufMgr)
{
return (uint8_t*)(&(bufMgr->Codec_Param.Codec_Param_JPEG.PicParamJPEG));
}
VAStatus DdiDecodeJPEG::AllocBsBuffer(
DDI_CODEC_COM_BUFFER_MGR *bufMgr,
DDI_MEDIA_BUFFER *buf)
{
// Allocate JPEG slice data memory from CPU.
uint8_t *bsAddr;
uint32_t index;
index = bufMgr->dwNumSliceData;
/* the pSliceData needs to be reallocated in order to contain more SliceDataBuf */
if (index >= bufMgr->m_maxNumSliceData)
{
/* In theroy it can resize the m_maxNumSliceData one by one. But in order to
* avoid calling realloc frequently, it will try to allocate 10 to hold more
* SliceDataBuf. This is only for the optimized purpose.
*/
int32_t reallocSize = bufMgr->m_maxNumSliceData + 10;
bufMgr->pSliceData = (DDI_CODEC_BITSTREAM_BUFFER_INFO *)realloc(bufMgr->pSliceData, sizeof(bufMgr->pSliceData[0]) * reallocSize);
if (bufMgr->pSliceData == nullptr)
{
DDI_ASSERTMESSAGE("fail to reallocate pSliceData for JPEG\n.");
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
memset((void *)(bufMgr->pSliceData + bufMgr->m_maxNumSliceData), 0,
sizeof(bufMgr->pSliceData[0]) * 10);
bufMgr->m_maxNumSliceData += 10;
}
bsAddr = (uint8_t*)MOS_AllocAndZeroMemory(buf->iSize);
if(bsAddr == 0)
{
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
buf->pData = bsAddr;
buf->format = Media_Format_CPU;
buf->bCFlushReq = false;
buf->uiOffset = 0;
bufMgr->pSliceData[index].uiLength = buf->iSize;
bufMgr->pSliceData[index].uiOffset = buf->uiOffset;
bufMgr->pSliceData[index].pBaseAddress = buf->pData;
bufMgr->dwNumSliceData ++;
return VA_STATUS_SUCCESS;
}
VAStatus DdiDecodeJPEG::AllocSliceControlBuffer(
DDI_MEDIA_BUFFER *buf)
{
DDI_CODEC_COM_BUFFER_MGR *bufMgr;
uint32_t availSize;
uint32_t newSize;
bufMgr = &(m_ddiDecodeCtx->BufMgr);
availSize = m_sliceCtrlBufNum - bufMgr->dwNumSliceControl;
if(availSize < buf->uiNumElements)
{
newSize = sizeof(VASliceParameterBufferJPEGBaseline) * (m_sliceCtrlBufNum - availSize + buf->uiNumElements);
bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG = (VASliceParameterBufferJPEGBaseline *)realloc(bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG, newSize);
if(bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG == nullptr)
{
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
MOS_ZeroMemory(bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG + m_sliceCtrlBufNum, sizeof(VASliceParameterBufferJPEGBaseline) * (buf->uiNumElements - availSize));
m_sliceCtrlBufNum = m_sliceCtrlBufNum - availSize + buf->uiNumElements;
}
buf->pData = (uint8_t*)bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG;
buf->uiOffset = sizeof(VASliceParameterBufferJPEGBaseline) * bufMgr->dwNumSliceControl;
bufMgr->dwNumSliceControl += buf->uiNumElements;
return VA_STATUS_SUCCESS;
}
void DdiDecodeJPEG::ContextInit(
int32_t picWidth,
int32_t picHeight)
{
// call the function in base class to initialize it.
DdiMediaDecode::ContextInit(picWidth, picHeight);
m_ddiDecodeCtx->wMode = CODECHAL_DECODE_MODE_JPEG;
}
VAStatus DdiDecodeJPEG::InitResourceBuffer()
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
bufMgr->pSliceData = nullptr;
bufMgr->ui64BitstreamOrder = 0;
bufMgr->dwMaxBsSize = m_width *
m_height * 3 / 2;
bufMgr->dwNumSliceData = 0;
bufMgr->dwNumSliceControl = 0;
m_sliceCtrlBufNum = DDI_DECODE_JPEG_SLICE_PARAM_BUF_NUM;
bufMgr->m_maxNumSliceData = DDI_DECODE_JPEG_SLICE_PARAM_BUF_NUM;
bufMgr->pSliceData = (DDI_CODEC_BITSTREAM_BUFFER_INFO *)MOS_AllocAndZeroMemory(sizeof(bufMgr->pSliceData[0]) * DDI_DECODE_JPEG_SLICE_PARAM_BUF_NUM);
if (bufMgr->pSliceData == nullptr)
{
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto finish;
}
bufMgr->dwNumOfRenderedSlicePara = 0;
bufMgr->dwNumOfRenderedSliceData = 0;
bufMgr->pNumOfRenderedSliceParaForOneBuffer = (int32_t *)MOS_AllocAndZeroMemory(sizeof(bufMgr->pNumOfRenderedSliceParaForOneBuffer[0]) * m_sliceCtrlBufNum);
bufMgr->pRenderedOrder = (int32_t *)MOS_AllocAndZeroMemory(sizeof(bufMgr->pRenderedOrder[0]) * m_sliceCtrlBufNum);
bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG = (VASliceParameterBufferJPEGBaseline *)MOS_AllocAndZeroMemory(sizeof(VASliceParameterBufferJPEGBaseline) * m_sliceCtrlBufNum);
if (bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG == nullptr)
{
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto finish;
}
return VA_STATUS_SUCCESS;
finish:
FreeResourceBuffer();
return vaStatus;
}
void DdiDecodeJPEG::FreeResourceBuffer()
{
DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
if (bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG)
{
MOS_FreeMemory(bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG);
bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG = nullptr;
}
bufMgr->dwNumOfRenderedSlicePara = 0;
bufMgr->dwNumOfRenderedSliceData = 0;
MOS_FreeMemory(bufMgr->pNumOfRenderedSliceParaForOneBuffer);
bufMgr->pNumOfRenderedSliceParaForOneBuffer = nullptr;
MOS_FreeMemory(bufMgr->pRenderedOrder);
bufMgr->pRenderedOrder = nullptr;
for (uint32_t i = 0; i < bufMgr->dwNumSliceData && (bufMgr->pSliceData != nullptr); i++)
{
if (bufMgr->pSliceData[i].pBaseAddress != nullptr)
{
MOS_FreeMemory(bufMgr->pSliceData[i].pBaseAddress);
bufMgr->pSliceData[i].pBaseAddress = nullptr;
}
}
bufMgr->dwNumSliceData = 0;
if (m_jpegBitstreamBuf)
{
DdiMediaUtil_FreeBuffer(m_jpegBitstreamBuf);
MOS_FreeMemory(m_jpegBitstreamBuf);
m_jpegBitstreamBuf = nullptr;
}
// free decode bitstream buffer object
MOS_FreeMemory(bufMgr->pSliceData);
bufMgr->pSliceData = nullptr;
return;
}
VAStatus DdiDecodeJPEG::CodecHalInit(
DDI_MEDIA_CONTEXT *mediaCtx,
void *ptr)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
MOS_CONTEXT *mosCtx = (MOS_CONTEXT *)ptr;
CODECHAL_FUNCTION codecFunction = CODECHAL_FUNCTION_DECODE;
m_ddiDecodeCtx->pCpDdiInterface->SetCpParams(m_ddiDecodeAttr->uiEncryptionType, m_codechalSettings);
CODECHAL_STANDARD_INFO standardInfo;
memset(&standardInfo, 0, sizeof(standardInfo));
standardInfo.CodecFunction = codecFunction;
standardInfo.Mode = (CODECHAL_MODE)m_ddiDecodeCtx->wMode;
m_codechalSettings->codecFunction = codecFunction;
m_codechalSettings->width = m_width;
m_codechalSettings->height = m_height;
m_codechalSettings->intelEntrypointInUse = false;
m_codechalSettings->lumaChromaDepth = CODECHAL_LUMA_CHROMA_DEPTH_8_BITS;
m_codechalSettings->shortFormatInUse = m_ddiDecodeCtx->bShortFormatInUse;
m_codechalSettings->mode = CODECHAL_DECODE_MODE_JPEG;
m_codechalSettings->standard = CODECHAL_JPEG;
#ifdef _DECODE_PROCESSING_SUPPORTED
m_codechalSettings->sfcEnablingHinted = true;
#endif
m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer = MOS_AllocAndZeroMemory(sizeof(CodecJpegQuantMatrix));
if (m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer == nullptr)
{
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto CleanUpandReturn;
}
m_ddiDecodeCtx->DecodeParams.m_picParams = MOS_AllocAndZeroMemory(sizeof(CodecDecodeJpegPicParams));
if (m_ddiDecodeCtx->DecodeParams.m_picParams == nullptr)
{
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto CleanUpandReturn;
}
m_ddiDecodeCtx->DecodeParams.m_huffmanTable = (void*)MOS_AllocAndZeroMemory(sizeof(CODECHAL_DECODE_JPEG_HUFFMAN_TABLE));
if (!m_ddiDecodeCtx->DecodeParams.m_huffmanTable)
{
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto CleanUpandReturn;
}
m_sliceParamBufNum = DDI_DECODE_JPEG_SLICE_PARAM_BUF_NUM;
m_ddiDecodeCtx->DecodeParams.m_sliceParams = (void *)MOS_AllocAndZeroMemory(m_sliceParamBufNum * sizeof(CodecDecodeJpegScanParameter));
if (m_ddiDecodeCtx->DecodeParams.m_sliceParams == nullptr)
{
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto CleanUpandReturn;
}
vaStatus = CreateCodecHal(mediaCtx,
ptr,
&standardInfo);
if (vaStatus != VA_STATUS_SUCCESS)
{
goto CleanUpandReturn;
}
if (InitResourceBuffer() != VA_STATUS_SUCCESS)
{
vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto CleanUpandReturn;
}
return vaStatus;
CleanUpandReturn:
FreeResourceBuffer();
if (m_ddiDecodeCtx->pCodecHal)
{
m_ddiDecodeCtx->pCodecHal->Destroy();
MOS_Delete(m_ddiDecodeCtx->pCodecHal);
m_ddiDecodeCtx->pCodecHal = nullptr;
}
MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer);
m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer = nullptr;
MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_picParams);
m_ddiDecodeCtx->DecodeParams.m_picParams = nullptr;
MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_huffmanTable);
m_ddiDecodeCtx->DecodeParams.m_huffmanTable = nullptr;
MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
m_ddiDecodeCtx->DecodeParams.m_sliceParams = nullptr;
return vaStatus;
}
extern template class MediaDdiFactory<DdiMediaDecode, DDI_DECODE_CONFIG_ATTR>;
static bool jpegRegistered =
MediaDdiFactory<DdiMediaDecode, DDI_DECODE_CONFIG_ATTR>::RegisterCodec<DdiDecodeJPEG>(DECODE_ID_JPEG);