/* * 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 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 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 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