OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/cast/logging/encoding_event_subscriber.h" | 5 #include "media/cast/logging/encoding_event_subscriber.h" |
6 | 6 |
7 #include <cstring> | 7 #include <cstring> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "media/cast/logging/proto/proto_utils.h" | 11 #include "media/cast/logging/proto/proto_utils.h" |
12 | 12 |
13 using google::protobuf::RepeatedPtrField; | 13 using google::protobuf::RepeatedPtrField; |
14 using media::cast::proto::AggregatedFrameEvent; | 14 using media::cast::proto::AggregatedFrameEvent; |
15 using media::cast::proto::AggregatedPacketEvent; | 15 using media::cast::proto::AggregatedPacketEvent; |
16 using media::cast::proto::BasePacketEvent; | 16 using media::cast::proto::BasePacketEvent; |
17 using media::cast::proto::LogMetadata; | 17 using media::cast::proto::LogMetadata; |
18 | 18 |
19 namespace { | |
20 | |
21 // A size limit on maps to keep lookups fast. | |
22 const size_t kMaxMapSize = 200; | |
23 | |
24 // The smallest (oredered by RTP timestamp) |kNumMapEntriesToTransfer| entries | |
25 // will be moved when the map size reaches |kMaxMapSize|. | |
26 // Must be smaller than |kMaxMapSize|. | |
27 const size_t kNumMapEntriesToTransfer = 100; | |
28 | |
29 template <typename ProtoPtr> | |
30 bool IsRtpTimestampLessThan(const ProtoPtr& lhs, const ProtoPtr& rhs) { | |
31 return lhs->relative_rtp_timestamp() < rhs->relative_rtp_timestamp(); | |
32 } | |
33 | |
34 } | |
35 | |
19 namespace media { | 36 namespace media { |
20 namespace cast { | 37 namespace cast { |
21 | 38 |
22 EncodingEventSubscriber::EncodingEventSubscriber( | 39 EncodingEventSubscriber::EncodingEventSubscriber( |
23 EventMediaType event_media_type, | 40 EventMediaType event_media_type, |
24 size_t max_frames) | 41 size_t max_frames) |
25 : event_media_type_(event_media_type), | 42 : event_media_type_(event_media_type), |
26 max_frames_(max_frames), | 43 max_frames_(max_frames), |
44 frame_event_storage_index_(0), | |
45 packet_event_storage_index_(0), | |
27 seen_first_rtp_timestamp_(false), | 46 seen_first_rtp_timestamp_(false), |
28 first_rtp_timestamp_(0u) {} | 47 first_rtp_timestamp_(0u) {} |
29 | 48 |
30 EncodingEventSubscriber::~EncodingEventSubscriber() { | 49 EncodingEventSubscriber::~EncodingEventSubscriber() { |
31 DCHECK(thread_checker_.CalledOnValidThread()); | 50 DCHECK(thread_checker_.CalledOnValidThread()); |
32 } | 51 } |
33 | 52 |
34 void EncodingEventSubscriber::OnReceiveFrameEvent( | 53 void EncodingEventSubscriber::OnReceiveFrameEvent( |
35 const FrameEvent& frame_event) { | 54 const FrameEvent& frame_event) { |
36 DCHECK(thread_checker_.CalledOnValidThread()); | 55 DCHECK(thread_checker_.CalledOnValidThread()); |
37 | 56 |
38 if (ShouldProcessEvent(frame_event.type)) { | 57 if (!ShouldProcessEvent(frame_event.type)) |
39 RtpTimestamp relative_rtp_timestamp = | 58 return; |
40 GetRelativeRtpTimestamp(frame_event.rtp_timestamp); | |
41 FrameEventMap::iterator it = frame_event_map_.find(relative_rtp_timestamp); | |
42 linked_ptr<AggregatedFrameEvent> event_proto; | |
43 | 59 |
44 // Look up existing entry. If not found, create a new entry and add to map. | 60 RtpTimestamp relative_rtp_timestamp = |
45 if (it == frame_event_map_.end()) { | 61 GetRelativeRtpTimestamp(frame_event.rtp_timestamp); |
62 FrameEventMap::iterator it = frame_event_map_.find(relative_rtp_timestamp); | |
63 linked_ptr<AggregatedFrameEvent> event_proto; | |
64 | |
65 // Look up existing entry. If not found, create a new entry and add to map. | |
66 if (it == frame_event_map_.end()) { | |
67 event_proto.reset(new AggregatedFrameEvent); | |
68 event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); | |
69 frame_event_map_.insert( | |
70 std::make_pair(relative_rtp_timestamp, event_proto)); | |
71 } else { | |
72 event_proto = it->second; | |
73 if (event_proto->event_type_size() >= kMaxEventsPerProto) { | |
74 DVLOG(2) << "Too many events in frame " << frame_event.rtp_timestamp | |
75 << ". Using new frame event proto."; | |
76 AddFrameEventToStorage(event_proto); | |
46 event_proto.reset(new AggregatedFrameEvent); | 77 event_proto.reset(new AggregatedFrameEvent); |
47 event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); | 78 event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); |
48 frame_event_map_.insert( | 79 it->second = event_proto; |
49 std::make_pair(relative_rtp_timestamp, event_proto)); | |
50 } else { | |
51 event_proto = it->second; | |
52 } | 80 } |
53 | |
54 event_proto->add_event_type(ToProtoEventType(frame_event.type)); | |
55 event_proto->add_event_timestamp_ms( | |
56 (frame_event.timestamp - base::TimeTicks()).InMilliseconds()); | |
57 | |
58 if (frame_event.type == kAudioFrameEncoded) { | |
59 event_proto->set_encoded_frame_size(frame_event.size); | |
60 } else if (frame_event.type == kVideoFrameEncoded) { | |
61 event_proto->set_encoded_frame_size(frame_event.size); | |
62 event_proto->set_key_frame(frame_event.key_frame); | |
63 } else if (frame_event.type == kAudioPlayoutDelay || | |
64 frame_event.type == kVideoRenderDelay) { | |
65 event_proto->set_delay_millis(frame_event.delay_delta.InMilliseconds()); | |
66 } | |
67 | |
68 TruncateFrameEventMapIfNeeded(); | |
69 } | 81 } |
70 | 82 |
71 DCHECK(frame_event_map_.size() <= max_frames_); | 83 event_proto->add_event_type(ToProtoEventType(frame_event.type)); |
84 event_proto->add_event_timestamp_ms( | |
85 (frame_event.timestamp - base::TimeTicks()).InMilliseconds()); | |
86 | |
87 if (frame_event.type == kAudioFrameEncoded) { | |
88 event_proto->set_encoded_frame_size(frame_event.size); | |
89 } else if (frame_event.type == kVideoFrameEncoded) { | |
90 event_proto->set_encoded_frame_size(frame_event.size); | |
91 event_proto->set_key_frame(frame_event.key_frame); | |
92 } else if (frame_event.type == kAudioPlayoutDelay || | |
93 frame_event.type == kVideoRenderDelay) { | |
94 event_proto->set_delay_millis(frame_event.delay_delta.InMilliseconds()); | |
95 } | |
96 | |
97 if (frame_event_map_.size() > kMaxMapSize) | |
98 TransferFrameEvents(kNumMapEntriesToTransfer); | |
99 | |
100 DCHECK(frame_event_map_.size() <= kMaxMapSize); | |
101 DCHECK(frame_event_storage_.size() <= max_frames_); | |
72 } | 102 } |
73 | 103 |
74 void EncodingEventSubscriber::OnReceivePacketEvent( | 104 void EncodingEventSubscriber::OnReceivePacketEvent( |
75 const PacketEvent& packet_event) { | 105 const PacketEvent& packet_event) { |
76 DCHECK(thread_checker_.CalledOnValidThread()); | 106 DCHECK(thread_checker_.CalledOnValidThread()); |
77 | 107 |
78 if (ShouldProcessEvent(packet_event.type)) { | 108 if (!ShouldProcessEvent(packet_event.type)) |
79 RtpTimestamp relative_rtp_timestamp = | 109 return; |
80 GetRelativeRtpTimestamp(packet_event.rtp_timestamp); | 110 RtpTimestamp relative_rtp_timestamp = |
81 PacketEventMap::iterator it = | 111 GetRelativeRtpTimestamp(packet_event.rtp_timestamp); |
82 packet_event_map_.find(relative_rtp_timestamp); | 112 PacketEventMap::iterator it = |
83 linked_ptr<AggregatedPacketEvent> event_proto; | 113 packet_event_map_.find(relative_rtp_timestamp); |
84 BasePacketEvent* base_packet_event_proto = NULL; | 114 linked_ptr<AggregatedPacketEvent> event_proto; |
115 BasePacketEvent* base_packet_event_proto = NULL; | |
85 | 116 |
86 // Look up existing entry. If not found, create a new entry and add to map. | 117 // Look up existing entry. If not found, create a new entry and add to map. |
87 if (it == packet_event_map_.end()) { | 118 if (it == packet_event_map_.end()) { |
119 event_proto.reset(new AggregatedPacketEvent); | |
120 event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); | |
121 packet_event_map_.insert( | |
122 std::make_pair(relative_rtp_timestamp, event_proto)); | |
123 base_packet_event_proto = event_proto->add_base_packet_event(); | |
124 base_packet_event_proto->set_packet_id(packet_event.packet_id); | |
125 } else { | |
126 // Found existing entry, now look up existing BasePacketEvent using packet | |
127 // ID. If not found, create a new entry and add to proto. | |
128 event_proto = it->second; | |
129 RepeatedPtrField<BasePacketEvent>* field = | |
130 event_proto->mutable_base_packet_event(); | |
131 for (RepeatedPtrField<BasePacketEvent>::pointer_iterator base_it = | |
132 field->pointer_begin(); | |
133 base_it != field->pointer_end(); | |
134 ++base_it) { | |
135 if ((*base_it)->packet_id() == packet_event.packet_id) { | |
136 base_packet_event_proto = *base_it; | |
137 break; | |
138 } | |
139 } | |
140 if (!base_packet_event_proto) { | |
141 if (event_proto->base_packet_event_size() >= kMaxPacketsPerFrame) { | |
142 DVLOG(3) << "Too many packets in AggregatedPacketEvent " | |
143 << packet_event.rtp_timestamp << ". " | |
144 << "Using new packet event proto."; | |
145 AddPacketEventToStorage(event_proto); | |
146 event_proto.reset(new AggregatedPacketEvent); | |
147 event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); | |
148 it->second = event_proto; | |
149 } | |
150 | |
151 base_packet_event_proto = event_proto->add_base_packet_event(); | |
152 base_packet_event_proto->set_packet_id(packet_event.packet_id); | |
153 } else if (base_packet_event_proto->event_type_size() >= | |
154 kMaxEventsPerProto) { | |
155 DVLOG(3) << "Too many events in packet " | |
156 << packet_event.rtp_timestamp << ", " | |
157 << packet_event.packet_id << ". Using new packet event proto."; | |
158 AddPacketEventToStorage(event_proto); | |
88 event_proto.reset(new AggregatedPacketEvent); | 159 event_proto.reset(new AggregatedPacketEvent); |
89 event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); | 160 event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); |
90 packet_event_map_.insert( | 161 it->second = event_proto; |
91 std::make_pair(relative_rtp_timestamp, event_proto)); | |
92 base_packet_event_proto = event_proto->add_base_packet_event(); | 162 base_packet_event_proto = event_proto->add_base_packet_event(); |
93 base_packet_event_proto->set_packet_id(packet_event.packet_id); | 163 base_packet_event_proto->set_packet_id(packet_event.packet_id); |
94 } else { | |
95 // Found existing entry, now look up existing BasePacketEvent using packet | |
96 // ID. If not found, create a new entry and add to proto. | |
97 event_proto = it->second; | |
98 RepeatedPtrField<BasePacketEvent>* field = | |
99 event_proto->mutable_base_packet_event(); | |
100 for (RepeatedPtrField<BasePacketEvent>::pointer_iterator it = | |
101 field->pointer_begin(); | |
102 it != field->pointer_end(); | |
103 ++it) { | |
104 if ((*it)->packet_id() == packet_event.packet_id) { | |
105 base_packet_event_proto = *it; | |
106 break; | |
107 } | |
108 } | |
109 if (!base_packet_event_proto) { | |
110 base_packet_event_proto = event_proto->add_base_packet_event(); | |
111 base_packet_event_proto->set_packet_id(packet_event.packet_id); | |
112 } | |
113 } | 164 } |
114 | |
115 base_packet_event_proto->add_event_type( | |
116 ToProtoEventType(packet_event.type)); | |
117 base_packet_event_proto->add_event_timestamp_ms( | |
118 (packet_event.timestamp - base::TimeTicks()).InMilliseconds()); | |
119 | |
120 TruncatePacketEventMapIfNeeded(); | |
121 } | 165 } |
122 | 166 |
123 DCHECK(packet_event_map_.size() <= max_frames_); | 167 base_packet_event_proto->add_event_type( |
168 ToProtoEventType(packet_event.type)); | |
169 base_packet_event_proto->add_event_timestamp_ms( | |
170 (packet_event.timestamp - base::TimeTicks()).InMilliseconds()); | |
171 | |
172 if (packet_event_map_.size() > kMaxMapSize) | |
173 TransferPacketEvents(kNumMapEntriesToTransfer); | |
174 | |
175 DCHECK(packet_event_map_.size() <= kMaxMapSize); | |
176 DCHECK(packet_event_storage_.size() <= max_frames_); | |
124 } | 177 } |
125 | 178 |
126 void EncodingEventSubscriber::OnReceiveGenericEvent( | 179 void EncodingEventSubscriber::OnReceiveGenericEvent( |
127 const GenericEvent& generic_event) { | 180 const GenericEvent& generic_event) { |
128 DCHECK(thread_checker_.CalledOnValidThread()); | 181 DCHECK(thread_checker_.CalledOnValidThread()); |
129 // Do nothing, there are no generic events we are interested in. | 182 // Do nothing, there are no generic events we are interested in. |
130 } | 183 } |
131 | 184 |
132 void EncodingEventSubscriber::GetEventsAndReset(LogMetadata* metadata, | 185 void EncodingEventSubscriber::GetEventsAndReset( |
133 FrameEventMap* frame_events, | 186 LogMetadata* metadata, FrameEventList* frame_events, |
134 PacketEventMap* packet_events) { | 187 PacketEventList* packet_events) { |
135 DCHECK(thread_checker_.CalledOnValidThread()); | 188 DCHECK(thread_checker_.CalledOnValidThread()); |
136 | 189 |
190 // Flush all events. | |
191 TransferFrameEvents(frame_event_map_.size()); | |
192 TransferPacketEvents(packet_event_map_.size()); | |
193 std::sort(frame_event_storage_.begin(), frame_event_storage_.end(), | |
194 &IsRtpTimestampLessThan<linked_ptr<AggregatedFrameEvent> >); | |
195 std::sort(packet_event_storage_.begin(), packet_event_storage_.end(), | |
196 &IsRtpTimestampLessThan<linked_ptr<AggregatedPacketEvent> >); | |
197 | |
137 metadata->set_is_audio(event_media_type_ == AUDIO_EVENT); | 198 metadata->set_is_audio(event_media_type_ == AUDIO_EVENT); |
138 metadata->set_first_rtp_timestamp(first_rtp_timestamp_); | 199 metadata->set_first_rtp_timestamp(first_rtp_timestamp_); |
139 metadata->set_num_frame_events(frame_event_map_.size()); | 200 metadata->set_num_frame_events(frame_event_storage_.size()); |
140 metadata->set_num_packet_events(packet_event_map_.size()); | 201 metadata->set_num_packet_events(packet_event_storage_.size()); |
141 metadata->set_reference_timestamp_ms_at_unix_epoch( | 202 metadata->set_reference_timestamp_ms_at_unix_epoch( |
142 (base::TimeTicks::UnixEpoch() - base::TimeTicks()).InMilliseconds()); | 203 (base::TimeTicks::UnixEpoch() - base::TimeTicks()).InMilliseconds()); |
143 frame_events->swap(frame_event_map_); | 204 frame_events->swap(frame_event_storage_); |
144 packet_events->swap(packet_event_map_); | 205 packet_events->swap(packet_event_storage_); |
145 Reset(); | 206 Reset(); |
146 } | 207 } |
147 | 208 |
148 bool EncodingEventSubscriber::ShouldProcessEvent(CastLoggingEvent event) { | 209 bool EncodingEventSubscriber::ShouldProcessEvent(CastLoggingEvent event) { |
149 return GetEventMediaType(event) == event_media_type_; | 210 return GetEventMediaType(event) == event_media_type_; |
150 } | 211 } |
151 | 212 |
152 void EncodingEventSubscriber::TruncateFrameEventMapIfNeeded() { | 213 void EncodingEventSubscriber::TransferFrameEvents(size_t num_entries) { |
153 // This works because this is called everytime an event is inserted and | 214 DCHECK(frame_event_map_.size() >= num_entries); |
154 // we only insert events one at a time. | 215 |
155 if (frame_event_map_.size() > max_frames_) | 216 FrameEventMap::iterator it = frame_event_map_.begin(); |
156 frame_event_map_.erase(frame_event_map_.begin()); | 217 for (size_t i = 0; i < num_entries; i++, ++it) |
218 AddFrameEventToStorage(it->second); | |
219 | |
220 frame_event_map_.erase(frame_event_map_.begin(), it); | |
157 } | 221 } |
158 | 222 |
159 void EncodingEventSubscriber::TruncatePacketEventMapIfNeeded() { | 223 void EncodingEventSubscriber::TransferPacketEvents(size_t num_entries) { |
160 // This works because this is called everytime an event is inserted and | 224 DCHECK(packet_event_map_.size() >= num_entries); |
161 // we only insert events one at a time. | 225 |
162 if (packet_event_map_.size() > max_frames_) | 226 PacketEventMap::iterator it = packet_event_map_.begin(); |
163 packet_event_map_.erase(packet_event_map_.begin()); | 227 for (size_t i = 0; i < num_entries; i++, ++it) |
Alpha Left Google
2014/04/22 18:20:42
Try to erase the entry while iterating. That way y
imcheng
2014/04/22 19:29:33
Per offline discussion, changed the semantics of f
| |
228 AddPacketEventToStorage(it->second); | |
229 | |
230 packet_event_map_.erase(packet_event_map_.begin(), it); | |
231 } | |
232 | |
233 void EncodingEventSubscriber::AddFrameEventToStorage( | |
234 const linked_ptr<AggregatedFrameEvent>& frame_event_proto) { | |
235 if (frame_event_storage_.size() >= max_frames_) { | |
236 frame_event_storage_[frame_event_storage_index_] = frame_event_proto; | |
237 } else { | |
238 frame_event_storage_.push_back(frame_event_proto); | |
239 } | |
240 | |
241 frame_event_storage_index_ = (frame_event_storage_index_ + 1) % max_frames_; | |
242 } | |
243 | |
244 void EncodingEventSubscriber::AddPacketEventToStorage( | |
245 const linked_ptr<AggregatedPacketEvent>& packet_event_proto) { | |
246 if (packet_event_storage_.size() >= max_frames_) | |
247 packet_event_storage_[packet_event_storage_index_] = packet_event_proto; | |
248 else | |
249 packet_event_storage_.push_back(packet_event_proto); | |
250 | |
251 packet_event_storage_index_ = (packet_event_storage_index_ + 1) % max_frames_; | |
164 } | 252 } |
165 | 253 |
166 RtpTimestamp EncodingEventSubscriber::GetRelativeRtpTimestamp( | 254 RtpTimestamp EncodingEventSubscriber::GetRelativeRtpTimestamp( |
167 RtpTimestamp rtp_timestamp) { | 255 RtpTimestamp rtp_timestamp) { |
168 if (!seen_first_rtp_timestamp_) { | 256 if (!seen_first_rtp_timestamp_) { |
169 seen_first_rtp_timestamp_ = true; | 257 seen_first_rtp_timestamp_ = true; |
170 first_rtp_timestamp_ = rtp_timestamp; | 258 first_rtp_timestamp_ = rtp_timestamp; |
171 } | 259 } |
172 | 260 |
173 return rtp_timestamp - first_rtp_timestamp_; | 261 return rtp_timestamp - first_rtp_timestamp_; |
174 } | 262 } |
175 | 263 |
176 void EncodingEventSubscriber::Reset() { | 264 void EncodingEventSubscriber::Reset() { |
177 frame_event_map_.clear(); | 265 frame_event_map_.clear(); |
266 frame_event_storage_.clear(); | |
267 frame_event_storage_index_ = 0; | |
178 packet_event_map_.clear(); | 268 packet_event_map_.clear(); |
269 packet_event_storage_.clear(); | |
270 packet_event_storage_index_ = 0; | |
179 seen_first_rtp_timestamp_ = false; | 271 seen_first_rtp_timestamp_ = false; |
180 first_rtp_timestamp_ = 0u; | 272 first_rtp_timestamp_ = 0u; |
181 } | 273 } |
182 | 274 |
183 } // namespace cast | 275 } // namespace cast |
184 } // namespace media | 276 } // namespace media |
OLD | NEW |