• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <array>
18 #include <cassert>
19 #include <cstring>
20 #include <mutex>  // NOLINT (unapproved c++11 header)
21 #include <new>
22 
23 #include "src/utils/common.h"
24 #include "src/utils/constants.h"
25 #include "src/utils/logging.h"
26 
27 namespace libgav1 {
28 
29 namespace {
30 
31 // Copies the feature_enabled, feature_data, segment_id_pre_skip, and
32 // last_active_segment_id fields of Segmentation.
CopySegmentationParameters(const Segmentation & from,Segmentation * to)33 void CopySegmentationParameters(const Segmentation& from, Segmentation* to) {
34   memcpy(to->feature_enabled, from.feature_enabled,
35          sizeof(to->feature_enabled));
36   memcpy(to->feature_data, from.feature_data, sizeof(to->feature_data));
37   to->segment_id_pre_skip = from.segment_id_pre_skip;
38   to->last_active_segment_id = from.last_active_segment_id;
39 }
40 
41 }  // namespace
42 
43 RefCountedBuffer::RefCountedBuffer() = default;
44 
45 RefCountedBuffer::~RefCountedBuffer() = default;
46 
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)47 bool RefCountedBuffer::Realloc(int bitdepth, bool is_monochrome, int width,
48                                int height, int subsampling_x, int subsampling_y,
49                                int left_border, int right_border,
50                                int top_border, int bottom_border) {
51   // The YuvBuffer::Realloc() could call the get frame buffer callback which
52   // will need to be thread safe. So we ensure that we only call Realloc() once
53   // at any given time.
54   std::lock_guard<std::mutex> lock(pool_->mutex_);
55   assert(!buffer_private_data_valid_);
56   if (!yuv_buffer_.Realloc(
57           bitdepth, is_monochrome, width, height, subsampling_x, subsampling_y,
58           left_border, right_border, top_border, bottom_border,
59           pool_->get_frame_buffer_, pool_->callback_private_data_,
60           &buffer_private_data_)) {
61     return false;
62   }
63   buffer_private_data_valid_ = true;
64   return true;
65 }
66 
SetFrameDimensions(const ObuFrameHeader & frame_header)67 bool RefCountedBuffer::SetFrameDimensions(const ObuFrameHeader& frame_header) {
68   upscaled_width_ = frame_header.upscaled_width;
69   frame_width_ = frame_header.width;
70   frame_height_ = frame_header.height;
71   render_width_ = frame_header.render_width;
72   render_height_ = frame_header.render_height;
73   rows4x4_ = frame_header.rows4x4;
74   columns4x4_ = frame_header.columns4x4;
75   if (frame_header.refresh_frame_flags != 0 &&
76       !IsIntraFrame(frame_header.frame_type)) {
77     const int rows4x4_half = DivideBy2(rows4x4_);
78     const int columns4x4_half = DivideBy2(columns4x4_);
79     if (!reference_info_.Reset(rows4x4_half, columns4x4_half)) {
80       return false;
81     }
82   }
83   return segmentation_map_.Allocate(rows4x4_, columns4x4_);
84 }
85 
SetGlobalMotions(const std::array<GlobalMotion,kNumReferenceFrameTypes> & global_motions)86 void RefCountedBuffer::SetGlobalMotions(
87     const std::array<GlobalMotion, kNumReferenceFrameTypes>& global_motions) {
88   for (int ref = kReferenceFrameLast; ref <= kReferenceFrameAlternate; ++ref) {
89     static_assert(sizeof(global_motion_[ref].params) ==
90                       sizeof(global_motions[ref].params),
91                   "");
92     memcpy(global_motion_[ref].params, global_motions[ref].params,
93            sizeof(global_motion_[ref].params));
94   }
95 }
96 
SetFrameContext(const SymbolDecoderContext & context)97 void RefCountedBuffer::SetFrameContext(const SymbolDecoderContext& context) {
98   frame_context_ = context;
99   frame_context_.ResetIntraFrameYModeCdf();
100   frame_context_.ResetCounters();
101 }
102 
GetSegmentationParameters(Segmentation * segmentation) const103 void RefCountedBuffer::GetSegmentationParameters(
104     Segmentation* segmentation) const {
105   CopySegmentationParameters(/*from=*/segmentation_, /*to=*/segmentation);
106 }
107 
SetSegmentationParameters(const Segmentation & segmentation)108 void RefCountedBuffer::SetSegmentationParameters(
109     const Segmentation& segmentation) {
110   CopySegmentationParameters(/*from=*/segmentation, /*to=*/&segmentation_);
111 }
112 
SetBufferPool(BufferPool * pool)113 void RefCountedBuffer::SetBufferPool(BufferPool* pool) { pool_ = pool; }
114 
ReturnToBufferPool(RefCountedBuffer * ptr)115 void RefCountedBuffer::ReturnToBufferPool(RefCountedBuffer* ptr) {
116   ptr->pool_->ReturnUnusedBuffer(ptr);
117 }
118 
BufferPool(FrameBufferSizeChangedCallback on_frame_buffer_size_changed,GetFrameBufferCallback get_frame_buffer,ReleaseFrameBufferCallback release_frame_buffer,void * callback_private_data)119 BufferPool::BufferPool(
120     FrameBufferSizeChangedCallback on_frame_buffer_size_changed,
121     GetFrameBufferCallback get_frame_buffer,
122     ReleaseFrameBufferCallback release_frame_buffer,
123     void* callback_private_data) {
124   if (get_frame_buffer != nullptr) {
125     // on_frame_buffer_size_changed may be null.
126     assert(release_frame_buffer != nullptr);
127     on_frame_buffer_size_changed_ = on_frame_buffer_size_changed;
128     get_frame_buffer_ = get_frame_buffer;
129     release_frame_buffer_ = release_frame_buffer;
130     callback_private_data_ = callback_private_data;
131   } else {
132     on_frame_buffer_size_changed_ = OnInternalFrameBufferSizeChanged;
133     get_frame_buffer_ = GetInternalFrameBuffer;
134     release_frame_buffer_ = ReleaseInternalFrameBuffer;
135     callback_private_data_ = &internal_frame_buffers_;
136   }
137 }
138 
~BufferPool()139 BufferPool::~BufferPool() {
140   for (const auto* buffer : buffers_) {
141     if (buffer->in_use_) {
142       assert(false && "RefCountedBuffer still in use at destruction time.");
143       LIBGAV1_DLOG(ERROR, "RefCountedBuffer still in use at destruction time.");
144     }
145     delete buffer;
146   }
147 }
148 
OnFrameBufferSizeChanged(int bitdepth,Libgav1ImageFormat image_format,int width,int height,int left_border,int right_border,int top_border,int bottom_border)149 bool BufferPool::OnFrameBufferSizeChanged(int bitdepth,
150                                           Libgav1ImageFormat image_format,
151                                           int width, int height,
152                                           int left_border, int right_border,
153                                           int top_border, int bottom_border) {
154   if (on_frame_buffer_size_changed_ == nullptr) return true;
155   return on_frame_buffer_size_changed_(callback_private_data_, bitdepth,
156                                        image_format, width, height, left_border,
157                                        right_border, top_border, bottom_border,
158                                        /*stride_alignment=*/16) == kStatusOk;
159 }
160 
GetFreeBuffer()161 RefCountedBufferPtr BufferPool::GetFreeBuffer() {
162   std::unique_lock<std::mutex> lock(mutex_);
163   for (auto buffer : buffers_) {
164     if (!buffer->in_use_) {
165       buffer->in_use_ = true;
166       buffer->progress_row_ = -1;
167       buffer->frame_state_ = kFrameStateUnknown;
168       buffer->hdr_cll_set_ = false;
169       buffer->hdr_mdcv_set_ = false;
170       buffer->itut_t35_set_ = false;
171       lock.unlock();
172       return RefCountedBufferPtr(buffer, RefCountedBuffer::ReturnToBufferPool);
173     }
174   }
175   lock.unlock();
176   auto* const buffer = new (std::nothrow) RefCountedBuffer();
177   if (buffer == nullptr) {
178     LIBGAV1_DLOG(ERROR, "Failed to allocate a new reference counted buffer.");
179     return RefCountedBufferPtr();
180   }
181   buffer->SetBufferPool(this);
182   buffer->in_use_ = true;
183   buffer->progress_row_ = -1;
184   buffer->frame_state_ = kFrameStateUnknown;
185   lock.lock();
186   const bool ok = buffers_.push_back(buffer);
187   lock.unlock();
188   if (!ok) {
189     LIBGAV1_DLOG(
190         ERROR,
191         "Failed to push the new reference counted buffer into the vector.");
192     delete buffer;
193     return RefCountedBufferPtr();
194   }
195   return RefCountedBufferPtr(buffer, RefCountedBuffer::ReturnToBufferPool);
196 }
197 
Abort()198 void BufferPool::Abort() {
199   std::unique_lock<std::mutex> lock(mutex_);
200   for (auto buffer : buffers_) {
201     if (buffer->in_use_) {
202       buffer->Abort();
203     }
204   }
205 }
206 
ReturnUnusedBuffer(RefCountedBuffer * buffer)207 void BufferPool::ReturnUnusedBuffer(RefCountedBuffer* buffer) {
208   std::lock_guard<std::mutex> lock(mutex_);
209   assert(buffer->in_use_);
210   buffer->in_use_ = false;
211   if (buffer->buffer_private_data_valid_) {
212     release_frame_buffer_(callback_private_data_, buffer->buffer_private_data_);
213     buffer->buffer_private_data_valid_ = false;
214   }
215 }
216 
217 }  // namespace libgav1
218