diff --git a/data/layout.xml b/data/layout.xml
index 62befa7..4658004 100644
--- a/data/layout.xml
+++ b/data/layout.xml
@@ -171,6 +171,9 @@
+
@@ -201,6 +204,7 @@
diff --git a/src/app.cpp b/src/app.cpp
index 534cce4..37132f4 100644
--- a/src/app.cpp
+++ b/src/app.cpp
@@ -794,7 +794,7 @@ void App::rec_loop()
{
std::unique_ptr frame;
std::unique_lock lock(rec_mutex);
- rec_cv.wait(lock);
+ rec_cv.wait(lock, [this] { return !(rec_frames.empty() && rec_running); });
if (!rec_running)
break;
if (!rec_frames.empty())
@@ -808,7 +808,10 @@ void App::rec_loop()
}
lock.unlock();
if (frame && Canvas::I->m_encoder)
+ {
Canvas::I->m_encoder->encode(*frame);
+ LOG("frame encoded");
+ }
update_rec_frames();
}
}
diff --git a/src/app.h b/src/app.h
index c0c8d29..7cf7753 100644
--- a/src/app.h
+++ b/src/app.h
@@ -257,6 +257,7 @@ public:
void dialog_preset_download();
void dialog_ppbr_export();
void dialog_export_mp4();
+ void dialog_timelapse_export();
void cloud_upload();
void cloud_upload_all();
diff --git a/src/app_dialogs.cpp b/src/app_dialogs.cpp
index 631aac0..a3b4d1b 100644
--- a/src/app_dialogs.cpp
+++ b/src/app_dialogs.cpp
@@ -646,6 +646,28 @@ void App::dialog_ppbr_export()
};
}
+void App::dialog_timelapse_export()
+{
+#if __IOS__ || __WEB__
+ pick_file_save("mp4",
+ [this](std::string path) {
+ rec_export(path);
+ },
+ [this](bool saved) {
+ message_box("Export Timelapse", "Timelapse exported succesfully.");
+ }
+ );
+#else
+ pick_file_save({ "mp4" }, [this](std::string path) {
+ std::thread([this, path] {
+ BT_SetTerminate();
+ rec_export(path);
+ message_box("Export Timelapse", "Timelapse exported to: " + path);
+ }).detach();
+ });
+#endif
+}
+
void App::dialog_export_mp4()
{
std::thread([this] {
diff --git a/src/app_events.cpp b/src/app_events.cpp
index 7a1390c..ff3244f 100644
--- a/src/app_events.cpp
+++ b/src/app_events.cpp
@@ -80,11 +80,11 @@ void App::tick(float dt)
if (auto* main = layout[main_id])
main->tick(dt);
- if (rec_running)
+ if (rec_running && Canvas::I->m_encoder)
{
auto t_now = std::chrono::high_resolution_clock::now();
float dt = std::chrono::duration(t_now - canvas->m_canvas->m_disrty_stroke_time).count();
- if (dt > 1.f && canvas->m_canvas->m_dirty_stroke)
+ if (dt > 0.1f && canvas->m_canvas->m_dirty_stroke)
{
canvas->m_canvas->m_dirty_stroke = false;
LOG("rec tick");
@@ -92,7 +92,7 @@ void App::tick(float dt)
Texture2D equirect;
App::I->render_task([&] {
Canvas::I->draw_merge(true);
- equirect = Canvas::I->m_layers_merge.gen_equirect({ 1024, 512 });
+ equirect = Canvas::I->m_layers_merge.gen_equirect(Canvas::I->m_encoder->frame_size() / 4);
});
auto img = std::make_unique(equirect.get_image());
{
diff --git a/src/app_layout.cpp b/src/app_layout.cpp
index 610cbec..24439f2 100644
--- a/src/app_layout.cpp
+++ b/src/app_layout.cpp
@@ -611,38 +611,45 @@ void App::init_menu_file()
layout[main_id]->add_child(subpopup);
subpopup->find("file-submenu-export-png")->on_click = [this, subpopup, popup](Node*) {
dialog_export(".png");
- subpopup->mouse_release();
- subpopup->destroy();
popup->mouse_release();
popup->destroy();
+ subpopup->mouse_release();
+ subpopup->destroy();
};
subpopup->find("file-submenu-export-layers")->on_click = [this, subpopup, popup](Node*) {
dialog_export_layers();
- subpopup->mouse_release();
- subpopup->destroy();
popup->mouse_release();
popup->destroy();
+ subpopup->mouse_release();
+ subpopup->destroy();
};
subpopup->find("file-submenu-export-cube")->on_click = [this, subpopup, popup](Node*) {
dialog_export_cube_faces();
- subpopup->mouse_release();
- subpopup->destroy();
popup->mouse_release();
popup->destroy();
+ subpopup->mouse_release();
+ subpopup->destroy();
};
subpopup->find("file-submenu-export-depth")->on_click = [this, subpopup, popup](Node*) {
dialog_export_depth();
- subpopup->mouse_release();
- subpopup->destroy();
popup->mouse_release();
popup->destroy();
+ subpopup->mouse_release();
+ subpopup->destroy();
};
subpopup->find("file-submenu-export-anim")->on_click = [this, subpopup, popup](Node*) {
dialog_export_layers();
- subpopup->mouse_release();
- subpopup->destroy();
popup->mouse_release();
popup->destroy();
+ subpopup->mouse_release();
+ subpopup->destroy();
+ };
+ subpopup->find("file-submenu-export-timelapse")->on_click = [this, subpopup, popup](Node*) {
+ dialog_timelapse_export();
+ popup->mouse_release();
+ popup->destroy();
+ subpopup->mouse_release();
+ subpopup->destroy();
};
};
if (auto b = popup->find("file-share"))
@@ -1037,11 +1044,13 @@ void App::init_menu_tools()
popup_exp->destroy();
};
+/*
popup_exp->find("mp4test")->on_click = [this, popup_exp](Node*) {
dialog_export_mp4();
popup_exp->mouse_release();
popup_exp->destroy();
};
+*/
#if __IOS__
popup_exp->find("sonarpen")->on_click = [this, popup_exp](Node*) {
diff --git a/src/mp4enc.h b/src/mp4enc.h
index 063aecc..54dcf98 100644
--- a/src/mp4enc.h
+++ b/src/mp4enc.h
@@ -34,6 +34,7 @@ public:
bool write_mp4(const std::string& filename) const noexcept;
void destroy() noexcept;
int frames_count() const noexcept { return m_frames.size(); }
+ glm::ivec2 frame_size() const noexcept { return { m_width, m_height }; }
virtual bool read(BinaryStreamReader& r) override;
virtual void write(BinaryStreamWriter& w) const override;
};