955 lines
46 KiB
C
955 lines
46 KiB
C
// Animation Decoder/Encoder Test Suite written by Xen
|
|
|
|
#include <SDL3/SDL.h>
|
|
#include <SDL3/SDL_test.h>
|
|
#include <SDL3_image/SDL_image.h>
|
|
|
|
static bool apply_dummy_metadata;
|
|
|
|
#if defined(SDL_PLATFORM_OS2) || defined(SDL_PLATFORM_WIN32)
|
|
static const char pathsep[] = "\\";
|
|
#elif defined(SDL_PLATFORM_RISCOS)
|
|
static const char pathsep[] = ".";
|
|
#else
|
|
static const char pathsep[] = "/";
|
|
#endif
|
|
|
|
#define MAX_METADATA 6
|
|
|
|
// Add a minimum of two frames so we don't conflict with specific formats (like WEBP).
|
|
#define MIN_FRAMES 2
|
|
|
|
typedef struct {
|
|
int width;
|
|
int height;
|
|
Uint64 duration;
|
|
} FrameData;
|
|
|
|
typedef struct
|
|
{
|
|
const char *metadata;
|
|
const void *value;
|
|
SDL_PropertyType type;
|
|
} MetadataInfo;
|
|
|
|
typedef struct {
|
|
const char* format;
|
|
MetadataInfo availableMetadata[MAX_METADATA];
|
|
} FormatInfo;
|
|
|
|
static const Sint64 default_loop_count = 1;
|
|
#define DEFAULT_TITLE "Lorem ipsum dolor sit amet"
|
|
#define DEFAULT_AUTHOR "consectetur adipiscing elit"
|
|
#define DEFAULT_DESCRIPTION "sed do eiusmod tempor <xml escape test> incididunt ut labore et dolore magna aliqua"
|
|
#define DEFAULT_CREATION_TIME "Ut enim ad minim veniam"
|
|
#define DEFAULT_COPYRIGHT "quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat"
|
|
|
|
static const FormatInfo formatInfo[] = {
|
|
{ "ANI", { { IMG_PROP_METADATA_TITLE_STRING, (const void*)DEFAULT_TITLE, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_AUTHOR_STRING, (const void*)DEFAULT_AUTHOR, SDL_PROPERTY_TYPE_STRING } } },
|
|
|
|
{ "APNG", { { IMG_PROP_METADATA_TITLE_STRING, (const void*)DEFAULT_TITLE, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_AUTHOR_STRING, (const void*)DEFAULT_AUTHOR, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_DESCRIPTION_STRING, (const void*)DEFAULT_DESCRIPTION, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_LOOP_COUNT_NUMBER, (const void *)&default_loop_count, SDL_PROPERTY_TYPE_NUMBER }, { IMG_PROP_METADATA_CREATION_TIME_STRING, (const void*)DEFAULT_CREATION_TIME, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_COPYRIGHT_STRING, (const void*)DEFAULT_COPYRIGHT, SDL_PROPERTY_TYPE_STRING } } },
|
|
|
|
{ "AVIFS", { { IMG_PROP_METADATA_TITLE_STRING, (const void*)DEFAULT_TITLE, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_AUTHOR_STRING, (const void*)DEFAULT_AUTHOR, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_DESCRIPTION_STRING, (const void*)DEFAULT_DESCRIPTION, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_LOOP_COUNT_NUMBER, (const void *)&default_loop_count, SDL_PROPERTY_TYPE_NUMBER }, { IMG_PROP_METADATA_CREATION_TIME_STRING, (const void*)DEFAULT_CREATION_TIME, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_COPYRIGHT_STRING, (const void*)DEFAULT_COPYRIGHT, SDL_PROPERTY_TYPE_STRING } } },
|
|
|
|
{ "GIF", { { IMG_PROP_METADATA_DESCRIPTION_STRING, (const void*)DEFAULT_DESCRIPTION, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_LOOP_COUNT_NUMBER, (const void *)&default_loop_count, SDL_PROPERTY_TYPE_NUMBER } } },
|
|
|
|
{ "WEBP", { { IMG_PROP_METADATA_TITLE_STRING, (const void*)DEFAULT_TITLE, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_AUTHOR_STRING, (const void*)DEFAULT_AUTHOR, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_DESCRIPTION_STRING, (const void*)DEFAULT_DESCRIPTION, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_LOOP_COUNT_NUMBER, (const void *)&default_loop_count, SDL_PROPERTY_TYPE_NUMBER }, { IMG_PROP_METADATA_CREATION_TIME_STRING, (const void*)DEFAULT_CREATION_TIME, SDL_PROPERTY_TYPE_STRING }, { IMG_PROP_METADATA_COPYRIGHT_STRING, (const void*)DEFAULT_COPYRIGHT, SDL_PROPERTY_TYPE_STRING } } },
|
|
};
|
|
|
|
|
|
static const struct {
|
|
const char *format;
|
|
const char *filename;
|
|
} inputImages[] = {
|
|
{ "ANI", "rgbrgb.ani" },
|
|
{ "APNG", "rgbrgb.png" },
|
|
{ "AVIFS", "rgbrgb.avifs" },
|
|
{ "GIF", "rgbrgb.gif" },
|
|
{ "WEBP", "rgbrgb.webp" }
|
|
};
|
|
static const char *outputImageFormats[] = { "ANI", "APNG", "AVIFS", "GIF", "WEBP" };
|
|
|
|
static const char *GetAnimationDecoderStatusString(IMG_AnimationDecoderStatus status)
|
|
{
|
|
switch (status) {
|
|
case IMG_DECODER_STATUS_OK:
|
|
return "IMG_DECODER_STATUS_OK";
|
|
case IMG_DECODER_STATUS_COMPLETE:
|
|
return "IMG_DECODER_STATUS_COMPLETE";
|
|
case IMG_DECODER_STATUS_FAILED:
|
|
return "IMG_DECODER_STATUS_FAILED";
|
|
case IMG_DECODER_STATUS_INVALID:
|
|
default:
|
|
return "IMG_DECODER_STATUS_INVALID";
|
|
}
|
|
}
|
|
|
|
static bool FormatAnimationEnabled(const char *format)
|
|
{
|
|
char env_name[64];
|
|
SDL_snprintf(env_name, sizeof(env_name), "SDL_IMAGE_ANIM_%s", format);
|
|
SDL_strupr(env_name);
|
|
const char *env_value = SDL_getenv(env_name);
|
|
if (!env_value) {
|
|
return true;
|
|
}
|
|
if (env_value[0] == '\0' || SDL_strcmp(env_value, "0") == 0 || SDL_strcasecmp(env_value, "no") == 0 || SDL_strcasecmp(env_value, "false") == 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Return the absolute path to a resource file, similar to GLib's
|
|
* g_test_build_filename().
|
|
*
|
|
* If type is TEST_FILE_DIST, look for it in $SDL_TEST_SRCDIR or next
|
|
* to the executable.
|
|
*
|
|
* Fails and returns NULL if out of memory.
|
|
*/
|
|
static char *
|
|
GetTestFilename(const char *file)
|
|
{
|
|
const char *base;
|
|
char *path = NULL;
|
|
bool needPathSep = true;
|
|
|
|
base = SDL_getenv("SDL_TEST_SRCDIR");
|
|
|
|
if (base == NULL) {
|
|
base = SDL_GetBasePath();
|
|
/* SDL_GetBasePath() guarantees a trailing path separator */
|
|
needPathSep = false;
|
|
}
|
|
|
|
if (base != NULL) {
|
|
size_t len = SDL_strlen(base) + SDL_strlen(pathsep) + SDL_strlen(file) + 1;
|
|
|
|
path = SDL_malloc(len);
|
|
if (path == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (needPathSep) {
|
|
SDL_snprintf(path, len, "%s%s%s", base, pathsep, file);
|
|
} else {
|
|
SDL_snprintf(path, len, "%s%s", base, file);
|
|
}
|
|
} else {
|
|
path = SDL_strdup(file);
|
|
if (path == NULL) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
static int SDLCALL testDecodeEncode(void *args) {
|
|
(void) args;
|
|
SDLTest_Log("Starting Animation Decoder/Encoder Tests -- Decode, encode decoded frames then decode again to compare...");
|
|
|
|
SDLTest_Log("--TESTS--");
|
|
for (size_t cim = 0; cim < SDL_arraysize(inputImages); ++cim) {
|
|
for (size_t com = 0; com < SDL_arraysize(outputImageFormats); ++com) {
|
|
const char *inputImage = inputImages[cim].filename;
|
|
const char *outputImageFormat = outputImageFormats[com];
|
|
SDLTest_Log("%s >> %s == %s", inputImage, outputImageFormat, inputImage);
|
|
if (com == 0) {
|
|
SDLTest_Log("--- Rewind Tests for %s ---", inputImage);
|
|
SDLTest_Log("--- Metadata Tests for %s ---", inputImage);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (size_t cim = 0; cim < SDL_arraysize(inputImages); ++cim) {
|
|
for (size_t com = 0; com < SDL_arraysize(outputImageFormats); ++com) {
|
|
const char *inputImage = inputImages[cim].filename;
|
|
const char *outputImageFormat = outputImageFormats[com];
|
|
|
|
if (!FormatAnimationEnabled(inputImages[cim].format)) {
|
|
SDLTest_Log("Animation format %s disabled (input)", inputImages[cim].format);
|
|
continue;
|
|
}
|
|
if (!FormatAnimationEnabled(outputImageFormats[com])) {
|
|
SDLTest_Log("animation format %s disabled (output)", outputImageFormats[com]);
|
|
continue;
|
|
}
|
|
|
|
char *inputImagePath = GetTestFilename(inputImage);
|
|
if (!inputImagePath) {
|
|
SDLTest_LogError("Failed to convert '%s' to absolute path", inputImage);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDLTest_Log("Input Image: %s (%s)", inputImage, inputImagePath);
|
|
SDLTest_Log("Output Format: %s", outputImageFormat);
|
|
|
|
IMG_AnimationDecoder *decoder = IMG_CreateAnimationDecoder(inputImagePath);
|
|
SDL_free(inputImagePath);
|
|
SDLTest_AssertCheck(decoder != NULL, "IMG_CreateAnimationDecoder: Failed to create animation decoder for input image: %s", SDL_GetError());
|
|
if (!decoder) {
|
|
continue;
|
|
}
|
|
SDL_IOStream *encoderIO = SDL_IOFromDynamicMem();
|
|
SDLTest_AssertCheck(encoderIO != NULL, "SDL_IOFromDynamicMem");
|
|
if (!encoderIO) {
|
|
SDLTest_LogError("Failed to create IO stream for output image: %s", SDL_GetError());
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDL_PropertiesID encoderProps = SDL_CreateProperties();
|
|
SDLTest_AssertCheck(encoderProps, "SDL_CreateProperties");
|
|
if (!encoderProps) {
|
|
SDLTest_LogError("Failed to create properties for encoder: %s", SDL_GetError());
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
SDL_CloseIO(encoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
SDL_SetPointerProperty(encoderProps, IMG_PROP_ANIMATION_ENCODER_CREATE_IOSTREAM_POINTER, encoderIO);
|
|
SDL_SetBooleanProperty(encoderProps, IMG_PROP_ANIMATION_ENCODER_CREATE_IOSTREAM_AUTOCLOSE_BOOLEAN,
|
|
false);
|
|
SDL_SetStringProperty(encoderProps, IMG_PROP_ANIMATION_ENCODER_CREATE_TYPE_STRING, outputImageFormat);
|
|
|
|
if (apply_dummy_metadata) {
|
|
SDLTest_Log("Applying dummy metadata...");
|
|
// Most formats hold metadata in the beginning of the file (except WEBP and AVIF since those are EXIF and XMP),
|
|
// when that is the case, the changes to metadata parser can destroy the reading of the frames as well since they
|
|
// might do modifications to the stream. For that reason we add dummy metadata to the encoder properties to make
|
|
// sure that the metadata code does not interfere with the frame reading process.
|
|
for (size_t k = 0; k < SDL_arraysize(formatInfo); ++k) {
|
|
const char *format = formatInfo[k].format;
|
|
for (int mi = 0; mi < MAX_METADATA; ++mi) {
|
|
const MetadataInfo *metadata = &formatInfo[k].availableMetadata[mi];
|
|
if (!metadata || !metadata->metadata || !metadata->value) {
|
|
continue;
|
|
}
|
|
|
|
switch (metadata->type) {
|
|
case SDL_PROPERTY_TYPE_BOOLEAN:
|
|
SDL_SetBooleanProperty(encoderProps, metadata->metadata, *(bool *) metadata->value);
|
|
break;
|
|
case SDL_PROPERTY_TYPE_NUMBER:
|
|
SDL_SetNumberProperty(encoderProps, metadata->metadata, *(Sint64 *) metadata->value);
|
|
break;
|
|
case SDL_PROPERTY_TYPE_STRING:
|
|
SDL_SetStringProperty(encoderProps, metadata->metadata, (const char *)metadata->value);
|
|
break;
|
|
default:
|
|
SDLTest_AssertCheck(false, "ERROR: Unsupported metadata type for %s: %d", format, metadata->type);
|
|
SDL_DestroyProperties(encoderProps);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
SDL_CloseIO(encoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
IMG_AnimationEncoder *encoder = IMG_CreateAnimationEncoderWithProperties(encoderProps);
|
|
SDLTest_AssertCheck(encoder != NULL, "IMG_CreateAnimationEncoderWithProperties");
|
|
SDL_DestroyProperties(encoderProps);
|
|
|
|
int arrayCapacity = 32;
|
|
int arraySize = 0;
|
|
FrameData **decodedFrameData = (FrameData **) SDL_calloc(arrayCapacity, sizeof(*decodedFrameData));
|
|
|
|
if (encoder) {
|
|
Uint64 duration;
|
|
SDL_Surface *frame;
|
|
int i = 0, ii = 0;
|
|
while (IMG_GetAnimationDecoderFrame(decoder, &frame, &duration)) {
|
|
if (frame) {
|
|
SDLTest_Log("Frame Duration (%i): %" SDL_PRIu64 " ms", i, duration);
|
|
SDLTest_Log("Frame Format (%i): %s", i, SDL_GetPixelFormatName(frame->format));
|
|
SDLTest_Log("Frame Size (%i): %ix%i", i, frame->w, frame->h);
|
|
|
|
bool result = IMG_AddAnimationEncoderFrame(encoder, frame, duration);
|
|
SDLTest_AssertCheck(result, "IMG_AddAnimationEncoderFrame");
|
|
|
|
if (result) {
|
|
SDLTest_Log("Frame (%i) added to encoder.", i);
|
|
ii++;
|
|
} else {
|
|
SDLTest_Log("ERROR: Failed to add frame (%i) to encoder: %s", i, SDL_GetError());
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationEncoder(encoder);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
if (arraySize >= arrayCapacity) {
|
|
arrayCapacity *= 2;
|
|
FrameData **temp = (FrameData **) SDL_realloc(decodedFrameData, arrayCapacity *
|
|
sizeof(*decodedFrameData));
|
|
SDLTest_AssertCheck(temp != NULL, "SDL_realloc");
|
|
if (!temp) {
|
|
SDLTest_LogError("ERROR: Failed to reallocate memory for decoded frames.");
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationEncoder(encoder);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
decodedFrameData = temp;
|
|
}
|
|
decodedFrameData[arraySize] = (FrameData *) SDL_calloc(1, sizeof(FrameData));
|
|
SDLTest_AssertCheck(decodedFrameData[arraySize] != NULL, "decodedFrameData[arraySize]");
|
|
if (!decodedFrameData[arraySize]) {
|
|
SDLTest_LogError("ERROR: Failed to allocate memory for frame data.");
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationEncoder(encoder);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
decodedFrameData[arraySize]->width = frame->w;
|
|
decodedFrameData[arraySize]->height = frame->h;
|
|
decodedFrameData[arraySize]->duration = duration;
|
|
arraySize++;
|
|
} else {
|
|
SDLTest_AssertCheck(false, "IMG_GetAnimationDecoderFrame");
|
|
SDLTest_LogError("Failed to get frame: %s", SDL_GetError());
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationEncoder(encoder);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (!IMG_CloseAnimationEncoder(encoder)) {
|
|
SDLTest_AssertCheck(false, "IMG_CloseAnimationEncoder");
|
|
SDLTest_LogError("Failed to close animation encoder: %s", SDL_GetError());
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
SDL_CloseIO(encoderIO);
|
|
return TEST_COMPLETED;
|
|
} else {
|
|
SDLTest_AssertPass("Encoder closed successfully after adding %i frames.", ii);
|
|
}
|
|
|
|
SDLTest_AssertCheck(ii == i, "All frames were added to the encoder. Added %i, Total: %i", ii, i);
|
|
if (ii != i) {
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
SDL_CloseIO(encoderIO);
|
|
return TEST_COMPLETED;
|
|
} else {
|
|
|
|
SDLTest_Log("All frames added to the encoder successfully.");
|
|
SDLTest_Log("Total frames processed: %i", i);
|
|
SDLTest_Log(
|
|
"Loading memory stream for %s back to IMG_AnimationDecoder to see if it results the same as %s",
|
|
outputImageFormat, inputImage);
|
|
|
|
Sint64 newpos = SDL_SeekIO(encoderIO, 0, SDL_IO_SEEK_SET);
|
|
SDLTest_AssertCheck(newpos == 0, "Failed to seek to the beginning of the IO stream: %s",
|
|
SDL_GetError());
|
|
if (newpos != 0) {
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
SDL_CloseIO(encoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
IMG_AnimationDecoder *decoder2 = IMG_CreateAnimationDecoder_IO(encoderIO, false,
|
|
outputImageFormat);
|
|
SDLTest_AssertCheck(decoder2 != NULL, "IMG_CreateAnimationDecoder_IO");
|
|
if (decoder2) {
|
|
bool check_duration = true;
|
|
Uint64 duration2;
|
|
SDL_Surface *frame2;
|
|
int j = 0;
|
|
if (SDL_strcmp(inputImages[cim].format, "ANI") == 0 || SDL_strcmp(outputImageFormat, "ANI") == 0) {
|
|
/* ANI uses 1/60 time units which can't represent our 20 ms sample frame durations.
|
|
* If we switched the sample data to be 100 FPS, that would work for both, but as-is...
|
|
*/
|
|
check_duration = false;
|
|
}
|
|
while (IMG_GetAnimationDecoderFrame(decoder2, &frame2, &duration2)) {
|
|
SDLTest_Log("Reloaded Frame Duration (%i): %" SDL_PRIu64 " ms", j, duration2);
|
|
SDLTest_Log("Reloaded Frame Format (%i): %s", j, SDL_GetPixelFormatName(frame2->format));
|
|
SDLTest_Log("Reloaded Frame Size (%i): %ix%i", j, frame2->w, frame2->h);
|
|
|
|
if (arraySize < j) {
|
|
SDLTest_LogError("Reloaded frame index %i exceeds decoded frame data size %d", j, arraySize);
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationDecoder(decoder2);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
SDL_CloseIO(encoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
if (decodedFrameData[j]->width != frame2->w ||
|
|
decodedFrameData[j]->height != frame2->h ||
|
|
(check_duration && decodedFrameData[j]->duration != duration2)) {
|
|
SDLTest_LogError("Frame data mismatch at index %i. Expected (%i, %i, %" SDL_PRIu64 "), Got (%i, %i, %" SDL_PRIu64 ")",
|
|
j, decodedFrameData[j]->width, decodedFrameData[j]->height, decodedFrameData[j]->duration, frame2->w, frame2->h, duration2);
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationDecoder(decoder2);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
SDL_CloseIO(encoderIO);
|
|
return TEST_ABORTED;
|
|
} else {
|
|
SDLTest_Log("Reloaded frame matches original frame data at index %i.", j);
|
|
}
|
|
|
|
j++;
|
|
}
|
|
|
|
if (j != i) {
|
|
SDLTest_LogError("Frame count mismatch after reloading output. Expected %i, Got %i", i, j);
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationDecoder(decoder2);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
SDL_CloseIO(encoderIO);
|
|
return TEST_ABORTED;
|
|
} else {
|
|
SDLTest_Log("All frames reloaded successfully from memory stream for %s with frame count %i.",
|
|
outputImageFormat, j);
|
|
}
|
|
|
|
IMG_CloseAnimationDecoder(decoder2);
|
|
} else {
|
|
SDLTest_LogError("Failed to create animation decoder for output image: %s",
|
|
SDL_GetError());
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
SDL_CloseIO(encoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
}
|
|
|
|
SDL_CloseIO(encoderIO);
|
|
} else {
|
|
SDLTest_LogError("Failed to create animation encoder for output format %s: %s", outputImageFormat, SDL_GetError());
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
for (int ai = 0; ai < arraySize; ++ai) {
|
|
SDL_free(decodedFrameData[ai]);
|
|
}
|
|
SDL_free(decodedFrameData);
|
|
|
|
IMG_CloseAnimationDecoder(decoder);
|
|
}
|
|
}
|
|
|
|
SDLTest_Log("Finished test 'Starting Animation Decoder/Encoder Tests'.");
|
|
return TEST_COMPLETED;
|
|
}
|
|
|
|
static int SDLCALL testDecoderRewind(void *args)
|
|
{
|
|
(void)args;
|
|
SDLTest_Log("Starting test 'Decoder Rewind Test'");
|
|
|
|
for (size_t cim = 0; cim < SDL_arraysize(outputImageFormats); ++cim) {
|
|
|
|
const char *outputImageFormat = outputImageFormats[cim];
|
|
if (!FormatAnimationEnabled(outputImageFormats[cim])) {
|
|
SDLTest_Log("animation format %s disabled (output)", outputImageFormats[cim]);
|
|
continue;
|
|
}
|
|
|
|
SDL_IOStream *rewindEncoderIO = SDL_IOFromDynamicMem();
|
|
SDLTest_AssertCheck(rewindEncoderIO != NULL, "SDL_IOFromDynamicMem");
|
|
if (!rewindEncoderIO) {
|
|
SDLTest_LogError("Failed to create IO stream for frame encoder: %s", SDL_GetError());
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
IMG_AnimationEncoder *encoder = IMG_CreateAnimationEncoder_IO(rewindEncoderIO, false, outputImageFormat);
|
|
if (!encoder) {
|
|
SDLTest_LogError("Failed to create animation encoder for output format %s: %s", outputImageFormat, SDL_GetError());
|
|
SDL_CloseIO(rewindEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
// We have to create different colors for each frame to ensure they are distinguishable. Otherwise, some formats like WEBP truncates identical repeating frames.
|
|
for (int fi = 0; fi < MIN_FRAMES; ++fi) {
|
|
SDL_Surface *frame = SDL_CreateSurface(256, 256, SDL_PIXELFORMAT_RGBA32);
|
|
SDLTest_AssertCheck(frame != NULL, "SDL_CreateSurface");
|
|
if (!frame) {
|
|
SDLTest_LogError("Failed to create surface for frame: %s", SDL_GetError());
|
|
IMG_CloseAnimationEncoder(encoder);
|
|
SDL_CloseIO(rewindEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
const SDL_PixelFormatDetails *pixelFormatDetails = SDL_GetPixelFormatDetails(frame->format);
|
|
bool result = SDL_FillSurfaceRect(frame, NULL, SDL_MapRGBA(pixelFormatDetails, NULL, (Uint8)SDL_rand(256), (Uint8)SDL_rand(256), (Uint8)SDL_rand(256), 255));
|
|
SDLTest_AssertCheck(result, "SDL_FillSurfaceRect: Failed to fill surface with red color: %s", SDL_GetError());
|
|
|
|
result = IMG_AddAnimationEncoderFrame(encoder, frame, 1000);
|
|
SDLTest_AssertCheck(result, "IMG_AddAnimationEncoderFrame");
|
|
if (result) {
|
|
SDLTest_Log("Frame %i added to encoder successfully.", fi);
|
|
SDL_DestroySurface(frame);
|
|
} else {
|
|
SDLTest_LogError("Failed to add frame to encoder: %sn", SDL_GetError());
|
|
SDL_DestroySurface(frame);
|
|
IMG_CloseAnimationEncoder(encoder);
|
|
SDL_CloseIO(rewindEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
}
|
|
|
|
if (!IMG_CloseAnimationEncoder(encoder)) {
|
|
SDLTest_LogError("Failed to close animation encoder for frame: %s", SDL_GetError());
|
|
SDL_CloseIO(rewindEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
SDLTest_Log("Frames encoded successfully for output format %s.", outputImageFormat);
|
|
if (SDL_SeekIO(rewindEncoderIO, 0, SDL_IO_SEEK_SET) != 0) {
|
|
SDLTest_AssertCheck(false, "SDL_SeekIO");
|
|
SDLTest_LogError("Failed to seek to the beginning of the IO stream for frame encoder: %s", SDL_GetError());
|
|
SDL_CloseIO(rewindEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
IMG_AnimationDecoder *rewindDecoder = IMG_CreateAnimationDecoder_IO(rewindEncoderIO, false, outputImageFormat);
|
|
if (rewindDecoder) {
|
|
SDLTest_Log("Rewind decoder created successfully for output format %s.", outputImageFormat);
|
|
SDLTest_Log("Decoding %i frames first.", MIN_FRAMES);
|
|
for (int ri = 0; ri < MIN_FRAMES; ++ri) {
|
|
if (!IMG_GetAnimationDecoderFrame(rewindDecoder, NULL, NULL)) {
|
|
SDLTest_AssertCheck(false, "IMG_GetAnimationDecoderFrame");
|
|
SDLTest_LogError("Failed to get frame %i from rewind decoder. status: %s --- SDL Error: %s", ri, GetAnimationDecoderStatusString(IMG_GetAnimationDecoderStatus(rewindDecoder)), SDL_GetError());
|
|
IMG_CloseAnimationDecoder(rewindDecoder);
|
|
SDL_CloseIO(rewindEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
}
|
|
|
|
SDLTest_Log("Now resetting the animation decoder...");
|
|
|
|
if (!IMG_ResetAnimationDecoder(rewindDecoder)) {
|
|
SDLTest_AssertCheck(false, "IMG_ResetAnimationDecoder");
|
|
SDLTest_LogError("Failed to reset rewind decoder: %s", SDL_GetError());
|
|
IMG_CloseAnimationDecoder(rewindDecoder);
|
|
SDL_CloseIO(rewindEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDLTest_Log("Decoding %i frames again after reset.", MIN_FRAMES);
|
|
|
|
for (int ri = 0; ri < MIN_FRAMES; ++ri) {
|
|
if (!IMG_GetAnimationDecoderFrame(rewindDecoder, NULL, NULL)) {
|
|
SDLTest_AssertCheck(false, "IMG_GetAnimationDecoderFrame");
|
|
SDLTest_LogError("Failed to get frame %i from rewind decoder. status: %s --- SDL Error: %s", ri, GetAnimationDecoderStatusString(IMG_GetAnimationDecoderStatus(rewindDecoder)), SDL_GetError());
|
|
IMG_CloseAnimationDecoder(rewindDecoder);
|
|
SDL_CloseIO(rewindEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
}
|
|
} else {
|
|
SDLTest_AssertCheck(false, "IMG_CreateAnimationDecoder_IO");
|
|
SDLTest_LogError("Failed to create rewind decoder for input image: %s", SDL_GetError());
|
|
SDL_CloseIO(rewindEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDL_CloseIO(rewindEncoderIO);
|
|
SDLTest_Log("Finished rewind test for output format %s.", outputImageFormat);
|
|
}
|
|
|
|
SDLTest_Log("Finished test 'Decoder Rewind Test'.");
|
|
return TEST_COMPLETED;
|
|
}
|
|
|
|
static int SDLCALL testEncodeDecodeMetadata(void *args) {
|
|
(void)args;
|
|
SDLTest_Log("=========================================================");
|
|
SDLTest_Log("=========================================================");
|
|
SDLTest_Log("Starting test 'Encode Metadata and Decode Metadata Test'");
|
|
|
|
for (size_t k = 0; k < SDL_arraysize(formatInfo); ++k) {
|
|
const char *format = formatInfo[k].format;
|
|
if (!FormatAnimationEnabled(format)) {
|
|
SDLTest_Log("animation format %s disabled", format);
|
|
continue;
|
|
}
|
|
SDLTest_Log("Testing format: %s", format);
|
|
SDL_IOStream *metadataEncoderIO = SDL_IOFromDynamicMem();
|
|
SDLTest_AssertCheck(metadataEncoderIO != NULL, "SDL_IOFromDynamicMem");
|
|
if (!metadataEncoderIO) {
|
|
SDLTest_LogError("Failed to create IO stream for metadata encoder: %s", SDL_GetError());
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDL_PropertiesID metadataProps = SDL_CreateProperties();
|
|
SDLTest_AssertCheck(metadataProps != 0, "SDL_CreateProperties");
|
|
if (!metadataProps) {
|
|
SDLTest_LogError("Failed to create properties for metadata encoder: %s", SDL_GetError());
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
for (int mi = 0; mi < MAX_METADATA; ++mi) {
|
|
const MetadataInfo *metadata = &formatInfo[k].availableMetadata[mi];
|
|
if (!metadata || !metadata->metadata || !metadata->value) {
|
|
continue;
|
|
}
|
|
|
|
switch (metadata->type) {
|
|
case SDL_PROPERTY_TYPE_BOOLEAN:
|
|
SDL_SetBooleanProperty(metadataProps, metadata->metadata, *(bool *) metadata->value);
|
|
break;
|
|
case SDL_PROPERTY_TYPE_NUMBER:
|
|
SDL_SetNumberProperty(metadataProps, metadata->metadata, *(Sint64 *) metadata->value);
|
|
break;
|
|
case SDL_PROPERTY_TYPE_STRING:
|
|
SDL_SetStringProperty(metadataProps, metadata->metadata, (const char *) metadata->value);
|
|
break;
|
|
default:
|
|
SDLTest_AssertCheck(false, "Unsupported metadata type for %s: %d", metadata->metadata,
|
|
metadata->type);
|
|
SDL_DestroyProperties(metadataProps);
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
}
|
|
|
|
SDL_SetStringProperty(metadataProps, IMG_PROP_ANIMATION_ENCODER_CREATE_TYPE_STRING, format);
|
|
SDL_SetPointerProperty(metadataProps, IMG_PROP_ANIMATION_ENCODER_CREATE_IOSTREAM_POINTER, metadataEncoderIO);
|
|
SDL_SetBooleanProperty(metadataProps, IMG_PROP_ANIMATION_ENCODER_CREATE_IOSTREAM_AUTOCLOSE_BOOLEAN, false);
|
|
|
|
IMG_AnimationEncoder *metadataEncoder = IMG_CreateAnimationEncoderWithProperties(metadataProps);
|
|
SDLTest_AssertCheck(metadataEncoder != NULL, "IMG_CreateAnimationEncoderWithProperties");
|
|
if (!metadataEncoder) {
|
|
SDLTest_LogError("Failed to create animation encoder for format %s: %s", format, SDL_GetError());
|
|
SDL_DestroyProperties(metadataProps);
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDL_DestroyProperties(metadataProps);
|
|
|
|
for (int fi = 0; fi < MIN_FRAMES; ++fi) {
|
|
SDL_Surface *metadataFrame = SDL_CreateSurface(256, 256, SDL_PIXELFORMAT_RGBA32);
|
|
SDLTest_AssertCheck(metadataFrame != NULL, "SDL_CreateSurface");
|
|
if (!metadataFrame) {
|
|
SDLTest_LogError("Failed to create surface for metadata frame: %s", SDL_GetError());
|
|
IMG_CloseAnimationEncoder(metadataEncoder);
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
const SDL_PixelFormatDetails *metadataPixelFormatDetails = SDL_GetPixelFormatDetails(metadataFrame->format);
|
|
bool result = SDL_FillSurfaceRect(metadataFrame, NULL,
|
|
SDL_MapRGBA(metadataPixelFormatDetails, NULL, (Uint8) SDL_rand(256),
|
|
(Uint8) SDL_rand(256), (Uint8) SDL_rand(256), 255));
|
|
SDLTest_AssertCheck(result, "SDL_FillSurfaceRect");
|
|
if (!result) {
|
|
SDLTest_LogError("Failed to fill surface with green color for metadata frame: %s", SDL_GetError());
|
|
SDL_DestroySurface(metadataFrame);
|
|
IMG_CloseAnimationEncoder(metadataEncoder);
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
if (IMG_AddAnimationEncoderFrame(metadataEncoder, metadataFrame, 1000)) {
|
|
SDLTest_Log("Metadata frame added to encoder successfully.");
|
|
SDL_DestroySurface(metadataFrame);
|
|
} else {
|
|
SDLTest_LogError("Failed to add metadata frame to encoder: %s", SDL_GetError());
|
|
SDL_DestroySurface(metadataFrame);
|
|
IMG_CloseAnimationEncoder(metadataEncoder);
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
}
|
|
|
|
bool result = IMG_CloseAnimationEncoder(metadataEncoder);
|
|
SDLTest_AssertCheck(result, "IMG_CloseAnimationEncoder");
|
|
if (!result) {
|
|
SDLTest_LogError("Failed to close animation encoder for format %s: %s", format, SDL_GetError());
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDLTest_Log("Metadata frame encoded successfully for format %s.", format);
|
|
if (SDL_SeekIO(metadataEncoderIO, 0, SDL_IO_SEEK_SET) != 0) {
|
|
SDLTest_AssertCheck(false, "SDL_SeekIO");
|
|
SDLTest_LogError("Failed to seek to the beginning of the IO stream for metadata encoder: %s",
|
|
SDL_GetError());
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
IMG_AnimationDecoder *metadataDecoder = IMG_CreateAnimationDecoder_IO(metadataEncoderIO, false, format);
|
|
SDLTest_AssertCheck(metadataDecoder != NULL, "IMG_CreateAnimationDecoder_IO");
|
|
if (metadataDecoder) {
|
|
SDL_PropertiesID decodedProps = IMG_GetAnimationDecoderProperties(metadataDecoder);
|
|
SDLTest_AssertCheck(decodedProps != 0, "IMG_GetAnimationDecoderProperties");
|
|
if (!decodedProps) {
|
|
SDLTest_LogError("Failed to get properties from metadata decoder: %s", SDL_GetError());
|
|
IMG_CloseAnimationDecoder(metadataDecoder);
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
for (int i = 0; i < MAX_METADATA; ++i) {
|
|
const MetadataInfo *metadata = &formatInfo[k].availableMetadata[i];
|
|
if (!metadata || !metadata->metadata || !metadata->value) {
|
|
continue;
|
|
}
|
|
|
|
const char *propName = metadata->metadata;
|
|
if (metadata->type == SDL_PROPERTY_TYPE_BOOLEAN) {
|
|
bool propValue = SDL_GetBooleanProperty(decodedProps, propName, false);
|
|
SDLTest_Log("Decoded Property %s: %s", propName, propValue ? "true" : "false");
|
|
const bool expectedValue = *(const bool *) metadata->value;
|
|
SDLTest_AssertCheck(propValue == expectedValue,
|
|
"Decoded boolean property %s should match expected value. Expected: %s, Got: %s",
|
|
propName, expectedValue ? "true" : "false", propValue ? "true" : "false");
|
|
if (propValue != expectedValue) {
|
|
IMG_CloseAnimationDecoder(metadataDecoder);
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
} else if (metadata->type == SDL_PROPERTY_TYPE_NUMBER) {
|
|
Sint64 propValue = SDL_GetNumberProperty(decodedProps, propName, 0);
|
|
SDLTest_Log("Decoded Property %s: %" SDL_PRIs64 "", propName, propValue);
|
|
const Sint64 expectedValue = *(const Sint64 *) metadata->value;
|
|
SDLTest_AssertCheck(propValue == expectedValue,
|
|
"Decoded number property %s should match expected value. Expected: %" SDL_PRIs64 ", Got: %" SDL_PRIs64 "",
|
|
propName, expectedValue, propValue);
|
|
if (propValue != expectedValue) {
|
|
IMG_CloseAnimationDecoder(metadataDecoder);
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
} else if (metadata->type == SDL_PROPERTY_TYPE_STRING) {
|
|
const char *propValue = SDL_GetStringProperty(decodedProps, propName, NULL);
|
|
SDLTest_Log("Decoded Property %s: %s", propName, propValue ? propValue : "NULL");
|
|
const char *expectedValue = (const char *) metadata->value;
|
|
if (propValue == NULL && expectedValue == NULL) {
|
|
SDLTest_Log("Both decoded and expected string properties are NULL for %s.", propName);
|
|
} else if (propValue == NULL || expectedValue == NULL ||
|
|
SDL_strcmp(propValue, expectedValue) != 0) {
|
|
SDLTest_AssertCheck(false,
|
|
"Decoded string property %s does not match expected value. Expected: %s, Got: %s",
|
|
propName, expectedValue ? expectedValue : "NULL",
|
|
propValue ? propValue : "NULL");
|
|
IMG_CloseAnimationDecoder(metadataDecoder);
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
} else {
|
|
SDLTest_LogError("Unsupported metadata type for %s: %d", propName, metadata->type);
|
|
IMG_CloseAnimationDecoder(metadataDecoder);
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
return TEST_ABORTED;
|
|
}
|
|
}
|
|
IMG_CloseAnimationDecoder(metadataDecoder);
|
|
} else {
|
|
SDLTest_AssertCheck(false, "Failed to create animation decoder for format %s: %s", format, SDL_GetError());
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
SDL_Quit();
|
|
return TEST_ABORTED;
|
|
}
|
|
SDL_CloseIO(metadataEncoderIO);
|
|
SDLTest_Log("Finished metadata encoding and decoding test for format %s.", format);
|
|
}
|
|
SDLTest_Log("Finished test 'Encode Metadata and Decode Metadata Test'.");
|
|
return TEST_COMPLETED;
|
|
}
|
|
|
|
static int SDLCALL testDecodeThirdPartyMetadata(void *args)
|
|
{
|
|
(void)args;
|
|
SDLTest_Log("Starting test 'Decode Third Party Metadata Test'");
|
|
|
|
if (!FormatAnimationEnabled("webp")) {
|
|
SDLTest_Log("Animation format webp disabled, skipping test");
|
|
return TEST_SKIPPED;
|
|
}
|
|
|
|
const char *inputImage = "rgbrgb_thirdpartymetadata.webp";
|
|
char *inputImagePath = GetTestFilename(inputImage);
|
|
if (!inputImagePath) {
|
|
SDLTest_LogError("Failed to convert '%s' to absolute path", inputImage);
|
|
return TEST_ABORTED;
|
|
}
|
|
IMG_AnimationDecoder *thirdPartyDecoder = IMG_CreateAnimationDecoder(inputImagePath);
|
|
SDLTest_AssertCheck(thirdPartyDecoder != NULL, "IMG_CreateAnimationDecoder");
|
|
SDL_free(inputImagePath);
|
|
if (thirdPartyDecoder) {
|
|
SDL_PropertiesID thirdPartyMetadata = IMG_GetAnimationDecoderProperties(thirdPartyDecoder);
|
|
SDLTest_AssertCheck(thirdPartyMetadata != 0, "IMG_GetAnimationDecoderProperties");
|
|
if (!thirdPartyMetadata) {
|
|
SDLTest_LogError("Failed to get properties from third party metadata decoder: %s", SDL_GetError());
|
|
IMG_CloseAnimationDecoder(thirdPartyDecoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
const char *xmpDesc = SDL_GetStringProperty(thirdPartyMetadata, IMG_PROP_METADATA_DESCRIPTION_STRING, NULL);
|
|
const char *xmpRights = SDL_GetStringProperty(thirdPartyMetadata, IMG_PROP_METADATA_COPYRIGHT_STRING, NULL);
|
|
|
|
// Both of them have to be valid.
|
|
SDLTest_AssertCheck(xmpDesc != NULL && xmpRights != NULL, "Failed to get XMP Description or Rights from third party metadata decoder. Description: %s, Rights: %s",
|
|
xmpDesc ? xmpDesc : "NULL", xmpRights ? xmpRights : "NULL");
|
|
if (!xmpDesc || !xmpRights) {
|
|
IMG_CloseAnimationDecoder(thirdPartyDecoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
size_t descLen = SDL_strnlen(xmpDesc, 256);
|
|
size_t rightsLen = SDL_strnlen(xmpRights, 256);
|
|
|
|
SDLTest_AssertCheck(descLen == 18, "XMP Description length mismatch. Expected: 18, Got: %" SDL_PRIu64, (Uint64)descLen);
|
|
if (descLen != 18) {
|
|
IMG_CloseAnimationDecoder(thirdPartyDecoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDLTest_AssertCheck(rightsLen == 16, "XMP Rights length mismatch. Expected: 16, Got: %" SDL_PRIu64, (Uint64)rightsLen);
|
|
if (rightsLen != 16) {
|
|
IMG_CloseAnimationDecoder(thirdPartyDecoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDLTest_AssertCheck(SDL_strncmp(xmpDesc, "Test <Description>", 18) == 0, "XMP Description content mismatch. Expected: 'Test <Description>', Got: '%s'", xmpDesc);
|
|
if (SDL_strncmp(xmpDesc, "Test <Description>", 18) != 0) {
|
|
IMG_CloseAnimationDecoder(thirdPartyDecoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDLTest_AssertCheck(SDL_strncmp(xmpRights, "Test <Copyright>", 16) == 0, "XMP Rights content mismatch. Expected: 'Test <Copyright>', Got: '%s'", xmpRights);
|
|
if (SDL_strncmp(xmpRights, "Test <Copyright>", 16) != 0) {
|
|
IMG_CloseAnimationDecoder(thirdPartyDecoder);
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDLTest_Log("Third party metadata decoded successfully. Description: '%s', Rights: '%s'", xmpDesc, xmpRights);
|
|
IMG_CloseAnimationDecoder(thirdPartyDecoder);
|
|
} else {
|
|
SDLTest_LogError("Failed to create animation decoder for third party metadata test image: %s", SDL_GetError());
|
|
return TEST_ABORTED;
|
|
}
|
|
|
|
SDLTest_Log("Finished test 'Decode Third Party Metadata Test'.");
|
|
return TEST_COMPLETED;
|
|
}
|
|
|
|
static const SDLTest_TestCaseReference decodeEncodeAnimations = {
|
|
testDecodeEncode, "decode_encode_animation", "Animation Decoder/Encoder Tests -- Decode, encode decoded frames then decode again to compare...", TEST_ENABLED
|
|
};
|
|
|
|
static const SDLTest_TestCaseReference decoderRewindAnimations = {
|
|
testDecoderRewind, "decoder_rewind", "Rewind Animatino decoder", TEST_ENABLED
|
|
};
|
|
|
|
static const SDLTest_TestCaseReference animationMetadata = {
|
|
testEncodeDecodeMetadata, "animation_metadata", "Encode Metadata and Decode Metadata", TEST_ENABLED
|
|
};
|
|
|
|
static const SDLTest_TestCaseReference decodeThirdPartyMetadata = {
|
|
testDecodeThirdPartyMetadata, "animation_decodeThirdPartyMetadata", "Decode Third Party Metadata", TEST_ENABLED
|
|
};
|
|
|
|
static const SDLTest_TestCaseReference *animationTests[] = {
|
|
&decodeEncodeAnimations,
|
|
&decoderRewindAnimations,
|
|
&animationMetadata,
|
|
&decodeThirdPartyMetadata,
|
|
NULL
|
|
};
|
|
|
|
static SDLTest_TestSuiteReference animationTestSuite = {
|
|
"animation",
|
|
NULL,
|
|
animationTests,
|
|
NULL
|
|
};
|
|
|
|
static SDLTest_TestSuiteReference *testSuites[] = {
|
|
&animationTestSuite,
|
|
NULL
|
|
};
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int result;
|
|
SDLTest_CommonState *state;
|
|
SDLTest_TestSuiteRunner *runner;
|
|
|
|
/* Initialize test framework */
|
|
state = SDLTest_CommonCreateState(argv, 0);
|
|
if (!state) {
|
|
return 1;
|
|
}
|
|
|
|
runner = SDLTest_CreateTestSuiteRunner(state, testSuites);
|
|
|
|
/* Parse commandline */
|
|
for (int i = 1; i < argc;) {
|
|
int consumed;
|
|
|
|
consumed = SDLTest_CommonArg(state, i);
|
|
if (!consumed) {
|
|
if (SDL_strcmp(argv[i], "--no-dummy-metadata") == 0) {
|
|
apply_dummy_metadata = false;
|
|
consumed = 1;
|
|
}
|
|
}
|
|
if (consumed <= 0) {
|
|
const char *options[] = {
|
|
"[--no-dummy-metadata]",
|
|
NULL
|
|
};
|
|
SDLTest_CommonLogUsage(state, argv[0], options);
|
|
return 1;
|
|
}
|
|
|
|
i += consumed;
|
|
}
|
|
|
|
SDL_Log(" SDL version: %i.%i.%i", SDL_VERSIONNUM_MAJOR(SDL_GetVersion()), SDL_VERSIONNUM_MINOR(SDL_GetVersion()), SDL_VERSIONNUM_MICRO(SDL_GetVersion()));
|
|
SDL_Log("SDL_image version: %i.%i.%i", SDL_VERSIONNUM_MAJOR(IMG_Version()), SDL_VERSIONNUM_MINOR(IMG_Version()), SDL_VERSIONNUM_MICRO(IMG_Version()));
|
|
|
|
result = SDLTest_ExecuteTestSuiteRunner(runner);
|
|
|
|
SDL_Quit();
|
|
SDLTest_DestroyTestSuiteRunner(runner);
|
|
SDLTest_CommonDestroyState(state);
|
|
return result;
|
|
}
|