Implement Dependency Descriptor reader
Bug: webrtc:10342 Change-Id: I671bf57368016b633546966cc994646095433519 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/152823 Reviewed-by: Philip Eliasson <philipel@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29197}
This commit is contained in:
parent
d9cc8c08dc
commit
f5dec1c6af
@ -12,6 +12,7 @@
|
||||
#define COMMON_VIDEO_GENERIC_FRAME_DESCRIPTOR_GENERIC_FRAME_INFO_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/container/inlined_vector.h"
|
||||
@ -82,6 +83,9 @@ struct FrameDependencyStructure {
|
||||
int structure_id = 0;
|
||||
int num_decode_targets = 0;
|
||||
int num_chains = 0;
|
||||
// If chains are used (num_chains > 0), maps decode target index into index of
|
||||
// the chain protecting that target or |num_chains| value if decode target is
|
||||
// not protected by a chain.
|
||||
absl::InlinedVector<int, 10> decode_target_protected_by_chain;
|
||||
absl::InlinedVector<RenderResolution, 4> resolutions;
|
||||
std::vector<FrameDependencyTemplate> templates;
|
||||
@ -90,10 +94,10 @@ struct FrameDependencyStructure {
|
||||
struct DependencyDescriptor {
|
||||
bool first_packet_in_frame = true;
|
||||
bool last_packet_in_frame = true;
|
||||
bool has_structure_attached = false;
|
||||
int frame_number = 0;
|
||||
FrameDependencyTemplate frame_dependencies;
|
||||
absl::optional<RenderResolution> resolution;
|
||||
std::unique_ptr<FrameDependencyStructure> attached_structure;
|
||||
};
|
||||
|
||||
// Describes how a certain encoder buffer was used when encoding a frame.
|
||||
|
||||
@ -86,6 +86,7 @@ rtc_source_set("rtp_rtcp_format") {
|
||||
"source/rtcp_packet/tmmbr.cc",
|
||||
"source/rtcp_packet/transport_feedback.cc",
|
||||
"source/rtp_dependency_descriptor_extension.cc",
|
||||
"source/rtp_dependency_descriptor_reader.cc",
|
||||
"source/rtp_generic_frame_descriptor.cc",
|
||||
"source/rtp_generic_frame_descriptor_extension.cc",
|
||||
"source/rtp_header_extension_map.cc",
|
||||
@ -116,6 +117,7 @@ rtc_source_set("rtp_rtcp_format") {
|
||||
"../../system_wrappers",
|
||||
"../video_coding:codec_globals_headers",
|
||||
"//third_party/abseil-cpp/absl/algorithm:container",
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
"//third_party/abseil-cpp/absl/types:variant",
|
||||
|
||||
@ -10,9 +10,24 @@
|
||||
|
||||
#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "common_video/generic_frame_descriptor/generic_frame_info.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
constexpr RTPExtensionType RtpDependencyDescriptorExtension::kId;
|
||||
constexpr char RtpDependencyDescriptorExtension::kUri[];
|
||||
|
||||
bool RtpDependencyDescriptorExtension::Parse(
|
||||
rtc::ArrayView<const uint8_t> data,
|
||||
const FrameDependencyStructure* structure,
|
||||
DependencyDescriptor* descriptor) {
|
||||
RtpDependencyDescriptorReader reader(data, structure, descriptor);
|
||||
return reader.ParseSuccessful();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
#include "api/array_view.h"
|
||||
#include "common_video/generic_frame_descriptor/generic_frame_info.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.h"
|
||||
#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_writer.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -32,10 +31,8 @@ class RtpDependencyDescriptorExtension {
|
||||
"generic-frame-descriptor-02";
|
||||
|
||||
static bool Parse(rtc::ArrayView<const uint8_t> data,
|
||||
RtpDependencyDescriptorReader* reader,
|
||||
DependencyDescriptor* descriptor) {
|
||||
return reader->Parse(data, descriptor);
|
||||
}
|
||||
const FrameDependencyStructure* structure,
|
||||
DependencyDescriptor* descriptor);
|
||||
|
||||
static size_t ValueSize(RtpDependencyDescriptorWriter* writer,
|
||||
const DependencyDescriptor& descriptor) {
|
||||
|
||||
256
modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc
Normal file
256
modules/rtp_rtcp/source/rtp_dependency_descriptor_reader.cc
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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_reader.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "rtc_base/bit_buffer.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
constexpr int kMaxTemporalId = 7;
|
||||
constexpr int kMaxSpatialId = 3;
|
||||
constexpr int kMaxTemplates = 63;
|
||||
constexpr int kMaxTemplateId = kMaxTemplates - 1;
|
||||
constexpr int kExtendedFieldsIndicator = kMaxTemplates;
|
||||
|
||||
} // namespace
|
||||
|
||||
RtpDependencyDescriptorReader::RtpDependencyDescriptorReader(
|
||||
rtc::ArrayView<const uint8_t> raw_data,
|
||||
const FrameDependencyStructure* structure,
|
||||
DependencyDescriptor* descriptor)
|
||||
: descriptor_(descriptor), buffer_(raw_data.data(), raw_data.size()) {
|
||||
RTC_DCHECK(descriptor);
|
||||
|
||||
ReadMandatoryFields();
|
||||
if (frame_dependency_template_id_ == kExtendedFieldsIndicator)
|
||||
ReadExtendedFields();
|
||||
|
||||
structure_ = descriptor->attached_structure
|
||||
? descriptor->attached_structure.get()
|
||||
: structure;
|
||||
if (structure_ == nullptr) {
|
||||
parsing_failed_ = true;
|
||||
return;
|
||||
}
|
||||
ReadFrameDependencyDefinition();
|
||||
}
|
||||
|
||||
uint32_t RtpDependencyDescriptorReader::ReadBits(size_t bit_count) {
|
||||
uint32_t value = 0;
|
||||
if (!buffer_.ReadBits(&value, bit_count))
|
||||
parsing_failed_ = true;
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t RtpDependencyDescriptorReader::ReadNonSymmetric(size_t num_values) {
|
||||
uint32_t value = 0;
|
||||
if (!buffer_.ReadNonSymmetric(&value, num_values))
|
||||
parsing_failed_ = true;
|
||||
return value;
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadTemplateDependencyStructure() {
|
||||
descriptor_->attached_structure =
|
||||
absl::make_unique<FrameDependencyStructure>();
|
||||
descriptor_->attached_structure->structure_id = ReadBits(6);
|
||||
descriptor_->attached_structure->num_decode_targets = ReadBits(5) + 1;
|
||||
|
||||
ReadTemplateLayers();
|
||||
ReadTemplateDtis();
|
||||
ReadTemplateFdiffs();
|
||||
ReadTemplateChains();
|
||||
|
||||
uint32_t has_resolutions = ReadBits(1);
|
||||
if (has_resolutions)
|
||||
ReadResolutions();
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadTemplateLayers() {
|
||||
enum NextLayerIdc : uint32_t {
|
||||
kSameLayer = 0,
|
||||
kNextTemporalLayer = 1,
|
||||
kNextSpatialLayer = 2,
|
||||
kNoMoreTemplates = 3,
|
||||
};
|
||||
std::vector<FrameDependencyTemplate> templates;
|
||||
|
||||
int temporal_id = 0;
|
||||
int spatial_id = 0;
|
||||
NextLayerIdc next_layer_idc;
|
||||
do {
|
||||
if (templates.size() == kMaxTemplates) {
|
||||
parsing_failed_ = true;
|
||||
break;
|
||||
}
|
||||
templates.emplace_back();
|
||||
FrameDependencyTemplate& last_template = templates.back();
|
||||
last_template.temporal_id = temporal_id;
|
||||
last_template.spatial_id = spatial_id;
|
||||
|
||||
next_layer_idc = static_cast<NextLayerIdc>(ReadBits(2));
|
||||
if (next_layer_idc == kNextTemporalLayer) {
|
||||
temporal_id++;
|
||||
if (temporal_id > kMaxTemporalId) {
|
||||
parsing_failed_ = true;
|
||||
break;
|
||||
}
|
||||
} else if (next_layer_idc == kNextSpatialLayer) {
|
||||
temporal_id = 0;
|
||||
spatial_id++;
|
||||
if (spatial_id > kMaxSpatialId) {
|
||||
parsing_failed_ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (next_layer_idc != kNoMoreTemplates && !parsing_failed_);
|
||||
|
||||
descriptor_->attached_structure->templates = std::move(templates);
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadTemplateDtis() {
|
||||
FrameDependencyStructure* structure = descriptor_->attached_structure.get();
|
||||
for (FrameDependencyTemplate& current_template : structure->templates) {
|
||||
current_template.decode_target_indications.resize(
|
||||
structure->num_decode_targets);
|
||||
for (int i = 0; i < structure->num_decode_targets; ++i) {
|
||||
current_template.decode_target_indications[i] =
|
||||
static_cast<DecodeTargetIndication>(ReadBits(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadTemplateFdiffs() {
|
||||
for (FrameDependencyTemplate& current_template :
|
||||
descriptor_->attached_structure->templates) {
|
||||
for (uint32_t fdiff_follows = ReadBits(1); fdiff_follows;
|
||||
fdiff_follows = ReadBits(1)) {
|
||||
uint32_t fdiff_minus_one = ReadBits(4);
|
||||
current_template.frame_diffs.push_back(fdiff_minus_one + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadTemplateChains() {
|
||||
FrameDependencyStructure* structure = descriptor_->attached_structure.get();
|
||||
structure->num_chains = ReadNonSymmetric(structure->num_decode_targets + 1);
|
||||
if (structure->num_chains == 0)
|
||||
return;
|
||||
for (int i = 0; i < structure->num_decode_targets; ++i) {
|
||||
uint32_t protected_by_chain = ReadNonSymmetric(structure->num_chains + 1);
|
||||
structure->decode_target_protected_by_chain.push_back(protected_by_chain);
|
||||
}
|
||||
for (FrameDependencyTemplate& frame_template : structure->templates) {
|
||||
for (int chain_id = 0; chain_id < structure->num_chains; ++chain_id) {
|
||||
frame_template.chain_diffs.push_back(ReadBits(4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadResolutions() {
|
||||
FrameDependencyStructure* structure = descriptor_->attached_structure.get();
|
||||
// The way templates are bitpacked, they are always ordered by spatial_id.
|
||||
int spatial_layers = structure->templates.back().spatial_id + 1;
|
||||
structure->resolutions.reserve(spatial_layers);
|
||||
for (int sid = 0; sid < spatial_layers; ++sid) {
|
||||
uint16_t width_minus_1 = ReadBits(16);
|
||||
uint16_t height_minus_1 = ReadBits(16);
|
||||
structure->resolutions.emplace_back(width_minus_1 + 1, height_minus_1 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadMandatoryFields() {
|
||||
descriptor_->first_packet_in_frame = ReadBits(1);
|
||||
descriptor_->last_packet_in_frame = ReadBits(1);
|
||||
frame_dependency_template_id_ = ReadBits(6);
|
||||
descriptor_->frame_number = ReadBits(16);
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadExtendedFields() {
|
||||
frame_dependency_template_id_ = ReadBits(6);
|
||||
if (frame_dependency_template_id_ == kExtendedFieldsIndicator) {
|
||||
parsing_failed_ = true;
|
||||
return;
|
||||
}
|
||||
bool template_dependency_structure_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);
|
||||
}
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadFrameDependencyDefinition() {
|
||||
size_t template_index = (frame_dependency_template_id_ +
|
||||
(kMaxTemplateId + 1) - structure_->structure_id) %
|
||||
(kMaxTemplateId + 1);
|
||||
|
||||
if (template_index >= structure_->templates.size()) {
|
||||
parsing_failed_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy all the fields from the matching template
|
||||
descriptor_->frame_dependencies = structure_->templates[template_index];
|
||||
|
||||
if (custom_dtis_flag_)
|
||||
ReadFrameDtis();
|
||||
if (custom_fdiffs_flag_)
|
||||
ReadFrameFdiffs();
|
||||
if (custom_chains_flag_)
|
||||
ReadFrameChains();
|
||||
|
||||
if (structure_->resolutions.empty()) {
|
||||
descriptor_->resolution = absl::nullopt;
|
||||
} else {
|
||||
// Format guarantees that if there were resolutions in the last structure,
|
||||
// then each spatial layer got one.
|
||||
RTC_DCHECK_LE(descriptor_->frame_dependencies.spatial_id,
|
||||
structure_->resolutions.size());
|
||||
descriptor_->resolution =
|
||||
structure_->resolutions[descriptor_->frame_dependencies.spatial_id];
|
||||
}
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadFrameDtis() {
|
||||
RTC_DCHECK_EQ(
|
||||
descriptor_->frame_dependencies.decode_target_indications.size(),
|
||||
structure_->num_decode_targets);
|
||||
for (auto& dti : descriptor_->frame_dependencies.decode_target_indications) {
|
||||
dti = static_cast<DecodeTargetIndication>(ReadBits(2));
|
||||
}
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadFrameFdiffs() {
|
||||
descriptor_->frame_dependencies.frame_diffs.clear();
|
||||
for (uint32_t next_fdiff_size = ReadBits(2); next_fdiff_size > 0;
|
||||
next_fdiff_size = ReadBits(2)) {
|
||||
uint32_t fdiff_minus_one = ReadBits(4 * next_fdiff_size);
|
||||
descriptor_->frame_dependencies.frame_diffs.push_back(fdiff_minus_one + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void RtpDependencyDescriptorReader::ReadFrameChains() {
|
||||
RTC_DCHECK_EQ(descriptor_->frame_dependencies.chain_diffs.size(),
|
||||
structure_->num_chains);
|
||||
for (auto& chain_diff : descriptor_->frame_dependencies.chain_diffs) {
|
||||
chain_diff = ReadBits(8);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -11,29 +11,62 @@
|
||||
#define MODULES_RTP_RTCP_SOURCE_RTP_DEPENDENCY_DESCRIPTOR_READER_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "common_video/generic_frame_descriptor/generic_frame_info.h"
|
||||
#include "rtc_base/bit_buffer.h"
|
||||
|
||||
namespace webrtc {
|
||||
// Keeps and updates state required to deserialize DependencyDescriptor
|
||||
// rtp header extension.
|
||||
// Deserializes DependencyDescriptor rtp header extension.
|
||||
class RtpDependencyDescriptorReader {
|
||||
public:
|
||||
// Parses the dependency descriptor. Returns false on failure.
|
||||
// Updates frame dependency structures if parsed descriptor has a new one.
|
||||
// Doesn't update own state when Parse fails.
|
||||
bool Parse(rtc::ArrayView<const uint8_t> raw_data,
|
||||
DependencyDescriptor* descriptor) {
|
||||
// TODO(bugs.webrtc.org/10342): Implement.
|
||||
return false;
|
||||
}
|
||||
// Parses the dependency descriptor.
|
||||
RtpDependencyDescriptorReader(rtc::ArrayView<const uint8_t> raw_data,
|
||||
const FrameDependencyStructure* structure,
|
||||
DependencyDescriptor* descriptor);
|
||||
RtpDependencyDescriptorReader(const RtpDependencyDescriptorReader&) = delete;
|
||||
RtpDependencyDescriptorReader& operator=(
|
||||
const RtpDependencyDescriptorReader&) = delete;
|
||||
|
||||
// Returns latest valid parsed structure or nullptr if none was parsed so far.
|
||||
const FrameDependencyStructure* GetStructure() const {
|
||||
// TODO(bugs.webrtc.org/10342): Implement.
|
||||
return nullptr;
|
||||
}
|
||||
// Returns true if parse was successful.
|
||||
bool ParseSuccessful() { return !parsing_failed_; }
|
||||
|
||||
private:
|
||||
// Reads bits from |buffer_|. If it fails, returns 0 and marks parsing as
|
||||
// failed, but doesn't stop the parsing.
|
||||
uint32_t ReadBits(size_t bit_count);
|
||||
uint32_t ReadNonSymmetric(size_t num_values);
|
||||
|
||||
// Functions to read template dependency structure.
|
||||
void ReadTemplateDependencyStructure();
|
||||
void ReadTemplateLayers();
|
||||
void ReadTemplateDtis();
|
||||
void ReadTemplateFdiffs();
|
||||
void ReadTemplateChains();
|
||||
void ReadResolutions();
|
||||
|
||||
// Function to read details for the current frame.
|
||||
void ReadMandatoryFields();
|
||||
void ReadExtendedFields();
|
||||
void ReadFrameDependencyDefinition();
|
||||
|
||||
void ReadFrameDtis();
|
||||
void ReadFrameFdiffs();
|
||||
void ReadFrameChains();
|
||||
|
||||
// Output.
|
||||
bool parsing_failed_ = false;
|
||||
DependencyDescriptor* const descriptor_;
|
||||
// Values that are needed while reading the descriptor, but can be discarded
|
||||
// when reading is complete.
|
||||
rtc::BitBuffer buffer_;
|
||||
int frame_dependency_template_id_ = 0;
|
||||
bool custom_dtis_flag_ = false;
|
||||
bool custom_fdiffs_flag_ = false;
|
||||
bool custom_chains_flag_ = false;
|
||||
const FrameDependencyStructure* structure_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user