1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/cast/logging/encoding_event_subscriber.h"
11 #include "base/logging.h"
12 #include "base/numerics/safe_conversions.h"
13 #include "media/cast/logging/proto/proto_utils.h"
15 using google::protobuf::RepeatedPtrField
;
16 using media::cast::proto::AggregatedFrameEvent
;
17 using media::cast::proto::AggregatedPacketEvent
;
18 using media::cast::proto::BasePacketEvent
;
19 using media::cast::proto::LogMetadata
;
23 // A size limit on maps to keep lookups fast.
24 const size_t kMaxMapSize
= 200;
26 // The smallest (oredered by RTP timestamp) |kNumMapEntriesToTransfer| entries
27 // will be moved when the map size reaches |kMaxMapSize|.
28 // Must be smaller than |kMaxMapSize|.
29 const size_t kNumMapEntriesToTransfer
= 100;
31 template <typename ProtoPtr
>
32 bool IsRtpTimestampLessThan(const ProtoPtr
& lhs
, const ProtoPtr
& rhs
) {
33 return lhs
->relative_rtp_timestamp() < rhs
->relative_rtp_timestamp();
36 BasePacketEvent
* GetNewBasePacketEvent(AggregatedPacketEvent
* event_proto
,
37 int packet_id
, int size
) {
38 BasePacketEvent
* base
= event_proto
->add_base_packet_event();
39 base
->set_packet_id(packet_id
);
49 EncodingEventSubscriber::EncodingEventSubscriber(
50 EventMediaType event_media_type
,
52 : event_media_type_(event_media_type
),
53 max_frames_(max_frames
),
54 frame_event_storage_index_(0),
55 packet_event_storage_index_(0),
56 seen_first_rtp_timestamp_(false),
57 first_rtp_timestamp_(0u) {}
59 EncodingEventSubscriber::~EncodingEventSubscriber() {
60 DCHECK(thread_checker_
.CalledOnValidThread());
63 void EncodingEventSubscriber::OnReceiveFrameEvent(
64 const FrameEvent
& frame_event
) {
65 DCHECK(thread_checker_
.CalledOnValidThread());
67 if (event_media_type_
!= frame_event
.media_type
)
70 RtpTimestamp relative_rtp_timestamp
=
71 GetRelativeRtpTimestamp(frame_event
.rtp_timestamp
);
72 FrameEventMap::iterator it
= frame_event_map_
.find(relative_rtp_timestamp
);
73 linked_ptr
<AggregatedFrameEvent
> event_proto
;
75 // Look up existing entry. If not found, create a new entry and add to map.
76 if (it
== frame_event_map_
.end()) {
77 event_proto
.reset(new AggregatedFrameEvent
);
78 event_proto
->set_relative_rtp_timestamp(relative_rtp_timestamp
);
79 frame_event_map_
.insert(
80 std::make_pair(relative_rtp_timestamp
, event_proto
));
82 event_proto
= it
->second
;
83 if (event_proto
->event_type_size() >= kMaxEventsPerProto
) {
84 DVLOG(2) << "Too many events in frame " << frame_event
.rtp_timestamp
85 << ". Using new frame event proto.";
86 AddFrameEventToStorage(event_proto
);
87 event_proto
.reset(new AggregatedFrameEvent
);
88 event_proto
->set_relative_rtp_timestamp(relative_rtp_timestamp
);
89 it
->second
= event_proto
;
93 event_proto
->add_event_type(ToProtoEventType(frame_event
.type
));
94 event_proto
->add_event_timestamp_ms(
95 (frame_event
.timestamp
- base::TimeTicks()).InMilliseconds());
97 if (frame_event
.type
== FRAME_CAPTURE_END
) {
98 if (frame_event
.media_type
== VIDEO_EVENT
&&
99 frame_event
.width
> 0 && frame_event
.height
> 0) {
100 event_proto
->set_width(frame_event
.width
);
101 event_proto
->set_height(frame_event
.height
);
103 } else if (frame_event
.type
== FRAME_ENCODED
) {
104 event_proto
->set_encoded_frame_size(frame_event
.size
);
105 if (frame_event
.encoder_cpu_utilization
>= 0.0) {
106 event_proto
->set_encoder_cpu_percent_utilized(base::saturated_cast
<int32
>(
107 frame_event
.encoder_cpu_utilization
* 100.0 + 0.5));
109 if (frame_event
.idealized_bitrate_utilization
>= 0.0) {
110 event_proto
->set_idealized_bitrate_percent_utilized(
111 base::saturated_cast
<int32
>(
112 frame_event
.idealized_bitrate_utilization
* 100.0 + 0.5));
114 if (frame_event
.media_type
== VIDEO_EVENT
) {
115 event_proto
->set_key_frame(frame_event
.key_frame
);
116 event_proto
->set_target_bitrate(frame_event
.target_bitrate
);
118 } else if (frame_event
.type
== FRAME_PLAYOUT
) {
119 event_proto
->set_delay_millis(frame_event
.delay_delta
.InMilliseconds());
122 if (frame_event_map_
.size() > kMaxMapSize
)
123 TransferFrameEvents(kNumMapEntriesToTransfer
);
125 DCHECK(frame_event_map_
.size() <= kMaxMapSize
);
126 DCHECK(frame_event_storage_
.size() <= max_frames_
);
129 void EncodingEventSubscriber::OnReceivePacketEvent(
130 const PacketEvent
& packet_event
) {
131 DCHECK(thread_checker_
.CalledOnValidThread());
133 if (event_media_type_
!= packet_event
.media_type
)
136 RtpTimestamp relative_rtp_timestamp
=
137 GetRelativeRtpTimestamp(packet_event
.rtp_timestamp
);
138 PacketEventMap::iterator it
=
139 packet_event_map_
.find(relative_rtp_timestamp
);
140 linked_ptr
<AggregatedPacketEvent
> event_proto
;
141 BasePacketEvent
* base_packet_event_proto
= NULL
;
143 // Look up existing entry. If not found, create a new entry and add to map.
144 if (it
== packet_event_map_
.end()) {
145 event_proto
.reset(new AggregatedPacketEvent
);
146 event_proto
->set_relative_rtp_timestamp(relative_rtp_timestamp
);
147 packet_event_map_
.insert(
148 std::make_pair(relative_rtp_timestamp
, event_proto
));
149 base_packet_event_proto
= GetNewBasePacketEvent(
150 event_proto
.get(), packet_event
.packet_id
, packet_event
.size
);
152 // Found existing entry, now look up existing BasePacketEvent using packet
153 // ID. If not found, create a new entry and add to proto.
154 event_proto
= it
->second
;
155 RepeatedPtrField
<BasePacketEvent
>* field
=
156 event_proto
->mutable_base_packet_event();
157 for (RepeatedPtrField
<BasePacketEvent
>::pointer_iterator base_it
=
158 field
->pointer_begin();
159 base_it
!= field
->pointer_end();
161 if ((*base_it
)->packet_id() == packet_event
.packet_id
) {
162 base_packet_event_proto
= *base_it
;
166 if (!base_packet_event_proto
) {
167 if (event_proto
->base_packet_event_size() >= kMaxPacketsPerFrame
) {
168 DVLOG(3) << "Too many packets in AggregatedPacketEvent "
169 << packet_event
.rtp_timestamp
<< ". "
170 << "Using new packet event proto.";
171 AddPacketEventToStorage(event_proto
);
172 event_proto
.reset(new AggregatedPacketEvent
);
173 event_proto
->set_relative_rtp_timestamp(relative_rtp_timestamp
);
174 it
->second
= event_proto
;
177 base_packet_event_proto
= GetNewBasePacketEvent(
178 event_proto
.get(), packet_event
.packet_id
, packet_event
.size
);
179 } else if (base_packet_event_proto
->event_type_size() >=
180 kMaxEventsPerProto
) {
181 DVLOG(3) << "Too many events in packet "
182 << packet_event
.rtp_timestamp
<< ", "
183 << packet_event
.packet_id
<< ". Using new packet event proto.";
184 AddPacketEventToStorage(event_proto
);
185 event_proto
.reset(new AggregatedPacketEvent
);
186 event_proto
->set_relative_rtp_timestamp(relative_rtp_timestamp
);
187 it
->second
= event_proto
;
188 base_packet_event_proto
= GetNewBasePacketEvent(
189 event_proto
.get(), packet_event
.packet_id
, packet_event
.size
);
193 base_packet_event_proto
->add_event_type(
194 ToProtoEventType(packet_event
.type
));
195 base_packet_event_proto
->add_event_timestamp_ms(
196 (packet_event
.timestamp
- base::TimeTicks()).InMilliseconds());
198 // |base_packet_event_proto| could have been created with a receiver event
199 // which does not have the packet size and we would need to overwrite it when
200 // we see a sender event, which does have the packet size.
201 if (packet_event
.size
> 0) {
202 base_packet_event_proto
->set_size(packet_event
.size
);
205 if (packet_event_map_
.size() > kMaxMapSize
)
206 TransferPacketEvents(kNumMapEntriesToTransfer
);
208 DCHECK(packet_event_map_
.size() <= kMaxMapSize
);
209 DCHECK(packet_event_storage_
.size() <= max_frames_
);
212 void EncodingEventSubscriber::GetEventsAndReset(LogMetadata
* metadata
,
213 FrameEventList
* frame_events
, PacketEventList
* packet_events
) {
214 DCHECK(thread_checker_
.CalledOnValidThread());
217 TransferFrameEvents(frame_event_map_
.size());
218 TransferPacketEvents(packet_event_map_
.size());
219 std::sort(frame_event_storage_
.begin(), frame_event_storage_
.end(),
220 &IsRtpTimestampLessThan
<linked_ptr
<AggregatedFrameEvent
> >);
221 std::sort(packet_event_storage_
.begin(), packet_event_storage_
.end(),
222 &IsRtpTimestampLessThan
<linked_ptr
<AggregatedPacketEvent
> >);
224 metadata
->set_is_audio(event_media_type_
== AUDIO_EVENT
);
225 metadata
->set_first_rtp_timestamp(first_rtp_timestamp_
);
226 metadata
->set_num_frame_events(frame_event_storage_
.size());
227 metadata
->set_num_packet_events(packet_event_storage_
.size());
228 metadata
->set_reference_timestamp_ms_at_unix_epoch(
229 (base::TimeTicks::UnixEpoch() - base::TimeTicks()).InMilliseconds());
230 frame_events
->swap(frame_event_storage_
);
231 packet_events
->swap(packet_event_storage_
);
235 void EncodingEventSubscriber::TransferFrameEvents(size_t max_num_entries
) {
236 DCHECK(frame_event_map_
.size() >= max_num_entries
);
238 FrameEventMap::iterator it
= frame_event_map_
.begin();
240 i
< max_num_entries
&& it
!= frame_event_map_
.end();
242 AddFrameEventToStorage(it
->second
);
245 frame_event_map_
.erase(frame_event_map_
.begin(), it
);
248 void EncodingEventSubscriber::TransferPacketEvents(size_t max_num_entries
) {
249 PacketEventMap::iterator it
= packet_event_map_
.begin();
251 i
< max_num_entries
&& it
!= packet_event_map_
.end();
253 AddPacketEventToStorage(it
->second
);
256 packet_event_map_
.erase(packet_event_map_
.begin(), it
);
259 void EncodingEventSubscriber::AddFrameEventToStorage(
260 const linked_ptr
<AggregatedFrameEvent
>& frame_event_proto
) {
261 if (frame_event_storage_
.size() >= max_frames_
) {
262 frame_event_storage_
[frame_event_storage_index_
] = frame_event_proto
;
264 frame_event_storage_
.push_back(frame_event_proto
);
267 frame_event_storage_index_
= (frame_event_storage_index_
+ 1) % max_frames_
;
270 void EncodingEventSubscriber::AddPacketEventToStorage(
271 const linked_ptr
<AggregatedPacketEvent
>& packet_event_proto
) {
272 if (packet_event_storage_
.size() >= max_frames_
)
273 packet_event_storage_
[packet_event_storage_index_
] = packet_event_proto
;
275 packet_event_storage_
.push_back(packet_event_proto
);
277 packet_event_storage_index_
= (packet_event_storage_index_
+ 1) % max_frames_
;
280 RtpTimestamp
EncodingEventSubscriber::GetRelativeRtpTimestamp(
281 RtpTimestamp rtp_timestamp
) {
282 if (!seen_first_rtp_timestamp_
) {
283 seen_first_rtp_timestamp_
= true;
284 first_rtp_timestamp_
= rtp_timestamp
;
287 return rtp_timestamp
- first_rtp_timestamp_
;
290 void EncodingEventSubscriber::Reset() {
291 frame_event_map_
.clear();
292 frame_event_storage_
.clear();
293 frame_event_storage_index_
= 0;
294 packet_event_map_
.clear();
295 packet_event_storage_
.clear();
296 packet_event_storage_index_
= 0;
297 seen_first_rtp_timestamp_
= false;
298 first_rtp_timestamp_
= 0u;