blob: 84e8cf03dfdc438edb32378d0092a2410cf8e4f7 [file] [log] [blame]
// 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 InverseCdfProbability(uint16_t probability) {
return kCdfMaxProbability - probability;
}
uint16_t CdfElementProbability(const uint16_t* const cdf, uint8_t element) {
return (element > 0 ? cdf[element - 1] : uint16_t{kCdfMaxProbability}) -
cdf[element];
}
void PartitionCdfGatherHorizontalAlike(const uint16_t* const partition_cdf,
BlockSize block_size,
uint16_t* const cdf) {
cdf[0] = kCdfMaxProbability;
cdf[0] -= CdfElementProbability(partition_cdf, kPartitionHorizontal);
cdf[0] -= CdfElementProbability(partition_cdf, kPartitionSplit);
cdf[0] -=
CdfElementProbability(partition_cdf, kPartitionHorizontalWithTopSplit);
cdf[0] -=
CdfElementProbability(partition_cdf, kPartitionHorizontalWithBottomSplit);
cdf[0] -=
CdfElementProbability(partition_cdf, kPartitionVerticalWithLeftSplit);
if (block_size != kBlock128x128) {
cdf[0] -= CdfElementProbability(partition_cdf, kPartitionHorizontal4);
}
cdf[0] = InverseCdfProbability(cdf[0]);
cdf[1] = 0;
cdf[2] = 0;
}
void PartitionCdfGatherVerticalAlike(const uint16_t* const partition_cdf,
BlockSize block_size,
uint16_t* const cdf) {
cdf[0] = kCdfMaxProbability;
cdf[0] -= CdfElementProbability(partition_cdf, kPartitionVertical);
cdf[0] -= CdfElementProbability(partition_cdf, kPartitionSplit);
cdf[0] -=
CdfElementProbability(partition_cdf, kPartitionVerticalWithLeftSplit);
cdf[0] -=
CdfElementProbability(partition_cdf, kPartitionVerticalWithRightSplit);
cdf[0] -=
CdfElementProbability(partition_cdf, kPartitionHorizontalWithTopSplit);
if (block_size != kBlock128x128) {
cdf[0] -= CdfElementProbability(partition_cdf, kPartitionVertical4);
}
cdf[0] = InverseCdfProbability(cdf[0]);
cdf[1] = 0;
cdf[2] = 0;
}
} // 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, cdf);
*partition = reader_.ReadSymbolWithoutCdfUpdate(cdf) ? kPartitionSplit
: kPartitionHorizontal;
} else {
uint16_t cdf[3];
PartitionCdfGatherHorizontalAlike(partition_cdf, block_size, cdf);
*partition = reader_.ReadSymbolWithoutCdfUpdate(cdf) ? kPartitionSplit
: kPartitionVertical;
}
return true;
}
} // namespace libgav1