X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Futil.cc;h=e7044027155715f2910dd4762d7e94b9b99d5081;hb=72eedf0b240c71b9dbd27d1f95b109b48e3200a2;hp=b9075310308442901452beb0e0a86d00967c6758;hpb=56139fd8f98ad306c32567c4b8070fe7ff18ab1e;p=dcpomatic.git diff --git a/src/lib/util.cc b/src/lib/util.cc index b90753103..e70440271 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -69,9 +70,6 @@ extern "C" { #ifdef DCPOMATIC_WINDOWS #include "stack.hpp" #endif -#ifdef DCPOMATIC_OSX -#include -#endif #include "i18n.h" @@ -83,7 +81,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; @@ -92,7 +89,7 @@ using std::multimap; using std::istream; using std::numeric_limits; using std::pair; -using std::ofstream; +using std::cout; using boost::shared_ptr; using boost::thread; using boost::lexical_cast; @@ -262,8 +259,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 @@ -278,6 +278,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 (); @@ -288,8 +303,7 @@ dcpomatic_setup () */ boost::filesystem::path lib = app_contents (); lib /= "lib"; - std::cout << "adding search dir " << lib.c_str() << "\n"; - lt_dladdsearchdir (lib.c_str ()); + setenv ("LTDL_LIBRARY_PATH", lib.c_str (), 1); #endif libdcp::init (); @@ -395,29 +409,28 @@ md5_digest (void const * data, int size) string md5_digest (boost::filesystem::path file) { - ifstream f (file.string().c_str(), std::ios::binary); - if (!f.good ()) { + FILE* f = fopen_boost (file, "rb"); + if (!f) { 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; + boost::uintmax_t bytes = boost::filesystem::file_size (file); + + boost::uintmax_t 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); + fread (buffer, 1, t, f); MD5_Update (&md5_context, buffer, t); bytes -= t; } unsigned char digest[MD5_DIGEST_LENGTH]; MD5_Final (digest, &md5_context); + fclose (f); stringstream s; for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) { @@ -431,7 +444,7 @@ md5_digest (boost::filesystem::path file) string md5_digest_directory (boost::filesystem::path directory, 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; @@ -446,18 +459,16 @@ md5_digest_directory (boost::filesystem::path directory, shared_ptr job) 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 ()) { + FILE* f = fopen_boost (i->path(), "rb"); + if (!f) { throw OpenFileError (i->path().string()); } - - f.seekg (0, std::ios::end); - int bytes = f.tellg (); - f.seekg (0, std::ios::beg); + + boost::uintmax_t bytes = boost::filesystem::file_size (i->path ()); while (bytes > 0) { int const t = min (bytes, buffer_size); - f.read (buffer, t); + fread (buffer, 1, t, f); MD5_Update (&md5_context, buffer, t); bytes -= t; } @@ -466,6 +477,8 @@ md5_digest_directory (boost::filesystem::path directory, shared_ptr job) job->set_progress (float (j) / files); ++j; } + + fclose (f); } unsigned char digest[MD5_DIGEST_LENGTH]; @@ -522,17 +535,27 @@ dcp_audio_frame_rate (int fs) Socket::Socket (int timeout) : _deadline (_io_service) , _socket (_io_service) + , _acceptor (0) , _timeout (timeout) { _deadline.expires_at (boost::posix_time::pos_infin); check (); } +Socket::~Socket () +{ + delete _acceptor; +} + void Socket::check () { if (_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now ()) { - _socket.close (); + if (_acceptor) { + _acceptor->cancel (); + } else { + _socket.close (); + } _deadline.expires_at (boost::posix_time::pos_infin); } @@ -543,7 +566,7 @@ Socket::check () * @param endpoint End-point to connect to. */ void -Socket::connect (boost::asio::ip::basic_resolver_entry const & endpoint) +Socket::connect (boost::asio::ip::tcp::endpoint endpoint) { _deadline.expires_from_now (boost::posix_time::seconds (_timeout)); boost::system::error_code ec = boost::asio::error::would_block; @@ -552,11 +575,35 @@ Socket::connect (boost::asio::ip::basic_resolver_entry con _io_service.run_one(); } while (ec == boost::asio::error::would_block); - if (ec || !_socket.is_open ()) { + if (ec) { + throw NetworkError (ec.message ()); + } + + if (!_socket.is_open ()) { throw NetworkError (_("connect timed out")); } } +void +Socket::accept (int port) +{ + _acceptor = new boost::asio::ip::tcp::acceptor (_io_service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)); + + _deadline.expires_from_now (boost::posix_time::seconds (_timeout)); + boost::system::error_code ec = boost::asio::error::would_block; + _acceptor->async_accept (_socket, boost::lambda::var(ec) = boost::lambda::_1); + do { + _io_service.run_one (); + } while (ec == boost::asio::error::would_block ); + + delete _acceptor; + _acceptor = 0; + + if (ec) { + throw NetworkError (ec.message ()); + } +} + /** Blocking write. * @param data Buffer to write. * @param size Number of bytes to write. @@ -748,7 +795,7 @@ audio_channel_name (int c) assert (MAX_AUDIO_CHANNELS == 6); /* TRANSLATORS: these are the names of audio channels; Lfe (sub) is the low-frequency - enhancement channel (sub-woofer)./ + enhancement channel (sub-woofer). */ string const channels[] = { _("Left"), @@ -764,24 +811,33 @@ audio_channel_name (int c) FrameRateConversion::FrameRateConversion (float source, int dcp) : skip (false) - , repeat (false) + , repeat (1) , change_speed (false) { - if (fabs (source / 2.0 - dcp) < (fabs (source - dcp))) { + if (fabs (source / 2.0 - dcp) < fabs (source - dcp)) { + /* The difference between source and DCP frame rate will be lower + (i.e. better) if we skip. + */ skip = true; } else if (fabs (source * 2 - dcp) < fabs (source - dcp)) { - repeat = true; + /* The difference between source and DCP frame rate would be better + if we repeated each frame once; it may be better still if we + repeated more than once. Work out the required repeat. + */ + repeat = round (dcp / source); } change_speed = !about_equal (source * factor(), dcp); - if (!skip && !repeat && !change_speed) { + if (!skip && repeat == 1 && !change_speed) { description = _("Content and DCP have the same rate.\n"); } else { if (skip) { description = _("DCP will use every other frame of the content.\n"); - } else if (repeat) { + } else if (repeat == 2) { description = _("Each content frame will be doubled in the DCP.\n"); + } else if (repeat > 2) { + description = String::compose (_("Each content frame will be repeated %1 more times in the DCP.\n"), repeat - 1); } if (change_speed) { @@ -886,3 +942,12 @@ make_signer () return shared_ptr (new libdcp::Signer (chain, signer_key)); } +libdcp::Size +fit_ratio_within (float ratio, libdcp::Size full_frame) +{ + if (ratio < full_frame.ratio ()) { + return libdcp::Size (rint (full_frame.height * ratio), full_frame.height); + } + + return libdcp::Size (full_frame.width, rint (full_frame.width / ratio)); +}