From 79c761c34deffb8f3eb2cb761b4ce419866a5e70 Mon Sep 17 00:00:00 2001 From: Furong Zhang Date: Mon, 5 Apr 2021 20:49:09 +0800 Subject: [PATCH] Add 3DLUT filter in VPP. 1. Add 3DLUT interface and Linux implementation. 2. Add tutorials for 3DLUT VPP and transcode. Signed-off-by: Furong Zhang --- _studio/mfx_lib/vpp/include/mfx_vpp_defs.h | 20 + _studio/mfx_lib/vpp/include/mfx_vpp_utils.h | 17 + _studio/mfx_lib/vpp/src/mfx_vpp_hw.cpp | 108 ++- .../mfx_lib/vpp/src/mfx_vpp_sw_internal.cpp | 7 +- _studio/mfx_lib/vpp/src/mfx_vpp_utils.cpp | 48 +- _studio/shared/include/mfx_utils_defs.h | 2 +- _studio/shared/include/mfx_vpp_interface.h | 23 +- _studio/shared/include/mfx_vpp_vaapi.h | 5 +- _studio/shared/src/mfx_vpp_vaapi.cpp | 114 ++- api/include/mfxcommon.h | 13 + api/include/mfxdefs.h | 31 +- api/include/mfxstructures.h | 91 ++- .../sample_common/include/base_allocator.h | 6 + .../sample_common/include/general_allocator.h | 3 + samples/sample_common/include/sample_utils.h | 3 + .../sample_common/include/sysmem_allocator.h | 3 + .../sample_common/include/vaapi_allocator.h | 3 + samples/sample_common/src/base_allocator.cpp | 20 + .../sample_common/src/general_allocator.cpp | 34 + samples/sample_common/src/vaapi_allocator.cpp | 112 +++ .../include/pipeline_transcode.h | 12 + .../src/pipeline_transcode.cpp | 52 +- .../src/transcode_utils.cpp | 21 +- tutorials/CMakeLists.txt | 2 + tutorials/common/common_utils.cpp | 87 +- tutorials/common/common_utils.h | 5 +- tutorials/common/common_utils_windows.cpp | 13 +- tutorials/common/common_vaapi.cpp | 125 ++- .../CMakeLists.txt | 4 + .../simple_vpp_d3d.sln | 28 + .../simple_vpp_d3d.vcxproj | 210 +++++ .../simple_vpp_d3d11.sln | 28 + .../simple_vpp_d3d11.vcxproj | 210 +++++ .../src/simple_vpp_vmem.cpp | 391 +++++++++ .../CMakeLists.txt | 4 + ...transcode_opaque_async_vppresize_3dlut.sln | 28 + ...scode_opaque_async_vppresize_3dlut.vcxproj | 208 +++++ ...transcode_opaque_async_vppresize_3dlut.cpp | 757 ++++++++++++++++++ 38 files changed, 2799 insertions(+), 49 deletions(-) create mode 100644 tutorials/simple_4_vpp_resize_3dlut_vmem/CMakeLists.txt create mode 100644 tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d.sln create mode 100644 tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d.vcxproj create mode 100644 tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d11.sln create mode 100644 tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d11.vcxproj create mode 100644 tutorials/simple_4_vpp_resize_3dlut_vmem/src/simple_vpp_vmem.cpp create mode 100644 tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/CMakeLists.txt create mode 100644 tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/simple_5_transcode_opaque_async_vppresize_3dlut.sln create mode 100644 tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/simple_5_transcode_opaque_async_vppresize_3dlut.vcxproj create mode 100644 tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/src/simple_5_transcode_opaque_async_vppresize_3dlut.cpp diff --git a/_studio/mfx_lib/vpp/include/mfx_vpp_defs.h b/_studio/mfx_lib/vpp/include/mfx_vpp_defs.h index bdd5d51162..cae1c1b4d3 100644 --- a/_studio/mfx_lib/vpp/include/mfx_vpp_defs.h +++ b/_studio/mfx_lib/vpp/include/mfx_vpp_defs.h @@ -132,6 +132,26 @@ typedef enum { } PicStructMode; +typedef enum { + MFX_COLOUR_PRIMARY_RESERVED = 0, + MFX_COLOUR_PRIMARY_BT709 = 1, + MFX_COLOUR_PRIMARY_UNSPECIFIED = 2, + MFX_COLOUR_PRIMARY_BT601_625 = 5, // BT601-7 625-line system + MFX_COLOUR_PRIMARY_BT601_525 = 6, // BT601-7 525-line system + MFX_COLOUR_PRIMARY_BT2020 = 9, // BT2100 shares this same value +} mfxColourPrimary; + +typedef enum { + MFX_TRANSFER_CHARACTERISTIC_RESERVED = 0, + MFX_TRANSFER_CHARACTERISTIC_BT709 = 1, + MFX_TRANSFER_CHARACTERISTIC_UNSPECIFIED = 2, + MFX_TRANSFER_CHARACTERISTIC_DISPLAY_GAMMA_2P2 = 4, + MFX_TRANSFER_CHARACTERISTIC_DISPLAY_GAMMA_2P8 = 5, + MFX_TRANSFER_CHARACTERISTIC_BT601 = 6, // BT601-7 625-line or 525-line system + MFX_TRANSFER_CHARACTERISTIC_LINEAR = 8, // Linear transfer characteristic + MFX_TRANSFER_CHARACTERISTIC_ST2084 = 16, // ST2084 transfer characteristic +} mfxTransferCharacteristic; + typedef enum { // gamut compression diff --git a/_studio/mfx_lib/vpp/include/mfx_vpp_utils.h b/_studio/mfx_lib/vpp/include/mfx_vpp_utils.h index 0ecea431b6..58e84660e6 100644 --- a/_studio/mfx_lib/vpp/include/mfx_vpp_utils.h +++ b/_studio/mfx_lib/vpp/include/mfx_vpp_utils.h @@ -195,6 +195,23 @@ size_t GetConfigSize( mfxU32 filterId ); void ConvertCaps2ListDoUse(MfxHwVideoProcessing::mfxVppCaps& caps, std::vector& list); +__inline mfxU16 GetTransferCharacteristic(mfxU16 transferMatrix) +{ + mfxTransferCharacteristic ret = MFX_TRANSFER_CHARACTERISTIC_BT709; + switch (transferMatrix) + { + case MFX_TRANSFERMATRIX_BT709: + ret = MFX_TRANSFER_CHARACTERISTIC_BT709; + break; + case MFX_TRANSFERMATRIX_BT601: + ret = MFX_TRANSFER_CHARACTERISTIC_BT601; + break; + default: + break; + } + return (mfxU16)ret; +} + //mfxStatus QueryExtParams() #endif // __MFX_VPP_UTILS_H diff --git a/_studio/mfx_lib/vpp/src/mfx_vpp_hw.cpp b/_studio/mfx_lib/vpp/src/mfx_vpp_hw.cpp index 6e8552b144..618aa80401 100755 --- a/_studio/mfx_lib/vpp/src/mfx_vpp_hw.cpp +++ b/_studio/mfx_lib/vpp/src/mfx_vpp_hw.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2008-2020 Intel Corporation +// Copyright (c) 2008-2021 Intel Corporation // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -148,6 +148,7 @@ static void MemSetZero4mfxExecuteParams (mfxExecuteParams *pMfxExecuteParams ) #endif pMfxExecuteParams->bEOS = false; pMfxExecuteParams->scene = VPP_NO_SCENE_CHANGE; + pMfxExecuteParams->lut3DInfo = {}; } /*void MemSetZero4mfxExecuteParams (mfxExecuteParams *pMfxExecuteParams )*/ @@ -2036,6 +2037,19 @@ mfxStatus VideoVPPHW::GetVideoParams(mfxVideoParam *par) const bufSc->InterpolationMethod = m_executeParams.interpolationMethod; #endif } + else if (MFX_EXTBUFF_VPP_3DLUT == bufferId) + { + mfxExtVPP3DLut *bufSc = reinterpret_cast(par->ExtParam[i]); + MFX_CHECK_NULL_PTR1(bufSc); + bufSc->ChannelMapping = m_executeParams.lut3DInfo.ChannelMapping; + bufSc->BufferType = m_executeParams.lut3DInfo.BufferType; + if (bufSc->BufferType == MFX_RESOURCE_VA_SURFACE) + { + bufSc->VideoBuffer.DataType = m_executeParams.lut3DInfo.DataType; + bufSc->VideoBuffer.MemLayout = m_executeParams.lut3DInfo.MemLayout; + bufSc->VideoBuffer.MemId = m_executeParams.lut3DInfo.MemId; + } + } #if (MFX_VERSION >= 1025) else if (MFX_EXTBUFF_VPP_COLOR_CONVERSION == bufferId) { @@ -3733,7 +3747,7 @@ mfxStatus VideoVPPHW::MergeRuntimeParams(const DdiTask *pTask, MfxHwVideoProcess /* Params look good */ execParams->VideoSignalInfo[i].enabled = true; execParams->VideoSignalInfo[i].NominalRange = vsi->NominalRange; - execParams->VideoSignalInfo[i].TransferMatrix = vsi->TransferMatrix; + execParams->VideoSignalInfo[i].TransferMatrix = GetTransferCharacteristic(vsi->TransferMatrix); } } @@ -3866,10 +3880,9 @@ mfxStatus VideoVPPHW::SyncTaskSubmission(DdiTask* pTask) if (m_executeParams.iFieldProcessingMode != 0) { mfxFrameSurface1 * pInputSurface = m_IOPattern & MFX_IOPATTERN_IN_OPAQUE_MEMORY ? - m_pCore->GetOpaqSurface(surfQueue[0].pSurf->Data.MemId): - surfQueue[0].pSurf; + m_pCore->GetOpaqSurface(surfQueue[0].pSurf->Data.MemId): + surfQueue[0].pSurf; MFX_CHECK(pInputSurface, MFX_ERR_NULL_PTR); - /* Mean filter was configured as DOUSE, but no ExtBuf in VPP Init() * And ... no any parameters in runtime. This is an error! */ if (((m_executeParams.iFieldProcessingMode -1) == FROM_RUNTIME_EXTBUFF_FIELD_PROC) && (pInputSurface->Data.NumExtParam == 0)) @@ -3961,6 +3974,52 @@ mfxStatus VideoVPPHW::SyncTaskSubmission(DdiTask* pTask) } } + mfxFrameSurface1 * pInputSurface = pTask->input.pSurf; + if (pTask->input.pSurf ) + { + for ( mfxU32 jj = 0; jj < pInputSurface->Data.NumExtParam; jj++ ) + { + if (pInputSurface->Data.ExtParam[jj]) + { + if ( (pInputSurface->Data.ExtParam[jj]->BufferId == MFX_EXTBUFF_VIDEO_SIGNAL_INFO) && + (pInputSurface->Data.ExtParam[jj]->BufferSz == sizeof(mfxExtVideoSignalInfo)) ) + { + mfxExtVideoSignalInfo* videoSignallInfo = (mfxExtVideoSignalInfo *)(pInputSurface->Data.ExtParam[jj]); + if (videoSignallInfo) + { + m_executeParams.VideoSignalInfoIn.enabled = TRUE; + m_executeParams.VideoSignalInfoIn.ColourPrimary = videoSignallInfo->ColourPrimaries; + m_executeParams.VideoSignalInfoIn.TransferMatrix = videoSignallInfo->TransferCharacteristics; + m_executeParams.VideoSignalInfoIn.MatrixCoeffs = videoSignallInfo->MatrixCoefficients; + m_executeParams.VideoSignalInfoIn.NominalRange = videoSignallInfo->VideoFullRange ? MFX_NOMINALRANGE_0_255 : MFX_NOMINALRANGE_16_235; + } + } + } + } + } + + mfxFrameSurface1 * pOutputSurface = pTask->output.pSurf; + MFX_CHECK(pOutputSurface, MFX_ERR_NULL_PTR); + for ( mfxU32 jj = 0; jj < pOutputSurface->Data.NumExtParam; jj++ ) + { + if (pOutputSurface->Data.ExtParam[jj]) + { + if ( (pOutputSurface->Data.ExtParam[jj]->BufferId == MFX_EXTBUFF_VIDEO_SIGNAL_INFO) && + (pOutputSurface->Data.ExtParam[jj]->BufferSz == sizeof(mfxExtVideoSignalInfo)) ) + { + mfxExtVideoSignalInfo* videoSignallInfo = (mfxExtVideoSignalInfo *)(pOutputSurface->Data.ExtParam[jj]); + if (videoSignallInfo) + { + m_executeParams.VideoSignalInfoOut.enabled = TRUE; + m_executeParams.VideoSignalInfoOut.ColourPrimary = videoSignallInfo->ColourPrimaries; + m_executeParams.VideoSignalInfoOut.TransferMatrix = videoSignallInfo->TransferCharacteristics; + m_executeParams.VideoSignalInfoOut.MatrixCoeffs = videoSignallInfo->MatrixCoefficients; + m_executeParams.VideoSignalInfoOut.NominalRange = videoSignallInfo->VideoFullRange ? MFX_NOMINALRANGE_0_255 : MFX_NOMINALRANGE_16_235; + } + } + } + } + if ((m_executeParams.iFieldProcessingMode != 0) && /* If Mode is enabled*/ ((imfxFPMode - 1) != (mfxU32)FRAME2FRAME)) /* And we don't do copy frame to frame lets call our FieldCopy*/ /* And remember our previous line imfxFPMode++;*/ @@ -5664,6 +5723,41 @@ mfxStatus ConfigureExecuteParams( bIsFilterSkipped = true; } + break; + } + case MFX_EXTBUFF_VPP_3DLUT: + { + if (caps.u3DLut) + { + for (mfxU32 i = 0; i < videoParam.NumExtParam; i++) + { + if (videoParam.ExtParam[i]->BufferId == MFX_EXTBUFF_VPP_3DLUT) + { + mfxExtVPP3DLut *ext3DLUT = (mfxExtVPP3DLut*) videoParam.ExtParam[i]; + if (ext3DLUT) + { + executeParams.lut3DInfo.Enabled = true; + executeParams.lut3DInfo.ChannelMapping = ext3DLUT->ChannelMapping; + executeParams.lut3DInfo.BufferType = ext3DLUT->BufferType; + if (ext3DLUT->BufferType == MFX_RESOURCE_VA_SURFACE) + { + executeParams.lut3DInfo.DataType = ext3DLUT->VideoBuffer.DataType; + executeParams.lut3DInfo.MemLayout = ext3DLUT->VideoBuffer.MemLayout; + executeParams.lut3DInfo.MemId = ext3DLUT->VideoBuffer.MemId; + } + else + { + return MFX_ERR_UNSUPPORTED; + } + } + } + } + } + else + { + bIsFilterSkipped = true; + } + break; } #if (MFX_VERSION >= 1025) @@ -6252,6 +6346,10 @@ mfxStatus ConfigureExecuteParams( { executeParams.scalingMode = MFX_SCALING_MODE_DEFAULT; } + else if (MFX_EXTBUFF_VPP_3DLUT == bufferId) + { + executeParams.lut3DInfo.Enabled = false; + } #if (MFX_VERSION >= 1025) else if (MFX_EXTBUFF_VPP_COLOR_CONVERSION == bufferId) { diff --git a/_studio/mfx_lib/vpp/src/mfx_vpp_sw_internal.cpp b/_studio/mfx_lib/vpp/src/mfx_vpp_sw_internal.cpp index eec5d561ea..3b18b126c3 100644 --- a/_studio/mfx_lib/vpp/src/mfx_vpp_sw_internal.cpp +++ b/_studio/mfx_lib/vpp/src/mfx_vpp_sw_internal.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 Intel Corporation +// Copyright (c) 2018-2021 Intel Corporation // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -151,6 +151,11 @@ mfxStatus GetExternalFramesCount(VideoCORE* core, break; } + case (mfxU32)MFX_EXTBUFF_VPP_3DLUT: + { + break; + } + case (mfxU32)MFX_EXTBUFF_VPP_DEINTERLACING: { break; diff --git a/_studio/mfx_lib/vpp/src/mfx_vpp_utils.cpp b/_studio/mfx_lib/vpp/src/mfx_vpp_utils.cpp index 4f742bb807..fc382bec49 100644 --- a/_studio/mfx_lib/vpp/src/mfx_vpp_utils.cpp +++ b/_studio/mfx_lib/vpp/src/mfx_vpp_utils.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 Intel Corporation +// Copyright (c) 2018-2021 Intel Corporation // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -45,7 +45,8 @@ const mfxU32 g_TABLE_DO_NOT_USE [] = #endif MFX_EXTBUFF_VPP_VIDEO_SIGNAL_INFO, MFX_EXTBUFF_VPP_FIELD_PROCESSING, - MFX_EXTBUFF_VPP_MIRRORING + MFX_EXTBUFF_VPP_MIRRORING, + MFX_EXTBUFF_VPP_3DLUT }; @@ -69,7 +70,8 @@ const mfxU32 g_TABLE_DO_USE [] = MFX_EXTBUFF_VPP_DEINTERLACING, MFX_EXTBUFF_VPP_VIDEO_SIGNAL_INFO, MFX_EXTBUFF_VPP_FIELD_PROCESSING, - MFX_EXTBUFF_VPP_MIRRORING + MFX_EXTBUFF_VPP_MIRRORING, + MFX_EXTBUFF_VPP_3DLUT }; @@ -94,7 +96,8 @@ const mfxU32 g_TABLE_CONFIG [] = #if (MFX_VERSION >= 1025) MFX_EXTBUFF_VPP_COLOR_CONVERSION, #endif - MFX_EXTBUFF_VPP_MIRRORING + MFX_EXTBUFF_VPP_MIRRORING, + MFX_EXTBUFF_VPP_3DLUT }; @@ -125,7 +128,8 @@ const mfxU32 g_TABLE_EXT_PARAM [] = #if (MFX_VERSION >= 1025) MFX_EXTBUFF_VPP_COLOR_CONVERSION, #endif - MFX_EXTBUFF_VPP_MIRRORING + MFX_EXTBUFF_VPP_MIRRORING, + MFX_EXTBUFF_VPP_3DLUT }; PicStructMode GetPicStructMode(mfxU16 inPicStruct, mfxU16 outPicStruct) @@ -674,6 +678,11 @@ void ShowPipeline( std::vector pipelineList ) break; } #endif + case (mfxU32)MFX_EXTBUFF_VPP_3DLUT: + { + fprintf(stderr, "MFX_EXTBUFF_VPP_3DLUT\n"); + break; + } default: { fprintf(stderr, "UNKNOWN Filter ID!!! \n"); @@ -793,6 +802,12 @@ void ReorderPipelineListForQuality( std::vector & pipelineList ) index++; } + if( IsFilterFound( &pipelineList[0], (mfxU32)pipelineList.size(), MFX_EXTBUFF_VPP_3DLUT ) ) + { + newList[index] = MFX_EXTBUFF_VPP_3DLUT; + index++; + } + if( IsFilterFound( &pipelineList[0], (mfxU32)pipelineList.size(), MFX_EXTBUFF_VPP_SCENE_ANALYSIS ) ) { newList[index] = MFX_EXTBUFF_VPP_SCENE_ANALYSIS; @@ -1253,6 +1268,14 @@ mfxStatus GetPipelineList( } } + if( IsFilterFound( &configList[0], configCount, MFX_EXTBUFF_VPP_3DLUT ) && !IsFilterFound(&pipelineList[0], (mfxU32)pipelineList.size(), MFX_EXTBUFF_VPP_3DLUT) ) + { + if( !IsFilterFound( &pipelineList[0], (mfxU32)pipelineList.size(), MFX_EXTBUFF_VPP_3DLUT ) ) + { + pipelineList.push_back( MFX_EXTBUFF_VPP_3DLUT ); + } + } + searchCount = sizeof(g_TABLE_CONFIG) / sizeof(*g_TABLE_CONFIG); fCount = configCount; for(fIdx = 0; fIdx < fCount; fIdx++) @@ -1404,8 +1427,14 @@ mfxStatus CheckFrameInfo(mfxFrameInfo* info, mfxU32 request, eMFXHWType platform } /* checking Height based on PicStruct filed */ - if (MFX_PICSTRUCT_PROGRESSIVE & info->PicStruct || - MFX_PICSTRUCT_FIELD_SINGLE & info->PicStruct) + if (MFX_PICSTRUCT_PROGRESSIVE & info->PicStruct) + { + if ((info->Height & 4) !=0) + { + return MFX_ERR_INVALID_VIDEO_PARAM; + } + } + else if (MFX_PICSTRUCT_FIELD_SINGLE & info->PicStruct) { if ((info->Height & 15) !=0) { @@ -2288,6 +2317,11 @@ void ConvertCaps2ListDoUse(MfxHwVideoProcessing::mfxVppCaps& caps, std::vector= 1025) if (caps.uChromaSiting) { diff --git a/_studio/shared/include/mfx_utils_defs.h b/_studio/shared/include/mfx_utils_defs.h index de2eaea436..1a6dc1fd96 100644 --- a/_studio/shared/include/mfx_utils_defs.h +++ b/_studio/shared/include/mfx_utils_defs.h @@ -25,7 +25,7 @@ #include #include #include - +#define MFX_DEBUG_TRACE #ifndef MFX_DEBUG_TRACE #define MFX_STS_TRACE(sts) sts #else diff --git a/_studio/shared/include/mfx_vpp_interface.h b/_studio/shared/include/mfx_vpp_interface.h index fd67b120c8..87588f1be0 100644 --- a/_studio/shared/include/mfx_vpp_interface.h +++ b/_studio/shared/include/mfx_vpp_interface.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 Intel Corporation +// Copyright (c) 2018-2021 Intel Corporation // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -186,6 +186,8 @@ namespace MfxHwVideoProcessing mfxU32 uMirroring; + mfxU32 u3DLut; + mfxVppCaps() : uAdvancedDI(0) , uSimpleDI(0) @@ -213,6 +215,7 @@ namespace MfxHwVideoProcessing , uChromaSiting(0) , mFormatSupport() , uMirroring(0) + , u3DLut(0) { }; }; @@ -244,15 +247,27 @@ namespace MfxHwVideoProcessing bool enabled; mfxU16 TransferMatrix; mfxU16 NominalRange; + mfxU16 ColourPrimary; + mfxU16 MatrixCoeffs; bool operator!=(const SignalInfo & other) const { return enabled != other.enabled || TransferMatrix != other.TransferMatrix - || NominalRange != other.NominalRange; + || NominalRange != other.NominalRange + || ColourPrimary != other.ColourPrimary; } }; + struct Lut3DInfo { + bool Enabled; + mfxMemId MemId; + mfxDataType DataType; + mfxResourceType BufferType; + mfx3DLutMemoryLayout MemLayout; + mfx3DLutChannelMapping ChannelMapping; + }; + public: mfxExecuteParams(): targetSurface() @@ -328,6 +343,7 @@ namespace MfxHwVideoProcessing VideoSignalInfo.clear(); VideoSignalInfo.assign(1, VideoSignalInfoIn); + lut3DInfo= {}; }; bool IsDoNothing() @@ -362,6 +378,7 @@ namespace MfxHwVideoProcessing #ifdef MFX_ENABLE_MCTF || bEnableMctf != false #endif + || lut3DInfo.Enabled != false ) return false; if (VideoSignalInfoIn != VideoSignalInfoOut) @@ -457,6 +474,8 @@ namespace MfxHwVideoProcessing #endif #endif bool reset; + + Lut3DInfo lut3DInfo; }; class DriverVideoProcessing diff --git a/_studio/shared/include/mfx_vpp_vaapi.h b/_studio/shared/include/mfx_vpp_vaapi.h index 89b3f144cb..1427010782 100644 --- a/_studio/shared/include/mfx_vpp_vaapi.h +++ b/_studio/shared/include/mfx_vpp_vaapi.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 Intel Corporation +// Copyright (c) 2017-2021 Intel Corporation // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -161,6 +161,9 @@ namespace MfxHwVideoProcessing UMC::Mutex m_guard; + VAProcFilterCap3DLUT *m_3dlutCaps; + VABufferID m_3dlutFilterID; + mfxStatus Init( _mfxPlatformAccelerationService* pVADisplay, mfxVideoParam *pParams); mfxStatus Close( void ); diff --git a/_studio/shared/src/mfx_vpp_vaapi.cpp b/_studio/shared/src/mfx_vpp_vaapi.cpp index c7bb07185b..c56c1c65ef 100644 --- a/_studio/shared/src/mfx_vpp_vaapi.cpp +++ b/_studio/shared/src/mfx_vpp_vaapi.cpp @@ -96,6 +96,8 @@ VAAPIVideoProcessing::VAAPIVideoProcessing(): , m_numFilterBufs(0) , m_MaxContextPriority(0) , m_primarySurface4Composition(NULL) +, m_3dlutCaps(NULL) +, m_3dlutFilterID(VA_INVALID_ID) { for(int i = 0; i < VAProcFilterCount; i++) @@ -182,6 +184,9 @@ mfxStatus VAAPIVideoProcessing::Close(void) sts = CheckAndDestroyVAbuffer(m_vaDisplay, m_frcFilterID); std::ignore = MFX_STS_TRACE(sts); + sts = CheckAndDestroyVAbuffer(m_vaDisplay, m_3dlutFilterID); + std::ignore = MFX_STS_TRACE(sts); + if (m_vaContextVPP != VA_INVALID_ID) { MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_EXTCALL, "vaDestroyContext"); @@ -205,6 +210,7 @@ mfxStatus VAAPIVideoProcessing::Close(void) m_denoiseFilterID = VA_INVALID_ID; m_deintFilterID = VA_INVALID_ID; m_procampFilterID = VA_INVALID_ID; + m_3dlutFilterID = VA_INVALID_ID; memset( (void*)&m_pipelineCaps, 0, sizeof(m_pipelineCaps)); memset( (void*)&m_denoiseCaps, 0, sizeof(m_denoiseCaps)); @@ -212,6 +218,12 @@ mfxStatus VAAPIVideoProcessing::Close(void) memset( (void*)&m_procampCaps, 0, sizeof(m_procampCaps)); memset( (void*)&m_deinterlacingCaps, 0, sizeof(m_deinterlacingCaps)); + if (m_3dlutCaps) + { + free(m_3dlutCaps); + m_3dlutCaps = NULL; + } + return MFX_ERR_NONE; } // mfxStatus VAAPIVideoProcessing::Close(void) @@ -249,7 +261,12 @@ mfxStatus VAAPIVideoProcessing::Init(_mfxPlatformAccelerationService* pVADisplay break; } } - delete[] va_entrypoints; + + if (va_entrypoints != NULL) + { + delete[] va_entrypoints; + va_entrypoints = NULL; + } if( !m_bRunning ) { @@ -408,6 +425,25 @@ mfxStatus VAAPIVideoProcessing::QueryCapabilities(mfxVppCaps& caps) } } + mfxU32 num_3dlut_caps = 0; + vaSts = vaQueryVideoProcFilterCaps(m_vaDisplay, + m_vaContextVPP, + VAProcFilter3DLUT, + m_3dlutCaps, + &num_3dlut_caps); + MFX_CHECK(((VA_STATUS_SUCCESS == vaSts) || (VA_STATUS_ERROR_MAX_NUM_EXCEEDED == vaSts)), MFX_ERR_DEVICE_FAILED); + if (num_3dlut_caps != 0) + { + m_3dlutCaps = (VAProcFilterCap3DLUT*)malloc(sizeof(VAProcFilterCap3DLUT) * num_3dlut_caps); + memset(m_3dlutCaps, 0, sizeof(VAProcFilterCap3DLUT) * num_3dlut_caps); + vaSts = vaQueryVideoProcFilterCaps(m_vaDisplay, + m_vaContextVPP, + VAProcFilter3DLUT, + m_3dlutCaps, &num_3dlut_caps); + MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED); + caps.u3DLut = 1; + } + memset(&m_pipelineCaps, 0, sizeof(VAProcPipelineCaps)); vaSts = vaQueryVideoProcPipelineCaps(m_vaDisplay, m_vaContextVPP, @@ -896,6 +932,73 @@ mfxStatus VAAPIVideoProcessing::Execute(mfxExecuteParams *pParams) } } + if (VA_INVALID_ID == m_3dlutFilterID) + { + if (pParams->lut3DInfo.Enabled) + { + const mfxU16 lut17_seg_size = 17, lut17_mul_size = 32; + const mfxU16 lut33_seg_size = 33, lut33_mul_size = 64; + const mfxU16 lut65_seg_size = 65, lut65_mul_size = 128; + + VAProcFilterParameterBuffer3DLUT lut3d_param = {}; + + lut3d_param.type = VAProcFilter3DLUT; + lut3d_param.lut_surface = *((VASurfaceID*)pParams->lut3DInfo.MemId); + lut3d_param.bit_depth = 16; + lut3d_param.num_channel = 4; + switch(pParams->lut3DInfo.MemLayout) + { + case MFX_3DLUT_MEMORY_LAYOUT_INTEL_17LUT: + lut3d_param.lut_size = lut17_seg_size; + lut3d_param.lut_stride[0] = lut17_seg_size; + lut3d_param.lut_stride[1] = lut17_seg_size; + lut3d_param.lut_stride[2] = lut17_mul_size; + break; + case MFX_3DLUT_MEMORY_LAYOUT_INTEL_33LUT: + case MFX_3DLUT_MEMORY_LAYOUT_DEFAULT: + lut3d_param.lut_size = lut33_seg_size; + lut3d_param.lut_stride[0] = lut33_seg_size; + lut3d_param.lut_stride[1] = lut33_seg_size; + lut3d_param.lut_stride[2] = lut33_mul_size; + break; + case MFX_3DLUT_MEMORY_LAYOUT_INTEL_65LUT: + lut3d_param.lut_size = lut65_seg_size; + lut3d_param.lut_stride[0] = lut65_seg_size; + lut3d_param.lut_stride[1] = lut65_seg_size; + lut3d_param.lut_stride[2] = lut65_mul_size; + break; + default: + break; + } + + switch(pParams->lut3DInfo.ChannelMapping) + { + case MFX_3DLUT_CHANNEL_MAPPING_RGB_RGB: + case MFX_3DLUT_CHANNEL_MAPPING_DEFAULT: + lut3d_param.channel_mapping = VA_3DLUT_CHANNEL_RGB_RGB; + break; + case MFX_3DLUT_CHANNEL_MAPPING_YUV_RGB: + lut3d_param.channel_mapping = VA_3DLUT_CHANNEL_YUV_RGB; + break; + case MFX_3DLUT_CHANNEL_MAPPING_VUY_RGB: + lut3d_param.channel_mapping = VA_3DLUT_CHANNEL_VUY_RGB; + break; + default: + break; + } + + /* create 3dlut fitler buffer */ + vaSts = vaCreateBuffer((void*)m_vaDisplay, + m_vaContextVPP, + VAProcFilterParameterBufferType, + sizeof(lut3d_param), + 1, + &lut3d_param, + &m_3dlutFilterID); + m_filterBufs[m_numFilterBufs++] = m_3dlutFilterID; + } + } + if (pParams->detailFactor || pParams->bDetailAutoAdjust) { /* Buffer was created earlier and it's time to refresh its value */ @@ -1209,6 +1312,12 @@ mfxStatus VAAPIVideoProcessing::Execute(mfxExecuteParams *pParams) if(pParams->VideoSignalInfo[index].TransferMatrix != MFX_TRANSFERMATRIX_UNKNOWN) { m_pipelineParam[0].surface_color_standard = (MFX_TRANSFERMATRIX_BT709 == pParams->VideoSignalInfo[index].TransferMatrix ? VAProcColorStandardBT709 : VAProcColorStandardBT601); + switch (pParams->VideoSignalInfo[index].ColourPrimary) + { + case MFX_COLOUR_PRIMARY_BT2020: + m_pipelineParam[0].surface_color_standard = VAProcColorStandardBT2020; + break; + } } if(pParams->VideoSignalInfo[index].NominalRange != MFX_NOMINALRANGE_UNKNOWN) @@ -1233,6 +1342,9 @@ mfxStatus VAAPIVideoProcessing::Execute(mfxExecuteParams *pParams) #endif // #ifdef MFX_ENABLE_VPP_VIDEO_SIGNAL } + //m_pipelineParam[0].surface_color_standard = VAProcColorStandardBT2020; + //m_pipelineParam[0].output_color_standard = VAProcColorStandardBT709; + m_pipelineParam[0].input_color_properties.chroma_sample_location = VA_CHROMA_SITING_UNKNOWN; m_pipelineParam[0].output_color_properties.chroma_sample_location = VA_CHROMA_SITING_UNKNOWN; diff --git a/api/include/mfxcommon.h b/api/include/mfxcommon.h index 0171d6d522..5cf389de47 100755 --- a/api/include/mfxcommon.h +++ b/api/include/mfxcommon.h @@ -206,6 +206,19 @@ typedef struct { } mfxPlatform; MFX_PACK_END() +/* The mfxResourceType enumerator specifies types of different native data frames and buffers. */ +typedef enum { + MFX_RESOURCE_SYSTEM_SURFACE = 1, /*!< System memory. */ + MFX_RESOURCE_VA_SURFACE = 2, /*!< VA surface. */ + MFX_RESOURCE_VA_BUFFER = 3, /*!< VA buffer. */ + MFX_RESOURCE_DX9_SURFACE = 4, /*!< IDirect3DSurface9. */ + MFX_RESOURCE_DX11_TEXTURE = 5, /*!< ID3D11Texture2D. */ + MFX_RESOURCE_DX12_RESOURCE = 6, /*!< ID3D12Resource. */ + MFX_RESOURCE_DMA_RESOURCE = 7, /*!< DMA resource. */ + MFX_RESOURCE_HDDLUNITE_REMOTE_MEMORY = 8, /*!< HDDL Unite Remote memory handle. */ +} mfxResourceType; + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/api/include/mfxdefs.h b/api/include/mfxdefs.h index 2c288c7f87..07be4ca5d3 100644 --- a/api/include/mfxdefs.h +++ b/api/include/mfxdefs.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 Intel Corporation +// Copyright (c) 2019-2021 Intel Corporation // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -242,6 +242,35 @@ typedef enum } mfxStatus; +typedef enum { + MFX_DATA_TYPE_UNSET = 0, /*!< Undefined type. */ + MFX_DATA_TYPE_U8, /*!< 8-bit unsigned integer. */ + MFX_DATA_TYPE_I8, /*!< 8-bit signed integer. */ + MFX_DATA_TYPE_U16, /*!< 16-bit unsigned integer. */ + MFX_DATA_TYPE_I16, /*!< 16-bit signed integer. */ + MFX_DATA_TYPE_U32, /*!< 32-bit unsigned integer. */ + MFX_DATA_TYPE_I32, /*!< 32-bit signed integer. */ + MFX_DATA_TYPE_U64, /*!< 64-bit unsigned integer. */ + MFX_DATA_TYPE_I64, /*!< 64-bit signed integer. */ + MFX_DATA_TYPE_F32, /*!< 32-bit single precision floating point. */ + MFX_DATA_TYPE_F64, /*!< 64-bit double precision floating point. */ +}mfxDataType; + +/*! The mfxVariantType enumerator data types for mfxVarianf type. */ +typedef enum { + MFX_VARIANT_TYPE_UNSET = 0, /*!< Undefined type. */ + MFX_VARIANT_TYPE_U8 = 1, /*!< 8-bit unsigned integer. */ + MFX_VARIANT_TYPE_I8, /*!< 8-bit signed integer. */ + MFX_VARIANT_TYPE_U16, /*!< 16-bit unsigned integer. */ + MFX_VARIANT_TYPE_I16, /*!< 16-bit signed integer. */ + MFX_VARIANT_TYPE_U32, /*!< 32-bit unsigned integer. */ + MFX_VARIANT_TYPE_I32, /*!< 32-bit signed integer. */ + MFX_VARIANT_TYPE_U64, /*!< 64-bit unsigned integer. */ + MFX_VARIANT_TYPE_I64, /*!< 64-bit signed integer. */ + MFX_VARIANT_TYPE_F32, /*!< 32-bit single precision floating point. */ + MFX_VARIANT_TYPE_F64, /*!< 64-bit double precision floating point. */ + MFX_VARIANT_TYPE_PTR, /*!< Generic type pointer. */ +} mfxVariantType; // Application #if defined(MFX_DISPATCHER_EXPOSED_PREFIX) diff --git a/api/include/mfxstructures.h b/api/include/mfxstructures.h index d4b8b96bf8..be6bfe3f34 100644 --- a/api/include/mfxstructures.h +++ b/api/include/mfxstructures.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 Intel Corporation +// Copyright (c) 2018-2021 Intel Corporation // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -949,6 +949,7 @@ enum { MFX_EXTBUFF_VPP_ROTATION = MFX_MAKEFOURCC('R','O','T',' '), MFX_EXTBUFF_ENCODED_SLICES_INFO = MFX_MAKEFOURCC('E','N','S','I'), MFX_EXTBUFF_VPP_SCALING = MFX_MAKEFOURCC('V','S','C','L'), + MFX_EXTBUFF_VPP_3DLUT = MFX_MAKEFOURCC('T','D','L','T'), MFX_EXTBUFF_HEVC_REFLIST_CTRL = MFX_EXTBUFF_AVC_REFLIST_CTRL, MFX_EXTBUFF_HEVC_REFLISTS = MFX_EXTBUFF_AVC_REFLISTS, MFX_EXTBUFF_HEVC_TEMPORAL_LAYERS = MFX_EXTBUFF_AVC_TEMPORAL_LAYERS, @@ -2121,6 +2122,94 @@ typedef struct { } mfxExtVPPScaling; MFX_PACK_END() +/*! The mfx3DLutChannelMapping enumerator specifies the channel mapping of 3DLUT. */ +typedef enum { + MFX_3DLUT_CHANNEL_MAPPING_DEFAULT = 0, /*!< Default 3DLUT channel mapping. The library selects the most appropriate 3DLUT channel mapping. */ + MFX_3DLUT_CHANNEL_MAPPING_RGB_RGB = 1, /*!< 3DLUT RGB channels maps to RGB channels. */ + MFX_3DLUT_CHANNEL_MAPPING_YUV_RGB = 2, /*!< 3DLUT YUV channels maps to RGB channels. */ + MFX_3DLUT_CHANNEL_MAPPING_VUY_RGB = 3, /*!< 3DLUT VUY channels maps to RGB channels. */ +} mfx3DLutChannelMapping; + +/*! The mfx3DLutMemoryLayout enumerator specifies the memory layout of 3DLUT. */ +typedef enum { + MFX_3DLUT_MEMORY_LAYOUT_DEFAULT = 0, /*!< Default 3DLUT memory layout. The library selects the most appropriate 3DLUT memory layout.*/ + + MFX_3DLUT_MEMORY_LAYOUT_VENDOR = 0x1000, /*!< The enumeration to separate default above and vendor specific.*/ + /*! + Intel specific memory layout. The enumerator indicates the attributes and memory layout of 3DLUT. + 3DLUT size is 17(the number of elements per dimension), 4 channels(3 valid channels, 1 channel is reserved), every channel must be 16-bit unsigned integer. + 3DLUT contains 17x17x32 entries with holes that are not filled. Take RGB as example, the nodes RxGx17 to RxGx31 are not filled, are "don't care" bits, and not accessed for the 17x17x17 nodes. + */ + MFX_3DLUT_MEMORY_LAYOUT_INTEL_17LUT = MFX_3DLUT_MEMORY_LAYOUT_VENDOR + 1, + /*! + Intel specific memory layout. The enumerator indicates the attributes and memory layout of 3DLUT. + 3DLUT size is 33(the number of elements per dimension), 4 channels(3 valid channels, 1 channel is reserved), every channel must be 16-bit unsigned integer. + 3DLUT contains 33x33x64 entries with holes that are not filled. Take RGB as example, the nodes RxGx33 to RxGx63 are not filled, are "don't care" bits, and not accessed for the 33x33x33 nodes. + */ + MFX_3DLUT_MEMORY_LAYOUT_INTEL_33LUT = MFX_3DLUT_MEMORY_LAYOUT_VENDOR + 2, + /*! + Intel specific memory layout. The enumerator indicates the attributes and memory layout of 3DLUT. + 3DLUT size is 65(the number of elements per dimension), 4 channels(3 valid channels, 1 channel is reserved), every channel must be 16-bit unsigned integer. + 3DLUT contains 65x65x128 entries with holes that are not filled. Take RGB as example, the nodes RxGx65 to RxGx127 are not filled, are "don't care" bits, and not accessed for the 65x65x65 nodes. + */ + MFX_3DLUT_MEMORY_LAYOUT_INTEL_65LUT = MFX_3DLUT_MEMORY_LAYOUT_VENDOR + 3, +} mfx3DLutMemoryLayout; + +MFX_PACK_BEGIN_STRUCT_W_PTR() +/*! + A hint structure that configures the data channel. +*/ +typedef struct { + mfxDataType DataType; /*!< Data type, mfxDataType enumerator.*/ + mfxU32 Size; /*!< Size of Look up table, the number of elements per dimension.*/ + union + { + mfxU8* Data; /*!< The pointer to 3DLUT data, 8 bit unsigned integer.*/ + mfxU16* Data16; /*!< The pointer to 3DLUT data, 16 bit unsigned integer.*/ + }; + mfxU32 reserved[4]; /*!< Reserved for future extension.*/ +} mfxChannel; +MFX_PACK_END() + +MFX_PACK_BEGIN_USUAL_STRUCT() +/*! + A hint structure that configures 3DLUT system buffer. +*/ +typedef struct { + mfxChannel Channel[3]; /*!< 3 Channels, can be RGB or YUV, mfxChannel structure.*/ + mfxU32 reserved[8]; /*!< Reserved for future extension.*/ +} mfx3DLutSystemBuffer; +MFX_PACK_END() + +MFX_PACK_BEGIN_USUAL_STRUCT() +/*! + A hint structure that configures 3DLUT video buffer. +*/ +typedef struct { + mfxDataType DataType; /*!< Data type, mfxDataType enumerator.*/ + mfx3DLutMemoryLayout MemLayout; /*!< Indicates 3DLUT memory layout. mfx3DLutMemoryLayout enumerator.*/ + mfxMemId MemId; /*!< Memory ID for holding the lookup table data. One MemID is dedicated for one instance of VPP.*/ + mfxU32 reserved[8]; /*!< Reserved for future extension.*/ +} mfx3DLutVideoBuffer; +MFX_PACK_END() + +MFX_PACK_BEGIN_USUAL_STRUCT() +/*! + A hint structure that configures 3DLUT filter. +*/ +typedef struct { + mfxExtBuffer Header; /*!< Extension buffer header. Header.BufferId must be equal to MFX_EXTBUFF_VPP_3DLUT..*/ + mfx3DLutChannelMapping ChannelMapping; /*!< Indicates 3DLUT channel mapping. mfx3DLutChannelMapping enumerator.*/ + mfxResourceType BufferType; /*!< Indicates 3DLUT buffer type. mfxResourceType enumerator, can be system memory, VA surface, DX11 texture/buffer etc.*/ + union + { + mfx3DLutSystemBuffer SystemBuffer; /*!< The 3DLUT system buffer. mfx3DLutSystemBuffer structure describes the details of the buffer.*/ + mfx3DLutVideoBuffer VideoBuffer; /*!< The 3DLUT video buffer. mfx3DLutVideoBuffer describes the details of 3DLUT video buffer.*/ + }; + mfxU32 reserved[4]; /*!< Reserved for future extension.*/ +} mfxExtVPP3DLut; +MFX_PACK_END() + #if (MFX_VERSION >= MFX_VERSION_NEXT) /* SceneChangeType */ diff --git a/samples/sample_common/include/base_allocator.h b/samples/sample_common/include/base_allocator.h index f01388e612..e4280ca4b7 100644 --- a/samples/sample_common/include/base_allocator.h +++ b/samples/sample_common/include/base_allocator.h @@ -51,6 +51,9 @@ class MFXFrameAllocator : public mfxFrameAllocator virtual mfxStatus GetFrameHDL(mfxMemId mid, mfxHDL *handle) = 0; virtual mfxStatus FreeFrames(mfxFrameAllocResponse *response) = 0; + virtual mfxStatus Create3DLutMemory(mfxMemId memId, const char*lut3d_file_name) = 0; + virtual mfxStatus Release3DLutMemory(mfxMemId memId) = 0; + private: static mfxStatus MFX_CDECL Alloc_(mfxHDL pthis, mfxFrameAllocRequest *request, mfxFrameAllocResponse *response); static mfxStatus MFX_CDECL Lock_(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr); @@ -80,6 +83,9 @@ class BaseFrameAllocator: public MFXFrameAllocator virtual mfxStatus ReallocFrame(mfxMemId midIn, const mfxFrameInfo *info, mfxU16 memType, mfxMemId *midOut); virtual mfxStatus FreeFrames(mfxFrameAllocResponse *response); + virtual mfxStatus Create3DLutMemory(mfxMemId memId, const char*lut3d_file_name) = 0; + virtual mfxStatus Release3DLutMemory(mfxMemId memId) = 0; + protected: std::mutex mtx; typedef std::list::iterator Iter; diff --git a/samples/sample_common/include/general_allocator.h b/samples/sample_common/include/general_allocator.h index c2c2324f67..fde938e62a 100644 --- a/samples/sample_common/include/general_allocator.h +++ b/samples/sample_common/include/general_allocator.h @@ -48,6 +48,9 @@ class GeneralAllocator : public BaseFrameAllocator virtual mfxStatus AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response); virtual mfxStatus ReallocImpl(mfxMemId midIn, const mfxFrameInfo *info, mfxU16 memType, mfxMemId *midOut); + virtual mfxStatus Create3DLutMemory(mfxMemId memId, const char*lut3d_file_name); + virtual mfxStatus Release3DLutMemory(mfxMemId memId); + void StoreFrameMids(bool isD3DFrames, mfxFrameAllocResponse *response); bool isD3DMid(mfxHDL mid); diff --git a/samples/sample_common/include/sample_utils.h b/samples/sample_common/include/sample_utils.h index fcba1d2f2a..fd1649e60c 100644 --- a/samples/sample_common/include/sample_utils.h +++ b/samples/sample_common/include/sample_utils.h @@ -512,6 +512,9 @@ template<>struct mfx_ext_buffer_id { template<>struct mfx_ext_buffer_id { enum {id = MFX_EXTBUFF_FEI_PPS}; }; +template<>struct mfx_ext_buffer_id { + enum {id = MFX_EXTBUFF_VPP_3DLUT}; +}; constexpr uint16_t max_num_ext_buffers = 63 * 2; // '*2' is for max estimation if all extBuffer were 'paired' diff --git a/samples/sample_common/include/sysmem_allocator.h b/samples/sample_common/include/sysmem_allocator.h index 0d796bbe42..9af4c624b8 100644 --- a/samples/sample_common/include/sysmem_allocator.h +++ b/samples/sample_common/include/sysmem_allocator.h @@ -62,6 +62,9 @@ class SysMemFrameAllocator: public BaseFrameAllocator virtual mfxStatus AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response); virtual mfxStatus ReallocImpl(mfxMemId midIn, const mfxFrameInfo *info, mfxU16 memType, mfxMemId *midOut); + virtual mfxStatus Create3DLutMemory(mfxMemId memId, const char*lut3d_file_name) {return MFX_ERR_NONE; } + virtual mfxStatus Release3DLutMemory(mfxMemId memId) {return MFX_ERR_NONE; } + MFXBufferAllocator *m_pBufferAllocator; bool m_bOwnBufferAllocator; diff --git a/samples/sample_common/include/vaapi_allocator.h b/samples/sample_common/include/vaapi_allocator.h index 385d280def..b466eb4d5e 100644 --- a/samples/sample_common/include/vaapi_allocator.h +++ b/samples/sample_common/include/vaapi_allocator.h @@ -88,6 +88,9 @@ class vaapiFrameAllocator: public BaseFrameAllocator virtual mfxStatus Init(mfxAllocatorParams *pParams); virtual mfxStatus Close(); + virtual mfxStatus Create3DLutMemory(mfxMemId memId, const char*lut3d_file_name); + virtual mfxStatus Release3DLutMemory(mfxMemId memId); + protected: DISALLOW_COPY_AND_ASSIGN(vaapiFrameAllocator); diff --git a/samples/sample_common/src/base_allocator.cpp b/samples/sample_common/src/base_allocator.cpp index 4938cd99c5..e9cadfc044 100644 --- a/samples/sample_common/src/base_allocator.cpp +++ b/samples/sample_common/src/base_allocator.cpp @@ -88,10 +88,13 @@ mfxStatus MFXFrameAllocator::GetHDL_(mfxHDL pthis, mfxMemId mid, mfxHDL *handle) BaseFrameAllocator::BaseFrameAllocator() { + printf("BaseFrameAllocator::BaseFrameAllocator!\n"); } BaseFrameAllocator::~BaseFrameAllocator() { + printf("BaseFrameAllocator::~BaseFrameAllocator!\n"); + } mfxStatus BaseFrameAllocator::CheckRequestType(mfxFrameAllocRequest *request) @@ -102,6 +105,8 @@ mfxStatus BaseFrameAllocator::CheckRequestType(mfxFrameAllocRequest *request) // check that Media SDK component is specified in request if ((request->Type & MEMTYPE_FROM_MASK) != 0) return MFX_ERR_NONE; + else if (request->Type == MFX_MEMTYPE_EXTERNAL_FRAME) + return MFX_ERR_NONE; else return MFX_ERR_UNSUPPORTED; } @@ -113,6 +118,8 @@ mfxStatus BaseFrameAllocator::ReallocFrame(mfxMemId midIn, const mfxFrameInfo *i mfxStatus BaseFrameAllocator::AllocFrames(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response) { + printf("BaseFrameAllocator::AllocFrames!\n"); + if (0 == request || 0 == response || 0 == request->NumFrameSuggested) return MFX_ERR_MEMORY_ALLOC; @@ -240,6 +247,19 @@ mfxStatus BaseFrameAllocator::Close() return MFX_ERR_NONE; } +#if 0 +mfxStatus BaseFrameAllocator::Create3DLutMemory(mfxMemId memId, const char*lut3d_file_name) +{ + printf("BaseFrameAllocator::Create3DLutMemory!\n"); + //Create3DLutMemory(memId, lut3d_file_name); + return MFX_ERR_NONE; +} +mfxStatus BaseFrameAllocator::Release3DLutMemory(mfxMemId memId) +{ + //Release3DLutMemory(memId); + return MFX_ERR_NONE; +} +#endif MFXBufferAllocator::MFXBufferAllocator() { diff --git a/samples/sample_common/src/general_allocator.cpp b/samples/sample_common/src/general_allocator.cpp index 258edfe709..f638c11389 100644 --- a/samples/sample_common/src/general_allocator.cpp +++ b/samples/sample_common/src/general_allocator.cpp @@ -170,3 +170,37 @@ bool GeneralAllocator::isD3DMid(mfxHDL mid) else return it->second; } + +mfxStatus GeneralAllocator::Create3DLutMemory(mfxMemId memId, const char*lut3d_file_name) +{ + mfxStatus sts = MFX_ERR_NONE; +#ifdef LIBVA_SUPPORT + vaapiFrameAllocator* pAllocator = dynamic_cast(m_D3DAllocator.get()); + if (pAllocator) + { + sts = pAllocator->Create3DLutMemory(memId, lut3d_file_name); + } + else + { + sts = MFX_ERR_NULL_PTR; + } +#endif + return sts; +} +mfxStatus GeneralAllocator::Release3DLutMemory(mfxMemId memId) +{ + mfxStatus sts = MFX_ERR_NONE; +#ifdef LIBVA_SUPPORT + vaapiFrameAllocator* pAllocator = dynamic_cast(m_D3DAllocator.get()); + if (pAllocator) + { + sts = pAllocator->Release3DLutMemory(memId); + } + else + { + sts = MFX_ERR_NULL_PTR; + } +#endif + return sts; +} + diff --git a/samples/sample_common/src/vaapi_allocator.cpp b/samples/sample_common/src/vaapi_allocator.cpp index bf20b0dba9..e879040c76 100644 --- a/samples/sample_common/src/vaapi_allocator.cpp +++ b/samples/sample_common/src/vaapi_allocator.cpp @@ -102,10 +102,13 @@ vaapiFrameAllocator::vaapiFrameAllocator() , m_export_mode(vaapiAllocatorParams::DONOT_EXPORT) , m_exporter(NULL) { + printf("vaapiFrameAllocator::vaapiFrameAllocator!\n"); } vaapiFrameAllocator::~vaapiFrameAllocator() { + printf("vaapiFrameAllocator::~vaapiFrameAllocator!\n"); + Close(); delete m_libva; } @@ -743,4 +746,113 @@ mfxStatus vaapiFrameAllocator::GetFrameHDL(mfxMemId mid, mfxHDL *handle) return MFX_ERR_NONE; } +mfxStatus vaapiFrameAllocator::Create3DLutMemory(mfxMemId memId, const char*lut3d_file_name) +{ + printf("vaapiFrameAllocator::Create3DLutMemory!\n"); + VAStatus va_status = VA_STATUS_SUCCESS; + VAImage surface_image = {}; + void *surface_p = NULL; + mfxU32 frame_size = 0, lut3d_size = 0; + mfxU8* newImageBuffer = NULL; + VASurfaceID surface_id = VA_INVALID_ID; + mfxU32 seg_size = 65, mul_size = 128; + + if (!memId) { + return MFX_ERR_NULL_PTR; + } + + FILE *f3dlut = NULL; + f3dlut = fopen(lut3d_file_name,"rb"); + if (!f3dlut) + { + printf("Fail to open 3DLUT data file!\n"); + return MFX_ERR_NULL_PTR; + } + + // create VA surface + VASurfaceAttrib surface_attrib = {}; + surface_attrib.type = VASurfaceAttribPixelFormat; + surface_attrib.flags = VA_SURFACE_ATTRIB_SETTABLE; + surface_attrib.value.type = VAGenericValueTypeInteger; + surface_attrib.value.value.i = VA_FOURCC_RGBA; + + va_status = m_libva->vaCreateSurfaces(m_dpy, + VA_RT_FORMAT_RGB32, + seg_size * mul_size, + seg_size * 2, + &surface_id, + 1, + &surface_attrib, + 1); + if (va_status != VA_STATUS_SUCCESS) { + printf("Load3DLutVAAPI vaCreateSurfaces 3dlut surface failed\n"); + return MFX_ERR_UNSUPPORTED; + } + + va_status = m_libva->vaSyncSurface (m_dpy,surface_id); + if (va_status != VA_STATUS_SUCCESS) { + printf("Load3DLutVAAPI vaSyncSurface 3dlut surface failed\n"); + return MFX_ERR_UNSUPPORTED; + } + + va_status = m_libva->vaDeriveImage(m_dpy, surface_id, &surface_image); + if (va_status != VA_STATUS_SUCCESS) { + printf("Load3DLutVAAPI vaDeriveImage from 3dlut surface failed\n"); + return MFX_ERR_UNSUPPORTED; + } + + va_status = m_libva->vaMapBuffer(m_dpy, surface_image.buf, &surface_p); + if (va_status != VA_STATUS_SUCCESS) { + printf("Load3DLutVAAPI vaMapBuffer from 3dlut surface failed\n"); + return MFX_ERR_UNSUPPORTED; + } + + if (surface_image.format.fourcc == VA_FOURCC_RGBA && f3dlut) { + /* 3DLUT surface is allocated to 32 bit RGB */ + frame_size = surface_image.width * surface_image.height * 4; + newImageBuffer = (mfxU8*)malloc(frame_size); + + fseek(f3dlut, 0L, SEEK_END); + lut3d_size = ftell(f3dlut); + rewind(f3dlut); + + uint32_t real_size = (frame_size > lut3d_size) ? lut3d_size : frame_size; + + uint32_t read_size = fread(newImageBuffer, 1, real_size, f3dlut); + memcpy(surface_p, newImageBuffer, read_size); + printf("upload_data_to_3dlut: 3DLUT surface width %d, height %d, pitch %d, frame size %d, 3dlut file size: %d\n", surface_image.width, surface_image.height, surface_image.pitches[0],frame_size, read_size); + } + + if (newImageBuffer) { + free(newImageBuffer); + newImageBuffer = NULL; + } + + m_libva->vaUnmapBuffer(m_dpy, surface_image.buf); + m_libva->vaDestroyImage(m_dpy, surface_image.image_id); + + *((VASurfaceID*)memId) = surface_id; + + if (f3dlut) + { + fclose(f3dlut); + f3dlut = NULL; + } + + return MFX_ERR_NONE; + +} + +mfxStatus vaapiFrameAllocator::Release3DLutMemory(mfxMemId memId) +{ + VAStatus va_status = VA_STATUS_SUCCESS; + mfxStatus mfx_res = MFX_ERR_NONE; + + VASurfaceID surface_id = *((VASurfaceID*)memId); + va_status= m_libva->vaDestroySurfaces(m_dpy, &surface_id, 1); + mfx_res = va_to_mfx_status(va_status); + + return MFX_ERR_NONE; +} + #endif // #if defined(LIBVA_SUPPORT) diff --git a/samples/sample_multi_transcode/include/pipeline_transcode.h b/samples/sample_multi_transcode/include/pipeline_transcode.h index ea6f064afb..5021f787c6 100644 --- a/samples/sample_multi_transcode/include/pipeline_transcode.h +++ b/samples/sample_multi_transcode/include/pipeline_transcode.h @@ -369,6 +369,10 @@ namespace TranscodingSample bool shouldPrintPresets; bool rawInput; + + //3DLut Binary File + msdk_char str3DLutFile[MSDK_MAX_FILENAME_LEN] = {}; + bool bEnable3DLut; }; struct sInputParams: public __sInputParams @@ -932,6 +936,14 @@ namespace TranscodingSample bool bPrefferiGfx; bool bPrefferdGfx; #endif + + bool m_b3DLutEnable; + // 3DLUT video memory default is 65*65*128*4*2 bytes + mfxU32 m_n3DLutVMemId; + mfxU32 m_n3DLutVWidth; + mfxU32 m_n3DLutVHeight; + msdk_char* m_p3DLutFile; + private: DISALLOW_COPY_AND_ASSIGN(CTranscodingPipeline); diff --git a/samples/sample_multi_transcode/src/pipeline_transcode.cpp b/samples/sample_multi_transcode/src/pipeline_transcode.cpp index 980e635c38..76599dfeaf 100644 --- a/samples/sample_multi_transcode/src/pipeline_transcode.cpp +++ b/samples/sample_multi_transcode/src/pipeline_transcode.cpp @@ -1,5 +1,5 @@ /******************************************************************************\ -Copyright (c) 2005-2020, Intel Corporation +Copyright (c) 2005-2021, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -130,6 +130,8 @@ sInputParams::sInputParams() : __sInputParams() bDecoderPostProcessing = false; bROIasQPMAP = false; #endif + bEnable3DLut = false; + } CTranscodingPipeline::CTranscodingPipeline(): @@ -201,10 +203,17 @@ CTranscodingPipeline::CTranscodingPipeline(): m_nRotationAngle = 0; m_bROIasQPMAP = false; m_bExtMBQP = false; + + m_b3DLutEnable = false; + m_n3DLutVMemId = 0xffffffff; + m_n3DLutVWidth = 65; + m_n3DLutVHeight = 65*128*2; + m_p3DLutFile = NULL; } //CTranscodingPipeline::CTranscodingPipeline() CTranscodingPipeline::~CTranscodingPipeline() { + m_b3DLutEnable = false; Close(); } //CTranscodingPipeline::CTranscodingPipeline() @@ -371,6 +380,11 @@ mfxStatus CTranscodingPipeline::VPPPreInit(sInputParams *pParams) m_bIsVpp = true; } + if (pParams->bEnable3DLut) + { + m_bIsVpp = true; + } + if (m_bIsVpp) { sts = InitVppMfxParams(pParams); @@ -3130,6 +3144,29 @@ mfxStatus CTranscodingPipeline::InitVppMfxParams(sInputParams *pInParams) MFX_PICSTRUCT_FIELD_BFF); } + if (pInParams->bEnable3DLut) + { + auto lut = m_mfxVppParams.AddExtBuffer(); + + lut->ChannelMapping = MFX_3DLUT_CHANNEL_MAPPING_RGB_RGB; + lut->BufferType = MFX_RESOURCE_VA_SURFACE; + + lut->VideoBuffer.DataType = MFX_DATA_TYPE_U16; + lut->VideoBuffer.MemLayout = MFX_3DLUT_MEMORY_LAYOUT_INTEL_65LUT; + lut->VideoBuffer.MemId = &m_n3DLutVMemId; + + m_b3DLutEnable = true; + m_p3DLutFile = pInParams->str3DLutFile; + + if (m_mfxVppParams.vpp.In.FourCC == MFX_FOURCC_P010) + { + m_mfxVppParams.vpp.In.BitDepthLuma = 10; + m_mfxVppParams.vpp.In.BitDepthChroma = 10; + m_mfxVppParams.vpp.In.Shift = 1; + m_mfxVppParams.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + } + } + if (enhFilterCount) { auto doUse = m_mfxVppParams.AddExtBuffer(); @@ -3200,7 +3237,7 @@ mfxStatus CTranscodingPipeline::AllocFrames(mfxFrameAllocRequest *pRequest, bool mfxFrameAllocResponse *pResponse = isDecAlloc ? &m_mfxDecResponse : &m_mfxEncResponse; // no actual memory is allocated if opaque memory type is used - if (!m_bUseOpaqueMemory) + if ((!m_bUseOpaqueMemory) || (pRequest->Type == MFX_MEMTYPE_EXTERNAL_FRAME)) { sts = m_pMFXAllocator->Alloc(m_pMFXAllocator->pthis, pRequest, pResponse); MSDK_CHECK_STATUS(sts, "m_pMFXAllocator->Alloc failed"); @@ -3394,6 +3431,12 @@ mfxStatus CTranscodingPipeline::AllocFrames() } } + if (m_b3DLutEnable) + { + sts = m_pMFXAllocator->Create3DLutMemory((void*)&m_n3DLutVMemId, m_p3DLutFile); + MSDK_CHECK_STATUS(sts, "m_pMFXAllocator->Create3DLutMemory failed"); + } + return MFX_ERR_NONE; } @@ -4277,6 +4320,11 @@ void CTranscodingPipeline::Close() } #endif + if (m_b3DLutEnable) + { + m_pMFXAllocator->Release3DLutMemory((void*)&m_n3DLutVMemId); + } + // free allocated surfaces AFTER closing components FreeFrames(); diff --git a/samples/sample_multi_transcode/src/transcode_utils.cpp b/samples/sample_multi_transcode/src/transcode_utils.cpp index 515783383c..9261b1f608 100644 --- a/samples/sample_multi_transcode/src/transcode_utils.cpp +++ b/samples/sample_multi_transcode/src/transcode_utils.cpp @@ -1,5 +1,5 @@ /******************************************************************************\ -Copyright (c) 2005-2020, Intel Corporation +Copyright (c) 2005-2021, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -363,6 +363,7 @@ void TranscodingSample::PrintHelp() #endif msdk_printf(MSDK_STRING(" -vpp_comp_dump Dump of VPP Composition's output into file. Valid if with -vpp_comp* options\n")); msdk_printf(MSDK_STRING(" -vpp_comp_dump null_render Disabling rendering after VPP Composition. This is for performance measurements\n")); + msdk_printf(MSDK_STRING(" -3dlut Enable 3DLUT VPP filter\n")); #if MFX_VERSION >= 1022 msdk_printf(MSDK_STRING(" -dec_postproc Resize after decoder using direct pipe (should be used in decoder session)\n")); msdk_printf(MSDK_STRING(" -single_texture_d3d11 single texture mode for d3d11 allocator \n")); @@ -1534,6 +1535,24 @@ mfxStatus ParseVPPCmdLine(msdk_char *argv[], mfxU32 argc, mfxU32& index, Transco } return MFX_ERR_NONE; } + else if (0 == msdk_strcmp(argv[index], MSDK_STRING("-3dlut"))) + { + VAL_CHECK(index+1 == argc, index, argv[index]); + index++; + // 3dlut file + if (msdk_strlen(argv[index]) < MSDK_ARRAY_LEN(params->str3DLutFile)) + { + msdk_opt_read(argv[index], params->str3DLutFile); + params->bEnable3DLut = true; + } + else + { + params->bEnable3DLut = false; + return MFX_ERR_UNSUPPORTED; + } + + return MFX_ERR_NONE; + } return MFX_ERR_MORE_DATA; } diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index e638b9ee3c..ce1cc0518f 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -31,12 +31,14 @@ if( PKG_LIBDRM_FOUND ) add_subdirectory(simple_3_encode_vmem) add_subdirectory(simple_3_encode_hevc10) add_subdirectory(simple_3_encode_vmem_async) + add_subdirectory(simple_4_vpp_resize_3dlut_vmem) add_subdirectory(simple_4_vpp_resize_denoise) add_subdirectory(simple_4_vpp_resize_denoise_vmem) add_subdirectory(simple_5_transcode) add_subdirectory(simple_5_transcode_opaque) add_subdirectory(simple_5_transcode_opaque_async) add_subdirectory(simple_5_transcode_opaque_async_vppresize) + add_subdirectory(simple_5_transcode_opaque_async_vppresize_3dlut) add_subdirectory(simple_5_transcode_vmem) add_subdirectory(simple_6_decode_vpp_postproc) add_subdirectory(simple_6_encode_vmem_lowlatency) diff --git a/tutorials/common/common_utils.cpp b/tutorials/common/common_utils.cpp index 541ae7f79c..2bdbd510ca 100644 --- a/tutorials/common/common_utils.cpp +++ b/tutorials/common/common_utils.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 Intel Corporation +// Copyright (c) 2019-2021 Intel Corporation // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -117,15 +117,14 @@ void CloseFile(FILE* fHdl) } mfxStatus ReadPlaneData(mfxU16 w, mfxU16 h, mfxU8* buf, mfxU8* ptr, - mfxU16 pitch, mfxU16 offset, FILE* fSource) + mfxU16 pitch, mfxU16 offset, FILE* fSource, mfxU16 nBitDepth) { mfxU32 nBytesRead; for (mfxU16 i = 0; i < h; i++) { - nBytesRead = (mfxU32) fread(buf, 1, w, fSource); - if (w != nBytesRead) + nBytesRead = (mfxU32) fread(buf, 1, w * (nBitDepth / 8), fSource); + if (w * (nBitDepth / 8) != nBytesRead) return MFX_ERR_MORE_DATA; - for (mfxU16 j = 0; j < w; j++) - ptr[i * pitch + j * 2 + offset] = buf[j]; + memcpy(ptr + i * pitch + offset * (nBitDepth / 8), buf, w * (nBitDepth / 8)); } return MFX_ERR_NONE; } @@ -145,6 +144,7 @@ mfxStatus LoadRawFrame(mfxFrameSurface1* pSurface, FILE* fSource) mfxU32 nBytesRead; mfxU16 w, h, i, pitch; mfxU8* ptr; + mfxU32 nBitDepth = 8; mfxFrameInfo* pInfo = &pSurface->Info; mfxFrameData* pData = &pSurface->Data; @@ -156,31 +156,48 @@ mfxStatus LoadRawFrame(mfxFrameSurface1* pSurface, FILE* fSource) h = pInfo->Height; } + if (pInfo->FourCC == MFX_FOURCC_P010) { + nBitDepth = 16; + } + pitch = pData->Pitch; ptr = pData->Y + pInfo->CropX + pInfo->CropY * pData->Pitch; // read luminance plane for (i = 0; i < h; i++) { - nBytesRead = (mfxU32) fread(ptr + i * pitch, 1, w, fSource); - if (w != nBytesRead) + nBytesRead = (mfxU32) fread(ptr + i * pitch, 1, w * (nBitDepth / 8), fSource); + if (w * (nBitDepth / 8) != nBytesRead) return MFX_ERR_MORE_DATA; } - mfxU8 buf[2048]; // maximum supported chroma width for nv12 - w /= 2; - h /= 2; + const mfxU32 nBufferLength = 4096; + mfxU8 buf[nBufferLength] = {}; // maximum supported chroma width for nv12 ptr = pData->UV + pInfo->CropX + (pInfo->CropY / 2) * pitch; - if (w > 2048) - return MFX_ERR_UNSUPPORTED; - // load V - sts = ReadPlaneData(w, h, buf, ptr, pitch, 1, fSource); - if (MFX_ERR_NONE != sts) - return sts; - // load U - ReadPlaneData(w, h, buf, ptr, pitch, 0, fSource); - if (MFX_ERR_NONE != sts) - return sts; + // load UV for P010 and NV12 + if ((pInfo->FourCC == MFX_FOURCC_P010) || (pInfo->FourCC == MFX_FOURCC_NV12)) { + h /= 2; + if ((w * nBitDepth /8) > 4096) + return MFX_ERR_UNSUPPORTED; + sts = ReadPlaneData(w, h, buf, ptr, pitch, 0, fSource, nBitDepth); + if (MFX_ERR_NONE != sts) + return sts; + } + else { + w /= 2; + h /= 2; + if (w > 4096) + return MFX_ERR_UNSUPPORTED; + + // load V + sts = ReadPlaneData(w, h, buf, ptr, pitch, 1, fSource, nBitDepth); + if (MFX_ERR_NONE != sts) + return sts; + // load U + sts = ReadPlaneData(w, h, buf, ptr, pitch, 0, fSource, nBitDepth); + if (MFX_ERR_NONE != sts) + return sts; + } return MFX_ERR_NONE; } @@ -371,19 +388,47 @@ mfxStatus WriteRawFrame(mfxFrameSurface1* pSurface, FILE* fSink) } } } + else if (pInfo->FourCC == MFX_FOURCC_NV12) + { + for (i = 0; i < pInfo->CropH; i++) + { + sts = WriteSection(pData->Y, 1, pInfo->CropW, pInfo, pData, i, 0, fSink); + if (sts != MFX_ERR_NONE) return sts; + } + + h = pInfo->CropH / 2; + for (i = 0; i < h; i++) + { + sts = WriteSection(pData->UV, 1, pInfo->CropW, pInfo, pData, i, 0, fSink); + if (sts != MFX_ERR_NONE) return sts; + } + } else { for (i = 0; i < pInfo->CropH; i++) + { sts = WriteSection(pData->Y, 1, pInfo->CropW, pInfo, pData, i, 0, fSink); + if (sts != MFX_ERR_NONE) return sts; + } h = pInfo->CropH / 2; w = pInfo->CropW; for (i = 0; i < h; i++) + { for (j = 0; j < w; j += 2) + { sts = WriteSection(pData->UV, 2, 1, pInfo, pData, i, j, fSink); + if (sts != MFX_ERR_NONE) return sts; + } + } for (i = 0; i < h; i++) + { for (j = 1; j < w; j += 2) + { sts = WriteSection(pData->UV, 2, 1, pInfo, pData, i, j, fSink); + if (sts != MFX_ERR_NONE) return sts; + } + } } return sts; diff --git a/tutorials/common/common_utils.h b/tutorials/common/common_utils.h index ae7a66b33d..448fcff6aa 100644 --- a/tutorials/common/common_utils.h +++ b/tutorials/common/common_utils.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Intel Corporation +// Copyright (c) 2019-2021 Intel Corporation // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -116,6 +116,9 @@ void ClearYUVSurfaceSysMem(mfxFrameSurface1* pSfc, mfxU16 width, mfxU16 height); void ClearYUVSurfaceVMem(mfxMemId memId); void ClearRGBSurfaceVMem(mfxMemId memId); +mfxStatus Create3DLutMemory(mfxMemId memId, mfxHDL hdl, const char*lut3d_file_name); +mfxStatus Release3DLutMemory(mfxMemId memId, mfxHDL hdl); + // Get free raw frame surface int GetFreeSurfaceIndex(mfxFrameSurface1** pSurfacesPool, mfxU16 nPoolSize); int GetFreeSurfaceIndex(const std::vector& pSurfacesPool); diff --git a/tutorials/common/common_utils_windows.cpp b/tutorials/common/common_utils_windows.cpp index 6bbf3f6711..0707968666 100644 --- a/tutorials/common/common_utils_windows.cpp +++ b/tutorials/common/common_utils_windows.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Intel Corporation +// Copyright (c) 2019-2021 Intel Corporation // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -115,3 +115,14 @@ void ClearRGBSurfaceVMem(mfxMemId memId) #endif } +mfxStatus Create3DLutMemory(mfxMemId memId, mfxHDL hdl, const char*lut3d_file_name) +{ + return MFX_ERR_UNSUPPORTED; +} + +mfxStatus Release3DLutMemory(mfxMemId memId, mfxHDL hdl) +{ + return MFX_ERR_UNSUPPORTED; +} + + diff --git a/tutorials/common/common_vaapi.cpp b/tutorials/common/common_vaapi.cpp index 0f48f0363d..3ccc513435 100644 --- a/tutorials/common/common_vaapi.cpp +++ b/tutorials/common/common_vaapi.cpp @@ -179,6 +179,8 @@ unsigned int ConvertMfxFourccToVAFormat(mfxU32 fourcc) return VA_FOURCC_ARGB; case MFX_FOURCC_P8: return VA_FOURCC_P208; + case MFX_FOURCC_P010: + return VA_FOURCC_P010; default: assert(!"unsupported fourcc"); @@ -216,6 +218,7 @@ mfxStatus _simple_alloc(mfxFrameAllocRequest* request, mfxStatus mfx_res = MFX_ERR_NONE; VAStatus va_res = VA_STATUS_SUCCESS; unsigned int va_fourcc = 0; + unsigned int va_format = VA_RT_FORMAT_YUV420; VASurfaceID* surfaces = NULL; VASurfaceAttrib attrib; vaapiMemId* vaapi_mids = NULL, *vaapi_mid = NULL; @@ -232,7 +235,8 @@ mfxStatus _simple_alloc(mfxFrameAllocRequest* request, (VA_FOURCC_YV12 != va_fourcc) && (VA_FOURCC_YUY2 != va_fourcc) && (VA_FOURCC_ARGB != va_fourcc) && - (VA_FOURCC_P208 != va_fourcc))) { + (VA_FOURCC_P208 != va_fourcc) && + (VA_FOURCC_P010 != va_fourcc))) { return MFX_ERR_MEMORY_ALLOC; } if (!surfaces_num) { @@ -256,8 +260,10 @@ mfxStatus _simple_alloc(mfxFrameAllocRequest* request, attrib.value.value.i = va_fourcc; attrib.flags = VA_SURFACE_ATTRIB_SETTABLE; + va_format = (va_fourcc == VA_FOURCC_ARGB) ? VA_RT_FORMAT_RGB32 : va_format; + va_res = vaCreateSurfaces(m_va_dpy, - VA_RT_FORMAT_YUV420, + va_format, request->Info.Width, request->Info.Height, surfaces, surfaces_num, @@ -403,7 +409,8 @@ mfxStatus simple_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData* ptr) if (MFX_ERR_NONE == mfx_res) { switch (vaapi_mid->m_image.format.fourcc) { case VA_FOURCC_NV12: - if (vaapi_mid->m_fourcc == MFX_FOURCC_NV12) { + case VA_FOURCC_P010: + if ((vaapi_mid->m_fourcc == MFX_FOURCC_NV12) || (vaapi_mid->m_fourcc == MFX_FOURCC_P010)) { ptr->Pitch = (mfxU16) vaapi_mid-> m_image.pitches[0]; @@ -571,3 +578,115 @@ mfxStatus simple_free(mfxHDL pthis, mfxFrameAllocResponse* response) return MFX_ERR_NONE; } + +mfxStatus Create3DLutMemory(mfxMemId memId, mfxHDL hdl, const char*lut3d_file_name) +{ + VAStatus va_status = VA_STATUS_SUCCESS; + VAImage surface_image = {}; + void *surface_p = NULL; + mfxU32 frame_size = 0, lut3d_size = 0; + mfxU8* newImageBuffer = NULL; + VASurfaceID surface_id = VA_INVALID_ID; + mfxU32 seg_size = 65, mul_size = 128; + + VADisplay va_dpy = hdl; + + if (!memId) { + return MFX_ERR_NULL_PTR; + } + + FILE *f3dlut = NULL; + f3dlut = fopen(lut3d_file_name,"rb"); + if (!f3dlut) + { + printf("Fail to open 3DLUT data file!\n"); + return MFX_ERR_NULL_PTR; + } + + // create VA surface + VASurfaceAttrib surface_attrib = {}; + surface_attrib.type = VASurfaceAttribPixelFormat; + surface_attrib.flags = VA_SURFACE_ATTRIB_SETTABLE; + surface_attrib.value.type = VAGenericValueTypeInteger; + surface_attrib.value.value.i = VA_FOURCC_RGBA; + + va_status = vaCreateSurfaces(va_dpy, + VA_RT_FORMAT_RGB32, + seg_size * mul_size, + seg_size * 2, + &surface_id, + 1, + &surface_attrib, + 1); + if (va_status != VA_STATUS_SUCCESS) { + printf("Load3DLutVAAPI vaCreateSurfaces 3dlut surface failed\n"); + return MFX_ERR_UNSUPPORTED; + } + + va_status = vaSyncSurface (va_dpy,surface_id); + if (va_status != VA_STATUS_SUCCESS) { + printf("Load3DLutVAAPI vaSyncSurface 3dlut surface failed\n"); + return MFX_ERR_UNSUPPORTED; + } + + va_status = vaDeriveImage(va_dpy, surface_id, &surface_image); + if (va_status != VA_STATUS_SUCCESS) { + printf("Load3DLutVAAPI vaDeriveImage from 3dlut surface failed\n"); + return MFX_ERR_UNSUPPORTED; + } + + va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p); + if (va_status != VA_STATUS_SUCCESS) { + printf("Load3DLutVAAPI vaMapBuffer from 3dlut surface failed\n"); + return MFX_ERR_UNSUPPORTED; + } + + if (surface_image.format.fourcc == VA_FOURCC_RGBA && f3dlut) { + /* 3DLUT surface is allocated to 32 bit RGB */ + frame_size = surface_image.width * surface_image.height * 4; + newImageBuffer = (mfxU8*)malloc(frame_size); + + fseek(f3dlut, 0L, SEEK_END); + lut3d_size = ftell(f3dlut); + rewind(f3dlut); + + uint32_t real_size = (frame_size > lut3d_size) ? lut3d_size : frame_size; + + uint32_t read_size = fread(newImageBuffer, 1, real_size, f3dlut); + memcpy(surface_p, newImageBuffer, read_size); + printf("upload_data_to_3dlut: 3DLUT surface width %d, height %d, pitch %d, frame size %d, 3dlut file size: %d\n", surface_image.width, surface_image.height, surface_image.pitches[0],frame_size, read_size); + } + + if (newImageBuffer) { + free(newImageBuffer); + newImageBuffer = NULL; + } + + vaUnmapBuffer(va_dpy, surface_image.buf); + vaDestroyImage(va_dpy, surface_image.image_id); + + *((VASurfaceID*)memId) = surface_id; + + if (f3dlut) + { + fclose(f3dlut); + f3dlut = NULL; + } + + printf("create 3dlut surface ID %d!\n", surface_id); + return MFX_ERR_NONE; +} + +mfxStatus Release3DLutMemory(mfxMemId memId, mfxHDL hdl) +{ + VADisplay va_dpy = hdl; + VAStatus va_status = VA_STATUS_SUCCESS; + mfxStatus mfx_res = MFX_ERR_NONE; + + VASurfaceID surface_id = *((VASurfaceID*)memId); + va_status= vaDestroySurfaces(va_dpy, &surface_id, 1); + mfx_res = va_to_mfx_status(va_status); + + return mfx_res; +} + diff --git a/tutorials/simple_4_vpp_resize_3dlut_vmem/CMakeLists.txt b/tutorials/simple_4_vpp_resize_3dlut_vmem/CMakeLists.txt new file mode 100644 index 0000000000..db385d0f94 --- /dev/null +++ b/tutorials/simple_4_vpp_resize_3dlut_vmem/CMakeLists.txt @@ -0,0 +1,4 @@ +include_directories (${CMAKE_CURRENT_SOURCE_DIR}/../common) +list( APPEND LIBS_VARIANT tutorials_common ) +set(DEPENDENCIES libva libva-drm libmfx dl pthread) +make_executable( shortname universal ) diff --git a/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d.sln b/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d.sln new file mode 100644 index 0000000000..e216020c9f --- /dev/null +++ b/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2000 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simple_vpp_d3d", "simple_vpp_d3d.vcxproj", "{8B29C54E-B344-4619-935D-0547AF9B7DB2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8B29C54E-B344-4619-935D-0547AF9B7DB2}.Debug|Win32.ActiveCfg = Debug|Win32 + {8B29C54E-B344-4619-935D-0547AF9B7DB2}.Debug|Win32.Build.0 = Debug|Win32 + {8B29C54E-B344-4619-935D-0547AF9B7DB2}.Debug|x64.ActiveCfg = Debug|x64 + {8B29C54E-B344-4619-935D-0547AF9B7DB2}.Debug|x64.Build.0 = Debug|x64 + {8B29C54E-B344-4619-935D-0547AF9B7DB2}.Release|Win32.ActiveCfg = Release|Win32 + {8B29C54E-B344-4619-935D-0547AF9B7DB2}.Release|Win32.Build.0 = Release|Win32 + {8B29C54E-B344-4619-935D-0547AF9B7DB2}.Release|x64.ActiveCfg = Release|x64 + {8B29C54E-B344-4619-935D-0547AF9B7DB2}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d.vcxproj b/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d.vcxproj new file mode 100644 index 0000000000..90e5024bbd --- /dev/null +++ b/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d.vcxproj @@ -0,0 +1,210 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {8B29C54E-B344-4619-935D-0547AF9B7DB2} + video_enc_con + Win32Proj + 10.0.17134.0 + simple_vpp_d3d + + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + + + + + + + + + + + + + + + + + + + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + true + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + true + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + false + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + false + + + + Disabled + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;DX9_D3D;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level4 + false + EditAndContinue + + + libmfx_vs2015.lib;dxva2.lib;d3d9.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;libcmt.lib;%(IgnoreSpecificDefaultLibraries) + true + $(IntDir)video_enc_con.pdb + Console + MachineX86 + + + + + X64 + + + Disabled + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;DX9_D3D;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level4 + false + ProgramDatabase + + + libmfx_vs2015.lib;dxva2.lib;d3d9.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;libcmt.lib;%(IgnoreSpecificDefaultLibraries) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;DX9_D3D;WIN32;NDEBUG;_CONSOLE;SAVE_RECON;%(PreprocessorDefinitions) + Default + MultiThreaded + true + + + Level4 + false + + + + + libmfx_vs2015.lib;dxva2.lib;d3d9.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;%(IgnoreSpecificDefaultLibraries) + false + true + Console + true + true + MachineX86 + + + + + X64 + + + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;DX9_D3D;WIN64;NDEBUG;_CONSOLE;SAVE_RECON;%(PreprocessorDefinitions) + Default + MultiThreaded + true + + + Level4 + false + + + + + libmfx_vs2015.lib;dxva2.lib;d3d9.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;%(IgnoreSpecificDefaultLibraries) + false + true + Console + true + true + MachineX64 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d11.sln b/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d11.sln new file mode 100644 index 0000000000..8aefc43c8b --- /dev/null +++ b/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d11.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2000 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simple_vpp_d3d11", "simple_vpp_d3d11.vcxproj", "{A102864A-E273-45B7-B2DA-E5E557888FAC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A102864A-E273-45B7-B2DA-E5E557888FAC}.Debug|Win32.ActiveCfg = Debug|Win32 + {A102864A-E273-45B7-B2DA-E5E557888FAC}.Debug|Win32.Build.0 = Debug|Win32 + {A102864A-E273-45B7-B2DA-E5E557888FAC}.Debug|x64.ActiveCfg = Debug|x64 + {A102864A-E273-45B7-B2DA-E5E557888FAC}.Debug|x64.Build.0 = Debug|x64 + {A102864A-E273-45B7-B2DA-E5E557888FAC}.Release|Win32.ActiveCfg = Release|Win32 + {A102864A-E273-45B7-B2DA-E5E557888FAC}.Release|Win32.Build.0 = Release|Win32 + {A102864A-E273-45B7-B2DA-E5E557888FAC}.Release|x64.ActiveCfg = Release|x64 + {A102864A-E273-45B7-B2DA-E5E557888FAC}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d11.vcxproj b/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d11.vcxproj new file mode 100644 index 0000000000..fee75ab02c --- /dev/null +++ b/tutorials/simple_4_vpp_resize_3dlut_vmem/simple_vpp_d3d11.vcxproj @@ -0,0 +1,210 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {A102864A-E273-45B7-B2DA-E5E557888FAC} + video_enc_con + Win32Proj + 10.0.17134.0 + simple_vpp_d3d11 + + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + + + + + + + + + + + + + + + + + + + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + true + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + true + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + false + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + false + + + + Disabled + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;DX11_D3D;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level4 + false + EditAndContinue + + + libmfx_vs2015.lib;d3d11.lib;dxgi.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;libcmt.lib;%(IgnoreSpecificDefaultLibraries) + true + $(IntDir)video_enc_con.pdb + Console + MachineX86 + + + + + X64 + + + Disabled + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;DX11_D3D;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level4 + false + ProgramDatabase + + + libmfx_vs2015.lib;d3d11.lib;dxgi.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;libcmt.lib;%(IgnoreSpecificDefaultLibraries) + true + $(TargetDir)$(TargetName).pdb + Console + MachineX64 + + + + + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;DX11_D3D;WIN32;NDEBUG;_CONSOLE;SAVE_RECON;%(PreprocessorDefinitions) + Default + MultiThreaded + true + + + Level4 + false + + + + + libmfx_vs2015.lib;d3d11.lib;dxgi.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;%(IgnoreSpecificDefaultLibraries) + false + true + Console + true + true + MachineX86 + + + + + X64 + + + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;DX11_D3D;WIN64;NDEBUG;_CONSOLE;SAVE_RECON;%(PreprocessorDefinitions) + Default + MultiThreaded + true + + + Level4 + false + + + + + libmfx_vs2015.lib;d3d11.lib;dxgi.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;%(IgnoreSpecificDefaultLibraries) + false + true + Console + true + true + MachineX64 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/simple_4_vpp_resize_3dlut_vmem/src/simple_vpp_vmem.cpp b/tutorials/simple_4_vpp_resize_3dlut_vmem/src/simple_vpp_vmem.cpp new file mode 100644 index 0000000000..5932b7581f --- /dev/null +++ b/tutorials/simple_4_vpp_resize_3dlut_vmem/src/simple_vpp_vmem.cpp @@ -0,0 +1,391 @@ +// Copyright (c) 2021 Intel Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common_utils.h" +#include "cmd_options.h" + +static void usage(CmdOptionsCtx* ctx) +{ + printf( + "Performs VPP conversion over INPUT and optionally writes OUTPUT. If\n" + "INPUT is not specified simulates input with empty frames filled with\n" + "the color.\n" + "\n" + "Usage: %s [options] [INPUT] [OUTPUT]\n", ctx->program); +} + +int main(int argc, char** argv) +{ + mfxStatus sts = MFX_ERR_NONE; + bool bEnableInput; // if true, removes all YUV file reading (which is replaced by pre-initialized surface data). Workload runs for 1000 frames. + bool bEnableOutput; // if true, removes all output bitsteam file writing and printing the progress + CmdOptions options; + + mfxU32 lut3DMemID = 0; + mfxHDL hDevice; + + const mfxU32 outWidth = 1280; + const mfxU32 outHeight = 720; + + // 3DLUT file name, please make sure this file exists. + const char* lut3dFileName = "3dlut_65cubic.dat"; + + // ===================================================================== + // Intel Media SDK Video Pre/Post Processing (VPP) pipeline setup + // - Showcasing two VPP features + // - Resize (frame width and height is halved) + // - Denoise: Remove noise from frames + // + + // Read options from the command line (if any is given) + memset(&options, 0, sizeof(CmdOptions)); + options.ctx.options = OPTIONS_VPP; + options.ctx.usage = usage; + // Set default values: + options.values.impl = MFX_IMPL_AUTO_ANY; + + // here we parse options + ParseOptions(argc, argv, &options); + + if (!options.values.Width || !options.values.Height) { + printf("error: input video geometry not set (mandatory)\n"); + return -1; + } + + bEnableInput = (options.values.SourceName[0] != '\0'); + bEnableOutput = (options.values.SinkName[0] != '\0'); + // Open input P010 YUV file + fileUniPtr fSource(nullptr, &CloseFile); + if (bEnableInput) { + fSource.reset(OpenFile(options.values.SourceName, "rb")); + MSDK_CHECK_POINTER(fSource, MFX_ERR_NULL_PTR); + } + // Create output YUV file + fileUniPtr fSink(nullptr, &CloseFile); + if (bEnableOutput) { + fSink.reset(OpenFile(options.values.SinkName, "wb")); + MSDK_CHECK_POINTER(fSink, MFX_ERR_NULL_PTR); + } + + // Initialize Intel Media SDK session + // - MFX_IMPL_AUTO_ANY selects HW acceleration if available (on any adapter) + // - Version 1.0 is selected for greatest backwards compatibility. + // If more recent API features are needed, change the version accordingly + mfxIMPL impl = options.values.impl; + mfxVersion ver = { {0, 1} }; + MFXVideoSession session; + + mfxFrameAllocator mfxAllocator; + + sts = Initialize(impl, ver, &session, &mfxAllocator); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Initialize VPP parameters + // - For video memory surfaces are used to store the raw frames + // (Note that when using HW acceleration video surfaces are prefered, for better performance) + mfxVideoParam VPPParams; + memset(&VPPParams, 0, sizeof(VPPParams)); + // Input data + VPPParams.vpp.In.FourCC = MFX_FOURCC_P010; + VPPParams.vpp.In.BitDepthLuma = 10; + VPPParams.vpp.In.BitDepthChroma = 10; + VPPParams.vpp.In.Shift = 1; + VPPParams.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + VPPParams.vpp.In.CropX = 0; + VPPParams.vpp.In.CropY = 0; + VPPParams.vpp.In.CropW = options.values.Width; + VPPParams.vpp.In.CropH = options.values.Height; + VPPParams.vpp.In.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + VPPParams.vpp.In.FrameRateExtN = 30; + VPPParams.vpp.In.FrameRateExtD = 1; + // width must be a multiple of 16 + // height must be a multiple of 16 in case of frame picture and a multiple of 32 in case of field picture + VPPParams.vpp.In.Width = MSDK_ALIGN16(options.values.Width); + VPPParams.vpp.In.Height = + (MFX_PICSTRUCT_PROGRESSIVE == VPPParams.vpp.In.PicStruct) ? + MSDK_ALIGN16(options.values.Height) : + MSDK_ALIGN32(options.values.Height); + // Output data + VPPParams.vpp.Out.FourCC = MFX_FOURCC_NV12; + VPPParams.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + VPPParams.vpp.Out.CropX = 0; + VPPParams.vpp.Out.CropY = 0; + VPPParams.vpp.Out.CropW = outWidth; + VPPParams.vpp.Out.CropH = outHeight; + VPPParams.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + VPPParams.vpp.Out.FrameRateExtN = 30; + VPPParams.vpp.Out.FrameRateExtD = 1; + // width must be a multiple of 16 + // height must be a multiple of 16 in case of frame picture and a multiple of 32 in case of field picture + VPPParams.vpp.Out.Width = outWidth; + VPPParams.vpp.Out.Height = outHeight; + + VPPParams.IOPattern = + MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY; + + // Create Media SDK VPP component + MFXVideoVPP mfxVPP(session); + + // Query number of required surfaces for VPP + mfxFrameAllocRequest VPPRequest[2]; // [0] - in, [1] - out + memset(&VPPRequest, 0, sizeof(mfxFrameAllocRequest) * 2); + sts = mfxVPP.QueryIOSurf(&VPPParams, VPPRequest); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + VPPRequest[0].Type |= WILL_WRITE; // This line is only required for Windows DirectX11 to ensure that surfaces can be written to by the application + VPPRequest[1].Type |= WILL_READ; // This line is only required for Windows DirectX11 to ensure that surfaces can be retrieved by the application + + // Allocate required surfaces + mfxFrameAllocResponse mfxResponseIn; + mfxFrameAllocResponse mfxResponseOut; + sts = mfxAllocator.Alloc(mfxAllocator.pthis, &VPPRequest[0], &mfxResponseIn); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + sts = mfxAllocator.Alloc(mfxAllocator.pthis, &VPPRequest[1], &mfxResponseOut); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + mfxU16 nVPPSurfNumIn = mfxResponseIn.NumFrameActual; + mfxU16 nVPPSurfNumOut = mfxResponseOut.NumFrameActual; + + printf("Test............................................\n"); + + // Allocate surface headers (mfxFrameSurface1) for VPP + std::vector pVPPSurfacesIn(nVPPSurfNumIn); + for (int i = 0; i < nVPPSurfNumIn; i++) { + memset(&pVPPSurfacesIn[i], 0, sizeof(mfxFrameSurface1)); + pVPPSurfacesIn[i].Info = VPPParams.vpp.In; + pVPPSurfacesIn[i].Data.MemId = mfxResponseIn.mids[i]; // MID (memory id) represent one D3D NV12 surface + + if (!bEnableInput) { + ClearYUVSurfaceVMem(pVPPSurfacesIn[i].Data.MemId); + } + } + + std::vector pVPPSurfacesOut(nVPPSurfNumOut); + mfxExtVideoSignalInfo videoSignalInfoOut[5]; + for (int i = 0; i < nVPPSurfNumOut; i++) { + memset(&pVPPSurfacesOut[i], 0, sizeof(mfxFrameSurface1)); + + pVPPSurfacesOut[i].Info = VPPParams.vpp.Out; + pVPPSurfacesOut[i].Data.MemId = mfxResponseOut.mids[i]; // MID (memory id) represent one D3D NV12 surface + } + + // Create 3DLut Memory to hold 3DLut data + session.GetHandle(MFX_HANDLE_VA_DISPLAY, &hDevice); + sts = Create3DLutMemory((void*)&lut3DMemID, hDevice, lut3dFileName); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Initialize extended buffer for frame processing + // - mfxExtVPPDoUse: Define the processing algorithm to be used + // - mfxExtVPP3DLut: 3DLUT configuration + // - mfxExtVPPScaling: Scaling configuration + // - mfxExtBuffer: Add extended buffers to VPP parameter configuration + mfxExtVPPDoUse extDoUse; + memset(&extDoUse, 0, sizeof(extDoUse)); + mfxU32 tabDoUseAlg[2]; + extDoUse.Header.BufferId = MFX_EXTBUFF_VPP_DOUSE; + extDoUse.Header.BufferSz = sizeof(mfxExtVPPDoUse); + extDoUse.NumAlg = 2; + extDoUse.AlgList = tabDoUseAlg; + tabDoUseAlg[0] = MFX_EXTBUFF_VPP_3DLUT; + tabDoUseAlg[1] = MFX_EXTBUFF_VPP_SCALING; + + mfxExtVPP3DLut lut3DConfig; + memset(&lut3DConfig, 0, sizeof(lut3DConfig)); + lut3DConfig.Header.BufferId = MFX_EXTBUFF_VPP_3DLUT; + lut3DConfig.Header.BufferSz = sizeof(mfxExtVPP3DLut); + + lut3DConfig.ChannelMapping = MFX_3DLUT_CHANNEL_MAPPING_RGB_RGB; + lut3DConfig.BufferType = MFX_RESOURCE_VA_SURFACE; + lut3DConfig.VideoBuffer.DataType = MFX_DATA_TYPE_U16; + lut3DConfig.VideoBuffer.MemLayout = MFX_3DLUT_MEMORY_LAYOUT_INTEL_65LUT; + lut3DConfig.VideoBuffer.MemId = &lut3DMemID; + + mfxExtVPPScaling scalingConfig; + memset(&scalingConfig, 0, sizeof(scalingConfig)); + scalingConfig.Header.BufferId = MFX_EXTBUFF_VPP_SCALING; + scalingConfig.Header.BufferSz = sizeof(mfxExtVPPScaling); + scalingConfig.ScalingMode = MFX_SCALING_MODE_LOWPOWER; + + mfxExtBuffer* ExtBuffer[3]; + ExtBuffer[0] = (mfxExtBuffer*) &extDoUse; + ExtBuffer[1] = (mfxExtBuffer*) &lut3DConfig; + ExtBuffer[2] = (mfxExtBuffer*) &scalingConfig; + VPPParams.NumExtParam = 3; + VPPParams.ExtParam = (mfxExtBuffer**) &ExtBuffer[0]; + + // Initialize Media SDK VPP + sts = mfxVPP.Init(&VPPParams); + MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // =================================== + // Start processing the frames + // + + mfxTime tStart, tEnd; + mfxGetTime(&tStart); + + int nSurfIdxIn = 0, nSurfIdxOut = 0; + mfxSyncPoint syncp; + mfxU32 nFrame = 0; + + // + // Stage 1: Main processing loop + // + while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_DATA == sts) { + nSurfIdxIn = GetFreeSurfaceIndex(pVPPSurfacesIn); // Find free input frame surface + MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nSurfIdxIn, MFX_ERR_MEMORY_ALLOC); + + // Surface locking required when read/write video surfaces + sts = mfxAllocator.Lock(mfxAllocator.pthis, pVPPSurfacesIn[nSurfIdxIn].Data.MemId, &(pVPPSurfacesIn[nSurfIdxIn].Data)); + MSDK_BREAK_ON_ERROR(sts); + + sts = LoadRawFrame(&pVPPSurfacesIn[nSurfIdxIn], fSource.get()); // Load frame from file into surface + MSDK_BREAK_ON_ERROR(sts); + + sts = mfxAllocator.Unlock(mfxAllocator.pthis, pVPPSurfacesIn[nSurfIdxIn].Data.MemId, &(pVPPSurfacesIn[nSurfIdxIn].Data)); + MSDK_BREAK_ON_ERROR(sts); + + nSurfIdxOut = GetFreeSurfaceIndex(pVPPSurfacesOut); // Find free output frame surface + MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nSurfIdxOut, MFX_ERR_MEMORY_ALLOC); + + mfxExtVideoSignalInfo videoSignalInfoIn = {}; + videoSignalInfoIn.Header.BufferId = MFX_EXTBUFF_VIDEO_SIGNAL_INFO; + videoSignalInfoIn.Header.BufferSz = sizeof(mfxExtVideoSignalInfo); + videoSignalInfoIn.ColourPrimaries = 9; + mfxExtBuffer* ExtBufferIn = (mfxExtBuffer*)&videoSignalInfoIn; + pVPPSurfacesIn[nSurfIdxIn].Data.NumExtParam = 1; + pVPPSurfacesIn[nSurfIdxIn].Data.ExtParam = (mfxExtBuffer**)&ExtBufferIn; + + mfxExtVideoSignalInfo videoSignalInfoOut = {}; + videoSignalInfoOut.Header.BufferId = MFX_EXTBUFF_VIDEO_SIGNAL_INFO; + videoSignalInfoOut.Header.BufferSz = sizeof(mfxExtVideoSignalInfo); + videoSignalInfoOut.ColourPrimaries = 1; + mfxExtBuffer* ExtBufferOut = (mfxExtBuffer*)&videoSignalInfoOut; + pVPPSurfacesOut[nSurfIdxOut].Data.NumExtParam = 1; + pVPPSurfacesOut[nSurfIdxOut].Data.ExtParam = (mfxExtBuffer**)&ExtBufferOut; + + for (;;) { + // Process a frame asychronously (returns immediately) + sts = mfxVPP.RunFrameVPPAsync(&pVPPSurfacesIn[nSurfIdxIn], &pVPPSurfacesOut[nSurfIdxOut], NULL, &syncp); + if (MFX_WRN_DEVICE_BUSY == sts) { + MSDK_SLEEP(1); // Wait if device is busy, then repeat the same call + } else + break; + } + + if (MFX_ERR_MORE_DATA == sts) // Fetch more input surfaces for VPP + continue; + + // MFX_ERR_MORE_SURFACE means output is ready but need more surface (example: Frame Rate Conversion 30->60) + // * Not handled in this example! + + MSDK_BREAK_ON_ERROR(sts); + + sts = session.SyncOperation(syncp, 60000); // Synchronize. Wait until frame processing is ready + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + ++nFrame; + if (bEnableOutput) { + // Surface locking required when read/write video surfaces + sts = mfxAllocator.Lock(mfxAllocator.pthis, pVPPSurfacesOut[nSurfIdxOut].Data.MemId, &(pVPPSurfacesOut[nSurfIdxOut].Data)); + MSDK_BREAK_ON_ERROR(sts); + + sts = WriteRawFrame(&pVPPSurfacesOut[nSurfIdxOut], fSink.get()); + MSDK_BREAK_ON_ERROR(sts); + + sts = mfxAllocator.Unlock(mfxAllocator.pthis, pVPPSurfacesOut[nSurfIdxOut].Data.MemId, &(pVPPSurfacesOut[nSurfIdxOut].Data)); + MSDK_BREAK_ON_ERROR(sts); + + printf("Frame number: %d\r", nFrame); + fflush(stdout); + } + } + + // MFX_ERR_MORE_DATA means that the input file has ended, need to go to buffering loop, exit in case of other errors + MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // + // Stage 2: Retrieve the buffered VPP frames + // + while (MFX_ERR_NONE <= sts) { + nSurfIdxOut = GetFreeSurfaceIndex(pVPPSurfacesOut); // Find free frame surface + MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nSurfIdxOut, MFX_ERR_MEMORY_ALLOC); + + for (;;) { + // Process a frame asychronously (returns immediately) + sts = mfxVPP.RunFrameVPPAsync(NULL, &pVPPSurfacesOut[nSurfIdxOut], NULL, &syncp); + if (MFX_WRN_DEVICE_BUSY == sts) { + MSDK_SLEEP(1); // Wait if device is busy, then repeat the same call + } else + break; + } + + MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_SURFACE); + MSDK_BREAK_ON_ERROR(sts); + + sts = session.SyncOperation(syncp, 60000); // Synchronize. Wait until frame processing is ready + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + ++nFrame; + if (bEnableOutput) { + // Surface locking required when read/write video surfaces + sts = mfxAllocator.Lock(mfxAllocator.pthis, pVPPSurfacesOut[nSurfIdxOut].Data.MemId, &(pVPPSurfacesOut[nSurfIdxOut].Data)); + MSDK_BREAK_ON_ERROR(sts); + + sts = WriteRawFrame(&pVPPSurfacesOut[nSurfIdxOut], fSink.get()); + MSDK_BREAK_ON_ERROR(sts); + + sts = mfxAllocator.Unlock(mfxAllocator.pthis, pVPPSurfacesOut[nSurfIdxOut].Data.MemId, &(pVPPSurfacesOut[nSurfIdxOut].Data)); + MSDK_BREAK_ON_ERROR(sts); + + printf("Frame number: %d\r", nFrame); + fflush(stdout); + } + } + + // MFX_ERR_MORE_DATA indicates that there are no more buffered frames, exit in case of other errors + MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + mfxGetTime(&tEnd); + double elapsed = TimeDiffMsec(tEnd, tStart) / 1000; + double fps = ((double)nFrame / elapsed); + printf("\nExecution time: %3.2f s (%3.2f fps)\n", elapsed, fps); + + // =================================================================== + // Clean up resources + // - It is recommended to close Media SDK components first, before releasing allocated surfaces, since + // some surfaces may still be locked by internal Media SDK resources. + mfxVPP.Close(); + //session closed automatically on destruction + + mfxAllocator.Free(mfxAllocator.pthis, &mfxResponseIn); + mfxAllocator.Free(mfxAllocator.pthis, &mfxResponseOut); + + sts = Release3DLutMemory(&lut3DMemID, &hDevice); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + Release(); + + + return 0; +} diff --git a/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/CMakeLists.txt b/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/CMakeLists.txt new file mode 100644 index 0000000000..db385d0f94 --- /dev/null +++ b/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/CMakeLists.txt @@ -0,0 +1,4 @@ +include_directories (${CMAKE_CURRENT_SOURCE_DIR}/../common) +list( APPEND LIBS_VARIANT tutorials_common ) +set(DEPENDENCIES libva libva-drm libmfx dl pthread) +make_executable( shortname universal ) diff --git a/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/simple_5_transcode_opaque_async_vppresize_3dlut.sln b/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/simple_5_transcode_opaque_async_vppresize_3dlut.sln new file mode 100644 index 0000000000..07b8dc3333 --- /dev/null +++ b/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/simple_5_transcode_opaque_async_vppresize_3dlut.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2000 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simple_transcode_opaque_async_vppresize", "simple_transcode_opaque_async_vppresize.vcxproj", "{B13225FB-F1D7-49F9-9AC9-A076560E7281}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B13225FB-F1D7-49F9-9AC9-A076560E7281}.Debug|Win32.ActiveCfg = Debug|Win32 + {B13225FB-F1D7-49F9-9AC9-A076560E7281}.Debug|Win32.Build.0 = Debug|Win32 + {B13225FB-F1D7-49F9-9AC9-A076560E7281}.Debug|x64.ActiveCfg = Debug|x64 + {B13225FB-F1D7-49F9-9AC9-A076560E7281}.Debug|x64.Build.0 = Debug|x64 + {B13225FB-F1D7-49F9-9AC9-A076560E7281}.Release|Win32.ActiveCfg = Release|Win32 + {B13225FB-F1D7-49F9-9AC9-A076560E7281}.Release|Win32.Build.0 = Release|Win32 + {B13225FB-F1D7-49F9-9AC9-A076560E7281}.Release|x64.ActiveCfg = Release|x64 + {B13225FB-F1D7-49F9-9AC9-A076560E7281}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/simple_5_transcode_opaque_async_vppresize_3dlut.vcxproj b/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/simple_5_transcode_opaque_async_vppresize_3dlut.vcxproj new file mode 100644 index 0000000000..eced285827 --- /dev/null +++ b/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/simple_5_transcode_opaque_async_vppresize_3dlut.vcxproj @@ -0,0 +1,208 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {B13225FB-F1D7-49F9-9AC9-A076560E7281} + video_enc_con + Win32Proj + 10.0.17134.0 + simple_transcode_opaque_async_vppresize + + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + v141 + + + + + + + + + + + + + + + + + + + + + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + true + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + true + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + false + ..\_build\$(Platform)\$(Configuration)\ + $(OutDir)obj\$(ProjectName)\ + false + + + + Disabled + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level4 + false + EditAndContinue + + + libmfx_vs2015.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;libcmt.lib;%(IgnoreSpecificDefaultLibraries) + %(DelayLoadDLLs) + true + Console + MachineX86 + + + + + X64 + + + Disabled + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level4 + false + ProgramDatabase + + + libmfx_vs2015.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;libcmt.lib;%(IgnoreSpecificDefaultLibraries) + %(DelayLoadDLLs) + true + Console + MachineX64 + + + + + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;WIN32;NDEBUG;_CONSOLE;SAVE_RECON;%(PreprocessorDefinitions) + Default + MultiThreaded + true + + + Level3 + false + + + + + libmfx_vs2015.lib;%(AdditionalDependencies) + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;%(IgnoreSpecificDefaultLibraries) + %(DelayLoadDLLs) + false + true + Console + true + true + MachineX86 + + + + + X64 + + + ..\common;$(INTELMEDIASDKROOT)\include;%(AdditionalIncludeDirectories) + NOMINMAX;WIN64;NDEBUG;_CONSOLE;SAVE_RECON;%(PreprocessorDefinitions) + Default + MultiThreaded + true + + + Level3 + false + + + + + libmfx_vs2015.lib;%(AdditionalDependencies) + $(ProjectDir)..\..\..\build\win_$(Platform)\$(Configuration)\lib\;$(INTELMEDIASDKROOT)\lib\$(Platform);%(AdditionalLibraryDirectories) + msvcrt.lib;msvcrtd.lib;%(IgnoreSpecificDefaultLibraries) + %(DelayLoadDLLs) + false + true + Console + true + true + MachineX64 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/src/simple_5_transcode_opaque_async_vppresize_3dlut.cpp b/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/src/simple_5_transcode_opaque_async_vppresize_3dlut.cpp new file mode 100644 index 0000000000..aaf032a3af --- /dev/null +++ b/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/src/simple_5_transcode_opaque_async_vppresize_3dlut.cpp @@ -0,0 +1,757 @@ +// Copyright (c) 2021 Intel Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common_utils.h" +#include "cmd_options.h" + +static void usage(CmdOptionsCtx* ctx) +{ + printf( + "Transcodes INPUT and optionally writes OUTPUT.\n" + "\n" + "Usage: %s [options] INPUT [OUTPUT]\n", ctx->program); +} + +int main(int argc, char** argv) +{ + mfxStatus sts = MFX_ERR_NONE; + bool bEnableOutput; // if true, removes all output bitsteam file writing and printing the progress + CmdOptions options; + + // ===================================================================== + // Intel Media SDK transcode opaque pipeline setup + // - In this example we are decoding and encoding an AVC (H.264) stream + // - Opaque memory decode->vpp->encode pipeline. Media SDK selects suitable memory surface internally + // - Asynchronous operation by executing more than one encode operation simultaneously + // + + // Read options from the command line (if any is given) + memset(&options, 0, sizeof(CmdOptions)); + options.ctx.options = OPTIONS_TRANSCODE; + options.ctx.usage = usage; + // Set default values: + options.values.impl = MFX_IMPL_AUTO_ANY; + + // here we parse options + ParseOptions(argc, argv, &options); + + if (!options.values.Bitrate) { + printf("error: bitrate not set (mandatory)\n"); + return -1; + } + if (!options.values.FrameRateN || !options.values.FrameRateD) { + printf("error: framerate not set (mandatory)\n"); + return -1; + } + if (!options.values.SourceName[0]) { + printf("error: source file name not set (mandatory)\n"); + return -1; + } + + bEnableOutput = (options.values.SinkName[0] != '\0'); + + // Open input H.264 elementary stream (ES) file + fileUniPtr fSource(OpenFile(options.values.SourceName, "rb"), &CloseFile); + MSDK_CHECK_POINTER(fSource, MFX_ERR_NULL_PTR); + + // Create output elementary stream (ES) H.264 file + fileUniPtr fSink(nullptr, &CloseFile); + if (bEnableOutput) { + fSink.reset(OpenFile(options.values.SinkName, "wb")); + MSDK_CHECK_POINTER(fSink, MFX_ERR_NULL_PTR); + } + + // Initialize Media SDK session + // - MFX_IMPL_AUTO_ANY selects HW acceleration if available (on any adapter) + // - Version 1.3 is selected since the opaque memory feature was added in this API release + // If more recent API features are needed, change the version accordingly + mfxIMPL impl = options.values.impl; + mfxVersion ver = { {3, 1} }; // Note: API 1.3 ! + MFXVideoSession session; + sts = Initialize(impl, ver, &session, NULL); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Create Media SDK decoder & encoder + MFXVideoDECODE mfxDEC(session); + MFXVideoENCODE mfxENC(session); + MFXVideoVPP mfxVPP(session); + + // Set required video parameters for decode + // - In this example we are decoding an AVC (H.264) stream + mfxVideoParam mfxDecParams; + memset(&mfxDecParams, 0, sizeof(mfxDecParams)); + mfxDecParams.mfx.CodecId = MFX_CODEC_HEVC; + mfxDecParams.IOPattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY; + + // Configure Media SDK to keep more operations in flight + // - AsyncDepth represents the number of tasks that can be submitted, before synchronizing is required + // - The choice of AsyncDepth = 4 is quite arbitrary but has proven to result in good performance + mfxDecParams.AsyncDepth = 4; + + // Prepare Media SDK bit stream buffer for decoder + // - Arbitrary buffer size for this example + mfxBitstream mfxBS; + memset(&mfxBS, 0, sizeof(mfxBS)); + mfxBS.MaxLength = 1024 * 1024; + std::vector bstData(mfxBS.MaxLength); + mfxBS.Data = bstData.data(); + + + // Read a chunk of data from stream file into bit stream buffer + // - Parse bit stream, searching for header and fill video parameters structure + // - Abort if bit stream header is not found in the first bit stream buffer chunk + sts = ReadBitStreamData(&mfxBS, fSource.get()); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + sts = mfxDEC.DecodeHeader(&mfxBS, &mfxDecParams); + MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Initialize VPP parameters + mfxVideoParam VPPParams; + memset(&VPPParams, 0, sizeof(VPPParams)); + // Input data + VPPParams.vpp.In.FourCC = MFX_FOURCC_P010; + VPPParams.vpp.In.BitDepthLuma = 10; + VPPParams.vpp.In.BitDepthChroma = 10; + VPPParams.vpp.In.Shift = 1; + VPPParams.vpp.In.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + VPPParams.vpp.In.CropX = 0; + VPPParams.vpp.In.CropY = 0; + VPPParams.vpp.In.CropW = mfxDecParams.mfx.FrameInfo.CropW; + VPPParams.vpp.In.CropH = mfxDecParams.mfx.FrameInfo.CropH; + VPPParams.vpp.In.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + VPPParams.vpp.In.FrameRateExtN = 30; + VPPParams.vpp.In.FrameRateExtD = 1; + // width must be a multiple of 16 + // height must be a multiple of 16 in case of frame picture and a multiple of 32 in case of field picture + VPPParams.vpp.In.Width = MSDK_ALIGN16(VPPParams.vpp.In.CropW); + VPPParams.vpp.In.Height = + (MFX_PICSTRUCT_PROGRESSIVE == VPPParams.vpp.In.PicStruct) ? + MSDK_ALIGN16(VPPParams.vpp.In.CropH) : + MSDK_ALIGN32(VPPParams.vpp.In.CropH); + // Output data + VPPParams.vpp.Out.FourCC = MFX_FOURCC_NV12; + VPPParams.vpp.Out.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + VPPParams.vpp.Out.CropX = 0; + VPPParams.vpp.Out.CropY = 0; + VPPParams.vpp.Out.CropW = 1280; + VPPParams.vpp.Out.CropH = 720; + VPPParams.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + VPPParams.vpp.Out.FrameRateExtN = 30; + VPPParams.vpp.Out.FrameRateExtD = 1; + // width must be a multiple of 16 + // height must be a multiple of 16 in case of frame picture and a multiple of 32 in case of field picture + VPPParams.vpp.Out.Width = MSDK_ALIGN16(VPPParams.vpp.Out.CropW); + VPPParams.vpp.Out.Height = + (MFX_PICSTRUCT_PROGRESSIVE == VPPParams.vpp.Out.PicStruct) ? + MSDK_ALIGN16(VPPParams.vpp.Out.CropH) : + MSDK_ALIGN32(VPPParams.vpp.Out.CropH); + + VPPParams.IOPattern = + MFX_IOPATTERN_IN_OPAQUE_MEMORY | MFX_IOPATTERN_OUT_OPAQUE_MEMORY; + + // Configure Media SDK to keep more operations in flight + // - AsyncDepth represents the number of tasks that can be submitted, before synchronizing is required + VPPParams.AsyncDepth = mfxDecParams.AsyncDepth; + + // Initialize encoder parameters + // - In this example we are encoding an AVC (H.264) stream + mfxVideoParam mfxEncParams; + memset(&mfxEncParams, 0, sizeof(mfxEncParams)); + mfxEncParams.mfx.CodecId = MFX_CODEC_AVC; + mfxEncParams.mfx.TargetUsage = MFX_TARGETUSAGE_BALANCED; + mfxEncParams.mfx.TargetKbps = options.values.Bitrate; + mfxEncParams.mfx.RateControlMethod = MFX_RATECONTROL_VBR; + mfxEncParams.mfx.FrameInfo.FrameRateExtN = options.values.FrameRateN; + mfxEncParams.mfx.FrameInfo.FrameRateExtD = options.values.FrameRateD; + mfxEncParams.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; + mfxEncParams.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + mfxEncParams.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + mfxEncParams.mfx.FrameInfo.CropX = 0; + mfxEncParams.mfx.FrameInfo.CropY = 0; + mfxEncParams.mfx.FrameInfo.CropW = VPPParams.vpp.Out.CropW; // Half the resolution of decode stream + mfxEncParams.mfx.FrameInfo.CropH = VPPParams.vpp.Out.CropH; + // width must be a multiple of 16 + // height must be a multiple of 16 in case of frame picture and a multiple of 32 in case of field picture + mfxEncParams.mfx.FrameInfo.Width = MSDK_ALIGN16(mfxEncParams.mfx.FrameInfo.CropW); + mfxEncParams.mfx.FrameInfo.Height = + (MFX_PICSTRUCT_PROGRESSIVE == mfxEncParams.mfx.FrameInfo.PicStruct) ? + MSDK_ALIGN16(mfxEncParams.mfx.FrameInfo.CropH) : + MSDK_ALIGN32(mfxEncParams.mfx.FrameInfo.CropH); + + mfxEncParams.IOPattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY; + + // Configure Media SDK to keep more operations in flight + // - AsyncDepth represents the number of tasks that can be submitted, before synchronizing is required + mfxEncParams.AsyncDepth = mfxDecParams.AsyncDepth; + + // Query number required surfaces for decoder + mfxFrameAllocRequest DecRequest; + memset(&DecRequest, 0, sizeof(DecRequest)); + sts = mfxDEC.QueryIOSurf(&mfxDecParams, &DecRequest); + MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Query number required surfaces for encoder + mfxFrameAllocRequest EncRequest; + memset(&EncRequest, 0, sizeof(EncRequest)); + sts = mfxENC.QueryIOSurf(&mfxEncParams, &EncRequest); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Query number of required surfaces for VPP + mfxFrameAllocRequest VPPRequest[2]; // [0] - in, [1] - out + memset(&VPPRequest, 0, sizeof(mfxFrameAllocRequest) * 2); + sts = mfxVPP.QueryIOSurf(&VPPParams, VPPRequest); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Determine the required number of surfaces for decoder output (VPP input) and for VPP output (encoder input) + mfxU16 nSurfNumDecVPP = DecRequest.NumFrameSuggested + VPPRequest[0].NumFrameSuggested + VPPParams.AsyncDepth; + mfxU16 nSurfNumVPPEnc = EncRequest.NumFrameSuggested + VPPRequest[1].NumFrameSuggested + VPPParams.AsyncDepth; + + // Initialize shared surfaces for decoder, VPP and encode + // - Note that no buffer memory is allocated, for opaque memory this is handled by Media SDK internally + // - Frame surface array keeps reference to all surfaces + // - Opaque memory is configured with the mfxExtOpaqueSurfaceAlloc extended buffers + + // we need vector of raw pointers for opaque buffer; + std::vector pSurfaces(nSurfNumDecVPP); + // additional vector for resource control + std::vector> pSurfacesPtrs(nSurfNumDecVPP + nSurfNumVPPEnc); + for (int i = 0; i < nSurfNumDecVPP; i++) { + pSurfacesPtrs[i].reset(new mfxFrameSurface1); + pSurfaces[i] = pSurfacesPtrs[i].get(); + MSDK_CHECK_POINTER(pSurfaces[i], MFX_ERR_MEMORY_ALLOC); + memset(pSurfaces[i], 0, sizeof(mfxFrameSurface1)); + pSurfaces[i]->Info = DecRequest.Info; + } + + std::vector pSurfaces2(nSurfNumVPPEnc); + for (int i = 0; i < nSurfNumVPPEnc; i++) { + pSurfacesPtrs[i + nSurfNumDecVPP].reset(new mfxFrameSurface1); + pSurfaces2[i] = pSurfacesPtrs[i + nSurfNumDecVPP].get(); + MSDK_CHECK_POINTER(pSurfaces2[i], MFX_ERR_MEMORY_ALLOC); + memset(pSurfaces2[i], 0, sizeof(mfxFrameSurface1)); + pSurfaces2[i]->Info = EncRequest.Info; + } + + mfxExtOpaqueSurfaceAlloc extOpaqueAllocDec; + memset(&extOpaqueAllocDec, 0, sizeof(extOpaqueAllocDec)); + extOpaqueAllocDec.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; + extOpaqueAllocDec.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc); + mfxExtBuffer* pExtParamsDec = (mfxExtBuffer*) & extOpaqueAllocDec; + + mfxExtOpaqueSurfaceAlloc extOpaqueAllocVPP; + memset(&extOpaqueAllocVPP, 0, sizeof(extOpaqueAllocVPP)); + extOpaqueAllocVPP.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; + extOpaqueAllocVPP.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc); + mfxExtBuffer* pExtParamsVPP = (mfxExtBuffer*) & extOpaqueAllocVPP; + + mfxExtOpaqueSurfaceAlloc extOpaqueAllocEnc; + memset(&extOpaqueAllocEnc, 0, sizeof(extOpaqueAllocEnc)); + extOpaqueAllocEnc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; + extOpaqueAllocEnc.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc); + mfxExtBuffer* pExtParamsENC = (mfxExtBuffer*) & extOpaqueAllocEnc; + + extOpaqueAllocDec.Out.Surfaces = pSurfaces.data(); + extOpaqueAllocDec.Out.NumSurface = nSurfNumDecVPP; + extOpaqueAllocDec.Out.Type = DecRequest.Type; + + memcpy(&extOpaqueAllocVPP.In, &extOpaqueAllocDec.Out, sizeof(extOpaqueAllocDec.Out)); + extOpaqueAllocVPP.Out.Surfaces = pSurfaces2.data(); + extOpaqueAllocVPP.Out.NumSurface = nSurfNumVPPEnc; + extOpaqueAllocVPP.Out.Type = EncRequest.Type; + + memcpy(&extOpaqueAllocEnc.In, &extOpaqueAllocVPP.Out, sizeof(extOpaqueAllocVPP.Out)); + + printf("read 3dlut file 3dlut_65cubic.dat and config MSDK parameters!\n"); + + mfxU32 lut3DMemID = 0; + mfxHDL hDevice = NULL; + const char* lut3dFileName = "3dlut_65cubic.dat"; + // Create 3DLut Memory to hold 3DLut data + session.GetHandle(MFX_HANDLE_VA_DISPLAY, &hDevice); + sts = Create3DLutMemory((void*)&lut3DMemID, hDevice, lut3dFileName); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Initialize extended buffer for frame processing + // - Denoise VPP denoise filter + // - mfxExtVPPDoUse: Define the processing algorithm to be used + // - mfxExtVPPDenoise: Denoise configuration + // - mfxExtBuffer: Add extended buffers to VPP parameter configuration + mfxExtVPPDoUse extDoUse; + memset(&extDoUse, 0, sizeof(extDoUse)); + mfxU32 tabDoUseAlg[2]; + extDoUse.Header.BufferId = MFX_EXTBUFF_VPP_DOUSE; + extDoUse.Header.BufferSz = sizeof(mfxExtVPPDoUse); + extDoUse.NumAlg = 2; + extDoUse.AlgList = tabDoUseAlg; + tabDoUseAlg[0] = MFX_EXTBUFF_VPP_3DLUT; + tabDoUseAlg[1] = MFX_EXTBUFF_VPP_SCALING; + + mfxExtVPP3DLut lut3DConfig; + memset(&lut3DConfig, 0, sizeof(lut3DConfig)); + lut3DConfig.Header.BufferId = MFX_EXTBUFF_VPP_3DLUT; + lut3DConfig.Header.BufferSz = sizeof(mfxExtVPP3DLut); + + lut3DConfig.ChannelMapping = MFX_3DLUT_CHANNEL_MAPPING_RGB_RGB; + lut3DConfig.BufferType = MFX_RESOURCE_VA_SURFACE; + lut3DConfig.VideoBuffer.DataType = MFX_DATA_TYPE_U16; + lut3DConfig.VideoBuffer.MemLayout = MFX_3DLUT_MEMORY_LAYOUT_INTEL_65LUT; + lut3DConfig.VideoBuffer.MemId = &lut3DMemID; + + mfxExtVPPScaling scalingConfig; + memset(&scalingConfig, 0, sizeof(scalingConfig)); + scalingConfig.Header.BufferId = MFX_EXTBUFF_VPP_SCALING; + scalingConfig.Header.BufferSz = sizeof(mfxExtVPPScaling); + scalingConfig.ScalingMode = MFX_SCALING_MODE_LOWPOWER; + + mfxExtBuffer* ExtBuffer[4]; + ExtBuffer[0] = (mfxExtBuffer*) &extDoUse; + ExtBuffer[1] = (mfxExtBuffer*) &lut3DConfig; + ExtBuffer[2] = (mfxExtBuffer*) &scalingConfig; + ExtBuffer[3] = (mfxExtBuffer*) pExtParamsVPP; + + mfxDecParams.ExtParam = &pExtParamsDec; + mfxDecParams.NumExtParam = 1; + VPPParams.ExtParam = (mfxExtBuffer**) &ExtBuffer[0]; + VPPParams.NumExtParam = 4; + mfxEncParams.ExtParam = &pExtParamsENC; + mfxEncParams.NumExtParam = 1; + + printf("initialize MSDK decoder, vpp, encoder!\n"); + // Initialize the Media SDK decoder + sts = mfxDEC.Init(&mfxDecParams); + MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Initialize the Media SDK encoder + sts = mfxENC.Init(&mfxEncParams); + MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Initialize Media SDK VPP + sts = mfxVPP.Init(&VPPParams); + MSDK_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Retrieve video parameters selected by encoder. + // - BufferSizeInKB parameter is required to set bit stream buffer size + mfxVideoParam par; + memset(&par, 0, sizeof(par)); + sts = mfxENC.GetVideoParam(&par); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Create task pool to improve asynchronous performance (greater GPU utilization) + mfxU16 taskPoolSize = mfxEncParams.AsyncDepth; // number of tasks that can be submitted, before synchronizing is required + std::vector pTasks(taskPoolSize); + std::vector> bstTaskData(taskPoolSize); + for (int i = 0; i < taskPoolSize; i++) { + // Prepare Media SDK bit stream buffer + pTasks[i] = {}; + pTasks[i].mfxBS.MaxLength = par.mfx.BufferSizeInKB * 1000; + bstTaskData[i].resize(pTasks[i].mfxBS.MaxLength); + pTasks[i].mfxBS.Data = bstTaskData[i].data(); + MSDK_CHECK_POINTER(pTasks[i].mfxBS.Data, MFX_ERR_MEMORY_ALLOC); + } + + // =================================== + // Start transcoding the frames + // + printf("start transcoding the frames!\n"); + + mfxTime tStart, tEnd; + mfxGetTime(&tStart); + + mfxSyncPoint syncpD, syncpV; + mfxFrameSurface1* pmfxOutSurface = NULL; + mfxU32 nFrame = 0; + int nIndex = 0; + int nIndex2 = 0; + int nFirstSyncTask = 0; + int nTaskIdx = 0; + + sts = MFX_ERR_NONE; + // + // Stage 1: Main transcoding loop + // + while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_DATA == sts || MFX_ERR_MORE_SURFACE == sts) { + nTaskIdx = GetFreeTaskIndex(pTasks.data(), taskPoolSize); // Find free task + if (MFX_ERR_NOT_FOUND == nTaskIdx) { + // No more free tasks, need to sync + sts = session.SyncOperation(pTasks[nFirstSyncTask].syncp, 60000); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + sts = WriteBitStreamFrame(&pTasks[nFirstSyncTask].mfxBS, fSink.get()); + MSDK_BREAK_ON_ERROR(sts); + + pTasks[nFirstSyncTask].syncp = NULL; + pTasks[nFirstSyncTask].mfxBS.DataLength = 0; + pTasks[nFirstSyncTask].mfxBS.DataOffset = 0; + nFirstSyncTask = (nFirstSyncTask + 1) % taskPoolSize; + + ++nFrame; + if (bEnableOutput && (nFrame%100 == 0)) { + printf("Frame number: %d\r", nFrame); + fflush(stdout); + } + } else { + if (MFX_WRN_DEVICE_BUSY == sts) + MSDK_SLEEP(1); // just wait and then repeat the same call to DecodeFrameAsync + + if (MFX_ERR_MORE_DATA == sts) { + sts = ReadBitStreamData(&mfxBS, fSource.get()); // Read more data to input bit stream + MSDK_BREAK_ON_ERROR(sts); + } + + if (MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE == sts) { + nIndex = GetFreeSurfaceIndex(pSurfaces.data(), nSurfNumDecVPP); // Find free frame surface + MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nIndex, MFX_ERR_MEMORY_ALLOC); + } + printf("decode a frame asychronously!\n"); + // Decode a frame asychronously (returns immediately) + sts = mfxDEC.DecodeFrameAsync(&mfxBS, pSurfaces[nIndex], &pmfxOutSurface, &syncpD); + + // Ignore warnings if output is available, + // if no output and no action required just repeat the DecodeFrameAsync call + if (MFX_ERR_NONE < sts && syncpD) + sts = MFX_ERR_NONE; + + if (MFX_ERR_NONE == sts) { + nIndex2 = GetFreeSurfaceIndex(pSurfaces2.data(), nSurfNumVPPEnc); // Find free frame surface + MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nIndex2, MFX_ERR_MEMORY_ALLOC); + + for (;;) { + // Process a frame asychronously (returns immediately) + printf("process a frame asychronously!\n"); + sts = mfxVPP.RunFrameVPPAsync(pmfxOutSurface, pSurfaces2[nIndex2], NULL, &syncpV); + + if (MFX_ERR_NONE < sts && !syncpV) { // repeat the call if warning and no output + if (MFX_WRN_DEVICE_BUSY == sts) + MSDK_SLEEP(1); // wait if device is busy + } else if (MFX_ERR_NONE < sts && syncpV) { + sts = MFX_ERR_NONE; // ignore warnings if output is available + break; + } else + break; // not a warning + } + + // VPP needs more data, let decoder decode another frame as input + if (MFX_ERR_MORE_DATA == sts) { + continue; + } else if (MFX_ERR_MORE_SURFACE == sts) { + // Not relevant for the illustrated workload! Therefore not handled. + // Relevant for cases when VPP produces more frames at output than consumes at input. E.g. framerate conversion 30 fps -> 60 fps + break; + } else + MSDK_BREAK_ON_ERROR(sts); + + for (;;) { + // Encode a frame asychronously (returns immediately) + printf("encode a frame asychronously!\n"); + sts = mfxENC.EncodeFrameAsync(NULL, pSurfaces2[nIndex2], &pTasks[nTaskIdx].mfxBS, &pTasks[nTaskIdx].syncp); + + if (MFX_ERR_NONE < sts && !pTasks[nTaskIdx].syncp) { // repeat the call if warning and no output + if (MFX_WRN_DEVICE_BUSY == sts) + MSDK_SLEEP(1); // wait if device is busy + } else if (MFX_ERR_NONE < sts && pTasks[nTaskIdx].syncp) { + sts = MFX_ERR_NONE; // ignore warnings if output is available + break; + } else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) { + // Allocate more bitstream buffer memory here if needed... + break; + } else + break; + } + + if (MFX_ERR_MORE_DATA == sts) { + // MFX_ERR_MORE_DATA indicates encoder need more input, request more surfaces from previous operation + sts = MFX_ERR_NONE; + continue; + } + } + } + } + + // MFX_ERR_MORE_DATA means that file has ended, need to go to buffering loop, exit in case of other errors + MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // + // Stage 2: Retrieve the buffered decoded frames + // + while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_SURFACE == sts) { + nTaskIdx = GetFreeTaskIndex(pTasks.data(), taskPoolSize); // Find free task + if (MFX_ERR_NOT_FOUND == nTaskIdx) { + // No more free tasks, need to sync + sts = session.SyncOperation(pTasks[nFirstSyncTask].syncp, 60000); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + sts = WriteBitStreamFrame(&pTasks[nFirstSyncTask].mfxBS, fSink.get()); + MSDK_BREAK_ON_ERROR(sts); + + pTasks[nFirstSyncTask].syncp = NULL; + pTasks[nFirstSyncTask].mfxBS.DataLength = 0; + pTasks[nFirstSyncTask].mfxBS.DataOffset = 0; + nFirstSyncTask = (nFirstSyncTask + 1) % taskPoolSize; + + ++nFrame; + if (bEnableOutput) { + printf("Frame number: %d\r", nFrame); + fflush(stdout); + } + } else { + if (MFX_WRN_DEVICE_BUSY == sts) + MSDK_SLEEP(1); + + nIndex = GetFreeSurfaceIndex(pSurfaces.data(), nSurfNumDecVPP); // Find free frame surface + MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nIndex, MFX_ERR_MEMORY_ALLOC); + + // Decode a frame asychronously (returns immediately) + sts = mfxDEC.DecodeFrameAsync(NULL, pSurfaces[nIndex], &pmfxOutSurface, &syncpD); + + // Ignore warnings if output is available, + // if no output and no action required just repeat the DecodeFrameAsync call + if (MFX_ERR_NONE < sts && syncpD) + sts = MFX_ERR_NONE; + + if (MFX_ERR_NONE == sts) { + nIndex2 = GetFreeSurfaceIndex(pSurfaces2.data(), nSurfNumVPPEnc); // Find free frame surface + MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nIndex2, MFX_ERR_MEMORY_ALLOC); + + for (;;) { + // Process a frame asychronously (returns immediately) + sts = mfxVPP.RunFrameVPPAsync(pmfxOutSurface, pSurfaces2[nIndex2], NULL, &syncpV); + + if (MFX_ERR_NONE < sts && !syncpV) { // repeat the call if warning and no output + if (MFX_WRN_DEVICE_BUSY == sts) + MSDK_SLEEP(1); // wait if device is busy + } else if (MFX_ERR_NONE < sts && syncpV) { + sts = MFX_ERR_NONE; // ignore warnings if output is available + break; + } else + break; // not a warning + } + + // VPP needs more data, let decoder decode another frame as input + if (MFX_ERR_MORE_DATA == sts) { + continue; + } else if (MFX_ERR_MORE_SURFACE == sts) { + // Not relevant for the illustrated workload! Therefore not handled. + // Relevant for cases when VPP produces more frames at output than consumes at input. E.g. framerate conversion 30 fps -> 60 fps + break; + } else + MSDK_BREAK_ON_ERROR(sts); + + for (;;) { + // Encode a frame asychronously (returns immediately) + sts = mfxENC.EncodeFrameAsync(NULL, pSurfaces2[nIndex2], &pTasks[nTaskIdx].mfxBS, &pTasks[nTaskIdx].syncp); + + if (MFX_ERR_NONE < sts && !pTasks[nTaskIdx].syncp) { // repeat the call if warning and no output + if (MFX_WRN_DEVICE_BUSY == sts) + MSDK_SLEEP(1); // wait if device is busy + } else if (MFX_ERR_NONE < sts && pTasks[nTaskIdx].syncp) { + sts = MFX_ERR_NONE; // ignore warnings if output is available + break; + } else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) { + // Allocate more bitstream buffer memory here if needed... + break; + } else + break; + } + + if (MFX_ERR_MORE_DATA == sts) { + // MFX_ERR_MORE_DATA indicates encoder need more input, request more surfaces from previous operation + sts = MFX_ERR_NONE; + continue; + } + } + } + } + + // MFX_ERR_MORE_DATA indicates that all decode buffers has been fetched, exit in case of other errors + MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // + // Stage 3: Retrieve buffered frames from VPP + // + while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_DATA == sts || MFX_ERR_MORE_SURFACE == sts) { + nTaskIdx = GetFreeTaskIndex(pTasks.data(), taskPoolSize); // Find free task + if (MFX_ERR_NOT_FOUND == nTaskIdx) { + // No more free tasks, need to sync + sts = session.SyncOperation(pTasks[nFirstSyncTask].syncp, 60000); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + sts = WriteBitStreamFrame(&pTasks[nFirstSyncTask].mfxBS, fSink.get()); + MSDK_BREAK_ON_ERROR(sts); + + pTasks[nFirstSyncTask].syncp = NULL; + pTasks[nFirstSyncTask].mfxBS.DataLength = 0; + pTasks[nFirstSyncTask].mfxBS.DataOffset = 0; + nFirstSyncTask = (nFirstSyncTask + 1) % taskPoolSize; + + ++nFrame; + if (bEnableOutput) { + printf("Frame number: %d\r", nFrame); + fflush(stdout); + } + } else { + nIndex2 = GetFreeSurfaceIndex(pSurfaces2.data(), nSurfNumVPPEnc); // Find free frame surface + MSDK_CHECK_ERROR(MFX_ERR_NOT_FOUND, nIndex2, MFX_ERR_MEMORY_ALLOC); + + for (;;) { + // Process a frame asychronously (returns immediately) + sts = mfxVPP.RunFrameVPPAsync(NULL, pSurfaces2[nIndex2], NULL, &syncpV); + + if (MFX_ERR_NONE < sts && !syncpV) { // repeat the call if warning and no output + if (MFX_WRN_DEVICE_BUSY == sts) + MSDK_SLEEP(1); // wait if device is busy + } else if (MFX_ERR_NONE < sts && syncpV) { + sts = MFX_ERR_NONE; // ignore warnings if output is available + break; + } else + break; // not a warning + } + + if (MFX_ERR_MORE_SURFACE == sts) { + // Not relevant for the illustrated workload! Therefore not handled. + // Relevant for cases when VPP produces more frames at output than consumes at input. E.g. framerate conversion 30 fps -> 60 fps + break; + } else + MSDK_BREAK_ON_ERROR(sts); + + for (;;) { + // Encode a frame asychronously (returns immediately) + sts = mfxENC.EncodeFrameAsync(NULL, pSurfaces2[nIndex2], &pTasks[nTaskIdx].mfxBS, &pTasks[nTaskIdx].syncp); + + if (MFX_ERR_NONE < sts && !pTasks[nTaskIdx].syncp) { // repeat the call if warning and no output + if (MFX_WRN_DEVICE_BUSY == sts) + MSDK_SLEEP(1); // wait if device is busy + } else if (MFX_ERR_NONE < sts && pTasks[nTaskIdx].syncp) { + sts = MFX_ERR_NONE; // ignore warnings if output is available + break; + } else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) { + // Allocate more bitstream buffer memory here if needed... + break; + } else + break; + } + + if (MFX_ERR_MORE_DATA == sts) { + // MFX_ERR_MORE_DATA indicates encoder need more input, request more surfaces from previous operation + sts = MFX_ERR_NONE; + continue; + } + } + } + + // MFX_ERR_MORE_DATA indicates that all VPP buffers has been fetched, exit in case of other errors + MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // + // Stage 4: Retrieve the buffered encoded frames + // + while (MFX_ERR_NONE <= sts) { + nTaskIdx = GetFreeTaskIndex(pTasks.data(), taskPoolSize); // Find free task + if (MFX_ERR_NOT_FOUND == nTaskIdx) { + // No more free tasks, need to sync + sts = session.SyncOperation(pTasks[nFirstSyncTask].syncp, 60000); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + sts = WriteBitStreamFrame(&pTasks[nFirstSyncTask].mfxBS, fSink.get()); + MSDK_BREAK_ON_ERROR(sts); + + pTasks[nFirstSyncTask].syncp = NULL; + pTasks[nFirstSyncTask].mfxBS.DataLength = 0; + pTasks[nFirstSyncTask].mfxBS.DataOffset = 0; + nFirstSyncTask = (nFirstSyncTask + 1) % taskPoolSize; + + ++nFrame; + if (bEnableOutput) { + printf("Frame number: %d\r", nFrame); + fflush(stdout); + } + } else { + for (;;) { + // Encode a frame asychronously (returns immediately) + sts = mfxENC.EncodeFrameAsync(NULL, NULL, &pTasks[nTaskIdx].mfxBS, &pTasks[nTaskIdx].syncp); + + if (MFX_ERR_NONE < sts && !pTasks[nTaskIdx].syncp) { // repeat the call if warning and no output + if (MFX_WRN_DEVICE_BUSY == sts) + MSDK_SLEEP(1); // wait if device is busy + } else if (MFX_ERR_NONE < sts && pTasks[nTaskIdx].syncp) { + sts = MFX_ERR_NONE; // ignore warnings if output is available + break; + } else + break; + } + } + } + + // MFX_ERR_MORE_DATA indicates that there are no more buffered frames, exit in case of other errors + MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // + // Stage 5: Sync all remaining tasks in task pool + // + while (pTasks[nFirstSyncTask].syncp) { + sts = session.SyncOperation(pTasks[nFirstSyncTask].syncp, 60000); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + sts = WriteBitStreamFrame(&pTasks[nFirstSyncTask].mfxBS, fSink.get()); + MSDK_BREAK_ON_ERROR(sts); + + pTasks[nFirstSyncTask].syncp = NULL; + pTasks[nFirstSyncTask].mfxBS.DataLength = 0; + pTasks[nFirstSyncTask].mfxBS.DataOffset = 0; + nFirstSyncTask = (nFirstSyncTask + 1) % taskPoolSize; + + ++nFrame; + if (bEnableOutput) { + printf("Frame number: %d\r", nFrame); + fflush(stdout); + } + } + + mfxGetTime(&tEnd); + double elapsed = TimeDiffMsec(tEnd, tStart) / 1000; + double fps = ((double)nFrame / elapsed); + printf("\nExecution time: %3.2f s (%3.2f fps)\n", elapsed, fps); + + // =================================================================== + // Clean up resources + // - It is recommended to close Media SDK components first, before releasing allocated surfaces, since + // some surfaces may still be locked by internal Media SDK resources. + + mfxENC.Close(); + mfxDEC.Close(); + mfxVPP.Close(); + // session closed automatically on destruction + + sts = Release3DLutMemory(&lut3DMemID, &hDevice); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + Release(); + + return 0; +}