Add support for rocDecCreateDecoder API (#28)

* Add support for rocDecCreateDecoder API

* check the decoder config support before initializing the vaapi

* rename RocdecDecoderCreateInfo to RocDecoderCreateInfo

* fix a typo

[ROCm/rocdecode commit: 32f854c159]
This commit is contained in:
Aryan Salmanpour
2023-11-01 09:22:46 -04:00
کامیت شده توسط GitHub
والد 9a80f51b34
کامیت b6557252a0
9فایلهای تغییر یافته به همراه170 افزوده شده و 77 حذف شده
@@ -102,7 +102,7 @@ typedef enum rocDecVideoCodec_enum {
/*********************************************************************************/
//! \enum rocDecVideoSurfaceFormat
//! Video surface format enums used for output format of decoded output
//! These enums are used in RocdecDecoderCreateInfo structure
//! These enums are used in RocDecoderCreateInfo structure
/*********************************************************************************/
typedef enum rocDecVideoSurfaceFormat_enum {
rocDecVideoSurfaceFormat_NV12=0, /**< Semi-Planar YUV [Y plane followed by interleaved UV plane] */
@@ -163,10 +163,12 @@ typedef struct _RocdecDecodeCaps {
} RocdecDecodeCaps;
/**************************************************************************************************************/
//! \struct RocdecDecoderCreateInfo
//! \struct RocDecoderCreateInfo
//! This structure is used in rocDecCreateDecoder API
/**************************************************************************************************************/
typedef struct _RocdecDecoderCreateInfo {
typedef struct _RocDecoderCreateInfo {
uint8_t deviceid; /**< IN: the device id for which a decoder should be created
0 for the first device, 1 for the second device on the system, etc.*/
uint32_t ulWidth; /**< IN: Coded sequence width in pixels */
uint32_t ulHeight; /**< IN: Coded sequence height in pixels */
uint32_t ulNumDecodeSurfaces; /**< IN: Maximum number of internal decode surfaces */
@@ -207,7 +209,7 @@ typedef struct _RocdecDecoderCreateInfo {
} target_rect;
uint32_t Reserved2[4]; /**< Reserved for future use - set to zero */
} RocdecDecoderCreateInfo;
} RocDecoderCreateInfo;
/*********************************************************************************************************/
//! \struct RocdecDecodeStatus
@@ -226,8 +228,8 @@ typedef struct _RocdecDecodeStatus {
//! This structure is used in rocDecReconfigureDecoder() API
/****************************************************/
typedef struct _RocdecReconfigureDecoderInfo {
uint32_t ulWidth; /**< IN: Coded sequence width in pixels, MUST be < = ulMaxWidth defined at RocdecDecoderCreateInfo */
uint32_t ulHeight; /**< IN: Coded sequence height in pixels, MUST be < = ulMaxHeight defined at RocdecDecoderCreateInfo */
uint32_t ulWidth; /**< IN: Coded sequence width in pixels, MUST be < = ulMaxWidth defined at RocDecoderCreateInfo */
uint32_t ulHeight; /**< IN: Coded sequence height in pixels, MUST be < = ulMaxHeight defined at RocDecoderCreateInfo */
uint32_t ulTargetWidth; /**< IN: Post processed output width */
uint32_t ulTargetHeight; /**< IN: Post Processed output height */
uint32_t ulNumDecodeSurfaces; /**< IN: Maximum number of internal decode surfaces */
@@ -701,10 +703,10 @@ typedef struct _RocdecProcParams
/***********************************************************************************************************/
/*****************************************************************************************************/
//! \fn rocDecStatus ROCDECAPI rocDecCreateDecoder(rocDecDecoderHandle *phDecoder, RocdecDecoderCreateInfo *pdci)
//! \fn rocDecStatus ROCDECAPI rocDecCreateDecoder(rocDecDecoderHandle *phDecoder, RocDecoderCreateInfo *pdci)
//! Create the decoder object based on pdci. A handle to the created decoder is returned
/*****************************************************************************************************/
extern rocDecStatus ROCDECAPI rocDecCreateDecoder(rocDecDecoderHandle *phDecoder, RocdecDecoderCreateInfo *pdci);
extern rocDecStatus ROCDECAPI rocDecCreateDecoder(rocDecDecoderHandle *phDecoder, RocDecoderCreateInfo *pdci);
/*****************************************************************************************************/
//! \fn rocDecStatus ROCDECAPI rocDecDestroyDecoder(rocDecDecoderHandle hDecoder)
@@ -32,7 +32,7 @@ THE SOFTWARE.
*/
struct DecHandle {
explicit DecHandle() : roc_decoder(std::make_shared<RocDecoder>()) {}; //constructor
explicit DecHandle(RocDecoderCreateInfo& decoder_create_info) : roc_decoder(std::make_shared<RocDecoder>(decoder_create_info)) {}; //constructor
~DecHandle() { clear_errors(); }
std::shared_ptr<RocDecoder> roc_decoder; // class instantiation
bool no_error() { return error.empty(); }
@@ -23,14 +23,7 @@ THE SOFTWARE.
#include "../commons.h"
#include "roc_decoder.h"
RocDecoder::RocDecoder(int device_id):device_id_ {device_id}, num_devices_{0} {
// todo::
if (ROCDEC_SUCCESS != initHIP(device_id_)) {
THROW("Failed to initilize the HIP");
}
initDRMnodes();
}
RocDecoder::RocDecoder(RocDecoderCreateInfo& decoder_create_info): va_video_decoder_{decoder_create_info}, device_id_{decoder_create_info.deviceid} {}
RocDecoder::~RocDecoder() {
// todo::
@@ -43,6 +36,23 @@ RocDecoder::RocDecoder(int device_id):device_id_ {device_id}, num_devices_{0} {
}
}
rocDecStatus RocDecoder::InitializeDecoder() {
rocDecStatus rocdec_status = ROCDEC_SUCCESS;
rocdec_status = InitHIP(device_id_);
if (rocdec_status != ROCDEC_SUCCESS) {
ERR("ERROR: Failed to initilize the HIP!" + TOSTR(rocdec_status));
return rocdec_status;
}
rocdec_status = va_video_decoder_.InitializeDecoder(hip_dev_prop_.gcnArchName);
if (rocdec_status != ROCDEC_SUCCESS) {
ERR("ERROR: Failed to initilize the VAAPI Video decoder!" + TOSTR(rocdec_status));
return rocdec_status;
}
return rocdec_status;
}
rocDecStatus RocDecoder::decodeFrame(RocdecPicParams *pPicParams) {
// todo:: return appropriate decStatus if fails
// call funsction to do va-api decoding using the picture parameters structure
@@ -80,7 +90,7 @@ rocDecStatus RocDecoder::unMapVideoFrame(void *pMappedDevPtr) {
}
rocDecStatus RocDecoder::initHIP(int device_id) {
rocDecStatus RocDecoder::InitHIP(int device_id) {
hipError_t hipStatus = hipSuccess;
hipStatus = hipGetDeviceCount(&num_devices_);
rocDecStatus decStatus = ROCDEC_SUCCESS;
@@ -115,11 +125,3 @@ rocDecStatus RocDecoder::initHIP(int device_id) {
}
return decStatus;
}
void RocDecoder::initDRMnodes() {
// build the DRM render node names
for (int i = 0; i < num_devices_; i++) {
drm_nodes_.push_back("/dev/dri/renderD" + std::to_string(128 + i));
}
}
@@ -32,11 +32,13 @@ THE SOFTWARE.
#include <map>
#include "../api/rocdecode.h"
#include <hip/hip_runtime.h>
#include "vaapi/vaapi_videodecoder.h"
class RocDecoder {
public:
RocDecoder(int device_id = 0);
RocDecoder(RocDecoderCreateInfo &decoder_create_info);
~RocDecoder();
rocDecStatus InitializeDecoder();
rocDecStatus decodeFrame(RocdecPicParams *pPicParams);
rocDecStatus getDecodeStatus(int nPicIdx, RocdecDecodeStatus* pDecodeStatus);
rocDecStatus reconfigureDecoder(RocdecReconfigureDecoderInfo *pDecReconfigParams);
@@ -44,11 +46,10 @@ public:
rocDecStatus unMapVideoFrame(void *pMappedDevPtr);
private:
rocDecStatus initHIP(int device_id);
void initDRMnodes();
rocDecStatus InitHIP(int device_id);
int num_devices_;
int device_id_;
VaapiVideoDecoder va_video_decoder_;
hipDeviceProp_t hip_dev_prop_;
hipStream_t hip_stream_;
std::vector<std::string> drm_nodes_;
};
@@ -49,7 +49,7 @@ struct VcnCodecsSpec {
// The RocDecVcnCodecSpec singleton class for providing access to the the vcn_spec_table
class RocDecVcnCodecSpec {
public:
static RocDecVcnCodecSpec& GetInastance() {
static RocDecVcnCodecSpec& GetInstance() {
static RocDecVcnCodecSpec instance;
return instance;
}
@@ -82,6 +82,28 @@ public:
return ROCDEC_DEVICE_INVALID;
}
}
bool IsCodecConfigSupported(std::string gcn_arch_name, rocDecVideoCodec codec_type, rocDecVideoChromaFormat chroma_format, uint32_t bit_depth_minus8, rocDecVideoSurfaceFormat output_format) {
std::lock_guard<std::mutex> lock(mutex);
auto it = vcn_spec_table.find(gcn_arch_name);
if (it != vcn_spec_table.end()) {
const VcnCodecsSpec& vcn_spec = it->second;
auto it1 = vcn_spec.codecs_spec.find(codec_type);
if (it1 != vcn_spec.codecs_spec.end()) {
const CodecSpec& codec_spec = it1->second;
auto it_chroma_format = std::find(codec_spec.chroma_format.begin(), codec_spec.chroma_format.end(), chroma_format);
auto it_bitdepth_minus8 = std::find(codec_spec.bitdepth_minus8.begin(), codec_spec.bitdepth_minus8.end(), bit_depth_minus8);
if (it_chroma_format != codec_spec.chroma_format.end() && it_bitdepth_minus8 != codec_spec.bitdepth_minus8.end()) {
return (codec_spec.output_format_mask & (static_cast<int>(output_format) + 1));
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
private:
std::unordered_map<std::string, VcnCodecsSpec> vcn_spec_table;
std::mutex mutex;
@@ -26,20 +26,21 @@ THE SOFTWARE.
/*****************************************************************************************************/
//! \fn rocDecStatus ROCDECAPI rocDecCreateDecoder(rocDecDecoderHandle *phDecoder, RocdecDecoderCreateInfo *pdci)
//! \fn rocDecStatus ROCDECAPI rocDecCreateDecoder(rocDecDecoderHandle *phDecoder, RocDecoderCreateInfo *pdci)
//! Create the decoder object based on pdci. A handle to the created decoder is returned
/*****************************************************************************************************/
rocDecStatus ROCDECAPI
rocDecCreateDecoder(rocDecDecoderHandle *phDecoder, RocdecDecoderCreateInfo *pdci) {
rocDecCreateDecoder(rocDecDecoderHandle *phDecoder, RocDecoderCreateInfo *pdci) {
rocDecDecoderHandle handle = nullptr;
try {
handle = new DecHandle();
handle = new DecHandle(*pdci);
}
catch(const std::exception& e) {
ERR( STR("Failed to init the rocDecode handle, ") + STR(e.what()))
return ROCDEC_NOT_INITIALIZED;
}
*phDecoder = handle;
return ROCDEC_SUCCESS;
return static_cast<DecHandle *>(handle)->roc_decoder->InitializeDecoder();
}
/*****************************************************************************************************/
@@ -87,7 +88,7 @@ rocDecGetDecoderCaps(RocdecDecodeCaps *pdc) {
return ROCDEC_DEVICE_INVALID;
}
RocDecVcnCodecSpec& vcn_codec_spec = RocDecVcnCodecSpec::GetInastance();
RocDecVcnCodecSpec& vcn_codec_spec = RocDecVcnCodecSpec::GetInstance();
return vcn_codec_spec.GetDecoderCaps(hip_dev_prop.gcnArchName, pdc);
}
@@ -20,13 +20,77 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <assert.h>
#include <stdint.h>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <string.h>
#include "../commons.h"
#include "vaapi_videodecoder.h"
VaapiVideoDecoder::VaapiVideoDecoder(RocDecoderCreateInfo &decoder_create_info) : decoder_create_info_{decoder_create_info},
drm_fd_{-1}, va_display_{0}, va_config_attrib_{{}}, va_config_id_{0}, va_profile_ {VAProfileNone} {};
VaapiVideoDecoder::~VaapiVideoDecoder() {
if (drm_fd_ != -1) {
close(drm_fd_);
}
if (va_display_) {
if (va_config_id_)
vaDestroyConfig(va_display_, va_config_id_);
vaTerminate(va_display_);
}
}
rocDecStatus VaapiVideoDecoder::InitializeDecoder(std::string gcn_arch_name) {
rocDecStatus rocdec_status = ROCDEC_SUCCESS;
//Before initializing the VAAPI, first check to see if the requested codec config is supported
RocDecVcnCodecSpec& vcn_codec_spec = RocDecVcnCodecSpec::GetInstance();
if (!vcn_codec_spec.IsCodecConfigSupported(gcn_arch_name, decoder_create_info_.CodecType, decoder_create_info_.ChromaFormat,
decoder_create_info_.bitDepthMinus8, decoder_create_info_.OutputFormat)) {
ERR("ERROR: the codec config combination is not supported!");
return ROCDEC_NOT_SUPPORTED;
}
rocdec_status = InitVAAPI();
if (rocdec_status != ROCDEC_SUCCESS) {
ERR("ERROR: Failed to initilize the VAAPI!" + TOSTR(rocdec_status));
return rocdec_status;
}
rocdec_status = CreateDecoderConfig();
if (rocdec_status != ROCDEC_SUCCESS) {
ERR("ERROR: Failed to create a VAAPI decoder configuration" + TOSTR(rocdec_status));
return rocdec_status;
}
return rocdec_status;
}
rocDecStatus VaapiVideoDecoder::InitVAAPI() {
std::string drm_node = "/dev/dri/renderD" + std::to_string(128 + decoder_create_info_.deviceid);
drm_fd_ = open(drm_node.c_str(), O_RDWR);
if (drm_fd_ < 0) {
ERR("ERROR: failed to open drm node " + drm_node);
return ROCDEC_NOT_INITIALIZED;
}
va_display_ = vaGetDisplayDRM(drm_fd_);
vaSetInfoCallback(va_display_, NULL, NULL);
int major_version = 0, minor_version = 0;
CHECK_VAAPI(vaInitialize(va_display_, &major_version, &minor_version));
return ROCDEC_SUCCESS;
}
rocDecStatus VaapiVideoDecoder::CreateDecoderConfig() {
switch (decoder_create_info_.CodecType) {
case rocDecVideoCodec_HEVC:
if (decoder_create_info_.bitDepthMinus8 == 0) {
va_profile_ = VAProfileHEVCMain;
} else if (decoder_create_info_.bitDepthMinus8 == 2) {
va_profile_ = VAProfileHEVCMain10;
}
break;
case rocDecVideoCodec_H264:
va_profile_ = VAProfileH264Main;
break;
default:
ERR("ERROR: the codec type is not supported!");
return ROCDEC_NOT_SUPPORTED;
}
va_config_attrib_.type = VAConfigAttribRTFormat;
CHECK_VAAPI(vaGetConfigAttributes(va_display_, va_profile_, VAEntrypointVLD, &va_config_attrib_, 1));
CHECK_VAAPI(vaCreateConfig(va_display_, va_profile_, VAEntrypointVLD, &va_config_attrib_, 1, &va_config_id_));
return ROCDEC_SUCCESS;
}
@@ -22,38 +22,39 @@ THE SOFTWARE.
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <fcntl.h>
#include <unistd.h>
#include <va/va.h>
#include <va/va_drm.h>
#include <va/va_drmcommon.h>
#include "../roc_decoder_caps.h"
#include "../../commons.h"
#include "../../../api/rocdecode.h"
// class implementing highlevel vaapi decoder
/***********************************************************************************************************/
//! requirement is as follows
//!
//! In order to minimize decode latencies, there should be always at least enough pictures (min 2) in the decode
//! queue at any time, in order to make sure that all VCN decode engines are always busy.
//! In addition to the reqular create and destroy: the decoder needs to have a task-Q for submitting decoding jobs from the high level
//!
//! Overall data flow:
//! - GetCaps(...)
//! - CreateVideoDecoder(...)
//! - For each picture:
//! + submitDecodeTask(0) /* submit first frame for decoding */
//! + ... /* submit next frame for decoding */
//! + submitDecodeTask(N) /* N is determined based on available HW decode engines in the system */
//!
//! + QueryStatus(N-4) /* Query the decode status of N-4 frame */
//! + MapVideoFrame(N-4)
//! + do some processing in HIP
//! + UnmapVideoFrame(N-4)
//! + submitDecodeTask(N+1)
//! + MapVideoFrame(N-3)
//! + ...
//! - DestroyVideoDecoder(...)
//!
//! NOTE:
//! - The decoder has to maintain a Q for decode jobs with associated picture buffers
//! - An intenal thread has to pick up the next available job: If none wait for the Q to fill
/***********************************************************************************************************/
class vaapiVideoDecoder {
#define CHECK_VAAPI(call) { \
VAStatus va_status = (call); \
if (va_status != VA_STATUS_SUCCESS) { \
std::cout << "VAAPI failure: 'status#" << va_status << "' at " << __FILE__ << ":" << __LINE__ << std::endl;\
return ROCDEC_RUNTIME_ERROR; \
} \
}
class VaapiVideoDecoder {
public:
VaapiVideoDecoder(RocDecoderCreateInfo &decoder_create_info);
~VaapiVideoDecoder();
rocDecStatus InitializeDecoder(std::string gcn_arch_name);
private:
RocDecoderCreateInfo decoder_create_info_;
int drm_fd_;
VADisplay va_display_;
VAConfigAttrib va_config_attrib_;
VAConfigID va_config_id_;
VAProfile va_profile_;
rocDecStatus InitVAAPI();
rocDecStatus CreateDecoderConfig();
};
@@ -257,7 +257,7 @@ int RocVideoDecoder::HandleVideoSequence(RocdecVideoFormat *pVideoFormat) {
}
video_format_ = *pVideoFormat;
RocdecDecoderCreateInfo videoDecodeCreateInfo = { 0 };
RocDecoderCreateInfo videoDecodeCreateInfo = { 0 };
videoDecodeCreateInfo.CodecType = pVideoFormat->codec;
videoDecodeCreateInfo.ChromaFormat = pVideoFormat->chroma_format;
videoDecodeCreateInfo.OutputFormat = video_surface_format_;