forked from AOMediaCodec/libavif
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support custom avifImage properties in avifEncoder (AOMediaCodec#2510)
Add avifImageAddOpaqueProperty() and avifImageAddUUIDProperty(). Check for basic validity of the written properties. Add tests.
- Loading branch information
Showing
13 changed files
with
440 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Copyright 2024 Brad Hards. All rights reserved. | ||
// SPDX-License-Identifier: BSD-2-Clause | ||
|
||
#include "avif/internal.h" | ||
|
||
#include <string.h> | ||
|
||
struct avifKnownProperty | ||
{ | ||
uint8_t fourcc[4]; | ||
}; | ||
|
||
static const struct avifKnownProperty knownProperties[] = { | ||
{ { 'f', 't', 'y', 'p' } }, { { 'u', 'u', 'i', 'd' } }, { { 'm', 'e', 't', 'a' } }, { { 'h', 'd', 'l', 'r' } }, | ||
{ { 'p', 'i', 't', 'm' } }, { { 'd', 'i', 'n', 'f' } }, { { 'd', 'r', 'e', 'f' } }, { { 'i', 'd', 'a', 't' } }, | ||
{ { 'i', 'l', 'o', 'c' } }, { { 'i', 'i', 'n', 'f' } }, { { 'i', 'n', 'f', 'e' } }, { { 'i', 'p', 'r', 'p' } }, | ||
{ { 'i', 'p', 'c', 'o' } }, { { 'a', 'v', '1', 'C' } }, { { 'a', 'v', '2', 'C' } }, { { 'i', 's', 'p', 'e' } }, | ||
{ { 'p', 'i', 'x', 'i' } }, { { 'p', 'a', 's', 'p' } }, { { 'c', 'o', 'l', 'r' } }, { { 'a', 'u', 'x', 'C' } }, | ||
{ { 'c', 'l', 'a', 'p' } }, { { 'i', 'r', 'o', 't' } }, { { 'i', 'm', 'i', 'r' } }, { { 'c', 'l', 'l', 'i' } }, | ||
{ { 'c', 'c', 'l', 'v' } }, { { 'm', 'd', 'c', 'v' } }, { { 'a', 'm', 'v', 'e' } }, { { 'r', 'e', 'v', 'e' } }, | ||
{ { 'n', 'd', 'w', 't' } }, { { 'a', '1', 'o', 'p' } }, { { 'l', 's', 'e', 'l' } }, { { 'a', '1', 'l', 'x' } }, | ||
{ { 'c', 'm', 'i', 'n' } }, { { 'c', 'm', 'e', 'x' } }, { { 'i', 'p', 'm', 'a' } }, { { 'i', 'r', 'e', 'f' } }, | ||
{ { 'a', 'u', 'x', 'l' } }, { { 't', 'h', 'm', 'b' } }, { { 'd', 'i', 'm', 'g' } }, { { 'p', 'r', 'e', 'm' } }, | ||
{ { 'c', 'd', 's', 'c' } }, { { 'g', 'r', 'p', 'l' } }, { { 'a', 'l', 't', 'r' } }, { { 's', 't', 'e', 'r' } }, | ||
{ { 'm', 'd', 'a', 't' } }, | ||
}; | ||
|
||
static const size_t numKnownProperties = sizeof(knownProperties) / sizeof(knownProperties[0]); | ||
|
||
static const size_t FOURCC_BYTES = 4; | ||
static const size_t UUID_BYTES = 16; | ||
|
||
static const uint8_t ISO_UUID_SUFFIX[12] = { 0x00, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9b, 0x71 }; | ||
|
||
avifBool avifIsKnownPropertyType(const uint8_t boxtype[4]) | ||
{ | ||
for (size_t i = 0; i < numKnownProperties; i++) { | ||
if (memcmp(knownProperties[i].fourcc, boxtype, FOURCC_BYTES) == 0) { | ||
return AVIF_TRUE; | ||
} | ||
} | ||
return AVIF_FALSE; | ||
} | ||
|
||
avifBool avifIsValidUUID(const uint8_t uuid[16]) | ||
{ | ||
// This check is to reject encoding a known property via the UUID mechanism | ||
// See ISO/IEC 14496-12 Section 4.2.3 | ||
for (size_t i = 0; i < numKnownProperties; i++) { | ||
if ((memcmp(knownProperties[i].fourcc, uuid, FOURCC_BYTES) == 0) && | ||
(memcmp(ISO_UUID_SUFFIX, uuid + FOURCC_BYTES, UUID_BYTES - FOURCC_BYTES) == 0)) { | ||
return AVIF_FALSE; | ||
} | ||
} | ||
// This check rejects UUIDs with unexpected variant field values, including Nil UUID and Max UUID. | ||
// See RFC 9562 Section 4.1 | ||
uint8_t variant = uuid[8] >> 4; | ||
if ((variant < 0x08) || (variant > 0x0b)) { | ||
return AVIF_FALSE; | ||
} | ||
// This check rejects UUIDs with unexpected version field values. | ||
// See RFC 9562 Section 4.2 | ||
uint8_t version = uuid[6] >> 4; | ||
if ((version < 1) || (version > 8)) { | ||
return AVIF_FALSE; | ||
} | ||
// The rest of a UUID is pretty much a bucket of bits, so assume its OK. | ||
return AVIF_TRUE; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// Copyright 2024 Google LLC | ||
// SPDX-License-Identifier: BSD-2-Clause | ||
|
||
#include <array> | ||
#include <cstdint> | ||
#include <cstring> | ||
#include <memory> | ||
#include <vector> | ||
|
||
#include "avif/avif.h" | ||
#include "avif/internal.h" | ||
#include "avif_fuzztest_helpers.h" | ||
#include "aviftest_helpers.h" | ||
#include "fuzztest/fuzztest.h" | ||
#include "gtest/gtest.h" | ||
|
||
namespace avif { | ||
namespace testutil { | ||
namespace { | ||
|
||
struct TestProp { | ||
std::vector<uint8_t> fourcc; | ||
std::vector<uint8_t> uuid; | ||
std::vector<uint8_t> body; | ||
}; | ||
|
||
static std::vector<uint8_t> UUID_4CC = {'u', 'u', 'i', 'd'}; | ||
|
||
void PropsValid(ImagePtr image, EncoderPtr encoder, DecoderPtr decoder, | ||
std::vector<TestProp> testProps) { | ||
ImagePtr decoded_image(avifImageCreateEmpty()); | ||
ASSERT_NE(image.get(), nullptr); | ||
ASSERT_NE(encoder.get(), nullptr); | ||
ASSERT_NE(decoder.get(), nullptr); | ||
ASSERT_NE(decoded_image.get(), nullptr); | ||
|
||
for (TestProp testProp : testProps) { | ||
if (testProp.fourcc == UUID_4CC) { | ||
ASSERT_EQ( | ||
avifImageAddUUIDProperty(image.get(), testProp.uuid.data(), | ||
testProp.body.data(), testProp.body.size()), | ||
AVIF_RESULT_OK); | ||
} else { | ||
ASSERT_EQ(avifImageAddOpaqueProperty(image.get(), testProp.fourcc.data(), | ||
testProp.body.data(), | ||
testProp.body.size()), | ||
AVIF_RESULT_OK); | ||
} | ||
} | ||
|
||
AvifRwData encoded_data; | ||
const avifResult encoder_result = | ||
avifEncoderWrite(encoder.get(), image.get(), &encoded_data); | ||
ASSERT_EQ(encoder_result, AVIF_RESULT_OK) | ||
<< avifResultToString(encoder_result); | ||
|
||
const avifResult decoder_result = avifDecoderReadMemory( | ||
decoder.get(), decoded_image.get(), encoded_data.data, encoded_data.size); | ||
ASSERT_EQ(decoder_result, AVIF_RESULT_OK) | ||
<< avifResultToString(decoder_result); | ||
|
||
ASSERT_EQ(decoder->image->numProperties, testProps.size()); | ||
for (size_t i = 0; i < testProps.size(); i++) { | ||
TestProp testProp = testProps[i]; | ||
const avifImageItemProperty& decodeProp = decoder->image->properties[i]; | ||
EXPECT_EQ(std::string(decodeProp.boxtype, decodeProp.boxtype + 4), | ||
std::string(testProp.fourcc.data(), testProp.fourcc.data() + 4)); | ||
EXPECT_EQ(std::vector<uint8_t>( | ||
decodeProp.boxPayload.data, | ||
decodeProp.boxPayload.data + decodeProp.boxPayload.size), | ||
testProp.body); | ||
} | ||
} | ||
|
||
inline auto ArbitraryProp() { | ||
auto fourcc = fuzztest::Arbitrary<std::vector<uint8_t>>().WithSize(4); | ||
auto uuid = | ||
fuzztest::Arbitrary<std::vector<uint8_t>>().WithSize(16); // ignored | ||
auto body = fuzztest::Arbitrary<std::vector<uint8_t>>(); | ||
// Don't return known properties. | ||
return fuzztest::Filter( | ||
[](TestProp prop) { | ||
return !avifIsKnownPropertyType(prop.fourcc.data()); | ||
}, | ||
fuzztest::StructOf<TestProp>(fourcc, uuid, body)); | ||
} | ||
|
||
inline auto ArbitraryUUIDProp() { | ||
auto fourcc = fuzztest::Just(UUID_4CC); | ||
auto uuid = fuzztest::Arbitrary<std::vector<uint8_t>>().WithSize(16); | ||
auto body = fuzztest::Arbitrary<std::vector<uint8_t>>(); | ||
// Don't use invalid UUIDs | ||
return fuzztest::Filter( | ||
[](TestProp prop) { return avifIsValidUUID(prop.uuid.data()); }, | ||
fuzztest::StructOf<TestProp>(fourcc, uuid, body)); | ||
} | ||
|
||
inline auto ArbitraryProps() { | ||
return fuzztest::VectorOf( | ||
fuzztest::OneOf(ArbitraryProp(), ArbitraryUUIDProp())); | ||
} | ||
|
||
FUZZ_TEST(PropertiesAvifFuzzTest, PropsValid) | ||
.WithDomains(ArbitraryAvifImage(), ArbitraryAvifEncoder(), | ||
ArbitraryAvifDecoder(), ArbitraryProps()); | ||
|
||
} // namespace | ||
} // namespace testutil | ||
} // namespace avif |
Oops, something went wrong.