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 (<R)[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 - <PocLsb]
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