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 "?";
+ }
+}