diff options
Diffstat (limited to 'src/VideoPlayer.cpp')
-rw-r--r-- | src/VideoPlayer.cpp | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/src/VideoPlayer.cpp b/src/VideoPlayer.cpp index 9e17bda..1d854de 100644 --- a/src/VideoPlayer.cpp +++ b/src/VideoPlayer.cpp @@ -2,6 +2,7 @@ #include "../include/Storage.hpp" #include "../include/Program.hpp" #include "../include/Utils.hpp" +#include "../include/StringUtils.hpp" #include "../include/Notification.hpp" #include <string> #include <json/reader.h> @@ -20,6 +21,49 @@ const int MAX_RETRIES_CONNECT = 1000; const int READ_TIMEOUT_MS = 200; namespace QuickMedia { + static std::string media_chapters_to_ffmetadata_chapters(const std::vector<MediaChapter> &chapters) { + std::string result = ";FFMETADATA1\n\n"; + for(size_t i = 0; i < chapters.size(); ++i) { + const MediaChapter &chapter = chapters[i]; + result += "[CHAPTER]\n"; + result += "TIMEBASE=1/1\n"; + result += "START=" + std::to_string(chapter.start_seconds) + "\n"; + result += "END=" + std::to_string(i + 1 == chapters.size() ? chapter.start_seconds : chapters[i].start_seconds) + "\n"; + std::string title = chapter.title; + string_replace_all(title, '\n', ' '); + result += "title=" + std::move(title) + "\n\n"; + } + return result; + } + + // If |chapters| is empty then |tmp_chapters_filepath| is removed, otherwise the file is overwritten + static bool create_tmp_file_with_chapters_data(char *tmp_chapters_filepath, const std::vector<MediaChapter> &chapters) { + if(chapters.empty()) { + if(tmp_chapters_filepath[0] != '\0') { + remove(tmp_chapters_filepath); + tmp_chapters_filepath[0] = '\0'; + } + return true; + } + + if(tmp_chapters_filepath[0] == '\0') { + strcpy(tmp_chapters_filepath, "/tmp/qm-mpv-chapter-XXXXXX"); + mktemp(tmp_chapters_filepath); + if(tmp_chapters_filepath[0] == '\0') { + fprintf(stderr, "Failed to create temporay file\n"); + return false; + } + } + + if(file_overwrite(tmp_chapters_filepath, media_chapters_to_ffmetadata_chapters(chapters)) == 0) { + return true; + } else { + remove(tmp_chapters_filepath); + tmp_chapters_filepath[0] = '\0'; + return false; + } + } + VideoPlayer::VideoPlayer(bool no_video, bool use_system_mpv_config, bool keep_open, EventCallbackFunc _event_callback, VideoPlayerWindowCreateCallback _window_create_callback, const std::string &resource_root, int monitor_height) : exit_status(0), no_video(no_video), @@ -41,6 +85,7 @@ namespace QuickMedia { response_data_status(ResponseDataStatus::NONE), resource_root(resource_root) { + tmp_chapters_filepath[0] = '\0'; display = XOpenDisplay(NULL); if (!display) { show_notification("QuickMedia", "Failed to open display to X11 server", Urgency::CRITICAL); @@ -64,6 +109,9 @@ namespace QuickMedia { if(display) XCloseDisplay(display); + + if(tmp_chapters_filepath[0] != '\0') + remove(tmp_chapters_filepath); } VideoPlayer::Error VideoPlayer::launch_video_process(const char *path, const char *audio_path, sf::WindowHandle _parent_window, bool is_youtube, const std::string &title, const std::string &start_time) { @@ -141,6 +189,12 @@ namespace QuickMedia { if(no_video) args.push_back("--no-video"); + std::string chapters_file_arg; + if(tmp_chapters_filepath[0] != '\0') { + chapters_file_arg = std::string("--chapters-file=") + tmp_chapters_filepath; + args.push_back(chapters_file_arg.c_str()); + } + std::string audio_file_arg; if(audio_path && audio_path[0] != '\0') { audio_file_arg = std::string("--audio-file=") + audio_path; @@ -171,11 +225,14 @@ namespace QuickMedia { return Error::OK; } - VideoPlayer::Error VideoPlayer::load_video(const char *path, const char *audio_path, sf::WindowHandle _parent_window, bool is_youtube, const std::string &title, const std::string &start_time) { + VideoPlayer::Error VideoPlayer::load_video(const char *path, const char *audio_path, sf::WindowHandle _parent_window, bool is_youtube, const std::string &title, const std::string &start_time, const std::vector<MediaChapter> &chapters) { // This check is to make sure we dont change window that the video belongs to. This is not a usecase we will have so // no need to support it for now at least. assert(parent_window == 0 || parent_window == _parent_window); assert(path); + if(!create_tmp_file_with_chapters_data(tmp_chapters_filepath, chapters)) + fprintf(stderr, "Warning: failed to create chapters file. Chapters will not be displayed\n"); + fprintf(stderr, "Playing video: %s, audio: %s\n", path ? path : "", audio_path ? audio_path : ""); if(video_process_id == -1) return launch_video_process(path, audio_path, _parent_window, is_youtube, title, start_time); |