• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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