1 /*
2 * Copyright (c) 2009-2017, 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_decode_jpeg.cpp
24 //! \brief The class implementation of DdiDecodeJPEG for JPEG decode
25 //!
26 //!
27
28 #include <va/va_dec_jpeg.h>
29 #include "media_libva_decoder.h"
30 #include "media_libva_util.h"
31 #include "media_ddi_decode_jpeg.h"
32 #include "mos_solo_generic.h"
33 #include "codechal_decode_jpeg.h"
34 #include "media_ddi_decode_const.h"
35 #include "media_ddi_factory.h"
36
37 typedef enum _DDI_DECODE_JPEG_BUFFER_STATE
38 {
39 BUFFER_UNLOADED = 0,
40 BUFFER_LOADED = 1,
41 } DDI_DECODE_JPEG_BUFFER_STATE;
42
43 #define DDI_DECODE_JPEG_MAXIMUM_HUFFMAN_TABLE 2
44 #define DDI_DECODE_JPEG_MAXIMUM_QMATRIX_NUM 4
45 #define DDI_DECODE_JPEG_MAXIMUM_QMATRIX_ENTRIES 64
46
47 #define DDI_DECODE_JPEG_SLICE_PARAM_BUF_NUM 0x4 //According to JPEG SPEC, max slice per frame is 4
48
49 static const uint32_t zigzag_order[64] =
50 {
51 0, 1, 8, 16, 9, 2, 3, 10,
52 17, 24, 32, 25, 18, 11, 4, 5,
53 12, 19, 26, 33, 40, 48, 41, 34,
54 27, 20, 13, 6, 7, 14, 21, 28,
55 35, 42, 49, 56, 57, 50, 43, 36,
56 29, 22, 15, 23, 30, 37, 44, 51,
57 58, 59, 52, 45, 38, 31, 39, 46,
58 53, 60, 61, 54, 47, 55, 62, 63
59 };
60
ParseSliceParams(DDI_MEDIA_CONTEXT * mediaCtx,VASliceParameterBufferJPEGBaseline * slcParam,uint32_t numSlices)61 VAStatus DdiDecodeJPEG::ParseSliceParams(
62 DDI_MEDIA_CONTEXT *mediaCtx,
63 VASliceParameterBufferJPEGBaseline *slcParam,
64 uint32_t numSlices)
65 {
66 CodecDecodeJpegScanParameter *jpegSliceParam =
67 (CodecDecodeJpegScanParameter *)(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
68
69 CodecDecodeJpegPicParams *picParam = (CodecDecodeJpegPicParams *)(m_ddiDecodeCtx->DecodeParams.m_picParams);
70
71 if ((jpegSliceParam == nullptr) ||
72 (picParam == nullptr) ||
73 (slcParam == nullptr))
74 {
75 DDI_ASSERTMESSAGE("Invalid Parameter for Parsing JPEG Slice parameter\n");
76 return VA_STATUS_ERROR_INVALID_PARAMETER;
77 }
78
79 jpegSliceParam->NumScans += numSlices;
80 picParam->m_totalScans += numSlices;
81 if (picParam->m_totalScans == 1 && slcParam[0].num_components > 1)
82 {
83 picParam->m_interleavedData = 1;
84 }
85
86 uint32_t j, i;
87 int32_t startIdx = m_numScans;
88 for (j = 0; j < numSlices; j++)
89 {
90 for (i = 0; i < slcParam[j].num_components; i++)
91 {
92 jpegSliceParam->ScanHeader[j + startIdx].ComponentSelector[i] = slcParam[j].components[i].component_selector;
93 jpegSliceParam->ScanHeader[j + startIdx].DcHuffTblSelector[i] = slcParam[j].components[i].dc_table_selector;
94 jpegSliceParam->ScanHeader[j + startIdx].AcHuffTblSelector[i] = slcParam[j].components[i].ac_table_selector;
95 }
96 jpegSliceParam->ScanHeader[j + startIdx].NumComponents = slcParam[j].num_components;
97 jpegSliceParam->ScanHeader[j + startIdx].RestartInterval = slcParam[j].restart_interval;
98 jpegSliceParam->ScanHeader[j + startIdx].MCUCount = slcParam[j].num_mcus;
99 jpegSliceParam->ScanHeader[j + startIdx].ScanHoriPosition = slcParam[j].slice_horizontal_position;
100 jpegSliceParam->ScanHeader[j + startIdx].ScanVertPosition = slcParam[j].slice_vertical_position;
101 jpegSliceParam->ScanHeader[j + startIdx].DataOffset = slcParam[j].slice_data_offset;
102 jpegSliceParam->ScanHeader[j + startIdx].DataLength = slcParam[j].slice_data_size;
103 }
104
105 return VA_STATUS_SUCCESS;
106 }
107
ParsePicParams(DDI_MEDIA_CONTEXT * mediaCtx,VAPictureParameterBufferJPEGBaseline * picParam)108 VAStatus DdiDecodeJPEG::ParsePicParams(
109 DDI_MEDIA_CONTEXT *mediaCtx,
110 VAPictureParameterBufferJPEGBaseline *picParam)
111 {
112 CodecDecodeJpegPicParams *jpegPicParam = (CodecDecodeJpegPicParams *)(m_ddiDecodeCtx->DecodeParams.m_picParams);
113
114 if ((jpegPicParam == nullptr) ||
115 (picParam == nullptr))
116 {
117 DDI_ASSERTMESSAGE("Null Parameter for Parsing JPEG Picture parameter\n");
118 return VA_STATUS_ERROR_INVALID_PARAMETER;
119 }
120
121 jpegPicParam->m_frameWidth = picParam->picture_width;
122 jpegPicParam->m_frameHeight = picParam->picture_height;
123 jpegPicParam->m_numCompInFrame = picParam->num_components;
124
125 switch (picParam->rotation)
126 {
127 case VA_ROTATION_NONE:
128 jpegPicParam->m_rotation = jpegRotation0;
129 break;
130 case VA_ROTATION_90:
131 jpegPicParam->m_rotation = jpegRotation90;
132 break;
133 case VA_ROTATION_180:
134 jpegPicParam->m_rotation = jpegRotation180;
135 break;
136 case VA_ROTATION_270:
137 jpegPicParam->m_rotation = jpegRotation270;
138 break;
139 default:
140 /* For the other rotation type, the rotation is disabled. */
141 jpegPicParam->m_rotation = jpegRotation0;
142 break;
143 ;
144 }
145
146 if (jpegPicParam->m_numCompInFrame == 1)
147 {
148 jpegPicParam->m_chromaType = jpegYUV400;
149 }
150 else if (jpegPicParam->m_numCompInFrame == 3)
151 {
152 int32_t h1 = picParam->components[0].h_sampling_factor;
153 int32_t h2 = picParam->components[1].h_sampling_factor;
154 int32_t h3 = picParam->components[2].h_sampling_factor;
155 int32_t v1 = picParam->components[0].v_sampling_factor;
156 int32_t v2 = picParam->components[1].v_sampling_factor;
157 int32_t v3 = picParam->components[2].v_sampling_factor;
158
159 if (h1 == 2 && h2 == 1 && h3 == 1 &&
160 v1 == 2 && v2 == 1 && v3 == 1)
161 {
162 jpegPicParam->m_chromaType = jpegYUV420;
163 }
164 else if (h1 == 2 && h2 == 1 && h3 == 1 &&
165 v1 == 1 && v2 == 1 && v3 == 1)
166 {
167 jpegPicParam->m_chromaType = jpegYUV422H2Y;
168 }
169 else if (h1 == 1 && h2 == 1 && h3 == 1 &&
170 v1 == 1 && v2 == 1 && v3 == 1)
171 {
172 switch (picParam->color_space)
173 {
174 case 0: //YUV
175 jpegPicParam->m_chromaType = jpegYUV444;
176 break;
177 case 1: //RGB
178 jpegPicParam->m_chromaType = jpegRGB;
179 break;
180 case 2: //BGR
181 jpegPicParam->m_chromaType = jpegBGR;
182 break;
183 default:
184 /* For the other type, the default YUV444 is used */
185 jpegPicParam->m_chromaType = jpegYUV444;
186 break;
187 ;
188 }
189 }
190 else if (h1 == 4 && h2 == 1 && h3 == 1 &&
191 v1 == 1 && v2 == 1 && v3 == 1)
192 {
193 jpegPicParam->m_chromaType = jpegYUV411;
194 }
195 else if (h1 == 1 && h2 == 1 && h3 == 1 &&
196 v1 == 2 && v2 == 1 && v3 == 1)
197 {
198 jpegPicParam->m_chromaType = jpegYUV422V2Y;
199 }
200 else if (h1 == 2 && h2 == 1 && h3 == 1 &&
201 v1 == 2 && v2 == 2 && v3 == 2)
202 {
203 jpegPicParam->m_chromaType = jpegYUV422H4Y;
204 }
205 else if (h1 == 2 && h2 == 2 && h3 == 2 &&
206 v1 == 2 && v2 == 1 && v3 == 1)
207 {
208 jpegPicParam->m_chromaType = jpegYUV422V4Y;
209 }
210 else
211 {
212 DDI_NORMALMESSAGE("Unsupported sampling factor in JPEG Picture parameter\n");
213 return VA_STATUS_ERROR_INVALID_PARAMETER;
214 }
215 }
216
217 memset(jpegPicParam->m_componentIdentifier, 0, jpegNumComponent);
218 memset(jpegPicParam->m_quantTableSelector, 0, jpegNumComponent);
219
220 if (picParam->num_components > jpegNumComponent)
221 {
222 DDI_NORMALMESSAGE("Unsupported component num in JPEG Picture parameter\n");
223 return VA_STATUS_ERROR_INVALID_PARAMETER;
224 }
225 for (int32_t i = 0; i < picParam->num_components; i++)
226 {
227 jpegPicParam->m_componentIdentifier[i] = picParam->components[i].component_id;
228 jpegPicParam->m_quantTableSelector[i] = picParam->components[i].quantiser_table_selector;
229 }
230
231 return VA_STATUS_SUCCESS;
232 }
233
ParseHuffmanTbl(DDI_MEDIA_CONTEXT * mediaCtx,VAHuffmanTableBufferJPEGBaseline * huffmanTbl)234 VAStatus DdiDecodeJPEG::ParseHuffmanTbl(
235 DDI_MEDIA_CONTEXT * mediaCtx,
236 VAHuffmanTableBufferJPEGBaseline *huffmanTbl)
237 {
238 PCODECHAL_DECODE_JPEG_HUFFMAN_TABLE jpegHuffTbl = (PCODECHAL_DECODE_JPEG_HUFFMAN_TABLE)(m_ddiDecodeCtx->DecodeParams.m_huffmanTable);
239 int32_t sumBITS = 0;
240
241 if ((jpegHuffTbl == nullptr) ||
242 (huffmanTbl == nullptr))
243 {
244 DDI_ASSERTMESSAGE("Null Parameter for Parsing JPEG Huffman Tableparameter\n");
245 return VA_STATUS_ERROR_INVALID_PARAMETER;
246 }
247
248 memset(jpegHuffTbl, 0, sizeof(CODECHAL_DECODE_JPEG_HUFFMAN_TABLE));
249
250 for (int32_t i = 0; i < DDI_DECODE_JPEG_MAXIMUM_HUFFMAN_TABLE; i++)
251 {
252 if (huffmanTbl->load_huffman_table[i] == BUFFER_LOADED)
253 {
254 sumBITS = 0;
255 for (int32_t j = 0; j < JPEG_NUM_HUFF_TABLE_DC_BITS; j++)
256 {
257 sumBITS += huffmanTbl->huffman_table[i].num_dc_codes[j];
258 }
259
260 if (sumBITS > JPEG_NUM_HUFF_TABLE_DC_HUFFVAL)
261 {
262 DDI_ASSERTMESSAGE("Huffman table DC entries number is out of HW limitation.");
263 return VA_STATUS_ERROR_INVALID_PARAMETER;
264 }
265
266 //the size of jpegHuffTbl->HuffTable[i].DC_BITS is 12 (defined in driver)
267 //the size of huffmanTbl->huffman_table[i].num_dc_codes is 16 (defined in libva)
268 //it is using the size of "DC_BITS" for solve the overflow
269 MOS_SecureMemcpy(jpegHuffTbl->HuffTable[i].DC_BITS,
270 sizeof(jpegHuffTbl->HuffTable[i].DC_BITS),
271 huffmanTbl->huffman_table[i].num_dc_codes,
272 sizeof(jpegHuffTbl->HuffTable[i].DC_BITS));
273 MOS_SecureMemcpy(jpegHuffTbl->HuffTable[i].DC_HUFFVAL,
274 sizeof(jpegHuffTbl->HuffTable[i].DC_HUFFVAL),
275 huffmanTbl->huffman_table[i].dc_values,
276 sizeof(huffmanTbl->huffman_table[i].dc_values));
277 MOS_SecureMemcpy(jpegHuffTbl->HuffTable[i].AC_BITS,
278 sizeof(jpegHuffTbl->HuffTable[i].AC_BITS),
279 huffmanTbl->huffman_table[i].num_ac_codes,
280 sizeof(huffmanTbl->huffman_table[i].num_ac_codes));
281 MOS_SecureMemcpy(jpegHuffTbl->HuffTable[i].AC_HUFFVAL,
282 sizeof(jpegHuffTbl->HuffTable[i].AC_HUFFVAL),
283 huffmanTbl->huffman_table[i].ac_values,
284 sizeof(huffmanTbl->huffman_table[i].ac_values));
285 }
286 }
287
288 return VA_STATUS_SUCCESS;
289 }
290
291 /////////////////////////////////////////////////////////////////////////////////////////
292 //
293 // Function: JpegQMatrixDecode
294 // Description: Parse the QMatrix table from VAAPI, and load the valid Qmatrix to the Buffer used by
295 // CodecHal
296 //
297 /////////////////////////////////////////////////////////////////////////////////////////
ParseIQMatrix(DDI_MEDIA_CONTEXT * mediaCtx,VAIQMatrixBufferJPEGBaseline * matrix)298 VAStatus DdiDecodeJPEG::ParseIQMatrix(
299 DDI_MEDIA_CONTEXT *mediaCtx,
300 VAIQMatrixBufferJPEGBaseline *matrix)
301 {
302 CodecJpegQuantMatrix *jpegQMatrix = (CodecJpegQuantMatrix *)(m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer);
303
304 if ((matrix == nullptr) || (jpegQMatrix == nullptr))
305 {
306 DDI_ASSERTMESSAGE("Null Parameter for Parsing JPEG IQMatrix \n");
307 return VA_STATUS_ERROR_INVALID_PARAMETER;
308 }
309
310 memset(jpegQMatrix, 0, sizeof(CodecJpegQuantMatrix));
311
312 int32_t idx, idx2;
313 for (idx = 0; idx < DDI_DECODE_JPEG_MAXIMUM_QMATRIX_NUM; idx++)
314 {
315 if (matrix->load_quantiser_table[idx] == BUFFER_LOADED)
316 {
317 for (idx2 = 0; idx2 < DDI_DECODE_JPEG_MAXIMUM_QMATRIX_ENTRIES; idx2++)
318 {
319 jpegQMatrix->m_quantMatrix[idx][zigzag_order[idx2]] = matrix->quantiser_table[idx][idx2];
320 }
321 }
322 }
323
324 return VA_STATUS_SUCCESS;
325 }
326
SetBufferRendered(VABufferID bufferID)327 VAStatus DdiDecodeJPEG::SetBufferRendered(VABufferID bufferID)
328 {
329 DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
330
331 if (bufMgr == nullptr)
332 {
333 DDI_ASSERTMESSAGE("Null Parameter for Parsing Data buffer for JPEG\n");
334 return VA_STATUS_ERROR_INVALID_PARAMETER;
335 }
336
337 bool renderFlag = false;
338 for (uint32_t i = 0; i < bufMgr->dwNumSliceData; i++)
339 {
340 // Depend on the ID we tracked, if application want to rendered one of them
341 // we set some flags
342 if (bufMgr->pSliceData[i].vaBufferId == bufferID)
343 {
344 if (bufMgr->pSliceData[i].bRendered == false)
345 {
346 // set the rendered flags. which will be used when EndPicture.
347 bufMgr->pSliceData[i].bRendered = true;
348 // calculate the size of a bunch of rendered buffers. for endpicture to allocate appropriate memory size of GPU.
349 bufMgr->dwSizeOfRenderedSliceData += bufMgr->pSliceData[i].uiLength;
350 // keep record the render order, so that we can calculate the offset correctly when endpicture.
351 // in this array we save the buffer index in pSliceData which render in sequence. if application create buffers like: 4,3,5,1,2.
352 // but only render 2,3,5. the content in this array is: [4,1,2], which is the index of created buffer.
353 bufMgr->pRenderedOrder[bufMgr->dwNumOfRenderedSliceData] = i;
354 bufMgr->dwNumOfRenderedSliceData++;
355 }
356 renderFlag = true;
357 break;
358 }
359 }
360
361 if (renderFlag)
362 {
363 return VA_STATUS_SUCCESS;
364 }
365 else
366 {
367 return VA_STATUS_ERROR_INVALID_BUFFER;
368 }
369 }
370
RenderPicture(VADriverContextP ctx,VAContextID context,VABufferID * buffers,int32_t numBuffers)371 VAStatus DdiDecodeJPEG::RenderPicture(
372 VADriverContextP ctx,
373 VAContextID context,
374 VABufferID *buffers,
375 int32_t numBuffers)
376 {
377 DDI_FUNCTION_ENTER();
378
379 VAStatus va = VA_STATUS_SUCCESS;
380 PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
381
382 void *data = nullptr;
383 for (int32_t i = 0; i < numBuffers; i++)
384 {
385 if (!buffers || (buffers[i] == VA_INVALID_ID))
386 {
387 return VA_STATUS_ERROR_INVALID_BUFFER;
388 }
389
390 DDI_MEDIA_BUFFER *buf = DdiMedia_GetBufferFromVABufferID(mediaCtx, buffers[i]);
391 if (nullptr == buf)
392 {
393 return VA_STATUS_ERROR_INVALID_BUFFER;
394 }
395
396 uint32_t dataSize = buf->iSize;
397 DdiMedia_MapBuffer(ctx, buffers[i], &data);
398
399 if (data == nullptr)
400 {
401 return VA_STATUS_ERROR_INVALID_BUFFER;
402 }
403
404 switch ((int32_t)buf->uiType)
405 {
406 case VASliceDataBufferType:
407 {
408 DDI_CHK_RET(SetBufferRendered(buffers[i]),"SetBufferRendered failed!");
409 m_ddiDecodeCtx->DecodeParams.m_dataSize += dataSize;
410 break;
411 }
412 case VASliceParameterBufferType:
413 {
414 if (buf->uiNumElements == 0)
415 {
416 return VA_STATUS_ERROR_INVALID_BUFFER;
417 }
418
419 uint32_t numSlices = buf->uiNumElements;
420
421 if ((m_numScans + numSlices) > jpegNumComponent)
422 {
423 DDI_NORMALMESSAGE("the total number of JPEG scans are beyond the supported num(4)\n");
424 return VA_STATUS_ERROR_INVALID_PARAMETER;
425 }
426 DDI_CHK_RET(AllocSliceParamContext(numSlices),"AllocSliceParamContext failed!");
427 VASliceParameterBufferJPEGBaseline *slcInfo = (VASliceParameterBufferJPEGBaseline *)data;
428 DDI_CHK_RET(ParseSliceParams(mediaCtx, slcInfo, numSlices),"ParseSliceParams failed!");
429 m_ddiDecodeCtx->BufMgr.pNumOfRenderedSliceParaForOneBuffer[m_ddiDecodeCtx->BufMgr.dwNumOfRenderedSlicePara] = numSlices;
430 m_ddiDecodeCtx->BufMgr.dwNumOfRenderedSlicePara ++;
431
432 m_ddiDecodeCtx->DecodeParams.m_numSlices += numSlices;
433 m_numScans += numSlices;
434 m_groupIndex++;
435 break;
436 }
437 case VAIQMatrixBufferType:
438 {
439 VAIQMatrixBufferJPEGBaseline *imxBuf = (VAIQMatrixBufferJPEGBaseline *)data;
440 DDI_CHK_RET(ParseIQMatrix(mediaCtx, imxBuf),"ParseIQMatrix failed!");
441 break;
442 }
443 case VAPictureParameterBufferType:
444 {
445 VAPictureParameterBufferJPEGBaseline *picParam = (VAPictureParameterBufferJPEGBaseline *)data;
446 DDI_CHK_RET(ParsePicParams(mediaCtx, picParam),"ParsePicParams failed!");
447 break;
448 }
449 case VAHuffmanTableBufferType:
450 {
451 VAHuffmanTableBufferJPEGBaseline *huffTbl = (VAHuffmanTableBufferJPEGBaseline *)data;
452 DDI_CHK_RET(ParseHuffmanTbl(mediaCtx, huffTbl),"ParseHuffmanTbl failed!");
453 break;
454 }
455 case VAProcPipelineParameterBufferType:
456 {
457 DDI_NORMALMESSAGE("ProcPipeline is not supported for JPEGBaseline decoding\n");
458 break;
459 }
460 case VADecodeStreamoutBufferType:
461 {
462 DdiMedia_MediaBufferToMosResource(buf, &m_ddiDecodeCtx->BufMgr.resExternalStreamOutBuffer);
463 m_streamOutEnabled = true;
464 break;
465 }
466 default:
467 va = VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
468 break;
469 }
470 DdiMedia_UnmapBuffer(ctx, buffers[i]);
471 }
472
473 DDI_FUNCTION_EXIT(va);
474 return va;
475 }
476
BeginPicture(VADriverContextP ctx,VAContextID context,VASurfaceID renderTarget)477 VAStatus DdiDecodeJPEG::BeginPicture(
478 VADriverContextP ctx,
479 VAContextID context,
480 VASurfaceID renderTarget)
481 {
482 VAStatus vaStatus = DdiMediaDecode::BeginPicture(ctx, context, renderTarget);
483
484 if (vaStatus != VA_STATUS_SUCCESS)
485 {
486 return vaStatus;
487 }
488
489 if (m_jpegBitstreamBuf)
490 {
491 DdiMediaUtil_FreeBuffer(m_jpegBitstreamBuf);
492 MOS_FreeMemory(m_jpegBitstreamBuf);
493 m_jpegBitstreamBuf = nullptr;
494 }
495
496 CodecDecodeJpegScanParameter *jpegSliceParam =
497 (CodecDecodeJpegScanParameter *)(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
498 jpegSliceParam->NumScans = 0;
499
500 CodecDecodeJpegPicParams *picParam = (CodecDecodeJpegPicParams *)(m_ddiDecodeCtx->DecodeParams.m_picParams);
501 picParam->m_totalScans = 0;
502
503 m_numScans = 0;
504 return vaStatus;
505 }
506
InitDecodeParams(VADriverContextP ctx,VAContextID context)507 VAStatus DdiDecodeJPEG::InitDecodeParams(
508 VADriverContextP ctx,
509 VAContextID context)
510 {
511 /* skip the mediaCtx check as it is checked in caller */
512 PDDI_MEDIA_CONTEXT mediaCtx;
513 mediaCtx = DdiMedia_GetMediaContext(ctx);
514 DDI_CHK_RET(DecodeCombineBitstream(mediaCtx),"DecodeCombineBitstream failed!");
515 DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
516 bufMgr->dwNumSliceControl = 0;
517 memset(&m_destSurface, 0, sizeof(MOS_SURFACE));
518 m_destSurface.dwOffset = 0;
519 DDI_CODEC_RENDER_TARGET_TABLE *rtTbl = &(m_ddiDecodeCtx->RTtbl);
520
521 if ((rtTbl == nullptr) || (rtTbl->pCurrentRT == nullptr))
522 {
523 return VA_STATUS_ERROR_INVALID_PARAMETER;
524 }
525 return VA_STATUS_SUCCESS;
526 }
527
SetDecodeParams()528 VAStatus DdiDecodeJPEG::SetDecodeParams()
529 {
530 DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
531
532 // we do not support mismatched usecase.
533 if ((bufMgr->dwNumOfRenderedSlicePara != bufMgr->dwNumOfRenderedSliceData) ||
534 (bufMgr->dwNumOfRenderedSlicePara == 0))
535 {
536 DDI_NORMALMESSAGE("DDI: Unsupported buffer mismatch usage!\n");
537 return VA_STATUS_ERROR_INVALID_PARAMETER;
538 }
539
540 // Allocate GPU Buffer description keeper.
541 m_jpegBitstreamBuf = (DDI_MEDIA_BUFFER *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_BUFFER));
542 if (m_jpegBitstreamBuf == nullptr)
543 {
544 DDI_ASSERTMESSAGE("DDI: Allocate Jpeg Media Buffer Failed!\n");
545 return VA_STATUS_ERROR_UNKNOWN;
546 }
547
548 m_jpegBitstreamBuf->iSize = bufMgr->dwSizeOfRenderedSliceData;
549 m_jpegBitstreamBuf->uiNumElements = bufMgr->dwNumOfRenderedSliceData;
550 m_jpegBitstreamBuf->uiType = VASliceDataBufferType;
551 m_jpegBitstreamBuf->format = Media_Format_Buffer;
552 m_jpegBitstreamBuf->uiOffset = 0;
553 m_jpegBitstreamBuf->bCFlushReq = false;
554 m_jpegBitstreamBuf->pMediaCtx = m_ddiDecodeCtx->pMediaCtx;
555
556 // Create GPU buffer
557 VAStatus va = DdiMediaUtil_CreateBuffer(m_jpegBitstreamBuf, m_ddiDecodeCtx->pMediaCtx->pDrmBufMgr);
558 if (va != VA_STATUS_SUCCESS)
559 {
560 DdiMediaUtil_FreeBuffer(m_jpegBitstreamBuf);
561 MOS_FreeMemory(m_jpegBitstreamBuf);
562 m_jpegBitstreamBuf = nullptr;
563 return va;
564 }
565
566 // For the first time you call DdiMediaUtil_LockBuffer for a fresh GPU memory, it will map GPU address to a virtual address.
567 // and then, DdiMediaUtil_LockBuffer is acutally to increase the reference count. so we used here for 2 resaons:
568 //
569 // 1. Map GPU address to virtual at the beginning when we combine the CPU -> GPU.
570 uint8_t *mappedBuf = (uint8_t *)DdiMediaUtil_LockBuffer(m_jpegBitstreamBuf, MOS_LOCKFLAG_WRITEONLY);
571
572 if (mappedBuf == nullptr)
573 {
574 DdiMediaUtil_FreeBuffer(m_jpegBitstreamBuf);
575 MOS_FreeMemory(m_jpegBitstreamBuf);
576 m_jpegBitstreamBuf = nullptr;
577 return VA_STATUS_ERROR_ALLOCATION_FAILED;
578 }
579
580 // get the JPEG Slice Header Params for offset recaculated.
581 CodecDecodeJpegScanParameter *sliceParam =
582 (CodecDecodeJpegScanParameter *)(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
583
584 uint32_t bufOffset = 0;
585 int32_t orderSlicePara = 0;
586 int32_t orderSliceData = 0;
587 for (uint32_t i = 0; i < bufMgr->dwNumOfRenderedSliceData; i++)
588 {
589 // get the rendered slice data index in rendered order.
590 int32_t renderedBufIdx = bufMgr->pRenderedOrder[i];
591 if (bufMgr->pSliceData[renderedBufIdx].bRendered)
592 {
593 MOS_SecureMemcpy((void *)(mappedBuf + bufOffset),
594 bufMgr->pSliceData[renderedBufIdx].uiLength,
595 bufMgr->pSliceData[renderedBufIdx].pBaseAddress,
596 bufMgr->pSliceData[renderedBufIdx].uiLength);
597
598 // since we assume application must make sure ONE slice parameter buffer ONE slice data buffer, so we recaculate header offset here.
599 for (int32_t j = 0; j < bufMgr->pNumOfRenderedSliceParaForOneBuffer[orderSliceData]; j++)
600 {
601 sliceParam->ScanHeader[orderSlicePara].DataOffset += bufOffset;
602 orderSlicePara++;
603 }
604 bufOffset += bufMgr->pSliceData[renderedBufIdx].uiLength;
605 bufMgr->pNumOfRenderedSliceParaForOneBuffer[orderSliceData] = 0;
606 orderSliceData++;
607 bufMgr->pSliceData[renderedBufIdx].bRendered = false;
608 }
609 }
610 DdiMediaUtil_UnlockBuffer(m_jpegBitstreamBuf);
611 DdiMedia_MediaBufferToMosResource(m_jpegBitstreamBuf, &(bufMgr->resBitstreamBuffer));
612 bufMgr->dwNumOfRenderedSliceData = 0;
613 bufMgr->dwNumOfRenderedSlicePara = 0;
614 bufMgr->dwSizeOfRenderedSliceData = 0;
615
616 m_destSurface.dwOffset = 0;
617 m_destSurface.Format = Format_NV12;
618
619 CodecDecodeJpegPicParams *jpegPicParam = (CodecDecodeJpegPicParams *)(m_ddiDecodeCtx->DecodeParams.m_picParams);
620 if((m_ddiDecodeCtx->RTtbl.pCurrentRT->format == Media_Format_NV12)
621 &&(jpegPicParam->m_chromaType == jpegYUV444))
622 {
623 m_ddiDecodeCtx->RTtbl.pCurrentRT = DdiMedia_ReplaceSurfaceWithNewFormat(m_ddiDecodeCtx->RTtbl.pCurrentRT, Media_Format_444P);
624 }
625 if(m_ddiDecodeCtx->RTtbl.pCurrentRT != nullptr)
626 {
627 DdiMedia_MediaSurfaceToMosResource((&(m_ddiDecodeCtx->RTtbl))->pCurrentRT, &(m_destSurface.OsResource));
628 }
629
630 (&m_ddiDecodeCtx->DecodeParams)->m_destSurface = &m_destSurface;
631
632 (&m_ddiDecodeCtx->DecodeParams)->m_deblockSurface = nullptr;
633
634 (&m_ddiDecodeCtx->DecodeParams)->m_dataBuffer = &bufMgr->resBitstreamBuffer;
635 (&m_ddiDecodeCtx->DecodeParams)->m_bitStreamBufData = bufMgr->pBitstreamBuffer;
636 Mos_Solo_OverrideBufferSize((&m_ddiDecodeCtx->DecodeParams)->m_dataSize, (&m_ddiDecodeCtx->DecodeParams)->m_dataBuffer);
637
638 (&m_ddiDecodeCtx->DecodeParams)->m_bitplaneBuffer = nullptr;
639
640 if (m_streamOutEnabled)
641 {
642 (&m_ddiDecodeCtx->DecodeParams)->m_streamOutEnabled = true;
643 (&m_ddiDecodeCtx->DecodeParams)->m_externalStreamOutBuffer = &bufMgr->resExternalStreamOutBuffer;
644 }
645 else
646 {
647 (&m_ddiDecodeCtx->DecodeParams)->m_streamOutEnabled = false;
648 (&m_ddiDecodeCtx->DecodeParams)->m_externalStreamOutBuffer = nullptr;
649 }
650 return VA_STATUS_SUCCESS;
651 }
652
AllocSliceParamContext(uint32_t numSlices)653 VAStatus DdiDecodeJPEG::AllocSliceParamContext(
654 uint32_t numSlices)
655 {
656 uint32_t baseSize = sizeof(CodecDecodeJpegScanParameter);
657
658 if (m_sliceParamBufNum < (m_ddiDecodeCtx->DecodeParams.m_numSlices + numSlices))
659 {
660 // in order to avoid that the buffer is reallocated multi-times,
661 // extra 10 slices are added.
662 uint32_t extraSlices = numSlices + 10;
663
664 m_ddiDecodeCtx->DecodeParams.m_sliceParams = realloc(m_ddiDecodeCtx->DecodeParams.m_sliceParams,
665 baseSize * (m_sliceParamBufNum + extraSlices));
666
667 if (m_ddiDecodeCtx->DecodeParams.m_sliceParams == nullptr)
668 {
669 return VA_STATUS_ERROR_ALLOCATION_FAILED;
670 }
671
672 memset((void *)((uint8_t *)m_ddiDecodeCtx->DecodeParams.m_sliceParams + baseSize * m_sliceParamBufNum), 0, baseSize * extraSlices);
673 m_sliceParamBufNum += extraSlices;
674 }
675
676 return VA_STATUS_SUCCESS;
677 }
678
DestroyContext(VADriverContextP ctx)679 void DdiDecodeJPEG::DestroyContext(
680 VADriverContextP ctx)
681 {
682 FreeResourceBuffer();
683 // explicitly call the base function to do the further clean-up
684 DdiMediaDecode::DestroyContext(ctx);
685 }
686
GetPicParamBuf(DDI_CODEC_COM_BUFFER_MGR * bufMgr)687 uint8_t* DdiDecodeJPEG::GetPicParamBuf(
688 DDI_CODEC_COM_BUFFER_MGR *bufMgr)
689 {
690 return (uint8_t*)(&(bufMgr->Codec_Param.Codec_Param_JPEG.PicParamJPEG));
691 }
692
AllocBsBuffer(DDI_CODEC_COM_BUFFER_MGR * bufMgr,DDI_MEDIA_BUFFER * buf)693 VAStatus DdiDecodeJPEG::AllocBsBuffer(
694 DDI_CODEC_COM_BUFFER_MGR *bufMgr,
695 DDI_MEDIA_BUFFER *buf)
696 {
697 // Allocate JPEG slice data memory from CPU.
698 uint8_t *bsAddr;
699 uint32_t index;
700
701 index = bufMgr->dwNumSliceData;
702
703 /* the pSliceData needs to be reallocated in order to contain more SliceDataBuf */
704 if (index >= bufMgr->m_maxNumSliceData)
705 {
706 /* In theroy it can resize the m_maxNumSliceData one by one. But in order to
707 * avoid calling realloc frequently, it will try to allocate 10 to hold more
708 * SliceDataBuf. This is only for the optimized purpose.
709 */
710 int32_t reallocSize = bufMgr->m_maxNumSliceData + 10;
711
712 bufMgr->pSliceData = (DDI_CODEC_BITSTREAM_BUFFER_INFO *)realloc(bufMgr->pSliceData, sizeof(bufMgr->pSliceData[0]) * reallocSize);
713
714 if (bufMgr->pSliceData == nullptr)
715 {
716 DDI_ASSERTMESSAGE("fail to reallocate pSliceData for JPEG\n.");
717 return VA_STATUS_ERROR_ALLOCATION_FAILED;
718 }
719 memset((void *)(bufMgr->pSliceData + bufMgr->m_maxNumSliceData), 0,
720 sizeof(bufMgr->pSliceData[0]) * 10);
721
722 bufMgr->m_maxNumSliceData += 10;
723 }
724
725 bsAddr = (uint8_t*)MOS_AllocAndZeroMemory(buf->iSize);
726 if(bsAddr == 0)
727 {
728 return VA_STATUS_ERROR_ALLOCATION_FAILED;
729 }
730
731 buf->pData = bsAddr;
732 buf->format = Media_Format_CPU;
733 buf->bCFlushReq = false;
734 buf->uiOffset = 0;
735 bufMgr->pSliceData[index].uiLength = buf->iSize;
736 bufMgr->pSliceData[index].uiOffset = buf->uiOffset;
737 bufMgr->pSliceData[index].pBaseAddress = buf->pData;
738 bufMgr->dwNumSliceData ++;
739 return VA_STATUS_SUCCESS;
740 }
741
AllocSliceControlBuffer(DDI_MEDIA_BUFFER * buf)742 VAStatus DdiDecodeJPEG::AllocSliceControlBuffer(
743 DDI_MEDIA_BUFFER *buf)
744 {
745 DDI_CODEC_COM_BUFFER_MGR *bufMgr;
746 uint32_t availSize;
747 uint32_t newSize;
748
749 bufMgr = &(m_ddiDecodeCtx->BufMgr);
750 availSize = m_sliceCtrlBufNum - bufMgr->dwNumSliceControl;
751
752 if(availSize < buf->uiNumElements)
753 {
754 newSize = sizeof(VASliceParameterBufferJPEGBaseline) * (m_sliceCtrlBufNum - availSize + buf->uiNumElements);
755 bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG = (VASliceParameterBufferJPEGBaseline *)realloc(bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG, newSize);
756 if(bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG == nullptr)
757 {
758 return VA_STATUS_ERROR_ALLOCATION_FAILED;
759 }
760 MOS_ZeroMemory(bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG + m_sliceCtrlBufNum, sizeof(VASliceParameterBufferJPEGBaseline) * (buf->uiNumElements - availSize));
761 m_sliceCtrlBufNum = m_sliceCtrlBufNum - availSize + buf->uiNumElements;
762 }
763 buf->pData = (uint8_t*)bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG;
764 buf->uiOffset = sizeof(VASliceParameterBufferJPEGBaseline) * bufMgr->dwNumSliceControl;
765
766 bufMgr->dwNumSliceControl += buf->uiNumElements;
767
768 return VA_STATUS_SUCCESS;
769 }
770
ContextInit(int32_t picWidth,int32_t picHeight)771 void DdiDecodeJPEG::ContextInit(
772 int32_t picWidth,
773 int32_t picHeight)
774 {
775 // call the function in base class to initialize it.
776 DdiMediaDecode::ContextInit(picWidth, picHeight);
777
778 m_ddiDecodeCtx->wMode = CODECHAL_DECODE_MODE_JPEG;
779 }
780
InitResourceBuffer()781 VAStatus DdiDecodeJPEG::InitResourceBuffer()
782 {
783 VAStatus vaStatus = VA_STATUS_SUCCESS;
784 DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
785 bufMgr->pSliceData = nullptr;
786
787 bufMgr->ui64BitstreamOrder = 0;
788 bufMgr->dwMaxBsSize = m_width *
789 m_height * 3 / 2;
790
791 bufMgr->dwNumSliceData = 0;
792 bufMgr->dwNumSliceControl = 0;
793
794 m_sliceCtrlBufNum = DDI_DECODE_JPEG_SLICE_PARAM_BUF_NUM;
795 bufMgr->m_maxNumSliceData = DDI_DECODE_JPEG_SLICE_PARAM_BUF_NUM;
796 bufMgr->pSliceData = (DDI_CODEC_BITSTREAM_BUFFER_INFO *)MOS_AllocAndZeroMemory(sizeof(bufMgr->pSliceData[0]) * DDI_DECODE_JPEG_SLICE_PARAM_BUF_NUM);
797 if (bufMgr->pSliceData == nullptr)
798 {
799 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
800 goto finish;
801 }
802 bufMgr->dwNumOfRenderedSlicePara = 0;
803 bufMgr->dwNumOfRenderedSliceData = 0;
804 bufMgr->pNumOfRenderedSliceParaForOneBuffer = (int32_t *)MOS_AllocAndZeroMemory(sizeof(bufMgr->pNumOfRenderedSliceParaForOneBuffer[0]) * m_sliceCtrlBufNum);
805 bufMgr->pRenderedOrder = (int32_t *)MOS_AllocAndZeroMemory(sizeof(bufMgr->pRenderedOrder[0]) * m_sliceCtrlBufNum);
806 bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG = (VASliceParameterBufferJPEGBaseline *)MOS_AllocAndZeroMemory(sizeof(VASliceParameterBufferJPEGBaseline) * m_sliceCtrlBufNum);
807 if (bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG == nullptr)
808 {
809 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
810 goto finish;
811 }
812
813 return VA_STATUS_SUCCESS;
814
815 finish:
816 FreeResourceBuffer();
817 return vaStatus;
818 }
819
FreeResourceBuffer()820 void DdiDecodeJPEG::FreeResourceBuffer()
821 {
822 DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
823
824 if (bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG)
825 {
826 MOS_FreeMemory(bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG);
827 bufMgr->Codec_Param.Codec_Param_JPEG.pVASliceParaBufJPEG = nullptr;
828 }
829 bufMgr->dwNumOfRenderedSlicePara = 0;
830 bufMgr->dwNumOfRenderedSliceData = 0;
831 MOS_FreeMemory(bufMgr->pNumOfRenderedSliceParaForOneBuffer);
832 bufMgr->pNumOfRenderedSliceParaForOneBuffer = nullptr;
833 MOS_FreeMemory(bufMgr->pRenderedOrder);
834 bufMgr->pRenderedOrder = nullptr;
835
836 for (uint32_t i = 0; i < bufMgr->dwNumSliceData && (bufMgr->pSliceData != nullptr); i++)
837 {
838 if (bufMgr->pSliceData[i].pBaseAddress != nullptr)
839 {
840 MOS_FreeMemory(bufMgr->pSliceData[i].pBaseAddress);
841 bufMgr->pSliceData[i].pBaseAddress = nullptr;
842 }
843 }
844
845 bufMgr->dwNumSliceData = 0;
846
847 if (m_jpegBitstreamBuf)
848 {
849 DdiMediaUtil_FreeBuffer(m_jpegBitstreamBuf);
850 MOS_FreeMemory(m_jpegBitstreamBuf);
851 m_jpegBitstreamBuf = nullptr;
852 }
853
854 // free decode bitstream buffer object
855 MOS_FreeMemory(bufMgr->pSliceData);
856 bufMgr->pSliceData = nullptr;
857
858 return;
859 }
860
CodecHalInit(DDI_MEDIA_CONTEXT * mediaCtx,void * ptr)861 VAStatus DdiDecodeJPEG::CodecHalInit(
862 DDI_MEDIA_CONTEXT *mediaCtx,
863 void *ptr)
864 {
865 VAStatus vaStatus = VA_STATUS_SUCCESS;
866 MOS_CONTEXT *mosCtx = (MOS_CONTEXT *)ptr;
867
868 CODECHAL_FUNCTION codecFunction = CODECHAL_FUNCTION_DECODE;
869 m_ddiDecodeCtx->pCpDdiInterface->SetCpParams(m_ddiDecodeAttr->uiEncryptionType, m_codechalSettings);
870
871 CODECHAL_STANDARD_INFO standardInfo;
872 memset(&standardInfo, 0, sizeof(standardInfo));
873
874 standardInfo.CodecFunction = codecFunction;
875 standardInfo.Mode = (CODECHAL_MODE)m_ddiDecodeCtx->wMode;
876
877 m_codechalSettings->codecFunction = codecFunction;
878 m_codechalSettings->width = m_width;
879 m_codechalSettings->height = m_height;
880 m_codechalSettings->intelEntrypointInUse = false;
881
882 m_codechalSettings->lumaChromaDepth = CODECHAL_LUMA_CHROMA_DEPTH_8_BITS;
883
884 m_codechalSettings->shortFormatInUse = m_ddiDecodeCtx->bShortFormatInUse;
885
886 m_codechalSettings->mode = CODECHAL_DECODE_MODE_JPEG;
887 m_codechalSettings->standard = CODECHAL_JPEG;
888
889 #ifdef _DECODE_PROCESSING_SUPPORTED
890 m_codechalSettings->sfcEnablingHinted = true;
891 #endif
892
893 m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer = MOS_AllocAndZeroMemory(sizeof(CodecJpegQuantMatrix));
894 if (m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer == nullptr)
895 {
896 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
897 goto CleanUpandReturn;
898 }
899 m_ddiDecodeCtx->DecodeParams.m_picParams = MOS_AllocAndZeroMemory(sizeof(CodecDecodeJpegPicParams));
900 if (m_ddiDecodeCtx->DecodeParams.m_picParams == nullptr)
901 {
902 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
903 goto CleanUpandReturn;
904 }
905
906 m_ddiDecodeCtx->DecodeParams.m_huffmanTable = (void*)MOS_AllocAndZeroMemory(sizeof(CODECHAL_DECODE_JPEG_HUFFMAN_TABLE));
907 if (!m_ddiDecodeCtx->DecodeParams.m_huffmanTable)
908 {
909 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
910 goto CleanUpandReturn;
911 }
912
913 m_sliceParamBufNum = DDI_DECODE_JPEG_SLICE_PARAM_BUF_NUM;
914 m_ddiDecodeCtx->DecodeParams.m_sliceParams = (void *)MOS_AllocAndZeroMemory(m_sliceParamBufNum * sizeof(CodecDecodeJpegScanParameter));
915
916 if (m_ddiDecodeCtx->DecodeParams.m_sliceParams == nullptr)
917 {
918 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
919 goto CleanUpandReturn;
920 }
921
922 vaStatus = CreateCodecHal(mediaCtx,
923 ptr,
924 &standardInfo);
925
926 if (vaStatus != VA_STATUS_SUCCESS)
927 {
928 goto CleanUpandReturn;
929 }
930
931 if (InitResourceBuffer() != VA_STATUS_SUCCESS)
932 {
933 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
934 goto CleanUpandReturn;
935 }
936
937 return vaStatus;
938
939 CleanUpandReturn:
940 FreeResourceBuffer();
941
942 if (m_ddiDecodeCtx->pCodecHal)
943 {
944 m_ddiDecodeCtx->pCodecHal->Destroy();
945 MOS_Delete(m_ddiDecodeCtx->pCodecHal);
946 m_ddiDecodeCtx->pCodecHal = nullptr;
947 }
948
949 MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer);
950 m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer = nullptr;
951 MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_picParams);
952 m_ddiDecodeCtx->DecodeParams.m_picParams = nullptr;
953 MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_huffmanTable);
954 m_ddiDecodeCtx->DecodeParams.m_huffmanTable = nullptr;
955 MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
956 m_ddiDecodeCtx->DecodeParams.m_sliceParams = nullptr;
957
958 return vaStatus;
959 }
960
961 extern template class MediaDdiFactory<DdiMediaDecode, DDI_DECODE_CONFIG_ATTR>;
962
963 static bool jpegRegistered =
964 MediaDdiFactory<DdiMediaDecode, DDI_DECODE_CONFIG_ATTR>::RegisterCodec<DdiDecodeJPEG>(DECODE_ID_JPEG);
965