Barely-functioning GL playback with new arrangement.
authorCarl Hetherington <cth@carlh.net>
Sun, 20 Oct 2019 22:55:52 +0000 (00:55 +0200)
committerCarl Hetherington <cth@carlh.net>
Wed, 8 Jan 2020 20:56:47 +0000 (21:56 +0100)
12 files changed:
src/lib/cross.cc
src/lib/cross.h
src/tools/dcpomatic.cc
src/tools/dcpomatic_player.cc
src/tools/wscript
src/wx/film_viewer.h
src/wx/gl_video_view.cc
src/wx/gl_video_view.h
src/wx/simple_video_view.cc
src/wx/video_view.cc
src/wx/video_view.h
wscript

index 8d82f7a51bcde1a17ea077eb32060ad85a305e38..5d35d5a4bbcb28da70ca7b77f0ceec678c1a826e 100644 (file)
@@ -75,6 +75,17 @@ dcpomatic_sleep_seconds (int s)
 #endif
 }
 
+void
+dcpomatic_sleep_milliseconds (int ms)
+{
+#ifdef DCPOMATIC_POSIX
+       usleep (ms * 1000);
+#endif
+#ifdef DCPOMATIC_WINDOWS
+       Sleep (ms);
+#endif
+}
+
 /** @return A string of CPU information (model name etc.) */
 string
 cpu_info ()
index 67709463ae4163e8ca86b1864618426b412f2d1d..584fa2b426a7f2fab9460205edbd47cd2395bf8f 100644 (file)
@@ -39,6 +39,7 @@ class Log;
 struct AVIOContext;
 
 void dcpomatic_sleep_seconds (int);
+void dcpomatic_sleep_milliseconds (int);
 extern std::string cpu_info ();
 extern void run_ffprobe (boost::filesystem::path, boost::filesystem::path);
 extern std::list<std::pair<std::string, std::string> > mount_info ();
index 68bf20732a0685d79b3e44800a4003c921522093..47851a21874249f67244ed168259c2c47d9ddbb6 100644 (file)
@@ -92,6 +92,9 @@
 #include <wx/preferences.h>
 #include <wx/splash.h>
 #include <wx/wxhtml.h>
+#ifdef __WXGTK__
+#include <X11/Xlib.h>
+#endif
 #ifdef __WXMSW__
 #include <shellapi.h>
 #endif
@@ -1503,7 +1506,11 @@ public:
                : wxApp ()
                , _frame (0)
                , _splash (0)
-       {}
+       {
+#ifdef DCPOMATIC_LINUX
+               XInitThreads ();
+#endif
+       }
 
 private:
 
index f68d0ead27bad93741e5cd54eca261f33baf199a..6bd5b36ffd1f0f61974c6b94d9de177f7a632aa3 100644 (file)
@@ -66,6 +66,9 @@
 #include <wx/preferences.h>
 #include <wx/progdlg.h>
 #include <wx/display.h>
+#ifdef __WXGTK__
+#include <X11/Xlib.h>
+#endif
 #ifdef __WXOSX__
 #include <ApplicationServices/ApplicationServices.h>
 #endif
@@ -1044,7 +1047,11 @@ public:
        App ()
                : wxApp ()
                , _frame (0)
-       {}
+       {
+#ifdef DCPOMATIC_LINUX
+               XInitThreads ();
+#endif
+       }
 
 private:
 
index 8fd23cfb36b2c028674e614651d26ce293b64186..3b2c0a04ca6eb5b3aaf778563e36a3dcef0f068e 100644 (file)
@@ -68,6 +68,8 @@ def build(bld):
         obj.uselib += ' WXWIDGETS'
         if not bld.env.TARGET_OSX:
             obj.uselib += ' GL GLU'
+        if bld.env.TARGET_LINUX:
+            obj.uselib += ' X11'
         obj.includes = ['..']
         obj.use    = ['libdcpomatic2', 'libdcpomatic2-wx']
         obj.source = '%s.cc' % t
index 55356f18815885a0218e752e9b4a29ea4d55e4d2..a59468c363579ab8a6d7d92c74c5fe47c2095e4b 100644 (file)
@@ -153,6 +153,8 @@ private:
 
        /* XXX_b: to remove */
        friend class SimpleVideoView;
+       friend class GLVideoView;
+       friend class VideoView;
 
        void video_view_sized ();
        void calculate_sizes ();
index a0f83db6d4390dfba4d056d5d4eb13da67048164..c69ab210ab5e962c3ea099043c72a4f20640a4f9 100644 (file)
@@ -23,6 +23,8 @@
 #include "lib/image.h"
 #include "lib/dcpomatic_assert.h"
 #include "lib/exceptions.h"
