> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dwe.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Reading DWVO Recordings

> Play back, export, and parse .dwvo recordings with Python and OpenCV.

<div style={{ marginTop: '-40px' }} />

`.dwvo` is DWE's multi-camera recording container, produced when you record in Discovery. The payload is MJPEG, so every frame in the file is already a complete JPEG — playback is a single `cv2.imdecode`, and export is a byte copy with no re-encoding or quality loss.

<Card title="Recording DWVO in Discovery" icon="video" href="/discovery/misc/dwvo-support" horizontal>
  New to DWVO? Start here to stream and record `.dwvo` files.
</Card>

```
DWE.ai | header: nCameras, width, height, pixelFormat, fps | ext data
block:   uint32 timestamp | per camera: busID\0, uint32 length, JPEG bytes
block:   ...
```

## Prerequisites

* Python (version 3.x)
* `opencv-python`, `numpy`, and `pillow`
* A `.dwvo` recording — the examples below use `test.dwvo`

## Setup

Clone the OpenCV Guides repository and open the folder for this guide, then create a virtual environment and install the dependencies:

<CodeGroup>
  ```bash macOS / Linux theme={null}
  git clone https://github.com/DeepWaterExploration/opencv-guides.git
  cd opencv-guides/4-dwvo-read/python

  python3 -m venv venv
  source venv/bin/activate
  pip install -r requirements.txt
  ```

  ```bash Windows theme={null}
  git clone https://github.com/DeepWaterExploration/opencv-guides.git
  cd opencv-guides\4-dwvo-read\python

  python3 -m venv venv
  venv\Scripts\activate
  pip install -r requirements.txt
  ```
</CodeGroup>

## Playback

`main.py` decodes every camera and shows them side by side in one OpenCV window.

```bash theme={null}
python main.py test.dwvo
python main.py test.dwvo --fps 60 --loop
```

| Argument / key |                                              |
| -------------- | -------------------------------------------- |
| `--fps N`      | Playback rate. Defaults to the header's fps. |
| `--loop`       | Restart at the end of the file.              |
| `space`        | Pause / resume.                              |
| `q` / `esc`    | Quit.                                        |

<Note>
  Playback is anchored to a fixed schedule: if decoding falls a full frame behind, that frame is dropped rather than shown late, so the video stays at wall-clock speed.
</Note>

## Export to JPEGs

Because DWVO already stores MJPEG, `export.py` copies each frame straight to disk — no decode, no quality loss.

```bash theme={null}
python export.py file.dwvo output-folder

# keep every fifth frame
python export.py file.dwvo output-folder --step 5
```

| Argument          |                                                                     |
| ----------------- | ------------------------------------------------------------------- |
| `--step N`        | Keep every Nth frame.                                               |
| `--start-frame N` | First output index, to continue numbering from an earlier sequence. |

Output is one directory per camera, numbered KITTI-style:

```
out/
  image_0/000000.jpg, 000001.jpg, ...
  image_1/000000.jpg, 000001.jpg, ...
  times.txt
```

## Lossless PNG (KITTI dataset)

`dwvo_to_kitti.py` produces the same layout but decodes through Pillow so it can emit lossless PNG. Use it when a downstream tool won't accept JPEG; otherwise `export.py` is faster.

```bash theme={null}
python dwvo_to_kitti.py test.dwvo out          # PNG
python dwvo_to_kitti.py test.dwvo out --jpeg   # same zero-copy JPEG as export.py
```

## Reading DWVO programmatically

In `dwvo.py`, `DWVOReader` iterates timestamp blocks, `DWVOWriter` writes them, and `combine_dwvos()` concatenates recordings that share a header.

```python theme={null}
from pathlib import Path
from dwvo import DWVOReader

with DWVOReader(Path("test.dwvo")) as reader:
    print(reader.header.n_cameras, reader.header.width, reader.header.height)
    for block in reader.iter_blocks():
        for frame in block.video_frames:   # one per camera
            frame.bus_id, frame.data       # "0" / "1", raw JPEG bytes
```

## FAQ

<AccordionGroup>
  <Accordion title="Why is the video slower than what I recorded?">
    In Discovery, some cameras require setting the FPS manually. If it was set to 30 FPS while the video was streamed at 60 FPS, the `.dwvo` file records 30 FPS in its metadata and tells applications to read at 30 FPS. Override it at playback with `--fps`.
  </Accordion>
</AccordionGroup>

## Further information

For additional details, examples in other languages, and the full source of the scripts above, see the OpenCV Guides repository.

<Card title="OpenCV Guides Repository" icon="Github" href="https://github.com/DeepWaterExploration/opencv-guides">
  DWVO reader, playback, export, and KITTI conversion source.
</Card>
