diff --git a/_studio/mfx_lib/vpp/src/mfx_vpp_hw.cpp b/_studio/mfx_lib/vpp/src/mfx_vpp_hw.cpp index 6e8552b144..201f48b3a9 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; + memset(&pMfxExecuteParams->lut3DInfo, 0, sizeof(pMfxExecuteParams->lut3DInfo)); } /*void MemSetZero4mfxExecuteParams (mfxExecuteParams *pMfxExecuteParams )*/ @@ -2036,6 +2037,16 @@ 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->MemID = m_executeParams.lut3DInfo.MemID; + bufSc->Size = m_executeParams.lut3DInfo.Size; + bufSc->DataPrecision = m_executeParams.lut3DInfo.DataPrecision; + bufSc->MemoryLayout = m_executeParams.lut3DInfo.MemoryLayout; + bufSc->ChannelMapping = m_executeParams.lut3DInfo.ChannelMapping; + } #if (MFX_VERSION >= 1025) else if (MFX_EXTBUFF_VPP_COLOR_CONVERSION == bufferId) { @@ -5664,6 +5675,35 @@ 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.MemID = ext3DLUT->MemID; + executeParams.lut3DInfo.Size = ext3DLUT->Size; + executeParams.lut3DInfo.DataPrecision = ext3DLUT->DataPrecision; + executeParams.lut3DInfo.MemoryLayout = ext3DLUT->MemoryLayout; + executeParams.lut3DInfo.ChannelMapping = ext3DLUT->ChannelMapping; + executeParams.lut3DInfo.IOPattern = videoParam.IOPattern; + } + } + } + } + else + { + bIsFilterSkipped = true; + } + break; } #if (MFX_VERSION >= 1025) @@ -6252,6 +6292,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..4c93a961f1 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) { }; }; @@ -253,6 +256,16 @@ namespace MfxHwVideoProcessing } }; + struct Lut3DInfo { + bool enabled; + mfxMemId MemID; + mfxU16 IOPattern; + mfxU16 Size; + mfxVariantType DataPrecision; + mfx3DLutMemoryLayout MemoryLayout; + mfx3DLutChannelMapping ChannelMapping; + }; + public: mfxExecuteParams(): targetSurface() @@ -328,6 +341,7 @@ namespace MfxHwVideoProcessing VideoSignalInfo.clear(); VideoSignalInfo.assign(1, VideoSignalInfoIn); + memset(&lut3DInfo, 0, sizeof(Lut3DInfo)); }; bool IsDoNothing() @@ -362,6 +376,7 @@ namespace MfxHwVideoProcessing #ifdef MFX_ENABLE_MCTF || bEnableMctf != false #endif + || lut3DInfo.enabled != false ) return false; if (VideoSignalInfoIn != VideoSignalInfoOut) @@ -457,6 +472,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..7708c3fcfc 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,27 @@ mfxStatus VAAPIVideoProcessing::QueryCapabilities(mfxVppCaps& caps) } } + // Query 3DLUT caps, return the number of 3DLUT caps + mfxU32 num_3dlut_caps = 0; + printf("vaQueryVideoProcFilterCaps !\n"); + 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 +934,71 @@ 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.lut_size = pParams->lut3DInfo.Size; + lut3d_param.bit_depth = 16; + lut3d_param.num_channel = 4; + switch(pParams->lut3DInfo.MemoryLayout) + { + case MFX_3DLUT_MEMORY_LAYOUT_INTEL_17LUT: + 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_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_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 */ diff --git a/api/include/mfxdefs.h b/api/include/mfxdefs.h index 2c288c7f87..fbb2172ebf 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,21 @@ typedef enum } mfxStatus; +/*! 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..5c706b18f9 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,36 @@ typedef struct { } mfxExtVPPScaling; MFX_PACK_END() +typedef enum { + MFX_3DLUT_CHANNEL_MAPPING_DEFAULT = 0, + MFX_3DLUT_CHANNEL_MAPPING_RGB_RGB = 1, + MFX_3DLUT_CHANNEL_MAPPING_YUV_RGB = 2, + MFX_3DLUT_CHANNEL_MAPPING_VUY_RGB = 3 +} mfx3DLutChannelMapping; + +typedef enum { + MFX_3DLUT_MEMORY_LAYOUT_DEFAULT = 0, + + MFX_3DLUT_MEMORY_LAYOUT_VENDOR = 0x1000, + MFX_3DLUT_MEMORY_LAYOUT_INTEL_17LUT = MFX_3DLUT_MEMORY_LAYOUT_VENDOR + (1 << 0), + MFX_3DLUT_MEMORY_LAYOUT_INTEL_33LUT = MFX_3DLUT_MEMORY_LAYOUT_VENDOR + (1 << 1), + MFX_3DLUT_MEMORY_LAYOUT_INTEL_65LUT = MFX_3DLUT_MEMORY_LAYOUT_VENDOR + (1 << 2) +} mfx3DLutMemoryLayout; + +MFX_PACK_BEGIN_USUAL_STRUCT() +typedef struct { + mfxExtBuffer Header; + + mfxMemId MemID; + mfxU16 Size; + mfxVariantType DataPrecision; + mfx3DLutMemoryLayout MemoryLayout; + mfx3DLutChannelMapping ChannelMapping; + + mfxU16 reserved[12]; +} mfxExtVPP3DLut; +MFX_PACK_END() + #if (MFX_VERSION >= MFX_VERSION_NEXT) /* SceneChangeType */ 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/src/base_allocator.cpp b/samples/sample_common/src/base_allocator.cpp index 4938cd99c5..c90aaa66e3 100644 --- a/samples/sample_common/src/base_allocator.cpp +++ b/samples/sample_common/src/base_allocator.cpp @@ -102,6 +102,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; } diff --git a/samples/sample_multi_transcode/include/pipeline_transcode.h b/samples/sample_multi_transcode/include/pipeline_transcode.h index ea6f064afb..ed32ddeb5f 100644 --- a/samples/sample_multi_transcode/include/pipeline_transcode.h +++ b/samples/sample_multi_transcode/include/pipeline_transcode.h @@ -137,6 +137,18 @@ namespace TranscodingSample mfxU16 FilterStrength; }; + // this is a structure with 3dlut-parameteres + // that can be changed in run-time; + struct s3DLutParam + { + msdk_char str3DLutFile[MSDK_MAX_FILENAME_LEN]; //3 //3DLut Binary File + mfxU16 nSegmentSize; + mfxU16 nMultipleSize; + mfxU16 nBitDepth; + mfxU16 nNumChannel; + mfxU32 nChannelMapping; + }; + struct sMctfRunTimeParams { sMctfRunTimeParams() : CurIdx(0) @@ -369,6 +381,9 @@ namespace TranscodingSample bool shouldPrintPresets; bool rawInput; + + // 3DLut filter in VPP + s3DLutParam* p3DLutParam; }; struct sInputParams: public __sInputParams @@ -932,6 +947,13 @@ 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; + 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..6055d707aa 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,7 @@ sInputParams::sInputParams() : __sInputParams() bDecoderPostProcessing = false; bROIasQPMAP = false; #endif + p3DLutParam = NULL; } CTranscodingPipeline::CTranscodingPipeline(): @@ -167,7 +168,11 @@ CTranscodingPipeline::CTranscodingPipeline(): m_nReqFrameTime(0), m_nOutputFramesNum(0), shouldUseGreedyFormula(false), - m_nRotationAngle(0) + m_nRotationAngle(0), + m_n3DLutVMemId(0), + m_b3DLutEnable(false), + m_n3DLutVWidth(65), + m_n3DLutVHeight(65*128*2) { MSDK_ZERO_MEMORY(m_RotateParam); MSDK_ZERO_MEMORY(m_mfxDecResponse); @@ -205,6 +210,7 @@ CTranscodingPipeline::CTranscodingPipeline(): CTranscodingPipeline::~CTranscodingPipeline() { + m_b3DLutEnable = false; Close(); } //CTranscodingPipeline::CTranscodingPipeline() @@ -371,6 +377,11 @@ mfxStatus CTranscodingPipeline::VPPPreInit(sInputParams *pParams) m_bIsVpp = true; } + if (pParams->p3DLutParam) + { + m_bIsVpp = true; + } + if (m_bIsVpp) { sts = InitVppMfxParams(pParams); @@ -3130,6 +3141,19 @@ mfxStatus CTranscodingPipeline::InitVppMfxParams(sInputParams *pInParams) MFX_PICSTRUCT_FIELD_BFF); } + if (pInParams->p3DLutParam) + { + auto lut = m_mfxVppParams.AddExtBuffer(); + + lut->MemID = &m_n3DLutVMemId; + lut->Size = m_n3DLutVWidth; + lut->DataPrecision = MFX_VARIANT_TYPE_U16; + lut->MemoryLayout = MFX_3DLUT_MEMORY_LAYOUT_INTEL_65LUT; + lut->ChannelMapping = MFX_3DLUT_CHANNEL_MAPPING_RGB_RGB; + + m_b3DLutEnable = true; + } + if (enhFilterCount) { auto doUse = m_mfxVppParams.AddExtBuffer(); @@ -3200,7 +3224,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 +3418,20 @@ mfxStatus CTranscodingPipeline::AllocFrames() } } + if (m_b3DLutEnable) + { + mfxFrameAllocRequest Alloc3DLut; + MSDK_ZERO_MEMORY(Alloc3DLut); + Alloc3DLut.Type = MFX_MEMTYPE_EXTERNAL_FRAME; + Alloc3DLut.Info.FourCC = MFX_FOURCC_RGB4; + Alloc3DLut.Info.Width = m_n3DLutVWidth; + Alloc3DLut.Info.Height = m_n3DLutVHeight; + Alloc3DLut.NumFrameSuggested = 1; + sts = AllocFrames(&Alloc3DLut, false); + MSDK_CHECK_STATUS(sts, "Alloc 3DLUT surface failed"); + m_n3DLutVMemId = Alloc3DLut.AllocId; + } + return MFX_ERR_NONE; } diff --git a/samples/sample_multi_transcode/src/transcode_utils.cpp b/samples/sample_multi_transcode/src/transcode_utils.cpp index 515783383c..7db942b694 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: @@ -1534,6 +1534,38 @@ mfxStatus ParseVPPCmdLine(msdk_char *argv[], mfxU32 argc, mfxU32& index, Transco } return MFX_ERR_NONE; } + else if (0 == msdk_strcmp(argv[index], MSDK_STRING("-3dlut"))) + { + // 3dult is requested to be enabled by APP + if (params->p3DLutParam == NULL) + { + params->p3DLutParam = (s3DLutParam*) malloc(sizeof(s3DLutParam)); + memset(params->p3DLutParam, 0, sizeof(s3DLutParam)); + } + s3DLutParam* p3DLutParam = params->p3DLutParam; + if (p3DLutParam) + { + VAL_CHECK(index+1 == argc, index, argv[index]); + index++; + // 3dlut file + if (msdk_strlen(argv[index]) < MSDK_ARRAY_LEN(p3DLutParam->str3DLutFile)) + { + msdk_opt_read(argv[index], p3DLutParam->str3DLutFile); + } + else + { + return MFX_ERR_UNSUPPORTED; + } + // 3dlut attribute by default + p3DLutParam->nSegmentSize = 65; + p3DLutParam->nMultipleSize = 128; + p3DLutParam->nNumChannel = 4; + p3DLutParam->nBitDepth = 16; + p3DLutParam->nChannelMapping = 0; + } + + 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..21e085e086 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,47 @@ 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; + mfxU8 buf[4096]; // 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 + ReadPlaneData(w, h, buf, ptr, pitch, 0, fSource, nBitDepth); + if (MFX_ERR_NONE != sts) + return sts; + } return MFX_ERR_NONE; } 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..777eb910fc 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,108 @@ 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; + unsigned char * newImageBuffer = NULL; + VASurfaceID surface_id = 0; + 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); + + 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 = (unsigned char*)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; + + VASurfaceID surface_id = *((VASurfaceID*)memId); + vaDestroySurfaces(va_dpy, &surface_id, 1); + + return MFX_ERR_NONE; +} + 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..f3553c75fe --- /dev/null +++ b/tutorials/simple_4_vpp_resize_3dlut_vmem/src/simple_vpp_vmem.cpp @@ -0,0 +1,374 @@ +// 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.BitDepthLuma = 0; + VPPParams.vpp.Out.BitDepthChroma = 0; + VPPParams.vpp.Out.Shift = 0; + 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("Allocate surface headers (mfxFrameSurface1) for VPP!\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); + } + } + printf("Allocate surface (pVPPSurfacesOut) for VPP!\n"); + std::vector pVPPSurfacesOut(nVPPSurfNumOut); + 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.MemID = &lut3DMemID; + lut3DConfig.Size = 65; + lut3DConfig.DataPrecision = MFX_VARIANT_TYPE_U16; + lut3DConfig.MemoryLayout = MFX_3DLUT_MEMORY_LAYOUT_INTEL_65LUT; + lut3DConfig.ChannelMapping = MFX_3DLUT_CHANNEL_MAPPING_RGB_RGB; + + 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]; + + printf("Initialize Media SDK VPP!\n"); + // 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); + + 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(); + + printf("exit\n"); + + 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..2047460ca7 --- /dev/null +++ b/tutorials/simple_5_transcode_opaque_async_vppresize_3dlut/src/simple_5_transcode_opaque_async_vppresize_3dlut.cpp @@ -0,0 +1,755 @@ +// 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.MemID = &lut3DMemID; + lut3DConfig.Size = 65; + lut3DConfig.DataPrecision = MFX_VARIANT_TYPE_U16; + lut3DConfig.ChannelMapping = MFX_3DLUT_CHANNEL_MAPPING_RGB_RGB; + + 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; +}