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..2742ccc6 100644 --- a/core/video_options.hpp +++ b/core/video_options.hpp @@ -159,6 +159,8 @@ struct VideoOptions : public Options "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.") #endif + ("sync", value(&sync_)->default_value("off"), + "Whether to synchronise with another camera. Use \"off\", \"server\" or \"client\".") ; // 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_; };