aboutsummaryrefslogtreecommitdiff
path: root/src/VideoPlayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VideoPlayer.cpp')
-rw-r--r--src/VideoPlayer.cpp59
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);