| /* |
| * Copyright (c) 2017-2018, 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_encode_jpeg.cpp |
| //! \brief Defines class for DDI media jpeg encode. |
| //! |
| |
| #include "media_libva_encoder.h" |
| #include "media_libva_util.h" |
| #include "media_ddi_encode_jpeg.h" |
| #include "media_ddi_encode_const.h" |
| #include "media_ddi_factory.h" |
| |
| extern template class MediaDdiFactoryNoArg<DdiEncodeBase>; |
| static bool isEncodeJpegRegistered = |
| MediaDdiFactoryNoArg<DdiEncodeBase>::RegisterCodec<DdiEncodeJpeg>(ENCODE_ID_JPEG); |
| |
| DdiEncodeJpeg::~DdiEncodeJpeg() |
| { |
| if (m_encodeCtx == nullptr) |
| { |
| return; |
| } |
| |
| MOS_FreeMemory(m_encodeCtx->pPicParams); |
| m_encodeCtx->pPicParams = nullptr; |
| |
| MOS_FreeMemory(m_encodeCtx->pEncodeStatusReport); |
| m_encodeCtx->pEncodeStatusReport = nullptr; |
| |
| MOS_FreeMemory(m_huffmanTable); |
| m_huffmanTable = nullptr; |
| |
| MOS_FreeMemory(m_encodeCtx->pQmatrixParams); |
| m_encodeCtx->pQmatrixParams = nullptr; |
| |
| MOS_FreeMemory(m_encodeCtx->pSliceParams); |
| m_encodeCtx->pSliceParams = nullptr; |
| |
| MOS_FreeMemory(m_encodeCtx->pbsBuffer); |
| m_encodeCtx->pbsBuffer = nullptr; |
| |
| MOS_FreeMemory(m_appData); |
| m_appData = nullptr; |
| } |
| |
| VAStatus DdiEncodeJpeg::ContextInitialize(CodechalSetting *codecHalSettings) |
| { |
| DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx.", VA_STATUS_ERROR_INVALID_CONTEXT); |
| DDI_CHK_NULL(m_encodeCtx->pCpDdiInterface, "nullptr m_encodeCtx->pCpDdiInterface.", VA_STATUS_ERROR_INVALID_CONTEXT); |
| DDI_CHK_NULL(codecHalSettings, "nullptr codecHalSettings.", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| codecHalSettings->codecFunction = CODECHAL_FUNCTION_PAK; |
| codecHalSettings->width = m_encodeCtx->dwFrameWidth; |
| codecHalSettings->height = m_encodeCtx->dwFrameHeight; |
| codecHalSettings->mode = m_encodeCtx->wModeType; |
| codecHalSettings->standard = CODECHAL_JPEG; |
| |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| |
| m_quantSupplied = false; |
| m_appDataSize = 0; |
| m_appDataTotalSize = 0; |
| m_appDataWholeHeader = false; |
| |
| m_encodeCtx->pPicParams = (void *)MOS_AllocAndZeroMemory(sizeof(CodecEncodeJpegPictureParams)); |
| DDI_CHK_NULL(m_encodeCtx->pPicParams, "nullptr m_encodeCtx->pPicParams.", VA_STATUS_ERROR_ALLOCATION_FAILED); |
| |
| m_encodeCtx->pbsBuffer = (BSBuffer *)MOS_AllocAndZeroMemory(sizeof(BSBuffer)); |
| DDI_CHK_NULL(m_encodeCtx->pbsBuffer, "nullptr m_encodeCtx->pbsBuffer.", VA_STATUS_ERROR_ALLOCATION_FAILED); |
| |
| // Allocate Encode Status Report |
| m_encodeCtx->pEncodeStatusReport = (void *)MOS_AllocAndZeroMemory(CODECHAL_ENCODE_STATUS_NUM * sizeof(EncodeStatusReport)); |
| DDI_CHK_NULL(m_encodeCtx->pEncodeStatusReport, "nullptr m_encodeCtx->pEncodeStatusReport.", VA_STATUS_ERROR_ALLOCATION_FAILED); |
| |
| // for scan header from application |
| m_encodeCtx->pSliceParams = (void *)MOS_AllocAndZeroMemory(sizeof(CodecEncodeJpegScanHeader)); |
| DDI_CHK_NULL(m_encodeCtx->pSliceParams, "nullptr m_encodeCtx->pSliceParams.", VA_STATUS_ERROR_ALLOCATION_FAILED); |
| |
| // for Quant table |
| m_encodeCtx->pQmatrixParams = (void *)MOS_AllocAndZeroMemory(sizeof(CodecEncodeJpegQuantTable)); |
| DDI_CHK_NULL(m_encodeCtx->pQmatrixParams, "nullptr m_encodeCtx->pQmatrixParams.", VA_STATUS_ERROR_ALLOCATION_FAILED); |
| |
| // for pHuffmanTable |
| m_huffmanTable = (CodecEncodeJpegHuffmanDataArray *)MOS_AllocAndZeroMemory(sizeof(CodecEncodeJpegHuffmanDataArray)); |
| DDI_CHK_NULL(m_huffmanTable, "nullptr m_huffmanTable.", VA_STATUS_ERROR_ALLOCATION_FAILED); |
| |
| return vaStatus; |
| } |
| |
| VAStatus DdiEncodeJpeg::RenderPicture( |
| VADriverContextP ctx, |
| VAContextID context, |
| VABufferID *buffers, |
| int32_t numBuffers) |
| { |
| VAStatus vaStatus = VA_STATUS_SUCCESS; |
| |
| DDI_FUNCTION_ENTER(); |
| |
| DDI_CHK_NULL(ctx, "nullptr context", VA_STATUS_ERROR_INVALID_CONTEXT); |
| |
| DDI_MEDIA_CONTEXT *mediaCtx = DdiMedia_GetMediaContext(ctx); |
| DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT); |
| |
| DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_CONTEXT); |
| |
| for (int32_t i = 0; i < numBuffers; i++) |
| { |
| DDI_MEDIA_BUFFER *buf = DdiMedia_GetBufferFromVABufferID(mediaCtx, buffers[i]); |
| DDI_CHK_NULL(buf, "Invalid buffer.", VA_STATUS_ERROR_INVALID_BUFFER); |
| if (buf->uiType == VAEncMacroblockDisableSkipMapBufferType) |
| { |
| DdiMedia_MediaBufferToMosResource(buf, &(m_encodeCtx->resPerMBSkipMapBuffer)); |
| m_encodeCtx->bMbDisableSkipMapEnabled = true; |
| continue; |
| } |
| uint32_t dataSize = buf->iSize; |
| // can use internal function instead of DdiMedia_MapBuffer here? |
| void *data = nullptr; |
| DdiMedia_MapBuffer(ctx, buffers[i], &data); |
| DDI_CHK_NULL(data, "nullptr data.", VA_STATUS_ERROR_INVALID_BUFFER); |
| |
| switch (buf->uiType) |
| { |
| case VAIQMatrixBufferType: |
| case VAQMatrixBufferType: |
| DDI_CHK_STATUS(Qmatrix(data), VA_STATUS_ERROR_INVALID_BUFFER); |
| break; |
| |
| case VAEncPictureParameterBufferType: |
| DDI_CHK_STATUS(ParsePicParams(mediaCtx, data), VA_STATUS_ERROR_INVALID_BUFFER); |
| DDI_CHK_STATUS( |
| AddToStatusReportQueue((void *)m_encodeCtx->resBitstreamBuffer.bo), |
| VA_STATUS_ERROR_INVALID_BUFFER); |
| break; |
| |
| case VAEncSliceParameterBufferType: |
| { |
| uint32_t numSlices = buf->uiNumElements; |
| DDI_CHK_STATUS(ParseSlcParams(mediaCtx, data, numSlices), VA_STATUS_ERROR_INVALID_BUFFER); |
| break; |
| } |
| |
| case VAEncPackedHeaderParameterBufferType: |
| if ((*((int32_t *)data) == VAEncPackedHeaderRawData) || (*((int32_t *)data) == VA_ENC_PACKED_HEADER_MISC)) |
| { |
| m_appDataSize = (((VAEncPackedHeaderParameterBuffer *)data)->bit_length + 7) >> 3; |
| } |
| else |
| { |
| vaStatus = VA_STATUS_ERROR_INVALID_BUFFER; |
| } |
| break; |
| |
| case VAEncPackedHeaderDataBufferType: |
| { |
| uint8_t *tmpAppData = (uint8_t *)data; |
| //by default m_appDataWholeHeader is false, it means it only include headers between 0xFFE0 to 0xFFEF; |
| //follow JPEG spec definition of application segment definition |
| //if the packed header is start with 0xFFD8, a new SOI, it should include whole jpeg headers |
| if((tmpAppData[0] == 0xFF) && (tmpAppData[1] == 0xD8)) |
| { |
| m_appDataWholeHeader = true; |
| } |
| if(m_appDataWholeHeader) |
| { |
| vaStatus = ParseAppData(data,m_appDataSize); |
| } |
| else |
| { |
| vaStatus = ParseAppData(data, buf->iSize); |
| } |
| m_appDataSize = 0; |
| } |
| break; |
| |
| case VAHuffmanTableBufferType: |
| DDI_CHK_STATUS(ParseHuffmanParams(data), VA_STATUS_ERROR_INVALID_BUFFER); |
| break; |
| |
| case VAEncQPBufferType: |
| DdiMedia_MediaBufferToMosResource(buf, &m_encodeCtx->resMBQpBuffer); |
| m_encodeCtx->bMBQpEnable = true; |
| break; |
| |
| default: |
| DDI_ASSERTMESSAGE("not supported buffer type."); |
| break; |
| } |
| DdiMedia_UnmapBuffer(ctx, buffers[i]); |
| } |
| |
| DDI_FUNCTION_EXIT(vaStatus); |
| return vaStatus; |
| } |
| |
| // reset the parameters before each frame |
| VAStatus DdiEncodeJpeg::ResetAtFrameLevel() |
| { |
| DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| // Set the render target format |
| CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams; |
| DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| picParams->m_inputSurfaceFormat = ConvertMediaFormatToInputSurfaceFormat(m_encodeCtx->RTtbl.pCurrentRT->format); |
| |
| m_appDataSize = 0; |
| m_appDataTotalSize = 0; |
| m_appDataWholeHeader = false; |
| m_quantSupplied = false; |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus DdiEncodeJpeg::ParsePicParams(DDI_MEDIA_CONTEXT *mediaCtx, void *ptr) |
| { |
| DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_PARAMETER); |
| DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER); |
| DDI_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| VAEncPictureParameterBufferJPEG *picParams = (VAEncPictureParameterBufferJPEG *)ptr; |
| |
| CodecEncodeJpegPictureParams *jpegPicParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams; |
| DDI_CHK_NULL(jpegPicParams, "nullptr jpegPicParams", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| if (jpegPicParams->m_inputSurfaceFormat == DDI_ENCODE_JPEG_INPUTFORMAT_RESERVED) |
| { |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| DDI_MEDIA_BUFFER *buf = DdiMedia_GetBufferFromVABufferID(mediaCtx, picParams->coded_buf); |
| DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER); |
| RemoveFromStatusReportQueue(buf); |
| DdiMedia_MediaBufferToMosResource(buf, &(m_encodeCtx->resBitstreamBuffer)); |
| |
| jpegPicParams->m_profile = picParams->pic_flags.bits.profile; |
| jpegPicParams->m_progressive = picParams->pic_flags.bits.progressive; |
| jpegPicParams->m_huffman = picParams->pic_flags.bits.huffman; |
| jpegPicParams->m_interleaved = picParams->pic_flags.bits.interleaved; |
| jpegPicParams->m_differential = picParams->pic_flags.bits.differential; |
| |
| jpegPicParams->m_picWidth = picParams->picture_width; |
| jpegPicParams->m_picHeight = picParams->picture_height; |
| jpegPicParams->m_sampleBitDepth = picParams->sample_bit_depth; |
| jpegPicParams->m_numComponent = picParams->num_components; |
| jpegPicParams->m_quality = picParams->quality; |
| jpegPicParams->m_numScan = picParams->num_scan; |
| jpegPicParams->m_statusReportFeedbackNumber = 1; |
| |
| for (int32_t i = 0; i < jpegNumComponent; i++) |
| { |
| jpegPicParams->m_componentID[i] = picParams->component_id[i]; |
| jpegPicParams->m_quantTableSelector[i] = picParams->quantiser_table_selector[i]; |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus DdiEncodeJpeg::ParseSlcParams(DDI_MEDIA_CONTEXT *mediaCtx, void *ptr, uint32_t numSlices) |
| { |
| DDI_UNUSED(mediaCtx); |
| |
| if (numSlices != 1) |
| { |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER); |
| DDI_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER); |
| DDI_CHK_NULL(m_huffmanTable, "nullptr m_huffmanTable", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| VAEncSliceParameterBufferJPEG *scanParams = (VAEncSliceParameterBufferJPEG *)ptr; |
| |
| CodecEncodeJpegScanHeader *scanData = (CodecEncodeJpegScanHeader *)m_encodeCtx->pSliceParams; |
| DDI_CHK_NULL(scanData, "nullptr scanData", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| m_encodeCtx->dwNumSlices = numSlices; |
| |
| // Only 1 scan is supported for JPEG |
| scanData->m_restartInterval = scanParams->restart_interval; |
| scanData->m_numComponent = scanParams->num_components; |
| |
| for (int32_t componentCount = 0; componentCount < jpegNumComponent; componentCount++) |
| { |
| scanData->m_componentSelector[componentCount] = scanParams->components[componentCount].component_selector; |
| scanData->m_dcCodingTblSelector[componentCount] = scanParams->components[componentCount].dc_table_selector; |
| scanData->m_acCodingTblSelector[componentCount] = scanParams->components[componentCount].ac_table_selector; |
| |
| // AC and DC table selectors always have the same value for android |
| m_huffmanTable->m_huffmanData[componentCount].m_tableID = scanData->m_dcCodingTblSelector[componentCount]; |
| } |
| |
| // Table ID for DC table for luma |
| m_huffmanTable->m_huffmanData[0].m_tableID = scanData->m_dcCodingTblSelector[0]; |
| |
| //Table ID for AC table for luma |
| m_huffmanTable->m_huffmanData[1].m_tableID = scanData->m_acCodingTblSelector[0]; |
| |
| // Table ID for DC table for chroma |
| m_huffmanTable->m_huffmanData[2].m_tableID = scanData->m_dcCodingTblSelector[1]; |
| |
| // Table ID for AC table for chroma |
| m_huffmanTable->m_huffmanData[3].m_tableID = scanData->m_dcCodingTblSelector[1]; |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus DdiEncodeJpeg::Qmatrix(void *ptr) |
| { |
| DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER); |
| DDI_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| VAQMatrixBufferJPEG *quantParams = (VAQMatrixBufferJPEG *)ptr; |
| |
| CodecEncodeJpegQuantTable *quantMatrix = (CodecEncodeJpegQuantTable *)m_encodeCtx->pQmatrixParams; |
| DDI_CHK_NULL(quantMatrix, "nullptr quantMatrix", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| // Setting number of Quantization tables in Picture Params |
| CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams; |
| DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| picParams->m_numQuantTable = 0; |
| |
| if (quantParams->load_lum_quantiser_matrix == 1) |
| { |
| quantMatrix->m_quantTable[0].m_precision = 0; // only 8 bit precision is supported |
| quantMatrix->m_quantTable[0].m_tableID = 0; // tableID is 0 for luma |
| |
| picParams->m_numQuantTable++; |
| |
| for (int32_t i = 0; i < numQuantMatrix; i++) |
| { |
| quantMatrix->m_quantTable[0].m_qm[i] = quantParams->lum_quantiser_matrix[i] & 0xFF; |
| } |
| } |
| else // no luma quantization table present - invalid argument |
| { |
| // switch to default quantization table |
| m_quantSupplied = false; |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| if (quantParams->load_chroma_quantiser_matrix == 1) |
| { |
| quantMatrix->m_quantTable[1].m_precision = 0; // only 8 bit precision is supported |
| quantMatrix->m_quantTable[1].m_tableID = 1; // table ID is 1 and 2 for U and V |
| |
| picParams->m_numQuantTable++; |
| |
| for (int32_t i = 0; i < numQuantMatrix; i++) |
| { |
| quantMatrix->m_quantTable[1].m_qm[i] = quantParams->chroma_quantiser_matrix[i] & 0xFF; |
| } |
| } |
| |
| m_quantSupplied = true; |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus DdiEncodeJpeg::ParseHuffmanParams(void *ptr) |
| { |
| DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER); |
| DDI_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER); |
| DDI_CHK_NULL(m_huffmanTable, "nullptr m_huffmanTable", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| VAHuffmanTableBufferJPEGBaseline *params = (VAHuffmanTableBufferJPEGBaseline *)ptr; |
| |
| // Setting number of Huffman tables in Picture Params |
| CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams; |
| DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| // For setting the tableIDs |
| CodecEncodeJpegScanHeader *scanData = (CodecEncodeJpegScanHeader *)m_encodeCtx->pSliceParams; |
| DDI_CHK_NULL(scanData, "nullptr scanData", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| picParams->m_numCodingTable = 0; |
| |
| uint32_t numHuffBuffers = 0; // To check how many Huffman buffers the app sends |
| |
| // Max number of huffman tables that can be sent by the app is 2 |
| for (int32_t tblCount = 0; tblCount < maxNumHuffTables; tblCount++) |
| { |
| if (params->load_huffman_table[tblCount] != 0) |
| { |
| numHuffBuffers++; |
| |
| // first copy DC table |
| m_huffmanTable->m_huffmanData[tblCount * 2].m_tableClass = 0; |
| m_huffmanTable->m_huffmanData[tblCount * 2].m_tableID = scanData->m_dcCodingTblSelector[tblCount]; |
| |
| for (int32_t i = 0; i < JPEG_NUM_HUFF_TABLE_DC_BITS; i++) |
| { |
| m_huffmanTable->m_huffmanData[tblCount * 2].m_bits[i] = params->huffman_table[tblCount].num_dc_codes[i] & 0xFF; |
| } |
| for (int32_t i = 0; i < JPEG_NUM_HUFF_TABLE_DC_HUFFVAL; i++) |
| { |
| m_huffmanTable->m_huffmanData[tblCount * 2].m_huffVal[i] = params->huffman_table[tblCount].dc_values[i] & 0xFF; |
| } |
| |
| // Now copy AC table |
| m_huffmanTable->m_huffmanData[(tblCount * 2) + 1].m_tableClass = 1; |
| m_huffmanTable->m_huffmanData[(tblCount * 2) + 1].m_tableID = scanData->m_acCodingTblSelector[tblCount]; |
| |
| for (int32_t i = 0; i < JPEG_NUM_HUFF_TABLE_AC_BITS; i++) |
| { |
| m_huffmanTable->m_huffmanData[(tblCount * 2) + 1].m_bits[i] = params->huffman_table[tblCount].num_ac_codes[i] & 0xFF; |
| } |
| for (int32_t i = 0; i < JPEG_NUM_HUFF_TABLE_AC_HUFFVAL; i++) |
| { |
| m_huffmanTable->m_huffmanData[(tblCount * 2) + 1].m_huffVal[i] = params->huffman_table[tblCount].ac_values[i] & 0xFF; |
| } |
| } |
| } |
| |
| if (numHuffBuffers > (JPEG_NUM_ENCODE_HUFF_BUFF / 2)) |
| { |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| // Multiplying with 2 because each table contains both AC and DC buffers |
| picParams->m_numCodingTable += numHuffBuffers * 2; |
| |
| return VA_STATUS_SUCCESS; |
| }; |
| |
| VAStatus DdiEncodeJpeg::ParseAppData(void *ptr, int32_t size) |
| { |
| DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx.", VA_STATUS_ERROR_INVALID_PARAMETER); |
| DDI_CHK_NULL(ptr, "nullptr ptr.", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| uint32_t prevAppDataSize = m_appDataTotalSize; |
| |
| if (m_appData == nullptr) |
| { |
| m_appData = (void *)MOS_AllocAndZeroMemory(size); |
| |
| if (!m_appData) |
| { |
| return VA_STATUS_ERROR_ALLOCATION_FAILED; |
| } |
| |
| MOS_SecureMemcpy(m_appData, size, ptr, size); |
| } |
| else // app data had been sent before |
| { |
| void *tempAppData = (void *)MOS_AllocAndZeroMemory(size + (int32_t)prevAppDataSize); |
| |
| if (nullptr == tempAppData) |
| { |
| return VA_STATUS_ERROR_ALLOCATION_FAILED; |
| } |
| |
| // Copy over previous app data to a new location |
| MOS_SecureMemcpy(tempAppData, prevAppDataSize, (uint8_t *)m_appData, prevAppDataSize); |
| |
| uint8_t *newAddress = (uint8_t *)tempAppData + prevAppDataSize; |
| |
| // Add new app data buffer to the new location |
| MOS_SecureMemcpy(newAddress, size, (uint8_t *)ptr, size); |
| |
| // Now free the previous location containing app data and overwrite with new app data buffer |
| MOS_FreeMemory(m_appData); |
| m_appData = tempAppData; |
| |
| } |
| |
| m_appDataTotalSize += size; |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus DdiEncodeJpeg::EncodeInCodecHal(uint32_t numSlices) |
| { |
| DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_CONTEXT); |
| DDI_CHK_NULL(m_encodeCtx->pCodecHal, "nullptr m_encodeCtx->pCodecHal", VA_STATUS_ERROR_INVALID_CONTEXT); |
| |
| if (numSlices != 1) |
| { |
| return VA_STATUS_ERROR_INVALID_PARAMETER; |
| } |
| |
| DDI_CODEC_RENDER_TARGET_TABLE *rtTbl = &(m_encodeCtx->RTtbl); |
| |
| CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)(m_encodeCtx->pPicParams); |
| |
| CodecEncodeJpegScanHeader *scanData = (CodecEncodeJpegScanHeader *)m_encodeCtx->pSliceParams; |
| |
| EncoderParams encodeParams; |
| MOS_ZeroMemory(&encodeParams, sizeof(EncoderParams)); |
| encodeParams.ExecCodecFunction = CODECHAL_FUNCTION_PAK; |
| |
| // Check if Qunt table was sent by application |
| // if it is not sent by application, driver will use default and scaled by quality setting |
| // if it is sent by application, and it also packed header with scaled qmatrix |
| // scal the qmatrix to change with quality setting |
| if (!m_quantSupplied) |
| { |
| DefaultQmatrix(); |
| } |
| else if(m_appDataWholeHeader) |
| { |
| QualityScaleQmatrix(); |
| } |
| |
| // Raw Surface |
| MOS_SURFACE rawSurface; |
| MOS_ZeroMemory(&rawSurface, sizeof(MOS_SURFACE)); |
| rawSurface.Format = (MOS_FORMAT)picParams->m_inputSurfaceFormat; |
| rawSurface.dwOffset = 0; |
| |
| DdiMedia_MediaSurfaceToMosResource(rtTbl->pCurrentRT, &(rawSurface.OsResource)); |
| // Recon Surface |
| MOS_SURFACE reconSurface; |
| MOS_ZeroMemory(&reconSurface, sizeof(MOS_SURFACE)); |
| reconSurface.Format = Format_Invalid; |
| reconSurface.dwOffset = 0; |
| |
| encodeParams.bJpegQuantMatrixSent = m_quantSupplied; |
| |
| // Bitstream surface |
| MOS_RESOURCE bitstreamSurface; |
| MOS_ZeroMemory(&bitstreamSurface, sizeof(MOS_RESOURCE)); |
| bitstreamSurface = m_encodeCtx->resBitstreamBuffer; // in render picture |
| bitstreamSurface.Format = Format_Buffer; |
| |
| encodeParams.psRawSurface = &rawSurface; |
| encodeParams.psReconSurface = &reconSurface; |
| encodeParams.presBitstreamBuffer = &bitstreamSurface; |
| |
| encodeParams.pPicParams = m_encodeCtx->pPicParams; |
| encodeParams.pSliceParams = m_encodeCtx->pSliceParams; |
| encodeParams.pApplicationData = m_appData; |
| |
| // Slice level data |
| encodeParams.dwNumSlices = numSlices; |
| encodeParams.dwNumHuffBuffers = picParams->m_numCodingTable; |
| encodeParams.dwAppDataSize = m_appDataTotalSize; |
| encodeParams.fullHeaderInAppData = m_appDataWholeHeader; |
| |
| encodeParams.pQuantizationTable = m_encodeCtx->pQmatrixParams; |
| encodeParams.pHuffmanTable = m_huffmanTable; |
| encodeParams.pBSBuffer = m_encodeCtx->pbsBuffer; |
| encodeParams.pSlcHeaderData = (void *)m_encodeCtx->pSliceHeaderData; |
| |
| if (scanData->m_numComponent == 1) // Y8 input format |
| { |
| // Take the first table sent by the app |
| encodeParams.dwNumHuffBuffers = 2; |
| } |
| |
| MOS_STATUS status = m_encodeCtx->pCodecHal->Execute(&encodeParams); |
| if (MOS_STATUS_SUCCESS != status) |
| { |
| return VA_STATUS_ERROR_ENCODING_ERROR; |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| uint32_t DdiEncodeJpeg::ConvertMediaFormatToInputSurfaceFormat(DDI_MEDIA_FORMAT format) |
| { |
| switch (format) |
| { |
| case Media_Format_NV12: |
| return DDI_ENCODE_JPEG_INPUTFORMAT_NV12; |
| case Media_Format_422H: |
| case Media_Format_422V: |
| case Media_Format_UYVY: |
| return DDI_ENCODE_JPEG_INPUTFORMAT_UYVY; |
| case Media_Format_YUY2: |
| return DDI_ENCODE_JPEG_INPUTFORMAT_YUY2; |
| case Media_Format_400P: |
| return DDI_ENCODE_JPEG_INPUTFORMAT_Y8; |
| case Media_Format_X8R8G8B8: |
| case Media_Format_A8R8G8B8: |
| case Media_Format_X8B8G8R8: |
| case Media_Format_R8G8B8A8: |
| case Media_Format_A8B8G8R8: |
| case Media_Format_444P: |
| return DDI_ENCODE_JPEG_INPUTFORMAT_RGB; |
| default: |
| return DDI_ENCODE_JPEG_INPUTFORMAT_RESERVED; |
| } |
| } |
| |
| VAStatus DdiEncodeJpeg::DefaultQmatrix() |
| { |
| DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| CodecEncodeJpegQuantTable *quantMatrix = (CodecEncodeJpegQuantTable *)m_encodeCtx->pQmatrixParams; |
| DDI_CHK_NULL(quantMatrix, "nullptr quantMatrix", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| // To get Quality from Pic Params |
| CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams; |
| DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| uint32_t quality = 0; |
| if (picParams->m_quality < 50) |
| { |
| quality = 5000 / picParams->m_quality; |
| } |
| else |
| { |
| quality = 200 - (picParams->m_quality * 2); |
| } |
| |
| // 2 tables - one for luma and one for chroma |
| for (int32_t qMatrixCount = 0; qMatrixCount < maxNumQuantTableIndex; qMatrixCount++) |
| { |
| quantMatrix->m_quantTable[qMatrixCount].m_precision = 0; |
| quantMatrix->m_quantTable[qMatrixCount].m_tableID = qMatrixCount; |
| |
| for (int32_t i = 0; i < numQuantMatrix; i++) |
| { |
| uint32_t quantValue = 0; |
| if (qMatrixCount == 0) |
| { |
| quantValue = (defaultLumaQuant[i] * quality + 50) / 100; |
| } |
| else |
| { |
| quantValue = (defaultChromaQuant[i] * quality + 50) / 100; |
| } |
| |
| // Clamp the value to range between 1 and 255 |
| if (quantValue < 1) |
| { |
| quantValue = 1; |
| } |
| else if (quantValue > 255) |
| { |
| quantValue = 255; |
| } |
| |
| quantMatrix->m_quantTable[qMatrixCount].m_qm[i] = (uint16_t)quantValue; |
| } |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus DdiEncodeJpeg::QualityScaleQmatrix() |
| { |
| DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| CodecEncodeJpegQuantTable *quantMatrix = (CodecEncodeJpegQuantTable *)m_encodeCtx->pQmatrixParams; |
| DDI_CHK_NULL(quantMatrix, "nullptr quantMatrix", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| // To get Quality from Pic Params |
| CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams; |
| DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER); |
| |
| uint32_t quality = 0; |
| if (picParams->m_quality < 50) |
| { |
| quality = 5000 / picParams->m_quality; |
| } |
| else |
| { |
| quality = 200 - (picParams->m_quality * 2); |
| } |
| |
| // 2 tables - one for luma and one for chroma |
| for (int32_t qMatrixCount = 0; qMatrixCount < picParams->m_numQuantTable; qMatrixCount++) |
| { |
| quantMatrix->m_quantTable[qMatrixCount].m_precision = 0; |
| quantMatrix->m_quantTable[qMatrixCount].m_tableID = qMatrixCount; |
| |
| for (int32_t i = 0; i < numQuantMatrix; i++) |
| { |
| uint32_t quantValue = 0; |
| quantValue = ( ((uint32_t)(quantMatrix->m_quantTable[qMatrixCount].m_qm[i])) * quality + 50) / 100; |
| |
| // Clamp the value to range between 1 and 255 |
| if (quantValue < 1) |
| { |
| quantValue = 1; |
| } |
| else if (quantValue > 255) |
| { |
| quantValue = 255; |
| } |
| |
| quantMatrix->m_quantTable[qMatrixCount].m_qm[i] = (uint16_t)quantValue; |
| } |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| uint32_t DdiEncodeJpeg::getSliceParameterBufferSize() |
| { |
| return sizeof(VAEncSliceParameterBufferJPEG); |
| } |
| |
| uint32_t DdiEncodeJpeg::getPictureParameterBufferSize() |
| { |
| return sizeof(VAEncPictureParameterBufferJPEG); |
| } |
| |
| uint32_t DdiEncodeJpeg::getQMatrixBufferSize() |
| { |
| return sizeof(VAQMatrixBufferJPEG); |
| } |