blob: 6c947d9d8df9b11bcdd77ad955ccfeba5c42f03a [file] [log] [blame]
msarett829caa22016-02-11 14:17:17 -08001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/codec/SkCodec.h"
Brian Salomon87d42e52020-08-24 09:18:16 -04009#include "include/core/SkPixmap.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkStream.h"
11#include "include/core/SkYUVASizeInfo.h"
12#include "include/private/SkTemplates.h"
13#include "src/core/SkAutoMalloc.h"
14#include "tests/Test.h"
15#include "tools/Resources.h"
msarett829caa22016-02-11 14:17:17 -080016
msarett829caa22016-02-11 14:17:17 -080017static void codec_yuv(skiatest::Reporter* reporter,
Jim Van Verth8f11e432018-10-18 14:36:59 -040018 const char path[],
Brian Salomon87d42e52020-08-24 09:18:16 -040019 const SkYUVAInfo* expectedInfo) {
Ben Wagner145dbcd2016-11-03 14:40:50 -040020 std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
msarett829caa22016-02-11 14:17:17 -080021 if (!stream) {
msarett829caa22016-02-11 14:17:17 -080022 return;
23 }
Mike Reedede7bac2017-07-23 15:30:02 -040024 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
msarett829caa22016-02-11 14:17:17 -080025 REPORTER_ASSERT(reporter, codec);
26 if (!codec) {
27 return;
28 }
29
Brian Salomon87d42e52020-08-24 09:18:16 -040030 // Test queryYUBAInfo()
Brian Salomonbe0e42c2020-08-27 11:00:04 -040031 SkYUVAPixmapInfo yuvaPixmapInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -040032
Brian Salomon59c60b02020-09-01 15:01:15 -040033 static constexpr auto kAllTypes = SkYUVAPixmapInfo::SupportedDataTypes::All();
34 static constexpr auto kNoTypes = SkYUVAPixmapInfo::SupportedDataTypes();
35
36 // SkYUVAInfo param is required to be non-null.
37 bool success = codec->queryYUVAInfo(kAllTypes, nullptr);
Brian Salomon87d42e52020-08-24 09:18:16 -040038 REPORTER_ASSERT(reporter, !success);
Brian Salomon59c60b02020-09-01 15:01:15 -040039 // Fails when there is no support for YUVA planes.
40 success = codec->queryYUVAInfo(kNoTypes, &yuvaPixmapInfo);
41 REPORTER_ASSERT(reporter, !success);
42
43 success = codec->queryYUVAInfo(kAllTypes, &yuvaPixmapInfo);
Brian Salomon87d42e52020-08-24 09:18:16 -040044 REPORTER_ASSERT(reporter, SkToBool(expectedInfo) == success);
45 if (!success) {
46 return;
47 }
Brian Salomonbe0e42c2020-08-27 11:00:04 -040048 REPORTER_ASSERT(reporter, *expectedInfo == yuvaPixmapInfo.yuvaInfo());
Jim Van Verth8f11e432018-10-18 14:36:59 -040049
Brian Salomonbe0e42c2020-08-27 11:00:04 -040050 int numPlanes = yuvaPixmapInfo.numPlanes();
Brian Salomon87d42e52020-08-24 09:18:16 -040051 REPORTER_ASSERT(reporter, numPlanes <= SkYUVAInfo::kMaxPlanes);
Brian Salomon87d42e52020-08-24 09:18:16 -040052 for (int i = 0; i < numPlanes; ++i) {
Brian Salomonbe0e42c2020-08-27 11:00:04 -040053 const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i);
Brian Salomon59c60b02020-09-01 15:01:15 -040054 SkColorType planeCT = planeInfo.colorType();
Brian Salomonbe0e42c2020-08-27 11:00:04 -040055 REPORTER_ASSERT(reporter, !planeInfo.isEmpty());
Brian Salomon59c60b02020-09-01 15:01:15 -040056 REPORTER_ASSERT(reporter, planeCT != kUnknown_SkColorType);
Brian Salomonbe0e42c2020-08-27 11:00:04 -040057 REPORTER_ASSERT(reporter, planeInfo.validRowBytes(yuvaPixmapInfo.rowBytes(i)));
Brian Salomon59c60b02020-09-01 15:01:15 -040058 // Currently all planes must share a data type, gettable as SkYUVAPixmapInfo::dataType().
59 auto [numChannels, planeDataType] = SkYUVAPixmapInfo::NumChannelsAndDataType(planeCT);
60 REPORTER_ASSERT(reporter, planeDataType == yuvaPixmapInfo.dataType());
Brian Salomon87d42e52020-08-24 09:18:16 -040061 }
62 for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) {
Brian Salomonbe0e42c2020-08-27 11:00:04 -040063 const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i);
64 REPORTER_ASSERT(reporter, planeInfo.dimensions().isEmpty());
65 REPORTER_ASSERT(reporter, planeInfo.colorType() == kUnknown_SkColorType);
66 REPORTER_ASSERT(reporter, yuvaPixmapInfo.rowBytes(i) == 0);
msarett829caa22016-02-11 14:17:17 -080067 }
Jim Van Verth8f11e432018-10-18 14:36:59 -040068
Brian Salomon87d42e52020-08-24 09:18:16 -040069 // Allocate the memory for the YUV decode.
Brian Salomonbe0e42c2020-08-27 11:00:04 -040070 auto pixmaps = SkYUVAPixmaps::Allocate(yuvaPixmapInfo);
71 REPORTER_ASSERT(reporter, pixmaps.isValid());
72
73 for (int i = 0; i < SkYUVAPixmaps::kMaxPlanes; ++i) {
74 REPORTER_ASSERT(reporter, pixmaps.plane(i).info() == yuvaPixmapInfo.planeInfo(i));
75 }
76 for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) {
77 REPORTER_ASSERT(reporter, pixmaps.plane(i).rowBytes() == 0);
Brian Salomon87d42e52020-08-24 09:18:16 -040078 }
Jim Van Verth8f11e432018-10-18 14:36:59 -040079
Brian Salomon87d42e52020-08-24 09:18:16 -040080 // Test getYUVAPlanes()
Brian Salomonbe0e42c2020-08-27 11:00:04 -040081 REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->getYUVAPlanes(pixmaps));
msarett829caa22016-02-11 14:17:17 -080082}
83
84DEF_TEST(Jpeg_YUV_Codec, r) {
Brian Salomon87d42e52020-08-24 09:18:16 -040085 auto setExpectations = [](SkISize dims, SkYUVAInfo::PlanarConfig planarConfig) {
86 return SkYUVAInfo(dims,
87 planarConfig,
88 kJPEG_Full_SkYUVColorSpace,
89 kTopLeft_SkEncodedOrigin,
90 SkYUVAInfo::Siting::kCentered,
91 SkYUVAInfo::Siting::kCentered);
92 };
msarett829caa22016-02-11 14:17:17 -080093
Brian Salomon87d42e52020-08-24 09:18:16 -040094 SkYUVAInfo expectations = setExpectations({128, 128}, SkYUVAInfo::PlanarConfig::kY_U_V_420);
95 codec_yuv(r, "images/color_wheel.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -080096
97 // H2V2
Brian Salomon87d42e52020-08-24 09:18:16 -040098 expectations = setExpectations({512, 512}, SkYUVAInfo::PlanarConfig::kY_U_V_420);
99 codec_yuv(r, "images/mandrill_512_q075.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -0800100
101 // H1V1
Brian Salomon87d42e52020-08-24 09:18:16 -0400102 expectations = setExpectations({512, 512}, SkYUVAInfo::PlanarConfig::kY_U_V_444);
103 codec_yuv(r, "images/mandrill_h1v1.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -0800104
105 // H2V1
Brian Salomon87d42e52020-08-24 09:18:16 -0400106 expectations = setExpectations({512, 512}, SkYUVAInfo::PlanarConfig::kY_U_V_422);
107 codec_yuv(r, "images/mandrill_h2v1.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -0800108
109 // Non-power of two dimensions
Brian Salomon87d42e52020-08-24 09:18:16 -0400110 expectations = setExpectations({439, 154}, SkYUVAInfo::PlanarConfig::kY_U_V_420);
111 codec_yuv(r, "images/cropped_mandrill.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -0800112
Brian Salomon87d42e52020-08-24 09:18:16 -0400113 expectations = setExpectations({8, 8}, SkYUVAInfo::PlanarConfig::kY_U_V_420);
114 codec_yuv(r, "images/randPixels.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -0800115
116 // Progressive images
Brian Salomon87d42e52020-08-24 09:18:16 -0400117 expectations = setExpectations({512, 512}, SkYUVAInfo::PlanarConfig::kY_U_V_444);
118 codec_yuv(r, "images/brickwork-texture.jpg", &expectations);
119 codec_yuv(r, "images/brickwork_normal-map.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -0800120
121 // A CMYK encoded image should fail.
Hal Canaryc465d132017-12-08 10:21:31 -0500122 codec_yuv(r, "images/CMYK.jpg", nullptr);
msarett829caa22016-02-11 14:17:17 -0800123 // A grayscale encoded image should fail.
Hal Canaryc465d132017-12-08 10:21:31 -0500124 codec_yuv(r, "images/grayscale.jpg", nullptr);
msarett829caa22016-02-11 14:17:17 -0800125 // A PNG should fail.
Hal Canaryc465d132017-12-08 10:21:31 -0500126 codec_yuv(r, "images/arrow.png", nullptr);
msarett829caa22016-02-11 14:17:17 -0800127}
Mike Reed6a5f7e22019-05-23 15:30:07 -0400128
129#include "include/effects/SkColorMatrix.h"
130#include "src/core/SkYUVMath.h"
131
132// Be sure that the two matrices are inverses of each other
133// (i.e. rgb2yuv and yuv2rgb
134DEF_TEST(YUVMath, reporter) {
135 const SkYUVColorSpace spaces[] = {
136 kJPEG_SkYUVColorSpace,
137 kRec601_SkYUVColorSpace,
138 kRec709_SkYUVColorSpace,
Brian Osman2b73e662019-11-01 10:02:24 -0400139 kBT2020_SkYUVColorSpace,
Mike Reed6a5f7e22019-05-23 15:30:07 -0400140 kIdentity_SkYUVColorSpace,
141 };
142
143 // Not sure what the theoretical precision we can hope for is, so pick a big value that
144 // passes (when I think we're correct).
145 const float tolerance = 1.0f/(1 << 18);
146
147 for (auto cs : spaces) {
148 float r2y[20], y2r[20];
149 SkColorMatrix_RGB2YUV(cs, r2y);
150 SkColorMatrix_YUV2RGB(cs, y2r);
151
152 SkColorMatrix r2ym, y2rm;
153 r2ym.setRowMajor(r2y);
154 y2rm.setRowMajor(y2r);
155 r2ym.postConcat(y2rm);
156
157 float tmp[20];
158 r2ym.getRowMajor(tmp);
159 for (int i = 0; i < 20; ++i) {
160 float expected = 0;
161 if (i % 6 == 0) { // diagonal
162 expected = 1;
163 }
164 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(tmp[i], expected, tolerance));
165 }
166 }
167}