80 lines
3.7 KiB
C++
80 lines
3.7 KiB
C++
#pragma once
|
|
|
|
#include "fgc/ICameraSource.h"
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
namespace fgc {
|
|
|
|
// Several camera sources behind one, so the scheduler and the pipeline keep
|
|
// seeing a single camera array: the colour cameras through Vimba and the
|
|
// thermal one through its own SDK take their pictures at the same waypoints
|
|
// and intervals without either knowing about the other.
|
|
//
|
|
// The first child leads. Its cameras come first in the index order (camera 0
|
|
// is its first camera, which the keep rule reads), and its trigger() decides
|
|
// whether a picture was taken: only once it has delivered are the others
|
|
// asked, so a retry while the leader waits never yields a second thermal
|
|
// frame for the same waypoint. The others are best effort - a follower with
|
|
// no fresh frame costs that picture its thermal image, nothing more.
|
|
//
|
|
// Every frame keeps its own time, when it reached the host: the thermal frame
|
|
// is the newest the camera had, so its time is up to max_frame_age_ms off the
|
|
// colour one, and that is what the file name and the CamEvent say.
|
|
//
|
|
// A follower that is briefly without a fresh frame (frameReady() false: the
|
|
// thermal camera's NUC) holds the picture back for up to `follower_wait_ms`,
|
|
// so the pair stays whole; past that the leader goes on alone.
|
|
//
|
|
// Indices are global: child k's camera i is offset(k) + i. Calls about one
|
|
// camera go to the child that has it.
|
|
//
|
|
// The offsets come from `counts`, how many cameras each child is configured
|
|
// with, not from cameraCount(): VimbaCameraSource counts what it has opened,
|
|
// which is 0 before open(), and a thermal frame numbered from that landed as
|
|
// camera 0 - the colour camera's label and file (seen on tower 111). Without
|
|
// counts, each child's cameraCount() at construction is taken.
|
|
class CompositeCameraSource : public ICameraSource {
|
|
public:
|
|
explicit CompositeCameraSource(std::vector<std::unique_ptr<ICameraSource>> children,
|
|
std::vector<int> counts = {}, int follower_wait_ms = 1000);
|
|
|
|
void open() override;
|
|
void close() override;
|
|
void start() override;
|
|
void stop() override;
|
|
bool trigger() override;
|
|
void moving() override;
|
|
bool frameReady() override;
|
|
bool setProfile(int camera_index, const CameraProfile& profile) override;
|
|
void setFrameCallback(FrameCallback cb) override;
|
|
uint64_t frameSeq() override;
|
|
std::vector<FrameStats> framesSince(uint64_t after) override;
|
|
bool readFeature(int camera_index, const std::string& name, double& value) override;
|
|
int cameraCount() const override;
|
|
std::vector<CameraDeviceInfo> deviceInfo() override;
|
|
std::string offline(int camera_index) override;
|
|
bool grabFrame(int camera_index, Frame& out, int timeout_ms) override;
|
|
bool setFeature(int camera_index, const std::string& name, const std::string& value) override;
|
|
bool featureRange(int camera_index, const std::string& name, double& min, double& max) override;
|
|
bool restoreProfile(int camera_index) override;
|
|
bool resetCamera(int camera_index) override;
|
|
|
|
size_t childCount() const { return children_.size(); }
|
|
ICameraSource& child(size_t k) { return *children_[k]; }
|
|
|
|
private:
|
|
// The child holding a global index and its index there; nullptr if none.
|
|
ICameraSource* route(int camera_index, int& local) const;
|
|
|
|
std::vector<std::unique_ptr<ICameraSource>> children_;
|
|
std::vector<int> counts_; // cameras each child is configured with
|
|
std::vector<int> offsets_; // global index of each child's camera 0
|
|
FrameCallback callback_;
|
|
int follower_wait_ms_;
|
|
long long waiting_since_ = 0; // steady ms a picture began waiting for a follower
|
|
};
|
|
|
|
} // namespace fgc
|