diff options
Diffstat (limited to 'third_party/libwebrtc/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc')
-rw-r--r-- | third_party/libwebrtc/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc new file mode 100644 index 0000000000..8a0810f445 --- /dev/null +++ b/third_party/libwebrtc/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h" + +#include "rtc_base/checks.h" + +namespace webrtc { +namespace { + +constexpr uint8_t kFlagBeginOfSubframe = 0x80; +constexpr uint8_t kFlagEndOfSubframe = 0x40; + +// In version 00, the flags F and L in the first byte correspond to +// kFlagFirstSubframeV00 and kFlagLastSubframeV00. In practice, they were +// always set to `true`. +constexpr uint8_t kFlagFirstSubframeV00 = 0x20; +constexpr uint8_t kFlagLastSubframeV00 = 0x10; + +constexpr uint8_t kFlagDependencies = 0x08; +constexpr uint8_t kMaskTemporalLayer = 0x07; + +constexpr uint8_t kFlagMoreDependencies = 0x01; +constexpr uint8_t kFlageXtendedOffset = 0x02; +} // namespace +// 0 1 2 3 4 5 6 7 +// +-+-+-+-+-+-+-+-+ +// |B|E|F|L|D| T | +// +-+-+-+-+-+-+-+-+ +// B: | S | +// +-+-+-+-+-+-+-+-+ +// | | +// B: + FID + +// | | +// +-+-+-+-+-+-+-+-+ +// | | +// + Width + +// B=1 | | +// and +-+-+-+-+-+-+-+-+ +// D=0 | | +// + Height + +// | | +// +-+-+-+-+-+-+-+-+ +// D: | FDIFF |X|M| +// +---------------+ +// X: | ... | +// +-+-+-+-+-+-+-+-+ +// M: | FDIFF |X|M| +// +---------------+ +// | ... | +// +-+-+-+-+-+-+-+-+ +constexpr RTPExtensionType RtpGenericFrameDescriptorExtension00::kId; + +bool RtpGenericFrameDescriptorExtension00::Parse( + rtc::ArrayView<const uint8_t> data, + RtpGenericFrameDescriptor* descriptor) { + if (data.empty()) { + return false; + } + + bool begins_subframe = (data[0] & kFlagBeginOfSubframe) != 0; + descriptor->SetFirstPacketInSubFrame(begins_subframe); + descriptor->SetLastPacketInSubFrame((data[0] & kFlagEndOfSubframe) != 0); + + // Parse Subframe details provided in 1st packet of subframe. + if (!begins_subframe) { + return data.size() == 1; + } + if (data.size() < 4) { + return false; + } + descriptor->SetTemporalLayer(data[0] & kMaskTemporalLayer); + descriptor->SetSpatialLayersBitmask(data[1]); + descriptor->SetFrameId(data[2] | (data[3] << 8)); + + // Parse dependencies. + descriptor->ClearFrameDependencies(); + size_t offset = 4; + bool has_more_dependencies = (data[0] & kFlagDependencies) != 0; + if (!has_more_dependencies && data.size() >= offset + 4) { + uint16_t width = (data[offset] << 8) | data[offset + 1]; + uint16_t height = (data[offset + 2] << 8) | data[offset + 3]; + descriptor->SetResolution(width, height); + offset += 4; + } + while (has_more_dependencies) { + if (data.size() == offset) + return false; + has_more_dependencies = (data[offset] & kFlagMoreDependencies) != 0; + bool extended = (data[offset] & kFlageXtendedOffset) != 0; + uint16_t fdiff = data[offset] >> 2; + offset++; + if (extended) { + if (data.size() == offset) + return false; + fdiff |= (data[offset] << 6); + offset++; + } + if (!descriptor->AddFrameDependencyDiff(fdiff)) + return false; + } + return true; +} + +size_t RtpGenericFrameDescriptorExtension00::ValueSize( + const RtpGenericFrameDescriptor& descriptor) { + if (!descriptor.FirstPacketInSubFrame()) + return 1; + + size_t size = 4; + for (uint16_t fdiff : descriptor.FrameDependenciesDiffs()) { + size += (fdiff >= (1 << 6)) ? 2 : 1; + } + if (descriptor.FirstPacketInSubFrame() && + descriptor.FrameDependenciesDiffs().empty() && descriptor.Width() > 0 && + descriptor.Height() > 0) { + size += 4; + } + return size; +} + +bool RtpGenericFrameDescriptorExtension00::Write( + rtc::ArrayView<uint8_t> data, + const RtpGenericFrameDescriptor& descriptor) { + RTC_CHECK_EQ(data.size(), ValueSize(descriptor)); + uint8_t base_header = + (descriptor.FirstPacketInSubFrame() ? kFlagBeginOfSubframe : 0) | + (descriptor.LastPacketInSubFrame() ? kFlagEndOfSubframe : 0); + base_header |= kFlagFirstSubframeV00; + base_header |= kFlagLastSubframeV00; + + if (!descriptor.FirstPacketInSubFrame()) { + data[0] = base_header; + return true; + } + data[0] = + base_header | + (descriptor.FrameDependenciesDiffs().empty() ? 0 : kFlagDependencies) | + descriptor.TemporalLayer(); + data[1] = descriptor.SpatialLayersBitmask(); + uint16_t frame_id = descriptor.FrameId(); + data[2] = frame_id & 0xff; + data[3] = frame_id >> 8; + rtc::ArrayView<const uint16_t> fdiffs = descriptor.FrameDependenciesDiffs(); + size_t offset = 4; + if (descriptor.FirstPacketInSubFrame() && fdiffs.empty() && + descriptor.Width() > 0 && descriptor.Height() > 0) { + data[offset++] = (descriptor.Width() >> 8); + data[offset++] = (descriptor.Width() & 0xFF); + data[offset++] = (descriptor.Height() >> 8); + data[offset++] = (descriptor.Height() & 0xFF); + } + for (size_t i = 0; i < fdiffs.size(); i++) { + bool extended = fdiffs[i] >= (1 << 6); + bool more = i < fdiffs.size() - 1; + data[offset++] = ((fdiffs[i] & 0x3f) << 2) | + (extended ? kFlageXtendedOffset : 0) | + (more ? kFlagMoreDependencies : 0); + if (extended) { + data[offset++] = fdiffs[i] >> 6; + } + } + return true; +} + +} // namespace webrtc |