// RTP Payload Format for VP9 Video draft-ietf-payload-vp9-03 #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 | | .... | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | VP9 payload descriptor (integer #octets) | : : | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | : VP9 pyld hdr | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | + | : Bytes 2..N of VP9 payload : | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | : OPTIONAL RTP padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static int rtp_decode_vp9(void* p, const void* packet, int bytes) { uint8_t pictureid_present; uint8_t inter_picture_predicted_layer_frame; uint8_t layer_indices_preset; uint8_t flex_mode; uint8_t start_of_layer_frame; //uint8_t end_of_layer_frame; uint8_t scalability_struct_data_present; 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; // VP9 payload descriptor /* 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |I|P|L|F|B|E|V|-| (REQUIRED) +-+-+-+-+-+-+-+-+ */ pictureid_present = ptr[0] & 0x80; inter_picture_predicted_layer_frame = ptr[0] & 0x40; layer_indices_preset = ptr[0] & 0x20; flex_mode = ptr[0] & 0x10; start_of_layer_frame = ptr[0] & 0x80; //end_of_layer_frame = ptr[0] & 0x04; scalability_struct_data_present = ptr[0] & 0x02; ptr++; if (pictureid_present && ptr < pend) { // +-+-+-+-+-+-+-+-+ // I: |M| PICTURE ID | (RECOMMENDED) // +-+-+-+-+-+-+-+-+ // M: | EXTENDED PID | (RECOMMENDED) // +-+-+-+-+-+-+-+-+ //uint16_t picture_id; //picture_id = ptr[0] & 0x7F; if ((ptr[0] & 0x80) && ptr + 1 < pend) { //picture_id = (ptr[0] << 8) | ptr[1]; ptr++; } ptr++; } if (layer_indices_preset && ptr < pend) { // +-+-+-+-+-+-+-+-+ // L: | T | U | S | D | (CONDITIONALLY RECOMMENDED) // +-+-+-+-+-+-+-+-+ // | TL0PICIDX | (CONDITIONALLY REQUIRED) // +-+-+-+-+-+-+-+-+ // ignore Layer indices if (0 == flex_mode) ptr++; // TL0PICIDX ptr++; } if (inter_picture_predicted_layer_frame && flex_mode && ptr < pend) { // +-+-+-+-+-+-+-+-+ -\ // P,F: | P_DIFF |N| (CONDITIONALLY REQUIRED) - up to 3 times // +-+-+-+-+-+-+-+-+ -/ // ignore Reference indices if (ptr[0] & 0x01) { if ((ptr[1] & 0x01) && ptr + 1 < pend) ptr++; ptr++; } ptr++; } if (scalability_struct_data_present && ptr < pend) { /* +-+-+-+-+-+-+-+-+ V: | N_S |Y|G|-|-|-| +-+-+-+-+-+-+-+-+ -\ Y: | WIDTH | (OPTIONAL) . + + . | | (OPTIONAL) . +-+-+-+-+-+-+-+-+ . - N_S + 1 times | HEIGHT | (OPTIONAL) . + + . | | (OPTIONAL) . +-+-+-+-+-+-+-+-+ -/ -\ G: | N_G | (OPTIONAL) +-+-+-+-+-+-+-+-+ -\ N_G:| T |U| R |-|-| (OPTIONAL) . +-+-+-+-+-+-+-+-+ -\ . - N_G times | P_DIFF | (OPTIONAL) . - R times . +-+-+-+-+-+-+-+-+ -/ -/ */ uint8_t N_S, Y, G; N_S = ((ptr[0] >> 5) & 0x07) + 1; Y = ptr[0] & 0x10; G = ptr[0] & 0x80; ptr++; if (Y) { ptr += N_S * 4; } if (G && ptr < pend) { uint8_t i; uint8_t N_G = ptr[0]; ptr++; for (i = 0; i < N_G && ptr < pend; i++) { uint8_t j; uint8_t R; R = (ptr[0] >> 2) & 0x03; ptr++; for (j = 0; j < R && ptr < pend; j++) { // ignore P_DIFF ptr++; } } } } if (ptr >= pend) { assert(0); //helper->size = 0; helper->lost = 1; //helper->flags |= RTP_PAYLOAD_FLAG_PACKET_LOST; return -1; // invalid packet } if (start_of_layer_frame) { // 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_vp9_decode() { static struct rtp_payload_decode_t unpacker = { rtp_payload_helper_create, rtp_payload_helper_destroy, rtp_decode_vp9, }; return &unpacker; }