Initial checkin.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 6 Apr 2013 10:16:09 +0000 (12:16 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 6 Apr 2013 10:16:09 +0000 (12:16 +0200)
cubemap.cpp [new file with mode: 0644]
metacube.h [new file with mode: 0644]
remux.cpp [new file with mode: 0644]

diff --git a/cubemap.cpp b/cubemap.cpp
new file mode 100644 (file)
index 0000000..cbdab18
--- /dev/null
@@ -0,0 +1,122 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+#include <arpa/inet.h>
+#include <curl/curl.h>
+#include <vector>
+#include "metacube.h"
+
+using namespace std;
+
+class Input {
+public:
+       Input();
+       void curl_callback(char *ptr, size_t bytes);
+
+private:
+       void process_block(const char *data, uint32_t size, uint32_t flags);
+       void drop_pending_data(size_t num_bytes);
+
+       // Data we have received but not fully processed yet.
+       vector<char> pending_data;
+
+       // If <pending_data> starts with a Metacube header,
+       // this is true.
+       bool has_metacube_header;
+};
+
+Input::Input()
+       : has_metacube_header(false)
+{
+}
+       
+void Input::curl_callback(char *ptr, size_t bytes)
+{
+       pending_data.insert(pending_data.end(), ptr, ptr + bytes);
+
+       for ( ;; ) {
+               // If we don't have enough data (yet) for even the Metacube header, just return.
+               if (pending_data.size() < sizeof(metacube_block_header)) {
+                       return;
+               }
+
+               // Make sure we have the Metacube sync header at the start.
+               // We may need to skip over junk data (it _should_ not happen, though).
+               if (!has_metacube_header) {
+                       char *ptr = static_cast<char *>(
+                               memmem(pending_data.data(), pending_data.size(),
+                                      METACUBE_SYNC, strlen(METACUBE_SYNC)));
+                       if (ptr == NULL) {
+                               // OK, so we didn't find the sync marker. We know then that
+                               // we do not have the _full_ marker in the buffer, but we
+                               // could have N-1 bytes. Drop everything before that,
+                               // and then give up.
+                               drop_pending_data(pending_data.size() - (strlen(METACUBE_SYNC) - 1));
+                               return;
+                       } else {
+                               // Yay, we found the header. Drop everything (if anything) before it.
+                               drop_pending_data(ptr - pending_data.data());
+                               has_metacube_header = true;
+
+                               // Re-check that we have the entire header; we could have dropped data.
+                               if (pending_data.size() < sizeof(metacube_block_header)) {
+                                       return;
+                               }
+                       }
+               }
+
+               // Now it's safe to read the header.
+               metacube_block_header *hdr = reinterpret_cast<metacube_block_header *>(pending_data.data());    
+               assert(memcmp(hdr->sync, METACUBE_SYNC, sizeof(hdr->sync)) == 0);
+               uint32_t size = ntohl(hdr->size);
+               uint32_t flags = ntohl(hdr->flags);
+
+               // See if we have the entire block. If not, wait for more data.
+               if (pending_data.size() < sizeof(metacube_block_header) + size) {
+                       return;
+               }
+
+               process_block(pending_data.data(), size, flags);
+
+               // Consume this block. This isn't the most efficient way of dealing with things
+               // should we have many blocks, but these routines don't need to be too efficient
+               // anyway.
+               pending_data.erase(pending_data.begin(), pending_data.begin() + sizeof(metacube_block_header) + size);
+       }
+}
+               
+void Input::process_block(const char *data, uint32_t size, uint32_t flags)
+{
+       // TODO: treat it right here
+       printf("Block: %d bytes, flags=0x%x\n", size, flags);
+}
+                       
+void Input::drop_pending_data(size_t num_bytes)
+{
+       if (num_bytes == 0) {
+               return;
+       }
+       fprintf(stderr, "Warning: Dropping %lld junk bytes from stream, maybe it is not a Metacube stream?\n",
+               (long long)num_bytes);
+       pending_data.erase(pending_data.begin(), pending_data.begin() + num_bytes);
+}
+
+size_t curl_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+       Input *input = static_cast<Input *>(userdata);
+       size_t bytes = size * nmemb;
+       input->curl_callback(ptr, bytes);       
+       return bytes;
+}
+
+int main(int argc, char **argv)
+{
+       Input input;
+       CURL *curl = curl_easy_init();
+       curl_easy_setopt(curl, CURLOPT_URL, "http://gruessi.zrh.sesse.net:4013/");
+       // curl_easy_setopt(curl, CURLOPT_URL, "http://www.google.com/");
+       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_callback);
+       curl_easy_setopt(curl, CURLOPT_WRITEDATA, &input);
+       curl_easy_perform(curl);
+}
diff --git a/metacube.h b/metacube.h
new file mode 100644 (file)
index 0000000..b40a42e
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _METACUBE_H
+#define _METACUBE_H
+
+/* Definitions for the Metacube protocol, used to communicate with Cubemap. */
+
+#include <stdlib.h>
+
+#define METACUBE_SYNC "\\o/_metacube_\\o/"  /* 16 bytes long. */
+#define METACUBE_FLAGS_HEADER 0x1
+
+struct metacube_block_header {
+       char sync[16];   /* METACUBE_SYNC */
+       uint32_t size;   /* Network byte order. Does not include header. */
+       uint32_t flags;  /* Network byte order. METACUBE_FLAGS_*. */
+};
+
+#endif  /* !defined(_METACUBE_H) */
diff --git a/remux.cpp b/remux.cpp
new file mode 100644 (file)
index 0000000..41008f0
--- /dev/null
+++ b/remux.cpp
@@ -0,0 +1,171 @@
+#define __STDC_CONSTANT_MACROS
+#include <stdio.h>
+#include <stdint.h>
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+}
+
+AVOutputFormat *find_output_format(const char *name)
+{
+       AVOutputFormat *output_fmt = NULL;
+       while ((output_fmt = av_oformat_next(output_fmt)) != NULL) {
+               if (strcmp(output_fmt->name, "flv") == 0) {
+                       return output_fmt;
+               }
+       }
+       return NULL;
+}
+
+void copy_stream_settings(AVStream *stream, const AVStream *istream)
+{
+       AVCodecContext *codec = stream->codec;
+
+       const AVCodecContext *icodec = istream->codec;
+
+       stream->disposition = istream->disposition;
+       codec->bits_per_raw_sample = icodec->bits_per_raw_sample;
+       codec->chroma_sample_location = icodec->chroma_sample_location;
+
+       codec->codec_id = icodec->codec_id;
+       codec->codec_type = icodec->codec_type;
+#if 0
+       if (codec->codec_tag == 0) {
+               if (output_ctx->oformat->codec_tag ||
+                               av_codec_get_id (output_ctx->oformat->codec_tag, icodec->codec_tag) == codec->codec_id ||
+                               av_codec_get_tag(output_ctx->oformat->codec_tag, icodec->codec_id) <= 0) {
+                       codec->codec_tag = icodec->codec_tag;
+               }
+       }
+#endif
+
+       codec->bit_rate = icodec->bit_rate;
+       codec->rc_max_rate = icodec->rc_max_rate;
+       codec->rc_buffer_size = icodec->rc_buffer_size;
+       codec->field_order = icodec->field_order;
+
+       uint64_t extra_size = (uint64_t)icodec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE;
+       codec->extradata = (uint8_t *)av_mallocz(extra_size);
+       memcpy(codec->extradata, icodec->extradata, icodec->extradata_size);
+       codec->extradata_size= icodec->extradata_size;
+
+       codec->bits_per_coded_sample  = icodec->bits_per_coded_sample;
+       codec->time_base = istream->time_base;
+
+       if (av_q2d(icodec->time_base)*icodec->ticks_per_frame > av_q2d(istream->time_base)
+                       && av_q2d(istream->time_base) < 1.0/500) {
+               codec->time_base = icodec->time_base;
+               codec->time_base.num *= icodec->ticks_per_frame;
+       }
+
+       av_reduce(&codec->time_base.num, &codec->time_base.den,
+                       codec->time_base.num, codec->time_base.den, INT_MAX);
+
+       printf("time base: %d/%d\n", codec->time_base.num, codec->time_base.den);
+
+       switch (codec->codec_type) {
+               case AVMEDIA_TYPE_AUDIO:
+                       printf("audio stream\n");
+                       codec->channel_layout     = icodec->channel_layout;
+                       codec->sample_rate        = icodec->sample_rate;
+                       codec->channels           = icodec->channels;
+                       codec->frame_size         = icodec->frame_size;
+                       codec->audio_service_type = icodec->audio_service_type;
+                       codec->block_align        = icodec->block_align;
+#if 0
+                       if((codec->block_align == 1 || codec->block_align == 1152) && codec->codec_id == AV_CODEC_ID_MP3)
+                               codec->block_align= 0;
+                       if(codec->codec_id == AV_CODEC_ID_AC3)
+                               codec->block_align= 0;
+#endif
+                       break;
+               case AVMEDIA_TYPE_VIDEO:
+                       printf("video stream\n");
+                       codec->pix_fmt            = icodec->pix_fmt;
+                       codec->width              = icodec->width;
+                       codec->height             = icodec->height;
+                       codec->has_b_frames       = icodec->has_b_frames;
+                       if (codec->sample_aspect_ratio.num == 0) {
+                               if (istream->sample_aspect_ratio.num != 0) {
+                                       stream->sample_aspect_ratio = istream->sample_aspect_ratio;
+                               } else if (istream->codec->sample_aspect_ratio.num != 0) {
+                                       stream->sample_aspect_ratio = istream->codec->sample_aspect_ratio;
+                               } else {
+                                       stream->sample_aspect_ratio = (AVRational){0, 1};
+                               }
+                               codec->sample_aspect_ratio = stream->sample_aspect_ratio;
+                       }
+                       stream->avg_frame_rate = istream->avg_frame_rate;
+                       break;
+               case AVMEDIA_TYPE_SUBTITLE:
+                       codec->width  = icodec->width;
+                       codec->height = icodec->height;
+                       break;
+               case AVMEDIA_TYPE_DATA:
+               case AVMEDIA_TYPE_ATTACHMENT:
+                       break;
+               default:
+                       abort();
+       }
+}
+                               
+int main(int argc, char *argv[])
+{
+       av_register_all();
+       avformat_network_init();
+
+       // Open input.
+       AVFormatContext *input_ctx = NULL;
+       if (avformat_open_input(&input_ctx, argv[1], NULL, NULL) != 0) {
+               exit(1);
+       }
+       if (avformat_find_stream_info(input_ctx, NULL) < 0) {
+               exit(1);
+       }
+       av_dump_format(input_ctx, 0, argv[1], 0);
+
+       // Open output.
+       AVFormatContext *output_ctx = avformat_alloc_context();
+       if (output_ctx == NULL) {
+               exit(1);
+       }
+
+       output_ctx->oformat = find_output_format("flv");
+       if (output_ctx->oformat == NULL) {
+               printf("Couldn't find output format 'flv'!\n");
+               exit(1);
+       }
+
+       if (avio_open2(&output_ctx->pb, "output.flv", AVIO_FLAG_WRITE, NULL, NULL) != 0) {
+               printf("Couldn't open output.flv\n");
+               exit(1);
+       }
+
+       // Copy the stream headers from input to output.
+       printf("Found %d stream(s).\n", input_ctx->nb_streams);
+       for (int i = 0; i < input_ctx->nb_streams; ++i) {
+               AVStream *stream = avformat_new_stream(output_ctx, NULL);
+               if (stream == NULL) {
+                       printf("Couldn't add stream %d\n", i);
+                       exit(1);
+               }
+
+               copy_stream_settings(stream, input_ctx->streams[i]);
+       }
+       if (avformat_write_header(output_ctx, NULL) != 0) {
+               printf("avformat_write_header()\n");
+               exit(1);
+       }
+       
+
+       AVPacket packet;
+       while (av_read_frame(input_ctx, &packet) >= 0) {
+//             printf("pts=%ld dts=%ld stream=%d size=%d flags=0x%x\n",
+//                     packet.pts, packet.dts, packet.stream_index, packet.size, packet.flags);
+               av_write_frame(output_ctx, &packet);
+//             av_free_packet(&packet);
+       }
+
+       return 0;
+}