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