Add 'projects/rocjpeg/' from commit '06a08d3cb83b7e77555ff2baebedfe4e52fa5dbb'

git-subtree-dir: projects/rocjpeg
git-subtree-mainline: d0396f30b3
git-subtree-split: 06a08d3cb8
This commit is contained in:
Ameya Keshava Mallya
2026-01-30 20:35:04 +00:00
förälder d0396f30b3 06a08d3cb8
incheckning f4f1df295a
72 ändrade filer med 14794 tillägg och 0 borttagningar
+44
Visa fil
@@ -0,0 +1,44 @@
resources:
repositories:
- repository: pipelines_repo
type: github
endpoint: ROCm
name: ROCm/ROCm
variables:
- group: common
- template: /.azuredevops/variables-global.yml@pipelines_repo
trigger:
batch: true
branches:
include:
- develop
- mainline
paths:
exclude:
- .github
- .jenkins
- docs
- '.*.y*ml'
- '*.md'
- LICENSE
pr:
autoCancel: true
branches:
include:
- develop
- mainline
paths:
exclude:
- .github
- .jenkins
- docs
- '.*.y*ml'
- '*.md'
- LICENSE
drafts: false
jobs:
- template: ${{ variables.CI_COMPONENT_PATH }}/rocJPEG.yml@pipelines_repo
+6
Visa fil
@@ -0,0 +1,6 @@
* @AryanSalmanpour @rrawther @kiritigowda
# Documentation files
docs/ @ROCm/rocm-documentation
*.md @ROCm/rocm-documentation
*.rst @ROCm/rocm-documentation
.readthedocs.yaml @ROCm/rocm-documentation
+18
Visa fil
@@ -0,0 +1,18 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "pip" # See documentation for possible values
directory: "/docs/sphinx" # Location of package manifests
open-pull-requests-limit: 10
schedule:
interval: "daily"
target-branch: "develop"
labels:
- "dependencies"
- "ci:docs-only"
reviewers:
- "samjwu"
+6
Visa fil
@@ -0,0 +1,6 @@
build/
samples/*/build
.vscode/
doxygen_output*
_doxygen/
api/rocjpeg_version.h
+18
Visa fil
@@ -0,0 +1,18 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
version: 2
sphinx:
configuration: docs/conf.py
formats: [htmlzip]
python:
install:
- requirements: docs/sphinx/requirements.txt
build:
os: ubuntu-22.04
tools:
python: "3.10"
+68
Visa fil
@@ -0,0 +1,68 @@
# rocJPEG changelog
Documentation for rocJPEG is available at
[https://rocm.docs.amd.com/projects/rocJPEG/en/latest/](https://rocm.docs.amd.com/projects/rocJPEG/en/latest/)
## rocJPEG 1.3.0 for ROCm 7.2.0
## Changed
* Updated libdrm path configuration and libva version requirements for ROCm and TheRock platforms
* RHEL now uses `libva-devel` instead of `libva-amdgpu`/`libva-amdgpu-devel`
* Use ROCm clang++ from `${ROCM_PATH}/lib/llvm/bin` location
## rocjpeg 1.2.0 for ROCm 7.1.0
## Changed
* HIP meta package changed - Use hip-dev/devel to bring required hip dev deps
### Resolved issues
* Fixed an issue where extra padding was incorrectly included when saving decoded JPEG images to files.
* Resolved a memory leak in the jpegDecode application.
## rocjpeg 1.1.0 for ROCm 7.0.0
## Added
* cmake config files
* CTEST - New tests were introduced for JPEG batch decoding using various output formats, such as yuv_planar, y, rgb, and rgb_planar, both with and without region-of-interest (ROI).
## Changed
* Readme - cleanup and updates to pre-reqs
* The `decode_params` argument of the `rocJpegDecodeBatched` API is now an array of `RocJpegDecodeParams` structs representing the decode parameters for the batch of JPEG images.
* `libdrm_amdgpu` is now explicitly linked with rocjpeg.
## Removed
* Dev Package - No longer installs pkg-config
### Resolved issues
* Fixed a bug that prevented copying the decoded image into the output buffer when the output buffer is larger than the input image.
* Resolved an issue with resizing the internal memory pool by utilizing the explicit constructor of the vector's type during the resizing process.
* Addressed and resolved CMake configuration warnings.
## rocJPEG 0.8.0 for ROCm 6.4
### Changed
* AMD Clang++ is now the default CXX compiler.
* The jpegDecodeMultiThreads sample has been renamed to jpegDecodePerf, and batch decoding has been added to this sample instead of single image decoding for improved performance.
## rocJPEG 0.6.0 for ROCm 6.3.0
### Changes
* Supported initial enablement of the rocJPEG library
* Supported JPEG chroma subsampling:
* YUV 4:4:4
* YUV 4:4:0
* YUV 4:2:2
* YUV 4:2:0
* YUV 4:0:0
* Supported various output image format:
* Native (i.e., native unchanged output from VCN Hardware, it can be either packed YUV or planar YUV)
* YUV planar
* Y only
* RGB
* RGB planar
* Supported single-image and batch-image decoding
* Supported Different partition modes on MI300 series
* Supported region-of-interest (ROI) decoding
* Supported color space conversion from YUV to RGB
+522
Visa fil
@@ -0,0 +1,522 @@
# ##############################################################################
# Copyright (c) 2024 - 2026 Advanced Micro Devices, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# ##############################################################################
cmake_minimum_required(VERSION 3.10)
# ROCM Path
if(DEFINED ENV{ROCM_PATH})
set(ROCM_PATH $ENV{ROCM_PATH} CACHE PATH "Default ROCm installation path")
elseif(ROCM_PATH)
message("-- INFO:ROCM_PATH Set -- ${ROCM_PATH}")
else()
set(ROCM_PATH /opt/rocm CACHE PATH "Default ROCm installation path")
endif()
# Check if lib/rocm_sysdeps/lib exists in the ROCm path which indicates ROCm installation via TheRock
set(USING_THE_ROCK OFF)
if(EXISTS "${ROCM_PATH}/lib/rocm_sysdeps/lib")
set(USING_THE_ROCK ON)
endif()
if(USING_THE_ROCK)
if(NOT DEFINED ENV{HIP_DEVICE_LIB_PATH})
set(ENV{HIP_DEVICE_LIB_PATH} ${ROCM_PATH}/lib/llvm/amdgcn/bitcode)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "HIP_DEVICE_LIB_PATH=${ROCM_PATH}/lib/llvm/amdgcn/bitcode")
endif()
endif()
# Set AMD Clang as default compiler
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED On)
set(CMAKE_CXX_EXTENSIONS ON)
if(NOT DEFINED CMAKE_CXX_COMPILER)
set(CMAKE_C_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang)
set(CMAKE_CXX_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang++)
endif()
# rocjpeg Version
# NOTE: package version and rocjpeg_version.h is generated with this version
set(VERSION "1.4.0")
# Set Project Version and Language
project(rocjpeg VERSION ${VERSION} LANGUAGES CXX)
set(CMAKE_INSTALL_LIBDIR "lib" CACHE STRING "Library install directory")
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE STRING "Include install directory")
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
find_program(MAKE_NSIS_EXE makensis)
find_program(RPMBUILD_EXE rpmbuild)
find_program(DPKG_EXE dpkg)
# avoid setting the default installation path to /usr/local
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX ${ROCM_PATH} CACHE PATH "rocjpeg default installation path" FORCE)
endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(DEFAULT_BUILD_TYPE "Release")
set(ENHANCED_MESSAGE ON)
if(ENHANCED_MESSAGE)
string(ASCII 27 Esc)
set(ColourReset "${Esc}[m")
set(Red "${Esc}[31m")
set(Green "${Esc}[32m")
set(Yellow "${Esc}[33m")
set(Blue "${Esc}[34m")
set(BoldBlue "${Esc}[1;34m")
set(Magenta "${Esc}[35m")
set(Cyan "${Esc}[36m")
set(White "${Esc}[37m")
endif()
message("-- ${BoldBlue}rocjpeg Version -- ${VERSION}${ColourReset}")
message("-- ${BoldBlue}rocjpeg Install Path -- ${CMAKE_INSTALL_PREFIX}${ColourReset}")
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
list(APPEND CMAKE_PREFIX_PATH ${ROCM_PATH}/lib/cmake ${ROCM_PATH}/share/rocmcmakebuildtools/cmake)
# rocjpeg Default Options
option(BUILD_WITH_AMD_ADVANCE "Build rocjpeg for advanced AMD GPU Architecture" OFF)
# rocjpeg Build Type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "rocjpeg Default Build Type" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
endif()
# Set supported GPU Targets
if(NOT GPU_TARGETS AND NOT AMDGPU_TARGETS)
find_package(ROCmCMakeBuildTools QUIET)
if(NOT ROCmCMakeBuildTools_FOUND)
find_package(ROCM QUIET)
endif()
include(ROCMCheckTargetIds OPTIONAL RESULT_VARIABLE HAS_ROCM_CHECK_TARGET_IDS)
set(OPTIONAL_GPU_TARGETS "gfx950;gfx1151;gfx1200;gfx1201")
if(HAS_ROCM_CHECK_TARGET_IDS)
rocm_check_target_ids(OPTIONAL_GPU_TARGETS_AVAILABLE TARGETS ${OPTIONAL_GPU_TARGETS})
else() # if we don't have rocm_check_target_ids, just assume the targets are available
set(OPTIONAL_GPU_TARGETS_AVAILABLE "${OPTIONAL_GPU_TARGETS}")
endif()
set(DEFAULT_GPU_TARGETS "gfx908;gfx90a;gfx942;gfx1030;gfx1031;gfx1032;gfx1100;gfx1101;gfx1102;${OPTIONAL_GPU_TARGETS_AVAILABLE}")
endif()
# Set AMD GPU_TARGETS
if((AMDGPU_TARGETS OR DEFINED ENV{AMDGPU_TARGETS}) AND (NOT GPU_TARGETS))
message("-- ${Red}${PROJECT_NAME} DEPRECATION -- AMDGPU_TARGETS use is deprecated. Use GPU_TARGETS${ColourReset}")
if(DEFINED ENV{AMDGPU_TARGETS})
set(GPU_TARGETS $ENV{AMDGPU_TARGETS} CACHE STRING "List of specific machine types for library to target")
else()
set(GPU_TARGETS ${AMDGPU_TARGETS})
endif()
endif()
if(DEFINED ENV{GPU_ARCHS})
set(GPU_TARGETS $ENV{GPU_ARCHS} CACHE STRING "List of specific machine types for library to target")
elseif(GPU_TARGETS)
message("-- ${White}${PROJECT_NAME} -- GPU_TARGETS set with -D option${ColourReset}")
else()
set(GPU_TARGETS "${DEFAULT_GPU_TARGETS}" CACHE STRING "List of specific machine types for library to target")
endif()
message("-- ${White}${PROJECT_NAME} -- AMD GPU_TARGETS: ${GPU_TARGETS}${ColourReset}")
# Add an option for enabling the rocprofiler-register
option(ROCJPEG_ENABLE_ROCPROFILER_REGISTER "Enable rocprofiler-register support" ON)
set (HIP_PLATFORM amd CACHE STRING "HIP platform")
find_package(HIP QUIET)
find_package(Libva QUIET)
find_package(Libdrm_amdgpu QUIET)
# Find Ubuntu 22.04
file(READ "/etc/os-release" OS_RELEASE)
string(REGEX MATCH "22.04" UBUNTU_22_FOUND ${OS_RELEASE})
# Check Libva version compatibility based on installation method and OS:
# - Ubuntu 22.04 with standard ROCm installation: requires libva >= 1.16
# - Other OS versions with standard ROCm: libva >= 1.8 is sufficient
# - TheRock installation (any OS): libva >= 1.8 is sufficient
if(Libva_FOUND)
if(UBUNTU_22_FOUND AND NOT USING_THE_ROCK)
if((${Libva_VERSION_MAJOR} GREATER_EQUAL 1) AND (${Libva_VERSION_MINOR} GREATER_EQUAL 16))
message("-- ${White}\tLibva Version Supported${ColourReset}")
else()
set(Libva_FOUND FALSE)
message("-- ${Yellow}\tLibva Version Not Supported${ColourReset}")
endif()
else()
if((${Libva_VERSION_MAJOR} GREATER_EQUAL 1) AND (${Libva_VERSION_MINOR} GREATER_EQUAL 8))
message("-- ${White}\tLibva Version Supported${ColourReset}")
else()
set(Libva_FOUND FALSE)
message("-- ${Yellow}\tLibva Version Not Supported${ColourReset}")
endif()
endif()
endif()
if(ROCJPEG_ENABLE_ROCPROFILER_REGISTER)
find_package(rocprofiler-register QUIET
HINTS $ENV{rocprofiler_register_ROOT} $ENV{ROCPROFILER_REGISTER_ROOT} ${CMAKE_INSTALL_PREFIX}
PATHS ${ROCM_PATH})
endif()
if(HIP_FOUND AND Libva_FOUND AND Libdrm_amdgpu_FOUND)
# HIP
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} hip::device)
# LibVA
include_directories(${LIBVA_INCLUDE_DIR})
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${LIBVA_LIBRARY})
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${LIBVA_DRM_LIBRARY})
# DRM_AMDGPU
include_directories(${LIBDRM_AMDGPU_INCLUDE_DIR})
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} ${LIBDRM_AMDGPU_LIBRARY})
# rocprofiler
if(rocprofiler-register_FOUND)
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocprofiler-register::rocprofiler-register)
endif()
# local include files
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/api ${CMAKE_CURRENT_SOURCE_DIR}/src)
# source files
file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# rocjpeg.so
add_library(${PROJECT_NAME} SHARED ${SOURCES})
if(CMAKE_BUILD_TYPE MATCHES Debug)
# -O0 -- Don't Optimize output file
# -g -- generate debugging information, 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")
target_compile_options(${PROJECT_NAME} PRIVATE -O0 -gdwarf-4 -Wall)
else()
# -O3 -- Optimize output file
# -DNDEBUG -- turn off asserts
# -fPIC -- Generate position-independent code if possible
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DNDEBUG -fPIC")
target_compile_options(${PROJECT_NAME} PRIVATE -O3 -DNDEBUG -fPIC -Wall)
endif()
message("-- ${BoldBlue}rocjpeg Build Type -- ${CMAKE_BUILD_TYPE}${ColourReset}")
target_link_libraries(${PROJECT_NAME} ${LINK_LIBRARY_LIST})
set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)
set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR})
if(USING_THE_ROCK)
set_target_properties(${PROJECT_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN;$ORIGIN/rocm_sysdeps/lib" BUILD_WITH_INSTALL_RPATH TRUE)
endif()
# rocprofiler
if(rocprofiler-register_FOUND)
string(REPLACE "." ";" VERSION_LIST ${VERSION})
list(GET VERSION_LIST 0 VERSION_MAJOR)
list(GET VERSION_LIST 1 VERSION_MINOR)
list(GET VERSION_LIST 2 VERSION_PATCH)
target_compile_definitions(${PROJECT_NAME} PRIVATE ROCJPEG_ROCPROFILER_REGISTER=1
ROCJPEG_ROCP_REG_VERSION_MAJOR=${VERSION_MAJOR}
ROCJPEG_ROCP_REG_VERSION_MINOR=${VERSION_MINOR}
ROCJPEG_ROCP_REG_VERSION_PATCH=${VERSION_PATCH})
endif()
# Set a default compile option to reuse the interop buffer. Disable this option if the ROCm version is below 7.0.0.
target_compile_definitions(${PROJECT_NAME} PRIVATE ENABLE_INTEROP_BUFFER_REUSE=1)
# rocm version
set(ROCM_VERSION_FILE ${ROCM_PATH}/.info/version-rocm)
if(EXISTS "${ROCM_VERSION_FILE}")
file(READ "${ROCM_VERSION_FILE}" ROCM_VERSION_STRING)
string(STRIP "${ROCM_VERSION_STRING}" ROCM_VERSION_STRING)
message(STATUS "Full ROCm version string: ${ROCM_VERSION_STRING}")
# Match version string with regex
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)-([0-9]+)$" _ "${ROCM_VERSION_STRING}")
if(CMAKE_MATCH_COUNT GREATER 0)
set(rocm_major_version "${CMAKE_MATCH_1}")
set(rocm_minor_version "${CMAKE_MATCH_2}")
set(rocm_patch_version "${CMAKE_MATCH_3}")
set(rocm_build_number "${CMAKE_MATCH_4}")
message(STATUS "ROCm Major Version: ${rocm_major_version}")
message(STATUS "ROCm Minor Version: ${rocm_minor_version}")
message(STATUS "ROCm Patch Version: ${rocm_patch_version}")
message(STATUS "ROCm Build Number: ${rocm_build_number}")
# Convert strings to integers
math(EXPR ROCM_VERSION_INT "${rocm_major_version} * 10000 + ${rocm_minor_version} * 100 + ${rocm_patch_version}")
set(TARGET_VERSION_INT 70000)
if(ROCM_VERSION_INT LESS TARGET_VERSION_INT)
message(STATUS "ROCm version is below the required threshold (>= 7.0.0) for reusing the interop buffer, so the compile option: ENABLE_INTEROP_BUFFER_REUSE is disabled.")
target_compile_definitions(${PROJECT_NAME} PRIVATE ENABLE_INTEROP_BUFFER_REUSE=0)
endif()
endif()
endif()
#Generate BUILD_INFO
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/api/rocjpeg_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/rocjpeg_version.h @ONLY )
# install rocjpeg libs -- {ROCM_PATH}/lib
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime NAMELINK_SKIP)
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT dev NAMELINK_ONLY)
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT asan)
# install rocjpeg include files -- {ROCM_PATH}/include/rocjpeg
install(FILES api/rocjpeg/rocjpeg.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} COMPONENT dev)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/rocjpeg_version.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} COMPONENT dev)
# install rocjpeg api trace include file -- {ROCM_PATH}/include/rocjpeg/amd_detail
install(FILES api/amd_detail/rocjpeg_api_trace.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/amd_detail COMPONENT dev)
# install rocjpeg samples -- {ROCM_PATH}/share/rocjpeg
install(FILES samples/jpegDecode/CMakeLists.txt samples/jpegDecode/jpegdecode.cpp samples/jpegDecode/README.md DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/samples/jpegDecode COMPONENT dev)
install(FILES samples/jpegDecodePerf/CMakeLists.txt samples/jpegDecodePerf/jpegdecodeperf.cpp samples/jpegDecodePerf/README.md DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/samples/jpegDecodePerf COMPONENT dev)
install(FILES samples/jpegDecodeBatched/CMakeLists.txt samples/jpegDecodeBatched/jpegdecodebatched.cpp samples/jpegDecodeBatched/README.md DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/samples/jpegDecodeBatched COMPONENT dev)
install(FILES samples/rocjpeg_samples_utils.h DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/samples COMPONENT dev)
install(DIRECTORY data/images DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME} COMPONENT dev)
# install license information - {ROCM_PATH}/share/doc/rocjpeg
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
install(FILES ${CPACK_RESOURCE_FILE_LICENSE} DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT runtime)
install(FILES ${CPACK_RESOURCE_FILE_LICENSE} DESTINATION ${CMAKE_INSTALL_DOCDIR}-asan COMPONENT asan)
# install test cmake
install(FILES test/CMakeLists.txt DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/test COMPONENT test)
install(FILES test/rocjpeg_negative_api_tests/CMakeLists.txt test/rocjpeg_negative_api_tests/README.md test/rocjpeg_negative_api_tests/rocjpeg_api_negative_tests.cpp test/rocjpeg_negative_api_tests/rocjpeg_api_negative_tests.h test/rocjpeg_negative_api_tests/rocjpegnegativetest.cpp DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/test/rocjpeg_negative_api_tests COMPONENT test)
message("-- ${White}AMD ROCm rocjpeg -- CMAKE_CXX_FLAGS:${CMAKE_CXX_FLAGS}${ColourReset}")
message("-- ${White}AMD ROCm rocjpeg -- Link Libraries: ${LINK_LIBRARY_LIST}${ColourReset}")
# Cmake module config file configurations
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/" CACHE INTERNAL "Default module path.")
# Export the package for use from the build-tree
# (this registers the build-tree with a global CMake-registry)
export(PACKAGE ${PROJECT_NAME})
set(CONF_LIB_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
# Create the rocjpeg-config.cmake and rocjpeg-config-version files
include(CMakePackageConfigHelpers)
set(CONFIG_PACKAGE_INSTALL_DIR ${CONF_LIB_DIR}/cmake/${PROJECT_NAME})
set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}")
set(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
# Generate Config File for rocjpeg
configure_package_config_file(
${CMAKE_MODULE_PATH}/${PROJECT_NAME}-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
INSTALL_DESTINATION ${CONFIG_PACKAGE_INSTALL_DIR}
PATH_VARS LIB_INSTALL_DIR INCLUDE_INSTALL_DIR BIN_INSTALL_DIR
)
# Generate config Version File for rocjpeg
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
COMPATIBILITY SameMajorVersion
)
# Install the rocjpeg-config.cmake and rocjpeg-config-version.cmake
install(FILES
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
COMPONENT dev
)
# Install the export set for use with the install-tree
install(EXPORT ${PROJECT_NAME}-targets
FILE ${PROJECT_NAME}-targets.cmake
NAMESPACE ${PROJECT_NAME}::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
COMPONENT dev
)
# make test with CTest
set(BUILD_FROM_SOURCE ON)
enable_testing()
include(CTest)
add_subdirectory(test)
# set package information
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_PACKAGE_LICENSE "MIT")
set(CPACK_PACKAGE_CONTACT "rocjpeg Support <mivisionx.support@amd.com>")
set(CPACK_PACKAGE_VENDOR "AMD ROCm")
set(CPACK_PACKAGE_GROUP "Development/Tools")
set(CPACK_PACKAGE_HOMEPAGE "https://github.com/ROCm/rocjpeg")
if(ENABLE_ASAN_PACKAGING)
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "AMD rocjpeg address sanitizer libraries")
set(CPACK_RPM_PACKAGE_SUMMARY "AMD rocjpeg address sanitizer libraries")
else()
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "AMD rocjpeg is a high performance JPEG decode SDK for AMD GPUs")
set(CPACK_RPM_PACKAGE_SUMMARY "AMD rocjpeg is a high performance JPEG decode SDK for AMD GPUs")
endif()
if(DEFINED ENV{ROCM_LIBPATCH_VERSION})
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}.$ENV{ROCM_LIBPATCH_VERSION}")
endif()
# Set the dependent packages
set(rocJPEG_DEBIAN_PACKAGE_LIST "hip-runtime-amd, libva-drm2 (>= 2.16.0) | libva-amdgpu-drm2, mesa-amdgpu-va-drivers")
set(rocJPEG_RPM_PACKAGE_LIST "hip-runtime-amd, (libva or libva-drm2), mesa-amdgpu-va-drivers")
# Add rocprofiler-register dependencies
if(ROCJPEG_ENABLE_ROCPROFILER_REGISTER)
set(rocJPEG_DEBIAN_PACKAGE_LIST "${rocJPEG_DEBIAN_PACKAGE_LIST}, rocprofiler-register")
set(rocJPEG_RPM_PACKAGE_LIST "${rocJPEG_RPM_PACKAGE_LIST}, rocprofiler-register")
endif()
set(rocJPEG_DEBIAN_DEV_PACKAGE_LIST "hip-dev, libva-dev (>= 2.16.0) | libva-amdgpu-dev")
if(UBUNTU_22_FOUND)
set(rocJPEG_DEBIAN_DEV_PACKAGE_LIST "${rocJPEG_DEBIAN_DEV_PACKAGE_LIST}, libstdc++-12-dev")
endif()
set(rocJPEG_RPM_DEV_PACKAGE_LIST "hip-devel, libva-devel")
# '%{?dist}' breaks manual builds on debian systems due to empty Provides
execute_process(
COMMAND rpm --eval %{?dist}
RESULT_VARIABLE PROC_RESULT
OUTPUT_VARIABLE EVAL_RESULT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(PROC_RESULT EQUAL "0" AND NOT EVAL_RESULT STREQUAL "")
string(APPEND CPACK_RPM_PACKAGE_RELEASE "%{?dist}")
endif()
# set package
set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE ${CPACK_PACKAGE_HOMEPAGE})
set(CPACK_RPM_PACKAGE_URL ${CPACK_PACKAGE_HOMEPAGE})
set(CPACK_RPM_PACKAGE_AUTOREQPROV "no")
# Debian package
set(CPACK_DEB_COMPONENT_INSTALL ON)
set(CPACK_DEBIAN_RUNTIME_PACKAGE_NAME "${PROJECT_NAME}")
set(CPACK_DEBIAN_RUNTIME_PACKAGE_DEPENDS "rocm-core, ${rocJPEG_DEBIAN_PACKAGE_LIST}")
set(CPACK_DEBIAN_DEV_PACKAGE_NAME "${PROJECT_NAME}-dev")
set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS
"rocm-core, ${PROJECT_NAME}, ${rocJPEG_DEBIAN_DEV_PACKAGE_LIST}")
# Debian package - specific variable for ASAN
set(CPACK_DEBIAN_ASAN_PACKAGE_NAME "${PROJECT_NAME}-asan" )
set(CPACK_DEBIAN_ASAN_PACKAGE_DEPENDS "rocm-core-asan, ${rocJPEG_DEBIAN_PACKAGE_LIST}" )
# Debian package - Test
set(CPACK_DEBIAN_TEST_PACKAGE_NAME "${PROJECT_NAME}-test" )
set(CPACK_DEBIAN_TEST_PACKAGE_DEPENDS "rocm-core, ${CPACK_DEBIAN_DEV_PACKAGE_NAME}" )
# RPM package
set(CPACK_RPM_COMPONENT_INSTALL ON)
set(CPACK_RPM_RUNTIME_PACKAGE_NAME "${PROJECT_NAME}")
set(CPACK_RPM_RUNTIME_PACKAGE_REQUIRES "rocm-core, ${rocJPEG_RPM_PACKAGE_LIST}")
set(CPACK_RPM_RUNTIME_PACKAGE_OBSOLETES "${PROJECT_NAME}")
set(CPACK_RPM_DEV_PACKAGE_NAME "${PROJECT_NAME}-devel")
set(CPACK_RPM_DEV_PACKAGE_REQUIRES "rocm-core, ${PROJECT_NAME}, ${rocJPEG_RPM_DEV_PACKAGE_LIST}")
set(CPACK_RPM_DEV_PACKAGE_OBSOLETES "${PROJECT_NAME}-devel")
set(CPACK_RPM_PACKAGE_LICENSE "MIT" )
# RPM package specific variable for ASAN
set(CPACK_RPM_ASAN_PACKAGE_NAME "${PROJECT_NAME}-asan" )
set(CPACK_RPM_ASAN_PACKAGE_REQUIRES "rocm-core-asan, ${rocJPEG_RPM_PACKAGE_LIST}" )
set(CPACK_RPM_ASAN_PACKAGE_OBSOLETES "${PROJECT_NAME}-asan")
# RPM package specific variable for Test
set(CPACK_RPM_TEST_PACKAGE_NAME "${PROJECT_NAME}-test" )
set(CPACK_RPM_TEST_PACKAGE_REQUIRES "rocm-core, ${CPACK_RPM_DEV_PACKAGE_NAME}" )
set(CPACK_RPM_TEST_PACKAGE_OBSOLETES "${PROJECT_NAME}-test")
if(NOT ROCM_DEP_ROCMCORE)
string(REGEX REPLACE ",? ?rocm-core," "" CPACK_RPM_RUNTIME_PACKAGE_REQUIRES ${CPACK_RPM_RUNTIME_PACKAGE_REQUIRES})
string(REGEX REPLACE ",? ?rocm-core-asan," "" CPACK_RPM_ASAN_PACKAGE_REQUIRES ${CPACK_RPM_ASAN_PACKAGE_REQUIRES})
string(REGEX REPLACE ",? ?rocm-core," "" CPACK_RPM_DEV_PACKAGE_REQUIRES ${CPACK_RPM_DEV_PACKAGE_REQUIRES})
string(REGEX REPLACE ",? ?rocm-core," "" CPACK_RPM_TEST_PACKAGE_REQUIRES ${CPACK_RPM_TEST_PACKAGE_REQUIRES})
string(REGEX REPLACE ",? ?rocm-core," "" CPACK_DEBIAN_RUNTIME_PACKAGE_DEPENDS ${CPACK_DEBIAN_RUNTIME_PACKAGE_DEPENDS})
string(REGEX REPLACE ",? ?rocm-core-asan," "" CPACK_DEBIAN_ASAN_PACKAGE_DEPENDS ${CPACK_DEBIAN_ASAN_PACKAGE_DEPENDS})
string(REGEX REPLACE ",? ?rocm-core," "" CPACK_DEBIAN_DEV_PACKAGE_DEPENDS ${CPACK_DEBIAN_DEV_PACKAGE_DEPENDS})
string(REGEX REPLACE ",? ?rocm-core," "" CPACK_DEBIAN_TEST_PACKAGE_DEPENDS ${CPACK_DEBIAN_TEST_PACKAGE_DEPENDS})
endif()
if(ENABLE_ASAN_PACKAGING)
# ASAN Package requires asan component with only libraries and license file
set(CPACK_COMPONENTS_ALL asan)
else()
set(CPACK_COMPONENTS_ALL runtime dev test)
endif()
set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT")
set(CPACK_RPM_FILE_NAME "RPM-DEFAULT")
set(CPACK_DEBIAN_PACKAGE_RELEASE "local")
set(CPACK_RPM_PACKAGE_RELEASE "local")
if(DEFINED ENV{CPACK_DEBIAN_PACKAGE_RELEASE})
set(CPACK_DEBIAN_PACKAGE_RELEASE $ENV{CPACK_DEBIAN_PACKAGE_RELEASE})
endif()
if(DEFINED ENV{CPACK_RPM_PACKAGE_RELEASE})
set(CPACK_RPM_PACKAGE_RELEASE $ENV{CPACK_RPM_PACKAGE_RELEASE})
endif()
set(CPACK_GENERATOR "TGZ;ZIP")
if(EXISTS ${MAKE_NSIS_EXE})
list(APPEND CPACK_GENERATOR "NSIS")
endif()
if(EXISTS ${RPMBUILD_EXE})
list(APPEND CPACK_GENERATOR "RPM")
message("-- ${White}AMD ROCm rocjpeg RunTime Package -- ${CPACK_RPM_RUNTIME_PACKAGE_REQUIRES}${ColourReset}")
message("-- ${White}AMD ROCm rocjpeg Dev Package -- ${CPACK_RPM_DEV_PACKAGE_REQUIRES}${ColourReset}")
endif()
if(EXISTS ${DPKG_EXE})
list(APPEND CPACK_GENERATOR "DEB")
message("-- ${White}AMD ROCm rocjpeg RunTime Package -- ${CPACK_DEBIAN_RUNTIME_PACKAGE_DEPENDS}${ColourReset}")
message("-- ${White}AMD ROCm rocjpeg Dev Package -- ${CPACK_DEBIAN_DEV_PACKAGE_DEPENDS}${ColourReset}")
endif()
include(CPack)
cpack_add_component(runtime
DISPLAY_NAME "rocjpeg Runtime Package"
DESCRIPTION "High perf JPEG decode SDK for AMD GPUs. Rocjpeg library and license.txt")
cpack_add_component(dev
DISPLAY_NAME "rocjpeg Develop Package"
DESCRIPTION "High perf JPEG decode SDK for AMD GPUs. Rocjpeg lib, header files and samples")
cpack_add_component(asan
DISPLAY_NAME "rocjpeg ASAN Package"
DESCRIPTION "AMD rocjpeg is a high performance JPEG decode SDK for AMD GPUs. \
rocjpeg ASAN package provides rocjpeg ASAN libraries")
cpack_add_component(test
DISPLAY_NAME "rocjpeg Test Package"
DESCRIPTION "AMD rocjpeg is a high performance JPEG decode SDK for AMD GPUs. \
rocjpeg Test package provides rocjpeg Test Components")
else()
message("-- ${Red}AMD ROCm rocjpeg -- unmet dependencies${ColourReset}")
if(NOT HIP_FOUND)
message(FATAL_ERROR "-- ERROR!: HIP Not Found! - please install rocm-hip-runtime-dev!")
endif()
if(NOT Libva_FOUND)
message(FATAL_ERROR "-- ERROR!: libva Not Found - please install (libva-dev >= 2.16 or libva-amdgpu-dev(DEBIAN))/(libva-devel >= 2.16 or libva-amdgpu-devel(RPM)) package!")
endif()
if(NOT Libdrm_amdgpu_FOUND)
message(FATAL_ERROR "-- ERROR!: libdrm_amdgpu Not Found - please install libdrm-amdgpu-dev(DEBIAN)/libdrm-amdgpu-devel(RPM) package!")
endif()
endif()
+21
Visa fil
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 - 2026 ROCm Software Platform
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.
+196
Visa fil
@@ -0,0 +1,196 @@
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
<p align="center"><img width="70%" src="docs/data/AMD_rocJPEG_Logo.png" /></p>
rocJPEG is a high performance JPEG decode SDK for AMD GPUs. Using the rocJPEG API, you can access the JPEG decoding features available on your GPU.
>[!Note]
>The published documentation is available at [rocJPEG](https://rocm.docs.amd.com/projects/rocJPEG/en/latest/) in an organized, easy-to-read format, with search and a table of contents. The documentation source files reside in the `docs` folder of this repository. As with all ROCm projects, the documentation is open source. For more information on contributing to the documentation, see [Contribute to ROCm documentation](https://rocm.docs.amd.com/en/latest/contribute/contributing.html)
## Supported JPEG chroma subsampling
* YUV 4:4:4
* YUV 4:4:0
* YUV 4:2:2
* YUV 4:2:0
* YUV 4:0:0
## Prerequisites
### Operating Systems
* Linux
* Ubuntu - `22.04` / `24.04`
* RedHat - `8` / `9`
* SLES - `15 SP7`
### Hardware
* **GPU**: [AMD Radeon&trade; Graphics](https://rocm.docs.amd.com/projects/install-on-linux/en/latest/reference/system-requirements.html) / [AMD Instinct&trade; Accelerators](https://rocm.docs.amd.com/projects/install-on-linux/en/latest/reference/system-requirements.html)
> [!IMPORTANT]
> * `gfx908` or higher GPU required
* Install ROCm `6.3.0` or later with [amdgpu-install](https://rocm.docs.amd.com/projects/install-on-linux/en/latest/how-to/amdgpu-install.html): **Required** usecase:`rocm`
> [!IMPORTANT]
> `sudo amdgpu-install --usecase=rocm`
### Compiler
* AMD Clang++ Version 18.0.0 or later - installed with ROCm
### Libraries
* CMake Version `3.10` or later
```shell
sudo apt install cmake
```
* Video Acceleration API - `libva-amdgpu-dev` is an AMD implementation for VA-API
```shell
sudo apt install libva-amdgpu-dev
```
> [!NOTE]
> * RPM Packages for `RHEL`/`SLES` - `libva-amdgpu-devel`
> * `libva-amdgpu` is strongly recommended over system `libva` as it is used for building mesa-amdgpu-va-driver
* AMD VA Drivers
```shell
sudo apt install libva2-amdgpu libva-amdgpu-drm2 libva-amdgpu-wayland2 libva-amdgpu-x11-2 mesa-amdgpu-va-drivers
```
> [!NOTE]
> RPM Packages for `RHEL`/`SLES` - `libva-amdgpu mesa-amdgpu-va-drivers`
* HIP
```shell
sudo apt install hip-dev
```
> [!IMPORTANT]
> * Required compiler support
> * C++17
> * Threads
> * On Ubuntu 22.04 - Additional package required: libstdc++-12-dev
> ```shell
> sudo apt install libstdc++-12-dev
> ```
>[!NOTE]
> * All package installs are shown with the `apt` package manager. Use the appropriate package manager for your operating system.
### Prerequisites setup script for Linux
For your convenience, we provide the setup script,
[rocJPEG-setup.py](rocJPEG-setup.py) which installs all required dependencies. Run this script only once.
**Usage:**
```shell
python rocJPEG-setup.py --rocm_path [ ROCm Installation Path - optional (default:/opt/rocm)]
```
**NOTE:** This script only needs to be executed once.
## Installation instructions
The installation process uses the following steps:
* [ROCm-supported hardware](https://rocm.docs.amd.com/projects/install-on-linux/en/latest/reference/system-requirements.html) install verification
* Install ROCm `6.3.0` or later with [amdgpu-install](https://rocm.docs.amd.com/projects/install-on-linux/en/latest/how-to/amdgpu-install.html) with `--usecase=rocm`
>[!IMPORTANT]
> Use **either** [package install](#package-install) **or** [source install](#source-install) as described below.
### Package install
Install rocJPEG runtime, development, and test packages.
* Runtime package - `rocjpeg` only provides the rocjpeg library `librocjpeg.so`
* Development package - `rocjpeg-dev`/`rocjpeg-devel` provides the library, header files, and samples
* Test package - `rocjpeg-test` provides CTest to verify installation
#### Ubuntu
```shell
sudo apt install rocjpeg rocjpeg-dev rocjpeg-test
```
#### RHEL
```shell
sudo yum install rocjpeg rocjpeg-devel rocjpeg-test
```
#### SLES
```shell
sudo zypper install rocjpeg rocjpeg-devel rocjpeg-test
```
>[!NOTE]
> Package install auto installs all dependencies.
### Source install
```shell
git clone https://github.com/ROCm/rocJPEG.git
cd rocJPEG
mkdir build && cd build
cmake ../
make -j8
sudo make install
```
#### Run tests
```shell
make test
```
**NOTE:** run tests with verbose option `make test ARGS="-VV"`
#### Make package
```shell
sudo make package
```
## Verify installation
The installer will copy
* Libraries into `/opt/rocm/lib`
* Header files into `/opt/rocm/include/rocjpeg`
* Samples folder into `/opt/rocm/share/rocjpeg`
* Documents folder into `/opt/rocm/share/doc/rocjpeg`
### Using sample application
To verify your installation using a sample application, run:
```shell
mkdir rocjpeg-sample && cd rocjpeg-sample
cmake /opt/rocm/share/rocjpeg/samples/jpegDecode/
make -j8
./jpegdecode -i /opt/rocm/share/rocjpeg/images/mug_420.jpg
```
### Using test package
To verify your installation using the `rocjpeg-test` package, run:
```shell
mkdir rocjpeg-test && cd rocjpeg-test
cmake /opt/rocm/share/rocjpeg/test/
ctest -VV
```
## Samples
The tool provides a few samples to decode JPEG images [here](samples/). Please refer to the individual folders to build and run the samples.
You can access samples to decode your images in our
[GitHub repository](https://github.com/ROCm/rocJPEG/tree/develop/samples). Refer to the
individual folders to build and run the samples.
## Docker
You can find rocJPEG Docker containers in our
[GitHub repository](https://github.com/ROCm/rocJPEG/tree/develop/docker).
@@ -0,0 +1,90 @@
/*
Copyright (c) 2024 - 2026 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 "rocjpeg/rocjpeg.h"
// Define version macros for the rocJPEG API dispatch table, specifying the MAJOR and STEP versions.
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// 1. When adding new functions to the rocJPEG API dispatch table, always append the new function pointer
// to the end of the table and increment the dispatch table's version number. Never rearrange the order of
// the member variables in the dispatch table, as doing so will break the Application Binary Interface (ABI).
// 2. In critical situations where the type of an existing member variable in a dispatch table has been changed
// or removed due to a data type modification, it is important to increment the major version number of the
// rocJPEG API dispatch table. If the function pointer type can no longer be declared, do not remove it.
// Instead, change the function pointer type to `void*` and ensure it is always initialized to `nullptr`.
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// The major version number should ideally remain unchanged. Increment the ROCJPEG_RUNTIME_API_TABLE_MAJOR_VERSION only
// for fundamental changes to the rocJPEGDispatchTable struct, such as altering the type or name of an existing member variable.
// Please DO NOT REMOVE it.
#define ROCJPEG_RUNTIME_API_TABLE_MAJOR_VERSION 0
// Increment the ROCJPEG_RUNTIME_API_TABLE_STEP_VERSION when new runtime API functions are added.
// If the corresponding ROCJPEG_RUNTIME_API_TABLE_MAJOR_VERSION increases reset the ROCJPEG_RUNTIME_API_TABLE_STEP_VERSION to zero.
#define ROCJPEG_RUNTIME_API_TABLE_STEP_VERSION 0
// rocJPEG API interface
typedef RocJpegStatus (ROCJPEGAPI *PfnRocJpegStreamCreate)(RocJpegStreamHandle *jpeg_stream_handle);
typedef RocJpegStatus (ROCJPEGAPI *PfnRocJpegStreamParse)(const unsigned char *data, size_t length, RocJpegStreamHandle jpeg_stream_handle);
typedef RocJpegStatus (ROCJPEGAPI *PfnRocJpegStreamDestroy)(RocJpegStreamHandle jpeg_stream_handle);
typedef RocJpegStatus (ROCJPEGAPI *PfnRocJpegCreate)(RocJpegBackend backend, int device_id, RocJpegHandle *handle);
typedef RocJpegStatus (ROCJPEGAPI *PfnRocJpegDestroy)(RocJpegHandle handle);
typedef RocJpegStatus (ROCJPEGAPI *PfnRocJpegGetImageInfo)(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, uint8_t *num_components, RocJpegChromaSubsampling *subsampling, uint32_t *widths, uint32_t *heights);
typedef RocJpegStatus (ROCJPEGAPI *PfnRocJpegDecode)(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, const RocJpegDecodeParams *decode_params, RocJpegImage *destination);
typedef RocJpegStatus (ROCJPEGAPI *PfnRocJpegDecodeBatched)(RocJpegHandle handle, RocJpegStreamHandle *jpeg_stream_handles, int batch_size, const RocJpegDecodeParams *decode_params, RocJpegImage *destinations);
typedef const char* (ROCJPEGAPI *PfnRocJpegGetErrorName)(RocJpegStatus rocjpeg_status);
// rocJPEG API dispatch table
struct RocJpegDispatchTable {
// ROCJPEG_RUNTIME_API_TABLE_STEP_VERSION == 0
size_t size;
PfnRocJpegStreamCreate pfn_rocjpeg_stream_create;
PfnRocJpegStreamParse pfn_rocjpeg_stream_parse;
PfnRocJpegStreamDestroy pfn_rocjpeg_stream_destroy;
PfnRocJpegCreate pfn_rocjpeg_create;
PfnRocJpegDestroy pfn_rocjpeg_destroy;
PfnRocJpegGetImageInfo pfn_rocjpeg_get_image_info;
PfnRocJpegDecode pfn_rocjpeg_decode;
PfnRocJpegDecodeBatched pfn_rocjpeg_decode_batched;
PfnRocJpegGetErrorName pfn_rocjpeg_get_error_name;
// PLEASE DO NOT EDIT ABOVE!
// ROCJPEG_RUNTIME_API_TABLE_STEP_VERSION == 1
// ******************************************************************************************* //
// READ BELOW
// ******************************************************************************************* //
// Please keep this text at the end of the structure:
// 1. Do not reorder any existing members.
// 2. Increase the step version definition before adding new members.
// 3. Insert new members under the appropriate step version comment.
// 4. Generate a comment for the next step version.
// 5. Add a "PLEASE DO NOT EDIT ABOVE!" comment.
// ******************************************************************************************* //
};
+349
Visa fil
@@ -0,0 +1,349 @@
/* Copyright (c) 2024 - 2026 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.
*/
#ifndef ROC_JPEG_H
#define ROC_JPEG_H
#define ROCJPEGAPI
#pragma once
#include "hip/hip_runtime.h"
/**
* @file rocjpeg.h
* @brief The AMD rocJPEG Library.
* @defgroup group_amd_rocjepg rocJPEG: AMD ROCm JPEG Decode API
* @brief rocJPEG API is a toolkit to decode JPEG images using a hardware-accelerated JPEG decoder on AMDs GPUs.
*/
#if defined(__cplusplus)
extern "C" {
#endif // __cplusplus
/**
* @def
* @ingroup group_amd_rocjpeg
* Maximum number of channels rocJPEG supports
*/
#define ROCJPEG_MAX_COMPONENT 4
/**
* @enum RocJpegStatus
* @ingroup group_amd_rocjpeg
* @brief Enumeration representing the status codes for the rocJPEG library.
*/
typedef enum {
ROCJPEG_STATUS_SUCCESS = 0, /**< The operation completed successfully. */
ROCJPEG_STATUS_NOT_INITIALIZED = -1, /**< The rocJPEG library is not initialized. */
ROCJPEG_STATUS_INVALID_PARAMETER = -2, /**< An invalid parameter was passed to a function. */
ROCJPEG_STATUS_BAD_JPEG = -3, /**< The input JPEG data is corrupted or invalid. */
ROCJPEG_STATUS_JPEG_NOT_SUPPORTED = -4, /**< The JPEG format is not supported. */
ROCJPEG_STATUS_OUTOF_MEMORY = -5, /**< Out of memory error. */
ROCJPEG_STATUS_EXECUTION_FAILED = -6, /**< The execution of a function failed. */
ROCJPEG_STATUS_ARCH_MISMATCH = -7, /**< The architecture is not supported. */
ROCJPEG_STATUS_INTERNAL_ERROR = -8, /**< Internal error occurred. */
ROCJPEG_STATUS_IMPLEMENTATION_NOT_SUPPORTED = -9, /**< The requested implementation is not supported. */
ROCJPEG_STATUS_HW_JPEG_DECODER_NOT_SUPPORTED = -10, /**< Hardware JPEG decoder is not supported. */
ROCJPEG_STATUS_RUNTIME_ERROR = -11, /**< Runtime error occurred. */
ROCJPEG_STATUS_NOT_IMPLEMENTED = -12, /**< The requested feature is not implemented. */
ROCJPEG_STATUS_MAX_VALUE = -13, /**< Maximum status code value. */
} RocJpegStatus;
/**
* @enum RocJpegChromaSubsampling
* @ingroup group_amd_rocjpeg
* @brief Enum representing the chroma subsampling options for JPEG encoding/decoding.
*
* The `RocJpegChromaSubsampling` enum defines the available chroma subsampling options for JPEG encoding/decoding.
* Chroma subsampling refers to the reduction of color information in an image to reduce file size.
*
* The possible values are:
* - `ROCJPEG_CSS_444`: Full chroma resolution (4:4:4).
* - `ROCJPEG_CSS_440`: Chroma resolution reduced by half vertically (4:4:0).
* - `ROCJPEG_CSS_422`: Chroma resolution reduced by half horizontally (4:2:2).
* - `ROCJPEG_CSS_420`: Chroma resolution reduced by half both horizontally and vertically (4:2:0).
* - `ROCJPEG_CSS_411`: Chroma resolution reduced by a quarter horizontally (4:1:1).
* - `ROCJPEG_CSS_400`: No chroma information (4:0:0).
* - `ROCJPEG_CSS_UNKNOWN`: Unknown chroma subsampling.
*/
typedef enum {
ROCJPEG_CSS_444 = 0,
ROCJPEG_CSS_440 = 1,
ROCJPEG_CSS_422 = 2,
ROCJPEG_CSS_420 = 3,
ROCJPEG_CSS_411 = 4,
ROCJPEG_CSS_400 = 5,
ROCJPEG_CSS_UNKNOWN = -1
} RocJpegChromaSubsampling;
/**
* @struct RocJpegImage
* @ingroup group_amd_rocjpeg
* @brief Structure representing a JPEG image.
*
* This structure holds the information about a JPEG image, including the pointers to the image channels
* and the pitch (stride) of each channel.
*/
typedef struct {
uint8_t* channel[ROCJPEG_MAX_COMPONENT]; /**< Pointers to the image channels. */
uint32_t pitch[ROCJPEG_MAX_COMPONENT]; /**< Pitch (stride) of each channel. */
} RocJpegImage;
/**
* @enum RocJpegOutputFormat
* @ingroup group_amd_rocjpeg
* @brief Enum representing the output format options for the RocJpegImage.
*
* The `RocJpegOutputFormat` enum specifies the different output formats that can be used when decoding a JPEG image using the VCN JPEG decoder.
*
* The available output formats are:
* - `ROCJPEG_OUTPUT_NATIVE`: Returns the native unchanged decoded YUV image from the VCN JPEG decoder. The channel arrangement depends on the chroma subsampling format.
* - `ROCJPEG_OUTPUT_YUV_PLANAR`: Extracts the Y, U, and V channels from the decoded YUV image and writes them into separate channels of the RocJpegImage.
* - `ROCJPEG_OUTPUT_Y`: Returns only the luma component (Y) and writes it to the first channel of the RocJpegImage.
* - `ROCJPEG_OUTPUT_RGB`: Converts the decoded image to interleaved RGB format using the VCN JPEG decoder or HIP kernels and writes it to the first channel of the RocJpegImage.
* - `ROCJPEG_OUTPUT_RGB_PLANAR`: Converts the decoded image to RGB PLANAR format using the VCN JPEG decoder or HIP kernels and writes the RGB channels to separate channels of the RocJpegImage.
* - `ROCJPEG_OUTPUT_FORMAT_MAX`: Maximum allowed value for the output format.
*/
typedef enum {
/**< return native unchanged decoded YUV image from the VCN JPEG decoder.
For ROCJPEG_CSS_444 and ROCJPEG_CSS_440 write Y, U, and V to first, second, and third channels of RocJpegImage
For ROCJPEG_CSS_422 write YUYV (packed) to first channel of RocJpegImage
For ROCJPEG_CSS_420 write Y to first channel and UV (interleaved) to second channel of RocJpegImage
For ROCJPEG_CSS_400 write Y to first channel of RocJpegImage */
ROCJPEG_OUTPUT_NATIVE = 0,
/**< extract Y, U, and V channels from the decoded YUV image from the VCN JPEG decoder and write into first, second, and third channel of RocJpegImage.
For ROCJPEG_CSS_400 write Y to first channel of RocJpegImage */
ROCJPEG_OUTPUT_YUV_PLANAR = 1,
/**< return luma component (Y) and write to first channel of RocJpegImage */
ROCJPEG_OUTPUT_Y = 2,
/**< convert to interleaved RGB using VCN JPEG decoder (on MI300+) or using HIP kernels and write to first channel of RocJpegImage */
ROCJPEG_OUTPUT_RGB = 3,
/**< convert to RGB PLANAR using VCN JPEG decoder (on MI300+) or HIP kernels and write to first, second, and third channel of RocJpegImage. */
ROCJPEG_OUTPUT_RGB_PLANAR = 4,
ROCJPEG_OUTPUT_FORMAT_MAX = 5 /**< maximum allowed value */
} RocJpegOutputFormat;
/**
* @struct RocJpegDecodeParams
* @ingroup group_amd_rocjpeg
* @brief Structure containing parameters for JPEG decoding.
*
* This structure defines the parameters for decoding a JPEG image using the rocJpeg library.
* It specifies the output format, crop rectangle, and target dimensions for the decoded image.
* Note that if both the crop rectangle and target dimensions are defined, cropping is done first,
* followed by resizing the resulting ROI to the target dimension.
*/
typedef struct {
RocJpegOutputFormat output_format; /**< Output data format. See RocJpegOutputFormat for description. */
struct {
int16_t left; /**< Left coordinate of the crop rectangle. */
int16_t top; /**< Top coordinate of the crop rectangle. */
int16_t right; /**< Right coordinate of the crop rectangle. */
int16_t bottom; /**< Bottom coordinate of the crop rectangle. */
} crop_rectangle; /**< Defines the region of interest (ROI) to be copied into the RocJpegImage output buffers. */
struct {
uint32_t width; /**< Target width of the picture to be resized. */
uint32_t height; /**< Target height of the picture to be resized. */
} target_dimension; /**< (future use) Defines the target width and height of the picture to be resized. Both should be even.
If specified, allocate the RocJpegImage buffers based on these dimensions. */
} RocJpegDecodeParams;
/**
* @enum RocJpegBackend
* @ingroup group_amd_rocjpeg
* @brief The backend options for the rocJpeg library.
*
* This enum defines the available backend options for the rocJpeg library.
* The backend can be either hardware or hybrid.
*/
typedef enum {
ROCJPEG_BACKEND_HARDWARE = 0, /**< Hardware backend option. */
ROCJPEG_BACKEND_HYBRID = 1 /**< Hybrid backend option. */
} RocJpegBackend;
/**
* @brief A handle representing a RocJpegStream instance.
*
* The `RocJpegStreamHandle` is a pointer type used to represent a RocJpegStream instance.
* It is used as a handle to parse and store various parameters from a JPEG stream.
*/
typedef void* RocJpegStreamHandle;
/**
* @fn RocJpegStatus ROCJPEGAPI rocJpegStreamCreate(RocJpegStreamHandle *jpeg_stream_handle);
* @ingroup group_amd_rocjpeg
* @brief Creates a RocJpegStreamHandle for JPEG stream processing.
*
* This function creates a RocJpegStreamHandle, which is used for processing JPEG streams.
* The created handle is stored in the `jpeg_stream_handle` parameter.
*
* @param jpeg_stream_handle Pointer to a RocJpegStreamHandle variable that will hold the created handle.
* @return RocJpegStatus Returns the status of the operation. Possible values are:
* - ROCJPEG_STATUS_SUCCESS: The operation was successful.
* - ROCJPEG_STATUS_INVALID_ARGUMENT: The `jpeg_stream_handle` parameter is NULL.
* - ROCJPEG_STATUS_OUT_OF_MEMORY: Failed to allocate memory for the handle.
* - ROCJPEG_STATUS_UNKNOWN_ERROR: An unknown error occurred.
*/
RocJpegStatus ROCJPEGAPI rocJpegStreamCreate(RocJpegStreamHandle *jpeg_stream_handle);
/**
* @fn RocJpegStatus ROCJPEGAPI rocJpegStreamParse(const unsigned char *data, size_t length, RocJpegStreamHandle jpeg_stream_handle);
* @ingroup group_amd_rocjpeg
* @brief Parses a JPEG stream.
*
* This function parses a JPEG stream represented by the `data` parameter of length `length`.
* The parsed stream is associated with the `jpeg_stream_handle` provided.
*
* @param data The pointer to the JPEG stream data.
* @param length The length of the JPEG stream data.
* @param jpeg_stream_handle The handle to the JPEG stream.
* @return The status of the JPEG stream parsing operation.
*/
RocJpegStatus ROCJPEGAPI rocJpegStreamParse(const unsigned char *data, size_t length, RocJpegStreamHandle jpeg_stream_handle);
/**
* @fn RocJpegStatus ROCJPEGAPI rocJpegStreamDestroy(RocJpegStreamHandle jpeg_stream_handle);
* @ingroup group_amd_rocjpeg
* @brief Destroys a RocJpegStreamHandle object and releases associated resources.
*
* This function destroys the RocJpegStreamHandle object specified by `jpeg_stream_handle` and releases any resources
* associated with it. After calling this function, the `jpeg_stream_handle` becomes invalid and should not be used
* anymore.
*
* @param jpeg_stream_handle The handle to the RocJpegStreamHandle object to be destroyed.
* @return The status of the operation. Returns ROCJPEG_STATUS_SUCCESS if the operation is successful, or an error code
* if an error occurs.
*/
RocJpegStatus ROCJPEGAPI rocJpegStreamDestroy(RocJpegStreamHandle jpeg_stream_handle);
/**
* @brief A handle representing a RocJpeg instance.
*
* The `RocJpegHandle` is a pointer type used to represent a RocJpeg instance.
* It is used as a handle to perform various operations on the rocJpeg library.
*/
typedef void *RocJpegHandle;
/**
* @fn RocJpegStatus ROCJPEGAPI rocJpegCreate(RocJpegBackend backend, int device_id, RocJpegHandle *handle);
* @ingroup group_amd_rocjpeg
* @brief Creates a RocJpegHandle for JPEG decoding.
*
* This function creates a RocJpegHandle for JPEG decoding using the specified backend and device ID.
*
* @param backend The backend to be used for JPEG decoding.
* @param device_id The ID of the device to be used for JPEG decoding.
* @param handle Pointer to a RocJpegHandle variable to store the created handle.
* @return The status of the operation. Returns ROCJPEG_STATUS_INVALID_PARAMETER if handle is nullptr,
* ROCJPEG_STATUS_NOT_INITIALIZED if the rocJPEG handle initialization fails, or the status
* returned by the InitializeDecoder function of the rocjpeg_decoder.
*/
RocJpegStatus ROCJPEGAPI rocJpegCreate(RocJpegBackend backend, int device_id, RocJpegHandle *handle);
/**
* @fn RocJpegStatus ROCJPEGAPI rocJpegDestroy(RocJpegHandle handle);
* @ingroup group_amd_rocjpeg
* @brief Destroys a RocJpegHandle object.
*
* This function destroys the RocJpegHandle object pointed to by the given handle.
* It releases any resources associated with the handle and frees the memory.
*
* @param handle The handle to the RocJpegHandle object to be destroyed.
* @return The status of the operation. Returns ROCJPEG_STATUS_SUCCESS if the handle was successfully destroyed,
* or ROCJPEG_STATUS_INVALID_PARAMETER if the handle is nullptr.
*/
RocJpegStatus ROCJPEGAPI rocJpegDestroy(RocJpegHandle handle);
/**
* @fn RocJpegStatus ROCJPEGAPI rocJpegGetImageInfo(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, uint8_t *num_components, RocJpegChromaSubsampling *subsampling, uint32_t *widths, uint32_t *heights);
* @ingroup group_amd_rocjpeg
* @brief Retrieves information about the JPEG image.
*
* This function retrieves the number of components, chroma subsampling, and dimensions (width and height) of the JPEG image
* specified by the `jpeg_stream_handle`. The information is stored in the provided output parameters `num_components`,
* `subsampling`, `widths`, and `heights`.
*
* @param handle The handle to the RocJpegDecoder instance.
* @param jpeg_stream_handle The handle to the RocJpegStream instance representing the JPEG image.
* @param num_components A pointer to an unsigned 8-bit integer that will store the number of components in the JPEG image.
* @param subsampling A pointer to a RocJpegChromaSubsampling enum that will store the chroma subsampling information.
* @param widths A pointer to an unsigned 32-bit integer array that will store the width of each component in the JPEG image.
* @param heights A pointer to an unsigned 32-bit integer array that will store the height of each component in the JPEG image.
*
* @return The RocJpegStatus indicating the success or failure of the operation.
* - ROCJPEG_STATUS_SUCCESS: The operation was successful.
* - ROCJPEG_STATUS_INVALID_PARAMETER: One or more input parameters are invalid.
* - ROCJPEG_STATUS_RUNTIME_ERROR: An exception occurred during the operation.
*/
RocJpegStatus ROCJPEGAPI rocJpegGetImageInfo(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, uint8_t *num_components, RocJpegChromaSubsampling *subsampling, uint32_t *widths, uint32_t *heights);
/**
* @fn RocJpegStatus ROCJPEGAPI rocJpegDecode(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, const RocJpegDecodeParams *decode_params, RocJpegImage *destination);
* @ingroup group_amd_rocjpeg
* @brief Decodes a JPEG image using the rocJPEG library.
*
* This function decodes a JPEG image using the rocJPEG library. It takes a rocJpegHandle, a rocJpegStreamHandle,
* a pointer to RocJpegDecodeParams, and a pointer to RocJpegImage as input parameters. The function returns a
* RocJpegStatus indicating the success or failure of the decoding operation.
*
* @param handle The rocJpegHandle representing the rocJPEG decoder instance.
* @param jpeg_stream_handle The rocJpegStreamHandle representing the input JPEG stream.
* @param decode_params A pointer to RocJpegDecodeParams containing the decoding parameters.
* @param destination A pointer to RocJpegImage where the decoded image will be stored.
* @return A RocJpegStatus indicating the success or failure of the decoding operation.
*/
RocJpegStatus ROCJPEGAPI rocJpegDecode(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, const RocJpegDecodeParams *decode_params, RocJpegImage *destination);
/**
* @fn RocJpegStatus ROCJPEGAPI rocJpegDecodeBatched(RocJpegHandle handle, RocJpegStreamHandle *jpeg_stream_handles, int batch_size, const RocJpegDecodeParams *decode_params, RocJpegImage *destinations);
* @ingroup group_amd_rocjpeg
* @brief Decodes a batch of JPEG images using the rocJPEG library.
*
* This function decodes a batch of JPEG images using the rocJPEG library.
*
* @param handle The rocJPEG handle.
* @param jpeg_stream_handles An array of rocJPEG stream handles representing the input JPEG streams.
* @param batch_size The number of JPEG streams in the batch.
* @param decode_params An array of RocJpegDecodeParams structs representing the decode parameters for the batch of JPEG images.
* @param destinations An array of rocJPEG images representing the output decoded images.
* @return The status of the JPEG decoding operation.
*/
RocJpegStatus ROCJPEGAPI rocJpegDecodeBatched(RocJpegHandle handle, RocJpegStreamHandle *jpeg_stream_handles, int batch_size, const RocJpegDecodeParams *decode_params, RocJpegImage *destinations);
/**
* @fn extern const char* ROCDECAPI rocJpegGetErrorName(RocJpegStatus rocjpeg_status);
* @ingroup group_amd_rocjpeg
* @brief Retrieves the name of the error associated with the given RocJpegStatus.
*
* This function returns a string representation of the error associated with the given RocJpegStatus.
*
* @param rocjpeg_status The RocJpegStatus for which to retrieve the error name.
* @return A pointer to a constant character string representing the error name.
*/
extern const char* ROCJPEGAPI rocJpegGetErrorName(RocJpegStatus rocjpeg_status);
#if defined(__cplusplus)
}
#endif
#endif // ROC_JPEG_H
+59
Visa fil
@@ -0,0 +1,59 @@
/*
Copyright (c) 2024 - 2026 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.
*/
#ifndef _ROCJPEG_VERSION_H_
#define _ROCJPEG_VERSION_H_
/*!
* \file
* \brief rocJPEG version
* \defgroup group_rocjpeg_version rocJPEG Version
* \brief rocJPEG version
*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define ROCJPEG_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define ROCJPEG_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define ROCJPEG_VERSION_PATCH @PROJECT_VERSION_PATCH@
/**
* ROCJPEG_CHECK_VERSION:
* @major: major version, like 1 in 1.2.3
* @minor: minor version, like 2 in 1.2.3
* @patch: patch version, like 3 in 1.2.3
*
* Evaluates to %TRUE if the version of rocJPEG is greater than
* @major, @minor and @patch
*/
#define ROCJPEG_CHECK_VERSION(major, minor, patch) \
(ROCJPEG_VERSION_MAJOR > (major) || \
(ROCJPEG_VERSION_MAJOR == (major) && ROCJPEG_VERSION_MINOR > (minor)) || \
(ROCJPEG_VERSION_MAJOR == (major) && ROCJPEG_VERSION_MINOR == (minor) && ROCJPEG_VERSION_PATCH >= (patch)))
#ifdef __cplusplus
} // end extern "C" block
#endif
#endif //_ROCJPEG_VERSION_H_ header guard
@@ -0,0 +1,42 @@
################################################################################
# Copyright (c) 2024 - 2026 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.
#
################################################################################
find_library(LIBDRM_AMDGPU_LIBRARY NAMES drm_amdgpu HINTS ${ROCM_PATH}/lib/rocm_sysdeps/lib /opt/amdgpu/lib/x86_64-linux-gnu /opt/amdgpu/lib64 /usr/lib/x86_64-linux-gnu /usr/lib64)
find_path(LIBDRM_AMDGPU_INCLUDE_DIR NAMES libdrm/amdgpu.h libdrm/amdgpu_drm.h PATHS ${ROCM_PATH}/lib/rocm_sysdeps/include /opt/amdgpu/include /usr/include /usr/ /usr/local/include NO_DEFAULT_PATH)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libdrm_amdgpu DEFAULT_MSG LIBDRM_AMDGPU_INCLUDE_DIR LIBDRM_AMDGPU_LIBRARY)
mark_as_advanced(LIBDRM_AMDGPU_INCLUDE_DIR LIBDRM_AMDGPU_LIBRARY)
if(Libdrm_amdgpu_FOUND)
if(NOT TARGET Libdrm_amdgpu::drm_amdgpu)
add_library(Libdrm_amdgpu::drm_amdgpu UNKNOWN IMPORTED)
set_target_properties(Libdrm_amdgpu::drm_amdgpu PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBDRM_AMDGPU_INCLUDE_DIR}"
IMPORTED_LOCATION "${LIBDRM_AMDGPU_LIBRARY}")
endif()
message("-- ${White}Using Libdrm_amdgpu -- \n\tLibraries:${LIBDRM_AMDGPU_LIBRARY} \n\tIncludes:${LIBDRM_AMDGPU_INCLUDE_DIR} ${ColourReset}")
else()
if(Libdrm_amdgpu_FIND_REQUIRED)
message(FATAL_ERROR "{Red}FindLibdrm_amdgpu -- Libdrm_admgpu NOT FOUND${ColourReset}")
endif()
endif()
+63
Visa fil
@@ -0,0 +1,63 @@
################################################################################
# Copyright (c) 2024 - 2026 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.
#
################################################################################
find_library(LIBVA_LIBRARY NAMES va HINTS ${ROCM_PATH}/lib/rocm_sysdeps/lib /opt/amdgpu/lib/x86_64-linux-gnu /opt/amdgpu/lib64 /usr/lib/x86_64-linux-gnu /usr/lib64)
find_library(LIBVA_DRM_LIBRARY NAMES va-drm HINTS ${ROCM_PATH}/lib/rocm_sysdeps/lib /opt/amdgpu/lib/x86_64-linux-gnu /opt/amdgpu/lib64 /usr/lib/x86_64-linux-gnu /usr/lib64)
find_path(LIBVA_INCLUDE_DIR NAMES va/va.h PATHS ${ROCM_PATH}/lib/rocm_sysdeps/include /opt/amdgpu/include /usr/include NO_DEFAULT_PATH)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libva DEFAULT_MSG LIBVA_INCLUDE_DIR LIBVA_LIBRARY)
mark_as_advanced(LIBVA_INCLUDE_DIR LIBVA_LIBRARY LIBVA_DRM_LIBRARY)
if(Libva_FOUND)
# Find VA Version
file(READ "${LIBVA_INCLUDE_DIR}/va/va_version.h" VA_VERSION_FILE)
string(REGEX MATCH "VA_MAJOR_VERSION ([0-9]*)" _ ${VA_VERSION_FILE})
set(Libva_VERSION_MAJOR ${CMAKE_MATCH_1})
string(REGEX MATCH "VA_MINOR_VERSION ([0-9]*)" _ ${VA_VERSION_FILE})
set(Libva_VERSION_MINOR ${CMAKE_MATCH_1})
string(REGEX MATCH "VA_MICRO_VERSION ([0-9]*)" _ ${VA_VERSION_FILE})
set(Libva_VERSION_MICRO ${CMAKE_MATCH_1})
set(Libva_VERSION "${Libva_VERSION_MAJOR}.${Libva_VERSION_MINOR}.${Libva_VERSION_MICRO}")
message("-- ${White}Found Libva Version: ${Libva_VERSION}${ColourReset}")
endif()
if(Libva_FOUND)
if(NOT TARGET Libva::va)
add_library(Libva::va UNKNOWN IMPORTED)
set_target_properties(Libva::va PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBVA_INCLUDE_DIR}"
IMPORTED_LOCATION "${LIBVA_LIBRARY}")
endif()
if(NOT TARGET Libva::va_drm)
add_library(Libva::va_drm UNKNOWN IMPORTED)
set_target_properties(Libva::va_drm PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBVA_INCLUDE_DIR}"
IMPORTED_LOCATION "${LIBVA_DRM_LIBRARY}")
endif()
message("-- ${White}Using Libva -- \n\tLibraries:${LIBVA_LIBRARY} \n\tIncludes:${LIBVA_INCLUDE_DIR}${ColourReset}")
message("-- ${White}Using Libva-drm -- \n\tLibraries:${LIBVA_DRM_LIBRARY}${ColourReset}")
else()
if(Libva_FIND_REQUIRED)
message(FATAL_ERROR "{Red}FindLibva -- Libva NOT FOUND${ColourReset}")
endif()
endif()
@@ -0,0 +1,37 @@
# - Config file for the rocjpeg package
# It defines the following variables
# use rocjpeg_INCLUDE_DIR - include directory for rocjpeg
# use rocjpeg_LIB_DIR - library directory for rocjpeg
# use rocjpeg_LIBRARY - library to link against
# use rocjpeg_LIBRARIES - library to link against
# compute paths
get_filename_component(@PROJECT_NAME@_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
# version
include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-config-version.cmake)
set(@PROJECT_NAME@_VERSION ${PACKAGE_VERSION})
# targets
include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake)
@PACKAGE_INIT@
set_and_check(@PROJECT_NAME@_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set_and_check(@PROJECT_NAME@_LIB_DIR "@PACKAGE_LIB_INSTALL_DIR@")
set_and_check(@PROJECT_NAME@_LIBRARY "@PACKAGE_LIB_INSTALL_DIR@/lib@PROJECT_NAME@.so")
set_and_check(@PROJECT_NAME@_LIBRARIES "@PACKAGE_LIB_INSTALL_DIR@/lib@PROJECT_NAME@.so")
if(NOT TARGET @PROJECT_NAME@::@PROJECT_NAME@)
add_library(@PROJECT_NAME@::@PROJECT_NAME@ INTERFACE IMPORTED)
set_target_properties(@PROJECT_NAME@::@PROJECT_NAME@ PROPERTIES INTERFACE_LINK_LIBRARIES ${@PROJECT_NAME@_LIBRARY})
endif ()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
@PROJECT_NAME@
FOUND_VAR @PROJECT_NAME@_FOUND
REQUIRED_VARS @PROJECT_NAME@_INCLUDE_DIR @PROJECT_NAME@_LIB_DIR @PROJECT_NAME@_LIBRARY @PROJECT_NAME@_LIBRARIES
VERSION_VAR @PROJECT_NAME@_VERSION
HANDLE_COMPONENTS)
Binary file not shown.

Efter

Bredd:  |  Höjd:  |  Storlek: 1.8 MiB

Binary file not shown.

Efter

Bredd:  |  Höjd:  |  Storlek: 2.2 MiB

Binary file not shown.

Efter

Bredd:  |  Höjd:  |  Storlek: 181 KiB

+13
Visa fil
@@ -0,0 +1,13 @@
# rocJEPG Docker
## Build - dockerfiles
```
sudo docker build -f {DOCKER_FILE_NAME}.dockerfile -t {DOCKER_IMAGE_NAME} .
```
## Run - docker
```
sudo docker run -it --device=/dev/kfd --device=/dev/dri --cap-add=SYS_RAWIO --device=/dev/mem --group-add video --network host --privileged {DOCKER_IMAGE_NAME}
```
@@ -0,0 +1,17 @@
FROM ubuntu:22.04
# install base dependencies
RUN apt-get update -y
#RUN apt-get dist-upgrade -y
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install gcc g++ cmake pkg-config git apt-utils sudo vainfo dialog libstdc++-12-dev
# install ROCm
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install initramfs-tools libnuma-dev wget keyboard-configuration && \
wget https://repo.radeon.com/amdgpu-install/6.3/ubuntu/jammy/amdgpu-install_6.3.60300-1_all.deb && \
sudo apt-get install ./amdgpu-install_6.3.60100-1_all.deb && \
sudo amdgpu-install -y --usecase=rocm
WORKDIR /workspace
# install rocJPEG package
RUN DEBIAN_FRONTEND=noninteractive sudo apt install -y rocjpeg rocjpeg-dev rocjpeg-test
+8
Visa fil
@@ -0,0 +1,8 @@
build/
_build/
_images/
_static/
_templates/
_toc.yml
docBin/
_doxygen/
+36
Visa fil
@@ -0,0 +1,36 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
import re
import shutil
from rocm_docs import ROCmDocs
with open('../CMakeLists.txt', encoding='utf-8') as f:
match = re.search(r'.*\bset\(VERSION\s+\"?([0-9.]+)[^0-9.]+', f.read())
if not match:
raise ValueError("VERSION not found!")
version_number = match[1]
left_nav_title = f"rocJPEG {version_number} Documentation"
# for PDF output on Read the Docs
project = "rocJPEG Documentation"
author = "Advanced Micro Devices, Inc."
copyright = "Copyright (c) 2024 - 2026 Advanced Micro Devices, Inc. All rights reserved."
version = version_number
release = version_number
external_toc_path = "./sphinx/_toc.yml"
docs_core = ROCmDocs(left_nav_title)
docs_core.run_doxygen(doxygen_root="doxygen", doxygen_path="doxygen/xml")
docs_core.enable_api_reference()
docs_core.setup()
external_projects_current_project = "rocjpeg"
for sphinx_var in ROCmDocs.SPHINX_VARS:
globals()[sphinx_var] = getattr(docs_core, sphinx_var)
Binary file not shown.

Efter

Bredd:  |  Höjd:  |  Storlek: 5.8 KiB

Binary file not shown.

Efter

Bredd:  |  Höjd:  |  Storlek: 30 KiB

+3
Visa fil
@@ -0,0 +1,3 @@
html
latex
xml
Filskillnaden har hållits tillbaka eftersom den är för stor Load Diff
@@ -0,0 +1,151 @@
.. meta::
:description: decoding a jpeg stream with rocJPEG
:keywords: rocJPEG, ROCm, API, documentation, decoding, jpeg
********************************************************************
Decoding a JPEG stream with rocJPEG
********************************************************************
rocJPEG provides two functions, ``rocJpegDecode()`` and ``rocJpegDecodeBatched()``, for decoding JPEG image.
.. code:: cpp
RocJpegStatus rocJpegDecode(
RocJpegHandle handle,
RocJpegStreamHandle jpeg_stream_handle,
const RocJpegDecodeParams *decode_params,
RocJpegImage *destination);
RocJpegStatus rocJpegDecodeBatched(
RocJpegHandle handle,
RocJpegStreamHandle *jpeg_stream_handles,
int batch_size,
const RocJpegDecodeParams *decode_params,
RocJpegImage *destinations);
``rocJpegDecode()`` is used for decoding single images and ``rocJpegDecodeBatched()`` is used for decoding batches of JPEG images. ``rocJpegDecode()`` and ``rocJpegDecodeBatched()`` copy decoded images to a ``RocJpegImage`` struct.
.. code:: cpp
typedef struct {
uint8_t* channel[ROCJPEG_MAX_COMPONENT];
uint32_t pitch[ROCJPEG_MAX_COMPONENT];
} RocJpegImage;
``rocJpegDecodeBatched()`` behaves the same way as ``rocJpegDecode()`` except that ``rocJpegDecodeBatched()`` takes an array of stream handles and an array of decode parameters as input, decodes the batch of JPEG images, and stores the decoded images in an output array of destination images.
``rocJpegDecodeBatched()`` is suited for use on ASICs with multiple JPEG cores and is more efficient than multiple calls to ``rocJpegDecode()``. Choosing a batch size that is a multiple of available JPEG cores is recommended.
Memory has to be allocate to each channel of ``RocJpegImage``, including every channel of every ``RocJpegImage`` in the destination image array passed to ``rocJpegDecodeBatched()``. Use |hipmalloc|_ to allocate memory.
.. |hipmalloc| replace:: ``hipMalloc()``
.. _hipmalloc: https://rocm.docs.amd.com/projects/HIP/en/latest/how-to/virtual_memory.html
For example:
.. code:: cpp
// Allocate device memory for the decoded output image
RocJpegImage output_image = {};
RocJpegDecodeParams decode_params = {};
decode_params.output_format = ROCJPEG_OUTPUT_NATIVE;
// For this sample assuming the input image has a YUV420 chroma subsampling.
// For YUV420 subsampling, the native decoded output image would be NV12 (i.e., the rocJPegDecode API copies Y to first channel and UV (interleaved) to second channel of RocJpegImage)
output_image.pitch[1] = output_image.pitch[0] = widths[0];
hipError_t hip_status;
hip_status = hipMalloc(&output_image.channel[0], output_image.pitch[0] * heights[0]);
if (hip_status != hipSuccess) {
std::cerr << "Failed to allocate device memory for the first channel" << std::endl;
rocJpegStreamDestroy(rocjpeg_stream_handle);
rocJpegDestroy(handle);
return EXIT_FAILURE;
}
hip_status = hipMalloc(&output_image.channel[1], output_image.pitch[1] * (heights[0] >> 1));
if (hip_status != hipSuccess) {
std::cerr << "Failed to allocate device memory for the second channel" << std::endl;
hipFree((void *)output_image.channel[0]);
rocJpegStreamDestroy(rocjpeg_stream_handle);
rocJpegDestroy(handle);
return EXIT_FAILURE;
}
// Decode the JPEG stream
status = rocJpegDecode(handle, rocjpeg_stream_handle, &decode_params, &output_image);
if (status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Failed to decode JPEG stream with error code: " << rocJpegGetErrorName(status) << std::endl;
hipFree((void *)output_image.channel[0]);
hipFree((void *)output_image.channel[1]);
rocJpegStreamDestroy(rocjpeg_stream_handle);
rocJpegDestroy(handle);
return EXIT_FAILURE;
}
The behaviors of ``rocJpegDecode()`` and ``rocJpegDecodeBatched()`` depend on ``RocJpegOutputFormat`` and ``RocJpegDecodeParms``.
``RocJpegOutputFormat`` specifies the output format to be used to decode the JPEG image. It can be set to any one of these output formats:
.. csv-table::
:header: "Output format", "Meaning"
"ROCJPEG_OUTPUT_NATIVE", "Return native unchanged decoded YUV image from the VCN JPEG deocder."
"ROCJPEG_OUTPUT_YUV_PLANAR", "Return in the YUV planar format."
"ROCJPEG_OUTPUT_Y", "Return the Y component only."
"ROCJPEG_OUTPUT_RGB", "Convert to interleaved RGB."
"ROCJPEG_OUTPUT_RGB_PLANAR", "Convert to planar RGB."
``RocJpegOutputFormat`` is a member of the ``RocJpegDecodeParams`` struct. ``RocJpegDecodeParams`` defines the output format, crop rectangle, and target dimensions to use when decoding the image.
.. code:: cpp
typedef struct {
RocJpegOutputFormat output_format; /**< Output data format. See RocJpegOutputFormat for description. */
struct {
int16_t left; /**< Left coordinate of the crop rectangle. */
int16_t top; /**< Top coordinate of the crop rectangle. */
int16_t right; /**< Right coordinate of the crop rectangle. */
int16_t bottom; /**< Bottom coordinate of the crop rectangle. */
} crop_rectangle; /**< Defines the region of interest (ROI) to be copied into the RocJpegImage output buffers. */
struct {
uint32_t width; /**< Target width of the picture to be resized. */
uint32_t height; /**< Target height of the picture to be resized. */
} target_dimension; /**< (future use) Defines the target width and height of the picture to be resized. Both should be even.
If specified, allocate the RocJpegImage buffers based on these dimensions. */
} RocJpegDecodeParams;
For example, consider a situation where ``RocJpegOutputFormat`` is set to ``ROCJPEG_OUTPUT_NATIVE``. Based on the chroma subsampling of the input image, ``rocJpegDecode()`` does one of the following:
* For ``ROCJPEG_CSS_444`` and ``ROCJPEG_CSS_440``: writes Y, U, and V to the first, second, and third channels of ``RocJpegImage``.
* For ``ROCJPEG_CSS_422``: writes YUYV (packed) to the first channel of ``RocJpegImage``.
* For ``ROCJPEG_CSS_420``: writes Y to the first channel and UV (interleaved) to the second channel of ``RocJpegImage``.
* For ``ROCJPEG_CSS_400``: writes Y to the first channel of ``RocJpegImage``.
If ``RocJpegOutputFormat`` is set to ``ROCJPEG_OUTPUT_Y`` or ``ROCJPEG_OUTPUT_RGB``, then ``rocJpegDecode()`` copies the output to the first channel of ``RocJpegImage``.
If ``RocJpegOutputFormat`` is set to ``ROCJPEG_OUTPUT_YUV_PLANAR`` or ``ROCJPEG_OUTPUT_RGB_PLANAR``, the data is written to the corresponding channels of the ``RocJpegImage`` destination structure.
The destination images must be large enough to store the output.
Use |rocjpegimageinfo|_ to extract information and calculate the required memory sizes for the destination image following these guidelines:.
.. |rocjpegimageinfo| replace:: ``rocJpegGetImageInfo()``
.. _rocjpegimageinfo: ./rocjpeg-retrieve-image-info.html
.. csv-table::
:header: "Output format", "Chroma subsampling", "Minimum size of destination.pitch[c]", "Minimum size of destination.channel[c]"
"ROCJPEG_OUTPUT_NATIVE", "ROCJPEG_CSS_444", "destination.pitch[c] = widths[c] for c = 0, 1, 2", "destination.channel[c] = destination.pitch[c] * heights[0] for c = 0, 1, 2"
"ROCJPEG_OUTPUT_NATIVE", "ROCJPEG_CSS_440", "destination.pitch[c] = widths[c] for c = 0, 1, 2", "destination.channel[0] = destination.pitch[0] * heights[0], destination.channel[c] = destination.pitch[c] * heights[0] / 2 for c = 1, 2"
"ROCJPEG_OUTPUT_NATIVE", "ROCJPEG_CSS_422", "destination.pitch[0] = widths[0] * 2", "destination.channel[0] = destination.pitch[0] * heights[0]"
"ROCJPEG_OUTPUT_NATIVE", "ROCJPEG_CSS_420", "destination.pitch[1] = destination.pitch[0] = widths[0]", "destination.channel[0] = destination.pitch[0] * heights[0], destination.channel[1] = destination.pitch[1] * (heights[0] >> 1)"
"ROCJPEG_OUTPUT_NATIVE", "ROCJPEG_CSS_400", "destination.pitch[0] = widths[0]", "destination.channel[0] = destination.pitch[0] * heights[0]"
"ROCJPEG_OUTPUT_YUV_PLANAR", "ROCJPEG_CSS_444, ROCJPEG_CSS_440, ROCJPEG_CSS_422, ROCJPEG_CSS_420", "destination.pitch[c] = widths[c] for c = 0, 1, 2", "destination.channel[c] = destination.pitch[c] * heights[c] for c = 0, 1, 2"
"ROCJPEG_OUTPUT_YUV_PLANAR", "ROCJPEG_CSS_400", "destination.pitch[0] = widths[0]", "destination.channel[0] = destination.pitch[0] * heights[0]"
"ROCJPEG_OUTPUT_Y", "Any of the supported chroma subsampling", "destination.pitch[0] = widths[0]", "destination.channel[0] = destination.pitch[0] * heights[0]"
"ROCJPEG_OUTPUT_RGB", "Any of the supported chroma subsampling", "destination.pitch[0] = widths[0] * 3", "destination.channel[0] = destination.pitch[0] * heights[0]"
"ROCJPEG_OUTPUT_RGB_PLANAR", "Any of the supported chroma subsampling", "destination.pitch[c] = widths[c] for c = 0, 1, 2", "destination.channel[c] = destination.pitch[c] * heights[c] for c = 0, 1, 2"
@@ -0,0 +1,63 @@
.. meta::
:description: retrieving image information with rocJPEG
:keywords: rocJPEG, ROCm, API, documentation, image information, jpeg
********************************************************************
Retrieving image information with rocJPEG
********************************************************************
Retrieving image information is done using ``rocJpegGetImageInfo()``.
.. code:: cpp
RocJpegStatus rocJpegGetImageInfo(
RocJpegHandle handle,
RocJpegStreamHandle jpeg_stream_handle,
uint8_t *num_components,
RocJpegChromaSubsampling *subsampling,
uint32_t *widths,
uint32_t *heights);
``rocJpegGetImageInfo()`` takes the ``RocJpegHandle`` and a ``RocJpegStreamHandle`` as inputs, and returns the subsampling, number of components, and widths and heights of the components. These are passed to the ``subsampling``, ``num_components``, and ``widths`` and ``heights`` output parameters.
The ``subsampling`` output parameter is a ``RocJpegChromaSubsampling`` enum.
.. code:: cpp
typedef enum {
ROCJPEG_CSS_444 = 0,
ROCJPEG_CSS_440 = 1,
ROCJPEG_CSS_422 = 2,
ROCJPEG_CSS_420 = 3,
ROCJPEG_CSS_411 = 4,
ROCJPEG_CSS_400 = 5,
ROCJPEG_CSS_UNKNOWN = -1
} RocJpegChromaSubsampling;
Its value is set to the chroma subsampling retrieved from the image.
For example:
.. code:: cpp
// Get the image info
uint8_t num_components;
RocJpegChromaSubsampling subsampling;
uint32_t widths[ROCJPEG_MAX_COMPONENT] = {};
uint32_t heights[ROCJPEG_MAX_COMPONENT] = {};
status = rocJpegGetImageInfo(handle, rocjpeg_stream_handle, &num_components, &subsampling, widths, heights);
if (status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Failed to get image info with error code: " << rocJpegGetErrorName(status) << std::endl;
rocJpegStreamDestroy(rocjpeg_stream_handle);
rocJpegDestroy(handle);
return EXIT_FAILURE;
}
``rocJpegGetImageInfo()`` is thread safe.
.. note::
The VCN hardware-accelerated JPEG decoder in AMD GPUs only supports decoding JPEG images with ``ROCJPEG_CSS_444``, ``ROCJPEG_CSS_440``, ``ROCJPEG_CSS_422``, ``ROCJPEG_CSS_420``, and ``ROCJPEG_CSS_400`` chroma subsampling.
@@ -0,0 +1,163 @@
.. meta::
:description: Using rocJPEG
:keywords: parse JPEG, parse, decode, JPEG decoder, JPEG decoding, rocJPEG, AMD, ROCm
********************************************************************
Using rocJPEG
********************************************************************
This document provides a high-level overview of how to do common operations using the rocJPEG APIs exposed in the ``rocjpeg.h`` header file.
Creating handles
==================
Handles need to be created to decode and parse JPEG streams.
``rocJpegCreate()`` returns an instance of a ``RocJpegHandle`` based on the specified backend and GPU device ID. The ``RocJpegHandle`` instance must be retained for the entire decode session.
.. code:: cpp
RocJpegStatus rocJpegCreate(
RocJpegBackend backend,
int device_id,
RocJpegHandle *handle);
``rocJpegStreamCreate()`` returns a ``rocJpegStreamHandle``, which is a pointer used to represent an instance of a JPEG stream. The instance of ``rocJpegStreamHandle`` is used to parse the JPEG stream and to store the JPEG stream parameters.
.. code:: cpp
RocJpegStatus rocJpegStreamCreate(RocJpegStreamHandle *jpeg_stream_handle);
For example:
.. code:: cpp
// Read the JPEG image file
std::ifstream input("mug_420.jpg", std::ios::in | std::ios::binary | std::ios::ate);
// Get the JPEG image file size
std::streamsize file_size = input.tellg();
input.seekg(0, std::ios::beg);
std::vector<char> file_data;
// resize if buffer is too small
if (file_data.size() < file_size) {
file_data.resize(file_size);
}
// Read the JPEG stream
if (!input.read(file_data.data(), file_size)) {
std::cerr << "ERROR: cannot read from file: " << std::endl;
return EXIT_FAILURE;
}
// Initialize rocJPEG
RocJpegHandle handle;
RocJpegStatus status = rocJpegCreate(ROCJPEG_BACKEND_HARDWARE, 0, &handle);
if (status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Failed to create rocJPEG handle with error code: " << rocJpegGetErrorName(status) << std::endl;
return EXIT_FAILURE;
}
// Create a JPEG stream
RocJpegStreamHandle rocjpeg_stream_handle;
status = rocJpegStreamCreate(&rocjpeg_stream_handle);
if (status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Failed to create JPEG stream with error code: " << rocJpegGetErrorName(status) << std::endl;
rocJpegDestroy(handle);
return EXIT_FAILURE;
}
``rocJpegGetErrorName()`` returns error codes in text format from rocJPEG APIs.
Parsing a stream
=================
``rocJpegStreamParse()`` is used to parse a JPEG stream.
The stream data buffer is passed through the ``data`` input parameter. The length of the buffer is passed through the ``length`` input parameter. The parsed stream is returned through the ``jpeg_stream_handle`` provided. ``jpeg_stream_handle`` must have already been created with ``rocJpegStreamCreate()``.
.. code:: cpp
RocJpegStatus rocJpegStreamParse(const unsigned char *data,
size_t length,
RocJpegStreamHandle jpeg_stream_handle);
For example:
.. code:: cpp
// Parse the JPEG stream
status = rocJpegStreamParse(reinterpret_cast<uint8_t*>(file_data.data()), file_size, rocjpeg_stream_handle);
if (status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Failed to parse JPEG stream with error code: " << rocJpegGetErrorName(status) << std::endl;
rocJpegStreamDestroy(rocjpeg_stream_handle);
rocJpegDestroy(handle);
return EXIT_FAILURE;
}
Getting image information
===========================
``rocJpegGetImageInfo()`` is used to retrieve the number of components, the chroma subsampling, and the width and height of the JPEG image.
.. code:: cpp
RocJpegStatus rocJpegGetImageInfo(
RocJpegHandle handle,
RocJpegStreamHandle jpeg_stream_handle,
uint8_t *num_components,
RocJpegChromaSubsampling *subsampling,
uint32_t *widths,
uint32_t *heights);
For more information on ``rocJpegGetImageInfo()``, see `Retrieving image information with rocJPEG <./rocjpeg-retrieve-image-info.html>`_.
Decoding a stream
====================
``rocJpegDecode()`` takes the image passed to it through the ``jpeg_stream_handle`` input parameter and decodes it based on the backend used to create ``handle`` input parameter.
The ``decode_params`` input parameter is used to specify the decoding parameters. Memory needs to be allocated for each channel of the destination image.
.. code:: cpp
RocJpegStatus rocJpegDecode(
RocJpegHandle handle,
RocJpegStreamHandle jpeg_stream_handle,
const RocJpegDecodeParams *decode_params,
RocJpegImage *destination);
For more information on decoding streams, see `Decoding a JPEG stream with rocJPEG <./rocjpeg-decoding-a-jpeg-stream.html>`_.
Destroying handles and freeing resources
==========================================
Once the JPEG stream is decoded, resources need to be freed.
Use |hipfree|_ to release the memory previously allocated by ``hipMalloc()`` for each channel of the destination ``rocJpegImage``.
.. |hipfree| replace:: ``hipFree()``
.. _hipfree: https://rocm.docs.amd.com/projects/HIP/en/latest/how-to/virtual_memory.html
Use ``rocJpegStreamDestroy()`` to release the ``rocJpegStreamHandle`` and its resources, and use ``rocJPegDestroy()`` to release ``RocJpegHandle`` and destroy the session.
.. code:: cpp
RocJpegStatus rocJpegStreamDestroy(RocJpegStreamHandle jpeg_stream_handle)
RocJpegStatus rocJpegDestroy(RocJpegHandle handle)
For example:
.. code:: cpp
hipFree((void *)output_image.channel[0]);
hipFree((void *)output_image.channel[1]);
rocJpegStreamDestroy(rocjpeg_stream_handle);
rocJpegDestroy(handle);
+46
Visa fil
@@ -0,0 +1,46 @@
.. meta::
:description: rocJPEG documentation and API reference library
:keywords: rocJPEG, ROCm, API, documentation
********************************************************************
rocJPEG documentation
********************************************************************
rocJPEG provides APIs and samples that you can use to easily access the JPEG decoding
features of your media engines (VCNs). It also allows interoperability with other compute engines on
the GPU using Video Acceleration API (VA-API)/HIP. To learn more, see :doc:`what-is-rocJPEG`
The rocJPEG public repository is located at `https://github.com/ROCm/rocJPEG <https://github.com/ROCm/rocJPEG>`_.
.. grid:: 2
:gutter: 3
.. grid-item-card:: Install
* :doc:`rocJPEG installation prerequisites <./install/rocjpeg-prerequisites>`
* :doc:`Installing rocJPEG with the package installer <./install/rocjpeg-package-install>`
* :doc:`Building rocJPEG from source code <./install/rocjpeg-build-and-install>`
.. grid-item-card:: How to
* :doc:`Use rocJPEG <how-to/using-rocjpeg>`
* :doc:`Retrieve image information with rocJPEG <how-to/rocjpeg-retrieve-image-info>`
* :doc:`Decode a JPEG stream with rocJPEG <how-to/rocjpeg-decoding-a-jpeg-stream>`
.. grid-item-card:: Samples
* `rocJPEG samples on GitHub <https://github.com/ROCm/rocJPEG/tree/develop/samples>`_
.. grid-item-card:: Reference
* :doc:`rocJPEG subsampling and hardware capabilities <./reference/rocjpeg-formats-and-architectures>`
* :doc:`rocJPEG API library <../doxygen/html/files>`
* :doc:`rocJPEG Functions <../doxygen/html/globals>`
* :doc:`rocJPEG Data structures <../doxygen/html/annotated>`
To contribute to the documentation, refer to
`Contributing to ROCm documentation <https://rocm.docs.amd.com/en/latest/contribute/contributing.html>`_.
You can find licensing information on the
`Licensing <https://rocm.docs.amd.com/en/latest/about/license.html>`_ page.
@@ -0,0 +1,42 @@
.. meta::
:description: Install rocJPEG with the source code
:keywords: install, building, rocJPEG, AMD, ROCm, source code, developer
********************************************************************
Building and installing rocJPEG from source code
********************************************************************
These instructions are for building rocJPEG from its source code. If you will not be contributing to the rocJPEG code base or previewing features, `package installers <https://rocm.docs.amd.com/projects/rocJPEG/en/latest/install/rocjpeg-package-install.html>`_ are available.
.. note::
ROCm must be installed before installing rocJPEG. See `Quick start installation guide <https://rocm.docs.amd.com/projects/install-on-linux/en/latest/install/quick-start.html>`_ for detailed ROCm installation instructions.
Use `rocJPEG-setup.py <https://github.com/ROCm/rocJPEG/blob/develop/rocJPEG-setup.py>`_ available from the rocJPEG GitHub repo to install the prerequisites:
.. code:: shell
python rocJPEG-setup.py --rocm_path [ ROCm Installation Path - optional (default:/opt/rocm)]
Build and install rocJPEG using the following commands:
.. code:: shell
git clone https://github.com/ROCm/rocJPEG.git
cd rocJPEG
mkdir build && cd build
cmake ../
make -j8
sudo make install
After installation, the rocJPEG libraries will be copied to ``/opt/rocm/lib`` and the rocJPEG header files will be copied to ``/opt/rocm/include/rocjpeg``.
Install the CTest module:
.. code:: shell
mkdir rocjpeg-test && cd rocjpeg-test
cmake /opt/rocm/share/rocjpeg/test/
ctest -VV
To test your build, run ``make test``. To run the test with the verbose option, run ``make test ARGS=\"-VV\"``.
@@ -0,0 +1,74 @@
.. meta::
:description: Installing rocJPEG with the package installer
:keywords: install, rocJPEG, AMD, ROCm, basic, development, package
********************************************************************
Installing rocJPEG with the package installer
********************************************************************
.. note::
ROCm must be installed before installing rocJPEG. See `Quick start installation guide <https://rocm.docs.amd.com/projects/install-on-linux/en/latest/install/quick-start.html>`_ for detailed ROCm installation instructions.
There are three rocJPEG packages available:
* ``rocjpeg``: The rocJPEG runtime package. This is the basic rocJPEG package.
* ``rocjpeg-dev``: The rocJPEG development package. This package installs a full suite of libraries, header files, and samples for contributing to the rocJPEG code base.
* ``rocjpeg-test``: A test package that provides a CTest to verify the installation.
Developers who want to contribute to the rocJPEG code base must install both ``rocjpeg-dev`` and ``rocjpeg-test`` in addition to ``rocjpeg``.
All the required prerequisites are installed when the package installation method is used.
Basic installation
========================================
Use the following commands to install only the rocJPEG runtime package:
.. tab-set::
.. tab-item:: Ubuntu
.. code:: shell
sudo apt install rocjpeg
.. tab-item:: RHEL
.. code:: shell
sudo yum install rocjpeg
.. tab-item:: SLES
.. code:: shell
sudo zypper install rocjpeg
Developer installation
========================================
All three rocJPEG packages, ``rocjpeg``, ``rocjpeg-dev``, and ``rocjpeg-test`` must be installed to develop for rocJPEG.
Use the following commands to install ``rocjpeg``, ``rocjpeg-dev``, and ``rocjpeg-test``:
.. tab-set::
.. tab-item:: Ubuntu
.. code:: shell
sudo apt install rocjpeg rocjpeg-dev rocjpeg-test
.. tab-item:: RHEL
.. code:: shell
sudo yum install rocjpeg rocjpeg-devel rocjpeg-test
.. tab-item:: SLES
.. code:: shell
sudo zypper install rocjpeg rocjpeg-devel rocjpeg-test
@@ -0,0 +1,30 @@
.. meta::
:description: rocJPEG Installation Prerequisites
:keywords: install, rocJPEG, AMD, ROCm, prerequisites, dependencies, requirements
********************************************************************
rocJPEG prerequisites
********************************************************************
rocJPEG requires ROCm running on `GPUs based on the CDNA architecture <https://rocm.docs.amd.com/projects/install-on-linux/en/latest/reference/system-requirements.html>`_.
ROCm must be installed before installing rocJPEG. See `Quick start installation guide <https://rocm.docs.amd.com/projects/install-on-linux/en/latest/install/quick-start.html>`_ for detailed ROCm installation instructions.
rocJPEG has been tested on the following Linux environments:
* Ubuntu 22.04 and 24.04
* RHEL 8 and 9
* SLES 15 SP7
See `Supported operating systems <https://rocm.docs.amd.com/projects/install-on-linux/en/latest/reference/system-requirements.html#supported-operating-systems>`_ for the complete list of ROCm supported Linux environments.
The following prerequisites are installed by the package installer. If you are building and installing using the source code, use the `rocJPEG-setup.py <https://github.com/ROCm/rocJPEG/blob/develop/rocJPEG-setup.py>`_ setup script available in the rocJPEG GitHub repository to install these prerequisites.
* CMake version 3.10 or later
* AMD Clang++
* AMD VA Drivers
* libva-devel on RHEL and SLES
* libva-dev on Ubuntu 24.04 and later
* libva-amdgpu-dev on Ubuntu 22.04 only
* libstdc++-12-dev on Ubuntu 22.04 only
* HIP, specifically the ``hip-dev`` package
+4
Visa fil
@@ -0,0 +1,4 @@
# License
```{include} ../LICENSE
```
+14
Visa fil
@@ -0,0 +1,14 @@
<head>
<meta charset="UTF-8">
<meta name="description" content="rocJPEG API reference">
<meta name="keywords" content="API reference, rocJPEG, AMD, ROCm">
</head>
# API reference
This section provides technical descriptions and important information about the different rocJPEG
APIs and library components.
* {doc}`Library <../doxygen/html/files>`
* {doc}`Functions <../doxygen/html/globals>`
* {doc}`Data structures <../doxygen/html/annotated>`
@@ -0,0 +1,28 @@
.. meta::
:description: rocJPEG chroma subsampling and hardware capabilities
:keywords: install, rocJPEG, AMD, ROCm, GPU, chroma, subsampling, VCN
********************************************************************
rocJPEG chroma subsampling and hardware capabilities
********************************************************************
rocJPEG supports the following chroma subsamplings:
* YUV 4:4:4
* YUV 4:4:0
* YUV 4:2:2
* YUV 4:2:0
* YUV 4:0:0
The following table shows the capabilities of the VCN and total number of JPEG cores for each supported GPU
architecture:
.. csv-table::
:header: "GPU Architecture", "VCN Generation", "Total number of JPEG cores", "Max width, Max height"
"gfx908 - MI1xx", "VCN 2.5.0", "2", "4096, 4096"
"gfx90a - MI2xx", "VCN 2.6.0", "4", "4096, 4096"
"gfx942 - MI300A", "VCN 3.0", "24", "16384, 16384"
"gfx942 - MI300X", "VCN 3.0", "32", "16384, 16384"
"gfx1030, gfx1031, gfx1032 - Navi2x", "VCN 3.x", "1", "16384, 16384"
"gfx1100, gfx1101, gfx1102 - Navi3x", "VCN 4.0", "1", "16384, 16384"
+46
Visa fil
@@ -0,0 +1,46 @@
defaults:
numbered: False
root: index
subtrees:
- entries:
- file: what-is-rocJPEG.rst
title: What is rocJPEG?
- caption: Install
entries:
- file: install/rocjpeg-prerequisites.rst
title: Installation prerequisites
- file: install/rocjpeg-package-install.rst
title: Installing with the package installer
- file: install/rocjpeg-build-and-install.rst
title: Building and installing from source code
- caption: How to
entries:
- file: how-to/using-rocjpeg.rst
title: Use rocJPEG
- file: how-to/rocjpeg-retrieve-image-info.rst
title: Retrieve image information
- file: how-to/rocjpeg-decoding-a-jpeg-stream.rst
title: Decode a JPEG stream
- caption: Samples
entries:
- url: https://github.com/ROCm/rocJPEG/tree/develop/samples
title: rocJPEG samples on GitHub
- caption: Reference
entries:
- file: reference/rocjpeg-formats-and-architectures.rst
title: Subsampling and hardware capabilities
- file: doxygen/html/files
title: API library
- file: doxygen/html/globals
title: Functions
- file: doxygen/html/annotated
title: Data structures
- caption: About
entries:
- file: license.md
@@ -0,0 +1 @@
rocm-docs-core[api_reference]==1.31.3
@@ -0,0 +1,319 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile requirements.in
#
accessible-pygments==0.0.5
# via pydata-sphinx-theme
alabaster==1.0.0
# via sphinx
asttokens==3.0.0
# via stack-data
attrs==24.3.0
# via
# jsonschema
# jupyter-cache
# referencing
babel==2.16.0
# via
# pydata-sphinx-theme
# sphinx
beautifulsoup4==4.12.3
# via pydata-sphinx-theme
breathe==4.35.0
# via rocm-docs-core
certifi==2024.8.30
# via requests
cffi==1.17.1
# via
# cryptography
# pynacl
charset-normalizer==3.4.0
# via requests
click==8.1.7
# via
# click-log
# doxysphinx
# jupyter-cache
# sphinx-external-toc
click-log==0.4.0
# via doxysphinx
comm==0.2.2
# via ipykernel
contourpy==1.3.1
# via matplotlib
cryptography==43.0.3
# via pyjwt
cycler==0.12.1
# via matplotlib
debugpy==1.8.12
# via ipykernel
decorator==5.1.1
# via ipython
deprecated==1.2.14
# via pygithub
docutils==0.21.2
# via
# breathe
# myst-parser
# pydata-sphinx-theme
# sphinx
doxysphinx==3.3.12
# via rocm-docs-core
exceptiongroup==1.2.2
# via ipython
executing==2.1.0
# via stack-data
fastjsonschema==2.20.0
# via
# nbformat
# rocm-docs-core
fonttools==4.55.0
# via matplotlib
gitdb==4.0.11
# via gitpython
gitpython==3.1.43
# via rocm-docs-core
greenlet==3.1.1
# via sqlalchemy
idna==3.10
# via requests
imagesize==1.4.1
# via sphinx
importlib-metadata==8.6.1
# via
# jupyter-cache
# myst-nb
ipykernel==6.29.5
# via myst-nb
ipython==8.31.0
# via
# ipykernel
# myst-nb
jedi==0.19.2
# via ipython
jinja2==3.1.4
# via
# myst-parser
# sphinx
jsonschema==4.23.0
# via nbformat
jsonschema-specifications==2024.10.1
# via jsonschema
jupyter-cache==1.0.1
# via myst-nb
jupyter-client==8.6.3
# via
# ipykernel
# nbclient
jupyter-core==5.7.2
# via
# ipykernel
# jupyter-client
# nbclient
# nbformat
kiwisolver==1.4.7
# via matplotlib
libsass==0.22.0
# via doxysphinx
lxml==5.2.1
# via doxysphinx
markdown-it-py==3.0.0
# via
# mdit-py-plugins
# myst-parser
markupsafe==3.0.2
# via jinja2
matplotlib==3.9.2
# via doxysphinx
matplotlib-inline==0.1.7
# via
# ipykernel
# ipython
mdit-py-plugins==0.4.2
# via myst-parser
mdurl==0.1.2
# via markdown-it-py
mpire==2.10.2
# via doxysphinx
myst-nb==1.1.2
# via rocm-docs-core
myst-parser==4.0.0
# via myst-nb
nbclient==0.10.2
# via
# jupyter-cache
# myst-nb
nbformat==5.10.4
# via
# jupyter-cache
# myst-nb
# nbclient
nest-asyncio==1.6.0
# via ipykernel
numpy==1.26.4
# via
# contourpy
# doxysphinx
# matplotlib
packaging==24.1
# via
# ipykernel
# matplotlib
# pydata-sphinx-theme
# sphinx
parso==0.8.4
# via jedi
pexpect==4.9.0
# via ipython
pillow==11.0.0
# via matplotlib
platformdirs==4.3.6
# via jupyter-core
prompt-toolkit==3.0.50
# via ipython
psutil==6.1.1
# via ipykernel
ptyprocess==0.7.0
# via pexpect
pure-eval==0.2.3
# via stack-data
pycparser==2.22
# via cffi
pydata-sphinx-theme==0.15.4
# via
# rocm-docs-core
# sphinx-book-theme
pygithub==2.4.0
# via rocm-docs-core
pygments==2.18.0
# via
# accessible-pygments
# ipython
# mpire
# pydata-sphinx-theme
# sphinx
pyjson5==1.6.7
# via doxysphinx
pyjwt[crypto]==2.9.0
# via pygithub
pynacl==1.5.0
# via pygithub
pyparsing==3.2.0
# via
# doxysphinx
# matplotlib
python-dateutil==2.9.0.post0
# via
# jupyter-client
# matplotlib
pyyaml==6.0.2
# via
# jupyter-cache
# myst-nb
# myst-parser
# rocm-docs-core
# sphinx-external-toc
pyzmq==26.2.0
# via
# ipykernel
# jupyter-client
referencing==0.36.1
# via
# jsonschema
# jsonschema-specifications
requests==2.32.3
# via
# pygithub
# sphinx
rocm-docs-core[api-reference]==1.31.3
# via -r requirements.in
rpds-py==0.22.3
# via
# jsonschema
# referencing
six==1.16.0
# via python-dateutil
smmap==5.0.1
# via gitdb
snowballstemmer==2.2.0
# via sphinx
soupsieve==2.6
# via beautifulsoup4
sphinx==8.1.3
# via
# breathe
# myst-nb
# myst-parser
# pydata-sphinx-theme
# rocm-docs-core
# sphinx-book-theme
# sphinx-copybutton
# sphinx-design
# sphinx-external-toc
# sphinx-notfound-page
sphinx-book-theme==1.1.4
# via rocm-docs-core
sphinx-copybutton==0.5.2
# via rocm-docs-core
sphinx-design==0.6.1
# via rocm-docs-core
sphinx-external-toc==1.0.1
# via rocm-docs-core
sphinx-notfound-page==1.0.4
# via rocm-docs-core
sphinxcontrib-applehelp==2.0.0
# via sphinx
sphinxcontrib-devhelp==2.0.0
# via sphinx
sphinxcontrib-htmlhelp==2.1.0
# via sphinx
sphinxcontrib-jsmath==1.0.1
# via sphinx
sphinxcontrib-qthelp==2.0.0
# via sphinx
sphinxcontrib-serializinghtml==2.0.0
# via sphinx
sqlalchemy==2.0.37
# via jupyter-cache
stack-data==0.6.3
# via ipython
tabulate==0.9.0
# via jupyter-cache
tomli==2.0.2
# via sphinx
tornado==6.4.2
# via
# ipykernel
# jupyter-client
tqdm==4.67.1
# via mpire
traitlets==5.14.3
# via
# comm
# ipykernel
# ipython
# jupyter-client
# jupyter-core
# matplotlib-inline
# nbclient
# nbformat
typing-extensions==4.12.2
# via
# ipython
# myst-nb
# pydata-sphinx-theme
# pygithub
# referencing
# sqlalchemy
urllib3==2.2.3
# via
# pygithub
# requests
wcwidth==0.2.13
# via prompt-toolkit
wrapt==1.16.0
# via deprecated
zipp==3.21.0
# via importlib-metadata
+23
Visa fil
@@ -0,0 +1,23 @@
.. meta::
:description: What is rocJPEG?
:keywords: video decoding, rocJPEG, AMD, ROCm
********************************************************************
What is rocJPEG?
********************************************************************
AMD GPUs contain one or more media engines (VCNs). Each VCN has one or more JPEG engines
that provide fully accelerated, hardware-based JPEG decoding. Hardware decoders consume lower power
than CPU-based decoders. Dedicated hardware decoders offload decoding tasks from the CPU, boosting
overall decoding throughput. With proper power management, decoding on hardware decoders can lower the
overall system power consumption and improve decoding performance.
Using the rocJPEG API, you can decode compressed JPEG streams while keeping the resulting YUV
images in video memory. With decoded images in video memory, you can run image post-processing
using ROCm HIP, thereby avoiding unnecessary data copies via PCIe bus. You can post-process images
using scaling or color space conversion and augmentation kernels (on a GPU or host) in a format for
GPU/CPU-accelerated inferencing and training.
In addition, you can use the rocJPEG API to create multiple instances of JPEG decoder based on the
number of available VCNs/JPEG engines in a GPU device. By configuring the decoder for a device, all available
VCNs can be used seamlessly for decoding a batch of JPEG streams in parallel.
+245
Visa fil
@@ -0,0 +1,245 @@
# Copyright (c) 2024 - 2026 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.
import os
import sys
import argparse
import platform
import traceback
if sys.version_info[0] < 3:
import commands
else:
import subprocess
__copyright__ = "Copyright (c) 2024 - 2026, AMD ROCm rocJPEG"
__version__ = "2.4.0"
__email__ = "mivisionx.support@amd.com"
__status__ = "Shipping"
# error check calls
def ERROR_CHECK(waitval):
if(waitval != 0): # return code and signal flags
print('ERROR_CHECK failed with status:'+str(waitval))
traceback.print_stack()
status = ((waitval >> 8) | waitval) & 255 # combine exit code and wait flags into single non-zero byte
exit(status)
# Arguments
parser = argparse.ArgumentParser()
parser.add_argument('--rocm_path', type=str, default='/opt/rocm',
help='ROCm Installation Path - optional (default:/opt/rocm) - ROCm Installation Required')
parser.add_argument('--runtime', type=str, default='ON',
help='Install RunTime Dependencies - optional (default:ON) [options:ON/OFF]')
args = parser.parse_args()
runtimeInstall = args.runtime.upper()
ROCM_PATH = args.rocm_path
if "ROCM_PATH" in os.environ:
ROCM_PATH = os.environ.get('ROCM_PATH')
print("\nROCm PATH set to -- "+ROCM_PATH+"\n")
# check ROCm installation
if os.path.exists(ROCM_PATH):
print("\nROCm Installation Found -- "+ROCM_PATH+"\n")
os.system('echo ROCm Info -- && '+ROCM_PATH+'/bin/rocminfo')
else:
print(
"WARNING: If ROCm installed, set ROCm Path with \"--rocm_path\" option for full installation [Default:/opt/rocm]\n")
print("ERROR: rocJPEG Setup requires ROCm install\n")
exit(-1)
if runtimeInstall not in ('OFF', 'ON'):
print(
"ERROR: Runtime Option Not Supported - [Supported Options: OFF or ON]\n")
exit()
# get platfrom info
platfromInfo = platform.platform()
# sudo requirement check
sudoLocation = ''
userName = ''
if sys.version_info[0] < 3:
status, sudoLocation = commands.getstatusoutput("which sudo")
if sudoLocation != '/usr/bin/sudo':
status, userName = commands.getstatusoutput("whoami")
else:
status, sudoLocation = subprocess.getstatusoutput("which sudo")
if sudoLocation != '/usr/bin/sudo':
status, userName = subprocess.getstatusoutput("whoami")
# check os version
os_info_data = 'NOT Supported'
if os.path.exists('/etc/os-release'):
with open('/etc/os-release', 'r') as os_file:
os_info_data = os_file.read().replace('\n', ' ')
os_info_data = os_info_data.replace('"', '')
# setup for Linux
linuxSystemInstall = ''
linuxCMake = 'cmake'
linuxSystemInstall_check = ''
linuxFlag = ''
sudoValidateOption= '-v'
osUpdate = ''
if "centos" in os_info_data or "redhat" in os_info_data:
linuxSystemInstall = 'yum -y'
linuxSystemInstall_check = '--nogpgcheck'
osUpdate = 'makecache'
if "VERSION_ID=7" in os_info_data:
linuxCMake = 'cmake3'
platfromInfo = platfromInfo+'-redhat-7'
elif "VERSION_ID=8" in os_info_data:
platfromInfo = platfromInfo+'-redhat-8'
elif "VERSION_ID=9" in os_info_data:
platfromInfo = platfromInfo+'-redhat-9'
else:
platfromInfo = platfromInfo+'-redhat-centos-undefined-version'
elif "Ubuntu" in os_info_data:
linuxSystemInstall = 'apt-get -y'
linuxSystemInstall_check = '--allow-unauthenticated'
linuxFlag = '-S'
osUpdate = 'update'
if "VERSION_ID=20" in os_info_data:
platfromInfo = platfromInfo+'-Ubuntu-20'
elif "VERSION_ID=22" in os_info_data:
platfromInfo = platfromInfo+'-Ubuntu-22'
elif "VERSION_ID=24" in os_info_data:
platfromInfo = platfromInfo+'-Ubuntu-24'
else:
platfromInfo = platfromInfo+'-Ubuntu-undefined-version'
elif "SLES" in os_info_data:
linuxSystemInstall = 'zypper -n'
linuxSystemInstall_check = '--no-gpg-checks'
platfromInfo = platfromInfo+'-SLES'
osUpdate = 'refresh'
elif "Mariner" in os_info_data:
linuxSystemInstall = 'tdnf -y'
linuxSystemInstall_check = '--nogpgcheck'
platfromInfo = platfromInfo+'-Mariner'
runtimeInstall = 'OFF'
osUpdate = 'makecache'
else:
print("\nrocJPEG Setup on "+platfromInfo+" is unsupported\n")
print("\nrocJPEG Setup Supported on: Ubuntu 20/22/24, RedHat 8/9, & SLES 15\n")
exit(-1)
# rocJPEG Setup
print("\nrocJPEG Setup on: "+platfromInfo+"\n")
print("\nrocJPEG Dependencies Installation with rocJPEG-setup.py V-"+__version__+"\n")
if userName == 'root':
ERROR_CHECK(os.system(linuxSystemInstall+' '+osUpdate))
ERROR_CHECK(os.system(linuxSystemInstall+' install sudo'))
# source install - common package dependencies
commonPackages = [
'cmake',
'hip-runtime-amd'
]
# Debian packages
coreDebianPackages = [
'libva-dev',
'hip-dev'
]
coreDebianU22Packages = [
'libva-amdgpu-dev',
'hip-dev',
'libstdc++-12-dev'
]
runtimeDebianPackages = [
'libva-drm2',
'mesa-amdgpu-va-drivers',
'vainfo'
]
runtimeDebianU22Packages = [
'libva-amdgpu-drm2',
'mesa-amdgpu-va-drivers',
'vainfo'
]
# RPM Packages
if "centos" in os_info_data or "redhat" in os_info_data:
coreRPMPackages = [
'libva-devel',
'hip-devel'
]
runtimeRPMPackages = [
'libva',
'mesa-amdgpu-va-drivers',
'libva-utils'
]
else:
coreRPMPackages = [
'libva-devel',
'hip-devel'
]
runtimeRPMPackages = [
'libva-drm2',
'mesa-amdgpu-va-drivers',
'libva-utils'
]
# update
ERROR_CHECK(os.system('sudo '+linuxFlag+' '+linuxSystemInstall +' '+linuxSystemInstall_check+' '+osUpdate))
# common packages
ERROR_CHECK(os.system('sudo '+sudoValidateOption))
for i in range(len(commonPackages)):
ERROR_CHECK(os.system('sudo '+linuxFlag+' '+linuxSystemInstall +
' '+linuxSystemInstall_check+' install '+ commonPackages[i]))
# rocJPEG Core - Requirements
ERROR_CHECK(os.system('sudo '+sudoValidateOption))
if "Ubuntu" in platfromInfo:
if "VERSION_ID=22" in os_info_data:
for i in range(len(coreDebianU22Packages)):
ERROR_CHECK(os.system('sudo '+linuxFlag+' '+linuxSystemInstall +
' '+linuxSystemInstall_check+' install '+ coreDebianU22Packages[i]))
else:
for i in range(len(coreDebianPackages)):
ERROR_CHECK(os.system('sudo '+linuxFlag+' '+linuxSystemInstall +
' '+linuxSystemInstall_check+' install '+ coreDebianPackages[i]))
else:
for i in range(len(coreRPMPackages)):
ERROR_CHECK(os.system('sudo '+linuxFlag+' '+linuxSystemInstall +
' '+linuxSystemInstall_check+' install '+ coreRPMPackages[i]))
# rocJPEG runTime - Requirements
ERROR_CHECK(os.system('sudo '+sudoValidateOption))
if runtimeInstall == 'ON':
if "Ubuntu" in platfromInfo:
if "VERSION_ID=22" in os_info_data:
for i in range(len(runtimeDebianU22Packages)):
ERROR_CHECK(os.system('sudo '+linuxFlag+' '+linuxSystemInstall +
' '+linuxSystemInstall_check+' install '+ runtimeDebianU22Packages[i]))
else:
for i in range(len(runtimeDebianPackages)):
ERROR_CHECK(os.system('sudo '+linuxFlag+' '+linuxSystemInstall +
' '+linuxSystemInstall_check+' install '+ runtimeDebianPackages[i]))
else:
for i in range(len(runtimeRPMPackages)):
ERROR_CHECK(os.system('sudo '+linuxFlag+' '+linuxSystemInstall +
' '+linuxSystemInstall_check+' install '+ runtimeRPMPackages[i]))
print("\nrocJPEG Dependencies Installed with rocJPEG-setup.py V-"+__version__+"\n")
+15
Visa fil
@@ -0,0 +1,15 @@
# Samples overview
rocJPEG samples
## [JPEG decode](jpegDecode)
The jpeg decode sample illustrates decoding a JPEG images using rocJPEG library to get the individual decoded images in one of the supported output format (i.e., native, yuv, y, rgb, rgb_planar). This sample can be configured with a device ID and optionally able to dump the output to a file.
## [JPEG decode batched](jpegDecodeBatched)
The jpeg decode bacthed sample illustrates decoding JPEG images by batches of specified size using rocJPEG library to get the individual decoded images in one of the supported output format (i.e., native, yuv, y, rgb, rgb_planar). This sample can be configured with a device ID and optionally able to dump the output to a file.
## [JPEG decode perf](jpegDecodePerf)
The jpeg decode perf sample illustrates decoding JPEG images by batches of specified size with multiple threads using rocJPEG library to achieve optimal performance. The individual decoded images can be retrieved in one of the supported output format (i.e., native, yuv, y, rgb, rgb_planar). This sample can be configured with a device ID and optionally able to dump the output to a file.
@@ -0,0 +1,78 @@
################################################################################
# Copyright (c) 2024 - 2026 Advanced Micro Devices, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
################################################################################
cmake_minimum_required (VERSION 3.10)
# ROCM Path
if(DEFINED ENV{ROCM_PATH})
set(ROCM_PATH $ENV{ROCM_PATH} CACHE PATH "Default ROCm installation path")
elseif(ROCM_PATH)
message("-- INFO:ROCM_PATH Set -- ${ROCM_PATH}")
else()
set(ROCM_PATH /opt/rocm CACHE PATH "Default ROCm installation path")
endif()
# Set AMD Clang as default compiler
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED On)
set(CMAKE_CXX_EXTENSIONS ON)
if(NOT DEFINED CMAKE_CXX_COMPILER)
set(CMAKE_C_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang)
set(CMAKE_CXX_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang++)
endif()
project(jpegdecode)
list(APPEND CMAKE_PREFIX_PATH ${ROCM_PATH}/lib/cmake)
set (HIP_PLATFORM amd CACHE STRING "HIP platform")
find_package(HIP QUIET)
find_package(rocjpeg QUIET)
find_package(rocprofiler-register QUIET)
if(HIP_FOUND AND rocjpeg_FOUND AND rocprofiler-register_FOUND)
# HIP
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} hip::host)
# rocJPEG
include_directories (${rocjpeg_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/..)
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocjpeg::rocjpeg)
# std filesystem
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} stdc++fs)
# rocprofiler-register
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocprofiler-register::rocprofiler-register)
list(APPEND SOURCES ${PROJECT_SOURCE_DIR} jpegdecode.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 rocjpeg_FOUND)
message(FATAL_ERROR "-- ERROR!: rocJPEG Not Found! - please install rocJPEG!")
endif()
if (NOT rocprofiler-register_FOUND)
message(FATAL_ERROR "-- ERROR!: rocprofiler-register Not Found! - please install rocprofiler-register!")
endif()
endif()
@@ -0,0 +1,27 @@
# JPEG decode sample
The jpeg decode sample illustrates decoding a JPEG images using rocJPEG library to get the individual decoded images in one of the supported output format (i.e., native, yuv, y, rgb, rgb_planar). This sample can be configured with a device ID and optionally able to dump the output to a file.
## Prerequisites:
* Install [rocJPEG](../../README.md#build-and-install-instructions)
## Build
```shell
mkdir jpeg_decode_sample && cd jpeg_decode_sample
cmake ../
make -j
```
## Run
```shell
./jpegdecode -i <[input path] - input path to a single JPEG image or a directory containing JPEG images - [required]>
-be <[backend] - select rocJPEG backend (0 for hardware-accelerated JPEG decoding using VCN,
1 for hybrid JPEG decoding using CPU and GPU HIP kernels (currently not supported)) [optional - default: 0]>
-fmt <[output format] - select rocJPEG output format for decoding, one of the [native, yuv_planar, y, rgb, rgb_planar] [optional - default: native]>
-o <[output path] - path to an output file or a path to a directory - write decoded images to a file or directory based on selected output format [optional]>
-crop <[crop rectangle] - crop rectangle for output in a comma-separated format: left,top,right,bottom - [optional]>
-d <[device id] - specify the GPU device id for the desired device (use 0 for the first device, 1 for the second device, and so on); [optional - default: 0]>
```
@@ -0,0 +1,234 @@
/*
Copyright (c) 2024 - 2026 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 "../rocjpeg_samples_utils.h"
int main(int argc, char **argv) {
int device_id = 0;
bool save_images = false;
uint8_t num_components;
uint32_t widths[ROCJPEG_MAX_COMPONENT] = {};
uint32_t heights[ROCJPEG_MAX_COMPONENT] = {};
uint32_t channel_sizes[ROCJPEG_MAX_COMPONENT] = {};
uint32_t prior_channel_sizes[ROCJPEG_MAX_COMPONENT] = {};
uint32_t num_channels = 0;
int total_images = 0;
double time_per_image_all = 0;
double mpixels_all = 0;
double images_per_sec = 0;
std::string chroma_sub_sampling = "";
std::string input_path, output_file_path;
std::vector<std::string> file_paths = {};
bool is_dir = false;
bool is_file = false;
RocJpegChromaSubsampling subsampling;
RocJpegBackend rocjpeg_backend = ROCJPEG_BACKEND_HARDWARE;
RocJpegHandle rocjpeg_handle = nullptr;
RocJpegStreamHandle rocjpeg_stream_handle = nullptr;
RocJpegImage output_image = {};
RocJpegDecodeParams decode_params = {};
RocJpegUtils rocjpeg_utils;
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, nullptr, argc, argv);
bool is_roi_valid = false;
uint32_t roi_width;
uint32_t roi_height;
roi_width = decode_params.crop_rectangle.right - decode_params.crop_rectangle.left;
roi_height = decode_params.crop_rectangle.bottom - decode_params.crop_rectangle.top;
if (!RocJpegUtils::GetFilePaths(input_path, file_paths, is_dir, is_file)) {
std::cerr << "ERROR: Failed to get input file paths!" << std::endl;
return EXIT_FAILURE;
}
if (!RocJpegUtils::InitHipDevice(device_id)) {
std::cerr << "ERROR: Failed to initialize HIP!" << std::endl;
return EXIT_FAILURE;
}
CHECK_ROCJPEG(rocJpegCreate(rocjpeg_backend, device_id, &rocjpeg_handle));
CHECK_ROCJPEG(rocJpegStreamCreate(&rocjpeg_stream_handle));
std::vector<char> file_data;
for (auto file_path : file_paths) {
std::string base_file_name = file_path.substr(file_path.find_last_of("/\\") + 1);
int image_count = 0;
// Read an image from disk.
std::ifstream input(file_path.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
if (!(input.is_open())) {
std::cerr << "ERROR: Cannot open image: " << file_path << std::endl;
return EXIT_FAILURE;
}
// Get the size
std::streamsize file_size = input.tellg();
input.seekg(0, std::ios::beg);
// resize if buffer is too small
if (file_data.size() < file_size) {
file_data.resize(file_size);
}
if (!input.read(file_data.data(), file_size)) {
std::cerr << "ERROR: Cannot read from file: " << file_path << std::endl;
return EXIT_FAILURE;
}
std::cout << "Input file name: " << file_path << std::endl;
RocJpegStatus rocjpeg_status = rocJpegStreamParse(reinterpret_cast<uint8_t*>(file_data.data()), file_size, rocjpeg_stream_handle);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
if (is_dir) {
std::cout << std::endl;
num_bad_jpegs++;
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_handle, &num_components, &subsampling, widths, heights));
if (roi_width > 0 && roi_height > 0 && roi_width <= widths[0] && roi_height <= heights[0]) {
is_roi_valid = true;
}
rocjpeg_utils.GetChromaSubsamplingStr(subsampling, chroma_sub_sampling);
std::cout << "Input image resolution: " << widths[0] << "x" << heights[0] << std::endl;
std::cout << "Chroma subsampling: " + chroma_sub_sampling << std::endl;
if (widths[0] < 64 || heights[0] < 64) {
std::cerr << "The image resolution is not supported by VCN Hardware" << std::endl;
if (is_dir) {
num_jpegs_with_unsupported_resolution++;
std::cout << std::endl;
continue;
} else
return EXIT_FAILURE;
}
if (subsampling == ROCJPEG_CSS_411 || subsampling == ROCJPEG_CSS_UNKNOWN) {
std::cerr << "The chroma sub-sampling is not supported by VCN Hardware" << std::endl;
if (is_dir) {
if (subsampling == ROCJPEG_CSS_411)
num_jpegs_with_411_subsampling++;
if (subsampling == ROCJPEG_CSS_UNKNOWN)
num_jpegs_with_unknown_subsampling++;
std::cout << std::endl;
continue;
} else
return EXIT_FAILURE;
}
if (rocjpeg_utils.GetChannelPitchAndSizes(decode_params, subsampling, widths, heights, num_channels, output_image, channel_sizes)) {
std::cerr << "ERROR: Failed to get the channel pitch and sizes" << std::endl;
return EXIT_FAILURE;
}
// allocate memory for each channel and reuse them if the sizes remain unchanged for a new image.
for (int i = 0; i < num_channels; i++) {
if (prior_channel_sizes[i] != channel_sizes[i]) {
if (output_image.channel[i] != nullptr) {
CHECK_HIP(hipFree((void *)output_image.channel[i]));
output_image.channel[i] = nullptr;
}
CHECK_HIP(hipMalloc(&output_image.channel[i], channel_sizes[i]));
}
}
if (is_roi_valid) {
std::cout << "Cropped image resolution: " << roi_width << "x" << roi_height << std::endl;
}
std::cout << "Decoding started, please wait! ... " << std::endl;
auto start_time = std::chrono::high_resolution_clock::now();
CHECK_ROCJPEG(rocJpegDecode(rocjpeg_handle, rocjpeg_stream_handle, &decode_params, &output_image));
auto end_time = std::chrono::high_resolution_clock::now();
double time_per_image_in_milli_sec = std::chrono::duration<double, std::milli>(end_time - start_time).count();
double image_size_in_mpixels = (static_cast<double>(widths[0]) * static_cast<double>(heights[0]) / 1000000);
image_count++;
if (save_images) {
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[0];
uint32_t height = is_roi_valid ? roi_height : heights[0];
if (is_dir) {
rocjpeg_utils.GetOutputFileExt(decode_params.output_format, base_file_name, width, height, subsampling, image_save_path);
}
rocjpeg_utils.SaveImage(image_save_path, &output_image, width, height, subsampling, decode_params.output_format);
}
std::cout << "Average processing time per image (ms): " << time_per_image_in_milli_sec << std::endl;
std::cout << "Average images per sec: " << 1000 / time_per_image_in_milli_sec << std::endl;
if (is_dir) {
std::cout << std::endl;
total_images += image_count;
time_per_image_all += time_per_image_in_milli_sec;
mpixels_all += image_size_in_mpixels;
}
for (int i = 0; i < ROCJPEG_MAX_COMPONENT; i++) {
prior_channel_sizes[i] = channel_sizes[i];
}
}
for (int i = 0; i < ROCJPEG_MAX_COMPONENT; i++) {
if (output_image.channel[i] != nullptr) {
CHECK_HIP(hipFree((void *)output_image.channel[i]));
output_image.channel[i] = nullptr;
}
}
if (is_dir) {
time_per_image_all = time_per_image_all / total_images;
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;
std::cout << "Average decoded images size (Mpixels/Sec): " << mpixels_per_sec << std::endl;
}
std::cout << std::endl;
}
CHECK_ROCJPEG(rocJpegDestroy(rocjpeg_handle));
CHECK_ROCJPEG(rocJpegStreamDestroy(rocjpeg_stream_handle));
std::cout << "Decoding completed!" << std::endl;
return EXIT_SUCCESS;
}
@@ -0,0 +1,78 @@
################################################################################
# Copyright (c) 2024 - 2026 Advanced Micro Devices, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
################################################################################
cmake_minimum_required(VERSION 3.10)
# ROCM Path
if(DEFINED ENV{ROCM_PATH})
set(ROCM_PATH $ENV{ROCM_PATH} CACHE PATH "Default ROCm installation path")
elseif(ROCM_PATH)
message("-- INFO:ROCM_PATH Set -- ${ROCM_PATH}")
else()
set(ROCM_PATH /opt/rocm CACHE PATH "Default ROCm installation path")
endif()
# Set AMD Clang as default compiler
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED On)
set(CMAKE_CXX_EXTENSIONS ON)
if(NOT DEFINED CMAKE_CXX_COMPILER)
set(CMAKE_C_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang)
set(CMAKE_CXX_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang++)
endif()
project(jpegdecodebatched)
list(APPEND CMAKE_PREFIX_PATH ${ROCM_PATH}/lib/cmake)
set (HIP_PLATFORM amd CACHE STRING "HIP platform")
find_package(HIP QUIET)
find_package(rocjpeg QUIET)
find_package(rocprofiler-register QUIET)
if(HIP_FOUND AND rocjpeg_FOUND AND rocprofiler-register_FOUND)
# HIP
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} hip::host)
# rocJPEG
include_directories (${rocjpeg_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/..)
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocjpeg::rocjpeg)
# std filesystem
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} stdc++fs)
# rocprofiler-register
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocprofiler-register::rocprofiler-register)
list(APPEND SOURCES ${PROJECT_SOURCE_DIR} jpegdecodebatched.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 rocjpeg_FOUND)
message(FATAL_ERROR "-- ERROR!: rocJPEG Not Found! - please install rocJPEG!")
endif()
if (NOT rocprofiler-register_FOUND)
message(FATAL_ERROR "-- ERROR!: rocprofiler-register Not Found! - please install rocprofiler-register!")
endif()
endif()
@@ -0,0 +1,28 @@
# JPEG decode batched sample
The jpeg decode bacthed sample illustrates decoding JPEG images by batches of specified size using rocJPEG library to get the individual decoded images in one of the supported output format (i.e., native, yuv, y, rgb, rgb_planar). This sample can be configured with a device ID and optionally able to dump the output to a file.
## Prerequisites:
* Install [rocJPEG](../../README.md#build-and-install-instructions)
## Build
```shell
mkdir jpeg_decode_batched_sample && cd jpeg_decode_batched_sample
cmake ../
make -j
```
## Run
```shell
./jpegdecodebatched -i <[input path] - input path to a single JPEG image or a directory containing JPEG images - [required]>
-be <[backend] - select rocJPEG backend (0 for hardware-accelerated JPEG decoding using VCN,
1 for hybrid JPEG decoding using CPU and GPU HIP kernels (currently not supported)) [optional - default: 0]>
-fmt <[output format] - select rocJPEG output format for decoding, one of the [native, yuv_planar, y, rgb, rgb_planar] [optional - default: native]>
-o <[output path] - path to an output file or a path to a directory - write decoded images to a file or directory based on selected output format [optional]>
-d <[device id] - specify the GPU device id for the desired device (use 0 for the first device, 1 for the second device, and so on) - [optional - default: 0]>
-crop <[crop rectangle] - crop rectangle for output in a comma-separated format: left,top,right,bottom - [optional]>
-b <[batch_size] - decode images from input by batches of a specified size - [optional - default: 1]>
```
@@ -0,0 +1,268 @@
/*
Copyright (c) 2024 - 2026 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 "../rocjpeg_samples_utils.h"
int main(int argc, char **argv) {
int device_id = 0;
bool save_images = false;
uint8_t num_components;
uint32_t channel_sizes[ROCJPEG_MAX_COMPONENT] = {};
std::vector<std::vector<uint32_t>> widths;
std::vector<std::vector<uint32_t>> heights;
std::vector<std::vector<uint32_t>> prior_channel_sizes;
uint32_t num_channels = 0;
int total_images = 0;
int batch_size = 2;
double time_per_image_all = 0;
double mpixels_all = 0;
double images_per_sec = 0;
std::string chroma_sub_sampling = "";
std::string input_path, output_file_path;
std::vector<std::string> file_paths = {};
bool is_dir = false;
bool is_file = false;
std::vector<std::vector<char>> batch_images;
std::vector<RocJpegChromaSubsampling> subsamplings;
RocJpegBackend rocjpeg_backend = ROCJPEG_BACKEND_HARDWARE;
RocJpegHandle rocjpeg_handle = nullptr;
std::vector<RocJpegStreamHandle> rocjpeg_stream_handles;
RocJpegImage output_image = {};
std::vector<RocJpegImage> output_images;
RocJpegDecodeParams decode_params = {};
std::vector<RocJpegDecodeParams> decode_params_batch;
RocJpegUtils rocjpeg_utils;
std::vector<std::string> base_file_names;
std::vector<RocJpegStreamHandle> rocjpeg_stream_handles_for_current_batch;
std::vector<uint32_t> temp_widths(ROCJPEG_MAX_COMPONENT, 0);
std::vector<uint32_t> temp_heights(ROCJPEG_MAX_COMPONENT, 0);
RocJpegChromaSubsampling temp_subsampling;
std::string temp_base_file_name;
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;
int current_batch_size = 0;
bool is_roi_valid = false;
uint32_t roi_width;
uint32_t roi_height;
RocJpegUtils::ParseCommandLine(input_path, output_file_path, save_images, device_id, rocjpeg_backend, decode_params, nullptr, &batch_size, argc, argv);
if (!RocJpegUtils::GetFilePaths(input_path, file_paths, is_dir, is_file)) {
std::cerr << "ERROR: Failed to get input file paths!" << std::endl;
return EXIT_FAILURE;
}
if (!RocJpegUtils::InitHipDevice(device_id)) {
std::cerr << "ERROR: Failed to initialize HIP!" << std::endl;
return EXIT_FAILURE;
}
CHECK_ROCJPEG(rocJpegCreate(rocjpeg_backend, device_id, &rocjpeg_handle));
batch_size = std::min(batch_size, static_cast<int>(file_paths.size()));
rocjpeg_stream_handles.resize(batch_size);
// create stream handles of batch size
for(auto i = 0; i < batch_size; i++) {
CHECK_ROCJPEG(rocJpegStreamCreate(&rocjpeg_stream_handles[i]));
}
batch_images.resize(batch_size);
output_images.resize(batch_size);
decode_params_batch.resize(batch_size, decode_params);
prior_channel_sizes.resize(batch_size, std::vector<uint32_t>(ROCJPEG_MAX_COMPONENT, 0));
widths.resize(batch_size, std::vector<uint32_t>(ROCJPEG_MAX_COMPONENT, 0));
heights.resize(batch_size, std::vector<uint32_t>(ROCJPEG_MAX_COMPONENT, 0));
subsamplings.resize(batch_size);
base_file_names.resize(batch_size);
rocjpeg_stream_handles_for_current_batch.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<int>(file_paths.size()));
for (int j = i; j < batch_end; j++) {
int index = j - i;
temp_base_file_name = file_paths[j].substr(file_paths[j].find_last_of("/\\") + 1);
// Read an image from disk.
std::ifstream input(file_paths[j].c_str(), std::ios::in | std::ios::binary | std::ios::ate);
if (!(input.is_open())) {
std::cerr << "ERROR: Cannot open image: " << file_paths[j] << std::endl;
return EXIT_FAILURE;
}
// Get the size
std::streamsize file_size = input.tellg();
input.seekg(0, std::ios::beg);
// resize if buffer is too small
if (batch_images[index].size() < file_size) {
batch_images[index].resize(file_size);
}
if (!input.read(batch_images[index].data(), file_size)) {
std::cerr << "ERROR: Cannot read from file: " << file_paths[j] << std::endl;
return EXIT_FAILURE;
}
RocJpegStatus rocjpeg_status = rocJpegStreamParse(reinterpret_cast<uint8_t*>(batch_images[index].data()), file_size, rocjpeg_stream_handles[index]);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
if (is_dir) {
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, &temp_subsampling, temp_widths.data(), temp_heights.data()));
rocjpeg_utils.GetChromaSubsamplingStr(temp_subsampling, chroma_sub_sampling);
if (temp_widths[0] < 64 || temp_heights[0] < 64) {
if (is_dir) {
num_jpegs_with_unsupported_resolution++;
continue;
} else {
std::cerr << "The image resolution is not supported by VCN Hardware" << std::endl;
return EXIT_FAILURE;
}
}
if (temp_subsampling == ROCJPEG_CSS_411 || temp_subsampling == ROCJPEG_CSS_UNKNOWN) {
if (is_dir) {
if (temp_subsampling == ROCJPEG_CSS_411) {
num_jpegs_with_411_subsampling++;
}
if (temp_subsampling == 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_batch[index], temp_subsampling, temp_widths.data(), temp_heights.data(), num_channels, output_images[current_batch_size], channel_sizes)) {
std::cerr << "ERROR: Failed to get the channel pitch and sizes" << std::endl;
return EXIT_FAILURE;
}
// allocate memory for each channel and reuse them if the sizes remain unchanged for a new image.
for (int n = 0; n < num_channels; n++) {
if (prior_channel_sizes[current_batch_size][n] != channel_sizes[n]) {
if (output_images[current_batch_size].channel[n] != nullptr) {
CHECK_HIP(hipFree((void *)output_images[current_batch_size].channel[n]));
output_images[current_batch_size].channel[n] = nullptr;
}
CHECK_HIP(hipMalloc(&output_images[current_batch_size].channel[n], channel_sizes[n]));
prior_channel_sizes[current_batch_size][n] = channel_sizes[n];
}
}
rocjpeg_stream_handles_for_current_batch[current_batch_size] = rocjpeg_stream_handles[index];
subsamplings[current_batch_size] = temp_subsampling;
widths[current_batch_size] = temp_widths;
heights[current_batch_size] = temp_heights;
base_file_names[current_batch_size] = temp_base_file_name;
current_batch_size++;
}
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, rocjpeg_stream_handles_for_current_batch.data(), current_batch_size, decode_params_batch.data(), output_images.data()));
auto end_time = std::chrono::high_resolution_clock::now();
time_per_batch_in_milli_sec = std::chrono::duration<double, std::milli>(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<double>(widths[b][0]) * static_cast<double>(heights[b][0]) / 1000000);
}
total_images += current_batch_size;
if (save_images) {
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
roi_width = decode_params_batch[b].crop_rectangle.right - decode_params_batch[b].crop_rectangle.left;
roi_height = decode_params_batch[b].crop_rectangle.bottom - decode_params_batch[b].crop_rectangle.top;
is_roi_valid = (roi_width > 0 && roi_height > 0 && roi_width <= widths[b][0] && roi_height <= heights[b][0]) ? true : false;
uint32_t width = is_roi_valid ? roi_width : widths[b][0];
uint32_t height = is_roi_valid ? roi_height : heights[b][0];
if (is_dir) {
rocjpeg_utils.GetOutputFileExt(decode_params_batch[b].output_format, base_file_names[b], width, height, subsamplings[b], image_save_path);
}
rocjpeg_utils.SaveImage(image_save_path, &output_images[b], width, height, subsamplings[b], decode_params_batch[b].output_format);
}
}
if (is_dir) {
time_per_image_all += time_per_batch_in_milli_sec;
mpixels_all += image_size_in_mpixels;
}
current_batch_size = 0;
}
if (is_dir) {
time_per_image_all = time_per_image_all / total_images;
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;
std::cout << "Average decoded images size (Mpixels/Sec): " << mpixels_per_sec << std::endl;
}
}
//cleanup
for (auto& it : output_images) {
for (int i = 0; i < ROCJPEG_MAX_COMPONENT; i++) {
if (it.channel[i] != nullptr) {
CHECK_HIP(hipFree((void *)it.channel[i]));
it.channel[i] = nullptr;
}
}
}
CHECK_ROCJPEG(rocJpegDestroy(rocjpeg_handle));
for(auto& it : rocjpeg_stream_handles) {
CHECK_ROCJPEG(rocJpegStreamDestroy(it));
}
std::cout << "Decoding completed!" << std::endl;
return EXIT_SUCCESS;
}
@@ -0,0 +1,87 @@
################################################################################
# Copyright (c) 2024 - 2026 Advanced Micro Devices, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
################################################################################
cmake_minimum_required(VERSION 3.10)
# ROCM Path
if(DEFINED ENV{ROCM_PATH})
set(ROCM_PATH $ENV{ROCM_PATH} CACHE PATH "Default ROCm installation path")
elseif(ROCM_PATH)
message("-- INFO:ROCM_PATH Set -- ${ROCM_PATH}")
else()
set(ROCM_PATH /opt/rocm CACHE PATH "Default ROCm installation path")
endif()
# Set AMD Clang as default compiler
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED On)
set(CMAKE_CXX_EXTENSIONS ON)
if(NOT DEFINED CMAKE_CXX_COMPILER)
set(CMAKE_C_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang)
set(CMAKE_CXX_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang++)
endif()
project(jpegdecodeperf)
list(APPEND CMAKE_PREFIX_PATH ${ROCM_PATH}/lib/cmake)
set (HIP_PLATFORM amd CACHE STRING "HIP platform")
find_package(HIP QUIET)
find_package(rocjpeg QUIET)
find_package(rocprofiler-register QUIET)
# threads
find_package(Threads REQUIRED)
if(HIP_FOUND AND rocjpeg_FOUND AND Threads_FOUND AND rocprofiler-register_FOUND)
# HIP
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} hip::host)
#threads
set(THREADS_PREFER_PTHREAD_FLAG ON)
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} Threads::Threads)
# std filesystem
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} stdc++fs)
# rocprofiler-register
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocprofiler-register::rocprofiler-register)
# rocJPEG
include_directories (${rocjpeg_INCLUDE_DIR})
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocjpeg::rocjpeg)
list(APPEND SOURCES ${PROJECT_SOURCE_DIR} jpegdecodeperf.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 rocjpeg_FOUND)
message(FATAL_ERROR "-- ERROR!: rocJPEG Not Found! - please install rocJPEG!")
endif()
if (NOT Threads_FOUND)
message(FATAL_ERROR "-- ERROR!: Threads Not Found! - please insatll Threads!")
endif()
if (NOT rocprofiler-register_FOUND)
message(FATAL_ERROR "-- ERROR!: rocprofiler-register Not Found! - please install rocprofiler-register!")
endif()
endif()
@@ -0,0 +1,29 @@
# JPEG decode perf sample
The jpeg decode perf sample illustrates decoding JPEG images by batches of specified size with multiple threads using rocJPEG library to achieve optimal performance. The individual decoded images can be retrieved in one of the supported output format (i.e., native, yuv, y, rgb, rgb_planar). This sample can be configured with a device ID and optionally able to dump the output to a file.
## Prerequisites:
* Install [rocJPEG](../../README.md#build-and-install-instructions)
## Build
```shell
mkdir jpeg_decode_perf_sample && cd jpeg_decode_perf_sample
cmake ../
make -j
```
## Run
```shell
./jpegdecodeperf -i <[input path] - input path to a single JPEG image or a directory containing JPEG images - [required]>
-be <[backend] - select rocJPEG backend (0 for hardware-accelerated JPEG decoding using VCN,
1 for hybrid JPEG decoding using CPU and GPU HIP kernels (currently not supported)) [optional - default: 0]>
-fmt <[output format] - select rocJPEG output format for decoding, one of the [native, yuv_planar, y, rgb, rgb_planar] [optional - default: native]>
-o <[output path] - path to an output file or a path to a directory - write decoded images to a file or directory based on selected output format [optional]>
-d <[device id] - specify the GPU device id for the desired device (use 0 for the first device, 1 for the second device, and so on) [optional - default: 0]>
-crop <[crop rectangle] - crop rectangle for output in a comma-separated format: left,top,right,bottom - [optional]>
-t <[threads] - number of threads for parallel JPEG decoding [optional - default: 1]>
-b <[batch_size] - decode images from input by batches of a specified size - [optional - default: 1]>
```
@@ -0,0 +1,311 @@
/*
Copyright (c) 2024 - 2026 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 "../rocjpeg_samples_utils.h"
struct DecodeInfo {
std::vector<std::string> file_paths;
RocJpegHandle rocjpeg_handle;
std::vector<RocJpegStreamHandle> rocjpeg_stream_handles;
uint64_t num_decoded_images;
double images_per_sec;
double image_size_in_mpixels_per_sec;
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;
};
/**
* @brief Decodes a batch of JPEG images and optionally saves the decoded images.
*
* @param decode_info parameters info for decoding a batch of jpeg images.
* @param rocjpeg_utils Utility functions for RocJpeg operations.
* @param decode_params Parameters for decoding the JPEG images (output_format, crop_rectangle)
* @param save_images A boolean flag indicating whether to save the decoded images.
* @param output_file_path The file path where the decoded images will be saved.
* @param batch_size The number of images to be processed in each batch.
*/
void DecodeImages(DecodeInfo &decode_info, RocJpegUtils rocjpeg_utils, RocJpegDecodeParams &decode_params, bool save_images, std::string &output_file_path, int batch_size, int device_id) {
bool is_roi_valid = false;
uint32_t roi_width;
uint32_t roi_height;
uint8_t num_components;
uint32_t channel_sizes[ROCJPEG_MAX_COMPONENT] = {};
std::string chroma_sub_sampling = "";
uint32_t num_channels = 0;
double image_size_in_mpixels_all = 0;
double total_decode_time_in_milli_sec = 0;
int current_batch_size = 0;
std::vector<std::vector<char>> batch_images(batch_size);
std::vector<std::vector<uint32_t>> widths(batch_size, std::vector<uint32_t>(ROCJPEG_MAX_COMPONENT, 0));
std::vector<std::vector<uint32_t>> heights(batch_size, std::vector<uint32_t>(ROCJPEG_MAX_COMPONENT, 0));
std::vector<std::vector<uint32_t>> prior_channel_sizes(batch_size, std::vector<uint32_t>(ROCJPEG_MAX_COMPONENT, 0));
std::vector<RocJpegChromaSubsampling> subsamplings(batch_size);
std::vector<RocJpegImage> output_images(batch_size);
std::vector<RocJpegDecodeParams> decode_params_batch(batch_size, decode_params);
std::vector<std::string> base_file_names(batch_size);
std::vector<RocJpegStreamHandle> rocjpeg_stream_handles(batch_size);
std::vector<uint32_t> temp_widths(ROCJPEG_MAX_COMPONENT, 0);
std::vector<uint32_t> temp_heights(ROCJPEG_MAX_COMPONENT, 0);
RocJpegChromaSubsampling temp_subsampling;
std::string temp_base_file_name;
CHECK_HIP(hipSetDevice(device_id));
for (int i = 0; i < decode_info.file_paths.size(); i += batch_size) {
int batch_end = std::min(i + batch_size, static_cast<int>(decode_info.file_paths.size()));
for (int j = i; j < batch_end; j++) {
int index = j - i;
temp_base_file_name = decode_info.file_paths[j].substr(decode_info.file_paths[j].find_last_of("/\\") + 1);
// Read an image from disk.
std::ifstream input(decode_info.file_paths[j].c_str(), std::ios::in | std::ios::binary | std::ios::ate);
if (!(input.is_open())) {
std::cerr << "ERROR: Cannot open image: " << decode_info.file_paths[j] << std::endl;
return;
}
// Get the size
std::streamsize file_size = input.tellg();
input.seekg(0, std::ios::beg);
// resize if buffer is too small
if (batch_images[index].size() < file_size) {
batch_images[index].resize(file_size);
}
if (!input.read(batch_images[index].data(), file_size)) {
std::cerr << "ERROR: Cannot read from file: " << decode_info.file_paths[j] << std::endl;
return;
}
RocJpegStatus rocjpeg_status = rocJpegStreamParse(reinterpret_cast<uint8_t*>(batch_images[index].data()), file_size, decode_info.rocjpeg_stream_handles[index]);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
decode_info.num_bad_jpegs++;
std::cerr << "Skipping decoding input file: " << decode_info.file_paths[j] << std::endl;
continue;
}
CHECK_ROCJPEG(rocJpegGetImageInfo(decode_info.rocjpeg_handle, decode_info.rocjpeg_stream_handles[index], &num_components, &temp_subsampling, temp_widths.data(), temp_heights.data()));
rocjpeg_utils.GetChromaSubsamplingStr(temp_subsampling, chroma_sub_sampling);
if (temp_widths[0] < 64 || temp_heights[0] < 64) {
decode_info.num_jpegs_with_unsupported_resolution++;
continue;
}
if (temp_subsampling == ROCJPEG_CSS_411 || temp_subsampling == ROCJPEG_CSS_UNKNOWN) {
if (temp_subsampling == ROCJPEG_CSS_411) {
decode_info.num_jpegs_with_411_subsampling++;
}
if (temp_subsampling == ROCJPEG_CSS_UNKNOWN) {
decode_info.num_jpegs_with_unknown_subsampling++;
}
continue;
}
if (rocjpeg_utils.GetChannelPitchAndSizes(decode_params_batch[index], temp_subsampling, temp_widths.data(), temp_heights.data(), num_channels, output_images[current_batch_size], channel_sizes)) {
std::cerr << "ERROR: Failed to get the channel pitch and sizes" << std::endl;
return;
}
// allocate memory for each channel and reuse them if the sizes remain unchanged for a new image.
for (int n = 0; n < num_channels; n++) {
if (prior_channel_sizes[current_batch_size][n] != channel_sizes[n]) {
if (output_images[current_batch_size].channel[n] != nullptr) {
CHECK_HIP(hipFree((void *)output_images[current_batch_size].channel[n]));
output_images[current_batch_size].channel[n] = nullptr;
}
CHECK_HIP(hipMalloc(&output_images[current_batch_size].channel[n], channel_sizes[n]));
prior_channel_sizes[current_batch_size][n] = channel_sizes[n];
}
}
rocjpeg_stream_handles[current_batch_size] = decode_info.rocjpeg_stream_handles[index];
subsamplings[current_batch_size] = temp_subsampling;
widths[current_batch_size] = temp_widths;
heights[current_batch_size] = temp_heights;
base_file_names[current_batch_size] = temp_base_file_name;
current_batch_size++;
}
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(decode_info.rocjpeg_handle, rocjpeg_stream_handles.data(), current_batch_size, decode_params_batch.data(), output_images.data()));
auto end_time = std::chrono::high_resolution_clock::now();
time_per_batch_in_milli_sec = std::chrono::duration<double, std::milli>(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<double>(widths[b][0]) * static_cast<double>(heights[b][0]) / 1000000);
}
decode_info.num_decoded_images += current_batch_size;
if (save_images) {
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
roi_width = decode_params_batch[b].crop_rectangle.right - decode_params_batch[b].crop_rectangle.left;
roi_height = decode_params_batch[b].crop_rectangle.bottom - decode_params_batch[b].crop_rectangle.top;
is_roi_valid = (roi_width > 0 && roi_height > 0 && roi_width <= widths[b][0] && roi_height <= heights[b][0]) ? true : false;
uint32_t width = is_roi_valid ? roi_width : widths[b][0];
uint32_t height = is_roi_valid ? roi_height : heights[b][0];
rocjpeg_utils.GetOutputFileExt(decode_params.output_format, base_file_names[b], width, height, subsamplings[b], image_save_path);
rocjpeg_utils.SaveImage(image_save_path, &output_images[b], width, height, subsamplings[b], decode_params.output_format);
}
}
total_decode_time_in_milli_sec += time_per_batch_in_milli_sec;
image_size_in_mpixels_all += image_size_in_mpixels;
current_batch_size = 0;
}
double avg_time_per_image = decode_info.num_decoded_images > 0 ? total_decode_time_in_milli_sec / decode_info.num_decoded_images : 0;
decode_info.images_per_sec = avg_time_per_image > 0 ? 1000 / avg_time_per_image : 0;
decode_info.image_size_in_mpixels_per_sec = decode_info.num_decoded_images > 0 ? decode_info.images_per_sec * image_size_in_mpixels_all / decode_info.num_decoded_images : 0;
for (auto& it : output_images) {
for (int i = 0; i < ROCJPEG_MAX_COMPONENT; i++) {
if (it.channel[i] != nullptr) {
CHECK_HIP(hipFree((void *)it.channel[i]));
it.channel[i] = nullptr;
}
}
}
}
int main(int argc, char **argv) {
int device_id = 0;
bool save_images = false;
int num_threads = 1;
int batch_size = 1;
bool is_dir = false;
bool is_file = false;
RocJpegBackend rocjpeg_backend = ROCJPEG_BACKEND_HARDWARE;
RocJpegDecodeParams decode_params = {};
RocJpegUtils rocjpeg_utils;
std::string input_path, output_file_path;
std::vector<std::string> file_paths = {};
std::vector<DecodeInfo> decode_info_per_thread;
RocJpegUtils::ParseCommandLine(input_path, output_file_path, save_images, device_id, rocjpeg_backend, decode_params, &num_threads, &batch_size, argc, argv);
if (!RocJpegUtils::GetFilePaths(input_path, file_paths, is_dir, is_file)) {
std::cerr << "ERROR: Failed to get input file paths!" << std::endl;
return EXIT_FAILURE;
}
if (!RocJpegUtils::InitHipDevice(device_id)) {
std::cerr << "ERROR: Failed to initialize HIP!" << std::endl;
return EXIT_FAILURE;
}
if (num_threads > file_paths.size()) {
num_threads = file_paths.size();
}
decode_info_per_thread.resize(num_threads);
for (int i = 0; i < num_threads; i++) {
CHECK_ROCJPEG(rocJpegCreate(rocjpeg_backend, device_id, &decode_info_per_thread[i].rocjpeg_handle));
decode_info_per_thread[i].rocjpeg_stream_handles.resize(batch_size);
for (auto j = 0; j < batch_size; j++) {
CHECK_ROCJPEG(rocJpegStreamCreate(&decode_info_per_thread[i].rocjpeg_stream_handles[j]));
}
decode_info_per_thread[i].num_decoded_images = 0;
decode_info_per_thread[i].images_per_sec = 0;
decode_info_per_thread[i].image_size_in_mpixels_per_sec = 0;
decode_info_per_thread[i].num_bad_jpegs = 0;
decode_info_per_thread[i].num_jpegs_with_411_subsampling = 0;
decode_info_per_thread[i].num_jpegs_with_unknown_subsampling = 0;
decode_info_per_thread[i].num_jpegs_with_unsupported_resolution = 0;
}
ThreadPool thread_pool(num_threads);
size_t files_per_thread = file_paths.size() / num_threads;
size_t remaining_files = file_paths.size() % num_threads;
size_t start_index = 0;
for (int i = 0; i < num_threads; i++) {
size_t end_index = start_index + files_per_thread + (i < remaining_files ? 1 : 0);
decode_info_per_thread[i].file_paths.assign(file_paths.begin() + start_index, file_paths.begin() + end_index);
start_index = end_index;
}
std::cout << "Decoding started with " << num_threads << " threads, please wait!" << std::endl;
for (int i = 0; i < num_threads; ++i) {
thread_pool.ExecuteJob(std::bind(DecodeImages, std::ref(decode_info_per_thread[i]), rocjpeg_utils, std::ref(decode_params), save_images, std::ref(output_file_path), batch_size, device_id));
}
thread_pool.JoinThreads();
uint64_t total_decoded_images = 0;
double total_images_per_sec = 0;
double total_image_size_in_mpixels_per_sec = 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 += decode_info_per_thread[i].num_decoded_images;
total_image_size_in_mpixels_per_sec += decode_info_per_thread[i].image_size_in_mpixels_per_sec;
total_images_per_sec += decode_info_per_thread[i].images_per_sec;
total_num_bad_jpegs += decode_info_per_thread[i].num_bad_jpegs;
total_num_jpegs_with_411_subsampling += decode_info_per_thread[i].num_jpegs_with_411_subsampling;
total_num_jpegs_with_unknown_subsampling += decode_info_per_thread[i].num_jpegs_with_unknown_subsampling;
total_num_jpegs_with_unsupported_resolution += decode_info_per_thread[i].num_jpegs_with_unsupported_resolution;
}
std::cout << "Total decoded images: " << total_decoded_images << 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): " << 1000 / total_images_per_sec << std::endl;
std::cout << "Average decoded images per sec (Images/Sec): " << total_images_per_sec << std::endl;
std::cout << "Average decoded images size (Mpixels/Sec): " << total_image_size_in_mpixels_per_sec << std::endl;
}
for (int i = 0; i < num_threads; i++) {
CHECK_ROCJPEG(rocJpegDestroy(decode_info_per_thread[i].rocjpeg_handle));
for (auto j = 0; j < batch_size; j++) {
CHECK_ROCJPEG(rocJpegStreamDestroy(decode_info_per_thread[i].rocjpeg_stream_handles[j]));
}
}
std::cout << "Decoding completed!" << std::endl;
return EXIT_SUCCESS;
}
@@ -0,0 +1,734 @@
/*
Copyright (c) 2024 - 2026 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.
*/
#ifndef ROC_JPEG_SAMPLES_COMMON
#define ROC_JPEG_SAMPLES_COMMON
#pragma once
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <vector>
#include <thread>
#include <mutex>
#include <algorithm>
#include <functional>
#include <condition_variable>
#include <queue>
#if __cplusplus >= 201703L && __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
#include <chrono>
#include "rocjpeg/rocjpeg.h"
#define CHECK_ROCJPEG(call) { \
RocJpegStatus rocjpeg_status = (call); \
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) { \
std::cerr << #call << " returned " << rocJpegGetErrorName(rocjpeg_status) << " at " << __FILE__ << ":" << __LINE__ << std::endl;\
exit(1); \
} \
}
#define CHECK_HIP(call) { \
hipError_t hip_status = (call); \
if (hip_status != hipSuccess) { \
std::cout << "HIP failure: 'status: " << hipGetErrorName(hip_status) << "' at " << __FILE__ << ":" << __LINE__ << std::endl;\
exit(1); \
} \
}
/**
* @class RocJpegUtils
* @brief Utility class for rocJPEG samples.
*
* This class provides utility functions for rocJPEG samples, such as parsing command line arguments,
* getting file paths, initializing HIP device, getting chroma subsampling string, getting channel pitch and sizes,
* getting output file extension, and saving images.
*/
class RocJpegUtils {
public:
/**
* @brief Parses the command line arguments.
*
* This function parses the command line arguments and sets the corresponding variables.
*
* @param input_path The input path.
* @param output_file_path The output file path.
* @param save_images Flag indicating whether to save images.
* @param device_id The device ID.
* @param rocjpeg_backend The rocJPEG backend.
* @param decode_params The rocJPEG decode parameters.
* @param num_threads The number of threads.
* @param crop The crop rectangle.
* @param argc The number of command line arguments.
* @param argv The command line arguments.
*/
static void ParseCommandLine(std::string &input_path, std::string &output_file_path, bool &save_images, int &device_id,
RocJpegBackend &rocjpeg_backend, RocJpegDecodeParams &decode_params, int *num_threads, int *batch_size, int argc, char *argv[]) {
if(argc <= 1) {
ShowHelpAndExit("", num_threads != nullptr, batch_size != nullptr);
}
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-h")) {
ShowHelpAndExit("", num_threads != nullptr, batch_size != nullptr);
}
if (!strcmp(argv[i], "-i")) {
if (++i == argc) {
ShowHelpAndExit("-i", num_threads != nullptr, batch_size != nullptr);
}
input_path = argv[i];
continue;
}
if (!strcmp(argv[i], "-o")) {
if (++i == argc) {
ShowHelpAndExit("-o", num_threads != nullptr, batch_size != nullptr);
}
output_file_path = argv[i];
save_images = true;
continue;
}
if (!strcmp(argv[i], "-d")) {
if (++i == argc) {
ShowHelpAndExit("-d", num_threads != nullptr, batch_size != nullptr);
}
device_id = atoi(argv[i]);
continue;
}
if (!strcmp(argv[i], "-be")) {
if (++i == argc) {
ShowHelpAndExit("-be", num_threads != nullptr, batch_size != nullptr);
}
rocjpeg_backend = static_cast<RocJpegBackend>(atoi(argv[i]));
continue;
}
if (!strcmp(argv[i], "-fmt")) {
if (++i == argc) {
ShowHelpAndExit("-fmt", num_threads != nullptr, batch_size != nullptr);
}
std::string selected_output_format = argv[i];
if (selected_output_format == "native") {
decode_params.output_format = ROCJPEG_OUTPUT_NATIVE;
} else if (selected_output_format == "yuv_planar") {
decode_params.output_format = ROCJPEG_OUTPUT_YUV_PLANAR;
} else if (selected_output_format == "y") {
decode_params.output_format = ROCJPEG_OUTPUT_Y;
} else if (selected_output_format == "rgb") {
decode_params.output_format = ROCJPEG_OUTPUT_RGB;
} else if (selected_output_format == "rgb_planar") {
decode_params.output_format = ROCJPEG_OUTPUT_RGB_PLANAR;
} else {
ShowHelpAndExit(argv[i], num_threads != nullptr);
}
continue;
}
if (!strcmp(argv[i], "-t")) {
if (++i == argc) {
ShowHelpAndExit("-t", num_threads != nullptr, batch_size != nullptr);
}
if (num_threads != nullptr) {
*num_threads = atoi(argv[i]);
if (*num_threads <= 0 || *num_threads > 32) {
ShowHelpAndExit(argv[i], num_threads != nullptr, batch_size != nullptr);
}
}
continue;
}
if (!strcmp(argv[i], "-b")) {
if (++i == argc) {
ShowHelpAndExit("-b", num_threads != nullptr, batch_size != nullptr);
}
if (batch_size != nullptr)
*batch_size = atoi(argv[i]);
continue;
}
if (!strcmp(argv[i], "-crop")) {
if (++i == argc || 4 != sscanf(argv[i], "%hd,%hd,%hd,%hd", &decode_params.crop_rectangle.left, &decode_params.crop_rectangle.top, &decode_params.crop_rectangle.right, &decode_params.crop_rectangle.bottom)) {
ShowHelpAndExit("-crop");
}
if ((&decode_params.crop_rectangle.right - &decode_params.crop_rectangle.left) % 2 == 1 || (&decode_params.crop_rectangle.bottom - &decode_params.crop_rectangle.top) % 2 == 1) {
std::cout << "output crop rectangle must have width and height of even numbers" << std::endl;
exit(1);
}
continue;
}
ShowHelpAndExit(argv[i], num_threads != nullptr, batch_size != nullptr);
}
}
/**
* Checks if a file is a JPEG file.
*
* @param filePath The path to the file to be checked.
* @return True if the file is a JPEG file, false otherwise.
*/
static bool IsJPEG(const std::string& filePath) {
std::ifstream file(filePath, std::ios::binary);
if (!file.is_open()) {
std::cerr << "Failed to open file: " << filePath << std::endl;
return false;
}
unsigned char buffer[2];
file.read(reinterpret_cast<char*>(buffer), 2);
file.close();
// The first two bytes of every JPEG stream are always 0xFFD8, which represents the Start of Image (SOI) marker.
return buffer[0] == 0xFF && buffer[1] == 0xD8;
}
/**
* @brief Gets the file paths.
*
* This function gets the file paths based on the input path and sets the corresponding variables.
*
* @param input_path The input path.
* @param file_paths The vector to store the file paths.
* @param is_dir Flag indicating whether the input path is a directory.
* @param is_file Flag indicating whether the input path is a file.
* @return True if successful, false otherwise.
*/
static bool GetFilePaths(std::string &input_path, std::vector<std::string> &file_paths, bool &is_dir, bool &is_file) {
std::cout << "Reading images from disk, please wait!" << std::endl;
if (!fs::exists(input_path)) {
std::cerr << "ERROR: the input path does not exist!" << std::endl;
return false;
}
is_dir = fs::is_directory(input_path);
is_file = fs::is_regular_file(input_path);
if (is_dir) {
for (const auto &entry : fs::recursive_directory_iterator(input_path)) {
if (fs::is_regular_file(entry) && IsJPEG(entry.path().string())) {
file_paths.push_back(entry.path().string());
}
}
} else if (is_file && IsJPEG(input_path)) {
file_paths.push_back(input_path);
} else {
std::cerr << "ERROR: the input path does not contain JPEG files!" << std::endl;
return false;
}
return true;
}
/**
* @brief Initializes the HIP device.
*
* This function initializes the HIP device with the specified device ID.
*
* @param device_id The device ID.
* @return True if successful, false otherwise.
*/
static bool InitHipDevice(int device_id) {
int num_devices;
hipDeviceProp_t hip_dev_prop;
CHECK_HIP(hipGetDeviceCount(&num_devices));
if (num_devices < 1) {
std::cerr << "ERROR: didn't find any GPU!" << std::endl;
return false;
}
if (device_id >= num_devices) {
std::cerr << "ERROR: the requested device_id is not found!" << std::endl;
return false;
}
CHECK_HIP(hipSetDevice(device_id));
CHECK_HIP(hipGetDeviceProperties(&hip_dev_prop, device_id));
std::cout << "Using GPU device " << device_id << ": " << hip_dev_prop.name << "[" << hip_dev_prop.gcnArchName << "] on PCI bus " <<
std::setfill('0') << std::setw(2) << std::right << std::hex << hip_dev_prop.pciBusID << ":" << std::setfill('0') << std::setw(2) <<
std::right << std::hex << hip_dev_prop.pciDomainID << "." << hip_dev_prop.pciDeviceID << std::dec << std::endl;
return true;
}
/**
* @brief Gets the chroma subsampling string.
*
* This function gets the chroma subsampling string based on the specified subsampling value.
*
* @param subsampling The chroma subsampling value.
* @param chroma_sub_sampling The string to store the chroma subsampling.
*/
void GetChromaSubsamplingStr(RocJpegChromaSubsampling subsampling, std::string &chroma_sub_sampling) {
switch (subsampling) {
case ROCJPEG_CSS_444:
chroma_sub_sampling = "YUV 4:4:4";
break;
case ROCJPEG_CSS_440:
chroma_sub_sampling = "YUV 4:4:0";
break;
case ROCJPEG_CSS_422:
chroma_sub_sampling = "YUV 4:2:2";
break;
case ROCJPEG_CSS_420:
chroma_sub_sampling = "YUV 4:2:0";
break;
case ROCJPEG_CSS_411:
chroma_sub_sampling = "YUV 4:1:1";
break;
case ROCJPEG_CSS_400:
chroma_sub_sampling = "YUV 4:0:0";
break;
case ROCJPEG_CSS_UNKNOWN:
chroma_sub_sampling = "UNKNOWN";
break;
default:
chroma_sub_sampling = "";
break;
}
}
/**
* @brief Gets the channel pitch and sizes.
*
* This function gets the channel pitch and sizes based on the specified output format, chroma subsampling,
* output image, and channel sizes.
*
* @param decode_params The decode parameters that specify the output format and crop rectangle.
* @param subsampling The chroma subsampling.
* @param widths The array to store the channel widths.
* @param heights The array to store the channel heights.
* @param num_channels The number of channels.
* @param output_image The output image.
* @param channel_sizes The array to store the channel sizes.
* @return The channel pitch.
*/
int GetChannelPitchAndSizes(RocJpegDecodeParams decode_params, RocJpegChromaSubsampling subsampling, uint32_t *widths, uint32_t *heights,
uint32_t &num_channels, RocJpegImage &output_image, uint32_t *channel_sizes) {
bool is_roi_valid = false;
uint32_t roi_width;
uint32_t roi_height;
roi_width = decode_params.crop_rectangle.right - decode_params.crop_rectangle.left;
roi_height = decode_params.crop_rectangle.bottom - decode_params.crop_rectangle.top;
if (roi_width > 0 && roi_height > 0 && roi_width <= widths[0] && roi_height <= heights[0]) {
is_roi_valid = true;
}
switch (decode_params.output_format) {
case ROCJPEG_OUTPUT_NATIVE:
switch (subsampling) {
case ROCJPEG_CSS_444:
num_channels = 3;
output_image.pitch[2] = output_image.pitch[1] = output_image.pitch[0] = is_roi_valid ? align(roi_width, mem_alignment) : align(widths[0], mem_alignment);
channel_sizes[2] = channel_sizes[1] = channel_sizes[0] = output_image.pitch[0] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[0], mem_alignment));
break;
case ROCJPEG_CSS_440:
num_channels = 3;
output_image.pitch[2] = output_image.pitch[1] = output_image.pitch[0] = is_roi_valid ? align(roi_width, mem_alignment) : align(widths[0], mem_alignment);
channel_sizes[0] = output_image.pitch[0] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[0], mem_alignment));
channel_sizes[2] = channel_sizes[1] = output_image.pitch[0] * (is_roi_valid ? align(roi_height >> 1, mem_alignment) : align(heights[0] >> 1, mem_alignment));
break;
case ROCJPEG_CSS_422:
num_channels = 1;
output_image.pitch[0] = (is_roi_valid ? align(roi_width, mem_alignment) : align(widths[0], mem_alignment)) * 2;
channel_sizes[0] = output_image.pitch[0] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[0], mem_alignment));
break;
case ROCJPEG_CSS_420:
num_channels = 2;
output_image.pitch[1] = output_image.pitch[0] = is_roi_valid ? align(roi_width, mem_alignment) : align(widths[0], mem_alignment);
channel_sizes[0] = output_image.pitch[0] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[0], mem_alignment));
channel_sizes[1] = output_image.pitch[1] * (is_roi_valid ? align(roi_height >> 1, mem_alignment) : align(heights[0] >> 1, mem_alignment));
break;
case ROCJPEG_CSS_400:
num_channels = 1;
output_image.pitch[0] = is_roi_valid ? align(roi_width, mem_alignment) : align(widths[0], mem_alignment);
channel_sizes[0] = output_image.pitch[0] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[0], mem_alignment));
break;
default:
std::cout << "Unknown chroma subsampling!" << std::endl;
return EXIT_FAILURE;
}
break;
case ROCJPEG_OUTPUT_YUV_PLANAR:
if (subsampling == ROCJPEG_CSS_400) {
num_channels = 1;
output_image.pitch[0] = is_roi_valid ? align(roi_width, mem_alignment) : align(widths[0], mem_alignment);
channel_sizes[0] = output_image.pitch[0] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[0], mem_alignment));
} else {
num_channels = 3;
output_image.pitch[0] = is_roi_valid ? align(roi_width, mem_alignment) : align(widths[0], mem_alignment);
output_image.pitch[1] = is_roi_valid ? align(roi_width, mem_alignment) : align(widths[1], mem_alignment);
output_image.pitch[2] = is_roi_valid ? align(roi_width, mem_alignment) : align(widths[2], mem_alignment);
channel_sizes[0] = output_image.pitch[0] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[0], mem_alignment));
channel_sizes[1] = output_image.pitch[1] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[1], mem_alignment));
channel_sizes[2] = output_image.pitch[2] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[2], mem_alignment));
}
break;
case ROCJPEG_OUTPUT_Y:
num_channels = 1;
output_image.pitch[0] = is_roi_valid ? align(roi_width, mem_alignment) : align(widths[0], mem_alignment);
channel_sizes[0] = output_image.pitch[0] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[0], mem_alignment));
break;
case ROCJPEG_OUTPUT_RGB:
num_channels = 1;
output_image.pitch[0] = (is_roi_valid ? align(roi_width, mem_alignment) : align(widths[0], mem_alignment)) * 3;
channel_sizes[0] = output_image.pitch[0] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[0], mem_alignment));
break;
case ROCJPEG_OUTPUT_RGB_PLANAR:
num_channels = 3;
output_image.pitch[2] = output_image.pitch[1] = output_image.pitch[0] = is_roi_valid ? align(roi_width, mem_alignment) : align(widths[0], mem_alignment);
channel_sizes[2] = channel_sizes[1] = channel_sizes[0] = output_image.pitch[0] * (is_roi_valid ? align(roi_height, mem_alignment) : align(heights[0], mem_alignment));
break;
default:
std::cout << "Unknown output format!" << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/**
* @brief Gets the output file extension.
*
* This function gets the output file extension based on the specified output format, base file name,
* image width, image height, and file name for saving.
*
* @param output_format The output format.
* @param base_file_name The base file name.
* @param image_width The image width.
* @param image_height The image height.
* @param file_name_for_saving The string to store the file name for saving.
*/
void GetOutputFileExt(RocJpegOutputFormat output_format, std::string &base_file_name, uint32_t image_width, uint32_t image_height, RocJpegChromaSubsampling subsampling, std::string &file_name_for_saving) {
std::string file_extension;
std::string::size_type const p(base_file_name.find_last_of('.'));
std::string file_name_no_ext = base_file_name.substr(0, p);
std::string format_description = "";
switch (output_format) {
case ROCJPEG_OUTPUT_NATIVE:
file_extension = "yuv";
switch (subsampling) {
case ROCJPEG_CSS_444:
format_description = "444";
break;
case ROCJPEG_CSS_440:
format_description = "440";
break;
case ROCJPEG_CSS_422:
format_description = "422_yuyv";
break;
case ROCJPEG_CSS_420:
format_description = "nv12";
break;
case ROCJPEG_CSS_400:
format_description = "400";
break;
default:
std::cout << "Unknown chroma subsampling!" << std::endl;
return;
}
break;
case ROCJPEG_OUTPUT_YUV_PLANAR:
file_extension = "yuv";
format_description = "planar";
break;
case ROCJPEG_OUTPUT_Y:
file_extension = "yuv";
format_description = "400";
break;
case ROCJPEG_OUTPUT_RGB:
file_extension = "rgb";
format_description = "packed";
break;
case ROCJPEG_OUTPUT_RGB_PLANAR:
file_extension = "rgb";
format_description = "planar";
break;
default:
file_extension = "";
break;
}
file_name_for_saving += "//" + file_name_no_ext + "_" + std::to_string(image_width) + "x"
+ std::to_string(image_height) + "_" + format_description + "." + file_extension;
}
/**
* @brief Saves the image.
*
* This function saves the image to the specified output file name based on the output image, image width,
* image height, chroma subsampling, and output format.
*
* @param output_file_name The output file name.
* @param output_image The output image.
* @param img_width The image width.
* @param img_height The image height.
* @param subsampling The chroma subsampling.
* @param output_format The output format.
*/
void SaveImage(std::string output_file_name, RocJpegImage *output_image, uint32_t img_width, uint32_t img_height,
RocJpegChromaSubsampling subsampling, RocJpegOutputFormat output_format) {
uint8_t *hst_ptr = nullptr;
FILE *fp;
hipError_t hip_status = hipSuccess;
if (output_image == nullptr || output_image->channel[0] == nullptr || output_image->pitch[0] == 0) {
return;
}
uint32_t widths[ROCJPEG_MAX_COMPONENT] = {};
uint32_t heights[ROCJPEG_MAX_COMPONENT] = {};
uint32_t aliged_heights[ROCJPEG_MAX_COMPONENT] = {};
switch (output_format) {
case ROCJPEG_OUTPUT_NATIVE:
switch (subsampling) {
case ROCJPEG_CSS_444:
widths[2] = widths[1] = widths[0] = img_width;
heights[2] = heights[1] = heights[0] = img_height;
break;
case ROCJPEG_CSS_440:
widths[2] = widths[1] = widths[0] = img_width;
heights[0] = img_height;
heights[2] = heights[1] = img_height >> 1;
break;
case ROCJPEG_CSS_422:
widths[0] = img_width * 2;
heights[0] = img_height;
break;
case ROCJPEG_CSS_420:
widths[1] = widths[0] = img_width;
heights[0] = img_height;
heights[1] = img_height >> 1;
break;
case ROCJPEG_CSS_400:
widths[0] = img_width;
heights[0] = img_height;
break;
default:
std::cout << "Unknown chroma subsampling!" << std::endl;
return;
}
break;
case ROCJPEG_OUTPUT_YUV_PLANAR:
switch (subsampling) {
case ROCJPEG_CSS_444:
widths[2] = widths[1] = widths[0] = img_width;
heights[2] = heights[1] = heights[0] = img_height;
break;
case ROCJPEG_CSS_440:
widths[2] = widths[1] = widths[0] = img_width;
heights[0] = img_height;
heights[2] = heights[1] = img_height >> 1;
break;
case ROCJPEG_CSS_422:
widths[0] = img_width;
widths[2] = widths[1] = widths[0] >> 1;
heights[2] = heights[1] = heights[0] = img_height;
break;
case ROCJPEG_CSS_420:
widths[0] = img_width;
widths[2] = widths[1] = widths[0] >> 1;
heights[0] = img_height;
heights[2] = heights[1] = img_height >> 1;
break;
case ROCJPEG_CSS_400:
widths[0] = img_width;
heights[0] = img_height;
break;
default:
std::cout << "Unknown chroma subsampling!" << std::endl;
return;
}
break;
case ROCJPEG_OUTPUT_Y:
widths[0] = img_width;
heights[0] = img_height;
break;
case ROCJPEG_OUTPUT_RGB:
widths[0] = img_width * 3;
heights[0] = img_height;
break;
case ROCJPEG_OUTPUT_RGB_PLANAR:
widths[2] = widths[1] = widths[0] = img_width;
heights[2] = heights[1] = heights[0] = img_height;
break;
default:
std::cout << "Unknown output format!" << std::endl;
return;
}
aliged_heights[0] = align(heights[0], mem_alignment);
aliged_heights[1] = align(heights[1], mem_alignment);
aliged_heights[2] = align(heights[2], mem_alignment);
uint32_t channel0_size = output_image->pitch[0] * aliged_heights[0];
uint32_t channel1_size = output_image->pitch[1] * aliged_heights[1];
uint32_t channel2_size = output_image->pitch[2] * aliged_heights[2];
uint32_t output_image_size = channel0_size + channel1_size + channel2_size;
if (hst_ptr == nullptr) {
hst_ptr = new uint8_t [output_image_size];
}
CHECK_HIP(hipMemcpyDtoH((void *)hst_ptr, output_image->channel[0], channel0_size));
uint8_t *tmp_hst_ptr = hst_ptr;
fp = fopen(output_file_name.c_str(), "wb");
if (fp) {
// write channel0
if (widths[0] == output_image->pitch[0] && heights[0] == aliged_heights[0]) {
fwrite(hst_ptr, 1, channel0_size, fp);
} else {
for (int i = 0; i < heights[0]; i++) {
fwrite(tmp_hst_ptr, 1, widths[0], fp);
tmp_hst_ptr += output_image->pitch[0];
}
}
// write channel1
if (channel1_size != 0 && output_image->channel[1] != nullptr) {
uint8_t *channel1_hst_ptr = hst_ptr + channel0_size;
CHECK_HIP(hipMemcpyDtoH((void *)channel1_hst_ptr, output_image->channel[1], channel1_size));
if (widths[1] == output_image->pitch[1] && heights[1] == aliged_heights[1]) {
fwrite(channel1_hst_ptr, 1, channel1_size, fp);
} else {
for (int i = 0; i < heights[1]; i++) {
fwrite(channel1_hst_ptr, 1, widths[1], fp);
channel1_hst_ptr += output_image->pitch[1];
}
}
}
// write channel2
if (channel2_size != 0 && output_image->channel[2] != nullptr) {
uint8_t *channel2_hst_ptr = hst_ptr + channel0_size + channel1_size;
CHECK_HIP(hipMemcpyDtoH((void *)channel2_hst_ptr, output_image->channel[2], channel2_size));
if (widths[2] == output_image->pitch[2] && heights[2] == aliged_heights[2]) {
fwrite(channel2_hst_ptr, 1, channel2_size, fp);
} else {
for (int i = 0; i < heights[2]; i++) {
fwrite(channel2_hst_ptr, 1, widths[2], fp);
channel2_hst_ptr += output_image->pitch[2];
}
}
}
fclose(fp);
}
if (hst_ptr != nullptr) {
delete [] hst_ptr;
hst_ptr = nullptr;
tmp_hst_ptr = nullptr;
}
}
private:
static const int mem_alignment = 16;
/**
* @brief Shows the help message and exits.
*
* This function shows the help message and exits the program.
*
* @param option The option to display in the help message (optional).
* @param show_threads Flag indicating whether to show the number of threads in the help message.
*/
static void ShowHelpAndExit(const char *option = nullptr, bool show_threads = false, bool show_batch_size = false) {
std::cout << "Options:\n"
"-i [input path] - input path to a single JPEG image or a directory containing JPEG images - [required]\n"
"-be [backend] - select rocJPEG backend (0 for hardware-accelerated JPEG decoding using VCN,\n"
" 1 for hybrid JPEG decoding using CPU and GPU HIP kernels (currently not supported)) [optional - default: 0]\n"
"-fmt [output format] - select rocJPEG output format for decoding, one of the [native, yuv_planar, y, rgb, rgb_planar] - [optional - default: native]\n"
"-o [output path] - path to an output file or a path to an existing directory - write decoded images to a file or an existing directory based on selected output format - [optional]\n"
"-crop [crop rectangle] - crop rectangle for output in a comma-separated format: left,top,right,bottom - [optional]\n"
"-d [device id] - specify the GPU device id for the desired device (use 0 for the first device, 1 for the second device, and so on) [optional - default: 0]\n";
if (show_threads) {
std::cout << "-t [threads] - number of threads (<= 32) for parallel JPEG decoding - [optional - default: 1]\n";
}
if (show_batch_size) {
std::cout << "-b [batch_size] - decode images from input by batches of a specified size - [optional - default: 1]\n";
}
exit(0);
}
/**
* @brief Aligns a value to a specified alignment.
*
* This function takes a value and aligns it to the specified alignment. It returns the aligned value.
*
* @param value The value to be aligned.
* @param alignment The alignment value.
* @return The aligned value.
*/
static inline int align(int value, int alignment) {
return (value + alignment - 1) & ~(alignment - 1);
}
};
class ThreadPool {
public:
ThreadPool(int nthreads) : shutdown_(false) {
// Create the specified number of threads
threads_.reserve(nthreads);
for (int i = 0; i < nthreads; ++i)
threads_.emplace_back(std::bind(&ThreadPool::ThreadEntry, this, i));
}
~ThreadPool() {}
void JoinThreads() {
{
// Unblock any threads and tell them to stop
std::unique_lock<std::mutex> lock(mutex_);
shutdown_ = true;
cond_var_.notify_all();
}
// Wait for all threads to stop
for (auto& thread : threads_)
thread.join();
}
void ExecuteJob(std::function<void()> func) {
// Place a job on the queue and unblock a thread
std::unique_lock<std::mutex> lock(mutex_);
decode_jobs_queue_.emplace(std::move(func));
cond_var_.notify_one();
}
protected:
void ThreadEntry(int i) {
std::function<void()> execute_decode_job;
while (true) {
{
std::unique_lock<std::mutex> lock(mutex_);
cond_var_.wait(lock, [&] {return shutdown_ || !decode_jobs_queue_.empty();});
if (decode_jobs_queue_.empty()) {
// No jobs to do; shutting down
return;
}
execute_decode_job = std::move(decode_jobs_queue_.front());
decode_jobs_queue_.pop();
}
// Execute the decode job without holding any locks
execute_decode_job();
}
}
std::mutex mutex_;
std::condition_variable cond_var_;
bool shutdown_;
std::queue<std::function<void()>> decode_jobs_queue_;
std::vector<std::thread> threads_;
};
#endif //ROC_JPEG_SAMPLES_COMMON
@@ -0,0 +1,55 @@
/*
Copyright (c) 2024 - 2026 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 "../../api/amd_detail/rocjpeg_api_trace.h"
namespace rocjpeg {
const RocJpegDispatchTable* GetRocJpegDispatchTable();
} //namespace rocjpeg
RocJpegStatus ROCJPEGAPI rocJpegStreamCreate(RocJpegStreamHandle *jpeg_stream_handle) {
return rocjpeg::GetRocJpegDispatchTable()->pfn_rocjpeg_stream_create(jpeg_stream_handle);
}
RocJpegStatus ROCJPEGAPI rocJpegStreamParse(const unsigned char *data, size_t length, RocJpegStreamHandle jpeg_stream_handle) {
return rocjpeg::GetRocJpegDispatchTable()->pfn_rocjpeg_stream_parse(data, length, jpeg_stream_handle);
}
RocJpegStatus ROCJPEGAPI rocJpegStreamDestroy(RocJpegStreamHandle jpeg_stream_handle) {
return rocjpeg::GetRocJpegDispatchTable()->pfn_rocjpeg_stream_destroy(jpeg_stream_handle);
}
RocJpegStatus ROCJPEGAPI rocJpegCreate(RocJpegBackend backend, int device_id, RocJpegHandle *handle) {
return rocjpeg::GetRocJpegDispatchTable()->pfn_rocjpeg_create(backend, device_id, handle);
}
RocJpegStatus ROCJPEGAPI rocJpegDestroy(RocJpegHandle handle) {
return rocjpeg::GetRocJpegDispatchTable()->pfn_rocjpeg_destroy(handle);
}
RocJpegStatus ROCJPEGAPI rocJpegGetImageInfo(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, uint8_t *num_components, RocJpegChromaSubsampling *subsampling, uint32_t *widths, uint32_t *heights) {
return rocjpeg::GetRocJpegDispatchTable()->pfn_rocjpeg_get_image_info(handle, jpeg_stream_handle, num_components, subsampling, widths, heights);
}
RocJpegStatus ROCJPEGAPI rocJpegDecode(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, const RocJpegDecodeParams *decode_params, RocJpegImage *destination) {
return rocjpeg::GetRocJpegDispatchTable()->pfn_rocjpeg_decode(handle, jpeg_stream_handle, decode_params, destination);
}
RocJpegStatus ROCJPEGAPI rocJpegDecodeBatched(RocJpegHandle handle, RocJpegStreamHandle *jpeg_stream_handles, int batch_size, const RocJpegDecodeParams *decode_params, RocJpegImage *destinations) {
return rocjpeg::GetRocJpegDispatchTable()->pfn_rocjpeg_decode_batched(handle, jpeg_stream_handles, batch_size, decode_params, destinations);
}
const char* ROCJPEGAPI rocJpegGetErrorName(RocJpegStatus rocjpeg_status) {
return rocjpeg::GetRocJpegDispatchTable()->pfn_rocjpeg_get_error_name(rocjpeg_status);
}
@@ -0,0 +1,153 @@
/*
Copyright (c) 2024 - 2026 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 "../../api/amd_detail/rocjpeg_api_trace.h"
#if defined(ROCJPEG_ROCPROFILER_REGISTER) && ROCJPEG_ROCPROFILER_REGISTER > 0
#include <rocprofiler-register/rocprofiler-register.h>
#define ROCJPEG_ROCP_REG_VERSION \
ROCPROFILER_REGISTER_COMPUTE_VERSION_3(ROCJPEG_ROCP_REG_VERSION_MAJOR, ROCJPEG_ROCP_REG_VERSION_MINOR, \
ROCJPEG_ROCP_REG_VERSION_PATCH)
ROCPROFILER_REGISTER_DEFINE_IMPORT(rocjpeg, ROCJPEG_ROCP_REG_VERSION)
#elif !defined(ROCJPEG_ROCPROFILER_REGISTER)
#define ROCJPEG_ROCPROFILER_REGISTER 0
#endif
namespace rocjpeg {
RocJpegStatus ROCJPEGAPI rocJpegStreamCreate(RocJpegStreamHandle *jpeg_stream_handle);
RocJpegStatus ROCJPEGAPI rocJpegStreamParse(const unsigned char *data, size_t length, RocJpegStreamHandle jpeg_stream_handle);
RocJpegStatus ROCJPEGAPI rocJpegStreamDestroy(RocJpegStreamHandle jpeg_stream_handle);
RocJpegStatus ROCJPEGAPI rocJpegCreate(RocJpegBackend backend, int device_id, RocJpegHandle *handle);
RocJpegStatus ROCJPEGAPI rocJpegDestroy(RocJpegHandle handle);
RocJpegStatus ROCJPEGAPI rocJpegGetImageInfo(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, uint8_t *num_components, RocJpegChromaSubsampling *subsampling, uint32_t *widths, uint32_t *heights);
RocJpegStatus ROCJPEGAPI rocJpegDecode(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, const RocJpegDecodeParams *decode_params, RocJpegImage *destination);
RocJpegStatus ROCJPEGAPI rocJpegDecodeBatched(RocJpegHandle handle, RocJpegStreamHandle *jpeg_stream_handles, int batch_size, const RocJpegDecodeParams *decode_params, RocJpegImage *destinations);
const char* ROCJPEGAPI rocJpegGetErrorName(RocJpegStatus rocjpeg_status);
}
namespace rocjpeg {
namespace {
void UpdateDispatchTable(RocJpegDispatchTable* ptr_dispatch_table) {
ptr_dispatch_table->size = sizeof(RocJpegDispatchTable);
ptr_dispatch_table->pfn_rocjpeg_stream_create = rocjpeg::rocJpegStreamCreate;
ptr_dispatch_table->pfn_rocjpeg_stream_parse = rocjpeg::rocJpegStreamParse;
ptr_dispatch_table->pfn_rocjpeg_stream_destroy = rocjpeg::rocJpegStreamDestroy;
ptr_dispatch_table->pfn_rocjpeg_create = rocjpeg::rocJpegCreate;
ptr_dispatch_table->pfn_rocjpeg_destroy = rocjpeg::rocJpegDestroy;
ptr_dispatch_table->pfn_rocjpeg_get_image_info = rocjpeg::rocJpegGetImageInfo;
ptr_dispatch_table->pfn_rocjpeg_decode = rocjpeg::rocJpegDecode;
ptr_dispatch_table->pfn_rocjpeg_decode_batched = rocjpeg::rocJpegDecodeBatched;
ptr_dispatch_table->pfn_rocjpeg_get_error_name = rocjpeg::rocJpegGetErrorName;
}
#if ROCJPEG_ROCPROFILER_REGISTER > 0
template <typename Tp> struct dispatch_table_info;
#define ROCJPEG_DEFINE_DISPATCH_TABLE_INFO(TYPE, NAME) \
template <> struct dispatch_table_info<TYPE> { \
static constexpr auto name = #NAME; \
static constexpr auto version = ROCJPEG_ROCP_REG_VERSION; \
static constexpr auto import_func = &ROCPROFILER_REGISTER_IMPORT_FUNC(NAME); \
};
ROCJPEG_DEFINE_DISPATCH_TABLE_INFO(RocJpegDispatchTable, rocjpeg)
#endif
template <typename Tp> void ToolInit(Tp* table) {
#if ROCJPEG_ROCPROFILER_REGISTER > 0
auto table_array = std::array<void*, 1>{static_cast<void*>(table)};
auto lib_id = rocprofiler_register_library_indentifier_t{};
rocprofiler_register_library_api_table(
dispatch_table_info<Tp>::name, dispatch_table_info<Tp>::import_func,
dispatch_table_info<Tp>::version, table_array.data(), table_array.size(), &lib_id);
#else
(void)table;
#endif
}
template <typename Tp> Tp& GetDispatchTableImpl() {
static auto dispatch_table = Tp{};
// Update all function pointers to reference the runtime implementation functions of rocJPEG.
UpdateDispatchTable(&dispatch_table);
// The profiler registration process may encapsulate the function pointers.
ToolInit(&dispatch_table);
return dispatch_table;
}
} //namespace
const RocJpegDispatchTable* GetRocJpegDispatchTable() {
static auto* rocjpeg_dispatch_table = &GetDispatchTableImpl<RocJpegDispatchTable>();
return rocjpeg_dispatch_table;
}
} //namespace rocjpeg
#if !defined(_WIN32)
constexpr auto ComputeTableOffset(size_t num_funcs) {
return (num_funcs * sizeof(void*)) + sizeof(size_t);
}
// The `ROCJPEG_ENFORCE_ABI_VERSIONING` macro will trigger a compiler error if the size of the rocJPEG dispatch API table changes,
// which is most likely due to the addition of a new dispatch table entry. This serves as a reminder for developers to update the table
// versioning value before changing the value in `ROCJPEG_ENFORCE_ABI_VERSIONING`, ensuring that this static assertion passes.
//
// The `ROCJPEG_ENFORCE_ABI` macro will also trigger a compiler error if the order of the members in the rocJPEG dispatch API table
// is altered. Therefore, it is essential to avoid reordering member variables.
//
// Please be aware that `rocprofiler` performs strict compile-time checks to ensure that these versioning values are correctly updated.
// Commenting out this check or merely updating the size field in `ROCJPEG_ENFORCE_ABI_VERSIONING` will cause the `rocprofiler` to fail
// during the build process.
#define ROCJPEG_ENFORCE_ABI_VERSIONING(TABLE, NUM) \
static_assert( \
sizeof(TABLE) == ComputeTableOffset(NUM), \
"The size of the API table structure has been updated. Please modify the " \
"STEP_VERSION number (or, in rare cases, the MAJOR_VERSION number) " \
"in <rocJPEG/api/amd_detail/rocjpeg_api_trace.h> for the failing API " \
"structure before changing the SIZE field passed to ROCJPEG_DEFINE_DISPATCH_TABLE_INFO.");
#define ROCJPEG_ENFORCE_ABI(TABLE, ENTRY, NUM) \
static_assert(offsetof(TABLE, ENTRY) == ComputeTableOffset(NUM), \
"ABI broke for " #TABLE "." #ENTRY \
", only add new function pointers at the end of the struct and do not rearrange them.");
// These ensure that function pointers are not re-ordered
// ROCJPEG_RUNTIME_API_TABLE_STEP_VERSION == 0
ROCJPEG_ENFORCE_ABI(RocJpegDispatchTable, pfn_rocjpeg_stream_create, 0)
ROCJPEG_ENFORCE_ABI(RocJpegDispatchTable, pfn_rocjpeg_stream_parse, 1)
ROCJPEG_ENFORCE_ABI(RocJpegDispatchTable, pfn_rocjpeg_stream_destroy, 2)
ROCJPEG_ENFORCE_ABI(RocJpegDispatchTable, pfn_rocjpeg_create, 3)
ROCJPEG_ENFORCE_ABI(RocJpegDispatchTable, pfn_rocjpeg_destroy, 4)
ROCJPEG_ENFORCE_ABI(RocJpegDispatchTable, pfn_rocjpeg_get_image_info, 5)
ROCJPEG_ENFORCE_ABI(RocJpegDispatchTable, pfn_rocjpeg_decode, 6)
ROCJPEG_ENFORCE_ABI(RocJpegDispatchTable, pfn_rocjpeg_decode_batched, 7)
ROCJPEG_ENFORCE_ABI(RocJpegDispatchTable, pfn_rocjpeg_get_error_name, 8)
// If ROCJPEG_ENFORCE_ABI entries are added for each new function pointer in the table,
// the number below will be one greater than the number in the last ROCJPEG_ENFORCE_ABI line. For example:
// ROCJPEG_ENFORCE_ABI(<table>, <functor>, 8)
// ROCJPEG_ENFORCE_ABI_VERSIONING(<table>, 9) <- 8 + 1 = 9
ROCJPEG_ENFORCE_ABI_VERSIONING(RocJpegDispatchTable, 9)
static_assert(ROCJPEG_RUNTIME_API_TABLE_MAJOR_VERSION == 0 && ROCJPEG_RUNTIME_API_TABLE_STEP_VERSION == 0,
"If you encounter this error, add the new ROCJPEG_ENFORCE_ABI(...) code for the updated function pointers, "
"and then modify this check to ensure it evaluates to true.");
#endif
+279
Visa fil
@@ -0,0 +1,279 @@
/*
Copyright (c) 2024 - 2026 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 "rocjpeg_api_stream_handle.h"
#include "rocjpeg_api_decoder_handle.h"
#include "rocjpeg_commons.h"
namespace rocjpeg {
/**
* @brief Creates a RocJpegStreamHandle for JPEG stream processing.
*
* This function creates a RocJpegStreamHandle, which is used for processing JPEG streams.
* The created handle is assigned to the provided jpeg_stream_handle pointer.
*
* @param jpeg_stream_handle A pointer to a RocJpegStreamHandle variable that will hold the created handle.
* @return RocJpegStatus The status of the operation. Returns ROCJPEG_STATUS_SUCCESS if successful,
* ROCJPEG_STATUS_INVALID_PARAMETER if the jpeg_stream_handle pointer is nullptr,
* or ROCJPEG_STATUS_NOT_INITIALIZED if the rocJPEG stream handle failed to initialize.
*/
RocJpegStatus ROCJPEGAPI rocJpegStreamCreate(RocJpegStreamHandle *jpeg_stream_handle) {
if (jpeg_stream_handle == nullptr) {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
RocJpegStreamHandle rocjpeg_stream_handle = nullptr;
try {
rocjpeg_stream_handle = new RocJpegStreamParserHandle();
}
catch(const std::exception& e) {
ERR(STR("Failed to init the rocJPEG stream handle, ") + STR(e.what()));
return ROCJPEG_STATUS_NOT_INITIALIZED;
}
*jpeg_stream_handle = rocjpeg_stream_handle;
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Parses a JPEG stream.
*
* This function parses a JPEG stream represented by the input data and length,
* and updates the provided JPEG stream handle accordingly.
*
* @param data The pointer to the JPEG stream data.
* @param length The length of the JPEG stream data.
* @param jpeg_stream_handle The handle to the JPEG stream.
* @return The status of the JPEG stream parsing operation.
* - ROCJPEG_STATUS_SUCCESS if the parsing is successful.
* - ROCJPEG_STATUS_INVALID_PARAMETER if the input parameters are invalid.
* - ROCJPEG_STATUS_BAD_JPEG if the JPEG stream is invalid.
*/
RocJpegStatus ROCJPEGAPI rocJpegStreamParse(const unsigned char *data, size_t length, RocJpegStreamHandle jpeg_stream_handle) {
if (data == nullptr || jpeg_stream_handle == nullptr) {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
auto rocjpeg_stream_handle = static_cast<RocJpegStreamParserHandle*>(jpeg_stream_handle);
if (!rocjpeg_stream_handle->rocjpeg_stream->ParseJpegStream(data, length)) {
return ROCJPEG_STATUS_BAD_JPEG;
}
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Destroys a RocJpegStreamHandle object and releases associated resources.
*
* @param jpeg_stream_handle The handle to the RocJpegStreamHandle object to be destroyed.
* @return RocJpegStatus The status of the operation. Returns ROCJPEG_STATUS_SUCCESS if successful,
* or ROCJPEG_STATUS_INVALID_PARAMETER if the input handle is nullptr.
*/
RocJpegStatus ROCJPEGAPI rocJpegStreamDestroy(RocJpegStreamHandle jpeg_stream_handle) {
if (jpeg_stream_handle == nullptr) {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
auto rocjpeg_stream_handle = static_cast<RocJpegStreamParserHandle*>(jpeg_stream_handle);
delete rocjpeg_stream_handle;
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Creates a RocJpegHandle for JPEG decoding.
*
* This function creates a RocJpegHandle for JPEG decoding using the specified backend and device ID.
*
* @param backend The backend to be used for JPEG decoding.
* @param device_id The ID of the device to be used for JPEG decoding.
* @param handle Pointer to a RocJpegHandle variable to store the created handle.
* @return The status of the operation. Returns ROCJPEG_STATUS_INVALID_PARAMETER if handle is nullptr,
* ROCJPEG_STATUS_NOT_INITIALIZED if the rocJPEG handle initialization fails, or the status
* returned by the InitializeDecoder function of the rocjpeg_decoder.
*/
RocJpegStatus ROCJPEGAPI rocJpegCreate(RocJpegBackend backend, int device_id, RocJpegHandle *handle) {
if (handle == nullptr) {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
RocJpegHandle rocjpeg_handle = nullptr;
try {
rocjpeg_handle = new RocJpegDecoderHandle(backend, device_id);
} catch(const std::exception& e) {
ERR(STR("Failed to init the rocJPEG handle, ") + STR(e.what()));
return ROCJPEG_STATUS_NOT_INITIALIZED;
}
*handle = rocjpeg_handle;
return static_cast<RocJpegDecoderHandle *>(rocjpeg_handle)->rocjpeg_decoder->InitializeDecoder();
}
/**
* @brief Destroys a RocJpegHandle object.
*
* This function destroys the RocJpegHandle object pointed to by the given handle.
* It releases any resources associated with the handle and frees the memory.
*
* @param handle The handle to the RocJpegHandle object to be destroyed.
* @return The status of the operation. Returns ROCJPEG_STATUS_SUCCESS if the handle was successfully destroyed,
* or ROCJPEG_STATUS_INVALID_PARAMETER if the handle is nullptr.
*/
RocJpegStatus ROCJPEGAPI rocJpegDestroy(RocJpegHandle handle) {
if (handle == nullptr) {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
auto rocjpeg_handle = static_cast<RocJpegDecoderHandle*>(handle);
delete rocjpeg_handle;
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Retrieves information about the JPEG image.
*
* This function retrieves the number of components, chroma subsampling, and dimensions (width and height) of the JPEG image
* specified by the `jpeg_stream_handle`. The information is stored in the provided output parameters `num_components`,
* `subsampling`, `widths`, and `heights`.
*
* @param handle The handle to the RocJpegDecoder instance.
* @param jpeg_stream_handle The handle to the RocJpegStream instance representing the JPEG image.
* @param num_components A pointer to an unsigned 8-bit integer that will store the number of components in the JPEG image.
* @param subsampling A pointer to a RocJpegChromaSubsampling enum that will store the chroma subsampling information.
* @param widths A pointer to an unsigned 32-bit integer array that will store the width of each component in the JPEG image.
* @param heights A pointer to an unsigned 32-bit integer array that will store the height of each component in the JPEG image.
*
* @return The RocJpegStatus indicating the success or failure of the operation.
* - ROCJPEG_STATUS_SUCCESS: The operation was successful.
* - ROCJPEG_STATUS_INVALID_PARAMETER: One or more input parameters are invalid.
* - ROCJPEG_STATUS_RUNTIME_ERROR: An exception occurred during the operation.
*/
RocJpegStatus ROCJPEGAPI rocJpegGetImageInfo(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, uint8_t *num_components,
RocJpegChromaSubsampling *subsampling, uint32_t *widths, uint32_t *heights) {
if (handle == nullptr || num_components == nullptr ||
subsampling == nullptr || widths == nullptr || heights == nullptr) {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
RocJpegStatus rocjpeg_status = ROCJPEG_STATUS_SUCCESS;
auto rocjpeg_handle = static_cast<RocJpegDecoderHandle*>(handle);
try {
rocjpeg_status = rocjpeg_handle->rocjpeg_decoder->GetImageInfo(jpeg_stream_handle, num_components, subsampling, widths, heights);
} catch (const std::exception& e) {
rocjpeg_handle->CaptureError(e.what());
ERR(e.what());
return ROCJPEG_STATUS_RUNTIME_ERROR;
}
return rocjpeg_status;
}
/**
* @brief Decodes a JPEG image using the rocJPEG library.
*
* This function decodes a JPEG image using the rocJPEG library. It takes a rocJpegHandle, a rocJpegStreamHandle,
* a pointer to RocJpegDecodeParams, and a pointer to RocJpegImage as input parameters. The function returns a
* RocJpegStatus indicating the success or failure of the decoding operation.
*
* @param handle The rocJpegHandle representing the rocJPEG decoder instance.
* @param jpeg_stream_handle The rocJpegStreamHandle representing the input JPEG stream.
* @param decode_params A pointer to RocJpegDecodeParams containing the decoding parameters.
* @param destination A pointer to RocJpegImage where the decoded image will be stored.
* @return A RocJpegStatus indicating the success or failure of the decoding operation.
*/
RocJpegStatus ROCJPEGAPI rocJpegDecode(RocJpegHandle handle, RocJpegStreamHandle jpeg_stream_handle, const RocJpegDecodeParams *decode_params,
RocJpegImage *destination) {
if (handle == nullptr || decode_params == nullptr || destination == nullptr) {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
RocJpegStatus rocjpeg_status = ROCJPEG_STATUS_SUCCESS;
auto rocjpeg_handle = static_cast<RocJpegDecoderHandle*>(handle);
try {
rocjpeg_status = rocjpeg_handle->rocjpeg_decoder->Decode(jpeg_stream_handle, decode_params, destination);
} catch (const std::exception& e) {
rocjpeg_handle->CaptureError(e.what());
ERR(e.what());
return ROCJPEG_STATUS_RUNTIME_ERROR;
}
return rocjpeg_status;
}
/**
* @brief Decodes a batch of JPEG images using the rocJPEG library.
*
* Decodes a batch of JPEG images using the specified handle, stream handles, decode parameters, and destination images.
*
* @param handle The handle to the RocJpeg decoder.
* @param jpeg_stream_handles An array of stream handles for the JPEG images to be decoded.
* @param decode_params The decode parameters for the decoding process.
* @param destinations An array of RocJpegImage structures to store the decoded images.
* @return The status of the decoding process. Returns ROCJPEG_STATUS_SUCCESS if successful, or an error code otherwise.
*/
RocJpegStatus ROCJPEGAPI rocJpegDecodeBatched(RocJpegHandle handle, RocJpegStreamHandle *jpeg_stream_handles, int batch_size, const RocJpegDecodeParams *decode_params, RocJpegImage *destinations) {
if (handle == nullptr || jpeg_stream_handles == nullptr|| decode_params == nullptr || destinations == nullptr) {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
RocJpegStatus rocjpeg_status = ROCJPEG_STATUS_SUCCESS;
auto rocjpeg_handle = static_cast<RocJpegDecoderHandle*>(handle);
try {
rocjpeg_status = rocjpeg_handle->rocjpeg_decoder->DecodeBatched(jpeg_stream_handles, batch_size, decode_params, destinations);
} catch (const std::exception& e) {
rocjpeg_handle->CaptureError(e.what());
ERR(e.what());
return ROCJPEG_STATUS_RUNTIME_ERROR;
}
return rocjpeg_status;
}
/**
* @brief Returns the error name corresponding to the given RocJpegStatus.
*
* This function takes a RocJpegStatus enum value and returns the corresponding error name as a string.
*
* @param rocjpeg_status The RocJpegStatus enum value.
* @return The error name as a string.
*/
extern const char* ROCJPEGAPI rocJpegGetErrorName(RocJpegStatus rocjpeg_status) {
switch (rocjpeg_status) {
case ROCJPEG_STATUS_SUCCESS:
return "ROCJPEG_STATUS_SUCCESS";
case ROCJPEG_STATUS_NOT_INITIALIZED:
return "ROCJPEG_STATUS_NOT_INITIALIZED";
case ROCJPEG_STATUS_INVALID_PARAMETER:
return "ROCJPEG_STATUS_INVALID_PARAMETER";
case ROCJPEG_STATUS_BAD_JPEG:
return "ROCJPEG_STATUS_BAD_JPEG";
case ROCJPEG_STATUS_JPEG_NOT_SUPPORTED:
return "ROCJPEG_STATUS_JPEG_NOT_SUPPORTED";
case ROCJPEG_STATUS_EXECUTION_FAILED:
return "ROCJPEG_STATUS_EXECUTION_FAILED";
case ROCJPEG_STATUS_ARCH_MISMATCH:
return "ROCJPEG_STATUS_ARCH_MISMATCH";
case ROCJPEG_STATUS_INTERNAL_ERROR:
return "ROCJPEG_STATUS_INTERNAL_ERROR";
case ROCJPEG_STATUS_IMPLEMENTATION_NOT_SUPPORTED:
return "ROCJPEG_STATUS_IMPLEMENTATION_NOT_SUPPORTED";
case ROCJPEG_STATUS_HW_JPEG_DECODER_NOT_SUPPORTED:
return "ROCJPEG_STATUS_HW_JPEG_DECODER_NOT_SUPPORTED";
case ROCJPEG_STATUS_RUNTIME_ERROR:
return "ROCJPEG_STATUS_RUNTIME_ERROR";
case ROCJPEG_STATUS_OUTOF_MEMORY:
return "ROCJPEG_STATUS_OUTOF_MEMORY";
case ROCJPEG_STATUS_NOT_IMPLEMENTED:
return "ROCJPEG_STATUS_NOT_IMPLEMENTED";
default:
return "UNKNOWN_ERROR";
}
}
} //namespace rocjpeg
@@ -0,0 +1,88 @@
/*
Copyright (c) 2024 - 2026 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.
*/
#ifndef ROC_JPEG_DECODER_HANDLE_H
#define ROC_JPEG_DECODER_HANDLE_H
#pragma once
#include "rocjpeg_decoder.h"
/**
* @brief The RocJpegDecoderHandle class represents a handle to the RocJpegDecoder object.
*
* This class provides a convenient way to manage the lifetime of a RocJpegDecoder object.
* It encapsulates the RocJpegDecoder object and provides error handling functionality.
*/
class RocJpegDecoderHandle {
public:
/**
* @brief Constructs a RocJpegDecoderHandle object with the specified backend and device ID.
*
* @param backend The backend to use for decoding.
* @param device_id The ID of the device to use for decoding.
*/
explicit RocJpegDecoderHandle(RocJpegBackend backend, int device_id) : rocjpeg_decoder(std::make_shared<RocJpegDecoder>(backend, device_id)) {};
/**
* @brief Destructor for the RocJpegDecoderHandle class.
*
* Clears any errors associated with the handle.
*/
~RocJpegDecoderHandle() { ClearErrors(); }
/**
* @brief The RocJpegDecoder object associated with the handle.
*/
std::shared_ptr<RocJpegDecoder> rocjpeg_decoder;
/**
* @brief Checks if there are no errors associated with the handle.
*
* @return true if there are no errors, false otherwise.
*/
bool NoError() { return error_.empty(); }
/**
* @brief Gets the error message associated with the handle.
*
* @return The error message as a C-style string.
*/
const char* ErrorMsg() { return error_.c_str(); }
/**
* @brief Captures an error message for the handle.
*
* @param err_msg The error message to capture.
*/
void CaptureError(const std::string& err_msg) { error_ = err_msg; }
private:
/**
* @brief Clears any errors associated with the handle.
*/
void ClearErrors() { error_ = ""; }
std::string error_;
};
#endif //ROC_JPEG_DECODER_HANDLE_H
@@ -0,0 +1,83 @@
/*
Copyright (c) 2024 - 2026 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.
*/
#ifndef ROC_JPEG_STREAM_HANDLE_H
#define ROC_JPEG_STREAM_HANDLE_H
#pragma once
#include <memory>
#include "rocjpeg_parser.h"
/**
* @brief The RocJpegStreamParserHandle class represents a handle to the RocJpegStreamParser object.
*
* This class provides a convenient way to manage the RocJpegStreamParser object by encapsulating it
* within a shared pointer. It also provides error handling functionality.
*/
class RocJpegStreamParserHandle {
public:
/**
* @brief Constructs a RocJpegStreamParserHandle object.
*
* This constructor initializes the rocjpeg_stream member with a new instance of RocJpegStreamParser
* using std::make_shared.
*/
explicit RocJpegStreamParserHandle() : rocjpeg_stream(std::make_shared<RocJpegStreamParser>()) {};
/**
* @brief Destroys the RocJpegStreamParserHandle object.
*
* This destructor clears any errors associated with the handle.
*/
~RocJpegStreamParserHandle() { ClearErrors(); }
std::shared_ptr<RocJpegStreamParser> rocjpeg_stream; /**< The RocJpegStreamParser object. */
/**
* @brief Checks if there are no errors associated with the handle.
* @return true if there are no errors, false otherwise.
*/
bool NoError() { return error_.empty(); }
/**
* @brief Gets the error message associated with the handle.
* @return The error message as a C-style string.
*/
const char* ErrorMsg() { return error_.c_str(); }
/**
* @brief Captures an error message.
* @param err_msg The error message to capture.
*/
void CaptureError(const std::string& err_msg) { error_ = err_msg; }
private:
/**
* @brief Clears any errors associated with the handle.
*/
void ClearErrors() { error_ = "";}
std::string error_; /**< The error message. */
};
#endif //ROC_JPEG_STREAM_HANDLE_H
+104
Visa fil
@@ -0,0 +1,104 @@
/*
Copyright (c) 2024 - 2026 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.
*/
#ifndef ROC_JPEG_COMMON_H_
#define ROC_JPEG_COMMON_H_
#pragma once
#include <stdexcept>
#include <exception>
#include <string>
#include <iostream>
#include <cstring>
#define TOSTR(X) std::to_string(static_cast<int>(X))
#define STR(X) std::string(X)
#if DBGINFO
#define INFO(X) std::clog << "[INF] " << " {" << __func__ <<"} " << " " << X << std::endl;
#else
#define INFO(X) ;
#endif
#define ERR(X) std::cerr << "[ERR] " << " {" << __func__ <<"} " << " " << X << std::endl;
#define CHECK_VAAPI(call) { \
VAStatus va_status = (call); \
if (va_status != VA_STATUS_SUCCESS) { \
std::cerr << "VAAPI failure: " << #call << " failed with status: " << std::hex << "0x" << va_status << std::dec << " = '" << vaErrorStr(va_status) << "' at " << __FILE__ << ":" << __LINE__ << std::endl;\
return ROCJPEG_STATUS_EXECUTION_FAILED; \
} \
}
#define CHECK_HIP(call) { \
hipError_t hip_status = (call); \
if (hip_status != hipSuccess) { \
std::cerr << "HIP failure: 'status: " << hipGetErrorName(hip_status) << "' at " << __FILE__ << ":" << __LINE__ << std::endl;\
return ROCJPEG_STATUS_EXECUTION_FAILED; \
} \
}
#define CHECK_ROCJPEG(call) { \
RocJpegStatus rocjpeg_status = (call); \
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) { \
std::cerr << #call << " returned " << rocJpegGetErrorName(rocjpeg_status) << " at " << __FILE__ << ":" << __LINE__ << std::endl;\
return rocjpeg_status; \
} \
}
static inline int align(int value, int alignment) {
return (value + alignment - 1) & ~(alignment - 1);
}
/**
* @brief Custom exception class for RocJpeg.
*
* This exception class is used to handle errors and exceptions that occur during RocJpeg operations.
* It inherits from the std::exception class and provides an implementation for the what() function.
*/
class RocJpegException : public std::exception {
public:
/**
* @brief Constructs a RocJpegException object with the specified error message.
*
* @param message The error message associated with the exception.
*/
explicit RocJpegException(const std::string& message):message_(message){}
/**
* @brief Returns a C-style string describing the exception.
*
* This function overrides the what() function from the std::exception class and returns
* the error message associated with the exception.
*
* @return A C-style string describing the exception.
*/
virtual const char* what() const throw() override {
return message_.c_str();
}
private:
std::string message_;
};
#define THROW(X) throw RocJpegException(" { "+std::string(__func__)+" } " + X);
#endif //ROC_JPEG_COMMON_H_
+708
Visa fil
@@ -0,0 +1,708 @@
/*
Copyright (c) 2024 - 2026 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 "rocjpeg_decoder.h"
RocJpegDecoder::RocJpegDecoder(RocJpegBackend backend, int device_id) :
num_devices_{0}, device_id_ {device_id}, hip_stream_ {0}, backend_{backend} {}
RocJpegDecoder::~RocJpegDecoder() {
if (hip_stream_) {
hipError_t hip_status = hipStreamDestroy(hip_stream_);
if (hip_status != hipSuccess) {
ERR("ERROR: Failed to destroy the HIP stream!");
}
}
}
/**
* @brief Initializes the HIP environment for the RocJpegDecoder.
*
* This function initializes the HIP environment for the RocJpegDecoder by setting the device,
* creating a HIP stream, and retrieving device properties.
*
* @param device_id The ID of the device to be used for decoding.
* @return The status of the initialization process.
* - ROCJPEG_STATUS_SUCCESS if the initialization is successful.
* - ROCJPEG_STATUS_NOT_INITIALIZED if no GPU device is found.
* - ROCJPEG_STATUS_INVALID_PARAMETER if the requested device_id is not found.
*/
RocJpegStatus RocJpegDecoder::InitHIP(int device_id) {
CHECK_HIP(hipGetDeviceCount(&num_devices_));
if (num_devices_ < 1) {
ERR("ERROR: Failed to find any GPU!");
return ROCJPEG_STATUS_NOT_INITIALIZED;
}
if (device_id >= num_devices_) {
ERR("ERROR: the requested device_id is not found!");
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
CHECK_HIP(hipSetDevice(device_id));
CHECK_HIP(hipGetDeviceProperties(&hip_dev_prop_, device_id));
CHECK_HIP(hipStreamCreate(&hip_stream_));
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Initializes the RocJpegDecoder.
*
* This function initializes the RocJpegDecoder by performing the following steps:
* 1. Initializes the HIP device.
* 2. If the backend is ROCJPEG_BACKEND_HARDWARE, initializes the VA-API JPEG decoder.
*
* @return The status of the initialization process.
* - ROCJPEG_STATUS_SUCCESS if the initialization is successful.
* - An error code if the initialization fails.
*/
RocJpegStatus RocJpegDecoder::InitializeDecoder() {
RocJpegStatus rocjpeg_status = ROCJPEG_STATUS_SUCCESS;
rocjpeg_status = InitHIP(device_id_);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
ERR("ERROR: Failed to initilize the HIP!");
return rocjpeg_status;
}
if (backend_ == ROCJPEG_BACKEND_HARDWARE) {
std::string gpu_uuid(hip_dev_prop_.uuid.bytes, sizeof(hip_dev_prop_.uuid.bytes));
rocjpeg_status = jpeg_vaapi_decoder_.InitializeDecoder(hip_dev_prop_.name, device_id_, gpu_uuid);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
ERR("ERROR: Failed to initialize the VA-API JPEG decoder!");
return rocjpeg_status;
}
} else if (backend_ == ROCJPEG_BACKEND_HYBRID) {
return ROCJPEG_STATUS_NOT_IMPLEMENTED;
} else {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
return rocjpeg_status;
}
/**
* @brief Decodes a JPEG image using the RocJpegDecoder.
*
* This function decodes a JPEG image from the provided JPEG stream handle and decode parameters,
* and stores the decoded image in the destination buffer.
*
* @param jpeg_stream_handle The handle to the JPEG stream.
* @param decode_params The decode parameters for the JPEG image.
* @param destination The destination buffer to store the decoded image.
* @return The status of the JPEG decoding operation.
*/
RocJpegStatus RocJpegDecoder::Decode(RocJpegStreamHandle jpeg_stream_handle, const RocJpegDecodeParams *decode_params, RocJpegImage *destination) {
std::lock_guard<std::mutex> lock(mutex_);
if (jpeg_stream_handle == nullptr || decode_params == nullptr || destination == nullptr) {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
auto rocjpeg_stream_handle = static_cast<RocJpegStreamParserHandle*>(jpeg_stream_handle);
const JpegStreamParameters *jpeg_stream_params = rocjpeg_stream_handle->rocjpeg_stream->GetJpegStreamParameters();
VASurfaceID current_surface_id;
CHECK_ROCJPEG(jpeg_vaapi_decoder_.SubmitDecode(jpeg_stream_params, current_surface_id, decode_params));
HipInteropDeviceMem hip_interop_dev_mem = {};
CHECK_ROCJPEG(jpeg_vaapi_decoder_.SyncSurface(current_surface_id));
CHECK_ROCJPEG(jpeg_vaapi_decoder_.GetHipInteropMem(current_surface_id, hip_interop_dev_mem));
uint16_t chroma_height = 0;
uint16_t picture_width = 0;
uint16_t picture_height = 0;
bool is_roi_valid = false;
uint32_t roi_width;
uint32_t roi_height;
roi_width = decode_params->crop_rectangle.right - decode_params->crop_rectangle.left;
roi_height = decode_params->crop_rectangle.bottom - decode_params->crop_rectangle.top;
if (roi_width > 0 && roi_height > 0 && roi_width <= jpeg_stream_params->picture_parameter_buffer.picture_width && roi_height <= jpeg_stream_params->picture_parameter_buffer.picture_height) {
is_roi_valid = true;
}
picture_width = is_roi_valid ? roi_width : jpeg_stream_params->picture_parameter_buffer.picture_width;
picture_height = is_roi_valid ? roi_height : jpeg_stream_params->picture_parameter_buffer.picture_height;
VcnJpegSpec current_vcn_jpeg_spec = jpeg_vaapi_decoder_.GetCurrentVcnJpegSpec();
if (is_roi_valid && current_vcn_jpeg_spec.can_roi_decode) {
// Set is_roi_valid to false because in this case, the hardware handles the ROI decode and we don't
// need to calculate the roi_offset later in the following functions (e.g., CopyChannel, GetPlanarYUVOutputFormat, etc) to copy the crop rectangle
is_roi_valid = false;
}
switch (decode_params->output_format) {
case ROCJPEG_OUTPUT_NATIVE:
// Copy the native decoded output buffers from interop memory directly to the destination buffers
CHECK_ROCJPEG(GetChromaHeight(hip_interop_dev_mem.surface_format, picture_height, chroma_height));
// Copy Luma (first channel) for any surface format
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, picture_height, 0, destination, decode_params, is_roi_valid));
if (hip_interop_dev_mem.surface_format == VA_FOURCC_NV12) {
// Copy the second channel (UV interleaved) for NV12
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, chroma_height, 1, destination, decode_params, is_roi_valid));
} else if (hip_interop_dev_mem.surface_format == VA_FOURCC_444P ||
hip_interop_dev_mem.surface_format == VA_FOURCC_422V) {
// Copy the second and third channels for YUV444 and YUV440 (i.e., YUV422V)
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, chroma_height, 1, destination, decode_params, is_roi_valid));
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, chroma_height, 2, destination, decode_params, is_roi_valid));
}
break;
case ROCJPEG_OUTPUT_YUV_PLANAR:
CHECK_ROCJPEG(GetChromaHeight(hip_interop_dev_mem.surface_format, picture_height, chroma_height));
CHECK_ROCJPEG(GetPlanarYUVOutputFormat(hip_interop_dev_mem, picture_width,
picture_height, chroma_height, destination, decode_params, is_roi_valid));
break;
case ROCJPEG_OUTPUT_Y:
CHECK_ROCJPEG(GetYOutputFormat(hip_interop_dev_mem, picture_width,
picture_height, destination, decode_params, is_roi_valid));
break;
case ROCJPEG_OUTPUT_RGB:
CHECK_ROCJPEG(ColorConvertToRGB(hip_interop_dev_mem, picture_width,
picture_height, destination, decode_params, is_roi_valid));
break;
case ROCJPEG_OUTPUT_RGB_PLANAR:
CHECK_ROCJPEG(ColorConvertToRGBPlanar(hip_interop_dev_mem, picture_width,
picture_height, destination, decode_params, is_roi_valid));
break;
default:
break;
}
CHECK_ROCJPEG(jpeg_vaapi_decoder_.SetSurfaceAsIdle(current_surface_id));
CHECK_HIP(hipStreamSynchronize(hip_stream_));
return ROCJPEG_STATUS_SUCCESS;
}
/**
* Decodes a batch of JPEG streams using the specified decode parameters and stores the decoded images in the provided destinations.
*
* @param jpeg_streams An array of RocJpegStreamHandle objects representing the JPEG streams to be decoded.
* @param batch_size The number of JPEG streams in the batch.
* @param decode_params A pointer to RocJpegDecodeParams object containing the decode parameters.
* @param destinations An array of RocJpegImage objects where the decoded images will be stored.
* @return A RocJpegStatus value indicating the success or failure of the decoding operation.
*/
RocJpegStatus RocJpegDecoder::DecodeBatched(RocJpegStreamHandle *jpeg_streams, int batch_size, const RocJpegDecodeParams *decode_params, RocJpegImage *destinations) {
std::lock_guard<std::mutex> lock(mutex_);
if (jpeg_streams == nullptr || decode_params == nullptr || destinations == nullptr) {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
std::vector<VASurfaceID> current_surface_ids;
std::vector<JpegStreamParameters> jpeg_streams_params;
current_surface_ids.resize(batch_size);
jpeg_streams_params.resize(batch_size);
VcnJpegSpec current_vcn_jpeg_spec = jpeg_vaapi_decoder_.GetCurrentVcnJpegSpec();
for (int i = 0; i < batch_size; i += current_vcn_jpeg_spec.num_jpeg_cores) {
int batch_end = std::min(i + static_cast<int>(current_vcn_jpeg_spec.num_jpeg_cores), batch_size);
int current_batch_size = batch_end - i;
for (int j = i; j < batch_end; j++) {
auto rocjpeg_stream_handle = static_cast<RocJpegStreamParserHandle*>(jpeg_streams[j]);
const JpegStreamParameters *jpeg_stream_params = rocjpeg_stream_handle->rocjpeg_stream->GetJpegStreamParameters();
jpeg_streams_params[j] = std::move(*jpeg_stream_params);
}
CHECK_ROCJPEG(jpeg_vaapi_decoder_.SubmitDecodeBatched(jpeg_streams_params.data() + i, current_batch_size, &decode_params[i], current_surface_ids.data() + i));
for (int k = 0; k < current_batch_size; k++) {
HipInteropDeviceMem hip_interop_dev_mem = {};
VASurfaceID current_surface_id = *(current_surface_ids.data() + k + i);
const JpegStreamParameters *jpeg_stream_params = jpeg_streams_params.data() + k + i;
CHECK_ROCJPEG(jpeg_vaapi_decoder_.SyncSurface(current_surface_id));
CHECK_ROCJPEG(jpeg_vaapi_decoder_.GetHipInteropMem(current_surface_id, hip_interop_dev_mem));
uint16_t chroma_height = 0;
uint16_t picture_width = 0;
uint16_t picture_height = 0;
bool is_roi_valid = false;
uint32_t roi_width;
uint32_t roi_height;
roi_width = decode_params[k + i].crop_rectangle.right - decode_params[k + i].crop_rectangle.left;
roi_height = decode_params[k + i].crop_rectangle.bottom - decode_params[k + i].crop_rectangle.top;
if (roi_width > 0 && roi_height > 0 && roi_width <= jpeg_stream_params->picture_parameter_buffer.picture_width && roi_height <= jpeg_stream_params->picture_parameter_buffer.picture_height) {
is_roi_valid = true;
}
picture_width = is_roi_valid ? roi_width : jpeg_stream_params->picture_parameter_buffer.picture_width;
picture_height = is_roi_valid ? roi_height : jpeg_stream_params->picture_parameter_buffer.picture_height;
if (is_roi_valid && current_vcn_jpeg_spec.can_roi_decode) {
// Set is_roi_valid to false because in this case, the hardware handles the ROI decode and we don't need to calculate the roi_offset
// later in the following functions (e.g., CopyChannel, GetPlanarYUVOutputFormat, etc) to copy the crop rectangle
is_roi_valid = false;
}
switch (decode_params[k + i].output_format) {
case ROCJPEG_OUTPUT_NATIVE:
// Copy the native decoded output buffers from interop memory directly to the destination buffers
CHECK_ROCJPEG(GetChromaHeight(hip_interop_dev_mem.surface_format, picture_height, chroma_height));
// Copy Luma (first channel) for any surface format
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, picture_height, 0, &destinations[k + i], &decode_params[k + i], is_roi_valid));
if (hip_interop_dev_mem.surface_format == VA_FOURCC_NV12) {
// Copy the second channel (UV interleaved) for NV12
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, chroma_height, 1, &destinations[k + i], &decode_params[k + i], is_roi_valid));
} else if (hip_interop_dev_mem.surface_format == VA_FOURCC_444P ||
hip_interop_dev_mem.surface_format == VA_FOURCC_422V) {
// Copy the second and third channels for YUV444 and YUV440 (i.e., YUV422V)
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, chroma_height, 1, &destinations[k + i], &decode_params[k + i], is_roi_valid));
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, chroma_height, 2, &destinations[k + i], &decode_params[k + i], is_roi_valid));
}
break;
case ROCJPEG_OUTPUT_YUV_PLANAR:
CHECK_ROCJPEG(GetChromaHeight(hip_interop_dev_mem.surface_format, picture_height, chroma_height));
CHECK_ROCJPEG(GetPlanarYUVOutputFormat(hip_interop_dev_mem, picture_width,
picture_height, chroma_height, &destinations[k + i], &decode_params[k + i], is_roi_valid));
break;
case ROCJPEG_OUTPUT_Y:
CHECK_ROCJPEG(GetYOutputFormat(hip_interop_dev_mem, picture_width,
picture_height, &destinations[k + i], &decode_params[k + i], is_roi_valid));
break;
case ROCJPEG_OUTPUT_RGB:
CHECK_ROCJPEG(ColorConvertToRGB(hip_interop_dev_mem, picture_width,
picture_height, &destinations[k + i], &decode_params[k + i], is_roi_valid));
break;
case ROCJPEG_OUTPUT_RGB_PLANAR:
CHECK_ROCJPEG(ColorConvertToRGBPlanar(hip_interop_dev_mem, picture_width,
picture_height, &destinations[k + i], &decode_params[k + i], is_roi_valid));
break;
default:
break;
}
}
CHECK_HIP(hipStreamSynchronize(hip_stream_));
for (int k = 0; k < current_batch_size; k++) {
VASurfaceID current_surface_id = *(current_surface_ids.data() + k + i);
CHECK_ROCJPEG(jpeg_vaapi_decoder_.SetSurfaceAsIdle(current_surface_id));
}
}
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Retrieves the image information from the JPEG stream.
*
* This function retrieves the number of components, chroma subsampling, widths, and heights
* of the image from the given JPEG stream.
*
* @param jpeg_stream_handle The handle to the JPEG stream.
* @param num_components Pointer to store the number of components in the image.
* @param subsampling Pointer to store the chroma subsampling of the image.
* @param widths Array to store the widths of the image components.
* @param heights Array to store the heights of the image components.
* @return The status of the operation. Returns ROCJPEG_STATUS_SUCCESS if successful,
* or ROCJPEG_STATUS_INVALID_PARAMETER if any of the input parameters are invalid.
*/
RocJpegStatus RocJpegDecoder::GetImageInfo(RocJpegStreamHandle jpeg_stream_handle, uint8_t *num_components, RocJpegChromaSubsampling *subsampling, uint32_t *widths, uint32_t *heights){
std::lock_guard<std::mutex> lock(mutex_);
if (jpeg_stream_handle == nullptr || num_components == nullptr || subsampling == nullptr || widths == nullptr || heights == nullptr) {
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
auto rocjpeg_stream_handle = static_cast<RocJpegStreamParserHandle*>(jpeg_stream_handle);
const JpegStreamParameters *jpeg_stream_params = rocjpeg_stream_handle->rocjpeg_stream->GetJpegStreamParameters();
*num_components = jpeg_stream_params->picture_parameter_buffer.num_components;
widths[0] = jpeg_stream_params->picture_parameter_buffer.picture_width;
heights[0] = jpeg_stream_params->picture_parameter_buffer.picture_height;
widths[3] = 0;
heights[3] = 0;
switch (jpeg_stream_params->chroma_subsampling) {
case CSS_444:
*subsampling = ROCJPEG_CSS_444;
widths[2] = widths[1] = widths[0];
heights[2] = heights[1] = heights[0];
break;
case CSS_440:
*subsampling = ROCJPEG_CSS_440;
widths[2] = widths[1] = widths[0];
heights[2] = heights[1] = heights[0] >> 1;
break;
case CSS_422:
*subsampling = ROCJPEG_CSS_422;
widths[2] = widths[1] = widths[0] >> 1;
heights[2] = heights[1] = heights[0];
break;
case CSS_420:
*subsampling = ROCJPEG_CSS_420;
widths[2] = widths[1] = widths[0] >> 1;
heights[2] = heights[1] = heights[0] >> 1;
break;
case CSS_400:
*subsampling = ROCJPEG_CSS_400;
widths[3] = widths[2] = widths[1] = 0;
heights[3] = heights[2] = heights[1] = 0;
break;
case CSS_411:
*subsampling = ROCJPEG_CSS_411;
widths[2] = widths[1] = widths[0] >> 2;
heights[2] = heights[1] = heights[0];
break;
default:
*subsampling = ROCJPEG_CSS_UNKNOWN;
break;
}
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Copies a channel from the `hip_interop_dev_mem` to the `destination` image.
*
* This function copies the channel specified by `channel_index` from the `hip_interop_dev_mem` to the `destination` image.
* The `channel_height` parameter specifies the height of the channel.
*
* @param hip_interop_dev_mem The `HipInteropDeviceMem` object containing the source channel data.
* @param channel_width The width of the channel to be copied.
* @param channel_height The height of the channel to be copied.
* @param channel_index The index of the channel to be copied.
* @param destination The `RocJpegImage` object representing the destination image.
* @return The status of the operation. Returns `ROCJPEG_STATUS_SUCCESS` if the channel was copied successfully.
*/
RocJpegStatus RocJpegDecoder::CopyChannel(HipInteropDeviceMem& hip_interop_dev_mem, uint16_t channel_width, uint16_t channel_height, uint8_t channel_index, RocJpegImage *destination, const RocJpegDecodeParams *decode_params, bool is_roi_valid) {
if (hip_interop_dev_mem.pitch[channel_index] != 0 && destination->pitch[channel_index] != 0 && destination->channel[channel_index] != nullptr) {
uint32_t roi_offset = 0;
if (is_roi_valid) {
int16_t top = decode_params->crop_rectangle.top;
int16_t left = decode_params->crop_rectangle.left;
// adjustments need to be made for these 3 pixel formats
switch (hip_interop_dev_mem.surface_format) {
case VA_FOURCC_NV12:
case VA_FOURCC_422V:
top = (channel_index == 1 || channel_index == 2) ? top >> 1 : top;
break;
case VA_FOURCC_YUY2:
left *= 2;
break;
}
roi_offset = top * hip_interop_dev_mem.pitch[channel_index] + left;
}
uint32_t channel_widths[ROCJPEG_MAX_COMPONENT] = {};
uint32_t roi_width = decode_params->crop_rectangle.right - decode_params->crop_rectangle.left;
bool is_roi_width_valid = roi_width > 0 && roi_width <= channel_width;
switch (decode_params->output_format) {
case ROCJPEG_OUTPUT_NATIVE:
switch (hip_interop_dev_mem.surface_format) {
case VA_FOURCC_444P:
channel_widths[2] = channel_widths[1] = channel_widths[0] = is_roi_width_valid ? roi_width : channel_width;
break;
case VA_FOURCC_422V:
channel_widths[2] = channel_widths[1] = channel_widths[0] = is_roi_width_valid ? roi_width : channel_width;
break;
case VA_FOURCC_YUY2:
channel_widths[0] = (is_roi_width_valid ? roi_width : channel_width) * 2;
break;
case VA_FOURCC_NV12:
channel_widths[1] = channel_widths[0] = is_roi_width_valid ? roi_width : channel_width;
break;
case VA_FOURCC_Y800:
channel_widths[0] = is_roi_width_valid ? roi_width : channel_width;
break;
default:
ERR("Unknown output format!");
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
break;
case ROCJPEG_OUTPUT_YUV_PLANAR:
switch (hip_interop_dev_mem.surface_format) {
case VA_FOURCC_444P:
channel_widths[2] = channel_widths[1] = channel_widths[0] = is_roi_width_valid ? roi_width : channel_width;
break;
case VA_FOURCC_422V:
channel_widths[2] = channel_widths[1] = channel_widths[0] = is_roi_width_valid ? roi_width : channel_width;
break;
case VA_FOURCC_YUY2:
channel_widths[0] = is_roi_width_valid ? roi_width : channel_width;
channel_widths[2] = channel_widths[1] = channel_widths[0] >> 1;
break;
case VA_FOURCC_NV12:
channel_widths[0] = is_roi_width_valid ? roi_width : channel_width;
channel_widths[2] = channel_widths[1] = channel_widths[0] >> 1;
break;
case VA_FOURCC_Y800:
channel_widths[0] = is_roi_width_valid ? roi_width : channel_width;
break;
default:
ERR("Unknown output format!");
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
break;
case ROCJPEG_OUTPUT_Y:
channel_widths[0] = is_roi_width_valid ? roi_width : channel_width;
break;
case ROCJPEG_OUTPUT_RGB:
channel_widths[0] = (is_roi_width_valid ? roi_width : channel_width) * 3;
break;
case ROCJPEG_OUTPUT_RGB_PLANAR:
channel_widths[2] = channel_widths[1] = channel_widths[0] = is_roi_width_valid ? roi_width : channel_width;
break;
default:
ERR("Unknown output format!");
return ROCJPEG_STATUS_INVALID_PARAMETER;
}
if (destination->pitch[channel_index] == hip_interop_dev_mem.pitch[channel_index]) {
uint32_t channel_size = destination->pitch[channel_index] * channel_height;
CHECK_HIP(hipMemcpyDtoDAsync(destination->channel[channel_index], hip_interop_dev_mem.hip_mapped_device_mem + hip_interop_dev_mem.offset[channel_index] + roi_offset, channel_size, hip_stream_));
} else {
CHECK_HIP(hipMemcpy2DAsync(destination->channel[channel_index], destination->pitch[channel_index], hip_interop_dev_mem.hip_mapped_device_mem + hip_interop_dev_mem.offset[channel_index] + roi_offset, hip_interop_dev_mem.pitch[channel_index],
channel_widths[channel_index], channel_height, hipMemcpyDeviceToDevice, hip_stream_));
}
}
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Calculates the chroma height based on the surface format and picture height.
*
* This function takes the surface format, picture height, and a reference to the chroma height.
* It calculates the chroma height based on the surface format and assigns the result to the chroma_height parameter.
*
* @param surface_format The surface format of the image.
* @param picture_height The height of the picture.
* @param chroma_height A reference to the variable where the calculated chroma height will be stored.
*
* @return The status of the operation. Returns ROCJPEG_STATUS_SUCCESS if successful, or ROCJPEG_STATUS_JPEG_NOT_SUPPORTED if the surface format is not supported.
*/
RocJpegStatus RocJpegDecoder::GetChromaHeight(uint32_t surface_format, uint16_t picture_height, uint16_t &chroma_height) {
switch (surface_format) {
case VA_FOURCC_NV12: /*NV12: two-plane 8-bit YUV 4:2:0*/
chroma_height = picture_height >> 1;
break;
case VA_FOURCC_444P: /*444P: three-plane 8-bit YUV 4:4:4*/
chroma_height = picture_height;
break;
case VA_FOURCC_Y800: /*Y800: one-plane 8-bit greyscale YUV 4:0:0*/
chroma_height = 0;
break;
case VA_FOURCC_YUY2: /*YUYV: one-plane packed 8-bit YUV 4:2:2. Four bytes per pair of pixels: Y, U, Y, V*/
chroma_height = picture_height;
break;
case VA_FOURCC_422V: /*422V: three-plane 8-bit YUV 4:4:0*/
chroma_height = picture_height >> 1;
break;
default:
return ROCJPEG_STATUS_JPEG_NOT_SUPPORTED;
}
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Converts the color format of the input image to RGB format.
*
* This function converts the color format of the input image to RGB format based on the surface format
* specified in the `hip_interop_dev_mem` parameter. The converted image is stored in the `destination`
* parameter.
*
* @param hip_interop_dev_mem The HipInteropDeviceMem object containing the input image data.
* @param picture_width The width of the destination image.
* @param picture_height The height of the destination image.
* @param destination Pointer to the RocJpegImage object where the converted image will be stored.
* @return The status of the color conversion operation. Returns ROCJPEG_STATUS_SUCCESS if the conversion
* is successful. Returns ROCJPEG_STATUS_JPEG_NOT_SUPPORTED if the surface format is not supported.
*/
RocJpegStatus RocJpegDecoder::ColorConvertToRGB(HipInteropDeviceMem& hip_interop_dev_mem, uint32_t picture_width, uint32_t picture_height, RocJpegImage *destination, const RocJpegDecodeParams *decode_params, bool is_roi_valid) {
uint32_t roi_offset = 0;
uint32_t roi_uv_offset = 0;
int16_t top = decode_params->crop_rectangle.top;
int16_t left = decode_params->crop_rectangle.left;
if (is_roi_valid) {
if (hip_interop_dev_mem.surface_format == VA_FOURCC_422V || hip_interop_dev_mem.surface_format == VA_FOURCC_NV12){
roi_uv_offset = (top >> 1) * hip_interop_dev_mem.pitch[1] + left;
} else if (hip_interop_dev_mem.surface_format == VA_FOURCC_YUY2) {
left *= 2;
}
roi_offset = top * hip_interop_dev_mem.pitch[0] + left;
}
switch (hip_interop_dev_mem.surface_format) {
case VA_FOURCC_444P:
ColorConvertYUV444ToRGB(hip_stream_, picture_width, picture_height, destination->channel[0], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0], hip_interop_dev_mem.offset[1] + roi_offset, hip_interop_dev_mem.offset[2] + roi_offset);
break;
case VA_FOURCC_422V:
ColorConvertYUV440ToRGB(hip_stream_, picture_width, picture_height, destination->channel[0], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0], hip_interop_dev_mem.offset[1] /*+ roi_uv_offset*/, hip_interop_dev_mem.offset[2] /*+ roi_uv_offset*/);
break;
case VA_FOURCC_YUY2:
ColorConvertYUYVToRGB(hip_stream_, picture_width, picture_height, destination->channel[0], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0]);
break;
case VA_FOURCC_NV12:
ColorConvertNV12ToRGB(hip_stream_, picture_width, picture_height, destination->channel[0], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + hip_interop_dev_mem.offset[1] + roi_uv_offset, hip_interop_dev_mem.pitch[1]);
break;
case VA_FOURCC_Y800:
ColorConvertYUV400ToRGB(hip_stream_, picture_width, picture_height, destination->channel[0], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0]);
break;
case VA_FOURCC_RGBA:
ColorConvertRGBAToRGB(hip_stream_, picture_width, picture_height, destination->channel[0], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0]);
break;
default:
ERR("ERROR! surface format is not supported!");
return ROCJPEG_STATUS_JPEG_NOT_SUPPORTED;
}
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Converts the color format of the input image to RGB planar format.
*
* This function converts the color format of the input image to RGB planar format.
* The conversion is performed based on the surface format specified in the `hip_interop_dev_mem`.
* The converted image is stored in the `destination` RocJpegImage object.
*
* @param hip_interop_dev_mem The HipInteropDeviceMem object containing the input image data.
* @param picture_width The width of the destination image.
* @param picture_height The height of the destination image.
* @param destination Pointer to the RocJpegImage object where the converted image will be stored.
* @return RocJpegStatus The status of the color conversion operation.
* Returns ROCJPEG_STATUS_SUCCESS if the conversion is successful.
* Returns ROCJPEG_STATUS_JPEG_NOT_SUPPORTED if the surface format is not supported.
*/
RocJpegStatus RocJpegDecoder::ColorConvertToRGBPlanar(HipInteropDeviceMem& hip_interop_dev_mem, uint32_t picture_width, uint32_t picture_height, RocJpegImage *destination, const RocJpegDecodeParams *decode_params, bool is_roi_valid) {
uint32_t roi_offset = 0;
uint32_t roi_uv_offset = 0;
int16_t top = decode_params->crop_rectangle.top;
int16_t left = decode_params->crop_rectangle.left;
if (is_roi_valid) {
if (hip_interop_dev_mem.surface_format == VA_FOURCC_422V || hip_interop_dev_mem.surface_format == VA_FOURCC_NV12){
roi_uv_offset = (top >> 1) * hip_interop_dev_mem.pitch[1] + left;
} else if (hip_interop_dev_mem.surface_format == VA_FOURCC_YUY2) {
left *= 2;
}
roi_offset = top * hip_interop_dev_mem.pitch[0] + left;
}
switch (hip_interop_dev_mem.surface_format) {
case VA_FOURCC_444P:
ColorConvertYUV444ToRGBPlanar(hip_stream_, picture_width, picture_height, destination->channel[0], destination->channel[1], destination->channel[2], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0], hip_interop_dev_mem.offset[1] + roi_offset, hip_interop_dev_mem.offset[2] + roi_offset);
break;
case VA_FOURCC_422V:
ColorConvertYUV440ToRGBPlanar(hip_stream_, picture_width, picture_height, destination->channel[0], destination->channel[1], destination->channel[2], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0], hip_interop_dev_mem.offset[1] /*+ roi_uv_offset*/, hip_interop_dev_mem.offset[2] /*+ roi_uv_offset*/);
break;
case VA_FOURCC_YUY2:
ColorConvertYUYVToRGBPlanar(hip_stream_, picture_width, picture_height, destination->channel[0], destination->channel[1], destination->channel[2], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0]);
break;
case VA_FOURCC_NV12:
ColorConvertNV12ToRGBPlanar(hip_stream_, picture_width, picture_height, destination->channel[0], destination->channel[1], destination->channel[2], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + hip_interop_dev_mem.offset[1] + roi_uv_offset, hip_interop_dev_mem.pitch[1]);
break;
case VA_FOURCC_Y800:
ColorConvertYUV400ToRGBPlanar(hip_stream_, picture_width, picture_height, destination->channel[0], destination->channel[1], destination->channel[2], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0]);
break;
case VA_FOURCC_RGBP:
// Copy red, green, and blue channels from the interop memory into the destination
for (uint8_t channel_index = 0; channel_index < 3; channel_index++) {
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, picture_height, channel_index, destination, decode_params, is_roi_valid));
}
break;
default:
ERR("ERROR! surface format is not supported!");
return ROCJPEG_STATUS_JPEG_NOT_SUPPORTED;
}
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Retrieves the planar YUV output format from the input image.
*
* This function converts the input image data to planar YUV format based on the surface format of the input data.
* If the surface format is VA_FOURCC_YUY2, the function extracts the packed YUYV data and copies them into the
* first, second, and third channels of the destination image. If the surface format is VA_FOURCC_NV12, the function
* extracts the interleaved UV channels and copies them into the second and third channels of the destination image.
* If the surface format is VA_FOURCC_444P, the function copies the luma channel and both chroma channels into the
* destination image.
*
* @param hip_interop_dev_mem The HipInteropDeviceMem object containing the input image data.
* @param picture_width The width of the input picture.
* @param picture_height The height of the input picture.
* @param chroma_height The height of the chroma channels.
* @param destination Pointer to the RocJpegImage object where the converted image data will be stored.
* @return The status of the operation. Returns ROCJPEG_STATUS_SUCCESS if successful.
*/
RocJpegStatus RocJpegDecoder::GetPlanarYUVOutputFormat(HipInteropDeviceMem& hip_interop_dev_mem, uint32_t picture_width, uint32_t picture_height, uint16_t chroma_height, RocJpegImage *destination, const RocJpegDecodeParams *decode_params, bool is_roi_valid) {
uint32_t roi_offset = 0;
if (is_roi_valid) {
int16_t top = decode_params->crop_rectangle.top;
int16_t left = decode_params->crop_rectangle.left;
if (hip_interop_dev_mem.surface_format == VA_FOURCC_NV12){
roi_offset = (top >> 1) * hip_interop_dev_mem.pitch[1] + left;
} else if (hip_interop_dev_mem.surface_format == VA_FOURCC_YUY2) {
roi_offset = top * hip_interop_dev_mem.pitch[0] + (left * 2);
}
}
if (hip_interop_dev_mem.surface_format == VA_FOURCC_YUY2) {
// Extract the packed YUYV and copy them into the first, second, and third channels of the destination.
ConvertPackedYUYVToPlanarYUV(hip_stream_, picture_width, picture_height, destination->channel[0], destination->channel[1], destination->channel[2],
destination->pitch[0], destination->pitch[1], hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0]);
} else {
// Copy Luma
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, picture_height, 0, destination, decode_params, is_roi_valid));
if (hip_interop_dev_mem.surface_format == VA_FOURCC_NV12) {
// Extract the interleaved UV channels and copy them into the second and third channels of the destination.
ConvertInterleavedUVToPlanarUV(hip_stream_, picture_width >> 1, picture_height >> 1, destination->channel[1], destination->channel[2],
destination->pitch[1], hip_interop_dev_mem.hip_mapped_device_mem + hip_interop_dev_mem.offset[1] + roi_offset, hip_interop_dev_mem.pitch[1]);
} else if (hip_interop_dev_mem.surface_format == VA_FOURCC_444P ||
hip_interop_dev_mem.surface_format == VA_FOURCC_422V) {
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, chroma_height, 1, destination, decode_params, is_roi_valid));
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, chroma_height, 2, destination, decode_params, is_roi_valid));
}
}
return ROCJPEG_STATUS_SUCCESS;
}
/**
* @brief Retrieves the Y output format from the input YUV image.
*
* This function extracts the Y output format from the RocJpegDecoder based on the provided parameters.
* If the surface format is VA_FOURCC_YUY2, it calls the ExtractYFromPackedYUYV function to extract the Y component
* from the packed YUYV format. Otherwise, it calls the CopyChannel function to copy the luma channel.
*
* @param hip_interop_dev_mem The HipInteropDeviceMem object containing the surface format and device memory.
* @param picture_width The width of the picture.
* @param picture_height The height of the picture.
* @param destination Pointer to the RocJpegImage object where the extracted Y component will be stored.
* @return The status of the operation. Returns ROCJPEG_STATUS_SUCCESS if successful.
*/
RocJpegStatus RocJpegDecoder::GetYOutputFormat(HipInteropDeviceMem& hip_interop_dev_mem, uint32_t picture_width, uint32_t picture_height, RocJpegImage *destination, const RocJpegDecodeParams *decode_params, bool is_roi_valid) {
uint32_t roi_offset = 0;
if (hip_interop_dev_mem.surface_format == VA_FOURCC_YUY2) {
// calculate offset and add to hip_mapped_device_mem
if (is_roi_valid) {
int16_t top = decode_params->crop_rectangle.top;
int16_t left = decode_params->crop_rectangle.left * 2;
roi_offset = top * hip_interop_dev_mem.pitch[0] + left;
}
ExtractYFromPackedYUYV(hip_stream_, picture_width, picture_height, destination->channel[0], destination->pitch[0],
hip_interop_dev_mem.hip_mapped_device_mem + roi_offset, hip_interop_dev_mem.pitch[0]);
} else {
// Copy Luma
CHECK_ROCJPEG(CopyChannel(hip_interop_dev_mem, picture_width, picture_height, 0, destination, decode_params, is_roi_valid));
}
return ROCJPEG_STATUS_SUCCESS;
}
+180
Visa fil
@@ -0,0 +1,180 @@
/*
Copyright (c) 2024 - 2026 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.
*/
#ifndef ROC_JPEG_DECODER_H_
#define ROC_JPEG_DECODER_H_
#include <unistd.h>
#include <vector>
#include <mutex>
#include <queue>
#include "../api/rocjpeg/rocjpeg.h"
#include "rocjpeg_api_stream_handle.h"
#include "rocjpeg_parser.h"
#include "rocjpeg_commons.h"
#include "rocjpeg_vaapi_decoder.h"
#include "rocjpeg_hip_kernels.h"
/**
* @class RocJpegDecoder
* @brief The RocJpegDecoder class represents a JPEG decoder.
*
* This class provides methods to initialize the decoder, retrieve image information,
* and decode JPEG streams into RocJpegImage objects.
*/
/**
* @brief The RocJpegDecoder class is responsible for decoding JPEG images using a hardware-accelerated jpeg decoder.
*/
class RocJpegDecoder {
public:
/**
* @brief Constructs a RocJpegDecoder object.
* @param backend The ROCm backend to be used for decoding (default: ROCJPEG_BACKEND_HARDWARE).
* @param device_id The ID of the device to be used for decoding (default: 0).
*/
RocJpegDecoder(RocJpegBackend backend = ROCJPEG_BACKEND_HARDWARE, int device_id = 0);
/**
* @brief Destroys the RocJpegDecoder object.
*/
~RocJpegDecoder();
/**
* @brief Initializes the decoder.
* @return The status of the initialization process.
*/
RocJpegStatus InitializeDecoder();
/**
* @brief Retrieves information about the JPEG image.
* @param jpeg_stream The handle to the JPEG stream.
* @param num_components Pointer to store the number of color components in the image.
* @param subsampling Pointer to store the chroma subsampling information.
* @param widths Pointer to store the widths of the image components.
* @param heights Pointer to store the heights of the image components.
* @return The status of the operation.
*/
RocJpegStatus GetImageInfo(RocJpegStreamHandle jpeg_stream, uint8_t *num_components, RocJpegChromaSubsampling *subsampling, uint32_t *widths, uint32_t *heights);
/**
* @brief Decodes the JPEG image.
* @param jpeg_stream The handle to the JPEG stream.
* @param decode_params The decoding parameters.
* @param destination Pointer to the destination image.
* @return The status of the decoding process.
*/
RocJpegStatus Decode(RocJpegStreamHandle jpeg_stream, const RocJpegDecodeParams *decode_params, RocJpegImage *destination);
/**
* Decodes a batch of JPEG streams.
*
* This function decodes a batch of JPEG streams specified by `jpeg_streams` into a batch of destination images specified by `destinations`.
* The number of JPEG streams in the batch is specified by `batch_size`.
* The decoding parameters are specified by `decode_params`.
*
* @param jpeg_streams The array of JPEG stream handles.
* @param batch_size The number of JPEG streams in the batch.
* @param decode_params The decoding parameters.
* @param destinations The array of destination images.
* @return The status of the decoding operation.
*/
RocJpegStatus DecodeBatched(RocJpegStreamHandle *jpeg_streams, int batch_size, const RocJpegDecodeParams *decode_params, RocJpegImage *destinations);
private:
/**
* @brief Initializes the HIP framework.
* @param device_id The ID of the device to be used for HIP operations.
* @return The status of the initialization process.
*/
RocJpegStatus InitHIP(int device_id);
/**
* @brief Retrieves the height of the chroma channel.
* @param surface_format The surface format of the image.
* @param picture_height The height of the picture.
* @param chroma_height Reference to store the height of the chroma channel.
* @return The status of the operation.
*/
RocJpegStatus GetChromaHeight(uint32_t surface_format, uint16_t picture_height, uint16_t &chroma_height);
/**
* @brief Copies a channel from the HIP interop device memory to the destination image.
* @param hip_interop The HIP interop device memory.
* @param channel_width The width of the channel.
* @param channel_height The height of the channel.
* @param channel_index The index of the channel.
* @param destination Pointer to the destination image.
* @return The status of the operation.
*/
RocJpegStatus CopyChannel(HipInteropDeviceMem& hip_interop, uint16_t channel_width, uint16_t channel_height, uint8_t channel_index, RocJpegImage *destination, const RocJpegDecodeParams *decode_params, bool is_roi_valid);
/**
* @brief Converts the image to RGB color space.
* @param hip_interop The HIP interop device memory.
* @param picture_width The width of the picture.
* @param picture_height The height of the picture.
* @param destination Pointer to the destination image.
* @return The status of the operation.
*/
RocJpegStatus ColorConvertToRGB(HipInteropDeviceMem& hip_interop, uint32_t picture_width, uint32_t picture_height, RocJpegImage *destination, const RocJpegDecodeParams *decode_params, bool is_roi_valid);
/**
* @brief Converts the image to RGB planar color space.
* @param hip_interop The HIP interop device memory.
* @param picture_width The width of the picture.
* @param picture_height The height of the picture.
* @param destination Pointer to the destination image.
* @return The status of the operation.
*/
RocJpegStatus ColorConvertToRGBPlanar(HipInteropDeviceMem& hip_interop, uint32_t picture_width, uint32_t picture_height, RocJpegImage *destination, const RocJpegDecodeParams *decode_params, bool is_roi_valid);
/**
* @brief Retrieves the output format for planar YUV images.
* @param hip_interop The HIP interop device memory.
* @param picture_width The width of the picture.
* @param picture_height The height of the picture.
* @param chroma_height The height of the chroma channel.
* @param destination Pointer to the destination image.
* @return The status of the operation.
*/
RocJpegStatus GetPlanarYUVOutputFormat(HipInteropDeviceMem& hip_interop, uint32_t picture_width, uint32_t picture_height, uint16_t chroma_height, RocJpegImage *destination, const RocJpegDecodeParams *decode_params, bool is_roi_valid);
/**
* @brief Retrieves the output format for Y images.
* @param hip_interop The HIP interop device memory.
* @param picture_width The width of the picture.
* @param picture_height The height of the picture.
* @param destination Pointer to the destination image.
* @return The status of the operation.
*/
RocJpegStatus GetYOutputFormat(HipInteropDeviceMem& hip_interop, uint32_t picture_width, uint32_t picture_height, RocJpegImage *destination, const RocJpegDecodeParams *decode_params, bool is_roi_valid);
int num_devices_; // Number of available devices
int device_id_; // ID of the device to be used
hipDeviceProp_t hip_dev_prop_; // HIP device properties
hipStream_t hip_stream_; // HIP stream
std::mutex mutex_; // Mutex for thread safety
RocJpegBackend backend_; // RocJpeg backend
RocJpegVappiDecoder jpeg_vaapi_decoder_; // RocJpeg VAAPI decoder object
};
#endif //ROC_JPEG_DECODER_H_
Filskillnaden har hållits tillbaka eftersom den är för stor Load Diff
+324
Visa fil
@@ -0,0 +1,324 @@
/*
Copyright (c) 2024 - 2026 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.
*/
#ifndef ROC_JPEG_HIP_KERNELS_H_
#define ROC_JPEG_HIP_KERNELS_H_
#pragma once
#include <hip/hip_runtime.h>
/**
* @brief Converts YUV444 image to RGB image.
*
* This function takes a YUV444 image and converts it to an RGB image.
*
* @param stream The HIP stream to be used for the conversion.
* @param dst_width The width of the destination RGB image.
* @param dst_height The height of the destination RGB image.
* @param dst_image Pointer to the destination RGB image buffer.
* @param dst_image_stride_in_bytes The stride (in bytes) of the destination RGB image buffer.
* @param src_yuv_image Pointer to the source YUV444 image buffer.
* @param src_yuv_image_stride_in_bytes The stride (in bytes) of the source YUV444 image buffer.
* @param src_u_image_offset The offset (in bytes) of the U component in the source YUV444 image buffer.
*/
void ColorConvertYUV444ToRGB(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image, uint32_t dst_image_stride_in_bytes, const uint8_t *src_yuv_image,
uint32_t src_yuv_image_stride_in_bytes, uint32_t src_u_image_offset, uint32_t src_v_image_offset);
/**
* @brief Converts YUV440 image to RGB image.
*
* This function takes a YUV440 image and converts it to an RGB image.
*
* @param stream The HIP stream to be used for the conversion.
* @param dst_width The width of the destination RGB image.
* @param dst_height The height of the destination RGB image.
* @param dst_image Pointer to the destination RGB image buffer.
* @param dst_image_stride_in_bytes The stride (in bytes) of the destination RGB image buffer.
* @param src_yuv_image Pointer to the source YUV440 image buffer.
* @param src_yuv_image_stride_in_bytes The stride (in bytes) of the source YUV440 image buffer.
* @param src_u_image_offset The offset (in bytes) of the U component in the source YUV440 image buffer.
*/
void ColorConvertYUV440ToRGB(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image, uint32_t dst_image_stride_in_bytes, const uint8_t *src_yuv_image,
uint32_t src_yuv_image_stride_in_bytes, uint32_t src_u_image_offset, uint32_t src_v_image_offset);
/**
* @brief Converts an image in YUYV format to RGB format.
*
* This function takes an image in YUYV format and converts it to RGB format.
* The converted image is stored in the destination buffer.
*
* @param stream The HIP stream to be used for the conversion.
* @param dst_width The width of the destination image in pixels.
* @param dst_height The height of the destination image in pixels.
* @param dst_image Pointer to the destination image buffer.
* @param dst_image_stride_in_bytes The stride (in bytes) of the destination image buffer.
* @param src_image Pointer to the source image buffer in YUYV format.
* @param src_image_stride_in_bytes The stride (in bytes) of the source image buffer.
*/
void ColorConvertYUYVToRGB(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image, uint32_t dst_image_stride_in_bytes,
const uint8_t *src_image, uint32_t src_image_stride_in_bytes);
/**
* @brief Converts an NV12 image to RGB format.
*
* This function takes an NV12 image, consisting of a luma (Y) plane and a chroma (UV) plane,
* and converts it to RGB format. The resulting RGB image is stored in the destination image buffer.
*
* @param stream The HIP stream to be used for the conversion.
* @param dst_width The width of the destination RGB image.
* @param dst_height The height of the destination RGB image.
* @param dst_image Pointer to the destination RGB image buffer.
* @param dst_image_stride_in_bytes The stride (in bytes) of the destination RGB image buffer.
* @param src_luma_image Pointer to the source luma (Y) plane of the NV12 image.
* @param src_luma_image_stride_in_bytes The stride (in bytes) of the source luma (Y) plane.
* @param src_chroma_image Pointer to the source chroma (UV) plane of the NV12 image.
* @param src_chroma_image_stride_in_bytes The stride (in bytes) of the source chroma (UV) plane.
*/
void ColorConvertNV12ToRGB(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image, uint32_t dst_image_stride_in_bytes,
const uint8_t *src_luma_image, uint32_t src_luma_image_stride_in_bytes,
const uint8_t *src_chroma_image, uint32_t src_chroma_image_stride_in_bytes);
/**
* @brief Converts a YUV400 image to RGB format.
*
* This function converts a YUV400 image to RGB format using the specified stream and parameters.
*
* @param stream The HIP stream to be used for the conversion.
* @param dst_width The width of the destination RGB image.
* @param dst_height The height of the destination RGB image.
* @param dst_image Pointer to the destination RGB image buffer.
* @param dst_image_stride_in_bytes The stride (in bytes) of the destination RGB image buffer.
* @param src_luma_image Pointer to the source YUV400 luma image buffer.
* @param src_luma_image_stride_in_bytes The stride (in bytes) of the source YUV400 luma image buffer.
*/
void ColorConvertYUV400ToRGB(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image, uint32_t dst_image_stride_in_bytes,
const uint8_t *src_luma_image, uint32_t src_luma_image_stride_in_bytes);
/**
* @brief Converts an RGBA image to an RGB image.
*
* This function takes an input RGBA image and converts it to an output RGB image.
* The conversion is performed in parallel using the HIP framework.
*
* @param stream The HIP stream to be used for the conversion.
* @param dst_width The width of the output RGB image.
* @param dst_height The height of the output RGB image.
* @param dst_image Pointer to the output RGB image buffer.
* @param dst_image_stride_in_bytes The stride (in bytes) of the output RGB image buffer.
* @param src_image Pointer to the input RGBA image buffer.
* @param src_image_stride_in_bytes The stride (in bytes) of the input RGBA image buffer.
*/
void ColorConvertRGBAToRGB(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image, uint32_t dst_image_stride_in_bytes,
const uint8_t *src_image, uint32_t src_image_stride_in_bytes);
/**
* @brief Converts YUV444 image to RGB planar format.
*
* This function takes a YUV444 image and converts it to RGB planar format.
* The resulting RGB image is stored in separate R, G, and B planes.
*
* @param stream The HIP stream to be used for the kernel execution.
* @param dst_width The width of the destination RGB image.
* @param dst_height The height of the destination RGB image.
* @param dst_image_r Pointer to the destination R plane of the RGB image.
* @param dst_image_g Pointer to the destination G plane of the RGB image.
* @param dst_image_b Pointer to the destination B plane of the RGB image.
* @param dst_image_stride_in_bytes The stride (in bytes) of the destination RGB image.
* @param src_yuv_image Pointer to the source YUV444 image.
* @param src_yuv_image_stride_in_bytes The stride (in bytes) of the source YUV444 image.
* @param src_u_image_offset The offset (in bytes) of the U plane in the source YUV444 image.
*/
void ColorConvertYUV444ToRGBPlanar(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image_r, uint8_t *dst_image_g, uint8_t *dst_image_b, uint32_t dst_image_stride_in_bytes, const uint8_t *src_yuv_image,
uint32_t src_yuv_image_stride_in_bytes, uint32_t src_u_image_offset, uint32_t src_v_image_offset);
/**
* @brief Converts YUV440 image to RGB planar format.
*
* This function takes a YUV440 image and converts it to RGB planar format.
* The resulting RGB image is stored in separate R, G, and B planes.
*
* @param stream The HIP stream to be used for the kernel execution.
* @param dst_width The width of the destination RGB image.
* @param dst_height The height of the destination RGB image.
* @param dst_image_r Pointer to the destination R plane of the RGB image.
* @param dst_image_g Pointer to the destination G plane of the RGB image.
* @param dst_image_b Pointer to the destination B plane of the RGB image.
* @param dst_image_stride_in_bytes The stride (in bytes) of the destination RGB image.
* @param src_yuv_image Pointer to the source YUV440 image.
* @param src_yuv_image_stride_in_bytes The stride (in bytes) of the source YUV440 image.
* @param src_u_image_offset The offset (in bytes) of the U plane in the source YUV440 image.
*/
void ColorConvertYUV440ToRGBPlanar(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image_r, uint8_t *dst_image_g, uint8_t *dst_image_b, uint32_t dst_image_stride_in_bytes, const uint8_t *src_yuv_image,
uint32_t src_yuv_image_stride_in_bytes, uint32_t src_u_image_offset, uint32_t src_v_image_offset);
/**
* Converts a YUYV image to RGB planar format.
*
* This function takes a YUYV image and converts it to RGB planar format. The resulting RGB image
* is stored in separate planes for red, green, and blue channels.
*
* @param stream The HIP stream to use for the conversion.
* @param dst_width The width of the destination RGB image.
* @param dst_height The height of the destination RGB image.
* @param dst_image_r Pointer to the destination red channel plane.
* @param dst_image_g Pointer to the destination green channel plane.
* @param dst_image_b Pointer to the destination blue channel plane.
* @param dst_image_stride_in_bytes The stride (in bytes) between consecutive rows in the destination image planes.
* @param src_image Pointer to the source YUYV image.
* @param src_image_stride_in_bytes The stride (in bytes) between consecutive rows in the source image.
*/
void ColorConvertYUYVToRGBPlanar(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image_r, uint8_t *dst_image_g, uint8_t *dst_image_b, uint32_t dst_image_stride_in_bytes,
const uint8_t *src_image, uint32_t src_image_stride_in_bytes);
/**
* @brief Converts an NV12 image to RGB planar format.
*
* This function takes an NV12 image and converts it to RGB planar format. The NV12 image consists of a luma (Y) plane followed by a packed chroma (UV) plane.
* The RGB planar format consists of separate R, G, and B planes.
*
* @param stream The HIP stream to be used for the conversion.
* @param dst_width The width of the destination RGB image.
* @param dst_height The height of the destination RGB image.
* @param dst_image_r Pointer to the destination R plane.
* @param dst_image_g Pointer to the destination G plane.
* @param dst_image_b Pointer to the destination B plane.
* @param dst_image_stride_in_bytes The stride (in bytes) of the destination RGB image.
* @param src_luma_image Pointer to the source luma (Y) plane.
* @param src_luma_image_stride_in_bytes The stride (in bytes) of the source luma (Y) plane.
* @param src_chroma_image Pointer to the source chroma (UV) plane.
* @param src_chroma_image_stride_in_bytes The stride (in bytes) of the source chroma (UV) plane.
*/
void ColorConvertNV12ToRGBPlanar(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image_r, uint8_t *dst_image_g, uint8_t *dst_image_b, uint32_t dst_image_stride_in_bytes,
const uint8_t *src_luma_image, uint32_t src_luma_image_stride_in_bytes,
const uint8_t *src_chroma_image, uint32_t src_chroma_image_stride_in_bytes);
/**
* @brief Converts a YUV400 image to RGB planar format.
*
* This function takes a YUV400 image and converts it to RGB planar format.
* The resulting RGB image will have separate planes for red, green, and blue channels.
*
* @param stream The HIP stream to be used for the kernel execution.
* @param dst_width The width of the destination RGB image.
* @param dst_height The height of the destination RGB image.
* @param dst_image_r Pointer to the destination red channel plane.
* @param dst_image_g Pointer to the destination green channel plane.
* @param dst_image_b Pointer to the destination blue channel plane.
* @param dst_image_stride_in_bytes The stride (in bytes) of the destination image planes.
* @param src_luma_image Pointer to the source YUV400 luma image.
* @param src_luma_image_stride_in_bytes The stride (in bytes) of the source luma image.
*/
void ColorConvertYUV400ToRGBPlanar(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image_r, uint8_t *dst_image_g, uint8_t *dst_image_b, uint32_t dst_image_stride_in_bytes,
const uint8_t *src_luma_image, uint32_t src_luma_image_stride_in_bytes);
/**
* @brief Converts interleaved UV data to planar UV data.
*
* This function takes interleaved UV data from the source image and converts it to planar UV data,
* which is then stored in the destination images. The conversion is performed on the GPU using
* the specified stream.
*
* @param stream The HIP stream to be used for the conversion.
* @param dst_width The width of the destination images.
* @param dst_height The height of the destination images.
* @param dst_image1 Pointer to the first destination image buffer.
* @param dst_image2 Pointer to the second destination image buffer.
* @param dst_image_stride_in_bytes The stride (in bytes) of the destination image buffers.
* @param src_image1 Pointer to the source image buffer containing interleaved UV data.
* @param src_image1_stride_in_bytes The stride (in bytes) of the source image buffer.
*/
void ConvertInterleavedUVToPlanarUV(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *dst_image1, uint8_t *dst_image2, uint32_t dst_image_stride_in_bytes,
const uint8_t *src_image1, uint32_t src_image1_stride_in_bytes);
/**
* @brief Extracts the Y component from a packed YUYV image and stores it in a separate buffer.
*
* This function takes a packed YUYV image and extracts the Y component (luma) from it. The extracted Y component
* is then stored in a separate buffer. The dimensions of the destination buffer, as well as the stride of the
* source and destination buffers, should be provided.
*
* @param stream The HIP stream to be used for the operation.
* @param dst_width The width of the destination buffer.
* @param dst_height The height of the destination buffer.
* @param destination_y Pointer to the destination buffer where the extracted Y component will be stored.
* @param dst_luma_stride_in_bytes The stride (in bytes) of the destination buffer.
* @param src_image Pointer to the source YUYV image.
* @param src_image_stride_in_bytes The stride (in bytes) of the source YUYV image.
*/
void ExtractYFromPackedYUYV(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *destination_y, uint32_t dst_luma_stride_in_bytes, const uint8_t *src_image, uint32_t src_image_stride_in_bytes);
/**
* @brief Converts a packed YUYV image to planar YUV format.
*
* This function takes a packed YUYV image and converts it to planar YUV format.
* The resulting planar YUV image will have separate planes for Y, U, and V components.
*
* @param stream The HIP stream to associate the kernel execution with.
* @param dst_width The width of the destination image in pixels.
* @param dst_height The height of the destination image in pixels.
* @param destination_y Pointer to the destination Y plane.
* @param destination_u Pointer to the destination U plane.
* @param destination_v Pointer to the destination V plane.
* @param dst_luma_stride_in_bytes The stride (in bytes) between consecutive rows of the destination Y plane.
* @param dst_chroma_stride_in_bytes The stride (in bytes) between consecutive rows of the destination U and V planes.
* @param src_image Pointer to the source packed YUYV image.
* @param src_image_stride_in_bytes The stride (in bytes) between consecutive rows of the source image.
*/
void ConvertPackedYUYVToPlanarYUV(hipStream_t stream, uint32_t dst_width, uint32_t dst_height,
uint8_t *destination_y, uint8_t *destination_u, uint8_t *destination_v, uint32_t dst_luma_stride_in_bytes,
uint32_t dst_chroma_stride_in_bytes, const uint8_t *src_image, uint32_t src_image_stride_in_bytes);
/**
* @brief Structure representing an array of 6 unsigned integers.
*
* This structure is used to store an array of 6 unsigned integers.
* The `data` member is an array of size 6 that holds the integer values.
*/
typedef struct UINT6TYPE {
uint data[6];
} DUINT6;
/**
* @brief Represents a struct that holds an array of 8 unsigned integers.
*
* This struct is used to store an array of 8 unsigned integers in the `data` member.
* It is typically used in the context of the `rocjpeg_hip_kernels` module.
*/
typedef struct UINT8TYPE {
uint data[8];
} DUINT8;
#endif //ROC_JPEG_HIP_KERNELS_H_
+470
Visa fil
@@ -0,0 +1,470 @@
/*
Copyright (c) 2024 - 2026 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 "rocjpeg_parser.h"
RocJpegStreamParser::RocJpegStreamParser() : stream_{nullptr}, stream_end_{nullptr}, stream_length_{0},
jpeg_stream_parameters_{} {
}
RocJpegStreamParser::~RocJpegStreamParser() {
stream_ = nullptr;
stream_end_ = nullptr;
stream_length_ = 0;
}
/**
* @brief Parses a JPEG stream.
*
* This function parses a JPEG stream and extracts various markers and parameters from it.
*
* @param jpeg_stream A pointer to the JPEG stream.
* @param jpeg_stream_size The size of the JPEG stream in bytes.
* @return True if the JPEG stream was successfully parsed, false otherwise.
*/
bool RocJpegStreamParser::ParseJpegStream(const uint8_t *jpeg_stream, uint32_t jpeg_stream_size) {
std::lock_guard<std::mutex> lock(mutex_);
if (jpeg_stream == nullptr) {
ERR("invalid argument!");
return false;
}
stream_ = jpeg_stream;
stream_length_ = jpeg_stream_size;
stream_end_ = stream_ + stream_length_;
jpeg_stream_parameters_ = {};
bool soi_marker_found = false;
bool sos_marker_found = false;
bool dht_marker_found = false;
bool dqt_marker_found = false;
uint8_t marker;
const uint8_t *next_chunck;
int32_t chuck_len;
// The first two bytes of a JPEG must be 0XFFD8
if (*stream_ != 0xFF || *(stream_ + 1) != SOI) {
ERR("Invalid JPEG!");
return false;
}
soi_marker_found = ParseSOI();
if (!soi_marker_found) {
ERR("failed to find the SOI marker!");
}
while (!sos_marker_found && stream_ <= stream_end_) {
while ((*stream_ == 0xFF))
stream_++;
marker = *stream_++;
chuck_len = swap_bytes(stream_);
next_chunck = stream_ + chuck_len;
switch (marker) {
case SOF:
if (!ParseSOF())
return false;
break;
case DHT:
if (!ParseDHT())
return false;
dht_marker_found = true;
break;
case DQT:
if (!ParseDQT())
return false;
dqt_marker_found = true;
break;
case DRI:
if (!ParseDRI())
return false;
break;
case SOS:
if (!ParseSOS())
return false;
sos_marker_found = true;
break;
default:
break;
}
stream_ = next_chunck;
}
if (!dht_marker_found) {
ERR("didn't find any Huffman table!");
return false;
}
if (!dqt_marker_found) {
ERR("didn't find any quantization table!");
return false;
}
if (!ParseEOI())
return false;
return true;
}
/**
* @brief Parses the Start of Image (SOI) marker in the JPEG stream.
*
* This function searches for the SOI marker (0xFFD8) in the JPEG stream and updates the stream pointer accordingly.
*
* @return true if the SOI marker is found and the stream pointer is updated, false otherwise.
*/
bool RocJpegStreamParser::ParseSOI() {
if (stream_ == nullptr) {
return false;
}
while (!(*stream_ == 0xFF && *(stream_ + 1) == SOI)) {
if (stream_ <= stream_end_) {
stream_++;
continue;
} else
return false;
}
stream_ += 2;
return true;
}
/**
* @brief Parses the Start of Frame (SOF) marker in the JPEG stream.
*
* This function reads and processes the SOF marker in the JPEG stream. It extracts
* information such as picture height, picture width, number of components, component
* IDs, sampling factors, and quantization table selectors. It also calculates the
* number of MCU (Minimum Coded Unit) blocks in the image and determines the chroma
* subsampling scheme.
*
* @return true if the SOF marker is successfully parsed, false otherwise.
*/
bool RocJpegStreamParser::ParseSOF() {
uint32_t component_id, sampling_factor;
uint8_t quantiser_table_selector;
if (stream_ == nullptr) {
return false;
}
jpeg_stream_parameters_.picture_parameter_buffer.picture_height = swap_bytes(stream_ + 3);
jpeg_stream_parameters_.picture_parameter_buffer.picture_width = swap_bytes(stream_ + 5);
jpeg_stream_parameters_.picture_parameter_buffer.num_components = stream_[7];
if (jpeg_stream_parameters_.picture_parameter_buffer.num_components > NUM_COMPONENTS - 1) {
ERR("invalid number of JPEG components!");
return false;
}
stream_ += 8;
for (int32_t i = 0; i < jpeg_stream_parameters_.picture_parameter_buffer.num_components; i++) {
component_id = *stream_++;
sampling_factor = *stream_++;
quantiser_table_selector = *stream_++;
jpeg_stream_parameters_.picture_parameter_buffer.components[i].component_id = component_id;
if (quantiser_table_selector >= NUM_COMPONENTS) {
ERR("invalid number of the quantization table!");
return false;
}
jpeg_stream_parameters_.picture_parameter_buffer.components[i].v_sampling_factor = sampling_factor & 0xF;
jpeg_stream_parameters_.picture_parameter_buffer.components[i].h_sampling_factor = sampling_factor >> 4;
jpeg_stream_parameters_.picture_parameter_buffer.components[i].quantiser_table_selector = quantiser_table_selector;
}
uint8_t max_h_factor = jpeg_stream_parameters_.picture_parameter_buffer.components[0].h_sampling_factor;
uint8_t max_v_factor = jpeg_stream_parameters_.picture_parameter_buffer.components[0].v_sampling_factor;
jpeg_stream_parameters_.slice_parameter_buffer.num_mcus = ((jpeg_stream_parameters_.picture_parameter_buffer.picture_width + max_h_factor * 8 - 1) / (max_h_factor * 8)) *
((jpeg_stream_parameters_.picture_parameter_buffer.picture_height + max_v_factor * 8 - 1) / (max_v_factor * 8));
jpeg_stream_parameters_.chroma_subsampling = GetChromaSubsampling(jpeg_stream_parameters_.picture_parameter_buffer.components[0].h_sampling_factor,
jpeg_stream_parameters_.picture_parameter_buffer.components[1].h_sampling_factor,
jpeg_stream_parameters_.picture_parameter_buffer.components[2].h_sampling_factor,
jpeg_stream_parameters_.picture_parameter_buffer.components[0].v_sampling_factor,
jpeg_stream_parameters_.picture_parameter_buffer.components[1].v_sampling_factor,
jpeg_stream_parameters_.picture_parameter_buffer.components[2].v_sampling_factor);
return true;
}
/**
* @brief Parses the DQT (Define Quantization Table) segment of a JPEG stream.
*
* This function reads the quantization tables from the JPEG stream and stores them in the
* `jpeg_stream_parameters_.quantization_matrix_buffer` data structure.
*
* @return `true` if the DQT segment is successfully parsed, `false` otherwise.
*/
bool RocJpegStreamParser::ParseDQT() {
int32_t quantization_table_index = 0;
const uint8_t *dqt_block_end;
if (stream_ == nullptr) {
return false;
}
dqt_block_end = stream_ + swap_bytes(stream_);
stream_ += 2;
while (stream_ < dqt_block_end) {
quantization_table_index = *stream_++;
if (quantization_table_index >> 4) {
ERR("16 bits quantization table is not supported!");
return false;
}
if (quantization_table_index >= 4) {
ERR("invalid number of quantization table!");
return false;
}
std::memcpy(jpeg_stream_parameters_.quantization_matrix_buffer.quantiser_table[quantization_table_index & 0x0F], stream_, 64);
jpeg_stream_parameters_.quantization_matrix_buffer.load_quantiser_table[quantization_table_index & 0x0F] = 1;
stream_ += 64;
}
return true;
}
/**
* @brief Parses the Define Huffman Table (DHT) segment in the JPEG stream.
*
* This function reads and processes the DHT segment in the JPEG stream. It extracts the Huffman table
* information and stores it in the `jpeg_stream_parameters_.huffman_table_buffer` data structure.
*
* @return `true` if the DHT segment is successfully parsed, `false` otherwise.
*/
bool RocJpegStreamParser::ParseDHT() {
uint32_t count, i;
int32_t length, index;
uint8_t ac_huffman_table, huffman_table_id;
if (stream_ == nullptr) {
return false;
}
length = swap_bytes(stream_) - 2;
stream_ += 2;
while (length > 0) {
index = *stream_++;
ac_huffman_table = index & 0xF0;
huffman_table_id = index & 0x0F;
if (huffman_table_id >= HUFFMAN_TABLES) {
ERR("invlaid number of Huffman table!");
return false;
}
if (ac_huffman_table) {
std::memcpy(jpeg_stream_parameters_.huffman_table_buffer.huffman_table[huffman_table_id].num_ac_codes, stream_, 16);
} else {
std::memcpy(jpeg_stream_parameters_.huffman_table_buffer.huffman_table[huffman_table_id].num_dc_codes, stream_, 16);
}
count = 0;
for (i = 0; i < 16; i++) {
count += *stream_++;
}
if (ac_huffman_table) {
if (count > AC_HUFFMAN_TABLE_VALUES_SIZE) {
ERR("invalid AC Huffman table!");
return false;
}
std::memcpy(jpeg_stream_parameters_.huffman_table_buffer.huffman_table[huffman_table_id].ac_values, stream_, count);
jpeg_stream_parameters_.huffman_table_buffer.load_huffman_table[huffman_table_id] = 1;
} else {
if (count > DC_HUFFMAN_TABLE_VALUES_SIZE) {
ERR("invlaid DC Huffman table!")
return false;
}
std::memcpy(jpeg_stream_parameters_.huffman_table_buffer.huffman_table[huffman_table_id].dc_values, stream_, count);
jpeg_stream_parameters_.huffman_table_buffer.load_huffman_table[huffman_table_id] = 1;
}
length -= 1;
length -= 16;
length -= count;
stream_ += count;
}
return true;
}
/**
* @brief Parses the Start of Scan (SOS) marker in the JPEG stream.
*
* This function reads and processes the SOS marker in the JPEG stream.
* It extracts the component IDs and Huffman table selectors for each component,
* and performs various checks for validity.
*
* @return true if the SOS marker is successfully parsed, false otherwise.
*/
bool RocJpegStreamParser::ParseSOS() {
uint32_t component_id, table;
if (stream_ == nullptr) {
return false;
}
uint32_t num_components = stream_[2];
if (num_components > NUM_COMPONENTS - 1 || num_components != jpeg_stream_parameters_.picture_parameter_buffer.num_components) {
ERR("invalid number of component!")
return false;
}
jpeg_stream_parameters_.slice_parameter_buffer.num_components = num_components;
stream_ += 3;
for (uint32_t i = 0; i < num_components; i++) {
component_id = *stream_++;
table = *stream_++;
jpeg_stream_parameters_.slice_parameter_buffer.components[i].component_selector = component_id;
jpeg_stream_parameters_.slice_parameter_buffer.components[i].dc_table_selector = ((table >> 4) & 0x0F);
jpeg_stream_parameters_.slice_parameter_buffer.components[i].ac_table_selector = (table & 0x0F);
if ((table & 0xF) >= 4) {
ERR("invalid number of AC Huffman table!");
return false;
}
if ((table >> 4) >= 4) {
ERR("invalid number of DC Huffman table!");
return false;
}
if (component_id != jpeg_stream_parameters_.picture_parameter_buffer.components[i].component_id) {
ERR("component id mismatch between SOS and SOF marker!");
return false;
}
}
stream_ += 3;
return true;
}
/**
* @brief Parses the Define Restart Interval (DRI) marker in the JPEG stream.
*
* This function reads the length field of the DRI marker and checks if it is valid.
* If the length is valid, it updates the restart interval value in the slice parameter buffer.
*
* @return true if the DRI marker is successfully parsed, false otherwise.
*/
bool RocJpegStreamParser::ParseDRI() {
uint32_t length;
if (stream_ == nullptr) {
return false;
}
length = swap_bytes(stream_);
if (length != 4) {
ERR("invalid size for DRI marker");
return false;
}
jpeg_stream_parameters_.slice_parameter_buffer.restart_interval = swap_bytes(stream_ + 2);
return true;
}
/**
* @brief Parses the End of Image (EOI) marker in the JPEG stream.
*
* This function searches for the EOI marker in the JPEG stream and updates the slice data buffer
* and slice data size in the jpeg_stream_parameters_ structure.
*
* @return true if the EOI marker is found and the slice data buffer is updated successfully, false otherwise.
*/
bool RocJpegStreamParser::ParseEOI() {
if (stream_ == nullptr) {
return false;
}
const uint8_t *stream_temp = stream_;
while (stream_temp <= stream_end_ && !(*stream_temp == 0xFF && *(stream_temp + 1) == EOI)) {
stream_temp++;
continue;
}
jpeg_stream_parameters_.slice_parameter_buffer.slice_data_size = stream_temp - stream_;
jpeg_stream_parameters_.slice_data_buffer = stream_;
return true;
}
/**
* @brief Determines the chroma subsampling format based on the given sampling factors.
*
* This function takes the horizontal and vertical sampling factors for each color component and determines
* the chroma subsampling format. It returns the corresponding `ChromaSubsampling` enum value.
*
* @param c1_h_sampling_factor The horizontal sampling factor for color component 1.
* @param c2_h_sampling_factor The horizontal sampling factor for color component 2.
* @param c3_h_sampling_factor The horizontal sampling factor for color component 3.
* @param c1_v_sampling_factor The vertical sampling factor for color component 1.
* @param c2_v_sampling_factor The vertical sampling factor for color component 2.
* @param c3_v_sampling_factor The vertical sampling factor for color component 3.
* @return The chroma subsampling format determined based on the given sampling factors.
*/
ChromaSubsampling RocJpegStreamParser::GetChromaSubsampling(uint8_t c1_h_sampling_factor, uint8_t c2_h_sampling_factor, uint8_t c3_h_sampling_factor,
uint8_t c1_v_sampling_factor, uint8_t c2_v_sampling_factor, uint8_t c3_v_sampling_factor) {
ChromaSubsampling subsampling;
if ((c1_h_sampling_factor == 1 && c2_h_sampling_factor == 1 && c3_h_sampling_factor == 1 &&
c1_v_sampling_factor == 1 && c2_v_sampling_factor == 1 && c3_v_sampling_factor == 1) ||
(c1_h_sampling_factor == 2 && c2_h_sampling_factor == 2 && c3_h_sampling_factor == 2 &&
c1_v_sampling_factor == 2 && c2_v_sampling_factor == 2 && c3_v_sampling_factor == 2) ||
(c1_h_sampling_factor == 4 && c2_h_sampling_factor == 4 && c3_h_sampling_factor == 4 &&
c1_v_sampling_factor == 4 && c2_v_sampling_factor == 4 && c3_v_sampling_factor == 4)) {
subsampling = CSS_444;
} else if (c1_h_sampling_factor == 1 && c2_h_sampling_factor == 1 && c3_h_sampling_factor == 1 &&
c1_v_sampling_factor == 2 && c2_v_sampling_factor == 1 && c3_v_sampling_factor == 1) {
subsampling = CSS_440;
} else if ((c1_h_sampling_factor == 2 && c2_h_sampling_factor == 1 && c3_h_sampling_factor == 1 &&
c1_v_sampling_factor == 1 && c2_v_sampling_factor == 1 && c3_v_sampling_factor == 1) ||
(c1_h_sampling_factor == 2 && c2_h_sampling_factor == 1 && c3_h_sampling_factor == 1 &&
c1_v_sampling_factor == 2 && c2_v_sampling_factor == 2 && c3_v_sampling_factor == 2) ||
(c1_h_sampling_factor == 2 && c2_h_sampling_factor == 2 && c3_h_sampling_factor == 2 &&
c1_v_sampling_factor == 2 && c2_v_sampling_factor == 1 && c3_v_sampling_factor == 1)) {
subsampling = CSS_422;
} else if (c1_h_sampling_factor == 2 && c2_h_sampling_factor == 1 && c3_h_sampling_factor == 1 &&
c1_v_sampling_factor == 2 && c2_v_sampling_factor == 1 && c3_v_sampling_factor == 1) {
subsampling = CSS_420;
} else if (c1_h_sampling_factor == 4 && c2_h_sampling_factor == 1 && c3_h_sampling_factor == 1 &&
c1_v_sampling_factor == 1 && c2_v_sampling_factor == 1 && c3_v_sampling_factor == 1) {
subsampling = CSS_411;
} else if ((c1_h_sampling_factor == 1 && c2_h_sampling_factor == 0 && c3_h_sampling_factor == 0 &&
c1_v_sampling_factor == 1 && c2_v_sampling_factor == 0 && c3_v_sampling_factor == 0) ||
(c1_h_sampling_factor == 4 && c2_h_sampling_factor == 0 && c3_h_sampling_factor == 0 &&
c1_v_sampling_factor == 4 && c2_v_sampling_factor == 0 && c3_v_sampling_factor == 0)) {
subsampling = CSS_400;
} else {
subsampling = CSS_UNKNOWN;
}
return subsampling;
}
+272
Visa fil
@@ -0,0 +1,272 @@
/*
Copyright (c) 2024 - 2026 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.
*/
#ifndef ROC_JPEG_PARSER_H_
#define ROC_JPEG_PARSER_H_
#include <stdint.h>
#include <iostream>
#include <cstring>
#include <mutex>
#include "rocjpeg_commons.h"
#pragma once
#define NUM_COMPONENTS 4
#define HUFFMAN_TABLES 2
#define AC_HUFFMAN_TABLE_VALUES_SIZE 162
#define DC_HUFFMAN_TABLE_VALUES_SIZE 12
#define swap_bytes(x) (((x)[0] << 8) | (x)[1])
/**
* @brief Enumeration representing the common JPEG markers.
*
* The `JpegMarkers` enum defines the common JPEG markers used in a JPEG stream.
*/
enum JpegMarkers {
SOI = 0xD8, /**< Start Of Image */
SOF = 0xC0, /**< Start Of Frame for a baseline DCT-based JPEG. */
DHT = 0xC4, /**< Define Huffman Table */
DQT = 0xDB, /**< Define Quantization Table */
DRI = 0xDD, /**< Define Restart Interval */
SOS = 0xDA, /**< Start of Scan */
EOI = 0xD9, /**< End Of Image */
};
/**
* @brief Structure representing the picture parameter buffer.
*
* This structure contains information about the picture width, picture height,
* color components, color space, rotation, and reserved fields.
*/
typedef struct PictureParameterBufferType {
uint16_t picture_width; /**< The width of the picture. */
uint16_t picture_height; /**< The height of the picture. */
struct {
uint8_t component_id; /**< The ID of the color component. */
uint8_t h_sampling_factor; /**< The horizontal sampling factor. */
uint8_t v_sampling_factor; /**< The vertical sampling factor. */
uint8_t quantiser_table_selector; /**< The quantiser table selector. */
} components[255]; /**< Array of color components. */
uint8_t num_components; /**< The number of color components. */
uint8_t color_space; /**< The color space of the picture. */
uint32_t rotation; /**< The rotation of the picture. */
uint32_t reserved[7]; /**< Reserved fields. */
} PictureParameterBuffer;
/**
* @brief Structure representing the quantization matrix buffer.
*
* This structure holds the quantization tables used in the JPEG decoding process.
* It consists of an array to indicate whether a quantization table is loaded or not,
* a 2D array to store the quantization tables, and a reserved field.
*/
typedef struct QuantizationMatrixBufferType {
uint8_t load_quantiser_table[4]; /**< Array indicating whether a quantization table is loaded or not. */
uint8_t quantiser_table[4][64]; /**< 2D array to store the quantization tables. */
uint32_t reserved[4]; /**< Reserved field. */
} QuantizationMatrixBuffer;
/**
* @brief Struct representing a buffer for Huffman tables.
*
* This struct is used to store Huffman tables for JPEG decoding.
* It contains two sets of Huffman tables, each consisting of
* arrays for the number of DC codes, DC values, number of AC codes,
* AC values, and padding.
*
* The `load_huffman_table` array is used to indicate whether a
* particular Huffman table should be loaded or not.
*
* The `reserved` array is used for future expansion and is currently
* unused.
*/
typedef struct HuffmanTableBufferType {
uint8_t load_huffman_table[2]; /**< Array indicating which Huffman tables to load. */
struct {
uint8_t num_dc_codes[16]; /**< Array of the number of DC codes for each bit length. */
uint8_t dc_values[12]; /**< Array of the DC values. */
uint8_t num_ac_codes[16]; /**< Array of the number of AC codes for each bit length. */
uint8_t ac_values[162]; /**< Array of the AC values. */
uint8_t pad[2]; /**< Padding to align the structure. */
} huffman_table[2]; /**< Array of two sets of Huffman tables. */
uint32_t reserved[4]; /**< Reserved field for future use. */
} HuffmanTableBuffer;
/**
* @brief Structure representing the slice parameter buffer.
*
* This structure contains information about the slice data, such as its size, offset, and flag.
* It also includes the horizontal and vertical position of the slice, as well as the component,
* DC table, and AC table selectors for each component. The number of components, restart interval,
* number of MCUs, and reserved fields are also included.
*/
typedef struct SliceParameterBufferType {
uint32_t slice_data_size; /**< Size of the slice data. */
uint32_t slice_data_offset; /**< Offset of the slice data. */
uint32_t slice_data_flag; /**< Flag indicating the slice data. */
uint32_t slice_horizontal_position; /**< Horizontal position of the slice. */
uint32_t slice_vertical_position; /**< Vertical position of the slice. */
struct {
uint8_t component_selector; /**< Component selector. */
uint8_t dc_table_selector; /**< DC table selector. */
uint8_t ac_table_selector; /**< AC table selector. */
} components[4]; /**< Array of component selectors. */
uint8_t num_components; /**< Number of components. */
uint16_t restart_interval; /**< Restart interval. */
uint32_t num_mcus; /**< Number of MCUs. */
uint32_t reserved[4]; /**< Reserved fields. */
} SliceParameterBuffer;
/**
* @brief Enumeration representing the chroma subsampling formats.
*
* The `ChromaSubsampling` enum defines the possible chroma subsampling formats in a JPEG stream.
* Each value corresponds to a specific chroma subsampling format, such as 4:4:4, 4:2:0, etc.
* The `CSS_UNKNOWN` value is used to indicate an unknown or unsupported format.
*/
typedef enum {
CSS_444 = 0,
CSS_440 = 1,
CSS_422 = 2,
CSS_420 = 3,
CSS_411 = 4,
CSS_400 = 5,
CSS_UNKNOWN = -1
} ChromaSubsampling;
/**
* @brief Structure representing the parameters for a JPEG stream.
*
* This structure contains various buffers and data required for processing a JPEG stream.
* It includes the picture parameter buffer, quantization matrix buffer, Huffman table buffer,
* slice parameter buffer, chroma subsampling information, and the slice data buffer.
*/
typedef struct JpegParameterBuffersType {
PictureParameterBuffer picture_parameter_buffer;
QuantizationMatrixBuffer quantization_matrix_buffer;
HuffmanTableBuffer huffman_table_buffer;
SliceParameterBuffer slice_parameter_buffer;
ChromaSubsampling chroma_subsampling;
const uint8_t* slice_data_buffer;
} JpegStreamParameters;
/**
* @class RocJpegStreamParser
* @brief A class for parsing JPEG streams and extracting stream parameters.
*
* The RocJpegStreamParser class provides functionality to parse a JPEG stream and extract various parameters
* such as Start of Image (SOI), Start of Frame (SOF), Quantization Tables (DQT), Start of Scan (SOS),
* Huffman Tables (DHT), Define Restart Interval (DRI), and End of Image (EOI). It also provides a method to
* retrieve the parsed JPEG stream parameters.
*/
class RocJpegStreamParser {
public:
/**
* @brief Default constructor for RocJpegStreamParser.
*/
RocJpegStreamParser();
/**
* @brief Destructor for RocJpegStreamParser.
*/
~RocJpegStreamParser();
/**
* @brief Parses a JPEG stream and extracts stream parameters.
* @param jpeg_stream The pointer to the JPEG stream.
* @param jpeg_stream_size The size of the JPEG stream.
* @return True if the parsing is successful, false otherwise.
*/
bool ParseJpegStream(const uint8_t* jpeg_stream, uint32_t jpeg_stream_size);
/**
* @brief Retrieves the JPEG stream parameters.
* @return A pointer to the JpegStreamParameters object.
*/
const JpegStreamParameters* GetJpegStreamParameters() const { return &jpeg_stream_parameters_; };
private:
/**
* @brief Parses the Start of Image (SOI) marker.
* @return True if the SOI marker is successfully parsed, false otherwise.
*/
bool ParseSOI();
/**
* @brief Parses the Start of Frame (SOF) marker.
* @return True if the SOF marker is successfully parsed, false otherwise.
*/
bool ParseSOF();
/**
* @brief Parses the Define Quantization Table (DQT) marker.
* @return True if the DQT marker is successfully parsed, false otherwise.
*/
bool ParseDQT();
/**
* @brief Parses the Start of Scan (SOS) marker.
* @return True if the SOS marker is successfully parsed, false otherwise.
*/
bool ParseSOS();
/**
* @brief Parses the Define Huffman Table (DHT) marker.
* @return True if the DHT marker is successfully parsed, false otherwise.
*/
bool ParseDHT();
/**
* @brief Parses the Define Restart Interval (DRI) marker.
* @return True if the DRI marker is successfully parsed, false otherwise.
*/
bool ParseDRI();
/**
* @brief Parses the End of Image (EOI) marker.
* @return True if the EOI marker is successfully parsed, false otherwise.
*/
bool ParseEOI();
/**
* @brief Retrieves the chroma subsampling information.
* @param c1_h_sampling_factor The horizontal sampling factor for component 1.
* @param c2_h_sampling_factor The horizontal sampling factor for component 2.
* @param c3_h_sampling_factor The horizontal sampling factor for component 3.
* @param c1_v_sampling_factor The vertical sampling factor for component 1.
* @param c2_v_sampling_factor The vertical sampling factor for component 2.
* @param c3_v_sampling_factor The vertical sampling factor for component 3.
* @return The chroma subsampling information.
*/
ChromaSubsampling GetChromaSubsampling(uint8_t c1_h_sampling_factor, uint8_t c2_h_sampling_factor, uint8_t c3_h_sampling_factor,
uint8_t c1_v_sampling_factor, uint8_t c2_v_sampling_factor, uint8_t c3_v_sampling_factor);
const uint8_t *stream_; ///< Pointer to the JPEG stream.
const uint8_t *stream_end_; ///< Pointer to the end of the JPEG stream.
uint32_t stream_length_; ///< Length of the JPEG stream.
JpegStreamParameters jpeg_stream_parameters_; ///< JPEG stream parameters.
std::mutex mutex_; ///< Mutex for thread safety.
};
#endif // ROC_JPEG_PARSER_H_
Filskillnaden har hållits tillbaka eftersom den är för stor Load Diff
+433
Visa fil
@@ -0,0 +1,433 @@
/*
Copyright (c) 2024 - 2026 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.
*/
#ifndef ROC_JPEG_VAAPI_DECODER_H_
#define ROC_JPEG_VAAPI_DECODER_H_
#pragma once
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unordered_map>
#include <memory>
#include <functional>
#include <libdrm/amdgpu.h>
#include <libdrm/amdgpu_drm.h>
#include <va/va.h>
#include <va/va_drm.h>
#include <va/va_drmcommon.h>
#include "rocjpeg_commons.h"
#include "rocjpeg_parser.h"
#include "../api/rocjpeg/rocjpeg.h"
/**
* @brief Enumeration representing the compute partition for the MI300+ family of GPUs.
*/
typedef enum {
kSpx = 0, /**< Single Partition Accelerator */
kDpx = 1, /**< Dual Partition Accelerator */
kTpx = 2, /**< Triple Partition Accelerator */
kQpx = 3, /**< Quad Partition Accelerator */
kCpx = 4, /**< Core Partition Accelerator */
} ComputePartition;
/**
* @brief Structure representing the specifications of a VCN JPEG decoder.
*
* This structure contains information about the VCN JPEG decoder, including the number of JPEG cores,
* whether it can convert to RGB, and whether it supports ROI (Region of Interest) decoding.
*/
typedef struct {
uint32_t num_jpeg_cores; /**< Number of JPEG cores in the VCN JPEG decoder. */
bool can_convert_to_rgb; /**< Flag indicating whether the VCN JPEG decoder can convert to RGB. */
bool can_roi_decode; /**< Flag indicating whether the VCN JPEG decoder supports ROI decoding. */
} VcnJpegSpec;
/**
* @brief Structure representing the HIP interop device memory.
*
* This structure holds information related to the HIP-VAAPI interop device memory.
* It includes the HIP external memory interface, mapped device memory for the YUV plane,
* pixel format fourcc of the whole surface, width and height of the surface in pixels,
* offset and pitch of each plane, and the number of layers making up the surface.
*/
struct HipInteropDeviceMem {
hipExternalMemory_t hip_ext_mem; /**< Interface to the vaapi-hip interop */
uint8_t* hip_mapped_device_mem; /**< Mapped device memory for the YUV plane */
uint32_t surface_format; /**< Pixel format fourcc of the whole surface */
uint32_t width; /**< Width of the surface in pixels. */
uint32_t height; /**< Height of the surface in pixels. */
uint32_t size; /**< Size of the surface in pixels. */
uint32_t offset[3]; /**< Offset of each plane */
uint32_t pitch[3]; /**< Pitch of each plane */
uint32_t num_layers; /**< Number of layers making up the surface */
};
/**
* @brief Defines the enumeration MemPoolEntryStatus.
*/
typedef enum {
kIdle = 0,
kBusy = 1,
} MemPoolEntryStatus;
/**
* @struct RocJpegVaapiMemPoolEntry
* @brief Structure representing an entry in the RocJpegVaapiMemPool.
*
* This structure holds information about a memory pool entry used by the RocJpegVaapiDecoder.
* It contains the image width and height, the entry status, an array of VA surface IDs,
* and an array of HipInteropDeviceMem objects.
*/
struct RocJpegVaapiMemPoolEntry {
uint32_t image_width;
uint32_t image_height;
MemPoolEntryStatus entry_status;
std::vector<VASurfaceID> va_surface_ids;
std::vector<HipInteropDeviceMem> hip_interops;
};
/**
* @class RocJpegVaapiMemoryPool
* @brief A class that represents a memory pool for VAAPI surfaces used by the RocJpegVappiDecoder.
*
* The RocJpegVaapiMemoryPool class provides methods to manage and allocate memory resources for VAAPI surfaces.
* It allows setting the pool size, associating a VADisplay, finding surface IDs, getting pool entries, adding pool entries,
* and retrieving HipInterop memory for a specific surface ID.
*/
class RocJpegVaapiMemoryPool {
public:
/**
* @brief Default constructor for RocJpegVaapiMemoryPool.
*/
RocJpegVaapiMemoryPool();
/**
* @brief Releases all the resources associated with the memory pool.
*/
void ReleaseResources();
/**
* @brief Sets the maximum size of the memory pool.
* @param max_pool_size The maximum size of the memory pool.
*/
void SetPoolSize(uint32_t max_pool_size);
/**
* @brief Sets the VADisplay for the memory pool.
* @param va_display The VADisplay to be set.
*/
void SetVaapiDisplay(const VADisplay& va_display);
/**
* @brief Finds a surface ID in the memory pool.
* @param surface_id The surface ID to find.
* @return True if the surface ID is found, false otherwise.
*/
bool FindSurfaceId(VASurfaceID surface_id);
/**
* @brief Gets a pool entry based on the surface format, image width, and image height.
* @param surface_format The surface format of the pool entry.
* @param image_width The image width of the pool entry.
* @param image_height The image height of the pool entry.
* @param num_surfaces The number of surfaces of the entry to retrieve.
* @return The RocJpegVaapiMemPoolEntry object if found, otherwise a default-constructed object.
*/
RocJpegVaapiMemPoolEntry GetEntry(uint32_t surface_format, uint32_t image_width, uint32_t image_height, uint32_t num_surfaces);
/**
* @brief Adds a pool entry to the memory pool.
* @param surface_format The surface format of the pool entry.
* @param pool_entry The RocJpegVaapiMemPoolEntry to be added.
* @return The status of the operation.
*/
RocJpegStatus AddPoolEntry(uint32_t surface_format, const RocJpegVaapiMemPoolEntry& pool_entry);
/**
* @brief Retrieves HipInterop memory for a specific surface ID.
* @param surface_id The surface ID to retrieve HipInterop memory for.
* @param hip_interop The HipInteropDeviceMem object to store the retrieved memory.
* @return The status of the operation.
*/
RocJpegStatus GetHipInteropMem(VASurfaceID surface_id, HipInteropDeviceMem& hip_interop);
/**
* @brief Sets a VASurfaceID as idle.
*
* This function sets the specified VASurfaceID as idle, indicating that it is available for reuse.
*
* @param surface_id The VASurfaceID to set as idle.
* @return true if the VASurfaceID was successfully set as idle, false otherwise.
*/
bool SetSurfaceAsIdle(VASurfaceID surface_id);
private:
VADisplay va_display_; // The VADisplay associated with the memory pool.
uint32_t max_pool_size_; // The maximum pool size of the memory pool (mem_pool_) per entry.
std::unordered_map<uint32_t, std::vector<RocJpegVaapiMemPoolEntry>> mem_pool_; // The memory pool.
/**
* @brief Retrieves the total size of the memory pool.
*
* @return The total size of the memory pool in bytes.
*/
size_t GetTotalMemPoolSize() const;
/**
* @brief Deletes an idle entry from the memory pool.
*
* This function is responsible for removing an idle entry from the memory pool.
* It ensures that resources associated with the idle entry are properly released.
*
* @return true if the idle entry was successfully deleted, false otherwise.
*/
bool DeleteIdleEntry();
};
/**
* @brief Structure representing the key for a JPEG stream.
*
* This structure contains information about the surface format, pixel format, width, and height
* of a JPEG stream. It is used for comparing two JpegStreamKey objects for equality.
*/
struct JpegStreamKey {
uint32_t surface_format; /**< The surface format of the JPEG stream. */
uint32_t pixel_format; /**< The pixel format of the JPEG stream. */
uint32_t width; /**< The width of the JPEG stream. */
uint32_t height; /**< The height of the JPEG stream. */
/**
* @brief Equality operator for comparing two JpegStreamKey objects.
*
* @param other The JpegStreamKey object to compare with.
* @return true if the two objects are equal, false otherwise.
*/
bool operator==(const JpegStreamKey& other) const {
return surface_format == other.surface_format &&
pixel_format == other.pixel_format &&
width == other.width &&
height == other.height;
}
};
/**
* @brief Specialization of the std::hash template for JpegStreamKey.
*
* This struct provides a hash function for the JpegStreamKey struct, which is used as a key in hash-based containers.
* It calculates the hash value based on the surface_format, pixel_format, width, and height members of the JpegStreamKey struct.
*/
template <>
struct std::hash<JpegStreamKey> {
/**
* @brief Calculates the hash value for a given JpegStreamKey object.
*
* @param k The JpegStreamKey object to calculate the hash value for.
* @return The calculated hash value.
*/
std::size_t operator()(const JpegStreamKey& k) const {
size_t result = std::hash<int>()(k.surface_format);
result ^= std::hash<int>()(k.pixel_format) << 1;
result ^= std::hash<uint32_t>()(k.width) << 1;
result ^= std::hash<uint32_t>()(k.height) << 1;
return result;
}
};
/**
* @brief The RocJpegVappiDecoder class represents a VAAPI-based JPEG decoder.
*/
class RocJpegVappiDecoder {
public:
/**
* @brief Constructs a RocJpegVappiDecoder object.
* @param device_id The ID of the device to use for decoding (default is 0).
*/
RocJpegVappiDecoder(int device_id = 0);
/**
* @brief Destroys the RocJpegVappiDecoder object.
*/
~RocJpegVappiDecoder();
/**
* @brief Initializes the decoder with the specified device, GCN architecture, and device ID.
* @param device_name The name of the device.
* @param device_id The ID of the device.
* @param gpu_uuid The UUID of the GPU.
* @return The status of the initialization.
*/
RocJpegStatus InitializeDecoder(std::string device_name, int device_id, std::string& gpu_uuid);
/**
* @brief Submits a JPEG stream for decoding.
* @param jpeg_stream_params The parameters of the JPEG stream.
* @param surface_id The ID of the output surface.
* @param decode_params Additional parameters for the decode operation.
* @return The status of the decoding operation.
*/
RocJpegStatus SubmitDecode(const JpegStreamParameters *jpeg_stream_params, uint32_t &surface_id, const RocJpegDecodeParams *decode_params);
/**
* @brief Waits for the decoding operation to complete.
* @param surface_id The ID of the output surface.
* @return The status of the synchronization operation.
*/
RocJpegStatus SyncSurface(VASurfaceID surface_id);
/**
* @brief Retrieves the HIP interop memory associated with the specified surface.
* @param surface_id The ID of the surface.
* @param hip_interop The HIP interop memory object to be filled.
* @return The status of the retrieval operation.
*/
RocJpegStatus GetHipInteropMem(VASurfaceID surface_id, HipInteropDeviceMem& hip_interop);
/**
* Submits a batch of JPEG streams for decoding using the VAAPI decoder.
*
* @param jpeg_streams_params An array of the JPEG streams parameters to be decoded.
* @param batch_size The number of JPEG streams in the batch.
* @param decode_params The decoding parameters for the VAAPI decoder.
* @param surface_ids An array to store the surface IDs of the decoded frames.
* @return The status of the decoding operation.
*/
RocJpegStatus SubmitDecodeBatched(JpegStreamParameters *jpeg_streams_params, int batch_size, const RocJpegDecodeParams *decode_params, uint32_t *surface_ids);
/**
* @brief Returns the current VCN JPEG specification.
* @return The current VCN JPEG specification.
*/
const VcnJpegSpec& GetCurrentVcnJpegSpec() const {return current_vcn_jpeg_spec_;}
/**
* Sets the specified VASurfaceID as idle.
*
* @param surface_id The VASurfaceID to set as idle.
* @return The status of the operation.
*/
RocJpegStatus SetSurfaceAsIdle(VASurfaceID surface_id);
private:
int device_id_; // The ID of the device
int drm_fd_; // The file descriptor for the DRM device
uint32_t min_picture_width_; // The minimum width of the picture
uint32_t min_picture_height_; // The minimum height of the picture
uint32_t max_picture_width_; // The maximum width of the picture
uint32_t max_picture_height_; // The maximum height of the picture
uint32_t default_surface_width_; // The default width of the surface
uint32_t default_surface_height_; // The default height of the surface
bool supports_modifiers_; // DRM format modifiers support
VADisplay va_display_; // The VAAPI display
VAContextID va_context_id_; // The VAAPI context ID
std::vector<VAConfigAttrib> va_config_attrib_; // The VAAPI configuration attributes
VAConfigID va_config_id_; // The VAAPI configuration ID
VAProfile va_profile_; // The VAAPI profile
std::unique_ptr<RocJpegVaapiMemoryPool> vaapi_mem_pool_; // The VAAPI memory pool
VcnJpegSpec current_vcn_jpeg_spec_; // The current VCN JPEG specification
VABufferID va_picture_parameter_buf_id_; // The VAAPI picture parameter buffer ID
VABufferID va_quantization_matrix_buf_id_; // The VAAPI quantization matrix buffer ID
VABufferID va_huffmantable_buf_id_; // The VAAPI Huffman table buffer ID
VABufferID va_slice_param_buf_id_; // The VAAPI slice parameter buffer ID
VABufferID va_slice_data_buf_id_; // The VAAPI slice data buffer ID
/**
* @brief A map that associates GPU UUIDs with their corresponding render node indices.
*
* This unordered map uses GPU UUIDs as keys (std::string) and maps them to their
* respective render node indices (int). It provides a fast lookup mechanism to
* retrieve the render node index for a given GPU UUID.
*/
std::unordered_map<std::string, int> gpu_uuids_to_render_nodes_map_;
/**
* @brief A map that associates GPU UUIDs with their corresponding compute partitions.
*
* This unordered map uses GPU UUIDs as keys (represented as strings) and maps them to
* ComputePartition objects. It allows for efficient lookup and management of compute
* partitions based on the unique identifiers of GPUs.
*/
std::unordered_map<std::string, ComputePartition> gpu_uuids_to_compute_partition_map_;
/**
* @brief Initializes the VAAPI with the specified DRM node.
* @param drm_node The DRM node to use for VAAPI initialization.
* @return The status of the VAAPI initialization.
*/
RocJpegStatus InitVAAPI(std::string drm_node);
/**
* @brief Creates the decoder configuration.
* @return The status of the configuration creation.
*/
RocJpegStatus CreateDecoderConfig();
/**
* @brief Creates the decoder context.
*
* This function initializes and sets up the necessary context for decoding
* JPEG images using the VA-API.
*
* @return RocJpegStatus indicating the success or failure of the context creation.
*/
RocJpegStatus CreateDecoderContext();
/**
* @brief Destroys the data buffers.
* @return The status of the buffer destruction.
*/
RocJpegStatus DestroyDataBuffers();
/**
* @brief Retrieves the visible devices.
* @param visible_devices The vector to store the visible devices.
*/
void GetVisibleDevices(std::vector<int>& visible_devices);
/**
* @brief Retrieves the DRM node offset.
* @param device_name The name of the device.
* @param device_id The ID of the device.
* @param visible_devices The vector of visible devices.
* @param current_compute_partition The current compute partition.
* @param offset The offset of the DRM node.
*/
void GetDrmNodeOffset(std::string device_name, uint8_t device_id, std::vector<int>& visible_devices,
ComputePartition current_compute_partitions,
int &offset);
/**
* @brief Retrieves GPU UUIDs and maps them to render node IDs.
*/
void GetGpuUuids();
/**
* @brief Retrieves the number of JPEG cores available.
*
* This function is used to determine the number of JPEG decoding cores
* that are available for use.
*/
void GetNumJpegCores();
};
#endif // ROC_JPEG_VAAPI_DECODER_H_
+414
Visa fil
@@ -0,0 +1,414 @@
# ##############################################################################
# Copyright (c) 2024 - 2026 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)
if(NOT DEFINED ENHANCED_MESSAGE)
string(ASCII 27 Esc)
set(ColourReset "${Esc}[m")
set(Red "${Esc}[31m")
set(Green "${Esc}[32m")
set(Yellow "${Esc}[33m")
set(White "${Esc}[37m")
endif()
# 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
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED On)
set(CMAKE_CXX_EXTENSIONS ON)
if(NOT DEFINED CMAKE_CXX_COMPILER)
set(CMAKE_C_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang)
set(CMAKE_CXX_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang++)
endif()
project(rocjpeg-test)
# make test with CTest
enable_testing()
include(CTest)
# add ROCm find Config location
list(APPEND CMAKE_PREFIX_PATH ${ROCM_PATH}/lib/cmake)
# find rocjpeg
if(BUILD_FROM_SOURCE)
message("-- ${White}${PROJECT_NAME}: CTests requires rocjpeg installed before running CTests")
else()
find_package(rocjpeg QUIET)
if(rocjpeg_FOUND)
message("-- ${White}${PROJECT_NAME}: rocjpeg found with find_package(rocjpeg QUIET)${ColourReset}")
message("-- \t${White}rocjpeg_INCLUDE_DIR -- ${rocjpeg_INCLUDE_DIR}${ColourReset}")
message("-- \t${White}rocjpeg_LIB_DIR -- ${rocjpeg_LIB_DIR}${ColourReset}")
message("-- \t${White}rocjpeg_LIBRARY -- ${rocjpeg_LIBRARY}${ColourReset}")
message("-- \t${White}rocjpeg_FOUND -- ${rocjpeg_FOUND}${ColourReset}")
message("-- \t${White}rocjpeg_VERSION -- ${rocjpeg_VERSION}${ColourReset}")
message("-- \t${White}rocjpeg_VERSION_MAJOR -- ${rocjpeg_VERSION_MAJOR}${ColourReset}")
message("-- \t${White}rocjpeg_VERSION_MINOR -- ${rocjpeg_VERSION_MINOR}${ColourReset}")
message("-- \t${White}rocjpeg_VERSION_PATCH -- ${rocjpeg_VERSION_PATCH}${ColourReset}")
else()
message("-- ${Yellow}${PROJECT_NAME} requires rocjpeg. Install rocjpeg before running CTests")
endif(rocjpeg_FOUND)
endif(BUILD_FROM_SOURCE)
# Check if lib/rocm_sysdeps/lib exists in the ROCm path which indicates ROCm installation via TheRock
set(USING_THE_ROCK OFF)
if(EXISTS "${ROCM_PATH}/lib/rocm_sysdeps/lib")
set(USING_THE_ROCK ON)
endif()
add_test(
NAME
jpeg-decode-fmt-native
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecode"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecode"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecode"
-i ${ROCM_PATH}/share/rocjpeg/images/
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-fmt-native PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-fmt-yuv-planar
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecode"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecode"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecode"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt yuv_planar
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-fmt-yuv-planar PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-fmt-y
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecode"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecode"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecode"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt y
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-fmt-y PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-fmt-rgb
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecode"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecode"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecode"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt rgb
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-fmt-rgb PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-fmt-rgb-planar
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecode"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecode"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecode"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt rgb_planar
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-fmt-rgb-planar PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-crop-fmt-native
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecode"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecode"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecode"
-i ${ROCM_PATH}/share/rocjpeg/images/ -crop 960,540,2880,1620
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-crop-fmt-native PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-crop-fmt-yuv-planar
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecode"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecode"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecode"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt yuv_planar -crop 960,540,2880,1620
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-crop-fmt-yuv-planar PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-crop-fmt-y
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecode"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecode"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecode"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt y -crop 960,540,2880,1620
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-crop-fmt-y PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-crop-fmt-rgb
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecode"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecode"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecode"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt rgb -crop 960,540,2880,1620
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-crop-fmt-rgb PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-crop-fmt-rgb-planar
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecode"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecode"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecode"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt rgb_planar -crop 960,540,2880,1620
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-crop-fmt-rgb-planar PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-batch-fmt-native
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecodeBatched"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecodeBatched"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecodebatched"
-i ${ROCM_PATH}/share/rocjpeg/images/
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-batch-fmt-native PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-batch-fmt-yuv-planar
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecodeBatched"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecodeBatched"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecodebatched"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt yuv_planar
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-batch-fmt-yuv-planar PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-batch-fmt-y
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecodeBatched"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecodeBatched"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecodebatched"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt y
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-batch-fmt-y PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-batch-fmt-rgb
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecodeBatched"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecodeBatched"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecodebatched"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt rgb
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-batch-fmt-rgb PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-batch-fmt-rgb-planar
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecodeBatched"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecodeBatched"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecodebatched"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt rgb_planar
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-batch-fmt-rgb-planar PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-batch-crop-fmt-native
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecodeBatched"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecodeBatched"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecodebatched"
-i ${ROCM_PATH}/share/rocjpeg/images/ -crop 960,540,2880,1620
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-batch-crop-fmt-native PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-batch-crop-fmt-yuv-planar
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecodeBatched"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecodeBatched"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecodebatched"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt yuv_planar -crop 960,540,2880,1620
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-batch-crop-fmt-yuv-planar PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-batch-crop-fmt-y
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecodeBatched"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecodeBatched"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecodebatched"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt y -crop 960,540,2880,1620
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-batch-crop-fmt-y PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-batch-crop-fmt-rgb
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecodeBatched"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecodeBatched"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecodebatched"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt rgb -crop 960,540,2880,1620
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-batch-crop-fmt-rgb PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-batch-crop-fmt-rgb-planar
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecodeBatched"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecodeBatched"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecodebatched"
-i ${ROCM_PATH}/share/rocjpeg/images/ -fmt rgb_planar -crop 960,540,2880,1620
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-batch-crop-fmt-rgb-planar PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-decode-perf-fmt-native
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/samples/jpegDecodePerf"
"${CMAKE_CURRENT_BINARY_DIR}/jpegDecodePerf"
--build-generator "${CMAKE_GENERATOR}"
--test-command "jpegdecodeperf"
-i ${ROCM_PATH}/share/rocjpeg/images/
)
if(USING_THE_ROCK)
set_property(TEST jpeg-decode-perf-fmt-native PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
add_test(
NAME
jpeg-negative-api-tests
COMMAND
"${CMAKE_CTEST_COMMAND}"
--build-and-test "${ROCM_PATH}/share/rocjpeg/test/rocjpeg_negative_api_tests"
"${CMAKE_CURRENT_BINARY_DIR}/rocjpeg_negative_api_tests"
--build-generator "${CMAKE_GENERATOR}"
--test-command "rocjpegnegativetest"
)
if(USING_THE_ROCK)
set_property(TEST jpeg-negative-api-tests PROPERTY ENVIRONMENT "LIBVA_DRIVERS_PATH=${ROCM_PATH}/lib/rocm_sysdeps/lib")
endif()
@@ -0,0 +1,94 @@
################################################################################
# Copyright (c) 2024 - 2026 Advanced Micro Devices, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
################################################################################
cmake_minimum_required(VERSION 3.10)
# ROCM Path
if(DEFINED ENV{ROCM_PATH})
set(ROCM_PATH $ENV{ROCM_PATH} CACHE PATH "Default ROCm installation path")
elseif(ROCM_PATH)
message("-- INFO:ROCM_PATH Set -- ${ROCM_PATH}")
else()
set(ROCM_PATH /opt/rocm CACHE PATH "Default ROCm installation path")
endif()
# Set AMD Clang as default compiler
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED On)
set(CMAKE_CXX_EXTENSIONS ON)
if(NOT DEFINED CMAKE_CXX_COMPILER)
set(CMAKE_C_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang)
set(CMAKE_CXX_COMPILER ${ROCM_PATH}/lib/llvm/bin/amdclang++)
endif()
project(rocjpegnegativetest)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../../cmake)
list(APPEND CMAKE_PREFIX_PATH ${ROCM_PATH}/lib/cmake)
# rocJPEG sample build type
set(DEFAULT_BUILD_TYPE "Release")
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "rocJPEG Default Build Type" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
endif()
if(CMAKE_BUILD_TYPE MATCHES Debug)
# -O0 -- Don't Optimize output file
# -gdwarf-4 -- generate debugging information, dwarf-4 for making valgrind work
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -gdwarf-4")
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()
set (HIP_PLATFORM amd CACHE STRING "HIP platform")
find_package(HIP QUIET)
find_package(rocjpeg QUIET)
find_package(rocprofiler-register QUIET)
if(HIP_FOUND AND rocjpeg_FOUND AND rocprofiler-register_FOUND)
# HIP
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} hip::host)
# rocJPEG and utils
include_directories (${rocjpeg_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocjpeg::rocjpeg)
# rocprofiler-register
set(LINK_LIBRARY_LIST ${LINK_LIBRARY_LIST} rocprofiler-register::rocprofiler-register)
# sample app exe
list(APPEND SOURCES ${PROJECT_SOURCE_DIR} rocjpegnegativetest.cpp rocjpeg_api_negative_tests.cpp)
# --all-warnings/-Wall Enable most warning messages
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
add_executable(${PROJECT_NAME} ${SOURCES})
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 rocjpeg_FOUND)
message(FATAL_ERROR "-- ERROR!: rocJPEG Not Found! - please install rocJPEG!")
endif()
if (NOT rocprofiler-register_FOUND)
message(FATAL_ERROR "-- ERROR!: rocprofiler-register Not Found! - please install rocprofiler-register!")
endif()
endif()
@@ -0,0 +1,22 @@
# rocJPEG API Negative tests
This test suite is designed to perform negative testing on all rocJPEG APIs. The purpose of these tests is to validate the robustness and error-handling mechanisms of the rocJPEG APIs
by providing invalid inputs, unexpected scenarios, or edge cases to ensure the APIs respond with appropriate error messages or behaviors.
## Prerequisites:
* Install [rocJPEG](../../README.md#build-and-install-instructions)
## Build
```shell
mkdir build && cd build
cmake ../
make -j
```
## Run
```shell
./rocjpegnegativetest
```
@@ -0,0 +1,385 @@
/*
Copyright (c) 2024 - 2026 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 "rocjpeg_api_negative_tests.h"
RocJpegApiNegativeTests:: RocJpegApiNegativeTests() {};
RocJpegApiNegativeTests::~RocJpegApiNegativeTests() {
RocJpegStatus rocjpeg_status = rocJpegDestroy(rocjpeg_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Failed to destroy rocjpeg handle: " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
}
rocjpeg_status = rocJpegStreamDestroy(rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Failed to destroy rocjpeg stream handle " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
}
}
int RocJpegApiNegativeTests::TestInvalidStreamCreate() {
std::cout << "info: Executing negative test cases for the rocJpegStreamCreate API" << std::endl;
//Scenario 1: Pass nullptr for jpeg_stream_handle
RocJpegStatus rocjpeg_status = rocJpegStreamCreate(nullptr);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Create a valid rocJPEG stream handle - This step ensures a valid rocjpeg_stream_handle_ is available for subsequent negative testing of other rocJPEG parser APIs.
rocjpeg_status = rocJpegStreamCreate(&rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Expected ROCJPEG_STATUS_SUCCESS but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int RocJpegApiNegativeTests::TestInvalidStreamParse() {
std::cout << "info: Executing negative test cases for the rocJpegStreamParse API" << std::endl;
// Scenario 1: Pass nullptr for data and jpeg_stream_handle
RocJpegStatus rocjpeg_status = rocJpegStreamParse(nullptr, 0, nullptr);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 2: Pass a valid jpeg_stream_handle but nullptr for data
rocjpeg_status = rocJpegStreamParse(nullptr, 0, rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 3: Invalid SOI marker
std::vector<uint8_t> invalid_soi_data = {0xFF, 0x00}; // Invalid SOI marker
rocjpeg_status = rocJpegStreamParse(invalid_soi_data.data(), invalid_soi_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 4: Invalid DRI marker
std::vector<uint8_t> invalid_dri_data = {0xFF, 0xD8, 0xFF, 0xDD, 0x00, 0x03}; // Invalid DRI marker length
rocjpeg_status = rocJpegStreamParse(invalid_dri_data.data(), invalid_dri_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 5: Invalid SOS marker - provide an invalid number of components (e.g., the number of components cannot exceed 3, but 4 is provided)
std::vector<uint8_t> invalid_sos_data = {0xFF, 0xD8, 0xFF, 0xDA, 0x00, 0x01, 0x04}; // Invalid number of component
rocjpeg_status = rocJpegStreamParse(invalid_sos_data.data(), invalid_sos_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 6: Invalid number of quantization tables in the DQT marker
std::vector<uint8_t> invalid_quantization_data = {0xFF, 0xD8, 0xFF, 0xDB, 0x00, 0x03, 0x1F}; // Invalid quantization table
rocjpeg_status = rocJpegStreamParse(invalid_quantization_data.data(), invalid_quantization_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 7: Invalid number of Huffman tables in the DHT marker
std::vector<uint8_t> invalid_huffman_table_data = {0xFF, 0xD8, 0xFF, 0xC4, 0x00, 0x03, 0x02}; // Too many Huffman tables
rocjpeg_status = rocJpegStreamParse(invalid_huffman_table_data.data(), invalid_huffman_table_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG for invalid number of Huffman tables but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 8: Invalid AC Huffman table in the DHT marker
std::vector<uint8_t> invalid_ac_huffman_table_data = {
0xFF, 0xD8, //SOI
0xFF, 0xC4, 0x00, 0x03, 0x10, // DHT with AC Hufman table
0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0xA3 // Array of the invalid number of AC codes - the count of values cannot exceed 0xA2, but 0xA3 is provided
};
rocjpeg_status = rocJpegStreamParse(invalid_ac_huffman_table_data.data(), invalid_ac_huffman_table_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 9: Invalid DC Huffman table in the DHT marker
std::vector<uint8_t> invalid_dc_huffman_table_data = {
0xFF, 0xD8, // SOI
0xFF, 0xC4, 0x00, 0x03, 0x01, // DHT with DC Hufman table
0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0x0D // Array of the invalid number of DC codes - the count of values cannot exceed 0x0C, but 0x0D is provided
}; // Invalid DC Huffman table
rocjpeg_status = rocJpegStreamParse(invalid_dc_huffman_table_data.data(), invalid_dc_huffman_table_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 10: invalid number of JPEG component in the SOF marker
std::vector<uint8_t> invalid_num_component_data = {
0xFF, 0xD8, // SOI
0xFF, 0xC0, 0x00, 0x08, // Invalid SOF with the number of component is set to 4
0x08, 0x00, 0x10, 0x00, 0x10, 0x04
};
rocjpeg_status = rocJpegStreamParse(invalid_num_component_data.data(), invalid_num_component_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 11: Invalid quantization table selector specified in the SOF marker
std::vector<uint8_t> Invalid_quantization_table_selector_data = {
0xFF, 0xD8, // SOI
0xFF, 0xC0, 0x00, 0x0B, // SOF with 3 components with invalid quantization table selector is set to 4
0x08, 0x00, 0x10, 0x00, 0x10, 0x03, 0x00, 0x00, 0x04
};
rocjpeg_status = rocJpegStreamParse(Invalid_quantization_table_selector_data.data(), Invalid_quantization_table_selector_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 11: Mismatch in the number of components between the SOS and SOF markers
std::vector<uint8_t> component_mismatch_data = {
0xFF, 0xD8, // SOI
0xFF, 0xC0, 0x00, 0x11, // SOF with 3 components
0x08, 0x00, 0x10, 0x00, 0x10, 0x03, 0x01, 0xFF, 0x00, 0x02, 0xFF, 0x01, 0x03, 0xFF, 0x02,
0xFF, 0xDA, 0x00, 0x07, // SOS with 2 components (mismatch)
0x01, 0x00, 0x02, 0x11, 0x00
};
rocjpeg_status = rocJpegStreamParse(component_mismatch_data.data(), component_mismatch_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 12: Invalid AC Huffman table selector in the SOS marker
std::vector<uint8_t> invalid_ac_huffman_sos_data = {
0xFF, 0xD8, // SOI
0xFF, 0xDA, 0x00, 0x07, // SOS with invalid number of AC Huffman table
0x01, 0x00, 0x04, 0x11, 0x00
};
rocjpeg_status = rocJpegStreamParse(invalid_ac_huffman_sos_data.data(), invalid_ac_huffman_sos_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 13: Invalid DC Huffman table selector in the SOS marker
std::vector<uint8_t> invalid_dc_huffman_sos_data = {
0xFF, 0xD8, // SOI
0xFF, 0xDA, 0x00, 0x07, // SOS with invalid number of DC Huffman table
0x01, 0x00, 0x44, 0x11, 0x00
};
rocjpeg_status = rocJpegStreamParse(invalid_dc_huffman_sos_data.data(), invalid_dc_huffman_sos_data.size(), rocjpeg_stream_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_BAD_JPEG) {
std::cerr << "Expected ROCJPEG_STATUS_BAD_JPEG but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int RocJpegApiNegativeTests::TestInvalidStreamDestroy() {
std::cout << "info: Executing negative test cases for the rocJpegStreamDestroy API" << std::endl;
//Scenario 1: Pass nullptr for jpeg_stream_handle
RocJpegStatus rocjpeg_status = rocJpegStreamDestroy(nullptr);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int RocJpegApiNegativeTests::TestInvalidCreate() {
std::cout << "info: Executing negative test cases for the rocJpegCreate API" << std::endl;
// Scenario 1: Pass nullptr for decoder_handle and decoder_create_info
RocJpegStatus rocjpeg_status = rocJpegCreate(ROCJPEG_BACKEND_HARDWARE, 0, nullptr);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 2: Pass valid pointer for handle but invalid negative device_id
int device_id = -1; // Invalid device ID
rocjpeg_status = rocJpegCreate(ROCJPEG_BACKEND_HARDWARE, device_id, &rocjpeg_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_EXECUTION_FAILED) {
std::cerr << "Expected ROCJPEG_STATUS_EXECUTION_FAILED but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
rocjpeg_status = rocJpegDestroy(rocjpeg_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Expected ROCJPEG_STATUS_SUCCESS but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 3: Pass valid pointer for handle but invalid device_id
device_id = 255; // Invalid device ID
rocjpeg_status = rocJpegCreate(ROCJPEG_BACKEND_HARDWARE, device_id, &rocjpeg_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
rocjpeg_status = rocJpegDestroy(rocjpeg_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Expected ROCJPEG_STATUS_SUCCESS but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 4: Pass valid pointer for handle but unsupported backend
device_id = 0;
rocjpeg_status = rocJpegCreate(ROCJPEG_BACKEND_HYBRID, device_id, &rocjpeg_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_NOT_IMPLEMENTED) {
std::cerr << "Expected ROCJPEG_STATUS_NOT_IMPLEMENTED but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
rocjpeg_status = rocJpegDestroy(rocjpeg_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Expected ROCJPEG_STATUS_SUCCESS but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 5: Use an unsupported backend
RocJpegBackend backend = static_cast<RocJpegBackend>(-1);
rocjpeg_status = rocJpegCreate(backend, device_id, &rocjpeg_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
rocjpeg_status = rocJpegDestroy(rocjpeg_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Expected ROCJPEG_STATUS_SUCCESS but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Create a valid rocJPEG handle - This step ensures a valid rocjpeg_handle_ is available for subsequent negative testing of other rocJPEG APIs.
rocjpeg_status = rocJpegCreate(ROCJPEG_BACKEND_HARDWARE, device_id, &rocjpeg_handle_);
if (rocjpeg_status != ROCJPEG_STATUS_SUCCESS) {
std::cerr << "Expected ROCJPEG_STATUS_SUCCESS but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int RocJpegApiNegativeTests::TestInvalidDestroy() {
std::cout << "info: Executing negative test cases for the rocJpegDestroy API" << std::endl;
//Scenario 1: Pass nullptr for decoder_handle
RocJpegStatus rocjpeg_status = rocJpegDestroy(nullptr);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int RocJpegApiNegativeTests::TestInvalidGetImageInfo() {
std::cout << "info: Executing negative test cases for the rocJpegGetImageInfo API" << std::endl;
// Scenario 1: Pass nullptr for all parameters
RocJpegStatus rocjpeg_status = rocJpegGetImageInfo(rocjpeg_handle_, nullptr, nullptr, nullptr, nullptr, nullptr);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int RocJpegApiNegativeTests::TestInvalidDecode() {
std::cout << "info: Executing negative test cases for the rocJpegDecode API" << std::endl;
// Scenario 1: Pass nullptr for all parameters
RocJpegStatus rocjpeg_status = rocJpegDecode(nullptr, nullptr, nullptr, nullptr);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 2: Pass valid handle but nullptr for other parameters
rocjpeg_status = rocJpegDecode(rocjpeg_handle_, nullptr, nullptr, nullptr);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 3: Pass valid handle and stream but nullptr for decode_params and destination
rocjpeg_status = rocJpegDecode(rocjpeg_handle_, rocjpeg_stream_handle_, nullptr, nullptr);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
// Scenario 4: Pass valid handle, stream, and decode_params but nullptr for destination
RocJpegDecodeParams decode_params = {}; // Assume this is initialized with valid data
rocjpeg_status = rocJpegDecode(rocjpeg_handle_, rocjpeg_stream_handle_, &decode_params, nullptr);
if (rocjpeg_status != ROCJPEG_STATUS_INVALID_PARAMETER) {
std::cerr << "Expected ROCJPEG_STATUS_INVALID_PARAMETER but got " << rocJpegGetErrorName(rocjpeg_status) << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int RocJpegApiNegativeTests::TestInvalidDecodeBatched() {
std::cout << "info: Executing negative test cases for the rocJpegDecodeBatched API" << std::endl;
return EXIT_SUCCESS;
}
int RocJpegApiNegativeTests::TestInvalidGetErrorName() {
std::cout << "info: Executing negative test cases for the rocJpegGetErrorName API" << std::endl;
// Scenario 1: Pass an invalid error code
RocJpegStatus invalid_status = static_cast<RocJpegStatus>(-999); // Invalid error code
const char *error_name = rocJpegGetErrorName(invalid_status);
if (error_name == nullptr) {
std::cerr << "Expected a valid error but got nullptr" << std::endl;
return EXIT_FAILURE;
}
// Scenario 2: Pass a valid error code and ensure it returns a non-null name
for (int i = 0; i >= ROCJPEG_STATUS_MAX_VALUE; i--) {
RocJpegStatus valid_status = static_cast<RocJpegStatus>(i);;
error_name = rocJpegGetErrorName(valid_status);
if (error_name == nullptr) {
std::cerr << "Expected a valid error but got nullptr" << std::endl;
return EXIT_FAILURE;
}
}
// Scenario 3: Pass a boundary value (e.g., maximum enum value + 1)
RocJpegStatus boundary_status = static_cast<RocJpegStatus>(ROCJPEG_STATUS_SUCCESS + 1);
error_name = rocJpegGetErrorName(boundary_status);
if (error_name == nullptr) {
std::cerr << "Expected a valid error but got nullptr" << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int RocJpegApiNegativeTests::RunTests() {
if (TestInvalidStreamCreate() || TestInvalidStreamParse () || TestInvalidStreamDestroy() || TestInvalidCreate() || TestInvalidDestroy() ||
TestInvalidGetImageInfo() || TestInvalidDecode() || TestInvalidDecodeBatched() || TestInvalidGetErrorName()) {
std::cerr << "One or more negative tests failed." << std::endl;
return EXIT_FAILURE;
} else {
return EXIT_SUCCESS;
}
}
@@ -0,0 +1,56 @@
/*
Copyright (c) 2024 - 2026 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.
*/
#ifndef ROCJPEG_API_NEGATIVE_TESTS_H
#define ROCJPEG_API_NEGATIVE_TESTS_H
#include <iostream>
#include <vector>
#include <rocjpeg/rocjpeg.h>
/**
* @class RocJpegApiNegativeTests
* @brief A class to perform negative API tests for the rocJPEG library.
*
* This class contains a set of test cases designed to validate the behavior
* of the rocJPEG library when invalid or unexpected inputs are provided.
* It ensures the robustness and error handling capabilities of the library.
*/
class RocJpegApiNegativeTests {
public:
RocJpegApiNegativeTests();
~RocJpegApiNegativeTests();
int RunTests();
private:
int TestInvalidStreamCreate();
int TestInvalidStreamParse();
int TestInvalidStreamDestroy();
int TestInvalidCreate();
int TestInvalidDestroy();
int TestInvalidGetImageInfo();
int TestInvalidDecode();
int TestInvalidDecodeBatched();
int TestInvalidGetErrorName();
RocJpegHandle rocjpeg_handle_;
RocJpegStreamHandle rocjpeg_stream_handle_;
};
#endif // ROCJPEG_API_NEGATIVE_TESTS_H
@@ -0,0 +1,33 @@
/*
Copyright (c) 2024 - 2026 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 "rocjpeg_api_negative_tests.h"
int main(int argc, char **argv) {
RocJpegApiNegativeTests rocjpeg_negative_test;
if (rocjpeg_negative_test.RunTests()) {
std::cout << "Test Failed!" << std::endl;
return EXIT_FAILURE;
}
std::cout << "Test Passed!" << std::endl;
return EXIT_SUCCESS;
}