33// Read LICENSE.txt for more information.
44
55#include < cmd/Command.hpp>
6+ #include < common/Config.hpp>
67#include < common/Messages.hpp>
78#include < common/PubSub.hpp>
89#include < doc/Cell.hpp>
1213#include < gui/Controller.hpp>
1314#include < gui/Node.hpp>
1415#include < log/Log.hpp>
16+ #include < optional>
17+ #include < task/TaskManager.hpp>
1518
1619namespace msg {
1720struct RecorderStart {};
1821struct RecorderStop {};
1922struct RecorderUpdateSequence {U32 number;};
23+ struct RecorderEncodingStart {};
24+ struct RecorderEncodingDone {};
25+ struct RecorderEncodingFail {};
2026}
2127
2228U32 initSequence () {
@@ -41,6 +47,47 @@ U32& sequence() {
4147 return num;
4248}
4349
50+ class Encoder {
51+ public:
52+ TaskHandle handle;
53+
54+ bool done () {
55+ return handle.task ->isDone ();
56+ }
57+
58+ void run () {
59+ String cmd;
60+ PubSub<>::pub (msg::RecorderEncodingStart{});
61+
62+ auto userdata = std::filesystem::path{inject<FileSystem>{}->find (" %userdata" , " dir" )->getUID ()};
63+ cmd += " cd " + join (split (userdata.string (), " \\ " ), " \\\\ " ) + " && " ;
64+
65+ cmd += " \" " ;
66+ if (auto ffmpeg = inject<Config>{}->properties ->get <String>(" ffmpeg-path" ); ffmpeg.empty ()) {
67+ cmd += " ffmpeg" ;
68+ } else {
69+ cmd += join (split (ffmpeg, " \\ " ), " \\\\ " );
70+ }
71+ cmd += " \" -y " ;
72+ cmd += " -start_number 1 -i \" recording_%d.png\" -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4" ;
73+
74+ logI (cmd);
75+
76+ handle = inject<TaskManager>{}->add (
77+ [=]() -> int {
78+ return system (cmd.c_str ());
79+ },
80+ [=](int code){
81+ if (code == 0 ) {
82+ PubSub<>::pub (msg::RecorderEncodingDone{});
83+ } else {
84+ PubSub<>::pub (msg::RecorderEncodingFail{});
85+ }
86+ });
87+ }
88+ };
89+ static std::optional<Encoder> encoder;
90+
4491class Recorder {
4592 PubSub<msg::ModifyDocument,
4693 msg::Tick> pub{this };
@@ -118,6 +165,43 @@ class RecorderSequence : public ui::Controller {
118165};
119166static ui::Controller::Shared<RecorderSequence> recseq{" recordersequence" };
120167
168+ class RecorderEncode : public ui ::Controller {
169+ public:
170+ PubSub<msg::RecorderEncodingStart,
171+ msg::RecorderEncodingDone,
172+ msg::RecorderEncodingFail,
173+ msg::RecorderUpdateSequence> pub{this };
174+ Property<String> label{this , " label" , " ${value}" };
175+
176+ void attach () override {
177+ if (encoder) {
178+ if (encoder->done ())
179+ on (msg::RecorderEncodingDone{});
180+ else
181+ on (msg::RecorderEncodingStart{});
182+ } else {
183+ on (msg::RecorderUpdateSequence{});
184+ }
185+ }
186+
187+ void on (const msg::RecorderUpdateSequence&) {
188+ node ()->set (" text" , " Encode MP4" );
189+ }
190+
191+ void on (const msg::RecorderEncodingDone&) {
192+ node ()->set (" text" , " Encoding Done" );
193+ }
194+
195+ void on (const msg::RecorderEncodingStart&) {
196+ node ()->set (" text" , " Encoding MP4" );
197+ }
198+
199+ void on (const msg::RecorderEncodingFail&) {
200+ node ()->set (" text" , " Encoding Error" );
201+ }
202+ };
203+ static ui::Controller::Shared<RecorderEncode> recenc{" recorderencode" };
204+
121205class ToggleRecording : public Command {
122206public:
123207 void run () override {
@@ -138,3 +222,16 @@ class ResetRecordingSequence : public Command {
138222 }
139223};
140224static Command::Shared<ResetRecordingSequence> cmd2{" resetrecsequence" };
225+
226+ class RecorderEncodeCmd : public Command {
227+ public:
228+ void run () override {
229+ if (encoder && !encoder->done ()) {
230+ return ;
231+ }
232+ encoder = std::nullopt ;
233+ encoder.emplace ();
234+ encoder->run ();
235+ }
236+ };
237+ static Command::Shared<RecorderEncodeCmd> cmd3{" recorderencode" };
0 commit comments