#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);
}
}
return ret;
}
if (endpoints.count(url)) {
- pair<string, string> contents_and_type = endpoints[url]();
+ pair<string, string> contents_and_type = endpoints[url].callback();
MHD_Response *response = MHD_create_response_from_buffer(
contents_and_type.first.size(), &contents_and_type.first[0], MHD_RESPMEM_MUST_COPY);
MHD_add_response_header(response, "Content-type", contents_and_type.second.c_str());
+ if (endpoints[url].cors_policy == ALLOW_ALL_ORIGINS) {
+ MHD_add_response_header(response, "Access-Control-Allow-Origin", "*");
+ }
int ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
MHD_destroy_response(response); // Only decreases the refcount; actual free is after the request is done.
return ret;
}
+ // Small hack; reject unknown /channels/foo.
+ if (string(url).find("/channels/") == 0) {
+ string contents = "Not found.";
+ MHD_Response *response = MHD_create_response_from_buffer(
+ contents.size(), &contents[0], MHD_RESPMEM_MUST_COPY);
+ MHD_add_response_header(response, "Content-type", "text/plain");
+ int ret = MHD_queue_response(connection, MHD_HTTP_NOT_FOUND, response);
+ MHD_destroy_response(response); // Only decreases the refcount; actual free is after the request is done.
+ return ret;
+ }
+
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));