summaryrefslogtreecommitdiff
path: root/utils/raspberrypi/ctt/ctt_ref.pgm
AgeCommit message (Expand)Author
2020-05-11libcamera: utils: Raspberry Pi Camera Tuning ToolNaushir Patuck
='#n18'>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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2021, Google Inc.
 *
 * post_processor_yuv.cpp - Post Processor using libyuv
 */

#include "post_processor_yuv.h"

#include <libyuv/scale.h>

#include <libcamera/base/log.h>

#include <libcamera/formats.h>
#include <libcamera/geometry.h>
#include <libcamera/pixel_format.h>

#include "libcamera/internal/formats.h"
#include "libcamera/internal/mapped_framebuffer.h"

using namespace libcamera;

LOG_DEFINE_CATEGORY(YUV)

int PostProcessorYuv::configure(const StreamConfiguration &inCfg,
				const StreamConfiguration &outCfg)
{
	if (inCfg.pixelFormat != outCfg.pixelFormat) {
		LOG(YUV, Error) << "Pixel format conversion is not supported"
				<< " (from " << inCfg.pixelFormat.toString()
				<< " to " << outCfg.pixelFormat.toString() << ")";
		return -EINVAL;
	}

	if (inCfg.size < outCfg.size) {
		LOG(YUV, Error) << "Up-scaling is not supported"
				<< " (from " << inCfg.size.toString()
				<< " to " << outCfg.size.toString() << ")";
		return -EINVAL;
	}

	if (inCfg.pixelFormat != formats::NV12) {
		LOG(YUV, Error) << "Unsupported format " << inCfg.pixelFormat
				<< " (only NV12 is supported)";
		return -EINVAL;
	}

	calculateLengths(inCfg, outCfg);
	return 0;
}

int PostProcessorYuv::process(const FrameBuffer &source,
			      CameraBuffer *destination,
			      [[maybe_unused]] Camera3RequestDescriptor *request)
{
	if (!isValidBuffers(source, *destination))
		return -EINVAL;

	const MappedFrameBuffer sourceMapped(&source, MappedFrameBuffer::MapFlag::Read);
	if (!sourceMapped.isValid()) {
		LOG(YUV, Error) << "Failed to mmap camera frame buffer";
		return -EINVAL;
	}

	int ret = libyuv::NV12Scale(sourceMapped.planes()[0].data(),
				    sourceStride_[0],
				    sourceMapped.planes()[1].data(),
				    sourceStride_[1],
				    sourceSize_.width, sourceSize_.height,
				    destination->plane(0).data(),
				    destinationStride_[0],
				    destination->plane(1).data(),
				    destinationStride_[1],
				    destinationSize_.width,
				    destinationSize_.height,
				    libyuv::FilterMode::kFilterBilinear);
	if (ret) {
		LOG(YUV, Error) << "Failed NV12 scaling: " << ret;
		return -EINVAL;
	}

	return 0;
}

bool PostProcessorYuv::isValidBuffers(const FrameBuffer &source,
				      const CameraBuffer &destination) const
{
	if (source.planes().size() != 2) {
		LOG(YUV, Error) << "Invalid number of source planes: "
				<< source.planes().size();
		return false;
	}
	if (destination.numPlanes() != 2) {
		LOG(YUV, Error) << "Invalid number of destination planes: "
				<< destination.numPlanes();
		return false;
	}

	if (source.planes()[0].length < sourceLength_[0] ||
	    source.planes()[1].length < sourceLength_[1]) {
		LOG(YUV, Error)
			<< "The source planes lengths are too small, actual size: {"
			<< source.planes()[0].length << ", "
			<< source.planes()[1].length
			<< "}, expected size: {"
			<< sourceLength_[0] << ", "
			<< sourceLength_[1] << "}";
		return false;
	}
	if (destination.plane(0).size() < destinationLength_[0] ||
	    destination.plane(1).size() < destinationLength_[1]) {
		LOG(YUV, Error)
			<< "The destination planes lengths are too small, actual size: {"
			<< destination.plane(0).size() << ", "
			<< destination.plane(1).size()
			<< "}, expected size: {"
			<< sourceLength_[0] << ", "
			<< sourceLength_[1] << "}";
		return false;
	}

	return true;
}

void PostProcessorYuv::calculateLengths(const StreamConfiguration &inCfg,
					const StreamConfiguration &outCfg)
{
	sourceSize_ = inCfg.size;
	destinationSize_ = outCfg.size;

	const PixelFormatInfo &nv12Info = PixelFormatInfo::info(formats::NV12);
	for (unsigned int i = 0; i < 2; i++) {
		sourceStride_[i] = inCfg.stride;
		destinationStride_[i] = nv12Info.stride(destinationSize_.width, i, 1);

		sourceLength_[i] = nv12Info.planeSize(sourceSize_.height, i,
						      sourceStride_[i]);
		destinationLength_[i] = nv12Info.planeSize(destinationSize_.height, i,
							   destinationStride_[i]);
	}
}