1 /* 2 * Copyright (c) 2018 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_generic_frame_descriptor_extension.h" 12 13 #include "rtc_base/checks.h" 14 15 namespace webrtc { 16 namespace { 17 18 constexpr uint8_t kFlagBeginOfSubframe = 0x80; 19 constexpr uint8_t kFlagEndOfSubframe = 0x40; 20 21 // In version 00, the flags F and L in the first byte correspond to 22 // kFlagFirstSubframeV00 and kFlagLastSubframeV00. In practice, they were 23 // always set to |true|. 24 constexpr uint8_t kFlagFirstSubframeV00 = 0x20; 25 constexpr uint8_t kFlagLastSubframeV00 = 0x10; 26 27 constexpr uint8_t kFlagDependencies = 0x08; 28 constexpr uint8_t kMaskTemporalLayer = 0x07; 29 30 constexpr uint8_t kFlagMoreDependencies = 0x01; 31 constexpr uint8_t kFlageXtendedOffset = 0x02; 32 } // namespace 33 // 0 1 2 3 4 5 6 7 34 // +-+-+-+-+-+-+-+-+ 35 // |B|E|F|L|D| T | 36 // +-+-+-+-+-+-+-+-+ 37 // B: | S | 38 // +-+-+-+-+-+-+-+-+ 39 // | | 40 // B: + FID + 41 // | | 42 // +-+-+-+-+-+-+-+-+ 43 // | | 44 // + Width + 45 // B=1 | | 46 // and +-+-+-+-+-+-+-+-+ 47 // D=0 | | 48 // + Height + 49 // | | 50 // +-+-+-+-+-+-+-+-+ 51 // D: | FDIFF |X|M| 52 // +---------------+ 53 // X: | ... | 54 // +-+-+-+-+-+-+-+-+ 55 // M: | FDIFF |X|M| 56 // +---------------+ 57 // | ... | 58 // +-+-+-+-+-+-+-+-+ 59 constexpr RTPExtensionType RtpGenericFrameDescriptorExtension00::kId; 60 constexpr char RtpGenericFrameDescriptorExtension00::kUri[]; 61 Parse(rtc::ArrayView<const uint8_t> data,RtpGenericFrameDescriptor * descriptor)62bool RtpGenericFrameDescriptorExtension00::Parse( 63 rtc::ArrayView<const uint8_t> data, 64 RtpGenericFrameDescriptor* descriptor) { 65 if (data.empty()) { 66 return false; 67 } 68 69 bool begins_subframe = (data[0] & kFlagBeginOfSubframe) != 0; 70 descriptor->SetFirstPacketInSubFrame(begins_subframe); 71 descriptor->SetLastPacketInSubFrame((data[0] & kFlagEndOfSubframe) != 0); 72 73 // Parse Subframe details provided in 1st packet of subframe. 74 if (!begins_subframe) { 75 return data.size() == 1; 76 } 77 if (data.size() < 4) { 78 return false; 79 } 80 descriptor->SetTemporalLayer(data[0] & kMaskTemporalLayer); 81 descriptor->SetSpatialLayersBitmask(data[1]); 82 descriptor->SetFrameId(data[2] | (data[3] << 8)); 83 84 // Parse dependencies. 85 descriptor->ClearFrameDependencies(); 86 size_t offset = 4; 87 bool has_more_dependencies = (data[0] & kFlagDependencies) != 0; 88 if (!has_more_dependencies && data.size() >= offset + 4) { 89 uint16_t width = (data[offset] << 8) | data[offset + 1]; 90 uint16_t height = (data[offset + 2] << 8) | data[offset + 3]; 91 descriptor->SetResolution(width, height); 92 offset += 4; 93 } 94 while (has_more_dependencies) { 95 if (data.size() == offset) 96 return false; 97 has_more_dependencies = (data[offset] & kFlagMoreDependencies) != 0; 98 bool extended = (data[offset] & kFlageXtendedOffset) != 0; 99 uint16_t fdiff = data[offset] >> 2; 100 offset++; 101 if (extended) { 102 if (data.size() == offset) 103 return false; 104 fdiff |= (data[offset] << 6); 105 offset++; 106 } 107 if (!descriptor->AddFrameDependencyDiff(fdiff)) 108 return false; 109 } 110 return true; 111 } 112 ValueSize(const RtpGenericFrameDescriptor & descriptor)113size_t RtpGenericFrameDescriptorExtension00::ValueSize( 114 const RtpGenericFrameDescriptor& descriptor) { 115 if (!descriptor.FirstPacketInSubFrame()) 116 return 1; 117 118 size_t size = 4; 119 for (uint16_t fdiff : descriptor.FrameDependenciesDiffs()) { 120 size += (fdiff >= (1 << 6)) ? 2 : 1; 121 } 122 if (descriptor.FirstPacketInSubFrame() && 123 descriptor.FrameDependenciesDiffs().empty() && descriptor.Width() > 0 && 124 descriptor.Height() > 0) { 125 size += 4; 126 } 127 return size; 128 } 129 Write(rtc::ArrayView<uint8_t> data,const RtpGenericFrameDescriptor & descriptor)130bool RtpGenericFrameDescriptorExtension00::Write( 131 rtc::ArrayView<uint8_t> data, 132 const RtpGenericFrameDescriptor& descriptor) { 133 RTC_CHECK_EQ(data.size(), ValueSize(descriptor)); 134 uint8_t base_header = 135 (descriptor.FirstPacketInSubFrame() ? kFlagBeginOfSubframe : 0) | 136 (descriptor.LastPacketInSubFrame() ? kFlagEndOfSubframe : 0); 137 base_header |= kFlagFirstSubframeV00; 138 base_header |= kFlagLastSubframeV00; 139 140 if (!descriptor.FirstPacketInSubFrame()) { 141 data[0] = base_header; 142 return true; 143 } 144 data[0] = 145 base_header | 146 (descriptor.FrameDependenciesDiffs().empty() ? 0 : kFlagDependencies) | 147 descriptor.TemporalLayer(); 148 data[1] = descriptor.SpatialLayersBitmask(); 149 uint16_t frame_id = descriptor.FrameId(); 150 data[2] = frame_id & 0xff; 151 data[3] = frame_id >> 8; 152 rtc::ArrayView<const uint16_t> fdiffs = descriptor.FrameDependenciesDiffs(); 153 size_t offset = 4; 154 if (descriptor.FirstPacketInSubFrame() && fdiffs.empty() && 155 descriptor.Width() > 0 && descriptor.Height() > 0) { 156 data[offset++] = (descriptor.Width() >> 8); 157 data[offset++] = (descriptor.Width() & 0xFF); 158 data[offset++] = (descriptor.Height() >> 8); 159 data[offset++] = (descriptor.Height() & 0xFF); 160 } 161 for (size_t i = 0; i < fdiffs.size(); i++) { 162 bool extended = fdiffs[i] >= (1 << 6); 163 bool more = i < fdiffs.size() - 1; 164 data[offset++] = ((fdiffs[i] & 0x3f) << 2) | 165 (extended ? kFlageXtendedOffset : 0) | 166 (more ? kFlagMoreDependencies : 0); 167 if (extended) { 168 data[offset++] = fdiffs[i] >> 6; 169 } 170 } 171 return true; 172 } 173 174 } // namespace webrtc 175