add export timelapse
This commit is contained in:
@@ -171,6 +171,9 @@
|
||||
<button-custom id="file-submenu-export-anim" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
|
||||
<text text="Animation Frames" grow="1" margin="0 0 0 5"/>
|
||||
</button-custom>
|
||||
<button-custom id="file-submenu-export-timelapse" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
|
||||
<text text="Timelapse" grow="1" margin="0 0 0 5"/>
|
||||
</button-custom>
|
||||
</popup-menu>
|
||||
</layout>
|
||||
|
||||
@@ -201,6 +204,7 @@
|
||||
<!-- MENU TOOLS -->
|
||||
<layout id="tools-menu">
|
||||
<popup-menu positioning="absolute" position="100 100" width="150" thickness="1" border-color=".1" color=".4 .4 .4 .8" dir="col">
|
||||
<!--
|
||||
<border dir="row" flood-events="1">
|
||||
<button-custom id="tools-timelapse" height="40" align="center" color=".2" pad="0 0 0 10" dir="row" grow="1">
|
||||
<text text="Timelapse" grow="1" margin="0 0 0 5"/>
|
||||
@@ -209,6 +213,7 @@
|
||||
<icon icon="resultset_next" width="20"/>
|
||||
</button-custom>
|
||||
</border>
|
||||
-->
|
||||
<border dir="row" flood-events="1" >
|
||||
<button-custom id="tools-panels" height="40" align="center" color=".2" pad="0 0 0 10" dir="row" grow="1">
|
||||
<text text="Panels" grow="1" margin="0 0 0 5"/>
|
||||
@@ -249,10 +254,12 @@
|
||||
<icon icon="pencil" width="20"/>
|
||||
<text id="menu-label" text="Start SonarPen" margin="0 0 0 5"/>
|
||||
</button-custom>
|
||||
<!--
|
||||
<button-custom id="mp4test" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
|
||||
<icon icon="pencil" width="20"/>
|
||||
<text id="menu-label" text="Test MP4 Export" margin="0 0 0 5"/>
|
||||
</button-custom>
|
||||
-->
|
||||
</popup-menu>
|
||||
</layout>
|
||||
|
||||
|
||||
@@ -794,7 +794,7 @@ void App::rec_loop()
|
||||
{
|
||||
std::unique_ptr<Image> frame;
|
||||
std::unique_lock<std::mutex> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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] {
|
||||
|
||||
@@ -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<float>(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<Image>(equirect.get_image());
|
||||
{
|
||||
|
||||
@@ -611,38 +611,45 @@ void App::init_menu_file()
|
||||
layout[main_id]->add_child(subpopup);
|
||||
subpopup->find<NodeButtonCustom>("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<NodeButtonCustom>("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<NodeButtonCustom>("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<NodeButtonCustom>("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<NodeButtonCustom>("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<NodeButtonCustom>("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<NodeButtonCustom>("file-share"))
|
||||
@@ -1037,11 +1044,13 @@ void App::init_menu_tools()
|
||||
popup_exp->destroy();
|
||||
};
|
||||
|
||||
/*
|
||||
popup_exp->find<NodeButtonCustom>("mp4test")->on_click = [this, popup_exp](Node*) {
|
||||
dialog_export_mp4();
|
||||
popup_exp->mouse_release();
|
||||
popup_exp->destroy();
|
||||
};
|
||||
*/
|
||||
|
||||
#if __IOS__
|
||||
popup_exp->find<NodeButtonCustom>("sonarpen")->on_click = [this, popup_exp](Node*) {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user