This document described the data format used to encode thermal video recordings for the Cacophony Project. The format is designed to efficiently represent thermal video data in a lossless way, and allow for future extensibility.
The data format is binary (non-text). All numbers are represented in little-endian form as this is the byte ordering used on the computer platforms we use.
The data format allows for compression of thermal video frames internally and is then also compressed again using standard gzip compression to obtain higher levels of compression. In order to read data the entire file/stream must be passed through a gzip decompressor first.
Parts of the data format include variable length sections of fields. To allow for the addition of extra fields in the future without breaking existing readers, each field includes its length and a identifying field code. Readers should skip over fields which they don't recognise.
A field is represented as follows:
Name | Length | Type | Description |
---|---|---|---|
Length | 1 | uint8 | Length of the field's data |
Code | 1 | char | Character identifying |
Data | ? | ? | Length & content depends on Length & Code |
The data format always starts with:
- 4 magic bytes: "CPTV"
- 1 byte: version code (1 at this stage)
A single header should come next. It starts with:
- 1 byte indicating the header: "H"
- 1 byte indicating the number of fields in the header.
After these a number of fields will exist.
Name | Length | Code | Type | Description |
---|---|---|---|---|
Timestamp | 8 | 'T' | uint64 | Microseconds since 1970-01-01 UTC |
X resolution | 4 | 'X' | uint32 | Frame X resolution (columns) |
Y resolution | 4 | 'Y' | uint32 | Frame Y resolution (rows) |
Compression | 1 | 'C' | uint8 | Compression scheme in use (0 = uncompressed) |
Unsupported for now but likely to get added as optional fields soon:
- Latitude
- Longitude
- Camera model
One more frames will follow the header. Each frame starts with:
- 1 byte indicating a frame: "F"
- 1 byte indicating the number of fields in the frame.
The following frame fields must exist in every frame:
Name | Length | Code | Type | Description |
---|---|---|---|---|
Offset | 4 | 't' | uint32 | Offset in microseconds to timestamp in header |
Bit width | 1 | 'w' | uint8 | Bit width of the frame data |
Frame size | 4 | 'f' | uint32 | Size of the frame data |
Following the frame fields (as indicated by the field count at the start of the frame) there will be a bytes of frame data. The number of bytes will match the "frame size" header (code 'f') in the frame's fields.
Decoding the frame will involve use of the frame's bit width and the compression scheme indicated in the header. For compression scheme 0 (no compression) read the frame data using the bit width provided. Remember that data is always represented using little-endian ordering.