1 // Copyright (c) 2019-2020 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 #include "mfx_common.h"
22 #if defined(MFX_ENABLE_H265_VIDEO_ENCODE)
23 
24 #include "hevcehw_base_legacy.h"
25 #include "hevcehw_base_data.h"
26 #include "hevcehw_base_constraints.h"
27 #include "hevcehw_base_parser.h"
28 #include "fast_copy.h"
29 #include <algorithm>
30 #include <exception>
31 #include <numeric>
32 #include <set>
33 #include <cmath>
34 
35 using namespace HEVCEHW;
36 using namespace HEVCEHW::Base;
37 
SetSupported(ParamSupport & blocks)38 void Legacy::SetSupported(ParamSupport& blocks)
39 {
40     auto CopyRawBuffer = [](mfxU8* pSrcBuf, mfxU16 szSrcBuf, mfxU8* pDstBuf, mfxU16& szDstBuf)
41     {
42         bool bCopy = pSrcBuf && pDstBuf;
43         ThrowIf(bCopy && szSrcBuf > szDstBuf, MFX_ERR_NOT_ENOUGH_BUFFER);
44 
45         if (bCopy)
46         {
47             std::copy_n(pSrcBuf, szSrcBuf, pDstBuf);
48             szDstBuf = szSrcBuf;
49         }
50     };
51 
52     blocks.m_mvpCopySupported.emplace_back(
53         [](const mfxVideoParam* pSrc, mfxVideoParam* pDst) -> void
54     {
55         const auto& buf_src = *(const mfxVideoParam*)pSrc;
56         auto& buf_dst = *(mfxVideoParam*)pDst;
57         MFX_COPY_FIELD(IOPattern);
58         MFX_COPY_FIELD(Protected);
59         MFX_COPY_FIELD(AsyncDepth);
60         MFX_COPY_FIELD(mfx.CodecId);
61         MFX_COPY_FIELD(mfx.LowPower);
62         MFX_COPY_FIELD(mfx.CodecLevel);
63         MFX_COPY_FIELD(mfx.CodecProfile);
64         MFX_COPY_FIELD(mfx.TargetUsage);
65         MFX_COPY_FIELD(mfx.GopPicSize);
66         MFX_COPY_FIELD(mfx.GopRefDist);
67         MFX_COPY_FIELD(mfx.GopOptFlag);
68         MFX_COPY_FIELD(mfx.IdrInterval);
69         MFX_COPY_FIELD(mfx.BRCParamMultiplier);
70         MFX_COPY_FIELD(mfx.RateControlMethod);
71         MFX_COPY_FIELD(mfx.InitialDelayInKB);
72         MFX_COPY_FIELD(mfx.BufferSizeInKB);
73         MFX_COPY_FIELD(mfx.TargetKbps);
74         MFX_COPY_FIELD(mfx.MaxKbps);
75         MFX_COPY_FIELD(mfx.NumSlice);
76         MFX_COPY_FIELD(mfx.NumRefFrame);
77         MFX_COPY_FIELD(mfx.EncodedOrder);
78         MFX_COPY_FIELD(mfx.FrameInfo.Shift);
79         MFX_COPY_FIELD(mfx.FrameInfo.BitDepthLuma);
80         MFX_COPY_FIELD(mfx.FrameInfo.BitDepthChroma);
81         MFX_COPY_FIELD(mfx.FrameInfo.FourCC);
82         MFX_COPY_FIELD(mfx.FrameInfo.Width);
83         MFX_COPY_FIELD(mfx.FrameInfo.Height);
84         MFX_COPY_FIELD(mfx.FrameInfo.CropX);
85         MFX_COPY_FIELD(mfx.FrameInfo.CropY);
86         MFX_COPY_FIELD(mfx.FrameInfo.CropW);
87         MFX_COPY_FIELD(mfx.FrameInfo.CropH);
88         MFX_COPY_FIELD(mfx.FrameInfo.FrameRateExtN);
89         MFX_COPY_FIELD(mfx.FrameInfo.FrameRateExtD);
90         MFX_COPY_FIELD(mfx.FrameInfo.AspectRatioW);
91         MFX_COPY_FIELD(mfx.FrameInfo.AspectRatioH);
92         MFX_COPY_FIELD(mfx.FrameInfo.ChromaFormat);
93         MFX_COPY_FIELD(mfx.FrameInfo.PicStruct);
94     });
95 
96     blocks.m_ebCopySupported[MFX_EXTBUFF_HEVC_PARAM].emplace_back(
97         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
98     {
99         const auto& buf_src = *(const mfxExtHEVCParam*)pSrc;
100         auto& buf_dst = *(mfxExtHEVCParam*)pDst;
101         MFX_COPY_FIELD(PicWidthInLumaSamples);
102         MFX_COPY_FIELD(PicHeightInLumaSamples);
103         MFX_COPY_FIELD(GeneralConstraintFlags);
104         MFX_COPY_FIELD(SampleAdaptiveOffset);
105         MFX_COPY_FIELD(LCUSize);
106     });
107     blocks.m_ebCopySupported[MFX_EXTBUFF_HEVC_TILES].emplace_back(
108         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
109     {
110         const auto& buf_src = *(const mfxExtHEVCTiles*)pSrc;
111         auto& buf_dst = *(mfxExtHEVCTiles*)pDst;
112         MFX_COPY_FIELD(NumTileRows);
113         MFX_COPY_FIELD(NumTileColumns);
114     });
115     blocks.m_ebCopySupported[MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION].emplace_back(
116         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
117     {
118         const auto& buf_src = *(const mfxExtOpaqueSurfaceAlloc*)pSrc;
119         auto& buf_dst = *(mfxExtOpaqueSurfaceAlloc*)pDst;
120         MFX_COPY_FIELD(In.Surfaces);
121         MFX_COPY_FIELD(In.Type);
122         MFX_COPY_FIELD(In.NumSurface);
123         MFX_COPY_FIELD(Out.Surfaces);
124         MFX_COPY_FIELD(Out.Type);
125         MFX_COPY_FIELD(Out.NumSurface);
126     });
127     blocks.m_ebCopySupported[MFX_EXTBUFF_AVC_REFLISTS].emplace_back(
128         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
129     {
130         const auto& buf_src = *(const mfxExtAVCRefLists*)pSrc;
131         auto& buf_dst = *(mfxExtAVCRefLists*)pDst;
132         MFX_COPY_FIELD(NumRefIdxL0Active);
133         MFX_COPY_FIELD(NumRefIdxL1Active);
134         for (mfxU32 i = 0; i < 16; i++)
135         {
136             MFX_COPY_FIELD(RefPicList0[i].FrameOrder);
137             MFX_COPY_FIELD(RefPicList1[i].FrameOrder);
138         }
139     });
140     blocks.m_ebCopySupported[MFX_EXTBUFF_CODING_OPTION].emplace_back(
141         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
142     {
143         const auto& buf_src = *(const mfxExtCodingOption*)pSrc;
144         auto& buf_dst = *(mfxExtCodingOption*)pDst;
145         MFX_COPY_FIELD(PicTimingSEI);
146         MFX_COPY_FIELD(VuiNalHrdParameters);
147         MFX_COPY_FIELD(NalHrdConformance);
148         MFX_COPY_FIELD(AUDelimiter);
149     });
150     blocks.m_ebCopySupported[MFX_EXTBUFF_CODING_OPTION2].emplace_back(
151         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
152     {
153         const auto& buf_src = *(const mfxExtCodingOption2*)pSrc;
154         auto& buf_dst = *(mfxExtCodingOption2*)pDst;
155         MFX_COPY_FIELD(IntRefType);
156         MFX_COPY_FIELD(IntRefCycleSize);
157         MFX_COPY_FIELD(IntRefQPDelta);
158         MFX_COPY_FIELD(MBBRC);
159         MFX_COPY_FIELD(BRefType);
160         MFX_COPY_FIELD(NumMbPerSlice);
161         MFX_COPY_FIELD(DisableDeblockingIdc);
162         MFX_COPY_FIELD(RepeatPPS);
163         MFX_COPY_FIELD(MaxSliceSize);
164         MFX_COPY_FIELD(ExtBRC);
165         MFX_COPY_FIELD(MinQPI);
166         MFX_COPY_FIELD(MaxQPI);
167         MFX_COPY_FIELD(MinQPP);
168         MFX_COPY_FIELD(MaxQPP);
169         MFX_COPY_FIELD(MinQPB);
170         MFX_COPY_FIELD(MaxQPB);
171         MFX_COPY_FIELD(SkipFrame);
172     });
173     blocks.m_ebCopySupported[MFX_EXTBUFF_CODING_OPTION3].emplace_back(
174         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
175     {
176         const auto& buf_src = *(const mfxExtCodingOption3*)pSrc;
177         auto& buf_dst = *(mfxExtCodingOption3*)pDst;
178         MFX_COPY_FIELD(PRefType);
179         MFX_COPY_FIELD(IntRefCycleDist);
180         MFX_COPY_FIELD(EnableQPOffset);
181         MFX_COPY_FIELD(GPB);
182         MFX_COPY_ARRAY_FIELD(QPOffset);
183         MFX_COPY_ARRAY_FIELD(NumRefActiveP);
184         MFX_COPY_ARRAY_FIELD(NumRefActiveBL0);
185         MFX_COPY_ARRAY_FIELD(NumRefActiveBL1);
186         MFX_COPY_FIELD(QVBRQuality);
187         MFX_COPY_FIELD(EnableMBQP);
188         MFX_COPY_FIELD(TransformSkip);
189         MFX_COPY_FIELD(TargetChromaFormatPlus1);
190         MFX_COPY_FIELD(TargetBitDepthLuma);
191         MFX_COPY_FIELD(TargetBitDepthChroma);
192         MFX_COPY_FIELD(WinBRCMaxAvgKbps);
193         MFX_COPY_FIELD(WinBRCSize);
194         MFX_COPY_FIELD(EnableNalUnitType);
195         MFX_COPY_FIELD(LowDelayBRC);
196 #if MFX_VERSION >= MFX_VERSION_NEXT
197         MFX_COPY_FIELD(DeblockingAlphaTcOffset);
198         MFX_COPY_FIELD(DeblockingBetaOffset);
199 #endif
200         MFX_COPY_FIELD(BRCPanicMode);
201         MFX_COPY_FIELD(ScenarioInfo);
202     });
203     blocks.m_ebCopyPtrs[MFX_EXTBUFF_CODING_OPTION_SPSPPS].emplace_back(
204         [&](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
205     {
206         const auto& buf_src = *(const mfxExtCodingOptionSPSPPS*)pSrc;
207         auto&       buf_dst = *(mfxExtCodingOptionSPSPPS*)pDst;
208 
209         MFX_COPY_FIELD(SPSBuffer);
210         MFX_COPY_FIELD(SPSBufSize);
211         MFX_COPY_FIELD(PPSBuffer);
212         MFX_COPY_FIELD(PPSBufSize);
213     });
214     blocks.m_ebCopySupported[MFX_EXTBUFF_CODING_OPTION_SPSPPS].emplace_back(
215         [&](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
216     {
217         const auto& buf_src = *(const mfxExtCodingOptionSPSPPS*)pSrc;
218         auto&       buf_dst = *(mfxExtCodingOptionSPSPPS*)pDst;
219 
220         CopyRawBuffer(buf_src.SPSBuffer, buf_src.SPSBufSize, buf_dst.SPSBuffer, buf_dst.SPSBufSize);
221         CopyRawBuffer(buf_src.PPSBuffer, buf_src.PPSBufSize, buf_dst.PPSBuffer, buf_dst.PPSBufSize);
222     });
223     blocks.m_ebCopySupported[MFX_EXTBUFF_AVC_REFLIST_CTRL].emplace_back(
224         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
225     {
226         const auto& buf_src = *(const mfxExtAVCRefListCtrl*)pSrc;
227         auto& buf_dst = *(mfxExtAVCRefListCtrl*)pDst;
228         MFX_COPY_FIELD(NumRefIdxL0Active);
229         MFX_COPY_FIELD(NumRefIdxL1Active);
230         for (mfxU32 i = 0; i < 16; i++)
231         {
232             MFX_COPY_FIELD(PreferredRefList[i].FrameOrder);
233             MFX_COPY_FIELD(RejectedRefList[i].FrameOrder);
234             MFX_COPY_FIELD(LongTermRefList[i].FrameOrder);
235         }
236     });
237     blocks.m_ebCopySupported[MFX_EXTBUFF_AVC_TEMPORAL_LAYERS].emplace_back(
238         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
239     {
240         const auto& buf_src = *(const mfxExtAvcTemporalLayers*)pSrc;
241         auto& buf_dst = *(mfxExtAvcTemporalLayers*)pDst;
242         for (mfxU32 i = 0; i < 7; i++)
243         {
244             MFX_COPY_FIELD(Layer[i].Scale);
245         }
246     });
247     blocks.m_ebCopySupported[MFX_EXTBUFF_ENCODER_RESET_OPTION].emplace_back(
248         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
249     {
250         const auto& buf_src = *(const mfxExtEncoderResetOption*)pSrc;
251         auto& buf_dst = *(mfxExtEncoderResetOption*)pDst;
252         MFX_COPY_FIELD(StartNewSequence);
253     });
254     blocks.m_ebCopyPtrs[MFX_EXTBUFF_CODING_OPTION_VPS].emplace_back(
255         [&](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
256     {
257         const auto& buf_src = *(const mfxExtCodingOptionVPS*)pSrc;
258         auto&       buf_dst = *(mfxExtCodingOptionVPS*)pDst;
259 
260         MFX_COPY_FIELD(VPSBuffer);
261         MFX_COPY_FIELD(VPSBufSize);
262     });
263     blocks.m_ebCopySupported[MFX_EXTBUFF_CODING_OPTION_VPS].emplace_back(
264         [&](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
265     {
266         const auto& buf_src = *(const mfxExtCodingOptionVPS*)pSrc;
267         auto& buf_dst = *(mfxExtCodingOptionVPS*)pDst;
268 
269         CopyRawBuffer(buf_src.VPSBuffer, buf_src.VPSBufSize, buf_dst.VPSBuffer, buf_dst.VPSBufSize);
270     });
271     blocks.m_ebCopySupported[MFX_EXTBUFF_VIDEO_SIGNAL_INFO].emplace_back(
272         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
273     {
274         const auto& buf_src = *(const mfxExtVideoSignalInfo*)pSrc;
275         auto& buf_dst = *(mfxExtVideoSignalInfo*)pDst;
276         buf_dst = buf_src;
277     });
278     blocks.m_ebCopySupported[MFX_EXTBUFF_LOOKAHEAD_STAT].emplace_back(
279         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
280     {
281         const auto& buf_src = *(const mfxExtLAFrameStatistics*)pSrc;
282         auto& buf_dst = *(mfxExtLAFrameStatistics*)pDst;
283         MFX_COPY_FIELD(NumAlloc);
284         MFX_COPY_FIELD(NumStream);
285         MFX_COPY_FIELD(NumFrame);
286         MFX_COPY_FIELD(FrameStat);
287         MFX_COPY_FIELD(OutSurface);
288     });
289     blocks.m_ebCopySupported[MFX_EXTBUFF_MBQP].emplace_back(
290         [](const mfxExtBuffer* pSrc, mfxExtBuffer* pDst) -> void
291     {
292         const auto& buf_src = *(const mfxExtMBQP*)pSrc;
293         auto& buf_dst = *(mfxExtMBQP*)pDst;
294         MFX_COPY_FIELD(NumQPAlloc);
295         MFX_COPY_FIELD(QP);
296     });
297 }
298 
IsTCBRC(const mfxVideoParam & par,mfxU16 tcbrcSupport)299 bool Legacy::IsTCBRC(const mfxVideoParam& par, mfxU16 tcbrcSupport)
300 {
301     const mfxExtCodingOption3& CO3 = ExtBuffer::Get(par);
302     const mfxExtCodingOption& CO = ExtBuffer::Get(par);
303     return (IsOn(CO3.LowDelayBRC) && tcbrcSupport && IsOff(CO.NalHrdConformance) &&
304            (par.mfx.RateControlMethod  ==  MFX_RATECONTROL_VBR  ||
305             par.mfx.RateControlMethod  ==  MFX_RATECONTROL_QVBR ||
306             par.mfx.RateControlMethod  ==  MFX_RATECONTROL_VCM ));
307 }
308 
SetInherited(ParamInheritance & par)309 void Legacy::SetInherited(ParamInheritance& par)
310 {
311     par.m_mvpInheritDefault.emplace_back(
312         [](const mfxVideoParam* pSrc, mfxVideoParam* pDst)
313     {
314         auto& parInit = *pSrc;
315         auto& parReset = *pDst;
316 
317 #define INHERIT_OPT(OPT) InheritOption(parInit.OPT, parReset.OPT)
318 #define INHERIT_BRC(OPT) { OPT tmp(parReset.mfx); InheritOption(OPT(parInit.mfx), tmp); }
319 
320         INHERIT_OPT(AsyncDepth);
321         //INHERIT_OPT(mfx.BRCParamMultiplier);
322         INHERIT_OPT(mfx.CodecId);
323         INHERIT_OPT(mfx.CodecProfile);
324         INHERIT_OPT(mfx.CodecLevel);
325         INHERIT_OPT(mfx.NumThread);
326         INHERIT_OPT(mfx.TargetUsage);
327         INHERIT_OPT(mfx.GopPicSize);
328         INHERIT_OPT(mfx.GopRefDist);
329         INHERIT_OPT(mfx.GopOptFlag);
330         INHERIT_OPT(mfx.IdrInterval);
331         INHERIT_OPT(mfx.RateControlMethod);
332         INHERIT_OPT(mfx.BufferSizeInKB);
333         INHERIT_OPT(mfx.NumSlice);
334         INHERIT_OPT(mfx.NumRefFrame);
335 
336         mfxU16 RC = parInit.mfx.RateControlMethod
337             * (parInit.mfx.RateControlMethod == parReset.mfx.RateControlMethod);
338         static const std::map<
339             mfxU16 , std::function<void(const mfxVideoParam&, mfxVideoParam&)>
340         > InheritBrcOpt =
341         {
342             {
343                 mfxU16(MFX_RATECONTROL_CBR)
344                 , [](const mfxVideoParam& parInit, mfxVideoParam& parReset)
345                 {
346                     INHERIT_BRC(InitialDelayInKB);
347                     INHERIT_BRC(TargetKbps);
348                 }
349             }
350             , {
351                 mfxU16(MFX_RATECONTROL_VBR)
352                 , [](const mfxVideoParam& parInit, mfxVideoParam& parReset)
353                 {
354                     INHERIT_BRC(InitialDelayInKB);
355                     INHERIT_BRC(TargetKbps);
356                     INHERIT_BRC(MaxKbps);
357                 }
358             }
359             , {
360                 mfxU16(MFX_RATECONTROL_CQP)
361                 , [](const mfxVideoParam& parInit, mfxVideoParam& parReset)
362                 {
363                     INHERIT_OPT(mfx.QPI);
364                     INHERIT_OPT(mfx.QPP);
365                     INHERIT_OPT(mfx.QPB);
366                 }
367             }
368             , {
369                 mfxU16(MFX_RATECONTROL_ICQ)
370                 , [](const mfxVideoParam& parInit, mfxVideoParam& parReset)
371                 {
372                     INHERIT_OPT(mfx.ICQQuality);
373                 }
374             }
375             , {
376                 mfxU16(MFX_RATECONTROL_LA_ICQ)
377                 , [](const mfxVideoParam& parInit, mfxVideoParam& parReset)
378                 {
379                     INHERIT_OPT(mfx.ICQQuality);
380                 }
381             }
382             , {
383                 mfxU16(MFX_RATECONTROL_VCM)
384                 , [](const mfxVideoParam& parInit, mfxVideoParam& parReset)
385                 {
386                     INHERIT_BRC(InitialDelayInKB);
387                     INHERIT_BRC(TargetKbps);
388                     INHERIT_BRC(MaxKbps);
389                 }
390             }
391             , {
392                 mfxU16(MFX_RATECONTROL_QVBR)
393                 , [](const mfxVideoParam& parInit, mfxVideoParam& parReset)
394                 {
395                     INHERIT_BRC(InitialDelayInKB);
396                     INHERIT_BRC(TargetKbps);
397                     INHERIT_BRC(MaxKbps);
398                 }
399             }
400         };
401         auto itInheritBrcOpt = InheritBrcOpt.find(RC);
402 
403         if (itInheritBrcOpt != InheritBrcOpt.end())
404             itInheritBrcOpt->second(parInit, parReset);
405 
406         INHERIT_OPT(mfx.FrameInfo.FourCC);
407         INHERIT_OPT(mfx.FrameInfo.Width);
408         INHERIT_OPT(mfx.FrameInfo.Height);
409         INHERIT_OPT(mfx.FrameInfo.CropX);
410         INHERIT_OPT(mfx.FrameInfo.CropY);
411         INHERIT_OPT(mfx.FrameInfo.CropW);
412         INHERIT_OPT(mfx.FrameInfo.CropH);
413         INHERIT_OPT(mfx.FrameInfo.FrameRateExtN);
414         INHERIT_OPT(mfx.FrameInfo.FrameRateExtD);
415         INHERIT_OPT(mfx.FrameInfo.AspectRatioW);
416         INHERIT_OPT(mfx.FrameInfo.AspectRatioH);
417 
418 #undef INHERIT_OPT
419 #undef INHERIT_BRC
420     });
421 
422 #define INIT_EB(TYPE)\
423     if (!pSrc || !pDst) return;\
424     auto& ebInit = *(TYPE*)pSrc;\
425     auto& ebReset = *(TYPE*)pDst;
426 #define INHERIT_OPT(OPT) InheritOption(ebInit.OPT, ebReset.OPT);
427 
428     par.m_ebInheritDefault[MFX_EXTBUFF_HEVC_PARAM].emplace_back(
429         [](const mfxVideoParam& /*parInit*/
430             , const mfxExtBuffer* pSrc
431             , const mfxVideoParam& /*parReset*/
432             , mfxExtBuffer* pDst)
433     {
434         INIT_EB(mfxExtHEVCParam);
435         INHERIT_OPT(GeneralConstraintFlags);
436         INHERIT_OPT(SampleAdaptiveOffset);
437         INHERIT_OPT(LCUSize);
438     });
439 
440     par.m_ebInheritDefault[MFX_EXTBUFF_HEVC_TILES].emplace_back(
441         [](const mfxVideoParam& /*parInit*/
442             , const mfxExtBuffer* pSrc
443             , const mfxVideoParam& /*parReset*/
444             , mfxExtBuffer* pDst)
445     {
446         INIT_EB(mfxExtHEVCTiles);
447         INHERIT_OPT(NumTileColumns);
448         INHERIT_OPT(NumTileRows);
449     });
450 
451     par.m_ebInheritDefault[MFX_EXTBUFF_CODING_OPTION].emplace_back(
452         [](const mfxVideoParam& /*parInit*/
453             , const mfxExtBuffer* pSrc
454             , const mfxVideoParam& /*parReset*/
455             , mfxExtBuffer* pDst)
456     {
457         INIT_EB(mfxExtCodingOption);
458         INHERIT_OPT(VuiNalHrdParameters);
459         INHERIT_OPT(NalHrdConformance);
460         INHERIT_OPT(PicTimingSEI);
461     });
462 
463     par.m_ebInheritDefault[MFX_EXTBUFF_CODING_OPTION2].emplace_back(
464         [](const mfxVideoParam& /*parInit*/
465             , const mfxExtBuffer* pSrc
466             , const mfxVideoParam& /*parReset*/
467             , mfxExtBuffer* pDst)
468     {
469         INIT_EB(mfxExtCodingOption2);
470         INHERIT_OPT(IntRefType);
471         INHERIT_OPT(IntRefCycleSize);
472         INHERIT_OPT(IntRefQPDelta);
473         INHERIT_OPT(MBBRC);
474         INHERIT_OPT(BRefType);
475         INHERIT_OPT(NumMbPerSlice);
476         INHERIT_OPT(MinQPI);
477         INHERIT_OPT(MinQPP);
478         INHERIT_OPT(MinQPB);
479         INHERIT_OPT(MaxQPI);
480         INHERIT_OPT(MaxQPP);
481         INHERIT_OPT(MaxQPB);
482     });
483 
484     par.m_ebInheritDefault[MFX_EXTBUFF_CODING_OPTION3].emplace_back(
485         [this](const mfxVideoParam& parInit
486             , const mfxExtBuffer* pSrc
487             , const mfxVideoParam& parReset
488             , mfxExtBuffer* pDst)
489     {
490         INIT_EB(mfxExtCodingOption3);
491         INHERIT_OPT(LowDelayBRC);
492         INHERIT_OPT(IntRefCycleDist);
493         INHERIT_OPT(PRefType);
494         INHERIT_OPT(GPB);
495         INHERIT_OPT(TransformSkip);
496         INHERIT_OPT(TargetChromaFormatPlus1);
497         INHERIT_OPT(TargetBitDepthLuma);
498         INHERIT_OPT(TargetBitDepthChroma);
499         INHERIT_OPT(WinBRCMaxAvgKbps);
500         INHERIT_OPT(WinBRCSize);
501         INHERIT_OPT(EnableMBQP);
502 
503         mfxU16 RC = parInit.mfx.RateControlMethod
504             * (parInit.mfx.RateControlMethod == parReset.mfx.RateControlMethod);
505 
506         if (RC == MFX_RATECONTROL_QVBR)
507             INHERIT_OPT(QVBRQuality);
508 
509         if (parInit.mfx.TargetUsage != parReset.mfx.TargetUsage)
510         {
511             auto maxRef = m_GetMaxRef(parReset);
512             auto ClipRefP   = [maxRef](mfxU16 ref) { return std::min<mfxU16>(ref, std::get<P>(maxRef)); };
513             auto ClipRefBL0 = [maxRef](mfxU16 ref) { return std::min<mfxU16>(ref, std::get<BL0>(maxRef)); };
514             auto ClipRefBL1 = [maxRef](mfxU16 ref) { return std::min<mfxU16>(ref, std::get<BL1>(maxRef)); };
515 
516             std::transform(ebInit.NumRefActiveP, ebInit.NumRefActiveP + 8, ebReset.NumRefActiveP, ClipRefP);
517             std::transform(ebInit.NumRefActiveBL0, ebInit.NumRefActiveBL0 + 8, ebReset.NumRefActiveBL0, ClipRefBL0);
518             std::transform(ebInit.NumRefActiveBL1, ebInit.NumRefActiveBL1 + 8, ebReset.NumRefActiveBL1, ClipRefBL1);
519         }
520         else
521         {
522             InheritOptions(ebInit.NumRefActiveP, ebInit.NumRefActiveP + 8, ebReset.NumRefActiveP);
523             InheritOptions(ebInit.NumRefActiveBL0, ebInit.NumRefActiveBL0 + 8, ebReset.NumRefActiveBL0);
524             InheritOptions(ebInit.NumRefActiveBL1, ebInit.NumRefActiveBL1 + 8, ebReset.NumRefActiveBL1);
525         }
526     });
527 
528     par.m_ebInheritDefault[MFX_EXTBUFF_VIDEO_SIGNAL_INFO].emplace_back(
529         [](const mfxVideoParam& /*parInit*/
530             , const mfxExtBuffer* pSrc
531             , const mfxVideoParam& /*parReset*/
532             , mfxExtBuffer* pDst)
533     {
534         INIT_EB(mfxExtVideoSignalInfo);
535         INHERIT_OPT(VideoFormat);
536         INHERIT_OPT(ColourPrimaries);
537         INHERIT_OPT(TransferCharacteristics);
538         INHERIT_OPT(MatrixCoefficients);
539         INHERIT_OPT(VideoFullRange);
540         INHERIT_OPT(ColourDescriptionPresent);
541     });
542 #undef INIT_EB
543 #undef INHERIT_OPT
544 }
545 
Query0(const FeatureBlocks & blocks,TPushQ0 Push)546 void Legacy::Query0(const FeatureBlocks& blocks, TPushQ0 Push)
547 {
548     using namespace std::placeholders;
549     Push( BLK_Query0, std::bind(&Legacy::CheckQuery0, this, std::cref(blocks), _1));
550 }
551 
Query1NoCaps(const FeatureBlocks & blocks,TPushQ1 Push)552 void Legacy::Query1NoCaps(const FeatureBlocks& blocks, TPushQ1 Push)
553 {
554     Push(BLK_SetDefaultsCallChain,
555         [this](const mfxVideoParam&, mfxVideoParam&, StorageRW& strg) -> mfxStatus
556     {
557         auto& defaults = Glob::Defaults::GetOrConstruct(strg);
558         auto& bSet = defaults.SetForFeature[GetID()];
559         MFX_CHECK(!bSet, MFX_ERR_NONE);
560 
561         PushDefaults(defaults);
562 
563         VideoCORE * pCore = &Glob::VideoCore::Get(strg);
564         defaults.RunFastCopyWrapper.Push([pCore](Defaults::TRunFastCopyWrapper::TExt
565             , mfxFrameSurface1 &surfDst
566             , mfxU16 dstMemType
567             , mfxFrameSurface1 &surfSrc
568             , mfxU16 srcMemType) -> mfxStatus
569             {
570                 return pCore->DoFastCopyWrapper(&surfDst, dstMemType, &surfSrc, srcMemType);
571             });
572 
573         bSet = true;
574 
575         m_pQNCDefaults = &defaults;
576         m_hw = Glob::VideoCore::Get(strg).GetHWType();
577 
578         return MFX_ERR_NONE;
579     });
580 
581     Push(BLK_PreCheckCodecId,
582         [this](const mfxVideoParam& in, mfxVideoParam&, StorageRW& /*strg*/) -> mfxStatus
583     {
584         return m_pQNCDefaults->PreCheckCodecId(in);
585     });
586 
587     Push(BLK_PreCheckChromaFormat,
588         [this](const mfxVideoParam& in, mfxVideoParam&, StorageW&) -> mfxStatus
589     {
590         return m_pQNCDefaults->PreCheckChromaFormat(in);
591     });
592 
593     Push(BLK_PreCheckExtBuffers
594         , [this, &blocks](const mfxVideoParam& in, mfxVideoParam& out, StorageW&) -> mfxStatus
595     {
596         return CheckBuffers(blocks, in, &out);
597     });
598 
599     Push(BLK_CopyConfigurable
600         , [this, &blocks](const mfxVideoParam& in, mfxVideoParam& out, StorageW&) -> mfxStatus
601     {
602         return CopyConfigurable(blocks, in, out);
603     });
604 
605     Push(BLK_SetLowPowerDefault
606         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW& /*strg*/) -> mfxStatus
607     {
608         auto lowPower = m_pQNCDefaults->GetLowPower(out, m_hw);
609         bool bChanged = out.mfx.LowPower && out.mfx.LowPower != lowPower;
610 
611         out.mfx.LowPower = lowPower;
612 
613         MFX_CHECK(!bChanged, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
614         return MFX_ERR_NONE;
615     });
616 
617     Push(BLK_SetGUID
618         , [](const mfxVideoParam&, mfxVideoParam& out, StorageRW& strg) -> mfxStatus
619     {
620         MFX_CHECK(!strg.Contains(Glob::GUID::Key), MFX_ERR_NONE);
621 
622         if (strg.Contains(Glob::RealState::Key))
623         {
624             //don't change GUID in Reset
625             auto& initPar = Glob::RealState::Get(strg);
626             strg.Insert(Glob::GUID::Key, make_storable<GUID>(Glob::GUID::Get(initPar)));
627             return MFX_ERR_NONE;
628         }
629 
630         VideoCORE& core = Glob::VideoCore::Get(strg);
631         auto pGUID = make_storable<GUID>();
632         auto& defaults = Glob::Defaults::Get(strg);
633         EncodeCapsHevc fakeCaps;
634         Defaults::Param defPar(out, fakeCaps, core.GetHWType(), defaults);
635         fakeCaps.MaxEncodedBitDepth = (defPar.hw >= MFX_HW_KBL);
636         fakeCaps.YUV422ReconSupport = (defPar.hw >= MFX_HW_ICL) && !IsOn(out.mfx.LowPower);
637         fakeCaps.YUV444ReconSupport = (defPar.hw >= MFX_HW_ICL) && IsOn(out.mfx.LowPower);
638 
639         MFX_CHECK(defaults.GetGUID(defPar, *pGUID), MFX_ERR_NONE);
640         strg.Insert(Glob::GUID::Key, std::move(pGUID));
641 
642         return MFX_ERR_NONE;
643     });
644 }
645 
Query1WithCaps(const FeatureBlocks &,TPushQ1 Push)646 void Legacy::Query1WithCaps(const FeatureBlocks& /*blocks*/, TPushQ1 Push)
647 {
648     Push(BLK_CheckHeaders
649         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW& strg) -> mfxStatus
650     {
651         mfxStatus sts = MFX_ERR_NONE;
652         m_pQWCDefaults.reset(
653             new Defaults::Param(
654                 out
655                 , Glob::EncodeCaps::Get(strg)
656                 , Glob::VideoCore::Get(strg).GetHWType()
657                 , Glob::Defaults::Get(strg)));
658 
659         if (strg.Contains(Glob::SPS::Key))
660             sts = CheckSPS(Glob::SPS::Get(strg), m_pQWCDefaults->caps, m_pQWCDefaults->hw);
661 
662         if (!sts && strg.Contains(Glob::PPS::Key))
663             sts = CheckPPS(Glob::PPS::Get(strg), m_pQWCDefaults->caps, m_pQWCDefaults->hw);
664 
665         return sts;
666     });
667 
668     Push(BLK_CheckLCUSize
669         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW& ) -> mfxStatus
670     {
671         return m_pQWCDefaults->base.CheckLCUSize(*m_pQWCDefaults, out);
672     });
673 
674     Push(BLK_CheckFormat
675         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
676     {
677         auto sts = m_pQWCDefaults->base.CheckFourCC(*m_pQWCDefaults, out);
678         MFX_CHECK_STS(sts);
679         sts = m_pQWCDefaults->base.CheckInputFormatByFourCC(*m_pQWCDefaults, out);
680         MFX_CHECK_STS(sts);
681         sts = m_pQWCDefaults->base.CheckTargetChromaFormat(*m_pQWCDefaults, out);
682         MFX_CHECK_STS(sts);
683         sts = m_pQWCDefaults->base.CheckTargetBitDepth(*m_pQWCDefaults, out);
684         MFX_CHECK_STS(sts);
685         return m_pQWCDefaults->base.CheckFourCCByTargetFormat(*m_pQWCDefaults, out);
686     });
687 
688     Push(BLK_CheckLowDelayBRC
689         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
690     {
691         return m_pQWCDefaults->base.CheckLowDelayBRC(*m_pQWCDefaults, out);
692     });
693 
694     Push(BLK_CheckLevel
695         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
696     {
697         return m_pQWCDefaults->base.CheckLevel(*m_pQWCDefaults, out);
698     });
699 
700     Push(BLK_CheckSurfSize
701         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
702     {
703         return m_pQWCDefaults->base.CheckSurfSize(*m_pQWCDefaults, out);
704     });
705 
706     Push(BLK_CheckCodedPicSize
707         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
708     {
709         return CheckCodedPicSize(out, *m_pQWCDefaults);
710     });
711 
712     Push(BLK_CheckTiles
713         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
714     {
715         return CheckTiles(out, *m_pQWCDefaults);
716     });
717 
718     Push(BLK_CheckTU
719         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
720     {
721         return CheckTU(out, m_pQWCDefaults->caps);
722     });
723 
724     Push(BLK_CheckTemporalLayers
725         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
726     {
727         return CheckTemporalLayers(out);
728     });
729 
730     Push(BLK_CheckGopRefDist
731         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
732     {
733         return CheckGopRefDist(out, m_pQWCDefaults->caps);
734     });
735 
736     Push(BLK_CheckNumRefFrame
737         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
738     {
739         return CheckNumRefFrame(out, *m_pQWCDefaults);
740     });
741 
742     Push(BLK_CheckIOPattern
743         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
744     {
745         return CheckIOPattern(out);
746     });
747 
748     Push(BLK_CheckBRC
749         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
750     {
751         return CheckBRC(out, *m_pQWCDefaults);
752     });
753 
754     Push(BLK_CheckCrops
755         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
756     {
757         return CheckCrops(out, *m_pQWCDefaults);
758     });
759 
760     Push(BLK_CheckShift
761         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
762     {
763         return CheckShift(out, ExtBuffer::Get(out));
764     });
765 
766     Push(BLK_CheckFrameRate
767         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
768     {
769         return CheckFrameRate(out);
770     });
771 
772     Push(BLK_CheckSlices
773         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
774     {
775         return CheckSlices(out, *m_pQWCDefaults);
776     });
777 
778     Push(BLK_CheckBPyramid
779         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
780     {
781         return CheckBPyramid(out, *m_pQWCDefaults);
782     });
783 
784     Push(BLK_CheckPPyramid
785         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
786     {
787         return CheckPPyramid(out);
788     });
789 
790     Push(BLK_CheckIntraRefresh
791         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
792     {
793         return CheckIntraRefresh(out, *m_pQWCDefaults);
794     });
795 
796     Push(BLK_CheckSkipFrame
797         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
798     {
799         return CheckSkipFrame(out);
800     });
801 
802     Push(BLK_CheckGPB
803         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
804     {
805         return CheckGPB(out);
806     });
807 
808     Push(BLK_CheckESPackParam
809         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
810     {
811         return CheckESPackParam(out, m_pQWCDefaults->hw);
812     });
813 
814     Push(BLK_CheckNumRefActive
815         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
816     {
817         return m_pQWCDefaults->base.CheckNumRefActive(*m_pQWCDefaults, out);
818     });
819 
820     Push(BLK_CheckSAO
821         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
822     {
823         return m_pQWCDefaults->base.CheckSAO(*m_pQWCDefaults, out);
824     });
825 
826     Push(BLK_CheckProfile
827         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
828     {
829         return m_pQWCDefaults->base.CheckProfile(*m_pQWCDefaults, out);
830     });
831 
832     Push(BLK_CheckLevelConstraints
833         , [this](const mfxVideoParam&, mfxVideoParam& out, StorageW&) -> mfxStatus
834     {
835         return CheckLevelConstraints(out, *m_pQWCDefaults);
836     });
837 }
838 
QueryIOSurf(const FeatureBlocks & blocks,TPushQIS Push)839 void Legacy::QueryIOSurf(const FeatureBlocks& blocks, TPushQIS Push)
840 {
841     Push(BLK_CheckIOPattern
842         , [](const mfxVideoParam& par, mfxFrameAllocRequest&, StorageRW&) -> mfxStatus
843     {
844         bool check_result = Check<mfxU16
845             , MFX_IOPATTERN_IN_VIDEO_MEMORY
846             , MFX_IOPATTERN_IN_SYSTEM_MEMORY
847             , MFX_IOPATTERN_IN_OPAQUE_MEMORY
848             >
849             (par.IOPattern);
850 
851         MFX_CHECK(!check_result, MFX_ERR_INVALID_VIDEO_PARAM);
852 
853         return MFX_ERR_NONE;
854     });
855 
856     Push(BLK_CheckVideoParam
857         , [&blocks](const mfxVideoParam& par, mfxFrameAllocRequest&, StorageRW& strg) -> mfxStatus
858     {
859         mfxStatus sts = MFX_ERR_NONE;
860         auto pTmpPar = make_storable<ExtBuffer::Param<mfxVideoParam>>(par);
861 
862         auto& queryNC = FeatureBlocks::BQ<FeatureBlocks::BQ_Query1NoCaps>::Get(blocks);
863         sts = RunBlocks(CheckGE<mfxStatus, MFX_ERR_NONE>, queryNC, par, *pTmpPar, strg);
864         MFX_CHECK(sts != MFX_ERR_UNSUPPORTED, MFX_ERR_INVALID_VIDEO_PARAM);
865         MFX_CHECK(sts >= MFX_ERR_NONE, sts);
866 
867         auto& queryWC = FeatureBlocks::BQ<FeatureBlocks::BQ_Query1WithCaps>::Get(blocks);
868         sts = RunBlocks(CheckGE<mfxStatus, MFX_ERR_NONE>, queryWC, par, *pTmpPar, strg);
869         MFX_CHECK(sts != MFX_ERR_UNSUPPORTED, MFX_ERR_INVALID_VIDEO_PARAM);
870         MFX_CHECK(sts >= MFX_ERR_NONE, sts);
871 
872         strg.Insert(Glob::VideoParam::Key, std::move(pTmpPar));
873 
874         return MFX_ERR_NONE;
875     });
876 
877     Push(BLK_SetDefaults
878         , [&blocks](const mfxVideoParam&, mfxFrameAllocRequest&, StorageRW& strg) -> mfxStatus
879     {
880         ExtBuffer::Param<mfxVideoParam>& par = Glob::VideoParam::Get(strg);
881         StorageRW local;
882 
883         auto& qSD = FeatureBlocks::BQ<FeatureBlocks::BQ_SetDefaults>::Get(blocks);
884         return RunBlocks(IgnoreSts, qSD, par, strg, local);
885     });
886 
887     Push(BLK_SetFrameAllocRequest
888         , [this](const mfxVideoParam&, mfxFrameAllocRequest& req, StorageRW& strg) -> mfxStatus
889     {
890         ExtBuffer::Param<mfxVideoParam>& par = Glob::VideoParam::Get(strg);
891         auto fourCC = par.mfx.FrameInfo.FourCC;
892 
893         req.Info = par.mfx.FrameInfo;
894         SetDefault(req.Info.Shift, (fourCC == MFX_FOURCC_P010 || fourCC == MFX_FOURCC_Y210));
895 
896         bool bSYS = par.IOPattern == MFX_IOPATTERN_IN_SYSTEM_MEMORY;
897         bool bVID = par.IOPattern == MFX_IOPATTERN_IN_VIDEO_MEMORY;
898         bool bOPQ = par.IOPattern == MFX_IOPATTERN_IN_OPAQUE_MEMORY;
899 
900         req.Type =
901             bSYS * (MFX_MEMTYPE_FROM_ENCODE | MFX_MEMTYPE_SYSTEM_MEMORY | MFX_MEMTYPE_EXTERNAL_FRAME)
902             + bVID * (MFX_MEMTYPE_FROM_ENCODE | MFX_MEMTYPE_DXVA2_DECODER_TARGET | MFX_MEMTYPE_EXTERNAL_FRAME)
903             + bOPQ * (MFX_MEMTYPE_FROM_ENCODE | MFX_MEMTYPE_DXVA2_DECODER_TARGET | MFX_MEMTYPE_OPAQUE_FRAME);
904         MFX_CHECK(req.Type, MFX_ERR_INVALID_VIDEO_PARAM);
905 
906         req.NumFrameMin = GetMaxRaw(par);
907         req.NumFrameSuggested = req.NumFrameMin;
908 
909         return MFX_ERR_NONE;
910     });
911 }
912 
SetDefaults(const FeatureBlocks &,TPushSD Push)913 void Legacy::SetDefaults(const FeatureBlocks& /*blocks*/, TPushSD Push)
914 {
915     Push(BLK_SetDefaults
916         , [this](mfxVideoParam& par, StorageW& strg, StorageRW&)
917     {
918         auto& core = Glob::VideoCore::Get(strg);
919         auto& caps = Glob::EncodeCaps::Get(strg);
920         auto& defchain = Glob::Defaults::Get(strg);
921         SetDefaults(par, Defaults::Param(par, caps, core.GetHWType(), defchain), core.IsExternalFrameAllocator());
922     });
923 }
924 
InitExternal(const FeatureBlocks & blocks,TPushIE Push)925 void Legacy::InitExternal(const FeatureBlocks& blocks, TPushIE Push)
926 {
927     Push(BLK_SetGUID
928         , [&blocks](const mfxVideoParam& in, StorageRW& strg, StorageRW&) -> mfxStatus
929     {
930         const auto& query = FeatureBlocks::BQ<FeatureBlocks::BQ_Query1NoCaps>::Get(blocks);
931         mfxStatus sts = MFX_ERR_NONE;
932         auto pPar = make_storable<ExtBuffer::Param<mfxVideoParam>>(in);
933         ExtBuffer::Param<mfxVideoParam>& par = *pPar;
934 
935         sts = RunBlocks(CheckGE<mfxStatus, MFX_ERR_NONE>, query, in, par, strg);
936         MFX_CHECK(sts != MFX_ERR_UNSUPPORTED, MFX_ERR_INVALID_VIDEO_PARAM);
937         MFX_CHECK(sts >= MFX_ERR_NONE, sts);
938 
939         strg.Insert(Glob::VideoParam::Key, std::move(pPar));
940 
941         return sts;
942     });
943 
944     Push(BLK_CheckVideoParam
945         , [&blocks](const mfxVideoParam& in, StorageRW& strg, StorageRW&) -> mfxStatus
946     {
947         const auto& query = FeatureBlocks::BQ<FeatureBlocks::BQ_Query1WithCaps>::Get(blocks);
948         mfxStatus sts = MFX_ERR_NONE;
949         ExtBuffer::Param<mfxVideoParam>& par = Glob::VideoParam::Get(strg);
950 
951         sts = RunBlocks(CheckGE<mfxStatus, MFX_ERR_NONE>, query, in, par, strg);
952         MFX_CHECK(sts != MFX_ERR_UNSUPPORTED, MFX_ERR_INVALID_VIDEO_PARAM);
953         MFX_CHECK(sts >= MFX_ERR_NONE, sts);
954 
955         MFX_CHECK(in.mfx.FrameInfo.Width  == par.mfx.FrameInfo.Width
956                && in.mfx.FrameInfo.Height == par.mfx.FrameInfo.Height, MFX_ERR_INVALID_VIDEO_PARAM);
957 
958         return sts;
959     });
960 
961     Push(BLK_SetDefaults
962         , [&blocks](const mfxVideoParam&, StorageRW& strg, StorageRW& local) -> mfxStatus
963     {
964         auto& par = Glob::VideoParam::Get(strg);
965 
966         for (auto& eb : blocks.m_ebCopySupported)
967             par.NewEB(eb.first, false);
968 
969         auto& qSD = FeatureBlocks::BQ<FeatureBlocks::BQ_SetDefaults>::Get(blocks);
970         return RunBlocks(IgnoreSts, qSD, par, strg, local);
971     });
972 }
973 
InitInternal(const FeatureBlocks &,TPushII Push)974 void Legacy::InitInternal(const FeatureBlocks& /*blocks*/, TPushII Push)
975 {
976     Push(BLK_SetReorder
977         , [this](StorageRW& strg, StorageRW&) -> mfxStatus
978     {
979         using namespace std::placeholders;
980         auto& par = Glob::VideoParam::Get(strg);
981 
982         auto pReorderer = make_storable<Reorderer>();
983 
984         pReorderer->BufferSize = par.mfx.GopRefDist - 1;
985         pReorderer->MaxReorder = par.mfx.GopRefDist - 1;
986         pReorderer->DPB        = &m_prevTask.DPB.After;
987 
988         pReorderer->Push(
989             [&](Reorderer::TExt, const DpbArray& DPB, TTaskIt begin, TTaskIt end, bool bFlush)
990         {
991             auto IsIdrFrame = [](TItWrap::reference fi) { return IsIdr(fi.FrameType); };
992             auto newEnd = std::find_if(TItWrap(begin), TItWrap(end), IsIdrFrame);
993 
994             bFlush |= (newEnd != begin && newEnd != end);
995 
996             return Reorder(par, DPB, TItWrap(begin), newEnd, bFlush).it;
997         });
998 
999         strg.Insert(Glob::Reorder::Key, std::move(pReorderer));
1000 
1001         return MFX_ERR_NONE;
1002     });
1003 
1004     Push(BLK_SetVPS
1005         , [this](StorageRW& strg, StorageRW&) -> mfxStatus
1006     {
1007         MFX_CHECK(!strg.Contains(Glob::VPS::Key), MFX_ERR_NONE);
1008         auto dflts = GetRTDefaults(strg);
1009 
1010         auto sts = dflts.base.GetVPS(dflts, Glob::VPS::GetOrConstruct(strg));
1011         MFX_CHECK_STS(sts);
1012 
1013         return MFX_ERR_NONE;
1014     });
1015 
1016     Push(BLK_SetSPS
1017         , [this](StorageRW& strg, StorageRW&) -> mfxStatus
1018     {
1019         if (!strg.Contains(Glob::SPS::Key))
1020         {
1021             auto pSPS = make_storable<SPS>();
1022             auto dflts = GetRTDefaults(strg);
1023 
1024             auto sts = dflts.base.GetSPS(dflts, Glob::VPS::Get(strg), *pSPS);
1025             MFX_CHECK_STS(sts);
1026 
1027             strg.Insert(Glob::SPS::Key, std::move(pSPS));
1028         }
1029 
1030         if (strg.Contains(Glob::RealState::Key))
1031         {
1032             auto& hint = Glob::ResetHint::Get(strg);
1033             const SPS& oldSPS = Glob::SPS::Get(Glob::RealState::Get(strg));
1034             SPS& newSPS = Glob::SPS::Get(strg);
1035 
1036             SPS oldSPScopy = oldSPS;
1037             std::copy(newSPS.strps, newSPS.strps + Size(newSPS.strps), oldSPScopy.strps);
1038             oldSPScopy.num_short_term_ref_pic_sets = newSPS.num_short_term_ref_pic_sets;
1039 
1040             if (!oldSPS.vui_parameters_present_flag)
1041                 oldSPScopy.vui = newSPS.vui;
1042 
1043             bool bSPSChanged = !!memcmp(&newSPS, &oldSPScopy, sizeof(SPS));
1044 
1045             hint.Flags |= RF_SPS_CHANGED * (bSPSChanged || (hint.Flags & RF_IDR_REQUIRED));
1046         }
1047 
1048         return CheckSPS(Glob::SPS::Get(strg)
1049             , Glob::EncodeCaps::Get(strg)
1050             , Glob::VideoCore::Get(strg).GetHWType());
1051     });
1052 
1053     Push(BLK_NestSTRPS
1054         , [](StorageRW& strg, StorageRW&) -> mfxStatus
1055     {
1056         MFX_CHECK(
1057             strg.Contains(Glob::RealState::Key)
1058             && !(Glob::ResetHint::Get(strg).Flags & RF_SPS_CHANGED)
1059             , MFX_ERR_NONE);
1060 
1061         SPS& newSPS = Glob::SPS::Get(strg);
1062         const SPS& oldSPS = Glob::SPS::Get(Glob::RealState::Get(strg));
1063 
1064         //sacrifice STRPS optimization at Reset to avoid IDR insertion
1065         newSPS.num_short_term_ref_pic_sets = oldSPS.num_short_term_ref_pic_sets;
1066         std::copy(oldSPS.strps, oldSPS.strps + Size(oldSPS.strps), newSPS.strps);
1067 
1068         return MFX_ERR_NONE;
1069     });
1070 
1071     Push(BLK_SetSTRPS
1072         , [this](StorageRW& strg, StorageRW&) -> mfxStatus
1073     {
1074         SPS& sps = Glob::SPS::Get(strg);
1075 
1076         MFX_CHECK(
1077             !sps.num_short_term_ref_pic_sets
1078             && !(strg.Contains(Glob::RealState::Key)
1079                 && !(Glob::ResetHint::Get(strg).Flags & RF_SPS_CHANGED))
1080             , MFX_ERR_NONE);
1081 
1082         auto dflts = GetRTDefaults(strg);
1083 
1084         MFX_CHECK(!dflts.base.GetNonStdReordering(dflts), MFX_ERR_NONE);
1085 
1086         SetSTRPS(dflts, sps, Glob::Reorder::Get(strg));
1087 
1088         return MFX_ERR_NONE;
1089     });
1090 
1091 
1092     Push(BLK_SetPPS
1093         , [this](StorageRW& strg, StorageRW&) -> mfxStatus
1094     {
1095         if (!strg.Contains(Glob::PPS::Key))
1096         {
1097             std::unique_ptr<MakeStorable<PPS>> pPPS(new MakeStorable<PPS>);
1098             auto dflts = GetRTDefaults(strg);
1099 
1100             auto sts = dflts.base.GetPPS(dflts, Glob::SPS::Get(strg), *pPPS);
1101             MFX_CHECK_STS(sts);
1102 
1103             strg.Insert(Glob::PPS::Key, std::move(pPPS));
1104         }
1105 
1106         if (strg.Contains(Glob::RealState::Key))
1107         {
1108             const PPS& oldPPS = Glob::PPS::Get(Glob::RealState::Get(strg));
1109             PPS& newPPS = Glob::PPS::Get(strg);
1110 
1111             if (memcmp(&oldPPS, &newPPS, sizeof(PPS)))
1112                 Glob::ResetHint::Get(strg).Flags |= RF_PPS_CHANGED;
1113         }
1114 
1115         return CheckPPS(Glob::PPS::Get(strg)
1116             , Glob::EncodeCaps::Get(strg)
1117             , Glob::VideoCore::Get(strg).GetHWType());
1118     });
1119 
1120     Push(BLK_SetSlices
1121         , [this](StorageRW& strg, StorageRW&) -> mfxStatus
1122     {
1123         auto dflts = GetRTDefaults(strg);
1124         dflts.base.GetSlices(dflts, Glob::SliceInfo::GetOrConstruct(strg));
1125         return MFX_ERR_NONE;
1126     });
1127 
1128     Push(BLK_SetRawInfo
1129         , [this](StorageRW& strg, StorageRW& local) -> mfxStatus
1130     {
1131         auto& par = Glob::VideoParam::Get(strg);
1132         mfxFrameAllocRequest raw = {};
1133 
1134         raw.Info = par.mfx.FrameInfo;
1135         auto& rawInfo = Tmp::RawInfo::GetOrConstruct(local, raw);
1136         SetDefault(rawInfo.NumFrameMin, GetMaxRaw(par));
1137         SetDefault(rawInfo.Type
1138             , mfxU16(MFX_MEMTYPE_FROM_ENCODE
1139                 | MFX_MEMTYPE_DXVA2_DECODER_TARGET
1140                 | MFX_MEMTYPE_INTERNAL_FRAME));
1141 
1142         return MFX_ERR_NONE;
1143     });
1144 }
1145 
InitAlloc(const FeatureBlocks &,TPushIA Push)1146 void Legacy::InitAlloc(const FeatureBlocks& /*blocks*/, TPushIA Push)
1147 {
1148     Push(BLK_AllocRaw
1149         , [this](StorageRW& strg, StorageRW& local) -> mfxStatus
1150     {
1151         mfxStatus sts = MFX_ERR_NONE;
1152         auto& par = Glob::VideoParam::Get(strg);
1153         const mfxExtCodingOption2& CO2 = ExtBuffer::Get(par);
1154         auto& rawInfo = Tmp::RawInfo::Get(local);
1155         auto AllocRaw = [&](mfxU16 NumFrameMin)
1156         {
1157             std::unique_ptr<IAllocation> pAlloc(Tmp::MakeAlloc::Get(local)(Glob::VideoCore::Get(strg)));
1158             mfxFrameAllocRequest req = rawInfo;
1159             req.NumFrameMin = NumFrameMin;
1160 
1161             sts = pAlloc->Alloc(req, true);
1162             MFX_CHECK_STS(sts);
1163 
1164             strg.Insert(Glob::AllocRaw::Key, std::move(pAlloc));
1165 
1166             return MFX_ERR_NONE;
1167         };
1168 
1169         if (par.IOPattern == MFX_IOPATTERN_IN_SYSTEM_MEMORY)
1170         {
1171             sts = AllocRaw(rawInfo.NumFrameMin);
1172             MFX_CHECK_STS(sts);
1173         }
1174         else if (par.IOPattern == MFX_IOPATTERN_IN_OPAQUE_MEMORY)
1175         {
1176             const mfxExtOpaqueSurfaceAlloc& osa = ExtBuffer::Get(par);
1177             std::unique_ptr<IAllocation> pAllocOpq(Tmp::MakeAlloc::Get(local)(Glob::VideoCore::Get(strg)));
1178 
1179             sts = pAllocOpq->AllocOpaque(par.mfx.FrameInfo, osa.In.Type, osa.In.Surfaces, osa.In.NumSurface);
1180             MFX_CHECK_STS(sts);
1181 
1182             strg.Insert(Glob::AllocOpq::Key, std::move(pAllocOpq));
1183 
1184             if (osa.In.Type & MFX_MEMTYPE_SYSTEM_MEMORY)
1185             {
1186                 sts = AllocRaw(osa.In.NumSurface);
1187                 MFX_CHECK_STS(sts);
1188             }
1189         }
1190 
1191         bool bSkipFramesMode = (
1192             (IsSWBRC(par, &CO2)
1193                 && (par.mfx.RateControlMethod == MFX_RATECONTROL_CBR || par.mfx.RateControlMethod == MFX_RATECONTROL_VBR))
1194             || (CO2.SkipFrame == MFX_SKIPFRAME_INSERT_DUMMY))
1195             && !strg.Contains(Glob::AllocRaw::Key);
1196 
1197         if (bSkipFramesMode)
1198         {
1199             sts = AllocRaw(GetMaxBS(par));
1200             MFX_CHECK_STS(sts);
1201         }
1202 
1203         return sts;
1204     });
1205 
1206     Push(BLK_AllocBS
1207         , [this](StorageRW& strg, StorageRW& local) -> mfxStatus
1208     {
1209         mfxStatus sts = MFX_ERR_NONE;
1210         auto& par = Glob::VideoParam::Get(strg);
1211         std::unique_ptr<IAllocation> pAlloc(Tmp::MakeAlloc::Get(local)(Glob::VideoCore::Get(strg)));
1212 
1213         MFX_CHECK(local.Contains(Tmp::BSAllocInfo::Key), MFX_ERR_UNDEFINED_BEHAVIOR);
1214         auto& req = Tmp::BSAllocInfo::Get(local);
1215 
1216         SetDefault(req.NumFrameMin, GetMaxBS(par));
1217         SetDefault(req.Type
1218             , mfxU16(MFX_MEMTYPE_FROM_ENCODE
1219             | MFX_MEMTYPE_DXVA2_DECODER_TARGET
1220             | MFX_MEMTYPE_INTERNAL_FRAME));
1221 
1222         mfxU32 minBS = GetMinBsSize(par, ExtBuffer::Get(par), ExtBuffer::Get(par), ExtBuffer::Get(par));
1223 
1224         if (mfxU32(req.Info.Width * req.Info.Height) < minBS)
1225         {
1226             MFX_CHECK(req.Info.Width != 0, MFX_ERR_UNDEFINED_BEHAVIOR);
1227             req.Info.Height = (mfxU16)CeilDiv<mfxU32>(minBS, req.Info.Width);
1228         }
1229 
1230         sts = pAlloc->Alloc(req, false);
1231         MFX_CHECK_STS(sts);
1232 
1233         strg.Insert(Glob::AllocBS::Key, std::move(pAlloc));
1234 
1235         return sts;
1236     });
1237 
1238     Push(BLK_AllocMBQP
1239         , [this](StorageRW& strg, StorageRW& local) -> mfxStatus
1240     {
1241         mfxStatus sts = MFX_ERR_NONE;
1242         auto& par = Glob::VideoParam::Get(strg);
1243         const mfxExtCodingOption3& CO3 = ExtBuffer::Get(par);
1244         auto& core = Glob::VideoCore::Get(strg);
1245 
1246         MFX_CHECK(IsOn(CO3.EnableMBQP) && core.GetVAType() != MFX_HW_VAAPI, MFX_ERR_NONE);
1247 
1248         MFX_CHECK(local.Contains(Tmp::MBQPAllocInfo::Key), MFX_ERR_UNDEFINED_BEHAVIOR);
1249         auto& req = Tmp::MBQPAllocInfo::Get(local);
1250 
1251         SetDefault(req.NumFrameMin, GetMaxBS(par));
1252         SetDefault(req.Type
1253             , mfxU16(MFX_MEMTYPE_FROM_ENCODE
1254                 | MFX_MEMTYPE_DXVA2_DECODER_TARGET
1255                 | MFX_MEMTYPE_INTERNAL_FRAME));
1256 
1257         std::tie(sts, m_CUQPBlkW, m_CUQPBlkH) = GetCUQPMapBlockSize(
1258             par.mfx.FrameInfo.Width
1259             , par.mfx.FrameInfo.Height
1260             , req.Info.Width
1261             , req.Info.Height);
1262         MFX_CHECK_STS(sts);
1263 
1264         // need LCU aligned width for the buffer for proper averaging
1265         const mfxExtHEVCParam& hpar = ExtBuffer::Get(par);
1266         mfxU16 numVal = mfxU16(hpar.LCUSize / m_CUQPBlkW);
1267         if (numVal > 1)
1268             req.Info.Width = (req.Info.Width + (numVal - 1)) & ~(numVal - 1);
1269 
1270         std::unique_ptr<IAllocation> pAlloc(Tmp::MakeAlloc::Get(local)(core));
1271         sts = pAlloc->Alloc(req, true);
1272         MFX_CHECK_STS(sts);
1273 
1274         strg.Insert(Glob::AllocMBQP::Key, std::move(pAlloc));
1275 
1276         return sts;
1277     });
1278 
1279     Push(BLK_ResetState
1280         , [this](StorageRW& /*strg*/, StorageRW& /*local*/) -> mfxStatus
1281     {
1282         ResetState();
1283         return MFX_ERR_NONE;
1284     });
1285 }
1286 
Reset(const FeatureBlocks & blocks,TPushR Push)1287 void Legacy::Reset(const FeatureBlocks& blocks, TPushR Push)
1288 {
1289     Push(BLK_ResetInit
1290         , [this, &blocks](
1291             const mfxVideoParam& par
1292             , StorageRW& global
1293             , StorageRW& local) -> mfxStatus
1294     {
1295         mfxStatus wrn = MFX_ERR_NONE;
1296         auto& init = Glob::RealState::Get(global);
1297         if (par.NumExtParam != 0)
1298             MFX_CHECK(std::none_of(par.ExtParam, par.ExtParam + par.NumExtParam, [](mfxExtBuffer* buf) { return buf == nullptr; }), MFX_ERR_NULL_PTR);
1299         auto pParNew = make_storable<ExtBuffer::Param<mfxVideoParam>>(par);
1300         ExtBuffer::Param<mfxVideoParam>& parNew = *pParNew;
1301         auto& parOld = Glob::VideoParam::Get(init);
1302         auto& core = Glob::VideoCore::Get(init);
1303 
1304         global.Insert(Glob::ResetHint::Key, make_storable<ResetHint>(ResetHint{}));
1305         auto& hint = Glob::ResetHint::Get(global);
1306 
1307         const mfxExtEncoderResetOption* pResetOpt = ExtBuffer::Get(par);
1308 
1309         hint.Flags = RF_IDR_REQUIRED * (pResetOpt && IsOn(pResetOpt->StartNewSequence));
1310 
1311 
1312         m_GetMaxRef = [&](const mfxVideoParam& par)
1313         {
1314             auto& def = Glob::Defaults::Get(init);
1315             auto hw = core.GetHWType();
1316             auto& caps = Glob::EncodeCaps::Get(init);
1317             return def.GetMaxNumRef(Defaults::Param(par, caps, hw, def));
1318         };
1319 
1320         std::for_each(std::begin(blocks.m_ebCopySupported)
1321             , std::end(blocks.m_ebCopySupported)
1322             , [&](decltype(*std::begin(blocks.m_ebCopySupported)) eb) { parNew.NewEB(eb.first, false); });
1323 
1324         std::for_each(std::begin(blocks.m_mvpInheritDefault)
1325             , std::end(blocks.m_mvpInheritDefault)
1326             , [&](decltype(*std::begin(blocks.m_mvpInheritDefault)) inherit) { inherit(&parOld, &parNew); });
1327 
1328 
1329         std::for_each(std::begin(blocks.m_ebInheritDefault)
1330             , std::end(blocks.m_ebInheritDefault)
1331             , [&](decltype(*std::begin(blocks.m_ebInheritDefault)) eb)
1332         {
1333             auto pEbNew = ExtBuffer::Get(parNew, eb.first);
1334             auto pEbOld = ExtBuffer::Get(parOld, eb.first);
1335 
1336             MFX_CHECK(pEbNew && pEbOld, MFX_ERR_NONE);
1337 
1338             std::for_each(std::begin(eb.second)
1339                 , std::end(eb.second)
1340                 , [&](decltype(*std::begin(eb.second)) inherit) { inherit(parOld, pEbOld, parNew, pEbNew); });
1341 
1342             return MFX_ERR_NONE;
1343         });
1344 
1345         auto& qInitExternal = FeatureBlocks::BQ<FeatureBlocks::BQ_InitExternal>::Get(blocks);
1346         auto& qInitInternal = FeatureBlocks::BQ<FeatureBlocks::BQ_InitInternal>::Get(blocks);
1347 
1348         auto sts = RunBlocks(CheckGE<mfxStatus, MFX_ERR_NONE>, qInitExternal, parNew, global, local);
1349         MFX_CHECK(sts >= MFX_ERR_NONE, sts);
1350         wrn = sts;
1351 
1352         sts = RunBlocks(CheckGE<mfxStatus, MFX_ERR_NONE>, qInitInternal, global, local);
1353         MFX_CHECK(sts >= MFX_ERR_NONE, sts);
1354 
1355         return GetWorstSts(sts, wrn);
1356     });
1357 
1358     Push(BLK_ResetCheck
1359         , [this](
1360             const mfxVideoParam& par
1361             , StorageRW& global
1362             , StorageRW& local) -> mfxStatus
1363     {
1364         auto& init = Glob::RealState::Get(global);
1365         auto& parOld = Glob::VideoParam::Get(init);
1366         auto& parNew = Glob::VideoParam::Get(global);
1367         auto& hint = Glob::ResetHint::Get(global);
1368         auto defOld = GetRTDefaults(init);
1369         auto defNew = GetRTDefaults(global);
1370 
1371         const mfxExtEncoderResetOption* pResetOpt = ExtBuffer::Get(par);
1372 
1373         const mfxExtHEVCParam (&hevcPar)[2] = { ExtBuffer::Get(parOld), ExtBuffer::Get(parNew) };
1374         MFX_CHECK(hevcPar[0].LCUSize == hevcPar[1].LCUSize, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM); // LCU Size Can't be changed
1375 
1376         MFX_CHECK(parOld.AsyncDepth                 == parNew.AsyncDepth,                   MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
1377         MFX_CHECK(parOld.mfx.GopRefDist             >= parNew.mfx.GopRefDist,               MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
1378         MFX_CHECK(parOld.mfx.NumRefFrame            >= parNew.mfx.NumRefFrame,              MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
1379         MFX_CHECK(parOld.mfx.RateControlMethod      == parNew.mfx.RateControlMethod,        MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
1380         MFX_CHECK(parOld.mfx.FrameInfo.ChromaFormat == parNew.mfx.FrameInfo.ChromaFormat,   MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
1381         MFX_CHECK(parOld.IOPattern                  == parNew.IOPattern,                    MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
1382 
1383         MFX_CHECK(local.Contains(Tmp::RecInfo::Key), MFX_ERR_UNDEFINED_BEHAVIOR);
1384         auto  recOld = Glob::AllocRec::Get(init).GetInfo();
1385         auto& recNew = Tmp::RecInfo::Get(local).Info;
1386         MFX_CHECK(recOld.Width  >= recNew.Width,  MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
1387         MFX_CHECK(recOld.Height >= recNew.Height, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
1388         MFX_CHECK(recOld.FourCC == recNew.FourCC, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
1389 
1390         MFX_CHECK(
1391             !(   parOld.mfx.RateControlMethod == MFX_RATECONTROL_CBR
1392               || parOld.mfx.RateControlMethod == MFX_RATECONTROL_VBR
1393               || parOld.mfx.RateControlMethod == MFX_RATECONTROL_VCM)
1394             ||(  (mfxU32)InitialDelayInKB(parOld.mfx) == (mfxU32)InitialDelayInKB(parNew.mfx)
1395               && (mfxU32)BufferSizeInKB(parOld.mfx) == (mfxU32)BufferSizeInKB(parNew.mfx))
1396             , MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
1397 
1398         mfxU32 tempLayerIdx = 0;
1399         bool changeTScalLayers = false;
1400         bool isIdrRequired = false;
1401 
1402         // check if change of temporal scalability required by new parameters
1403         auto numTlOld = defOld.base.GetNumTemporalLayers(defOld);
1404         auto numTlNew = defNew.base.GetNumTemporalLayers(defNew);
1405         bool bTlActive = numTlOld > 1 && numTlNew > 1;
1406 
1407         if (bTlActive)
1408         {
1409             // calculate temporal layer for next frame
1410             tempLayerIdx = defOld.base.GetTId(defOld, m_frameOrder + 1);
1411             changeTScalLayers = numTlOld != numTlNew;
1412         }
1413 
1414         // check if IDR required after change of encoding parameters
1415         const mfxExtCodingOption2(&CO2)[2] = { ExtBuffer::Get(parOld), ExtBuffer::Get(parNew) };
1416 
1417         isIdrRequired =
1418                (hint.Flags & RF_SPS_CHANGED)
1419             || (hint.Flags & RF_IDR_REQUIRED)
1420             || (tempLayerIdx != 0 && changeTScalLayers)
1421             || parOld.mfx.GopPicSize != parNew.mfx.GopPicSize
1422             || CO2[0].IntRefType != CO2[1].IntRefType;
1423 
1424         hint.Flags |= RF_IDR_REQUIRED * isIdrRequired;
1425 
1426         MFX_CHECK(!isIdrRequired || !(pResetOpt && IsOff(pResetOpt->StartNewSequence))
1427             , MFX_ERR_INVALID_VIDEO_PARAM); // Reset can't change parameters w/o IDR. Report an error
1428 
1429         bool brcReset =
1430             (      parOld.mfx.RateControlMethod == MFX_RATECONTROL_CBR
1431                 || parOld.mfx.RateControlMethod == MFX_RATECONTROL_VBR
1432                 || parOld.mfx.RateControlMethod == MFX_RATECONTROL_VCM)
1433             && (   (mfxU32)TargetKbps(parOld.mfx) != (mfxU32)TargetKbps(parNew.mfx)
1434                 || (mfxU32)BufferSizeInKB(parOld.mfx) != (mfxU32)BufferSizeInKB(parNew.mfx)
1435                 || (mfxU32)InitialDelayInKB(parOld.mfx) != (mfxU32)InitialDelayInKB(parNew.mfx)
1436                 || parOld.mfx.FrameInfo.FrameRateExtN != parNew.mfx.FrameInfo.FrameRateExtN
1437                 || parOld.mfx.FrameInfo.FrameRateExtD != parNew.mfx.FrameInfo.FrameRateExtD);
1438 
1439         brcReset |=
1440             (      parOld.mfx.RateControlMethod == MFX_RATECONTROL_VBR
1441                 || parOld.mfx.RateControlMethod == MFX_RATECONTROL_VCM)
1442             && ((mfxU32)MaxKbps(parOld.mfx) != (mfxU32)MaxKbps(parNew.mfx));
1443 
1444         const mfxExtCodingOption(&CO)[2] = { ExtBuffer::Get(parOld), ExtBuffer::Get(parNew) };
1445         bool HRDConformance = !(IsOff(CO[1].NalHrdConformance) || IsOff(CO[1].VuiNalHrdParameters));
1446 
1447         MFX_CHECK(
1448            !(   brcReset
1449              && parOld.mfx.RateControlMethod == MFX_RATECONTROL_CBR
1450              && (HRDConformance || !isIdrRequired))
1451             , MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
1452 
1453         hint.Flags |= RF_BRC_RESET * (brcReset || isIdrRequired);
1454 
1455         return MFX_ERR_NONE;
1456     });
1457 }
1458 
ResetState(const FeatureBlocks & blocks,TPushRS Push)1459 void Legacy::ResetState(const FeatureBlocks& blocks, TPushRS Push)
1460 {
1461     Push(BLK_ResetState
1462         , [this, &blocks](
1463             StorageRW& global
1464             , StorageRW&) -> mfxStatus
1465     {
1466         auto& real = Glob::RealState::Get(global);
1467         auto& parInt = Glob::VideoParam::Get(real);
1468         auto& parNew = Glob::VideoParam::Get(global);
1469         auto& hint = Glob::ResetHint::Get(global);
1470 
1471         CopyConfigurable(blocks, parNew, parInt);
1472         Glob::VPS::Get(real) = Glob::VPS::Get(global);
1473         Glob::SPS::Get(real) = Glob::SPS::Get(global);
1474         Glob::PPS::Get(real) = Glob::PPS::Get(global);
1475         Glob::SliceInfo::Get(real) = Glob::SliceInfo::Get(global);
1476 
1477         m_forceHeaders |= !!(hint.Flags & RF_PPS_CHANGED) * INSERT_PPS;
1478 
1479         MFX_CHECK(hint.Flags & RF_IDR_REQUIRED, MFX_ERR_NONE);
1480 
1481         Glob::AllocRec::Get(real).UnlockAll();
1482         Glob::AllocBS::Get(real).UnlockAll();
1483 
1484         if (real.Contains(Glob::AllocMBQP::Key))
1485             Glob::AllocMBQP::Get(real).UnlockAll();
1486 
1487         if (real.Contains(Glob::AllocRaw::Key))
1488             Glob::AllocRaw::Get(real).UnlockAll();
1489 
1490         ResetState();
1491 
1492         return MFX_ERR_NONE;
1493     });
1494 }
1495 
FrameSubmit(const FeatureBlocks &,TPushFS Push)1496 void Legacy::FrameSubmit(const FeatureBlocks& /*blocks*/, TPushFS Push)
1497 {
1498     Push(BLK_CheckSurf
1499         , [](
1500             const mfxEncodeCtrl* /*pCtrl*/
1501             , const mfxFrameSurface1* pSurf
1502             , mfxBitstream& /*bs*/
1503             , StorageW& global
1504             , StorageRW& /*local*/) -> mfxStatus
1505     {
1506         MFX_CHECK(pSurf, MFX_ERR_NONE);
1507 
1508         auto& par = Glob::VideoParam::Get(global);
1509         MFX_CHECK(LumaIsNull(pSurf) == (pSurf->Data.UV == 0), MFX_ERR_UNDEFINED_BEHAVIOR);
1510         MFX_CHECK(pSurf->Info.Width >= par.mfx.FrameInfo.Width, MFX_ERR_INVALID_VIDEO_PARAM);
1511         MFX_CHECK(pSurf->Info.Height >= par.mfx.FrameInfo.Height, MFX_ERR_INVALID_VIDEO_PARAM);
1512 
1513         return MFX_ERR_NONE;
1514     });
1515 
1516     Push(BLK_CheckBS
1517         , [](
1518             const mfxEncodeCtrl* /*pCtrl*/
1519             , const mfxFrameSurface1* /*pSurf*/
1520             , mfxBitstream& bs
1521             , StorageW& global
1522             , StorageRW& local) -> mfxStatus
1523     {
1524         auto& par = Glob::VideoParam::Get(global);
1525         BsDataInfo bsData = {};
1526 
1527         bsData.Data       = bs.Data;
1528         bsData.DataLength = bs.DataLength;
1529         bsData.DataOffset = bs.DataOffset;
1530         bsData.MaxLength  = bs.MaxLength;
1531 
1532         if (local.Contains(Tmp::BsDataInfo::Key))
1533             bsData = Tmp::BsDataInfo::Get(local);
1534 
1535         MFX_CHECK(bsData.DataOffset <= bsData.MaxLength, MFX_ERR_UNDEFINED_BEHAVIOR);
1536         MFX_CHECK(bsData.DataOffset + bsData.DataLength + BufferSizeInKB(par.mfx) * 1000u <= bsData.MaxLength, MFX_ERR_NOT_ENOUGH_BUFFER);
1537         MFX_CHECK_NULL_PTR1(bsData.Data);
1538 
1539         return MFX_ERR_NONE;
1540     });
1541 }
1542 
AllocTask(const FeatureBlocks &,TPushAT Push)1543 void Legacy::AllocTask(const FeatureBlocks& /*blocks*/, TPushAT Push)
1544 {
1545     Push(BLK_AllocTask
1546         , [](
1547             StorageR& /*global*/
1548             , StorageRW& task) -> mfxStatus
1549     {
1550         task.Insert(Task::Common::Key, new Task::Common::TRef);
1551         task.Insert(Task::SSH::Key, new MakeStorable<Task::SSH::TRef>);
1552         return MFX_ERR_NONE;
1553     });
1554 }
1555 
InitTask(const FeatureBlocks &,TPushIT Push)1556 void Legacy::InitTask(const FeatureBlocks& /*blocks*/, TPushIT Push)
1557 {
1558     Push(BLK_InitTask
1559         , [](
1560             mfxEncodeCtrl* pCtrl
1561             , mfxFrameSurface1* pSurf
1562             , mfxBitstream* pBs
1563             , StorageW& global
1564             , StorageW& task) -> mfxStatus
1565     {
1566         auto& par = Glob::VideoParam::Get(global);
1567         auto& core = Glob::VideoCore::Get(global);
1568         auto& tpar = Task::Common::Get(task);
1569 
1570         auto stage = tpar.stage;
1571         tpar = TaskCommonPar();
1572         tpar.stage = stage;
1573         tpar.pBsOut = pBs;
1574 
1575         MFX_CHECK(pSurf, MFX_ERR_NONE);
1576 
1577         tpar.pSurfIn = pSurf;
1578 
1579         if (pCtrl)
1580             tpar.ctrl = *pCtrl;
1581 
1582         if (par.IOPattern == MFX_IOPATTERN_IN_OPAQUE_MEMORY)
1583         {
1584             tpar.pSurfReal = core.GetNativeSurface(tpar.pSurfIn);
1585             MFX_CHECK(tpar.pSurfReal, MFX_ERR_UNDEFINED_BEHAVIOR);
1586 
1587             tpar.pSurfReal->Info             = tpar.pSurfIn->Info;
1588             tpar.pSurfReal->Data.TimeStamp   = tpar.pSurfIn->Data.TimeStamp;
1589             tpar.pSurfReal->Data.FrameOrder  = tpar.pSurfIn->Data.FrameOrder;
1590             tpar.pSurfReal->Data.Corrupted   = tpar.pSurfIn->Data.Corrupted;
1591             tpar.pSurfReal->Data.DataFlag    = tpar.pSurfIn->Data.DataFlag;
1592         }
1593         else
1594             tpar.pSurfReal = tpar.pSurfIn;
1595 
1596         core.IncreaseReference(&tpar.pSurfIn->Data);
1597 
1598         return MFX_ERR_NONE;
1599     });
1600 }
1601 
PreReorderTask(const FeatureBlocks &,TPushPreRT Push)1602 void Legacy::PreReorderTask(const FeatureBlocks& /*blocks*/, TPushPreRT Push)
1603 {
1604     Push(BLK_PrepareTask
1605         , [this](
1606             StorageW& global
1607             , StorageW& s_task) -> mfxStatus
1608     {
1609         auto& par = Glob::VideoParam::Get(global);
1610         auto& task = Task::Common::Get(s_task);
1611         auto  dflts = GetRTDefaults(global);
1612 
1613         m_frameOrder = dflts.base.GetFrameOrder(dflts, s_task, m_frameOrder);
1614 
1615         auto sts = dflts.base.GetPreReorderInfo(
1616             dflts, task, task.pSurfIn, &task.ctrl, m_lastIDR, m_prevTask.PrevIPoc, m_frameOrder);
1617         MFX_CHECK_STS(sts);
1618 
1619         if (par.mfx.EncodedOrder)
1620         {
1621             auto BufferSize     = Glob::Reorder::Get(global).BufferSize;
1622             auto MaxReorder     = Glob::Reorder::Get(global).MaxReorder;
1623             bool bFrameFromPast = m_frameOrder && (m_frameOrder < m_prevTask.DisplayOrder);
1624 
1625             MFX_CHECK(!bFrameFromPast || ((m_prevTask.DisplayOrder - m_frameOrder) <= MaxReorder), MFX_ERR_UNDEFINED_BEHAVIOR);
1626             MFX_CHECK(m_frameOrder <= (m_prevTask.EncodedOrder + 1 + BufferSize), MFX_ERR_UNDEFINED_BEHAVIOR);
1627             MFX_CHECK(isValid(m_prevTask.DPB.After[0]) || IsIdr(task.FrameType), MFX_ERR_UNDEFINED_BEHAVIOR);
1628         }
1629         task.DisplayOrder = m_frameOrder;
1630         task.PrevIPoc     = m_prevTask.PrevIPoc;
1631 
1632         SetIf(m_lastIDR, IsIdr(task.FrameType), m_frameOrder);
1633         SetIf(task.PrevIPoc, IsI(task.FrameType), task.POC);
1634 
1635         return MFX_ERR_NONE;
1636     });
1637 }
1638 
PostReorderTask(const FeatureBlocks &,TPushPostRT Push)1639 void Legacy::PostReorderTask(const FeatureBlocks& /*blocks*/, TPushPostRT Push)
1640 {
1641     Push(BLK_ConfigureTask
1642         , [this](
1643             StorageW& global
1644             , StorageW& s_task) -> mfxStatus
1645     {
1646         auto& task = Task::Common::Get(s_task);
1647 
1648         if (global.Contains(Glob::AllocRaw::Key))
1649         {
1650             task.Raw = Glob::AllocRaw::Get(global).Acquire();
1651             MFX_CHECK(task.Raw.Mid, MFX_ERR_UNDEFINED_BEHAVIOR);
1652         }
1653         if (global.Contains(Glob::AllocMBQP::Key))
1654         {
1655             task.CUQP = Glob::AllocMBQP::Get(global).Acquire();
1656             MFX_CHECK(task.CUQP.Mid, MFX_ERR_UNDEFINED_BEHAVIOR);
1657         }
1658 
1659         task.Rec = Glob::AllocRec::Get(global).Acquire();
1660         task.BS = Glob::AllocBS::Get(global).Acquire();
1661         MFX_CHECK(task.BS.Idx != IDX_INVALID, MFX_ERR_UNDEFINED_BEHAVIOR);
1662         MFX_CHECK(task.Rec.Idx != IDX_INVALID, MFX_ERR_UNDEFINED_BEHAVIOR);
1663         MFX_CHECK(task.Rec.Mid && task.BS.Mid, MFX_ERR_UNDEFINED_BEHAVIOR);
1664 
1665         auto& par = Glob::VideoParam::Get(global);
1666         auto& sps = Glob::SPS::Get(global);
1667         auto& pps = Glob::PPS::Get(global);
1668         auto  def = GetRTDefaults(global);
1669 
1670         ConfigureTask(task, def, sps);
1671 
1672         auto sts = GetSliceHeader(par, task, sps, pps, Task::SSH::Get(s_task));
1673         MFX_CHECK_STS(sts);
1674 
1675         return sts;
1676     });
1677 }
1678 
SubmitTask(const FeatureBlocks &,TPushST Push)1679 void Legacy::SubmitTask(const FeatureBlocks& /*blocks*/, TPushST Push)
1680 {
1681     Push(BLK_SkipFrame
1682         , [](
1683             StorageW& global
1684             , StorageW& s_task) -> mfxStatus
1685     {
1686         auto& par = Glob::VideoParam::Get(global);
1687         auto& task = Task::Common::Get(s_task);
1688 
1689         bool bCheckSkip =
1690             !task.bSkip
1691             && IsB(task.FrameType)
1692             && !task.isLDB
1693             && IsSWBRC(par, ExtBuffer::Get(par));
1694 
1695         auto& allocRec = Glob::AllocRec::Get(global);
1696 
1697         task.bSkip |=
1698             bCheckSkip
1699             && !!(allocRec.GetFlag(task.DPB.Active[task.RefPicList[1][0]].Rec.Idx) & REC_SKIPPED);
1700 
1701         MFX_CHECK(task.bSkip, MFX_ERR_NONE);
1702 
1703         task.bForceSync = true;
1704 
1705         if (IsI(task.FrameType))
1706         {
1707             MFX_CHECK(
1708                 par.mfx.FrameInfo.FourCC == MFX_FOURCC_NV12
1709                 || par.mfx.FrameInfo.FourCC == MFX_FOURCC_P010
1710                 , MFX_ERR_UNDEFINED_BEHAVIOR);
1711 
1712             FrameLocker raw(Glob::VideoCore::Get(global), task.Raw.Mid);
1713 
1714             mfxU32 size = raw.Pitch * par.mfx.FrameInfo.Height;
1715             int UVFiller = (par.mfx.FrameInfo.FourCC == MFX_FOURCC_NV12) * 126;
1716 
1717             memset(raw.Y, 0, size);
1718             memset(raw.UV, UVFiller, size >> 1);
1719 
1720             allocRec.SetFlag(task.Rec.Idx, REC_SKIPPED);
1721 
1722             return MFX_ERR_NONE;
1723         }
1724 
1725         auto& core = Glob::VideoCore::Get(global);
1726         bool  bL1  = (IsB(task.FrameType) && !task.isLDB && task.NumRefActive[1] && !task.b2ndField);
1727         auto  idx  = task.RefPicList[bL1][0];
1728 
1729         mfxFrameSurface1 surfSrc = {};
1730         mfxFrameSurface1 surfDst = {};
1731 
1732         surfSrc.Info = par.mfx.FrameInfo;
1733         surfDst.Info = allocRec.GetInfo();
1734 
1735         MFX_CHECK(!memcmp(&surfSrc.Info, &surfDst.Info, sizeof(mfxFrameInfo)), MFX_ERR_UNDEFINED_BEHAVIOR);
1736         MFX_CHECK(idx < MAX_DPB_SIZE, MFX_ERR_UNDEFINED_BEHAVIOR);
1737 
1738         auto& ref = task.DPB.Active[idx];
1739 
1740         allocRec.SetFlag(task.Rec.Idx, REC_SKIPPED);
1741 
1742         MFX_CHECK(allocRec.GetFlag(ref.Rec.Idx) & REC_READY, MFX_ERR_NONE);
1743 
1744         surfSrc.Data.MemId = ref.Rec.Mid;
1745         surfDst.Data.MemId = task.Raw.Mid;
1746 
1747         mfxStatus sts = core.DoFastCopyWrapper(
1748             &surfDst, MFX_MEMTYPE_INTERNAL_FRAME | MFX_MEMTYPE_DXVA2_DECODER_TARGET | MFX_MEMTYPE_FROM_ENCODE,
1749             &surfSrc, MFX_MEMTYPE_INTERNAL_FRAME | MFX_MEMTYPE_DXVA2_DECODER_TARGET | MFX_MEMTYPE_FROM_ENCODE);
1750         MFX_CHECK_STS(sts);
1751 
1752         allocRec.SetFlag(ref.Rec.Idx, REC_SKIPPED * !!idx);
1753 
1754         return MFX_ERR_NONE;
1755     });
1756 
1757     Push(BLK_GetRawHDL
1758         , [](
1759             StorageW& global
1760             , StorageW& s_task) -> mfxStatus
1761     {
1762         auto& core = Glob::VideoCore::Get(global);
1763         auto& par = Glob::VideoParam::Get(global);
1764         const mfxExtOpaqueSurfaceAlloc& opaq = ExtBuffer::Get(par);
1765         auto& task = Task::Common::Get(s_task);
1766 
1767         bool bInternalFrame =
1768             par.IOPattern == MFX_IOPATTERN_IN_SYSTEM_MEMORY
1769             || (par.IOPattern == MFX_IOPATTERN_IN_OPAQUE_MEMORY
1770                 && (opaq.In.Type & MFX_MEMTYPE_SYSTEM_MEMORY))
1771             || task.bSkip;
1772 
1773         MFX_CHECK(!bInternalFrame, core.GetFrameHDL(task.Raw.Mid, &task.HDLRaw.first));
1774 
1775         MFX_CHECK(par.IOPattern != MFX_IOPATTERN_IN_VIDEO_MEMORY
1776             , core.GetExternalFrameHDL(task.pSurfReal->Data.MemId, &task.HDLRaw.first));
1777 
1778         MFX_CHECK(par.IOPattern == MFX_IOPATTERN_IN_OPAQUE_MEMORY
1779             , MFX_ERR_UNDEFINED_BEHAVIOR);
1780 
1781         return core.GetFrameHDL(task.pSurfReal->Data.MemId, &task.HDLRaw.first);
1782     });
1783 
1784     Push(BLK_CopySysToRaw
1785         , [this](
1786             StorageW& global
1787             , StorageW& s_task)->mfxStatus
1788     {
1789         auto& par = Glob::VideoParam::Get(global);
1790         const mfxExtOpaqueSurfaceAlloc& opaq = ExtBuffer::Get(par);
1791         auto& task = Task::Common::Get(s_task);
1792         auto dflts = GetRTDefaults(global);
1793 
1794         MFX_CHECK(
1795             !(task.bSkip
1796             || par.IOPattern == MFX_IOPATTERN_IN_VIDEO_MEMORY
1797             || (    par.IOPattern == MFX_IOPATTERN_IN_OPAQUE_MEMORY
1798                  && !(opaq.In.Type & MFX_MEMTYPE_SYSTEM_MEMORY)))
1799             , MFX_ERR_NONE);
1800 
1801         mfxFrameSurface1 surfSrc = { {}, par.mfx.FrameInfo, task.pSurfReal->Data };
1802         mfxFrameSurface1 surfDst = { {}, par.mfx.FrameInfo, {} };
1803         surfDst.Data.MemId = task.Raw.Mid;
1804 
1805         surfDst.Info.Shift =
1806             surfDst.Info.FourCC == MFX_FOURCC_P010
1807             || surfDst.Info.FourCC == MFX_FOURCC_Y210; // convert to native shift in core.CopyFrame() if required
1808 
1809         return  dflts.base.RunFastCopyWrapper(
1810             surfDst,
1811             MFX_MEMTYPE_INTERNAL_FRAME | MFX_MEMTYPE_DXVA2_DECODER_TARGET | MFX_MEMTYPE_FROM_ENCODE,
1812             surfSrc,
1813             MFX_MEMTYPE_EXTERNAL_FRAME | MFX_MEMTYPE_SYSTEM_MEMORY);
1814     });
1815 
1816     Push(BLK_FillCUQPSurf
1817         , [this](
1818             StorageW& global
1819             , StorageW& s_task)->mfxStatus
1820     {
1821         auto& task = Task::Common::Get(s_task);
1822 
1823         MFX_CHECK(task.CUQP.Mid && task.bCUQPMap, MFX_ERR_NONE);
1824 
1825         mfxExtMBQP *mbqp = ExtBuffer::Get(task.ctrl);
1826         auto& par = Glob::VideoParam::Get(global);
1827         auto& core = Glob::VideoCore::Get(global);
1828         auto CUQPFrameInfo = Glob::AllocMBQP::Get(global).GetInfo();
1829 
1830         MFX_CHECK(CUQPFrameInfo.Width && CUQPFrameInfo.Height, MFX_ERR_UNDEFINED_BEHAVIOR);
1831         MFX_CHECK(m_CUQPBlkW && m_CUQPBlkH, MFX_ERR_UNDEFINED_BEHAVIOR);
1832 
1833         mfxU32 drBlkW = m_CUQPBlkW;  // block size of driver
1834         mfxU32 drBlkH = m_CUQPBlkH;  // block size of driver
1835         mfxU16 inBlkSize = 16; //mbqp->BlockSize ? mbqp->BlockSize : 16;  //input block size
1836 
1837         mfxU32 pitch_MBQP = (par.mfx.FrameInfo.Width + inBlkSize - 1) / inBlkSize;
1838 
1839         MFX_CHECK(mbqp && mbqp->NumQPAlloc, MFX_ERR_NONE);
1840 
1841         // CUQPFrameInfo.Width is LCU aligned, so compute unaligned
1842         mfxU32 unalignedWidth = (par.mfx.FrameInfo.Width + drBlkW - 1) / drBlkW;
1843         bool bInvalid =
1844             (mbqp->NumQPAlloc * inBlkSize * inBlkSize) < (drBlkW * drBlkH * unalignedWidth * CUQPFrameInfo.Height);
1845         bInvalid &= (drBlkW < inBlkSize || drBlkH < inBlkSize); // needs changing filling loop
1846 
1847         task.bCUQPMap &= !bInvalid;
1848         MFX_CHECK(!bInvalid, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
1849 
1850         FrameLocker lock(core, task.CUQP.Mid);
1851         MFX_CHECK(lock.Y, MFX_ERR_LOCK_MEMORY);
1852 
1853         auto itSrcRow   = MakeStepIter(mbqp->QP, drBlkH / inBlkSize * pitch_MBQP);
1854         auto itDstRow   = MakeStepIter(lock.Y, lock.Pitch);
1855         auto stepSrcRow = drBlkW / inBlkSize;
1856 
1857         std::for_each(itSrcRow, std::next(itSrcRow, CUQPFrameInfo.Height)
1858             , [&](mfxU8& rSrcRowBegin)
1859         {
1860             std::copy_n(MakeStepIter(&rSrcRowBegin, stepSrcRow), unalignedWidth, &*itDstRow);
1861             // fill till EO LCU aligned width
1862             auto ItLastPos = MakeStepIter(&*itDstRow++ + unalignedWidth - 1);
1863             std::fill_n(std::next(ItLastPos), CUQPFrameInfo.Width - unalignedWidth, *ItLastPos);
1864         });
1865 
1866         return MFX_ERR_NONE;
1867     });
1868 }
1869 
QueryTask(const FeatureBlocks &,TPushQT Push)1870 void Legacy::QueryTask(const FeatureBlocks& /*blocks*/, TPushQT Push)
1871 {
1872     Push(BLK_CopyBS
1873         , [](StorageW& global, StorageW& s_task) -> mfxStatus
1874     {
1875         auto& task = Task::Common::Get(s_task);
1876 
1877         if (!task.pBsData)
1878         {
1879             auto& bs              = *task.pBsOut;
1880             task.pBsData          = bs.Data + bs.DataOffset + bs.DataLength;
1881             task.pBsDataLength    = &bs.DataLength;
1882             task.BsBytesAvailable = bs.MaxLength - bs.DataOffset - bs.DataLength;
1883         }
1884 
1885         MFX_CHECK(task.BsDataLength, MFX_ERR_NONE);
1886 
1887         mfxStatus sts = MFX_ERR_NONE;
1888 
1889         MFX_CHECK(task.BsBytesAvailable >= task.BsDataLength, MFX_ERR_NOT_ENOUGH_BUFFER);
1890 
1891         FrameLocker codedFrame(Glob::VideoCore::Get(global), task.BS.Mid);
1892         MFX_CHECK(codedFrame.Y, MFX_ERR_LOCK_MEMORY);
1893 
1894         sts = FastCopy::Copy(
1895             task.pBsData
1896             , task.BsDataLength
1897             , codedFrame.Y
1898             , codedFrame.Pitch
1899             , { int(task.BsDataLength), 1 }
1900             , COPY_VIDEO_TO_SYS);
1901         MFX_CHECK_STS(sts);
1902 
1903         task.BsBytesAvailable -= task.BsDataLength;
1904 
1905         return MFX_ERR_NONE;
1906     });
1907 
1908     Push(BLK_DoPadding
1909         , [](StorageW& /*global*/, StorageW& s_task) -> mfxStatus
1910     {
1911         auto& task = Task::Common::Get(s_task);
1912 
1913         MFX_CHECK(task.MinFrameSize >= task.BsDataLength, MFX_ERR_NONE);
1914         MFX_CHECK(!task.bDontPatchBS, MFX_ERR_UNDEFINED_BEHAVIOR);
1915 
1916         mfxU32 padding = task.MinFrameSize - task.BsDataLength;
1917 
1918         MFX_CHECK(task.BsBytesAvailable >= padding, MFX_ERR_NOT_ENOUGH_BUFFER);
1919 
1920         memset(task.pBsData + task.BsDataLength, 0, padding);
1921 
1922         task.BsDataLength += padding;
1923         task.BsBytesAvailable -= padding;
1924 
1925         return MFX_ERR_NONE;
1926     });
1927 
1928     Push(BLK_UpdateBsInfo
1929         , [](StorageW& global, StorageW& s_task) -> mfxStatus
1930     {
1931         const auto& par = Glob::VideoParam::Get(global);
1932         auto& task = Task::Common::Get(s_task);
1933         auto& sps = Glob::SPS::Get(global);
1934         auto& bs = *task.pBsOut;
1935         mfxI32 dpbOutputDelay =
1936             task.DisplayOrder
1937             + sps.sub_layer[sps.max_sub_layers_minus1].max_num_reorder_pics
1938             - task.EncodedOrder;
1939 
1940         bs.TimeStamp = task.pSurfIn->Data.TimeStamp;
1941         bs.DecodeTimeStamp = MFX_TIMESTAMP_UNKNOWN;
1942 
1943         if (bs.TimeStamp != mfxU64(MFX_TIMESTAMP_UNKNOWN))
1944         {
1945             mfxF64 tcDuration90KHz = (mfxF64)par.mfx.FrameInfo.FrameRateExtD / par.mfx.FrameInfo.FrameRateExtN * 90000;
1946             bs.DecodeTimeStamp = mfxI64(bs.TimeStamp - tcDuration90KHz * dpbOutputDelay);
1947         }
1948 
1949         bs.PicStruct = task.pSurfIn->Info.PicStruct;
1950         bs.FrameType = task.FrameType;
1951         bs.FrameType &= ~(task.isLDB * MFX_FRAMETYPE_B);
1952         bs.FrameType |= task.isLDB * MFX_FRAMETYPE_P;
1953 
1954         *task.pBsDataLength += task.BsDataLength;
1955 
1956         return MFX_ERR_NONE;
1957     });
1958 }
1959 
ReleaseResource(IAllocation & a,Resource & r)1960 inline bool ReleaseResource(IAllocation& a, Resource& r)
1961 {
1962     if (r.Mid)
1963     {
1964         a.Release(r.Idx);
1965         r = Resource();
1966         return true;
1967     }
1968 
1969     return r.Idx == IDX_INVALID;
1970 }
1971 
FreeTask(const FeatureBlocks &,TPushFT Push)1972 void Legacy::FreeTask(const FeatureBlocks& /*blocks*/, TPushFT Push)
1973 {
1974     Push(BLK_FreeTask
1975         , [](StorageW& global, StorageW& s_task) -> mfxStatus
1976     {
1977         auto& task = Task::Common::Get(s_task);
1978         auto& core = Glob::VideoCore::Get(global);
1979 
1980         ThrowAssert(
1981             !ReleaseResource(Glob::AllocBS::Get(global), task.BS)
1982             , "task.BS resource is invalid");
1983         ThrowAssert(
1984             global.Contains(Glob::AllocMBQP::Key)
1985             && !ReleaseResource(Glob::AllocMBQP::Get(global), task.CUQP)
1986             , "task.CUQP resource is invalid");
1987         ThrowAssert(
1988             global.Contains(Glob::AllocRaw::Key)
1989             && !ReleaseResource(Glob::AllocRaw::Get(global), task.Raw)
1990             , "task.Raw resource is invalid");
1991 
1992         SetIf(task.pSurfIn, task.pSurfIn && !core.DecreaseReference(&task.pSurfIn->Data), nullptr);
1993         ThrowAssert(!!task.pSurfIn, "failed in core.DecreaseReference");
1994 
1995         auto& atrRec = Glob::AllocRec::Get(global);
1996 
1997         if (task.Rec.Idx != IDX_INVALID)
1998             atrRec.SetFlag(task.Rec.Idx, REC_READY);
1999 
2000         ThrowAssert(
2001             !IsRef(task.FrameType)
2002             && !ReleaseResource(atrRec, task.Rec)
2003             , "task.Rec resource is invalid");
2004 
2005         auto pDPBBeforeEnd = std::find_if_not(
2006             task.DPB.Before, task.DPB.Before + Size(task.DPB.Before), isValid);
2007         auto pDPBAfterEnd = std::find_if_not(
2008             task.DPB.After, task.DPB.After + Size(task.DPB.After), isValid);
2009         auto DPBFrameReleaseVerify = [&](DpbFrame& ref)
2010         {
2011             auto IsSameRecIdx = [&](DpbFrame& refA) { return refA.Rec.Idx == ref.Rec.Idx; };
2012             return pDPBAfterEnd != std::find_if(task.DPB.After, pDPBAfterEnd, IsSameRecIdx)
2013                 || ReleaseResource(atrRec, ref.Rec);
2014         };
2015         auto nDPBFramesValid = std::count_if(task.DPB.Before, pDPBBeforeEnd, DPBFrameReleaseVerify);
2016 
2017         ThrowAssert(nDPBFramesValid != (pDPBBeforeEnd - task.DPB.Before), "task.DPB.Before is invalid");
2018 
2019         return MFX_ERR_NONE;
2020     });
2021 }
2022 
GetVideoParam(const FeatureBlocks & blocks,TPushGVP Push)2023 void Legacy::GetVideoParam(const FeatureBlocks& blocks, TPushGVP Push)
2024 {
2025     Push(BLK_CopyConfigurable
2026         , [this, &blocks](mfxVideoParam& out, StorageR& global) -> mfxStatus
2027     {
2028         return CopyConfigurable(blocks, Glob::VideoParam::Get(global), out);
2029     });
2030 }
2031 
GetIntraRefreshState(const ExtBuffer::Param<mfxVideoParam> & par,const mfxEncodeCtrl & ctrl,mfxU32 frameOrderInGopDispOrder,mfxU32 IntraRefreshBlockUnitSize)2032 IntraRefreshState GetIntraRefreshState(
2033     const ExtBuffer::Param<mfxVideoParam> & par
2034     , const mfxEncodeCtrl& ctrl
2035     , mfxU32                frameOrderInGopDispOrder
2036     , mfxU32                IntraRefreshBlockUnitSize)
2037 {
2038     IntraRefreshState state={};
2039     const mfxExtCodingOption2& CO2       = ExtBuffer::Get(par);
2040     const mfxExtCodingOption3& CO3       = ExtBuffer::Get(par);
2041     const mfxExtHEVCParam&     HEVCParam = ExtBuffer::Get(par);
2042     const mfxExtCodingOption2* pCO2RT    = ExtBuffer::Get(ctrl);
2043 
2044     mfxU32 refreshPeriod             = std::max<mfxU32>(CO3.IntRefCycleDist + (!CO3.IntRefCycleDist * CO2.IntRefCycleSize), 1);
2045     mfxU32 offsetFromStartOfGop      = std::max<mfxU32>(!!CO3.IntRefCycleDist * refreshPeriod, 1); // 1st refresh cycle in GOP starts with offset
2046     mfxI32 frameOrderMinusOffset     = frameOrderInGopDispOrder - offsetFromStartOfGop;
2047     mfxU32 frameOrderInRefreshPeriod = frameOrderMinusOffset % refreshPeriod;
2048 
2049     state.firstFrameInCycle = false;
2050 
2051     bool bNoUpdate =
2052         CO2.IntRefType == 0
2053         || frameOrderMinusOffset < 0 // too early to start refresh
2054         || frameOrderInRefreshPeriod >= CO2.IntRefCycleSize; // for current refresh period refresh cycle is already passed
2055 
2056     if (bNoUpdate)
2057         return state;
2058 
2059     mfxU32 IRBlockSize = 1 << (3 + IntraRefreshBlockUnitSize);
2060     // refreshing parts (stripes) in frame
2061     mfxU32 refreshDimension = CO2.IntRefType == MFX_REFRESH_HORIZONTAL
2062         ? CeilDiv<mfxU32>(HEVCParam.PicHeightInLumaSamples, IRBlockSize)
2063         : CeilDiv<mfxU32>(HEVCParam.PicWidthInLumaSamples, IRBlockSize);
2064 
2065     // In most cases number of refresh stripes is no aligned with number of frames for refresh.
2066     // In head frames are refreshed min stripes (can be 0), in tail min+1
2067     // min * head + (min+1) * tail == min * frames + tail == refreshDimension
2068     mfxU32 frames   = CO2.IntRefCycleSize;          // frames to commit full refresh
2069     mfxU32 minStr   = refreshDimension / frames;    // minimal refreshed stripes
2070     mfxU32 tail     = refreshDimension % frames;    // tail frames have minStr+1 stripes
2071     mfxU32 head     = frames - tail;                // head frames with minStr stripes
2072 
2073     if (frameOrderInRefreshPeriod < head) // min, can be 0
2074     {
2075         if (!minStr)
2076             return state; // actual refresh isn't started yet within current refresh cycle, no Intra column/row required for current frame
2077 
2078         state.IntraSize     = (mfxU16)minStr;
2079         state.IntraLocation = (mfxU16)(frameOrderInRefreshPeriod * minStr);
2080     }
2081     else
2082     {
2083         state.IntraSize     = (mfxU16)(minStr + 1);
2084         state.IntraLocation = (mfxU16)(frameOrderInRefreshPeriod * minStr + (frameOrderInRefreshPeriod - head));
2085     }
2086 
2087     state.firstFrameInCycle = (frameOrderInRefreshPeriod == 0);
2088     state.refrType          = CO2.IntRefType;
2089 
2090     // set QP for Intra macroblocks within refreshing line
2091     state.IntRefQPDelta = CO2.IntRefQPDelta;
2092 
2093     bool bUpdateQPDelta = pCO2RT && pCO2RT->IntRefQPDelta <= 51 && pCO2RT->IntRefQPDelta >= -51;
2094     if (bUpdateQPDelta)
2095         state.IntRefQPDelta = pCO2RT->IntRefQPDelta;
2096 
2097     return state;
2098 }
2099 
GetCodingType(const TaskCommonPar & task)2100 mfxU8 GetCodingType(const TaskCommonPar & task)
2101 {
2102     const mfxU8 I  = 1; // I picture.
2103     const mfxU8 P  = 2; // P or GPB picture at base temporal level.
2104     const mfxU8 B  = 3; // P, GPB or B picture at temporal level 1.
2105     const mfxU8 B1 = 4; // P, GPB or B picture at temporal level 2.
2106     const mfxU8 B2 = 5; // P, GPB or B picture at temporal level 3.
2107 
2108     auto IsBX = [&](mfxU8 idx)
2109     {
2110         auto& ref = task.DPB.Active[idx];
2111         return !ref.isLDB && ref.CodingType > B;
2112     };
2113     auto IsB0 = [&](mfxU8 idx)
2114     {
2115         auto& ref = task.DPB.Active[idx];
2116         return !ref.isLDB && ref.CodingType == B;
2117     };
2118     mfxU8 type = 0;
2119     type += I * IsI(task.FrameType);
2120     type += P * (!type && IsP(task.FrameType));
2121     type += B * (!type && task.isLDB);
2122     type += B2 * (!type && std::any_of(task.RefPicList[0], task.RefPicList[0] + task.NumRefActive[0], IsBX));
2123     type += B2 * (!type && std::any_of(task.RefPicList[1], task.RefPicList[1] + task.NumRefActive[1], IsBX));
2124     type += B1 * (!type && std::any_of(task.RefPicList[0], task.RefPicList[0] + task.NumRefActive[0], IsB0));
2125     type += B1 * (!type && std::any_of(task.RefPicList[1], task.RefPicList[1] + task.NumRefActive[1], IsB0));
2126     type += B * !type;
2127 
2128     return type;
2129 }
2130 
2131 class SkipMode
2132 {
2133 private:
2134     eSkipMode m_mode;
2135     mfxU32 m_cmd;
2136 
SetCMD()2137     void SetCMD()
2138     {
2139         m_cmd = 0;
2140         m_cmd |= NeedInputReplacement()     * SKIPCMD_NeedInputReplacement;
2141         m_cmd |= NeedDriverCall()           * SKIPCMD_NeedDriverCall;
2142         m_cmd |= NeedSkipSliceGen()         * SKIPCMD_NeedSkipSliceGen;
2143         m_cmd |= NeedCurrentFrameSkipping() * SKIPCMD_NeedCurrentFrameSkipping;
2144         m_cmd |= NeedNumSkipAdding()        * SKIPCMD_NeedNumSkipAdding;
2145     }
2146 public:
SkipMode(eSkipMode mode=SKIPFRAME_NO)2147     SkipMode(eSkipMode mode = SKIPFRAME_NO)
2148         : m_mode(mode)
2149     {
2150         SetCMD();
2151     }
2152 
SkipMode(mfxU16 mode,bool bProtected)2153     SkipMode(mfxU16 mode, bool bProtected)
2154     {
2155         SetMode(mode, bProtected);
2156     }
2157 
SetMode(mfxU16 skipModeMFX,bool bProtected)2158     void SetMode(mfxU16 skipModeMFX, bool bProtected)
2159     {
2160         m_mode = eSkipMode(
2161             SKIPFRAME_INSERT_DUMMY_PROTECTED * (skipModeMFX == MFX_SKIPFRAME_INSERT_DUMMY && bProtected)
2162             + SKIPFRAME_INSERT_DUMMY         * (skipModeMFX == MFX_SKIPFRAME_INSERT_DUMMY && !bProtected)
2163             + SKIPFRAME_INSERT_NOTHING       * (skipModeMFX == MFX_SKIPFRAME_INSERT_NOTHING)
2164             + SKIPFRAME_BRC_ONLY             * (skipModeMFX == MFX_SKIPFRAME_BRC_ONLY));
2165         SetCMD();
2166     }
2167 
SetPseudoSkip()2168     void SetPseudoSkip()
2169     {
2170         m_mode = SKIPFRAME_EXT_PSEUDO;
2171     }
2172 
GetMode()2173     eSkipMode GetMode() { return m_mode; }
GetCMD()2174     mfxU32 GetCMD() { return m_cmd; }
2175 
NeedInputReplacement()2176     bool NeedInputReplacement()
2177     {
2178         return m_mode == SKIPFRAME_EXT_PSEUDO;
2179     }
NeedDriverCall()2180     bool NeedDriverCall()
2181     {
2182         return m_mode == SKIPFRAME_INSERT_DUMMY_PROTECTED
2183             || m_mode == SKIPFRAME_EXT_PSEUDO
2184             || m_mode == SKIPFRAME_NO
2185             || m_mode == SKIPFRAME_EXT_PSEUDO;
2186     }
NeedSkipSliceGen()2187     bool NeedSkipSliceGen()
2188     {
2189         return m_mode == SKIPFRAME_INSERT_DUMMY_PROTECTED
2190             || m_mode == SKIPFRAME_INSERT_DUMMY;
2191     }
NeedCurrentFrameSkipping()2192     bool NeedCurrentFrameSkipping()
2193     {
2194         return m_mode == SKIPFRAME_INSERT_DUMMY_PROTECTED
2195             || m_mode == SKIPFRAME_INSERT_DUMMY
2196             || m_mode == SKIPFRAME_INSERT_NOTHING;
2197     }
NeedNumSkipAdding()2198     bool NeedNumSkipAdding()
2199     {
2200         return m_mode == SKIPFRAME_BRC_ONLY;
2201     }
2202 };
2203 
SetTaskQpY(TaskCommonPar & task,const ExtBuffer::Param<mfxVideoParam> & par,const SPS & sps,const Defaults::Param & dflts)2204 static void SetTaskQpY(
2205     TaskCommonPar & task
2206     , const ExtBuffer::Param<mfxVideoParam> & par
2207     , const SPS& sps
2208     , const Defaults::Param& dflts)
2209 {
2210     const auto& hw = dflts.hw;
2211     const mfxExtCodingOption2& CO2 = ExtBuffer::Get(par);
2212     const mfxExtCodingOption3& CO3 = ExtBuffer::Get(par);
2213     const mfxU8 maxQP = mfxU8(51 + 6 * (CO3.TargetBitDepthLuma - 8));
2214 
2215     if (par.mfx.RateControlMethod != MFX_RATECONTROL_CQP)
2216     {
2217         task.QpY &= 0xff * (par.mfx.RateControlMethod == MFX_RATECONTROL_LA_EXT);
2218         return;
2219     }
2220 
2221     bool bUseQPP = IsP(task.FrameType) || task.isLDB;
2222     bool bUseQPB = !bUseQPP && IsB(task.FrameType);
2223     bool bUseQPOffset =
2224         (bUseQPB && CO2.BRefType == MFX_B_REF_PYRAMID)
2225         || (bUseQPP && CO3.PRefType == MFX_P_REF_PYRAMID);
2226 
2227     // set coding type and QP
2228     if (bUseQPB)
2229     {
2230         task.QpY = (mfxI8)par.mfx.QPB;
2231         if (bUseQPOffset)
2232         {
2233             task.QpY = (mfxI8)mfx::clamp<mfxI32>(
2234                 CO3.QPOffset[mfx::clamp<mfxI32>(task.PyramidLevel - 1, 0, 7)] + task.QpY
2235                 , 1, maxQP);
2236         }
2237     }
2238     else if (bUseQPP)
2239     {
2240         // encode P as GPB
2241         task.QpY = (mfxI8)par.mfx.QPP;
2242 
2243         if (dflts.base.GetNumTemporalLayers(dflts) > 1)
2244         {
2245             task.QpY = (mfxI8)mfx::clamp<mfxI32>(CO3.QPOffset[task.TemporalID] + task.QpY, 1, maxQP);
2246         }
2247         else if (bUseQPOffset)
2248         {
2249             task.QpY = (mfxI8)mfx::clamp<mfxI32>(
2250                 CO3.QPOffset[std::min<size_t>(task.PyramidLevel, Size(CO3.QPOffset) - 1)] + task.QpY
2251                 , 1, maxQP);
2252         }
2253     }
2254     else
2255     {
2256         assert(IsI(task.FrameType));
2257         task.QpY = (mfxI8)par.mfx.QPI;
2258     }
2259 
2260     SetIf(task.QpY, !!task.ctrl.QP, (mfxI8)task.ctrl.QP);
2261 
2262     task.QpY -= 6 * sps.bit_depth_luma_minus8;
2263     task.QpY &= 0xff * !(task.QpY < 0 && (IsOn(par.mfx.LowPower) || (hw >= MFX_HW_KBL && hw <= MFX_HW_CNL)));
2264 }
2265 
ConfigureTask(TaskCommonPar & task,const Defaults::Param & dflts,const SPS & sps)2266 void Legacy::ConfigureTask(
2267     TaskCommonPar & task
2268     , const Defaults::Param& dflts
2269     , const SPS& sps)
2270 {
2271     auto&                      par = dflts.mvp;
2272     const mfxExtCodingOption&  CO  = ExtBuffer::Get(par);
2273     const mfxExtCodingOption2& CO2 = ExtBuffer::Get(par);
2274     const mfxExtCodingOption3& CO3 = ExtBuffer::Get(par);
2275     const bool isI    = IsI(task.FrameType);
2276     const bool isP    = IsP(task.FrameType);
2277     const bool isIDR  = IsIdr(task.FrameType);
2278 
2279     mfxExtAVCRefLists*    pExtLists    = ExtBuffer::Get(task.ctrl);
2280     mfxExtAVCRefListCtrl* pExtListCtrl = ExtBuffer::Get(task.ctrl);
2281 
2282     {
2283         const mfxExtCodingOption2* pCO2 = ExtBuffer::Get(task.ctrl);
2284         SkipMode mode;
2285 
2286         SetDefault(pCO2, &CO2);
2287 
2288         mode.SetMode(mfxU16(!!task.ctrl.SkipFrame * pCO2->SkipFrame), !!par.Protected);
2289 
2290         task.FrameType &= ~(MFX_FRAMETYPE_REF
2291             * (mode.NeedCurrentFrameSkipping() && par.mfx.GopRefDist == 1 && isP));
2292 
2293 
2294         if (IsRef(task.FrameType))
2295         {
2296             task.ctrl.SkipFrame = 0;
2297             mode.SetMode(MFX_SKIPFRAME_NO_SKIP, !!par.Protected);
2298         }
2299 
2300         task.SkipCMD = mode.GetCMD();
2301     }
2302 
2303     task.ctrl.MfxNalUnitType &= 0xffff * IsOn(CO3.EnableNalUnitType);
2304 
2305     const mfxExtMBQP *pMBQP = ExtBuffer::Get(task.ctrl);
2306     task.bCUQPMap |= (IsOn(CO3.EnableMBQP) && pMBQP && pMBQP->NumQPAlloc > 0);
2307 
2308     bool bUpdateIRState = task.TemporalID == 0 && CO2.IntRefType;
2309     if (bUpdateIRState)
2310     {
2311         m_baseLayerOrder *= !isI;
2312         task.IRState = GetIntraRefreshState(
2313             par, task.ctrl, m_baseLayerOrder++, dflts.caps.IntraRefreshBlockUnitSize);
2314     }
2315 
2316     if (IsTCBRC(par, dflts.caps.TCBRCSupport) && task.TCBRCTargetFrameSize == 0)
2317     {
2318         ThrowAssert(par.mfx.FrameInfo.FrameRateExtD == 0, "FrameRateExtD = 0");
2319 
2320         mfxU32 AvgFrameSizeInBytes = mfxU32(1000.0 / 8.0*(par.mfx.TargetKbps) * std::max<mfxU32>(par.mfx.BRCParamMultiplier,1) /
2321             (mfxF64(par.mfx.FrameInfo.FrameRateExtN) / par.mfx.FrameInfo.FrameRateExtD));
2322         task.TCBRCTargetFrameSize = AvgFrameSizeInBytes;
2323     }
2324 
2325     mfxU32 needRecoveryPointSei = (CO.RecoveryPointSEI == MFX_CODINGOPTION_ON
2326         && (   (CO2.IntRefType && task.IRState.firstFrameInCycle && task.IRState.IntraLocation == 0)
2327             || (CO2.IntRefType == 0 && isI)));
2328     mfxU32 needCpbRemovalDelay = isIDR || needRecoveryPointSei;
2329     const bool isRef = IsRef(task.FrameType);
2330 
2331     // encode P as GPB
2332     task.isLDB      = IsOn(CO3.GPB) && isP;
2333     task.FrameType &= ~(MFX_FRAMETYPE_P * task.isLDB);
2334     task.FrameType |= (MFX_FRAMETYPE_B * task.isLDB);
2335 
2336     task.PrevIPoc = m_prevTask.PrevIPoc;
2337     task.PrevRAP = m_prevTask.PrevRAP;
2338     task.EncodedOrder = m_prevTask.EncodedOrder + 1;
2339 
2340     InitDPB(task, m_prevTask, pExtListCtrl);
2341 
2342     //construct ref lists
2343     std::tie(task.NumRefActive[0], task.NumRefActive[1]) = dflts.base.GetFrameNumRefActive(dflts, task);
2344 
2345     if (!isI)
2346     {
2347         ConstructRPL(dflts, task.DPB.Active, task, task.RefPicList, task.NumRefActive, pExtLists, pExtListCtrl);
2348     }
2349 
2350     SetTaskQpY(task, par, sps, dflts);
2351     task.CodingType = GetCodingType(task);
2352 
2353     task.InsertHeaders |= m_forceHeaders;
2354     m_forceHeaders = 0;
2355 
2356     task.InsertHeaders |= (INSERT_VPS | INSERT_SPS | INSERT_PPS) * isIDR;
2357     task.InsertHeaders |= INSERT_BPSEI * (needCpbRemovalDelay && sps.vui.hrd_parameters_present_flag );
2358     task.InsertHeaders |= INSERT_PTSEI
2359                 * (sps.vui.frame_field_info_present_flag
2360                 || sps.vui.hrd.nal_hrd_parameters_present_flag
2361                 || sps.vui.hrd.vcl_hrd_parameters_present_flag);
2362     task.InsertHeaders |= INSERT_PPS * IsOn(CO2.RepeatPPS);
2363     task.InsertHeaders |= INSERT_AUD * IsOn(CO.AUDelimiter);
2364 
2365     // update dpb
2366     std::copy(task.DPB.Active, task.DPB.Active + Size(task.DPB.Active), task.DPB.After);
2367     Remove(task.DPB.After, 0, MAX_DPB_SIZE * isIDR);
2368 
2369     if (isRef)
2370     {
2371         task.PrevIPoc = isI * task.POC + !isI * task.PrevIPoc;
2372 
2373         UpdateDPB(dflts, task, task.DPB.After, pExtListCtrl);
2374 
2375         using TRLtrDesc = decltype(pExtListCtrl->LongTermRefList[0]);
2376         auto IsCurFrame = [&](TRLtrDesc ltr)
2377         {
2378             return ltr.FrameOrder == task.DisplayOrder;
2379         };
2380 
2381         task.isLTR |=
2382             pExtListCtrl
2383             && std::any_of(
2384                 std::begin(pExtListCtrl->LongTermRefList)
2385                 , std::end(pExtListCtrl->LongTermRefList)
2386                 , IsCurFrame);
2387     }
2388 
2389     task.SliceNUT = dflts.base.GetSHNUT(dflts, task, true);
2390 
2391     bool bRAP =
2392         task.SliceNUT == CRA_NUT
2393         || task.SliceNUT == IDR_W_RADL
2394         || task.SliceNUT == IDR_N_LP;
2395 
2396     task.PrevRAP = bRAP * task.POC + !bRAP * task.PrevRAP;
2397 
2398     task.StatusReportId = std::max<mfxU32>(1, m_prevTask.StatusReportId + 1);
2399     task.bForceSync = !!(task.InsertHeaders & INSERT_BPSEI);
2400 
2401     if (task.FrameType & MFX_FRAMETYPE_I)
2402     {
2403         task.m_minQP = CO2.MinQPI;
2404         task.m_maxQP = CO2.MaxQPI;
2405     }
2406     else if (task.FrameType & MFX_FRAMETYPE_P)
2407     {
2408         task.m_minQP = CO2.MinQPP;
2409         task.m_maxQP = CO2.MaxQPP;
2410     }
2411     else if (task.FrameType & MFX_FRAMETYPE_B)
2412     {
2413         task.m_minQP = CO2.MinQPB;
2414         task.m_maxQP = CO2.MaxQPB;
2415     }
2416 
2417     m_prevTask = task;
2418 }
2419 
CountL1(DpbArray const & dpb,mfxI32 poc)2420 static mfxU32 CountL1(DpbArray const & dpb, mfxI32 poc)
2421 {
2422     mfxU32 c = 0;
2423     for (mfxU32 i = 0; !isDpbEnd(dpb, i); i++)
2424         c += dpb[i].POC > poc;
2425     return c;
2426 }
2427 
GetEncodingOrder(mfxU32 displayOrder,mfxU32 begin,mfxU32 end,mfxU32 & level,mfxU32 before,bool & ref)2428 static mfxU32 GetEncodingOrder(
2429     mfxU32 displayOrder
2430     , mfxU32 begin
2431     , mfxU32 end
2432     , mfxU32 &level
2433     , mfxU32 before
2434     , bool & ref)
2435 {
2436     assert(displayOrder >= begin);
2437     assert(displayOrder <  end);
2438 
2439     ref = (end - begin > 1);
2440 
2441     mfxU32 pivot = (begin + end) / 2;
2442     if (displayOrder == pivot)
2443         return level + before;
2444 
2445     level++;
2446     if (displayOrder < pivot)
2447         return GetEncodingOrder(displayOrder, begin, pivot, level, before, ref);
2448     else
2449         return GetEncodingOrder(displayOrder, pivot + 1, end, level, before + pivot - begin, ref);
2450 }
2451 
GetBiFrameLocation(mfxU32 i,mfxU32 num,bool & ref,mfxU32 & level)2452 mfxU32 Legacy::GetBiFrameLocation(mfxU32 i, mfxU32 num, bool &ref, mfxU32 &level)
2453 {
2454     ref = false;
2455     level = 1;
2456     return GetEncodingOrder(i, 0, num, level, 0, ref);
2457 }
2458 
BPyrReorder(TItWrapIt begin,TItWrapIt end)2459 Legacy::TItWrapIt Legacy::BPyrReorder(TItWrapIt begin, TItWrapIt end)
2460 {
2461     using TRef = std::iterator_traits<TItWrapIt>::reference;
2462 
2463     mfxU32 num = mfxU32(std::distance(begin, end));
2464     bool bSetOrder = num && (*begin)->BPyramidOrder == mfxU32(MFX_FRAMEORDER_UNKNOWN);
2465 
2466     if (bSetOrder)
2467     {
2468         mfxU32 i = 0;
2469         std::for_each(begin, end, [&](TRef bref)
2470         {
2471             bool bRef = false;
2472             bref->BPyramidOrder = Legacy::GetBiFrameLocation(i++, num, bRef, bref->PyramidLevel);
2473             bref->FrameType |= mfxU16(MFX_FRAMETYPE_REF * bRef);
2474         });
2475     }
2476 
2477     return std::min_element(begin, end
2478         , [](TRef a, TRef b) { return a->BPyramidOrder < b->BPyramidOrder; });
2479 }
2480 
Reorder(ExtBuffer::Param<mfxVideoParam> const & par,DpbArray const & dpb,TItWrap begin,TItWrap end,bool flush)2481 Legacy::TItWrap Legacy::Reorder(
2482     ExtBuffer::Param<mfxVideoParam> const & par
2483     , DpbArray const & dpb
2484     , TItWrap begin
2485     , TItWrap end
2486     , bool flush)
2487 {
2488     using TRef = TItWrap::reference;
2489 
2490     const mfxExtCodingOption2& CO2 = ExtBuffer::Get(par);
2491     bool isBPyramid = (CO2.BRefType == MFX_B_REF_PYRAMID);
2492     TItWrap top = begin;
2493     std::list<TItWrap> brefs;
2494     auto IsB = [](TRef f) { return HEVCEHW::IsB(f.FrameType); };
2495     auto NoL1 = [&](TItWrap& f) { return !CountL1(dpb, f->POC); };
2496 
2497     std::generate_n(
2498         std::back_inserter(brefs)
2499         , std::distance(begin, std::find_if_not(begin, end, IsB))
2500         , [&]() { return top++; });
2501 
2502     brefs.remove_if(NoL1);
2503 
2504     bool bNoPyramidB = !isBPyramid && !brefs.empty();
2505     if (bNoPyramidB)
2506     {
2507         auto B0POC = brefs.front()->POC;
2508         auto RefB = [B0POC](TItWrap& f)
2509         {
2510             return IsRef(f->FrameType) && (f->POC - B0POC < 2);
2511         };
2512         TItWrapIt BCand[2] =
2513         {
2514             std::find_if(brefs.begin() , brefs.end(), RefB)
2515             , brefs.begin()
2516         };
2517 
2518         return *BCand[BCand[0] == brefs.end()];
2519     }
2520 
2521     if (!brefs.empty())
2522         return *BPyrReorder(brefs.begin(), brefs.end());
2523 
2524     bool bForcePRef = flush && top == end && begin != end;
2525     if (bForcePRef)
2526     {
2527         --top;
2528         top->FrameType = mfxU16(MFX_FRAMETYPE_P | MFX_FRAMETYPE_REF);
2529     }
2530 
2531     return top;
2532 }
2533 
2534 std::tuple<mfxStatus, mfxU16, mfxU16>
GetCUQPMapBlockSize(mfxU16 frameWidth,mfxU16 frameHeight,mfxU16 CUQPWidth,mfxU16 CUHeight)2535 Legacy::GetCUQPMapBlockSize(
2536     mfxU16 frameWidth
2537     , mfxU16 frameHeight
2538     , mfxU16 CUQPWidth
2539     , mfxU16 CUHeight)
2540 {
2541     bool bValid = CUQPWidth && CUHeight;
2542 
2543     if (bValid)
2544     {
2545         const mfxU16 BlkSizes[] = { 4, 8, 16, 32, 64 };
2546         auto itBlkWidth = std::lower_bound(BlkSizes, std::end(BlkSizes), frameWidth / CUQPWidth);
2547         auto itBlkHeight = std::lower_bound(BlkSizes, std::end(BlkSizes), frameHeight / CUHeight);
2548 
2549         bValid =
2550             itBlkWidth != std::end(BlkSizes)
2551             && itBlkHeight != std::end(BlkSizes)
2552             && (*itBlkWidth   * (CUQPWidth - 1) < frameWidth)
2553             && (*itBlkHeight  * (CUHeight - 1) < frameHeight);
2554 
2555         if (bValid)
2556             return std::make_tuple(MFX_ERR_NONE, *itBlkWidth, *itBlkHeight);
2557     }
2558 
2559     return std::make_tuple(MFX_ERR_UNDEFINED_BEHAVIOR, mfxU16(0), mfxU16(0));
2560 }
2561 
GetMinBsSize(const mfxVideoParam & par,const mfxExtHEVCParam & HEVCParam,const mfxExtCodingOption2 & CO2,const mfxExtCodingOption3 & CO3)2562 mfxU32 Legacy::GetMinBsSize(
2563     const mfxVideoParam & par
2564     , const mfxExtHEVCParam& HEVCParam
2565     , const mfxExtCodingOption2& CO2
2566     , const mfxExtCodingOption3& CO3)
2567 {
2568     mfxU32 size = HEVCParam.PicHeightInLumaSamples * HEVCParam.PicWidthInLumaSamples;
2569 
2570     SetDefault(size, par.mfx.FrameInfo.Width * par.mfx.FrameInfo.Height);
2571 
2572     bool b10bit = (CO3.TargetBitDepthLuma == 10);
2573     bool b422   = (CO3.TargetChromaFormatPlus1 == (MFX_CHROMAFORMAT_YUV422 + 1));
2574     bool b444   = (CO3.TargetChromaFormatPlus1 == (MFX_CHROMAFORMAT_YUV444 + 1));
2575 
2576     mfxF64 k = 2.0
2577         + (b10bit * 0.3)
2578         + (b422   * 0.5)
2579         + (b444   * 1.5);
2580 
2581     size = mfxU32(k * size);
2582 
2583     bool bUseAvgSize =
2584         par.mfx.RateControlMethod == MFX_RATECONTROL_CBR
2585         && IsSWBRC(par, &CO2)
2586         && par.mfx.FrameInfo.FrameRateExtD != 0;
2587 
2588     if (!bUseAvgSize)
2589         return size;
2590 
2591     mfxU32 avgSize = TargetKbps(par.mfx) * 1000 * par.mfx.FrameInfo.FrameRateExtD / (par.mfx.FrameInfo.FrameRateExtN * 8);
2592 
2593     return std::max<mfxU32>(size, avgSize * 2);
2594 }
2595 
2596 typedef std::remove_reference<decltype(((mfxExtAVCRefListCtrl*)nullptr)->PreferredRefList[0])>::type TLCtrlRLE;
2597 
InitDPB(TaskCommonPar & task,TaskCommonPar const & prevTask,const mfxExtAVCRefListCtrl * pLCtrl)2598 void Legacy::InitDPB(
2599     TaskCommonPar &        task,
2600     TaskCommonPar const &  prevTask,
2601     const mfxExtAVCRefListCtrl* pLCtrl)
2602 {
2603     bool b1stTrail =
2604         task.POC > task.PrevRAP
2605         && prevTask.POC <= prevTask.PrevRAP;
2606 
2607     if ((task.IRState.refrType && !task.IRState.firstFrameInCycle) // IntRefCycle
2608         || (!task.IRState.refrType && prevTask.IRState.refrType)) // First frame after IntRefCycle
2609     {
2610         Remove(task.DPB.Active, 0, MAX_DPB_SIZE);
2611 
2612         for (mfxU8 i = 0; !isDpbEnd(prevTask.DPB.After, i); i++)
2613         {
2614             const DpbFrame& ref = prevTask.DPB.After[i]; // initial POC = -1
2615             if (ref.POC > task.DPB.Active[0].POC && ref.TemporalID == 0) // disable multiref within IntraRefCycle and next frame
2616                                                                          // and update DPB.Active only if temporal layer id = 0 for IntraRef cases
2617                 task.DPB.Active[0] = ref;
2618         }
2619     }
2620     else if (b1stTrail)
2621     {
2622         Remove(task.DPB.Active, 0, MAX_DPB_SIZE);
2623 
2624         // TODO: add mode to disable this check
2625         std::copy_if(
2626             prevTask.DPB.After
2627             , prevTask.DPB.After + Size(prevTask.DPB.After)
2628             , task.DPB.Active
2629             , [&](const DpbFrame& ref)
2630         {
2631             return isValid(ref) && (ref.POC == task.PrevRAP || ref.isLTR);
2632         });
2633     }
2634     else
2635     {
2636         std::copy_n(prevTask.DPB.After, Size(prevTask.DPB.After), task.DPB.Active);
2637     }
2638 
2639     std::copy_n(prevTask.DPB.After, Size(prevTask.DPB.After), task.DPB.Before);
2640 
2641     DpbArray& dpb = task.DPB.Active;
2642     auto dpbEnd = std::find_if_not(dpb, dpb + Size(dpb), isValid);
2643 
2644     dpbEnd = RemoveIf(dpb, dpbEnd
2645         , [&](const DpbFrame& ref)
2646     {
2647         return ref.TemporalID > 0 && ref.TemporalID >= task.TemporalID;
2648     });
2649 
2650     if (pLCtrl)
2651     {
2652         std::list<mfxU32> rejectIDX;
2653 
2654         std::transform(
2655             std::begin(pLCtrl->RejectedRefList)
2656             , std::end(pLCtrl->RejectedRefList)
2657             , std::back_inserter(rejectIDX)
2658             , [&](const TLCtrlRLE& lt)
2659         {
2660             mfxU16 idx = GetDPBIdxByFO(dpb, lt.FrameOrder);
2661             bool bInvalid = (idx >= MAX_DPB_SIZE) || !dpb[idx].isLTR;
2662             return std::max(lt.FrameOrder, mfxU32(bInvalid * MFX_FRAMEORDER_UNKNOWN));
2663         });
2664 
2665         rejectIDX.sort();
2666         rejectIDX.unique();
2667         rejectIDX.remove(mfxU32(MFX_FRAMEORDER_UNKNOWN));
2668 
2669         std::for_each(rejectIDX.begin(), rejectIDX.end()
2670             , [&](mfxU32 fo)
2671         {
2672             Remove(dpb, GetDPBIdxByFO(dpb, fo));
2673         });
2674     }
2675 }
2676 
UpdateDPB(const Defaults::Param & def,const DpbFrame & task,DpbArray & dpb,const mfxExtAVCRefListCtrl * pLCtrl)2677 mfxU16 Legacy::UpdateDPB(
2678     const Defaults::Param& def
2679     , const DpbFrame& task
2680     , DpbArray & dpb
2681     , const mfxExtAVCRefListCtrl * pLCtrl)
2682 {
2683     auto& par = def.mvp;
2684     const mfxExtCodingOption2& CO2  = ExtBuffer::Get(par);
2685     bool isBPyramid                 = (CO2.BRefType == MFX_B_REF_PYRAMID);
2686     mfxU16 end                      = 0; // DPB end
2687     mfxU16 st0                      = 0; // first ST ref in DPB
2688     bool bClearCodingType           = isBPyramid && (task.isLDB || task.CodingType < CODING_TYPE_B);
2689     auto ClearCodingType            = [](DpbFrame& ref) { ref.CodingType = 0; };
2690     auto IsLTR                      = [](DpbFrame& f) { return f.isLTR; };
2691     auto POCLess                    = [](DpbFrame& l, DpbFrame& r) { return l.POC < r.POC; };
2692 
2693     end = mfxU16(std::find_if_not(dpb, dpb + Size(dpb), isValid) - dpb);
2694     st0 = mfxU16(std::find_if_not(dpb, dpb + end, IsLTR) - dpb);
2695 
2696     // frames stored in DPB in POC ascending order,
2697     // LTRs before STRs (use LTR-candidate as STR as long as it is possible)
2698     std::sort(dpb, dpb + st0, POCLess);
2699     std::sort(dpb + st0, dpb + end, POCLess);
2700 
2701     // sliding window over STRs
2702     bool bRunSlidingWindow = end && end == par.mfx.NumRefFrame;
2703     if (bRunSlidingWindow)
2704     {
2705         st0 = mfxU16(def.base.GetWeakRef(def, task, dpb + st0, dpb + end) - dpb);
2706 
2707         Remove(dpb, st0 * (st0 < end));
2708         --end;
2709     }
2710 
2711     ThrowAssert(end >= MAX_DPB_SIZE, "DPB overflow, no space for new frame");
2712 
2713     //don't keep coding types for prev. mini-GOP
2714     std::for_each(dpb, dpb + (end * bClearCodingType), ClearCodingType);
2715 
2716     dpb[end++] = task;
2717 
2718     if (pLCtrl)
2719     {
2720         st0 = mfxU16(std::find_if_not(dpb, dpb + end, IsLTR) - dpb);
2721 
2722         auto lctrlLtrEnd = std::find_if(
2723             pLCtrl->LongTermRefList
2724             , pLCtrl->LongTermRefList + Size(pLCtrl->LongTermRefList)
2725             , [](const TLCtrlRLE& lt) { return lt.FrameOrder == mfxU32(MFX_FRAMEORDER_UNKNOWN); });
2726 
2727         std::list<mfxU16> markLTR;
2728 
2729         std::transform(pLCtrl->LongTermRefList, lctrlLtrEnd, std::back_inserter(markLTR)
2730             , [&](const TLCtrlRLE& lt)
2731         {
2732             mfxU16 idx = GetDPBIdxByFO(dpb, lt.FrameOrder);
2733             idx += !!dpb[idx].isLTR * MAX_DPB_SIZE;
2734             return std::min<mfxU16>(idx, MAX_DPB_SIZE);
2735         });
2736 
2737         markLTR.sort();
2738         markLTR.remove(mfxU16(MAX_DPB_SIZE));
2739         markLTR.unique();
2740 
2741         std::for_each(markLTR.begin(), markLTR.end()
2742             , [&](mfxU16 idx)
2743         {
2744             DpbFrame ltr = dpb[idx];
2745             ltr.isLTR = true;
2746             Remove(dpb, idx);
2747             Insert(dpb, st0, ltr);
2748             st0++;
2749         });
2750 
2751         std::sort(dpb, dpb + st0, POCLess);
2752     }
2753 
2754     return end;
2755 }
2756 
ConstructRPL(const Defaults::Param & dflts,const DpbArray & DPB,const FrameBaseInfo & cur,mfxU8 (& RPL)[2][MAX_DPB_SIZE],mfxU8 (& numRefActive)[2],const mfxExtAVCRefLists * pExtLists,const mfxExtAVCRefListCtrl * pLCtrl)2757 void Legacy::ConstructRPL(
2758     const Defaults::Param& dflts
2759     , const DpbArray & DPB
2760     , const FrameBaseInfo& cur
2761     , mfxU8(&RPL)[2][MAX_DPB_SIZE]
2762     , mfxU8(&numRefActive)[2]
2763     , const mfxExtAVCRefLists * pExtLists
2764     , const mfxExtAVCRefListCtrl * pLCtrl)
2765 {
2766     auto GetRPLFromExt = [&]()
2767     {
2768         return dflts.base.GetRPLFromExt(
2769             dflts
2770             , DPB
2771             , numRefActive[0]
2772             , numRefActive[1]
2773             , *pExtLists
2774             , RPL);
2775     };
2776     auto GetRPLFromCtrl = [&]()
2777     {
2778         return dflts.base.GetRPLFromCtrl (
2779             dflts
2780             , DPB
2781             , numRefActive[0]
2782             , numRefActive[1]
2783             , cur
2784             , *pLCtrl
2785             , RPL);
2786     };
2787 
2788     std::tuple<mfxU8, mfxU8> nRef(mfxU8(0), mfxU8(0));
2789 
2790     SetIf(nRef, !!pExtLists, GetRPLFromExt);
2791 
2792     SetIf(nRef, !std::get<0>(nRef)
2793         , dflts.base.GetRPL
2794         , dflts
2795         , DPB
2796         , numRefActive[0]
2797         , numRefActive[1]
2798         , cur
2799         , RPL);
2800 
2801     SetIf(nRef, !!pLCtrl, GetRPLFromCtrl);
2802     ThrowAssert(!std::get<0>(nRef), "L0 is empty");
2803 
2804     nRef = dflts.base.GetRPLMod(
2805         dflts
2806         , DPB
2807         , numRefActive[0]
2808         , numRefActive[1]
2809         , cur
2810         , RPL);
2811 
2812     numRefActive[0] = std::get<0>(nRef);
2813     numRefActive[1] = std::get<1>(nRef);
2814 }
2815 
ConstructSTRPS(const DpbArray & DPB,const mfxU8 (& RPL)[2][MAX_DPB_SIZE],const mfxU8 (& numRefActive)[2],mfxI32 poc,STRPS & rps)2816 void Legacy::ConstructSTRPS(
2817     const DpbArray & DPB
2818     , const mfxU8(&RPL)[2][MAX_DPB_SIZE]
2819     , const mfxU8(&numRefActive)[2]
2820     , mfxI32 poc
2821     , STRPS& rps)
2822 {
2823     mfxU32 i, nRef;
2824 
2825     for (i = 0, nRef = 0; !isDpbEnd(DPB, i); i ++)
2826     {
2827         if (DPB[i].isLTR)
2828             continue;
2829 
2830         rps.pic[nRef].DeltaPocSX = (mfxI16)(DPB[i].POC - poc);
2831         rps.pic[nRef].used_by_curr_pic_sx_flag = IsCurrRef(DPB, RPL, numRefActive, DPB[i].POC);
2832 
2833         rps.num_negative_pics += rps.pic[nRef].DeltaPocSX < 0;
2834         rps.num_positive_pics += rps.pic[nRef].DeltaPocSX > 0;
2835         nRef ++;
2836     }
2837 
2838     std::sort(rps.pic, rps.pic + nRef
2839         , [](decltype(rps.pic[0]) l, decltype(rps.pic[0]) r) { return l.DeltaPocSX < r.DeltaPocSX; });
2840     std::sort(rps.pic, rps.pic + rps.num_negative_pics
2841         , [](decltype(rps.pic[0]) l, decltype(rps.pic[0]) r) { return l.DeltaPocSX > r.DeltaPocSX; });
2842 
2843     for (i = 0; i < nRef; i ++)
2844     {
2845         mfxI16 prev  = (!i || i == rps.num_negative_pics) ? 0 : rps.pic[i-1].DeltaPocSX;
2846         rps.pic[i].delta_poc_sx_minus1 = mfxU16(abs(rps.pic[i].DeltaPocSX - prev) - 1);
2847     }
2848 }
2849 
EstimateRpsBits(const STRPS * pSpsRps,mfxU8 nSet,const STRPS & rps,mfxU8 idx)2850 mfxU32 EstimateRpsBits(const STRPS* pSpsRps, mfxU8 nSet, const STRPS & rps, mfxU8 idx)
2851 {
2852     auto NBitsUE = [](mfxU32 b) -> mfxU32
2853     {
2854         return CeilLog2(b + 2) * 2 - 1;
2855     };
2856     auto IsNotUsed = [](const STRPSPic& pic)
2857     {
2858         return !pic.used_by_curr_pic_flag;
2859     };
2860     auto AccNBitsDPoc = [&](mfxU32 x, const STRPSPic& pic)
2861     {
2862         return std::move(x) + NBitsUE(pic.delta_poc_sx_minus1) + 1;
2863     };
2864     mfxU32 n = (idx != 0);
2865 
2866     if (!rps.inter_ref_pic_set_prediction_flag)
2867     {
2868         mfxU32 nPic = mfxU32(rps.num_negative_pics + rps.num_positive_pics);
2869 
2870         n += NBitsUE(rps.num_negative_pics);
2871         n += NBitsUE(rps.num_positive_pics);
2872 
2873         return std::accumulate(rps.pic, rps.pic + nPic, n, AccNBitsDPoc);
2874     }
2875 
2876     assert(idx > rps.delta_idx_minus1);
2877     STRPS const & ref = pSpsRps[idx - rps.delta_idx_minus1 - 1];
2878     mfxU32 nPic = mfxU32(ref.num_negative_pics + ref.num_positive_pics);
2879 
2880     if (idx == nSet)
2881         n += NBitsUE(rps.delta_idx_minus1);
2882 
2883     n += 1;
2884     n += NBitsUE(rps.abs_delta_rps_minus1);
2885     n += nPic;
2886     n += mfxU32(std::count_if(rps.pic, rps.pic + nPic + 1, IsNotUsed));
2887 
2888     return n;
2889 }
2890 
GetInterRps(STRPS const & refRPS,STRPS & rps,mfxU8 dIdxMinus1)2891 bool GetInterRps(STRPS const & refRPS, STRPS& rps, mfxU8 dIdxMinus1)
2892 {
2893     auto oldRPS = rps;
2894     auto newRPS = oldRPS;
2895     newRPS.inter_ref_pic_set_prediction_flag = 1;
2896     newRPS.delta_idx_minus1 = dIdxMinus1;
2897 
2898     std::list<mfxI16> dPocs[2];
2899     auto AddDPoc = [&dPocs](mfxI16 dPoc)
2900     {
2901         if (dPoc)
2902             dPocs[dPoc > 0].push_back(dPoc);
2903     };
2904 
2905     std::for_each(oldRPS.pic, oldRPS.pic + oldRPS.num_negative_pics + oldRPS.num_positive_pics
2906         , [&](STRPSPic& oldPic)
2907     {
2908         AddDPoc(oldPic.DeltaPocSX);
2909 
2910         std::for_each(refRPS.pic, refRPS.pic + refRPS.num_negative_pics + refRPS.num_positive_pics
2911             , [&](const STRPSPic& refPic)
2912         {
2913             AddDPoc(oldPic.DeltaPocSX - refPic.DeltaPocSX);
2914         });
2915     });
2916 
2917     dPocs[0].sort(std::greater<mfxI16>());
2918     dPocs[1].sort(std::less<mfxI16>());
2919     dPocs[0].unique();
2920     dPocs[1].unique();
2921 
2922     mfxI16 dPoc = 0;
2923     bool bDPocFound = false;
2924     auto NextDPock = [&]()
2925     {
2926         return ((!dPocs[0].empty() || !dPocs[1].empty()) && !bDPocFound);
2927     };
2928 
2929     while (NextDPock())
2930     {
2931         dPoc *= -1;
2932         bool bPositive = (dPoc > 0 && !dPocs[1].empty()) || dPocs[0].empty();
2933         dPoc = dPocs[bPositive].front();
2934         dPocs[bPositive].pop_front();
2935 
2936         std::for_each(newRPS.pic
2937             , newRPS.pic + refRPS.num_negative_pics + refRPS.num_positive_pics + 1
2938             , [&](STRPSPic& newPic)
2939         {
2940             newPic.used_by_curr_pic_flag = 0;
2941             newPic.use_delta_flag = 0;
2942         });
2943 
2944         auto pOldPic = oldRPS.pic;
2945         auto UseDelta = [&pOldPic, dPoc](STRPSPic& newPic, mfxI16 refDeltaPocSX, mfxI16 sign)
2946         {
2947             bool bUse =
2948                 ((pOldPic->DeltaPocSX * sign) > 0)
2949                 && ((pOldPic->DeltaPocSX - refDeltaPocSX) == dPoc);
2950 
2951             newPic.used_by_curr_pic_flag =
2952                 (bUse && pOldPic->used_by_curr_pic_sx_flag)
2953                 || (!bUse && newPic.used_by_curr_pic_flag);
2954             newPic.use_delta_flag = bUse || (!bUse && newPic.use_delta_flag);
2955             pOldPic += bUse;
2956         };
2957 
2958         auto pRefPic = refRPS.pic + refRPS.num_negative_pics + refRPS.num_positive_pics - 1;
2959 
2960         std::for_each(
2961             MakeRIter(newRPS.pic + refRPS.num_negative_pics + refRPS.num_positive_pics)
2962             , MakeRIter(newRPS.pic + refRPS.num_negative_pics)
2963             , [&](STRPSPic& newPic)
2964         {
2965             UseDelta(newPic, pRefPic->DeltaPocSX, -1);
2966             --pRefPic;
2967         });
2968 
2969         UseDelta(newRPS.pic[refRPS.num_negative_pics + refRPS.num_positive_pics], 0, (dPoc < 0) * -1);
2970 
2971         pRefPic = refRPS.pic;
2972 
2973         std::for_each(newRPS.pic, newRPS.pic + refRPS.num_negative_pics
2974             , [&](STRPSPic& newPic)
2975         {
2976             UseDelta(newPic, pRefPic->DeltaPocSX, -1);
2977             ++pRefPic;
2978         });
2979 
2980         if (pOldPic != (oldRPS.pic + oldRPS.num_negative_pics))
2981             continue;
2982 
2983         pRefPic = refRPS.pic + refRPS.num_negative_pics - 1;
2984 
2985         std::for_each(
2986             MakeRIter(newRPS.pic + refRPS.num_negative_pics)
2987             , MakeRIter(newRPS.pic)
2988             , [&](STRPSPic& newPic)
2989         {
2990             UseDelta(newPic, pRefPic->DeltaPocSX, +1);
2991             --pRefPic;
2992         });
2993 
2994         UseDelta(newRPS.pic[refRPS.num_negative_pics + refRPS.num_positive_pics], 0, dPoc > 0);
2995 
2996         pRefPic = refRPS.pic + refRPS.num_negative_pics;
2997 
2998         std::for_each(
2999             newRPS.pic + refRPS.num_negative_pics
3000             , newRPS.pic + refRPS.num_negative_pics + refRPS.num_positive_pics
3001             , [&](STRPSPic& newPic)
3002         {
3003             UseDelta(newPic, pRefPic->DeltaPocSX, +1);
3004             ++pRefPic;
3005         });
3006 
3007         bDPocFound = (pOldPic == (oldRPS.pic + oldRPS.num_negative_pics + oldRPS.num_positive_pics));
3008     }
3009 
3010     newRPS.delta_rps_sign       = (dPoc < 0);
3011     newRPS.abs_delta_rps_minus1 = mfxU16(abs(dPoc) - 1);
3012 
3013     SetIf(rps, bDPocFound, newRPS);
3014 
3015     return bDPocFound;
3016 }
3017 
OptimizeSTRPS(const STRPS * pSpsRps,mfxU8 n,STRPS & oldRPS,mfxU8 idx)3018 void OptimizeSTRPS(const STRPS* pSpsRps, mfxU8 n, STRPS& oldRPS, mfxU8 idx)
3019 {
3020     auto  IsEnoughPics   = [&](const STRPS& refRPS)
3021     {
3022         return (refRPS.num_negative_pics + refRPS.num_positive_pics + 1)
3023             < (oldRPS.num_negative_pics + oldRPS.num_positive_pics);
3024     };
3025     auto  itRBegin       = MakeRIter(pSpsRps + idx);
3026     auto  itREnd         = MakeRIter(pSpsRps + ((idx < n && idx > 1) * (idx - 1)));
3027     auto  itSearchRBegin = std::find_if_not(itRBegin, itREnd, IsEnoughPics);
3028     mfxU8 dIdxMinus1     = mfxU8(std::distance(itRBegin, itSearchRBegin));
3029     auto  UpdateRPS      = [&](const STRPS& refRPS)
3030     {
3031         STRPS newRPS = oldRPS;
3032         bool bUpdateRps =
3033             GetInterRps(refRPS, newRPS, dIdxMinus1++)
3034             && (EstimateRpsBits(pSpsRps, n, newRPS, idx) < EstimateRpsBits(pSpsRps, n, oldRPS, idx));
3035         SetIf(oldRPS, bUpdateRps, newRPS);
3036     };
3037     auto    itSearchREnd = itREnd;
3038     bool    b1Ref = (idx < n) && (itSearchRBegin != itREnd);
3039 
3040     SetIf(itSearchREnd, b1Ref, std::next(itSearchRBegin, b1Ref));
3041     std::for_each(itSearchRBegin, itSearchREnd, UpdateRPS);
3042 }
3043 
Equal(const STRPS & l,const STRPS & r)3044 bool Equal(const STRPS & l, const STRPS & r)
3045 {
3046     //ignore inter_ref_pic_set_prediction_flag, check only DeltaPocSX
3047     auto IsSame = [](const STRPSPic & l, const STRPSPic & r)
3048     {
3049         return
3050             l.DeltaPocSX == r.DeltaPocSX
3051             && l.used_by_curr_pic_sx_flag == r.used_by_curr_pic_sx_flag;
3052     };
3053     auto nPic = l.num_negative_pics + l.num_positive_pics;
3054 
3055     return
3056         l.num_negative_pics == r.num_negative_pics
3057         && l.num_positive_pics == r.num_positive_pics
3058         && (std::mismatch(l.pic, l.pic + nPic, r.pic, IsSame) == std::make_pair(l.pic + nPic, r.pic + nPic));
3059 }
3060 
SetSTRPS(const Defaults::Param & dflts,SPS & sps,const Reorderer & reorder)3061 void Legacy::SetSTRPS(
3062     const Defaults::Param& dflts
3063     , SPS& sps
3064     , const Reorderer& reorder)
3065 {
3066     std::list<StorageRW> frames;
3067     auto&     par        = dflts.mvp;
3068     STRPS     sets[65]   = {};
3069     auto      pSetsBegin = sets;
3070     auto      pSetsEnd   = pSetsBegin;
3071     bool      bTL        = dflts.base.GetNumTemporalLayers(dflts) > 1;
3072     mfxI32    nGops      = par.mfx.IdrInterval + !par.mfx.IdrInterval * 4;
3073     mfxI32    stDist     = std::min<mfxI32>(par.mfx.GopPicSize * nGops, 128);
3074     mfxI32    lastIPoc   = 0;
3075     bool      bDone      = false;
3076     mfxI32    i          = 0;
3077 
3078     mfxI32    RAPPOC     = -1;   // if >= 0 first frame with bigger POC clears refs previous to RAP
3079     bool      bFields    = (par.mfx.FrameInfo.PicStruct & (MFX_PICSTRUCT_FIELD_TOP | MFX_PICSTRUCT_FIELD_BOTTOM));
3080     bool      bIisRAP    = !bFields; // control to match real encoding here
3081 
3082     Reorderer localReorder;
3083     DpbArray  dpb;
3084     localReorder        = reorder;
3085     localReorder.DPB    = &dpb; //use own DPB
3086 
3087     do
3088     {
3089         {
3090             FrameBaseInfo fi;
3091             auto sts = dflts.base.GetPreReorderInfo(dflts, fi, nullptr, nullptr, 0, lastIPoc, mfxU32(i));
3092             ThrowIf(!!sts, "failed at GetPreReorderInfo");
3093 
3094             frames.push_back(StorageRW());
3095             frames.back().Insert(Task::Common::Key, new FrameBaseInfo(fi));
3096         }
3097 
3098         auto frIt  = localReorder(frames.begin(), frames.end(), false);
3099         bool bNext = frIt == frames.end();
3100 
3101         FrameBaseInfo* cur = nullptr;
3102         SetIf(cur, !bNext, [&]() { return &frIt->Write<FrameBaseInfo>(Task::Common::Key); });
3103 
3104         bDone =
3105             (i > 0 && !bNext && IsIdr(cur->FrameType))
3106             || (!bNext && cur->POC >= stDist)
3107             || (pSetsEnd + 1) >= std::end(sets);
3108 
3109         bNext |= bDone;
3110 
3111         if (!bNext)
3112         {
3113             bool bAfterRAP = (RAPPOC >= 0) && (cur->POC > RAPPOC); // if true - need to remove refs <RAPPOC
3114 
3115             RemoveIf(dpb, dpb + Size(dpb) * (bTL | bAfterRAP)
3116                 , [&](DpbFrame& ref)
3117             {
3118                 return
3119                     isValid(ref)
3120                     && ((bAfterRAP && ref.POC != RAPPOC && !ref.isLTR) // only RAP and LTR remains
3121                         || (ref.TemporalID > 0 && ref.TemporalID >= cur->TemporalID));
3122             });
3123 
3124             bool bIDR = IsIdr(cur->FrameType);
3125             bool bI   = IsI(cur->FrameType);
3126             bool bB   = IsB(cur->FrameType);
3127             bool bP   = IsP(cur->FrameType);
3128             bool bRef = IsRef(cur->FrameType);
3129 
3130             SetIf(RAPPOC, bAfterRAP, -1);           // clear after use
3131             SetIf(RAPPOC, bI && bIisRAP, cur->POC); // enable at I if conrol allows
3132 
3133             if (!bIDR)
3134             {
3135                 mfxU8 nRef[2] = {};
3136                 mfxU8 rpl[2][MAX_DPB_SIZE];
3137 
3138                 std::fill_n(rpl[0], Size(rpl[0]), IDX_INVALID);
3139                 std::fill_n(rpl[1], Size(rpl[1]), IDX_INVALID);
3140 
3141                 auto SetRPL = [&]()
3142                 {
3143                     ConstructRPL(dflts, dpb, *cur, rpl, nRef);
3144                     return true;
3145                 };
3146 
3147                 std::tie(nRef[0], nRef[1]) = dflts.base.GetFrameNumRefActive(dflts, *cur);
3148 
3149                 bool bRPL =
3150                        (bB && nRef[0] && SetRPL())
3151                     || (bP && nRef[0] && SetRPL())
3152                     || (bI); //I picture is not using any refs, but saves them in RPS to be used by future pics.
3153                 // but currently every I is RAP and frames after it won't use refs before it
3154 
3155                 ThrowAssert(!bRPL, "failed to construct RPL");
3156 
3157                 STRPS rps = {};
3158                 ConstructSTRPS(dpb, rpl, nRef, cur->POC, rps);
3159 
3160                 auto pCurSet = std::find_if(pSetsBegin, pSetsEnd
3161                     , [&](const STRPS& x) { return Equal(x, rps); });
3162 
3163                 pSetsEnd += SetIf(*pCurSet, pSetsEnd == pCurSet, rps);
3164                 ++pCurSet->WeightInGop;
3165             }
3166 
3167             SetIf(lastIPoc, bI, cur->POC);
3168 
3169             DpbFrame tmp;
3170             (FrameBaseInfo&)tmp = *cur;
3171             tmp.Rec.Idx += bRef;
3172             ThrowAssert(bRef && !UpdateDPB(dflts, tmp, dpb), "failed to UpdateDPB");
3173 
3174             frames.erase(frIt);
3175         }
3176 
3177         ++i;
3178     } while (!bDone);
3179 
3180     mfxU8 nSet         = mfxU8(std::distance(pSetsBegin, pSetsEnd));
3181     auto  IsRpsOptimal = [&nSet, &par, pSetsBegin](const STRPS& curRps)
3182     {
3183         STRPS  rps   = curRps;
3184         mfxU32 n     = curRps.WeightInGop; //current RPS used for N frames
3185         //bits for RPS in SPS and SSHs
3186         mfxU32 bits0 =
3187             EstimateRpsBits(pSetsBegin, nSet, rps, nSet - 1) //bits for RPS in SPS
3188             + (CeilLog2(nSet + 1) - CeilLog2(nSet)) * 2 //diff of bits for STRPS num in SPS (ue() coded)
3189             + (nSet > 1) * (par.mfx.NumSlice * CeilLog2(nSet) * n); //bits for RPS idx in SSHs
3190 
3191         // count frames that use SPS RPS
3192         auto AccFrWithRPS = [](mfxU32 x, const STRPS& r)
3193         {
3194             return std::move(x) + r.inter_ref_pic_set_prediction_flag * r.WeightInGop;
3195         };
3196         if (CeilLog2(nSet) - CeilLog2(nSet - 1)) //diff RPS idx bits with bigger RPS for ALL frames
3197             bits0 = par.mfx.NumSlice * std::accumulate(pSetsBegin, pSetsBegin + nSet - 1, bits0, AccFrWithRPS);
3198 
3199         //emulate removal of current RPS from SPS
3200         --nSet;
3201         rps.inter_ref_pic_set_prediction_flag = 0;
3202         OptimizeSTRPS(pSetsBegin, nSet, rps, nSet);
3203 
3204         //bits for RPS in SSHs (no RPS in SPS)
3205         mfxU32 bits1 =
3206             EstimateRpsBits(pSetsBegin, nSet, rps, nSet)
3207             * par.mfx.NumSlice
3208             * n;
3209 
3210         return bits0 <= bits1;
3211     };
3212 
3213     std::sort(pSetsBegin, pSetsEnd
3214         , [&](const STRPS& l, const STRPS& r) { return l.WeightInGop > r.WeightInGop; });
3215 
3216     i = 0;
3217     std::for_each(pSetsBegin, pSetsEnd
3218         , [&](STRPS& sf) { OptimizeSTRPS(sets, nSet, sf, mfxU8(i++)); });
3219 
3220     auto ritLastRps = std::find_if(MakeRIter(pSetsEnd), MakeRIter(pSetsBegin), IsRpsOptimal);
3221     // Also makes sense to try cut nSet to 2^n. Shorter idx code can overweight
3222 
3223     sps.num_short_term_ref_pic_sets = mfxU8(std::distance(ritLastRps, MakeRIter(pSetsBegin)));
3224 
3225     std::copy_n(pSetsBegin, sps.num_short_term_ref_pic_sets, sps.strps);
3226 }
3227 
CheckSPS(const SPS & sps,const ENCODE_CAPS_HEVC & caps,eMFXHWType hw)3228 mfxStatus Legacy::CheckSPS(const SPS& sps, const ENCODE_CAPS_HEVC& caps, eMFXHWType hw)
3229 {
3230     MFX_CHECK_COND(
3231            sps.log2_min_luma_coding_block_size_minus3 == 0
3232         && sps.separate_colour_plane_flag == 0
3233         && sps.pcm_enabled_flag == 0);
3234 
3235     if (hw >= MFX_HW_CNL)
3236     {
3237         MFX_CHECK_COND(sps.amp_enabled_flag == 1);
3238     }
3239     else
3240     {
3241         MFX_CHECK_COND(sps.amp_enabled_flag == 0);
3242         MFX_CHECK_COND(sps.sample_adaptive_offset_enabled_flag == 0);
3243     }
3244 
3245     MFX_CHECK_COND(
3246       !(   (!caps.YUV444ReconSupport && (sps.chroma_format_idc == 3))
3247         || (!caps.YUV422ReconSupport && (sps.chroma_format_idc == 2))
3248         || (caps.Color420Only && (sps.chroma_format_idc != 1))));
3249 
3250     MFX_CHECK_COND(
3251       !(   sps.pic_width_in_luma_samples > caps.MaxPicWidth
3252         || sps.pic_height_in_luma_samples > caps.MaxPicHeight));
3253 
3254     MFX_CHECK_COND(
3255       !(   (caps.MaxEncodedBitDepth == 0 || caps.BitDepth8Only)
3256         && (sps.bit_depth_luma_minus8 != 0 || sps.bit_depth_chroma_minus8 != 0)));
3257 
3258     MFX_CHECK_COND(
3259       !(   (caps.MaxEncodedBitDepth == 2 || caps.MaxEncodedBitDepth == 1 || !caps.BitDepth8Only)
3260         && ( !(sps.bit_depth_luma_minus8 == 0
3261             || sps.bit_depth_luma_minus8 == 2
3262             || sps.bit_depth_luma_minus8 == 4)
3263           || !(sps.bit_depth_chroma_minus8 == 0
3264             || sps.bit_depth_chroma_minus8 == 2
3265             || sps.bit_depth_chroma_minus8 == 4))));
3266 
3267     MFX_CHECK_COND(
3268       !(   caps.MaxEncodedBitDepth == 2
3269         && ( !(sps.bit_depth_luma_minus8 == 0
3270             || sps.bit_depth_luma_minus8 == 2
3271             || sps.bit_depth_luma_minus8 == 4)
3272           || !(sps.bit_depth_chroma_minus8 == 0
3273             || sps.bit_depth_chroma_minus8 == 2
3274             || sps.bit_depth_chroma_minus8 == 4))));
3275 
3276     MFX_CHECK_COND(
3277       !(   caps.MaxEncodedBitDepth == 3
3278         && ( !(sps.bit_depth_luma_minus8 == 0
3279             || sps.bit_depth_luma_minus8 == 2
3280             || sps.bit_depth_luma_minus8 == 4
3281             || sps.bit_depth_luma_minus8 == 8)
3282           || !(sps.bit_depth_chroma_minus8 == 0
3283             || sps.bit_depth_chroma_minus8 == 2
3284             || sps.bit_depth_chroma_minus8 == 4
3285             || sps.bit_depth_chroma_minus8 == 8))));
3286 
3287     return MFX_ERR_NONE;
3288 }
3289 
CheckPPS(const PPS & pps,const ENCODE_CAPS_HEVC & caps,eMFXHWType)3290 mfxStatus Legacy::CheckPPS(const PPS& pps, const ENCODE_CAPS_HEVC& caps, eMFXHWType /*hw*/)
3291 {
3292     if (pps.tiles_enabled_flag)
3293     {
3294         MFX_CHECK_COND(pps.loop_filter_across_tiles_enabled_flag);
3295     }
3296 
3297     MFX_CHECK_COND(!((mfxU32)(((pps.num_tile_columns_minus1 + 1) * (pps.num_tile_rows_minus1 + 1)) > 1) > caps.TileSupport));
3298 
3299     return MFX_ERR_NONE;
3300 }
3301 
SetDefaultFormat(mfxVideoParam & par,const Defaults::Param & defPar,mfxExtCodingOption3 * pCO3)3302 void SetDefaultFormat(
3303     mfxVideoParam& par
3304     , const Defaults::Param& defPar
3305     , mfxExtCodingOption3* pCO3)
3306 {
3307     auto& fi = par.mfx.FrameInfo;
3308 
3309     assert(fi.FourCC);
3310 
3311     SetDefault(fi.BitDepthLuma, [&]() { return defPar.base.GetMaxBitDepth(defPar); });
3312     SetDefault(fi.BitDepthChroma, fi.BitDepthLuma);
3313 
3314     if (pCO3)
3315     {
3316         pCO3->TargetChromaFormatPlus1 = defPar.base.GetTargetChromaFormat(defPar);
3317         pCO3->TargetBitDepthLuma = defPar.base.GetTargetBitDepthLuma(defPar);
3318         SetDefault(pCO3->TargetBitDepthChroma, pCO3->TargetBitDepthLuma);
3319     }
3320 }
3321 
SetDefaultSize(mfxVideoParam & par,const Defaults::Param & defPar,mfxExtHEVCParam * pHEVC)3322 void SetDefaultSize(
3323     mfxVideoParam & par
3324     , const Defaults::Param& defPar
3325     , mfxExtHEVCParam* pHEVC)
3326 {
3327     auto& fi = par.mfx.FrameInfo;
3328     mfxU16 PicWidthInLumaSamples = defPar.base.GetCodedPicWidth(defPar);
3329     mfxU16 PicHeightInLumaSamples = defPar.base.GetCodedPicHeight(defPar);
3330 
3331     if (pHEVC)
3332     {
3333         SetDefault(pHEVC->PicWidthInLumaSamples, PicWidthInLumaSamples);
3334         SetDefault(pHEVC->PicHeightInLumaSamples, PicHeightInLumaSamples);
3335     }
3336 
3337     SetDefault(fi.CropW, mfxU16(PicWidthInLumaSamples - fi.CropX));
3338     SetDefault(fi.CropH, mfxU16(PicHeightInLumaSamples - fi.CropY));
3339     SetDefault(fi.AspectRatioW, mfxU16(1));
3340     SetDefault(fi.AspectRatioH, mfxU16(1));
3341 
3342     std::tie(fi.FrameRateExtN, fi.FrameRateExtD) = defPar.base.GetFrameRate(defPar);
3343 }
3344 
SetDefaultGOP(mfxVideoParam & par,const Defaults::Param & defPar,mfxExtCodingOption2 * pCO2,mfxExtCodingOption3 * pCO3)3345 void SetDefaultGOP(
3346     mfxVideoParam& par
3347     , const Defaults::Param& defPar
3348     , mfxExtCodingOption2* pCO2
3349     , mfxExtCodingOption3* pCO3)
3350 {
3351     par.mfx.GopPicSize = defPar.base.GetGopPicSize(defPar);
3352     par.mfx.GopRefDist = defPar.base.GetGopRefDist(defPar);
3353 
3354     SetIf(pCO2->BRefType, pCO2 && !pCO2->BRefType, [&]() { return defPar.base.GetBRefType(defPar); });
3355     SetIf(pCO3->PRefType, pCO3 && !pCO3->PRefType, [&]() { return defPar.base.GetPRefType(defPar); });
3356 
3357     par.mfx.NumRefFrame = defPar.base.GetNumRefFrames(defPar);
3358 
3359     if (pCO3)
3360     {
3361         SetDefault<mfxU16>(pCO3->GPB, MFX_CODINGOPTION_ON);
3362 
3363         defPar.base.GetNumRefActive(
3364             defPar
3365             , &pCO3->NumRefActiveP
3366             , &pCO3->NumRefActiveBL0
3367             , &pCO3->NumRefActiveBL1);
3368     }
3369 }
3370 
SetDefaultBRC(mfxVideoParam & par,const Defaults::Param & defPar,mfxExtCodingOption2 * pCO2,mfxExtCodingOption3 * pCO3)3371 void SetDefaultBRC(
3372     mfxVideoParam& par
3373     , const Defaults::Param& defPar
3374     , mfxExtCodingOption2* pCO2
3375     , mfxExtCodingOption3* pCO3)
3376 {
3377     par.mfx.RateControlMethod = defPar.base.GetRateControlMethod(defPar);
3378     BufferSizeInKB(par.mfx) = defPar.base.GetBufferSizeInKB(defPar);
3379 
3380     if (pCO2)
3381         pCO2->MBBRC = defPar.base.GetMBBRC(defPar);
3382 
3383     bool bSetQP = par.mfx.RateControlMethod == MFX_RATECONTROL_CQP
3384         && !(par.mfx.QPI && par.mfx.QPP && par.mfx.QPB);
3385     bool bSetRCPar = (par.mfx.RateControlMethod == MFX_RATECONTROL_CBR
3386         || par.mfx.RateControlMethod == MFX_RATECONTROL_VBR
3387         || par.mfx.RateControlMethod == MFX_RATECONTROL_QVBR
3388         || par.mfx.RateControlMethod == MFX_RATECONTROL_VCM
3389         || par.mfx.RateControlMethod == MFX_RATECONTROL_LA_EXT);
3390     bool bSetICQ  = (par.mfx.RateControlMethod == MFX_RATECONTROL_ICQ);
3391     bool bSetQVBR = (par.mfx.RateControlMethod == MFX_RATECONTROL_QVBR && pCO3);
3392 
3393     if (bSetQP)
3394     {
3395         std::tie(par.mfx.QPI, par.mfx.QPP, par.mfx.QPB) = defPar.base.GetQPMFX(defPar);
3396     }
3397 
3398     if (bSetRCPar)
3399     {
3400         TargetKbps(par.mfx) = defPar.base.GetTargetKbps(defPar);
3401         SetDefault<mfxU16>(par.mfx.MaxKbps, par.mfx.TargetKbps);
3402         SetDefault<mfxU16>(par.mfx.InitialDelayInKB
3403             , par.mfx.BufferSizeInKB * (2 + (par.mfx.RateControlMethod == MFX_RATECONTROL_VBR && Legacy::IsSWBRC(par, ExtBuffer::Get(par)))) / 4);
3404     }
3405 
3406     if (bSetICQ)
3407         SetDefault<mfxU16>(par.mfx.ICQQuality, 26);
3408 
3409     if (bSetQVBR)
3410         SetDefault<mfxU16>(pCO3->QVBRQuality, 26);
3411 
3412     if (pCO3)
3413     {
3414         SetDefault<mfxU16>(pCO3->LowDelayBRC, MFX_CODINGOPTION_OFF);
3415 
3416         pCO3->EnableQPOffset = defPar.base.GetQPOffset(defPar, &pCO3->QPOffset);
3417 
3418         SetDefault<mfxU16>(pCO3->EnableMBQP
3419             , Bool2CO(
3420               !(   par.mfx.RateControlMethod == MFX_RATECONTROL_CQP
3421                 || Legacy::IsSWBRC(par, pCO2)
3422                 || !defPar.caps.MbQpDataSupport)));
3423 
3424         bool bSetWinBRC = pCO3->WinBRCSize || pCO3->WinBRCMaxAvgKbps;
3425 
3426         if (bSetWinBRC)
3427         {
3428             SetDefault<mfxU16>(pCO3->WinBRCSize
3429                 , (mfxU16)CeilDiv(par.mfx.FrameInfo.FrameRateExtN, par.mfx.FrameInfo.FrameRateExtD));
3430             SetDefault<mfxU16>(pCO3->WinBRCMaxAvgKbps, par.mfx.MaxKbps);
3431         }
3432 
3433         SetDefault<mfxU16>(pCO3->BRCPanicMode, Bool2CO(defPar.caps.HRDConformanceSupport));
3434     }
3435 }
3436 
SetDefaultEsOptions(mfxVideoParam & par,const Defaults::Param & defPar,mfxExtHEVCParam * pHEVC,mfxExtCodingOption * pCO,mfxExtCodingOption2 * pCO2,mfxExtCodingOption3 * pCO3)3437 void SetDefaultEsOptions(
3438     mfxVideoParam& par
3439     , const Defaults::Param& defPar
3440     , mfxExtHEVCParam* pHEVC
3441     , mfxExtCodingOption* pCO
3442     , mfxExtCodingOption2* pCO2
3443     , mfxExtCodingOption3* pCO3)
3444 {
3445     if (pCO)
3446     {
3447         bool bHRDConformance = defPar.base.GetHRDConformanceON(defPar);
3448 
3449         SetDefault(pCO->NalHrdConformance, Bool2CO(bHRDConformance));
3450         SetDefault(pCO->VuiNalHrdParameters, Bool2CO(bHRDConformance));
3451         SetDefault(pCO->AUDelimiter, mfxU16(MFX_CODINGOPTION_OFF));
3452 
3453         pCO->PicTimingSEI = defPar.base.GetPicTimingSEI(defPar);
3454     }
3455 
3456     if (pCO2)
3457         SetDefault(pCO2->RepeatPPS, mfxU16(MFX_CODINGOPTION_OFF));
3458 
3459     if (pCO3)
3460     {
3461         SetDefault(pCO3->TransformSkip, mfxU16(MFX_CODINGOPTION_ON * (defPar.hw >= MFX_HW_ICL)));
3462         SetDefault(pCO3->TransformSkip, mfxU16(MFX_CODINGOPTION_OFF));
3463         SetDefault(pCO3->EnableNalUnitType, Bool2CO(!!par.mfx.EncodedOrder));
3464     }
3465 
3466     if (pHEVC)
3467     {
3468         bool bNoSAO =
3469             SetDefault(pHEVC->SampleAdaptiveOffset, mfxU16(MFX_SAO_ENABLE_LUMA | MFX_SAO_ENABLE_CHROMA))
3470             && defPar.base.CheckSAO(defPar, par);
3471 
3472         pHEVC->SampleAdaptiveOffset *= !bNoSAO;
3473         SetDefault(pHEVC->SampleAdaptiveOffset, mfxU16(MFX_SAO_DISABLE));
3474     }
3475 }
3476 
SetDefaults(mfxVideoParam & par,const Defaults::Param & defPar,bool bExternalFrameAllocator)3477 void Legacy::SetDefaults(
3478     mfxVideoParam& par
3479     , const Defaults::Param& defPar
3480     , bool bExternalFrameAllocator)
3481 {
3482     auto&                    fi            = par.mfx.FrameInfo;
3483     mfxExtHEVCParam*         pHEVC         = ExtBuffer::Get(par);
3484     mfxExtHEVCTiles*         pTile         = ExtBuffer::Get(par);
3485     mfxExtAvcTemporalLayers* pTL           = ExtBuffer::Get(par);
3486     mfxExtCodingOption*      pCO           = ExtBuffer::Get(par);
3487     mfxExtCodingOption2*     pCO2          = ExtBuffer::Get(par);
3488     mfxExtCodingOption3*     pCO3          = ExtBuffer::Get(par);
3489     mfxU16                   IOPByAlctr[2] = { MFX_IOPATTERN_IN_SYSTEM_MEMORY, MFX_IOPATTERN_IN_VIDEO_MEMORY };
3490     auto GetNumSlices = [&]()
3491     {
3492         std::vector<SliceInfo> slices;
3493         return defPar.base.GetSlices(defPar, slices);
3494     };
3495     auto GetDefaultLevel = [&]()
3496     {
3497         mfxU16 nCol, nRow;
3498         std::tie(nCol, nRow) = defPar.base.GetNumTiles(defPar);
3499 
3500         return GetMinLevel(
3501             fi.FrameRateExtN
3502             , fi.FrameRateExtD
3503             , defPar.base.GetCodedPicWidth(defPar)
3504             , defPar.base.GetCodedPicHeight(defPar)
3505             , par.mfx.NumRefFrame
3506             , nCol
3507             , nRow
3508             , par.mfx.NumSlice
3509             , BufferSizeInKB(par.mfx)
3510             , MaxKbps(par.mfx)
3511             , MFX_LEVEL_HEVC_1);
3512     };
3513 
3514     if (pHEVC)
3515     {
3516         pHEVC->LCUSize = defPar.base.GetLCUSize(defPar);
3517     }
3518 
3519     SetDefaultFormat(par, defPar, pCO3);
3520     SetDefault(par.mfx.CodecProfile, defPar.base.GetProfile(defPar));
3521     SetDefault(par.AsyncDepth, defPar.base.GetAsyncDepth(defPar));
3522     SetDefault(par.IOPattern, IOPByAlctr[!!bExternalFrameAllocator]);
3523     SetDefault(par.mfx.TargetUsage, mfxU16(4)) && CheckTU(par, defPar.caps);
3524 
3525     if (pTile)
3526     {
3527         std::tie(pTile->NumTileColumns, pTile->NumTileRows) = defPar.base.GetNumTiles(defPar);
3528     }
3529 
3530     SetDefault(par.mfx.NumSlice, GetNumSlices);
3531 
3532     SetDefaultSize(par, defPar, pHEVC);
3533     SetDefaultGOP(par, defPar, pCO2, pCO3);
3534     SetDefaultBRC(par, defPar, pCO2, pCO3);
3535 
3536     if (pTL)
3537     {
3538         SetDefault(pTL->Layer[0].Scale, mfxU16(1));
3539     }
3540 
3541     SetDefault(par.mfx.CodecLevel, GetDefaultLevel);
3542 
3543     SetDefaultEsOptions(par, defPar, pHEVC, pCO, pCO2, pCO3);
3544 
3545     if (pCO2)
3546     {
3547         auto minQP = defPar.base.GetMinQPMFX(defPar);
3548         auto maxQP = defPar.base.GetMaxQPMFX(defPar);
3549 
3550         SetDefault(pCO2->IntRefCycleSize, mfxU16(CeilDiv(fi.FrameRateExtN, fi.FrameRateExtD) * !!pCO2->IntRefType));
3551 
3552         SetDefault(pCO2->MinQPI, minQP);
3553         SetDefault(pCO2->MinQPP, minQP);
3554         SetDefault(pCO2->MinQPB, minQP);
3555         SetDefault(pCO2->MaxQPI, maxQP);
3556         SetDefault(pCO2->MaxQPP, maxQP);
3557         SetDefault(pCO2->MaxQPB, maxQP);
3558     }
3559 
3560     bool bSetConstr = pHEVC && (par.mfx.CodecProfile >= MFX_PROFILE_HEVC_REXT && !pHEVC->GeneralConstraintFlags);
3561 
3562     if (bSetConstr)
3563     {
3564         auto& constr = pHEVC->GeneralConstraintFlags;
3565         mfxU16 bdY = defPar.base.GetTargetBitDepthLuma(defPar);
3566         mfxU16 cf = defPar.base.GetTargetChromaFormat(defPar) - 1;
3567 
3568         constr |= MFX_HEVC_CONSTR_REXT_MAX_422CHROMA * (cf <= MFX_CHROMAFORMAT_YUV422);
3569         constr |= MFX_HEVC_CONSTR_REXT_MAX_420CHROMA * (cf <= MFX_CHROMAFORMAT_YUV420);
3570         constr |= MFX_HEVC_CONSTR_REXT_MAX_12BIT * (bdY <= 12);
3571         constr |= MFX_HEVC_CONSTR_REXT_MAX_10BIT * (bdY <= 10);
3572         //there is no Main 4:2:2 in current standard spec.(2016/12), only Main 4:2:2 10
3573         constr |= MFX_HEVC_CONSTR_REXT_MAX_8BIT * (bdY <= 8 && (cf != MFX_CHROMAFORMAT_YUV422));
3574         constr |= MFX_HEVC_CONSTR_REXT_LOWER_BIT_RATE;
3575     }
3576 }
3577 
CheckLevelConstraints(mfxVideoParam & par,const Defaults::Param & defPar)3578 mfxStatus Legacy::CheckLevelConstraints(
3579     mfxVideoParam & par
3580     , const Defaults::Param& defPar)
3581 {
3582     MFX_CHECK(par.mfx.CodecLevel, MFX_ERR_NONE);
3583 
3584     mfxU16 PicWidthInLumaSamples    = defPar.base.GetCodedPicWidth(defPar);
3585     mfxU16 PicHeightInLumaSamples   = defPar.base.GetCodedPicHeight(defPar);
3586     mfxU16 MinRef                   = defPar.base.GetNumRefFrames(defPar);
3587     mfxU32 NumSlice                 = defPar.base.GetNumSlices(defPar);
3588     mfxU32 BufferSizeInKB           = defPar.base.GetBufferSizeInKB(defPar);
3589     mfxU32 MaxKbps                  = 0;
3590     mfxU16 rc                       = defPar.base.GetRateControlMethod(defPar);
3591     auto   tiles                    = defPar.base.GetNumTiles(defPar);
3592     auto   frND                     = defPar.base.GetFrameRate(defPar);
3593 
3594     SetIf(MaxKbps
3595         , rc != MFX_RATECONTROL_CQP && rc != MFX_RATECONTROL_ICQ
3596         , [&]() { return defPar.base.GetMaxKbps(defPar); });
3597 
3598     mfxU16 minLevel = GetMinLevel(
3599           std::get<0>(frND)
3600         , std::get<1>(frND)
3601         , PicWidthInLumaSamples
3602         , PicHeightInLumaSamples
3603         , MinRef
3604         , std::get<0>(tiles)
3605         , std::get<1>(tiles)
3606         , NumSlice
3607         , BufferSizeInKB
3608         , MaxKbps
3609         , par.mfx.CodecLevel);
3610 
3611     MFX_CHECK(!CheckMinOrClip(par.mfx.CodecLevel, minLevel), MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
3612 
3613     return MFX_ERR_NONE;
3614 }
3615 
CheckESPackParam(mfxVideoParam & par,eMFXHWType hw)3616 mfxStatus Legacy::CheckESPackParam(mfxVideoParam & par, eMFXHWType hw)
3617 {
3618     mfxU32 changed = 0;
3619     mfxExtCodingOption*     pCO = ExtBuffer::Get(par);
3620     mfxExtCodingOption2*    pCO2 = ExtBuffer::Get(par);
3621     mfxExtCodingOption3*    pCO3 = ExtBuffer::Get(par);
3622     mfxExtVideoSignalInfo*  pVSI = ExtBuffer::Get(par);
3623 
3624     if (pCO)
3625     {
3626         bool bNoHRD = par.mfx.RateControlMethod != MFX_RATECONTROL_CBR
3627             && par.mfx.RateControlMethod != MFX_RATECONTROL_VBR
3628             && par.mfx.RateControlMethod != MFX_RATECONTROL_VCM
3629             && par.mfx.RateControlMethod != MFX_RATECONTROL_QVBR;
3630 
3631         changed += CheckOrZero<mfxU16>(
3632             pCO->NalHrdConformance
3633             , mfxU16(MFX_CODINGOPTION_UNKNOWN)
3634             , mfxU16(MFX_CODINGOPTION_OFF)
3635             , mfxU16(MFX_CODINGOPTION_ON * !bNoHRD));
3636 
3637         changed += CheckOrZero<mfxU16>(
3638             pCO->VuiNalHrdParameters
3639             , mfxU16(MFX_CODINGOPTION_UNKNOWN)
3640             , mfxU16(MFX_CODINGOPTION_OFF)
3641             , mfxU16(MFX_CODINGOPTION_ON * !(bNoHRD || IsOff(pCO->NalHrdConformance))));
3642 
3643         changed += CheckTriStateOrZero(pCO->PicTimingSEI);
3644         changed += CheckTriStateOrZero(pCO->AUDelimiter);
3645     }
3646 
3647     if (pCO2)
3648         changed += CheckTriStateOrZero(pCO2->RepeatPPS);
3649 
3650     if (pVSI)
3651     {
3652         changed += CheckRangeOrSetDefault<mfxU16>(pVSI->VideoFormat, 0, 8, 5);
3653         changed += CheckRangeOrSetDefault<mfxU16>(pVSI->ColourPrimaries, 0, 255, 2);
3654         changed += CheckRangeOrSetDefault<mfxU16>(pVSI->TransferCharacteristics, 0, 255, 2);
3655         changed += CheckRangeOrSetDefault<mfxU16>(pVSI->MatrixCoefficients, 0, 255, 2);
3656         changed += CheckOrZero<mfxU16, 0, 1>(pVSI->VideoFullRange);
3657         changed += CheckOrZero<mfxU16, 0, 1>(pVSI->ColourDescriptionPresent);
3658     }
3659 
3660     if (pCO3)
3661     {
3662         changed += CheckOrZero<mfxU16>(
3663             pCO3->TransformSkip
3664             , mfxU16(MFX_CODINGOPTION_UNKNOWN)
3665             , mfxU16(MFX_CODINGOPTION_OFF)
3666             , mfxU16(MFX_CODINGOPTION_ON * (hw >= MFX_HW_CNL)));
3667 
3668         changed += CheckOrZero<mfxU16>(
3669             pCO3->EnableNalUnitType
3670             , mfxU16(MFX_CODINGOPTION_UNKNOWN)
3671             , mfxU16(MFX_CODINGOPTION_OFF)
3672             , mfxU16(MFX_CODINGOPTION_ON * !!par.mfx.EncodedOrder));
3673 
3674 #if MFX_VERSION >= MFX_VERSION_NEXT
3675         changed += CheckRangeOrSetDefault<mfxI16>(pCO3->DeblockingAlphaTcOffset, -12, 12, 0);
3676         changed += CheckRangeOrSetDefault<mfxI16>(pCO3->DeblockingBetaOffset, -12, 12, 0);
3677 #endif
3678     }
3679 
3680     MFX_CHECK(!changed, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
3681     return MFX_ERR_NONE;
3682 }
3683 
CheckGPB(mfxVideoParam & par)3684 mfxStatus Legacy::CheckGPB(mfxVideoParam & par)
3685 {
3686     mfxU32 changed = 0;
3687     mfxExtCodingOption3* pCO3 = ExtBuffer::Get(par);
3688 
3689     if (pCO3)
3690     {
3691         changed += CheckOrZero<mfxU16>(
3692             pCO3->GPB
3693             , mfxU16(MFX_CODINGOPTION_ON)
3694             , mfxU16(MFX_CODINGOPTION_OFF * !!m_pQWCDefaults->caps.msdk.PSliceSupport)
3695             , mfxU16(MFX_CODINGOPTION_UNKNOWN));
3696     }
3697 
3698     MFX_CHECK(!changed, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
3699     return MFX_ERR_NONE;
3700 }
3701 
CheckSkipFrame(mfxVideoParam & par)3702 mfxStatus Legacy::CheckSkipFrame(mfxVideoParam & par)
3703 {
3704     mfxExtCodingOption2* pCO2 = ExtBuffer::Get(par);
3705 
3706     if (pCO2 && CheckOrZero<mfxU16
3707         , MFX_SKIPFRAME_NO_SKIP
3708         , MFX_SKIPFRAME_INSERT_DUMMY
3709         , MFX_SKIPFRAME_INSERT_NOTHING>
3710         (pCO2->SkipFrame))
3711         return MFX_WRN_INCOMPATIBLE_VIDEO_PARAM;
3712 
3713     return MFX_ERR_NONE;
3714 }
3715 
CheckIntraRefresh(mfxVideoParam & par,const Defaults::Param & defPar)3716 mfxStatus Legacy::CheckIntraRefresh(
3717     mfxVideoParam & par
3718     , const Defaults::Param& defPar)
3719 {
3720     mfxStatus sts = MFX_ERR_NONE;
3721     mfxU32 changed = 0;
3722     mfxExtCodingOption2* pCO2 = ExtBuffer::Get(par);
3723     mfxExtCodingOption3* pCO3 = ExtBuffer::Get(par);
3724 
3725     if (pCO2)
3726     {
3727         MFX_CHECK_NO_RET(
3728             !CheckMaxOrClip(pCO2->IntRefType, MFX_REFRESH_HORIZONTAL)
3729             , sts, MFX_ERR_UNSUPPORTED);
3730 
3731         MFX_CHECK_NO_RET(
3732             defPar.caps.RollingIntraRefresh
3733             || !CheckOrZero<mfxU16>(pCO2->IntRefType, MFX_REFRESH_NO)
3734             , sts, MFX_ERR_UNSUPPORTED);
3735 
3736         MFX_CHECK_NO_RET(
3737             defPar.caps.RollingIntraRefresh
3738             || !CheckOrZero<mfxU16>(pCO2->IntRefCycleSize, 0)
3739             , sts, MFX_ERR_UNSUPPORTED);
3740 
3741         MFX_CHECK_NO_RET(
3742             defPar.caps.RollingIntraRefresh
3743             || !pCO3
3744             || !CheckOrZero<mfxU16>(pCO3->IntRefCycleDist, 0)
3745             , sts, MFX_ERR_UNSUPPORTED);
3746 
3747         // B-Frames should be disabled for intra refresh
3748         if (pCO2->IntRefType && par.mfx.GopRefDist > 1)
3749         {
3750             pCO2->IntRefType = MFX_REFRESH_NO;
3751             ++changed;
3752         }
3753 
3754         // refresh cycle length shouldn't be greater or equal to GOP size
3755         bool bInvalidCycle =
3756             pCO2->IntRefCycleSize != 0
3757             && par.mfx.GopPicSize != 0
3758             && pCO2->IntRefCycleSize >= par.mfx.GopPicSize;
3759 
3760         pCO2->IntRefType *= !bInvalidCycle;
3761         pCO2->IntRefCycleSize *= !bInvalidCycle;
3762         changed += bInvalidCycle;
3763 
3764         // refresh period shouldn't be greater than refresh cycle size
3765         bool bInvalidDist =
3766             pCO3
3767             && pCO3->IntRefCycleDist != 0
3768             && pCO2->IntRefCycleSize != 0
3769             && pCO2->IntRefCycleSize > pCO3->IntRefCycleDist;
3770 
3771         if (bInvalidDist)
3772         {
3773             pCO3->IntRefCycleDist = 0;
3774             ++changed;
3775         }
3776 
3777         mfxI16 qpDiff = defPar.base.GetMaxQPMFX(defPar) - defPar.base.GetMinQPMFX(defPar);
3778 
3779         changed += CheckRangeOrSetDefault(pCO2->IntRefQPDelta, mfxI16(-qpDiff), qpDiff, mfxI16(0));
3780     }
3781     MFX_CHECK_STS(sts);
3782 
3783     MFX_CHECK(!changed, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
3784     return MFX_ERR_NONE;
3785 }
3786 
CheckTemporalLayers(mfxVideoParam & par)3787 mfxStatus Legacy::CheckTemporalLayers(mfxVideoParam & par)
3788 {
3789     mfxU32 changed = 0;
3790     mfxExtAvcTemporalLayers* pTL = ExtBuffer::Get(par);
3791 
3792     MFX_CHECK(pTL, MFX_ERR_NONE);
3793     MFX_CHECK(!CheckOrZero<mfxU16>(pTL->Layer[0].Scale, 0, 1), MFX_ERR_UNSUPPORTED);
3794     MFX_CHECK(!CheckOrZero<mfxU16>(pTL->Layer[7].Scale, 0), MFX_ERR_UNSUPPORTED);
3795 
3796     mfxU16 nTL = 1;
3797 
3798     for (mfxU16 i = 1, prev = 0; i < 7; ++i)
3799     {
3800         if (!pTL->Layer[i].Scale)
3801             continue;
3802 
3803         auto& scaleCurr = pTL->Layer[i].Scale;
3804         auto  scalePrev = pTL->Layer[prev].Scale;
3805 
3806         MFX_CHECK(!CheckMinOrZero(scaleCurr, scalePrev + 1), MFX_ERR_UNSUPPORTED);
3807         MFX_CHECK(scalePrev, MFX_ERR_UNSUPPORTED);
3808         MFX_CHECK(!CheckOrZero(scaleCurr, mfxU16(scaleCurr - (scaleCurr % scalePrev))), MFX_ERR_UNSUPPORTED);
3809 
3810         prev = i;
3811         ++nTL;
3812     }
3813 
3814     changed += CheckOrZero<mfxU16>(par.mfx.GopRefDist, 0, 1, par.mfx.GopRefDist * (nTL <= 1));
3815 
3816     MFX_CHECK(!changed, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
3817     return MFX_ERR_NONE;
3818 }
3819 
CheckPPyramid(mfxVideoParam & par)3820 mfxStatus Legacy::CheckPPyramid(mfxVideoParam & par)
3821 {
3822     mfxU32 changed = 0;
3823     mfxExtCodingOption3* pCO3 = ExtBuffer::Get(par);
3824 
3825     if (pCO3)
3826     {
3827         changed += CheckOrZero<mfxU16
3828             , MFX_P_REF_DEFAULT
3829             , MFX_P_REF_SIMPLE
3830             , MFX_P_REF_PYRAMID>
3831             (pCO3->PRefType);
3832 
3833         if (pCO3->PRefType == MFX_P_REF_PYRAMID && par.mfx.GopRefDist > 1)
3834         {
3835             pCO3->PRefType = MFX_P_REF_DEFAULT;
3836             changed++;
3837         }
3838     }
3839 
3840     MFX_CHECK(!changed, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
3841     return MFX_ERR_NONE;
3842 }
3843 
CheckBPyramid(mfxVideoParam & par,const Defaults::Param & defPar)3844 mfxStatus Legacy::CheckBPyramid(
3845     mfxVideoParam & par
3846     , const Defaults::Param& defPar)
3847 {
3848     mfxU32 changed = 0;
3849     mfxExtCodingOption2* pCO2 = ExtBuffer::Get(par);
3850 
3851     if (pCO2)
3852     {
3853         mfxU16 minRefForPyramid = 3;
3854 
3855         if (par.mfx.GopRefDist)
3856             minRefForPyramid = defPar.base.GetMinRefForBPyramid(defPar);
3857 
3858         bool bNoBPyramid =
3859             par.mfx.GopRefDist > 0
3860             && (   par.mfx.GopRefDist < 2
3861                 || minRefForPyramid > 16
3862                 || (par.mfx.NumRefFrame
3863                     && (minRefForPyramid > par.mfx.NumRefFrame)
3864                     && !defPar.base.GetNonStdReordering(defPar)));
3865 
3866         changed += CheckOrZero(pCO2->BRefType
3867             , mfxU16(MFX_B_REF_UNKNOWN)
3868             , mfxU16(MFX_B_REF_OFF)
3869             , mfxU16(MFX_B_REF_PYRAMID * !bNoBPyramid));
3870     }
3871 
3872     MFX_CHECK(!changed, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
3873     return MFX_ERR_NONE;
3874 }
3875 
CheckSlices(mfxVideoParam & par,const Defaults::Param & defPar)3876 mfxStatus Legacy::CheckSlices(
3877     mfxVideoParam & par
3878     , const Defaults::Param& defPar)
3879 {
3880     mfxU32 changed = 0;
3881     mfxExtCodingOption2* pCO2 = ExtBuffer::Get(par);
3882     bool bCheckNMB = pCO2 && pCO2->NumMbPerSlice;
3883 
3884     if (bCheckNMB)
3885     {
3886         auto   tiles            = defPar.base.GetNumTiles(defPar);
3887         mfxU16 W                = defPar.base.GetCodedPicWidth(defPar);
3888         mfxU16 H                = defPar.base.GetCodedPicHeight(defPar);
3889         mfxU16 LCUSize          = defPar.base.GetLCUSize(defPar);
3890         mfxU32 nLCU             = CeilDiv(W, LCUSize) * CeilDiv(H, LCUSize);
3891         mfxU32 nTile            = std::get<0>(tiles) * std::get<1>(tiles);
3892         mfxU32 maxSlicesPerTile = MAX_SLICES / nTile;
3893         mfxU32 maxSlicesTotal   = maxSlicesPerTile * nTile;
3894         mfxU32 maxNumMbPerSlice = CeilDiv(nLCU, nTile);
3895         mfxU32 minNumMbPerSlice = CeilDiv(nLCU, maxSlicesTotal);
3896 
3897         changed += CheckMinOrClip(pCO2->NumMbPerSlice, minNumMbPerSlice);
3898         changed += CheckMaxOrClip(pCO2->NumMbPerSlice, maxNumMbPerSlice);
3899     }
3900 
3901     std::vector<SliceInfo> slices;
3902 
3903     auto supportedNslices = defPar.base.GetSlices(defPar, slices);
3904     if (par.mfx.NumSlice)
3905     {
3906         changed += CheckRangeOrSetDefault(par.mfx.NumSlice, supportedNslices, supportedNslices, supportedNslices);
3907     }
3908 
3909     if (bCheckNMB)
3910     {
3911         auto itMaxSlice = std::max_element(slices.begin(), slices.end()
3912             , [](SliceInfo a, SliceInfo b){ return a.NumLCU < b.NumLCU; });
3913 
3914         if (itMaxSlice != std::end(slices))
3915             changed += CheckMinOrClip(pCO2->NumMbPerSlice, itMaxSlice->NumLCU);
3916     }
3917 
3918     MFX_CHECK(!changed, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
3919     return MFX_ERR_NONE;
3920 }
3921 
CheckNumRefFrame(mfxVideoParam & par,const Defaults::Param & defPar)3922 mfxStatus Legacy::CheckNumRefFrame(
3923     mfxVideoParam & par
3924     , const Defaults::Param& defPar)
3925 {
3926     mfxU32 changed = 0;
3927 
3928     changed += CheckMaxOrClip(par.mfx.NumRefFrame, defPar.base.GetMaxDPB(defPar) - 1);
3929     changed += SetIf(
3930         par.mfx.NumRefFrame
3931         , (par.mfx.GopRefDist > 1
3932             && par.mfx.NumRefFrame == 1
3933             && !defPar.base.GetNonStdReordering(defPar))
3934         , defPar.base.GetMinRefForBNoPyramid(defPar));
3935 
3936     MFX_CHECK(!changed, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
3937     return MFX_ERR_NONE;
3938 }
3939 
CheckFrameRate(mfxVideoParam & par)3940 mfxStatus Legacy::CheckFrameRate(mfxVideoParam & par)
3941 {
3942     auto& fi = par.mfx.FrameInfo;
3943 
3944     if (fi.FrameRateExtN && fi.FrameRateExtD) // FR <= 300
3945     {
3946         if (fi.FrameRateExtN > mfxU32(300 * fi.FrameRateExtD))
3947         {
3948             fi.FrameRateExtN = fi.FrameRateExtD = 0;
3949             return MFX_ERR_UNSUPPORTED;
3950         }
3951     }
3952 
3953     if ((fi.FrameRateExtN == 0) != (fi.FrameRateExtD == 0))
3954     {
3955         fi.FrameRateExtN = 0;
3956         fi.FrameRateExtD = 0;
3957         return MFX_ERR_UNSUPPORTED;
3958     }
3959 
3960     return MFX_ERR_NONE;
3961 }
3962 
IsInVideoMem(const mfxVideoParam & par,const mfxExtOpaqueSurfaceAlloc * pOSA)3963 bool Legacy::IsInVideoMem(const mfxVideoParam & par, const mfxExtOpaqueSurfaceAlloc* pOSA)
3964 {
3965     if (par.IOPattern == MFX_IOPATTERN_IN_VIDEO_MEMORY)
3966         return true;
3967 
3968     if (par.IOPattern == MFX_IOPATTERN_IN_OPAQUE_MEMORY)
3969         return (!pOSA || (pOSA->In.Type & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)));
3970 
3971     return false;
3972 }
3973 
CheckShift(mfxVideoParam & par,mfxExtOpaqueSurfaceAlloc * pOSA)3974 mfxStatus Legacy::CheckShift(mfxVideoParam & par, mfxExtOpaqueSurfaceAlloc* pOSA)
3975 {
3976     auto& fi = par.mfx.FrameInfo;
3977     bool bVideoMem = IsInVideoMem(par, pOSA);
3978 
3979     if (bVideoMem && !fi.Shift)
3980     {
3981         if (fi.FourCC == MFX_FOURCC_P010 || fi.FourCC == MFX_FOURCC_P210)
3982         {
3983             fi.Shift = 1;
3984             return MFX_WRN_INCOMPATIBLE_VIDEO_PARAM;
3985         }
3986     }
3987 
3988     return MFX_ERR_NONE;
3989 }
3990 
CheckCrops(mfxVideoParam & par,const Defaults::Param & defPar)3991 mfxStatus Legacy::CheckCrops(
3992     mfxVideoParam & par
3993     , const Defaults::Param& defPar)
3994 {
3995     mfxU32 changed = 0;
3996 
3997     auto W = defPar.base.GetCodedPicWidth(defPar);
3998     auto H = defPar.base.GetCodedPicHeight(defPar);
3999     auto& fi = par.mfx.FrameInfo;
4000 
4001     changed += CheckMaxOrClip(fi.CropX, W);
4002     changed += CheckMaxOrClip(fi.CropW, W - fi.CropX);
4003     changed += CheckMaxOrClip(fi.CropY, H);
4004     changed += CheckMaxOrClip(fi.CropH, H - fi.CropY);
4005 
4006     MFX_CHECK(!changed, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
4007     return MFX_ERR_NONE;
4008 }
4009 
IsSWBRC(mfxVideoParam const & par,const mfxExtCodingOption2 * pCO2)4010 bool Legacy::IsSWBRC(mfxVideoParam const & par, const mfxExtCodingOption2* pCO2)
4011 {
4012     return
4013         (      pCO2 && IsOn(pCO2->ExtBRC)
4014             && (   par.mfx.RateControlMethod == MFX_RATECONTROL_CBR
4015                 || par.mfx.RateControlMethod == MFX_RATECONTROL_VBR))
4016         || par.mfx.RateControlMethod == MFX_RATECONTROL_LA_EXT;
4017 }
4018 
CheckBufferSizeInKB(mfxVideoParam & par,const Defaults::Param & defPar,mfxU16 bd)4019 bool CheckBufferSizeInKB(
4020     mfxVideoParam & par
4021     , const Defaults::Param& defPar
4022     , mfxU16 bd)
4023 {
4024     mfxU32 changed = 0;
4025     auto W = defPar.base.GetCodedPicWidth(defPar);
4026     auto H = defPar.base.GetCodedPicHeight(defPar);
4027     mfxU16 cf = defPar.base.GetTargetChromaFormat(defPar) - 1;
4028 
4029     mfxU32 rawBytes = Legacy::GetRawBytes(W, H, cf, bd) / 1000;
4030 
4031     bool bCqpOrIcq =
4032         par.mfx.RateControlMethod == MFX_RATECONTROL_CQP
4033         || par.mfx.RateControlMethod == MFX_RATECONTROL_ICQ;
4034 
4035     bool bSetToRaw = bCqpOrIcq && BufferSizeInKB(par.mfx) < rawBytes;
4036 
4037     if (bSetToRaw)
4038     {
4039         BufferSizeInKB(par.mfx) = rawBytes;
4040         changed++;
4041     }
4042     else if (!bCqpOrIcq)
4043     {
4044         mfxU32 frN, frD;
4045 
4046         std::tie(frN, frD) = defPar.base.GetFrameRate(defPar);
4047         mfxU32 avgFS = mfxU32(std::ceil((mfxF64)TargetKbps(par.mfx) * frD / frN / 8));
4048 
4049         if (BufferSizeInKB(par.mfx) < avgFS * 2 + 1)
4050         {
4051             BufferSizeInKB(par.mfx) = avgFS * 2 + 1;
4052             changed++;
4053         }
4054 
4055         if (par.mfx.CodecLevel)
4056         {
4057             mfxU32 maxCPB = GetMaxCpbInKBByLevel(par);
4058 
4059             if (BufferSizeInKB(par.mfx) > maxCPB)
4060             {
4061                 BufferSizeInKB(par.mfx) = maxCPB;
4062                 changed++;
4063             }
4064         }
4065     }
4066 
4067     return !!changed;
4068 }
4069 
CheckBRC(mfxVideoParam & par,const Defaults::Param & defPar)4070 mfxStatus Legacy::CheckBRC(
4071     mfxVideoParam & par
4072     , const Defaults::Param& defPar)
4073 {
4074     mfxU32 changed = 0;
4075     mfxExtCodingOption2* pCO2 = ExtBuffer::Get(par);
4076     mfxExtCodingOption3* pCO3 = ExtBuffer::Get(par);
4077 
4078     if (par.mfx.RateControlMethod == MFX_RATECONTROL_AVBR)
4079     {
4080         par.mfx.RateControlMethod = MFX_RATECONTROL_VBR;
4081         par.mfx.Accuracy          = 0;
4082         par.mfx.Convergence       = 0;
4083         changed++;
4084     }
4085 
4086     MFX_CHECK(!CheckOrZero<mfxU16>(par.mfx.RateControlMethod
4087         , 0
4088         , !!defPar.caps.msdk.CBRSupport * MFX_RATECONTROL_CBR
4089         , !!defPar.caps.msdk.VBRSupport * MFX_RATECONTROL_VBR
4090         , !!defPar.caps.msdk.CQPSupport * MFX_RATECONTROL_CQP
4091         , MFX_RATECONTROL_LA_EXT
4092         , !!defPar.caps.msdk.ICQSupport * MFX_RATECONTROL_ICQ
4093         , !!defPar.caps.VCMBitRateControl * MFX_RATECONTROL_VCM
4094         , !!defPar.caps.QVBRBRCSupport * MFX_RATECONTROL_QVBR), MFX_ERR_UNSUPPORTED);
4095 
4096     MFX_CHECK(par.mfx.RateControlMethod != MFX_RATECONTROL_ICQ
4097         || !CheckMaxOrZero(par.mfx.ICQQuality, 51), MFX_ERR_UNSUPPORTED);
4098 
4099     changed += ((   par.mfx.RateControlMethod == MFX_RATECONTROL_VBR
4100                  || par.mfx.RateControlMethod == MFX_RATECONTROL_QVBR
4101                  || par.mfx.RateControlMethod == MFX_RATECONTROL_VCM)
4102                 && par.mfx.MaxKbps != 0
4103                 && par.mfx.TargetKbps != 0)
4104         && CheckMinOrClip(par.mfx.MaxKbps, par.mfx.TargetKbps)
4105         && CheckMaxOrClip(par.mfx.TargetKbps, par.mfx.MaxKbps);
4106 
4107     auto bd = defPar.base.GetTargetBitDepthLuma(defPar);
4108     auto minQP = defPar.base.GetMinQPMFX(defPar);
4109     auto maxQP = defPar.base.GetMaxQPMFX(defPar);
4110 
4111     if (par.mfx.RateControlMethod == MFX_RATECONTROL_CQP)
4112     {
4113         changed += par.mfx.QPI && CheckMinOrClip<mfxU16>(par.mfx.QPI, minQP);
4114         changed += par.mfx.QPI && CheckMaxOrClip<mfxU16>(par.mfx.QPI, maxQP);
4115         changed += par.mfx.QPP && CheckMinOrClip<mfxU16>(par.mfx.QPP, minQP);
4116         changed += par.mfx.QPP && CheckMaxOrClip<mfxU16>(par.mfx.QPP, maxQP);
4117         changed += par.mfx.QPB && CheckMinOrClip<mfxU16>(par.mfx.QPB, minQP);
4118         changed += par.mfx.QPB && CheckMaxOrClip<mfxU16>(par.mfx.QPB, maxQP);
4119     }
4120 
4121     changed += par.mfx.BufferSizeInKB && CheckBufferSizeInKB(par, defPar, bd);
4122 
4123     if (pCO3)
4124     {
4125         MFX_CHECK(par.mfx.RateControlMethod != MFX_RATECONTROL_QVBR
4126             || !CheckMaxOrZero(pCO3->QVBRQuality, 51), MFX_ERR_UNSUPPORTED);
4127 
4128         auto    GopRefDist  = defPar.base.GetGopRefDist(defPar);
4129         mfxU16  QPPB[2]     = { par.mfx.QPP, par.mfx.QPB };
4130         mfxI16  QPX         = QPPB[GopRefDist != 1] * (par.mfx.RateControlMethod == MFX_RATECONTROL_CQP);
4131         bool    bNoQpOffset = (par.mfx.RateControlMethod != MFX_RATECONTROL_CQP)
4132             || (GopRefDist > 1 && defPar.base.GetBRefType(defPar) == MFX_B_REF_OFF)
4133             || (GopRefDist == 1 && defPar.base.GetPRefType(defPar) == MFX_P_REF_SIMPLE);
4134 
4135         changed += CheckOrZero<mfxU16>(pCO3->EnableQPOffset
4136             , mfxU16(MFX_CODINGOPTION_UNKNOWN)
4137             , mfxU16(MFX_CODINGOPTION_OFF)
4138             , mfxU16(MFX_CODINGOPTION_ON * !bNoQpOffset));
4139 
4140         auto CheckQPOffset = [&](mfxI16& QPO)
4141         {
4142             return
4143                 CheckMinOrClip(QPO, minQP - QPX)
4144                 + CheckMaxOrClip(QPO, maxQP - QPX);
4145         };
4146 
4147         changed +=
4148             IsOn(pCO3->EnableQPOffset)
4149             && QPX
4150             && std::count_if(std::begin(pCO3->QPOffset), std::end(pCO3->QPOffset), CheckQPOffset);
4151 
4152         changed += CheckOrZero(pCO3->EnableMBQP
4153             , mfxU16(MFX_CODINGOPTION_UNKNOWN)
4154             , mfxU16(MFX_CODINGOPTION_OFF)
4155             , mfxU16(MFX_CODINGOPTION_ON * !!(defPar.caps.MbQpDataSupport)));
4156 
4157         auto sts = defPar.base.CheckWinBRC(defPar, par);
4158         MFX_CHECK(sts >= MFX_ERR_NONE, sts);
4159 
4160         changed += (sts > MFX_ERR_NONE);
4161 
4162         changed += CheckOrZero(pCO3->BRCPanicMode
4163             , mfxU16(MFX_CODINGOPTION_UNKNOWN)
4164             , mfxU16(MFX_CODINGOPTION_OFF)
4165             , mfxU16(MFX_CODINGOPTION_ON * !!(defPar.caps.HRDConformanceSupport)));
4166     }
4167 
4168     if (pCO2)
4169     {
4170         changed += CheckTriStateOrZero(pCO2->MBBRC);
4171         changed += (   defPar.caps.MBBRCSupport == 0
4172                     || par.mfx.RateControlMethod == MFX_RATECONTROL_CQP
4173                     || IsSWBRC(par, pCO2))
4174                 && CheckOrZero<mfxU16, 0, MFX_CODINGOPTION_OFF>(pCO2->MBBRC);
4175 
4176         changed += !defPar.caps.SliceByteSizeCtrl && CheckOrZero<mfxU32, 0>(pCO2->MaxSliceSize);
4177 
4178         bool bMinMaxQpAllowed = (par.mfx.RateControlMethod != MFX_RATECONTROL_CQP) && (IsSWBRC(par, pCO2)||IsOn(par.mfx.LowPower));
4179 
4180         if (bMinMaxQpAllowed)
4181         {
4182             changed += pCO2->MinQPI && CheckRangeOrSetDefault<mfxU8>(pCO2->MinQPI,                        minQP,  maxQP, 0);
4183             changed += pCO2->MaxQPI && CheckRangeOrSetDefault<mfxU8>(pCO2->MaxQPI, std::max(pCO2->MinQPI, minQP), maxQP, 0);
4184             changed += pCO2->MinQPP && CheckRangeOrSetDefault<mfxU8>(pCO2->MinQPP,                        minQP,  maxQP, 0);
4185             changed += pCO2->MaxQPP && CheckRangeOrSetDefault<mfxU8>(pCO2->MaxQPP, std::max(pCO2->MinQPP, minQP), maxQP, 0);
4186             changed += pCO2->MinQPB && CheckRangeOrSetDefault<mfxU8>(pCO2->MinQPB,                        minQP,  maxQP, 0);
4187             changed += pCO2->MaxQPB && CheckRangeOrSetDefault<mfxU8>(pCO2->MaxQPB, std::max(pCO2->MinQPB, minQP), maxQP, 0);
4188         }
4189         else
4190         {
4191             changed += CheckOrZero<mfxU8>(pCO2->MinQPI, 0, minQP);
4192             changed += CheckOrZero<mfxU8>(pCO2->MaxQPI, 0, maxQP);
4193             changed += CheckOrZero<mfxU8>(pCO2->MinQPP, 0, minQP);
4194             changed += CheckOrZero<mfxU8>(pCO2->MaxQPP, 0, maxQP);
4195             changed += CheckOrZero<mfxU8>(pCO2->MinQPB, 0, minQP);
4196             changed += CheckOrZero<mfxU8>(pCO2->MaxQPB, 0, maxQP);
4197         }
4198     }
4199 
4200     MFX_CHECK(!changed, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
4201 
4202     return MFX_ERR_NONE;
4203 }
4204 
GetRawBytes(mfxU16 w,mfxU16 h,mfxU16 ChromaFormat,mfxU16 BitDepth)4205 mfxU32 Legacy::GetRawBytes(mfxU16 w, mfxU16 h, mfxU16 ChromaFormat, mfxU16 BitDepth)
4206 {
4207     mfxU32 s = w * h;
4208 
4209     if (ChromaFormat == MFX_CHROMAFORMAT_YUV420)
4210         s = s * 3 / 2;
4211     else if (ChromaFormat == MFX_CHROMAFORMAT_YUV422)
4212         s *= 2;
4213     else if (ChromaFormat == MFX_CHROMAFORMAT_YUV444)
4214         s *= 3;
4215 
4216     assert(BitDepth >= 8);
4217     if (BitDepth != 8)
4218         s = (s * BitDepth + 7) / 8;
4219 
4220     return s;
4221 }
CheckIOPattern(mfxVideoParam & par)4222 mfxStatus Legacy::CheckIOPattern(mfxVideoParam & par)
4223 {
4224     bool check_result = Check<mfxU16
4225                             , MFX_IOPATTERN_IN_VIDEO_MEMORY
4226                             , MFX_IOPATTERN_IN_SYSTEM_MEMORY
4227                             , MFX_IOPATTERN_IN_OPAQUE_MEMORY
4228                             , 0>
4229                             (par.IOPattern);
4230 
4231     MFX_CHECK(!check_result, MFX_ERR_INVALID_VIDEO_PARAM);
4232 
4233     return MFX_ERR_NONE;
4234 }
4235 
CheckGopRefDist(mfxVideoParam & par,const ENCODE_CAPS_HEVC & caps)4236 mfxStatus Legacy::CheckGopRefDist(mfxVideoParam & par, const ENCODE_CAPS_HEVC& caps)
4237 {
4238     MFX_CHECK(par.mfx.GopRefDist, MFX_ERR_NONE);
4239 
4240     mfxU16 maxRefDist = std::max<mfxU16>(1, !caps.SliceIPOnly * (par.mfx.GopPicSize - 1));
4241     MFX_CHECK(!CheckMaxOrClip(par.mfx.GopRefDist, maxRefDist), MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
4242 
4243     return MFX_ERR_NONE;
4244 }
4245 
CheckTU(mfxVideoParam & par,const ENCODE_CAPS_HEVC & caps)4246 mfxStatus Legacy::CheckTU(mfxVideoParam & par, const ENCODE_CAPS_HEVC& caps)
4247 {
4248     auto& tu = par.mfx.TargetUsage;
4249 
4250     if (CheckMaxOrZero(tu, 7u))
4251         return MFX_ERR_UNSUPPORTED;
4252 
4253     if (!tu)
4254         return MFX_ERR_NONE;
4255 
4256     auto support = caps.TUSupport;
4257     mfxI16 abs_diff = 0;
4258     bool   sign = 0;
4259     mfxI16 newtu = tu;
4260 
4261     do
4262     {
4263         newtu = tu + (1 - 2 * sign) * abs_diff;
4264         abs_diff += !sign;
4265         sign = !sign;
4266     } while (!(support & (1 << (newtu - 1))) && newtu > 0);
4267 
4268     if (tu != newtu)
4269     {
4270         tu = newtu;
4271         return MFX_WRN_INCOMPATIBLE_VIDEO_PARAM;
4272     }
4273 
4274     return MFX_ERR_NONE;
4275 
4276 }
4277 
CheckTiles(mfxVideoParam & par,const Defaults::Param & defPar)4278 mfxStatus Legacy::CheckTiles(
4279     mfxVideoParam & par
4280     , const Defaults::Param& defPar)
4281 {
4282     mfxExtHEVCTiles* pTile = ExtBuffer::Get(par);
4283     MFX_CHECK(pTile, MFX_ERR_NONE);
4284 
4285     mfxU16
4286         MaxTileColumns = MAX_NUM_TILE_COLUMNS
4287         , MaxTileRows    = MAX_NUM_TILE_ROWS
4288         , changed = 0;
4289 
4290     if (!defPar.caps.TileSupport)
4291     {
4292         MaxTileColumns = 1;
4293         MaxTileRows = 1;
4294     }
4295     else
4296     {
4297         mfxU32 minTileWidth  = MIN_TILE_WIDTH_IN_SAMPLES;
4298         mfxU32 minTileHeight = MIN_TILE_HEIGHT_IN_SAMPLES;
4299 
4300         // min 2x2 lcu is supported on VDEnc
4301         // TODO: replace indirect NumScalablePipesMinus1 by platform
4302         SetIf(minTileHeight, defPar.caps.NumScalablePipesMinus1 > 0 && IsOn(par.mfx.LowPower), 128);
4303 
4304         mfxU16 maxCol = std::max<mfxU16>(1, mfxU16(defPar.base.GetCodedPicWidth(defPar) / minTileWidth));
4305         mfxU16 maxRow = std::max<mfxU16>(1, mfxU16(defPar.base.GetCodedPicHeight(defPar) / minTileHeight));
4306 
4307         changed += CheckMaxOrClip(pTile->NumTileColumns, maxCol);
4308         changed += CheckMaxOrClip(pTile->NumTileRows, maxRow);
4309 
4310         // for ICL VDEnc only 1xN or Nx1 configurations are allowed for single pipe
4311         // we ignore "Rows" condition
4312         bool bForce1Row =
4313             (defPar.hw == MFX_HW_ICL || defPar.hw == MFX_HW_ICL_LP)
4314             && IsOn(par.mfx.LowPower)
4315             && pTile->NumTileColumns > 1
4316             && pTile->NumTileRows > 1;
4317 
4318         changed += bForce1Row && CheckMaxOrClip(pTile->NumTileRows, 1);
4319     }
4320 
4321     MFX_CHECK(!CheckMaxOrClip(pTile->NumTileColumns, MaxTileColumns), MFX_ERR_UNSUPPORTED);
4322     MFX_CHECK(!CheckMaxOrClip(pTile->NumTileRows, MaxTileRows), MFX_ERR_UNSUPPORTED);
4323 
4324 
4325     MFX_CHECK(!changed, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
4326 
4327     return MFX_ERR_NONE;
4328 }
4329 
CheckQuery0(const ParamSupport & sprt,mfxVideoParam & par)4330 void Legacy::CheckQuery0(const ParamSupport& sprt, mfxVideoParam& par)
4331 {
4332     std::vector<mfxU8> onesBuf(sizeof(par), 1);
4333 
4334     auto ExtParam    = par.ExtParam;
4335     auto NumExtParam = par.NumExtParam;
4336 
4337     par = mfxVideoParam{};
4338 
4339     for (auto& copy : sprt.m_mvpCopySupported)
4340         copy((mfxVideoParam*)onesBuf.data(), &par);
4341 
4342     par.ExtParam    = ExtParam;
4343     par.NumExtParam = NumExtParam;
4344 
4345     if (par.ExtParam)
4346     {
4347         for (mfxU32 i = 0; i < par.NumExtParam; i++)
4348         {
4349             if (!par.ExtParam[i])
4350                 continue;
4351 
4352             mfxExtBuffer header = *par.ExtParam[i];
4353 
4354             memset(par.ExtParam[i], 0, header.BufferSz);
4355             *par.ExtParam[i] = header;
4356 
4357             auto it = sprt.m_ebCopySupported.find(header.BufferId);
4358 
4359             if (it != sprt.m_ebCopySupported.end())
4360             {
4361                 if (onesBuf.size() < header.BufferSz)
4362                     onesBuf.insert(onesBuf.end(), header.BufferSz - mfxU32(onesBuf.size()), 1);
4363 
4364                 auto pSrc = (mfxExtBuffer*)onesBuf.data();
4365                 *pSrc = header;
4366 
4367                 for (auto& copy : it->second)
4368                     copy(pSrc, par.ExtParam[i]);
4369             }
4370         }
4371     }
4372 }
4373 
CheckBuffers(const ParamSupport & sprt,const mfxVideoParam & in,const mfxVideoParam * out)4374 mfxStatus Legacy::CheckBuffers(const ParamSupport& sprt, const mfxVideoParam& in, const mfxVideoParam* out)
4375 {
4376     MFX_CHECK(!(!in.NumExtParam && (!out || !out->NumExtParam)), MFX_ERR_NONE);
4377     MFX_CHECK(in.ExtParam, MFX_ERR_UNDEFINED_BEHAVIOR);
4378     MFX_CHECK(!(out && (!out->ExtParam || out->NumExtParam != in.NumExtParam))
4379         , MFX_ERR_UNDEFINED_BEHAVIOR);
4380 
4381     std::map<mfxU32, mfxU32> detected[2];
4382     mfxU32 dId = 0;
4383 
4384     for (auto pPar : { &in, out })
4385     {
4386         if (!pPar)
4387             continue;
4388 
4389         for (mfxU32 i = 0; i < pPar->NumExtParam; i++)
4390         {
4391             MFX_CHECK_NULL_PTR1(pPar->ExtParam[i]);
4392 
4393             auto id = pPar->ExtParam[i]->BufferId;
4394 
4395             MFX_CHECK(sprt.m_ebCopySupported.find(id) != sprt.m_ebCopySupported.end(), MFX_ERR_UNSUPPORTED);
4396             MFX_CHECK(!(detected[dId][id]++), MFX_ERR_UNDEFINED_BEHAVIOR);
4397         }
4398         dId++;
4399     }
4400 
4401     MFX_CHECK(!(out && detected[0] != detected[1]), MFX_ERR_UNDEFINED_BEHAVIOR);
4402 
4403     return MFX_ERR_NONE;
4404 }
4405 
CopyConfigurable(const ParamSupport & sprt,const mfxVideoParam & in,mfxVideoParam & out)4406 mfxStatus Legacy::CopyConfigurable(const ParamSupport& sprt, const mfxVideoParam& in, mfxVideoParam& out)
4407 {
4408     using TFnCopyMVP = std::function<void(const mfxVideoParam*, mfxVideoParam*)>;
4409     using TFnCopyEB  = std::function<void(const mfxExtBuffer*, mfxExtBuffer*)>;
4410 
4411     auto CopyMVP = [&](const mfxVideoParam& src, mfxVideoParam& dst)
4412     {
4413         std::for_each(sprt.m_mvpCopySupported.begin(), sprt.m_mvpCopySupported.end()
4414             , [&](const TFnCopyMVP& copy)
4415         {
4416             copy(&src, &dst);
4417         });
4418     };
4419     auto CopyEB = [](const std::list<TFnCopyEB>& copyList, const mfxExtBuffer* pIn, mfxExtBuffer* pOut)
4420     {
4421         std::for_each(copyList.begin(), copyList.end()
4422             , [&](const TFnCopyEB& copy)
4423         {
4424             copy(pIn, pOut);
4425         });
4426     };
4427     mfxVideoParam tmpMVP = {};
4428 
4429     CopyMVP(in, tmpMVP);
4430 
4431     tmpMVP.NumExtParam  = out.NumExtParam;
4432     tmpMVP.ExtParam     = out.ExtParam;
4433 
4434     out = tmpMVP;
4435 
4436     std::list<mfxExtBuffer*> outBufs(out.ExtParam, out.ExtParam + out.NumExtParam);
4437     outBufs.sort();
4438     outBufs.remove(nullptr);
4439 
4440     std::for_each(outBufs.begin(), outBufs.end()
4441         , [&](mfxExtBuffer* pEbOut)
4442     {
4443         std::vector<mfxU8> ebTmp(pEbOut->BufferSz, mfxU8(0));
4444         auto               pEbIn      = ExtBuffer::Get(in, pEbOut->BufferId);
4445         auto               copyIt     = sprt.m_ebCopySupported.find(pEbOut->BufferId);
4446         auto               copyPtrsIt = sprt.m_ebCopyPtrs.find(pEbOut->BufferId);
4447         mfxExtBuffer*      pEbTmp     = (mfxExtBuffer*)ebTmp.data();
4448         bool               bCopyPar   = pEbIn && copyIt != sprt.m_ebCopySupported.end();
4449         bool               bCopyPtr   = copyPtrsIt != sprt.m_ebCopyPtrs.end();
4450 
4451         *pEbTmp = *pEbOut;
4452 
4453         if (bCopyPtr)
4454         {
4455             CopyEB(copyPtrsIt->second, pEbOut, pEbTmp);
4456         }
4457 
4458         if (bCopyPar)
4459         {
4460             CopyEB(copyIt->second, pEbIn, pEbTmp);
4461         }
4462 
4463         std::copy_n(ebTmp.data(), ebTmp.size(), (mfxU8*)pEbOut);
4464     });
4465 
4466     return MFX_ERR_NONE;
4467 }
4468 
CheckCodedPicSize(mfxVideoParam & par,const Defaults::Param & defPar)4469 mfxStatus Legacy::CheckCodedPicSize(
4470     mfxVideoParam & par
4471     , const Defaults::Param& defPar)
4472 {
4473     mfxExtHEVCParam* pHEVC = ExtBuffer::Get(par);
4474     MFX_CHECK(pHEVC, MFX_ERR_NONE);
4475 
4476     auto alignment = defPar.base.GetCodedPicAlignment(defPar);
4477     auto& W = pHEVC->PicWidthInLumaSamples;
4478     auto& H = pHEVC->PicHeightInLumaSamples;
4479     auto AW = mfx::align2_value(W, alignment);
4480     auto AH = mfx::align2_value(H, alignment);
4481 
4482     MFX_CHECK(!CheckMaxOrZero(W, par.mfx.FrameInfo.Width), MFX_ERR_UNSUPPORTED);
4483     MFX_CHECK(!CheckMaxOrZero(H, par.mfx.FrameInfo.Height), MFX_ERR_UNSUPPORTED);
4484 
4485     if ((W != AW) || (H != AH))
4486     {
4487         W = AW;
4488         H = AH;
4489         return MFX_WRN_INCOMPATIBLE_VIDEO_PARAM;
4490     }
4491 
4492     return MFX_ERR_NONE;
4493 }
4494 
FrameType2SliceType(mfxU32 ft)4495 mfxU16 FrameType2SliceType(mfxU32 ft)
4496 {
4497     bool bB = IsB(ft);
4498     bool bP = !bB && IsP(ft);
4499     return 1 * bP + 2 * !(bB || bP);
4500 }
4501 
isCurrLt(DpbArray const & DPB,mfxU8 const (& RPL)[2][MAX_DPB_SIZE],mfxU8 const (& numRefActive)[2],mfxI32 poc)4502 bool isCurrLt(
4503     DpbArray const & DPB,
4504     mfxU8 const (&RPL)[2][MAX_DPB_SIZE],
4505     mfxU8 const (&numRefActive)[2],
4506     mfxI32 poc)
4507 {
4508     for (mfxU32 i = 0; i < 2; i++)
4509         for (mfxU32 j = 0; j < numRefActive[i]; j++)
4510             if (poc == DPB[RPL[i][j]].POC)
4511                 return DPB[RPL[i][j]].isLTR;
4512     return false;
4513 }
4514 
isCurrLt(const TaskCommonPar & task,mfxI32 poc)4515 inline bool isCurrLt(const TaskCommonPar & task, mfxI32 poc)
4516 {
4517     return isCurrLt(task.DPB.Active, task.RefPicList, task.NumRefActive, poc);
4518 }
4519 
Lsb(T val,mfxU32 maxLSB)4520 template<class T> inline T Lsb(T val, mfxU32 maxLSB)
4521 {
4522     if (val >= 0)
4523         return val % maxLSB;
4524     return (maxLSB - ((-val) % maxLSB)) % maxLSB;
4525 }
4526 
isForcedDeltaPocMsbPresent(const TaskCommonPar & prevTask,mfxI32 poc,mfxU32 MaxPocLsb)4527 bool isForcedDeltaPocMsbPresent(
4528     const TaskCommonPar & prevTask,
4529     mfxI32 poc,
4530     mfxU32 MaxPocLsb)
4531 {
4532     DpbArray const & DPB = prevTask.DPB.Active;
4533 
4534     if (Lsb(prevTask.POC, MaxPocLsb) == Lsb(poc, MaxPocLsb))
4535         return true;
4536 
4537     for (mfxU16 i = 0; !isDpbEnd(DPB, i); i++)
4538         if (DPB[i].POC != poc && Lsb(DPB[i].POC, MaxPocLsb) == Lsb(poc, MaxPocLsb))
4539             return true;
4540 
4541     return false;
4542 }
4543 
GetSliceHeaderLTRs(const TaskCommonPar & task,const TaskCommonPar & prevTask,const DpbArray & DPB,const SPS & sps,mfxI32 (& LTR)[MAX_NUM_LONG_TERM_PICS],Slice & s)4544 mfxU16 GetSliceHeaderLTRs(
4545     const TaskCommonPar& task
4546     , const TaskCommonPar& prevTask
4547     , const DpbArray & DPB
4548     , const SPS& sps
4549     , mfxI32 (&LTR)[MAX_NUM_LONG_TERM_PICS]
4550     , Slice & s)
4551 {
4552     mfxU16 nLTR = 0;
4553     size_t nDPBLT = 0;
4554     mfxU32 MaxPocLsb  = (1<<(sps.log2_max_pic_order_cnt_lsb_minus4+4));
4555     mfxU32 dPocCycleMSBprev = 0;
4556     mfxI32 DPBLT[MAX_DPB_SIZE] = {};
4557     mfxI32 InvalidPOC = -9000;
4558 
4559     std::transform(DPB, DPB + Size(DPB), DPBLT
4560         , [InvalidPOC](const DpbFrame& x) { return (x.isLTR && isValid(x)) ? x.POC : InvalidPOC; });
4561 
4562     nDPBLT = std::remove_if(DPBLT, DPBLT + Size(DPBLT)
4563         , [InvalidPOC](mfxI32 x) { return x == InvalidPOC; }) - DPBLT;
4564 
4565     std::sort(DPBLT, DPBLT + nDPBLT, std::greater<mfxI32>()); // sort for DeltaPocMsbCycleLt (may only increase)
4566 
4567     // insert LTR using lt_ref_pic_poc_lsb_sps
4568     std::for_each(DPBLT, DPBLT + nDPBLT, [&](mfxI32& ltpoc) {
4569         mfxU32 dPocCycleMSB = (task.POC / MaxPocLsb - ltpoc / MaxPocLsb);
4570         mfxU32 dPocLSB      = ltpoc - (task.POC - dPocCycleMSB * MaxPocLsb - s.pic_order_cnt_lsb);
4571 
4572         size_t ltId = std::find_if(
4573             sps.lt_ref_pic_poc_lsb_sps
4574             , sps.lt_ref_pic_poc_lsb_sps + sps.num_long_term_ref_pics_sps
4575             , [&](const mfxU16& ltPocLsb) {
4576             return dPocLSB == ltPocLsb
4577                 &&     isCurrLt(task, DPBLT[ltpoc])
4578                     == !!sps.used_by_curr_pic_lt_sps_flag[sps.lt_ref_pic_poc_lsb_sps - &ltPocLsb]
4579                 && dPocCycleMSB >= dPocCycleMSBprev;
4580         }) - sps.lt_ref_pic_poc_lsb_sps;
4581 
4582         if (ltId >= sps.num_long_term_ref_pics_sps)
4583             return;
4584 
4585         auto& curlt = s.lt[s.num_long_term_sps];
4586 
4587         curlt.lt_idx_sps                    = ltId;
4588         curlt.used_by_curr_pic_lt_flag      = !!sps.used_by_curr_pic_lt_sps_flag[ltId];
4589         curlt.poc_lsb_lt                    = sps.lt_ref_pic_poc_lsb_sps[ltId];
4590         curlt.delta_poc_msb_cycle_lt        = dPocCycleMSB - dPocCycleMSBprev;
4591         curlt.delta_poc_msb_present_flag    =
4592             !!curlt.delta_poc_msb_cycle_lt || isForcedDeltaPocMsbPresent(prevTask, ltpoc, MaxPocLsb);
4593         dPocCycleMSBprev                    = dPocCycleMSB;
4594 
4595         ++s.num_long_term_sps;
4596 
4597         if (curlt.used_by_curr_pic_lt_flag)
4598         {
4599             assert(nLTR < MAX_NUM_LONG_TERM_PICS);
4600             LTR[nLTR++] = ltpoc;
4601         }
4602 
4603         ltpoc = InvalidPOC;
4604     });
4605 
4606     nDPBLT = std::remove_if(DPBLT, DPBLT + nDPBLT
4607         , [InvalidPOC](mfxI32 x) { return x == InvalidPOC; }) - DPBLT;
4608     dPocCycleMSBprev = 0;
4609 
4610     std::for_each(DPBLT, DPBLT + nDPBLT, [&](mfxI32 ltpoc) {
4611         auto& curlt = s.lt[s.num_long_term_sps + s.num_long_term_pics];
4612         mfxU32 dPocCycleMSB = (task.POC / MaxPocLsb - ltpoc / MaxPocLsb);
4613         mfxU32 dPocLSB      = ltpoc - (task.POC - dPocCycleMSB * MaxPocLsb - s.pic_order_cnt_lsb);
4614 
4615         assert(dPocCycleMSB >= dPocCycleMSBprev);
4616 
4617         curlt.used_by_curr_pic_lt_flag      = isCurrLt(task, ltpoc);
4618         curlt.poc_lsb_lt                    = dPocLSB;
4619         curlt.delta_poc_msb_cycle_lt        = dPocCycleMSB - dPocCycleMSBprev;
4620         curlt.delta_poc_msb_present_flag    =
4621             !!curlt.delta_poc_msb_cycle_lt || isForcedDeltaPocMsbPresent(prevTask, ltpoc, MaxPocLsb);
4622         dPocCycleMSBprev                    = dPocCycleMSB;
4623 
4624         ++s.num_long_term_pics;
4625 
4626         if (curlt.used_by_curr_pic_lt_flag)
4627         {
4628             if (nLTR < MAX_NUM_LONG_TERM_PICS) //KW
4629                 LTR[nLTR++] = ltpoc;
4630             else
4631                 assert(!"too much LTRs");
4632         }
4633     });
4634 
4635     return nLTR;
4636 }
4637 
GetSliceHeaderRPLMod(const TaskCommonPar & task,const DpbArray & DPB,const mfxI32 (& STR)[2][MAX_DPB_SIZE],const mfxU16 (& nSTR)[2],const mfxI32 LTR[MAX_NUM_LONG_TERM_PICS],mfxU16 nLTR,Slice & s)4638 void GetSliceHeaderRPLMod(
4639     const TaskCommonPar& task
4640     , const DpbArray & DPB
4641     , const mfxI32 (&STR)[2][MAX_DPB_SIZE]
4642     , const mfxU16 (&nSTR)[2]
4643     , const mfxI32 LTR[MAX_NUM_LONG_TERM_PICS]
4644     , mfxU16 nLTR
4645     , Slice & s)
4646 {
4647     auto& RPL = task.RefPicList;
4648     auto ModLX = [&](mfxU16 lx, mfxU16 NumRpsCurrTempListX)
4649     {
4650         mfxU16 rIdx = 0;
4651         mfxI32 RPLTempX[16] = {}; // default ref. list without modifications
4652         auto AddRef = [&](mfxI32 ref) { RPLTempX[rIdx++] = ref; };
4653 
4654         while (rIdx < NumRpsCurrTempListX)
4655         {
4656             std::for_each(STR[lx], STR[lx] + std::min<mfxU16>(nSTR[lx], NumRpsCurrTempListX - rIdx), AddRef);
4657             std::for_each(STR[!lx], STR[!lx] + std::min<mfxU16>(nSTR[!lx], NumRpsCurrTempListX - rIdx), AddRef);
4658             std::for_each(LTR, LTR + std::min<mfxU16>(nLTR, NumRpsCurrTempListX - rIdx), AddRef);
4659         }
4660 
4661         for (rIdx = 0; rIdx < task.NumRefActive[lx]; rIdx++)
4662         {
4663             auto pRef = std::find_if(RPLTempX, RPLTempX + NumRpsCurrTempListX
4664                 , [&](mfxI32 ref) {return DPB[RPL[lx][rIdx]].POC == ref; });
4665             s.list_entry_lx[lx][rIdx] = mfxU8(pRef - RPLTempX);
4666             s.ref_pic_list_modification_flag_lx[lx] |= (s.list_entry_lx[lx][rIdx] != rIdx);
4667         }
4668     };
4669 
4670     ModLX(0, std::max<mfxU16>(nSTR[0] + nSTR[1] + nLTR, task.NumRefActive[0]));
4671     ModLX(1, std::max<mfxU16>(nSTR[0] + nSTR[1] + nLTR, task.NumRefActive[1]));
4672 }
4673 
GetSliceHeader(const ExtBuffer::Param<mfxVideoParam> & par,const TaskCommonPar & task,const SPS & sps,const PPS & pps,Slice & s)4674 mfxStatus Legacy::GetSliceHeader(
4675     const ExtBuffer::Param<mfxVideoParam> & par
4676     , const TaskCommonPar& task
4677     , const SPS& sps
4678     , const PPS& pps
4679     , Slice & s)
4680 {
4681     bool isP = IsP(task.FrameType);
4682     bool isB = IsB(task.FrameType);
4683     bool isI = IsI(task.FrameType);
4684 
4685     ThrowAssert(isP + isB + isI != 1, "task.FrameType is invalid");
4686 
4687     s = {};
4688 
4689     s.first_slice_segment_in_pic_flag = 1;
4690     s.no_output_of_prior_pics_flag    = 0;
4691     s.pic_parameter_set_id            = pps.pic_parameter_set_id;
4692     s.type                            = FrameType2SliceType(task.FrameType);
4693     s.pic_output_flag                 = !!pps.output_flag_present_flag;
4694 
4695     assert(0 == sps.separate_colour_plane_flag);
4696 
4697     bool bNonIdrNut = task.SliceNUT != IDR_W_RADL && task.SliceNUT != IDR_N_LP;
4698     if (bNonIdrNut)
4699     {
4700         mfxU16 nLTR = 0, nSTR[2] = {};
4701         mfxI32 STR[2][MAX_DPB_SIZE] = {};         // used short-term references
4702         mfxI32 LTR[MAX_NUM_LONG_TERM_PICS] = {};  // used long-term references
4703         const auto& DPB = task.DPB.Active;        // DPB before encoding
4704         const auto& RPL = task.RefPicList;        // Ref. Pic. List
4705         auto IsSame     = [&s](const STRPS& x)      { return Equal(x, s.strps); };
4706         auto IsLTR      = [](const DpbFrame& ref)   { return isValid(ref) && ref.isLTR; };
4707         auto IsL0Pic    = [](const STRPSPic& pic)   { return pic.used_by_curr_pic_sx_flag && (pic.DeltaPocSX <= 0); };
4708         auto IsL1Pic    = [](const STRPSPic& pic)   { return pic.used_by_curr_pic_sx_flag && (pic.DeltaPocSX > 0); };
4709         auto PicToPOC   = [&](const STRPSPic& pic)  { return (task.POC + pic.DeltaPocSX); };
4710 
4711         ConstructSTRPS(DPB, RPL, task.NumRefActive, task.POC, s.strps);
4712 
4713         s.pic_order_cnt_lsb = (task.POC & ~(0xFFFFFFFF << (sps.log2_max_pic_order_cnt_lsb_minus4 + 4)));
4714 
4715         s.short_term_ref_pic_set_idx      = mfxU8(std::find_if(sps.strps, sps.strps + sps.num_short_term_ref_pic_sets, IsSame) - sps.strps);
4716         s.short_term_ref_pic_set_sps_flag = (s.short_term_ref_pic_set_idx < sps.num_short_term_ref_pic_sets);
4717 
4718         if (!s.short_term_ref_pic_set_sps_flag)
4719             OptimizeSTRPS(sps.strps, sps.num_short_term_ref_pic_sets, s.strps, sps.num_short_term_ref_pic_sets);
4720 
4721         std::list<STRPSPic> picsUsed[2];
4722         auto itStrpsPicsBegin = s.strps.pic;
4723         auto itStrpsPicsEnd   = s.strps.pic + mfxU32(s.strps.num_negative_pics + s.strps.num_positive_pics);
4724 
4725         std::copy_if(itStrpsPicsBegin, itStrpsPicsEnd, std::back_inserter(picsUsed[0]), IsL0Pic);
4726         std::copy_if(itStrpsPicsBegin, itStrpsPicsEnd, std::back_inserter(picsUsed[1]), IsL1Pic);
4727 
4728         nSTR[0] = mfxU16(std::transform(picsUsed[0].begin(), picsUsed[0].end(), STR[0], PicToPOC) - STR[0]);
4729         nSTR[1] = mfxU16(std::transform(picsUsed[1].begin(), picsUsed[1].end(), STR[1], PicToPOC) - STR[1]);
4730 
4731         if (std::any_of(DPB, DPB + Size(DPB), IsLTR))
4732         {
4733             assert(sps.long_term_ref_pics_present_flag);
4734             nLTR = GetSliceHeaderLTRs(task, m_prevTask, DPB, sps, LTR, s);
4735         }
4736 
4737 
4738         if (pps.lists_modification_present_flag)
4739         {
4740             GetSliceHeaderRPLMod(task, DPB, STR, nSTR, LTR, nLTR, s);
4741         }
4742     }
4743 
4744     s.temporal_mvp_enabled_flag = !!sps.temporal_mvp_enabled_flag;
4745 
4746     if (sps.sample_adaptive_offset_enabled_flag)
4747     {
4748         const mfxExtHEVCParam* rtHEVCParam = ExtBuffer::Get(task.ctrl);
4749         const mfxExtHEVCParam& HEVCParam   = ExtBuffer::Get(par);
4750         mfxU16 FrameSAO = (rtHEVCParam && rtHEVCParam->SampleAdaptiveOffset)
4751             ? rtHEVCParam->SampleAdaptiveOffset
4752             : HEVCParam.SampleAdaptiveOffset;
4753 
4754         s.sao_luma_flag   = !!(FrameSAO & MFX_SAO_ENABLE_LUMA);
4755         s.sao_chroma_flag = !!(FrameSAO & MFX_SAO_ENABLE_CHROMA);
4756     }
4757 
4758     if (!isI)
4759     {
4760         s.num_ref_idx_active_override_flag =
4761            (   pps.num_ref_idx_l0_default_active_minus1 + 1 != task.NumRefActive[0]
4762             || (isB && pps.num_ref_idx_l1_default_active_minus1 + 1 != task.NumRefActive[1]));
4763 
4764         s.num_ref_idx_l0_active_minus1  = task.NumRefActive[0] - 1;
4765         s.num_ref_idx_l1_active_minus1  = isB * (task.NumRefActive[1] - 1);
4766         s.mvd_l1_zero_flag              &= !isB;
4767         s.cabac_init_flag               = 0;
4768         s.collocated_from_l0_flag       = !!s.temporal_mvp_enabled_flag;
4769         s.five_minus_max_num_merge_cand = 0;
4770     }
4771 
4772     bool bSetQPd =
4773         par.mfx.RateControlMethod == MFX_RATECONTROL_CQP
4774         || par.mfx.RateControlMethod == MFX_RATECONTROL_LA_EXT;
4775     s.slice_qp_delta     = mfxI8((task.QpY - (pps.init_qp_minus26 + 26)) * bSetQPd);
4776     s.slice_cb_qp_offset = 0;
4777     s.slice_cr_qp_offset = 0;
4778 
4779     const mfxExtCodingOption2& CO2  = ExtBuffer::Get(par);
4780     const mfxExtCodingOption2* pCO2 = ExtBuffer::Get(task.ctrl);
4781 
4782     SetDefault(pCO2, &CO2);
4783 
4784     s.deblocking_filter_disabled_flag = !!pCO2->DisableDeblockingIdc;
4785     s.deblocking_filter_override_flag = (s.deblocking_filter_disabled_flag != pps.deblocking_filter_disabled_flag);
4786     s.beta_offset_div2                = pps.beta_offset_div2;
4787     s.tc_offset_div2                  = pps.tc_offset_div2;
4788 #if MFX_VERSION >= MFX_VERSION_NEXT
4789     const mfxExtCodingOption3&   CO3 = ExtBuffer::Get(par);
4790     const mfxExtCodingOption3  *pCO3 = ExtBuffer::Get(task.ctrl);
4791 
4792     SetDefault(pCO3, &CO3);
4793 
4794     s.beta_offset_div2 = mfxI8(mfx::clamp(mfxI32(pCO3->DeblockingBetaOffset),    -12, 12) * 0.5 * !s.deblocking_filter_disabled_flag);
4795     s.tc_offset_div2   = mfxI8(mfx::clamp(mfxI32(pCO3->DeblockingAlphaTcOffset), -12, 12) * 0.5 * !s.deblocking_filter_disabled_flag);
4796 
4797     s.deblocking_filter_override_flag |=
4798         !s.deblocking_filter_disabled_flag
4799         && (s.beta_offset_div2 != pps.beta_offset_div2
4800             || s.tc_offset_div2 != pps.tc_offset_div2);
4801 #endif
4802 
4803     s.loop_filter_across_slices_enabled_flag = pps.loop_filter_across_slices_enabled_flag;
4804     s.num_entry_point_offsets *= !(pps.tiles_enabled_flag || pps.entropy_coding_sync_enabled_flag);
4805 
4806     return MFX_ERR_NONE;
4807 }
4808 
4809 
4810 #endif
4811