--- /dev/null
+#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);
+}
--- /dev/null
+#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;
+}