/* * Copyright (c) 2019 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_dependency_descriptor_writer.h" #include #include #include #include #include #include "absl/algorithm/container.h" #include "api/array_view.h" #include "api/transport/rtp/dependency_descriptor.h" #include "rtc_base/bit_buffer.h" #include "rtc_base/checks.h" namespace webrtc { namespace { enum class NextLayerIdc : uint64_t { kSameLayer = 0, kNextTemporal = 1, kNewSpatial = 2, kNoMoreLayers = 3, kInvalid = 4 }; NextLayerIdc GetNextLayerIdc(const FrameDependencyTemplate& previous, const FrameDependencyTemplate& next) { RTC_DCHECK_LT(next.spatial_id, DependencyDescriptor::kMaxSpatialIds); RTC_DCHECK_LT(next.temporal_id, DependencyDescriptor::kMaxTemporalIds); if (next.spatial_id == previous.spatial_id && next.temporal_id == previous.temporal_id) { return NextLayerIdc::kSameLayer; } else if (next.spatial_id == previous.spatial_id && next.temporal_id == previous.temporal_id + 1) { return NextLayerIdc::kNextTemporal; } else if (next.spatial_id == previous.spatial_id + 1 && next.temporal_id == 0) { return NextLayerIdc::kNewSpatial; } // Everything else is unsupported. return NextLayerIdc::kInvalid; } } // namespace RtpDependencyDescriptorWriter::RtpDependencyDescriptorWriter( rtc::ArrayView data, const FrameDependencyStructure& structure, std::bitset<32> active_chains, const DependencyDescriptor& descriptor) : descriptor_(descriptor), structure_(structure), active_chains_(active_chains), bit_writer_(data.data(), data.size()) { FindBestTemplate(); } bool RtpDependencyDescriptorWriter::Write() { if (build_failed_) { return false; } WriteMandatoryFields(); if (HasExtendedFields()) { WriteExtendedFields(); WriteFrameDependencyDefinition(); } size_t remaining_bits = bit_writer_.RemainingBitCount(); // Zero remaining memory to avoid leaving it uninitialized. if (remaining_bits % 64 != 0) { WriteBits(/*val=*/0, remaining_bits % 64); } for (size_t i = 0; i < remaining_bits / 64; ++i) { WriteBits(/*val=*/0, 64); } return !build_failed_; } int RtpDependencyDescriptorWriter::ValueSizeBits() const { if (build_failed_) { return 0; } static constexpr int kMandatoryFields = 1 + 1 + 6 + 16; int value_size_bits = kMandatoryFields + best_template_.extra_size_bits; if (HasExtendedFields()) { value_size_bits += 5; if (descriptor_.attached_structure) value_size_bits += StructureSizeBits(); if (ShouldWriteActiveDecodeTargetsBitmask()) value_size_bits += structure_.num_decode_targets; } return value_size_bits; } int RtpDependencyDescriptorWriter::StructureSizeBits() const { // template_id offset (6 bits) and number of decode targets (5 bits) int bits = 11; // template layers. bits += 2 * structure_.templates.size(); // dtis. bits += 2 * structure_.templates.size() * structure_.num_decode_targets; // fdiffs. each templates uses 1 + 5 * sizeof(fdiff) bits. bits += structure_.templates.size(); for (const FrameDependencyTemplate& frame_template : structure_.templates) { bits += 5 * frame_template.frame_diffs.size(); } bits += rtc::BitBufferWriter::SizeNonSymmetricBits( structure_.num_chains, structure_.num_decode_targets + 1); if (structure_.num_chains > 0) { for (int protected_by : structure_.decode_target_protected_by_chain) { bits += rtc::BitBufferWriter::SizeNonSymmetricBits(protected_by, structure_.num_chains); } bits += 4 * structure_.templates.size() * structure_.num_chains; } // Resolutions. bits += 1 + 32 * structure_.resolutions.size(); return bits; } RtpDependencyDescriptorWriter::TemplateMatch RtpDependencyDescriptorWriter::CalculateMatch( TemplateIterator frame_template) const { TemplateMatch result; result.template_position = frame_template; result.need_custom_fdiffs = descriptor_.frame_dependencies.frame_diffs != frame_template->frame_diffs; result.need_custom_dtis = descriptor_.frame_dependencies.decode_target_indications != frame_template->decode_target_indications; result.need_custom_chains = false; for (int i = 0; i < structure_.num_chains; ++i) { if (active_chains_[i] && descriptor_.frame_dependencies.chain_diffs[i] != frame_template->chain_diffs[i]) { result.need_custom_chains = true; break; } } result.extra_size_bits = 0; if (result.need_custom_fdiffs) { result.extra_size_bits += 2 * (1 + descriptor_.frame_dependencies.frame_diffs.size()); for (int fdiff : descriptor_.frame_dependencies.frame_diffs) { if (fdiff <= (1 << 4)) result.extra_size_bits += 4; else if (fdiff <= (1 << 8)) result.extra_size_bits += 8; else result.extra_size_bits += 12; } } if (result.need_custom_dtis) { result.extra_size_bits += 2 * descriptor_.frame_dependencies.decode_target_indications.size(); } if (result.need_custom_chains) result.extra_size_bits += 8 * structure_.num_chains; return result; } void RtpDependencyDescriptorWriter::FindBestTemplate() { const std::vector& templates = structure_.templates; // Find range of templates with matching spatial/temporal id. auto same_layer = [&](const FrameDependencyTemplate& frame_template) { return descriptor_.frame_dependencies.spatial_id == frame_template.spatial_id && descriptor_.frame_dependencies.temporal_id == frame_template.temporal_id; }; auto first = absl::c_find_if(templates, same_layer); if (first == templates.end()) { build_failed_ = true; return; } auto last = std::find_if_not(first, templates.end(), same_layer); best_template_ = CalculateMatch(first); // Search if there any better template than the first one. for (auto next = std::next(first); next != last; ++next) { TemplateMatch match = CalculateMatch(next); if (match.extra_size_bits < best_template_.extra_size_bits) best_template_ = match; } } bool RtpDependencyDescriptorWriter::ShouldWriteActiveDecodeTargetsBitmask() const { if (!descriptor_.active_decode_targets_bitmask) return false; const uint64_t all_decode_targets_bitmask = (uint64_t{1} << structure_.num_decode_targets) - 1; if (descriptor_.attached_structure && descriptor_.active_decode_targets_bitmask == all_decode_targets_bitmask) return false; return true; } bool RtpDependencyDescriptorWriter::HasExtendedFields() const { return best_template_.extra_size_bits > 0 || descriptor_.attached_structure || descriptor_.active_decode_targets_bitmask; } uint64_t RtpDependencyDescriptorWriter::TemplateId() const { return (best_template_.template_position - structure_.templates.begin() + structure_.structure_id) % DependencyDescriptor::kMaxTemplates; } void RtpDependencyDescriptorWriter::WriteBits(uint64_t val, size_t bit_count) { if (!bit_writer_.WriteBits(val, bit_count)) build_failed_ = true; } void RtpDependencyDescriptorWriter::WriteNonSymmetric(uint32_t value, uint32_t num_values) { if (!bit_writer_.WriteNonSymmetric(value, num_values)) build_failed_ = true; } void RtpDependencyDescriptorWriter::WriteTemplateDependencyStructure() { RTC_DCHECK_GE(structure_.structure_id, 0); RTC_DCHECK_LT(structure_.structure_id, DependencyDescriptor::kMaxTemplates); RTC_DCHECK_GT(structure_.num_decode_targets, 0); RTC_DCHECK_LE(structure_.num_decode_targets, DependencyDescriptor::kMaxDecodeTargets); WriteBits(structure_.structure_id, 6); WriteBits(structure_.num_decode_targets - 1, 5); WriteTemplateLayers(); WriteTemplateDtis(); WriteTemplateFdiffs(); WriteTemplateChains(); uint64_t has_resolutions = structure_.resolutions.empty() ? 0 : 1; WriteBits(has_resolutions, 1); if (has_resolutions) WriteResolutions(); } void RtpDependencyDescriptorWriter::WriteTemplateLayers() { const auto& templates = structure_.templates; RTC_DCHECK(!templates.empty()); RTC_DCHECK_LE(templates.size(), DependencyDescriptor::kMaxTemplates); RTC_DCHECK_EQ(templates[0].spatial_id, 0); RTC_DCHECK_EQ(templates[0].temporal_id, 0); for (size_t i = 1; i < templates.size(); ++i) { uint64_t next_layer_idc = static_cast(GetNextLayerIdc(templates[i - 1], templates[i])); RTC_DCHECK_LE(next_layer_idc, 3); WriteBits(next_layer_idc, 2); } WriteBits(static_cast(NextLayerIdc::kNoMoreLayers), 2); } void RtpDependencyDescriptorWriter::WriteTemplateDtis() { for (const FrameDependencyTemplate& current_template : structure_.templates) { RTC_DCHECK_EQ(current_template.decode_target_indications.size(), structure_.num_decode_targets); for (DecodeTargetIndication dti : current_template.decode_target_indications) { WriteBits(static_cast(dti), 2); } } } void RtpDependencyDescriptorWriter::WriteTemplateFdiffs() { for (const FrameDependencyTemplate& current_template : structure_.templates) { for (int fdiff : current_template.frame_diffs) { RTC_DCHECK_GE(fdiff - 1, 0); RTC_DCHECK_LT(fdiff - 1, 1 << 4); WriteBits((1u << 4) | (fdiff - 1), 1 + 4); } // No more diffs for current template. WriteBits(/*val=*/0, /*bit_count=*/1); } } void RtpDependencyDescriptorWriter::WriteTemplateChains() { RTC_DCHECK_GE(structure_.num_chains, 0); RTC_DCHECK_LE(structure_.num_chains, structure_.num_decode_targets); WriteNonSymmetric(structure_.num_chains, structure_.num_decode_targets + 1); if (structure_.num_chains == 0) return; RTC_DCHECK_EQ(structure_.decode_target_protected_by_chain.size(), structure_.num_decode_targets); for (int protected_by : structure_.decode_target_protected_by_chain) { RTC_DCHECK_GE(protected_by, 0); RTC_DCHECK_LT(protected_by, structure_.num_chains); WriteNonSymmetric(protected_by, structure_.num_chains); } for (const auto& frame_template : structure_.templates) { RTC_DCHECK_EQ(frame_template.chain_diffs.size(), structure_.num_chains); for (int chain_diff : frame_template.chain_diffs) { RTC_DCHECK_GE(chain_diff, 0); RTC_DCHECK_LT(chain_diff, 1 << 4); WriteBits(chain_diff, 4); } } } void RtpDependencyDescriptorWriter::WriteResolutions() { int max_spatial_id = structure_.templates.back().spatial_id; RTC_DCHECK_EQ(structure_.resolutions.size(), max_spatial_id + 1); for (const RenderResolution& resolution : structure_.resolutions) { RTC_DCHECK_GT(resolution.Width(), 0); RTC_DCHECK_LE(resolution.Width(), 1 << 16); RTC_DCHECK_GT(resolution.Height(), 0); RTC_DCHECK_LE(resolution.Height(), 1 << 16); WriteBits(resolution.Width() - 1, 16); WriteBits(resolution.Height() - 1, 16); } } void RtpDependencyDescriptorWriter::WriteMandatoryFields() { WriteBits(descriptor_.first_packet_in_frame, 1); WriteBits(descriptor_.last_packet_in_frame, 1); WriteBits(TemplateId(), 6); WriteBits(descriptor_.frame_number, 16); } void RtpDependencyDescriptorWriter::WriteExtendedFields() { uint64_t template_dependency_structure_present_flag = descriptor_.attached_structure ? 1u : 0u; WriteBits(template_dependency_structure_present_flag, 1); uint64_t active_decode_targets_present_flag = ShouldWriteActiveDecodeTargetsBitmask() ? 1u : 0u; WriteBits(active_decode_targets_present_flag, 1); WriteBits(best_template_.need_custom_dtis, 1); WriteBits(best_template_.need_custom_fdiffs, 1); WriteBits(best_template_.need_custom_chains, 1); if (template_dependency_structure_present_flag) WriteTemplateDependencyStructure(); if (active_decode_targets_present_flag) WriteBits(*descriptor_.active_decode_targets_bitmask, structure_.num_decode_targets); } void RtpDependencyDescriptorWriter::WriteFrameDependencyDefinition() { if (best_template_.need_custom_dtis) WriteFrameDtis(); if (best_template_.need_custom_fdiffs) WriteFrameFdiffs(); if (best_template_.need_custom_chains) WriteFrameChains(); } void RtpDependencyDescriptorWriter::WriteFrameDtis() { RTC_DCHECK_EQ(descriptor_.frame_dependencies.decode_target_indications.size(), structure_.num_decode_targets); for (DecodeTargetIndication dti : descriptor_.frame_dependencies.decode_target_indications) { WriteBits(static_cast(dti), 2); } } void RtpDependencyDescriptorWriter::WriteFrameFdiffs() { for (int fdiff : descriptor_.frame_dependencies.frame_diffs) { RTC_DCHECK_GT(fdiff, 0); RTC_DCHECK_LE(fdiff, 1 << 12); if (fdiff <= (1 << 4)) WriteBits((1u << 4) | (fdiff - 1), 2 + 4); else if (fdiff <= (1 << 8)) WriteBits((2u << 8) | (fdiff - 1), 2 + 8); else // fdiff <= (1 << 12) WriteBits((3u << 12) | (fdiff - 1), 2 + 12); } // No more diffs. WriteBits(/*val=*/0, /*bit_count=*/2); } void RtpDependencyDescriptorWriter::WriteFrameChains() { RTC_DCHECK_EQ(descriptor_.frame_dependencies.chain_diffs.size(), structure_.num_chains); for (int i = 0; i < structure_.num_chains; ++i) { int chain_diff = active_chains_[i] ? descriptor_.frame_dependencies.chain_diffs[i] : 0; RTC_DCHECK_GE(chain_diff, 0); RTC_DCHECK_LT(chain_diff, 1 << 8); WriteBits(chain_diff, 8); } } } // namespace webrtc