1 /******************************************************************************\
2 Copyright (c) 2017-2019, Intel Corporation
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6 
7 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8 
9 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
10 
11 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
12 
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14 
15 This sample was distributed or derived from the Intel's Media Samples package.
16 The original version of this sample may be obtained from https://software.intel.com/en-us/intel-media-server-studio
17 or https://software.intel.com/en-us/media-client-solutions-support.
18 \**********************************************************************************/
19 
20 #include "pipeline_hevc_fei.h"
21 #include <version.h>
22 
CEncodingPipeline(sInputParams & userInput)23 CEncodingPipeline::CEncodingPipeline(sInputParams& userInput)
24     : m_inParams(userInput)
25     , m_impl(MFX_IMPL_HARDWARE_ANY | MFX_IMPL_VIA_VAAPI)
26     , m_EncSurfPool()
27 {
28 }
29 
~CEncodingPipeline()30 CEncodingPipeline::~CEncodingPipeline()
31 {
32 }
33 
Init()34 mfxStatus CEncodingPipeline::Init()
35 {
36     mfxStatus sts = MFX_ERR_NONE;
37 
38     try
39     {
40         sts = m_mfxSession.Init(m_impl, NULL);
41         MSDK_CHECK_STATUS(sts, "m_mfxSession.Init failed");
42 
43         // create and init frame allocator
44         sts = CreateAllocator();
45         MSDK_CHECK_STATUS(sts, "CreateAllocator failed");
46 
47         m_EncSurfPool.SetAllocator(m_pMFXAllocator.get());
48 
49         {
50             mfxHDL hdl = NULL;
51             sts = m_pHWdev->GetHandle(MFX_HANDLE_VA_DISPLAY, &hdl);
52             MSDK_CHECK_STATUS(sts, "m_pHWdev->GetHandle failed");
53             m_pParamChecker.reset(new HEVCEncodeParamsChecker(m_impl, hdl));
54         }
55 
56         mfxFrameInfo frameInfo;
57 
58         m_pYUVSource.reset(CreateYUVSource());
59         MSDK_CHECK_POINTER(m_pYUVSource.get(), MFX_ERR_UNSUPPORTED);
60 
61         {
62             sts = m_pYUVSource->PreInit();
63             MSDK_CHECK_STATUS(sts, "m_pYUVSource PreInit failed");
64 
65             sts = m_pYUVSource->GetActualFrameInfo(frameInfo);
66             MSDK_CHECK_STATUS(sts, "m_pYUVSource GetActualFrameInfo failed");
67         }
68 
69         if (0 != msdk_strlen(m_inParams.refctrlInFile)) // it is to disable RAPintra
70         {
71             frameInfo.PicStruct &= ~MFX_PICSTRUCT_PROGRESSIVE;
72             frameInfo.PicStruct |= MFX_PICSTRUCT_FIELD_SINGLE;
73         }
74 
75         m_pFEI_PreENC.reset(CreatePreENC(frameInfo));
76         if (m_pFEI_PreENC.get())
77         {
78             sts = m_pFEI_PreENC->PreInit();
79             MSDK_CHECK_STATUS(sts, "FEI PreENC PreInit failed");
80         }
81 
82         if (m_inParams.bEncodedOrder)
83         {
84             MfxVideoParamsWrapper param = GetEncodeParams(m_inParams, frameInfo, PIPELINE_COMPONENT::ENCODE);
85 
86             sts = m_pParamChecker->Query(param);
87             MSDK_CHECK_STATUS(sts, "m_pParamChecker->Query failed");
88 
89             if (0 != msdk_strlen(m_inParams.refctrlInFile)) {
90                 m_pOrderCtrl.reset(new EncodeOrderExtControl(param, !!(m_pFEI_PreENC.get()), m_inParams.refctrlInFile));
91                 MSDK_CHECK_STATUS(dynamic_cast<EncodeOrderExtControl*>(m_pOrderCtrl.get())->State(), "RefList ctrl file open failed");
92             } else
93                 m_pOrderCtrl.reset(new EncodeOrderControl(param, !!(m_pFEI_PreENC.get())));
94         }
95 
96         m_pFEI_Encode.reset(CreateEncode(frameInfo));
97         if (m_pFEI_Encode.get())
98         {
99             sts = m_pFEI_Encode->PreInit();
100             MSDK_CHECK_STATUS(sts, "FEI ENCODE PreInit failed");
101         }
102 
103         sts = AllocFrames();
104         MSDK_CHECK_STATUS(sts, "AllocFrames failed");
105 
106         sts = InitComponents();
107         MSDK_CHECK_STATUS(sts, "InitComponents failed");
108     }
109     catch (mfxError& ex)
110     {
111         MSDK_CHECK_STATUS(ex.GetStatus(), ex.what());
112     }
113     catch(std::exception& ex)
114     {
115         MSDK_CHECK_STATUS(MFX_ERR_UNDEFINED_BEHAVIOR, ex.what());
116     }
117     catch(...)
118     {
119         MSDK_CHECK_STATUS(MFX_ERR_UNDEFINED_BEHAVIOR, "Undefined exception in Pipeline::Init");
120     }
121 
122     return sts;
123 }
124 
PrintInfo()125 void CEncodingPipeline::PrintInfo()
126 {
127     msdk_printf(MSDK_STRING("\nIntel(R) Media SDK HEVC FEI Encoding Sample Version %s\n"), GetMSDKSampleVersion().c_str());
128 
129     const msdk_char* sPipeline = m_inParams.bPREENC && m_inParams.bENCODE ? MSDK_STRING("PreENC + Encode") : (m_inParams.bPREENC ? MSDK_STRING("PreENC") : MSDK_STRING("Encode"));
130     msdk_printf(MSDK_STRING("\nPipeline         :\t%s"), sPipeline);
131 
132     mfxFrameInfo sourceFrameInfo;
133     m_pYUVSource->GetActualFrameInfo(sourceFrameInfo);
134 
135     msdk_printf(MSDK_STRING("\nResolution       :\t%dx%d"), sourceFrameInfo.Width, sourceFrameInfo.Height);
136     msdk_printf(MSDK_STRING("\nFrame rate       :\t%d/%d = %.2f"), sourceFrameInfo.FrameRateExtN, sourceFrameInfo.FrameRateExtD, CalculateFrameRate(sourceFrameInfo.FrameRateExtN, sourceFrameInfo.FrameRateExtD));
137 
138     MfxVideoParamsWrapper param;
139     if (m_pFEI_Encode.get())
140         param = m_pFEI_Encode->GetVideoParam();
141     else if (m_pFEI_PreENC.get())
142         param = m_pFEI_PreENC->GetVideoParam();
143 
144     msdk_printf(MSDK_STRING("\nProcessing order :\t%s"), param.mfx.EncodedOrder ? MSDK_STRING("Encoded") : MSDK_STRING("Display"));
145     msdk_printf(MSDK_STRING("\nGop Size         :\t%d"), param.mfx.GopPicSize);
146 
147     mfxU16 gopOptFlag = param.mfx.GopOptFlag;
148     const msdk_char* GopClosed = (gopOptFlag & MFX_GOP_CLOSED) == 0 ? MSDK_STRING("Open") : MSDK_STRING("Closed");
149     const msdk_char* GopStrict = (gopOptFlag & MFX_GOP_STRICT) == 0 ? MSDK_STRING("Not Strict") : MSDK_STRING("Strict");
150     msdk_printf(MSDK_STRING("\nGopOptFlag       :\t%s, %s"), GopClosed, GopStrict);
151 
152     if (param.mfx.IdrInterval == 0xffff)
153         msdk_printf(MSDK_STRING("\nIDR Interval     :\tInfinite"));
154     else
155 	msdk_printf(MSDK_STRING("\nIDR Interval     :\t%d"), param.mfx.IdrInterval);
156 
157     msdk_printf(MSDK_STRING("\nGopRefDist       :\t%d"), param.mfx.GopRefDist);
158     msdk_printf(MSDK_STRING("\nNumRefFrame      :\t%d"), param.mfx.NumRefFrame);
159 
160     msdk_printf(MSDK_STRING("\nNumRefActiveP    :\t%d"), param.GetExtBuffer<mfxExtCodingOption3>()->NumRefActiveP[0]);
161     msdk_printf(MSDK_STRING("\nNumRefActiveBL0  :\t%d"), param.GetExtBuffer<mfxExtCodingOption3>()->NumRefActiveBL0[0]);
162     msdk_printf(MSDK_STRING("\nNumRefActiveBL1  :\t%d"), param.GetExtBuffer<mfxExtCodingOption3>()->NumRefActiveBL1[0]);
163 
164     mfxU16 bRefType = param.GetExtBuffer<mfxExtCodingOption2>()->BRefType;
165     msdk_printf(MSDK_STRING("\nB-pyramid        :\t%s"), bRefType ? (bRefType == MFX_B_REF_OFF ? MSDK_STRING("Off") : MSDK_STRING("On")) : MSDK_STRING("MSDK default"));
166 
167     static std::string PRefStrs[] = {"DEFAULT", "SIMPLE", "PYRAMID" };
168     mfxU16 pRefType = param.GetExtBuffer<mfxExtCodingOption3>()->PRefType;
169     msdk_printf(MSDK_STRING("\nP-pyramid        :\t%s"), PRefStrs[pRefType].c_str());
170 
171     mfxVersion ver;
172     m_mfxSession.QueryVersion(&ver);
173     msdk_printf(MSDK_STRING("\n\nMedia SDK version\t%d.%d"), ver.Major, ver.Minor);
174 
175     msdk_printf(MSDK_STRING("\n"));
176 }
177 
LoadFEIPlugin()178 mfxStatus CEncodingPipeline::LoadFEIPlugin()
179 {
180     mfxPluginUID pluginGuid = msdkGetPluginUID(m_impl, MSDK_VENCODE | MSDK_FEI, MFX_CODEC_HEVC); // remove '| MSDK_FEI' to use HW HEVC for debug
181     MSDK_CHECK_ERROR(AreGuidsEqual(pluginGuid, MSDK_PLUGINGUID_NULL), true, MFX_ERR_NOT_FOUND);
182 
183     m_pHEVCePlugin.reset(LoadPlugin(MFX_PLUGINTYPE_VIDEO_ENCODE, m_mfxSession, pluginGuid, 1));
184     MSDK_CHECK_POINTER(m_pHEVCePlugin.get(), MFX_ERR_UNSUPPORTED);
185 
186     return MFX_ERR_NONE;
187 }
188 
CreateAllocator()189 mfxStatus CEncodingPipeline::CreateAllocator()
190 {
191     mfxStatus sts = MFX_ERR_NONE;
192 
193     sts = CreateHWDevice();
194     MSDK_CHECK_STATUS(sts, "CreateHWDevice failed");
195 
196     mfxHDL hdl = NULL;
197     sts = m_pHWdev->GetHandle(MFX_HANDLE_VA_DISPLAY, &hdl);
198     MSDK_CHECK_STATUS(sts, "m_pHWdev->GetHandle failed");
199 
200     // provide device manager to MediaSDK
201     sts = m_mfxSession.SetHandle(MFX_HANDLE_VA_DISPLAY, hdl);
202     MSDK_CHECK_STATUS(sts, "m_mfxSession.SetHandle failed");
203 
204     /* Only video memory is supported now. So application must provide MediaSDK
205     with external allocator and call SetFrameAllocator */
206     // create VAAPI allocator
207     m_pMFXAllocator.reset(new vaapiFrameAllocator);
208 
209     std::unique_ptr<vaapiAllocatorParams> p_vaapiAllocParams(new vaapiAllocatorParams);
210 
211     p_vaapiAllocParams->m_dpy = (VADisplay)hdl;
212     m_pMFXAllocatorParams = std::move(p_vaapiAllocParams);
213 
214     // Call SetAllocator to pass external allocator to MediaSDK
215     sts = m_mfxSession.SetFrameAllocator(m_pMFXAllocator.get());
216     MSDK_CHECK_STATUS(sts, "m_mfxSession.SetFrameAllocator failed");
217 
218     // initialize memory allocator
219     sts = m_pMFXAllocator->Init(m_pMFXAllocatorParams.get());
220     MSDK_CHECK_STATUS(sts, "m_pMFXAllocator->Init failed");
221 
222     return sts;
223 }
224 
CreateHWDevice()225 mfxStatus CEncodingPipeline::CreateHWDevice()
226 {
227     mfxStatus sts = MFX_ERR_NONE;
228 
229     m_pHWdev.reset(CreateVAAPIDevice());
230     MSDK_CHECK_POINTER(m_pHWdev.get(), MFX_ERR_MEMORY_ALLOC);
231 
232     sts = m_pHWdev->Init(NULL, 0, MSDKAdapter::GetNumber(m_mfxSession));
233     MSDK_CHECK_STATUS(sts, "m_pHWdev->Init failed");
234 
235     return sts;
236 }
237 
238 
AllocFrames()239 mfxStatus CEncodingPipeline::AllocFrames()
240 {
241     mfxStatus sts = MFX_ERR_NOT_INITIALIZED;
242 
243     // Here we build a final alloc request from alloc requests from several components.
244     // TODO: This code is a good candidate to become a 'builder' utility class.
245     // While it's safe to use it, it needs to be optimized for reasonable resource allocation.
246     // TODO: Find a reasonable minimal number of required surfaces for YUVSource+Reorderer+PreENC+ENCODE pipeline_hevc_fei
247 
248     mfxFrameAllocRequest allocRequest;
249     MSDK_ZERO_MEMORY(allocRequest);
250 
251     {
252         mfxFrameAllocRequest request;
253         MSDK_ZERO_MEMORY(request);
254 
255         sts = m_pYUVSource->QueryIOSurf(&request);
256         MSDK_CHECK_STATUS(sts, "m_pYUVSource->QueryIOSurf failed");
257 
258         allocRequest = request;
259     }
260     if (m_pFEI_Encode.get())
261     {
262         mfxFrameAllocRequest encodeRequest;
263         MSDK_ZERO_MEMORY(encodeRequest);
264 
265         sts = m_pFEI_Encode->QueryIOSurf(&encodeRequest);
266         MSDK_CHECK_STATUS(sts, "m_pFEI_Encode->QueryIOSurf failed");
267 
268         allocRequest.Type |= encodeRequest.Type | MFX_MEMTYPE_EXTERNAL_FRAME | MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET;
269         allocRequest.NumFrameSuggested += encodeRequest.NumFrameSuggested;
270         allocRequest.NumFrameMin = allocRequest.NumFrameSuggested;
271     }
272     if (m_pFEI_PreENC.get())
273     {
274         mfxFrameAllocRequest preEncRequest;
275         MSDK_ZERO_MEMORY(preEncRequest);
276         sts = m_pFEI_PreENC->QueryIOSurf(&preEncRequest);
277         MSDK_CHECK_STATUS(sts, "m_pFEI_PreENC->QueryIOSurf failed");
278 
279         allocRequest.Type |= preEncRequest.Type | MFX_MEMTYPE_EXTERNAL_FRAME | MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET | MFX_MEMTYPE_FROM_ENC;
280         allocRequest.NumFrameSuggested += preEncRequest.NumFrameSuggested;
281         allocRequest.NumFrameMin = allocRequest.NumFrameSuggested;
282     }
283     if (m_pOrderCtrl.get())
284     {
285         // encode order ctrl buffering surfaces in own pools,
286         // so add number of required frames for it
287         allocRequest.NumFrameSuggested += m_pOrderCtrl->GetNumReorderFrames();
288         allocRequest.NumFrameMin = allocRequest.NumFrameSuggested;
289     }
290 
291     sts = m_EncSurfPool.AllocSurfaces(allocRequest);
292     MSDK_CHECK_STATUS(sts, "AllocFrames::EncSurfPool->AllocSurfaces failed");
293 
294     return sts;
295 }
296 
InitComponents()297 mfxStatus CEncodingPipeline::InitComponents()
298 {
299     mfxStatus sts = MFX_ERR_NONE;
300 
301     MSDK_CHECK_POINTER(m_pYUVSource.get(), MFX_ERR_UNSUPPORTED);
302     sts = m_pYUVSource->Init();
303     MSDK_CHECK_STATUS(sts, "m_pYUVSource->Init failed");
304 
305     if (m_pFEI_PreENC.get())
306     {
307         sts = m_pFEI_PreENC->Init();
308         MSDK_CHECK_STATUS(sts, "FEI PreENC Init failed");
309     }
310 
311     if (m_pFEI_Encode.get())
312     {
313         sts = m_pFEI_Encode->Init();
314         MSDK_CHECK_STATUS(sts, "FEI ENCODE Init failed");
315     }
316 
317     return sts;
318 }
319 
Execute()320 mfxStatus CEncodingPipeline::Execute()
321 {
322     mfxStatus sts = MFX_ERR_NONE;
323 
324     mfxFrameSurface1* pSurf = NULL; // points to frame being processed
325 
326     mfxU32 numSubmitted = 0;
327     time_t start = time(0);
328 
329     while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_DATA == sts)
330     {
331         if ((m_inParams.nNumFrames && m_inParams.nNumFrames <= numSubmitted)    // frame encoding limit
332             || (m_inParams.nTimeout && time(0) - start >= m_inParams.nTimeout)) // encoding time limit
333             break;
334 
335         sts = m_pYUVSource->GetFrame(pSurf);
336         if (MFX_ERR_MORE_DATA == sts && (m_inParams.nTimeout || m_inParams.nNumFrames))
337         {
338             // reached end of input file, reset file pointers and start from the beginning
339             MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);
340             MSDK_BREAK_ON_ERROR(sts);
341 
342             sts = m_pYUVSource->ResetIOState();
343             MSDK_BREAK_ON_ERROR(sts);
344 
345             if (m_inParams.nTimeout && !m_inParams.nNumFrames)
346             {
347                 // execution timeout can be too big for available disk space, so reset output file pointers
348                 // despite the fact that stream can be undecodable
349                 if (m_pFEI_PreENC.get())
350                 {
351                     sts = m_pFEI_PreENC->ResetIOState();
352                     MSDK_BREAK_ON_ERROR(sts);
353                 }
354                 if (m_pFEI_Encode.get())
355                 {
356                     sts = m_pFEI_Encode->ResetIOState();
357                     MSDK_BREAK_ON_ERROR(sts);
358                 }
359             }
360 
361             continue;
362         }
363         MSDK_BREAK_ON_ERROR(sts);
364 
365         numSubmitted++;
366 
367         HevcTask* task = NULL;
368         if (m_pOrderCtrl.get())
369         {
370             task = m_pOrderCtrl->GetTask(pSurf);
371             if (!task)
372                 continue; // frame is buffered here
373         }
374 
375         if (m_pFEI_PreENC.get())
376         {
377             sts = m_pFEI_PreENC->PreEncFrame(task);
378             MSDK_BREAK_ON_ERROR(sts);
379         }
380 
381         if (m_pFEI_Encode.get())
382         {
383             sts = task ? m_pFEI_Encode->EncodeFrame(task) : m_pFEI_Encode->EncodeFrame(pSurf);
384             MSDK_BREAK_ON_ERROR(sts);
385         }
386 
387         if (m_pOrderCtrl.get())
388             m_pOrderCtrl->FreeTask(task);
389     } // while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_DATA == sts)
390 
391     MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA); // reached end of input file
392     // exit in case of other errors
393     MSDK_CHECK_STATUS(sts, "Frame processing failed");
394 
395     sts = DrainBufferedFrames();
396     MSDK_CHECK_STATUS(sts, "Buffered frames processing failed");
397 
398     return sts;
399 }
400 
DrainBufferedFrames()401 mfxStatus CEncodingPipeline::DrainBufferedFrames()
402 {
403     mfxStatus sts = MFX_ERR_NONE;
404 
405     // encode order
406     if (m_pOrderCtrl.get())
407     {
408         HevcTask* task;
409         while ( NULL != (task = m_pOrderCtrl->GetTask(NULL)))
410         {
411             if (m_pFEI_PreENC.get())
412             {
413                 sts = m_pFEI_PreENC->PreEncFrame(task);
414                 MSDK_CHECK_STATUS(sts, "PreEncFrame drain failed");
415             }
416 
417             if (m_pFEI_Encode.get())
418             {
419                 sts = m_pFEI_Encode->EncodeFrame(task);
420                 // exit in case of other errors
421                 MSDK_CHECK_STATUS(sts, "EncodeFrame drain failed");
422 
423             }
424             m_pOrderCtrl->FreeTask(task);
425         }
426         return sts;
427     }
428 
429     // display order
430     if (m_pFEI_Encode.get())
431     {
432         mfxFrameSurface1* null_surf = NULL;
433         while (MFX_ERR_NONE <= sts)
434         {
435             sts = m_pFEI_Encode->EncodeFrame(null_surf);
436         }
437 
438         // MFX_ERR_MORE_DATA indicates that there are no more buffered frames
439         MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);
440         // exit in case of other errors
441         MSDK_CHECK_STATUS(sts, "EncodeFrame failed");
442     }
443 
444     return sts;
445 }
446 
447 // Function generates common mfxVideoParam ENCODE
448 // from user cmd line parameters and frame info from upstream component in pipeline.
GetEncodeParams(const sInputParams & user_pars,const mfxFrameInfo & in_fi,PIPELINE_COMPONENT component)449 MfxVideoParamsWrapper GetEncodeParams(const sInputParams& user_pars, const mfxFrameInfo& in_fi, PIPELINE_COMPONENT component)
450 {
451     MfxVideoParamsWrapper pars;
452 
453     // frame info from previous component
454     MSDK_MEMCPY_VAR(pars.mfx.FrameInfo, &in_fi, sizeof(mfxFrameInfo));
455 
456     pars.mfx.CodecId = MFX_CODEC_HEVC;
457 
458     // default settings
459     pars.mfx.TargetUsage       = 0;
460     pars.AsyncDepth            = 1; // inherited limitation from AVC FEI
461     pars.IOPattern             = MFX_IOPATTERN_IN_VIDEO_MEMORY;
462 
463     // user defined settings
464     pars.mfx.CodecLevel   = user_pars.CodecLevel;
465     pars.mfx.CodecProfile = user_pars.CodecProfile;
466     pars.mfx.GopRefDist   = user_pars.nRefDist;
467     pars.mfx.GopPicSize   = user_pars.nGopSize;
468     pars.mfx.GopOptFlag   = user_pars.nGopOptFlag;
469     pars.mfx.IdrInterval  = user_pars.nIdrInterval;
470     pars.mfx.NumRefFrame  = user_pars.nNumRef;
471     pars.mfx.NumSlice     = user_pars.nNumSlices;
472     pars.mfx.EncodedOrder = user_pars.bEncodedOrder;
473 
474     mfxExtCodingOption* pCO = pars.AddExtBuffer<mfxExtCodingOption>();
475     if (!pCO) throw mfxError(MFX_ERR_NOT_INITIALIZED, "Failed to attach mfxExtCodingOption");
476 
477     pCO->PicTimingSEI = user_pars.PicTimingSEI;
478 
479     mfxExtCodingOption2* pCO2 = pars.AddExtBuffer<mfxExtCodingOption2>();
480     if (!pCO2) throw mfxError(MFX_ERR_NOT_INITIALIZED, "Failed to attach mfxExtCodingOption2");
481 
482     // configure B-pyramid settings
483     pCO2->BRefType = user_pars.BRefType;
484 
485     if (user_pars.bExtBRC && component == PIPELINE_COMPONENT::ENCODE) {
486         // This is for explicit extbrc only. In case of implicit (built-into-library) version - we don't need this extension buffer
487         mfxExtBRC* pBrc = pars.AddExtBuffer<mfxExtBRC>();
488         if (!pBrc) throw mfxError(MFX_ERR_NOT_INITIALIZED, "Failed to attach mfxExtBRC");
489 
490         pCO2->ExtBRC = (mfxU16)MFX_CODINGOPTION_ON;
491 
492         pars.mfx.RateControlMethod = MFX_RATECONTROL_CBR;
493         pars.mfx.TargetKbps = user_pars.TargetKbps;
494     }
495     else
496     {
497         pars.mfx.RateControlMethod = MFX_RATECONTROL_CQP;
498         pars.mfx.QPI = pars.mfx.QPP = pars.mfx.QPB = user_pars.QP;
499     }
500 
501     mfxExtCodingOption3* pCO3 = pars.AddExtBuffer<mfxExtCodingOption3>();
502     if (!pCO3) throw mfxError(MFX_ERR_NOT_INITIALIZED, "Failed to attach mfxExtCodingOption3");
503 
504     pCO3->PRefType             = user_pars.PRefType;
505 
506     std::fill(pCO3->NumRefActiveP,   pCO3->NumRefActiveP   + 8, user_pars.NumRefActiveP);
507     std::fill(pCO3->NumRefActiveBL0, pCO3->NumRefActiveBL0 + 8, user_pars.NumRefActiveBL0);
508     std::fill(pCO3->NumRefActiveBL1, pCO3->NumRefActiveBL1 + 8, user_pars.NumRefActiveBL1);
509 
510     pCO3->GPB = user_pars.GPB;
511 
512     // qp offset per pyramid layer, default is library behavior
513     pCO3->EnableQPOffset = user_pars.bDisableQPOffset ? MFX_CODINGOPTION_OFF : MFX_CODINGOPTION_UNKNOWN;
514 
515     // This buffer is a correct way to pass coding window size to HEVC encoder
516     // (if required, it will be rounded up to 16 or 8 alignment depending on HW (expect warning in such case)).
517     // This code added to sample just to show this possibility. Current implementation of sample will work correctly without this buffer as well.
518     if (component == PIPELINE_COMPONENT::ENCODE) {
519         mfxExtHEVCParam* pHP = pars.AddExtBuffer<mfxExtHEVCParam>();
520         if (!pHP) throw mfxError(MFX_ERR_NOT_INITIALIZED, "Failed to attach mfxExtHEVCParam");
521 
522         pHP->PicWidthInLumaSamples  = pars.mfx.FrameInfo.CropX + pars.mfx.FrameInfo.CropW;
523         pHP->PicHeightInLumaSamples = pars.mfx.FrameInfo.CropY + pars.mfx.FrameInfo.CropH;
524     }
525     return pars;
526 }
527 
CreateYUVSource()528 IYUVSource* CEncodingPipeline::CreateYUVSource()
529 {
530     std::unique_ptr<IYUVSource> pSource;
531 
532     if (m_inParams.input.DecodeId)
533     {
534         mfxPluginUID pluginGuid = MSDK_PLUGINGUID_NULL;
535         pluginGuid = msdkGetPluginUID(m_impl, MSDK_VDECODE, m_inParams.input.DecodeId);
536 
537         if (!AreGuidsEqual(pluginGuid, MSDK_PLUGINGUID_NULL))
538         {
539             m_pDecoderPlugin.reset(LoadPlugin(MFX_PLUGINTYPE_VIDEO_DECODE, m_mfxSession, pluginGuid, 1));
540             if (m_pDecoderPlugin.get() == NULL)
541                 return NULL;
542         }
543 
544         pSource.reset(new Decoder(m_inParams.input, &m_EncSurfPool, &m_mfxSession));
545     }
546     else
547         pSource.reset(new YUVReader(m_inParams.input, &m_EncSurfPool));
548 
549     if (m_inParams.input.fieldSplitting)
550     {
551         IYUVSource* pFieldSplitter = new FieldSplitter(pSource.get(), m_inParams.input, &m_EncSurfPool, &m_mfxSession);
552         pSource.release(); // FieldSplitter takes responsibility for memory deallocation of pSource
553         pSource.reset(pFieldSplitter);
554     }
555 
556     return pSource.release();
557 }
558 
CreatePreENC(mfxFrameInfo & in_fi)559 IPreENC* CEncodingPipeline::CreatePreENC(mfxFrameInfo& in_fi)
560 {
561     if (!m_inParams.bPREENC && (0 == msdk_strlen(m_inParams.mvpInFile) || !m_inParams.bFormattedMVPin))
562         return NULL;
563 
564     MfxVideoParamsWrapper pars = GetEncodeParams(m_inParams, in_fi, PIPELINE_COMPONENT::PREENC);
565 
566     mfxStatus sts = m_pParamChecker->Query(pars);
567     CHECK_STS_AND_RETURN(sts, "m_pParamChecker->Query failed", NULL);
568 
569     // PreENC specific parameters
570     pars.mfx.CodecId = MFX_CODEC_AVC;
571 
572     // attach buffer to set FEI PreENC usage model
573     mfxExtFeiParam* pExtBufInit = pars.AddExtBuffer<mfxExtFeiParam>();
574     if (!pExtBufInit) throw mfxError(MFX_ERR_NOT_INITIALIZED, "Failed to attach mfxExtFeiParam");
575     pExtBufInit->Func = MFX_FEI_FUNCTION_PREENC;
576 
577     std::unique_ptr<IPreENC> pPreENC;
578 
579     if (0 == msdk_strlen(m_inParams.mvpInFile))
580     {
581         pPreENC.reset(new FEI_Preenc(&m_mfxSession, pars, m_inParams.preencCtrl, m_inParams.mvoutFile,
582             m_inParams.bFormattedMVout, m_inParams.mbstatoutFile));
583 
584         if (m_inParams.preencDSfactor > 1)
585         {
586             IPreENC* pPreENC_DS = new PreencDownsampler(pPreENC.get(), m_inParams.preencDSfactor, &m_mfxSession, m_pMFXAllocator.get());
587             pPreENC.release(); // PreencDownsampler saves an auto-pointer for just created FEI_Preenc
588             pPreENC.reset(pPreENC_DS);
589         }
590     }
591     else
592     {
593         pPreENC.reset(new Preenc_Reader(pars, m_inParams.preencCtrl, m_inParams.mvpInFile));
594     }
595 
596 
597     return pPreENC.release();
598 }
599 
CreateEncode(mfxFrameInfo & in_fi)600 FEI_Encode* CEncodingPipeline::CreateEncode(mfxFrameInfo& in_fi)
601 {
602     if (!m_inParams.bENCODE)
603         return NULL;
604 
605     mfxStatus sts = MFX_ERR_NONE;
606 
607     sts = LoadFEIPlugin();
608     CHECK_STS_AND_RETURN(sts, "LoadFEIPlugin failed", NULL);
609 
610     MfxVideoParamsWrapper pars = GetEncodeParams(m_inParams, in_fi, PIPELINE_COMPONENT::ENCODE);
611     sts = m_pParamChecker->Query(pars);
612     CHECK_STS_AND_RETURN(sts, "m_pParamChecker->Query failed", NULL);
613 
614     std::unique_ptr<PredictorsRepaking> pRepacker;
615 
616     if (m_inParams.bPREENC || (0 != msdk_strlen(m_inParams.mvpInFile) && m_inParams.bFormattedMVPin))
617     {
618         pRepacker.reset(new PredictorsRepaking());
619         sts = pRepacker->Init(pars, m_inParams.preencDSfactor, m_inParams.encodeCtrl.NumMvPredictors);
620         CHECK_STS_AND_RETURN(sts, "CreateEncode::pRepacker->Init failed", NULL);
621 
622         m_inParams.bQualityRepack ? pRepacker->SetQualityRepackingMode() : pRepacker->SetPerfomanceRepackingMode();
623     }
624 
625     mfxHDL hdl = NULL;
626     sts = m_pHWdev->GetHandle(MFX_HANDLE_VA_DISPLAY, &hdl);
627     CHECK_STS_AND_RETURN(sts, "CreateEncode::m_pHWdev->GetHandle failed", NULL);
628 
629     FEI_Encode* pEncode = new FEI_Encode(&m_mfxSession, hdl,
630                                          pars, m_inParams.encodeCtrl, m_inParams.frameCtrl,
631                                          m_inParams.strDstFile, m_inParams.mvpInFile,
632                                          m_inParams.repackctrlFile, m_inParams.repackstatFile,
633                                          pRepacker.get());
634 
635     pRepacker.release(); // FEI_Encode takes responsibility for pRepakcer's deallocation
636 
637     return pEncode;
638 }
639