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