]> git.sesse.net Git - nageru/commitdiff
Add Metacube stream output (for Cubemap).
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 18 Apr 2016 22:19:43 +0000 (00:19 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 18 Apr 2016 22:19:43 +0000 (00:19 +0200)
Makefile
httpd.cpp
httpd.h
metacube2.cpp [new file with mode: 0644]
metacube2.h [new file with mode: 0644]

index f68d8989582c2db2b852efb9d51e8124c447c44f..ffc1f1c32e99e07c356af1a0f3e2e2de0cfa54aa 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ OBJS=glwidget.o main.o mainwindow.o vumeter.o lrameter.o vu_common.o correlation
 OBJS += glwidget.moc.o mainwindow.moc.o vumeter.moc.o lrameter.moc.o correlation_meter.moc.o aboutdialog.moc.o
 
 # Mixer objects
-OBJS += h264encode.o x264encode.o mixer.o bmusb/bmusb.o pbo_frame_allocator.o context.o ref_counted_frame.o theme.o resampling_queue.o httpd.o mux.o ebu_r128_proc.o flags.o image_input.o stereocompressor.o filter.o alsa_output.o correlation_measurer.o
+OBJS += h264encode.o x264encode.o mixer.o bmusb/bmusb.o pbo_frame_allocator.o context.o ref_counted_frame.o theme.o resampling_queue.o metacube2.o httpd.o mux.o ebu_r128_proc.o flags.o image_input.o stereocompressor.o filter.o alsa_output.o correlation_measurer.o
 
 # DeckLink
 OBJS += decklink_capture.o decklink/DeckLinkAPIDispatch.o
index ed46f52566832d6faa1ac63e0edfe071d8030e6b..5226885be2e1e4e4fb76ba7534c9ee58b14fdba4 100644 (file)
--- a/httpd.cpp
+++ b/httpd.cpp
@@ -1,3 +1,4 @@
+#include <arpa/inet.h>
 #include <assert.h>
 #include <microhttpd.h>
 #include <stdio.h>
@@ -10,6 +11,7 @@
 
 #include "defs.h"
 #include "flags.h"
+#include "metacube2.h"
 #include "timebase.h"
 
 struct MHD_Connection;
@@ -53,7 +55,18 @@ int HTTPD::answer_to_connection(MHD_Connection *connection,
                                const char *version, const char *upload_data,
                                size_t *upload_data_size, void **con_cls)
 {
-       HTTPD::Stream *stream = new HTTPD::Stream;
+       // See if the URL ends in “.metacube”.
+       HTTPD::Stream::Framing framing;
+       printf("url=[%s]\n", url);
+       if (strstr(url, ".metacube") == url + strlen(url) - strlen(".metacube")) {
+               printf("metacube\n");
+               framing = HTTPD::Stream::FRAMING_METACUBE;
+       } else {
+               printf("raw\n");
+               framing = HTTPD::Stream::FRAMING_RAW;
+       }
+
+       HTTPD::Stream *stream = new HTTPD::Stream(framing);
        stream->add_data(header.data(), header.size(), Stream::DATA_TYPE_HEADER);
        {
                unique_lock<mutex> lock(streams_mutex);
@@ -64,6 +77,11 @@ int HTTPD::answer_to_connection(MHD_Connection *connection,
        // Does not strictly have to be equal to MUX_BUFFER_SIZE.
        MHD_Response *response = MHD_create_response_from_callback(
                (size_t)-1, MUX_BUFFER_SIZE, &HTTPD::Stream::reader_callback_thunk, stream, &HTTPD::free_stream);
+
+       // TODO: Content-type?
+       if (framing == HTTPD::Stream::FRAMING_METACUBE) {
+               MHD_add_response_header(response, "Content-encoding", "metacube");
+       }
        int ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
        //MHD_destroy_response(response);
 
@@ -148,6 +166,21 @@ void HTTPD::Stream::add_data(const char *buf, size_t buf_size, HTTPD::Stream::Da
        }
 
        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;
+               }
+               hdr.flags = htons(flags);
+               hdr.csum = htons(metacube2_compute_crc(&hdr));
+               buffered_data.emplace_back((char *)&hdr, sizeof(hdr));
+       }
        buffered_data.emplace_back(buf, buf_size);
        has_buffered_data.notify_all(); 
 }
diff --git a/httpd.h b/httpd.h
index 21d8746172adc5231820a8c6a676d6bf08ef8ff0..94de03199827f5282e4e195ee23e0150bc4fbb4f 100644 (file)
--- a/httpd.h
+++ b/httpd.h
@@ -48,6 +48,12 @@ private:
 
        class Stream {
        public:
+               enum Framing {
+                       FRAMING_RAW,
+                       FRAMING_METACUBE
+               };
+               Stream(Framing framing) : framing(framing) {}
+
                static ssize_t reader_callback_thunk(void *cls, uint64_t pos, char *buf, size_t max);
                ssize_t reader_callback(uint64_t pos, char *buf, size_t max);
 
@@ -59,6 +65,8 @@ private:
                void add_data(const char *buf, size_t size, DataType data_type);
 
        private:
+               Framing framing;
+
                std::mutex buffer_mutex;
                std::condition_variable has_buffered_data;
                std::deque<std::string> buffered_data;  // Protected by <mutex>.
diff --git a/metacube2.cpp b/metacube2.cpp
new file mode 100644 (file)
index 0000000..1bf9efb
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Implementation of Metacube2 utility functions.
+ *
+ * Note: This file is meant to compile as both C and C++, for easier inclusion
+ * in other projects.
+ */
+
+#include "metacube2.h"
+
+/*
+ * https://www.ece.cmu.edu/~koopman/pubs/KoopmanCRCWebinar9May2012.pdf
+ * recommends this for messages as short as ours (see table at page 34).
+ */
+#define METACUBE2_CRC_POLYNOMIAL 0x8FDB
+
+/* Semi-random starting value to make sure all-zero won't pass. */
+#define METACUBE2_CRC_START 0x1234
+
+/* This code is based on code generated by pycrc. */
+uint16_t metacube2_compute_crc(const struct metacube2_block_header *hdr)
+{
+       static const int data_len = sizeof(hdr->size) + sizeof(hdr->flags);
+       const uint8_t *data = (uint8_t *)&hdr->size;
+       uint16_t crc = METACUBE2_CRC_START;
+       int i, j;
+
+       for (i = 0; i < data_len; ++i) {
+               uint8_t c = data[i];
+               for (j = 0; j < 8; j++) {
+                       int bit = crc & 0x8000;
+                       crc = (crc << 1) | ((c >> (7 - j)) & 0x01);
+                       if (bit) {
+                               crc ^= METACUBE2_CRC_POLYNOMIAL;
+                       }
+               }
+       }
+
+       /* Finalize. */
+       for (i = 0; i < 16; i++) {
+               int bit = crc & 0x8000;
+               crc = crc << 1;
+               if (bit) {
+                       crc ^= METACUBE2_CRC_POLYNOMIAL;
+               }
+       }
+
+       return crc;
+}
diff --git a/metacube2.h b/metacube2.h
new file mode 100644 (file)
index 0000000..43de8b7
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _METACUBE2_H
+#define _METACUBE2_H
+
+/*
+ * Definitions for the Metacube2 protocol, used to communicate with Cubemap.
+ *
+ * Note: This file is meant to compile as both C and C++, for easier inclusion
+ * in other projects.
+ */
+
+#include <stdint.h>
+
+#define METACUBE2_SYNC "cube!map"  /* 8 bytes long. */
+#define METACUBE_FLAGS_HEADER 0x1
+#define METACUBE_FLAGS_NOT_SUITABLE_FOR_STREAM_START 0x2
+
+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 metacube2_compute_crc(const struct metacube2_block_header *hdr);
+
+#endif  /* !defined(_METACUBE_H) */