Chromium Code Reviews| 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 |