-
Notifications
You must be signed in to change notification settings - Fork 200
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
Add experimental support for reading and writing gain maps. #1501
Conversation
8801215
to
f02b994
Compare
src/write.c
Outdated
// only process alpha payloads when alphaPass is true | ||
avifBool isAlphaOrGainMap = item->itemCategory == AVIF_ITEM_ALPHA; | ||
#if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP) | ||
isAlphaOrGainMap = isAlphaOrGainMap || item->itemCategory == AVIF_ITEM_GAIN_MAP || !memcmp(item->type, "tmap", 4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be isAlphaOrGainMap |=
, fine as is as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would work but it's not exactly the same thing since |= is a bitwise operator, and won't skip evaluating the right side if the value is already true. Not that I think the performance matters much, but I think it's better to keep |= for actual bitwise operations like flags like we do now.
const int num_cols = (int)cell_rows[0].size(); | ||
AVIF_CHECKRES( | ||
testutil::MergeGrid(num_cols, num_rows, cell_images, grid.get())); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rows below should be removed now that there is testutil::MergeGrid()
Note: testutil::MergeGrid()
could be made in another PR to reduce the size of this one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed I forgot to remove them, thanks for spotting it.
I agree it could be split... but I'm afraid of spending a while fighting with git and merges again... So if it's not a strong request I'd rather leave it as is.
f02b994
to
2e80228
Compare
Note I rebased this patch but had some issues with the merge and I had to add my latests fixes to the last commit, apologies for the confusing history. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maryla: I only reviewed the public header avif.h. I suggest some changes in anticipation of the libavif 1.0.0 release.
apps/avifenc.c
Outdated
@@ -1945,7 +1945,7 @@ int main(int argc, char * argv[]) | |||
} | |||
} | |||
|
|||
avifIOStats ioStats = { 0, 0, 0 }; | |||
avifIOStats ioStats = { 0, 0 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maryla: It would be good to modify the following code in avifenc.c:
printf("Encoded successfully.\n");
printf(" * Color AV1 total size: %" AVIF_FMT_ZU " bytes\n", ioStats.colorOBUSize);
printf(" * Alpha AV1 total size: %" AVIF_FMT_ZU " bytes\n", ioStats.alphaOBUSize);
to also print the gain map AV1 total size, and see if you find it useful to report that information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, there's no way to encode a gain map with avifenc right now, only through the API, so this can be done later I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avif.h LGTM.
The feature is hidden behind the AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP compile flag. See https://helpx.adobe.com/camera-raw/using/gain-map.html for an introduction to gain maps. Note that in this change, gain maps are not stored as auxiliary items as proposed by Adobe, but as a hidden input to a new 'tmap' (tone mapped) derived item. An 'altr' (alternatives group) box is also added to tell the decoder that it may show the tone mapped image (preferrably) or the base image as a fall back. The primary item id still points to the base image for backward compatibility.
Move new fields to the end of structs. Add back accidentally deleted test code. Remove gainMapOBUSize.
0074195
to
072c49a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maryla: Could you add an entry to CHANGELOG.md? Please indicate that this is an experimental feature. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maryla: In this round of review, I only checked whether the pull request is essentially a no-op if the experimental feature is disabled. Unfortunately I didn't make a complete pass through the PR. (I stopped after src/read.c, so I haven't reviewed src/write.c.)
This PR has more code and comments outside #if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
. We should try to move as much code into #if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
as possible. It is more difficult to deal with the comments. I suggested adding "if AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP is defned" to the comments, but that may become a little wordy.
// images containing a gain map encoded with the current version of libavif might | ||
// not decode with a feature future version of libavif. Use are your own risk. | ||
// This is based on ISO/IEC JTC 1/SC 29/WG 3 m64379 | ||
// This product includes Gain Map technology under license by Adobe. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Move this comment block inside #if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
@@ -577,6 +680,7 @@ AVIF_API avifResult avifImageSetMetadataExif(avifImage * image, const uint8_t * | |||
// Sets XMP metadata. | |||
AVIF_API avifResult avifImageSetMetadataXMP(avifImage * image, const uint8_t * xmp, size_t xmpSize); | |||
|
|||
// Allocate/free/steal planes. These functions do not affect the gain map image if present. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit/optional: In these new comments (lines 668, 670, 683), add "if AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP is defined".
@@ -92,6 +93,7 @@ void avifImageCopyNoAlloc(avifImage * dstImage, const avifImage * srcImage); | |||
// Copies the samples from srcImage to dstImage. dstImage must be allocated. | |||
// srcImage and dstImage must have the same width, height, and depth. | |||
// If the AVIF_PLANES_YUV bit is set in planes, then srcImage and dstImage must have the same yuvFormat and yuvRange. | |||
// The gain map (if present) is not affected. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit/optional: Add "if AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP is defined" to this comment.
@@ -681,7 +683,7 @@ typedef struct avifTile | |||
avifCodecDecodeInput * input; | |||
avifCodecType codecType; | |||
// This may point to a codec that it owns or point to a shared codec that it does not own. In the shared case, this will | |||
// point to one of avifDecoderData.codec or avifDecoderData.codecAlpha. | |||
// point to one of avifDecoderData.codec, avifDecoderData.codecAlpha or avifDecoderData.codecGainMap. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Add "if AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP is defined" to this comment.
@@ -815,6 +817,7 @@ typedef struct avifDecoderData | |||
avifTileArray tiles; | |||
avifTileInfo color; | |||
avifTileInfo alpha; | |||
avifTileInfo gainMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Put inside #if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
.
@@ -830,6 +833,7 @@ typedef struct avifDecoderData | |||
// decoder instance (same as above). | |||
avifCodec * codec; | |||
avifCodec * codecAlpha; | |||
avifCodec * codecGainMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Put inside #if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
.
@@ -4025,7 +4246,7 @@ avifResult avifDecoderReset(avifDecoder * decoder) | |||
|
|||
if (tile->input->itemCategory == AVIF_ITEM_ALPHA) { | |||
decoder->ioStats.alphaOBUSize += sample->size; | |||
} else { | |||
} else if (tile->input->itemCategory == AVIF_ITEM_COLOR) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Reorder this in more natural order:
if (tile->input->itemCategory == AVIF_ITEM_COLOR) {
decoder->ioStats.colorOBUSize += sample->size;
} else if (tile->input->itemCategory == AVIF_ITEM_ALPHA) {
decoder->ioStats.alphaOBUSize += sample->size;
}
assert(dstImage); | ||
} | ||
#endif | ||
AVIF_CHECKRES(avifDecoderDataAllocateGridImagePlanes(decoder->data, info, dstImage)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also change decoder->image
to dstImage
below, at line 4495?
} else | ||
#endif | ||
if ((decoder->image->width != src->width) || (decoder->image->height != src->height) || | ||
(decoder->image->depth != src->depth)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nesting of #if
and if
breaks indentation. We should try to restructure this, e.g., as a switch statement:
switch (tile->input->itemCategory) {
#if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
case AVIF_ITEM_GAIN_MAP:
decoder->image->gainMap.image->width = src->width;
decoder->image->gainMap.image->height = src->height;
decoder->image->gainMap.image->depth = src->depth;
break;
#endif
default:
...
break
}
You can experiment with other alternatives.
typedef struct avifEncoderData | ||
{ | ||
avifEncoderItemArray items; | ||
avifEncoderFrameArray frames; | ||
// Map the encoder settings quality and qualityAlpha to quantizer and quantizerAlpha | ||
int quantizer; | ||
int quantizerAlpha; | ||
int quantizerGainMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Put this inside #if defined(AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP)
.
Reverts changes in avifDecoderItemShouldBeSkipped() introduced in AOMediaCodec#1501 The new changes are made in code garded by AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP.
Reverts changes in avifDecoderItemShouldBeSkipped() introduced in AOMediaCodec#1501 The new changes are made in code garded by AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP.
Reverts changes in avifDecoderItemShouldBeSkipped() introduced in #1501 The new changes are made in code guarded by AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP.
And adress some more minor comments from AOMediaCodec#1501.
And adress some more minor comments from AOMediaCodec#1501.
The feature is hidden behind the AVIF_ENABLE_EXPERIMENTAL_GAIN_MAP compile flag.
See https://helpx.adobe.com/camera-raw/using/gain-map.html for an introduction to gain maps. Note that in this change, gain maps are not stored as auxiliary items as proposed by Adobe, but as a hidden input to a new 'tmap' (tone mapped) derived item.
An 'altr' (alternatives group) box is also added to tell the decoder that it may show the tone mapped image (preferrably) or the base image as a fall back. The primary item id still points to the base image for backward compatibility.