Change how video timing is done.
[dcpomatic.git] / src / lib / util.cc
index d020ba13d45250c00b009c251aaa95144a6cb607..6a353818cb2e26d42e74c1289826df44543b5205 100644 (file)
@@ -34,6 +34,7 @@
 #include "cross.h"
 #include "crypto.h"
 #include "dcp_content_type.h"
+#include "dcpomatic_log.h"
 #include "digester.h"
 #include "exceptions.h"
 #include "ffmpeg_image_proxy.h"
@@ -410,8 +411,8 @@ LIBDCP_ENABLE_WARNINGS
                optional<string>(), false, false, false, dcp::Colour(), 42, 1, dcp::Time(), dcp::Time(), 0, dcp::HAlign::CENTER, 0, dcp::VAlign::CENTER, dcp::Direction::LTR,
                "Hello dolly", dcp::Effect::NONE, dcp::Colour(), dcp::Time(), dcp::Time(), 0
                );
-       subs.push_back (StringText(ss, 0));
-       render_text (subs, list<shared_ptr<Font>>(), dcp::Size(640, 480), DCPTime(), 24);
+       subs.push_back (StringText(ss, 0, {}, dcp::Standard::SMPTE));
+       render_text (subs, dcp::Size(640, 480), DCPTime(), 24);
 #endif
 
        Ratio::setup_ratios ();
@@ -424,6 +425,8 @@ LIBDCP_ENABLE_WARNINGS
        curl_global_init (CURL_GLOBAL_ALL);
 
        ui_thread = boost::this_thread::get_id ();
+
+       capture_asdcp_logs ();
 }
 
 #ifdef DCPOMATIC_WINDOWS
@@ -591,14 +594,14 @@ short_audio_channel_name (int c)
                _("Rs"),
                _("HI"),
                _("VI"),
-               _("Lc"),
-               _("Rc"),
+               _("9"),
+               _("10"),
                _("BsL"),
                _("BsR"),
                _("DBP"),
                _("DBS"),
                _("Sign"),
-               ""
+               _("16")
        };
 
        return channels[c];
@@ -705,44 +708,47 @@ split_get_request (string url)
        return r;
 }
 
+
+static
 string
-video_asset_filename (shared_ptr<dcp::PictureAsset> asset, int reel_index, int reel_count, optional<string> summary)
+asset_filename (shared_ptr<dcp::Asset> asset, string type, int reel_index, int reel_count, optional<string> summary, string extension)
 {
        dcp::NameFormat::Map values;
-       values['t'] = "j2c";
-       values['r'] = raw_convert<string> (reel_index + 1);
-       values['n'] = raw_convert<string> (reel_count);
+       values['t'] = type;
+       values['r'] = raw_convert<string>(reel_index + 1);
+       values['n'] = raw_convert<string>(reel_count);
        if (summary) {
-               values['c'] = careful_string_filter (summary.get());
+               values['c'] = careful_string_filter(summary.get());
        }
-       return Config::instance()->dcp_asset_filename_format().get(values, "_" + asset->id() + ".mxf");
+       return Config::instance()->dcp_asset_filename_format().get(values, "_" + asset->id() + extension);
+}
+
+
+string
+video_asset_filename (shared_ptr<dcp::PictureAsset> asset, int reel_index, int reel_count, optional<string> summary)
+{
+       return asset_filename(asset, "j2c", reel_index, reel_count, summary, ".mxf");
 }
 
+
 string
 audio_asset_filename (shared_ptr<dcp::SoundAsset> asset, int reel_index, int reel_count, optional<string> summary)
 {
-       dcp::NameFormat::Map values;
-       values['t'] = "pcm";
-       values['r'] = raw_convert<string> (reel_index + 1);
-       values['n'] = raw_convert<string> (reel_count);
-       if (summary) {
-               values['c'] = careful_string_filter (summary.get());
-       }
-       return Config::instance()->dcp_asset_filename_format().get(values, "_" + asset->id() + ".mxf");
+       return asset_filename(asset, "pcm", reel_index, reel_count, summary, ".mxf");
+}
+
+
+string
+subtitle_asset_filename (shared_ptr<dcp::SubtitleAsset> asset, int reel_index, int reel_count, optional<string> summary, string extension)
+{
+       return asset_filename(asset, "sub", reel_index, reel_count, summary, extension);
 }
 
 
 string
 atmos_asset_filename (shared_ptr<dcp::AtmosAsset> asset, int reel_index, int reel_count, optional<string> summary)
 {
-       dcp::NameFormat::Map values;
-       values['t'] = "atmos";
-       values['r'] = raw_convert<string> (reel_index + 1);
-       values['n'] = raw_convert<string> (reel_count);
-       if (summary) {
-               values['c'] = careful_string_filter (summary.get());
-       }
-       return Config::instance()->dcp_asset_filename_format().get(values, "_" + asset->id() + ".mxf");
+       return asset_filename(asset, "atmos", reel_index, reel_count, summary, ".mxf");
 }
 
 
