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