<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>