msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 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 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 8 | #include "include/codec/SkCodec.h" |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 9 | #include "include/core/SkPixmap.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 10 | #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" |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 16 | |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 17 | static void codec_yuv(skiatest::Reporter* reporter, |
Jim Van Verth | 8f11e43 | 2018-10-18 14:36:59 -0400 | [diff] [blame] | 18 | const char path[], |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 19 | const SkYUVAInfo* expectedInfo) { |
Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 20 | std::unique_ptr<SkStream> stream(GetResourceAsStream(path)); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 21 | if (!stream) { |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 22 | return; |
| 23 | } |
Mike Reed | ede7bac | 2017-07-23 15:30:02 -0400 | [diff] [blame] | 24 | std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream))); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 25 | REPORTER_ASSERT(reporter, codec); |
| 26 | if (!codec) { |
| 27 | return; |
| 28 | } |
| 29 | |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 30 | // Test queryYUBAInfo() |
Brian Salomon | be0e42c | 2020-08-27 11:00:04 -0400 | [diff] [blame] | 31 | SkYUVAPixmapInfo yuvaPixmapInfo; |
Jim Van Verth | 8f11e43 | 2018-10-18 14:36:59 -0400 | [diff] [blame] | 32 | |
Brian Salomon | 59c60b0 | 2020-09-01 15:01:15 -0400 | [diff] [blame] | 33 | 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 Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 38 | REPORTER_ASSERT(reporter, !success); |
Brian Salomon | 59c60b0 | 2020-09-01 15:01:15 -0400 | [diff] [blame] | 39 | // 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 Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 44 | REPORTER_ASSERT(reporter, SkToBool(expectedInfo) == success); |
| 45 | if (!success) { |
| 46 | return; |
| 47 | } |
Brian Salomon | be0e42c | 2020-08-27 11:00:04 -0400 | [diff] [blame] | 48 | REPORTER_ASSERT(reporter, *expectedInfo == yuvaPixmapInfo.yuvaInfo()); |
Jim Van Verth | 8f11e43 | 2018-10-18 14:36:59 -0400 | [diff] [blame] | 49 | |
Brian Salomon | be0e42c | 2020-08-27 11:00:04 -0400 | [diff] [blame] | 50 | int numPlanes = yuvaPixmapInfo.numPlanes(); |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 51 | REPORTER_ASSERT(reporter, numPlanes <= SkYUVAInfo::kMaxPlanes); |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 52 | for (int i = 0; i < numPlanes; ++i) { |
Brian Salomon | be0e42c | 2020-08-27 11:00:04 -0400 | [diff] [blame] | 53 | const SkImageInfo& planeInfo = yuvaPixmapInfo.planeInfo(i); |
Brian Salomon | 59c60b0 | 2020-09-01 15:01:15 -0400 | [diff] [blame] | 54 | SkColorType planeCT = planeInfo.colorType(); |
Brian Salomon | be0e42c | 2020-08-27 11:00:04 -0400 | [diff] [blame] | 55 | REPORTER_ASSERT(reporter, !planeInfo.isEmpty()); |
Brian Salomon | 59c60b0 | 2020-09-01 15:01:15 -0400 | [diff] [blame] | 56 | REPORTER_ASSERT(reporter, planeCT != kUnknown_SkColorType); |
Brian Salomon | be0e42c | 2020-08-27 11:00:04 -0400 | [diff] [blame] | 57 | REPORTER_ASSERT(reporter, planeInfo.validRowBytes(yuvaPixmapInfo.rowBytes(i))); |
Brian Salomon | 59c60b0 | 2020-09-01 15:01:15 -0400 | [diff] [blame] | 58 | // 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 Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 61 | } |
| 62 | for (int i = numPlanes; i < SkYUVAInfo::kMaxPlanes; ++i) { |
Brian Salomon | be0e42c | 2020-08-27 11:00:04 -0400 | [diff] [blame] | 63 | 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); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 67 | } |
Jim Van Verth | 8f11e43 | 2018-10-18 14:36:59 -0400 | [diff] [blame] | 68 | |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 69 | // Allocate the memory for the YUV decode. |
Brian Salomon | be0e42c | 2020-08-27 11:00:04 -0400 | [diff] [blame] | 70 | 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 Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 78 | } |
Jim Van Verth | 8f11e43 | 2018-10-18 14:36:59 -0400 | [diff] [blame] | 79 | |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 80 | // Test getYUVAPlanes() |
Brian Salomon | be0e42c | 2020-08-27 11:00:04 -0400 | [diff] [blame] | 81 | REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->getYUVAPlanes(pixmaps)); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 82 | } |
| 83 | |
| 84 | DEF_TEST(Jpeg_YUV_Codec, r) { |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 85 | 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 | }; |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 93 | |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 94 | SkYUVAInfo expectations = setExpectations({128, 128}, SkYUVAInfo::PlanarConfig::kY_U_V_420); |
| 95 | codec_yuv(r, "images/color_wheel.jpg", &expectations); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 96 | |
| 97 | // H2V2 |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 98 | expectations = setExpectations({512, 512}, SkYUVAInfo::PlanarConfig::kY_U_V_420); |
| 99 | codec_yuv(r, "images/mandrill_512_q075.jpg", &expectations); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 100 | |
| 101 | // H1V1 |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 102 | expectations = setExpectations({512, 512}, SkYUVAInfo::PlanarConfig::kY_U_V_444); |
| 103 | codec_yuv(r, "images/mandrill_h1v1.jpg", &expectations); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 104 | |
| 105 | // H2V1 |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 106 | expectations = setExpectations({512, 512}, SkYUVAInfo::PlanarConfig::kY_U_V_422); |
| 107 | codec_yuv(r, "images/mandrill_h2v1.jpg", &expectations); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 108 | |
| 109 | // Non-power of two dimensions |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 110 | expectations = setExpectations({439, 154}, SkYUVAInfo::PlanarConfig::kY_U_V_420); |
| 111 | codec_yuv(r, "images/cropped_mandrill.jpg", &expectations); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 112 | |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 113 | expectations = setExpectations({8, 8}, SkYUVAInfo::PlanarConfig::kY_U_V_420); |
| 114 | codec_yuv(r, "images/randPixels.jpg", &expectations); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 115 | |
| 116 | // Progressive images |
Brian Salomon | 87d42e5 | 2020-08-24 09:18:16 -0400 | [diff] [blame] | 117 | 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); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 120 | |
| 121 | // A CMYK encoded image should fail. |
Hal Canary | c465d13 | 2017-12-08 10:21:31 -0500 | [diff] [blame] | 122 | codec_yuv(r, "images/CMYK.jpg", nullptr); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 123 | // A grayscale encoded image should fail. |
Hal Canary | c465d13 | 2017-12-08 10:21:31 -0500 | [diff] [blame] | 124 | codec_yuv(r, "images/grayscale.jpg", nullptr); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 125 | // A PNG should fail. |
Hal Canary | c465d13 | 2017-12-08 10:21:31 -0500 | [diff] [blame] | 126 | codec_yuv(r, "images/arrow.png", nullptr); |
msarett | 829caa2 | 2016-02-11 14:17:17 -0800 | [diff] [blame] | 127 | } |
Mike Reed | 6a5f7e2 | 2019-05-23 15:30:07 -0400 | [diff] [blame] | 128 | |
| 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 |
| 134 | DEF_TEST(YUVMath, reporter) { |
| 135 | const SkYUVColorSpace spaces[] = { |
| 136 | kJPEG_SkYUVColorSpace, |
| 137 | kRec601_SkYUVColorSpace, |
| 138 | kRec709_SkYUVColorSpace, |
Brian Osman | 2b73e66 | 2019-11-01 10:02:24 -0400 | [diff] [blame] | 139 | kBT2020_SkYUVColorSpace, |
Mike Reed | 6a5f7e2 | 2019-05-23 15:30:07 -0400 | [diff] [blame] | 140 | 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 | } |