rocDecode resize sample implementation (#285)

* WIP: resize kernels

* hipified kernels for scaling from cuda

* updated videodecodeRGB sample for scaling

* added stream parameter to kernels

* add scale kernels using tex2d and NN

* enable tex2D kernels

* add NN resize kernels

* fixed scaling kernels

* fixed tex2D scaling kernel for UV scaling

* minor formatting

* address review comments

---------

Co-authored-by: Aryan Salmanpour <aryan.salmanpour@amd.com>

[ROCm/rocdecode commit: 39e274d02d]
Cette révision appartient à :
Rajy Rawther
2024-03-18 05:32:19 -07:00
révisé par GitHub
Parent f5c3feacfe
révision 5ac584fad5
5 fichiers modifiés avec 509 ajouts et 17 suppressions
+3 -1
Voir le fichier
@@ -87,7 +87,9 @@ if(HIP_FOUND AND FFMPEG_FOUND AND ROCDECODE_FOUND)
list(APPEND SOURCES ${PROJECT_SOURCE_DIR}
videodecrgb.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../utils/rocvideodecode/roc_video_dec.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../utils/colorspace_kernels.cpp)
${CMAKE_CURRENT_SOURCE_DIR}/../../utils/colorspace_kernels.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../utils/resize_kernels.cpp)
add_executable(${PROJECT_NAME} ${SOURCES})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17")
target_link_libraries(${PROJECT_NAME} ${LINK_LIBRARY_LIST})
+71 -16
Voir le fichier
@@ -40,6 +40,7 @@ THE SOFTWARE.
#include "video_demuxer.h"
#include "roc_video_dec.h"
#include "colorspace_kernels.h"
#include "resize_kernels.h"
FILE *fpOut = nullptr;
enum OutputFormatEnum {
@@ -158,34 +159,70 @@ std::queue<uint8_t*> frame_queue[frame_buffers_size];
std::mutex mutex[frame_buffers_size];
std::condition_variable cv[frame_buffers_size];
void ColorSpaceConversionThread(std::atomic<bool>& continue_processing, bool convert_to_rgb, OutputSurfaceInfo **surf_info, OutputFormatEnum e_output_format,
uint8_t *p_rgb_dev_mem, bool dump_output_frames, std::string &output_file_path, RocVideoDecoder &viddec) {
size_t rgb_image_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) {
size_t rgb_image_size, resize_image_size;
hipError_t hip_status = hipSuccess;
int current_frame_index = 0;
uint8_t *frame;
while (continue_processing || !frame_queue[current_frame_index].empty()) {
OutputSurfaceInfo *p_surf_info;
uint8_t *out_frame;
{
std::unique_lock<std::mutex> lock(mutex[current_frame_index]);
cv[current_frame_index].wait(lock, [&] {return !frame_queue[current_frame_index].empty() || !continue_processing;});
if (!continue_processing && frame_queue[current_frame_index].empty()) {
break;
}
p_surf_info = *surf_info;
// Get the current frame at the curren_buffer index for processing
frame = frame_queue[current_frame_index].front();
frame_queue[current_frame_index].pop();
out_frame = frame;
}
if (p_resize_dim->w && p_resize_dim->h && *res_surf_info) {
// check if the resize dims are different from output dims
// resize is needed since output dims are different from resize dims
// TODO:: the below code assumes NV12/P016 for decoded output surface. Modify to take other surface formats in future
if (((*surf_info)->output_width != p_resize_dim->w) || ((*surf_info)->output_height != p_resize_dim->h)) {
resize_image_size = p_resize_dim->w * (p_resize_dim->h + (p_resize_dim->h >> 1)) * (*surf_info)->bytes_per_pixel;
if (p_resize_dev_mem == nullptr && resize_image_size > 0) {
hip_status = hipMalloc(&p_resize_dev_mem, resize_image_size);
if (hip_status != hipSuccess) {
std::cerr << "ERROR: hipMalloc failed to allocate the device memory for the output!" << hip_status << std::endl;
return;
}
}
// call resize kernel
if ((*surf_info)->bytes_per_pixel == 2) {
ResizeP016(p_resize_dev_mem, p_resize_dim->w * 2, p_resize_dim->w, p_resize_dim->h, frame, (*surf_info)->output_pitch, (*surf_info)->output_width,
(*surf_info)->output_height, (frame + (*surf_info)->output_vstride * (*surf_info)->output_pitch), nullptr, viddec.GetStream());
} else {
ResizeNv12(p_resize_dev_mem, p_resize_dim->w, p_resize_dim->w, p_resize_dim->h, frame, (*surf_info)->output_pitch, (*surf_info)->output_width,
(*surf_info)->output_height, (frame + (*surf_info)->output_vstride * (*surf_info)->output_pitch), nullptr, viddec.GetStream());
}
(*res_surf_info)->output_width = p_resize_dim->w;
(*res_surf_info)->output_height = p_resize_dim->h;
(*res_surf_info)->output_pitch = p_resize_dim->w * (*surf_info)->bytes_per_pixel;
(*res_surf_info)->output_vstride = p_resize_dim->h;
(*res_surf_info)->output_surface_size_in_bytes = (*res_surf_info)->output_pitch * (p_resize_dim->h + (p_resize_dim->h >> 1));
(*res_surf_info)->mem_type = OUT_SURFACE_MEM_DEV_COPIED;
p_surf_info = *res_surf_info;
out_frame = p_resize_dev_mem;
}
}
if (convert_to_rgb) {
int rgb_width;
if ((*surf_info)->bit_depth == 8) {
rgb_width = ((*surf_info)->output_width + 1) & ~1; // has to be a multiple of 2 for hip colorconvert kernels
rgb_image_size = ((e_output_format == bgr) || (e_output_format == rgb)) ? rgb_width * (*surf_info)->output_height * 3 : rgb_width * (*surf_info)->output_height * 4;
if (p_surf_info->bit_depth == 8) {
rgb_width = (p_surf_info->output_width + 1) & ~1; // has to be a multiple of 2 for hip colorconvert kernels
rgb_image_size = ((e_output_format == bgr) || (e_output_format == rgb)) ? rgb_width * p_surf_info->output_height * 3 : rgb_width * p_surf_info->output_height * 4;
} else {
rgb_width = ((*surf_info)->output_width + 1) & ~1;
rgb_image_size = ((e_output_format == bgr) || (e_output_format == rgb)) ? rgb_width * (*surf_info)->output_height * 3 : ((e_output_format == bgr48) || (e_output_format == rgb48)) ?
rgb_width * (*surf_info)->output_height * 6 : rgb_width * (*surf_info)->output_height * 8;
rgb_width = (p_surf_info->output_width + 1) & ~1;
rgb_image_size = ((e_output_format == bgr) || (e_output_format == rgb)) ? rgb_width * p_surf_info->output_height * 3 : ((e_output_format == bgr48) || (e_output_format == rgb48)) ?
rgb_width * p_surf_info->output_height * 6 : rgb_width * p_surf_info->output_height * 8;
}
if (p_rgb_dev_mem == nullptr) {
hip_status = hipMalloc(&p_rgb_dev_mem, rgb_image_size);
@@ -194,18 +231,17 @@ void ColorSpaceConversionThread(std::atomic<bool>& continue_processing, bool con
return;
}
}
ColorConvertYUV2RGB(frame, *surf_info, p_rgb_dev_mem, e_output_format, viddec.GetStream());
ColorConvertYUV2RGB(out_frame, p_surf_info, p_rgb_dev_mem, e_output_format, viddec.GetStream());
}
if (dump_output_frames) {
if (convert_to_rgb)
DumpRGBImage(output_file_path, p_rgb_dev_mem, *surf_info, rgb_image_size);
DumpRGBImage(output_file_path, p_rgb_dev_mem, p_surf_info, rgb_image_size);
else
viddec.SaveFrameToFile(output_file_path, frame, *surf_info);
viddec.SaveFrameToFile(output_file_path, out_frame, p_surf_info);
}
cv[current_frame_index].notify_one();
current_frame_index = (current_frame_index + 1) % frame_buffers_size;
}
}
@@ -216,11 +252,13 @@ int main(int argc, char **argv) {
bool convert_to_rgb = false;
int device_id = 0;
Rect crop_rect = {};
Dim resize_dim = {};
Rect *p_crop_rect = nullptr;
size_t rgb_image_size;
uint32_t rgb_image_stride;
hipError_t hip_status = hipSuccess;
uint8_t *p_rgb_dev_mem = nullptr;
uint8_t *p_resize_dev_mem = nullptr;
OutputSurfaceMemoryType mem_type = OUT_SURFACE_MEM_DEV_INTERNAL;
OutputFormatEnum e_output_format = native;
int rgb_width;
@@ -268,6 +306,16 @@ int main(int argc, char **argv) {
p_crop_rect = &crop_rect;
continue;
}
if (!strcmp(argv[i], "-resize")) {
if (++i == argc || 2 != sscanf(argv[i], "%dx%d", &resize_dim.w, &resize_dim.h)) {
ShowHelpAndExit("-resize");
}
if (resize_dim.w % 2 == 1 || resize_dim.h % 2 == 1) {
std::cout << "Resizing dimensions must have width and height of even numbers" << std::endl;
exit(1);
}
continue;
}
if (!strcmp(argv[i], "-of")) {
if (++i == argc) {
ShowHelpAndExit("-of");
@@ -302,13 +350,13 @@ int main(int argc, char **argv) {
uint8_t *p_frame = nullptr;
int64_t pts = 0;
OutputSurfaceInfo *surf_info;
OutputSurfaceInfo *resize_surf_info = nullptr;
uint32_t width, height;
double total_dec_time = 0;
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), &surf_info, std::ref(e_output_format),
std::ref(p_rgb_dev_mem), std::ref(dump_output_frames), std::ref(output_file_path), std::ref(viddec));
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));
auto startTime = std::chrono::high_resolution_clock::now();
do {
@@ -318,6 +366,10 @@ int main(int argc, char **argv) {
std::cerr << "Error: Failed to get Output Image Info!" << std::endl;
break;
}
if (resize_dim.w && resize_dim.h && !resize_surf_info) {
resize_surf_info = new OutputSurfaceInfo;
memcpy(resize_surf_info, surf_info, sizeof(OutputSurfaceInfo));
}
int last_index = 0;
for (int i = 0; i < n_frames_returned; i++) {
@@ -386,6 +438,9 @@ int main(int argc, char **argv) {
std::cout << info_message << total_dec_time / n_frame << std::endl;
std::cout << "info: avg FPS: " << (n_frame / total_dec_time) * 1000 << std::endl;
}
if (resize_surf_info != nullptr) {
delete resize_surf_info;
}
} catch (const std::exception &ex) {
std::cout << ex.what() << std::endl;
exit(1);