2 Copyright (C) 2023 Grok Image Compression Inc.
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
24 #include "dcpomatic_log.h"
25 #include "grok_messenger.h"
31 using namespace dcpomatic;
33 static std::mutex launchMutex;
35 namespace grk_plugin {
37 struct GrokLogger : public MessengerLogger
39 explicit GrokLogger(const std::string& preamble)
40 : MessengerLogger(preamble)
44 virtual ~GrokLogger() = default;
46 void info(const char* fmt, ...) override
50 dcpomatic_log->log(preamble_ + log_message(fmt, arg), LogEntry::TYPE_GENERAL);
54 void warn(const char* fmt, ...) override
58 dcpomatic_log->log(preamble_ + log_message(fmt, arg), LogEntry::TYPE_WARNING);
62 void error(const char* fmt, ...) override
66 dcpomatic_log->log(preamble_ + log_message(fmt, arg), LogEntry::TYPE_ERROR);
71 struct GrokInitializer
75 setMessengerLogger(new GrokLogger("[GROK] "));
78 ~GrokInitializer() = default;
84 : FrameProxy(0, Eyes::LEFT, DCPVideo())
88 FrameProxy(int index, Eyes eyes, DCPVideo dcpv)
100 Eyes eyes(void) const
110 struct DcpomaticContext
112 DcpomaticContext(std::shared_ptr<const Film> film, Writer& writer,
113 EventHistory& history, const std::string& location)
117 , location_(location)
123 void setDimensions(uint32_t w, uint32_t h)
129 std::shared_ptr<const Film> film_;
131 EventHistory& history_;
132 std::string location_;
140 explicit GrokContext(const DcpomaticContext& dcpomaticContext)
141 : dcpomaticContext_(dcpomaticContext)
142 , messenger_(nullptr)
145 struct CompressedData : public dcp::Data
147 explicit CompressedData(int dataLen)
148 : data_(new uint8_t[dataLen])
153 ~CompressedData(void)
158 uint8_t const* data() const override
163 uint8_t* data() override
168 int size() const override
177 if (Config::instance()->enable_gpu()) {
178 boost::filesystem::path folder(dcpomaticContext_.location_);
179 boost::filesystem::path binaryPath = folder / "grk_compress";
180 if (!boost::filesystem::exists(binaryPath)) {
181 getMessengerLogger()->error("Invalid binary location %s",
182 dcpomaticContext_.location_.c_str());
185 auto proc = [this](const std::string& str) {
188 auto tag = msg.next();
189 if (tag == GRK_MSGR_BATCH_SUBMIT_COMPRESSED) {
190 auto clientFrameId = msg.nextUint();
191 auto compressedFrameId = msg.nextUint();
192 (void)compressedFrameId;
193 auto compressedFrameLength = msg.nextUint();
195 [this](FrameProxy srcFrame, uint8_t* compressed, uint32_t compressedFrameLength) {
196 auto compressedData = std::make_shared<CompressedData>(compressedFrameLength);
197 memcpy(compressedData->data_, compressed, compressedFrameLength);
198 dcpomaticContext_.writer_.write(compressedData, srcFrame.index(), srcFrame.eyes());
201 int const minimum_size = 16384;
202 bool needsRecompression = compressedFrameLength < minimum_size;
203 messenger_->processCompressed(str, processor, needsRecompression);
204 if (needsRecompression) {
205 bool success = false;
206 auto fp = messenger_->retrieve(clientFrameId, success);
210 auto encoded = std::make_shared<dcp::ArrayData>(fp.vf.encode_locally());
211 dcpomaticContext_.writer_.write(encoded, fp.vf.index(), fp.vf.eyes());
215 } catch (std::exception& ex) {
216 getMessengerLogger()->error("%s", ex.what());
220 MessengerInit(clientToGrokMessageBuf, clientSentSynch, grokReceiveReadySynch,
221 grokToClientMessageBuf, grokSentSynch, clientReceiveReadySynch, proc,
222 std::thread::hardware_concurrency());
223 messenger_ = new ScheduledMessenger<FrameProxy>(clientInit);
232 bool launch(DCPVideo dcpv, int device)
238 std::unique_lock<std::mutex> lk_global(launchMutex);
243 if (MessengerInit::firstLaunch(true)) {
244 auto s = dcpv.get_size();
245 dcpomaticContext_.setDimensions(s.width, s.height);
246 auto config = Config::instance();
247 messenger_->launchGrok(dcpomaticContext_.location_,
248 dcpomaticContext_.width_, dcpomaticContext_.width_,
249 dcpomaticContext_.height_,
251 dcpomaticContext_.film_->resolution() == Resolution::FOUR_K,
252 dcpomaticContext_.film_->video_frame_rate(),
253 dcpomaticContext_.film_->j2k_bandwidth(),
254 config->gpu_license_server(),
255 config->gpu_license_port(),
256 config->gpu_license());
258 launched_ = messenger_->waitForClientInit();
263 bool scheduleCompress(const DCPVideo& vf)
268 auto fp = FrameProxy(vf.index(), vf.eyes(), vf);
269 auto cvt = [this, &fp](BufferSrc src) {
271 fp.vf.convert_to_xyz((uint16_t*)src.framePtr_);
273 return messenger_->scheduleCompress(fp, cvt);
281 std::unique_lock<std::mutex> lk_global(launchMutex);
285 messenger_->shutdown();
287 messenger_ = nullptr;
292 dcpomaticContext_.history_.event();
296 DcpomaticContext dcpomaticContext_;
297 ScheduledMessenger<FrameProxy>* messenger_;
301 } // namespace grk_plugin