From dd4862cf956b539acdf3fd9d0cc65bd20dea1f1f Mon Sep 17 00:00:00 2001 From: TzuHuanTai Date: Wed, 25 Jun 2025 08:26:58 -0700 Subject: [PATCH 1/3] feat: support libcamera dma source --- src/capturer/libcamera_capturer.cpp | 13 +++++++++---- src/common/v4l2_utils.h | 4 +++- test/test_libcamera.cpp | 5 +++-- test/test_v4l2_encoder.cpp | 14 +++++++------- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/capturer/libcamera_capturer.cpp b/src/capturer/libcamera_capturer.cpp index 120d7c8f..b131e7e4 100644 --- a/src/capturer/libcamera_capturer.cpp +++ b/src/capturer/libcamera_capturer.cpp @@ -171,7 +171,7 @@ int LibcameraCapturer::width() const { return width_; } int LibcameraCapturer::height() const { return height_; } -bool LibcameraCapturer::is_dma_capture() const { return false; } +bool LibcameraCapturer::is_dma_capture() const { return true; } uint32_t LibcameraCapturer::format() const { return format_; } @@ -188,6 +188,12 @@ LibcameraCapturer &LibcameraCapturer::SetResolution(int width, int height) { camera_config_->at(0).pixelFormat = libcamera::formats::YUV420; camera_config_->at(0).bufferCount = buffer_count_; + if (width >= 1280 || height >= 720) { + camera_config_->at(0).colorSpace = libcamera::ColorSpace::Rec709; + } else { + camera_config_->at(0).colorSpace = libcamera::ColorSpace::Smpte170m; + } + auto validation = camera_config_->validate(); if (validation == libcamera::CameraConfiguration::Status::Valid) { INFO_PRINT("camera validated format: %s.", camera_config_->at(0).toString().c_str()); @@ -292,15 +298,14 @@ void LibcameraCapturer::RequestComplete(libcamera::Request *request) { auto &buffers = request->buffers(); auto *buffer = buffers.begin()->second; - auto &plane = buffer->planes()[0]; - int fd = plane.fd.get(); + int fd = buffer->planes()[0].fd.get(); void *data = mapped_buffers_[fd].first; int length = mapped_buffers_[fd].second; timeval tv = {}; tv.tv_sec = buffer->metadata().timestamp / 1000000000; tv.tv_usec = (buffer->metadata().timestamp % 1000000000) / 1000; - auto v4l2_buffer = V4L2Buffer::FromLibcamera((uint8_t *)data, length, tv, format_); + auto v4l2_buffer = V4L2Buffer::FromLibcamera((uint8_t *)data, length, fd, tv, format_); frame_buffer_ = V4L2FrameBuffer::Create(width_, height_, v4l2_buffer); NextFrameBuffer(frame_buffer_); diff --git a/src/common/v4l2_utils.h b/src/common/v4l2_utils.h index 75cb3f5d..584a06ac 100644 --- a/src/common/v4l2_utils.h +++ b/src/common/v4l2_utils.h @@ -37,9 +37,11 @@ struct V4L2Buffer { return buf; } - static V4L2Buffer FromLibcamera(void *start, int length, timeval timestamp, uint32_t fmt) { + static V4L2Buffer FromLibcamera(void *start, int length, int dmafd, timeval timestamp, + uint32_t fmt) { V4L2Buffer buf; buf.start = start; + buf.dmafd = dmafd; buf.pix_fmt = fmt; buf.length = length; buf.timestamp = timestamp; diff --git a/test/test_libcamera.cpp b/test/test_libcamera.cpp index 5c92aade..0c22cd00 100644 --- a/test/test_libcamera.cpp +++ b/test/test_libcamera.cpp @@ -32,9 +32,10 @@ int main(int argc, char *argv[]) { auto capturer = LibcameraCapturer::Create(args); - auto observer = capturer->AsRawBufferObservable(); - observer->Subscribe([&](V4L2Buffer buffer) { + auto observer = capturer->AsFrameBufferObservable(); + observer->Subscribe([&](rtc::scoped_refptr frame_buffer) { if (i < images_nb) { + auto buffer = frame_buffer->GetRawBuffer(); WriteImage(buffer.start, buffer.length, ++i); } else { is_finished = true; diff --git a/test/test_v4l2_encoder.cpp b/test/test_v4l2_encoder.cpp index c1666d3c..f559f053 100644 --- a/test/test_v4l2_encoder.cpp +++ b/test/test_v4l2_encoder.cpp @@ -1,5 +1,5 @@ #include "args.h" -#include "capturer/v4l2_capturer.h" +#include "capturer/libcamera_capturer.h" #include "codecs/v4l2/v4l2_encoder.h" #include @@ -15,20 +15,20 @@ int main(int argc, char *argv[]) { bool is_finished = false; bool has_first_keyframe_ = false; int images_nb = 0; - int record_sec = 10; + int record_sec = 100; Args args{ .cameraId = 0, .fps = 30, - .width = 1280, - .height = 960, - .format = V4L2_PIX_FMT_YUYV, + .width = 1920, + .height = 1080, + .format = V4L2_PIX_FMT_YUV420, .hw_accel = true, }; - auto capturer = V4L2Capturer::Create(args); + auto capturer = LibcameraCapturer::Create(args); auto observer = capturer->AsFrameBufferObservable(); - auto encoder = V4L2Encoder::Create(args.width, args.height, V4L2_PIX_FMT_YUYV, false); + auto encoder = V4L2Encoder::Create(args.width, args.height, V4L2_PIX_FMT_YUV420, true); int cam_frame_count = 0; auto cam_start_time = std::chrono::steady_clock::now(); From 0abd9d8deab10221d09d402dd6b28e87a11edfd3 Mon Sep 17 00:00:00 2001 From: TzuHuanTai Date: Wed, 25 Jun 2025 08:28:22 -0700 Subject: [PATCH 2/3] fix: replace exit with runtime error --- src/common/v4l2_utils.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/common/v4l2_utils.cpp b/src/common/v4l2_utils.cpp index afc930d9..af2abc30 100644 --- a/src/common/v4l2_utils.cpp +++ b/src/common/v4l2_utils.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -37,7 +38,7 @@ int V4L2Util::OpenDevice(const char *file) { int fd = open(file, O_RDWR); if (fd < 0) { ERROR_PRINT("v4l2 open(%s): %s", file, strerror(errno)); - exit(-1); + throw std::runtime_error("failed to open v4l2 device"); } DEBUG_PRINT("Open file %s fd(%d) success!", file, fd); return fd; @@ -170,7 +171,7 @@ bool V4L2Util::SetFormat(int fd, V4L2BufferGroup *gbuffer, int width, int height if (fmt.fmt.pix_mp.width != width || fmt.fmt.pix_mp.height != height) { ERROR_PRINT("fd(%d) input size (%dx%d) doesn't match driver's output size (%dx%d): %s", fd, width, height, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height, strerror(EINVAL)); - exit(0); + throw std::runtime_error("the frame size doesn't match"); } return true; From 866e96b7b290b69491dfba155c1b0fb2617d4cd2 Mon Sep 17 00:00:00 2001 From: TzuHuanTai Date: Wed, 25 Jun 2025 09:16:44 -0700 Subject: [PATCH 3/3] chore: update to v1.1.2 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 42c819f8..89cd7ef2 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,8 @@ sudo apt install libcamera0.5 libmosquitto1 pulseaudio libavformat59 libswscale6 Get the latest [release binary](https://github.com/TzuHuanTai/RaspberryPi-WebRTC/releases) . ```bash -wget https://github.com/TzuHuanTai/RaspberryPi-WebRTC/releases/latest/download/pi-webrtc-v1.1.1_raspios-bookworm-arm64.tar.gz -tar -xzf pi-webrtc-v1.1.1_raspios-bookworm-arm64.tar.gz +wget https://github.com/TzuHuanTai/RaspberryPi-WebRTC/releases/latest/download/pi-webrtc-v1.1.2_raspios-bookworm-arm64.tar.gz +tar -xzf pi-webrtc-v1.1.2_raspios-bookworm-arm64.tar.gz ``` ### 4. MQTT Signaling