Skip to content

Commit

Permalink
Merge branch 'master' into rename-heif-convert
Browse files Browse the repository at this point in the history
  • Loading branch information
farindk committed Jun 26, 2024
2 parents db223b7 + 78f97e3 commit a0275c7
Show file tree
Hide file tree
Showing 169 changed files with 13,418 additions and 1,430 deletions.
128 changes: 125 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ macro(plugin_compilation_info optionVariableName detectionVariable displayName)
endif ()

string(LENGTH "${displayName}" len)
math(EXPR fill "29 - ${len}")
string(SUBSTRING " " 0 ${fill} filler)
math(EXPR fill "32 - ${len}")
string(SUBSTRING " " 0 ${fill} filler)
message("${displayName}${filler}: ${msg}")
unset(msg)
endmacro()
Expand Down Expand Up @@ -125,6 +125,18 @@ if (WITH_KVAZAAR)
endif ()
endif ()

# uvg266

plugin_option(UVG266 "uvg266 VVC encoder (experimental)" OFF OFF)
if (WITH_UVG266)
find_package(UVG266)
if ("${HAVE_UVG266_ENABLE_LOGGING}")
add_definitions(-DHAVE_UVG266_ENABLE_LOGGING=1)
else ()
add_definitions(-DHAVE_UVG266_ENABLE_LOGGING=0)
endif ()
endif ()

# dav1d

plugin_option(DAV1D "Dav1d AV1 decoder" OFF ON)
Expand All @@ -138,6 +150,14 @@ plugin_option(AOM_DECODER "AOM AV1 decoder" ON OFF)
plugin_option(AOM_ENCODER "AOM AV1 encoder" ON OFF)
if (WITH_AOM_ENCODER OR WITH_AOM_DECODER)
find_package(AOM)

# When decoding/encoding is disabled, overwrite the *_FOUND variables, because they are used to ultimately decide what to build.
if (NOT WITH_AOM_DECODER)
set(AOM_DECODER_FOUND FALSE)
endif()
if (NOT WITH_AOM_ENCODER)
set(AOM_ENCODER_FOUND FALSE)
endif()
endif()

# svt
Expand Down Expand Up @@ -177,14 +197,22 @@ if (WITH_FFMPEG_DECODER)
find_package(FFMPEG COMPONENTS avcodec avutil)
endif ()

# openjph

plugin_option(OPENJPH_ENCODER "OpenJPH HT-J2K encoder" OFF ON)
# plugin_option(OPENJPH_DECODER "OpenJPH HT-J2K decoder" OFF ON)
if (WITH_OPENJPH_ENCODER OR WITH_OPENJPH_DECODER)
find_package(OPENJPH)
endif()

# uncompressed

option(WITH_UNCOMPRESSED_CODEC " Support internal ISO/IEC 23001-17 uncompressed codec (experimental) " OFF)


# --- show codec compilation summary

message("=== Summary of compiled codecs ===")
message("\n=== Summary of compiled codecs ===")
plugin_compilation_info(LIBDE265 LIBDE265 "libde265 HEVC decoder")
plugin_compilation_info(FFMPEG_DECODER FFMPEG_avcodec "FFMPEG HEVC decoder (HW acc)")
plugin_compilation_info(X265 X265 "x265 HEVC encoder")
Expand All @@ -198,7 +226,83 @@ plugin_compilation_info(JPEG_DECODER JPEG "JPEG decoder")
plugin_compilation_info(JPEG_ENCODER JPEG "JPEG encoder")
plugin_compilation_info(OpenJPEG_DECODER OpenJPEG "OpenJPEG J2K decoder")
plugin_compilation_info(OpenJPEG_ENCODER OpenJPEG "OpenJPEG J2K encoder")
# plugin_compilation_info(OPENJPH_DECODER OPENJPH "OpenJPH HT-J2K decoder")
plugin_compilation_info(OPENJPH_ENCODER OPENJPH "OpenJPH HT-J2K encoder")
plugin_compilation_info(UVG266_ENCODER UVG266 "uvg266 VVC enc. (experimental)")

# --- show summary which formats are supported

macro(format_compilation_info formatName decoding_supported encoding_supported)
if (${decoding_supported})
set(decoding "YES")
else()
set(decoding "NO ")
endif()

if (${encoding_supported})
set(encoding "YES")
else()
set(encoding "NO ")
endif()

string(LENGTH "${formatName}" len)
math(EXPR fill "12 - ${len}")
string(SUBSTRING " " 0 ${fill} filler)
message("${formatName}${filler} ${decoding} ${encoding}")
unset(msg)
endmacro()


