1 /*
2 * Copyright (c) 2022, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file ddi_encode_jpeg_specific.cpp
24 //! \brief Defines class for DDI media jpeg encode.
25 //!
26
27 #include "media_libva_encoder.h"
28 #include "media_libva_util_next.h"
29 #include "ddi_encode_jpeg_specific.h"
30 #include "media_ddi_encode_const.h"
31 #include "media_ddi_factory.h"
32 #include "media_libva_interface_next.h"
33
34 namespace encode
35 {
36
~DdiEncodeJpeg()37 DdiEncodeJpeg::~DdiEncodeJpeg()
38 {
39 if (m_encodeCtx == nullptr)
40 {
41 return;
42 }
43
44 MOS_FreeMemory(m_encodeCtx->pPicParams);
45 m_encodeCtx->pPicParams = nullptr;
46
47 MOS_FreeMemory(m_encodeCtx->pEncodeStatusReport);
48 m_encodeCtx->pEncodeStatusReport = nullptr;
49
50 MOS_FreeMemory(m_huffmanTable);
51 m_huffmanTable = nullptr;
52
53 MOS_FreeMemory(m_encodeCtx->pQmatrixParams);
54 m_encodeCtx->pQmatrixParams = nullptr;
55
56 MOS_FreeMemory(m_encodeCtx->pSliceParams);
57 m_encodeCtx->pSliceParams = nullptr;
58
59 MOS_FreeMemory(m_encodeCtx->pbsBuffer);
60 m_encodeCtx->pbsBuffer = nullptr;
61
62 MOS_FreeMemory(m_appData);
63 m_appData = nullptr;
64 }
65
ContextInitialize(CodechalSetting * codecHalSettings)66 VAStatus DdiEncodeJpeg::ContextInitialize(CodechalSetting *codecHalSettings)
67 {
68 DDI_CODEC_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx.", VA_STATUS_ERROR_INVALID_CONTEXT);
69 DDI_CODEC_CHK_NULL(m_encodeCtx->pCpDdiInterfaceNext, "nullptr m_encodeCtx->pCpDdiInterfaceNext.", VA_STATUS_ERROR_INVALID_CONTEXT);
70 DDI_CODEC_CHK_NULL(codecHalSettings, "nullptr codecHalSettings.", VA_STATUS_ERROR_INVALID_PARAMETER);
71 VAStatus vaStatus = VA_STATUS_SUCCESS;
72
73 codecHalSettings->codecFunction = CODECHAL_FUNCTION_PAK;
74 codecHalSettings->width = m_encodeCtx->dwFrameWidth;
75 codecHalSettings->height = m_encodeCtx->dwFrameHeight;
76 codecHalSettings->mode = m_encodeCtx->wModeType;
77 codecHalSettings->standard = CODECHAL_JPEG;
78
79 m_quantSupplied = false;
80 m_appDataSize = 0;
81 m_appDataTotalSize = 0;
82 m_appDataWholeHeader = false;
83
84 m_encodeCtx->pPicParams = (void *)MOS_AllocAndZeroMemory(sizeof(CodecEncodeJpegPictureParams));
85 DDI_CODEC_CHK_NULL(m_encodeCtx->pPicParams, "nullptr m_encodeCtx->pPicParams.", VA_STATUS_ERROR_ALLOCATION_FAILED);
86
87 m_encodeCtx->pbsBuffer = (BSBuffer *)MOS_AllocAndZeroMemory(sizeof(BSBuffer));
88 DDI_CODEC_CHK_NULL(m_encodeCtx->pbsBuffer, "nullptr m_encodeCtx->pbsBuffer.", VA_STATUS_ERROR_ALLOCATION_FAILED);
89
90 // Allocate Encode Status Report
91 m_encodeCtx->pEncodeStatusReport = (void *)MOS_AllocAndZeroMemory(CODECHAL_ENCODE_STATUS_NUM * sizeof(EncodeStatusReportData));
92 DDI_CODEC_CHK_NULL(m_encodeCtx->pEncodeStatusReport, "nullptr m_encodeCtx->pEncodeStatusReport.", VA_STATUS_ERROR_ALLOCATION_FAILED);
93
94 // for scan header from application
95 m_encodeCtx->pSliceParams = (void *)MOS_AllocAndZeroMemory(sizeof(CodecEncodeJpegScanHeader));
96 DDI_CODEC_CHK_NULL(m_encodeCtx->pSliceParams, "nullptr m_encodeCtx->pSliceParams.", VA_STATUS_ERROR_ALLOCATION_FAILED);
97
98 // for Quant table
99 m_encodeCtx->pQmatrixParams = (void *)MOS_AllocAndZeroMemory(sizeof(CodecEncodeJpegQuantTable));
100 DDI_CODEC_CHK_NULL(m_encodeCtx->pQmatrixParams, "nullptr m_encodeCtx->pQmatrixParams.", VA_STATUS_ERROR_ALLOCATION_FAILED);
101
102 // for pHuffmanTable
103 m_huffmanTable = (CodecEncodeJpegHuffmanDataArray *)MOS_AllocAndZeroMemory(sizeof(CodecEncodeJpegHuffmanDataArray));
104 DDI_CODEC_CHK_NULL(m_huffmanTable, "nullptr m_huffmanTable.", VA_STATUS_ERROR_ALLOCATION_FAILED);
105
106 return vaStatus;
107 }
108
RenderPicture(VADriverContextP ctx,VAContextID context,VABufferID * buffers,int32_t numBuffers)109 VAStatus DdiEncodeJpeg::RenderPicture(
110 VADriverContextP ctx,
111 VAContextID context,
112 VABufferID *buffers,
113 int32_t numBuffers)
114 {
115 VAStatus vaStatus = VA_STATUS_SUCCESS;
116
117 DDI_CODEC_FUNC_ENTER;
118
119 DDI_CODEC_CHK_NULL(ctx, "nullptr context", VA_STATUS_ERROR_INVALID_CONTEXT);
120
121 DDI_MEDIA_CONTEXT *mediaCtx = GetMediaContext(ctx);
122 DDI_CODEC_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
123
124 DDI_CODEC_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
125
126 for (int32_t i = 0; i < numBuffers; i++)
127 {
128 DDI_MEDIA_BUFFER *buf = MediaLibvaCommonNext::GetBufferFromVABufferID(mediaCtx, buffers[i]);
129 DDI_CODEC_CHK_NULL(buf, "Invalid buffer.", VA_STATUS_ERROR_INVALID_BUFFER);
130 if (buf->uiType == VAEncMacroblockDisableSkipMapBufferType)
131 {
132 MediaLibvaCommonNext::MediaBufferToMosResource(buf, &(m_encodeCtx->resPerMBSkipMapBuffer));
133 m_encodeCtx->bMbDisableSkipMapEnabled = true;
134 continue;
135 }
136 uint32_t dataSize = buf->iSize;
137 // can use internal function instead of MediaLibvaInterfaceNext::MapBuffer here?
138 void *data = nullptr;
139 MediaLibvaInterfaceNext::MapBuffer(ctx, buffers[i], &data);
140 DDI_CODEC_CHK_NULL(data, "nullptr data.", VA_STATUS_ERROR_INVALID_BUFFER);
141
142 switch (buf->uiType)
143 {
144 case VAIQMatrixBufferType:
145 case VAQMatrixBufferType:
146 {
147 DDI_CHK_STATUS(Qmatrix(data), VA_STATUS_ERROR_INVALID_BUFFER);
148 break;
149 }
150
151 case VAEncPictureParameterBufferType:
152 {
153 DDI_CHK_STATUS(ParsePicParams(mediaCtx, data), VA_STATUS_ERROR_INVALID_BUFFER);
154 DDI_CHK_STATUS(
155 AddToStatusReportQueue((void*)m_encodeCtx->resBitstreamBuffer.bo),
156 VA_STATUS_ERROR_INVALID_BUFFER);
157 break;
158 }
159
160 case VAEncSliceParameterBufferType:
161 {
162 uint32_t numSlices = buf->uiNumElements;
163 DDI_CHK_STATUS(ParseSlcParams(mediaCtx, data, numSlices), VA_STATUS_ERROR_INVALID_BUFFER);
164 break;
165 }
166
167 case VAEncPackedHeaderParameterBufferType:
168 {
169 if ((*((int32_t*)data) == VAEncPackedHeaderRawData) || (*((int32_t*)data) == VA_ENC_PACKED_HEADER_MISC))
170 {
171 m_appDataSize = (((VAEncPackedHeaderParameterBuffer*)data)->bit_length + 7) >> 3;
172 }
173 else
174 {
175 vaStatus = VA_STATUS_ERROR_INVALID_BUFFER;
176 }
177 break;
178 }
179
180 case VAEncPackedHeaderDataBufferType:
181 {
182 uint8_t* tmpAppData = (uint8_t*)data;
183 //by default m_appDataWholeHeader is false, it means it only include headers between 0xFFE0 to 0xFFEF;
184 //follow JPEG spec definition of application segment definition
185 //if the packed header is start with 0xFFD8, a new SOI, it should include whole jpeg headers
186 if ((tmpAppData[0] == 0xFF) && (tmpAppData[1] == 0xD8))
187 {
188 m_appDataWholeHeader = true;
189 }
190 if (m_appDataWholeHeader)
191 {
192 vaStatus = ParseAppData(data, m_appDataSize);
193 }
194 else
195 {
196 vaStatus = ParseAppData(data, buf->iSize);
197 }
198 m_appDataSize = 0;
199 break;
200 }
201
202 case VAHuffmanTableBufferType:
203 {
204 DDI_CHK_STATUS(ParseHuffmanParams(data), VA_STATUS_ERROR_INVALID_BUFFER);
205 break;
206 }
207
208 case VAEncQPBufferType:
209 {
210 MediaLibvaCommonNext::MediaBufferToMosResource(buf, &m_encodeCtx->resMBQpBuffer);
211 m_encodeCtx->bMBQpEnable = true;
212 break;
213 }
214
215 default:
216 {
217 DDI_CODEC_ASSERTMESSAGE("not supported buffer type.");
218 break;
219 }
220 }
221 MediaLibvaInterfaceNext::UnmapBuffer(ctx, buffers[i]);
222 }
223
224 return vaStatus;
225 }
226
227 // reset the parameters before each frame
ResetAtFrameLevel()228 VAStatus DdiEncodeJpeg::ResetAtFrameLevel()
229 {
230 DDI_CODEC_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
231
232 // Set the render target format
233 CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams;
234 DDI_CODEC_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
235
236 picParams->m_inputSurfaceFormat = ConvertMediaFormatToInputSurfaceFormat(m_encodeCtx->RTtbl.pCurrentRT->format);
237
238 m_appDataSize = 0;
239 m_appDataTotalSize = 0;
240 m_appDataWholeHeader = false;
241 m_quantSupplied = false;
242
243 return VA_STATUS_SUCCESS;
244 }
245
ParsePicParams(DDI_MEDIA_CONTEXT * mediaCtx,void * ptr)246 VAStatus DdiEncodeJpeg::ParsePicParams(DDI_MEDIA_CONTEXT *mediaCtx, void *ptr)
247 {
248 DDI_CODEC_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
249 DDI_CODEC_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
250 DDI_CODEC_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER);
251
252 VAEncPictureParameterBufferJPEG *picParams = (VAEncPictureParameterBufferJPEG *)ptr;
253
254 CodecEncodeJpegPictureParams *jpegPicParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams;
255 DDI_CODEC_CHK_NULL(jpegPicParams, "nullptr jpegPicParams", VA_STATUS_ERROR_INVALID_PARAMETER);
256
257 if (jpegPicParams->m_inputSurfaceFormat == DDI_ENCODE_JPEG_INPUTFORMAT_RESERVED)
258 {
259 return VA_STATUS_ERROR_INVALID_PARAMETER;
260 }
261
262 DDI_MEDIA_BUFFER *buf = MediaLibvaCommonNext::GetBufferFromVABufferID(mediaCtx, picParams->coded_buf);
263 DDI_CODEC_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER);
264 RemoveFromStatusReportQueue(buf);
265 MediaLibvaCommonNext::MediaBufferToMosResource(buf, &(m_encodeCtx->resBitstreamBuffer));
266
267 jpegPicParams->m_profile = picParams->pic_flags.bits.profile;
268 jpegPicParams->m_progressive = picParams->pic_flags.bits.progressive;
269 jpegPicParams->m_huffman = picParams->pic_flags.bits.huffman;
270 jpegPicParams->m_interleaved = picParams->pic_flags.bits.interleaved;
271 jpegPicParams->m_differential = picParams->pic_flags.bits.differential;
272
273 jpegPicParams->m_picWidth = picParams->picture_width;
274 jpegPicParams->m_picHeight = picParams->picture_height;
275 jpegPicParams->m_sampleBitDepth = picParams->sample_bit_depth;
276 jpegPicParams->m_numComponent = picParams->num_components;
277 jpegPicParams->m_quality = picParams->quality;
278 jpegPicParams->m_numScan = picParams->num_scan;
279 jpegPicParams->m_statusReportFeedbackNumber = 1;
280
281 for (int32_t i = 0; i < jpegNumComponent; i++)
282 {
283 jpegPicParams->m_componentID[i] = picParams->component_id[i];
284 jpegPicParams->m_quantTableSelector[i] = picParams->quantiser_table_selector[i];
285 }
286
287 return VA_STATUS_SUCCESS;
288 }
289
ParseSlcParams(DDI_MEDIA_CONTEXT * mediaCtx,void * ptr,uint32_t numSlices)290 VAStatus DdiEncodeJpeg::ParseSlcParams(DDI_MEDIA_CONTEXT *mediaCtx, void *ptr, uint32_t numSlices)
291 {
292 DDI_UNUSED(mediaCtx);
293
294 if (numSlices != 1)
295 {
296 return VA_STATUS_ERROR_INVALID_PARAMETER;
297 }
298
299 DDI_CODEC_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
300 DDI_CODEC_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER);
301 DDI_CODEC_CHK_NULL(m_huffmanTable, "nullptr m_huffmanTable", VA_STATUS_ERROR_INVALID_PARAMETER);
302
303 VAEncSliceParameterBufferJPEG *scanParams = (VAEncSliceParameterBufferJPEG *)ptr;
304
305 CodecEncodeJpegScanHeader *scanData = (CodecEncodeJpegScanHeader *)m_encodeCtx->pSliceParams;
306 DDI_CODEC_CHK_NULL(scanData, "nullptr scanData", VA_STATUS_ERROR_INVALID_PARAMETER);
307
308 m_encodeCtx->dwNumSlices = numSlices;
309
310 // Only 1 scan is supported for JPEG
311 scanData->m_restartInterval = scanParams->restart_interval;
312 scanData->m_numComponent = scanParams->num_components;
313
314 for (int32_t componentCount = 0; componentCount < jpegNumComponent; componentCount++)
315 {
316 scanData->m_componentSelector[componentCount] = scanParams->components[componentCount].component_selector;
317 scanData->m_dcCodingTblSelector[componentCount] = scanParams->components[componentCount].dc_table_selector;
318 scanData->m_acCodingTblSelector[componentCount] = scanParams->components[componentCount].ac_table_selector;
319
320 // AC and DC table selectors always have the same value for android
321 m_huffmanTable->m_huffmanData[componentCount].m_tableID = scanData->m_dcCodingTblSelector[componentCount];
322 }
323
324 // Table ID for DC table for luma
325 m_huffmanTable->m_huffmanData[0].m_tableID = scanData->m_dcCodingTblSelector[0];
326
327 //Table ID for AC table for luma
328 m_huffmanTable->m_huffmanData[1].m_tableID = scanData->m_acCodingTblSelector[0];
329
330 // Table ID for DC table for chroma
331 m_huffmanTable->m_huffmanData[2].m_tableID = scanData->m_dcCodingTblSelector[1];
332
333 // Table ID for AC table for chroma
334 m_huffmanTable->m_huffmanData[3].m_tableID = scanData->m_dcCodingTblSelector[1];
335
336 return VA_STATUS_SUCCESS;
337 }
338
Qmatrix(void * ptr)339 VAStatus DdiEncodeJpeg::Qmatrix(void *ptr)
340 {
341 DDI_CODEC_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
342 DDI_CODEC_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER);
343
344 VAQMatrixBufferJPEG *quantParams = (VAQMatrixBufferJPEG *)ptr;
345
346 CodecEncodeJpegQuantTable *quantMatrix = (CodecEncodeJpegQuantTable *)m_encodeCtx->pQmatrixParams;
347 DDI_CODEC_CHK_NULL(quantMatrix, "nullptr quantMatrix", VA_STATUS_ERROR_INVALID_PARAMETER);
348
349 // Setting number of Quantization tables in Picture Params
350 CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams;
351 DDI_CODEC_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
352
353 picParams->m_numQuantTable = 0;
354
355 if (quantParams->load_lum_quantiser_matrix == 1)
356 {
357 quantMatrix->m_quantTable[0].m_precision = 0; // only 8 bit precision is supported
358 quantMatrix->m_quantTable[0].m_tableID = 0; // tableID is 0 for luma
359
360 picParams->m_numQuantTable++;
361
362 for (int32_t i = 0; i < QuantMatrixSize; i++)
363 {
364 quantMatrix->m_quantTable[0].m_qm[i] = quantParams->lum_quantiser_matrix[i] & 0xFF;
365 }
366 }
367 else // no luma quantization table present - invalid argument
368 {
369 // switch to default quantization table
370 m_quantSupplied = false;
371 return VA_STATUS_ERROR_INVALID_PARAMETER;
372 }
373
374 if (quantParams->load_chroma_quantiser_matrix == 1)
375 {
376 quantMatrix->m_quantTable[1].m_precision = 0; // only 8 bit precision is supported
377 quantMatrix->m_quantTable[1].m_tableID = 1; // table ID is 1 and 2 for U and V
378
379 picParams->m_numQuantTable++;
380
381 for (int32_t i = 0; i < QuantMatrixSize; i++)
382 {
383 quantMatrix->m_quantTable[1].m_qm[i] = quantParams->chroma_quantiser_matrix[i] & 0xFF;
384 }
385 }
386
387 m_quantSupplied = true;
388
389 return VA_STATUS_SUCCESS;
390 }
391
ParseHuffmanParams(void * ptr)392 VAStatus DdiEncodeJpeg::ParseHuffmanParams(void *ptr)
393 {
394 DDI_CODEC_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
395 DDI_CODEC_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER);
396 DDI_CODEC_CHK_NULL(m_huffmanTable, "nullptr m_huffmanTable", VA_STATUS_ERROR_INVALID_PARAMETER);
397
398 VAHuffmanTableBufferJPEGBaseline *params = (VAHuffmanTableBufferJPEGBaseline *)ptr;
399
400 // Setting number of Huffman tables in Picture Params
401 CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams;
402 DDI_CODEC_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
403
404 // For setting the tableIDs
405 CodecEncodeJpegScanHeader *scanData = (CodecEncodeJpegScanHeader *)m_encodeCtx->pSliceParams;
406 DDI_CODEC_CHK_NULL(scanData, "nullptr scanData", VA_STATUS_ERROR_INVALID_PARAMETER);
407
408 picParams->m_numCodingTable = 0;
409
410 uint32_t numHuffBuffers = 0; // To check how many Huffman buffers the app sends
411
412 // Max number of huffman tables that can be sent by the app is 2
413 for (int32_t tblCount = 0; tblCount < MaxNumHuffTables; tblCount++)
414 {
415 if (params->load_huffman_table[tblCount] != 0)
416 {
417 numHuffBuffers++;
418
419 // first copy DC table
420 m_huffmanTable->m_huffmanData[tblCount * 2].m_tableClass = 0;
421 m_huffmanTable->m_huffmanData[tblCount * 2].m_tableID = scanData->m_dcCodingTblSelector[tblCount];
422
423 for (int32_t i = 0; i < JPEG_NUM_HUFF_TABLE_DC_BITS; i++)
424 {
425 m_huffmanTable->m_huffmanData[tblCount * 2].m_bits[i] = params->huffman_table[tblCount].num_dc_codes[i] & 0xFF;
426 }
427 for (int32_t i = 0; i < JPEG_NUM_HUFF_TABLE_DC_HUFFVAL; i++)
428 {
429 m_huffmanTable->m_huffmanData[tblCount * 2].m_huffVal[i] = params->huffman_table[tblCount].dc_values[i] & 0xFF;
430 }
431
432 // Now copy AC table
433 m_huffmanTable->m_huffmanData[(tblCount * 2) + 1].m_tableClass = 1;
434 m_huffmanTable->m_huffmanData[(tblCount * 2) + 1].m_tableID = scanData->m_acCodingTblSelector[tblCount];
435
436 for (int32_t i = 0; i < JPEG_NUM_HUFF_TABLE_AC_BITS; i++)
437 {
438 m_huffmanTable->m_huffmanData[(tblCount * 2) + 1].m_bits[i] = params->huffman_table[tblCount].num_ac_codes[i] & 0xFF;
439 }
440 for (int32_t i = 0; i < JPEG_NUM_HUFF_TABLE_AC_HUFFVAL; i++)
441 {
442 m_huffmanTable->m_huffmanData[(tblCount * 2) + 1].m_huffVal[i] = params->huffman_table[tblCount].ac_values[i] & 0xFF;
443 }
444 }
445 }
446
447 if (numHuffBuffers > (JPEG_NUM_ENCODE_HUFF_BUFF / 2))
448 {
449 return VA_STATUS_ERROR_INVALID_PARAMETER;
450 }
451
452 // Multiplying with 2 because each table contains both AC and DC buffers
453 picParams->m_numCodingTable += numHuffBuffers * 2;
454
455 return VA_STATUS_SUCCESS;
456 };
457
ParseAppData(void * ptr,int32_t size)458 VAStatus DdiEncodeJpeg::ParseAppData(void *ptr, int32_t size)
459 {
460 DDI_CODEC_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx.", VA_STATUS_ERROR_INVALID_PARAMETER);
461 DDI_CODEC_CHK_NULL(ptr, "nullptr ptr.", VA_STATUS_ERROR_INVALID_PARAMETER);
462
463 uint32_t prevAppDataSize = m_appDataTotalSize;
464
465 if (m_appData == nullptr)
466 {
467 m_appData = (void *)MOS_AllocAndZeroMemory(size);
468
469 if (!m_appData)
470 {
471 return VA_STATUS_ERROR_ALLOCATION_FAILED;
472 }
473
474 MOS_SecureMemcpy(m_appData, size, ptr, size);
475 }
476 else // app data had been sent before
477 {
478 void *tempAppData = (void *)MOS_AllocAndZeroMemory(size + (int32_t)prevAppDataSize);
479
480 if (nullptr == tempAppData)
481 {
482 return VA_STATUS_ERROR_ALLOCATION_FAILED;
483 }
484
485 // Copy over previous app data to a new location
486 MOS_SecureMemcpy(tempAppData, prevAppDataSize, (uint8_t *)m_appData, prevAppDataSize);
487
488 uint8_t *newAddress = (uint8_t *)tempAppData + prevAppDataSize;
489
490 // Add new app data buffer to the new location
491 MOS_SecureMemcpy(newAddress, size, (uint8_t *)ptr, size);
492
493 // Now free the previous location containing app data and overwrite with new app data buffer
494 MOS_FreeMemory(m_appData);
495 m_appData = tempAppData;
496
497 }
498
499 m_appDataTotalSize += size;
500
501 return VA_STATUS_SUCCESS;
502 }
503
EncodeInCodecHal(uint32_t numSlices)504 VAStatus DdiEncodeJpeg::EncodeInCodecHal(uint32_t numSlices)
505 {
506 DDI_CODEC_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
507 DDI_CODEC_CHK_NULL(m_encodeCtx->pCodecHal, "nullptr m_encodeCtx->pCodecHal", VA_STATUS_ERROR_INVALID_CONTEXT);
508
509 if (numSlices != 1)
510 {
511 return VA_STATUS_ERROR_INVALID_PARAMETER;
512 }
513
514 DDI_CODEC_RENDER_TARGET_TABLE *rtTbl = &(m_encodeCtx->RTtbl);
515
516 CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)(m_encodeCtx->pPicParams);
517
518 CodecEncodeJpegScanHeader *scanData = (CodecEncodeJpegScanHeader *)m_encodeCtx->pSliceParams;
519
520 EncoderParams encodeParams;
521 MOS_ZeroMemory(&encodeParams, sizeof(EncoderParams));
522 encodeParams.ExecCodecFunction = CODECHAL_FUNCTION_PAK;
523
524 // If app sends whole header - driver must extract QMatrix from it and ignore QMatrix buffer
525 // If app sends only QMatrix - driver must use it without scaling
526 // otherwise - driver must scale default QMatrix
527 DDI_CODEC_NORMALMESSAGE("Func %s: m_appDataWholeHeader: %d, m_quantSupplied: %d", __FUNCTION__, m_appDataWholeHeader, m_quantSupplied);
528 if (m_appDataWholeHeader)
529 {
530 DDI_CODEC_CHK_RET(QmatrixFromHeader(), "Failed to parse Quant Matrix from header");
531 }
532 else if (!m_quantSupplied)
533 {
534 DDI_CODEC_CHK_RET(DefaultQmatrix(), "Failed to load default Quant Matrix");
535 }
536
537 // Raw Surface
538 MOS_SURFACE rawSurface;
539 MOS_ZeroMemory(&rawSurface, sizeof(MOS_SURFACE));
540 rawSurface.Format = (MOS_FORMAT)picParams->m_inputSurfaceFormat;
541 rawSurface.dwOffset = 0;
542
543 MediaLibvaCommonNext::MediaSurfaceToMosResource(rtTbl->pCurrentRT, &(rawSurface.OsResource));
544
545 encodeParams.bJpegQuantMatrixSent = m_quantSupplied;
546
547 // Bitstream surface
548 MOS_RESOURCE bitstreamSurface;
549 MOS_ZeroMemory(&bitstreamSurface, sizeof(MOS_RESOURCE));
550 bitstreamSurface = m_encodeCtx->resBitstreamBuffer; // in render picture
551 bitstreamSurface.Format = Format_Buffer;
552
553 encodeParams.psRawSurface = &rawSurface;
554 encodeParams.psReconSurface = nullptr;
555 encodeParams.presBitstreamBuffer = &bitstreamSurface;
556
557 encodeParams.pPicParams = m_encodeCtx->pPicParams;
558 encodeParams.pSliceParams = m_encodeCtx->pSliceParams;
559 encodeParams.pApplicationData = m_appData;
560
561 // Slice level data
562 encodeParams.dwNumSlices = numSlices;
563 encodeParams.dwNumHuffBuffers = picParams->m_numCodingTable;
564 encodeParams.dwAppDataSize = m_appDataTotalSize;
565 encodeParams.fullHeaderInAppData = m_appDataWholeHeader;
566
567 encodeParams.pQuantizationTable = m_encodeCtx->pQmatrixParams;
568 encodeParams.pHuffmanTable = m_huffmanTable;
569 encodeParams.pBSBuffer = m_encodeCtx->pbsBuffer;
570 encodeParams.pSlcHeaderData = (void *)m_encodeCtx->pSliceHeaderData;
571
572 if (scanData->m_numComponent == 1) // Y8 input format
573 {
574 // Take the first table sent by the app
575 encodeParams.dwNumHuffBuffers = 2;
576 }
577
578 MOS_STATUS status = m_encodeCtx->pCodecHal->Execute(&encodeParams);
579 if (MOS_STATUS_SUCCESS != status)
580 {
581 return VA_STATUS_ERROR_ENCODING_ERROR;
582 }
583
584 return VA_STATUS_SUCCESS;
585 }
586
ConvertMediaFormatToInputSurfaceFormat(DDI_MEDIA_FORMAT format)587 uint32_t DdiEncodeJpeg::ConvertMediaFormatToInputSurfaceFormat(DDI_MEDIA_FORMAT format)
588 {
589 switch (format)
590 {
591 case Media_Format_NV12:
592 return DDI_ENCODE_JPEG_INPUTFORMAT_NV12;
593 case Media_Format_422H:
594 case Media_Format_422V:
595 case Media_Format_UYVY:
596 return DDI_ENCODE_JPEG_INPUTFORMAT_UYVY;
597 case Media_Format_YUY2:
598 return DDI_ENCODE_JPEG_INPUTFORMAT_YUY2;
599 case Media_Format_400P:
600 return DDI_ENCODE_JPEG_INPUTFORMAT_Y8;
601 case Media_Format_X8R8G8B8:
602 case Media_Format_A8R8G8B8:
603 case Media_Format_X8B8G8R8:
604 case Media_Format_R8G8B8A8:
605 case Media_Format_A8B8G8R8:
606 case Media_Format_444P:
607 return DDI_ENCODE_JPEG_INPUTFORMAT_RGB;
608 default:
609 return DDI_ENCODE_JPEG_INPUTFORMAT_RESERVED;
610 }
611 }
612
DefaultQmatrix()613 VAStatus DdiEncodeJpeg::DefaultQmatrix()
614 {
615 DDI_CODEC_FUNC_ENTER;
616 DDI_CODEC_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
617
618 CodecEncodeJpegQuantTable *quantMatrix = (CodecEncodeJpegQuantTable *)m_encodeCtx->pQmatrixParams;
619 DDI_CODEC_CHK_NULL(quantMatrix, "nullptr quantMatrix", VA_STATUS_ERROR_INVALID_PARAMETER);
620
621 // To get Quality from Pic Params
622 CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams;
623 DDI_CODEC_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
624
625 uint32_t quality = 0;
626 if (picParams->m_quality < 50)
627 {
628 if(picParams->m_quality == 0)
629 {
630 return VA_STATUS_ERROR_INVALID_PARAMETER;
631 }
632 quality = 5000 / picParams->m_quality;
633 }
634 else
635 {
636 quality = 200 - (picParams->m_quality * 2);
637 }
638
639 // 2 tables - one for luma and one for chroma
640 for (int32_t qMatrixCount = 0; qMatrixCount < MaxNumQuantTableIndex; qMatrixCount++)
641 {
642 quantMatrix->m_quantTable[qMatrixCount].m_precision = 0;
643 quantMatrix->m_quantTable[qMatrixCount].m_tableID = qMatrixCount;
644
645 for (int32_t i = 0; i < QuantMatrixSize; i++)
646 {
647 uint32_t quantValue = 0;
648 if (qMatrixCount == 0)
649 {
650 quantValue = (defaultLumaQuant[i] * quality + 50) / 100;
651 }
652 else
653 {
654 quantValue = (defaultChromaQuant[i] * quality + 50) / 100;
655 }
656
657 // Clamp the value to range between 1 and 255
658 if (quantValue < 1)
659 {
660 quantValue = 1;
661 }
662 else if (quantValue > 255)
663 {
664 quantValue = 255;
665 }
666
667 quantMatrix->m_quantTable[qMatrixCount].m_qm[i] = (uint16_t)quantValue;
668 }
669 }
670
671 return VA_STATUS_SUCCESS;
672 }
673
QmatrixFromHeader()674 VAStatus DdiEncodeJpeg::QmatrixFromHeader()
675 {
676 DDI_CODEC_FUNC_ENTER;
677 DDI_CODEC_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
678 DDI_CODEC_CHK_NULL(m_appData, "nullptr m_appData", VA_STATUS_ERROR_INVALID_PARAMETER);
679
680 CodecEncodeJpegQuantTable *quantMatrix = (CodecEncodeJpegQuantTable *)m_encodeCtx->pQmatrixParams;
681 DDI_CODEC_CHK_NULL(quantMatrix, "nullptr quantMatrix", VA_STATUS_ERROR_INVALID_PARAMETER);
682
683 // To get Quality from Pic Params
684 CodecEncodeJpegPictureParams *picParams = (CodecEncodeJpegPictureParams *)m_encodeCtx->pPicParams;
685 DDI_CODEC_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
686 picParams->m_numQuantTable = 0; // Will be extracted from header
687 m_quantSupplied = false;
688
689 const uint8_t hdrStartCode = 0xFF;
690 const int32_t startCodeBlockSize = 2;
691 const int32_t qTblLengthBlockSize = 2;
692 const int32_t qTblPrecisionTypeBlockSize = 1;
693 uint8_t *appQTblData = ((uint8_t*)m_appData);
694 uint8_t *appQTblDataEnd = ((uint8_t*)m_appData) + m_appDataTotalSize;
695 while (appQTblData = (uint8_t*)memchr(appQTblData, hdrStartCode, appQTblDataEnd - appQTblData))
696 {
697 if (appQTblDataEnd - appQTblData < startCodeBlockSize + qTblLengthBlockSize) // Don't find header start code or tbl length
698 break;
699
700 if (appQTblData[1] == 0xDA) // "Start of scan" 2nd start code
701 {
702 break;
703 }
704 else if (appQTblData[1] != 0xDB) // Not "Define Quantization Table" 2nd start code
705 {
706 appQTblData += startCodeBlockSize;
707 continue;
708 }
709
710 // Handle "Define Quantization Table"
711 // Structure: [16Bits start code][16Bits length]{ [4Bits precision][4Bits type][8 * 64Bits QTable] } * num_quant_tables
712 //
713 // Note: qTableLength include
714 // - 16Bits for length block size
715 // - { 8 bits for Precision&Type + (8 * 64Bits) for QTable } * num_quant_tables
716 int32_t qTableLength = (appQTblData[2] << 8) + appQTblData[3];
717 appQTblData += startCodeBlockSize;
718
719 int32_t numQMatrix = (qTableLength - qTblLengthBlockSize) / (qTblPrecisionTypeBlockSize + QuantMatrixSize);
720 DDI_CODEC_CHK_CONDITION(appQTblData + qTableLength > appQTblDataEnd, "Table length is greater than jpeg header", VA_STATUS_ERROR_INVALID_PARAMETER);
721 DDI_CODEC_CHK_CONDITION((qTableLength - qTblLengthBlockSize) % (qTblPrecisionTypeBlockSize + QuantMatrixSize),
722 "Invalid qtable length. It must contain 2Bytes for qtable length and (1Byte for Precision&Type + 64Bytes for QTable) * num_qtables", VA_STATUS_ERROR_INVALID_PARAMETER);
723
724 appQTblData += qTblLengthBlockSize;
725 for (int qMatrixIdx = 0; qMatrixIdx < numQMatrix; ++qMatrixIdx)
726 {
727 uint8_t tablePrecision = appQTblData[0] >> 4;
728 uint8_t tableType = appQTblData[0] & 0xF;
729 appQTblData++;
730 DDI_CODEC_CHK_CONDITION(tableType >= JPEG_MAX_NUM_QUANT_TABLE_INDEX, "QTable type is equal or greater than JPEG_MAX_NUM_QUANT_TABLE (3)", VA_STATUS_ERROR_INVALID_PARAMETER);
731
732 picParams->m_numQuantTable++;
733 quantMatrix->m_quantTable[tableType].m_precision = tablePrecision;
734 quantMatrix->m_quantTable[tableType].m_tableID = tableType;
735 for (int32_t j = 0; j < QuantMatrixSize; ++appQTblData, ++j)
736 quantMatrix->m_quantTable[tableType].m_qm[j] = *appQTblData;
737
738 if (picParams->m_numQuantTable == JPEG_MAX_NUM_QUANT_TABLE_INDEX) // Max 3 QTables for encode
739 break;
740 }
741 }
742 DDI_CODEC_CHK_CONDITION(picParams->m_numQuantTable == 0, "No quant tables were found in header", VA_STATUS_ERROR_INVALID_PARAMETER);
743
744 m_quantSupplied = true;
745 return VA_STATUS_SUCCESS;
746 }
747
getSliceParameterBufferSize()748 uint32_t DdiEncodeJpeg::getSliceParameterBufferSize()
749 {
750 return sizeof(VAEncSliceParameterBufferJPEG);
751 }
752
getPictureParameterBufferSize()753 uint32_t DdiEncodeJpeg::getPictureParameterBufferSize()
754 {
755 return sizeof(VAEncPictureParameterBufferJPEG);
756 }
757
getQMatrixBufferSize()758 uint32_t DdiEncodeJpeg::getQMatrixBufferSize()
759 {
760 return sizeof(VAQMatrixBufferJPEG);
761 }
762
GetEncodeCodecFunction(VAProfile profile,VAEntrypoint entrypoint,bool bVDEnc)763 CODECHAL_FUNCTION DdiEncodeJpeg::GetEncodeCodecFunction(VAProfile profile, VAEntrypoint entrypoint, bool bVDEnc)
764 {
765 CODECHAL_FUNCTION codecFunction = CODECHAL_FUNCTION_INVALID;
766 if (profile == VAProfileJPEGBaseline)
767 {
768 codecFunction = CODECHAL_FUNCTION_PAK;
769 }
770 else
771 {
772 DDI_CODEC_ASSERTMESSAGE("Unsuported CODECHAL_FUNCTION");
773 }
774 return codecFunction;
775 }
776
GetEncodeCodecMode(VAProfile profile,VAEntrypoint entrypoint)777 CODECHAL_MODE DdiEncodeJpeg::GetEncodeCodecMode(
778 VAProfile profile,
779 VAEntrypoint entrypoint)
780 {
781 switch (profile)
782 {
783 case VAProfileJPEGBaseline:
784 return CODECHAL_ENCODE_MODE_JPEG;
785 default:
786 DDI_CODEC_ASSERTMESSAGE("Unsuported CODECHAL_MODE");
787 return CODECHAL_UNSUPPORTED_MODE;
788 }
789 }
790
791 }
792