1 // Copyright (c) 2018-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 #include "mfx_ext_buffers.h"
25 #include "mfx_trace.h"
26 #include "umc_mutex.h"
27 #include <vector>
28 #include <list>
29 #include <memory>
30 #include "mfxstructures.h"
31 #include "mfx_enc_common.h"
32 #include "assert.h"
33 
34 static inline bool operator==(mfxVP9SegmentParam const& l, mfxVP9SegmentParam const& r)
35 {
36     return MFX_EQ_FIELD(FeatureEnabled)
37         && MFX_EQ_FIELD(QIndexDelta)
38         && MFX_EQ_FIELD(LoopFilterLevelDelta)
39         && MFX_EQ_FIELD(ReferenceFrame);
40 }
41 
42 namespace MfxHwVP9Encode
43 {
44 
45 constexpr auto DPB_SIZE = 8; // DPB size by VP9 spec
46 constexpr auto DPB_SIZE_REAL = 3; // DPB size really used by encoder
47 constexpr auto MAX_SEGMENTS = 8;
48 constexpr auto REF_FRAMES_LOG2 = 3;
49 constexpr auto REF_FRAMES = (1 << REF_FRAMES_LOG2);
50 constexpr auto MAX_REF_LF_DELTAS = 4;
51 constexpr auto MAX_MODE_LF_DELTAS = 2;
52 constexpr auto SEG_LVL_MAX = 4;
53 
54 constexpr auto IVF_SEQ_HEADER_SIZE_BYTES = 32;
55 constexpr auto IVF_PIC_HEADER_SIZE_BYTES = 12;
56 constexpr auto MAX_IVF_HEADER_SIZE = IVF_SEQ_HEADER_SIZE_BYTES + IVF_PIC_HEADER_SIZE_BYTES;
57 
58 constexpr auto MAX_Q_INDEX = 255;
59 constexpr auto MAX_ICQ_QUALITY_INDEX = 255;
60 constexpr auto MAX_LF_LEVEL = 63;
61 
62 constexpr auto MAX_ABS_COEFF_TYPE_Q_INDEX_DELTA = 15;
63 
64 constexpr auto MAX_TASK_ID = 0xffff;
65 constexpr auto MAX_NUM_TEMP_LAYERS = 8;
66 constexpr auto MAX_NUM_TEMP_LAYERS_SUPPORTED = 4;
67 
68 constexpr auto MAX_UPSCALE_RATIO = 16;
69 constexpr auto MAX_DOWNSCALE_RATIO = 2;
70 
71 constexpr auto MIN_TILE_HEIGHT = 128;
72 constexpr auto MIN_TILE_WIDTH = 256;
73 constexpr auto MAX_TILE_WIDTH = 4096;
74 constexpr auto MAX_NUM_TILE_ROWS = 4;
75 constexpr auto MAX_NUM_TILES = 16;
76 
77 const mfxU16 segmentSkipMask = 0xf0;
78 const mfxU16 segmentRefMask = 0x0f;
79 
80 enum
81 {
82     MFX_MEMTYPE_D3D_INT = MFX_MEMTYPE_FROM_ENCODE | MFX_MEMTYPE_DXVA2_DECODER_TARGET | MFX_MEMTYPE_INTERNAL_FRAME,
83     MFX_MEMTYPE_D3D_EXT = MFX_MEMTYPE_FROM_ENCODE | MFX_MEMTYPE_DXVA2_DECODER_TARGET | MFX_MEMTYPE_EXTERNAL_FRAME,
84     MFX_MEMTYPE_SYS_EXT = MFX_MEMTYPE_FROM_ENCODE | MFX_MEMTYPE_SYSTEM_MEMORY        | MFX_MEMTYPE_EXTERNAL_FRAME,
85     MFX_MEMTYPE_SYS_INT = MFX_MEMTYPE_FROM_ENCODE | MFX_MEMTYPE_SYSTEM_MEMORY        | MFX_MEMTYPE_INTERNAL_FRAME
86 };
87 
88 static const mfxU16 MFX_IOPATTERN_IN_MASK_SYS_OR_D3D =
89     MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_IN_VIDEO_MEMORY;
90 
91 static const mfxU16 MFX_IOPATTERN_IN_MASK =
92     MFX_IOPATTERN_IN_MASK_SYS_OR_D3D | MFX_IOPATTERN_IN_OPAQUE_MEMORY;
93 
94 static const mfxU16 MFX_MEMTYPE_SYS_OR_D3D =
95 MFX_MEMTYPE_DXVA2_DECODER_TARGET | MFX_MEMTYPE_SYSTEM_MEMORY;
96 
97 enum // identifies memory type at encoder input w/o any details
98 {
99     INPUT_SYSTEM_MEMORY,
100     INPUT_VIDEO_MEMORY
101 };
102 
103 
104     enum eTaskStatus
105     {
106         TASK_FREE = 0,
107         TASK_INITIALIZED,
108         TASK_SUBMITTED
109     };
110     enum
111     {
112         REF_LAST  = 0,
113         REF_GOLD  = 1,
114         REF_ALT   = 2,
115         REF_TOTAL = 3
116     };
117 
118     enum {
119         KEY_FRAME       = 0,
120         INTER_FRAME     = 1,
121         NUM_FRAME_TYPES
122     };
123 
124     enum {
125         UNKNOWN_COLOR_SPACE = 0,
126         BT_601              = 1,
127         BT_709              = 2,
128         SMPTE_170           = 3,
129         SMPTE_240           = 4,
130         BT_2020             = 5,
131         RESERVED            = 6,
132         SRGB                = 7
133     };
134 
135     enum {
136         BITDEPTH_8 = 8,
137         BITDEPTH_10 = 10,
138         BITDEPTH_12 = 12
139     };
140 
141     enum {
142         PROFILE_0 = 0,
143         PROFILE_1 = 1,
144         PROFILE_2 = 2,
145         PROFILE_3 = 3,
146         MAX_PROFILES
147     };
148 
149     // Sequence level parameters should contain only parameters that will not change during encoding
150     struct VP9SeqLevelParam
151     {
152         mfxU8  profile;
153         mfxU8  bitDepth;;
154         mfxU8  colorSpace;
155         mfxU8  colorRange;
156         mfxU8  subsamplingX;
157         mfxU8  subsamplingY;
158 
159         mfxU8  frameParallelDecoding;
160     };
161 
162     enum
163     {
164         NO_SEGMENTATION = 0,
165         APP_SEGMENTATION = 1,
166         BRC_SEGMENTATION = 2
167     };
168 
169     struct VP9FrameLevelParam
170     {
171         mfxU8  frameType;
172         mfxU8  baseQIndex;
173         mfxI8  qIndexDeltaLumaDC;
174         mfxI8  qIndexDeltaChromaAC;
175         mfxI8  qIndexDeltaChromaDC;
176 
177         mfxU32 width;
178         mfxU32 height;
179         mfxU32 renderWidth;
180         mfxU32 renderHeight;
181 
182         mfxU8  refreshFrameContext;
183         mfxU8  resetFrameContext;
184         mfxU8  refList[REF_TOTAL]; // indexes of last, gold, alt refs for current frame
185         mfxU8  refBiases[REF_TOTAL];
186         mfxU8  refreshRefFrames[DPB_SIZE]; // which reference frames are refreshed with current reconstructed frame
187         mfxU16 modeInfoCols;
188         mfxU16 modeInfoRows;
189         mfxU8  allowHighPrecisionMV;
190 
191         mfxU8  showFrame;
192         mfxU8  intraOnly;
193 
194         mfxU8  lfLevel;
195         mfxI8  lfRefDelta[4];
196         mfxI8  lfModeDelta[2];
197         mfxU8  modeRefDeltaEnabled;
198         mfxU8  modeRefDeltaUpdate;
199 
200         mfxU8  sharpness;
201         mfxU8  segmentation;
202         mfxU8  segmentationUpdateMap;
203         mfxU8  segmentationUpdateData;
204         mfxU8  segmentationTemporalUpdate;
205         mfxU16  segmentIdBlockSize;
206         mfxU8  errorResilentMode;
207         mfxU8  interpFilter;
208         mfxU8  frameContextIdx;
209         mfxU8  log2TileCols;
210         mfxU8  log2TileRows;
211 
212         mfxU16  temporalLayer;
213         mfxU16  nextTemporalLayer;
214     };
215 
216     struct sFrameEx
217     {
218         mfxFrameSurface1 *pSurface;
219         mfxU32            idInPool;
220         mfxU32            frameOrder;
221         mfxU8             refCount;
222     };
223 
LockSurface(sFrameEx * pFrame,VideoCORE * pCore)224     inline mfxStatus LockSurface(sFrameEx*  pFrame, VideoCORE* pCore)
225     {
226         return (pFrame) ? pCore->IncreaseReference(&pFrame->pSurface->Data) : MFX_ERR_NONE;
227     }
FreeSurface(sFrameEx * & pFrame,VideoCORE * pCore)228     inline mfxStatus FreeSurface(sFrameEx* &pFrame, VideoCORE* pCore)
229     {
230         mfxStatus sts = MFX_ERR_NONE;
231         if (pFrame && pFrame->pSurface)
232         {
233             sts = pCore->DecreaseReference(&pFrame->pSurface->Data);
234             pFrame = 0;
235         }
236         return sts;
237     }
isFreeSurface(sFrameEx * pFrame)238     inline bool isFreeSurface (sFrameEx* pFrame)
239     {
240         return (pFrame->pSurface->Data.Locked == 0);
241     }
IncreaseRef(sFrameEx * & pFrame)242     inline void IncreaseRef(sFrameEx* &pFrame)
243     {
244         pFrame->refCount++;
245     }
DecreaseRef(sFrameEx * & pFrame,VideoCORE * pCore)246     inline mfxStatus DecreaseRef(sFrameEx* &pFrame, VideoCORE* pCore)
247     {
248         if (pFrame->refCount)
249         {
250             pFrame->refCount--;
251             if (pFrame->refCount == 0)
252             {
253                 mfxStatus sts = FreeSurface(pFrame, pCore);
254                 MFX_CHECK_STS(sts);
255             }
256         }
257 
258         return MFX_ERR_NONE;
259     }
260 
Zero(T & obj)261     template<class T> inline void Zero(T & obj)                { obj = T(); }
Zero(T (& obj)[N])262     template<class T, size_t N> inline void Zero(T (&obj)[N])  { std::fill_n(obj, N, T()); }
Zero(std::vector<T> & vec)263     template<class T> inline void Zero(std::vector<T> & vec)   { vec.assign(vec.size(), T()); }
ZeroExtBuffer(T & obj)264     template<class T> inline void ZeroExtBuffer(T & obj)
265     {
266         mfxExtBuffer header = obj.Header;
267         obj = T();
268         obj.Header = header;
269     }
270 
CeilDiv(mfxU32 x,mfxU32 y)271     inline mfxU32 CeilDiv(mfxU32 x, mfxU32 y) { return (x + y - 1) / y; }
CeilLog2(mfxU32 x)272     inline mfxU32 CeilLog2(mfxU32 x) { mfxU32 l = 0; while (x > (1U << l)) l++; return l; }
FloorLog2(mfxU32 x)273     inline mfxU32 FloorLog2(mfxU32 x) { mfxU32 l = 0; while (x >= (1U << (l + 1))) l++; return l; }
274 
275     template<class T> struct ExtBufTypeToId {};
276 
277 #define BIND_EXTBUF_TYPE_TO_ID(TYPE, ID) template<> struct ExtBufTypeToId<TYPE> { enum { id = ID }; }
278     BIND_EXTBUF_TYPE_TO_ID (mfxExtVP9Param,  MFX_EXTBUFF_VP9_PARAM);
279     BIND_EXTBUF_TYPE_TO_ID (mfxExtOpaqueSurfaceAlloc,MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION);
280     BIND_EXTBUF_TYPE_TO_ID (mfxExtCodingOption2, MFX_EXTBUFF_CODING_OPTION2);
281     BIND_EXTBUF_TYPE_TO_ID (mfxExtCodingOption3, MFX_EXTBUFF_CODING_OPTION3);
282     BIND_EXTBUF_TYPE_TO_ID (mfxExtCodingOptionDDI, MFX_EXTBUFF_DDI);
283     BIND_EXTBUF_TYPE_TO_ID (mfxExtVP9Segmentation, MFX_EXTBUFF_VP9_SEGMENTATION);
284     BIND_EXTBUF_TYPE_TO_ID (mfxExtVP9TemporalLayers, MFX_EXTBUFF_VP9_TEMPORAL_LAYERS);
285 #undef BIND_EXTBUF_TYPE_TO_ID
286 
InitExtBufHeader(T & extBuf)287     template <class T> inline void InitExtBufHeader(T & extBuf)
288     {
289         Zero(extBuf);
290         extBuf.Header.BufferId = ExtBufTypeToId<T>::id;
291         extBuf.Header.BufferSz = sizeof(T);
292     }
293 
294     template <class T> struct GetPointedType {};
295     template <class T> struct GetPointedType<T *> { typedef T Type; };
296     template <class T> struct GetPointedType<T const *> { typedef T Type; };
297 
298     struct mfxExtBufferProxy
299     {
300     public:
301         template <typename T> operator T()
302         {
303             mfxExtBuffer * p = GetExtBuffer(
304                 m_extParam,
305                 m_numExtParam,
306                 ExtBufTypeToId<typename GetPointedType<T>::Type>::id);
307             return reinterpret_cast<T>(p);
308         }
309 
310         template <typename T> friend mfxExtBufferProxy GetExtBuffer(const T & par);
311 
312     protected:
313         mfxExtBufferProxy(mfxExtBuffer ** extParam, mfxU32 numExtParam)
314             : m_extParam(extParam)
315             , m_numExtParam(numExtParam)
316         {
317         }
318 
319     private:
320         mfxExtBuffer ** m_extParam;
321         mfxU32          m_numExtParam;
322     };
323 
324     template <typename T> mfxExtBufferProxy GetExtBuffer(T const & par)
325     {
326         return mfxExtBufferProxy(par.ExtParam, par.NumExtParam);
327     }
328 
329 struct mfxExtBufferRefProxy{
330 public:
331     template <typename T> operator T&()
332     {
333         mfxExtBuffer * p = GetExtBuffer(
334             m_extParam,
335             m_numExtParam,
336             ExtBufTypeToId<typename GetPointedType<T*>::Type>::id);
337         assert(p);
338         return *(reinterpret_cast<T*>(p));
339     }
340 
341     template <typename T> friend mfxExtBufferRefProxy GetExtBufferRef(const T & par);
342 
343 protected:
344     mfxExtBufferRefProxy(mfxExtBuffer ** extParam, mfxU32 numExtParam)
345         : m_extParam(extParam)
346         , m_numExtParam(numExtParam)
347     {
348     }
349 private:
350     mfxExtBuffer ** m_extParam;
351     mfxU32          m_numExtParam;
352 };
353 
354 template <typename T> mfxExtBufferRefProxy GetExtBufferRef(T const & par)
355 {
356     return mfxExtBufferRefProxy(par.ExtParam, par.NumExtParam);
357 }
358 
359 class VP9MfxVideoParam;
360 
361 struct ActualExtBufferExtractor {
362 public:
363     template <typename T> operator T&()
364     {
365         mfxExtBuffer * p = GetExtBuffer(
366             m_newParam,
367             m_newNum,
368             ExtBufTypeToId<typename GetPointedType<T*>::Type>::id);
369         if (p)
370         {
371             return *(reinterpret_cast<T*>(p));
372         }
373         else
374         {
375             p = GetExtBuffer(
376                 m_basicParam,
377                 m_basicNum,
378                 ExtBufTypeToId<typename GetPointedType<T*>::Type>::id);
379             assert(p);
380             return *(reinterpret_cast<T*>(p));
381         }
382     }
383 
384     template <typename T> friend ActualExtBufferExtractor GetActualExtBufferRef(const VP9MfxVideoParam & basicPar, const T & newPar);
385 
386 protected:
387     ActualExtBufferExtractor(mfxExtBuffer ** basicParam, mfxU32 basicNum,
388         mfxExtBuffer ** newParam, mfxU32 newNum)
389         : m_basicParam(basicParam)
390         , m_basicNum(basicNum)
391         , m_newParam(newParam)
392         , m_newNum(newNum)
393 
394     {
395     }
396 private:
397     mfxExtBuffer ** m_basicParam;
398     mfxU32          m_basicNum;
399     mfxExtBuffer ** m_newParam;
400     mfxU32          m_newNum;
401 };
402 
403 // remove first entry of extended buffer
404 template <typename T> mfxStatus RemoveExtBuffer(T & par, mfxU32 id)
405 {
406     if (par.ExtParam == 0)
407     {
408         return MFX_ERR_NONE;
409     }
410 
411     for (mfxU16 i = 0; i < par.NumExtParam; i++)
412     {
413         mfxExtBuffer* pBuf = par.ExtParam[i];
414         MFX_CHECK_NULL_PTR1(pBuf);
415         if (pBuf->BufferId == id)
416         {
417             for (mfxU16 j = i + 1; j < par.NumExtParam; j++)
418             {
419                 par.ExtParam[j - 1] = par.ExtParam[j];
420                 par.ExtParam[j] = 0;
421             }
422             par.NumExtParam--;
423             break;
424         }
425     }
426 
427     return MFX_ERR_NONE;
428 }
429 
430     class MfxFrameAllocResponse : public mfxFrameAllocResponse
431     {
432     public:
433         MfxFrameAllocResponse();
434 
435         MfxFrameAllocResponse(MfxFrameAllocResponse const &) = delete;
436         MfxFrameAllocResponse & operator =(MfxFrameAllocResponse const &) = delete;
437 
438         ~MfxFrameAllocResponse();
439 
440         mfxStatus Alloc(
441             VideoCORE* pCore,
442             mfxFrameAllocRequest & req,
443             bool isCopyRequired);
444 
445         mfxStatus Release();
446 
447         mfxFrameInfo               m_info;
448 
449     private:
450         VideoCORE* m_pCore;
451         mfxU16      m_numFrameActualReturnedByAllocFrames;
452 
453         std::vector<mfxFrameAllocResponse> m_responseQueue;
454         std::vector<mfxMemId>              m_mids;
455     };
456 
457     struct FrameLocker
458     {
459         FrameLocker(VideoCORE * pCore, mfxFrameData & data)
460             : m_core(pCore)
461             , m_data(data)
462             , m_memId(data.MemId)
463             , m_status(Lock())
464         {
465         }
466 
467         FrameLocker(VideoCORE * pCore, mfxFrameData & data, mfxMemId memId)
468             : m_core(pCore)
469             , m_data(data)
470             , m_memId(memId)
471             , m_status(Lock())
472         {
473         }
474 
475         ~FrameLocker() { Unlock(); }
476 
477         mfxStatus Unlock()
478         {
479             mfxStatus mfxSts = MFX_ERR_NONE;
480             mfxSts = m_core->UnlockFrame(m_memId, &m_data);
481 
482             m_status = LOCK_NO;
483             return mfxSts;
484         }
485 
486     protected:
487         enum { LOCK_NO, LOCK_DONE };
488 
489         mfxU32 Lock()
490         {
491             mfxU32 status = LOCK_NO;
492 
493             if (m_data.Y == 0 &&
494                 MFX_ERR_NONE == m_core->LockFrame(m_memId, &m_data))
495                 status = LOCK_DONE;
496 
497             return status;
498         }
499 
500     private:
501         FrameLocker(FrameLocker const &);
502         FrameLocker & operator =(FrameLocker const &);
503 
504         VideoCORE*         m_core;
505         mfxFrameData&      m_data;
506         mfxMemId           m_memId;
507         mfxU32             m_status;
508     };
509 
510     struct TempLayerParam
511     {
512         mfxU16 Scale;
513         mfxU32 targetKbps;
514     };
515 
516 constexpr auto NUM_OF_SUPPORTED_EXT_BUFFERS = 7; // mfxExtVP9Param, mfxExtOpaqueSurfaceAlloc, mfxExtCodingOption2, mfxExtCodingOption3, mfxExtCodingOptionDDI, mfxExtVP9Segmentation, mfxExtVP9TemporalLayers
517 
518     class VP9MfxVideoParam : public mfxVideoParam
519     {
520     public:
521         VP9MfxVideoParam();
522         VP9MfxVideoParam(VP9MfxVideoParam const &);
523         VP9MfxVideoParam(mfxVideoParam const &);
524         VP9MfxVideoParam(mfxVideoParam const & par, eMFXHWType const & platform);
525 
526         VP9MfxVideoParam & operator = (VP9MfxVideoParam const &);
527         VP9MfxVideoParam & operator = (mfxVideoParam const &);
528 
529         eMFXHWType m_platform;
530         mfxU16 m_inMemType;
531         mfxU32 m_targetKbps;
532         mfxU32 m_maxKbps;
533         mfxU32 m_bufferSizeInKb;
534         mfxU32 m_initialDelayInKb;
535 
536         TempLayerParam m_layerParam[MAX_NUM_TEMP_LAYERS];
537 
538         bool m_segBufPassed;
539 
540         bool m_tempLayersBufPassed;
541         bool m_webRTCMode;
542         mfxU16 m_numLayers;
543 
544         void CalculateInternalParams();
545         void SyncInternalParamToExternal();
546 
547     protected:
548         void Construct(mfxVideoParam const & par);
549 
550     private:
551         mfxExtBuffer*               m_extParam[NUM_OF_SUPPORTED_EXT_BUFFERS];
552         mfxExtVP9Param              m_extPar;
553         mfxExtOpaqueSurfaceAlloc    m_extOpaque;
554         mfxExtCodingOption2         m_extOpt2;
555         mfxExtCodingOption3         m_extOpt3;
556         mfxExtCodingOptionDDI       m_extOptDDI;
557         mfxExtVP9Segmentation       m_extSeg;
558         mfxExtVP9TemporalLayers     m_extTempLayers;
559     };
560 
561     template <typename T> ActualExtBufferExtractor GetActualExtBufferRef(VP9MfxVideoParam const & basicPar, T const & newPar)
562     {
563         return  ActualExtBufferExtractor(basicPar.ExtParam, basicPar.NumExtParam, newPar.ExtParam, newPar.NumExtParam);
564     }
565 
566     class Task;
567     mfxStatus SetFramesParams(VP9MfxVideoParam const &par,
568                               Task const & task,
569                               mfxU8 frameType,
570                               VP9FrameLevelParam &frameParam,
571                               eMFXHWType platform);
572 
573     mfxStatus InitVp9SeqLevelParam(VP9MfxVideoParam const &video, VP9SeqLevelParam &param);
574 
575     mfxStatus DecideOnRefListAndDPBRefresh(VP9MfxVideoParam const & par,
576                                            Task *pTask,
577                                            std::vector<sFrameEx*>& dpb,
578                                            VP9FrameLevelParam &frameParam,
579                                            mfxU32 prevFrameOrderInRefStructure);
580 
581     mfxStatus UpdateDpb(VP9FrameLevelParam &frameParam,
582                         sFrameEx *pRecFrame,
583                         std::vector<sFrameEx*>&dpb,
584                         VideoCORE *pCore);
585 
586     class ExternalFrames
587     {
588     protected:
589         std::list<sFrameEx>  m_frames;
590     public:
591         ExternalFrames() {}
592         void Init(mfxU32 numFrames);
593         mfxStatus GetFrame(mfxFrameSurface1 *pInFrame, sFrameEx *&pOutFrame);
594      };
595 
596     class InternalFrames
597     {
598     protected:
599         std::vector<sFrameEx>           m_frames;
600         MfxFrameAllocResponse           m_response;
601         std::vector<mfxFrameSurface1>   m_surfaces;
602     public:
603         InternalFrames() {}
604         mfxStatus Init(VideoCORE *pCore, mfxFrameAllocRequest *pAllocReq, bool isCopyRequired);
605         sFrameEx * GetFreeFrame();
606         mfxStatus  GetFrame(mfxU32 numFrame, sFrameEx * &Frame);
607         mfxStatus Release();
608 
609         inline mfxU16 Height()
610         {
611             return m_response.m_info.Height;
612         }
613         inline mfxU16 Width()
614         {
615             return m_response.m_info.Width;
616         }
617         inline mfxU32 Num()
618         {
619             return m_response.NumFrameActual;
620         }
621         inline MfxFrameAllocResponse& GetFrameAllocReponse()  {return m_response;}
622     };
623 
624     bool isVideoSurfInput(mfxVideoParam const & video);
625 
626     inline bool isOpaq(mfxVideoParam const & video)
627     {
628         return (video.IOPattern & MFX_IOPATTERN_IN_OPAQUE_MEMORY)!=0;
629     }
630 
631     inline mfxU32 CalcNumTasks(mfxVideoParam const & video)
632     {
633         return video.AsyncDepth;
634     }
635 
636     inline mfxU32 CalcNumSurfRecon(mfxVideoParam const & video)
637     {
638         return video.mfx.NumRefFrame + CalcNumTasks(video);
639     }
640 
641     inline mfxU32 CalcNumSurfRaw(mfxVideoParam const & video)
642     {
643         // number of input surfaces is same for VIDEO and SYSTEM memory
644         // because so far encoder doesn't support LookAhead and B-frames
645         return video.AsyncDepth + ((video.AsyncDepth > 1)? 1: 0);
646     }
647 
648     class Task
649     {
650     public:
651 
652         sFrameEx*         m_pRawFrame;
653         sFrameEx*         m_pRawLocalFrame;
654         mfxBitstream*     m_pBitsteam;
655 
656         VP9FrameLevelParam m_frameParam;
657         sFrameEx*         m_pRecFrame;
658         sFrameEx*         m_pRecRefFrames[3];
659         sFrameEx*         m_pOutBs;
660         sFrameEx*         m_pSegmentMap;
661         mfxU32            m_frameOrder;
662         mfxU64            m_timeStamp;
663         mfxU32            m_taskIdForDriver;
664         mfxU32            m_frameOrderInGop;
665         mfxU32            m_frameOrderInRefStructure;
666 
667         mfxEncodeCtrl     m_ctrl;
668 
669         mfxU32 m_bsDataLength;
670 
671         VP9MfxVideoParam* m_pParam;
672 
673         bool m_insertIVFSeqHeader;
674         bool m_resetBrc;
675 
676         mfxExtVP9Segmentation const * m_pPrevSegment;
677 
678         Task ():
679               m_pRawFrame(NULL),
680               m_pRawLocalFrame(NULL),
681               m_pBitsteam(0),
682               m_pRecFrame(NULL),
683               m_pOutBs(NULL),
684               m_pSegmentMap(NULL),
685               m_frameOrder(0),
686               m_timeStamp(0),
687               m_taskIdForDriver(0),
688               m_frameOrderInGop(0),
689               m_frameOrderInRefStructure(0),
690               m_bsDataLength(0),
691               m_pParam(NULL),
692               m_insertIVFSeqHeader(false),
693               m_resetBrc(false),
694               m_pPrevSegment(NULL)
695           {
696               Zero(m_pRecRefFrames);
697               Zero(m_frameParam);
698               Zero(m_ctrl);
699           }
700 
701           ~Task() {};
702     };
703 
704     inline mfxStatus FreeTask(VideoCORE *pCore, Task &task)
705     {
706         mfxStatus sts = FreeSurface(task.m_pRawFrame, pCore);
707         MFX_CHECK_STS(sts);
708         sts = FreeSurface(task.m_pRawLocalFrame, pCore);
709         MFX_CHECK_STS(sts);
710         sts = FreeSurface(task.m_pOutBs, pCore);
711         MFX_CHECK_STS(sts);
712         sts = FreeSurface(task.m_pSegmentMap, pCore);
713         MFX_CHECK_STS(sts);
714         sts = DecreaseRef(task.m_pRecFrame, pCore);
715         MFX_CHECK_STS(sts);
716         task.m_pRecFrame = 0;
717 
718         const VP9MfxVideoParam& curMfxPar = *task.m_pParam;
719         if (curMfxPar.m_numLayers && task.m_frameParam.temporalLayer == curMfxPar.m_numLayers - 1 &&
720             curMfxPar.m_numLayers > curMfxPar.mfx.NumRefFrame)
721         {
722             // if last temporal layer is non-reference, need to free reconstructed surface right away.
723             sts = FreeSurface(task.m_pRecFrame, pCore);
724             MFX_CHECK_STS(sts);
725         }
726 
727         task.m_pBitsteam = 0;
728         Zero(task.m_frameParam);
729         Zero(task.m_ctrl);
730 
731         return MFX_ERR_NONE;
732     }
733 
734     inline bool IsBufferBasedBRC(mfxU16 brcMethod)
735     {
736         return brcMethod == MFX_RATECONTROL_CBR
737             || brcMethod == MFX_RATECONTROL_VBR;
738     }
739 
740     inline bool IsBitrateBasedBRC(mfxU16 brcMethod)
741     {
742         return IsBufferBasedBRC(brcMethod);
743     }
744 
745     inline bool isBrcResetRequired(VP9MfxVideoParam const & parBefore, VP9MfxVideoParam const & parAfter)
746     {
747         mfxU16 brc = parAfter.mfx.RateControlMethod;
748         if (false == IsBitrateBasedBRC(brc))
749         {
750             return false;
751         }
752 
753         double frameRateBefore = (double)parBefore.mfx.FrameInfo.FrameRateExtN / (double)parBefore.mfx.FrameInfo.FrameRateExtD;
754         double frameRateAfter = (double)parAfter.mfx.FrameInfo.FrameRateExtN / (double)parAfter.mfx.FrameInfo.FrameRateExtD;
755 
756         mfxExtVP9Param const & extParBefore = GetExtBufferRef(parBefore);
757         mfxExtVP9Param const & extParAfter = GetExtBufferRef(parAfter);
758 
759         if (parBefore.m_targetKbps != parAfter.m_targetKbps
760             || ((brc == MFX_RATECONTROL_VBR) && (parBefore.m_maxKbps != parAfter.m_maxKbps))
761             || frameRateBefore != frameRateAfter
762             || (IsBufferBasedBRC(brc) && (parBefore.m_bufferSizeInKb != parAfter.m_bufferSizeInKb))
763             || ((brc == MFX_RATECONTROL_ICQ) && (parBefore.mfx.ICQQuality != parAfter.mfx.ICQQuality))
764             || extParBefore.FrameWidth != extParAfter.FrameWidth
765             || extParBefore.FrameHeight != extParAfter.FrameHeight)
766         {
767             return true;
768         }
769         else
770         {
771             return false;
772         }
773     }
774 
775     inline mfxU16 CalcTemporalLayerIndex(VP9MfxVideoParam const & par, mfxU32 frameOrder)
776     {
777         mfxU16 i = 0;
778         mfxExtVP9TemporalLayers const & tl = GetExtBufferRef(par);
779 
780         if (par.m_numLayers > 0)
781         {
782             mfxU32 maxScale = tl.Layer[par.m_numLayers - 1].FrameRateScale;
783             for (; i < par.m_numLayers; i++)
784                 if (frameOrder % (maxScale / tl.Layer[i].FrameRateScale) == 0)
785                     break;
786         }
787 
788         return i;
789     }
790 
791     // for TS-encoding: context refreshing should be disabled for the 1st frame in each layer
792     //  in case if this frame can appear next to the key-frame after layers extraction
793     // this is demand by kernel processing logic
794     inline bool IsNeedDisableRefreshForFrameTS(VP9MfxVideoParam const & par, mfxU32 frameOrderInGop)
795     {
796         if (par.m_numLayers > 1 && frameOrderInGop >= 2)
797         {
798             mfxExtVP9TemporalLayers const & tl = GetExtBufferRef(par);
799             mfxU32 maxScale = tl.Layer[par.m_numLayers - 1].FrameRateScale;
800             if (frameOrderInGop > maxScale)
801             {
802                 // not applicable outside of the 1st GOP
803                 return false;
804             }
805             else if (frameOrderInGop == maxScale)
806             {
807                 // the last affected frame is the first frame in the 2nd GOP
808                 return true;
809             }
810             else if (frameOrderInGop <= (maxScale / 2))
811             {
812                 // inside the first GOP affected all frames in the beginning of Layer-2 and Layer-3
813                 // (Layer-0 and Layer-1 not affected)
814                 if (CalcTemporalLayerIndex(par, frameOrderInGop) < CalcTemporalLayerIndex(par, frameOrderInGop - 1))
815                 {
816                     return true;
817                 }
818             }
819         }
820 
821         return false;
822     }
823 
824     mfxStatus GetRealSurface(
825         VideoCORE *pCore,
826         VP9MfxVideoParam const &par,
827         Task const &task,
828         mfxFrameSurface1 *& pSurface);
829 
830     mfxStatus GetInputSurface(
831         VideoCORE *pCore,
832         VP9MfxVideoParam const &par,
833         Task const &task,
834         mfxFrameSurface1 *& pSurface);
835 
836     mfxStatus CopyRawSurfaceToVideoMemory(
837         VideoCORE *pCore,
838         VP9MfxVideoParam const &par,
839         Task const &task);
840 
841 /*mfxStatus ReleaseDpbFrames(VideoCORE* pCore, std::vector<sFrameEx*> & dpb)
842 {
843     for (mfxU8 refIdx = 0; refIdx < dpb.size(); refIdx ++)
844     {
845         if (dpb[refIdx])
846         {
847             dpb[refIdx]->refCount = 0;
848             MFX_CHECK_STS(FreeSurface(dpb[refIdx], pCore));
849         }
850     }
851 
852     return MFX_ERR_NONE;
853 }*/
854 
855 struct FindTaskByRawSurface
856 {
857     FindTaskByRawSurface(mfxFrameSurface1 * pSurf) : m_pSurface(pSurf) {}
858 
859     bool operator ()(Task const & task)
860     {
861         return task.m_pRawFrame->pSurface == m_pSurface;
862     }
863 
864     mfxFrameSurface1* m_pSurface;
865 };
866 
867 struct FindTaskByMfxVideoParam
868 {
869     FindTaskByMfxVideoParam(mfxVideoParam* pPar) : m_pPar(pPar) {}
870 
871     bool operator ()(Task const & task)
872     {
873         return task.m_pParam == m_pPar;
874     }
875 
876     mfxVideoParam* m_pPar;
877 };
878 
879 // full list of essential segmentation parametes is provided
880 inline bool AllMandatorySegMapParams(mfxExtVP9Segmentation const & seg)
881 {
882     return seg.SegmentIdBlockSize &&
883         seg.NumSegmentIdAlloc && seg.SegmentId;
884 }
885 
886 // at least one essential segmentation parameter is provided
887 inline bool AnyMandatorySegMapParam(mfxExtVP9Segmentation const & seg)
888 {
889     return seg.SegmentIdBlockSize ||
890         seg.NumSegmentIdAlloc || seg.SegmentId;
891 }
892 
893 inline mfxU16 MapIdToBlockSize(mfxU16 id)
894 {
895     return id;
896 }
897 
898 inline bool CompareSegmentMaps(mfxExtVP9Segmentation const & first, mfxExtVP9Segmentation const & second)
899 {
900     if (!first.SegmentId || !second.SegmentId ||
901         first.SegmentIdBlockSize != second.SegmentIdBlockSize ||
902         !first.NumSegmentIdAlloc || !second.NumSegmentIdAlloc)
903         return false;
904 
905     return std::equal(first.SegmentId, first.SegmentId + std::min(first.NumSegmentIdAlloc, second.NumSegmentIdAlloc), second.SegmentId);
906 }
907 
908 inline bool CompareSegmentParams(mfxExtVP9Segmentation const & first, mfxExtVP9Segmentation const & second)
909 {
910     if (first.NumSegments != second.NumSegments)
911         return false;
912 
913     return std::equal(first.Segment, first.Segment + first.NumSegments, second.Segment);
914 }
915 
916 inline void CopySegmentationBuffer(mfxExtVP9Segmentation & dst, mfxExtVP9Segmentation const & src)
917 {
918     mfxU8* tmp = dst.SegmentId;
919     ZeroExtBuffer(dst);
920     dst = src;
921     dst.SegmentId = tmp;
922     if (dst.SegmentId && src.SegmentId && dst.NumSegmentIdAlloc)
923     {
924         std::copy(src.SegmentId, src.SegmentId + dst.NumSegmentIdAlloc, dst.SegmentId);
925     }
926 }
927 
928 inline void CombineInitAndRuntimeSegmentBuffers(mfxExtVP9Segmentation & runtime, mfxExtVP9Segmentation const & init)
929 {
930     if (runtime.SegmentId == 0 && init.SegmentId != 0)
931     {
932         runtime.SegmentId = init.SegmentId;
933         runtime.SegmentIdBlockSize = init.SegmentIdBlockSize;
934         runtime.NumSegmentIdAlloc = init.NumSegmentIdAlloc;
935     }
936 }
937 
938 enum
939 {
940     FEAT_QIDX = 0,
941     FEAT_LF_LVL = 1,
942     FEAT_REF = 2,
943     FEAT_SKIP = 3
944 };
945 
946 inline bool IsFeatureEnabled(mfxU16 features, mfxU8 feature)
947 {
948     return (features & (1 << feature)) != 0;
949 }
950 
951 mfxStatus GetNativeHandleToRawSurface(
952     VideoCORE & core,
953     mfxMemId mid,
954     mfxHDL *handle,
955     VP9MfxVideoParam const & video);
956 
957 } // MfxHwVP9Encode
958 
959 template<class T, class I>
960 inline bool Clamp(T & opt, I min, I max)
961 {
962     if (opt < static_cast<T>(min))
963     {
964         opt = static_cast<T>(min);
965         return false;
966     }
967 
968     if (opt > static_cast<T>(max))
969     {
970         opt = static_cast<T>(max);
971         return false;
972     }
973 
974     return true;
975 }
976