| /* |
| * 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); |