Chromium Code Reviews| Index: media/cast/logging/encoding_event_subscriber.cc |
| diff --git a/media/cast/logging/encoding_event_subscriber.cc b/media/cast/logging/encoding_event_subscriber.cc |
| index 10ced1a5cceee7e98f1ee853023291e1bc0c172c..8f360a6b8bf3b9bbaf2747f7189edd5dddc57958 100644 |
| --- a/media/cast/logging/encoding_event_subscriber.cc |
| +++ b/media/cast/logging/encoding_event_subscriber.cc |
| @@ -16,6 +16,23 @@ using media::cast::proto::AggregatedPacketEvent; |
| using media::cast::proto::BasePacketEvent; |
| using media::cast::proto::LogMetadata; |
| +namespace { |
| + |
| +// A size limit on maps to keep lookups fast. |
| +const size_t kMaxMapSize = 200; |
| + |
| +// The smallest (oredered by RTP timestamp) |kNumMapEntriesToTransfer| entries |
| +// will be moved when the map size reaches |kMaxMapSize|. |
| +// Must be smaller than |kMaxMapSize|. |
| +const size_t kNumMapEntriesToTransfer = 100; |
| + |
| +template <typename ProtoPtr> |
| +bool IsRtpTimestampLessThan(const ProtoPtr& lhs, const ProtoPtr& rhs) { |
| + return lhs->relative_rtp_timestamp() < rhs->relative_rtp_timestamp(); |
| +} |
| + |
| +} |
| + |
| namespace media { |
| namespace cast { |
| @@ -24,6 +41,8 @@ EncodingEventSubscriber::EncodingEventSubscriber( |
| size_t max_frames) |
| : event_media_type_(event_media_type), |
| max_frames_(max_frames), |
| + frame_event_storage_index_(0), |
| + packet_event_storage_index_(0), |
| seen_first_rtp_timestamp_(false), |
| first_rtp_timestamp_(0u) {} |
| @@ -35,92 +54,126 @@ void EncodingEventSubscriber::OnReceiveFrameEvent( |
| const FrameEvent& frame_event) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - if (ShouldProcessEvent(frame_event.type)) { |
| - RtpTimestamp relative_rtp_timestamp = |
| - GetRelativeRtpTimestamp(frame_event.rtp_timestamp); |
| - FrameEventMap::iterator it = frame_event_map_.find(relative_rtp_timestamp); |
| - linked_ptr<AggregatedFrameEvent> event_proto; |
| + if (!ShouldProcessEvent(frame_event.type)) |
| + return; |
| - // Look up existing entry. If not found, create a new entry and add to map. |
| - if (it == frame_event_map_.end()) { |
| + RtpTimestamp relative_rtp_timestamp = |
| + GetRelativeRtpTimestamp(frame_event.rtp_timestamp); |
| + FrameEventMap::iterator it = frame_event_map_.find(relative_rtp_timestamp); |
| + linked_ptr<AggregatedFrameEvent> event_proto; |
| + |
| + // Look up existing entry. If not found, create a new entry and add to map. |
| + if (it == frame_event_map_.end()) { |
| + event_proto.reset(new AggregatedFrameEvent); |
| + event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); |
| + frame_event_map_.insert( |
| + std::make_pair(relative_rtp_timestamp, event_proto)); |
| + } else { |
| + event_proto = it->second; |
| + if (event_proto->event_type_size() >= kMaxEventsPerProto) { |
| + DVLOG(2) << "Too many events in frame " << frame_event.rtp_timestamp |
| + << ". Using new frame event proto."; |
| + AddFrameEventToStorage(event_proto); |
| event_proto.reset(new AggregatedFrameEvent); |
| event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); |
| - frame_event_map_.insert( |
| - std::make_pair(relative_rtp_timestamp, event_proto)); |
| - } else { |
| - event_proto = it->second; |
| + it->second = event_proto; |
| } |
| + } |
| - event_proto->add_event_type(ToProtoEventType(frame_event.type)); |
| - event_proto->add_event_timestamp_ms( |
| - (frame_event.timestamp - base::TimeTicks()).InMilliseconds()); |
| - |
| - if (frame_event.type == kAudioFrameEncoded) { |
| - event_proto->set_encoded_frame_size(frame_event.size); |
| - } else if (frame_event.type == kVideoFrameEncoded) { |
| - event_proto->set_encoded_frame_size(frame_event.size); |
| - event_proto->set_key_frame(frame_event.key_frame); |
| - } else if (frame_event.type == kAudioPlayoutDelay || |
| - frame_event.type == kVideoRenderDelay) { |
| - event_proto->set_delay_millis(frame_event.delay_delta.InMilliseconds()); |
| - } |
| + event_proto->add_event_type(ToProtoEventType(frame_event.type)); |
| + event_proto->add_event_timestamp_ms( |
| + (frame_event.timestamp - base::TimeTicks()).InMilliseconds()); |
| - TruncateFrameEventMapIfNeeded(); |
| + if (frame_event.type == kAudioFrameEncoded) { |
| + event_proto->set_encoded_frame_size(frame_event.size); |
| + } else if (frame_event.type == kVideoFrameEncoded) { |
| + event_proto->set_encoded_frame_size(frame_event.size); |
| + event_proto->set_key_frame(frame_event.key_frame); |
| + } else if (frame_event.type == kAudioPlayoutDelay || |
| + frame_event.type == kVideoRenderDelay) { |
| + event_proto->set_delay_millis(frame_event.delay_delta.InMilliseconds()); |
| } |
| - DCHECK(frame_event_map_.size() <= max_frames_); |
| + if (frame_event_map_.size() > kMaxMapSize) |
| + TransferFrameEvents(kNumMapEntriesToTransfer); |
| + |
| + DCHECK(frame_event_map_.size() <= kMaxMapSize); |
| + DCHECK(frame_event_storage_.size() <= max_frames_); |
| } |
| void EncodingEventSubscriber::OnReceivePacketEvent( |
| const PacketEvent& packet_event) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - if (ShouldProcessEvent(packet_event.type)) { |
| - RtpTimestamp relative_rtp_timestamp = |
| - GetRelativeRtpTimestamp(packet_event.rtp_timestamp); |
| - PacketEventMap::iterator it = |
| - packet_event_map_.find(relative_rtp_timestamp); |
| - linked_ptr<AggregatedPacketEvent> event_proto; |
| - BasePacketEvent* base_packet_event_proto = NULL; |
| + if (!ShouldProcessEvent(packet_event.type)) |
| + return; |
| + RtpTimestamp relative_rtp_timestamp = |
| + GetRelativeRtpTimestamp(packet_event.rtp_timestamp); |
| + PacketEventMap::iterator it = |
| + packet_event_map_.find(relative_rtp_timestamp); |
| + linked_ptr<AggregatedPacketEvent> event_proto; |
| + BasePacketEvent* base_packet_event_proto = NULL; |
| + |
| + // Look up existing entry. If not found, create a new entry and add to map. |
| + if (it == packet_event_map_.end()) { |
| + event_proto.reset(new AggregatedPacketEvent); |
| + event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); |
| + packet_event_map_.insert( |
| + std::make_pair(relative_rtp_timestamp, event_proto)); |
| + base_packet_event_proto = event_proto->add_base_packet_event(); |
| + base_packet_event_proto->set_packet_id(packet_event.packet_id); |
| + } else { |
| + // Found existing entry, now look up existing BasePacketEvent using packet |
| + // ID. If not found, create a new entry and add to proto. |
| + event_proto = it->second; |
| + RepeatedPtrField<BasePacketEvent>* field = |
| + event_proto->mutable_base_packet_event(); |
| + for (RepeatedPtrField<BasePacketEvent>::pointer_iterator base_it = |
| + field->pointer_begin(); |
| + base_it != field->pointer_end(); |
| + ++base_it) { |
| + if ((*base_it)->packet_id() == packet_event.packet_id) { |
| + base_packet_event_proto = *base_it; |
| + break; |
| + } |
| + } |
| + if (!base_packet_event_proto) { |
| + if (event_proto->base_packet_event_size() >= kMaxPacketsPerFrame) { |
| + DVLOG(3) << "Too many packets in AggregatedPacketEvent " |
| + << packet_event.rtp_timestamp << ". " |
| + << "Using new packet event proto."; |
| + AddPacketEventToStorage(event_proto); |
| + event_proto.reset(new AggregatedPacketEvent); |
| + event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); |
| + it->second = event_proto; |
| + } |
| - // Look up existing entry. If not found, create a new entry and add to map. |
| - if (it == packet_event_map_.end()) { |
| + base_packet_event_proto = event_proto->add_base_packet_event(); |
| + base_packet_event_proto->set_packet_id(packet_event.packet_id); |
| + } else if (base_packet_event_proto->event_type_size() >= |
| + kMaxEventsPerProto) { |
| + DVLOG(3) << "Too many events in packet " |
| + << packet_event.rtp_timestamp << ", " |
| + << packet_event.packet_id << ". Using new packet event proto."; |
| + AddPacketEventToStorage(event_proto); |
| event_proto.reset(new AggregatedPacketEvent); |
| event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp); |
| - packet_event_map_.insert( |
| - std::make_pair(relative_rtp_timestamp, event_proto)); |
| + it->second = event_proto; |
| base_packet_event_proto = event_proto->add_base_packet_event(); |
| base_packet_event_proto->set_packet_id(packet_event.packet_id); |
| - } else { |
| - // Found existing entry, now look up existing BasePacketEvent using packet |
| - // ID. If not found, create a new entry and add to proto. |
| - event_proto = it->second; |
| - RepeatedPtrField<BasePacketEvent>* field = |
| - event_proto->mutable_base_packet_event(); |
| - for (RepeatedPtrField<BasePacketEvent>::pointer_iterator it = |
| - field->pointer_begin(); |
| - it != field->pointer_end(); |
| - ++it) { |
| - if ((*it)->packet_id() == packet_event.packet_id) { |
| - base_packet_event_proto = *it; |
| - break; |
| - } |
| - } |
| - if (!base_packet_event_proto) { |
| - base_packet_event_proto = event_proto->add_base_packet_event(); |
| - base_packet_event_proto->set_packet_id(packet_event.packet_id); |
| - } |
| } |
| + } |
| - base_packet_event_proto->add_event_type( |
| - ToProtoEventType(packet_event.type)); |
| - base_packet_event_proto->add_event_timestamp_ms( |
| - (packet_event.timestamp - base::TimeTicks()).InMilliseconds()); |
| + base_packet_event_proto->add_event_type( |
| + ToProtoEventType(packet_event.type)); |
| + base_packet_event_proto->add_event_timestamp_ms( |
| + (packet_event.timestamp - base::TimeTicks()).InMilliseconds()); |
| - TruncatePacketEventMapIfNeeded(); |
| - } |
| + if (packet_event_map_.size() > kMaxMapSize) |
| + TransferPacketEvents(kNumMapEntriesToTransfer); |
| - DCHECK(packet_event_map_.size() <= max_frames_); |
| + DCHECK(packet_event_map_.size() <= kMaxMapSize); |
| + DCHECK(packet_event_storage_.size() <= max_frames_); |
| } |
| void EncodingEventSubscriber::OnReceiveGenericEvent( |
| @@ -129,19 +182,27 @@ void EncodingEventSubscriber::OnReceiveGenericEvent( |
| // Do nothing, there are no generic events we are interested in. |
| } |
| -void EncodingEventSubscriber::GetEventsAndReset(LogMetadata* metadata, |
| - FrameEventMap* frame_events, |
| - PacketEventMap* packet_events) { |
| +void EncodingEventSubscriber::GetEventsAndReset( |
| + LogMetadata* metadata, FrameEventList* frame_events, |
| + PacketEventList* packet_events) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| + // Flush all events. |
| + TransferFrameEvents(frame_event_map_.size()); |
| + TransferPacketEvents(packet_event_map_.size()); |
| + std::sort(frame_event_storage_.begin(), frame_event_storage_.end(), |
| + &IsRtpTimestampLessThan<linked_ptr<AggregatedFrameEvent> >); |
| + std::sort(packet_event_storage_.begin(), packet_event_storage_.end(), |
| + &IsRtpTimestampLessThan<linked_ptr<AggregatedPacketEvent> >); |
| + |
| metadata->set_is_audio(event_media_type_ == AUDIO_EVENT); |
| metadata->set_first_rtp_timestamp(first_rtp_timestamp_); |
| - metadata->set_num_frame_events(frame_event_map_.size()); |
| - metadata->set_num_packet_events(packet_event_map_.size()); |
| + metadata->set_num_frame_events(frame_event_storage_.size()); |
| + metadata->set_num_packet_events(packet_event_storage_.size()); |
| metadata->set_reference_timestamp_ms_at_unix_epoch( |
| (base::TimeTicks::UnixEpoch() - base::TimeTicks()).InMilliseconds()); |
| - frame_events->swap(frame_event_map_); |
| - packet_events->swap(packet_event_map_); |
| + frame_events->swap(frame_event_storage_); |
| + packet_events->swap(packet_event_storage_); |
| Reset(); |
| } |
| @@ -149,18 +210,45 @@ bool EncodingEventSubscriber::ShouldProcessEvent(CastLoggingEvent event) { |
| return GetEventMediaType(event) == event_media_type_; |
| } |
| -void EncodingEventSubscriber::TruncateFrameEventMapIfNeeded() { |
| - // This works because this is called everytime an event is inserted and |
| - // we only insert events one at a time. |
| - if (frame_event_map_.size() > max_frames_) |
| - frame_event_map_.erase(frame_event_map_.begin()); |
| +void EncodingEventSubscriber::TransferFrameEvents(size_t num_entries) { |
| + DCHECK(frame_event_map_.size() >= num_entries); |
| + |
| + FrameEventMap::iterator it = frame_event_map_.begin(); |
| + for (size_t i = 0; i < num_entries; i++, ++it) |
| + AddFrameEventToStorage(it->second); |
| + |
| + frame_event_map_.erase(frame_event_map_.begin(), it); |
| +} |
| + |
| +void EncodingEventSubscriber::TransferPacketEvents(size_t num_entries) { |
| + DCHECK(packet_event_map_.size() >= num_entries); |
| + |
| + PacketEventMap::iterator it = packet_event_map_.begin(); |
| + 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
|
| + AddPacketEventToStorage(it->second); |
| + |
| + packet_event_map_.erase(packet_event_map_.begin(), it); |
| +} |
| + |
| +void EncodingEventSubscriber::AddFrameEventToStorage( |
| + const linked_ptr<AggregatedFrameEvent>& frame_event_proto) { |
| + if (frame_event_storage_.size() >= max_frames_) { |
| + frame_event_storage_[frame_event_storage_index_] = frame_event_proto; |
| + } else { |
| + frame_event_storage_.push_back(frame_event_proto); |
| + } |
| + |
| + frame_event_storage_index_ = (frame_event_storage_index_ + 1) % max_frames_; |
| } |
| -void EncodingEventSubscriber::TruncatePacketEventMapIfNeeded() { |
| - // This works because this is called everytime an event is inserted and |
| - // we only insert events one at a time. |
| - if (packet_event_map_.size() > max_frames_) |
| - packet_event_map_.erase(packet_event_map_.begin()); |
| +void EncodingEventSubscriber::AddPacketEventToStorage( |
| + const linked_ptr<AggregatedPacketEvent>& packet_event_proto) { |
| + if (packet_event_storage_.size() >= max_frames_) |
| + packet_event_storage_[packet_event_storage_index_] = packet_event_proto; |
| + else |
| + packet_event_storage_.push_back(packet_event_proto); |
| + |
| + packet_event_storage_index_ = (packet_event_storage_index_ + 1) % max_frames_; |
| } |
| RtpTimestamp EncodingEventSubscriber::GetRelativeRtpTimestamp( |
| @@ -175,7 +263,11 @@ RtpTimestamp EncodingEventSubscriber::GetRelativeRtpTimestamp( |
| void EncodingEventSubscriber::Reset() { |
| frame_event_map_.clear(); |
| + frame_event_storage_.clear(); |
| + frame_event_storage_index_ = 0; |
| packet_event_map_.clear(); |
| + packet_event_storage_.clear(); |
| + packet_event_storage_index_ = 0; |
| seen_first_rtp_timestamp_ = false; |
| first_rtp_timestamp_ = 0u; |
| } |