Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
YUVTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
11#include "include/core/SkData.h"
15#include "include/core/SkSize.h"
23#include "tests/Test.h"
24#include "tools/Resources.h"
25
26#include <cmath>
27#include <cstdint>
28#include <memory>
29#include <utility>
30
32 const char path[],
33 const SkYUVAInfo* expectedInfo) {
34 std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
35 if (!stream) {
36 return;
37 }
38 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
40 if (!codec) {
41 return;
42 }
43
44 // Test queryYUBAInfo()
45 SkYUVAPixmapInfo yuvaPixmapInfo;
46
47 static constexpr auto kAllTypes = SkYUVAPixmapInfo::SupportedDataTypes::All();
48 static constexpr auto kNoTypes = SkYUVAPixmapInfo::SupportedDataTypes();
49
50 // SkYUVAInfo param is required to be non-null.
51 bool success = codec->queryYUVAInfo(kAllTypes, nullptr);
52 REPORTER_ASSERT(reporter, !success);
53 // Fails when there is no support for YUVA planes.
54 success = codec->queryYUVAInfo(kNoTypes, &yuvaPixmapInfo);
55 REPORTER_ASSERT(reporter, !success);
56
57 success = codec->queryYUVAInfo(kAllTypes, &yuvaPixmapInfo);
58 REPORTER_ASSERT(reporter, SkToBool(expectedInfo) == success);
59 if (!success) {
60 return;
61 }
62 REPORTER_ASSERT(reporter, *expectedInfo == yuvaPixmapInfo.yuvaInfo());
63
64 int numPlanes = yuvaPixmapInfo.numPlanes();
66 for (int i = 0; i < numPlanes; ++i) {
67 const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i);
68 SkColorType planeCT = planeInfo.colorType();
69 REPORTER_ASSERT(reporter, !planeInfo.isEmpty());
71 REPORTER_ASSERT(reporter, planeInfo.validRowBytes(yuvaPixmapInfo.rowBytes(i)));
72 // Currently all planes must share a data type, gettable as SkYUVAPixmapInfo::dataType().
73 auto [numChannels, planeDataType] = SkYUVAPixmapInfo::NumChannelsAndDataType(planeCT);
74 REPORTER_ASSERT(reporter, planeDataType == yuvaPixmapInfo.dataType());
75 }
76 for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) {
77 const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i);
80 REPORTER_ASSERT(reporter, yuvaPixmapInfo.rowBytes(i) == 0);
81 }
82
83 // Allocate the memory for the YUV decode.
84 auto pixmaps = SkYUVAPixmaps::Allocate(yuvaPixmapInfo);
85 REPORTER_ASSERT(reporter, pixmaps.isValid());
86
87 for (int i = 0; i < SkYUVAPixmaps::kMaxPlanes; ++i) {
88 REPORTER_ASSERT(reporter, pixmaps.plane(i).info() == yuvaPixmapInfo.planeInfo(i));
89 }
90 for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) {
91 REPORTER_ASSERT(reporter, pixmaps.plane(i).rowBytes() == 0);
92 }
93
94 // Test getYUVAPlanes()
95 REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->getYUVAPlanes(pixmaps));
96}
97
98DEF_TEST(Jpeg_YUV_Codec, r) {
99 auto setExpectations = [](SkISize dims, SkYUVAInfo::Subsampling subsampling) {
100 return SkYUVAInfo(dims,
102 subsampling,
107 };
108
109 SkYUVAInfo expectations = setExpectations({128, 128}, SkYUVAInfo::Subsampling::k420);
110 codec_yuv(r, "images/color_wheel.jpg", &expectations);
111
112 // H2V2
113 expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k420);
114 codec_yuv(r, "images/mandrill_512_q075.jpg", &expectations);
115
116 // H1V1
117 expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k444);
118 codec_yuv(r, "images/mandrill_h1v1.jpg", &expectations);
119
120 // H2V1
121 expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k422);
122 codec_yuv(r, "images/mandrill_h2v1.jpg", &expectations);
123
124 // Non-power of two dimensions
125 expectations = setExpectations({439, 154}, SkYUVAInfo::Subsampling::k420);
126 codec_yuv(r, "images/cropped_mandrill.jpg", &expectations);
127
128 expectations = setExpectations({8, 8}, SkYUVAInfo::Subsampling::k420);
129 codec_yuv(r, "images/randPixels.jpg", &expectations);
130
131 // Progressive images
132 expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k444);
133 codec_yuv(r, "images/brickwork-texture.jpg", &expectations);
134 codec_yuv(r, "images/brickwork_normal-map.jpg", &expectations);
135
136 // A CMYK encoded image should fail.
137 codec_yuv(r, "images/CMYK.jpg", nullptr);
138 // A grayscale encoded image should fail.
139 codec_yuv(r, "images/grayscale.jpg", nullptr);
140 // A PNG should fail.
141 codec_yuv(r, "images/arrow.png", nullptr);
142}
143
144SkYUVAPixmaps decode_yuva(skiatest::Reporter* r, std::unique_ptr<SkStream> stream) {
145 static constexpr auto kAllTypes = SkYUVAPixmapInfo::SupportedDataTypes::All();
147
148 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
149 REPORTER_ASSERT(r, codec);
150
151 SkYUVAPixmapInfo yuvaPixmapInfo;
152 REPORTER_ASSERT(r, codec->queryYUVAInfo(kAllTypes, &yuvaPixmapInfo));
153 result = SkYUVAPixmaps::Allocate(yuvaPixmapInfo);
154 REPORTER_ASSERT(r, result.isValid());
155 REPORTER_ASSERT(r, SkCodec::kSuccess == codec->getYUVAPlanes(result));
156 return result;
157}
158
160 REPORTER_ASSERT(r, a.yuvaInfo() == b.yuvaInfo());
161 REPORTER_ASSERT(r, a.numPlanes() == b.numPlanes());
162 for (int plane = 0; plane < a.numPlanes(); ++plane) {
163 const SkPixmap& aPlane = a.plane(plane);
164 const SkPixmap& bPlane = b.plane(plane);
165 REPORTER_ASSERT(r, aPlane.computeByteSize() == bPlane.computeByteSize());
166 const uint8_t* aData = reinterpret_cast<const uint8_t*>(aPlane.addr());
167 const uint8_t* bData = reinterpret_cast<const uint8_t*>(bPlane.addr());
168 for (int row = 0; row < aPlane.height(); ++row) {
169 for (int col = 0; col < aPlane.width() * aPlane.info().bytesPerPixel(); ++col) {
170 int32_t aByte = aData[col];
171 int32_t bByte = bData[col];
172 // Allow at most one bit of difference.
173 REPORTER_ASSERT(r, std::abs(aByte - bByte) <= 1);
174 }
175 aData += aPlane.rowBytes();
176 bData += bPlane.rowBytes();
177 }
178 }
179}
180
181DEF_TEST(Jpeg_YUV_Encode, r) {
182 const char* paths[] = {
183 "images/color_wheel.jpg",
184 "images/mandrill_512_q075.jpg",
185 "images/mandrill_h1v1.jpg",
186 "images/mandrill_h2v1.jpg",
187 "images/cropped_mandrill.jpg",
188 "images/randPixels.jpg",
189 };
190 for (const auto* path : paths) {
191 SkYUVAPixmaps decoded;
192 {
193 std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
194 decoded = decode_yuva(r, std::move(stream));
195 }
196
197 SkYUVAPixmaps roundtrip;
198 {
200 SkDynamicMemoryWStream encodeStream;
201 REPORTER_ASSERT(r, SkJpegEncoder::Encode(&encodeStream, decoded, nullptr, options));
202 auto encodedData = encodeStream.detachAsData();
203 roundtrip = decode_yuva(r, SkMemoryStream::Make(encodedData));
204 }
205
206 verify_same(r, decoded, roundtrip);
207 }
208}
209
210// Be sure that the two matrices are inverses of each other
211// (i.e. rgb2yuv and yuv2rgb
213 const SkYUVColorSpace spaces[] = {
219 };
220
221 // Not sure what the theoretical precision we can hope for is, so pick a big value that
222 // passes (when I think we're correct).
223 const float tolerance = 1.0f/(1 << 18);
224
225 for (auto cs : spaces) {
227 y2rm = SkColorMatrix::YUVtoRGB(cs);
228 r2ym.postConcat(y2rm);
229
230 float tmp[20];
231 r2ym.getRowMajor(tmp);
232 for (int i = 0; i < 20; ++i) {
233 float expected = 0;
234 if (i % 6 == 0) { // diagonal
235 expected = 1;
236 }
237 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(tmp[i], expected, tolerance));
238 }
239 }
240}
const char * options
reporter
std::unique_ptr< SkStreamAsset > GetResourceAsStream(const char *resource, bool useFileStream)
Definition Resources.cpp:31
SkColorType
Definition SkColorType.h:19
@ kUnknown_SkColorType
uninitialized
Definition SkColorType.h:20
@ kTopLeft_SkEncodedOrigin
SkYUVColorSpace
Definition SkImageInfo.h:68
@ kBT2020_SkYUVColorSpace
@ kJPEG_SkYUVColorSpace
Definition SkImageInfo.h:98
@ kRec601_SkYUVColorSpace
Definition SkImageInfo.h:99
@ kRec709_SkYUVColorSpace
@ kIdentity_SkYUVColorSpace
maps Y->R, U->G, V->B
Definition SkImageInfo.h:93
@ kJPEG_Full_SkYUVColorSpace
describes full range
Definition SkImageInfo.h:69
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition SkScalar.h:107
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
#define DEF_TEST(name, reporter)
Definition Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
static void codec_yuv(skiatest::Reporter *reporter, const char path[], const SkYUVAInfo *expectedInfo)
Definition YUVTest.cpp:31
static void verify_same(skiatest::Reporter *r, const SkYUVAPixmaps a, const SkYUVAPixmaps &b)
Definition YUVTest.cpp:159
SkYUVAPixmaps decode_yuva(skiatest::Reporter *r, std::unique_ptr< SkStream > stream)
Definition YUVTest.cpp:144
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, SkSpan< const SkCodecs::Decoder > decoders, Result *=nullptr, SkPngChunkReader *=nullptr, SelectionPolicy selectionPolicy=SelectionPolicy::kPreferStillImage)
Definition SkCodec.cpp:163
@ kSuccess
Definition SkCodec.h:80
static SkColorMatrix RGBtoYUV(SkYUVColorSpace)
void postConcat(const SkColorMatrix &mat)
static SkColorMatrix YUVtoRGB(SkYUVColorSpace)
void getRowMajor(float dst[20]) const
sk_sp< SkData > detachAsData()
Definition SkStream.cpp:707
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
Definition SkStream.cpp:314
size_t rowBytes() const
Definition SkPixmap.h:145
int width() const
Definition SkPixmap.h:160
const SkImageInfo & info() const
Definition SkPixmap.h:135
size_t computeByteSize() const
Definition SkPixmap.h:231
const void * addr() const
Definition SkPixmap.h:153
int height() const
Definition SkPixmap.h:166
@ kY_U_V
Plane 0: Y, Plane 1: U, Plane 2: V.
static constexpr int kMaxPlanes
Definition SkYUVAInfo.h:98
@ k420
1 set of UV values for each 2x2 block of Y values.
@ k422
1 set of UV values for each 2x1 block of Y values.
@ k444
No subsampling. UV values for each Y.
static constexpr SupportedDataTypes All()
size_t rowBytes(int i) const
const SkYUVAInfo & yuvaInfo() const
DataType dataType() const
static std::tuple< int, DataType > NumChannelsAndDataType(SkColorType)
int numPlanes() const
const SkImageInfo & planeInfo(int i) const
static SkYUVAPixmaps Allocate(const SkYUVAPixmapInfo &yuvaPixmapInfo)
static constexpr auto kMaxPlanes
static bool b
struct MyStruct a[10]
GAsyncResult * result
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
bool isEmpty() const
Definition SkSize.h:31
bool isEmpty() const
int bytesPerPixel() const
SkISize dimensions() const
SkColorType colorType() const
bool validRowBytes(size_t rowBytes) const