Created new cmake option AVIF_CODEC_AOM, reorganized struct avifCodec to prepare for other codec impls
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 273f3fc..2be50e2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,13 +6,10 @@
## [Unreleased]
### Added
-- Added install rules in CMake
+- Added new CMake option `AVIF_CODEC_AOM` to enable/disable the usage of AOM's codec (default: on)
### Changed
-- Minor CMake cleanup
-
-### Changed
-- Various README url updates to point at official repo
+- Reorganized internal struct avifCodec to accomodate multiple codecs simultaneously (compile time; not exposed to API)
## [0.2.0] - 2019-06-12
### Added
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4bc35a9..70c337a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,14 +8,11 @@
add_definitions(-std=c99) # Enforce C99 for gcc
endif()
+option(AVIF_CODEC_AOM "Use the AOM codec for encoding (and decoding if no other decoder is present)" ON)
+
add_subdirectory(ext)
-include_directories(
- include
- "${CMAKE_CURRENT_SOURCE_DIR}/ext/aom"
- "${AOM_BINARY_DIR}"
-)
-
+include_directories(include)
if(NOT AVIF_EXTERNAL_GB)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/ext/gb")
endif()
@@ -34,13 +31,21 @@
src/write.c
)
-# TODO: Support other codec implementations here
-set(AVIF_SRCS ${AVIF_SRCS}
- src/codec_aom.c
-)
+set(AVIF_CODEC_LIBARIES)
+if(AVIF_CODEC_AOM)
+ add_definitions(-DAVIF_CODEC_AOM=1)
+ set(AVIF_SRCS ${AVIF_SRCS}
+ src/codec_aom.c
+ )
+ include_directories(
+ "${CMAKE_CURRENT_SOURCE_DIR}/ext/aom"
+ "${AOM_BINARY_DIR}"
+ )
+ set(AVIF_CODEC_LIBARIES ${AVIF_CODEC_LIBARIES} aom)
+endif()
add_library(avif STATIC ${AVIF_SRCS})
-target_link_libraries(avif aom gb)
+target_link_libraries(avif gb ${AVIF_CODEC_LIBARIES})
option(AVIF_BUILD_EXAMPLES "Build avif Examples." OFF)
if(AVIF_BUILD_EXAMPLES)
@@ -65,32 +70,19 @@
target_link_libraries(avifdec avif)
endif()
-# Install rules
-if(NOT CMAKE_SKIP_INSTALL_RULES)
- install(
- FILES "include/avif/avif.h" "include/avif/internal.h"
- DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/avif"
- )
- install(
- TARGETS avif
- DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
- )
- if(AVIF_BUILD_APPS)
- install(
- TARGETS avifenc avifdec
- DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}"
- )
+macro(avif_set_folder_safe target folder)
+ if(TARGET ${target})
+ set_target_properties(${target} PROPERTIES FOLDER ${folder})
endif()
-endif()
+endmacro()
if(WIN32)
- # Allow for continuous builders to make a static avif library package
option(AVIF_BUILD_STATIC "Build static avif library (with codec/gb included)" OFF)
if(AVIF_BUILD_STATIC)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/avif_static_x64.lib
COMMAND link.exe /lib /nologo /MACHINE:x64 /OUT:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/avif_static_x64.lib $<TARGET_FILE:avif> $<TARGET_FILE:aom> $<TARGET_FILE:gb>
- DEPENDS avif aom
+ DEPENDS avif ${AVIF_CODEC_LIBARIES}
COMMENT "Creating static avif library..."
)
@@ -99,13 +91,8 @@
)
endif()
- # Visual Studio organizing
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
- macro(avif_set_folder_safe target folder)
- if(TARGET ${target})
- set_target_properties(${target} PROPERTIES FOLDER ${folder})
- endif()
- endmacro()
+
avif_set_folder_safe(aom "ext/avif")
avif_set_folder_safe(aom_av1 "ext/avif")
avif_set_folder_safe(aom_av1_common "ext/avif")
@@ -149,6 +136,7 @@
avif_set_folder_safe(aom_version_check "ext/avif")
avif_set_folder_safe(avif "ext/avif")
avif_set_folder_safe(dist "ext/avif")
+
if(NOT AVIF_EXTERNAL_GB)
avif_set_folder_safe(gb "ext/avif")
endif()
diff --git a/README.md b/README.md
index 84f9a4f..e2c1f8e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# libavif [](https://ci.appveyor.com/project/louquillio/libavif) [](https://travis-ci.com/AOMediaCodec/libavif)
+# libavif [](https://ci.appveyor.com/project/joedrago/avif) [](https://travis-ci.com/joedrago/avif)
This library aims to be a friendly, portable C implementation of the AV1 Image File Format, as described here:
@@ -16,7 +16,7 @@
# Prebuilt Library (Windows)
-If you're building on Windows with VS2017 and want to try out libavif without going through the build process, static library builds for both Debug and Release are available on [Appveyor](https://ci.appveyor.com/project/louquillio/libavif).
+If you're building on Windows with VS2017 and want to try out libavif without going through the build process, static library builds for both Debug and Release are available on [Appveyor](https://ci.appveyor.com/project/joedrago/avif).
---
diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt
index 45325c2..9a5e9f5 100644
--- a/ext/CMakeLists.txt
+++ b/ext/CMakeLists.txt
@@ -1,12 +1,14 @@
# Copyright 2019 Joe Drago. All rights reserved.
# SPDX-License-Identifier: BSD-2-Clause
-set(ENABLE_DOCS 0)
-set(ENABLE_EXAMPLES 0)
-set(ENABLE_TESTDATA 0)
-set(ENABLE_TESTS 0)
-set(ENABLE_TOOLS 0)
-add_subdirectory(aom EXCLUDE_FROM_ALL)
+if(AVIF_CODEC_AOM)
+ set(ENABLE_DOCS 0)
+ set(ENABLE_EXAMPLES 0)
+ set(ENABLE_TESTDATA 0)
+ set(ENABLE_TESTS 0)
+ set(ENABLE_TOOLS 0)
+ add_subdirectory(aom EXCLUDE_FROM_ALL)
+endif()
if(NOT AVIF_EXTERNAL_GB)
include_directories(gb)
diff --git a/include/avif/avif.h b/include/avif/avif.h
index 54a67cd..12fb80e 100644
--- a/include/avif/avif.h
+++ b/include/avif/avif.h
@@ -93,7 +93,8 @@
AVIF_RESULT_DECODE_ALPHA_FAILED,
AVIF_RESULT_COLOR_ALPHA_SIZE_MISMATCH,
AVIF_RESULT_ISPE_SIZE_MISMATCH,
- AVIF_UNSUPPORTED_PIXEL_FORMAT
+ AVIF_RESULT_NO_CODEC_AVAILABLE,
+ AVIF_RESULT_
} avifResult;
const char * avifResultToString(avifResult result);
diff --git a/include/avif/internal.h b/include/avif/internal.h
index 0748ed5..cd4de2f 100644
--- a/include/avif/internal.h
+++ b/include/avif/internal.h
@@ -88,23 +88,33 @@
uint32_t height;
} avifCodecImageSize;
+struct avifCodec;
struct avifCodecInternal;
+typedef avifBool (* avifCodecDecodeFunc)(struct avifCodec * codec, avifCodecPlanes planes, avifRawData * obu);
+typedef avifCodecImageSize (* avifCodecGetImageSizeFunc)(struct avifCodec * codec, avifCodecPlanes planes); // should return 0s if absent
+typedef avifBool (* avifCodecAlphaLimitedRangeFunc)(struct avifCodec * codec); // returns AVIF_TRUE if an alpha plane exists and was encoded with limited range
+typedef avifResult (* avifCodecGetDecodedImageFunc)(struct avifCodec * codec, avifImage * image);
+typedef avifResult (* avifCodecEncodeImageFunc)(struct avifCodec * codec, avifImage * image, avifEncoder * encoder, avifRawData * colorOBU, avifRawData * alphaOBU); // if either OBU* is null, skip its encode. alpha should always be lossless
+typedef void (* avifCodecGetConfigurationBoxFunc)(struct avifCodec * codec, avifCodecPlanes planes, avifCodecConfigurationBox * outConfig);
+typedef void (* avifCodecDestroyInternalFunc)(struct avifCodec * codec);
+
typedef struct avifCodec
{
struct avifCodecInternal * internal; // up to each codec to use how it wants
+
+ avifCodecDecodeFunc decode;
+ avifCodecGetImageSizeFunc getImageSize;
+ avifCodecAlphaLimitedRangeFunc alphaLimitedRange;
+ avifCodecGetDecodedImageFunc getDecodedImage;
+ avifCodecEncodeImageFunc encodeImage;
+ avifCodecGetConfigurationBoxFunc getConfigurationBox;
+ avifCodecDestroyInternalFunc destroyInternal;
} avifCodec;
-avifCodec * avifCodecCreate();
+avifCodec * avifCodecCreateAOM();
void avifCodecDestroy(avifCodec * codec);
-avifBool avifCodecDecode(avifCodec * codec, avifCodecPlanes planes, avifRawData * obu);
-avifCodecImageSize avifCodecGetImageSize(avifCodec * codec, avifCodecPlanes planes); // should return 0s if absent
-avifBool avifCodecAlphaLimitedRange(avifCodec * codec); // returns AVIF_TRUE if an alpha plane exists and was encoded with limited range
-avifResult avifCodecGetDecodedImage(avifCodec * codec, avifImage * image);
-avifResult avifCodecEncodeImage(avifCodec * codec, avifImage * image, avifEncoder * encoder, avifRawData * colorOBU, avifRawData * alphaOBU); // if either OBU* is null, skip its encode. alpha should always be lossless
-void avifCodecGetConfigurationBox(avifCodec * codec, avifCodecPlanes planes, avifCodecConfigurationBox * outConfig);
-
// ---------------------------------------------------------------------------
// avifStream
diff --git a/src/avif.c b/src/avif.c
index 99a9f5b..ffe5e0c 100644
--- a/src/avif.c
+++ b/src/avif.c
@@ -1,7 +1,7 @@
// Copyright 2019 Joe Drago. All rights reserved.
// SPDX-License-Identifier: BSD-2-Clause
-#include "avif/avif.h"
+#include "avif/internal.h"
#include <string.h>
@@ -80,7 +80,7 @@
case AVIF_RESULT_DECODE_ALPHA_FAILED: return "Decoding of alpha plane failed";
case AVIF_RESULT_COLOR_ALPHA_SIZE_MISMATCH: return "Color and alpha planes size mismatch";
case AVIF_RESULT_ISPE_SIZE_MISMATCH: return "Plane sizes don't match ispe values";
- case AVIF_UNSUPPORTED_PIXEL_FORMAT: return "Unsupported pixel format";
+ case AVIF_RESULT_NO_CODEC_AVAILABLE: return "No codec available";
case AVIF_RESULT_UNKNOWN_ERROR:
default:
break;
@@ -238,3 +238,13 @@
{
return (image->depth > 8) ? AVIF_TRUE : AVIF_FALSE;
}
+
+// avifCodecCreate*() functions are in their respective codec_*.c files
+
+void avifCodecDestroy(avifCodec * codec)
+{
+ if (codec && codec->destroyInternal) {
+ codec->destroyInternal(codec);
+ }
+ avifFree(codec);
+}
diff --git a/src/codec_aom.c b/src/codec_aom.c
index 97783bd..e715b9c 100644
--- a/src/codec_aom.c
+++ b/src/codec_aom.c
@@ -20,15 +20,7 @@
avifCodecConfigurationBox configs[AVIF_CODEC_PLANES_COUNT];
};
-avifCodec * avifCodecCreate()
-{
- avifCodec * codec = (avifCodec *)avifAlloc(sizeof(avifCodec));
- codec->internal = (struct avifCodecInternal *)avifAlloc(sizeof(struct avifCodecInternal));
- memset(codec->internal, 0, sizeof(struct avifCodecInternal));
- return codec;
-}
-
-void avifCodecDestroy(avifCodec * codec)
+static void aomCodecDestroyInternal(avifCodec * codec)
{
for (int plane = 0; plane < AVIF_CODEC_PLANES_COUNT; ++plane) {
if (codec->internal->decoderInitialized[plane]) {
@@ -37,10 +29,9 @@
avifRawDataFree(&codec->internal->encodedOBUs[plane]);
}
avifFree(codec->internal);
- avifFree(codec);
}
-avifBool avifCodecDecode(avifCodec * codec, avifCodecPlanes planes, avifRawData * obu)
+static avifBool aomCodecDecode(avifCodec * codec, avifCodecPlanes planes, avifRawData * obu)
{
aom_codec_stream_info_t si;
aom_codec_iface_t * decoder_interface = aom_codec_av1_dx();
@@ -67,7 +58,7 @@
return (codec->internal->images[planes]) ? AVIF_TRUE : AVIF_FALSE;
}
-avifCodecImageSize avifCodecGetImageSize(avifCodec * codec, avifCodecPlanes planes)
+static avifCodecImageSize aomCodecGetImageSize(avifCodec * codec, avifCodecPlanes planes)
{
avifCodecImageSize size;
if (codec->internal->images[planes]) {
@@ -80,7 +71,7 @@
return size;
}
-avifBool avifCodecAlphaLimitedRange(avifCodec * codec)
+static avifBool aomCodecAlphaLimitedRange(avifCodec * codec)
{
aom_image_t * aomAlphaImage = codec->internal->images[AVIF_CODEC_PLANES_ALPHA];
if (aomAlphaImage && (aomAlphaImage->range == AOM_CR_STUDIO_RANGE)) {
@@ -89,7 +80,7 @@
return AVIF_FALSE;
}
-avifResult avifCodecGetDecodedImage(avifCodec * codec, avifImage * image)
+static avifResult aomCodecGetDecodedImage(avifCodec * codec, avifImage * image)
{
aom_image_t * aomColorImage = codec->internal->images[AVIF_CODEC_PLANES_COLOR];
aom_image_t * aomAlphaImage = codec->internal->images[AVIF_CODEC_PLANES_ALPHA];
@@ -360,7 +351,7 @@
return success;
}
-avifResult avifCodecEncodeImage(avifCodec * codec, avifImage * image, avifEncoder * encoder, avifRawData * colorOBU, avifRawData * alphaOBU)
+static avifResult aomCodecEncodeImage(avifCodec * codec, avifImage * image, avifEncoder * encoder, avifRawData * colorOBU, avifRawData * alphaOBU)
{
if (colorOBU) {
if (!encodeOBU(image, AVIF_FALSE, encoder, colorOBU, &codec->internal->configs[AVIF_CODEC_PLANES_COLOR])) {
@@ -375,7 +366,24 @@
return AVIF_RESULT_OK;
}
-void avifCodecGetConfigurationBox(avifCodec * codec, avifCodecPlanes planes, avifCodecConfigurationBox * outConfig)
+static void aomCodecGetConfigurationBox(avifCodec * codec, avifCodecPlanes planes, avifCodecConfigurationBox * outConfig)
{
memcpy(outConfig, &codec->internal->configs[planes], sizeof(avifCodecConfigurationBox));
}
+
+avifCodec * avifCodecCreateAOM()
+{
+ avifCodec * codec = (avifCodec *)avifAlloc(sizeof(avifCodec));
+ memset(codec, 0, sizeof(struct avifCodec));
+ codec->decode = aomCodecDecode;
+ codec->getImageSize = aomCodecGetImageSize;
+ codec->alphaLimitedRange = aomCodecAlphaLimitedRange;
+ codec->getDecodedImage = aomCodecGetDecodedImage;
+ codec->encodeImage = aomCodecEncodeImage;
+ codec->getConfigurationBox = aomCodecGetConfigurationBox;
+ codec->destroyInternal = aomCodecDestroyInternal;
+
+ codec->internal = (struct avifCodecInternal *)avifAlloc(sizeof(struct avifCodecInternal));
+ memset(codec->internal, 0, sizeof(struct avifCodecInternal));
+ return codec;
+}
diff --git a/src/read.c b/src/read.c
index a40bc6c..73b97a5 100644
--- a/src/read.c
+++ b/src/read.c
@@ -554,6 +554,11 @@
{
avifCodec * codec = NULL;
+#ifndef AVIF_CODEC_AOM
+ // Just bail out early, we're not surviving this function without a decoder compiled in
+ return AVIF_RESULT_NO_CODEC_AVAILABLE;
+#endif
+
// -----------------------------------------------------------------------
// Parse BMFF boxes
@@ -647,21 +652,26 @@
}
avifBool hasAlpha = (alphaOBU.size > 0) ? AVIF_TRUE : AVIF_FALSE;
- codec = avifCodecCreate();
- if (!avifCodecDecode(codec, AVIF_CODEC_PLANES_COLOR, &colorOBU)) {
+#ifdef AVIF_CODEC_AOM
+ codec = avifCodecCreateAOM();
+#else
+// #error No decoder available!
+ return AVIF_RESULT_NO_CODEC_AVAILABLE;
+#endif
+ if (!codec->decode(codec, AVIF_CODEC_PLANES_COLOR, &colorOBU)) {
avifCodecDestroy(codec);
return AVIF_RESULT_DECODE_COLOR_FAILED;
}
- avifCodecImageSize colorPlanesSize = avifCodecGetImageSize(codec, AVIF_CODEC_PLANES_COLOR);
+ avifCodecImageSize colorPlanesSize = codec->getImageSize(codec, AVIF_CODEC_PLANES_COLOR);
avifCodecImageSize alphaPlanesSize;
memset(&alphaPlanesSize, 0, sizeof(alphaPlanesSize));
if (hasAlpha) {
- if (!avifCodecDecode(codec, AVIF_CODEC_PLANES_ALPHA, &alphaOBU)) {
+ if (!codec->decode(codec, AVIF_CODEC_PLANES_ALPHA, &alphaOBU)) {
avifCodecDestroy(codec);
return AVIF_RESULT_DECODE_ALPHA_FAILED;
}
- alphaPlanesSize = avifCodecGetImageSize(codec, AVIF_CODEC_PLANES_ALPHA);
+ alphaPlanesSize = codec->getImageSize(codec, AVIF_CODEC_PLANES_ALPHA);
if ((colorPlanesSize.width != alphaPlanesSize.width) || (colorPlanesSize.height != alphaPlanesSize.height)) {
avifCodecDestroy(codec);
@@ -686,14 +696,14 @@
avifImageFreePlanes(image, AVIF_PLANES_ALL);
- avifResult imageResult = avifCodecGetDecodedImage(codec, image);
+ avifResult imageResult = codec->getDecodedImage(codec, image);
if (imageResult != AVIF_RESULT_OK) {
avifCodecDestroy(codec);
return imageResult;
}
#if defined(AVIF_FIX_STUDIO_ALPHA)
- if (hasAlpha && avifCodecAlphaLimitedRange(codec)) {
+ if (hasAlpha && codec->alphaLimitedRange(codec)) {
// Naughty! Alpha planes are supposed to be full range. Correct that here.
if (avifImageUsesU16(image)) {
for (int j = 0; j < image->height; ++j) {
diff --git a/src/write.c b/src/write.c
index 354ef1a..bb3a2d0 100644
--- a/src/write.c
+++ b/src/write.c
@@ -46,7 +46,14 @@
avifResult result = AVIF_RESULT_UNKNOWN_ERROR;
avifRawData colorOBU = AVIF_RAW_DATA_EMPTY;
avifRawData alphaOBU = AVIF_RAW_DATA_EMPTY;
- avifCodec * codec = avifCodecCreate();
+ avifCodec * codec = NULL;
+
+#ifdef AVIF_CODEC_AOM
+ codec = avifCodecCreateAOM();
+#else
+ // Just bail out early, we're not surviving this function without an encoder compiled in
+ return AVIF_RESULT_NO_CODEC_AVAILABLE;
+#endif
avifStream s;
avifStreamStart(&s, output);
@@ -81,7 +88,7 @@
alphaOBUPtr = NULL;
}
- avifResult encodeResult = avifCodecEncodeImage(codec, image, encoder, &colorOBU, alphaOBUPtr);
+ avifResult encodeResult = codec->encodeImage(codec, image, encoder, &colorOBU, alphaOBUPtr);
if (encodeResult != AVIF_RESULT_OK) {
result = encodeResult;
goto writeCleanup;
@@ -246,7 +253,7 @@
ipmaPush(&ipmaColor, ipcoIndex);
avifCodecConfigurationBox colorConfig;
- avifCodecGetConfigurationBox(codec, AVIF_CODEC_PLANES_COLOR, &colorConfig);
+ codec->getConfigurationBox(codec, AVIF_CODEC_PLANES_COLOR, &colorConfig);
writeConfigBox(&s, &colorConfig);
++ipcoIndex;
ipmaPush(&ipmaColor, ipcoIndex);
@@ -260,7 +267,7 @@
ipmaPush(&ipmaAlpha, ipcoIndex);
avifCodecConfigurationBox alphaConfig;
- avifCodecGetConfigurationBox(codec, AVIF_CODEC_PLANES_ALPHA, &alphaConfig);
+ codec->getConfigurationBox(codec, AVIF_CODEC_PLANES_ALPHA, &alphaConfig);
writeConfigBox(&s, &alphaConfig);
++ipcoIndex;
ipmaPush(&ipmaAlpha, ipcoIndex);