#include "include/dvr/dvr_api.h"
#include "include/dvr/dvr_buffer_queue.h"
#include <android/native_window.h>
#include <gui/Surface.h>
#include <private/dvr/buffer_hub_queue_client.h>
#include <private/dvr/buffer_hub_queue_producer.h>
#include "dvr_internal.h"
#define CHECK_PARAM(param) \
LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \
__FUNCTION__)
using namespace android;
namespace android {
namespace dvr {
DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue(
const std::shared_ptr<dvr::ProducerQueue>& producer_queue) {
return new DvrWriteBufferQueue{std::move(producer_queue)};
}
DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue(
const std::shared_ptr<dvr::ConsumerQueue>& consumer_queue) {
return new DvrReadBufferQueue{std::move(consumer_queue)};
}
dvr::ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue(
DvrWriteBufferQueue* write_queue) {
return write_queue->producer_queue.get();
}
} // namespace dvr
} // namespace android
extern "C" {
void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
if (write_queue != nullptr && write_queue->native_window != nullptr)
ANativeWindow_release(write_queue->native_window);
delete write_queue;
}
ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
if (!write_queue || !write_queue->producer_queue)
return -EINVAL;
return write_queue->producer_queue->capacity();
}
int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
if (!write_queue)
return -EINVAL;
return write_queue->producer_queue->id();
}
int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
ANativeWindow** out_window) {
if (!write_queue || !out_window)
return -EINVAL;
if (write_queue->producer_queue->metadata_size() !=
sizeof(DvrNativeBufferMetadata)) {
ALOGE(
"The size of buffer metadata (%zu) of the write queue does not match "
"of size of DvrNativeBufferMetadata (%zu).",
write_queue->producer_queue->metadata_size(),
sizeof(DvrNativeBufferMetadata));
return -EINVAL;
}
// Lazy creation of |native_window|.
if (write_queue->native_window == nullptr) {
sp<IGraphicBufferProducer> gbp =
dvr::BufferHubQueueProducer::Create(write_queue->producer_queue);
sp<Surface> surface = new Surface(gbp, true);
write_queue->native_window = static_cast<ANativeWindow*>(surface.get());
ANativeWindow_acquire(write_queue->native_window);
}
*out_window = write_queue->native_window;
return 0;
}
int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
DvrReadBufferQueue** out_read_queue) {
if (!write_queue || !write_queue->producer_queue || !out_read_queue)
return -EINVAL;
auto read_queue = std::make_unique<DvrReadBufferQueue>();
read_queue->consumer_queue =
write_queue->producer_queue->CreateConsumerQueue();
if (read_queue->consumer_queue == nullptr) {
ALOGE(
"dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue "
"from DvrWriteBufferQueue[%p].",
write_queue);
return -ENOMEM;
}
*out_read_queue = read_queue.release();
return 0;
}
int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
DvrWriteBuffer* write_buffer,
int* out_fence_fd) {
if (!write_queue || !write_queue->producer_queue || !write_buffer ||
!out_fence_fd) {
return -EINVAL;
}
size_t slot;
pdx::LocalHandle release_fence;
auto buffer_status =
write_queue->producer_queue->Dequeue(timeout, &slot, &release_fence);
if (!buffer_status) {
ALOGE_IF(buffer_status.error() != ETIMEDOUT,
"dvrWriteBufferQueueDequeue: Failed to dequeue buffer: %s",
buffer_status.GetErrorMessage().c_str());
return -buffer_status.error();
}
write_buffer->write_buffer = buffer_status.take();
*out_fence_fd = release_fence.Release();
return 0;
}
// ReadBufferQueue
void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
delete read_queue;
}
ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
if (!read_queue)
return -EINVAL;
return read_queue->consumer_queue->capacity();
}
int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
if (!read_queue)
return -EINVAL;
return read_queue->consumer_queue->id();
}
int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
DvrReadBufferQueue** out_read_queue) {
if (!read_queue || !read_queue->consumer_queue || !out_read_queue)
return -EINVAL;
auto new_read_queue = std::make_unique<DvrReadBufferQueue>();
new_read_queue->consumer_queue =
read_queue->consumer_queue->CreateConsumerQueue();
if (new_read_queue->consumer_queue == nullptr) {
ALOGE(
"dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue "
"from DvrReadBufferQueue[%p].",
read_queue);
return -ENOMEM;
}
*out_read_queue = new_read_queue.release();
return 0;
}
int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
DvrReadBuffer* read_buffer, int* out_fence_fd,
void* out_meta, size_t meta_size_bytes) {
if (!read_queue || !read_queue->consumer_queue || !read_buffer ||
!out_fence_fd || !out_meta) {
return -EINVAL;
}
if (meta_size_bytes != read_queue->consumer_queue->metadata_size()) {
ALOGE(
"dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), "
"but actual (%zu).",
read_queue->consumer_queue->metadata_size(), meta_size_bytes);
return -EINVAL;
}
size_t slot;
pdx::LocalHandle acquire_fence;
auto buffer_status = read_queue->consumer_queue->Dequeue(
timeout, &slot, out_meta, meta_size_bytes, &acquire_fence);
if (!buffer_status) {
ALOGE_IF(buffer_status.error() != ETIMEDOUT,
"dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s",
buffer_status.GetErrorMessage().c_str());
return -buffer_status.error();
}
read_buffer->read_buffer = buffer_status.take();
*out_fence_fd = acquire_fence.Release();
return 0;
}
} // extern "C"