[vlc-devel] [PATCH 3/3] vout: win32: handle tilt sensors for VR orientation

Steve Lhomme robux4 at videolabs.io
Mon Feb 27 17:35:29 CET 2017


---
 modules/video_output/Makefile.am       |   5 +
 modules/video_output/win32/events.c    |   7 +
 modules/video_output/win32/events.h    |   9 ++
 modules/video_output/win32/sensors.cpp | 235 +++++++++++++++++++++++++++++++++
 4 files changed, 256 insertions(+)
 create mode 100644 modules/video_output/win32/sensors.cpp

diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index ab35948e33..d2144f8ac4 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -208,6 +208,7 @@ endif
 libdirect3d9_plugin_la_SOURCES = video_output/win32/direct3d9.c \
 	video_output/win32/common.c video_output/win32/common.h \
 	video_output/win32/events.c video_output/win32/events.h \
+	video_output/win32/sensors.cpp \
 	video_output/win32/builtin_shaders.h \
 	video_output/win32/win32touch.c video_output/win32/win32touch.h
 libdirect3d9_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
@@ -227,6 +228,7 @@ libdirect3d11_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
 if !HAVE_WINSTORE
 libdirect3d11_plugin_la_SOURCES += video_output/win32/events.c \
  video_output/win32/events.h \
+ video_output/win32/sensors.cpp \
  video_output/win32/win32touch.c video_output/win32/win32touch.h
 libdirect3d11_plugin_la_LIBADD = -lgdi32 $(LIBCOM) -luuid
 else
@@ -239,6 +241,7 @@ EXTRA_LTLIBRARIES += libdirect3d11_plugin.la
 libdirectdraw_plugin_la_SOURCES = video_output/win32/directdraw.c \
 	video_output/win32/common.c video_output/win32/common.h \
 	video_output/win32/events.c video_output/win32/events.h \
+	video_output/win32/sensors.cpp \
 	video_output/win32/win32touch.c video_output/win32/win32touch.h
 libdirectdraw_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
 	-DMODULE_NAME_IS_directdraw
@@ -253,6 +256,7 @@ libglwin32_plugin_la_SOURCES = $(OPENGL_COMMONSOURCES) \
 	video_output/win32/glwin32.c \
 	video_output/win32/common.c video_output/win32/common.h \
 	video_output/win32/events.c video_output/win32/events.h \
+	video_output/win32/sensors.cpp \
 	video_output/win32/win32touch.c video_output/win32/win32touch.h
 libwgl_plugin_la_SOURCES = video_output/win32/wgl.c $(OPENGL_COMMONSOURCES)
 
@@ -277,6 +281,7 @@ endif
 libwingdi_plugin_la_SOURCES = video_output/win32/wingdi.c \
 	video_output/win32/common.c video_output/win32/common.h \
 	video_output/win32/events.c video_output/win32/events.h \
+	video_output/win32/sensors.cpp \
 	video_output/win32/win32touch.c video_output/win32/win32touch.h
 libwingdi_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
 	-DMODULE_NAME_IS_wingdi
diff --git a/modules/video_output/win32/events.c b/modules/video_output/win32/events.c
index 231086ce30..51ef3f34ec 100644
--- a/modules/video_output/win32/events.c
+++ b/modules/video_output/win32/events.c
@@ -76,6 +76,9 @@ struct event_thread_t
     /* Gestures */
     win32_gesture_sys_t *p_gesture;
 
+    /* Sensors */
+    void *p_sensors;
+
     /* Title */
     char *psz_title;
 
@@ -802,6 +805,8 @@ static int Win32VoutCreateWindow( event_thread_t *p_event )
 
     InitGestures( p_event->hwnd, &p_event->p_gesture );
 
+    p_event->p_sensors = HookWindowsSensors(vd, p_event->hwnd);
+
     if( p_event->hparent )
     {
         LONG i_style;
@@ -891,6 +896,8 @@ static void Win32VoutCloseWindow( event_thread_t *p_event )
 
     DestroyCursor( p_event->cursor_empty );
 
+    UnhookWindowsSensors(p_event->p_sensors);
+
     CloseGestures( p_event->p_gesture);
 }
 
