_playing = false;
_video_view->stop ();
Stopped (position());
+
+ _video_view->rethrow ();
return true;
}
recreate_butler ();
} else if (p == Film::VIDEO_FRAME_RATE) {
_video_view->set_video_frame_rate (_film->video_frame_rate());
+ } else if (p == Film::THREE_D) {
+ _video_view->set_three_d (_film->three_d());
}
}
_pad_black = p;
}
-/* May be called from a non-UI thread */
+/** Called when a player has finished the current film.
+ * May be called from a non-UI thread.
+ */
void
-FilmViewer::emit_finished ()
+FilmViewer::finished ()
{
- emit (boost::bind(boost::ref(Finished)));
+ emit (boost::bind(&FilmViewer::ui_finished, this));
+}
+
+/** Called by finished() in the UI thread */
+void
+FilmViewer::ui_finished ()
+{
+ stop ();
+ Finished ();
}
int
ClosedCaptionsDialog* closed_captions_dialog () const {
return _closed_captions_dialog;
}
+ void finished ();
boost::signals2::signal<void (boost::weak_ptr<PlayerVideo>)> ImageChanged;
boost::signals2::signal<void (dcpomatic::DCPTime)> Started;
boost::signals2::signal<void (dcpomatic::DCPTime)> Stopped;
/** While playing back we reached the end of the film (emitted from GUI thread) */
boost::signals2::signal<void ()> Finished;
- void emit_finished ();
boost::signals2::signal<bool ()> PlaybackPermitted;
void recreate_butler ();
void config_changed (Config::Property);
void film_length_change ();
+ void ui_finished ();
dcpomatic::DCPTime uncorrected_time () const;
Frame average_latency () const;
void
GLVideoView::update ()
{
- if (!_canvas->IsShownOnScreen()) {
- return;
+ {
+ boost::mutex::scoped_lock lm (_canvas_mutex);
+ if (!_canvas->IsShownOnScreen()) {
+ return;
+ }
}
request_one_shot ();
}
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 ();
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 */
}
glFlush();
+
+ boost::mutex::scoped_lock lm (_canvas_mutex);
_canvas->SwapBuffers();
}
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);
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));
inter_position = player_video().first->inter_position();
inter_size = player_video().first->inter_size();
dcpomatic_sleep_milliseconds (time_until_next_frame());
}
- 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
void create ();
void check_for_butler_errors ();
+ /* Mutex for use of _canvas; it's only contended when our ::thread
+ is started up so this may be overkill.
+ */
+ boost::mutex _canvas_mutex;
wxGLCanvas* _canvas;
wxGLContext* _context;
#include "film_viewer.h"
#include "lib/butler.h"
+using boost::shared_ptr;
+
VideoView::VideoView (FilmViewer* viewer)
: _viewer (viewer)
#ifdef DCPOMATIC_VARIANT_SWAROOP
, _state_timer ("viewer")
, _video_frame_rate (0)
, _eyes (EYES_LEFT)
+ , _three_d (false)
, _dropped (0)
, _gets (0)
{
_player_video.second = dcpomatic::DCPTime ();
}
-/** @param non_blocking true to return false quickly if no video is available quickly.
+/** Could be called from any thread.
+ * @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)
{
- if (_length == dcpomatic::DCPTime()) {
+ if (length() == dcpomatic::DCPTime()) {
return true;
}
- DCPOMATIC_ASSERT (_viewer->butler());
+ shared_ptr<Butler> butler = _viewer->butler ();
+ DCPOMATIC_ASSERT (butler);
add_get ();
boost::mutex::scoped_lock lm (_mutex);
do {
Butler::Error e;
- _player_video = _viewer->butler()->get_video (!non_blocking, &e);
+ _player_video = butler->get_video (!non_blocking, &e);
if (!_player_video.first && e == Butler::AGAIN) {
return false;
}
} while (
_player_video.first &&
- _viewer->film()->three_d() &&
+ _three_d &&
_eyes != _player_video.first->eyes() &&
_player_video.first->eyes() != EYES_BOTH
);
#include "lib/dcpomatic_time.h"
#include "lib/timer.h"
#include "lib/types.h"
+#include "lib/exception_store.h"
#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>
#include <boost/thread.hpp>
+#include <boost/noncopyable.hpp>
class Image;
class wxWindow;
class FilmViewer;
class PlayerVideo;
-class VideoView
+class VideoView : public ExceptionStore, public boost::noncopyable
{
public:
VideoView (FilmViewer* viewer);
_eyes = eyes;
}
+ void set_three_d (bool t) {
+ boost::mutex::scoped_lock lm (_mutex);
+ _three_d = t;
+ }
+
protected:
/* XXX_b: to remove */
friend class FilmViewer;
/** length of the film we are playing, or 0 if there is none */
dcpomatic::DCPTime _length;
Eyes _eyes;
+ bool _three_d;
int _dropped;
int _gets;