/* 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 . */ #include "grok_context.h" #include 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 film_, Writer& writer_, EventHistory& history_, const boost::optional& 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) { 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 compressed_data = std::make_shared(compressedFrameLength); memcpy(compressed_data->data(), compressed, compressedFrameLength); _dcpomatic_context.writer.write(compressed_data, 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(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(clientInit); } } GrokContext::~GrokContext() { shutdown(); } bool GrokContext::launch(DCPVideo dcpv, int device) { if (!_messenger) { return false; } if (_launched) { return true; } std::unique_lock 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 lk_global(launchMutex); if (!_messenger) { return; } if (_launched) { _messenger->shutdown(); } delete _messenger; _messenger = nullptr; } void GrokContext::frame_done() { _dcpomatic_context.history.event(); }