external_player.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /* external_player.cpp - play animation in external player
  2. * Copyright (C) 2017-2018 caryoscelus
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <cstdlib>
  18. #include <thread>
  19. #include <fmt/format.h>
  20. #include <core/document.h>
  21. #include <core/node/abstract_node.h>
  22. #include <core/node/abstract_value.h>
  23. #include <generic/action.h>
  24. using namespace fmt::literals;
  25. namespace rainynite::studio::actions {
  26. /**
  27. * Launch external player (or, perhaps, other command on rendered frames)
  28. *
  29. * TODO: configuration: UI & store
  30. */
  31. class LaunchExternalPlayer : public UiAction, public ContextListener {
  32. ACTION_NAME("Launch external player")
  33. public:
  34. void process() override {
  35. if (auto ctx = get_core_context()) {
  36. string audio_file;
  37. if (auto audio_node = abstract_node_cast(ctx->get_document_node()->get_property("soundtrack")))
  38. audio_file = audio_node->get_property_value<string>("file_path", ctx).value_or("");
  39. auto command = fmt::format(
  40. player_command(),
  41. "audio_command"_a=audio_command(audio_file),
  42. "lst_file"_a="renders/rendered.lst",
  43. "fps"_a=ctx->get_fps()
  44. );
  45. std::thread t([command]() {
  46. std::system(command.c_str());
  47. });
  48. t.detach();
  49. }
  50. }
  51. protected:
  52. virtual string player_command() const = 0;
  53. virtual string audio_command(string const& fname) const = 0;
  54. };
  55. class LaunchMpv : public LaunchExternalPlayer, REGISTERED_ACTION(LaunchMpv) {
  56. ACTION_NAME("Launch external player (mpv)")
  57. protected:
  58. string player_command() const override {
  59. return "mpv -loop {audio_command} -mf-fps {fps} mf://@{lst_file}";
  60. }
  61. string audio_command(string const& fname) const override {
  62. if (fname.empty())
  63. return "";
  64. return "-audio-file '"+fname+"'";
  65. }
  66. };
  67. class FfmpegToWebm : public LaunchExternalPlayer, REGISTERED_ACTION(FfmpegToWebm) {
  68. ACTION_NAME("Encode render results to webm (ffmpeg)")
  69. protected:
  70. string player_command() const override {
  71. return R"(cat {lst_file} | sed -e "s/^/file '/" -e "s/$/'/" > renders/rendered_ffmpeg.lst && ffmpeg -f concat -safe 0 -r {fps} -i renders/rendered_ffmpeg.lst {audio_command} result.webm)";
  72. }
  73. string audio_command(string const& fname) const override {
  74. if (fname.empty())
  75. return "";
  76. return "-i '"+fname+"'";
  77. }
  78. };
  79. } // namespace rainynite::studio::actions