1 /*
2 * Copyright (c) 2019, 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     decode_hevc_reference_frames.cpp
24 //! \brief    Defines reference list related logic for hevc decode
25 //!
26 
27 #include "decode_hevc_basic_feature.h"
28 #include "decode_utils.h"
29 #include "codec_utilities_next.h"
30 #include "decode_hevc_reference_frames.h"
31 #include "codec_def_decode_hevc.h"
32 
33 namespace decode
34 {
35 
HevcReferenceFrames()36 HevcReferenceFrames::HevcReferenceFrames()
37 {
38     memset(m_refList, 0, sizeof(m_refList));
39 }
40 
Init(HevcBasicFeature * basicFeature,DecodeAllocator & allocator)41 MOS_STATUS HevcReferenceFrames::Init(HevcBasicFeature *basicFeature, DecodeAllocator& allocator)
42 {
43     DECODE_FUNC_CALL();
44     DECODE_CHK_NULL(basicFeature);
45 
46     m_basicFeature = basicFeature;
47     m_allocator = &allocator;
48     DECODE_CHK_STATUS(CodecUtilities::CodecHalAllocateDataList(m_refList, CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC));
49 
50     m_osInterface = basicFeature->GetOsInterface();
51 
52     return MOS_STATUS_SUCCESS;
53 }
54 
~HevcReferenceFrames()55 HevcReferenceFrames::~HevcReferenceFrames()
56 {
57     DECODE_FUNC_CALL();
58     CodecUtilities::CodecHalFreeDataList(m_refList, CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC);
59     m_activeReferenceList.clear();
60 }
61 
UpdatePicture(CODEC_HEVC_PIC_PARAMS & picParams,bool isSCCIBCMode)62 MOS_STATUS HevcReferenceFrames::UpdatePicture(CODEC_HEVC_PIC_PARAMS & picParams, bool isSCCIBCMode)
63 {
64     DECODE_FUNC_CALL();
65 
66     DECODE_CHK_STATUS(DetectPocDuplication(picParams.PicOrderCntValList, picParams.RefFrameList));
67     DECODE_CHK_STATUS(UpdateCurFrame(picParams, isSCCIBCMode));
68     DECODE_CHK_STATUS(UpdateCurRefList(picParams, isSCCIBCMode));
69     DECODE_CHK_STATUS(UpdateRefIdxMapping(picParams, isSCCIBCMode));
70     DECODE_CHK_STATUS(UpdateRefCachePolicy(picParams));
71 
72     return MOS_STATUS_SUCCESS;
73 }
74 
GetActiveReferenceList(const CODEC_HEVC_PIC_PARAMS & picParams)75 const std::vector<uint8_t> & HevcReferenceFrames::GetActiveReferenceList(const CODEC_HEVC_PIC_PARAMS & picParams)
76 {
77     DECODE_FUNC_CALL();
78 
79     m_activeReferenceList.clear();
80 
81     for (auto i = 0; i < CODEC_MAX_NUM_REF_FRAME_HEVC; i++)
82     {
83         if (m_frameUsedAsCurRef[i])
84         {
85             m_activeReferenceList.push_back(picParams.RefFrameList[i].FrameIdx);
86         }
87     }
88 
89     return m_activeReferenceList;
90 }
91 
GetReferenceByFrameIndex(uint8_t frameIndex)92 PMOS_RESOURCE HevcReferenceFrames::GetReferenceByFrameIndex(uint8_t frameIndex)
93 {
94     DECODE_FUNC_CALL();
95 
96     if (frameIndex >= CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC)
97     {
98         DECODE_ASSERTMESSAGE("Invalid reference frame index");
99         return nullptr;
100     }
101 
102     PCODEC_REF_LIST ref = m_refList[frameIndex];
103 
104     if (ref == nullptr || m_allocator->ResourceIsNull(&(ref->resRefPic)))
105     {
106         return nullptr;
107     }
108 
109     return &(ref->resRefPic);
110 }
111 
GetValidReference()112 PMOS_RESOURCE HevcReferenceFrames::GetValidReference()
113 {
114     DECODE_FUNC_CALL();
115 
116     if (m_basicFeature->m_hevcPicParams == nullptr)
117     {
118         return nullptr;
119     }
120     auto picParams = m_basicFeature->m_hevcPicParams;
121 
122     for(uint32_t i = 0; i < CODEC_MAX_NUM_REF_FRAME_HEVC; i++)
123     {
124         uint8_t frameIdx = picParams->RefFrameList[i].FrameIdx;
125         if (frameIdx >= m_basicFeature->m_maxFrameIndex)
126         {
127             continue;
128         }
129 
130         PMOS_RESOURCE buffer = GetReferenceByFrameIndex(frameIdx);
131         if (buffer != nullptr)
132         {
133             return buffer;
134         }
135     }
136 
137     return &(m_basicFeature->m_destSurface.OsResource);
138 }
139 
UpdateCurResource(const CODEC_HEVC_PIC_PARAMS & picParams,bool isSCCIBCMode)140 MOS_STATUS HevcReferenceFrames::UpdateCurResource(const CODEC_HEVC_PIC_PARAMS &picParams, bool isSCCIBCMode)
141 {
142     DECODE_FUNC_CALL();
143 
144     PCODEC_REF_LIST destEntry = m_refList[picParams.CurrPic.FrameIdx];
145 
146     if (isSCCIBCMode)
147     {
148         bool twoVersionsOfCurrDecPicFlag = (!picParams.pps_deblocking_filter_disabled_flag) ||
149                                            picParams.sample_adaptive_offset_enabled_flag ||
150                                            picParams.deblocking_filter_override_enabled_flag;
151 #ifdef _MMC_SUPPORTED
152         // Due to limitation, IBC reference has to be uncompressed, while recon surface is still compressed.
153         // Always need internal surface for IBC reference while MMC is enabled.
154         if (m_basicFeature->IsMmcEnabled())
155         {
156             twoVersionsOfCurrDecPicFlag = true;
157         }
158 #endif
159         if (twoVersionsOfCurrDecPicFlag)
160         {
161             // In downsampling case, m_referenceBeforeLoopFilter will be allocated by downsampling feature later.
162             if(m_basicFeature->m_referenceBeforeLoopFilter != nullptr)
163             {
164                 destEntry->resRefPic = m_basicFeature->m_referenceBeforeLoopFilter->OsResource;
165             }
166         }
167         else
168         {
169             destEntry->resRefPic = m_basicFeature->m_destSurface.OsResource;
170         }
171     }
172     else
173     {
174         destEntry->resRefPic = m_basicFeature->m_destSurface.OsResource;
175     }
176 
177     return MOS_STATUS_SUCCESS;
178 }
179 
UpdateCurFrame(const CODEC_HEVC_PIC_PARAMS & picParams,bool isSCCIBCMode)180 MOS_STATUS HevcReferenceFrames::UpdateCurFrame(const CODEC_HEVC_PIC_PARAMS & picParams, bool isSCCIBCMode)
181 {
182     DECODE_FUNC_CALL();
183 
184     DECODE_CHK_COND(picParams.CurrPic.FrameIdx >= CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC,
185                     "Invalid frame index of current frame");
186     PCODEC_REF_LIST destEntry = m_refList[picParams.CurrPic.FrameIdx];
187     MOS_ZeroMemory(destEntry, sizeof(CODEC_REF_LIST));
188 
189     DECODE_CHK_STATUS(UpdateCurResource(picParams, isSCCIBCMode));
190 
191     if (isSCCIBCMode)
192     {
193         m_curIsIntra = false;
194     }
195     else
196     {
197         m_curIsIntra = !IsCurFrameUseReference(picParams);
198     }
199 
200     destEntry->RefPic            = picParams.CurrPic;
201     destEntry->sFrameNumber      = int16_t(picParams.CurrPicOrderCntVal);
202     destEntry->iFieldOrderCnt[0] = picParams.CurrPicOrderCntVal;
203     destEntry->bIsIntra          = m_curIsIntra;
204 
205     for(auto i = 0; i < CODEC_MAX_NUM_REF_FRAME_HEVC; i++)
206     {
207         destEntry->RefList[i] = picParams.RefFrameList[i];
208     }
209 
210     return MOS_STATUS_SUCCESS;
211 }
212 
UpdateCurRefList(const CODEC_HEVC_PIC_PARAMS & picParams,bool isSCCIBCMode)213 MOS_STATUS HevcReferenceFrames::UpdateCurRefList(const CODEC_HEVC_PIC_PARAMS & picParams, bool isSCCIBCMode)
214 {
215     DECODE_FUNC_CALL();
216 
217     // Override reference list with ref surface passed from DDI if needed
218     uint8_t surfCount = 0;
219     uint8_t surfIndex = 0;
220     if (m_osInterface->pfnIsMismatchOrderProgrammingSupported())
221     {
222         while (surfIndex < CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC)
223         {
224             if (!m_allocator->ResourceIsNull(&m_basicFeature->m_refFrameSurface[surfIndex].OsResource))
225             {
226                 m_refList[surfIndex]->resRefPic = m_basicFeature->m_refFrameSurface[surfIndex].OsResource;
227             }
228             surfIndex++;
229         }
230     }
231     else
232     {
233         while (surfCount < m_basicFeature->m_refSurfaceNum && surfIndex < CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC)
234         {
235             if (!m_allocator->ResourceIsNull(&m_basicFeature->m_refFrameSurface[surfIndex].OsResource))
236             {
237                 m_refList[surfIndex]->resRefPic = m_basicFeature->m_refFrameSurface[surfIndex].OsResource;
238                 surfCount++;
239             }
240             surfIndex++;
241         }
242     }
243 
244     memset(m_frameUsedAsCurRef, 0, sizeof(m_frameUsedAsCurRef));
245 
246     for (auto i = 0; i < CODECHAL_MAX_CUR_NUM_REF_FRAME_HEVC; i++)
247     {
248         uint8_t index = picParams.RefPicSetStCurrBefore[i];
249         if (index < CODEC_MAX_NUM_REF_FRAME_HEVC)
250         {
251             m_frameUsedAsCurRef[index] = true;
252         }
253 
254         index = picParams.RefPicSetStCurrAfter[i];
255         if (index < CODEC_MAX_NUM_REF_FRAME_HEVC)
256         {
257             m_frameUsedAsCurRef[index] = true;
258         }
259 
260         index = picParams.RefPicSetLtCurr[i];
261         if (index < CODEC_MAX_NUM_REF_FRAME_HEVC)
262         {
263             m_frameUsedAsCurRef[index] = true;
264         }
265     }
266 
267     if (isSCCIBCMode)
268     {
269         for (auto i = 0; i < CODEC_MAX_NUM_REF_FRAME_HEVC; i++)
270         {
271             if (picParams.PicOrderCntValList[i] == picParams.CurrPicOrderCntVal)
272             {
273                 m_frameUsedAsCurRef[i] = !CodecHal_PictureIsInvalid(picParams.RefFrameList[i]);
274                 break;
275             }
276         }
277     }
278     else
279     {
280         uint8_t refCurrIndex   = -1;
281         uint8_t refBeforeIndex = -1;
282         uint8_t refAfterIndex  = -1;
283 
284         for (auto i = 0; i < CODECHAL_MAX_CUR_NUM_REF_FRAME_HEVC; i++)
285         {
286             uint8_t indexCurr   = picParams.RefPicSetLtCurr[i];
287             uint8_t indexBefore = picParams.RefPicSetStCurrBefore[i];
288             uint8_t indexAfter  = picParams.RefPicSetStCurrAfter[i];
289 
290             if (indexCurr < CODEC_MAX_NUM_REF_FRAME_HEVC)
291             {
292                 refCurrIndex = picParams.RefFrameList[indexCurr].FrameIdx;
293             }
294             if (indexBefore < CODEC_MAX_NUM_REF_FRAME_HEVC)
295             {
296                 refBeforeIndex = picParams.RefFrameList[indexBefore].FrameIdx;
297             }
298             if (indexAfter < CODEC_MAX_NUM_REF_FRAME_HEVC)
299             {
300                 refAfterIndex = picParams.RefFrameList[indexAfter].FrameIdx;
301             }
302 
303             if ((refCurrIndex == picParams.CurrPic.FrameIdx) || (refBeforeIndex == picParams.CurrPic.FrameIdx) || (refAfterIndex == picParams.CurrPic.FrameIdx))
304             {
305                 return MOS_STATUS_INVALID_PARAMETER;
306             }
307         }
308     }
309 
310     return MOS_STATUS_SUCCESS;
311 }
312 
UpdateRefIdxMapping(const CODEC_HEVC_PIC_PARAMS & picParams,bool isSCCIBCMode)313 MOS_STATUS HevcReferenceFrames::UpdateRefIdxMapping(const CODEC_HEVC_PIC_PARAMS & picParams, bool isSCCIBCMode)
314 {
315     DECODE_FUNC_CALL();
316 
317     memset(m_refIdxMapping, -1, sizeof(m_refIdxMapping));
318     m_IBCRefIdx = 0;
319 
320     uint8_t curRefIdx = 0;
321     for (auto i = 0; i < CODEC_MAX_NUM_REF_FRAME_HEVC; i++)
322     {
323         if (m_frameUsedAsCurRef[i])
324         {
325             if (isSCCIBCMode &&
326                 picParams.PicOrderCntValList[i] == picParams.CurrPicOrderCntVal)
327             {
328                 // pre-dbk reference id for IBC mode
329                 m_IBCRefIdx = curRefIdx;
330             }
331             m_refIdxMapping[i] = curRefIdx++;
332         }
333     }
334 
335     DECODE_CHK_COND(curRefIdx > 8, "Invalid reference number for current frame");
336 
337     return MOS_STATUS_SUCCESS;
338 }
339 
UpdateRefCachePolicy(const CODEC_HEVC_PIC_PARAMS & picParams)340 MOS_STATUS HevcReferenceFrames::UpdateRefCachePolicy(const CODEC_HEVC_PIC_PARAMS &picParams)
341 {
342     DECODE_FUNC_CALL();
343     MOS_STATUS sts = MOS_STATUS_SUCCESS;
344 
345     HevcReferenceFrames        &refFrames     = m_basicFeature->m_refFrames;
346     const std::vector<uint8_t> &activeRefList = refFrames.GetActiveReferenceList(picParams);
347     if (!refFrames.m_curIsIntra)
348     {
349         for (uint8_t i = 0; i < activeRefList.size(); i++)
350         {
351             uint8_t frameIdx = activeRefList[i];
352             if (frameIdx >= CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC)
353             {
354                 continue;
355             }
356             sts = m_allocator->UpdateResoreceUsageType(&m_refList[frameIdx]->resRefPic, resourceInputReference);
357             if (sts != MOS_STATUS_SUCCESS)
358             {
359                 DECODE_NORMALMESSAGE("GetReferenceByFrameIndex invalid\n");
360             }
361         }
362     }
363 
364     return MOS_STATUS_SUCCESS;
365 }
366 
IsCurFrameUseReference(const CODEC_HEVC_PIC_PARAMS & picParams)367 bool HevcReferenceFrames::IsCurFrameUseReference(const CODEC_HEVC_PIC_PARAMS & picParams)
368 {
369     DECODE_FUNC_CALL();
370 
371     bool useRef = false;
372     if (picParams.IntraPicFlag == 0)
373     {
374         for (uint32_t i = 0; i < CODECHAL_MAX_CUR_NUM_REF_FRAME_HEVC; i++)
375         {
376             uint8_t index = picParams.RefPicSetStCurrBefore[i];
377             if (index < CODEC_MAX_NUM_REF_FRAME_HEVC)
378             {
379                 useRef = true;
380                 break;
381             }
382 
383             index = picParams.RefPicSetStCurrAfter[i];
384             if (index < CODEC_MAX_NUM_REF_FRAME_HEVC)
385             {
386                 useRef = true;
387                 break;
388             }
389 
390             index = picParams.RefPicSetLtCurr[i];
391             if (index < CODEC_MAX_NUM_REF_FRAME_HEVC)
392             {
393                 useRef = true;
394                 break;
395             }
396         }
397     }
398 
399     return useRef;
400 }
401 
DetectPocDuplication(const int32_t (& picOrderCntValList)[CODEC_MAX_NUM_REF_FRAME_HEVC],CODEC_PICTURE (& refFrameList)[CODEC_MAX_NUM_REF_FRAME_HEVC])402 MOS_STATUS HevcReferenceFrames::DetectPocDuplication(const int32_t (&picOrderCntValList)[CODEC_MAX_NUM_REF_FRAME_HEVC],
403                                                      CODEC_PICTURE (&refFrameList)[CODEC_MAX_NUM_REF_FRAME_HEVC])
404 {
405     DECODE_FUNC_CALL();
406 
407     for (auto i = 0; i < CODEC_MAX_NUM_REF_FRAME_HEVC; i++)
408     {
409         m_duplicationPocMap[i].clear();
410     }
411 
412     bool pocListFilter[CODEC_MAX_NUM_REF_FRAME_HEVC]; // Marker to indicate if poc already be filtered
413     memset(pocListFilter, 0, sizeof(pocListFilter));
414 
415     for (int8_t m = 0; m < CODEC_MAX_NUM_REF_FRAME_HEVC; m++)
416     {
417         if (pocListFilter[m] || (picOrderCntValList[m] == m_invalidPocValue))
418         {
419             continue;
420         }
421         pocListFilter[m] = true;
422 
423         for (int8_t n = m + 1; n < CODEC_MAX_NUM_REF_FRAME_HEVC; n++)
424         {
425             if (picOrderCntValList[m] == picOrderCntValList[n])
426             {
427                 pocListFilter[n] = true;
428                 m_duplicationPocMap[m].push_back(n);
429 
430                 refFrameList[n].PicFlags = PICTURE_INVALID;
431             }
432         }
433     }
434 
435     return MOS_STATUS_SUCCESS;
436 }
437 
FixSliceRefList(const CODEC_HEVC_PIC_PARAMS & picParams,CODEC_HEVC_SLICE_PARAMS & slc)438 MOS_STATUS HevcReferenceFrames::FixSliceRefList(const CODEC_HEVC_PIC_PARAMS & picParams,
439                                                 CODEC_HEVC_SLICE_PARAMS & slc)
440 {
441     DECODE_FUNC_CALL();
442 
443     for (auto i = 0; i < CODEC_MAX_NUM_REF_FRAME_HEVC; i++)
444     {
445         if (m_duplicationPocMap[i].size() == 0)
446         {
447             continue;
448         }
449 
450         for (auto dupIdx : m_duplicationPocMap[i])
451         {
452             for (auto k = 0; k < 2; k++)
453             {
454                 for (auto j = 0; j < CODEC_MAX_NUM_REF_FRAME_HEVC; j++)
455                 {
456                     if (slc.RefPicList[k][j].FrameIdx == picParams.RefFrameList[dupIdx].FrameIdx)
457                     {
458                         slc.RefPicList[k][j].FrameIdx = picParams.RefFrameList[i].FrameIdx;
459                         slc.RefPicList[k][j].PicEntry = picParams.RefFrameList[i].PicEntry;
460                         slc.RefPicList[k][j].PicFlags = picParams.RefFrameList[i].PicFlags;
461                     }
462                 }
463             }
464         }
465     }
466 
467     return MOS_STATUS_SUCCESS;
468 }
469 
470 }  // namespace decode
471