aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/V4L2Device.cpp3128
-rw-r--r--common/V4L2DevicePoller.cpp168
-rw-r--r--common/include/v4l2_codec2/common/V4L2Device.h1009
-rw-r--r--common/include/v4l2_codec2/common/V4L2DevicePoller.h139
4 files changed, 2096 insertions, 2348 deletions
diff --git a/common/V4L2Device.cpp b/common/V4L2Device.cpp
index 7a0e83e..52ef5ac 100644
--- a/common/V4L2Device.cpp
+++ b/common/V4L2Device.cpp
@@ -5,7 +5,10 @@
// Note: Added some missing defines that are only defined in newer kernel
// versions (e.g. V4L2_PIX_FMT_VP8_FRAME)
-#include "v4l2_codec2/common/V4L2Device.h"
+//#define LOG_NDEBUG 0
+#define LOG_TAG "V4L2Device"
+
+#include <v4l2_codec2/common/V4L2Device.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -18,18 +21,18 @@
#include <sys/mman.h>
#include <algorithm>
+#include <mutex>
#include <set>
#include <sstream>
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/posix/eintr_wrapper.h"
-#include "base/thread_annotations.h"
+#include <base/bind.h>
+#include <base/numerics/safe_conversions.h>
+#include <base/posix/eintr_wrapper.h>
+#include <base/thread_annotations.h>
+#include <utils/Log.h>
-#include "color_plane_layout.h"
-#include "macros.h"
-#include "video_pixel_format.h"
+#include <color_plane_layout.h>
+#include <video_pixel_format.h>
// VP8 parsed frames
#ifndef V4L2_PIX_FMT_VP8_FRAME
@@ -46,2116 +49,1971 @@
#define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4')
#endif
-namespace media {
+namespace android {
-struct v4l2_format BuildV4L2Format(const enum v4l2_buf_type type,
- uint32_t fourcc,
- const Size& size,
- size_t buffer_size,
- uint32_t stride) {
- struct v4l2_format format;
- memset(&format, 0, sizeof(format));
- format.type = type;
- format.fmt.pix_mp.pixelformat = fourcc;
- format.fmt.pix_mp.width = size.width();
- format.fmt.pix_mp.height = size.height();
- format.fmt.pix_mp.num_planes = V4L2Device::GetNumPlanesOfV4L2PixFmt(fourcc);
- format.fmt.pix_mp.plane_fmt[0].sizeimage = buffer_size;
+struct v4l2_format buildV4L2Format(const enum v4l2_buf_type type, uint32_t fourcc,
+ const media::Size& size, size_t buffer_size, uint32_t stride) {
+ struct v4l2_format format;
+ memset(&format, 0, sizeof(format));
+ format.type = type;
+ format.fmt.pix_mp.pixelformat = fourcc;
+ format.fmt.pix_mp.width = size.width();
+ format.fmt.pix_mp.height = size.height();
+ format.fmt.pix_mp.num_planes = V4L2Device::getNumPlanesOfV4L2PixFmt(fourcc);
+ format.fmt.pix_mp.plane_fmt[0].sizeimage = buffer_size;
- // When the image format is planar the bytesperline value applies to the
- // first plane and is divided by the same factor as the width field for the
- // other planes.
- format.fmt.pix_mp.plane_fmt[0].bytesperline = stride;
+ // When the image format is planar the bytesperline value applies to the first plane and is
+ // divided by the same factor as the width field for the other planes.
+ format.fmt.pix_mp.plane_fmt[0].bytesperline = stride;
- return format;
+ return format;
}
V4L2ExtCtrl::V4L2ExtCtrl(uint32_t id) {
- memset(&ctrl, 0, sizeof(ctrl));
- ctrl.id = id;
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = id;
}
V4L2ExtCtrl::V4L2ExtCtrl(uint32_t id, int32_t val) : V4L2ExtCtrl(id) {
- ctrl.value = val;
+ ctrl.value = val;
}
-// Class used to store the state of a buffer that should persist between
-// reference creations. This includes:
+// Class used to store the state of a buffer that should persist between reference creations. This
+// includes:
// * Result of initial VIDIOC_QUERYBUF ioctl,
// * Plane mappings.
//
// Also provides helper functions.
class V4L2Buffer {
- public:
- static std::unique_ptr<V4L2Buffer> Create(scoped_refptr<V4L2Device> device,
- enum v4l2_buf_type type,
- enum v4l2_memory memory,
- const struct v4l2_format& format,
- size_t buffer_id);
- ~V4L2Buffer();
-
- void* GetPlaneMapping(const size_t plane);
- size_t GetMemoryUsage() const;
- const struct v4l2_buffer& v4l2_buffer() const { return v4l2_buffer_; }
-
- private:
- V4L2Buffer(scoped_refptr<V4L2Device> device,
- enum v4l2_buf_type type,
- enum v4l2_memory memory,
- const struct v4l2_format& format,
- size_t buffer_id);
- bool Query();
-
- scoped_refptr<V4L2Device> device_;
- std::vector<void*> plane_mappings_;
-
- // V4L2 data as queried by QUERYBUF.
- struct v4l2_buffer v4l2_buffer_;
- // WARNING: do not change this to a vector or something smaller than
- // VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
- // the number of allocated planes, resulting in memory corruption.
- struct v4l2_plane v4l2_planes_[VIDEO_MAX_PLANES];
-
- struct v4l2_format format_ __attribute__((unused));
-
- DISALLOW_COPY_AND_ASSIGN(V4L2Buffer);
+public:
+ static std::unique_ptr<V4L2Buffer> create(scoped_refptr<V4L2Device> device,
+ enum v4l2_buf_type type, enum v4l2_memory memory,
+ const struct v4l2_format& format, size_t bufferId);
+ ~V4L2Buffer();
+
+ V4L2Buffer(const V4L2Buffer&) = delete;
+ V4L2Buffer& operator=(const V4L2Buffer&) = delete;
+
+ void* getPlaneMapping(const size_t plane);
+ size_t getMemoryUsage() const;
+ const struct v4l2_buffer& v4l2_buffer() const { return mV4l2Buffer; }
+
+private:
+ V4L2Buffer(scoped_refptr<V4L2Device> device, enum v4l2_buf_type type, enum v4l2_memory memory,
+ const struct v4l2_format& format, size_t bufferId);
+ bool query();
+
+ scoped_refptr<V4L2Device> mDevice;
+ std::vector<void*> mPlaneMappings;
+
+ // V4L2 data as queried by QUERYBUF.
+ struct v4l2_buffer mV4l2Buffer;
+ // WARNING: do not change this to a vector or something smaller than VIDEO_MAX_PLANES, otherwise
+ // the Tegra libv4l2 will write data beyond the number of allocated planes, resulting in memory
+ // corruption.
+ struct v4l2_plane mV4l2Planes[VIDEO_MAX_PLANES];
+
+ struct v4l2_format mFormat __attribute__((unused));
};
-std::unique_ptr<V4L2Buffer> V4L2Buffer::Create(scoped_refptr<V4L2Device> device,
- enum v4l2_buf_type type,
- enum v4l2_memory memory,
- const struct v4l2_format& format,
- size_t buffer_id) {
- // Not using std::make_unique because constructor is private.
- std::unique_ptr<V4L2Buffer> buffer(
- new V4L2Buffer(device, type, memory, format, buffer_id));
-
- if (!buffer->Query())
- return nullptr;
-
- return buffer;
-}
-
-V4L2Buffer::V4L2Buffer(scoped_refptr<V4L2Device> device,
- enum v4l2_buf_type type,
- enum v4l2_memory memory,
- const struct v4l2_format& format,
- size_t buffer_id)
- : device_(device), format_(format) {
- DCHECK(V4L2_TYPE_IS_MULTIPLANAR(type));
- DCHECK_LE(format.fmt.pix_mp.num_planes, base::size(v4l2_planes_));
-
- memset(v4l2_planes_, 0, sizeof(v4l2_planes_));
- memset(&v4l2_buffer_, 0, sizeof(v4l2_buffer_));
- v4l2_buffer_.m.planes = v4l2_planes_;
- // Just in case we got more planes than we want.
- v4l2_buffer_.length =
- std::min(static_cast<size_t>(format.fmt.pix_mp.num_planes),
- base::size(v4l2_planes_));
- v4l2_buffer_.index = buffer_id;
- v4l2_buffer_.type = type;
- v4l2_buffer_.memory = memory;
- plane_mappings_.resize(v4l2_buffer_.length);
+std::unique_ptr<V4L2Buffer> V4L2Buffer::create(scoped_refptr<V4L2Device> device,
+ enum v4l2_buf_type type, enum v4l2_memory memory,
+ const struct v4l2_format& format, size_t bufferId) {
+ // Not using std::make_unique because constructor is private.
+ std::unique_ptr<V4L2Buffer> buffer(new V4L2Buffer(device, type, memory, format, bufferId));
+
+ if (!buffer->query()) return nullptr;
+
+ return buffer;
+}
+
+V4L2Buffer::V4L2Buffer(scoped_refptr<V4L2Device> device, enum v4l2_buf_type type,
+ enum v4l2_memory memory, const struct v4l2_format& format, size_t bufferId)
+ : mDevice(device), mFormat(format) {
+ ALOG_ASSERT(V4L2_TYPE_IS_MULTIPLANAR(type));
+ ALOG_ASSERT(format.fmt.pix_mp.num_planes <= base::size(mV4l2Planes));
+
+ memset(mV4l2Planes, 0, sizeof(mV4l2Planes));
+ memset(&mV4l2Buffer, 0, sizeof(mV4l2Buffer));
+ mV4l2Buffer.m.planes = mV4l2Planes;
+ // Just in case we got more planes than we want.
+ mV4l2Buffer.length =
+ std::min(static_cast<size_t>(format.fmt.pix_mp.num_planes), base::size(mV4l2Planes));
+ mV4l2Buffer.index = bufferId;
+ mV4l2Buffer.type = type;
+ mV4l2Buffer.memory = memory;
+ mV4l2Buffer.memory = V4L2_MEMORY_DMABUF;
+ mPlaneMappings.resize(mV4l2Buffer.length);
}
V4L2Buffer::~V4L2Buffer() {
- if (v4l2_buffer_.memory == V4L2_MEMORY_MMAP) {
- for (size_t i = 0; i < plane_mappings_.size(); i++)
- if (plane_mappings_[i] != nullptr)
- device_->Munmap(plane_mappings_[i], v4l2_buffer_.m.planes[i].length);
- }
+ if (mV4l2Buffer.memory == V4L2_MEMORY_MMAP) {
+ for (size_t i = 0; i < mPlaneMappings.size(); i++) {
+ if (mPlaneMappings[i] != nullptr) {
+ mDevice->munmap(mPlaneMappings[i], mV4l2Buffer.m.planes[i].length);
+ }
+ }
+ }
}
-bool V4L2Buffer::Query() {
- int ret = device_->Ioctl(VIDIOC_QUERYBUF, &v4l2_buffer_);
- if (ret) {
- VPLOGF(1) << "VIDIOC_QUERYBUF failed: ";
- return false;
- }
+bool V4L2Buffer::query() {
+ int ret = mDevice->ioctl(VIDIOC_QUERYBUF, &mV4l2Buffer);
+ if (ret) {
+ ALOGE("VIDIOC_QUERYBUF failed");
+ return false;
+ }
- DCHECK(plane_mappings_.size() == v4l2_buffer_.length);
+ DCHECK(mPlaneMappings.size() == mV4l2Buffer.length);
- return true;
+ return true;
}
-void* V4L2Buffer::GetPlaneMapping(const size_t plane) {
- if (plane >= plane_mappings_.size()) {
- VLOGF(1) << "Invalid plane " << plane << " requested.";
- return nullptr;
- }
+void* V4L2Buffer::getPlaneMapping(const size_t plane) {
+ if (plane >= mPlaneMappings.size()) {
+ ALOGE("Invalid plane %zu requested.", plane);
+ return nullptr;
+ }
+
+ void* p = mPlaneMappings[plane];
+ if (p) {
+ return p;
+ }
+
+ // Do this check here to avoid repeating it after a buffer has been successfully mapped (we know
+ // we are of MMAP type by then).
+ if (mV4l2Buffer.memory != V4L2_MEMORY_MMAP) {
+ ALOGE("Cannot create mapping on non-MMAP buffer");
+ return nullptr;
+ }
- void* p = plane_mappings_[plane];
- if (p)
+ p = mDevice->mmap(NULL, mV4l2Buffer.m.planes[plane].length, PROT_READ | PROT_WRITE, MAP_SHARED,
+ mV4l2Buffer.m.planes[plane].m.mem_offset);
+ if (p == MAP_FAILED) {
+ ALOGE("mmap() failed: ");
+ return nullptr;
+ }
+
+ mPlaneMappings[plane] = p;
return p;
+}
+
+size_t V4L2Buffer::getMemoryUsage() const {
+ size_t usage = 0;
+ for (size_t i = 0; i < mV4l2Buffer.length; i++) {
+ usage += mV4l2Buffer.m.planes[i].length;
+ }
+ return usage;
+}
- // Do this check here to avoid repeating it after a buffer has been
- // successfully mapped (we know we are of MMAP type by then).
- if (v4l2_buffer_.memory != V4L2_MEMORY_MMAP) {
- VLOGF(1) << "Cannot create mapping on non-MMAP buffer";
- return nullptr;
- }
-
- p = device_->Mmap(NULL, v4l2_buffer_.m.planes[plane].length,
- PROT_READ | PROT_WRITE, MAP_SHARED,
- v4l2_buffer_.m.planes[plane].m.mem_offset);
- if (p == MAP_FAILED) {
- VPLOGF(1) << "mmap() failed: ";
- return nullptr;
- }
-
- plane_mappings_[plane] = p;
- return p;
-}
-
-size_t V4L2Buffer::GetMemoryUsage() const {
- size_t usage = 0;
- for (size_t i = 0; i < v4l2_buffer_.length; i++) {
- usage += v4l2_buffer_.m.planes[i].length;
- }
- return usage;
-}
-
-// A thread-safe pool of buffer indexes, allowing buffers to be obtained and
-// returned from different threads. All the methods of this class are
-// thread-safe. Users should keep a scoped_refptr to instances of this class
-// in order to ensure the list remains alive as long as they need it.
+// A thread-safe pool of buffer indexes, allowing buffers to be obtained and returned from different
+// threads. All the methods of this class are thread-safe. Users should keep a scoped_refptr to
+// instances of this class in order to ensure the list remains alive as long as they need it.
class V4L2BuffersList : public base::RefCountedThreadSafe<V4L2BuffersList> {
- public:
- V4L2BuffersList() = default;
- // Return a buffer to this list. Also can be called to set the initial pool
- // of buffers.
- // Note that it is illegal to return the same buffer twice.
- void ReturnBuffer(size_t buffer_id);
- // Get any of the buffers in the list. There is no order guarantee whatsoever.
- base::Optional<size_t> GetFreeBuffer();
- // Get the buffer with specified index.
- base::Optional<size_t> GetFreeBuffer(size_t requested_buffer_id);
- // Number of buffers currently in this list.
- size_t size() const;
-
- private:
- friend class base::RefCountedThreadSafe<V4L2BuffersList>;
- ~V4L2BuffersList() = default;
-
- mutable base::Lock lock_;
- std::set<size_t> free_buffers_ GUARDED_BY(lock_);
- DISALLOW_COPY_AND_ASSIGN(V4L2BuffersList);
+public:
+ V4L2BuffersList() = default;
+
+ V4L2BuffersList(const V4L2BuffersList&) = delete;
+ V4L2BuffersList& operator=(const V4L2BuffersList&) = delete;
+
+ // Return a buffer to this list. Also can be called to set the initial pool of buffers.
+ // Note that it is illegal to return the same buffer twice.
+ void returnBuffer(size_t bufferId);
+ // Get any of the buffers in the list. There is no order guarantee whatsoever.
+ std::optional<size_t> getFreeBuffer();
+ // Get the buffer with specified index.
+ std::optional<size_t> getFreeBuffer(size_t requestedBufferId);
+ // Number of buffers currently in this list.
+ size_t size() const;
+
+private:
+ friend class base::RefCountedThreadSafe<V4L2BuffersList>;
+ ~V4L2BuffersList() = default;
+
+ mutable std::mutex mLock;
+ std::set<size_t> mFreeBuffers GUARDED_BY(mLock);
};
-void V4L2BuffersList::ReturnBuffer(size_t buffer_id) {
- base::AutoLock auto_lock(lock_);
+void V4L2BuffersList::returnBuffer(size_t bufferId) {
+ std::lock_guard<std::mutex> lock(mLock);
- auto inserted = free_buffers_.emplace(buffer_id);
- DCHECK(inserted.second);
+ auto inserted = mFreeBuffers.emplace(bufferId);
+ if (!inserted.second) {
+ ALOGE("Returning buffer failed");
+ }
}
-base::Optional<size_t> V4L2BuffersList::GetFreeBuffer() {
- base::AutoLock auto_lock(lock_);
+std::optional<size_t> V4L2BuffersList::getFreeBuffer() {
+ std::lock_guard<std::mutex> lock(mLock);
- auto iter = free_buffers_.begin();
- if (iter == free_buffers_.end()) {
- DVLOGF(4) << "No free buffer available!";
- return base::nullopt;
- }
+ auto iter = mFreeBuffers.begin();
+ if (iter == mFreeBuffers.end()) {
+ ALOGV("No free buffer available!");
+ return std::nullopt;
+ }
- size_t buffer_id = *iter;
- free_buffers_.erase(iter);
+ size_t bufferId = *iter;
+ mFreeBuffers.erase(iter);
- return buffer_id;
+ return bufferId;
}
-base::Optional<size_t> V4L2BuffersList::GetFreeBuffer(
- size_t requested_buffer_id) {
- base::AutoLock auto_lock(lock_);
+std::optional<size_t> V4L2BuffersList::getFreeBuffer(size_t requestedBufferId) {
+ std::lock_guard<std::mutex> lock(mLock);
- return (free_buffers_.erase(requested_buffer_id) > 0)
- ? base::make_optional(requested_buffer_id)
- : base::nullopt;
+ return (mFreeBuffers.erase(requestedBufferId) > 0) ? std::make_optional(requestedBufferId)
+ : std::nullopt;
}
size_t V4L2BuffersList::size() const {
- base::AutoLock auto_lock(lock_);
+ std::lock_guard<std::mutex> lock(mLock);
- return free_buffers_.size();
+ return mFreeBuffers.size();
}
-// Module-private class that let users query/write V4L2 buffer information.
-// It also makes some private V4L2Queue methods available to this module only.
+// Module-private class that let users query/write V4L2 buffer information. It also makes some
+// private V4L2Queue methods available to this module only.
class V4L2BufferRefBase {
- public:
- V4L2BufferRefBase(const struct v4l2_buffer& v4l2_buffer,
- base::WeakPtr<V4L2Queue> queue);
- ~V4L2BufferRefBase();
-
- bool QueueBuffer();
- void* GetPlaneMapping(const size_t plane);
-
- // Checks that the number of passed FDs is adequate for the current format
- // and buffer configuration. Only useful for DMABUF buffers.
- bool CheckNumFDsForFormat(const size_t num_fds) const;
-
- // Data from the buffer, that users can query and/or write.
- struct v4l2_buffer v4l2_buffer_;
- // WARNING: do not change this to a vector or something smaller than
- // VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
- // the number of allocated planes, resulting in memory corruption.
- struct v4l2_plane v4l2_planes_[VIDEO_MAX_PLANES];
-
- private:
- size_t BufferId() const { return v4l2_buffer_.index; }
-
- friend class V4L2WritableBufferRef;
- // A weak pointer to the queue this buffer belongs to. Will remain valid as
- // long as the underlying V4L2 buffer is valid too.
- // This can only be accessed from the sequence protected by sequence_checker_.
- // Thread-safe methods (like ~V4L2BufferRefBase) must *never* access this.
- base::WeakPtr<V4L2Queue> queue_;
- // Where to return this buffer if it goes out of scope without being queued.
- scoped_refptr<V4L2BuffersList> return_to_;
- bool queued = false;
-
- SEQUENCE_CHECKER(sequence_checker_);
- DISALLOW_COPY_AND_ASSIGN(V4L2BufferRefBase);
+public:
+ V4L2BufferRefBase(const struct v4l2_buffer& v4l2Buffer, base::WeakPtr<V4L2Queue> queue);
+ ~V4L2BufferRefBase();
+
+ V4L2BufferRefBase(const V4L2BufferRefBase&) = delete;
+ V4L2BufferRefBase& operator=(const V4L2BufferRefBase&) = delete;
+
+ bool queueBuffer();
+ void* getPlaneMapping(const size_t plane);
+
+ // Checks that the number of passed FDs is adequate for the current format and buffer
+ // configuration. Only useful for DMABUF buffers.
+ bool checkNumFDsForFormat(const size_t numFds) const;
+
+ // Data from the buffer, that users can query and/or write.
+ struct v4l2_buffer mV4l2Buffer;
+ // WARNING: do not change this to a vector or something smaller than VIDEO_MAX_PLANES, otherwise
+ // the Tegra libv4l2 will write data beyond the number of allocated planes, resulting in memory
+ // corruption.
+ struct v4l2_plane mV4l2Planes[VIDEO_MAX_PLANES];
+
+private:
+ size_t bufferId() const { return mV4l2Buffer.index; }
+
+ friend class V4L2WritableBufferRef;
+ // A weak pointer to the queue this buffer belongs to. Will remain valid as long as the
+ // underlying V4L2 buffer is valid too. This can only be accessed from the sequence protected by
+ // sequence_checker_. Thread-safe methods (like ~V4L2BufferRefBase) must *never* access this.
+ base::WeakPtr<V4L2Queue> mQueue;
+ // Where to return this buffer if it goes out of scope without being queued.
+ scoped_refptr<V4L2BuffersList> mReturnTo;
+ bool queued = false;
+
+ SEQUENCE_CHECKER(mSequenceChecker);
};
-V4L2BufferRefBase::V4L2BufferRefBase(const struct v4l2_buffer& v4l2_buffer,
+V4L2BufferRefBase::V4L2BufferRefBase(const struct v4l2_buffer& v4l2Buffer,
base::WeakPtr<V4L2Queue> queue)
- : queue_(std::move(queue)), return_to_(queue_->free_buffers_) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(V4L2_TYPE_IS_MULTIPLANAR(v4l2_buffer.type));
- DCHECK_LE(v4l2_buffer.length, base::size(v4l2_planes_));
- DCHECK(return_to_);
+ : mQueue(std::move(queue)), mReturnTo(mQueue->mFreeBuffers) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(V4L2_TYPE_IS_MULTIPLANAR(v4l2Buffer.type));
+ ALOG_ASSERT(v4l2Buffer.length <= base::size(mV4l2Planes));
+ ALOG_ASSERT(mReturnTo);
- memcpy(&v4l2_buffer_, &v4l2_buffer, sizeof(v4l2_buffer_));
- memcpy(v4l2_planes_, v4l2_buffer.m.planes,
- sizeof(struct v4l2_plane) * v4l2_buffer.length);
- v4l2_buffer_.m.planes = v4l2_planes_;
+ memcpy(&mV4l2Buffer, &v4l2Buffer, sizeof(mV4l2Buffer));
+ memcpy(mV4l2Planes, v4l2Buffer.m.planes, sizeof(struct v4l2_plane) * v4l2Buffer.length);
+ mV4l2Buffer.m.planes = mV4l2Planes;
}
V4L2BufferRefBase::~V4L2BufferRefBase() {
- // We are the last reference and are only accessing the thread-safe
- // return_to_, so we are safe to call from any sequence.
- // If we have been queued, then the queue is our owner so we don't need to
- // return to the free buffers list.
- if (!queued)
- return_to_->ReturnBuffer(BufferId());
+ // We are the last reference and are only accessing the thread-safe mReturnTo, so we are safe
+ // to call from any sequence. If we have been queued, then the queue is our owner so we don't
+ // need to return to the free buffers list.
+ if (!queued) mReturnTo->returnBuffer(bufferId());
}
-bool V4L2BufferRefBase::QueueBuffer() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+bool V4L2BufferRefBase::queueBuffer() {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- if (!queue_)
- return false;
+ if (!mQueue) return false;
- queued = queue_->QueueBuffer(&v4l2_buffer_);
+ queued = mQueue->queueBuffer(&mV4l2Buffer);
- return queued;
+ return queued;
}
-void* V4L2BufferRefBase::GetPlaneMapping(const size_t plane) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+void* V4L2BufferRefBase::getPlaneMapping(const size_t plane) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- if (!queue_)
- return nullptr;
+ if (!mQueue) return nullptr;
- return queue_->buffers_[BufferId()]->GetPlaneMapping(plane);
+ return mQueue->mBuffers[bufferId()]->getPlaneMapping(plane);
}
-bool V4L2BufferRefBase::CheckNumFDsForFormat(const size_t num_fds) const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+bool V4L2BufferRefBase::checkNumFDsForFormat(const size_t numFds) const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- if (!queue_)
- return false;
+ if (!mQueue) return false;
- // We have not used SetFormat(), assume this is ok.
- // Hopefully we standardize SetFormat() in the future.
- if (!queue_->current_format_)
- return true;
+ // We have not used SetFormat(), assume this is ok.
+ // Hopefully we standardize SetFormat() in the future.
+ if (!mQueue->mCurrentFormat) return true;
- const size_t required_fds = queue_->current_format_->fmt.pix_mp.num_planes;
- // Sanity check.
- DCHECK_EQ(v4l2_buffer_.length, required_fds);
- if (num_fds < required_fds) {
- VLOGF(1) << "Insufficient number of FDs given for the current format. "
- << num_fds << " provided, " << required_fds << " required.";
- return false;
- }
+ const size_t requiredFds = mQueue->mCurrentFormat->fmt.pix_mp.num_planes;
+ // Sanity check.
+ ALOG_ASSERT(mV4l2Buffer.length == requiredFds);
+ if (numFds < requiredFds) {
+ ALOGE("Insufficient number of FDs given for the current format. "
+ "%zu provided, %zu required.",
+ numFds, requiredFds);
+ return false;
+ }
- const auto* planes = v4l2_buffer_.m.planes;
- for (size_t i = v4l2_buffer_.length - 1; i >= num_fds; --i) {
- // Assume that an fd is a duplicate of a previous plane's fd if offset != 0.
- // Otherwise, if offset == 0, return error as it is likely pointing to
- // a new plane.
- if (planes[i].data_offset == 0) {
- VLOGF(1) << "Additional dmabuf fds point to a new buffer.";
- return false;
+ const auto* planes = mV4l2Buffer.m.planes;
+ for (size_t i = mV4l2Buffer.length - 1; i >= numFds; --i) {
+ // Assume that an fd is a duplicate of a previous plane's fd if offset != 0. Otherwise, if
+ // offset == 0, return error as it is likely pointing to a new plane.
+ if (planes[i].data_offset == 0) {
+ ALOGE("Additional dmabuf fds point to a new buffer.");
+ return false;
+ }
}
- }
- return true;
+ return true;
}
-V4L2WritableBufferRef::V4L2WritableBufferRef(
- const struct v4l2_buffer& v4l2_buffer,
- base::WeakPtr<V4L2Queue> queue)
- : buffer_data_(
- std::make_unique<V4L2BufferRefBase>(v4l2_buffer, std::move(queue))) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+V4L2WritableBufferRef::V4L2WritableBufferRef(const struct v4l2_buffer& v4l2Buffer,
+ base::WeakPtr<V4L2Queue> queue)
+ : mBufferData(std::make_unique<V4L2BufferRefBase>(v4l2Buffer, std::move(queue))) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
}
V4L2WritableBufferRef::V4L2WritableBufferRef(V4L2WritableBufferRef&& other)
- : buffer_data_(std::move(other.buffer_data_)) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK_CALLED_ON_VALID_SEQUENCE(other.sequence_checker_);
+ : mBufferData(std::move(other.mBufferData)) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(other.mSequenceChecker);
}
V4L2WritableBufferRef::~V4L2WritableBufferRef() {
- // Only valid references should be sequence-checked
- if (buffer_data_) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- }
+ // Only valid references should be sequence-checked
+ if (mBufferData) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ }
}
-V4L2WritableBufferRef& V4L2WritableBufferRef::operator=(
- V4L2WritableBufferRef&& other) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK_CALLED_ON_VALID_SEQUENCE(other.sequence_checker_);
+V4L2WritableBufferRef& V4L2WritableBufferRef::operator=(V4L2WritableBufferRef&& other) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(other.mSequenceChecker);
- if (this == &other)
- return *this;
+ if (this == &other) return *this;
- buffer_data_ = std::move(other.buffer_data_);
+ mBufferData = std::move(other.mBufferData);
- return *this;
+ return *this;
}
-enum v4l2_memory V4L2WritableBufferRef::Memory() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+enum v4l2_memory V4L2WritableBufferRef::memory() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- return static_cast<enum v4l2_memory>(buffer_data_->v4l2_buffer_.memory);
+ return static_cast<enum v4l2_memory>(mBufferData->mV4l2Buffer.memory);
}
-bool V4L2WritableBufferRef::DoQueue() && {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+bool V4L2WritableBufferRef::doQueue() && {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- bool queued = buffer_data_->QueueBuffer();
+ bool queued = mBufferData->queueBuffer();
- // Clear our own reference.
- buffer_data_.reset();
+ // Clear our own reference.
+ mBufferData.reset();
- return queued;
+ return queued;
}
-bool V4L2WritableBufferRef::QueueMMap() && {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+bool V4L2WritableBufferRef::queueMMap() && {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- // Move ourselves so our data gets freed no matter when we return
- V4L2WritableBufferRef self(std::move(*this));
+ // Move ourselves so our data gets freed no matter when we return
+ V4L2WritableBufferRef self(std::move(*this));
- if (self.Memory() != V4L2_MEMORY_MMAP) {
- VLOGF(1) << "Called on invalid buffer type!";
- return false;
- }
+ if (self.memory() != V4L2_MEMORY_MMAP) {
+ ALOGE("Called on invalid buffer type!");
+ return false;
+ }
- return std::move(self).DoQueue();
+ return std::move(self).doQueue();
}
-bool V4L2WritableBufferRef::QueueUserPtr(const std::vector<void*>& ptrs) && {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
-
- // Move ourselves so our data gets freed no matter when we return
- V4L2WritableBufferRef self(std::move(*this));
+bool V4L2WritableBufferRef::queueUserPtr(const std::vector<void*>& ptrs) && {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- if (self.Memory() != V4L2_MEMORY_USERPTR) {
- VLOGF(1) << "Called on invalid buffer type!";
- return false;
- }
+ // Move ourselves so our data gets freed no matter when we return
+ V4L2WritableBufferRef self(std::move(*this));
- if (ptrs.size() != self.PlanesCount()) {
- VLOGF(1) << "Provided " << ptrs.size() << " pointers while we require "
- << self.buffer_data_->v4l2_buffer_.length << ".";
- return false;
- }
-
- for (size_t i = 0; i < ptrs.size(); i++)
- self.buffer_data_->v4l2_buffer_.m.planes[i].m.userptr =
- reinterpret_cast<unsigned long>(ptrs[i]);
-
- return std::move(self).DoQueue();
-}
+ if (self.memory() != V4L2_MEMORY_USERPTR) {
+ ALOGE("Called on invalid buffer type!");
+ return false;
+ }
-bool V4L2WritableBufferRef::QueueDMABuf(const std::vector<base::ScopedFD>& scoped_fds) && {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (ptrs.size() != self.planesCount()) {
+ ALOGE("Provided %zu pointers while we require %u.", ptrs.size(),
+ self.mBufferData->mV4l2Buffer.length);
+ return false;
+ }
- std::vector<int> fds;
- fds.reserve(scoped_fds.size());
- for (const base::ScopedFD& scoped_fd : scoped_fds)
- fds.push_back(scoped_fd.get());
+ for (size_t i = 0; i < ptrs.size(); i++) {
+ self.mBufferData->mV4l2Buffer.m.planes[i].m.userptr =
+ reinterpret_cast<unsigned long>(ptrs[i]);
+ }
- return std::move(*this).QueueDMABuf(fds);
+ return std::move(self).doQueue();
}
-bool V4L2WritableBufferRef::QueueDMABuf(const std::vector<int>& fds) && {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+bool V4L2WritableBufferRef::queueDMABuf(const std::vector<int>& fds) && {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- // Move ourselves so our data gets freed no matter when we return
- V4L2WritableBufferRef self(std::move(*this));
+ // Move ourselves so our data gets freed no matter when we return
+ V4L2WritableBufferRef self(std::move(*this));
- if (self.Memory() != V4L2_MEMORY_DMABUF) {
- VLOGF(1) << "Called on invalid buffer type!";
- return false;
- }
+ if (self.memory() != V4L2_MEMORY_DMABUF) {
+ ALOGE("Called on invalid buffer type!");
+ return false;
+ }
- if (!self.buffer_data_->CheckNumFDsForFormat(fds.size()))
- return false;
+ if (!self.mBufferData->checkNumFDsForFormat(fds.size())) return false;
- size_t num_planes = self.PlanesCount();
- for (size_t i = 0; i < num_planes; i++)
- self.buffer_data_->v4l2_buffer_.m.planes[i].m.fd = fds[i];
+ size_t numPlanes = self.planesCount();
+ for (size_t i = 0; i < numPlanes; i++) self.mBufferData->mV4l2Buffer.m.planes[i].m.fd = fds[i];
- return std::move(self).DoQueue();
+ return std::move(self).doQueue();
}
-size_t V4L2WritableBufferRef::PlanesCount() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+size_t V4L2WritableBufferRef::planesCount() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- return buffer_data_->v4l2_buffer_.length;
+ return mBufferData->mV4l2Buffer.length;
}
-size_t V4L2WritableBufferRef::GetPlaneSize(const size_t plane) const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+size_t V4L2WritableBufferRef::getPlaneSize(const size_t plane) const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- if (plane >= PlanesCount()) {
- VLOGF(1) << "Invalid plane " << plane << " requested.";
- return 0;
- }
+ if (plane >= planesCount()) {
+ ALOGE("Invalid plane %zu requested.", plane);
+ return 0;
+ }
- return buffer_data_->v4l2_buffer_.m.planes[plane].length;
+ return mBufferData->mV4l2Buffer.m.planes[plane].length;
}
-void V4L2WritableBufferRef::SetPlaneSize(const size_t plane,
- const size_t size) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+void V4L2WritableBufferRef::setPlaneSize(const size_t plane, const size_t size) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- enum v4l2_memory memory = Memory();
- if (memory == V4L2_MEMORY_MMAP) {
- DCHECK_EQ(buffer_data_->v4l2_buffer_.m.planes[plane].length, size);
- return;
- }
- DCHECK(memory == V4L2_MEMORY_USERPTR || memory == V4L2_MEMORY_DMABUF);
+ enum v4l2_memory mem = memory();
+ if (mem == V4L2_MEMORY_MMAP) {
+ ALOG_ASSERT(mBufferData->mV4l2Buffer.m.planes[plane].length == size);
+ return;
+ }
+ ALOG_ASSERT(mem == V4L2_MEMORY_USERPTR || mem == V4L2_MEMORY_DMABUF);
- if (plane >= PlanesCount()) {
- VLOGF(1) << "Invalid plane " << plane << " requested.";
- return;
- }
+ if (plane >= planesCount()) {
+ ALOGE("Invalid plane %zu requested.", plane);
+ return;
+ }
- buffer_data_->v4l2_buffer_.m.planes[plane].length = size;
+ mBufferData->mV4l2Buffer.m.planes[plane].length = size;
}
-void* V4L2WritableBufferRef::GetPlaneMapping(const size_t plane) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+void* V4L2WritableBufferRef::getPlaneMapping(const size_t plane) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- return buffer_data_->GetPlaneMapping(plane);
+ return mBufferData->getPlaneMapping(plane);
}
-void V4L2WritableBufferRef::SetTimeStamp(const struct timeval& timestamp) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+void V4L2WritableBufferRef::setTimeStamp(const struct timeval& timestamp) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- buffer_data_->v4l2_buffer_.timestamp = timestamp;
+ mBufferData->mV4l2Buffer.timestamp = timestamp;
}
-const struct timeval& V4L2WritableBufferRef::GetTimeStamp() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+const struct timeval& V4L2WritableBufferRef::getTimeStamp() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- return buffer_data_->v4l2_buffer_.timestamp;
+ return mBufferData->mV4l2Buffer.timestamp;
}
-void V4L2WritableBufferRef::SetPlaneBytesUsed(const size_t plane,
- const size_t bytes_used) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+void V4L2WritableBufferRef::setPlaneBytesUsed(const size_t plane, const size_t bytesUsed) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- if (plane >= PlanesCount()) {
- VLOGF(1) << "Invalid plane " << plane << " requested.";
- return;
- }
+ if (plane >= planesCount()) {
+ ALOGE("Invalid plane %zu requested.", plane);
+ return;
+ }
- if (bytes_used > GetPlaneSize(plane)) {
- VLOGF(1) << "Set bytes used " << bytes_used << " larger than plane size "
- << GetPlaneSize(plane) << ".";
- return;
- }
+ if (bytesUsed > getPlaneSize(plane)) {
+ ALOGE("Set bytes used %zu larger than plane size %zu.", bytesUsed, getPlaneSize(plane));
+ return;
+ }
- buffer_data_->v4l2_buffer_.m.planes[plane].bytesused = bytes_used;
+ mBufferData->mV4l2Buffer.m.planes[plane].bytesused = bytesUsed;
}
-size_t V4L2WritableBufferRef::GetPlaneBytesUsed(const size_t plane) const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+size_t V4L2WritableBufferRef::getPlaneBytesUsed(const size_t plane) const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- if (plane >= PlanesCount()) {
- VLOGF(1) << "Invalid plane " << plane << " requested.";
- return 0;
- }
+ if (plane >= planesCount()) {
+ ALOGE("Invalid plane %zu requested.", plane);
+ return 0;
+ }
- return buffer_data_->v4l2_buffer_.m.planes[plane].bytesused;
+ return mBufferData->mV4l2Buffer.m.planes[plane].bytesused;
}
-void V4L2WritableBufferRef::SetPlaneDataOffset(const size_t plane,
- const size_t data_offset) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+void V4L2WritableBufferRef::setPlaneDataOffset(const size_t plane, const size_t dataOffset) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- if (plane >= PlanesCount()) {
- VLOGF(1) << "Invalid plane " << plane << " requested.";
- return;
- }
+ if (plane >= planesCount()) {
+ ALOGE("Invalid plane %zu requested.", plane);
+ return;
+ }
- buffer_data_->v4l2_buffer_.m.planes[plane].data_offset = data_offset;
+ mBufferData->mV4l2Buffer.m.planes[plane].data_offset = dataOffset;
}
-size_t V4L2WritableBufferRef::BufferId() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+size_t V4L2WritableBufferRef::bufferId() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- return buffer_data_->v4l2_buffer_.index;
+ return mBufferData->mV4l2Buffer.index;
}
-V4L2ReadableBuffer::V4L2ReadableBuffer(const struct v4l2_buffer& v4l2_buffer,
+V4L2ReadableBuffer::V4L2ReadableBuffer(const struct v4l2_buffer& v4l2Buffer,
base::WeakPtr<V4L2Queue> queue)
- : buffer_data_(
- std::make_unique<V4L2BufferRefBase>(v4l2_buffer, std::move(queue))) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ : mBufferData(std::make_unique<V4L2BufferRefBase>(v4l2Buffer, std::move(queue))) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
}
V4L2ReadableBuffer::~V4L2ReadableBuffer() {
- // This method is thread-safe. Since we are the destructor, we are guaranteed
- // to be called from the only remaining reference to us. Also, we are just
- // calling the destructor of buffer_data_, which is also thread-safe.
- DCHECK(buffer_data_);
+ // This method is thread-safe. Since we are the destructor, we are guaranteed to be called from
+ // the only remaining reference to us. Also, we are just calling the destructor of buffer_data_,
+ // which is also thread-safe.
+ ALOG_ASSERT(mBufferData);
}
-bool V4L2ReadableBuffer::IsLast() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+bool V4L2ReadableBuffer::isLast() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- return buffer_data_->v4l2_buffer_.flags & V4L2_BUF_FLAG_LAST;
+ return mBufferData->mV4l2Buffer.flags & V4L2_BUF_FLAG_LAST;
}
-bool V4L2ReadableBuffer::IsKeyframe() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+bool V4L2ReadableBuffer::isKeyframe() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- return buffer_data_->v4l2_buffer_.flags & V4L2_BUF_FLAG_KEYFRAME;
+ return mBufferData->mV4l2Buffer.flags & V4L2_BUF_FLAG_KEYFRAME;
}
-struct timeval V4L2ReadableBuffer::GetTimeStamp() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+struct timeval V4L2ReadableBuffer::getTimeStamp() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- return buffer_data_->v4l2_buffer_.timestamp;
+ return mBufferData->mV4l2Buffer.timestamp;
}
-size_t V4L2ReadableBuffer::PlanesCount() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+size_t V4L2ReadableBuffer::planesCount() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- return buffer_data_->v4l2_buffer_.length;
+ return mBufferData->mV4l2Buffer.length;
}
-const void* V4L2ReadableBuffer::GetPlaneMapping(const size_t plane) const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+const void* V4L2ReadableBuffer::getPlaneMapping(const size_t plane) const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ DCHECK(mBufferData);
- return buffer_data_->GetPlaneMapping(plane);
+ return mBufferData->getPlaneMapping(plane);
}
-size_t V4L2ReadableBuffer::GetPlaneBytesUsed(const size_t plane) const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+size_t V4L2ReadableBuffer::getPlaneBytesUsed(const size_t plane) const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- if (plane >= PlanesCount()) {
- VLOGF(1) << "Invalid plane " << plane << " requested.";
- return 0;
- }
+ if (plane >= planesCount()) {
+ ALOGE("Invalid plane %zu requested.", plane);
+ return 0;
+ }
- return buffer_data_->v4l2_planes_[plane].bytesused;
+ return mBufferData->mV4l2Planes[plane].bytesused;
}
-size_t V4L2ReadableBuffer::GetPlaneDataOffset(const size_t plane) const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+size_t V4L2ReadableBuffer::getPlaneDataOffset(const size_t plane) const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- if (plane >= PlanesCount()) {
- VLOGF(1) << "Invalid plane " << plane << " requested.";
- return 0;
- }
+ if (plane >= planesCount()) {
+ ALOGE("Invalid plane %zu requested.", plane);
+ return 0;
+ }
- return buffer_data_->v4l2_planes_[plane].data_offset;
+ return mBufferData->mV4l2Planes[plane].data_offset;
}
-size_t V4L2ReadableBuffer::BufferId() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(buffer_data_);
+size_t V4L2ReadableBuffer::bufferId() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(mBufferData);
- return buffer_data_->v4l2_buffer_.index;
+ return mBufferData->mV4l2Buffer.index;
}
-// This class is used to expose buffer reference classes constructors to
-// this module. This is to ensure that nobody else can create buffer references.
+// This class is used to expose buffer reference classes constructors to this module. This is to
+// ensure that nobody else can create buffer references.
class V4L2BufferRefFactory {
- public:
- static V4L2WritableBufferRef CreateWritableRef(
- const struct v4l2_buffer& v4l2_buffer,
- base::WeakPtr<V4L2Queue> queue) {
- return V4L2WritableBufferRef(v4l2_buffer, std::move(queue));
- }
-
- static V4L2ReadableBufferRef CreateReadableRef(
- const struct v4l2_buffer& v4l2_buffer,
- base::WeakPtr<V4L2Queue> queue) {
- return new V4L2ReadableBuffer(v4l2_buffer, std::move(queue));
- }
+public:
+ static V4L2WritableBufferRef CreateWritableRef(const struct v4l2_buffer& v4l2Buffer,
+ base::WeakPtr<V4L2Queue> queue) {
+ return V4L2WritableBufferRef(v4l2Buffer, std::move(queue));
+ }
+
+ static V4L2ReadableBufferRef CreateReadableRef(const struct v4l2_buffer& v4l2Buffer,
+ base::WeakPtr<V4L2Queue> queue) {
+ return new V4L2ReadableBuffer(v4l2Buffer, std::move(queue));
+ }
};
-// Helper macros that print the queue type with logs.
-#define VPQLOGF(level) \
- VPLOGF(level) << "(" << V4L2Device::V4L2BufferTypeToString(type_) << ") "
-#define VQLOGF(level) \
- VLOGF(level) << "(" << V4L2Device::V4L2BufferTypeToString(type_) << ") "
-#define DVQLOGF(level) \
- DVLOGF(level) << "(" << V4L2Device::V4L2BufferTypeToString(type_) << ") "
+//// Helper macros that print the queue type with logs.
+#define ALOGEQ(fmt, ...) ALOGE("(%s)" fmt, V4L2Device::v4L2BufferTypeToString(mType), ##__VA_ARGS__)
+#define ALOGVQ(fmt, ...) ALOGD("(%s)" fmt, V4L2Device::v4L2BufferTypeToString(mType), ##__VA_ARGS__)
-V4L2Queue::V4L2Queue(scoped_refptr<V4L2Device> dev,
- enum v4l2_buf_type type,
- base::OnceClosure destroy_cb)
- : type_(type),
- device_(dev),
- destroy_cb_(std::move(destroy_cb)),
- weak_this_factory_(this) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+V4L2Queue::V4L2Queue(scoped_refptr<V4L2Device> dev, enum v4l2_buf_type type,
+ base::OnceClosure destroyCb)
+ : mType(type), mDevice(dev), mDestroyCb(std::move(destroyCb)) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
}
V4L2Queue::~V4L2Queue() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (is_streaming_) {
- VQLOGF(1) << "Queue is still streaming, trying to stop it...";
- Streamoff();
- }
-
- DCHECK(queued_buffers_.empty());
- DCHECK(!free_buffers_);
-
- if (!buffers_.empty()) {
- VQLOGF(1) << "Buffers are still allocated, trying to deallocate them...";
- DeallocateBuffers();
- }
-
- std::move(destroy_cb_).Run();
-}
-
-base::Optional<struct v4l2_format> V4L2Queue::SetFormat(uint32_t fourcc,
- const Size& size,
- size_t buffer_size,
- uint32_t stride) {
- struct v4l2_format format = BuildV4L2Format(type_, fourcc, size, buffer_size, stride);
- if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0 ||
- format.fmt.pix_mp.pixelformat != fourcc) {
- VPQLOGF(2) << "Failed to set format (format_fourcc=0x" << std::hex << fourcc
- << ")";
- return base::nullopt;
- }
-
- current_format_ = format;
- return current_format_;
-}
-
-base::Optional<struct v4l2_format> V4L2Queue::TryFormat(uint32_t fourcc,
- const Size& size,
- size_t buffer_size) {
- struct v4l2_format format = BuildV4L2Format(type_, fourcc, size, buffer_size, 0);
- if (device_->Ioctl(VIDIOC_TRY_FMT, &format) != 0 ||
- format.fmt.pix_mp.pixelformat != fourcc) {
- VPQLOGF(2) << "Tried format not supported (format_fourcc=0x" << std::hex
- << fourcc << ")";
- return base::nullopt;
- }
-
- return format;
-}
-
-std::pair<base::Optional<struct v4l2_format>, int> V4L2Queue::GetFormat() {
- struct v4l2_format format;
- memset(&format, 0, sizeof(format));
- format.type = type_;
- if (device_->Ioctl(VIDIOC_G_FMT, &format) != 0) {
- VPQLOGF(2) << "Failed to get format";
- return std::make_pair(base::nullopt, errno);
- }
-
- return std::make_pair(format, 0);
-}
-
-size_t V4L2Queue::AllocateBuffers(size_t count, enum v4l2_memory memory) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(!free_buffers_);
- DCHECK_EQ(queued_buffers_.size(), 0u);
-
- if (IsStreaming()) {
- VQLOGF(1) << "Cannot allocate buffers while streaming.";
- return 0;
- }
-
- if (buffers_.size() != 0) {
- VQLOGF(1)
- << "Cannot allocate new buffers while others are still allocated.";
- return 0;
- }
-
- if (count == 0) {
- VQLOGF(1) << "Attempting to allocate 0 buffers.";
- return 0;
- }
-
- // First query the number of planes in the buffers we are about to request.
- // This should not be required, but Tegra's VIDIOC_QUERYBUF will fail on
- // output buffers if the number of specified planes does not exactly match the
- // format.
- struct v4l2_format format = {.type = type_};
- int ret = device_->Ioctl(VIDIOC_G_FMT, &format);
- if (ret) {
- VPQLOGF(1) << "VIDIOC_G_FMT failed";
- return 0;
- }
- planes_count_ = format.fmt.pix_mp.num_planes;
- DCHECK_LE(planes_count_, static_cast<size_t>(VIDEO_MAX_PLANES));
-
- struct v4l2_requestbuffers reqbufs;
- memset(&reqbufs, 0, sizeof(reqbufs));
- reqbufs.count = count;
- reqbufs.type = type_;
- reqbufs.memory = memory;
- DVQLOGF(3) << "Requesting " << count << " buffers.";
-
- ret = device_->Ioctl(VIDIOC_REQBUFS, &reqbufs);
- if (ret) {
- VPQLOGF(1) << "VIDIOC_REQBUFS failed";
- return 0;
- }
- DVQLOGF(3) << "queue " << type_ << ": got " << reqbufs.count << " buffers.";
-
- memory_ = memory;
-
- free_buffers_ = new V4L2BuffersList();
-
- // Now query all buffer information.
- for (size_t i = 0; i < reqbufs.count; i++) {
- auto buffer = V4L2Buffer::Create(device_, type_, memory_, format, i);
-
- if (!buffer) {
- DeallocateBuffers();
-
- return 0;
- }
-
- buffers_.emplace_back(std::move(buffer));
- free_buffers_->ReturnBuffer(i);
- }
-
- DCHECK(free_buffers_);
- DCHECK_EQ(free_buffers_->size(), buffers_.size());
- DCHECK_EQ(queued_buffers_.size(), 0u);
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+
+ if (mIsStreaming) {
+ ALOGEQ("Queue is still streaming, trying to stop it...");
+ streamoff();
+ }
+
+ ALOG_ASSERT(mQueuedBuffers.empty());
+ ALOG_ASSERT(!mFreeBuffers);
+
+ if (!mBuffers.empty()) {
+ ALOGEQ("Buffers are still allocated, trying to deallocate them...");
+ deallocateBuffers();
+ }
- return buffers_.size();
+ std::move(mDestroyCb).Run();
}
-bool V4L2Queue::DeallocateBuffers() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (IsStreaming()) {
- VQLOGF(1) << "Cannot deallocate buffers while streaming.";
- return false;
- }
+std::optional<struct v4l2_format> V4L2Queue::setFormat(uint32_t fourcc, const media::Size& size,
+ size_t bufferSize, uint32_t stride) {
+ struct v4l2_format format = buildV4L2Format(mType, fourcc, size, bufferSize, stride);
+ if (mDevice->ioctl(VIDIOC_S_FMT, &format) != 0 || format.fmt.pix_mp.pixelformat != fourcc) {
+ ALOGEQ("Failed to set format (format_fourcc=0x%" PRIx32 ")", fourcc);
+ return std::nullopt;
+ }
- if (buffers_.size() == 0)
- return true;
+ mCurrentFormat = format;
+ return mCurrentFormat;
+}
+
+std::optional<struct v4l2_format> V4L2Queue::tryFormat(uint32_t fourcc, const media::Size& size,
+ size_t bufferSize) {
+ struct v4l2_format format = buildV4L2Format(mType, fourcc, size, bufferSize, 0);
+ if (mDevice->ioctl(VIDIOC_TRY_FMT, &format) != 0 || format.fmt.pix_mp.pixelformat != fourcc) {
+ ALOGEQ("Tried format not supported (format_fourcc=0x%" PRIx32 ")", fourcc);
+ return std::nullopt;
+ }
+
+ return format;
+}
- weak_this_factory_.InvalidateWeakPtrs();
- buffers_.clear();
- free_buffers_ = nullptr;
+std::pair<std::optional<struct v4l2_format>, int> V4L2Queue::getFormat() {
+ struct v4l2_format format;
+ memset(&format, 0, sizeof(format));
+ format.type = mType;
+ if (mDevice->ioctl(VIDIOC_G_FMT, &format) != 0) {
+ ALOGEQ("Failed to get format");
+ return std::make_pair(std::nullopt, errno);
+ }
+
+ return std::make_pair(format, 0);
+}
+
+size_t V4L2Queue::allocateBuffers(size_t count, enum v4l2_memory memory) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ ALOG_ASSERT(!mFreeBuffers);
+ ALOG_ASSERT(mQueuedBuffers.size() == 0u);
- // Free all buffers.
- struct v4l2_requestbuffers reqbufs;
- memset(&reqbufs, 0, sizeof(reqbufs));
- reqbufs.count = 0;
- reqbufs.type = type_;
- reqbufs.memory = memory_;
+ if (isStreaming()) {
+ ALOGEQ("Cannot allocate buffers while streaming.");
+ return 0;
+ }
- int ret = device_->Ioctl(VIDIOC_REQBUFS, &reqbufs);
- if (ret) {
- VPQLOGF(1) << "VIDIOC_REQBUFS failed";
- return false;
- }
+ if (mBuffers.size() != 0) {
+ ALOGEQ("Cannot allocate new buffers while others are still allocated.");
+ return 0;
+ }
- DCHECK(!free_buffers_);
- DCHECK_EQ(queued_buffers_.size(), 0u);
+ if (count == 0) {
+ ALOGEQ("Attempting to allocate 0 buffers.");
+ return 0;
+ }
- return true;
+ // First query the number of planes in the buffers we are about to request. This should not be
+ // required, but Tegra's VIDIOC_QUERYBUF will fail on output buffers if the number of specified
+ // planes does not exactly match the format.
+ struct v4l2_format format = {.type = mType};
+ int ret = mDevice->ioctl(VIDIOC_G_FMT, &format);
+ if (ret) {
+ ALOGEQ("VIDIOC_G_FMT failed");
+ return 0;
+ }
+ mPlanesCount = format.fmt.pix_mp.num_planes;
+ ALOG_ASSERT(mPlanesCount <= static_cast<size_t>(VIDEO_MAX_PLANES));
+
+ struct v4l2_requestbuffers reqbufs;
+ memset(&reqbufs, 0, sizeof(reqbufs));
+ reqbufs.count = count;
+ reqbufs.type = mType;
+ reqbufs.memory = memory;
+ ALOGVQ("Requesting %zu buffers.", count);
+
+ ret = mDevice->ioctl(VIDIOC_REQBUFS, &reqbufs);
+ if (ret) {
+ ALOGEQ("VIDIOC_REQBUFS failed");
+ return 0;
+ }
+ ALOGVQ("Queue %u: got %u buffers.", mType, reqbufs.count);
+
+ mMemory = memory;
+
+ mFreeBuffers = new V4L2BuffersList();
+
+ // Now query all buffer information.
+ for (size_t i = 0; i < reqbufs.count; i++) {
+ auto buffer = V4L2Buffer::create(mDevice, mType, mMemory, format, i);
+
+ if (!buffer) {
+ deallocateBuffers();
+
+ return 0;
+ }
+
+ mBuffers.emplace_back(std::move(buffer));
+ mFreeBuffers->returnBuffer(i);
+ }
+
+ ALOG_ASSERT(mFreeBuffers);
+ ALOG_ASSERT(mFreeBuffers->size() == mBuffers.size());
+ ALOG_ASSERT(mQueuedBuffers.size() == 0u);
+
+ return mBuffers.size();
}
-size_t V4L2Queue::GetMemoryUsage() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- size_t usage = 0;
- for (const auto& buf : buffers_) {
- usage += buf->GetMemoryUsage();
- }
- return usage;
+bool V4L2Queue::deallocateBuffers() {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+
+ if (isStreaming()) {
+ ALOGEQ("Cannot deallocate buffers while streaming.");
+ return false;
+ }
+
+ if (mBuffers.size() == 0) return true;
+
+ mWeakThisFactory.InvalidateWeakPtrs();
+ mBuffers.clear();
+ mFreeBuffers = nullptr;
+
+ // Free all buffers.
+ struct v4l2_requestbuffers reqbufs;
+ memset(&reqbufs, 0, sizeof(reqbufs));
+ reqbufs.count = 0;
+ reqbufs.type = mType;
+ reqbufs.memory = mMemory;
+
+ int ret = mDevice->ioctl(VIDIOC_REQBUFS, &reqbufs);
+ if (ret) {
+ ALOGEQ("VIDIOC_REQBUFS failed");
+ return false;
+ }
+
+ ALOG_ASSERT(!mFreeBuffers);
+ ALOG_ASSERT(mQueuedBuffers.size() == 0u);
+
+ return true;
}
-v4l2_memory V4L2Queue::GetMemoryType() const {
- return memory_;
+size_t V4L2Queue::getMemoryUsage() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
+ size_t usage = 0;
+ for (const auto& buf : mBuffers) {
+ usage += buf->getMemoryUsage();
+ }
+ return usage;
+}
+
+v4l2_memory V4L2Queue::getMemoryType() const {
+ return mMemory;
}
-base::Optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBuffer() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+std::optional<V4L2WritableBufferRef> V4L2Queue::getFreeBuffer() {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- // No buffers allocated at the moment?
- if (!free_buffers_)
- return base::nullopt;
+ // No buffers allocated at the moment?
+ if (!mFreeBuffers) return std::nullopt;
- auto buffer_id = free_buffers_->GetFreeBuffer();
- if (!buffer_id.has_value())
- return base::nullopt;
+ auto bufferId = mFreeBuffers->getFreeBuffer();
+ if (!bufferId.has_value()) return std::nullopt;
- return V4L2BufferRefFactory::CreateWritableRef(
- buffers_[buffer_id.value()]->v4l2_buffer(),
- weak_this_factory_.GetWeakPtr());
+ return V4L2BufferRefFactory::CreateWritableRef(mBuffers[bufferId.value()]->v4l2_buffer(),
+ mWeakThisFactory.GetWeakPtr());
}
-base::Optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBuffer(
- size_t requested_buffer_id) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+std::optional<V4L2WritableBufferRef> V4L2Queue::getFreeBuffer(size_t requestedBufferIid) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- // No buffers allocated at the moment?
- if (!free_buffers_)
- return base::nullopt;
+ // No buffers allocated at the moment?
+ if (!mFreeBuffers) return std::nullopt;
- auto buffer_id = free_buffers_->GetFreeBuffer(requested_buffer_id);
- if (!buffer_id.has_value())
- return base::nullopt;
+ auto bufferId = mFreeBuffers->getFreeBuffer(requestedBufferIid);
+ if (!bufferId.has_value()) return std::nullopt;
- return V4L2BufferRefFactory::CreateWritableRef(
- buffers_[buffer_id.value()]->v4l2_buffer(),
- weak_this_factory_.GetWeakPtr());
+ return V4L2BufferRefFactory::CreateWritableRef(mBuffers[bufferId.value()]->v4l2_buffer(),
+ mWeakThisFactory.GetWeakPtr());
}
-bool V4L2Queue::QueueBuffer(struct v4l2_buffer* v4l2_buffer) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+bool V4L2Queue::queueBuffer(struct v4l2_buffer* v4l2Buffer) {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- int ret = device_->Ioctl(VIDIOC_QBUF, v4l2_buffer);
- if (ret) {
- VPQLOGF(1) << "VIDIOC_QBUF failed";
- return false;
- }
+ int ret = mDevice->ioctl(VIDIOC_QBUF, v4l2Buffer);
+ if (ret) {
+ ALOGEQ("VIDIOC_QBUF failed");
+ return false;
+ }
- auto inserted = queued_buffers_.emplace(v4l2_buffer->index);
- DCHECK_EQ(inserted.second, true);
+ auto inserted = mQueuedBuffers.emplace(v4l2Buffer->index);
+ if (!inserted.second) {
+ ALOGE("Queuing buffer failed");
+ return false;
+ }
- device_->SchedulePoll();
+ mDevice->schedulePoll();
- return true;
+ return true;
}
-std::pair<bool, V4L2ReadableBufferRef> V4L2Queue::DequeueBuffer() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- // No need to dequeue if no buffers queued.
- if (QueuedBuffersCount() == 0)
- return std::make_pair(true, nullptr);
+std::pair<bool, V4L2ReadableBufferRef> V4L2Queue::dequeueBuffer() {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- if (!IsStreaming()) {
- VQLOGF(1) << "Attempting to dequeue a buffer while not streaming.";
- return std::make_pair(true, nullptr);
- }
+ // No need to dequeue if no buffers queued.
+ if (queuedBuffersCount() == 0) return std::make_pair(true, nullptr);
- struct v4l2_buffer v4l2_buffer;
- memset(&v4l2_buffer, 0, sizeof(v4l2_buffer));
- // WARNING: do not change this to a vector or something smaller than
- // VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
- // the number of allocated planes, resulting in memory corruption.
- struct v4l2_plane planes[VIDEO_MAX_PLANES];
- memset(planes, 0, sizeof(planes));
- v4l2_buffer.type = type_;
- v4l2_buffer.memory = memory_;
- v4l2_buffer.m.planes = planes;
- v4l2_buffer.length = planes_count_;
- int ret = device_->Ioctl(VIDIOC_DQBUF, &v4l2_buffer);
- if (ret) {
- // TODO(acourbot): we should not have to check for EPIPE as codec clients
- // should not call this method after the last buffer is dequeued.
- switch (errno) {
- case EAGAIN:
- case EPIPE:
- // This is not an error so we'll need to continue polling but won't
- // provide a buffer.
- device_->SchedulePoll();
+ if (!isStreaming()) {
+ ALOGEQ("Attempting to dequeue a buffer while not streaming.");
return std::make_pair(true, nullptr);
- default:
- VPQLOGF(1) << "VIDIOC_DQBUF failed";
- return std::make_pair(false, nullptr);
}
- }
- auto it = queued_buffers_.find(v4l2_buffer.index);
- DCHECK(it != queued_buffers_.end());
- queued_buffers_.erase(*it);
+ struct v4l2_buffer v4l2Buffer;
+ memset(&v4l2Buffer, 0, sizeof(v4l2Buffer));
+ // WARNING: do not change this to a vector or something smaller than VIDEO_MAX_PLANES, otherwise
+ // the Tegra libv4l2 will write data beyond the number of allocated planes, resulting in memory
+ // corruption.
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ memset(planes, 0, sizeof(planes));
+ v4l2Buffer.type = mType;
+ v4l2Buffer.memory = mMemory;
+ v4l2Buffer.m.planes = planes;
+ v4l2Buffer.length = mPlanesCount;
+ int ret = mDevice->ioctl(VIDIOC_DQBUF, &v4l2Buffer);
+ if (ret) {
+ // TODO(acourbot): we should not have to check for EPIPE as codec clients should not call
+ // this method after the last buffer is dequeued.
+ switch (errno) {
+ case EAGAIN:
+ case EPIPE:
+ // This is not an error so we'll need to continue polling but won't provide a buffer.
+ mDevice->schedulePoll();
+ return std::make_pair(true, nullptr);
+ default:
+ ALOGEQ("VIDIOC_DQBUF failed");
+ return std::make_pair(false, nullptr);
+ }
+ }
+
+ auto it = mQueuedBuffers.find(v4l2Buffer.index);
+ ALOG_ASSERT(it != mQueuedBuffers.end());
+ mQueuedBuffers.erase(*it);
- if (QueuedBuffersCount() > 0)
- device_->SchedulePoll();
+ if (queuedBuffersCount() > 0) mDevice->schedulePoll();
- DCHECK(free_buffers_);
- return std::make_pair(true,
- V4L2BufferRefFactory::CreateReadableRef(
- v4l2_buffer, weak_this_factory_.GetWeakPtr()));
+ ALOG_ASSERT(mFreeBuffers);
+ return std::make_pair(true, V4L2BufferRefFactory::CreateReadableRef(
+ v4l2Buffer, mWeakThisFactory.GetWeakPtr()));
}
-bool V4L2Queue::IsStreaming() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+bool V4L2Queue::isStreaming() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- return is_streaming_;
+ return mIsStreaming;
}
-bool V4L2Queue::Streamon() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+bool V4L2Queue::streamon() {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- if (is_streaming_)
- return true;
+ if (mIsStreaming) return true;
- int arg = static_cast<int>(type_);
- int ret = device_->Ioctl(VIDIOC_STREAMON, &arg);
- if (ret) {
- VPQLOGF(1) << "VIDIOC_STREAMON failed";
- return false;
- }
+ int arg = static_cast<int>(mType);
+ int ret = mDevice->ioctl(VIDIOC_STREAMON, &arg);
+ if (ret) {
+ ALOGEQ("VIDIOC_STREAMON failed");
+ return false;
+ }
- is_streaming_ = true;
+ mIsStreaming = true;
- return true;
+ return true;
}
-bool V4L2Queue::Streamoff() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+bool V4L2Queue::streamoff() {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- // We do not check the value of IsStreaming(), because we may have queued
- // buffers to the queue and wish to get them back - in such as case, we may
- // need to do a VIDIOC_STREAMOFF on a stopped queue.
+ // We do not check the value of IsStreaming(), because we may have queued buffers to the queue
+ // and wish to get them back - in such as case, we may need to do a VIDIOC_STREAMOFF on a
+ // stopped queue.
- int arg = static_cast<int>(type_);
- int ret = device_->Ioctl(VIDIOC_STREAMOFF, &arg);
- if (ret) {
- VPQLOGF(1) << "VIDIOC_STREAMOFF failed";
- return false;
- }
+ int arg = static_cast<int>(mType);
+ int ret = mDevice->ioctl(VIDIOC_STREAMOFF, &arg);
+ if (ret) {
+ ALOGEQ("VIDIOC_STREAMOFF failed");
+ return false;
+ }
- for (const auto& buffer_id : queued_buffers_) {
- DCHECK(free_buffers_);
- free_buffers_->ReturnBuffer(buffer_id);
- }
+ for (const auto& bufferId : mQueuedBuffers) {
+ ALOG_ASSERT(mFreeBuffers);
+ mFreeBuffers->returnBuffer(bufferId);
+ }
- queued_buffers_.clear();
+ mQueuedBuffers.clear();
- is_streaming_ = false;
+ mIsStreaming = false;
- return true;
+ return true;
}
-size_t V4L2Queue::AllocatedBuffersCount() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+size_t V4L2Queue::allocatedBuffersCount() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- return buffers_.size();
+ return mBuffers.size();
}
-size_t V4L2Queue::FreeBuffersCount() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+size_t V4L2Queue::freeBuffersCount() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- return free_buffers_ ? free_buffers_->size() : 0;
+ return mFreeBuffers ? mFreeBuffers->size() : 0;
}
-size_t V4L2Queue::QueuedBuffersCount() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+size_t V4L2Queue::queuedBuffersCount() const {
+ ALOG_ASSERT(mSequenceChecker.CalledOnValidSequence());
- return queued_buffers_.size();
+ return mQueuedBuffers.size();
}
-#undef VDQLOGF
-#undef VPQLOGF
-#undef VQLOGF
+#undef ALOGEQ
+#undef ALOGVQ
-// This class is used to expose V4L2Queue's constructor to this module. This is
-// to ensure that nobody else can create instances of it.
+// This class is used to expose V4L2Queue's constructor to this module. This is to ensure that
+// nobody else can create instances of it.
class V4L2QueueFactory {
- public:
- static scoped_refptr<V4L2Queue> CreateQueue(scoped_refptr<V4L2Device> dev,
- enum v4l2_buf_type type,
- base::OnceClosure destroy_cb) {
- return new V4L2Queue(std::move(dev), type, std::move(destroy_cb));
- }
+public:
+ static scoped_refptr<V4L2Queue> createQueue(scoped_refptr<V4L2Device> dev,
+ enum v4l2_buf_type type,
+ base::OnceClosure destroyCb) {
+ return new V4L2Queue(std::move(dev), type, std::move(destroyCb));
+ }
};
V4L2Device::V4L2Device() {
- DETACH_FROM_SEQUENCE(client_sequence_checker_);
+ DETACH_FROM_SEQUENCE(mClientSequenceChecker);
}
-V4L2Device::~V4L2Device() {}
+V4L2Device::~V4L2Device() {
+ closeDevice();
+}
-scoped_refptr<V4L2Queue> V4L2Device::GetQueue(enum v4l2_buf_type type) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+scoped_refptr<V4L2Queue> V4L2Device::getQueue(enum v4l2_buf_type type) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
- switch (type) {
+ switch (type) {
// Supported queue types.
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- break;
+ break;
default:
- VLOGF(1) << "Unsupported V4L2 queue type: " << type;
- return nullptr;
- }
+ ALOGE("Unsupported V4L2 queue type: %u", type);
+ return nullptr;
+ }
- // TODO(acourbot): we should instead query the device for available queues,
- // and allocate them accordingly. This will do for now though.
- auto it = queues_.find(type);
- if (it != queues_.end())
- return scoped_refptr<V4L2Queue>(it->second);
+ // TODO(acourbot): we should instead query the device for available queues, and allocate them
+ // accordingly. This will do for now though.
+ auto it = mQueues.find(type);
+ if (it != mQueues.end()) return scoped_refptr<V4L2Queue>(it->second);
- scoped_refptr<V4L2Queue> queue = V4L2QueueFactory::CreateQueue(
- this, type, base::BindOnce(&V4L2Device::OnQueueDestroyed, this, type));
+ scoped_refptr<V4L2Queue> queue = V4L2QueueFactory::createQueue(
+ this, type, base::BindOnce(&V4L2Device::onQueueDestroyed, this, type));
- queues_[type] = queue.get();
- return queue;
+ mQueues[type] = queue.get();
+ return queue;
}
-void V4L2Device::OnQueueDestroyed(v4l2_buf_type buf_type) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+void V4L2Device::onQueueDestroyed(v4l2_buf_type bufType) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
- auto it = queues_.find(buf_type);
- DCHECK(it != queues_.end());
- queues_.erase(it);
+ auto it = mQueues.find(bufType);
+ ALOG_ASSERT(it != mQueues.end());
+ mQueues.erase(it);
}
// static
-scoped_refptr<V4L2Device> V4L2Device::Create() {
- DVLOGF(3);
- return scoped_refptr<V4L2Device>(new V4L2Device());
+scoped_refptr<V4L2Device> V4L2Device::create() {
+ ALOGV("%s()", __func__);
+ return scoped_refptr<V4L2Device>(new V4L2Device());
}
-bool V4L2Device::Open(Type type, uint32_t v4l2_pixfmt) {
- DVLOGF(3);
- std::string path = GetDevicePathFor(type, v4l2_pixfmt);
+bool V4L2Device::open(Type type, uint32_t v4l2PixFmt) {
+ ALOGV("%s()", __func__);
- if (path.empty()) {
- VLOGF(1) << "No devices supporting " << FourccToString(v4l2_pixfmt)
- << " for type: " << static_cast<int>(type);
- return false;
- }
+ std::string path = getDevicePathFor(type, v4l2PixFmt);
- if (!OpenDevicePath(path, type)) {
- VLOGF(1) << "Failed opening " << path;
- return false;
- }
-
- device_poll_interrupt_fd_.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
- if (!device_poll_interrupt_fd_.is_valid()) {
- VLOGF(1) << "Failed creating a poll interrupt fd";
- return false;
- }
+ if (path.empty()) {
+ ALOGE("No devices supporting %s for type: %u", media::FourccToString(v4l2PixFmt).c_str(),
+ static_cast<uint32_t>(type));
+ return false;
+ }
- return true;
-}
+ if (!openDevicePath(path, type)) {
+ ALOGE("Failed opening %s", path.c_str());
+ return false;
+ }
-bool V4L2Device::Initialize() {
- DVLOGF(3);
- static bool v4l2_functions_initialized = PostSandboxInitialization();
- if (!v4l2_functions_initialized) {
- VLOGF(1) << "Failed to initialize LIBV4L2 libs";
- return false;
- }
+ mDevicePollInterruptFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
+ if (!mDevicePollInterruptFd.is_valid()) {
+ ALOGE("Failed creating a poll interrupt fd");
+ return false;
+ }
- return true;
+ return true;
}
-int V4L2Device::Ioctl(int request, void* arg) {
- DCHECK(device_fd_.is_valid());
- return HANDLE_EINTR(ioctl(device_fd_.get(), request, arg));
+int V4L2Device::ioctl(int request, void* arg) {
+ ALOG_ASSERT(mDeviceFd.is_valid());
+ return HANDLE_EINTR(::ioctl(mDeviceFd.get(), request, arg));
}
-bool V4L2Device::Poll(bool poll_device, bool* event_pending) {
- struct pollfd pollfds[2];
- nfds_t nfds;
- int pollfd = -1;
+bool V4L2Device::poll(bool pollDevice, bool* eventPending) {
+ struct pollfd pollfds[2];
+ nfds_t nfds;
+ int pollfd = -1;
- pollfds[0].fd = device_poll_interrupt_fd_.get();
- pollfds[0].events = POLLIN | POLLERR;
- nfds = 1;
+ pollfds[0].fd = mDevicePollInterruptFd.get();
+ pollfds[0].events = POLLIN | POLLERR;
+ nfds = 1;
- if (poll_device) {
- DVLOGF(5) << "adding device fd to poll() set";
- pollfds[nfds].fd = device_fd_.get();
- pollfds[nfds].events = POLLIN | POLLOUT | POLLERR | POLLPRI;
- pollfd = nfds;
- nfds++;
- }
+ if (pollDevice) {
+ ALOGV("adding device fd to poll() set");
+ pollfds[nfds].fd = mDeviceFd.get();
+ pollfds[nfds].events = POLLIN | POLLOUT | POLLERR | POLLPRI;
+ pollfd = nfds;
+ nfds++;
+ }
- if (HANDLE_EINTR(poll(pollfds, nfds, -1)) == -1) {
- VPLOGF(1) << "poll() failed";
- return false;
- }
- *event_pending = (pollfd != -1 && pollfds[pollfd].revents & POLLPRI);
- return true;
+ if (HANDLE_EINTR(::poll(pollfds, nfds, -1)) == -1) {
+ ALOGE("poll() failed");
+ return false;
+ }
+ *eventPending = (pollfd != -1 && pollfds[pollfd].revents & POLLPRI);
+ return true;
}
-void* V4L2Device::Mmap(void* addr,
- unsigned int len,
- int prot,
- int flags,
- unsigned int offset) {
- DCHECK(device_fd_.is_valid());
- return mmap(addr, len, prot, flags, device_fd_.get(), offset);
+void* V4L2Device::mmap(void* addr, unsigned int len, int prot, int flags, unsigned int offset) {
+ DCHECK(mDeviceFd.is_valid());
+ return ::mmap(addr, len, prot, flags, mDeviceFd.get(), offset);
}
-void V4L2Device::Munmap(void* addr, unsigned int len) {
- munmap(addr, len);
+void V4L2Device::munmap(void* addr, unsigned int len) {
+ ::munmap(addr, len);
}
-bool V4L2Device::SetDevicePollInterrupt() {
- DVLOGF(4);
+bool V4L2Device::setDevicePollInterrupt() {
+ ALOGV("%s()", __func__);
- const uint64_t buf = 1;
- if (HANDLE_EINTR(write(device_poll_interrupt_fd_.get(), &buf, sizeof(buf))) ==
- -1) {
- VPLOGF(1) << "write() failed";
- return false;
- }
- return true;
+ const uint64_t buf = 1;
+ if (HANDLE_EINTR(write(mDevicePollInterruptFd.get(), &buf, sizeof(buf))) == -1) {
+ ALOGE("write() failed");
+ return false;
+ }
+ return true;
}
-bool V4L2Device::ClearDevicePollInterrupt() {
- DVLOGF(5);
+bool V4L2Device::clearDevicePollInterrupt() {
+ ALOGV("%s()", __func__);
- uint64_t buf;
- if (HANDLE_EINTR(read(device_poll_interrupt_fd_.get(), &buf, sizeof(buf))) ==
- -1) {
- if (errno == EAGAIN) {
- // No interrupt flag set, and we're reading nonblocking. Not an error.
- return true;
- } else {
- VPLOGF(1) << "read() failed";
- return false;
+ uint64_t buf;
+ if (HANDLE_EINTR(read(mDevicePollInterruptFd.get(), &buf, sizeof(buf))) == -1) {
+ if (errno == EAGAIN) {
+ // No interrupt flag set, and we're reading nonblocking. Not an error.
+ return true;
+ } else {
+ ALOGE("read() failed");
+ return false;
+ }
}
- }
- return true;
+ return true;
}
-std::vector<base::ScopedFD> V4L2Device::GetDmabufsForV4L2Buffer(
- int index,
- size_t num_planes,
- enum v4l2_buf_type buf_type) {
- DVLOGF(3);
- DCHECK(V4L2_TYPE_IS_MULTIPLANAR(buf_type));
+std::vector<base::ScopedFD> V4L2Device::getDmabufsForV4L2Buffer(int index, size_t numPlanes,
+ enum v4l2_buf_type bufType) {
+ ALOGV("%s()", __func__);
+ ALOG_ASSERT(V4L2_TYPE_IS_MULTIPLANAR(bufType));
+
+ std::vector<base::ScopedFD> dmabufFds;
+ for (size_t i = 0; i < numPlanes; ++i) {
+ struct v4l2_exportbuffer expbuf;
+ memset(&expbuf, 0, sizeof(expbuf));
+ expbuf.type = bufType;
+ expbuf.index = index;
+ expbuf.plane = i;
+ expbuf.flags = O_CLOEXEC;
+ if (ioctl(VIDIOC_EXPBUF, &expbuf) != 0) {
+ dmabufFds.clear();
+ break;
+ }
- std::vector<base::ScopedFD> dmabuf_fds;
- for (size_t i = 0; i < num_planes; ++i) {
- struct v4l2_exportbuffer expbuf;
- memset(&expbuf, 0, sizeof(expbuf));
- expbuf.type = buf_type;
- expbuf.index = index;
- expbuf.plane = i;
- expbuf.flags = O_CLOEXEC;
- if (Ioctl(VIDIOC_EXPBUF, &expbuf) != 0) {
- dmabuf_fds.clear();
- break;
+ dmabufFds.push_back(base::ScopedFD(expbuf.fd));
}
- dmabuf_fds.push_back(base::ScopedFD(expbuf.fd));
- }
-
- return dmabuf_fds;
+ return dmabufFds;
}
-std::vector<uint32_t> V4L2Device::PreferredInputFormat(Type type) {
- if (type == Type::kEncoder)
- return {V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_NV12};
+std::vector<uint32_t> V4L2Device::preferredInputFormat(Type type) {
+ if (type == Type::kEncoder) return {V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_NV12};
- return {};
+ return {};
}
-VideoDecodeAccelerator::SupportedProfiles
-V4L2Device::GetSupportedDecodeProfiles(const size_t num_formats,
- const uint32_t pixelformats[]) {
- VideoDecodeAccelerator::SupportedProfiles supported_profiles;
+media::VideoDecodeAccelerator::SupportedProfiles V4L2Device::getSupportedDecodeProfiles(
+ const size_t numFormats, const uint32_t pixelFormats[]) {
+ media::VideoDecodeAccelerator::SupportedProfiles supportedProfiles;
- Type type = Type::kDecoder;
- const auto& devices = GetDevicesForType(type);
- for (const auto& device : devices) {
- if (!OpenDevicePath(device.first, type)) {
- VLOGF(1) << "Failed opening " << device.first;
- continue;
- }
+ Type type = Type::kDecoder;
+ const auto& devices = getDevicesForType(type);
+ for (const auto& device : devices) {
+ if (!openDevicePath(device.first, type)) {
+ ALOGV("Failed opening %s", device.first.c_str());
+ continue;
+ }
- const auto& profiles =
- EnumerateSupportedDecodeProfiles(num_formats, pixelformats);
- supported_profiles.insert(supported_profiles.end(), profiles.begin(),
- profiles.end());
- CloseDevice();
- }
+ const auto& profiles = enumerateSupportedDecodeProfiles(numFormats, pixelFormats);
+ supportedProfiles.insert(supportedProfiles.end(), profiles.begin(), profiles.end());
+ closeDevice();
+ }
- return supported_profiles;
+ return supportedProfiles;
}
-VideoEncodeAccelerator::SupportedProfiles
-V4L2Device::GetSupportedEncodeProfiles() {
- VideoEncodeAccelerator::SupportedProfiles supported_profiles;
+media::VideoEncodeAccelerator::SupportedProfiles V4L2Device::getSupportedEncodeProfiles() {
+ media::VideoEncodeAccelerator::SupportedProfiles supportedProfiles;
- Type type = Type::kEncoder;
- const auto& devices = GetDevicesForType(type);
- for (const auto& device : devices) {
- if (!OpenDevicePath(device.first, type)) {
- VLOGF(1) << "Failed opening " << device.first;
- continue;
- }
+ Type type = Type::kEncoder;
+ const auto& devices = getDevicesForType(type);
+ for (const auto& device : devices) {
+ if (!openDevicePath(device.first, type)) {
+ ALOGV("Failed opening %s", device.first.c_str());
+ continue;
+ }
- const auto& profiles = EnumerateSupportedEncodeProfiles();
- supported_profiles.insert(supported_profiles.end(), profiles.begin(),
- profiles.end());
- CloseDevice();
- }
+ const auto& profiles = enumerateSupportedEncodeProfiles();
+ supportedProfiles.insert(supportedProfiles.end(), profiles.begin(), profiles.end());
+ closeDevice();
+ }
- return supported_profiles;
+ return supportedProfiles;
}
-bool V4L2Device::OpenDevicePath(const std::string& path, Type /*type*/) {
- DCHECK(!device_fd_.is_valid());
+bool V4L2Device::openDevicePath(const std::string& path, Type /*type*/) {
+ ALOG_ASSERT(!mDeviceFd.is_valid());
- device_fd_.reset(
- HANDLE_EINTR(open(path.c_str(), O_RDWR | O_NONBLOCK | O_CLOEXEC)));
- if (!device_fd_.is_valid())
- return false;
+ mDeviceFd.reset(HANDLE_EINTR(::open(path.c_str(), O_RDWR | O_NONBLOCK | O_CLOEXEC)));
+ if (!mDeviceFd.is_valid()) return false;
- return true;
+ return true;
}
-void V4L2Device::CloseDevice() {
- DVLOGF(3);
- device_fd_.reset();
-}
+void V4L2Device::closeDevice() {
+ ALOGV("%s()", __func__);
-// static
-bool V4L2Device::PostSandboxInitialization() {
- return true;
+ mDeviceFd.reset();
}
-void V4L2Device::EnumerateDevicesForType(Type type) {
- // video input/output devices are registered as /dev/videoX in V4L2.
- static const std::string kVideoDevicePattern = "/dev/video";
+void V4L2Device::enumerateDevicesForType(Type type) {
+ // video input/output devices are registered as /dev/videoX in V4L2.
+ static const std::string kVideoDevicePattern = "/dev/video";
- std::string device_pattern;
- v4l2_buf_type buf_type;
- switch (type) {
+ std::string devicePattern;
+ v4l2_buf_type bufType;
+ switch (type) {
case Type::kDecoder:
- device_pattern = kVideoDevicePattern;
- buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- break;
+ devicePattern = kVideoDevicePattern;
+ bufType = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ break;
case Type::kEncoder:
- device_pattern = kVideoDevicePattern;
- buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- break;
+ devicePattern = kVideoDevicePattern;
+ bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ break;
default:
- LOG(ERROR) << "Only decoder and encoder types are supported!!";
- return;
- }
+ ALOGE("Only decoder and encoder types are supported!!");
+ return;
+ }
- std::vector<std::string> candidate_paths;
+ std::vector<std::string> candidatePaths;
- // TODO(posciak): Remove this legacy unnumbered device once
- // all platforms are updated to use numbered devices.
- candidate_paths.push_back(device_pattern);
+ // TODO(posciak): Remove this legacy unnumbered device once all platforms are updated to use
+ // numbered devices.
+ candidatePaths.push_back(devicePattern);
- // We are sandboxed, so we can't query directory contents to check which
- // devices are actually available. Try to open the first 10; if not present,
- // we will just fail to open immediately.
- for (int i = 0; i < 10; ++i) {
- candidate_paths.push_back(
- base::StringPrintf("%s%d", device_pattern.c_str(), i));
- }
+ // We are sandboxed, so we can't query directory contents to check which devices are actually
+ // available. Try to open the first 10; if not present, we will just fail to open immediately.
+ for (int i = 0; i < 10; ++i) {
+ candidatePaths.push_back(base::StringPrintf("%s%d", devicePattern.c_str(), i));
+ }
- Devices devices;
- for (const auto& path : candidate_paths) {
- if (!OpenDevicePath(path, type))
- continue;
+ Devices devices;
+ for (const auto& path : candidatePaths) {
+ if (!openDevicePath(path, type)) {
+ continue;
+ }
- const auto& supported_pixelformats =
- EnumerateSupportedPixelformats(buf_type);
- if (!supported_pixelformats.empty()) {
- DVLOGF(3) << "Found device: " << path;
- devices.push_back(std::make_pair(path, supported_pixelformats));
- }
+ const auto& supportedPixelformats = enumerateSupportedPixelformats(bufType);
+ if (!supportedPixelformats.empty()) {
+ ALOGV("Found device: %s", path.c_str());
+ devices.push_back(std::make_pair(path, supportedPixelformats));
+ }
- CloseDevice();
- }
+ closeDevice();
+ }
- DCHECK_EQ(devices_by_type_.count(type), 0u);
- devices_by_type_[type] = devices;
+ ALOG_ASSERT(mDevicesByType.count(type) == 0u);
+ mDevicesByType[type] = devices;
}
-const V4L2Device::Devices& V4L2Device::GetDevicesForType(
- Type type) {
- if (devices_by_type_.count(type) == 0)
- EnumerateDevicesForType(type);
+const V4L2Device::Devices& V4L2Device::getDevicesForType(Type type) {
+ if (mDevicesByType.count(type) == 0) enumerateDevicesForType(type);
- DCHECK_NE(devices_by_type_.count(type), 0u);
- return devices_by_type_[type];
+ ALOG_ASSERT(mDevicesByType.count(type) != 0u);
+ return mDevicesByType[type];
}
-std::string V4L2Device::GetDevicePathFor(Type type, uint32_t pixfmt) {
- const Devices& devices = GetDevicesForType(type);
+std::string V4L2Device::getDevicePathFor(Type type, uint32_t pixFmt) {
+ const Devices& devices = getDevicesForType(type);
- for (const auto& device : devices) {
- if (std::find(device.second.begin(), device.second.end(), pixfmt) !=
- device.second.end())
- return device.first;
- }
+ for (const auto& device : devices) {
+ if (std::find(device.second.begin(), device.second.end(), pixFmt) != device.second.end())
+ return device.first;
+ }
- return std::string();
+ return std::string();
}
// static
-uint32_t V4L2Device::VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile,
- bool slice_based) {
- if (profile >= H264PROFILE_MIN && profile <= H264PROFILE_MAX) {
- if (slice_based)
- return V4L2_PIX_FMT_H264_SLICE;
- else
- return V4L2_PIX_FMT_H264;
- } else if (profile >= VP8PROFILE_MIN && profile <= VP8PROFILE_MAX) {
- if (slice_based)
- return V4L2_PIX_FMT_VP8_FRAME;
- else
- return V4L2_PIX_FMT_VP8;
- } else if (profile >= VP9PROFILE_MIN && profile <= VP9PROFILE_MAX) {
- if (slice_based)
- return V4L2_PIX_FMT_VP9_FRAME;
- else
- return V4L2_PIX_FMT_VP9;
- } else {
- LOG(ERROR) << "Unknown profile: " << GetProfileName(profile);
- return 0;
- }
+uint32_t V4L2Device::videoCodecProfileToV4L2PixFmt(media::VideoCodecProfile profile,
+ bool sliceBased) {
+ if (profile >= media::H264PROFILE_MIN && profile <= media::H264PROFILE_MAX) {
+ if (sliceBased) {
+ return V4L2_PIX_FMT_H264_SLICE;
+ } else {
+ return V4L2_PIX_FMT_H264;
+ }
+ } else if (profile >= media::VP8PROFILE_MIN && profile <= media::VP8PROFILE_MAX) {
+ if (sliceBased) {
+ return V4L2_PIX_FMT_VP8_FRAME;
+ } else {
+ return V4L2_PIX_FMT_VP8;
+ }
+ } else if (profile >= media::VP9PROFILE_MIN && profile <= media::VP9PROFILE_MAX) {
+ if (sliceBased) {
+ return V4L2_PIX_FMT_VP9_FRAME;
+ } else {
+ return V4L2_PIX_FMT_VP9;
+ }
+ } else {
+ ALOGE("Unknown profile: %s", GetProfileName(profile).c_str());
+ return 0;
+ }
}
// static
-VideoCodecProfile V4L2Device::V4L2ProfileToVideoCodecProfile(VideoCodec codec,
- uint32_t profile) {
- switch (codec) {
- case kCodecH264:
- switch (profile) {
+media::VideoCodecProfile V4L2Device::v4L2ProfileToVideoCodecProfile(media::VideoCodec codec,
+ uint32_t profile) {
+ switch (codec) {
+ case media::kCodecH264:
+ switch (profile) {
case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
- return H264PROFILE_BASELINE;
+ return media::H264PROFILE_BASELINE;
case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
- return H264PROFILE_MAIN;
+ return media::H264PROFILE_MAIN;
case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
- return H264PROFILE_EXTENDED;
+ return media::H264PROFILE_EXTENDED;
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
- return H264PROFILE_HIGH;
- }
- break;
- case kCodecVP8:
- switch (profile) {
+ return media::H264PROFILE_HIGH;
+ }
+ break;
+ case media::kCodecVP8:
+ switch (profile) {
case V4L2_MPEG_VIDEO_VP8_PROFILE_0:
case V4L2_MPEG_VIDEO_VP8_PROFILE_1:
case V4L2_MPEG_VIDEO_VP8_PROFILE_2:
case V4L2_MPEG_VIDEO_VP8_PROFILE_3:
- return VP8PROFILE_ANY;
- }
- break;
- case kCodecVP9:
- switch (profile) {
+ return media::VP8PROFILE_ANY;
+ }
+ break;
+ case media::kCodecVP9:
+ switch (profile) {
case V4L2_MPEG_VIDEO_VP9_PROFILE_0:
- return VP9PROFILE_PROFILE0;
+ return media::VP9PROFILE_PROFILE0;
case V4L2_MPEG_VIDEO_VP9_PROFILE_1:
- return VP9PROFILE_PROFILE1;
+ return media::VP9PROFILE_PROFILE1;
case V4L2_MPEG_VIDEO_VP9_PROFILE_2:
- return VP9PROFILE_PROFILE2;
+ return media::VP9PROFILE_PROFILE2;
case V4L2_MPEG_VIDEO_VP9_PROFILE_3:
- return VP9PROFILE_PROFILE3;
- }
- break;
- default:
- VLOGF(2) << "Unknown codec: " << codec;
- }
- VLOGF(2) << "Unknown profile: " << profile;
- return VIDEO_CODEC_PROFILE_UNKNOWN;
-}
-
-std::vector<VideoCodecProfile> V4L2Device::V4L2PixFmtToVideoCodecProfiles(
- uint32_t pix_fmt,
- bool /*is_encoder*/) {
- auto get_supported_profiles = [this](
- VideoCodec codec,
- std::vector<VideoCodecProfile>* profiles) {
- uint32_t query_id = 0;
- switch (codec) {
- case kCodecH264:
- query_id = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
- break;
- case kCodecVP8:
- query_id = V4L2_CID_MPEG_VIDEO_VP8_PROFILE;
- break;
- case kCodecVP9:
- query_id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE;
+ return media::VP9PROFILE_PROFILE3;
+ }
break;
- default:
- return false;
+ default:
+ ALOGE("Unknown codec: %u", codec);
}
+ ALOGE("Unknown profile: %u", profile);
+ return media::VIDEO_CODEC_PROFILE_UNKNOWN;
+}
+
+std::vector<media::VideoCodecProfile> V4L2Device::v4L2PixFmtToVideoCodecProfiles(
+ uint32_t pixFmt, bool /*isEncoder*/) {
+ auto getSupportedProfiles = [this](media::VideoCodec codec,
+ std::vector<media::VideoCodecProfile>* profiles) {
+ uint32_t queryId = 0;
+ switch (codec) {
+ case media::kCodecH264:
+ queryId = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
+ break;
+ case media::kCodecVP8:
+ queryId = V4L2_CID_MPEG_VIDEO_VP8_PROFILE;
+ break;
+ case media::kCodecVP9:
+ queryId = V4L2_CID_MPEG_VIDEO_VP9_PROFILE;
+ break;
+ default:
+ return false;
+ }
- v4l2_queryctrl query_ctrl = {};
- query_ctrl.id = query_id;
- if (Ioctl(VIDIOC_QUERYCTRL, &query_ctrl) != 0) {
- return false;
- }
- v4l2_querymenu query_menu = {};
- query_menu.id = query_ctrl.id;
- for (query_menu.index = query_ctrl.minimum;
- static_cast<int>(query_menu.index) <= query_ctrl.maximum;
- query_menu.index++) {
- if (Ioctl(VIDIOC_QUERYMENU, &query_menu) == 0) {
- const VideoCodecProfile profile =
- V4L2Device::V4L2ProfileToVideoCodecProfile(codec, query_menu.index);
- if (profile != VIDEO_CODEC_PROFILE_UNKNOWN)
- profiles->push_back(profile);
- }
- }
- return true;
- };
+ v4l2_queryctrl queryCtrl = {};
+ queryCtrl.id = queryId;
+ if (ioctl(VIDIOC_QUERYCTRL, &queryCtrl) != 0) {
+ return false;
+ }
+ v4l2_querymenu queryMenu = {};
+ queryMenu.id = queryCtrl.id;
+ for (queryMenu.index = queryCtrl.minimum;
+ static_cast<int>(queryMenu.index) <= queryCtrl.maximum; queryMenu.index++) {
+ if (ioctl(VIDIOC_QUERYMENU, &queryMenu) == 0) {
+ const media::VideoCodecProfile profile =
+ V4L2Device::v4L2ProfileToVideoCodecProfile(codec, queryMenu.index);
+ if (profile != media::VIDEO_CODEC_PROFILE_UNKNOWN) profiles->push_back(profile);
+ }
+ }
+ return true;
+ };
- std::vector<VideoCodecProfile> profiles;
- switch (pix_fmt) {
+ std::vector<media::VideoCodecProfile> profiles;
+ switch (pixFmt) {
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_H264_SLICE:
- if (!get_supported_profiles(kCodecH264, &profiles)) {
- DLOG(WARNING) << "Driver doesn't support QUERY H264 profiles, "
- << "use default values, Base, Main, High";
- profiles = {
- H264PROFILE_BASELINE,
- H264PROFILE_MAIN,
- H264PROFILE_HIGH,
- };
- }
- break;
+ if (!getSupportedProfiles(media::kCodecH264, &profiles)) {
+ ALOGW("Driver doesn't support QUERY H264 profiles, "
+ "use default values, Base, Main, High");
+ profiles = {
+ media::H264PROFILE_BASELINE,
+ media::H264PROFILE_MAIN,
+ media::H264PROFILE_HIGH,
+ };
+ }
+ break;
case V4L2_PIX_FMT_VP8:
case V4L2_PIX_FMT_VP8_FRAME:
- profiles = {VP8PROFILE_ANY};
- break;
+ profiles = {media::VP8PROFILE_ANY};
+ break;
case V4L2_PIX_FMT_VP9:
case V4L2_PIX_FMT_VP9_FRAME:
- if (!get_supported_profiles(kCodecVP9, &profiles)) {
- DLOG(WARNING) << "Driver doesn't support QUERY VP9 profiles, "
- << "use default values, Profile0";
- profiles = {VP9PROFILE_PROFILE0};
- }
- break;
+ if (!getSupportedProfiles(media::kCodecVP9, &profiles)) {
+ ALOGW("Driver doesn't support QUERY VP9 profiles, "
+ "use default values, Profile0");
+ profiles = {media::VP9PROFILE_PROFILE0};
+ }
+ break;
default:
- VLOGF(1) << "Unhandled pixelformat " << FourccToString(pix_fmt);
- return {};
- }
+ ALOGE("Unhandled pixelformat %s", media::FourccToString(pixFmt).c_str());
+ return {};
+ }
- // Erase duplicated profiles.
- std::sort(profiles.begin(), profiles.end());
- profiles.erase(std::unique(profiles.begin(), profiles.end()), profiles.end());
- return profiles;
+ // Erase duplicated profiles.
+ std::sort(profiles.begin(), profiles.end());
+ profiles.erase(std::unique(profiles.begin(), profiles.end()), profiles.end());
+ return profiles;
}
// static
-int32_t V4L2Device::VideoCodecProfileToV4L2H264Profile(
- VideoCodecProfile profile) {
- switch (profile) {
- case H264PROFILE_BASELINE:
- return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
- case H264PROFILE_MAIN:
- return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
- case H264PROFILE_EXTENDED:
- return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
- case H264PROFILE_HIGH:
- return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
- case H264PROFILE_HIGH10PROFILE:
- return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
- case H264PROFILE_HIGH422PROFILE:
- return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422;
- case H264PROFILE_HIGH444PREDICTIVEPROFILE:
- return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE;
- case H264PROFILE_SCALABLEBASELINE:
- return V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE;
- case H264PROFILE_SCALABLEHIGH:
- return V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH;
- case H264PROFILE_STEREOHIGH:
- return V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH;
- case H264PROFILE_MULTIVIEWHIGH:
- return V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH;
+int32_t V4L2Device::videoCodecProfileToV4L2H264Profile(media::VideoCodecProfile profile) {
+ switch (profile) {
+ case media::H264PROFILE_BASELINE:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
+ case media::H264PROFILE_MAIN:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
+ case media::H264PROFILE_EXTENDED:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
+ case media::H264PROFILE_HIGH:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
+ case media::H264PROFILE_HIGH10PROFILE:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
+ case media::H264PROFILE_HIGH422PROFILE:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422;
+ case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE;
+ case media::H264PROFILE_SCALABLEBASELINE:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE;
+ case media::H264PROFILE_SCALABLEHIGH:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH;
+ case media::H264PROFILE_STEREOHIGH:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH;
+ case media::H264PROFILE_MULTIVIEWHIGH:
+ return V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH;
default:
- DVLOGF(1) << "Add more cases as needed";
- return -1;
- }
+ ALOGE("Add more cases as needed");
+ return -1;
+ }
}
// static
-int32_t V4L2Device::H264LevelIdcToV4L2H264Level(uint8_t level_idc) {
- switch (level_idc) {
+int32_t V4L2Device::h264LevelIdcToV4L2H264Level(uint8_t levelIdc) {
+ switch (levelIdc) {
case 10:
- return V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
case 9:
- return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
case 11:
- return V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
case 12:
- return V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
case 13:
- return V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
case 20:
- return V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
case 21:
- return V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
case 22:
- return V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
case 30:
- return V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
case 31:
- return V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
case 32:
- return V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
case 40:
- return V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
case 41:
- return V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
case 42:
- return V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
case 50:
- return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
case 51:
- return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
+ return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
default:
- DVLOGF(1) << "Unrecognized level_idc: " << static_cast<int>(level_idc);
- return -1;
- }
+ ALOGE("Unrecognized levelIdc: %u", static_cast<uint32_t>(levelIdc));
+ return -1;
+ }
}
// static
-Size V4L2Device::AllocatedSizeFromV4L2Format(const struct v4l2_format& format) {
- Size coded_size;
- Size visible_size;
- VideoPixelFormat frame_format = PIXEL_FORMAT_UNKNOWN;
- size_t bytesperline = 0;
- // Total bytes in the frame.
- size_t sizeimage = 0;
-
- if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
- DCHECK_GT(format.fmt.pix_mp.num_planes, 0);
- bytesperline =
- base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[0].bytesperline);
- for (size_t i = 0; i < format.fmt.pix_mp.num_planes; ++i) {
- sizeimage +=
- base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[i].sizeimage);
- }
- visible_size.SetSize(base::checked_cast<int>(format.fmt.pix_mp.width),
- base::checked_cast<int>(format.fmt.pix_mp.height));
- const uint32_t pix_fmt = format.fmt.pix_mp.pixelformat;
- const auto frame_fourcc = Fourcc::FromV4L2PixFmt(pix_fmt);
- if (!frame_fourcc) {
- VLOGF(1) << "Unsupported format " << FourccToString(pix_fmt);
- return coded_size;
- }
- frame_format = frame_fourcc->ToVideoPixelFormat();
- } else {
- bytesperline = base::checked_cast<int>(format.fmt.pix.bytesperline);
- sizeimage = base::checked_cast<int>(format.fmt.pix.sizeimage);
- visible_size.SetSize(base::checked_cast<int>(format.fmt.pix.width),
- base::checked_cast<int>(format.fmt.pix.height));
- const uint32_t fourcc = format.fmt.pix.pixelformat;
- const auto frame_fourcc = Fourcc::FromV4L2PixFmt(fourcc);
- if (!frame_fourcc) {
- VLOGF(1) << "Unsupported format " << FourccToString(fourcc);
- return coded_size;
- }
- frame_format = frame_fourcc ? frame_fourcc->ToVideoPixelFormat()
- : PIXEL_FORMAT_UNKNOWN;
- }
-
- // V4L2 does not provide per-plane bytesperline (bpl) when different
- // components are sharing one physical plane buffer. In this case, it only
- // provides bpl for the first component in the plane. So we can't depend on it
- // for calculating height, because bpl may vary within one physical plane
- // buffer. For example, YUV420 contains 3 components in one physical plane,
- // with Y at 8 bits per pixel, and Cb/Cr at 4 bits per pixel per component,
- // but we only get 8 pits per pixel from bytesperline in physical plane 0.
- // So we need to get total frame bpp from elsewhere to calculate coded height.
-
- // We need bits per pixel for one component only to calculate
- // coded_width from bytesperline.
- int plane_horiz_bits_per_pixel =
- VideoFrame::PlaneHorizontalBitsPerPixel(frame_format, 0);
-
- // Adding up bpp for each component will give us total bpp for all components.
- int total_bpp = 0;
- for (size_t i = 0; i < VideoFrame::NumPlanes(frame_format); ++i)
- total_bpp += VideoFrame::PlaneBitsPerPixel(frame_format, i);
-
- if (sizeimage == 0 || bytesperline == 0 || plane_horiz_bits_per_pixel == 0 ||
- total_bpp == 0 || (bytesperline * 8) % plane_horiz_bits_per_pixel != 0) {
- VLOGF(1) << "Invalid format provided";
- return coded_size;
- }
-
- // Coded width can be calculated by taking the first component's bytesperline,
- // which in V4L2 always applies to the first component in physical plane
- // buffer.
- int coded_width = bytesperline * 8 / plane_horiz_bits_per_pixel;
- // Sizeimage is coded_width * coded_height * total_bpp.
- int coded_height = sizeimage * 8 / coded_width / total_bpp;
-
- coded_size.SetSize(coded_width, coded_height);
- DVLOGF(3) << "coded_size=" << coded_size.ToString();
-
- // Sanity checks. Calculated coded size has to contain given visible size
- // and fulfill buffer byte size requirements.
- DCHECK(Rect(coded_size).Contains(Rect(visible_size)));
- DCHECK_LE(sizeimage, VideoFrame::AllocationSize(frame_format, coded_size));
-
- return coded_size;
+media::Size V4L2Device::allocatedSizeFromV4L2Format(const struct v4l2_format& format) {
+ media::Size codedSize;
+ media::Size visibleSize;
+ media::VideoPixelFormat frameFormat = media::PIXEL_FORMAT_UNKNOWN;
+ size_t bytesPerLine = 0;
+ // Total bytes in the frame.
+ size_t sizeimage = 0;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
+ ALOG_ASSERT(format.fmt.pix_mp.num_planes > 0);
+ bytesPerLine = base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[0].bytesperline);
+ for (size_t i = 0; i < format.fmt.pix_mp.num_planes; ++i) {
+ sizeimage += base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[i].sizeimage);
+ }
+ visibleSize.SetSize(base::checked_cast<int>(format.fmt.pix_mp.width),
+ base::checked_cast<int>(format.fmt.pix_mp.height));
+ const uint32_t pixFmt = format.fmt.pix_mp.pixelformat;
+ const auto frameFourcc = media::Fourcc::FromV4L2PixFmt(pixFmt);
+ if (!frameFourcc) {
+ ALOGE("Unsupported format %s", media::FourccToString(pixFmt).c_str());
+ return codedSize;
+ }
+ frameFormat = frameFourcc->ToVideoPixelFormat();
+ } else {
+ bytesPerLine = base::checked_cast<int>(format.fmt.pix.bytesperline);
+ sizeimage = base::checked_cast<int>(format.fmt.pix.sizeimage);
+ visibleSize.SetSize(base::checked_cast<int>(format.fmt.pix.width),
+ base::checked_cast<int>(format.fmt.pix.height));
+ const uint32_t fourcc = format.fmt.pix.pixelformat;
+ const auto frameFourcc = media::Fourcc::FromV4L2PixFmt(fourcc);
+ if (!frameFourcc) {
+ ALOGE("Unsupported format %s", media::FourccToString(fourcc).c_str());
+ return codedSize;
+ }
+ frameFormat = frameFourcc ? frameFourcc->ToVideoPixelFormat() : media::PIXEL_FORMAT_UNKNOWN;
+ }
+
+ // V4L2 does not provide per-plane bytesperline (bpl) when different components are sharing one
+ // physical plane buffer. In this case, it only provides bpl for the first component in the
+ // plane. So we can't depend on it for calculating height, because bpl may vary within one
+ // physical plane buffer. For example, YUV420 contains 3 components in one physical plane, with
+ // Y at 8 bits per pixel, and Cb/Cr at 4 bits per pixel per component, but we only get 8 pits
+ // per pixel from bytesperline in physical plane 0. So we need to get total frame bpp from
+ // elsewhere to calculate coded height.
+
+ // We need bits per pixel for one component only to calculate the coded width from bytesperline.
+ int planeHorizBitsPerPixel = media::VideoFrame::PlaneHorizontalBitsPerPixel(frameFormat, 0);
+
+ // Adding up bpp for each component will give us total bpp for all components.
+ int totalBpp = 0;
+ for (size_t i = 0; i < media::VideoFrame::NumPlanes(frameFormat); ++i)
+ totalBpp += media::VideoFrame::PlaneBitsPerPixel(frameFormat, i);
+
+ if (sizeimage == 0 || bytesPerLine == 0 || planeHorizBitsPerPixel == 0 || totalBpp == 0 ||
+ (bytesPerLine * 8) % planeHorizBitsPerPixel != 0) {
+ ALOGE("Invalid format provided");
+ return codedSize;
+ }
+
+ // Coded width can be calculated by taking the first component's bytesperline, which in V4L2
+ // always applies to the first component in physical plane buffer.
+ int codedWidth = bytesPerLine * 8 / planeHorizBitsPerPixel;
+ // Sizeimage is codedWidth * codedHeight * totalBpp.
+ int codedHeight = sizeimage * 8 / codedWidth / totalBpp;
+
+ codedSize.SetSize(codedWidth, codedHeight);
+ ALOGV("codedSize=%s", codedSize.ToString().c_str());
+
+ // Sanity checks. Calculated coded size has to contain given visible size and fulfill buffer
+ // byte size requirements.
+ ALOG_ASSERT(media::Rect(codedSize).Contains(media::Rect(visibleSize)));
+ ALOG_ASSERT(sizeimage <= media::VideoFrame::AllocationSize(frameFormat, codedSize));
+
+ return codedSize;
}
// static
-const char* V4L2Device::V4L2MemoryToString(const v4l2_memory memory) {
- switch (memory) {
+const char* V4L2Device::v4L2MemoryToString(const v4l2_memory memory) {
+ switch (memory) {
case V4L2_MEMORY_MMAP:
- return "V4L2_MEMORY_MMAP";
+ return "V4L2_MEMORY_MMAP";
case V4L2_MEMORY_USERPTR:
- return "V4L2_MEMORY_USERPTR";
+ return "V4L2_MEMORY_USERPTR";
case V4L2_MEMORY_DMABUF:
- return "V4L2_MEMORY_DMABUF";
+ return "V4L2_MEMORY_DMABUF";
case V4L2_MEMORY_OVERLAY:
- return "V4L2_MEMORY_OVERLAY";
+ return "V4L2_MEMORY_OVERLAY";
default:
- return "UNKNOWN";
- }
+ return "UNKNOWN";
+ }
}
// static
-const char* V4L2Device::V4L2BufferTypeToString(
- const enum v4l2_buf_type buf_type) {
- switch (buf_type) {
+const char* V4L2Device::v4L2BufferTypeToString(const enum v4l2_buf_type bufType) {
+ switch (bufType) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- return "OUTPUT";
+ return "OUTPUT";
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- return "CAPTURE";
+ return "CAPTURE";
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- return "OUTPUT_MPLANE";
+ return "OUTPUT_MPLANE";
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- return "CAPTURE_MPLANE";
+ return "CAPTURE_MPLANE";
default:
- return "UNKNOWN";
- }
+ return "UNKNOWN";
+ }
}
// static
-std::string V4L2Device::V4L2FormatToString(const struct v4l2_format& format) {
- std::ostringstream s;
- s << "v4l2_format type: " << format.type;
- if (format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- format.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- // single-planar
- const struct v4l2_pix_format& pix = format.fmt.pix;
- s << ", width_height: " << Size(pix.width, pix.height).ToString()
- << ", pixelformat: " << FourccToString(pix.pixelformat)
- << ", field: " << pix.field << ", bytesperline: " << pix.bytesperline
- << ", sizeimage: " << pix.sizeimage;
- } else if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
- const struct v4l2_pix_format_mplane& pix_mp = format.fmt.pix_mp;
- // As long as num_planes's type is uint8_t, ostringstream treats it as a
- // char instead of an integer, which is not what we want. Casting
- // pix_mp.num_planes unsigned int solves the issue.
- s << ", width_height: " << Size(pix_mp.width, pix_mp.height).ToString()
- << ", pixelformat: " << FourccToString(pix_mp.pixelformat)
- << ", field: " << pix_mp.field
- << ", num_planes: " << static_cast<unsigned int>(pix_mp.num_planes);
- for (size_t i = 0; i < pix_mp.num_planes; ++i) {
- const struct v4l2_plane_pix_format& plane_fmt = pix_mp.plane_fmt[i];
- s << ", plane_fmt[" << i << "].sizeimage: " << plane_fmt.sizeimage
- << ", plane_fmt[" << i << "].bytesperline: " << plane_fmt.bytesperline;
- }
- } else {
- s << " unsupported yet.";
- }
- return s.str();
+std::string V4L2Device::v4L2FormatToString(const struct v4l2_format& format) {
+ std::ostringstream s;
+ s << "v4l2_format type: " << format.type;
+ if (format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE || format.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ // single-planar
+ const struct v4l2_pix_format& pix = format.fmt.pix;
+ s << ", width_height: " << media::Size(pix.width, pix.height).ToString()
+ << ", pixelformat: " << media::FourccToString(pix.pixelformat) << ", field: " << pix.field
+ << ", bytesperline: " << pix.bytesperline << ", sizeimage: " << pix.sizeimage;
+ } else if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
+ const struct v4l2_pix_format_mplane& pixMp = format.fmt.pix_mp;
+ // As long as num_planes's type is uint8_t, ostringstream treats it as a char instead of an
+ // integer, which is not what we want. Casting pix_mp.num_planes unsigned int solves the
+ // issue.
+ s << ", width_height: " << media::Size(pixMp.width, pixMp.height).ToString()
+ << ", pixelformat: " << media::FourccToString(pixMp.pixelformat)
+ << ", field: " << pixMp.field
+ << ", num_planes: " << static_cast<unsigned int>(pixMp.num_planes);
+ for (size_t i = 0; i < pixMp.num_planes; ++i) {
+ const struct v4l2_plane_pix_format& plane_fmt = pixMp.plane_fmt[i];
+ s << ", plane_fmt[" << i << "].sizeimage: " << plane_fmt.sizeimage << ", plane_fmt["
+ << i << "].bytesperline: " << plane_fmt.bytesperline;
+ }
+ } else {
+ s << " unsupported yet.";
+ }
+ return s.str();
}
// static
-std::string V4L2Device::V4L2BufferToString(const struct v4l2_buffer& buffer) {
- std::ostringstream s;
- s << "v4l2_buffer type: " << buffer.type << ", memory: " << buffer.memory
- << ", index: " << buffer.index << " bytesused: " << buffer.bytesused
- << ", length: " << buffer.length;
- if (buffer.type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buffer.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- // single-planar
- if (buffer.memory == V4L2_MEMORY_MMAP) {
- s << ", m.offset: " << buffer.m.offset;
- } else if (buffer.memory == V4L2_MEMORY_USERPTR) {
- s << ", m.userptr: " << buffer.m.userptr;
- } else if (buffer.memory == V4L2_MEMORY_DMABUF) {
- s << ", m.fd: " << buffer.m.fd;
- }
- } else if (V4L2_TYPE_IS_MULTIPLANAR(buffer.type)) {
- for (size_t i = 0; i < buffer.length; ++i) {
- const struct v4l2_plane& plane = buffer.m.planes[i];
- s << ", m.planes[" << i << "](bytesused: " << plane.bytesused
- << ", length: " << plane.length
- << ", data_offset: " << plane.data_offset;
- if (buffer.memory == V4L2_MEMORY_MMAP) {
- s << ", m.mem_offset: " << plane.m.mem_offset;
- } else if (buffer.memory == V4L2_MEMORY_USERPTR) {
- s << ", m.userptr: " << plane.m.userptr;
- } else if (buffer.memory == V4L2_MEMORY_DMABUF) {
- s << ", m.fd: " << plane.m.fd;
- }
- s << ")";
- }
- } else {
- s << " unsupported yet.";
- }
- return s.str();
+std::string V4L2Device::v4L2BufferToString(const struct v4l2_buffer& buffer) {
+ std::ostringstream s;
+ s << "v4l2_buffer type: " << buffer.type << ", memory: " << buffer.memory
+ << ", index: " << buffer.index << " bytesused: " << buffer.bytesused
+ << ", length: " << buffer.length;
+ if (buffer.type == V4L2_BUF_TYPE_VIDEO_CAPTURE || buffer.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ // single-planar
+ if (buffer.memory == V4L2_MEMORY_MMAP) {
+ s << ", m.offset: " << buffer.m.offset;
+ } else if (buffer.memory == V4L2_MEMORY_USERPTR) {
+ s << ", m.userptr: " << buffer.m.userptr;
+ } else if (buffer.memory == V4L2_MEMORY_DMABUF) {
+ s << ", m.fd: " << buffer.m.fd;
+ };
+ } else if (V4L2_TYPE_IS_MULTIPLANAR(buffer.type)) {
+ for (size_t i = 0; i < buffer.length; ++i) {
+ const struct v4l2_plane& plane = buffer.m.planes[i];
+ s << ", m.planes[" << i << "](bytesused: " << plane.bytesused
+ << ", length: " << plane.length << ", data_offset: " << plane.data_offset;
+ if (buffer.memory == V4L2_MEMORY_MMAP) {
+ s << ", m.mem_offset: " << plane.m.mem_offset;
+ } else if (buffer.memory == V4L2_MEMORY_USERPTR) {
+ s << ", m.userptr: " << plane.m.userptr;
+ } else if (buffer.memory == V4L2_MEMORY_DMABUF) {
+ s << ", m.fd: " << plane.m.fd;
+ }
+ s << ")";
+ }
+ } else {
+ s << " unsupported yet.";
+ }
+ return s.str();
}
// static
-base::Optional<VideoFrameLayout> V4L2Device::V4L2FormatToVideoFrameLayout(
- const struct v4l2_format& format) {
- if (!V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
- VLOGF(1) << "v4l2_buf_type is not multiplanar: " << std::hex << "0x"
- << format.type;
- return base::nullopt;
- }
- const v4l2_pix_format_mplane& pix_mp = format.fmt.pix_mp;
- const uint32_t& pix_fmt = pix_mp.pixelformat;
- const auto video_fourcc = Fourcc::FromV4L2PixFmt(pix_fmt);
- if (!video_fourcc) {
- VLOGF(1) << "Failed to convert pixel format to VideoPixelFormat: "
- << FourccToString(pix_fmt);
- return base::nullopt;
- }
- const VideoPixelFormat video_format = video_fourcc->ToVideoPixelFormat();
- const size_t num_buffers = pix_mp.num_planes;
- const size_t num_color_planes = VideoFrame::NumPlanes(video_format);
- if (num_color_planes == 0) {
- VLOGF(1) << "Unsupported video format for NumPlanes(): "
- << VideoPixelFormatToString(video_format);
- return base::nullopt;
- }
- if (num_buffers > num_color_planes) {
- VLOGF(1) << "pix_mp.num_planes: " << num_buffers
- << " should not be larger than NumPlanes("
- << VideoPixelFormatToString(video_format)
- << "): " << num_color_planes;
- return base::nullopt;
- }
- // Reserve capacity in advance to prevent unnecessary vector reallocation.
- std::vector<ColorPlaneLayout> planes;
- planes.reserve(num_color_planes);
- for (size_t i = 0; i < num_buffers; ++i) {
- const v4l2_plane_pix_format& plane_format = pix_mp.plane_fmt[i];
- planes.emplace_back(static_cast<int32_t>(plane_format.bytesperline), 0u,
- plane_format.sizeimage);
- }
- // For the case that #color planes > #buffers, it fills stride of color
- // plane which does not map to buffer.
- // Right now only some pixel formats are supported: NV12, YUV420, YVU420.
- if (num_color_planes > num_buffers) {
- const int32_t y_stride = planes[0].stride;
- // Note that y_stride is from v4l2 bytesperline and its type is uint32_t.
- // It is safe to cast to size_t.
- const size_t y_stride_abs = static_cast<size_t>(y_stride);
- switch (pix_fmt) {
- case V4L2_PIX_FMT_NV12:
- // The stride of UV is the same as Y in NV12.
- // The height is half of Y plane.
- planes.emplace_back(y_stride, y_stride_abs * pix_mp.height,
- y_stride_abs * pix_mp.height / 2);
- DCHECK_EQ(2u, planes.size());
- break;
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420: {
- // The spec claims that two Cx rows (including padding) is exactly as
- // long as one Y row (including padding). So stride of Y must be even
- // number.
- if (y_stride % 2 != 0 || pix_mp.height % 2 != 0) {
- VLOGF(1) << "Plane-Y stride and height should be even; stride: "
- << y_stride << ", height: " << pix_mp.height;
- return base::nullopt;
+std::optional<media::VideoFrameLayout> V4L2Device::v4L2FormatToVideoFrameLayout(
+ const struct v4l2_format& format) {
+ if (!V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
+ ALOGE("v4l2_buf_type is not multiplanar: 0x%" PRIx32, format.type);
+ return std::nullopt;
+ }
+ const v4l2_pix_format_mplane& pixMp = format.fmt.pix_mp;
+ const uint32_t& pixFmt = pixMp.pixelformat;
+ const auto videoFourcc = media::Fourcc::FromV4L2PixFmt(pixFmt);
+ if (!videoFourcc) {
+ ALOGE("Failed to convert pixel format to VideoPixelFormat: %s",
+ media::FourccToString(pixFmt).c_str());
+ return std::nullopt;
+ }
+ const media::VideoPixelFormat videoFormat = videoFourcc->ToVideoPixelFormat();
+ const size_t numBuffers = pixMp.num_planes;
+ const size_t numColorPlanes = media::VideoFrame::NumPlanes(videoFormat);
+ if (numColorPlanes == 0) {
+ ALOGE("Unsupported video format for NumPlanes(): %s",
+ VideoPixelFormatToString(videoFormat).c_str());
+ return std::nullopt;
+ }
+ if (numBuffers > numColorPlanes) {
+ ALOGE("pix_mp.num_planes: %zu should not be larger than NumPlanes(%s): %zu", numBuffers,
+ VideoPixelFormatToString(videoFormat).c_str(), numColorPlanes);
+ return std::nullopt;
+ }
+ // Reserve capacity in advance to prevent unnecessary vector reallocation.
+ std::vector<media::ColorPlaneLayout> planes;
+ planes.reserve(numColorPlanes);
+ for (size_t i = 0; i < numBuffers; ++i) {
+ const v4l2_plane_pix_format& planeFormat = pixMp.plane_fmt[i];
+ planes.emplace_back(static_cast<int32_t>(planeFormat.bytesperline), 0u,
+ planeFormat.sizeimage);
+ }
+ // For the case that #color planes > #buffers, it fills stride of color plane which does not map
+ // to buffer. Right now only some pixel formats are supported: NV12, YUV420, YVU420.
+ if (numColorPlanes > numBuffers) {
+ const int32_t yStride = planes[0].stride;
+ // Note that y_stride is from v4l2 bytesperline and its type is uint32_t. It is safe to cast
+ // to size_t.
+ const size_t yStrideAbs = static_cast<size_t>(yStride);
+ switch (pixFmt) {
+ case V4L2_PIX_FMT_NV12:
+ // The stride of UV is the same as Y in NV12. The height is half of Y plane.
+ planes.emplace_back(yStride, yStrideAbs * pixMp.height, yStrideAbs * pixMp.height / 2);
+ ALOG_ASSERT(2u == planes.size());
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420: {
+ // The spec claims that two Cx rows (including padding) is exactly as long as one Y row
+ // (including padding). So stride of Y must be even number.
+ if (yStride % 2 != 0 || pixMp.height % 2 != 0) {
+ ALOGE("Plane-Y stride and height should be even; stride: %i, height: %u", yStride,
+ pixMp.height);
+ return std::nullopt;
+ }
+ const int32_t halfStride = yStride / 2;
+ const size_t plane0Area = yStrideAbs * pixMp.height;
+ const size_t plane1Area = plane0Area / 4;
+ planes.emplace_back(halfStride, plane0Area, plane1Area);
+ planes.emplace_back(halfStride, plane0Area + plane1Area, plane1Area);
+ ALOG_ASSERT(3u == planes.size());
+ break;
}
- const int32_t half_stride = y_stride / 2;
- const size_t plane_0_area = y_stride_abs * pix_mp.height;
- const size_t plane_1_area = plane_0_area / 4;
- planes.emplace_back(half_stride, plane_0_area, plane_1_area);
- planes.emplace_back(half_stride, plane_0_area + plane_1_area,
- plane_1_area);
- DCHECK_EQ(3u, planes.size());
- break;
- }
- default:
- VLOGF(1) << "Cannot derive stride for each plane for pixel format "
- << FourccToString(pix_fmt);
- return base::nullopt;
- }
- }
-
- // Some V4L2 devices expect buffers to be page-aligned. We cannot detect
- // such devices individually, so set this as a video frame layout property.
- constexpr size_t buffer_alignment = 0x1000;
- if (num_buffers == 1) {
- return VideoFrameLayout::CreateWithPlanes(
- video_format, Size(pix_mp.width, pix_mp.height), std::move(planes),
- buffer_alignment);
- } else {
- return VideoFrameLayout::CreateMultiPlanar(
- video_format, Size(pix_mp.width, pix_mp.height), std::move(planes),
- buffer_alignment);
- }
+ default:
+ ALOGE("Cannot derive stride for each plane for pixel format %s",
+ media::FourccToString(pixFmt).c_str());
+ return std::nullopt;
+ }
+ }
+
+ // Some V4L2 devices expect buffers to be page-aligned. We cannot detect such devices
+ // individually, so set this as a video frame layout property.
+ constexpr size_t bufferAlignment = 0x1000;
+ if (numBuffers == 1) {
+ return media::VideoFrameLayout::CreateWithPlanes(videoFormat,
+ media::Size(pixMp.width, pixMp.height),
+ std::move(planes), bufferAlignment);
+ } else {
+ return media::VideoFrameLayout::CreateMultiPlanar(videoFormat,
+ media::Size(pixMp.width, pixMp.height),
+ std::move(planes), bufferAlignment);
+ }
}
// static
-size_t V4L2Device::GetNumPlanesOfV4L2PixFmt(uint32_t pix_fmt) {
- base::Optional<Fourcc> fourcc = Fourcc::FromV4L2PixFmt(pix_fmt);
- if (fourcc && fourcc->IsMultiPlanar()) {
- return VideoFrame::NumPlanes(fourcc->ToVideoPixelFormat());
- }
- return 1u;
-}
-
-void V4L2Device::GetSupportedResolution(uint32_t pixelformat,
- Size* min_resolution,
- Size* max_resolution) {
- max_resolution->SetSize(0, 0);
- min_resolution->SetSize(0, 0);
- v4l2_frmsizeenum frame_size;
- memset(&frame_size, 0, sizeof(frame_size));
- frame_size.pixel_format = pixelformat;
- for (; Ioctl(VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0; ++frame_size.index) {
- if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
- if (frame_size.discrete.width >=
- base::checked_cast<uint32_t>(max_resolution->width()) &&
- frame_size.discrete.height >=
- base::checked_cast<uint32_t>(max_resolution->height())) {
- max_resolution->SetSize(frame_size.discrete.width,
- frame_size.discrete.height);
- }
- if (min_resolution->IsEmpty() ||
- (frame_size.discrete.width <=
- base::checked_cast<uint32_t>(min_resolution->width()) &&
- frame_size.discrete.height <=
- base::checked_cast<uint32_t>(min_resolution->height()))) {
- min_resolution->SetSize(frame_size.discrete.width,
- frame_size.discrete.height);
- }
- } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE ||
- frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
- max_resolution->SetSize(frame_size.stepwise.max_width,
- frame_size.stepwise.max_height);
- min_resolution->SetSize(frame_size.stepwise.min_width,
- frame_size.stepwise.min_height);
- break;
- }
- }
- if (max_resolution->IsEmpty()) {
- max_resolution->SetSize(1920, 1088);
- VLOGF(1) << "GetSupportedResolution failed to get maximum resolution for "
- << "fourcc " << FourccToString(pixelformat) << ", fall back to "
- << max_resolution->ToString();
- }
- if (min_resolution->IsEmpty()) {
- min_resolution->SetSize(16, 16);
- VLOGF(1) << "GetSupportedResolution failed to get minimum resolution for "
- << "fourcc " << FourccToString(pixelformat) << ", fall back to "
- << min_resolution->ToString();
- }
-}
-
-std::vector<uint32_t> V4L2Device::EnumerateSupportedPixelformats(
- v4l2_buf_type buf_type) {
- std::vector<uint32_t> pixelformats;
-
- v4l2_fmtdesc fmtdesc;
- memset(&fmtdesc, 0, sizeof(fmtdesc));
- fmtdesc.type = buf_type;
-
- for (; Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) {
- DVLOGF(3) << "Found " << fmtdesc.description << std::hex << " (0x"
- << fmtdesc.pixelformat << ")";
- pixelformats.push_back(fmtdesc.pixelformat);
- }
+size_t V4L2Device::getNumPlanesOfV4L2PixFmt(uint32_t pixFmt) {
+ std::optional<media::Fourcc> fourcc = media::Fourcc::FromV4L2PixFmt(pixFmt);
+ if (fourcc && fourcc->IsMultiPlanar()) {
+ return media::VideoFrame::NumPlanes(fourcc->ToVideoPixelFormat());
+ }
+ return 1u;
+}
+
+void V4L2Device::getSupportedResolution(uint32_t pixelFormat, media::Size* minResolution,
+ media::Size* maxResolution) {
+ maxResolution->SetSize(0, 0);
+ minResolution->SetSize(0, 0);
+ v4l2_frmsizeenum frameSize;
+ memset(&frameSize, 0, sizeof(frameSize));
+ frameSize.pixel_format = pixelFormat;
+ for (; ioctl(VIDIOC_ENUM_FRAMESIZES, &frameSize) == 0; ++frameSize.index) {
+ if (frameSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+ if (frameSize.discrete.width >= base::checked_cast<uint32_t>(maxResolution->width()) &&
+ frameSize.discrete.height >=
+ base::checked_cast<uint32_t>(maxResolution->height())) {
+ maxResolution->SetSize(frameSize.discrete.width, frameSize.discrete.height);
+ }
+ if (minResolution->IsEmpty() ||
+ (frameSize.discrete.width <= base::checked_cast<uint32_t>(minResolution->width()) &&
+ frameSize.discrete.height <=
+ base::checked_cast<uint32_t>(minResolution->height()))) {
+ minResolution->SetSize(frameSize.discrete.width, frameSize.discrete.height);
+ }
+ } else if (frameSize.type == V4L2_FRMSIZE_TYPE_STEPWISE ||
+ frameSize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
+ maxResolution->SetSize(frameSize.stepwise.max_width, frameSize.stepwise.max_height);
+ minResolution->SetSize(frameSize.stepwise.min_width, frameSize.stepwise.min_height);
+ break;
+ }
+ }
+ if (maxResolution->IsEmpty()) {
+ maxResolution->SetSize(1920, 1088);
+ ALOGE("GetSupportedResolution failed to get maximum resolution for fourcc %s, "
+ "fall back to %s",
+ media::FourccToString(pixelFormat).c_str(), maxResolution->ToString().c_str());
+ }
+ if (minResolution->IsEmpty()) {
+ minResolution->SetSize(16, 16);
+ ALOGE("GetSupportedResolution failed to get minimum resolution for fourcc %s, "
+ "fall back to %s",
+ media::FourccToString(pixelFormat).c_str(), minResolution->ToString().c_str());
+ }
+}
+
+std::vector<uint32_t> V4L2Device::enumerateSupportedPixelformats(v4l2_buf_type bufType) {
+ std::vector<uint32_t> pixelFormats;
- return pixelformats;
+ v4l2_fmtdesc fmtDesc;
+ memset(&fmtDesc, 0, sizeof(fmtDesc));
+ fmtDesc.type = bufType;
+
+ for (; ioctl(VIDIOC_ENUM_FMT, &fmtDesc) == 0; ++fmtDesc.index) {
+ ALOGV("Found %s (0x%" PRIx32 ")", fmtDesc.description, fmtDesc.pixelformat);
+ pixelFormats.push_back(fmtDesc.pixelformat);
+ }
+
+ return pixelFormats;
}
-VideoDecodeAccelerator::SupportedProfiles
-V4L2Device::EnumerateSupportedDecodeProfiles(const size_t num_formats,
- const uint32_t pixelformats[]) {
- VideoDecodeAccelerator::SupportedProfiles profiles;
+media::VideoDecodeAccelerator::SupportedProfiles V4L2Device::enumerateSupportedDecodeProfiles(
+ const size_t numFormats, const uint32_t pixelFormats[]) {
+ media::VideoDecodeAccelerator::SupportedProfiles profiles;
- const auto& supported_pixelformats =
- EnumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+ const auto& supportedPixelformats =
+ enumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
- for (uint32_t pixelformat : supported_pixelformats) {
- if (std::find(pixelformats, pixelformats + num_formats, pixelformat) ==
- pixelformats + num_formats)
- continue;
+ for (uint32_t pixelFormat : supportedPixelformats) {
+ if (std::find(pixelFormats, pixelFormats + numFormats, pixelFormat) ==
+ pixelFormats + numFormats)
+ continue;
- VideoDecodeAccelerator::SupportedProfile profile;
- GetSupportedResolution(pixelformat, &profile.min_resolution,
- &profile.max_resolution);
+ media::VideoDecodeAccelerator::SupportedProfile profile;
+ getSupportedResolution(pixelFormat, &profile.min_resolution, &profile.max_resolution);
- const auto video_codec_profiles =
- V4L2PixFmtToVideoCodecProfiles(pixelformat, false);
+ const auto videoCodecProfiles = v4L2PixFmtToVideoCodecProfiles(pixelFormat, false);
- for (const auto& video_codec_profile : video_codec_profiles) {
- profile.profile = video_codec_profile;
- profiles.push_back(profile);
+ for (const auto& videoCodecProfile : videoCodecProfiles) {
+ profile.profile = videoCodecProfile;
+ profiles.push_back(profile);
- DVLOGF(3) << "Found decoder profile " << GetProfileName(profile.profile)
- << ", resolutions: " << profile.min_resolution.ToString() << " "
- << profile.max_resolution.ToString();
+ ALOGV("Found decoder profile %s, resolutions: %s %s",
+ GetProfileName(profile.profile).c_str(),
+ profile.min_resolution.ToString().c_str(),
+ profile.max_resolution.ToString().c_str());
+ }
}
- }
- return profiles;
+ return profiles;
}
-VideoEncodeAccelerator::SupportedProfiles
-V4L2Device::EnumerateSupportedEncodeProfiles() {
- VideoEncodeAccelerator::SupportedProfiles profiles;
+media::VideoEncodeAccelerator::SupportedProfiles V4L2Device::enumerateSupportedEncodeProfiles() {
+ media::VideoEncodeAccelerator::SupportedProfiles profiles;
- const auto& supported_pixelformats =
- EnumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ const auto& supportedPixelformats =
+ enumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
- for (const auto& pixelformat : supported_pixelformats) {
- VideoEncodeAccelerator::SupportedProfile profile;
- profile.max_framerate_numerator = 30;
- profile.max_framerate_denominator = 1;
- Size min_resolution;
- GetSupportedResolution(pixelformat, &min_resolution,
- &profile.max_resolution);
+ for (const auto& pixelformat : supportedPixelformats) {
+ media::VideoEncodeAccelerator::SupportedProfile profile;
+ profile.max_framerate_numerator = 30;
+ profile.max_framerate_denominator = 1;
+ media::Size minResolution;
+ getSupportedResolution(pixelformat, &minResolution, &profile.max_resolution);
- const auto video_codec_profiles =
- V4L2PixFmtToVideoCodecProfiles(pixelformat, true);
+ const auto videoCodecProfiles = v4L2PixFmtToVideoCodecProfiles(pixelformat, true);
- for (const auto& video_codec_profile : video_codec_profiles) {
- profile.profile = video_codec_profile;
- profiles.push_back(profile);
+ for (const auto& videoCodecProfile : videoCodecProfiles) {
+ profile.profile = videoCodecProfile;
+ profiles.push_back(profile);
- DVLOGF(3) << "Found encoder profile " << GetProfileName(profile.profile)
- << ", max resolution: " << profile.max_resolution.ToString();
+ ALOGV("Found encoder profile %s, max resolution: %s",
+ GetProfileName(profile.profile).c_str(),
+ profile.max_resolution.ToString().c_str());
+ }
}
- }
- return profiles;
+ return profiles;
}
-bool V4L2Device::StartPolling(V4L2DevicePoller::EventCallback event_callback,
- base::RepeatingClosure error_callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+bool V4L2Device::startPolling(android::V4L2DevicePoller::EventCallback eventCallback,
+ base::RepeatingClosure errorCallback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
- if (!device_poller_) {
- device_poller_ =
- std::make_unique<V4L2DevicePoller>(this, "V4L2DeviceThreadPoller");
- }
+ if (!mDevicePoller) {
+ mDevicePoller = std::make_unique<android::V4L2DevicePoller>(this, "V4L2DeviceThreadPoller");
+ }
- bool ret = device_poller_->StartPolling(std::move(event_callback),
- std::move(error_callback));
+ bool ret = mDevicePoller->startPolling(std::move(eventCallback), std::move(errorCallback));
- if (!ret)
- device_poller_ = nullptr;
+ if (!ret) mDevicePoller = nullptr;
- return ret;
+ return ret;
}
-bool V4L2Device::StopPolling() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+bool V4L2Device::stopPolling() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
- return !device_poller_ || device_poller_->StopPolling();
+ return !mDevicePoller || mDevicePoller->stopPolling();
}
-void V4L2Device::SchedulePoll() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+void V4L2Device::schedulePoll() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
- if (!device_poller_ || !device_poller_->IsPolling())
- return;
+ if (!mDevicePoller || !mDevicePoller->isPolling()) return;
- device_poller_->SchedulePoll();
+ mDevicePoller->schedulePoll();
}
-bool V4L2Device::IsCtrlExposed(uint32_t ctrl_id) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+bool V4L2Device::isCtrlExposed(uint32_t ctrlId) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
- struct v4l2_queryctrl query_ctrl;
- memset(&query_ctrl, 0, sizeof(query_ctrl));
- query_ctrl.id = ctrl_id;
+ struct v4l2_queryctrl queryCtrl;
+ memset(&queryCtrl, 0, sizeof(queryCtrl));
+ queryCtrl.id = ctrlId;
- return Ioctl(VIDIOC_QUERYCTRL, &query_ctrl) == 0;
+ return ioctl(VIDIOC_QUERYCTRL, &queryCtrl) == 0;
}
-bool V4L2Device::SetExtCtrls(uint32_t ctrl_class,
- std::vector<V4L2ExtCtrl> ctrls) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+bool V4L2Device::setExtCtrls(uint32_t ctrlClass, std::vector<V4L2ExtCtrl> ctrls) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
- if (ctrls.empty())
- return true;
+ if (ctrls.empty()) return true;
- struct v4l2_ext_controls ext_ctrls;
- memset(&ext_ctrls, 0, sizeof(ext_ctrls));
- ext_ctrls.ctrl_class = ctrl_class;
- ext_ctrls.count = ctrls.size();
- ext_ctrls.controls = &ctrls[0].ctrl;
- return Ioctl(VIDIOC_S_EXT_CTRLS, &ext_ctrls) == 0;
+ struct v4l2_ext_controls extCtrls;
+ memset(&extCtrls, 0, sizeof(extCtrls));
+ extCtrls.ctrl_class = ctrlClass;
+ extCtrls.count = ctrls.size();
+ extCtrls.controls = &ctrls[0].ctrl;
+ return ioctl(VIDIOC_S_EXT_CTRLS, &extCtrls) == 0;
}
-bool V4L2Device::IsCommandSupported(uint32_t command_id) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+bool V4L2Device::isCommandSupported(uint32_t commandId) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
- struct v4l2_encoder_cmd cmd;
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = command_id;
+ struct v4l2_encoder_cmd cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.cmd = commandId;
- return Ioctl(VIDIOC_TRY_ENCODER_CMD, &cmd) == 0;
+ return ioctl(VIDIOC_TRY_ENCODER_CMD, &cmd) == 0;
}
-bool V4L2Device::HasCapabilities(uint32_t capabilities) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+bool V4L2Device::hasCapabilities(uint32_t capabilities) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
- struct v4l2_capability caps;
- memset(&caps, 0, sizeof(caps));
- if (Ioctl(VIDIOC_QUERYCAP, &caps) != 0) {
- LOG(ERROR) << "Failed to query capabilities";
- return false;
- }
+ struct v4l2_capability caps;
+ memset(&caps, 0, sizeof(caps));
+ if (ioctl(VIDIOC_QUERYCAP, &caps) != 0) {
+ ALOGE("Failed to query capabilities");
+ return false;
+ }
- return (caps.capabilities & capabilities) == capabilities;
+ return (caps.capabilities & capabilities) == capabilities;
}
-} // namespace media
+} // namespace android
diff --git a/common/V4L2DevicePoller.cpp b/common/V4L2DevicePoller.cpp
index 618dca3..5f2d0a5 100644
--- a/common/V4L2DevicePoller.cpp
+++ b/common/V4L2DevicePoller.cpp
@@ -3,138 +3,128 @@
// found in the LICENSE file.
// Note: ported from Chromium commit head: 22d34680c8ac
-#include "v4l2_codec2/common/V4L2DevicePoller.h"
+#include <v4l2_codec2/common/V4L2DevicePoller.h>
#include <string>
-#include "base/bind.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/threading/thread_checker.h"
+#include <base/bind.h>
+#include <base/threading/sequenced_task_runner_handle.h>
+#include <base/threading/thread_checker.h>
+#include <log/log.h>
-#include "macros.h"
-#include "v4l2_codec2/common/V4L2Device.h"
+#include <v4l2_codec2/common/V4L2Device.h>
-namespace media {
+namespace android {
-V4L2DevicePoller::V4L2DevicePoller(V4L2Device* const device,
- const std::string& thread_name)
- : device_(device),
- poll_thread_(std::move(thread_name)),
- trigger_poll_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED),
- stop_polling_(false) {
- DETACH_FROM_SEQUENCE(client_sequence_checker_);
-}
+V4L2DevicePoller::V4L2DevicePoller(V4L2Device* const device, const std::string& threadName)
+ : mDevice(device),
+ mPollThread(std::move(threadName)),
+ mTriggerPoll(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED),
+ mStopPolling(false) {}
V4L2DevicePoller::~V4L2DevicePoller() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+ ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
- StopPolling();
+ stopPolling();
}
-bool V4L2DevicePoller::StartPolling(EventCallback event_callback,
- base::RepeatingClosure error_callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
-
- if (IsPolling())
- return true;
+bool V4L2DevicePoller::startPolling(EventCallback eventCallback,
+ base::RepeatingClosure errorCallback) {
+ if (isPolling()) return true;
- DVLOGF(4) << "Starting polling";
+ ALOGV("Starting polling");
- client_task_runner_ = base::SequencedTaskRunnerHandle::Get();
- error_callback_ = error_callback;
+ mClientTaskTunner = base::SequencedTaskRunnerHandle::Get();
+ mErrorCallback = errorCallback;
- if (!poll_thread_.Start()) {
- VLOGF(1) << "Failed to start device poll thread";
- return false;
- }
+ if (!mPollThread.Start()) {
+ ALOGE("Failed to start device poll thread");
+ return false;
+ }
- event_callback_ = std::move(event_callback);
+ mEventCallback = std::move(eventCallback);
- stop_polling_.store(false);
- poll_thread_.task_runner()->PostTask(
- FROM_HERE, base::BindOnce(&V4L2DevicePoller::DevicePollTask,
- base::Unretained(this)));
+ mStopPolling.store(false);
+ mPollThread.task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&V4L2DevicePoller::devicePollTask, base::Unretained(this)));
- DVLOGF(3) << "Polling thread started";
+ ALOGV("Polling thread started");
- SchedulePoll();
+ schedulePoll();
- return true;
+ return true;
}
-bool V4L2DevicePoller::StopPolling() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+bool V4L2DevicePoller::stopPolling() {
+ ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
- if (!IsPolling())
- return true;
+ if (!isPolling()) return true;
- DVLOGF(4) << "Stopping polling";
+ ALOGV("Stopping polling");
- stop_polling_.store(true);
+ mStopPolling.store(true);
- trigger_poll_.Signal();
+ mTriggerPoll.Signal();
- if (!device_->SetDevicePollInterrupt()) {
- VLOGF(1) << "Failed to interrupt device poll.";
- return false;
- }
+ if (!mDevice->setDevicePollInterrupt()) {
+ ALOGE("Failed to interrupt device poll.");
+ return false;
+ }
- DVLOGF(3) << "Stop device poll thread";
- poll_thread_.Stop();
+ ALOGV("Stop device poll thread");
+ mPollThread.Stop();
- if (!device_->ClearDevicePollInterrupt()) {
- VLOGF(1) << "Failed to clear interrupting device poll.";
- return false;
- }
+ if (!mDevice->clearDevicePollInterrupt()) {
+ ALOGE("Failed to clear interrupting device poll.");
+ return false;
+ }
- DVLOGF(4) << "Polling thread stopped";
+ ALOGV("Polling thread stopped");
- return true;
+ return true;
}
-bool V4L2DevicePoller::IsPolling() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+bool V4L2DevicePoller::isPolling() const {
+ ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
- return poll_thread_.IsRunning();
+ return mPollThread.IsRunning();
}
-void V4L2DevicePoller::SchedulePoll() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
+void V4L2DevicePoller::schedulePoll() {
+ ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
- // A call to DevicePollTask() will be posted when we actually start polling.
- if (!IsPolling())
- return;
+ // A call to DevicePollTask() will be posted when we actually start polling.
+ if (!isPolling()) return;
- DVLOGF(4) << "Scheduling poll";
+ ALOGV("Scheduling poll");
- trigger_poll_.Signal();
+ mTriggerPoll.Signal();
}
-void V4L2DevicePoller::DevicePollTask() {
- DCHECK(poll_thread_.task_runner()->RunsTasksInCurrentSequence());
+void V4L2DevicePoller::devicePollTask() {
+ ALOG_ASSERT(mClientTaskTunner->RunsTasksInCurrentSequence());
- while (true) {
- DVLOGF(4) << "Waiting for poll to be scheduled.";
- trigger_poll_.Wait();
+ while (true) {
+ ALOGV("Waiting for poll to be scheduled.");
+ mTriggerPoll.Wait();
- if (stop_polling_) {
- DVLOGF(4) << "Poll stopped, exiting.";
- break;
- }
+ if (mStopPolling) {
+ ALOGV("Poll stopped, exiting.");
+ break;
+ }
- bool event_pending = false;
- DVLOGF(4) << "Polling device.";
- if (!device_->Poll(true, &event_pending)) {
- VLOGF(1) << "An error occurred while polling, calling error callback";
- client_task_runner_->PostTask(FROM_HERE, error_callback_);
- return;
- }
+ bool event_pending = false;
+ ALOGV("Polling device.");
+ if (!mDevice->poll(true, &event_pending)) {
+ ALOGE("An error occurred while polling, calling error callback");
+ mClientTaskTunner->PostTask(FROM_HERE, mErrorCallback);
+ return;
+ }
- DVLOGF(4) << "Poll returned, calling event callback.";
- client_task_runner_->PostTask(FROM_HERE,
- base::Bind(event_callback_, event_pending));
- }
+ ALOGV("Poll returned, calling event callback.");
+ mClientTaskTunner->PostTask(FROM_HERE, base::Bind(mEventCallback, event_pending));
+ }
}
-} // namespace media
+} // namespace android
diff --git a/common/include/v4l2_codec2/common/V4L2Device.h b/common/include/v4l2_codec2/common/V4L2Device.h
index fcd34b8..70a72b7 100644
--- a/common/include/v4l2_codec2/common/V4L2Device.h
+++ b/common/include/v4l2_codec2/common/V4L2Device.h
@@ -2,49 +2,35 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// This file defines the V4L2Device interface which is used by the
-// V4L2DecodeAccelerator class to delegate/pass the device specific
-// handling of any of the functionalities.
-// Note: ported from Chromium commit head: 2f13d62f0c0d
-// Note: the complete v4l2 device code is ported from Chromium, but some parts
-// have been removed:
-// - All V4L2 request functionality has been removed, as it required a newer
-// kernel version.
-// - void SetConfigStore() has been removed as it depends on a newer kernel
-// version.
-// - QueueDMABuf() from native pixmap planes has been removed, as
-// NativePixmapPlane have not been ported.
-// - GetVideoFrame() is removed as it depends on some helper functions that have
-// not been ported.
-// - GL-related functionality has been removed: canCreateEGLImageFrom(),
-// CreateEGLImage(), CreateGLImage() and GetTextureTarget()
-// - V4L2PixFmtToDrmFormat() has been removed, as DRM is not supported yet.
-
-#ifndef V4L2_DEVICE_H_
-#define V4L2_DEVICE_H_
+// This file defines the V4L2Device which is used by the V4L2Decoder and V4L2Encoder classes to
+// delegate/pass the device specific handling of any of the functionalities.
+// Note: ported from Chromium commit head: 2f13d62f0c0d, but some parts have been removed.
+
+#ifndef ANDROID_V4L2_CODEC2_COMMON_V4L2_DEVICE_H
+#define ANDROID_V4L2_CODEC2_COMMON_V4L2_DEVICE_H
#include <linux/videodev2.h>
#include <stddef.h>
#include <stdint.h>
-#include <queue>
+#include <optional>
#include <vector>
-#include "base/containers/flat_map.h"
-#include "base/files/scoped_file.h"
-#include "base/memory/ref_counted.h"
+#include <base/containers/flat_map.h>
+#include <base/files/scoped_file.h>
+#include <base/memory/ref_counted.h>
-#include "fourcc.h"
-#include "size.h"
-#include "video_codecs.h"
-#include "video_decode_accelerator.h"
-#include "video_encode_accelerator.h"
-#include "video_frame.h"
-#include "video_frame_layout.h"
-#include "video_pixel_format.h"
-#include "v4l2_codec2/common/V4L2DevicePoller.h"
+#include <fourcc.h>
+#include <size.h>
+#include <v4l2_codec2/common/V4L2DevicePoller.h>
+#include <video_codecs.h>
+#include <video_decode_accelerator.h>
+#include <video_encode_accelerator.h>
+#include <video_frame.h>
+#include <video_frame_layout.h>
+#include <video_pixel_format.h>
-namespace media {
+namespace android {
class V4L2Queue;
class V4L2BufferRefBase;
@@ -53,154 +39,131 @@ class V4L2DecodeSurface;
// Wrapper for the 'v4l2_ext_control' structure.
struct V4L2ExtCtrl {
- V4L2ExtCtrl(uint32_t id);
- V4L2ExtCtrl(uint32_t id, int32_t val);
- struct v4l2_ext_control ctrl;
+ V4L2ExtCtrl(uint32_t id);
+ V4L2ExtCtrl(uint32_t id, int32_t val);
+ struct v4l2_ext_control ctrl;
};
// A unique reference to a buffer for clients to prepare and submit.
//
-// Clients can prepare a buffer for queuing using the methods of this class, and
-// then either queue it using the Queue() method corresponding to the memory
-// type of the buffer, or drop the reference to make the buffer available again.
+// Clients can prepare a buffer for queuing using the methods of this class, and then either queue
+// it using the Queue() method corresponding to the memory type of the buffer, or drop the reference
+// to make the buffer available again.
class V4L2WritableBufferRef {
- public:
- V4L2WritableBufferRef(V4L2WritableBufferRef&& other);
- V4L2WritableBufferRef() = delete;
- V4L2WritableBufferRef& operator=(V4L2WritableBufferRef&& other);
-
- // Return the memory type of the buffer. Useful to e.g. decide which Queue()
- // method to use.
- enum v4l2_memory Memory() const;
-
- // Queue a MMAP buffer.
- // If successful, true is returned and the reference to the buffer is dropped
- // so this reference becomes invalid.
- // In case of error, false is returned and the buffer is returned to the free
- // list.
- bool QueueMMap() &&;
- // Queue a USERPTR buffer, assigning |ptrs| as pointer for each plane.
- // The size of |ptrs| must be equal to the number of planes of this buffer.
- // If successful, true is returned and the reference to the buffer is dropped
- // so this reference becomes invalid.
- // In case of error, false is returned and the buffer is returned to the free
- // list.
- bool QueueUserPtr(const std::vector<void*>& ptrs) &&;
- // Queue a DMABUF buffer, assigning |fds| as file descriptors for each plane.
- // It is allowed the number of |fds| might be greater than the number of
- // planes of this buffer. It happens when the v4l2 pixel format is single
- // planar. The fd of the first plane is only used in that case.
- // If successful, true is returned and the reference to the buffer is dropped
- // so this reference becomes invalid.
- // In case of error, false is returned and the buffer is returned to the free
- // list.
- bool QueueDMABuf(const std::vector<base::ScopedFD>& scoped_fds) &&;
- // Queue a DMABUF buffer, assigning |fds| as file descriptors for each plane.
- // It is allowed the number of |fds| might be greater than the number of
- // planes of this buffer. It happens when the v4l2 pixel format is single
- // planar. The fd of the first plane is only used in that case.
- // If successful, true is returned and the reference to the buffer is dropped
- // so this reference becomes invalid.
- // In case of error, false is returned and the buffer is returned to the free
- // list.
- bool QueueDMABuf(const std::vector<int>& fds) &&;
-
- // Returns the number of planes in this buffer.
- size_t PlanesCount() const;
- // Returns the size of the requested |plane|, in bytes.
- size_t GetPlaneSize(const size_t plane) const;
- // Set the size of the requested |plane|, in bytes. It is only valid for
- // USERPTR and DMABUF buffers. When using MMAP buffer, this method triggers a
- // DCHECK and is a no-op for release builds.
- void SetPlaneSize(const size_t plane, const size_t size);
- // This method can only be used with MMAP buffers.
- // It will return a pointer to the data of the |plane|th plane.
- // In case of error (invalid plane index or mapping failed), a nullptr is
- // returned.
- void* GetPlaneMapping(const size_t plane);
- // Set the timestamp field for this buffer.
- void SetTimeStamp(const struct timeval& timestamp);
- // Return the previously-set timestamp field for this buffer.
- const struct timeval& GetTimeStamp() const;
- // Set the number of bytes used for |plane|.
- void SetPlaneBytesUsed(const size_t plane, const size_t bytes_used);
- // Returns the previously-set number of bytes used for |plane|.
- size_t GetPlaneBytesUsed(const size_t plane) const;
- // Set the data offset for |plane|, in bytes.
- void SetPlaneDataOffset(const size_t plane, const size_t data_offset);
-
- // Return the V4L2 buffer ID of the underlying buffer.
- // TODO(acourbot) This is used for legacy clients but should be ultimately
- // removed. See crbug/879971
- size_t BufferId() const;
-
- ~V4L2WritableBufferRef();
-
- private:
- // Do the actual queue operation once the v4l2_buffer structure is properly
- // filled.
- bool DoQueue() &&;
-
- V4L2WritableBufferRef(const struct v4l2_buffer& v4l2_buffer,
- base::WeakPtr<V4L2Queue> queue);
- friend class V4L2BufferRefFactory;
-
- std::unique_ptr<V4L2BufferRefBase> buffer_data_;
-
- SEQUENCE_CHECKER(sequence_checker_);
- DISALLOW_COPY_AND_ASSIGN(V4L2WritableBufferRef);
+public:
+ V4L2WritableBufferRef(V4L2WritableBufferRef&& other);
+ V4L2WritableBufferRef() = delete;
+ V4L2WritableBufferRef& operator=(V4L2WritableBufferRef&& other);
+
+ // Return the memory type of the buffer. Useful to e.g. decide which Queue() method to use.
+ enum v4l2_memory memory() const;
+
+ // Queue a MMAP buffer. If successful, true is returned and the reference to the buffer is
+ // dropped so this reference becomes invalid. In case of error, false is returned and the buffer
+ // is returned to the free list.
+ bool queueMMap() &&;
+ // Queue a USERPTR buffer, assigning |ptrs| as pointer for each plane. The size of |ptrs| must
+ // be equal to the number of planes of this buffer. If successful, true is returned and the
+ // reference to the buffer is dropped so this reference becomes invalid. In case of error, false
+ // is returned and the buffer is returned to the free list.
+ bool queueUserPtr(const std::vector<void*>& ptrs) &&;
+ // Queue a DMABUF buffer, assigning |fds| as file descriptors for each plane. It is allowed the
+ // number of |fds| might be greater than the number of planes of this buffer. It happens when
+ // the v4l2 pixel format is single planar. The fd of the first plane is only used in that case.
+ // If successful, true is returned and the reference to the buffer is dropped so this reference
+ // becomes invalid. In case of error, false is returned and the buffer is returned to the free
+ // list.
+ bool queueDMABuf(const std::vector<int>& fds) &&;
+
+ // Returns the number of planes in this buffer.
+ size_t planesCount() const;
+ // Returns the size of the requested |plane|, in bytes.
+ size_t getPlaneSize(const size_t plane) const;
+ // Set the size of the requested |plane|, in bytes. It is only valid for USERPTR and DMABUF
+ // buffers. When using an MMAP buffer, this method triggers an assert and is a no-op for release
+ // builds.
+ void setPlaneSize(const size_t plane, const size_t size);
+ // This method can only be used with MMAP buffers. It will return a pointer to the data of the
+ // |plane|th plane. In case of error (invalid plane index or mapping failed), a nullptr is
+ // returned.
+ void* getPlaneMapping(const size_t plane);
+ // Set the timestamp field for this buffer.
+ void setTimeStamp(const struct timeval& timestamp);
+ // Return the previously-set timestamp field for this buffer.
+ const struct timeval& getTimeStamp() const;
+ // Set the number of bytes used for |plane|.
+ void setPlaneBytesUsed(const size_t plane, const size_t bytesUsed);
+ // Returns the previously-set number of bytes used for |plane|.
+ size_t getPlaneBytesUsed(const size_t plane) const;
+ // Set the data offset for |plane|, in bytes.
+ void setPlaneDataOffset(const size_t plane, const size_t dataOffset);
+
+ // Return the V4L2 buffer ID of the underlying buffer.
+ size_t bufferId() const;
+
+ ~V4L2WritableBufferRef();
+
+private:
+ friend class V4L2BufferRefFactory;
+
+ // Do the actual queue operation once the v4l2_buffer structure is properly filled.
+ bool doQueue() &&;
+
+ V4L2WritableBufferRef(const struct v4l2_buffer& v4l2Buffer, base::WeakPtr<V4L2Queue> queue);
+
+ V4L2WritableBufferRef(const V4L2WritableBufferRef&) = delete;
+ V4L2WritableBufferRef& operator=(const V4L2WritableBufferRef&) = delete;
+
+ std::unique_ptr<V4L2BufferRefBase> mBufferData;
+
+ SEQUENCE_CHECKER(mSequenceChecker);
};
// A reference to a read-only, dequeued buffer.
//
-// Clients use this class to query the buffer state and content, and are
-// guaranteed that the buffer will not be reused until all references are
-// destroyed.
-// All methods of this class must be called from the same sequence, but
-// instances of V4L2ReadableBuffer objects can be destroyed from any sequence.
-// They can even outlive the V4L2 buffers they originate from. This flexibility
-// is required because V4L2ReadableBufferRefs can be embedded into VideoFrames,
-// which are then passed to other threads and not necessarily destroyed before
-// the V4L2Queue buffers are freed.
-class V4L2ReadableBuffer
- : public base::RefCountedThreadSafe<V4L2ReadableBuffer> {
- public:
- // Returns whether the V4L2_BUF_FLAG_LAST flag is set for this buffer.
- bool IsLast() const;
- // Returns whether the V4L2_BUF_FLAG_KEYFRAME flag is set for this buffer.
- bool IsKeyframe() const;
- // Return the timestamp set by the driver on this buffer.
- struct timeval GetTimeStamp() const;
- // Returns the number of planes in this buffer.
- size_t PlanesCount() const;
- // Returns the number of bytes used for |plane|.
- size_t GetPlaneBytesUsed(size_t plane) const;
- // Returns the data offset for |plane|.
- size_t GetPlaneDataOffset(size_t plane) const;
- // This method can only be used with MMAP buffers.
- // It will return a pointer to the data of the |plane|th plane.
- // In case of error (invalid plane index or mapping failed), a nullptr is
- // returned.
- const void* GetPlaneMapping(const size_t plane) const;
-
- // Return the V4L2 buffer ID of the underlying buffer.
- // TODO(acourbot) This is used for legacy clients but should be ultimately
- // removed. See crbug/879971
- size_t BufferId() const;
-
- private:
- friend class V4L2BufferRefFactory;
- friend class base::RefCountedThreadSafe<V4L2ReadableBuffer>;
-
- ~V4L2ReadableBuffer();
-
- V4L2ReadableBuffer(const struct v4l2_buffer& v4l2_buffer,
- base::WeakPtr<V4L2Queue> queue);
-
- std::unique_ptr<V4L2BufferRefBase> buffer_data_;
-
- SEQUENCE_CHECKER(sequence_checker_);
- DISALLOW_COPY_AND_ASSIGN(V4L2ReadableBuffer);
+// Clients use this class to query the buffer state and content, and are guaranteed that the buffer
+// will not be reused until all references are destroyed.
+// All methods of this class must be called from the same sequence, but instances of
+// V4L2ReadableBuffer objects can be destroyed from any sequence. They can even outlive the V4L2
+// buffers they originate from. This flexibility is required because V4L2ReadableBufferRefs can be
+// embedded into VideoFrames, which are then passed to other threads and not necessarily destroyed
+// before the V4L2Queue buffers are freed.
+class V4L2ReadableBuffer : public base::RefCountedThreadSafe<V4L2ReadableBuffer> {
+public:
+ // Returns whether the V4L2_BUF_FLAG_LAST flag is set for this buffer.
+ bool isLast() const;
+ // Returns whether the V4L2_BUF_FLAG_KEYFRAME flag is set for this buffer.
+ bool isKeyframe() const;
+ // Return the timestamp set by the driver on this buffer.
+ struct timeval getTimeStamp() const;
+ // Returns the number of planes in this buffer.
+ size_t planesCount() const;
+ // Returns the number of bytes used for |plane|.
+ size_t getPlaneBytesUsed(size_t plane) const;
+ // Returns the data offset for |plane|.
+ size_t getPlaneDataOffset(size_t plane) const;
+ // This method can only be used with MMAP buffers. It will return a pointer to the data of the
+ // |plane|th plane. In case of error (invalid plane index or mapping failed), a nullptr is
+ // returned.
+ const void* getPlaneMapping(const size_t plane) const;
+
+ // Return the V4L2 buffer ID of the underlying buffer.
+ size_t bufferId() const;
+
+private:
+ friend class V4L2BufferRefFactory;
+ friend class base::RefCountedThreadSafe<V4L2ReadableBuffer>;
+
+ ~V4L2ReadableBuffer();
+
+ V4L2ReadableBuffer(const struct v4l2_buffer& v4l2Buffer, base::WeakPtr<V4L2Queue> queue);
+
+ V4L2ReadableBuffer(const V4L2ReadableBuffer&) = delete;
+ V4L2ReadableBuffer& operator=(const V4L2ReadableBuffer&) = delete;
+
+ std::unique_ptr<V4L2BufferRefBase> mBufferData;
+
+ SEQUENCE_CHECKER(mSequenceChecker);
};
// Shortcut for naming consistency.
@@ -209,389 +172,335 @@ using V4L2ReadableBufferRef = scoped_refptr<V4L2ReadableBuffer>;
class V4L2Device;
class V4L2Buffer;
-// Interface representing a specific queue of a |V4L2Device|. It provides free
-// and queued buffer management that is commonly required by clients.
+// Interface representing a specific queue of a |V4L2Device|. It provides free and queued buffer
+// management that is commonly required by clients.
//
// Buffers managed by this class undergo the following cycle:
-// 1) Allocated buffers are put into a free buffers pool, indicating that they
-// are used neither by the client nor the hardware.
-// 2) The client obtains a unique, writable reference to one of the free
-// buffers in order to set its content and other parameters.
-// 3) The client then queues the buffer obtained in 2), which invalidates its
-// reference. The buffer is now prepared to be processed by the hardware.
-// 4) Once the hardware is done with the buffer, it is ready to be dequeued by
-// the client. The client obtains a read-only, counted reference to the
-// buffer and can read its content and metadata, as well as making other
-// references to it. The buffer will not be reused until all the references
-// are dropped. Once this happens, the buffer goes back to the free list
-// described in 1).
+// 1) Allocated buffers are put into a free buffers pool, indicating that they are used neither by
+// the client nor the hardware.
+// 2) The client obtains a unique, writable reference to one of the free buffers in order to set
+// its content and other parameters.
+// 3) The client then queues the buffer obtained in 2), which invalidates its reference. The buffer
+// is now prepared to be processed by the hardware.
+// 4) Once the hardware is done with the buffer, it is ready to be dequeued by the client. The
+// client obtains a read-only, counted reference to the buffer and can read its content and
+// metadata, as well as making other references to it. The buffer will not be reused until all
+// the references are dropped. Once this happens, the buffer goes back to the free list described
+// in 1).
class V4L2Queue : public base::RefCountedThreadSafe<V4L2Queue> {
- public:
- // Set |fourcc| as the current format on this queue. |size| corresponds to the
- // desired buffer's dimensions (i.e. width and height members of
- // v4l2_pix_format_mplane (if not applicable, pass Size()).
- // |buffer_size| is the desired size in bytes of the buffer for single-planar
- // formats (i.e. sizeimage of the first plane). It can be set to 0 if not
- // relevant for the desired format.
- // |stride| is the desired stride in bytes of the buffer (i.e. bytesperline).
- // It can be set to 0 if not relevant or to let the driver decide.
- // If the format could be set, then the |v4l2_format| reflecting the actual
- // format is returned. It is guaranteed to feature the specified |fourcc|,
- // but any other parameter (including |size| and |buffer_size| may have been
- // adjusted by the driver, so the caller must check their values.
- base::Optional<struct v4l2_format> SetFormat(uint32_t fourcc,
- const Size& size,
- size_t buffer_size,
- uint32_t stride = 0)
- WARN_UNUSED_RESULT;
-
- // Identical to |SetFormat|, but does not actually apply the format, and can
- // be called anytime.
- // Returns an adjusted V4L2 format if |fourcc| is supported by the queue, or
- // |nullopt| if |fourcc| is not supported or an ioctl error happened.
- base::Optional<struct v4l2_format> TryFormat(uint32_t fourcc,
- const Size& size,
- size_t buffer_size)
- WARN_UNUSED_RESULT;
-
- // Returns the currently set format on the queue. The result is returned as
- // a std::pair where the first member is the format, or base::nullopt if the
- // format could not be obtained due to an ioctl error. The second member is
- // only used in case of an error and contains the |errno| set by the failing
- // ioctl. If the first member is not base::nullopt, the second member will
- // always be zero.
- //
- // If the second member is 0, then the first member is guaranteed to have
- // a valid value. So clients that are not interested in the precise error
- // message can just check that the first member is valid and go on.
- //
- // This pair is used because not all failures to get the format are
- // necessarily errors, so we need to way to let the use decide whether it
- // is one or not.
- std::pair<base::Optional<struct v4l2_format>, int> GetFormat();
-
- // Allocate |count| buffers for the current format of this queue, with a
- // specific |memory| allocation, and returns the number of buffers allocated
- // or zero if an error occurred, or if references to any previously allocated
- // buffers are still held by any clients.
- //
- // The number of allocated buffers may be larger than the number requested, so
- // callers must always check the return value.
- //
- // Calling this method while buffers are still allocated results in an error.
- size_t AllocateBuffers(size_t count,
- enum v4l2_memory memory) WARN_UNUSED_RESULT;
-
- // Deallocate all buffers previously allocated by |AllocateBuffers|. Any
- // references to buffers previously allocated held by the client must be
- // released, or this call will fail.
- bool DeallocateBuffers();
-
- // Returns the memory usage of v4l2 buffers owned by this V4L2Queue which are
- // mapped in user space memory.
- size_t GetMemoryUsage() const;
-
- // Returns |memory_|, memory type of last buffers allocated by this V4L2Queue.
- v4l2_memory GetMemoryType() const;
-
- // Return a reference to a free buffer for the caller to prepare and submit,
- // or nullopt if no buffer is currently free.
- //
- // If the caller discards the returned reference, the underlying buffer is
- // made available to clients again.
- base::Optional<V4L2WritableBufferRef> GetFreeBuffer();
- base::Optional<V4L2WritableBufferRef> GetFreeBuffer(
- size_t requested_buffer_id);
-
- // Attempt to dequeue a buffer, and return a reference to it if one was
- // available.
- //
- // The first element of the returned pair will be false if an error occurred,
- // in which case the second element will be nullptr. If no error occurred,
- // then the first element will be true and the second element will contain a
- // reference to the dequeued buffer if one was available, or nullptr
- // otherwise.
- // Dequeued buffers will not be reused by the driver until all references to
- // them are dropped.
- std::pair<bool, V4L2ReadableBufferRef> DequeueBuffer();
-
- // Returns true if this queue is currently streaming.
- bool IsStreaming() const;
- // If not currently streaming, starts streaming. Returns true if we started
- // streaming, or were already streaming, or false if we were not streaming
- // and an error occurred when attempting to start the stream. On failure, any
- // previously-queued buffers will be dequeued without processing and made
- // available to the client, while any buffers held by the client will remain
- // unchanged and their ownership will remain with the client.
- bool Streamon();
- // If currently streaming, stops streaming. Also make all queued buffers
- // available to the client again regardless of the streaming state.
- // If an error occurred while attempting to stop streaming, then false is
- // returned and queued buffers are left untouched since the V4L2 queue may
- // still be using them.
- bool Streamoff();
-
- // Returns the number of buffers currently allocated for this queue.
- size_t AllocatedBuffersCount() const;
- // Returns the number of currently free buffers on this queue.
- size_t FreeBuffersCount() const;
- // Returns the number of buffers currently queued on this queue.
- size_t QueuedBuffersCount() const;
-
- private:
- ~V4L2Queue();
-
- // Called when clients request a buffer to be queued.
- bool QueueBuffer(struct v4l2_buffer* v4l2_buffer);
-
- const enum v4l2_buf_type type_;
- enum v4l2_memory memory_ = V4L2_MEMORY_MMAP;
- bool is_streaming_ = false;
- size_t planes_count_ = 0;
- // Current format as set by SetFormat.
- base::Optional<struct v4l2_format> current_format_;
-
- std::vector<std::unique_ptr<V4L2Buffer>> buffers_;
-
- // Buffers that are available for client to get and submit.
- // Buffers in this list are not referenced by anyone else than ourselves.
- scoped_refptr<V4L2BuffersList> free_buffers_;
- // Buffers that have been queued by the client, and not dequeued yet.
- std::set<size_t> queued_buffers_;
-
- scoped_refptr<V4L2Device> device_;
- // Callback to call in this queue's destructor.
- base::OnceClosure destroy_cb_;
-
- V4L2Queue(scoped_refptr<V4L2Device> dev,
- enum v4l2_buf_type type,
- base::OnceClosure destroy_cb);
- friend class V4L2QueueFactory;
- friend class V4L2BufferRefBase;
- friend class base::RefCountedThreadSafe<V4L2Queue>;
-
- SEQUENCE_CHECKER(sequence_checker_);
-
- base::WeakPtrFactory<V4L2Queue> weak_this_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(V4L2Queue);
+public:
+ // Set |fourcc| as the current format on this queue. |size| corresponds to the desired buffer's
+ // dimensions (i.e. width and height members of v4l2_pix_format_mplane (if not applicable, pass
+ // Size()).
+ // |bufferSize| is the desired size in bytes of the buffer for single-planar formats (i.e.
+ // sizeimage of the first plane). It can be set to 0 if not relevant for the desired format.
+ // |stride| is the desired stride in bytes of the buffer (i.e. bytesperline). It can be set to 0
+ // if not relevant or to let the driver decide. If the format could be set, then the
+ // |v4l2_format| reflecting the actual format is returned. It is guaranteed to feature the
+ // specified |fourcc|, but any other parameter (including |size| and |bufferSize| may have been
+ // adjusted by the driver, so the caller must check their values.
+ std::optional<struct v4l2_format> setFormat(uint32_t fourcc, const media::Size& size,
+ size_t bufferSize,
+ uint32_t stride = 0) WARN_UNUSED_RESULT;
+
+ // Identical to |setFormat|, but does not actually apply the format, and can be called anytime.
+ // Returns an adjusted V4L2 format if |fourcc| is supported by the queue, or |nullopt| if
+ // |fourcc| is not supported or an ioctl error happened.
+ std::optional<struct v4l2_format> tryFormat(uint32_t fourcc, const media::Size& size,
+ size_t bufferSize) WARN_UNUSED_RESULT;
+
+ // Returns the currently set format on the queue. The result is returned as a std::pair where
+ // the first member is the format, or base::nullopt if the format could not be obtained due to
+ // an ioctl error. The second member is only used in case of an error and contains the |errno|
+ // set by the failing ioctl. If the first member is not base::nullopt, the second member will
+ // always be zero.
+ //
+ // If the second member is 0, then the first member is guaranteed to have a valid value. So
+ // clients that are not interested in the precise error message can just check that the first
+ // member is valid and go on.
+ //
+ // This pair is used because not all failures to get the format are necessarily errors, so we
+ // need to way to let the use decide whether it is one or not.
+ std::pair<std::optional<struct v4l2_format>, int> getFormat();
+
+ // Allocate |count| buffers for the current format of this queue, with a specific |memory|
+ // allocation, and returns the number of buffers allocated or zero if an error occurred, or if
+ // references to any previously allocated buffers are still held by any clients.
+ //
+ // The number of allocated buffers may be larger than the number requested, so callers must
+ // always check the return value.
+ //
+ // Calling this method while buffers are still allocated results in an error.
+ size_t allocateBuffers(size_t count, enum v4l2_memory memory) WARN_UNUSED_RESULT;
+
+ // Deallocate all buffers previously allocated by |allocateBuffers|. Any references to buffers
+ // previously allocated held by the client must be released, or this call will fail.
+ bool deallocateBuffers();
+
+ // Returns the memory usage of v4l2 buffers owned by this V4L2Queue which are mapped in user
+ // space memory.
+ size_t getMemoryUsage() const;
+
+ // Returns |mMemory|, memory type of last buffers allocated by this V4L2Queue.
+ v4l2_memory getMemoryType() const;
+
+ // Return a reference to a free buffer for the caller to prepare and submit, or nullopt if no
+ // buffer is currently free.
+ //
+ // If the caller discards the returned reference, the underlying buffer is made available to
+ // clients again.
+ std::optional<V4L2WritableBufferRef> getFreeBuffer();
+ std::optional<V4L2WritableBufferRef> getFreeBuffer(size_t requestedBufferId);
+
+ // Attempt to dequeue a buffer, and return a reference to it if one was available.
+ //
+ // The first element of the returned pair will be false if an error occurred, in which case the
+ // second element will be nullptr. If no error occurred, then the first element will be true and
+ // the second element will contain a reference to the dequeued buffer if one was available, or
+ // nullptr otherwise. Dequeued buffers will not be reused by the driver until all references to
+ // them are dropped.
+ std::pair<bool, V4L2ReadableBufferRef> dequeueBuffer();
+
+ // Returns true if this queue is currently streaming.
+ bool isStreaming() const;
+ // If not currently streaming, starts streaming. Returns true if we started streaming, or were
+ // already streaming, or false if we were not streaming and an error occurred when attempting to
+ // start the stream. On failure, any previously-queued buffers will be dequeued without
+ // processing and made available to the client, while any buffers held by the client will remain
+ // unchanged and their ownership will remain with the client.
+ bool streamon();
+ // If currently streaming, stops streaming. Also make all queued buffers available to the client
+ // again regardless of the streaming state. If an error occurred while attempting to stop
+ // streaming, then false is returned and queued buffers are left untouched since the V4L2 queue
+ // may still be using them.
+ bool streamoff();
+
+ // Returns the number of buffers currently allocated for this queue.
+ size_t allocatedBuffersCount() const;
+ // Returns the number of currently free buffers on this queue.
+ size_t freeBuffersCount() const;
+ // Returns the number of buffers currently queued on this queue.
+ size_t queuedBuffersCount() const;
+
+private:
+ ~V4L2Queue();
+
+ V4L2Queue(const V4L2Queue&) = delete;
+ V4L2Queue& operator=(const V4L2Queue&) = delete;
+
+ // Called when clients request a buffer to be queued.
+ bool queueBuffer(struct v4l2_buffer* v4l2Buffer);
+
+ const enum v4l2_buf_type mType;
+ enum v4l2_memory mMemory = V4L2_MEMORY_MMAP;
+ bool mIsStreaming = false;
+ size_t mPlanesCount = 0;
+ // Current format as set by SetFormat.
+ std::optional<struct v4l2_format> mCurrentFormat;
+
+ std::vector<std::unique_ptr<V4L2Buffer>> mBuffers;
+
+ // Buffers that are available for client to get and submit. Buffers in this list are not
+ // referenced by anyone else than ourselves.
+ scoped_refptr<V4L2BuffersList> mFreeBuffers;
+ // Buffers that have been queued by the client, and not dequeued yet.
+ std::set<size_t> mQueuedBuffers;
+
+ scoped_refptr<V4L2Device> mDevice;
+ // Callback to call in this queue's destructor.
+ base::OnceClosure mDestroyCb;
+
+ V4L2Queue(scoped_refptr<V4L2Device> dev, enum v4l2_buf_type type, base::OnceClosure destroyCb);
+ friend class V4L2QueueFactory;
+ friend class V4L2BufferRefBase;
+ friend class base::RefCountedThreadSafe<V4L2Queue>;
+
+ SEQUENCE_CHECKER(mSequenceChecker);
+
+ base::WeakPtrFactory<V4L2Queue> mWeakThisFactory{this};
};
class V4L2Device : public base::RefCountedThreadSafe<V4L2Device> {
- public:
- // Utility format conversion functions
- // If there is no corresponding single- or multi-planar format, returns 0.
- static uint32_t VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile,
- bool slice_based);
- static VideoCodecProfile V4L2ProfileToVideoCodecProfile(VideoCodec codec,
- uint32_t profile);
- std::vector<VideoCodecProfile> V4L2PixFmtToVideoCodecProfiles(
- uint32_t pix_fmt,
- bool is_encoder);
- // Calculates the largest plane's allocation size requested by a V4L2 device.
- static Size AllocatedSizeFromV4L2Format(const struct v4l2_format& format);
-
- // Convert required H264 profile and level to V4L2 enums.
- static int32_t VideoCodecProfileToV4L2H264Profile(VideoCodecProfile profile);
- static int32_t H264LevelIdcToV4L2H264Level(uint8_t level_idc);
-
- // Converts v4l2_memory to a string.
- static const char* V4L2MemoryToString(const v4l2_memory memory);
-
- // Returns the printable name of a v4l2_buf_type.
- static const char* V4L2BufferTypeToString(const enum v4l2_buf_type buf_type);
-
- // Composes human readable string of v4l2_format.
- static std::string V4L2FormatToString(const struct v4l2_format& format);
-
- // Composes human readable string of v4l2_buffer.
- static std::string V4L2BufferToString(const struct v4l2_buffer& buffer);
-
- // Composes VideoFrameLayout based on v4l2_format.
- // If error occurs, it returns base::nullopt.
- static base::Optional<VideoFrameLayout> V4L2FormatToVideoFrameLayout(
- const struct v4l2_format& format);
-
- // Returns number of planes of |pix_fmt|.
- static size_t GetNumPlanesOfV4L2PixFmt(uint32_t pix_fmt);
-
- enum class Type {
- kDecoder,
- kEncoder,
- };
-
- // Create and initialize an appropriate V4L2Device instance for the current
- // platform, or return nullptr if not available.
- static scoped_refptr<V4L2Device> Create();
-
- // Open a V4L2 device of |type| for use with |v4l2_pixfmt|.
- // Return true on success.
- // The device will be closed in the destructor.
- bool Open(Type type, uint32_t v4l2_pixfmt);
-
- // Returns the V4L2Queue corresponding to the requested |type|, or nullptr
- // if the requested queue type is not supported.
- scoped_refptr<V4L2Queue> GetQueue(enum v4l2_buf_type type);
-
- // Parameters and return value are the same as for the standard ioctl() system
- // call.
- int Ioctl(int request, void* arg);
-
- // This method sleeps until either:
- // - SetDevicePollInterrupt() is called (on another thread),
- // - |poll_device| is true, and there is new data to be read from the device,
- // or an event from the device has arrived; in the latter case
- // |*event_pending| will be set to true.
- // Returns false on error, true otherwise.
- // This method should be called from a separate thread.
- bool Poll(bool poll_device, bool* event_pending);
-
- // These methods are used to interrupt the thread sleeping on Poll() and force
- // it to return regardless of device state, which is usually when the client
- // is no longer interested in what happens with the device (on cleanup,
- // client state change, etc.). When SetDevicePollInterrupt() is called, Poll()
- // will return immediately, and any subsequent calls to it will also do so
- // until ClearDevicePollInterrupt() is called.
- bool SetDevicePollInterrupt();
- bool ClearDevicePollInterrupt();
-
- // Wrappers for standard mmap/munmap system calls.
- void* Mmap(void* addr,
- unsigned int len,
- int prot,
- int flags,
- unsigned int offset);
- void Munmap(void* addr, unsigned int len);
-
- // Return a vector of dmabuf file descriptors, exported for V4L2 buffer with
- // |index|, assuming the buffer contains |num_planes| V4L2 planes and is of
- // |type|. Return an empty vector on failure.
- // The caller is responsible for closing the file descriptors after use.
- std::vector<base::ScopedFD> GetDmabufsForV4L2Buffer(
- int index,
- size_t num_planes,
- enum v4l2_buf_type type);
-
- // Returns the preferred V4L2 input formats for |type| or empty if none.
- std::vector<uint32_t> PreferredInputFormat(Type type);
-
- // NOTE: The below methods to query capabilities have a side effect of
- // closing the previously-open device, if any, and should not be called after
- // Open().
- // TODO(posciak): fix this.
-
- // Get minimum and maximum resolution for fourcc |pixelformat| and store to
- // |min_resolution| and |max_resolution|.
- void GetSupportedResolution(uint32_t pixelformat,
- Size* min_resolution,
- Size* max_resolution);
-
- std::vector<uint32_t> EnumerateSupportedPixelformats(v4l2_buf_type buf_type);
-
- // Return supported profiles for decoder, including only profiles for given
- // fourcc |pixelformats|.
- VideoDecodeAccelerator::SupportedProfiles GetSupportedDecodeProfiles(
- const size_t num_formats,
- const uint32_t pixelformats[]);
-
- // Return supported profiles for encoder.
- VideoEncodeAccelerator::SupportedProfiles
- GetSupportedEncodeProfiles();
-
- // Start polling on this V4L2Device. |event_callback| will be posted to
- // the caller's sequence if a buffer is ready to be dequeued and/or a V4L2
- // event has been posted. |error_callback| will be posted to the client's
- // sequence if a polling error has occurred.
- bool StartPolling(V4L2DevicePoller::EventCallback event_callback,
- base::RepeatingClosure error_callback);
- // Stop polling this V4L2Device if polling was active. No new events will
- // be posted after this method has returned.
- bool StopPolling();
- // Schedule a polling event if polling is enabled. This method is intended
- // to be called from V4L2Queue, clients should not need to call it directly.
- void SchedulePoll();
-
- // Check whether the V4L2 control with specified |ctrl_id| is supported.
- bool IsCtrlExposed(uint32_t ctrl_id);
- // Set the specified list of |ctrls| for the specified |ctrl_class|, returns
- // whether the operation succeeded.
- bool SetExtCtrls(uint32_t ctrl_class, std::vector<V4L2ExtCtrl> ctrls);
-
- // Check whether the V4L2 command with specified |command_id| is supported.
- bool IsCommandSupported(uint32_t command_id);
- // Check whether the V4L2 device has the specified |capabilities|.
- bool HasCapabilities(uint32_t capabilities);
-
- private:
- // Vector of video device node paths and corresponding pixelformats supported
- // by each device node.
- using Devices = std::vector<std::pair<std::string, std::vector<uint32_t>>>;
-
- friend class base::RefCountedThreadSafe<V4L2Device>;
- V4L2Device();
- ~V4L2Device();
-
- VideoDecodeAccelerator::SupportedProfiles EnumerateSupportedDecodeProfiles(
- const size_t num_formats,
- const uint32_t pixelformats[]);
-
- VideoEncodeAccelerator::SupportedProfiles EnumerateSupportedEncodeProfiles();
-
- // Perform platform-specific initialization of the device instance.
- // Return true on success, false on error or if the particular implementation
- // is not available.
- bool Initialize();
-
- // Open device node for |path| as a device of |type|.
- bool OpenDevicePath(const std::string& path, Type type);
-
- // Close the currently open device.
- void CloseDevice();
-
- // Enumerate all V4L2 devices on the system for |type| and store the results
- // under devices_by_type_[type].
- void EnumerateDevicesForType(V4L2Device::Type type);
-
- // Return device information for all devices of |type| available in the
- // system. Enumerates and queries devices on first run and caches the results
- // for subsequent calls.
- const Devices& GetDevicesForType(V4L2Device::Type type);
-
- // Return device node path for device of |type| supporting |pixfmt|, or
- // an empty string if the given combination is not supported by the system.
- std::string GetDevicePathFor(V4L2Device::Type type, uint32_t pixfmt);
-
- // Callback that is called upon a queue's destruction, to cleanup its pointer
- // in queues_.
- void OnQueueDestroyed(v4l2_buf_type buf_type);
-
- // Lazily initialize static data after sandbox is enabled. Return false on
- // init failure.
- static bool PostSandboxInitialization();
-
- // Stores information for all devices available on the system
- // for each device Type.
- std::map<V4L2Device::Type, Devices> devices_by_type_;
-
- // The actual device fd.
- base::ScopedFD device_fd_;
-
- // eventfd fd to signal device poll thread when its poll() should be
- // interrupted.
- base::ScopedFD device_poll_interrupt_fd_;
-
- // Associates a v4l2_buf_type to its queue.
- base::flat_map<enum v4l2_buf_type, V4L2Queue*> queues_;
-
- // Used if EnablePolling() is called to signal the user that an event
- // happened or a buffer is ready to be dequeued.
- std::unique_ptr<V4L2DevicePoller> device_poller_;
-
- DISALLOW_COPY_AND_ASSIGN(V4L2Device);
-
- SEQUENCE_CHECKER(client_sequence_checker_);
+public:
+ // Utility format conversion functions
+ // If there is no corresponding single- or multi-planar format, returns 0.
+ static uint32_t videoCodecProfileToV4L2PixFmt(media::VideoCodecProfile profile,
+ bool sliceBased);
+ static media::VideoCodecProfile v4L2ProfileToVideoCodecProfile(media::VideoCodec codec,
+ uint32_t profile);
+ std::vector<media::VideoCodecProfile> v4L2PixFmtToVideoCodecProfiles(uint32_t pixFmt,
+ bool isEncoder);
+ // Calculates the largest plane's allocation size requested by a V4L2 device.
+ static media::Size allocatedSizeFromV4L2Format(const struct v4l2_format& format);
+
+ // Convert required H264 profile and level to V4L2 enums.
+ static int32_t videoCodecProfileToV4L2H264Profile(media::VideoCodecProfile profile);
+ static int32_t h264LevelIdcToV4L2H264Level(uint8_t levelIdc);
+
+ // Converts v4l2_memory to a string.
+ static const char* v4L2MemoryToString(const v4l2_memory memory);
+
+ // Returns the printable name of a v4l2_buf_type.
+ static const char* v4L2BufferTypeToString(const enum v4l2_buf_type bufType);
+
+ // Composes human readable string of v4l2_format.
+ static std::string v4L2FormatToString(const struct v4l2_format& format);
+
+ // Composes human readable string of v4l2_buffer.
+ static std::string v4L2BufferToString(const struct v4l2_buffer& buffer);
+
+ // Composes VideoFrameLayout based on v4l2_format.
+ // If error occurs, it returns base::nullopt.
+ static std::optional<media::VideoFrameLayout> v4L2FormatToVideoFrameLayout(
+ const struct v4l2_format& format);
+
+ // Returns number of planes of |pixFmt|.
+ static size_t getNumPlanesOfV4L2PixFmt(uint32_t pixFmt);
+
+ enum class Type { kDecoder, kEncoder };
+
+ // Create and initialize an appropriate V4L2Device instance for the current platform, or return
+ // nullptr if not available.
+ static scoped_refptr<V4L2Device> create();
+
+ // Open a V4L2 device of |type| for use with |v4l2PixFmt|. Return true on success. The device
+ // will be closed in the destructor.
+ bool open(Type type, uint32_t v4l2PixFmt);
+
+ // Returns the V4L2Queue corresponding to the requested |type|, or nullptr if the requested
+ // queue type is not supported.
+ scoped_refptr<V4L2Queue> getQueue(enum v4l2_buf_type type);
+
+ // Parameters and return value are the same as for the standard ioctl() system call.
+ int ioctl(int request, void* arg);
+
+ // This method sleeps until either:
+ // - SetDevicePollInterrupt() is called (on another thread),
+ // - |pollDevice| is true, and there is new data to be read from the device,
+ // or an event from the device has arrived; in the latter case
+ // |*eventPending| will be set to true.
+ // Returns false on error, true otherwise. This method should be called from a separate thread.
+ bool poll(bool pollDevice, bool* eventPending);
+
+ // These methods are used to interrupt the thread sleeping on poll() and force it to return
+ // regardless of device state, which is usually when the client is no longer interested in what
+ // happens with the device (on cleanup, client state change, etc.). When
+ // setDevicePollInterrupt() is called, poll() will return immediately, and any subsequent calls
+ // to it will also do so until clearDevicePollInterrupt() is called.
+ bool setDevicePollInterrupt();
+ bool clearDevicePollInterrupt();
+
+ // Wrappers for standard mmap/munmap system calls.
+ void* mmap(void* addr, unsigned int len, int prot, int flags, unsigned int offset);
+ void munmap(void* addr, unsigned int len);
+
+ // Return a vector of dmabuf file descriptors, exported for V4L2 buffer with |index|, assuming
+ // the buffer contains |numPlanes| V4L2 planes and is of |bufType|. Return an empty vector on
+ // failure. The caller is responsible for closing the file descriptors after use.
+ std::vector<base::ScopedFD> getDmabufsForV4L2Buffer(int index, size_t numPlanes,
+ enum v4l2_buf_type bufType);
+
+ // Returns the preferred V4L2 input formats for |type| or empty if none.
+ std::vector<uint32_t> preferredInputFormat(Type type);
+
+ // NOTE: The below methods to query capabilities have a side effect of closing the
+ // previously-open device, if any, and should not be called after Open().
+
+ // Get minimum and maximum resolution for fourcc |pixelFormat| and store to |minResolution| and
+ // |maxResolution|.
+ void getSupportedResolution(uint32_t pixelFormat, media::Size* minResolution,
+ media::Size* maxResolution);
+
+ std::vector<uint32_t> enumerateSupportedPixelformats(v4l2_buf_type bufType);
+
+ // Return supported profiles for decoder, including only profiles for given fourcc
+ // |pixelFormats|.
+ media::VideoDecodeAccelerator::SupportedProfiles getSupportedDecodeProfiles(
+ const size_t numFormats, const uint32_t pixelFormats[]);
+
+ // Return supported profiles for encoder.
+ media::VideoEncodeAccelerator::SupportedProfiles getSupportedEncodeProfiles();
+
+ // Start polling on this V4L2Device. |eventCallback| will be posted to the caller's sequence if
+ // a buffer is ready to be dequeued and/or a V4L2 event has been posted. |errorCallback| will
+ // be posted to the client's
+ // sequence if a polling error has occurred.
+ bool startPolling(android::V4L2DevicePoller::EventCallback eventCallback,
+ base::RepeatingClosure errorCallback);
+ // Stop polling this V4L2Device if polling was active. No new events will be posted after this
+ // method has returned.
+ bool stopPolling();
+ // Schedule a polling event if polling is enabled. This method is intended to be called from
+ // V4L2Queue, clients should not need to call it directly.
+ void schedulePoll();
+
+ // Check whether the V4L2 control with specified |ctrlId| is supported.
+ bool isCtrlExposed(uint32_t ctrlId);
+ // Set the specified list of |ctrls| for the specified |ctrlClass|, returns whether the
+ // operation succeeded.
+ bool setExtCtrls(uint32_t ctrlClass, std::vector<V4L2ExtCtrl> ctrls);
+
+ // Check whether the V4L2 command with specified |commandId| is supported.
+ bool isCommandSupported(uint32_t commandId);
+ // Check whether the V4L2 device has the specified |capabilities|.
+ bool hasCapabilities(uint32_t capabilities);
+
+private:
+ // Vector of video device node paths and corresponding pixelformats supported by each device node.
+ using Devices = std::vector<std::pair<std::string, std::vector<uint32_t>>>;
+
+ friend class base::RefCountedThreadSafe<V4L2Device>;
+ V4L2Device();
+ ~V4L2Device();
+
+ V4L2Device(const V4L2Device&) = delete;
+ V4L2Device& operator=(const V4L2Device&) = delete;
+
+ media::VideoDecodeAccelerator::SupportedProfiles enumerateSupportedDecodeProfiles(
+ const size_t numFormats, const uint32_t pixelFormats[]);
+
+ media::VideoEncodeAccelerator::SupportedProfiles enumerateSupportedEncodeProfiles();
+
+ // Open device node for |path| as a device of |type|.
+ bool openDevicePath(const std::string& path, Type type);
+
+ // Close the currently open device.
+ void closeDevice();
+
+ // Enumerate all V4L2 devices on the system for |type| and store the results under
+ // mDevicesByType[type].
+ void enumerateDevicesForType(V4L2Device::Type type);
+
+ // Return device information for all devices of |type| available in the system. Enumerates and
+ // queries devices on first run and caches the results for subsequent calls.
+ const Devices& getDevicesForType(V4L2Device::Type type);
+
+ // Return device node path for device of |type| supporting |pixFmt|, or an empty string if the
+ // given combination is not supported by the system.
+ std::string getDevicePathFor(V4L2Device::Type type, uint32_t pixFmt);
+
+ // Callback that is called upon a queue's destruction, to cleanup its pointer in mQueues.
+ void onQueueDestroyed(v4l2_buf_type buf_type);
+
+ // Stores information for all devices available on the system for each device Type.
+ std::map<V4L2Device::Type, Devices> mDevicesByType;
+
+ // The actual device fd.
+ base::ScopedFD mDeviceFd;
+
+ // eventfd fd to signal device poll thread when its poll() should be interrupted.
+ base::ScopedFD mDevicePollInterruptFd;
+
+ // Associates a v4l2_buf_type to its queue.
+ base::flat_map<enum v4l2_buf_type, V4L2Queue*> mQueues;
+
+ // Used if EnablePolling() is called to signal the user that an event happened or a buffer is
+ // ready to be dequeued.
+ std::unique_ptr<android::V4L2DevicePoller> mDevicePoller;
+
+ SEQUENCE_CHECKER(mClientSequenceChecker);
};
-} // namespace media
+} // namespace android
-#endif // V4L2_DEVICE_H_
+#endif // ANDROID_V4L2_CODEC2_COMMON_V4L2_DEVICE_H
diff --git a/common/include/v4l2_codec2/common/V4L2DevicePoller.h b/common/include/v4l2_codec2/common/V4L2DevicePoller.h
index aac3d8c..ad256be 100644
--- a/common/include/v4l2_codec2/common/V4L2DevicePoller.h
+++ b/common/include/v4l2_codec2/common/V4L2DevicePoller.h
@@ -3,95 +3,86 @@
// found in the LICENSE file.
// Note: ported from Chromium commit head: f65c38dcdac2
-#ifndef V4L2_V4L2_DEVICE_POLLER_H_
-#define V4L2_V4L2_DEVICE_POLLER_H_
+#ifndef ANDROID_V4L2_CODEC2_COMMON_V4L2_DEVICE_POLLER_H
+#define ANDROID_V4L2_CODEC2_COMMON_V4L2_DEVICE_POLLER_H
#include <atomic>
-#include "base/callback_forward.h"
-#include "base/sequence_checker.h"
-#include "base/sequenced_task_runner.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
+#include <base/callback_forward.h>
+#include <base/sequence_checker.h>
+#include <base/sequenced_task_runner.h>
+#include <base/synchronization/waitable_event.h>
+#include <base/threading/thread.h>
-namespace media {
+namespace android {
class V4L2Device;
-// Allows a client to poll() on a given V4L2Device and be signaled when
-// a buffer is ready to be dequeued or a V4L2 event has been received. Polling
-// is done on a dedicated thread, and notifications are delivered in the form of
-// a callback to the listener's sequence.
+// Allows a client to poll() on a given V4L2Device and be signaled when a buffer is ready to be
+// dequeued or a V4L2 event has been received. Polling is done on a dedicated thread, and
+// notifications are delivered in the form of a callback to the listener's sequence.
//
-// All the methods of this class (with the exception of the constructor) must be
-// called from the same sequence.
+// All the methods of this class (with the exception of the constructor) must be called from the
+// same sequence.
//
-// Note that the service callback may also be called when no particular event
-// occurred due to the way poll() works. It is the responsibility of the caller
-// to call SchedulePoll() again if there may still be pending events.
+// Note that the service callback may also be called when no particular event occurred due to the
+// way poll() works. It is the responsibility of the caller to call SchedulePoll() again if there
+// may still be pending events.
class V4L2DevicePoller {
- public:
- // Callback to be called when buffer ready/V4L2 event has potentially been
- // polled. |event| is set if a V4L2 event has been detected.
- using EventCallback = base::RepeatingCallback<void(bool event)>;
+public:
+ // Callback to be called when buffer ready/V4L2 event has potentially been polled. |event| is
+ // set if a V4L2 event has been detected.
+ using EventCallback = base::RepeatingCallback<void(bool event)>;
- // Create a poller for |device|, using a thread named |thread_name|.
- // Notification won't start until |StartPolling()| is called.
- V4L2DevicePoller(V4L2Device* const device, const std::string& thread_name);
- ~V4L2DevicePoller();
+ // Create a poller for |device|, using a thread named |threadName|. Notification won't start
+ // until |startPolling()| is called.
+ V4L2DevicePoller(V4L2Device* const device, const std::string& threadName);
+ ~V4L2DevicePoller();
- // Starts polling. |event_callback| will be posted on the caller's sequence
- // every time an event occurs. The client is then responsible for consuming
- // all pending events in that callback. If new events may still happen after
- // the callback has run, the client must call |SchedulePoll()| again in order
- // to be notified for them.
- //
- // If an error occurs during polling, |error_callback| will be posted on the
- // caller's sequence.
- bool StartPolling(EventCallback event_callback,
- base::RepeatingClosure error_callback);
- // Stop polling and stop the thread. The poller won't post any new event to
- // the caller's sequence after this method has returned.
- bool StopPolling();
- // Returns true if currently polling, false otherwise.
- bool IsPolling() const;
- // Attempts polling the V4L2 device. This method should be called whenever
- // doing something that may trigger an event of interest (buffer dequeue or
- // V4L2 event), for instance queueing a buffer. In the absence of a pending
- // event, poll() will return immediately and the service callback will be
- // posted to the caller's sequence. The client is then responsible for calling
- // this method again when it is interested in receiving events.
- void SchedulePoll();
+ // Starts polling. |mEventCallback| will be posted on the caller's sequence every time an event
+ // occurs. The client is then responsible for consuming all pending events in that callback. If
+ // new events may still happen after the callback has run, the client must call |schedulePoll()|
+ // again in order to be notified for them.
+ //
+ // If an error occurs during polling, |mErrorCallback| will be posted on the caller's sequence.
+ bool startPolling(EventCallback eventCallback, base::RepeatingClosure errorCallback);
+ // Stop polling and stop the thread. The poller won't post any new event to the caller's
+ // sequence after this method has returned.
+ bool stopPolling();
+ // Returns true if currently polling, false otherwise.
+ bool isPolling() const;
+ // Attempts polling the V4L2 device. This method should be called whenever doing something that
+ // may trigger an event of interest (buffer dequeue or V4L2 event), for instance queueing a
+ // buffer. In the absence of a pending event, poll() will return immediately and the service
+ // callback will be posted to the caller's sequence. The client is then responsible for calling
+ // this method again when it is interested in receiving events.
+ void schedulePoll();
- private:
- // Perform a poll() on |device_| and post either |service_task_| or
- // |error_callback_| on the client's sequence when poll() returns.
- void DevicePollTask();
+private:
+ // Perform a poll() on |mDevice| and post either |mEventCallback| or |mErrorCallback| on the
+ // client's sequence when poll() returns.
+ void devicePollTask();
- // V4L2 device we are polling.
- V4L2Device* const device_;
- // Thread on which polling is done.
- base::Thread poll_thread_;
- // Callback to post to the client's sequence when an event occurs.
- EventCallback event_callback_;
- // Closure to post to the client's sequence when an error occurs.
- base::RepeatingClosure error_callback_;
- // Client sequence's task runner, where closures are posted.
- scoped_refptr<base::SequencedTaskRunner> client_task_runner_;
+ // V4L2 device we are polling.
+ V4L2Device* const mDevice;
+ // Thread on which polling is done.
+ base::Thread mPollThread;
+ // Callback to post to the client's sequence when an event occurs.
+ EventCallback mEventCallback;
+ // Closure to post to the client's sequence when an error occurs.
+ base::RepeatingClosure mErrorCallback;
+ // Client sequence's task runner, where closures are posted.
+ scoped_refptr<base::SequencedTaskRunner> mClientTaskTunner;
- // Since poll() returns immediately if no buffers have been queued, we cannot
- // rely on it to pause the polling thread until an event occurs. Instead,
- // the polling thread will wait on this WaitableEvent (signaled by
- // |SchedulePoll| before calling poll(), so we only call it when we are
- // actually waiting for an event.
- base::WaitableEvent trigger_poll_;
- // Set to true when we wish to stop polling, instructing the poller thread
- // to break its loop.
- std::atomic_bool stop_polling_;
-
- SEQUENCE_CHECKER(client_sequence_checker_);
+ // Since poll() returns immediately if no buffers have been queued, we cannot rely on it to
+ // pause the polling thread until an event occurs. Instead,
+ // the polling thread will wait on this WaitableEvent (signaled by |schedulePoll| before calling
+ // poll(), so we only call it when we are actually waiting for an event.
+ base::WaitableEvent mTriggerPoll;
+ // Set to true when we wish to stop polling, instructing the poller thread to break its loop.
+ std::atomic_bool mStopPolling;
};
-} // namespace media
+} // namespace android
-#endif // V4L2_V4L2_DEVICE_POLLER_H_
+#endif // ANDROID_V4L2_CODEC2_COMMON_V4L2_DEVICE_POLLER_H