X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fwx%2Fgl_video_view.cc;h=ddae9bb3c4861b0406550cd9ad542ec1c0881b3d;hb=b33437685e43427459e7ea752f3cd3d621878573;hp=ebf8b8fe211e6b74421a9a0c68f349f2db67132e;hpb=805487369e57e5eb57911805ba6de78b653d79ad;p=dcpomatic.git diff --git a/src/wx/gl_video_view.cc b/src/wx/gl_video_view.cc index ebf8b8fe2..ddae9bb3c 100644 --- a/src/wx/gl_video_view.cc +++ b/src/wx/gl_video_view.cc @@ -20,11 +20,13 @@ #include "gl_video_view.h" #include "film_viewer.h" +#include "wx_util.h" #include "lib/image.h" #include "lib/dcpomatic_assert.h" #include "lib/exceptions.h" #include "lib/cross.h" #include "lib/player_video.h" +#include "lib/butler.h" #include #include @@ -55,11 +57,17 @@ GLVideoView::GLVideoView (FilmViewer* viewer, wxWindow *parent) : VideoView (viewer) , _vsync_enabled (false) , _thread (0) + , _playing (false) , _one_shot (false) { _canvas = new wxGLCanvas (parent, wxID_ANY, 0, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE); - _canvas->Bind (wxEVT_PAINT, boost::bind(&GLVideoView::paint, this)); + _canvas->Bind (wxEVT_PAINT, boost::bind(&GLVideoView::update, this)); _canvas->Bind (wxEVT_SIZE, boost::bind(boost::ref(Sized))); + _canvas->Bind (wxEVT_CREATE, boost::bind(&GLVideoView::create, this)); + + _canvas->Bind (wxEVT_TIMER, boost::bind(&GLVideoView::check_for_butler_errors, this)); + _timer.reset (new wxTimer(_canvas)); + _timer->Start (2000); #if defined(DCPOMATIC_LINUX) && defined(DCPOMATIC_HAVE_GLX_SWAP_INTERVAL_EXT) if (_canvas->IsExtensionSupported("GLX_EXT_swap_control")) { @@ -96,15 +104,23 @@ GLVideoView::GLVideoView (FilmViewer* viewer, wxWindow *parent) GLVideoView::~GLVideoView () { - if (_thread) { - _thread->interrupt (); - _thread->join (); - } + _thread->interrupt (); + _thread->join (); delete _thread; glDeleteTextures (1, &_id); } +void +GLVideoView::check_for_butler_errors () +{ + try { + _viewer->butler()->rethrow (); + } catch (DecodeError& e) { + error_dialog (get(), e.what()); + } +} + static void check_gl_error (char const * last) { @@ -114,32 +130,20 @@ check_gl_error (char const * last) } } -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 GLVideoView::update () { - if (!_canvas->IsShownOnScreen()) { - return; + { + boost::mutex::scoped_lock lm (_canvas_mutex); + if (!_canvas->IsShownOnScreen()) { + return; + } } - /* XXX_b */ -// wxClientDC dc (_canvas); -// draw (); + request_one_shot (); } void -GLVideoView::draw () +GLVideoView::draw (Position inter_position, dcp::Size inter_size) { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); check_gl_error ("glClear"); @@ -154,25 +158,33 @@ GLVideoView::draw () check_gl_error ("glDisable GL_DEPTH_TEST"); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if (_canvas->GetSize().x < 64 || _canvas->GetSize().y < 0) { + wxSize canvas_size; + { + boost::mutex::scoped_lock lm (_canvas_mutex); + canvas_size = _canvas->GetSize (); + } + + if (canvas_size.GetWidth() < 64 || canvas_size.GetHeight() < 0) { return; } - glViewport (0, 0, _canvas->GetSize().x, _canvas->GetSize().y); + glViewport (0, 0, canvas_size.GetWidth(), canvas_size.GetHeight()); check_gl_error ("glViewport"); glMatrixMode (GL_PROJECTION); glLoadIdentity (); - gluOrtho2D (0, _canvas->GetSize().x, _canvas->GetSize().y, 0); + gluOrtho2D (0, canvas_size.GetWidth(), canvas_size.GetHeight(), 0); check_gl_error ("gluOrtho2d"); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glTranslatef (0, 0, 0); + dcp::Size const out_size = _viewer->out_size (); + if (_size) { + /* Render our image (texture) */ glBegin (GL_QUADS); - glTexCoord2f (0, 1); glVertex2f (0, _size->height); glTexCoord2f (1, 1); @@ -181,13 +193,19 @@ GLVideoView::draw () glVertex2f (_size->width, 0); glTexCoord2f (0, 0); glVertex2f (0, 0); - + glEnd (); + } else { + /* No image, so just fill with black */ + glBegin (GL_QUADS); + glColor3ub (0, 0, 0); + glVertex2f (0, 0); + glVertex2f (out_size.width, 0); + glVertex2f (out_size.width, out_size.height); + glVertex2f (0, out_size.height); + glVertex2f (0, 0); glEnd (); } - dcp::Size const out_size = _viewer->out_size (); - wxSize const canvas_size = _canvas->GetSize (); - if (!_viewer->pad_black() && out_size.width < canvas_size.GetWidth()) { glBegin (GL_QUADS); /* XXX: these colours are right for GNOME; may need adjusting for other OS */ @@ -221,8 +239,6 @@ GLVideoView::draw () if (_viewer->outline_content()) { glColor3ub (255, 0, 0); glBegin (GL_LINE_LOOP); - Position inter_position = _viewer->inter_position (); - dcp::Size inter_size = _viewer->inter_size (); glVertex2f (inter_position.x, inter_position.y + (canvas_size.GetHeight() - out_size.height) / 2); glVertex2f (inter_position.x + inter_size.width, inter_position.y + (canvas_size.GetHeight() - out_size.height) / 2); glVertex2f (inter_position.x + inter_size.width, inter_position.y + (canvas_size.GetHeight() - out_size.height) / 2 + inter_size.height); @@ -232,6 +248,8 @@ GLVideoView::draw () } glFlush(); + + boost::mutex::scoped_lock lm (_canvas_mutex); _canvas->SwapBuffers(); } @@ -264,70 +282,96 @@ GLVideoView::set_image (shared_ptr image) void GLVideoView::start () { - _thread = new boost::thread (boost::bind(&GLVideoView::thread, this)); + VideoView::start (); + + boost::mutex::scoped_lock lm (_playing_mutex); + _playing = true; + _playing_condition.notify_all (); +} + +void +GLVideoView::stop () +{ + boost::mutex::scoped_lock lm (_playing_mutex); + _playing = false; } 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); + boost::mutex::scoped_lock lm (_canvas_mutex); + _context = new wxGLContext (_canvas); //local _canvas->SetCurrent (*_context); } while (true) { - if ((!_viewer->film() || !_viewer->playing()) && !_one_shot) { - dcpomatic_sleep_milliseconds (40); - continue; + boost::mutex::scoped_lock lm (_playing_mutex); + while (!_playing && !_one_shot) { + _playing_condition.wait (lm); } - _one_shot = false; - - dcpomatic::DCPTime const next = _viewer->position() + _viewer->one_video_frame(); - - if (next >= _viewer->film()->length()) { - _viewer->stop (); - _viewer->Finished (); - continue; + lm.unlock (); + + Position inter_position; + dcp::Size inter_size; + if (length() != dcpomatic::DCPTime()) { + dcpomatic::DCPTime const next = position() + one_video_frame(); + + if (next >= length()) { + _viewer->finished (); + continue; + } + + get_next_frame (false); + shared_ptr pv = player_video().first; + if (pv) { + set_image (pv->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true)); + inter_position = pv->inter_position(); + inter_size = pv->inter_size(); + } } + draw (inter_position, inter_size); - get_next_frame (false); - set_image (_player_video.first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true)); - draw (); - - while (_viewer->time_until_next_frame() < 5) { + while (time_until_next_frame() < 5) { get_next_frame (true); + add_dropped (); } - dcpomatic_sleep_milliseconds (_viewer->time_until_next_frame()); + boost::this_thread::interruption_point (); + dcpomatic_sleep_milliseconds (time_until_next_frame()); } - { - boost::mutex::scoped_lock lm (_context_mutex); - delete _context; - } + /* XXX: leaks _context, but that seems preferable to deleting it here + * without also deleting the wxGLCanvas. + */ } catch (boost::thread_interrupted& e) { - /* XXX_b: store exceptions here */ - delete _context; - return; + store_current (); } -wxGLContext * -GLVideoView::context () const +bool +GLVideoView::display_next_frame (bool non_blocking) { - boost::mutex::scoped_lock lm (_context_mutex); - return _context; + bool const r = get_next_frame (non_blocking); + request_one_shot (); + return r; } -bool -GLVideoView::display_next_frame (bool non_blocking) +void +GLVideoView::request_one_shot () { - bool const g = get_next_frame (non_blocking); + boost::mutex::scoped_lock lm (_playing_mutex); _one_shot = true; - return g; + _playing_condition.notify_all (); +} + +void +GLVideoView::create () +{ + if (!_thread) { + _thread = new boost::thread (boost::bind(&GLVideoView::thread, this)); + } }