# Holistic Record

This example demonstrates how to record all selected input streams (such as video and IMU data) holistically during a DepthAI
pipeline run, enabling full replay for development and testing.

This example requires the DepthAI v3 API, see [installation instructions](https://docs.luxonis.com/software-v3/depthai.md).

## Pipeline

## Source code

#### Python

```python
#!/usr/bin/env python3

import cv2
import depthai as dai
import argparse
from pathlib import Path

parser = argparse.ArgumentParser()
parser.add_argument("-o", "--output", default="recordings", help="Output path")
parser.add_argument("-fps", "--fps", default=30, type=int, help="FPS for recording")
args = parser.parse_args()

# Create output directory if it doesn't exist
Path(args.output).mkdir(parents=True, exist_ok=True)

# Create pipeline
with dai.Pipeline(True) as pipeline:
    config = dai.RecordConfig()
    config.outputDir = args.output
    # config.videoEncoding.enabled = True
    # config.videoEncoding.bitrate = 0 # Automatic
    # config.videoEncoding.profile = dai.VideoEncoderProperties.Profile.H264_MAIN

    pipeline.enableHolisticRecord(config)

    # Define source and output
    camA = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_A)
    camAOut = camA.requestFullResolutionOutput(fps=args.fps)
    camB = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_B)
    camBOut = camB.requestFullResolutionOutput(fps=args.fps)
    camC = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_C)
    camCOut = camC.requestFullResolutionOutput(fps=args.fps)

    viewFinderOut = camA.requestOutput((640, 480), fps=args.fps)

    imu = pipeline.create(dai.node.IMU)
    imu.enableIMUSensor(dai.IMUSensor.ACCELEROMETER_RAW, 400)
    imu.enableIMUSensor(dai.IMUSensor.GYROSCOPE_RAW, 400)
    imu.setBatchReportThreshold(100)

    sync = pipeline.create(dai.node.Sync)
    sync.setSyncAttempts(0)
    camAOut.link(sync.inputs["camA"])
    camBOut.link(sync.inputs["camB"])
    camCOut.link(sync.inputs["camC"])

    viewFinderQueue = viewFinderOut.createOutputQueue()

    # Connect to device and start pipeline
    pipeline.start()
    try:
        while pipeline.isRunning():
            frame = viewFinderQueue.get()
            cv2.imshow("video", frame.getCvFrame())
            if cv2.waitKey(1) == ord('q'):
                break
    except KeyboardInterrupt:
        pass

    pipeline.stop()
```

#### C++

```cpp
#include <atomic>
#include <csignal>
#include <filesystem>
#include <opencv2/highgui.hpp>

#include "depthai/common/CameraBoardSocket.hpp"
#include "depthai/depthai.hpp"
#include "depthai/utility/RecordReplay.hpp"
#include "utility.hpp"
#ifndef DEPTHAI_MERGED_TARGET
    #error This example needs OpenCV support, which is not available on your system
#endif

// Signal handling for clean shutdown
static std::atomic<bool> isRunning = true;
void signalHandler(int signum) {
    (void)signum;
    isRunning = false;
}

int main(int argc, char** argv) {
    // Register signal handler
    std::signal(SIGINT, signalHandler);

    dai::Pipeline pipeline;

    dai::RecordConfig config;
    config.outputDir = argc > 1 ? std::string(argv[1]) : getDefaultRecordingPath();
    // config.videoEncoding.enabled = true;  // Use video encoding
    // config.videoEncoding.bitrate = 0;     // Automatic
    // config.videoEncoding.profile = dai::VideoEncoderProperties::Profile::H264_MAIN;

    pipeline.enableHolisticRecord(config);

    auto camA = pipeline.create<dai::node::Camera>()->build(dai::CameraBoardSocket::CAM_A);
    auto* camAOut = camA->requestFullResolutionOutput(std::nullopt, 10);
    auto camB = pipeline.create<dai::node::Camera>()->build(dai::CameraBoardSocket::CAM_B);
    auto* camBOut = camB->requestFullResolutionOutput(std::nullopt, 10);
    auto camC = pipeline.create<dai::node::Camera>()->build(dai::CameraBoardSocket::CAM_C);
    auto* camCOut = camC->requestFullResolutionOutput(std::nullopt, 10);

    auto* viewFinderOut = camA->requestOutput({640, 480});

    auto imu = pipeline.create<dai::node::IMU>();

    // enable ACCELEROMETER_RAW at 400 hz rate
    imu->enableIMUSensor(dai::IMUSensor::ACCELEROMETER_RAW, 400);
    // enable GYROSCOPE_RAW at 400 hz rate
    imu->enableIMUSensor(dai::IMUSensor::GYROSCOPE_RAW, 400);
    imu->setBatchReportThreshold(100);

    // Discard frames by passing through sync
    auto sync = pipeline.create<dai::node::Sync>();
    sync->setSyncAttempts(0);  // Don't wait for frames to sync
    camAOut->link(sync->inputs["camA"]);
    camBOut->link(sync->inputs["camB"]);
    camCOut->link(sync->inputs["camC"]);

    auto viewFinderQueue = viewFinderOut->createOutputQueue();

    pipeline.start();

    while(isRunning && pipeline.isRunning()) {
        auto frame = viewFinderQueue->get<dai::ImgFrame>();
        if(!frame) continue;
        cv::imshow("Video", frame->getCvFrame());
        auto key = cv::waitKey(10);
        if(key == 'q') {
            break;
        }
    }

    pipeline.stop();
}
```

### Need assistance?

Head over to [Discussion Forum](https://discuss.luxonis.com/) for technical support or any other questions you might have.
