diff options
author | dec05eba <dec05eba@protonmail.com> | 2019-08-08 22:12:09 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2019-08-08 22:12:12 +0200 |
commit | f26534ca8d7107b14fdd5a02cbadd56505d159de (patch) | |
tree | e8f91f264126665a175709046bd92c9b0973323a /src | |
parent | c9c2621accb68634685a14703491cacdd7ed2bb1 (diff) |
Switch from libmpv to mpv process with window embed
Diffstat (limited to 'src')
-rw-r--r-- | src/Program.c | 60 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 171 | ||||
-rw-r--r-- | src/VideoPlayer.cpp | 357 | ||||
-rw-r--r-- | src/plugins/Manganelo.cpp | 2 | ||||
-rw-r--r-- | src/plugins/Plugin.cpp | 4 | ||||
-rw-r--r-- | src/plugins/Youtube.cpp | 3 |
6 files changed, 306 insertions, 291 deletions
diff --git a/src/Program.c b/src/Program.c index 731a20e..a863fcd 100644 --- a/src/Program.c +++ b/src/Program.c @@ -4,6 +4,7 @@ #include <errno.h> #include <string.h> #include <stdio.h> +#include <assert.h> #define READ_END 0 #define WRITE_END 1 @@ -85,3 +86,62 @@ int exec_program(const char **args, ProgramOutputCallback output_callback, void return result; } } + +int exec_program_async(const char **args, pid_t *result_process_id) { + /* 1 arguments */ + if(args[0] == NULL) + return -1; + + pid_t pid = fork(); + if(pid == -1) { + int err = errno; + perror("Failed to fork"); + return -err; + } else if(pid == 0) { /* child */ + execvp(args[0], args); + } else { /* parent */ + if(result_process_id) + *result_process_id = pid; + } + return 0; +} + +#if 0 +int program_pipe_write(ProgramPipe *self, const char *data, size_t size) { + ssize_t bytes_written = write(self->write_fd, data, size); + if(bytes_written == -1) { + int err = errno; + perror("Failed to write to pipe to program"); + return -err; + } + return 0; +} + +int program_pipe_read(ProgramPipe *self, ProgramOutputCallback output_callback, void *userdata) { + char buffer[2048]; + + for(;;) { + ssize_t bytes_read = read(self->read_fd, buffer, sizeof(buffer) - 1); + if(bytes_read == 0) { + break; + } else if(bytes_read == -1) { + int err = errno; + perror("Failed to read from pipe to program"); + return -err; + } + + buffer[bytes_read] = '\0'; + if(output_callback && output_callback(buffer, bytes_read, userdata) != 0) + break; + } + + return 0; +} + +void program_pipe_close(ProgramPipe *self) { + close(self->read_fd); + close(self->write_fd); + self->read_fd = -1; + self->write_fd = -1; +} +#endif diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 0a34508..cb58a1d 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -1,12 +1,13 @@ #include "../include/QuickMedia.hpp" #include "../plugins/Manganelo.hpp" #include "../plugins/Youtube.hpp" -#include "../include/VideoPlayer.hpp" #include "../include/Scale.hpp" #include "../include/Program.h" +#include "../include/VideoPlayer.hpp" #include <cppcodec/base64_rfc4648.hpp> #include <SFML/Graphics/RectangleShape.hpp> +#include <SFML/Graphics/Sprite.hpp> #include <SFML/Graphics/Text.hpp> #include <SFML/Window/Event.hpp> #include <json/reader.h> @@ -14,11 +15,19 @@ #include <assert.h> #include <cmath> #include <string.h> +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <signal.h> const sf::Color front_color(43, 45, 47); const sf::Color back_color(33, 35, 37); const int DOUBLE_CLICK_TIME = 500; +// Prevent writing to broken pipe from exiting the program +static void sigpipe_handler(int unused) { + +} + namespace QuickMedia { Program::Program() : window(sf::VideoMode(800, 600), "QuickMedia"), @@ -35,6 +44,12 @@ namespace QuickMedia { } body = new Body(font); search_bar = std::make_unique<SearchBar>(font); + + struct sigaction action; + action.sa_handler = sigpipe_handler; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + sigaction(SIGPIPE, &action, NULL); } Program::~Program() { @@ -316,64 +331,86 @@ namespace QuickMedia { #endif } + struct XDisplayScope { + XDisplayScope(Display *_display) : display(_display) { + + } + + ~XDisplayScope() { + if(display) + XCloseDisplay(display); + } + + Display *display; + }; + void Program::video_content_page() { search_bar->onTextUpdateCallback = nullptr; search_bar->onTextSubmitCallback = nullptr; + Display* disp = XOpenDisplay(NULL); + if (!disp) + throw std::runtime_error("Failed to open display to X11 server"); + XDisplayScope display_scope(disp); + + #if 0 + sf::RenderWindow video_window(sf::VideoMode(300, 300), "QuickMedia Video Player"); + video_window.setVerticalSyncEnabled(true); + XReparentWindow(disp, video_window.getSystemHandle(), window.getSystemHandle(), 0, 0); + XMapWindow(disp, video_window.getSystemHandle()); + XSync(disp, False); + video_window.setSize(sf::Vector2u(400, 300)); + #endif + // This variable is needed because calling play_video is not possible in onPlaybackEndedCallback bool play_next_video = false; - auto onPlaybackEndedCallback = [this, &play_next_video]() { - std::string new_video_url; - std::vector<std::unique_ptr<BodyItem>> related_media = current_plugin->get_related_media(content_url); - // Find video that hasn't been played before in this video session - for(auto it = related_media.begin(), end = related_media.end(); it != end; ++it) { - if(watched_videos.find((*it)->url) == watched_videos.end()) { - new_video_url = (*it)->url; - break; - } - } + std::unique_ptr<VideoPlayer> video_player; - // If there are no videos to play, then dont play any... - if(new_video_url.empty()) { - show_notification("Video player", "No more related videos to play"); - return; - } + auto play_video = [this, &video_player, &play_next_video]() { + printf("Playing video: %s\n", content_url.c_str()); + watched_videos.insert(content_url); + video_player = std::make_unique<VideoPlayer>([this, &play_next_video](const char *event_name) { + if(strcmp(event_name, "end-file") == 0) { + std::string new_video_url; + std::vector<std::unique_ptr<BodyItem>> related_media = current_plugin->get_related_media(content_url); + // Find video that hasn't been played before in this video session + for(auto it = related_media.begin(), end = related_media.end(); it != end; ++it) { + if(watched_videos.find((*it)->url) == watched_videos.end()) { + new_video_url = (*it)->url; + break; + } + } - content_url = std::move(new_video_url); - play_next_video = true; - // TODO: This doesn't seem to work correctly right now, it causes video to become black when changing video (context reset bug). - //video_player->load_file(video_url); - }; + // If there are no videos to play, then dont play any... + if(new_video_url.empty()) { + show_notification("Video player", "No more related videos to play"); + current_page = Page::SEARCH_SUGGESTION; + return; + } - std::unique_ptr<VideoPlayer> video_player = nullptr; - auto play_video = [this, &video_player, &onPlaybackEndedCallback]() { - watched_videos.insert(content_url); - try { - printf("Play video: %s\n", content_url.c_str()); - video_player.reset(new VideoPlayer(&window, window_size.x, window_size.y, content_url.c_str())); - video_player->onPlaybackEndedCallback = onPlaybackEndedCallback; - } catch(VideoInitializationException &e) { - show_notification("Video player", "Failed to create video player", Urgency::CRITICAL); - video_player = nullptr; + content_url = std::move(new_video_url); + play_next_video = true; + // TODO: This doesn't seem to work correctly right now, it causes video to become black when changing video (context reset bug). + //video_player->load_file(video_url); + } + }); + + VideoPlayer::Error err = video_player->load_video(content_url.c_str(), window.getSystemHandle()); + if(err != VideoPlayer::Error::OK) { + std::string err_msg = "Failed to play url: "; + err_msg += content_url; + show_notification("Video player", err_msg.c_str(), Urgency::CRITICAL); + current_page = Page::SEARCH_SUGGESTION; } }; play_video(); sf::Clock time_since_last_left_click; int left_click_counter; - bool video_is_fullscreen = false; sf::Event event; - auto on_doubleclick = [this, &video_is_fullscreen]() { - if(video_is_fullscreen) { - window.create(sf::VideoMode::getDesktopMode(), "QuickMedia", sf::Style::Default); - } else { - window.create(sf::VideoMode::getDesktopMode(), "QuickMedia", sf::Style::Fullscreen); - } - window.setVerticalSyncEnabled(true); - video_is_fullscreen = !video_is_fullscreen; - }; + sf::RectangleShape rect(sf::Vector2f(500, 500)); while (current_page == Page::VIDEO_CONTENT) { if(play_next_video) { @@ -383,33 +420,61 @@ namespace QuickMedia { while (window.pollEvent(event)) { base_event_handler(event, Page::SEARCH_SUGGESTION); + if(event.type == sf::Event::Resized) { + //video_window.setSize(sf::Vector2u(event.size.width, event.size.height)); + } else if(event.key.code == sf::Keyboard::Space) { + if(video_player->toggle_pause() != VideoPlayer::Error::OK) { + fprintf(stderr, "Failed to toggle pause!\n"); + } + } + } + + #if 0 + while(video_window.pollEvent(event)) { + if (event.type == sf::Event::Closed) { + current_page = Page::EXIT; + } else if(event.type == sf::Event::Resized) { + sf::FloatRect visible_area(0, 0, event.size.width, event.size.height); + video_window.setView(sf::View(visible_area)); + } else if(event.type == sf::Event::KeyPressed) { + if(event.key.code == sf::Keyboard::Escape) { + current_page = Page::SEARCH_SUGGESTION; + return; + } + + if(event.key.code == sf::Keyboard::Space) { + if(video_player.toggle_pause() != VideoPlayer::Error::OK) { + fprintf(stderr, "Failed to toggle pause!\n"); + } + } + } + if(event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { if(time_since_last_left_click.restart().asMilliseconds() <= DOUBLE_CLICK_TIME) { if(++left_click_counter == 2) { - on_doubleclick(); + //on_doubleclick(); left_click_counter = 0; } } else { left_click_counter = 1; } } + } + #endif - if(video_player) { - if(event.type == sf::Event::Resized) - video_player->resize(window_size); - video_player->handle_event(event); - } + VideoPlayer::Error update_err = video_player->update(); + if(update_err == VideoPlayer::Error::FAIL_TO_CONNECT_TIMEOUT) { + show_notification("Video player", "Failed to connect to mpv ipc after 5 seconds", Urgency::CRITICAL); + current_page = Page::SEARCH_SUGGESTION; + return; } window.clear(); - if(video_player) - video_player->draw(window); window.display(); - } - if(video_is_fullscreen) { - window.create(sf::VideoMode::getDesktopMode(), "QuickMedia", sf::Style::Default); - window.setVerticalSyncEnabled(true); + // TODO: Show loading video animation + //video_window.clear(sf::Color::Red); + //video_window.display(); } } diff --git a/src/VideoPlayer.cpp b/src/VideoPlayer.cpp index 4c19c61..e0e69df 100644 --- a/src/VideoPlayer.cpp +++ b/src/VideoPlayer.cpp @@ -1,275 +1,164 @@ #include "../include/VideoPlayer.hpp" -#include "../include/Scale.hpp" -#include <SFML/Window/Mouse.hpp> -#include <mpv/client.h> -#include <mpv/render_gl.h> -#include <SFML/OpenGL.hpp> -#include <clocale> -#include <cmath> +#include "../include/Program.h" +#include <string> +#include <json/reader.h> +#include <assert.h> -const int UI_VISIBLE_TIMEOUT_MS = 2500; -const auto pause_key = sf::Keyboard::Space; +#include <sys/socket.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> -namespace QuickMedia { - static void* getProcAddressMpv(void *funcContext, const char *name) { - return (void*)sf::Context::getFunction(name); - } - - static void onMpvRedraw(void *ctx) { - VideoPlayer *video_player = (VideoPlayer*)ctx; - video_player->redraw = true; - } +const int RETRY_TIME_MS = 1000; +const int MAX_RETRIES = 5; - static void on_mpv_events(void *ctx) { - VideoPlayer *video_player = (VideoPlayer*)ctx; - video_player->event_update = true; +namespace QuickMedia { + VideoPlayer::VideoPlayer(EventCallbackFunc _event_callback) : + video_process_id(-1), + ipc_socket(-1), + connected_to_ipc(false), + connect_tries(0), + event_callback(_event_callback), + alive(true) + { + } - static void check_error(int status) { - if(status < 0) - fprintf(stderr, "mpv api error: %s\n", mpv_error_string(status)); - } + VideoPlayer::~VideoPlayer() { + if(video_process_id != -1) + kill(video_process_id, SIGTERM); - static void mpv_set_option_bool(mpv_handle *mpv, const char *option, bool value) { - int int_value = value; - check_error(mpv_set_option(mpv, option, MPV_FORMAT_FLAG, &int_value)); - } + if(ipc_socket != -1) + close(ipc_socket); + + if(video_process_id != -1) + remove(ipc_server_path); - static void mpv_set_option_int64(mpv_handle *mpv, const char *option, int64_t value) { - check_error(mpv_set_option(mpv, option, MPV_FORMAT_INT64, &value)); + alive = false; + if(event_read_thread.joinable()) + event_read_thread.join(); } - class ContextScope { - public: - ContextScope(sf::Context *_context) : context(_context) { - context->setActive(true); - } - - ~ContextScope() { - context->setActive(false); + VideoPlayer::Error VideoPlayer::launch_video_process(const char *path, sf::WindowHandle parent_window) { + if(!tmpnam(ipc_server_path)) { + perror("Failed to generate ipc file name"); + return Error::FAIL_TO_GENERATE_IPC_FILENAME; } - sf::Context *context; - }; - - VideoPlayer::VideoPlayer(sf::RenderWindow *_window, unsigned int width, unsigned int height, const char *file, bool loop) : - redraw(false), - event_update(false), - onPlaybackEndedCallback(nullptr), - mpv(nullptr), - mpvGl(nullptr), - context(nullptr), - textureBuffer(nullptr), - desired_size(width, height) - { - //ContextScope context_scope(context.get()); - texture.setSmooth(true); - - // mpv_create requires LC_NUMERIC to be set to "C" for some reason, see mpv_create documentation - std::setlocale(LC_NUMERIC, "C"); - mpv = mpv_create(); - if(!mpv) - throw VideoInitializationException("Failed to create mpv handle"); - - //check_error(mpv_set_option_string(mpv, "input-default-bindings", "yes")); - //check_error(mpv_set_option_string(mpv, "input-vo-keyboard", "yes")); - check_error(mpv_set_option_string(mpv, "cache-secs", "120")); - check_error(mpv_set_option_string(mpv, "demuxer-max-bytes", "20M")); - check_error(mpv_set_option_string(mpv, "demuxer-max-back-bytes", "10M")); + const std::string parent_window_str = std::to_string(parent_window); + const char *args[] = { "mpv", /*"--keep-open=yes", "--keep-open-pause=no",*/ "--input-ipc-server", ipc_server_path, + "--no-config", "--no-input-default-bindings", "--input-vo-keyboard=no", "--no-input-cursor", + "--cache-secs=120", "--demuxer-max-bytes=20M", "--demuxer-max-back-bytes=10M", + "--vo=gpu", "--hwdec=auto", + "--wid", parent_window_str.c_str(), "--", path, nullptr }; + if(exec_program_async(args, &video_process_id) != 0) + return Error::FAIL_TO_LAUNCH_PROCESS; - //mpv_set_option_bool(mpv, "osc", true); - //mpv_set_option_int64(mpv, "wid", window.getSystemHandle()); - - if(mpv_initialize(mpv) < 0) - throw VideoInitializationException("Failed to initialize mpv"); + printf("mpv input ipc server: %s\n", ipc_server_path); - // TODO: Enabling vo=gpu will make mpv create its own window, or take over the QuickMedia window fully - // if "wid" option is used. To take advantage of vo=gpu, QuickMedia should create a parent window - // and make mpv use that and then embed that into the parent QuickMedia window. - // This will also remove the need for rendering with sfml (no need for texture copy!). - //check_error(mpv_set_option_string(mpv, "vo", "gpu")); - //check_error(mpv_set_option_string(mpv, "hwdec", "auto")); + if((ipc_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + perror("Failed to create socket for video player"); + return Error::FAIL_TO_CREATE_SOCKET; + } - //check_error(mpv_set_option_string(mpv, "terminal", "yes")); - //check_error(mpv_set_option_string(mpv, "msg-level", "all=v")); + ipc_addr.sun_family = AF_UNIX; + strcpy(ipc_addr.sun_path, ipc_server_path); - if(loop) - check_error(mpv_set_option_string(mpv, "loop", "inf")); + int flags = fcntl(ipc_socket, F_GETFL, 0); + fcntl(ipc_socket, F_SETFL, flags | O_NONBLOCK); - //mpvGl = (mpv_opengl_cb_context*)mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB); - //if(!mpvGl) - // throw VideoInitializationException("Failed to initialize mpv opengl render context"); + return Error::OK; + } - mpv_opengl_init_params opengl_init_params; - opengl_init_params.get_proc_address = getProcAddressMpv; - opengl_init_params.get_proc_address_ctx = nullptr; - opengl_init_params.extra_exts = nullptr; - mpv_render_param params[] = { - { MPV_RENDER_PARAM_API_TYPE, (void*)MPV_RENDER_API_TYPE_OPENGL }, - { MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &opengl_init_params }, - { (mpv_render_param_type)0, nullptr } - }; + VideoPlayer::Error VideoPlayer::load_video(const char *path, sf::WindowHandle parent_window) { + if(video_process_id == -1) + return launch_video_process(path, parent_window); - if (mpv_render_context_create(&mpvGl, mpv, params) < 0) - throw VideoInitializationException("failed to initialize mpv GL context"); - - mpv_render_context_set_update_callback(mpvGl, onMpvRedraw, this); - mpv_set_wakeup_callback(mpv, on_mpv_events, this); - - seekbar.setFillColor(sf::Color(255, 20, 60, 200)); - seekbar_background.setFillColor(sf::Color(33, 33, 33, 200)); - load_file(file); + std::string cmd = "loadfile "; + cmd += path; + return send_command(cmd.c_str(), cmd.size()); } - - VideoPlayer::~VideoPlayer() { - if(mpvGl) { - //mpv_render_context_set_update_callback(mpvGl, nullptr, nullptr); - mpv_render_context_free(mpvGl); - } - free(textureBuffer); + VideoPlayer::Error VideoPlayer::update() { + if(ipc_socket == -1) + return Error::INIT_FAILED; - if(mpv) { - //mpv_set_wakeup_callback(mpv, nullptr, nullptr); - mpv_destroy(mpv); - //mpv_terminate_destroy(mpv); - } - } + if(connect_tries == MAX_RETRIES) + return Error::FAIL_TO_CONNECT_TIMEOUT; - void VideoPlayer::handle_event(sf::Event &event) { - if(event.type == sf::Event::MouseMoved) { - cursor_last_active_timer.restart(); - } else if(event.type == sf::Event::KeyPressed) { - if(event.key.code == pause_key) { - mpv_command_string(mpv, "cycle pause"); + if(!connected_to_ipc && ipc_connect_retry_timer.getElapsedTime().asMilliseconds() >= RETRY_TIME_MS) { + if(connect(ipc_socket, (struct sockaddr*)&ipc_addr, sizeof(ipc_addr)) == -1) { + ++connect_tries; + if(connect_tries == MAX_RETRIES) { + fprintf(stderr, "Failed to connect to mpv ipc after 5 seconds, last error: %s\n", strerror(errno)); + return Error::FAIL_TO_CONNECT_TIMEOUT; + } + } else { + connected_to_ipc = true; + if(event_callback) + event_read_thread = std::thread(&VideoPlayer::read_ipc_func, this); } } - } - - void VideoPlayer::setPosition(float x, float y) { - sprite.setPosition(x, y); - } - // TODO: Make this work in the future when video size and sprite texture size wont be the same - void VideoPlayer::resize(const sf::Vector2f &size) { - desired_size = sf::Vector2f(size.x, size.y); - if(!textureBuffer) - return; - - sf::Vector2f video_size_f(video_size.x, video_size.y); - auto video_scale = get_ratio(video_size_f, wrap_to_size(video_size_f, desired_size)); - sprite.setScale(video_scale); - - auto image_size = video_size_f; - image_size.x *= video_scale.x; - image_size.y *= video_scale.y; - sprite.setPosition(std::floor(desired_size.x * 0.5f - image_size.x * 0.5f), std::floor(desired_size.y * 0.5f - image_size.y * 0.5f)); + return Error::OK; } - void VideoPlayer::handle_mpv_events() { - while(true) { - mpv_event *mpvEvent = mpv_wait_event(mpv, 0.0); - if(mpvEvent->event_id == MPV_EVENT_NONE) + void VideoPlayer::read_ipc_func() { + assert(connected_to_ipc); + assert(event_callback); + + Json::Value json_root; + Json::CharReaderBuilder json_builder; + std::unique_ptr<Json::CharReader> json_reader(json_builder.newCharReader()); + std::string json_errors; + + char buffer[2048]; + while(alive) { + ssize_t bytes_read = read(ipc_socket, buffer, sizeof(buffer)); + if(bytes_read == -1) { + int err = errno; + if(err == EAGAIN) { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + continue; + } + + fprintf(stderr, "Failed to read from ipc socket, error: %s\n", strerror(err)); break; - else if(mpvEvent->event_id == MPV_EVENT_SHUTDOWN) - return; - else if(mpvEvent->event_id == MPV_EVENT_VIDEO_RECONFIG) { - int64_t w, h; - if (mpv_get_property(mpv, "dwidth", MPV_FORMAT_INT64, &w) >= 0 && - mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &h) >= 0 && - w > 0 && h > 0 && (w != video_size.x || h != video_size.y)) - { - video_size.x = w; - video_size.y = h; - context.reset(new sf::Context(sf::ContextSettings(), w, h)); - context->setActive(true); - // TODO: Verify if it's valid to re-create the texture like this, - // instead of using deconstructor - if(texture.create(w, h)) { - void *newTextureBuf = realloc(textureBuffer, w * h * 4); - if(newTextureBuf) - textureBuffer = (sf::Uint8*)newTextureBuf; + } else if(bytes_read > 0) { + int start = 0; + for(int i = 0; i < bytes_read; ++i) { + if(buffer[i] != '\n') + continue; + + if(json_reader->parse(buffer + start, buffer + i, &json_root, &json_errors)) { + const Json::Value &event = json_root["event"]; + if(event.isString()) + event_callback(event.asCString()); + } else { + fprintf(stderr, "Failed to parse json for ipc: |%.*s|, reason: %s\n", (int)bytes_read, buffer, json_errors.c_str()); } - glViewport(0, 0, w, h); - context->setActive(false); - resize(desired_size); + + start = i + 1; } - } else if(mpvEvent->event_id == MPV_EVENT_END_FILE) { - if(onPlaybackEndedCallback) - onPlaybackEndedCallback(); - } else { - //printf("Mpv event: %s\n", mpv_event_name(mpvEvent->event_id)); } } } - - void VideoPlayer::draw(sf::RenderWindow &window) { - if(event_update.exchange(false)) - handle_mpv_events(); - - if(textureBuffer && redraw) { - uint64_t update_flags = mpv_render_context_update(mpvGl); - if((update_flags & MPV_RENDER_UPDATE_FRAME) && redraw.exchange(false)) { - auto textureSize = texture.getSize(); - - mpv_opengl_fbo opengl_fbo; - opengl_fbo.fbo = 0; - opengl_fbo.w = textureSize.x; - opengl_fbo.h = textureSize.y; - opengl_fbo.internal_format = 0; - mpv_render_param params[] = - { - { MPV_RENDER_PARAM_OPENGL_FBO, &opengl_fbo }, - { (mpv_render_param_type)0, nullptr } - }; - - context->setActive(true); - mpv_render_context_render(mpvGl, params); - // TODO: Instead of copying video to cpu buffer and then to texture, copy directly from video buffer to texture buffer - glReadPixels(0, 0, textureSize.x, textureSize.y, GL_RGBA, GL_UNSIGNED_BYTE, textureBuffer); - context->setActive(false); - texture.update(textureBuffer); - sprite.setTexture(texture, true); - mpv_render_context_report_swap(mpvGl); - } - } - window.draw(sprite); - - if(cursor_last_active_timer.getElapsedTime().asMilliseconds() > UI_VISIBLE_TIMEOUT_MS) - return; - double pos = 0.0; - mpv_get_property(mpv, "percent-pos", MPV_FORMAT_DOUBLE, &pos); - pos *= 0.01; - - auto window_size = window.getSize(); - - const float seekbar_height = std::floor(window_size.y * 0.02f); - const float seekbar_max_size = window_size.x; - sf::Vector2f seekbar_size(seekbar_max_size * pos, seekbar_height); - seekbar.setPosition(0.0f, window_size.y - seekbar_height); - seekbar.setSize(seekbar_size); - window.draw(seekbar); + VideoPlayer::Error VideoPlayer::toggle_pause() { + const char cmd[] = "cycle pause\n"; + return send_command(cmd, sizeof(cmd) - 1); + } - seekbar_background.setPosition(seekbar.getPosition() + sf::Vector2f(seekbar_size.x, 0.0f)); - seekbar_background.setSize(sf::Vector2f(seekbar_max_size - seekbar_size.x, seekbar_height)); - window.draw(seekbar_background); + VideoPlayer::Error VideoPlayer::send_command(const char *cmd, size_t size) { + if(!connected_to_ipc) + return Error::FAIL_NOT_CONNECTED; - if(sf::Mouse::isButtonPressed(sf::Mouse::Left)) { - auto mouse_pos = sf::Mouse::getPosition(window); - auto seekbar_pos = seekbar.getPosition(); - float diff_x = mouse_pos.x - seekbar_pos.x; - if(mouse_pos.x >= seekbar_pos.x && mouse_pos.x <= seekbar_pos.x + seekbar_max_size && - mouse_pos.y >= seekbar_pos.y && mouse_pos.y <= seekbar_pos.y + seekbar_height) - { - double new_pos = ((double)diff_x / seekbar_max_size) * 100.0; - mpv_set_property(mpv, "percent-pos", MPV_FORMAT_DOUBLE, &new_pos); - } + if(send(ipc_socket, cmd, size, 0) == -1) { + fprintf(stderr, "Failed to send to ipc socket, error: %s, command: %.*s\n", strerror(errno), (int)size, cmd); + return Error::FAIL_TO_SEND; } - } - void VideoPlayer::load_file(const std::string &path) { - const char *cmd[] = { "loadfile", path.c_str(), nullptr }; - mpv_command(mpv, cmd); + return Error::OK; } } diff --git a/src/plugins/Manganelo.cpp b/src/plugins/Manganelo.cpp index b1f02a3..e91baf0 100644 --- a/src/plugins/Manganelo.cpp +++ b/src/plugins/Manganelo.cpp @@ -67,7 +67,7 @@ namespace QuickMedia { Json::CharReaderBuilder json_builder; std::unique_ptr<Json::CharReader> json_reader(json_builder.newCharReader()); std::string json_errors; - if(json_reader->parse(&server_response.front(), &server_response.back(), &json_root, &json_errors)) { + if(!json_reader->parse(&server_response[0], &server_response[server_response.size()], &json_root, &json_errors)) { fprintf(stderr, "Manganelo suggestions json error: %s\n", json_errors.c_str()); return SuggestionResult::ERR; } diff --git a/src/plugins/Plugin.cpp b/src/plugins/Plugin.cpp index 86f5d7d..5d81aad 100644 --- a/src/plugins/Plugin.cpp +++ b/src/plugins/Plugin.cpp @@ -28,11 +28,13 @@ namespace QuickMedia { } DownloadResult download_to_string(const std::string &url, std::string &result, const std::vector<CommandArg> &additional_args) { - std::vector<const char*> args = { "curl", "-H", "Accept-Language: en-US,en;q=0.5", "--compressed", "-s", "-L", url.c_str() }; + std::vector<const char*> args = { "curl", "-H", "Accept-Language: en-US,en;q=0.5", "--compressed", "-s", "-L" }; for(const CommandArg &arg : additional_args) { args.push_back(arg.option.c_str()); args.push_back(arg.value.c_str()); } + args.push_back("--"); + args.push_back(url.c_str()); args.push_back(nullptr); if(exec_program(args.data(), accumulate_string, &result) != 0) return DownloadResult::NET_ERR; diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index a5670ec..2a3f011 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -48,13 +48,12 @@ namespace QuickMedia { if(json_end == 0 || json_start >= json_end) return SuggestionResult::ERR; - --json_end; Json::Value json_root; Json::CharReaderBuilder json_builder; std::unique_ptr<Json::CharReader> json_reader(json_builder.newCharReader()); std::string json_errors; - if(json_reader->parse(&server_response[json_start], &server_response[json_end], &json_root, &json_errors)) { + if(!json_reader->parse(&server_response[json_start], &server_response[json_end], &json_root, &json_errors)) { fprintf(stderr, "Youtube suggestions json error: %s\n", json_errors.c_str()); return SuggestionResult::ERR; } |