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 static std::mutex launchMutex;
33 namespace grk_plugin {
35 struct GrokLogger : public MessengerLogger
37 explicit GrokLogger(const std::string& preamble)
38 : MessengerLogger(preamble)
42 virtual ~GrokLogger() = default;
44 void info(const char* fmt, ...) override
48 dcpomatic_log->log(preamble_ + log_message(fmt, arg), LogEntry::TYPE_GENERAL);
52 void warn(const char* fmt, ...) override
56 dcpomatic_log->log(preamble_ + log_message(fmt, arg), LogEntry::TYPE_WARNING);
60 void error(const char* fmt, ...) override
64 dcpomatic_log->log(preamble_ + log_message(fmt, arg), LogEntry::TYPE_ERROR);
69 struct GrokInitializer
73 setMessengerLogger(new GrokLogger("[GROK] "));
76 ~GrokInitializer() = default;
82 : FrameProxy(0, Eyes::LEFT, DCPVideo())
86 FrameProxy(int index, Eyes eyes, DCPVideo dcpv)
108 struct DcpomaticContext
110 DcpomaticContext(std::shared_ptr<const Film> film, Writer& writer,
111 EventHistory& history, const std::string& location)
115 , location_(location)
121 void set_dimensions(uint32_t w, uint32_t h)
127 std::shared_ptr<const Film> film_;
129 EventHistory& history_;
130 std::string location_;
138 explicit GrokContext(const DcpomaticContext& dcpomaticContext)
139 : _dcpomatic_context(dcpomaticContext)
140 , _messenger(nullptr)
143 struct CompressedData : public dcp::Data
145 explicit CompressedData(int dataLen)
146 : data_(new uint8_t[dataLen])
156 uint8_t const* data() const override
161 uint8_t* data() override
166 int size() const override
175 if (Config::instance()->enable_gpu()) {
176 boost::filesystem::path folder(_dcpomatic_context.location_);
177 boost::filesystem::path binaryPath = folder / "grk_compress";
178 if (!boost::filesystem::exists(binaryPath)) {
179 getMessengerLogger()->error("Invalid binary location %s",
180 _dcpomatic_context.location_.c_str());
183 auto proc = [this](const std::string& str) {
186 auto tag = msg.next();
187 if (tag == GRK_MSGR_BATCH_SUBMIT_COMPRESSED) {
188 auto clientFrameId = msg.next_uint();
189 auto compressedFrameId = msg.next_uint();
190 (void)compressedFrameId;
191 auto compressedFrameLength = msg.next_uint();
193 [this](FrameProxy srcFrame, uint8_t* compressed, uint32_t compressedFrameLength) {
194 auto compressedData = std::make_shared<CompressedData>(compressedFrameLength);
195 memcpy(compressedData->data_, compressed, compressedFrameLength);
196 _dcpomatic_context.writer_.write(compressedData, srcFrame.index(), srcFrame.eyes());
199 int const minimum_size = 16384;
200 bool needsRecompression = compressedFrameLength < minimum_size;
201 _messenger->process_compressed(str, processor, needsRecompression);
202 if (needsRecompression) {
203 bool success = false;
204 auto fp = _messenger->retrieve(clientFrameId, success);
209 auto encoded = std::make_shared<dcp::ArrayData>(fp.vf.encode_locally());
210 _dcpomatic_context.writer_.write(encoded, fp.vf.index(), fp.vf.eyes());
214 } catch (std::exception& ex) {
215 getMessengerLogger()->error("%s", ex.what());
219 MessengerInit(clientToGrokMessageBuf, clientSentSynch, grokReceiveReadySynch,
220 grokToClientMessageBuf, grokSentSynch, clientReceiveReadySynch, proc,
221 std::thread::hardware_concurrency());
222 _messenger = new ScheduledMessenger<FrameProxy>(clientInit);
231 bool launch(DCPVideo dcpv, int device)
239 std::unique_lock<std::mutex> lk_global(launchMutex);
246 if (MessengerInit::first_launch(true)) {
247 auto s = dcpv.get_size();
248 _dcpomatic_context.set_dimensions(s.width, s.height);
249 auto config = Config::instance();
250 _messenger->launch_grok(_dcpomatic_context.location_,
251 _dcpomatic_context.width_, _dcpomatic_context.width_,
252 _dcpomatic_context.height_,
254 _dcpomatic_context.film_->resolution() == Resolution::FOUR_K,
255 _dcpomatic_context.film_->video_frame_rate(),
256 _dcpomatic_context.film_->j2k_bandwidth(),
257 config->gpu_license_server(),
258 config->gpu_license_port(),
259 config->gpu_license());
261 _launched = _messenger->wait_for_client_init();
266 bool schedule_compress(const DCPVideo& vf)
272 auto fp = FrameProxy(vf.index(), vf.eyes(), vf);
273 auto cvt = [this, &fp](BufferSrc src) {
275 fp.vf.convert_to_xyz((uint16_t*)src.framePtr_);
277 return _messenger->schedule_compress(fp, cvt);
286 std::unique_lock<std::mutex> lk_global(launchMutex);
291 _messenger->shutdown();
294 _messenger = nullptr;
299 _dcpomatic_context.history_.event();
303 DcpomaticContext _dcpomatic_context;
304 ScheduledMessenger<FrameProxy>* _messenger;
308 } // namespace grk_plugin