Added the bit stream reader feature. (#433)
* * rocDecode/ES parser: Added elementary stream file parser for HEVC and AVC. * * rocDecode/ES parser: Added elementary stream file parser for AV1. Also cleaned up the bitstream ring buffer code. * * rocDecode/ES parser: Added the IVF container file parser for AV1. Also fixed a bug in fill ring buffer function. * * rocDecode/ES file parder: Added supported stream type detection. - The stream type detection checks the unique syntax patterns of the stream type and calculate the likeliheed score. Based on the score, the most likely type is determined. - The current supported stream types are: AVC/HEVC/AV1 elementary streams, IVF AV1 streams. * * rocDecode/ES file parser: Fixed an AVC decode regression due to a copy and paste error. * * rocDecode/ES file parser: Added bit depth parsing for codec support check; Added stronger AV1 detection for IVF AV1 stream type. * * rocDecode/ES file parser: Removed debugging logs. * * rocDecode/ES file parser: Added exmaple code to use the built-in file parser. * * rocDecode/Bitstream reader: Renamed the elementary parser feature to bitstream reader and re-organized the code. - Moved the bitstream reader code to rocDecode core lib from utility. - Added bitstream reader interface in parallel with rocDecode parser and decoder interfaces. * * rocDecode/Bitstream reader: Added sample to use bitstream reader, instead of FFMPEG demuxer, to get picture data. Also reverted the original sample app back to using FFMPEG demuxer only. * * rocDecode/Bitstream reader: Renamed the new sample app. * * rocDecode/Bitstream reader: FFMPEG dependency reduction. - Moved MD5 functions out of RocVideoDecoder utility class. This removed RocVideoDecoder's dependency on FFMPEG. - Added the new MD5 utility, which depends on FFMPEG lib. MD5 message digest generation is now performed in the MD5 utility. - Modified decode sampples that uses MD5 generation function. - Removed FFMPEG dependency from video decoder basic sample. * * rocDecode/Bitstream reader: Added option to use bitstream reader to video decode sample and conformance test script. Added the missing destroy bitstream reader call in video decode basic sample. * * rocDecode/Bitstream reader: Minor format change. No functional changes. * * rocDecode/Bitstream reader: Added handling of unsupported stream file type by the bitstream reader to decode sample apps. * * rocDecode/Bitstream reader: Fixed build errors of several samples. * * rocDecode/Bitstream reader: Added changes based on review comments. * * rocDecode/Bitstream reader: File name changes based on review comments. * * rocDecode/Bitstream reader: Moved MD5 code into single header file. Added changes based on review comments. * * rocDecode/Bitstream reader: Removed redundant path. * * rocDecode/Bitstream reader: Changed rocDecode version to 0.10.0. Added minor changes based on review comments. --------- Co-authored-by: Kiriti Gowda <kiritigowda@gmail.com>
Bu işleme şunda yer alıyor:
işlemeyi yapan:
GitHub
ebeveyn
52eb62fabf
işleme
e62aa3e09b
@@ -2,6 +2,37 @@
|
||||
|
||||
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/)
|
||||
|
||||
## (Unreleased) rocDecode 0.10.0
|
||||
|
||||
### Added
|
||||
|
||||
* The new bitstream reader feature. The bitstream reader contains a few built-in stream file parsers, including elementary stream file parser and IVF container file parser. Currently the reader can parse AVC, HEVC and AV1 elementary stream files and AV1 IVF container files. More format support will be added in the future.
|
||||
* A new sample app, called videodecoderaw which uses the bitstream reader instead of FFMPEG demuxer to get picture data.
|
||||
|
||||
### Changed
|
||||
|
||||
* Moved MD5 code out of roc video decode utility.
|
||||
|
||||
### Removed
|
||||
|
||||
*
|
||||
|
||||
### Resolved issues
|
||||
|
||||
*
|
||||
|
||||
### Tested configurations
|
||||
|
||||
* Linux
|
||||
* Ubuntu - `22.04` / `24.04`
|
||||
* RHEL - `8` / `9`
|
||||
* SLES - `15 SP5`
|
||||
* ROCm: `6.3.0`
|
||||
* libva-amdgpu-dev - `2.16.0`
|
||||
* mesa-amdgpu-va-drivers - `1:24.3.0`
|
||||
* FFmpeg - `4.4.2` / `6.1.1`
|
||||
* rocDecode Setup Script - `V2.4.0`
|
||||
|
||||
## (Unreleased) rocDecode 0.9.0
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -38,7 +38,7 @@ if (NOT DEFINED CMAKE_CXX_COMPILER)
|
||||
endif()
|
||||
|
||||
# NOTE: Match version with api/rocdecode_version.h
|
||||
set(VERSION "0.9.0")
|
||||
set(VERSION "0.10.0")
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Set Project Version and Language
|
||||
@@ -162,7 +162,7 @@ if(HIP_FOUND AND Libva_FOUND)
|
||||
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev NAMELINK_ONLY)
|
||||
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT asan)
|
||||
# install rocDecode include files -- {ROCM_PATH}/include/rocdecode
|
||||
install(FILES api/rocdecode.h api/rocparser.h api/rocdecode_version.h
|
||||
install(FILES api/rocdecode.h api/rocparser.h api/roc_bitstream_reader.h api/rocdecode_version.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} COMPONENT dev)
|
||||
# install rocDecode api trace include file -- {ROCM_PATH}/include/rocdecode/amd_detail
|
||||
install(FILES api/amd_detail/rocdecode_api_trace.h
|
||||
@@ -178,6 +178,7 @@ if(HIP_FOUND AND Libva_FOUND)
|
||||
install(FILES samples/videoDecodeRGB/CMakeLists.txt samples/videoDecodeRGB/README.md samples/videoDecodeRGB/videodecrgb.cpp DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/samples/videoDecodeRGB COMPONENT dev)
|
||||
install(FILES samples/videoDecodeBatch/CMakeLists.txt samples/videoDecodeBatch/README.md samples/videoDecodeBatch/videodecodebatch.cpp DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/samples/videoDecodeBatch COMPONENT dev)
|
||||
install(FILES samples/common.h DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/samples COMPONENT dev)
|
||||
install(FILES utils/md5.h DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/utils COMPONENT dev)
|
||||
install(FILES utils/video_demuxer.h DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/utils COMPONENT dev)
|
||||
install(FILES utils/colorspace_kernels.cpp DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/utils COMPONENT dev)
|
||||
install(FILES utils/colorspace_kernels.h DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/utils COMPONENT dev)
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2024 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 "rocdecode.h"
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief The AMD rocBitstreamReader Library.
|
||||
*
|
||||
* \defgroup group_roc_bitstream_reader rocDecode Parser: AMD ROCm Video Bitstream Reader API
|
||||
* \brief AMD The rocBitstreamReader is a toolkit to read picture data from bitstream files for decoding on AMD’s GPUs.
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*********************************************************************************/
|
||||
//! HANDLE of rocBitstreamReader
|
||||
//! Used in subsequent API calls after rocDecCreateBitstreamReader
|
||||
/*********************************************************************************/
|
||||
typedef void *RocdecBitstreamReader;
|
||||
|
||||
/************************************************************************************************/
|
||||
//! \ingroup group_roc_bitstream_reader
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecCreateBitstreamReader(RocdecBitstreamReader *bs_reader_handle, const char *input_file_path)
|
||||
//! Create video bitstream reader object and initialize
|
||||
/************************************************************************************************/
|
||||
extern rocDecStatus ROCDECAPI rocDecCreateBitstreamReader(RocdecBitstreamReader *bs_reader_handle, const char *input_file_path);
|
||||
|
||||
/************************************************************************************************/
|
||||
//! \ingroup group_roc_bitstream_reader
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecGetBitstreamCodecType(RocdecBitstreamReader bs_reader_handle, rocDecVideoCodec *codec_type)
|
||||
//! Get the codec type of the bitstream
|
||||
/************************************************************************************************/
|
||||
extern rocDecStatus ROCDECAPI rocDecGetBitstreamCodecType(RocdecBitstreamReader bs_reader_handle, rocDecVideoCodec *codec_type);
|
||||
|
||||
/************************************************************************************************/
|
||||
//! \ingroup group_roc_bitstream_reader
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecGetBitstreamBitDepth(RocdecBitstreamReader bs_reader_handle, int *bit_depth)
|
||||
//! Get the bit depth of the bitstream
|
||||
/************************************************************************************************/
|
||||
extern rocDecStatus ROCDECAPI rocDecGetBitstreamBitDepth(RocdecBitstreamReader bs_reader_handle, int *bit_depth);
|
||||
|
||||
/************************************************************************************************/
|
||||
//! \ingroup group_roc_bitstream_reader
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecGetBitstreamPicData(RocdecBitstreamReader bs_reader_handle, uint8_t **pic_data, int *pic_size, int64_t *pts)
|
||||
//! Read one unit of picture data from the bitstream. The unit can be a frame or field for AVC/HEVC,
|
||||
//! a temporal unit for AV1, or a frame (including superframe) for VP9. The picture data unit is pointed
|
||||
//! by pic_data. The size of the unit is specified by pic_size. The presentation time stamp, if available,
|
||||
//! is given by pts.
|
||||
/************************************************************************************************/
|
||||
extern rocDecStatus ROCDECAPI rocDecGetBitstreamPicData(RocdecBitstreamReader bs_reader_handle, uint8_t **pic_data, int *pic_size, int64_t *pts);
|
||||
|
||||
/************************************************************************************************/
|
||||
//! \ingroup group_roc_bitstream_reader
|
||||
//! \fn rocDecStatus ROCDECAPI rocDecDestroyBitstreamReader(RocdecBitstreamReader bs_reader_handle)
|
||||
//! Destroy the video parser object
|
||||
/************************************************************************************************/
|
||||
extern rocDecStatus ROCDECAPI rocDecDestroyBitstreamReader(RocdecBitstreamReader bs_reader_handle);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
@@ -35,7 +35,7 @@ extern "C" {
|
||||
#endif
|
||||
/* NOTE: Match version with CMakeLists.txt */
|
||||
#define ROCDECODE_MAJOR_VERSION 0
|
||||
#define ROCDECODE_MINOR_VERSION 9
|
||||
#define ROCDECODE_MINOR_VERSION 10
|
||||
#define ROCDECODE_MICRO_VERSION 0
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ THE SOFTWARE.
|
||||
#pragma once
|
||||
|
||||
#include "roc_video_dec.h"
|
||||
#include "md5.h"
|
||||
|
||||
typedef enum ReconfigFlushMode_enum {
|
||||
RECONFIG_FLUSH_MODE_NONE = 0, /**< Just flush to get the frame count */
|
||||
@@ -34,6 +35,7 @@ typedef enum ReconfigFlushMode_enum {
|
||||
typedef struct ReconfigDumpFileStruct_t {
|
||||
bool b_dump_frames_to_file;
|
||||
std::string output_file_name;
|
||||
void *md5_generator_handle;
|
||||
} ReconfigDumpFileStruct;
|
||||
|
||||
|
||||
@@ -53,13 +55,14 @@ int ReconfigureFlushCallback(void *p_viddec_obj, uint32_t flush_mode, void *p_us
|
||||
int64_t pts;
|
||||
while ((pframe = viddec->GetFrame(&pts))) {
|
||||
if (flush_mode != RECONFIG_FLUSH_MODE_NONE) {
|
||||
ReconfigDumpFileStruct *p_dump_file_struct = static_cast<ReconfigDumpFileStruct *>(p_user_struct);
|
||||
if (flush_mode == ReconfigFlushMode::RECONFIG_FLUSH_MODE_DUMP_TO_FILE) {
|
||||
ReconfigDumpFileStruct *p_dump_file_struct = static_cast<ReconfigDumpFileStruct *>(p_user_struct);
|
||||
if (p_dump_file_struct->b_dump_frames_to_file) {
|
||||
viddec->SaveFrameToFile(p_dump_file_struct->output_file_name, pframe, surf_info);
|
||||
}
|
||||
} else if (flush_mode == ReconfigFlushMode::RECONFIG_FLUSH_MODE_CALCULATE_MD5) {
|
||||
viddec->UpdateMd5ForFrame(pframe, surf_info);
|
||||
MD5Generator *md5_generator = static_cast<MD5Generator*>(p_dump_file_struct->md5_generator_handle);
|
||||
md5_generator->UpdateMd5ForFrame(pframe, surf_info);
|
||||
}
|
||||
}
|
||||
// release and flush frame
|
||||
|
||||
@@ -38,4 +38,5 @@ make -j
|
||||
-md5_check MD5_File_Path <generate MD5 message digest on the decoded YUV image sequence and compare to the reference MD5 string in a file [optional]>
|
||||
-crop <crop rectangle for output (not used when using interopped decoded frame) [optional - default: 0,0,0,0]>
|
||||
-m <output_surface_memory_type - decoded surface memory [optional - default: 0][0 : OUT_SURFACE_MEM_DEV_INTERNAL/ 1 : OUT_SURFACE_MEM_DEV_COPIED/ 2 : OUT_SURFACE_MEM_HOST_COPIED/3 : OUT_SURFACE_MEM_NOT_MAPPED]>
|
||||
-no_ffmpeg_demux <use the built-in bitstream reader instead of FFMPEG demuxer to obtain picture data [optional]>
|
||||
```
|
||||
@@ -37,6 +37,7 @@ THE SOFTWARE.
|
||||
#include <experimental/filesystem>
|
||||
#endif
|
||||
#include "video_demuxer.h"
|
||||
#include "roc_bitstream_reader.h"
|
||||
#include "roc_video_dec.h"
|
||||
#include "ffmpeg_video_dec.h"
|
||||
#include "common.h"
|
||||
@@ -59,7 +60,8 @@ void ShowHelpAndExit(const char *option = NULL) {
|
||||
<< "-seek_criteria - Demux seek criteria & value - optional; default - 0,0; "
|
||||
<< "[0: no seek; 1: SEEK_CRITERIA_FRAME_NUM, frame number; 2: SEEK_CRITERIA_TIME_STAMP, frame number (time calculated internally)]" << std::endl
|
||||
<< "-seek_mode - Seek to previous key frame or exact - optional; default - 0"
|
||||
<< "[0: SEEK_MODE_PREV_KEY_FRAME; 1: SEEK_MODE_EXACT_FRAME]" << std::endl;
|
||||
<< "[0: SEEK_MODE_PREV_KEY_FRAME; 1: SEEK_MODE_EXACT_FRAME]" << std::endl
|
||||
<< "-no_ffmpeg_demux - use the built-in bitstream reader instead of FFMPEG demuxer to obtain picture data; optional." << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -85,6 +87,7 @@ int main(int argc, char **argv) {
|
||||
// seek options
|
||||
uint64_t seek_to_frame = 0;
|
||||
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
|
||||
if(argc <= 1) {
|
||||
@@ -207,6 +210,13 @@ int main(int argc, char **argv) {
|
||||
ShowHelpAndExit("-seek_mode");
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-no_ffmpeg_demux")) {
|
||||
if (i == argc) {
|
||||
ShowHelpAndExit("-no_ffmpeg_demux");
|
||||
}
|
||||
b_use_ffmpeg_demuxer = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
ShowHelpAndExit(argv[i]);
|
||||
}
|
||||
@@ -214,10 +224,38 @@ int main(int argc, char **argv) {
|
||||
try {
|
||||
std::size_t found_file = input_file_path.find_last_of('/');
|
||||
std::cout << "info: Input file: " << input_file_path.substr(found_file + 1) << std::endl;
|
||||
VideoDemuxer *demuxer;
|
||||
RocdecBitstreamReader bs_reader = nullptr;
|
||||
rocDecVideoCodec rocdec_codec_id;
|
||||
int bit_depth;
|
||||
|
||||
if (b_use_ffmpeg_demuxer) {
|
||||
std::cout << "info: Using FFMPEG demuxer" << std::endl;
|
||||
demuxer = new VideoDemuxer(input_file_path.c_str());
|
||||
rocdec_codec_id = AVCodec2RocDecVideoCodec(demuxer->GetCodecID());
|
||||
bit_depth = demuxer->GetBitDepth();
|
||||
} else {
|
||||
std::cout << "info: Using built-in bitstream reader" << std::endl;
|
||||
if (rocDecCreateBitstreamReader(&bs_reader, input_file_path.c_str()) != ROCDEC_SUCCESS) {
|
||||
std::cerr << "Failed to create the bitstream reader." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (rocDecGetBitstreamCodecType(bs_reader, &rocdec_codec_id) != ROCDEC_SUCCESS) {
|
||||
std::cerr << "Failed to get stream codec type." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (rocdec_codec_id >= rocDecVideoCodec_NumCodecs) {
|
||||
std::cerr << "Unsupported stream file type or codec type by the bitstream reader. Exiting." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (rocDecGetBitstreamBitDepth(bs_reader, &bit_depth) != ROCDEC_SUCCESS) {
|
||||
std::cerr << "Failed to get stream bit depth." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
RocVideoDecoder *viddec;
|
||||
VideoDemuxer demuxer(input_file_path.c_str());
|
||||
VideoSeekContext video_seek_ctx;
|
||||
rocDecVideoCodec rocdec_codec_id = AVCodec2RocDecVideoCodec(demuxer.GetCodecID());
|
||||
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 {
|
||||
@@ -230,10 +268,10 @@ int main(int argc, char **argv) {
|
||||
viddec = new FFMpegVideoDecoder(device_id, mem_type, rocdec_codec_id, b_force_zero_latency, p_crop_rect, b_extract_sei_messages, disp_delay, true);
|
||||
}
|
||||
|
||||
if(!viddec->CodecSupported(device_id, rocdec_codec_id, demuxer.GetBitDepth())) {
|
||||
if(!viddec->CodecSupported(device_id, rocdec_codec_id, bit_depth)) {
|
||||
std::cerr << "rocDecode doesn't support codec!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
std::string device_name, gcn_arch_name;
|
||||
int pci_bus_id, pci_domain_id, pci_device_id;
|
||||
|
||||
@@ -253,6 +291,8 @@ int main(int argc, char **argv) {
|
||||
uint32_t width, height;
|
||||
double total_dec_time = 0;
|
||||
bool first_frame = true;
|
||||
MD5Generator *md5_generator = nullptr;
|
||||
|
||||
// initialize reconfigure params: the following is configured to dump to output which is relevant for this sample
|
||||
reconfig_params.p_fn_reconfigure_flush = ReconfigureFlushCallback;
|
||||
reconfig_user_struct.b_dump_frames_to_file = dump_output_frames;
|
||||
@@ -267,32 +307,41 @@ int main(int argc, char **argv) {
|
||||
reconfig_params.p_reconfig_user_struct = &reconfig_user_struct;
|
||||
|
||||
if (b_generate_md5) {
|
||||
viddec->InitMd5();
|
||||
md5_generator = new MD5Generator();
|
||||
md5_generator->InitMd5();
|
||||
reconfig_user_struct.md5_generator_handle = static_cast<void*>(md5_generator);
|
||||
}
|
||||
viddec->SetReconfigParams(&reconfig_params);
|
||||
|
||||
do {
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
if (seek_criteria == 1 && first_frame) {
|
||||
// use VideoSeekContext class to seek to given frame number
|
||||
video_seek_ctx.seek_frame_ = seek_to_frame;
|
||||
video_seek_ctx.seek_crit_ = SEEK_CRITERIA_FRAME_NUM;
|
||||
video_seek_ctx.seek_mode_ = (seek_mode ? SEEK_MODE_EXACT_FRAME : SEEK_MODE_PREV_KEY_FRAME);
|
||||
demuxer.Seek(video_seek_ctx, &pvideo, &n_video_bytes);
|
||||
pts = video_seek_ctx.out_frame_pts_;
|
||||
std::cout << "info: Number of frames that were decoded during seek - " << video_seek_ctx.num_frames_decoded_ << std::endl;
|
||||
first_frame = false;
|
||||
} else if (seek_criteria == 2 && first_frame) {
|
||||
// use VideoSeekContext class to seek to given timestamp
|
||||
video_seek_ctx.seek_frame_ = seek_to_frame;
|
||||
video_seek_ctx.seek_crit_ = SEEK_CRITERIA_TIME_STAMP;
|
||||
video_seek_ctx.seek_mode_ = (seek_mode ? SEEK_MODE_EXACT_FRAME : SEEK_MODE_PREV_KEY_FRAME);
|
||||
demuxer.Seek(video_seek_ctx, &pvideo, &n_video_bytes);
|
||||
pts = video_seek_ctx.out_frame_pts_;
|
||||
std::cout << "info: Duration of frame found after seek - " << video_seek_ctx.out_frame_duration_ << " ms" << std::endl;
|
||||
first_frame = false;
|
||||
if (b_use_ffmpeg_demuxer) {
|
||||
if (seek_criteria == 1 && first_frame) {
|
||||
// use VideoSeekContext class to seek to given frame number
|
||||
video_seek_ctx.seek_frame_ = seek_to_frame;
|
||||
video_seek_ctx.seek_crit_ = SEEK_CRITERIA_FRAME_NUM;
|
||||
video_seek_ctx.seek_mode_ = (seek_mode ? SEEK_MODE_EXACT_FRAME : SEEK_MODE_PREV_KEY_FRAME);
|
||||
demuxer->Seek(video_seek_ctx, &pvideo, &n_video_bytes);
|
||||
pts = video_seek_ctx.out_frame_pts_;
|
||||
std::cout << "info: Number of frames that were decoded during seek - " << video_seek_ctx.num_frames_decoded_ << std::endl;
|
||||
first_frame = false;
|
||||
} else if (seek_criteria == 2 && first_frame) {
|
||||
// use VideoSeekContext class to seek to given timestamp
|
||||
video_seek_ctx.seek_frame_ = seek_to_frame;
|
||||
video_seek_ctx.seek_crit_ = SEEK_CRITERIA_TIME_STAMP;
|
||||
video_seek_ctx.seek_mode_ = (seek_mode ? SEEK_MODE_EXACT_FRAME : SEEK_MODE_PREV_KEY_FRAME);
|
||||
demuxer->Seek(video_seek_ctx, &pvideo, &n_video_bytes);
|
||||
pts = video_seek_ctx.out_frame_pts_;
|
||||
std::cout << "info: Duration of frame found after seek - " << video_seek_ctx.out_frame_duration_ << " ms" << std::endl;
|
||||
first_frame = false;
|
||||
} else {
|
||||
demuxer->Demux(&pvideo, &n_video_bytes, &pts);
|
||||
}
|
||||
} else {
|
||||
demuxer.Demux(&pvideo, &n_video_bytes, &pts);
|
||||
if (rocDecGetBitstreamPicData(bs_reader, &pvideo, &n_video_bytes, &pts) != ROCDEC_SUCCESS) {
|
||||
std::cerr << "Failed to get picture data." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// Treat 0 bitstream size as end of stream indicator
|
||||
if (n_video_bytes == 0) {
|
||||
@@ -307,7 +356,7 @@ int main(int argc, char **argv) {
|
||||
for (int i = 0; i < n_frame_returned; i++) {
|
||||
pframe = viddec->GetFrame(&pts);
|
||||
if (b_generate_md5) {
|
||||
viddec->UpdateMd5ForFrame(pframe, surf_info);
|
||||
md5_generator->UpdateMd5ForFrame(pframe, surf_info);
|
||||
}
|
||||
if (dump_output_frames && mem_type != OUT_SURFACE_MEM_NOT_MAPPED) {
|
||||
viddec->SaveFrameToFile(output_file_path, pframe, surf_info);
|
||||
@@ -323,7 +372,6 @@ int main(int argc, char **argv) {
|
||||
if (num_decoded_frames && num_decoded_frames <= n_frame) {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (n_video_bytes);
|
||||
|
||||
n_frame += viddec->GetNumOfFlushedFrames();
|
||||
@@ -343,7 +391,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
if (b_generate_md5) {
|
||||
uint8_t *digest;
|
||||
viddec->FinalizeMd5(&digest);
|
||||
md5_generator->FinalizeMd5(&digest);
|
||||
std::cout << "MD5 message digest: ";
|
||||
for (int i = 0; i < 16; i++) {
|
||||
std::cout << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(digest[i]);
|
||||
@@ -371,9 +419,15 @@ int main(int argc, char **argv) {
|
||||
} else {
|
||||
std::cout << "MD5 digest does not match the reference MD5 digest: ";
|
||||
}
|
||||
std::cout << ref_md5_string << std::endl;
|
||||
std::cout << ref_md5_string.c_str() << std::endl;
|
||||
ref_md5_file.close();
|
||||
}
|
||||
delete md5_generator;
|
||||
}
|
||||
if (b_use_ffmpeg_demuxer && demuxer) {
|
||||
delete demuxer;
|
||||
} else if (bs_reader) {
|
||||
rocDecDestroyBitstreamReader(bs_reader);
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
std::cout << ex.what() << std::endl;
|
||||
|
||||
@@ -37,6 +37,7 @@ THE SOFTWARE.
|
||||
#endif
|
||||
#include "video_demuxer.h"
|
||||
#include "roc_video_dec.h"
|
||||
#include "md5.h"
|
||||
|
||||
class FileStreamProvider : public VideoDemuxer::StreamProvider {
|
||||
public:
|
||||
@@ -210,9 +211,11 @@ int main(int argc, char **argv) {
|
||||
OutputSurfaceInfo *surf_info;
|
||||
uint32_t width, height;
|
||||
double total_dec_time = 0;
|
||||
MD5Generator *md5_generator = nullptr;
|
||||
|
||||
if (b_generate_md5) {
|
||||
viddec.InitMd5();
|
||||
md5_generator = new MD5Generator();
|
||||
md5_generator->InitMd5();
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -233,7 +236,7 @@ int main(int argc, char **argv) {
|
||||
for (int i = 0; i < n_frame_returned; i++) {
|
||||
pframe = viddec.GetFrame(&pts);
|
||||
if (b_generate_md5) {
|
||||
viddec.UpdateMd5ForFrame(pframe, surf_info);
|
||||
md5_generator->UpdateMd5ForFrame(pframe, surf_info);
|
||||
}
|
||||
if (dump_output_frames && mem_type != OUT_SURFACE_MEM_NOT_MAPPED) {
|
||||
viddec.SaveFrameToFile(output_file_path, pframe, surf_info);
|
||||
@@ -258,7 +261,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
if (b_generate_md5) {
|
||||
uint8_t *digest;
|
||||
viddec.FinalizeMd5(&digest);
|
||||
md5_generator->FinalizeMd5(&digest);
|
||||
std::cout << "MD5 message digest: ";
|
||||
for (int i = 0; i < 16; i++) {
|
||||
std::cout << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(digest[i]);
|
||||
@@ -289,6 +292,7 @@ int main(int argc, char **argv) {
|
||||
std::cout << ref_md5_string << std::endl;
|
||||
ref_md5_file.close();
|
||||
}
|
||||
delete md5_generator;
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
std::cout << ex.what() << std::endl;
|
||||
|
||||
@@ -42,6 +42,7 @@ THE SOFTWARE.
|
||||
#include "video_demuxer.h"
|
||||
#include "roc_video_dec.h"
|
||||
#include "video_post_process.h"
|
||||
#include "md5.h"
|
||||
|
||||
std::vector<std::string> st_output_format_name = {"native", "bgr", "bgr48", "rgb", "rgb48", "bgra", "bgra64", "rgba", "rgba64"};
|
||||
|
||||
@@ -65,7 +66,7 @@ std::condition_variable cv[frame_buffers_size];
|
||||
|
||||
void ColorSpaceConversionThread(std::atomic<bool>& continue_processing, bool convert_to_rgb, Dim *p_resize_dim, OutputSurfaceInfo **surf_info, OutputSurfaceInfo **res_surf_info,
|
||||
OutputFormatEnum e_output_format, uint8_t *p_rgb_dev_mem, uint8_t *p_resize_dev_mem, bool dump_output_frames,
|
||||
std::string &output_file_path, RocVideoDecoder &viddec, VideoPostProcess &post_proc, bool b_generate_md5) {
|
||||
std::string &output_file_path, RocVideoDecoder &viddec, VideoPostProcess &post_proc, MD5Generator *md5_gen_handle, bool b_generate_md5) {
|
||||
|
||||
size_t rgb_image_size, resize_image_size;
|
||||
hipError_t hip_status = hipSuccess;
|
||||
@@ -138,7 +139,7 @@ void ColorSpaceConversionThread(std::atomic<bool>& continue_processing, bool con
|
||||
viddec.SaveFrameToFile(output_file_path, out_frame, p_surf_info);
|
||||
}
|
||||
if(b_generate_md5 && convert_to_rgb){
|
||||
viddec.UpdateMd5ForDataBuffer(p_rgb_dev_mem, rgb_image_size);
|
||||
md5_gen_handle->UpdateMd5ForDataBuffer(p_rgb_dev_mem, rgb_image_size);
|
||||
}
|
||||
|
||||
|
||||
@@ -270,6 +271,7 @@ int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
VideoPostProcess post_process;
|
||||
MD5Generator *md5_generator = nullptr;
|
||||
|
||||
std::string device_name, gcn_arch_name;
|
||||
int pci_bus_id, pci_domain_id, pci_device_id;
|
||||
@@ -282,7 +284,8 @@ int main(int argc, char **argv) {
|
||||
std::cout << "info: decoding started, please wait!" << std::endl;
|
||||
|
||||
if (b_generate_md5) {
|
||||
viddec.InitMd5();
|
||||
md5_generator = new MD5Generator();
|
||||
md5_generator->InitMd5();
|
||||
}
|
||||
|
||||
int n_video_bytes = 0, n_frames_returned = 0, n_frame = 0;
|
||||
@@ -296,7 +299,7 @@ int main(int argc, char **argv) {
|
||||
convert_to_rgb = e_output_format != native;
|
||||
std::atomic<bool> continue_processing(true);
|
||||
std::thread color_space_conversion_thread(ColorSpaceConversionThread, std::ref(continue_processing), std::ref(convert_to_rgb), &resize_dim, &surf_info, &resize_surf_info, std::ref(e_output_format),
|
||||
std::ref(p_rgb_dev_mem), std::ref(p_resize_dev_mem), std::ref(dump_output_frames), std::ref(output_file_path), std::ref(viddec), std::ref(post_process), b_generate_md5);
|
||||
std::ref(p_rgb_dev_mem), std::ref(p_resize_dev_mem), std::ref(dump_output_frames), std::ref(output_file_path), std::ref(viddec), std::ref(post_process), md5_generator, b_generate_md5);
|
||||
|
||||
auto startTime = std::chrono::high_resolution_clock::now();
|
||||
do {
|
||||
@@ -379,7 +382,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
if (b_generate_md5) {
|
||||
uint8_t *digest;
|
||||
viddec.FinalizeMd5(&digest);
|
||||
md5_generator->FinalizeMd5(&digest);
|
||||
std::cout << "MD5 message digest: ";
|
||||
for (int i = 0; i < 16; i++) {
|
||||
std::cout << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(digest[i]);
|
||||
@@ -410,6 +413,7 @@ int main(int argc, char **argv) {
|
||||
std::cout << ref_md5_string << std::endl;
|
||||
ref_md5_file.close();
|
||||
}
|
||||
delete md5_generator;
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
std::cout << ex.what() << std::endl;
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
################################################################################
|
||||
# Copyright (c) 2023 - 2024 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 "${White}${PROJECT_NAME}: Default ROCm installation path${ColourReset}")
|
||||
elseif(ROCM_PATH)
|
||||
message("-- ${White}${PROJECT_NAME} :ROCM_PATH Set -- ${ROCM_PATH}${ColourReset}")
|
||||
else()
|
||||
set(ROCM_PATH /opt/rocm CACHE PATH "${White}${PROJECT_NAME}: Default ROCm installation path${ColourReset}")
|
||||
endif()
|
||||
# Set AMD Clang as default compiler
|
||||
if (NOT DEFINED CMAKE_CXX_COMPILER)
|
||||
set(CMAKE_CXX_COMPILER ${ROCM_PATH}/bin/amdclang++)
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../../cmake)
|
||||
list(APPEND CMAKE_PREFIX_PATH ${ROCM_PATH}/hip ${ROCM_PATH})
|
||||
|
||||
project(videodecoderaw)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# rocDecode sample build type
|
||||
set(DEFAULT_BUILD_TYPE "Release")
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "rocDecode 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
|
||||
# -Og -- Optimize for debugging experience rather than speed or size
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -gdwarf-4 -Og")
|
||||
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")
|
||||
endif()
|
||||
|
||||
find_package(HIP QUIET)
|
||||
find_package(rocDecode QUIET)
|
||||
|
||||
if(HIP_FOUND AND ROCDECODE_FOUND)
|
||||
# HIP
|
||||
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} hip::host)
|
||||
# rocDecode and utils
|
||||
include_directories (${ROCDECODE_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../../utils ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/rocvideodecode)
|
||||
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${ROCDECODE_LIBRARY})
|
||||
# sample app exe
|
||||
list(APPEND SOURCES ${PROJECT_SOURCE_DIR} videodecoderaw.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../utils/rocvideodecode/roc_video_dec.cpp)
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17")
|
||||
target_link_libraries(${PROJECT_NAME} ${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 ROCDECODE_FOUND)
|
||||
message(FATAL_ERROR "-- ERROR!: rocDecode Not Found! - please install rocDecode!")
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,29 @@
|
||||
# Video decode sample
|
||||
|
||||
The video decode raw sample illustrates decoding a single packetized video stream using the built-in bitstream reader, video parser, and rocDecoder to get the individual decoded frames in YUV format. This sample can be configured with a device ID and optionally able to dump the output to a file. This sample uses the high-level RocVideoDecoder class which connects both the video parser and Rocdecoder. This process repeats in a loop until all frames have been decoded.
|
||||
|
||||
## Prerequisites:
|
||||
|
||||
* Install [rocDecode](../../README.md#build-and-install-instructions)
|
||||
|
||||
## Build
|
||||
|
||||
```shell
|
||||
mkdir video_decode_raw_sample && cd video_decode_raw_sample
|
||||
cmake ../
|
||||
make -j
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```shell
|
||||
./videodecoderaw -i <input video file [required]>
|
||||
-o <output path to save decoded YUV frames [optional]>
|
||||
-d <GPU device ID - 0:device 0 / 1:device 1/ ... [optional - default:0]>
|
||||
-f <Number of decoded frames - specify the number of pictures to be decoded [optional]>
|
||||
-z <force_zero_latency - Decoded frames will be flushed out for display immediately [optional]>
|
||||
-disp_delay <display delay - specify the number of frames to be delayed for display [optional - default: 1]>
|
||||
-sei <extract SEI messages [optional]>
|
||||
-crop <crop rectangle for output (not used when using interopped decoded frame) [optional - default: 0,0,0,0]>
|
||||
-m <output_surface_memory_type - decoded surface memory [optional - default: 0][0 : OUT_SURFACE_MEM_DEV_INTERNAL/ 1 : OUT_SURFACE_MEM_DEV_COPIED/ 2 : OUT_SURFACE_MEM_HOST_COPIED/3 : OUT_SURFACE_MEM_NOT_MAPPED]>
|
||||
```
|
||||
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2024 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 <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <sys/stat.h>
|
||||
#include <libgen.h>
|
||||
#if __cplusplus >= 201703L && __has_include(<filesystem>)
|
||||
#include <filesystem>
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
#endif
|
||||
|
||||
#include "roc_bitstream_reader.h"
|
||||
#include "roc_video_dec.h"
|
||||
|
||||
typedef enum ReconfigFlushMode_enum {
|
||||
RECONFIG_FLUSH_MODE_NONE = 0, /**< Just flush to get the frame count */
|
||||
RECONFIG_FLUSH_MODE_DUMP_TO_FILE = 1, /**< The remaining frames will be dumped to file in this mode */
|
||||
RECONFIG_FLUSH_MODE_CALCULATE_MD5 = 2, /**< Calculate the MD5 of the flushed frames */
|
||||
} ReconfigFlushMode;
|
||||
|
||||
// this struct is used by videodecode and videodecodeMultiFiles to dump last frames to file
|
||||
typedef struct ReconfigDumpFileStruct_t {
|
||||
bool b_dump_frames_to_file;
|
||||
std::string output_file_name;
|
||||
void *md5_generator_handle;
|
||||
} ReconfigDumpFileStruct;
|
||||
|
||||
|
||||
// callback function to flush last frames and save it to file when reconfigure happens
|
||||
int ReconfigureFlushCallback(void *p_viddec_obj, uint32_t flush_mode, void *p_user_struct) {
|
||||
int n_frames_flushed = 0;
|
||||
if ((p_viddec_obj == nullptr) || (p_user_struct == nullptr)) return n_frames_flushed;
|
||||
|
||||
RocVideoDecoder *viddec = static_cast<RocVideoDecoder *> (p_viddec_obj);
|
||||
OutputSurfaceInfo *surf_info;
|
||||
if (!viddec->GetOutputSurfaceInfo(&surf_info)) {
|
||||
std::cerr << "Error: Failed to get Output Surface Info!" << std::endl;
|
||||
return n_frames_flushed;
|
||||
}
|
||||
|
||||
uint8_t *pframe = nullptr;
|
||||
int64_t pts;
|
||||
while ((pframe = viddec->GetFrame(&pts))) {
|
||||
if (flush_mode != RECONFIG_FLUSH_MODE_NONE) {
|
||||
ReconfigDumpFileStruct *p_dump_file_struct = static_cast<ReconfigDumpFileStruct *>(p_user_struct);
|
||||
if (flush_mode == ReconfigFlushMode::RECONFIG_FLUSH_MODE_DUMP_TO_FILE) {
|
||||
if (p_dump_file_struct->b_dump_frames_to_file) {
|
||||
viddec->SaveFrameToFile(p_dump_file_struct->output_file_name, pframe, surf_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
// release and flush frame
|
||||
viddec->ReleaseFrame(pts, true);
|
||||
n_frames_flushed ++;
|
||||
}
|
||||
|
||||
return n_frames_flushed;
|
||||
}
|
||||
|
||||
void ShowHelpAndExit(const char *option = NULL) {
|
||||
std::cout << "Options:" << std::endl
|
||||
<< "-i Input File Path - required" << std::endl
|
||||
<< "-o Output File Path - dumps output if requested; optional" << std::endl
|
||||
<< "-d GPU device ID (0 for the first device, 1 for the second, etc.); optional; default: 0" << std::endl
|
||||
<< "-f Number of decoded frames - specify the number of pictures to be decoded; optional" << std::endl
|
||||
<< "-z force_zero_latency (force_zero_latency, Decoded frames will be flushed out for display immediately); optional;" << std::endl
|
||||
<< "-disp_delay -specify the number of frames to be delayed for display; optional; default: 1" << std::endl
|
||||
<< "-sei extract SEI messages; optional;" << std::endl
|
||||
<< "-crop crop rectangle for output (not used when using interopped decoded frame); optional; default: 0" << std::endl
|
||||
<< "-m output_surface_memory_type - decoded surface memory; optional; default - 0"
|
||||
<< " [0 : OUT_SURFACE_MEM_DEV_INTERNAL/ 1 : OUT_SURFACE_MEM_DEV_COPIED/ 2 : OUT_SURFACE_MEM_HOST_COPIED/ 3 : OUT_SURFACE_MEM_NOT_MAPPED]" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::string input_file_path, output_file_path;
|
||||
int dump_output_frames = 0;
|
||||
int device_id = 0;
|
||||
int disp_delay = 1;
|
||||
bool b_force_zero_latency = false; // false by default: enabling this option might affect decoding performance
|
||||
bool b_extract_sei_messages = false;
|
||||
bool b_flush_frames_during_reconfig = true;
|
||||
Rect crop_rect = {};
|
||||
Rect *p_crop_rect = nullptr;
|
||||
OutputSurfaceMemoryType mem_type = OUT_SURFACE_MEM_DEV_INTERNAL; // set to internal
|
||||
ReconfigParams reconfig_params = { 0 };
|
||||
ReconfigDumpFileStruct reconfig_user_struct = { 0 };
|
||||
uint32_t num_decoded_frames = 0; // default value is 0, meaning decode the entire stream
|
||||
|
||||
// Parse command-line arguments
|
||||
if(argc <= 1) {
|
||||
ShowHelpAndExit();
|
||||
}
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-h")) {
|
||||
ShowHelpAndExit();
|
||||
}
|
||||
if (!strcmp(argv[i], "-i")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-i");
|
||||
}
|
||||
input_file_path = argv[i];
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-o")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-o");
|
||||
}
|
||||
output_file_path = argv[i];
|
||||
dump_output_frames = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-d")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-d");
|
||||
}
|
||||
device_id = atoi(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-disp_delay")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-disp_delay");
|
||||
}
|
||||
disp_delay = atoi(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-f")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-d");
|
||||
}
|
||||
num_decoded_frames = atoi(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-z")) {
|
||||
if (i == argc) {
|
||||
ShowHelpAndExit("-z");
|
||||
}
|
||||
b_force_zero_latency = true;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-sei")) {
|
||||
if (i == argc) {
|
||||
ShowHelpAndExit("-sei");
|
||||
}
|
||||
b_extract_sei_messages = true;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-crop")) {
|
||||
if (++i == argc || 4 != sscanf(argv[i], "%d,%d,%d,%d", &crop_rect.left, &crop_rect.top, &crop_rect.right, &crop_rect.bottom)) {
|
||||
ShowHelpAndExit("-crop");
|
||||
}
|
||||
if ((crop_rect.right - crop_rect.left) % 2 == 1 || (crop_rect.bottom - crop_rect.top) % 2 == 1) {
|
||||
std::cout << "output crop rectangle must have width and height of even numbers" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
p_crop_rect = &crop_rect;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-m")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-m");
|
||||
}
|
||||
mem_type = static_cast<OutputSurfaceMemoryType>(atoi(argv[i]));
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "flush")) {
|
||||
b_flush_frames_during_reconfig = atoi(argv[i]) ? true : false;
|
||||
continue;
|
||||
}
|
||||
|
||||
ShowHelpAndExit(argv[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
std::size_t found_file = input_file_path.find_last_of('/');
|
||||
std::cout << "info: Input file: " << input_file_path.substr(found_file + 1) << std::endl;
|
||||
std::cout << "info: Using built-in bitstream reader" << std::endl;
|
||||
RocdecBitstreamReader bs_reader = nullptr;
|
||||
rocDecVideoCodec rocdec_codec_id;
|
||||
int bit_depth;
|
||||
if (rocDecCreateBitstreamReader(&bs_reader, input_file_path.c_str()) != ROCDEC_SUCCESS) {
|
||||
std::cerr << "Failed to create the bitstream reader." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (rocDecGetBitstreamCodecType(bs_reader, &rocdec_codec_id) != ROCDEC_SUCCESS) {
|
||||
std::cerr << "Failed to get stream codec type." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (rocdec_codec_id >= rocDecVideoCodec_NumCodecs) {
|
||||
std::cerr << "Unsupported stream file type or codec type by the bitstream reader. Exiting." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (rocDecGetBitstreamBitDepth(bs_reader, &bit_depth) != ROCDEC_SUCCESS) {
|
||||
std::cerr << "Failed to get stream bit depth." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
RocVideoDecoder viddec(device_id, mem_type, rocdec_codec_id, b_force_zero_latency, p_crop_rect, b_extract_sei_messages, disp_delay);
|
||||
if(!viddec.CodecSupported(device_id, rocdec_codec_id, bit_depth)) {
|
||||
std::cerr << "GPU doesn't support codec!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
std::string device_name, gcn_arch_name;
|
||||
int pci_bus_id, pci_domain_id, pci_device_id;
|
||||
|
||||
viddec.GetDeviceinfo(device_name, gcn_arch_name, pci_bus_id, pci_domain_id, pci_device_id);
|
||||
std::cout << "info: Using GPU device " << device_id << " - " << device_name << "[" << gcn_arch_name << "] on PCI bus " <<
|
||||
std::setfill('0') << std::setw(2) << std::right << std::hex << pci_bus_id << ":" << std::setfill('0') << std::setw(2) <<
|
||||
std::right << std::hex << pci_domain_id << "." << pci_device_id << std::dec << std::endl;
|
||||
std::cout << "info: decoding started, please wait!" << std::endl;
|
||||
|
||||
int n_video_bytes = 0, n_frame_returned = 0, n_frame = 0;
|
||||
int n_pic_decoded = 0, decoded_pics = 0;
|
||||
uint8_t *pvideo = nullptr;
|
||||
int pkg_flags = 0;
|
||||
uint8_t *pframe = nullptr;
|
||||
int64_t pts = 0;
|
||||
OutputSurfaceInfo *surf_info;
|
||||
uint32_t width, height;
|
||||
double total_dec_time = 0;
|
||||
bool first_frame = true;
|
||||
// initialize reconfigure params: the following is configured to dump to output which is relevant for this sample
|
||||
reconfig_params.p_fn_reconfigure_flush = ReconfigureFlushCallback;
|
||||
reconfig_user_struct.b_dump_frames_to_file = dump_output_frames;
|
||||
reconfig_user_struct.output_file_name = output_file_path;
|
||||
if (dump_output_frames) {
|
||||
reconfig_params.reconfig_flush_mode = RECONFIG_FLUSH_MODE_DUMP_TO_FILE;
|
||||
} else {
|
||||
reconfig_params.reconfig_flush_mode = RECONFIG_FLUSH_MODE_NONE;
|
||||
}
|
||||
reconfig_params.p_reconfig_user_struct = &reconfig_user_struct;
|
||||
|
||||
viddec.SetReconfigParams(&reconfig_params);
|
||||
|
||||
do {
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
if (rocDecGetBitstreamPicData(bs_reader, &pvideo, &n_video_bytes, &pts) != ROCDEC_SUCCESS) {
|
||||
std::cerr << "Failed to get picture data." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
// Treat 0 bitstream size as end of stream indicator
|
||||
if (n_video_bytes == 0) {
|
||||
pkg_flags |= ROCDEC_PKT_ENDOFSTREAM;
|
||||
}
|
||||
n_frame_returned = viddec.DecodeFrame(pvideo, n_video_bytes, pkg_flags, pts, &decoded_pics);
|
||||
|
||||
if (!n_frame && !viddec.GetOutputSurfaceInfo(&surf_info)) {
|
||||
std::cerr << "Error: Failed to get Output Surface Info!" << std::endl;
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < n_frame_returned; i++) {
|
||||
pframe = viddec.GetFrame(&pts);
|
||||
if (dump_output_frames && mem_type != OUT_SURFACE_MEM_NOT_MAPPED) {
|
||||
viddec.SaveFrameToFile(output_file_path, pframe, surf_info);
|
||||
}
|
||||
// release frame
|
||||
viddec.ReleaseFrame(pts);
|
||||
}
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
auto time_per_decode = std::chrono::duration<double, std::milli>(end_time - start_time).count();
|
||||
total_dec_time += time_per_decode;
|
||||
n_frame += n_frame_returned;
|
||||
n_pic_decoded += decoded_pics;
|
||||
if (num_decoded_frames && num_decoded_frames <= n_frame) {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (n_video_bytes);
|
||||
|
||||
n_frame += viddec.GetNumOfFlushedFrames();
|
||||
std::cout << "info: Total pictures decoded: " << n_pic_decoded << std::endl;
|
||||
std::cout << "info: Total frames output/displayed: " << n_frame << std::endl;
|
||||
if (!dump_output_frames) {
|
||||
std::cout << "info: avg decoding time per picture: " << total_dec_time / n_pic_decoded << " ms" <<std::endl;
|
||||
std::cout << "info: avg decode FPS: " << (n_pic_decoded / total_dec_time) * 1000 << std::endl;
|
||||
std::cout << "info: avg output/display time per frame: " << total_dec_time / n_frame << " ms" <<std::endl;
|
||||
std::cout << "info: avg output/display FPS: " << (n_frame / total_dec_time) * 1000 << std::endl;
|
||||
} else {
|
||||
if (mem_type == OUT_SURFACE_MEM_NOT_MAPPED) {
|
||||
std::cout << "info: saving frames with -m 3 option is not supported!" << std::endl;
|
||||
} else {
|
||||
std::cout << "info: saved frames into " << output_file_path << std::endl;
|
||||
}
|
||||
}
|
||||
if (bs_reader) {
|
||||
rocDecDestroyBitstreamReader(bs_reader);
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
std::cout << ex.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2024 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_bitstream_reader.h"
|
||||
#include "es_reader.h"
|
||||
|
||||
class RocBitstreamReaderHandle {
|
||||
public:
|
||||
explicit RocBitstreamReaderHandle(const char *input_file_path) : bs_reader_(std::make_shared<RocVideoESParser>(input_file_path)) {};
|
||||
~RocBitstreamReaderHandle() { ClearErrors(); }
|
||||
bool NoError() { return error_.empty(); }
|
||||
const char* ErrorMsg() { return error_.c_str(); }
|
||||
void CaptureError(const std::string& err_msg) { error_ = err_msg; }
|
||||
rocDecStatus GetBitstreamCodecType(rocDecVideoCodec *codec_type) { *codec_type = bs_reader_->GetCodecId(); return ROCDEC_SUCCESS; }
|
||||
rocDecStatus GetBitstreamBitDepth(int *bit_depth) { *bit_depth = bs_reader_->GetBitDepth(); return ROCDEC_SUCCESS; }
|
||||
rocDecStatus GetBitstreamPicData(uint8_t **pic_data, int *pic_size, int64_t *pts) { return static_cast<rocDecStatus>(bs_reader_->GetPicData(pic_data, pic_size, pts)); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<RocVideoESParser> bs_reader_ = nullptr;
|
||||
void ClearErrors() { error_ = ""; }
|
||||
|
||||
std::string error_;
|
||||
};
|
||||
Dosya farkı çok büyük olduğundan ihmal edildi
Fark Yükle
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2024 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 <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include "rocdecode.h"
|
||||
|
||||
#define BS_RING_SIZE (16 * 1024 * 1024)
|
||||
#define INIT_PIC_DATA_SIZE (2 * 1024 * 1024)
|
||||
|
||||
enum {
|
||||
kStreamTypeUnsupported = -1,
|
||||
kStreamTypeAvcElementary = 0,
|
||||
kStreamTypeHevcElementary,
|
||||
kStreamTypeAv1Elementary,
|
||||
kStreamTypeAv1Ivf,
|
||||
kStreamTypeNumSupported
|
||||
} StreamFileType;
|
||||
|
||||
#define STREAM_PROBE_SIZE 2 * 1024
|
||||
#define STREAM_TYPE_SCORE_THRESHOLD 50
|
||||
|
||||
class RocVideoESParser {
|
||||
public:
|
||||
RocVideoESParser(const char *input_file_path);
|
||||
RocVideoESParser();
|
||||
~RocVideoESParser();
|
||||
|
||||
/*! \brief Function to probe the bitstream file and try to get the codec id
|
||||
* \retrun Codec id
|
||||
*/
|
||||
rocDecVideoCodec GetCodecId();
|
||||
|
||||
/*! \brief Function to retrieve the bitstream of a picture
|
||||
* \param [out] p_pic_data Pointer to the picture data
|
||||
* \param [out] pic_size Size of the picture in bytes
|
||||
* \param [out] pts Presentation time stamp
|
||||
*/
|
||||
int GetPicData(uint8_t **p_pic_data, int *pic_size, int64_t *pts);
|
||||
|
||||
/*! \brief Function to return the bit depth of the stream
|
||||
*/
|
||||
int GetBitDepth() {return bit_depth_;};
|
||||
|
||||
private:
|
||||
std::ifstream p_stream_file_;
|
||||
int stream_type_;
|
||||
int bit_depth_;
|
||||
|
||||
// Bitstream ring buffer
|
||||
uint8_t bs_ring_[BS_RING_SIZE];
|
||||
uint32_t read_ptr_; /// start position of unprocessed stream in the ring
|
||||
uint32_t write_ptr_; /// end position of unprocessed stream in the ring
|
||||
bool end_of_file_;
|
||||
bool end_of_stream_;
|
||||
int curr_byte_offset_;
|
||||
// AVC/HEVC
|
||||
int num_start_code_;
|
||||
int curr_start_code_offset_;
|
||||
int next_start_code_offset_;
|
||||
//int nal_unit_size_;
|
||||
// AV1
|
||||
int obu_byte_offset_; // header offset
|
||||
int obu_size_; // including header
|
||||
int num_td_obus_; // number of temporal delimiter OBUs
|
||||
|
||||
// Picture data (linear buffer)
|
||||
std::vector<uint8_t> pic_data_;
|
||||
int pic_data_size_;
|
||||
// AVC/HEVC
|
||||
int curr_pic_end_;
|
||||
int next_pic_start_;
|
||||
int num_pictures_;
|
||||
// AV1
|
||||
int num_temp_units_; // number of temporal units
|
||||
|
||||
bool ivf_file_header_read_; // indicator if IVF file header has been checked
|
||||
|
||||
/*! \brief Function to retrieve the bitstream of a picture for AVC/HEVC
|
||||
* \param [out] p_pic_data Pointer to the picture data
|
||||
* \param [out] pic_size Size of the picture in bytes
|
||||
*/
|
||||
int GetPicDataAvcHevc(uint8_t **p_pic_data, int *pic_size);
|
||||
|
||||
/*! \brief Function to retrieve the bitstream of a temporal unit for AV1
|
||||
* \param [out] p_pic_data Pointer to the picture data
|
||||
* \param [out] pic_size Size of the picture in bytes
|
||||
*/
|
||||
int GetPicDataAv1(uint8_t **p_pic_data, int *pic_size);
|
||||
|
||||
/*! \brief Function to retrieve the bitstream of a temporal unit for AV1 from IVF container
|
||||
* \param [out] p_pic_data Pointer to the picture data
|
||||
* \param [out] pic_size Size of the picture in bytes
|
||||
*/
|
||||
int GetPicDataIvfAv1(uint8_t **p_pic_data, int *pic_size);
|
||||
|
||||
/*! \brief Function to read bitstream from file and fill into the ring buffer.
|
||||
* \return Number of bytes read from file.
|
||||
*/
|
||||
int FetchBitStream();
|
||||
|
||||
/*! \brief Function to check the remaining data size in the ring buffer
|
||||
* \return Number of bytes still available in the ring
|
||||
*/
|
||||
int GetDataSizeInRB();
|
||||
|
||||
/*! \brief Function to read one byte from the ring buffer without advancing the read pointer
|
||||
* \param [in] offset The byte offset to read
|
||||
* \param [out] data The byte read
|
||||
* \return True: success; False: no more byte available.
|
||||
*/
|
||||
bool GetByte(int offset, uint8_t *data);
|
||||
|
||||
/*! \brief Function to read the specified bytes from the ring buffer without advancing the read pointer
|
||||
* \param [in] offset The starting byte offset to read
|
||||
* \param [in] size The numbers of bytes to read
|
||||
* \param [out] data The bytes read
|
||||
* \return True: success; False: can not read the set bytes
|
||||
*/
|
||||
bool ReadBytes(int offset, int size, uint8_t *data);
|
||||
|
||||
/*! \brief Function to update the read pointer by the set bytes
|
||||
* \param [in] value The new read pointer value
|
||||
*/
|
||||
void SetReadPointer(int value);
|
||||
|
||||
/*! \brief Function to find the start codes from the ring buffer to locate the NAL units
|
||||
* \return Returns: true: a new start code is found or end of stream reached; false: no start code found.
|
||||
*/
|
||||
bool FindStartCode();
|
||||
|
||||
/*! \brief Function to check if an HEVC NAL is the (first) slice of a picture
|
||||
* \param [in] start_code_offset Start code location of the NAL unit
|
||||
* \param [out] slice_flag Slice NAL unit indicator
|
||||
* \param [out] first_slice_flag First slice indicator
|
||||
*/
|
||||
void CheckHevcNalForSlice(int start_code_offset, int *slice_flag, int *first_slice_flag);
|
||||
|
||||
/*! \brief Function to check if an AVC NAL is the (first) slice of a picture
|
||||
* \param [in] start_code_offset Start code location of the NAL unit
|
||||
* \param [out] slice_flag Slice NAL unit indicator
|
||||
* \param [out] first_slice_flag First slice indicator
|
||||
*/
|
||||
void CheckAvcNalForSlice(int start_code_offset, int *slice_flag, int *first_slice_flag);
|
||||
|
||||
/*! \brief Function to copy a NAL unit from the bitstream ring buffer to the linear picture data buffer
|
||||
*/
|
||||
void CopyNalUnitFromRing();
|
||||
|
||||
/*! \brief Function to parse an OBU header and size
|
||||
* \param [out] obu_type Pointer to the returned OBU type
|
||||
* \return true if success
|
||||
*/
|
||||
bool ReadObuHeaderAndSize(int *obu_type);
|
||||
|
||||
/*! \brief Function to copy an OBU from the bitstream ring buffer to the linear picture data buffer
|
||||
* \return true if success
|
||||
*/
|
||||
bool CopyObuFromRing();
|
||||
|
||||
/*! \brief Function to check the 32 byte stream for IVF file header identity
|
||||
* \return true if IVF file header is identified; false: otherwise
|
||||
*/
|
||||
bool CheckIvfFileHeader(uint8_t *stream);
|
||||
|
||||
/*! \brief Function to probe the bitstream file and try to find if it is one of types supported.
|
||||
* \return Elementary stream file type
|
||||
*/
|
||||
int ProbeStreamType();
|
||||
|
||||
/*! \brief Function to check the likelihood of a stream to be an AVC elementary stream.
|
||||
* \param [in] p_stream Pointer to the stream
|
||||
* \param [in] stream_size Size of the stream in bytes
|
||||
* \return The likelihood score
|
||||
*/
|
||||
int CheckAvcEStream(uint8_t *p_stream, int stream_size);
|
||||
|
||||
/*! \brief Function to check the likelihood of a stream to be an HEVC elementary stream.
|
||||
* \param [in] p_stream Pointer to the stream
|
||||
* \param [in] stream_size Size of the stream in bytes
|
||||
* \return The likelihood score
|
||||
*/
|
||||
int CheckHevcEStream(uint8_t *p_stream, int stream_size);
|
||||
|
||||
/*! \brief Function to convert from Encapsulated Byte Sequence Packets to Raw Byte Sequence Payload
|
||||
* \param [inout] stream_buffer A pointer of <tt>uint8_t</tt> for the converted RBSP buffer.
|
||||
* \param [in] begin_bytepos Start position in the EBSP buffer to convert
|
||||
* \param [in] end_bytepos End position in the EBSP buffer to convert, generally it's size.
|
||||
* \return Returns the size of the converted buffer
|
||||
*/
|
||||
int EbspToRbsp(uint8_t *stream_buffer, int begin_bytepos, int end_bytepos);
|
||||
|
||||
/*! \brief Function to check the likelihood of a stream to be an AV1 elementary stream.
|
||||
* \param [in] p_stream Pointer to the stream
|
||||
* \param [in] stream_size Size of the stream in bytes
|
||||
* \return The likelihood score
|
||||
*/
|
||||
int CheckAv1EStream(uint8_t *p_stream, int stream_size);
|
||||
|
||||
/*! \brief Function to check the likelihood of a stream to be an IVF container of AV1 elementary stream.
|
||||
* \param [in] p_stream Pointer to the stream
|
||||
* \param [in] stream_size Size of the stream in bytes
|
||||
* \return The likelihood score
|
||||
*/
|
||||
int CheckIvfAv1Stream(uint8_t *p_stream, int stream_size);
|
||||
|
||||
/*! \brief Function to read variable length unsigned n-bit number appearing directly in the bitstream. 4.10.3. uvlc().
|
||||
* \param [in] p_stream Bit stream pointer
|
||||
* \param [in] bit_offset Starting bit offset
|
||||
* \param [out] bit_offset Updated bit offset
|
||||
* \return The unsigned value
|
||||
*/
|
||||
uint32_t ReadUVLC(const uint8_t *p_stream, size_t &bit_offset);
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2024 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 "bs_reader_handle.h"
|
||||
|
||||
rocDecStatus ROCDECAPI rocDecCreateBitstreamReader(RocdecBitstreamReader *bs_reader_handle, const char *input_file_path) {
|
||||
if (bs_reader_handle == nullptr || input_file_path == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
RocdecBitstreamReader handle = nullptr;
|
||||
try {
|
||||
handle = new RocBitstreamReaderHandle(input_file_path);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
ERR( STR("Failed to create RocBitstreamReader handle, ") + STR(e.what()))
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
*bs_reader_handle = handle;
|
||||
return ROCDEC_SUCCESS;
|
||||
}
|
||||
|
||||
rocDecStatus ROCDECAPI rocDecGetBitstreamCodecType(RocdecBitstreamReader bs_reader_handle, rocDecVideoCodec *codec_type) {
|
||||
if (bs_reader_handle == nullptr || codec_type == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
auto roc_bs_reader_handle = static_cast<RocBitstreamReaderHandle*>(bs_reader_handle);
|
||||
rocDecStatus ret;
|
||||
try {
|
||||
ret = roc_bs_reader_handle->GetBitstreamCodecType(codec_type);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
roc_bs_reader_handle->CaptureError(e.what());
|
||||
ERR(e.what())
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
rocDecStatus ROCDECAPI rocDecGetBitstreamBitDepth(RocdecBitstreamReader bs_reader_handle, int *bit_depth) {
|
||||
if (bs_reader_handle == nullptr || bit_depth == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
auto roc_bs_reader_handle = static_cast<RocBitstreamReaderHandle*>(bs_reader_handle);
|
||||
rocDecStatus ret;
|
||||
try {
|
||||
ret = roc_bs_reader_handle->GetBitstreamBitDepth(bit_depth);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
roc_bs_reader_handle->CaptureError(e.what());
|
||||
ERR(e.what())
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
rocDecStatus ROCDECAPI rocDecGetBitstreamPicData(RocdecBitstreamReader bs_reader_handle, uint8_t **pic_data, int *pic_size, int64_t *pts) {
|
||||
if (bs_reader_handle == nullptr || pic_data == nullptr || pic_size == nullptr || pts == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
auto roc_bs_reader_handle = static_cast<RocBitstreamReaderHandle*>(bs_reader_handle);
|
||||
rocDecStatus ret;
|
||||
try {
|
||||
ret = roc_bs_reader_handle->GetBitstreamPicData(pic_data, pic_size, pts);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
roc_bs_reader_handle->CaptureError(e.what());
|
||||
ERR(e.what())
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
rocDecStatus ROCDECAPI rocDecDestroyBitstreamReader(RocdecBitstreamReader bs_reader_handle) {
|
||||
if (bs_reader_handle == nullptr) {
|
||||
return ROCDEC_INVALID_PARAMETER;
|
||||
}
|
||||
auto roc_bs_reader_handle = static_cast<RocBitstreamReaderHandle*>(bs_reader_handle);
|
||||
delete roc_bs_reader_handle;
|
||||
return ROCDEC_SUCCESS;
|
||||
}
|
||||
@@ -45,6 +45,8 @@ parser.add_argument('--files_directory', type=str, default='',
|
||||
help='The path to a dirctory containing one or more supported files for decoding (e.g., mp4, mov, etc.) and their corresponding reference MD5 digests - required')
|
||||
parser.add_argument('--results_directory', type=str, default='',
|
||||
help='The path to a dirctory to store results - optional')
|
||||
parser.add_argument('--use_ffmpeg_demuxer', type=int, default=1,
|
||||
help='Indicator to use FFMPEG demuxer - optional (default:1). If set to 0, built-in bitstream reader is used.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -53,6 +55,12 @@ gpuDeviceID = args.gpu_device_id
|
||||
filesDir = args.files_directory
|
||||
videoDecodeEXE = args.videodecode_exe
|
||||
resultsDir = args.results_directory
|
||||
useFFDemuxer = args.use_ffmpeg_demuxer
|
||||
|
||||
if useFFDemuxer == 1:
|
||||
bsReaderOption = ''
|
||||
else:
|
||||
bsReaderOption = '-no_ffmpeg_demux'
|
||||
|
||||
print("\nrunrocDecodeTests V"+__version__+"\n")
|
||||
|
||||
@@ -108,7 +116,7 @@ if streamListSize != md5ListSize:
|
||||
for i in range(streamListSize):
|
||||
streamFilePath = streamFileDir + streamFileList[i]
|
||||
md5FilePath = md5FileDir + md5FileList[i]
|
||||
os.system(run_rocDecode_app +' -i ' + streamFilePath + ' -md5_check ' + md5FilePath + ' -d ' + str(gpuDeviceID) + ' | tee -a ' + resultsPath + '/rocDecode_output.log')
|
||||
os.system(run_rocDecode_app +' -i ' + streamFilePath + ' ' + bsReaderOption + ' -md5_check ' + md5FilePath + ' -d ' + str(gpuDeviceID) + ' | tee -a ' + resultsPath + '/rocDecode_output.log')
|
||||
print("======================================================================================\n")
|
||||
|
||||
fileString = 'Input file'
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
Copyright (c) 2023 - 2024 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 "libavutil/md5.h"
|
||||
#include "libavutil/mem.h"
|
||||
}
|
||||
#include "roc_video_dec.h"
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief The MD5 message digest generation utility.
|
||||
*/
|
||||
|
||||
class MD5Generator {
|
||||
public:
|
||||
MD5Generator() {};
|
||||
~MD5Generator() {};
|
||||
|
||||
/*! \brief Function to start MD5 calculation
|
||||
*/
|
||||
void InitMd5() {
|
||||
md5_ctx_ = av_md5_alloc();
|
||||
av_md5_init(md5_ctx_);
|
||||
}
|
||||
|
||||
/*! \brief Function to update MD5 digest for a device data buffer
|
||||
* \param [in] data_buf Pointer to the data buffer
|
||||
* \param [in] buf_size Buffer info
|
||||
*/
|
||||
void UpdateMd5ForDataBuffer(void *data_buf, int buf_size) {
|
||||
uint8_t *hstPtr = nullptr;
|
||||
hstPtr = new uint8_t[buf_size];
|
||||
hipError_t hip_status = hipSuccess;
|
||||
hip_status = hipMemcpyDtoH((void *)hstPtr, data_buf, buf_size);
|
||||
if (hip_status != hipSuccess) {
|
||||
std::cerr << "ERROR: hipMemcpyDtoH failed! (" << hip_status << ")" << std::endl;
|
||||
delete [] hstPtr;
|
||||
return;
|
||||
}
|
||||
av_md5_update(md5_ctx_, hstPtr, buf_size);
|
||||
if (hstPtr) {
|
||||
delete [] hstPtr;
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Function to update MD5 digest for a decoded frame
|
||||
* \param [in] surf_mem Pointer to surface memory
|
||||
* \param [in] surf_info Surface info
|
||||
*/
|
||||
void UpdateMd5ForFrame(void *surf_mem, OutputSurfaceInfo *surf_info) {
|
||||
int i;
|
||||
uint8_t *hst_ptr = nullptr;
|
||||
uint64_t output_image_size = surf_info->output_surface_size_in_bytes;
|
||||
if (surf_info->mem_type == OUT_SURFACE_MEM_DEV_INTERNAL || surf_info->mem_type == OUT_SURFACE_MEM_DEV_COPIED) {
|
||||
if (hst_ptr == nullptr) {
|
||||
hst_ptr = new uint8_t [output_image_size];
|
||||
}
|
||||
hipError_t hip_status = hipSuccess;
|
||||
hip_status = hipMemcpyDtoH((void *)hst_ptr, surf_mem, output_image_size);
|
||||
if (hip_status != hipSuccess) {
|
||||
std::cerr << "ERROR: hipMemcpyDtoH failed! (" << hip_status << ")" << std::endl;
|
||||
delete [] hst_ptr;
|
||||
return;
|
||||
}
|
||||
} else
|
||||
hst_ptr = static_cast<uint8_t *> (surf_mem);
|
||||
|
||||
// Need to covert interleaved planar to stacked planar, assuming 4:2:0 chroma sampling.
|
||||
uint8_t *stacked_ptr = new uint8_t [output_image_size];
|
||||
uint8_t *tmp_hst_ptr = hst_ptr;
|
||||
int output_stride = surf_info->output_pitch;
|
||||
tmp_hst_ptr += (surf_info->disp_rect.top * output_stride) + surf_info->disp_rect.left * surf_info->bytes_per_pixel;
|
||||
uint8_t *tmp_stacked_ptr = stacked_ptr;
|
||||
int img_width = surf_info->output_width;
|
||||
int img_height = surf_info->output_height;
|
||||
// Luma
|
||||
if (img_width * surf_info->bytes_per_pixel == output_stride && img_height == surf_info->output_vstride) {
|
||||
memcpy(stacked_ptr, hst_ptr, img_width * surf_info->bytes_per_pixel * img_height);
|
||||
} else {
|
||||
for (i = 0; i < img_height; i++) {
|
||||
memcpy(tmp_stacked_ptr, tmp_hst_ptr, img_width * surf_info->bytes_per_pixel);
|
||||
tmp_hst_ptr += output_stride;
|
||||
tmp_stacked_ptr += img_width * surf_info->bytes_per_pixel;
|
||||
}
|
||||
}
|
||||
// Chroma
|
||||
int img_width_chroma = img_width >> 1;
|
||||
tmp_hst_ptr = hst_ptr + output_stride * surf_info->output_vstride;
|
||||
if (surf_info->mem_type == OUT_SURFACE_MEM_DEV_INTERNAL) {
|
||||
tmp_hst_ptr += ((surf_info->disp_rect.top >> 1) * output_stride) + (surf_info->disp_rect.left * surf_info->bytes_per_pixel);
|
||||
}
|
||||
tmp_stacked_ptr = stacked_ptr + img_width * surf_info->bytes_per_pixel * img_height; // Cb
|
||||
uint8_t *tmp_stacked_ptr_v = tmp_stacked_ptr + img_width_chroma * surf_info->bytes_per_pixel * surf_info->chroma_height; // Cr
|
||||
for (i = 0; i < surf_info->chroma_height; i++) {
|
||||
for ( int j = 0; j < img_width_chroma; j++) {
|
||||
uint8_t *src_ptr, *dst_ptr;
|
||||
// Cb
|
||||
src_ptr = &tmp_hst_ptr[j * surf_info->bytes_per_pixel * 2];
|
||||
dst_ptr = &tmp_stacked_ptr[j * surf_info->bytes_per_pixel];
|
||||
memcpy(dst_ptr, src_ptr, surf_info->bytes_per_pixel);
|
||||
// Cr
|
||||
src_ptr += surf_info->bytes_per_pixel;
|
||||
dst_ptr = &tmp_stacked_ptr_v[j * surf_info->bytes_per_pixel];
|
||||
memcpy(dst_ptr, src_ptr, surf_info->bytes_per_pixel);
|
||||
}
|
||||
tmp_hst_ptr += output_stride;
|
||||
tmp_stacked_ptr += img_width_chroma * surf_info->bytes_per_pixel;
|
||||
tmp_stacked_ptr_v += img_width_chroma * surf_info->bytes_per_pixel;
|
||||
}
|
||||
|
||||
int img_size = img_width * surf_info->bytes_per_pixel * (img_height + surf_info->chroma_height);
|
||||
// For 10 bit, convert from P010 to LSB to match reference decoder output
|
||||
if (surf_info->bytes_per_pixel == 2) {
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t *> (stacked_ptr);
|
||||
for (i = 0; i < img_size / 2; i++) {
|
||||
ptr[i] = ptr[i] >> 6;
|
||||
}
|
||||
}
|
||||
|
||||
av_md5_update(md5_ctx_, stacked_ptr, img_size);
|
||||
if (hst_ptr && (surf_info->mem_type != OUT_SURFACE_MEM_HOST_COPIED)) {
|
||||
delete [] hst_ptr;
|
||||
}
|
||||
delete [] stacked_ptr;
|
||||
}
|
||||
|
||||
/*! \brief Function to complete MD5 calculation
|
||||
* \param [out] digest Pointer to the 16 byte message digest
|
||||
*/
|
||||
void FinalizeMd5(uint8_t **digest) {
|
||||
av_md5_final(md5_ctx_, md5_digest_);
|
||||
av_freep(&md5_ctx_);
|
||||
*digest = md5_digest_;
|
||||
}
|
||||
|
||||
private:
|
||||
struct AVMD5 *md5_ctx_;
|
||||
uint8_t md5_digest_[16];
|
||||
};
|
||||
@@ -381,6 +381,8 @@ int RocVideoDecoder::HandleVideoSequence(RocdecVideoFormat *p_video_format) {
|
||||
output_surface_info_.output_height = target_height_;
|
||||
output_surface_info_.output_pitch = surface_stride_;
|
||||
output_surface_info_.output_vstride = (out_mem_type_ == OUT_SURFACE_MEM_DEV_INTERNAL) ? surface_vstride_ : videoDecodeCreateInfo.target_height;
|
||||
output_surface_info_.disp_rect = disp_rect_;
|
||||
output_surface_info_.chroma_height = chroma_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_;
|
||||
@@ -541,6 +543,8 @@ int RocVideoDecoder::ReconfigureDecoder(RocdecVideoFormat *p_video_format) {
|
||||
output_surface_info_.output_height = target_height_;
|
||||
output_surface_info_.output_pitch = surface_stride_;
|
||||
output_surface_info_.output_vstride = (out_mem_type_ == OUT_SURFACE_MEM_DEV_INTERNAL) ? surface_vstride_ : target_height_;
|
||||
output_surface_info_.disp_rect = disp_rect_;
|
||||
output_surface_info_.chroma_height = chroma_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_;
|
||||
@@ -1011,113 +1015,6 @@ void RocVideoDecoder::ResetSaveFrameToFile() {
|
||||
}
|
||||
}
|
||||
|
||||
void RocVideoDecoder::InitMd5() {
|
||||
md5_ctx_ = av_md5_alloc();
|
||||
av_md5_init(md5_ctx_);
|
||||
}
|
||||
|
||||
void RocVideoDecoder::UpdateMd5ForDataBuffer(void *pDevMem, int rgb_image_size){
|
||||
uint8_t *hstPtr = nullptr;
|
||||
hstPtr = new uint8_t [rgb_image_size];
|
||||
hipError_t hip_status = hipSuccess;
|
||||
hip_status = hipMemcpyDtoH((void *)hstPtr, pDevMem, rgb_image_size);
|
||||
if (hip_status != hipSuccess) {
|
||||
std::cout << "ERROR: hipMemcpyDtoH failed! (" << hip_status << ")" << std::endl;
|
||||
delete [] hstPtr;
|
||||
return;
|
||||
}
|
||||
av_md5_update(md5_ctx_, hstPtr, rgb_image_size);
|
||||
if(hstPtr){
|
||||
delete [] hstPtr;
|
||||
}
|
||||
}
|
||||
|
||||
void RocVideoDecoder::UpdateMd5ForFrame(void *surf_mem, OutputSurfaceInfo *surf_info) {
|
||||
int i;
|
||||
uint8_t *hst_ptr = nullptr;
|
||||
uint64_t output_image_size = surf_info->output_surface_size_in_bytes;
|
||||
if (surf_info->mem_type == OUT_SURFACE_MEM_DEV_INTERNAL || surf_info->mem_type == OUT_SURFACE_MEM_DEV_COPIED) {
|
||||
if (hst_ptr == nullptr) {
|
||||
hst_ptr = new uint8_t [output_image_size];
|
||||
}
|
||||
hipError_t hip_status = hipSuccess;
|
||||
hip_status = hipMemcpyDtoH((void *)hst_ptr, surf_mem, output_image_size);
|
||||
if (hip_status != hipSuccess) {
|
||||
std::cerr << "ERROR: hipMemcpyDtoH failed! (" << hip_status << ")" << std::endl;
|
||||
delete [] hst_ptr;
|
||||
return;
|
||||
}
|
||||
} else
|
||||
hst_ptr = static_cast<uint8_t *> (surf_mem);
|
||||
|
||||
// Need to covert interleaved planar to stacked planar, assuming 4:2:0 chroma sampling.
|
||||
uint8_t *stacked_ptr = new uint8_t [output_image_size];
|
||||
|
||||
uint8_t *tmp_hst_ptr = hst_ptr;
|
||||
int output_stride = surf_info->output_pitch;
|
||||
tmp_hst_ptr += (disp_rect_.top * output_stride) + disp_rect_.left * surf_info->bytes_per_pixel;
|
||||
uint8_t *tmp_stacked_ptr = stacked_ptr;
|
||||
int img_width = surf_info->output_width;
|
||||
int img_height = surf_info->output_height;
|
||||
// Luma
|
||||
if (img_width * surf_info->bytes_per_pixel == output_stride && img_height == surf_info->output_vstride) {
|
||||
memcpy(stacked_ptr, hst_ptr, img_width * surf_info->bytes_per_pixel * img_height);
|
||||
} else {
|
||||
for (i = 0; i < img_height; i++) {
|
||||
memcpy(tmp_stacked_ptr, tmp_hst_ptr, img_width * surf_info->bytes_per_pixel);
|
||||
tmp_hst_ptr += output_stride;
|
||||
tmp_stacked_ptr += img_width * surf_info->bytes_per_pixel;
|
||||
}
|
||||
}
|
||||
// Chroma
|
||||
int img_width_chroma = img_width >> 1;
|
||||
tmp_hst_ptr = hst_ptr + output_stride * surf_info->output_vstride;
|
||||
if (surf_info->mem_type == OUT_SURFACE_MEM_DEV_INTERNAL) {
|
||||
tmp_hst_ptr += ((disp_rect_.top >> 1) * output_stride) + (disp_rect_.left * surf_info->bytes_per_pixel);
|
||||
}
|
||||
tmp_stacked_ptr = stacked_ptr + img_width * surf_info->bytes_per_pixel * img_height; // Cb
|
||||
uint8_t *tmp_stacked_ptr_v = tmp_stacked_ptr + img_width_chroma * surf_info->bytes_per_pixel * chroma_height_; // Cr
|
||||
for (i = 0; i < chroma_height_; i++) {
|
||||
for ( int j = 0; j < img_width_chroma; j++) {
|
||||
uint8_t *src_ptr, *dst_ptr;
|
||||
// Cb
|
||||
src_ptr = &tmp_hst_ptr[j * surf_info->bytes_per_pixel * 2];
|
||||
dst_ptr = &tmp_stacked_ptr[j * surf_info->bytes_per_pixel];
|
||||
memcpy(dst_ptr, src_ptr, surf_info->bytes_per_pixel);
|
||||
// Cr
|
||||
src_ptr += surf_info->bytes_per_pixel;
|
||||
dst_ptr = &tmp_stacked_ptr_v[j * surf_info->bytes_per_pixel];
|
||||
memcpy(dst_ptr, src_ptr, surf_info->bytes_per_pixel);
|
||||
}
|
||||
tmp_hst_ptr += output_stride;
|
||||
tmp_stacked_ptr += img_width_chroma * surf_info->bytes_per_pixel;
|
||||
tmp_stacked_ptr_v += img_width_chroma * surf_info->bytes_per_pixel;
|
||||
}
|
||||
|
||||
int img_size = img_width * surf_info->bytes_per_pixel * (img_height + chroma_height_);
|
||||
|
||||
// For 10 bit, convert from P010 to little endian to match reference decoder output
|
||||
if (surf_info->bytes_per_pixel == 2) {
|
||||
uint16_t *ptr = reinterpret_cast<uint16_t *> (stacked_ptr);
|
||||
for (i = 0; i < img_size / 2; i++) {
|
||||
ptr[i] = ptr[i] >> 6;
|
||||
}
|
||||
}
|
||||
|
||||
av_md5_update(md5_ctx_, stacked_ptr, img_size);
|
||||
|
||||
if (hst_ptr && (surf_info->mem_type != OUT_SURFACE_MEM_HOST_COPIED)) {
|
||||
delete [] hst_ptr;
|
||||
}
|
||||
delete [] stacked_ptr;
|
||||
}
|
||||
|
||||
void RocVideoDecoder::FinalizeMd5(uint8_t **digest) {
|
||||
av_md5_final(md5_ctx_, md5_digest_);
|
||||
av_freep(&md5_ctx_);
|
||||
*digest = md5_digest_;
|
||||
}
|
||||
|
||||
void RocVideoDecoder::GetDeviceinfo(std::string &device_name, std::string &gcn_arch_name, int &pci_bus_id, int &pci_domain_id, int &pci_device_id) {
|
||||
device_name = hip_dev_prop_.name;
|
||||
gcn_arch_name = hip_dev_prop_.gcnArchName;
|
||||
|
||||
@@ -37,10 +37,6 @@ THE SOFTWARE.
|
||||
#include <unordered_map>
|
||||
#include <chrono>
|
||||
#include <hip/hip_runtime.h>
|
||||
extern "C" {
|
||||
#include "libavutil/md5.h"
|
||||
#include "libavutil/mem.h"
|
||||
}
|
||||
#include "rocdecode.h"
|
||||
#include "rocparser.h"
|
||||
|
||||
@@ -181,16 +177,18 @@ typedef struct DecFrameBuffer_ {
|
||||
|
||||
|
||||
typedef struct OutputSurfaceInfoType {
|
||||
uint32_t output_width; /**< Output width of decoded surface*/
|
||||
uint32_t output_height; /**< Output height of decoded surface*/
|
||||
uint32_t output_pitch; /**< Output pitch in bytes of luma plane, chroma pitch can be inferred based on chromaFormat*/
|
||||
uint32_t output_vstride; /**< Output vertical stride in case of using internal mem pointer **/
|
||||
uint32_t bytes_per_pixel; /**< Output BytesPerPixel of decoded image*/
|
||||
uint32_t bit_depth; /**< Output BitDepth of the image*/
|
||||
uint32_t num_chroma_planes; /**< Output Chroma number of planes*/
|
||||
uint64_t output_surface_size_in_bytes; /**< Output Image Size in Bytes; including both luma and chroma planes*/
|
||||
rocDecVideoSurfaceFormat surface_format; /**< Chroma format of the decoded image*/
|
||||
OutputSurfaceMemoryType mem_type; /**< Output mem_type of the surface*/
|
||||
uint32_t output_width; /**< Output width of decoded surface*/
|
||||
uint32_t output_height; /**< Output height of decoded surface*/
|
||||
uint32_t output_pitch; /**< Output pitch in bytes of luma plane, chroma pitch can be inferred based on chromaFormat*/
|
||||
uint32_t output_vstride; /**< Output vertical stride in case of using internal mem pointer **/
|
||||
uint32_t chroma_height; /**< Chroma plane height **/
|
||||
Rect disp_rect; /**< Display area **/
|
||||
uint32_t bytes_per_pixel; /**< Output BytesPerPixel of decoded image*/
|
||||
uint32_t bit_depth; /**< Output BitDepth of the image*/
|
||||
uint32_t num_chroma_planes; /**< Output Chroma number of planes*/
|
||||
uint64_t output_surface_size_in_bytes; /**< Output Image Size in Bytes; including both luma and chroma planes*/
|
||||
rocDecVideoSurfaceFormat surface_format; /**< Chroma format of the decoded image*/
|
||||
OutputSurfaceMemoryType mem_type; /**< Output mem_type of the surface*/
|
||||
} OutputSurfaceInfo;
|
||||
|
||||
typedef struct ReconfigParams_t {
|
||||
@@ -371,27 +369,6 @@ class RocVideoDecoder {
|
||||
*/
|
||||
virtual void ResetSaveFrameToFile();
|
||||
|
||||
/**
|
||||
* @brief Helper function to start MD5 calculation
|
||||
*/
|
||||
void InitMd5();
|
||||
|
||||
void UpdateMd5ForDataBuffer(void *pDevMem, int rgb_image_size);
|
||||
|
||||
/**
|
||||
* @brief Helper function to dump decoded output surface to file
|
||||
*
|
||||
* @param dev_mem - pointer to surface memory
|
||||
* @param surf_info - surface info
|
||||
*/
|
||||
void UpdateMd5ForFrame(void *surf_mem, OutputSurfaceInfo *surf_info);
|
||||
|
||||
/**
|
||||
* @brief Helper function to complete MD5 calculation
|
||||
*
|
||||
* @param [out] digest Pointer to the 16 byte message digest
|
||||
*/
|
||||
void FinalizeMd5(uint8_t **digest);
|
||||
/**
|
||||
* @brief Get the Num Of Flushed Frames from video decoder object
|
||||
*
|
||||
@@ -542,8 +519,6 @@ class RocVideoDecoder {
|
||||
Rect crop_rect_ = {}; // user specified region of interest within diplayable area disp_rect_
|
||||
FILE *fp_sei_ = NULL;
|
||||
FILE *fp_out_ = NULL;
|
||||
struct AVMD5 *md5_ctx_;
|
||||
uint8_t md5_digest_[16];
|
||||
bool is_decoder_reconfigured_ = false;
|
||||
std::string current_output_filename = "";
|
||||
uint32_t extra_output_file_count_ = 0;
|
||||
|
||||
Yeni konuda referans
Bir kullanıcı engelle