summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2019-08-18 03:49:58 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2019-08-19 19:08:08 +0300
commit82bdcc91fc3626f9caa5225f932b8efad7a575d3 (patch)
treebe7161b4311c860130d115484b1986cac0929b25 /src
parent53704ac3f406a776cfe636c45fd7fdd305962788 (diff)
android: camera_device: Store static metadata in cache
The CameraDevice class has a mechanism to cache static metadata, but doesn't use it. Fix it. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
Diffstat (limited to 'src')
-rw-r--r--src/android/camera_device.cpp42
1 files changed, 21 insertions, 21 deletions
diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index 9acfed69..c27175ac 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -131,14 +131,14 @@ camera_metadata_t *CameraDevice::getStaticMetadata()
/* \todo Use correct sizes */
#define STATIC_ENTRY_CAP 256
#define STATIC_DATA_CAP 6688
- camera_metadata_t *staticMetadata =
- allocate_camera_metadata(STATIC_ENTRY_CAP, STATIC_DATA_CAP);
+ staticMetadata_ = allocate_camera_metadata(STATIC_ENTRY_CAP,
+ STATIC_DATA_CAP);
/* Sensor static metadata. */
int32_t pixelArraySize[] = {
2592, 1944,
};
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
&pixelArraySize, 2);
METADATA_ASSERT(ret);
@@ -146,7 +146,7 @@ camera_metadata_t *CameraDevice::getStaticMetadata()
int32_t sensorSizes[] = {
0, 0, 2560, 1920,
};
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
&sensorSizes, 4);
METADATA_ASSERT(ret);
@@ -154,13 +154,13 @@ camera_metadata_t *CameraDevice::getStaticMetadata()
int32_t sensitivityRange[] = {
32, 2400,
};
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
&sensitivityRange, 2);
METADATA_ASSERT(ret);
uint16_t filterArr = ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG;
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
&filterArr, 1);
METADATA_ASSERT(ret);
@@ -168,33 +168,33 @@ camera_metadata_t *CameraDevice::getStaticMetadata()
int64_t exposureTimeRange[] = {
100000, 200000000,
};
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
&exposureTimeRange, 2);
METADATA_ASSERT(ret);
int32_t orientation = 0;
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_SENSOR_ORIENTATION,
&orientation, 1);
METADATA_ASSERT(ret);
/* Flash static metadata. */
char flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_FLASH_INFO_AVAILABLE,
&flashAvailable, 1);
METADATA_ASSERT(ret);
/* Lens static metadata. */
float fn = 2.53 / 100;
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_LENS_INFO_AVAILABLE_APERTURES, &fn, 1);
METADATA_ASSERT(ret);
/* Control metadata. */
char controlMetadata = ANDROID_CONTROL_MODE_AUTO;
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_CONTROL_AVAILABLE_MODES,
&controlMetadata, 1);
METADATA_ASSERT(ret);
@@ -205,7 +205,7 @@ camera_metadata_t *CameraDevice::getStaticMetadata()
ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,
ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,
};
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
availableAntiBandingModes, 4);
METADATA_ASSERT(ret);
@@ -214,19 +214,19 @@ camera_metadata_t *CameraDevice::getStaticMetadata()
ANDROID_CONTROL_AE_MODE_ON,
ANDROID_CONTROL_AE_MODE_OFF,
};
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_CONTROL_AE_AVAILABLE_MODES,
aeAvailableModes, 2);
METADATA_ASSERT(ret);
controlMetadata = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_CONTROL_AE_LOCK_AVAILABLE,
&controlMetadata, 1);
METADATA_ASSERT(ret);
uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
&awbLockAvailable, 1);
@@ -236,7 +236,7 @@ camera_metadata_t *CameraDevice::getStaticMetadata()
ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
};
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_SCALER_AVAILABLE_FORMATS,
availableStreamFormats.data(),
availableStreamFormats.size());
@@ -250,7 +250,7 @@ camera_metadata_t *CameraDevice::getStaticMetadata()
ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED, 2560, 1920,
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
};
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
availableStreamConfigurations.data(),
availableStreamConfigurations.size());
@@ -259,7 +259,7 @@ camera_metadata_t *CameraDevice::getStaticMetadata()
std::vector<int64_t> availableStallDurations = {
ANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,
};
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
availableStallDurations.data(),
availableStallDurations.size());
@@ -270,18 +270,18 @@ camera_metadata_t *CameraDevice::getStaticMetadata()
ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED, 2560, 1920, 33333333,
ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888, 2560, 1920, 33333333,
};
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
minFrameDurations.data(), minFrameDurations.size());
METADATA_ASSERT(ret);
/* Info static metadata. */
uint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
- ret = add_camera_metadata_entry(staticMetadata,
+ ret = add_camera_metadata_entry(staticMetadata_,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
&supportedHWLevel, 1);
- return staticMetadata;
+ return staticMetadata_;
}
/*
> 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * unixsocket.cpp - Unix socket IPC test
 */

