diff options
author | Mikhail Burakov <mburakov@mailbox.org> | 2023-03-21 19:05:32 +0100 |
---|---|---|
committer | Mikhail Burakov <mburakov@mailbox.org> | 2023-03-21 19:05:32 +0100 |
commit | 844143e0c6cc1efa90bd27c9aa0cade7f7dd7930 (patch) | |
tree | c19f8b7bbd6169ef47069ab759e7e61b1033ce5a | |
parent | 8d32de4648dd9659d3bfdd252d03f713211f4f8b (diff) |
Add timing stats to video decoding
-rw-r--r-- | decode.c | 89 |
1 files changed, 89 insertions, 0 deletions
@@ -19,11 +19,13 @@ #include <errno.h> #include <fcntl.h> +#include <limits.h> #include <mfxvideo.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> #include <va/va.h> #include <va/va_drm.h> @@ -39,6 +41,12 @@ struct Surface { bool locked; }; +struct TimingStats { + unsigned long long min; + unsigned long long max; + unsigned long long sum; +}; + struct DecodeContext { int drm_fd; VADisplay display; @@ -52,8 +60,43 @@ struct DecodeContext { uint32_t packet_offset; struct Surface** sufaces; struct Frame* decoded; + + unsigned long long recording_started; + unsigned long long frame_header_ts; + unsigned long long frame_received_ts; + unsigned long long frame_decoded_ts; + unsigned long long frame_counter; + unsigned long long bitstream; + + struct TimingStats receive; + struct TimingStats decode; + struct TimingStats total; }; +static void TimingStatsReset(struct TimingStats* timing_stats) { + *timing_stats = (struct TimingStats){.min = ULLONG_MAX}; +} + +static void TimingStatsRecord(struct TimingStats* timing_stats, + unsigned long long value) { + timing_stats->min = MIN(timing_stats->min, value); + timing_stats->max = MAX(timing_stats->max, value); + timing_stats->sum += value; +} + +static void TimingStatsLog(const struct TimingStats* timing_stats, + const char* name, unsigned long long counter) { + LOG("%s min/avg/max: %llu/%llu/%llu", name, timing_stats->min, + timing_stats->sum / counter, timing_stats->max); +} + +static unsigned long long MicrosNow(void) { + struct timespec ts = {.tv_sec = 0, .tv_nsec = 0}; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (unsigned long long)ts.tv_sec * 1000000ull + + (unsigned long long)ts.tv_nsec / 1000ull; +} + static void SurfaceDestroy(struct Surface*** psurfaces) { if (!psurfaces || !*psurfaces) return; for (struct Surface** surfaces = *psurfaces; *surfaces; surfaces++) { @@ -236,6 +279,11 @@ struct DecodeContext* DecodeContextCreate(void) { LOG("Failed to set frame allocator (%d)", status); return NULL; } + + decode_context->recording_started = MicrosNow(); + TimingStatsReset(&decode_context->receive); + TimingStatsReset(&decode_context->decode); + TimingStatsReset(&decode_context->total); return RELEASE(decode_context); } @@ -282,6 +330,7 @@ again:; if (!decode_context->packet_size) { target = &decode_context->packet_size; size = sizeof(decode_context->packet_size); + decode_context->frame_header_ts = MicrosNow(); } else { target = decode_context->packet_data + decode_context->packet_offset; size = decode_context->packet_size - decode_context->packet_offset; @@ -336,6 +385,40 @@ static void UnlockAllSurfaces(struct DecodeContext* decode_context, } } +void HandleTimingStats(struct DecodeContext* decode_context) { + TimingStatsRecord( + &decode_context->receive, + decode_context->frame_received_ts - decode_context->frame_header_ts); + TimingStatsRecord( + &decode_context->decode, + decode_context->frame_decoded_ts - decode_context->frame_received_ts); + TimingStatsRecord( + &decode_context->total, + decode_context->frame_received_ts - decode_context->frame_header_ts); + + unsigned long long period = + decode_context->frame_decoded_ts - decode_context->recording_started; + static const unsigned long long second = 1000000; + if (period < 10 * second) return; + + LOG("---->8-------->8-------->8----"); + TimingStatsLog(&decode_context->receive, "Receive", + decode_context->frame_counter); + TimingStatsLog(&decode_context->decode, "Decode", + decode_context->frame_counter); + TimingStatsLog(&decode_context->total, "Total", + decode_context->frame_counter); + LOG("Framerate: %llu fps", decode_context->frame_counter * second / period); + LOG("Bitstream: %llu Kbps", + decode_context->bitstream * second * 8 / period / 1024); + decode_context->recording_started = decode_context->frame_decoded_ts; + TimingStatsReset(&decode_context->receive); + TimingStatsReset(&decode_context->decode); + TimingStatsReset(&decode_context->total); + decode_context->frame_counter = 0; + decode_context->bitstream = 0; +} + bool DecodeContextDecode(struct DecodeContext* decode_context, int fd) { if (!ReadSomePacketData(decode_context, fd)) { LOG("Failed to read some packet data"); @@ -356,6 +439,8 @@ bool DecodeContextDecode(struct DecodeContext* decode_context, int fd) { }; decode_context->packet_size = 0; decode_context->packet_offset = 0; + decode_context->frame_received_ts = MicrosNow(); + decode_context->bitstream += bitstream.DataLength; if (!decode_context->initialized) { if (!InitializeDecoder(decode_context, &bitstream)) { @@ -399,6 +484,10 @@ bool DecodeContextDecode(struct DecodeContext* decode_context, int fd) { surface = surface_out->Data.MemId; decode_context->decoded = surface->frame; UnlockAllSurfaces(decode_context, surface); + + decode_context->frame_decoded_ts = MicrosNow(); + decode_context->frame_counter++; + HandleTimingStats(decode_context); return true; } } |