1 /*############################################################################
2 # Copyright (C) 2005 Intel Corporation
3 #
4 # SPDX-License-Identifier: MIT
5 ############################################################################*/
6
7 #include <algorithm>
8 #include "mfx_samples_config.h"
9 #include "sample_defs.h"
10
11 #if defined(_WIN32) || defined(_WIN64)
12 #include <tchar.h>
13 #include <windows.h>
14 #endif
15
16 #include <assert.h>
17 #include <algorithm>
18 #include <ctime>
19 #include <thread>
20 #include "pipeline_decode.h"
21 #include "sysmem_allocator.h"
22
23 #if defined(_WIN32) || defined(_WIN64)
24 #include "d3d11_allocator.h"
25 #include "d3d11_device.h"
26 #include "d3d_allocator.h"
27 #include "d3d_device.h"
28
29 #endif
30
31 #if defined LIBVA_SUPPORT
32 #include "vaapi_allocator.h"
33 #include "vaapi_device.h"
34 #include "vaapi_utils.h"
35 #endif
36
37 #if defined(LIBVA_WAYLAND_SUPPORT)
38 #include "class_wayland.h"
39 #endif
40
41 #include "version.h"
42
43 #define __SYNC_WA // avoid sync issue on Media SDK side
44
45 #ifndef MFX_VERSION
46 #error MFX_VERSION not defined
47 #endif
48
CDecodingPipeline()49 CDecodingPipeline::CDecodingPipeline()
50 : m_FileWriter(),
51 m_FileReader(),
52 m_mfxBS(8 * 1024 * 1024),
53 totalBytesProcessed(0),
54 m_pLoader(),
55 m_mfxSession(),
56 m_impl(0),
57 m_pmfxDEC(NULL),
58 m_pmfxVPP(NULL),
59 m_mfxVideoParams(),
60 m_mfxVppVideoParams(),
61 m_pGeneralAllocator(NULL),
62 m_pmfxAllocatorParams(NULL),
63 m_memType(SYSTEM_MEMORY),
64 m_bExternalAlloc(false),
65 m_bDecOutSysmem(false),
66 m_mfxResponse({}),
67 m_mfxVppResponse({}),
68 m_pCurrentFreeSurface(NULL),
69 m_pCurrentFreeVppSurface(NULL),
70 m_pCurrentFreeOutputSurface(NULL),
71 m_pCurrentOutputSurface(NULL),
72 m_pDeliverOutputSemaphore(NULL),
73 m_pDeliveredEvent(NULL),
74 m_error(MFX_ERR_NONE),
75 m_bStopDeliverLoop(false),
76 m_eWorkMode(MODE_PERFORMANCE),
77 m_bIsMVC(false),
78 m_bIsVideoWall(false),
79 m_bIsCompleteFrame(false),
80 m_fourcc(0),
81 m_bPrintLatency(false),
82 m_bOutI420(false),
83 m_vppOutWidth(0),
84 m_vppOutHeight(0),
85 m_nTimeout(0),
86 m_nMaxFps(0),
87 m_nFrames(0),
88 m_diMode(0),
89 m_bVppIsUsed(false),
90 m_bVppFullColorRange(false),
91 m_bSoftRobustFlag(false),
92 m_vLatency(),
93 m_fpsLimiter(),
94 m_VppVideoSignalInfo({}),
95 m_VppSurfaceExtParams(),
96 #if defined(LINUX32) || defined(LINUX64)
97 m_strDevicePath(),
98 #endif
99 m_hwdev(NULL),
100 #if D3D_SURFACES_SUPPORT
101 m_d3dRender(),
102 #endif
103 m_bRenderWin(false),
104 m_nRenderWinX(0),
105 m_nRenderWinY(0),
106 m_nRenderWinW(0),
107 m_nRenderWinH(0),
108 #ifdef LIBVA_SUPPORT
109 m_export_mode(vaapiAllocatorParams::DONOT_EXPORT),
110 #else
111 m_export_mode(0),
112 #endif
113 m_monitorType(0),
114 #ifdef LIBVA_SUPPORT
115 m_libvaBackend(0),
116 m_bPerfMode(false),
117 #endif
118 m_bResetFileWriter(false),
119 m_bResetFileReader(false) {
120 // reserve some space to reduce dynamic reallocation impact on pipeline execution
121 m_vLatency.reserve(1000);
122 m_VppVideoSignalInfo.Header.BufferId = MFX_EXTBUFF_VPP_VIDEO_SIGNAL_INFO;
123 m_VppVideoSignalInfo.Header.BufferSz = sizeof(m_VppVideoSignalInfo);
124 }
125
~CDecodingPipeline()126 CDecodingPipeline::~CDecodingPipeline() {
127 Close();
128 }
129
Init(sInputParams * pParams)130 mfxStatus CDecodingPipeline::Init(sInputParams* pParams) {
131 MSDK_CHECK_POINTER(pParams, MFX_ERR_NULL_PTR);
132
133 mfxStatus sts = MFX_ERR_NONE;
134
135 // prepare input stream file reader
136 // for VP8 complete and single frame reader is a requirement
137 // create reader that supports completeframe mode for latency oriented scenarios
138 if (pParams->bLowLat || pParams->bCalLat) {
139 switch (pParams->videoType) {
140 case MFX_CODEC_AVC:
141 m_FileReader.reset(new CH264FrameReader());
142 m_bIsCompleteFrame = true;
143 m_bPrintLatency = pParams->bCalLat;
144 break;
145 case MFX_CODEC_JPEG:
146 m_FileReader.reset(new CJPEGFrameReader());
147 m_bIsCompleteFrame = true;
148 m_bPrintLatency = pParams->bCalLat;
149 break;
150 case MFX_CODEC_VP8:
151 case MFX_CODEC_VP9:
152 case MFX_CODEC_AV1:
153 m_FileReader.reset(new CIVFFrameReader());
154 m_bIsCompleteFrame = true;
155 m_bPrintLatency = pParams->bCalLat;
156 break;
157 default:
158 return MFX_ERR_UNSUPPORTED; // latency mode is supported only for H.264 and JPEG codecs
159 }
160 }
161 else {
162 switch (pParams->videoType) {
163 case MFX_CODEC_VP8:
164 case MFX_CODEC_VP9:
165 case MFX_CODEC_AV1:
166 m_FileReader.reset(new CIVFFrameReader());
167 break;
168 default:
169 m_FileReader.reset(new CSmplBitstreamReader());
170 break;
171 }
172 }
173
174 if (pParams->fourcc)
175 m_fourcc = pParams->fourcc;
176
177 #ifdef LIBVA_SUPPORT
178 if (pParams->bPerfMode)
179 m_bPerfMode = true;
180 #endif
181
182 if (pParams->Width)
183 m_vppOutWidth = pParams->Width;
184 if (pParams->Height)
185 m_vppOutHeight = pParams->Height;
186
187 #if defined(LINUX32) || defined(LINUX64)
188 m_strDevicePath = pParams->strDevicePath;
189 #endif
190
191 if (pParams->memType)
192 m_memType = pParams->memType;
193 else {
194 switch (pParams->mode) {
195 case MODE_PERFORMANCE:
196 #if defined(_WIN32) || defined(_WIN64)
197 m_memType = pParams->bUseHWLib ? D3D11_MEMORY : SYSTEM_MEMORY;
198 #elif defined(LIBVA_SUPPORT)
199 m_memType = pParams->bUseHWLib ? D3D9_MEMORY : SYSTEM_MEMORY;
200 #endif
201 break;
202 case MODE_RENDERING:
203 m_memType = D3D9_MEMORY;
204 break;
205 case MODE_FILE_DUMP:
206 m_memType = SYSTEM_MEMORY;
207 break;
208 default:
209 assert(0);
210 MSDK_CHECK_STATUS(MFX_ERR_UNSUPPORTED, "Unexpected eWorkMode");
211 }
212 }
213
214 m_nMaxFps = pParams->nMaxFPS;
215 m_nFrames = pParams->nFrames ? pParams->nFrames : MFX_INFINITE;
216
217 m_bOutI420 = pParams->outI420;
218
219 m_nTimeout = pParams->nTimeout;
220 m_bSoftRobustFlag = pParams->bSoftRobustFlag;
221
222 // Initializing file reader
223 totalBytesProcessed = 0;
224 sts = m_FileReader->Init(pParams->strSrcFile);
225 if (sts == MFX_ERR_UNSUPPORTED && pParams->videoType == MFX_CODEC_AV1) {
226 m_FileReader.reset(new CSmplBitstreamReader());
227 msdk_printf(MSDK_STRING("WARNING: Stream is not IVF, default reader\n"));
228 }
229 MSDK_CHECK_STATUS(sts, "m_FileReader->Init failed");
230
231 mfxInitParamlWrap initPar;
232 auto threadsPar = initPar.AddExtBuffer<mfxExtThreadsParam>();
233 MSDK_CHECK_POINTER(threadsPar, MFX_ERR_MEMORY_ALLOC);
234
235 initPar.GPUCopy = pParams->gpuCopy;
236
237 if (pParams->nThreadsNum) {
238 threadsPar->NumThread = pParams->nThreadsNum;
239 }
240 if (pParams->SchedulingType) {
241 threadsPar->SchedulingType = pParams->SchedulingType;
242 }
243 if (pParams->Priority) {
244 threadsPar->Priority = pParams->Priority;
245 }
246
247 if (pParams->eDeinterlace) {
248 m_diMode = pParams->eDeinterlace;
249 }
250 if (pParams->bUseFullColorRange) {
251 m_bVppFullColorRange = pParams->bUseFullColorRange;
252 }
253
254 bool bResolutionSpecified =
255 pParams->Width || pParams->Height; // potentially VPP can be inserted
256
257 if (bResolutionSpecified)
258 m_bDecOutSysmem = pParams->bUseHWLib ? false : true;
259 else
260 m_bDecOutSysmem = m_memType == SYSTEM_MEMORY;
261
262 m_eWorkMode = pParams->mode;
263
264 m_monitorType = pParams->monitorType;
265 // create device and allocator
266 #if defined(LIBVA_SUPPORT)
267 m_libvaBackend = pParams->libvaBackend;
268 #endif // defined(MFX_LIBVA_SUPPORT)
269
270 initPar.Implementation = pParams->bUseHWLib ? MFX_IMPL_HARDWARE : MFX_IMPL_SOFTWARE;
271
272 m_pLoader.reset(new VPLImplementationLoader);
273
274 if (pParams->dGfxIdx >= 0)
275 m_pLoader->SetDiscreteAdapterIndex(pParams->dGfxIdx);
276 else
277 m_pLoader->SetAdapterType(pParams->adapterType);
278
279 if (pParams->adapterNum >= 0)
280 m_pLoader->SetAdapterNum(pParams->adapterNum);
281
282 #ifdef ONEVPL_EXPERIMENTAL
283 if (pParams->PCIDeviceSetup)
284 m_pLoader->SetPCIDevice(pParams->PCIDomain,
285 pParams->PCIBus,
286 pParams->PCIDevice,
287 pParams->PCIFunction);
288
289 #if (defined(_WIN64) || defined(_WIN32))
290 if (pParams->luid.HighPart > 0 || pParams->luid.LowPart)
291 m_pLoader->SetupLUID(pParams->luid);
292 #else
293 m_pLoader->SetupDRMRenderNodeNum(pParams->DRMRenderNodeNum);
294 #endif
295 #endif
296
297 if (!pParams->accelerationMode && pParams->bUseHWLib) {
298 #if D3D_SURFACES_SUPPORT
299 pParams->accelerationMode = MFX_ACCEL_MODE_VIA_D3D11;
300 #elif defined(LIBVA_SUPPORT)
301 pParams->accelerationMode = MFX_ACCEL_MODE_VIA_VAAPI;
302 #endif
303 }
304
305 bool bLowLatencyMode = !pParams->dispFullSearch;
306
307 sts = m_pLoader->ConfigureAndEnumImplementations(initPar.Implementation,
308 pParams->accelerationMode,
309 bLowLatencyMode);
310 MSDK_CHECK_STATUS(sts, "m_mfxSession.EnumImplementations failed");
311
312 sts = m_mfxSession.CreateSession(m_pLoader.get());
313 MSDK_CHECK_STATUS(sts, "m_mfxSession.CreateSession failed");
314
315 mfxVersion version;
316 sts = m_mfxSession.QueryVersion(&version); // get real API version of the loaded library
317 MSDK_CHECK_STATUS(sts, "m_mfxSession.QueryVersion failed");
318
319 sts = m_mfxSession.QueryIMPL(&m_impl); // get actual library implementation
320 MSDK_CHECK_STATUS(sts, "m_mfxSession.QueryIMPL failed");
321
322 #if defined(_WIN32) || defined(_WIN64)
323 if (pParams->videoType == MFX_CODEC_AV1 && MFX_IMPL_VIA_MASK(m_impl) == MFX_IMPL_VIA_D3D9) {
324 sts = MFX_ERR_UNSUPPORTED;
325 MSDK_CHECK_STATUS(sts, "AV1d have no DX9 support \n");
326 }
327 #endif
328
329 bool isDeviceRequired = false;
330 mfxHandleType hdl_t;
331 #if D3D_SURFACES_SUPPORT
332 isDeviceRequired = m_memType != SYSTEM_MEMORY || !m_bDecOutSysmem;
333 hdl_t =
334 #if MFX_D3D11_SUPPORT
335 D3D11_MEMORY == m_memType ? MFX_HANDLE_D3D11_DEVICE :
336 #endif // #if MFX_D3D11_SUPPORT
337 MFX_HANDLE_D3D9_DEVICE_MANAGER;
338 #elif LIBVA_SUPPORT
339 if (MFX_IMPL_SOFTWARE != initPar.Implementation) {
340 isDeviceRequired = true; // on Linux MediaSDK doesn't create device internally
341 hdl_t = MFX_HANDLE_VA_DISPLAY;
342 }
343 #endif
344 if (isDeviceRequired) {
345 sts = CreateHWDevice();
346 MSDK_CHECK_STATUS(sts, "CreateHWDevice failed");
347 if (pParams->bUseHWLib) {
348 mfxHDL hdl = NULL;
349 sts = m_hwdev->GetHandle(hdl_t, &hdl);
350 MSDK_CHECK_STATUS(sts, "m_hwdev->GetHandle failed");
351 sts = m_mfxSession.SetHandle(hdl_t, hdl);
352 MSDK_CHECK_STATUS(sts, "m_mfxSession.SetHandle failed");
353 }
354 }
355
356 if (pParams->bIsMVC && !CheckVersion(&version, MSDK_FEATURE_MVC)) {
357 msdk_printf(MSDK_STRING("error: MVC is not supported in the %d.%d API version\n"),
358 (int)version.Major,
359 (int)version.Minor);
360 return MFX_ERR_UNSUPPORTED;
361 }
362 if ((pParams->videoType == MFX_CODEC_JPEG) &&
363 !CheckVersion(&version, MSDK_FEATURE_JPEG_DECODE)) {
364 msdk_printf(MSDK_STRING("error: Jpeg is not supported in the %d.%d API version\n"),
365 (int)version.Major,
366 (int)version.Minor);
367 return MFX_ERR_UNSUPPORTED;
368 }
369 if (pParams->bLowLat && !CheckVersion(&version, MSDK_FEATURE_LOW_LATENCY)) {
370 msdk_printf(
371 MSDK_STRING("error: Low Latency mode is not supported in the %d.%d API version\n"),
372 (int)version.Major,
373 (int)version.Minor);
374 return MFX_ERR_UNSUPPORTED;
375 }
376
377 if (pParams->eDeinterlace && (pParams->eDeinterlace != MFX_DEINTERLACING_ADVANCED) &&
378 (pParams->eDeinterlace != MFX_DEINTERLACING_BOB)) {
379 msdk_printf(MSDK_STRING("error: Unsupported deinterlace value: %d\n"),
380 (int)pParams->eDeinterlace);
381 return MFX_ERR_UNSUPPORTED;
382 }
383
384 if (pParams->bRenderWin) {
385 m_bRenderWin = pParams->bRenderWin;
386 // note: currently position is unsupported for Wayland
387 #if !defined(LIBVA_WAYLAND_SUPPORT)
388 m_nRenderWinX = pParams->nRenderWinX;
389 m_nRenderWinY = pParams->nRenderWinY;
390 #endif
391 }
392
393 m_fpsLimiter.Reset(pParams->nMaxFPS);
394
395 // create decoder
396 m_pmfxDEC = new MFXVideoDECODE(m_mfxSession);
397 MSDK_CHECK_POINTER(m_pmfxDEC, MFX_ERR_MEMORY_ALLOC);
398
399 // set video type in parameters
400 m_mfxVideoParams.mfx.CodecId = pParams->videoType;
401
402 m_mfxVideoParams.mfx.IgnoreLevelConstrain = pParams->bIgnoreLevelConstrain;
403
404 // Populate parameters. Involves DecodeHeader call
405 sts = InitMfxParams(pParams);
406 MSDK_CHECK_STATUS(sts, "InitMfxParams failed");
407
408 if (m_bVppIsUsed) {
409 m_pmfxVPP = new MFXVideoVPP(m_mfxSession);
410 if (!m_pmfxVPP)
411 return MFX_ERR_MEMORY_ALLOC;
412 }
413
414 if (m_eWorkMode == MODE_FILE_DUMP) {
415 // prepare YUV file writer
416 sts = m_FileWriter.Init(pParams->strDstFile, pParams->numViews);
417 MSDK_CHECK_STATUS(sts, "m_FileWriter.Init failed");
418 }
419 else if ((m_eWorkMode != MODE_PERFORMANCE) && (m_eWorkMode != MODE_RENDERING)) {
420 msdk_printf(MSDK_STRING("error: unsupported work mode\n"));
421 return MFX_ERR_UNSUPPORTED;
422 }
423
424 sts = CreateAllocator();
425 MSDK_CHECK_STATUS(sts, "CreateAllocator failed");
426
427 // in case of HW accelerated decode frames must be allocated prior to decoder initialization
428 sts = AllocFrames();
429 MSDK_CHECK_STATUS(sts, "AllocFrames failed");
430
431 sts = m_pmfxDEC->Init(&m_mfxVideoParams);
432 if (MFX_WRN_PARTIAL_ACCELERATION == sts) {
433 msdk_printf(MSDK_STRING("WARNING: partial acceleration\n"));
434 MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
435 }
436 MSDK_CHECK_STATUS(sts, "m_pmfxDEC->Init failed");
437
438 if (m_bVppIsUsed) {
439 if (m_diMode)
440 m_mfxVppVideoParams.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
441
442 if (pParams->ScalingMode) {
443 auto par = m_mfxVppVideoParams.AddExtBuffer<mfxExtVPPScaling>();
444 par->ScalingMode = pParams->ScalingMode;
445 }
446
447 sts = m_pmfxVPP->Init(&m_mfxVppVideoParams);
448 if (MFX_WRN_PARTIAL_ACCELERATION == sts) {
449 msdk_printf(MSDK_STRING("WARNING: partial acceleration\n"));
450 MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
451 }
452 MSDK_CHECK_STATUS(sts, "m_pmfxVPP->Init failed");
453 }
454
455 sts = m_pmfxDEC->GetVideoParam(&m_mfxVideoParams);
456 MSDK_CHECK_STATUS(sts, "m_pmfxDEC->GetVideoParam failed");
457
458 if (m_eWorkMode == MODE_RENDERING) {
459 sts = CreateRenderingWindow(pParams);
460 MSDK_CHECK_STATUS(sts, "CreateRenderingWindow failed");
461 }
462
463 return sts;
464 }
465
IsVppRequired(sInputParams * pParams)466 bool CDecodingPipeline::IsVppRequired(sInputParams* pParams) {
467 bool bVppIsUsed = false;
468 /* Re-size */
469 if ((m_mfxVideoParams.mfx.FrameInfo.CropW != pParams->Width) ||
470 (m_mfxVideoParams.mfx.FrameInfo.CropH != pParams->Height)) {
471 bVppIsUsed = pParams->Width && pParams->Height;
472 if ((MODE_DECODER_POSTPROC_AUTO == pParams->nDecoderPostProcessing) ||
473 (MODE_DECODER_POSTPROC_FORCE == pParams->nDecoderPostProcessing)) {
474 /* Decoder will make decision about internal post-processing usage slightly later */
475 bVppIsUsed = false;
476 }
477 }
478
479 // JPEG and Capture decoders can provide output in nv12 and rgb4 formats
480 if (pParams->videoType == MFX_CODEC_JPEG) {
481 bVppIsUsed |= m_fourcc && (m_fourcc != MFX_FOURCC_NV12) && (m_fourcc != MFX_FOURCC_RGB4);
482 }
483 else {
484 bVppIsUsed |= m_fourcc && (m_fourcc != m_mfxVideoParams.mfx.FrameInfo.FourCC);
485 }
486
487 if (pParams->eDeinterlace) {
488 bVppIsUsed = true;
489 }
490
491 if ((MODE_DECODER_POSTPROC_AUTO == pParams->nDecoderPostProcessing) ||
492 (MODE_DECODER_POSTPROC_FORCE == pParams->nDecoderPostProcessing)) {
493 /* Decoder will make decision about internal post-processing usage slightly later */
494 if ((pParams->videoType == MFX_CODEC_AVC) || (pParams->videoType == MFX_CODEC_HEVC))
495 bVppIsUsed = false;
496 }
497
498 return bVppIsUsed;
499 }
500
Close()501 void CDecodingPipeline::Close() {
502 #if D3D_SURFACES_SUPPORT
503 m_d3dRender.Close();
504 #endif
505 MSDK_SAFE_DELETE(m_pmfxDEC);
506 MSDK_SAFE_DELETE(m_pmfxVPP);
507
508 DeleteFrames();
509
510 DeallocateExtMVCBuffers();
511
512 m_mfxSession.Close();
513 m_FileWriter.Close();
514 if (m_FileReader.get())
515 m_FileReader->Close();
516
517 auto vppExtParams = m_mfxVppVideoParams.GetExtBuffer<mfxExtVPPDoNotUse>();
518 if (vppExtParams)
519 MSDK_SAFE_DELETE_ARRAY(vppExtParams->AlgList);
520
521 // allocator if used as external for MediaSDK must be deleted after decoder
522 DeleteAllocator();
523
524 return;
525 }
526
CreateRenderingWindow(sInputParams * pParams)527 mfxStatus CDecodingPipeline::CreateRenderingWindow(sInputParams* pParams) {
528 mfxStatus sts = MFX_ERR_NONE;
529
530 #if D3D_SURFACES_SUPPORT
531 sWindowParams windowParams;
532
533 windowParams.lpWindowName = pParams->bWallNoTitle ? NULL : MSDK_STRING("sample_decode");
534 windowParams.nx = pParams->nWallW;
535 windowParams.ny = pParams->nWallH;
536 if (m_bVppIsUsed) {
537 windowParams.nWidth = m_mfxVppVideoParams.vpp.Out.Width;
538 windowParams.nHeight = m_mfxVppVideoParams.vpp.Out.Height;
539 }
540 else {
541 windowParams.nWidth = m_mfxVideoParams.mfx.FrameInfo.Width;
542 windowParams.nHeight = m_mfxVideoParams.mfx.FrameInfo.Height;
543 }
544
545 windowParams.ncell = pParams->nWallCell;
546 windowParams.nAdapter = pParams->nWallMonitor;
547
548 windowParams.lpClassName = MSDK_STRING("Render Window Class");
549 windowParams.dwStyle = WS_OVERLAPPEDWINDOW;
550 windowParams.hWndParent = NULL;
551 windowParams.hMenu = NULL;
552 windowParams.hInstance = GetModuleHandle(NULL);
553 windowParams.lpParam = NULL;
554 windowParams.bFullScreen = FALSE;
555
556 sts = m_d3dRender.Init(windowParams);
557 MSDK_CHECK_STATUS(sts, "m_d3dRender.Init failed");
558
559 //setting videowall flag
560 m_bIsVideoWall = 0 != windowParams.nx;
561
562 #endif
563 return sts;
564 }
565
InitMfxParams(sInputParams * pParams)566 mfxStatus CDecodingPipeline::InitMfxParams(sInputParams* pParams) {
567 MSDK_CHECK_POINTER(m_pmfxDEC, MFX_ERR_NULL_PTR);
568 mfxStatus sts = MFX_ERR_NONE;
569 mfxU32& numViews = pParams->numViews;
570
571 if (pParams->bErrorReport) {
572 auto decErrorReport = m_mfxBS.AddExtBuffer<mfxExtDecodeErrorReport>();
573 MSDK_CHECK_POINTER(decErrorReport, MFX_ERR_MEMORY_ALLOC);
574 }
575
576 if (m_mfxVideoParams.mfx.CodecId == MFX_CODEC_VP9)
577 m_mfxVideoParams.mfx.EnableReallocRequest = MFX_CODINGOPTION_ON;
578
579 // try to find a sequence header in the stream
580 // if header is not found this function exits with error (e.g. if device was lost and there's no header in the remaining stream)
581 for (;;) {
582 // trying to find PicStruct information in AVI headers
583 if (m_mfxVideoParams.mfx.CodecId == MFX_CODEC_JPEG)
584 MJPEG_AVI_ParsePicStruct(&m_mfxBS);
585 if (pParams->bErrorReport) {
586 auto errorReport = m_mfxBS.GetExtBuffer<mfxExtDecodeErrorReport>();
587 MSDK_CHECK_POINTER(errorReport, MFX_ERR_NOT_INITIALIZED);
588
589 errorReport->ErrorTypes = 0;
590
591 // parse bit stream and fill mfx params
592 sts = m_pmfxDEC->DecodeHeader(&m_mfxBS, &m_mfxVideoParams);
593
594 PrintDecodeErrorReport(errorReport);
595 }
596 else {
597 // parse bit stream and fill mfx params
598 sts = m_pmfxDEC->DecodeHeader(&m_mfxBS, &m_mfxVideoParams);
599 }
600
601 if (!sts) {
602 m_bVppIsUsed = IsVppRequired(pParams);
603 }
604
605 if (MFX_ERR_MORE_DATA == sts) {
606 if (m_mfxBS.MaxLength == m_mfxBS.DataLength) {
607 m_mfxBS.Extend(m_mfxBS.MaxLength * 2);
608 }
609 // read a portion of data
610 totalBytesProcessed += m_mfxBS.DataOffset;
611 sts = m_FileReader->ReadNextFrame(&m_mfxBS);
612 MSDK_CHECK_STATUS(sts, "m_FileReader->ReadNextFrame failed");
613
614 continue;
615 }
616 else {
617 // Enter MVC mode
618 if (m_bIsMVC) {
619 // Check for attached external parameters - if we have them already,
620 // we don't need to attach them again
621 if (NULL != m_mfxVideoParams.ExtParam)
622 break;
623
624 auto mvcSeqDesc = m_mfxVideoParams.AddExtBuffer<mfxExtMVCSeqDesc>();
625 MSDK_CHECK_POINTER(mvcSeqDesc, MFX_ERR_MEMORY_ALLOC);
626
627 sts = m_pmfxDEC->DecodeHeader(&m_mfxBS, &m_mfxVideoParams);
628
629 if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) {
630 sts = AllocateExtMVCBuffers();
631
632 MSDK_CHECK_STATUS(sts, "AllocateExtMVCBuffers failed");
633 MSDK_CHECK_POINTER(m_mfxVideoParams.ExtParam, MFX_ERR_MEMORY_ALLOC);
634 continue;
635 }
636 }
637
638 // if input is interlaced JPEG stream
639 if (m_mfxBS.PicStruct == MFX_PICSTRUCT_FIELD_TFF ||
640 m_mfxBS.PicStruct == MFX_PICSTRUCT_FIELD_BFF) {
641 m_mfxVideoParams.mfx.FrameInfo.CropH *= 2;
642 m_mfxVideoParams.mfx.FrameInfo.Height =
643 MSDK_ALIGN16(m_mfxVideoParams.mfx.FrameInfo.CropH);
644 m_mfxVideoParams.mfx.FrameInfo.PicStruct = m_mfxBS.PicStruct;
645 }
646
647 switch (pParams->nRotation) {
648 case 0:
649 m_mfxVideoParams.mfx.Rotation = MFX_ROTATION_0;
650 break;
651 case 90:
652 m_mfxVideoParams.mfx.Rotation = MFX_ROTATION_90;
653 break;
654 case 180:
655 m_mfxVideoParams.mfx.Rotation = MFX_ROTATION_180;
656 break;
657 case 270:
658 m_mfxVideoParams.mfx.Rotation = MFX_ROTATION_270;
659 break;
660 default:
661 return MFX_ERR_UNSUPPORTED;
662 }
663
664 break;
665 }
666 }
667
668 // check DecodeHeader status
669 if (MFX_WRN_PARTIAL_ACCELERATION == sts) {
670 msdk_printf(MSDK_STRING("WARNING: partial acceleration\n"));
671 MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
672 }
673 MSDK_CHECK_STATUS(sts, "m_pmfxDEC->DecodeHeader failed");
674
675 if (!m_mfxVideoParams.mfx.FrameInfo.FrameRateExtN ||
676 !m_mfxVideoParams.mfx.FrameInfo.FrameRateExtD) {
677 msdk_printf(MSDK_STRING("pretending that stream is 30fps one\n"));
678 m_mfxVideoParams.mfx.FrameInfo.FrameRateExtN = 30;
679 m_mfxVideoParams.mfx.FrameInfo.FrameRateExtD = 1;
680 }
681 if (!m_mfxVideoParams.mfx.FrameInfo.AspectRatioW ||
682 !m_mfxVideoParams.mfx.FrameInfo.AspectRatioH) {
683 msdk_printf(MSDK_STRING("pretending that aspect ratio is 1:1\n"));
684 m_mfxVideoParams.mfx.FrameInfo.AspectRatioW = 1;
685 m_mfxVideoParams.mfx.FrameInfo.AspectRatioH = 1;
686 }
687
688 // Videoparams for RGB4 JPEG decoder output
689 if ((pParams->fourcc == MFX_FOURCC_RGB4) && (pParams->videoType == MFX_CODEC_JPEG)) {
690 m_mfxVideoParams.mfx.FrameInfo.FourCC = MFX_FOURCC_RGB4;
691 m_mfxVideoParams.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
692 if (pParams->chromaType == MFX_JPEG_COLORFORMAT_RGB) {
693 m_mfxVideoParams.mfx.JPEGColorFormat = pParams->chromaType;
694 }
695 }
696
697 /* Lets make final decision how to use VPP...*/
698 if (!m_bVppIsUsed) {
699 if ((m_mfxVideoParams.mfx.FrameInfo.CropW != pParams->Width && pParams->Width) ||
700 (m_mfxVideoParams.mfx.FrameInfo.CropH != pParams->Height && pParams->Height) ||
701 (pParams->nDecoderPostProcessing && pParams->videoType == MFX_CODEC_AVC) ||
702 (pParams->nDecoderPostProcessing && pParams->videoType == MFX_CODEC_HEVC) ||
703 (pParams->nDecoderPostProcessing && pParams->videoType == MFX_CODEC_JPEG &&
704 pParams->fourcc == MFX_FOURCC_RGB4 &&
705 // No need to use decoder's post processing for decoding of JPEG with RGB 4:4:4
706 // to MFX_FOURCC_RGB4, because this decoding is done in one step
707 // In every other case, color conversion is requred, so try decoder's post processing.
708 !(m_mfxVideoParams.mfx.JPEGColorFormat == MFX_JPEG_COLORFORMAT_RGB &&
709 m_mfxVideoParams.mfx.FrameInfo.ChromaFormat == MFX_CHROMAFORMAT_YUV444))) {
710 /* By default VPP used for resize */
711 m_bVppIsUsed = true;
712 /* But... lets try to use decoder's post processing */
713 if (((MODE_DECODER_POSTPROC_AUTO == pParams->nDecoderPostProcessing) ||
714 (MODE_DECODER_POSTPROC_FORCE == pParams->nDecoderPostProcessing)) &&
715 (MFX_CODEC_AVC == m_mfxVideoParams.mfx.CodecId ||
716 MFX_CODEC_JPEG == m_mfxVideoParams.mfx.CodecId ||
717 MFX_CODEC_HEVC == m_mfxVideoParams.mfx.CodecId ||
718 MFX_CODEC_VP9 == m_mfxVideoParams.mfx.CodecId ||
719 MFX_CODEC_AV1 == m_mfxVideoParams.mfx.CodecId) &&
720 (MFX_PICSTRUCT_PROGRESSIVE ==
721 m_mfxVideoParams.mfx.FrameInfo.PicStruct)) /* ...And only for progressive!*/
722 { /* it is possible to use decoder's post-processing */
723
724 // JPEG only suppoted w/o resize, so use W/H from DecodeHeader(), if they are not set
725 if (MFX_CODEC_JPEG == m_mfxVideoParams.mfx.CodecId &&
726 (!pParams->Width || !pParams->Height)) {
727 pParams->Width = m_mfxVideoParams.mfx.FrameInfo.CropW;
728 pParams->Height = m_mfxVideoParams.mfx.FrameInfo.CropH;
729 }
730
731 m_bVppIsUsed = false;
732 auto decPostProcessing = m_mfxVideoParams.AddExtBuffer<mfxExtDecVideoProcessing>();
733 MSDK_CHECK_POINTER(decPostProcessing, MFX_ERR_MEMORY_ALLOC);
734
735 decPostProcessing->In.CropX = 0;
736 decPostProcessing->In.CropY = 0;
737 decPostProcessing->In.CropW = m_mfxVideoParams.mfx.FrameInfo.CropW;
738 decPostProcessing->In.CropH = m_mfxVideoParams.mfx.FrameInfo.CropH;
739
740 decPostProcessing->Out.FourCC = m_mfxVideoParams.mfx.FrameInfo.FourCC;
741 decPostProcessing->Out.ChromaFormat = m_mfxVideoParams.mfx.FrameInfo.ChromaFormat;
742
743 if (pParams->videoType == MFX_CODEC_AVC || pParams->videoType == MFX_CODEC_HEVC) {
744 switch (pParams->fourcc) {
745 case MFX_FOURCC_RGB4:
746 decPostProcessing->Out.FourCC = MFX_FOURCC_RGB4;
747 decPostProcessing->Out.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
748 break;
749
750 case MFX_FOURCC_NV12:
751 decPostProcessing->Out.FourCC = MFX_FOURCC_NV12;
752 decPostProcessing->Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
753 break;
754
755 case MFX_FOURCC_P010:
756 decPostProcessing->Out.FourCC = MFX_FOURCC_P010;
757 decPostProcessing->Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
758 break;
759
760 case MFX_FOURCC_P016:
761 decPostProcessing->Out.FourCC = MFX_FOURCC_P016;
762 decPostProcessing->Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
763 break;
764
765 case MFX_FOURCC_YUY2:
766 decPostProcessing->Out.FourCC = MFX_FOURCC_YUY2;
767 decPostProcessing->Out.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
768 break;
769
770 case MFX_FOURCC_Y210:
771 decPostProcessing->Out.FourCC = MFX_FOURCC_Y210;
772 decPostProcessing->Out.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
773 break;
774
775 case MFX_FOURCC_Y216:
776 decPostProcessing->Out.FourCC = MFX_FOURCC_Y216;
777 decPostProcessing->Out.ChromaFormat = MFX_CHROMAFORMAT_YUV422;
778 break;
779
780 case MFX_FOURCC_AYUV:
781 decPostProcessing->Out.FourCC = MFX_FOURCC_AYUV;
782 decPostProcessing->Out.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
783 break;
784
785 case MFX_FOURCC_Y410:
786 decPostProcessing->Out.FourCC = MFX_FOURCC_Y410;
787 decPostProcessing->Out.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
788 break;
789
790 case MFX_FOURCC_Y416:
791 decPostProcessing->Out.FourCC = MFX_FOURCC_Y416;
792 decPostProcessing->Out.ChromaFormat = MFX_CHROMAFORMAT_YUV444;
793 break;
794
795 default:
796 break;
797 }
798 }
799 decPostProcessing->Out.Width = MSDK_ALIGN16(pParams->Width);
800 decPostProcessing->Out.Height = MSDK_ALIGN16(pParams->Height);
801 decPostProcessing->Out.CropX = 0;
802 decPostProcessing->Out.CropY = 0;
803 decPostProcessing->Out.CropW = pParams->Width;
804 decPostProcessing->Out.CropH = pParams->Height;
805
806 msdk_printf(MSDK_STRING("Decoder's post-processing is used for resizing\n"));
807 }
808 /* POSTPROC_FORCE */
809 if (MODE_DECODER_POSTPROC_FORCE == pParams->nDecoderPostProcessing && m_bVppIsUsed) {
810 /* it is impossible to use decoder's post-processing */
811 msdk_printf(MSDK_STRING(
812 "ERROR: decoder postprocessing (-dec_postproc forced) cannot resize this stream!\n"));
813 return MFX_ERR_UNSUPPORTED;
814 }
815 if ((m_bVppIsUsed) && (MODE_DECODER_POSTPROC_AUTO == pParams->nDecoderPostProcessing))
816 msdk_printf(MSDK_STRING(
817 "Decoder post-processing is unsupported for this stream, VPP is used\n"));
818 }
819 }
820
821 // If MVC mode we need to detect number of views in stream
822 if (m_bIsMVC) {
823 auto sequenceBuffer = m_mfxVideoParams.GetExtBuffer<mfxExtMVCSeqDesc>();
824 MSDK_CHECK_POINTER(sequenceBuffer, MFX_ERR_INVALID_VIDEO_PARAM);
825
826 mfxU32 i = 0;
827 numViews = 0;
828 for (i = 0; i < sequenceBuffer->NumView; ++i) {
829 /* Some MVC streams can contain different information about
830 number of views and view IDs, e.x. numVews = 2
831 and ViewId[0, 1] = 0, 2 instead of ViewId[0, 1] = 0, 1.
832 numViews should be equal (max(ViewId[i]) + 1)
833 to prevent crashes during output files writing */
834 if (sequenceBuffer->View[i].ViewId >= numViews)
835 numViews = sequenceBuffer->View[i].ViewId + 1;
836 }
837 }
838 else {
839 numViews = 1;
840 }
841
842 // specify memory type
843 if (!m_bVppIsUsed)
844 m_mfxVideoParams.IOPattern =
845 (mfxU16)(m_memType != SYSTEM_MEMORY ? MFX_IOPATTERN_OUT_VIDEO_MEMORY
846 : MFX_IOPATTERN_OUT_SYSTEM_MEMORY);
847 else
848 m_mfxVideoParams.IOPattern = (mfxU16)(pParams->bUseHWLib ? MFX_IOPATTERN_OUT_VIDEO_MEMORY
849 : MFX_IOPATTERN_OUT_SYSTEM_MEMORY);
850
851 m_mfxVideoParams.AsyncDepth = pParams->nAsyncDepth;
852
853 if (m_mfxVideoParams.mfx.CodecId == MFX_CODEC_AV1)
854 m_mfxVideoParams.mfx.FilmGrain =
855 pParams->bDisableFilmGrain ? 0 : m_mfxVideoParams.mfx.FilmGrain;
856
857 return MFX_ERR_NONE;
858 }
859
InitVppFilters()860 mfxStatus CDecodingPipeline::InitVppFilters() {
861 auto vppExtParams = m_mfxVppVideoParams.AddExtBuffer<mfxExtVPPDoNotUse>();
862 MSDK_CHECK_POINTER(vppExtParams, MFX_ERR_MEMORY_ALLOC);
863
864 vppExtParams->NumAlg = 4;
865
866 /* In case of Reset() this code called twice!
867 * But required to have only one allocation to prevent memleaks
868 * Deallocation done in Close() */
869 if (NULL == vppExtParams->AlgList)
870 vppExtParams->AlgList = new mfxU32[vppExtParams->NumAlg];
871
872 if (!vppExtParams->AlgList)
873 return MFX_ERR_NULL_PTR;
874
875 vppExtParams->AlgList[0] = MFX_EXTBUFF_VPP_DENOISE; // turn off denoising (on by default)
876 vppExtParams->AlgList[1] =
877 MFX_EXTBUFF_VPP_SCENE_ANALYSIS; // turn off scene analysis (on by default)
878 vppExtParams->AlgList[2] =
879 MFX_EXTBUFF_VPP_DETAIL; // turn off detail enhancement (on by default)
880 vppExtParams->AlgList[3] =
881 MFX_EXTBUFF_VPP_PROCAMP; // turn off processing amplified (on by default)
882
883 if (m_diMode) {
884 auto vppDi = m_mfxVppVideoParams.AddExtBuffer<mfxExtVPPDeinterlacing>();
885 MSDK_CHECK_POINTER(vppDi, MFX_ERR_MEMORY_ALLOC);
886
887 vppDi->Mode = m_diMode;
888 }
889
890 return MFX_ERR_NONE;
891 }
892
InitVppParams()893 mfxStatus CDecodingPipeline::InitVppParams() {
894 m_mfxVppVideoParams.IOPattern =
895 (mfxU16)(m_bDecOutSysmem ? MFX_IOPATTERN_IN_SYSTEM_MEMORY : MFX_IOPATTERN_IN_VIDEO_MEMORY);
896
897 m_mfxVppVideoParams.IOPattern |= (m_memType != SYSTEM_MEMORY) ? MFX_IOPATTERN_OUT_VIDEO_MEMORY
898 : MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
899
900 MSDK_MEMCPY_VAR(m_mfxVppVideoParams.vpp.In,
901 &m_mfxVideoParams.mfx.FrameInfo,
902 sizeof(mfxFrameInfo));
903 MSDK_MEMCPY_VAR(m_mfxVppVideoParams.vpp.Out, &m_mfxVppVideoParams.vpp.In, sizeof(mfxFrameInfo));
904
905 if (m_fourcc) {
906 m_mfxVppVideoParams.vpp.Out.FourCC = m_fourcc;
907 }
908
909 if (m_vppOutWidth && m_vppOutHeight) {
910 m_mfxVppVideoParams.vpp.Out.CropW = m_vppOutWidth;
911 m_mfxVppVideoParams.vpp.Out.Width = MSDK_ALIGN16(m_vppOutWidth);
912 m_mfxVppVideoParams.vpp.Out.CropH = m_vppOutHeight;
913 m_mfxVppVideoParams.vpp.Out.Height =
914 (MFX_PICSTRUCT_PROGRESSIVE == m_mfxVppVideoParams.vpp.Out.PicStruct)
915 ? MSDK_ALIGN16(m_vppOutHeight)
916 : MSDK_ALIGN32(m_vppOutHeight);
917 }
918
919 m_mfxVppVideoParams.AsyncDepth = m_mfxVideoParams.AsyncDepth;
920
921 m_VppSurfaceExtParams.clear();
922 if (m_bVppFullColorRange) {
923 //Let MSDK figure out the transfer matrix to use
924 m_VppVideoSignalInfo.TransferMatrix = MFX_TRANSFERMATRIX_UNKNOWN;
925 m_VppVideoSignalInfo.NominalRange = MFX_NOMINALRANGE_0_255;
926
927 m_VppSurfaceExtParams.push_back((mfxExtBuffer*)&m_VppVideoSignalInfo);
928 }
929
930 // P010 video surfaces should be shifted
931 if (m_memType != SYSTEM_MEMORY && (m_mfxVppVideoParams.vpp.Out.FourCC == MFX_FOURCC_P010 ||
932 m_mfxVppVideoParams.vpp.Out.FourCC == MFX_FOURCC_Y210 ||
933 m_mfxVppVideoParams.vpp.Out.FourCC == MFX_FOURCC_P016 ||
934 m_mfxVppVideoParams.vpp.Out.FourCC == MFX_FOURCC_Y216 ||
935 m_mfxVppVideoParams.vpp.Out.FourCC == MFX_FOURCC_Y416)) {
936 m_mfxVppVideoParams.vpp.Out.Shift = 1;
937 }
938
939 return MFX_ERR_NONE;
940 }
941
CreateHWDevice()942 mfxStatus CDecodingPipeline::CreateHWDevice() {
943 #if D3D_SURFACES_SUPPORT
944 mfxStatus sts = MFX_ERR_NONE;
945
946 HWND window = NULL;
947 bool render = (m_eWorkMode == MODE_RENDERING);
948
949 if (render) {
950 window = (D3D11_MEMORY == m_memType) ? NULL : m_d3dRender.GetWindowHandle();
951 }
952
953 #if MFX_D3D11_SUPPORT
954 if (D3D11_MEMORY == m_memType)
955 m_hwdev = new CD3D11Device();
956 else
957 #endif // #if MFX_D3D11_SUPPORT
958 m_hwdev = new CD3D9Device();
959
960 if (NULL == m_hwdev)
961 return MFX_ERR_MEMORY_ALLOC;
962
963 sts = m_hwdev->Init(window,
964 render ? (m_bIsMVC ? 2 : 1) : 0,
965 MSDKAdapter::GetNumber(m_pLoader.get()));
966 MSDK_CHECK_STATUS(sts, "m_hwdev->Init failed");
967
968 if (render)
969 m_d3dRender.SetHWDevice(m_hwdev);
970 #elif LIBVA_SUPPORT
971 mfxStatus sts = MFX_ERR_NONE;
972
973 m_hwdev = CreateVAAPIDevice(m_strDevicePath, m_libvaBackend);
974
975 if (NULL == m_hwdev) {
976 return MFX_ERR_MEMORY_ALLOC;
977 }
978
979 sts = m_hwdev->Init(&m_monitorType,
980 (m_eWorkMode == MODE_RENDERING) ? 1 : 0,
981 MSDKAdapter::GetNumber(m_pLoader.get()));
982 MSDK_CHECK_STATUS(sts, "m_hwdev->Init failed");
983
984 #if defined(LIBVA_WAYLAND_SUPPORT)
985 if (m_eWorkMode == MODE_RENDERING && m_libvaBackend == MFX_LIBVA_WAYLAND) {
986 CVAAPIDeviceWayland* w_dev = dynamic_cast<CVAAPIDeviceWayland*>(m_hwdev);
987 if (!w_dev) {
988 MSDK_CHECK_STATUS(MFX_ERR_DEVICE_FAILED, "Failed to reach Wayland VAAPI device");
989 }
990 Wayland* wld = w_dev->GetWaylandHandle();
991 if (!wld) {
992 MSDK_CHECK_STATUS(MFX_ERR_DEVICE_FAILED, "Failed to reach Wayland VAAPI device");
993 }
994
995 wld->SetRenderWinPos(m_nRenderWinX, m_nRenderWinY);
996 wld->SetPerfMode(m_bPerfMode);
997 }
998 #endif //LIBVA_WAYLAND_SUPPORT
999
1000 #endif
1001 return MFX_ERR_NONE;
1002 }
1003
ResetDevice()1004 mfxStatus CDecodingPipeline::ResetDevice() {
1005 if (m_hwdev)
1006 return m_hwdev->Reset();
1007
1008 return CreateHWDevice();
1009 }
1010
AllocFrames()1011 mfxStatus CDecodingPipeline::AllocFrames() {
1012 MSDK_CHECK_POINTER(m_pmfxDEC, MFX_ERR_NULL_PTR);
1013
1014 mfxStatus sts = MFX_ERR_NONE;
1015
1016 mfxFrameAllocRequest Request;
1017 mfxFrameAllocRequest VppRequest[2];
1018
1019 mfxU16 nSurfNum = 0; // number of surfaces for decoder
1020 mfxU16 nVppSurfNum = 0; // number of surfaces for vpp
1021
1022 nSurfNum = std::max(0, 4);
1023
1024 MSDK_ZERO_MEMORY(Request);
1025
1026 MSDK_ZERO_MEMORY(VppRequest[0]);
1027 MSDK_ZERO_MEMORY(VppRequest[1]);
1028
1029 sts = m_pmfxDEC->Query(&m_mfxVideoParams, &m_mfxVideoParams);
1030 MSDK_IGNORE_MFX_STS(sts, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
1031 MSDK_CHECK_STATUS(sts, "m_pmfxDEC->Query failed");
1032
1033 // calculate number of surfaces required for decoder
1034 sts = m_pmfxDEC->QueryIOSurf(&m_mfxVideoParams, &Request);
1035 if (MFX_WRN_PARTIAL_ACCELERATION == sts) {
1036 msdk_printf(MSDK_STRING("WARNING: partial acceleration\n"));
1037 MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
1038 m_bDecOutSysmem = true;
1039 }
1040 MSDK_CHECK_STATUS(sts, "m_pmfxDEC->QueryIOSurf failed");
1041
1042 if (m_eWorkMode == MODE_RENDERING) {
1043 // Add surfaces for rendering smoothness
1044 Request.NumFrameSuggested += m_nMaxFps / 3;
1045 }
1046
1047 if (m_bVppIsUsed) {
1048 // respecify memory type between Decoder and VPP
1049 m_mfxVideoParams.IOPattern = (mfxU16)(m_bDecOutSysmem ? MFX_IOPATTERN_OUT_SYSTEM_MEMORY
1050 : MFX_IOPATTERN_OUT_VIDEO_MEMORY);
1051
1052 // recalculate number of surfaces required for decoder
1053 sts = m_pmfxDEC->QueryIOSurf(&m_mfxVideoParams, &Request);
1054 MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
1055 MSDK_CHECK_STATUS(sts, "m_pmfxDEC->QueryIOSurf failed");
1056
1057 sts = InitVppParams();
1058 MSDK_CHECK_STATUS(sts, "InitVppParams failed");
1059
1060 sts = m_pmfxVPP->Query(&m_mfxVppVideoParams, &m_mfxVppVideoParams);
1061 MSDK_IGNORE_MFX_STS(sts, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
1062 MSDK_CHECK_STATUS(sts, "m_pmfxVPP->Query failed");
1063
1064 // VppRequest[0] for input frames request, VppRequest[1] for output frames request
1065 sts = m_pmfxVPP->QueryIOSurf(&m_mfxVppVideoParams, VppRequest);
1066 if (MFX_WRN_PARTIAL_ACCELERATION == sts) {
1067 msdk_printf(MSDK_STRING("WARNING: partial acceleration\n"));
1068 MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
1069 }
1070 MSDK_CHECK_STATUS(sts, "m_pmfxVPP->QueryIOSurf failed");
1071
1072 if ((VppRequest[0].NumFrameSuggested < m_mfxVppVideoParams.AsyncDepth) ||
1073 (VppRequest[1].NumFrameSuggested < m_mfxVppVideoParams.AsyncDepth))
1074 return MFX_ERR_MEMORY_ALLOC;
1075
1076 // If surfaces are shared by 2 components, c1 and c2. NumSurf = c1_out + c2_in - AsyncDepth + 1
1077 // The number of surfaces shared by vpp input and decode output
1078 nSurfNum = Request.NumFrameSuggested + VppRequest[0].NumFrameSuggested -
1079 m_mfxVideoParams.AsyncDepth + 1;
1080
1081 // The number of surfaces for vpp output
1082 // Need to add one more surface in render mode if AsyncDepth == 1
1083 nVppSurfNum = VppRequest[1].NumFrameSuggested +
1084 (m_eWorkMode == MODE_RENDERING ? m_mfxVideoParams.AsyncDepth == 1 : 0);
1085
1086 // prepare allocation request
1087 Request.NumFrameSuggested = Request.NumFrameMin = nSurfNum;
1088
1089 // surfaces are shared between vpp input and decode output
1090 Request.Type |=
1091 MFX_MEMTYPE_EXTERNAL_FRAME | MFX_MEMTYPE_FROM_DECODE | MFX_MEMTYPE_FROM_VPPIN;
1092 }
1093
1094 if ((Request.NumFrameSuggested < m_mfxVideoParams.AsyncDepth) &&
1095 (m_impl & MFX_IMPL_HARDWARE_ANY))
1096 return MFX_ERR_MEMORY_ALLOC;
1097
1098 Request.Type |=
1099 (m_bDecOutSysmem) ? MFX_MEMTYPE_SYSTEM_MEMORY : MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
1100
1101 #ifdef LIBVA_SUPPORT
1102 if (!m_bVppIsUsed && (m_export_mode != vaapiAllocatorParams::DONOT_EXPORT)) {
1103 Request.Type |= MFX_MEMTYPE_EXPORT_FRAME;
1104 }
1105 #endif
1106
1107 // alloc frames for decoder
1108 sts = m_pGeneralAllocator->Alloc(m_pGeneralAllocator->pthis, &Request, &m_mfxResponse);
1109 MSDK_CHECK_STATUS(sts, "m_pGeneralAllocator->Alloc failed");
1110
1111 if (m_bVppIsUsed) {
1112 // alloc frames for VPP
1113 #ifdef LIBVA_SUPPORT
1114 if (m_export_mode != vaapiAllocatorParams::DONOT_EXPORT) {
1115 VppRequest[1].Type |= MFX_MEMTYPE_EXPORT_FRAME;
1116 }
1117 #endif
1118 VppRequest[1].NumFrameSuggested = VppRequest[1].NumFrameMin = nVppSurfNum;
1119 MSDK_MEMCPY_VAR(VppRequest[1].Info, &(m_mfxVppVideoParams.vpp.Out), sizeof(mfxFrameInfo));
1120
1121 sts = m_pGeneralAllocator->Alloc(m_pGeneralAllocator->pthis,
1122 &VppRequest[1],
1123 &m_mfxVppResponse);
1124 MSDK_CHECK_STATUS(sts, "m_pGeneralAllocator->Alloc failed");
1125
1126 // prepare mfxFrameSurface1 array for decoder
1127 nVppSurfNum = m_mfxVppResponse.NumFrameActual;
1128
1129 // AllocVppBuffers should call before AllocBuffers to set the value of m_OutputSurfacesNumber
1130 sts = AllocVppBuffers(nVppSurfNum);
1131 MSDK_CHECK_STATUS(sts, "AllocVppBuffers failed");
1132 }
1133
1134 // prepare mfxFrameSurface1 array for decoder
1135 nSurfNum = m_mfxResponse.NumFrameActual;
1136
1137 sts = AllocBuffers(nSurfNum);
1138 MSDK_CHECK_STATUS(sts, "AllocBuffers failed");
1139
1140 for (int i = 0; i < nSurfNum; i++) {
1141 // initating each frame:
1142 MSDK_MEMCPY_VAR(m_pSurfaces[i].frame.Info, &(Request.Info), sizeof(mfxFrameInfo));
1143 m_pSurfaces[i].frame.Data.MemType = Request.Type;
1144 if (m_bExternalAlloc) {
1145 m_pSurfaces[i].frame.Data.MemId = m_mfxResponse.mids[i];
1146 if (m_bVppFullColorRange) {
1147 m_pSurfaces[i].frame.Data.ExtParam = &m_VppSurfaceExtParams[0];
1148 m_pSurfaces[i].frame.Data.NumExtParam = (mfxU16)m_VppSurfaceExtParams.size();
1149 }
1150 }
1151 }
1152
1153 // prepare mfxFrameSurface1 array for VPP
1154 for (int i = 0; i < nVppSurfNum; i++) {
1155 MSDK_MEMCPY_VAR(m_pVppSurfaces[i].frame.Info, &(VppRequest[1].Info), sizeof(mfxFrameInfo));
1156 if (m_bExternalAlloc) {
1157 m_pVppSurfaces[i].frame.Data.MemId = m_mfxVppResponse.mids[i];
1158 if (m_bVppFullColorRange) {
1159 m_pVppSurfaces[i].frame.Data.ExtParam = &m_VppSurfaceExtParams[0];
1160 m_pVppSurfaces[i].frame.Data.NumExtParam = (mfxU16)m_VppSurfaceExtParams.size();
1161 }
1162 }
1163 }
1164 return MFX_ERR_NONE;
1165 }
1166
ReallocCurrentSurface(const mfxFrameInfo & info)1167 mfxStatus CDecodingPipeline::ReallocCurrentSurface(const mfxFrameInfo& info) {
1168 mfxStatus sts = MFX_ERR_NONE;
1169 mfxMemId inMid = nullptr;
1170 mfxMemId outMid = nullptr;
1171
1172 if (!m_pGeneralAllocator)
1173 return MFX_ERR_MEMORY_ALLOC;
1174
1175 m_pCurrentFreeSurface->frame.Info.CropW = info.CropW;
1176 m_pCurrentFreeSurface->frame.Info.CropH = info.CropH;
1177 m_mfxVideoParams.mfx.FrameInfo.Width =
1178 MSDK_ALIGN16(std::max(info.Width, m_mfxVideoParams.mfx.FrameInfo.Width));
1179 m_mfxVideoParams.mfx.FrameInfo.Height =
1180 MSDK_ALIGN16(std::max(info.Height, m_mfxVideoParams.mfx.FrameInfo.Height));
1181 m_pCurrentFreeSurface->frame.Info.Width = m_mfxVideoParams.mfx.FrameInfo.Width;
1182 m_pCurrentFreeSurface->frame.Info.Height = m_mfxVideoParams.mfx.FrameInfo.Height;
1183
1184 inMid = m_pCurrentFreeSurface->frame.Data.MemId;
1185
1186 sts = m_pGeneralAllocator->ReallocFrame(inMid,
1187 &m_pCurrentFreeSurface->frame.Info,
1188 m_pCurrentFreeSurface->frame.Data.MemType,
1189 &outMid);
1190 if (MFX_ERR_NONE == sts)
1191 m_pCurrentFreeSurface->frame.Data.MemId = outMid;
1192
1193 return sts;
1194 }
1195
CreateAllocator()1196 mfxStatus CDecodingPipeline::CreateAllocator() {
1197 mfxStatus sts = MFX_ERR_NONE;
1198
1199 m_pGeneralAllocator = new GeneralAllocator();
1200 if (m_memType != SYSTEM_MEMORY || !m_bDecOutSysmem) {
1201 #if D3D_SURFACES_SUPPORT
1202 mfxHDL hdl = NULL;
1203 mfxHandleType hdl_t =
1204 #if MFX_D3D11_SUPPORT
1205 D3D11_MEMORY == m_memType ? MFX_HANDLE_D3D11_DEVICE :
1206 #endif // #if MFX_D3D11_SUPPORT
1207 MFX_HANDLE_D3D9_DEVICE_MANAGER;
1208
1209 sts = m_hwdev->GetHandle(hdl_t, &hdl);
1210 MSDK_CHECK_STATUS(sts, "m_hwdev->GetHandle failed");
1211
1212 // create D3D allocator
1213 #if MFX_D3D11_SUPPORT
1214 if (D3D11_MEMORY == m_memType) {
1215 D3D11AllocatorParams* pd3dAllocParams = new D3D11AllocatorParams;
1216 MSDK_CHECK_POINTER(pd3dAllocParams, MFX_ERR_MEMORY_ALLOC);
1217 pd3dAllocParams->pDevice = reinterpret_cast<ID3D11Device*>(hdl);
1218
1219 m_pmfxAllocatorParams = pd3dAllocParams;
1220 }
1221 else
1222 #endif // #if MFX_D3D11_SUPPORT
1223 {
1224 D3DAllocatorParams* pd3dAllocParams = new D3DAllocatorParams;
1225 MSDK_CHECK_POINTER(pd3dAllocParams, MFX_ERR_MEMORY_ALLOC);
1226 pd3dAllocParams->pManager = reinterpret_cast<IDirect3DDeviceManager9*>(hdl);
1227
1228 m_pmfxAllocatorParams = pd3dAllocParams;
1229 }
1230
1231 /* In case of video memory we must provide MediaSDK with external allocator
1232 thus we demonstrate "external allocator" usage model.
1233 Call SetAllocator to pass allocator to mediasdk */
1234 sts = m_mfxSession.SetFrameAllocator(m_pGeneralAllocator);
1235 MSDK_CHECK_STATUS(sts, "m_mfxSession.SetFrameAllocator failed");
1236
1237 m_bExternalAlloc = true;
1238 #elif LIBVA_SUPPORT
1239 VADisplay va_dpy = NULL;
1240 sts = m_hwdev->GetHandle(MFX_HANDLE_VA_DISPLAY, (mfxHDL*)&va_dpy);
1241 MSDK_CHECK_STATUS(sts, "m_hwdev->GetHandle failed");
1242
1243 vaapiAllocatorParams* p_vaapiAllocParams = new vaapiAllocatorParams;
1244 MSDK_CHECK_POINTER(p_vaapiAllocParams, MFX_ERR_MEMORY_ALLOC);
1245
1246 p_vaapiAllocParams->m_dpy = va_dpy;
1247 if (m_eWorkMode == MODE_RENDERING) {
1248 if (m_libvaBackend == MFX_LIBVA_DRM_MODESET) {
1249 #if defined(LIBVA_DRM_SUPPORT)
1250 CVAAPIDeviceDRM* drmdev = dynamic_cast<CVAAPIDeviceDRM*>(m_hwdev);
1251 p_vaapiAllocParams->m_export_mode = vaapiAllocatorParams::CUSTOM_FLINK;
1252 p_vaapiAllocParams->m_exporter =
1253 dynamic_cast<vaapiAllocatorParams::Exporter*>(drmdev->getRenderer());
1254 #endif
1255 }
1256 else if (m_libvaBackend == MFX_LIBVA_WAYLAND || m_libvaBackend == MFX_LIBVA_X11) {
1257 p_vaapiAllocParams->m_export_mode = vaapiAllocatorParams::PRIME;
1258 }
1259 }
1260 m_export_mode = p_vaapiAllocParams->m_export_mode;
1261 m_pmfxAllocatorParams = p_vaapiAllocParams;
1262
1263 /* In case of video memory we must provide MediaSDK with external allocator
1264 thus we demonstrate "external allocator" usage model.
1265 Call SetAllocator to pass allocator to mediasdk */
1266 sts = m_mfxSession.SetFrameAllocator(m_pGeneralAllocator);
1267 MSDK_CHECK_STATUS(sts, "m_mfxSession.SetFrameAllocator failed");
1268
1269 m_bExternalAlloc = true;
1270 #endif
1271 }
1272 else {
1273 sts = m_mfxSession.SetFrameAllocator(m_pGeneralAllocator);
1274 MSDK_CHECK_STATUS(sts, "m_mfxSession.SetFrameAllocator failed");
1275 m_bExternalAlloc = true;
1276 }
1277
1278 // initialize memory allocator
1279 sts = m_pGeneralAllocator->Init(m_pmfxAllocatorParams);
1280 MSDK_CHECK_STATUS(sts, "m_pGeneralAllocator->Init failed");
1281
1282 return MFX_ERR_NONE;
1283 }
1284
DeleteFrames()1285 void CDecodingPipeline::DeleteFrames() {
1286 FreeBuffers();
1287
1288 m_pCurrentFreeSurface = NULL;
1289 MSDK_SAFE_FREE(m_pCurrentFreeOutputSurface);
1290
1291 m_pCurrentFreeVppSurface = NULL;
1292
1293 // delete frames
1294 if (m_pGeneralAllocator) {
1295 m_pGeneralAllocator->Free(m_pGeneralAllocator->pthis, &m_mfxResponse);
1296 }
1297
1298 return;
1299 }
1300
DeleteAllocator()1301 void CDecodingPipeline::DeleteAllocator() {
1302 // delete allocator
1303 MSDK_SAFE_DELETE(m_pGeneralAllocator);
1304 MSDK_SAFE_DELETE(m_pmfxAllocatorParams);
1305 MSDK_SAFE_DELETE(m_hwdev);
1306 }
1307
SetMultiView()1308 void CDecodingPipeline::SetMultiView() {
1309 m_FileWriter.SetMultiView();
1310 m_bIsMVC = true;
1311 }
1312
AllocateExtMVCBuffers()1313 mfxStatus CDecodingPipeline::AllocateExtMVCBuffers() {
1314 mfxU32 i;
1315
1316 auto mvcBuffer = m_mfxVideoParams.GetExtBuffer<mfxExtMVCSeqDesc>();
1317 MSDK_CHECK_POINTER(mvcBuffer, MFX_ERR_MEMORY_ALLOC);
1318
1319 mvcBuffer->View = new mfxMVCViewDependency[mvcBuffer->NumView];
1320 MSDK_CHECK_POINTER(mvcBuffer->View, MFX_ERR_MEMORY_ALLOC);
1321 for (i = 0; i < mvcBuffer->NumView; ++i) {
1322 MSDK_ZERO_MEMORY(mvcBuffer->View[i]);
1323 }
1324 mvcBuffer->NumViewAlloc = mvcBuffer->NumView;
1325
1326 mvcBuffer->ViewId = new mfxU16[mvcBuffer->NumViewId];
1327 MSDK_CHECK_POINTER(mvcBuffer->ViewId, MFX_ERR_MEMORY_ALLOC);
1328 for (i = 0; i < mvcBuffer->NumViewId; ++i) {
1329 MSDK_ZERO_MEMORY(mvcBuffer->ViewId[i]);
1330 }
1331 mvcBuffer->NumViewIdAlloc = mvcBuffer->NumViewId;
1332
1333 mvcBuffer->OP = new mfxMVCOperationPoint[mvcBuffer->NumOP];
1334 MSDK_CHECK_POINTER(mvcBuffer->OP, MFX_ERR_MEMORY_ALLOC);
1335 for (i = 0; i < mvcBuffer->NumOP; ++i) {
1336 MSDK_ZERO_MEMORY(mvcBuffer->OP[i]);
1337 }
1338 mvcBuffer->NumOPAlloc = mvcBuffer->NumOP;
1339
1340 return MFX_ERR_NONE;
1341 }
1342
DeallocateExtMVCBuffers()1343 void CDecodingPipeline::DeallocateExtMVCBuffers() {
1344 auto mvcBuffer = m_mfxVideoParams.GetExtBuffer<mfxExtMVCSeqDesc>();
1345 if (mvcBuffer) {
1346 MSDK_SAFE_DELETE_ARRAY(mvcBuffer->View);
1347 MSDK_SAFE_DELETE_ARRAY(mvcBuffer->ViewId);
1348 MSDK_SAFE_DELETE_ARRAY(mvcBuffer->OP);
1349 }
1350 }
1351
ResetDecoder(sInputParams * pParams)1352 mfxStatus CDecodingPipeline::ResetDecoder(sInputParams* pParams) {
1353 mfxStatus sts = MFX_ERR_NONE;
1354
1355 // close decoder
1356 sts = m_pmfxDEC->Close();
1357 MSDK_IGNORE_MFX_STS(sts, MFX_ERR_NOT_INITIALIZED);
1358 MSDK_CHECK_STATUS(sts, "m_pmfxDEC->Close failed");
1359
1360 // close VPP
1361 if (m_pmfxVPP) {
1362 sts = m_pmfxVPP->Close();
1363 MSDK_IGNORE_MFX_STS(sts, MFX_ERR_NOT_INITIALIZED);
1364 MSDK_CHECK_STATUS(sts, "m_pmfxVPP->Close failed");
1365 }
1366
1367 // free allocated frames
1368 DeleteFrames();
1369
1370 // initialize parameters with values from parsed header
1371 sts = InitMfxParams(pParams);
1372 MSDK_CHECK_STATUS(sts, "InitMfxParams failed");
1373
1374 // in case of HW accelerated decode frames must be allocated prior to decoder initialization
1375 sts = AllocFrames();
1376 MSDK_CHECK_STATUS(sts, "AllocFrames failed");
1377
1378 // init decoder
1379 sts = m_pmfxDEC->Init(&m_mfxVideoParams);
1380 if (MFX_WRN_PARTIAL_ACCELERATION == sts) {
1381 msdk_printf(MSDK_STRING("WARNING: partial acceleration\n"));
1382 MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
1383 }
1384 MSDK_CHECK_STATUS(sts, "m_pmfxDEC->Init failed");
1385
1386 if (m_pmfxVPP) {
1387 if (m_diMode)
1388 m_mfxVppVideoParams.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
1389
1390 if (pParams->ScalingMode) {
1391 auto par = m_mfxVppVideoParams.AddExtBuffer<mfxExtVPPScaling>();
1392 par->ScalingMode = pParams->ScalingMode;
1393 }
1394
1395 sts = m_pmfxVPP->Init(&m_mfxVppVideoParams);
1396 if (MFX_WRN_PARTIAL_ACCELERATION == sts) {
1397 msdk_printf(MSDK_STRING("WARNING: partial acceleration\n"));
1398 MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
1399 }
1400 MSDK_CHECK_STATUS(sts, "m_pmfxVPP->Init failed");
1401 }
1402
1403 return MFX_ERR_NONE;
1404 }
1405
DeliverOutput(mfxFrameSurface1 * frame)1406 mfxStatus CDecodingPipeline::DeliverOutput(mfxFrameSurface1* frame) {
1407 CAutoTimer timer_fwrite(m_tick_fwrite);
1408
1409 mfxStatus res = MFX_ERR_NONE, sts = MFX_ERR_NONE;
1410
1411 if (!frame) {
1412 return MFX_ERR_NULL_PTR;
1413 }
1414
1415 if (m_bResetFileWriter) {
1416 sts = m_FileWriter.Reset();
1417 MSDK_CHECK_STATUS(sts, "");
1418 m_bResetFileWriter = false;
1419 }
1420
1421 if (m_bExternalAlloc) {
1422 if (m_eWorkMode == MODE_FILE_DUMP) {
1423 res = m_pGeneralAllocator->Lock(m_pGeneralAllocator->pthis,
1424 frame->Data.MemId,
1425 &(frame->Data));
1426 if (MFX_ERR_NONE == res) {
1427 res = m_bOutI420 ? m_FileWriter.WriteNextFrameI420(frame)
1428 : m_FileWriter.WriteNextFrame(frame);
1429 sts = m_pGeneralAllocator->Unlock(m_pGeneralAllocator->pthis,
1430 frame->Data.MemId,
1431 &(frame->Data));
1432 }
1433 if ((MFX_ERR_NONE == res) && (MFX_ERR_NONE != sts)) {
1434 res = sts;
1435 }
1436 }
1437 else if (m_eWorkMode == MODE_RENDERING) {
1438 #if D3D_SURFACES_SUPPORT
1439 res = m_d3dRender.RenderFrame(frame, m_pGeneralAllocator);
1440 #elif LIBVA_SUPPORT
1441 res = m_hwdev->RenderFrame(frame, m_pGeneralAllocator);
1442 #endif
1443 }
1444 }
1445 else {
1446 res = m_bOutI420 ? m_FileWriter.WriteNextFrameI420(frame)
1447 : m_FileWriter.WriteNextFrame(frame);
1448 }
1449
1450 m_fpsLimiter.Work();
1451
1452 return res;
1453 }
1454
DeliverLoop(void)1455 void CDecodingPipeline::DeliverLoop(void) {
1456 while (!m_bStopDeliverLoop) {
1457 m_pDeliverOutputSemaphore->Wait();
1458 if (m_bStopDeliverLoop) {
1459 continue;
1460 }
1461 if (MFX_ERR_NONE != m_error) {
1462 continue;
1463 }
1464 msdkOutputSurface* pCurrentDeliveredSurface = m_DeliveredSurfacesPool.GetSurface();
1465 if (!pCurrentDeliveredSurface) {
1466 m_error = MFX_ERR_NULL_PTR;
1467 continue;
1468 }
1469 mfxFrameSurface1* frame = &(pCurrentDeliveredSurface->surface->frame);
1470
1471 m_error = DeliverOutput(frame);
1472 ReturnSurfaceToBuffers(pCurrentDeliveredSurface);
1473
1474 pCurrentDeliveredSurface = NULL;
1475 msdk_atomic_inc32(&m_output_count);
1476 m_pDeliveredEvent->Signal();
1477 }
1478 return;
1479 }
1480
PrintPerFrameStat(bool force)1481 void CDecodingPipeline::PrintPerFrameStat(bool force) {
1482 #define MY_COUNT 1 // TODO: this will be cmd option
1483 #define MY_THRESHOLD 10000.0
1484 if ((!(m_output_count % MY_COUNT) && (m_eWorkMode != MODE_PERFORMANCE)) || force) {
1485 double fps, fps_fread, fps_fwrite;
1486
1487 m_timer_overall.Sync();
1488
1489 fps = (m_tick_overall) ? m_output_count / CTimer::ConvertToSeconds(m_tick_overall) : 0.0;
1490 fps_fread = (m_tick_fread) ? m_output_count / CTimer::ConvertToSeconds(m_tick_fread) : 0.0;
1491 fps_fwrite =
1492 (m_tick_fwrite) ? m_output_count / CTimer::ConvertToSeconds(m_tick_fwrite) : 0.0;
1493 // decoding progress
1494 msdk_printf(
1495 MSDK_STRING("Frame number: %4d, fps: %0.3f, fread_fps: %0.3f, fwrite_fps: %.3f\r"),
1496 (int)m_output_count,
1497 fps,
1498 (fps_fread < MY_THRESHOLD) ? fps_fread : 0.0,
1499 (fps_fwrite < MY_THRESHOLD) ? fps_fwrite : 0.0);
1500 fflush(NULL);
1501 #if D3D_SURFACES_SUPPORT
1502 m_d3dRender.UpdateTitle(fps);
1503 #elif LIBVA_SUPPORT
1504 if (m_hwdev)
1505 m_hwdev->UpdateTitle(fps);
1506 #endif
1507 }
1508 }
1509
SyncOutputSurface(mfxU32 wait)1510 mfxStatus CDecodingPipeline::SyncOutputSurface(mfxU32 wait) {
1511 if (!m_pCurrentOutputSurface) {
1512 m_pCurrentOutputSurface = m_OutputSurfacesPool.GetSurface();
1513 }
1514 if (!m_pCurrentOutputSurface) {
1515 return MFX_ERR_MORE_DATA;
1516 }
1517
1518 mfxStatus sts = m_mfxSession.SyncOperation(m_pCurrentOutputSurface->syncp, wait);
1519
1520 if (MFX_ERR_GPU_HANG == sts && m_bSoftRobustFlag) {
1521 msdk_printf(MSDK_STRING("GPU hang happened\n"));
1522 // Output surface can be corrupted
1523 // But should be delivered to output anyway
1524 sts = MFX_ERR_NONE;
1525 }
1526
1527 if (MFX_WRN_IN_EXECUTION == sts) {
1528 return sts;
1529 }
1530 if (MFX_ERR_NONE == sts) {
1531 // we got completely decoded frame - pushing it to the delivering thread...
1532 ++m_synced_count;
1533 if (m_bPrintLatency) {
1534 m_vLatency.push_back(m_timer_overall.Sync() - m_pCurrentOutputSurface->surface->submit);
1535 }
1536 else {
1537 PrintPerFrameStat();
1538 }
1539
1540 if (m_eWorkMode == MODE_PERFORMANCE) {
1541 m_output_count = m_synced_count;
1542 m_fpsLimiter.Work();
1543 ReturnSurfaceToBuffers(m_pCurrentOutputSurface);
1544 }
1545 else if (m_eWorkMode == MODE_FILE_DUMP) {
1546 sts = DeliverOutput(&(m_pCurrentOutputSurface->surface->frame));
1547 if (MFX_ERR_NONE != sts) {
1548 sts = MFX_ERR_UNKNOWN;
1549 }
1550 else {
1551 m_output_count = m_synced_count;
1552 }
1553 ReturnSurfaceToBuffers(m_pCurrentOutputSurface);
1554 }
1555 else if (m_eWorkMode == MODE_RENDERING) {
1556 m_DeliveredSurfacesPool.AddSurface(m_pCurrentOutputSurface);
1557 m_pDeliveredEvent->Reset();
1558 m_pDeliverOutputSemaphore->Post();
1559 }
1560 m_pCurrentOutputSurface = NULL;
1561 }
1562
1563 return sts;
1564 }
1565
RunDecoding()1566 mfxStatus CDecodingPipeline::RunDecoding() {
1567 mfxFrameSurface1* pOutSurface = NULL;
1568 mfxBitstream* pBitstream = &m_mfxBS;
1569 mfxStatus sts = MFX_ERR_NONE;
1570 bool bErrIncompatibleVideoParams = false;
1571 CTimeInterval<> decodeTimer(m_bIsCompleteFrame);
1572 time_t start_time = time(0);
1573 std::thread deliverThread;
1574
1575 if (m_eWorkMode == MODE_RENDERING) {
1576 m_pDeliverOutputSemaphore = new MSDKSemaphore(sts);
1577 m_pDeliveredEvent = new MSDKEvent(sts, false, false);
1578
1579 deliverThread = std::thread(&CDecodingPipeline::DeliverLoop, this);
1580 }
1581
1582 while (((sts == MFX_ERR_NONE) || (MFX_ERR_MORE_DATA == sts) || (MFX_ERR_MORE_SURFACE == sts)) &&
1583 (m_nFrames > m_output_count)) {
1584 if (MFX_ERR_NONE != m_error) {
1585 msdk_printf(MSDK_STRING("DeliverOutput return error = %d\n"), (int)m_error);
1586 break;
1587 }
1588
1589 if (pBitstream &&
1590 ((MFX_ERR_MORE_DATA == sts) || (m_bIsCompleteFrame && !pBitstream->DataLength))) {
1591 CAutoTimer timer_fread(m_tick_fread);
1592 sts = m_FileReader->ReadNextFrame(pBitstream); // read more data to input bit stream
1593
1594 if (MFX_ERR_MORE_DATA == sts) {
1595 sts = MFX_ERR_NONE;
1596 // Timeout has expired or videowall mode
1597 m_timer_overall.Sync();
1598 if (((CTimer::ConvertToSeconds(m_tick_overall) < m_nTimeout) && m_nTimeout) ||
1599 m_bIsVideoWall) {
1600 m_FileReader->Reset();
1601 m_bResetFileWriter = true;
1602
1603 // Reset bitstream state
1604 pBitstream->DataFlag = 0;
1605
1606 continue;
1607 }
1608
1609 // we almost reached end of stream, need to pull buffered data now
1610 pBitstream = NULL;
1611 }
1612 }
1613
1614 if ((MFX_ERR_NONE == sts) || (MFX_ERR_MORE_DATA == sts) || (MFX_ERR_MORE_SURFACE == sts)) {
1615 // here we check whether output is ready, though we do not wait...
1616 #ifndef __SYNC_WA
1617 mfxStatus _sts = SyncOutputSurface(0);
1618 if (MFX_ERR_UNKNOWN == _sts) {
1619 sts = _sts;
1620 break;
1621 }
1622 else if (MFX_ERR_NONE == _sts) {
1623 continue;
1624 }
1625 #endif
1626 }
1627 else {
1628 MSDK_CHECK_STATUS_NO_RET(sts, "ReadNextFrame failed");
1629 }
1630
1631 if ((MFX_ERR_NONE == sts) || (MFX_ERR_MORE_DATA == sts) || (MFX_ERR_MORE_SURFACE == sts)) {
1632 SyncFrameSurfaces();
1633 SyncVppFrameSurfaces();
1634 if (!m_pCurrentFreeSurface) {
1635 m_pCurrentFreeSurface = m_FreeSurfacesPool.GetSurface();
1636 }
1637 if (!m_pCurrentFreeVppSurface) {
1638 m_pCurrentFreeVppSurface = m_FreeVppSurfacesPool.GetSurface();
1639 }
1640 #ifndef __SYNC_WA
1641 if (!m_pCurrentFreeSurface || !m_pCurrentFreeVppSurface) {
1642 #else
1643 if (!m_pCurrentFreeSurface || (!m_pCurrentFreeVppSurface && m_bVppIsUsed) ||
1644 (m_OutputSurfacesPool.GetSurfaceCount() == m_mfxVideoParams.AsyncDepth)) {
1645 #endif
1646 // we stuck with no free surface available, now we will sync...
1647 sts = SyncOutputSurface(MSDK_DEC_WAIT_INTERVAL);
1648 if (MFX_ERR_MORE_DATA == sts) {
1649 if ((m_eWorkMode == MODE_PERFORMANCE) || (m_eWorkMode == MODE_FILE_DUMP)) {
1650 sts = MFX_ERR_NOT_FOUND;
1651 }
1652 else if (m_eWorkMode == MODE_RENDERING) {
1653 if (m_synced_count != m_output_count) {
1654 sts = m_pDeliveredEvent->TimedWait(MSDK_DEC_WAIT_INTERVAL);
1655 }
1656 else {
1657 sts = MFX_ERR_NOT_FOUND;
1658 }
1659 }
1660 if (MFX_ERR_NOT_FOUND == sts) {
1661 msdk_printf(
1662 MSDK_STRING("fatal: failed to find output surface, that's a bug!\n"));
1663 break;
1664 }
1665 }
1666 MSDK_CHECK_ERR_NONE_STATUS_NO_RET(sts, "SyncOperation fail or timeout");
1667 // note: MFX_WRN_IN_EXECUTION will also be treated as an error at this point
1668 continue;
1669 }
1670
1671 if (!m_pCurrentFreeOutputSurface) {
1672 m_pCurrentFreeOutputSurface = GetFreeOutputSurface();
1673 }
1674 if (!m_pCurrentFreeOutputSurface) {
1675 sts = MFX_ERR_NOT_FOUND;
1676 break;
1677 }
1678 }
1679
1680 // exit by timeout
1681 if ((MFX_ERR_NONE == sts) && m_bIsVideoWall && (time(0) - start_time) >= m_nTimeout) {
1682 sts = MFX_ERR_NONE;
1683 break;
1684 }
1685
1686 if ((MFX_ERR_NONE == sts) || (MFX_ERR_MORE_DATA == sts) || (MFX_ERR_MORE_SURFACE == sts)) {
1687 if (m_bIsCompleteFrame) {
1688 m_pCurrentFreeSurface->submit = m_timer_overall.Sync();
1689 }
1690 pOutSurface = NULL;
1691 do {
1692 mfxExtDecodeErrorReport* errorReport = nullptr;
1693 if (pBitstream) {
1694 errorReport =
1695 (mfxExtDecodeErrorReport*)GetExtBuffer(pBitstream->ExtParam,
1696 pBitstream->NumExtParam,
1697 MFX_EXTBUFF_DECODE_ERROR_REPORT);
1698 }
1699 sts = m_pmfxDEC->DecodeFrameAsync(pBitstream,
1700 &(m_pCurrentFreeSurface->frame),
1701 &pOutSurface,
1702 &(m_pCurrentFreeOutputSurface->syncp));
1703
1704 PrintDecodeErrorReport(errorReport);
1705
1706 if (pBitstream && MFX_ERR_MORE_DATA == sts &&
1707 pBitstream->MaxLength == pBitstream->DataLength) {
1708 m_mfxBS.Extend(pBitstream->MaxLength * 2);
1709 }
1710
1711 if (MFX_WRN_DEVICE_BUSY == sts) {
1712 if (m_bIsCompleteFrame) {
1713 //in low latency mode device busy leads to increasing of latency
1714 //msdk_printf(MSDK_STRING("Warning : latency increased due to MFX_WRN_DEVICE_BUSY\n"));
1715 }
1716 mfxStatus _sts = SyncOutputSurface(MSDK_DEC_WAIT_INTERVAL);
1717 // note: everything except MFX_ERR_NONE are errors at this point
1718 if (MFX_ERR_NONE == _sts) {
1719 sts = MFX_WRN_DEVICE_BUSY;
1720 }
1721 else {
1722 sts = _sts;
1723 if (MFX_ERR_MORE_DATA == sts) {
1724 // we can't receive MFX_ERR_MORE_DATA and have no output - that's a bug
1725 sts = MFX_WRN_DEVICE_BUSY; //MFX_ERR_NOT_FOUND;
1726 }
1727 }
1728 }
1729 } while (MFX_WRN_DEVICE_BUSY == sts);
1730
1731 if (sts > MFX_ERR_NONE) {
1732 // ignoring warnings...
1733 if (m_pCurrentFreeOutputSurface->syncp) {
1734 MSDK_SELF_CHECK(pOutSurface);
1735 // output is available
1736 sts = MFX_ERR_NONE;
1737 }
1738 else {
1739 // output is not available
1740 sts = MFX_ERR_MORE_SURFACE;
1741 }
1742 }
1743 else if ((MFX_ERR_MORE_DATA == sts) && pBitstream) {
1744 if (m_bIsCompleteFrame && pBitstream->DataLength) {
1745 // In low_latency mode decoder have to process bitstream completely
1746 msdk_printf(MSDK_STRING(
1747 "error: Incorrect decoder behavior in low latency mode (bitstream length is not equal to 0 after decoding)\n"));
1748 sts = MFX_ERR_UNDEFINED_BEHAVIOR;
1749 continue;
1750 }
1751 }
1752 else if ((MFX_ERR_MORE_DATA == sts) && !pBitstream) {
1753 // that's it - we reached end of stream; now we need to render bufferred data...
1754 do {
1755 sts = SyncOutputSurface(MSDK_DEC_WAIT_INTERVAL);
1756 } while (MFX_ERR_NONE == sts);
1757
1758 MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);
1759 if (sts)
1760 MSDK_PRINT_WRN_MSG(sts, "SyncOutputSurface failed")
1761
1762 while (m_synced_count != m_output_count) {
1763 m_pDeliveredEvent->Wait();
1764 }
1765 break;
1766 }
1767 else if (MFX_ERR_INCOMPATIBLE_VIDEO_PARAM == sts) {
1768 bErrIncompatibleVideoParams = true;
1769 // need to go to the buffering loop prior to reset procedure
1770 pBitstream = NULL;
1771 sts = MFX_ERR_NONE;
1772 continue;
1773 }
1774 else if (MFX_ERR_REALLOC_SURFACE == sts) {
1775 mfxVideoParam param{};
1776 sts = m_pmfxDEC->GetVideoParam(¶m);
1777 if (MFX_ERR_NONE != sts) {
1778 // need to go to the buffering loop prior to reset procedure
1779 pBitstream = NULL;
1780 sts = MFX_ERR_NONE;
1781 continue;
1782 }
1783
1784 sts = ReallocCurrentSurface(param.mfx.FrameInfo);
1785 if (MFX_ERR_NONE != sts) {
1786 // need to go to the buffering loop prior to reset procedure
1787 pBitstream = NULL;
1788 sts = MFX_ERR_NONE;
1789 }
1790 continue;
1791 }
1792 }
1793
1794 if ((MFX_ERR_NONE == sts) || (MFX_ERR_MORE_DATA == sts) || (MFX_ERR_MORE_SURFACE == sts)) {
1795 // if current free surface is locked we are moving it to the used surfaces array
1796 /*if (m_pCurrentFreeSurface->frame.Data.Locked)*/ {
1797 m_UsedSurfacesPool.AddSurface(m_pCurrentFreeSurface);
1798 m_pCurrentFreeSurface = NULL;
1799 }
1800 }
1801 else {
1802 MSDK_CHECK_STATUS_NO_RET(sts, "DecodeFrameAsync returned error status");
1803 }
1804
1805 if (MFX_ERR_NONE == sts) {
1806 if (m_bVppIsUsed) {
1807 if (m_pCurrentFreeVppSurface) {
1808 do {
1809 if ((m_pCurrentFreeVppSurface->frame.Info.CropW == 0) ||
1810 (m_pCurrentFreeVppSurface->frame.Info.CropH == 0)) {
1811 m_pCurrentFreeVppSurface->frame.Info.CropW = pOutSurface->Info.CropW;
1812 m_pCurrentFreeVppSurface->frame.Info.CropH = pOutSurface->Info.CropH;
1813 m_pCurrentFreeVppSurface->frame.Info.CropX = pOutSurface->Info.CropX;
1814 m_pCurrentFreeVppSurface->frame.Info.CropY = pOutSurface->Info.CropY;
1815 }
1816 if (pOutSurface->Info.PicStruct !=
1817 m_pCurrentFreeVppSurface->frame.Info.PicStruct) {
1818 m_pCurrentFreeVppSurface->frame.Info.PicStruct =
1819 pOutSurface->Info.PicStruct;
1820 }
1821 if ((pOutSurface->Info.PicStruct == 0) &&
1822 (m_pCurrentFreeVppSurface->frame.Info.PicStruct == 0)) {
1823 m_pCurrentFreeVppSurface->frame.Info.PicStruct =
1824 pOutSurface->Info.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
1825 }
1826
1827 if (m_diMode)
1828 m_pCurrentFreeVppSurface->frame.Info.PicStruct =
1829 MFX_PICSTRUCT_PROGRESSIVE;
1830
1831 // WA: RunFrameVPPAsync doesn't copy ViewId from input to output
1832 m_pCurrentFreeVppSurface->frame.Info.FrameId.ViewId =
1833 pOutSurface->Info.FrameId.ViewId;
1834 sts = m_pmfxVPP->RunFrameVPPAsync(pOutSurface,
1835 &(m_pCurrentFreeVppSurface->frame),
1836 NULL,
1837 &(m_pCurrentFreeOutputSurface->syncp));
1838
1839 if (MFX_WRN_DEVICE_BUSY == sts) {
1840 MSDK_SLEEP(
1841 1); // just wait and then repeat the same call to RunFrameVPPAsync
1842 }
1843 } while (MFX_WRN_DEVICE_BUSY == sts);
1844
1845 // process errors
1846 if (MFX_ERR_MORE_DATA == sts) { // will never happen actually
1847 continue;
1848 }
1849 else if (MFX_ERR_NONE != sts) {
1850 MSDK_PRINT_RET_MSG(sts, "RunFrameVPPAsync failed");
1851 break;
1852 }
1853
1854 m_UsedVppSurfacesPool.AddSurface(m_pCurrentFreeVppSurface);
1855 msdk_atomic_inc16(&(m_pCurrentFreeVppSurface->render_lock));
1856
1857 m_pCurrentFreeOutputSurface->surface = m_pCurrentFreeVppSurface;
1858 m_OutputSurfacesPool.AddSurface(m_pCurrentFreeOutputSurface);
1859
1860 m_pCurrentFreeOutputSurface = NULL;
1861 m_pCurrentFreeVppSurface = NULL;
1862 }
1863 }
1864 else {
1865 msdkFrameSurface* surface = FindUsedSurface(pOutSurface);
1866
1867 msdk_atomic_inc16(&(surface->render_lock));
1868
1869 m_pCurrentFreeOutputSurface->surface = surface;
1870 m_OutputSurfacesPool.AddSurface(m_pCurrentFreeOutputSurface);
1871 m_pCurrentFreeOutputSurface = NULL;
1872 }
1873 }
1874 } //while processing
1875
1876 if (m_nFrames == m_output_count) {
1877 if (sts != MFX_ERR_NONE)
1878 msdk_printf(
1879 MSDK_STRING(
1880 "[WARNING] Decoder returned error %s that could be compensated during next iterations of decoding process.\
1881 But requested amount of frames is already successfully decoded, so whole process is finished successfully."),
1882 StatusToString(sts).c_str());
1883 sts = MFX_ERR_NONE;
1884 }
1885
1886 PrintPerFrameStat(true);
1887
1888 if (m_bPrintLatency && m_vLatency.size() > 0) {
1889 unsigned int frame_idx = 0;
1890 msdk_tick sum = 0;
1891 for (std::vector<msdk_tick>::iterator it = m_vLatency.begin(); it != m_vLatency.end();
1892 ++it) {
1893 sum += *it;
1894 msdk_printf(MSDK_STRING("Frame %4d, latency=%5.5f ms\n"),
1895 ++frame_idx,
1896 (double)(CTimer::ConvertToSeconds(*it) * 1000));
1897 }
1898 msdk_printf(MSDK_STRING("\nLatency summary:\n"));
1899 msdk_printf(
1900 MSDK_STRING("\nAVG=%5.5f ms, MAX=%5.5f ms, MIN=%5.5f ms"),
1901 (double)CTimer::ConvertToSeconds((msdk_tick)((mfxF64)sum / m_vLatency.size())) * 1000,
1902 (double)CTimer::ConvertToSeconds(
1903 *std::max_element(m_vLatency.begin(), m_vLatency.end())) *
1904 1000,
1905 (double)CTimer::ConvertToSeconds(
1906 *std::min_element(m_vLatency.begin(), m_vLatency.end())) *
1907 1000);
1908 }
1909
1910 if (m_eWorkMode == MODE_RENDERING) {
1911 m_bStopDeliverLoop = true;
1912 m_pDeliverOutputSemaphore->Post();
1913
1914 if (deliverThread.joinable())
1915 deliverThread.join();
1916 }
1917
1918 MSDK_SAFE_DELETE(m_pDeliverOutputSemaphore);
1919 MSDK_SAFE_DELETE(m_pDeliveredEvent);
1920
1921 // exit in case of other errors
1922 MSDK_CHECK_STATUS(sts, "Unexpected error!!");
1923
1924 // if we exited main decoding loop with ERR_INCOMPATIBLE_PARAM we need to send this status to caller
1925 if (bErrIncompatibleVideoParams) {
1926 sts = MFX_ERR_INCOMPATIBLE_VIDEO_PARAM;
1927 }
1928
1929 return sts; // ERR_NONE or ERR_INCOMPATIBLE_VIDEO_PARAM
1930 }
1931
1932 void CDecodingPipeline::PrintInfo() {
1933 msdk_printf(MSDK_STRING("Decoding Sample Version %s\n\n"), GetMSDKSampleVersion().c_str());
1934 msdk_printf(MSDK_STRING("\nInput video\t%s\n"),
1935 CodecIdToStr(m_mfxVideoParams.mfx.CodecId).c_str());
1936 if (m_bVppIsUsed) {
1937 msdk_printf(MSDK_STRING("Output format\t%s (using vpp)\n"),
1938 m_bOutI420 ? MSDK_STRING("I420(YUV)")
1939 : CodecIdToStr(m_mfxVppVideoParams.vpp.Out.FourCC).c_str());
1940 }
1941 else {
1942 msdk_printf(MSDK_STRING("Output format\t%s\n"),
1943 m_bOutI420 ? MSDK_STRING("I420(YUV)")
1944 : CodecIdToStr(m_mfxVideoParams.mfx.FrameInfo.FourCC).c_str());
1945 }
1946
1947 mfxFrameInfo Info = m_mfxVideoParams.mfx.FrameInfo;
1948 msdk_printf(MSDK_STRING("Input:\n"));
1949 msdk_printf(MSDK_STRING(" Resolution\t%dx%d\n"), (int)Info.Width, (int)Info.Height);
1950 msdk_printf(MSDK_STRING(" Crop X,Y,W,H\t%d,%d,%d,%d\n"),
1951 (int)Info.CropX,
1952 (int)Info.CropY,
1953 (int)Info.CropW,
1954 (int)Info.CropH);
1955 msdk_printf(MSDK_STRING("Output:\n"));
1956 if (m_vppOutHeight && m_vppOutWidth) {
1957 msdk_printf(MSDK_STRING(" Resolution\t%hux%hu\n"),
1958 (short int)m_vppOutWidth,
1959 (short int)m_vppOutHeight);
1960 }
1961 else {
1962 msdk_printf(MSDK_STRING(" Resolution\t%dx%d\n"),
1963 Info.CropW ? (int)Info.CropW : (int)Info.Width,
1964 Info.CropH ? (int)Info.CropH : (int)Info.Height);
1965 }
1966
1967 mfxF64 dFrameRate = CalculateFrameRate(Info.FrameRateExtN, Info.FrameRateExtD);
1968 msdk_printf(MSDK_STRING("Frame rate\t%.2f\n"), (double)dFrameRate);
1969
1970 const msdk_char* sMemType =
1971 #if defined(_WIN32) || defined(_WIN64)
1972 m_memType == D3D9_MEMORY
1973 ? MSDK_STRING("d3d")
1974 #else
1975 m_memType == D3D9_MEMORY
1976 ? MSDK_STRING("vaapi")
1977 #endif
1978 : (m_memType == D3D11_MEMORY ? MSDK_STRING("d3d11") : MSDK_STRING("system"));
1979 msdk_printf(MSDK_STRING("Memory type\t\t%s\n"), sMemType);
1980
1981 const msdk_char* sImpl = (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(m_impl))
1982 ? MSDK_STRING("hw_d3d11")
1983 : (MFX_IMPL_SOFTWARE == MFX_IMPL_BASETYPE(m_impl))
1984 ? MSDK_STRING("sw")
1985 : MSDK_STRING("hw");
1986 msdk_printf(MSDK_STRING("MediaSDK impl\t\t%s\n"), sImpl);
1987
1988 mfxVersion ver;
1989 m_mfxSession.QueryVersion(&ver);
1990 msdk_printf(MSDK_STRING("MediaSDK version\t%d.%d\n"), (int)ver.Major, (int)ver.Minor);
1991
1992 msdk_printf(MSDK_STRING("\n"));
1993
1994 return;
1995 }
1996