aboutsummaryrefslogtreecommitdiff
path: root/src/decoder/footprint.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/decoder/footprint.cc')
-rw-r--r--src/decoder/footprint.cc162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/decoder/footprint.cc b/src/decoder/footprint.cc
new file mode 100644
index 0000000..e4f076e
--- /dev/null
+++ b/src/decoder/footprint.cc
@@ -0,0 +1,162 @@
+// Copyright 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/decoder/footprint.h"
+#include "src/base/string_utils.h"
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace astc_codec {
+
+namespace {
+
+// Encodes the width and height into an integer so that we can use a switch
+// statement instead of a costly lookup map.
+constexpr int EncodeDims(int width, int height) {
+ return (width << 16) | height;
+}
+
+} // namespace
+
+base::Optional<FootprintType>
+Footprint::GetValidFootprintForDimensions(int width, int height) {
+ switch (EncodeDims(width, height)) {
+ case EncodeDims(4, 4): return FootprintType::k4x4;
+ case EncodeDims(5, 4): return FootprintType::k5x4;
+ case EncodeDims(5, 5): return FootprintType::k5x5;
+ case EncodeDims(6, 5): return FootprintType::k6x5;
+ case EncodeDims(6, 6): return FootprintType::k6x6;
+ case EncodeDims(8, 5): return FootprintType::k8x5;
+ case EncodeDims(8, 6): return FootprintType::k8x6;
+ case EncodeDims(8, 8): return FootprintType::k8x8;
+ case EncodeDims(10, 5): return FootprintType::k10x5;
+ case EncodeDims(10, 6): return FootprintType::k10x6;
+ case EncodeDims(10, 8): return FootprintType::k10x8;
+ case EncodeDims(10, 10): return FootprintType::k10x10;
+ case EncodeDims(12, 10): return FootprintType::k12x10;
+ case EncodeDims(12, 12): return FootprintType::k12x12;
+ default: return {};
+ }
+}
+
+int Footprint::GetWidthForFootprint(FootprintType footprint) {
+ switch (footprint) {
+ case FootprintType::k4x4: return 4;
+ case FootprintType::k5x4: return 5;
+ case FootprintType::k5x5: return 5;
+ case FootprintType::k6x5: return 6;
+ case FootprintType::k6x6: return 6;
+ case FootprintType::k8x5: return 8;
+ case FootprintType::k8x6: return 8;
+ case FootprintType::k10x5: return 10;
+ case FootprintType::k10x6: return 10;
+ case FootprintType::k8x8: return 8;
+ case FootprintType::k10x8: return 10;
+ case FootprintType::k10x10: return 10;
+ case FootprintType::k12x10: return 12;
+ case FootprintType::k12x12: return 12;
+ default:
+ assert(false);
+ return -1;
+ }
+}
+
+int Footprint::GetHeightForFootprint(FootprintType footprint) {
+ switch (footprint) {
+ case FootprintType::k4x4: return 4;
+ case FootprintType::k5x4: return 4;
+ case FootprintType::k5x5: return 5;
+ case FootprintType::k6x5: return 5;
+ case FootprintType::k6x6: return 6;
+ case FootprintType::k8x5: return 5;
+ case FootprintType::k8x6: return 6;
+ case FootprintType::k10x5: return 5;
+ case FootprintType::k10x6: return 6;
+ case FootprintType::k8x8: return 8;
+ case FootprintType::k10x8: return 8;
+ case FootprintType::k10x10: return 10;
+ case FootprintType::k12x10: return 10;
+ case FootprintType::k12x12: return 12;
+ default:
+ assert(false);
+ return -1;
+ }
+}
+
+Footprint::Footprint(FootprintType footprint)
+ : footprint_(footprint), width_(GetWidthForFootprint(footprint)),
+ height_(GetHeightForFootprint(footprint)) { }
+
+////////////////////////////////////////////////////////////////////////////////
+
+base::Optional<Footprint> Footprint::Parse(const char* footprint_string) {
+ assert(footprint_string && footprint_string[0] != '\0');
+
+ std::vector<std::string> dimension_strings;
+ base::Split(footprint_string, "x", [&dimension_strings](std::string&& s) {
+ dimension_strings.push_back(std::move(s));
+ });
+
+ if (dimension_strings.size() != 2) {
+ assert(false && "Invalid format for footprint");
+ return {};
+ }
+
+ const int width = base::ParseInt32(dimension_strings[0].c_str(), 0);
+ const int height = base::ParseInt32(dimension_strings[1].c_str(), 0);
+
+ assert(width > 0 && height > 0 && "Invalid width or height.");
+
+ return FromDimensions(width, height);
+}
+
+base::Optional<Footprint> Footprint::FromDimensions(int width, int height) {
+ base::Optional<FootprintType> valid_footprint =
+ GetValidFootprintForDimensions(width, height);
+ if (valid_footprint) {
+ return Footprint(valid_footprint.value());
+ } else {
+ return {};
+ }
+}
+
+// Returns a Footprint for the given FootprintType.
+base::Optional<Footprint> Footprint::FromFootprintType(FootprintType type) {
+ if (type >= FootprintType::k4x4 && type < FootprintType::kCount) {
+ return Footprint(type);
+ } else {
+ return {};
+ }
+}
+
+size_t Footprint::StorageRequirements(int width, int height) const {
+ const int blocks_wide = (width + width_ - 1) / width_;
+ const int blocks_high = (height + height_ - 1) / height_;
+
+ constexpr size_t kASTCBlockSizeInBytes = 16;
+ return blocks_wide * blocks_high * kASTCBlockSizeInBytes;
+}
+
+// Returns bits/pixel for a given footprint.
+float Footprint::Bitrate() const {
+ const int kASTCBlockBitCount = 128;
+ const int footprint_pixel_count = width_ * height_;
+ return static_cast<float>(kASTCBlockBitCount) /
+ static_cast<float>(footprint_pixel_count);
+}
+
+} // namespace astc_codec