[libcamera-devel] [RFC 01/12] test: camera: buffer_import: Remove test
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Mon Nov 18 20:08:21 CET 2019
Hi Niklas,
On Mon, Oct 28, 2019 at 03:25:14AM +0100, Niklas Söderlund wrote:
> The buffer interface is about to be reworked to hide the specifics of
> buffer importing and its mapping to V4L2 devices from applications. In
> preparation of that remove the camera test which examines this.
>
> The proper operation of buffer importing on the V4L2 level is still
> tested in the V4L2 specific buffer sharing test case.
>
> Signed-off-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
While I'm sad to see 432 lines of test going away, I understand they're
in the way of the rework, so I'm OK with it. I however assume that the
non-RFC version of this series will have a new buffer import test (and
even more tests if possible :-)). On that basis,
Acked-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> ---
> test/camera/buffer_import.cpp | 432 ----------------------------------
> test/camera/meson.build | 1 -
> 2 files changed, 433 deletions(-)
> delete mode 100644 test/camera/buffer_import.cpp
>
> diff --git a/test/camera/buffer_import.cpp b/test/camera/buffer_import.cpp
> deleted file mode 100644
> index 9cac19d8ce81fa4d..0000000000000000
> --- a/test/camera/buffer_import.cpp
> +++ /dev/null
> @@ -1,432 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-or-later */
> -/*
> - * Copyright (C) 2019, Google Inc.
> - *
> - * libcamera Camera API tests
> - *
> - * Test importing buffers exported from the VIVID output device into a Camera
> - */
> -
> -#include <algorithm>
> -#include <iostream>
> -#include <numeric>
> -#include <random>
> -#include <vector>
> -
> -#include "device_enumerator.h"
> -#include "media_device.h"
> -#include "v4l2_videodevice.h"
> -
> -#include "camera_test.h"
> -
> -using namespace libcamera;
> -
> -/* Keep SINK_BUFFER_COUNT > CAMERA_BUFFER_COUNT + 1 */
> -static constexpr unsigned int SINK_BUFFER_COUNT = 8;
> -static constexpr unsigned int CAMERA_BUFFER_COUNT = 4;
> -
> -class FrameSink
> -{
> -public:
> - FrameSink()
> - : video_(nullptr)
> - {
> - }
> -
> - int init()
> - {
> - int ret;
> -
> - /* Locate and open the video device. */
> - std::string videoDeviceName = "vivid-000-vid-out";
> -
> - std::unique_ptr<DeviceEnumerator> enumerator =
> - DeviceEnumerator::create();
> - if (!enumerator) {
> - std::cout << "Failed to create device enumerator" << std::endl;
> - return TestFail;
> - }
> -
> - if (enumerator->enumerate()) {
> - std::cout << "Failed to enumerate media devices" << std::endl;
> - return TestFail;
> - }
> -
> - DeviceMatch dm("vivid");
> - dm.add(videoDeviceName);
> -
> - media_ = enumerator->search(dm);
> - if (!media_) {
> - std::cout << "No vivid output device available" << std::endl;
> - return TestSkip;
> - }
> -
> - video_ = V4L2VideoDevice::fromEntityName(media_.get(), videoDeviceName);
> - if (!video_) {
> - std::cout << "Unable to open " << videoDeviceName << std::endl;
> - return TestFail;
> - }
> -
> - if (video_->open())
> - return TestFail;
> -
> - /* Configure the format. */
> - ret = video_->getFormat(&format_);
> - if (ret) {
> - std::cout << "Failed to get format on output device" << std::endl;
> - return ret;
> - }
> -
> - format_.size.width = 1920;
> - format_.size.height = 1080;
> - format_.fourcc = V4L2_PIX_FMT_RGB24;
> - format_.planesCount = 1;
> - format_.planes[0].size = 1920 * 1080 * 3;
> - format_.planes[0].bpl = 1920 * 3;
> -
> - if (video_->setFormat(&format_)) {
> - cleanup();
> - return TestFail;
> - }
> -
> - /* Export the buffers to a pool. */
> - pool_.createBuffers(SINK_BUFFER_COUNT);
> - ret = video_->exportBuffers(&pool_);
> - if (ret) {
> - std::cout << "Failed to export buffers" << std::endl;
> - cleanup();
> - return TestFail;
> - }
> -
> - /* Only use the first CAMERA_BUFFER_COUNT buffers to start with. */
> - availableBuffers_.resize(CAMERA_BUFFER_COUNT);
> - std::iota(availableBuffers_.begin(), availableBuffers_.end(), 0);
> -
> - /* Connect the buffer ready signal. */
> - video_->bufferReady.connect(this, &FrameSink::bufferComplete);
> -
> - return TestPass;
> - }
> -
> - void cleanup()
> - {
> - if (video_) {
> - video_->streamOff();
> - video_->releaseBuffers();
> - video_->close();
> -
> - delete video_;
> - video_ = nullptr;
> - }
> -
> - if (media_)
> - media_->release();
> - }
> -
> - int start()
> - {
> - requestsCount_ = 0;
> - done_ = false;
> -
> - int ret = video_->streamOn();
> - if (ret < 0)
> - return ret;
> -
> - /* Queue all the initial requests. */
> - for (unsigned int index = 0; index < CAMERA_BUFFER_COUNT; ++index)
> - queueRequest(index);
> -
> - return 0;
> - }
> -
> - int stop()
> - {
> - return video_->streamOff();
> - }
> -
> - void requestComplete(uint64_t cookie, const Buffer *metadata)
> - {
> - unsigned int index = cookie;
> -
> - Buffer *buffer = new Buffer(index, metadata);
> - int ret = video_->queueBuffer(buffer);
> - if (ret < 0)
> - std::cout << "Failed to queue buffer to sink" << std::endl;
> - }
> -
> - bool done() const { return done_; }
> - const V4L2DeviceFormat &format() const { return format_; }
> -
> - Signal<uint64_t, int> requestReady;
> -
> -private:
> - void queueRequest(unsigned int index)
> - {
> - auto it = std::find(availableBuffers_.begin(),
> - availableBuffers_.end(), index);
> - availableBuffers_.erase(it);
> -
> - uint64_t cookie = index;
> - BufferMemory &mem = pool_.buffers()[index];
> - int dmabuf = mem.planes()[0].dmabuf();
> -
> - requestReady.emit(cookie, dmabuf);
> -
> - requestsCount_++;
> - }
> -
> - void bufferComplete(Buffer *buffer)
> - {
> - availableBuffers_.push_back(buffer->index());
> -
> - /*
> - * Pick the buffer for the next request among the available
> - * buffers.
> - *
> - * For the first 20 frames, select the buffer that has just
> - * completed to keep the mapping of dmabuf fds to buffers
> - * unchanged in the camera.
> - *
> - * For the next 20 frames, cycle randomly over the available
> - * buffers. The mapping should still be kept unchanged, as the
> - * camera should map using the cached fds.
> - *
> - * For the last 20 frames, cycles through all buffers, which
> - * should trash the mappings.
> - */
> - unsigned int index = buffer->index();
> - delete buffer;
> -
> - std::cout << "Completed buffer, request=" << requestsCount_
> - << ", available buffers=" << availableBuffers_.size()
> - << std::endl;
> -
> - if (requestsCount_ >= 60) {
> - if (availableBuffers_.size() == SINK_BUFFER_COUNT)
> - done_ = true;
> - return;
> - }
> -
> - if (requestsCount_ == 40) {
> - /* Add the remaining of the buffers. */
> - for (unsigned int i = CAMERA_BUFFER_COUNT;
> - i < SINK_BUFFER_COUNT; ++i)
> - availableBuffers_.push_back(i);
> - }
> -
> - if (requestsCount_ >= 20) {
> - /*
> - * Wait until we have enough buffers to make this
> - * meaningful. Preferably half of the camera buffers,
> - * but no less than 2 in any case.
> - */
> - const unsigned int min_pool_size =
> - std::min(CAMERA_BUFFER_COUNT / 2, 2U);
> - if (availableBuffers_.size() < min_pool_size)
> - return;
> -
> - /* Pick a buffer at random. */
> - unsigned int pos = random_() % availableBuffers_.size();
> - index = availableBuffers_[pos];
> - }
> -
> - queueRequest(index);
> - }
> -
> - std::shared_ptr<MediaDevice> media_;
> - V4L2VideoDevice *video_;
> - BufferPool pool_;
> - V4L2DeviceFormat format_;
> -
> - unsigned int requestsCount_;
> - std::vector<int> availableBuffers_;
> - std::random_device random_;
> -
> - bool done_;
> -};
> -
> -class BufferImportTest : public CameraTest
> -{
> -public:
> - BufferImportTest()
> - : CameraTest()
> - {
> - }
> -
> - void queueRequest(uint64_t cookie, int dmabuf)
> - {
> - Request *request = camera_->createRequest(cookie);
> -
> - std::unique_ptr<Buffer> buffer = stream_->createBuffer({ dmabuf, -1, -1 });
> - request->addBuffer(move(buffer));
> - camera_->queueRequest(request);
> - }
> -
> -protected:
> - void bufferComplete(Request *request, Buffer *buffer)
> - {
> - if (buffer->status() != Buffer::BufferSuccess)
> - return;
> -
> - unsigned int index = buffer->index();
> - int dmabuf = buffer->dmabufs()[0];
> -
> - /* Record dmabuf to index remappings. */
> - bool remapped = false;
> - if (bufferMappings_.find(index) != bufferMappings_.end()) {
> - if (bufferMappings_[index] != dmabuf)
> - remapped = true;
> - }
> -
> - std::cout << "Completed request " << framesCaptured_
> - << ": dmabuf fd " << dmabuf
> - << " -> index " << index
> - << " (" << (remapped ? 'R' : '-') << ")"
> - << std::endl;
> -
> - if (remapped)
> - bufferRemappings_.push_back(framesCaptured_);
> -
> - bufferMappings_[index] = dmabuf;
> - framesCaptured_++;
> -
> - sink_.requestComplete(request->cookie(), buffer);
> -
> - if (framesCaptured_ == 60)
> - sink_.stop();
> - }
> -
> - int initCamera()
> - {
> - if (camera_->acquire()) {
> - std::cout << "Failed to acquire the camera" << std::endl;
> - return TestFail;
> - }
> -
> - /*
> - * Configure the Stream to work with externally allocated
> - * buffers by setting the memoryType to ExternalMemory.
> - */
> - std::unique_ptr<CameraConfiguration> config;
> - config = camera_->generateConfiguration({ StreamRole::VideoRecording });
> - if (!config || config->size() != 1) {
> - std::cout << "Failed to generate configuration" << std::endl;
> - return TestFail;
> - }
> -
> - const V4L2DeviceFormat &format = sink_.format();
> -
> - StreamConfiguration &cfg = config->at(0);
> - cfg.size = format.size;
> - cfg.pixelFormat = format.fourcc;
> - cfg.bufferCount = CAMERA_BUFFER_COUNT;
> - cfg.memoryType = ExternalMemory;
> -
> - if (camera_->configure(config.get())) {
> - std::cout << "Failed to set configuration" << std::endl;
> - return TestFail;
> - }
> -
> - stream_ = cfg.stream();
> -
> - /* Allocate buffers. */
> - if (camera_->allocateBuffers()) {
> - std::cout << "Failed to allocate buffers" << std::endl;
> - return TestFail;
> - }
> -
> - /* Connect the buffer completed signal. */
> - camera_->bufferCompleted.connect(this, &BufferImportTest::bufferComplete);
> -
> - return TestPass;
> - }
> -
> - int init()
> - {
> - int ret = CameraTest::init();
> - if (ret)
> - return ret;
> -
> - ret = sink_.init();
> - if (ret != TestPass) {
> - cleanup();
> - return ret;
> - }
> -
> - ret = initCamera();
> - if (ret != TestPass) {
> - cleanup();
> - return ret;
> - }
> -
> - sink_.requestReady.connect(this, &BufferImportTest::queueRequest);
> - return TestPass;
> - }
> -
> - int run()
> - {
> - int ret;
> -
> - framesCaptured_ = 0;
> -
> - if (camera_->start()) {
> - std::cout << "Failed to start camera" << std::endl;
> - return TestFail;
> - }
> -
> - ret = sink_.start();
> - if (ret < 0) {
> - std::cout << "Failed to start sink" << std::endl;
> - return TestFail;
> - }
> -
> - EventDispatcher *dispatcher = cm_->eventDispatcher();
> -
> - Timer timer;
> - timer.start(5000);
> - while (timer.isRunning() && !sink_.done())
> - dispatcher->processEvents();
> -
> - std::cout << framesCaptured_ << " frames captured, "
> - << bufferRemappings_.size() << " buffers remapped"
> - << std::endl;
> -
> - if (framesCaptured_ < 60) {
> - std::cout << "Too few frames captured" << std::endl;
> - return TestFail;
> - }
> -
> - if (bufferRemappings_.empty()) {
> - std::cout << "No buffer remappings" << std::endl;
> - return TestFail;
> - }
> -
> - if (bufferRemappings_[0] < 40) {
> - std::cout << "Early buffer remapping" << std::endl;
> - return TestFail;
> - }
> -
> - return TestPass;
> - }
> -
> - void cleanup()
> - {
> - sink_.cleanup();
> -
> - camera_->stop();
> - camera_->freeBuffers();
> -
> - CameraTest::cleanup();
> - }
> -
> -private:
> - Stream *stream_;
> -
> - std::map<unsigned int, int> bufferMappings_;
> - std::vector<unsigned int> bufferRemappings_;
> - unsigned int framesCaptured_;
> -
> - FrameSink sink_;
> -};
> -
> -TEST_REGISTER(BufferImportTest);
> diff --git a/test/camera/meson.build b/test/camera/meson.build
> index d6fd66b8f89e21b4..35e97ce5de1a72ca 100644
> --- a/test/camera/meson.build
> +++ b/test/camera/meson.build
> @@ -3,7 +3,6 @@
> camera_tests = [
> [ 'configuration_default', 'configuration_default.cpp' ],
> [ 'configuration_set', 'configuration_set.cpp' ],
> - [ 'buffer_import', 'buffer_import.cpp' ],
> [ 'statemachine', 'statemachine.cpp' ],
> [ 'capture', 'capture.cpp' ],
> ]
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list