/*
- Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#include "util.h"
#include "film.h"
#include "log.h"
+#include "dcpomatic_log.h"
#include "config.h"
#include "dcp_video.h"
#include "cross.h"
#include "i18n.h"
-#define LOG_GENERAL(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
-#define LOG_GENERAL_NC(...) _film->log()->log (__VA_ARGS__, LogEntry::TYPE_GENERAL);
-#define LOG_ERROR(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_ERROR);
-#define LOG_TIMING(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_TIMING);
-#define LOG_DEBUG_ENCODE(...) _film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_DEBUG_ENCODE);
-
using std::list;
using std::cout;
+using std::exception;
using boost::shared_ptr;
using boost::weak_ptr;
using boost::optional;
using dcp::Data;
+using namespace dcpomatic;
/** @param film Film that we are encoding.
* @param writer Writer that we are using.
J2KEncoder::~J2KEncoder ()
{
- try {
- terminate_threads ();
- } catch (...) {
- /* Destructors must not throw exceptions; anything bad
- happening now is too late to worry about anyway,
- I think.
- */
- }
+ terminate_threads ();
}
void
terminate_threads ();
+ /* Something might have been thrown during terminate_threads */
+ rethrow ();
+
LOG_GENERAL (N_("Mopping up %1"), _queue.size());
/* The following sequence of events can occur in the above code:
LOG_GENERAL (N_("Encode left-over frame %1"), (*i)->index ());
try {
_writer->write (
- (*i)->encode_locally (boost::bind (&Log::dcp_log, _film->log().get(), _1, _2)),
- (*i)->index (),
- (*i)->eyes ()
+ (*i)->encode_locally(),
+ (*i)->index(),
+ (*i)->eyes()
);
frame_done ();
} catch (std::exception& e) {
}
/** @return an estimate of the current number of frames we are encoding per second,
- * or 0 if not known.
+ * if known.
*/
-float
+optional<float>
J2KEncoder::current_encoding_rate () const
{
return _history.rate ();
{
_waker.nudge ();
- size_t threads = 0;
- {
- boost::mutex::scoped_lock threads_lock (_threads_mutex);
- threads = _threads.size ();
- }
+ size_t threads = _threads->size();
boost::mutex::scoped_lock queue_lock (_queue_mutex);
LOG_DEBUG_ENCODE("Frame @ %1 FAKE", to_string(time));
_writer->fake_write (position, pv->eyes ());
frame_done ();
- } else if (pv->has_j2k ()) {
+ } else if (pv->has_j2k() && !_film->reencode_j2k()) {
LOG_DEBUG_ENCODE("Frame @ %1 J2K", to_string(time));
/* This frame already has J2K data, so just write it */
_writer->write (pv->j2k(), position, pv->eyes ());
position,
_film->video_frame_rate(),
_film->j2k_bandwidth(),
- _film->resolution(),
- _film->log()
+ _film->resolution()
)
));
void
J2KEncoder::terminate_threads ()
{
- boost::mutex::scoped_lock threads_lock (_threads_mutex);
+ boost::this_thread::disable_interruption dis;
- int n = 0;
- for (list<boost::thread *>::iterator i = _threads.begin(); i != _threads.end(); ++i) {
- LOG_GENERAL ("Terminating thread %1 of %2", n + 1, _threads.size ());
- (*i)->interrupt ();
- DCPOMATIC_ASSERT ((*i)->joinable ());
- try {
- (*i)->join ();
- } catch (boost::thread_interrupted& e) {
- /* This is to be expected */
- }
- delete *i;
- LOG_GENERAL_NC ("Thread terminated");
- ++n;
+ if (!_threads) {
+ return;
}
- _threads.clear ();
+ _threads->interrupt_all ();
+ try {
+ _threads->join_all ();
+ } catch (exception& e) {
+ LOG_ERROR ("join() threw an exception: %1", e.what());
+ } catch (...) {
+ LOG_ERROR_NC ("join() threw an exception");
+ }
+
+ _threads.reset ();
}
void
} else {
try {
LOG_TIMING ("start-local-encode thread=%1 frame=%2", thread_id(), vf->index());
- encoded = vf->encode_locally (boost::bind (&Log::dcp_log, _film->log().get(), _1, _2));
+ encoded = vf->encode_locally ();
LOG_TIMING ("finish-local-encode thread=%1 frame=%2", thread_id(), vf->index());
} catch (std::exception& e) {
/* This is very bad, so don't cope with it, just pass it on */
J2KEncoder::servers_list_changed ()
{
terminate_threads ();
+ _threads.reset (new boost::thread_group());
/* XXX: could re-use threads */
- boost::mutex::scoped_lock lm (_threads_mutex);
-
-#ifdef BOOST_THREAD_PLATFORM_WIN32
- OSVERSIONINFO info;
- info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
- GetVersionEx (&info);
- bool const windows_xp = (info.dwMajorVersion == 5 && info.dwMinorVersion == 1);
- if (windows_xp) {
- LOG_GENERAL_NC (N_("Setting thread affinity for Windows XP"));
- }
-#endif
-
if (!Config::instance()->only_servers_encode ()) {
for (int i = 0; i < Config::instance()->master_encoding_threads (); ++i) {
- boost::thread* t = new boost::thread (boost::bind (&J2KEncoder::encoder_thread, this, optional<EncodeServerDescription> ()));
#ifdef DCPOMATIC_LINUX
+ boost::thread* t = _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, optional<EncodeServerDescription>()));
pthread_setname_np (t->native_handle(), "encode-worker");
-#endif
- _threads.push_back (t);
-#ifdef BOOST_THREAD_PLATFORM_WIN32
- if (windows_xp) {
- SetThreadAffinityMask (t->native_handle(), 1 << i);
- }
+#else
+ _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, optional<EncodeServerDescription>()));
#endif
}
}
- BOOST_FOREACH (EncodeServerDescription i, EncodeServerFinder::instance()->good_servers ()) {
+ BOOST_FOREACH (EncodeServerDescription i, EncodeServerFinder::instance()->servers()) {
+ if (!i.current_link_version()) {
+ continue;
+ }
+
LOG_GENERAL (N_("Adding %1 worker threads for remote %2"), i.threads(), i.host_name ());
for (int j = 0; j < i.threads(); ++j) {
- _threads.push_back (new boost::thread (boost::bind (&J2KEncoder::encoder_thread, this, i)));
+ _threads->create_thread(boost::bind(&J2KEncoder::encoder_thread, this, i));
}
}
- _writer->set_encoder_threads (_threads.size ());
+ _writer->set_encoder_threads (_threads->size());
}