1 #include "include/dvr/dvr_api.h"
2 #include "include/dvr/dvr_buffer_queue.h"
3
4 #include <android/native_window.h>
5 #include <gui/BufferHubProducer.h>
6
7 #include "dvr_internal.h"
8 #include "dvr_buffer_queue_internal.h"
9
10 using namespace android;
11 using android::dvr::BufferHubBase;
12 using android::dvr::ConsumerBuffer;
13 using android::dvr::ConsumerQueue;
14 using android::dvr::ProducerBuffer;
15 using android::dvr::ProducerQueue;
16 using android::dvr::ProducerQueueConfigBuilder;
17 using android::dvr::UsagePolicy;
18
19 extern "C" {
20
DvrWriteBufferQueue(const std::shared_ptr<ProducerQueue> & producer_queue)21 DvrWriteBufferQueue::DvrWriteBufferQueue(
22 const std::shared_ptr<ProducerQueue>& producer_queue)
23 : producer_queue_(producer_queue),
24 width_(producer_queue->default_width()),
25 height_(producer_queue->default_height()),
26 format_(producer_queue->default_format()) {}
27
GetNativeWindow(ANativeWindow ** out_window)28 int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) {
29 if (native_window_ == nullptr) {
30 // Lazy creation of |native_window|, as not everyone is using
31 // DvrWriteBufferQueue as an external surface.
32 sp<IGraphicBufferProducer> gbp = BufferHubProducer::Create(producer_queue_);
33 native_window_ = new Surface(gbp, true);
34 }
35
36 *out_window = static_cast<ANativeWindow*>(native_window_.get());
37 return 0;
38 }
39
CreateReadQueue(DvrReadBufferQueue ** out_read_queue)40 int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
41 std::unique_ptr<ConsumerQueue> consumer_queue =
42 producer_queue_->CreateConsumerQueue();
43 if (consumer_queue == nullptr) {
44 ALOGE(
45 "DvrWriteBufferQueue::CreateReadQueue: Failed to create consumer queue "
46 "from producer queue: queue_id=%d.", producer_queue_->id());
47 return -ENOMEM;
48 }
49
50 *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
51 return 0;
52 }
53
Dequeue(int timeout,DvrWriteBuffer * write_buffer,int * out_fence_fd)54 int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
55 int* out_fence_fd) {
56 DvrNativeBufferMetadata meta;
57 DvrWriteBuffer* buffer = nullptr;
58 int fence_fd = -1;
59 if (const int ret = GainBuffer(timeout, &buffer, &meta, &fence_fd))
60 return ret;
61 if (!buffer)
62 return -ENOMEM;
63
64 write_buffers_[buffer->slot].reset(buffer);
65 write_buffer->write_buffer = std::move(buffer->write_buffer);
66 *out_fence_fd = fence_fd;
67 return 0;
68 }
69
GainBuffer(int timeout,DvrWriteBuffer ** out_write_buffer,DvrNativeBufferMetadata * out_meta,int * out_fence_fd)70 int DvrWriteBufferQueue::GainBuffer(int timeout,
71 DvrWriteBuffer** out_write_buffer,
72 DvrNativeBufferMetadata* out_meta,
73 int* out_fence_fd) {
74 size_t slot;
75 pdx::LocalHandle release_fence;
76
77 // Need to retry N+1 times, where N is total number of buffers in the queue.
78 // As in the worst case, we will dequeue all N buffers and reallocate them, on
79 // the {N+1}th dequeue, we are guaranteed to get a buffer with new dimension.
80 size_t max_retries = 1 + producer_queue_->capacity();
81 size_t retry = 0;
82
83 for (; retry < max_retries; retry++) {
84 auto buffer_status =
85 producer_queue_->Dequeue(timeout, &slot, out_meta, &release_fence);
86 if (!buffer_status) {
87 ALOGE_IF(buffer_status.error() != ETIMEDOUT,
88 "DvrWriteBufferQueue::GainBuffer: Failed to dequeue buffer: %s",
89 buffer_status.GetErrorMessage().c_str());
90 return -buffer_status.error();
91 }
92
93 if (write_buffers_[slot] == nullptr) {
94 // Lazy initialization of a write_buffers_ slot. Note that a slot will
95 // only be dynamically allocated once during the entire cycle life of a
96 // queue.
97 write_buffers_[slot] = std::make_unique<DvrWriteBuffer>();
98 write_buffers_[slot]->slot = slot;
99 }
100
101 LOG_ALWAYS_FATAL_IF(
102 write_buffers_[slot]->write_buffer,
103 "DvrWriteBufferQueue::GainBuffer: Buffer slot is not empty: %zu", slot);
104 write_buffers_[slot]->write_buffer = std::move(buffer_status.take());
105
106 const auto& producer_buffer = write_buffers_[slot]->write_buffer;
107 if (!producer_buffer)
108 return -ENOMEM;
109
110 if (width_ == producer_buffer->width() &&
111 height_ == producer_buffer->height() &&
112 format_ == producer_buffer->format()) {
113 // Producer queue returns a buffer matches the current request.
114 break;
115 }
116
117 // Needs reallocation. Note that if there are already multiple available
118 // buffers in the queue, the next one returned from |queue_->Dequeue| may
119 // still have the old buffer dimension or format. Retry up to N+1 times or
120 // until we dequeued a buffer with new configuration.
121 ALOGD_IF(TRACE,
122 "DvrWriteBufferQueue::Dequeue: requested buffer at slot: %zu "
123 "(w=%u, h=%u, fmt=%u) is different from the buffer returned "
124 "(w=%u, h=%u, fmt=%u). Need re-allocation.",
125 slot, width_, height_, format_, producer_buffer->width(),
126 producer_buffer->height(), producer_buffer->format());
127
128 // Currently, we are not storing |layer_count| and |usage| in queue
129 // configuration. Copy those setup from the last buffer dequeued before we
130 // remove it.
131 uint32_t old_layer_count = producer_buffer->layer_count();
132 uint64_t old_usage = producer_buffer->usage();
133
134 // Allocate a new producer buffer with new buffer configs. Note that if
135 // there are already multiple available buffers in the queue, the next one
136 // returned from |queue_->Dequeue| may still have the old buffer dimension
137 // or format. Retry up to BufferHubQueue::kMaxQueueCapacity times or until
138 // we dequeued a buffer with new configuration.
139 auto remove_status = producer_queue_->RemoveBuffer(slot);
140 if (!remove_status) {
141 ALOGE("DvrWriteBufferQueue::Dequeue: Failed to remove buffer: %s",
142 remove_status.GetErrorMessage().c_str());
143 return -remove_status.error();
144 }
145 // Make sure that the previously allocated buffer is dereferenced from
146 // write_buffers_ array.
147 write_buffers_[slot]->write_buffer = nullptr;
148
149 auto allocate_status = producer_queue_->AllocateBuffer(
150 width_, height_, old_layer_count, format_, old_usage);
151 if (!allocate_status) {
152 ALOGE("DvrWriteBufferQueue::Dequeue: Failed to allocate buffer: %s",
153 allocate_status.GetErrorMessage().c_str());
154 return -allocate_status.error();
155 }
156 }
157
158 if (retry >= max_retries) {
159 ALOGE(
160 "DvrWriteBufferQueue::Dequeue: Failed to re-allocate buffer after "
161 "resizing.");
162 return -ENOMEM;
163 }
164
165 *out_write_buffer = write_buffers_[slot].release();
166 *out_fence_fd = release_fence.Release();
167
168 return 0;
169 }
170
PostBuffer(DvrWriteBuffer * write_buffer,const DvrNativeBufferMetadata * meta,int ready_fence_fd)171 int DvrWriteBufferQueue::PostBuffer(DvrWriteBuffer* write_buffer,
172 const DvrNativeBufferMetadata* meta,
173 int ready_fence_fd) {
174 // Some basic sanity checks before we put the buffer back into a slot.
175 size_t slot = static_cast<size_t>(write_buffer->slot);
176 LOG_FATAL_IF(
177 (write_buffers->slot < 0 || write_buffers->slot >= write_buffers_.size()),
178 "DvrWriteBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
179
180 if (write_buffers_[slot] != nullptr) {
181 ALOGE("DvrWriteBufferQueue::PostBuffer: Slot is not empty: %zu", slot);
182 return -EINVAL;
183 }
184 if (write_buffer->write_buffer == nullptr) {
185 ALOGE("DvrWriteBufferQueue::PostBuffer: Invalid write buffer.");
186 return -EINVAL;
187 }
188 if (write_buffer->write_buffer->id() != producer_queue_->GetBufferId(slot)) {
189 ALOGE(
190 "DvrWriteBufferQueue::PostBuffer: Buffer to be posted does not "
191 "belong to this buffer queue. Posting buffer: id=%d, buffer in "
192 "queue: id=%d",
193 write_buffer->write_buffer->id(), producer_queue_->GetBufferId(slot));
194 return -EINVAL;
195 }
196
197 write_buffer->write_buffer->SetQueueIndex(next_post_index_++);
198 pdx::LocalHandle fence(ready_fence_fd);
199 const int ret = write_buffer->write_buffer->PostAsync(meta, fence);
200 if (ret < 0) {
201 ALOGE("DvrWriteBufferQueue::PostBuffer: Failed to post buffer, ret=%d",
202 ret);
203 return ret;
204 }
205
206 // Put the DvrWriteBuffer pointer back into its slot for reuse.
207 write_buffers_[slot].reset(write_buffer);
208 // It's import to reset the write buffer client now. It should stay invalid
209 // until next GainBuffer on the same slot.
210 write_buffers_[slot]->write_buffer = nullptr;
211 return 0;
212 }
213
ResizeBuffer(uint32_t width,uint32_t height)214 int DvrWriteBufferQueue::ResizeBuffer(uint32_t width, uint32_t height) {
215 if (width == 0 || height == 0) {
216 ALOGE(
217 "DvrWriteBufferQueue::ResizeBuffer: invalid buffer dimension: w=%u, "
218 "h=%u.",
219 width, height);
220 return -EINVAL;
221 }
222
223 width_ = width;
224 height_ = height;
225 return 0;
226 }
227
dvrWriteBufferQueueCreate(uint32_t width,uint32_t height,uint32_t format,uint32_t layer_count,uint64_t usage,size_t capacity,size_t metadata_size,DvrWriteBufferQueue ** out_write_queue)228 int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
229 uint32_t layer_count, uint64_t usage,
230 size_t capacity, size_t metadata_size,
231 DvrWriteBufferQueue** out_write_queue) {
232 if (!out_write_queue)
233 return -EINVAL;
234
235 auto config_builder = ProducerQueueConfigBuilder()
236 .SetDefaultWidth(width)
237 .SetDefaultHeight(height)
238 .SetDefaultFormat(format)
239 .SetMetadataSize(metadata_size);
240 std::unique_ptr<ProducerQueue> producer_queue =
241 ProducerQueue::Create(config_builder.Build(), UsagePolicy{});
242 if (!producer_queue) {
243 ALOGE("dvrWriteBufferQueueCreate: Failed to create producer queue.");
244 return -ENOMEM;
245 }
246
247 auto status = producer_queue->AllocateBuffers(width, height, layer_count,
248 format, usage, capacity);
249 if (!status.ok()) {
250 ALOGE("dvrWriteBufferQueueCreate: Failed to allocate buffers.");
251 return -ENOMEM;
252 }
253
254 *out_write_queue = new DvrWriteBufferQueue(std::move(producer_queue));
255 return 0;
256 }
257
dvrWriteBufferQueueDestroy(DvrWriteBufferQueue * write_queue)258 void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
259 delete write_queue;
260 }
261
dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue * write_queue)262 ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
263 if (!write_queue)
264 return -EINVAL;
265
266 return write_queue->capacity();
267 }
268
dvrWriteBufferQueueGetId(DvrWriteBufferQueue * write_queue)269 int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
270 if (!write_queue)
271 return -EINVAL;
272
273 return write_queue->id();
274 }
275
dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue * write_queue,ANativeWindow ** out_window)276 int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
277 ANativeWindow** out_window) {
278 if (!write_queue || !out_window)
279 return -EINVAL;
280
281 return write_queue->GetNativeWindow(out_window);
282 }
283
dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue * write_queue,DvrReadBufferQueue ** out_read_queue)284 int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
285 DvrReadBufferQueue** out_read_queue) {
286 if (!write_queue || !out_read_queue)
287 return -EINVAL;
288
289 return write_queue->CreateReadQueue(out_read_queue);
290 }
291
dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue * write_queue,int timeout,DvrWriteBuffer ** out_write_buffer,DvrNativeBufferMetadata * out_meta,int * out_fence_fd)292 int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
293 DvrWriteBuffer** out_write_buffer,
294 DvrNativeBufferMetadata* out_meta,
295 int* out_fence_fd) {
296 if (!write_queue || !out_write_buffer || !out_meta || !out_fence_fd)
297 return -EINVAL;
298
299 return write_queue->GainBuffer(timeout, out_write_buffer, out_meta,
300 out_fence_fd);
301 }
302
dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue * write_queue,DvrWriteBuffer * write_buffer,const DvrNativeBufferMetadata * meta,int ready_fence_fd)303 int dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue* write_queue,
304 DvrWriteBuffer* write_buffer,
305 const DvrNativeBufferMetadata* meta,
306 int ready_fence_fd) {
307 if (!write_queue || !write_buffer || !write_buffer->write_buffer || !meta)
308 return -EINVAL;
309
310 return write_queue->PostBuffer(write_buffer, meta, ready_fence_fd);
311 }
312
dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue * write_queue,uint32_t width,uint32_t height)313 int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
314 uint32_t width, uint32_t height) {
315 if (!write_queue)
316 return -EINVAL;
317
318 return write_queue->ResizeBuffer(width, height);
319 }
320
321 // ReadBufferQueue
322
DvrReadBufferQueue(const std::shared_ptr<ConsumerQueue> & consumer_queue)323 DvrReadBufferQueue::DvrReadBufferQueue(
324 const std::shared_ptr<ConsumerQueue>& consumer_queue)
325 : consumer_queue_(consumer_queue) {}
326
CreateReadQueue(DvrReadBufferQueue ** out_read_queue)327 int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
328 std::unique_ptr<ConsumerQueue> consumer_queue =
329 consumer_queue_->CreateConsumerQueue();
330 if (consumer_queue == nullptr) {
331 ALOGE(
332 "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue "
333 "from producer queue: queue_id=%d.", consumer_queue_->id());
334 return -ENOMEM;
335 }
336
337 *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
338 return 0;
339 }
340
AcquireBuffer(int timeout,DvrReadBuffer ** out_read_buffer,DvrNativeBufferMetadata * out_meta,int * out_fence_fd)341 int DvrReadBufferQueue::AcquireBuffer(int timeout,
342 DvrReadBuffer** out_read_buffer,
343 DvrNativeBufferMetadata* out_meta,
344 int* out_fence_fd) {
345 size_t slot;
346 pdx::LocalHandle acquire_fence;
347 auto buffer_status =
348 consumer_queue_->Dequeue(timeout, &slot, out_meta, &acquire_fence);
349 if (!buffer_status) {
350 ALOGE_IF(buffer_status.error() != ETIMEDOUT,
351 "DvrReadBufferQueue::AcquireBuffer: Failed to dequeue buffer: %s",
352 buffer_status.GetErrorMessage().c_str());
353 return -buffer_status.error();
354 }
355
356 if (read_buffers_[slot] == nullptr) {
357 // Lazy initialization of a read_buffers_ slot. Note that a slot will only
358 // be dynamically allocated once during the entire cycle life of a queue.
359 read_buffers_[slot] = std::make_unique<DvrReadBuffer>();
360 read_buffers_[slot]->slot = slot;
361 }
362
363 LOG_FATAL_IF(
364 read_buffers_[slot]->read_buffer,
365 "DvrReadBufferQueue::AcquireBuffer: Buffer slot is not empty: %zu", slot);
366 read_buffers_[slot]->read_buffer = std::move(buffer_status.take());
367
368 *out_read_buffer = read_buffers_[slot].release();
369 *out_fence_fd = acquire_fence.Release();
370
371 return 0;
372 }
373
ReleaseBuffer(DvrReadBuffer * read_buffer,const DvrNativeBufferMetadata * meta,int release_fence_fd)374 int DvrReadBufferQueue::ReleaseBuffer(DvrReadBuffer* read_buffer,
375 const DvrNativeBufferMetadata* meta,
376 int release_fence_fd) {
377 // Some basic sanity checks before we put the buffer back into a slot.
378 size_t slot = static_cast<size_t>(read_buffer->slot);
379 LOG_FATAL_IF(
380 (read_buffers->slot < 0 || read_buffers->slot >= read_buffers_size()),
381 "DvrReadBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
382
383 if (read_buffers_[slot] != nullptr) {
384 ALOGE("DvrReadBufferQueue::ReleaseBuffer: Slot is not empty: %zu", slot);
385 return -EINVAL;
386 }
387 if (read_buffer->read_buffer == nullptr) {
388 ALOGE("DvrReadBufferQueue::ReleaseBuffer: Invalid read buffer.");
389 return -EINVAL;
390 }
391 if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
392 if (consumer_queue_->GetBufferId(slot) > 0) {
393 ALOGE(
394 "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
395 "belong to this queue (queue_id=%d): attempting to release buffer "
396 "(buffer_id=%d) at slot %d which holds a different buffer "
397 "(buffer_id=%d).",
398 consumer_queue_->id(), read_buffer->read_buffer->id(),
399 static_cast<int>(slot), consumer_queue_->GetBufferId(slot));
400 } else {
401 ALOGI(
402 "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
403 "belong to this queue (queue_id=%d): attempting to release buffer "
404 "(buffer_id=%d) at slot %d which is empty.",
405 consumer_queue_->id(), read_buffer->read_buffer->id(),
406 static_cast<int>(slot));
407 }
408 }
409
410 pdx::LocalHandle fence(release_fence_fd);
411 int ret = read_buffer->read_buffer->ReleaseAsync(meta, fence);
412 if (ret < 0) {
413 ALOGE("DvrReadBufferQueue::ReleaseBuffer: Failed to release buffer, ret=%d",
414 ret);
415 return ret;
416 }
417
418 // Put the DvrReadBuffer pointer back into its slot for reuse.
419 read_buffers_[slot].reset(read_buffer);
420 // It's import to reset the read buffer client now. It should stay invalid
421 // until next AcquireBuffer on the same slot.
422 read_buffers_[slot]->read_buffer = nullptr;
423 return 0;
424 }
425
SetBufferAvailableCallback(DvrReadBufferQueueBufferAvailableCallback callback,void * context)426 void DvrReadBufferQueue::SetBufferAvailableCallback(
427 DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
428 if (callback == nullptr) {
429 consumer_queue_->SetBufferAvailableCallback(nullptr);
430 } else {
431 consumer_queue_->SetBufferAvailableCallback(
432 [callback, context]() { callback(context); });
433 }
434 }
435
SetBufferRemovedCallback(DvrReadBufferQueueBufferRemovedCallback callback,void * context)436 void DvrReadBufferQueue::SetBufferRemovedCallback(
437 DvrReadBufferQueueBufferRemovedCallback callback, void* context) {
438 if (callback == nullptr) {
439 consumer_queue_->SetBufferRemovedCallback(nullptr);
440 } else {
441 consumer_queue_->SetBufferRemovedCallback(
442 [callback, context](const std::shared_ptr<BufferHubBase>& buffer) {
443 // When buffer is removed from the queue, the slot is already invalid.
444 auto read_buffer = std::make_unique<DvrReadBuffer>();
445 read_buffer->read_buffer =
446 std::static_pointer_cast<ConsumerBuffer>(buffer);
447 callback(read_buffer.release(), context);
448 });
449 }
450 }
451
HandleEvents()452 int DvrReadBufferQueue::HandleEvents() {
453 // TODO(jwcai) Probably should change HandleQueueEvents to return Status.
454 consumer_queue_->HandleQueueEvents();
455 return 0;
456 }
457
dvrReadBufferQueueDestroy(DvrReadBufferQueue * read_queue)458 void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
459 delete read_queue;
460 }
461
dvrReadBufferQueueGetCapacity(DvrReadBufferQueue * read_queue)462 ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
463 if (!read_queue)
464 return -EINVAL;
465
466 return read_queue->capacity();
467 }
468
dvrReadBufferQueueGetId(DvrReadBufferQueue * read_queue)469 int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
470 if (!read_queue)
471 return -EINVAL;
472
473 return read_queue->id();
474 }
475
dvrReadBufferQueueGetEventFd(DvrReadBufferQueue * read_queue)476 int dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue) {
477 if (!read_queue)
478 return -EINVAL;
479
480 return read_queue->event_fd();
481 }
482
dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue * read_queue,DvrReadBufferQueue ** out_read_queue)483 int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
484 DvrReadBufferQueue** out_read_queue) {
485 if (!read_queue || !out_read_queue)
486 return -EINVAL;
487
488 return read_queue->CreateReadQueue(out_read_queue);
489 }
490
dvrReadBufferQueueDequeue(DvrReadBufferQueue * read_queue,int timeout,DvrReadBuffer * read_buffer,int * out_fence_fd,void * out_meta,size_t meta_size_bytes)491 int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
492 DvrReadBuffer* read_buffer, int* out_fence_fd,
493 void* out_meta, size_t meta_size_bytes) {
494 if (!read_queue || !read_buffer || !out_fence_fd)
495 return -EINVAL;
496
497 if (meta_size_bytes != 0 && !out_meta)
498 return -EINVAL;
499
500 return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
501 meta_size_bytes);
502 }
503
dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue * read_queue,int timeout,DvrReadBuffer ** out_read_buffer,DvrNativeBufferMetadata * out_meta,int * out_fence_fd)504 int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout,
505 DvrReadBuffer** out_read_buffer,
506 DvrNativeBufferMetadata* out_meta,
507 int* out_fence_fd) {
508 if (!read_queue || !out_read_buffer || !out_meta || !out_fence_fd)
509 return -EINVAL;
510
511 return read_queue->AcquireBuffer(timeout, out_read_buffer, out_meta,
512 out_fence_fd);
513 }
514
dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue * read_queue,DvrReadBuffer * read_buffer,const DvrNativeBufferMetadata * meta,int release_fence_fd)515 int dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue* read_queue,
516 DvrReadBuffer* read_buffer,
517 const DvrNativeBufferMetadata* meta,
518 int release_fence_fd) {
519 if (!read_queue || !read_buffer || !read_buffer->read_buffer || !meta)
520 return -EINVAL;
521
522 return read_queue->ReleaseBuffer(read_buffer, meta, release_fence_fd);
523 }
524
dvrReadBufferQueueSetBufferAvailableCallback(DvrReadBufferQueue * read_queue,DvrReadBufferQueueBufferAvailableCallback callback,void * context)525 int dvrReadBufferQueueSetBufferAvailableCallback(
526 DvrReadBufferQueue* read_queue,
527 DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
528 if (!read_queue)
529 return -EINVAL;
530
531 read_queue->SetBufferAvailableCallback(callback, context);
532 return 0;
533 }
534
dvrReadBufferQueueSetBufferRemovedCallback(DvrReadBufferQueue * read_queue,DvrReadBufferQueueBufferRemovedCallback callback,void * context)535 int dvrReadBufferQueueSetBufferRemovedCallback(
536 DvrReadBufferQueue* read_queue,
537 DvrReadBufferQueueBufferRemovedCallback callback, void* context) {
538 if (!read_queue)
539 return -EINVAL;
540
541 read_queue->SetBufferRemovedCallback(callback, context);
542 return 0;
543 }
544
dvrReadBufferQueueHandleEvents(DvrReadBufferQueue * read_queue)545 int dvrReadBufferQueueHandleEvents(DvrReadBufferQueue* read_queue) {
546 if (!read_queue)
547 return -EINVAL;
548
549 return read_queue->HandleEvents();
550 }
551
552 } // extern "C"
553