diff options
| -rw-r--r-- | src/lib/analyse_audio_job.cc | 7 | ||||
| -rw-r--r-- | src/lib/change_signaller.cc | 10 | ||||
| -rw-r--r-- | src/lib/change_signaller.h | 24 | ||||
| -rw-r--r-- | src/lib/content.cc | 6 | ||||
| -rw-r--r-- | src/lib/content.h | 4 | ||||
| -rw-r--r-- | src/lib/dcp_film_encoder.cc | 2 | ||||
| -rw-r--r-- | src/lib/film.cc | 35 | ||||
| -rw-r--r-- | src/lib/film.h | 12 | ||||
| -rw-r--r-- | src/lib/fix_audio_levels_job.cc | 41 | ||||
| -rw-r--r-- | src/lib/j2k_encoder.cc | 2 | ||||
| -rw-r--r-- | src/lib/player.cc | 105 | ||||
| -rw-r--r-- | src/lib/player.h | 15 | ||||
| -rw-r--r-- | src/lib/playlist.cc | 38 | ||||
| -rw-r--r-- | src/lib/playlist.h | 6 | ||||
| -rw-r--r-- | src/lib/signal_manager.h | 2 | ||||
| -rw-r--r-- | src/lib/video_content.cc | 2 | ||||
| -rw-r--r-- | src/tools/dcpomatic_processor.cc | 72 |
17 files changed, 283 insertions, 100 deletions
diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index cd6a2bbd6..9a7bc05f1 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -87,6 +87,7 @@ AnalyseAudioJob::run() { LOG_DEBUG_AUDIO_ANALYSIS_NC("AnalyseAudioJob::run"); + std::cout << "-------make the player-------\n"; auto player = make_shared<Player>(_film, _playlist, false); player->set_ignore_video(); player->set_ignore_text(); @@ -97,6 +98,8 @@ AnalyseAudioJob::run() player->set_disable_audio_processor(); } + std::cout << "[A]\n"; + bool has_any_audio = false; for (auto c: _playlist->content()) { if (c->audio) { @@ -104,11 +107,15 @@ AnalyseAudioJob::run() } } + std::cout << "[B]\n"; + if (has_any_audio) { player->seek(_analyser.start(), true); while (!player->pass()) {} } + std::cout << "[C]\n"; + LOG_DEBUG_AUDIO_ANALYSIS_NC("Loop complete"); _analyser.finish(); diff --git a/src/lib/change_signaller.cc b/src/lib/change_signaller.cc index a1f093d14..b00fb4960 100644 --- a/src/lib/change_signaller.cc +++ b/src/lib/change_signaller.cc @@ -22,3 +22,13 @@ #include "change_signaller.h" +boost::atomic<int> ChangeID::_next; + + +int +ChangeID::next() +{ + return _next.add(1, boost::memory_order::relaxed); +} + + diff --git a/src/lib/change_signaller.h b/src/lib/change_signaller.h index 094716598..d3e3958d4 100644 --- a/src/lib/change_signaller.h +++ b/src/lib/change_signaller.h @@ -27,6 +27,16 @@ #include <vector> +class ChangeID +{ +public: + static int next(); + +private: + static boost::atomic<int> _next; +}; + + enum class ChangeType { PENDING, @@ -39,15 +49,17 @@ template <class T, class P> class ChangeSignal { public: - ChangeSignal(T* thing_, P property_, ChangeType type_) + ChangeSignal(T* thing_, P property_, ChangeType type_, int id_) : thing(thing_) , property(property_) , type(type_) + , id(id_) {} T* thing; P property; ChangeType type; + int id; }; @@ -80,7 +92,7 @@ public: _pending.push_back(signal); } } else { - signal.thing->signal_change(signal.type, signal.property); + signal.thing->signal_change(signal.type, signal.property, signal.id); } } @@ -99,7 +111,7 @@ public: lm.unlock(); for (auto signal: pending) { - signal.thing->signal_change(signal.type, signal.property); + signal.thing->signal_change(signal.type, signal.property, signal.id); } } @@ -129,13 +141,14 @@ public: : _thing(t) , _property(p) , _done(true) + , _id(ChangeID::next()) { - ChangeSignalDespatcher<T, P>::instance()->signal_change({_thing, _property, ChangeType::PENDING}); + ChangeSignalDespatcher<T, P>::instance()->signal_change({_thing, _property, ChangeType::PENDING, _id}); } ~ChangeSignaller () { - ChangeSignalDespatcher<T, P>::instance()->signal_change({_thing, _property, _done ? ChangeType::DONE : ChangeType::CANCELLED}); + ChangeSignalDespatcher<T, P>::instance()->signal_change({_thing, _property, _done ? ChangeType::DONE : ChangeType::CANCELLED, _id}); } void abort () @@ -147,6 +160,7 @@ private: T* _thing; P _property; bool _done; + int _id; }; diff --git a/src/lib/content.cc b/src/lib/content.cc index ac87c6e79..583a89cde 100644 --- a/src/lib/content.cc +++ b/src/lib/content.cc @@ -188,13 +188,13 @@ Content::examine(shared_ptr<const Film>, shared_ptr<Job> job, bool) void -Content::signal_change(ChangeType c, int p) +Content::signal_change(ChangeType c, int p, int id) { try { if (c == ChangeType::PENDING || c == ChangeType::CANCELLED) { - Change(c, p, _change_signals_frequent); + Change(c, p, _change_signals_frequent, id); } else { - emit(boost::bind(boost::ref(Change), c, p, _change_signals_frequent)); + emit(boost::bind(boost::ref(Change), c, p, _change_signals_frequent, id)); } } catch (std::bad_weak_ptr &) { /* This must be during construction; never mind */ diff --git a/src/lib/content.h b/src/lib/content.h index d84505b72..0314d2c13 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -219,7 +219,7 @@ public: bool has_mapped_audio() const; /* ChangeType::PENDING and ChangeType::CANCELLED may be emitted from any thread; ChangeType::DONE always from GUI thread */ - boost::signals2::signal<void (ChangeType, int, bool)> Change; + boost::signals2::signal<void (ChangeType, int, bool, int)> Change; std::shared_ptr<VideoContent> video; std::shared_ptr<AudioContent> audio; @@ -251,7 +251,7 @@ private: friend struct subtitle_font_id_change_test2; template<class, class> friend class ChangeSignalDespatcher; - void signal_change(ChangeType, int); + void signal_change(ChangeType, int, int id); /** Paths of our data files */ std::vector<boost::filesystem::path> _paths; diff --git a/src/lib/dcp_film_encoder.cc b/src/lib/dcp_film_encoder.cc index 63540c360..56eadcad4 100644 --- a/src/lib/dcp_film_encoder.cc +++ b/src/lib/dcp_film_encoder.cc @@ -84,6 +84,7 @@ DCPFilmEncoder::DCPFilmEncoder(shared_ptr<const Film> film, weak_ptr<Job> job, b /* Now that we have a Writer we can clear out the assets directory */ clean_up_asset_directory(film->assets_path()); + std::cout << "Connect " << this << " to " << &_player << "\n"; _player_video_connection = _player.Video.connect(bind(&DCPFilmEncoder::video, this, _1, _2)); _player_audio_connection = _player.Audio.connect(bind(&DCPFilmEncoder::audio, this, _1, _2)); _player_text_connection = _player.Text.connect(bind(&DCPFilmEncoder::text, this, _1, _2, _3, _4)); @@ -158,6 +159,7 @@ DCPFilmEncoder::resume() void DCPFilmEncoder::video(shared_ptr<PlayerVideo> data, DCPTime time) { + std::cout << "DCPFilmEncoder encodes @ " << to_string(time) << "\n"; _encoder->encode(data, time); } diff --git a/src/lib/film.cc b/src/lib/film.cc index f726b2549..b1ee5481d 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -210,9 +210,9 @@ Film::Film(optional<boost::filesystem::path> dir) _video_bit_rate[encoding] = Config::instance()->default_video_bit_rate(encoding); } - _playlist_change_connection = _playlist->Change.connect(bind(&Film::playlist_change, this, _1)); + _playlist_change_connection = _playlist->Change.connect(bind(&Film::playlist_change, this, _1, _2)); _playlist_order_changed_connection = _playlist->OrderChange.connect(bind(&Film::playlist_order_changed, this)); - _playlist_content_change_connection = _playlist->ContentChange.connect(bind(&Film::playlist_content_change, this, _1, _2, _3)); + _playlist_content_change_connection = _playlist->ContentChange.connect(bind(&Film::playlist_content_change, this, _1, _2, _3, _4)); _playlist_length_change_connection = _playlist->LengthChange.connect(bind(&Film::playlist_length_change, this)); if (dir) { @@ -1307,13 +1307,13 @@ Film::set_reencode_j2k(bool r) } void -Film::signal_change(ChangeType type, int p) +Film::signal_change(ChangeType type, int p, int id) { - signal_change(type, static_cast<FilmProperty>(p)); + signal_change(type, static_cast<FilmProperty>(p), id); } void -Film::signal_change(ChangeType type, FilmProperty p) +Film::signal_change(ChangeType type, FilmProperty p, int id) { if (type == ChangeType::DONE) { set_dirty(true); @@ -1324,7 +1324,7 @@ Film::signal_change(ChangeType type, FilmProperty p) } } - emit(boost::bind(boost::ref(Change), type, p)); + emit(boost::bind(boost::ref(Change), type, p, id)); if (p == FilmProperty::VIDEO_FRAME_RATE || p == FilmProperty::SEQUENCE) { /* We want to call Playlist::maybe_sequence but this must happen after the @@ -1333,7 +1333,7 @@ Film::signal_change(ChangeType type, FilmProperty p) emit(boost::bind(&Playlist::maybe_sequence, _playlist.get(), shared_from_this())); } } else { - Change(type, p); + Change(type, p, id); } } @@ -1597,24 +1597,24 @@ Film::active_frame_rate_change(DCPTime t) const } void -Film::playlist_content_change(ChangeType type, int p, bool frequent) +Film::playlist_content_change(ChangeType type, int p, bool frequent, int id) { switch (p) { case ContentProperty::VIDEO_FRAME_RATE: - signal_change(type, FilmProperty::CONTENT); + signal_change(type, FilmProperty::CONTENT, id); break; case AudioContentProperty::STREAMS: - signal_change(type, FilmProperty::NAME); + signal_change(type, FilmProperty::NAME, id); break; } if (type == ChangeType::DONE) { - emit(boost::bind(boost::ref(ContentChange), type, p, frequent)); + emit(boost::bind(boost::ref(ContentChange), type, p, frequent, id)); if (!frequent) { check_settings_consistency(); } } else { - ContentChange(type, p, frequent); + ContentChange(type, p, frequent, id); } set_dirty(true); @@ -1627,10 +1627,10 @@ Film::playlist_length_change() } void -Film::playlist_change(ChangeType type) +Film::playlist_change(ChangeType type, int id) { - signal_change(type, FilmProperty::CONTENT); - signal_change(type, FilmProperty::NAME); + signal_change(type, FilmProperty::CONTENT, id); + signal_change(type, FilmProperty::NAME, id); if (type == ChangeType::DONE) { check_settings_consistency(); @@ -1776,8 +1776,9 @@ Film::check_settings_consistency() void Film::playlist_order_changed() { - /* XXX: missing PENDING */ - signal_change(ChangeType::DONE, FilmProperty::CONTENT_ORDER); + auto const id = ChangeID::next(); + signal_change(ChangeType::PENDING, FilmProperty::CONTENT_ORDER, id); + signal_change(ChangeType::DONE, FilmProperty::CONTENT_ORDER, id); } diff --git a/src/lib/film.h b/src/lib/film.h index 08f639db9..f763b7158 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -434,10 +434,10 @@ public: boost::filesystem::path info_file(dcpomatic::DCPTimePeriod p) const; /** Emitted when some property has of the Film is about to change or has changed */ - mutable boost::signals2::signal<void (ChangeType, FilmProperty)> Change; + mutable boost::signals2::signal<void (ChangeType, FilmProperty, int id)> Change; /** Emitted when some property of our content has changed */ - mutable boost::signals2::signal<void (ChangeType, int, bool)> ContentChange; + mutable boost::signals2::signal<void (ChangeType, int, bool, int id)> ContentChange; /** Emitted when the film's length might have changed; this is not like a normal property as its value is derived from the playlist, so it has its own signal. @@ -464,11 +464,11 @@ private: friend struct ::recover_test_2d_encrypted; template <class, class> friend class ChangeSignalDespatcher; - void signal_change(ChangeType, FilmProperty); - void signal_change(ChangeType, int); - void playlist_change(ChangeType); + void signal_change(ChangeType, FilmProperty, int id); + void signal_change(ChangeType, int, int id); + void playlist_change(ChangeType, int id); void playlist_order_changed(); - void playlist_content_change(ChangeType type, int, bool frequent); + void playlist_content_change(ChangeType type, int, bool frequent, int id); void playlist_length_change(); void maybe_add_content(std::weak_ptr<Job>, std::vector<std::weak_ptr<Content>> const& weak_content, bool disable_audio_analysis); void audio_analysis_finished(); diff --git a/src/lib/fix_audio_levels_job.cc b/src/lib/fix_audio_levels_job.cc index b5d9e39d9..258210b85 100644 --- a/src/lib/fix_audio_levels_job.cc +++ b/src/lib/fix_audio_levels_job.cc @@ -35,6 +35,7 @@ #include "i18n.h" +using std::exception; using std::make_shared; using std::shared_ptr; using std::string; @@ -78,21 +79,53 @@ FixAudioLevelsJob::run() auto playlist = make_shared<Playlist>(); playlist->add(film, input_dcp); + auto set_progress_wrapper = [this](Job* job) { + if (auto p = job->progress()) { + set_progress(*p); + } else { + set_progress_unknown(); + } + }; + AnalyseAudioJob analyse(film, playlist, false, boost::none); - analyse.run(); + std::cout << "AAJ is " << &analyse << "\n"; + analyse.Progress.connect(boost::bind<void>(set_progress_wrapper, &analyse)); + try { + std::cout << "-> calling analyse.run\n"; + analyse.run(); + std::cout << "<- calling analyse.run\n"; + } catch (exception& e) { + std::cout << "analyse failed.\n"; + set_progress(1); + set_state(FINISHED_ERROR); + set_error(e.what()); + return; + } auto const level = analyse.analysis().leqm(); DCPOMATIC_ASSERT(level); if ((!_make_quieter_dcps_louder && *level < _leqm_target) || !input_dcp->audio) { + std::cout << "nothing to do.\n"; set_progress(1); set_state(FINISHED_OK); } input_dcp->audio->set_gain(_leqm_target - *level); - auto transcode = make_shared<DCPTranscodeJob>(film, TranscodeJob::ChangedBehaviour::IGNORE); - transcode->set_encoder(make_shared<DCPFilmEncoder>(film, transcode, true)); - transcode->run(); + + DCPTranscodeJob transcode(film, TranscodeJob::ChangedBehaviour::IGNORE); + transcode.Progress.connect(boost::bind<void>(set_progress_wrapper, &transcode)); + transcode.set_encoder(make_shared<DCPFilmEncoder>(film, shared_from_this(), true)); + try { + std::cout << "transcode.\n"; + transcode.run(); + } catch (exception& e) { + std::cout << "transcode failed " << e.what() << "\n"; + set_progress(1); + set_state(FINISHED_ERROR); + set_error(e.what()); + return; + } set_progress(1); set_state(FINISHED_OK); diff --git a/src/lib/j2k_encoder.cc b/src/lib/j2k_encoder.cc index 97f190d17..b3d2e462a 100644 --- a/src/lib/j2k_encoder.cc +++ b/src/lib/j2k_encoder.cc @@ -317,7 +317,7 @@ J2KEncoder::encode (shared_ptr<PlayerVideo> pv, DCPTime time) _writer.fake_write(position, pv->eyes ()); frame_done (); } else if (pv->has_j2k() && !_film->reencode_j2k()) { - LOG_DEBUG_ENCODE("Frame @ {} J2K", to_string(time)); + LOG_DEBUG_ENCODE("{} Frame @ {} J2K", static_cast<void*>(this), to_string(time)); /* This frame already has J2K data, so just write it */ _writer.write(pv->j2k(), position, pv->eyes ()); frame_done (); diff --git a/src/lib/player.cc b/src/lib/player.cc index 743d17fcb..567c71aec 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -85,7 +85,6 @@ using namespace dcpomatic; Player::Player(shared_ptr<const Film> film, Image::Alignment subtitle_alignment, bool tolerant) : _film(film) - , _suspended(0) , _ignore_video(false) , _ignore_audio(false) , _ignore_text(false) @@ -103,7 +102,6 @@ Player::Player(shared_ptr<const Film> film, Image::Alignment subtitle_alignment, Player::Player(shared_ptr<const Film> film, shared_ptr<const Playlist> playlist_, bool tolerant) : _film(film) , _playlist(playlist_) - , _suspended(0) , _ignore_video(false) , _ignore_audio(false) , _ignore_text(false) @@ -126,7 +124,9 @@ Player::construct() connect(); set_video_container_size(film->frame_size()); - film_change(ChangeType::DONE, FilmProperty::AUDIO_PROCESSOR); + auto const id = ChangeID::next(); + film_change(ChangeType::PENDING, FilmProperty::AUDIO_PROCESSOR, id); + film_change(ChangeType::DONE, FilmProperty::AUDIO_PROCESSOR, id); setup_pieces(); seek(DCPTime(), true); @@ -139,19 +139,19 @@ Player::connect() auto film = _film.lock(); DCPOMATIC_ASSERT(film); - _film_changed_connection = film->Change.connect(bind(&Player::film_change, this, _1, _2)); + _film_changed_connection = film->Change.connect(bind(&Player::film_change, this, _1, _2, _3)); /* The butler must hear about this first, so since we are proxying this through to the butler we must be first. */ - _playlist_change_connection = playlist()->Change.connect(bind(&Player::playlist_change, this, _1), boost::signals2::at_front); - _playlist_content_change_connection = playlist()->ContentChange.connect(bind(&Player::playlist_content_change, this, _1, _2, _3)); + _playlist_change_connection = playlist()->Change.connect(bind(&Player::playlist_change, this, _1, _2), boost::signals2::at_front); + _playlist_content_change_connection = playlist()->ContentChange.connect(bind(&Player::playlist_content_change, this, _1, _2, _3, _4)); } Player::Player(Player&& other) : _film(other._film) , _playlist(std::move(other._playlist)) - , _suspended(other._suspended.load()) + , _suspended(other._suspended) , _pieces(std::move(other._pieces)) , _video_container_size(other._video_container_size.load()) , _black_image(std::move(other._black_image)) @@ -191,7 +191,7 @@ Player::operator=(Player&& other) _film = std::move(other._film); _playlist = std::move(other._playlist); - _suspended = other._suspended.load(); + _suspended = other._suspended; _pieces = std::move(other._pieces); _video_container_size = other._video_container_size.load(); _black_image = std::move(other._black_image); @@ -241,6 +241,8 @@ have_audio(shared_ptr<const Content> content) void Player::setup_pieces() { + std::cout << "--setup_pieces--\n"; + boost::mutex::scoped_lock lm(_mutex); auto old_pieces = _pieces; @@ -400,7 +402,7 @@ Player::setup_pieces() void -Player::playlist_content_change(ChangeType type, int property, bool frequent) +Player::playlist_content_change(ChangeType type, int property, bool frequent, int id) { auto film = _film.lock(); if (!film) { @@ -420,17 +422,21 @@ Player::playlist_content_change(ChangeType type, int property, bool frequent) until that has happened and we've rebuilt our pieces. Stop pass() and seek() from working until then. */ - ++_suspended; + boost::mutex::scoped_lock lm(_suspended_mutex); + _suspended.insert(id); } else if (type == ChangeType::DONE) { /* A change in our content has gone through. Re-build our pieces. */ + std::cout << "setup_pieces because playlist_content_change " << property << "\n"; setup_pieces(); - --_suspended; + boost::mutex::scoped_lock lm(_suspended_mutex); + _suspended.erase(id); } else if (type == ChangeType::CANCELLED) { - --_suspended; + boost::mutex::scoped_lock lm(_suspended_mutex); + _suspended.erase(id); } } - Change(type, property, frequent); + Change(type, property, frequent, id); } @@ -455,17 +461,18 @@ Player::set_video_container_size(dcp::Size s) void -Player::playlist_change(ChangeType type) +Player::playlist_change(ChangeType type, int id) { if (type == ChangeType::DONE) { + std::cout << "setup_pieces because of playlist_change\n"; setup_pieces(); } - Change(type, PlayerProperty::PLAYLIST, false); + Change(type, PlayerProperty::PLAYLIST, false, id); } void -Player::film_change(ChangeType type, FilmProperty p) +Player::film_change(ChangeType type, FilmProperty p, int id) { /* Here we should notice Film properties that affect our output, and alert listeners that our output now would be different to how it was @@ -478,15 +485,16 @@ Player::film_change(ChangeType type, FilmProperty p) } if (p == FilmProperty::CONTAINER) { - Change(type, PlayerProperty::FILM_CONTAINER, false); + Change(type, PlayerProperty::FILM_CONTAINER, false, id); } else if (p == FilmProperty::VIDEO_FRAME_RATE) { /* Pieces contain a FrameRateChange which contains the DCP frame rate, so we need new pieces here. */ if (type == ChangeType::DONE) { + std::cout << "Setup pieces because FilmProperty::VIDEO_FRAME_RATE\n"; setup_pieces(); } - Change(type, PlayerProperty::FILM_VIDEO_FRAME_RATE, false); + Change(type, PlayerProperty::FILM_VIDEO_FRAME_RATE, false, id); } else if (p == FilmProperty::AUDIO_PROCESSOR) { if (type == ChangeType::DONE && film->audio_processor()) { boost::mutex::scoped_lock lm(_mutex); @@ -681,6 +689,8 @@ Player::earliest_piece_and_time() const shared_ptr<Piece> earliest_content; optional<DCPTime> earliest_time; + std::cout << "EP&T: " << _pieces.size() << "\n"; + for (auto const& piece: _pieces) { if (piece->done) { continue; @@ -709,10 +719,13 @@ Player::pass() { boost::mutex::scoped_lock lm(_mutex); - if (_suspended) { - /* We can't pass in this state */ - LOG_DEBUG_PLAYER_NC("Player is suspended"); - return false; + { + boost::mutex::scoped_lock lm2(_suspended_mutex); + if (!_suspended.empty()) { + /* We can't pass in this state */ + LOG_DEBUG_PLAYER_NC("Player is suspended"); + return false; + } } auto film = _film.lock(); @@ -756,6 +769,7 @@ Player::pass() case CONTENT: { LOG_DEBUG_PLAYER("Calling pass() on {}", earliest_content->content->path(0).string()); + std::cout << "Calling pass() on " << earliest_content << "\n"; earliest_content->done = earliest_content->decoder->pass(); auto dcp = dynamic_pointer_cast<DCPContent>(earliest_content->content); if (dcp && !_play_referenced) { @@ -1031,8 +1045,11 @@ Player::emit_video_until(DCPTime time) void Player::video(weak_ptr<Piece> weak_piece, ContentVideo video) { - if (_suspended) { - return; + { + boost::mutex::scoped_lock lm(_suspended_mutex); + if (!_suspended.empty()) { + return; + } } auto piece = weak_piece.lock(); @@ -1137,8 +1154,11 @@ Player::use_video(shared_ptr<PlayerVideo> pv, DCPTime time, DCPTime end) void Player::audio(weak_ptr<Piece> weak_piece, AudioStreamPtr stream, ContentAudio content_audio) { - if (_suspended) { - return; + { + boost::mutex::scoped_lock lm(_suspended_mutex); + if (!_suspended.empty()) { + return; + } } DCPOMATIC_ASSERT(content_audio.audio->frames() > 0); @@ -1233,8 +1253,11 @@ Player::audio(weak_ptr<Piece> weak_piece, AudioStreamPtr stream, ContentAudio co boost::optional<DCPTime> Player::should_store(weak_ptr<Piece> weak_piece, weak_ptr<const TextContent> weak_content, ContentTime subtitle_from) const { - if (_suspended) { - return {}; + { + boost::mutex::scoped_lock lm(_suspended_mutex); + if (!_suspended.empty()) { + return {}; + } } auto piece = weak_piece.lock(); @@ -1343,8 +1366,11 @@ Player::plain_text_start(weak_ptr<Piece> weak_piece, weak_ptr<const TextContent> void Player::text_stop(weak_ptr<Piece> weak_piece, weak_ptr<const TextContent> weak_content, ContentTime to) { - if (_suspended) { - return; + { + boost::mutex::scoped_lock lm(_suspended_mutex); + if (!_suspended.empty()) { + return; + } } auto content = weak_content.lock(); @@ -1384,9 +1410,11 @@ Player::seek(DCPTime time, bool accurate) boost::mutex::scoped_lock lm(_mutex); LOG_DEBUG_PLAYER("Seek to {} ({}accurate)", to_string(time), accurate ? "" : "in"); - if (_suspended) { - /* We can't seek in this state */ - return; + { + boost::mutex::scoped_lock lm(_suspended_mutex); + if (!_suspended.empty()) { + return; + } } auto film = _film.lock(); @@ -1595,8 +1623,11 @@ Player::playlist() const void Player::atmos(weak_ptr<Piece> weak_piece, ContentAtmos data) { - if (_suspended) { - return; + { + boost::mutex::scoped_lock lm(_suspended_mutex); + if (!_suspended.empty()) { + return; + } } auto film = _film.lock(); @@ -1626,9 +1657,9 @@ Player::atmos(weak_ptr<Piece> weak_piece, ContentAtmos data) void -Player::signal_change(ChangeType type, int property) +Player::signal_change(ChangeType type, int property, int id) { - Change(type, property, false); + Change(type, property, false, id); } diff --git a/src/lib/player.h b/src/lib/player.h index 9076ac242..def165b51 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -113,13 +113,13 @@ public: boost::optional<dcpomatic::DCPTime> content_time_to_dcp(std::shared_ptr<const Content> content, dcpomatic::ContentTime t) const; boost::optional<dcpomatic::ContentTime> dcp_to_content_time(std::shared_ptr<const Content> content, dcpomatic::DCPTime t) const; - void signal_change(ChangeType type, int property); + void signal_change(ChangeType type, int property, int id); /** First parameter is PENDING, DONE or CANCELLED. * Second parameter is the property. * Third parameter is true if these signals are currently likely to be frequent. */ - boost::signals2::signal<void (ChangeType, int, bool)> Change; + boost::signals2::signal<void (ChangeType, int, bool, int)> Change; /** Emitted when a video frame is ready. These emissions happen in the correct order. */ boost::signals2::signal<void (std::shared_ptr<PlayerVideo>, dcpomatic::DCPTime)> Video; @@ -148,9 +148,9 @@ private: void construct(); void connect(); void setup_pieces(); - void film_change(ChangeType, FilmProperty); - void playlist_change(ChangeType); - void playlist_content_change(ChangeType, int, bool); + void film_change(ChangeType, FilmProperty, int id); + void playlist_change(ChangeType, int id); + void playlist_content_change(ChangeType, int, bool, int id); Frame dcp_to_content_video(std::shared_ptr<const Piece> piece, dcpomatic::DCPTime t) const; dcpomatic::DCPTime content_video_to_dcp(std::shared_ptr<const Piece> piece, Frame f) const; Frame dcp_to_resampled_audio(std::shared_ptr<const Piece> piece, dcpomatic::DCPTime t) const; @@ -193,8 +193,9 @@ private: /** Playlist, or 0 if we are using the one from the _film */ std::shared_ptr<const Playlist> _playlist; - /** > 0 if we are suspended (i.e. pass() and seek() do nothing) */ - boost::atomic<int> _suspended; + mutable boost::mutex _suspended_mutex; + /** Contains something if we are suspended (i.e. pass() and seek() do nothing) */ + std::set<int> _suspended; std::vector<std::shared_ptr<Piece>> _pieces; /** Size of the image we are rendering to; this may be the DCP frame size, or diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 8c60a5458..5398d0d87 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -89,7 +89,7 @@ Playlist::~Playlist() void -Playlist::content_change(weak_ptr<const Film> weak_film, ChangeType type, int property, bool frequent) +Playlist::content_change(weak_ptr<const Film> weak_film, ChangeType type, int property, bool frequent, int id) { auto film = weak_film.lock(); DCPOMATIC_ASSERT(film); @@ -133,7 +133,7 @@ Playlist::content_change(weak_ptr<const Film> weak_film, ChangeType type, int pr } } - ContentChange(type, property, frequent); + ContentChange(type, property, frequent, id); } @@ -293,7 +293,9 @@ Playlist::as_xml(xmlpp::Element* element, bool with_content_paths, PathBehaviour void Playlist::add(shared_ptr<const Film> film, shared_ptr<Content> c) { - Change(ChangeType::PENDING); + auto const id = ChangeID::next(); + + Change(ChangeType::PENDING, id); { boost::mutex::scoped_lock lm(_mutex); @@ -302,7 +304,7 @@ Playlist::add(shared_ptr<const Film> film, shared_ptr<Content> c) reconnect(film); } - Change(ChangeType::DONE); + Change(ChangeType::DONE, id); LengthChange(); } @@ -311,7 +313,9 @@ Playlist::add(shared_ptr<const Film> film, shared_ptr<Content> c) void Playlist::add_at_end(shared_ptr<const Film> film, vector<shared_ptr<Content>> const& content) { - Change(ChangeType::PENDING); + auto const id = ChangeID::next(); + + Change(ChangeType::PENDING, id); for (auto c: content) { /* Add {video,subtitle} content after any existing {video,subtitle} content */ @@ -327,7 +331,7 @@ Playlist::add_at_end(shared_ptr<const Film> film, vector<shared_ptr<Content>> co reconnect(film); } - Change(ChangeType::DONE); + Change(ChangeType::DONE, id); LengthChange(); } @@ -336,7 +340,9 @@ Playlist::add_at_end(shared_ptr<const Film> film, vector<shared_ptr<Content>> co void Playlist::remove(shared_ptr<Content> c) { - Change(ChangeType::PENDING); + auto const id = ChangeID::next(); + + Change(ChangeType::PENDING, id); bool cancelled = false; @@ -356,9 +362,9 @@ Playlist::remove(shared_ptr<Content> c) } if (cancelled) { - Change(ChangeType::CANCELLED); + Change(ChangeType::CANCELLED, id); } else { - Change(ChangeType::DONE); + Change(ChangeType::DONE, id); } /* This won't change order, so it does not need a sort */ @@ -370,7 +376,9 @@ Playlist::remove(shared_ptr<Content> c) void Playlist::remove(ContentList c) { - Change(ChangeType::PENDING); + auto const id = ChangeID::next(); + + Change(ChangeType::PENDING, id); { boost::mutex::scoped_lock lm(_mutex); @@ -387,7 +395,7 @@ Playlist::remove(ContentList c) } } - Change(ChangeType::DONE); + Change(ChangeType::DONE, id); /* This won't change order, so it does not need a sort */ @@ -516,7 +524,7 @@ Playlist::reconnect(shared_ptr<const Film> film) disconnect(); for (auto i: _content) { - _content_connections.push_back(i->Change.connect(boost::bind(&Playlist::content_change, this, film, _1, _2, _3))); + _content_connections.push_back(i->Change.connect(boost::bind(&Playlist::content_change, this, film, _1, _2, _3, _4))); } } @@ -603,7 +611,9 @@ Playlist::repeat(shared_ptr<const Film> film, ContentList c, int n) range.second = max(range.second, i->end(film)); } - Change(ChangeType::PENDING); + auto const id = ChangeID::next(); + + Change(ChangeType::PENDING, id); { boost::mutex::scoped_lock lm(_mutex); @@ -622,7 +632,7 @@ Playlist::repeat(shared_ptr<const Film> film, ContentList c, int n) reconnect(film); } - Change(ChangeType::DONE); + Change(ChangeType::DONE, id); LengthChange(); } diff --git a/src/lib/playlist.h b/src/lib/playlist.h index 0d38cbf67..649492544 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -82,15 +82,15 @@ public: void repeat(std::shared_ptr<const Film> film, ContentList, int); /** Emitted when content has been added to or removed from the playlist; implies OrderChange */ - mutable boost::signals2::signal<void (ChangeType)> Change; + mutable boost::signals2::signal<void (ChangeType, int)> Change; mutable boost::signals2::signal<void ()> OrderChange; /** Emitted when the length might have changed; may sometimes be emitted when it has not */ mutable boost::signals2::signal<void ()> LengthChange; - mutable boost::signals2::signal<void (ChangeType, int, bool)> ContentChange; + mutable boost::signals2::signal<void (ChangeType, int, bool, int)> ContentChange; private: - void content_change(std::weak_ptr<const Film>, ChangeType, int, bool); + void content_change(std::weak_ptr<const Film>, ChangeType, int, bool, int id); void disconnect(); void reconnect(std::shared_ptr<const Film> film); diff --git a/src/lib/signal_manager.h b/src/lib/signal_manager.h index 8138817d3..81a52dc10 100644 --- a/src/lib/signal_manager.h +++ b/src/lib/signal_manager.h @@ -65,7 +65,7 @@ public: } /** This should wake the UI and make it call ui_idle() */ - virtual void wake_ui () { + virtual void wake () { /* This is only a sensible implementation when there is no GUI */ ui_idle (); } diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc index b6e350d34..10bbd05d7 100644 --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@ -324,7 +324,9 @@ VideoContent::take_from_examiner(shared_ptr<const Film> film, shared_ptr<VideoEx LOG_GENERAL("Video length obtained from header as {} frames", _length); if (d->video_frame_rate()) { + std::cout << "-> set_video_frame_rate\n"; _parent->set_video_frame_rate(film, d->video_frame_rate().get()); + std::cout << "<- set_video_frame_rate\n"; } } diff --git a/src/tools/dcpomatic_processor.cc b/src/tools/dcpomatic_processor.cc index 0624d3b45..460de87b6 100644 --- a/src/tools/dcpomatic_processor.cc +++ b/src/tools/dcpomatic_processor.cc @@ -24,9 +24,12 @@ #include "wx/check_box.h" #include "wx/editable_list.h" #include "wx/i18n_setup.h" +#include "wx/wx_signal_manager.h" #include "wx/wx_util.h" #include "wx/wx_variant.h" #include "lib/cross.h" +#include "lib/dcpomatic_log.h" +#include "lib/file_log.h" #include "lib/fix_audio_levels_job.h" #include "lib/job_manager.h" #include "lib/util.h" @@ -42,9 +45,11 @@ LIBDCP_ENABLE_WARNINGS #endif +using std::dynamic_pointer_cast; using std::exception; using std::make_shared; using std::shared_ptr; +using std::string; using std::vector; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; @@ -78,6 +83,53 @@ public: +class ProgressPanel : public wxPanel +{ +public: + ProgressPanel(wxWindow* parent) + : wxPanel(parent, wxID_ANY) + { + auto overall_sizer = new wxBoxSizer(wxVERTICAL); + + _job_name = new wxStaticText(this, wxID_ANY, {}); + overall_sizer->Add(_job_name, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, DCPOMATIC_SIZER_GAP); + + _progress = new wxGauge(this, wxID_ANY, 100); + overall_sizer->Add(_progress, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP); + + SetSizerAndFit(overall_sizer); + } + + void update(std::shared_ptr<const FixAudioLevelsJob> job) + { + auto const progress = job->progress(); + if (progress) { + _progress->SetValue(*progress * 100); + } else { + _progress->Pulse(); + } + string const sub = job->sub_name(); + size_t colon = sub.find(":"); + if (colon != string::npos) { + _job_name->SetLabel(std_to_wx(sub.substr(0, colon))); + } else { + _job_name->SetLabel(std_to_wx(sub)); + } + } + + void clear() + { + _job_name->SetLabel(wxT("")); + _progress->SetValue(0); + } + +private: + wxStaticText* _job_name; + wxGauge* _progress; +}; + + + class DOMFrame : public wxFrame { public: @@ -125,6 +177,9 @@ public: options_sizer->Add(_fix_audio_levels, 0, wxBOTTOM, DCPOMATIC_SIZER_GAP); overall_sizer->Add(options_sizer, 0, wxLEFT, DCPOMATIC_DIALOG_BORDER); + _progress_panel = new ProgressPanel(_overall_panel); + overall_sizer->Add(_progress_panel, 0, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + auto actions_sizer = new wxBoxSizer(wxHORIZONTAL); _cancel = new Button(_overall_panel, _("Cancel")); actions_sizer->Add(_cancel, 0, wxRIGHT, DCPOMATIC_SIZER_GAP); @@ -138,6 +193,9 @@ public: _process->bind(&DOMFrame::process_clicked, this); setup_sensitivity(); + + dcpomatic_log = make_shared<FileLog>("/home/carl/shite.log"); + dcpomatic_log->set_types(dcpomatic_log->types() | LogEntry::TYPE_DEBUG_ENCODE); } private: @@ -198,15 +256,26 @@ private: while (job_manager->work_to_do() && !_cancel_pending) { wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT); dcpomatic_sleep_milliseconds(250); + while (signal_manager->ui_idle()) {} + auto last = job_manager->last_active_job(); + if (auto locked = last.lock()) { + if (auto job = dynamic_pointer_cast<FixAudioLevelsJob>(locked)) { + _progress_panel->update(job); + } + } } if (_cancel_pending) { _cancel_pending = false; JobManager::instance()->cancel_all_jobs(); + _progress_panel->clear(); setup_sensitivity(); return; } + _progress_panel->clear(); + setup_sensitivity(); + #if 0 dcp::VerificationOptions options; options.check_picture_details = _check_picture_details->get(); @@ -274,6 +343,7 @@ private: CheckBox* _fix_audio_levels; Button* _cancel; Button* _process; + ProgressPanel* _progress_panel; bool _cancel_pending = false; }; @@ -330,6 +400,8 @@ private: */ Config::drop(); + signal_manager = new wxSignalManager(this); + _frame = new DOMFrame(variant::wx::dcpomatic_processor()); SetTopWindow(_frame); _frame->Maximize(); |
