diff --git a/projects/rocjpeg/samples/jpegDecodeBatched/jpegdecodebatched.cpp b/projects/rocjpeg/samples/jpegDecodeBatched/jpegdecodebatched.cpp index dae50032bb..a278a555f9 100644 --- a/projects/rocjpeg/samples/jpegDecodeBatched/jpegdecodebatched.cpp +++ b/projects/rocjpeg/samples/jpegDecodeBatched/jpegdecodebatched.cpp @@ -50,6 +50,19 @@ int main(int argc, char **argv) { std::vector output_images; RocJpegDecodeParams decode_params = {}; RocJpegUtils rocjpeg_utils; + std::vector base_file_names; + std::vector bad_image_indices; + std::vector valid_rocjpeg_stream_handles; + std::vector valid_subsamplings; + std::vector> valid_widths; + std::vector> valid_heights; + std::vector> valid_prior_channel_sizes; + std::vector valid_output_images; + std::vector valid_base_file_names; + uint64_t num_bad_jpegs = 0; + uint64_t num_jpegs_with_411_subsampling = 0; + uint64_t num_jpegs_with_unknown_subsampling = 0; + uint64_t num_jpegs_with_unsupported_resolution = 0; RocJpegUtils::ParseCommandLine(input_path, output_file_path, save_images, device_id, rocjpeg_backend, decode_params, nullptr, &batch_size, argc, argv); @@ -82,7 +95,15 @@ int main(int argc, char **argv) { widths.resize(batch_size, std::vector(ROCJPEG_MAX_COMPONENT, 0)); heights.resize(batch_size, std::vector(ROCJPEG_MAX_COMPONENT, 0)); subsamplings.resize(batch_size); - std::vector base_file_names(batch_size); + base_file_names.resize(batch_size); + valid_rocjpeg_stream_handles.resize(batch_size); + valid_output_images.resize(batch_size); + valid_prior_channel_sizes.resize(batch_size, std::vector(ROCJPEG_MAX_COMPONENT, 0)); + valid_widths.resize(batch_size, std::vector(ROCJPEG_MAX_COMPONENT, 0)); + valid_heights.resize(batch_size, std::vector(ROCJPEG_MAX_COMPONENT, 0)); + valid_subsamplings.resize(batch_size); + valid_base_file_names.resize(batch_size); + std::cout << "Decoding started, please wait! ... " << std::endl; for (int i = 0; i < file_paths.size(); i += batch_size) { int batch_end = std::min(i + batch_size, static_cast(file_paths.size())); @@ -107,7 +128,19 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } - CHECK_ROCJPEG(rocJpegStreamParse(reinterpret_cast(batch_images[index].data()), file_size, rocjpeg_stream_handles[index])); + RocJpegStatus rocjpeg_status = rocJpegStreamParse(reinterpret_cast(batch_images[index].data()), file_size, rocjpeg_stream_handles[index]); + if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) { + if (is_dir) { + bad_image_indices.push_back(index); + num_bad_jpegs++; + std::cerr << "Skipping decoding input file: " << file_paths[j] << std::endl; + continue; + } else { + std::cerr << "ERROR: Failed to parse the input jpeg stream with " << rocJpegGetErrorName(rocjpeg_status) << std::endl; + return EXIT_FAILURE; + } + } + CHECK_ROCJPEG(rocJpegGetImageInfo(rocjpeg_handle, rocjpeg_stream_handles[index], &num_components, &subsamplings[index], widths[index].data(), heights[index].data())); if (roi_width > 0 && roi_height > 0 && roi_width <= widths[index][0] && roi_height <= heights[index][0]) { @@ -116,21 +149,30 @@ int main(int argc, char **argv) { rocjpeg_utils.GetChromaSubsamplingStr(subsamplings[index], chroma_sub_sampling); if (widths[index][0] < 64 || heights[index][0] < 64) { - std::cerr << "The image resolution is not supported by VCN Hardware" << std::endl; if (is_dir) { - std::cout << std::endl; + bad_image_indices.push_back(index); + num_jpegs_with_unsupported_resolution++; continue; - } else + } else { + std::cerr << "The image resolution is not supported by VCN Hardware" << std::endl; return EXIT_FAILURE; + } } if (subsamplings[index] == ROCJPEG_CSS_411 || subsamplings[index] == ROCJPEG_CSS_UNKNOWN) { - std::cerr << "The chroma sub-sampling is not supported by VCN Hardware" << std::endl; if (is_dir) { - std::cout << std::endl; - continue; - } else + bad_image_indices.push_back(index); + if (subsamplings[index] == ROCJPEG_CSS_411) { + num_jpegs_with_411_subsampling++; + } + if (subsamplings[index] == ROCJPEG_CSS_UNKNOWN) { + num_jpegs_with_unknown_subsampling++; + } + continue; + } else { + std::cerr << "The chroma sub-sampling is not supported by VCN Hardware" << std::endl; return EXIT_FAILURE; + } } if (rocjpeg_utils.GetChannelPitchAndSizes(decode_params, subsamplings[index], widths[index].data(), heights[index].data(), num_channels, output_images[index], channel_sizes)) { @@ -150,16 +192,50 @@ int main(int argc, char **argv) { } } } - int current_batch_size = batch_end - i; + int current_batch_size = batch_end - i - bad_image_indices.size(); - auto start_time = std::chrono::high_resolution_clock::now(); - CHECK_ROCJPEG(rocJpegDecodeBatched(rocjpeg_handle, rocjpeg_stream_handles.data(), current_batch_size, &decode_params, output_images.data())); - auto end_time = std::chrono::high_resolution_clock::now(); - double time_per_batch_in_milli_sec = std::chrono::duration(end_time - start_time).count(); + // Select valid images for decoding + if (current_batch_size > 0) { + if (!bad_image_indices.empty()) { + // Iterate through the batch images and select only the valid ones + int valid_idx = 0; + for (int idx = 0; idx < batch_size; idx++) { + // Check if the current image index is not in the list of bad image indices + if (std::find(bad_image_indices.begin(), bad_image_indices.end(), idx) == bad_image_indices.end()) { + // Add the valid image index to the corresponding vectors + valid_rocjpeg_stream_handles[valid_idx] = rocjpeg_stream_handles[idx]; + valid_subsamplings[valid_idx] = subsamplings[idx]; + valid_widths[valid_idx] = widths[idx]; + valid_heights[valid_idx] = heights[idx]; + valid_prior_channel_sizes[valid_idx] = prior_channel_sizes[idx]; + valid_output_images[valid_idx] = output_images[idx]; + valid_base_file_names[valid_idx] = base_file_names[idx]; + valid_idx++; + } + } + } else { + // If there are no bad images, select all the batch images + valid_rocjpeg_stream_handles = rocjpeg_stream_handles; + valid_subsamplings = subsamplings; + valid_widths = widths; + valid_heights = heights; + valid_prior_channel_sizes = prior_channel_sizes; + valid_output_images = output_images; + valid_base_file_names = base_file_names; + } + } + + double time_per_batch_in_milli_sec = 0; + if (current_batch_size > 0) { + auto start_time = std::chrono::high_resolution_clock::now(); + CHECK_ROCJPEG(rocJpegDecodeBatched(rocjpeg_handle, valid_rocjpeg_stream_handles.data(), current_batch_size, &decode_params, valid_output_images.data())); + auto end_time = std::chrono::high_resolution_clock::now(); + time_per_batch_in_milli_sec = std::chrono::duration(end_time - start_time).count(); + } double image_size_in_mpixels = 0; for (int b = 0; b < current_batch_size; b++) { - image_size_in_mpixels += (static_cast(widths[b][0]) * static_cast(heights[b][0]) / 1000000); + image_size_in_mpixels += (static_cast(valid_widths[b][0]) * static_cast(valid_heights[b][0]) / 1000000); } total_images += current_batch_size; @@ -168,12 +244,12 @@ int main(int argc, char **argv) { for (int b = 0; b < current_batch_size; b++) { std::string image_save_path = output_file_path; //if ROI is present, need to pass roi_width and roi_height - uint32_t width = is_roi_valid ? roi_width : widths[b][0]; - uint32_t height = is_roi_valid ? roi_height : heights[b][0]; + uint32_t width = is_roi_valid ? roi_width : valid_widths[b][0]; + uint32_t height = is_roi_valid ? roi_height : valid_heights[b][0]; if (is_dir) { - rocjpeg_utils.GetOutputFileExt(decode_params.output_format, base_file_names[b], width, height, subsamplings[b], image_save_path); + rocjpeg_utils.GetOutputFileExt(decode_params.output_format, valid_base_file_names[b], width, height, valid_subsamplings[b], image_save_path); } - rocjpeg_utils.SaveImage(image_save_path, &output_images[b], width, height, subsamplings[b], decode_params.output_format); + rocjpeg_utils.SaveImage(image_save_path, &valid_output_images[b], width, height, valid_subsamplings[b], decode_params.output_format); } } @@ -182,10 +258,7 @@ int main(int argc, char **argv) { mpixels_all += image_size_in_mpixels; } - // Clear the batch_images vector after processing each batch - for (int j = i; j < batch_end; j++) { - batch_images[j - i].clear(); - } + bad_image_indices.clear(); } if (is_dir) { @@ -193,6 +266,22 @@ int main(int argc, char **argv) { images_per_sec = 1000 / time_per_image_all; double mpixels_per_sec = mpixels_all * images_per_sec / total_images; std::cout << "Total decoded images: " << total_images << std::endl; + if (num_bad_jpegs || num_jpegs_with_411_subsampling || num_jpegs_with_unknown_subsampling || num_jpegs_with_unsupported_resolution) { + std::cout << "Total skipped images: " << num_bad_jpegs + num_jpegs_with_411_subsampling + num_jpegs_with_unknown_subsampling + num_jpegs_with_unsupported_resolution; + if (num_bad_jpegs) { + std::cout << " ,total images that cannot be parsed: " << num_bad_jpegs; + } + if (num_jpegs_with_411_subsampling) { + std::cout << " ,total images with YUV 4:1:1 chroam subsampling: " << num_jpegs_with_411_subsampling; + } + if (num_jpegs_with_unknown_subsampling) { + std::cout << " ,total images with unknwon chroam subsampling: " << num_jpegs_with_unknown_subsampling; + } + if (num_jpegs_with_unsupported_resolution) { + std::cout << " ,total images with unsupported_resolution: " << num_jpegs_with_unsupported_resolution; + } + std::cout << std::endl; + } if (total_images) { std::cout << "Average processing time per image (ms): " << time_per_image_all << std::endl; std::cout << "Average decoded images per sec (Images/Sec): " << images_per_sec << std::endl; diff --git a/projects/rocjpeg/samples/jpegDecodeMultiThreads/jpegdecodemultithreads.cpp b/projects/rocjpeg/samples/jpegDecodeMultiThreads/jpegdecodemultithreads.cpp index 77287cb32f..d0a4a2f442 100644 --- a/projects/rocjpeg/samples/jpegDecodeMultiThreads/jpegdecodemultithreads.cpp +++ b/projects/rocjpeg/samples/jpegDecodeMultiThreads/jpegdecodemultithreads.cpp @@ -23,7 +23,8 @@ THE SOFTWARE. #include "../rocjpeg_samples_utils.h" void ThreadFunction(std::vector& jpegFiles, RocJpegHandle rocjpeg_handle, RocJpegStreamHandle rocjpeg_stream, RocJpegUtils rocjpeg_util, RocJpegImage *output_image, std::mutex &mutex, - RocJpegDecodeParams &decode_params, bool save_images, std::string &output_file_path, uint64_t *num_decoded_images, double *image_size_in_mpixels) { + RocJpegDecodeParams &decode_params, bool save_images, std::string &output_file_path, uint64_t *num_decoded_images, double *image_size_in_mpixels, uint64_t *num_bad_jpegs, uint64_t *num_jpegs_with_411_subsampling, + uint64_t *num_jpegs_with_unknown_subsampling, uint64_t *num_jpegs_with_unsupported_resolution) { bool is_roi_valid = false; uint32_t roi_width; @@ -75,22 +76,32 @@ void ThreadFunction(std::vector& jpegFiles, RocJpegHandle rocjpeg_h return; } - CHECK_ROCJPEG(rocJpegStreamParse(reinterpret_cast(file_data.data()), file_size, rocjpeg_stream)); + RocJpegStatus rocjpeg_status = rocJpegStreamParse(reinterpret_cast(file_data.data()), file_size, rocjpeg_stream); + if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) { + std::cerr << "Skipping decoding input file: " << file_path << std::endl; + *num_bad_jpegs += 1; + continue; + } + CHECK_ROCJPEG(rocJpegGetImageInfo(rocjpeg_handle, rocjpeg_stream, &num_components, &subsampling, widths, heights)); if (roi_width > 0 && roi_height > 0 && roi_width <= widths[0] && roi_height <= heights[0]) { is_roi_valid = true; } if (widths[0] < 64 || heights[0] < 64) { - std::cerr << "The image resolution is not supported by VCN Hardware" << std::endl; - std::cout << "Skipping decoding file " << base_file_name << std::endl; - return; + *num_jpegs_with_unsupported_resolution += 1; + continue; } if (subsampling == ROCJPEG_CSS_411 || subsampling == ROCJPEG_CSS_UNKNOWN) { - std::cerr << "The chroma sub-sampling is not supported by VCN Hardware" << std::endl; - std::cout << "Skipping decoding file " << base_file_name << std::endl; - return; + if (subsampling == ROCJPEG_CSS_411) { + *num_jpegs_with_411_subsampling += 1; + } + if (subsampling == ROCJPEG_CSS_UNKNOWN) { + *num_jpegs_with_unknown_subsampling += 1; + } + + continue; } if (rocjpeg_util.GetChannelPitchAndSizes(decode_params, subsampling, widths, heights, num_channels, *output_image, channel_sizes)) { @@ -150,6 +161,10 @@ int main(int argc, char **argv) { std::vector rocjpeg_images; RocJpegUtils rocjpeg_utils; std::vector threads; + std::vector num_bad_jpegs; + std::vector num_jpegs_with_411_subsampling; + std::vector num_jpegs_with_unknown_subsampling; + std::vector num_jpegs_with_unsupported_resolution; RocJpegUtils::ParseCommandLine(input_path, output_file_path, save_images, device_id, rocjpeg_backend, decode_params, &num_threads, nullptr, argc, argv); if (!RocJpegUtils::GetFilePaths(input_path, file_paths, is_dir, is_file)) { @@ -177,12 +192,16 @@ int main(int argc, char **argv) { num_decoded_images_per_thread.resize(num_threads, 0); image_size_in_mpixels_per_thread.resize(num_threads, 0); rocjpeg_images.resize(num_threads, {0}); + num_bad_jpegs.resize(num_threads, 0); + num_jpegs_with_411_subsampling.resize(num_threads, 0); + num_jpegs_with_unknown_subsampling.resize(num_threads, 0); + num_jpegs_with_unsupported_resolution.resize(num_threads, 0); std::cout << "Decoding started with " << num_threads << " threads, please wait!" << std::endl; auto start_time = std::chrono::high_resolution_clock::now(); for (int i = 0; i < num_threads; ++i) { threads.emplace_back(ThreadFunction, std::ref(file_paths), rocjpeg_handles[i], rocjpeg_streams[i], rocjpeg_utils, &rocjpeg_images[i], std::ref(mutex), std::ref(decode_params), save_images, std::ref(output_file_path), - &num_decoded_images_per_thread[i], &image_size_in_mpixels_per_thread[i]); + &num_decoded_images_per_thread[i], &image_size_in_mpixels_per_thread[i], &num_bad_jpegs[i], &num_jpegs_with_411_subsampling[i], &num_jpegs_with_unknown_subsampling[i], &num_jpegs_with_unsupported_resolution[i]); } for (auto& thread : threads) { thread.join(); @@ -192,9 +211,18 @@ int main(int argc, char **argv) { uint64_t total_decoded_images = 0; double total_image_size_in_mpixels = 0; + uint64_t total_num_bad_jpegs = 0; + uint64_t total_num_jpegs_with_411_subsampling = 0; + uint64_t total_num_jpegs_with_unknown_subsampling = 0; + uint64_t total_num_jpegs_with_unsupported_resolution = 0; + for (auto i = 0 ; i < num_threads; i++) { total_decoded_images += num_decoded_images_per_thread[i]; total_image_size_in_mpixels += image_size_in_mpixels_per_thread[i]; + total_num_bad_jpegs += num_bad_jpegs[i]; + total_num_jpegs_with_411_subsampling += num_jpegs_with_411_subsampling[i]; + total_num_jpegs_with_unknown_subsampling += num_jpegs_with_unknown_subsampling[i]; + total_num_jpegs_with_unsupported_resolution += num_jpegs_with_unsupported_resolution[i]; for (int j = 0; j < ROCJPEG_MAX_COMPONENT; j++) { if (rocjpeg_images[i].channel[j] != nullptr) { CHECK_HIP(hipFree((void *)rocjpeg_images[i].channel[j])); @@ -208,9 +236,28 @@ int main(int argc, char **argv) { double avg_image_size_in_mpixels_per_sec = total_image_size_in_mpixels * avg_images_per_sec / total_decoded_images; std::cout << "Total elapsed time (ms): " << total_time_in_milli_sec << std::endl; std::cout << "Total decoded images: " << total_decoded_images << std::endl; - std::cout << "Average processing time per image (ms): " << average_decoding_time_in_milli_sec << std::endl; - std::cout << "Average decoded images per sec (Images/Sec): " << avg_images_per_sec << std::endl; - std::cout << "Average decoded images size (Mpixels/Sec): " << avg_image_size_in_mpixels_per_sec << std::endl; + if (total_num_bad_jpegs || total_num_jpegs_with_411_subsampling || total_num_jpegs_with_unknown_subsampling || total_num_jpegs_with_unsupported_resolution) { + std::cout << "Total skipped images: " << total_num_bad_jpegs + total_num_jpegs_with_411_subsampling + total_num_jpegs_with_unknown_subsampling + total_num_jpegs_with_unsupported_resolution; + if (total_num_bad_jpegs) { + std::cout << " ,total images that cannot be parsed: " << total_num_bad_jpegs; + } + if (total_num_jpegs_with_411_subsampling) { + std::cout << " ,total images with YUV 4:1:1 chroam subsampling: " << total_num_jpegs_with_411_subsampling; + } + if (total_num_jpegs_with_unknown_subsampling) { + std::cout << " ,total images with unknwon chroam subsampling: " << total_num_jpegs_with_unknown_subsampling; + } + if (total_num_jpegs_with_unsupported_resolution) { + std::cout << " ,total images with unsupported_resolution: " << total_num_jpegs_with_unsupported_resolution; + } + std::cout << std::endl; + } + + if (total_decoded_images > 0) { + std::cout << "Average processing time per image (ms): " << average_decoding_time_in_milli_sec << std::endl; + std::cout << "Average decoded images per sec (Images/Sec): " << avg_images_per_sec << std::endl; + std::cout << "Average decoded images size (Mpixels/Sec): " << avg_image_size_in_mpixels_per_sec << std::endl; + } for (auto& handle : rocjpeg_handles) { CHECK_ROCJPEG(rocJpegDestroy(handle)); diff --git a/projects/rocjpeg/samples/rocjpeg_samples_utils.h b/projects/rocjpeg/samples/rocjpeg_samples_utils.h index 01261ffd1a..b7cfadb101 100644 --- a/projects/rocjpeg/samples/rocjpeg_samples_utils.h +++ b/projects/rocjpeg/samples/rocjpeg_samples_utils.h @@ -30,6 +30,7 @@ THE SOFTWARE. #include #include #include +#include #if __cplusplus >= 201703L && __has_include() #include namespace fs = std::filesystem;