summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/analyse_audio_job.cc7
-rw-r--r--src/lib/change_signaller.cc10
-rw-r--r--src/lib/change_signaller.h24
-rw-r--r--src/lib/content.cc6
-rw-r--r--src/lib/content.h4
-rw-r--r--src/lib/dcp_film_encoder.cc2
-rw-r--r--src/lib/film.cc35
-rw-r--r--src/lib/film.h12
-rw-r--r--src/lib/fix_audio_levels_job.cc41
-rw-r--r--src/lib/j2k_encoder.cc2
-rw-r--r--src/lib/player.cc105
-rw-r--r--src/lib/player.h15
-rw-r--r--src/lib/playlist.cc38
-rw-r--r--src/lib/playlist.h6
-rw-r--r--src/lib/signal_manager.h2
-rw-r--r--src/lib/video_content.cc2
-rw-r--r--src/tools/dcpomatic_processor.cc72
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();