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