+#include "lib/cross.h"
+#include "lib/player_video.h"
 #include <boost/bind.hpp>
 #include <iostream>
 
@@ -52,9 +54,9 @@ using boost::optional;
 GLVideoView::GLVideoView (FilmViewer* viewer, wxWindow *parent)
        : VideoView (viewer)
        , _vsync_enabled (false)
+       , _thread (0)
 {
        _canvas = new wxGLCanvas (parent, wxID_ANY, 0, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE);
-       _context = new wxGLContext (_canvas);
        _canvas->Bind (wxEVT_PAINT, boost::bind(&GLVideoView::paint, this));
        _canvas->Bind (wxEVT_SIZE, boost::bind(boost::ref(Sized)));
 
@@ -93,8 +95,13 @@ GLVideoView::GLVideoView (FilmViewer* viewer, wxWindow *parent)
 
 GLVideoView::~GLVideoView ()
 {
+       if (_thread) {
+               _thread->interrupt ();
+               _thread->join ();
+       }
+       delete _thread;
+
        glDeleteTextures (1, &_id);
-       delete _context;
 }
 
 static void
@@ -109,11 +116,14 @@ static void
 void
 GLVideoView::paint ()
 {
+       /* XXX_b: can't do this yet */
+#if 0
         _viewer->state_timer().set("paint-panel");
        _canvas->SetCurrent (*_context);
        wxPaintDC dc (_canvas);
        draw ();
        _viewer->state_timer().unset();
+#endif
 }
 
 void
@@ -122,8 +132,9 @@ GLVideoView::update ()
        if (!_canvas->IsShownOnScreen()) {
                return;
        }
-       wxClientDC dc (_canvas);
-       draw ();
+       /* XXX_b */
+//     wxClientDC dc (_canvas);
+//     draw ();
 }
 
 void
@@ -248,3 +259,62 @@ GLVideoView::set_image (shared_ptr<const Image> image)
        glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        check_gl_error ("glTexParameterf");
 }
+
+void
+GLVideoView::start ()
+{
+       _thread = new boost::thread (boost::bind(&GLVideoView::thread, this));
+}
+
+void
+GLVideoView::thread ()
+try
+{
+       /* XXX_b: check all calls and signal emissions in this method & protect them if necessary */
+       {
+               boost::mutex::scoped_lock lm (_context_mutex);
+               _context = new wxGLContext (_canvas);
+               _canvas->SetCurrent (*_context);
+       }
+
+       while (true) {
+               if (!_viewer->film() || !_viewer->playing()) {
+                       dcpomatic_sleep_milliseconds (40);
+                       continue;
+               }
+
+               dcpomatic::DCPTime const next = _viewer->position() + _viewer->one_video_frame();
+
+               if (next >= _viewer->film()->length()) {
+                       _viewer->stop ();
+                       _viewer->Finished ();
+                       return;
+               }
+
+               get_next_frame (false);
+               set_image (_player_video.first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
+               draw ();
+               _viewer->_video_position = _player_video.second;
+
+               std::cout << "sleep " << _viewer->time_until_next_frame() << "\n";
+               dcpomatic_sleep_milliseconds (_viewer->time_until_next_frame());
+       }
+
+       {
+               boost::mutex::scoped_lock lm (_context_mutex);
+               delete _context;
+       }
+}
+catch (boost::thread_interrupted& e)
+{
+       /* XXX_b: store exceptions here */
+       delete _context;
+       return;
+}
+
+wxGLContext *
+GLVideoView::context () const
+{
+       boost::mutex::scoped_lock lm (_context_mutex);
+       return _context;
+}
index ba4c7cfdc92df3a32afbc9642f3de5d8264b8fdc..e32a1ede95eeea421b808733ea4b0a91058c5a6f 100644 (file)
@@ -23,6 +23,7 @@
 #include <wx/glcanvas.h>
 #include <dcp/util.h>
 #include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
 #undef None
 #undef Success
 
@@ -37,18 +38,25 @@ public:
                return _canvas;
        }
        void update ();
+       void start ();
 
        bool vsync_enabled () const {
                return _vsync_enabled;
        }
 
 private:
-        void paint ();
-        void draw ();
+       void paint ();
+       void draw ();
+       void thread ();
+       wxGLContext* context () const;
 
        wxGLCanvas* _canvas;
-        wxGLContext* _context;
-        GLuint _id;
-        boost::optional<dcp::Size> _size;
+
+       wxGLContext* _context;
+       mutable boost::mutex _context_mutex;
+
+       GLuint _id;
+       boost::optional<dcp::Size> _size;
        bool _vsync_enabled;
+       boost::thread* _thread;
 };
