/* 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