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:
Rajy Rawther
2025-06-07 10:12:57 -07:00
committed by GitHub
parent 0f89c9c17c
commit 3ddb12f075
68 changed files with 2194 additions and 5 deletions
+114
View File
@@ -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;
};
+45
View File
@@ -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_;
};
+85
View File
@@ -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;
}
+51
View File
@@ -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_;
};
+200
View File
@@ -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";
}
}
+1 -1
View File
@@ -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) {