X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fwriter.cc;h=fbe2d248d5c952c3112f1e5f9f7184ae3b4073c3;hb=HEAD;hp=6bc3da504e0e786643a9f5835123cf8da077f366;hpb=96f50dd5e600925488fdd9db1580aa01b026269b;p=dcpomatic.git diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 6bc3da504..7b9defd73 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -41,7 +41,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -142,6 +144,10 @@ Writer::write (shared_ptr encoded, Frame frame, Eyes eyes) { boost::mutex::scoped_lock lock (_state_mutex); + if (_zombie) { + return; + } + while (_queued_full_in_memory > _maximum_frames_in_memory) { /* There are too many full frames in memory; wake the main writer thread and wait until it sorts everything out */ @@ -375,6 +381,9 @@ try while (true) { boost::mutex::scoped_lock lock (_state_mutex); + if (_zombie) { + return; + } while (true) { @@ -531,19 +540,32 @@ Writer::calculate_digests () pool.create_thread (boost::bind (&boost::asio::io_service::run, &service)); } - std::function set_progress; + std::function set_progress; if (job) { - set_progress = boost::bind (&Writer::set_digest_progress, this, job.get(), _1); + set_progress = boost::bind(&Writer::set_digest_progress, this, job.get(), _1, _2, _3); } else { - set_progress = [](float) { + set_progress = [](int, int64_t, int64_t) { boost::this_thread::interruption_point(); }; } + int index = 0; + for (auto& i: _reels) { - service.post (boost::bind (&ReelWriter::calculate_digests, &i, set_progress)); + service.post( + boost::bind( + &ReelWriter::calculate_digests, + &i, + std::function(boost::bind(set_progress, index, _1, _2)) + )); + ++index; } - service.post (boost::bind (&Writer::calculate_referenced_digests, this, set_progress)); + service.post( + boost::bind( + &Writer::calculate_referenced_digests, + this, + std::function(boost::bind(set_progress, index, _1, _2)) + )); work.reset (); @@ -875,53 +897,9 @@ Writer::write (vector> fonts) } _chosen_interop_font = fonts[0]; } else { - set used_ids; - - /* Return the index of a _N at the end of a string, or string::npos */ - auto underscore_number_position = [](string s) { - auto last_underscore = s.find_last_of("_"); - if (last_underscore == string::npos) { - return string::npos; - } - - for (auto i = last_underscore + 1; i < s.size(); ++i) { - if (!isdigit(s[i])) { - return string::npos; - } - } - - return last_underscore; - }; - - /* Write fonts to _fonts, changing any duplicate IDs so that they are unique */ for (auto font: fonts) { - auto id = fix_id(font->id()); - if (used_ids.find(id) == used_ids.end()) { - /* This ID is unique so we can just use it as-is */ - _fonts.put(font, id); - used_ids.insert(id); - } else { - auto end = underscore_number_position(id); - if (end == string::npos) { - /* This string has no _N suffix, so add one */ - id += "_0"; - end = underscore_number_position(id); - } - - ++end; - - /* Increment the suffix until we find a unique one */ - auto number = dcp::raw_convert(id.substr(end)); - while (used_ids.find(id) != used_ids.end()) { - ++number; - id = String::compose("%1_%2", id.substr(0, end - 1), number); - } - used_ids.insert(id); - } - _fonts.put(font, id); + _fonts.put(font, fix_id(font->id())); } - - DCPOMATIC_ASSERT(_fonts.map().size() == used_ids.size()); } } @@ -961,6 +939,22 @@ void Writer::write (ReferencedReelAsset asset) { _reel_assets.push_back (asset); + + if (dynamic_pointer_cast(asset.asset)) { + _have_subtitles = true; + } else if (auto ccap = dynamic_pointer_cast(asset.asset)) { + /* This feels quite fragile. We have a referenced reel and want to know if it's + * part of a given closed-caption track so that we can fill if it has any + * missing reels. I guess for that purpose almost any DCPTextTrack values are + * fine so long as they are consistent. + */ + DCPTextTrack track; + track.name = ccap->annotation_text().get_value_or(""); + track.language = dcp::LanguageTag(ccap->language().get_value_or("en-US")); + if (_have_closed_captions.find(track) == _have_closed_captions.end()) { + _have_closed_captions.insert(track); + } + } } @@ -978,18 +972,29 @@ Writer::video_reel (int frame) const } +/** Update job progress with information about the progress of a single digest calculation + * thread. + * @param id Unique identifier for the thread whose progress has changed. + * @param done Number of bytes that this thread has processed. + * @param size Total number of bytes that this thread must process. + */ void -Writer::set_digest_progress (Job* job, float progress) +Writer::set_digest_progress(Job* job, int id, int64_t done, int64_t size) { boost::mutex::scoped_lock lm (_digest_progresses_mutex); - _digest_progresses[boost::this_thread::get_id()] = progress; - float min_progress = FLT_MAX; + /* Update the progress for this thread */ + _digest_progresses[id] = std::make_pair(done, size); + + /* Get the total progress across all threads and use it to set job progress */ + int64_t total_done = 0; + int64_t total_size = 0; for (auto const& i: _digest_progresses) { - min_progress = min (min_progress, i.second); + total_done += i.second.first; + total_size += i.second.second; } - job->set_progress (min_progress); + job->set_progress(float(total_done) / total_size); Waker waker; waker.nudge (); @@ -1000,13 +1005,27 @@ Writer::set_digest_progress (Job* job, float progress) /** Calculate hashes for any referenced MXF assets which do not already have one */ void -Writer::calculate_referenced_digests (std::function set_progress) +Writer::calculate_referenced_digests(std::function set_progress) try { + int64_t total_size = 0; + for (auto const& i: _reel_assets) { + auto file = dynamic_pointer_cast(i.asset); + if (file && !file->hash()) { + auto filename = file->asset_ref().asset()->file(); + DCPOMATIC_ASSERT(filename); + total_size += boost::filesystem::file_size(*filename); + } + } + + int64_t total_done = 0; for (auto const& i: _reel_assets) { auto file = dynamic_pointer_cast(i.asset); if (file && !file->hash()) { - file->asset_ref().asset()->hash (set_progress); + file->asset_ref().asset()->hash([&total_done, total_size, set_progress](int64_t done, int64_t) { + set_progress(total_done + done, total_size); + }); + total_done += boost::filesystem::file_size(*file->asset_ref().asset()->file()); file->set_hash (file->asset_ref().asset()->hash()); } } @@ -1030,3 +1049,17 @@ Writer::write_hanging_text (ReelWriter& reel) } _hanging_texts = new_hanging_texts; } + + +/** Set the writer so that it has no queue and drops any pending or future requests to write images */ +void +Writer::zombify() +{ + boost::mutex::scoped_lock lock(_state_mutex); + + _queue.clear(); + _queued_full_in_memory = 0; + _zombie = true; + _full_condition.notify_all(); +} +