MpvWidget::MpvWidget(QWidget *parent, Qt::WindowFlags f) : QOpenGLWidget(parent, f) { mpv = mpv::qt::Handle::FromRawHandle(mpv_create()); if (!mpv) throw std::runtime_error("could not create mpv context"); mpv_set_option_string(mpv, "terminal", "yes"); mpv_set_option_string(mpv, "msg-level", "all=v"); if (mpv_initialize(mpv) < 0) throw std::runtime_error("could not initialize mpv context"); // Make use of the MPV_SUB_API_OPENGL_CB API. mpv::qt::set_option_variant(mpv, "vo", "opengl-cb"); // Request hw decoding, just for testing. mpv::qt::set_option_variant(mpv, "hwdec", "auto"); mpv_gl = (mpv_opengl_cb_context *)mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB); if (!mpv_gl) throw std::runtime_error("OpenGL not compiled in"); mpv_opengl_cb_set_update_callback(mpv_gl, MpvWidget::on_update, (void *)this); connect(this, SIGNAL(frameSwapped()), SLOT(swapped())); mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE); mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE); mpv_set_wakeup_callback(mpv, wakeup, this); }
MpvHandler::MpvHandler(int64_t wid, QObject *parent): QObject(parent), baka(static_cast<BakaEngine*>(parent)) { // create mpv mpv = mpv_create(); if(!mpv) throw "Could not create mpv object"; // set mpv options mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid); mpv_set_option_string(mpv, "input-cursor", "no"); // no mouse handling mpv_set_option_string(mpv, "cursor-autohide", "no");// no cursor-autohide, we handle that mpv_set_option_string(mpv, "ytdl", "yes"); // youtube-dl support // get updates when these properties change mpv_observe_property(mpv, 0, "playback-time", MPV_FORMAT_DOUBLE); mpv_observe_property(mpv, 0, "volume", MPV_FORMAT_DOUBLE); mpv_observe_property(mpv, 0, "sid", MPV_FORMAT_INT64); mpv_observe_property(mpv, 0, "aid", MPV_FORMAT_INT64); mpv_observe_property(mpv, 0, "sub-visibility", MPV_FORMAT_FLAG); mpv_observe_property(mpv, 0, "mute", MPV_FORMAT_FLAG); mpv_observe_property(mpv, 0, "core-idle", MPV_FORMAT_FLAG); mpv_observe_property(mpv, 0, "paused-for-cache", MPV_FORMAT_FLAG); // setup callback event handling mpv_set_wakeup_callback(mpv, wakeup, this); }
DanmakuDelayGetter::DanmakuDelayGetter(QStringList &names, QStringList &urls, const QString &danmakuUrl, bool download, QObject *parent) : QObject(parent), names(names), urls(urls), danmakuUrl(danmakuUrl), download(download) { mpv = mpv_create(); if (!mpv) { qDebug("Fails to create mpv instance."); deleteLater(); return; } mpv_set_option(mpv, "no-video", MPV_FORMAT_NONE, NULL); mpv_set_option(mpv, "pause", MPV_FORMAT_NONE, NULL); mpv_set_option_string(mpv, "ao", "null"); mpv_set_option_string(mpv, "user-agent", generateUA(urls.first())); QString host = QUrl(urls.first()).host(); if (referer_table.contains(host)) mpv_set_option_string(mpv, "referrer", referer_table[host].constData()); mpv_observe_property(mpv, 0, "duration", MPV_FORMAT_DOUBLE); mpv_set_wakeup_callback(mpv, postEvent, this); if (mpv_initialize(mpv) < 0) { qDebug("Fails to initialaze mpv instance."); deleteLater(); return; } delay = 0; start(); }
static void gt_player_backend_mpv_opengl_init(GtPlayerBackendMpvOpenGL* self) { GtPlayerBackendMpvOpenGLPrivate* priv = gt_player_backend_mpv_opengl_get_instance_private(self); MESSAGE("Init"); setlocale(LC_NUMERIC, "C"); priv->widget = gtk_gl_area_new(); priv->mpv = mpv_create(); g_object_set(priv->widget, "expand", TRUE, NULL); gtk_widget_add_events(priv->widget, GDK_BUTTON_PRESS_MASK); check_mpv_error(mpv_set_option_string(priv->mpv, "audio-client-name", "GNOME Twitch")); check_mpv_error(mpv_set_option_string(priv->mpv, "title", "")); check_mpv_error(mpv_set_option_string(priv->mpv, "vo", "opengl-cb")); check_mpv_error(mpv_set_option_string(priv->mpv, "softvol", "yes")); check_mpv_error(mpv_set_option_string(priv->mpv, "softvol-max", "100")); check_mpv_error(mpv_observe_property(priv->mpv, 0, "volume", MPV_FORMAT_DOUBLE)); check_mpv_error(mpv_observe_property(priv->mpv, 0, "cache-buffering-state", MPV_FORMAT_INT64)); check_mpv_error(mpv_initialize(priv->mpv)); mpv_set_wakeup_callback(priv->mpv, mpv_wakeup_cb, self); priv->mpv_opengl = mpv_get_sub_api(priv->mpv, MPV_SUB_API_OPENGL_CB); mpv_opengl_cb_set_update_callback(priv->mpv_opengl, (mpv_opengl_cb_update_fn) opengl_cb, self); g_signal_connect(priv->widget, "destroy", G_CALLBACK(widget_destroy_cb), self); g_signal_connect(priv->widget, "realize", G_CALLBACK(realise_oneshot_cb), self); g_signal_connect(priv->widget, "render", G_CALLBACK(render_cb), self); }
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QMenu *menu = menuBar()->addMenu(tr("&File")); QAction *on_open = new QAction(tr("&Open"), this); on_open->setShortcuts(QKeySequence::Open); on_open->setStatusTip(tr("Open a file")); connect(on_open, SIGNAL(triggered()), this, SLOT(on_file_open())); menu->addAction(on_open); statusBar(); mpv = mpv_create(); if (!mpv) throw "can't create mpv instance"; // Create a video child window. Force Qt to create a native window, and // pass the window ID to the mpv wid option. This doesn't work on OSX, // because Cocoa doesn't support this form of embedding. mpv_container = new QWidget(this); setCentralWidget(mpv_container); mpv_container->setAttribute(Qt::WA_NativeWindow); // If you have a HWND, use: int64_t wid = (intptr_t)hwnd; int64_t wid = mpv_container->winId(); mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid); // Enable default bindings, because we're lazy. Normally, a player using // mpv as backend would implement its own key bindings. mpv_set_option_string(mpv, "input-default-bindings", "yes"); // Let us receive property change events with MPV_EVENT_PROPERTY_CHANGE if // this property changes. mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE); // From this point on, the wakeup function will be called. The callback // can come from any thread, so we use the Qt QEvent mechanism to relay // the wakeup in a thread-safe way. mpv_set_wakeup_callback(mpv, wakeup, this); if (mpv_initialize(mpv) < 0) throw "mpv failed to initialize"; }
KNMusicBackendMpvThread::KNMusicBackendMpvThread(QObject *parent) : KNMusicStandardBackendThread(parent), m_volumeCurve(QEasingCurve(QEasingCurve::OutQuad)), m_filePath(QString()), m_totalDuration(-1), m_duration(-1), m_startPosition(-1), m_endPosition(-1), m_mpvHandle(nullptr), m_state(MusicUtil::Stopped), m_volumeSize(100) { //Initial the locale settings. setlocale(LC_NUMERIC, "C"); //Create the mpv handle. m_mpvHandle=mpv_create(); //Check out the mpv handle. if(!m_mpvHandle) { //Cannot create an instance for mpv. return; } //Set mpv options. // No mouse handling. mpv_set_option_string(m_mpvHandle, "input-cursor", "no"); // No cursor-autohide. mpv_set_option_string(m_mpvHandle, "cursor-autohide", "no"); mpv_set_option_string(m_mpvHandle, "no-video", NULL); // get updates when these properties change mpv_observe_property(m_mpvHandle, 0, "time-pos", MPV_FORMAT_DOUBLE); // setup callback event handling mpv_set_wakeup_callback(m_mpvHandle, KNMusicBackendMpvThread::instanceWakeUp, this); //Initialize the mpv handler. mpv_initialize(m_mpvHandle); }
static void setup_gtk_stuff(mpv_gtk_helper_context *helper) { // Out of severe lazyness, you don't free ctx. This is left as exercise // to the reader. struct plugin_context *ctx = calloc(1, sizeof(*ctx)); ctx->helper = helper; // Make mpv notify us if there are new events. mpv_set_wakeup_callback(ctx->helper->mpv, wakeup_mpv, ctx); mpv_observe_property(ctx->helper->mpv, 0, "percent-pos", MPV_FORMAT_INT64); GtkWidget *window; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (window, "delete-event", G_CALLBACK (delete_event), ctx); gtk_container_set_border_width (GTK_CONTAINER (window), 10); ctx->pbar = gtk_progress_bar_new (); gtk_container_add (GTK_CONTAINER (window), ctx->pbar); gtk_widget_show (ctx->pbar); gtk_widget_show (window); }
bool PlayerComponent::componentInitialize() { m_mpv = mpv::qt::Handle::FromRawHandle(mpv_create()); if (!m_mpv) throw FatalException(tr("Failed to load mpv.")); mpv_request_log_messages(m_mpv, "terminal-default"); mpv_set_option_string(m_mpv, "msg-level", "all=v"); // No mouse events mpv_set_option_string(m_mpv, "input-cursor", "no"); mpv_set_option_string(m_mpv, "cursor-autohide", "no"); mpv_set_option_string(m_mpv, "config", "yes"); mpv_set_option_string(m_mpv, "config-dir", Paths::dataDir().toUtf8().data()); // We don't need this, so avoid initializing fontconfig. mpv_set_option_string(m_mpv, "use-text-osd", "no"); // This forces the player not to rebase playback time to 0 with mkv. We // require this, because mkv transcoding lets files start at times other // than 0, and web-client expects that we return these times unchanged. mpv::qt::set_option_variant(m_mpv, "demuxer-mkv-probe-start-time", false); // Always use the system mixer. mpv_set_option_string(m_mpv, "softvol", "no"); // Just discard audio output if no audio device could be opened. This gives // us better flexibility how to react to such errors (instead of just // aborting playback immediately). mpv_set_option_string(m_mpv, "audio-fallback-to-null", "yes"); // Do not let the decoder downmix (better customization for us). mpv::qt::set_option_variant(m_mpv, "ad-lavc-downmix", false); // Make it load the hwdec interop, so hwdec can be enabled at runtime. mpv::qt::set_option_variant(m_mpv, "hwdec-preload", "auto"); // User-visible application name used by some audio APIs (at least PulseAudio). mpv_set_option_string(m_mpv, "audio-client-name", QCoreApplication::applicationName().toUtf8().data()); // User-visible stream title used by some audio APIs (at least PulseAudio and wasapi). mpv_set_option_string(m_mpv, "title", QCoreApplication::applicationName().toUtf8().data()); // Apply some low-memory settings on RPI, which is relatively memory-constrained. #ifdef TARGET_RPI // The backbuffer makes seeking back faster (without having to do a HTTP-level seek) mpv::qt::set_option_variant(m_mpv, "cache-backbuffer", 10 * 1024); // KB // The demuxer queue is used for the readahead, and also for dealing with badly // interlaved audio/video. Setting it too low increases sensitivity to network // issues, and could cause playback failure with "bad" files. mpv::qt::set_option_variant(m_mpv, "demuxer-max-bytes", 50 * 1024 * 1024); // bytes #endif mpv_observe_property(m_mpv, 0, "pause", MPV_FORMAT_FLAG); mpv_observe_property(m_mpv, 0, "cache-buffering-state", MPV_FORMAT_INT64); mpv_observe_property(m_mpv, 0, "playback-time", MPV_FORMAT_DOUBLE); mpv_observe_property(m_mpv, 0, "vo-configured", MPV_FORMAT_FLAG); mpv_observe_property(m_mpv, 0, "duration", MPV_FORMAT_DOUBLE); mpv_observe_property(m_mpv, 0, "audio-device-list", MPV_FORMAT_NODE); connect(this, &PlayerComponent::onMpvEvents, this, &PlayerComponent::handleMpvEvents, Qt::QueuedConnection); mpv_set_wakeup_callback(m_mpv, wakeup_cb, this); if (mpv_initialize(m_mpv) < 0) throw FatalException(tr("Failed to initialize mpv.")); // Setup a hook with the ID 1, which is run during the file is loaded. // Used to delay playback start for display framerate switching. // (See handler in handleMpvEvent() for details.) mpv::qt::command_variant(m_mpv, QStringList() << "hook-add" << "on_load" << "1" << "0"); updateAudioDeviceList(); setAudioConfiguration(); updateSubtitleSettings(); updateVideoSettings(); connect(SettingsComponent::Get().getSection(SETTINGS_SECTION_VIDEO), &SettingsSection::valuesUpdated, this, &PlayerComponent::updateVideoSettings); connect(SettingsComponent::Get().getSection(SETTINGS_SECTION_SUBTITLES), &SettingsSection::valuesUpdated, this, &PlayerComponent::updateSubtitleSettings); connect(SettingsComponent::Get().getSection(SETTINGS_SECTION_AUDIO), &SettingsSection::valuesUpdated, this, &PlayerComponent::setAudioConfiguration); return true; }
void gmpv_mpv_obj_initialize(GmpvMpvObj *mpv) { GSettings *main_settings = g_settings_new(CONFIG_ROOT); gchar *config_dir = get_config_dir_path(); gchar *mpvopt = NULL; gchar *current_vo = NULL; gchar *mpv_version = NULL; const struct { const gchar *name; const gchar *value; } options[] = { {"osd-level", "1"}, {"softvol", "yes"}, {"force-window", "yes"}, {"input-default-bindings", "yes"}, {"audio-client-name", ICON_NAME}, {"title", "${media-title}"}, {"autofit-larger", "75%"}, {"window-scale", "1"}, {"pause", "no"}, {"ytdl", "yes"}, {"osd-bar", "no"}, {"input-cursor", "no"}, {"cursor-autohide", "no"}, {"softvol-max", "100"}, {"config", "yes"}, {"screenshot-template", "gnome-mpv-shot%n"}, {"config-dir", config_dir}, {NULL, NULL} }; g_assert(mpv->mpv_ctx); for(gint i = 0; options[i].name; i++) { g_debug( "Applying default option --%s=%s", options[i].name, options[i].value ); mpv_set_option_string( mpv->mpv_ctx, options[i].name, options[i].value ); } if(g_settings_get_boolean(main_settings, "mpv-config-enable")) { gchar *mpv_conf = g_settings_get_string (main_settings, "mpv-config-file"); g_info("Loading config file: %s", mpv_conf); mpv_load_config_file(mpv->mpv_ctx, mpv_conf); g_free(mpv_conf); } if(g_settings_get_boolean(main_settings, "mpv-input-config-enable")) { gchar *input_conf = g_settings_get_string (main_settings, "mpv-input-config-file"); g_info("Loading input config file: %s", input_conf); load_input_conf(mpv, input_conf); g_free(input_conf); } else { load_input_conf(mpv, NULL); } mpvopt = g_settings_get_string(main_settings, "mpv-options"); g_debug("Applying extra mpv options: %s", mpvopt); /* Apply extra options */ if(mpv_obj_apply_args(mpv->mpv_ctx, mpvopt) < 0) { const gchar *msg = _("Failed to apply one or more MPV options."); g_signal_emit_by_name(mpv, "mpv-error", msg); } if(mpv->force_opengl) { g_info("Forcing --vo=opengl-cb"); mpv_set_option_string(mpv->mpv_ctx, "vo", "opengl-cb"); } else { g_debug( "Attaching mpv window to wid %#x", (guint)mpv->wid ); mpv_set_option(mpv->mpv_ctx, "wid", MPV_FORMAT_INT64, &mpv->wid); } mpv_observe_property(mpv->mpv_ctx, 0, "aid", MPV_FORMAT_INT64); mpv_observe_property(mpv->mpv_ctx, 0, "chapters", MPV_FORMAT_INT64); mpv_observe_property(mpv->mpv_ctx, 0, "core-idle", MPV_FORMAT_FLAG); mpv_observe_property(mpv->mpv_ctx, 0, "fullscreen", MPV_FORMAT_FLAG); mpv_observe_property(mpv->mpv_ctx, 0, "pause", MPV_FORMAT_FLAG); mpv_observe_property(mpv->mpv_ctx, 0, "length", MPV_FORMAT_DOUBLE); mpv_observe_property(mpv->mpv_ctx, 0, "media-title", MPV_FORMAT_STRING); mpv_observe_property(mpv->mpv_ctx, 0, "playlist-pos", MPV_FORMAT_INT64); mpv_observe_property(mpv->mpv_ctx, 0, "track-list", MPV_FORMAT_NODE); mpv_observe_property(mpv->mpv_ctx, 0, "volume", MPV_FORMAT_DOUBLE); mpv_set_wakeup_callback(mpv->mpv_ctx, wakeup_callback, mpv); mpv_check_error(mpv_initialize(mpv->mpv_ctx)); mpv_version = gmpv_mpv_obj_get_property_string(mpv, "mpv-version"); current_vo = gmpv_mpv_obj_get_property_string(mpv, "current-vo"); g_info("Using %s", mpv_version); if(current_vo && !GDK_IS_X11_DISPLAY(gdk_display_get_default())) { g_info( "The chosen vo is %s but the display is not X11; " "forcing --vo=opengl-cb and resetting", current_vo ); mpv->force_opengl = TRUE; mpv->state.paused = FALSE; gmpv_mpv_obj_reset(mpv); } else { GSettings *win_settings; gdouble volume; win_settings = g_settings_new(CONFIG_WIN_STATE); volume = g_settings_get_double(win_settings, "volume")*100; g_debug("Setting volume to %f", volume); mpv_set_property( mpv->mpv_ctx, "volume", MPV_FORMAT_DOUBLE, &volume ); /* The vo should be opengl-cb if current_vo is NULL*/ if(!current_vo) { mpv->opengl_ctx = mpv_get_sub_api ( mpv->mpv_ctx, MPV_SUB_API_OPENGL_CB ); } gmpv_mpv_opt_handle_msg_level(mpv); gmpv_mpv_opt_handle_fs(mpv); gmpv_mpv_opt_handle_geometry(mpv); mpv->force_opengl = FALSE; mpv->state.ready = TRUE; g_signal_emit_by_name(mpv, "mpv-init"); g_clear_object(&win_settings); } g_clear_object(&main_settings); g_free(config_dir); g_free(mpvopt); mpv_free(current_vo); mpv_free(mpv_version); }
void MpvAudioOutput::observe_property(const std::string &name, mpv_format format) { auto r = mpv_observe_property(handle_, 0, name.c_str(), format); if (r < 0) qDebug() << "Failed mpv_observe_property " << name.c_str() << ": " << mpv_error_string(r); }