blob: 47d47c9a95991a88104a6ed68173aca5b17eec42 [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/private/SkTemplates.h"
12#include "src/core/SkAutoMalloc.h"
13#include "tests/Test.h"
14#include "tools/Resources.h"
msarett829caa22016-02-11 14:17:17 -080015
msarett829caa22016-02-11 14:17:17 -080016static void codec_yuv(skiatest::Reporter* reporter,
Jim Van Verth8f11e432018-10-18 14:36:59 -040017 const char path[],
Brian Salomon87d42e52020-08-24 09:18:16 -040018 const SkYUVAInfo* expectedInfo) {
Ben Wagner145dbcd2016-11-03 14:40:50 -040019 std::unique_ptr<SkStream> stream(GetResourceAsStream(path));
msarett829caa22016-02-11 14:17:17 -080020 if (!stream) {
msarett829caa22016-02-11 14:17:17 -080021 return;
22 }
Mike Reedede7bac2017-07-23 15:30:02 -040023 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
msarett829caa22016-02-11 14:17:17 -080024 REPORTER_ASSERT(reporter, codec);
25 if (!codec) {
26 return;
27 }
28
Brian Salomon87d42e52020-08-24 09:18:16 -040029 // Test queryYUBAInfo()
Brian Salomonbe0e42c2020-08-27 11:00:04 -040030 SkYUVAPixmapInfo yuvaPixmapInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -040031
Brian Salomon59c60b02020-09-01 15:01:15 -040032 static constexpr auto kAllTypes = SkYUVAPixmapInfo::SupportedDataTypes::All();
33 static constexpr auto kNoTypes = SkYUVAPixmapInfo::SupportedDataTypes();
34
35 // SkYUVAInfo param is required to be non-null.
36 bool success = codec->queryYUVAInfo(kAllTypes, nullptr);
Brian Salomon87d42e52020-08-24 09:18:16 -040037 REPORTER_ASSERT(reporter, !success);
Brian Salomon59c60b02020-09-01 15:01:15 -040038 // Fails when there is no support for YUVA planes.
39 success = codec->queryYUVAInfo(kNoTypes, &yuvaPixmapInfo);
40 REPORTER_ASSERT(reporter, !success);
41
42 success = codec->queryYUVAInfo(kAllTypes, &yuvaPixmapInfo);
Brian Salomon87d42e52020-08-24 09:18:16 -040043 REPORTER_ASSERT(reporter, SkToBool(expectedInfo) == success);
44 if (!success) {
45 return;
46 }
Brian Salomonbe0e42c2020-08-27 11:00:04 -040047 REPORTER_ASSERT(reporter, *expectedInfo == yuvaPixmapInfo.yuvaInfo());
Jim Van Verth8f11e432018-10-18 14:36:59 -040048
Brian Salomonbe0e42c2020-08-27 11:00:04 -040049 int numPlanes = yuvaPixmapInfo.numPlanes();
Brian Salomon87d42e52020-08-24 09:18:16 -040050 REPORTER_ASSERT(reporter, numPlanes <= SkYUVAInfo::kMaxPlanes);
Brian Salomon87d42e52020-08-24 09:18:16 -040051 for (int i = 0; i < numPlanes; ++i) {
Brian Salomonbe0e42c2020-08-27 11:00:04 -040052 const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i);
Brian Salomon59c60b02020-09-01 15:01:15 -040053 SkColorType planeCT = planeInfo.colorType();
Brian Salomonbe0e42c2020-08-27 11:00:04 -040054 REPORTER_ASSERT(reporter, !planeInfo.isEmpty());
Brian Salomon59c60b02020-09-01 15:01:15 -040055 REPORTER_ASSERT(reporter, planeCT != kUnknown_SkColorType);
Brian Salomonbe0e42c2020-08-27 11:00:04 -040056 REPORTER_ASSERT(reporter, planeInfo.validRowBytes(yuvaPixmapInfo.rowBytes(i)));
Brian Salomon59c60b02020-09-01 15:01:15 -040057 // Currently all planes must share a data type, gettable as SkYUVAPixmapInfo::dataType().
58 auto [numChannels, planeDataType] = SkYUVAPixmapInfo::NumChannelsAndDataType(planeCT);
59 REPORTER_ASSERT(reporter, planeDataType == yuvaPixmapInfo.dataType());
Brian Salomon87d42e52020-08-24 09:18:16 -040060 }
61 for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) {
Brian Salomonbe0e42c2020-08-27 11:00:04 -040062 const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i);
63 REPORTER_ASSERT(reporter, planeInfo.dimensions().isEmpty());
64 REPORTER_ASSERT(reporter, planeInfo.colorType() == kUnknown_SkColorType);
65 REPORTER_ASSERT(reporter, yuvaPixmapInfo.rowBytes(i) == 0);
msarett829caa22016-02-11 14:17:17 -080066 }
Jim Van Verth8f11e432018-10-18 14:36:59 -040067
Brian Salomon87d42e52020-08-24 09:18:16 -040068 // Allocate the memory for the YUV decode.
Brian Salomonbe0e42c2020-08-27 11:00:04 -040069 auto pixmaps = SkYUVAPixmaps::Allocate(yuvaPixmapInfo);
70 REPORTER_ASSERT(reporter, pixmaps.isValid());
71
72 for (int i = 0; i < SkYUVAPixmaps::kMaxPlanes; ++i) {
73 REPORTER_ASSERT(reporter, pixmaps.plane(i).info() == yuvaPixmapInfo.planeInfo(i));
74 }
75 for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) {
76 REPORTER_ASSERT(reporter, pixmaps.plane(i).rowBytes() == 0);
Brian Salomon87d42e52020-08-24 09:18:16 -040077 }
Jim Van Verth8f11e432018-10-18 14:36:59 -040078
Brian Salomon87d42e52020-08-24 09:18:16 -040079 // Test getYUVAPlanes()
Brian Salomonbe0e42c2020-08-27 11:00:04 -040080 REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->getYUVAPlanes(pixmaps));
msarett829caa22016-02-11 14:17:17 -080081}
82
83DEF_TEST(Jpeg_YUV_Codec, r) {
Brian Salomone4387382020-11-11 16:34:19 -050084 auto setExpectations = [](SkISize dims, SkYUVAInfo::Subsampling subsampling) {
Brian Salomon87d42e52020-08-24 09:18:16 -040085 return SkYUVAInfo(dims,
Brian Salomone4387382020-11-11 16:34:19 -050086 SkYUVAInfo::PlaneConfig::kY_U_V,
87 subsampling,
Brian Salomon87d42e52020-08-24 09:18:16 -040088 kJPEG_Full_SkYUVColorSpace,
89 kTopLeft_SkEncodedOrigin,
90 SkYUVAInfo::Siting::kCentered,
91 SkYUVAInfo::Siting::kCentered);
92 };
msarett829caa22016-02-11 14:17:17 -080093
Brian Salomone4387382020-11-11 16:34:19 -050094 SkYUVAInfo expectations = setExpectations({128, 128}, SkYUVAInfo::Subsampling::k420);
Brian Salomon87d42e52020-08-24 09:18:16 -040095 codec_yuv(r, "images/color_wheel.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -080096
97 // H2V2
Brian Salomone4387382020-11-11 16:34:19 -050098 expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k420);
Brian Salomon87d42e52020-08-24 09:18:16 -040099 codec_yuv(r, "images/mandrill_512_q075.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -0800100
101 // H1V1
Brian Salomone4387382020-11-11 16:34:19 -0500102 expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k444);
Brian Salomon87d42e52020-08-24 09:18:16 -0400103 codec_yuv(r, "images/mandrill_h1v1.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -0800104
105 // H2V1
Brian Salomone4387382020-11-11 16:34:19 -0500106 expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k422);
Brian Salomon87d42e52020-08-24 09:18:16 -0400107 codec_yuv(r, "images/mandrill_h2v1.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -0800108
109 // Non-power of two dimensions
Brian Salomone4387382020-11-11 16:34:19 -0500110 expectations = setExpectations({439, 154}, SkYUVAInfo::Subsampling::k420);
Brian Salomon87d42e52020-08-24 09:18:16 -0400111 codec_yuv(r, "images/cropped_mandrill.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -0800112
Brian Salomone4387382020-11-11 16:34:19 -0500113 expectations = setExpectations({8, 8}, SkYUVAInfo::Subsampling::k420);
Brian Salomon87d42e52020-08-24 09:18:16 -0400114 codec_yuv(r, "images/randPixels.jpg", &expectations);
msarett829caa22016-02-11 14:17:17 -0800115
116 // Progressive images
Brian Salomone4387382020-11-11 16:34:19 -0500117 expectations = setExpectations({512, 512}, SkYUVAInfo::Subsampling::k444);
Brian Salomon87d42e52020-08-24 09:18:16 -0400118 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}