#include <sys/time.h>
#include <time.h>
#include <memory>
+extern "C" {
+#include <libavutil/avutil.h>
+}
#include "defs.h"
#include "metacube2.h"
}
}
-void HTTPD::add_data(const char *buf, size_t size, bool keyframe)
+void HTTPD::add_data(const char *buf, size_t size, bool keyframe, int64_t time, AVRational timebase)
{
unique_lock<mutex> lock(streams_mutex);
for (Stream *stream : streams) {
- stream->add_data(buf, size, keyframe ? Stream::DATA_TYPE_KEYFRAME : Stream::DATA_TYPE_OTHER);
+ stream->add_data(buf, size, keyframe ? Stream::DATA_TYPE_KEYFRAME : Stream::DATA_TYPE_OTHER, time, timebase);
}
}
}
HTTPD::Stream *stream = new HTTPD::Stream(this, framing);
- stream->add_data(header.data(), header.size(), Stream::DATA_TYPE_HEADER);
+ stream->add_data(header.data(), header.size(), Stream::DATA_TYPE_HEADER, AV_NOPTS_VALUE, AVRational{ 1, 0 });
{
unique_lock<mutex> lock(streams_mutex);
streams.insert(stream);
return ret;
}
-void HTTPD::Stream::add_data(const char *buf, size_t buf_size, HTTPD::Stream::DataType data_type)
+void HTTPD::Stream::add_data(const char *buf, size_t buf_size, HTTPD::Stream::DataType data_type, int64_t time, AVRational timebase)
{
if (buf_size == 0) {
return;
unique_lock<mutex> lock(buffer_mutex);
if (framing == FRAMING_METACUBE) {
- metacube2_block_header hdr;
- memcpy(hdr.sync, METACUBE2_SYNC, sizeof(hdr.sync));
- hdr.size = htonl(buf_size);
int flags = 0;
if (data_type == DATA_TYPE_HEADER) {
flags |= METACUBE_FLAGS_HEADER;
} else if (data_type == DATA_TYPE_OTHER) {
flags |= METACUBE_FLAGS_NOT_SUITABLE_FOR_STREAM_START;
}
+
+ // If we're about to send a keyframe, send a pts metadata block
+ // to mark its time.
+ if ((flags & METACUBE_FLAGS_NOT_SUITABLE_FOR_STREAM_START) == 0 && time != AV_NOPTS_VALUE) {
+ metacube2_pts_packet packet;
+ packet.type = htobe64(METACUBE_METADATA_TYPE_NEXT_BLOCK_PTS);
+ packet.pts = htobe64(time);
+ packet.timebase_num = htobe64(timebase.num);
+ packet.timebase_den = htobe64(timebase.den);
+
+ 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));
+ }
+
+ metacube2_block_header hdr;
+ memcpy(hdr.sync, METACUBE2_SYNC, sizeof(hdr.sync));
+ hdr.size = htonl(buf_size);
hdr.flags = htons(flags);
hdr.csum = htons(metacube2_compute_crc(&hdr));
buffered_data.emplace_back((char *)&hdr, sizeof(hdr));
#include <unordered_map>
#include <utility>
+extern "C" {
+#include <libavutil/rational.h>
+}
+
struct MHD_Connection;
struct MHD_Daemon;
}
void start(int port);
- void add_data(const char *buf, size_t size, bool keyframe);
+ void add_data(const char *buf, size_t size, bool keyframe, int64_t time, AVRational timebase);
int64_t get_num_connected_clients() const {
return metric_num_connected_clients.load();
}
DATA_TYPE_KEYFRAME,
DATA_TYPE_OTHER
};
- void add_data(const char *buf, size_t size, DataType data_type);
+ void add_data(const char *buf, size_t size, DataType data_type, int64_t time, AVRational timebase);
void stop();
HTTPD *get_parent() const { return parent; }
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.
+ * 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
uint64_t tv_nsec;
};
+/*
+ * Sent before a block to mark its presentation timestamp (ie., counts
+ * only for the next Metacube block). Used so that the reflector can know
+ * the length (in seconds) of fragments.
+ */
+#define METACUBE_METADATA_TYPE_NEXT_BLOCK_PTS 0x2
+
+struct metacube2_pts_packet {
+ uint64_t type; /* METACUBE_METADATA_TYPE_NEXT_BLOCK_PTS, in network byte order. */
+
+ /* The timestamp of the first packet in the next block, in network byte order. */
+ int64_t pts;
+
+ /* Timebase "pts" is expressed in, as a fraction. Network byte order. */
+ uint64_t timebase_num, timebase_den;
+};
+
#endif /* !defined(_METACUBE_H) */