diff --git a/common_video/generic_frame_descriptor/generic_frame_info.h b/common_video/generic_frame_descriptor/generic_frame_info.h index 3916530c73..2aff0e3fd5 100644 --- a/common_video/generic_frame_descriptor/generic_frame_info.h +++ b/common_video/generic_frame_descriptor/generic_frame_info.h @@ -97,6 +97,7 @@ struct DependencyDescriptor { int frame_number = 0; FrameDependencyTemplate frame_dependencies; absl::optional resolution; + absl::optional active_decode_targets_bitmask; std::unique_ptr attached_structure; }; diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc index 517057822c..5103d7f6c1 100644 --- a/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc +++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc @@ -41,10 +41,15 @@ RtpDependencyDescriptorReader::RtpDependencyDescriptorReader( structure_ = descriptor->attached_structure ? descriptor->attached_structure.get() : structure; - if (structure_ == nullptr) { + if (structure_ == nullptr || parsing_failed_) { parsing_failed_ = true; return; } + if (active_decode_targets_present_flag_) { + descriptor->active_decode_targets_bitmask = + ReadBits(structure_->num_decode_targets); + } + ReadFrameDependencyDefinition(); } @@ -190,12 +195,16 @@ void RtpDependencyDescriptorReader::ReadExtendedFields() { return; } bool template_dependency_structure_present_flag = ReadBits(1); + active_decode_targets_present_flag_ = ReadBits(1); custom_dtis_flag_ = ReadBits(1); custom_fdiffs_flag_ = ReadBits(1); custom_chains_flag_ = ReadBits(1); if (template_dependency_structure_present_flag) { ReadTemplateDependencyStructure(); RTC_DCHECK(descriptor_->attached_structure); + descriptor_->active_decode_targets_bitmask = + (uint64_t{1} << descriptor_->attached_structure->num_decode_targets) - + 1; } } diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h index e16fba8b3d..11df2f49a0 100644 --- a/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h +++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h @@ -63,6 +63,7 @@ class RtpDependencyDescriptorReader { // when reading is complete. rtc::BitBuffer buffer_; int frame_dependency_template_id_ = 0; + bool active_decode_targets_present_flag_ = false; bool custom_dtis_flag_ = false; bool custom_fdiffs_flag_ = false; bool custom_chains_flag_ = false; diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.cc b/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.cc index ea10e375f2..1190acf012 100644 --- a/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.cc +++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.cc @@ -80,8 +80,13 @@ bool RtpDependencyDescriptorWriter::Write() { int RtpDependencyDescriptorWriter::ValueSizeBits() const { static constexpr int kMandatoryFields = 1 + 1 + 6 + 16; int value_size_bits = kMandatoryFields + best_template_.extra_size_bits; - if (descriptor_.attached_structure) - value_size_bits += 10 + StructureSizeBits(); + if (HasExtendedFields()) { + value_size_bits += 11; + if (descriptor_.attached_structure) + value_size_bits += StructureSizeBits(); + if (ShouldWriteActiveDecodeTargetsBitmask()) + value_size_bits += structure_.num_decode_targets; + } return value_size_bits; } @@ -124,15 +129,7 @@ RtpDependencyDescriptorWriter::CalculateMatch( result.need_custom_chains = descriptor_.frame_dependencies.chain_diffs != frame_template->chain_diffs; - if (!result.need_custom_fdiffs && !result.need_custom_dtis && - !result.need_custom_chains) { - // Perfect match. - result.extra_size_bits = 0; - return result; - } - // If structure should be attached, then there will be ExtendedFields anyway, - // so do not count 10 bits for them as extra. - result.extra_size_bits = descriptor_.attached_structure ? 0 : 10; + result.extra_size_bits = 0; if (result.need_custom_fdiffs) { result.extra_size_bits += 2 * (1 + descriptor_.frame_dependencies.frame_diffs.size()); @@ -176,8 +173,21 @@ void RtpDependencyDescriptorWriter::FindBestTemplate() { } } +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; + return best_template_.extra_size_bits > 0 || descriptor_.attached_structure || + descriptor_.active_decode_targets_bitmask; } uint64_t RtpDependencyDescriptorWriter::TemplateId() const { @@ -306,11 +316,17 @@ 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 (descriptor_.attached_structure) + 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() { diff --git a/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.h b/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.h index 750c7ed18c..5274f2da95 100644 --- a/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.h +++ b/modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.h @@ -50,6 +50,7 @@ class RtpDependencyDescriptorWriter { int StructureSizeBits() const; TemplateMatch CalculateMatch(TemplateIterator frame_template) const; void FindBestTemplate(); + bool ShouldWriteActiveDecodeTargetsBitmask() const; bool HasExtendedFields() const; uint64_t TemplateId() const; diff --git a/test/fuzzers/rtp_dependency_descriptor_fuzzer.cc b/test/fuzzers/rtp_dependency_descriptor_fuzzer.cc index fbe7ac32e0..0736bba27c 100644 --- a/test/fuzzers/rtp_dependency_descriptor_fuzzer.cc +++ b/test/fuzzers/rtp_dependency_descriptor_fuzzer.cc @@ -21,19 +21,6 @@ #include "test/fuzzers/fuzz_data_helper.h" namespace webrtc { -namespace { - -bool AreSame(const DependencyDescriptor& lhs, const DependencyDescriptor& rhs) { - return lhs.first_packet_in_frame == rhs.first_packet_in_frame && - lhs.last_packet_in_frame == rhs.last_packet_in_frame && - (lhs.attached_structure != nullptr) == - (rhs.attached_structure != nullptr) && - lhs.frame_number == rhs.frame_number && - lhs.resolution == rhs.resolution && - lhs.frame_dependencies == rhs.frame_dependencies; -} - -} // namespace void FuzzOneInput(const uint8_t* data, size_t size) { FrameDependencyStructure structure1; @@ -80,7 +67,23 @@ void FuzzOneInput(const uint8_t* data, size_t size) { DependencyDescriptor descriptor2; RTC_CHECK(RtpDependencyDescriptorExtension::Parse( write_buffer, structure2.get(), &descriptor2)); - RTC_CHECK(AreSame(descriptor1, descriptor2)); + // Check descriptor1 and descriptor2 have same values. + RTC_CHECK_EQ(descriptor1.first_packet_in_frame, + descriptor2.first_packet_in_frame); + RTC_CHECK_EQ(descriptor1.last_packet_in_frame, + descriptor2.last_packet_in_frame); + RTC_CHECK_EQ(descriptor1.attached_structure != nullptr, + descriptor2.attached_structure != nullptr); + // Using value_or would miss invalid corner case when one value is nullopt + // while another one is 0, but for other errors would produce much nicer + // error message than using RTC_CHECK(optional1 == optional2); + // If logger would support pretty printing optional values, value_or can be + // removed. + RTC_CHECK_EQ(descriptor1.active_decode_targets_bitmask.value_or(0), + descriptor2.active_decode_targets_bitmask.value_or(0)); + RTC_CHECK_EQ(descriptor1.frame_number, descriptor2.frame_number); + RTC_CHECK(descriptor1.resolution == descriptor2.resolution); + RTC_CHECK(descriptor1.frame_dependencies == descriptor2.frame_dependencies); if (descriptor2.attached_structure) { structure2 = std::move(descriptor2.attached_structure);