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