// 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 "src/prediction_mask.h" #include #include #include #include #include #include #include #include #include "src/utils/array_2d.h" #include "src/utils/bit_mask_set.h" #include "src/utils/common.h" #include "src/utils/constants.h" #include "src/utils/logging.h" #include "src/utils/memory.h" namespace libgav1 { namespace { constexpr int kWedgeDirectionTypes = 16; enum kWedgeDirection : uint8_t { kWedgeHorizontal, kWedgeVertical, kWedgeOblique27, kWedgeOblique63, kWedgeOblique117, kWedgeOblique153, }; constexpr uint8_t kWedgeCodebook[3][16][3] = {{{kWedgeOblique27, 4, 4}, {kWedgeOblique63, 4, 4}, {kWedgeOblique117, 4, 4}, {kWedgeOblique153, 4, 4}, {kWedgeHorizontal, 4, 2}, {kWedgeHorizontal, 4, 4}, {kWedgeHorizontal, 4, 6}, {kWedgeVertical, 4, 4}, {kWedgeOblique27, 4, 2}, {kWedgeOblique27, 4, 6}, {kWedgeOblique153, 4, 2}, {kWedgeOblique153, 4, 6}, {kWedgeOblique63, 2, 4}, {kWedgeOblique63, 6, 4}, {kWedgeOblique117, 2, 4}, {kWedgeOblique117, 6, 4}}, {{kWedgeOblique27, 4, 4}, {kWedgeOblique63, 4, 4}, {kWedgeOblique117, 4, 4}, {kWedgeOblique153, 4, 4}, {kWedgeVertical, 2, 4}, {kWedgeVertical, 4, 4}, {kWedgeVertical, 6, 4}, {kWedgeHorizontal, 4, 4}, {kWedgeOblique27, 4, 2}, {kWedgeOblique27, 4, 6}, {kWedgeOblique153, 4, 2}, {kWedgeOblique153, 4, 6}, {kWedgeOblique63, 2, 4}, {kWedgeOblique63, 6, 4}, {kWedgeOblique117, 2, 4}, {kWedgeOblique117, 6, 4}}, {{kWedgeOblique27, 4, 4}, {kWedgeOblique63, 4, 4}, {kWedgeOblique117, 4, 4}, {kWedgeOblique153, 4, 4}, {kWedgeHorizontal, 4, 2}, {kWedgeHorizontal, 4, 6}, {kWedgeVertical, 2, 4}, {kWedgeVertical, 6, 4}, {kWedgeOblique27, 4, 2}, {kWedgeOblique27, 4, 6}, {kWedgeOblique153, 4, 2}, {kWedgeOblique153, 4, 6}, {kWedgeOblique63, 2, 4}, {kWedgeOblique63, 6, 4}, {kWedgeOblique117, 2, 4}, {kWedgeOblique117, 6, 4}}}; constexpr BitMaskSet kWedgeFlipSignMasks[9] = { BitMaskSet(0xBBFF), // kBlock8x8 BitMaskSet(0xBBEF), // kBlock8x16 BitMaskSet(0xBAEF), // kBlock8x32 BitMaskSet(0xBBEF), // kBlock16x8 BitMaskSet(0xBBFF), // kBlock16x16 BitMaskSet(0xBBEF), // kBlock16x32 BitMaskSet(0xABEF), // kBlock32x8 BitMaskSet(0xBBEF), // kBlock32x16 BitMaskSet(0xBBFF) // kBlock32x32 }; // This table (and the one below) contains a few leading zeros and trailing 64s // to avoid some additional memcpys where it is actually used. constexpr uint8_t kWedgeMasterObliqueOdd[kWedgeMaskMasterSize * 3 / 2] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 6, 18, 37, 53, 60, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}; constexpr uint8_t kWedgeMasterObliqueEven[kWedgeMaskMasterSize * 3 / 2] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 11, 27, 46, 58, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}; constexpr uint8_t kWedgeMasterVertical[kWedgeMaskMasterSize] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 7, 21, 43, 57, 62, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}; int BlockShape(BlockSize block_size) { const int width = kNum4x4BlocksWide[block_size]; const int height = kNum4x4BlocksHigh[block_size]; if (height > width) return 0; if (height < width) return 1; return 2; } uint8_t GetWedgeDirection(BlockSize block_size, int index) { return kWedgeCodebook[BlockShape(block_size)][index][0]; } uint8_t GetWedgeOffsetX(BlockSize block_size, int index) { return kWedgeCodebook[BlockShape(block_size)][index][1]; } uint8_t GetWedgeOffsetY(BlockSize block_size, int index) { return kWedgeCodebook[BlockShape(block_size)][index][2]; } } // namespace bool GenerateWedgeMask(WedgeMaskArray* const wedge_masks) { // Generate master masks. uint8_t master_mask[6][kWedgeMaskMasterSize][kWedgeMaskMasterSize]; for (int y = 0; y < kWedgeMaskMasterSize; ++y) { memcpy(master_mask[kWedgeVertical][y], kWedgeMasterVertical, kWedgeMaskMasterSize); } for (int y = 0, shift = 0; y < kWedgeMaskMasterSize; y += 2, ++shift) { memcpy(master_mask[kWedgeOblique63][y], kWedgeMasterObliqueEven + shift, kWedgeMaskMasterSize); memcpy(master_mask[kWedgeOblique63][y + 1], kWedgeMasterObliqueOdd + shift, kWedgeMaskMasterSize); } for (int y = 0; y < kWedgeMaskMasterSize; ++y) { for (int x = 0; x < kWedgeMaskMasterSize; ++x) { const uint8_t mask_value = master_mask[kWedgeOblique63][y][x]; master_mask[kWedgeHorizontal][x][y] = master_mask[kWedgeVertical][y][x]; master_mask[kWedgeOblique27][x][y] = mask_value; master_mask[kWedgeOblique117][y][kWedgeMaskMasterSize - 1 - x] = 64 - mask_value; master_mask[kWedgeOblique153][(kWedgeMaskMasterSize - 1 - x)][y] = 64 - mask_value; } } // Generate wedge masks. int block_size_index = 0; for (int size = kBlock8x8; size <= kBlock32x32; ++size) { if (!kIsWedgeCompoundModeAllowed.Contains(size)) continue; const int width = kBlockWidthPixels[size]; const int height = kBlockHeightPixels[size]; assert(width >= 8); assert(width <= 32); assert(height >= 8); assert(height <= 32); const auto block_size = static_cast(size); for (int wedge_index = 0; wedge_index < kWedgeDirectionTypes; ++wedge_index) { const uint8_t direction = GetWedgeDirection(block_size, wedge_index); const uint8_t offset_x = DivideBy2(kWedgeMaskMasterSize) - ((GetWedgeOffsetX(block_size, wedge_index) * width) >> 3); const uint8_t offset_y = DivideBy2(kWedgeMaskMasterSize) - ((GetWedgeOffsetY(block_size, wedge_index) * height) >> 3); // Allocate the 2d array. for (int flip_sign = 0; flip_sign < 2; ++flip_sign) { if (!((*wedge_masks)[block_size_index][flip_sign][wedge_index].Reset( height, width, /*zero_initialize=*/false))) { LIBGAV1_DLOG(ERROR, "Failed to allocate memory for wedge masks."); return false; } } const auto flip_sign = static_cast( kWedgeFlipSignMasks[block_size_index].Contains(wedge_index)); uint8_t* wedge_masks_row = (*wedge_masks)[block_size_index][flip_sign][wedge_index][0]; uint8_t* wedge_masks_row_flip = (*wedge_masks)[block_size_index][1 - flip_sign][wedge_index][0]; uint8_t* master_mask_row = &master_mask[direction][offset_y][offset_x]; for (int y = 0; y < height; ++y) { memcpy(wedge_masks_row, master_mask_row, width); for (int x = 0; x < width; ++x) { wedge_masks_row_flip[x] = 64 - wedge_masks_row[x]; } wedge_masks_row += width; wedge_masks_row_flip += width; master_mask_row += kWedgeMaskMasterSize; } } block_size_index++; } return true; } } // namespace libgav1