X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fwriter.cc;h=915376055b31f9f55561dc7a5ca6b48fa44746a9;hb=3f9b394d57e750624d361f5daae6db77079f862a;hp=8ee6293094c1397d58ef8a7384a94cde58aff9d4;hpb=80908df324b330dc35d7e70b69ae5fce0dcfbab1;p=dcpomatic.git diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 8ee629309..915376055 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2017 Carl Hetherington + Copyright (C) 2012-2019 Carl Hetherington This file is part of DCP-o-matic. @@ -23,6 +23,7 @@ #include "film.h" #include "ratio.h" #include "log.h" +#include "dcpomatic_log.h" #include "dcp_video.h" #include "dcp_content_type.h" #include "audio_mapping.h" @@ -34,6 +35,7 @@ #include "font.h" #include "util.h" #include "reel_writer.h" +#include "text_content.h" #include #include #include @@ -44,14 +46,6 @@ #include "i18n.h" -#define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL); -#define LOG_GENERAL_NC(...) _film->log()->log (__VA_ARGS__, LogEntry::TYPE_GENERAL); -#define LOG_DEBUG_ENCODE(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_DEBUG_ENCODE); -#define LOG_TIMING(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_TIMING); -#define LOG_WARNING_NC(...) _film->log()->log (__VA_ARGS__, LogEntry::TYPE_WARNING); -#define LOG_WARNING(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_WARNING); -#define LOG_ERROR(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_ERROR); - /* OS X strikes again */ #undef set_key @@ -63,10 +57,13 @@ using std::cout; using std::map; using std::min; using std::max; +using std::vector; using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; +using boost::optional; using dcp::Data; +using namespace dcpomatic; Writer::Writer (shared_ptr film, weak_ptr j) : _film (film) @@ -91,11 +88,14 @@ Writer::Writer (shared_ptr film, weak_ptr j) _reels.push_back (ReelWriter (film, p, job, reel_index++, reels.size(), _film->content_summary(p))); } - /* We can keep track of the current audio and subtitle reels easily because audio - and subs arrive to the Writer in sequence. This is not so for video. + /* We can keep track of the current audio, subtitle and closed caption reels easily because audio + and captions arrive to the Writer in sequence. This is not so for video. */ _audio_reel = _reels.begin (); _subtitle_reel = _reels.begin (); + BOOST_FOREACH (DCPTextTrack i, _film->closed_caption_tracks()) { + _caption_reels[i] = _reels.begin (); + } /* Check that the signer is OK if we need one */ string reason; @@ -130,7 +130,9 @@ Writer::write (Data encoded, Frame frame, Eyes eyes) boost::mutex::scoped_lock lock (_state_mutex); while (_queued_full_in_memory > _maximum_frames_in_memory) { - /* There are too many full frames in memory; wait until that is sorted out */ + /* There are too many full frames in memory; wake the main writer thread and + wait until it sorts everything out */ + _empty_condition.notify_all (); _full_condition.wait (lock); } @@ -173,8 +175,11 @@ Writer::repeat (Frame frame, Eyes eyes) { boost::mutex::scoped_lock lock (_state_mutex); - while (_queue.size() > _maximum_queue_size) { - /* The queue is too big; wait until that is sorted out */ + while (_queue.size() > _maximum_queue_size && have_sequenced_image_at_queue_head()) { + /* The queue is too big, and the main writer thread can run and fix it, so + wake it and wait until it has done. + */ + _empty_condition.notify_all (); _full_condition.wait (lock); } @@ -201,29 +206,25 @@ Writer::fake_write (Frame frame, Eyes eyes) { boost::mutex::scoped_lock lock (_state_mutex); - while (_queue.size() > _maximum_queue_size) { - /* The queue is too big; wait until that is sorted out. We're assuming here - that it will be sorted out either by time or by a necessary full-written - frame being given to us. fake_write() must be called more-or-less in - order or this will deadlock due to the main write thread waiting for - a frame that never arrives because we're waiting here. + while (_queue.size() > _maximum_queue_size && have_sequenced_image_at_queue_head()) { + /* The queue is too big, and the main writer thread can run and fix it, so + wake it and wait until it has done. */ + _empty_condition.notify_all (); _full_condition.wait (lock); } size_t const reel = video_reel (frame); Frame const reel_frame = frame - _reels[reel].start (); - FILE* file = fopen_boost (_film->info_file(_reels[reel].period()), "rb"); - if (!file) { - throw ReadFileError (_film->info_file(_reels[reel].period())); - } - dcp::FrameInfo info = _reels[reel].read_frame_info (file, reel_frame, eyes); - fclose (file); - QueueItem qi; qi.type = QueueItem::FAKE; - qi.size = info.size; + + { + shared_ptr info_file = _film->info_file_handle(_reels[reel].period(), true); + qi.size = _reels[reel].read_frame_info(info_file, reel_frame, eyes).size; + } + qi.reel = reel; qi.frame = reel_frame; if (_film->three_d() && eyes == EYES_BOTH) { @@ -268,8 +269,11 @@ Writer::write (shared_ptr audio, DCPTime const time) /* Easy case: we can write all the audio to this reel */ _audio_reel->write (audio); t = end; + } else if (_audio_reel->period().to <= t) { + /* This reel is entirely before the start of our audio; just skip the reel */ + ++_audio_reel; } else { - /* Split the audio into two and write the first part */ + /* This audio is over a reel boundary; split the audio into two and write the first part */ DCPTime part_lengths[2] = { _audio_reel->period().to - t, end - _audio_reel->period().to @@ -430,7 +434,7 @@ try DCPOMATIC_ASSERT (i != _queue.rend()); ++_pushed_to_disk; /* For the log message below */ - int const awaiting = _reels[_queue.front().reel].last_written_video_frame(); + int const awaiting = _reels[_queue.front().reel].last_written_video_frame() + 1; lock.unlock (); /* i is valid here, even though we don't hold a lock on the mutex, @@ -556,6 +560,7 @@ Writer::finish () meta.set_issue_date_now (); cpl->set_metadata (meta); + cpl->set_ratings (vector_to_list(_film->ratings())); shared_ptr signer; if (_film->is_signed ()) { @@ -582,7 +587,7 @@ Writer::write_cover_sheet () boost::filesystem::path const cover = _film->file ("COVER_SHEET.txt"); FILE* f = fopen_boost (cover, "w"); if (!f) { - throw OpenFileError (cover, errno, false); + throw OpenFileError (cover, errno, OpenFileError::WRITE); } string text = Config::instance()->cover_sheet (); @@ -590,7 +595,16 @@ Writer::write_cover_sheet () boost::algorithm::replace_all (text, "$TYPE", _film->dcp_content_type()->pretty_name()); boost::algorithm::replace_all (text, "$CONTAINER", _film->container()->container_nickname()); boost::algorithm::replace_all (text, "$AUDIO_LANGUAGE", _film->isdcf_metadata().audio_language); - boost::algorithm::replace_all (text, "$SUBTITLE_LANGUAGE", _film->isdcf_metadata().subtitle_language); + + optional subtitle_language; + BOOST_FOREACH (shared_ptr i, _film->content()) { + BOOST_FOREACH (shared_ptr j, i->text) { + if (j->type() == TEXT_OPEN_SUBTITLE && j->use()) { + subtitle_language = j->language (); + } + } + } + boost::algorithm::replace_all (text, "$SUBTITLE_LANGUAGE", subtitle_language.get_value_or("None")); boost::uintmax_t size = 0; for ( @@ -633,7 +647,7 @@ Writer::write_cover_sheet () boost::algorithm::replace_all (text, "$LENGTH", length); - fwrite (text.c_str(), 1, text.length(), f); + checked_fwrite (text.c_str(), text.length(), f, cover); fclose (f); } @@ -659,21 +673,32 @@ Writer::can_fake_write (Frame frame) const return (frame != 0 && frame < reel.first_nonexistant_frame()); } +/** @param track Closed caption track if type == TEXT_CLOSED_CAPTION */ void -Writer::write (PlayerSubtitles subs, DCPTimePeriod period) +Writer::write (PlayerText text, TextType type, optional track, DCPTimePeriod period) { - if (subs.text.empty ()) { - return; - } + vector::iterator* reel = 0; - while (_subtitle_reel->period().to <= period.from) { - ++_subtitle_reel; - DCPOMATIC_ASSERT (_subtitle_reel != _reels.end()); + switch (type) { + case TEXT_OPEN_SUBTITLE: + reel = &_subtitle_reel; + break; + case TEXT_CLOSED_CAPTION: + DCPOMATIC_ASSERT (track); + DCPOMATIC_ASSERT (_caption_reels.find(*track) != _caption_reels.end()); + reel = &_caption_reels[*track]; + break; + default: + DCPOMATIC_ASSERT (false); } - DCPOMATIC_ASSERT (_subtitle_reel != _reels.end()); + DCPOMATIC_ASSERT (*reel != _reels.end()); + while ((*reel)->period().to <= period.from) { + ++(*reel); + DCPOMATIC_ASSERT (*reel != _reels.end()); + } - _subtitle_reel->write (subs); + (*reel)->write (text, type, track, period); } void