/*
- Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#include "playhead_to_frame_dialog.h"
#include "wx_util.h"
#include "closed_captions_dialog.h"
+#include "gl_video_view.h"
+#include "simple_video_view.h"
#include "lib/film.h"
#include "lib/ratio.h"
#include "lib/util.h"
#include "lib/log.h"
#include "lib/config.h"
#include "lib/compose.hpp"
+#include "lib/dcpomatic_log.h"
extern "C" {
#include <libavutil/pixfmt.h>
}
using boost::weak_ptr;
using boost::optional;
using dcp::Size;
+using namespace dcpomatic;
static
int
}
FilmViewer::FilmViewer (wxWindow* p)
- : _panel (new wxPanel (p))
- , _coalesce_player_changes (false)
+ : _coalesce_player_changes (false)
, _audio (DCPOMATIC_RTAUDIO_API)
, _audio_channels (0)
, _audio_block_size (1024)
, _playing (false)
, _latency_history_count (0)
, _dropped (0)
- , _closed_captions_dialog (new ClosedCaptionsDialog(p))
+ , _closed_captions_dialog (new ClosedCaptionsDialog(p, this))
, _outline_content (false)
, _eyes (EYES_LEFT)
+ , _pad_black (false)
#ifdef DCPOMATIC_VARIANT_SWAROOP
, _in_watermark (false)
+ , _background_image (false)
#endif
+ , _state_timer ("viewer")
+ , _gets (0)
{
-#ifndef __WXOSX__
- _panel->SetDoubleBuffered (true);
-#endif
-
- _panel->SetBackgroundStyle (wxBG_STYLE_PAINT);
- _panel->SetBackgroundColour (*wxBLACK);
+ switch (Config::instance()->video_view_type()) {
+ case Config::VIDEO_VIEW_OPENGL:
+ _video_view = new GLVideoView (this, p);
+ break;
+ case Config::VIDEO_VIEW_SIMPLE:
+ _video_view = new SimpleVideoView (this, p);
+ break;
+ }
- _panel->Bind (wxEVT_PAINT, boost::bind (&FilmViewer::paint_panel, this));
- _panel->Bind (wxEVT_SIZE, boost::bind (&FilmViewer::panel_sized, this, _1));
- _timer.Bind (wxEVT_TIMER, boost::bind (&FilmViewer::timer, this));
+ _video_view->Sized.connect (boost::bind(&FilmViewer::video_view_sized, this));
+ _timer.Bind (wxEVT_TIMER, boost::bind(&FilmViewer::timer, this));
set_film (shared_ptr<Film> ());
}
_film = film;
+ _video_position = DCPTime ();
+ _player_video.first.reset ();
+ _player_video.second = DCPTime ();
- FilmChanged ();
-
- _frame.reset ();
+ _video_view->set_image (shared_ptr<Image>());
_closed_captions_dialog->clear ();
if (!_film) {
_player.reset ();
recreate_butler ();
- _frame.reset ();
- refresh_panel ();
+ refresh_view ();
return;
}
if (_dcp_decode_reduction) {
_player->set_dcp_decode_reduction (_dcp_decode_reduction);
}
- } catch (bad_alloc) {
- error_dialog (_panel, _("There is not enough free memory to do that."));
+ } catch (bad_alloc &) {
+ error_dialog (_video_view->get(), _("There is not enough free memory to do that."));
_film.reset ();
return;
}
map.set (dcp::RS, 1, 1 / sqrt(2)); // Rs -> Rt
}
- _butler.reset (new Butler (_player, _film->log(), map, _audio_channels));
+ _butler.reset (new Butler(_player, map, _audio_channels, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
if (!Config::instance()->sound() && !_audio.isStreamOpen()) {
_butler->disable_audio ();
}
- _closed_captions_dialog->set_butler (_butler);
+ _closed_captions_dialog->set_film_and_butler (_film, _butler);
if (was_running) {
start ();
}
void
-FilmViewer::refresh_panel ()
+FilmViewer::refresh_view ()
{
- _panel->Refresh ();
- _panel->Update ();
+ _state_timer.set ("update-view");
+ _video_view->update ();
+ _state_timer.unset ();
}
void
FilmViewer::get ()
{
DCPOMATIC_ASSERT (_butler);
+ ++_gets;
do {
Butler::Error e;
} while (
_player_video.first &&
_film->three_d() &&
- (_eyes != _player_video.first->eyes())
+ _eyes != _player_video.first->eyes() &&
+ _player_video.first->eyes() != EYES_BOTH
);
_butler->rethrow ();
FilmViewer::display_player_video ()
{
if (!_player_video.first) {
- _frame.reset ();
- refresh_panel ();
+ _video_view->set_image (shared_ptr<Image>());
+ refresh_view ();
return;
}
* The content's specified colour conversion indicates the colourspace
* which the content is in (according to the user).
*
- * PlayerVideo::image (bound to PlayerVideo::always_rgb) will take the source
+ * PlayerVideo::image (bound to PlayerVideo::force) will take the source
* image and convert it (from whatever the user has said it is) to RGB.
*/
- _frame = _player_video.first->image (
- bind (&Log::dcp_log, _film->log().get(), _1, _2),
- bind (&PlayerVideo::always_rgb, _1),
- false, true
+ _state_timer.set ("get image");
+
+ _video_view->set_image (
+ _player_video.first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true)
);
+ _state_timer.set ("ImageChanged");
ImageChanged (_player_video.first);
+ _state_timer.unset ();
_video_position = _player_video.second;
_inter_position = _player_video.first->inter_position ();
_inter_size = _player_video.first->inter_size ();
- refresh_panel ();
+ refresh_view ();
_closed_captions_dialog->update (time());
}
if (next >= _film->length()) {
stop ();
+ Finished ();
+ return;
}
+ LOG_DEBUG_PLAYER("%1 -> %2; delay %3", next.seconds(), time().seconds(), max((next.seconds() - time().seconds()) * 1000, 1.0));
_timer.Start (max ((next.seconds() - time().seconds()) * 1000, 1.0), wxTIMER_ONE_SHOT);
if (_butler) {
}
}
-void
-FilmViewer::paint_panel ()
-{
- wxPaintDC dc (_panel);
-
- if (!_frame || !_film || !_out_size.width || !_out_size.height || _out_size != _frame->size()) {
- dc.Clear ();
-#ifdef DCPOMATIC_VARIANT_SWAROOP
- optional<boost::filesystem::path> bg = Config::instance()->player_background_image();
- if (bg) {
- wxImage image (std_to_wx(bg->string()));
- wxBitmap bitmap (image);
- dc.DrawBitmap (bitmap, max(0, (_panel_size.width - image.GetSize().GetWidth()) / 2), max(0, (_panel_size.height - image.GetSize().GetHeight()) / 2));
- }
-#endif
- return;
- }
-
- wxImage frame (_out_size.width, _out_size.height, _frame->data()[0], true);
- wxBitmap frame_bitmap (frame);
- dc.DrawBitmap (frame_bitmap, 0, max(0, (_panel_size.height - _out_size.height) / 2));
-
+bool
#ifdef DCPOMATIC_VARIANT_SWAROOP
- DCPTime const period = DCPTime::from_seconds(Config::instance()->player_watermark_period() * 60);
- int64_t n = _video_position.get() / period.get();
- DCPTime from(n * period.get());
- DCPTime to = from + DCPTime::from_seconds(Config::instance()->player_watermark_duration() / 1000.0);
- if (from <= _video_position && _video_position <= to) {
- if (!_in_watermark) {
- _in_watermark = true;
- _watermark_x = rand() % _panel_size.width;
- _watermark_y = rand() % _panel_size.height;
- }
- dc.SetTextForeground(*wxWHITE);
- string wm = Config::instance()->player_watermark_theatre();
- boost::posix_time::ptime t = boost::posix_time::second_clock::local_time();
- wm += "\n" + boost::posix_time::to_iso_extended_string(t);
- dc.DrawText(std_to_wx(wm), _watermark_x, _watermark_y);
- } else {
- _in_watermark = false;
- }
-#endif
-
- if (_out_size.width < _panel_size.width) {
- /* XXX: these colours are right for GNOME; may need adjusting for other OS */
- wxPen p (wxColour (240, 240, 240));
- wxBrush b (wxColour (240, 240, 240));
- dc.SetPen (p);
- dc.SetBrush (b);
- dc.DrawRectangle (_out_size.width, 0, _panel_size.width - _out_size.width, _panel_size.height);
- }
-
- if (_out_size.height < _panel_size.height) {
- wxPen p (wxColour (240, 240, 240));
- wxBrush b (wxColour (240, 240, 240));
- dc.SetPen (p);
- dc.SetBrush (b);
- int const gap = (_panel_size.height - _out_size.height) / 2;
- dc.DrawRectangle (0, 0, _panel_size.width, gap);
- dc.DrawRectangle (0, gap + _out_size.height + 1, _panel_size.width, gap);
+XXX
+FilmViewer::maybe_draw_background_image (wxPaintDC& dc)
+{
+ optional<boost::filesystem::path> bg = Config::instance()->player_background_image();
+ if (bg) {
+ wxImage image (std_to_wx(bg->string()));
+ wxBitmap bitmap (image);
+ dc.DrawBitmap (bitmap, max(0, (_panel_size.width - image.GetSize().GetWidth()) / 2), max(0, (_panel_size.height - image.GetSize().GetHeight()) / 2));
+ return true;
}
- if (_outline_content) {
- wxPen p (wxColour (255, 0, 0), 2);
- dc.SetPen (p);
- dc.SetBrush (*wxTRANSPARENT_BRUSH);
- dc.DrawRectangle (_inter_position.x, _inter_position.y + (_panel_size.height - _out_size.height) / 2, _inter_size.width, _inter_size.height);
- }
+ return false;
}
+#else
+FilmViewer::maybe_draw_background_image (wxPaintDC &)
+{
+ return false;
+}
+#endif
void
FilmViewer::set_outline_content (bool o)
{
_outline_content = o;
- refresh_panel ();
+ refresh_view ();
}
void
}
void
-FilmViewer::panel_sized (wxSizeEvent& ev)
+FilmViewer::video_view_sized ()
{
- _panel_size.width = ev.GetSize().GetWidth();
- _panel_size.height = ev.GetSize().GetHeight();
-
calculate_sizes ();
if (!quick_refresh()) {
slow_refresh ();
Ratio const * container = _film->container ();
- float const panel_ratio = _panel_size.ratio ();
+ float const view_ratio = float(_video_view->get()->GetSize().x) / _video_view->get()->GetSize().y;
float const film_ratio = container ? container->ratio () : 1.78;
- if (panel_ratio < film_ratio) {
+ if (view_ratio < film_ratio) {
/* panel is less widscreen than the film; clamp width */
- _out_size.width = _panel_size.width;
+ _out_size.width = _video_view->get()->GetSize().x;
_out_size.height = lrintf (_out_size.width / film_ratio);
} else {
/* panel is more widescreen than the film; clamp height */
- _out_size.height = _panel_size.height;
+ _out_size.height = _video_view->get()->GetSize().y;
_out_size.width = lrintf (_out_size.height * film_ratio);
}
return false;
}
- if (!_player_video.first->reset_metadata (_player->video_container_size(), _film->frame_size())) {
+ if (!_player_video.first->reset_metadata (_film, _player->video_container_size(), _film->frame_size())) {
return false;
}
}
PositionChanged ();
- Seeked (position());
}
void
{
#ifdef DCPOMATIC_VARIANT_SWAROOP
if (p == Config::PLAYER_BACKGROUND_IMAGE) {
- refresh_panel ();
+ refresh_view ();
return;
}
#endif
} catch (RtAudioError& e) {
#endif
error_dialog (
- _panel,
+ _video_view->get(),
_("Could not set up audio output. There will be no audio during the preview."), std_to_wx(e.what())
);
}
{
seek (_video_position + by, accurate);
}
+
+void
+FilmViewer::set_pad_black (bool p)
+{
+ _pad_black = p;
+}