Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b

Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/rtmp/hdr.c b/src/rtmp/hdr.c
new file mode 100644
index 0000000..38bd370
--- /dev/null
+++ b/src/rtmp/hdr.c
@@ -0,0 +1,279 @@
+/**
+ * @file rtmp/hdr.c  Real Time Messaging Protocol (RTMP) -- Headers
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+#include <re_net.h>
+#include <re_sa.h>
+#include <re_list.h>
+#include <re_sys.h>
+#include <re_rtmp.h>
+#include "rtmp.h"
+
+
+enum {
+	RTMP_CHUNK_ID_MIN     = 3,
+	RTMP_CHUNK_ID_MAX     = 65599,  /* 65535 + 64 */
+
+	RTMP_CHUNK_OFFSET     = 64,
+	TIMESTAMP_24MAX       = 0x00ffffff,
+};
+
+
+static int mbuf_write_u24_hton(struct mbuf *mb, uint32_t u24)
+{
+	int err = 0;
+
+	err |= mbuf_write_u8(mb, u24 >> 16);
+	err |= mbuf_write_u8(mb, u24 >> 8);
+	err |= mbuf_write_u8(mb, u24 >> 0);
+
+	return err;
+}
+
+
+static uint32_t mbuf_read_u24_ntoh(struct mbuf *mb)
+{
+	uint32_t u24;
+
+	u24  = (uint32_t)mbuf_read_u8(mb) << 16;
+	u24 |= (uint32_t)mbuf_read_u8(mb) << 8;
+	u24 |= (uint32_t)mbuf_read_u8(mb) << 0;
+
+	return u24;
+}
+
+
+static int encode_basic_hdr(struct mbuf *mb, unsigned fmt,
+			    uint32_t chunk_id)
+{
+	uint8_t v;
+	int err = 0;
+
+	if (chunk_id >= 320) {
+
+		const uint16_t cs_id = chunk_id - RTMP_CHUNK_OFFSET;
+
+		v = fmt<<6 | 1;
+
+		err |= mbuf_write_u8(mb, v);
+		err |= mbuf_write_u16(mb, htons(cs_id));
+	}
+	else if (chunk_id >= RTMP_CHUNK_OFFSET) {
+
+		const uint8_t cs_id = chunk_id - RTMP_CHUNK_OFFSET;
+
+		v = fmt<<6 | 0;
+
+		err |= mbuf_write_u8(mb, v);
+		err |= mbuf_write_u8(mb, cs_id);
+	}
+	else {
+		v = fmt<<6 | chunk_id;
+
+		err |= mbuf_write_u8(mb, v);
+	}
+
+	return err;
+}
+
+
+static int decode_basic_hdr(struct rtmp_header *hdr, struct mbuf *mb)
+{
+	uint8_t cs_id;
+	uint8_t v;
+
+	if (mbuf_get_left(mb) < 1)
+		return ENODATA;
+
+	v = mbuf_read_u8(mb);
+
+	hdr->format = v>>6;
+
+	cs_id = v & 0x3f;
+
+	switch (cs_id) {
+
+	case 0:
+		if (mbuf_get_left(mb) < 1)
+			return ENODATA;
+
+		hdr->chunk_id = mbuf_read_u8(mb) + RTMP_CHUNK_OFFSET;
+		break;
+
+	case 1:
+		if (mbuf_get_left(mb) < 2)
+			return ENODATA;
+
+		hdr->chunk_id = ntohs(mbuf_read_u16(mb)) + RTMP_CHUNK_OFFSET;
+		break;
+
+	default:
+		hdr->chunk_id = cs_id;
+		break;
+	}
+
+	return 0;
+}
+
+
+static uint32_t ts_24(uint32_t ts)
+{
+	return ts >= TIMESTAMP_24MAX ? TIMESTAMP_24MAX : ts;
+}
+
+
+static uint32_t ts_ext(uint32_t ts)
+{
+	return ts >= TIMESTAMP_24MAX ? ts : 0;
+}
+
+
+int rtmp_header_encode(struct mbuf *mb, struct rtmp_header *hdr)
+{
+	int err = 0;
+
+	if (!mb || !hdr)
+		return EINVAL;
+
+	err = encode_basic_hdr(mb, hdr->format, hdr->chunk_id);
+	if (err)
+		return err;
+
+	switch (hdr->format) {
+
+	case 0:
+		hdr->timestamp_ext = ts_ext(hdr->timestamp);
+
+		err |= mbuf_write_u24_hton(mb, ts_24(hdr->timestamp));
+		err |= mbuf_write_u24_hton(mb, hdr->length);
+		err |= mbuf_write_u8(mb, hdr->type_id);
+		err |= mbuf_write_u32(mb, sys_htoll(hdr->stream_id));
+		break;
+
+	case 1:
+		hdr->timestamp_ext = ts_ext(hdr->timestamp_delta);
+
+		err |= mbuf_write_u24_hton(mb, ts_24(hdr->timestamp_delta));
+		err |= mbuf_write_u24_hton(mb, hdr->length);
+		err |= mbuf_write_u8(mb, hdr->type_id);
+		break;
+
+	case 2:
+		hdr->timestamp_ext = ts_ext(hdr->timestamp_delta);
+
+		err |= mbuf_write_u24_hton(mb, ts_24(hdr->timestamp_delta));
+		break;
+
+	case 3:
+		break;
+	}
+
+	if (hdr->timestamp_ext) {
+		err |= mbuf_write_u32(mb, htonl(hdr->timestamp_ext));
+	}
+
+	return err;
+}
+
+
+int rtmp_header_decode(struct rtmp_header *hdr, struct mbuf *mb)
+{
+	uint32_t *timestamp_ext = NULL;
+	int err;
+
+	if (!hdr || !mb)
+		return EINVAL;
+
+	memset(hdr, 0, sizeof(*hdr));
+
+	err = decode_basic_hdr(hdr, mb);
+	if (err)
+		return err;
+
+	switch (hdr->format) {
+
+	case 0:
+		if (mbuf_get_left(mb) < 11)
+			return ENODATA;
+
+		hdr->timestamp = mbuf_read_u24_ntoh(mb);
+		hdr->length    = mbuf_read_u24_ntoh(mb);
+		hdr->type_id   = mbuf_read_u8(mb);
+		hdr->stream_id = sys_ltohl(mbuf_read_u32(mb));
+		break;
+
+	case 1:
+		if (mbuf_get_left(mb) < 7)
+			return ENODATA;
+
+		hdr->timestamp_delta = mbuf_read_u24_ntoh(mb);
+		hdr->length          = mbuf_read_u24_ntoh(mb);
+		hdr->type_id         = mbuf_read_u8(mb);
+		break;
+
+	case 2:
+		if (mbuf_get_left(mb) < 3)
+			return ENODATA;
+
+		hdr->timestamp_delta = mbuf_read_u24_ntoh(mb);
+		break;
+
+	case 3:
+		/* no payload */
+		break;
+	}
+
+	if (hdr->timestamp == TIMESTAMP_24MAX)
+		timestamp_ext = &hdr->timestamp;
+	else if (hdr->timestamp_delta == TIMESTAMP_24MAX)
+		timestamp_ext = &hdr->timestamp_delta;
+
+	if (timestamp_ext) {
+		if (mbuf_get_left(mb) < 4)
+			return ENODATA;
+
+		*timestamp_ext = ntohl(mbuf_read_u32(mb));
+		hdr->ext_ts = true;
+	}
+
+	return 0;
+}
+
+
+int rtmp_header_print(struct re_printf *pf, const struct rtmp_header *hdr)
+{
+	if (!hdr)
+		return 0;
+
+	return re_hprintf(pf,
+			  "fmt %u, chunk %u, "
+			  "timestamp %5u, ts_delta %2u,"
+			  " len %3u, type %2u (%-14s) stream_id %u",
+			  hdr->format, hdr->chunk_id, hdr->timestamp,
+			  hdr->timestamp_delta, hdr->length, hdr->type_id,
+			  rtmp_packet_type_name(hdr->type_id), hdr->stream_id);
+}
+
+
+const char *rtmp_packet_type_name(enum rtmp_packet_type type)
+{
+	switch (type) {
+
+	case RTMP_TYPE_SET_CHUNK_SIZE:    return "Set Chunk Size";
+	case RTMP_TYPE_ACKNOWLEDGEMENT:   return "Acknowledgement";
+	case RTMP_TYPE_USER_CONTROL_MSG:  return "User Control Message";
+	case RTMP_TYPE_WINDOW_ACK_SIZE:   return "Window Acknowledgement Size";
+	case RTMP_TYPE_SET_PEER_BANDWIDTH:return "Set Peer Bandwidth";
+	case RTMP_TYPE_AUDIO:             return "Audio Message";
+	case RTMP_TYPE_VIDEO:             return "Video Message";
+	case RTMP_TYPE_DATA:              return "Data Message";
+	case RTMP_TYPE_AMF0:              return "AMF";
+	default: return "?";
+	}
+}