X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Ffilm.cc;h=28017669bd035afa2e7cb00327c23c27888e62da;hb=b1dc9c3a2f7e55c9afc5bf2d5b465371b048e14f;hp=7d319fc1e02e6882e8638a3c3f51cb1bc87f97a5;hpb=6f344b876689a1234a5eb75041882f06f5d9fe5c;p=dcpomatic.git diff --git a/src/lib/film.cc b/src/lib/film.cc index 7d319fc1e..28017669b 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -1,19 +1,20 @@ /* Copyright (C) 2012-2016 Carl Hetherington - This program is free software; you can redistribute it and/or modify + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + DCP-o-matic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with DCP-o-matic. If not, see . */ @@ -37,11 +38,10 @@ #include "dcp_content_type.h" #include "ratio.h" #include "cross.h" -#include "safe_stringstream.h" #include "environment_info.h" #include "raw_convert.h" #include "audio_processor.h" -#include "md5_digester.h" +#include "digester.h" #include "compose.hpp" #include "screen.h" #include "audio_content.h" @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -107,8 +108,15 @@ using boost::is_any_of; * * 32 -> 33 * Changed to in FFmpegSubtitleStream + * 33 -> 34 + * Content only contains audio/subtitle-related tags if those things + * are present. + * 34 -> 35 + * VideoFrameType in VideoContent is a string rather than an integer. + * 35 -> 36 + * EffectColour rather than OutlineColour in Subtitle. */ -int const Film::current_state_version = 33; +int const Film::current_state_version = 36; /** Construct a Film object in a given directory. * @@ -126,7 +134,7 @@ Film::Film (boost::filesystem::path dir, bool log) , _j2k_bandwidth (Config::instance()->default_j2k_bandwidth ()) , _isdcf_metadata (Config::instance()->default_isdcf_metadata ()) , _video_frame_rate (24) - , _audio_channels (6) + , _audio_channels (Config::instance()->default_dcp_audio_channels ()) , _three_d (false) , _sequence (true) , _interop (Config::instance()->default_interop ()) @@ -188,32 +196,29 @@ Film::video_identifier () const { DCPOMATIC_ASSERT (container ()); - SafeStringStream s; - s.imbue (std::locale::classic ()); - - s << container()->id() - << "_" << resolution_to_string (_resolution) - << "_" << _playlist->video_identifier() - << "_" << _video_frame_rate - << "_" << j2k_bandwidth(); + string s = container()->id() + + "_" + resolution_to_string (_resolution) + + "_" + _playlist->video_identifier() + + "_" + raw_convert(_video_frame_rate) + + "_" + raw_convert(j2k_bandwidth()); if (encrypted ()) { - s << "_E"; + s += "_E"; } else { - s << "_P"; + s += "_P"; } if (_interop) { - s << "_I"; + s += "_I"; } else { - s << "_S"; + s += "_S"; } if (_three_d) { - s << "_3D"; + s += "_3D"; } - return s.str (); + return s; } /** @return The file to write video frame info to */ @@ -243,15 +248,14 @@ Film::audio_analysis_path (shared_ptr playlist) const { boost::filesystem::path p = dir ("analysis"); - MD5Digester digester; + Digester digester; BOOST_FOREACH (shared_ptr i, playlist->content ()) { - shared_ptr ac = dynamic_pointer_cast (i); - if (!ac) { + if (!i->audio) { continue; } - digester.add (ac->digest ()); - digester.add (ac->audio_mapping().digest ()); + digester.add (i->digest ()); + digester.add (i->audio->mapping().digest ()); if (playlist->content().size() != 1) { /* Analyses should be considered equal regardless of gain if they were made from just one piece of content. This @@ -259,7 +263,7 @@ Film::audio_analysis_path (shared_ptr playlist) const analysis at the plotting stage rather than having to recompute it. */ - digester.add (ac->audio_gain ()); + digester.add (i->audio->gain ()); } } @@ -505,9 +509,8 @@ Film::mapped_audio_channels () const } } else { BOOST_FOREACH (shared_ptr i, content ()) { - shared_ptr ac = dynamic_pointer_cast (i); - if (ac) { - list c = ac->audio_mapping().mapped_output_channels (); + if (i->audio) { + list c = i->audio->mapping().mapped_output_channels (); copy (c.begin(), c.end(), back_inserter (mapped)); } } @@ -523,7 +526,7 @@ Film::mapped_audio_channels () const string Film::isdcf_name (bool if_created_now) const { - SafeStringStream d; + string d; string raw_name = name (); @@ -566,49 +569,49 @@ Film::isdcf_name (bool if_created_now) const fixed_name = fixed_name.substr (0, 14); } - d << fixed_name; + d += fixed_name; if (dcp_content_type()) { - d << "_" << dcp_content_type()->isdcf_name(); - d << "-" << isdcf_metadata().content_version; + d += "_" + dcp_content_type()->isdcf_name(); + d += "-" + raw_convert(isdcf_metadata().content_version); } ISDCFMetadata const dm = isdcf_metadata (); if (dm.temp_version) { - d << "-Temp"; + d += "-Temp"; } if (dm.pre_release) { - d << "-Pre"; + d += "-Pre"; } if (dm.red_band) { - d << "-RedBand"; + d += "-RedBand"; } if (!dm.chain.empty ()) { - d << "-" << dm.chain; + d += "-" + dm.chain; } if (three_d ()) { - d << "-3D"; + d += "-3D"; } if (dm.two_d_version_of_three_d) { - d << "-2D"; + d += "-2D"; } if (!dm.mastered_luminance.empty ()) { - d << "-" << dm.mastered_luminance; + d += "-" + dm.mastered_luminance; } if (video_frame_rate() != 24) { - d << "-" << video_frame_rate(); + d += "-" + raw_convert(video_frame_rate()); } if (container()) { - d << "_" << container()->isdcf_name(); + d += "_" + container()->isdcf_name(); } /* XXX: this uses the first bit of content only */ @@ -622,29 +625,28 @@ Film::isdcf_name (bool if_created_now) const if (i->video->scale().ratio ()) { content_ratio = i->video->scale().ratio (); } else { - content_ratio = Ratio::from_ratio (i->video->video_size().ratio ()); + content_ratio = Ratio::from_ratio (i->video->size().ratio ()); } break; } } if (content_ratio && content_ratio != container()) { - d << "-" << content_ratio->isdcf_name(); + d += "-" + content_ratio->isdcf_name(); } } if (!dm.audio_language.empty ()) { - d << "_" << dm.audio_language; + d += "_" + dm.audio_language; if (!dm.subtitle_language.empty()) { bool burnt_in = true; BOOST_FOREACH (shared_ptr i, content ()) { - shared_ptr sc = dynamic_pointer_cast (i); - if (!sc) { + if (!i->subtitle) { continue; } - if (sc->use_subtitles() && !sc->burn_subtitles()) { + if (i->subtitle->use() && !i->subtitle->burn()) { burnt_in = false; } } @@ -656,18 +658,18 @@ Film::isdcf_name (bool if_created_now) const transform (language.begin(), language.end(), language.begin(), ::toupper); } - d << "-" << language; + d += "-" + language; } else { - d << "-XX"; + d += "-XX"; } } if (!dm.territory.empty ()) { - d << "_" << dm.territory; + d += "_" + dm.territory; if (dm.rating.empty ()) { - d << "-NR"; + d += "-NR"; } else { - d << "-" << dm.rating; + d += "-" + dm.rating; } } @@ -690,35 +692,35 @@ Film::isdcf_name (bool if_created_now) const } if (non_lfe) { - d << "_" << non_lfe << lfe; + d += String::compose("_%1%2", non_lfe, lfe); } /* XXX: HI/VI */ - d << "_" << resolution_to_string (_resolution); + d += "_" + resolution_to_string (_resolution); if (!dm.studio.empty ()) { - d << "_" << dm.studio; + d += "_" + dm.studio; } if (if_created_now) { - d << "_" << boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ()); + d += "_" + boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ()); } else { - d << "_" << boost::gregorian::to_iso_string (_isdcf_date); + d += "_" + boost::gregorian::to_iso_string (_isdcf_date); } if (!dm.facility.empty ()) { - d << "_" << dm.facility; + d += "_" + dm.facility; } if (_interop) { - d << "_IOP"; + d += "_IOP"; } else { - d << "_SMPTE"; + d += "_SMPTE"; } if (three_d ()) { - d << "-3D"; + d += "-3D"; } bool vf = false; @@ -730,12 +732,12 @@ Film::isdcf_name (bool if_created_now) const } if (vf) { - d << "_VF"; + d += "_VF"; } else { - d << "_OV"; + d += "_OV"; } - return d.str (); + return d; } /** @return name to give the DCP */ @@ -890,7 +892,7 @@ Film::signal_changed (Property p) switch (p) { case Film::CONTENT: - set_video_frame_rate (_playlist->best_dcp_frame_rate ()); + set_video_frame_rate (_playlist->best_video_frame_rate ()); break; case Film::VIDEO_FRAME_RATE: case Film::SEQUENCE: @@ -916,23 +918,23 @@ Film::j2c_path (int reel, Frame frame, Eyes eyes, bool tmp) const p /= "j2c"; p /= video_identifier (); - SafeStringStream s; - s.width (8); - s << setfill('0') << reel << "_" << frame; + char buffer[256]; + snprintf(buffer, sizeof(buffer), "%08d_%08" PRId64, reel, frame); + string s (buffer); if (eyes == EYES_LEFT) { - s << ".L"; + s += ".L"; } else if (eyes == EYES_RIGHT) { - s << ".R"; + s += ".R"; } - s << ".j2c"; + s += ".j2c"; if (tmp) { - s << ".tmp"; + s += ".tmp"; } - p /= s.str(); + p /= s; return file (p); } @@ -1033,7 +1035,7 @@ Film::maybe_add_content (weak_ptr j, weak_ptr c) } add_content (content); - if (Config::instance()->automatic_audio_analysis() && dynamic_pointer_cast (content)) { + if (Config::instance()->automatic_audio_analysis() && content->audio) { shared_ptr playlist (new Playlist); playlist->add (content); boost::signals2::connection c; @@ -1050,7 +1052,7 @@ Film::add_content (shared_ptr c) /* Add {video,subtitle} content after any existing {video,subtitle} content */ if (c->video) { c->set_position (_playlist->video_end ()); - } else if (dynamic_pointer_cast (c)) { + } else if (c->subtitle) { c->set_position (_playlist->subtitle_end ()); } @@ -1085,7 +1087,7 @@ Film::length () const int Film::best_video_frame_rate () const { - return _playlist->best_dcp_frame_rate (); + return _playlist->best_video_frame_rate (); } FrameRateChange @@ -1099,9 +1101,9 @@ Film::playlist_content_changed (weak_ptr c, int p, bool frequent) { _dirty = true; - if (p == VideoContentProperty::VIDEO_FRAME_RATE) { - set_video_frame_rate (_playlist->best_dcp_frame_rate ()); - } else if (p == AudioContentProperty::AUDIO_STREAMS) { + if (p == ContentProperty::VIDEO_FRAME_RATE) { + set_video_frame_rate (_playlist->best_video_frame_rate ()); + } else if (p == AudioContentProperty::STREAMS) { signal_changed (NAME); } @@ -1125,8 +1127,7 @@ int Film::audio_frame_rate () const { BOOST_FOREACH (shared_ptr i, content ()) { - shared_ptr a = dynamic_pointer_cast (i); - if (a && a->has_rate_above_48k ()) { + if (i->audio && i->audio->has_rate_above_48k ()) { return 96000; } } @@ -1271,9 +1272,8 @@ Film::subtitle_language () const ContentList cl = content (); BOOST_FOREACH (shared_ptr& c, cl) { - shared_ptr sc = dynamic_pointer_cast (c); - if (sc) { - languages.insert (sc->subtitle_language ()); + if (c->subtitle) { + languages.insert (c->subtitle->language ()); } } @@ -1291,18 +1291,44 @@ Film::subtitle_language () const /** Change the gains of the supplied AudioMapping to make it a default * for this film. The defaults are guessed based on what processor (if any) - * is in use and the number of input channels. + * is in use, the number of input channels and any filename supplied. */ void -Film::make_audio_mapping_default (AudioMapping& mapping) const +Film::make_audio_mapping_default (AudioMapping& mapping, optional filename) const { + static string const regex[] = { + ".*[\\._-]L[\\._-].*", + ".*[\\._-]R[\\._-].*", + ".*[\\._-]C[\\._-].*", + ".*[\\._-]Lfe[\\._-].*", + ".*[\\._-]Ls[\\._-].*", + ".*[\\._-]Rs[\\._-].*" + }; + + static int const regexes = sizeof(regex) / sizeof(*regex); + if (audio_processor ()) { audio_processor()->make_audio_mapping_default (mapping); } else { mapping.make_zero (); if (mapping.input_channels() == 1) { - /* Mono -> Centre */ - mapping.set (0, static_cast (dcp::CENTRE), 1); + bool guessed = false; + + /* See if we can guess where this stream should go */ + if (filename) { + for (int i = 0; i < regexes; ++i) { + boost::regex e (regex[i], boost::regex::icase); + if (boost::regex_match (filename->string(), e) && i < mapping.output_channels()) { + mapping.set (0, i, 1); + guessed = true; + } + } + } + + if (!guessed) { + /* If we have no idea, just put it on centre */ + mapping.set (0, static_cast (dcp::CENTRE), 1); + } } else { /* 1:1 mapping */ for (int i = 0; i < min (mapping.input_channels(), mapping.output_channels()); ++i) { @@ -1377,7 +1403,6 @@ Film::reels () const { optional last_split; shared_ptr last_video; - ContentList cl = content (); BOOST_FOREACH (shared_ptr c, content ()) { if (c->video) { BOOST_FOREACH (DCPTime t, c->reel_split_points()) { @@ -1418,3 +1443,9 @@ Film::reels () const return p; } + +string +Film::content_summary (DCPTimePeriod period) const +{ + return _playlist->content_summary (period); +}