#include <algorithm>
#include <fcntl.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <libcamera/event_dispatcher.h>
#include <libcamera/timer.h>

#include "libcamera/internal/ipc_unixsocket.h"
#include "libcamera/internal/thread.h"
#include "libcamera/internal/utils.h"

#include "test.h"

#define CMD_CLOSE	0
#define CMD_REVERSE	1
#define CMD_LEN_CALC	2
#define CMD_LEN_CMP	3
#define CMD_JOIN	4

using namespace std;
using namespace libcamera;

int calculateLength(int fd)
{
	lseek(fd, 0, 0);
	int size = lseek(fd, 0, SEEK_END);
	lseek(fd, 0, 0);

	return size;
}

class UnixSocketTestSlave
{
public:
	UnixSocketTestSlave()
		: exitCode_(EXIT_FAILURE), exit_(false)
	{
		dispatcher_ = Thread::current()->eventDispatcher();
		ipc_.readyRead.connect(this, &UnixSocketTestSlave::readyRead);
	}

	int run(int fd)
	{
		if (ipc_.bind(fd)) {
			cerr << "Failed to connect to IPC channel" << endl;
			return EXIT_FAILURE;
		}

		while (!exit_)
			dispatcher_->processEvents();

		ipc_.close();

		return exitCode_;
	}

private:
	void readyRead(IPCUnixSocket *ipc)
	{
		IPCUnixSocket::Payload message, response;
		int ret;

		ret = ipc->receive(&message);
		if (ret) {
			cerr << "Receive message failed: " << ret << endl;
			return;
		}

		const uint8_t cmd = message.data[0];

		switch (cmd) {
		case CMD_CLOSE:
			stop(0);
			break;

		case CMD_REVERSE: {
			response.data = message.data;
			std::reverse(response.data.begin() + 1, response.data.end());

			ret = ipc_.send(response);
			if (ret < 0) {
				cerr << "Reverse failed" << endl;
				stop(ret);
			}
			break;
		}

		case CMD_LEN_CALC: {
			int size = 0;
			for (int fd : message.fds)
				size += calculateLength(fd);

			response.data.resize(1 + sizeof(size));
			response.data[0] = cmd;
			memcpy(response.data.data() + 1, &size, sizeof(size));

			ret = ipc_.send(response);
			if (ret < 0) {
				cerr << "Calc failed" << endl;
				stop(ret);
			}
			break;
		}

		case CMD_LEN_CMP: {
			int size = 0;
			for (int fd : message.fds)
				size += calculateLength(fd);

			int cmp;
			memcpy(&cmp, message.data.data() + 1, sizeof(cmp));

			if (cmp != size) {
				cerr << "Compare failed" << endl;
				stop(-ERANGE);
			}
			break;
		}

		case CMD_JOIN: {
			int outfd = open("/tmp", O_TMPFILE | O_RDWR,
					 S_IRUSR | S_IWUSR);
			if (outfd < 0) {
				cerr << "Create out file failed" << endl;
				stop(outfd);
				return;
			}

			for (int fd : message.fds) {
				while (true) {
					char buf[32];
					ssize_t num = read(fd, &buf, sizeof(buf));

					if (num < 0) {
						cerr << "Read failed" << endl;
						close(outfd);
						stop(-EIO);
						return;
					} else if (!num)
						break;

					if (write(outfd, buf, num) < 0) {
						cerr << "Write failed" << endl;
						close(outfd);
						stop(-EIO);
						return;
					}
				}

				close(fd);
			}

			lseek(outfd, 0, 0);
			response.data.push_back(CMD_JOIN);
			response.fds.push_back(outfd);

			ret = ipc_.send(response);
			if (ret < 0) {
				cerr << "Join failed" << endl;
				stop(ret);
			}

			close(outfd);

			break;
		}

		default:
			cerr << "Unknown command " << cmd << endl;
			stop(-EINVAL);
			break;
		}
	}

