Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the gainMap member of avifImage a pointer. #1801

Merged
merged 2 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions apps/avifenc.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,10 +531,10 @@ static avifBool avifInputReadImage(avifInput * input,
assert(AVIF_FALSE);
}
#if defined(AVIF_ENABLE_EXPERIMENTAL_JPEG_GAIN_MAP_CONVERSION)
if (cached->image->gainMap.image != NULL) {
image->gainMap.image = avifImageCreateEmpty();
const avifCropRect gainMapRect = { 0, 0, cached->image->gainMap.image->width, cached->image->gainMap.image->height };
if (avifImageSetViewRect(image->gainMap.image, cached->image->gainMap.image, &gainMapRect) != AVIF_RESULT_OK) {
if (cached->image->gainMap && cached->image->gainMap->image) {
image->gainMap->image = avifImageCreateEmpty();
const avifCropRect gainMapRect = { 0, 0, cached->image->gainMap->image->width, cached->image->gainMap->image->height };
if (avifImageSetViewRect(image->gainMap->image, cached->image->gainMap->image, &gainMapRect) != AVIF_RESULT_OK) {
assert(AVIF_FALSE);
}
}
Expand Down Expand Up @@ -1192,7 +1192,7 @@ static avifBool avifEncodeImagesFixedQuality(const avifSettings * settings,
}
char gainMapStr[100] = { 0 };
#if defined(AVIF_ENABLE_EXPERIMENTAL_JPEG_GAIN_MAP_CONVERSION)
if (firstImage->gainMap.image != NULL) {
if (firstImage->gainMap && firstImage->gainMap->image) {
snprintf(gainMapStr, sizeof(gainMapStr), ", gain map quality [%d (%s)]", encoder->qualityGainMap, qualityString(encoder->qualityGainMap));
}
#endif
Expand Down Expand Up @@ -1305,7 +1305,7 @@ static avifBool avifEncodeImages(avifSettings * settings,
avifBool hasGainMap = AVIF_FALSE;
avifBool allQualitiesConstrained = settings->qualityIsConstrained && settings->qualityAlphaIsConstrained;
#if defined(AVIF_ENABLE_EXPERIMENTAL_JPEG_GAIN_MAP_CONVERSION)
hasGainMap = (firstImage->gainMap.image != NULL);
hasGainMap = (firstImage->gainMap && firstImage->gainMap->image);
if (hasGainMap) {
allQualitiesConstrained = allQualitiesConstrained && settings->qualityGainMapIsConstrained;
}
Expand Down Expand Up @@ -2503,7 +2503,7 @@ MAIN()
const avifImage * avif = gridCells ? gridCells[0] : image;
avifBool gainMapPresent = AVIF_FALSE;
#if defined(AVIF_ENABLE_EXPERIMENTAL_JPEG_GAIN_MAP_CONVERSION)
gainMapPresent = (avif->gainMap.image != NULL);
gainMapPresent = (avif->gainMap && avif->gainMap->image);
#endif
avifImageDump(avif,
settings.gridDims[0],
Expand Down
7 changes: 4 additions & 3 deletions apps/avifgainmaputil/combine_command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,16 @@ avifResult CombineCommand::Run() {
std::cout << "Creating a gain map of size " << gain_map_width << " x "
<< gain_map_height << "\n";

base_image->gainMap.image =
base_image->gainMap = avifGainMapCreate();
base_image->gainMap->image =
avifImageCreate(gain_map_width, gain_map_height, arg_gain_map_depth_,
gain_map_pixel_format);
if (base_image->gainMap.image == nullptr) {
if (base_image->gainMap->image == nullptr) {
return AVIF_RESULT_OUT_OF_MEMORY;
}
avifDiagnostics diag;
result = avifImageComputeGainMap(base_image.get(), alternate_image.get(),
&base_image->gainMap, &diag);
base_image->gainMap, &diag);
if (result != AVIF_RESULT_OK) {
std::cout << "Failed to compute gain map: " << avifResultToString(result)
<< " (" << diag.error << ")\n";
Expand Down
4 changes: 2 additions & 2 deletions apps/avifgainmaputil/convert_command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ avifResult ConvertCommand::Run() {
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
}

if (image->gainMap.image == nullptr) {
if (image->gainMap == nullptr || image->gainMap->image == nullptr) {
std::cerr << "Input image " << arg_input_filename_
<< " does not contain a gain map\n";
return AVIF_RESULT_INVALID_ARGUMENT;
Expand All @@ -75,7 +75,7 @@ avifResult ConvertCommand::Run() {
if (arg_swap_base_) {
int depth = arg_image_read_.depth;
if (depth == 0) {
depth = image->gainMap.metadata.alternateHdrHeadroomN == 0 ? 8 : 10;
depth = image->gainMap->metadata.alternateHdrHeadroomN == 0 ? 8 : 10;
}
ImagePtr new_base(
avifImageCreate(image->width, image->height, depth, image->yuvFormat));
Expand Down
5 changes: 3 additions & 2 deletions apps/avifgainmaputil/extractgainmap_command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ avifResult ExtractGainMapCommand::Run() {
return result;
}

if (decoder->image->gainMap.image == nullptr) {
if (decoder->image->gainMap == nullptr ||
decoder->image->gainMap->image == nullptr) {
std::cerr << "Input image " << arg_input_filename_
<< " does not contain a gain map\n";
return AVIF_RESULT_INVALID_ARGUMENT;
}

return WriteImage(decoder->image->gainMap.image, arg_output_filename_,
return WriteImage(decoder->image->gainMap->image, arg_output_filename_,
arg_image_encode_.quality, arg_image_encode_.speed);
}

Expand Down
5 changes: 3 additions & 2 deletions apps/avifgainmaputil/imageio.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,11 @@ avifResult WriteAvif(const avifImage* image, avifEncoder* encoder,
const std::string& output_filename) {
avifRWData encoded = AVIF_DATA_EMPTY;
std::cout << "AVIF to be written:\n";
const bool gain_map_present =
(image->gainMap != nullptr && image->gainMap->image != nullptr);
avifImageDump(image,
/*gridCols=*/1,
/*gridRows=*/1,
/*gainMapPresent=*/image->gainMap.image != nullptr,
/*gridRows=*/1, gain_map_present,
AVIF_PROGRESSIVE_STATE_UNAVAILABLE);
std::cout << "Encoding AVIF at quality " << encoder->quality << " speed "
<< encoder->speed << ", please wait...\n";
Expand Down
4 changes: 3 additions & 1 deletion apps/avifgainmaputil/printmetadata_command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "printmetadata_command.h"

#include <cassert>
#include <iomanip>

#include "avif/avif_cxx.h"
Expand Down Expand Up @@ -62,8 +63,9 @@ avifResult PrintMetadataCommand::Run() {
<< " does not contain a gain map\n";
return AVIF_RESULT_INVALID_ARGUMENT;
}
assert(decoder->image->gainMap);

const avifGainMapMetadata& metadata = decoder->image->gainMap.metadata;
const avifGainMapMetadata& metadata = decoder->image->gainMap->metadata;
const int w = 20;
std::cout << " * " << std::left << std::setw(w) << "Base headroom: "
<< FormatFraction(metadata.baseHdrHeadroomN,
Expand Down
40 changes: 21 additions & 19 deletions apps/avifgainmaputil/swapbase_command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
namespace avif {

avifResult ChangeBase(avifImage& image, avifImage* swapped) {
if (image.gainMap.image == nullptr) {
if (image.gainMap == nullptr || image.gainMap->image == nullptr) {
return AVIF_RESULT_INVALID_ARGUMENT;
}

const float headroom =
static_cast<double>(image.gainMap.metadata.alternateHdrHeadroomN) /
image.gainMap.metadata.alternateHdrHeadroomD;
static_cast<double>(image.gainMap->metadata.alternateHdrHeadroomN) /
image.gainMap->metadata.alternateHdrHeadroomD;
const bool tone_mapping_to_sdr = (headroom == 0.0f);

// The gain map's cicp values are those of the 'tmap' item and describe the
Expand All @@ -24,13 +24,14 @@ avifResult ChangeBase(avifImage& image, avifImage* swapped) {
// property. This property describes the colour properties of the
// reconstructed image if the gain map input item is fully applied according
// to ISO/AWI 214961.
if (image.gainMap.image->transferCharacteristics !=
if (image.gainMap->image->transferCharacteristics !=
AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED ||
image.gainMap.image->colorPrimaries != AVIF_COLOR_PRIMARIES_UNSPECIFIED) {
swapped->colorPrimaries = image.gainMap.image->colorPrimaries;
image.gainMap->image->colorPrimaries !=
AVIF_COLOR_PRIMARIES_UNSPECIFIED) {
swapped->colorPrimaries = image.gainMap->image->colorPrimaries;
swapped->transferCharacteristics =
image.gainMap.image->transferCharacteristics;
swapped->matrixCoefficients = image.gainMap.image->matrixCoefficients;
image.gainMap->image->transferCharacteristics;
swapped->matrixCoefficients = image.gainMap->image->matrixCoefficients;
} else {
// If there is no cicp on the gain map, use the same values as the old base
// image, except for the transfer characteristics.
Expand All @@ -45,13 +46,13 @@ avifResult ChangeBase(avifImage& image, avifImage* swapped) {
avifRGBImage swapped_rgb;
avifRGBImageSetDefaults(&swapped_rgb, swapped);

avifContentLightLevelInformationBox clli = image.gainMap.image->clli;
avifContentLightLevelInformationBox clli = image.gainMap->image->clli;
const bool compute_clli =
!tone_mapping_to_sdr && clli.maxCLL == 0 && clli.maxPALL == 0;

avifDiagnostics diag;
avifResult result = avifImageApplyGainMap(
&image, &image.gainMap, headroom, swapped->transferCharacteristics,
&image, image.gainMap, headroom, swapped->transferCharacteristics,
&swapped_rgb, (compute_clli ? &clli : nullptr), &diag);
if (result != AVIF_RESULT_OK) {
std::cout << "Failed to tone map image: " << avifResultToString(result)
Expand All @@ -67,19 +68,19 @@ avifResult ChangeBase(avifImage& image, avifImage* swapped) {

swapped->clli = clli;
swapped->gainMap = image.gainMap;
// swapped has taken ownership of the gain map image, so remove ownership
// 'swapped' has taken ownership of the gain map, so remove ownership
// from the old image to prevent a double free.
image.gainMap.image = nullptr;
image.gainMap = nullptr;
// Set the gain map's cicp values and clli to the old base image's.
swapped->gainMap.image->clli = image.clli;
swapped->gainMap.image->colorPrimaries = image.colorPrimaries;
swapped->gainMap.image->transferCharacteristics =
swapped->gainMap->image->clli = image.clli;
swapped->gainMap->image->colorPrimaries = image.colorPrimaries;
swapped->gainMap->image->transferCharacteristics =
image.transferCharacteristics;
// Don't touch matrixCoefficients as it's needed to correctly decode the gain
// map.

// Swap base and alternate in the gain map metadata.
avifGainMapMetadata& metadata = swapped->gainMap.metadata;
avifGainMapMetadata& metadata = swapped->gainMap->metadata;
metadata.backwardDirection = !metadata.backwardDirection;
metadata.useBaseColorSpace = !metadata.useBaseColorSpace;
std::swap(metadata.baseHdrHeadroomN, metadata.alternateHdrHeadroomN);
Expand Down Expand Up @@ -124,18 +125,19 @@ avifResult SwapBaseCommand::Run() {
return result;
}

if (decoder->image->gainMap.image == nullptr) {
if (decoder->image->gainMap == nullptr ||
decoder->image->gainMap->image == nullptr) {
std::cerr << "Input image " << arg_input_filename_
<< " does not contain a gain map\n";
return AVIF_RESULT_INVALID_ARGUMENT;
}

int depth = arg_image_read_.depth;
if (depth == 0) {
depth = decoder->image->gainMap.metadata.alternateHdrHeadroomN == 0
depth = decoder->image->gainMap->metadata.alternateHdrHeadroomN == 0
? 8
: std::max(decoder->image->depth,
decoder->image->gainMap.image->depth);
decoder->image->gainMap->image->depth);
}
avifPixelFormat pixel_format =
(avifPixelFormat)arg_image_read_.pixel_format.value();
Expand Down
9 changes: 5 additions & 4 deletions apps/avifgainmaputil/tonemap_command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,16 @@ avifResult TonemapCommand::Run() {
arg_input_cicp_.value().matrix_coefficients;
}

if (decoder->image->gainMap.image == nullptr) {
if (decoder->image->gainMap == nullptr ||
decoder->image->gainMap->image == nullptr) {
std::cerr << "Input image " << arg_input_filename_
<< " does not contain a gain map\n";
return AVIF_RESULT_INVALID_ARGUMENT;
}

avifGainMapMetadataDouble metadata;
if (!avifGainMapMetadataFractionsToDouble(
&metadata, &decoder->image->gainMap.metadata)) {
&metadata, &decoder->image->gainMap->metadata)) {
std::cerr << "Input image " << arg_input_filename_
<< " has invalid gain map metadata\n";
return AVIF_RESULT_INVALID_ARGUMENT;
Expand All @@ -123,7 +124,7 @@ avifResult TonemapCommand::Run() {
metadata.alternateHdrHeadroom <= metadata.baseHdrHeadroom) ||
(headroom >= metadata.alternateHdrHeadroom &&
metadata.alternateHdrHeadroom >= metadata.baseHdrHeadroom)) {
clli_box = decoder->image->gainMap.image->clli;
clli_box = decoder->image->gainMap->image->clli;
}
clli_set = (clli_box.maxCLL != 0) || (clli_box.maxPALL != 0);
}
Expand All @@ -145,7 +146,7 @@ avifResult TonemapCommand::Run() {
avifRGBImage tone_mapped_rgb;
avifRGBImageSetDefaults(&tone_mapped_rgb, tone_mapped.get());
avifDiagnostics diag;
result = avifImageApplyGainMap(decoder->image, &decoder->image->gainMap,
result = avifImageApplyGainMap(decoder->image, decoder->image->gainMap,
arg_headroom_, cicp.transfer_characteristics,
&tone_mapped_rgb,
clli_set ? nullptr : &clli_box, &diag);
Expand Down
7 changes: 6 additions & 1 deletion apps/shared/avifjpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,12 @@ static avifBool avifJPEGReadInternal(FILE * f,
// The primary XMP block (for the main image) must contain a node with an hdrgm:Version field if and only if a gain map is present.
if (!ignoreGainMap && avifJPEGHasGainMapXMPNode(avif->xmp.data, avif->xmp.size)) {
// Ignore the return value: continue even if we fail to find/parse/decode the gain map.
avifJPEGExtractGainMapImage(f, &cinfo, &avif->gainMap, chromaDownsampling);
avifGainMap * gainMap = avifGainMapCreate();
if (avifJPEGExtractGainMapImage(f, &cinfo, gainMap, chromaDownsampling)) {
avif->gainMap = gainMap;
} else {
avifGainMapDestroy(gainMap);
}
}

if (avif->xmp.size > 0 && ignoreXMP) {
Expand Down
4 changes: 2 additions & 2 deletions apps/shared/avifutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ static void avifImageDumpInternal(const avifImage * avif,

#if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
printf(" * Gain map : ");
avifImage * gainMap = avif->gainMap.image;
avifImage * gainMap = avif->gainMap ? avif->gainMap->image : NULL;
if (gainMap != NULL) {
printf("%ux%u pixels, %u bit, %s, %s Range, Matrix Coeffs. %u, Base Image is %s\n",
gainMap->width,
Expand All @@ -141,7 +141,7 @@ static void avifImageDumpInternal(const avifImage * avif,
avifPixelFormatToString(gainMap->yuvFormat),
(gainMap->yuvRange == AVIF_RANGE_FULL) ? "Full" : "Limited",
gainMap->matrixCoefficients,
(avif->gainMap.metadata.baseHdrHeadroomN == 0) ? "SDR" : "HDR");
(avif->gainMap->metadata.baseHdrHeadroomN == 0) ? "SDR" : "HDR");
printf(" * Color Primaries: %u\n", gainMap->colorPrimaries);
printf(" * Transfer Char. : %u\n", gainMap->transferCharacteristics);
printf(" * Matrix Coeffs. : %u\n", gainMap->matrixCoefficients);
Expand Down
15 changes: 11 additions & 4 deletions include/avif/avif.h
Original file line number Diff line number Diff line change
Expand Up @@ -626,9 +626,11 @@ typedef struct avifGainMapMetadata
} avifGainMapMetadata;

// Gain map image and associated metadata.
// Must be allocated by calling avifGainMapCreate().
typedef struct avifGainMap
{
// Gain map pixels.
// Owned by the avifGainMap and gets freed when calling avifGainMapDestroy().
// Used fields: width, height, depth, yufFormat, yuvRange,
// yuvChromaSamplePosition, yuvPlanes, yuvRowBytes, imageOwnsYUVPlanes,
// matrixCoefficients, transferCharacteristics. Other fields are ignored.
Expand All @@ -639,6 +641,12 @@ typedef struct avifGainMap
avifGainMapMetadata metadata;
} avifGainMap;

// Allocates a gain map. Returns NULL if a memory allocation failed.
// The 'image' field is NULL by default and must be allocated separately.
AVIF_API avifGainMap * avifGainMapCreate();
// Frees a gain map, including the 'image' field if non NULL.
AVIF_API void avifGainMapDestroy(avifGainMap * gainMap);

// Same as avifGainMapMetadata, but with fields of type double instead of uint32_t fractions.
// Use avifGainMapMetadataDoubleToFractions() to convert this to a avifGainMapMetadata.
// See avifGainMapMetadata for detailed descriptions of fields.
Expand Down Expand Up @@ -731,10 +739,9 @@ typedef struct avifImage
// Version 1.0.0 ends here. Add any new members after this line.

#if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
// Gain map image and metadata. If no gain map is present, gainMap.image is NULL.
// When calling avifImageDestroy on the containing image, the gain map image is also destroyed
// (the containing image "owns" the gain map).
avifGainMap gainMap;
// Gain map image and metadata. NULL if no gain map is present.
// Owned by the avifImage and gets freed when calling avifImageDestroy().
avifGainMap * gainMap;
#endif
} avifImage;

Expand Down
Loading