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/>.
23 #include "../config.h"
24 #include "../dcp_video.h"
26 #include "../dcpomatic_log.h"
27 #include "../writer.h"
28 #include "messenger.h"
32 using namespace dcpomatic;
34 static std::mutex launchMutex;
39 struct GrokLogger : public MessengerLogger {
40 explicit GrokLogger(const std::string &preamble) : MessengerLogger(preamble)
42 virtual ~GrokLogger() = default;
43 void info(const char* fmt, ...) override{
46 dcpomatic_log->log(preamble_ + log_message(fmt, arg),LogEntry::TYPE_GENERAL);
49 void warn(const char* fmt, ...) override{
52 dcpomatic_log->log(preamble_ + log_message(fmt, arg),LogEntry::TYPE_WARNING);
55 void error(const char* fmt, ...) override{
58 dcpomatic_log->log(preamble_ + log_message(fmt, arg),LogEntry::TYPE_ERROR);
63 struct GrokInitializer {
64 GrokInitializer(void) {
65 setMessengerLogger(new GrokLogger("[GROK] "));
67 ~GrokInitializer() = default;
71 FrameProxy(void) : FrameProxy(0,Eyes::LEFT,DCPVideo())
73 FrameProxy(int index, Eyes eyes, DCPVideo dcpv) : index_(index), eyes_(eyes), vf(dcpv)
78 Eyes eyes(void) const {
86 struct DcpomaticContext {
87 DcpomaticContext(std::shared_ptr<const Film> film, Writer& writer,
88 EventHistory &history, const std::string &location) :
89 film_(film), writer_(writer),
90 history_(history), location_(location),
93 void setDimensions(uint32_t w, uint32_t h) {
97 std::shared_ptr<const Film> film_;
99 EventHistory &history_;
100 std::string location_;
107 explicit GrokContext(const DcpomaticContext &dcpomaticContext) :
108 dcpomaticContext_(dcpomaticContext),
112 struct CompressedData : public dcp::Data {
113 explicit CompressedData(int dataLen) : data_(new uint8_t[dataLen]), dataLen_(dataLen)
115 ~CompressedData(void){
118 uint8_t const * data () const override {
121 uint8_t * data () override {
124 int size () const override {
130 if (Config::instance()->enable_gpu ()) {
131 boost::filesystem::path folder(dcpomaticContext_.location_);
132 boost::filesystem::path binaryPath = folder / "grk_compress";
133 if (!boost::filesystem::exists(binaryPath)) {
134 getMessengerLogger()->error("Invalid binary location %s",
135 dcpomaticContext_.location_.c_str());
138 auto proc = [this](const std::string& str) {
141 auto tag = msg.next();
142 if(tag == GRK_MSGR_BATCH_SUBMIT_COMPRESSED)
144 auto clientFrameId = msg.nextUint();
145 auto compressedFrameId = msg.nextUint();
146 (void)compressedFrameId;
147 auto compressedFrameLength = msg.nextUint();
149 [this](FrameProxy srcFrame, uint8_t* compressed, uint32_t compressedFrameLength)
151 auto compressedData = std::make_shared<CompressedData>(compressedFrameLength);
152 memcpy(compressedData->data_,compressed,compressedFrameLength );
153 dcpomaticContext_.writer_.write(compressedData, srcFrame.index(), srcFrame.eyes());
156 int const minimum_size = 16384;
157 bool needsRecompression = compressedFrameLength < minimum_size;
158 messenger_->processCompressed(str, processor, needsRecompression);
159 if (needsRecompression) {
160 bool success = false;
161 auto fp = messenger_->retrieve(clientFrameId, success);
165 auto encoded = std::make_shared<dcp::ArrayData>(fp.vf.encode_locally());
166 dcpomaticContext_.writer_.write(encoded, fp.vf.index(), fp.vf.eyes());
170 } catch (std::exception &ex){
171 getMessengerLogger()->error("%s",ex.what());
175 MessengerInit(clientToGrokMessageBuf, clientSentSynch, grokReceiveReadySynch,
176 grokToClientMessageBuf, grokSentSynch, clientReceiveReadySynch, proc,
177 std::thread::hardware_concurrency());
178 messenger_ = new ScheduledMessenger<FrameProxy>(clientInit);
184 bool launch(DCPVideo dcpv, int device){
189 std::unique_lock<std::mutex> lk_global(launchMutex);
194 if (MessengerInit::firstLaunch(true)) {
195 auto s = dcpv.get_size();
196 dcpomaticContext_.setDimensions(s.width, s.height);
197 auto config = Config::instance();
198 messenger_->launchGrok(dcpomaticContext_.location_,
199 dcpomaticContext_.width_,dcpomaticContext_.width_,
200 dcpomaticContext_.height_,
202 dcpomaticContext_.film_->resolution() == Resolution::FOUR_K,
203 dcpomaticContext_.film_->video_frame_rate(),
204 dcpomaticContext_.film_->j2k_bandwidth(),
205 config->gpu_license_server(),
206 config->gpu_license_port(),
207 config->gpu_license());
209 launched_ = messenger_->waitForClientInit();
213 bool scheduleCompress(const DCPVideo &vf){
217 auto fp = FrameProxy(vf.index(),vf.eyes(),vf);
218 auto cvt = [this, &fp](BufferSrc src){
220 fp.vf.convert_to_xyz((uint16_t*)src.framePtr_);
222 return messenger_->scheduleCompress(fp, cvt);
228 std::unique_lock<std::mutex> lk_global(launchMutex);
232 messenger_->shutdown();
234 messenger_ = nullptr;
237 dcpomaticContext_.history_.event ();
240 DcpomaticContext dcpomaticContext_;
241 ScheduledMessenger<FrameProxy> *messenger_;