1 /* 2 * Copyright 2019 The libgav1 Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef LIBGAV1_SRC_BUFFER_POOL_H_ 18 #define LIBGAV1_SRC_BUFFER_POOL_H_ 19 20 #include <array> 21 #include <cassert> 22 #include <climits> 23 #include <condition_variable> // NOLINT (unapproved c++11 header) 24 #include <cstdint> 25 #include <cstring> 26 #include <mutex> // NOLINT (unapproved c++11 header) 27 28 #include "src/dsp/common.h" 29 #include "src/gav1/decoder_buffer.h" 30 #include "src/gav1/frame_buffer.h" 31 #include "src/internal_frame_buffer_list.h" 32 #include "src/symbol_decoder_context.h" 33 #include "src/utils/compiler_attributes.h" 34 #include "src/utils/constants.h" 35 #include "src/utils/reference_info.h" 36 #include "src/utils/segmentation.h" 37 #include "src/utils/segmentation_map.h" 38 #include "src/utils/types.h" 39 #include "src/utils/vector.h" 40 #include "src/yuv_buffer.h" 41 42 namespace libgav1 { 43 44 class BufferPool; 45 46 enum FrameState : uint8_t { 47 kFrameStateUnknown, 48 kFrameStateStarted, 49 kFrameStateParsed, 50 kFrameStateDecoded 51 }; 52 53 // A reference-counted frame buffer. Clients should access it via 54 // RefCountedBufferPtr, which manages reference counting transparently. 55 class RefCountedBuffer { 56 public: 57 // Not copyable or movable. 58 RefCountedBuffer(const RefCountedBuffer&) = delete; 59 RefCountedBuffer& operator=(const RefCountedBuffer&) = delete; 60 61 // Allocates the YUV buffer. Returns true on success. Returns false on 62 // failure. This function ensures the thread safety of the |get_frame_buffer_| 63 // call (i.e.) only one |get_frame_buffer_| call will happen at a given time. 64 // TODO(b/142583029): In frame parallel mode, we can require the callbacks to 65 // be thread safe so that we can remove the thread safety of this function and 66 // applications can have fine grained locks. 67 // 68 // * |width| and |height| are the image dimensions in pixels. 69 // * |subsampling_x| and |subsampling_y| (either 0 or 1) specify the 70 // subsampling of the width and height of the chroma planes, respectively. 71 // * |left_border|, |right_border|, |top_border|, and |bottom_border| are 72 // the sizes (in pixels) of the borders on the left, right, top, and 73 // bottom sides, respectively. 74 // 75 // NOTE: The strides are a multiple of 16. Since the first row in each plane 76 // is 16-byte aligned, subsequent rows are also 16-byte aligned. 77 bool Realloc(int bitdepth, bool is_monochrome, int width, int height, 78 int subsampling_x, int subsampling_y, int left_border, 79 int right_border, int top_border, int bottom_border); 80 buffer()81 YuvBuffer* buffer() { return &yuv_buffer_; } 82 83 // Returns the buffer private data set by the get frame buffer callback when 84 // it allocated the YUV buffer. buffer_private_data()85 void* buffer_private_data() const { 86 assert(buffer_private_data_valid_); 87 return buffer_private_data_; 88 } 89 90 // NOTE: In the current frame, this is the frame_type syntax element in the 91 // frame header. In a reference frame, this implements the RefFrameType array 92 // in the spec. frame_type()93 FrameType frame_type() const { return frame_type_; } set_frame_type(FrameType frame_type)94 void set_frame_type(FrameType frame_type) { frame_type_ = frame_type; } 95 96 // The sample position for subsampled streams. This is the 97 // chroma_sample_position syntax element in the sequence header. 98 // 99 // NOTE: The decoder does not use chroma_sample_position, but it needs to be 100 // passed on to the client in DecoderBuffer. chroma_sample_position()101 ChromaSamplePosition chroma_sample_position() const { 102 return chroma_sample_position_; 103 } set_chroma_sample_position(ChromaSamplePosition chroma_sample_position)104 void set_chroma_sample_position(ChromaSamplePosition chroma_sample_position) { 105 chroma_sample_position_ = chroma_sample_position; 106 } 107 108 // Whether the frame can be used as show existing frame in the future. showable_frame()109 bool showable_frame() const { return showable_frame_; } set_showable_frame(bool value)110 void set_showable_frame(bool value) { showable_frame_ = value; } 111 112 // Sets upscaled_width_, frame_width_, frame_height_, render_width_, 113 // render_height_, rows4x4_ and columns4x4_ from the corresponding fields 114 // in frame_header. Allocates reference_info_.motion_field_reference_frame, 115 // reference_info_.motion_field_mv_, and segmentation_map_. Returns true on 116 // success, false on failure. 117 bool SetFrameDimensions(const ObuFrameHeader& frame_header); 118 upscaled_width()119 int32_t upscaled_width() const { return upscaled_width_; } frame_width()120 int32_t frame_width() const { return frame_width_; } frame_height()121 int32_t frame_height() const { return frame_height_; } 122 // RenderWidth() and RenderHeight() return the render size, which is a hint 123 // to the application about the desired display size. render_width()124 int32_t render_width() const { return render_width_; } render_height()125 int32_t render_height() const { return render_height_; } rows4x4()126 int32_t rows4x4() const { return rows4x4_; } columns4x4()127 int32_t columns4x4() const { return columns4x4_; } 128 spatial_id()129 int spatial_id() const { return spatial_id_; } set_spatial_id(int value)130 void set_spatial_id(int value) { spatial_id_ = value; } temporal_id()131 int temporal_id() const { return temporal_id_; } set_temporal_id(int value)132 void set_temporal_id(int value) { temporal_id_ = value; } 133 segmentation_map()134 SegmentationMap* segmentation_map() { return &segmentation_map_; } segmentation_map()135 const SegmentationMap* segmentation_map() const { return &segmentation_map_; } 136 137 // Only the |params| field of each GlobalMotion struct should be used. GlobalMotions()138 const std::array<GlobalMotion, kNumReferenceFrameTypes>& GlobalMotions() 139 const { 140 return global_motion_; 141 } 142 // Saves the GlobalMotion array. Only the |params| field of each GlobalMotion 143 // struct is saved. 144 void SetGlobalMotions( 145 const std::array<GlobalMotion, kNumReferenceFrameTypes>& global_motions); 146 147 // Returns the saved CDF tables. FrameContext()148 const SymbolDecoderContext& FrameContext() const { return frame_context_; } 149 // Saves the CDF tables. The intra_frame_y_mode_cdf table is reset to the 150 // default. The last entry in each table, representing the symbol count for 151 // that context, is set to 0. 152 void SetFrameContext(const SymbolDecoderContext& context); 153 loop_filter_ref_deltas()154 const std::array<int8_t, kNumReferenceFrameTypes>& loop_filter_ref_deltas() 155 const { 156 return loop_filter_ref_deltas_; 157 } loop_filter_mode_deltas()158 const std::array<int8_t, kLoopFilterMaxModeDeltas>& loop_filter_mode_deltas() 159 const { 160 return loop_filter_mode_deltas_; 161 } 162 // Saves the ref_deltas and mode_deltas arrays in loop_filter. SetLoopFilterDeltas(const LoopFilter & loop_filter)163 void SetLoopFilterDeltas(const LoopFilter& loop_filter) { 164 loop_filter_ref_deltas_ = loop_filter.ref_deltas; 165 loop_filter_mode_deltas_ = loop_filter.mode_deltas; 166 } 167 168 // Copies the saved values of the following fields to the Segmentation 169 // struct: feature_enabled, feature_data, segment_id_pre_skip, and 170 // last_active_segment_id. The other fields are left unchanged. 171 void GetSegmentationParameters(Segmentation* segmentation) const; 172 // Saves the feature_enabled, feature_data, segment_id_pre_skip, and 173 // last_active_segment_id fields of the Segmentation struct. 174 void SetSegmentationParameters(const Segmentation& segmentation); 175 film_grain_params()176 const FilmGrainParams& film_grain_params() const { 177 return film_grain_params_; 178 } set_film_grain_params(const FilmGrainParams & params)179 void set_film_grain_params(const FilmGrainParams& params) { 180 film_grain_params_ = params; 181 } 182 reference_info()183 const ReferenceInfo* reference_info() const { return &reference_info_; } reference_info()184 ReferenceInfo* reference_info() { return &reference_info_; } 185 186 // This will wake up the WaitUntil*() functions and make them return false. Abort()187 void Abort() { 188 { 189 std::lock_guard<std::mutex> lock(mutex_); 190 abort_ = true; 191 } 192 parsed_condvar_.notify_all(); 193 decoded_condvar_.notify_all(); 194 progress_row_condvar_.notify_all(); 195 } 196 SetFrameState(FrameState frame_state)197 void SetFrameState(FrameState frame_state) { 198 { 199 std::lock_guard<std::mutex> lock(mutex_); 200 frame_state_ = frame_state; 201 } 202 if (frame_state == kFrameStateParsed) { 203 parsed_condvar_.notify_all(); 204 } else if (frame_state == kFrameStateDecoded) { 205 decoded_condvar_.notify_all(); 206 progress_row_condvar_.notify_all(); 207 } 208 } 209 210 // Sets the progress of this frame to |progress_row| and notifies any threads 211 // that may be waiting on rows <= |progress_row|. SetProgress(int progress_row)212 void SetProgress(int progress_row) { 213 { 214 std::lock_guard<std::mutex> lock(mutex_); 215 if (progress_row_ >= progress_row) return; 216 progress_row_ = progress_row; 217 } 218 progress_row_condvar_.notify_all(); 219 } 220 MarkFrameAsStarted()221 void MarkFrameAsStarted() { 222 std::lock_guard<std::mutex> lock(mutex_); 223 if (frame_state_ != kFrameStateUnknown) return; 224 frame_state_ = kFrameStateStarted; 225 } 226 227 // All the WaitUntil* functions will return true if the desired wait state was 228 // reached successfully. If the return value is false, then the caller must 229 // assume that the wait was not successful and try to stop whatever they are 230 // doing as early as possible. 231 232 // Waits until the frame has been parsed. WaitUntilParsed()233 bool WaitUntilParsed() { 234 std::unique_lock<std::mutex> lock(mutex_); 235 while (frame_state_ < kFrameStateParsed && !abort_) { 236 parsed_condvar_.wait(lock); 237 } 238 return !abort_; 239 } 240 241 // Waits until the |progress_row| has been decoded (as indicated either by 242 // |progress_row_| or |frame_state_|). |progress_row_cache| must not be 243 // nullptr and will be populated with the value of |progress_row_| after the 244 // wait. 245 // 246 // Typical usage of |progress_row_cache| is as follows: 247 // * Initialize |*progress_row_cache| to INT_MIN. 248 // * Call WaitUntil only if |*progress_row_cache| < |progress_row|. WaitUntil(int progress_row,int * progress_row_cache)249 bool WaitUntil(int progress_row, int* progress_row_cache) { 250 // If |progress_row| is negative, it means that the wait is on the top 251 // border to be available. The top border will be available when row 0 has 252 // been decoded. So we can simply wait on row 0 instead. 253 progress_row = std::max(progress_row, 0); 254 std::unique_lock<std::mutex> lock(mutex_); 255 while (progress_row_ < progress_row && frame_state_ != kFrameStateDecoded && 256 !abort_) { 257 progress_row_condvar_.wait(lock); 258 } 259 // Once |frame_state_| reaches kFrameStateDecoded, |progress_row_| may no 260 // longer be updated. So we set |*progress_row_cache| to INT_MAX in that 261 // case. 262 *progress_row_cache = 263 (frame_state_ != kFrameStateDecoded) ? progress_row_ : INT_MAX; 264 return !abort_; 265 } 266 267 // Waits until the entire frame has been decoded. WaitUntilDecoded()268 bool WaitUntilDecoded() { 269 std::unique_lock<std::mutex> lock(mutex_); 270 while (frame_state_ != kFrameStateDecoded && !abort_) { 271 decoded_condvar_.wait(lock); 272 } 273 return !abort_; 274 } 275 276 private: 277 friend class BufferPool; 278 279 // Methods for BufferPool: 280 RefCountedBuffer(); 281 ~RefCountedBuffer(); 282 void SetBufferPool(BufferPool* pool); 283 static void ReturnToBufferPool(RefCountedBuffer* ptr); 284 285 BufferPool* pool_ = nullptr; 286 bool buffer_private_data_valid_ = false; 287 void* buffer_private_data_ = nullptr; 288 YuvBuffer yuv_buffer_; 289 bool in_use_ = false; // Only used by BufferPool. 290 291 std::mutex mutex_; 292 FrameState frame_state_ = kFrameStateUnknown LIBGAV1_GUARDED_BY(mutex_); 293 int progress_row_ = -1 LIBGAV1_GUARDED_BY(mutex_); 294 // Signaled when progress_row_ is updated or when frame_state_ is set to 295 // kFrameStateDecoded. 296 std::condition_variable progress_row_condvar_; 297 // Signaled when the frame state is set to kFrameStateParsed. 298 std::condition_variable parsed_condvar_; 299 // Signaled when the frame state is set to kFrameStateDecoded. 300 std::condition_variable decoded_condvar_; 301 bool abort_ = false LIBGAV1_GUARDED_BY(mutex_); 302 303 FrameType frame_type_ = kFrameKey; 304 ChromaSamplePosition chroma_sample_position_ = kChromaSamplePositionUnknown; 305 bool showable_frame_ = false; 306 307 int32_t upscaled_width_ = 0; 308 int32_t frame_width_ = 0; 309 int32_t frame_height_ = 0; 310 int32_t render_width_ = 0; 311 int32_t render_height_ = 0; 312 int32_t columns4x4_ = 0; 313 int32_t rows4x4_ = 0; 314 int spatial_id_ = 0; 315 int temporal_id_ = 0; 316 317 // segmentation_map_ contains a rows4x4_ by columns4x4_ 2D array. 318 SegmentationMap segmentation_map_; 319 320 // Only the |params| field of each GlobalMotion struct is used. 321 // global_motion_[0] (for kReferenceFrameIntra) is not used. 322 std::array<GlobalMotion, kNumReferenceFrameTypes> global_motion_ = {}; 323 SymbolDecoderContext frame_context_; 324 std::array<int8_t, kNumReferenceFrameTypes> loop_filter_ref_deltas_; 325 std::array<int8_t, kLoopFilterMaxModeDeltas> loop_filter_mode_deltas_; 326 // Only the feature_enabled, feature_data, segment_id_pre_skip, and 327 // last_active_segment_id fields of the Segmentation struct are used. 328 // 329 // Note: The spec only requires that we save feature_enabled and 330 // feature_data. Since segment_id_pre_skip and last_active_segment_id depend 331 // on feature_enabled only, we also save their values as an optimization. 332 Segmentation segmentation_ = {}; 333 FilmGrainParams film_grain_params_ = {}; 334 ReferenceInfo reference_info_; 335 }; 336 337 // RefCountedBufferPtr contains a reference to a RefCountedBuffer. 338 // 339 // Note: For simplicity, RefCountedBufferPtr is implemented as a 340 // std::shared_ptr<RefCountedBuffer>. This requires a heap allocation of the 341 // control block for std::shared_ptr. To avoid that heap allocation, we can 342 // add a |ref_count_| field to RefCountedBuffer and implement a custom 343 // RefCountedBufferPtr class. 344 using RefCountedBufferPtr = std::shared_ptr<RefCountedBuffer>; 345 346 // BufferPool maintains a pool of RefCountedBuffers. 347 class BufferPool { 348 public: 349 BufferPool(FrameBufferSizeChangedCallback on_frame_buffer_size_changed, 350 GetFrameBufferCallback get_frame_buffer, 351 ReleaseFrameBufferCallback release_frame_buffer, 352 void* callback_private_data); 353 354 // Not copyable or movable. 355 BufferPool(const BufferPool&) = delete; 356 BufferPool& operator=(const BufferPool&) = delete; 357 358 ~BufferPool(); 359 360 LIBGAV1_MUST_USE_RESULT bool OnFrameBufferSizeChanged( 361 int bitdepth, Libgav1ImageFormat image_format, int width, int height, 362 int left_border, int right_border, int top_border, int bottom_border); 363 364 // Finds a free buffer in the buffer pool and returns a reference to the free 365 // buffer. If there is no free buffer, returns a null pointer. This function 366 // is thread safe. 367 RefCountedBufferPtr GetFreeBuffer(); 368 369 // Aborts all the buffers that are in use. 370 void Abort(); 371 372 private: 373 friend class RefCountedBuffer; 374 375 // Returns an unused buffer to the buffer pool. Called by RefCountedBuffer 376 // only. This function is thread safe. 377 void ReturnUnusedBuffer(RefCountedBuffer* buffer); 378 379 // Used to make the following functions thread safe: GetFreeBuffer(), 380 // ReturnUnusedBuffer(), RefCountedBuffer::Realloc(). 381 std::mutex mutex_; 382 383 // Storing a RefCountedBuffer object in a Vector is complicated because of the 384 // copy/move semantics. So the simplest way around that is to store a list of 385 // pointers in the vector. 386 Vector<RefCountedBuffer*> buffers_ LIBGAV1_GUARDED_BY(mutex_); 387 InternalFrameBufferList internal_frame_buffers_; 388 389 // Frame buffer callbacks. 390 FrameBufferSizeChangedCallback on_frame_buffer_size_changed_; 391 GetFrameBufferCallback get_frame_buffer_; 392 ReleaseFrameBufferCallback release_frame_buffer_; 393 // Private data associated with the frame buffer callbacks. 394 void* callback_private_data_; 395 }; 396 397 } // namespace libgav1 398 399 #endif // LIBGAV1_SRC_BUFFER_POOL_H_ 400