1 // Copyright 2019 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/buffer_pool.h"
16 
17 #include <cassert>
18 #include <cstring>
19 
20 #include "src/utils/common.h"
21 #include "src/utils/constants.h"
22 #include "src/utils/logging.h"
23 
24 namespace libgav1 {
25 
26 namespace {
27 
28 // Copies the feature_enabled, feature_data, segment_id_pre_skip, and
29 // last_active_segment_id fields of Segmentation.
CopySegmentationParameters(const Segmentation & from,Segmentation * to)30 void CopySegmentationParameters(const Segmentation& from, Segmentation* to) {
31   memcpy(to->feature_enabled, from.feature_enabled,
32          sizeof(to->feature_enabled));
33   memcpy(to->feature_data, from.feature_data, sizeof(to->feature_data));
34   to->segment_id_pre_skip = from.segment_id_pre_skip;
35   to->last_active_segment_id = from.last_active_segment_id;
36 }
37 
38 }  // namespace
39 
40 RefCountedBuffer::RefCountedBuffer() = default;
41 
42 RefCountedBuffer::~RefCountedBuffer() = default;
43 
Realloc(int bitdepth,bool is_monochrome,int width,int height,int subsampling_x,int subsampling_y,int left_border,int right_border,int top_border,int bottom_border)44 bool RefCountedBuffer::Realloc(int bitdepth, bool is_monochrome, int width,
45                                int height, int subsampling_x, int subsampling_y,
46                                int left_border, int right_border,
47                                int top_border, int bottom_border) {
48   // The YuvBuffer::Realloc() could call the get frame buffer callback which
49   // will need to be thread safe. So we ensure that we only call Realloc() once
50   // at any given time.
51   std::lock_guard<std::mutex> lock(pool_->mutex_);
52   assert(!buffer_private_data_valid_);
53   if (!yuv_buffer_.Realloc(
54           bitdepth, is_monochrome, width, height, subsampling_x, subsampling_y,
55           left_border, right_border, top_border, bottom_border,
56           pool_->get_frame_buffer_, pool_->callback_private_data_,
57           &buffer_private_data_)) {
58     return false;
59   }
60   buffer_private_data_valid_ = true;
61   return true;
62 }
63 
SetFrameDimensions(const ObuFrameHeader & frame_header)64 bool RefCountedBuffer::SetFrameDimensions(const ObuFrameHeader& frame_header) {
65   upscaled_width_ = frame_header.upscaled_width;
66   frame_width_ = frame_header.width;
67   frame_height_ = frame_header.height;
68   render_width_ = frame_header.render_width;
69   render_height_ = frame_header.render_height;
70   rows4x4_ = frame_header.rows4x4;
71   columns4x4_ = frame_header.columns4x4;
72   if (frame_header.refresh_frame_flags != 0 &&
73       !IsIntraFrame(frame_header.frame_type)) {
74     const int rows4x4_half = DivideBy2(rows4x4_);
75     const int columns4x4_half = DivideBy2(columns4x4_);
76     if (!reference_info_.Reset(rows4x4_half, columns4x4_half)) {
77       return false;
78     }
79   }
80   return segmentation_map_.Allocate(rows4x4_, columns4x4_);
81 }
82 
SetGlobalMotions(const std::array<GlobalMotion,kNumReferenceFrameTypes> & global_motions)83 void RefCountedBuffer::SetGlobalMotions(
84     const std::array<GlobalMotion, kNumReferenceFrameTypes>& global_motions) {
85   for (int ref = kReferenceFrameLast; ref <= kReferenceFrameAlternate; ++ref) {
86     static_assert(sizeof(global_motion_[ref].params) ==
87                       sizeof(global_motions[ref].params),
88                   "");
89     memcpy(global_motion_[ref].params, global_motions[ref].params,
90            sizeof(global_motion_[ref].params));
91   }
92 }
93 
SetFrameContext(const SymbolDecoderContext & context)94 void RefCountedBuffer::SetFrameContext(const SymbolDecoderContext& context) {
95   frame_context_ = context;
96   frame_context_.ResetIntraFrameYModeCdf();
97   frame_context_.ResetCounters();
98 }
99 
GetSegmentationParameters(Segmentation * segmentation) const100 void RefCountedBuffer::GetSegmentationParameters(
101     Segmentation* segmentation) const {
102   CopySegmentationParameters(/*from=*/segmentation_, /*to=*/segmentation);
103 }
104 
SetSegmentationParameters(const Segmentation & segmentation)105 void RefCountedBuffer::SetSegmentationParameters(
106     const Segmentation& segmentation) {
107   CopySegmentationParameters(/*from=*/segmentation, /*to=*/&segmentation_);
108 }
109 
SetBufferPool(BufferPool * pool)110 void RefCountedBuffer::SetBufferPool(BufferPool* pool) { pool_ = pool; }
111 
ReturnToBufferPool(RefCountedBuffer * ptr)112 void RefCountedBuffer::ReturnToBufferPool(RefCountedBuffer* ptr) {
113   ptr->pool_->ReturnUnusedBuffer(ptr);
114 }
115 
BufferPool(FrameBufferSizeChangedCallback on_frame_buffer_size_changed,GetFrameBufferCallback get_frame_buffer,ReleaseFrameBufferCallback release_frame_buffer,void * callback_private_data)116 BufferPool::BufferPool(
117     FrameBufferSizeChangedCallback on_frame_buffer_size_changed,
118     GetFrameBufferCallback get_frame_buffer,
119     ReleaseFrameBufferCallback release_frame_buffer,
120     void* callback_private_data) {
121   if (get_frame_buffer != nullptr) {
122     // on_frame_buffer_size_changed may be null.
123     assert(release_frame_buffer != nullptr);
124     on_frame_buffer_size_changed_ = on_frame_buffer_size_changed;
125     get_frame_buffer_ = get_frame_buffer;
126     release_frame_buffer_ = release_frame_buffer;
127     callback_private_data_ = callback_private_data;
128   } else {
129     on_frame_buffer_size_changed_ = OnInternalFrameBufferSizeChanged;
130     get_frame_buffer_ = GetInternalFrameBuffer;
131     release_frame_buffer_ = ReleaseInternalFrameBuffer;
132     callback_private_data_ = &internal_frame_buffers_;
133   }
134 }
135 
~BufferPool()136 BufferPool::~BufferPool() {
137   for (const auto* buffer : buffers_) {
138     if (buffer->in_use_) {
139       assert(false && "RefCountedBuffer still in use at destruction time.");
140       LIBGAV1_DLOG(ERROR, "RefCountedBuffer still in use at destruction time.");
141     }
142     delete buffer;
143   }
144 }
145 
OnFrameBufferSizeChanged(int bitdepth,Libgav1ImageFormat image_format,int width,int height,int left_border,int right_border,int top_border,int bottom_border)146 bool BufferPool::OnFrameBufferSizeChanged(int bitdepth,
147                                           Libgav1ImageFormat image_format,
148                                           int width, int height,
149                                           int left_border, int right_border,
150                                           int top_border, int bottom_border) {
151   if (on_frame_buffer_size_changed_ == nullptr) return true;
152   return on_frame_buffer_size_changed_(callback_private_data_, bitdepth,
153                                        image_format, width, height, left_border,
154                                        right_border, top_border, bottom_border,
155                                        /*stride_alignment=*/16) == kStatusOk;
156 }
157 
GetFreeBuffer()158 RefCountedBufferPtr BufferPool::GetFreeBuffer() {
159   // In frame parallel mode, the GetFreeBuffer() calls from ObuParser all happen
160   // from the same thread serially, but the GetFreeBuffer() call in
161   // DecoderImpl::ApplyFilmGrain can happen from multiple threads at the same
162   // time. So this function has to be thread safe.
163   // TODO(b/142583029): Investigate if the GetFreeBuffer() call in
164   // DecoderImpl::ApplyFilmGrain() call can be serialized so that this function
165   // need not be thread safe.
166   std::unique_lock<std::mutex> lock(mutex_);
167   for (auto buffer : buffers_) {
168     if (!buffer->in_use_) {
169       buffer->in_use_ = true;
170       buffer->progress_row_ = -1;
171       buffer->frame_state_ = kFrameStateUnknown;
172       lock.unlock();
173       return RefCountedBufferPtr(buffer, RefCountedBuffer::ReturnToBufferPool);
174     }
175   }
176   lock.unlock();
177   auto* const buffer = new (std::nothrow) RefCountedBuffer();
178   if (buffer == nullptr) {
179     LIBGAV1_DLOG(ERROR, "Failed to allocate a new reference counted buffer.");
180     return RefCountedBufferPtr();
181   }
182   buffer->SetBufferPool(this);
183   buffer->in_use_ = true;
184   buffer->progress_row_ = -1;
185   buffer->frame_state_ = kFrameStateUnknown;
186   lock.lock();
187   const bool ok = buffers_.push_back(buffer);
188   lock.unlock();
189   if (!ok) {
190     LIBGAV1_DLOG(
191         ERROR,
192         "Failed to push the new reference counted buffer into the vector.");
193     delete buffer;
194     return RefCountedBufferPtr();
195   }
196   return RefCountedBufferPtr(buffer, RefCountedBuffer::ReturnToBufferPool);
197 }
198 
Abort()199 void BufferPool::Abort() {
200   std::unique_lock<std::mutex> lock(mutex_);
201   for (auto buffer : buffers_) {
202     if (buffer->in_use_) {
203       buffer->Abort();
204     }
205   }
206 }
207 
ReturnUnusedBuffer(RefCountedBuffer * buffer)208 void BufferPool::ReturnUnusedBuffer(RefCountedBuffer* buffer) {
209   std::lock_guard<std::mutex> lock(mutex_);
210   assert(buffer->in_use_);
211   buffer->in_use_ = false;
212   if (buffer->buffer_private_data_valid_) {
213     release_frame_buffer_(callback_private_data_, buffer->buffer_private_data_);
214     buffer->buffer_private_data_valid_ = false;
215   }
216 }
217 
218 }  // namespace libgav1
219