/*** Oak - Non-Linear Video Editor Copyright (C) 2026 Oak Team This program 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 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . ***/ #include "oliveimpl/render/ipc/ipcmessage.h" #include #include #include namespace olive { namespace engine { namespace internal { namespace ipc { bool write_message(QIODevice *device, const QJsonObject &obj) { QByteArray line = QJsonDocument(obj).toJson(QJsonDocument::Compact); line.append('\n'); return device->write(line) == line.size(); } bool read_message(QByteArray *buffer, QJsonObject *out, bool *ok) { while (true) { const int newline = buffer->indexOf('\n'); if (newline < 0) { // No complete line buffered yet. return false; } const QByteArray line = buffer->left(newline); buffer->remove(0, newline + 1); // Skip blank lines silently (e.g. a stray newline) without flagging an error. if (line.trimmed().isEmpty()) { continue; } QJsonParseError err; const QJsonDocument doc = QJsonDocument::fromJson(line, &err); if (err.error != QJsonParseError::NoError || !doc.isObject()) { if (ok) { *ok = false; } return false; } *out = doc.object(); if (ok) { *ok = true; } return true; } } // ---- HandshakeMsg --------------------------------------------------------------------------- QJsonObject HandshakeMsg::to_json() const { QJsonObject o; o["type"] = msgtype::k_handshake; o["protocol_version"] = protocol_version; o["shm_key"] = shm_key; o["input_shm_key"] = input_shm_key; o["input_slots"] = input_slots; o["output_slots"] = output_slots; o["slot_data_bytes"] = double(slot_data_bytes); o["input_slot_data_bytes"] = double(input_slot_data_bytes); return o; } bool HandshakeMsg::from_json(const QJsonObject &o, HandshakeMsg *out) { if (o["type"].toString() != QLatin1String(msgtype::k_handshake)) { return false; } out->protocol_version = o["protocol_version"].toInt(); out->shm_key = o["shm_key"].toString(); out->input_shm_key = o["input_shm_key"].toString(); out->input_slots = o["input_slots"].toInt(); out->output_slots = o["output_slots"].toInt(); out->slot_data_bytes = qint64(o["slot_data_bytes"].toDouble()); out->input_slot_data_bytes = qint64(o["input_slot_data_bytes"].toDouble()); return true; } // ---- RenderFrameMsg ------------------------------------------------------------------------- QJsonObject RenderFrameMsg::to_json() const { QJsonObject o; o["type"] = msgtype::k_render_frame; o["ticket"] = double(ticket_id); o["node"] = node_uuid; o["time_num"] = double(time_num); o["time_den"] = double(time_den); o["width"] = width; o["height"] = height; o["format"] = format; o["channels"] = channel_count; o["mode"] = mode; o["input_slot"] = input_slot; QJsonArray input_slot_array; for (int slot : input_slots) { input_slot_array.append(slot); } o["input_slots"] = input_slot_array; if (has_color_transform) { o["has_color_transform"] = true; o["color_is_display"] = color_is_display; o["color_output"] = color_output; o["color_view"] = color_view; o["color_look"] = color_look; } return o; } bool RenderFrameMsg::from_json(const QJsonObject &o, RenderFrameMsg *out) { if (o["type"].toString() != QLatin1String(msgtype::k_render_frame)) { return false; } out->ticket_id = qint64(o["ticket"].toDouble()); out->node_uuid = o["node"].toString(); out->time_num = qint64(o["time_num"].toDouble()); out->time_den = qint64(o["time_den"].toDouble(1)); out->width = o["width"].toInt(); out->height = o["height"].toInt(); out->format = o["format"].toInt(-1); out->channel_count = o["channels"].toInt(); out->mode = o["mode"].toInt(); out->input_slot = o["input_slot"].toInt(-1); out->input_slots.clear(); const QJsonArray input_slot_array = o["input_slots"].toArray(); for (const QJsonValue &slot : input_slot_array) { out->input_slots.append(slot.toInt(-1)); } if (out->input_slots.isEmpty() && out->input_slot >= 0) { out->input_slots.append(out->input_slot); } out->has_color_transform = o["has_color_transform"].toBool(false); if (out->has_color_transform) { out->color_is_display = o["color_is_display"].toBool(false); out->color_output = o["color_output"].toString(); out->color_view = o["color_view"].toString(); out->color_look = o["color_look"].toString(); } return true; } // ---- FrameReadyMsg -------------------------------------------------------------------------- QJsonObject FrameReadyMsg::to_json() const { QJsonObject o; o["type"] = msgtype::k_frame_ready; o["ticket"] = double(ticket_id); o["slot"] = output_slot; return o; } bool FrameReadyMsg::from_json(const QJsonObject &o, FrameReadyMsg *out) { if (o["type"].toString() != QLatin1String(msgtype::k_frame_ready)) { return false; } out->ticket_id = qint64(o["ticket"].toDouble()); out->output_slot = o["slot"].toInt(); return true; } // ---- CancelMsg ------------------------------------------------------------------------------ QJsonObject CancelMsg::to_json() const { QJsonObject o; o["type"] = msgtype::k_cancel; o["ticket"] = double(ticket_id); return o; } bool CancelMsg::from_json(const QJsonObject &o, CancelMsg *out) { if (o["type"].toString() != QLatin1String(msgtype::k_cancel)) { return false; } out->ticket_id = qint64(o["ticket"].toDouble()); return true; } // ---- LoadGraphMsg --------------------------------------------------------------------------- QJsonObject LoadGraphMsg::to_json() const { QJsonObject o; o["type"] = msgtype::k_load_graph; o["path"] = path; return o; } bool LoadGraphMsg::from_json(const QJsonObject &o, LoadGraphMsg *out) { if (o["type"].toString() != QLatin1String(msgtype::k_load_graph)) { return false; } out->path = o["path"].toString(); return true; } } // namespace ipc } // namespace internal } // namespace engine } // namespace olive