| // Copyright 2019 The libgav1 Authors |
| // |
| // 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 |
| // |
| // http://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 <cassert> |
| #include <cstdint> |
| |
| #include "src/symbol_decoder_context.h" |
| #include "src/tile.h" |
| #include "src/utils/block_parameters_holder.h" |
| #include "src/utils/common.h" |
| #include "src/utils/constants.h" |
| #include "src/utils/entropy_decoder.h" |
| #include "src/utils/types.h" |
| |
| namespace libgav1 { |
| namespace { |
| |
| uint16_t PartitionCdfGatherHorizontalAlike(const uint16_t* const partition_cdf, |
| BlockSize block_size) { |
| // The spec computes the cdf value using the following formula (not writing |
| // partition_cdf[] and using short forms for partition names for clarity): |
| // cdf = None - H + V - S + S - HTS + HTS - HBS + HBS - VLS; |
| // if (block_size != 128x128) { |
| // cdf += VRS - H4; |
| // } |
| // After canceling out the repeated terms with opposite signs, we have: |
| // cdf = None - H + V - VLS; |
| // if (block_size != 128x128) { |
| // cdf += VRS - H4; |
| // } |
| uint16_t cdf = partition_cdf[kPartitionNone] - |
| partition_cdf[kPartitionHorizontal] + |
| partition_cdf[kPartitionVertical] - |
| partition_cdf[kPartitionVerticalWithLeftSplit]; |
| if (block_size != kBlock128x128) { |
| cdf += partition_cdf[kPartitionVerticalWithRightSplit] - |
| partition_cdf[kPartitionHorizontal4]; |
| } |
| return cdf; |
| } |
| |
| uint16_t PartitionCdfGatherVerticalAlike(const uint16_t* const partition_cdf, |
| BlockSize block_size) { |
| // The spec computes the cdf value using the following formula (not writing |
| // partition_cdf[] and using short forms for partition names for clarity): |
| // cdf = H - V + V - S + HBS - VLS + VLS - VRS + S - HTS; |
| // if (block_size != 128x128) { |
| // cdf += H4 - V4; |
| // } |
| // V4 is always zero. So, after canceling out the repeated terms with opposite |
| // signs, we have: |
| // cdf = H + HBS - VRS - HTS; |
| // if (block_size != 128x128) { |
| // cdf += H4; |
| // } |
| // VRS is zero for 128x128 blocks. So, further simplifying we have: |
| // cdf = H + HBS - HTS; |
| // if (block_size != 128x128) { |
| // cdf += H4 - VRS; |
| // } |
| uint16_t cdf = partition_cdf[kPartitionHorizontal] + |
| partition_cdf[kPartitionHorizontalWithBottomSplit] - |
| partition_cdf[kPartitionHorizontalWithTopSplit]; |
| if (block_size != kBlock128x128) { |
| cdf += partition_cdf[kPartitionHorizontal4] - |
| partition_cdf[kPartitionVerticalWithRightSplit]; |
| } |
| return cdf; |
| } |
| |
| } // namespace |
| |
| uint16_t* Tile::GetPartitionCdf(int row4x4, int column4x4, |
| BlockSize block_size) { |
| const int block_size_log2 = k4x4WidthLog2[block_size]; |
| int top = 0; |
| if (IsInside(row4x4 - 1, column4x4)) { |
| top = static_cast<int>( |
| k4x4WidthLog2[block_parameters_holder_.Find(row4x4 - 1, column4x4) |
| ->size] < block_size_log2); |
| } |
| int left = 0; |
| if (IsInside(row4x4, column4x4 - 1)) { |
| left = static_cast<int>( |
| k4x4HeightLog2[block_parameters_holder_.Find(row4x4, column4x4 - 1) |
| ->size] < block_size_log2); |
| } |
| const int context = left * 2 + top; |
| return symbol_decoder_context_.partition_cdf[block_size_log2 - 1][context]; |
| } |
| |
| bool Tile::ReadPartition(int row4x4, int column4x4, BlockSize block_size, |
| bool has_rows, bool has_columns, |
| Partition* const partition) { |
| if (IsBlockSmallerThan8x8(block_size)) { |
| *partition = kPartitionNone; |
| return true; |
| } |
| if (!has_rows && !has_columns) { |
| *partition = kPartitionSplit; |
| return true; |
| } |
| uint16_t* const partition_cdf = |
| GetPartitionCdf(row4x4, column4x4, block_size); |
| if (partition_cdf == nullptr) { |
| return false; |
| } |
| if (has_rows && has_columns) { |
| const int bsize_log2 = k4x4WidthLog2[block_size]; |
| // The partition block size should be 8x8 or above. |
| assert(bsize_log2 > 0); |
| const int cdf_size = SymbolDecoderContext::PartitionCdfSize(bsize_log2); |
| *partition = |
| static_cast<Partition>(reader_.ReadSymbol(partition_cdf, cdf_size)); |
| } else if (has_columns) { |
| uint16_t cdf[3] = { |
| PartitionCdfGatherVerticalAlike(partition_cdf, block_size), 0, 0}; |
| *partition = reader_.ReadSymbolWithoutCdfUpdate(cdf) ? kPartitionSplit |
| : kPartitionHorizontal; |
| } else { |
| uint16_t cdf[3] = { |
| PartitionCdfGatherHorizontalAlike(partition_cdf, block_size), 0, 0}; |
| *partition = reader_.ReadSymbolWithoutCdfUpdate(cdf) ? kPartitionSplit |
| : kPartitionVertical; |
| } |
| return true; |
| } |
| |
| } // namespace libgav1 |