xref: /aosp_15_r20/external/intel-media-driver/media_driver/linux/common/codec/ddi/media_ddi_encode_jpeg.cpp (revision ba62d9d3abf0e404f2022b4cd7a85e107f48596f)
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