if (LIBDE265_FOUND OR FFMPEG_avcodec_FOUND)
set(SUPPORTS_HEIC_DECODING TRUE)
endif()
if (X265_FOUND OR KVAZAAR_FOUND)
set(SUPPORTS_HEIC_ENCODING TRUE)
endif()
if (AOM_DECODER_FOUND OR DAV1D_FOUND)
set(SUPPORTS_AVIF_DECODING TRUE)
endif()
if (AOM_ENCODER_FOUND OR RAV1E_FOUND OR SvtEnc_FOUND)
set(SUPPORTS_AVIF_ENCODING TRUE)
endif ()
if (JPEG_FOUND AND WITH_JPEG_DECODER)
set(SUPPORTS_JPEG_DECODING TRUE)
endif()
if (JPEG_FOUND AND WITH_JPEG_ENCODER)
set(SUPPORTS_JPEG_ENCODING TRUE)
endif()
if (OpenJPEG_FOUND AND WITH_OpenJPEG_DECODER)
set(SUPPORTS_J2K_DECODING TRUE)
set(SUPPORTS_J2K_HT_DECODING TRUE)
endif()
if (OpenJPEG_FOUND AND WITH_OpenJPEG_ENCODER)
set(SUPPORTS_J2K_ENCODING TRUE)
endif()
if (OPENJPH_FOUND AND WITH_OPENJPH_ENCODER)
set(SUPPORTS_J2K_HT_ENCODING TRUE)
endif()
if (OPENJPH_FOUND AND WITH_OPENJPH_DECODER)
set(SUPPORTS_J2K_HT_ENCODING TRUE)
endif()
if (UVG266_FOUND)
set(SUPPORTS_VVC_ENCODING TRUE)
endif()

if (WITH_UNCOMPRESSED_CODEC)
set(SUPPORTS_UNCOMPRESSED_DECODING TRUE)
set(SUPPORTS_UNCOMPRESSED_ENCODING TRUE)
endif()

message("\n=== Supported formats ===")
message("format decoding encoding")
format_compilation_info("HEIC" SUPPORTS_HEIC_DECODING SUPPORTS_HEIC_ENCODING)
format_compilation_info("AVIF" SUPPORTS_AVIF_DECODING SUPPORTS_AVIF_ENCODING)
format_compilation_info("VVC" FALSE SUPPORTS_VVC_ENCODING)
format_compilation_info("JPEG" SUPPORTS_JPEG_DECODING SUPPORTS_JPEG_ENCODING)
format_compilation_info("JPEG2000" SUPPORTS_J2K_DECODING SUPPORTS_J2K_ENCODING)
format_compilation_info("JPEG2000-HT" SUPPORTS_J2K_HT_DECODING SUPPORTS_J2K_HT_ENCODING)
format_compilation_info("Uncompressed" SUPPORTS_UNCOMPRESSED_DECODING SUPPORTS_UNCOMPRESSED_ENCODING)
message("")

# --- Libsharpyuv color space transforms

Expand Down Expand Up @@ -327,6 +431,24 @@ endif (DOXYGEN_FOUND)

# --- Testing

option(ENABLE_COVERAGE "" OFF)
if(ENABLE_COVERAGE)
# set compiler flags
set(CMAKE_CXX_FLAGS "-O0 -coverage")

# find required tools
find_program(LCOV lcov REQUIRED)
find_program(GENHTML genhtml REQUIRED)

