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