index c195bbc35489024d8fcf435e1dee57d0291755c1..1e97adb30478eafb9e5b4a39195d41dcb2a8e23d 100644 (file)
@@ -159,7 +159,7 @@ SimpleVideoView::timer ()
        }
 
        LOG_DEBUG_PLAYER("%1 -> %2; delay %3", next.seconds(), _viewer->time().seconds(), max((next.seconds() - _viewer->time().seconds()) * 1000, 1.0));
-       _timer.Start (_viewer->time_until_next_frame()), wxTIMER_ONE_SHOT);
+       _timer.Start (_viewer->time_until_next_frame(), wxTIMER_ONE_SHOT);
 
        if (_viewer->butler()) {
                _viewer->butler()->rethrow ();
@@ -180,33 +180,16 @@ SimpleVideoView::start ()
 bool
 SimpleVideoView::get (bool lazy)
 {
-       DCPOMATIC_ASSERT (_viewer->butler());
-       _viewer->_gets++;
-
-       do {
-               Butler::Error e;
-               _player_video = _viewer->butler()->get_video (!lazy, &e);
-               if (!_player_video.first && e == Butler::AGAIN) {
-                       if (lazy) {
-                               /* No video available; return saying we failed */
-                               return false;
-                       } else {
-                               /* Player was suspended; come back later */
-                               signal_manager->when_idle (boost::bind(&SimpleVideoView::get, this, false));
-                               return false;
-                       }
+       bool r = get_next_frame (lazy);
+       if (!r) {
+               if (lazy) {
+                       /* No video available; return saying we failed */
+                       return false;
+               } else {
+                       /* Player was suspended; come back later */
+                       signal_manager->when_idle (boost::bind(&SimpleVideoView::get, this, false));
+                       return false;
                }
-       } while (
-               _player_video.first &&
-               _viewer->film()->three_d() &&
-               _viewer->_eyes != _player_video.first->eyes() &&
-               _player_video.first->eyes() != EYES_BOTH
-               );
-
-       try {
-               _viewer->butler()->rethrow ();
-       } catch (DecodeError& e) {
-               error_dialog (get(), e.what());
        }
 
        display_player_video ();
index eb85079c3795285adf4f5548ff94f86ea4f5e91d..22cad3979dbdc44cb18375f51e9487aa2a7ee09c 100644 (file)
@@ -19,6 +19,9 @@
 */
 
 #include "video_view.h"
+#include "wx_util.h"
+#include "film_viewer.h"
+#include "lib/butler.h"
 
 void
 VideoView::clear ()
@@ -26,3 +29,34 @@ VideoView::clear ()
        _player_video.first.reset ();
        _player_video.second = dcpomatic::DCPTime ();
 }
+
+/** @param non_blocking true to return false quickly if no video is available quickly.
+ *  @return false if we gave up because it would take too long, otherwise true.
+ */
+bool
+VideoView::get_next_frame (bool non_blocking)
+{
+       DCPOMATIC_ASSERT (_viewer->butler());
+       _viewer->_gets++;
+
+       do {
+               Butler::Error e;
+               _player_video = _viewer->butler()->get_video (!non_blocking, &e);
+               if (!_player_video.first && e == Butler::AGAIN) {
+                       return false;
+               }
+       } while (
+               _player_video.first &&
+               _viewer->film()->three_d() &&
+               _viewer->_eyes != _player_video.first->eyes() &&
+               _player_video.first->eyes() != EYES_BOTH
+               );
+
+       try {
+               _viewer->butler()->rethrow ();
+       } catch (DecodeError& e) {
+               error_dialog (get(), e.what());
+       }
+
+       return true;
+}
index f4a8ea22bcf1b4c13087c2cfcc92ba13c9bb6ad8..827d1bf73d65a2f0e8a93c2c7d5c4862dd7ec834 100644 (file)
@@ -64,6 +64,8 @@ protected:
        /* XXX_b: to remove */
        friend class FilmViewer;
 
+       bool get_next_frame (bool non_blocking);
+
        FilmViewer* _viewer;
        std::pair<boost::shared_ptr<PlayerVideo>, dcpomatic::DCPTime> _player_video;
 
diff --git a/wscript b/wscript
index 9f45778e9e99999186c2c551c88752fdaaf728d2..fe14313160623cc5f167b0aebd30d3c2c1ca7580 100644 (file)
--- a/wscript
+++ b/wscript
@@ -444,6 +444,9 @@ def configure(conf):
     conf.env['CXXFLAGS_AVCODEC'] = []
     conf.env['CXXFLAGS_AVUTIL'] = []
 
+    if conf.env.TARGET_LINUX:
+        conf.env.LIB_X11 = ['X11']
+
     # Boost
     if conf.options.static_boost:
         conf.env.STLIB_BOOST_THREAD = ['boost_thread']