diff --git a/modules/video_output/win32/events.h b/modules/video_output/win32/events.h
index 883d769c28..af1414fcde 100644
--- a/modules/video_output/win32/events.h
+++ b/modules/video_output/win32/events.h
@@ -62,3 +62,12 @@ void            EventThreadUpdateSourceAndPlace( event_thread_t *p_event,
 void            EventThreadUseOverlay( event_thread_t *, bool b_used );
 bool            EventThreadGetAndResetHasMoved( event_thread_t * );
 
+# ifdef __cplusplus
+extern "C" {
+# endif
+void* HookWindowsSensors(vout_display_t*, HWND);
+void UnhookWindowsSensors(void*);
+# ifdef __cplusplus
+}
+# endif
+
diff --git a/modules/video_output/win32/sensors.cpp b/modules/video_output/win32/sensors.cpp
new file mode 100644
index 0000000000..13d171c3fd
--- /dev/null
+++ b/modules/video_output/win32/sensors.cpp
@@ -0,0 +1,235 @@
+/*****************************************************************************
+ * sensors.cpp: Windows sensor handling
+ *****************************************************************************
+ * Copyright © 2017 Steve Lhomme
+ * Copyright © 2017 VideoLabs
+ *
+ * Authors: Steve Lhomme <robux4 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_vout_wrapper.h>
+#include <vlc_charset.h> /* FromWide */
+#include "events.h"
+
+#include <initguid.h>
+#include <propsys.h> /* stupid mingw headers don't include this */
+#include <sensors.h>
+#include <sensorsapi.h>
+
+#include <new>
+
+#ifndef _MSC_VER
+DEFINE_PROPERTYKEY(SENSOR_DATA_TYPE_MAGNETOMETER_ACCURACY, 0x1637d8a2, 0x4248, 0x4275, 0x86, 0x5d, 0x55, 0x8d, 0xe8, 0x4a, 0xed, 0xfd, 22);
+#endif
+
+class SensorReceiver : public ISensorEvents
+{
+public:
+    SensorReceiver(vout_display_t *vd, const vlc_viewpoint_t & init_viewpoint)
+        :vd(vd)
+        ,current_pos(init_viewpoint)
+    {}
+
+    virtual ~SensorReceiver()
+    {}
+
+    STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
+    {
+        if (ppv == NULL)
+        {
+            return E_POINTER;
+        }
+        if (iid == __uuidof(IUnknown))
+        {
+            *ppv = static_cast<IUnknown*>(this);
+        }
+        else if (iid == __uuidof(ISensorEvents))
+        {
+            *ppv = static_cast<ISensorEvents*>(this);
+        }
+        else
+        {
+            *ppv = NULL;
+            return E_NOINTERFACE;
+        }
+        AddRef();
+        return S_OK;
+    }
+
+    STDMETHODIMP_(ULONG) AddRef()
+    {
+        return InterlockedIncrement(&m_cRef);
+    }
+
+    STDMETHODIMP_(ULONG) Release()
+    {
+        ULONG count = InterlockedDecrement(&m_cRef);
+        if (count == 0)
+        {
+            delete this;
+            return 0;
+        }
+        return count;
+    }
+
+    HRESULT STDMETHODCALLTYPE OnStateChanged(ISensor *pSensor, SensorState state)
+    {
+        (void)pSensor;
+        (void)state;
+        return S_OK;
+    }
+
+    HRESULT STDMETHODCALLTYPE OnDataUpdated(ISensor *pSensor, ISensorDataReport *pNewData)
+    {
+        (void)pSensor;
+        vlc_viewpoint_t old_pos = current_pos;
+        HRESULT hr;
+        PROPVARIANT pvRot;
+
+        PropVariantInit(&pvRot);
+        hr = pNewData->GetSensorValue(SENSOR_DATA_TYPE_TILT_X_DEGREES, &pvRot);
+        if (SUCCEEDED(hr) && pvRot.vt == VT_R4)
+        {
+            current_pos.pitch = pvRot.fltVal;
+            PropVariantClear(&pvRot);
+        }
+        hr = pNewData->GetSensorValue(SENSOR_DATA_TYPE_TILT_Y_DEGREES, &pvRot);
+        if (SUCCEEDED(hr) && pvRot.vt == VT_R4)
+        {
+            current_pos.roll = pvRot.fltVal;
+            PropVariantClear(&pvRot);
+        }
+        hr = pNewData->GetSensorValue(SENSOR_DATA_TYPE_TILT_Z_DEGREES, &pvRot);
+        if (SUCCEEDED(hr) && pvRot.vt == VT_R4)
+        {
+            current_pos.yaw = pvRot.fltVal;
+            PropVariantClear(&pvRot);
+        }
+
+        vout_display_SendEventViewpointChanged(vd, current_pos.yaw   - old_pos.yaw,
+                                                   current_pos.pitch - old_pos.pitch,
+                                                   current_pos.roll  - old_pos.roll);
+        return S_OK;
+    }
+
+    HRESULT STDMETHODCALLTYPE OnEvent(ISensor *pSensor, REFGUID eventID, IPortableDeviceValues *pEventData)
+    {
+        (void)pSensor;
+        (void)eventID;
+        (void)pEventData;
+        return S_OK;
+    }
+
+    HRESULT STDMETHODCALLTYPE OnLeave(REFSENSOR_ID ID)
+    {
+        (void)ID;
+        return S_OK;
+    }
+
+private:
+    vout_display_t *const vd;
+    vlc_viewpoint_t current_pos;
+    long m_cRef;
+};
+
+void *HookWindowsSensors(vout_display_t *vd, HWND hwnd)
+{
+    ISensor *pSensor = NULL;
+    ISensorManager *pSensorManager;
+    HRESULT hr = CoCreateInstance( CLSID_SensorManager,
+                      NULL, CLSCTX_INPROC_SERVER,
+                      IID_ISensorManager, (void**)&pSensorManager );
+    if (SUCCEEDED(hr))
+    {
+        ISensorCollection *pInclinometers;
+        hr = pSensorManager->GetSensorsByType(SENSOR_TYPE_INCLINOMETER_3D, &pInclinometers);
+        if (SUCCEEDED(hr))
+        {
+            ULONG count;
+            pInclinometers->GetCount(&count);
+            msg_Dbg(vd, "Found %lu inclinometer", count);
+            for (ULONG i=0; i<count; ++i)
+            {
+                hr = pInclinometers->GetAt(i, &pSensor);
+                if (SUCCEEDED(hr))
+                {
+                    SensorState state = SENSOR_STATE_NOT_AVAILABLE;
+                    hr = pSensor->GetState(&state);
+                    if (SUCCEEDED(hr))
+                    {
+                        if (state == SENSOR_STATE_ACCESS_DENIED)
+                            hr = pSensorManager->RequestPermissions(hwnd, pInclinometers, TRUE);
+
+                        if (SUCCEEDED(hr))
+                        {
+                            vlc_viewpoint_t start_viewpoint;
+                            vlc_viewpoint_init(&start_viewpoint);
+                            PROPVARIANT pvRot;
+                            PropVariantInit(&pvRot);
+                            hr = pSensor->GetProperty(SENSOR_DATA_TYPE_TILT_X_DEGREES, &pvRot);
+                            if (SUCCEEDED(hr) && pvRot.vt == VT_R4)
+                            {
+                                start_viewpoint.pitch = pvRot.fltVal;
+                                PropVariantClear(&pvRot);
+                            }
+                            hr = pSensor->GetProperty(SENSOR_DATA_TYPE_TILT_Y_DEGREES, &pvRot);
+                            if (SUCCEEDED(hr) && pvRot.vt == VT_R4)
+                            {
+                                start_viewpoint.roll = pvRot.fltVal;
+                                PropVariantClear(&pvRot);
+                            }
+                            hr = pSensor->GetProperty(SENSOR_DATA_TYPE_TILT_Z_DEGREES, &pvRot);
+                            if (SUCCEEDED(hr) && pvRot.vt == VT_R4)
+                            {
+                                start_viewpoint.yaw = pvRot.fltVal;
+                                PropVariantClear(&pvRot);
+                            }
+
+                            SensorReceiver *received = new(std::nothrow) SensorReceiver(vd, start_viewpoint);
+                            if (received)
+                            {
+                                pSensor->SetEventSink(received);
+                                break;
+                            }
+                        }
+                    }
+
+                    pSensor->Release();
+                }
+            }
+            pInclinometers->Release();
+        }
+        else
+            msg_Dbg(vd, "inclinometer not found. (hr=0x%lX)", hr);
+        pSensorManager->Release();
+    }
+    return pSensor;
+}
+
+void UnhookWindowsSensors(void *vSensor)
+{
+    if (!vSensor)
+        return;
+
+    ISensor *pSensor = static_cast<ISensor*>(vSensor);
+    pSensor->SetEventSink(NULL);
+    pSensor->Release();
+}
-- 
2.11.1



More information about the vlc-devel mailing list