FFMpeg decoder rocdecode integration (#583)
* initial commit * initial implementation for host based decoder * minor change * cmake changes and added new sample * rocdecDecode sample implementation * rocdecode sample changes working * working version of avcodec decoder and sample * Add end of stream handling for repeated decoding with reconfigure * reorg files and added changelog * update readme * revert file * remove unused class members * addressed reviw comment for changelog * fix sample to work on more video files * resolved review comments * bumped version to 0.14.0 * fixed build warnings * addressed review comments * addressed review comments * addressed review comments * fixed readme to match .cpp file options for parameters * updated review comments, readme, and added test data for the sample * fixed bug for saving frame for 10 bit videos * addressed review comments * addressed all the new review comments
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
# ##############################################################################
|
||||
# Copyright (c) 2023 - 2025 Advanced Micro Devices, Inc.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# ##############################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
# ROCM Path
|
||||
if(DEFINED ENV{ROCM_PATH})
|
||||
set(ROCM_PATH $ENV{ROCM_PATH} CACHE PATH "Default ROCm installation path")
|
||||
elseif(ROCM_PATH)
|
||||
message("-- INFO:ROCM_PATH Set -- ${ROCM_PATH}")
|
||||
else()
|
||||
set(ROCM_PATH /opt/rocm CACHE PATH "Default ROCm installation path")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED On)
|
||||
|
||||
# Set AMD Clang as default compiler
|
||||
if (NOT DEFINED CMAKE_CXX_COMPILER)
|
||||
set(CMAKE_C_COMPILER ${ROCM_PATH}/bin/amdclang)
|
||||
set(CMAKE_CXX_COMPILER ${ROCM_PATH}/bin/amdclang++)
|
||||
endif()
|
||||
|
||||
# Set Project Version and Language
|
||||
project(rocdecodehost LANGUAGES CXX)
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../../cmake)
|
||||
list(APPEND CMAKE_PREFIX_PATH ${ROCM_PATH}/lib/cmake)
|
||||
|
||||
set(DEFAULT_BUILD_TYPE "Release")
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "rocdecode-host Default Build Type" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
|
||||
endif()
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
# -O0 -- Don't Optimize output file
|
||||
# -gdwarf-4 -- generate debugging information, dwarf-4 for making valgrind work
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -gdwarf-4 -Wall")
|
||||
else()
|
||||
# -O3 -- Optimize output file
|
||||
# -DNDEBUG -- turn off asserts
|
||||
# -fPIC -- Generate position-independent code if possible
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DNDEBUG -fPIC -Wall")
|
||||
endif()
|
||||
|
||||
message("-- ${BoldBlue}rocdecode-host Build Type -- ${CMAKE_BUILD_TYPE}${ColourReset}")
|
||||
|
||||
find_package(rocprofiler-register QUIET)
|
||||
#find_package(FFmpeg QUIET)
|
||||
find_package(FFmpeg)
|
||||
|
||||
if(HIP_FOUND AND FFMPEG_FOUND AND Threads_FOUND AND rocprofiler-register_FOUND)
|
||||
# HIP
|
||||
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} hip::host)
|
||||
# FFMPEG
|
||||
include_directories(${AVUTIL_INCLUDE_DIR} ${AVCODEC_INCLUDE_DIR} ${AVFORMAT_INCLUDE_DIR})
|
||||
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${FFMPEG_LIBRARIES})
|
||||
|
||||
# rocprofiler
|
||||
if (rocprofiler-register_FOUND)
|
||||
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocprofiler-register::rocprofiler-register)
|
||||
endif()
|
||||
|
||||
# local include files
|
||||
include_directories(api rocdecode-host ../src/rocdecode ../src/parser)
|
||||
# source files
|
||||
file(GLOB_RECURSE SOURCES "./*.cpp")
|
||||
# rocdecode.so
|
||||
add_library(${PROJECT_NAME} SHARED ${SOURCES})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} ${LINK_LIBRARY_LIST})
|
||||
# FFMPEG multi-version support
|
||||
if(_FFMPEG_AVCODEC_VERSION VERSION_LESS_EQUAL 58.134.100)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC USE_AVCODEC_GREATER_THAN_58_134=0)
|
||||
else()
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC USE_AVCODEC_GREATER_THAN_58_134=1)
|
||||
endif()
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
else()
|
||||
message("-- ERROR!: ${PROJECT_NAME} excluded! please install all the dependencies and try again!")
|
||||
if (NOT HIP_FOUND)
|
||||
message(FATAL_ERROR "-- ERROR!: HIP Not Found! - please install ROCm and HIP!")
|
||||
endif()
|
||||
if (NOT FFMPEG_FOUND)
|
||||
message(FATAL_ERROR "-- ERROR!: FFMPEG Not Found! - please install FFMPEG!")
|
||||
endif()
|
||||
if (NOT Threads_FOUND)
|
||||
message(FATAL_ERROR "-- ERROR!: Threads Not Found! - please insatll Threads!")
|
||||
endif()
|
||||
if (NOT rocprofiler-register_FOUND)
|
||||
message(FATAL_ERROR "-- ERROR!: rocprofiler-register Not Found! - please install rocprofiler-register!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# install rocDecode libs -- {ROCM_PATH}/lib
|
||||
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev)
|
||||
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2025 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 "avcodec_videodecoder.h"
|
||||
|
||||
/**
|
||||
* @brief helper function for inferring AVCodecID from rocDecVideoCodec
|
||||
*
|
||||
* @param rocdec_codec
|
||||
* @return AVCodecID
|
||||
*/
|
||||
static inline AVCodecID RocDecVideoCodec2AVCodec(rocDecVideoCodec rocdec_codec) {
|
||||
switch (rocdec_codec) {
|
||||
case rocDecVideoCodec_MPEG1 : return AV_CODEC_ID_MPEG1VIDEO;
|
||||
case rocDecVideoCodec_MPEG2 : return AV_CODEC_ID_MPEG2VIDEO;
|
||||
case rocDecVideoCodec_MPEG4 : return AV_CODEC_ID_MPEG4;
|
||||
case rocDecVideoCodec_AVC : return AV_CODEC_ID_H264;
|
||||
case rocDecVideoCodec_HEVC : return AV_CODEC_ID_HEVC;
|
||||
case rocDecVideoCodec_VP8 : return AV_CODEC_ID_VP8;
|
||||
case rocDecVideoCodec_VP9 : return AV_CODEC_ID_VP9;
|
||||
case rocDecVideoCodec_JPEG : return AV_CODEC_ID_MJPEG;
|
||||
case rocDecVideoCodec_AV1 : return AV_CODEC_ID_AV1;
|
||||
default : return AV_CODEC_ID_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief helper function for inferring AVCodecID from rocDecVideoSurfaceFormat
|
||||
*
|
||||
* @param AVPixelFormat
|
||||
* @return rocDecVideoChromaFormat
|
||||
*/
|
||||
static inline rocDecVideoChromaFormat AVPixelFormat2rocDecVideoChromaFormat(AVPixelFormat av_pixel_format) {
|
||||
switch (av_pixel_format) {
|
||||
case AV_PIX_FMT_YUV420P :
|
||||
case AV_PIX_FMT_YUVJ420P :
|
||||
case AV_PIX_FMT_YUV420P10LE :
|
||||
case AV_PIX_FMT_YUV420P12LE :
|
||||
return rocDecVideoChromaFormat_420;
|
||||
case AV_PIX_FMT_YUV422P :
|
||||
case AV_PIX_FMT_YUVJ422P :
|
||||
return rocDecVideoChromaFormat_422;
|
||||
case AV_PIX_FMT_YUV444P :
|
||||
case AV_PIX_FMT_YUVJ444P :
|
||||
return rocDecVideoChromaFormat_444;
|
||||
default :
|
||||
std::cerr << "ERROR: " << av_get_pix_fmt_name(av_pixel_format) << " pixel_format is not supported!" << std::endl;
|
||||
return rocDecVideoChromaFormat_420; // for sanity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief helper function for inferring AVCodecID from rocDecVideoSurfaceFormat
|
||||
*
|
||||
* @param AVPixelFormat
|
||||
* @return AVCodecID
|
||||
*/
|
||||
static inline int BitDepthFromPixelFormat(AVPixelFormat av_pixel_format) {
|
||||
switch (av_pixel_format) {
|
||||
case AV_PIX_FMT_YUV420P :
|
||||
case AV_PIX_FMT_YUVJ420P :
|
||||
return 8;
|
||||
case AV_PIX_FMT_YUV420P10LE :
|
||||
case AV_PIX_FMT_YUV420P12LE :
|
||||
return 16;
|
||||
case AV_PIX_FMT_YUV422P :
|
||||
case AV_PIX_FMT_YUVJ422P :
|
||||
case AV_PIX_FMT_YUV444P :
|
||||
case AV_PIX_FMT_YUVJ444P :
|
||||
return 16;
|
||||
default :
|
||||
std::cerr << "ERROR: " << av_get_pix_fmt_name(av_pixel_format) << " pixel_format is not supported!" << std::endl;
|
||||
return AV_PIX_FMT_YUV420P; // for sanity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief helper function for inferring AVCodecID from rocDecVideoSurfaceFormat
|
||||
*
|
||||
* @param AVPixelFormat
|
||||
* @return rocDecVideoSurfaceFormat
|
||||
*/
|
||||
static inline rocDecVideoSurfaceFormat AVPixelFormat2rocDecVideoSurfaceFormat(AVPixelFormat av_pixel_format) {
|
||||
switch (av_pixel_format) {
|
||||
case AV_PIX_FMT_YUV420P :
|
||||
case AV_PIX_FMT_YUVJ420P :
|
||||
return rocDecVideoSurfaceFormat_YUV420;
|
||||
case AV_PIX_FMT_YUV444P :
|
||||
case AV_PIX_FMT_YUVJ444P :
|
||||
return rocDecVideoSurfaceFormat_YUV444;
|
||||
case AV_PIX_FMT_YUV420P10LE :
|
||||
case AV_PIX_FMT_YUV420P12LE :
|
||||
return rocDecVideoSurfaceFormat_YUV420_16Bit;
|
||||
default :
|
||||
std::cerr << "ERROR: " << av_get_pix_fmt_name(av_pixel_format) << " pixel_format is not supported!" << std::endl;
|
||||
return rocDecVideoSurfaceFormat_NV12; // for sanity
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
|
||||
AvcodecVideoDecoder::AvcodecVideoDecoder(RocDecoderHostCreateInfo &decoder_create_info) : decoder_create_info_{decoder_create_info} {
|
||||
|
||||
b_multithreading_ = false; // todo:: remove
|
||||
pfn_sequece_cb_ = decoder_create_info_.pfn_sequence_callback;
|
||||
pfn_display_picture_cb_ = decoder_create_info_.pfn_display_picture;
|
||||
pfn_get_sei_message_cb_ = decoder_create_info_.pfn_get_sei_msg;
|
||||
|
||||
// start the avcodec decoding thread for multi-threading
|
||||
if (b_multithreading_) {
|
||||
ffmpeg_decoder_thread_ = new std::thread(&AvcodecVideoDecoder::DecodeThread, this);
|
||||
if (!ffmpeg_decoder_thread_) {
|
||||
THROW("FFMpegVideoDecoder create thread failed");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AvcodecVideoDecoder::~AvcodecVideoDecoder() {
|
||||
// free av_packet_data_
|
||||
while (!av_packet_data_.empty()) {
|
||||
std::pair<uint8_t *, int> *packet_data = &av_packet_data_.back();
|
||||
av_freep(&packet_data->first);
|
||||
av_packet_data_.pop_back();
|
||||
}
|
||||
//release av_packets
|
||||
while (!av_packets_.empty()) {
|
||||
av_packet_free(&av_packets_.back());
|
||||
av_packets_.pop_back();
|
||||
}
|
||||
// free decoder context
|
||||
if (dec_context_) {
|
||||
avcodec_free_context(&dec_context_);
|
||||
dec_context_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief InitializeDecoder()
|
||||
*
|
||||
* @return rocDecStatus
|
||||
*/
|
||||
rocDecStatus AvcodecVideoDecoder::InitializeDecoder() {
|
||||
if (!decoder_) decoder_ = avcodec_find_decoder(RocDecVideoCodec2AVCodec(decoder_create_info_.codec_type));
|
||||
if(!decoder_) {
|
||||
ERR("rocDecode<FFMpeg>:: Codec not supported by FFMpeg ");
|
||||
return ROCDEC_NOT_SUPPORTED;
|
||||
}
|
||||
if (!dec_context_) {
|
||||
dec_context_ = avcodec_alloc_context3(decoder_); //alloc dec_context_
|
||||
if (!dec_context_) {
|
||||
ERR("Could not allocate video codec context");
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
// set codec to automatically determine how many threads suits best for the decoding job
|
||||
dec_context_->thread_count = decoder_create_info_.num_decode_threads;
|
||||
|
||||
if (decoder_->capabilities & AV_CODEC_CAP_FRAME_THREADS)
|
||||
dec_context_->thread_type = FF_THREAD_FRAME;
|
||||
else if (decoder_->capabilities & AV_CODEC_CAP_SLICE_THREADS)
|
||||
dec_context_->thread_type = FF_THREAD_SLICE;
|
||||
else
|
||||
dec_context_->thread_count = 1;
|
||||
|
||||
// open the codec
|
||||
if (avcodec_open2(dec_context_, decoder_, NULL) < 0) {
|
||||
ERR("Could not open codec");
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
// get the output pixel format from dec_context_
|
||||
decoder_pixel_format_ = (dec_context_->pix_fmt == AV_PIX_FMT_NONE) ? AV_PIX_FMT_YUV420P : dec_context_->pix_fmt;
|
||||
}
|
||||
// set log level to
|
||||
av_log_set_level(AV_LOG_QUIET);
|
||||
// allocate av_frame buffer pool for number of surfaces to be in the decoder pool
|
||||
// Note: with multi-threading, av_codec needs (dec_context_->delay + max_num_B_frames) number of av_frames.
|
||||
// max_num_B_frames is assumed to be 4 here
|
||||
if (dec_frames_.empty()) {
|
||||
for (int i = 0; i < (dec_context_->delay + 4); i++) {
|
||||
AVFrame *p_frame = av_frame_alloc();
|
||||
dec_frames_.push_back(p_frame);
|
||||
}
|
||||
av_frame_cnt_ = 0;
|
||||
}
|
||||
// allocate max. packet_q of 4
|
||||
if (av_packet_data_.empty()) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint8_t *pkt_data = static_cast<uint8_t *> (av_malloc(MAX_AV_PACKET_DATA_SIZE));
|
||||
av_packet_data_.push_back(std::make_pair(pkt_data, MAX_AV_PACKET_DATA_SIZE));
|
||||
}
|
||||
}
|
||||
// allocate av_packets_ for decoding
|
||||
if (av_packets_.empty()) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
AVPacket *pkt = av_packet_alloc();
|
||||
pkt->data = static_cast<uint8_t *> (av_packet_data_[i].first);
|
||||
pkt->size = av_packet_data_[i].second;
|
||||
av_packets_.push_back(pkt);
|
||||
}
|
||||
}
|
||||
disp_rect_.left = decoder_create_info_.display_rect.left;
|
||||
disp_rect_.top = decoder_create_info_.display_rect.top;
|
||||
disp_rect_.right = decoder_create_info_.display_rect.right;
|
||||
disp_rect_.bottom = decoder_create_info_.display_rect.bottom;
|
||||
return ROCDEC_SUCCESS;
|
||||
}
|
||||
|
||||
rocDecStatus AvcodecVideoDecoder::SubmitDecode(RocdecPicParamsHost *pPicParams) {
|
||||
decoded_pic_cnt_ = 0;
|
||||
if (end_of_stream_) {
|
||||
avcodec_flush_buffers(dec_context_);
|
||||
av_pkt_cnt_ = 0;
|
||||
end_of_stream_ = false;
|
||||
}
|
||||
AVPacket *av_pkt = av_packets_[av_pkt_cnt_];
|
||||
std::pair<uint8_t *, int> *packet_data = &av_packet_data_[av_pkt_cnt_];
|
||||
if (pPicParams->bitstream_data_len > packet_data->second) {
|
||||
void *new_pkt_data = av_realloc(av_pkt->data, (pPicParams->bitstream_data_len + MAX_AV_PACKET_DATA_SIZE)); // add more to avoid frequence reallocation
|
||||
if (!new_pkt_data) {
|
||||
ERR("ERROR: couldn't allocate packet data");
|
||||
return ROCDEC_OUTOF_MEMORY;
|
||||
}
|
||||
packet_data->first = static_cast<uint8_t *>(new_pkt_data);
|
||||
packet_data->second = (pPicParams->bitstream_data_len + MAX_AV_PACKET_DATA_SIZE);
|
||||
av_pkt->data = packet_data->first;
|
||||
}
|
||||
memcpy(av_pkt->data, pPicParams->bitstream_data, pPicParams->bitstream_data_len);
|
||||
av_pkt->size = pPicParams->bitstream_data_len;
|
||||
av_pkt->flags = 0;
|
||||
av_pkt->pts = pPicParams->pts;
|
||||
|
||||
if (!b_multithreading_) {
|
||||
// flush and reconfigure the decoder when we reached eos
|
||||
DecodeAvFrame(av_pkt, dec_frames_[av_frame_cnt_]);
|
||||
NotifyPictureDisplay();
|
||||
if ((!pPicParams->bitstream_data_len || pPicParams->flags == ROCDEC_PKT_ENDOFPICTURE) && !end_of_stream_) {
|
||||
AVPacket pkt = {0};
|
||||
DecodeAvFrame(&pkt, dec_frames_[av_frame_cnt_]);
|
||||
NotifyPictureDisplay();
|
||||
}
|
||||
} else {
|
||||
//push packet into packet q for decoding
|
||||
PushPacket(av_pkt);
|
||||
if ((!pPicParams->bitstream_data_len || pPicParams->flags == ROCDEC_PKT_ENDOFPICTURE) && !end_of_stream_) {
|
||||
AVPacket pkt = {0};
|
||||
PushPacket(&pkt);
|
||||
}
|
||||
// display frames
|
||||
if (!disp_frames_q_.empty()) {
|
||||
NotifyPictureDisplay();
|
||||
}
|
||||
}
|
||||
av_pkt_cnt_ = (av_pkt_cnt_ + 1) % av_packets_.size();
|
||||
if (!av_pkt->data || !av_pkt->size) {
|
||||
end_of_stream_ = true;
|
||||
}
|
||||
if (pPicParams->flags & ROCDEC_PKT_ENDOFSTREAM) {
|
||||
// flush last packet and let FFMpeg decode last frames
|
||||
NotifyPictureDisplay();
|
||||
}
|
||||
|
||||
return ROCDEC_SUCCESS;
|
||||
}
|
||||
|
||||
rocDecStatus AvcodecVideoDecoder::GetDecodeStatus(int pic_idx, RocdecDecodeStatus *decode_status) {
|
||||
if (p_disp_frame_ && p_disp_frame_->picture_index == pic_idx)
|
||||
return ROCDEC_SUCCESS;
|
||||
else
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
|
||||
rocDecStatus AvcodecVideoDecoder::GetVideoFrame(int pic_idx, void **frame_ptr, uint32_t *line_size, RocdecProcParams *vid_postproc_params){
|
||||
|
||||
if (p_disp_frame_ == nullptr) {
|
||||
ERR("GetVideoFrame: No frame available to display");
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
if (p_disp_frame_->picture_index != pic_idx) {
|
||||
ERR("GetVideoFrame: pic_index is invalid" );
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
auto p_av_frame = p_disp_frame_->av_frame_ptr;
|
||||
frame_ptr[0] = p_av_frame->data[0];
|
||||
frame_ptr[1] = p_av_frame->data[1];
|
||||
frame_ptr[2] = p_av_frame->data[2];
|
||||
line_size[0] = p_av_frame->linesize[0];
|
||||
line_size[1] = p_av_frame->linesize[1];
|
||||
line_size[2] = p_av_frame->linesize[2];
|
||||
|
||||
return ROCDEC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
rocDecStatus AvcodecVideoDecoder::ReconfigureDecoder(RocdecReconfigureDecoderInfo *preconfig_params) {
|
||||
rocDecStatus rocdec_status = ROCDEC_SUCCESS;
|
||||
if (preconfig_params == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
//avcoded can handle reolution changes. So we just need to flush all remaining frames here.
|
||||
bool is_decode_res_changed = !(preconfig_params->width == coded_width_ && preconfig_params->height == coded_height_);
|
||||
if (is_decode_res_changed) {
|
||||
AVPacket pkt = {0};
|
||||
PushPacket(&pkt);
|
||||
NotifyPictureDisplay();
|
||||
}
|
||||
return rocdec_status;
|
||||
}
|
||||
|
||||
void AvcodecVideoDecoder::DecodeThread()
|
||||
{
|
||||
AVPacket *pkt;
|
||||
do {
|
||||
pkt = PopPacket();
|
||||
DecodeAvFrame(pkt, dec_frames_[av_frame_cnt_]);
|
||||
} while (!end_of_stream_);
|
||||
}
|
||||
|
||||
int AvcodecVideoDecoder::DecodeAvFrame(AVPacket *av_pkt, AVFrame *p_frame) {
|
||||
int status;
|
||||
//send packet to av_codec
|
||||
status = avcodec_send_packet(dec_context_, av_pkt);
|
||||
if (status < 0) {
|
||||
ERR("Error sending av packet for decoding: status: ");
|
||||
return status;
|
||||
}
|
||||
while (status >= 0) {
|
||||
status = avcodec_receive_frame(dec_context_, p_frame);
|
||||
if (status == AVERROR(EAGAIN) || status == AVERROR_EOF) {
|
||||
//if (status == AVERROR_EOF) std::cout << "got end of stream from avcodec_receive_frame" << std::endl;
|
||||
end_of_stream_ = (status == AVERROR_EOF);
|
||||
return 0;
|
||||
}
|
||||
else if (status < 0) {
|
||||
ERR("Error during decoding");
|
||||
return 0;
|
||||
}
|
||||
// for the first frame, initialize OutputsurfaceInfo
|
||||
if (p_frame->width != coded_width_ || p_frame->height != coded_height_ || p_frame->format != av_sample_format) {
|
||||
coded_width_ = p_frame->width;
|
||||
coded_height_ = p_frame->height;
|
||||
av_sample_format = p_frame->format;
|
||||
NotifyNewSequence(p_frame);
|
||||
}
|
||||
// push frame into q
|
||||
DecFrameBufferFFMpeg dec_frame = { 0 };
|
||||
dec_frame.av_frame_ptr = p_frame;
|
||||
dec_frame.pts = p_frame->pts;
|
||||
dec_frame.picture_index = av_frame_cnt_; //picture_index is not used here since it is handled within FFMpeg decoder
|
||||
PushDisplayFrame(dec_frame);
|
||||
decoded_pic_cnt_++;
|
||||
|
||||
av_frame_cnt_ = (av_frame_cnt_ + 1) % dec_frames_.size();
|
||||
p_frame = dec_frames_[av_frame_cnt_]; //advance for next frame decode
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
rocDecStatus AvcodecVideoDecoder::NotifyNewSequence(AVFrame *p_frame) {
|
||||
if (!p_frame)
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
video_format_host_.video_surface_format = AVPixelFormat2rocDecVideoSurfaceFormat((AVPixelFormat)p_frame->format);
|
||||
RocdecVideoFormat *p_video_format = &video_format_host_.video_format;
|
||||
p_video_format->codec = decoder_create_info_.codec_type;
|
||||
p_video_format->frame_rate.numerator = dec_context_->framerate.num;
|
||||
p_video_format->frame_rate.denominator = dec_context_->framerate.den;
|
||||
p_video_format->bit_depth_luma_minus8 = BitDepthFromPixelFormat(dec_context_->pix_fmt) - 8;
|
||||
p_video_format->bit_depth_chroma_minus8 = p_video_format->bit_depth_luma_minus8;
|
||||
p_video_format->progressive_sequence = !p_frame->interlaced_frame;
|
||||
p_video_format->min_num_decode_surfaces = dec_context_->delay + dec_context_->max_b_frames;
|
||||
p_video_format->coded_width = p_frame->linesize[0];
|
||||
p_video_format->coded_height = p_frame->height;
|
||||
p_video_format->chroma_format = AVPixelFormat2rocDecVideoChromaFormat(dec_context_->pix_fmt);
|
||||
p_video_format->display_area = { 0, 0, p_frame->width, p_frame->height };
|
||||
p_video_format->bitrate = 0;
|
||||
p_video_format->display_aspect_ratio.x = p_frame->sample_aspect_ratio.num;
|
||||
p_video_format->display_aspect_ratio.y = p_frame->sample_aspect_ratio.den;
|
||||
if (pfn_sequece_cb_ && decoder_create_info_.user_data &&
|
||||
pfn_sequece_cb_(decoder_create_info_.user_data, &video_format_host_) == 0) {
|
||||
ERR("Sequence callback function failed.");
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
} else {
|
||||
return ROCDEC_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
rocDecStatus AvcodecVideoDecoder::SendSeiMsgPayload(AVFrame *p_frame) {
|
||||
#if 0 //todo
|
||||
sei_message_info_params_.sei_message_count = sei_message_count_;
|
||||
sei_message_info_params_.sei_message = sei_message_list_.data();
|
||||
sei_message_info_params_.sei_data = (void*)sei_payload_buf_;
|
||||
sei_message_info_params_.picIdx = curr_pic_info_.dec_buf_idx;
|
||||
|
||||
// callback function with RocdecSeiMessageInfo params filled out
|
||||
if (pfn_get_sei_message_cb_) pfn_get_sei_message_cb_(parser_params_.user_data, &sei_message_info_params_);
|
||||
#endif
|
||||
return ROCDEC_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
rocDecStatus AvcodecVideoDecoder::NotifyPictureDisplay() {
|
||||
int num_frames_to_display = decoded_pic_cnt_;
|
||||
while (num_frames_to_display) {
|
||||
p_disp_frame_ = GetDisplayFrame();
|
||||
if (p_disp_frame_) {
|
||||
RocdecParserDispInfo dispInfo = {0}; // dispinfo is not used in ffmpeg decoder, so setting it to zero
|
||||
dispInfo.picture_index = p_disp_frame_->picture_index;
|
||||
if (pfn_display_picture_cb_ && decoder_create_info_.user_data) {
|
||||
pfn_display_picture_cb_(decoder_create_info_.user_data, &dispInfo);
|
||||
}
|
||||
}
|
||||
num_frames_to_display--;
|
||||
};
|
||||
|
||||
return ROCDEC_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2025 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
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/pixdesc.h>
|
||||
#if USE_AVCODEC_GREATER_THAN_58_134
|
||||
#include <libavcodec/bsf.h>
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <queue>
|
||||
#include <atomic>
|
||||
#include "../src/commons.h"
|
||||
#include "../api/rocdecode/rocdecode.h"
|
||||
#include "../api/rocdecode/rocdecode_host.h"
|
||||
|
||||
|
||||
#define MAX_AV_PACKET_DATA_SIZE 4096
|
||||
|
||||
typedef struct DecFrameBufferFFMpeg_ {
|
||||
AVFrame *av_frame_ptr; /**< av_frame pointer for the decoded frame */
|
||||
uint8_t *frame_ptr; /**< host memory pointer for the decoded frame depending on mem_type*/
|
||||
int64_t pts; /**< timestamp for the decoded frame */
|
||||
int picture_index; /**< surface index for the decoded frame */
|
||||
} DecFrameBufferFFMpeg;
|
||||
|
||||
typedef struct DecPacketBuffer_
|
||||
{
|
||||
AVPacket *av_pckt;
|
||||
int av_frame_index;
|
||||
} DecPacketBuffer;
|
||||
|
||||
typedef struct Rect_{
|
||||
int16_t left;
|
||||
int16_t top;
|
||||
int16_t right;
|
||||
int16_t bottom;
|
||||
} Rect;
|
||||
|
||||
/**
|
||||
* Class definition for AVcodec based video decoder class. This uses FFMpeg avcodec decoder to decode video frames
|
||||
*/
|
||||
class AvcodecVideoDecoder {
|
||||
public:
|
||||
AvcodecVideoDecoder(RocDecoderHostCreateInfo &decoder_create_info);
|
||||
~AvcodecVideoDecoder();
|
||||
rocDecStatus InitializeDecoder();
|
||||
rocDecStatus SubmitDecode(RocdecPicParamsHost *pPicParams);
|
||||
rocDecStatus GetDecodeStatus(int pic_idx, RocdecDecodeStatus* decode_status);
|
||||
rocDecStatus ReconfigureDecoder(RocdecReconfigureDecoderInfo *reconfig_params);
|
||||
rocDecStatus GetVideoFrame(int pic_idx, void **frame_ptr, uint32_t *line_size, RocdecProcParams *vid_postproc_params);
|
||||
|
||||
protected:
|
||||
RocDecoderHostCreateInfo decoder_create_info_;
|
||||
RocdecVideoFormatHost video_format_host_;
|
||||
|
||||
/*! \brief callback function pointers for the parser
|
||||
*/
|
||||
PFNVIDSEQUENCECHOSTALLBACK pfn_sequece_cb_ = nullptr; /**< Called before decoding frames and/or whenever there is a fmt change */
|
||||
PFNVIDDISPLAYCALLBACK pfn_display_picture_cb_ = nullptr; /**< Called whenever a picture is ready to be displayed (display order) */
|
||||
PFNVIDSEIMSGCALLBACK pfn_get_sei_message_cb_ = nullptr; /**< Called when all SEI messages are parsed for particular frame */
|
||||
|
||||
private:
|
||||
void DecodeThread();
|
||||
int DecodeAvFrame(AVPacket *av_pkt, AVFrame *p_frame);
|
||||
int FlushDecoder();
|
||||
rocDecStatus NotifyNewSequence(AVFrame *p_frame);
|
||||
rocDecStatus NotifySeiMesage(AVFrame *p_frame);
|
||||
rocDecStatus NotifyPictureDisplay();
|
||||
rocDecStatus SendSeiMsgPayload(AVFrame *p_frame);
|
||||
|
||||
void PushPacket(AVPacket *pkt) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx_pkt_q_);
|
||||
av_packet_q_.push(pkt);
|
||||
}
|
||||
cv_pkt_.notify_one();
|
||||
}
|
||||
|
||||
AVPacket *PopPacket() {
|
||||
AVPacket *pkt;
|
||||
std::unique_lock<std::mutex> lock(mtx_pkt_q_);
|
||||
cv_pkt_.wait(lock, [&] { return !av_packet_q_.empty(); });
|
||||
pkt = av_packet_q_.front();
|
||||
av_packet_q_.pop();
|
||||
return pkt;
|
||||
}
|
||||
|
||||
DecFrameBufferFFMpeg *GetDisplayFrame() {
|
||||
std::unique_lock<std::mutex> lock(mtx_frame_q_);
|
||||
cv_frame_.wait(lock, [&] { return !disp_frames_q_.empty() || end_of_stream_; });
|
||||
if (end_of_stream_ && disp_frames_q_.empty())
|
||||
return nullptr;
|
||||
DecFrameBufferFFMpeg *p_disp_frame = &disp_frames_q_.front();
|
||||
disp_frames_q_.pop();
|
||||
return p_disp_frame;
|
||||
}
|
||||
|
||||
void PushDisplayFrame(DecFrameBufferFFMpeg& frame) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx_frame_q_);
|
||||
disp_frames_q_.push(frame);
|
||||
}
|
||||
cv_frame_.notify_one();
|
||||
};
|
||||
|
||||
int decoded_pic_cnt_ = 0;
|
||||
int coded_width_ = 0, coded_height_ = 0; // need to detect resolution changes for sps callback function
|
||||
Rect disp_rect_ = {}; // displayable area specified in the bitstream
|
||||
int av_sample_format = -1;
|
||||
bool b_multithreading_ = true;
|
||||
uint32_t av_frame_cnt_ = 0;
|
||||
uint32_t av_pkt_cnt_ = 0;
|
||||
RocdecSourceDataPacket last_packet_;
|
||||
std::thread *ffmpeg_decoder_thread_ = nullptr;
|
||||
std::queue<AVPacket *> av_packet_q_; // queue for compressed packets
|
||||
std::queue<DecFrameBufferFFMpeg> disp_frames_q_; // vector of decoded frames
|
||||
std::vector<AVFrame *> dec_frames_; // vector of AVFrame * for decoded frames
|
||||
std::vector<AVPacket *> av_packets_; // store of AVPackets for decoding
|
||||
std::vector<std::pair<uint8_t *, int>> av_packet_data_;
|
||||
std::mutex mtx_pkt_q_, mtx_frame_q_; //for packet and frames
|
||||
std::condition_variable cv_pkt_, cv_frame_;
|
||||
DecFrameBufferFFMpeg *p_disp_frame_ = nullptr; // frame to display
|
||||
std::atomic<bool> end_of_stream_ = false;
|
||||
// Variables for FFMpeg decoding
|
||||
AVCodecContext * dec_context_ = nullptr;
|
||||
AVPixelFormat decoder_pixel_format_;
|
||||
#if USE_AVCODEC_GREATER_THAN_58_134
|
||||
const AVCodec *decoder_ = nullptr;
|
||||
#else
|
||||
AVCodec *decoder_ = nullptr;
|
||||
#endif
|
||||
AVFormatContext * formatContext = nullptr;
|
||||
AVInputFormat * inputFormat = nullptr;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2025 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 <memory>
|
||||
#include <string>
|
||||
|
||||
#include "roc_decoder_host.h"
|
||||
|
||||
/**
|
||||
* @brief DecHandle structure
|
||||
*
|
||||
*/
|
||||
struct DecHandleHost {
|
||||
|
||||
explicit DecHandleHost(RocDecoderHostCreateInfo& decoder_create_info) : roc_decoder_host_(std::make_shared<RocDecoderHost>(decoder_create_info)) {}; //constructor
|
||||
~DecHandleHost() { ClearErrors(); }
|
||||
std::shared_ptr<RocDecoderHost> roc_decoder_host_;
|
||||
bool NoError() { return error_.empty(); }
|
||||
const char* ErrorMsg() { return error_.c_str(); }
|
||||
void CaptureError(const std::string& err_msg) { error_ = err_msg; }
|
||||
|
||||
private:
|
||||
void ClearErrors() { error_ = "";}
|
||||
std::string error_;
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2025 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 "../commons.h"
|
||||
#include "roc_decoder_host.h"
|
||||
|
||||
RocDecoderHost::RocDecoderHost(RocDecoderHostCreateInfo& decoder_create_info): avcodec_video_decoder_{decoder_create_info}, decoder_create_info_{decoder_create_info} {}
|
||||
|
||||
RocDecoderHost::~RocDecoderHost() {}
|
||||
|
||||
rocDecStatus RocDecoderHost::InitializeDecoder() {
|
||||
rocDecStatus rocdec_status = ROCDEC_SUCCESS;
|
||||
if (!decoder_create_info_.user_data) {
|
||||
ERR("Invalid function callback pointer passed");
|
||||
return ROCDEC_NOT_INITIALIZED;
|
||||
}
|
||||
rocdec_status = avcodec_video_decoder_.InitializeDecoder();
|
||||
if (rocdec_status != ROCDEC_SUCCESS) {
|
||||
ERR("Failed to initialize the FFMpeg Video decoder.");
|
||||
return rocdec_status;
|
||||
}
|
||||
return rocdec_status;
|
||||
}
|
||||
|
||||
rocDecStatus RocDecoderHost::DecodeFrame(RocdecPicParamsHost *pic_params) {
|
||||
rocDecStatus rocdec_status = ROCDEC_SUCCESS;
|
||||
rocdec_status = avcodec_video_decoder_.SubmitDecode(pic_params);
|
||||
if (rocdec_status != ROCDEC_SUCCESS) {
|
||||
ERR("Decode submission is not successful.");
|
||||
}
|
||||
|
||||
return rocdec_status;
|
||||
}
|
||||
|
||||
rocDecStatus RocDecoderHost::GetDecodeStatus(int pic_idx, RocdecDecodeStatus* decode_status) {
|
||||
rocDecStatus rocdec_status = ROCDEC_SUCCESS;
|
||||
rocdec_status = avcodec_video_decoder_.GetDecodeStatus(pic_idx, decode_status);
|
||||
if (rocdec_status != ROCDEC_SUCCESS) {
|
||||
ERR("Failed to query the decode status.");
|
||||
}
|
||||
return rocdec_status;
|
||||
}
|
||||
|
||||
rocDecStatus RocDecoderHost::ReconfigureDecoder(RocdecReconfigureDecoderInfo *reconfig_params) {
|
||||
if (reconfig_params == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
rocDecStatus rocdec_status = avcodec_video_decoder_.ReconfigureDecoder(reconfig_params);
|
||||
if (rocdec_status != ROCDEC_SUCCESS) {
|
||||
ERR("Reconfiguration of the decoder failed.");
|
||||
return rocdec_status;
|
||||
}
|
||||
return rocdec_status;
|
||||
}
|
||||
|
||||
rocDecStatus RocDecoderHost::GetVideoFrame(int pic_idx, void **frame_ptr, uint32_t *line_size, RocdecProcParams *vid_postproc_params) {
|
||||
if (vid_postproc_params == nullptr || frame_ptr == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
rocDecStatus rocdec_status = avcodec_video_decoder_.GetVideoFrame(pic_idx, frame_ptr, line_size, vid_postproc_params);
|
||||
if (rocdec_status != ROCDEC_SUCCESS) {
|
||||
ERR("GetVideoFrame failed.");
|
||||
return rocdec_status;
|
||||
}
|
||||
return rocdec_status;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2025 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 <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
#include "avcodec/avcodec_videodecoder.h"
|
||||
|
||||
/**
|
||||
* RocDecoderHost class: Wrapper class for rocDecoderHost API implementation
|
||||
*/
|
||||
class RocDecoderHost {
|
||||
public:
|
||||
RocDecoderHost(RocDecoderHostCreateInfo &decoder_create_info);
|
||||
~RocDecoderHost();
|
||||
rocDecStatus InitializeDecoder();
|
||||
rocDecStatus DecodeFrame(RocdecPicParamsHost *pic_params);
|
||||
rocDecStatus GetDecodeStatus(int pic_idx, RocdecDecodeStatus* decode_status);
|
||||
rocDecStatus ReconfigureDecoder(RocdecReconfigureDecoderInfo *reconfig_params);
|
||||
rocDecStatus GetVideoFrame(int pic_idx, void *frame_ptr[3], uint32_t line_size[3], RocdecProcParams *vid_postproc_params);
|
||||
|
||||
private:
|
||||
AvcodecVideoDecoder avcodec_video_decoder_;
|
||||
RocDecoderHostCreateInfo decoder_create_info_;
|
||||
};
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2025 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 "dec_handle_host.h"
|
||||
#include "../api/rocdecode/rocdecode.h"
|
||||
#include "../src/commons.h"
|
||||
|
||||
/*****************************************************************************************************/
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecCreateDecoderHost(rocDecDecoderHandle *decoder_handle, RocDecoderCreateInfoHost *decoder_create_info)
|
||||
//! Create the decoder object based on decoder_create_info. A handle to the created decoder is returned
|
||||
/*****************************************************************************************************/
|
||||
rocDecStatus ROCDECAPI
|
||||
rocDecCreateDecoderHost(rocDecDecoderHandle *decoder_handle, RocDecoderHostCreateInfo *decoder_create_info) {
|
||||
if (decoder_handle == nullptr || decoder_create_info == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
rocDecDecoderHandle handle = nullptr;
|
||||
try {
|
||||
handle = new DecHandleHost(*decoder_create_info);
|
||||
}
|
||||
catch(const std::exception& e) {
|
||||
ERR( STR("Failed to init the rocDecode handle, ") + STR(e.what()))
|
||||
return ROCDEC_NOT_INITIALIZED;
|
||||
}
|
||||
*decoder_handle = handle;
|
||||
return static_cast<DecHandleHost *>(handle)->roc_decoder_host_->InitializeDecoder();
|
||||
}
|
||||
|
||||
/*****************************************************************************************************/
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecDestroyDecoderHost(rocDecDecoderHandle decoder_handle)
|
||||
//! Destroy the decoder object
|
||||
/*****************************************************************************************************/
|
||||
rocDecStatus ROCDECAPI
|
||||
rocDecDestroyDecoderHost(rocDecDecoderHandle decoder_handle) {
|
||||
if (decoder_handle == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
auto handle = static_cast<DecHandleHost *>(decoder_handle);
|
||||
delete handle;
|
||||
return ROCDEC_SUCCESS;
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecGetDecoderCapsHost(rocDecDecoderHandle decoder_handle, RocdecDecodeCaps *pdc)
|
||||
//! Queries decode capabilities of host based decoder based on codec type, chroma_format and BitDepthMinus8 parameters.
|
||||
//! 1. Application fills IN parameters codec_type, chroma_format and BitDepthMinus8 of RocdecDecodeCaps structure
|
||||
//! 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.
|
||||
//! Currently this is not supported in avcodec based decoder
|
||||
/**********************************************************************************************************************/
|
||||
rocDecStatus ROCDECAPI
|
||||
rocDecGetDecoderCapsHost(RocdecDecodeCaps *pdc) {
|
||||
if (pdc == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
//todo:
|
||||
return ROCDEC_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/*****************************************************************************************************/
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecDecodeFrameHost(rocDecDecoderHandle decoder_handle, RocdecPicParams *pic_params)
|
||||
//! Decodes a single picture
|
||||
//! Submits the frame for HW decoding
|
||||
/*****************************************************************************************************/
|
||||
rocDecStatus ROCDECAPI
|
||||
rocDecDecodeFrameHost(rocDecDecoderHandle decoder_handle, _RocdecPicParamsHost *pic_params) {
|
||||
if (decoder_handle == nullptr || pic_params == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
auto handle = static_cast<DecHandleHost *>(decoder_handle);
|
||||
rocDecStatus ret;
|
||||
try {
|
||||
ret = handle->roc_decoder_host_->DecodeFrame(pic_params);
|
||||
}
|
||||
catch(const std::exception& e) {
|
||||
handle->CaptureError(e.what());
|
||||
ERR(e.what())
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/************************************************************************************************************/
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecGetDecodeStatusHost(rocDecDecoderHandle decoder_handle, int pic_idx, RocdecDecodeStatus* decode_status);
|
||||
//! Get the decode status for frame corresponding to pic_idx
|
||||
//! API is currently supported for HEVC codec.
|
||||
//! API returns ROCDEC_NOT_SUPPORTED error code for unsupported GPU or codec.
|
||||
/************************************************************************************************************/
|
||||
rocDecStatus ROCDECAPI
|
||||
rocDecGetDecodeStatusHost(rocDecDecoderHandle decoder_handle, int pic_idx, RocdecDecodeStatus* decode_status) {
|
||||
if (decoder_handle == nullptr || decode_status == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
auto handle = static_cast<DecHandleHost *>(decoder_handle);
|
||||
rocDecStatus ret;
|
||||
try {
|
||||
ret = handle->roc_decoder_host_->GetDecodeStatus(pic_idx, decode_status);
|
||||
}
|
||||
catch(const std::exception& e) {
|
||||
handle->CaptureError(e.what());
|
||||
ERR(e.what())
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*********************************************************************************************************/
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecReconfigureDecoderHost(rocDecDecoderHandle decoder_handle, RocdecReconfigureDecoderInfo *reconfig_params)
|
||||
//! Used to reuse single decoder for multiple clips. Currently supports resolution change, resize params
|
||||
//! params, target area params change for same codec. Must be called during RocdecParserParams::pfn_sequence_callback
|
||||
/*********************************************************************************************************/
|
||||
rocDecStatus ROCDECAPI
|
||||
rocDecReconfigureDecoderHost(rocDecDecoderHandle decoder_handle, RocdecReconfigureDecoderInfo *reconfig_params) {
|
||||
if (decoder_handle == nullptr || reconfig_params == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
auto handle = static_cast<DecHandleHost *>(decoder_handle);
|
||||
rocDecStatus ret;
|
||||
try {
|
||||
ret = handle->roc_decoder_host_->ReconfigureDecoder(reconfig_params);
|
||||
}
|
||||
catch(const std::exception& e) {
|
||||
handle->CaptureError(e.what());
|
||||
ERR(e.what())
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecGetVideoFrameHost(rocDecDecoderHandle decoder_handle, int pic_idx, unsigned int *dev_mem_ptr,
|
||||
//! unsigned int *horizontal_pitch, RocdecProcParams *vid_postproc_params);
|
||||
//! Post-process and map video frame corresponding to pic_idx 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) separately
|
||||
/************************************************************************************************************************/
|
||||
rocDecStatus ROCDECAPI
|
||||
rocDecGetVideoFrameHost(rocDecDecoderHandle decoder_handle, int pic_idx,
|
||||
void **frame_data, uint32_t *line_size,
|
||||
RocdecProcParams *vid_postproc_params) {
|
||||
if (decoder_handle == nullptr || frame_data == nullptr || line_size == nullptr || vid_postproc_params == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
auto handle = static_cast<DecHandleHost *>(decoder_handle);
|
||||
rocDecStatus ret;
|
||||
try {
|
||||
ret = handle->roc_decoder_host_->GetVideoFrame(pic_idx, frame_data, line_size, vid_postproc_params);
|
||||
}
|
||||
catch(const std::exception& e) {
|
||||
handle->CaptureError(e.what());
|
||||
ERR(e.what())
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************************************************/
|
||||
//! \fn const char* ROCDECAPI rocDecGetErrorNameHost(rocDecStatus rocdec_status)
|
||||
//! \ingroup group_amd_rocdecode
|
||||
//! Return name of the specified error code in text form.
|
||||
/*****************************************************************************************************/
|
||||
const char* ROCDECAPI rocDecGetErrorNameHost(rocDecStatus rocdec_status) {
|
||||
switch (rocdec_status) {
|
||||
case ROCDEC_DEVICE_INVALID:
|
||||
return "ROCDEC_DEVICE_INVALID";
|
||||
case ROCDEC_CONTEXT_INVALID:
|
||||
return "ROCDEC_CONTEXT_INVALID";
|
||||
case ROCDEC_RUNTIME_ERROR:
|
||||
return "ROCDEC_RUNTIME_ERROR";
|
||||
case ROCDEC_OUTOF_MEMORY:
|
||||
return "ROCDEC_OUTOF_MEMORY";
|
||||
case ROCDEC_INVALID_PARAMETER:
|
||||
return "ROCDEC_INVALID_PARAMETER";
|
||||
case ROCDEC_NOT_IMPLEMENTED:
|
||||
return "ROCDEC_NOT_IMPLEMENTED";
|
||||
case ROCDEC_NOT_INITIALIZED:
|
||||
return "ROCDEC_NOT_INITIALIZED";
|
||||
case ROCDEC_NOT_SUPPORTED:
|
||||
return "ROCDEC_NOT_SUPPORTED";
|
||||
default:
|
||||
return "UNKNOWN_ERROR";
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@ rocDecDecodeFrame(rocDecDecoderHandle decoder_handle, RocdecPicParams *pic_param
|
||||
//! \fn rocDecStatus ROCDECAPI RocdecGetDecodeStatus(rocDecDecoderHandle decoder_handle, int pic_idx, RocdecDecodeStatus* decode_status);
|
||||
//! Get the decode status for frame corresponding to pic_idx
|
||||
//! API is currently supported for HEVC codec.
|
||||
//! API returns CUDA_ERROR_NOT_SUPPORTED error code for unsupported GPU or codec.
|
||||
//! API returns ROCDEC_NOT_SUPPORTED error code for unsupported GPU or codec.
|
||||
/************************************************************************************************************/
|
||||
rocDecStatus ROCDECAPI
|
||||
rocDecGetDecodeStatus(rocDecDecoderHandle decoder_handle, int pic_idx, RocdecDecodeStatus* decode_status) {
|
||||
|
||||
Reference in New Issue
Block a user