blob: c74c8c4b63796e351b399b56cc8662137923f293 [file] [log] [blame]
philipeld20b1cf2023-03-20 12:31:131/*
2 * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "logging/rtc_event_log/dependency_descriptor_encoder_decoder.h"
12
13#include <string>
14#include <vector>
15
16#include "logging/rtc_event_log/encoder/delta_encoding.h"
17#include "logging/rtc_event_log/encoder/optional_blob_encoding.h"
18#include "logging/rtc_event_log/events/rtc_event_log_parse_status.h"
19#include "logging/rtc_event_log/rtc_event_log2_proto_include.h"
20#include "rtc_base/logging.h"
21
22namespace webrtc {
23
24// static
25absl::optional<rtclog2::DependencyDescriptorsWireInfo>
26RtcEventLogDependencyDescriptorEncoderDecoder::Encode(
27 const std::vector<rtc::ArrayView<const uint8_t>>& raw_dd_data) {
28 if (raw_dd_data.empty()) {
29 return {};
30 }
31
32 for (const auto& dd : raw_dd_data) {
33 if (!dd.empty() && dd.size() < 3) {
34 RTC_LOG(LS_WARNING) << "DependencyDescriptor size not valid.";
35 return {};
36 }
37 }
38
39 rtclog2::DependencyDescriptorsWireInfo res;
40 const rtc::ArrayView<const uint8_t>& base_dd = raw_dd_data[0];
41 auto delta_dds =
42 rtc::MakeArrayView(raw_dd_data.data(), raw_dd_data.size()).subview(1);
43
44 // Start and end bit.
45 {
46 absl::optional<uint32_t> start_end_bit;
47 if (!base_dd.empty()) {
48 start_end_bit = (base_dd[0] >> 6);
49 res.set_start_end_bit(*start_end_bit);
50 }
51 if (!delta_dds.empty()) {
52 std::vector<absl::optional<uint64_t>> values(delta_dds.size());
53 for (size_t i = 0; i < delta_dds.size(); ++i) {
54 if (!delta_dds[i].empty()) {
55 values[i] = delta_dds[i][0] >> 6;
56 }
57 }
58 std::string encoded_deltas = EncodeDeltas(start_end_bit, values);
59 if (!encoded_deltas.empty()) {
60 res.set_start_end_bit_deltas(encoded_deltas);
61 }
62 }
63 }
64
65 // Template IDs.
66 {
67 absl::optional<uint32_t> template_id;
68 if (!base_dd.empty()) {
69 template_id = (base_dd[0] & 0b0011'1111);
70 res.set_template_id(*template_id);
71 }
72
73 if (!delta_dds.empty()) {
74 std::vector<absl::optional<uint64_t>> values(delta_dds.size());
75 for (size_t i = 0; i < delta_dds.size(); ++i) {
76 if (!delta_dds[i].empty()) {
77 values[i] = delta_dds[i][0] & 0b0011'1111;
78 }
79 }
80 std::string encoded_deltas = EncodeDeltas(template_id, values);
81 if (!encoded_deltas.empty()) {
82 res.set_template_id_deltas(encoded_deltas);
83 }
84 }
85 }
86
87 // Frame IDs.
88 {
89 absl::optional<uint32_t> frame_id;
90 if (!base_dd.empty()) {
91 frame_id = (uint16_t{base_dd[1]} << 8) + base_dd[2];
92 res.set_frame_id(*frame_id);
93 }
94
95 if (!delta_dds.empty()) {
96 std::vector<absl::optional<uint64_t>> values(delta_dds.size());
97 for (size_t i = 0; i < delta_dds.size(); ++i) {
98 if (!delta_dds[i].empty()) {
99 values[i] = (uint16_t{delta_dds[i][1]} << 8) + delta_dds[i][2];
100 }
101 }
102 std::string encoded_deltas = EncodeDeltas(frame_id, values);
103 if (!encoded_deltas.empty()) {
104 res.set_frame_id_deltas(encoded_deltas);
105 }
106 }
107 }
108
109 // Extended info
110 {
111 std::vector<absl::optional<std::string>> values(raw_dd_data.size());
112 for (size_t i = 0; i < raw_dd_data.size(); ++i) {
113 if (raw_dd_data[i].size() > 3) {
114 auto extended_info = raw_dd_data[i].subview(3);
115 values[i] = {reinterpret_cast<const char*>(extended_info.data()),
116 extended_info.size()};
117 }
118 }
119
120 std::string encoded_blobs = EncodeOptionalBlobs(values);
121 if (!encoded_blobs.empty()) {
122 res.set_extended_infos(encoded_blobs);
123 }
124 }
125
126 return res;
127}
128
129// static
130RtcEventLogParseStatusOr<std::vector<std::vector<uint8_t>>>
131RtcEventLogDependencyDescriptorEncoderDecoder::Decode(
132 const rtclog2::DependencyDescriptorsWireInfo& dd_wire_info,
133 size_t num_packets) {
134 if (num_packets == 0) {
135 return {std::vector<std::vector<uint8_t>>()};
136 }
137
138 std::vector<std::vector<uint8_t>> res(num_packets);
139
140 absl::optional<uint64_t> start_end_bit_base;
141 if (dd_wire_info.has_start_end_bit()) {
142 start_end_bit_base = dd_wire_info.start_end_bit();
143 }
144 absl::optional<uint64_t> template_id_base;
145 if (dd_wire_info.has_template_id()) {
146 template_id_base = dd_wire_info.template_id();
147 }
148 absl::optional<uint64_t> frame_id_base;
149 if (dd_wire_info.has_frame_id()) {
150 frame_id_base = dd_wire_info.frame_id();
151 }
152
153 std::vector<absl::optional<uint64_t>> start_end_bit_deltas;
154 if (dd_wire_info.has_start_end_bit_deltas()) {
155 start_end_bit_deltas = DecodeDeltas(dd_wire_info.start_end_bit_deltas(),
156 start_end_bit_base, num_packets - 1);
157 RTC_DCHECK(start_end_bit_deltas.empty() ||
158 start_end_bit_deltas.size() == (num_packets - 1));
159 }
160 std::vector<absl::optional<uint64_t>> template_id_deltas;
161 if (dd_wire_info.has_template_id_deltas()) {
162 template_id_deltas = DecodeDeltas(dd_wire_info.template_id_deltas(),
163 template_id_base, num_packets - 1);
164 RTC_DCHECK(template_id_deltas.empty() ||
165 template_id_deltas.size() == (num_packets - 1));
166 }
167 std::vector<absl::optional<uint64_t>> frame_id_deltas;
168 if (dd_wire_info.has_frame_id_deltas()) {
169 frame_id_deltas = DecodeDeltas(dd_wire_info.frame_id_deltas(),
170 frame_id_base, num_packets - 1);
171 RTC_DCHECK(frame_id_deltas.empty() ||
172 frame_id_deltas.size() == (num_packets - 1));
173 }
174 std::vector<absl::optional<std::string>> extended_infos;
175 if (dd_wire_info.has_extended_infos()) {
176 extended_infos =
177 DecodeOptionalBlobs(dd_wire_info.extended_infos(), num_packets);
178 }
179
180 auto recreate_raw_dd = [&](int i, const absl::optional<uint64_t>& be,
181 const absl::optional<uint64_t>& tid,
182 const absl::optional<uint64_t>& fid) {
183 absl::string_view ext;
184 if (!extended_infos.empty() && extended_infos[i].has_value()) {
185 ext = *extended_infos[i];
186 }
187 if (be.has_value() && tid.has_value() && fid.has_value()) {
188 res[i].reserve(3 + ext.size());
189 res[i].push_back((*be << 6) | *tid);
190 res[i].push_back(*fid >> 8);
191 res[i].push_back(*fid);
192 if (!ext.empty()) {
193 res[i].insert(res[i].end(), ext.begin(), ext.end());
194 }
195 } else if (be.has_value() || tid.has_value() || fid.has_value()) {
196 RTC_PARSE_RETURN_ERROR("Not all required fields present.");
197 } else if (!ext.empty()) {
198 RTC_PARSE_RETURN_ERROR(
199 "Extended info present without required fields present.");
200 }
201
202 return RtcEventLogParseStatus::Success();
203 };
204
205 RTC_RETURN_IF_ERROR(
206 recreate_raw_dd(0, start_end_bit_base, template_id_base, frame_id_base));
207
208 for (size_t i = 1; i < num_packets; ++i) {
209 RTC_RETURN_IF_ERROR(recreate_raw_dd(
210 i,
211 start_end_bit_deltas.empty() ? start_end_bit_base
212 : start_end_bit_deltas[i - 1],
213 template_id_deltas.empty() ? template_id_base
214 : template_id_deltas[i - 1],
215 frame_id_deltas.empty() ? frame_id_base : frame_id_deltas[i - 1]));
216 }
217
218 return res;
219}
220
221} // namespace webrtc