1*77c1e3ccSAndroid Build Coastguard Worker /* 2*77c1e3ccSAndroid Build Coastguard Worker * Copyright (c) 2022, Alliance for Open Media. All rights reserved. 3*77c1e3ccSAndroid Build Coastguard Worker * 4*77c1e3ccSAndroid Build Coastguard Worker * This source code is subject to the terms of the BSD 2 Clause License and 5*77c1e3ccSAndroid Build Coastguard Worker * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 6*77c1e3ccSAndroid Build Coastguard Worker * was not distributed with this source code in the LICENSE file, you can 7*77c1e3ccSAndroid Build Coastguard Worker * obtain it at www.aomedia.org/license/software. If the Alliance for Open 8*77c1e3ccSAndroid Build Coastguard Worker * Media Patent License 1.0 was not distributed with this source code in the 9*77c1e3ccSAndroid Build Coastguard Worker * PATENTS file, you can obtain it at www.aomedia.org/license/patent. 10*77c1e3ccSAndroid Build Coastguard Worker */ 11*77c1e3ccSAndroid Build Coastguard Worker 12*77c1e3ccSAndroid Build Coastguard Worker #ifndef AOM_AOM_DSP_PYRAMID_H_ 13*77c1e3ccSAndroid Build Coastguard Worker #define AOM_AOM_DSP_PYRAMID_H_ 14*77c1e3ccSAndroid Build Coastguard Worker 15*77c1e3ccSAndroid Build Coastguard Worker #include <stddef.h> 16*77c1e3ccSAndroid Build Coastguard Worker #include <stdint.h> 17*77c1e3ccSAndroid Build Coastguard Worker #include <stdbool.h> 18*77c1e3ccSAndroid Build Coastguard Worker 19*77c1e3ccSAndroid Build Coastguard Worker #include "config/aom_config.h" 20*77c1e3ccSAndroid Build Coastguard Worker 21*77c1e3ccSAndroid Build Coastguard Worker #include "aom_scale/yv12config.h" 22*77c1e3ccSAndroid Build Coastguard Worker #include "aom_util/aom_pthread.h" 23*77c1e3ccSAndroid Build Coastguard Worker 24*77c1e3ccSAndroid Build Coastguard Worker #ifdef __cplusplus 25*77c1e3ccSAndroid Build Coastguard Worker extern "C" { 26*77c1e3ccSAndroid Build Coastguard Worker #endif 27*77c1e3ccSAndroid Build Coastguard Worker 28*77c1e3ccSAndroid Build Coastguard Worker // Minimum dimensions of a downsampled image 29*77c1e3ccSAndroid Build Coastguard Worker #define MIN_PYRAMID_SIZE_LOG2 3 30*77c1e3ccSAndroid Build Coastguard Worker #define MIN_PYRAMID_SIZE (1 << MIN_PYRAMID_SIZE_LOG2) 31*77c1e3ccSAndroid Build Coastguard Worker 32*77c1e3ccSAndroid Build Coastguard Worker // Size of border around each pyramid image, in pixels 33*77c1e3ccSAndroid Build Coastguard Worker // Similarly to the border around regular image buffers, this border is filled 34*77c1e3ccSAndroid Build Coastguard Worker // with copies of the outermost pixels of the frame, to allow for more efficient 35*77c1e3ccSAndroid Build Coastguard Worker // convolution code 36*77c1e3ccSAndroid Build Coastguard Worker // TODO(rachelbarker): How many pixels do we actually need here? 37*77c1e3ccSAndroid Build Coastguard Worker // I think we only need 9 for disflow, but how many for corner matching? 38*77c1e3ccSAndroid Build Coastguard Worker #define PYRAMID_PADDING 16 39*77c1e3ccSAndroid Build Coastguard Worker 40*77c1e3ccSAndroid Build Coastguard Worker // Byte alignment of each line within the image pyramids. 41*77c1e3ccSAndroid Build Coastguard Worker // That is, the first pixel inside the image (ie, not in the border region), 42*77c1e3ccSAndroid Build Coastguard Worker // on each row of each pyramid level, is aligned to this byte alignment. 43*77c1e3ccSAndroid Build Coastguard Worker // This value must be a power of 2. 44*77c1e3ccSAndroid Build Coastguard Worker #define PYRAMID_ALIGNMENT 32 45*77c1e3ccSAndroid Build Coastguard Worker 46*77c1e3ccSAndroid Build Coastguard Worker typedef struct { 47*77c1e3ccSAndroid Build Coastguard Worker uint8_t *buffer; 48*77c1e3ccSAndroid Build Coastguard Worker int width; 49*77c1e3ccSAndroid Build Coastguard Worker int height; 50*77c1e3ccSAndroid Build Coastguard Worker int stride; 51*77c1e3ccSAndroid Build Coastguard Worker } PyramidLayer; 52*77c1e3ccSAndroid Build Coastguard Worker 53*77c1e3ccSAndroid Build Coastguard Worker // Struct for an image pyramid 54*77c1e3ccSAndroid Build Coastguard Worker typedef struct image_pyramid { 55*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_MULTITHREAD 56*77c1e3ccSAndroid Build Coastguard Worker // Mutex which is used to prevent the pyramid being computed twice at the 57*77c1e3ccSAndroid Build Coastguard Worker // same time 58*77c1e3ccSAndroid Build Coastguard Worker // 59*77c1e3ccSAndroid Build Coastguard Worker // Semantics: 60*77c1e3ccSAndroid Build Coastguard Worker // * This mutex must be held whenever reading or writing the 61*77c1e3ccSAndroid Build Coastguard Worker // `filled_levels` field 62*77c1e3ccSAndroid Build Coastguard Worker // 63*77c1e3ccSAndroid Build Coastguard Worker // * This mutex must also be held while computing the image pyramid, 64*77c1e3ccSAndroid Build Coastguard Worker // to ensure that only one thread may do so at a time. 65*77c1e3ccSAndroid Build Coastguard Worker // 66*77c1e3ccSAndroid Build Coastguard Worker // * However, once you have read the filled_levels field and observed 67*77c1e3ccSAndroid Build Coastguard Worker // a value N, it is safe to drop the mutex and read from the remaining 68*77c1e3ccSAndroid Build Coastguard Worker // fields, including the first N pyramid levels (but no higher). 69*77c1e3ccSAndroid Build Coastguard Worker // Note that filled_levels must be read once and cached in a local variable 70*77c1e3ccSAndroid Build Coastguard Worker // in order for this to be safe - it cannot be re-read without retaking 71*77c1e3ccSAndroid Build Coastguard Worker // the mutex. 72*77c1e3ccSAndroid Build Coastguard Worker // 73*77c1e3ccSAndroid Build Coastguard Worker // This works because, once the image pyramid is computed, its contents 74*77c1e3ccSAndroid Build Coastguard Worker // will not be changed until the parent frame buffer is recycled, 75*77c1e3ccSAndroid Build Coastguard Worker // which will not happen until there are no more outstanding references 76*77c1e3ccSAndroid Build Coastguard Worker // to the frame buffer. 77*77c1e3ccSAndroid Build Coastguard Worker pthread_mutex_t mutex; 78*77c1e3ccSAndroid Build Coastguard Worker #endif 79*77c1e3ccSAndroid Build Coastguard Worker // Maximum number of levels for the given frame size 80*77c1e3ccSAndroid Build Coastguard Worker // We always allocate enough memory for this many levels, as the memory 81*77c1e3ccSAndroid Build Coastguard Worker // cost of higher levels of the pyramid is minimal. 82*77c1e3ccSAndroid Build Coastguard Worker int max_levels; 83*77c1e3ccSAndroid Build Coastguard Worker // Number of levels which currently hold valid data 84*77c1e3ccSAndroid Build Coastguard Worker int filled_levels; 85*77c1e3ccSAndroid Build Coastguard Worker // Pointer to allocated buffer 86*77c1e3ccSAndroid Build Coastguard Worker uint8_t *buffer_alloc; 87*77c1e3ccSAndroid Build Coastguard Worker // Data for each level 88*77c1e3ccSAndroid Build Coastguard Worker // The `buffer` pointers inside this array point into the region which 89*77c1e3ccSAndroid Build Coastguard Worker // is stored in the `buffer_alloc` field here 90*77c1e3ccSAndroid Build Coastguard Worker PyramidLayer *layers; 91*77c1e3ccSAndroid Build Coastguard Worker } ImagePyramid; 92*77c1e3ccSAndroid Build Coastguard Worker 93*77c1e3ccSAndroid Build Coastguard Worker size_t aom_get_pyramid_alloc_size(int width, int height, bool image_is_16bit); 94*77c1e3ccSAndroid Build Coastguard Worker 95*77c1e3ccSAndroid Build Coastguard Worker ImagePyramid *aom_alloc_pyramid(int width, int height, bool image_is_16bit); 96*77c1e3ccSAndroid Build Coastguard Worker 97*77c1e3ccSAndroid Build Coastguard Worker // Fill out a downsampling pyramid for a given frame. 98*77c1e3ccSAndroid Build Coastguard Worker // 99*77c1e3ccSAndroid Build Coastguard Worker // The top level (index 0) will always be an 8-bit copy of the input frame, 100*77c1e3ccSAndroid Build Coastguard Worker // regardless of the input bit depth. Additional levels are then downscaled 101*77c1e3ccSAndroid Build Coastguard Worker // by powers of 2. 102*77c1e3ccSAndroid Build Coastguard Worker // 103*77c1e3ccSAndroid Build Coastguard Worker // This function will ensure that the first `n_levels` levels of the pyramid 104*77c1e3ccSAndroid Build Coastguard Worker // are filled, unless the frame is too small to have this many levels. 105*77c1e3ccSAndroid Build Coastguard Worker // In that case, we will fill all available levels and then stop. 106*77c1e3ccSAndroid Build Coastguard Worker // 107*77c1e3ccSAndroid Build Coastguard Worker // Returns the actual number of levels filled, capped at n_levels, 108*77c1e3ccSAndroid Build Coastguard Worker // or -1 on error. 109*77c1e3ccSAndroid Build Coastguard Worker int aom_compute_pyramid(const YV12_BUFFER_CONFIG *frame, int bit_depth, 110*77c1e3ccSAndroid Build Coastguard Worker int n_levels, ImagePyramid *pyr); 111*77c1e3ccSAndroid Build Coastguard Worker 112*77c1e3ccSAndroid Build Coastguard Worker #ifndef NDEBUG 113*77c1e3ccSAndroid Build Coastguard Worker // Check if a pyramid has already been computed to at least n levels 114*77c1e3ccSAndroid Build Coastguard Worker // This is mostly a debug helper - as it is necessary to hold pyr->mutex 115*77c1e3ccSAndroid Build Coastguard Worker // while reading the number of already-computed levels, we cannot just write: 116*77c1e3ccSAndroid Build Coastguard Worker // assert(pyr->filled_levels >= n_levels); 117*77c1e3ccSAndroid Build Coastguard Worker // This function allows the check to be correctly written as: 118*77c1e3ccSAndroid Build Coastguard Worker // assert(aom_is_pyramid_valid(pyr, n_levels)); 119*77c1e3ccSAndroid Build Coastguard Worker // 120*77c1e3ccSAndroid Build Coastguard Worker // Note: This deliberately does not restrict n_levels based on the maximum 121*77c1e3ccSAndroid Build Coastguard Worker // number of permitted levels for the frame size. This allows the check to 122*77c1e3ccSAndroid Build Coastguard Worker // catch cases where the caller forgets to handle the case where 123*77c1e3ccSAndroid Build Coastguard Worker // max_levels is less than the requested number of levels 124*77c1e3ccSAndroid Build Coastguard Worker bool aom_is_pyramid_valid(ImagePyramid *pyr, int n_levels); 125*77c1e3ccSAndroid Build Coastguard Worker #endif 126*77c1e3ccSAndroid Build Coastguard Worker 127*77c1e3ccSAndroid Build Coastguard Worker // Mark a pyramid as no longer containing valid data. 128*77c1e3ccSAndroid Build Coastguard Worker // This must be done whenever the corresponding frame buffer is reused 129*77c1e3ccSAndroid Build Coastguard Worker void aom_invalidate_pyramid(ImagePyramid *pyr); 130*77c1e3ccSAndroid Build Coastguard Worker 131*77c1e3ccSAndroid Build Coastguard Worker // Release the memory associated with a pyramid 132*77c1e3ccSAndroid Build Coastguard Worker void aom_free_pyramid(ImagePyramid *pyr); 133*77c1e3ccSAndroid Build Coastguard Worker 134*77c1e3ccSAndroid Build Coastguard Worker #ifdef __cplusplus 135*77c1e3ccSAndroid Build Coastguard Worker } 136*77c1e3ccSAndroid Build Coastguard Worker #endif 137*77c1e3ccSAndroid Build Coastguard Worker 138*77c1e3ccSAndroid Build Coastguard Worker #endif // AOM_AOM_DSP_PYRAMID_H_ 139