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