1 // Copyright (c) 2019-2021 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_interlace.h"
25 #include "hevcehw_base_packer.h"
26 #include "hevcehw_base_legacy.h"
27 #include <numeric>
28 
29 using namespace HEVCEHW;
30 using namespace HEVCEHW::Base;
31 
Query1NoCaps(const FeatureBlocks &,TPushQ1 Push)32 void Interlace::Query1NoCaps(const FeatureBlocks& , TPushQ1 Push)
33 {
34     Push(BLK_SetDefaultsCallChain,
35         [this](const mfxVideoParam&, mfxVideoParam&, StorageRW& strg) -> mfxStatus
36     {
37         auto& defaults = Glob::Defaults::GetOrConstruct(strg);
38         auto& bSet = defaults.SetForFeature[GetID()];
39         MFX_CHECK(!bSet, MFX_ERR_NONE);
40 
41         defaults.GetMinRefForBPyramid.Push(
42             [](Defaults::TChain<mfxU16>::TExt prev
43                 , const Defaults::Param& par)
44         {
45             bool bField = IsField(par.mvp.mfx.FrameInfo.PicStruct);
46             return mfxU16(prev(par) * (1 + bField) + bField);
47         });
48 
49         defaults.GetMinRefForBNoPyramid.Push(
50             [](Defaults::TChain<mfxU16>::TExt prev
51                 , const Defaults::Param& par)
52         {
53             bool bField = IsField(par.mvp.mfx.FrameInfo.PicStruct);
54             return mfxU16(prev(par) * (1 + bField));
55         });
56 
57         defaults.GetNumReorderFrames.Push(
58             [](Defaults::TChain<mfxU8>::TExt prev
59                 , const Defaults::Param& par)
60         {
61             bool bField = IsField(par.mvp.mfx.FrameInfo.PicStruct);
62             return mfxU8(prev(par) * (1 + bField));
63         });
64 
65         defaults.GetNonStdReordering.Push(
66             [](Defaults::TChain<bool>::TExt prev
67                 , const Defaults::Param& par)
68         {
69             return
70                 (IsField(par.mvp.mfx.FrameInfo.PicStruct)
71                     && par.mvp.mfx.EncodedOrder
72                     && par.mvp.mfx.NumRefFrame
73                     && par.mvp.mfx.GopRefDist > 1
74                     && par.base.GetMinRefForBNoPyramid(par) > par.mvp.mfx.NumRefFrame)
75                 || prev(par);
76         });
77 
78         defaults.GetNumRefPPyramid.Push(
79             [](Defaults::TChain<mfxU16>::TExt prev
80                 , const Defaults::Param& par)
81         {
82             mfxU16 k = 1 + IsField(par.mvp.mfx.FrameInfo.PicStruct);
83             return mfxU16(prev(par) * k);
84         });
85 
86         defaults.GetNumRefNoPyramid.Push(
87             [](Defaults::TChain<mfxU16>::TExt prev
88                 , const Defaults::Param& par)
89         {
90             return mfxU16(prev(par) * (1 + IsField(par.mvp.mfx.FrameInfo.PicStruct)));
91         });
92 
93         defaults.GetFrameType.Push(
94             [](Defaults::TGetFrameType::TExt prev
95                 , const Defaults::Param& par
96                 , mfxU32 fo
97                 , mfxU32 lastIDR)
98         {
99             bool   bField       = IsField(par.mvp.mfx.FrameInfo.PicStruct);
100             mfxU32 dFO          = bField * (lastIDR % 2);
101             mfxU32 nPicInFrame  = bField + 1;
102 
103             auto   ft = prev(par, (fo + dFO - lastIDR) / nPicInFrame,  0);
104 
105             bool   b2ndField    = bField && ((fo + dFO - lastIDR) % 2);
106             bool   bForceP      = b2ndField && IsI(ft);
107 
108             ft &= ~((MFX_FRAMETYPE_I | MFX_FRAMETYPE_IDR) * bForceP);
109             ft |= MFX_FRAMETYPE_P * bForceP;
110 
111             bool bForceRef = bField && !b2ndField && !IsB(ft);
112             ft |= MFX_FRAMETYPE_REF * bForceRef;
113             return ft;
114         });
115 
116         defaults.GetPicTimingSEI.Push(
117             [](Defaults::TChain<mfxU16>::TExt prev
118             , const Defaults::Param& par)
119         {
120             return Bool2CO(IsField(par.mvp.mfx.FrameInfo.PicStruct) || IsOn(prev(par)));
121         });
122 
123         defaults.GetPLayer.Push(
124             [](Defaults::TGetPLayer::TExt prev
125                 , const Defaults::Param& par
126                 , mfxU32 fo)
127         {
128             return prev(par, fo / (1 + IsField(par.mvp.mfx.FrameInfo.PicStruct)));
129         });
130 
131         defaults.GetTId.Push(
132             [](Defaults::TGetTId::TExt prev
133                 , const Defaults::Param& par
134                 , mfxU32 fo)
135         {
136             return prev(par, fo / (1 + IsField(par.mvp.mfx.FrameInfo.PicStruct)));
137         });
138 
139         defaults.GetRPL.Push( [](
140             Defaults::TGetRPL::TExt prev
141             , const Defaults::Param& par
142             , const DpbArray &DPB
143             , mfxU16 maxL0
144             , mfxU16 maxL1
145             , const FrameBaseInfo& cur
146             , mfxU8(&RPL)[2][MAX_DPB_SIZE]) -> std::tuple<mfxU8, mfxU8>
147         {
148             if (!IsField(par.mvp.mfx.FrameInfo.PicStruct))
149                 return prev(par, DPB, maxL0, maxL1, cur, RPL);
150 
151             auto nRefLX = prev(par, DPB, MAX_DPB_SIZE, MAX_DPB_SIZE, cur, RPL);
152             auto& l0    = std::get<0>(nRefLX);
153             auto& l1    = std::get<1>(nRefLX);
154 
155             bool bValid = l0 <= maxL0 && l1 <= maxL1;
156             if (!bValid)
157             {
158                 std::list<mfxU8> L0(RPL[0], RPL[0] + l0);
159                 std::list<mfxU8> L1(RPL[1], RPL[1] + l1);
160                 auto CmpRef = [&](mfxU8 a, mfxU8 b)
161                 {
162                     auto FN = [](const FrameBaseInfo& x) { return (x.POC + !x.b2ndField) / 2; };
163                     auto aDist = abs(FN(DPB[a]) - FN(cur)) * 2 + (DPB[a].bBottomField != cur.bBottomField);
164                     auto bDist = abs(FN(DPB[b]) - FN(cur)) * 2 + (DPB[b].bBottomField != cur.bBottomField);
165                     return aDist <= bDist;
166                 };
167                 auto IsNotInL0 = [&](mfxU8 x) { return std::find(L0.begin(), L0.end(), x) == L0.end(); };
168                 auto IsNotInL1 = [&](mfxU8 x) { return std::find(L1.begin(), L1.end(), x) == L1.end(); };
169 
170                 L0.sort(CmpRef);
171                 L1.sort(CmpRef);
172 
173                 L0.resize(std::min<mfxU16>(maxL0, l0));
174                 L1.resize(std::min<mfxU16>(maxL1, l1));
175 
176                 std::remove_if(RPL[0], RPL[0] + l0, IsNotInL0);
177                 std::remove_if(RPL[1], RPL[1] + l1, IsNotInL1);
178 
179                 l0 = mfxU8(L0.size());
180                 l1 = mfxU8(L1.size());
181 
182                 std::fill(std::next(RPL[0], l0), std::end(RPL[0]), IDX_INVALID);
183                 std::fill(std::next(RPL[1], l1), std::end(RPL[1]), IDX_INVALID);
184             }
185 
186             return nRefLX;
187         });
188 
189         defaults.GetPreReorderInfo.Push([](
190             Defaults::TGetPreReorderInfo::TExt  prev
191             , const Defaults::Param&            par
192             , FrameBaseInfo&                    fi
193             , const mfxFrameSurface1*           pSurfIn
194             , const mfxEncodeCtrl*              pCtrl
195             , mfxU32                            prevIDROrder
196             , mfxI32                            prevIPOC
197             , mfxU32                            frameOrder)
198         {
199             auto sts = prev(par, fi, pSurfIn, pCtrl, prevIDROrder, prevIPOC, frameOrder);
200             MFX_CHECK_STS(sts);
201 
202             MFX_CHECK(IsField(par.mvp.mfx.FrameInfo.PicStruct), MFX_ERR_NONE);
203 
204             bool bInfoValid = pSurfIn && !!(pSurfIn->Info.PicStruct & (MFX_PICSTRUCT_FIELD_TFF | MFX_PICSTRUCT_FIELD_BFF));
205             fi.b2ndField = !!(frameOrder & 1);
206             fi.bBottomField =
207                 (bInfoValid && IsBFF(pSurfIn->Info.PicStruct))
208                 || (!bInfoValid && (IsBFF(par.mvp.mfx.FrameInfo.PicStruct) != fi.b2ndField));
209 
210             return MFX_ERR_NONE;
211         });
212 
213         // min 2 active L0 refs for 2nd field
214         defaults.GetFrameNumRefActive.Push([](
215             Defaults::TGetFrameNumRefActive::TExt prev
216             , const Defaults::Param& par
217             , const FrameBaseInfo& fi)
218         {
219             auto  nRef      = prev(par, fi);
220             auto& nL0       = std::get<0>(nRef);
221             bool  bSetMinL0 = nL0 && fi.b2ndField && nL0 < 2;
222 
223             SetIf(nL0, bSetMinL0, mfxU8(2));
224 
225             return nRef;
226         });
227 
228         defaults.GetSHNUT.Push([](
229             Defaults::TGetSHNUT::TExt prev
230             , const Defaults::Param& par
231             , const TaskCommonPar& task
232             , bool bRAPIntra)
233         {
234             return prev(par, task, bRAPIntra && !IsField(par.mvp.mfx.FrameInfo.PicStruct));
235         });
236 
237         defaults.GetVPS.Push([](
238             Defaults::TGetVPS::TExt prev
239             , const Defaults::Param& par
240             , VPS& vps)
241         {
242             auto sts = prev(par, vps);
243 
244             vps.general.progressive_source_flag    = !!(par.mvp.mfx.FrameInfo.PicStruct & MFX_PICSTRUCT_PROGRESSIVE);
245             vps.general.interlaced_source_flag     = !(par.mvp.mfx.FrameInfo.PicStruct & MFX_PICSTRUCT_PROGRESSIVE);
246             vps.general.frame_only_constraint_flag = !IsField(par.mvp.mfx.FrameInfo.PicStruct);
247 
248             return sts;
249         });
250 
251         defaults.GetSPS.Push([](
252             Defaults::TGetSPS::TExt prev
253             , const Defaults::Param& par
254             , const VPS& vps
255             , SPS& sps)
256         {
257             auto  sts = prev(par, vps, sps);
258             auto& mfx = par.mvp.mfx;
259 
260             MFX_CHECK(IsField(mfx.FrameInfo.PicStruct) && sts >= MFX_ERR_NONE, sts);
261 
262             sps.log2_max_pic_order_cnt_lsb_minus4 =
263                 mfx::clamp<mfxU32>(
264                     CeilLog2(mfx.GopRefDist * 2 + sps.sub_layer[sps.max_sub_layers_minus1].max_dec_pic_buffering_minus1) - 1
265                     , sps.log2_max_pic_order_cnt_lsb_minus4
266                     , 12u);
267             sps.vui.frame_field_info_present_flag = 1;
268             sps.vui.field_seq_flag                = 1;
269 
270             return sts;
271         });
272 
273         defaults.GetWeakRef.Push([](
274             Defaults::TGetWeakRef::TExt prev
275             , const Defaults::Param& par
276             , const FrameBaseInfo  &cur
277             , const DpbFrame       *begin
278             , const DpbFrame       *end)
279         {
280             if (!IsField(par.mvp.mfx.FrameInfo.PicStruct))
281             {
282                 return prev(par, cur, begin, end);
283             }
284 
285             const mfxExtCodingOption3& CO3 = ExtBuffer::Get(par.mvp);
286             auto POCLess = [](const DpbFrame& l, const DpbFrame& r) { return l.POC < r.POC; };
287 
288             if (CO3.PRefType == MFX_P_REF_PYRAMID)
289             {
290                 auto PyrInt = par.base.GetPPyrInterval(par);
291                 auto FN     = [](const FrameBaseInfo& x) { return (x.POC + !x.b2ndField) / 2; };
292                 auto IsWeak = [&](const FrameBaseInfo& x) { return (FN(x) - FN(*begin)) % PyrInt != 0; };
293 
294                 if (FN(begin[1]) == FN(begin[0]))
295                 {
296                     return std::find_if(begin, end, IsWeak);
297                 }
298 
299                 return begin;
300             }
301 
302             return std::min_element(begin, end, POCLess);
303         });
304 
305         bSet = true;
306 
307         return MFX_ERR_NONE;
308     });
309 }
310 
Query1WithCaps(const FeatureBlocks &,TPushQ1 Push)311 void Interlace::Query1WithCaps(const FeatureBlocks&, TPushQ1 Push)
312 {
313     Push(BLK_CheckPicStruct,
314         [](const mfxVideoParam&, mfxVideoParam& par, StorageRW&) -> mfxStatus
315     {
316         mfxExtCodingOption2* pCO2 = ExtBuffer::Get(par);
317         bool bInterlaceAllowed =
318             par.mfx.RateControlMethod == MFX_RATECONTROL_CQP
319             || (   pCO2
320                 && IsOn(pCO2->ExtBRC)
321                 && (   par.mfx.RateControlMethod == MFX_RATECONTROL_CBR
322                     || par.mfx.RateControlMethod == MFX_RATECONTROL_VBR));
323 
324         bool bChanged = CheckOrZero<mfxU16>(
325             par.mfx.FrameInfo.PicStruct
326             , mfxU16(MFX_PICSTRUCT_UNKNOWN)
327             , mfxU16(MFX_PICSTRUCT_PROGRESSIVE)
328             , mfxU16(bInterlaceAllowed * MFX_PICSTRUCT_FIELD_TOP)
329             , mfxU16(bInterlaceAllowed * MFX_PICSTRUCT_FIELD_BOTTOM)
330             , mfxU16(bInterlaceAllowed * MFX_PICSTRUCT_FIELD_SINGLE)
331             , mfxU16(bInterlaceAllowed * MFX_PICSTRUCT_FIELD_TFF)
332             , mfxU16(bInterlaceAllowed * MFX_PICSTRUCT_FIELD_BFF));
333 
334         MFX_CHECK(!bChanged, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
335         return MFX_ERR_NONE;
336     });
337 }
338 
QueryIOSurf(const FeatureBlocks &,TPushQIS Push)339 void Interlace::QueryIOSurf(const FeatureBlocks&, TPushQIS Push)
340 {
341     Push(BLK_QueryIOSurf
342         , [](const mfxVideoParam&, mfxFrameAllocRequest& req, StorageRW& strg) -> mfxStatus
343     {
344         auto& par  = Glob::VideoParam::Get(strg);
345         mfxU16 nExtraRaw = IsField(par.mfx.FrameInfo.PicStruct) * (par.mfx.GopRefDist - 1);
346 
347         req.NumFrameMin += nExtraRaw;
348         req.NumFrameSuggested += nExtraRaw;
349 
350         return MFX_ERR_NONE;
351     });
352 }
353 
354 using TTaskItWrap = TaskItWrap<FrameBaseInfo, Task::Common::Key>;
355 
IsL1Ready(DpbArray const & dpb,mfxI32 poc,TTaskItWrap begin,TTaskItWrap end,bool flush)356 static bool IsL1Ready(
357     DpbArray const & dpb,
358     mfxI32 poc,
359     TTaskItWrap begin,
360     TTaskItWrap end,
361     bool flush)
362 {
363     std::list<const DpbFrame*> bwd(Size(dpb), nullptr);
364     std::iota(bwd.begin(), bwd.end(), std::begin(dpb));
365 
366     bwd.remove_if([&](const DpbFrame* p) { return !isValid(*p) || p->POC < poc; });
367 
368     if (bwd.size() != 1)
369         return !bwd.empty();
370 
371     auto top = std::find_if_not(begin, end
372         , [&](const FrameBaseInfo& f) { return f.POC <= bwd.back()->POC; });
373 
374     bool bRes = (top != end && IsB(top->FrameType))
375         || (top == end && flush);
376 
377     return bRes;
378 }
379 
380 template <class T>
IntBPyrReorder(T begin,T end)381 static T IntBPyrReorder(T begin, T end)
382 {
383     typedef typename std::iterator_traits<T>::reference TRef;
384 
385     mfxU32 num = mfxU32(std::distance(begin, end));
386     bool bSetOrder = num && (*begin)->BPyramidOrder == mfxU32(MFX_FRAMEORDER_UNKNOWN);
387 
388     if (bSetOrder)
389     {
390         mfxU32 i = 0;
391         std::for_each(begin, end, [&](TRef bref)
392         {
393             bool bRef = false;
394             bref->BPyramidOrder = Legacy::GetBiFrameLocation(i++ / 2, num / 2, bRef, bref->PyramidLevel);
395             bref->PyramidLevel *= 2;
396             bref->FrameType |= mfxU16(MFX_FRAMETYPE_REF * (bRef || !bref->b2ndField));
397         });
398     }
399 
400     return std::min_element(begin, end
401         , [](TRef a, TRef b) { return a->BPyramidOrder < b->BPyramidOrder; });
402 }
403 
IntReorder(mfxVideoParam const & par,DpbArray const & dpb,TTaskItWrap begin,TTaskItWrap end,bool flush)404 static TTaskItWrap IntReorder(
405     mfxVideoParam const & par,
406     DpbArray const & dpb,
407     TTaskItWrap begin,
408     TTaskItWrap end,
409     bool flush)
410 {
411     const mfxExtCodingOption2& CO2 = ExtBuffer::Get(par);
412     bool bBPyramid = (CO2.BRefType == MFX_B_REF_PYRAMID);
413     auto top = begin;
414     std::list<TTaskItWrap> brefs;
415 
416     auto IsB      = [] (FrameBaseInfo& f){ return !!(f.FrameType & MFX_FRAMETYPE_B); };
417     auto NoL1     = [&](TTaskItWrap f)   { return !IsL1Ready(dpb, f->POC, begin, end, flush); };
418     auto NextBRef = [&]()                { return *IntBPyrReorder(brefs.begin(), brefs.end()); };
419 
420     std::generate_n(
421         std::back_inserter(brefs)
422         , std::distance(begin, std::find_if_not(begin, end, IsB))
423         , [&]() { return top++; });
424 
425     brefs.remove_if(NoL1);
426 
427     bool bNoPyramidB = !bBPyramid && !brefs.empty();
428 
429     if (bNoPyramidB)
430     {
431         auto            topB        = brefs.begin();
432         FrameBaseInfo*  pPrevB      = nullptr;
433         auto            IsNextBRef  = [&](TTaskItWrap& f)
434         {
435             bool bRes = IsRef(f->FrameType) && (!pPrevB || ((f->POC - pPrevB->POC) < 3));
436             pPrevB = &*f;
437             return bRes;
438         };
439         auto ref = std::find_if(brefs.begin(), brefs.end(), IsNextBRef);
440 
441         SetIf(topB, ref != brefs.end(), ref);
442 
443         return *topB;
444     }
445 
446     SetIf(top, !brefs.empty(), NextBRef);
447 
448     bool bForcePRef = flush && top == end && begin != end;
449     while (bForcePRef)
450     {
451         --top;
452         top->FrameType = mfxU16(MFX_FRAMETYPE_P | MFX_FRAMETYPE_REF);
453         bForcePRef = top != begin && top->b2ndField;
454     }
455 
456     return top;
457 }
458 
InitInternal(const FeatureBlocks &,TPushII Push)459 void Interlace::InitInternal(const FeatureBlocks&, TPushII Push)
460 {
461     Push(BLK_SetReorder
462         , [](StorageRW& strg, StorageRW&) -> mfxStatus
463     {
464         auto& par = Glob::VideoParam::Get(strg);
465         MFX_CHECK(IsField(par.mfx.FrameInfo.PicStruct), MFX_ERR_NONE);
466 
467         auto& rdr = Glob::Reorder::Get(strg);
468         rdr.BufferSize += par.mfx.GopRefDist - 1;
469         rdr.MaxReorder += par.mfx.GopRefDist;
470         rdr.Push([&](Reorderer::TExt, const DpbArray& DPB, TTaskIt begin, TTaskIt end, bool bFlush)
471         {
472             return IntReorder(par, DPB, begin, end, bFlush).it;
473         });
474 
475         return MFX_ERR_NONE;
476     });
477 
478     Push(BLK_PatchRawInfo
479         , [](StorageRW& strg, StorageRW& local) -> mfxStatus
480     {
481         auto& par = Glob::VideoParam::Get(strg);
482         MFX_CHECK(IsField(par.mfx.FrameInfo.PicStruct), MFX_ERR_NONE);
483 
484         Tmp::RawInfo::Get(local).NumFrameMin += par.mfx.GopRefDist - 1;
485 
486         return MFX_ERR_NONE;
487     });
488 }
489 
SubmitTask(const FeatureBlocks &,TPushST Push)490 void Interlace::SubmitTask(const FeatureBlocks& , TPushST Push)
491 {
492     Push(BLK_InsertPTSEI
493         , [this](StorageW& global, StorageW& s_task) -> mfxStatus
494     {
495         auto& par = Glob::VideoParam::Get(global);
496         auto PS = par.mfx.FrameInfo.PicStruct;
497         MFX_CHECK(IsField(PS), MFX_ERR_NONE);
498 
499         auto& task = Task::Common::Get(s_task);
500         MFX_CHECK(task.InsertHeaders & INSERT_PTSEI, MFX_ERR_NONE);
501 
502         auto usrPlEnd = task.ctrl.Payload + task.ctrl.NumPayload;
503         bool bUserPTSEI = usrPlEnd != std::find_if(task.ctrl.Payload, usrPlEnd
504             , [](const mfxPayload* pPl) { return pPl && pPl->Type == 1; });
505         MFX_CHECK(!bUserPTSEI, MFX_ERR_NONE);
506 
507         auto& sps = Glob::SPS::Get(global);
508         static const std::map<mfxU16, mfxU8> PicStructMFX2STD =
509         {
510               {mfxU16(MFX_PICSTRUCT_FIELD_TOP), mfxU8(1)}
511             , {mfxU16(MFX_PICSTRUCT_FIELD_BOTTOM), mfxU8(2)}
512             , {mfxU16(MFX_PICSTRUCT_FIELD_TOP | MFX_PICSTRUCT_FIELD_PAIRED_PREV), mfxU8(9)}
513             , {mfxU16(MFX_PICSTRUCT_FIELD_TOP | MFX_PICSTRUCT_FIELD_PAIRED_NEXT), mfxU8(11)}
514             , {mfxU16(MFX_PICSTRUCT_FIELD_BOTTOM | MFX_PICSTRUCT_FIELD_PAIRED_PREV), mfxU8(10)}
515             , {mfxU16(MFX_PICSTRUCT_FIELD_BOTTOM | MFX_PICSTRUCT_FIELD_PAIRED_NEXT), mfxU8(12)}
516         };
517         PicTimingSEI pt = {};
518         pt.pic_struct = 1 + task.bBottomField;
519 
520         if (PicStructMFX2STD.count(task.pSurfIn->Info.PicStruct))
521             pt.pic_struct = PicStructMFX2STD.at(task.pSurfIn->Info.PicStruct);
522 
523         pt.source_scan_type = 0;
524         pt.duplicate_flag = 0;
525 
526         pt.au_cpb_removal_delay_minus1 = std::max<mfxU32>(task.cpb_removal_delay, 1) - 1;
527         pt.pic_dpb_output_delay =
528             task.DisplayOrder
529             + sps.sub_layer[sps.max_sub_layers_minus1].max_num_reorder_pics
530             - task.EncodedOrder;
531 
532         BitstreamWriter bs(m_buf.data(), (mfxU32)m_buf.size(), 0);
533         mfxPayload pl = {};
534         pl.Type = 1;
535         pl.Data = bs.GetStart();
536 
537         bs.PutBits(8, 1);    //payload type
538         bs.PutBits(8, 0xff); //place for payload size
539 
540         Packer::PackSEIPayload(bs, sps.vui, pt);
541 
542         pl.NumBit  = bs.GetOffset();
543         pl.BufSize = mfxU16(CeilDiv(pl.NumBit, 8u));
544 
545         assert(pl.BufSize < 256);
546         pl.Data[1] = (mfxU8)pl.BufSize - 2; //payload size
547 
548         task.PLInternal.push_back(pl);
549 
550         return MFX_ERR_NONE;
551     });
552 
553     Push(BLK_SkipFrame
554         , [this](StorageW& global, StorageW& s_task) -> mfxStatus
555     {
556         auto& par = Glob::VideoParam::Get(global);
557         auto& task = Task::Common::Get(s_task);
558         auto& allocRec = Glob::AllocRec::Get(global);
559 
560         //skip second field when the first one is skipped
561         bool b2ndFieldSkip =
562             !task.bSkip
563             && task.b2ndField
564             && Legacy::IsSWBRC(par, ExtBuffer::Get(par))
565             && !!(allocRec.GetFlag(task.DPB.Active[task.RefPicList[0][0]].Rec.Idx) & REC_SKIPPED);
566 
567         task.bSkip |= b2ndFieldSkip;
568         m_b2ndFieldRecode = b2ndFieldSkip && !(!!(allocRec.GetFlag(task.DPB.Active[task.RefPicList[0][0]].Rec.Idx) & REC_READY));
569 
570         return MFX_ERR_NONE;
571     });
572 }
573 
QueryTask(const FeatureBlocks &,TPushQT Push)574 void Interlace::QueryTask(const FeatureBlocks&, TPushQT Push)
575 {
576     Push(BLK_QueryTask
577         , [this](StorageW& /*global*/, StorageW& s_task) -> mfxStatus
578     {
579         MFX_CHECK(m_b2ndFieldRecode, MFX_ERR_NONE);
580 
581         m_b2ndFieldRecode = false;
582         auto& task = Task::Common::Get(s_task);
583         task.bRecode = true;
584 
585         return MFX_ERR_NONE;
586     });
587 }
588 
589 
590 #endif //defined(MFX_ENABLE_H265_VIDEO_ENCODE)
591