# add coverage target
add_custom_target(coverage
# gather data
COMMAND ${LCOV} --directory . --capture --output-file coverage.info
# generate report
COMMAND ${GENHTML} --demangle-cpp -o coverage coverage.info
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
endif()

option(BUILD_TESTING "" ON)
include(CTest)
if(BUILD_TESTING)
Expand Down
1 change: 1 addition & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"WITH_OpenJPEG_DECODER_PLUGIN" : "ON",
"WITH_OpenJPEG_ENCODER" : "ON",
"WITH_OpenJPEG_ENCODER_PLUGIN" : "ON",
"WITH_OPENJPH_ENCODER" : "ON",
"WITH_FFMPEG_DECODER" : "ON",
"WITH_FFMPEG_DECODER_PLUGIN" : "ON",

Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@ libheif has support for:
* decoding of files while downloading (e.g. extract image size before file has been completely downloaded)

Supported codecs:
| Format | Decoders | Encoders |
|:-------------|:----------------:|:-------------------:|
| HEIC | libde265, ffmpeg | x265, kvazaar |
| AVIF | AOM, dav1d | AOM, rav1e, svt-av1 |
| JPEG | libjpeg(-turbo) | libjpeg(-turbo) |
| JPEG2000 | OpenJPEG | OpenJPEG |
| uncompressed | built-in | built-in |
| Format | Decoders | Encoders |
|:-------------|:----------------:|:---------------------:|
| HEIC | libde265, ffmpeg | x265, kvazaar |
| AVIF | AOM, dav1d | AOM, rav1e, svt-av1 |
| VVC | - | uvg266 (experimental) |
| JPEG | libjpeg(-turbo) | libjpeg(-turbo) |
| JPEG2000 | OpenJPEG | OpenJPEG |
| uncompressed | built-in | built-in |

## API

The library has a C API for easy integration and wide language support.
Note that the API is still work in progress and may still change.

The decoder automatically supports both HEIF and AVIF through the same API. No changes are required to existing code to support AVIF.
The encoder can be switched between HEIF and AVIF simply by setting `heif_compression_HEVC` or `heif_compression_AV1`
Expand Down Expand Up @@ -155,7 +155,7 @@ For each codec, there are two configuration variables:
* `WITH_{codec}_PLUGIN`: when enabled, the codec is compiled as a separate plugin.

In order to use dynamic plugins, also make sure that `ENABLE_PLUGIN_LOADING` is enabled.
The placeholder `{codec}` can have these values: `LIBDE265`, `X265`, `AOM_DECODER`, `AOM_ENCODER`, `SvtEnc`, `DAV1D`, `FFMPEG_DECODER`, `JPEG_DECODER`, `JPEG_ENCODER`, `KVAZAAR`, `OpenJPEG_DECODER`, `OpenJPEG_ENCODER`.
The placeholder `{codec}` can have these values: `LIBDE265`, `X265`, `AOM_DECODER`, `AOM_ENCODER`, `SvtEnc`, `DAV1D`, `FFMPEG_DECODER`, `JPEG_DECODER`, `JPEG_ENCODER`, `KVAZAAR`, `OpenJPEG_DECODER`, `OpenJPEG_ENCODER`, `OPENJPH_ENCODER`

Further options are:

Expand Down
24 changes: 24 additions & 0 deletions cmake/modules/FindOPENJPH.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
include(LibFindMacros)
libfind_pkg_check_modules(OPENJPH_PKGCONF openjph)

find_path(OPENJPH_INCLUDE_DIR
NAMES openjph/ojph_version.h
HINTS ${OPENJPH_PKGCONF_INCLUDE_DIRS} ${OPENJPH_PKGCONF_INCLUDEDIR}
PATH_SUFFIXES OPENJPH
)

find_library(OPENJPH_LIBRARY
NAMES libopenjph openjph
HINTS ${OPENJPH_PKGCONF_LIBRARY_DIRS} ${OPENJPH_PKGCONF_LIBDIR}
)

set(OPENJPH_PROCESS_LIBS OPENJPH_LIBRARY)
set(OPENJPH_PROCESS_INCLUDES OPENJPH_INCLUDE_DIR)
libfind_process(OPENJPH)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(OPENJPH
REQUIRED_VARS
OPENJPH_INCLUDE_DIR
OPENJPH_LIBRARY
)
4 changes: 2 additions & 2 deletions examples/heif-dec.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.TH HEIF-THUMBNAILER 1
.TH HEIF-CONVERT 1
.SH NAME
heif-dec \- decode HEIC/HEIF image
.SH SYNOPSIS
Expand All @@ -12,7 +12,7 @@ Convert HEIC/HEIF image to a different image format.
.SH OPTIONS
.TP
.BR \-q\fR\ \fIQUALITY\fR
Defines quality level between 0 and 100 for the generated output file.
Defines quality level between 0 and 100 for the generated output file. Only used for JPEG.
.SH EXIT STATUS
.PP
\fB0\fR
Expand Down
2 changes: 1 addition & 1 deletion examples/heif-enc.1
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Output filename (optional).
Enable logging output (more will increase logging level).
.TP
.BR \-P ", "\-\-params\fR
Show all encoder parameters.
Show all encoder parameters and exit. Input file is not required or used.
.TP
.BR \-b\fR\ \fIDEPTH\fR
Bit-depth of generated HEIF file when using 16-bit PNG input (default: 10 bit).
Expand Down
8 changes: 6 additions & 2 deletions examples/heif-info.1
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ heif-info \- show information on HEIC/HEIF file
.B heif-info
[\fB\-d\fR|\fB--dump-boxes\fR]
[\fB\-h\fR|\fB--help\fR]
[\fB\-v\fR|\fB--version\fR]
.IR filename
.SH DESCRIPTION
.B heif-info
Expand All @@ -14,8 +15,11 @@ Show information on HEIC/HEIF file.
.BR \-d ", " \-\-dump-boxes\fR
Show a low-level dump of all MP4 file boxes.
.TP
.BR \-help ", " \-\-help\fR
Show help.
.BR \-h ", " \-\-help\fR
Show help. A filename is not required or used.
.TP
.BR \-v ", " \-\-version\fR
Show version information for the tool, library version, and the plugin path. A filename is not required or used.
.SH EXIT STATUS
.PP
\fB0\fR
Expand Down
41 changes: 26 additions & 15 deletions examples/heif_dec.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <cstring>
#include <getopt.h>
#include "libheif/heif_items.h"

#if defined(HAVE_UNISTD_H)

Expand All @@ -39,6 +40,7 @@
#include <cassert>
#include <algorithm>
#include <vector>
#include <array>
#include <cctype>

#include <libheif/heif.h>
Expand Down Expand Up @@ -165,6 +167,9 @@ void list_all_decoders()
std::cout << "HEIC decoders:\n";
list_decoders(heif_compression_HEVC);

std::cout << "VVIC decoders:\n";
list_decoders(heif_compression_VVC);

std::cout << "AVIF decoders:\n";
list_decoders(heif_compression_AV1);

Expand All @@ -174,6 +179,9 @@ void list_all_decoders()
std::cout << "JPEG 2000 decoders:\n";
list_decoders(heif_compression_JPEG2000);

std::cout << "HT-J2K decoders:\n";
list_decoders(heif_compression_HTJ2K);

#if WITH_UNCOMPRESSED_CODEC
std::cout << "uncompressed: yes\n";
#else
Expand Down Expand Up @@ -376,27 +384,29 @@ int main(int argc, char** argv)
// TODO: check, whether reading from named pipes works at all.

std::ifstream istr(input_filename.c_str(), std::ios_base::binary);
uint8_t magic[12];
istr.read((char*) magic, 12);

if (heif_check_jpeg_filetype(magic, 12)) {
fprintf(stderr, "Input file '%s' is a JPEG image\n", input_filename.c_str());
std::array<uint8_t,4> length{};
istr.read((char*) length.data(), length.size());
uint32_t box_size = (length[0] << 24) + (length[1] << 16) + (length[2] << 8) + (length[3]);
if ((box_size < 16) || (box_size > 512)) {
fprintf(stderr, "Input file does not appear to start with a valid box length.");
if ((box_size & 0xFFFFFFF0) == 0xFFD8FFE0) {
fprintf(stderr, " Possibly could be a JPEG file instead.\n");
} else {
fprintf(stderr, "\n");
}
return 1;
}

enum heif_filetype_result filetype_check = heif_check_filetype(magic, 12);
if (filetype_check == heif_filetype_no) {
fprintf(stderr, "Input file is not an HEIF/AVIF file\n");
return 1;
}
std::vector<uint8_t> ftyp_bytes(box_size);
std::copy(length.begin(), length.end(), ftyp_bytes.begin());
istr.read((char*) ftyp_bytes.data() + 4, ftyp_bytes.size() - 4);

if (filetype_check == heif_filetype_yes_unsupported) {
fprintf(stderr, "Input file is an unsupported HEIF/AVIF file type\n");
heif_error filetype_check = heif_has_compatible_filetype(ftyp_bytes.data(), (int)ftyp_bytes.size());
if (filetype_check.code != heif_error_Ok) {
fprintf(stderr, "Input file is not a supported format. %s\n", filetype_check.message);
return 1;
}



// --- read the HEIF file

struct heif_context* ctx = heif_context_alloc();
Expand All @@ -413,6 +423,7 @@ int main(int argc, char** argv)
return 1;
}


int num_images = heif_context_get_number_of_top_level_images(ctx);
if (num_images == 0) {
fprintf(stderr, "File doesn't contain any images\n");
Expand Down Expand Up @@ -703,7 +714,7 @@ int main(int argc, char** argv)

offset = (exif[0]<<24) | (exif[1]<<16) | (exif[2]<<8) | exif[3];
offset += 4;

if (offset >= exifSize) {
heif_image_handle_release(handle);
std::cerr << "Invalid EXIF metadata, offset out of range.\n";
Expand Down
Loading

0 comments on commit a0275c7

Please sign in to comment.