Rr/roc video decode class (#20)
* WIP: class implementation
* add more definitions
* rocvideodecode implementation
* formatting fixes
* address review comments
[ROCm/rocdecode commit: d0e6743872]
Este commit está contenido en:
@@ -132,7 +132,7 @@ if(HIP_FOUND AND FFMPEG_FOUND AND Libva_FOUND)
|
||||
target_link_libraries(${PROJECT_NAME} ${LINK_LIBRARY_LIST})
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(FILES api/rocdecode.h api/rocparser.h utils/video_demuxer.hpp
|
||||
install(FILES api/rocdecode.h api/rocparser.h utils/video_demuxer.hpp utils/rocvideodecode/roc_video_dec.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
|
||||
|
||||
message("-- ${White}AMD ROCm rocDecode -- CMAKE_CXX_FLAGS:${CMAKE_CXX_FLAGS}${ColourReset}")
|
||||
|
||||
@@ -108,7 +108,7 @@ typedef enum rocDecVideoSurfaceFormat_enum {
|
||||
rocDecVideoSurfaceFormat_NV12=0, /**< Semi-Planar YUV [Y plane followed by interleaved UV plane] */
|
||||
rocDecVideoSurfaceFormat_P016=1, /**< 16 bit Semi-Planar YUV [Y plane followed by interleaved UV plane].
|
||||
Can be used for 10 bit(6LSB bits 0), 12 bit (4LSB bits 0) */
|
||||
rocDecVideoSurfaceFormat_YUV444=2, /**< Planar YUV [Y plane followed by U and V planes] */
|
||||
rocDecVideoSurfaceFormat_YUV444=2, /**< Planar YUV [Y plane followed by U and V planes] */
|
||||
rocDecVideoSurfaceFormat_YUV444_16Bit=3, /**< 16 bit Planar YUV [Y plane followed by U and V planes].
|
||||
Can be used for 10 bit(6LSB bits 0), 12 bit (4LSB bits 0) */
|
||||
} rocDecVideoSurfaceFormat;
|
||||
@@ -125,6 +125,7 @@ typedef enum rocDecVideoChromaFormat_enum {
|
||||
rocDecVideoChromaFormat_444 /**< YUV 4:4:4 */
|
||||
} rocDecVideoChromaFormat;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
//! \enum rocDecDecodeStatus
|
||||
//! Decode status enums
|
||||
@@ -178,14 +179,14 @@ typedef struct _RocdecDecoderCreateInfo {
|
||||
uint32_t ulMaxWidth; /**< IN: Coded sequence max width in pixels used with reconfigure Decoder */
|
||||
uint32_t ulMaxHeight; /**< IN: Coded sequence max height in pixels used with reconfigure Decoder */
|
||||
/**
|
||||
* IN: area of the frame that should be copied
|
||||
* IN: area of the frame that should be displayed
|
||||
*/
|
||||
struct {
|
||||
int16_t left;
|
||||
int16_t top;
|
||||
int16_t right;
|
||||
int16_t bottom;
|
||||
} roi_area;
|
||||
} display_area;
|
||||
|
||||
rocDecVideoSurfaceFormat OutputFormat; /**< IN: rocDecVideoSurfaceFormat_XXX */
|
||||
uint32_t ulTargetWidth; /**< IN: Post-processed output width (Should be aligned to 2) */
|
||||
@@ -203,7 +204,6 @@ typedef struct _RocdecDecoderCreateInfo {
|
||||
int16_t bottom;
|
||||
} target_rect;
|
||||
|
||||
uint32_t enableHistogram; /**< IN: enable histogram output, if supported */
|
||||
uint32_t Reserved2[4]; /**< Reserved for future use - set to zero */
|
||||
} RocdecDecoderCreateInfo;
|
||||
|
||||
@@ -668,7 +668,7 @@ typedef struct _RocdecProcParams
|
||||
uint64_t raw_output_dptr; /**< IN: Output HIP device mem ptr for raw YUV extensions */
|
||||
uint32_t raw_output_pitch; /**< IN: pitch in bytes of raw YUV output (should be aligned appropriately) */
|
||||
uint32_t raw_output_format; /**< IN: Output YUV format (rocDecVideoCodec_enum) */
|
||||
hipStream_t output_hstream; /**< IN: stream object used by rocDecMapVideoFrame */
|
||||
hipStream_t output_hipstream; /**< IN: stream object used by rocDecMapVideoFrame */
|
||||
uint32_t Reserved[16]; /**< Reserved for future use (set to zero) */
|
||||
} RocdecProcParams;
|
||||
|
||||
@@ -714,10 +714,10 @@ extern rocDecStatus ROCDECAPI rocDecDestroyDecoder(rocDecDecoderHandle hDecoder)
|
||||
//! \fn rocDecStatus ROCDECAPI rocdecGetDecoderCaps(RocdecDecodeCaps *pdc)
|
||||
//! Queries decode capabilities of AMD's VCN decoder based on CodecType, ChromaFormat and BitDepthMinus8 parameters.
|
||||
//! 1. Application fills IN parameters CodecType, ChromaFormat and BitDepthMinus8 of RocdecDecodeCaps structure
|
||||
//! 2. On calling rocdecGetDecoderCaps, driver fills OUT parameters if the IN parameters are supported
|
||||
//! 2. On calling rocdecGetDecoderCaps, driver fills OUT parameters (for GPU device) if the IN parameters are supported
|
||||
//! If IN parameters passed to the driver are not supported by AMD-VCN-HW, then all OUT params are set to 0.
|
||||
/**********************************************************************************************************************/
|
||||
extern rocDecStatus ROCDECAPI rocDecGetDecoderCaps(rocDecDecoderHandle hDecoder, RocdecDecodeCaps *pdc);
|
||||
extern rocDecStatus ROCDECAPI rocDecGetDecoderCaps(RocdecDecodeCaps *pdc);
|
||||
|
||||
/*****************************************************************************************************/
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecDecodeFrame(rocDecDecoderHandle hDecoder, RocdecPicParams *pPicParams)
|
||||
@@ -746,10 +746,10 @@ extern rocDecStatus ROCDECAPI rocDecReconfigureDecoder(rocDecDecoderHandle hDeco
|
||||
//! uint32_t *pDevMemPtr, uint32_t *pHorizontalPitch,
|
||||
//! RocdecProcParams *pVidPostprocParams);
|
||||
//! Post-process and map video frame corresponding to nPicIdx for use in HIP. Returns HIP device pointer and associated
|
||||
//! pitch(horizontal stride) of the video frame. Returns device memory pointers for each plane (Y, U and V) seperately
|
||||
//! pitch(horizontal stride) of the video frame. Returns device memory pointers and pitch for each plane (Y, U and V) seperately
|
||||
/************************************************************************************************************************/
|
||||
extern rocDecStatus ROCDECAPI rocDecMapVideoFrame(rocDecDecoderHandle hDecoder, int nPicIdx,
|
||||
void *pDevMemPtr[3], uint32_t *pHorizontalPitch[3],
|
||||
void *pDevMemPtr[3], uint32_t (&pHorizontalPitch)[3],
|
||||
RocdecProcParams *pVidPostprocParams);
|
||||
|
||||
/*****************************************************************************************************/
|
||||
|
||||
@@ -132,6 +132,21 @@ typedef struct {
|
||||
uint8_t raw_seqhdr_data[1024]; /**< OUT: Sequence header data */
|
||||
} RocdecVideoFormatEx;
|
||||
|
||||
/***************************************************************/
|
||||
//! \enum RocdecVideoPacketFlags
|
||||
//! Data packet flags
|
||||
//! Used in RocdecSourceDataPacket structure
|
||||
/***************************************************************/
|
||||
typedef enum {
|
||||
ROCDEC_PKT_ENDOFSTREAM = 0x01, /**< Set when this is the last packet for this stream */
|
||||
ROCDEC_PKT_TIMESTAMP = 0x02, /**< Timestamp is valid */
|
||||
ROCDEC_PKT_DISCONTINUITY = 0x04, /**< Set when a discontinuity has to be signalled */
|
||||
ROCDEC_PKT_ENDOFPICTURE = 0x08, /**< Set when the packet contains exactly one frame or one field */
|
||||
ROCDEC_PKT_NOTIFY_EOS = 0x10, /**< If this flag is set along with ROCDEC_PKT_ENDOFSTREAM, an additional (dummy)
|
||||
display callback will be invoked with null value of ROCDECPARSERDISPINFO which
|
||||
should be interpreted as end of the stream. */
|
||||
} RocdecVideoPacketFlags;
|
||||
|
||||
/*****************************************************************************/
|
||||
//! \ingroup STRUCTS
|
||||
//! \struct RocdecSourceDataPacket
|
||||
@@ -140,11 +155,11 @@ typedef struct {
|
||||
//! IN for rocDecParseVideoData
|
||||
/*****************************************************************************/
|
||||
typedef struct _RocdecSourceDataPacket {
|
||||
uint32_t flags; /**< IN: Combination of CUVID_PKT_XXX flags */
|
||||
uint32_t flags; /**< IN: Combination of ROCDEC_PKT_XXX flags */
|
||||
uint32_t payload_size; /**< IN: number of bytes in the payload (may be zero if EOS flag is set) */
|
||||
const uint8_t *payload; /**< IN: Pointer to packet payload data (may be NULL if EOS flag is set) */
|
||||
RocdecTimeStamp pts; /**< IN: Presentation time stamp (10MHz clock), only valid if
|
||||
CUVID_PKT_TIMESTAMP flag is set */
|
||||
ROCDEC_PKT_TIMESTAMP flag is set */
|
||||
} RocdecSourceDataPacket;
|
||||
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
# ##############################################################################
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(ROC_VIDEO_DEC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../utils/rocvideodecode)
|
||||
# videoDecode
|
||||
add_test(
|
||||
NAME
|
||||
|
||||
@@ -33,13 +33,13 @@ set(DEFAULT_AMDGPU_TARGETS "gfx803;gfx900;gfx906;gfx908;gfx90a;gfx940;gfx1030;gf
|
||||
set(AMDGPU_TARGETS "${DEFAULT_AMDGPU_TARGETS}" CACHE STRING "List of specific machine types for library to target")
|
||||
find_package(HIP QUIET)
|
||||
find_package(FFmpeg QUIET)
|
||||
find_package(Libva QUIET)
|
||||
if(HIP_FOUND AND FFMPEG_FOUND AND Libva_FOUND)
|
||||
message("-- ${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
if(HIP_FOUND AND FFMPEG_FOUND)
|
||||
include_directories (${ROCM_PATH}/include/rocdecode)
|
||||
list(APPEND SOURCES ${PROJECT_SOURCE_DIR} videodecode.cpp)
|
||||
list(APPEND SOURCES ${PROJECT_SOURCE_DIR} videodecode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/rocvideodecode/roc_video_dec.cpp)
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17")
|
||||
target_link_libraries(${PROJECT_NAME} ${AVUTIL_LIBRARY} ${AVCODEC_LIBRARY} ${AVFORMAT_LIBRARY} Libva::va Libva::va_drm hip::device rocdecode)
|
||||
target_link_libraries(${PROJECT_NAME} ${AVUTIL_LIBRARY} ${AVCODEC_LIBRARY} ${AVFORMAT_LIBRARY} hip::device rocdecode)
|
||||
else()
|
||||
if (NOT HIP_FOUND)
|
||||
message(FATAL_ERROR "-- ERROR!: HIP Not Found! - please install ROCm and HIP!")
|
||||
|
||||
@@ -49,4 +49,14 @@ rocDecStatus H264VideoParser::Initialize(RocdecParserParams *pParams) {
|
||||
*/
|
||||
rocDecStatus H264VideoParser::ParseVideoData(RocdecSourceDataPacket *pData) {
|
||||
return ROCDEC_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief function to uninitialize h264 parser
|
||||
*
|
||||
* @return rocDecStatus
|
||||
*/
|
||||
rocDecStatus H264VideoParser::UnInitialize() {
|
||||
//todo::
|
||||
return ROCDEC_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,13 @@ public:
|
||||
* @return rocDecStatus: returns success on completion, else error_code for failure
|
||||
*/
|
||||
virtual rocDecStatus ParseVideoData(RocdecSourceDataPacket *pData);
|
||||
/**
|
||||
* @brief function to uninitialize h264 parser
|
||||
*
|
||||
* @return rocDecStatus
|
||||
*/
|
||||
virtual rocDecStatus UnInitialize(); // derived method
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -43,6 +43,17 @@ rocDecStatus HEVCVideoParser::Initialize(RocdecParserParams *p_params) {
|
||||
return ROCDEC_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief function to uninitialize hevc parser
|
||||
*
|
||||
* @return rocDecStatus
|
||||
*/
|
||||
rocDecStatus HEVCVideoParser::UnInitialize() {
|
||||
//todo:: do any uninitialization here
|
||||
return ROCDEC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
rocDecStatus HEVCVideoParser::ParseVideoData(RocdecSourceDataPacket *p_data) {
|
||||
bool status = ParseFrameData(p_data->payload, p_data->payload_size);
|
||||
if (!status) {
|
||||
|
||||
@@ -59,12 +59,20 @@ public:
|
||||
*/
|
||||
virtual rocDecStatus ParseVideoData(RocdecSourceDataPacket *p_data);
|
||||
|
||||
/*! \brief HEVCParser object destructor
|
||||
/**
|
||||
* @brief function to uninitialize hevc parser
|
||||
*
|
||||
* @return rocDecStatus
|
||||
*/
|
||||
virtual rocDecStatus UnInitialize(); // derived method
|
||||
|
||||
/**
|
||||
* @brief HEVCParser object destructor
|
||||
*/
|
||||
virtual ~HEVCVideoParser();
|
||||
|
||||
protected:
|
||||
/*! \brief Enumerator for the NAL Unit types - ISO-IEC 14496-15-2004.pdf, page 14, table 1 " NAL unit types in elementary streams.
|
||||
/*! \brief Enumerator for the NAL Unit types - ISO-IEC 14496-15-2004.pdf, page 14, table 1 " NAL unit types in elementary streams
|
||||
*/
|
||||
enum NalUnitType {
|
||||
NAL_UNIT_CODED_SLICE_TRAIL_N = 0, // 0
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
const char* error_msg() { return error.c_str(); }
|
||||
void capture_error(const std::string& err_msg) { error = err_msg; }
|
||||
rocDecStatus ParseVideoData(RocdecSourceDataPacket *pPacket) { return roc_parser_->ParseVideoData(pPacket); }
|
||||
rocDecStatus DestroyParser() { return destroy_parser(); };
|
||||
|
||||
private:
|
||||
std::shared_ptr<RocVideoParser> roc_parser_ = nullptr; // class instantiation
|
||||
@@ -59,5 +60,15 @@ private:
|
||||
THROW("rocParser Initialization failed with error: "+ TOSTR(ret));
|
||||
}
|
||||
}
|
||||
rocDecStatus destroy_parser() {
|
||||
rocDecStatus ret = ROCDEC_NOT_INITIALIZED;
|
||||
if (roc_parser_ ) {
|
||||
ret = roc_parser_->UnInitialize();
|
||||
if (ret != ROCDEC_SUCCESS)
|
||||
THROW("rocParser UnInitialization failed with error: "+ TOSTR(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string error;
|
||||
};
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
RocdecParserParams *GetParserParams() {return parser_params_;};
|
||||
virtual rocDecStatus Initialize(RocdecParserParams *pParams);
|
||||
virtual rocDecStatus ParseVideoData(RocdecSourceDataPacket *pData) = 0; // pure virtual: implemented by derived class
|
||||
virtual rocDecStatus UnInitialize() = 0; // pure virtual: implemented by derived class
|
||||
|
||||
protected:
|
||||
RocdecParserParams *parser_params_ = nullptr;
|
||||
|
||||
@@ -65,3 +65,23 @@ rocDecParseVideoData(RocdecVideoParser handle, RocdecSourceDataPacket *pPacket)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
//! \ingroup FUNCTS
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecDestroyVideoParser(RocdecVideoParser handle)
|
||||
//! Destroy the video parser object
|
||||
/************************************************************************************************/
|
||||
extern rocDecStatus ROCDECAPI
|
||||
rocDecDestroyVideoParser(RocdecVideoParser handle) {
|
||||
auto parser_hdl = static_cast<RocParserHandle *> (handle);
|
||||
rocDecStatus ret;
|
||||
try {
|
||||
ret = parser_hdl->DestroyParser();
|
||||
}
|
||||
catch(const std::exception& e) {
|
||||
parser_hdl->capture_error(e.what());
|
||||
ERR(e.what())
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -42,13 +42,6 @@ RocDecoder::RocDecoder(int device_id):device_id_ {device_id}, num_devices_{0} {
|
||||
}
|
||||
}
|
||||
}
|
||||
rocDecStatus RocDecoder::getDecoderCaps(RocdecDecodeCaps *pdc) {
|
||||
// todo:: return appropriate decStatus if fails
|
||||
//vaQueryConfigProfiles
|
||||
// fill the RocdecDecodeCaps struct
|
||||
// return status
|
||||
return ROCDEC_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
rocDecStatus RocDecoder::decodeFrame(RocdecPicParams *pPicParams) {
|
||||
// todo:: return appropriate decStatus if fails
|
||||
@@ -73,7 +66,7 @@ rocDecStatus RocDecoder::reconfigureDecoder(RocdecReconfigureDecoderInfo *pDecRe
|
||||
}
|
||||
|
||||
rocDecStatus RocDecoder::mapVideoFrame(int nPicIdx, void *pDevMemPtr[3],
|
||||
unsigned int *pHorizontalPitch[3], RocdecProcParams *pVidPostprocParams) {
|
||||
unsigned int pHorizontalPitch[3], RocdecProcParams *pVidPostprocParams) {
|
||||
// todo:: return appropriate decStatus
|
||||
// Post-process and map video frame corresponding to nPicIdx for use in HIP. Returns HIP device pointer and associated
|
||||
// pitch(horizontal stride) of the video frame. Returns device memory pointers for each plane (Y, U and V) seperately
|
||||
|
||||
@@ -38,11 +38,10 @@ class RocDecoder {
|
||||
public:
|
||||
RocDecoder(int device_id = 0);
|
||||
~RocDecoder();
|
||||
rocDecStatus getDecoderCaps(RocdecDecodeCaps *pdc);
|
||||
rocDecStatus decodeFrame(RocdecPicParams *pPicParams);
|
||||
rocDecStatus getDecodeStatus(int nPicIdx, RocdecDecodeStatus* pDecodeStatus);
|
||||
rocDecStatus reconfigureDecoder(RocdecReconfigureDecoderInfo *pDecReconfigParams);
|
||||
rocDecStatus mapVideoFrame(int nPicIdx, void *pDevMemPtr[3], unsigned int *pHorizontalPitch[3], RocdecProcParams *pVidPostprocParams);
|
||||
rocDecStatus mapVideoFrame(int nPicIdx, void *pDevMemPtr[3], unsigned int pHorizontalPitch[3], RocdecProcParams *pVidPostprocParams);
|
||||
rocDecStatus unMapVideoFrame(void *pMappedDevPtr);
|
||||
|
||||
private:
|
||||
|
||||
@@ -58,19 +58,9 @@ rocDecDestroyDecoder(rocDecDecoderHandle hDecoder) {
|
||||
//! 2. On calling rocdecGetDecoderCaps, driver fills OUT parameters if the IN parameters are supported
|
||||
//! If IN parameters passed to the driver are not supported by AMD-VCN-HW, then all OUT params are set to 0.
|
||||
/**********************************************************************************************************************/
|
||||
rocDecStatus ROCDECAPI
|
||||
rocDecGetDecoderCaps(rocDecDecoderHandle hDecoder, RocdecDecodeCaps *pdc) {
|
||||
auto handle = static_cast<DecHandle *> (hDecoder);
|
||||
rocDecStatus ret;
|
||||
try {
|
||||
ret = handle->roc_decoder->getDecoderCaps(pdc);
|
||||
}
|
||||
catch(const std::exception& e) {
|
||||
handle->capture_error(e.what());
|
||||
ERR(e.what())
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
return ret;
|
||||
rocDecStatus ROCDECAPI
|
||||
rocDecGetDecoderCaps(RocdecDecodeCaps *pdc) {
|
||||
return ROCDEC_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/*****************************************************************************************************/
|
||||
@@ -100,7 +90,7 @@ rocDecDecodeFrame(rocDecDecoderHandle hDecoder, RocdecPicParams *pPicParams) {
|
||||
//! API returns CUDA_ERROR_NOT_SUPPORTED error code for unsupported GPU or codec.
|
||||
/************************************************************************************************************/
|
||||
rocDecStatus ROCDECAPI
|
||||
RocdecGetDecodeStatus(rocDecDecoderHandle hDecoder, int nPicIdx, RocdecDecodeStatus* pDecodeStatus) {
|
||||
rocDecGetDecodeStatus(rocDecDecoderHandle hDecoder, int nPicIdx, RocdecDecodeStatus* pDecodeStatus) {
|
||||
auto handle = static_cast<DecHandle *> (hDecoder);
|
||||
rocDecStatus ret;
|
||||
try {
|
||||
@@ -143,7 +133,7 @@ rocDecReconfigureDecoder(rocDecDecoderHandle hDecoder, RocdecReconfigureDecoderI
|
||||
/************************************************************************************************************************/
|
||||
rocDecStatus ROCDECAPI
|
||||
rocDecMapVideoFrame(rocDecDecoderHandle hDecoder, int nPicIdx,
|
||||
void *pDevMemPtr[3], unsigned int *pHorizontalPitch[3], RocdecProcParams *pVidPostprocParams) {
|
||||
void *pDevMemPtr[3], uint32_t (&pHorizontalPitch)[3], RocdecProcParams *pVidPostprocParams) {
|
||||
auto handle = static_cast<DecHandle *> (hDecoder);
|
||||
rocDecStatus ret;
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdexcept>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#define TOSTR(X) std::to_string(static_cast<int>(X))
|
||||
#define STR(X) std::string(X)
|
||||
|
||||
#if DBGINFO
|
||||
#define INFO(X) std::clog << "[INF] " << " {" << __func__ <<"} " << " " << X << std::endl;
|
||||
#else
|
||||
#define INFO(X) ;
|
||||
#endif
|
||||
#define ERR(X) std::cerr << "[ERR] " << " {" << __func__ <<"} " << " " << X << std::endl;
|
||||
|
||||
|
||||
class rocVideoDecodeException : public std::exception {
|
||||
public:
|
||||
|
||||
explicit rocVideoDecodeException(const std::string& message):_message(message){}
|
||||
virtual const char* what() const throw() override {
|
||||
return _message.c_str();
|
||||
}
|
||||
private:
|
||||
std::string _message;
|
||||
};
|
||||
|
||||
#define THROW(X) throw rocVideoDecodeException(" { "+std::string(__func__)+" } " + X);
|
||||
@@ -0,0 +1,663 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
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 "roc_video_dec.h"
|
||||
|
||||
RocVideoDecoder::RocVideoDecoder(int device_id, bool b_use_device_mem, rocDecVideoCodec codec, bool b_low_latency, bool device_frame_pitched,
|
||||
const Rect *p_crop_rect, const Dim *p_resize_dim, bool extract_user_SEI_Message, int max_width, int max_height,
|
||||
uint32_t clk_rate, bool force_zero_latency) : device_id_{device_id}, b_use_device_mem_(b_use_device_mem), codec_id_(codec),
|
||||
b_low_latency_(b_low_latency), b_device_frame_pitched_(device_frame_pitched), b_extract_sei_message_(extract_user_SEI_Message),
|
||||
max_width_ (max_width), max_height_(max_height), b_force_zero_latency_(force_zero_latency) {
|
||||
|
||||
if (!InitHIP(device_id_)) {
|
||||
THROW("Failed to initilize the HIP");
|
||||
}
|
||||
if (p_crop_rect) crop_rect_ = *p_crop_rect;
|
||||
if (p_resize_dim) resize_dim_ = *p_resize_dim;
|
||||
if (b_extract_sei_message_) {
|
||||
fp_sei_ = fopen("rocdec_sei_message.txt", "wb");
|
||||
curr_sei_message_ptr_ = new RocdecSeiMessageInfo;
|
||||
memset(&sei_message_display_q_, 0, sizeof(sei_message_display_q_));
|
||||
}
|
||||
// create rocdec videoparser
|
||||
RocdecParserParams parser_params = {};
|
||||
parser_params.CodecType = codec_id_;
|
||||
parser_params.ulMaxNumDecodeSurfaces = 1;
|
||||
parser_params.ulClockRate = clk_rate;
|
||||
parser_params.ulMaxDisplayDelay = b_low_latency ? 0 : 1;
|
||||
parser_params.pUserData = this;
|
||||
parser_params.pfnSequenceCallback = HandleVideoSequenceProc;
|
||||
parser_params.pfnDecodePicture = HandlePictureDecodeProc;
|
||||
parser_params.pfnDisplayPicture = b_force_zero_latency_ ? NULL : HandlePictureDisplayProc;
|
||||
parser_params.pfnGetSEIMsg = b_extract_sei_message_ ? HandleSEIMessagesProc : NULL;
|
||||
ROCDEC_API_CALL(rocDecCreateVideoParser(&rocdec_parser_, &parser_params));
|
||||
}
|
||||
|
||||
|
||||
RocVideoDecoder::~RocVideoDecoder() {
|
||||
if (curr_sei_message_ptr_) {
|
||||
delete curr_sei_message_ptr_;
|
||||
curr_sei_message_ptr_ = nullptr;
|
||||
}
|
||||
|
||||
if (fp_sei_) {
|
||||
fclose(fp_sei_);
|
||||
fp_sei_ = nullptr;
|
||||
}
|
||||
|
||||
if (rocdec_parser_) {
|
||||
rocDecDestroyVideoParser(rocdec_parser_);
|
||||
rocdec_parser_ = nullptr;
|
||||
}
|
||||
|
||||
if (roc_decoder_) {
|
||||
rocDecDestroyDecoder(roc_decoder_);
|
||||
roc_decoder_ = nullptr;
|
||||
}
|
||||
|
||||
if (hip_stream_) {
|
||||
hipError_t hip_status = hipSuccess;
|
||||
hip_status = hipStreamDestroy(hip_stream_);
|
||||
if (hip_status != hipSuccess) {
|
||||
std::cout << "ERROR: hipStream_Destroy failed! (" << hip_status << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char * GetVideoCodecString(rocDecVideoCodec eCodec) {
|
||||
static struct {
|
||||
rocDecVideoCodec eCodec;
|
||||
const char *name;
|
||||
} aCodecName [] = {
|
||||
{ rocDecVideoCodec_MPEG1, "MPEG-1" },
|
||||
{ rocDecVideoCodec_MPEG2, "MPEG-2" },
|
||||
{ rocDecVideoCodec_MPEG4, "MPEG-4 (ASP)" },
|
||||
{ rocDecVideoCodec_H264, "AVC/H.264" },
|
||||
{ rocDecVideoCodec_JPEG, "M-JPEG" },
|
||||
{ rocDecVideoCodec_HEVC, "H.265/HEVC" },
|
||||
{ rocDecVideoCodec_VP8, "VP8" },
|
||||
{ rocDecVideoCodec_VP9, "VP9" },
|
||||
{ rocDecVideoCodec_AV1, "AV1" },
|
||||
{ rocDecVideoCodec_NumCodecs, "Invalid" },
|
||||
};
|
||||
|
||||
if (eCodec >= 0 && eCodec <= rocDecVideoCodec_NumCodecs) {
|
||||
return aCodecName[eCodec].name;
|
||||
}
|
||||
for (int i = rocDecVideoCodec_NumCodecs + 1; i < sizeof(aCodecName) / sizeof(aCodecName[0]); i++) {
|
||||
if (eCodec == aCodecName[i].eCodec) {
|
||||
return aCodecName[eCodec].name;
|
||||
}
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief function to return the name from codec_id
|
||||
*
|
||||
* @param codec_id
|
||||
* @return const char*
|
||||
*/
|
||||
const char *RocVideoDecoder::GetCodecFmtName(rocDecVideoCodec codec_id)
|
||||
{
|
||||
return GetVideoCodecString(codec_id);
|
||||
}
|
||||
|
||||
static const char * GetVideoChromaFormatName(rocDecVideoChromaFormat e_chroma_format) {
|
||||
static struct {
|
||||
rocDecVideoChromaFormat chroma_fmt;
|
||||
const char *name;
|
||||
} ChromaFormatName[] = {
|
||||
{ rocDecVideoChromaFormat_Monochrome, "YUV 400 (Monochrome)" },
|
||||
{ rocDecVideoChromaFormat_420, "YUV 420" },
|
||||
{ rocDecVideoChromaFormat_422, "YUV 422" },
|
||||
{ rocDecVideoChromaFormat_444, "YUV 444" },
|
||||
};
|
||||
|
||||
if (e_chroma_format >= 0 && e_chroma_format <= rocDecVideoChromaFormat_444) {
|
||||
return ChromaFormatName[e_chroma_format].name;
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static float GetChromaHeightFactor(rocDecVideoSurfaceFormat surface_format) {
|
||||
float factor = 0.5;
|
||||
switch (surface_format) {
|
||||
case rocDecVideoSurfaceFormat_NV12:
|
||||
case rocDecVideoSurfaceFormat_P016:
|
||||
factor = 0.5;
|
||||
break;
|
||||
case rocDecVideoSurfaceFormat_YUV444:
|
||||
case rocDecVideoSurfaceFormat_YUV444_16Bit:
|
||||
factor = 1.0;
|
||||
break;
|
||||
}
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
static int GetChromaPlaneCount(rocDecVideoSurfaceFormat surface_format) {
|
||||
int num_planes = 1;
|
||||
switch (surface_format) {
|
||||
case rocDecVideoSurfaceFormat_NV12:
|
||||
case rocDecVideoSurfaceFormat_P016:
|
||||
num_planes = 1;
|
||||
break;
|
||||
case rocDecVideoSurfaceFormat_YUV444:
|
||||
case rocDecVideoSurfaceFormat_YUV444_16Bit:
|
||||
num_planes = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
return num_planes;
|
||||
}
|
||||
|
||||
|
||||
/* Return value from HandleVideoSequence() are interpreted as :
|
||||
* 0: fail, 1: succeeded, > 1: override dpb size of parser (set by CUVIDPARSERPARAMS::ulMaxNumDecodeSurfaces while creating parser)
|
||||
*/
|
||||
int RocVideoDecoder::HandleVideoSequence(RocdecVideoFormat *pVideoFormat) {
|
||||
//START_TIMER
|
||||
input_video_info_str_.str("");
|
||||
input_video_info_str_.clear();
|
||||
input_video_info_str_ << "Input Video Information" << std::endl
|
||||
<< "\tCodec : " << GetCodecFmtName(pVideoFormat->codec) << std::endl
|
||||
<< "\tFrame rate : " << pVideoFormat->frame_rate.numerator << "/" << pVideoFormat->frame_rate.denominator
|
||||
<< " = " << 1.0 * pVideoFormat->frame_rate.numerator / pVideoFormat->frame_rate.denominator << " fps" << std::endl
|
||||
<< "\tSequence : " << (pVideoFormat->progressive_sequence ? "Progressive" : "Interlaced") << std::endl
|
||||
<< "\tCoded size : [" << pVideoFormat->coded_width << ", " << pVideoFormat->coded_height << "]" << std::endl
|
||||
<< "\tDisplay area : [" << pVideoFormat->display_area.left << ", " << pVideoFormat->display_area.top << ", "
|
||||
<< pVideoFormat->display_area.right << ", " << pVideoFormat->display_area.bottom << "]" << std::endl
|
||||
<< "\tChroma : " << GetVideoChromaFormatName(pVideoFormat->chroma_format) << std::endl
|
||||
<< "\tBit depth : " << pVideoFormat->bit_depth_luma_minus8 + 8
|
||||
;
|
||||
input_video_info_str_ << std::endl;
|
||||
|
||||
int nDecodeSurface = pVideoFormat->min_num_decode_surfaces;
|
||||
|
||||
RocdecDecodeCaps decode_caps;
|
||||
memset(&decode_caps, 0, sizeof(decode_caps));
|
||||
decode_caps.eCodecType = pVideoFormat->codec;
|
||||
decode_caps.eChromaFormat = pVideoFormat->chroma_format;
|
||||
decode_caps.nBitDepthMinus8 = pVideoFormat->bit_depth_luma_minus8;
|
||||
|
||||
ROCDEC_API_CALL(rocDecGetDecoderCaps(&decode_caps));
|
||||
|
||||
if(!decode_caps.bIsSupported){
|
||||
THROW("Rocdec:: Codec not supported on this GPU: " + TOSTR(ROCDEC_NOT_SUPPORTED));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((pVideoFormat->coded_width > decode_caps.nMaxWidth) ||
|
||||
(pVideoFormat->coded_height > decode_caps.nMaxHeight)){
|
||||
|
||||
std::ostringstream errorString;
|
||||
errorString << std::endl
|
||||
<< "Resolution : " << pVideoFormat->coded_width << "x" << pVideoFormat->coded_height << std::endl
|
||||
<< "Max Supported (wxh) : " << decode_caps.nMaxWidth << "x" << decode_caps.nMaxHeight << std::endl
|
||||
<< "Resolution not supported on this GPU ";
|
||||
|
||||
const std::string cErr = errorString.str();
|
||||
THROW(cErr+ TOSTR(ROCDEC_NOT_SUPPORTED));
|
||||
return nDecodeSurface;
|
||||
}
|
||||
|
||||
if (width_ && height_ && chroma_height_) {
|
||||
|
||||
// rocdecCreateDecoder() has been called before, and now there's possible config change
|
||||
// todo:: support reconfigure
|
||||
//return ReconfigureDecoder(pVideoFormat);
|
||||
}
|
||||
|
||||
// eCodec has been set in the constructor (for parser). Here it's set again for potential correction
|
||||
codec_id_ = pVideoFormat->codec;
|
||||
video_chroma_format_ = pVideoFormat->chroma_format;
|
||||
bitdepth_minus_8_ = pVideoFormat->bit_depth_luma_minus8;
|
||||
byte_per_pixel_ = bitdepth_minus_8_ > 0 ? 2 : 1;
|
||||
|
||||
// Set the output surface format same as chroma format
|
||||
if (video_chroma_format_ == rocDecVideoChromaFormat_420 || rocDecVideoChromaFormat_Monochrome)
|
||||
video_surface_format_ = pVideoFormat->bit_depth_luma_minus8 ? rocDecVideoSurfaceFormat_P016 : rocDecVideoSurfaceFormat_NV12;
|
||||
else if (video_chroma_format_ == rocDecVideoChromaFormat_444)
|
||||
video_surface_format_ = pVideoFormat->bit_depth_luma_minus8 ? rocDecVideoSurfaceFormat_YUV444_16Bit : rocDecVideoSurfaceFormat_YUV444;
|
||||
else if (video_chroma_format_ == rocDecVideoChromaFormat_422)
|
||||
video_surface_format_ = rocDecVideoSurfaceFormat_NV12; // 422 output surface is not supported:: default to NV12
|
||||
|
||||
// Check if output format supported. If not, check falback options
|
||||
if (!(decode_caps.nOutputFormatMask & (1 << video_surface_format_))){
|
||||
if (decode_caps.nOutputFormatMask & (1 << rocDecVideoSurfaceFormat_NV12))
|
||||
video_surface_format_ = rocDecVideoSurfaceFormat_NV12;
|
||||
else if (decode_caps.nOutputFormatMask & (1 << rocDecVideoSurfaceFormat_P016))
|
||||
video_surface_format_ = rocDecVideoSurfaceFormat_P016;
|
||||
else if (decode_caps.nOutputFormatMask & (1 << rocDecVideoSurfaceFormat_YUV444))
|
||||
video_surface_format_ = rocDecVideoSurfaceFormat_YUV444;
|
||||
else if (decode_caps.nOutputFormatMask & (1 << rocDecVideoSurfaceFormat_YUV444_16Bit))
|
||||
video_surface_format_ = rocDecVideoSurfaceFormat_YUV444_16Bit;
|
||||
else
|
||||
THROW("No supported output format found" + TOSTR(ROCDEC_NOT_SUPPORTED));
|
||||
}
|
||||
video_format_ = *pVideoFormat;
|
||||
|
||||
RocdecDecoderCreateInfo videoDecodeCreateInfo = { 0 };
|
||||
videoDecodeCreateInfo.CodecType = pVideoFormat->codec;
|
||||
videoDecodeCreateInfo.ChromaFormat = pVideoFormat->chroma_format;
|
||||
videoDecodeCreateInfo.OutputFormat = video_surface_format_;
|
||||
videoDecodeCreateInfo.bitDepthMinus8 = pVideoFormat->bit_depth_luma_minus8;
|
||||
videoDecodeCreateInfo.ulNumOutputSurfaces = 2;
|
||||
videoDecodeCreateInfo.ulNumDecodeSurfaces = nDecodeSurface;
|
||||
videoDecodeCreateInfo.ulWidth = pVideoFormat->coded_width;
|
||||
videoDecodeCreateInfo.ulHeight = pVideoFormat->coded_height;
|
||||
// AV1 has max width/height of sequence in sequence header
|
||||
if (pVideoFormat->codec == rocDecVideoCodec_AV1 && pVideoFormat->seqhdr_data_length > 0) {
|
||||
// dont overwrite if it is already set from cmdline or reconfig.txt
|
||||
if (!(max_width_ > pVideoFormat->coded_width || max_height_ > pVideoFormat->coded_height))
|
||||
{
|
||||
RocdecVideoFormatEx *vidFormatEx = (RocdecVideoFormatEx *)pVideoFormat;
|
||||
max_width_ = vidFormatEx->max_width;
|
||||
max_height_ = vidFormatEx->max_height;
|
||||
}
|
||||
}
|
||||
if (max_width_ < (int)pVideoFormat->coded_width)
|
||||
max_width_ = pVideoFormat->coded_width;
|
||||
if (max_height_ < (int)pVideoFormat->coded_height)
|
||||
max_height_ = pVideoFormat->coded_height;
|
||||
videoDecodeCreateInfo.ulMaxWidth = max_width_;
|
||||
videoDecodeCreateInfo.ulMaxHeight = max_height_;
|
||||
|
||||
if (!(crop_rect_.r && crop_rect_.b) && !(resize_dim_.w && resize_dim_.h)) {
|
||||
width_ = pVideoFormat->display_area.right - pVideoFormat->display_area.left;
|
||||
height_ = pVideoFormat->display_area.bottom - pVideoFormat->display_area.top;
|
||||
videoDecodeCreateInfo.ulTargetWidth = pVideoFormat->coded_width;
|
||||
videoDecodeCreateInfo.ulTargetHeight = pVideoFormat->coded_height;
|
||||
} else {
|
||||
if (resize_dim_.w && resize_dim_.h) {
|
||||
videoDecodeCreateInfo.display_area.left = pVideoFormat->display_area.left;
|
||||
videoDecodeCreateInfo.display_area.top = pVideoFormat->display_area.top;
|
||||
videoDecodeCreateInfo.display_area.right = pVideoFormat->display_area.right;
|
||||
videoDecodeCreateInfo.display_area.bottom = pVideoFormat->display_area.bottom;
|
||||
width_ = resize_dim_.w;
|
||||
height_ = resize_dim_.h;
|
||||
}
|
||||
|
||||
if (crop_rect_.r && crop_rect_.b) {
|
||||
videoDecodeCreateInfo.display_area.left = crop_rect_.l;
|
||||
videoDecodeCreateInfo.display_area.top = crop_rect_.t;
|
||||
videoDecodeCreateInfo.display_area.right = crop_rect_.r;
|
||||
videoDecodeCreateInfo.display_area.bottom = crop_rect_.b;
|
||||
width_ = crop_rect_.r - crop_rect_.l;
|
||||
height_ = crop_rect_.b - crop_rect_.t;
|
||||
}
|
||||
videoDecodeCreateInfo.ulTargetWidth = width_;
|
||||
videoDecodeCreateInfo.ulTargetHeight = height_;
|
||||
}
|
||||
|
||||
chroma_height_ = (int)(ceil(height_ * GetChromaHeightFactor(video_surface_format_)));
|
||||
num_chroma_planes_ = GetChromaPlaneCount(video_surface_format_);
|
||||
surface_height_ = videoDecodeCreateInfo.ulTargetHeight;
|
||||
surface_width_ = videoDecodeCreateInfo.ulTargetWidth;
|
||||
surface_stride_ = align(surface_width_, 256) * byte_per_pixel_; // 256 alignment is enforced for internal VCN surface, keeping the same for ease of memcpy
|
||||
// fill output_surface_info_
|
||||
output_surface_info_.output_width = surface_width_;
|
||||
output_surface_info_.output_height = surface_height_;
|
||||
output_surface_info_.output_pitch = surface_stride_;
|
||||
output_surface_info_.bit_depth = bitdepth_minus_8_ + 8;
|
||||
output_surface_info_.bytes_per_pixel = byte_per_pixel_;
|
||||
output_surface_info_.surface_format = video_surface_format_;
|
||||
output_surface_info_.num_chroma_planes = num_chroma_planes_;
|
||||
|
||||
disp_rect_.b = videoDecodeCreateInfo.display_area.bottom;
|
||||
disp_rect_.t = videoDecodeCreateInfo.display_area.top;
|
||||
disp_rect_.l = videoDecodeCreateInfo.display_area.left;
|
||||
disp_rect_.r = videoDecodeCreateInfo.display_area.right;
|
||||
|
||||
input_video_info_str_ << "Video Decoding Params:" << std::endl
|
||||
<< "\tNum Surfaces : " << videoDecodeCreateInfo.ulNumDecodeSurfaces << std::endl
|
||||
<< "\tCrop : [" << videoDecodeCreateInfo.display_area.left << ", " << videoDecodeCreateInfo.display_area.top << ", "
|
||||
<< videoDecodeCreateInfo.display_area.right << ", " << videoDecodeCreateInfo.display_area.bottom << "]" << std::endl
|
||||
<< "\tResize : " << videoDecodeCreateInfo.ulTargetWidth << "x" << videoDecodeCreateInfo.ulTargetHeight << std::endl
|
||||
;
|
||||
input_video_info_str_ << std::endl;
|
||||
|
||||
ROCDEC_API_CALL(rocDecCreateDecoder(&roc_decoder_, &videoDecodeCreateInfo));
|
||||
return nDecodeSurface;
|
||||
}
|
||||
|
||||
|
||||
int RocVideoDecoder::ReconfigureDecoder(RocdecVideoFormat *pVideoFormat) {
|
||||
THROW("ReconfigureDecoder is not supported in this version: " + TOSTR(ROCDEC_NOT_SUPPORTED));
|
||||
return ROCDEC_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param pPicParams
|
||||
* @return int 1: success 0: fail
|
||||
*/
|
||||
int RocVideoDecoder::HandlePictureDecode(RocdecPicParams *pPicParams) {
|
||||
if (!roc_decoder_)
|
||||
{
|
||||
THROW("Decoder not initialized: failed with ErrCode: " + TOSTR(ROCDEC_NOT_INITIALIZED));
|
||||
return false;
|
||||
}
|
||||
pic_num_in_dec_order_[pPicParams->CurrPicIdx] = decode_poc_++;
|
||||
ROCDEC_API_CALL(rocDecDecodeFrame(roc_decoder_, pPicParams));
|
||||
if (b_force_zero_latency_ && ((!pPicParams->field_pic_flag) || (pPicParams->second_field)))
|
||||
{
|
||||
RocdecParserDispInfo disp_info;
|
||||
memset(&disp_info, 0, sizeof(disp_info));
|
||||
disp_info.picture_index = pPicParams->CurrPicIdx;
|
||||
disp_info.progressive_frame = !pPicParams->field_pic_flag;
|
||||
disp_info.top_field_first = pPicParams->bottom_field_flag ^ 1;
|
||||
HandlePictureDisplay(&disp_info);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief function to handle display picture
|
||||
*
|
||||
* @param pDispInfo
|
||||
* @return int 0:fail 1: success
|
||||
*/
|
||||
int RocVideoDecoder::HandlePictureDisplay(RocdecParserDispInfo *pDispInfo) {
|
||||
RocdecProcParams video_proc_params = {};
|
||||
video_proc_params.progressive_frame = pDispInfo->progressive_frame;
|
||||
video_proc_params.top_field_first = pDispInfo->top_field_first;
|
||||
video_proc_params.output_hipstream = hip_stream_;
|
||||
|
||||
if (b_extract_sei_message_) {
|
||||
if (sei_message_display_q_[pDispInfo->picture_index].pSEIData) {
|
||||
// Write SEI Message
|
||||
uint8_t *sei_buffer = (uint8_t *)(sei_message_display_q_[pDispInfo->picture_index].pSEIData);
|
||||
uint32_t sei_num_messages = sei_message_display_q_[pDispInfo->picture_index].sei_message_count;
|
||||
RocdecSeiMessage *sei_message = sei_message_display_q_[pDispInfo->picture_index].pSEIMessage;
|
||||
if (fp_sei_) {
|
||||
for (uint32_t i = 0; i < sei_num_messages; i++) {
|
||||
if (codec_id_ == rocDecVideoCodec_H264 || rocDecVideoCodec_HEVC) {
|
||||
switch (sei_message[i].sei_message_type) {
|
||||
case SEI_TYPE_TIME_CODE:
|
||||
{
|
||||
//todo:: check if we need to write timecode
|
||||
}
|
||||
break;
|
||||
case SEI_TYPE_USER_DATA_UNREGISTERED:
|
||||
{
|
||||
fwrite(sei_buffer, sei_message[i].sei_message_size, 1, fp_sei_);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (codec_id_ == rocDecVideoCodec_AV1) {
|
||||
fwrite(sei_buffer, sei_message[i].sei_message_size, 1, fp_sei_);
|
||||
}
|
||||
sei_buffer += sei_message[i].sei_message_size;
|
||||
}
|
||||
}
|
||||
free(sei_message_display_q_[pDispInfo->picture_index].pSEIData);
|
||||
free(sei_message_display_q_[pDispInfo->picture_index].pSEIMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void * src_dev_ptr[3] = { 0 };
|
||||
uint32_t src_pitch[3] = { 0 };
|
||||
ROCDEC_API_CALL(rocDecMapVideoFrame(roc_decoder_, pDispInfo->picture_index, src_dev_ptr, src_pitch, &video_proc_params));
|
||||
|
||||
RocdecDecodeStatus dec_status;
|
||||
memset(&dec_status, 0, sizeof(dec_status));
|
||||
rocDecStatus result = rocDecGetDecodeStatus(roc_decoder_, pDispInfo->picture_index, &dec_status);
|
||||
if (result == ROCDEC_SUCCESS && (dec_status.decodeStatus == rocDecodeStatus_Error || dec_status.decodeStatus == rocDecodeStatus_Error_Concealed)) {
|
||||
std::cerr << "Decode Error occurred for picture: " << pic_num_in_dec_order_[pDispInfo->picture_index] << std::endl;
|
||||
}
|
||||
// copy the decoded surface info device or host
|
||||
uint8_t *p_dec_frame = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx_vp_frame_);
|
||||
if ((unsigned)++decoded_frame_cnt_ > vp_frames_.size()) {
|
||||
// Not enough frames in stock
|
||||
num_alloced_frames_++;
|
||||
DecFrameBuffer dec_frame = { 0 };
|
||||
if (b_use_device_mem_) {
|
||||
// allocate based on piched or not
|
||||
if (b_device_frame_pitched_)
|
||||
HIP_API_CALL(hipMalloc((void **)&dec_frame.frame_ptr, GetFrameSizePitched()));
|
||||
else
|
||||
HIP_API_CALL(hipMalloc((void **)&dec_frame.frame_ptr, GetFrameSize()));
|
||||
}
|
||||
else{
|
||||
dec_frame.frame_ptr = new uint8_t[GetFrameSize()];
|
||||
}
|
||||
dec_frame.pts = pDispInfo->pts;
|
||||
vp_frames_.push_back(dec_frame);
|
||||
}
|
||||
p_dec_frame = vp_frames_[decoded_frame_cnt_ - 1].frame_ptr;
|
||||
}
|
||||
|
||||
// Copy luma data
|
||||
int dst_pitch = b_device_frame_pitched_? surface_stride_ : width_*byte_per_pixel_;
|
||||
if (b_use_device_mem_) {
|
||||
if (src_pitch[0] == dst_pitch) {
|
||||
int luma_size = src_pitch[0] * height_;
|
||||
HIP_API_CALL(hipMemcpyDtoDAsync(p_dec_frame, src_dev_ptr[0], luma_size, hip_stream_));
|
||||
}else {
|
||||
// use 2d copy to copy an ROI
|
||||
HIP_API_CALL(hipMemcpy2DAsync(p_dec_frame, dst_pitch, src_dev_ptr[0], src_pitch[0], width_*byte_per_pixel_, height_, hipMemcpyDeviceToDevice, hip_stream_));
|
||||
}
|
||||
}
|
||||
else
|
||||
HIP_API_CALL(hipMemcpy2DAsync(p_dec_frame, width_*byte_per_pixel_, src_dev_ptr[0], src_pitch[0], width_*byte_per_pixel_, height_, hipMemcpyDeviceToHost, hip_stream_));
|
||||
|
||||
// Copy chroma plane ( )
|
||||
// rocDec output gives pointer to luma and chroma pointers seperated for the decoded frame
|
||||
uint8_t *p_frame_uv = p_dec_frame + dst_pitch * height_;
|
||||
if (b_use_device_mem_) {
|
||||
if (src_pitch[1] == dst_pitch) {
|
||||
int chroma_size = chroma_height_ * dst_pitch;
|
||||
HIP_API_CALL(hipMemcpyDtoDAsync(p_frame_uv, src_dev_ptr[1], chroma_size, hip_stream_));
|
||||
}else {
|
||||
// use 2d copy to copy an ROI
|
||||
HIP_API_CALL(hipMemcpy2DAsync(p_frame_uv, dst_pitch, src_dev_ptr[1], src_pitch[1], width_*byte_per_pixel_, chroma_height_, hipMemcpyDeviceToDevice, hip_stream_));
|
||||
}
|
||||
}else
|
||||
HIP_API_CALL(hipMemcpy2DAsync(p_frame_uv, dst_pitch, src_dev_ptr[1], src_pitch[1], width_*byte_per_pixel_, chroma_height_, hipMemcpyDeviceToHost, hip_stream_));
|
||||
|
||||
if (num_chroma_planes_ == 2) {
|
||||
uint8_t *p_frame_uv = p_dec_frame + dst_pitch * height_*2;
|
||||
if (b_use_device_mem_) {
|
||||
if (src_pitch[2] == dst_pitch) {
|
||||
int chroma_size = chroma_height_ * dst_pitch;
|
||||
HIP_API_CALL(hipMemcpyDtoDAsync(p_frame_uv, src_dev_ptr[2], chroma_size, hip_stream_));
|
||||
}else {
|
||||
// use 2d copy to copy an ROI
|
||||
HIP_API_CALL(hipMemcpy2DAsync(p_frame_uv, dst_pitch, src_dev_ptr[2], src_pitch[2], width_*byte_per_pixel_, chroma_height_, hipMemcpyDeviceToDevice, hip_stream_));
|
||||
}
|
||||
}else
|
||||
HIP_API_CALL(hipMemcpy2DAsync(p_frame_uv, dst_pitch, src_dev_ptr[2], src_pitch[2], width_*byte_per_pixel_, chroma_height_, hipMemcpyDeviceToHost, hip_stream_));
|
||||
}
|
||||
|
||||
HIP_API_CALL(hipStreamSynchronize(hip_stream_));
|
||||
ROCDEC_API_CALL(rocDecUnMapVideoFrame(roc_decoder_, src_dev_ptr[0]));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int RocVideoDecoder::GetSEIMessage(RocdecSeiMessageInfo *pSEIMessageInfo) {
|
||||
uint32_t sei_num_mesages = pSEIMessageInfo->sei_message_count;
|
||||
RocdecSeiMessage *p_sei_msg_info = pSEIMessageInfo->pSEIMessage;
|
||||
size_t total_SEI_buff_size = 0;
|
||||
if ((pSEIMessageInfo->picIdx < 0) || (pSEIMessageInfo->picIdx >= MAX_FRAME_NUM)) {
|
||||
ERR("Invalid picture index for SEI message: " + TOSTR(pSEIMessageInfo->picIdx));
|
||||
return 0;
|
||||
}
|
||||
for (uint32_t i = 0; i < sei_num_mesages; i++) {
|
||||
total_SEI_buff_size += p_sei_msg_info[i].sei_message_size;
|
||||
}
|
||||
if (!curr_sei_message_ptr_) {
|
||||
ERR("Out of Memory, Allocation failed for m_pCurrSEIMessage");
|
||||
return 0;
|
||||
}
|
||||
curr_sei_message_ptr_->pSEIData = malloc(total_SEI_buff_size);
|
||||
if (!curr_sei_message_ptr_->pSEIData) {
|
||||
ERR("Out of Memory, Allocation failed for SEI Buffer");
|
||||
return 0;
|
||||
}
|
||||
memcpy(curr_sei_message_ptr_->pSEIData, pSEIMessageInfo->pSEIData, total_SEI_buff_size);
|
||||
curr_sei_message_ptr_->pSEIMessage = (RocdecSeiMessage *)malloc(sizeof(RocdecSeiMessage) * sei_num_mesages);
|
||||
if (!curr_sei_message_ptr_->pSEIMessage) {
|
||||
free(curr_sei_message_ptr_->pSEIData);
|
||||
curr_sei_message_ptr_->pSEIData = NULL;
|
||||
return 0;
|
||||
}
|
||||
memcpy(curr_sei_message_ptr_->pSEIMessage, pSEIMessageInfo->pSEIMessage, sizeof(RocdecSeiMessage) * sei_num_mesages);
|
||||
curr_sei_message_ptr_->sei_message_count = pSEIMessageInfo->sei_message_count;
|
||||
sei_message_display_q_[pSEIMessageInfo->picIdx] = *curr_sei_message_ptr_;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int RocVideoDecoder::DecodeFrame(const uint8_t *data, size_t size, int pkt_flags, int64_t pts) {
|
||||
int decoded_frame_cnt_ = 0, decoded_frame_cnt_ret_ = 0;
|
||||
RocdecSourceDataPacket packet = { 0 };
|
||||
packet.payload = data;
|
||||
packet.payload_size = size;
|
||||
packet.flags = pkt_flags | ROCDEC_PKT_TIMESTAMP;
|
||||
packet.pts = pts;
|
||||
if (!data || size == 0) {
|
||||
packet.flags |= ROCDEC_PKT_ENDOFSTREAM;
|
||||
}
|
||||
ROCDEC_API_CALL(rocDecParseVideoData(rocdec_parser_, &packet));
|
||||
|
||||
return decoded_frame_cnt_;
|
||||
}
|
||||
|
||||
uint8_t* RocVideoDecoder::GetFrame(int64_t *pts) {
|
||||
if (decoded_frame_cnt_ > 0) {
|
||||
std::lock_guard<std::mutex> lock(mtx_vp_frame_);
|
||||
decoded_frame_cnt_--;
|
||||
if (pts) *pts = vp_frames_[decoded_frame_cnt_ret_].pts;
|
||||
return vp_frames_[decoded_frame_cnt_ret_++].frame_ptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if 0 // may be needed for future
|
||||
|
||||
void RocVideoDecoder::SaveImage(std::string output_file_name, void *dev_mem, OutputImageInfo *image_info, bool is_output_RGB) {
|
||||
uint8_t *hst_ptr = nullptr;
|
||||
uint64_t output_image_size = image_info->output_image_size_in_bytes;
|
||||
if (hst_ptr == nullptr) {
|
||||
hst_ptr = new uint8_t [output_image_size];
|
||||
}
|
||||
hipError_t hip_status = hipSuccess;
|
||||
hip_status = hipMemcpyDtoH((void *)hst_ptr, dev_mem, output_image_size);
|
||||
if (hip_status != hipSuccess) {
|
||||
std::cout << "ERROR: hipMemcpyDtoH failed! (" << hip_status << ")" << std::endl;
|
||||
delete [] hst_ptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// no RGB dump if the surface type is YUV400
|
||||
if (image_info->chroma_format == ROCDEC_FMT_YUV400 && is_output_RGB) {
|
||||
return;
|
||||
}
|
||||
uint8_t *tmp_hst_ptr = hst_ptr;
|
||||
if (fp_out_ == nullptr) {
|
||||
fp_out_ = fopen(output_file_name.c_str(), "wb");
|
||||
}
|
||||
if (fp_out_) {
|
||||
int img_width = image_info->output_width;
|
||||
int img_height = image_info->output_height;
|
||||
int output_image_stride = image_info->output_h_stride;
|
||||
if (img_width * image_info->bytes_per_pixel == output_image_stride && img_height == image_info->output_v_stride) {
|
||||
fwrite(hst_ptr, 1, output_image_size, fp_out_);
|
||||
} else {
|
||||
uint32_t width = is_output_RGB ? image_info->output_width * 3 : image_info->output_width;
|
||||
if (image_info->bit_depth == 8) {
|
||||
for (int i = 0; i < image_info->output_height; i++) {
|
||||
fwrite(tmp_hst_ptr, 1, width, fp_out_);
|
||||
tmp_hst_ptr += output_image_stride;
|
||||
}
|
||||
if (!is_output_RGB) {
|
||||
// dump chroma
|
||||
uint8_t *uv_hst_ptr = hst_ptr + output_image_stride * image_info->output_v_stride;
|
||||
for (int i = 0; i < img_height >> 1; i++) {
|
||||
fwrite(uv_hst_ptr, 1, width, fp_out_);
|
||||
uv_hst_ptr += output_image_stride;
|
||||
}
|
||||
}
|
||||
} else if (image_info->bit_depth > 8 && image_info->bit_depth <= 16 ) {
|
||||
for (int i = 0; i < img_height; i++) {
|
||||
fwrite(tmp_hst_ptr, 1, width * image_info->bytes_per_pixel, fp_out_);
|
||||
tmp_hst_ptr += output_image_stride;
|
||||
}
|
||||
if (!is_output_RGB) {
|
||||
// dump chroma
|
||||
uint8_t *uv_hst_ptr = hst_ptr + output_image_stride * image_info->output_v_stride;
|
||||
for (int i = 0; i < img_height >> 1; i++) {
|
||||
fwrite(uv_hst_ptr, 1, width * image_info->bytes_per_pixel, fp_out_);
|
||||
uv_hst_ptr += output_image_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hst_ptr != nullptr) {
|
||||
delete [] hst_ptr;
|
||||
hst_ptr = nullptr;
|
||||
tmp_hst_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void RocVideoDecoder::GetDeviceinfo(std::string &device_name, std::string &gcn_arch_name, int &pci_bus_id, int &pci_domain_id, int &pci_device_id) {
|
||||
device_name = hip_dev_prop_.name;
|
||||
gcn_arch_name = hip_dev_prop_.gcnArchName;
|
||||
pci_bus_id = hip_dev_prop_.pciBusID;
|
||||
pci_domain_id = hip_dev_prop_.pciDomainID;
|
||||
pci_device_id = hip_dev_prop_.pciDeviceID;
|
||||
}
|
||||
|
||||
|
||||
bool RocVideoDecoder::GetOutputSurfaceInfo(OutputSurfaceInfo **surface_info) {
|
||||
if (!width_ || !height_) {
|
||||
std::cerr << "ERROR: RocVideoDecoderr is not intialized" << std::endl;
|
||||
return false;
|
||||
}
|
||||
*surface_info = &output_surface_info_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RocVideoDecoder::InitHIP(int device_id) {
|
||||
HIP_API_CALL(hipGetDeviceCount(&num_devices_));
|
||||
if (num_devices_ < 1) {
|
||||
std::cerr << "ERROR: didn't find any GPU!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (device_id >= num_devices_) {
|
||||
std::cerr << "ERROR: the requested device_id is not found! " << std::endl;
|
||||
return false;
|
||||
}
|
||||
HIP_API_CALL(hipSetDevice(device_id));
|
||||
HIP_API_CALL(hipGetDeviceProperties(&hip_dev_prop_, device_id));
|
||||
HIP_API_CALL(hipStreamCreate(&hip_stream_));
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2023 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
#include <hip/hip_runtime.h>
|
||||
#include "rocdecode.h"
|
||||
#include "rocparser.h"
|
||||
#include "commons.h"
|
||||
|
||||
#define MAX_FRAME_NUM 16
|
||||
|
||||
typedef enum{
|
||||
SEI_TYPE_TIME_CODE = 136,
|
||||
SEI_TYPE_USER_DATA_UNREGISTERED = 5
|
||||
}SEI_H264_HEVC_PAYLOAD_TYPE;
|
||||
|
||||
|
||||
#define ROCDEC_API_CALL( rocDecAPI ) \
|
||||
do { \
|
||||
rocDecStatus errorCode = rocDecAPI; \
|
||||
if( errorCode != ROCDEC_SUCCESS) { \
|
||||
std::ostringstream errorLog; \
|
||||
errorLog << #rocDecAPI << " returned error " << errorCode; \
|
||||
THROW(errorLog.str() + TOSTR(errorCode)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define HIP_API_CALL( call ) \
|
||||
do { \
|
||||
hipError_t hip_status = call; \
|
||||
if (hip_status != hipSuccess) { \
|
||||
const char *szErrName = NULL; \
|
||||
szErrName = hipGetErrorName(hip_status); \
|
||||
std::ostringstream errorLog; \
|
||||
errorLog << "hip API error " << szErrName ; \
|
||||
THROW(errorLog.str()); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
|
||||
struct Rect {
|
||||
int l, t, r, b;
|
||||
};
|
||||
|
||||
struct Dim {
|
||||
int w, h;
|
||||
};
|
||||
|
||||
static inline int align(int value, int alignment) {
|
||||
return (value + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
typedef struct DecFrameBuffer_ {
|
||||
uint8_t *frame_ptr; /**< device memory pointer for the decoded frame */
|
||||
int64_t pts; // timestamp
|
||||
} DecFrameBuffer;
|
||||
|
||||
|
||||
typedef struct OutputSurfaceInfoType {
|
||||
uint32_t output_width; /**< Output width of decoded surface*/
|
||||
uint32_t output_height; /**< Output height of decoded surface*/
|
||||
uint32_t output_pitch; /**< Output pitch in bytes of luma plane, chroma pitch can be inferred based on chromaFormat*/
|
||||
uint32_t bytes_per_pixel; /**< Output BytesPerPixel of decoded image*/
|
||||
uint32_t bit_depth; /**< Output BitDepth of the image*/
|
||||
uint32_t num_chroma_planes; /**< Output Chroma number of planes*/
|
||||
uint64_t output_surface_size_in_bytes; /**< Output Image Size in Bytes; including both luma and chroma planes*/
|
||||
rocDecVideoSurfaceFormat surface_format; /**< Chroma format of the decoded image*/
|
||||
} OutputSurfaceInfo;
|
||||
|
||||
class RocVideoDecoder {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Roc Video Decoder object
|
||||
*
|
||||
* @param hip_ctx
|
||||
* @param b_use_device_mem
|
||||
* @param codec
|
||||
* @param device_id
|
||||
* @param b_low_latency
|
||||
* @param device_frame_pitched
|
||||
* @param p_crop_rect
|
||||
* @param p_resize_dim
|
||||
* @param extract_user_SEI_Message
|
||||
* @param max_width
|
||||
* @param max_height
|
||||
* @param clk_rate
|
||||
* @param force_zero_latency
|
||||
*/
|
||||
RocVideoDecoder(int device_id, bool b_use_device_mem, rocDecVideoCodec codec, bool b_low_latency, bool device_frame_pitched,
|
||||
const Rect *p_crop_rect, const Dim *p_resize_dim, bool extract_user_SEI_Message, int max_width, int max_height,
|
||||
uint32_t clk_rate, bool force_zero_latency);
|
||||
~RocVideoDecoder();
|
||||
|
||||
/**
|
||||
* @brief Get the output frame width
|
||||
*/
|
||||
uint32_t GetWidth() { assert(width_); return width_;}
|
||||
|
||||
/**
|
||||
* @brief This function is used to get the actual decode width
|
||||
*/
|
||||
int GetDecodeWidth() { assert(width_); return width_; }
|
||||
|
||||
/**
|
||||
* @brief Get the output frame height
|
||||
*/
|
||||
uint32_t GetHeight() { assert(height_); return height_; }
|
||||
|
||||
/**
|
||||
* @brief This function is used to get the current chroma height.
|
||||
*/
|
||||
int GetChromaHeight() { assert(chroma_height_); return chroma_height_; }
|
||||
|
||||
/**
|
||||
* @brief This function is used to get the number of chroma planes.
|
||||
*/
|
||||
int GetNumChromaPlanes() { assert(num_chroma_planes_); return num_chroma_planes_; }
|
||||
|
||||
/**
|
||||
* @brief This function is used to get the current frame size based on pixel format.
|
||||
*/
|
||||
int GetFrameSize() { assert(width_); return width_ * (height_ + (chroma_height_ * num_chroma_planes_)) * byte_per_pixel_; }
|
||||
|
||||
/**
|
||||
* @brief This function is used to get the current frame size based on pitch
|
||||
*/
|
||||
int GetFrameSizePitched() { assert(surface_stride_); return surface_stride_ * (height_ + (chroma_height_ * num_chroma_planes_)); }
|
||||
|
||||
/**
|
||||
* @brief Get the Bit Depth and BytesPerPixel associated with the pixel format
|
||||
*
|
||||
* @return uint32_t
|
||||
*/
|
||||
uint32_t GetBitDepth() { assert(bitdepth_minus_8_); return (bitdepth_minus_8_ + 8); }
|
||||
uint32_t GetBytePerPixel() { assert(byte_per_pixel_); return byte_per_pixel_; }
|
||||
/**
|
||||
* @brief Functions to get the output surface attributes
|
||||
*/
|
||||
size_t GetSurfaceSize() { assert(surface_size_); return surface_size_; }
|
||||
uint32_t GetSurfaceStride() { assert(surface_stride_); return surface_stride_; }
|
||||
//RocDecImageFormat GetSubsampling() { return subsampling_; }
|
||||
int GetSurfaceWidth() { assert(surface_width_); return surface_width_;}
|
||||
int GetSurfaceHeight() { assert(surface_height_); return surface_height_;}
|
||||
/**
|
||||
* @brief Get the name of the output format
|
||||
*
|
||||
* @param codec_id
|
||||
* @return std::string
|
||||
*/
|
||||
const char *GetCodecFmtName(rocDecVideoCodec codec_id);
|
||||
/**
|
||||
* @brief Get the pointer to the Output Image Info
|
||||
*
|
||||
* @param surface_info ptr to output surface info
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool GetOutputSurfaceInfo(OutputSurfaceInfo **surface_info);
|
||||
/**
|
||||
* @brief this function decodes a frame and returns the number of frames avalable for display
|
||||
*
|
||||
* @param data - pointer to the data buffer that is to be decode
|
||||
* @param size - size of the data buffer in bytes
|
||||
* @param pts - presentation timestamp
|
||||
* @param flags - video packet flags
|
||||
* @return int - num of frames to display
|
||||
*/
|
||||
int DecodeFrame(const uint8_t *data, size_t size, int pkt_flags, int64_t pts = 0);
|
||||
/**
|
||||
* @brief This function returns a decoded frame and timestamp. This should be called in a loop fetching all the available frames
|
||||
*
|
||||
*/
|
||||
uint8_t* GetFrame(int64_t *pts);
|
||||
|
||||
/**
|
||||
* @brief utility function to save image to a file
|
||||
*
|
||||
* @param output_file_name - file to write
|
||||
* @param dev_mem - dev_memory pointer of the frame
|
||||
* @param image_info - output image info
|
||||
* @param is_output_RGB - to write in RGB
|
||||
*/
|
||||
//void SaveImage(std::string output_file_name, void* dev_mem, OutputImageInfo* image_info, bool is_output_RGB = 0);
|
||||
|
||||
/**
|
||||
* @brief Get the Device info for the current device
|
||||
*
|
||||
* @param device_name
|
||||
* @param gcn_arch_name
|
||||
* @param pci_bus_id
|
||||
* @param pci_domain_id
|
||||
* @param pci_device_id
|
||||
*/
|
||||
void GetDeviceinfo(std::string &device_name, std::string &gcn_arch_name, int &pci_bus_id, int &pci_domain_id, int &pci_device_id);
|
||||
|
||||
private:
|
||||
int decoder_session_id_; // Decoder session identifier. Used to gather session level stats.
|
||||
/**
|
||||
* @brief Callback function to be registered for getting a callback when decoding of sequence starts
|
||||
*/
|
||||
static int ROCDECAPI HandleVideoSequenceProc(void *pUserData, RocdecVideoFormat *pVideoFormat) { return ((RocVideoDecoder *)pUserData)->HandleVideoSequence(pVideoFormat); }
|
||||
|
||||
/**
|
||||
* @brief Callback function to be registered for getting a callback when a decoded frame is ready to be decoded
|
||||
*/
|
||||
static int ROCDECAPI HandlePictureDecodeProc(void *pUserData, RocdecPicParams *pPicParams) { return ((RocVideoDecoder *)pUserData)->HandlePictureDecode(pPicParams); }
|
||||
|
||||
/**
|
||||
* @brief Callback function to be registered for getting a callback when a decoded frame is available for display
|
||||
*/
|
||||
static int ROCDECAPI HandlePictureDisplayProc(void *pUserData, RocdecParserDispInfo *pDispInfo) { return ((RocVideoDecoder *)pUserData)->HandlePictureDisplay(pDispInfo); }
|
||||
|
||||
/**
|
||||
* @brief Callback function to be registered for getting a callback when all the unregistered user SEI Messages are parsed for a frame.
|
||||
*/
|
||||
static int ROCDECAPI HandleSEIMessagesProc(void *pUserData, RocdecSeiMessageInfo *pSEIMessageInfo) { return ((RocVideoDecoder *)pUserData)->GetSEIMessage(pSEIMessageInfo); }
|
||||
|
||||
/**
|
||||
* @brief This function gets called when a sequence is ready to be decoded. The function also gets called
|
||||
when there is format change
|
||||
*/
|
||||
int HandleVideoSequence(RocdecVideoFormat *pVideoFormat);
|
||||
|
||||
/**
|
||||
* @brief This function gets called when a picture is ready to be decoded. cuvidDecodePicture is called from this function
|
||||
* to decode the picture
|
||||
*/
|
||||
int HandlePictureDecode(RocdecPicParams *pPicParams);
|
||||
|
||||
/**
|
||||
* @brief This function gets called after a picture is decoded and available for display. Frames are fetched and stored in
|
||||
internal buffer
|
||||
*/
|
||||
int HandlePictureDisplay(RocdecParserDispInfo *pDispInfo);
|
||||
/**
|
||||
* @brief This function gets called when all unregistered user SEI messages are parsed for a frame
|
||||
*/
|
||||
int GetSEIMessage(RocdecSeiMessageInfo *pSEIMessageInfo);
|
||||
|
||||
/**
|
||||
* @brief This function reconfigure decoder if there is a change in sequence params.
|
||||
*/
|
||||
int ReconfigureDecoder(RocdecVideoFormat *pVideoFormat);
|
||||
|
||||
/**
|
||||
* @brief Function to Initialize GPU-HIP
|
||||
*
|
||||
*/
|
||||
bool InitHIP(int device_id);
|
||||
int num_devices_;
|
||||
int device_id_;
|
||||
RocdecVideoParser rocdec_parser_ = nullptr;
|
||||
rocDecDecoderHandle roc_decoder_ = nullptr;
|
||||
bool b_use_device_mem_ = true;
|
||||
bool b_extract_sei_message_ = false;
|
||||
bool b_low_latency_ = true;
|
||||
bool b_force_zero_latency_ = true;
|
||||
bool b_device_frame_pitched_ = true;
|
||||
hipDeviceProp_t hip_dev_prop_;
|
||||
hipStream_t hip_stream_;
|
||||
rocDecVideoCodec codec_id_ = rocDecVideoCodec_NumCodecs;
|
||||
rocDecVideoChromaFormat video_chroma_format_ = rocDecVideoChromaFormat_420;
|
||||
rocDecVideoSurfaceFormat video_surface_format_ = rocDecVideoSurfaceFormat_NV12;
|
||||
RocdecVideoFormat video_format_ = {};
|
||||
RocdecSeiMessageInfo *curr_sei_message_ptr_ = nullptr;
|
||||
RocdecSeiMessageInfo sei_message_display_q_[MAX_FRAME_NUM];
|
||||
int decoded_frame_cnt_ = 0, decoded_frame_cnt_ret_ = 0;
|
||||
int decode_poc_ = 0, pic_num_in_dec_order_[MAX_FRAME_NUM];
|
||||
int num_alloced_frames_ = 0;
|
||||
std::ostringstream input_video_info_str_;
|
||||
int bitdepth_minus_8_ = 0;
|
||||
uint32_t byte_per_pixel_ = 1;
|
||||
uint32_t width_;
|
||||
uint32_t height_;
|
||||
int max_width_, max_height_;
|
||||
uint32_t chroma_height_;
|
||||
uint32_t surface_height_;
|
||||
uint32_t surface_width_;
|
||||
uint32_t num_chroma_planes_;
|
||||
uint32_t num_components_;
|
||||
uint32_t surface_stride_;
|
||||
size_t surface_size_;
|
||||
OutputSurfaceInfo output_surface_info_;
|
||||
std::mutex mtx_vp_frame_;
|
||||
std::vector<DecFrameBuffer> vp_frames_; // vector of decoded frames
|
||||
Rect disp_rect_ = {};
|
||||
Rect crop_rect_ = {};
|
||||
Dim resize_dim_ = {};
|
||||
FILE *fp_sei_ = NULL;
|
||||
FILE *fp_out_ = NULL;
|
||||
};
|
||||
Referencia en una nueva incidencia
Block a user