rtp_format_vp8.cc (5050B)
1 /* 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/rtp_rtcp/source/rtp_format_vp8.h" 12 13 #include <cstdint> 14 #include <cstring> 15 #include <vector> 16 17 #include "api/array_view.h" 18 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" 19 #include "modules/video_coding/codecs/interface/common_constants.h" 20 #include "modules/video_coding/codecs/vp8/include/vp8_globals.h" 21 #include "rtc_base/checks.h" 22 23 namespace webrtc { 24 namespace { 25 26 constexpr int kXBit = 0x80; 27 constexpr int kNBit = 0x20; 28 constexpr int kSBit = 0x10; 29 constexpr int kKeyIdxField = 0x1F; 30 constexpr int kIBit = 0x80; 31 constexpr int kLBit = 0x40; 32 constexpr int kTBit = 0x20; 33 constexpr int kKBit = 0x10; 34 constexpr int kYBit = 0x20; 35 36 bool ValidateHeader(const RTPVideoHeaderVP8& hdr_info) { 37 if (hdr_info.pictureId != kNoPictureId) { 38 RTC_DCHECK_GE(hdr_info.pictureId, 0); 39 RTC_DCHECK_LE(hdr_info.pictureId, 0x7FFF); 40 } 41 if (hdr_info.tl0PicIdx != kNoTl0PicIdx) { 42 RTC_DCHECK_GE(hdr_info.tl0PicIdx, 0); 43 RTC_DCHECK_LE(hdr_info.tl0PicIdx, 0xFF); 44 } 45 if (hdr_info.temporalIdx != kNoTemporalIdx) { 46 RTC_DCHECK_GE(hdr_info.temporalIdx, 0); 47 RTC_DCHECK_LE(hdr_info.temporalIdx, 3); 48 } else { 49 RTC_DCHECK(!hdr_info.layerSync); 50 } 51 if (hdr_info.keyIdx != kNoKeyIdx) { 52 RTC_DCHECK_GE(hdr_info.keyIdx, 0); 53 RTC_DCHECK_LE(hdr_info.keyIdx, 0x1F); 54 } 55 return true; 56 } 57 58 } // namespace 59 60 RtpPacketizerVp8::RtpPacketizerVp8(ArrayView<const uint8_t> payload, 61 PayloadSizeLimits limits, 62 const RTPVideoHeaderVP8& hdr_info) 63 : hdr_(BuildHeader(hdr_info)), remaining_payload_(payload) { 64 limits.max_payload_len -= hdr_.size(); 65 if (!payload.empty()) { 66 payload_sizes_ = SplitAboutEqually(payload.size(), limits); 67 } 68 current_packet_ = payload_sizes_.begin(); 69 } 70 71 RtpPacketizerVp8::~RtpPacketizerVp8() = default; 72 73 size_t RtpPacketizerVp8::NumPackets() const { 74 return payload_sizes_.end() - current_packet_; 75 } 76 77 bool RtpPacketizerVp8::NextPacket(RtpPacketToSend* packet) { 78 RTC_DCHECK(packet); 79 if (current_packet_ == payload_sizes_.end()) { 80 return false; 81 } 82 83 size_t packet_payload_len = *current_packet_; 84 ++current_packet_; 85 86 uint8_t* buffer = packet->AllocatePayload(hdr_.size() + packet_payload_len); 87 RTC_CHECK(buffer); 88 89 memcpy(buffer, hdr_.data(), hdr_.size()); 90 memcpy(buffer + hdr_.size(), remaining_payload_.data(), packet_payload_len); 91 92 remaining_payload_ = remaining_payload_.subview(packet_payload_len); 93 hdr_[0] &= (~kSBit); // Clear 'Start of partition' bit. 94 packet->SetMarker(current_packet_ == payload_sizes_.end()); 95 return true; 96 } 97 98 RtpPacketizerVp8::RawHeader RtpPacketizerVp8::BuildHeader( 99 const RTPVideoHeaderVP8& header) { 100 // VP8 payload descriptor 101 // https://datatracker.ietf.org/doc/html/rfc7741#section-4.2 102 // 103 // 0 1 2 3 4 5 6 7 104 // +-+-+-+-+-+-+-+-+ 105 // |X|R|N|S|R| PID | (REQUIRED) 106 // +-+-+-+-+-+-+-+-+ 107 // X: |I|L|T|K| RSV | (OPTIONAL) 108 // +-+-+-+-+-+-+-+-+ 109 // I: |M| PictureID | (OPTIONAL) 110 // +-+-+-+-+-+-+-+-+ 111 // | PictureID | 112 // +-+-+-+-+-+-+-+-+ 113 // L: | TL0PICIDX | (OPTIONAL) 114 // +-+-+-+-+-+-+-+-+ 115 // T/K: |TID|Y| KEYIDX | (OPTIONAL) 116 // +-+-+-+-+-+-+-+-+ 117 RTC_DCHECK(ValidateHeader(header)); 118 119 RawHeader result; 120 bool tid_present = header.temporalIdx != kNoTemporalIdx; 121 bool keyid_present = header.keyIdx != kNoKeyIdx; 122 bool tl0_pid_present = header.tl0PicIdx != kNoTl0PicIdx; 123 bool pid_present = header.pictureId != kNoPictureId; 124 uint8_t x_field = 0; 125 if (pid_present) 126 x_field |= kIBit; 127 if (tl0_pid_present) 128 x_field |= kLBit; 129 if (tid_present) 130 x_field |= kTBit; 131 if (keyid_present) 132 x_field |= kKBit; 133 134 uint8_t flags = 0; 135 if (x_field != 0) 136 flags |= kXBit; 137 if (header.nonReference) 138 flags |= kNBit; 139 // Create header as first packet in the frame. NextPacket() will clear it 140 // after first use. 141 flags |= kSBit; 142 result.push_back(flags); 143 if (x_field == 0) { 144 return result; 145 } 146 result.push_back(x_field); 147 if (pid_present) { 148 const uint16_t pic_id = static_cast<uint16_t>(header.pictureId); 149 result.push_back(0x80 | ((pic_id >> 8) & 0x7F)); 150 result.push_back(pic_id & 0xFF); 151 } 152 if (tl0_pid_present) { 153 result.push_back(header.tl0PicIdx); 154 } 155 if (tid_present || keyid_present) { 156 uint8_t data_field = 0; 157 if (tid_present) { 158 data_field |= header.temporalIdx << 6; 159 if (header.layerSync) 160 data_field |= kYBit; 161 } 162 if (keyid_present) { 163 data_field |= (header.keyIdx & kKeyIdxField); 164 } 165 result.push_back(data_field); 166 } 167 return result; 168 } 169 170 } // namespace webrtc