1 // Copyright (c) 2019 Intel Corporation
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in all
11 // copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 
21 #pragma once
22 
23 #include "mfx_common.h"
24 
25 #include "mfxvideo.h"
26 #include <memory>
27 #include <map>
28 #include <list>
29 #include <exception>
30 #include <functional>
31 #include <algorithm>
32 #include <assert.h>
33 
34 namespace MfxFeatureBlocks
35 {
36 
37 struct Storable
38 {
~StorableStorable39     virtual ~Storable() {}
40 };
41 
42 template<class T>
43 class StorableRef
44     : public Storable
45     , public std::reference_wrapper<T>
46 {
47 public:
StorableRef(T & ref)48     StorableRef(T& ref)
49         : std::reference_wrapper<T>(ref)
50     {}
51 };
52 
53 template<class T>
54 class MakeStorable
55     : public T
56     , public StorableRef<T>
57 {
58 public:
59     template<class... TArg>
MakeStorable(TArg &&...arg)60     MakeStorable(TArg&& ...arg)
61         : T(std::forward<TArg>(arg)...)
62         , StorableRef<T>((T&)*this)
63     {}
64 };
65 
66 template<class T>
67 class MakeStorablePtr
68     : public std::unique_ptr<T>
69     , public StorableRef<T>
70 {
71 public:
72     using std::unique_ptr<T>::get;
73 
MakeStorablePtr(T * p)74     MakeStorablePtr(T* p)
75         : std::unique_ptr<T>(p)
76         , StorableRef<T>((T&)*get())
77     {}
78 };
79 
80 template<typename T, typename... Args>
make_unique(Args &&...args)81 std::unique_ptr<T> make_unique(Args&&... args)
82 {
83     return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
84 }
85 
86 template<typename T, typename... Args>
87 std::unique_ptr<typename std::conditional<std::is_base_of<Storable, T>::value, T, MakeStorable<T>>::type>
make_storable(Args &&...args)88     make_storable(Args&&... args)
89 {
90     return make_unique<typename std::conditional<std::is_base_of<Storable, T>::value, T, MakeStorable<T>>::type>
91         (std::forward<Args>(args)...);
92 }
93 
94 class StorageR
95 {
96 public:
97     typedef mfxU32 TKey;
98     static const TKey KEY_INVALID = TKey(-1);
99 
100     template<class T>
Read(TKey key)101     const T& Read(TKey key) const
102     {
103         auto it = m_map.find(key);
104         if (it == m_map.end())
105             throw std::logic_error("Requested object was not found in storage");
106         return dynamic_cast<T&>(*it->second);
107     }
108 
Contains(TKey key)109     bool Contains(TKey key) const
110     {
111         return (m_map.find(key) != m_map.end());
112     }
113 
Empty()114     bool Empty() const
115     {
116         return m_map.empty();
117     }
118 
119 protected:
120     std::map<TKey, std::unique_ptr<Storable>> m_map;
121 };
122 
123 class StorageW : public StorageR
124 {
125 public:
126     template<class T>
Write(TKey key)127     T& Write(TKey key) const
128     {
129         auto it = m_map.find(key);
130         if (it == m_map.end())
131             throw std::logic_error("Requested object was not found in storage");
132         return dynamic_cast<T&>(*it->second);
133     }
134 };
135 
136 class StorageRW : public StorageW
137 {
138 public:
TryInsert(TKey key,std::unique_ptr<Storable> && pObj)139     bool TryInsert(TKey key, std::unique_ptr<Storable>&& pObj)
140     {
141         return m_map.emplace(key, std::move(pObj)).second;
142     }
143 
Insert(TKey key,std::unique_ptr<Storable> && pObj)144     void Insert(TKey key, std::unique_ptr<Storable>&& pObj)
145     {
146         if (!TryInsert(key, std::move(pObj)))
147             throw std::logic_error("Keys must be unique");
148     }
149 
150     template<class T, typename std::enable_if<!std::is_base_of<Storable, T>::value, int>::type = 0>
Insert(TKey key,T * pObj)151     void Insert(TKey key, T* pObj)
152     {
153         Insert(key, new MakeStorablePtr<T>(pObj));
154     }
155 
156     template<class T, typename = typename std::enable_if<std::is_base_of<Storable, T>::value>::type>
Insert(TKey key,T * pObj)157     void Insert(TKey key, T* pObj)
158     {
159         Insert(key, std::unique_ptr<T>(pObj));
160     }
161 
Erase(TKey key)162     void Erase(TKey key)
163     {
164         m_map.erase(key);
165     }
166 
Clear()167     void Clear()
168     {
169         m_map.clear();
170     }
171 };
172 
173 template<StorageR::TKey K, class T>
174 struct StorageVar
175 {
176     static const StorageR::TKey Key = K;
177     typedef typename std::conditional<std::is_base_of<Storable, T>::value, T, StorableRef<T>>::type TStore;
178     typedef T TRef;
179 
GetStorageVar180     static const TRef& Get(const StorageR& s)
181     {
182         return s.Read<TStore>(Key);
183     }
184 
GetStorageVar185     static TRef& Get(StorageW& s)
186     {
187         return s.Write<TStore>(Key);
188     }
189 
190     template<typename... Args>
GetOrConstructStorageVar191     static TRef& GetOrConstruct(StorageRW& s, Args&&... args)
192     {
193         if (!s.Contains(Key))
194             s.Insert(Key, make_storable<TRef>(std::forward<Args>(args)...));
195         return s.Write<TStore>(Key);
196     }
197 };
198 
GetWorstSts(mfxStatus sts1,mfxStatus sts2)199 inline mfxStatus GetWorstSts(mfxStatus sts1, mfxStatus sts2)
200 {
201     mfxStatus sts_min = std::min<mfxStatus>(sts1, sts2);
202     return sts_min == MFX_ERR_NONE ? std::max<mfxStatus>(sts1, sts2) : sts_min;
203 }
204 
205 template<class T>
ThrowIf(bool bThrow,T sts)206 inline void ThrowIf(bool bThrow, T sts)
207 {
208     if (bThrow)
209         throw sts;
210 }
211 
212 template<class STS, class T, class... Args>
Catch(STS dflt,T func,Args &&...args)213 inline STS Catch(STS dflt, T func, Args&&... args)
214 {
215     try
216     {
217         func(std::forward<Args>(args)...);
218     }
219     catch (STS sts)
220     {
221         return sts;
222     }
223 
224     return dflt;
225 }
226 
IgnoreSts(mfxStatus)227 inline bool IgnoreSts(mfxStatus) { return false; }
228 
229 template<
230     class TBlock
231     , typename std::enable_if<!std::is_same<typename std::remove_reference<TBlock>::type::TCall::result_type, mfxStatus>::value, int>::type = 0
232     , class... TArgs>
CallAndGetMfxSts(TBlock && blk,TArgs &&...args)233 inline mfxStatus CallAndGetMfxSts(TBlock&& blk, TArgs&&... args)
234 {
235     blk.Call(std::forward<TArgs>(args)...);
236     return MFX_ERR_NONE;
237 }
238 
239 template<
240     class TBlock
241     , typename = typename std::enable_if<std::is_same<typename std::remove_reference<TBlock>::type::TCall::result_type, mfxStatus>::value>::type
242     , class... TArgs>
CallAndGetMfxSts(TBlock && blk,TArgs &&...args)243 inline mfxStatus CallAndGetMfxSts(TBlock&& blk, TArgs&&... args)
244 {
245     return blk.Call(std::forward<TArgs>(args)...);
246 }
247 
248 template <class TPred, class TQ, class... TArgs>
RunBlocks(TPred stopAtSts,TQ & queue,TArgs &&...args)249 mfxStatus RunBlocks(TPred stopAtSts, TQ& queue, TArgs&&... args)
250 {
251     mfxStatus wrn = MFX_ERR_NONE, sts;
252     using TBlock = typename TQ::value_type;
253     auto RunBlock = [&](const TBlock& blk)
254     {
255         auto sts = CallAndGetMfxSts(blk, std::forward<TArgs>(args)...);
256         ThrowIf(stopAtSts(sts), sts);
257         wrn = GetWorstSts(sts, wrn);
258     };
259 
260     try
261     {
262         sts = Catch(
263             MFX_ERR_NONE
264             , std::for_each<decltype(queue.begin()), decltype(RunBlock)>
265             , queue.begin(), queue.end(), RunBlock
266         );
267     }
268     catch (std::exception& ex)
269     {
270         sts = MFX_ERR_UNKNOWN;
271 #if defined(_DEBUG)
272         printf("HEVCEHW Exception: %s\n", ex.what());
273         fflush(stdout);
274 #endif
275     }
276 
277     return GetWorstSts(sts, wrn);
278 }
279 
280 template<class TRV, class... TArg>
281 struct CallChain
282     : public std::function<TRV(TArg...)>
283 {
284     typedef std::function<TRV(TArg...)> TExt;
285     typedef std::function<TRV(TExt, TArg...)> TInt;
286 
PushCallChain287     void Push(TInt newCall)
288     {
289         m_prev.push_front(*this);
290         auto pPrev = &m_prev.front();
291         (TExt&)*this = TExt([=](TArg... args)
292         {
293             return newCall(*pPrev, args...);
294         });
295     }
296 
297     std::list<TExt> m_prev;
298 };
299 
300 } //namespace MfxFeatureBlocks
301 
302