libobs: Add encoder packet timing support

Introduce support for the `encoder_packet_time` struct
to capture timing information for each frame, starting
from the composition of each frame, through the encoder,
to the queueing of the frame data to each output_t.

Timestamps for each of the following events are based on
`os_gettime_ns()`:

CTS: Composition time stamp (in the encoder render threads)
FER: Frame encode request
FERC: Frame encoder request completely
PIR: Packet interleave request (`send_interleaved()`)

Frame times are forwarded through encoder callbacks in the
context that runs on the relevant encoder thread, ensuring
no race conditions with accessing per encoder array happen.
All per-output processing happens on data that is owned by
the output.

Co-authored-by: Ruwen Hahn <haruwenz@twitch.tv>
This commit is contained in:
Alex Luccisano
2024-09-05 16:38:58 -04:00
committed by Ryan Foster
co-authored by Ruwen Hahn
parent 26b7b4511c
commit 6a53b8928f
7 changed files with 268 additions and 47 deletions
+50
View File
@@ -45,6 +45,56 @@ enum obs_encoder_type {
OBS_ENCODER_VIDEO /**< The encoder provides a video codec */
};
/* encoder_packet_time is used for timestamping events associated
* with each video frame. This is useful for deriving absolute
* timestamps (i.e. wall-clock based formats) and measuring latency.
*
* For each frame, there are four events of interest, described in
* the encoder_packet_time struct, namely cts, fer, ferc, and pir.
* The timebase of these four events is os_gettime_ns(), which provides
* very high resolution timestamping, and the ability to convert the
* timing to any other time format.
*
* Each frame follows a timeline in the following temporal order:
* CTS, FER, FERC, PIR
*
* PTS is the integer-based monotonically increasing value that is used
* to associate an encoder_packet_time entry with a specific encoder_packet.
*/
struct encoder_packet_time {
/* PTS used to associate uncompressed frames with encoded packets. */
int64_t pts;
/* Composition timestamp is when the frame was rendered,
* captured via os_gettime_ns().
*/
uint64_t cts;
/* FERC (Frame Encode Request) is when the frame was
* submitted to the encoder for encoding via the encode
* callback (e.g. encode_texture2()), captured via os_gettime_ns().
*/
uint64_t fer;
/* FERC (Frame Encode Request Complete) is when
* the associated FER event completed. If the encode
* is synchronous with the call, this means FERC - FEC
* measures the actual encode time, otherwise if the
* encode is asynchronous, it measures the pipeline
* delay between encode request and encode complete.
* FERC is also captured via os_gettime_ns().
*/
uint64_t ferc;
/* PIR (Packet Interleave Request) is when the encoded packet
* is interleaved with the stream. PIR is captured via
* os_gettime_ns(). The difference between PIR and CTS gives
* the total latency between frame rendering
* and packet interleaving.
*/
uint64_t pir;
};
/** Encoder output packet */
struct encoder_packet {
uint8_t *data; /**< Packet data */