From 8c16520949ab0b3d3f2e51bb40278f9ca64659fd Mon Sep 17 00:00:00 2001 From: terelius Date: Mon, 22 Aug 2016 11:35:47 -0700 Subject: [PATCH] Method to parse event log directly from a string. Switches the main parsing function for RtcEventLogs to take an istream instead of a file pointer. Adds wrappers that accept either a string or a filename. Review-Url: https://codereview.webrtc.org/2253943006 Cr-Commit-Position: refs/heads/master@{#13852} --- webrtc/call/rtc_event_log_parser.cc | 102 +++++++++++-------- webrtc/call/rtc_event_log_parser.h | 8 +- webrtc/call/rtc_event_log_unittest_helper.cc | 16 +-- 3 files changed, 77 insertions(+), 49 deletions(-) diff --git a/webrtc/call/rtc_event_log_parser.cc b/webrtc/call/rtc_event_log_parser.cc index c49b9b47b4..59906b01c8 100644 --- a/webrtc/call/rtc_event_log_parser.cc +++ b/webrtc/call/rtc_event_log_parser.cc @@ -13,6 +13,8 @@ #include #include +#include +#include #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" @@ -82,87 +84,107 @@ ParsedRtcEventLog::EventType GetRuntimeEventType( return ParsedRtcEventLog::EventType::UNKNOWN_EVENT; } -bool ParseVarInt(std::FILE* file, uint64_t* varint, size_t* bytes_read) { - uint8_t byte; - *varint = 0; - for (*bytes_read = 0; *bytes_read < 10 && fread(&byte, 1, 1, file) == 1; - ++(*bytes_read)) { +std::pair ParseVarInt(std::istream& stream) { + uint64_t varint = 0; + for (size_t bytes_read = 0; bytes_read < 10; ++bytes_read) { // The most significant bit of each byte is 0 if it is the last byte in // the varint and 1 otherwise. Thus, we take the 7 least significant bits // of each byte and shift them 7 bits for each byte read previously to get // the (unsigned) integer. - *varint |= static_cast(byte & 0x7F) << (7 * *bytes_read); + int byte = stream.get(); + if (stream.eof()) { + return std::make_pair(varint, false); + } + RTC_DCHECK(0 <= byte && byte <= 255); + varint |= static_cast(byte & 0x7F) << (7 * bytes_read); if ((byte & 0x80) == 0) { - return true; + return std::make_pair(varint, true); } } - return false; + return std::make_pair(varint, false); } } // namespace bool ParsedRtcEventLog::ParseFile(const std::string& filename) { - stream_.clear(); - const size_t kMaxEventSize = (1u << 16) - 1; - char tmp_buffer[kMaxEventSize]; - - std::FILE* file = fopen(filename.c_str(), "rb"); - if (!file) { + std::ifstream file(filename, std::ios_base::in | std::ios_base::binary); + if (!file.good() || !file.is_open()) { LOG(LS_WARNING) << "Could not open file for reading."; return false; } + return ParseStream(file); +} + +bool ParsedRtcEventLog::ParseString(const std::string& s) { + std::istringstream stream(s, std::ios_base::in | std::ios_base::binary); + return ParseStream(stream); +} + +bool ParsedRtcEventLog::ParseStream(std::istream& stream) { + events_.clear(); + const size_t kMaxEventSize = (1u << 16) - 1; + char tmp_buffer[kMaxEventSize]; + uint64_t tag; + uint64_t message_length; + bool success; + + RTC_DCHECK(stream.good()); + while (1) { - // Peek at the next message tag. The tag number is defined as + // Check whether we have reached end of file. + stream.peek(); + if (stream.eof()) { + return true; + } + + // Read the next message tag. The tag number is defined as // (fieldnumber << 3) | wire_type. In our case, the field number is // supposed to be 1 and the wire type for an length-delimited field is 2. const uint64_t kExpectedTag = (1 << 3) | 2; - uint64_t tag; - size_t bytes_read; - if (!ParseVarInt(file, &tag, &bytes_read) || tag != kExpectedTag) { - fclose(file); - if (bytes_read == 0) { - return true; // Reached end of file. - } + std::tie(tag, success) = ParseVarInt(stream); + if (!success) { LOG(LS_WARNING) << "Missing field tag from beginning of protobuf event."; return false; + } else if (tag != kExpectedTag) { + LOG(LS_WARNING) << "Unexpected field tag at beginning of protobuf event."; + return false; } - // Peek at the length field. - uint64_t message_length; - if (!ParseVarInt(file, &message_length, &bytes_read)) { + // Read the length field. + std::tie(message_length, success) = ParseVarInt(stream); + if (!success) { LOG(LS_WARNING) << "Missing message length after protobuf field tag."; - fclose(file); return false; } else if (message_length > kMaxEventSize) { LOG(LS_WARNING) << "Protobuf message length is too large."; - fclose(file); return false; } - if (fread(tmp_buffer, 1, message_length, file) != message_length) { + // Read the next protobuf event to a temporary char buffer. + stream.read(tmp_buffer, message_length); + if (stream.gcount() != static_cast(message_length)) { LOG(LS_WARNING) << "Failed to read protobuf message from file."; - fclose(file); return false; } + // Parse the protobuf event from the buffer. rtclog::Event event; if (!event.ParseFromArray(tmp_buffer, message_length)) { LOG(LS_WARNING) << "Failed to parse protobuf message."; - fclose(file); return false; } - stream_.push_back(event); + events_.push_back(event); } } size_t ParsedRtcEventLog::GetNumberOfEvents() const { - return stream_.size(); + return events_.size(); } int64_t ParsedRtcEventLog::GetTimestamp(size_t index) const { RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = stream_[index]; + const rtclog::Event& event = events_[index]; RTC_CHECK(event.has_timestamp_us()); return event.timestamp_us(); } @@ -170,7 +192,7 @@ int64_t ParsedRtcEventLog::GetTimestamp(size_t index) const { ParsedRtcEventLog::EventType ParsedRtcEventLog::GetEventType( size_t index) const { RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = stream_[index]; + const rtclog::Event& event = events_[index]; RTC_CHECK(event.has_type()); return GetRuntimeEventType(event.type()); } @@ -183,7 +205,7 @@ void ParsedRtcEventLog::GetRtpHeader(size_t index, size_t* header_length, size_t* total_length) const { RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = stream_[index]; + const rtclog::Event& event = events_[index]; RTC_CHECK(event.has_type()); RTC_CHECK_EQ(event.type(), rtclog::Event::RTP_EVENT); RTC_CHECK(event.has_rtp_packet()); @@ -225,7 +247,7 @@ void ParsedRtcEventLog::GetRtcpPacket(size_t index, uint8_t* packet, size_t* length) const { RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = stream_[index]; + const rtclog::Event& event = events_[index]; RTC_CHECK(event.has_type()); RTC_CHECK_EQ(event.type(), rtclog::Event::RTCP_EVENT); RTC_CHECK(event.has_rtcp_packet()); @@ -258,7 +280,7 @@ void ParsedRtcEventLog::GetVideoReceiveConfig( size_t index, VideoReceiveStream::Config* config) const { RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = stream_[index]; + const rtclog::Event& event = events_[index]; RTC_CHECK(config != nullptr); RTC_CHECK(event.has_type()); RTC_CHECK_EQ(event.type(), rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT); @@ -313,7 +335,7 @@ void ParsedRtcEventLog::GetVideoSendConfig( size_t index, VideoSendStream::Config* config) const { RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = stream_[index]; + const rtclog::Event& event = events_[index]; RTC_CHECK(config != nullptr); RTC_CHECK(event.has_type()); RTC_CHECK_EQ(event.type(), rtclog::Event::VIDEO_SENDER_CONFIG_EVENT); @@ -356,7 +378,7 @@ void ParsedRtcEventLog::GetVideoSendConfig( void ParsedRtcEventLog::GetAudioPlayout(size_t index, uint32_t* ssrc) const { RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = stream_[index]; + const rtclog::Event& event = events_[index]; RTC_CHECK(event.has_type()); RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_PLAYOUT_EVENT); RTC_CHECK(event.has_audio_playout_event()); @@ -372,7 +394,7 @@ void ParsedRtcEventLog::GetBwePacketLossEvent(size_t index, uint8_t* fraction_loss, int32_t* total_packets) const { RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = stream_[index]; + const rtclog::Event& event = events_[index]; RTC_CHECK(event.has_type()); RTC_CHECK_EQ(event.type(), rtclog::Event::BWE_PACKET_LOSS_EVENT); RTC_CHECK(event.has_bwe_packet_loss_event()); diff --git a/webrtc/call/rtc_event_log_parser.h b/webrtc/call/rtc_event_log_parser.h index acdfa77da1..74f066d575 100644 --- a/webrtc/call/rtc_event_log_parser.h +++ b/webrtc/call/rtc_event_log_parser.h @@ -50,6 +50,12 @@ class ParsedRtcEventLog { // Reads an RtcEventLog file and returns true if parsing was successful. bool ParseFile(const std::string& file_name); + // Reads an RtcEventLog from a string and returns true if successful. + bool ParseString(const std::string& s); + + // Reads an RtcEventLog from an istream and returns true if successful. + bool ParseStream(std::istream& stream); + // Returns the number of events in an EventStream. size_t GetNumberOfEvents() const; @@ -106,7 +112,7 @@ class ParsedRtcEventLog { int32_t* total_packets) const; private: - std::vector stream_; + std::vector events_; }; } // namespace webrtc diff --git a/webrtc/call/rtc_event_log_unittest_helper.cc b/webrtc/call/rtc_event_log_unittest_helper.cc index dcaeaf979c..194414f4ba 100644 --- a/webrtc/call/rtc_event_log_unittest_helper.cc +++ b/webrtc/call/rtc_event_log_unittest_helper.cc @@ -108,7 +108,7 @@ void RtcEventLogTestHelper::VerifyReceiveStreamConfig( const ParsedRtcEventLog& parsed_log, size_t index, const VideoReceiveStream::Config& config) { - const rtclog::Event& event = parsed_log.stream_[index]; + const rtclog::Event& event = parsed_log.events_[index]; ASSERT_TRUE(IsValidBasicEvent(event)); ASSERT_EQ(rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT, event.type()); const rtclog::VideoReceiveConfig& receiver_config = @@ -204,7 +204,7 @@ void RtcEventLogTestHelper::VerifySendStreamConfig( const ParsedRtcEventLog& parsed_log, size_t index, const VideoSendStream::Config& config) { - const rtclog::Event& event = parsed_log.stream_[index]; + const rtclog::Event& event = parsed_log.events_[index]; ASSERT_TRUE(IsValidBasicEvent(event)); ASSERT_EQ(rtclog::Event::VIDEO_SENDER_CONFIG_EVENT, event.type()); const rtclog::VideoSendConfig& sender_config = event.video_sender_config(); @@ -279,7 +279,7 @@ void RtcEventLogTestHelper::VerifyRtpEvent(const ParsedRtcEventLog& parsed_log, const uint8_t* header, size_t header_size, size_t total_size) { - const rtclog::Event& event = parsed_log.stream_[index]; + const rtclog::Event& event = parsed_log.events_[index]; ASSERT_TRUE(IsValidBasicEvent(event)); ASSERT_EQ(rtclog::Event::RTP_EVENT, event.type()); const rtclog::RtpPacket& rtp_packet = event.rtp_packet(); @@ -316,7 +316,7 @@ void RtcEventLogTestHelper::VerifyRtcpEvent(const ParsedRtcEventLog& parsed_log, MediaType media_type, const uint8_t* packet, size_t total_size) { - const rtclog::Event& event = parsed_log.stream_[index]; + const rtclog::Event& event = parsed_log.events_[index]; ASSERT_TRUE(IsValidBasicEvent(event)); ASSERT_EQ(rtclog::Event::RTCP_EVENT, event.type()); const rtclog::RtcpPacket& rtcp_packet = event.rtcp_packet(); @@ -347,7 +347,7 @@ void RtcEventLogTestHelper::VerifyPlayoutEvent( const ParsedRtcEventLog& parsed_log, size_t index, uint32_t ssrc) { - const rtclog::Event& event = parsed_log.stream_[index]; + const rtclog::Event& event = parsed_log.events_[index]; ASSERT_TRUE(IsValidBasicEvent(event)); ASSERT_EQ(rtclog::Event::AUDIO_PLAYOUT_EVENT, event.type()); const rtclog::AudioPlayoutEvent& playout_event = event.audio_playout_event(); @@ -366,7 +366,7 @@ void RtcEventLogTestHelper::VerifyBweLossEvent( int32_t bitrate, uint8_t fraction_loss, int32_t total_packets) { - const rtclog::Event& event = parsed_log.stream_[index]; + const rtclog::Event& event = parsed_log.events_[index]; ASSERT_TRUE(IsValidBasicEvent(event)); ASSERT_EQ(rtclog::Event::BWE_PACKET_LOSS_EVENT, event.type()); const rtclog::BwePacketLossEvent& bwe_event = event.bwe_packet_loss_event(); @@ -391,7 +391,7 @@ void RtcEventLogTestHelper::VerifyBweLossEvent( void RtcEventLogTestHelper::VerifyLogStartEvent( const ParsedRtcEventLog& parsed_log, size_t index) { - const rtclog::Event& event = parsed_log.stream_[index]; + const rtclog::Event& event = parsed_log.events_[index]; ASSERT_TRUE(IsValidBasicEvent(event)); EXPECT_EQ(rtclog::Event::LOG_START, event.type()); } @@ -399,7 +399,7 @@ void RtcEventLogTestHelper::VerifyLogStartEvent( void RtcEventLogTestHelper::VerifyLogEndEvent( const ParsedRtcEventLog& parsed_log, size_t index) { - const rtclog::Event& event = parsed_log.stream_[index]; + const rtclog::Event& event = parsed_log.events_[index]; ASSERT_TRUE(IsValidBasicEvent(event)); EXPECT_EQ(rtclog::Event::LOG_END, event.type()); }