@@ -767,19 +773,32 @@ careful_string_filter (string s)
        */
 
        /* First transliterate using libicu to try to remove accents in a "nice" way */
-       auto icu_utf16 = icu::UnicodeString::fromUTF8(icu::StringPiece(s));
+       auto transliterated = icu::UnicodeString::fromUTF8(icu::StringPiece(s));
        auto status = U_ZERO_ERROR;
        auto transliterator = icu::Transliterator::createInstance("NFD; [:M:] Remove; NFC", UTRANS_FORWARD, status);
-       transliterator->transliterate(icu_utf16);
-       s.clear ();
-       icu_utf16.toUTF8String(s);
+       transliterator->transliterate(transliterated);
+
+       /* Some things are missed by ICU's transliterator */
+       std::map<wchar_t, wchar_t> replacements = {
+               { L'ł',         L'l' },
+               { L'Ł',         L'L' }
+       };
+
+       icu::UnicodeString transliterated_more;
+       for (int i = 0; i < transliterated.length(); ++i) {
+               auto replacement = replacements.find(transliterated[i]);
+               if (replacement != replacements.end()) {
+                       transliterated_more += replacement->second;
+               } else {
+                       transliterated_more += transliterated[i];
+               }
+       }
 
        /* Then remove anything that's not in a very limited character set */
-       wstring ws = boost::locale::conv::utf_to_utf<wchar_t>(s);
-       string out;
-       string const allowed = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_%.+";
-       for (size_t i = 0; i < ws.size(); ++i) {
-               wchar_t c = ws[i];
+       wstring out;
+       wstring const allowed = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_%.+";
+       for (int i = 0; i < transliterated_more.length(); ++i) {
+               wchar_t c = transliterated_more[i];
                if (allowed.find(c) != string::npos) {
                        out += c;
                }
@@ -854,16 +873,6 @@ remap (shared_ptr<const AudioBuffers> input, int output_channels, AudioMapping m
        return mapped;
 }
 
-Eyes
-increment_eyes (Eyes e)
-{
-       if (e == Eyes::LEFT) {
-               return Eyes::RIGHT;
-       }
-
-       return Eyes::LEFT;
-}
-
 
 size_t
 utf8_strlen (string s)
@@ -1102,6 +1111,9 @@ default_font_file ()
        if (!boost::filesystem::exists(liberation_normal)) {
                liberation_normal = "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf";
        }
+       if (!boost::filesystem::exists(liberation_normal)) {
+               liberation_normal = "/usr/share/fonts/liberation-sans/LiberationSans-Regular.ttf";
+       }
 
        return liberation_normal;
 }
@@ -1132,3 +1144,36 @@ start_of_thread (string)
 }
 #endif
 
+
+class LogSink : public Kumu::ILogSink
+{
+public:
+       LogSink () {}
+       LogSink (LogSink const&) = delete;
+       LogSink& operator= (LogSink const&) = delete;
+
+       void WriteEntry(const Kumu::LogEntry& entry) override {
+               Kumu::AutoMutex L(m_lock);
+               WriteEntryToListeners(entry);
+               if (entry.TestFilter(m_filter)) {
+                       string buffer;
+                       entry.CreateStringWithOptions(buffer, m_options);
+                       LOG_GENERAL("asdcplib: %1", buffer);
+               }
+       }
+};
+
+
+void
+capture_asdcp_logs ()
+{
+       static LogSink log_sink;
+       Kumu::SetDefaultLogSink(&log_sink);
+}
+
+
+string
+error_details(boost::system::error_code ec)
+{
+       return String::compose("%1:%2:%3", ec.category().name(), ec.value(), ec.message());
+}