|
- // https://aomediacodec.github.io/av1-rtp-spec/#41-rtp-header-usage
-
- #include "rtp-packet.h"
- #include "rtp-profile.h"
- #include "rtp-payload-helper.h"
- #include "rtp-payload-internal.h"
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <errno.h>
- #include <errno.h>
-
- #define N_MAX_OBU 255
- #define N_RESERVED_OBU_SIZE_FIELD 2
-
- struct rtp_decode_av1_obu_t
- {
- int off;
- int len;
- };
-
- struct rtp_decode_av1_t
- {
- struct rtp_payload_t handler;
- void* cbparam;
-
- int lost;
- uint16_t seq; // rtp seq
- uint32_t timestamp;
-
- int flags;
-
- struct
- {
- struct rtp_decode_av1_obu_t* arr;
- int num, cap;
- } obu;
-
- struct
- {
- uint8_t* ptr;
- int len, cap;
- } ptr;
- };
-
- static inline const uint8_t* leb128(const uint8_t* data, size_t bytes, int64_t* size)
- {
- size_t i;
- for (*size = i = 0; i * 7 < 64 && i < bytes;)
- {
- *size |= ((int64_t)(data[i] & 0x7F)) << (i * 7);
- if (0 == (data[i++] & 0x80))
- break;
- }
- return data + i;
- }
-
- //static inline uint8_t* leb128_write(int64_t size, uint8_t* data, size_t bytes)
- //{
- // size_t i;
- // assert(3 == bytes && size <= 0x1FFFFF);
- // for (i = 0; i * 7 < 64 && i < bytes; i++)
- // {
- // data[i] = (uint8_t)(size & 0x7F);
- // size >>= 7;
- // data[i] |= (size > 0 || i + 1 < bytes)? 0x80 : 0;
- // }
- // return data + i;
- //}
-
- static inline int leb128_write(int64_t size, uint8_t* data, int bytes)
- {
- int i;
- for (i = 0; i * 7 < 64 && i < bytes;)
- {
- data[i] = (uint8_t)(size & 0x7F);
- size >>= 7;
- data[i++] |= size > 0 ? 0x80 : 0;
- if (0 == size)
- break;
- }
- return i;
- }
-
- static void* rtp_av1_unpack_create(struct rtp_payload_t* handler, void* param)
- {
- struct rtp_decode_av1_t* unpacker;
- unpacker = (struct rtp_decode_av1_t*)calloc(1, sizeof(*unpacker));
- if (!unpacker)
- return NULL;
-
- memcpy(&unpacker->handler, handler, sizeof(unpacker->handler));
- unpacker->cbparam = param;
- unpacker->flags = -1;
- return unpacker;
- }
-
- static void rtp_av1_unpack_destroy(void* p)
- {
- struct rtp_decode_av1_t* unpacker;
- unpacker = (struct rtp_decode_av1_t*)p;
-
- if (unpacker->obu.arr)
- free(unpacker->obu.arr);
- if (unpacker->ptr.ptr)
- free(unpacker->ptr.ptr);
- #if defined(_DEBUG) || defined(DEBUG)
- memset(unpacker, 0xCC, sizeof(*unpacker));
- #endif
- free(unpacker);
- }
-
- static int rtp_av1_unpack_obu_append(struct rtp_decode_av1_t* unpacker, const uint8_t* data, int bytes, int start)
- {
- void* p;
- int size;
- int64_t n;
- uint8_t head;
- const uint8_t* pend;
-
- pend = data + bytes;
- size = unpacker->ptr.len + bytes + 9 /*obu_size*/ + 2 /*obu temporal delimiter*/;
- if (size > RTP_PAYLOAD_MAX_SIZE || size < 0 || bytes < 2)
- return -EINVAL;
-
- if (size >= unpacker->ptr.cap)
- {
- size += size / 4 > 16000 ? size / 4 : 16000;
- p = realloc(unpacker->ptr.ptr, size);
- if (!p)
- {
- //unpacker->flags |= RTP_PAYLOAD_FLAG_PACKET_LOST;
- unpacker->lost = 1;
- //unpacker->size = 0;
- return -ENOMEM;
- }
-
- unpacker->ptr.ptr = (uint8_t*)p;
- unpacker->ptr.cap = size;
- }
-
- if (unpacker->obu.num + start >= unpacker->obu.cap)
- {
- if (unpacker->obu.cap >= N_MAX_OBU)
- return -E2BIG;
- p = realloc(unpacker->obu.arr, sizeof(struct rtp_decode_av1_obu_t) * (unpacker->obu.cap + 8));
- if (!p)
- return -ENOMEM;
-
- memset((struct rtp_decode_av1_obu_t*)p + unpacker->obu.cap, 0, sizeof(struct rtp_decode_av1_obu_t) * 8);
- unpacker->obu.arr = (struct rtp_decode_av1_obu_t*)p;
- unpacker->obu.cap += 8;
- }
-
- // add temporal delimiter obu
- //if (0 == unpacker->ptr.len)
- //{
- // static const uint8_t av1_temporal_delimiter[] = { 0x12, 0x00 };
- // assert(0 == unpacker->ptr.len);
- // memcpy(unpacker->ptr.ptr, av1_temporal_delimiter, sizeof(av1_temporal_delimiter));
- // unpacker->ptr.len += sizeof(av1_temporal_delimiter);
- //}
-
- if (start)
- {
- unpacker->obu.arr[unpacker->obu.num].off = unpacker->ptr.len;
- unpacker->obu.arr[unpacker->obu.num].len = 0;
-
- // obu_head
- head = *data++;
- unpacker->ptr.ptr[unpacker->ptr.len++] = head;
- if (head & 0x04) { // obu_extension_flag
- unpacker->ptr.ptr[unpacker->ptr.len++] = *data++;
- }
-
- if (head & 0x02) { // obu_has_size_field
- data = leb128(data, pend - data, &n);
- unpacker->ptr.len += leb128_write(n, unpacker->ptr.ptr + unpacker->ptr.len, unpacker->ptr.cap - unpacker->ptr.len);
- } else {
- unpacker->ptr.len += N_RESERVED_OBU_SIZE_FIELD; // obu_size
- }
-
- unpacker->obu.num++;
- }
-
- unpacker->obu.arr[unpacker->obu.num-1].len += (int)(intptr_t)(pend - data);
-
- // obu
- memcpy(unpacker->ptr.ptr + unpacker->ptr.len, data, pend - data);
- unpacker->ptr.len += (int)(intptr_t)(pend - data);
- return 0;
- }
-
- int rtp_av1_unpack_onframe(struct rtp_decode_av1_t* unpacker)
- {
- int i, j, r, n;
- uint8_t* obu, *data, obu_size_field[9];
- int64_t len;
- r = 0;
-
- if (unpacker->obu.num < unpacker->obu.cap && unpacker->obu.arr[0].len > 0
- #if !defined(RTP_ENABLE_COURRUPT_PACKET)
- && 0 == unpacker->lost
- #endif
- )
- {
- // write obu length
- for (i = 0; i < unpacker->obu.num; i++)
- {
- obu = unpacker->ptr.ptr + unpacker->obu.arr[i].off;
- data = obu + ((0x04 & obu[0]) ? 2 : 1);
- if (0x02 & obu[0]) { // obu_has_size_field
- assert(unpacker->lost || (leb128(data, 9, &len) && len == unpacker->obu.arr[i].len));
- continue;
- }
-
- obu[0] |= 0x02; // obu_has_size_field
- n = leb128_write(unpacker->obu.arr[i].len, obu_size_field, sizeof(obu_size_field));
- if (n != N_RESERVED_OBU_SIZE_FIELD) {
- memmove(data + n, data + N_RESERVED_OBU_SIZE_FIELD, unpacker->ptr.ptr + unpacker->ptr.len - (data + N_RESERVED_OBU_SIZE_FIELD));
- unpacker->ptr.len -= N_RESERVED_OBU_SIZE_FIELD - n;
- for (j = i + 1; j < unpacker->obu.num; j++)
- {
- assert(unpacker->obu.arr[j].off + n > N_RESERVED_OBU_SIZE_FIELD);
- unpacker->obu.arr[j].off = unpacker->obu.arr[j].off + n - N_RESERVED_OBU_SIZE_FIELD;
- }
- }
- memcpy(data, obu_size_field, n);
- }
-
- // previous packet done
- r = unpacker->handler.packet(unpacker->cbparam, unpacker->ptr.ptr, unpacker->ptr.len, unpacker->timestamp, unpacker->flags | (unpacker->lost ? RTP_PAYLOAD_FLAG_PACKET_CORRUPT : 0));
-
- // RTP_PAYLOAD_FLAG_PACKET_LOST: miss
- unpacker->flags &= ~RTP_PAYLOAD_FLAG_PACKET_LOST; // clear packet lost flag
- }
-
- // set packet lost flag on next frame
- if (unpacker->lost)
- unpacker->flags |= RTP_PAYLOAD_FLAG_PACKET_LOST;
-
- // new frame start
- unpacker->lost = 0;
- unpacker->ptr.len = 0;
- unpacker->obu.num = 0;
- memset(unpacker->obu.arr, 0, sizeof(struct rtp_decode_av1_obu_t) * unpacker->obu.cap);
- return r;
- }
-
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |V=2|P|X| CC |M| PT | sequence number |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | timestamp |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | synchronization source (SSRC) identifier |
- +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
- | contributing source (CSRC) identifiers |
- | .... |
- +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
- | 0x100 | 0x0 | extensions length |
- +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
- | 0x1(ID) | hdr_length | |
- +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
- | |
- | dependency descriptor (hdr_length #octets) |
- | |
- | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | | Other rtp header extensions...|
- +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
- | AV1 aggr hdr | |
- +-+-+-+-+-+-+-+-+ |
- | |
- | Bytes 2..N of AV1 payload |
- | |
- | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | : OPTIONAL RTP padding |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- static int rtp_av1_unpack_input(void* p, const void* packet, int bytes)
- {
- int lost;
- int64_t size;
- uint8_t z, y, w, n, i;
- const uint8_t *ptr, *pend;
- struct rtp_packet_t pkt;
- struct rtp_decode_av1_t* unpacker;
-
- unpacker = (struct rtp_decode_av1_t*)p;
- if (!unpacker || 0 != rtp_packet_deserialize(&pkt, packet, bytes) || pkt.payloadlen < 1)
- return -EINVAL;
-
- lost = 0;
- if (-1 == unpacker->flags)
- {
- unpacker->flags = 0;
- unpacker->seq = (uint16_t)(pkt.rtp.seq - 1); // disable packet lost
- }
-
- if ((uint16_t)pkt.rtp.seq != (uint16_t)(unpacker->seq + 1))
- {
- lost = 1;
- unpacker->flags = RTP_PAYLOAD_FLAG_PACKET_LOST;
- unpacker->ptr.len = 0; // discard previous packets
- }
-
- // check timestamp
- if (pkt.rtp.timestamp != unpacker->timestamp)
- {
- rtp_av1_unpack_onframe(unpacker);
-
- // lost:
- // 0 - packet lost before timestamp change
- // 1 - packet lost on timestamp changed, can't known losted packet is at old packet tail or new packet start, so two packets mark as packet lost
- if (0 != lost)
- unpacker->lost = lost;
- }
- unpacker->seq = (uint16_t)pkt.rtp.seq;
- unpacker->timestamp = pkt.rtp.timestamp;
-
- ptr = (const uint8_t *)pkt.payload;
- pend = ptr + pkt.payloadlen;
-
- // AV1 aggregation header
- /*
- 0 1 2 3 4 5 6 7
- +-+-+-+-+-+-+-+-+
- |Z|Y| W |N|-|-|-|
- +-+-+-+-+-+-+-+-+
- */
- z = ptr[0] & 0x80; // MUST be set to 1 if the first OBU element is an OBU fragment that is a continuation of an OBU fragment from the previous packet, and MUST be set to 0 otherwise.
- y = ptr[0] & 0x40; // MUST be set to 1 if the last OBU element is an OBU fragment that will continue in the next packet, and MUST be set to 0 otherwise.
- w = (ptr[0] & 0x30) >> 4; // two bit field that describes the number of OBU elements in the packet. This field MUST be set equal to 0 or equal to the number of OBU elements contained in the packet. If set to 0, each OBU element MUST be preceded by a length field.
- n = ptr[0] & 0x08; // MUST be set to 1 if the packet is the first packet of a coded video sequence, and MUST be set to 0 otherwise.
- (void)y;
-
- // if N equals 1 then Z must equal 0.
- assert(!n || 0 == z);
- if (0 == z && 1 == n) {
- // new video codec sequence
- rtp_av1_unpack_onframe(unpacker);
- }
-
- for (i = 1, ptr++; ptr < pend; ptr += size, i++)
- {
- if (i < w || 0 == w)
- {
- ptr = leb128(ptr, pend - ptr, &size);
- }
- else
- {
- size = pend - ptr;
- }
-
- // skip fragment frame OBU size
- if (ptr + size > pend)
- {
- //assert(0);
- //unpacker->size = 0;
- unpacker->lost = 1;
- //unpacker->flags |= RTP_PAYLOAD_FLAG_PACKET_LOST;
- return -1; // invalid packet
- }
-
- rtp_av1_unpack_obu_append(unpacker, ptr, (int)size, (1 != i || 0 == z) ? 1 : 0);
- }
-
- // The RTP header Marker bit MUST be set equal to 0
- // if the packet is not the last packet of the temporal unit,
- // it SHOULD be set equal to 1 otherwise.
- if (pkt.rtp.m)
- {
- rtp_av1_unpack_onframe(unpacker);
- }
-
- return 1; // packet handled
- }
-
- struct rtp_payload_decode_t *rtp_av1_decode()
- {
- static struct rtp_payload_decode_t unpacker = {
- rtp_av1_unpack_create,
- rtp_av1_unpack_destroy,
- rtp_av1_unpack_input,
- };
-
- return &unpacker;
- }
|