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