blob: cfeebed242a9ba4b65f45943a721991a70700317 [file] [log] [blame]
#include "src/loop_restoration_info.h"
#include <algorithm>
#include <array>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <new>
#include "src/utils/common.h"
#include "src/utils/logging.h"
namespace libgav1 {
// Controls how self guided deltas are read.
constexpr int kSgrProjReadControl = 4;
// Maps the restoration type encoded in the compressed headers (restoration_type
// element in the spec) of the bitstream to LoopRestorationType. This is used
// only when the restoration type in the frame header is
// LoopRestorationTypeSwitchable.
constexpr LoopRestorationType kBitstreamRestorationTypeMap[] = {
kLoopRestorationTypeNone, kLoopRestorationTypeWiener,
kLoopRestorationTypeSgrProj};
bool LoopRestorationInfo::Allocate() {
const int num_planes = is_monochrome_ ? kMaxPlanesMonochrome : kMaxPlanes;
int total_num_units = 0;
for (int plane = kPlaneY; plane < num_planes; ++plane) {
if (loop_restoration_.type[plane] == kLoopRestorationTypeNone) {
plane_needs_filtering_[plane] = false;
continue;
}
plane_needs_filtering_[plane] = true;
const int width = (plane == kPlaneY)
? width_
: RightShiftWithRounding(width_, subsampling_x_);
const int height = (plane == kPlaneY)
? height_
: RightShiftWithRounding(height_, subsampling_y_);
num_horizontal_units_[plane] =
std::max(1, (width + DivideBy2(loop_restoration_.unit_size[plane])) /
loop_restoration_.unit_size[plane]);
num_vertical_units_[plane] =
std::max(1, (height + DivideBy2(loop_restoration_.unit_size[plane])) /
loop_restoration_.unit_size[plane]);
num_units_[plane] =
num_horizontal_units_[plane] * num_vertical_units_[plane];
total_num_units += num_units_[plane];
}
// Allocate the RestorationUnitInfo arrays for all planes in a single heap
// allocation and divide up the buffer into arrays of the right sizes.
loop_restoration_info_buffer_.reset(new (std::nothrow)
RestorationUnitInfo[total_num_units]);
if (loop_restoration_info_buffer_ == nullptr) return false;
RestorationUnitInfo* loop_restoration_info =
loop_restoration_info_buffer_.get();
for (int plane = kPlaneY; plane < num_planes; ++plane) {
if (loop_restoration_.type[plane] == kLoopRestorationTypeNone) {
continue;
}
loop_restoration_info_[plane] = loop_restoration_info;
loop_restoration_info += num_units_[plane];
}
return true;
}
bool LoopRestorationInfo::PopulateUnitInfoForSuperBlock(
Plane plane, BlockSize block_size, bool is_superres_scaled,
uint8_t superres_scale_denominator, int row4x4, int column4x4,
LoopRestorationUnitInfo* const unit_info) const {
assert(unit_info != nullptr);
if (!plane_needs_filtering_[plane]) return false;
const int denominator_column =
is_superres_scaled
? loop_restoration_.unit_size[plane] * kSuperResScaleNumerator
: loop_restoration_.unit_size[plane];
const int numerator_column =
is_superres_scaled ? superres_scale_denominator : 1;
const int pixel_column_start =
RowOrColumn4x4ToPixel(column4x4, plane, subsampling_x_);
const int pixel_column_end = RowOrColumn4x4ToPixel(
column4x4 + kNum4x4BlocksWide[block_size], plane, subsampling_x_);
const int unit_row = loop_restoration_.unit_size[plane];
const int pixel_row_start =
RowOrColumn4x4ToPixel(row4x4, plane, subsampling_y_);
const int pixel_row_end = RowOrColumn4x4ToPixel(
row4x4 + kNum4x4BlocksHigh[block_size], plane, subsampling_y_);
unit_info->column_start =
(pixel_column_start * numerator_column + denominator_column - 1) /
denominator_column;
unit_info->column_end =
(pixel_column_end * numerator_column + denominator_column - 1) /
denominator_column;
unit_info->row_start = (pixel_row_start + unit_row - 1) / unit_row;
unit_info->row_end = (pixel_row_end + unit_row - 1) / unit_row;
unit_info->column_end =
std::min(unit_info->column_end, num_horizontal_units_[plane]);
unit_info->row_end = std::min(unit_info->row_end, num_vertical_units_[plane]);
return true;
}
void LoopRestorationInfo::ReadUnitCoefficients(
DaalaBitReader* const reader,
SymbolDecoderContext* const symbol_decoder_context, Plane plane,
int unit_id,
std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) {
LoopRestorationType unit_restoration_type = kLoopRestorationTypeNone;
if (loop_restoration_.type[plane] == kLoopRestorationTypeSwitchable) {
unit_restoration_type = kBitstreamRestorationTypeMap
[reader->ReadSymbol<kRestorationTypeSymbolCount>(
symbol_decoder_context->restoration_type_cdf)];
} else if (loop_restoration_.type[plane] == kLoopRestorationTypeWiener) {
const bool use_wiener =
reader->ReadSymbol(symbol_decoder_context->use_wiener_cdf);
if (use_wiener) unit_restoration_type = kLoopRestorationTypeWiener;
} else if (loop_restoration_.type[plane] == kLoopRestorationTypeSgrProj) {
const bool use_sgrproj =
reader->ReadSymbol(symbol_decoder_context->use_sgrproj_cdf);
if (use_sgrproj) unit_restoration_type = kLoopRestorationTypeSgrProj;
}
loop_restoration_info_[plane][unit_id].type = unit_restoration_type;
if (unit_restoration_type == kLoopRestorationTypeWiener) {
ReadWienerInfo(reader, plane, unit_id, reference_unit_info);
} else if (unit_restoration_type == kLoopRestorationTypeSgrProj) {
ReadSgrProjInfo(reader, plane, unit_id, reference_unit_info);
}
}
void LoopRestorationInfo::ReadWienerInfo(
DaalaBitReader* const reader, Plane plane, int unit_id,
std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) {
for (int i = WienerInfo::kVertical; i <= WienerInfo::kHorizontal; ++i) {
if (plane != kPlaneY) {
loop_restoration_info_[plane][unit_id].wiener_info.filter[i][0] = 0;
}
for (int j = static_cast<int>(plane != kPlaneY); j < kNumWienerCoefficients;
++j) {
const int8_t wiener_min = kWienerTapsMin[j];
const int8_t wiener_max = kWienerTapsMax[j];
const int control = j + 1;
int value;
if (!reader->DecodeSignedSubexpWithReference(
wiener_min, wiener_max + 1,
(*reference_unit_info)[plane].wiener_info.filter[i][j], control,
&value)) {
LIBGAV1_DLOG(
ERROR,
"Error decoding Wiener filter coefficients: plane %d, unit_id %d",
static_cast<int>(plane), unit_id);
return;
}
loop_restoration_info_[plane][unit_id].wiener_info.filter[i][j] = value;
(*reference_unit_info)[plane].wiener_info.filter[i][j] = value;
}
}
}
void LoopRestorationInfo::ReadSgrProjInfo(
DaalaBitReader* const reader, Plane plane, int unit_id,
std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) {
const int sgr_proj_index =
static_cast<int>(reader->ReadLiteral(kSgrProjParamsBits));
loop_restoration_info_[plane][unit_id].sgr_proj_info.index = sgr_proj_index;
for (int i = 0; i < 2; ++i) {
const uint8_t radius = kSgrProjParams[sgr_proj_index][i * 2];
const int8_t multiplier_min = kSgrProjMultiplierMin[i];
const int8_t multiplier_max = kSgrProjMultiplierMax[i];
int multiplier;
if (radius != 0) {
if (!reader->DecodeSignedSubexpWithReference(
multiplier_min, multiplier_max + 1,
(*reference_unit_info)[plane].sgr_proj_info.multiplier[i],
kSgrProjReadControl, &multiplier)) {
LIBGAV1_DLOG(ERROR,
"Error decoding Self-guided filter coefficients: plane "
"%d, unit_id %d",
static_cast<int>(plane), unit_id);
return;
}
} else {
multiplier = 0;
if (i == 1) {
multiplier =
Clip3((1 << kSgrProjPrecisionBits) -
(*reference_unit_info)[plane].sgr_proj_info.multiplier[0],
multiplier_min, multiplier_max);
}
}
loop_restoration_info_[plane][unit_id].sgr_proj_info.multiplier[i] =
multiplier;
(*reference_unit_info)[plane].sgr_proj_info.multiplier[i] = multiplier;
}
}
} // namespace libgav1