// RFC7741 RTP Payload Format for VP8 Video

#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>

/*
 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            |
|                              ....                             |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|             VP8 payload descriptor (integer #octets)          |
:                                                               :
|                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                               : VP8 payload header (3 octets) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| VP8 pyld hdr  :                                               |
+-+-+-+-+-+-+-+-+                                               |
:                   Octets 4..N of VP8 payload                  :
|                                                               |
|                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                               :      OPTIONAL RTP padding     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
static int rtp_decode_vp8(void* p, const void* packet, int bytes)
{
	uint8_t extended_control_bits;
	uint8_t start_of_vp8_partition;
	//uint8_t PID;
	const uint8_t *ptr, *pend;
	struct rtp_packet_t pkt;
	struct rtp_payload_helper_t *helper;

	helper = (struct rtp_payload_helper_t *)p;
	if (!helper || 0 != rtp_packet_deserialize(&pkt, packet, bytes) || pkt.payloadlen < 1)
		return -EINVAL;

	rtp_payload_check(helper, &pkt);

	ptr = (const uint8_t *)pkt.payload;
	pend = ptr + pkt.payloadlen;

	// VP8 payload descriptor
	extended_control_bits = ptr[0] & 0x80;
	start_of_vp8_partition = ptr[0] & 0x10;
	//PID = ptr[0] & 0x0f;
	ptr++;

	if (extended_control_bits && ptr < pend)
	{
		/*
			 0 1 2 3 4 5 6 7
			+-+-+-+-+-+-+-+-+
			|X|R|N|S|R| PID | (REQUIRED)
			+-+-+-+-+-+-+-+-+
		X:  |I|L|T|K|   RSV | (OPTIONAL)
			+-+-+-+-+-+-+-+-+
		I:  |M|  PictureID  | (OPTIONAL)
			+-+-+-+-+-+-+-+-+
			|   PictureID   |
			+-+-+-+-+-+-+-+-+
		L:  |   TL0PICIDX   | (OPTIONAL)
			+-+-+-+-+-+-+-+-+
		T/K:|TID|Y|  KEYIDX | (OPTIONAL)
			+-+-+-+-+-+-+-+-+
		*/
		uint8_t pictureid_present;
		uint8_t tl0picidx_present;
		uint8_t tid_present;
		uint8_t keyidx_present;

		pictureid_present = ptr[0] & 0x80;
		tl0picidx_present = ptr[0] & 0x40;
		tid_present = ptr[0] & 0x20;
		keyidx_present = ptr[0] & 0x10;
		ptr++;

		if (pictureid_present && ptr < pend)
		{
			uint16_t picture_id;
			picture_id = ptr[0] & 0x7F;
			if ((ptr[0] & 0x80) && ptr + 1 < pend)
			{
				picture_id = (picture_id << 8) | ptr[1];
				ptr++;
			}
			ptr++;
		}

		if (tl0picidx_present && ptr < pend)
		{
			// ignore temporal level zero index
			ptr++;
		}

		if ((tid_present || keyidx_present) && ptr < pend)
		{
			// ignore KEYIDX
			ptr++;
		}
	}

	if (ptr >= pend)
	{
		assert(0);
		//helper->size = 0;
		helper->lost = 1;
		//helper->flags |= RTP_PAYLOAD_FLAG_PACKET_LOST;
		return -1; // invalid packet
	}

	// VP8 payload header (3 octets)
	if (start_of_vp8_partition)
	{
		/*
		0 1 2 3 4 5 6 7
		+-+-+-+-+-+-+-+-+
		|Size0|H| VER |P|
		+-+-+-+-+-+-+-+-+
		| Size1 |
		+-+-+-+-+-+-+-+-+
		| Size2 |
		+-+-+-+-+-+-+-+-+
		*/
		// P: Inverse key frame flag. When set to 0, the current frame is a key
		//    frame. When set to 1, the current frame is an interframe.
		//    Defined in [RFC6386]
		//int keyframe;
		//keyframe = ptr[0] & 0x01; // PID == 0

		// new frame begin
		rtp_payload_onframe(helper);
	}

	pkt.payload = ptr;
	pkt.payloadlen = (int)(pend - ptr);
	rtp_payload_write(helper, &pkt);

	if (pkt.rtp.m)
	{
		rtp_payload_onframe(helper);
	}

	return 1; // packet handled
}

struct rtp_payload_decode_t *rtp_vp8_decode()
{
	static struct rtp_payload_decode_t unpacker = {
		rtp_payload_helper_create,
		rtp_payload_helper_destroy,
		rtp_decode_vp8,
	};

	return &unpacker;
}
