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