1 /*
2 * Copyright (c) 2015-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_mpeg2.cpp
24 //! \brief    The class implementation of DdiDecodeMpeg2  for Mpeg2 decode
25 //!
26 
27 #include "media_libva_decoder.h"
28 #include "media_libva_util.h"
29 #include "media_libva_caps.h"
30 
31 #include "media_ddi_decode_mpeg2.h"
32 #include "mos_solo_generic.h"
33 #include "codechal_memdecomp.h"
34 #include "media_ddi_decode_const.h"
35 #include "media_ddi_factory.h"
36 
ParseNumMbsForSlice(int32_t numSlices)37 void DdiDecodeMPEG2::ParseNumMbsForSlice(
38     int32_t numSlices)
39 {
40     CodecDecodeMpeg2PicParams *picParam = (CodecDecodeMpeg2PicParams *)(m_ddiDecodeCtx->DecodeParams.m_picParams);
41 
42     CodecDecodeMpeg2SliceParams *sliceParam = (CodecDecodeMpeg2SliceParams *)(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
43 
44     uint16_t widthInMB, heightInMB, numMBInSlc;
45     widthInMB  = m_picWidthInMB;
46     heightInMB = m_picHeightInMB;
47 
48     int32_t                      slcIndex;
49     CodecDecodeMpeg2SliceParams *nextSlc;
50     for (slcIndex = 0; slcIndex < numSlices; slcIndex++)
51     {
52         if (slcIndex == numSlices - 1)  // last slice
53         {
54             numMBInSlc = widthInMB - sliceParam->m_sliceHorizontalPosition;
55         }
56         else
57         {
58             nextSlc    = sliceParam + 1;
59             numMBInSlc = (nextSlc->m_sliceVerticalPosition * widthInMB + nextSlc->m_sliceHorizontalPosition) -
60                          (sliceParam->m_sliceVerticalPosition * widthInMB + sliceParam->m_sliceHorizontalPosition);
61         }
62 
63         sliceParam->m_numMbsForSlice = numMBInSlc & 0x007f;
64 
65         if (sliceParam->m_numMbsForSlice < numMBInSlc)
66         {
67             sliceParam->m_numMbsForSlice = widthInMB - sliceParam->m_sliceHorizontalPosition;
68         }
69 
70         sliceParam++;
71     }
72 }
73 
ParseSliceParams(DDI_MEDIA_CONTEXT * mediaCtx,VASliceParameterBufferMPEG2 * slcParam,uint32_t numSlices)74 VAStatus DdiDecodeMPEG2::ParseSliceParams(
75     DDI_MEDIA_CONTEXT            *mediaCtx,
76     VASliceParameterBufferMPEG2  *slcParam,
77     uint32_t                      numSlices)
78 {
79     CodecDecodeMpeg2PicParams *picParams = (CodecDecodeMpeg2PicParams *)(m_ddiDecodeCtx->DecodeParams.m_picParams);
80     CodecDecodeMpeg2SliceParams *codecSlcParams = (CodecDecodeMpeg2SliceParams *)(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
81     codecSlcParams += m_ddiDecodeCtx->DecodeParams.m_numSlices;
82 
83     if ((slcParam == nullptr) ||
84         (codecSlcParams == nullptr) ||
85         (picParams == nullptr))
86     {
87         DDI_ASSERTMESSAGE("Invalid Parameter for Parsing Mpeg2 Slice parameter\n");
88         return VA_STATUS_ERROR_INVALID_PARAMETER;
89     }
90 
91     uint32_t isField;
92     if ((picParams->m_currPic.PicFlags == PICTURE_TOP_FIELD) || (picParams->m_currPic.PicFlags == PICTURE_BOTTOM_FIELD))
93     {
94         isField = 1;
95     }
96     else
97     {
98         isField = 0;
99     }
100 
101     uint32_t sliceBaseOffset = GetBsBufOffset(m_groupIndex);
102     uint32_t slcCount;
103     for (slcCount = 0; slcCount < numSlices; slcCount++)
104     {
105         codecSlcParams->m_sliceHorizontalPosition = slcParam->slice_horizontal_position;
106         codecSlcParams->m_sliceVerticalPosition   = slcParam->slice_vertical_position;
107 
108         codecSlcParams->m_sliceDataSize   = (slcParam->slice_data_size) * 8;
109         codecSlcParams->m_sliceDataOffset = slcParam->slice_data_offset + sliceBaseOffset;
110         if (slcParam->slice_data_flag)
111         {
112             DDI_NORMALMESSAGE("The whole slice is not in the bitstream buffer for this Execute call");
113         }
114         codecSlcParams->m_macroblockOffset   = slcParam->macroblock_offset;
115         codecSlcParams->m_quantiserScaleCode = slcParam->quantiser_scale_code;
116         codecSlcParams->m_reservedBits       = 0;
117         slcParam++;
118         codecSlcParams++;
119     }
120 
121     return VA_STATUS_SUCCESS;
122 }
123 
ParseIQMatrix(DDI_MEDIA_CONTEXT * mediaCtx,VAIQMatrixBufferMPEG2 * matrix)124 VAStatus DdiDecodeMPEG2::ParseIQMatrix(
125     DDI_MEDIA_CONTEXT     *mediaCtx,
126     VAIQMatrixBufferMPEG2 *matrix)
127 {
128     CodecMpeg2IqMatrix *iqMatrix = (CodecMpeg2IqMatrix *)(m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer);
129 
130     if ((iqMatrix == nullptr) || (matrix == nullptr))
131     {
132         DDI_ASSERTMESSAGE("Invalid Parameter for Parsing Mpeg2 IQ Matrix parameter\n");
133         return VA_STATUS_ERROR_INVALID_PARAMETER;
134     }
135 
136     iqMatrix->m_loadIntraQuantiserMatrix          = matrix->load_intra_quantiser_matrix;
137     iqMatrix->m_loadNonIntraQuantiserMatrix       = matrix->load_non_intra_quantiser_matrix;
138     iqMatrix->m_loadChromaIntraQuantiserMatrix    = matrix->load_chroma_intra_quantiser_matrix;
139     iqMatrix->m_loadChromaNonIntraQuantiserMatrix = matrix->load_chroma_non_intra_quantiser_matrix;
140 
141     MOS_SecureMemcpy(iqMatrix->m_intraQuantiserMatrix,
142         64,
143         matrix->intra_quantiser_matrix,
144         64);
145     MOS_SecureMemcpy(iqMatrix->m_nonIntraQuantiserMatrix,
146         64,
147         matrix->non_intra_quantiser_matrix,
148         64);
149     MOS_SecureMemcpy(iqMatrix->m_chromaIntraQuantiserMatrix,
150         64,
151         matrix->chroma_intra_quantiser_matrix,
152         64);
153     MOS_SecureMemcpy(iqMatrix->m_chromaNonIntraQuantiserMatrix,
154         64,
155         matrix->chroma_non_intra_quantiser_matrix,
156         64);
157     return VA_STATUS_SUCCESS;
158 }
159 
160 #define INTRA_CODED 0x1
161 #define PREDICTIVE_CODED 0x2
162 #define BIDIRECTIONAL_CODED 0x3
163 
164 // S-(GMC) VOP coding used for MPEG4 part 2
165 //
166 #define S_CODED 0x4
167 
ParsePicParams(DDI_MEDIA_CONTEXT * mediaCtx,VAPictureParameterBufferMPEG2 * picParam)168 VAStatus DdiDecodeMPEG2::ParsePicParams(
169     DDI_MEDIA_CONTEXT             *mediaCtx,
170     VAPictureParameterBufferMPEG2 *picParam)
171 {
172     CodecDecodeMpeg2PicParams *codecPicParam = (CodecDecodeMpeg2PicParams *)(m_ddiDecodeCtx->DecodeParams.m_picParams);
173     if ((codecPicParam == nullptr) || (picParam == nullptr))
174     {
175         DDI_ASSERTMESSAGE("Invalid Parameter for Parsing Mpeg2 Picture Parameter\n");
176         return VA_STATUS_ERROR_INVALID_PARAMETER;
177     }
178 
179     codecPicParam->m_currPic.FrameIdx = GetRenderTargetID(&(m_ddiDecodeCtx->RTtbl), m_ddiDecodeCtx->RTtbl.pCurrentRT);
180     switch (picParam->picture_coding_extension.bits.picture_structure)
181     {
182     case TOP_FIELD:
183         codecPicParam->m_currPic.PicFlags = PICTURE_TOP_FIELD;
184         break;
185     case BOTTOM_FIELD:
186         codecPicParam->m_currPic.PicFlags = PICTURE_BOTTOM_FIELD;
187         break;
188     case FRAME_PICTURE:
189         codecPicParam->m_currPic.PicFlags = PICTURE_FRAME;
190         break;
191     default:
192         break;
193     }
194     codecPicParam->m_topFieldFirst     = picParam->picture_coding_extension.bits.top_field_first;
195     codecPicParam->m_secondField       = !(picParam->picture_coding_extension.bits.is_first_field);
196     codecPicParam->m_pictureCodingType = picParam->picture_coding_type;
197 
198     if (picParam->picture_coding_extension.bits.is_first_field)
199     {
200         if (codecPicParam->m_currPic.PicFlags == PICTURE_TOP_FIELD)
201             codecPicParam->m_topFieldFirst = 1;
202         if (codecPicParam->m_currPic.PicFlags == PICTURE_BOTTOM_FIELD)
203             codecPicParam->m_topFieldFirst = 0;
204     }
205     else
206     {
207         if (codecPicParam->m_currPic.PicFlags == PICTURE_TOP_FIELD)
208             codecPicParam->m_topFieldFirst = 0;
209 
210         if (codecPicParam->m_currPic.PicFlags == PICTURE_BOTTOM_FIELD)
211             codecPicParam->m_topFieldFirst = 1;
212     }
213     if (picParam->picture_coding_type == INTRA_CODED)
214     {
215         codecPicParam->m_forwardRefIdx  = codecPicParam->m_currPic.FrameIdx;
216         codecPicParam->m_backwardRefIdx = codecPicParam->m_currPic.FrameIdx;
217     }
218     else if (picParam->picture_coding_type == PREDICTIVE_CODED)
219     {
220         if (picParam->forward_reference_picture != VA_INVALID_SURFACE)
221         {
222             if (UpdateRegisteredRTSurfaceFlag(&(m_ddiDecodeCtx->RTtbl), DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParam->forward_reference_picture)) != VA_STATUS_SUCCESS)
223             {
224                 DDI_CHK_RET(RegisterRTSurfaces(&(m_ddiDecodeCtx->RTtbl), DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParam->forward_reference_picture)), "RegisterRTSurfaces failed!");
225             }
226 
227             codecPicParam->m_forwardRefIdx = GetRenderTargetID(&(m_ddiDecodeCtx->RTtbl), DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParam->forward_reference_picture));  //(unsigned char)GetMPEG2SurfaceIdx(&(pRTtbl->pRT[0]), picParam->forward_reference_picture);
228         }
229         else
230         {
231             codecPicParam->m_forwardRefIdx = codecPicParam->m_currPic.FrameIdx;
232         }
233 
234         if (codecPicParam->m_secondField)
235         {
236             codecPicParam->m_backwardRefIdx = codecPicParam->m_currPic.FrameIdx;
237         }
238         else
239         {
240             codecPicParam->m_backwardRefIdx = codecPicParam->m_forwardRefIdx;
241         }
242     }
243     else
244     {
245         if (picParam->forward_reference_picture != VA_INVALID_SURFACE)
246         {
247             if (UpdateRegisteredRTSurfaceFlag(&(m_ddiDecodeCtx->RTtbl), DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParam->forward_reference_picture)) != VA_STATUS_SUCCESS)
248             {
249                 DDI_CHK_RET(RegisterRTSurfaces(&(m_ddiDecodeCtx->RTtbl), DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParam->forward_reference_picture)), "RegisterRTSurfaces failed!");
250             }
251             codecPicParam->m_forwardRefIdx = GetRenderTargetID(&(m_ddiDecodeCtx->RTtbl), DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParam->forward_reference_picture));  //(unsigned char)GetMPEG2SurfaceIdx(&(pRTtbl->pRT[0]), picParam->forward_reference_picture);
252         }
253         else
254         {
255             codecPicParam->m_forwardRefIdx = codecPicParam->m_currPic.FrameIdx;
256         }
257         if (picParam->backward_reference_picture != VA_INVALID_SURFACE)
258         {
259             if (UpdateRegisteredRTSurfaceFlag(&(m_ddiDecodeCtx->RTtbl), DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParam->backward_reference_picture)) != VA_STATUS_SUCCESS)
260             {
261                 DDI_CHK_RET(RegisterRTSurfaces(&(m_ddiDecodeCtx->RTtbl), DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParam->backward_reference_picture)), "RegisterRTSurfaces failed!");
262             }
263             codecPicParam->m_backwardRefIdx = GetRenderTargetID(&(m_ddiDecodeCtx->RTtbl), DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParam->backward_reference_picture));  //(unsigned char)GetMPEG2SurfaceIdx(&(pRTtbl->pRT[0]), picParam->backward_reference_picture);
264         }
265         else
266         {
267             codecPicParam->m_backwardRefIdx = codecPicParam->m_currPic.FrameIdx;
268         }
269     }
270 
271     //add protection checking to prevent ref pic index larger than DPB size
272     if (codecPicParam->m_forwardRefIdx >= CODECHAL_NUM_UNCOMPRESSED_SURFACE_MPEG2)
273     {
274         codecPicParam->m_forwardRefIdx = CODECHAL_NUM_UNCOMPRESSED_SURFACE_MPEG2 - 1;
275     }
276 
277     if (codecPicParam->m_backwardRefIdx >= CODECHAL_NUM_UNCOMPRESSED_SURFACE_MPEG2)
278     {
279         codecPicParam->m_backwardRefIdx = CODECHAL_NUM_UNCOMPRESSED_SURFACE_MPEG2 - 1;
280     }
281 
282     codecPicParam->W0.m_scanOrder          = picParam->picture_coding_extension.bits.alternate_scan;
283     codecPicParam->W0.m_intraVlcFormat     = picParam->picture_coding_extension.bits.intra_vlc_format;
284     codecPicParam->W0.m_quantizerScaleType = picParam->picture_coding_extension.bits.q_scale_type;
285     codecPicParam->W0.m_concealmentMVFlag  = picParam->picture_coding_extension.bits.concealment_motion_vectors;
286     codecPicParam->W0.m_frameDctPrediction = picParam->picture_coding_extension.bits.frame_pred_frame_dct;
287     codecPicParam->W0.m_topFieldFirst      = picParam->picture_coding_extension.bits.top_field_first;
288     codecPicParam->W0.m_intraDCPrecision   = picParam->picture_coding_extension.bits.intra_dc_precision;
289     codecPicParam->W1.m_value              = 0;
290     codecPicParam->W1.m_fcode11            = (picParam->f_code) & 0xf;
291     codecPicParam->W1.m_fcode10            = (picParam->f_code >> 4) & 0xf;
292     codecPicParam->W1.m_fcode01            = (picParam->f_code >> 8) & 0xf;
293     codecPicParam->W1.m_fcode00            = (picParam->f_code >> 12) & 0xf;
294     codecPicParam->m_horizontalSize        = picParam->horizontal_size;
295     codecPicParam->m_verticalSize          = picParam->vertical_size;
296 
297     if (picParam->picture_coding_type == INTRA_CODED)
298     {
299         m_picWidthInMB  = (int16_t)(DDI_CODEC_NUM_MACROBLOCKS_WIDTH(picParam->horizontal_size));
300         m_picHeightInMB = (int16_t)(DDI_CODEC_NUM_MACROBLOCKS_WIDTH(picParam->vertical_size));
301     }
302 
303     if ((codecPicParam->m_currPic.PicFlags == PICTURE_TOP_FIELD) || (codecPicParam->m_currPic.PicFlags == PICTURE_BOTTOM_FIELD))
304     {
305         codecPicParam->m_verticalSize = picParam->vertical_size >> 1;
306     }
307 
308     codecPicParam->m_statusReportFeedbackNumber = 0;
309 
310     DDI_CHK_NULL(mediaCtx, "Null mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
311     DDI_CHK_NULL(mediaCtx->m_caps, "Null m_cpas", VA_STATUS_ERROR_INVALID_CONTEXT);
312     VAStatus vaStatus = mediaCtx->m_caps->CheckDecodeResolution(
313             m_ddiDecodeCtx->wMode,
314             VAProfileMPEG2Simple,
315             codecPicParam->m_horizontalSize,
316             codecPicParam->m_verticalSize);
317     if (vaStatus != VA_STATUS_SUCCESS)
318     {
319         return VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED;
320     }
321 
322     return VA_STATUS_SUCCESS;
323 }
324 
RenderPicture(VADriverContextP ctx,VAContextID context,VABufferID * buffers,int32_t numBuffers)325 VAStatus DdiDecodeMPEG2::RenderPicture(
326     VADriverContextP ctx,
327     VAContextID      context,
328     VABufferID       *buffers,
329     int32_t          numBuffers)
330 {
331     VAStatus           va = VA_STATUS_SUCCESS;
332     PDDI_MEDIA_CONTEXT mediaCtx;
333 
334     DDI_FUNCTION_ENTER();
335 
336     mediaCtx = DdiMedia_GetMediaContext(ctx);
337 
338     void             *data = nullptr;
339     for (int32_t i = 0; i < numBuffers; i++)
340     {
341         if (!buffers || (buffers[i] == VA_INVALID_ID))
342         {
343             return VA_STATUS_ERROR_INVALID_BUFFER;
344         }
345 
346         DDI_MEDIA_BUFFER *buf = DdiMedia_GetBufferFromVABufferID(mediaCtx, buffers[i]);
347         if (nullptr == buf)
348         {
349             return VA_STATUS_ERROR_INVALID_BUFFER;
350         }
351 
352         uint32_t dataSize = buf->iSize;
353         DdiMedia_MapBuffer(ctx, buffers[i], &data);
354 
355         if (data == nullptr)
356         {
357             return VA_STATUS_ERROR_INVALID_BUFFER;
358         }
359 
360         switch ((int32_t)buf->uiType)
361         {
362         case VASliceDataBufferType:
363         {
364             int32_t index = GetBitstreamBufIndexFromBuffer(&m_ddiDecodeCtx->BufMgr, buf);
365             if (index == DDI_CODEC_INVALID_BUFFER_INDEX)
366             {
367                 return VA_STATUS_ERROR_INVALID_BUFFER;
368             }
369 
370             DdiMedia_MediaBufferToMosResource(m_ddiDecodeCtx->BufMgr.pBitStreamBuffObject[index], &m_ddiDecodeCtx->BufMgr.resBitstreamBuffer);
371             m_ddiDecodeCtx->DecodeParams.m_dataSize += dataSize;
372             break;
373         }
374         case VASliceParameterBufferType:
375         {
376             if (buf->uiNumElements == 0)
377             {
378                 return VA_STATUS_ERROR_INVALID_BUFFER;
379             }
380 
381             VASliceParameterBufferMPEG2 *slcInfoMpeg2 =
382                 (VASliceParameterBufferMPEG2 *)data;
383             uint32_t numSlices = buf->uiNumElements;
384             DDI_CHK_RET(AllocSliceParamContext(numSlices),"AllocSliceParamContext failed!");
385             DDI_CHK_RET(ParseSliceParams(mediaCtx, slcInfoMpeg2, numSlices),"ParseSliceParams failed!");
386             m_ddiDecodeCtx->DecodeParams.m_numSlices += numSlices;
387             m_groupIndex++;
388             break;
389         }
390         case VAPictureParameterBufferType:
391         {
392             VAPictureParameterBufferMPEG2 *picParam = (VAPictureParameterBufferMPEG2 *)data;
393             DDI_CHK_RET(ParsePicParams(mediaCtx, picParam),"ParsePicParams failed!");
394             break;
395         }
396         case VAIQMatrixBufferType:
397         {
398             VAIQMatrixBufferMPEG2 *imxBuf =
399                 (VAIQMatrixBufferMPEG2 *)data;
400             DDI_CHK_RET(ParseIQMatrix(mediaCtx, imxBuf),"ParseIQMatrix failed!");
401             break;
402         }
403         case VADecodeStreamoutBufferType:
404         {
405             DdiMedia_MediaBufferToMosResource(buf, &m_ddiDecodeCtx->BufMgr.resExternalStreamOutBuffer);
406             m_streamOutEnabled = true;
407             break;
408         }
409         default:
410             va = VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
411             break;
412         }
413         DdiMedia_UnmapBuffer(ctx, buffers[i]);
414     }
415 
416     DDI_FUNCTION_EXIT(va);
417     return va;
418 }
419 
SetDecodeParams()420 VAStatus DdiDecodeMPEG2::SetDecodeParams()
421 {
422     DDI_CHK_RET(DdiMediaDecode::SetDecodeParams(),"SetDecodeParams failed!");
423     ParseNumMbsForSlice((&m_ddiDecodeCtx->DecodeParams)->m_numSlices);
424     return  VA_STATUS_SUCCESS;
425 }
426 
AllocSliceParamContext(uint32_t numSlices)427 VAStatus DdiDecodeMPEG2::AllocSliceParamContext(
428     uint32_t numSlices)
429 {
430     uint32_t baseSize = sizeof(CodecDecodeMpeg2SliceParams);
431 
432     if (m_sliceParamBufNum < (m_ddiDecodeCtx->DecodeParams.m_numSlices + numSlices))
433     {
434         // in order to avoid that the buffer is reallocated multi-times,
435         // extra 10 slices are added.
436         uint32_t extraSlices = numSlices + 10;
437 
438         m_ddiDecodeCtx->DecodeParams.m_sliceParams = realloc(m_ddiDecodeCtx->DecodeParams.m_sliceParams,
439             baseSize * (m_sliceParamBufNum + extraSlices));
440 
441         if (m_ddiDecodeCtx->DecodeParams.m_sliceParams == nullptr)
442         {
443             return VA_STATUS_ERROR_ALLOCATION_FAILED;
444         }
445 
446         memset((void *)((uint8_t *)m_ddiDecodeCtx->DecodeParams.m_sliceParams + baseSize * m_sliceParamBufNum), 0, baseSize * extraSlices);
447         m_sliceParamBufNum += extraSlices;
448     }
449 
450     return VA_STATUS_SUCCESS;
451 }
452 
DestroyContext(VADriverContextP ctx)453 void DdiDecodeMPEG2::DestroyContext(
454     VADriverContextP ctx)
455 {
456     FreeResourceBuffer();
457     // explicitly call the base function to do the further clean-up
458     DdiMediaDecode::DestroyContext(ctx);
459 }
460 
GetPicParamBuf(DDI_CODEC_COM_BUFFER_MGR * bufMgr)461 uint8_t* DdiDecodeMPEG2::GetPicParamBuf(
462     DDI_CODEC_COM_BUFFER_MGR    *bufMgr)
463 {
464     return (uint8_t*)(&(bufMgr->Codec_Param.Codec_Param_MPEG2.PicParamMPEG2));
465 }
466 
AllocSliceControlBuffer(DDI_MEDIA_BUFFER * buf)467 VAStatus DdiDecodeMPEG2::AllocSliceControlBuffer(
468     DDI_MEDIA_BUFFER       *buf)
469 {
470     DDI_CODEC_COM_BUFFER_MGR   *bufMgr;
471     uint32_t                    availSize;
472     uint32_t                    newSize;
473 
474     bufMgr     = &(m_ddiDecodeCtx->BufMgr);
475     availSize  = m_sliceCtrlBufNum - bufMgr->dwNumSliceControl;
476     if(availSize < buf->uiNumElements)
477     {
478         newSize   = sizeof(VASliceParameterBufferMPEG2) * (m_sliceCtrlBufNum - availSize + buf->uiNumElements);
479         bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2 = (VASliceParameterBufferMPEG2 *)realloc(bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2, newSize);
480         if(bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2 == nullptr)
481         {
482             return VA_STATUS_ERROR_ALLOCATION_FAILED;
483         }
484         MOS_ZeroMemory(bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2 + m_sliceCtrlBufNum, sizeof(VASliceParameterBufferMPEG2) * (buf->uiNumElements - availSize));
485         m_sliceCtrlBufNum = m_sliceCtrlBufNum - availSize + buf->uiNumElements;
486     }
487     buf->pData      = (uint8_t*)bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2;
488     buf->uiOffset   = sizeof(VASliceParameterBufferMPEG2) * bufMgr->dwNumSliceControl;
489 
490     bufMgr->dwNumSliceControl += buf->uiNumElements;
491 
492     return VA_STATUS_SUCCESS;
493 }
494 
ContextInit(int32_t picWidth,int32_t picHeight)495 void DdiDecodeMPEG2::ContextInit(
496     int32_t picWidth,
497     int32_t picHeight)
498 {
499     // call the function in base class to initialize it.
500     DdiMediaDecode::ContextInit(picWidth, picHeight);
501 
502     m_ddiDecodeCtx->wMode             = CODECHAL_DECODE_MODE_MPEG2VLD;
503 }
504 
InitResourceBuffer()505 VAStatus DdiDecodeMPEG2::InitResourceBuffer()
506 {
507     VAStatus                  vaStatus = VA_STATUS_SUCCESS;
508     DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
509 
510     bufMgr->pSliceData = nullptr;
511 
512     bufMgr->ui64BitstreamOrder = 0;
513     bufMgr->dwMaxBsSize        = m_width *
514                           m_height * 3 / 2;
515     // minimal 10k bytes for some special case. Will refractor this later
516     if (bufMgr->dwMaxBsSize < DDI_CODEC_MIN_VALUE_OF_MAX_BS_SIZE)
517     {
518         bufMgr->dwMaxBsSize = DDI_CODEC_MIN_VALUE_OF_MAX_BS_SIZE;
519     }
520 
521     int32_t i;
522     // init decode bitstream buffer object
523     for (i = 0; i < DDI_CODEC_MAX_BITSTREAM_BUFFER; i++)
524     {
525         bufMgr->pBitStreamBuffObject[i] = (DDI_MEDIA_BUFFER *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_BUFFER));
526         if (bufMgr->pBitStreamBuffObject[i] == nullptr)
527         {
528             vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
529             goto finish;
530         }
531         bufMgr->pBitStreamBuffObject[i]->iSize    = bufMgr->dwMaxBsSize;
532         bufMgr->pBitStreamBuffObject[i]->uiType   = VASliceDataBufferType;
533         bufMgr->pBitStreamBuffObject[i]->format   = Media_Format_Buffer;
534         bufMgr->pBitStreamBuffObject[i]->uiOffset = 0;
535         bufMgr->pBitStreamBuffObject[i]->bo       = nullptr;
536         bufMgr->pBitStreamBase[i]                 = nullptr;
537     }
538 
539     // Most Mpeg2 clips are based on row.
540     // As the pSliceData can be allocated on demand, the default size is based on wPicHeightInMB.
541     bufMgr->m_maxNumSliceData = m_picHeightInMB;
542     bufMgr->pSliceData        = (DDI_CODEC_BITSTREAM_BUFFER_INFO *)MOS_AllocAndZeroMemory(sizeof(bufMgr->pSliceData[0]) *
543                                                                                    bufMgr->m_maxNumSliceData);
544 
545     if (bufMgr->pSliceData == nullptr)
546     {
547         vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
548         goto finish;
549     }
550 
551     bufMgr->dwNumSliceData    = 0;
552     bufMgr->dwNumSliceControl = 0;
553 
554     m_sliceCtrlBufNum                          = m_picHeightInMB;
555     bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2 = (VASliceParameterBufferMPEG2 *)MOS_AllocAndZeroMemory(sizeof(VASliceParameterBufferMPEG2) * m_sliceCtrlBufNum);
556     if (bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2 == nullptr)
557     {
558         vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
559         goto finish;
560     }
561 
562     return VA_STATUS_SUCCESS;
563 
564 finish:
565     FreeResourceBuffer();
566     return vaStatus;
567 }
568 
FreeResourceBuffer()569 void DdiDecodeMPEG2::FreeResourceBuffer()
570 {
571     DDI_CODEC_COM_BUFFER_MGR *bufMgr = &(m_ddiDecodeCtx->BufMgr);
572 
573     int32_t i;
574     for (i = 0; i < DDI_CODEC_MAX_BITSTREAM_BUFFER; i++)
575     {
576         if (bufMgr->pBitStreamBase[i])
577         {
578             DdiMediaUtil_UnlockBuffer(bufMgr->pBitStreamBuffObject[i]);
579             bufMgr->pBitStreamBase[i] = nullptr;
580         }
581         if (bufMgr->pBitStreamBuffObject[i])
582         {
583             DdiMediaUtil_FreeBuffer(bufMgr->pBitStreamBuffObject[i]);
584             MOS_FreeMemory(bufMgr->pBitStreamBuffObject[i]);
585             bufMgr->pBitStreamBuffObject[i] = nullptr;
586         }
587     }
588 
589     if (bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2)
590     {
591         MOS_FreeMemory(bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2);
592         bufMgr->Codec_Param.Codec_Param_MPEG2.pVASliceParaBufMPEG2 = nullptr;
593     }
594 
595     // free decode bitstream buffer object
596     MOS_FreeMemory(bufMgr->pSliceData);
597     bufMgr->pSliceData = nullptr;
598 
599     return;
600 }
601 
CodecHalInit(DDI_MEDIA_CONTEXT * mediaCtx,void * ptr)602 VAStatus DdiDecodeMPEG2::CodecHalInit(
603     DDI_MEDIA_CONTEXT *mediaCtx,
604     void              *ptr)
605 {
606     VAStatus     vaStatus = VA_STATUS_SUCCESS;
607     MOS_CONTEXT *mosCtx   = (MOS_CONTEXT *)ptr;
608 
609     CODECHAL_FUNCTION codecFunction = CODECHAL_FUNCTION_DECODE;
610     m_ddiDecodeCtx->pCpDdiInterface->SetCpParams(m_ddiDecodeAttr->uiEncryptionType, m_codechalSettings);
611 
612     CODECHAL_STANDARD_INFO standardInfo;
613     memset(&standardInfo, 0, sizeof(standardInfo));
614 
615     standardInfo.CodecFunction = codecFunction;
616     standardInfo.Mode          = (CODECHAL_MODE)m_ddiDecodeCtx->wMode;
617 
618     m_codechalSettings->codecFunction                = codecFunction;
619     m_codechalSettings->width                      = m_width;
620     m_codechalSettings->height                     = m_height;
621     m_codechalSettings->intelEntrypointInUse        = false;
622 
623     m_codechalSettings->lumaChromaDepth = CODECHAL_LUMA_CHROMA_DEPTH_8_BITS;
624 
625     m_codechalSettings->shortFormatInUse = m_ddiDecodeCtx->bShortFormatInUse;
626 
627     m_codechalSettings->mode     = CODECHAL_DECODE_MODE_MPEG2VLD;
628     m_codechalSettings->standard = CODECHAL_MPEG2;
629 
630     m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer = MOS_AllocAndZeroMemory(sizeof(CodecMpeg2IqMatrix));
631     if (m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer == nullptr)
632     {
633         vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
634         goto CleanUpandReturn;
635     }
636     m_ddiDecodeCtx->DecodeParams.m_picParams = MOS_AllocAndZeroMemory(sizeof(CodecDecodeMpeg2PicParams));
637     if (m_ddiDecodeCtx->DecodeParams.m_picParams == nullptr)
638     {
639         vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
640         goto CleanUpandReturn;
641     }
642 
643     m_sliceParamBufNum         = m_picHeightInMB;
644     m_ddiDecodeCtx->DecodeParams.m_sliceParams = MOS_AllocAndZeroMemory(m_sliceParamBufNum * sizeof(CodecDecodeMpeg2SliceParams));
645     if (m_ddiDecodeCtx->DecodeParams.m_sliceParams == nullptr)
646     {
647         vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
648         goto CleanUpandReturn;
649     }
650 
651     vaStatus = CreateCodecHal(mediaCtx,
652         ptr,
653         &standardInfo);
654 
655     if (vaStatus != VA_STATUS_SUCCESS)
656     {
657         goto CleanUpandReturn;
658     }
659 
660     if (InitResourceBuffer() != VA_STATUS_SUCCESS)
661     {
662         vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
663         goto CleanUpandReturn;
664     }
665 
666     return vaStatus;
667 
668 CleanUpandReturn:
669     FreeResourceBuffer();
670 
671     if (m_ddiDecodeCtx->pCodecHal)
672     {
673         m_ddiDecodeCtx->pCodecHal->Destroy();
674         MOS_Delete(m_ddiDecodeCtx->pCodecHal);
675         m_ddiDecodeCtx->pCodecHal = nullptr;
676     }
677 
678     MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer);
679     m_ddiDecodeCtx->DecodeParams.m_iqMatrixBuffer = nullptr;
680     MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_picParams);
681     m_ddiDecodeCtx->DecodeParams.m_picParams = nullptr;
682     MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_huffmanTable);
683     m_ddiDecodeCtx->DecodeParams.m_huffmanTable = nullptr;
684     MOS_FreeMemory(m_ddiDecodeCtx->DecodeParams.m_sliceParams);
685     m_ddiDecodeCtx->DecodeParams.m_sliceParams = nullptr;
686 
687     return vaStatus;
688 }
689 
690 extern template class MediaDdiFactory<DdiMediaDecode, DDI_DECODE_CONFIG_ATTR>;
691 
692 static bool mpeg2Registered =
693     MediaDdiFactory<DdiMediaDecode, DDI_DECODE_CONFIG_ATTR>::RegisterCodec<DdiDecodeMPEG2>(DECODE_ID_MPEG2);
694