Revert "Create new API for RtcEventLogParser."

This reverts commit 9e336ec0b8a77c3461d13677cff3563c11c88daa.

Reason for revert: Code can accidentally include the deprecated parser but link with the new one, or vice versa. Reverting to fix naming.

Original change's description:
> Create new API for RtcEventLogParser.
> 
> The new API stores events gathered by event type. For example, it is
> possible to ask fo a list of all incoming RTCP messages or all audio
> playout events.
> 
> The new API is experimental and may change over next few weeks. Once
> it has stabilized and all unit tests and existing tools have been
> ported to the new API, the old one will be removed.
> 
> This CL also updates the event_log_visualizer tool to use the new
> parser API. This is not a funcional change except for:
> - Incoming and outgoing audio level are now drawn in two separate plots.
> - Incoming and outgoing timstamps are now drawn in two separate plots.
> - RTCP count is no longer split into Video and Audio. It also counts
>   all RTCP packets rather than only specific message types.
> - Slight timing difference in sendside BWE simulation due to only
>   iterating over transport feedbacks and not over all RTCP packets.
>   This timing changes are not visible in the plots.
> 
> 
> Media type for RTCP messages might not be identified correctly by
> rtc_event_log2text anymore. On the other hand, assigning a specific
> media type to an RTCP packet was a bit hacky to begin with.
> 
> Bug: webrtc:8111
> Change-Id: I8e7168302beb69b2e163a097a2a142b86dd4a26b
> Reviewed-on: https://webrtc-review.googlesource.com/60865
> Reviewed-by: Minyue Li <minyue@webrtc.org>
> Reviewed-by: Sebastian Jansson <srte@webrtc.org>
> Commit-Queue: Björn Terelius <terelius@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#23015}

TBR=terelius@webrtc.org,srte@webrtc.org,minyue@webrtc.org

