X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Futil.cc;h=5eba8d73a0f214f07339998c9a6c4543f5f86e2f;hb=05d90a3edda9c1f5e7499f0ce7b6617fe46ac54d;hp=38451e9314e9bbd67da2afeb9a226115727ead83;hpb=00b60f52add041a36fa62118baf4b5ac78993980;p=dcpomatic.git diff --git a/src/lib/util.cc b/src/lib/util.cc index 38451e931..5eba8d73a 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -36,6 +36,7 @@ #include "digester.h" #include "audio_processor.h" #include "compose.hpp" +#include "audio_buffers.h" #include #include #include @@ -44,12 +45,10 @@ #include extern "C" { #include +#include #include } #include -#ifdef DCPOMATIC_GRAPHICS_MAGICK -#include -#endif #include #include #include @@ -88,6 +87,7 @@ using std::pair; using std::cout; using std::bad_alloc; using std::set_terminate; +using std::make_pair; using boost::shared_ptr; using boost::thread; using boost::optional; @@ -101,6 +101,7 @@ using dcp::locale_convert; * in during App::onInit(). */ string program_name; +bool is_batch_converter = false; static boost::thread::id ui_thread; static boost::filesystem::path backtrace_file; @@ -124,6 +125,22 @@ seconds_to_hms (int s) return buffer; } +string +time_to_hmsf (DCPTime time, Frame rate) +{ + Frame f = time.frames_round (rate); + int s = f / rate; + f -= (s * rate); + int m = s / 60; + s -= m * 60; + int h = m / 60; + m -= h * 60; + + char buffer[64]; + snprintf (buffer, sizeof(buffer), "%d:%02d:%02d.%d", h, m, s, static_cast(f)); + return buffer; +} + /** @param s Number of seconds. * @return String containing an approximate description of s (e.g. "about 2 hours") */ @@ -137,18 +154,27 @@ seconds_to_approximate_hms (int s) string ap; - bool const hours = h > 0; - bool const minutes = h < 6 && m > 0; - bool const seconds = h == 0 && m < 10 && s > 0; + bool hours = h > 0; + bool minutes = h < 6 && m > 0; + bool seconds = h == 0 && m < 10 && s > 0; - if (hours) { - if (m > 30 && !minutes) { - /// TRANSLATORS: h here is an abbreviation for hours - ap += locale_convert(h + 1) + _("h"); - } else { - /// TRANSLATORS: h here is an abbreviation for hours - ap += locale_convert(h) + _("h"); + if (m > 30 && !minutes) { + /* round up the hours */ + ++h; + } + if (s > 30 && !seconds) { + /* round up the minutes */ + ++m; + if (m == 60) { + m = 0; + minutes = false; + ++h; } + } + + if (hours) { + /// TRANSLATORS: h here is an abbreviation for hours + ap += locale_convert(h) + _("h"); if (minutes || seconds) { ap += N_(" "); @@ -156,14 +182,8 @@ seconds_to_approximate_hms (int s) } if (minutes) { - /* Minutes */ - if (s > 30 && !seconds) { - /// TRANSLATORS: m here is an abbreviation for minutes - ap += locale_convert(m + 1) + _("m"); - } else { - /// TRANSLATORS: m here is an abbreviation for minutes - ap += locale_convert(m) + _("m"); - } + /// TRANSLATORS: m here is an abbreviation for minutes + ap += locale_convert(m) + _("m"); if (seconds) { ap += N_(" "); @@ -322,14 +342,15 @@ dcpomatic_setup () SetUnhandledExceptionFilter(exception_handler); #endif + av_register_all (); avfilter_register_all (); #ifdef DCPOMATIC_OSX - /* Add our lib directory to the libltdl search path so that + /* Add our library directory to the libltdl search path so that xmlsec can find xmlsec1-openssl. */ boost::filesystem::path lib = app_contents (); - lib /= "lib"; + lib /= "Frameworks"; setenv ("LTDL_LIBRARY_PATH", lib.c_str (), 1); #endif @@ -348,10 +369,6 @@ dcpomatic_setup () curl_global_init (CURL_GLOBAL_ALL); -#ifdef DCPOMATIC_GRAPHICS_MAGICK - Magick::InitializeMagick (0); -#endif - ui_thread = boost::this_thread::get_id (); } @@ -427,7 +444,7 @@ digest_head_tail (vector files, boost::uintmax_t size) } boost::uintmax_t this_time = min (to_do, boost::filesystem::file_size (files[i])); - fread (p, 1, this_time, f); + checked_fread (p, this_time, f, files[i]); p += this_time; to_do -= this_time; fclose (f); @@ -448,7 +465,7 @@ digest_head_tail (vector files, boost::uintmax_t size) boost::uintmax_t this_time = min (to_do, boost::filesystem::file_size (files[i])); dcpomatic_fseek (f, -this_time, SEEK_END); - fread (p, 1, this_time, f); + checked_fread (p, this_time, f, files[i]); p += this_time; to_do -= this_time; fclose (f); @@ -462,7 +479,7 @@ digest_head_tail (vector files, boost::uintmax_t size) /** Round a number up to the nearest multiple of another number. * @param c Index. - * @param s Array of numbers to round, indexed by c. + * @param stride Array of numbers to round, indexed by c. * @param t Multiple to round to. * @return Rounded number. */ @@ -533,8 +550,8 @@ short_audio_channel_name (int c) _("BsR"), _("DBP"), _("DBS"), - _(""), - _("") + "", + "" }; return channels[c]; @@ -553,10 +570,23 @@ valid_image_file (boost::filesystem::path f) return ( ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".bmp" || ext == ".tga" || ext == ".dpx" || - ext == ".j2c" || ext == ".j2k" || ext == ".jp2" + ext == ".j2c" || ext == ".j2k" || ext == ".jp2" || ext == ".exr" || + ext == ".jpf" ); } +bool +valid_sound_file (boost::filesystem::path f) +{ + if (boost::starts_with (f.leaf().string(), "._")) { + return false; + } + + string ext = f.extension().string(); + transform (ext.begin(), ext.end(), ext.begin(), ::tolower); + return (ext == ".wav" || ext == ".mp3" || ext == ".aif" || ext == ".aiff"); +} + bool valid_j2k_file (boost::filesystem::path f) { @@ -646,7 +676,7 @@ video_asset_filename (shared_ptr asset, int reel_index, int r values['r'] = raw_convert (reel_index + 1); values['n'] = raw_convert (reel_count); if (summary) { - values['c'] = summary.get(); + values['c'] = careful_string_filter (summary.get()); } return Config::instance()->dcp_asset_filename_format().get(values, "_" + asset->id() + ".mxf"); } @@ -659,7 +689,7 @@ audio_asset_filename (shared_ptr asset, int reel_index, int ree values['r'] = raw_convert (reel_index + 1); values['n'] = raw_convert (reel_count); if (summary) { - values['c'] = summary.get(); + values['c'] = careful_string_filter (summary.get()); } return Config::instance()->dcp_asset_filename_format().get(values, "_" + asset->id() + ".mxf"); } @@ -675,3 +705,93 @@ relaxed_string_to_float (string s) return lexical_cast (s); } } + +string +careful_string_filter (string s) +{ + /* Filter out `bad' characters which `may' cause problems with some systems (either for DCP name or filename). + There's no apparent list of what really is allowed, so this is a guess. + Safety first and all that. + */ + + string out; + string const allowed = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_%.+"; + for (size_t i = 0; i < s.size(); ++i) { + if (allowed.find (s[i]) != string::npos) { + out += s[i]; + } + } + + return out; +} + +/** @param mapped List of mapped audio channels from a Film. + * @param channels Total number of channels in the Film. + * @return First: number of non-LFE channels, second: number of LFE channels. + */ +pair +audio_channel_types (list mapped, int channels) +{ + int non_lfe = 0; + int lfe = 0; + + BOOST_FOREACH (int i, mapped) { + if (i >= channels) { + /* This channel is mapped but is not included in the DCP */ + continue; + } + + if (static_cast (i) == dcp::LFE) { + ++lfe; + } else { + ++non_lfe; + } + } + + return make_pair (non_lfe, lfe); +} + +shared_ptr +remap (shared_ptr input, int output_channels, AudioMapping map) +{ + shared_ptr mapped (new AudioBuffers (output_channels, input->frames())); + mapped->make_silent (); + + for (int i = 0; i < map.input_channels(); ++i) { + for (int j = 0; j < mapped->channels(); ++j) { + if (map.get (i, static_cast (j)) > 0) { + mapped->accumulate_channel ( + input.get(), + i, + static_cast (j), + map.get (i, static_cast (j)) + ); + } + } + } + + return mapped; +} + +Eyes +increment_eyes (Eyes e) +{ + if (e == EYES_LEFT) { + return EYES_RIGHT; + } + + return EYES_LEFT; +} + +void +checked_fread (void* ptr, size_t size, FILE* stream, boost::filesystem::path path) +{ + size_t N = fread (ptr, 1, size, stream); + if (N != size) { + if (ferror(stream)) { + throw FileError (String::compose("fread error %1", errno), path); + } else { + throw FileError ("Unexpected short read", path); + } + } +}