	void stop(int code)
	{
		exitCode_ = code;
		exit_ = true;
	}

	IPCUnixSocket ipc_;
	EventDispatcher *dispatcher_;
	int exitCode_;
	bool exit_;
};

class UnixSocketTest : public Test
{
protected:
	int slaveStart(int fd)
	{
		pid_ = fork();

		if (pid_ == -1)
			return TestFail;

		if (!pid_) {
			std::string arg = std::to_string(fd);
			execl("/proc/self/exe", "/proc/self/exe",
			      arg.c_str(), nullptr);

			/* Only get here if exec fails. */
			exit(TestFail);
		}

		return TestPass;
	}

	int slaveStop()
	{
		int status;

		if (pid_ < 0)
			return TestFail;

		if (waitpid(pid_, &status, 0) < 0)
			return TestFail;

		if (!WIFEXITED(status) || WEXITSTATUS(status))
			return TestFail;

		return TestPass;
	}

	int testReverse()
	{
		IPCUnixSocket::Payload message, response;
		int ret;

		message.data = { CMD_REVERSE, 1, 2, 3, 4, 5 };

		ret = call(message, &response);
		if (ret)
			return ret;

		std::reverse(response.data.begin() + 1, response.data.end());
		if (message.data != response.data)
			return TestFail;

		return 0;
	}

	int testEmptyFail()
	{
		IPCUnixSocket::Payload message;

		return ipc_.send(message) != -EINVAL;
	}

	int testCalc()
	{
		IPCUnixSocket::Payload message, response;
		int sizeOut, sizeIn, ret;

		sizeOut = prepareFDs(&message, 2);
		if (sizeOut < 0)
			return sizeOut;

		message.data.push_back(CMD_LEN_CALC);

		ret = call(message, &response);
		if (ret)
			return ret;

		memcpy(&sizeIn, response.data.data() + 1, sizeof(sizeIn));
		if (sizeOut != sizeIn)
			return TestFail;

		return 0;
	}

	int testCmp()
	{
		IPCUnixSocket::Payload message;
		int size;

		size = prepareFDs(&message, 7);
		if (size < 0)
			return size;

		message.data.resize(1 + sizeof(size));
		message.data[0] = CMD_LEN_CMP;
		memcpy(message.data.data() + 1, &size, sizeof(size));

		if (ipc_.send(message))
			return TestFail;

		return 0;
	}

	int testFdOrder()
	{
		IPCUnixSocket::Payload message, response;
		int ret;

		static const char *strings[2] = {
			"Foo",
			"Bar",
		};
		int fds[2];

		for (unsigned int i = 0; i < ARRAY_SIZE(strings); i++) {
			unsigned int len = strlen(strings[i]);

			fds[i] = open("/tmp", O_TMPFILE | O_RDWR,
				      S_IRUSR | S_IWUSR);
			if (fds[i] < 0)
				return TestFail;

			ret = write(fds[i], strings[i], len);
			if (ret < 0)
				return TestFail;

			lseek(fds[i], 0, 0);
			message.fds.push_back(fds[i]);
		}

		message.data.push_back(CMD_JOIN);

		ret = call(message, &response);
		if (ret)
			return ret;

		for (unsigned int i = 0; i < ARRAY_SIZE(strings); i++) {
			unsigned int len = strlen(strings[i]);
			char buf[len];

			close(fds[i]);

			if (read(response.fds[0], &buf, len) <= 0)
				return TestFail;

			if (memcmp(buf, strings[i], len))
				return TestFail;
		}

		close(response.fds[0]);

		return 0;
	}

