Switch from "skip" (index-based) lsel implementation to spatial_id matching
diff --git a/include/avif/internal.h b/include/avif/internal.h
index 3515b41..93a4d8e 100644
--- a/include/avif/internal.h
+++ b/include/avif/internal.h
@@ -164,19 +164,21 @@
// ---------------------------------------------------------------------------
// avifCodecDecodeInput
+// Legal spatial_id values are [0,1,2,3], so this serves as a sentinel value for "do not filter by spatial_id"
+#define AVIF_SPATIAL_ID_UNSET 0xff
+
typedef struct avifDecodeSample
{
avifROData data;
avifBool ownsData;
avifBool partialData; // if true, data exists but doesn't have all of the sample in it
- uint32_t itemID; // if non-zero, data comes from a mergedExtents buffer in an avifDecoderItem, not a file offset
- uint64_t offset; // additional offset into data. Can be used to offset into an itemID's payload as well.
- size_t size; //
- uint8_t skip; // After feeding this sample, this is how many frames must be skipped before returning a frame
- // This is used in layer selection, as layer selection requires that decoders decode all
- // layers sequentially, but only a specific layer index is actually wanted.
- avifBool sync; // is sync sample (keyframe)
+ uint32_t itemID; // if non-zero, data comes from a mergedExtents buffer in an avifDecoderItem, not a file offset
+ uint64_t offset; // additional offset into data. Can be used to offset into an itemID's payload as well.
+ size_t size; //
+ uint8_t spatialID; // If set to a value other than AVIF_SPATIAL_ID_UNSET, the output frame's spatial_id must match
+ // this ID, otherwise output frames from this sample should be skipped until it does.
+ avifBool sync; // is sync sample (keyframe)
} avifDecodeSample;
AVIF_ARRAY_DECLARE(avifDecodeSampleArray, avifDecodeSample, sample);
diff --git a/src/codec_aom.c b/src/codec_aom.c
index 8c7a7e8..fc34a83 100644
--- a/src/codec_aom.c
+++ b/src/codec_aom.c
@@ -114,13 +114,15 @@
codec->internal->iter = NULL;
}
- uint8_t skipRemaining = sample->skip;
aom_image_t * nextFrame = NULL;
for (;;) {
nextFrame = aom_codec_get_frame(&codec->internal->decoder, &codec->internal->iter);
if (nextFrame) {
- if (skipRemaining) {
- --skipRemaining;
+ if (sample->spatialID != AVIF_SPATIAL_ID_UNSET) {
+ if (sample->spatialID == nextFrame->spatial_id) {
+ // Found the correct spatial_id.
+ break;
+ }
} else {
// Got an image!
break;
diff --git a/src/codec_dav1d.c b/src/codec_dav1d.c
index 268e633..b063fb0 100644
--- a/src/codec_dav1d.c
+++ b/src/codec_dav1d.c
@@ -76,7 +76,6 @@
return AVIF_FALSE;
}
- uint8_t skipRemaining = sample->skip;
for (;;) {
if (dav1dData.data) {
int res = dav1d_send_data(codec->internal->dav1dContext, &dav1dData);
@@ -101,10 +100,9 @@
return AVIF_FALSE;
} else {
// Got a picture!
- if (skipRemaining) {
+ if ((sample->spatialID != AVIF_SPATIAL_ID_UNSET) && (sample->spatialID != nextFrame.frame_hdr->spatial_id)) {
// Layer selection: skip this unwanted layer
dav1d_picture_unref(&nextFrame);
- --skipRemaining;
} else {
gotPicture = AVIF_TRUE;
break;
diff --git a/src/codec_libgav1.c b/src/codec_libgav1.c
index 93d7027..de5fa15 100644
--- a/src/codec_libgav1.c
+++ b/src/codec_libgav1.c
@@ -52,14 +52,12 @@
codec->internal->gav1Image = NULL;
const Libgav1DecoderBuffer * nextFrame = NULL;
- uint8_t skipRemaining = sample->skip;
for (;;) {
if (Libgav1DecoderDequeueFrame(codec->internal->gav1Decoder, &nextFrame) != kLibgav1StatusOk) {
return AVIF_FALSE;
}
- if (nextFrame && skipRemaining) {
+ if (nextFrame && (sample->spatialID != AVIF_SPATIAL_ID_UNSET) && (nextFrame->spatial_id != sample->spatialID)) {
nextFrame = NULL;
- --skipRemaining;
} else {
break;
}
diff --git a/src/read.c b/src/read.c
index 70f573e..7be9f1f 100644
--- a/src/read.c
+++ b/src/read.c
@@ -440,8 +440,8 @@
avifDecodeSample * sample = (avifDecodeSample *)avifArrayPushPtr(&decodeInput->samples);
sample->offset = sampleOffset;
sample->size = sampleSize;
- sample->skip = 0; // Never skip frames when decoding tracks (skip is for layer selection)
- sample->sync = AVIF_FALSE; // to potentially be set to true following the outer loop
+ sample->spatialID = AVIF_SPATIAL_ID_UNSET; // Not filtering by spatial_id
+ sample->sync = AVIF_FALSE; // to potentially be set to true following the outer loop
if (sampleSize > UINT64_MAX - sampleOffset) {
avifDiagnosticsPrintf(diag,
@@ -552,7 +552,7 @@
assert(lselProp->u.lsel.layerID < MAX_AV1_LAYER_COUNT);
sample->offset = 0;
sample->size = sampleSize;
- sample->skip = (uint8_t)lselProp->u.lsel.layerID;
+ sample->spatialID = (uint8_t)lselProp->u.lsel.layerID;
sample->sync = AVIF_TRUE;
} else if (allowProgressive && a1lxProp) {
// Progressive image. Decode all layers and expose them all to the user.
@@ -570,7 +570,7 @@
sample->itemID = item->id;
sample->offset = offset;
sample->size = layerSizes[i];
- sample->skip = 0;
+ sample->spatialID = AVIF_SPATIAL_ID_UNSET;
sample->sync = (i == 0); // Assume all layers depend on the first layer
offset += layerSizes[i];
@@ -582,7 +582,7 @@
sample->itemID = item->id;
sample->offset = 0;
sample->size = item->size;
- sample->skip = 0;
+ sample->spatialID = AVIF_SPATIAL_ID_UNSET;
sample->sync = AVIF_TRUE;
}
return AVIF_TRUE;