ffmpeg decode utility class cleanup (#616)
* cleaned up ffmpeg decode utility class to use rocdecode host lib
* added changelog for the PR
* address review comments for FFMPEG dependancy in cmake
* Update CHANGELOG.md
Co-authored-by: spolifroni-amd <Sandra.Polifroni@amd.com>
* addressed review comments
* update version in Cmake
---------
Co-authored-by: spolifroni-amd <Sandra.Polifroni@amd.com>
[ROCm/rocdecode commit: 3b280ac7c3]
このコミットが含まれているのは:
@@ -2,7 +2,7 @@
|
||||
|
||||
Full documentation for rocDecode is available at [https://rocm.docs.amd.com/projects/rocDecode/en/latest/](https://rocm.docs.amd.com/projects/rocDecode/en/latest/)
|
||||
|
||||
## rocdecode 1.0.0 for ROCm 7.0.0
|
||||
## rocdecode 1.1.0 for ROCm 7.0.0
|
||||
|
||||
### Added
|
||||
|
||||
@@ -13,7 +13,7 @@ Full documentation for rocDecode is available at [https://rocm.docs.amd.com/proj
|
||||
* AVC stream DPB buffer size change handling through decoder reconfiguration.
|
||||
* rocdecode now uses the Cmake CMAKE_PREFIX_PATH directive.
|
||||
* rocdecode - A new avcodec-based decoder built as a separate "rocdecode-host" library
|
||||
|
||||
* The host backend in the `videoDeode` sample now uses the rocdecode-host library
|
||||
|
||||
### Optimized
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ if (NOT DEFINED CMAKE_CXX_COMPILER)
|
||||
endif()
|
||||
|
||||
# rocdecode Version
|
||||
set(VERSION "1.0.0")
|
||||
set(VERSION "1.1.0")
|
||||
|
||||
# Set Project Version and Language
|
||||
project(rocdecode VERSION ${VERSION} LANGUAGES CXX)
|
||||
|
||||
@@ -82,24 +82,30 @@ if(HIP_FOUND AND FFMPEG_FOUND AND rocdecode_FOUND AND Threads_FOUND AND rocprofi
|
||||
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} Threads::Threads)
|
||||
# rocprofiler-register
|
||||
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocprofiler-register::rocprofiler-register)
|
||||
# sample app exe
|
||||
# rocdecodehost
|
||||
find_library(ROCDECODE_HOST_LIBRARY NAMES rocdecodehost HINTS ${ROCM_PATH}/lib)
|
||||
list(APPEND SOURCES ${PROJECT_SOURCE_DIR} videodecode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/rocvideodecode/roc_video_dec.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/ffmpegvideodecode/ffmpeg_video_dec.cpp)
|
||||
# sample app exe
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} ${LINK_LIBRARY_LIST})
|
||||
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocdecode::rocdecode)
|
||||
if(ROCDECODE_HOST_LIBRARY)
|
||||
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${ROCDECODE_HOST_LIBRARY})
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC ENABLE_HOST_DECODE=1)
|
||||
else()
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC ENABLE_HOST_DECODE=0)
|
||||
endif()
|
||||
# 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()
|
||||
target_link_libraries(${PROJECT_NAME} ${LINK_LIBRARY_LIST})
|
||||
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 rocdecode_FOUND)
|
||||
message(FATAL_ERROR "-- ERROR!: rocdecode Not Found! - please install rocdecode!")
|
||||
endif()
|
||||
|
||||
@@ -42,6 +42,11 @@ THE SOFTWARE.
|
||||
#include "ffmpeg_video_dec.h"
|
||||
#include "common.h"
|
||||
|
||||
//hardcoding for host based decoder creation if demux is not available
|
||||
#define DEFAULT_WIDTH 2912
|
||||
#define DEFAULT_HEIGHT 1888
|
||||
|
||||
|
||||
void ShowHelpAndExit(const char *option = NULL) {
|
||||
std::cout << "Options:" << std::endl
|
||||
<< "-i Input File Path - required" << std::endl
|
||||
@@ -89,7 +94,7 @@ int main(int argc, char **argv) {
|
||||
int seek_criteria = 0, seek_mode = 0;
|
||||
bool b_use_ffmpeg_demuxer = true; // true by default to use FFMPEG demuxer. set to false to use the built-in bitstream reader.
|
||||
|
||||
// Parse command-line arguments
|
||||
// Parse command-line arguments
|
||||
if(argc <= 1) {
|
||||
ShowHelpAndExit();
|
||||
}
|
||||
@@ -259,10 +264,16 @@ int main(int argc, char **argv) {
|
||||
if (!backend) // gpu backend
|
||||
viddec = new RocVideoDecoder(device_id, mem_type, rocdec_codec_id, b_force_zero_latency, p_crop_rect, b_extract_sei_messages, disp_delay);
|
||||
else {
|
||||
#if ENABLE_HOST_DECODE
|
||||
std::cout << "info: RocDecode is using CPU backend!" << std::endl;
|
||||
bool use_threading = false;
|
||||
uint32_t max_width = b_use_ffmpeg_demuxer ? demuxer->GetWidth() : DEFAULT_WIDTH;
|
||||
uint32_t max_height = b_use_ffmpeg_demuxer ? demuxer->GetHeight() : DEFAULT_HEIGHT;
|
||||
if (mem_type == OUT_SURFACE_MEM_DEV_INTERNAL) mem_type = OUT_SURFACE_MEM_DEV_COPIED; // mem_type internal is not supported in this mode
|
||||
viddec = new FFMpegVideoDecoder(device_id, mem_type, rocdec_codec_id, b_force_zero_latency, p_crop_rect, b_extract_sei_messages, disp_delay, true);
|
||||
viddec = new FFMpegVideoDecoder(device_id, mem_type, rocdec_codec_id, b_force_zero_latency, p_crop_rect, b_extract_sei_messages, disp_delay, max_width, max_height);
|
||||
#else
|
||||
std::cout << "Error: RocDecode HOST library is not found and backend is not supported!" << std::endl;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(!viddec->CodecSupported(device_id, rocdec_codec_id, bit_depth)) {
|
||||
@@ -346,7 +357,8 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
n_frame_returned = viddec->DecodeFrame(pvideo, n_video_bytes, pkg_flags, pts, &decoded_pics);
|
||||
|
||||
if (!n_frame && !viddec->GetOutputSurfaceInfo(&surf_info)) {
|
||||
// get output surface info after the first decoded frame
|
||||
if (!n_frame && (n_frame_returned > 0) && !viddec->GetOutputSurfaceInfo(&surf_info)) {
|
||||
std::cerr << "Error: Failed to get Output Surface Info!" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -341,7 +341,8 @@ int AvcodecVideoDecoder::DecodeAvFrame(AVPacket *av_pkt, AVFrame *p_frame) {
|
||||
//send packet to av_codec
|
||||
status = avcodec_send_packet(dec_context_, av_pkt);
|
||||
if (status < 0) {
|
||||
ERR("Error sending av packet for decoding: status: ");
|
||||
if (av_pkt->data && av_pkt->size)
|
||||
ERR("Error sending av packet for decoding: status: ");
|
||||
return status;
|
||||
}
|
||||
while (status >= 0) {
|
||||
|
||||
@@ -23,27 +23,7 @@ THE SOFTWARE.
|
||||
|
||||
#include "ffmpeg_video_dec.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;
|
||||
}
|
||||
}
|
||||
|
||||
//helper function
|
||||
static inline float GetChromaWidthFactor(rocDecVideoSurfaceFormat surface_format) {
|
||||
float factor = 0.5;
|
||||
switch (surface_format) {
|
||||
@@ -63,66 +43,44 @@ static inline float GetChromaWidthFactor(rocDecVideoSurfaceFormat surface_format
|
||||
return factor;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief helper function for inferring AVCodecID from rocDecVideoSurfaceFormat
|
||||
*
|
||||
* @param rocdec_codec
|
||||
* @return AVCodecID
|
||||
*/
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
FFMpegVideoDecoder::FFMpegVideoDecoder(int device_id, OutputSurfaceMemoryType out_mem_type, rocDecVideoCodec codec, bool force_zero_latency,
|
||||
const Rect *p_crop_rect, bool extract_user_sei_Message, uint32_t disp_delay, bool no_multithreading, int max_width, int max_height, uint32_t clk_rate) :
|
||||
RocVideoDecoder(device_id, out_mem_type, codec, force_zero_latency, p_crop_rect, extract_user_sei_Message, disp_delay, max_width, max_height, clk_rate), no_multithreading_(no_multithreading) {
|
||||
const Rect *p_crop_rect, bool extract_user_sei_Message, uint32_t disp_delay, int max_width, int max_height, uint32_t clk_rate) :
|
||||
RocVideoDecoder(device_id, out_mem_type, codec, force_zero_latency, p_crop_rect, extract_user_sei_Message, disp_delay, max_width, max_height, clk_rate) {
|
||||
|
||||
if ((out_mem_type_ == OUT_SURFACE_MEM_DEV_INTERNAL) || (out_mem_type_ == OUT_SURFACE_MEM_NOT_MAPPED)) {
|
||||
ROCDEC_THROW("Output Memory Type is not supported", ROCDEC_INVALID_PARAMETER);
|
||||
}
|
||||
if (rocdec_parser_) {
|
||||
rocDecDestroyVideoParser(rocdec_parser_); // need to do this here since it was already created in the base class
|
||||
// create rocdec videoparser
|
||||
RocdecParserParams parser_params = {};
|
||||
parser_params.codec_type = codec_id_;
|
||||
parser_params.max_num_decode_surfaces = 1; // let the parser to determine the decode buffer pool size
|
||||
parser_params.clock_rate = clk_rate;
|
||||
parser_params.max_display_delay = disp_delay_;
|
||||
parser_params.user_data = this;
|
||||
parser_params.pfn_sequence_callback = FFMpegHandleVideoSequenceProc;
|
||||
parser_params.pfn_decode_picture = FFMpegHandlePictureDecodeProc;
|
||||
parser_params.pfn_display_picture = nullptr; // HandlePictureDisplay will be controlled by FFMpegDecoder
|
||||
parser_params.pfn_get_sei_msg = b_extract_sei_message_ ? RocVideoDecoder::HandleSEIMessagesProc : NULL;
|
||||
ROCDEC_API_CALL(rocDecCreateVideoParser(&rocdec_parser_, &parser_params));
|
||||
}
|
||||
if (!no_multithreading_) {
|
||||
// start the FFMpeg decoding thread
|
||||
ffmpeg_decoder_thread_ = new std::thread(&FFMpegVideoDecoder::DecodeThread, this);
|
||||
if (!ffmpeg_decoder_thread_) {
|
||||
ROCDEC_THROW("FFMpegVideoDecoder create thread failed", -1);
|
||||
}
|
||||
ROCDEC_THROW("Unsupported output memory type", ROCDEC_INVALID_PARAMETER);
|
||||
}
|
||||
// many of the decoder parameters are hardcoded below for just creating the decoder.
|
||||
// In the handlevideosequence callback, the decoder will get reconfigured to the actual parameters in the sequence header
|
||||
RocDecoderHostCreateInfo create_info = {};
|
||||
create_info.codec_type = codec;
|
||||
create_info.num_decode_threads = 0; // default
|
||||
create_info.max_width = max_width;
|
||||
create_info.max_height = max_height;
|
||||
create_info.width = max_width;
|
||||
create_info.height = max_height;
|
||||
create_info.target_width = max_width;
|
||||
create_info.target_height = max_height;
|
||||
create_info.display_rect.left = 0;
|
||||
create_info.display_rect.right = static_cast<short>(max_width);
|
||||
create_info.display_rect.top = 0;
|
||||
create_info.display_rect.bottom = static_cast<short>(max_height);
|
||||
create_info.chroma_format = rocDecVideoChromaFormat_420;
|
||||
create_info.output_format = rocDecVideoSurfaceFormat_P016;
|
||||
create_info.bit_depth_minus_8 = 2;
|
||||
create_info.num_output_surfaces = 1;
|
||||
create_info.user_data = this;
|
||||
create_info.pfn_sequence_callback = FFMpegHandleVideoSequenceProc;
|
||||
create_info.pfn_display_picture = FFMpegHandlePictureDisplayProc;
|
||||
create_info.pfn_get_sei_msg = nullptr; // tobe supported in future
|
||||
ROCDEC_API_CALL(rocDecCreateDecoderHost(&roc_decoder_, &create_info));
|
||||
|
||||
}
|
||||
|
||||
|
||||
FFMpegVideoDecoder::~FFMpegVideoDecoder() {
|
||||
|
||||
std::lock_guard<std::mutex> lock(mtx_vp_frame_);
|
||||
for (auto &p_frame : vp_frames_ffmpeg_) {
|
||||
for (auto &p_frame : vp_frames_) {
|
||||
if (p_frame.frame_ptr) {
|
||||
if (out_mem_type_ == OUT_SURFACE_MEM_DEV_COPIED) {
|
||||
hipError_t hip_status = hipFree(p_frame.frame_ptr);
|
||||
@@ -132,39 +90,18 @@ FFMpegVideoDecoder::~FFMpegVideoDecoder() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// release frame_q
|
||||
while (!dec_frames_.empty()) {
|
||||
av_frame_free(&dec_frames_.back());
|
||||
dec_frames_.pop_back();
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
|
||||
if (dec_context_) {
|
||||
avcodec_free_context(&dec_context_);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return value from HandleVideoSequence() are interpreted as :
|
||||
* 0: fail, 1: succeeded, > 1: override dpb size of parser (set by RocdecParserParams::max_num_decode_surfaces while creating parser)
|
||||
*/
|
||||
int FFMpegVideoDecoder::HandleVideoSequence(RocdecVideoFormat *p_video_format) {
|
||||
if (p_video_format == nullptr) {
|
||||
int FFMpegVideoDecoder::HandleVideoSequence(RocdecVideoFormatHost *format_host) {
|
||||
if (format_host == nullptr) {
|
||||
ROCDEC_THROW("Rocdec:: Invalid video format in HandleVideoSequence: ", ROCDEC_INVALID_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
auto start_time = StartTimer();
|
||||
RocdecVideoFormat *p_video_format = &format_host->video_format;
|
||||
input_video_info_str_.str("");
|
||||
input_video_info_str_.clear();
|
||||
input_video_info_str_ << "Input Video Information" << std::endl
|
||||
@@ -181,63 +118,6 @@ int FFMpegVideoDecoder::HandleVideoSequence(RocdecVideoFormat *p_video_format) {
|
||||
input_video_info_str_ << std::endl;
|
||||
|
||||
int num_decode_surfaces = p_video_format->min_num_decode_surfaces;
|
||||
|
||||
// check if the codec is supported in FFMpeg
|
||||
// Initialize FFMpeg and find the decoder for codec
|
||||
if (!decoder_) decoder_ = avcodec_find_decoder(RocDecVideoCodec2AVCodec(p_video_format->codec));
|
||||
if(!decoder_) {
|
||||
ROCDEC_THROW("rocDecode<FFMpeg>:: Codec not supported by FFMpeg ", ROCDEC_NOT_SUPPORTED);
|
||||
return 0;
|
||||
}
|
||||
if (!dec_context_) {
|
||||
dec_context_ = avcodec_alloc_context3(decoder_); //alloc dec_context_
|
||||
if (!dec_context_) {
|
||||
ROCDEC_THROW("Could not allocate video codec context", ROCDEC_RUNTIME_ERROR);
|
||||
}
|
||||
// set codec to automatically determine how many threads suits best for the decoding job
|
||||
dec_context_->thread_count = 0;
|
||||
|
||||
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) {
|
||||
ROCDEC_THROW("Could not open codec", 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;
|
||||
}
|
||||
// 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: revisit this to fix with the correct number from seq_header
|
||||
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;
|
||||
}
|
||||
if (av_packet_data_.empty()) {
|
||||
for (int i = 0; i < num_decode_surfaces; 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 < num_decode_surfaces; 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_video_format_ptr_ == nullptr) {
|
||||
curr_video_format_ptr_ = new RocdecVideoFormat();
|
||||
}
|
||||
@@ -245,8 +125,7 @@ int FFMpegVideoDecoder::HandleVideoSequence(RocdecVideoFormat *p_video_format) {
|
||||
if (curr_video_format_ptr_) memcpy(curr_video_format_ptr_, p_video_format, sizeof(RocdecVideoFormat));
|
||||
|
||||
if (coded_width_ && coded_height_) {
|
||||
end_of_stream_ = false;
|
||||
b_decoder_initialized = false; // reinitialize for reconfigure
|
||||
// rocdecCreateDecoder() has been called before, and now there's possible config change
|
||||
return ReconfigureDecoder(p_video_format);
|
||||
}
|
||||
// e_codec has been set in the constructor (for parser). Here it's set again for potential correction
|
||||
@@ -256,7 +135,7 @@ int FFMpegVideoDecoder::HandleVideoSequence(RocdecVideoFormat *p_video_format) {
|
||||
byte_per_pixel_ = bitdepth_minus_8_ > 0 ? 2 : 1;
|
||||
|
||||
// convert AVPixelFormat to rocDecVideoChromaFormat
|
||||
video_surface_format_ = AVPixelFormat2rocDecVideoSurfaceFormat(decoder_pixel_format_);
|
||||
video_surface_format_ = format_host->video_surface_format;
|
||||
coded_width_ = p_video_format->coded_width;
|
||||
coded_height_ = p_video_format->coded_height;
|
||||
disp_rect_.top = p_video_format->display_area.top;
|
||||
@@ -279,7 +158,7 @@ int FFMpegVideoDecoder::HandleVideoSequence(RocdecVideoFormat *p_video_format) {
|
||||
max_width_ = p_video_format->coded_width;
|
||||
if (max_height_ < static_cast<int>(p_video_format->coded_height))
|
||||
max_height_ = p_video_format->coded_height;
|
||||
|
||||
|
||||
if (!(crop_rect_.right && crop_rect_.bottom)) {
|
||||
target_width_ = (disp_width_ + 1) & ~1;
|
||||
target_height_ = (disp_height_ + 1) & ~1;
|
||||
@@ -287,13 +166,12 @@ int FFMpegVideoDecoder::HandleVideoSequence(RocdecVideoFormat *p_video_format) {
|
||||
target_width_ = (crop_rect_.right - crop_rect_.left + 1) & ~1;
|
||||
target_height_ = (crop_rect_.bottom - crop_rect_.top + 1) & ~1;
|
||||
}
|
||||
|
||||
chroma_height_ = static_cast<int>(ceil(target_height_ * GetChromaHeightFactor(video_surface_format_)));
|
||||
chroma_width_ = static_cast<int>(ceil(target_width_ * GetChromaWidthFactor(video_surface_format_)));
|
||||
num_chroma_planes_ = GetChromaPlaneCount(video_surface_format_);
|
||||
if (video_chroma_format_ == rocDecVideoChromaFormat_Monochrome) num_chroma_planes_ = 0;
|
||||
surface_stride_ = target_width_ * byte_per_pixel_;
|
||||
chroma_vstride_ = static_cast<int>(ceil(surface_vstride_ * GetChromaHeightFactor(video_surface_format_)));
|
||||
|
||||
// fill output_surface_info_
|
||||
output_surface_info_.output_width = target_width_;
|
||||
output_surface_info_.output_height = target_height_;
|
||||
@@ -318,7 +196,6 @@ int FFMpegVideoDecoder::HandleVideoSequence(RocdecVideoFormat *p_video_format) {
|
||||
;
|
||||
input_video_info_str_ << std::endl;
|
||||
std::cout << input_video_info_str_.str();
|
||||
|
||||
double elapsed_time = StopTimer(start_time);
|
||||
AddDecoderSessionOverHead(std::this_thread::get_id(), elapsed_time);
|
||||
return num_decode_surfaces;
|
||||
@@ -359,20 +236,16 @@ int FFMpegVideoDecoder::ReconfigureDecoder(RocdecVideoFormat *p_video_format) {
|
||||
// clear the existing output buffers of different size
|
||||
// note that app lose the remaining frames in the vp_frames in case application didn't set p_fn_reconfigure_flush_ callback
|
||||
std::lock_guard<std::mutex> lock(mtx_vp_frame_);
|
||||
while(!vp_frames_ffmpeg_.empty()) {
|
||||
DecFrameBufferFFMpeg *p_frame = &vp_frames_ffmpeg_.back();
|
||||
while(!vp_frames_.empty()) {
|
||||
DecFrameBuffer *p_frame = &vp_frames_.back();
|
||||
// pop decoded frame
|
||||
vp_frames_ffmpeg_.pop_back();
|
||||
vp_frames_.pop_back();
|
||||
if (p_frame->frame_ptr) {
|
||||
if (out_mem_type_ == OUT_SURFACE_MEM_DEV_COPIED) {
|
||||
hipError_t hip_status = hipFree(p_frame->frame_ptr);
|
||||
if (hip_status != hipSuccess) std::cerr << "ERROR: hipFree failed! (" << hip_status << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
// release associated av_frame
|
||||
if (p_frame->av_frame_ptr) {
|
||||
av_frame_free(&p_frame->av_frame_ptr);
|
||||
}
|
||||
}
|
||||
output_frame_cnt_ = 0; // reset frame_count
|
||||
if (is_decode_res_changed) {
|
||||
@@ -402,7 +275,7 @@ int FFMpegVideoDecoder::ReconfigureDecoder(RocdecVideoFormat *p_video_format) {
|
||||
chroma_width_ = static_cast<int>(ceil(target_width_ * GetChromaWidthFactor(video_surface_format_)));
|
||||
num_chroma_planes_ = GetChromaPlaneCount(video_surface_format_);
|
||||
if (p_video_format->chroma_format == rocDecVideoChromaFormat_Monochrome) num_chroma_planes_ = 0;
|
||||
chroma_vstride_ = static_cast<int>(std::ceil(surface_vstride_ * GetChromaHeightFactor(video_surface_format_)));
|
||||
|
||||
// Fill output_surface_info_
|
||||
output_surface_info_.output_width = target_width_;
|
||||
output_surface_info_.output_height = target_height_;
|
||||
@@ -436,62 +309,6 @@ int FFMpegVideoDecoder::ReconfigureDecoder(RocdecVideoFormat *p_video_format) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param pPicParams
|
||||
* @return int 1: success 0: fail
|
||||
*/
|
||||
int FFMpegVideoDecoder::HandlePictureDecode(RocdecPicParams *pPicParams) {
|
||||
AVPacket *av_pkt = av_packets_[av_pkt_cnt_];
|
||||
std::pair<uint8_t *, int> *packet_data = &av_packet_data_[av_pkt_cnt_];
|
||||
if (last_packet_.payload_size > packet_data->second) {
|
||||
void *new_pkt_data = av_realloc(av_pkt->data, (last_packet_.payload_size + MAX_AV_PACKET_DATA_SIZE)); // add more to avoid frequence reallocation
|
||||
if (!new_pkt_data) {
|
||||
std::cerr << "ERROR: couldn't allocate packet data" << std::endl;
|
||||
}
|
||||
packet_data->first = static_cast<uint8_t *>(new_pkt_data);
|
||||
packet_data->second = (last_packet_.payload_size + MAX_AV_PACKET_DATA_SIZE);
|
||||
av_pkt->data = packet_data->first;
|
||||
}
|
||||
memcpy(av_pkt->data, last_packet_.payload, last_packet_.payload_size);
|
||||
av_pkt->size = last_packet_.payload_size;
|
||||
av_pkt->flags = 0;
|
||||
av_pkt->pts = last_packet_.pts;
|
||||
|
||||
if (no_multithreading_) {
|
||||
DecodeAvFrame(av_pkt, dec_frames_[av_frame_cnt_]);
|
||||
int num_frames_to_display = decoded_pic_cnt_;
|
||||
while (num_frames_to_display) {
|
||||
RocdecParserDispInfo dispInfo = {0}; // dispinfo is not used in ffmpeg decoder, so setting it to zero
|
||||
HandlePictureDisplay(&dispInfo);
|
||||
num_frames_to_display--;
|
||||
};
|
||||
if (!last_packet_.payload_size && !end_of_stream_) {
|
||||
AVPacket pkt = {0};
|
||||
DecodeAvFrame(&pkt, dec_frames_[av_frame_cnt_]);
|
||||
int num_frames_to_display = decoded_pic_cnt_;
|
||||
while (num_frames_to_display) {
|
||||
RocdecParserDispInfo dispInfo = {0}; // don't care about this as this will be igonored
|
||||
HandlePictureDisplay(&dispInfo);
|
||||
num_frames_to_display--;
|
||||
};
|
||||
}
|
||||
} else {
|
||||
//push packet into packet q for decoding
|
||||
PushPacket(av_pkt);
|
||||
if (!last_packet_.payload_size && !end_of_stream_) {
|
||||
AVPacket pkt = {0};
|
||||
PushPacket(&pkt);
|
||||
}
|
||||
}
|
||||
av_pkt_cnt_ = (av_pkt_cnt_ + 1) % av_packets_.size();
|
||||
if (!av_pkt->data || !av_pkt->size) {
|
||||
end_of_stream_ = true;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief function to handle display picture
|
||||
@@ -532,38 +349,22 @@ int FFMpegVideoDecoder::HandlePictureDisplay(RocdecParserDispInfo *pDispInfo) {
|
||||
sei_message_display_q_[pDispInfo->picture_index].sei_message = NULL; // to avoid double free
|
||||
}
|
||||
}
|
||||
// this will happen during PopFrame()
|
||||
AVFrame *p_av_frame = nullptr;
|
||||
if (no_multithreading_ ) {
|
||||
if (!av_frame_q_.empty()) {
|
||||
p_av_frame = av_frame_q_.front();
|
||||
av_frame_q_.pop();
|
||||
}
|
||||
} else {
|
||||
p_av_frame = PopFrame();
|
||||
}
|
||||
|
||||
if (p_av_frame == nullptr) {
|
||||
std::cerr << "Invalid avframe decode output" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
void* src_ptr[3] = {0};
|
||||
int32_t src_pitch[3] = {0};
|
||||
src_ptr[0] = p_av_frame->data[0];
|
||||
src_ptr[1] = p_av_frame->data[1];
|
||||
src_ptr[2] = p_av_frame->data[2];
|
||||
src_pitch[0] = p_av_frame->linesize[0];
|
||||
src_pitch[1] = p_av_frame->linesize[1];
|
||||
src_pitch[2] = p_av_frame->linesize[2];
|
||||
|
||||
RocdecParserDispInfo *p_disp_info = static_cast<RocdecParserDispInfo *>(pDispInfo);
|
||||
RocdecProcParams video_proc_params = {};
|
||||
video_proc_params.progressive_frame = p_disp_info->progressive_frame;
|
||||
video_proc_params.top_field_first = p_disp_info->top_field_first;
|
||||
void * src_ptr[3] = { 0 };
|
||||
uint32_t src_pitch[3] = { 0 };
|
||||
ROCDEC_API_CALL(rocDecGetVideoFrameHost(roc_decoder_, pDispInfo->picture_index, src_ptr, src_pitch, &video_proc_params));
|
||||
// copy the decoded surface info device or host
|
||||
uint8_t *p_dec_frame = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx_vp_frame_);
|
||||
// if not enough frames in stock, allocate
|
||||
if (++output_frame_cnt_ > vp_frames_ffmpeg_.size()) {
|
||||
if (++output_frame_cnt_ > vp_frames_.size()) {
|
||||
num_alloced_frames_++;
|
||||
DecFrameBufferFFMpeg dec_frame = {0};
|
||||
DecFrameBuffer dec_frame = {0};
|
||||
if (out_mem_type_ == OUT_SURFACE_MEM_DEV_COPIED) {
|
||||
// allocate device memory
|
||||
HIP_API_CALL(hipMalloc((void **)&dec_frame.frame_ptr, GetFrameSize()));
|
||||
@@ -571,12 +372,11 @@ int FFMpegVideoDecoder::HandlePictureDisplay(RocdecParserDispInfo *pDispInfo) {
|
||||
dec_frame.frame_ptr = new uint8_t[GetFrameSize()];
|
||||
}
|
||||
|
||||
dec_frame.av_frame_ptr = p_av_frame;
|
||||
dec_frame.pts = p_av_frame->pts;
|
||||
dec_frame.picture_index = -1; //picture_index is not used here since it is handled within FFMpeg decoder
|
||||
vp_frames_ffmpeg_.push_back(dec_frame);
|
||||
dec_frame.pts = pDispInfo->pts;
|
||||
dec_frame.picture_index = pDispInfo->picture_index; //picture_index is not used here since it is handled within FFMpeg decoder
|
||||
vp_frames_.push_back(dec_frame);
|
||||
}
|
||||
p_dec_frame = vp_frames_ffmpeg_[output_frame_cnt_ - 1].frame_ptr;
|
||||
p_dec_frame = vp_frames_[output_frame_cnt_ - 1].frame_ptr;
|
||||
}
|
||||
|
||||
// Copy luma data
|
||||
@@ -607,7 +407,7 @@ int FFMpegVideoDecoder::HandlePictureDisplay(RocdecParserDispInfo *pDispInfo) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Copy chroma plane ( )
|
||||
// Copy chroma plane/s
|
||||
// rocDec output gives pointer to luma and chroma pointers seperated for the decoded frame
|
||||
uint8_t *p_frame_uv = p_dec_frame + dst_pitch * disp_height_;
|
||||
uint8_t *p_src_ptr_uv = static_cast<uint8_t *>(src_ptr[1]) + ((disp_rect_.top + crop_rect_.top) >> 1) * src_pitch[1] + ((disp_rect_.left + crop_rect_.left)>>1) * byte_per_pixel_ ;
|
||||
@@ -669,22 +469,15 @@ int FFMpegVideoDecoder::HandlePictureDisplay(RocdecParserDispInfo *pDispInfo) {
|
||||
int FFMpegVideoDecoder::DecodeFrame(const uint8_t *data, size_t size, int pkt_flags, int64_t pts, int *num_decoded_pics) {
|
||||
output_frame_cnt_ = 0, output_frame_cnt_ret_ = 0;
|
||||
decoded_pic_cnt_ = 0;
|
||||
last_packet_ = {0};
|
||||
last_packet_.payload = data;
|
||||
last_packet_.payload_size = size;
|
||||
last_packet_.flags = pkt_flags | ROCDEC_PKT_TIMESTAMP;
|
||||
last_packet_.pts = pts;
|
||||
RocdecPicParamsHost pic_params = {};
|
||||
pic_params.bitstream_data_len = size;
|
||||
pic_params.bitstream_data = data;
|
||||
if (!data || size == 0) {
|
||||
last_packet_.flags |= ROCDEC_PKT_ENDOFSTREAM;
|
||||
pic_params.flags = ROCDEC_PKT_ENDOFPICTURE; // mark end_of_picture flag for last frame
|
||||
}
|
||||
ROCDEC_API_CALL(rocDecParseVideoData(rocdec_parser_, &last_packet_));
|
||||
if (last_packet_.flags & ROCDEC_PKT_ENDOFSTREAM) {
|
||||
// flush last packet and let FFMpeg decode last frames
|
||||
FlushDecoder();
|
||||
}
|
||||
|
||||
ROCDEC_API_CALL(rocDecDecodeFrameHost(roc_decoder_, &pic_params));
|
||||
if (num_decoded_pics) {
|
||||
*num_decoded_pics = decoded_pic_cnt_;
|
||||
*num_decoded_pics = output_frame_cnt_;
|
||||
}
|
||||
return output_frame_cnt_;
|
||||
}
|
||||
@@ -693,10 +486,10 @@ int FFMpegVideoDecoder::DecodeFrame(const uint8_t *data, size_t size, int pkt_fl
|
||||
uint8_t* FFMpegVideoDecoder::GetFrame(int64_t *pts) {
|
||||
if (output_frame_cnt_ > 0) {
|
||||
std::lock_guard<std::mutex> lock(mtx_vp_frame_);
|
||||
if (vp_frames_ffmpeg_.size() > 0){
|
||||
if (vp_frames_.size() > 0){
|
||||
output_frame_cnt_--;
|
||||
if (pts) *pts = vp_frames_ffmpeg_[output_frame_cnt_ret_].pts;
|
||||
return vp_frames_ffmpeg_[output_frame_cnt_ret_++].frame_ptr;
|
||||
if (pts) *pts = vp_frames_[output_frame_cnt_ret_].pts;
|
||||
return vp_frames_[output_frame_cnt_ret_++].frame_ptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -704,116 +497,21 @@ uint8_t* FFMpegVideoDecoder::GetFrame(int64_t *pts) {
|
||||
|
||||
bool FFMpegVideoDecoder::ReleaseFrame(int64_t pTimestamp, bool b_flushing) {
|
||||
// if not flushing the buffers are re-used, so keep them
|
||||
if (out_mem_type_ == OUT_SURFACE_MEM_NOT_MAPPED || !b_flushing)
|
||||
return true; // nothing to do
|
||||
if (!b_flushing)
|
||||
return true;
|
||||
else {
|
||||
// remove frames in flushing mode
|
||||
std::lock_guard<std::mutex> lock(mtx_vp_frame_);
|
||||
DecFrameBufferFFMpeg *fb = &vp_frames_ffmpeg_[0];
|
||||
DecFrameBuffer *fb = &vp_frames_[0];
|
||||
if (pTimestamp != fb->pts) {
|
||||
std::cerr << "Decoded Frame is released out of order" << std::endl;
|
||||
return false;
|
||||
}
|
||||
av_frame_free(&fb->av_frame_ptr);
|
||||
vp_frames_ffmpeg_.erase(vp_frames_ffmpeg_.begin()); // get rid of the frames from the framestore
|
||||
vp_frames_.erase(vp_frames_.begin()); // get rid of the frames from the framestore
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void FFMpegVideoDecoder::InitOutputFrameInfo(AVFrame *p_frame) {
|
||||
|
||||
video_surface_format_ = AVPixelFormat2rocDecVideoSurfaceFormat((AVPixelFormat)p_frame->format);
|
||||
surface_stride_ = target_width_ * byte_per_pixel_;
|
||||
chroma_width_ = static_cast<int>(ceil(target_width_ * GetChromaWidthFactor(video_surface_format_)));
|
||||
chroma_height_ = static_cast<int>(ceil(target_height_ * GetChromaHeightFactor(video_surface_format_)));
|
||||
num_chroma_planes_ = GetChromaPlaneCount(video_surface_format_);
|
||||
// Fill output_surface_info_
|
||||
output_surface_info_.output_width = target_width_;
|
||||
output_surface_info_.output_height = target_height_;
|
||||
output_surface_info_.output_pitch = surface_stride_;
|
||||
output_surface_info_.output_vstride = target_height_;
|
||||
output_surface_info_.bit_depth = bitdepth_minus_8_ + 8;
|
||||
output_surface_info_.bytes_per_pixel = byte_per_pixel_;
|
||||
output_surface_info_.surface_format = video_surface_format_;
|
||||
output_surface_info_.num_chroma_planes = num_chroma_planes_;
|
||||
if (out_mem_type_ == OUT_SURFACE_MEM_DEV_COPIED) {
|
||||
output_surface_info_.output_surface_size_in_bytes = GetFrameSize();
|
||||
output_surface_info_.mem_type = OUT_SURFACE_MEM_DEV_COPIED;
|
||||
} else if (out_mem_type_ == OUT_SURFACE_MEM_HOST_COPIED) {
|
||||
output_surface_info_.output_surface_size_in_bytes = GetFrameSize();
|
||||
output_surface_info_.mem_type = OUT_SURFACE_MEM_HOST_COPIED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Flush decoder with decoding of last frames
|
||||
*
|
||||
* @return int 1: success 0: fail
|
||||
*/
|
||||
int FFMpegVideoDecoder::FlushDecoder() {
|
||||
AVPacket pkt = {0};
|
||||
if (no_multithreading_) {
|
||||
DecodeAvFrame(&pkt, dec_frames_[av_frame_cnt_]);
|
||||
int num_frames_to_display = decoded_pic_cnt_;
|
||||
while (num_frames_to_display) {
|
||||
RocdecParserDispInfo dispInfo = {0}; // don't care about this as this will be igonored
|
||||
HandlePictureDisplay(&dispInfo);
|
||||
num_frames_to_display--;
|
||||
};
|
||||
|
||||
} else {
|
||||
//push packet into packet q for decoding
|
||||
PushPacket(&pkt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void FFMpegVideoDecoder::DecodeThread()
|
||||
{
|
||||
AVPacket *pkt;
|
||||
do {
|
||||
pkt = PopPacket();
|
||||
DecodeAvFrame(pkt, dec_frames_[av_frame_cnt_]);
|
||||
} while (!end_of_stream_);
|
||||
}
|
||||
|
||||
int FFMpegVideoDecoder::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) {
|
||||
std::cout << "Error sending av packet for decoding: status: " << status << std::endl;
|
||||
}
|
||||
while (status >= 0) {
|
||||
status = avcodec_receive_frame(dec_context_, p_frame);
|
||||
if (status == AVERROR(EAGAIN) || status == AVERROR_EOF) {
|
||||
end_of_stream_ = (status == AVERROR_EOF);
|
||||
return 0;
|
||||
}
|
||||
else if (status < 0) {
|
||||
std::cout << "Error during decoding" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
// for the first frame, initialize OutputsurfaceInfo
|
||||
if (!b_decoder_initialized) {
|
||||
InitOutputFrameInfo(p_frame);
|
||||
b_decoder_initialized = true;
|
||||
}
|
||||
decoded_pic_cnt_++;
|
||||
if (no_multithreading_)
|
||||
av_frame_q_.push(p_frame);
|
||||
else
|
||||
PushFrame(p_frame); // add frame to the frame_q
|
||||
av_frame_cnt_ = (av_frame_cnt_ + 1) % dec_frames_.size();
|
||||
p_frame = dec_frames_[av_frame_cnt_]; //advance for next frame decode
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void FFMpegVideoDecoder::SaveFrameToFile(std::string output_file_name, void *surf_mem, OutputSurfaceInfo *surf_info, size_t rgb_image_size) {
|
||||
uint8_t *hst_ptr = nullptr;
|
||||
bool is_rgb = (rgb_image_size != 0);
|
||||
|
||||
@@ -31,28 +31,11 @@ extern "C" {
|
||||
#endif
|
||||
}
|
||||
#include "rocvideodecode/roc_video_dec.h" // for derived class
|
||||
#include "rocdecode/rocdecode_host.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <queue>
|
||||
#include <atomic>
|
||||
|
||||
|
||||
#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/device 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;
|
||||
|
||||
/**
|
||||
* FFMpegVideoDecoder: Derived class for FFMpeg based host decoder
|
||||
*/
|
||||
class FFMpegVideoDecoder: public RocVideoDecoder {
|
||||
public:
|
||||
/**
|
||||
@@ -71,7 +54,7 @@ class FFMpegVideoDecoder: public RocVideoDecoder {
|
||||
* @param no_multithreading : run FFMpeg decoder in the main thread (no multithreading)
|
||||
*/
|
||||
FFMpegVideoDecoder(int num_threads, OutputSurfaceMemoryType out_mem_type, rocDecVideoCodec codec, bool force_zero_latency = false,
|
||||
const Rect *p_crop_rect = nullptr, bool extract_user_SEI_Message = false, uint32_t disp_delay = 0, bool no_multithreading = false, int max_width = 0, int max_height = 0,
|
||||
const Rect *p_crop_rect = nullptr, bool extract_user_SEI_Message = false, uint32_t disp_delay = 0, int max_width = 0, int max_height = 0,
|
||||
uint32_t clk_rate = 1000);
|
||||
/**
|
||||
* @brief destructor
|
||||
@@ -126,12 +109,7 @@ class FFMpegVideoDecoder: public RocVideoDecoder {
|
||||
/**
|
||||
* @brief Callback function to be registered for getting a callback when decoding of sequence starts
|
||||
*/
|
||||
static int ROCDECAPI FFMpegHandleVideoSequenceProc(void *p_user_data, RocdecVideoFormat *p_video_format) { return ((FFMpegVideoDecoder *)p_user_data)->HandleVideoSequence(p_video_format); }
|
||||
|
||||
/**
|
||||
* @brief Callback function to be registered for getting a callback when a decoded frame is ready to be decoded
|
||||
*/
|
||||
static int ROCDECAPI FFMpegHandlePictureDecodeProc(void *p_user_data, RocdecPicParams *p_pic_params) { return ((FFMpegVideoDecoder *)p_user_data)->HandlePictureDecode(p_pic_params); }
|
||||
static int ROCDECAPI FFMpegHandleVideoSequenceProc(void *p_user_data, RocdecVideoFormatHost *p_video_format) { return ((FFMpegVideoDecoder *)p_user_data)->HandleVideoSequence(p_video_format); }
|
||||
|
||||
/**
|
||||
* @brief Callback function to be registered for getting a callback when a decoded frame is available for display
|
||||
@@ -147,13 +125,7 @@ class FFMpegVideoDecoder: public RocVideoDecoder {
|
||||
* @brief This function gets called when a sequence is ready to be decoded. The function also gets called
|
||||
when there is format change
|
||||
*/
|
||||
int HandleVideoSequence(RocdecVideoFormat *p_video_format);
|
||||
|
||||
/**
|
||||
* @brief This function gets called when a picture is ready to be decoded. rocDecDecodeFrame is called from this function
|
||||
* to decode the picture
|
||||
*/
|
||||
int HandlePictureDecode(RocdecPicParams *p_pic_params);
|
||||
int HandleVideoSequence(RocdecVideoFormatHost *p_video_format);
|
||||
|
||||
/**
|
||||
* @brief This function gets called after a picture is decoded and available for display. Frames are fetched and stored in
|
||||
@@ -171,72 +143,4 @@ class FFMpegVideoDecoder: public RocVideoDecoder {
|
||||
*/
|
||||
int ReconfigureDecoder(RocdecVideoFormat *p_video_format);
|
||||
|
||||
void DecodeThread();
|
||||
int DecodeAvFrame(AVPacket *av_pkt, AVFrame *p_frame);
|
||||
void InitOutputFrameInfo(AVFrame *p_frame);
|
||||
int FlushDecoder();
|
||||
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;
|
||||
}
|
||||
|
||||
void PushFrame(AVFrame *av_frame) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx_frame_q_);
|
||||
av_frame_q_.push(av_frame);
|
||||
}
|
||||
cv_frame_.notify_one();
|
||||
};
|
||||
|
||||
AVFrame *PopFrame() {
|
||||
std::unique_lock<std::mutex> lock(mtx_frame_q_);
|
||||
cv_frame_.wait(lock, [&] { return !av_frame_q_.empty() || end_of_stream_; });
|
||||
if (end_of_stream_ && av_frame_q_.empty())
|
||||
return nullptr;
|
||||
AVFrame *p_frame = av_frame_q_.front();
|
||||
av_frame_q_.pop();
|
||||
return p_frame;
|
||||
}
|
||||
|
||||
typedef enum { CMD_ABORT, CMD_DECODE } CommandType;
|
||||
typedef enum { STATUS_SUCCESS = 0, STATUS_FAILURE = -1 } StatusType;
|
||||
|
||||
bool no_multithreading_ = false;
|
||||
bool b_decoder_initialized = false;
|
||||
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<AVFrame *> av_frame_q_;
|
||||
std::vector<DecFrameBufferFFMpeg> vp_frames_ffmpeg_; // 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 command and status
|
||||
std::condition_variable cv_pkt_, cv_frame_; //for command and status
|
||||
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;
|
||||
AVStream *video = nullptr;
|
||||
};
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする