Browse Source

Request "Low Latency" scheduling during video playback

Use AvSetMmThreadCharacteristics() to set "Low Latency" scheduling on
the video rendering thread. In tests with mpv CLI, this has shown to be
helpful, and apparently enables higher performance by disabling energy
saving features which can interfere with playback.

Because I'm afraid that this will affect the system even if video
playback is inactive and the renderer thread is idle, do this only
during playback.
Vincent Lang 9 years ago
parent
commit
96b0fd2604

+ 2 - 1
CMakeModules/Win32Configuration.cmake

@@ -9,4 +9,5 @@ find_library(WINMM winmm)
 find_library(IMMLIB imm32)
 find_library(VERLIB version)
 find_library(DWMLIB dwmapi)
-set(OS_LIBS ${WINMM} ${IMMLIB} ${VERLIB} ${DWMLIB})
+find_library(AVRTLIB avrt)
+set(OS_LIBS ${WINMM} ${IMMLIB} ${VERLIB} ${DWMLIB} ${AVRTLIB})

+ 5 - 0
src/player/PlayerComponent.cpp

@@ -113,6 +113,7 @@ bool PlayerComponent::componentInitialize()
 #endif
 
   mpv_observe_property(m_mpv, 0, "pause", MPV_FORMAT_FLAG);
+  mpv_observe_property(m_mpv, 0, "core-idle", 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);
@@ -369,6 +370,10 @@ void PlayerComponent::handleMpvEvent(mpv_event *event)
         int state = *(int *)prop->data;
         emit paused(state);
       }
+      else if (strcmp(prop->name, "core-idle") == 0 && prop->format == MPV_FORMAT_FLAG)
+      {
+        emit playbackActive(!*(int *)prop->data);
+      }
       else if (strcmp(prop->name, "cache-buffering-state") == 0 && prop->format == MPV_FORMAT_INT64)
       {
         int64_t percentage = *(int64_t *)prop->data;

+ 3 - 0
src/player/PlayerComponent.h

@@ -122,6 +122,9 @@ Q_SIGNALS:
   // playback starts normally
   void playbackStarting();
   void paused(bool paused);
+  // true if the video (or music) is actually
+  // false if nothing is loaded, playback is paused, during seeking, or media is being loaded
+  void playbackActive(bool active);
   void windowVisible(bool visible);
   // emitted as soon as the duration of the current file is known
   void updateDuration(qint64 milliseconds);

+ 20 - 1
src/player/PlayerQuickItem.cpp

@@ -17,6 +17,7 @@
 #include <windows.h>
 #include <d3d9.h>
 #include <dwmapi.h>
+#include <avrt.h>
 
 typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT);
 
@@ -125,7 +126,7 @@ static void* get_proc_address(void* ctx, const char* name)
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 PlayerRenderer::PlayerRenderer(mpv::qt::Handle mpv, QQuickWindow* window)
-: m_mpv(mpv), m_mpvGL(0), m_window(window), m_size()
+: m_mpv(mpv), m_mpvGL(0), m_window(window), m_size(), m_hAvrtHandle(0)
 {
   m_mpvGL = (mpv_opengl_cb_context *)mpv_get_sub_api(m_mpv, MPV_SUB_API_OPENGL_CB);
 }
@@ -171,6 +172,23 @@ void PlayerRenderer::swap()
   mpv_opengl_cb_report_flip(m_mpvGL, 0);
 }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+void PlayerRenderer::onPlaybackActive(bool active)
+{
+#ifdef Q_OS_WIN32
+  if (active && !m_hAvrtHandle)
+  {
+    DWORD handle = 0;
+    m_hAvrtHandle = AvSetMmThreadCharacteristicsW(L"Low Latency", &handle);
+  }
+  else if (!active && m_hAvrtHandle)
+  {
+    AvRevertMmThreadCharacteristics(m_hAvrtHandle);
+    m_hAvrtHandle = 0;
+  }
+#endif
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 PlayerQuickItem::PlayerQuickItem(QQuickItem* parent)
 : QQuickItem(parent), m_mpvGL(NULL), m_renderer(NULL)
@@ -218,6 +236,7 @@ void PlayerQuickItem::onSynchronize()
     }
     connect(window(), &QQuickWindow::beforeRendering, m_renderer, &PlayerRenderer::render, Qt::DirectConnection);
     connect(window(), &QQuickWindow::frameSwapped, m_renderer, &PlayerRenderer::swap, Qt::DirectConnection);
+    connect(&PlayerComponent::Get(), &PlayerComponent::playbackActive, m_renderer, &PlayerRenderer::onPlaybackActive, Qt::QueuedConnection);
     window()->setPersistentOpenGLContext(true);
     window()->setPersistentSceneGraph(true);
     window()->setClearBeforeRendering(false);

+ 9 - 0
src/player/PlayerQuickItem.h

@@ -8,6 +8,10 @@
 #include <mpv/opengl_cb.h>
 #include <mpv/qthelper.hpp>
 
+#ifdef Q_OS_WIN32
+#include <windows.h>
+#endif
+
 #include "PlayerComponent.h"
 
 class PlayerRenderer : public QObject
@@ -21,10 +25,15 @@ class PlayerRenderer : public QObject
   void render();
   void swap();
 
+public slots:
+  void onPlaybackActive(bool active);
+
+private:
   mpv::qt::Handle m_mpv;
   mpv_opengl_cb_context* m_mpvGL;
   QQuickWindow* m_window;
   QSize m_size;
+  HANDLE m_hAvrtHandle;
 };
 
 class PlayerQuickItem : public QQuickItem