Player::Player (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist)
: _film (film)
, _playlist (playlist)
- , _have_valid_pieces (false)
+ , _suspended (false)
, _ignore_video (false)
, _ignore_audio (false)
, _ignore_text (false)
{
_film_changed_connection = _film->Changed.connect (bind (&Player::film_changed, this, _1));
_playlist_changed_connection = _playlist->Changed.connect (bind (&Player::playlist_changed, this));
- _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Player::playlist_content_changed, this, _1, _2, _3));
+ _playlist_content_may_change_connection = _playlist->ContentMayChange.connect (bind(&Player::playlist_content_may_change, this));
+ _playlist_content_changed_connection = _playlist->ContentChanged.connect (bind(&Player::playlist_content_changed, this, _1, _2, _3));
+ _playlist_content_not_changed_connection = _playlist->ContentNotChanged.connect (bind(&Player::playlist_content_not_changed, this));
set_video_container_size (_film->frame_size ());
film_changed (Film::AUDIO_PROCESSOR);
+ setup_pieces ();
seek (DCPTime (), true);
}
void
Player::setup_pieces ()
+{
+ boost::mutex::scoped_lock lm (_mutex);
+ setup_pieces_unlocked ();
+}
+
+void
+Player::setup_pieces_unlocked ()
{
_pieces.clear ();
_last_video_time = DCPTime ();
_last_video_eyes = EYES_BOTH;
_last_audio_time = DCPTime ();
- _have_valid_pieces = true;
+ _suspended = false;
+}
+
+void
+Player::playlist_content_may_change ()
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ /* The player content is probably about to change, so we can't carry on
+ until that has happened and we've rebuilt our pieces. Stop pass()
+ and seek() from working until then.
+ */
+ _suspended = true;
+ }
+
+ MayChange ();
}
void
Player::playlist_content_changed (weak_ptr<Content> w, int property, bool frequent)
{
+ /* A change in our content has gone through. Re-build our pieces and signal
+ it to anybody that is interested.
+ */
+
shared_ptr<Content> c = w.lock ();
if (!c) {
return;
}
+ setup_pieces ();
+
if (
property == ContentProperty::POSITION ||
property == ContentProperty::LENGTH ||
property == AudioContentProperty::STREAMS ||
property == DCPContentProperty::NEEDS_ASSETS ||
property == DCPContentProperty::NEEDS_KDM ||
+ property == DCPContentProperty::CPL ||
property == TextContentProperty::COLOUR ||
property == TextContentProperty::EFFECT ||
property == TextContentProperty::EFFECT_COLOUR ||
property == FFmpegContentProperty::SUBTITLE_STREAM ||
- property == FFmpegContentProperty::FILTERS
- ) {
-
- {
- boost::mutex::scoped_lock lm (_mutex);
- _have_valid_pieces = false;
- }
-
- Changed (property, frequent);
-
- } else if (
+ property == FFmpegContentProperty::FILTERS ||
property == TextContentProperty::LINE_SPACING ||
property == TextContentProperty::OUTLINE_WIDTH ||
property == TextContentProperty::Y_SCALE ||
}
}
+void
+Player::playlist_content_not_changed ()
+{
+ /* A possible content change did end up happening for some reason */
+ NotChanged ();
+}
+
void
Player::set_video_container_size (dcp::Size s)
{
void
Player::playlist_changed ()
{
- {
- boost::mutex::scoped_lock lm (_mutex);
- _have_valid_pieces = false;
- }
-
+ setup_pieces ();
Changed (PlayerProperty::PLAYLIST, false);
}
/* Pieces contain a FrameRateChange which contains the DCP frame rate,
so we need new pieces here.
*/
- {
- boost::mutex::scoped_lock lm (_mutex);
- _have_valid_pieces = false;
- }
+ setup_pieces ();
Changed (PlayerProperty::FILM_VIDEO_FRAME_RATE, false);
} else if (p == Film::AUDIO_PROCESSOR) {
if (_film->audio_processor ()) {
list<shared_ptr<Font> >
Player::get_subtitle_fonts ()
{
- /* Does not require a lock on _mutex as it's only called from DCPEncoder */
-
- if (!_have_valid_pieces) {
- setup_pieces ();
- }
+ boost::mutex::scoped_lock lm (_mutex);
list<shared_ptr<Font> > fonts;
BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
{
boost::mutex::scoped_lock lm (_mutex);
_ignore_video = true;
- _have_valid_pieces = false;
+ setup_pieces_unlocked ();
}
void
{
boost::mutex::scoped_lock lm (_mutex);
_ignore_audio = true;
- _have_valid_pieces = false;
+ setup_pieces_unlocked ();
}
void
{
boost::mutex::scoped_lock lm (_mutex);
_ignore_text = true;
+ setup_pieces_unlocked ();
}
/** Set the player to always burn open texts into the image regardless of the content settings */
{
boost::mutex::scoped_lock lm (_mutex);
_fast = true;
- _have_valid_pieces = false;
+ setup_pieces_unlocked ();
}
void
{
boost::mutex::scoped_lock lm (_mutex);
_play_referenced = true;
- _have_valid_pieces = false;
+ setup_pieces_unlocked ();
}
list<ReferencedReelAsset>
{
boost::mutex::scoped_lock lm (_mutex);
- if (!_have_valid_pieces) {
- setup_pieces ();
+ if (_suspended) {
+ /* We can't pass in this state */
+ return false;
}
if (_playlist->length() == DCPTime()) {
return done;
}
-list<PlayerText>
-Player::closed_captions_for_frame (DCPTime time) const
-{
- boost::mutex::scoped_lock _lm (_mutex);
- return _active_texts[TEXT_CLOSED_CAPTION].get (
- DCPTimePeriod(time, time + DCPTime::from_frames(1, _film->video_frame_rate()))
- );
-}
-
/** @return Open subtitles for the frame at the given time, converted to images */
optional<PositionImage>
Player::open_subtitles_for_frame (DCPTime time) const
DCPTime fill_from = max (*_last_video_time, piece->content->position());
LastVideoMap::const_iterator last = _last_video.find (wp);
if (_film->three_d()) {
+ Eyes fill_to_eyes = video.eyes;
+ if (fill_to == piece->content->end()) {
+ /* Don't fill after the end of the content */
+ fill_to_eyes = EYES_LEFT;
+ }
DCPTime j = fill_from;
Eyes eyes = _last_video_eyes.get_value_or(EYES_LEFT);
if (eyes == EYES_BOTH) {
eyes = EYES_LEFT;
}
- while (j < fill_to || eyes != video.eyes) {
+ while (j < fill_to || eyes != fill_to_eyes) {
if (last != _last_video.end()) {
shared_ptr<PlayerVideo> copy = last->second->shallow_copy();
copy->set_eyes (eyes);
{
boost::mutex::scoped_lock lm (_mutex);
- if (!_have_valid_pieces) {
- setup_pieces ();
+ if (_suspended) {
+ /* We can't seek in this state */
+ return;
}
if (_shuffler) {
}
_dcp_decode_reduction = reduction;
- _have_valid_pieces = false;
+ setup_pieces_unlocked ();
}
Changed (PlayerProperty::DCP_DECODE_REDUCTION, false);
}
-DCPTime
+optional<DCPTime>
Player::content_time_to_dcp (shared_ptr<Content> content, ContentTime t)
{
boost::mutex::scoped_lock lm (_mutex);
- if (_have_valid_pieces) {
- setup_pieces ();
- }
-
BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
if (i->content == content) {
return content_time_to_dcp (i, t);
}
}
- DCPOMATIC_ASSERT (false);
- return DCPTime ();
+ /* We couldn't find this content; perhaps things are being changed over */
+ return optional<DCPTime>();
}