<div dir="ltr"><div dir="ltr">Hi Tomi,</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, 10 May 2022 at 08:16, Tomi Valkeinen via libcamera-devel <<a href="mailto:libcamera-devel@lists.libcamera.org" target="_blank">libcamera-devel@lists.libcamera.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This is just a conversation starter, not for merging. I really like<br>
libfmt, and I really hate the C++ stream-based string formatting. libfmt<br>
is the first library I add to any new C++ project I make.<br>
<br>
You can find more information about libfmt from:<br>
<br>
<a href="https://github.com/fmtlib/fmt" rel="noreferrer" target="_blank">https://github.com/fmtlib/fmt</a><br>
<a href="https://fmt.dev/latest/index.html" rel="noreferrer" target="_blank">https://fmt.dev/latest/index.html</a><br>
<br>
This patch is just a crude conversion with ugly macros to showcase what<br>
the formatting code might look like.<br>
<br>
libfmt pages suggest that libfmt would be faster and smaller (exe size)<br>
than iostreams, but for the size it didn't seem to be true in cam's case<br>
as the tests below show. However, simple prints did reduce the exe size,<br>
but the few more complex ones increased the size.<br>
<br>
Size tests with gcc 11.2.0-19ubuntu1<br>
<br>
- Without libfmt<br>
<br>
debug 3523400<br>
debug lto 3269368<br>
release 223056<br>
release lto 172280<br>
<br>
- With libfmt<br>
<br>
debug 4424256<br>
debug lto 4143840<br>
release 303952<br>
release lto 252640<br>
<br>
Above shows that cam's size clearly increases with libfmt. However, the<br>
increase really comes only from one case, the use of fmt::memory_buffer<br>
and std::back_inserter. Converting that code to use fmt::format() and<br>
naive string append gives:<br>
<br>
release with string append 233680<br>
release lto with string append 186936<br>
<br>
Also, if I add another use of fmt::memory_buffer and std::back_inserter<br>
to another file, I see much less increase in the size:<br>
<br>
release lto with two uses of memory_buffer, back_inserter 256736<br>
<br>
Signed-off-by: Tomi Valkeinen <<a href="mailto:tomi.valkeinen@ideasonboard.com" target="_blank">tomi.valkeinen@ideasonboard.com</a>><br></blockquote><div><br></div><div>For what it's worth, I absolutely loathe formatting in std iostream, and libfmt is a wonderful alternative.</div><div>It also is close enough to the C++20 std::format implementation that eventual porting would be low effort. So I am all for this change :)</div><div><br></div><div>Regards,</div><div>Naush</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
---<br>
src/cam/camera_session.cpp | 105 ++++++++++++++++---------------------<br>
src/cam/drm.cpp | 68 ++++++++----------------<br>
src/cam/event_loop.cpp | 9 ++--<br>
src/cam/file_sink.cpp | 31 +++++------<br>
src/cam/image.cpp | 15 +++---<br>
src/cam/kms_sink.cpp | 38 ++++++--------<br>
src/cam/main.cpp | 28 +++++-----<br>
src/cam/meson.build | 5 +-<br>
src/cam/options.cpp | 66 ++++++++++-------------<br>
src/cam/stream_options.cpp | 18 +++----<br>
10 files changed, 165 insertions(+), 218 deletions(-)<br>
<br>
diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp<br>
index efffafbf..7843c3fd 100644<br>
--- a/src/cam/camera_session.cpp<br>
+++ b/src/cam/camera_session.cpp<br>
@@ -5,10 +5,9 @@<br>
* camera_session.cpp - Camera capture session<br>
*/<br>
<br>
-#include <iomanip><br>
-#include <iostream><br>
#include <limits.h><br>
-#include <sstream><br>
+#include <fmt/format.h><br>
+#include <fmt/ostream.h><br>
<br>
#include <libcamera/control_ids.h><br>
#include <libcamera/property_ids.h><br>
@@ -22,6 +21,9 @@<br>
#include "main.h"<br>
#include "stream_options.h"<br>
<br>
+#define PR(...) fmt::print(__VA_ARGS__)<br>
+#define EPR(...) fmt::print(stderr, __VA_ARGS__)<br>
+<br>
using namespace libcamera;<br>
<br>
CameraSession::CameraSession(CameraManager *cm,<br>
@@ -40,13 +42,12 @@ CameraSession::CameraSession(CameraManager *cm,<br>
camera_ = cm->get(cameraId);<br>
<br>
if (!camera_) {<br>
- std::cerr << "Camera " << cameraId << " not found" << std::endl;<br>
+ EPR("Camera {} not found\n", cameraId);<br>
return;<br>
}<br>
<br>
if (camera_->acquire()) {<br>
- std::cerr << "Failed to acquire camera " << cameraId<br>
- << std::endl;<br>
+ EPR("Failed to acquire camera {}", cameraId);<br>
return;<br>
}<br>
<br>
@@ -55,15 +56,14 @@ CameraSession::CameraSession(CameraManager *cm,<br>
std::unique_ptr<CameraConfiguration> config =<br>
camera_->generateConfiguration(roles);<br>
if (!config || config->size() != roles.size()) {<br>
- std::cerr << "Failed to get default stream configuration"<br>
- << std::endl;<br>
+ EPR("Failed to get default stream configuration\n");<br>
return;<br>
}<br>
<br>
/* Apply configuration if explicitly requested. */<br>
if (StreamKeyValueParser::updateConfiguration(config.get(),<br>
options_[OptStream])) {<br>
- std::cerr << "Failed to update configuration" << std::endl;<br>
+ EPR("Failed to update configuration\n");<br>
return;<br>
}<br>
<br>
@@ -72,20 +72,17 @@ CameraSession::CameraSession(CameraManager *cm,<br>
#ifdef HAVE_KMS<br>
if (options_.isSet(OptDisplay)) {<br>
if (options_.isSet(OptFile)) {<br>
- std::cerr << "--display and --file options are mutually exclusive"<br>
- << std::endl;<br>
+ EPR("--display and --file options are mutually exclusive\n");<br>
return;<br>
}<br>
<br>
if (roles.size() != 1) {<br>
- std::cerr << "Display doesn't support multiple streams"<br>
- << std::endl;<br>
+ EPR("Display doesn't support multiple streams\n");<br>
return;<br>
}<br>
<br>
if (roles[0] != StreamRole::Viewfinder) {<br>
- std::cerr << "Display requires a viewfinder stream"<br>
- << std::endl;<br>
+ EPR("Display requires a viewfinder stream\n");<br>
return;<br>
}<br>
}<br>
@@ -97,15 +94,14 @@ CameraSession::CameraSession(CameraManager *cm,<br>
<br>
case CameraConfiguration::Adjusted:<br>
if (strictFormats) {<br>
- std::cout << "Adjusting camera configuration disallowed by --strict-formats argument"<br>
- << std::endl;<br>
+ PR("Adjusting camera configuration disallowed by --strict-formats argument\n");<br>
return;<br>
}<br>
- std::cout << "Camera configuration adjusted" << std::endl;<br>
+ PR("Camera configuration adjusted\n");<br>
break;<br>
<br>
case CameraConfiguration::Invalid:<br>
- std::cout << "Camera configuration invalid" << std::endl;<br>
+ PR("Camera configuration invalid\n");<br>
return;<br>
}<br>
<br>
@@ -121,8 +117,7 @@ CameraSession::~CameraSession()<br>
void CameraSession::listControls() const<br>
{<br>
for (const auto &[id, info] : camera_->controls()) {<br>
- std::cout << "Control: " << id->name() << ": "<br>
- << info.toString() << std::endl;<br>
+ PR("Control: {}: {}}n", id->name(), info.toString());<br>
}<br>
}<br>
<br>
@@ -131,8 +126,7 @@ void CameraSession::listProperties() const<br>
for (const auto &[key, value] : camera_->properties()) {<br>
const ControlId *id = properties::<a href="http://properties.at" rel="noreferrer" target="_blank">properties.at</a>(key);<br>
<br>
- std::cout << "Property: " << id->name() << " = "<br>
- << value.toString() << std::endl;<br>
+ PR("Property: {} = {}\n", id->name(), value.toString());<br>
}<br>
}<br>
<br>
@@ -140,17 +134,15 @@ void CameraSession::infoConfiguration() const<br>
{<br>
unsigned int index = 0;<br>
for (const StreamConfiguration &cfg : *config_) {<br>
- std::cout << index << ": " << cfg.toString() << std::endl;<br>
+ PR("{}: {}\n", index, cfg.toString());<br>
<br>
const StreamFormats &formats = cfg.formats();<br>
for (PixelFormat pixelformat : formats.pixelformats()) {<br>
- std::cout << " * Pixelformat: "<br>
- << pixelformat << " "<br>
- << formats.range(pixelformat).toString()<br>
- << std::endl;<br>
+ PR(" * Pixelformat: {} {}\n", pixelformat,<br>
+ formats.range(pixelformat).toString());<br>
<br>
for (const Size &size : formats.sizes(pixelformat))<br>
- std::cout << " - " << size << std::endl;<br>
+ PR(" - {}\n", size);<br>
}<br>
<br>
index++;<br>
@@ -168,7 +160,7 @@ int CameraSession::start()<br>
<br>
ret = camera_->configure(config_.get());<br>
if (ret < 0) {<br>
- std::cout << "Failed to configure camera" << std::endl;<br>
+ PR("Failed to configure camera\n");<br>
return ret;<br>
}<br>
<br>
@@ -197,8 +189,7 @@ int CameraSession::start()<br>
if (sink_) {<br>
ret = sink_->configure(*config_);<br>
if (ret < 0) {<br>
- std::cout << "Failed to configure frame sink"<br>
- << std::endl;<br>
+ PR("Failed to configure frame sink\n");<br>
return ret;<br>
}<br>
<br>
@@ -214,12 +205,12 @@ void CameraSession::stop()<br>
{<br>
int ret = camera_->stop();<br>
if (ret)<br>
- std::cout << "Failed to stop capture" << std::endl;<br>
+ PR("Failed to stop capture\n");<br>
<br>
if (sink_) {<br>
ret = sink_->stop();<br>
if (ret)<br>
- std::cout << "Failed to stop frame sink" << std::endl;<br>
+ PR("Failed to stop frame sink\n");<br>
}<br>
<br>
sink_.reset();<br>
@@ -238,7 +229,7 @@ int CameraSession::startCapture()<br>
for (StreamConfiguration &cfg : *config_) {<br>
ret = allocator_->allocate(cfg.stream());<br>
if (ret < 0) {<br>
- std::cerr << "Can't allocate buffers" << std::endl;<br>
+ EPR("Can't allocate buffers\n");<br>
return -ENOMEM;<br>
}<br>
<br>
@@ -254,7 +245,7 @@ int CameraSession::startCapture()<br>
for (unsigned int i = 0; i < nbuffers; i++) {<br>
std::unique_ptr<Request> request = camera_->createRequest();<br>
if (!request) {<br>
- std::cerr << "Can't create request" << std::endl;<br>
+ EPR("Can't create request\n");<br>
return -ENOMEM;<br>
}<br>
<br>
@@ -266,8 +257,7 @@ int CameraSession::startCapture()<br>
<br>
ret = request->addBuffer(stream, buffer.get());<br>
if (ret < 0) {<br>
- std::cerr << "Can't set buffer for request"<br>
- << std::endl;<br>
+ EPR("Can't set buffer for request\n");<br>
return ret;<br>
}<br>
<br>
@@ -281,14 +271,14 @@ int CameraSession::startCapture()<br>
if (sink_) {<br>
ret = sink_->start();<br>
if (ret) {<br>
- std::cout << "Failed to start frame sink" << std::endl;<br>
+ PR("Failed to start frame sink\n");<br>
return ret;<br>
}<br>
}<br>
<br>
ret = camera_->start();<br>
if (ret) {<br>
- std::cout << "Failed to start capture" << std::endl;<br>
+ PR("Failed to start capture\n");<br>
if (sink_)<br>
sink_->stop();<br>
return ret;<br>
@@ -297,7 +287,7 @@ int CameraSession::startCapture()<br>
for (std::unique_ptr<Request> &request : requests_) {<br>
ret = queueRequest(request.get());<br>
if (ret < 0) {<br>
- std::cerr << "Can't queue request" << std::endl;<br>
+ EPR("Can't queue request\n");<br>
camera_->stop();<br>
if (sink_)<br>
sink_->stop();<br>
@@ -306,13 +296,11 @@ int CameraSession::startCapture()<br>
}<br>
<br>
if (captureLimit_)<br>
- std::cout << "cam" << cameraIndex_<br>
- << ": Capture " << captureLimit_ << " frames"<br>
- << std::endl;<br>
+ PR("cam{}: Capture {} frames\n", cameraIndex_,<br>
+ captureLimit_);<br>
else<br>
- std::cout << "cam" << cameraIndex_<br>
- << ": Capture until user interrupts by SIGINT"<br>
- << std::endl;<br>
+ PR("cam{}: Capture until user interrupts by SIGINT\n",<br>
+ cameraIndex_);<br>
<br>
return 0;<br>
}<br>
@@ -364,23 +352,23 @@ void CameraSession::processRequest(Request *request)<br>
<br>
bool requeue = true;<br>
<br>
- std::stringstream info;<br>
- info << ts / 1000000000 << "."<br>
- << std::setw(6) << std::setfill('0') << ts / 1000 % 1000000<br>
- << " (" << std::fixed << std::setprecision(2) << fps << " fps)";<br>
+ auto sbuf = fmt::memory_buffer();<br>
+ fmt::format_to(std::back_inserter(sbuf), "{}.{:06} ({:.2f} fps)",<br>
+ ts / 1000000000,<br>
+ ts / 1000 % 1000000,<br>
+ fps);<br>
<br>
for (const auto &[stream, buffer] : buffers) {<br>
const FrameMetadata &metadata = buffer->metadata();<br>
<br>
- info << " " << streamNames_[stream]<br>
- << " seq: " << std::setw(6) << std::setfill('0') << metadata.sequence<br>
- << " bytesused: ";<br>
+ fmt::format_to(std::back_inserter(sbuf), " {} seq: {:06} bytesused: ",<br>
+ streamNames_[stream], metadata.sequence);<br>
<br>
unsigned int nplane = 0;<br>
for (const FrameMetadata::Plane &plane : metadata.planes()) {<br>
- info << plane.bytesused;<br>
+ fmt::format_to(std::back_inserter(sbuf), "{}", plane.bytesused);<br>
if (++nplane < metadata.planes().size())<br>
- info << "/";<br>
+ fmt::format_to(std::back_inserter(sbuf), "/");<br>
}<br>
}<br>
<br>
@@ -389,14 +377,13 @@ void CameraSession::processRequest(Request *request)<br>
requeue = false;<br>
}<br>
<br>
- std::cout << info.str() << std::endl;<br>
+ PR("{}\n", fmt::to_string(sbuf));<br>
<br>
if (printMetadata_) {<br>
const ControlList &requestMetadata = request->metadata();<br>
for (const auto &[key, value] : requestMetadata) {<br>
const ControlId *id = controls::<a href="http://controls.at" rel="noreferrer" target="_blank">controls.at</a>(key);<br>
- std::cout << "\t" << id->name() << " = "<br>
- << value.toString() << std::endl;<br>
+ PR("\t{} = {}\n", id->name(), value.toString());<br>
}<br>
}<br>
<br>
diff --git a/src/cam/drm.cpp b/src/cam/drm.cpp<br>
index 46e34eb5..84919ab3 100644<br>
--- a/src/cam/drm.cpp<br>
+++ b/src/cam/drm.cpp<br>
@@ -10,12 +10,12 @@<br>
#include <algorithm><br>
#include <errno.h><br>
#include <fcntl.h><br>
-#include <iostream><br>
#include <set><br>
#include <string.h><br>
#include <sys/ioctl.h><br>
#include <sys/stat.h><br>
#include <sys/types.h><br>
+#include <fmt/core.h><br>
<br>
#include <libcamera/framebuffer.h><br>
#include <libcamera/geometry.h><br>
@@ -25,6 +25,9 @@<br>
<br>
#include "event_loop.h"<br>
<br>
+#define PR(...) fmt::print(__VA_ARGS__)<br>
+#define EPR(...) fmt::print(stderr, __VA_ARGS__)<br>
+<br>
namespace DRM {<br>
<br>
Object::Object(Device *dev, uint32_t id, Type type)<br>
@@ -178,9 +181,7 @@ Connector::Connector(Device *dev, const drmModeConnector *connector)<br>
{<br>
auto typeName = connectorTypeNames.find(connector->connector_type);<br>
if (typeName == connectorTypeNames.end()) {<br>
- std::cerr<br>
- << "Invalid connector type "<br>
- << connector->connector_type << std::endl;<br>
+ EPR("Invalid connector type {}}n", connector->connector_type);<br>
typeName = connectorTypeNames.find(DRM_MODE_CONNECTOR_Unknown);<br>
}<br>
<br>
@@ -213,9 +214,7 @@ Connector::Connector(Device *dev, const drmModeConnector *connector)<br>
return <a href="http://e.id" rel="noreferrer" target="_blank">e.id</a>() == encoderId;<br>
});<br>
if (encoder == encoders.end()) {<br>
- std::cerr<br>
- << "Encoder " << encoderId << " not found"<br>
- << std::endl;<br>
+ EPR("Encoder {} not found\n", encoderId);<br>
continue;<br>
}<br>
<br>
@@ -296,9 +295,7 @@ FrameBuffer::~FrameBuffer()<br>
<br>
if (ret == -1) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Failed to close GEM object: "<br>
- << strerror(-ret) << std::endl;<br>
+ EPR("Failed to close GEM object: {}\n", strerror(-ret));<br>
}<br>
}<br>
<br>
@@ -408,9 +405,8 @@ int Device::init()<br>
fd_ = open(name, O_RDWR | O_CLOEXEC);<br>
if (fd_ < 0) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Failed to open DRM/KMS device " << name << ": "<br>
- << strerror(-ret) << std::endl;<br>
+ EPR("Failed to open DRM/KMS device {}: {}\n", name,<br>
+ strerror(-ret));<br>
return ret;<br>
}<br>
<br>
@@ -421,9 +417,7 @@ int Device::init()<br>
ret = drmSetClientCap(fd_, DRM_CLIENT_CAP_ATOMIC, 1);<br>
if (ret < 0) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Failed to enable atomic capability: "<br>
- << strerror(-ret) << std::endl;<br>
+ EPR("Failed to enable atomic capability: {}\n", strerror(-ret));<br>
return ret;<br>
}<br>
<br>
@@ -448,9 +442,7 @@ int Device::getResources()<br>
};<br>
if (!resources) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Failed to get DRM/KMS resources: "<br>
- << strerror(-ret) << std::endl;<br>
+ EPR("Failed to get DRM/KMS resources: {}\n", strerror(-ret));<br>
return ret;<br>
}<br>
<br>
@@ -458,9 +450,7 @@ int Device::getResources()<br>
drmModeCrtc *crtc = drmModeGetCrtc(fd_, resources->crtcs[i]);<br>
if (!crtc) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Failed to get CRTC: " << strerror(-ret)<br>
- << std::endl;<br>
+ EPR("Failed to get CRTC: {}\n", strerror(-ret));<br>
return ret;<br>
}<br>
<br>
@@ -476,9 +466,7 @@ int Device::getResources()<br>
drmModeGetEncoder(fd_, resources->encoders[i]);<br>
if (!encoder) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Failed to get encoder: " << strerror(-ret)<br>
- << std::endl;<br>
+ EPR("Failed to get encoder: {}\n", strerror(-ret));<br>
return ret;<br>
}<br>
<br>
@@ -494,9 +482,7 @@ int Device::getResources()<br>
drmModeGetConnector(fd_, resources->connectors[i]);<br>
if (!connector) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Failed to get connector: " << strerror(-ret)<br>
- << std::endl;<br>
+ EPR("Failed to get connector: {}\n", strerror(-ret));<br>
return ret;<br>
}<br>
<br>
@@ -513,9 +499,7 @@ int Device::getResources()<br>
};<br>
if (!planes) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Failed to get DRM/KMS planes: "<br>
- << strerror(-ret) << std::endl;<br>
+ EPR("Failed to get DRM/KMS planes: {}\n", strerror(-ret));<br>
return ret;<br>
}<br>
<br>
@@ -524,9 +508,7 @@ int Device::getResources()<br>
drmModeGetPlane(fd_, planes->planes[i]);<br>
if (!plane) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Failed to get plane: " << strerror(-ret)<br>
- << std::endl;<br>
+ EPR("Failed to get plane: {}\n", strerror(-ret));<br>
return ret;<br>
}<br>
<br>
@@ -556,9 +538,7 @@ int Device::getResources()<br>
drmModePropertyRes *property = drmModeGetProperty(fd_, id);<br>
if (!property) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Failed to get property: " << strerror(-ret)<br>
- << std::endl;<br>
+ EPR("Failed to get property: {}\n", strerror(-ret));<br>
continue;<br>
}<br>
<br>
@@ -573,9 +553,8 @@ int Device::getResources()<br>
for (auto &object : objects_) {<br>
ret = object.second->setup();<br>
if (ret < 0) {<br>
- std::cerr<br>
- << "Failed to setup object " << object.second->id()<br>
- << ": " << strerror(-ret) << std::endl;<br>
+ EPR("Failed to setup object {}: {}\n",<br>
+ object.second->id(), strerror(-ret));<br>
return ret;<br>
}<br>
}<br>
@@ -616,9 +595,8 @@ std::unique_ptr<FrameBuffer> Device::createFrameBuffer(<br>
ret = drmPrimeFDToHandle(fd_, plane.fd.get(), &handle);<br>
if (ret < 0) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Unable to import framebuffer dmabuf: "<br>
- << strerror(-ret) << std::endl;<br>
+ EPR("Unable to import framebuffer dmabuf: {}\n",<br>
+ strerror(-ret));<br>
return nullptr;<br>
}<br>
<br>
@@ -636,9 +614,7 @@ std::unique_ptr<FrameBuffer> Device::createFrameBuffer(<br>
strides.data(), offsets, &fb->id_, 0);<br>
if (ret < 0) {<br>
ret = -errno;<br>
- std::cerr<br>
- << "Failed to add framebuffer: "<br>
- << strerror(-ret) << std::endl;<br>
+ EPR("Failed to add framebuffer: {}\n", strerror(-ret));<br>
return nullptr;<br>
}<br>
<br>
diff --git a/src/cam/event_loop.cpp b/src/cam/event_loop.cpp<br>
index e25784c0..87aaf59a 100644<br>
--- a/src/cam/event_loop.cpp<br>
+++ b/src/cam/event_loop.cpp<br>
@@ -10,7 +10,10 @@<br>
#include <assert.h><br>
#include <event2/event.h><br>
#include <event2/thread.h><br>
-#include <iostream><br>
+#include <fmt/core.h><br>
+<br>
+#define PR(...) fmt::print(__VA_ARGS__)<br>
+#define EPR(...) fmt::print(stderr, __VA_ARGS__)<br>
<br>
EventLoop *EventLoop::instance_ = nullptr;<br>
<br>
@@ -71,13 +74,13 @@ void EventLoop::addEvent(int fd, EventType type,<br>
event->event_ = event_new(base_, fd, events, &EventLoop::Event::dispatch,<br>
event.get());<br>
if (!event->event_) {<br>
- std::cerr << "Failed to create event for fd " << fd << std::endl;<br>
+ EPR("Failed to create event for fd {}\n", fd);<br>
return;<br>
}<br>
<br>
int ret = event_add(event->event_, nullptr);<br>
if (ret < 0) {<br>
- std::cerr << "Failed to add event for fd " << fd << std::endl;<br>
+ EPR("Failed to add event for fd {}\n", fd);<br>
return;<br>
}<br>
<br>
diff --git a/src/cam/file_sink.cpp b/src/cam/file_sink.cpp<br>
index 45213d4a..86e2118c 100644<br>
--- a/src/cam/file_sink.cpp<br>
+++ b/src/cam/file_sink.cpp<br>
@@ -7,11 +7,12 @@<br>
<br>
#include <assert.h><br>
#include <fcntl.h><br>
-#include <iomanip><br>
-#include <iostream><br>
-#include <sstream><br>
#include <string.h><br>
#include <unistd.h><br>
+#include <fmt/core.h><br>
+<br>
+#define PR(...) fmt::print(__VA_ARGS__)<br>
+#define EPR(...) fmt::print(stderr, __VA_ARGS__)<br>
<br>
#include <libcamera/camera.h><br>
<br>
@@ -70,10 +71,10 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)<br>
<br>
pos = filename.find_first_of('#');<br>
if (pos != std::string::npos) {<br>
- std::stringstream ss;<br>
- ss << streamNames_[stream] << "-" << std::setw(6)<br>
- << std::setfill('0') << buffer->metadata().sequence;<br>
- filename.replace(pos, 1, ss.str());<br>
+ auto s = fmt::format("{}-{:06}",<br>
+ streamNames_[stream],<br>
+ buffer->metadata().sequence);<br>
+ filename.replace(pos, 1, s);<br>
}<br>
<br>
fd = open(filename.c_str(), O_CREAT | O_WRONLY |<br>
@@ -81,8 +82,7 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)<br>
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);<br>
if (fd == -1) {<br>
ret = -errno;<br>
- std::cerr << "failed to open file " << filename << ": "<br>
- << strerror(-ret) << std::endl;<br>
+ EPR("failed to open file {}: {}\n", filename, strerror(-ret));<br>
return;<br>
}<br>
<br>
@@ -95,20 +95,17 @@ void FileSink::writeBuffer(const Stream *stream, FrameBuffer *buffer)<br>
unsigned int length = std::min<unsigned int>(meta.bytesused, data.size());<br>
<br>
if (meta.bytesused > data.size())<br>
- std::cerr << "payload size " << meta.bytesused<br>
- << " larger than plane size " << data.size()<br>
- << std::endl;<br>
+ EPR("payload size {} larger than plane size {}\n",<br>
+ meta.bytesused, data.size());<br>
<br>
ret = ::write(fd, data.data(), length);<br>
if (ret < 0) {<br>
ret = -errno;<br>
- std::cerr << "write error: " << strerror(-ret)<br>
- << std::endl;<br>
+ EPR("write error: {}\n", strerror(-ret));<br>
break;<br>
} else if (ret != (int)length) {<br>
- std::cerr << "write error: only " << ret<br>
- << " bytes written instead of "<br>
- << length << std::endl;<br>
+ EPR("write error: only {} bytes written instead of {}\n",<br>
+ ret, length);<br>
break;<br>
}<br>
}<br>
diff --git a/src/cam/image.cpp b/src/cam/image.cpp<br>
index fe2cc6da..73bcf915 100644<br>
--- a/src/cam/image.cpp<br>
+++ b/src/cam/image.cpp<br>
@@ -9,11 +9,14 @@<br>
<br>
#include <assert.h><br>
#include <errno.h><br>
-#include <iostream><br>
#include <map><br>
#include <string.h><br>
#include <sys/mman.h><br>
#include <unistd.h><br>
+#include <fmt/core.h><br>
+<br>
+#define PR(...) fmt::print(__VA_ARGS__)<br>
+#define EPR(...) fmt::print(stderr, __VA_ARGS__)<br>
<br>
using namespace libcamera;<br>
<br>
@@ -49,10 +52,8 @@ std::unique_ptr<Image> Image::fromFrameBuffer(const FrameBuffer *buffer, MapMode<br>
<br>
if (plane.offset > length ||<br>
plane.offset + plane.length > length) {<br>
- std::cerr << "plane is out of buffer: buffer length="<br>
- << length << ", plane offset=" << plane.offset<br>
- << ", plane length=" << plane.length<br>
- << std::endl;<br>
+ EPR("plane is out of buffer: buffer length={}, plane offset={}, plane length={}\n",<br>
+ length, plane.offset, plane.length);<br>
return nullptr;<br>
}<br>
size_t &mapLength = mappedBuffers[fd].mapLength;<br>
@@ -68,8 +69,8 @@ std::unique_ptr<Image> Image::fromFrameBuffer(const FrameBuffer *buffer, MapMode<br>
MAP_SHARED, fd, 0);<br>
if (address == MAP_FAILED) {<br>
int error = -errno;<br>
- std::cerr << "Failed to mmap plane: "<br>
- << strerror(-error) << std::endl;<br>
+ EPR("Failed to mmap plane: {}\n",<br>
+ strerror(-error));<br>
return nullptr;<br>
}<br>
<br>
diff --git a/src/cam/kms_sink.cpp b/src/cam/kms_sink.cpp<br>
index 7add81a6..823b75e4 100644<br>
--- a/src/cam/kms_sink.cpp<br>
+++ b/src/cam/kms_sink.cpp<br>
@@ -10,10 +10,13 @@<br>
#include <array><br>
#include <algorithm><br>
#include <assert.h><br>
-#include <iostream><br>
#include <memory><br>
#include <stdint.h><br>
#include <string.h><br>
+#include <fmt/core.h><br>
+<br>
+#define PR(...) fmt::print(__VA_ARGS__)<br>
+#define EPR(...) fmt::print(stderr, __VA_ARGS__)<br>
<br>
#include <libcamera/camera.h><br>
#include <libcamera/formats.h><br>
@@ -54,11 +57,9 @@ KMSSink::KMSSink(const std::string &connectorName)<br>
<br>
if (!connector_) {<br>
if (!connectorName.empty())<br>
- std::cerr<br>
- << "Connector " << connectorName << " not found"<br>
- << std::endl;<br>
+ EPR("Connector {} not found\n", connectorName);<br>
else<br>
- std::cerr << "No connected connector found" << std::endl;<br>
+ EPR("No connected connector found\n");<br>
return;<br>
}<br>
<br>
@@ -119,7 +120,7 @@ int KMSSink::configure(const libcamera::CameraConfiguration &config)<br>
mode.vdisplay == cfg.size.height;<br>
});<br>
if (iter == modes.end()) {<br>
- std::cerr << "No mode matching " << cfg.size << std::endl;<br>
+ EPR("No mode matching {}\n", cfg.size);<br>
return -EINVAL;<br>
}<br>
<br>
@@ -192,17 +193,12 @@ int KMSSink::configurePipeline(const libcamera::PixelFormat &format)<br>
{<br>
const int ret = selectPipeline(format);<br>
if (ret) {<br>
- std::cerr<br>
- << "Unable to find display pipeline for format "<br>
- << format << std::endl;<br>
-<br>
+ EPR("Unable to find display pipeline for format {}\n", format);<br>
return ret;<br>
}<br>
<br>
- std::cout<br>
- << "Using KMS plane " << plane_->id() << ", CRTC " << crtc_->id()<br>
- << ", connector " << connector_->name()<br>
- << " (" << connector_->id() << ")" << std::endl;<br>
+ PR("Using KMS plane {}, CRTC {}, connector {} ({})\n",<br>
+ plane_->id(), crtc_->id(), connector_->name(), connector_->id());<br>
<br>
return 0;<br>
}<br>
@@ -228,9 +224,8 @@ int KMSSink::start()<br>
<br>
ret = request->commit(DRM::AtomicRequest::FlagAllowModeset);<br>
if (ret < 0) {<br>
- std::cerr<br>
- << "Failed to disable CRTCs and planes: "<br>
- << strerror(-ret) << std::endl;<br>
+ EPR("Failed to disable CRTCs and planes: {}\n",<br>
+ strerror(-ret));<br>
return ret;<br>
}<br>
<br>
@@ -250,9 +245,7 @@ int KMSSink::stop()<br>
<br>
int ret = request.commit(DRM::AtomicRequest::FlagAllowModeset);<br>
if (ret < 0) {<br>
- std::cerr<br>
- << "Failed to stop display pipeline: "<br>
- << strerror(-ret) << std::endl;<br>
+ EPR("Failed to stop display pipeline: {}\n", strerror(-ret));<br>
return ret;<br>
}<br>
<br>
@@ -312,9 +305,8 @@ bool KMSSink::processRequest(libcamera::Request *camRequest)<br>
if (!queued_) {<br>
int ret = drmRequest->commit(flags);<br>
if (ret < 0) {<br>
- std::cerr<br>
- << "Failed to commit atomic request: "<br>
- << strerror(-ret) << std::endl;<br>
+ EPR("Failed to commit atomic request: {}\n",<br>
+ strerror(-ret));<br>
/* \todo Implement error handling */<br>
}<br>
<br>
diff --git a/src/cam/main.cpp b/src/cam/main.cpp<br>
index c7f664b9..03615dc9 100644<br>
--- a/src/cam/main.cpp<br>
+++ b/src/cam/main.cpp<br>
@@ -6,10 +6,9 @@<br>
*/<br>
<br>
#include <atomic><br>
-#include <iomanip><br>
-#include <iostream><br>
#include <signal.h><br>
#include <string.h><br>
+#include <fmt/core.h><br>
<br>
#include <libcamera/libcamera.h><br>
#include <libcamera/property_ids.h><br>
@@ -78,8 +77,7 @@ int CamApp::init(int argc, char **argv)<br>
<br>
ret = cm_->start();<br>
if (ret) {<br>
- std::cout << "Failed to start camera manager: "<br>
- << strerror(-ret) << std::endl;<br>
+ fmt::print("Failed to start camera manager: {}\n", -ret);<br>
return ret;<br>
}<br>
<br>
@@ -173,12 +171,12 @@ int CamApp::parseOptions(int argc, char *argv[])<br>
<br>
void CamApp::cameraAdded(std::shared_ptr<Camera> cam)<br>
{<br>
- std::cout << "Camera Added: " << cam->id() << std::endl;<br>
+ fmt::print("Camera Added: {}\n", cam->id());<br>
}<br>
<br>
void CamApp::cameraRemoved(std::shared_ptr<Camera> cam)<br>
{<br>
- std::cout << "Camera Removed: " << cam->id() << std::endl;<br>
+ fmt::print("Camera Removed: {}\n", cam->id());<br>
}<br>
<br>
void CamApp::captureDone()<br>
@@ -193,11 +191,11 @@ int CamApp::run()<br>
<br>
/* 1. List all cameras. */<br>
if (options_.isSet(OptList)) {<br>
- std::cout << "Available cameras:" << std::endl;<br>
+ fmt::print("Available cameras:\n");<br>
<br>
unsigned int index = 1;<br>
for (const std::shared_ptr<Camera> &cam : cm_->cameras()) {<br>
- std::cout << index << ": " << cameraName(cam.get()) << std::endl;<br>
+ fmt::print("{}: {}\n", cameraName(cam.get()), index);<br>
index++;<br>
}<br>
}<br>
@@ -215,12 +213,12 @@ int CamApp::run()<br>
index,<br>
camera.children());<br>
if (!session->isValid()) {<br>
- std::cout << "Failed to create camera session" << std::endl;<br>
+ fmt::print("Failed to create camera session\n");<br>
return -EINVAL;<br>
}<br>
<br>
- std::cout << "Using camera " << session->camera()->id()<br>
- << " as cam" << index << std::endl;<br>
+ fmt::print("Using camera{} as cam{}\n",<br>
+ session->camera()->id(), index);<br>
<br>
session->captureDone.connect(this, &CamApp::captureDone);<br>
<br>
@@ -250,7 +248,7 @@ int CamApp::run()<br>
<br>
ret = session->start();<br>
if (ret) {<br>
- std::cout << "Failed to start camera session" << std::endl;<br>
+ fmt::print("Failed to start camera session\n");<br>
return ret;<br>
}<br>
<br>
@@ -259,8 +257,8 @@ int CamApp::run()<br>
<br>
/* 5. Enable hotplug monitoring. */<br>
if (options_.isSet(OptMonitor)) {<br>
- std::cout << "Monitoring new hotplug and unplug events" << std::endl;<br>
- std::cout << "Press Ctrl-C to interrupt" << std::endl;<br>
+ fmt::print("Monitoring new hotplug and unplug events\n");<br>
+ fmt::print("Press Ctrl-C to interrupt\n");<br>
<br>
cm_->cameraAdded.connect(this, &CamApp::cameraAdded);<br>
cm_->cameraRemoved.connect(this, &CamApp::cameraRemoved);<br>
@@ -323,7 +321,7 @@ std::string CamApp::cameraName(const Camera *camera)<br>
<br>
void signalHandler([[maybe_unused]] int signal)<br>
{<br>
- std::cout << "Exiting" << std::endl;<br>
+ fmt::print("Exiting");<br>
CamApp::instance()->quit();<br>
}<br>
<br>
diff --git a/src/cam/meson.build b/src/cam/meson.build<br>
index 5bab8c9e..2b47383d 100644<br>
--- a/src/cam/meson.build<br>
+++ b/src/cam/meson.build<br>
@@ -7,6 +7,8 @@ if not libevent.found()<br>
subdir_done()<br>
endif<br>
<br>
+libfmt_dep = dependency('fmt')<br>
+<br>
cam_enabled = true<br>
<br>
cam_sources = files([<br>
@@ -25,7 +27,7 @@ cam_cpp_args = []<br>
libdrm = dependency('libdrm', required : false)<br>
<br>
if libdrm.found()<br>
- cam_cpp_args += [ '-DHAVE_KMS' ]<br>
+ cam_cpp_args += [ '-DHAVE_KMS', ]<br>
cam_sources += files([<br>
'drm.cpp',<br>
'kms_sink.cpp'<br>
@@ -38,6 +40,7 @@ cam = executable('cam', cam_sources,<br>
libcamera_public,<br>
libdrm,<br>
libevent,<br>
+ libfmt_dep,<br>
],<br>
cpp_args : cam_cpp_args,<br>
install : true)<br>
diff --git a/src/cam/options.cpp b/src/cam/options.cpp<br>
index 4f7e8691..c9979385 100644<br>
--- a/src/cam/options.cpp<br>
+++ b/src/cam/options.cpp<br>
@@ -7,9 +7,11 @@<br>
<br>
#include <assert.h><br>
#include <getopt.h><br>
-#include <iomanip><br>
-#include <iostream><br>
#include <string.h><br>
+#include <fmt/core.h><br>
+<br>
+#define PR(...) fmt::print(__VA_ARGS__)<br>
+#define EPR(...) fmt::print(stderr, __VA_ARGS__)<br>
<br>
#include "options.h"<br>
<br>
@@ -390,26 +392,23 @@ KeyValueParser::Options KeyValueParser::parse(const char *arguments)<br>
continue;<br>
<br>
if (optionsMap_.find(key) == optionsMap_.end()) {<br>
- std::cerr << "Invalid option " << key << std::endl;<br>
+ EPR("Invalid option {}\n", key);<br>
return options;<br>
}<br>
<br>
OptionArgument arg = optionsMap_[key].argument;<br>
if (value.empty() && arg == ArgumentRequired) {<br>
- std::cerr << "Option " << key << " requires an argument"<br>
- << std::endl;<br>
+ EPR("Option {} requires an argument\n", key);<br>
return options;<br>
} else if (!value.empty() && arg == ArgumentNone) {<br>
- std::cerr << "Option " << key << " takes no argument"<br>
- << std::endl;<br>
+ EPR("Option {} takes no argument\n", key);<br>
return options;<br>
}<br>
<br>
const Option &option = optionsMap_[key];<br>
if (!options.parseValue(key, option, value.c_str())) {<br>
- std::cerr << "Failed to parse '" << value << "' as "<br>
- << option.typeName() << " for option " << key<br>
- << std::endl;<br>
+ EPR("Failed to parse '{}' as {} for option {}\n",<br>
+ value, option.typeName(), key);<br>
return options;<br>
}<br>
}<br>
@@ -453,16 +452,16 @@ void KeyValueParser::usage(int indent)<br>
argument += "]";<br>
}<br>
<br>
- std::cerr << std::setw(indent) << argument;<br>
+ EPR("{:{}}", argument, indent);<br>
<br>
for (const char *help = option.help, *end = help; end;) {<br>
end = strchr(help, '\n');<br>
if (end) {<br>
- std::cerr << std::string(help, end - help + 1);<br>
- std::cerr << std::setw(indent) << " ";<br>
+ EPR(std::string(help, end - help + 1));<br>
+ EPR("{:{}}", "", indent);<br>
help = end + 1;<br>
} else {<br>
- std::cerr << help << std::endl;<br>
+ EPR("{}\n", help);<br>
}<br>
}<br>
}<br>
@@ -929,10 +928,10 @@ OptionsParser::Options OptionsParser::parse(int argc, char **argv)<br>
<br>
if (c == '?' || c == ':') {<br>
if (c == '?')<br>
- std::cerr << "Invalid option ";<br>
+ EPR("Invalid option ");<br>
else<br>
- std::cerr << "Missing argument for option ";<br>
- std::cerr << argv[optind - 1] << std::endl;<br>
+ EPR("Missing argument for option ");<br>
+ EPR("{}\n", argv[optind - 1]);<br>
<br>
usage();<br>
return options;<br>
@@ -946,8 +945,7 @@ OptionsParser::Options OptionsParser::parse(int argc, char **argv)<br>
}<br>
<br>
if (optind < argc) {<br>
- std::cerr << "Invalid non-option argument '" << argv[optind]<br>
- << "'" << std::endl;<br>
+ EPR("Invalid non-option argument '{}'\n", argv[optind]);<br>
usage();<br>
return options;<br>
}<br>
@@ -992,14 +990,9 @@ void OptionsParser::usage()<br>
<br>
indent = (indent + 7) / 8 * 8;<br>
<br>
- std::cerr << "Options:" << std::endl;<br>
-<br>
- std::ios_base::fmtflags f(std::cerr.flags());<br>
- std::cerr << std::left;<br>
+ EPR("Options:\n");<br>
<br>
usageOptions(options_, indent);<br>
-<br>
- std::cerr.flags(f);<br>
}<br>
<br>
void OptionsParser::usageOptions(const std::list<Option> &options,<br>
@@ -1036,16 +1029,16 @@ void OptionsParser::usageOptions(const std::list<Option> &options,<br>
if (option.isArray)<br>
argument += " ...";<br>
<br>
- std::cerr << std::setw(indent) << argument;<br>
+ EPR("{:{}}", argument, indent);<br>
<br>
- for (const char *help = option.help, *end = help; end; ) {<br>
+ for (const char *help = option.help, *end = help; end;) {<br>
end = strchr(help, '\n');<br>
if (end) {<br>
- std::cerr << std::string(help, end - help + 1);<br>
- std::cerr << std::setw(indent) << " ";<br>
+ EPR(std::string(help, end - help + 1));<br>
+ EPR("{:{}}", "", indent);<br>
help = end + 1;<br>
} else {<br>
- std::cerr << help << std::endl;<br>
+ EPR("{}\n", help);<br>
}<br>
}<br>
<br>
@@ -1060,8 +1053,8 @@ void OptionsParser::usageOptions(const std::list<Option> &options,<br>
return;<br>
<br>
for (const Option *option : parentOptions) {<br>
- std::cerr << std::endl << "Options valid in the context of "<br>
- << option->optionName() << ":" << std::endl;<br>
+ EPR("\nOptions valid in the context of {}:\n",<br>
+ option->optionName());<br>
usageOptions(option->children, indent);<br>
}<br>
}<br>
@@ -1125,15 +1118,14 @@ bool OptionsParser::parseValue(const Option &option, const char *arg,<br>
<br>
std::tie(options, error) = childOption(option.parent, options);<br>
if (error) {<br>
- std::cerr << "Option " << option.optionName() << " requires a "<br>
- << error->optionName() << " context" << std::endl;<br>
+ EPR("Option {} requires a {} context\n",<br>
+ option.optionName(), error->optionName());<br>
return false;<br>
}<br>
<br>
if (!options->parseValue(option.opt, option, arg)) {<br>
- std::cerr << "Can't parse " << option.typeName()<br>
- << " argument for option " << option.optionName()<br>
- << std::endl;<br>
+ EPR("Can't parse {} argument for option {}\n",<br>
+ option.typeName(), option.optionName());<br>
return false;<br>
}<br>
<br>
diff --git a/src/cam/stream_options.cpp b/src/cam/stream_options.cpp<br>
index 150bd27c..666862eb 100644<br>
--- a/src/cam/stream_options.cpp<br>
+++ b/src/cam/stream_options.cpp<br>
@@ -6,7 +6,10 @@<br>
*/<br>
#include "stream_options.h"<br>
<br>
-#include <iostream><br>
+#include <fmt/core.h><br>
+<br>
+#define PR(...) fmt::print(__VA_ARGS__)<br>
+#define EPR(...) fmt::print(stderr, __VA_ARGS__)<br>
<br>
using namespace libcamera;<br>
<br>
@@ -30,8 +33,7 @@ KeyValueParser::Options StreamKeyValueParser::parse(const char *arguments)<br>
<br>
if (options.valid() && options.isSet("role") &&<br>
!parseRole(&role, options)) {<br>
- std::cerr << "Unknown stream role "<br>
- << options["role"].toString() << std::endl;<br>
+ EPR("Unknown stream role {}\n", options["role"].toString());<br>
options.invalidate();<br>
}<br>
<br>
@@ -64,7 +66,7 @@ int StreamKeyValueParser::updateConfiguration(CameraConfiguration *config,<br>
const OptionValue &values)<br>
{<br>
if (!config) {<br>
- std::cerr << "No configuration provided" << std::endl;<br>
+ EPR("No configuration provided\n");<br>
return -EINVAL;<br>
}<br>
<br>
@@ -75,12 +77,8 @@ int StreamKeyValueParser::updateConfiguration(CameraConfiguration *config,<br>
const std::vector<OptionValue> &streamParameters = values.toArray();<br>
<br>
if (config->size() != streamParameters.size()) {<br>
- std::cerr<br>
- << "Number of streams in configuration "<br>
- << config->size()<br>
- << " does not match number of streams parsed "<br>
- << streamParameters.size()<br>
- << std::endl;<br>
+ EPR("Number of streams in configuration {} does not match number of streams parsed {}\n",<br>
+ config->size(), streamParameters.size());<br>
return -EINVAL;<br>
}<br>
<br>
-- <br>
2.34.1<br>
<br>
</blockquote></div></div>