From b1b7b5477664b3871f25e4e990fa8835952303d6 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sat, 16 Jul 2016 17:16:06 +0200 Subject: [PATCH] Add Metacube timestamping to every keyframe, for easier detection of streams not keeping up. Works with the new timestamp feature of Cubemap 1.3.1. Will be ignored (save for some logging) in older Cubemap versions. --- httpd.cpp | 21 +++++++++++++++++++++ metacube2.cpp | 11 +++++++++++ metacube2.h | 31 ++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/httpd.cpp b/httpd.cpp index c6a233d..6f94409 100644 --- a/httpd.cpp +++ b/httpd.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -174,6 +175,26 @@ void HTTPD::Stream::add_data(const char *buf, size_t buf_size, HTTPD::Stream::Da buffered_data.emplace_back((char *)&hdr, sizeof(hdr)); } buffered_data.emplace_back(buf, buf_size); + + // Send a Metacube2 timestamp every keyframe. + if (framing == FRAMING_METACUBE && data_type == DATA_TYPE_KEYFRAME) { + timespec now; + clock_gettime(CLOCK_REALTIME, &now); + + metacube2_timestamp_packet packet; + packet.type = htobe64(METACUBE_METADATA_TYPE_ENCODER_TIMESTAMP); + packet.tv_sec = htobe64(now.tv_sec); + packet.tv_nsec = htobe64(now.tv_nsec); + + metacube2_block_header hdr; + memcpy(hdr.sync, METACUBE2_SYNC, sizeof(hdr.sync)); + hdr.size = htonl(sizeof(packet)); + hdr.flags = htons(METACUBE_FLAGS_METADATA); + hdr.csum = htons(metacube2_compute_crc(&hdr)); + buffered_data.emplace_back((char *)&hdr, sizeof(hdr)); + buffered_data.emplace_back((char *)&packet, sizeof(packet)); + } + has_buffered_data.notify_all(); } diff --git a/metacube2.cpp b/metacube2.cpp index 1bf9efb..666355d 100644 --- a/metacube2.cpp +++ b/metacube2.cpp @@ -7,6 +7,8 @@ #include "metacube2.h" +#include + /* * https://www.ece.cmu.edu/~koopman/pubs/KoopmanCRCWebinar9May2012.pdf * recommends this for messages as short as ours (see table at page 34). @@ -44,5 +46,14 @@ uint16_t metacube2_compute_crc(const struct metacube2_block_header *hdr) } } + /* + * Invert the checksum for metadata packets, so that clients that + * don't understand metadata will ignore it as broken. There will + * probably be logging, but apart from that, it's harmless. + */ + if (ntohs(hdr->flags) & METACUBE_FLAGS_METADATA) { + crc ^= 0xffff; + } + return crc; } diff --git a/metacube2.h b/metacube2.h index 43de8b7..5b6077e 100644 --- a/metacube2.h +++ b/metacube2.h @@ -14,13 +14,42 @@ #define METACUBE_FLAGS_HEADER 0x1 #define METACUBE_FLAGS_NOT_SUITABLE_FOR_STREAM_START 0x2 +/* + * Metadata packets; should not be counted as data, but rather + * parsed (or ignored if you don't understand them). + * + * Metadata packets start with a uint64_t (network byte order) + * that describe the type; the rest is defined by the type. + */ +#define METACUBE_FLAGS_METADATA 0x4 + struct metacube2_block_header { char sync[8]; /* METACUBE2_SYNC */ uint32_t size; /* Network byte order. Does not include header. */ uint16_t flags; /* Network byte order. METACUBE_FLAGS_*. */ - uint16_t csum; /* Network byte order. CRC16 of size and flags. */ + uint16_t csum; /* Network byte order. CRC16 of size and flags. + If METACUBE_FLAGS_METADATA is set, inverted + so that older clients will ignore it as broken. */ }; uint16_t metacube2_compute_crc(const struct metacube2_block_header *hdr); +/* + * The only currently defined metadata type. Set by the encoder, + * and can be measured for latency purposes (e.g., if the network + * can't keep up, the latency will tend to increase. + */ +#define METACUBE_METADATA_TYPE_ENCODER_TIMESTAMP 0x1 + +struct metacube2_timestamp_packet { + uint64_t type; /* METACUBE_METADATA_TYPE_ENCODER_TIMESTAMP, in network byte order. */ + + /* + * Time since the UTC epoch. Basically a struct timespec. + * Both are in network byte order. + */ + uint64_t tv_sec; + uint64_t tv_nsec; +}; + #endif /* !defined(_METACUBE_H) */ -- 2.39.2