2019-09-06 17:07:21 +08:00
|
|
|
# Recorder Binary File Format
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
The recorder system saves all the info needed to replay the simulation in a binary file,
|
|
|
|
using little endian byte order for the multibyte values.
|
|
|
|
In the next image representing the file format, we can get a quick view of all the detailed
|
|
|
|
information. Each part that is visualized in the image will be explained in the following sections:
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![file format 1](img/RecorderFileFormat1.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
In summary, the file format has a small header with general info
|
|
|
|
(version, magic string, date and the map used) and a collection of packets of different types
|
|
|
|
(currently we use 10 types, but that will continue growing up in the future).
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![global file format](img/RecorderFileFormat3.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
## 1. Strings in binary
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
Strings are encoded first with the length of it, followed by its characters without null
|
|
|
|
character ending. For example, the string 'Town06' will be saved
|
|
|
|
as hex values: 06 00 54 6f 77 6e 30 36
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![binary dynamic string](img/RecorderString.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
## 2. Info header
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
The info header has general information about the recorded file. Basically, it contains the version
|
|
|
|
and a magic string to identify the file as a recorder file. If the header changes then the version
|
|
|
|
will change also. Furthermore, it contains a date timestamp, with the number of seconds from the
|
|
|
|
Epoch 1900, and also it contains a string with the name of the map that has been used for recording.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![info header](img/RecorderInfoHeader.png)
|
|
|
|
|
|
|
|
A sample info header is:
|
|
|
|
|
|
|
|
![info header sample](img/RecorderHeader.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
## 3. Packets
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
Each packet starts with a little header of two fields (5 bytes):
|
|
|
|
|
|
|
|
![packet header](img/RecorderPacketHeader.png)
|
|
|
|
|
2019-07-05 21:02:17 +08:00
|
|
|
* **id**: The packet type
|
|
|
|
* **size**: Size of packet data
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-07-05 21:02:17 +08:00
|
|
|
Header information is then followed by the **data**.
|
2019-07-02 23:04:42 +08:00
|
|
|
The **data** is optional, a **size** of 0 means there is no **data** in the packet.
|
2019-09-06 17:07:21 +08:00
|
|
|
If the **size** is greater than 0 it means that the packet has **data** bytes. Therefore,
|
|
|
|
the **data** needs to be reinterpreted depending on the type of the packet.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
The header of the packet is useful because we can just ignore those packets we are not interested
|
|
|
|
in when doing playback. We only need to read the header (first 5 bytes) of the packet and jump to
|
|
|
|
the next packet just skipping the data of the packet:
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![packets size](img/RecorderPackets.png)
|
|
|
|
|
|
|
|
The types of packets are:
|
|
|
|
|
|
|
|
![packets type list](img/RecorderPacketsList.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
We suggest to use **id** over 100 for user custom packets, because this list will keep growing in
|
|
|
|
the future.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
### 3.1 Packet 0: Frame Start
|
2019-04-26 17:46:38 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
This packet marks the start of a new frame, and it will be the first one to start each frame.
|
|
|
|
All packets need to be placed between a **Frame Start** and a **Frame End**.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![frame start](img/RecorderFrameStart.png)
|
|
|
|
|
|
|
|
So, elapsed + durationThis = elapsed time for next frame
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
### 3.2 Packet 1: Frame End
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
This frame has no data and it only marks the end of the current frame. That helps the replayer
|
|
|
|
to know the end of each frame just before the new one starts.
|
2019-07-05 21:02:17 +08:00
|
|
|
Usually, the next frame should be a Frame Start packet to start a new frame.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![frame end](img/RecorderFrameEnd.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
### 3.3 Packet 2: Event Add
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-07-05 21:02:17 +08:00
|
|
|
This packet says how many actors we need to create at current frame.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![event add](img/RecorderEventAdd.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
The field **total** says how many records follow. Each record starts with the **id** field,
|
|
|
|
that is the id the actor has when it was recorded (on playback that id could change internally,
|
|
|
|
but we need to use this id ). The **type** of actor can have these possible values:
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
* 0 = Other
|
|
|
|
* 1 = Vehicle
|
|
|
|
* 2 = Walker
|
|
|
|
* 3 = TrafficLight
|
|
|
|
* 4 = INVALID
|
|
|
|
|
2019-07-05 21:02:17 +08:00
|
|
|
After that, the **location** and the **rotation** where we want to create the actor is proceeded.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
Right after we have the **description** of the actor. The description **uid** is the numeric id of
|
|
|
|
the description and the **id** is the textual id, like 'vehicle.seat.leon'.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
Then comes a collection of its **attributes** like color, number of wheels, role, etc.
|
|
|
|
The number of attributes is variable and should look similar to this:
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
* number_of_wheels = 4
|
|
|
|
* sticky_control = true
|
|
|
|
* color = 79,33,85
|
|
|
|
* role_name = autopilot
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
### 3.4 Packet 3: Event Del
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-07-05 21:02:17 +08:00
|
|
|
This packet says how many actors need to be destroyed this frame.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![event del](img/RecorderEventDel.png)
|
|
|
|
|
|
|
|
It has the **total** of records, and each record has the **id** of the actor to remove.
|
|
|
|
|
|
|
|
For example, this packet could be like this:
|
|
|
|
|
|
|
|
![event del](img/RecorderPacketSampleEventDel.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
The number 3 identifies the packet as (Event Del). The number 16 is the size of the data of
|
|
|
|
the packet (4 fields of 4 bytes each). So if we don't want to process this packet, we could skip
|
|
|
|
the next 16 bytes and will be directly to the start of the next packet.
|
|
|
|
The next 3 says the total records that follows, and each record is the id of the actor to remove.
|
|
|
|
So, we need to remove at this frame the actors 100, 101 and 120.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
### 3.5 Packet 4: Event Parent
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-07-05 21:02:17 +08:00
|
|
|
This packet says which actor is the child of another (the parent).
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![event parent](img/RecorderEventParent.png)
|
|
|
|
|
|
|
|
The first id is the child actor, and the second one will be the parent actor.
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
### 3.6 Packet 5: Event Collision
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
If a collision happens between two actors, it will be registered in this packet. Currently only
|
|
|
|
actors with a collision sensor will report collisions, so currently only hero vehicles have that
|
|
|
|
sensor attached automatically.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![event collision](img/RecorderCollision.png)
|
|
|
|
|
|
|
|
The **id** is just a sequence to identify each collision internally.
|
2019-09-06 17:07:21 +08:00
|
|
|
Several collisions between the same pair of actors can happen in the same frame, because physics
|
|
|
|
frame rate is fixed and usually there are several physics substeps in the same rendered frame.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
### 3.7 Packet 6: Position
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
This packet records the position and orientation of all actors of type **vehicle** and
|
|
|
|
**walker** that exist in the scene.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![position](img/RecorderPosition.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
### 3.8 Packet 7: TrafficLight
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
This packet records the state of all **traffic lights** in the scene. Which means that it
|
|
|
|
stores the state (red, orange or green) and the time it is waiting to change to a new state.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![state](img/RecorderTrafficLight.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
### 3.9 Packet 8: Vehicle animation
|
2019-04-24 18:11:41 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
This packet records the animation of the vehicles, bikes and cycles. This packet stores the
|
|
|
|
**throttle**, **sterring**, **brake**, **handbrake** and **gear** inputs, and then set them at playback.
|
2019-04-24 18:11:41 +08:00
|
|
|
|
|
|
|
![state](img/RecorderVehicle.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
### 3.10 Packet 9: Walker animation
|
2019-04-24 18:11:41 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
This packet records the animation of the walker. It just saves the **speed** of the walker
|
|
|
|
that is used in the animation.
|
2019-04-24 18:11:41 +08:00
|
|
|
|
|
|
|
![state](img/RecorderWalker.png)
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
## 4. Frame Layout
|
2019-04-26 17:46:38 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
A frame consists of several packets, where all of them are optional, except the ones that
|
|
|
|
have the **start** and **end** in that frame, that must be there always.
|
2019-04-26 17:46:38 +08:00
|
|
|
|
|
|
|
![layout](img/RecorderFrameLayout.png)
|
|
|
|
|
2019-07-05 21:02:17 +08:00
|
|
|
**Event** packets exist only in the frame where they happen.
|
2019-04-26 17:46:38 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
**Position** and **traffic light** packets should exist in all frames, because they are
|
|
|
|
required to move all actors and set the traffic lights to its state.
|
|
|
|
They are optional but if they are not present then the replayer will not be able to move
|
|
|
|
or set the state of traffic lights.
|
2019-04-26 17:46:38 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
The **animation** packets are also optional, but by default they are recorded. That way the walkers
|
|
|
|
are animated and also the vehicle wheels follow the direction of the vehicles.
|
2019-04-26 17:46:38 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
## 5. File Layout
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
The layout of the file starts with the **info header** and then follows a collection of packets in
|
|
|
|
groups. The first in each group is the **Frame Start** packet, and the last in the group is
|
|
|
|
the **Frame End** packet. In between, we can find the rest of packets as well.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![layout](img/RecorderLayout.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
Usually, it is a good idea to have all packets regarding events first, and then the packets
|
|
|
|
regarding position and state later.
|
2019-04-12 23:21:54 +08:00
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
The event packets are optional, since they appear when they happen, so we could have a layout
|
|
|
|
like this one:
|
2019-04-12 23:21:54 +08:00
|
|
|
|
|
|
|
![layout](img/RecorderLayoutSample.png)
|
|
|
|
|
2019-09-06 17:07:21 +08:00
|
|
|
In **frame 1** some actors are created and reparented, so we can observe its events in the image.
|
|
|
|
In **frame 2** there are no events. In **frame 3** some actors have collided so the collision event
|
|
|
|
appears with that info. In **frame 4** the actors are destroyed.
|