Move some stuff from grok_context.h to a .cc.
[dcpomatic.git] / src / lib / grok_context.cc
diff --git a/src/lib/grok_context.cc b/src/lib/grok_context.cc
new file mode 100644 (file)
index 0000000..b13ab08
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+    Copyright (C) 2023 Grok Image Compression Inc.
+
+    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 "grok_context.h"
+
+
+using namespace grk_plugin;
+
+
+GrokLogger::GrokLogger(const std::string& preamble)
+       : MessengerLogger(preamble)
+{
+
+}
+
+
+void
+GrokLogger::info(const char* fmt, ...)
+{
+       va_list arg;
+       va_start(arg, fmt);
+       dcpomatic_log->log(preamble_ + log_message(fmt, arg), LogEntry::TYPE_GENERAL);
+       va_end(arg);
+}
+
+
+void
+GrokLogger::warn(const char* fmt, ...)
+{
+       va_list arg;
+       va_start(arg, fmt);
+       dcpomatic_log->log(preamble_ + log_message(fmt, arg), LogEntry::TYPE_WARNING);
+       va_end(arg);
+}
+
+
+void
+GrokLogger::error(const char* fmt, ...)
+{
+       va_list arg;
+       va_start(arg, fmt);
+       dcpomatic_log->log(preamble_ + log_message(fmt, arg), LogEntry::TYPE_ERROR);
+       va_end(arg);
+}
+
+
+GrokInitializer::GrokInitializer()
+{
+       set_messenger_logger(new GrokLogger("[GROK] "));
+}
+
+
+FrameProxy::FrameProxy()
+       : FrameProxy(0, Eyes::LEFT, DCPVideo())
+{
+
+}
+
+
+FrameProxy::FrameProxy(int index, Eyes eyes, DCPVideo dcpv)
+       : _index(index)
+       , _eyes(eyes)
+       , _vf(dcpv)
+{
+
+}
+
+
+DcpomaticContext::DcpomaticContext(
+       std::shared_ptr<const Film> film_,
+       Writer& writer_,
+       EventHistory& history_,
+       const boost::optional<boost::filesystem::path>& location_
+       )
+       : film(film_)
+       , writer(writer_)
+       , history(history_)
+       , location(location_)
+       , width(0)
+       , height(0)
+{
+
+}
+
+
+void
+DcpomaticContext::set_dimensions(uint32_t w, uint32_t h)
+{
+       width = w;
+       height = h;
+}
+
+
+GrokContext::GrokContext(const DcpomaticContext& dcpomaticContext)
+       : _dcpomatic_context(dcpomaticContext)
+       , _messenger(nullptr)
+       , _launched(false)
+{
+       struct CompressedData : public dcp::Data
+       {
+               explicit CompressedData(int dataLen)
+                       : data_(new uint8_t[dataLen])
+                       , dataLen_(dataLen)
+               {
+               }
+
+               ~CompressedData()
+               {
+                       delete[] data_;
+               }
+
+               uint8_t const* data() const override
+               {
+                       return data_;
+               }
+
+               uint8_t* data() override
+               {
+                       return data_;
+               }
+
+               int size() const override
+               {
+                       return dataLen_;
+               }
+
+               uint8_t* data_;
+               int dataLen_;
+       };
+
+       if (Config::instance()->enable_gpu()) {
+               DCPOMATIC_ASSERT(_dcpomatic_context.location);
+               boost::filesystem::path folder(*_dcpomatic_context.location);
+               boost::filesystem::path binaryPath = folder / "grk_compress";
+               if (!boost::filesystem::exists(binaryPath)) {
+                       get_messenger_logger()->error("Invalid binary location %s",
+                                                   _dcpomatic_context.location->c_str());
+                       return;
+               }
+               auto proc = [this](const std::string& str) {
+                       try {
+                               Msg msg(str);
+                               auto tag = msg.next();
+                               if (tag == GRK_MSGR_BATCH_SUBMIT_COMPRESSED) {
+                                       auto clientFrameId = msg.next_uint();
+                                       auto compressedFrameId = msg.next_uint();
+                                       (void)compressedFrameId;
+                                       auto compressedFrameLength = msg.next_uint();
+                                       auto processor =
+                                           [this](FrameProxy srcFrame, uint8_t* compressed, uint32_t compressedFrameLength) {
+                                                   auto compressedData = std::make_shared<CompressedData>(compressedFrameLength);
+                                                   memcpy(compressedData->data_, compressed, compressedFrameLength);
+                                                   _dcpomatic_context.writer.write(compressedData, srcFrame.index(), srcFrame.eyes());
+                                                   frame_done();
+                                           };
+                                       int const minimum_size = 16384;
+                                       bool needsRecompression = compressedFrameLength < minimum_size;
+                                       _messenger->process_compressed(str, processor, needsRecompression);
+                                       if (needsRecompression) {
+                                               bool success = false;
+                                               auto fp = _messenger->retrieve(clientFrameId, success);
+                                               if (!success) {
+                                                       return;
+                                               }
+
+                                               auto encoded = std::make_shared<dcp::ArrayData>(fp.vf().encode_locally());
+                                               _dcpomatic_context.writer.write(encoded, fp.vf().index(), fp.vf().eyes());
+                                               frame_done();
+                                       }
+                               }
+                       } catch (std::exception& ex) {
+                               get_messenger_logger()->error("%s", ex.what());
+                       }
+               };
+               auto clientInit =
+                   MessengerInit(clientToGrokMessageBuf, clientSentSynch, grokReceiveReadySynch,
+                                 grokToClientMessageBuf, grokSentSynch, clientReceiveReadySynch, proc,
+                                 std::thread::hardware_concurrency());
+               _messenger = new ScheduledMessenger<FrameProxy>(clientInit);
+       }
+}
+
+
+GrokContext::~GrokContext()
+{
+       shutdown();
+}
+
+
+bool
+GrokContext::launch(DCPVideo dcpv, int device)
+{
+       if (!_messenger) {
+               return false;
+       }
+       if (_launched) {
+               return true;
+       }
+       std::unique_lock<std::mutex> lk_global(launchMutex);
+       if (!_messenger) {
+               return false;
+       }
+       if (_launched) {
+               return true;
+       }
+       if (MessengerInit::first_launch(true)) {
+               auto s = dcpv.get_size();
+               _dcpomatic_context.set_dimensions(s.width, s.height);
+               auto config = Config::instance();
+               DCPOMATIC_ASSERT(_dcpomatic_context.location);
+               DCPOMATIC_ASSERT(config->gpu_license_server());
+               DCPOMATIC_ASSERT(config->gpu_license());
+               _messenger->launch_grok(*_dcpomatic_context.location,
+                                       _dcpomatic_context.width, _dcpomatic_context.width,
+                                       _dcpomatic_context.height,
+                                       3, 12, device,
+                                       _dcpomatic_context.film->resolution() == Resolution::FOUR_K,
+                                       _dcpomatic_context.film->video_frame_rate(),
+                                       _dcpomatic_context.film->j2k_bandwidth(),
+                                       *config->gpu_license_server(),
+                                       config->gpu_license_port(),
+                                       *config->gpu_license());
+       }
+       _launched = _messenger->wait_for_client_init();
+
+       return _launched;
+}
+
+
+bool
+GrokContext::schedule_compress(const DCPVideo& vf)
+{
+       if (!_messenger) {
+               return false;
+       }
+
+       auto fp = FrameProxy(vf.index(), vf.eyes(), vf);
+       auto cvt = [this, &fp](BufferSrc src) {
+               // xyz conversion
+               fp.vf().convert_to_xyz((uint16_t*)src.framePtr_);
+       };
+       return _messenger->schedule_compress(fp, cvt);
+}
+
+void
+GrokContext::shutdown()
+{
+       if (!_messenger) {
+               return;
+       }
+
+       std::unique_lock<std::mutex> lk_global(launchMutex);
+       if (!_messenger) {
+               return;
+       }
+       if (_launched) {
+               _messenger->shutdown();
+       }
+       delete _messenger;
+       _messenger = nullptr;
+}
+
+
+void
+GrokContext::frame_done()
+{
+       _dcpomatic_context.history.event();
+}
+
+