Cleanup: reformat and rename dcpomaticContext_ -> _dcpomatic_context
[dcpomatic.git] / src / lib / grok / context.h
1 /*
2     Copyright (C) 2023 Grok Image Compression Inc.
3
4     This file is part of DCP-o-matic.
5
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.
10
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.
15
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/>.
18
19 */
20
21 #pragma once
22
23 #include "../config.h"
24 #include "../dcp_video.h"
25 #include "../film.h"
26 #include "../log.h"
27 #include "../dcpomatic_log.h"
28 #include "../writer.h"
29 #include "messenger.h"
30 #include <dcp/array_data.h>
31
32
33 static std::mutex launchMutex;
34
35 namespace grk_plugin
36 {
37
38 struct GrokLogger : public MessengerLogger {
39         explicit GrokLogger(const std::string &preamble) : MessengerLogger(preamble)
40         {}
41         virtual ~GrokLogger() = default;
42         void info(const char* fmt, ...) override{
43                 va_list arg;
44                 va_start(arg, fmt);
45                 dcpomatic_log->log(preamble_ + log_message(fmt, arg),LogEntry::TYPE_GENERAL);
46                 va_end(arg);
47         }
48         void warn(const char* fmt, ...) override{
49                 va_list arg;
50                 va_start(arg, fmt);
51                 dcpomatic_log->log(preamble_ + log_message(fmt, arg),LogEntry::TYPE_WARNING);
52                 va_end(arg);
53         }
54         void error(const char* fmt, ...) override{
55                 va_list arg;
56                 va_start(arg, fmt);
57                 dcpomatic_log->log(preamble_ + log_message(fmt, arg),LogEntry::TYPE_ERROR);
58                 va_end(arg);
59         }
60 };
61
62 struct FrameProxy {
63         FrameProxy(int index, Eyes eyes, DCPVideo dcpv) : index_(index), eyes_(eyes), vf(dcpv)
64         {}
65         int index() const {
66                 return index_;
67         }
68         Eyes eyes(void) const {
69                 return eyes_;
70         }
71         int index_;
72         Eyes eyes_;
73         DCPVideo vf;
74 };
75
76 struct DcpomaticContext {
77         DcpomaticContext(
78                 std::shared_ptr<const Film> film,
79                 Writer& writer,
80                 EventHistory& history,
81                 boost::filesystem::path const& location
82                 )
83                 : film_(film)
84                 , writer_(writer)
85                 , history_(history)
86                 , _location(location)
87                 , width_(0)
88                 , height_(0)
89         {
90
91         }
92
93         void setDimensions(uint32_t w, uint32_t h) {
94                 width_ = w;
95                 height_ = h;
96         }
97         std::shared_ptr<const Film> film_;
98         Writer& writer_;
99         EventHistory &history_;
100         boost::filesystem::path _location;
101         uint32_t width_;
102         uint32_t height_;
103 };
104
105
106 class GrokContext
107 {
108 public:
109         explicit GrokContext(DcpomaticContext const& dcpomatic_context)
110                 : _dcpomatic_context(dcpomatic_context)
111                 , messenger_(nullptr)
112                 , launched_(false)
113         {
114                 if (Config::instance()->enable_gpu ())  {
115                     boost::filesystem::path folder(_dcpomatic_context._location);
116                     boost::filesystem::path binaryPath = folder / "grk_compress";
117                     if (!boost::filesystem::exists(binaryPath)) {
118                             getMessengerLogger()->error(
119                                     "Invalid binary location %s", _dcpomatic_context._location.c_str()
120                                     );
121                             return;
122                     }
123                         auto proc = [this](const std::string& str) {
124                                 try {
125                                         Msg msg(str);
126                                         auto tag = msg.next();
127                                         if(tag == GRK_MSGR_BATCH_SUBMIT_COMPRESSED)
128                                         {
129                                                 auto clientFrameId = msg.nextUint();
130                                                 auto compressedFrameId = msg.nextUint();
131                                                 (void)compressedFrameId;
132                                                 auto compressedFrameLength = msg.nextUint();
133                                                 auto  processor =
134                                                                 [this](FrameProxy srcFrame, uint8_t* compressed, uint32_t compressedFrameLength)
135                                                 {
136                                                         auto compressed_data = std::make_shared<dcp::ArrayData>(compressed, compressedFrameLength);
137                                                         _dcpomatic_context.writer_.write(compressed_data, srcFrame.index(), srcFrame.eyes());
138                                                         frame_done ();
139                                                 };
140                                                 int const minimum_size = 16384;
141                                                 bool needsRecompression = compressedFrameLength < minimum_size;
142                                                 messenger_->processCompressed(str, processor, needsRecompression);
143                                                 if (needsRecompression) {
144                                                         auto fp = messenger_->retrieve(clientFrameId);
145                                                         if (!fp) {
146                                                                 return;
147                                                         }
148
149                                                         auto encoded = std::make_shared<dcp::ArrayData>(fp->vf.encode_locally());
150                                                         _dcpomatic_context.writer_.write(encoded, fp->vf.index(), fp->vf.eyes());
151                                                         frame_done ();
152                                                 }
153                                         }
154                                 } catch (std::exception &ex){
155                                         getMessengerLogger()->error("%s",ex.what());
156                                 }
157                         };
158                         auto clientInit =
159                                 MessengerInit(clientToGrokMessageBuf, clientSentSynch, grokReceiveReadySynch,
160                                                           grokToClientMessageBuf, grokSentSynch, clientReceiveReadySynch, proc,
161                                                           std::thread::hardware_concurrency());
162                         messenger_ = new ScheduledMessenger<FrameProxy>(clientInit);
163                 }
164         }
165         ~GrokContext(void) {
166                 shutdown();
167         }
168         bool launch(DCPVideo dcpv, int device){
169                 if (!messenger_ )
170                         return false;
171                 if (launched_)
172                         return true;
173                 std::unique_lock<std::mutex> lk_global(launchMutex);
174                 if (!messenger_)
175                         return false;
176                 if (launched_)
177                         return true;
178                 if (MessengerInit::firstLaunch(true)) {
179                         auto s = dcpv.get_size();
180                         _dcpomatic_context.setDimensions(s.width, s.height);
181                         auto config = Config::instance();
182                         messenger_->launchGrok(
183                                 _dcpomatic_context._location,
184                                 _dcpomatic_context.width_,_dcpomatic_context.width_,
185                                 _dcpomatic_context.height_,
186                                 3, 12, device,
187                                 _dcpomatic_context.film_->resolution() == Resolution::FOUR_K,
188                                 _dcpomatic_context.film_->video_frame_rate(),
189                                 _dcpomatic_context.film_->j2k_bandwidth(),
190                                 config->gpu_license_server(),
191                                 config->gpu_license_port(),
192                                 config->gpu_license()
193                                 );
194                 }
195                 launched_ =  messenger_->waitForClientInit();
196
197                 return launched_;
198         }
199         bool scheduleCompress(DCPVideo const& vf){
200                 if (!messenger_)
201                         return false;
202
203                 auto fp = FrameProxy(vf.index(), vf.eyes(), vf);
204                 auto cvt = [this, &fp](BufferSrc src){
205                         // xyz conversion
206                         fp.vf.convert_to_xyz((uint16_t*)src.framePtr_);
207                 };
208                 return messenger_->scheduleCompress(fp, cvt);
209         }
210         void shutdown(void){
211                 if (!messenger_)
212                         return;
213
214                 std::unique_lock<std::mutex> lk_global(launchMutex);
215                 if (!messenger_)
216                         return;
217                 if (launched_)
218                         messenger_->shutdown();
219                 delete messenger_;
220                 messenger_ = nullptr;
221         }
222         void frame_done () {
223                 _dcpomatic_context.history_.event();
224         }
225 private:
226         DcpomaticContext _dcpomatic_context;
227         ScheduledMessenger<FrameProxy> *messenger_;
228         bool launched_;
229 };
230
231 }
232