updated metadata (where possible). Helps with #1194.
using boost::optional;
using boost::scoped_ptr;
+int const PlayerProperty::VIDEO_CONTAINER_SIZE = 700;
+int const PlayerProperty::PLAYLIST = 701;
+int const PlayerProperty::FILM_CONTAINER = 702;
+int const PlayerProperty::FILM_VIDEO_FRAME_RATE = 703;
+int const PlayerProperty::DCP_DECODE_REDUCTION = 704;
+
Player::Player (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist)
: _film (film)
, _playlist (playlist)
) {
_have_valid_pieces = false;
- Changed (frequent);
+ Changed (property, frequent);
} else if (
property == SubtitleContentProperty::LINE_SPACING ||
property == VideoContentProperty::FADE_OUT
) {
- Changed (frequent);
+ Changed (property, frequent);
}
}
_black_image.reset (new Image (AV_PIX_FMT_RGB24, _video_container_size, true));
_black_image->make_black ();
- Changed (false);
+ Changed (PlayerProperty::VIDEO_CONTAINER_SIZE, false);
}
void
Player::playlist_changed ()
{
_have_valid_pieces = false;
- Changed (false);
+ Changed (PlayerProperty::PLAYLIST, false);
}
void
*/
if (p == Film::CONTAINER) {
- Changed (false);
+ Changed (PlayerProperty::FILM_CONTAINER, false);
} else if (p == Film::VIDEO_FRAME_RATE) {
/* Pieces contain a FrameRateChange which contains the DCP frame rate,
so we need new pieces here.
*/
_have_valid_pieces = false;
- Changed (false);
+ Changed (PlayerProperty::FILM_VIDEO_FRAME_RATE, false);
} else if (p == Film::AUDIO_PROCESSOR) {
if (_film->audio_processor ()) {
_audio_processor = _film->audio_processor()->clone (_film->audio_frame_rate ());
_video_container_size,
eyes,
PART_WHOLE,
- PresetColourConversion::all().front().conversion
+ PresetColourConversion::all().front().conversion,
+ boost::weak_ptr<Content>(),
+ boost::optional<Frame>()
)
);
}
_video_container_size,
video.eyes,
video.part,
- piece->content->video->colour_conversion ()
+ piece->content->video->colour_conversion(),
+ piece->content,
+ video.frame
)
);
_dcp_decode_reduction = reduction;
_have_valid_pieces = false;
- Changed (false);
+ Changed (PlayerProperty::DCP_DECODE_REDUCTION, false);
}
class ReferencedReelAsset;
class Shuffler;
+class PlayerProperty
+{
+public:
+ static int const VIDEO_CONTAINER_SIZE;
+ static int const PLAYLIST;
+ static int const FILM_CONTAINER;
+ static int const FILM_VIDEO_FRAME_RATE;
+ static int const DCP_DECODE_REDUCTION;
+};
+
/** @class Player
* @brief A class which can `play' a Playlist.
*/
std::list<boost::shared_ptr<Font> > get_subtitle_fonts ();
std::list<ReferencedReelAsset> get_reel_assets ();
+ dcp::Size video_container_size () const {
+ return _video_container_size;
+ }
void set_video_container_size (dcp::Size);
void set_ignore_video ();
* the last frame again it would look different. This is not emitted after
* a seek.
*
- * The parameter is true if these signals are currently likely to be frequent.
+ * The first parameter is what changed.
+ * The second parameter is true if these signals are currently likely to be frequent.
*/
- boost::signals2::signal<void (bool)> Changed;
+ boost::signals2::signal<void (int, bool)> Changed;
/** Emitted when a video frame is ready. These emissions happen in the correct order. */
boost::signals2::signal<void (boost::shared_ptr<PlayerVideo>, DCPTime)> Video;
/*
- Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
#include "player_video.h"
+#include "content.h"
+#include "video_content.h"
#include "image.h"
#include "image_proxy.h"
#include "j2k_image_proxy.h"
using std::string;
using std::cout;
using boost::shared_ptr;
+using boost::weak_ptr;
using boost::dynamic_pointer_cast;
using boost::optional;
using boost::function;
dcp::Size out_size,
Eyes eyes,
Part part,
- optional<ColourConversion> colour_conversion
+ optional<ColourConversion> colour_conversion,
+ weak_ptr<Content> content,
+ optional<Frame> video_frame
)
: _in (in)
, _crop (crop)
, _eyes (eyes)
, _part (part)
, _colour_conversion (colour_conversion)
+ , _content (content)
+ , _video_frame (video_frame)
{
}
_out_size,
_eyes,
_part,
- _colour_conversion
+ _colour_conversion,
+ _content,
+ _video_frame
)
);
}
+
+/** Re-read crop, fade, inter/out size and colour conversion from our content */
+void
+PlayerVideo::reset_metadata (dcp::Size video_container_size, dcp::Size film_frame_size)
+{
+ shared_ptr<Content> content = _content.lock();
+ DCPOMATIC_ASSERT (content);
+ DCPOMATIC_ASSERT (_video_frame);
+
+ _crop = content->video->crop();
+ _fade = content->video->fade(_video_frame.get());
+ _inter_size = content->video->scale().size(content->video, video_container_size, film_frame_size);
+ _out_size = video_container_size;
+ _colour_conversion = content->video->colour_conversion();
+}
#include <libavutil/pixfmt.h>
}
#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
class Image;
class ImageProxy;
dcp::Size,
Eyes,
Part,
- boost::optional<ColourConversion>
+ boost::optional<ColourConversion>,
+ boost::weak_ptr<Content>,
+ boost::optional<Frame>
);
PlayerVideo (boost::shared_ptr<cxml::Node>, boost::shared_ptr<Socket>);
void add_metadata (xmlpp::Node* node) const;
void send_binary (boost::shared_ptr<Socket> socket) const;
+ void reset_metadata (dcp::Size video_container_size, dcp::Size film_frame_size);
+
bool has_j2k () const;
dcp::Data j2k () const;
Part _part;
boost::optional<ColourConversion> _colour_conversion;
boost::optional<PositionImage> _subtitle;
+ /** Content that we came from. This is so that reset_metadata() can work */
+ boost::weak_ptr<Content> _content;
+ /** Video frame that we came from. Again, this is for reset_metadata() */
+ boost::optional<Frame> _video_frame;
};
#endif
, _timecode (new wxStaticText (this, wxID_ANY, wxT("")))
, _play_button (new wxToggleButton (this, wxID_ANY, _("Play")))
, _coalesce_player_changes (false)
- , _pending_player_change (false)
, _slider_being_moved (false)
, _was_running_before_slider (false)
, _audio (DCPOMATIC_RTAUDIO_API)
if (_outline_content) {
_outline_content->Bind (wxEVT_CHECKBOX, boost::bind (&FilmViewer::refresh_panel, this));
}
- _left_eye->Bind (wxEVT_RADIOBUTTON, boost::bind (&FilmViewer::refresh, this));
- _right_eye->Bind (wxEVT_RADIOBUTTON, boost::bind (&FilmViewer::refresh, this));
+ _left_eye->Bind (wxEVT_RADIOBUTTON, boost::bind (&FilmViewer::slow_refresh, this));
+ _right_eye->Bind (wxEVT_RADIOBUTTON, boost::bind (&FilmViewer::slow_refresh, this));
_slider->Bind (wxEVT_SCROLL_THUMBTRACK, boost::bind (&FilmViewer::slider_moved, this, false));
_slider->Bind (wxEVT_SCROLL_PAGEUP, boost::bind (&FilmViewer::slider_moved, this, true));
_slider->Bind (wxEVT_SCROLL_PAGEDOWN, boost::bind (&FilmViewer::slider_moved, this, true));
_player->set_play_referenced ();
_film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1));
- _player->Changed.connect (boost::bind (&FilmViewer::player_changed, this, _1));
+ _player->Changed.connect (boost::bind (&FilmViewer::player_changed, this, _1, _2));
/* Keep about 1 second's worth of history samples */
_latency_history_count = _film->audio_frame_rate() / _audio_block_size;
recreate_butler ();
calculate_sizes ();
- refresh ();
+ slow_refresh ();
setup_sensitivity ();
}
{
DCPOMATIC_ASSERT (_butler);
- pair<shared_ptr<PlayerVideo>, DCPTime> video;
do {
- video = _butler->get_video ();
+ _player_video = _butler->get_video ();
} while (
_film->three_d() &&
- ((_left_eye->GetValue() && video.first->eyes() == EYES_RIGHT) || (_right_eye->GetValue() && video.first->eyes() == EYES_LEFT))
+ ((_left_eye->GetValue() && _player_video.first->eyes() == EYES_RIGHT) || (_right_eye->GetValue() && _player_video.first->eyes() == EYES_LEFT))
);
_butler->rethrow ();
- if (!video.first) {
+ display_player_video ();
+}
+
+void
+FilmViewer::display_player_video ()
+{
+ if (!_player_video.first) {
_frame.reset ();
refresh_panel ();
return;
}
- if (_playing && (time() - video.second) > one_video_frame()) {
+ if (_playing && (time() - _player_video.second) > one_video_frame()) {
/* Too late; just drop this frame before we try to get its image (which will be the time-consuming
part if this frame is J2K).
*/
- _video_position = video.second;
+ _video_position = _player_video.second;
++_dropped;
return;
}
* image and convert it (from whatever the user has said it is) to RGB.
*/
- _frame = video.first->image (
+ _frame = _player_video.first->image (
bind (&Log::dcp_log, _film->log().get(), _1, _2),
bind (&PlayerVideo::always_rgb, _1),
false, true
);
- ImageChanged (video.first);
+ ImageChanged (_player_video.first);
- _video_position = video.second;
- _inter_position = video.first->inter_position ();
- _inter_size = video.first->inter_size ();
+ _video_position = _player_video.second;
+ _inter_position = _player_video.first->inter_position ();
+ _inter_size = _player_video.first->inter_size ();
refresh_panel ();
}
_panel_size.height = ev.GetSize().GetHeight();
calculate_sizes ();
- refresh ();
+ quick_refresh ();
update_position_label ();
update_position_slider ();
}
}
void
-FilmViewer::player_changed (bool frequent)
+FilmViewer::player_changed (int property, bool frequent)
{
if (frequent) {
return;
}
if (_coalesce_player_changes) {
- _pending_player_change = true;
+ _pending_player_changes.push_back (property);
return;
}
calculate_sizes ();
- refresh ();
+ if (
+ property == VideoContentProperty::CROP ||
+ property == VideoContentProperty::SCALE ||
+ property == VideoContentProperty::FADE_IN ||
+ property == VideoContentProperty::FADE_OUT ||
+ property == VideoContentProperty::COLOUR_CONVERSION ||
+ property == PlayerProperty::VIDEO_CONTAINER_SIZE ||
+ property == PlayerProperty::FILM_CONTAINER
+ ) {
+ quick_refresh ();
+ } else {
+ slow_refresh ();
+ }
update_position_label ();
update_position_slider ();
}
}
}
-/** Re-get the current frame */
+/** Re-get the current frame slowly by seeking */
void
-FilmViewer::refresh ()
+FilmViewer::slow_refresh ()
{
seek (_video_position, true);
}
+/** Re-get the current frame quickly by resetting the metadata in the PlayerVideo that we used last time */
+void
+FilmViewer::quick_refresh ()
+{
+ if (!_player_video.first) {
+ return;
+ }
+
+ _player_video.first->reset_metadata (_player->video_container_size(), _film->frame_size());
+ display_player_video ();
+}
+
void
FilmViewer::set_position (DCPTime p)
{
{
_coalesce_player_changes = c;
- if (c) {
- _pending_player_change = false;
- } else {
- if (_pending_player_change) {
- player_changed (false);
+ if (!c) {
+ BOOST_FOREACH (int i, _pending_player_changes) {
+ player_changed (i, false);
}
+ _pending_player_changes.clear ();
}
}
void set_dcp_decode_reduction (boost::optional<int> reduction);
boost::optional<int> dcp_decode_reduction () const;
- void refresh ();
+ void slow_refresh ();
+ void quick_refresh ();
int dropped () const {
return _dropped;
void rewind_clicked (wxMouseEvent &);
void back_clicked (wxMouseEvent &);
void forward_clicked (wxMouseEvent &);
- void player_changed (bool);
+ void player_changed (int, bool);
void update_position_label ();
void update_position_slider ();
void get ();
+ void display_player_video ();
void seek (DCPTime t, bool accurate);
void refresh_panel ();
void setup_sensitivity ();
wxToggleButton* _play_button;
wxTimer _timer;
bool _coalesce_player_changes;
- bool _pending_player_change;
+ std::list<int> _pending_player_changes;
bool _slider_being_moved;
bool _was_running_before_slider;
+ std::pair<boost::shared_ptr<PlayerVideo>, DCPTime> _player_video;
boost::shared_ptr<const Image> _frame;
DCPTime _video_position;
Position<int> _inter_position;
{
_plot->set_enabled (ev.IsShown ());
if (ev.IsShown ()) {
- _viewer->refresh ();
+ _viewer->slow_refresh ();
}
}
using boost::shared_ptr;
using boost::thread;
using boost::optional;
+using boost::weak_ptr;
using dcp::Data;
void
dcp::Size (1998, 1080),
EYES_BOTH,
PART_WHOLE,
- ColourConversion ()
+ ColourConversion(),
+ weak_ptr<Content>(),
+ optional<Frame>()
)
);
dcp::Size (1998, 1080),
EYES_BOTH,
PART_WHOLE,
- ColourConversion ()
+ ColourConversion(),
+ weak_ptr<Content>(),
+ optional<Frame>()
)
);
dcp::Size (1998, 1080),
EYES_BOTH,
PART_WHOLE,
- ColourConversion ()
+ ColourConversion(),
+ weak_ptr<Content>(),
+ optional<Frame>()
)
);
dcp::Size (1998, 1080),
EYES_BOTH,
PART_WHOLE,
- PresetColourConversion::all().front().conversion
+ PresetColourConversion::all().front().conversion,
+ weak_ptr<Content>(),
+ optional<Frame>()
)
);