diff options
| author | Carl Hetherington <cth@carlh.net> | 2023-07-06 23:09:08 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2024-01-28 02:01:57 +0100 |
| commit | c80eca531e01860e6714f526b2efb07a58c2e26e (patch) | |
| tree | 8b2ca4b071b6def5f2e9e85809b6bc25caa81586 /src/lib/j2k_encoder.cc | |
| parent | 3299d48531d631264dacd01faf1fa3c069b28e62 (diff) | |
Patch from Aaron Boxer adding initial support for GPU-powered J2K encoding via his tool "grok".
Diffstat (limited to 'src/lib/j2k_encoder.cc')
| -rw-r--r-- | src/lib/j2k_encoder.cc | 133 |
1 files changed, 89 insertions, 44 deletions
diff --git a/src/lib/j2k_encoder.cc b/src/lib/j2k_encoder.cc index 7c9777c16..e2fca09b1 100644 --- a/src/lib/j2k_encoder.cc +++ b/src/lib/j2k_encoder.cc @@ -53,6 +53,7 @@ using boost::optional; using dcp::Data; using namespace dcpomatic; +static grk_plugin::GrokInitializer grokInitializer; /** @param film Film that we are encoding. * @param writer Writer that we are using. @@ -60,7 +61,9 @@ using namespace dcpomatic; J2KEncoder::J2KEncoder(shared_ptr<const Film> film, Writer& writer) : _film (film) , _history (200) - , _writer (writer) + , _writer (writer) , + dcpomaticContext_(film,writer,_history, Config::instance()->gpu_binary_location ()), + context_(Config::instance()->enable_gpu () ? new grk_plugin::GrokContext(dcpomaticContext_) : nullptr) { } @@ -69,10 +72,13 @@ J2KEncoder::~J2KEncoder () { _server_found_connection.disconnect(); + { boost::mutex::scoped_lock lm (_threads_mutex); terminate_threads (); -} + } + delete context_; +} void J2KEncoder::begin () @@ -83,23 +89,35 @@ J2KEncoder::begin () servers_list_changed (); } +void J2KEncoder::pause(void){ + if (Config::instance()->enable_gpu ()) + end(false); +} + +void J2KEncoder::resume(void){ + if (Config::instance()->enable_gpu ()) { + context_ = new grk_plugin::GrokContext(dcpomaticContext_); + servers_list_changed (); + } +} void -J2KEncoder::end () +J2KEncoder::end (bool isFinal) { - boost::mutex::scoped_lock lock (_queue_mutex); + if (isFinal) { + boost::mutex::scoped_lock lock (_queue_mutex); - LOG_GENERAL (N_("Clearing queue of %1"), _queue.size ()); + LOG_GENERAL (N_("Clearing queue of %1"), _queue.size ()); - /* Keep waking workers until the queue is empty */ - while (!_queue.empty ()) { - rethrow (); - _empty_condition.notify_all (); - _full_condition.wait (lock); + /* Keep waking workers until the queue is empty */ + while (!_queue.empty ()) { + rethrow (); + _empty_condition.notify_all (); + _full_condition.wait (lock); + } + lock.unlock (); } - lock.unlock (); - LOG_GENERAL_NC (N_("Terminating encoder threads")); { @@ -113,27 +131,38 @@ J2KEncoder::end () LOG_GENERAL (N_("Mopping up %1"), _queue.size()); /* The following sequence of events can occur in the above code: - 1. a remote worker takes the last image off the queue - 2. the loop above terminates - 3. the remote worker fails to encode the image and puts it back on the queue - 4. the remote worker is then terminated by terminate_threads + 1. a remote worker takes the last image off the queue + 2. the loop above terminates + 3. the remote worker fails to encode the image and puts it back on the queue + 4. the remote worker is then terminated by terminate_threads - So just mop up anything left in the queue here. + So just mop up anything left in the queue here. */ - - for (auto const& i: _queue) { - LOG_GENERAL(N_("Encode left-over frame %1"), i.index()); - try { - _writer.write( - make_shared<dcp::ArrayData>(i.encode_locally()), - i.index(), - i.eyes() - ); - frame_done (); - } catch (std::exception& e) { - LOG_ERROR (N_("Local encode failed (%1)"), e.what ()); + if (isFinal) { + for (auto & i: _queue) { + if (Config::instance()->enable_gpu ()) { + if (!context_->scheduleCompress(i)){ + LOG_GENERAL (N_("[%1] J2KEncoder thread pushes frame %2 back onto queue after failure"), thread_id(), i.index()); + // handle error + } + } + else { + LOG_GENERAL(N_("Encode left-over frame %1"), i.index()); + try { + _writer.write( + make_shared<dcp::ArrayData>(i.encode_locally()), + i.index(), + i.eyes() + ); + frame_done (); + } catch (std::exception& e) { + LOG_ERROR (N_("Local encode failed (%1)"), e.what ()); + } + } } } + delete context_; + context_ = nullptr; } @@ -183,7 +212,10 @@ J2KEncoder::encode (shared_ptr<PlayerVideo> pv, DCPTime time) size_t threads = 0; { boost::mutex::scoped_lock lm (_threads_mutex); - threads = _threads->size(); + if (_threads) + threads = _threads->size(); + else + threads = std::thread::hardware_concurrency(); } boost::mutex::scoped_lock queue_lock (_queue_mutex); @@ -223,13 +255,14 @@ J2KEncoder::encode (shared_ptr<PlayerVideo> pv, DCPTime time) LOG_DEBUG_ENCODE("Frame @ %1 ENCODE", to_string(time)); /* Queue this new frame for encoding */ LOG_TIMING ("add-frame-to-queue queue=%1", _queue.size ()); - _queue.push_back (DCPVideo( + auto dcpv = DCPVideo( pv, position, _film->video_frame_rate(), _film->j2k_bandwidth(), _film->resolution() - )); + ); + _queue.push_back (dcpv); /* The queue might not be empty any more, so notify anything which is waiting on that. @@ -269,6 +302,8 @@ void J2KEncoder::encoder_thread (optional<EncodeServerDescription> server) try { + auto config = Config::instance (); + start_of_thread ("J2KEncoder"); if (server) { @@ -332,14 +367,22 @@ try } } else { - try { - LOG_TIMING ("start-local-encode thread=%1 frame=%2", thread_id(), vf.index()); - encoded = make_shared<dcp::ArrayData>(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 */ - LOG_ERROR (N_("Local encode failed (%1)"), e.what ()); - throw; + if (context_) { + if (!context_->launch(vf, config->selected_gpu()) || !context_->scheduleCompress(vf)) { + LOG_GENERAL (N_("[%1] J2KEncoder thread pushes frame %2 back onto queue after failure"), thread_id(), vf.index()); + _queue.push_front (vf); + } + + } else { + try { + LOG_TIMING ("start-local-encode thread=%1 frame=%2", thread_id(), vf.index()); + encoded = make_shared<dcp::ArrayData>(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 */ + LOG_ERROR (N_("Local encode failed (%1)"), e.what ()); + throw; + } } } @@ -347,10 +390,12 @@ try _writer.write(encoded, vf.index(), vf.eyes()); frame_done (); } else { - lock.lock (); - LOG_GENERAL (N_("[%1] J2KEncoder thread pushes frame %2 back onto queue after failure"), thread_id(), vf.index()); - _queue.push_front (vf); - lock.unlock (); + if (!Config::instance()->enable_gpu ()) { + lock.lock (); + LOG_GENERAL (N_("[%1] J2KEncoder thread pushes frame %2 back onto queue after failure"), thread_id(), vf.index()); + _queue.push_front (vf); + lock.unlock (); + } } } |
