X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Futil.cc;h=ef203c2bdc82fae52119f0acef4b4d4c2ba27764;hb=8353a009aae1a604251c0160193c39741c2fa27c;hp=e2ce94dd9ea8f75eaf84a4841afe17298a99c211;hpb=f660fe3f1be97f373318806a77b3ce3fcd53cb73;p=dcpomatic.git diff --git a/src/lib/util.cc b/src/lib/util.cc index e2ce94dd9..ef203c2bd 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -39,11 +39,15 @@ #include #include #include +#ifdef DCPOMATIC_WINDOWS +#include +#endif #include #include #include #include #include +#include #include #include #include @@ -80,7 +84,6 @@ using std::endl; using std::vector; using std::hex; using std::setw; -using std::ifstream; using std::ios; using std::min; using std::max; @@ -89,8 +92,8 @@ using std::multimap; using std::istream; using std::numeric_limits; using std::pair; -using std::ofstream; using std::cout; +using std::streampos; using boost::shared_ptr; using boost::thread; using boost::lexical_cast; @@ -260,8 +263,11 @@ seconds (struct timeval t) LONG WINAPI exception_handler(struct _EXCEPTION_POINTERS *) { dbg::stack s; - ofstream f (backtrace_file.string().c_str()); - std::copy(s.begin(), s.end(), std::ostream_iterator(f, "\n")); + FILE* f = fopen_boost (backtrace_file, "w"); + for (dbg::stack::const_iterator i = s.begin(); i != s.end(); ++i) { + fprintf (f, "%p %s %d %s", i->instruction, i->function.c_str(), i->line, i->module.c_str()); + } + fclose (f); return EXCEPTION_CONTINUE_SEARCH; } #endif @@ -276,6 +282,21 @@ dcpomatic_setup () backtrace_file /= g_get_user_config_dir (); backtrace_file /= "backtrace.txt"; SetUnhandledExceptionFilter(exception_handler); + + /* Dark voodoo which, I think, gets boost::filesystem::path to + correctly convert UTF-8 strings to paths, and also paths + back to UTF-8 strings (on path::string()). + + After this, constructing boost::filesystem::paths from strings + converts from UTF-8 to UTF-16 inside the path. Then + path::string().c_str() gives UTF-8 and + path::c_str() gives UTF-16. + + This is all Windows-only. AFAICT Linux/OS X use UTF-8 everywhere, + so things are much simpler. + */ + std::locale::global (boost::locale::generator().generate ("")); + boost::filesystem::path::imbue (std::locale ()); #endif avfilter_register_all (); @@ -289,6 +310,7 @@ dcpomatic_setup () setenv ("LTDL_LIBRARY_PATH", lib.c_str (), 1); #endif + Pango::init (); libdcp::init (); Ratio::setup_ratios (); @@ -330,6 +352,8 @@ dcpomatic_setup_gettext_i18n (string lang) putenv (cmd); snprintf (cmd, sizeof(cmd), "LANG=%s", lang.c_str ()); putenv (cmd); + snprintf (cmd, sizeof(cmd), "LC_ALL=%s", lang.c_str ()); + putenv (cmd); } setlocale (LC_ALL, ""); @@ -386,83 +410,42 @@ md5_digest (void const * data, int size) return s.str (); } -/** @param file File name. - * @return MD5 digest of file's contents. - */ -string -md5_digest (boost::filesystem::path file) -{ - ifstream f (file.string().c_str(), std::ios::binary); - if (!f.good ()) { - throw OpenFileError (file.string()); - } - - f.seekg (0, std::ios::end); - int bytes = f.tellg (); - f.seekg (0, std::ios::beg); - - int const buffer_size = 64 * 1024; - char buffer[buffer_size]; - - MD5_CTX md5_context; - MD5_Init (&md5_context); - while (bytes > 0) { - int const t = min (bytes, buffer_size); - f.read (buffer, t); - MD5_Update (&md5_context, buffer, t); - bytes -= t; - } - - unsigned char digest[MD5_DIGEST_LENGTH]; - MD5_Final (digest, &md5_context); - - stringstream s; - for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) { - s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]); - } - - return s.str (); -} - /** @param job Optional job for which to report progress */ string -md5_digest_directory (boost::filesystem::path directory, shared_ptr job) +md5_digest (vector files, shared_ptr job) { - int const buffer_size = 64 * 1024; + boost::uintmax_t const buffer_size = 64 * 1024; char buffer[buffer_size]; MD5_CTX md5_context; MD5_Init (&md5_context); - int files = 0; - if (job) { - for (boost::filesystem::directory_iterator i(directory); i != boost::filesystem::directory_iterator(); ++i) { - ++files; - } + vector sizes; + for (size_t i = 0; i < files.size(); ++i) { + sizes.push_back (boost::filesystem::file_size (files[i])); } - int j = 0; - for (boost::filesystem::directory_iterator i(directory); i != boost::filesystem::directory_iterator(); ++i) { - ifstream f (i->path().string().c_str(), std::ios::binary); - if (!f.good ()) { - throw OpenFileError (i->path().string()); + for (size_t i = 0; i < files.size(); ++i) { + FILE* f = fopen_boost (files[i], "rb"); + if (!f) { + throw OpenFileError (files[i].string()); } - - f.seekg (0, std::ios::end); - int bytes = f.tellg (); - f.seekg (0, std::ios::beg); - while (bytes > 0) { - int const t = min (bytes, buffer_size); - f.read (buffer, t); + boost::uintmax_t const bytes = boost::filesystem::file_size (files[i]); + boost::uintmax_t remaining = bytes; + + while (remaining > 0) { + int const t = min (remaining, buffer_size); + fread (buffer, 1, t, f); MD5_Update (&md5_context, buffer, t); - bytes -= t; - } + remaining -= t; - if (job) { - job->set_progress (float (j) / files); - ++j; + if (job) { + job->set_progress ((float (i) + 1 - float(remaining) / bytes) / files.size ()); + } } + + fclose (f); } unsigned char digest[MD5_DIGEST_LENGTH]; @@ -560,7 +543,7 @@ Socket::connect (boost::asio::ip::tcp::endpoint endpoint) } while (ec == boost::asio::error::would_block); if (ec) { - throw NetworkError (ec.message ()); + throw NetworkError (String::compose (_("error during async_connect (%1)"), ec.value ())); } if (!_socket.is_open ()) { @@ -584,7 +567,7 @@ Socket::accept (int port) _acceptor = 0; if (ec) { - throw NetworkError (ec.message ()); + throw NetworkError (String::compose (_("error during async_accept (%1)"), ec.value ())); } } @@ -605,7 +588,7 @@ Socket::write (uint8_t const * data, int size) } while (ec == boost::asio::error::would_block); if (ec) { - throw NetworkError (ec.message ()); + throw NetworkError (String::compose (_("error during async_write (%1)"), ec.value ())); } } @@ -633,7 +616,7 @@ Socket::read (uint8_t* data, int size) } while (ec == boost::asio::error::would_block); if (ec) { - throw NetworkError (ec.message ()); + throw NetworkError (String::compose (_("error during async_read (%1)"), ec.value ())); } } @@ -768,7 +751,7 @@ ensure_ui_thread () * @return Equivalent number of audio frames for `v'. */ int64_t -video_frames_to_audio_frames (VideoContent::Frame v, float audio_sample_rate, float frames_per_second) +video_frames_to_audio_frames (VideoFrame v, float audio_sample_rate, float frames_per_second) { return ((int64_t) v * audio_sample_rate / frames_per_second); } @@ -793,7 +776,7 @@ audio_channel_name (int c) return channels[c]; } -FrameRateConversion::FrameRateConversion (float source, int dcp) +FrameRateChange::FrameRateChange (float source, int dcp) : skip (false) , repeat (1) , change_speed (false) @@ -811,7 +794,8 @@ FrameRateConversion::FrameRateConversion (float source, int dcp) repeat = round (dcp / source); } - change_speed = !about_equal (source * factor(), dcp); + speed_up = dcp / (source * factor()); + change_speed = !about_equal (speed_up, 1.0); if (!skip && repeat == 1 && !change_speed) { description = _("Content and DCP have the same rate.\n"); @@ -930,8 +914,15 @@ libdcp::Size fit_ratio_within (float ratio, libdcp::Size full_frame) { if (ratio < full_frame.ratio ()) { - return libdcp::Size (full_frame.height * ratio, full_frame.height); + return libdcp::Size (rint (full_frame.height * ratio), full_frame.height); } - return libdcp::Size (full_frame.width, full_frame.width / ratio); + return libdcp::Size (full_frame.width, rint (full_frame.width / ratio)); +} + +DCPTime +time_round_up (DCPTime t, DCPTime nearest) +{ + DCPTime const a = t + nearest - 1; + return a - (a % nearest); }