blob: de8abaece766a44dcc5f2772607ecf1f18538851 [file] [log] [blame]
// Copyright 2022 Google LLC. All rights reserved.
// SPDX-License-Identifier: BSD-2-Clause
#include "aviftest_helpers.h"
#include <algorithm>
#include <cassert>
#include "avif/avif.h"
namespace libavif {
namespace testutil {
namespace {
constexpr int AVIF_CHAN_A = AVIF_CHAN_V + 1;
constexpr int AVIF_CHANS[] = {AVIF_CHAN_Y, AVIF_CHAN_U, AVIF_CHAN_V,
AVIF_CHAN_A};
} // namespace
//------------------------------------------------------------------------------
AvifImagePtr CreateImage(int width, int height, int depth,
avifPixelFormat yuv_format, avifPlanesFlags planes,
avifRange yuv_range) {
AvifImagePtr image(avifImageCreate(width, height, depth, yuv_format),
avifImageDestroy);
if (!image) {
return {nullptr, nullptr};
}
image->yuvRange = yuv_range;
avifImageAllocatePlanes(image.get(), planes);
return image;
}
void FillImagePlain(avifImage* image, const uint32_t yuva[4]) {
avifPixelFormatInfo info;
avifGetPixelFormatInfo(image->yuvFormat, &info);
for (int c : AVIF_CHANS) {
uint8_t* row = (c == AVIF_CHAN_A) ? image->alphaPlane : image->yuvPlanes[c];
if (!row) {
continue;
}
const uint32_t row_bytes =
(c == AVIF_CHAN_A) ? image->alphaRowBytes : image->yuvRowBytes[c];
const uint32_t plane_width =
(c == AVIF_CHAN_Y || c == AVIF_CHAN_A)
? image->width
: ((image->width + info.chromaShiftX) >> info.chromaShiftX);
const uint32_t plane_height =
(c == AVIF_CHAN_Y || c == AVIF_CHAN_A)
? image->height
: ((image->height + info.chromaShiftY) >> info.chromaShiftY);
for (uint32_t y = 0; y < plane_height; ++y) {
if (avifImageUsesU16(image)) {
std::fill(reinterpret_cast<uint16_t*>(row),
reinterpret_cast<uint16_t*>(row) + plane_width,
static_cast<uint16_t>(yuva[c]));
} else {
std::fill(row, row + plane_width, static_cast<uint8_t>(yuva[c]));
}
row += row_bytes;
}
}
}
void FillImageGradient(avifImage* image) {
avifPixelFormatInfo info;
avifGetPixelFormatInfo(image->yuvFormat, &info);
for (int c : AVIF_CHANS) {
uint8_t* row = (c == AVIF_CHAN_A) ? image->alphaPlane : image->yuvPlanes[c];
if (!row) {
continue;
}
const uint32_t row_bytes =
(c == AVIF_CHAN_A) ? image->alphaRowBytes : image->yuvRowBytes[c];
const uint32_t plane_width =
(c == AVIF_CHAN_Y || c == AVIF_CHAN_A)
? image->width
: ((image->width + info.chromaShiftX) >> info.chromaShiftX);
const uint32_t plane_height =
(c == AVIF_CHAN_Y || c == AVIF_CHAN_A)
? image->height
: ((image->height + info.chromaShiftY) >> info.chromaShiftY);
for (uint32_t y = 0; y < plane_height; ++y) {
for (uint32_t x = 0; x < plane_width; ++x) {
const uint32_t value = (x + y) * ((1u << image->depth) - 1u) /
std::max(1u, plane_width + plane_height - 2);
if (avifImageUsesU16(image)) {
reinterpret_cast<uint16_t*>(row)[x] = static_cast<uint16_t>(value);
} else {
row[x] = static_cast<uint8_t>(value);
}
}
row += row_bytes;
}
}
}
//------------------------------------------------------------------------------
// Returns true if image1 and image2 are identical.
bool AreImagesEqual(const avifImage& image1, const avifImage& image2) {
if (image1.width != image2.width || image1.height != image2.height ||
image1.depth != image2.depth || image1.yuvFormat != image2.yuvFormat ||
image1.yuvRange != image2.yuvRange) {
return false;
}
assert(image1.width * image1.height > 0);
avifPixelFormatInfo info;
avifGetPixelFormatInfo(image1.yuvFormat, &info);
for (int c : AVIF_CHANS) {
uint8_t* row1 =
(c == AVIF_CHAN_A) ? image1.alphaPlane : image1.yuvPlanes[c];
uint8_t* row2 =
(c == AVIF_CHAN_A) ? image2.alphaPlane : image2.yuvPlanes[c];
if (!row1 != !row2) {
return false;
}
if (!row1) {
continue;
}
const uint32_t row_bytes1 =
(c == AVIF_CHAN_A) ? image1.alphaRowBytes : image1.yuvRowBytes[c];
const uint32_t row_bytes2 =
(c == AVIF_CHAN_A) ? image2.alphaRowBytes : image2.yuvRowBytes[c];
const uint32_t plane_width =
(c == AVIF_CHAN_Y || c == AVIF_CHAN_A)
? image1.width
: ((image1.width + info.chromaShiftX) >> info.chromaShiftX);
const uint32_t plane_height =
(c == AVIF_CHAN_Y || c == AVIF_CHAN_A)
? image1.height
: ((image1.height + info.chromaShiftY) >> info.chromaShiftY);
for (uint32_t y = 0; y < plane_height; ++y) {
if (avifImageUsesU16(&image1)) {
if (!std::equal(reinterpret_cast<uint16_t*>(row1),
reinterpret_cast<uint16_t*>(row1) + plane_width,
reinterpret_cast<uint16_t*>(row2))) {
return false;
}
} else {
if (!std::equal(row1, row1 + plane_width, row2)) {
return false;
}
}
row1 += row_bytes1;
row2 += row_bytes2;
}
}
return true;
}
//------------------------------------------------------------------------------
} // namespace testutil
} // namespace libavif