docs: add build and test instructions
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
# DMF Studio
|
||||
|
||||
Node-based visual production platform for the Dynamic Media Facility architecture.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- CMake 3.24+
|
||||
- C++20 compiler (GCC 12+, Clang 15+)
|
||||
- vcpkg (at `~/vcpkg` or set `CMAKE_TOOLCHAIN_FILE`)
|
||||
- GStreamer (for MXL test tools only)
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
# Configure (from project root)
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$HOME/vcpkg/scripts/buildsystems/vcpkg.cmake \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DBUILD_DOCS=OFF \
|
||||
-DBUILD_TESTS=OFF \
|
||||
-DBUILD_TOOLS=OFF \
|
||||
-DBUILD_UTILS=OFF
|
||||
|
||||
# Build all
|
||||
cmake --build build -j$(nproc)
|
||||
```
|
||||
|
||||
Binaries end up in:
|
||||
- `build/engine/dmf-studio-engine`
|
||||
- `build/nodes/passthrough/dmf-node-passthrough`
|
||||
|
||||
## Rebuild after changes
|
||||
|
||||
```bash
|
||||
# Full rebuild
|
||||
cmake --build build -j$(nproc)
|
||||
|
||||
# Rebuild only one target (faster)
|
||||
cmake --build build -j$(nproc) --target dmf-node-passthrough
|
||||
cmake --build build -j$(nproc) --target dmf-studio-engine
|
||||
```
|
||||
|
||||
## Clean rebuild
|
||||
|
||||
```bash
|
||||
rm -rf build
|
||||
# Then re-run the configure + build steps above
|
||||
```
|
||||
|
||||
## Run unit tests
|
||||
|
||||
```bash
|
||||
build/tests/dmf-test-graph
|
||||
```
|
||||
|
||||
## Test with MXL
|
||||
|
||||
### 1. Create MXL domain
|
||||
|
||||
```bash
|
||||
mkdir -p /tmp/dmf-mxl
|
||||
```
|
||||
|
||||
### 2. Start MXL test source (writes V210 video flow)
|
||||
|
||||
Create a flow config file:
|
||||
|
||||
```bash
|
||||
cat > /tmp/v210_50p.json << 'EOF'
|
||||
{
|
||||
"id": "a0000001-0000-0000-0000-000000000001",
|
||||
"description": "DMF Studio test video flow",
|
||||
"format": "urn:x-nmos:format:video",
|
||||
"label": "DMF Studio Test Video",
|
||||
"tags": {
|
||||
"urn:x-nmos:tag:grouphint/v1.0": ["dmf-studio:Video"]
|
||||
},
|
||||
"media_type": "video/v210",
|
||||
"grain_rate": {"numerator": 50, "denominator": 1},
|
||||
"frame_width": 1920,
|
||||
"frame_height": 1080,
|
||||
"interlace_mode": "progressive",
|
||||
"colorspace": "BT709",
|
||||
"components": [
|
||||
{"name": "Y", "width": 1920, "height": 1080, "bit_depth": 10},
|
||||
{"name": "Cb", "width": 960, "height": 1080, "bit_depth": 10},
|
||||
{"name": "Cr", "width": 960, "height": 1080, "bit_depth": 10}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
Start test source (needs GStreamer + MXL tools built separately):
|
||||
|
||||
```bash
|
||||
mxl-gst-testsrc -d /tmp/dmf-mxl -v /tmp/v210_50p.json --pattern smpte &
|
||||
```
|
||||
|
||||
Check active flows:
|
||||
|
||||
```bash
|
||||
mxl-info --domain /tmp/dmf-mxl
|
||||
```
|
||||
|
||||
### 3. Start passthrough node
|
||||
|
||||
```bash
|
||||
build/nodes/passthrough/dmf-node-passthrough \
|
||||
--node-id pass1 \
|
||||
--control-port 9100 \
|
||||
--mxl-domain /tmp/dmf-mxl
|
||||
```
|
||||
|
||||
Options:
|
||||
- `--node-id, -n` — Unique node instance ID (required)
|
||||
- `--control-port, -p` — WebSocket control port (required)
|
||||
- `--mxl-domain, -d` — MXL domain path (default: `/dev/shm/mxl`)
|
||||
- `--config, -c` — Node config as JSON string
|
||||
|
||||
### 4. Start engine
|
||||
|
||||
```bash
|
||||
export DMF_STUDIO_BIN_DIR=build/nodes/passthrough
|
||||
build/engine/dmf-studio-engine --port 8080
|
||||
```
|
||||
|
||||
### 5. Control via REST API
|
||||
|
||||
```bash
|
||||
# Add nodes
|
||||
curl -X POST http://localhost:8080/api/graph/nodes \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type":"passthrough","id":"pass1"}'
|
||||
|
||||
curl -X POST http://localhost:8080/api/graph/nodes \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type":"passthrough","id":"pass2"}'
|
||||
|
||||
# Connect nodes (creates MXL flow between them)
|
||||
curl -X POST http://localhost:8080/api/graph/edges \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"from_node":"pass1","from_port":"video_out","to_node":"pass2","to_port":"video_in"}'
|
||||
|
||||
# View graph
|
||||
curl http://localhost:8080/api/graph
|
||||
|
||||
# Start all nodes
|
||||
curl -X POST http://localhost:8080/api/graph/start
|
||||
|
||||
# Stop all nodes
|
||||
curl -X POST http://localhost:8080/api/graph/stop
|
||||
|
||||
# Remove node
|
||||
curl -X DELETE http://localhost:8080/api/graph/nodes/pass1
|
||||
|
||||
# Remove edge
|
||||
curl -X DELETE http://localhost:8080/api/graph/edges/pass1:video_out->pass2:video_in
|
||||
```
|
||||
|
||||
### 6. Control node directly via WebSocket
|
||||
|
||||
Connect to `ws://localhost:9100` with subprotocol `dmf-control`:
|
||||
|
||||
```bash
|
||||
wscat -c ws://localhost:9100 -s dmf-control
|
||||
```
|
||||
|
||||
Commands:
|
||||
```json
|
||||
{"cmd": "add_reader", "flow_id": "<uuid>", "port_id": "video_in"}
|
||||
{"cmd": "add_writer", "flow_id": "<uuid>", "port_id": "video_out", "flow_def": {<NMOS flow JSON>}}
|
||||
{"cmd": "remove_reader", "port_id": "video_in"}
|
||||
{"cmd": "remove_writer", "port_id": "video_out"}
|
||||
{"cmd": "configure", "params": {}}
|
||||
{"cmd": "shutdown"}
|
||||
```
|
||||
|
||||
## Project structure
|
||||
|
||||
```
|
||||
libs/dmf-node/ — Node skeleton library (interface, WS control, MXL lifecycle)
|
||||
libs/dmf-engine/ — Engine library (graph model, flow manager, process manager, REST API)
|
||||
nodes/passthrough/ — Passthrough node (1 MXL in → 1 MXL out, memcpy)
|
||||
engine/ — Engine binary
|
||||
tests/ — Unit tests
|
||||
```
|
||||
Reference in New Issue
Block a user