X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fcross.cc;h=75205dc1aa11709d84b651421f452005e0399b6d;hb=3df4d6271a6a660fdce143dcd65467c402e98976;hp=86146c1b1797fba6387aa9d4f4bdbdaa6714d68b;hpb=318d819afd66b76e3ea7ce728452c2fb668c0b80;p=dcpomatic.git diff --git a/src/lib/cross.cc b/src/lib/cross.cc index 86146c1b1..75205dc1a 100644 --- a/src/lib/cross.cc +++ b/src/lib/cross.cc @@ -1,66 +1,93 @@ /* - Copyright (C) 2012 Carl Hetherington + Copyright (C) 2012-2018 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 . */ -#include -#include #include "cross.h" #include "compose.hpp" #include "log.h" -#ifdef DVDOMATIC_POSIX +#include "config.h" +#include "exceptions.h" +extern "C" { +#include +} +#include +#ifdef DCPOMATIC_LINUX #include #include #endif -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS #include #undef DATADIR #include +#include +#include #endif -#ifdef DVDOMATIC_OSX +#ifdef DCPOMATIC_OSX #include +#include +#include #endif +#ifdef DCPOMATIC_POSIX +#include +#include +#include +#include +#endif +#include + +#include "i18n.h" + +#define LOG_GENERAL(...) log->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL); +#define LOG_ERROR(...) log->log (String::compose (__VA_ARGS__), LogEntry::TYPE_ERROR); +#define LOG_ERROR_NC(...) log->log (__VA_ARGS__, LogEntry::TYPE_ERROR); using std::pair; using std::list; using std::ifstream; using std::string; +using std::wstring; using std::make_pair; +using std::runtime_error; using boost::shared_ptr; +/** @param s Number of seconds to sleep for */ void -dvdomatic_sleep (int s) +dcpomatic_sleep (int s) { -#ifdef DVDOMATIC_POSIX +#ifdef DCPOMATIC_POSIX sleep (s); #endif -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS Sleep (s * 1000); #endif } -/** @return A pair containing CPU model name and the number of processors */ -pair +/** @return A string of CPU information (model name etc.) */ +string cpu_info () { - pair info; - info.second = 0; - -#ifdef DVDOMATIC_LINUX + string info; + +#ifdef DCPOMATIC_LINUX + /* This use of ifstream is ok; the filename can never + be non-Latin + */ ifstream f ("/proc/cpuinfo"); while (f.good ()) { string l; @@ -68,31 +95,96 @@ cpu_info () if (boost::algorithm::starts_with (l, "model name")) { string::size_type const c = l.find (':'); if (c != string::npos) { - info.first = l.substr (c + 2); + info = l.substr (c + 2); } - } else if (boost::algorithm::starts_with (l, "processor")) { - ++info.second; } } #endif -#ifdef DVDOMATIC_OSX - size_t N = sizeof (info.second); - sysctlbyname ("hw.ncpu", &info.second, &N, 0, 0); +#ifdef DCPOMATIC_OSX char buffer[64]; - N = sizeof (buffer); + size_t N = sizeof (buffer); if (sysctlbyname ("machdep.cpu.brand_string", buffer, &N, 0, 0) == 0) { - info.first = buffer; - } -#endif + info = buffer; + } +#endif + +#ifdef DCPOMATIC_WINDOWS + HKEY key; + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &key) != ERROR_SUCCESS) { + return info; + } + + DWORD type; + DWORD data; + if (RegQueryValueEx (key, L"ProcessorNameString", 0, &type, 0, &data) != ERROR_SUCCESS) { + return info; + } + + if (type != REG_SZ) { + return info; + } + + wstring value (data / sizeof (wchar_t), L'\0'); + if (RegQueryValueEx (key, L"ProcessorNameString", 0, 0, reinterpret_cast (&value[0]), &data) != ERROR_SUCCESS) { + RegCloseKey (key); + return info; + } + + info = string (value.begin(), value.end()); + + RegCloseKey (key); + +#endif return info; } +#ifdef DCPOMATIC_OSX +/** @return Path of the Contents directory in the .app */ +boost::filesystem::path +app_contents () +{ + uint32_t size = 1024; + char buffer[size]; + if (_NSGetExecutablePath (buffer, &size)) { + throw runtime_error ("_NSGetExecutablePath failed"); + } + + boost::filesystem::path path (buffer); + path = boost::filesystem::canonical (path); + path = path.parent_path (); + path = path.parent_path (); + return path; +} +#endif + +boost::filesystem::path +shared_path () +{ +#ifdef DCPOMATIC_LINUX + char const * p = getenv ("DCPOMATIC_LINUX_SHARE_PREFIX"); + if (p) { + return p; + } + return boost::filesystem::canonical (LINUX_SHARE_PREFIX); +#endif +#ifdef DCPOMATIC_WINDOWS + wchar_t dir[512]; + GetModuleFileName (GetModuleHandle (0), dir, sizeof (dir)); + PathRemoveFileSpec (dir); + boost::filesystem::path path = dir; + return path.parent_path(); +#endif +#ifdef DCPOMATIC_OSX + return app_contents() / "Resources"; +#endif +} + void run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, shared_ptr log) { -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS SECURITY_ATTRIBUTES security; security.nLength = sizeof (security); security.bInheritHandle = TRUE; @@ -101,7 +193,7 @@ run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, share HANDLE child_stderr_read; HANDLE child_stderr_write; if (!CreatePipe (&child_stderr_read, &child_stderr_write, &security, 0)) { - log->log ("ffprobe call failed (could not CreatePipe)"); + LOG_ERROR_NC ("ffprobe call failed (could not CreatePipe)"); return; } @@ -117,28 +209,30 @@ run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, share startup_info.dwFlags |= STARTF_USESTDHANDLES; wchar_t command[512]; - wcscpy (command, L"ffprobe.exe "); + wcscpy (command, L"ffprobe.exe \""); wchar_t file[512]; MultiByteToWideChar (CP_UTF8, 0, content.string().c_str(), -1, file, sizeof(file)); wcscat (command, file); + wcscat (command, L"\""); + PROCESS_INFORMATION process_info; ZeroMemory (&process_info, sizeof (process_info)); if (!CreateProcess (0, command, 0, 0, TRUE, CREATE_NO_WINDOW, 0, 0, &startup_info, &process_info)) { - log->log ("ffprobe call failed (could not CreateProcess)"); + LOG_ERROR_NC (N_("ffprobe call failed (could not CreateProcess)")); return; } - FILE* o = fopen (out.string().c_str(), "w"); + FILE* o = fopen_boost (out, "w"); if (!o) { - log->log ("ffprobe call failed (could not create output file)"); + LOG_ERROR_NC (N_("ffprobe call failed (could not create output file)")); return; } CloseHandle (child_stderr_write); - while (1) { + while (true) { char buffer[512]; DWORD read; if (!ReadFile(child_stderr_read, buffer, sizeof(buffer), &read, 0) || read == 0) { @@ -153,25 +247,37 @@ run_ffprobe (boost::filesystem::path content, boost::filesystem::path out, share CloseHandle (process_info.hProcess); CloseHandle (process_info.hThread); CloseHandle (child_stderr_read); -#else +#endif + +#ifdef DCPOMATIC_LINUX string ffprobe = "ffprobe \"" + content.string() + "\" 2> \"" + out.string() + "\""; - log->log (String::compose ("Probing with %1", ffprobe)); + LOG_GENERAL (N_("Probing with %1"), ffprobe); + system (ffprobe.c_str ()); +#endif + +#ifdef DCPOMATIC_OSX + boost::filesystem::path path = app_contents(); + path /= "MacOS"; + path /= "ffprobe"; + + string ffprobe = "\"" + path.string() + "\" \"" + content.string() + "\" 2> \"" + out.string() + "\""; + LOG_GENERAL (N_("Probing with %1"), ffprobe); system (ffprobe.c_str ()); -#endif +#endif } list > mount_info () { list > m; - -#ifdef DVDOMATIC_POSIX + +#ifdef DCPOMATIC_LINUX FILE* f = setmntent ("/etc/mtab", "r"); if (!f) { return m; } - - while (1) { + + while (true) { struct mntent* mnt = getmntent (f); if (!mnt) { break; @@ -185,3 +291,178 @@ mount_info () return m; } + +boost::filesystem::path +openssl_path () +{ +#ifdef DCPOMATIC_WINDOWS + wchar_t dir[512]; + GetModuleFileName (GetModuleHandle (0), dir, sizeof (dir)); + PathRemoveFileSpec (dir); + + boost::filesystem::path path = dir; + path /= "openssl.exe"; + return path; +#else + /* We assume that it's on the path for Linux and OS X */ + return "openssl"; +#endif + +} + +/* Apparently there is no way to create an ofstream using a UTF-8 + filename under Windows. We are hence reduced to using fopen + with this wrapper. +*/ +FILE * +fopen_boost (boost::filesystem::path p, string t) +{ +#ifdef DCPOMATIC_WINDOWS + wstring w (t.begin(), t.end()); + /* c_str() here should give a UTF-16 string */ + return _wfopen (p.c_str(), w.c_str ()); +#else + return fopen (p.c_str(), t.c_str ()); +#endif +} + +int +dcpomatic_fseek (FILE* stream, int64_t offset, int whence) +{ +#ifdef DCPOMATIC_WINDOWS + return _fseeki64 (stream, offset, whence); +#else + return fseek (stream, offset, whence); +#endif +} + +void +Waker::nudge () +{ +#ifdef DCPOMATIC_WINDOWS + SetThreadExecutionState (ES_SYSTEM_REQUIRED); +#endif +} + +Waker::Waker () +{ +#ifdef DCPOMATIC_OSX + /* We should use this */ + // IOPMAssertionCreateWithName (kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, CFSTR ("Encoding DCP"), &_assertion_id); + /* but it's not available on 10.5, so we use this */ + IOPMAssertionCreate (kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, &_assertion_id); +#endif +} + +Waker::~Waker () +{ +#ifdef DCPOMATIC_OSX + IOPMAssertionRelease (_assertion_id); +#endif +} + +void +start_tool (boost::filesystem::path dcpomatic, string executable, +#ifdef DCPOMATIC_OSX + string app +#else + string +#endif + ) +{ +#if defined(DCPOMATIC_LINUX) || defined(DCPOMATIC_WINDOWS) + boost::filesystem::path batch = dcpomatic.parent_path() / executable; +#endif + +#ifdef DCPOMATIC_OSX + boost::filesystem::path batch = dcpomatic.parent_path (); + batch = batch.parent_path (); // MacOS + batch = batch.parent_path (); // Contents + batch = batch.parent_path (); // DCP-o-matic.app + batch = batch.parent_path (); // Applications + batch /= app; + batch /= "Contents"; + batch /= "MacOS"; + batch /= executable; +#endif + +#if defined(DCPOMATIC_LINUX) || defined(DCPOMATIC_OSX) + pid_t pid = fork (); + if (pid == 0) { + int const r = system (batch.string().c_str()); + exit (WEXITSTATUS (r)); + } +#endif + +#ifdef DCPOMATIC_WINDOWS + STARTUPINFO startup_info; + ZeroMemory (&startup_info, sizeof (startup_info)); + startup_info.cb = sizeof (startup_info); + + PROCESS_INFORMATION process_info; + ZeroMemory (&process_info, sizeof (process_info)); + + wchar_t cmd[512]; + MultiByteToWideChar (CP_UTF8, 0, batch.string().c_str(), -1, cmd, sizeof(cmd)); + CreateProcess (0, cmd, 0, 0, FALSE, 0, 0, 0, &startup_info, &process_info); +#endif +} + +void +start_batch_converter (boost::filesystem::path dcpomatic) +{ + start_tool (dcpomatic, "dcpomatic2_batch", "DCP-o-matic\\ 2\\ Batch\\ Converter.app"); +} + +void +start_player (boost::filesystem::path dcpomatic) +{ + start_tool (dcpomatic, "dcpomatic2_player", "DCP-o-matic\\ 2\\ Player.app"); +} + +uint64_t +thread_id () +{ +#ifdef DCPOMATIC_WINDOWS + return (uint64_t) GetCurrentThreadId (); +#else + return (uint64_t) pthread_self (); +#endif +} + +int +avio_open_boost (AVIOContext** s, boost::filesystem::path file, int flags) +{ +#ifdef DCPOMATIC_WINDOWS + int const length = (file.string().length() + 1) * 2; + char* utf8 = new char[length]; + WideCharToMultiByte (CP_UTF8, 0, file.c_str(), -1, utf8, length, 0, 0); + int const r = avio_open (s, utf8, flags); + delete[] utf8; + return r; +#else + return avio_open (s, file.c_str(), flags); +#endif +} + +#ifdef DCPOMATIC_WINDOWS +void +maybe_open_console () +{ + if (Config::instance()->win32_console ()) { + AllocConsole(); + + HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); + int hCrt = _open_osfhandle((intptr_t) handle_out, _O_TEXT); + FILE* hf_out = _fdopen(hCrt, "w"); + setvbuf(hf_out, NULL, _IONBF, 1); + *stdout = *hf_out; + + HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE); + hCrt = _open_osfhandle((intptr_t) handle_in, _O_TEXT); + FILE* hf_in = _fdopen(hCrt, "r"); + setvbuf(hf_in, NULL, _IONBF, 128); + *stdin = *hf_in; + } +} +#endif