	int init()
	{
		callResponse_ = nullptr;
		return 0;
	}

	int run()
	{
		int slavefd = ipc_.create();
		if (slavefd < 0)
			return TestFail;

		if (slaveStart(slavefd)) {
			cerr << "Failed to start slave" << endl;
			return TestFail;
		}

		ipc_.readyRead.connect(this, &UnixSocketTest::readyRead);

		/* Test reversing a string, this test sending only data. */
		if (testReverse()) {
			cerr << "Reverse array test failed" << endl;
			return TestFail;
		}

		/* Test that an empty message fails. */
		if (testEmptyFail()) {
			cerr << "Empty message test failed" << endl;
			return TestFail;
		}

		/* Test offloading a calculation, this test sending only FDs. */
		if (testCalc()) {
			cerr << "Calc test failed" << endl;
			return TestFail;
		}

		/* Test fire and forget, this tests sending data and FDs. */
		if (testCmp()) {
			cerr << "Cmp test failed" << endl;
			return TestFail;
		}

		/* Test order of file descriptors. */
		if (testFdOrder()) {
			cerr << "fd order test failed" << endl;
			return TestFail;
		}

		/* Close slave connection. */
		IPCUnixSocket::Payload close;
		close.data.push_back(CMD_CLOSE);
		if (ipc_.send(close)) {
			cerr << "Closing IPC channel failed" << endl;
			return TestFail;
		}

		ipc_.close();
		if (slaveStop()) {
			cerr << "Failed to stop slave" << endl;
			return TestFail;
		}

		return TestPass;
	}

private:
	int call(const IPCUnixSocket::Payload &message, IPCUnixSocket::Payload *response)
	{
		Timer timeout;
		int ret;

		callDone_ = false;
		callResponse_ = response;

		ret = ipc_.send(message);
		if (ret)
			return ret;

		timeout.start(200);
		while (!callDone_) {
			if (!timeout.isRunning()) {
				cerr << "Call timeout!" << endl;
				callResponse_ = nullptr;
				return -ETIMEDOUT;
			}

			Thread::current()->eventDispatcher()->processEvents();
		}

		callResponse_ = nullptr;

		return 0;
	}

	void readyRead(IPCUnixSocket *ipc)
	{
		if (!callResponse_) {
			cerr << "Read ready without expecting data, fail." << endl;
			return;
		}

		if (ipc->receive(callResponse_)) {
			cerr << "Receive message failed" << endl;
			return;
		}

		callDone_ = true;
	}

	int prepareFDs(IPCUnixSocket::Payload *message, unsigned int num)
	{
		int fd = open("/proc/self/exe", O_RDONLY);
		if (fd < 0)
			return fd;

		int size = 0;
		for (unsigned int i = 0; i < num; i++) {
			int clone = dup(fd);
			if (clone < 0)
				return clone;

			size += calculateLength(clone);
			message->fds.push_back(clone);
		}

		close(fd);

		return size;
	}

	pid_t pid_;
	IPCUnixSocket ipc_;
	bool callDone_;
	IPCUnixSocket::Payload *callResponse_;
};

/*
 * Can't use TEST_REGISTER() as single binary needs to act as both proxy
 * master and slave.
 */
int main(int argc, char **argv)
{
	if (argc == 2) {
		int ipcfd = std::stoi(argv[1]);
		UnixSocketTestSlave slave;
		return slave.run(ipcfd);
	}

	return UnixSocketTest().execute();
}