1 /*
2 * Copyright (c) 2019 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 "test/pc/e2e/analyzer/video/single_process_encoded_image_data_injector.h"
12
13 #include <algorithm>
14 #include <cstddef>
15
16 #include "absl/memory/memory.h"
17 #include "api/video/encoded_image.h"
18 #include "rtc_base/checks.h"
19
20 namespace webrtc {
21 namespace webrtc_pc_e2e {
22
23 SingleProcessEncodedImageDataInjector::SingleProcessEncodedImageDataInjector() =
24 default;
25 SingleProcessEncodedImageDataInjector::
26 ~SingleProcessEncodedImageDataInjector() = default;
27
InjectData(uint16_t id,bool discard,const EncodedImage & source)28 EncodedImage SingleProcessEncodedImageDataInjector::InjectData(
29 uint16_t id,
30 bool discard,
31 const EncodedImage& source) {
32 RTC_CHECK(source.size() >= ExtractionInfo::kUsedBufferSize);
33
34 ExtractionInfo info;
35 info.discard = discard;
36 size_t insertion_pos = source.size() - ExtractionInfo::kUsedBufferSize;
37 memcpy(info.origin_data, &source.data()[insertion_pos],
38 ExtractionInfo::kUsedBufferSize);
39 {
40 MutexLock lock(&lock_);
41 // Will create new one if missed.
42 ExtractionInfoVector& ev = extraction_cache_[id];
43 info.sub_id = ev.next_sub_id++;
44 ev.infos[info.sub_id] = info;
45 }
46
47 auto buffer = EncodedImageBuffer::Create(source.data(), source.size());
48 buffer->data()[insertion_pos] = id & 0x00ff;
49 buffer->data()[insertion_pos + 1] = (id & 0xff00) >> 8;
50 buffer->data()[insertion_pos + 2] = info.sub_id;
51
52 EncodedImage out = source;
53 out.SetEncodedData(buffer);
54 return out;
55 }
56
AddParticipantInCall()57 void SingleProcessEncodedImageDataInjector::AddParticipantInCall() {
58 MutexLock crit(&lock_);
59 expected_receivers_count_++;
60 }
61
RemoveParticipantInCall()62 void SingleProcessEncodedImageDataInjector::RemoveParticipantInCall() {
63 MutexLock crit(&lock_);
64 expected_receivers_count_--;
65 // Now we need go over `extraction_cache_` and removed frames which have been
66 // received by `expected_receivers_count_`.
67 for (auto& [frame_id, extraction_infos] : extraction_cache_) {
68 for (auto it = extraction_infos.infos.begin();
69 it != extraction_infos.infos.end();) {
70 // Frame is received if `received_count` equals to
71 // `expected_receivers_count_`.
72 if (it->second.received_count == expected_receivers_count_) {
73 it = extraction_infos.infos.erase(it);
74 } else {
75 ++it;
76 }
77 }
78 }
79 }
80
ExtractData(const EncodedImage & source)81 EncodedImageExtractionResult SingleProcessEncodedImageDataInjector::ExtractData(
82 const EncodedImage& source) {
83 size_t size = source.size();
84 auto buffer = EncodedImageBuffer::Create(source.data(), source.size());
85 EncodedImage out = source;
86 out.SetEncodedData(buffer);
87
88 std::vector<size_t> frame_sizes;
89 std::vector<size_t> frame_sl_index;
90 size_t max_spatial_index = out.SpatialIndex().value_or(0);
91 for (size_t i = 0; i <= max_spatial_index; ++i) {
92 auto frame_size = source.SpatialLayerFrameSize(i);
93 if (frame_size.value_or(0)) {
94 frame_sl_index.push_back(i);
95 frame_sizes.push_back(frame_size.value());
96 }
97 }
98 if (frame_sizes.empty()) {
99 frame_sizes.push_back(size);
100 }
101
102 size_t prev_frames_size = 0;
103 absl::optional<uint16_t> id = absl::nullopt;
104 bool discard = true;
105 std::vector<ExtractionInfo> extraction_infos;
106 for (size_t frame_size : frame_sizes) {
107 size_t insertion_pos =
108 prev_frames_size + frame_size - ExtractionInfo::kUsedBufferSize;
109 // Extract frame id from first 2 bytes starting from insertion pos.
110 uint16_t next_id = buffer->data()[insertion_pos] +
111 (buffer->data()[insertion_pos + 1] << 8);
112 // Extract frame sub id from second 3 byte starting from insertion pos.
113 uint8_t sub_id = buffer->data()[insertion_pos + 2];
114 RTC_CHECK(!id || *id == next_id)
115 << "Different frames encoded into single encoded image: " << *id
116 << " vs " << next_id;
117 id = next_id;
118 ExtractionInfo info;
119 {
120 MutexLock lock(&lock_);
121 auto ext_vector_it = extraction_cache_.find(next_id);
122 RTC_CHECK(ext_vector_it != extraction_cache_.end())
123 << "Unknown frame_id=" << next_id;
124
125 auto info_it = ext_vector_it->second.infos.find(sub_id);
126 RTC_CHECK(info_it != ext_vector_it->second.infos.end())
127 << "Unknown sub_id=" << sub_id << " for frame_id=" << next_id;
128 info_it->second.received_count++;
129 info = info_it->second;
130 if (info.received_count == expected_receivers_count_) {
131 ext_vector_it->second.infos.erase(info_it);
132 }
133 }
134 // We need to discard encoded image only if all concatenated encoded images
135 // have to be discarded.
136 discard = discard && info.discard;
137
138 extraction_infos.push_back(info);
139 prev_frames_size += frame_size;
140 }
141 RTC_CHECK(id);
142
143 if (discard) {
144 out.set_size(0);
145 for (size_t i = 0; i <= max_spatial_index; ++i) {
146 out.SetSpatialLayerFrameSize(i, 0);
147 }
148 return EncodedImageExtractionResult{*id, out, true};
149 }
150
151 // Make a pass from begin to end to restore origin payload and erase discarded
152 // encoded images.
153 size_t pos = 0;
154 for (size_t frame_index = 0; frame_index < frame_sizes.size();
155 ++frame_index) {
156 RTC_CHECK(pos < size);
157 const size_t frame_size = frame_sizes[frame_index];
158 const ExtractionInfo& info = extraction_infos[frame_index];
159 if (info.discard) {
160 // If this encoded image is marked to be discarded - erase it's payload
161 // from the buffer.
162 memmove(&buffer->data()[pos], &buffer->data()[pos + frame_size],
163 size - pos - frame_size);
164 RTC_CHECK_LT(frame_index, frame_sl_index.size())
165 << "codec doesn't support discard option or the image, that was "
166 "supposed to be discarded, is lost";
167 out.SetSpatialLayerFrameSize(frame_sl_index[frame_index], 0);
168 size -= frame_size;
169 } else {
170 memcpy(
171 &buffer->data()[pos + frame_size - ExtractionInfo::kUsedBufferSize],
172 info.origin_data, ExtractionInfo::kUsedBufferSize);
173 pos += frame_size;
174 }
175 }
176 out.set_size(pos);
177
178 return EncodedImageExtractionResult{*id, out, discard};
179 }
180
181 SingleProcessEncodedImageDataInjector::ExtractionInfoVector::
182 ExtractionInfoVector() = default;
183 SingleProcessEncodedImageDataInjector::ExtractionInfoVector::
184 ~ExtractionInfoVector() = default;
185
186 } // namespace webrtc_pc_e2e
187 } // namespace webrtc
188