Change-Id: Ib4bbcf0563423675a3cc1dce59ebf665e0c5dae9
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: webrtc:8111
Reviewed-on: https://webrtc-review.googlesource.com/72500
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23026}
diff --git a/logging/BUILD.gn b/logging/BUILD.gn
index 8f81e7a..a47c81d 100644
--- a/logging/BUILD.gn
+++ b/logging/BUILD.gn
@@ -253,8 +253,8 @@
 
   rtc_static_library("rtc_event_log_parser") {
     sources = [
-      "rtc_event_log/rtc_event_log_parser2.cc",
-      "rtc_event_log/rtc_event_log_parser2.h",
+      "rtc_event_log/rtc_event_log_parser.cc",
+      "rtc_event_log/rtc_event_log_parser.h",
     ]
 
     deps = [
@@ -265,7 +265,6 @@
       ":rtc_event_log_proto",
       ":rtc_stream_config",
       "..:webrtc_common",
-      "../api:libjingle_peerconnection_api",
       "../call:video_stream_api",
       "../modules/audio_coding:audio_network_adaptor",
       "../modules/remote_bitrate_estimator:remote_bitrate_estimator",
@@ -366,7 +365,6 @@
         "../rtc_base:checks",
         "../rtc_base:protobuf_utils",
         "../rtc_base:rtc_base_approved",
-        "../rtc_base:stringutils",
 
         # TODO(kwiberg): Remove this dependency.
         "../api/audio_codecs:audio_codecs_api",
diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc
index 0e6e183..6d88298 100644
--- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc
+++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc
@@ -32,7 +32,7 @@
 #include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h"
 #include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
 #include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
-#include "logging/rtc_event_log/rtc_event_log_parser2.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
 #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
 #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/bye.h"  // Arbitrary RTCP message.
@@ -142,11 +142,11 @@
   ASSERT_EQ(parsed_log_.GetEventType(0),
             ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT);
 
-  LoggedAudioNetworkAdaptationEvent parsed_event =
-      parsed_log_.GetAudioNetworkAdaptation(0);
+  AudioEncoderRuntimeConfig parsed_runtime_config;
+  parsed_log_.GetAudioNetworkAdaptation(0, &parsed_runtime_config);
 
-  EXPECT_EQ(parsed_event.timestamp_us, timestamp_us);
-  EXPECT_EQ(parsed_event.config, original_runtime_config);
+  EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us);
+  EXPECT_EQ(parsed_runtime_config, original_runtime_config);
 }
 
 TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationBitrate) {
@@ -234,10 +234,11 @@
   ASSERT_EQ(parsed_log_.GetEventType(0),
             ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT);
 
-  LoggedAudioPlayoutEvent playout_event = parsed_log_.GetAudioPlayout(0);
+  uint32_t parsed_ssrc;
+  parsed_log_.GetAudioPlayout(0, &parsed_ssrc);
 
-  EXPECT_EQ(playout_event.timestamp_us, timestamp_us);
-  EXPECT_EQ(playout_event.ssrc, ssrc);
+  EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us);
+  EXPECT_EQ(parsed_ssrc, ssrc);
 }
 
 TEST_P(RtcEventLogEncoderTest, RtcEventAudioReceiveStreamConfig) {
@@ -332,12 +333,16 @@
   ASSERT_EQ(parsed_log_.GetEventType(0),
             ParsedRtcEventLog::LOSS_BASED_BWE_UPDATE);
 
-  LoggedBweLossBasedUpdate bwe_update = parsed_log_.GetLossBasedBweUpdate(0);
+  int32_t parsed_bitrate_bps;
+  uint8_t parsed_fraction_loss;
+  int32_t parsed_total_packets;
+  parsed_log_.GetLossBasedBweUpdate(
+      0, &parsed_bitrate_bps, &parsed_fraction_loss, &parsed_total_packets);
 
-  EXPECT_EQ(bwe_update.timestamp_us, timestamp_us);
-  EXPECT_EQ(bwe_update.bitrate_bps, bitrate_bps);
-  EXPECT_EQ(bwe_update.fraction_lost, fraction_loss);
-  EXPECT_EQ(bwe_update.expected_packets, total_packets);
+  EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us);
+  EXPECT_EQ(parsed_bitrate_bps, bitrate_bps);
+  EXPECT_EQ(parsed_fraction_loss, fraction_loss);
+  EXPECT_EQ(parsed_total_packets, total_packets);
 }
 
 TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStarted) {
diff --git a/logging/rtc_event_log/rtc_event_log.h b/logging/rtc_event_log/rtc_event_log.h
index 0c71406..a0714e0 100644
--- a/logging/rtc_event_log/rtc_event_log.h
+++ b/logging/rtc_event_log/rtc_event_log.h
@@ -21,7 +21,6 @@
 
 namespace webrtc {
 
-// TODO(terelius): Move this to the parser.
 enum PacketDirection { kIncomingPacket = 0, kOutgoingPacket };
 
 class RtcEventLog {
diff --git a/logging/rtc_event_log/rtc_event_log2rtp_dump.cc b/logging/rtc_event_log/rtc_event_log2rtp_dump.cc
index c4d6948..c6fa129 100644
--- a/logging/rtc_event_log/rtc_event_log2rtp_dump.cc
+++ b/logging/rtc_event_log/rtc_event_log2rtp_dump.cc
@@ -16,7 +16,7 @@
 #include <string>
 
 #include "logging/rtc_event_log/rtc_event_log.h"
-#include "logging/rtc_event_log/rtc_event_log_parser2.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
 #include "modules/rtp_rtcp/source/rtp_utility.h"
 #include "rtc_base/checks.h"
diff --git a/logging/rtc_event_log/rtc_event_log2text.cc b/logging/rtc_event_log/rtc_event_log2text.cc
index 6ceeaaf..c71a2b8 100644
--- a/logging/rtc_event_log/rtc_event_log2text.cc
+++ b/logging/rtc_event_log/rtc_event_log2text.cc
@@ -13,12 +13,13 @@
 #include <iomanip>  // setfill, setw
 #include <iostream>
 #include <map>
+#include <sstream>
 #include <string>
 #include <utility>  // pair
 
 #include "call/video_config.h"
 #include "common_types.h"  // NOLINT(build/include)
-#include "logging/rtc_event_log/rtc_event_log_parser2.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
 #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
@@ -39,7 +40,6 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/flags.h"
 #include "rtc_base/logging.h"
-#include "rtc_base/strings/string_builder.h"
 
 namespace {
 
@@ -443,7 +443,7 @@
           size_t total_length;
           uint8_t header[IP_PACKET_SIZE];
           webrtc::PacketDirection direction;
-          const webrtc::RtpHeaderExtensionMap* extension_map =
+          webrtc::RtpHeaderExtensionMap* extension_map =
               parsed_stream.GetRtpHeader(i, &direction, header, &header_length,
                                          &total_length, nullptr);
 
@@ -583,9 +583,10 @@
 
       case webrtc::ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT: {
         if (FLAG_playout) {
-          auto audio_playout = parsed_stream.GetAudioPlayout(i);
-          std::cout << audio_playout.log_time_us() << "\tAUDIO_PLAYOUT"
-                    << "\tssrc=" << audio_playout.ssrc << std::endl;
+          uint32_t ssrc;
+          parsed_stream.GetAudioPlayout(i, &ssrc);
+          std::cout << parsed_stream.GetTimestamp(i) << "\tAUDIO_PLAYOUT"
+                    << "\tssrc=" << ssrc << std::endl;
         }
         event_recognized = true;
         break;
@@ -593,13 +594,15 @@
 
       case webrtc::ParsedRtcEventLog::LOSS_BASED_BWE_UPDATE: {
         if (FLAG_bwe) {
-          auto bwe_update = parsed_stream.GetLossBasedBweUpdate(i);
-          std::cout << bwe_update.log_time_us() << "\tBWE(LOSS_BASED)"
-                    << "\tbitrate_bps=" << bwe_update.bitrate_bps
-                    << "\tfraction_lost="
-                    << static_cast<unsigned>(bwe_update.fraction_lost)
-                    << "\texpected_packets=" << bwe_update.expected_packets
-                    << std::endl;
+          int32_t bitrate_bps;
+          uint8_t fraction_loss;
+          int32_t total_packets;
+          parsed_stream.GetLossBasedBweUpdate(i, &bitrate_bps, &fraction_loss,
+                                              &total_packets);
+          std::cout << parsed_stream.GetTimestamp(i) << "\tBWE(LOSS_BASED)"
+                    << "\tbitrate_bps=" << bitrate_bps << "\tfraction_loss="
+                    << static_cast<unsigned>(fraction_loss)
+                    << "\ttotal_packets=" << total_packets << std::endl;
         }
         event_recognized = true;
         break;
@@ -608,7 +611,7 @@
       case webrtc::ParsedRtcEventLog::DELAY_BASED_BWE_UPDATE: {
         if (FLAG_bwe) {
           auto bwe_update = parsed_stream.GetDelayBasedBweUpdate(i);
-          std::cout << bwe_update.log_time_us() << "\tBWE(DELAY_BASED)"
+          std::cout << parsed_stream.GetTimestamp(i) << "\tBWE(DELAY_BASED)"
                     << "\tbitrate_bps=" << bwe_update.bitrate_bps
                     << "\tdetector_state="
                     << static_cast<int>(bwe_update.detector_state) << std::endl;
@@ -720,31 +723,30 @@
 
       case webrtc::ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT: {
         if (FLAG_ana) {
-          auto ana_event = parsed_stream.GetAudioNetworkAdaptation(i);
-          char buffer[300];
-          rtc::SimpleStringBuilder builder(buffer);
-          builder << parsed_stream.GetTimestamp(i) << "\tANA_UPDATE";
-          if (ana_event.config.bitrate_bps) {
-            builder << "\tbitrate_bps=" << *ana_event.config.bitrate_bps;
+          webrtc::AudioEncoderRuntimeConfig ana_config;
+          parsed_stream.GetAudioNetworkAdaptation(i, &ana_config);
+          std::stringstream ss;
+          ss << parsed_stream.GetTimestamp(i) << "\tANA_UPDATE";
+          if (ana_config.bitrate_bps) {
+            ss << "\tbitrate_bps=" << *ana_config.bitrate_bps;
           }
-          if (ana_event.config.frame_length_ms) {
-            builder << "\tframe_length_ms="
-                    << *ana_event.config.frame_length_ms;
+          if (ana_config.frame_length_ms) {
+            ss << "\tframe_length_ms=" << *ana_config.frame_length_ms;
           }
-          if (ana_event.config.uplink_packet_loss_fraction) {
-            builder << "\tuplink_packet_loss_fraction="
-                    << *ana_event.config.uplink_packet_loss_fraction;
+          if (ana_config.uplink_packet_loss_fraction) {
+            ss << "\tuplink_packet_loss_fraction="
+               << *ana_config.uplink_packet_loss_fraction;
           }
-          if (ana_event.config.enable_fec) {
-            builder << "\tenable_fec=" << *ana_event.config.enable_fec;
+          if (ana_config.enable_fec) {
+            ss << "\tenable_fec=" << *ana_config.enable_fec;
           }
-          if (ana_event.config.enable_dtx) {
-            builder << "\tenable_dtx=" << *ana_event.config.enable_dtx;
+          if (ana_config.enable_dtx) {
+            ss << "\tenable_dtx=" << *ana_config.enable_dtx;
           }
-          if (ana_event.config.num_channels) {
-            builder << "\tnum_channels=" << *ana_event.config.num_channels;
+          if (ana_config.num_channels) {
+            ss << "\tnum_channels=" << *ana_config.num_channels;
           }
-          std::cout << builder.str() << std::endl;
+          std::cout << ss.str() << std::endl;
         }
         event_recognized = true;
         break;
@@ -752,7 +754,8 @@
 
       case webrtc::ParsedRtcEventLog::BWE_PROBE_CLUSTER_CREATED_EVENT: {
         if (FLAG_probe) {
-          auto probe_event = parsed_stream.GetBweProbeClusterCreated(i);
+          webrtc::ParsedRtcEventLog::BweProbeClusterCreatedEvent probe_event =
+              parsed_stream.GetBweProbeClusterCreated(i);
           std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_CREATED("
                     << probe_event.id << ")"
                     << "\tbitrate_bps=" << probe_event.bitrate_bps
@@ -765,7 +768,7 @@
 
       case webrtc::ParsedRtcEventLog::BWE_PROBE_RESULT_EVENT: {
         if (FLAG_probe) {
-          webrtc::LoggedBweProbeResultEvent probe_result =
+          webrtc::ParsedRtcEventLog::BweProbeResultEvent probe_result =
               parsed_stream.GetBweProbeResult(i);
           if (probe_result.failure_reason) {
             std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_SUCCESS("
@@ -786,7 +789,8 @@
 
       case webrtc::ParsedRtcEventLog::ALR_STATE_EVENT: {
         if (FLAG_bwe) {
-          webrtc::LoggedAlrStateEvent alr_state = parsed_stream.GetAlrState(i);
+          webrtc::ParsedRtcEventLog::AlrStateEvent alr_state =
+              parsed_stream.GetAlrState(i);
           std::cout << parsed_stream.GetTimestamp(i) << "\tALR_STATE"
                     << "\tin_alr=" << alr_state.in_alr << std::endl;
         }
@@ -796,7 +800,7 @@
 
       case webrtc::ParsedRtcEventLog::ICE_CANDIDATE_PAIR_CONFIG: {
         if (FLAG_ice) {
-          webrtc::LoggedIceCandidatePairConfig ice_cp_config =
+          webrtc::ParsedRtcEventLog::IceCandidatePairConfig ice_cp_config =
               parsed_stream.GetIceCandidatePairConfig(i);
           // TODO(qingsi): convert the numeric representation of states to text
           std::cout << parsed_stream.GetTimestamp(i)
@@ -810,7 +814,7 @@
 
       case webrtc::ParsedRtcEventLog::ICE_CANDIDATE_PAIR_EVENT: {
         if (FLAG_ice) {
-          webrtc::LoggedIceCandidatePairEvent ice_cp_event =
+          webrtc::ParsedRtcEventLog::IceCandidatePairEvent ice_cp_event =
               parsed_stream.GetIceCandidatePairEvent(i);
           // TODO(qingsi): convert the numeric representation of states to text
           std::cout << parsed_stream.GetTimestamp(i)
diff --git a/logging/rtc_event_log/rtc_event_log_parser2.cc b/logging/rtc_event_log/rtc_event_log_parser2.cc
deleted file mode 100644
index 9bcad0d..0000000
--- a/logging/rtc_event_log/rtc_event_log_parser2.cc
+++ /dev/null
@@ -1,1248 +0,0 @@
-/*
- *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "logging/rtc_event_log/rtc_event_log_parser2.h"
-
-#include <stdint.h>
-#include <string.h>
-
-#include <algorithm>
-#include <fstream>
-#include <istream>  // no-presubmit-check TODO(webrtc:8982)
-#include <limits>
-#include <map>
-#include <utility>
-
-#include "api/rtp_headers.h"
-#include "api/rtpparameters.h"
-#include "logging/rtc_event_log/rtc_event_log.h"
-#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
-#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
-#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "modules/rtp_rtcp/source/byte_io.h"
-#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
-#include "modules/rtp_rtcp/source/rtp_utility.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/protobuf_utils.h"
-#include "rtc_base/ptr_util.h"
-
-namespace webrtc {
-
-namespace {
-RtcpMode GetRuntimeRtcpMode(rtclog::VideoReceiveConfig::RtcpMode rtcp_mode) {
-  switch (rtcp_mode) {
-    case rtclog::VideoReceiveConfig::RTCP_COMPOUND:
-      return RtcpMode::kCompound;
-    case rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE:
-      return RtcpMode::kReducedSize;
-  }
-  RTC_NOTREACHED();
-  return RtcpMode::kOff;
-}
-
-ParsedRtcEventLog::EventType GetRuntimeEventType(
-    rtclog::Event::EventType event_type) {
-  switch (event_type) {
-    case rtclog::Event::UNKNOWN_EVENT:
-      return ParsedRtcEventLog::EventType::UNKNOWN_EVENT;
-    case rtclog::Event::LOG_START:
-      return ParsedRtcEventLog::EventType::LOG_START;
-    case rtclog::Event::LOG_END:
-      return ParsedRtcEventLog::EventType::LOG_END;
-    case rtclog::Event::RTP_EVENT:
-      return ParsedRtcEventLog::EventType::RTP_EVENT;
-    case rtclog::Event::RTCP_EVENT:
-      return ParsedRtcEventLog::EventType::RTCP_EVENT;
-    case rtclog::Event::AUDIO_PLAYOUT_EVENT:
-      return ParsedRtcEventLog::EventType::AUDIO_PLAYOUT_EVENT;
-    case rtclog::Event::LOSS_BASED_BWE_UPDATE:
-      return ParsedRtcEventLog::EventType::LOSS_BASED_BWE_UPDATE;
-    case rtclog::Event::DELAY_BASED_BWE_UPDATE:
-      return ParsedRtcEventLog::EventType::DELAY_BASED_BWE_UPDATE;
-    case rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT:
-      return ParsedRtcEventLog::EventType::VIDEO_RECEIVER_CONFIG_EVENT;
-    case rtclog::Event::VIDEO_SENDER_CONFIG_EVENT:
-      return ParsedRtcEventLog::EventType::VIDEO_SENDER_CONFIG_EVENT;
-    case rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT:
-      return ParsedRtcEventLog::EventType::AUDIO_RECEIVER_CONFIG_EVENT;
-    case rtclog::Event::AUDIO_SENDER_CONFIG_EVENT:
-      return ParsedRtcEventLog::EventType::AUDIO_SENDER_CONFIG_EVENT;
-    case rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT:
-      return ParsedRtcEventLog::EventType::AUDIO_NETWORK_ADAPTATION_EVENT;
-    case rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT:
-      return ParsedRtcEventLog::EventType::BWE_PROBE_CLUSTER_CREATED_EVENT;
-    case rtclog::Event::BWE_PROBE_RESULT_EVENT:
-      return ParsedRtcEventLog::EventType::BWE_PROBE_RESULT_EVENT;
-    case rtclog::Event::ALR_STATE_EVENT:
-      return ParsedRtcEventLog::EventType::ALR_STATE_EVENT;
-    case rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG:
-      return ParsedRtcEventLog::EventType::ICE_CANDIDATE_PAIR_CONFIG;
-    case rtclog::Event::ICE_CANDIDATE_PAIR_EVENT:
-      return ParsedRtcEventLog::EventType::ICE_CANDIDATE_PAIR_EVENT;
-  }
-  return ParsedRtcEventLog::EventType::UNKNOWN_EVENT;
-}
-
-BandwidthUsage GetRuntimeDetectorState(
-    rtclog::DelayBasedBweUpdate::DetectorState detector_state) {
-  switch (detector_state) {
-    case rtclog::DelayBasedBweUpdate::BWE_NORMAL:
-      return BandwidthUsage::kBwNormal;
-    case rtclog::DelayBasedBweUpdate::BWE_UNDERUSING:
-      return BandwidthUsage::kBwUnderusing;
-    case rtclog::DelayBasedBweUpdate::BWE_OVERUSING:
-      return BandwidthUsage::kBwOverusing;
-  }
-  RTC_NOTREACHED();
-  return BandwidthUsage::kBwNormal;
-}
-
-IceCandidatePairEventType GetRuntimeIceCandidatePairConfigType(
-    rtclog::IceCandidatePairConfig::IceCandidatePairConfigType type) {
-  switch (type) {
-    case rtclog::IceCandidatePairConfig::ADDED:
-      return IceCandidatePairEventType::kAdded;
-    case rtclog::IceCandidatePairConfig::UPDATED:
-      return IceCandidatePairEventType::kUpdated;
-    case rtclog::IceCandidatePairConfig::DESTROYED:
-      return IceCandidatePairEventType::kDestroyed;
-    case rtclog::IceCandidatePairConfig::SELECTED:
-      return IceCandidatePairEventType::kSelected;
-  }
-  RTC_NOTREACHED();
-  return IceCandidatePairEventType::kAdded;
-}
-
-IceCandidateType GetRuntimeIceCandidateType(
-    rtclog::IceCandidatePairConfig::IceCandidateType type) {
-  switch (type) {
-    case rtclog::IceCandidatePairConfig::LOCAL:
-      return IceCandidateType::kLocal;
-    case rtclog::IceCandidatePairConfig::STUN:
-      return IceCandidateType::kStun;
-    case rtclog::IceCandidatePairConfig::PRFLX:
-      return IceCandidateType::kPrflx;
-    case rtclog::IceCandidatePairConfig::RELAY:
-      return IceCandidateType::kRelay;
-    case rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE:
-      return IceCandidateType::kUnknown;
-  }
-  RTC_NOTREACHED();
-  return IceCandidateType::kUnknown;
-}
-
-IceCandidatePairProtocol GetRuntimeIceCandidatePairProtocol(
-    rtclog::IceCandidatePairConfig::Protocol protocol) {
-  switch (protocol) {
-    case rtclog::IceCandidatePairConfig::UDP:
-      return IceCandidatePairProtocol::kUdp;
-    case rtclog::IceCandidatePairConfig::TCP:
-      return IceCandidatePairProtocol::kTcp;
-    case rtclog::IceCandidatePairConfig::SSLTCP:
-      return IceCandidatePairProtocol::kSsltcp;
-    case rtclog::IceCandidatePairConfig::TLS:
-      return IceCandidatePairProtocol::kTls;
-    case rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL:
-      return IceCandidatePairProtocol::kUnknown;
-  }
-  RTC_NOTREACHED();
-  return IceCandidatePairProtocol::kUnknown;
-}
-
-IceCandidatePairAddressFamily GetRuntimeIceCandidatePairAddressFamily(
-    rtclog::IceCandidatePairConfig::AddressFamily address_family) {
-  switch (address_family) {
-    case rtclog::IceCandidatePairConfig::IPV4:
-      return IceCandidatePairAddressFamily::kIpv4;
-    case rtclog::IceCandidatePairConfig::IPV6:
-      return IceCandidatePairAddressFamily::kIpv6;
-    case rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY:
-      return IceCandidatePairAddressFamily::kUnknown;
-  }
-  RTC_NOTREACHED();
-  return IceCandidatePairAddressFamily::kUnknown;
-}
-
-IceCandidateNetworkType GetRuntimeIceCandidateNetworkType(
-    rtclog::IceCandidatePairConfig::NetworkType network_type) {
-  switch (network_type) {
-    case rtclog::IceCandidatePairConfig::ETHERNET:
-      return IceCandidateNetworkType::kEthernet;
-    case rtclog::IceCandidatePairConfig::LOOPBACK:
-      return IceCandidateNetworkType::kLoopback;
-    case rtclog::IceCandidatePairConfig::WIFI:
-      return IceCandidateNetworkType::kWifi;
-    case rtclog::IceCandidatePairConfig::VPN:
-      return IceCandidateNetworkType::kVpn;
-    case rtclog::IceCandidatePairConfig::CELLULAR:
-      return IceCandidateNetworkType::kCellular;
-    case rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE:
-      return IceCandidateNetworkType::kUnknown;
-  }
-  RTC_NOTREACHED();
-  return IceCandidateNetworkType::kUnknown;
-}
-
-IceCandidatePairEventType GetRuntimeIceCandidatePairEventType(
-    rtclog::IceCandidatePairEvent::IceCandidatePairEventType type) {
-  switch (type) {
-    case rtclog::IceCandidatePairEvent::CHECK_SENT:
-      return IceCandidatePairEventType::kCheckSent;
-    case rtclog::IceCandidatePairEvent::CHECK_RECEIVED:
-      return IceCandidatePairEventType::kCheckReceived;
-    case rtclog::IceCandidatePairEvent::CHECK_RESPONSE_SENT:
-      return IceCandidatePairEventType::kCheckResponseSent;
-    case rtclog::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED:
-      return IceCandidatePairEventType::kCheckResponseReceived;
-  }
-  RTC_NOTREACHED();
-  return IceCandidatePairEventType::kCheckSent;
-}
-
-// Return default values for header extensions, to use on streams without stored
-// mapping data. Currently this only applies to audio streams, since the mapping
-// is not stored in the event log.
-// TODO(ivoc): Remove this once this mapping is stored in the event log for
-//             audio streams. Tracking bug: webrtc:6399
-webrtc::RtpHeaderExtensionMap GetDefaultHeaderExtensionMap() {
-  webrtc::RtpHeaderExtensionMap default_map;
-  default_map.Register<AudioLevel>(webrtc::RtpExtension::kAudioLevelDefaultId);
-  default_map.Register<TransmissionOffset>(
-      webrtc::RtpExtension::kTimestampOffsetDefaultId);
-  default_map.Register<AbsoluteSendTime>(
-      webrtc::RtpExtension::kAbsSendTimeDefaultId);
-  default_map.Register<VideoOrientation>(
-      webrtc::RtpExtension::kVideoRotationDefaultId);
-  default_map.Register<VideoContentTypeExtension>(
-      webrtc::RtpExtension::kVideoContentTypeDefaultId);
-  default_map.Register<VideoTimingExtension>(
-      webrtc::RtpExtension::kVideoTimingDefaultId);
-  default_map.Register<TransportSequenceNumber>(
-      webrtc::RtpExtension::kTransportSequenceNumberDefaultId);
-  default_map.Register<PlayoutDelayLimits>(
-      webrtc::RtpExtension::kPlayoutDelayDefaultId);
-  return default_map;
-}
-
-std::pair<uint64_t, bool> ParseVarInt(
-    std::istream& stream) {  // no-presubmit-check TODO(webrtc:8982)
-  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.
-    int byte = stream.get();
-    if (stream.eof()) {
-      return std::make_pair(varint, false);
-    }
-    RTC_DCHECK_GE(byte, 0);
-    RTC_DCHECK_LE(byte, 255);
-    varint |= static_cast<uint64_t>(byte & 0x7F) << (7 * bytes_read);
-    if ((byte & 0x80) == 0) {
-      return std::make_pair(varint, true);
-    }
-  }
-  return std::make_pair(varint, false);
-}
-
-void GetHeaderExtensions(std::vector<RtpExtension>* header_extensions,
-                         const RepeatedPtrField<rtclog::RtpHeaderExtension>&
-                             proto_header_extensions) {
-  header_extensions->clear();
-  for (auto& p : proto_header_extensions) {
-    RTC_CHECK(p.has_name());
-    RTC_CHECK(p.has_id());
-    const std::string& name = p.name();
-    int id = p.id();
-    header_extensions->push_back(RtpExtension(name, id));
-  }
-}
-
-}  // namespace
-
-ParsedRtcEventLog::ParsedRtcEventLog(
-    UnconfiguredHeaderExtensions parse_unconfigured_header_extensions)
-    : parse_unconfigured_header_extensions_(
-          parse_unconfigured_header_extensions) {
-  Clear();
-}
-
-void ParsedRtcEventLog::Clear() {
-  events_.clear();
-  default_extension_map_ = GetDefaultHeaderExtensionMap();
-
-  incoming_rtx_ssrcs_.clear();
-  incoming_video_ssrcs_.clear();
-  incoming_audio_ssrcs_.clear();
-  outgoing_rtx_ssrcs_.clear();
-  outgoing_video_ssrcs_.clear();
-  outgoing_audio_ssrcs_.clear();
-
-  incoming_rtp_packets_map_.clear();
-  outgoing_rtp_packets_map_.clear();
-  incoming_rtp_packets_by_ssrc_.clear();
-  outgoing_rtp_packets_by_ssrc_.clear();
-  incoming_rtp_packet_views_by_ssrc_.clear();
-  outgoing_rtp_packet_views_by_ssrc_.clear();
-
-  incoming_rtcp_packets_.clear();
-  outgoing_rtcp_packets_.clear();
-
-  incoming_rr_.clear();
-  outgoing_rr_.clear();
-  incoming_sr_.clear();
-  outgoing_sr_.clear();
-  incoming_nack_.clear();
-  outgoing_nack_.clear();
-  incoming_remb_.clear();
-  outgoing_remb_.clear();
-  incoming_transport_feedback_.clear();
-  outgoing_transport_feedback_.clear();
-
-  start_log_events_.clear();
-  stop_log_events_.clear();
-  audio_playout_events_.clear();
-  audio_network_adaptation_events_.clear();
-  bwe_probe_cluster_created_events_.clear();
-  bwe_probe_result_events_.clear();
-  bwe_delay_updates_.clear();
-  bwe_loss_updates_.clear();
-  alr_state_events_.clear();
-  ice_candidate_pair_configs_.clear();
-  ice_candidate_pair_events_.clear();
-  audio_recv_configs_.clear();
-  audio_send_configs_.clear();
-  video_recv_configs_.clear();
-  video_send_configs_.clear();
-
-  memset(last_incoming_rtcp_packet_, 0, IP_PACKET_SIZE);
-  last_incoming_rtcp_packet_length_ = 0;
-
-  first_timestamp_ = std::numeric_limits<int64_t>::max();
-  last_timestamp_ = std::numeric_limits<int64_t>::min();
-
-  incoming_rtp_extensions_maps_.clear();
-  outgoing_rtp_extensions_maps_.clear();
-}
-
-bool ParsedRtcEventLog::ParseFile(const std::string& filename) {
-  std::ifstream file(  // no-presubmit-check TODO(webrtc:8982)
-      filename, std::ios_base::in | std::ios_base::binary);
-  if (!file.good() || !file.is_open()) {
-    RTC_LOG(LS_WARNING) << "Could not open file for reading.";
-    return false;
-  }
-
-  return ParseStream(file);
-}
-
-bool ParsedRtcEventLog::ParseString(const std::string& s) {
-  std::istringstream stream(  // no-presubmit-check TODO(webrtc:8982)
-      s, std::ios_base::in | std::ios_base::binary);
-  return ParseStream(stream);
-}
-
-bool ParsedRtcEventLog::ParseStream(
-    std::istream& stream) {  // no-presubmit-check TODO(webrtc:8982)
-  Clear();
-  const size_t kMaxEventSize = (1u << 16) - 1;
-  std::vector<char> tmp_buffer(kMaxEventSize);
-  uint64_t tag;
-  uint64_t message_length;
-  bool success;
-
-  RTC_DCHECK(stream.good());
-
-  while (1) {
-    // Check whether we have reached end of file.
-    stream.peek();
-    if (stream.eof()) {
-      break;
-    }
-
-    // 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;
-    std::tie(tag, success) = ParseVarInt(stream);
-    if (!success) {
-      RTC_LOG(LS_WARNING)
-          << "Missing field tag from beginning of protobuf event.";
-      return false;
-    } else if (tag != kExpectedTag) {
-      RTC_LOG(LS_WARNING)
-          << "Unexpected field tag at beginning of protobuf event.";
-      return false;
-    }
-
-    // Read the length field.
-    std::tie(message_length, success) = ParseVarInt(stream);
-    if (!success) {
-      RTC_LOG(LS_WARNING) << "Missing message length after protobuf field tag.";
-      return false;
-    } else if (message_length > kMaxEventSize) {
-      RTC_LOG(LS_WARNING) << "Protobuf message length is too large.";
-      return false;
-    }
-
-    // Read the next protobuf event to a temporary char buffer.
-    stream.read(tmp_buffer.data(), message_length);
-    if (stream.gcount() != static_cast<int>(message_length)) {
-      RTC_LOG(LS_WARNING) << "Failed to read protobuf message from file.";
-      return false;
-    }
-
-    // Parse the protobuf event from the buffer.
-    rtclog::Event event;
-    if (!event.ParseFromArray(tmp_buffer.data(), message_length)) {
-      RTC_LOG(LS_WARNING) << "Failed to parse protobuf message.";
-      return false;
-    }
-
-    StoreParsedEvent(event);
-
-    events_.push_back(event);
-  }
-
-  // Move packets_streams from map to vector.
-  incoming_rtp_packets_by_ssrc_.reserve(incoming_rtp_packets_map_.size());
-  for (const auto& kv : incoming_rtp_packets_map_) {
-    incoming_rtp_packets_by_ssrc_.emplace_back(LoggedRtpStreamIncoming());
-    incoming_rtp_packets_by_ssrc_.back().ssrc = kv.first;
-    incoming_rtp_packets_by_ssrc_.back().incoming_packets =
-        std::move(kv.second);
-  }
-  outgoing_rtp_packets_by_ssrc_.reserve(outgoing_rtp_packets_map_.size());
-  for (const auto& kv : outgoing_rtp_packets_map_) {
-    outgoing_rtp_packets_by_ssrc_.emplace_back(LoggedRtpStreamOutgoing());
-    outgoing_rtp_packets_by_ssrc_.back().ssrc = kv.first;
-    outgoing_rtp_packets_by_ssrc_.back().outgoing_packets =
-        std::move(kv.second);
-  }
-
-  // Build PacketViews for easier iteration over RTP packets
-  for (const auto& stream : incoming_rtp_packets_by_ssrc_) {
-    incoming_rtp_packet_views_by_ssrc_.emplace_back(
-        LoggedRtpStreamView(stream.ssrc, stream.incoming_packets.data(),
-                            stream.incoming_packets.size()));
-  }
-  for (const auto& stream : outgoing_rtp_packets_by_ssrc_) {
-    outgoing_rtp_packet_views_by_ssrc_.emplace_back(
-        LoggedRtpStreamView(stream.ssrc, stream.outgoing_packets.data(),
-                            stream.outgoing_packets.size()));
-  }
-
-  return true;
-}
-
-void ParsedRtcEventLog::StoreParsedEvent(const rtclog::Event& event) {
-  if (event.type() != rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT &&
-      event.type() != rtclog::Event::VIDEO_SENDER_CONFIG_EVENT &&
-      event.type() != rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT &&
-      event.type() != rtclog::Event::AUDIO_SENDER_CONFIG_EVENT &&
-      event.type() != rtclog::Event::LOG_START &&
-      event.type() != rtclog::Event::LOG_END) {
-    RTC_CHECK(event.has_timestamp_us());
-    int64_t timestamp = event.timestamp_us();
-    first_timestamp_ = std::min(first_timestamp_, timestamp);
-    last_timestamp_ = std::max(last_timestamp_, timestamp);
-  }
-
-  switch (event.type()) {
-    case rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT: {
-      rtclog::StreamConfig config = GetVideoReceiveConfig(event);
-      video_recv_configs_.emplace_back(GetTimestamp(event), config);
-      incoming_rtp_extensions_maps_[config.remote_ssrc] =
-          RtpHeaderExtensionMap(config.rtp_extensions);
-      // TODO(terelius): I don't understand the reason for configuring header
-      // extensions for the local SSRC. I think it should be removed, but for
-      // now I want to preserve the previous functionality.
-      incoming_rtp_extensions_maps_[config.local_ssrc] =
-          RtpHeaderExtensionMap(config.rtp_extensions);
-      incoming_video_ssrcs_.insert(config.remote_ssrc);
-      incoming_video_ssrcs_.insert(config.rtx_ssrc);
-      incoming_rtx_ssrcs_.insert(config.rtx_ssrc);
-      break;
-    }
-    case rtclog::Event::VIDEO_SENDER_CONFIG_EVENT: {
-      std::vector<rtclog::StreamConfig> configs = GetVideoSendConfig(event);
-      video_send_configs_.emplace_back(GetTimestamp(event), configs);
-      for (const auto& config : configs) {
-        outgoing_rtp_extensions_maps_[config.local_ssrc] =
-            RtpHeaderExtensionMap(config.rtp_extensions);
-        outgoing_rtp_extensions_maps_[config.rtx_ssrc] =
-            RtpHeaderExtensionMap(config.rtp_extensions);
-        outgoing_video_ssrcs_.insert(config.local_ssrc);
-        outgoing_video_ssrcs_.insert(config.rtx_ssrc);
-        outgoing_rtx_ssrcs_.insert(config.rtx_ssrc);
-      }
-      break;
-    }
-    case rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT: {
-      rtclog::StreamConfig config = GetAudioReceiveConfig(event);
-      audio_recv_configs_.emplace_back(GetTimestamp(event), config);
-      incoming_rtp_extensions_maps_[config.remote_ssrc] =
-          RtpHeaderExtensionMap(config.rtp_extensions);
-      incoming_rtp_extensions_maps_[config.local_ssrc] =
-          RtpHeaderExtensionMap(config.rtp_extensions);
-      incoming_audio_ssrcs_.insert(config.remote_ssrc);
-      break;
-    }
-    case rtclog::Event::AUDIO_SENDER_CONFIG_EVENT: {
-      rtclog::StreamConfig config = GetAudioSendConfig(event);
-      audio_send_configs_.emplace_back(GetTimestamp(event), config);
-      outgoing_rtp_extensions_maps_[config.local_ssrc] =
-          RtpHeaderExtensionMap(config.rtp_extensions);
-      outgoing_audio_ssrcs_.insert(config.local_ssrc);
-      break;
-    }
-    case rtclog::Event::RTP_EVENT: {
-      PacketDirection direction;
-      uint8_t header[IP_PACKET_SIZE];
-      size_t header_length;
-      size_t total_length;
-      const RtpHeaderExtensionMap* extension_map = GetRtpHeader(
-          event, &direction, header, &header_length, &total_length, nullptr);
-      RtpUtility::RtpHeaderParser rtp_parser(header, header_length);
-      RTPHeader parsed_header;
-      if (extension_map != nullptr) {
-        rtp_parser.Parse(&parsed_header, extension_map);
-      } else {
-        // Use the default extension map.
-        // TODO(ivoc): Once configuration of audio streams is stored in the
-        //             event log, this can be removed.
-        //             Tracking bug: webrtc:6399
-        rtp_parser.Parse(&parsed_header, &default_extension_map_);
-      }
-      RTC_CHECK(event.has_timestamp_us());
-      uint64_t timestamp_us = event.timestamp_us();
-      if (direction == kIncomingPacket) {
-        incoming_rtp_packets_map_[parsed_header.ssrc].push_back(
-            LoggedRtpPacketIncoming(timestamp_us, parsed_header, header_length,
-                                    total_length));
-      } else {
-        outgoing_rtp_packets_map_[parsed_header.ssrc].push_back(
-            LoggedRtpPacketOutgoing(timestamp_us, parsed_header, header_length,
-                                    total_length));
-      }
-      break;
-    }
-    case rtclog::Event::RTCP_EVENT: {
-      PacketDirection direction;
-      uint8_t packet[IP_PACKET_SIZE];
-      size_t total_length;
-      GetRtcpPacket(event, &direction, packet, &total_length);
-      uint64_t timestamp_us = GetTimestamp(event);
-      RTC_CHECK_LE(total_length, IP_PACKET_SIZE);
-      if (direction == kIncomingPacket) {
-        // Currently incoming RTCP packets are logged twice, both for audio and
-        // video. Only act on one of them. Compare against the previous parsed
-        // incoming RTCP packet.
-        if (total_length == last_incoming_rtcp_packet_length_ &&
-            memcmp(last_incoming_rtcp_packet_, packet, total_length) == 0)
-          break;
-        incoming_rtcp_packets_.push_back(
-            LoggedRtcpPacketIncoming(timestamp_us, packet, total_length));
-        last_incoming_rtcp_packet_length_ = total_length;
-        memcpy(last_incoming_rtcp_packet_, packet, total_length);
-      } else {
-        outgoing_rtcp_packets_.push_back(
-            LoggedRtcpPacketOutgoing(timestamp_us, packet, total_length));
-      }
-      rtcp::CommonHeader header;
-      const uint8_t* packet_end = packet + total_length;
-      for (const uint8_t* block = packet; block < packet_end;
-           block = header.NextPacket()) {
-        RTC_CHECK(header.Parse(block, packet_end - block));
-        if (header.type() == rtcp::TransportFeedback::kPacketType &&
-            header.fmt() == rtcp::TransportFeedback::kFeedbackMessageType) {
-          if (direction == kIncomingPacket) {
-            incoming_transport_feedback_.emplace_back();
-            LoggedRtcpPacketTransportFeedback& parsed_block =
-                incoming_transport_feedback_.back();
-            parsed_block.timestamp_us = GetTimestamp(event);
-            if (!parsed_block.transport_feedback.Parse(header))
-              incoming_transport_feedback_.pop_back();
-          } else {
-            outgoing_transport_feedback_.emplace_back();
-            LoggedRtcpPacketTransportFeedback& parsed_block =
-                outgoing_transport_feedback_.back();
-            parsed_block.timestamp_us = GetTimestamp(event);
-            if (!parsed_block.transport_feedback.Parse(header))
-              outgoing_transport_feedback_.pop_back();
-          }
-        } else if (header.type() == rtcp::SenderReport::kPacketType) {
-          LoggedRtcpPacketSenderReport parsed_block;
-          parsed_block.timestamp_us = GetTimestamp(event);
-          if (parsed_block.sr.Parse(header)) {
-            if (direction == kIncomingPacket)
-              incoming_sr_.push_back(std::move(parsed_block));
-            else
-              outgoing_sr_.push_back(std::move(parsed_block));
-          }
-        } else if (header.type() == rtcp::ReceiverReport::kPacketType) {
-          LoggedRtcpPacketReceiverReport parsed_block;
-          parsed_block.timestamp_us = GetTimestamp(event);
-          if (parsed_block.rr.Parse(header)) {
-            if (direction == kIncomingPacket)
-              incoming_rr_.push_back(std::move(parsed_block));
-            else
-              outgoing_rr_.push_back(std::move(parsed_block));
-          }
-        } else if (header.type() == rtcp::Remb::kPacketType &&
-                   header.fmt() == rtcp::Remb::kFeedbackMessageType) {
-          LoggedRtcpPacketRemb parsed_block;
-          parsed_block.timestamp_us = GetTimestamp(event);
-          if (parsed_block.remb.Parse(header)) {
-            if (direction == kIncomingPacket)
-              incoming_remb_.push_back(std::move(parsed_block));
-            else
-              outgoing_remb_.push_back(std::move(parsed_block));
-          }
-        } else if (header.type() == rtcp::Nack::kPacketType &&
-                   header.fmt() == rtcp::Nack::kFeedbackMessageType) {
-          LoggedRtcpPacketNack parsed_block;
-          parsed_block.timestamp_us = GetTimestamp(event);
-          if (parsed_block.nack.Parse(header)) {
-            if (direction == kIncomingPacket)
-              incoming_nack_.push_back(std::move(parsed_block));
-            else
-              outgoing_nack_.push_back(std::move(parsed_block));
-          }
-        }
-      }
-      break;
-    }
-    case ParsedRtcEventLog::LOG_START: {
-      start_log_events_.push_back(LoggedStartEvent(GetTimestamp(event)));
-      break;
-    }
-    case ParsedRtcEventLog::LOG_END: {
-      stop_log_events_.push_back(LoggedStopEvent(GetTimestamp(event)));
-      break;
-    }
-    case ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT: {
-      LoggedAudioPlayoutEvent playout_event = GetAudioPlayout(event);
-      audio_playout_events_[playout_event.ssrc].push_back(
-          playout_event.timestamp_us);
-      break;
-    }
-    case ParsedRtcEventLog::LOSS_BASED_BWE_UPDATE: {
-      bwe_loss_updates_.push_back(GetLossBasedBweUpdate(event));
-      break;
-    }
-    case ParsedRtcEventLog::DELAY_BASED_BWE_UPDATE: {
-      bwe_delay_updates_.push_back(GetDelayBasedBweUpdate(event));
-      break;
-    }
-    case ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT: {
-      LoggedAudioNetworkAdaptationEvent ana_event =
-          GetAudioNetworkAdaptation(event);
-      audio_network_adaptation_events_.push_back(ana_event);
-      break;
-    }
-    case ParsedRtcEventLog::BWE_PROBE_CLUSTER_CREATED_EVENT: {
-      bwe_probe_cluster_created_events_.push_back(
-          GetBweProbeClusterCreated(event));
-      break;
-    }
-    case ParsedRtcEventLog::BWE_PROBE_RESULT_EVENT: {
-      bwe_probe_result_events_.push_back(GetBweProbeResult(event));
-      break;
-    }
-    case ParsedRtcEventLog::ALR_STATE_EVENT: {
-      alr_state_events_.push_back(GetAlrState(event));
-      break;
-    }
-    case ParsedRtcEventLog::ICE_CANDIDATE_PAIR_CONFIG: {
-      ice_candidate_pair_configs_.push_back(GetIceCandidatePairConfig(event));
-      break;
-    }
-    case ParsedRtcEventLog::ICE_CANDIDATE_PAIR_EVENT: {
-      ice_candidate_pair_events_.push_back(GetIceCandidatePairEvent(event));
-      break;
-    }
-    case ParsedRtcEventLog::UNKNOWN_EVENT: {
-      break;
-    }
-  }
-}
-
-size_t ParsedRtcEventLog::GetNumberOfEvents() const {
-  return events_.size();
-}
-
-int64_t ParsedRtcEventLog::GetTimestamp(size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& event = events_[index];
-  return GetTimestamp(event);
-}
-
-int64_t ParsedRtcEventLog::GetTimestamp(const rtclog::Event& event) const {
-  RTC_CHECK(event.has_timestamp_us());
-  return event.timestamp_us();
-}
-
-ParsedRtcEventLog::EventType ParsedRtcEventLog::GetEventType(
-    size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& event = events_[index];
-  RTC_CHECK(event.has_type());
-  return GetRuntimeEventType(event.type());
-}
-
-// The header must have space for at least IP_PACKET_SIZE bytes.
-const webrtc::RtpHeaderExtensionMap* ParsedRtcEventLog::GetRtpHeader(
-    size_t index,
-    PacketDirection* incoming,
-    uint8_t* header,
-    size_t* header_length,
-    size_t* total_length,
-    int* probe_cluster_id) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& event = events_[index];
-  return GetRtpHeader(event, incoming, header, header_length, total_length,
-                      probe_cluster_id);
-}
-
-const webrtc::RtpHeaderExtensionMap* ParsedRtcEventLog::GetRtpHeader(
-    const rtclog::Event& event,
-    PacketDirection* incoming,
-    uint8_t* header,
-    size_t* header_length,
-    size_t* total_length,
-    int* probe_cluster_id) const {
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::RTP_EVENT);
-  RTC_CHECK(event.has_rtp_packet());
-  const rtclog::RtpPacket& rtp_packet = event.rtp_packet();
-  // Get direction of packet.
-  RTC_CHECK(rtp_packet.has_incoming());
-  if (incoming != nullptr) {
-    *incoming = rtp_packet.incoming() ? kIncomingPacket : kOutgoingPacket;
-  }
-  // Get packet length.
-  RTC_CHECK(rtp_packet.has_packet_length());
-  if (total_length != nullptr) {
-    *total_length = rtp_packet.packet_length();
-  }
-  // Get header length.
-  RTC_CHECK(rtp_packet.has_header());
-  if (header_length != nullptr) {
-    *header_length = rtp_packet.header().size();
-  }
-  if (probe_cluster_id != nullptr) {
-    if (rtp_packet.has_probe_cluster_id()) {
-      *probe_cluster_id = rtp_packet.probe_cluster_id();
-      RTC_CHECK_NE(*probe_cluster_id, PacedPacketInfo::kNotAProbe);
-    } else {
-      *probe_cluster_id = PacedPacketInfo::kNotAProbe;
-    }
-  }
-  // Get header contents.
-  if (header != nullptr) {
-    const size_t kMinRtpHeaderSize = 12;
-    RTC_CHECK_GE(rtp_packet.header().size(), kMinRtpHeaderSize);
-    RTC_CHECK_LE(rtp_packet.header().size(),
-                 static_cast<size_t>(IP_PACKET_SIZE));
-    memcpy(header, rtp_packet.header().data(), rtp_packet.header().size());
-    uint32_t ssrc = ByteReader<uint32_t>::ReadBigEndian(header + 8);
-    auto& extensions_maps = rtp_packet.incoming()
-                                ? incoming_rtp_extensions_maps_
-                                : outgoing_rtp_extensions_maps_;
-    auto it = extensions_maps.find(ssrc);
-    if (it != extensions_maps.end()) {
-      return &(it->second);
-    }
-    if (parse_unconfigured_header_extensions_ ==
-        UnconfiguredHeaderExtensions::kAttemptWebrtcDefaultConfig) {
-      RTC_LOG(LS_WARNING) << "Using default header extension map for SSRC "
-                          << ssrc;
-      extensions_maps.insert(std::make_pair(ssrc, default_extension_map_));
-      return &default_extension_map_;
-    }
-  }
-  return nullptr;
-}
-
-// The packet must have space for at least IP_PACKET_SIZE bytes.
-void ParsedRtcEventLog::GetRtcpPacket(size_t index,
-                                      PacketDirection* incoming,
-                                      uint8_t* packet,
-                                      size_t* length) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& event = events_[index];
-  GetRtcpPacket(event, incoming, packet, length);
-}
-
-void ParsedRtcEventLog::GetRtcpPacket(const rtclog::Event& event,
-                                      PacketDirection* incoming,
-                                      uint8_t* packet,
-                                      size_t* length) const {
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::RTCP_EVENT);
-  RTC_CHECK(event.has_rtcp_packet());
-  const rtclog::RtcpPacket& rtcp_packet = event.rtcp_packet();
-  // Get direction of packet.
-  RTC_CHECK(rtcp_packet.has_incoming());
-  if (incoming != nullptr) {
-    *incoming = rtcp_packet.incoming() ? kIncomingPacket : kOutgoingPacket;
-  }
-  // Get packet length.
-  RTC_CHECK(rtcp_packet.has_packet_data());
-  if (length != nullptr) {
-    *length = rtcp_packet.packet_data().size();
-  }
-  // Get packet contents.
-  if (packet != nullptr) {
-    RTC_CHECK_LE(rtcp_packet.packet_data().size(),
-                 static_cast<unsigned>(IP_PACKET_SIZE));
-    memcpy(packet, rtcp_packet.packet_data().data(),
-           rtcp_packet.packet_data().size());
-  }
-}
-
-rtclog::StreamConfig ParsedRtcEventLog::GetVideoReceiveConfig(
-    size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  return GetVideoReceiveConfig(events_[index]);
-}
-
-rtclog::StreamConfig ParsedRtcEventLog::GetVideoReceiveConfig(
-    const rtclog::Event& event) const {
-  rtclog::StreamConfig config;
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT);
-  RTC_CHECK(event.has_video_receiver_config());
-  const rtclog::VideoReceiveConfig& receiver_config =
-      event.video_receiver_config();
-  // Get SSRCs.
-  RTC_CHECK(receiver_config.has_remote_ssrc());
-  config.remote_ssrc = receiver_config.remote_ssrc();
-  RTC_CHECK(receiver_config.has_local_ssrc());
-  config.local_ssrc = receiver_config.local_ssrc();
-  config.rtx_ssrc = 0;
-  // Get RTCP settings.
-  RTC_CHECK(receiver_config.has_rtcp_mode());
-  config.rtcp_mode = GetRuntimeRtcpMode(receiver_config.rtcp_mode());
-  RTC_CHECK(receiver_config.has_remb());
-  config.remb = receiver_config.remb();
-
-  // Get RTX map.
-  std::map<uint32_t, const rtclog::RtxConfig> rtx_map;
-  for (int i = 0; i < receiver_config.rtx_map_size(); i++) {
-    const rtclog::RtxMap& map = receiver_config.rtx_map(i);
-    RTC_CHECK(map.has_payload_type());
-    RTC_CHECK(map.has_config());
-    RTC_CHECK(map.config().has_rtx_ssrc());
-    RTC_CHECK(map.config().has_rtx_payload_type());
-    rtx_map.insert(std::make_pair(map.payload_type(), map.config()));
-  }
-
-  // Get header extensions.
-  GetHeaderExtensions(&config.rtp_extensions,
-                      receiver_config.header_extensions());
-  // Get decoders.
-  config.codecs.clear();
-  for (int i = 0; i < receiver_config.decoders_size(); i++) {
-    RTC_CHECK(receiver_config.decoders(i).has_name());
-    RTC_CHECK(receiver_config.decoders(i).has_payload_type());
-    int rtx_payload_type = 0;
-    auto rtx_it = rtx_map.find(receiver_config.decoders(i).payload_type());
-    if (rtx_it != rtx_map.end()) {
-      rtx_payload_type = rtx_it->second.rtx_payload_type();
-      if (config.rtx_ssrc != 0 &&
-          config.rtx_ssrc != rtx_it->second.rtx_ssrc()) {
-        RTC_LOG(LS_WARNING)
-            << "RtcEventLog protobuf contained different SSRCs for "
-               "different received RTX payload types. Will only use "
-               "rtx_ssrc = "
-            << config.rtx_ssrc << ".";
-      } else {
-        config.rtx_ssrc = rtx_it->second.rtx_ssrc();
-      }
-    }
-    config.codecs.emplace_back(receiver_config.decoders(i).name(),
-                               receiver_config.decoders(i).payload_type(),
-                               rtx_payload_type);
-  }
-  return config;
-}
-
-std::vector<rtclog::StreamConfig> ParsedRtcEventLog::GetVideoSendConfig(
-    size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  return GetVideoSendConfig(events_[index]);
-}
-
-std::vector<rtclog::StreamConfig> ParsedRtcEventLog::GetVideoSendConfig(
-    const rtclog::Event& event) const {
-  std::vector<rtclog::StreamConfig> configs;
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::VIDEO_SENDER_CONFIG_EVENT);
-  RTC_CHECK(event.has_video_sender_config());
-  const rtclog::VideoSendConfig& sender_config = event.video_sender_config();
-  if (sender_config.rtx_ssrcs_size() > 0 &&
-      sender_config.ssrcs_size() != sender_config.rtx_ssrcs_size()) {
-    RTC_LOG(WARNING)
-        << "VideoSendConfig is configured for RTX but the number of "
-           "SSRCs doesn't match the number of RTX SSRCs.";
-  }
-  configs.resize(sender_config.ssrcs_size());
-  for (int i = 0; i < sender_config.ssrcs_size(); i++) {
-    // Get SSRCs.
-    configs[i].local_ssrc = sender_config.ssrcs(i);
-    if (sender_config.rtx_ssrcs_size() > 0 &&
-        i < sender_config.rtx_ssrcs_size()) {
-      RTC_CHECK(sender_config.has_rtx_payload_type());
-      configs[i].rtx_ssrc = sender_config.rtx_ssrcs(i);
-    }
-    // Get header extensions.
-    GetHeaderExtensions(&configs[i].rtp_extensions,
-                        sender_config.header_extensions());
-
-    // Get the codec.
-    RTC_CHECK(sender_config.has_encoder());
-    RTC_CHECK(sender_config.encoder().has_name());
-    RTC_CHECK(sender_config.encoder().has_payload_type());
-    configs[i].codecs.emplace_back(
-        sender_config.encoder().name(), sender_config.encoder().payload_type(),
-        sender_config.has_rtx_payload_type() ? sender_config.rtx_payload_type()
-                                             : 0);
-  }
-  return configs;
-}
-
-rtclog::StreamConfig ParsedRtcEventLog::GetAudioReceiveConfig(
-    size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  return GetAudioReceiveConfig(events_[index]);
-}
-
-rtclog::StreamConfig ParsedRtcEventLog::GetAudioReceiveConfig(
-    const rtclog::Event& event) const {
-  rtclog::StreamConfig config;
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT);
-  RTC_CHECK(event.has_audio_receiver_config());
-  const rtclog::AudioReceiveConfig& receiver_config =
-      event.audio_receiver_config();
-  // Get SSRCs.
-  RTC_CHECK(receiver_config.has_remote_ssrc());
-  config.remote_ssrc = receiver_config.remote_ssrc();
-  RTC_CHECK(receiver_config.has_local_ssrc());
-  config.local_ssrc = receiver_config.local_ssrc();
-  // Get header extensions.
-  GetHeaderExtensions(&config.rtp_extensions,
-                      receiver_config.header_extensions());
-  return config;
-}
-
-rtclog::StreamConfig ParsedRtcEventLog::GetAudioSendConfig(size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  return GetAudioSendConfig(events_[index]);
-}
-
-rtclog::StreamConfig ParsedRtcEventLog::GetAudioSendConfig(
-    const rtclog::Event& event) const {
-  rtclog::StreamConfig config;
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_SENDER_CONFIG_EVENT);
-  RTC_CHECK(event.has_audio_sender_config());
-  const rtclog::AudioSendConfig& sender_config = event.audio_sender_config();
-  // Get SSRCs.
-  RTC_CHECK(sender_config.has_ssrc());
-  config.local_ssrc = sender_config.ssrc();
-  // Get header extensions.
-  GetHeaderExtensions(&config.rtp_extensions,
-                      sender_config.header_extensions());
-  return config;
-}
-
-LoggedAudioPlayoutEvent ParsedRtcEventLog::GetAudioPlayout(size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& event = events_[index];
-  return GetAudioPlayout(event);
-}
-
-LoggedAudioPlayoutEvent ParsedRtcEventLog::GetAudioPlayout(
-    const rtclog::Event& event) const {
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_PLAYOUT_EVENT);
-  RTC_CHECK(event.has_audio_playout_event());
-  const rtclog::AudioPlayoutEvent& playout_event = event.audio_playout_event();
-  LoggedAudioPlayoutEvent res;
-  res.timestamp_us = GetTimestamp(event);
-  RTC_CHECK(playout_event.has_local_ssrc());
-  res.ssrc = playout_event.local_ssrc();
-  return res;
-}
-
-LoggedBweLossBasedUpdate ParsedRtcEventLog::GetLossBasedBweUpdate(
-    size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& event = events_[index];
-  return GetLossBasedBweUpdate(event);
-}
-
-LoggedBweLossBasedUpdate ParsedRtcEventLog::GetLossBasedBweUpdate(
-    const rtclog::Event& event) const {
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::LOSS_BASED_BWE_UPDATE);
-  RTC_CHECK(event.has_loss_based_bwe_update());
-  const rtclog::LossBasedBweUpdate& loss_event = event.loss_based_bwe_update();
-
-  LoggedBweLossBasedUpdate bwe_update;
-  bwe_update.timestamp_us = GetTimestamp(event);
-  RTC_CHECK(loss_event.has_bitrate_bps());
-  bwe_update.bitrate_bps = loss_event.bitrate_bps();
-  RTC_CHECK(loss_event.has_fraction_loss());
-  bwe_update.fraction_lost = loss_event.fraction_loss();
-  RTC_CHECK(loss_event.has_total_packets());
-  bwe_update.expected_packets = loss_event.total_packets();
-  return bwe_update;
-}
-
-LoggedBweDelayBasedUpdate ParsedRtcEventLog::GetDelayBasedBweUpdate(
-    size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& event = events_[index];
-  return GetDelayBasedBweUpdate(event);
-}
-
-LoggedBweDelayBasedUpdate ParsedRtcEventLog::GetDelayBasedBweUpdate(
-    const rtclog::Event& event) const {
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::DELAY_BASED_BWE_UPDATE);
-  RTC_CHECK(event.has_delay_based_bwe_update());
-  const rtclog::DelayBasedBweUpdate& delay_event =
-      event.delay_based_bwe_update();
-
-  LoggedBweDelayBasedUpdate res;
-  res.timestamp_us = GetTimestamp(event);
-  RTC_CHECK(delay_event.has_bitrate_bps());
-  res.bitrate_bps = delay_event.bitrate_bps();
-  RTC_CHECK(delay_event.has_detector_state());
-  res.detector_state = GetRuntimeDetectorState(delay_event.detector_state());
-  return res;
-}
-
-LoggedAudioNetworkAdaptationEvent ParsedRtcEventLog::GetAudioNetworkAdaptation(
-    size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& event = events_[index];
-  return GetAudioNetworkAdaptation(event);
-}
-
-LoggedAudioNetworkAdaptationEvent ParsedRtcEventLog::GetAudioNetworkAdaptation(
-    const rtclog::Event& event) const {
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT);
-  RTC_CHECK(event.has_audio_network_adaptation());
-  const rtclog::AudioNetworkAdaptation& ana_event =
-      event.audio_network_adaptation();
-
-  LoggedAudioNetworkAdaptationEvent res;
-  res.timestamp_us = GetTimestamp(event);
-  if (ana_event.has_bitrate_bps())
-    res.config.bitrate_bps = ana_event.bitrate_bps();
-  if (ana_event.has_enable_fec())
-    res.config.enable_fec = ana_event.enable_fec();
-  if (ana_event.has_enable_dtx())
-    res.config.enable_dtx = ana_event.enable_dtx();
-  if (ana_event.has_frame_length_ms())
-    res.config.frame_length_ms = ana_event.frame_length_ms();
-  if (ana_event.has_num_channels())
-    res.config.num_channels = ana_event.num_channels();
-  if (ana_event.has_uplink_packet_loss_fraction())
-    res.config.uplink_packet_loss_fraction =
-        ana_event.uplink_packet_loss_fraction();
-  return res;
-}
-
-LoggedBweProbeClusterCreatedEvent ParsedRtcEventLog::GetBweProbeClusterCreated(
-    size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& event = events_[index];
-  return GetBweProbeClusterCreated(event);
-}
-
-LoggedBweProbeClusterCreatedEvent ParsedRtcEventLog::GetBweProbeClusterCreated(
-    const rtclog::Event& event) const {
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT);
-  RTC_CHECK(event.has_probe_cluster());
-  const rtclog::BweProbeCluster& pcc_event = event.probe_cluster();
-  LoggedBweProbeClusterCreatedEvent res;
-  res.timestamp_us = GetTimestamp(event);
-  RTC_CHECK(pcc_event.has_id());
-  res.id = pcc_event.id();
-  RTC_CHECK(pcc_event.has_bitrate_bps());
-  res.bitrate_bps = pcc_event.bitrate_bps();
-  RTC_CHECK(pcc_event.has_min_packets());
-  res.min_packets = pcc_event.min_packets();
-  RTC_CHECK(pcc_event.has_min_bytes());
-  res.min_bytes = pcc_event.min_bytes();
-  return res;
-}
-
-LoggedBweProbeResultEvent ParsedRtcEventLog::GetBweProbeResult(
-    size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& event = events_[index];
-  return GetBweProbeResult(event);
-}
-
-LoggedBweProbeResultEvent ParsedRtcEventLog::GetBweProbeResult(
-    const rtclog::Event& event) const {
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::BWE_PROBE_RESULT_EVENT);
-  RTC_CHECK(event.has_probe_result());
-  const rtclog::BweProbeResult& pr_event = event.probe_result();
-  LoggedBweProbeResultEvent res;
-  res.timestamp_us = GetTimestamp(event);
-  RTC_CHECK(pr_event.has_id());
-  res.id = pr_event.id();
-
-  RTC_CHECK(pr_event.has_result());
-  if (pr_event.result() == rtclog::BweProbeResult::SUCCESS) {
-    RTC_CHECK(pr_event.has_bitrate_bps());
-    res.bitrate_bps = pr_event.bitrate_bps();
-  } else if (pr_event.result() ==
-             rtclog::BweProbeResult::INVALID_SEND_RECEIVE_INTERVAL) {
-    res.failure_reason = ProbeFailureReason::kInvalidSendReceiveInterval;
-  } else if (pr_event.result() ==
-             rtclog::BweProbeResult::INVALID_SEND_RECEIVE_RATIO) {
-    res.failure_reason = ProbeFailureReason::kInvalidSendReceiveRatio;
-  } else if (pr_event.result() == rtclog::BweProbeResult::TIMEOUT) {
-    res.failure_reason = ProbeFailureReason::kTimeout;
-  } else {
-    RTC_NOTREACHED();
-  }
-
-  return res;
-}
-
-LoggedAlrStateEvent ParsedRtcEventLog::GetAlrState(size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& event = events_[index];
-  return GetAlrState(event);
-}
-
-LoggedAlrStateEvent ParsedRtcEventLog::GetAlrState(
-    const rtclog::Event& event) const {
-  RTC_CHECK(event.has_type());
-  RTC_CHECK_EQ(event.type(), rtclog::Event::ALR_STATE_EVENT);
-  RTC_CHECK(event.has_alr_state());
-  const rtclog::AlrState& alr_event = event.alr_state();
-  LoggedAlrStateEvent res;
-  res.timestamp_us = GetTimestamp(event);
-  RTC_CHECK(alr_event.has_in_alr());
-  res.in_alr = alr_event.in_alr();
-
-  return res;
-}
-
-LoggedIceCandidatePairConfig ParsedRtcEventLog::GetIceCandidatePairConfig(
-    size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& rtc_event = events_[index];
-  return GetIceCandidatePairConfig(rtc_event);
-}
-
-LoggedIceCandidatePairConfig ParsedRtcEventLog::GetIceCandidatePairConfig(
-    const rtclog::Event& rtc_event) const {
-  RTC_CHECK(rtc_event.has_type());
-  RTC_CHECK_EQ(rtc_event.type(), rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG);
-  LoggedIceCandidatePairConfig res;
-  const rtclog::IceCandidatePairConfig& config =
-      rtc_event.ice_candidate_pair_config();
-  res.timestamp_us = GetTimestamp(rtc_event);
-  RTC_CHECK(config.has_config_type());
-  res.type = GetRuntimeIceCandidatePairConfigType(config.config_type());
-  RTC_CHECK(config.has_candidate_pair_id());
-  res.candidate_pair_id = config.candidate_pair_id();
-  RTC_CHECK(config.has_local_candidate_type());
-  res.local_candidate_type =
-      GetRuntimeIceCandidateType(config.local_candidate_type());
-  RTC_CHECK(config.has_local_relay_protocol());
-  res.local_relay_protocol =
-      GetRuntimeIceCandidatePairProtocol(config.local_relay_protocol());
-  RTC_CHECK(config.has_local_network_type());
-  res.local_network_type =
-      GetRuntimeIceCandidateNetworkType(config.local_network_type());
-  RTC_CHECK(config.has_local_address_family());
-  res.local_address_family =
-      GetRuntimeIceCandidatePairAddressFamily(config.local_address_family());
-  RTC_CHECK(config.has_remote_candidate_type());
-  res.remote_candidate_type =
-      GetRuntimeIceCandidateType(config.remote_candidate_type());
-  RTC_CHECK(config.has_remote_address_family());
-  res.remote_address_family =
-      GetRuntimeIceCandidatePairAddressFamily(config.remote_address_family());
-  RTC_CHECK(config.has_candidate_pair_protocol());
-  res.candidate_pair_protocol =
-      GetRuntimeIceCandidatePairProtocol(config.candidate_pair_protocol());
-  return res;
-}
-
-LoggedIceCandidatePairEvent ParsedRtcEventLog::GetIceCandidatePairEvent(
-    size_t index) const {
-  RTC_CHECK_LT(index, GetNumberOfEvents());
-  const rtclog::Event& rtc_event = events_[index];
-  return GetIceCandidatePairEvent(rtc_event);
-}
-
-LoggedIceCandidatePairEvent ParsedRtcEventLog::GetIceCandidatePairEvent(
-    const rtclog::Event& rtc_event) const {
-  RTC_CHECK(rtc_event.has_type());
-  RTC_CHECK_EQ(rtc_event.type(), rtclog::Event::ICE_CANDIDATE_PAIR_EVENT);
-  LoggedIceCandidatePairEvent res;
-  const rtclog::IceCandidatePairEvent& event =
-      rtc_event.ice_candidate_pair_event();
-  res.timestamp_us = GetTimestamp(rtc_event);
-  RTC_CHECK(event.has_event_type());
-  res.type = GetRuntimeIceCandidatePairEventType(event.event_type());
-  RTC_CHECK(event.has_candidate_pair_id());
-  res.candidate_pair_id = event.candidate_pair_id();
-  return res;
-}
-
-// Returns the MediaType for registered SSRCs. Search from the end to use last
-// registered types first.
-ParsedRtcEventLog::MediaType ParsedRtcEventLog::GetMediaType(
-    uint32_t ssrc,
-    PacketDirection direction) const {
-  if (direction == kIncomingPacket) {
-    if (std::find(incoming_video_ssrcs_.begin(), incoming_video_ssrcs_.end(),
-                  ssrc) != incoming_video_ssrcs_.end()) {
-      return MediaType::VIDEO;
-    }
-    if (std::find(incoming_audio_ssrcs_.begin(), incoming_audio_ssrcs_.end(),
-                  ssrc) != incoming_audio_ssrcs_.end()) {
-      return MediaType::AUDIO;
-    }
-  } else {
-    if (std::find(outgoing_video_ssrcs_.begin(), outgoing_video_ssrcs_.end(),
-                  ssrc) != outgoing_video_ssrcs_.end()) {
-      return MediaType::VIDEO;
-    }
-    if (std::find(outgoing_audio_ssrcs_.begin(), outgoing_audio_ssrcs_.end(),
-                  ssrc) != outgoing_audio_ssrcs_.end()) {
-      return MediaType::AUDIO;
-    }
-  }
-  return MediaType::ANY;
-}
-
-}  // namespace webrtc
diff --git a/logging/rtc_event_log/rtc_event_log_parser2.h b/logging/rtc_event_log/rtc_event_log_parser2.h
deleted file mode 100644
index dfc607d..0000000
--- a/logging/rtc_event_log/rtc_event_log_parser2.h
+++ /dev/null
@@ -1,920 +0,0 @@
-/*
- *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-#ifndef LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_PARSER2_H_
-#define LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_PARSER2_H_
-
-#include <iterator>
-#include <map>
-#include <set>
-#include <string>
-#include <utility>  // pair
-#include <vector>
-
-#include "call/video_receive_stream.h"
-#include "call/video_send_stream.h"
-#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h"
-#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h"
-#include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h"
-#include "logging/rtc_event_log/rtc_event_log.h"
-#include "logging/rtc_event_log/rtc_stream_config.h"
-#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
-#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
-#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
-#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
-#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
-#include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
-#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
-#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
-#include "rtc_base/ignore_wundef.h"
-
-// Files generated at build-time by the protobuf compiler.
-RTC_PUSH_IGNORING_WUNDEF()
-#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
-#include "external/webrtc/webrtc/logging/rtc_event_log/rtc_event_log.pb.h"
-#else
-#include "logging/rtc_event_log/rtc_event_log.pb.h"
-#endif
-RTC_POP_IGNORING_WUNDEF()
-
-namespace webrtc {
-
-enum class BandwidthUsage;
-struct AudioEncoderRuntimeConfig;
-
-struct LoggedAlrStateEvent {
-  int64_t timestamp_us;
-  bool in_alr;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedAudioPlayoutEvent {
-  int64_t timestamp_us;
-  uint32_t ssrc;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedAudioNetworkAdaptationEvent {
-  int64_t timestamp_us;
-  AudioEncoderRuntimeConfig config;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedBweDelayBasedUpdate {
-  int64_t timestamp_us;
-  int32_t bitrate_bps;
-  BandwidthUsage detector_state;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedBweLossBasedUpdate {
-  int64_t timestamp_us;
-  int32_t bitrate_bps;
-  uint8_t fraction_lost;
-  int32_t expected_packets;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedBweProbeClusterCreatedEvent {
-  int64_t timestamp_us;
-  uint32_t id;
-  uint64_t bitrate_bps;
-  uint32_t min_packets;
-  uint32_t min_bytes;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedBweProbeResultEvent {
-  int64_t timestamp_us;
-  uint32_t id;
-  rtc::Optional<uint64_t> bitrate_bps;
-  rtc::Optional<ProbeFailureReason> failure_reason;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedIceCandidatePairConfig {
-  int64_t timestamp_us;
-  IceCandidatePairEventType type;
-  uint32_t candidate_pair_id;
-  IceCandidateType local_candidate_type;
-  IceCandidatePairProtocol local_relay_protocol;
-  IceCandidateNetworkType local_network_type;
-  IceCandidatePairAddressFamily local_address_family;
-  IceCandidateType remote_candidate_type;
-  IceCandidatePairAddressFamily remote_address_family;
-  IceCandidatePairProtocol candidate_pair_protocol;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedIceCandidatePairEvent {
-  int64_t timestamp_us;
-  IceCandidatePairEventType type;
-  uint32_t candidate_pair_id;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedRtpPacket {
-  LoggedRtpPacket(uint64_t timestamp_us,
-                  RTPHeader header,
-                  size_t header_length,
-                  size_t total_length)
-      : timestamp_us(timestamp_us),
-        header(header),
-        header_length(header_length),
-        total_length(total_length) {}
-  int64_t timestamp_us;
-  // TODO(terelius): This allocates space for 15 CSRCs even if none are used.
-  RTPHeader header;
-  size_t header_length;
-  size_t total_length;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedRtpPacketIncoming {
-  LoggedRtpPacketIncoming(uint64_t timestamp_us,
-                          RTPHeader header,
-                          size_t header_length,
-                          size_t total_length)
-      : rtp(timestamp_us, header, header_length, total_length) {}
-  LoggedRtpPacket rtp;
-  int64_t log_time_us() const { return rtp.timestamp_us; }
-  int64_t log_time_ms() const { return rtp.timestamp_us / 1000; }
-};
-
-struct LoggedRtpPacketOutgoing {
-  LoggedRtpPacketOutgoing(uint64_t timestamp_us,
-                          RTPHeader header,
-                          size_t header_length,
-                          size_t total_length)
-      : rtp(timestamp_us, header, header_length, total_length) {}
-  LoggedRtpPacket rtp;
-  int64_t log_time_us() const { return rtp.timestamp_us; }
-  int64_t log_time_ms() const { return rtp.timestamp_us / 1000; }
-};
-
-struct LoggedRtcpPacket {
-  LoggedRtcpPacket(uint64_t timestamp_us,
-                   const uint8_t* packet,
-                   size_t total_length)
-      : timestamp_us(timestamp_us), raw_data(packet, packet + total_length) {}
-  int64_t timestamp_us;
-  std::vector<uint8_t> raw_data;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedRtcpPacketIncoming {
-  LoggedRtcpPacketIncoming(uint64_t timestamp_us,
-                           const uint8_t* packet,
-                           size_t total_length)
-      : rtcp(timestamp_us, packet, total_length) {}
-  LoggedRtcpPacket rtcp;
-  int64_t log_time_us() const { return rtcp.timestamp_us; }
-  int64_t log_time_ms() const { return rtcp.timestamp_us / 1000; }
-};
-
-struct LoggedRtcpPacketOutgoing {
-  LoggedRtcpPacketOutgoing(uint64_t timestamp_us,
-                           const uint8_t* packet,
-                           size_t total_length)
-      : rtcp(timestamp_us, packet, total_length) {}
-  LoggedRtcpPacket rtcp;
-  int64_t log_time_us() const { return rtcp.timestamp_us; }
-  int64_t log_time_ms() const { return rtcp.timestamp_us / 1000; }
-};
-
-struct LoggedRtcpPacketReceiverReport {
-  int64_t timestamp_us;
-  rtcp::ReceiverReport rr;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedRtcpPacketSenderReport {
-  int64_t timestamp_us;
-  rtcp::SenderReport sr;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedRtcpPacketRemb {
-  int64_t timestamp_us;
-  rtcp::Remb remb;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedRtcpPacketNack {
-  int64_t timestamp_us;
-  rtcp::Nack nack;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedRtcpPacketTransportFeedback {
-  int64_t timestamp_us;
-  rtcp::TransportFeedback transport_feedback;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedStartEvent {
-  explicit LoggedStartEvent(uint64_t timestamp_us)
-      : timestamp_us(timestamp_us) {}
-  int64_t timestamp_us;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedStopEvent {
-  explicit LoggedStopEvent(uint64_t timestamp_us)
-      : timestamp_us(timestamp_us) {}
-  int64_t timestamp_us;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedAudioRecvConfig {
-  LoggedAudioRecvConfig(int64_t timestamp_us, const rtclog::StreamConfig config)
-      : timestamp_us(timestamp_us), config(config) {}
-  int64_t timestamp_us;
-  rtclog::StreamConfig config;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedAudioSendConfig {
-  LoggedAudioSendConfig(int64_t timestamp_us, const rtclog::StreamConfig config)
-      : timestamp_us(timestamp_us), config(config) {}
-  int64_t timestamp_us;
-  rtclog::StreamConfig config;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedVideoRecvConfig {
-  LoggedVideoRecvConfig(int64_t timestamp_us, const rtclog::StreamConfig config)
-      : timestamp_us(timestamp_us), config(config) {}
-  int64_t timestamp_us;
-  rtclog::StreamConfig config;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-struct LoggedVideoSendConfig {
-  LoggedVideoSendConfig(int64_t timestamp_us,
-                        const std::vector<rtclog::StreamConfig> configs)
-      : timestamp_us(timestamp_us), configs(configs) {}
-  int64_t timestamp_us;
-  std::vector<rtclog::StreamConfig> configs;
-  int64_t log_time_us() const { return timestamp_us; }
-  int64_t log_time_ms() const { return timestamp_us / 1000; }
-};
-
-template <typename T>
-class PacketView;
-
-template <typename T>
-class PacketIterator {
-  friend class PacketView<T>;
-
- public:
-  // Standard iterator traits.
-  using difference_type = std::ptrdiff_t;
-  using value_type = T;
-  using pointer = T*;
-  using reference = T&;
-  using iterator_category = std::bidirectional_iterator_tag;
-
-  // The default-contructed iterator is meaningless, but is required by the
-  // ForwardIterator concept.
-  PacketIterator() : ptr_(nullptr), element_size_(0) {}
-  PacketIterator(const PacketIterator& other)
-      : ptr_(other.ptr_), element_size_(other.element_size_) {}
-  PacketIterator(const PacketIterator&& other)
-      : ptr_(other.ptr_), element_size_(other.element_size_) {}
-  ~PacketIterator() = default;
-
-  PacketIterator& operator=(const PacketIterator& other) {
-    ptr_ = other.ptr_;
-    element_size_ = other.element_size_;
-    return *this;
-  }
-  PacketIterator& operator=(const PacketIterator&& other) {
-    ptr_ = other.ptr_;
-    element_size_ = other.element_size_;
-    return *this;
-  }
-
-  bool operator==(const PacketIterator<T>& other) const {
-    RTC_DCHECK_EQ(element_size_, other.element_size_);
-    return ptr_ == other.ptr_;
-  }
-  bool operator!=(const PacketIterator<T>& other) const {
-    RTC_DCHECK_EQ(element_size_, other.element_size_);
-    return ptr_ != other.ptr_;
-  }
-
-  PacketIterator& operator++() {
-    ptr_ += element_size_;
-    return *this;
-  }
-  PacketIterator& operator--() {
-    ptr_ -= element_size_;
-    return *this;
-  }
-  PacketIterator operator++(int) {
-    PacketIterator iter_copy(ptr_, element_size_);
-    ptr_ += element_size_;
-    return iter_copy;
-  }
-  PacketIterator operator--(int) {
-    PacketIterator iter_copy(ptr_, element_size_);
-    ptr_ -= element_size_;
-    return iter_copy;
-  }
-
-  T& operator*() { return *reinterpret_cast<T*>(ptr_); }
-  const T& operator*() const { return *reinterpret_cast<const T*>(ptr_); }
-
- private:
-  PacketIterator(typename std::conditional<std::is_const<T>::value,
-                                           const void*,
-                                           void*>::type p,
-                 size_t s)
-      : ptr_(reinterpret_cast<decltype(ptr_)>(p)), element_size_(s) {}
-
-  typename std::conditional<std::is_const<T>::value, const char*, char*>::type
-      ptr_;
-  size_t element_size_;
-};
-
-// Suppose that we have a struct S where we are only interested in a specific
-// member M. Given an array of S, PacketView can be used to treat the array
-// as an array of M, without exposing the type S to surrounding code and without
-// accessing the member through a virtual function. In this case, we want to
-// have a common view for incoming and outgoing RtpPackets, hence the PacketView
-// name.
-// Note that constructing a PacketView bypasses the typesystem, so the caller
-// has to take extra care when constructing these objects. The implementation
-// also requires that the containing struct is standard-layout (e.g. POD).
-//
-// Usage example:
-// struct A {...};
-// struct B { A a; ...};
-// struct C { A a; ...};
-// size_t len = 10;
-// B* array1 = new B[len];
-// C* array2 = new C[len];
-//
-// PacketView<A> view1 = PacketView<A>::Create<B>(array1, len, offsetof(B, a));
-// PacketView<A> view2 = PacketView<A>::Create<C>(array2, len, offsetof(C, a));
-//
-// The following code works with either view1 or view2.
-// void f(PacketView<A> view)
-// for (A& a : view) {
-//   DoSomething(a);
-// }
-template <typename T>
-class PacketView {
- public:
-  template <typename U>
-  static PacketView Create(U* ptr, size_t num_elements, size_t offset) {
-    static_assert(std::is_standard_layout<U>::value,
-                  "PacketView can only be created for standard layout types.");
-    static_assert(std::is_standard_layout<T>::value,
-                  "PacketView can only be created for standard layout types.");
-    return PacketView(ptr, num_elements, offset, sizeof(U));
-  }
-
-  using iterator = PacketIterator<T>;
-  using const_iterator = PacketIterator<const T>;
-  using reverse_iterator = std::reverse_iterator<iterator>;
-  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-
-  iterator begin() { return iterator(data_, element_size_); }
-  iterator end() {
-    auto end_ptr = data_ + num_elements_ * element_size_;
-    return iterator(end_ptr, element_size_);
-  }
-
-  const_iterator begin() const { return const_iterator(data_, element_size_); }
-  const_iterator end() const {
-    auto end_ptr = data_ + num_elements_ * element_size_;
-    return const_iterator(end_ptr, element_size_);
-  }
-
-  reverse_iterator rbegin() { return reverse_iterator(end()); }
-  reverse_iterator rend() { return reverse_iterator(begin()); }
-
-  const_reverse_iterator rbegin() const {
-    return const_reverse_iterator(end());
-  }
-  const_reverse_iterator rend() const {
-    return const_reverse_iterator(begin());
-  }
-
-  size_t size() const { return num_elements_; }
-
-  T& operator[](size_t i) {
-    auto elem_ptr = data_ + i * element_size_;
-    return *reinterpret_cast<T*>(elem_ptr);
-  }
-
-  const T& operator[](size_t i) const {
-    auto elem_ptr = data_ + i * element_size_;
-    return *reinterpret_cast<const T*>(elem_ptr);
-  }
-
- private:
-  PacketView(typename std::conditional<std::is_const<T>::value,
-                                       const void*,
-                                       void*>::type data,
-             size_t num_elements,
-             size_t offset,
-             size_t element_size)
-      : data_(reinterpret_cast<decltype(data_)>(data) + offset),
-        num_elements_(num_elements),
-        element_size_(element_size) {}
-
-  typename std::conditional<std::is_const<T>::value, const char*, char*>::type
-      data_;
-  size_t num_elements_;
-  size_t element_size_;
-};
-
-class ParsedRtcEventLog {
-  friend class RtcEventLogTestHelper;
-
- public:
-  enum EventType {
-    UNKNOWN_EVENT = 0,
-    LOG_START = 1,
-    LOG_END = 2,
-    RTP_EVENT = 3,
-    RTCP_EVENT = 4,
-    AUDIO_PLAYOUT_EVENT = 5,
-    LOSS_BASED_BWE_UPDATE = 6,
-    DELAY_BASED_BWE_UPDATE = 7,
-    VIDEO_RECEIVER_CONFIG_EVENT = 8,
-    VIDEO_SENDER_CONFIG_EVENT = 9,
-    AUDIO_RECEIVER_CONFIG_EVENT = 10,
-    AUDIO_SENDER_CONFIG_EVENT = 11,
-    AUDIO_NETWORK_ADAPTATION_EVENT = 16,
-    BWE_PROBE_CLUSTER_CREATED_EVENT = 17,
-    BWE_PROBE_RESULT_EVENT = 18,
-    ALR_STATE_EVENT = 19,
-    ICE_CANDIDATE_PAIR_CONFIG = 20,
-    ICE_CANDIDATE_PAIR_EVENT = 21,
-  };
-
-  enum class MediaType { ANY, AUDIO, VIDEO, DATA };
-  enum class UnconfiguredHeaderExtensions {
-    kDontParse,
-    kAttemptWebrtcDefaultConfig
-  };
-
-  explicit ParsedRtcEventLog(
-      UnconfiguredHeaderExtensions parse_unconfigured_header_extensions =
-          UnconfiguredHeaderExtensions::kDontParse);
-
-  // Clears previously parsed events and resets the ParsedRtcEventLog to an
-  // empty state.
-  void Clear();
-
-  // 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);  // no-presubmit-check TODO(webrtc:8982)
-
-  // Returns the number of events in an EventStream.
-  size_t GetNumberOfEvents() const;
-
-  // Reads the arrival timestamp (in microseconds) from a rtclog::Event.
-  int64_t GetTimestamp(size_t index) const;
-  int64_t GetTimestamp(const rtclog::Event& event) const;
-
-  // Reads the event type of the rtclog::Event at |index|.
-  EventType GetEventType(size_t index) const;
-
-  // Reads the header, direction, header length and packet length from the RTP
-  // event at |index|, and stores the values in the corresponding output
-  // parameters. Each output parameter can be set to nullptr if that value
-  // isn't needed.
-  // NB: The header must have space for at least IP_PACKET_SIZE bytes.
-  // Returns: a pointer to a header extensions map acquired from parsing
-  // corresponding Audio/Video Sender/Receiver config events.
-  // Warning: if the same SSRC is reused by both video and audio streams during
-  // call, extensions maps may be incorrect (the last one would be returned).
-  const webrtc::RtpHeaderExtensionMap* GetRtpHeader(
-      size_t index,
-      PacketDirection* incoming,
-      uint8_t* header,
-      size_t* header_length,
-      size_t* total_length,
-      int* probe_cluster_id) const;
-  const webrtc::RtpHeaderExtensionMap* GetRtpHeader(
-      const rtclog::Event& event,
-      PacketDirection* incoming,
-      uint8_t* header,
-      size_t* header_length,
-      size_t* total_length,
-      int* probe_cluster_id) const;
-
-  // Reads packet, direction and packet length from the RTCP event at |index|,
-  // and stores the values in the corresponding output parameters.
-  // Each output parameter can be set to nullptr if that value isn't needed.
-  // NB: The packet must have space for at least IP_PACKET_SIZE bytes.
-  void GetRtcpPacket(size_t index,
-                     PacketDirection* incoming,
-                     uint8_t* packet,
-                     size_t* length) const;
-  void GetRtcpPacket(const rtclog::Event& event,
-                     PacketDirection* incoming,
-                     uint8_t* packet,
-                     size_t* length) const;
-
-  // Reads a video receive config event to a StreamConfig struct.
-  // Only the fields that are stored in the protobuf will be written.
-  rtclog::StreamConfig GetVideoReceiveConfig(size_t index) const;
-
-  // Reads a video send config event to a StreamConfig struct. If the proto
-  // contains multiple SSRCs and RTX SSRCs (this used to be the case for
-  // simulcast streams) then we return one StreamConfig per SSRC,RTX_SSRC pair.
-  // Only the fields that are stored in the protobuf will be written.
-  std::vector<rtclog::StreamConfig> GetVideoSendConfig(size_t index) const;
-
-  // Reads a audio receive config event to a StreamConfig struct.
-  // Only the fields that are stored in the protobuf will be written.
-  rtclog::StreamConfig GetAudioReceiveConfig(size_t index) const;
-
-  // Reads a config event to a StreamConfig struct.
-  // Only the fields that are stored in the protobuf will be written.
-  rtclog::StreamConfig GetAudioSendConfig(size_t index) const;
-
-  // Reads the SSRC from the audio playout event at |index|. The SSRC is stored
-  // in the output parameter ssrc. The output parameter can be set to nullptr
-  // and in that case the function only asserts that the event is well formed.
-  LoggedAudioPlayoutEvent GetAudioPlayout(size_t index) const;
-
-  // Reads bitrate, fraction loss (as defined in RFC 1889) and total number of
-  // expected packets from the loss based BWE event at |index| and stores the
-  // values in
-  // the corresponding output parameters. Each output parameter can be set to
-  // nullptr if that
-  // value isn't needed.
-  LoggedBweLossBasedUpdate GetLossBasedBweUpdate(size_t index) const;
-
-  // Reads bitrate and detector_state from the delay based BWE event at |index|
-  // and stores the values in the corresponding output parameters. Each output
-  // parameter can be set to nullptr if that
-  // value isn't needed.
-  LoggedBweDelayBasedUpdate GetDelayBasedBweUpdate(size_t index) const;
-
-  // Reads a audio network adaptation event to a (non-NULL)
-  // AudioEncoderRuntimeConfig struct. Only the fields that are
-  // stored in the protobuf will be written.
-  LoggedAudioNetworkAdaptationEvent GetAudioNetworkAdaptation(
-      size_t index) const;
-
-  LoggedBweProbeClusterCreatedEvent GetBweProbeClusterCreated(
-      size_t index) const;
-
-  LoggedBweProbeResultEvent GetBweProbeResult(size_t index) const;
-
-  MediaType GetMediaType(uint32_t ssrc, PacketDirection direction) const;
-
-  LoggedAlrStateEvent GetAlrState(size_t index) const;
-
-  LoggedIceCandidatePairConfig GetIceCandidatePairConfig(size_t index) const;
-
-  LoggedIceCandidatePairEvent GetIceCandidatePairEvent(size_t index) const;
-
-  const std::set<uint32_t>& incoming_rtx_ssrcs() const {
-    return incoming_rtx_ssrcs_;
-  }
-  const std::set<uint32_t>& incoming_video_ssrcs() const {
-    return incoming_video_ssrcs_;
-  }
-  const std::set<uint32_t>& incoming_audio_ssrcs() const {
-    return incoming_audio_ssrcs_;
-  }
-  const std::set<uint32_t>& outgoing_rtx_ssrcs() const {
-    return outgoing_rtx_ssrcs_;
-  }
-  const std::set<uint32_t>& outgoing_video_ssrcs() const {
-    return outgoing_video_ssrcs_;
-  }
-  const std::set<uint32_t>& outgoing_audio_ssrcs() const {
-    return outgoing_audio_ssrcs_;
-  }
-
-  const std::vector<LoggedStartEvent>& start_log_events() const {
-    return start_log_events_;
-  }
-  const std::vector<LoggedStopEvent>& stop_log_events() const {
-    return stop_log_events_;
-  }
-  const std::map<uint32_t, std::vector<int64_t>>& audio_playout_events() const {
-    return audio_playout_events_;
-  }
-  const std::vector<LoggedAudioNetworkAdaptationEvent>&
-  audio_network_adaptation_events() const {
-    return audio_network_adaptation_events_;
-  }
-  const std::vector<LoggedBweProbeClusterCreatedEvent>&
-  bwe_probe_cluster_created_events() const {
-    return bwe_probe_cluster_created_events_;
-  }
-  const std::vector<LoggedBweProbeResultEvent>& bwe_probe_result_events()
-      const {
-    return bwe_probe_result_events_;
-  }
-  const std::vector<LoggedBweDelayBasedUpdate>& bwe_delay_updates() const {
-    return bwe_delay_updates_;
-  }
-  const std::vector<LoggedBweLossBasedUpdate>& bwe_loss_updates() const {
-    return bwe_loss_updates_;
-  }
-  const std::vector<LoggedAlrStateEvent>& alr_state_events() const {
-    return alr_state_events_;
-  }
-  const std::vector<LoggedIceCandidatePairConfig>& ice_candidate_pair_configs()
-      const {
-    return ice_candidate_pair_configs_;
-  }
-  const std::vector<LoggedIceCandidatePairEvent>& ice_candidate_pair_events()
-      const {
-    return ice_candidate_pair_events_;
-  }
-
-  struct LoggedRtpStreamIncoming {
-    uint32_t ssrc;
-    std::vector<LoggedRtpPacketIncoming> incoming_packets;
-  };
-
-  struct LoggedRtpStreamOutgoing {
-    uint32_t ssrc;
-    std::vector<LoggedRtpPacketOutgoing> outgoing_packets;
-  };
-
-  struct LoggedRtpStreamView {
-    LoggedRtpStreamView(uint32_t ssrc,
-                        const LoggedRtpPacketIncoming* ptr,
-                        size_t num_elements)
-        : ssrc(ssrc),
-          packet_view(PacketView<const LoggedRtpPacket>::Create(
-              ptr,
-              num_elements,
-              offsetof(LoggedRtpPacketIncoming, rtp))) {}
-    LoggedRtpStreamView(uint32_t ssrc,
-                        const LoggedRtpPacketOutgoing* ptr,
-                        size_t num_elements)
-        : ssrc(ssrc),
-          packet_view(PacketView<const LoggedRtpPacket>::Create(
-              ptr,
-              num_elements,
-              offsetof(LoggedRtpPacketOutgoing, rtp))) {}
-    uint32_t ssrc;
-    PacketView<const LoggedRtpPacket> packet_view;
-  };
-
-  const std::vector<LoggedRtpStreamIncoming>& incoming_rtp_packets_by_ssrc()
-      const {
-    return incoming_rtp_packets_by_ssrc_;
-  }
-
-  const std::vector<LoggedRtpStreamOutgoing>& outgoing_rtp_packets_by_ssrc()
-      const {
-    return outgoing_rtp_packets_by_ssrc_;
-  }
-
-  const std::vector<LoggedRtcpPacketIncoming>& incoming_rtcp_packets() const {
-    return incoming_rtcp_packets_;
-  }
-
-  const std::vector<LoggedRtcpPacketOutgoing>& outgoing_rtcp_packets() const {
-    return outgoing_rtcp_packets_;
-  }
-
-  const std::vector<LoggedRtpStreamView>& rtp_packets_by_ssrc(
-      PacketDirection direction) const {
-    if (direction == kIncomingPacket)
-      return incoming_rtp_packet_views_by_ssrc_;
-    else
-      return outgoing_rtp_packet_views_by_ssrc_;
-  }
-
-  const std::vector<LoggedRtcpPacketReceiverReport>& receiver_reports(
-      PacketDirection direction) const {
-    if (direction == kIncomingPacket) {
-      return incoming_rr_;
-    } else {
-      return outgoing_rr_;
-    }
-  }
-
-  const std::vector<LoggedRtcpPacketSenderReport>& sender_reports(
-      PacketDirection direction) const {
-    if (direction == kIncomingPacket) {
-      return incoming_sr_;
-    } else {
-      return outgoing_sr_;
-    }
-  }
-
-  const std::vector<LoggedRtcpPacketNack>& nacks(
-      PacketDirection direction) const {
-    if (direction == kIncomingPacket) {
-      return incoming_nack_;
-    } else {
-      return outgoing_nack_;
-    }
-  }
-
-  const std::vector<LoggedRtcpPacketRemb>& rembs(
-      PacketDirection direction) const {
-    if (direction == kIncomingPacket) {
-      return incoming_remb_;
-    } else {
-      return outgoing_remb_;
-    }
-  }
-
-  const std::vector<LoggedRtcpPacketTransportFeedback>& transport_feedbacks(
-      PacketDirection direction) const {
-    if (direction == kIncomingPacket) {
-      return incoming_transport_feedback_;
-    } else {
-      return outgoing_transport_feedback_;
-    }
-  }
-
-  int64_t first_timestamp() const { return first_timestamp_; }
-  int64_t last_timestamp() const { return last_timestamp_; }
-
- private:
-  void StoreParsedEvent(const rtclog::Event& event);
-
-  rtclog::StreamConfig GetVideoReceiveConfig(const rtclog::Event& event) const;
-  std::vector<rtclog::StreamConfig> GetVideoSendConfig(
-      const rtclog::Event& event) const;
-  rtclog::StreamConfig GetAudioReceiveConfig(const rtclog::Event& event) const;
-  rtclog::StreamConfig GetAudioSendConfig(const rtclog::Event& event) const;
-
-  LoggedAudioPlayoutEvent GetAudioPlayout(const rtclog::Event& event) const;
-
-  LoggedBweLossBasedUpdate GetLossBasedBweUpdate(
-      const rtclog::Event& event) const;
-  LoggedBweDelayBasedUpdate GetDelayBasedBweUpdate(
-      const rtclog::Event& event) const;
-
-  LoggedAudioNetworkAdaptationEvent GetAudioNetworkAdaptation(
-      const rtclog::Event& event) const;
-
-  LoggedBweProbeClusterCreatedEvent GetBweProbeClusterCreated(
-      const rtclog::Event& event) const;
-  LoggedBweProbeResultEvent GetBweProbeResult(const rtclog::Event& event) const;
-
-  LoggedAlrStateEvent GetAlrState(const rtclog::Event& event) const;
-
-  LoggedIceCandidatePairConfig GetIceCandidatePairConfig(
-      const rtclog::Event& event) const;
-  LoggedIceCandidatePairEvent GetIceCandidatePairEvent(
-      const rtclog::Event& event) const;
-
-  std::vector<rtclog::Event> events_;
-
-  struct Stream {
-    Stream(uint32_t ssrc,
-           MediaType media_type,
-           PacketDirection direction,
-           webrtc::RtpHeaderExtensionMap map)
-        : ssrc(ssrc),
-          media_type(media_type),
-          direction(direction),
-          rtp_extensions_map(map) {}
-    uint32_t ssrc;
-    MediaType media_type;
-    PacketDirection direction;
-    webrtc::RtpHeaderExtensionMap rtp_extensions_map;
-  };
-
-  const UnconfiguredHeaderExtensions parse_unconfigured_header_extensions_;
-
-  // Make a default extension map for streams without configuration information.
-  // TODO(ivoc): Once configuration of audio streams is stored in the event log,
-  //             this can be removed. Tracking bug: webrtc:6399
-  RtpHeaderExtensionMap default_extension_map_;
-
-  // Tracks what each stream is configured for. Note that a single SSRC can be
-  // in several sets. For example, the SSRC used for sending video over RTX
-  // will appear in both video_ssrcs_ and rtx_ssrcs_. In the unlikely case that
-  // an SSRC is reconfigured to a different media type mid-call, it will also
-  // appear in multiple sets.
-  std::set<uint32_t> incoming_rtx_ssrcs_;
-  std::set<uint32_t> incoming_video_ssrcs_;
-  std::set<uint32_t> incoming_audio_ssrcs_;
-  std::set<uint32_t> outgoing_rtx_ssrcs_;
-  std::set<uint32_t> outgoing_video_ssrcs_;
-  std::set<uint32_t> outgoing_audio_ssrcs_;
-
-  // Maps an SSRC to the parsed  RTP headers in that stream. Header extensions
-  // are parsed if the stream has been configured. This is only used for
-  // grouping the events by SSRC during parsing; the events are moved to
-  // incoming_rtp_packets_by_ssrc_ once the parsing is done.
-  std::map<uint32_t, std::vector<LoggedRtpPacketIncoming>>
-      incoming_rtp_packets_map_;
-  std::map<uint32_t, std::vector<LoggedRtpPacketOutgoing>>
-      outgoing_rtp_packets_map_;
-
-  // RTP headers.
-  std::vector<LoggedRtpStreamIncoming> incoming_rtp_packets_by_ssrc_;
-  std::vector<LoggedRtpStreamOutgoing> outgoing_rtp_packets_by_ssrc_;
-  std::vector<LoggedRtpStreamView> incoming_rtp_packet_views_by_ssrc_;
-  std::vector<LoggedRtpStreamView> outgoing_rtp_packet_views_by_ssrc_;
-
-  // Raw RTCP packets.
-  std::vector<LoggedRtcpPacketIncoming> incoming_rtcp_packets_;
-  std::vector<LoggedRtcpPacketOutgoing> outgoing_rtcp_packets_;
-
-  // Parsed RTCP messages. Currently not separated based on SSRC.
-  std::vector<LoggedRtcpPacketReceiverReport> incoming_rr_;
-  std::vector<LoggedRtcpPacketReceiverReport> outgoing_rr_;
-  std::vector<LoggedRtcpPacketSenderReport> incoming_sr_;
-  std::vector<LoggedRtcpPacketSenderReport> outgoing_sr_;
-  std::vector<LoggedRtcpPacketNack> incoming_nack_;
-  std::vector<LoggedRtcpPacketNack> outgoing_nack_;
-  std::vector<LoggedRtcpPacketRemb> incoming_remb_;
-  std::vector<LoggedRtcpPacketRemb> outgoing_remb_;
-  std::vector<LoggedRtcpPacketTransportFeedback> incoming_transport_feedback_;
-  std::vector<LoggedRtcpPacketTransportFeedback> outgoing_transport_feedback_;
-
-  std::vector<LoggedStartEvent> start_log_events_;
-  std::vector<LoggedStopEvent> stop_log_events_;
-
-  // Maps an SSRC to the timestamps of parsed audio playout events.
-  std::map<uint32_t, std::vector<int64_t>> audio_playout_events_;
-
-  std::vector<LoggedAudioNetworkAdaptationEvent>
-      audio_network_adaptation_events_;
-
-  std::vector<LoggedBweProbeClusterCreatedEvent>
-      bwe_probe_cluster_created_events_;
-
-  std::vector<LoggedBweProbeResultEvent> bwe_probe_result_events_;
-
-  std::vector<LoggedBweDelayBasedUpdate> bwe_delay_updates_;
-
-  // A list of all updates from the send-side loss-based bandwidth estimator.
-  std::vector<LoggedBweLossBasedUpdate> bwe_loss_updates_;
-
-  std::vector<LoggedAlrStateEvent> alr_state_events_;
-
-  std::vector<LoggedIceCandidatePairConfig> ice_candidate_pair_configs_;
-
-  std::vector<LoggedIceCandidatePairEvent> ice_candidate_pair_events_;
-
-  std::vector<LoggedAudioRecvConfig> audio_recv_configs_;
-  std::vector<LoggedAudioSendConfig> audio_send_configs_;
-  std::vector<LoggedVideoRecvConfig> video_recv_configs_;
-  std::vector<LoggedVideoSendConfig> video_send_configs_;
-
-  uint8_t last_incoming_rtcp_packet_[IP_PACKET_SIZE];
-  uint8_t last_incoming_rtcp_packet_length_;
-
-  int64_t first_timestamp_;
-  int64_t last_timestamp_;
-
-  // The extension maps are mutable to allow us to insert the default
-  // configuration when parsing an RTP header for an unconfigured stream.
-  mutable std::map<uint32_t, webrtc::RtpHeaderExtensionMap>
-      incoming_rtp_extensions_maps_;
-  mutable std::map<uint32_t, webrtc::RtpHeaderExtensionMap>
-      outgoing_rtp_extensions_maps_;
-};
-
-}  // namespace webrtc
-
-#endif  // LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_PARSER2_H_
diff --git a/logging/rtc_event_log/rtc_event_log_unittest.cc b/logging/rtc_event_log/rtc_event_log_unittest.cc
index 529228b..1cea313 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest.cc
@@ -34,7 +34,7 @@
 #include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h"
 #include "logging/rtc_event_log/output/rtc_event_log_output_file.h"
 #include "logging/rtc_event_log/rtc_event_log.h"
-#include "logging/rtc_event_log/rtc_event_log_parser2.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
 #include "logging/rtc_event_log/rtc_event_log_unittest_helper.h"
 #include "logging/rtc_event_log/rtc_stream_config.h"
 #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
@@ -750,16 +750,17 @@
   for (size_t i = 1; i < parsed_log.GetNumberOfEvents() - 1; i++) {
     EXPECT_EQ(parsed_log.GetEventType(i),
               ParsedRtcEventLog::EventType::AUDIO_PLAYOUT_EVENT);
-    LoggedAudioPlayoutEvent playout_event = parsed_log.GetAudioPlayout(i);
-    EXPECT_LT(playout_event.ssrc, kNumEvents);
-    EXPECT_EQ(static_cast<int64_t>(kStartTime + 10000 * playout_event.ssrc),
-              playout_event.timestamp_us);
+    uint32_t ssrc;
+    parsed_log.GetAudioPlayout(i, &ssrc);
+    int64_t timestamp = parsed_log.GetTimestamp(i);
+    EXPECT_LT(ssrc, kNumEvents);
+    EXPECT_EQ(static_cast<int64_t>(kStartTime + 10000 * ssrc), timestamp);
     if (last_ssrc)
-      EXPECT_EQ(playout_event.ssrc, *last_ssrc + 1);
+      EXPECT_EQ(ssrc, *last_ssrc + 1);
     if (last_timestamp)
-      EXPECT_EQ(playout_event.timestamp_us, *last_timestamp + 10000);
-    last_ssrc = playout_event.ssrc;
-    last_timestamp = playout_event.timestamp_us;
+      EXPECT_EQ(timestamp, *last_timestamp + 10000);
+    last_ssrc = ssrc;
+    last_timestamp = timestamp;
   }
   RtcEventLogTestHelper::VerifyLogEndEvent(parsed_log,
                                            parsed_log.GetNumberOfEvents() - 1);
diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
index 955c3b9..23e15b5 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
@@ -460,8 +460,9 @@
   EXPECT_EQ(ssrc, playout_event.local_ssrc());
 
   // Check consistency of the parser.
-  LoggedAudioPlayoutEvent parsed_event = parsed_log.GetAudioPlayout(index);
-  EXPECT_EQ(ssrc, parsed_event.ssrc);
+  uint32_t parsed_ssrc;
+  parsed_log.GetAudioPlayout(index, &parsed_ssrc);
+  EXPECT_EQ(ssrc, parsed_ssrc);
 }
 
 void RtcEventLogTestHelper::VerifyBweLossEvent(
@@ -483,10 +484,14 @@
   EXPECT_EQ(total_packets, bwe_event.total_packets());
 
   // Check consistency of the parser.
-  LoggedBweLossBasedUpdate bwe_update = parsed_log.GetLossBasedBweUpdate(index);
-  EXPECT_EQ(bitrate, bwe_update.bitrate_bps);
-  EXPECT_EQ(fraction_loss, bwe_update.fraction_lost);
-  EXPECT_EQ(total_packets, bwe_update.expected_packets);
+  int32_t parsed_bitrate;
+  uint8_t parsed_fraction_loss;
+  int32_t parsed_total_packets;
+  parsed_log.GetLossBasedBweUpdate(
+      index, &parsed_bitrate, &parsed_fraction_loss, &parsed_total_packets);
+  EXPECT_EQ(bitrate, parsed_bitrate);
+  EXPECT_EQ(fraction_loss, parsed_fraction_loss);
+  EXPECT_EQ(total_packets, parsed_total_packets);
 }
 
 void RtcEventLogTestHelper::VerifyBweDelayEvent(
@@ -506,7 +511,8 @@
             GetRuntimeDetectorState(bwe_event.detector_state()));
 
   // Check consistency of the parser.
-  LoggedBweDelayBasedUpdate res = parsed_log.GetDelayBasedBweUpdate(index);
+  ParsedRtcEventLog::BweDelayBasedUpdate res =
+      parsed_log.GetDelayBasedBweUpdate(index);
   EXPECT_EQ(res.bitrate_bps, bitrate);
   EXPECT_EQ(res.detector_state, detector_state);
 }
@@ -515,20 +521,15 @@
     const ParsedRtcEventLog& parsed_log,
     size_t index,
     const AudioEncoderRuntimeConfig& config) {
-  ASSERT_LT(index, parsed_log.events_.size());
-  const rtclog::Event& event = parsed_log.events_[index];
-  ASSERT_TRUE(IsValidBasicEvent(event));
-  ASSERT_EQ(rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT, event.type());
-
-  LoggedAudioNetworkAdaptationEvent parsed_event =
-      parsed_log.GetAudioNetworkAdaptation(index);
-  EXPECT_EQ(config.bitrate_bps, parsed_event.config.bitrate_bps);
-  EXPECT_EQ(config.enable_dtx, parsed_event.config.enable_dtx);
-  EXPECT_EQ(config.enable_fec, parsed_event.config.enable_fec);
-  EXPECT_EQ(config.frame_length_ms, parsed_event.config.frame_length_ms);
-  EXPECT_EQ(config.num_channels, parsed_event.config.num_channels);
+  AudioEncoderRuntimeConfig parsed_config;
+  parsed_log.GetAudioNetworkAdaptation(index, &parsed_config);
+  EXPECT_EQ(config.bitrate_bps, parsed_config.bitrate_bps);
+  EXPECT_EQ(config.enable_dtx, parsed_config.enable_dtx);
+  EXPECT_EQ(config.enable_fec, parsed_config.enable_fec);
+  EXPECT_EQ(config.frame_length_ms, parsed_config.frame_length_ms);
+  EXPECT_EQ(config.num_channels, parsed_config.num_channels);
   EXPECT_EQ(config.uplink_packet_loss_fraction,
-            parsed_event.config.uplink_packet_loss_fraction);
+            parsed_config.uplink_packet_loss_fraction);
 }
 
 void RtcEventLogTestHelper::VerifyLogStartEvent(
diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.h b/logging/rtc_event_log/rtc_event_log_unittest_helper.h
index 949a3db..630f160 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.h
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.h
@@ -12,7 +12,7 @@
 #define LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_UNITTEST_HELPER_H_
 
 #include "call/call.h"
-#include "logging/rtc_event_log/rtc_event_log_parser2.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
 #include "modules/rtp_rtcp/source/rtp_packet_received.h"
 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
 
diff --git a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
index b370e88..d6224ff 100644
--- a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
+++ b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc
@@ -66,7 +66,7 @@
       }
 
       if (parsed_stream_.GetMediaType(packet->header().ssrc, direction) !=
-          ParsedRtcEventLog::MediaType::AUDIO) {
+          webrtc::ParsedRtcEventLog::MediaType::AUDIO) {
         continue;
       }
 
@@ -85,10 +85,12 @@
   while (audio_output_index_ < parsed_stream_.GetNumberOfEvents()) {
     if (parsed_stream_.GetEventType(audio_output_index_) ==
         ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT) {
-      LoggedAudioPlayoutEvent playout_event =
-          parsed_stream_.GetAudioPlayout(audio_output_index_);
+      uint64_t timestamp_us = parsed_stream_.GetTimestamp(audio_output_index_);
+      // We call GetAudioPlayout only to check that the protobuf event is
+      // well-formed.
+      parsed_stream_.GetAudioPlayout(audio_output_index_, nullptr);
       audio_output_index_++;
-      return playout_event.timestamp_us / 1000;
+      return timestamp_us / 1000;
     }
     audio_output_index_++;
   }
diff --git a/modules/audio_coding/neteq/tools/rtc_event_log_source.h b/modules/audio_coding/neteq/tools/rtc_event_log_source.h
index 1b25e12..df01e06 100644
--- a/modules/audio_coding/neteq/tools/rtc_event_log_source.h
+++ b/modules/audio_coding/neteq/tools/rtc_event_log_source.h
@@ -14,7 +14,7 @@
 #include <memory>
 #include <string>
 
-#include "logging/rtc_event_log/rtc_event_log_parser2.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
 #include "modules/audio_coding/neteq/tools/packet_source.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "rtc_base/constructormagic.h"
diff --git a/rtc_tools/BUILD.gn b/rtc_tools/BUILD.gn
index 73e2494..d1d2b55 100644
--- a/rtc_tools/BUILD.gn
+++ b/rtc_tools/BUILD.gn
@@ -237,7 +237,6 @@
         "../rtc_base:checks",
         "../rtc_base:rtc_base_approved",
         "../rtc_base:rtc_numerics",
-        "../rtc_base:stringutils",
 
         # TODO(kwiberg): Remove this dependency.
         "../api/audio_codecs:audio_codecs_api",
diff --git a/rtc_tools/event_log_visualizer/analyzer.cc b/rtc_tools/event_log_visualizer/analyzer.cc
index c780632..1a7309c 100644
--- a/rtc_tools/event_log_visualizer/analyzer.cc
+++ b/rtc_tools/event_log_visualizer/analyzer.cc
@@ -14,6 +14,7 @@
 #include <cmath>
 #include <limits>
 #include <map>
+#include <sstream>
 #include <string>
 #include <utility>
 
@@ -24,7 +25,6 @@
 #include "call/video_send_stream.h"
 #include "common_types.h"  // NOLINT(build/include)
 #include "logging/rtc_event_log/rtc_stream_config.h"
-#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
 #include "modules/audio_coding/neteq/tools/audio_sink.h"
 #include "modules/audio_coding/neteq/tools/fake_decode_from_file.h"
 #include "modules/audio_coding/neteq/tools/neteq_delay_analyzer.h"
@@ -40,7 +40,6 @@
 #include "modules/pacing/packet_router.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
-#include "modules/rtp_rtcp/source/rtcp_packet.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/remb.h"
@@ -50,7 +49,6 @@
 #include "modules/rtp_rtcp/source/rtp_utility.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/format_macros.h"
-#include "rtc_base/function_view.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/numerics/sequence_number_util.h"
 #include "rtc_base/ptr_util.h"
@@ -61,6 +59,7 @@
 #endif  // BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
 
 namespace webrtc {
+namespace plotting {
 
 namespace {
 
@@ -128,45 +127,29 @@
   return difference;
 }
 
-// This is much more reliable for outgoing streams than for incoming streams.
-template <typename RtpPacketContainer>
-rtc::Optional<uint32_t> EstimateRtpClockFrequency(
-    const RtpPacketContainer& packets,
-    int64_t end_time_us) {
-  RTC_CHECK(packets.size() >= 2);
-  SeqNumUnwrapper<uint32_t> unwrapper;
-  uint64_t first_rtp_timestamp =
-      unwrapper.Unwrap(packets[0].rtp.header.timestamp);
-  int64_t first_log_timestamp = packets[0].log_time_us();
-  uint64_t last_rtp_timestamp = first_rtp_timestamp;
-  int64_t last_log_timestamp = first_log_timestamp;
-  for (size_t i = 1; i < packets.size(); i++) {
-    if (packets[i].log_time_us() > end_time_us)
-      break;
-    last_rtp_timestamp = unwrapper.Unwrap(packets[i].rtp.header.timestamp);
-    last_log_timestamp = packets[i].log_time_us();
-  }
-  if (last_log_timestamp - first_log_timestamp < kNumMicrosecsPerSec) {
-    RTC_LOG(LS_WARNING)
-        << "Failed to estimate RTP clock frequency: Stream too short. ("
-        << packets.size() << " packets, "
-        << last_log_timestamp - first_log_timestamp << " us)";
-    return rtc::nullopt;
-  }
-  double duration =
-      static_cast<double>(last_log_timestamp - first_log_timestamp) /
-      kNumMicrosecsPerSec;
-  double estimated_frequency =
-      (last_rtp_timestamp - first_rtp_timestamp) / duration;
-  for (uint32_t f : {8000, 16000, 32000, 48000, 90000}) {
-    if (std::fabs(estimated_frequency - f) < 0.05 * f) {
-      return f;
-    }
-  }
-  RTC_LOG(LS_WARNING) << "Failed to estimate RTP clock frequency: Estimate "
-                      << estimated_frequency
-                      << "not close to any stardard RTP frequency.";
-  return rtc::nullopt;
+// Return default values for header extensions, to use on streams without stored
+// mapping data. Currently this only applies to audio streams, since the mapping
+// is not stored in the event log.
+// TODO(ivoc): Remove this once this mapping is stored in the event log for
+//             audio streams. Tracking bug: webrtc:6399
+webrtc::RtpHeaderExtensionMap GetDefaultHeaderExtensionMap() {
+  webrtc::RtpHeaderExtensionMap default_map;
+  default_map.Register<AudioLevel>(webrtc::RtpExtension::kAudioLevelDefaultId);
+  default_map.Register<TransmissionOffset>(
+      webrtc::RtpExtension::kTimestampOffsetDefaultId);
+  default_map.Register<AbsoluteSendTime>(
+      webrtc::RtpExtension::kAbsSendTimeDefaultId);
+  default_map.Register<VideoOrientation>(
+      webrtc::RtpExtension::kVideoRotationDefaultId);
+  default_map.Register<VideoContentTypeExtension>(
+      webrtc::RtpExtension::kVideoContentTypeDefaultId);
+  default_map.Register<VideoTimingExtension>(
+      webrtc::RtpExtension::kVideoTimingDefaultId);
+  default_map.Register<TransportSequenceNumber>(
+      webrtc::RtpExtension::kTransportSequenceNumberDefaultId);
+  default_map.Register<PlayoutDelayLimits>(
+      webrtc::RtpExtension::kPlayoutDelayDefaultId);
+  return default_map;
 }
 
 constexpr float kLeftMargin = 0.01f;
@@ -182,8 +165,7 @@
     int64_t send_time_diff = WrappingDifference(
         new_packet.header.extension.absoluteSendTime,
         old_packet.header.extension.absoluteSendTime, 1ul << 24);
-    int64_t recv_time_diff =
-        new_packet.log_time_us() - old_packet.log_time_us();
+    int64_t recv_time_diff = new_packet.timestamp - old_packet.timestamp;
     double delay_change_us =
         recv_time_diff - AbsSendTimeToMicroseconds(send_time_diff);
     return delay_change_us / 1000;
@@ -197,7 +179,7 @@
     const LoggedRtpPacket& new_packet) {
   int64_t send_time_diff = WrappingDifference(
       new_packet.header.timestamp, old_packet.header.timestamp, 1ull << 32);
-  int64_t recv_time_diff = new_packet.log_time_us() - old_packet.log_time_us();
+  int64_t recv_time_diff = new_packet.timestamp - old_packet.timestamp;
 
   const double kVideoSampleRate = 90000;
   // TODO(terelius): We treat all streams as video for now, even though
@@ -211,9 +193,9 @@
   if (delay_change < -10000 || 10000 < delay_change) {
     RTC_LOG(LS_WARNING) << "Very large delay change. Timestamps correct?";
     RTC_LOG(LS_WARNING) << "Old capture time " << old_packet.header.timestamp
-                        << ", received time " << old_packet.log_time_us();
+                        << ", received time " << old_packet.timestamp;
     RTC_LOG(LS_WARNING) << "New capture time " << new_packet.header.timestamp
-                        << ", received time " << new_packet.log_time_us();
+                        << ", received time " << new_packet.timestamp;
     RTC_LOG(LS_WARNING) << "Receive time difference " << recv_time_diff << " = "
                         << static_cast<double>(recv_time_diff) /
                                kNumMicrosecsPerSec
@@ -226,55 +208,55 @@
   return delay_change;
 }
 
-// For each element in data_view, use |f()| to extract a y-coordinate and
+// For each element in data, use |get_y()| to extract a y-coordinate and
 // store the result in a TimeSeries.
-template <typename DataType, typename IterableType>
-void ProcessPoints(rtc::FunctionView<rtc::Optional<float>(const DataType&)> f,
-                   const IterableType& data_view,
-                   int64_t begin_time,
-                   TimeSeries* result) {
-  for (size_t i = 0; i < data_view.size(); i++) {
-    const DataType& elem = data_view[i];
-    float x = static_cast<float>(elem.log_time_us() - begin_time) /
+template <typename DataType>
+void ProcessPoints(
+    rtc::FunctionView<rtc::Optional<float>(const DataType&)> get_y,
+    const std::vector<DataType>& data,
+    uint64_t begin_time,
+    TimeSeries* result) {
+  for (size_t i = 0; i < data.size(); i++) {
+    float x = static_cast<float>(data[i].timestamp - begin_time) /
               kNumMicrosecsPerSec;
-    rtc::Optional<float> y = f(elem);
+    rtc::Optional<float> y = get_y(data[i]);
     if (y)
       result->points.emplace_back(x, *y);
   }
 }
 
-// For each pair of adjacent elements in |data|, use |f()| to extract a
+// For each pair of adjacent elements in |data|, use |get_y| to extract a
 // y-coordinate and store the result in a TimeSeries. Note that the x-coordinate
 // will be the time of the second element in the pair.
-template <typename DataType, typename ResultType, typename IterableType>
+template <typename DataType, typename ResultType>
 void ProcessPairs(
     rtc::FunctionView<rtc::Optional<ResultType>(const DataType&,
-                                                const DataType&)> f,
-    const IterableType& data,
-    int64_t begin_time,
+                                                const DataType&)> get_y,
+    const std::vector<DataType>& data,
+    uint64_t begin_time,
     TimeSeries* result) {
   for (size_t i = 1; i < data.size(); i++) {
-    float x = static_cast<float>(data[i].log_time_us() - begin_time) /
+    float x = static_cast<float>(data[i].timestamp - begin_time) /
               kNumMicrosecsPerSec;
-    rtc::Optional<ResultType> y = f(data[i - 1], data[i]);
+    rtc::Optional<ResultType> y = get_y(data[i - 1], data[i]);
     if (y)
       result->points.emplace_back(x, static_cast<float>(*y));
   }
 }
 
-// For each element in data, use |f()| to extract a y-coordinate and
+// For each element in data, use |extract()| to extract a y-coordinate and
 // store the result in a TimeSeries.
-template <typename DataType, typename ResultType, typename IterableType>
+template <typename DataType, typename ResultType>
 void AccumulatePoints(
-    rtc::FunctionView<rtc::Optional<ResultType>(const DataType&)> f,
-    const IterableType& data,
-    int64_t begin_time,
+    rtc::FunctionView<rtc::Optional<ResultType>(const DataType&)> extract,
+    const std::vector<DataType>& data,
+    uint64_t begin_time,
     TimeSeries* result) {
   ResultType sum = 0;
   for (size_t i = 0; i < data.size(); i++) {
-    float x = static_cast<float>(data[i].log_time_us() - begin_time) /
+    float x = static_cast<float>(data[i].timestamp - begin_time) /
               kNumMicrosecsPerSec;
-    rtc::Optional<ResultType> y = f(data[i]);
+    rtc::Optional<ResultType> y = extract(data[i]);
     if (y) {
       sum += *y;
       result->points.emplace_back(x, static_cast<float>(sum));
@@ -282,21 +264,21 @@
   }
 }
 
-// For each pair of adjacent elements in |data|, use |f()| to extract a
+// For each pair of adjacent elements in |data|, use |extract()| to extract a
 // y-coordinate and store the result in a TimeSeries. Note that the x-coordinate
 // will be the time of the second element in the pair.
-template <typename DataType, typename ResultType, typename IterableType>
+template <typename DataType, typename ResultType>
 void AccumulatePairs(
     rtc::FunctionView<rtc::Optional<ResultType>(const DataType&,
-                                                const DataType&)> f,
-    const IterableType& data,
-    int64_t begin_time,
+                                                const DataType&)> extract,
+    const std::vector<DataType>& data,
+    uint64_t begin_time,
     TimeSeries* result) {
   ResultType sum = 0;
   for (size_t i = 1; i < data.size(); i++) {
-    float x = static_cast<float>(data[i].log_time_us() - begin_time) /
+    float x = static_cast<float>(data[i].timestamp - begin_time) /
               kNumMicrosecsPerSec;
-    rtc::Optional<ResultType> y = f(data[i - 1], data[i]);
+    rtc::Optional<ResultType> y = extract(data[i - 1], data[i]);
     if (y)
       sum += *y;
     result->points.emplace_back(x, static_cast<float>(sum));
@@ -307,31 +289,30 @@
 // A data point is generated every |step| microseconds from |begin_time|
 // to |end_time|. The value of each data point is the average of the data
 // during the preceeding |window_duration_us| microseconds.
-template <typename DataType, typename ResultType, typename IterableType>
+template <typename DataType, typename ResultType>
 void MovingAverage(
-    rtc::FunctionView<rtc::Optional<ResultType>(const DataType&)> f,
-    const IterableType& data_view,
-    int64_t begin_time,
-    int64_t end_time,
-    int64_t window_duration_us,
-    int64_t step,
-    TimeSeries* result) {
+    rtc::FunctionView<rtc::Optional<ResultType>(const DataType&)> extract,
+    const std::vector<DataType>& data,
+    uint64_t begin_time,
+    uint64_t end_time,
+    uint64_t window_duration_us,
+    uint64_t step,
+    webrtc::plotting::TimeSeries* result) {
   size_t window_index_begin = 0;
   size_t window_index_end = 0;
   ResultType sum_in_window = 0;
 
-  for (int64_t t = begin_time; t < end_time + step; t += step) {
-    while (window_index_end < data_view.size() &&
-           data_view[window_index_end].log_time_us() < t) {
-      rtc::Optional<ResultType> value = f(data_view[window_index_end]);
+  for (uint64_t t = begin_time; t < end_time + step; t += step) {
+    while (window_index_end < data.size() &&
+           data[window_index_end].timestamp < t) {
+      rtc::Optional<ResultType> value = extract(data[window_index_end]);
       if (value)
         sum_in_window += *value;
       ++window_index_end;
     }
-    while (window_index_begin < data_view.size() &&
-           data_view[window_index_begin].log_time_us() <
-               t - window_duration_us) {
-      rtc::Optional<ResultType> value = f(data_view[window_index_begin]);
+    while (window_index_begin < data.size() &&
+           data[window_index_begin].timestamp < t - window_duration_us) {
+      rtc::Optional<ResultType> value = extract(data[window_index_begin]);
       if (value)
         sum_in_window -= *value;
       ++window_index_begin;
@@ -425,7 +406,7 @@
 }
 
 std::string GetCandidatePairLogDescriptionAsString(
-    const LoggedIceCandidatePairConfig& config) {
+    const ParsedRtcEventLog::IceCandidatePairConfig& config) {
   // Example: stun:wifi->relay(tcp):cellular@udp:ipv4
   // represents a pair of a local server-reflexive candidate on a WiFi network
   // and a remote relay candidate using TCP as the relay protocol on a cell
@@ -448,57 +429,244 @@
   return ss.str();
 }
 
-std::string GetDirectionAsString(PacketDirection direction) {
-  if (direction == kIncomingPacket) {
-    return "Incoming";
-  } else {
-    return "Outgoing";
-  }
-}
-
-std::string GetDirectionAsShortString(PacketDirection direction) {
-  if (direction == kIncomingPacket) {
-    return "In";
-  } else {
-    return "Out";
-  }
-}
-
 }  // namespace
 
 EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
     : parsed_log_(log), window_duration_(250000), step_(10000) {
-  begin_time_ = parsed_log_.first_timestamp();
-  end_time_ = parsed_log_.last_timestamp();
-  if (end_time_ < begin_time_) {
-    RTC_LOG(LS_WARNING) << "No useful events in the log.";
-    begin_time_ = end_time_ = 0;
-  }
-  call_duration_s_ = ToCallTime(end_time_);
+  uint64_t first_timestamp = std::numeric_limits<uint64_t>::max();
+  uint64_t last_timestamp = std::numeric_limits<uint64_t>::min();
 
-  const auto& log_start_events = parsed_log_.start_log_events();
-  const auto& log_end_events = parsed_log_.stop_log_events();
-  auto start_iter = log_start_events.begin();
-  auto end_iter = log_end_events.begin();
-  while (start_iter != log_start_events.end()) {
-    int64_t start = start_iter->log_time_us();
-    ++start_iter;
-    rtc::Optional<int64_t> next_start;
-    if (start_iter != log_start_events.end())
-      next_start.emplace(start_iter->log_time_us());
-    if (end_iter != log_end_events.end() &&
-        end_iter->log_time_us() <=
-            next_start.value_or(std::numeric_limits<int64_t>::max())) {
-      int64_t end = end_iter->log_time_us();
-      RTC_DCHECK_LE(start, end);
-      log_segments_.push_back(std::make_pair(start, end));
-      ++end_iter;
-    } else {
-      // we're missing an end event. Assume that it occurred just before the
-      // next start.
-      log_segments_.push_back(
-          std::make_pair(start, next_start.value_or(end_time_)));
+  PacketDirection direction;
+  uint8_t header[IP_PACKET_SIZE];
+  size_t header_length;
+  size_t total_length;
+
+  uint8_t last_incoming_rtcp_packet[IP_PACKET_SIZE];
+  uint8_t last_incoming_rtcp_packet_length = 0;
+
+  // Make a default extension map for streams without configuration information.
+  // TODO(ivoc): Once configuration of audio streams is stored in the event log,
+  //             this can be removed. Tracking bug: webrtc:6399
+  RtpHeaderExtensionMap default_extension_map = GetDefaultHeaderExtensionMap();
+
+  rtc::Optional<uint64_t> last_log_start;
+
+  for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
+    ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
+    if (event_type != ParsedRtcEventLog::VIDEO_RECEIVER_CONFIG_EVENT &&
+        event_type != ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT &&
+        event_type != ParsedRtcEventLog::AUDIO_RECEIVER_CONFIG_EVENT &&
+        event_type != ParsedRtcEventLog::AUDIO_SENDER_CONFIG_EVENT &&
+        event_type != ParsedRtcEventLog::LOG_START &&
+        event_type != ParsedRtcEventLog::LOG_END) {
+      uint64_t timestamp = parsed_log_.GetTimestamp(i);
+      first_timestamp = std::min(first_timestamp, timestamp);
+      last_timestamp = std::max(last_timestamp, timestamp);
     }
+
+    switch (parsed_log_.GetEventType(i)) {
+      case ParsedRtcEventLog::VIDEO_RECEIVER_CONFIG_EVENT: {
+        rtclog::StreamConfig config = parsed_log_.GetVideoReceiveConfig(i);
+        StreamId stream(config.remote_ssrc, kIncomingPacket);
+        video_ssrcs_.insert(stream);
+        StreamId rtx_stream(config.rtx_ssrc, kIncomingPacket);
+        video_ssrcs_.insert(rtx_stream);
+        rtx_ssrcs_.insert(rtx_stream);
+        break;
+      }
+      case ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT: {
+        std::vector<rtclog::StreamConfig> configs =
+            parsed_log_.GetVideoSendConfig(i);
+        for (const auto& config : configs) {
+          StreamId stream(config.local_ssrc, kOutgoingPacket);
+          video_ssrcs_.insert(stream);
+          StreamId rtx_stream(config.rtx_ssrc, kOutgoingPacket);
+          video_ssrcs_.insert(rtx_stream);
+          rtx_ssrcs_.insert(rtx_stream);
+        }
+        break;
+      }
+      case ParsedRtcEventLog::AUDIO_RECEIVER_CONFIG_EVENT: {
+        rtclog::StreamConfig config = parsed_log_.GetAudioReceiveConfig(i);
+        StreamId stream(config.remote_ssrc, kIncomingPacket);
+        audio_ssrcs_.insert(stream);
+        break;
+      }
+      case ParsedRtcEventLog::AUDIO_SENDER_CONFIG_EVENT: {
+        rtclog::StreamConfig config = parsed_log_.GetAudioSendConfig(i);
+        StreamId stream(config.local_ssrc, kOutgoingPacket);
+        audio_ssrcs_.insert(stream);
+        break;
+      }
+      case ParsedRtcEventLog::RTP_EVENT: {
+        RtpHeaderExtensionMap* extension_map = parsed_log_.GetRtpHeader(
+            i, &direction, header, &header_length, &total_length, nullptr);
+        RtpUtility::RtpHeaderParser rtp_parser(header, header_length);
+        RTPHeader parsed_header;
+        if (extension_map != nullptr) {
+          rtp_parser.Parse(&parsed_header, extension_map);
+        } else {
+          // Use the default extension map.
+          // TODO(ivoc): Once configuration of audio streams is stored in the
+          //             event log, this can be removed.
+          //             Tracking bug: webrtc:6399
+          rtp_parser.Parse(&parsed_header, &default_extension_map);
+        }
+        uint64_t timestamp = parsed_log_.GetTimestamp(i);
+        StreamId stream(parsed_header.ssrc, direction);
+        rtp_packets_[stream].push_back(LoggedRtpPacket(
+            timestamp, parsed_header, header_length, total_length));
+        break;
+      }
+      case ParsedRtcEventLog::RTCP_EVENT: {
+        uint8_t packet[IP_PACKET_SIZE];
+        parsed_log_.GetRtcpPacket(i, &direction, packet, &total_length);
+        // Currently incoming RTCP packets are logged twice, both for audio and
+        // video. Only act on one of them. Compare against the previous parsed
+        // incoming RTCP packet.
+        if (direction == webrtc::kIncomingPacket) {
+          RTC_CHECK_LE(total_length, IP_PACKET_SIZE);
+          if (total_length == last_incoming_rtcp_packet_length &&
+              memcmp(last_incoming_rtcp_packet, packet, total_length) == 0) {
+            continue;
+          } else {
+            memcpy(last_incoming_rtcp_packet, packet, total_length);
+            last_incoming_rtcp_packet_length = total_length;
+          }
+        }
+        rtcp::CommonHeader header;
+        const uint8_t* packet_end = packet + total_length;
+        for (const uint8_t* block = packet; block < packet_end;
+             block = header.NextPacket()) {
+          RTC_CHECK(header.Parse(block, packet_end - block));
+          if (header.type() == rtcp::TransportFeedback::kPacketType &&
+              header.fmt() == rtcp::TransportFeedback::kFeedbackMessageType) {
+            std::unique_ptr<rtcp::TransportFeedback> rtcp_packet(
+                rtc::MakeUnique<rtcp::TransportFeedback>());
+            if (rtcp_packet->Parse(header)) {
+              uint32_t ssrc = rtcp_packet->sender_ssrc();
+              StreamId stream(ssrc, direction);
+              uint64_t timestamp = parsed_log_.GetTimestamp(i);
+              rtcp_packets_[stream].push_back(LoggedRtcpPacket(
+                  timestamp, kRtcpTransportFeedback, std::move(rtcp_packet)));
+            }
+          } else if (header.type() == rtcp::SenderReport::kPacketType) {
+            std::unique_ptr<rtcp::SenderReport> rtcp_packet(
+                rtc::MakeUnique<rtcp::SenderReport>());
+            if (rtcp_packet->Parse(header)) {
+              uint32_t ssrc = rtcp_packet->sender_ssrc();
+              StreamId stream(ssrc, direction);
+              uint64_t timestamp = parsed_log_.GetTimestamp(i);
+              rtcp_packets_[stream].push_back(
+                  LoggedRtcpPacket(timestamp, kRtcpSr, std::move(rtcp_packet)));
+            }
+          } else if (header.type() == rtcp::ReceiverReport::kPacketType) {
+            std::unique_ptr<rtcp::ReceiverReport> rtcp_packet(
+                rtc::MakeUnique<rtcp::ReceiverReport>());
+            if (rtcp_packet->Parse(header)) {
+              uint32_t ssrc = rtcp_packet->sender_ssrc();
+              StreamId stream(ssrc, direction);
+              uint64_t timestamp = parsed_log_.GetTimestamp(i);
+              rtcp_packets_[stream].push_back(
+                  LoggedRtcpPacket(timestamp, kRtcpRr, std::move(rtcp_packet)));
+            }
+          } else if (header.type() == rtcp::Remb::kPacketType &&
+                     header.fmt() == rtcp::Remb::kFeedbackMessageType) {
+            std::unique_ptr<rtcp::Remb> rtcp_packet(
+                rtc::MakeUnique<rtcp::Remb>());
+            if (rtcp_packet->Parse(header)) {
+              uint32_t ssrc = rtcp_packet->sender_ssrc();
+              StreamId stream(ssrc, direction);
+              uint64_t timestamp = parsed_log_.GetTimestamp(i);
+              rtcp_packets_[stream].push_back(LoggedRtcpPacket(
+                  timestamp, kRtcpRemb, std::move(rtcp_packet)));
+            }
+          }
+        }
+        break;
+      }
+      case ParsedRtcEventLog::LOG_START: {
+        if (last_log_start) {
+          // A LOG_END event was missing. Use last_timestamp.
+          RTC_DCHECK_GE(last_timestamp, *last_log_start);
+          log_segments_.push_back(
+            std::make_pair(*last_log_start, last_timestamp));
+        }
+        last_log_start = parsed_log_.GetTimestamp(i);
+        break;
+      }
+      case ParsedRtcEventLog::LOG_END: {
+        RTC_DCHECK(last_log_start);
+        log_segments_.push_back(
+            std::make_pair(*last_log_start, parsed_log_.GetTimestamp(i)));
+        last_log_start.reset();
+        break;
+      }
+      case ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT: {
+        uint32_t this_ssrc;
+        parsed_log_.GetAudioPlayout(i, &this_ssrc);
+        audio_playout_events_[this_ssrc].push_back(parsed_log_.GetTimestamp(i));
+        break;
+      }
+      case ParsedRtcEventLog::LOSS_BASED_BWE_UPDATE: {
+        LossBasedBweUpdate bwe_update;
+        bwe_update.timestamp = parsed_log_.GetTimestamp(i);
+        parsed_log_.GetLossBasedBweUpdate(i, &bwe_update.new_bitrate,
+                                          &bwe_update.fraction_loss,
+                                          &bwe_update.expected_packets);
+        bwe_loss_updates_.push_back(bwe_update);
+        break;
+      }
+      case ParsedRtcEventLog::DELAY_BASED_BWE_UPDATE: {
+        bwe_delay_updates_.push_back(parsed_log_.GetDelayBasedBweUpdate(i));
+        break;
+      }
+      case ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT: {
+        AudioNetworkAdaptationEvent ana_event;
+        ana_event.timestamp = parsed_log_.GetTimestamp(i);
+        parsed_log_.GetAudioNetworkAdaptation(i, &ana_event.config);
+        audio_network_adaptation_events_.push_back(ana_event);
+        break;
+      }
+      case ParsedRtcEventLog::BWE_PROBE_CLUSTER_CREATED_EVENT: {
+        bwe_probe_cluster_created_events_.push_back(
+            parsed_log_.GetBweProbeClusterCreated(i));
+        break;
+      }
+      case ParsedRtcEventLog::BWE_PROBE_RESULT_EVENT: {
+        bwe_probe_result_events_.push_back(parsed_log_.GetBweProbeResult(i));
+        break;
+      }
+      case ParsedRtcEventLog::ALR_STATE_EVENT: {
+        alr_state_events_.push_back(parsed_log_.GetAlrState(i));
+        break;
+      }
+      case ParsedRtcEventLog::ICE_CANDIDATE_PAIR_CONFIG: {
+        ice_candidate_pair_configs_.push_back(
+            parsed_log_.GetIceCandidatePairConfig(i));
+        break;
+      }
+      case ParsedRtcEventLog::ICE_CANDIDATE_PAIR_EVENT: {
+        ice_candidate_pair_events_.push_back(
+            parsed_log_.GetIceCandidatePairEvent(i));
+        break;
+      }
+      case ParsedRtcEventLog::UNKNOWN_EVENT: {
+        break;
+      }
+    }
+  }
+
+  if (last_timestamp < first_timestamp) {
+    // No useful events in the log.
+    first_timestamp = last_timestamp = 0;
+  }
+  begin_time_ = first_timestamp;
+  end_time_ = last_timestamp;
+  call_duration_s_ = ToCallTime(end_time_);
+  if (last_log_start) {
+    // The log was missing the last LOG_END event. Fake it.
+    log_segments_.push_back(std::make_pair(*last_log_start, end_time_));
   }
   RTC_LOG(LS_INFO) << "Found " << log_segments_.size()
                << " (LOG_START, LOG_END) segments in log.";
@@ -510,7 +678,7 @@
   BitrateObserver() : last_bitrate_bps_(0), bitrate_updated_(false) {}
 
   void OnNetworkChanged(uint32_t bitrate_bps,
-                        uint8_t fraction_lost,
+                        uint8_t fraction_loss,
                         int64_t rtt_ms,
                         int64_t probing_interval_ms) override {
     last_bitrate_bps_ = bitrate_bps;
@@ -532,90 +700,187 @@
   bool bitrate_updated_;
 };
 
+bool EventLogAnalyzer::IsRtxSsrc(StreamId stream_id) const {
+  return rtx_ssrcs_.count(stream_id) == 1;
+}
+
+bool EventLogAnalyzer::IsVideoSsrc(StreamId stream_id) const {
+  return video_ssrcs_.count(stream_id) == 1;
+}
+
+bool EventLogAnalyzer::IsAudioSsrc(StreamId stream_id) const {
+  return audio_ssrcs_.count(stream_id) == 1;
+}
+
+std::string EventLogAnalyzer::GetStreamName(StreamId stream_id) const {
+  std::stringstream name;
+  if (IsAudioSsrc(stream_id)) {
+    name << "Audio ";
+  } else if (IsVideoSsrc(stream_id)) {
+    name << "Video ";
+  } else {
+    name << "Unknown ";
+  }
+  if (IsRtxSsrc(stream_id))
+    name << "RTX ";
+  if (stream_id.GetDirection() == kIncomingPacket) {
+    name << "(In) ";
+  } else {
+    name << "(Out) ";
+  }
+  name << SsrcToString(stream_id.GetSsrc());
+  return name.str();
+}
+
+// This is much more reliable for outgoing streams than for incoming streams.
+rtc::Optional<uint32_t> EventLogAnalyzer::EstimateRtpClockFrequency(
+    const std::vector<LoggedRtpPacket>& packets) const {
+  RTC_CHECK(packets.size() >= 2);
+  uint64_t end_time_us = log_segments_.empty()
+                             ? std::numeric_limits<uint64_t>::max()
+                             : log_segments_.front().second;
+  SeqNumUnwrapper<uint32_t> unwrapper;
+  uint64_t first_rtp_timestamp = unwrapper.Unwrap(packets[0].header.timestamp);
+  uint64_t first_log_timestamp = packets[0].timestamp;
+  uint64_t last_rtp_timestamp = first_rtp_timestamp;
+  uint64_t last_log_timestamp = first_log_timestamp;
+  for (size_t i = 1; i < packets.size(); i++) {
+    if (packets[i].timestamp > end_time_us)
+      break;
+    last_rtp_timestamp = unwrapper.Unwrap(packets[i].header.timestamp);
+    last_log_timestamp = packets[i].timestamp;
+  }
+  if (last_log_timestamp - first_log_timestamp < kNumMicrosecsPerSec) {
+    RTC_LOG(LS_WARNING)
+        << "Failed to estimate RTP clock frequency: Stream too short. ("
+        << packets.size() << " packets, "
+        << last_log_timestamp - first_log_timestamp << " us)";
+    return rtc::nullopt;
+  }
+  double duration =
+      static_cast<double>(last_log_timestamp - first_log_timestamp) /
+      kNumMicrosecsPerSec;
+  double estimated_frequency =
+      (last_rtp_timestamp - first_rtp_timestamp) / duration;
+  for (uint32_t f : {8000, 16000, 32000, 48000, 90000}) {
+    if (std::fabs(estimated_frequency - f) < 0.05 * f) {
+      return f;
+    }
+  }
+  RTC_LOG(LS_WARNING) << "Failed to estimate RTP clock frequency: Estimate "
+                      << estimated_frequency
+                      << "not close to any stardard RTP frequency.";
+  return rtc::nullopt;
+}
+
 float EventLogAnalyzer::ToCallTime(int64_t timestamp) const {
   return static_cast<float>(timestamp - begin_time_) / kNumMicrosecsPerSec;
 }
 
-void EventLogAnalyzer::CreatePacketGraph(PacketDirection direction,
+void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction,
                                          Plot* plot) {
-  for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) {
-    // Filter on SSRC.
-    if (!MatchingSsrc(stream.ssrc, desired_ssrc_)) {
+  for (auto& kv : rtp_packets_) {
+    StreamId stream_id = kv.first;
+    const std::vector<LoggedRtpPacket>& packet_stream = kv.second;
+    // Filter on direction and SSRC.
+    if (stream_id.GetDirection() != desired_direction ||
+        !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) {
       continue;
     }
 
-    TimeSeries time_series(GetStreamName(direction, stream.ssrc),
-                           LineStyle::kBar);
-    auto GetPacketSize = [](const LoggedRtpPacket& packet) {
-      return rtc::Optional<float>(packet.total_length);
-    };
-    ProcessPoints<LoggedRtpPacket>(GetPacketSize, stream.packet_view,
-                                   begin_time_, &time_series);
+    TimeSeries time_series(GetStreamName(stream_id), LineStyle::kBar);
+    ProcessPoints<LoggedRtpPacket>(
+        [](const LoggedRtpPacket& packet) {
+          return rtc::Optional<float>(packet.total_length);
+        },
+        packet_stream, begin_time_, &time_series);
     plot->AppendTimeSeries(std::move(time_series));
   }
 
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
   plot->SetSuggestedYAxis(0, 1, "Packet size (bytes)", kBottomMargin,
                           kTopMargin);
-  plot->SetTitle(GetDirectionAsString(direction) + " RTP packets");
+  if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
+    plot->SetTitle("Incoming RTP packets");
+  } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
+    plot->SetTitle("Outgoing RTP packets");
+  }
 }
 
-template <typename IterableType>
+template <typename T>
 void EventLogAnalyzer::CreateAccumulatedPacketsTimeSeries(
+    PacketDirection desired_direction,
     Plot* plot,
-    const IterableType& packets,
-    const std::string& label) {
-  TimeSeries time_series(label, LineStyle::kStep);
-  for (size_t i = 0; i < packets.size(); i++) {
-    float x = ToCallTime(packets[i].log_time_us());
-    time_series.points.emplace_back(x, i + 1);
+    const std::map<StreamId, std::vector<T>>& packets,
+    const std::string& label_prefix) {
+  for (auto& kv : packets) {
+    StreamId stream_id = kv.first;
+    const std::vector<T>& packet_stream = kv.second;
+    // Filter on direction and SSRC.
+    if (stream_id.GetDirection() != desired_direction ||
+        !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) {
+      continue;
+    }
+
+    std::string label = label_prefix + " " + GetStreamName(stream_id);
+    TimeSeries time_series(label, LineStyle::kStep);
+    for (size_t i = 0; i < packet_stream.size(); i++) {
+      float x = ToCallTime(packet_stream[i].timestamp);
+      time_series.points.emplace_back(x, i + 1);
+    }
+
+    plot->AppendTimeSeries(std::move(time_series));
   }
-  plot->AppendTimeSeries(std::move(time_series));
 }
 
-void EventLogAnalyzer::CreateAccumulatedPacketsGraph(PacketDirection direction,
-                                                     Plot* plot) {
-  for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) {
-    if (!MatchingSsrc(stream.ssrc, desired_ssrc_))
-      continue;
-    std::string label =
-        std::string("RTP ") + GetStreamName(direction, stream.ssrc);
-    CreateAccumulatedPacketsTimeSeries(plot, stream.packet_view, label);
-  }
-  std::string label =
-      std::string("RTCP ") + "(" + GetDirectionAsShortString(direction) + ")";
-  if (direction == kIncomingPacket) {
-    CreateAccumulatedPacketsTimeSeries(
-        plot, parsed_log_.incoming_rtcp_packets(), label);
-  } else {
-    CreateAccumulatedPacketsTimeSeries(
-        plot, parsed_log_.outgoing_rtcp_packets(), label);
-  }
+void EventLogAnalyzer::CreateAccumulatedPacketsGraph(
+    PacketDirection desired_direction,
+    Plot* plot) {
+  CreateAccumulatedPacketsTimeSeries(desired_direction, plot, rtp_packets_,
+                                     "RTP");
+  CreateAccumulatedPacketsTimeSeries(desired_direction, plot, rtcp_packets_,
+                                     "RTCP");
 
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
   plot->SetSuggestedYAxis(0, 1, "Received Packets", kBottomMargin, kTopMargin);
-  plot->SetTitle(std::string("Accumulated ") + GetDirectionAsString(direction) +
-                 " RTP/RTCP packets");
+  if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
+    plot->SetTitle("Accumulated Incoming RTP/RTCP packets");
+  } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
+    plot->SetTitle("Accumulated Outgoing RTP/RTCP packets");
+  }
 }
 
 // For each SSRC, plot the time between the consecutive playouts.
 void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) {
-  for (const auto& playout_stream : parsed_log_.audio_playout_events()) {
-    uint32_t ssrc = playout_stream.first;
-    if (!MatchingSsrc(ssrc, desired_ssrc_))
-      continue;
-    rtc::Optional<int64_t> last_playout;
-    TimeSeries time_series(SsrcToString(ssrc), LineStyle::kBar);
-    for (const auto& playout_time : playout_stream.second) {
-      float x = ToCallTime(playout_time);
-      // If there were no previous playouts, place the point on the x-axis.
-      float y = static_cast<float>(playout_time -
-                                   last_playout.value_or(playout_time)) /
-                1000;
-      time_series.points.push_back(TimeSeriesPoint(x, y));
-      last_playout.emplace(playout_time);
+  std::map<uint32_t, TimeSeries> time_series;
+  std::map<uint32_t, uint64_t> last_playout;
+
+  uint32_t ssrc;
+
+  for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
+    ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
+    if (event_type == ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT) {
+      parsed_log_.GetAudioPlayout(i, &ssrc);
+      uint64_t timestamp = parsed_log_.GetTimestamp(i);
+      if (MatchingSsrc(ssrc, desired_ssrc_)) {
+        float x = ToCallTime(timestamp);
+        float y = static_cast<float>(timestamp - last_playout[ssrc]) / 1000;
+        if (time_series[ssrc].points.size() == 0) {
+          // There were no previusly logged playout for this SSRC.
+          // Generate a point, but place it on the x-axis.
+          y = 0;
+        }
+        time_series[ssrc].points.push_back(TimeSeriesPoint(x, y));
+        last_playout[ssrc] = timestamp;
+      }
     }
-    plot->AppendTimeSeries(std::move(time_series));
+  }
+
+  // Set labels and put in graph.
+  for (auto& kv : time_series) {
+    kv.second.label = SsrcToString(kv.first);
+    kv.second.line_style = LineStyle::kBar;
+    plot->AppendTimeSeries(std::move(kv.second));
   }
 
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
@@ -625,51 +890,59 @@
 }
 
 // For audio SSRCs, plot the audio level.
-void EventLogAnalyzer::CreateAudioLevelGraph(PacketDirection direction,
-                                             Plot* plot) {
-  for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) {
-    if (!IsAudioSsrc(direction, stream.ssrc))
-      continue;
-    TimeSeries time_series(GetStreamName(direction, stream.ssrc),
-                           LineStyle::kLine);
-    for (auto& packet : stream.packet_view) {
+void EventLogAnalyzer::CreateAudioLevelGraph(Plot* plot) {
+  std::map<StreamId, TimeSeries> time_series;
+
+  for (auto& kv : rtp_packets_) {
+    StreamId stream_id = kv.first;
+    const std::vector<LoggedRtpPacket>& packet_stream = kv.second;
+    // TODO(ivoc): When audio send/receive configs are stored in the event
+    //             log, a check should be added here to only process audio
+    //             streams. Tracking bug: webrtc:6399
+    for (auto& packet : packet_stream) {
       if (packet.header.extension.hasAudioLevel) {
-        float x = ToCallTime(packet.log_time_us());
+        float x = ToCallTime(packet.timestamp);
         // The audio level is stored in -dBov (so e.g. -10 dBov is stored as 10)
         // Here we convert it to dBov.
         float y = static_cast<float>(-packet.header.extension.audioLevel);
-        time_series.points.emplace_back(TimeSeriesPoint(x, y));
+        time_series[stream_id].points.emplace_back(TimeSeriesPoint(x, y));
       }
     }
-    plot->AppendTimeSeries(std::move(time_series));
+  }
+
+  for (auto& series : time_series) {
+    series.second.label = GetStreamName(series.first);
+    series.second.line_style = LineStyle::kLine;
+    plot->AppendTimeSeries(std::move(series.second));
   }
 
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
   plot->SetYAxis(-127, 0, "Audio level (dBov)", kBottomMargin,
                  kTopMargin);
-  plot->SetTitle(GetDirectionAsString(direction) + " audio level");
+  plot->SetTitle("Audio level");
 }
 
 // For each SSRC, plot the time between the consecutive playouts.
 void EventLogAnalyzer::CreateSequenceNumberGraph(Plot* plot) {
-  for (const auto& stream : parsed_log_.incoming_rtp_packets_by_ssrc()) {
-    // Filter on SSRC.
-    if (!MatchingSsrc(stream.ssrc, desired_ssrc_)) {
+  for (auto& kv : rtp_packets_) {
+    StreamId stream_id = kv.first;
+    const std::vector<LoggedRtpPacket>& packet_stream = kv.second;
+    // Filter on direction and SSRC.
+    if (stream_id.GetDirection() != kIncomingPacket ||
+        !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) {
       continue;
     }
 
-    TimeSeries time_series(GetStreamName(kIncomingPacket, stream.ssrc),
-                           LineStyle::kBar);
-    auto GetSequenceNumberDiff = [](const LoggedRtpPacketIncoming& old_packet,
-                                    const LoggedRtpPacketIncoming& new_packet) {
-      int64_t diff =
-          WrappingDifference(new_packet.rtp.header.sequenceNumber,
-                             old_packet.rtp.header.sequenceNumber, 1ul << 16);
-      return diff;
-    };
-    ProcessPairs<LoggedRtpPacketIncoming, float>(GetSequenceNumberDiff,
-                                                 stream.incoming_packets,
-                                                 begin_time_, &time_series);
+    TimeSeries time_series(GetStreamName(stream_id), LineStyle::kBar);
+    ProcessPairs<LoggedRtpPacket, float>(
+        [](const LoggedRtpPacket& old_packet,
+           const LoggedRtpPacket& new_packet) {
+          int64_t diff =
+              WrappingDifference(new_packet.header.sequenceNumber,
+                                 old_packet.header.sequenceNumber, 1ul << 16);
+          return diff;
+        },
+        packet_stream, begin_time_, &time_series);
     plot->AppendTimeSeries(std::move(time_series));
   }
 
@@ -680,47 +953,47 @@
 }
 
 void EventLogAnalyzer::CreateIncomingPacketLossGraph(Plot* plot) {
-  for (const auto& stream : parsed_log_.incoming_rtp_packets_by_ssrc()) {
-    const std::vector<LoggedRtpPacketIncoming>& packets =
-        stream.incoming_packets;
-    // Filter on SSRC.
-    if (!MatchingSsrc(stream.ssrc, desired_ssrc_) || packets.size() == 0) {
+  for (auto& kv : rtp_packets_) {
+    StreamId stream_id = kv.first;
+    const std::vector<LoggedRtpPacket>& packet_stream = kv.second;
+    // Filter on direction and SSRC.
+    if (stream_id.GetDirection() != kIncomingPacket ||
+        !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_) ||
+        packet_stream.size() == 0) {
       continue;
     }
 
-    TimeSeries time_series(GetStreamName(kIncomingPacket, stream.ssrc),
-                           LineStyle::kLine, PointStyle::kHighlight);
-    // TODO(terelius): Should the window and step size be read from the class
-    // instead?
-    const int64_t kWindowUs = 1000000;
-    const int64_t kStep = 1000000;
+    TimeSeries time_series(GetStreamName(stream_id), LineStyle::kLine,
+                           PointStyle::kHighlight);
+    const uint64_t kWindowUs = 1000000;
+    const uint64_t kStep = 1000000;
     SeqNumUnwrapper<uint16_t> unwrapper_;
     SeqNumUnwrapper<uint16_t> prior_unwrapper_;
     size_t window_index_begin = 0;
     size_t window_index_end = 0;
-    uint64_t highest_seq_number =
-        unwrapper_.Unwrap(packets[0].rtp.header.sequenceNumber) - 1;
-    uint64_t highest_prior_seq_number =
-        prior_unwrapper_.Unwrap(packets[0].rtp.header.sequenceNumber) - 1;
+    int64_t highest_seq_number =
+        unwrapper_.Unwrap(packet_stream[0].header.sequenceNumber) - 1;
+    int64_t highest_prior_seq_number =
+        prior_unwrapper_.Unwrap(packet_stream[0].header.sequenceNumber) - 1;
 
-    for (int64_t t = begin_time_; t < end_time_ + kStep; t += kStep) {
-      while (window_index_end < packets.size() &&
-             packets[window_index_end].rtp.log_time_us() < t) {
-        uint64_t sequence_number = unwrapper_.Unwrap(
-            packets[window_index_end].rtp.header.sequenceNumber);
+    for (uint64_t t = begin_time_; t < end_time_ + kStep; t += kStep) {
+      while (window_index_end < packet_stream.size() &&
+             packet_stream[window_index_end].timestamp < t) {
+        int64_t sequence_number = unwrapper_.Unwrap(
+            packet_stream[window_index_end].header.sequenceNumber);
         highest_seq_number = std::max(highest_seq_number, sequence_number);
         ++window_index_end;
       }
-      while (window_index_begin < packets.size() &&
-             packets[window_index_begin].rtp.log_time_us() < t - kWindowUs) {
-        uint64_t sequence_number = prior_unwrapper_.Unwrap(
-            packets[window_index_begin].rtp.header.sequenceNumber);
+      while (window_index_begin < packet_stream.size() &&
+             packet_stream[window_index_begin].timestamp < t - kWindowUs) {
+        int64_t sequence_number = prior_unwrapper_.Unwrap(
+            packet_stream[window_index_begin].header.sequenceNumber);
         highest_prior_seq_number =
             std::max(highest_prior_seq_number, sequence_number);
         ++window_index_begin;
       }
       float x = ToCallTime(t);
-      uint64_t expected_packets = highest_seq_number - highest_prior_seq_number;
+      int64_t expected_packets = highest_seq_number - highest_prior_seq_number;
       if (expected_packets > 0) {
         int64_t received_packets = window_index_end - window_index_begin;
         int64_t lost_packets = expected_packets - received_packets;
@@ -738,28 +1011,28 @@
 }
 
 void EventLogAnalyzer::CreateIncomingDelayDeltaGraph(Plot* plot) {
-  for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(kIncomingPacket)) {
-    // Filter on SSRC.
-    if (!MatchingSsrc(stream.ssrc, desired_ssrc_) ||
-        IsAudioSsrc(kIncomingPacket, stream.ssrc) ||
-        !IsVideoSsrc(kIncomingPacket, stream.ssrc) ||
-        IsRtxSsrc(kIncomingPacket, stream.ssrc)) {
+  for (auto& kv : rtp_packets_) {
+    StreamId stream_id = kv.first;
+    const std::vector<LoggedRtpPacket>& packet_stream = kv.second;
+    // Filter on direction and SSRC.
+    if (stream_id.GetDirection() != kIncomingPacket ||
+        !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_) ||
+        IsAudioSsrc(stream_id) || !IsVideoSsrc(stream_id) ||
+        IsRtxSsrc(stream_id)) {
       continue;
     }
 
-    TimeSeries capture_time_data(
-        GetStreamName(kIncomingPacket, stream.ssrc) + " capture-time",
-        LineStyle::kBar);
+    TimeSeries capture_time_data(GetStreamName(stream_id) + " capture-time",
+                                 LineStyle::kBar);
     ProcessPairs<LoggedRtpPacket, double>(NetworkDelayDiff_CaptureTime,
-                                          stream.packet_view, begin_time_,
+                                          packet_stream, begin_time_,
                                           &capture_time_data);
     plot->AppendTimeSeries(std::move(capture_time_data));
 
-    TimeSeries send_time_data(
-        GetStreamName(kIncomingPacket, stream.ssrc) + " abs-send-time",
-        LineStyle::kBar);
+    TimeSeries send_time_data(GetStreamName(stream_id) + " abs-send-time",
+                              LineStyle::kBar);
     ProcessPairs<LoggedRtpPacket, double>(NetworkDelayDiff_AbsSendTime,
-                                          stream.packet_view, begin_time_,
+                                          packet_stream, begin_time_,
                                           &send_time_data);
     plot->AppendTimeSeries(std::move(send_time_data));
   }
@@ -771,28 +1044,28 @@
 }
 
 void EventLogAnalyzer::CreateIncomingDelayGraph(Plot* plot) {
-  for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(kIncomingPacket)) {
-    // Filter on SSRC.
-    if (!MatchingSsrc(stream.ssrc, desired_ssrc_) ||
-        IsAudioSsrc(kIncomingPacket, stream.ssrc) ||
-        !IsVideoSsrc(kIncomingPacket, stream.ssrc) ||
-        IsRtxSsrc(kIncomingPacket, stream.ssrc)) {
+  for (auto& kv : rtp_packets_) {
+    StreamId stream_id = kv.first;
+    const std::vector<LoggedRtpPacket>& packet_stream = kv.second;
+    // Filter on direction and SSRC.
+    if (stream_id.GetDirection() != kIncomingPacket ||
+        !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_) ||
+        IsAudioSsrc(stream_id) || !IsVideoSsrc(stream_id) ||
+        IsRtxSsrc(stream_id)) {
       continue;
     }
 
-    TimeSeries capture_time_data(
-        GetStreamName(kIncomingPacket, stream.ssrc) + " capture-time",
-        LineStyle::kLine);
+    TimeSeries capture_time_data(GetStreamName(stream_id) + " capture-time",
+                                 LineStyle::kLine);
     AccumulatePairs<LoggedRtpPacket, double>(NetworkDelayDiff_CaptureTime,
-                                             stream.packet_view, begin_time_,
+                                             packet_stream, begin_time_,
                                              &capture_time_data);
     plot->AppendTimeSeries(std::move(capture_time_data));
 
-    TimeSeries send_time_data(
-        GetStreamName(kIncomingPacket, stream.ssrc) + " abs-send-time",
-        LineStyle::kLine);
+    TimeSeries send_time_data(GetStreamName(stream_id) + " abs-send-time",
+                              LineStyle::kLine);
     AccumulatePairs<LoggedRtpPacket, double>(NetworkDelayDiff_AbsSendTime,
-                                             stream.packet_view, begin_time_,
+                                             packet_stream, begin_time_,
                                              &send_time_data);
     plot->AppendTimeSeries(std::move(send_time_data));
   }
@@ -807,9 +1080,9 @@
 void EventLogAnalyzer::CreateFractionLossGraph(Plot* plot) {
   TimeSeries time_series("Fraction lost", LineStyle::kLine,
                          PointStyle::kHighlight);
-  for (auto& bwe_update : parsed_log_.bwe_loss_updates()) {
-    float x = ToCallTime(bwe_update.log_time_us());
-    float y = static_cast<float>(bwe_update.fraction_lost) / 255 * 100;
+  for (auto& bwe_update : bwe_loss_updates_) {
+    float x = ToCallTime(bwe_update.timestamp);
+    float y = static_cast<float>(bwe_update.fraction_loss) / 255 * 100;
     time_series.points.emplace_back(x, y);
   }
 
@@ -821,82 +1094,51 @@
 }
 
 // Plot the total bandwidth used by all RTP streams.
-void EventLogAnalyzer::CreateTotalIncomingBitrateGraph(Plot* plot) {
-  // TODO(terelius): This could be provided by the parser.
-  std::multimap<int64_t, size_t> packets_in_order;
-  for (const auto& stream : parsed_log_.incoming_rtp_packets_by_ssrc()) {
-    for (const LoggedRtpPacketIncoming& packet : stream.incoming_packets)
-      packets_in_order.insert(
-          std::make_pair(packet.rtp.log_time_us(), packet.rtp.total_length));
+void EventLogAnalyzer::CreateTotalBitrateGraph(
+    PacketDirection desired_direction,
+    Plot* plot,
+    bool show_detector_state,
+    bool show_alr_state) {
+  struct TimestampSize {
+    TimestampSize(uint64_t t, size_t s) : timestamp(t), size(s) {}
+    uint64_t timestamp;
+    size_t size;
+  };
+  std::vector<TimestampSize> packets;
+
+  PacketDirection direction;
+  size_t total_length;
+
+  // Extract timestamps and sizes for the relevant packets.
+  for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
+    ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
+    if (event_type == ParsedRtcEventLog::RTP_EVENT) {
+      parsed_log_.GetRtpHeader(i, &direction, nullptr, nullptr, &total_length,
+                               nullptr);
+      if (direction == desired_direction) {
+        uint64_t timestamp = parsed_log_.GetTimestamp(i);
+        packets.push_back(TimestampSize(timestamp, total_length));
+      }
+    }
   }
 
-  auto window_begin = packets_in_order.begin();
-  auto window_end = packets_in_order.begin();
+  size_t window_index_begin = 0;
+  size_t window_index_end = 0;
   size_t bytes_in_window = 0;
 
   // Calculate a moving average of the bitrate and store in a TimeSeries.
   TimeSeries bitrate_series("Bitrate", LineStyle::kLine);
-  for (int64_t time = begin_time_; time < end_time_ + step_; time += step_) {
-    while (window_end != packets_in_order.end() && window_end->first < time) {
-      bytes_in_window += window_end->second;
-      ++window_end;
+  for (uint64_t time = begin_time_; time < end_time_ + step_; time += step_) {
+    while (window_index_end < packets.size() &&
+           packets[window_index_end].timestamp < time) {
+      bytes_in_window += packets[window_index_end].size;
+      ++window_index_end;
     }
-    while (window_begin != packets_in_order.end() &&
-           window_begin->first < time - window_duration_) {
-      RTC_DCHECK_LE(window_begin->second, bytes_in_window);
-      bytes_in_window -= window_begin->second;
-      ++window_begin;
-    }
-    float window_duration_in_seconds =
-        static_cast<float>(window_duration_) / kNumMicrosecsPerSec;
-    float x = ToCallTime(time);
-    float y = bytes_in_window * 8 / window_duration_in_seconds / 1000;
-    bitrate_series.points.emplace_back(x, y);
-  }
-  plot->AppendTimeSeries(std::move(bitrate_series));
-
-  // Overlay the outgoing REMB over incoming bitrate.
-  TimeSeries remb_series("Remb", LineStyle::kStep);
-  for (const auto& rtcp : parsed_log_.rembs(kOutgoingPacket)) {
-    float x = ToCallTime(rtcp.log_time_us());
-    float y = static_cast<float>(rtcp.remb.bitrate_bps()) / 1000;
-    remb_series.points.emplace_back(x, y);
-  }
-  plot->AppendTimeSeriesIfNotEmpty(std::move(remb_series));
-
-  plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
-  plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin);
-  plot->SetTitle("Incoming RTP bitrate");
-}
-
-// Plot the total bandwidth used by all RTP streams.
-void EventLogAnalyzer::CreateTotalOutgoingBitrateGraph(Plot* plot,
-                                                       bool show_detector_state,
-                                                       bool show_alr_state) {
-  // TODO(terelius): This could be provided by the parser.
-  std::multimap<int64_t, size_t> packets_in_order;
-  for (const auto& stream : parsed_log_.outgoing_rtp_packets_by_ssrc()) {
-    for (const LoggedRtpPacketOutgoing& packet : stream.outgoing_packets)
-      packets_in_order.insert(
-          std::make_pair(packet.rtp.log_time_us(), packet.rtp.total_length));
-  }
-
-  auto window_begin = packets_in_order.begin();
-  auto window_end = packets_in_order.begin();
-  size_t bytes_in_window = 0;
-
-  // Calculate a moving average of the bitrate and store in a TimeSeries.
-  TimeSeries bitrate_series("Bitrate", LineStyle::kLine);
-  for (int64_t time = begin_time_; time < end_time_ + step_; time += step_) {
-    while (window_end != packets_in_order.end() && window_end->first < time) {
-      bytes_in_window += window_end->second;
-      ++window_end;
-    }
-    while (window_begin != packets_in_order.end() &&
-           window_begin->first < time - window_duration_) {
-      RTC_DCHECK_LE(window_begin->second, bytes_in_window);
-      bytes_in_window -= window_begin->second;
-      ++window_begin;
+    while (window_index_begin < packets.size() &&
+           packets[window_index_begin].timestamp < time - window_duration_) {
+      RTC_DCHECK_LE(packets[window_index_begin].size, bytes_in_window);
+      bytes_in_window -= packets[window_index_begin].size;
+      ++window_index_begin;
     }
     float window_duration_in_seconds =
         static_cast<float>(window_duration_) / kNumMicrosecsPerSec;
@@ -907,161 +1149,195 @@
   plot->AppendTimeSeries(std::move(bitrate_series));
 
   // Overlay the send-side bandwidth estimate over the outgoing bitrate.
-  TimeSeries loss_series("Loss-based estimate", LineStyle::kStep);
-  for (auto& loss_update : parsed_log_.bwe_loss_updates()) {
-    float x = ToCallTime(loss_update.log_time_us());
-    float y = static_cast<float>(loss_update.bitrate_bps) / 1000;
-    loss_series.points.emplace_back(x, y);
-  }
+  if (desired_direction == kOutgoingPacket) {
+    TimeSeries loss_series("Loss-based estimate", LineStyle::kStep);
+    for (auto& loss_update : bwe_loss_updates_) {
+      float x = ToCallTime(loss_update.timestamp);
+      float y = static_cast<float>(loss_update.new_bitrate) / 1000;
+      loss_series.points.emplace_back(x, y);
+    }
 
-  TimeSeries delay_series("Delay-based estimate", LineStyle::kStep);
-  IntervalSeries overusing_series("Overusing", "#ff8e82",
-                                  IntervalSeries::kHorizontal);
-  IntervalSeries underusing_series("Underusing", "#5092fc",
-                                   IntervalSeries::kHorizontal);
-  IntervalSeries normal_series("Normal", "#c4ffc4",
-                               IntervalSeries::kHorizontal);
-  IntervalSeries* last_series = &normal_series;
-  double last_detector_switch = 0.0;
+    TimeSeries delay_series("Delay-based estimate", LineStyle::kStep);
+    IntervalSeries overusing_series("Overusing", "#ff8e82",
+                                    IntervalSeries::kHorizontal);
+    IntervalSeries underusing_series("Underusing", "#5092fc",
+                                     IntervalSeries::kHorizontal);
+    IntervalSeries normal_series("Normal", "#c4ffc4",
+                                 IntervalSeries::kHorizontal);
+    IntervalSeries* last_series = &normal_series;
+    double last_detector_switch = 0.0;
 
-  BandwidthUsage last_detector_state = BandwidthUsage::kBwNormal;
+    BandwidthUsage last_detector_state = BandwidthUsage::kBwNormal;
 
-  for (auto& delay_update : parsed_log_.bwe_delay_updates()) {
-    float x = ToCallTime(delay_update.log_time_us());
-    float y = static_cast<float>(delay_update.bitrate_bps) / 1000;
+    for (auto& delay_update : bwe_delay_updates_) {
+      float x = ToCallTime(delay_update.timestamp);
+      float y = static_cast<float>(delay_update.bitrate_bps) / 1000;
 
-    if (last_detector_state != delay_update.detector_state) {
-      last_series->intervals.emplace_back(last_detector_switch, x);
-      last_detector_state = delay_update.detector_state;
-      last_detector_switch = x;
+      if (last_detector_state != delay_update.detector_state) {
+        last_series->intervals.emplace_back(last_detector_switch, x);
+        last_detector_state = delay_update.detector_state;
+        last_detector_switch = x;
 
-      switch (delay_update.detector_state) {
-        case BandwidthUsage::kBwNormal:
-          last_series = &normal_series;
-          break;
-        case BandwidthUsage::kBwUnderusing:
-          last_series = &underusing_series;
-          break;
-        case BandwidthUsage::kBwOverusing:
-          last_series = &overusing_series;
-          break;
-        case BandwidthUsage::kLast:
-          RTC_NOTREACHED();
+        switch (delay_update.detector_state) {
+          case BandwidthUsage::kBwNormal:
+            last_series = &normal_series;
+            break;
+          case BandwidthUsage::kBwUnderusing:
+            last_series = &underusing_series;
+            break;
+          case BandwidthUsage::kBwOverusing:
+            last_series = &overusing_series;
+            break;
+          case BandwidthUsage::kLast:
+            RTC_NOTREACHED();
+        }
+      }
+
+      delay_series.points.emplace_back(x, y);
+    }
+
+    RTC_CHECK(last_series);
+    last_series->intervals.emplace_back(last_detector_switch, end_time_);
+
+    TimeSeries created_series("Probe cluster created.", LineStyle::kNone,
+                              PointStyle::kHighlight);
+    for (auto& cluster : bwe_probe_cluster_created_events_) {
+      float x = ToCallTime(cluster.timestamp);
+      float y = static_cast<float>(cluster.bitrate_bps) / 1000;
+      created_series.points.emplace_back(x, y);
+    }
+
+    TimeSeries result_series("Probing results.", LineStyle::kNone,
+                             PointStyle::kHighlight);
+    for (auto& result : bwe_probe_result_events_) {
+      if (result.bitrate_bps) {
+        float x = ToCallTime(result.timestamp);
+        float y = static_cast<float>(*result.bitrate_bps) / 1000;
+        result_series.points.emplace_back(x, y);
       }
     }
 
-    delay_series.points.emplace_back(x, y);
-  }
-
-  RTC_CHECK(last_series);
-  last_series->intervals.emplace_back(last_detector_switch, end_time_);
-
-  TimeSeries created_series("Probe cluster created.", LineStyle::kNone,
-                            PointStyle::kHighlight);
-  for (auto& cluster : parsed_log_.bwe_probe_cluster_created_events()) {
-    float x = ToCallTime(cluster.log_time_us());
-    float y = static_cast<float>(cluster.bitrate_bps) / 1000;
-    created_series.points.emplace_back(x, y);
-  }
-
-  TimeSeries result_series("Probing results.", LineStyle::kNone,
-                           PointStyle::kHighlight);
-  for (auto& result : parsed_log_.bwe_probe_result_events()) {
-    if (result.bitrate_bps) {
-      float x = ToCallTime(result.log_time_us());
-      float y = static_cast<float>(*result.bitrate_bps) / 1000;
-      result_series.points.emplace_back(x, y);
+    IntervalSeries alr_state("ALR", "#555555", IntervalSeries::kHorizontal);
+    bool previously_in_alr = false;
+    int64_t alr_start = 0;
+    for (auto& alr : alr_state_events_) {
+      float y = ToCallTime(alr.timestamp);
+      if (!previously_in_alr && alr.in_alr) {
+        alr_start = alr.timestamp;
+        previously_in_alr = true;
+      } else if (previously_in_alr && !alr.in_alr) {
+        float x = ToCallTime(alr_start);
+        alr_state.intervals.emplace_back(x, y);
+        previously_in_alr = false;
+      }
     }
-  }
 
-  IntervalSeries alr_state("ALR", "#555555", IntervalSeries::kHorizontal);
-  bool previously_in_alr = false;
-  int64_t alr_start = 0;
-  for (auto& alr : parsed_log_.alr_state_events()) {
-    float y = ToCallTime(alr.log_time_us());
-    if (!previously_in_alr && alr.in_alr) {
-      alr_start = alr.log_time_us();
-      previously_in_alr = true;
-    } else if (previously_in_alr && !alr.in_alr) {
+    if (previously_in_alr) {
       float x = ToCallTime(alr_start);
+      float y = ToCallTime(end_time_);
       alr_state.intervals.emplace_back(x, y);
-      previously_in_alr = false;
+    }
+
+    if (show_detector_state) {
+      plot->AppendIntervalSeries(std::move(overusing_series));
+      plot->AppendIntervalSeries(std::move(underusing_series));
+      plot->AppendIntervalSeries(std::move(normal_series));
+    }
+
+    if (show_alr_state) {
+      plot->AppendIntervalSeries(std::move(alr_state));
+    }
+    plot->AppendTimeSeries(std::move(loss_series));
+    plot->AppendTimeSeries(std::move(delay_series));
+    plot->AppendTimeSeries(std::move(created_series));
+    plot->AppendTimeSeries(std::move(result_series));
+  }
+
+  // Overlay the incoming REMB over the outgoing bitrate
+  // and outgoing REMB over incoming bitrate.
+  PacketDirection remb_direction =
+      desired_direction == kOutgoingPacket ? kIncomingPacket : kOutgoingPacket;
+  TimeSeries remb_series("Remb", LineStyle::kStep);
+  std::multimap<uint64_t, const LoggedRtcpPacket*> remb_packets;
+  for (const auto& kv : rtcp_packets_) {
+    if (kv.first.GetDirection() == remb_direction) {
+      for (const LoggedRtcpPacket& rtcp_packet : kv.second) {
+        if (rtcp_packet.type == kRtcpRemb) {
+          remb_packets.insert(
+              std::make_pair(rtcp_packet.timestamp, &rtcp_packet));
+        }
+      }
     }
   }
 
-  if (previously_in_alr) {
-    float x = ToCallTime(alr_start);
-    float y = ToCallTime(end_time_);
-    alr_state.intervals.emplace_back(x, y);
-  }
-
-  if (show_detector_state) {
-    plot->AppendIntervalSeries(std::move(overusing_series));
-    plot->AppendIntervalSeries(std::move(underusing_series));
-    plot->AppendIntervalSeries(std::move(normal_series));
-  }
-
-  if (show_alr_state) {
-    plot->AppendIntervalSeries(std::move(alr_state));
-  }
-  plot->AppendTimeSeries(std::move(loss_series));
-  plot->AppendTimeSeries(std::move(delay_series));
-  plot->AppendTimeSeries(std::move(created_series));
-  plot->AppendTimeSeries(std::move(result_series));
-
-  // Overlay the incoming REMB over the outgoing bitrate.
-  TimeSeries remb_series("Remb", LineStyle::kStep);
-  for (const auto& rtcp : parsed_log_.rembs(kIncomingPacket)) {
-    float x = ToCallTime(rtcp.log_time_us());
-    float y = static_cast<float>(rtcp.remb.bitrate_bps()) / 1000;
+  for (const auto& kv : remb_packets) {
+    const LoggedRtcpPacket* const rtcp = kv.second;
+    const rtcp::Remb* const remb = static_cast<rtcp::Remb*>(rtcp->packet.get());
+    float x = ToCallTime(rtcp->timestamp);
+    float y = static_cast<float>(remb->bitrate_bps()) / 1000;
     remb_series.points.emplace_back(x, y);
   }
   plot->AppendTimeSeriesIfNotEmpty(std::move(remb_series));
 
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
   plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin);
-  plot->SetTitle("Outgoing RTP bitrate");
+  if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
+    plot->SetTitle("Incoming RTP bitrate");
+  } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
+    plot->SetTitle("Outgoing RTP bitrate");
+  }
 }
 
 // For each SSRC, plot the bandwidth used by that stream.
-void EventLogAnalyzer::CreateStreamBitrateGraph(PacketDirection direction,
-                                                Plot* plot) {
-  for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) {
-    // Filter on SSRC.
-    if (!MatchingSsrc(stream.ssrc, desired_ssrc_)) {
+void EventLogAnalyzer::CreateStreamBitrateGraph(
+    PacketDirection desired_direction,
+    Plot* plot) {
+  for (auto& kv : rtp_packets_) {
+    StreamId stream_id = kv.first;
+    const std::vector<LoggedRtpPacket>& packet_stream = kv.second;
+    // Filter on direction and SSRC.
+    if (stream_id.GetDirection() != desired_direction ||
+        !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) {
       continue;
     }
 
-    TimeSeries time_series(GetStreamName(direction, stream.ssrc),
-                           LineStyle::kLine);
-    auto GetPacketSizeKilobits = [](const LoggedRtpPacket& packet) {
-      return packet.total_length * 8.0 / 1000.0;
-    };
+    TimeSeries time_series(GetStreamName(stream_id), LineStyle::kLine);
     MovingAverage<LoggedRtpPacket, double>(
-        GetPacketSizeKilobits, stream.packet_view, begin_time_, end_time_,
-        window_duration_, step_, &time_series);
+        [](const LoggedRtpPacket& packet) {
+          return packet.total_length * 8.0 / 1000.0;
+        },
+        packet_stream, begin_time_, end_time_, window_duration_, step_,
+        &time_series);
     plot->AppendTimeSeries(std::move(time_series));
   }
 
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
   plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin);
-  plot->SetTitle(GetDirectionAsString(direction) + " bitrate per stream");
+  if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
+    plot->SetTitle("Incoming bitrate per stream");
+  } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
+    plot->SetTitle("Outgoing bitrate per stream");
+  }
 }
 
 void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
-  using RtpPacketType = LoggedRtpPacketOutgoing;
-  using TransportFeedbackType = LoggedRtcpPacketTransportFeedback;
+  std::multimap<uint64_t, const LoggedRtpPacket*> outgoing_rtp;
+  std::multimap<uint64_t, const LoggedRtcpPacket*> incoming_rtcp;
 
-  // TODO(terelius): This could be provided by the parser.
-  std::multimap<int64_t, const RtpPacketType*> outgoing_rtp;
-  for (const auto& stream : parsed_log_.outgoing_rtp_packets_by_ssrc()) {
-    for (const RtpPacketType& rtp_packet : stream.outgoing_packets)
-      outgoing_rtp.insert(
-          std::make_pair(rtp_packet.rtp.log_time_us(), &rtp_packet));
+  for (const auto& kv : rtp_packets_) {
+    if (kv.first.GetDirection() == PacketDirection::kOutgoingPacket) {
+      for (const LoggedRtpPacket& rtp_packet : kv.second)
+        outgoing_rtp.insert(std::make_pair(rtp_packet.timestamp, &rtp_packet));
+    }
   }
 
-  const std::vector<TransportFeedbackType>& incoming_rtcp =
-      parsed_log_.transport_feedbacks(kIncomingPacket);
+  for (const auto& kv : rtcp_packets_) {
+    if (kv.first.GetDirection() == PacketDirection::kIncomingPacket) {
+      for (const LoggedRtcpPacket& rtcp_packet : kv.second)
+        incoming_rtcp.insert(
+            std::make_pair(rtcp_packet.timestamp, &rtcp_packet));
+    }
+  }
 
   SimulatedClock clock(0);
   BitrateObserver observer;
@@ -1091,7 +1367,7 @@
 
   auto NextRtcpTime = [&]() {
     if (rtcp_iterator != incoming_rtcp.end())
-      return static_cast<int64_t>(rtcp_iterator->log_time_us());
+      return static_cast<int64_t>(rtcp_iterator->first);
     return std::numeric_limits<int64_t>::max();
   };
 
@@ -1122,38 +1398,41 @@
     clock.AdvanceTimeMicroseconds(time_us - clock.TimeInMicroseconds());
     if (clock.TimeInMicroseconds() >= NextRtcpTime()) {
       RTC_DCHECK_EQ(clock.TimeInMicroseconds(), NextRtcpTime());
-      cc.OnTransportFeedback(rtcp_iterator->transport_feedback);
-      std::vector<PacketFeedback> feedback = cc.GetTransportFeedbackVector();
-      SortPacketFeedbackVector(&feedback);
-      rtc::Optional<uint32_t> bitrate_bps;
-      if (!feedback.empty()) {
+      const LoggedRtcpPacket& rtcp = *rtcp_iterator->second;
+      if (rtcp.type == kRtcpTransportFeedback) {
+        cc.OnTransportFeedback(
+            *static_cast<rtcp::TransportFeedback*>(rtcp.packet.get()));
+        std::vector<PacketFeedback> feedback = cc.GetTransportFeedbackVector();
+        SortPacketFeedbackVector(&feedback);
+        rtc::Optional<uint32_t> bitrate_bps;
+        if (!feedback.empty()) {
 #if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
-        acknowledged_bitrate_estimator.IncomingPacketFeedbackVector(feedback);
+          acknowledged_bitrate_estimator.IncomingPacketFeedbackVector(feedback);
 #endif  // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
-        for (const PacketFeedback& packet : feedback)
-          acked_bitrate.Update(packet.payload_size, packet.arrival_time_ms);
-        bitrate_bps = acked_bitrate.Rate(feedback.back().arrival_time_ms);
+          for (const PacketFeedback& packet : feedback)
+            acked_bitrate.Update(packet.payload_size, packet.arrival_time_ms);
+          bitrate_bps = acked_bitrate.Rate(feedback.back().arrival_time_ms);
+        }
+        float x = ToCallTime(clock.TimeInMicroseconds());
+        float y = bitrate_bps.value_or(0) / 1000;
+        acked_time_series.points.emplace_back(x, y);
+#if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
+        y = acknowledged_bitrate_estimator.bitrate_bps().value_or(0) / 1000;
+        acked_estimate_time_series.points.emplace_back(x, y);
+#endif  // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
       }
-      float x = ToCallTime(clock.TimeInMicroseconds());
-      float y = bitrate_bps.value_or(0) / 1000;
-      acked_time_series.points.emplace_back(x, y);
-#if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
-      y = acknowledged_bitrate_estimator.bitrate_bps().value_or(0) / 1000;
-      acked_estimate_time_series.points.emplace_back(x, y);
-#endif  // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
       ++rtcp_iterator;
     }
     if (clock.TimeInMicroseconds() >= NextRtpTime()) {
       RTC_DCHECK_EQ(clock.TimeInMicroseconds(), NextRtpTime());
-      const RtpPacketType& rtp_packet = *rtp_iterator->second;
-      if (rtp_packet.rtp.header.extension.hasTransportSequenceNumber) {
-        RTC_DCHECK(rtp_packet.rtp.header.extension.hasTransportSequenceNumber);
-        cc.AddPacket(rtp_packet.rtp.header.ssrc,
-                     rtp_packet.rtp.header.extension.transportSequenceNumber,
-                     rtp_packet.rtp.total_length, PacedPacketInfo());
+      const LoggedRtpPacket& rtp = *rtp_iterator->second;
+      if (rtp.header.extension.hasTransportSequenceNumber) {
+        RTC_DCHECK(rtp.header.extension.hasTransportSequenceNumber);
+        cc.AddPacket(rtp.header.ssrc,
+                     rtp.header.extension.transportSequenceNumber,
+                     rtp.total_length, PacedPacketInfo());
         rtc::SentPacket sent_packet(
-            rtp_packet.rtp.header.extension.transportSequenceNumber,
-            rtp_packet.rtp.log_time_us() / 1000);
+            rtp.header.extension.transportSequenceNumber, rtp.timestamp / 1000);
         cc.OnSentPacket(sent_packet);
       }
       ++rtp_iterator;
@@ -1182,7 +1461,6 @@
 }
 
 void EventLogAnalyzer::CreateReceiveSideBweSimulationGraph(Plot* plot) {
-  using RtpPacketType = LoggedRtpPacketIncoming;
   class RembInterceptingPacketRouter : public PacketRouter {
    public:
     void OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
@@ -1203,19 +1481,19 @@
     bool bitrate_updated_;
   };
 
-  std::multimap<int64_t, const RtpPacketType*> incoming_rtp;
+  std::multimap<uint64_t, const LoggedRtpPacket*> incoming_rtp;
 
-  for (const auto& stream : parsed_log_.incoming_rtp_packets_by_ssrc()) {
-    if (IsVideoSsrc(kIncomingPacket, stream.ssrc)) {
-      for (const auto& rtp_packet : stream.incoming_packets)
-        incoming_rtp.insert(
-            std::make_pair(rtp_packet.rtp.log_time_us(), &rtp_packet));
+  for (const auto& kv : rtp_packets_) {
+    if (kv.first.GetDirection() == PacketDirection::kIncomingPacket &&
+        IsVideoSsrc(kv.first)) {
+      for (const LoggedRtpPacket& rtp_packet : kv.second)
+        incoming_rtp.insert(std::make_pair(rtp_packet.timestamp, &rtp_packet));
     }
   }
 
   SimulatedClock clock(0);
   RembInterceptingPacketRouter packet_router;
-  // TODO(terelius): The PacketRouter is used as the RemoteBitrateObserver.
+  // TODO(terelius): The PacketRrouter is the used as the RemoteBitrateObserver.
   // Is this intentional?
   ReceiveSideCongestionController rscc(&clock, &packet_router);
   // TODO(holmer): Log the call config and use that here instead.
@@ -1229,12 +1507,12 @@
   RateStatistics acked_bitrate(250, 8000);
   int64_t last_update_us = 0;
   for (const auto& kv : incoming_rtp) {
-    const RtpPacketType& packet = *kv.second;
-    int64_t arrival_time_ms = packet.rtp.log_time_us() / 1000;
-    size_t payload = packet.rtp.total_length; /*Should subtract header?*/
-    clock.AdvanceTimeMicroseconds(packet.rtp.log_time_us() -
+    const LoggedRtpPacket& packet = *kv.second;
+    int64_t arrival_time_ms = packet.timestamp / 1000;
+    size_t payload = packet.total_length; /*Should subtract header?*/
+    clock.AdvanceTimeMicroseconds(packet.timestamp -
                                   clock.TimeInMicroseconds());
-    rscc.OnReceivedPacket(arrival_time_ms, payload, packet.rtp.header);
+    rscc.OnReceivedPacket(arrival_time_ms, payload, packet.header);
     acked_bitrate.Update(payload, arrival_time_ms);
     rtc::Optional<uint32_t> bitrate_bps = acked_bitrate.Rate(arrival_time_ms);
     if (bitrate_bps) {
@@ -1260,19 +1538,23 @@
 }
 
 void EventLogAnalyzer::CreateNetworkDelayFeedbackGraph(Plot* plot) {
-  using RtpPacketType = LoggedRtpPacketOutgoing;
-  using TransportFeedbackType = LoggedRtcpPacketTransportFeedback;
+  std::multimap<uint64_t, const LoggedRtpPacket*> outgoing_rtp;
+  std::multimap<uint64_t, const LoggedRtcpPacket*> incoming_rtcp;
 
-  // TODO(terelius): This could be provided by the parser.
-  std::multimap<int64_t, const RtpPacketType*> outgoing_rtp;
-  for (const auto& stream : parsed_log_.outgoing_rtp_packets_by_ssrc()) {
-    for (const RtpPacketType& rtp_packet : stream.outgoing_packets)
-      outgoing_rtp.insert(
-          std::make_pair(rtp_packet.rtp.log_time_us(), &rtp_packet));
+  for (const auto& kv : rtp_packets_) {
+    if (kv.first.GetDirection() == PacketDirection::kOutgoingPacket) {
+      for (const LoggedRtpPacket& rtp_packet : kv.second)
+        outgoing_rtp.insert(std::make_pair(rtp_packet.timestamp, &rtp_packet));
+    }
   }
 
-  const std::vector<TransportFeedbackType>& incoming_rtcp =
-      parsed_log_.transport_feedbacks(kIncomingPacket);
+  for (const auto& kv : rtcp_packets_) {
+    if (kv.first.GetDirection() == PacketDirection::kIncomingPacket) {
+      for (const LoggedRtcpPacket& rtcp_packet : kv.second)
+        incoming_rtcp.insert(
+            std::make_pair(rtcp_packet.timestamp, &rtcp_packet));
+    }
+  }
 
   SimulatedClock clock(0);
   TransportFeedbackAdapter feedback_adapter(&clock);
@@ -1294,7 +1576,7 @@
 
   auto NextRtcpTime = [&]() {
     if (rtcp_iterator != incoming_rtcp.end())
-      return static_cast<int64_t>(rtcp_iterator->log_time_us());
+      return static_cast<int64_t>(rtcp_iterator->first);
     return std::numeric_limits<int64_t>::max();
   };
 
@@ -1304,34 +1586,37 @@
     clock.AdvanceTimeMicroseconds(time_us - clock.TimeInMicroseconds());
     if (clock.TimeInMicroseconds() >= NextRtcpTime()) {
       RTC_DCHECK_EQ(clock.TimeInMicroseconds(), NextRtcpTime());
-      feedback_adapter.OnTransportFeedback(rtcp_iterator->transport_feedback);
-      std::vector<PacketFeedback> feedback =
-          feedback_adapter.GetTransportFeedbackVector();
-      SortPacketFeedbackVector(&feedback);
-      for (const PacketFeedback& packet : feedback) {
-        float x = ToCallTime(clock.TimeInMicroseconds());
-        if (packet.send_time_ms == PacketFeedback::kNoSendTime) {
-          late_feedback_series.points.emplace_back(x, prev_y);
-          continue;
+      const LoggedRtcpPacket& rtcp = *rtcp_iterator->second;
+      if (rtcp.type == kRtcpTransportFeedback) {
+        feedback_adapter.OnTransportFeedback(
+            *static_cast<rtcp::TransportFeedback*>(rtcp.packet.get()));
+        std::vector<PacketFeedback> feedback =
+            feedback_adapter.GetTransportFeedbackVector();
+        SortPacketFeedbackVector(&feedback);
+        for (const PacketFeedback& packet : feedback) {
+          float x = ToCallTime(clock.TimeInMicroseconds());
+          if (packet.send_time_ms == PacketFeedback::kNoSendTime) {
+            late_feedback_series.points.emplace_back(x, prev_y);
+            continue;
+          }
+          int64_t y = packet.arrival_time_ms - packet.send_time_ms;
+          prev_y = y;
+          estimated_base_delay_ms = std::min(y, estimated_base_delay_ms);
+          time_series.points.emplace_back(x, y);
         }
-        int64_t y = packet.arrival_time_ms - packet.send_time_ms;
-        prev_y = y;
-        estimated_base_delay_ms = std::min(y, estimated_base_delay_ms);
-        time_series.points.emplace_back(x, y);
       }
       ++rtcp_iterator;
     }
     if (clock.TimeInMicroseconds() >= NextRtpTime()) {
       RTC_DCHECK_EQ(clock.TimeInMicroseconds(), NextRtpTime());
-      const RtpPacketType& rtp_packet = *rtp_iterator->second;
-      if (rtp_packet.rtp.header.extension.hasTransportSequenceNumber) {
-        feedback_adapter.AddPacket(
-            rtp_packet.rtp.header.ssrc,
-            rtp_packet.rtp.header.extension.transportSequenceNumber,
-            rtp_packet.rtp.total_length, PacedPacketInfo());
+      const LoggedRtpPacket& rtp = *rtp_iterator->second;
+      if (rtp.header.extension.hasTransportSequenceNumber) {
+        RTC_DCHECK(rtp.header.extension.hasTransportSequenceNumber);
+        feedback_adapter.AddPacket(rtp.header.ssrc,
+                                   rtp.header.extension.transportSequenceNumber,
+                                   rtp.total_length, PacedPacketInfo());
         feedback_adapter.OnSentPacket(
-            rtp_packet.rtp.header.extension.transportSequenceNumber,
-            rtp_packet.rtp.log_time_us() / 1000);
+            rtp.header.extension.transportSequenceNumber, rtp.timestamp / 1000);
       }
       ++rtp_iterator;
     }
@@ -1352,10 +1637,40 @@
   plot->SetTitle("Network Delay Change.");
 }
 
+std::vector<std::pair<int64_t, int64_t>> EventLogAnalyzer::GetFrameTimestamps()
+    const {
+  std::vector<std::pair<int64_t, int64_t>> timestamps;
+  size_t largest_stream_size = 0;
+  const std::vector<LoggedRtpPacket>* largest_video_stream = nullptr;
+  // Find the incoming video stream with the most number of packets that is
+  // not rtx.
+  for (const auto& kv : rtp_packets_) {
+    if (kv.first.GetDirection() == kIncomingPacket &&
+        video_ssrcs_.find(kv.first) != video_ssrcs_.end() &&
+        rtx_ssrcs_.find(kv.first) == rtx_ssrcs_.end() &&
+        kv.second.size() > largest_stream_size) {
+      largest_stream_size = kv.second.size();
+      largest_video_stream = &kv.second;
+    }
+  }
+  if (largest_video_stream == nullptr) {
+    for (auto& packet : *largest_video_stream) {
+      if (packet.header.markerBit) {
+        int64_t capture_ms = packet.header.timestamp / 90.0;
+        int64_t arrival_ms = packet.timestamp / 1000.0;
+        timestamps.push_back(std::make_pair(capture_ms, arrival_ms));
+      }
+    }
+  }
+  return timestamps;
+}
+
 void EventLogAnalyzer::CreatePacerDelayGraph(Plot* plot) {
-  for (const auto& stream : parsed_log_.outgoing_rtp_packets_by_ssrc()) {
-    const std::vector<LoggedRtpPacketOutgoing>& packets =
-        stream.outgoing_packets;
+  for (const auto& kv : rtp_packets_) {
+    const std::vector<LoggedRtpPacket>& packets = kv.second;
+    StreamId stream_id = kv.first;
+    if (stream_id.GetDirection() == kIncomingPacket)
+      continue;
 
     if (packets.size() < 2) {
       RTC_LOG(LS_WARNING)
@@ -1363,15 +1678,11 @@
              "pacer delay with less than 2 packets in the stream";
       continue;
     }
-    int64_t end_time_us = log_segments_.empty()
-                              ? std::numeric_limits<int64_t>::max()
-                              : log_segments_.front().second;
     rtc::Optional<uint32_t> estimated_frequency =
-        EstimateRtpClockFrequency(packets, end_time_us);
+        EstimateRtpClockFrequency(packets);
     if (!estimated_frequency)
       continue;
-    if (IsVideoSsrc(kOutgoingPacket, stream.ssrc) &&
-        *estimated_frequency != 90000) {
+    if (IsVideoSsrc(stream_id) && *estimated_frequency != 90000) {
       RTC_LOG(LS_WARNING)
           << "Video stream should use a 90 kHz clock but appears to use "
           << *estimated_frequency / 1000 << ". Discarding.";
@@ -1379,22 +1690,21 @@
     }
 
     TimeSeries pacer_delay_series(
-        GetStreamName(kOutgoingPacket, stream.ssrc) + "(" +
+        GetStreamName(stream_id) + "(" +
             std::to_string(*estimated_frequency / 1000) + " kHz)",
         LineStyle::kLine, PointStyle::kHighlight);
     SeqNumUnwrapper<uint32_t> timestamp_unwrapper;
     uint64_t first_capture_timestamp =
-        timestamp_unwrapper.Unwrap(packets.front().rtp.header.timestamp);
-    uint64_t first_send_timestamp = packets.front().rtp.log_time_us();
-    for (const auto& packet : packets) {
+        timestamp_unwrapper.Unwrap(packets.front().header.timestamp);
+    uint64_t first_send_timestamp = packets.front().timestamp;
+    for (LoggedRtpPacket packet : packets) {
       double capture_time_ms = (static_cast<double>(timestamp_unwrapper.Unwrap(
-                                    packet.rtp.header.timestamp)) -
+                                    packet.header.timestamp)) -
                                 first_capture_timestamp) /
                                *estimated_frequency * 1000;
       double send_time_ms =
-          static_cast<double>(packet.rtp.log_time_us() - first_send_timestamp) /
-          1000;
-      float x = ToCallTime(packet.rtp.log_time_us());
+          static_cast<double>(packet.timestamp - first_send_timestamp) / 1000;
+      float x = ToCallTime(packet.timestamp);
       float y = send_time_ms - capture_time_ms;
       pacer_delay_series.points.emplace_back(x, y);
     }
@@ -1407,52 +1717,58 @@
       "Delay from capture to send time. (First packet normalized to 0.)");
 }
 
-void EventLogAnalyzer::CreateTimestampGraph(PacketDirection direction,
-                                            Plot* plot) {
-  for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) {
-    TimeSeries rtp_timestamps(
-        GetStreamName(direction, stream.ssrc) + " capture-time",
-        LineStyle::kLine, PointStyle::kHighlight);
-    for (const auto& packet : stream.packet_view) {
-      float x = ToCallTime(packet.log_time_us());
-      float y = packet.header.timestamp;
-      rtp_timestamps.points.emplace_back(x, y);
-    }
-    plot->AppendTimeSeries(std::move(rtp_timestamps));
+void EventLogAnalyzer::CreateTimestampGraph(Plot* plot) {
+  for (const auto& kv : rtp_packets_) {
+    const std::vector<LoggedRtpPacket>& rtp_packets = kv.second;
+    StreamId stream_id = kv.first;
 
-    TimeSeries rtcp_timestamps(
-        GetStreamName(direction, stream.ssrc) + " rtcp capture-time",
-        LineStyle::kLine, PointStyle::kHighlight);
-    // TODO(terelius): Why only sender reports?
-    const auto& sender_reports = parsed_log_.sender_reports(direction);
-    for (const auto& rtcp : sender_reports) {
-      if (rtcp.sr.sender_ssrc() != stream.ssrc)
-        continue;
-      float x = ToCallTime(rtcp.log_time_us());
-      float y = rtcp.sr.rtp_timestamp();
-      rtcp_timestamps.points.emplace_back(x, y);
+    {
+      TimeSeries timestamp_data(GetStreamName(stream_id) + " capture-time",
+                                LineStyle::kLine, PointStyle::kHighlight);
+      for (LoggedRtpPacket packet : rtp_packets) {
+        float x = ToCallTime(packet.timestamp);
+        float y = packet.header.timestamp;
+        timestamp_data.points.emplace_back(x, y);
+      }
+      plot->AppendTimeSeries(std::move(timestamp_data));
     }
-    plot->AppendTimeSeriesIfNotEmpty(std::move(rtcp_timestamps));
+
+    {
+      auto kv = rtcp_packets_.find(stream_id);
+      if (kv != rtcp_packets_.end()) {
+        const auto& packets = kv->second;
+        TimeSeries timestamp_data(
+            GetStreamName(stream_id) + " rtcp capture-time", LineStyle::kLine,
+            PointStyle::kHighlight);
+        for (const LoggedRtcpPacket& rtcp : packets) {
+          if (rtcp.type != kRtcpSr)
+            continue;
+          rtcp::SenderReport* sr;
+          sr = static_cast<rtcp::SenderReport*>(rtcp.packet.get());
+          float x = ToCallTime(rtcp.timestamp);
+          float y = sr->rtp_timestamp();
+          timestamp_data.points.emplace_back(x, y);
+        }
+        plot->AppendTimeSeries(std::move(timestamp_data));
+      }
+    }
   }
 
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
-  plot->SetSuggestedYAxis(0, 1, "RTP timestamp", kBottomMargin, kTopMargin);
-  plot->SetTitle(GetDirectionAsString(direction) + " timestamps");
+  plot->SetSuggestedYAxis(0, 1, "Timestamp (90khz)", kBottomMargin, kTopMargin);
+  plot->SetTitle("Timestamps");
 }
 
 void EventLogAnalyzer::CreateAudioEncoderTargetBitrateGraph(Plot* plot) {
   TimeSeries time_series("Audio encoder target bitrate", LineStyle::kLine,
                          PointStyle::kHighlight);
-  auto GetAnaBitrateBps = [](const LoggedAudioNetworkAdaptationEvent& ana_event)
-      -> rtc::Optional<float> {
-    if (ana_event.config.bitrate_bps)
-      return rtc::Optional<float>(
-          static_cast<float>(*ana_event.config.bitrate_bps));
-    return rtc::nullopt;
-  };
-  ProcessPoints<LoggedAudioNetworkAdaptationEvent>(
-      GetAnaBitrateBps, parsed_log_.audio_network_adaptation_events(),
-      begin_time_, &time_series);
+  ProcessPoints<AudioNetworkAdaptationEvent>(
+      [](const AudioNetworkAdaptationEvent& ana_event) -> rtc::Optional<float> {
+        if (ana_event.config.bitrate_bps)
+          return static_cast<float>(*ana_event.config.bitrate_bps);
+        return rtc::nullopt;
+      },
+      audio_network_adaptation_events_, begin_time_, &time_series);
   plot->AppendTimeSeries(std::move(time_series));
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
   plot->SetSuggestedYAxis(0, 1, "Bitrate (bps)", kBottomMargin, kTopMargin);
@@ -1462,16 +1778,14 @@
 void EventLogAnalyzer::CreateAudioEncoderFrameLengthGraph(Plot* plot) {
   TimeSeries time_series("Audio encoder frame length", LineStyle::kLine,
                          PointStyle::kHighlight);
-  auto GetAnaFrameLengthMs =
-      [](const LoggedAudioNetworkAdaptationEvent& ana_event) {
+  ProcessPoints<AudioNetworkAdaptationEvent>(
+      [](const AudioNetworkAdaptationEvent& ana_event) {
         if (ana_event.config.frame_length_ms)
           return rtc::Optional<float>(
               static_cast<float>(*ana_event.config.frame_length_ms));
         return rtc::Optional<float>();
-      };
-  ProcessPoints<LoggedAudioNetworkAdaptationEvent>(
-      GetAnaFrameLengthMs, parsed_log_.audio_network_adaptation_events(),
-      begin_time_, &time_series);
+      },
+      audio_network_adaptation_events_, begin_time_, &time_series);
   plot->AppendTimeSeries(std::move(time_series));
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
   plot->SetSuggestedYAxis(0, 1, "Frame length (ms)", kBottomMargin, kTopMargin);
@@ -1481,16 +1795,14 @@
 void EventLogAnalyzer::CreateAudioEncoderPacketLossGraph(Plot* plot) {
   TimeSeries time_series("Audio encoder uplink packet loss fraction",
                          LineStyle::kLine, PointStyle::kHighlight);
-  auto GetAnaPacketLoss =
-      [](const LoggedAudioNetworkAdaptationEvent& ana_event) {
+  ProcessPoints<AudioNetworkAdaptationEvent>(
+      [](const AudioNetworkAdaptationEvent& ana_event) {
         if (ana_event.config.uplink_packet_loss_fraction)
           return rtc::Optional<float>(static_cast<float>(
               *ana_event.config.uplink_packet_loss_fraction));
         return rtc::Optional<float>();
-      };
-  ProcessPoints<LoggedAudioNetworkAdaptationEvent>(
-      GetAnaPacketLoss, parsed_log_.audio_network_adaptation_events(),
-      begin_time_, &time_series);
+      },
+      audio_network_adaptation_events_, begin_time_, &time_series);
   plot->AppendTimeSeries(std::move(time_series));
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
   plot->SetSuggestedYAxis(0, 10, "Percent lost packets", kBottomMargin,
@@ -1501,16 +1813,14 @@
 void EventLogAnalyzer::CreateAudioEncoderEnableFecGraph(Plot* plot) {
   TimeSeries time_series("Audio encoder FEC", LineStyle::kLine,
                          PointStyle::kHighlight);
-  auto GetAnaFecEnabled =
-      [](const LoggedAudioNetworkAdaptationEvent& ana_event) {
+  ProcessPoints<AudioNetworkAdaptationEvent>(
+      [](const AudioNetworkAdaptationEvent& ana_event) {
         if (ana_event.config.enable_fec)
           return rtc::Optional<float>(
               static_cast<float>(*ana_event.config.enable_fec));
         return rtc::Optional<float>();
-      };
-  ProcessPoints<LoggedAudioNetworkAdaptationEvent>(
-      GetAnaFecEnabled, parsed_log_.audio_network_adaptation_events(),
-      begin_time_, &time_series);
+      },
+      audio_network_adaptation_events_, begin_time_, &time_series);
   plot->AppendTimeSeries(std::move(time_series));
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
   plot->SetSuggestedYAxis(0, 1, "FEC (false/true)", kBottomMargin, kTopMargin);
@@ -1520,16 +1830,14 @@
 void EventLogAnalyzer::CreateAudioEncoderEnableDtxGraph(Plot* plot) {
   TimeSeries time_series("Audio encoder DTX", LineStyle::kLine,
                          PointStyle::kHighlight);
-  auto GetAnaDtxEnabled =
-      [](const LoggedAudioNetworkAdaptationEvent& ana_event) {
+  ProcessPoints<AudioNetworkAdaptationEvent>(
+      [](const AudioNetworkAdaptationEvent& ana_event) {
         if (ana_event.config.enable_dtx)
           return rtc::Optional<float>(
               static_cast<float>(*ana_event.config.enable_dtx));
         return rtc::Optional<float>();
-      };
-  ProcessPoints<LoggedAudioNetworkAdaptationEvent>(
-      GetAnaDtxEnabled, parsed_log_.audio_network_adaptation_events(),
-      begin_time_, &time_series);
+      },
+      audio_network_adaptation_events_, begin_time_, &time_series);
   plot->AppendTimeSeries(std::move(time_series));
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
   plot->SetSuggestedYAxis(0, 1, "DTX (false/true)", kBottomMargin, kTopMargin);
@@ -1539,16 +1847,14 @@
 void EventLogAnalyzer::CreateAudioEncoderNumChannelsGraph(Plot* plot) {
   TimeSeries time_series("Audio encoder number of channels", LineStyle::kLine,
                          PointStyle::kHighlight);
-  auto GetAnaNumChannels =
-      [](const LoggedAudioNetworkAdaptationEvent& ana_event) {
+  ProcessPoints<AudioNetworkAdaptationEvent>(
+      [](const AudioNetworkAdaptationEvent& ana_event) {
         if (ana_event.config.num_channels)
           return rtc::Optional<float>(
               static_cast<float>(*ana_event.config.num_channels));
         return rtc::Optional<float>();
-      };
-  ProcessPoints<LoggedAudioNetworkAdaptationEvent>(
-      GetAnaNumChannels, parsed_log_.audio_network_adaptation_events(),
-      begin_time_, &time_series);
+      },
+      audio_network_adaptation_events_, begin_time_, &time_series);
   plot->AppendTimeSeries(std::move(time_series));
   plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin);
   plot->SetSuggestedYAxis(0, 1, "Number of channels (1 (mono)/2 (stereo))",
@@ -1560,9 +1866,9 @@
  public:
   // Does not take any ownership, and all pointers must refer to valid objects
   // that outlive the one constructed.
-  NetEqStreamInput(const std::vector<LoggedRtpPacketIncoming>* packet_stream,
-                   const std::vector<int64_t>* output_events_us,
-                   rtc::Optional<int64_t> end_time_us)
+  NetEqStreamInput(const std::vector<LoggedRtpPacket>* packet_stream,
+                   const std::vector<uint64_t>* output_events_us,
+                   rtc::Optional<uint64_t> end_time_us)
       : packet_stream_(*packet_stream),
         packet_stream_it_(packet_stream_.begin()),
         output_events_us_it_(output_events_us->begin()),
@@ -1576,11 +1882,11 @@
     if (packet_stream_it_ == packet_stream_.end()) {
       return rtc::nullopt;
     }
-    if (end_time_us_ && packet_stream_it_->rtp.log_time_us() > *end_time_us_) {
+    if (end_time_us_ && packet_stream_it_->timestamp > *end_time_us_) {
       return rtc::nullopt;
     }
     // Convert from us to ms.
-    return packet_stream_it_->rtp.log_time_us() / 1000;
+    return packet_stream_it_->timestamp / 1000;
   }
 
   rtc::Optional<int64_t> NextOutputEventTime() const override {
@@ -1599,14 +1905,14 @@
       return std::unique_ptr<PacketData>();
     }
     std::unique_ptr<PacketData> packet_data(new PacketData());
-    packet_data->header = packet_stream_it_->rtp.header;
+    packet_data->header = packet_stream_it_->header;
     // Convert from us to ms.
-    packet_data->time_ms = packet_stream_it_->rtp.log_time_us() / 1000.0;
+    packet_data->time_ms = packet_stream_it_->timestamp / 1000.0;
 
     // This is a header-only "dummy" packet. Set the payload to all zeros, with
     // length according to the virtual length.
-    packet_data->payload.SetSize(packet_stream_it_->rtp.total_length -
-                                 packet_stream_it_->rtp.header_length);
+    packet_data->payload.SetSize(packet_stream_it_->total_length -
+                                 packet_stream_it_->header_length);
     std::fill_n(packet_data->payload.data(), packet_data->payload.size(), 0);
 
     ++packet_stream_it_;
@@ -1625,15 +1931,15 @@
     if (packet_stream_it_ == packet_stream_.end()) {
       return rtc::nullopt;
     }
-    return packet_stream_it_->rtp.header;
+    return packet_stream_it_->header;
   }
 
  private:
-  const std::vector<LoggedRtpPacketIncoming>& packet_stream_;
-  std::vector<LoggedRtpPacketIncoming>::const_iterator packet_stream_it_;
-  std::vector<int64_t>::const_iterator output_events_us_it_;
-  const std::vector<int64_t>::const_iterator output_events_us_end_;
-  const rtc::Optional<int64_t> end_time_us_;
+  const std::vector<LoggedRtpPacket>& packet_stream_;
+  std::vector<LoggedRtpPacket>::const_iterator packet_stream_it_;
+  std::vector<uint64_t>::const_iterator output_events_us_it_;
+  const std::vector<uint64_t>::const_iterator output_events_us_end_;
+  const rtc::Optional<uint64_t> end_time_us_;
 };
 
 namespace {
@@ -1641,9 +1947,9 @@
 // the test and returns the NetEqDelayAnalyzer object that was used to
 // instrument the test.
 std::unique_ptr<test::NetEqDelayAnalyzer> CreateNetEqTestAndRun(
-    const std::vector<LoggedRtpPacketIncoming>* packet_stream,
-    const std::vector<int64_t>* output_events_us,
-    rtc::Optional<int64_t> end_time_us,
+    const std::vector<LoggedRtpPacket>* packet_stream,
+    const std::vector<uint64_t>* output_events_us,
+    rtc::Optional<uint64_t> end_time_us,
     const std::string& replacement_file_name,
     int file_sample_rate_hz) {
   std::unique_ptr<test::NetEqInput> input(
@@ -1698,35 +2004,34 @@
     const std::string& replacement_file_name,
     int file_sample_rate_hz,
     Plot* plot) {
-  const std::vector<LoggedRtpPacketIncoming>* audio_packets = nullptr;
-  uint32_t ssrc;
-  for (const auto& stream : parsed_log_.incoming_rtp_packets_by_ssrc()) {
-    if (IsAudioSsrc(kIncomingPacket, stream.ssrc)) {
-      audio_packets = &stream.incoming_packets;
-      ssrc = stream.ssrc;
-      break;
-    }
-  }
-  if (audio_packets == nullptr) {
+  const auto& incoming_audio_kv = std::find_if(
+      rtp_packets_.begin(), rtp_packets_.end(),
+      [this](std::pair<StreamId, std::vector<LoggedRtpPacket>> kv) {
+        return kv.first.GetDirection() == kIncomingPacket &&
+               this->IsAudioSsrc(kv.first);
+      });
+  if (incoming_audio_kv == rtp_packets_.end()) {
     // No incoming audio stream found.
     return;
   }
 
-  std::map<uint32_t, std::vector<int64_t>>::const_iterator output_events_it =
-      parsed_log_.audio_playout_events().find(ssrc);
-  if (output_events_it == parsed_log_.audio_playout_events().end()) {
+  const uint32_t ssrc = incoming_audio_kv->first.GetSsrc();
+
+  std::map<uint32_t, std::vector<uint64_t>>::const_iterator output_events_it =
+      audio_playout_events_.find(ssrc);
+  if (output_events_it == audio_playout_events_.end()) {
     // Could not find output events with SSRC matching the input audio stream.
     // Using the first available stream of output events.
-    output_events_it = parsed_log_.audio_playout_events().cbegin();
+    output_events_it = audio_playout_events_.cbegin();
   }
 
-  rtc::Optional<int64_t> end_time_us =
+  rtc::Optional<uint64_t> end_time_us =
       log_segments_.empty()
           ? rtc::nullopt
-          : rtc::Optional<int64_t>(log_segments_.front().second);
+          : rtc::Optional<uint64_t>(log_segments_.front().second);
 
   auto delay_cb = CreateNetEqTestAndRun(
-      audio_packets, &output_events_it->second, end_time_us,
+      &incoming_audio_kv->second, &output_events_it->second, end_time_us,
       replacement_file_name, file_sample_rate_hz);
 
   std::vector<float> send_times_s;
@@ -1742,27 +2047,28 @@
   RTC_DCHECK_EQ(send_times_s.size(), playout_delay_ms.size());
   RTC_DCHECK_EQ(send_times_s.size(), target_delay_ms.size());
 
-  std::map<uint32_t, TimeSeries> time_series_packet_arrival;
-  std::map<uint32_t, TimeSeries> time_series_relative_packet_arrival;
-  std::map<uint32_t, TimeSeries> time_series_play_time;
-  std::map<uint32_t, TimeSeries> time_series_target_time;
+  std::map<StreamId, TimeSeries> time_series_packet_arrival;
+  std::map<StreamId, TimeSeries> time_series_relative_packet_arrival;
+  std::map<StreamId, TimeSeries> time_series_play_time;
+  std::map<StreamId, TimeSeries> time_series_target_time;
   float min_y_axis = 0.f;
   float max_y_axis = 0.f;
+  const StreamId stream_id = incoming_audio_kv->first;
   for (size_t i = 0; i < send_times_s.size(); ++i) {
-    time_series_packet_arrival[ssrc].points.emplace_back(
+    time_series_packet_arrival[stream_id].points.emplace_back(
         TimeSeriesPoint(send_times_s[i], arrival_delay_ms[i]));
-    time_series_relative_packet_arrival[ssrc].points.emplace_back(
+    time_series_relative_packet_arrival[stream_id].points.emplace_back(
         TimeSeriesPoint(send_times_s[i], corrected_arrival_delay_ms[i]));
     min_y_axis = std::min(min_y_axis, corrected_arrival_delay_ms[i]);
     max_y_axis = std::max(max_y_axis, corrected_arrival_delay_ms[i]);
     if (playout_delay_ms[i]) {
-      time_series_play_time[ssrc].points.emplace_back(
+      time_series_play_time[stream_id].points.emplace_back(
           TimeSeriesPoint(send_times_s[i], *playout_delay_ms[i]));
       min_y_axis = std::min(min_y_axis, *playout_delay_ms[i]);
       max_y_axis = std::max(max_y_axis, *playout_delay_ms[i]);
     }
     if (target_delay_ms[i]) {
-      time_series_target_time[ssrc].points.emplace_back(
+      time_series_target_time[stream_id].points.emplace_back(
           TimeSeriesPoint(send_times_s[i], *target_delay_ms[i]));
       min_y_axis = std::min(min_y_axis, *target_delay_ms[i]);
       max_y_axis = std::max(max_y_axis, *target_delay_ms[i]);
@@ -1800,7 +2106,7 @@
 
 void EventLogAnalyzer::CreateIceCandidatePairConfigGraph(Plot* plot) {
   std::map<uint32_t, TimeSeries> configs_by_cp_id;
-  for (const auto& config : parsed_log_.ice_candidate_pair_configs()) {
+  for (const auto& config : ice_candidate_pair_configs_) {
     if (configs_by_cp_id.find(config.candidate_pair_id) ==
         configs_by_cp_id.end()) {
       const std::string candidate_pair_desc =
@@ -1812,7 +2118,7 @@
       candidate_pair_desc_by_id_[config.candidate_pair_id] =
           candidate_pair_desc;
     }
-    float x = ToCallTime(config.log_time_us());
+    float x = ToCallTime(config.timestamp);
     float y = static_cast<float>(config.type);
     configs_by_cp_id[config.candidate_pair_id].points.emplace_back(x, y);
   }
@@ -1836,7 +2142,7 @@
       candidate_pair_desc_by_id_.end()) {
     return candidate_pair_desc_by_id_[candidate_pair_id];
   }
-  for (const auto& config : parsed_log_.ice_candidate_pair_configs()) {
+  for (const auto& config : ice_candidate_pair_configs_) {
     // TODO(qingsi): Add the handling of the "Updated" config event after the
     // visualization of property change for candidate pairs is introduced.
     if (candidate_pair_desc_by_id_.find(config.candidate_pair_id) ==
@@ -1852,7 +2158,7 @@
 
 void EventLogAnalyzer::CreateIceConnectivityCheckGraph(Plot* plot) {
   std::map<uint32_t, TimeSeries> checks_by_cp_id;
-  for (const auto& event : parsed_log_.ice_candidate_pair_events()) {
+  for (const auto& event : ice_candidate_pair_events_) {
     if (checks_by_cp_id.find(event.candidate_pair_id) ==
         checks_by_cp_id.end()) {
       checks_by_cp_id[event.candidate_pair_id] = TimeSeries(
@@ -1860,7 +2166,7 @@
               GetCandidatePairLogDescriptionFromId(event.candidate_pair_id),
           LineStyle::kNone, PointStyle::kHighlight);
     }
-    float x = ToCallTime(event.log_time_us());
+    float x = ToCallTime(event.timestamp);
     float y = static_cast<float>(event.type);
     checks_by_cp_id[event.candidate_pair_id].points.emplace_back(x, y);
   }
@@ -1876,176 +2182,163 @@
   plot->SetTitle("[IceEventLog] ICE connectivity checks");
 }
 
+void EventLogAnalyzer::Notification(
+    std::unique_ptr<TriageNotification> notification) {
+  notifications_.push_back(std::move(notification));
+}
+
 void EventLogAnalyzer::PrintNotifications(FILE* file) {
+  if (notifications_.size() == 0)
+    return;
   fprintf(file, "========== TRIAGE NOTIFICATIONS ==========\n");
-  for (const auto& alert : incoming_rtp_recv_time_gaps_) {
-    fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str());
-  }
-  for (const auto& alert : incoming_rtcp_recv_time_gaps_) {
-    fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str());
-  }
-  for (const auto& alert : outgoing_rtp_send_time_gaps_) {
-    fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str());
-  }
-  for (const auto& alert : outgoing_rtcp_send_time_gaps_) {
-    fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str());
-  }
-  for (const auto& alert : incoming_seq_num_jumps_) {
-    fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str());
-  }
-  for (const auto& alert : incoming_capture_time_jumps_) {
-    fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str());
-  }
-  for (const auto& alert : outgoing_seq_num_jumps_) {
-    fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str());
-  }
-  for (const auto& alert : outgoing_capture_time_jumps_) {
-    fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str());
-  }
-  for (const auto& alert : outgoing_high_loss_alerts_) {
-    fprintf(file, "          : %s\n", alert.ToString().c_str());
+  for (const auto& notification : notifications_) {
+    rtc::Optional<float> call_timestamp = notification->Time();
+    if (call_timestamp.has_value()) {
+      fprintf(file, "%3.3lf s : %s\n", call_timestamp.value(),
+              notification->ToString().c_str());
+    } else {
+      fprintf(file, "          : %s\n", notification->ToString().c_str());
+    }
   }
   fprintf(file, "========== END TRIAGE NOTIFICATIONS ==========\n");
 }
 
-void EventLogAnalyzer::CreateStreamGapAlerts(PacketDirection direction) {
-  // With 100 packets/s (~800kbps), false positives would require 10 s without
-  // data.
-  constexpr int64_t kMaxSeqNumJump = 1000;
-  // With a 90 kHz clock, false positives would require 10 s without data.
-  constexpr int64_t kMaxCaptureTimeJump = 900000;
-
-  int64_t end_time_us = log_segments_.empty()
-                            ? std::numeric_limits<int64_t>::max()
-                            : log_segments_.front().second;
-
-  SeqNumUnwrapper<uint16_t> seq_num_unwrapper;
-  rtc::Optional<int64_t> last_seq_num;
-  SeqNumUnwrapper<uint32_t> capture_time_unwrapper;
-  rtc::Optional<int64_t> last_capture_time;
-  // Check for gaps in sequence numbers and capture timestamps.
-  for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) {
-    for (const auto& packet : stream.packet_view) {
-      if (packet.log_time_us() > end_time_us) {
-        // Only process the first (LOG_START, LOG_END) segment.
-        break;
-      }
-
-      int64_t seq_num = seq_num_unwrapper.Unwrap(packet.header.sequenceNumber);
-      if (last_seq_num.has_value() &&
-          std::abs(seq_num - last_seq_num.value()) > kMaxSeqNumJump) {
-        Alert_SeqNumJump(direction, ToCallTime(packet.log_time_us()),
-                         packet.header.ssrc);
-      }
-      last_seq_num.emplace(seq_num);
-
-      int64_t capture_time =
-          capture_time_unwrapper.Unwrap(packet.header.timestamp);
-      if (last_capture_time.has_value() &&
-          std::abs(capture_time - last_capture_time.value()) >
-              kMaxCaptureTimeJump) {
-        Alert_CaptureTimeJump(direction, ToCallTime(packet.log_time_us()),
-                              packet.header.ssrc);
-      }
-      last_capture_time.emplace(capture_time);
-    }
-  }
-}
-
-void EventLogAnalyzer::CreateTransmissionGapAlerts(PacketDirection direction) {
-  constexpr int64_t kMaxRtpTransmissionGap = 500000;
-  constexpr int64_t kMaxRtcpTransmissionGap = 2000000;
-  int64_t end_time_us = log_segments_.empty()
-                            ? std::numeric_limits<int64_t>::max()
-                            : log_segments_.front().second;
-
-  // TODO(terelius): The parser could provide a list of all packets, ordered
-  // by time, for each direction.
-  std::multimap<int64_t, const LoggedRtpPacket*> rtp_in_direction;
-  for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) {
-    for (const LoggedRtpPacket& rtp_packet : stream.packet_view)
-      rtp_in_direction.emplace(rtp_packet.log_time_us(), &rtp_packet);
-  }
-  rtc::Optional<int64_t> last_rtp_time;
-  for (const auto& kv : rtp_in_direction) {
-    int64_t timestamp = kv.first;
-    if (timestamp > end_time_us) {
-      // Only process the first (LOG_START, LOG_END) segment.
-      break;
-    }
-    int64_t duration = timestamp - last_rtp_time.value_or(0);
-    if (last_rtp_time.has_value() && duration > kMaxRtpTransmissionGap) {
-      // No packet sent/received for more than 500 ms.
-      Alert_RtpLogTimeGap(direction, ToCallTime(timestamp), duration / 1000);
-    }
-    last_rtp_time.emplace(timestamp);
-  }
-
-  rtc::Optional<int64_t> last_rtcp_time;
-  if (direction == kIncomingPacket) {
-    for (const auto& rtcp : parsed_log_.incoming_rtcp_packets()) {
-      if (rtcp.log_time_us() > end_time_us) {
-        // Only process the first (LOG_START, LOG_END) segment.
-        break;
-      }
-      int64_t duration = rtcp.log_time_us() - last_rtcp_time.value_or(0);
-      if (last_rtcp_time.has_value() && duration > kMaxRtcpTransmissionGap) {
-        // No feedback sent/received for more than 2000 ms.
-        Alert_RtcpLogTimeGap(direction, ToCallTime(rtcp.log_time_us()),
-                             duration / 1000);
-      }
-      last_rtcp_time.emplace(rtcp.log_time_us());
-    }
-  } else {
-    for (const auto& rtcp : parsed_log_.outgoing_rtcp_packets()) {
-      if (rtcp.log_time_us() > end_time_us) {
-        // Only process the first (LOG_START, LOG_END) segment.
-        break;
-      }
-      int64_t duration = rtcp.log_time_us() - last_rtcp_time.value_or(0);
-      if (last_rtcp_time.has_value() && duration > kMaxRtcpTransmissionGap) {
-        // No feedback sent/received for more than 2000 ms.
-        Alert_RtcpLogTimeGap(direction, ToCallTime(rtcp.log_time_us()),
-                             duration / 1000);
-      }
-      last_rtcp_time.emplace(rtcp.log_time_us());
-    }
-  }
-}
-
 // TODO(terelius): Notifications could possibly be generated by the same code
 // that produces the graphs. There is some code duplication that could be
 // avoided, but that might be solved anyway when we move functionality from the
 // analyzer to the parser.
 void EventLogAnalyzer::CreateTriageNotifications() {
-  CreateStreamGapAlerts(kIncomingPacket);
-  CreateStreamGapAlerts(kOutgoingPacket);
-  CreateTransmissionGapAlerts(kIncomingPacket);
-  CreateTransmissionGapAlerts(kOutgoingPacket);
+  uint64_t end_time_us = log_segments_.empty()
+                             ? std::numeric_limits<uint64_t>::max()
+                             : log_segments_.front().second;
+  // Check for gaps in sequence numbers and capture timestamps.
+  for (auto& kv : rtp_packets_) {
+    StreamId stream_id = kv.first;
+    const std::vector<LoggedRtpPacket>& packet_stream = kv.second;
 
-  int64_t end_time_us = log_segments_.empty()
-                            ? std::numeric_limits<int64_t>::max()
-                            : log_segments_.front().second;
+    SeqNumUnwrapper<uint16_t> seq_no_unwrapper;
+    rtc::Optional<int64_t> last_seq_no;
+    SeqNumUnwrapper<uint32_t> timestamp_unwrapper;
+    rtc::Optional<int64_t> last_timestamp;
+    for (const auto& packet : packet_stream) {
+      if (packet.timestamp > end_time_us) {
+        // Only process the first (LOG_START, LOG_END) segment.
+        break;
+      }
+      int64_t seq_no = seq_no_unwrapper.Unwrap(packet.header.sequenceNumber);
+      if (last_seq_no.has_value() &&
+          std::abs(seq_no - last_seq_no.value()) > 1000) {
+        // With roughly 100 packets per second (~800kbps), this would require 10
+        // seconds without data to trigger incorrectly.
+        if (stream_id.GetDirection() == kIncomingPacket) {
+          Notification(rtc::MakeUnique<IncomingSeqNoJump>(
+              ToCallTime(packet.timestamp), packet.header.ssrc));
+        } else {
+          Notification(rtc::MakeUnique<OutgoingSeqNoJump>(
+              ToCallTime(packet.timestamp), packet.header.ssrc));
+        }
+      }
+      last_seq_no.emplace(seq_no);
+      int64_t timestamp = timestamp_unwrapper.Unwrap(packet.header.timestamp);
+      if (last_timestamp.has_value() &&
+          std::abs(timestamp - last_timestamp.value()) > 900000) {
+        // With a 90 kHz clock, this would require 10 seconds without data to
+        // trigger incorrectly.
+        if (stream_id.GetDirection() == kIncomingPacket) {
+          Notification(rtc::MakeUnique<IncomingCaptureTimeJump>(
+              ToCallTime(packet.timestamp), packet.header.ssrc));
+        } else {
+          Notification(rtc::MakeUnique<OutgoingCaptureTimeJump>(
+              ToCallTime(packet.timestamp), packet.header.ssrc));
+        }
+      }
+      last_timestamp.emplace(timestamp);
+    }
+  }
 
-  constexpr double kMaxLossFraction = 0.05;
+  // Check for gaps in RTP and RTCP streams
+  for (const auto direction :
+       {PacketDirection::kIncomingPacket, PacketDirection::kOutgoingPacket}) {
+    // TODO(terelius): The parser could provide a list of all packets, ordered
+    // by time, for each direction.
+    std::multimap<uint64_t, const LoggedRtpPacket*> rtp_in_direction;
+    for (const auto& kv : rtp_packets_) {
+      if (kv.first.GetDirection() == direction) {
+        for (const LoggedRtpPacket& rtp_packet : kv.second)
+          rtp_in_direction.emplace(rtp_packet.timestamp, &rtp_packet);
+      }
+    }
+    rtc::Optional<uint64_t> last_rtp_packet;
+    for (const auto& kv : rtp_in_direction) {
+      uint64_t timestamp = kv.first;
+      if (timestamp > end_time_us) {
+        // Only process the first (LOG_START, LOG_END) segment.
+        break;
+      }
+      int64_t duration = timestamp - last_rtp_packet.value_or(0);
+      if (last_rtp_packet.has_value() && duration > 500000) {
+        // No incoming packet for more than 500 ms.
+        if (direction == kIncomingPacket) {
+          Notification(rtc::MakeUnique<IncomingRtpReceiveTimeGap>(
+              ToCallTime(timestamp), duration / 1000));
+        } else {
+          Notification(rtc::MakeUnique<OutgoingRtpSendTimeGap>(
+              ToCallTime(timestamp), duration / 1000));
+        }
+      }
+      last_rtp_packet.emplace(timestamp);
+    }
+
+    // TODO(terelius): The parser could provide a list of all packets, ordered
+    // by time, for each direction.
+    std::multimap<uint64_t, const LoggedRtcpPacket*> rtcp_in_direction;
+    for (const auto& kv : rtcp_packets_) {
+      if (kv.first.GetDirection() == direction) {
+        for (const LoggedRtcpPacket& rtcp_packet : kv.second)
+          rtcp_in_direction.emplace(rtcp_packet.timestamp, &rtcp_packet);
+      }
+    }
+    rtc::Optional<uint64_t> last_incoming_rtcp_packet;
+    for (const auto& kv : rtcp_in_direction) {
+      uint64_t timestamp = kv.first;
+      if (timestamp > end_time_us) {
+        // Only process the first (LOG_START, LOG_END) segment.
+        break;
+      }
+      int64_t duration = timestamp - last_incoming_rtcp_packet.value_or(0);
+      if (last_incoming_rtcp_packet.has_value() && duration > 2000000) {
+        // No incoming feedback for more than 2000 ms.
+        if (direction == kIncomingPacket) {
+          Notification(rtc::MakeUnique<IncomingRtcpReceiveTimeGap>(
+              ToCallTime(timestamp), duration / 1000));
+        } else {
+          Notification(rtc::MakeUnique<OutgoingRtcpSendTimeGap>(
+              ToCallTime(timestamp), duration / 1000));
+        }
+      }
+      last_incoming_rtcp_packet.emplace(timestamp);
+    }
+  }
+
   // Loss feedback
   int64_t total_lost_packets = 0;
   int64_t total_expected_packets = 0;
-  for (auto& bwe_update : parsed_log_.bwe_loss_updates()) {
-    if (bwe_update.log_time_us() > end_time_us) {
+  for (auto& bwe_update : bwe_loss_updates_) {
+    if (bwe_update.timestamp > end_time_us) {
       // Only process the first (LOG_START, LOG_END) segment.
       break;
     }
-    int64_t lost_packets = static_cast<double>(bwe_update.fraction_lost) / 255 *
+    int64_t lost_packets = static_cast<double>(bwe_update.fraction_loss) / 255 *
                            bwe_update.expected_packets;
     total_lost_packets += lost_packets;
     total_expected_packets += bwe_update.expected_packets;
   }
   double avg_outgoing_loss =
       static_cast<double>(total_lost_packets) / total_expected_packets;
-  if (avg_outgoing_loss > kMaxLossFraction) {
-    Alert_OutgoingHighLoss(avg_outgoing_loss);
+  if (avg_outgoing_loss > 0.05) {
+    Notification(rtc::MakeUnique<OutgoingHighLoss>(avg_outgoing_loss));
   }
 }
 
+}  // namespace plotting
 }  // namespace webrtc
diff --git a/rtc_tools/event_log_visualizer/analyzer.h b/rtc_tools/event_log_visualizer/analyzer.h
index b37de21..a8fedb8 100644
--- a/rtc_tools/event_log_visualizer/analyzer.h
+++ b/rtc_tools/event_log_visualizer/analyzer.h
@@ -18,12 +18,54 @@
 #include <utility>
 #include <vector>
 
-#include "logging/rtc_event_log/rtc_event_log_parser2.h"
-#include "rtc_base/strings/string_builder.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
+#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "modules/rtp_rtcp/source/rtcp_packet.h"
+#include "rtc_base/function_view.h"
 #include "rtc_tools/event_log_visualizer/plot_base.h"
 #include "rtc_tools/event_log_visualizer/triage_notifications.h"
 
 namespace webrtc {
+namespace plotting {
+
+struct LoggedRtpPacket {
+  LoggedRtpPacket(uint64_t timestamp,
+                  RTPHeader header,
+                  size_t header_length,
+                  size_t total_length)
+      : timestamp(timestamp),
+        header(header),
+        header_length(header_length),
+        total_length(total_length) {}
+  uint64_t timestamp;
+  // TODO(terelius): This allocates space for 15 CSRCs even if none are used.
+  RTPHeader header;
+  size_t header_length;
+  size_t total_length;
+};
+
+struct LoggedRtcpPacket {
+  LoggedRtcpPacket(uint64_t timestamp,
+                   RTCPPacketType rtcp_type,
+                   std::unique_ptr<rtcp::RtcpPacket> rtcp_packet)
+      : timestamp(timestamp), type(rtcp_type), packet(std::move(rtcp_packet)) {}
+  uint64_t timestamp;
+  RTCPPacketType type;
+  std::unique_ptr<rtcp::RtcpPacket> packet;
+};
+
+struct LossBasedBweUpdate {
+  uint64_t timestamp;
+  int32_t new_bitrate;
+  uint8_t fraction_loss;
+  int32_t expected_packets;
+};
+
+struct AudioNetworkAdaptationEvent {
+  uint64_t timestamp;
+  AudioEncoderRuntimeConfig config;
+};
 
 class EventLogAnalyzer {
  public:
@@ -32,13 +74,14 @@
   // modified while the EventLogAnalyzer is being used.
   explicit EventLogAnalyzer(const ParsedRtcEventLog& log);
 
-  void CreatePacketGraph(PacketDirection direction, Plot* plot);
+  void CreatePacketGraph(PacketDirection desired_direction, Plot* plot);
 
-  void CreateAccumulatedPacketsGraph(PacketDirection direction, Plot* plot);
+  void CreateAccumulatedPacketsGraph(PacketDirection desired_direction,
+                                     Plot* plot);
 
   void CreatePlayoutGraph(Plot* plot);
 
-  void CreateAudioLevelGraph(PacketDirection direction, Plot* plot);
+  void CreateAudioLevelGraph(Plot* plot);
 
   void CreateSequenceNumberGraph(Plot* plot);
 
@@ -49,20 +92,19 @@
 
   void CreateFractionLossGraph(Plot* plot);
 
-  void CreateTotalIncomingBitrateGraph(Plot* plot);
-  void CreateTotalOutgoingBitrateGraph(Plot* plot,
-                                       bool show_detector_state = false,
-                                       bool show_alr_state = false);
+  void CreateTotalBitrateGraph(PacketDirection desired_direction,
+                               Plot* plot,
+                               bool show_detector_state = false,
+                               bool show_alr_state = false);
 
-  void CreateStreamBitrateGraph(PacketDirection direction, Plot* plot);
+  void CreateStreamBitrateGraph(PacketDirection desired_direction, Plot* plot);
 
   void CreateSendSideBweSimulationGraph(Plot* plot);
   void CreateReceiveSideBweSimulationGraph(Plot* plot);
 
   void CreateNetworkDelayFeedbackGraph(Plot* plot);
   void CreatePacerDelayGraph(Plot* plot);
-
-  void CreateTimestampGraph(PacketDirection direction, Plot* plot);
+  void CreateTimestampGraph(Plot* plot);
 
   void CreateAudioEncoderTargetBitrateGraph(Plot* plot);
   void CreateAudioEncoderFrameLengthGraph(Plot* plot);
@@ -77,114 +119,55 @@
   void CreateIceCandidatePairConfigGraph(Plot* plot);
   void CreateIceConnectivityCheckGraph(Plot* plot);
 
+  // Returns a vector of capture and arrival timestamps for the video frames
+  // of the stream with the most number of frames.
+  std::vector<std::pair<int64_t, int64_t>> GetFrameTimestamps() const;
+
   void CreateTriageNotifications();
   void PrintNotifications(FILE* file);
 
  private:
-  bool IsRtxSsrc(PacketDirection direction, uint32_t ssrc) const {
-    if (direction == kIncomingPacket) {
-      return parsed_log_.incoming_rtx_ssrcs().find(ssrc) !=
-             parsed_log_.incoming_rtx_ssrcs().end();
-    } else {
-      return parsed_log_.outgoing_rtx_ssrcs().find(ssrc) !=
-             parsed_log_.outgoing_rtx_ssrcs().end();
+  class StreamId {
+   public:
+    StreamId(uint32_t ssrc, webrtc::PacketDirection direction)
+        : ssrc_(ssrc), direction_(direction) {}
+    bool operator<(const StreamId& other) const {
+      return std::tie(ssrc_, direction_) <
+             std::tie(other.ssrc_, other.direction_);
     }
-  }
-
-  bool IsVideoSsrc(PacketDirection direction, uint32_t ssrc) const {
-    if (direction == kIncomingPacket) {
-      return parsed_log_.incoming_video_ssrcs().find(ssrc) !=
-             parsed_log_.incoming_video_ssrcs().end();
-    } else {
-      return parsed_log_.outgoing_video_ssrcs().find(ssrc) !=
-             parsed_log_.outgoing_video_ssrcs().end();
+    bool operator==(const StreamId& other) const {
+      return std::tie(ssrc_, direction_) ==
+             std::tie(other.ssrc_, other.direction_);
     }
-  }
+    uint32_t GetSsrc() const { return ssrc_; }
+    webrtc::PacketDirection GetDirection() const { return direction_; }
 
-  bool IsAudioSsrc(PacketDirection direction, uint32_t ssrc) const {
-    if (direction == kIncomingPacket) {
-      return parsed_log_.incoming_audio_ssrcs().find(ssrc) !=
-             parsed_log_.incoming_audio_ssrcs().end();
-    } else {
-      return parsed_log_.outgoing_audio_ssrcs().find(ssrc) !=
-             parsed_log_.outgoing_audio_ssrcs().end();
-    }
-  }
+   private:
+    uint32_t ssrc_;
+    webrtc::PacketDirection direction_;
+  };
 
-  template <typename IterableType>
-  void CreateAccumulatedPacketsTimeSeries(Plot* plot,
-                                          const IterableType& packets,
-                                          const std::string& label);
+  template <typename T>
+  void CreateAccumulatedPacketsTimeSeries(
+      PacketDirection desired_direction,
+      Plot* plot,
+      const std::map<StreamId, std::vector<T>>& packets,
+      const std::string& label_prefix);
 
-  void CreateStreamGapAlerts(PacketDirection direction);
-  void CreateTransmissionGapAlerts(PacketDirection direction);
+  bool IsRtxSsrc(StreamId stream_id) const;
 
-  std::string GetStreamName(PacketDirection direction, uint32_t ssrc) const {
-    char buffer[200];
-    rtc::SimpleStringBuilder name(buffer);
-    if (IsAudioSsrc(direction, ssrc)) {
-      name << "Audio ";
-    } else if (IsVideoSsrc(direction, ssrc)) {
-      name << "Video ";
-    } else {
-      name << "Unknown ";
-    }
-    if (IsRtxSsrc(direction, ssrc)) {
-      name << "RTX ";
-    }
-    if (direction == kIncomingPacket)
-      name << "(In) ";
-    else
-      name << "(Out) ";
-    name << "SSRC " << ssrc;
-    return name.str();
-  }
+  bool IsVideoSsrc(StreamId stream_id) const;
+
+  bool IsAudioSsrc(StreamId stream_id) const;
+
+  std::string GetStreamName(StreamId stream_id) const;
+
+  rtc::Optional<uint32_t> EstimateRtpClockFrequency(
+      const std::vector<LoggedRtpPacket>& packets) const;
 
   float ToCallTime(int64_t timestamp) const;
 
-  void Alert_RtpLogTimeGap(PacketDirection direction,
-                           float time_seconds,
-                           int64_t duration) {
-    if (direction == kIncomingPacket) {
-      incoming_rtp_recv_time_gaps_.emplace_back(time_seconds, duration);
-    } else {
-      outgoing_rtp_send_time_gaps_.emplace_back(time_seconds, duration);
-    }
-  }
-
-  void Alert_RtcpLogTimeGap(PacketDirection direction,
-                            float time_seconds,
-                            int64_t duration) {
-    if (direction == kIncomingPacket) {
-      incoming_rtcp_recv_time_gaps_.emplace_back(time_seconds, duration);
-    } else {
-      outgoing_rtcp_send_time_gaps_.emplace_back(time_seconds, duration);
-    }
-  }
-
-  void Alert_SeqNumJump(PacketDirection direction,
-                        float time_seconds,
-                        uint32_t ssrc) {
-    if (direction == kIncomingPacket) {
-      incoming_seq_num_jumps_.emplace_back(time_seconds, ssrc);
-    } else {
-      outgoing_seq_num_jumps_.emplace_back(time_seconds, ssrc);
-    }
-  }
-
-  void Alert_CaptureTimeJump(PacketDirection direction,
-                             float time_seconds,
-                             uint32_t ssrc) {
-    if (direction == kIncomingPacket) {
-      incoming_capture_time_jumps_.emplace_back(time_seconds, ssrc);
-    } else {
-      outgoing_capture_time_jumps_.emplace_back(time_seconds, ssrc);
-    }
-  }
-
-  void Alert_OutgoingHighLoss(double avg_loss_fraction) {
-    outgoing_high_loss_alerts_.emplace_back(avg_loss_fraction);
-  }
+  void Notification(std::unique_ptr<TriageNotification> notification);
 
   std::string GetCandidatePairLogDescriptionFromId(uint32_t candidate_pair_id);
 
@@ -194,19 +177,50 @@
   // If left empty, all SSRCs will be considered relevant.
   std::vector<uint32_t> desired_ssrc_;
 
+  // Tracks what each stream is configured for. Note that a single SSRC can be
+  // in several sets. For example, the SSRC used for sending video over RTX
+  // will appear in both video_ssrcs_ and rtx_ssrcs_. In the unlikely case that
+  // an SSRC is reconfigured to a different media type mid-call, it will also
+  // appear in multiple sets.
+  std::set<StreamId> rtx_ssrcs_;
+  std::set<StreamId> video_ssrcs_;
+  std::set<StreamId> audio_ssrcs_;
+
+  // Maps a stream identifier consisting of ssrc and direction to the parsed
+  // RTP headers in that stream. Header extensions are parsed if the stream
+  // has been configured.
+  std::map<StreamId, std::vector<LoggedRtpPacket>> rtp_packets_;
+
+  std::map<StreamId, std::vector<LoggedRtcpPacket>> rtcp_packets_;
+
+  // Maps an SSRC to the timestamps of parsed audio playout events.
+  std::map<uint32_t, std::vector<uint64_t>> audio_playout_events_;
+
   // Stores the timestamps for all log segments, in the form of associated start
   // and end events.
-  std::vector<std::pair<int64_t, int64_t>> log_segments_;
+  std::vector<std::pair<uint64_t, uint64_t>> log_segments_;
 
-  std::vector<IncomingRtpReceiveTimeGap> incoming_rtp_recv_time_gaps_;
-  std::vector<IncomingRtcpReceiveTimeGap> incoming_rtcp_recv_time_gaps_;
-  std::vector<OutgoingRtpSendTimeGap> outgoing_rtp_send_time_gaps_;
-  std::vector<OutgoingRtcpSendTimeGap> outgoing_rtcp_send_time_gaps_;
-  std::vector<IncomingSeqNumJump> incoming_seq_num_jumps_;
-  std::vector<IncomingCaptureTimeJump> incoming_capture_time_jumps_;
-  std::vector<OutgoingSeqNoJump> outgoing_seq_num_jumps_;
-  std::vector<OutgoingCaptureTimeJump> outgoing_capture_time_jumps_;
-  std::vector<OutgoingHighLoss> outgoing_high_loss_alerts_;
+  // A list of all updates from the send-side loss-based bandwidth estimator.
+  std::vector<LossBasedBweUpdate> bwe_loss_updates_;
+
+  std::vector<AudioNetworkAdaptationEvent> audio_network_adaptation_events_;
+
+  std::vector<ParsedRtcEventLog::BweProbeClusterCreatedEvent>
+      bwe_probe_cluster_created_events_;
+
+  std::vector<ParsedRtcEventLog::BweProbeResultEvent> bwe_probe_result_events_;
+
+  std::vector<ParsedRtcEventLog::BweDelayBasedUpdate> bwe_delay_updates_;
+
+  std::vector<std::unique_ptr<TriageNotification>> notifications_;
+
+  std::vector<ParsedRtcEventLog::AlrStateEvent> alr_state_events_;
+
+  std::vector<ParsedRtcEventLog::IceCandidatePairConfig>
+      ice_candidate_pair_configs_;
+
+  std::vector<ParsedRtcEventLog::IceCandidatePairEvent>
+      ice_candidate_pair_events_;
 
   std::map<uint32_t, std::string> candidate_pair_desc_by_id_;
 
@@ -214,17 +228,18 @@
   // The generated data points will be |step_| microseconds apart.
   // Only events occuring at most |window_duration_| microseconds before the
   // current data point will be part of the average.
-  int64_t window_duration_;
-  int64_t step_;
+  uint64_t window_duration_;
+  uint64_t step_;
 
   // First and last events of the log.
-  int64_t begin_time_;
-  int64_t end_time_;
+  uint64_t begin_time_;
+  uint64_t end_time_;
 
   // Duration (in seconds) of log file.
   float call_duration_s_;
 };
 
+}  // namespace plotting
 }  // namespace webrtc
 
 #endif  // RTC_TOOLS_EVENT_LOG_VISUALIZER_ANALYZER_H_
diff --git a/rtc_tools/event_log_visualizer/main.cc b/rtc_tools/event_log_visualizer/main.cc
index 3dce290..2e7a79e 100644
--- a/rtc_tools/event_log_visualizer/main.cc
+++ b/rtc_tools/event_log_visualizer/main.cc
@@ -10,7 +10,7 @@
 
 #include <iostream>
 
-#include "logging/rtc_event_log/rtc_event_log_parser2.h"
+#include "logging/rtc_event_log/rtc_event_log_parser.h"
 #include "rtc_base/flags.h"
 #include "rtc_tools/event_log_visualizer/analyzer.h"
 #include "rtc_tools/event_log_visualizer/plot_base.h"
@@ -143,15 +143,10 @@
             false,
             "Show the state ALR state on the total bitrate graph");
 
-DEFINE_bool(parse_unconfigured_header_extensions,
-            true,
-            "Attempt to parse unconfigured header extensions using the default "
-            "WebRTC mapping. This can give very misleading results if the "
-            "application negotiates a different mapping.");
-
-DEFINE_bool(print_triage_alerts,
-            false,
-            "Print triage alerts, i.e. a list of potential problems.");
+DEFINE_bool(
+    print_triage_notifications,
+    false,
+    "Print triage notifications, i.e. a list of suspicious looking events.");
 
 void SetAllPlotFlags(bool setting);
 
@@ -214,13 +209,7 @@
 
   std::string filename = argv[1];
 
-  webrtc::ParsedRtcEventLog::UnconfiguredHeaderExtensions header_extensions =
-      webrtc::ParsedRtcEventLog::UnconfiguredHeaderExtensions::kDontParse;
-  if (FLAG_parse_unconfigured_header_extensions) {
-    header_extensions = webrtc::ParsedRtcEventLog::
-        UnconfiguredHeaderExtensions::kAttemptWebrtcDefaultConfig;
-  }
-  webrtc::ParsedRtcEventLog parsed_log(header_extensions);
+  webrtc::ParsedRtcEventLog parsed_log;
 
   if (!parsed_log.ParseFile(filename)) {
     std::cerr << "Could not parse the entire log file." << std::endl;
@@ -229,34 +218,31 @@
               << std::endl;
   }
 
-  webrtc::EventLogAnalyzer analyzer(parsed_log);
-  std::unique_ptr<webrtc::PlotCollection> collection(
-      new webrtc::PythonPlotCollection());
+  webrtc::plotting::EventLogAnalyzer analyzer(parsed_log);
+  std::unique_ptr<webrtc::plotting::PlotCollection> collection(
+      new webrtc::plotting::PythonPlotCollection());
 
   if (FLAG_plot_incoming_packet_sizes) {
-    analyzer.CreatePacketGraph(webrtc::kIncomingPacket,
+    analyzer.CreatePacketGraph(webrtc::PacketDirection::kIncomingPacket,
                                collection->AppendNewPlot());
   }
   if (FLAG_plot_outgoing_packet_sizes) {
-    analyzer.CreatePacketGraph(webrtc::kOutgoingPacket,
+    analyzer.CreatePacketGraph(webrtc::PacketDirection::kOutgoingPacket,
                                collection->AppendNewPlot());
   }
   if (FLAG_plot_incoming_packet_count) {
-    analyzer.CreateAccumulatedPacketsGraph(webrtc::kIncomingPacket,
-                                           collection->AppendNewPlot());
+    analyzer.CreateAccumulatedPacketsGraph(
+        webrtc::PacketDirection::kIncomingPacket, collection->AppendNewPlot());
   }
   if (FLAG_plot_outgoing_packet_count) {
-    analyzer.CreateAccumulatedPacketsGraph(webrtc::kOutgoingPacket,
-                                           collection->AppendNewPlot());
+    analyzer.CreateAccumulatedPacketsGraph(
+        webrtc::PacketDirection::kOutgoingPacket, collection->AppendNewPlot());
   }
   if (FLAG_plot_audio_playout) {
     analyzer.CreatePlayoutGraph(collection->AppendNewPlot());
   }
   if (FLAG_plot_audio_level) {
-    analyzer.CreateAudioLevelGraph(webrtc::kIncomingPacket,
-                                   collection->AppendNewPlot());
-    analyzer.CreateAudioLevelGraph(webrtc::kOutgoingPacket,
-                                   collection->AppendNewPlot());
+    analyzer.CreateAudioLevelGraph(collection->AppendNewPlot());
   }
   if (FLAG_plot_incoming_sequence_number_delta) {
     analyzer.CreateSequenceNumberGraph(collection->AppendNewPlot());
@@ -271,19 +257,23 @@
     analyzer.CreateIncomingPacketLossGraph(collection->AppendNewPlot());
   }
   if (FLAG_plot_incoming_bitrate) {
-    analyzer.CreateTotalIncomingBitrateGraph(collection->AppendNewPlot());
+    analyzer.CreateTotalBitrateGraph(webrtc::PacketDirection::kIncomingPacket,
+                                     collection->AppendNewPlot(),
+                                     FLAG_show_detector_state,
+                                     FLAG_show_alr_state);
   }
   if (FLAG_plot_outgoing_bitrate) {
-    analyzer.CreateTotalOutgoingBitrateGraph(collection->AppendNewPlot(),
-                                             FLAG_show_detector_state,
-                                             FLAG_show_alr_state);
+    analyzer.CreateTotalBitrateGraph(webrtc::PacketDirection::kOutgoingPacket,
+                                     collection->AppendNewPlot(),
+                                     FLAG_show_detector_state,
+                                     FLAG_show_alr_state);
   }
   if (FLAG_plot_incoming_stream_bitrate) {
-    analyzer.CreateStreamBitrateGraph(webrtc::kIncomingPacket,
+    analyzer.CreateStreamBitrateGraph(webrtc::PacketDirection::kIncomingPacket,
                                       collection->AppendNewPlot());
   }
   if (FLAG_plot_outgoing_stream_bitrate) {
-    analyzer.CreateStreamBitrateGraph(webrtc::kOutgoingPacket,
+    analyzer.CreateStreamBitrateGraph(webrtc::PacketDirection::kOutgoingPacket,
                                       collection->AppendNewPlot());
   }
   if (FLAG_plot_simulated_receiveside_bwe) {
@@ -299,10 +289,7 @@
     analyzer.CreateFractionLossGraph(collection->AppendNewPlot());
   }
   if (FLAG_plot_timestamps) {
-    analyzer.CreateTimestampGraph(webrtc::kIncomingPacket,
-                                  collection->AppendNewPlot());
-    analyzer.CreateTimestampGraph(webrtc::kOutgoingPacket,
-                                  collection->AppendNewPlot());
+    analyzer.CreateTimestampGraph(collection->AppendNewPlot());
   }
   if (FLAG_plot_pacer_delay) {
     analyzer.CreatePacerDelayGraph(collection->AppendNewPlot());
@@ -346,7 +333,7 @@
 
   collection->Draw();
 
-  if (FLAG_print_triage_alerts) {
+  if (FLAG_print_triage_notifications) {
     analyzer.CreateTriageNotifications();
     analyzer.PrintNotifications(stderr);
   }
diff --git a/rtc_tools/event_log_visualizer/plot_base.cc b/rtc_tools/event_log_visualizer/plot_base.cc
index 9a21393..7ff4ef9 100644
--- a/rtc_tools/event_log_visualizer/plot_base.cc
+++ b/rtc_tools/event_log_visualizer/plot_base.cc
@@ -15,6 +15,7 @@
 #include "rtc_base/checks.h"
 
 namespace webrtc {
+namespace plotting {
 
 void Plot::SetXAxis(float min_value,
                     float max_value,
@@ -84,4 +85,5 @@
   }
 }
 
+}  // namespace plotting
 }  // namespace webrtc
diff --git a/rtc_tools/event_log_visualizer/plot_base.h b/rtc_tools/event_log_visualizer/plot_base.h
index e73f004..700ffbf 100644
--- a/rtc_tools/event_log_visualizer/plot_base.h
+++ b/rtc_tools/event_log_visualizer/plot_base.h
@@ -16,6 +16,7 @@
 #include <vector>
 
 namespace webrtc {
+namespace plotting {
 
 enum class LineStyle {
   kNone,  // No line connecting the points. Used to create scatter plots.
@@ -172,6 +173,7 @@
   std::vector<std::unique_ptr<Plot> > plots_;
 };
 
+}  // namespace plotting
 }  // namespace webrtc
 
 #endif  // RTC_TOOLS_EVENT_LOG_VISUALIZER_PLOT_BASE_H_
diff --git a/rtc_tools/event_log_visualizer/plot_protobuf.cc b/rtc_tools/event_log_visualizer/plot_protobuf.cc
index e986a74..e5e0a8b 100644
--- a/rtc_tools/event_log_visualizer/plot_protobuf.cc
+++ b/rtc_tools/event_log_visualizer/plot_protobuf.cc
@@ -13,6 +13,7 @@
 #include <memory>
 
 namespace webrtc {
+namespace plotting {
 
 ProtobufPlot::ProtobufPlot() {}
 
@@ -82,4 +83,5 @@
   return plot;
 }
 
+}  // namespace plotting
 }  // namespace webrtc
diff --git a/rtc_tools/event_log_visualizer/plot_protobuf.h b/rtc_tools/event_log_visualizer/plot_protobuf.h
index f59d303..5c5cce1 100644
--- a/rtc_tools/event_log_visualizer/plot_protobuf.h
+++ b/rtc_tools/event_log_visualizer/plot_protobuf.h
@@ -17,6 +17,7 @@
 #include "rtc_tools/event_log_visualizer/plot_base.h"
 
 namespace webrtc {
+namespace plotting {
 
 class ProtobufPlot final : public Plot {
  public:
@@ -35,6 +36,7 @@
   void ExportProtobuf(webrtc::analytics::ChartCollection* collection);
 };
 
+}  // namespace plotting
 }  // namespace webrtc
 
 #endif  // RTC_TOOLS_EVENT_LOG_VISUALIZER_PLOT_PROTOBUF_H_
diff --git a/rtc_tools/event_log_visualizer/plot_python.cc b/rtc_tools/event_log_visualizer/plot_python.cc
index 37c4d84..8f406e2 100644
--- a/rtc_tools/event_log_visualizer/plot_python.cc
+++ b/rtc_tools/event_log_visualizer/plot_python.cc
@@ -17,6 +17,7 @@
 #include "rtc_base/checks.h"
 
 namespace webrtc {
+namespace plotting {
 
 PythonPlot::PythonPlot() {}
 
@@ -179,4 +180,5 @@
   return plot;
 }
 
+}  // namespace plotting
 }  // namespace webrtc
diff --git a/rtc_tools/event_log_visualizer/plot_python.h b/rtc_tools/event_log_visualizer/plot_python.h
index 61d17a0..2a5a66c 100644
--- a/rtc_tools/event_log_visualizer/plot_python.h
+++ b/rtc_tools/event_log_visualizer/plot_python.h
@@ -13,6 +13,7 @@
 #include "rtc_tools/event_log_visualizer/plot_base.h"
 
 namespace webrtc {
+namespace plotting {
 
 class PythonPlot final : public Plot {
  public:
@@ -29,6 +30,7 @@
   Plot* AppendNewPlot() override;
 };
 
+}  // namespace plotting
 }  // namespace webrtc
 
 #endif  // RTC_TOOLS_EVENT_LOG_VISUALIZER_PLOT_PYTHON_H_
diff --git a/rtc_tools/event_log_visualizer/triage_notifications.h b/rtc_tools/event_log_visualizer/triage_notifications.h
index 49e0620..641e2ae 100644
--- a/rtc_tools/event_log_visualizer/triage_notifications.h
+++ b/rtc_tools/event_log_visualizer/triage_notifications.h
@@ -14,136 +14,130 @@
 #include <string>
 
 namespace webrtc {
+namespace plotting {
 
-class IncomingRtpReceiveTimeGap {
+class TriageNotification {
+ public:
+  TriageNotification() : time_seconds_() {}
+  explicit TriageNotification(float time_seconds)
+      : time_seconds_(time_seconds) {}
+  virtual ~TriageNotification() = default;
+  virtual std::string ToString() = 0;
+  rtc::Optional<float> Time() { return time_seconds_; }
+
+ private:
+  rtc::Optional<float> time_seconds_;
+};
+
+class IncomingRtpReceiveTimeGap : public TriageNotification {
  public:
   IncomingRtpReceiveTimeGap(float time_seconds, int64_t duration)
-      : time_seconds_(time_seconds), duration_(duration) {}
-  float Time() const { return time_seconds_; }
-  std::string ToString() const {
+      : TriageNotification(time_seconds), duration_(duration) {}
+  std::string ToString() {
     return std::string("No RTP packets received for ") +
            std::to_string(duration_) + std::string(" ms");
   }
 
  private:
-  float time_seconds_;
   int64_t duration_;
 };
 
-class IncomingRtcpReceiveTimeGap {
+class IncomingRtcpReceiveTimeGap : public TriageNotification {
  public:
   IncomingRtcpReceiveTimeGap(float time_seconds, int64_t duration)
-      : time_seconds_(time_seconds), duration_(duration) {}
-  float Time() const { return time_seconds_; }
-  std::string ToString() const {
+      : TriageNotification(time_seconds), duration_(duration) {}
+  std::string ToString() {
     return std::string("No RTCP packets received for ") +
            std::to_string(duration_) + std::string(" ms");
   }
 
  private:
-  float time_seconds_;
   int64_t duration_;
 };
 
-class OutgoingRtpSendTimeGap {
+class OutgoingRtpSendTimeGap : public TriageNotification {
  public:
   OutgoingRtpSendTimeGap(float time_seconds, int64_t duration)
-      : time_seconds_(time_seconds), duration_(duration) {}
-  float Time() const { return time_seconds_; }
-  std::string ToString() const {
+      : TriageNotification(time_seconds), duration_(duration) {}
+  std::string ToString() {
     return std::string("No RTP packets sent for ") + std::to_string(duration_) +
            std::string(" ms");
   }
 
  private:
-  float time_seconds_;
   int64_t duration_;
 };
 
-class OutgoingRtcpSendTimeGap {
+class OutgoingRtcpSendTimeGap : public TriageNotification {
  public:
   OutgoingRtcpSendTimeGap(float time_seconds, int64_t duration)
-      : time_seconds_(time_seconds), duration_(duration) {}
-  float Time() const { return time_seconds_; }
-  std::string ToString() const {
+      : TriageNotification(time_seconds), duration_(duration) {}
+  std::string ToString() {
     return std::string("No RTCP packets sent for ") +
            std::to_string(duration_) + std::string(" ms");
   }
 
  private:
-  float time_seconds_;
   int64_t duration_;
 };
 
-class IncomingSeqNumJump {
+class IncomingSeqNoJump : public TriageNotification {
  public:
-  IncomingSeqNumJump(float time_seconds, uint32_t ssrc)
-      : time_seconds_(time_seconds), ssrc_(ssrc) {}
-  float Time() const { return time_seconds_; }
-  std::string ToString() const {
+  IncomingSeqNoJump(float time_seconds, uint32_t ssrc)
+      : TriageNotification(time_seconds), ssrc_(ssrc) {}
+  std::string ToString() {
     return std::string("Sequence number jumps on incoming SSRC ") +
            std::to_string(ssrc_);
   }
 
  private:
-  float time_seconds_;
-
   uint32_t ssrc_;
 };
 
-class IncomingCaptureTimeJump {
+class IncomingCaptureTimeJump : public TriageNotification {
  public:
   IncomingCaptureTimeJump(float time_seconds, uint32_t ssrc)
-      : time_seconds_(time_seconds), ssrc_(ssrc) {}
-  float Time() const { return time_seconds_; }
-  std::string ToString() const {
+      : TriageNotification(time_seconds), ssrc_(ssrc) {}
+  std::string ToString() {
     return std::string("Capture timestamp jumps on incoming SSRC ") +
            std::to_string(ssrc_);
   }
 
  private:
-  float time_seconds_;
-
   uint32_t ssrc_;
 };
 
-class OutgoingSeqNoJump {
+class OutgoingSeqNoJump : public TriageNotification {
  public:
   OutgoingSeqNoJump(float time_seconds, uint32_t ssrc)
-      : time_seconds_(time_seconds), ssrc_(ssrc) {}
-  float Time() const { return time_seconds_; }
-  std::string ToString() const {
+      : TriageNotification(time_seconds), ssrc_(ssrc) {}
+  std::string ToString() {
     return std::string("Sequence number jumps on outgoing SSRC ") +
            std::to_string(ssrc_);
   }
 
  private:
-  float time_seconds_;
-
   uint32_t ssrc_;
 };
 
-class OutgoingCaptureTimeJump {
+class OutgoingCaptureTimeJump : public TriageNotification {
  public:
   OutgoingCaptureTimeJump(float time_seconds, uint32_t ssrc)
-      : time_seconds_(time_seconds), ssrc_(ssrc) {}
-  float Time() const { return time_seconds_; }
-  std::string ToString() const {
+      : TriageNotification(time_seconds), ssrc_(ssrc) {}
+  std::string ToString() {
     return std::string("Capture timestamp jumps on outgoing SSRC ") +
            std::to_string(ssrc_);
   }
 
  private:
-  float time_seconds_;
-
   uint32_t ssrc_;
 };
 
-class OutgoingHighLoss {
+class OutgoingHighLoss : public TriageNotification {
  public:
   explicit OutgoingHighLoss(double avg_loss_fraction)
       : avg_loss_fraction_(avg_loss_fraction) {}
-  std::string ToString() const {
+  std::string ToString() {
     return std::string("High average loss (") +
            std::to_string(avg_loss_fraction_ * 100) +
            std::string("%) across the call.");
@@ -153,6 +147,7 @@
   double avg_loss_fraction_;
 };
 
+}  // namespace plotting
 }  // namespace webrtc
 
 #endif  // RTC_TOOLS_EVENT_LOG_VISUALIZER_TRIAGE_NOTIFICATIONS_H_