summaryrefslogtreecommitdiff
path: root/src/cam/image.h
blob: 7953b1776782207a2c77ece7e152076add93d8e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2021, Ideas on Board Oy
 *
 * image.h - Multi-planar image with access to pixel data
 */

#pragma once

#include <memory>
#include <stdint.h>
#include <vector>

#include <libcamera/base/class.h>
#include <libcamera/base/flags.h>
#include <libcamera/base/span.h>

#include <libcamera/framebuffer.h>

class Image
{
public:
	enum class MapMode {
		ReadOnly = 1 << 0,
		WriteOnly = 1 << 1,
		ReadWrite = ReadOnly | WriteOnly,
	};

	static std::unique_ptr<Image> fromFrameBuffer(const libcamera::FrameBuffer *buffer,
						      MapMode mode);

	~Image();

	unsigned int numPlanes() const;

	libcamera::Span<uint8_t> data(unsigned int plane);
	libcamera::Span<const uint8_t> data(unsigned int plane) const;

private:
	LIBCAMERA_DISABLE_COPY(Image)

	Image();

	std::vector<libcamera::Span<uint8_t>> maps_;
	std::vector<libcamera::Span<uint8_t>> planes_;
};

namespace libcamera {
LIBCAMERA_FLAGS_ENABLE_OPERATORS(Image::MapMode)
}
enum Status { NoMessage, MessageReceived, }; InstrumentedObject(Object *parent = nullptr) : Object(parent), status_(NoMessage) { } Status status() const { return status_; } void reset() { status_ = NoMessage; } protected: void message(Message *msg) override { if (msg->type() == Message::ThreadMoveMessage) status_ = MessageReceived; Object::message(msg); } private: Status status_; }; class ObjectTest : public Test { protected: int init() { /* * Create a hierarchy of objects: * A -> B -> C * \->D * E */ a_ = new InstrumentedObject(); b_ = new InstrumentedObject(a_); c_ = new InstrumentedObject(b_); d_ = new InstrumentedObject(a_); e_ = new InstrumentedObject(); f_ = nullptr; return TestPass; } int run() { /* Verify the parent-child relationships. */ if (a_->parent() != nullptr || b_->parent() != a_ || c_->parent() != b_ || d_->parent() != a_ || e_->parent() != nullptr) { cout << "Incorrect parent-child relationships" << endl; return TestFail; } /* * Verify that moving an object with no parent to a different * thread succeeds. */ e_->moveToThread(&thread_); if (e_->thread() != &thread_ || e_->thread() == Thread::current()) { cout << "Failed to move object to thread" << endl; return TestFail; } /* * Verify that moving an object with a parent to a different * thread fails. This results in an undefined behaviour, the * test thus depends on the internal implementation returning * without performing any change. */ b_->moveToThread(&thread_); if (b_->thread() != Thread::current()) { cout << "Moving object with parent to thread shouldn't succeed" << endl; return TestFail; } /* * Verify that moving an object with children to a different * thread moves all the children. */ a_->moveToThread(&thread_); if (a_->thread() != &thread_ || b_->thread() != &thread_ || c_->thread() != &thread_ || d_->thread() != &thread_) { cout << "Failed to move children to thread" << endl; return TestFail; } /* Verify that objects are bound to the thread of their parent. */ f_ = new InstrumentedObject(d_); if (f_->thread() != &thread_) { cout << "Failed to bind child to parent thread" << endl; return TestFail; } /* Verify that objects receive a ThreadMoveMessage when moved. */ if (a_->status() != InstrumentedObject::MessageReceived || b_->status() != InstrumentedObject::MessageReceived || c_->status() != InstrumentedObject::MessageReceived || d_->status() != InstrumentedObject::MessageReceived || e_->status() != InstrumentedObject::MessageReceived) { cout << "Moving object didn't deliver ThreadMoveMessage" << endl; return TestFail; } return TestPass; } void cleanup() { delete a_; delete b_; delete c_; delete d_; delete e_; delete f_; } private: InstrumentedObject *a_; InstrumentedObject *b_; InstrumentedObject *c_; InstrumentedObject *d_; InstrumentedObject *e_; InstrumentedObject *f_; Thread thread_; }; TEST_REGISTER(ObjectTest)