• 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 <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