diff options
| author | Carl Hetherington <cth@carlh.net> | 2026-02-16 23:39:22 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2026-02-16 23:39:22 +0100 |
| commit | 8b0241e4825c1ff50b5909e356a9bc2522775df6 (patch) | |
| tree | 165f679467d72e49d5957990bd4b374d5f55a69a /src | |
| parent | d056ab7d3d202506e64f2ea1c143b286df4c9cc1 (diff) | |
Sort-of works.kakadu
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/j2k_encoder.cc | 45 | ||||
| -rw-r--r-- | src/lib/j2k_encoder.h | 15 | ||||
| -rw-r--r-- | src/lib/kakadu.cc | 58 | ||||
| -rw-r--r-- | src/lib/kakadu.h | 55 | ||||
| -rw-r--r-- | src/lib/kakadu_j2k_encoder_thread.cc | 78 | ||||
| -rw-r--r-- | src/lib/kakadu_j2k_encoder_thread.h | 37 | ||||
| -rw-r--r-- | src/lib/wscript | 3 |
7 files changed, 285 insertions, 6 deletions
diff --git a/src/lib/j2k_encoder.cc b/src/lib/j2k_encoder.cc index e3e3c881b..4acf6158b 100644 --- a/src/lib/j2k_encoder.cc +++ b/src/lib/j2k_encoder.cc @@ -35,6 +35,9 @@ #include "grok/context.h" #include "grok_j2k_encoder_thread.h" #endif +#ifdef DCPOMATIC_KAKADU +#include "kakadu_j2k_encoder_thread.h" +#endif #include "openjpeg_j2k_encoder_thread.h" #include "remote_j2k_encoder_thread.h" #include "j2k_encoder.h" @@ -104,6 +107,15 @@ J2KEncoder::J2KEncoder(shared_ptr<const Film> film, Writer& writer) _context = new grk_plugin::GrokContext(_dcpomatic_context); } #endif + +#ifdef DCPOMATIC_KAKADU + try { + _kakadu_shared_memory = new KakaduSharedMemory(); + LOG_GENERAL("Found Kakadu server"); + } catch (boost::interprocess::interprocess_exception& e) { + LOG_ERROR("Could not find Kakadu server ({})", e.what()); + } +#endif } @@ -127,6 +139,10 @@ J2KEncoder::~J2KEncoder() delete _context; delete _dcpomatic_context; #endif + +#ifdef DCPOMATIC_KAKADU + delete _kakadu_shared_memory; +#endif } @@ -140,11 +156,12 @@ J2KEncoder::servers_list_changed() auto const grok_enable = false; #endif - auto const openjpeg = (grok_enable || config->only_servers_encode()) ? 0 : config->master_encoding_threads(); + auto const openjpeg = 0;// (grok_enable || config->only_servers_encode()) ? 0 : config->master_encoding_threads(); + auto const kakadu = 1; auto const gpu = grok_enable ? config->master_encoding_threads() : 0; LOG_GENERAL("Thread counts from: grok={}, only_servers={}, master={}", grok_enable ? "yes" : "no", config->only_servers_encode() ? "yes" : "no", config->master_encoding_threads()); - remake_threads(openjpeg, gpu, EncodeServerFinder::instance()->servers()); + remake_threads(openjpeg, kakadu, gpu, EncodeServerFinder::instance()->servers()); } @@ -362,10 +379,10 @@ J2KEncoder::terminate_threads() void -J2KEncoder::remake_threads(int openjpeg, int gpu, list<EncodeServerDescription> servers) +J2KEncoder::remake_threads(int openjpeg, int kakadu, int gpu, list<EncodeServerDescription> servers) { - LOG_GENERAL("Making threads: OpenJPEG={}, GPU={}, Remote={}", openjpeg, gpu, servers.size()); - if ((openjpeg + gpu + servers.size()) == 0) { + LOG_GENERAL("Making threads: OpenJPEG={}, Kakadu={}, GPU={}, Remote={}", openjpeg, kakadu, gpu, servers.size()); + if ((openjpeg + kakadu + gpu + servers.size()) == 0) { /* Make at least one thread, even if all else fails. Maybe we are configured * for "only servers encode" but no servers have been registered yet. */ @@ -404,6 +421,24 @@ J2KEncoder::remake_threads(int openjpeg, int gpu, list<EncodeServerDescription> remove_threads(openjpeg, current_openjpeg_threads, is_openjpeg_thread); +#ifdef DCPOMATIC_KAKADU + /* Kakadu (on CPU) */ + + auto const is_kakadu_thread = [](shared_ptr<J2KEncoderThread> thread) { + return static_cast<bool>(dynamic_pointer_cast<KakaduJ2KEncoderThread>(thread)); + }; + + auto const current_kakadu_threads = std::count_if(_threads.begin(), _threads.end(), is_kakadu_thread); + + for (auto i = current_kakadu_threads; i < kakadu; ++i) { + auto thread = make_shared<KakaduJ2KEncoderThread>(*this); + thread->start(); + _threads.push_back(thread); + } + + remove_threads(kakadu, current_kakadu_threads, is_kakadu_thread); +#endif + #ifdef DCPOMATIC_GROK /* GPU */ diff --git a/src/lib/j2k_encoder.h b/src/lib/j2k_encoder.h index 18f7be9e4..130214c2d 100644 --- a/src/lib/j2k_encoder.h +++ b/src/lib/j2k_encoder.h @@ -33,6 +33,9 @@ #include "event_history.h" #include "exception_store.h" #include "j2k_encoder_thread.h" +#ifdef DCPOMATIC_KAKADU +#include "kakadu.h" +#endif #include "writer.h" #include "video_encoder.h" #include <dcp/warnings.h> @@ -94,6 +97,12 @@ public: void retry(DCPVideo frame); void write(std::shared_ptr<const dcp::Data> data, int index, Eyes eyes); +#ifdef DCPOMATIC_KAKADU + KakaduSharedMemory* kakadu_shared_memory() { + return _kakadu_shared_memory; + } +#endif + private: friend struct ::local_threads_created_and_destroyed; friend struct ::remote_threads_created_and_destroyed; @@ -101,7 +110,7 @@ private: void frame_done(); void servers_list_changed(); - void remake_threads(int openjpeg, int gpu, std::list<EncodeServerDescription> servers); + void remake_threads(int openjpeg, int kakadu, int gpu, std::list<EncodeServerDescription> servers); void terminate_threads(); boost::mutex _threads_mutex; @@ -126,6 +135,10 @@ private: std::atomic<bool> _give_up; #endif +#ifdef DCPOMATIC_KAKADU + KakaduSharedMemory* _kakadu_shared_memory = nullptr; +#endif + bool _ending = false; }; diff --git a/src/lib/kakadu.cc b/src/lib/kakadu.cc new file mode 100644 index 000000000..32b05e6e8 --- /dev/null +++ b/src/lib/kakadu.cc @@ -0,0 +1,58 @@ +/* + Copyright (C) 2026 Carl Hetherington <cth@carlh.net> + + 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. + + 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>. + +*/ + + +#include "kakadu.h" + + +KakaduSharedMemory::KakaduSharedMemory() + : _segment(boost::interprocess::open_only, "dcpomatic:kakadu") +{ + +} + + +KakaduSharedMemory::~KakaduSharedMemory() +{ + +} + + +KakaduSharedMetadata* +KakaduSharedMemory::metadata() +{ + return _segment.find<KakaduSharedMetadata>("metadata").first; +} + + +uint16_t* +KakaduSharedMemory::xyz() +{ + return _segment.find<uint16_t>("xyz").first; +} + + +uint8_t* +KakaduSharedMemory::j2k() +{ + return _segment.find<uint8_t>("j2k").first; +} + + diff --git a/src/lib/kakadu.h b/src/lib/kakadu.h new file mode 100644 index 000000000..e9e3e2edf --- /dev/null +++ b/src/lib/kakadu.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2026 Carl Hetherington <cth@carlh.net> + + 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. + + 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>. + +*/ + + +#include <boost/interprocess/managed_shared_memory.hpp> +#include <boost/interprocess/sync/interprocess_mutex.hpp> +#include <boost/interprocess/sync/interprocess_condition.hpp> + + +struct KakaduSharedMetadata +{ + boost::interprocess::interprocess_mutex mutex; + bool request = false; + boost::interprocess::interprocess_condition request_condition; + bool reply = false; + int j2k_size = 0; + boost::interprocess::interprocess_condition reply_condition; +}; + + + +class KakaduSharedMemory +{ +public: + KakaduSharedMemory(); + ~KakaduSharedMemory(); + + KakaduSharedMemory(KakaduSharedMemory const&) = delete; + KakaduSharedMemory& operator=(KakaduSharedMemory const&) = delete; + + KakaduSharedMetadata* metadata(); + uint16_t* xyz(); + uint8_t* j2k(); + +private: + boost::interprocess::managed_shared_memory _segment; +}; + diff --git a/src/lib/kakadu_j2k_encoder_thread.cc b/src/lib/kakadu_j2k_encoder_thread.cc new file mode 100644 index 000000000..d8f2a0530 --- /dev/null +++ b/src/lib/kakadu_j2k_encoder_thread.cc @@ -0,0 +1,78 @@ +/* + Copyright (C) 2026 Carl Hetherington <cth@carlh.net> + + 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. + + 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>. + +*/ + + +#include "cross.h" +#include "dcpomatic_log.h" +#include "dcp_video.h" +#include "j2k_encoder.h" +#include "kakadu_j2k_encoder_thread.h" +#include "util.h" +#include <boost/interprocess/sync/scoped_lock.hpp> + +#include "i18n.h" + + +using std::make_shared; +using std::shared_ptr; + + +KakaduJ2KEncoderThread::KakaduJ2KEncoderThread(J2KEncoder& encoder) + : J2KSyncEncoderThread(encoder) +{ + +} + + +void +KakaduJ2KEncoderThread::log_thread_start() const +{ + start_of_thread("KakaduJ2KEncoder"); + LOG_TIMING("start-encoder-thread thread={} server=localhost", thread_id()); +} + + +shared_ptr<dcp::ArrayData> +KakaduJ2KEncoderThread::encode(DCPVideo const& frame) +{ + auto shmem = _encoder.kakadu_shared_memory(); + if (!shmem) { + LOG_ERROR(N_("Kakadu encode failed (no shared memory)")); + return {}; + } + + auto metadata = shmem->metadata(); + + std::cout << "Send an image.\n"; + boost::interprocess::scoped_lock lm(metadata->mutex); + frame.convert_to_xyz(shmem->xyz()); + + metadata->request = true; + metadata->request_condition.notify_one(); + + while (!metadata->reply) { + metadata->reply_condition.wait(lm); + } + metadata->reply = false; + std::cout << "reading " << metadata->j2k_size << "\n"; + + return make_shared<dcp::ArrayData>(shmem->j2k(), metadata->j2k_size); +} + diff --git a/src/lib/kakadu_j2k_encoder_thread.h b/src/lib/kakadu_j2k_encoder_thread.h new file mode 100644 index 000000000..aac9d338a --- /dev/null +++ b/src/lib/kakadu_j2k_encoder_thread.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2026 Carl Hetherington <cth@carlh.net> + + 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. + + 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>. + +*/ + + +#include "j2k_sync_encoder_thread.h" +#include <dcp/data.h> + + +class DCPVideo; + + +class KakaduJ2KEncoderThread : public J2KSyncEncoderThread +{ +public: + KakaduJ2KEncoderThread(J2KEncoder& encoder); + + void log_thread_start() const override; + std::shared_ptr<dcp::ArrayData> encode(DCPVideo const& frame) override; +}; + diff --git a/src/lib/wscript b/src/lib/wscript index 79393c425..b4fb17eb3 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -276,6 +276,9 @@ def build(bld): if bld.env.ENABLE_GROK: obj.source += ' grok_j2k_encoder_thread.cc grok/util.cc' + if bld.env.ENABLE_KAKADU: + obj.source += ' kakadu.cc kakadu_j2k_encoder_thread.cc' + if bld.env.TARGET_WINDOWS_64 or bld.env.TARGET_WINDOWS_32: obj.uselib += ' WINSOCK2 DBGHELP SHLWAPI MSWSOCK BOOST_LOCALE SETUPAPI OLE32 UUID' obj.source += ' cross_windows.cc i18n_setup_windows.cc' |
