/*** 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 "ipcmessage.h" #include #include #include namespace olive { namespace ipc { bool WriteMessage(QIODevice *device, const QJsonObject &obj) { QByteArray line = QJsonDocument(obj).toJson(QJsonDocument::Compact); line.append('\n'); return device->write(line) == line.size(); } bool ReadMessage(QByteArray *buffer, QJsonObject *out, bool *ok) { 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()) { if (ok) { *ok = false; } return false; } 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::ToJson() const { QJsonObject o; o["type"] = msgtype::kHandshake; 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::FromJson(const QJsonObject &o, HandshakeMsg *out) { if (o["type"].toString() != QLatin1String(msgtype::kHandshake)) { 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::ToJson() const { QJsonObject o; o["type"] = msgtype::kRenderFrame; 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; return o; } bool RenderFrameMsg::FromJson(const QJsonObject &o, RenderFrameMsg *out) { if (o["type"].toString() != QLatin1String(msgtype::kRenderFrame)) { 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); } return true; } // ---- FrameReadyMsg -------------------------------------------------------------------------- QJsonObject FrameReadyMsg::ToJson() const { QJsonObject o; o["type"] = msgtype::kFrameReady; o["ticket"] = double(ticket_id); o["slot"] = output_slot; return o; } bool FrameReadyMsg::FromJson(const QJsonObject &o, FrameReadyMsg *out) { if (o["type"].toString() != QLatin1String(msgtype::kFrameReady)) { return false; } out->ticket_id = qint64(o["ticket"].toDouble()); out->output_slot = o["slot"].toInt(); return true; } // ---- CancelMsg ------------------------------------------------------------------------------ QJsonObject CancelMsg::ToJson() const { QJsonObject o; o["type"] = msgtype::kCancel; o["ticket"] = double(ticket_id); return o; } bool CancelMsg::FromJson(const QJsonObject &o, CancelMsg *out) { if (o["type"].toString() != QLatin1String(msgtype::kCancel)) { return false; } out->ticket_id = qint64(o["ticket"].toDouble()); return true; } // ---- LoadGraphMsg --------------------------------------------------------------------------- QJsonObject LoadGraphMsg::ToJson() const { QJsonObject o; o["type"] = msgtype::kLoadGraph; o["path"] = path; return o; } bool LoadGraphMsg::FromJson(const QJsonObject &o, LoadGraphMsg *out) { if (o["type"].toString() != QLatin1String(msgtype::kLoadGraph)) { return false; } out->path = o["path"].toString(); return true; } } // namespace ipc } // namespace olive