diff --git a/applications/gui/src/camera.cpp b/applications/gui/src/camera.cpp index 38f6c5f779ec2c23d334bd31ee3f5c5a65727777..9d8dac421d0189c978dbc0312302f2b34349945c 100644 --- a/applications/gui/src/camera.cpp +++ b/applications/gui/src/camera.cpp @@ -524,11 +524,8 @@ const GLTexture &ftl::gui::Camera::captureFrame() { return texture1_; } -void ftl::gui::Camera::snapshot() { +void ftl::gui::Camera::snapshot(const std::string &filename) { UNIQUE_LOCK(mutex_, lk); - char timestamp[18]; - std::time_t t = std::time(NULL); - std::strftime(timestamp, sizeof(timestamp), "%F-%H%M%S", std::localtime(&t)); cv::Mat blended; cv::Mat visualized = visualizeActiveChannel(); if (!visualized.empty()) { @@ -539,7 +536,7 @@ void ftl::gui::Camera::snapshot() { } cv::Mat flipped; cv::flip(blended, flipped, 0); - cv::imwrite(std::string(timestamp) + ".png", flipped); + cv::imwrite(filename, flipped); } void ftl::gui::Camera::startVideoRecording(const std::string &filename) { diff --git a/applications/gui/src/camera.hpp b/applications/gui/src/camera.hpp index fe477f624ed42c8fdca4535355b914a4676540e4..90914cf599942107f8d7bbba8b8f5a9505f815e9 100644 --- a/applications/gui/src/camera.hpp +++ b/applications/gui/src/camera.hpp @@ -52,7 +52,7 @@ class Camera { bool thumbnail(cv::Mat &thumb); - void snapshot(); + void snapshot(const std::string &filename); void startVideoRecording(const std::string &filename); diff --git a/applications/gui/src/media_panel.cpp b/applications/gui/src/media_panel.cpp index c576f28f63cd4edc35a56768f50f27c2818631a2..1a6f288ce788f1b808c2eb0b42515b5b8ca37c83 100644 --- a/applications/gui/src/media_panel.cpp +++ b/applications/gui/src/media_panel.cpp @@ -47,23 +47,10 @@ MediaPanel::MediaPanel(ftl::gui::Screen *screen, ftl::gui::SourceWindow *sourceW recordpopup->setAnchorHeight(150); auto itembutton = new Button(recordpopup, "2D snapshot (.png)"); itembutton->setCallback([this,recordbutton]() { - screen_->activeCamera()->snapshot(); - recordbutton->setPushed(false); - }); - itembutton = new Button(recordpopup, "3D snapshot (.ftl)"); - itembutton->setCallback([this,recordbutton]() { - auto tag = screen_->activeCamera()->source()->get<std::string>("uri"); - if (tag) { - auto tagvalue = tag.value(); - auto configurables = ftl::config::findByTag(tagvalue); - if (configurables.size() > 0) { - ftl::Configurable *configurable = configurables[0]; - char timestamp[18]; - std::time_t t=std::time(NULL); - std::strftime(timestamp, sizeof(timestamp), "%F-%H%M%S", std::localtime(&t)); - configurable->set("3D-snapshot", std::string(timestamp) + ".ftl"); - } - } + char timestamp[18]; + std::time_t t=std::time(NULL); + std::strftime(timestamp, sizeof(timestamp), "%F-%H%M%S", std::localtime(&t)); + screen_->activeCamera()->snapshot(std::string(timestamp) + ".png"); recordbutton->setPushed(false); }); itembutton = new Button(recordpopup, "Virtual camera recording (.ftl)"); @@ -76,24 +63,26 @@ MediaPanel::MediaPanel(ftl::gui::Screen *screen, ftl::gui::SourceWindow *sourceW recordbutton->setTextColor(nanogui::Color(1.0f,0.1f,0.1f,1.0f)); recordbutton->setPushed(false); }); + itembutton = new Button(recordpopup, "3D scene snapshot (.ftl)"); + itembutton->setCallback([this,recordbutton]() { + char timestamp[18]; + std::time_t t=std::time(NULL); + std::strftime(timestamp, sizeof(timestamp), "%F-%H%M%S", std::localtime(&t)); + snapshot3D(screen_->activeCamera(), std::string(timestamp) + ".ftl"); + recordbutton->setPushed(false); + }); itembutton = new Button(recordpopup, "3D scene recording (.ftl)"); itembutton->setCallback([this,recordbutton]() { - auto tag = screen_->activeCamera()->source()->get<std::string>("uri"); - if (tag) { - auto tagvalue = tag.value(); - auto configurables = ftl::config::findByTag(tagvalue); - if (configurables.size() > 0) { - ftl::Configurable *configurable = configurables[0]; - configurable->set("record", true); - recordbutton->setTextColor(nanogui::Color(1.0f,0.1f,0.1f,1.0f)); - sceneRecording_ = std::optional<ftl::Configurable*>(configurable); - } - } + char timestamp[18]; + std::time_t t=std::time(NULL); + std::strftime(timestamp, sizeof(timestamp), "%F-%H%M%S", std::localtime(&t)); + startRecording3D(screen_->activeCamera(), std::string(timestamp) + ".ftl"); + recordbutton->setTextColor(nanogui::Color(1.0f,0.1f,0.1f,1.0f)); recordbutton->setPushed(false); }); itembutton = new Button(recordpopup, "Detailed recording options"); itembutton->setCallback([this,sourceWindow,recordbutton] { - auto record_window = new RecordWindow(screen_, sourceWindow->getCameras(), this); + auto record_window = new RecordWindow(screen_, screen_, sourceWindow->getCameras(), this); record_window->setTheme(screen_->windowtheme); recordbutton->setPushed(false); }); @@ -308,4 +297,30 @@ void MediaPanel::cameraChanged() { void MediaPanel::toggleVirtualCameraRecording(ftl::gui::Camera *camera, const std::string &filename) { camera->startVideoRecording(filename); virtualCameraRecording_ = std::optional<ftl::gui::Camera*>(camera); +} + +void MediaPanel::snapshot3D(ftl::gui::Camera *camera, const std::string &filename) { + auto tag = camera->source()->get<std::string>("uri"); + if (tag) { + auto tagvalue = tag.value(); + auto configurables = ftl::config::findByTag(tagvalue); + if (configurables.size() > 0) { + ftl::Configurable *configurable = configurables[0]; + configurable->set("3D-snapshot", filename); + } + } +} + +void MediaPanel::startRecording3D(ftl::gui::Camera *camera, const std::string &filename) { + auto tag = camera->source()->get<std::string>("uri"); + if (tag) { + auto tagvalue = tag.value(); + auto configurables = ftl::config::findByTag(tagvalue); + if (configurables.size() > 0) { + ftl::Configurable *configurable = configurables[0]; + configurable->set("record-name", filename); + configurable->set("record", true); + sceneRecording_ = std::optional<ftl::Configurable*>(configurable); + } + } } \ No newline at end of file diff --git a/applications/gui/src/media_panel.hpp b/applications/gui/src/media_panel.hpp index b7e5957cca4e6c171972013448229df8bd364f4c..a71ee81838d87bd9af4183e60e45dd4c7dfd92b1 100644 --- a/applications/gui/src/media_panel.hpp +++ b/applications/gui/src/media_panel.hpp @@ -26,6 +26,10 @@ class MediaPanel : public nanogui::Window { void toggleVirtualCameraRecording(ftl::gui::Camera *camera, const std::string &filename); + void snapshot3D(ftl::gui::Camera *camera, const std::string &filename); + + void startRecording3D(ftl::gui::Camera *camera, const std::string &filename); + private: ftl::gui::Screen *screen_; diff --git a/applications/gui/src/record_window.cpp b/applications/gui/src/record_window.cpp index 82b333bc9cd0b568697725b8b3e564a9df73c82f..50cdf9d3ed7e0a5277a52b976108deae4c82adc0 100644 --- a/applications/gui/src/record_window.cpp +++ b/applications/gui/src/record_window.cpp @@ -1,5 +1,7 @@ #include "record_window.hpp" +#include "screen.hpp" + #include <ftl/codecs/channels.hpp> #include <nanogui/layout.h> @@ -11,7 +13,7 @@ using ftl::gui::RecordWindow; -RecordWindow::RecordWindow(nanogui::Widget *parent, const std::vector<ftl::gui::Camera *> &streams, ftl::gui::MediaPanel *media_panel) +RecordWindow::RecordWindow(nanogui::Widget *parent, ftl::gui::Screen *screen, const std::vector<ftl::gui::Camera *> &streams, ftl::gui::MediaPanel *media_panel) : nanogui::Window(parent, "Recording options") { using namespace nanogui; @@ -54,23 +56,42 @@ RecordWindow::RecordWindow(nanogui::Widget *parent, const std::vector<ftl::gui:: new Label(recording2D, "Select channel (in addition to Left)", "sans-bold"); auto recordingChannel = recording2D->add<ComboBox>(); streamSelect->setCallback([this,streams,snapshotChannel,recordingChannel](int ix) { - channels_ = std::vector<std::string>(); + channels_ = std::vector<ftl::codecs::Channel>(); + channel_names_ = std::vector<std::string>(); ftl::codecs::Channels availableChannels = streams[ix]->availableChannels(); for (auto c : availableChannels) { - channels_.push_back(ftl::codecs::name(c)); + channels_.push_back(c); + channel_names_.push_back(ftl::codecs::name(c)); } - snapshotChannel->setItems(channels_); - recordingChannel->setItems(channels_); + snapshotChannel->setItems(channel_names_); + recordingChannel->setItems(channel_names_); }); Widget *actionButtons = new Widget(this); actionButtons->setLayout(new BoxLayout(Orientation::Horizontal)); auto button = new Button(actionButtons, "Start"); - button->setCallback([streams,streamSelect,media_panel,fileName]() { + button->setCallback([this,streams,streamSelect,screen,media_panel,fileName,tabWidget,snapshot2D,recording2D,snapshot3D,recording3D,snapshotChannel,recordingChannel]() { // Check the chosen stream type and channels, then record them. auto stream = streams[streamSelect->selectedIndex()]; - // TODO: If the camera isn't active, no frames are currently received. - media_panel->toggleVirtualCameraRecording(stream, fileName->value()); + auto tab = tabWidget->tab(tabWidget->activeTab()); + if (tab == snapshot2D) { + // If the channel isn't the same as the one that was active + // previously, the channel won't have an image. + // One possible solution is to set the channels immediately + // as they are chosen in the recording window. + // Alternatively, 2D snapshots might not need a channel option at all. + stream->setChannel(channels_[snapshotChannel->selectedIndex()]); + stream->snapshot(fileName->value()); + } else if (tab == recording2D) { + stream->setChannel(channels_[recordingChannel->selectedIndex()]); + screen->setActiveCamera(stream); + media_panel->toggleVirtualCameraRecording(stream, fileName->value()); + } else if (tab == snapshot3D) { + media_panel->snapshot3D(stream, fileName->value()); + } else if (tab == recording3D) { + media_panel->startRecording3D(stream, fileName->value()); + } + dispose(); }); button = new Button(actionButtons, "Cancel"); button->setCallback([this]() { diff --git a/applications/gui/src/record_window.hpp b/applications/gui/src/record_window.hpp index 4396c04569e908ee58bc64fdc9c0cca94a488c97..5a9b28fef85b5ef2832b7a43b2db1be2b09aa202 100644 --- a/applications/gui/src/record_window.hpp +++ b/applications/gui/src/record_window.hpp @@ -8,11 +8,12 @@ namespace gui { class RecordWindow : public nanogui::Window { public: - explicit RecordWindow(nanogui::Widget *parent, const std::vector<ftl::gui::Camera *> &streams, ftl::gui::MediaPanel *media_panel); + explicit RecordWindow(nanogui::Widget *parent, ftl::gui::Screen *screen, const std::vector<ftl::gui::Camera *> &streams, ftl::gui::MediaPanel *media_panel); ~RecordWindow(); private: - std::vector<std::string> channels_; + std::vector<ftl::codecs::Channel> channels_; + std::vector<std::string> channel_names_; }; } diff --git a/applications/reconstruct/src/main.cpp b/applications/reconstruct/src/main.cpp index 66d6e3189eb3b2ed13dbe86b8f7f47a2cf4905cb..3a5807171ec9d83057291d32e6ba20c027609647 100644 --- a/applications/reconstruct/src/main.cpp +++ b/applications/reconstruct/src/main.cpp @@ -294,7 +294,7 @@ static void run(ftl::Configurable *root) { char timestamp[18]; std::time_t t=std::time(NULL); std::strftime(timestamp, sizeof(timestamp), "%F-%H%M%S", std::localtime(&t)); - fileout.open(std::string(timestamp) + ".ftl"); + fileout.open(e.entity->value<std::string>("record-name", std::string(timestamp) + ".ftl")); writer.begin(); group->addRawCallback(std::function(recorder));