/* Copyright 2017 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "arc/frame_buffer.h"
#include <sys/mman.h>
#include <utility>
#include "arc/common.h"
#include "arc/image_processor.h"
namespace arc {
FrameBuffer::FrameBuffer()
: data_(nullptr),
data_size_(0),
buffer_size_(0),
width_(0),
height_(0),
fourcc_(0) {}
FrameBuffer::~FrameBuffer() {}
int FrameBuffer::SetDataSize(size_t data_size) {
if (data_size > buffer_size_) {
LOGF(ERROR) << "Buffer overflow: Buffer only has " << buffer_size_
<< ", but data needs " << data_size;
return -EINVAL;
}
data_size_ = data_size;
return 0;
}
AllocatedFrameBuffer::AllocatedFrameBuffer(int buffer_size) {
buffer_.reset(new uint8_t[buffer_size]);
buffer_size_ = buffer_size;
data_ = buffer_.get();
}
AllocatedFrameBuffer::AllocatedFrameBuffer(uint8_t* buffer, int buffer_size) {
buffer_.reset(buffer);
buffer_size_ = buffer_size;
data_ = buffer_.get();
}
AllocatedFrameBuffer::~AllocatedFrameBuffer() {}
int AllocatedFrameBuffer::SetDataSize(size_t size) {
if (size > buffer_size_) {
buffer_.reset(new uint8_t[size]);
buffer_size_ = size;
data_ = buffer_.get();
}
data_size_ = size;
return 0;
}
void AllocatedFrameBuffer::Reset() { memset(data_, 0, buffer_size_); }
V4L2FrameBuffer::V4L2FrameBuffer(base::ScopedFD fd, int buffer_size,
uint32_t width, uint32_t height,
uint32_t fourcc)
: fd_(std::move(fd)), is_mapped_(false) {
buffer_size_ = buffer_size;
width_ = width;
height_ = height;
fourcc_ = fourcc;
}
V4L2FrameBuffer::~V4L2FrameBuffer() {
if (Unmap()) {
LOGF(ERROR) << "Unmap failed";
}
}
int V4L2FrameBuffer::Map() {
base::AutoLock l(lock_);
if (is_mapped_) {
LOGF(ERROR) << "The buffer is already mapped";
return -EINVAL;
}
void* addr = mmap(NULL, buffer_size_, PROT_READ, MAP_SHARED, fd_.get(), 0);
if (addr == MAP_FAILED) {
LOGF(ERROR) << "mmap() failed: " << strerror(errno);
return -EINVAL;
}
data_ = static_cast<uint8_t*>(addr);
is_mapped_ = true;
return 0;
}
int V4L2FrameBuffer::Unmap() {
base::AutoLock l(lock_);
if (is_mapped_ && munmap(data_, buffer_size_)) {
LOGF(ERROR) << "mummap() failed: " << strerror(errno);
return -EINVAL;
}
is_mapped_ = false;
return 0;
}
GrallocFrameBuffer::GrallocFrameBuffer(buffer_handle_t buffer, uint32_t width,
uint32_t height, uint32_t fourcc,
uint32_t device_buffer_length,
uint32_t stream_usage)
: buffer_(buffer),
is_mapped_(false),
device_buffer_length_(device_buffer_length),
stream_usage_(stream_usage) {
const hw_module_t* module = nullptr;
int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
if (ret || !module) {
LOGF(ERROR) << "Failed to get gralloc module.";
return;
}
gralloc_module_ = reinterpret_cast<const gralloc_module_t*>(module);
width_ = width;
height_ = height;
fourcc_ = fourcc;
}
GrallocFrameBuffer::~GrallocFrameBuffer() {
if (Unmap()) {
LOGF(ERROR) << "Unmap failed";
}
}
int GrallocFrameBuffer::Map() {
base::AutoLock l(lock_);
if (is_mapped_) {
LOGF(ERROR) << "The buffer is already mapped";
return -EINVAL;
}
void* addr;
int ret = 0;
switch (fourcc_) {
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YUYV:
android_ycbcr yuv_data;
ret = gralloc_module_->lock_ycbcr(gralloc_module_, buffer_, stream_usage_,
0, 0, width_, height_, &yuv_data);
addr = yuv_data.y;
break;
case V4L2_PIX_FMT_JPEG:
ret = gralloc_module_->lock(gralloc_module_, buffer_, stream_usage_, 0, 0,
device_buffer_length_, 1, &addr);
break;
case V4L2_PIX_FMT_BGR32:
case V4L2_PIX_FMT_RGB32:
ret = gralloc_module_->lock(gralloc_module_, buffer_, stream_usage_, 0, 0,
width_, height_, &addr);
break;
default:
return -EINVAL;
}
if (ret) {
LOGF(ERROR) << "Failed to gralloc lock buffer: " << ret;
return ret;
}
data_ = static_cast<uint8_t*>(addr);
if (fourcc_ == V4L2_PIX_FMT_YVU420 || fourcc_ == V4L2_PIX_FMT_YUV420 ||
fourcc_ == V4L2_PIX_FMT_NV21 || fourcc_ == V4L2_PIX_FMT_RGB32 ||
fourcc_ == V4L2_PIX_FMT_BGR32) {
buffer_size_ = ImageProcessor::GetConvertedSize(fourcc_, width_, height_);
}
is_mapped_ = true;
return 0;
}
int GrallocFrameBuffer::Unmap() {
base::AutoLock l(lock_);
if (is_mapped_ && gralloc_module_->unlock(gralloc_module_, buffer_)) {
LOGF(ERROR) << "Failed to unmap buffer: ";
return -EINVAL;
}
is_mapped_ = false;
return 0;
}
} // namespace arc