| /* |
| * Copyright (c) 2023 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 "logging/rtc_event_log/dependency_descriptor_encoder_decoder.h" |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <optional> |
| #include <string> |
| #include <vector> |
| |
| #include "absl/strings/string_view.h" |
| #include "api/array_view.h" |
| #include "logging/rtc_event_log/encoder/delta_encoding.h" |
| #include "logging/rtc_event_log/encoder/optional_blob_encoding.h" |
| #include "logging/rtc_event_log/events/rtc_event_log_parse_status.h" |
| #include "logging/rtc_event_log/rtc_event_log2_proto_include.h" |
| #include "rtc_base/checks.h" |
| #include "rtc_base/logging.h" |
| |
| namespace webrtc { |
| |
| // static |
| std::optional<rtclog2::DependencyDescriptorsWireInfo> |
| RtcEventLogDependencyDescriptorEncoderDecoder::Encode( |
| const std::vector<rtc::ArrayView<const uint8_t>>& raw_dd_data) { |
| if (raw_dd_data.empty()) { |
| return {}; |
| } |
| |
| for (const auto& dd : raw_dd_data) { |
| if (!dd.empty() && dd.size() < 3) { |
| RTC_LOG(LS_WARNING) << "DependencyDescriptor size not valid."; |
| return {}; |
| } |
| } |
| |
| rtclog2::DependencyDescriptorsWireInfo res; |
| const rtc::ArrayView<const uint8_t>& base_dd = raw_dd_data[0]; |
| auto delta_dds = |
| rtc::MakeArrayView(raw_dd_data.data(), raw_dd_data.size()).subview(1); |
| |
| // Start and end bit. |
| { |
| std::optional<uint32_t> start_end_bit; |
| if (!base_dd.empty()) { |
| start_end_bit = (base_dd[0] >> 6); |
| res.set_start_end_bit(*start_end_bit); |
| } |
| if (!delta_dds.empty()) { |
| std::vector<std::optional<uint64_t>> values(delta_dds.size()); |
| for (size_t i = 0; i < delta_dds.size(); ++i) { |
| if (!delta_dds[i].empty()) { |
| values[i] = delta_dds[i][0] >> 6; |
| } |
| } |
| std::string encoded_deltas = EncodeDeltas(start_end_bit, values); |
| if (!encoded_deltas.empty()) { |
| res.set_start_end_bit_deltas(encoded_deltas); |
| } |
| } |
| } |
| |
| // Template IDs. |
| { |
| std::optional<uint32_t> template_id; |
| if (!base_dd.empty()) { |
| template_id = (base_dd[0] & 0b0011'1111); |
| res.set_template_id(*template_id); |
| } |
| |
| if (!delta_dds.empty()) { |
| std::vector<std::optional<uint64_t>> values(delta_dds.size()); |
| for (size_t i = 0; i < delta_dds.size(); ++i) { |
| if (!delta_dds[i].empty()) { |
| values[i] = delta_dds[i][0] & 0b0011'1111; |
| } |
| } |
| std::string encoded_deltas = EncodeDeltas(template_id, values); |
| if (!encoded_deltas.empty()) { |
| res.set_template_id_deltas(encoded_deltas); |
| } |
| } |
| } |
| |
| // Frame IDs. |
| { |
| std::optional<uint32_t> frame_id; |
| if (!base_dd.empty()) { |
| frame_id = (uint16_t{base_dd[1]} << 8) + base_dd[2]; |
| res.set_frame_id(*frame_id); |
| } |
| |
| if (!delta_dds.empty()) { |
| std::vector<std::optional<uint64_t>> values(delta_dds.size()); |
| for (size_t i = 0; i < delta_dds.size(); ++i) { |
| if (!delta_dds[i].empty()) { |
| values[i] = (uint16_t{delta_dds[i][1]} << 8) + delta_dds[i][2]; |
| } |
| } |
| std::string encoded_deltas = EncodeDeltas(frame_id, values); |
| if (!encoded_deltas.empty()) { |
| res.set_frame_id_deltas(encoded_deltas); |
| } |
| } |
| } |
| |
| // Extended info |
| { |
| std::vector<std::optional<std::string>> values(raw_dd_data.size()); |
| for (size_t i = 0; i < raw_dd_data.size(); ++i) { |
| if (raw_dd_data[i].size() > 3) { |
| auto extended_info = raw_dd_data[i].subview(3); |
| values[i] = {reinterpret_cast<const char*>(extended_info.data()), |
| extended_info.size()}; |
| } |
| } |
| |
| std::string encoded_blobs = EncodeOptionalBlobs(values); |
| if (!encoded_blobs.empty()) { |
| res.set_extended_infos(encoded_blobs); |
| } |
| } |
| |
| return res; |
| } |
| |
| // static |
| RtcEventLogParseStatusOr<std::vector<std::vector<uint8_t>>> |
| RtcEventLogDependencyDescriptorEncoderDecoder::Decode( |
| const rtclog2::DependencyDescriptorsWireInfo& dd_wire_info, |
| size_t num_packets) { |
| if (num_packets == 0) { |
| return {std::vector<std::vector<uint8_t>>()}; |
| } |
| |
| std::vector<std::vector<uint8_t>> res(num_packets); |
| |
| std::optional<uint64_t> start_end_bit_base; |
| if (dd_wire_info.has_start_end_bit()) { |
| start_end_bit_base = dd_wire_info.start_end_bit(); |
| } |
| std::optional<uint64_t> template_id_base; |
| if (dd_wire_info.has_template_id()) { |
| template_id_base = dd_wire_info.template_id(); |
| } |
| std::optional<uint64_t> frame_id_base; |
| if (dd_wire_info.has_frame_id()) { |
| frame_id_base = dd_wire_info.frame_id(); |
| } |
| |
| std::vector<std::optional<uint64_t>> start_end_bit_deltas; |
| if (dd_wire_info.has_start_end_bit_deltas()) { |
| start_end_bit_deltas = DecodeDeltas(dd_wire_info.start_end_bit_deltas(), |
| start_end_bit_base, num_packets - 1); |
| RTC_DCHECK(start_end_bit_deltas.empty() || |
| start_end_bit_deltas.size() == (num_packets - 1)); |
| } |
| std::vector<std::optional<uint64_t>> template_id_deltas; |
| if (dd_wire_info.has_template_id_deltas()) { |
| template_id_deltas = DecodeDeltas(dd_wire_info.template_id_deltas(), |
| template_id_base, num_packets - 1); |
| RTC_DCHECK(template_id_deltas.empty() || |
| template_id_deltas.size() == (num_packets - 1)); |
| } |
| std::vector<std::optional<uint64_t>> frame_id_deltas; |
| if (dd_wire_info.has_frame_id_deltas()) { |
| frame_id_deltas = DecodeDeltas(dd_wire_info.frame_id_deltas(), |
| frame_id_base, num_packets - 1); |
| RTC_DCHECK(frame_id_deltas.empty() || |
| frame_id_deltas.size() == (num_packets - 1)); |
| } |
| std::vector<std::optional<std::string>> extended_infos; |
| if (dd_wire_info.has_extended_infos()) { |
| extended_infos = |
| DecodeOptionalBlobs(dd_wire_info.extended_infos(), num_packets); |
| } |
| |
| auto recreate_raw_dd = [&](int i, const std::optional<uint64_t>& be, |
| const std::optional<uint64_t>& tid, |
| const std::optional<uint64_t>& fid) { |
| absl::string_view ext; |
| if (!extended_infos.empty() && extended_infos[i].has_value()) { |
| ext = *extended_infos[i]; |
| } |
| if (be.has_value() && tid.has_value() && fid.has_value()) { |
| res[i].reserve(3 + ext.size()); |
| res[i].push_back((*be << 6) | *tid); |
| res[i].push_back(*fid >> 8); |
| res[i].push_back(*fid); |
| if (!ext.empty()) { |
| res[i].insert(res[i].end(), ext.begin(), ext.end()); |
| } |
| } else if (be.has_value() || tid.has_value() || fid.has_value()) { |
| RTC_PARSE_RETURN_ERROR("Not all required fields present."); |
| } else if (!ext.empty()) { |
| RTC_PARSE_RETURN_ERROR( |
| "Extended info present without required fields present."); |
| } |
| |
| return RtcEventLogParseStatus::Success(); |
| }; |
| |
| RTC_RETURN_IF_ERROR( |
| recreate_raw_dd(0, start_end_bit_base, template_id_base, frame_id_base)); |
| |
| for (size_t i = 1; i < num_packets; ++i) { |
| RTC_RETURN_IF_ERROR(recreate_raw_dd( |
| i, |
| start_end_bit_deltas.empty() ? start_end_bit_base |
| : start_end_bit_deltas[i - 1], |
| template_id_deltas.empty() ? template_id_base |
| : template_id_deltas[i - 1], |
| frame_id_deltas.empty() ? frame_id_base : frame_id_deltas[i - 1])); |
| } |
| |
| return res; |
| } |
| |
| } // namespace webrtc |