1 /*
2 * Copyright (c) 2019-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 //! \file     decode_reference_associated_buffer.h
24 //! \brief    Defines the interface for reference associated buffer
25 //! \details  Each reference has associated buffers for most of the codecs,
26 //!           this file implements the basic management for such buffers.
27 //!
28 
29 #ifndef __DECODE_REFRENCE_ASSOCIATED_BUFFER_H__
30 #define __DECODE_REFRENCE_ASSOCIATED_BUFFER_H__
31 
32 #include "decode_allocator.h"
33 #include "decode_utils.h"
34 #include "codec_hw_next.h"
35 
36 namespace decode {
37 
38 template<typename BufferType, typename BasicFeature>
39 class BufferOpInf
40 {
41 public:
~BufferOpInf()42     virtual ~BufferOpInf() {}
Init(void * hwInterface,DecodeAllocator & allocator,BasicFeature & basicFeature)43     virtual MOS_STATUS Init(void *hwInterface, DecodeAllocator &allocator, BasicFeature &basicFeature)
44     {
45         m_hwInterface  = hwInterface;
46         m_allocator    = &allocator;
47         m_basicFeature = &basicFeature;
48         return MOS_STATUS_SUCCESS;
49     }
50 
51     virtual BufferType *Allocate() = 0;
52     virtual MOS_STATUS Resize(BufferType* &buffer) = 0;
Deactive(BufferType * & buffer)53     virtual MOS_STATUS Deactive(BufferType* &buffer) { return MOS_STATUS_SUCCESS; }
IsAvailable(BufferType * & buffer)54     virtual bool IsAvailable(BufferType* &buffer) { return true; }
55     virtual void Destroy(BufferType* &buffer) = 0;
56 
57     void*                m_hwInterface  = nullptr;
58     DecodeAllocator*     m_allocator    = nullptr;
59     BasicFeature*        m_basicFeature = nullptr;
60 
61 MEDIA_CLASS_DEFINE_END(decode__BufferOpInf)
62 };
63 
64 template<typename BufferType, typename BufferOp, typename BasicFeature>
65 class RefrenceAssociatedBuffer
66 {
67 public:
68     //!
69     //! \brief  RefrenceAssociatedBuffer constructor
70     //!
RefrenceAssociatedBuffer()71     RefrenceAssociatedBuffer()
72     {};
73 
74     //!
75     //! \brief  RefrenceAssociatedBuffer deconstructor
76     //!
~RefrenceAssociatedBuffer()77     virtual ~RefrenceAssociatedBuffer()
78     {
79         DECODE_FUNC_CALL();
80 
81         for (auto& buf : m_activeBuffers)
82         {
83             m_bufferOp.Destroy(buf.second);
84         }
85         m_activeBuffers.clear();
86 
87         for (auto& buf : m_availableBuffers)
88         {
89             m_bufferOp.Destroy(buf);
90         }
91         m_availableBuffers.clear();
92     }
93 
94     //!
95     //! \brief  Initialize buffers
96     //! \param  [in] hwInterface
97     //!         Point to hardware interface
98     //! \param  [in] allocator
99     //!         Reference to decode allocator
100     //! \param  [in] basicFeature
101     //!         Basic feature
102     //! \param  [in] initialAllocNum
103     //!         The number of buffers allocated when initialize
104     //! \return  MOS_STATUS
105     //!         MOS_STATUS_SUCCESS if success, else fail reason
106     //!
Init(void * hwInterface,DecodeAllocator & allocator,BasicFeature & basicFeature,uint32_t initialAllocNum)107     MOS_STATUS Init(void* hwInterface, DecodeAllocator& allocator, BasicFeature& basicFeature,
108                     uint32_t initialAllocNum)
109     {
110         DECODE_FUNC_CALL();
111 
112         DECODE_CHK_STATUS(m_bufferOp.Init(hwInterface, allocator, basicFeature));
113 
114         DECODE_ASSERT(m_availableBuffers.empty());
115         DECODE_ASSERT(m_activeBuffers.empty());
116 
117         for (uint32_t i = 0; i < initialAllocNum; i++)
118         {
119             BufferType *buffer = m_bufferOp.Allocate();
120             DECODE_CHK_NULL(buffer);
121             m_availableBuffers.push_back(buffer);
122         }
123 
124         return MOS_STATUS_SUCCESS;
125     }
126 
127     //!
128     //! \brief  Update buffers for current picture
129     //! \param  [in] frameIdx
130     //!         The frame index for current picture
131     //! \param  [in] refFrameList
132     //!         The frame indicies of reference frame list
133     //! \param  [in] fixedFrameIdx
134     //!         The frameIdx user wants to keep into the refFrameList
135     //!         Default value is 0xff
136     //! \return  MOS_STATUS
137     //!         MOS_STATUS_SUCCESS if success, else fail reason
138     //!
139     MOS_STATUS UpdatePicture(uint32_t curFrameIdx, const std::vector<uint32_t> &refFrameList, uint32_t fixedFrameIdx = 0xff)
140     {
141         DECODE_FUNC_CALL();
142 
143         DECODE_CHK_STATUS(UpdateRefList(curFrameIdx, refFrameList, fixedFrameIdx));
144         DECODE_CHK_STATUS(ActiveCurBuffer(curFrameIdx));
145 
146         return MOS_STATUS_SUCCESS;
147     }
148 
149     //!
150     //! \brief  Return buffer for current frame
151     //! \return  BufferType*
152     //!         Point to buffer for current frame, nullptr if fail
153     //!
GetCurBuffer()154     BufferType* GetCurBuffer() { return m_currentBuffer; }
155 
156     //!
157     //! \brief  Return valid buffer for reference error concealment
158     //! \param  [in] refFrameList
159     //!         The frame indicies of reference frame list
160     //! \return  BufferType*
161     //!         Point of valid buffer, nullptr if fail
162     //!
GetValidBufferForReference(const std::vector<uint32_t> & refFrameList)163     BufferType* GetValidBufferForReference(const std::vector<uint32_t> &refFrameList)
164     {
165         DECODE_FUNC_CALL();
166 
167         for(auto frameIdx : refFrameList)
168         {
169             BufferType* buffer = GetBufferByFrameIndex(frameIdx);
170             if (buffer != nullptr)
171             {
172                 return buffer;
173             }
174         }
175 
176         return GetCurBuffer();
177     }
178 
179     //!
180     //! \brief  Return buffer by frame index
181     //! \param  [in] frameIdx
182     //!         The frame index for current picture
183     //! \return  BufferType*
184     //!         Point of buffer, nullptr if fail
185     //!
GetBufferByFrameIndex(uint32_t frameIndex)186     BufferType* GetBufferByFrameIndex(uint32_t frameIndex)
187     {
188         DECODE_FUNC_CALL();
189 
190         auto iter = m_activeBuffers.find(frameIndex);
191         if (iter != m_activeBuffers.end())
192         {
193             DECODE_ASSERT(iter->second != nullptr);
194             return iter->second;
195         }
196 
197         return nullptr;
198     }
199 
200     //!
201     //! \brief  Return one available buffer
202     //! \return BufferType*
203     //!         Point of buffer, nullptr if fail
204     //!
GetAvailableBuffer()205     BufferType *GetAvailableBuffer()
206     {
207         DECODE_FUNC_CALL();
208 
209         BufferType *buffer = nullptr;
210         for (auto &availableBuffer : m_availableBuffers)
211         {
212             if (m_bufferOp.IsAvailable(availableBuffer))
213             {
214                 buffer = availableBuffer;
215             }
216         }
217 
218         if (buffer == nullptr)
219         {
220             buffer = m_bufferOp.Allocate();
221             if (buffer != nullptr)
222             {
223                 m_availableBuffers.push_back(buffer);
224             }
225         }
226 
227         return buffer;
228     }
229 
230     //!
231     //! \brief  Figure out buffer for current picture, and add it to active buffer list
232     //! \param  [in] frameIdx
233     //!         The frame index for current picture
234     //! \return  MOS_STATUS
235     //!         MOS_STATUS_SUCCESS if success, else fail reason
236     //!
ActiveCurBuffer(uint32_t curFrameIdx)237     MOS_STATUS ActiveCurBuffer(uint32_t curFrameIdx)
238     {
239         DECODE_FUNC_CALL();
240 
241         m_currentBuffer = nullptr;
242 
243         for (auto iter = m_activeBuffers.begin(); iter != m_activeBuffers.end(); iter++)
244         {
245             if (curFrameIdx == iter->first)
246             {
247                 m_currentBuffer = iter->second;
248                 return MOS_STATUS_SUCCESS;
249             }
250         }
251 
252         // The function UpdateRefList always attach the retired buffers to end of
253         // available buffer list, reusing those buffers could improve the health with
254         // error stream, so pick up the last element of list for current frame as possible.
255         for (auto iter = m_availableBuffers.rbegin(); iter != m_availableBuffers.rend(); iter++)
256         {
257             if (m_bufferOp.IsAvailable(*iter))
258             {
259                 m_currentBuffer = *iter;
260                 m_availableBuffers.erase((++iter).base());
261                 break;
262             }
263         }
264 
265         if (m_currentBuffer == nullptr)
266         {
267             m_currentBuffer = m_bufferOp.Allocate();
268             DECODE_CHK_NULL(m_currentBuffer);
269         }
270         m_bufferOp.Resize(m_currentBuffer);
271 
272         auto ret = m_activeBuffers.insert(std::make_pair(curFrameIdx, m_currentBuffer));
273         DECODE_CHK_COND(ret.second == false,
274             "Failed to acitve reference associated buffer with index %d, maybe it is already existed",
275             ret.first->first);
276 
277         return MOS_STATUS_SUCCESS;
278     }
279 
280 protected:
281     //!
282     //! \brief  Update buffers corresponding to reference list
283     //! \param  [in] curFrameIdx
284     //!         The frame index for current picture
285     //! \param  [in] refFrameList
286     //!         The frame indicies of reference frame list
287     //! \param  [in] fixedFrameIdx
288     //!         The frameIdx user wants to keep into the refFrameList
289     //! \return  MOS_STATUS
290     //!         MOS_STATUS_SUCCESS if success, else fail reason
291     //!
UpdateRefList(uint32_t curFrameIdx,const std::vector<uint32_t> & refFrameList,uint32_t fixedFrameIdx)292     MOS_STATUS UpdateRefList(uint32_t curFrameIdx, const std::vector<uint32_t> &refFrameList, uint32_t fixedFrameIdx)
293     {
294         DECODE_FUNC_CALL();
295 
296         auto iter = m_activeBuffers.begin();
297         while (iter != m_activeBuffers.end())
298         {
299             if (iter->first == fixedFrameIdx)
300             {
301                 ++iter;
302                 continue;
303             }
304 
305             if (!IsReference(iter->first, curFrameIdx, refFrameList))
306             {
307                 auto buffer = iter->second;
308                 iter = m_activeBuffers.erase(iter);
309 
310                 m_availableBuffers.push_back(buffer);
311                 DECODE_CHK_STATUS(m_bufferOp.Deactive(buffer));
312             }
313             else
314             {
315                 ++iter;
316             }
317         }
318 
319         return MOS_STATUS_SUCCESS;
320     }
321 
322     //!
323     //! \brief  Check if the index of buffer is persent in current reference list
324     //! \param  [in] frameIndex
325     //!         The frame index corresponding to buffer
326     //! \param  [in] frameIdx
327     //!         The frame index for current picture
328     //! \param  [in] refFrameList
329     //!         The frame indicies of reference frame list
330     //! \return  bool
331     //!         True if buffer is using by current frame, false if not
332     //!
IsReference(uint32_t frameIdx,uint32_t curFrameIdx,const std::vector<uint32_t> & refFrameList)333     bool IsReference(uint32_t frameIdx, uint32_t curFrameIdx, const std::vector<uint32_t> &refFrameList)
334     {
335         DECODE_FUNC_CALL();
336 
337         if (frameIdx == curFrameIdx)
338         {
339             return false;
340         }
341 
342         for(auto iter : refFrameList)
343         {
344             if (frameIdx == iter)
345             {
346                 return true;
347             }
348         }
349 
350         return false;
351     }
352 
353     BufferOp                        m_bufferOp;                //!< Buffer operation
354     std::map<uint32_t, BufferType*> m_activeBuffers;           //!< Active buffers corresponding to current reference frame list
355     std::vector<BufferType*>        m_availableBuffers;        //!< Buffers in idle
356     BufferType*                     m_currentBuffer = nullptr; //!< Point to buffer of current picture
357 
358 MEDIA_CLASS_DEFINE_END(decode__RefrenceAssociatedBuffer)
359 };
360 
361 }
362 #endif // !__DECODE_REFRENCE_ASSOCIATED_BUFFER_H__
363