From 555c5390974dcbec0d1df94d2ba63e2c7f760544 Mon Sep 17 00:00:00 2001 From: Naushir Patuck Date: Thu, 20 Jun 2024 09:25:16 +0100 Subject: [PATCH] rpicam-vid: Update for camera sync algorithm A "sync" option has been added, which may take the values "server" or "client", turning the camera into either the server of client of a synchronised recording. Setting the camera into sync mode, and skipping frames while waiting for sync, is delegated to the RPiCamEncoder class, so that all video recording applications acquire the functionality. Signed-off-by: David Plowman Signed-off-by: Arsen Mikovic Signed-off-by: Naushir Patuck --- .gitignore | 1 + apps/rpicam_vid.cpp | 1 - core/rpicam_encoder.hpp | 17 +++++++++++++++++ core/video_options.hpp | 14 ++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index dee53c53..829bbf74 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build *~ +.vscode/ diff --git a/apps/rpicam_vid.cpp b/apps/rpicam_vid.cpp index 800663d3..c016ee27 100644 --- a/apps/rpicam_vid.cpp +++ b/apps/rpicam_vid.cpp @@ -117,7 +117,6 @@ static void event_loop(RPiCamEncoder &app) app.StopEncoder(); return; } - CompletedRequestPtr &completed_request = std::get(msg.payload); app.EncodeBuffer(completed_request, app.VideoStream()); app.ShowPreview(completed_request, app.VideoStream()); diff --git a/core/rpicam_encoder.hpp b/core/rpicam_encoder.hpp index 86908303..420fdcef 100644 --- a/core/rpicam_encoder.hpp +++ b/core/rpicam_encoder.hpp @@ -29,6 +29,18 @@ class RPiCamEncoder : public RPiCamApp createEncoder(); encoder_->SetInputDoneCallback(std::bind(&RPiCamEncoder::encodeBufferDone, this, std::placeholders::_1)); encoder_->SetOutputReadyCallback(encode_output_ready_callback_); + + // Set up the encode function to wait for synchronisation with another camera system, + // when this has been requested in the options. + VideoOptions const *options = GetOptions(); + libcamera::ControlList cl; + if (options->sync == 0) + cl.set(libcamera::controls::rpi::SyncMode, libcamera::controls::rpi::SyncModeOff); + else if (options->sync == 1) + cl.set(libcamera::controls::rpi::SyncMode, libcamera::controls::rpi::SyncModeServer); + else if (options->sync == 2) + cl.set(libcamera::controls::rpi::SyncMode, libcamera::controls::rpi::SyncModeClient); + SetControls(cl); } // This is callback when the encoder gives you the encoded output data. void SetEncodeOutputReadyCallback(EncodeOutputReadyCallback callback) { encode_output_ready_callback_ = callback; } @@ -36,6 +48,11 @@ class RPiCamEncoder : public RPiCamApp void EncodeBuffer(CompletedRequestPtr &completed_request, Stream *stream) { assert(encoder_); + + // If sync was enabled, and the SyncWait metadata is still "true" then we must skip this frame. + if (GetOptions()->sync && completed_request->metadata.get(controls::rpi::SyncWait).value_or(true)) + return; + StreamInfo info = GetStreamInfo(stream); FrameBuffer *buffer = completed_request->buffers[stream]; BufferReadSync r(this, buffer); diff --git a/core/video_options.hpp b/core/video_options.hpp index 918596ab..21ba6db1 100644 --- a/core/video_options.hpp +++ b/core/video_options.hpp @@ -158,6 +158,8 @@ struct VideoOptions : public Options ("av-sync", value(&av_sync_)->default_value("0us"), "Add a time offset (in microseconds if no units provided) to the audio stream, relative to the video stream. " "The offset value can be either positive or negative.") + ("sync", value(&sync_)->default_value("off"), + "Whether to synchronise with another camera. Use \"off\", \"server\" or \"client\".") #endif ; // clang-format on @@ -191,6 +193,7 @@ struct VideoOptions : public Options uint32_t segment; size_t circular; uint32_t frames; + uint32_t sync; virtual bool Parse(int argc, char *argv[]) override { @@ -235,6 +238,15 @@ struct VideoOptions : public Options level = "4.2"; } + if (strcasecmp(sync_.c_str(), "off") == 0) + sync = 0; + else if (strcasecmp(sync_.c_str(), "server") == 0) + sync = 1; + else if (strcasecmp(sync_.c_str(), "client") == 0) + sync = 2; + else + throw std::runtime_error("incorrect sync value " + sync_); + return true; } virtual void Print() const override @@ -254,6 +266,7 @@ struct VideoOptions : public Options std::cerr << " split: " << split << std::endl; std::cerr << " segment: " << segment << std::endl; std::cerr << " circular: " << circular << std::endl; + std::cerr << " sync: " << sync << std::endl; } private: @@ -262,4 +275,5 @@ struct VideoOptions : public Options std::string av_sync_; std::string audio_bitrate_; #endif /* LIBAV_PRESENT */ + std::string sync_; };