1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/decoder/footprint.h"
16 #include "src/base/string_utils.h"
17
18 #include <map>
19 #include <string>
20 #include <utility>
21 #include <vector>
22
23 namespace astc_codec {
24
25 namespace {
26
27 // Encodes the width and height into an integer so that we can use a switch
28 // statement instead of a costly lookup map.
EncodeDims(int width,int height)29 constexpr int EncodeDims(int width, int height) {
30 return (width << 16) | height;
31 }
32
33 } // namespace
34
35 base::Optional<FootprintType>
GetValidFootprintForDimensions(int width,int height)36 Footprint::GetValidFootprintForDimensions(int width, int height) {
37 switch (EncodeDims(width, height)) {
38 case EncodeDims(4, 4): return FootprintType::k4x4;
39 case EncodeDims(5, 4): return FootprintType::k5x4;
40 case EncodeDims(5, 5): return FootprintType::k5x5;
41 case EncodeDims(6, 5): return FootprintType::k6x5;
42 case EncodeDims(6, 6): return FootprintType::k6x6;
43 case EncodeDims(8, 5): return FootprintType::k8x5;
44 case EncodeDims(8, 6): return FootprintType::k8x6;
45 case EncodeDims(8, 8): return FootprintType::k8x8;
46 case EncodeDims(10, 5): return FootprintType::k10x5;
47 case EncodeDims(10, 6): return FootprintType::k10x6;
48 case EncodeDims(10, 8): return FootprintType::k10x8;
49 case EncodeDims(10, 10): return FootprintType::k10x10;
50 case EncodeDims(12, 10): return FootprintType::k12x10;
51 case EncodeDims(12, 12): return FootprintType::k12x12;
52 default: return {};
53 }
54 }
55
GetWidthForFootprint(FootprintType footprint)56 int Footprint::GetWidthForFootprint(FootprintType footprint) {
57 switch (footprint) {
58 case FootprintType::k4x4: return 4;
59 case FootprintType::k5x4: return 5;
60 case FootprintType::k5x5: return 5;
61 case FootprintType::k6x5: return 6;
62 case FootprintType::k6x6: return 6;
63 case FootprintType::k8x5: return 8;
64 case FootprintType::k8x6: return 8;
65 case FootprintType::k10x5: return 10;
66 case FootprintType::k10x6: return 10;
67 case FootprintType::k8x8: return 8;
68 case FootprintType::k10x8: return 10;
69 case FootprintType::k10x10: return 10;
70 case FootprintType::k12x10: return 12;
71 case FootprintType::k12x12: return 12;
72 default:
73 assert(false);
74 return -1;
75 }
76 }
77
GetHeightForFootprint(FootprintType footprint)78 int Footprint::GetHeightForFootprint(FootprintType footprint) {
79 switch (footprint) {
80 case FootprintType::k4x4: return 4;
81 case FootprintType::k5x4: return 4;
82 case FootprintType::k5x5: return 5;
83 case FootprintType::k6x5: return 5;
84 case FootprintType::k6x6: return 6;
85 case FootprintType::k8x5: return 5;
86 case FootprintType::k8x6: return 6;
87 case FootprintType::k10x5: return 5;
88 case FootprintType::k10x6: return 6;
89 case FootprintType::k8x8: return 8;
90 case FootprintType::k10x8: return 8;
91 case FootprintType::k10x10: return 10;
92 case FootprintType::k12x10: return 10;
93 case FootprintType::k12x12: return 12;
94 default:
95 assert(false);
96 return -1;
97 }
98 }
99
Footprint(FootprintType footprint)100 Footprint::Footprint(FootprintType footprint)
101 : footprint_(footprint), width_(GetWidthForFootprint(footprint)),
102 height_(GetHeightForFootprint(footprint)) { }
103
104 ////////////////////////////////////////////////////////////////////////////////
105
Parse(const char * footprint_string)106 base::Optional<Footprint> Footprint::Parse(const char* footprint_string) {
107 assert(footprint_string && footprint_string[0] != '\0');
108
109 std::vector<std::string> dimension_strings;
110 base::Split(footprint_string, "x", [&dimension_strings](std::string&& s) {
111 dimension_strings.push_back(std::move(s));
112 });
113
114 if (dimension_strings.size() != 2) {
115 assert(false && "Invalid format for footprint");
116 return {};
117 }
118
119 const int width = base::ParseInt32(dimension_strings[0].c_str(), 0);
120 const int height = base::ParseInt32(dimension_strings[1].c_str(), 0);
121
122 assert(width > 0 && height > 0 && "Invalid width or height.");
123
124 return FromDimensions(width, height);
125 }
126
FromDimensions(int width,int height)127 base::Optional<Footprint> Footprint::FromDimensions(int width, int height) {
128 base::Optional<FootprintType> valid_footprint =
129 GetValidFootprintForDimensions(width, height);
130 if (valid_footprint) {
131 return Footprint(valid_footprint.value());
132 } else {
133 return {};
134 }
135 }
136
137 // Returns a Footprint for the given FootprintType.
FromFootprintType(FootprintType type)138 base::Optional<Footprint> Footprint::FromFootprintType(FootprintType type) {
139 if (type >= FootprintType::k4x4 && type < FootprintType::kCount) {
140 return Footprint(type);
141 } else {
142 return {};
143 }
144 }
145
StorageRequirements(int width,int height) const146 size_t Footprint::StorageRequirements(int width, int height) const {
147 const int blocks_wide = (width + width_ - 1) / width_;
148 const int blocks_high = (height + height_ - 1) / height_;
149
150 constexpr size_t kASTCBlockSizeInBytes = 16;
151 return blocks_wide * blocks_high * kASTCBlockSizeInBytes;
152 }
153
154 // Returns bits/pixel for a given footprint.
Bitrate() const155 float Footprint::Bitrate() const {
156 const int kASTCBlockBitCount = 128;
157 const int footprint_pixel_count = width_ * height_;
158 return static_cast<float>(kASTCBlockBitCount) /
159 static_cast<float>(footprint_pixel_count);
160 }
161
162 } // namespace astc_codec
163