#include "playhead_to_timecode_dialog.h"
#include "simple_video_view.h"
#include "wx_util.h"
-#include "lib/film.h"
-#include "lib/ratio.h"
-#include "lib/util.h"
-#include "lib/job_manager.h"
-#include "lib/image.h"
-#include "lib/exceptions.h"
+#include "lib/butler.h"
+#include "lib/compose.hpp"
+#include "lib/config.h"
+#include "lib/dcpomatic_log.h"
#include "lib/examine_content_job.h"
+#include "lib/exceptions.h"
+#include "lib/film.h"
#include "lib/filter.h"
+#include "lib/image.h"
+#include "lib/job_manager.h"
+#include "lib/log.h"
#include "lib/player.h"
#include "lib/player_video.h"
+#include "lib/ratio.h"
+#include "lib/text_content.h"
+#include "lib/timer.h"
+#include "lib/util.h"
#include "lib/video_content.h"
#include "lib/video_decoder.h"
-#include "lib/timer.h"
-#include "lib/butler.h"
-#include "lib/log.h"
-#include "lib/config.h"
-#include "lib/compose.hpp"
-#include "lib/dcpomatic_log.h"
-#include "lib/text_content.h"
+#include <dcp/exceptions.h>
+#include <dcp/warnings.h>
extern "C" {
#include <libavutil/pixfmt.h>
}
-#include <dcp/exceptions.h>
+LIBDCP_DISABLE_WARNINGS
#include <wx/tglbtn.h>
-#include <iostream>
+LIBDCP_ENABLE_WARNINGS
#include <iomanip>
using std::bad_alloc;
-using std::cout;
using std::dynamic_pointer_cast;
-using std::exception;
-using std::list;
-using std::make_pair;
using std::make_shared;
using std::max;
-using std::min;
-using std::pair;
using std::shared_ptr;
using std::string;
using std::vector;
-using std::weak_ptr;
using boost::optional;
#if BOOST_VERSION >= 106100
using namespace boost::placeholders;
: _audio (DCPOMATIC_RTAUDIO_API)
, _closed_captions_dialog (new ClosedCaptionsDialog(p, this))
{
+#if wxCHECK_VERSION(3, 1, 0)
switch (Config::instance()->video_view_type()) {
case Config::VIDEO_VIEW_OPENGL:
_video_view = std::make_shared<GLVideoView>(this, p);
_video_view = std::make_shared<SimpleVideoView>(this, p);
break;
}
+#else
+ _video_view = std::make_shared<SimpleVideoView>(this, p);
+#endif
_video_view->Sized.connect (boost::bind(&FilmViewer::video_view_sized, this));
_video_view->TooManyDropped.connect (boost::bind(boost::ref(TooManyDropped)));
}
-/** Ask for ::get() to be called next time we are idle */
+/** Ask for ::idle_handler() to be called next time we are idle */
void
FilmViewer::request_idle_display_next_frame ()
{
}
try {
- _player = make_shared<Player>(_film);
+ _player = make_shared<Player>(_film, _optimise_for_j2k ? Image::Alignment::COMPACT : Image::Alignment::PADDED);
_player->set_fast ();
if (_dcp_decode_reduction) {
_player->set_dcp_decode_reduction (_dcp_decode_reduction);
return;
}
+#if wxCHECK_VERSION(3, 1, 0)
+ auto const j2k_gl_optimised = dynamic_pointer_cast<GLVideoView>(_video_view) && _optimise_for_j2k;
+#else
+ auto const j2k_gl_optimised = false;
+#endif
+
_butler = std::make_shared<Butler>(
_film,
_player,
Config::instance()->audio_mapping(_audio_channels),
_audio_channels,
- bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24),
+ boost::bind(&PlayerVideo::force, AV_PIX_FMT_RGB24),
VideoRange::FULL,
- false,
- true
+ j2k_gl_optimised ? Image::Alignment::COMPACT : Image::Alignment::PADDED,
+ true,
+ j2k_gl_optimised,
+ (Config::instance()->sound() && _audio.isStreamOpen()) ? Butler::Audio::ENABLED : Butler::Audio::DISABLED
);
- if (!Config::instance()->sound() && !_audio.isStreamOpen()) {
- _butler->disable_audio ();
- }
-
_closed_captions_dialog->set_butler (_butler);
resume ();
auto const container = _film->container ();
- auto const view_ratio = float(_video_view->get()->GetSize().x) / _video_view->get()->GetSize().y;
+ auto const scale = dpi_scale_factor (_video_view->get());
+ int const video_view_width = std::round(_video_view->get()->GetSize().x * scale);
+ int const video_view_height = std::round(_video_view->get()->GetSize().y * scale);
+
+ auto const view_ratio = float(video_view_width) / video_view_height;
auto const film_ratio = container ? container->ratio () : 1.78;
dcp::Size out_size;
if (view_ratio < film_ratio) {
/* panel is less widscreen than the film; clamp width */
- out_size.width = _video_view->get()->GetSize().x;
+ out_size.width = video_view_width;
out_size.height = lrintf (out_size.width / film_ratio);
} else {
/* panel is more widescreen than the film; clamp height */
- out_size.height = _video_view->get()->GetSize().y;
+ out_size.height = video_view_height;
out_size.width = lrintf (out_size.height * film_ratio);
}
out_size.width = max (64, out_size.width);
out_size.height = max (64, out_size.height);
+ /* Make sure the video container sizes are always a multiple of 2 so that
+ * we don't get gaps with subsampled sources (e.g. YUV420)
+ */
+ if (out_size.width % 2) {
+ out_size.width++;
+ }
+ if (out_size.height % 2) {
+ out_size.height++;
+ }
+
_player->set_video_container_size (out_size);
}
}
+void
+FilmViewer::start_audio_stream_if_open ()
+{
+ if (_audio.isStreamOpen()) {
+ _audio.setStreamTime (_video_view->position().seconds());
+ try {
+ _audio.startStream ();
+ } catch (RtAudioError& e) {
+ _audio_channels = 0;
+ error_dialog (
+ _video_view->get(),
+ _("There was a problem starting audio playback. Please try another audio output device in Preferences."), std_to_wx(e.what())
+ );
+ }
+ }
+}
+
+
void
FilmViewer::resume ()
{
DCPOMATIC_ASSERT (_suspended > 0);
--_suspended;
if (_playing && !_suspended) {
- if (_audio.isStreamOpen()) {
- _audio.setStreamTime (_video_view->position().seconds());
- _audio.startStream ();
- }
+ start_audio_stream_if_open ();
_video_view->start ();
}
}
/* Take the video view's idea of position as our `playhead' and start the
audio stream (which is the timing reference) there.
*/
- if (_audio.isStreamOpen()) {
- _audio.setStreamTime (_video_view->position().seconds());
- try {
- _audio.startStream ();
- } catch (RtAudioError& e) {
- _audio_channels = 0;
- error_dialog (
- _video_view->get(),
- _("There was a problem starting audio playback. Please try another audio output device in Preferences."), std_to_wx(e.what())
- );
- }
- }
+ start_audio_stream_if_open ();
_playing = true;
/* Calling start() below may directly result in Stopped being emitted, and if that
* happens we want it to come after the Started signal, so do that first.
*/
- Started (position());
+ Started ();
_video_view->start ();
}
_playing = false;
_video_view->stop ();
- Stopped (position());
+ Stopped ();
_video_view->rethrow ();
return true;
FilmViewer::audio_callback (void* out_p, unsigned int frames)
{
while (true) {
- auto t = _butler->get_audio (reinterpret_cast<float*> (out_p), frames);
+ auto t = _butler->get_audio (Butler::Behaviour::NON_BLOCKING, reinterpret_cast<float*> (out_p), frames);
if (!t || DCPTime(uncorrected_time() - *t) < one_video_frame()) {
/* There was an underrun or this audio is on time; carry on */
break;
}
+optional<ContentTime>
+FilmViewer::position_in_content (shared_ptr<const Content> content) const
+{
+ return _player->dcp_to_content_time (content, position());
+}
+
+
DCPTime
FilmViewer::one_video_frame () const
{
{
emit (boost::bind(boost::ref(ImageChanged), pv));
}
+
+
+void
+FilmViewer::set_optimise_for_j2k (bool o)
+{
+ _optimise_for_j2k = o;
+ _video_view->set_optimise_for_j2k (o);
+}
+
+
+void
+FilmViewer::set_crop_guess (dcpomatic::Rect<float> crop)
+{
+ if (crop != _crop_guess) {
+ _crop_guess = crop;
+ _video_view->update ();
+ }
+}
+
+
+void
+FilmViewer::unset_crop_guess ()
+{
+ _crop_guess = boost::none;
+ _video_view->update ();
+}
+