# 解同步脚本输出同步

本示例演示了 DepthAI Sync 节点与 Demux 节点的结合使用，以同步并随后解复用来自两个独立脚本节点的输出。每个脚本节点以不同间隔生成数据缓冲区，这些缓冲区首先由 Sync 节点同步，然后由 MessageDemux 节点解复用。

### 类似示例

 * [多脚本同步](https://docs.luxonis.com/software/depthai/examples/scripts_sync.md)
 * [深度与视频同步](https://docs.luxonis.com/software/depthai/examples/depth_video_sync.md)
 * [IMU 与视频同步](https://docs.luxonis.com/software/depthai/examples/imu_video_sync.md)

## 演示

```bash
~/depthai-python/examples/Sync $ python3 demux_message_group.py
Start
Buffer 1 timestamp: 0:00:03.581073
Buffer 2 timestamp: 0:00:03.591084
----------
Buffer 1 timestamp: 0:00:04.583100
Buffer 2 timestamp: 0:00:04.497079
----------
Buffer 1 timestamp: 0:00:06.587174
Buffer 2 timestamp: 0:00:06.611154
----------
Buffer 1 timestamp: 0:00:07.589147
Buffer 2 timestamp: 0:00:07.517125
----------
Buffer 1 timestamp: 0:00:09.593076
Buffer 2 timestamp: 0:00:09.631089
----------
Buffer 1 timestamp: 0:00:10.595106
Buffer 2 timestamp: 0:00:10.537082
```

## 安装

请运行[安装脚本](https://github.com/luxonis/depthai-python/blob/main/examples/install_requirements.py)以下载所有必需的依赖项。请注意，此脚本必须在 git
上下文中运行，因此您需要先下载 [depthai-python](https://github.com/luxonis/depthai-python) 仓库，然后运行该脚本。

```bash
git clone https://github.com/luxonis/depthai-python.git
cd depthai-python/examples
python3 install_requirements.py
```

更多信息，请参考[安装指南](https://docs.luxonis.com/software/depthai/manual-install.md)。

## 源代码

#### Python

```python
import depthai as dai
import time
from datetime import timedelta

pipeline = dai.Pipeline()

script1 = pipeline.create(dai.node.Script)
script1.setScript("""
from time import sleep

while True:
    sleep(1)
    b = Buffer(512)
    b.setData(bytes(4 * [i for i in range(0, 128)]))
    b.setTimestamp(Clock.now())
    node.io['out'].send(b)
""")

script2 = pipeline.create(dai.node.Script)
script2.setScript("""
from time import sleep

while True:
    sleep(0.3)
    b = Buffer(512)
    b.setData(bytes(4 * [i for i in range(128, 256)]))
    b.setTimestamp(Clock.now())
    node.io['out'].send(b)
""")

sync = pipeline.create(dai.node.Sync)
sync.setSyncThreshold(timedelta(milliseconds=100))

demux = pipeline.create(dai.node.MessageDemux)

xout1 = pipeline.create(dai.node.XLinkOut)
xout1.setStreamName("xout1")
xout2 = pipeline.create(dai.node.XLinkOut)
xout2.setStreamName("xout2")

script1.outputs["out"].link(sync.inputs["s1"])
script2.outputs["out"].link(sync.inputs["s2"])
sync.out.link(demux.input)
demux.outputs["s1"].link(xout1.input)
demux.outputs["s2"].link(xout2.input)

with dai.Device(pipeline) as device:
    print("Start")
    q1 = device.getOutputQueue("xout1", maxSize=10, blocking=True)
    q2 = device.getOutputQueue("xout2", maxSize=10, blocking=True)
    while True:
        bufS1 = q1.get()
        bufS2 = q2.get()
        print(f"Buffer 1 timestamp: {bufS1.getTimestamp()}")
        print(f"Buffer 2 timestamp: {bufS2.getTimestamp()}")
        print("----------")
        time.sleep(0.2)
```

#### C++

```cpp
#include <chrono>
#include <iostream>

#include "depthai/depthai.hpp"

int main() {
    dai::Pipeline pipeline;

    auto script1 = pipeline.create<dai::node::Script>();
    script1->setScript(
        R"SCRPT(
from time import sleep

while True:
    sleep(1)
    b = Buffer(512)
    b.setData(bytes(4 * [i for i in range(0, 128)]))
    b.setTimestamp(Clock.now())
    node.io['out'].send(b)
)SCRPT");

    auto script2 = pipeline.create<dai::node::Script>();
    script2->setScript(
        R"SCRPT(
from time import sleep

while True:
    sleep(0.3)
    b = Buffer(512)
    b.setData(bytes(4 * [i for i in range(128, 256)]))
    b.setTimestamp(Clock.now())
    node.io['out'].send(b)
)SCRPT");

    auto sync = pipeline.create<dai::node::Sync>();
    sync->setSyncThreshold(std::chrono::milliseconds(100));

    auto demux = pipeline.create<dai::node::MessageDemux>();

    auto xout1 = pipeline.create<dai::node::XLinkOut>();
    xout1->setStreamName("xout1");
    auto xout2 = pipeline.create<dai::node::XLinkOut>();
    xout2->setStreamName("xout2");

    script1->outputs["out"].link(sync->inputs["s1"]);
    script2->outputs["out"].link(sync->inputs["s2"]);
    sync->out.link(demux->input);
    demux->outputs["s1"].link(xout1->input);
    demux->outputs["s2"].link(xout2->input);

    dai::Device device(pipeline);
    std::cout << "Start" << std::endl;
    auto queue1 = device.getOutputQueue("xout1", 10, true);
    auto queue2 = device.getOutputQueue("xout2", 10, true);
    while(true) {
        auto bufS1 = queue1->get<dai::Buffer>();
        auto bufS2 = queue2->get<dai::Buffer>();
        std::cout << "Buffer 1 timestamp: " << bufS1->getTimestamp().time_since_epoch().count() << std::endl;
        std::cout << "Buffer 2 timestamp: " << bufS2->getTimestamp().time_since_epoch().count() << std::endl;
        std::cout << "----------" << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
    }
}
```

### 工作原理

 * 初始化一个 DepthAI 管道。
 * 创建两个 Script 节点，每个脚本以不同间隔生成并发送数据缓冲区。
 * 设置一个带有同步阈值的 Sync 节点。
 * 集成一个 MessageDemux 节点，用于分离同步后的数据流。
 * 将 Script 节点的输出链接到 Sync 节点，然后将 Sync 节点链接到 MessageDemux 节点。
 * 启动管道，并持续从 MessageDemux 节点接收解复用后的数据。
 * 打印解复用数据的时间戳以进行比较。

## 管道

### examples/demux_message_group.pipeline.json

```json
{
  "pipeline": {
    "connections": [
      {
        "node1Id": 0,
        "node1Output": "out",
        "node1OutputGroup": "io",
        "node2Id": 2,
        "node2Input": "s1",
        "node2InputGroup": "inputs"
      },
      {
        "node1Id": 1,
        "node1Output": "out",
        "node1OutputGroup": "io",
        "node2Id": 2,
        "node2Input": "s2",
        "node2InputGroup": "inputs"
      },
      {
        "node1Id": 2,
        "node1Output": "out",
        "node1OutputGroup": "",
        "node2Id": 3,
        "node2Input": "input",
        "node2InputGroup": ""
      },
      {
        "node1Id": 3,
        "node1Output": "s1",
        "node1OutputGroup": "outputs",
        "node2Id": 4,
        "node2Input": "in",
        "node2InputGroup": ""
      },
      {
        "node1Id": 3,
        "node1Output": "s2",
        "node1OutputGroup": "outputs",
        "node2Id": 5,
        "node2Input": "in",
        "node2InputGroup": ""
      }
    ],
    "globalProperties": {
      "calibData": null,
      "cameraTuningBlobSize": null,
      "cameraTuningBlobUri": "",
      "leonCssFrequencyHz": 700000000.0,
      "leonMssFrequencyHz": 700000000.0,
      "pipelineName": null,
      "pipelineVersion": null,
      "sippBufferSize": 18432,
      "sippDmaBufferSize": 16384,
      "xlinkChunkSize": -1
    },
    "nodes": [
      [
        0,
        {
          "id": 0,
          "ioInfo": [
            [
              [
                "io",
                "out"
              ],
              {
                "blocking": false,
                "group": "io",
                "id": 1,
                "name": "out",
                "queueSize": 8,
                "type": 0,
                "waitForMessage": false
              }
            ]
          ],
          "name": "Script",
          "properties": {
            "processor": 1,
            "scriptName": "<script>",
            "scriptUri": "asset:__script"
          }
        }
      ],
      [
        1,
        {
          "id": 1,
          "ioInfo": [
            [
              [
                "io",
                "out"
              ],
              {
                "blocking": false,
                "group": "io",
                "id": 2,
                "name": "out",
                "queueSize": 8,
                "type": 0,
                "waitForMessage": false
              }
            ]
          ],
          "name": "Script",
          "properties": {
            "processor": 1,
            "scriptName": "<script>",
            "scriptUri": "asset:__script"
          }
        }
      ],
      [
        2,
        {
          "id": 2,
          "ioInfo": [
            [
              [
                "inputs",
                "s1"
              ],
              {
                "blocking": true,
                "group": "inputs",
                "id": 3,
                "name": "s1",
                "queueSize": 8,
                "type": 3,
                "waitForMessage": false
              }
            ],
            [
              [
                "inputs",
                "s2"
              ],
              {
                "blocking": true,
                "group": "inputs",
                "id": 4,
                "name": "s2",
                "queueSize": 8,
                "type": 3,
                "waitForMessage": false
              }
            ],
            [
              [
                "",
                "out"
              ],
              {
                "blocking": false,
                "group": "",
                "id": 5,
                "name": "out",
                "queueSize": 8,
                "type": 0,
                "waitForMessage": false
              }
            ]
          ],
          "name": "Sync",
          "properties": {
            "syncAttempts": -1,
            "syncThresholdNs": 100000000
          }
        }
      ],
      [
        3,
        {
          "id": 3,
          "ioInfo": [
            [
              [
                "",
                "input"
              ],
              {
                "blocking": true,
                "group": "",
                "id": 6,
                "name": "input",
                "queueSize": 8,
                "type": 3,
                "waitForMessage": false
              }
            ],
            [
              [
                "outputs",
                "s1"
              ],
              {
                "blocking": false,
                "group": "outputs",
                "id": 7,
                "name": "s1",
                "queueSize": 8,
                "type": 0,
                "waitForMessage": false
              }
            ],
            [
              [
                "outputs",
                "s2"
              ],
              {
                "blocking": false,
                "group": "outputs",
                "id": 8,
                "name": "s2",
                "queueSize": 8,
                "type": 0,
                "waitForMessage": false
              }
            ]
          ],
          "name": "MessageDemux",
          "properties": {
            "dummy": 0
          }
        }
      ],
      [
        4,
        {
          "id": 4,
          "ioInfo": [
            [
              [
                "",
                "in"
              ],
              {
                "blocking": true,
                "group": "",
                "id": 9,
                "name": "in",
                "queueSize": 8,
                "type": 3,
                "waitForMessage": true
              }
            ]
          ],
          "name": "XLinkOut",
          "properties": {
            "maxFpsLimit": -1.0,
            "metadataOnly": false,
            "streamName": "xout1"
          }
        }
      ],
      [
        5,
        {
          "id": 5,
          "ioInfo": [
            [
              [
                "",
                "in"
              ],
              {
                "blocking": true,
                "group": "",
                "id": 10,
                "name": "in",
                "queueSize": 8,
                "type": 3,
                "waitForMessage": true
              }
            ]
          ],
          "name": "XLinkOut",
          "properties": {
            "maxFpsLimit": -1.0,
            "metadataOnly": false,
            "streamName": "xout2"
          }
        }
      ]
    ]
  }
}
```

### 需要帮助？

请前往 [OAKChina 官网](https://www.oakchina.cn/) 获取技术支持或解答您的任何疑问。
