summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorAlfred E. Heggestad <aeh@db.org>2015-06-28 12:04:30 +0200
committerAlfred E. Heggestad <aeh@db.org>2015-06-28 12:04:30 +0200
commit502385d05c9a5b962f6636dd19df6683bd29860f (patch)
tree05949bc573995ffdedbdafefa4f17b2e31885fb1 /modules
parent8b5ced23d0986ccb510c2c9b1eb59bda2200fe81 (diff)
daala: new experimental video-codec module
Diffstat (limited to 'modules')
-rw-r--r--modules/daala/daala.c62
-rw-r--r--modules/daala/daala.h20
-rw-r--r--modules/daala/decode.c177
-rw-r--r--modules/daala/encode.c276
-rw-r--r--modules/daala/module.mk13
5 files changed, 548 insertions, 0 deletions
diff --git a/modules/daala/daala.c b/modules/daala/daala.c
new file mode 100644
index 0000000..130ca59
--- /dev/null
+++ b/modules/daala/daala.c
@@ -0,0 +1,62 @@
+/**
+ * @file daala.c Experimental video-codec using Daala
+ *
+ * Copyright (C) 2010 - 2015 Creytiv.com
+ */
+
+#include <re.h>
+#include <baresip.h>
+#include <daala/codec.h>
+#include "daala.h"
+
+
+/**
+ * @defgroup daala daala
+ *
+ * Very experimental video-codec using Daala
+ *
+ * TODO:
+ *
+ * - Define and implement fragmentation of large packets
+ * - Define an IETF RTP Payload type
+ *
+ *
+ * References:
+ *
+ * https://wiki.xiph.org/Daala
+ */
+
+
+static struct vidcodec daala = {
+ .name = "daala",
+ .encupdh = daala_encode_update,
+ .ench = daala_encode,
+ .decupdh = daala_decode_update,
+ .dech = daala_decode,
+};
+
+
+static int module_init(void)
+{
+ info("daala: using version '%s'\n", daala_version_string());
+
+ vidcodec_register(&daala);
+
+ return 0;
+}
+
+
+static int module_close(void)
+{
+ vidcodec_unregister(&daala);
+
+ return 0;
+}
+
+
+EXPORT_SYM const struct mod_export DECL_EXPORTS(daala) = {
+ "daala",
+ "video codec",
+ module_init,
+ module_close,
+};
diff --git a/modules/daala/daala.h b/modules/daala/daala.h
new file mode 100644
index 0000000..3649253
--- /dev/null
+++ b/modules/daala/daala.h
@@ -0,0 +1,20 @@
+/**
+ * @file daala.h Experimental video-codec using Daala -- internal api
+ *
+ * Copyright (C) 2010 - 2015 Creytiv.com
+ */
+
+
+/* Encode */
+int daala_encode_update(struct videnc_state **vesp, const struct vidcodec *vc,
+ struct videnc_param *prm, const char *fmtp,
+ videnc_packet_h *pkth, void *arg);
+int daala_encode(struct videnc_state *ves, bool update,
+ const struct vidframe *frame);
+
+
+/* Decode */
+int daala_decode_update(struct viddec_state **vdsp, const struct vidcodec *vc,
+ const char *fmtp);
+int daala_decode(struct viddec_state *vds, struct vidframe *frame,
+ bool marker, uint16_t seq, struct mbuf *mb);
diff --git a/modules/daala/decode.c b/modules/daala/decode.c
new file mode 100644
index 0000000..646605e
--- /dev/null
+++ b/modules/daala/decode.c
@@ -0,0 +1,177 @@
+/**
+ * @file daala/decode.c Experimental video-codec using Daala -- decoder
+ *
+ * Copyright (C) 2010 - 2015 Creytiv.com
+ */
+
+#include <string.h>
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include <daala/daaladec.h>
+#include "daala.h"
+
+
+struct viddec_state {
+ daala_dec_ctx *dec;
+
+ bool got_headers;
+
+ daala_info di;
+ daala_comment dc;
+ daala_setup_info *ds;
+
+ struct {
+ bool valid;
+ size_t n_frame;
+ size_t n_header;
+ size_t n_keyframe;
+ size_t n_packet;
+ } stats;
+};
+
+
+static void dump_stats(const struct viddec_state *vds)
+{
+ re_printf("~~~~~ Daala Decoder stats ~~~~~\n");
+ re_printf("num frames: %zu\n", vds->stats.n_frame);
+ re_printf("num headers: %zu\n", vds->stats.n_header);
+ re_printf("key-frames packets: %zu\n", vds->stats.n_keyframe);
+ re_printf("total packets: %zu\n", vds->stats.n_packet);
+}
+
+
+static void destructor(void *arg)
+{
+ struct viddec_state *vds = arg;
+
+ if (vds->stats.valid)
+ dump_stats(vds);
+
+ if (vds->dec)
+ daala_decode_free(vds->dec);
+
+ if (vds->ds)
+ daala_setup_free(vds->ds);
+ daala_comment_clear(&vds->dc);
+ daala_info_clear(&vds->di);
+}
+
+
+int daala_decode_update(struct viddec_state **vdsp, const struct vidcodec *vc,
+ const char *fmtp)
+{
+ struct viddec_state *vds;
+ int err = 0;
+ (void)vc;
+ (void)fmtp;
+
+ if (!vdsp)
+ return EINVAL;
+
+ vds = *vdsp;
+
+ if (vds)
+ return 0;
+
+ vds = mem_zalloc(sizeof(*vds), destructor);
+ if (!vds)
+ return ENOMEM;
+
+ daala_info_init(&vds->di);
+ daala_comment_init(&vds->dc);
+
+ if (err)
+ mem_deref(vds);
+ else
+ *vdsp = vds;
+
+ return err;
+}
+
+
+int daala_decode(struct viddec_state *vds, struct vidframe *frame,
+ bool marker, uint16_t seq, struct mbuf *mb)
+{
+ ogg_packet op;
+ bool ishdr;
+ int i, r, err = 0;
+ (void)seq;
+
+ if (!vds || !frame || !mb)
+ return EINVAL;
+
+ ++vds->stats.n_packet;
+ ++vds->stats.valid;
+
+ ishdr = daala_packet_isheader(mbuf_buf(mb), mbuf_get_left(mb));
+
+ if (ishdr)
+ ++vds->stats.n_header;
+ else if (daala_packet_iskeyframe(mbuf_buf(mb), mbuf_get_left(mb)) > 0)
+ ++vds->stats.n_keyframe;
+
+#if 0
+ re_printf("decode: [%s] %zu bytes\n",
+ ishdr ? "HEADER" : "DATA",
+ mbuf_get_left(mb));
+#endif
+
+ memset(&op, 0, sizeof(op));
+
+ op.packet = mbuf_buf(mb);
+ op.bytes = mbuf_get_left(mb);
+ op.b_o_s = marker;
+
+ if (daala_packet_isheader(mbuf_buf(mb), mbuf_get_left(mb))) {
+
+ r = daala_decode_header_in(&vds->di, &vds->dc, &vds->ds,
+ &op);
+ if (r < 0) {
+ warning("daala: decoder: decode_header_in failed"
+ " (ret = %d)\n",
+ r);
+ return EPROTO;
+ }
+ else if (r == 0) {
+ vds->got_headers = true;
+ info("daala: all headers received\n");
+
+ vds->dec = daala_decode_alloc(&vds->di, vds->ds);
+ if (!vds->dec) {
+ warning("daala: decoder: alloc failed\n");
+ return ENOMEM;
+ }
+ }
+ else {
+ /* waiting for more headers */
+ }
+ }
+ else {
+ od_img img;
+
+ if (!vds->got_headers) {
+ warning("daala: decode: still waiting for headers\n");
+ return EPROTO;
+ }
+
+ r = daala_decode_packet_in(vds->dec, &img, &op);
+ if (r < 0) {
+ warning("daala: decode: packet_in error (%d)\n", r);
+ return EPROTO;
+ }
+
+ for (i=0; i<3; i++) {
+ frame->data[i] = img.planes[i].data;
+ frame->linesize[i] = img.planes[i].ystride;
+ }
+
+ frame->size.w = img.width;
+ frame->size.h = img.height;
+ frame->fmt = VID_FMT_YUV420P;
+
+ ++vds->stats.n_frame;
+ }
+
+ return err;
+}
diff --git a/modules/daala/encode.c b/modules/daala/encode.c
new file mode 100644
index 0000000..338efcf
--- /dev/null
+++ b/modules/daala/encode.c
@@ -0,0 +1,276 @@
+/**
+ * @file daala/encode.c Experimental video-codec using Daala -- encoder
+ *
+ * Copyright (C) 2010 - 2015 Creytiv.com
+ */
+
+#include <string.h>
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include <daala/daalaenc.h>
+#include "daala.h"
+
+
+struct videnc_state {
+ struct vidsz size;
+ daala_enc_ctx *enc;
+ int64_t pts;
+ unsigned fps;
+ unsigned bitrate;
+ unsigned pktsize;
+ videnc_packet_h *pkth;
+ void *arg;
+
+ struct {
+ bool valid;
+ size_t n_frame;
+ size_t n_header;
+ size_t n_keyframe;
+ size_t n_packet;
+ } stats;
+};
+
+
+static void dump_stats(const struct videnc_state *ves)
+{
+ re_printf("~~~~~ Daala Encoder stats ~~~~~\n");
+ re_printf("num frames: %zu\n", ves->stats.n_frame);
+ re_printf("num headers: %zu\n", ves->stats.n_header);
+ re_printf("key-frames packets: %zu\n", ves->stats.n_keyframe);
+ re_printf("total packets: %zu\n", ves->stats.n_packet);
+}
+
+
+static int send_packet(struct videnc_state *ves, bool marker,
+ const uint8_t *pld, size_t pld_len)
+{
+ int err;
+
+ err = ves->pkth(marker, NULL, 0, pld, pld_len, ves->arg);
+ if (err)
+ return err;
+
+ ++ves->stats.n_packet;
+ ++ves->stats.valid;
+
+ if (daala_packet_isheader(pld, pld_len))
+ ++ves->stats.n_header;
+ else if (daala_packet_iskeyframe(pld, pld_len) > 0)
+ ++ves->stats.n_keyframe;
+
+ return 0;
+}
+
+
+static void destructor(void *arg)
+{
+ struct videnc_state *ves = arg;
+
+ if (ves->stats.valid)
+ dump_stats(ves);
+
+ if (ves->enc)
+ daala_encode_free(ves->enc);
+}
+
+
+int daala_encode_update(struct videnc_state **vesp, const struct vidcodec *vc,
+ struct videnc_param *prm, const char *fmtp,
+ videnc_packet_h *pkth, void *arg)
+{
+ struct videnc_state *ves;
+ (void)fmtp;
+
+ if (!vesp || !vc || !prm || prm->pktsize < 3 || !pkth)
+ return EINVAL;
+
+ ves = *vesp;
+
+ if (!ves) {
+
+ ves = mem_zalloc(sizeof(*ves), destructor);
+ if (!ves)
+ return ENOMEM;
+
+ *vesp = ves;
+ }
+ else {
+ if (ves->enc && (ves->bitrate != prm->bitrate ||
+ ves->pktsize != prm->pktsize ||
+ ves->fps != prm->fps)) {
+
+ info("daala: encoder: params changed\n");
+
+ daala_encode_free(ves->enc);
+ ves->enc = NULL;
+ }
+ }
+
+ ves->bitrate = prm->bitrate;
+ ves->pktsize = prm->pktsize;
+ ves->fps = prm->fps;
+ ves->pkth = pkth;
+ ves->arg = arg;
+
+ return 0;
+}
+
+
+static int open_encoder(struct videnc_state *ves, const struct vidsz *size)
+{
+ daala_info di;
+ daala_comment dc;
+ ogg_packet op;
+ int err = 0;
+ int complexity = 0;
+ int video_q = 10;
+
+ info("daala: open encoder (%d x %d)\n", size->w, size->h);
+
+ if (ves->enc) {
+ debug("daala: re-opening encoder\n");
+ daala_encode_free(ves->enc);
+ }
+
+ daala_info_init(&di);
+ daala_comment_init(&dc);
+
+ di.pic_width = size->w;
+ di.pic_height = size->h;
+ di.timebase_numerator = 1;
+ di.timebase_denominator = ves->fps;
+ di.frame_duration = 1;
+ di.pixel_aspect_numerator = -1;
+ di.pixel_aspect_denominator = -1;
+ di.nplanes = 3;
+ di.plane_info[0].xdec = 0; /* YUV420P */
+ di.plane_info[0].ydec = 0;
+ di.plane_info[1].xdec = 1;
+ di.plane_info[1].ydec = 1;
+ di.plane_info[2].xdec = 1;
+ di.plane_info[2].ydec = 1;
+
+ di.keyframe_rate = 100;
+
+ info("daala: open encoder with bitstream version %u.%u.%u\n",
+ di.version_major, di.version_minor, di.version_sub);
+
+ ves->enc = daala_encode_create(&di);
+ if (!ves->enc) {
+ warning("daala: failed to open DAALA encoder\n");
+ return ENOMEM;
+ }
+
+ daala_encode_ctl(ves->enc, OD_SET_QUANT,
+ &video_q, sizeof(video_q));
+
+ daala_encode_ctl(ves->enc, OD_SET_COMPLEXITY,
+ &complexity, sizeof(complexity));
+
+ for (;;) {
+ int r;
+
+ r = daala_encode_flush_header(ves->enc, &dc, &op);
+ if (r < 0) {
+ warning("daala: flush_header returned %d\n", r);
+ break;
+ }
+ else if (r == 0)
+ break;
+
+ debug("daala: header: %lld bytes header=%d key=%d\n",
+ op.bytes,
+ daala_packet_isheader(op.packet, op.bytes),
+ daala_packet_iskeyframe(op.packet, op.bytes));
+
+#if 0
+ re_printf("bos=%lld, eos=%lld, granule=%lld, packetno=%lld\n",
+ op.b_o_s,
+ op.e_o_s,
+ op.granulepos,
+ op.packetno);
+#endif
+
+ err = send_packet(ves, op.b_o_s, op.packet, op.bytes);
+ if (err)
+ break;
+ }
+
+ daala_info_clear(&di);
+ daala_comment_clear(&dc);
+
+ return err;
+}
+
+
+int daala_encode(struct videnc_state *ves, bool update,
+ const struct vidframe *frame)
+{
+ int r, err = 0;
+ od_img img;
+ (void)update; /* XXX: how to force a KEY-frame? */
+
+ if (!ves || !frame || frame->fmt != VID_FMT_YUV420P)
+ return EINVAL;
+
+ ++ves->stats.n_frame;
+
+ if (!ves->enc || !vidsz_cmp(&ves->size, &frame->size)) {
+
+ err = open_encoder(ves, &frame->size);
+ if (err)
+ return err;
+
+ ves->size = frame->size;
+ }
+
+ img.planes[0].data = frame->data[0];
+ img.planes[0].xdec = 0;
+ img.planes[0].ydec = 0;
+ img.planes[0].xstride = 1;
+ img.planes[0].ystride = frame->linesize[0];
+
+ img.planes[1].data = frame->data[1];
+ img.planes[1].xdec = 1;
+ img.planes[1].ydec = 1;
+ img.planes[1].xstride = 1;
+ img.planes[1].ystride = frame->linesize[1];
+
+ img.planes[2].data = frame->data[2];
+ img.planes[2].xdec = 1;
+ img.planes[2].ydec = 1;
+ img.planes[2].xstride = 1;
+ img.planes[2].ystride = frame->linesize[2];
+
+ img.nplanes = 3;
+
+ img.width = frame->size.w;
+ img.height = frame->size.h;
+
+ r = daala_encode_img_in(ves->enc, &img, 0);
+ if (r != 0) {
+ warning("daala: encoder: encode_img_in failed (ret = %d)\n",
+ r);
+ return EPROTO;
+ }
+
+ for (;;) {
+ ogg_packet op;
+
+ r = daala_encode_packet_out(ves->enc, 0, &op);
+ if (r < 0) {
+ warning("daala: encoder: packet_out ret=%d\n", r);
+ break;
+ }
+ else if (r == 0) {
+ break;
+ }
+
+ err = send_packet(ves, op.b_o_s, op.packet, op.bytes);
+ if (err)
+ break;
+ }
+
+ return 0;
+}
diff --git a/modules/daala/module.mk b/modules/daala/module.mk
new file mode 100644
index 0000000..93f88ac
--- /dev/null
+++ b/modules/daala/module.mk
@@ -0,0 +1,13 @@
+#
+# module.mk
+#
+# Copyright (C) 2010 Creytiv.com
+#
+
+MOD := daala
+$(MOD)_SRCS += decode.c
+$(MOD)_SRCS += encode.c
+$(MOD)_SRCS += daala.c
+$(MOD)_LFLAGS += -ldaalaenc -ldaaladec -ldaalabase
+
+include mk/mod.mk