#include "ratio.h"
#include "rect.h"
#include "render_text.h"
+#include "scope_guard.h"
#include "string_text.h"
#include "text_decoder.h"
#include "util.h"
#include "video_content.h"
#include <dcp/atmos_asset.h>
#include <dcp/decrypted_kdm.h>
+#include <dcp/file.h>
#include <dcp/locale_convert.h>
#include <dcp/picture_asset.h>
#include <dcp/raw_convert.h>
#include <unicode/utypes.h>
#include <unicode/unistr.h>
#include <unicode/translit.h>
+#include <unicode/brkiter.h>
#include <boost/algorithm/string.hpp>
#include <boost/range/algorithm/replace_if.hpp>
#include <boost/thread.hpp>
#include <boost/locale.hpp>
LIBDCP_ENABLE_WARNINGS
#ifdef DCPOMATIC_WINDOWS
-#include <boost/locale.hpp>
#include <dbghelp.h>
#endif
#include <signal.h>
#include "i18n.h"
-using std::bad_alloc;
using std::cout;
using std::endl;
-using std::istream;
using std::list;
using std::make_pair;
using std::make_shared;
-using std::map;
+using std::max;
using std::min;
-using std::ostream;
using std::pair;
using std::set_terminate;
using std::shared_ptr;
using std::string;
using std::vector;
using std::wstring;
-using boost::thread;
using boost::optional;
-using boost::lexical_cast;
-using boost::bad_lexical_cast;
-using boost::scoped_array;
using dcp::Size;
using dcp::raw_convert;
using dcp::locale_convert;
#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);
+}
+
+
+static
+void
+ffmpeg_log_callback(void* ptr, int level, const char* fmt, va_list vl)
+{
+ if (level > AV_LOG_WARNING) {
+ return;
+ }
+
+ char line[1024];
+ static int prefix = 0;
+ av_log_format_line(ptr, level, fmt, vl, line, sizeof (line), &prefix);
+ string str(line);
+ boost::algorithm::trim(str);
+ dcpomatic_log->log(String::compose("FFmpeg: %1", str), LogEntry::TYPE_GENERAL);
+}
+
+
+void
+capture_ffmpeg_logs()
+{
+ av_log_set_callback(ffmpeg_log_callback);
+}
+
+
/** Call the required functions to set up DCP-o-matic's static arrays, etc.
* Must be called from the UI thread, if there is one.
*/
#ifdef DCPOMATIC_WINDOWS
putenv ("PANGOCAIRO_BACKEND=fontconfig");
- putenv (String::compose("FONTCONFIG_PATH=%1", resources_path().string()).c_str());
+ if (boost::filesystem::exists(resources_path() / "fonts.conf")) {
+ /* The actual application after installation */
+ putenv(String::compose("FONTCONFIG_PATH=%1", resources_path().string()).c_str());
+ } else {
+ /* The place where fonts.conf is during tests */
+ putenv("FONTCONFIG_PATH=build\\fonts");
+ }
#endif
#ifdef DCPOMATIC_OSX
#if defined(DCPOMATIC_WINDOWS) || defined(DCPOMATIC_OSX)
/* Render something to fontconfig to create its cache */
- list<StringText> subs;
+ vector<StringText> subs;
dcp::SubtitleString ss(
optional<string>(), false, false, false, dcp::Colour(), 42, 1, dcp::Time(), dcp::Time(), 0, dcp::HAlign::CENTER, 0, dcp::VAlign::CENTER, 0, dcp::Direction::LTR,
"Hello dolly", dcp::Effect::NONE, dcp::Colour(), dcp::Time(), dcp::Time(), 0
);
- subs.push_back(StringText(ss, 0, {}, dcp::SubtitleStandard::SMPTE_2014));
+ subs.push_back(StringText(ss, 0, make_shared<dcpomatic::Font>("foo"), dcp::SubtitleStandard::SMPTE_2014));
render_text (subs, dcp::Size(640, 480), DCPTime(), 24);
#endif
ui_thread = boost::this_thread::get_id ();
capture_asdcp_logs ();
+ capture_ffmpeg_logs();
}
#ifdef DCPOMATIC_WINDOWS
dcp::Size
scale_for_display (dcp::Size s, dcp::Size display_container, dcp::Size film_container, PixelQuanta quanta)
{
- /* Now scale it down if the display container is smaller than the film container */
- if (display_container != film_container) {
- float const scale = min (
- float (display_container.width) / film_container.width,
- float (display_container.height) / film_container.height
+ if (std::abs(display_container.ratio() - film_container.ratio()) < 0.01) {
+ /* The display ratio is very close to what it should be, but it might not be exactly the same.
+ * Allow the image to stretch slightly (differently in x and y) so that we are less likely
+ * to get single pixel gaps in the preview.
+ */
+ return quanta.round(
+ static_cast<float>(s.width) * display_container.width / film_container.width,
+ static_cast<float>(s.height) * display_container.height / film_container.height
);
-
- s.width = lrintf (s.width * scale);
- s.height = lrintf (s.height * scale);
- s = quanta.round (s);
+ } else {
+ /* The display ratio is quite different to the film, so scale it so that the dimension
+ * that needs to fit does fit.
+ */
+ auto const scale = min(
+ static_cast<float>(display_container.width) / film_container.width,
+ static_cast<float>(display_container.height) / film_container.height
+ );
+ return quanta.round(s.width * scale, s.height * scale);
}
-
- return s;
}
#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 boost::filesystem::is_regular_file(dir / "ASSETMAP") || boost::filesystem::is_regular_file(dir / "ASSETMAP.xml");
}
+
+string
+word_wrap(string input, int columns)
+{
+ icu::Locale locale;
+ UErrorCode status = U_ZERO_ERROR;
+ auto iter = icu::BreakIterator::createLineInstance(locale, status);
+ ScopeGuard sg = [iter]() { delete iter; };
+ if (U_FAILURE(status)) {
+ return input;
+ }
+
+ auto input_icu = icu::UnicodeString::fromUTF8(icu::StringPiece(input));
+ iter->setText(input_icu);
+
+ int position = 0;
+ string output;
+ while (position < input_icu.length()) {
+ int end_of_line = iter->preceding(position + columns + 1);
+ icu::UnicodeString line;
+ if (end_of_line <= position) {
+ /* There's no good line-break position; just break in the middle of a word */
+ line = input_icu.tempSubString(position, columns);
+ position += columns;
+ } else {
+ line = input_icu.tempSubString(position, end_of_line - position);
+ position = end_of_line;
+ }
+ line.toUTF8String(output);
+ output += "\n";
+ }
+
+ return output;
+}
+