// 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 #include #include #include #include /* 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; }