X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fwx%2Fgl_video_view.cc;h=0e4bcb671b88cfbebdba84ac0fe55a6b42169fe8;hb=6ef1fc5f40567650ca9ef2b7644e4fdd97640ae6;hp=836b3eb351584b790e9c6f077c4e090b3d73277a;hpb=83c9e9c858072ab919916269790dcc65565fdd25;p=dcpomatic.git diff --git a/src/wx/gl_video_view.cc b/src/wx/gl_video_view.cc index 836b3eb35..0e4bcb671 100644 --- a/src/wx/gl_video_view.cc +++ b/src/wx/gl_video_view.cc @@ -55,13 +55,13 @@ using boost::optional; GLVideoView::GLVideoView (FilmViewer* viewer, wxWindow *parent) : VideoView (viewer) + , _have_storage (false) , _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)); @@ -104,9 +104,12 @@ GLVideoView::GLVideoView (FilmViewer* viewer, wxWindow *parent) GLVideoView::~GLVideoView () { - _thread->interrupt (); - _thread->join (); - delete _thread; + try { + _thread.interrupt (); + _thread.join (); + } catch (...) { + + } glDeleteTextures (1, &_id); } @@ -114,6 +117,10 @@ GLVideoView::~GLVideoView () void GLVideoView::check_for_butler_errors () { + if (!_viewer->butler()) { + return; + } + try { _viewer->butler()->rethrow (); } catch (DecodeError& e) { @@ -130,25 +137,20 @@ check_gl_error (char const * last) } } -void -GLVideoView::paint () -{ - request_one_shot (); -} - 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"); @@ -163,16 +165,22 @@ 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 (); @@ -205,8 +213,6 @@ GLVideoView::draw () glEnd (); } - 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 */ @@ -240,8 +246,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); @@ -251,6 +255,8 @@ GLVideoView::draw () } glFlush(); + + boost::mutex::scoped_lock lm (_canvas_mutex); _canvas->SwapBuffers(); } @@ -265,11 +271,21 @@ GLVideoView::set_image (shared_ptr image) DCPOMATIC_ASSERT (image->pixel_format() == AV_PIX_FMT_RGB24); DCPOMATIC_ASSERT (!image->aligned()); + if (image->size() != _size) { + _have_storage = false; + } + _size = image->size (); glPixelStorei (GL_UNPACK_ALIGNMENT, 1); check_gl_error ("glPixelStorei"); - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB8, _size->width, _size->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image->data()[0]); - check_gl_error ("glTexImage2D"); + if (_have_storage) { + glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, _size->width, _size->height, GL_RGB, GL_UNSIGNED_BYTE, image->data()[0]); + check_gl_error ("glTexSubImage2D"); + } else { + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB8, _size->width, _size->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image->data()[0]); + _have_storage = true; + check_gl_error ("glTexImage2D"); + } glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -283,6 +299,8 @@ GLVideoView::set_image (shared_ptr image) void GLVideoView::start () { + VideoView::start (); + boost::mutex::scoped_lock lm (_playing_mutex); _playing = true; _playing_condition.notify_all (); @@ -299,9 +317,11 @@ void GLVideoView::thread () try { - /* XXX_b: check all calls and signal emissions in this method & protect them if necessary */ - _context = new wxGLContext (_canvas); - _canvas->SetCurrent (*_context); + { + boost::mutex::scoped_lock lm (_canvas_mutex); + _context = new wxGLContext (_canvas); //local + _canvas->SetCurrent (*_context); + } while (true) { boost::mutex::scoped_lock lm (_playing_mutex); @@ -311,35 +331,46 @@ try _one_shot = false; 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->stop (); - _viewer->emit_finished (); + _viewer->finished (); continue; } get_next_frame (false); - set_image (player_video().first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true)); + 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 (); + draw (inter_position, inter_size); - while (time_until_next_frame() < 5) { + while (true) { + optional n = time_until_next_frame(); + if (!n || *n > 5) { + break; + } get_next_frame (true); + add_dropped (); } boost::this_thread::interruption_point (); - dcpomatic_sleep_milliseconds (time_until_next_frame()); + dcpomatic_sleep_milliseconds (time_until_next_frame().get_value_or(0)); } - 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 (); } bool @@ -361,7 +392,7 @@ GLVideoView::request_one_shot () void GLVideoView::create () { - if (!_thread) { - _thread = new boost::thread (boost::bind(&GLVideoView::thread, this)); + if (!_thread.joinable()) { + _thread = boost::thread (boost::bind(&GLVideoView::thread, this)); } }