@@ -9,6 +9,7 @@
#include <libcamera/framebuffer.h>
#include <libcamera/geometry.h>
+#include <libcamera/stream.h>
namespace libcamera {
@@ -19,7 +20,7 @@ public:
virtual void configure(const Size &size) = 0;
- virtual int generateFrame(const Size &size,
+ virtual int generateFrame(const StreamConfiguration &cfg,
const FrameBuffer *buffer) = 0;
protected:
@@ -12,9 +12,11 @@
#include <libcamera/base/file.h>
#include <libcamera/base/log.h>
+#include <libcamera/formats.h>
#include <libcamera/framebuffer.h>
#include "libcamera/internal/dma_buf_allocator.h"
+#include "libcamera/internal/formats.h"
#include "libcamera/internal/mapped_framebuffer.h"
#include "libyuv/convert.h"
@@ -124,7 +126,7 @@ void ImageFrameGenerator::configure(const Size &size)
}
}
-int ImageFrameGenerator::generateFrame(const Size &size, const FrameBuffer *buffer)
+int ImageFrameGenerator::generateFrame(const StreamConfiguration &cfg, const FrameBuffer *buffer)
{
ASSERT(!scaledFrameDatas_.empty());
@@ -141,16 +143,55 @@ int ImageFrameGenerator::generateFrame(const Size &size, const FrameBuffer *buff
MappedFrameBuffer::MapFlag::Write);
const auto &planes = mappedFrameBuffer.planes();
+ auto size = cfg.size;
+ const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
/* Loop only around the number of images available */
frameIndex_ %= imageFrameDatas_.size();
/* Write the scaledY and scaledUV to the mapped frame buffer */
- libyuv::NV12Copy(scaledFrameDatas_[frameIndex_].Y.get(), size.width,
- scaledFrameDatas_[frameIndex_].UV.get(), size.width,
- planes[0].data(), size.width,
- planes[1].data(), size.width,
- size.width, size.height);
+ int ret;
+ switch (cfg.pixelFormat) {
+ case formats::NV12:
+ ret = libyuv::NV12Copy(scaledFrameDatas_[frameIndex_].Y.get(),
+ size.width,
+ scaledFrameDatas_[frameIndex_].UV.get(),
+ size.width,
+ planes[0].data(),
+ info.stride(size.width, 0),
+ planes[1].data(),
+ info.stride(size.width, 1),
+ size.width, size.height);
+ break;
+ case formats::YUV420:
+ ret = libyuv::NV12ToI420(scaledFrameDatas_[frameIndex_].Y.get(),
+ size.width,
+ scaledFrameDatas_[frameIndex_].UV.get(),
+ size.width,
+ planes[0].data(),
+ info.stride(size.width, 0),
+ planes[1].data(),
+ info.stride(size.width, 1),
+ planes[2].data(),
+ info.stride(size.width, 2),
+ size.width, size.height);
+ break;
+ case formats::ABGR8888:
+ case formats::XBGR8888:
+ ret = libyuv::NV12ToABGR(scaledFrameDatas_[frameIndex_].Y.get(),
+ size.width,
+ scaledFrameDatas_[frameIndex_].UV.get(),
+ size.width,
+ planes[0].data(),
+ info.stride(size.width, 0),
+ size.width, size.height);
+ break;
+ default:
+ LOG(Virtual, Error) << "Unsupported format";
+ return -1;
+ }
+ if (ret != 0)
+ LOG(Virtual, Error) << "Conversation failed with " << ret;
/* Proceed to the next image every 4 frames */
/* \todo Consider setting the frameRepeat in the config file */
@@ -158,7 +199,7 @@ int ImageFrameGenerator::generateFrame(const Size &size, const FrameBuffer *buff
if (parameter_ % frameRepeat == 0)
frameIndex_++;
- return 0;
+ return ret;
}
/*
@@ -37,7 +37,7 @@ private:
};
void configure(const Size &size) override;
- int generateFrame(const Size &size, const FrameBuffer *buffer) override;
+ int generateFrame(const StreamConfiguration &cfg, const FrameBuffer *buffer) override;
std::vector<ImageFrameData> imageFrameDatas_;
std::vector<ImageFrameData> scaledFrameDatas_;
@@ -11,7 +11,9 @@
#include <libcamera/base/log.h>
+#include <libcamera/formats.h>
#include "libcamera/internal/dma_buf_allocator.h"
+#include "libcamera/internal/formats.h"
#include "libcamera/internal/mapped_framebuffer.h"
#include <libyuv/convert_from_argb.h>
@@ -42,7 +44,7 @@ LOG_DECLARE_CATEGORY(Virtual)
static const unsigned int kARGBSize = 4;
-int TestPatternGenerator::generateFrame(const Size &size,
+int TestPatternGenerator::generateFrame(const StreamConfiguration &cfg,
const FrameBuffer *buffer)
{
/*
@@ -58,16 +60,48 @@ int TestPatternGenerator::generateFrame(const Size &size,
MappedFrameBuffer::MapFlag::Write);
const auto &planes = mappedFrameBuffer.planes();
+ const auto size = cfg.size;
+ const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
rotateLeft1Column<kARGBSize>(size, template_.get());
/* Convert the template_ to the frame buffer */
- int ret = libyuv::ARGBToNV12(template_.get(), size.width * kARGBSize,
- planes[0].data(), size.width,
- planes[1].data(), size.width,
- size.width, size.height);
+ int ret;
+ switch (cfg.pixelFormat) {
+ case formats::NV12:
+ ret = libyuv::ARGBToNV12(template_.get(),
+ size.width * kARGBSize,
+ planes[0].data(),
+ info.stride(size.width, 0),
+ planes[1].data(),
+ info.stride(size.width, 1),
+ size.width, size.height);
+ break;
+ case formats::YUV420:
+ ret = libyuv::ARGBToI420(template_.get(),
+ size.width * kARGBSize,
+ planes[0].data(),
+ info.stride(size.width, 0),
+ planes[1].data(),
+ info.stride(size.width, 1),
+ planes[2].data(),
+ info.stride(size.width, 2),
+ size.width, size.height);
+ break;
+ case formats::ABGR8888:
+ case formats::XBGR8888:
+ ret = libyuv::ARGBCopy(template_.get(),
+ size.width * kARGBSize,
+ planes[0].data(),
+ info.stride(size.width, 0),
+ size.width, size.height);
+ break;
+ default:
+ LOG(Virtual, Error) << "Unsupported format";
+ return -1;
+ }
if (ret != 0)
- LOG(Virtual, Error) << "ARGBToNV12() failed with " << ret;
+ LOG(Virtual, Error) << "Conversation failed with " << ret;
return ret;
}
@@ -24,7 +24,7 @@ enum class TestPattern : char {
class TestPatternGenerator : public FrameGenerator
{
public:
- int generateFrame(const Size &size, const FrameBuffer *buffer) override;
+ int generateFrame(const StreamConfiguration &cfg, const FrameBuffer *buffer) override;
protected:
/* Buffer of test pattern template */
@@ -47,6 +47,13 @@ LOG_DEFINE_CATEGORY(Virtual)
namespace {
+constexpr PixelFormat outputFormats[] = {
+ formats::NV12,
+ formats::YUV420,
+ formats::ABGR8888,
+ formats::XBGR8888,
+};
+
uint64_t currentTimestamp()
{
const auto now = std::chrono::steady_clock::now();
@@ -148,7 +155,7 @@ void VirtualCameraData::processRequest(Request *request)
found = true;
if (streamConfig.frameGenerator->generateFrame(
- stream->configuration().size, buffer))
+ stream->configuration(), buffer))
fmd.status = FrameMetadata::Status::FrameError;
bufferCompleted.emit(buffer);
@@ -202,17 +209,31 @@ CameraConfiguration::Status VirtualCameraConfiguration::validate()
adjusted = true;
}
- if (cfg.pixelFormat != formats::NV12) {
- cfg.pixelFormat = formats::NV12;
+ if (std::find(std::begin(outputFormats),
+ std::end(outputFormats),
+ cfg.pixelFormat) == std::end(outputFormats)) {
+ cfg.pixelFormat = outputFormats[0];
status = Adjusted;
adjusted = true;
}
- if (cfg.colorSpace != ColorSpace::Smpte170m) {
- cfg.colorSpace = ColorSpace::Smpte170m;
+ const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
+ std::optional<ColorSpace> colorSpace;
+ switch (info.colourEncoding) {
+ case PixelFormatInfo::ColourEncodingRGB:
+ colorSpace = ColorSpace::Srgb;
+ break;
+ case PixelFormatInfo::ColourEncodingYUV:
+ colorSpace = ColorSpace::Smpte170m;
+ break;
+ default:
+ ASSERT(false);
+ }
+ if (cfg.colorSpace && cfg.colorSpace != colorSpace) {
status = Adjusted;
adjusted = true;
}
+ cfg.colorSpace = colorSpace;
if (validateColorSpaces() == Adjusted) {
status = Adjusted;
@@ -223,7 +244,6 @@ CameraConfiguration::Status VirtualCameraConfiguration::validate()
LOG(Virtual, Info)
<< "Stream configuration adjusted to " << cfg.toString();
- const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
cfg.stride = info.stride(cfg.size.width, 0, 1);
cfg.frameSize = info.frameSize(cfg.size, 1);
@@ -275,12 +295,13 @@ PipelineHandlerVirtual::generateConfiguration(Camera *camera,
}
std::map<PixelFormat, std::vector<SizeRange>> streamFormats;
- PixelFormat pixelFormat = formats::NV12;
- streamFormats[pixelFormat] = { { data->config_.minResolutionSize,
- data->config_.maxResolutionSize } };
+ for (auto pixelFormat : outputFormats) {
+ streamFormats[pixelFormat] = { { data->config_.minResolutionSize,
+ data->config_.maxResolutionSize } };
+ }
StreamFormats formats(streamFormats);
StreamConfiguration cfg(formats);
- cfg.pixelFormat = pixelFormat;
+ cfg.pixelFormat = outputFormats[0];
cfg.size = data->config_.maxResolutionSize;
cfg.bufferCount = VirtualCameraConfiguration::kBufferCount;
cfg.colorSpace = ColorSpace::Smpte170m;