1 /*
2 * Copyright (c) 2021, 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 //!
24 //! \file     decode_mpeg2_basic_features.cpp
25 //! \brief    Defines the common interface for decode mpeg2 basic feature
26 //!
27 #include "decode_mpeg2_basic_feature.h"
28 #include "decode_utils.h"
29 #include "decode_allocator.h"
30 #include "decode_resource_array.h"
31 
32 namespace decode{
33 
~Mpeg2BasicFeature()34 Mpeg2BasicFeature::~Mpeg2BasicFeature()
35 {
36     if (m_allocator != nullptr)
37     {
38         if (m_resMpeg2DummyBistream != nullptr)
39         {
40             m_allocator->Destroy(m_resMpeg2DummyBistream);
41         }
42 
43         m_allocator->Destroy(m_copiedDataBufArray);
44     }
45 }
46 
Init(void * setting)47 MOS_STATUS Mpeg2BasicFeature::Init(void *setting)
48 {
49     DECODE_FUNC_CALL();
50 
51     PERF_UTILITY_AUTO(__FUNCTION__, PERF_DECODE, PERF_LEVEL_HAL);
52     DECODE_CHK_STATUS(DecodeBasicFeature::Init(setting));
53 
54     m_picWidthInMb  = (uint16_t)CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_width);
55     m_picHeightInMb = (uint16_t)CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_height);
56 
57     DECODE_CHK_STATUS(m_refFrames.Init(this, *m_allocator));
58 
59     // Dummy slice buffer
60     if (m_mode == CODECHAL_DECODE_MODE_MPEG2VLD)
61     {
62         uint32_t size = MOS_ALIGN_CEIL(sizeof(Mpeg2DummyBsBuf), 64);
63         m_resMpeg2DummyBistream = m_allocator->AllocateBuffer(
64                                      size,
65                                      "Mpeg2DummyBitstream",
66                                      resourceInternalReadWriteCache,
67                                      lockableVideoMem);
68         auto data = (uint8_t *)m_allocator->LockResourceForWrite(&m_resMpeg2DummyBistream->OsResource);
69         DECODE_CHK_NULL(data);
70 
71         MOS_ZeroMemory(data, size);
72         MOS_SecureMemcpy(data, sizeof(Mpeg2DummyBsBuf), Mpeg2DummyBsBuf, sizeof(Mpeg2DummyBsBuf));
73     }
74 
75     if (m_mode == CODECHAL_DECODE_MODE_MPEG2IDCT)
76     {
77         // The common indirect IT-COEFF data structure is defined as a uint32_t.
78         m_copiedDataBufferSize = (m_picWidthInMb * m_picHeightInMb + 2) *
79             (CODEC_NUM_BLOCK_PER_MB * CODEC_MPEG2_IDCTBLOCK_SIZE * sizeof(uint32_t));
80     }
81     else
82     {
83         // Bitstream buffer size = height * width + dummy slice + 512 (for padding)
84         m_copiedDataBufferSize = (m_picWidthInMb * m_picHeightInMb * CODEC_MPEG2_BYTES_PER_MB) +
85             sizeof(Mpeg2DummyBsBuf) + 512;
86     }
87 
88     m_copiedDataBufArray = m_allocator->AllocateBufferArray(
89         m_copiedDataBufferSize,
90         "copied data buffer",
91         m_mpeg2NumCopiedBufs,
92         resourceInputBitstream,
93         notLockableVideoMem);
94     DECODE_CHK_NULL(m_copiedDataBufArray);
95 
96     return MOS_STATUS_SUCCESS;
97 }
98 
Update(void * params)99 MOS_STATUS Mpeg2BasicFeature::Update(void *params)
100 {
101     DECODE_FUNC_CALL();
102 
103     PERF_UTILITY_AUTO(__FUNCTION__, PERF_DECODE, PERF_LEVEL_HAL);
104 
105     DECODE_CHK_NULL(params);
106     DECODE_CHK_STATUS(DecodeBasicFeature::Update(params));
107 
108     CodechalDecodeParams* decodeParams = (CodechalDecodeParams*)params;
109     DECODE_CHK_NULL(decodeParams->m_picParams);
110     m_mpeg2PicParams                      = (CodecDecodeMpeg2PicParams *)decodeParams->m_picParams;
111     m_mpeg2SliceParams                    = (CodecDecodeMpeg2SliceParams *)decodeParams->m_sliceParams;
112     m_mpeg2IqMatrixBuffer                 = (CodecMpeg2IqMatrix *)decodeParams->m_iqMatrixBuffer;
113     m_mpeg2MbParams                       = (CodecDecodeMpeg2MbParams *)decodeParams->m_macroblockParams;
114     m_numMacroblocks                      = decodeParams->m_numMacroblocks;
115     m_mpeg2ISliceConcealmentMode          = decodeParams->m_mpeg2ISliceConcealmentMode;
116     m_mpeg2PbSliceConcealmentMode         = decodeParams->m_mpeg2PBSliceConcealmentMode;
117     m_mpeg2PbSlicePredBiDirMvTypeOverride = decodeParams->m_mpeg2PBSlicePredBiDirMVTypeOverride;
118     m_mpeg2PbSlicePredMvOverride          = decodeParams->m_mpeg2PBSlicePredMVOverride;
119     DECODE_CHK_NULL(m_mpeg2PicParams);
120 
121     if (decodeParams->m_executeCallIndex == 0)
122     {
123         DECODE_CHK_STATUS(ResetFrameValues());
124         DECODE_CHK_STATUS(SetPictureStructs());
125     }
126     else
127     {
128         DECODE_VERBOSEMESSAGE("there is multiple execution call in current Frame = %d",
129             m_mpeg2PicParams->m_currPic.FrameIdx);
130     }
131 
132     if (m_mode == CODECHAL_DECODE_MODE_MPEG2VLD)
133     {
134         DECODE_CHK_STATUS(SetSliceStructs());
135     }
136     else if (m_mode == CODECHAL_DECODE_MODE_MPEG2IDCT)
137     {
138         DECODE_CHK_STATUS(SetMbStructs());
139     }
140 
141     return MOS_STATUS_SUCCESS;
142 }
143 
ResetFrameValues()144 MOS_STATUS Mpeg2BasicFeature::ResetFrameValues()
145 {
146     DECODE_FUNC_CALL();
147 
148     m_copiedDataBuf = m_copiedDataBufArray->Fetch();
149     DECODE_CHK_NULL(m_copiedDataBuf);
150 
151     m_incompletePicture     = false;
152     m_copiedDataBufferInUse = false;
153     m_copiedDataOffset      = 0;
154     m_nextCopiedDataOffset  = 0;
155     m_lastMbAddress         = 0;
156 
157     if (m_mode == CODECHAL_DECODE_MODE_MPEG2VLD)
158     {
159         m_slicesInvalid          = false;
160         m_copyDummySlicePresent  = false;
161         m_totalNumSlicesRecv     = 0;
162         m_lastSliceMbEnd         = 0;
163     }
164     else
165     {
166         m_totalNumMbsRecv = 0;
167     }
168 
169     return MOS_STATUS_SUCCESS;
170 }
171 
SetPictureStructs()172 MOS_STATUS Mpeg2BasicFeature::SetPictureStructs()
173 {
174     DECODE_FUNC_CALL();
175 
176     m_secondField = m_mpeg2PicParams->m_secondField ? true : false;
177     m_pictureCodingType = (uint16_t)m_mpeg2PicParams->m_pictureCodingType;
178     m_curRenderPic = m_mpeg2PicParams->m_currPic;
179 
180     m_picWidthInMb  = CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_mpeg2PicParams->m_horizontalSize);
181     m_picHeightInMb = CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_mpeg2PicParams->m_verticalSize);
182 
183     // For some corrupted mpeg2 streams, need to use dwHeight and dwWidth because they are updated at decode
184     // creation time. Horizontal_size or vertical_size may be different and wrong in first picture parameter.
185     uint32_t totalMBInFrame = (m_curRenderPic.PicFlags == PICTURE_FRAME) ?
186         (CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_width) * CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_height)):
187         (CODECHAL_GET_WIDTH_IN_MACROBLOCKS(m_width) * CODECHAL_GET_HEIGHT_IN_MACROBLOCKS(m_height) / 2);
188 
189     if (m_numSlices > totalMBInFrame)
190     {
191         DECODE_ASSERTMESSAGE("Invalid slice number due to larger than MB number.");
192         return MOS_STATUS_INVALID_PARAMETER;
193     }
194 
195     m_refFrameIndexList.clear();
196     m_fwdRefIdx = (uint8_t)m_mpeg2PicParams->m_forwardRefIdx;
197     m_bwdRefIdx = (uint8_t)m_mpeg2PicParams->m_backwardRefIdx;
198     m_refFrameIndexList.push_back(m_fwdRefIdx);
199     m_refFrameIndexList.push_back(m_bwdRefIdx);
200 
201     DECODE_CHK_STATUS(m_refFrames.UpdatePicture(*m_mpeg2PicParams));
202 
203     return MOS_STATUS_SUCCESS;
204 }
205 
SetSliceStructs()206 MOS_STATUS Mpeg2BasicFeature::SetSliceStructs()
207 {
208     DECODE_FUNC_CALL();
209 
210     uint32_t numMBs              = 0;
211     uint32_t firstMbAddress      = 0;
212     bool     skippedSlicePresent = false;
213     bool     invalidFrame        = true;
214     uint16_t lastSlice           = 0;
215 
216     if (m_numSlices == 0)
217     {
218         DECODE_ASSERTMESSAGE("MPEG2 VLD slice data invalid, unable to determine final MB address.");
219         numMBs = 0;
220         return MOS_STATUS_INVALID_PARAMETER;
221     }
222 
223     DECODE_CHK_NULL(m_mpeg2SliceParams);
224     CodecDecodeMpeg2SliceParams *slc = m_mpeg2SliceParams;
225 
226     // For a incomplete picture, this indicates if it is the first
227     // vaild slice from second execution call.
228     bool firstValidSlice = m_incompletePicture ? true : false;
229 
230     uint16_t startSliceIdx = m_totalNumSlicesRecv;
231     m_totalNumSlicesRecv  += (uint16_t)m_numSlices;
232 
233     if (m_sliceRecord.size() < m_totalNumSlicesRecv)
234     {
235         m_sliceRecord.resize(m_totalNumSlicesRecv);
236     }
237 
238     uint32_t prevSliceMbEnd = m_lastSliceMbEnd;
239 
240     for (uint16_t slcIdx = startSliceIdx; slcIdx < m_totalNumSlicesRecv; slcIdx++)
241     {
242         uint32_t sliceStartMbOffset = slc->m_sliceHorizontalPosition +
243             (slc->m_sliceVerticalPosition * m_picWidthInMb);
244         uint32_t slcLength = ((slc->m_sliceDataSize + 0x0007) >> 3);
245 
246         // HW limitation and won't be fixed
247         if (slcLength > 0x1FFE0)
248         {
249             slcLength = 0x1FFE0;
250         }
251 
252         // #of bytes of header data in bitstream buffer (before video data)
253         uint32_t u32Offset = ((slc->m_macroblockOffset & 0x0000fff8) >> 3);
254 
255         slcLength                               -= u32Offset;
256         m_sliceRecord[slcIdx].length             = slcLength;
257         m_sliceRecord[slcIdx].offset             = u32Offset + m_copiedDataOffset;
258         m_sliceRecord[slcIdx].sliceStartMbOffset = sliceStartMbOffset;
259         m_sliceRecord[slcIdx].prevSliceMbEnd     = prevSliceMbEnd;
260         m_sliceRecord[slcIdx].recordSliceParam   = *slc;
261         m_sliceRecord[slcIdx].skip               = false;
262         m_sliceRecord[slcIdx].isLastSlice        = false;
263 
264         if (DetectSliceError(*slc, slcIdx, firstValidSlice))
265         {
266             m_sliceRecord[slcIdx].skip = true;
267             skippedSlicePresent = true;
268         }
269         else
270         {
271             if (firstValidSlice)
272             {
273                 // First MB Address
274                 firstMbAddress = slc->m_sliceHorizontalPosition + (slc->m_sliceVerticalPosition * m_picWidthInMb);
275             }
276 
277             lastSlice = slcIdx;
278             firstValidSlice = false;
279             invalidFrame = false;
280         }
281 
282         prevSliceMbEnd = m_sliceRecord[slcIdx].sliceStartMbOffset + slc->m_numMbsForSlice;
283 
284         if (slcIdx == m_totalNumSlicesRecv - 1)
285         {
286             m_lastSliceMbEnd = prevSliceMbEnd;
287         }
288 
289         slc++;
290     }
291 
292     slc -= m_numSlices;
293     m_sliceRecord[lastSlice].isLastSlice = true;
294 
295     // Last MB Address
296     slc += lastSlice;
297     numMBs = (uint16_t)(m_sliceRecord[lastSlice].sliceStartMbOffset + slc->m_numMbsForSlice);
298 
299     // It means all slices in the frame are wrong, we just need skip decoding
300     // for this frame and won't insert any dummy slices.
301     if (invalidFrame && m_numSlices && !m_incompletePicture)
302     {
303         DECODE_ASSERTMESSAGE("Current frame is invalid.");
304         return MOS_STATUS_UNKNOWN;
305     }
306 
307     // MPEG2 Error Concealment for VLD mode from Gen6+
308     m_copiedDataNeeded = m_incompletePicture ||
309         (numMBs != (m_picWidthInMb * m_picHeightInMb)) ||
310         (skippedSlicePresent || (firstMbAddress != 0));
311 
312     DECODE_CHK_STATUS(CheckCompletePicture(startSliceIdx));
313 
314     return MOS_STATUS_SUCCESS;
315 }
316 
CheckCompletePicture(uint16_t startSliceIdx)317 MOS_STATUS Mpeg2BasicFeature::CheckCompletePicture(uint16_t startSliceIdx)
318 {
319     DECODE_FUNC_CALL();
320 
321     CodecDecodeMpeg2SliceParams *slc = m_mpeg2SliceParams;
322     DECODE_CHK_NULL(slc)
323 
324     for (uint16_t slcIdx = startSliceIdx; slcIdx < m_totalNumSlicesRecv; slcIdx++)
325     {
326         if (!m_sliceRecord[slcIdx].skip && m_sliceRecord[slcIdx].isLastSlice)
327         {
328             uint16_t expectedFinalMb = m_picWidthInMb * m_picHeightInMb;
329             m_lastMbAddress = m_sliceRecord[slcIdx].sliceStartMbOffset + slc->m_numMbsForSlice;
330             if (m_lastMbAddress < expectedFinalMb)
331             {
332                 m_incompletePicture = true;
333                 m_sliceRecord[slcIdx].isLastSlice = false;
334             }
335             else
336             {
337                 m_incompletePicture = false;
338             }
339         }
340         slc++;
341     }
342 
343     return MOS_STATUS_SUCCESS;
344 }
345 
DetectSliceError(CodecDecodeMpeg2SliceParams & slc,uint32_t slcIdx,bool firstValidSlice)346 bool Mpeg2BasicFeature::DetectSliceError(CodecDecodeMpeg2SliceParams &slc,
347                                          uint32_t slcIdx,
348                                          bool firstValidSlice)
349 {
350     bool result  = false;
351 
352     VldSliceRecord currSliceRecord = m_sliceRecord[slcIdx];
353 
354     if (currSliceRecord.length == 0 || currSliceRecord.length > (uint32_t)(1 << (sizeof(uint32_t) * 8 - 1)))
355     {
356         result = true;
357     }
358     else if ((slc.m_sliceDataOffset + currSliceRecord.length) > m_dataSize)
359     {
360         // error handling for garbage data
361         result = true;
362     }
363     else if (m_slicesInvalid)
364     {
365         // If cp copy failed for this interation due to lack of buffer space, cannot use any
366         // slices in this iteration since there is no bitstream data for them
367         result = true;
368     }
369     else if (currSliceRecord.prevSliceMbEnd > currSliceRecord.sliceStartMbOffset ||
370             slc.m_sliceVerticalPosition >= m_picHeightInMb ||
371             slc.m_sliceHorizontalPosition >= m_picWidthInMb)
372     {
373         result = true;
374         m_slicesInvalid = true;
375     }
376     else if (!slc.m_numMbsForSlice)
377     {
378         // For SNB HW will not process BSD objects where the MbCount is 0, and if an invalid
379         // slice start position has been detected or the number of MBs in the current slice
380         // is invalid, the rest of the data may be garbage since SNB does not have robust
381         // error concealment for MPEG2 VLD, skipping these slices prevents HW going to hang
382         result = true;
383         m_slicesInvalid = true;
384     }
385     else if (slc.m_numMbsForSliceOverflow)
386     {
387         // Special case for last slice of an incomplete frame
388         if ((slcIdx == m_totalNumSlicesRecv - 1) && !firstValidSlice &&
389             ((currSliceRecord.sliceStartMbOffset + slc.m_numMbsForSlice) <
390             (uint32_t)(m_picHeightInMb * m_picWidthInMb)))
391         {
392             slc.m_numMbsForSlice = m_picWidthInMb;
393         }
394         else
395         {
396             result = true;
397             m_slicesInvalid = true;
398         }
399     }
400 
401     return result;
402 }
403 
SetMbStructs()404 MOS_STATUS Mpeg2BasicFeature::SetMbStructs()
405 {
406     DECODE_FUNC_CALL();
407 
408     DECODE_CHK_NULL(m_mpeg2MbParams);
409     CodecDecodeMpeg2MbParams *mb = m_mpeg2MbParams;
410 
411     //MPEG2 Error Concealment for IT mode from Gen6+
412     m_copiedDataNeeded = (m_incompletePicture || (m_numMacroblocks != (m_picWidthInMb * m_picHeightInMb)));
413 
414     uint32_t startMbIdx = m_totalNumMbsRecv;
415     m_totalNumMbsRecv += m_numMacroblocks;
416 
417     if (m_mbRecord.size() < m_totalNumMbsRecv)
418     {
419         m_mbRecord.resize(m_totalNumMbsRecv);
420     }
421 
422     uint16_t expectedMBAddress = (m_incompletePicture) ? m_lastMbAddress : 0;
423 
424     for (uint32_t mbIdx = startMbIdx; mbIdx < m_totalNumMbsRecv; mbIdx++)
425     {
426         uint16_t skippedMBs = 0;
427 
428         if (mb[mbIdx].m_mbAddr >= expectedMBAddress)
429         {
430              uint16_t skippedMBs = mb[mbIdx].m_mbAddr - expectedMBAddress;
431         }
432 
433         m_mbRecord[mbIdx].recordMbParam  = mb[mbIdx];
434         m_mbRecord[mbIdx].skippedMBs     = skippedMBs;
435         m_mbRecord[mbIdx].expectedMBAddr = expectedMBAddress;
436 
437         expectedMBAddress = mb[mbIdx].m_mbAddr + 1;
438 
439         if (m_pictureCodingType != I_TYPE && mb[mbIdx].m_mbSkipFollowing)
440         {
441             uint16_t skippedMBs = mb[mbIdx].m_mbSkipFollowing;
442             expectedMBAddress += skippedMBs;
443         }
444 
445         // insert extra MBs to ensure expected number of MBs sent to HW
446         if (mbIdx + 1 == m_numMacroblocks)
447         {
448             uint16_t expectedFinalMB = m_picWidthInMb * m_picHeightInMb;
449             if (expectedMBAddress != expectedFinalMB)
450             {
451                 m_incompletePicture = true;
452                 m_lastMbAddress     = expectedMBAddress;
453             }
454             else
455             {
456                 m_incompletePicture = false;
457             }
458         }
459     }
460 
461     return MOS_STATUS_SUCCESS;
462 }
463 
464 }
465