X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Freel_writer.cc;h=81057185aea935c24c01ce96f20b53d2c97630b4;hb=c4403784febdbdd42e9c32e67fadb147f11fe566;hp=f9e3471a8a8d8a8cc40d1ba0e59ac45721f17ae3;hpb=0a5e92450ae992e9ed24026dd60ae351d0a3e60b;p=dcpomatic.git diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc index f9e3471a8..81057185a 100644 --- a/src/lib/reel_writer.cc +++ b/src/lib/reel_writer.cc @@ -23,6 +23,7 @@ #include "cross.h" #include "job.h" #include "log.h" +#include "dcpomatic_log.h" #include "digester.h" #include "font.h" #include "compose.hpp" @@ -38,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -49,19 +51,16 @@ #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_WARNING_NC(...) _film->log()->log (__VA_ARGS__, LogEntry::TYPE_WARNING); -#define LOG_ERROR(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_ERROR); - using std::list; using std::string; using std::cout; +using std::map; using boost::shared_ptr; using boost::optional; using boost::dynamic_pointer_cast; using dcp::Data; using dcp::raw_convert; +using namespace dcpomatic; int const ReelWriter::_info_size = 48; @@ -146,9 +145,9 @@ ReelWriter::write_frame_info (Frame frame, Eyes eyes, dcp::FrameInfo info) const throw OpenFileError (info_file, errno, read); } dcpomatic_fseek (file, frame_info_position (frame, eyes), SEEK_SET); - fwrite (&info.offset, sizeof (info.offset), 1, file); - fwrite (&info.size, sizeof (info.size), 1, file); - fwrite (info.hash.c_str(), 1, info.hash.size(), file); + checked_fwrite (&info.offset, sizeof (info.offset), file, info_file); + checked_fwrite (&info.size, sizeof (info.size), file, info_file); + checked_fwrite (info.hash.c_str(), info.hash.size(), file, info_file); fclose (file); } @@ -157,11 +156,11 @@ ReelWriter::read_frame_info (FILE* file, Frame frame, Eyes eyes) const { dcp::FrameInfo info; dcpomatic_fseek (file, frame_info_position (frame, eyes), SEEK_SET); - fread (&info.offset, sizeof (info.offset), 1, file); - fread (&info.size, sizeof (info.size), 1, file); + checked_fread (&info.offset, sizeof(info.offset), file, _film->info_file(_period)); + checked_fread (&info.size, sizeof(info.size), file, _film->info_file(_period)); char hash_buffer[33]; - fread (hash_buffer, 1, 32, file); + checked_fread (hash_buffer, 32, file, _film->info_file(_period)); hash_buffer[32] = '\0'; info.hash = hash_buffer; @@ -334,8 +333,8 @@ ReelWriter::finish () } template -void -maybe_add_captions ( +shared_ptr +maybe_add_text ( shared_ptr asset, int64_t picture_duration, shared_ptr reel, @@ -350,7 +349,6 @@ maybe_add_captions ( shared_ptr reel_asset; if (asset) { - boost::filesystem::path liberation_normal; try { liberation_normal = shared_path() / "LiberationSans-Regular.ttf"; @@ -366,9 +364,9 @@ maybe_add_captions ( liberation_normal = "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf"; } - /* Add all the fonts to the subtitle content */ + /* Add the font to the subtitle content */ BOOST_FOREACH (shared_ptr j, fonts) { - asset->add_font (j->id(), j->file(FontFiles::NORMAL).get_value_or(liberation_normal)); + asset->add_font (j->id(), j->file().get_value_or(liberation_normal)); } if (dynamic_pointer_cast (asset)) { @@ -376,7 +374,6 @@ maybe_add_captions ( boost::filesystem::create_directories (directory); asset->write (directory / ("sub_" + asset->id() + ".xml")); } else { - /* All our assets should be the same length; use the picture asset length here as a reference to set the subtitle one. We'll use the duration rather than the intrinsic duration; we don't care if the picture asset has been trimmed, we're @@ -412,14 +409,16 @@ maybe_add_captions ( } if (reel_asset) { - if (reel_asset->duration() != period_duration) { + if (reel_asset->actual_duration() != period_duration) { throw ProgrammingError ( __FILE__, __LINE__, - String::compose ("%1 vs %2", reel_asset->duration(), period_duration) + String::compose ("%1 vs %2", reel_asset->actual_duration(), period_duration) ); } reel->add (reel_asset); } + + return reel_asset; } shared_ptr @@ -462,7 +461,7 @@ ReelWriter::create_reel (list const & refs, listduration() != period_duration) { throw ProgrammingError ( __FILE__, __LINE__, - String::compose ("%1 vs %2", reel_picture_asset->duration(), period_duration) + String::compose ("%1 vs %2", reel_picture_asset->actual_duration(), period_duration) ); } reel->add (reel_picture_asset); @@ -492,24 +491,49 @@ ReelWriter::create_reel (list const & refs, listduration() != period_duration) { + if (reel_sound_asset->actual_duration() != period_duration) { LOG_ERROR ( "Reel sound asset has length %1 but reel period is %2", - reel_sound_asset->duration(), + reel_sound_asset->actual_duration(), period_duration ); - if (reel_sound_asset->duration() != period_duration) { + if (reel_sound_asset->actual_duration() != period_duration) { throw ProgrammingError ( __FILE__, __LINE__, - String::compose ("%1 vs %2", reel_sound_asset->duration(), period_duration) + String::compose ("%1 vs %2", reel_sound_asset->actual_duration(), period_duration) ); } } reel->add (reel_sound_asset); - maybe_add_captions (_caption_asset[TEXT_OPEN_SUBTITLE], reel_picture_asset->duration(), reel, refs, fonts, _film, _period); - maybe_add_captions (_caption_asset[TEXT_CLOSED_CAPTION], reel_picture_asset->duration(), reel, refs, fonts, _film, _period); + maybe_add_text (_subtitle_asset, reel_picture_asset->actual_duration(), reel, refs, fonts, _film, _period); + for (map >::const_iterator i = _closed_caption_assets.begin(); i != _closed_caption_assets.end(); ++i) { + shared_ptr a = maybe_add_text ( + i->second, reel_picture_asset->actual_duration(), reel, refs, fonts, _film, _period + ); + a->set_annotation_text (i->first.name); + a->set_language (i->first.language); + } + + map markers = _film->markers (); + map reel_markers; + for (map::const_iterator i = markers.begin(); i != markers.end(); ++i) { + if (_period.contains(i->second)) { + reel_markers[i->first] = i->second; + } + } + + if (!reel_markers.empty ()) { + shared_ptr ma (new dcp::ReelMarkersAsset(dcp::Fraction(_film->video_frame_rate(), 1), 0)); + for (map::const_iterator i = reel_markers.begin(); i != reel_markers.end(); ++i) { + int h, m, s, f; + DCPTime relative = i->second - _period.from; + relative.split (_film->video_frame_rate(), h, m, s, f); + ma->set (i->first, dcp::Time(h, m, s, f, _film->video_frame_rate())); + } + reel->add (ma); + } return reel; } @@ -545,23 +569,42 @@ ReelWriter::write (shared_ptr audio) } void -ReelWriter::write (PlayerText subs, TextType type, DCPTimePeriod period) +ReelWriter::write (PlayerText subs, TextType type, optional track, DCPTimePeriod period) { - if (!_caption_asset[type]) { + shared_ptr asset; + + switch (type) { + case TEXT_OPEN_SUBTITLE: + asset = _subtitle_asset; + break; + case TEXT_CLOSED_CAPTION: + DCPOMATIC_ASSERT (track); + asset = _closed_caption_assets[*track]; + break; + default: + DCPOMATIC_ASSERT (false); + } + + if (!asset) { string lang = _film->subtitle_language (); - if (lang.empty ()) { - lang = "Unknown"; - } if (_film->interop ()) { shared_ptr s (new dcp::InteropSubtitleAsset ()); s->set_movie_title (_film->name ()); - s->set_language (lang); + if (type == TEXT_OPEN_SUBTITLE) { + s->set_language (lang.empty() ? "Unknown" : lang); + } else { + s->set_language (track->language); + } s->set_reel_number (raw_convert (_reel_index + 1)); - _caption_asset[type] = s; + asset = s; } else { shared_ptr s (new dcp::SMPTESubtitleAsset ()); s->set_content_title_text (_film->name ()); - s->set_language (lang); + if (type == TEXT_OPEN_SUBTITLE && !lang.empty()) { + s->set_language (lang); + } else { + s->set_language (track->language); + } s->set_edit_rate (dcp::Fraction (_film->video_frame_rate (), 1)); s->set_reel_number (_reel_index + 1); s->set_time_code_rate (_film->video_frame_rate ()); @@ -569,19 +612,31 @@ ReelWriter::write (PlayerText subs, TextType type, DCPTimePeriod period) if (_film->encrypted ()) { s->set_key (_film->key ()); } - _caption_asset[type] = s; + asset = s; } } + switch (type) { + case TEXT_OPEN_SUBTITLE: + _subtitle_asset = asset; + break; + case TEXT_CLOSED_CAPTION: + DCPOMATIC_ASSERT (track); + _closed_caption_assets[*track] = asset; + break; + default: + DCPOMATIC_ASSERT (false); + } + BOOST_FOREACH (StringText i, subs.string) { /* XXX: couldn't / shouldn't we use period here rather than getting time from the subtitle? */ i.set_in (i.in() - dcp::Time (_period.from.seconds(), i.in().tcr)); i.set_out (i.out() - dcp::Time (_period.from.seconds(), i.out().tcr)); - _caption_asset[type]->add (shared_ptr(new dcp::SubtitleString(i))); + asset->add (shared_ptr(new dcp::SubtitleString(i))); } BOOST_FOREACH (BitmapText i, subs.bitmap) { - _caption_asset[type]->add ( + asset->add ( shared_ptr( new dcp::SubtitleImage( i.image->as_png(),