143 lines
5.5 KiB
C++
143 lines
5.5 KiB
C++
/***
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
#ifndef IPC_IPCMESSAGE_H
|
|
#define IPC_IPCMESSAGE_H
|
|
|
|
#include <cstdint>
|
|
#include <QByteArray>
|
|
#include <QJsonObject>
|
|
#include <QString>
|
|
|
|
class QIODevice;
|
|
|
|
namespace olive
|
|
{
|
|
namespace ipc
|
|
{
|
|
|
|
/**
|
|
* @brief Control-plane protocol exchanged over stdio between main and render worker.
|
|
*
|
|
* The wire format is NDJSON: one compact QJsonObject per line, terminated by '\n'. This is
|
|
* deliberately human-readable so the channel can be inspected live with `tee`/`cat` and test
|
|
* messages can be injected by hand. The stdio channel carries only low-frequency control traffic;
|
|
* bulk pixel data travels through the shared-memory FrameSlotPool, and the (potentially large)
|
|
* serialized node graph travels via a temporary file referenced by path.
|
|
*
|
|
* Every message object has a "type" string field. Directionality (M = main, W = worker):
|
|
* "handshake" M<->W Negotiate protocol version and announce shared-memory key/geometry.
|
|
* "load_graph" M ->W Path to a temporary file holding the serialized node graph.
|
|
* "render_frame" M ->W Request a frame: node uuid, time, video params.
|
|
* "frame_ready" W ->M A rendered frame is published; carries the output-slot index + ticket.
|
|
* "cancel" M ->W Abandon an in-flight ticket by id.
|
|
* "graph_update" M ->W (Reserved, Phase 6) Incremental graph mutation, mirrors ProjectCopier.
|
|
* "shutdown" M ->W Finish current work and exit cleanly.
|
|
* "error" W ->M Worker-side failure report (human-readable "message" field).
|
|
*/
|
|
namespace msgtype
|
|
{
|
|
constexpr const char *kHandshake = "handshake";
|
|
constexpr const char *kLoadGraph = "load_graph";
|
|
constexpr const char *kRenderFrame = "render_frame";
|
|
constexpr const char *kFrameReady = "frame_ready";
|
|
constexpr const char *kCancel = "cancel";
|
|
constexpr const char *kGraphUpdate = "graph_update";
|
|
constexpr const char *kShutdown = "shutdown";
|
|
constexpr const char *kError = "error";
|
|
} // namespace msgtype
|
|
|
|
/**
|
|
* @brief Write one NDJSON message line to `device`.
|
|
*
|
|
* Serializes `obj` to compact JSON, appends '\n', and writes the whole line in one call. Returns
|
|
* true only if the full line was written.
|
|
*/
|
|
bool WriteMessage(QIODevice *device, const QJsonObject &obj);
|
|
|
|
/**
|
|
* @brief Pull one complete NDJSON line out of `buffer` and parse it.
|
|
*
|
|
* If `buffer` contains at least one '\n', the leading line is removed, parsed as JSON, and returned
|
|
* via `out` (true). If no complete line is buffered yet, leaves `buffer` untouched and returns
|
|
* false. Malformed lines are skipped (removed) and reported via `*ok = false` so the reader can log
|
|
* and continue rather than wedge. Supports the typical "append bytes as they arrive, then drain
|
|
* complete lines" reader loop on a pipe.
|
|
*/
|
|
bool ReadMessage(QByteArray *buffer, QJsonObject *out, bool *ok = nullptr);
|
|
|
|
// ---- Typed message builders / parsers -------------------------------------------------------
|
|
//
|
|
// Thin helpers that construct or read the QJsonObject for each message type, keeping field names in
|
|
// one place so main and worker agree. Fields use plain JSON numbers/strings; 64-bit ids are stored
|
|
// as JSON numbers (doubles exactly represent integers up to 2^53, ample for our counters).
|
|
|
|
struct HandshakeMsg {
|
|
int protocol_version = 0;
|
|
QString shm_key; ///< Shared-memory segment key for this worker.
|
|
int input_slots = 0; ///< Number of main->worker input frame slots.
|
|
int output_slots = 0; ///< Number of worker->main output frame slots.
|
|
qint64 slot_data_bytes = 0; ///< Per-slot pixel block size (max frame size).
|
|
|
|
QJsonObject ToJson() const;
|
|
static bool FromJson(const QJsonObject &o, HandshakeMsg *out);
|
|
};
|
|
|
|
struct RenderFrameMsg {
|
|
qint64 ticket_id = 0; ///< Correlates this request with the eventual frame_ready.
|
|
QString node_uuid; ///< Output/viewer node to render, by stable uuid in the loaded graph.
|
|
qint64 time_num = 0;
|
|
qint64 time_den = 1;
|
|
int width = 0; ///< Forced output size (0 = use graph default).
|
|
int height = 0;
|
|
int format = -1; ///< Forced PixelFormat::Format (-1 = default/INVALID).
|
|
int channel_count = 0; ///< 0 = default.
|
|
int mode = 0; ///< RenderMode::Mode.
|
|
|
|
QJsonObject ToJson() const;
|
|
static bool FromJson(const QJsonObject &o, RenderFrameMsg *out);
|
|
};
|
|
|
|
struct FrameReadyMsg {
|
|
qint64 ticket_id = 0;
|
|
int output_slot = 0; ///< Index into the worker->main output FrameSlotPool.
|
|
|
|
QJsonObject ToJson() const;
|
|
static bool FromJson(const QJsonObject &o, FrameReadyMsg *out);
|
|
};
|
|
|
|
struct CancelMsg {
|
|
qint64 ticket_id = 0;
|
|
|
|
QJsonObject ToJson() const;
|
|
static bool FromJson(const QJsonObject &o, CancelMsg *out);
|
|
};
|
|
|
|
struct LoadGraphMsg {
|
|
QString path; ///< Temporary file holding the serialized node graph.
|
|
|
|
QJsonObject ToJson() const;
|
|
static bool FromJson(const QJsonObject &o, LoadGraphMsg *out);
|
|
};
|
|
|
|
} // namespace ipc
|
|
} // namespace olive
|
|
|
|
#endif // IPC_IPCMESSAGE_H
|