Reland "Add fine grained dropped video frames counters on sending side"

Add fine grained dropped video frames counters on sending side

4 new counters added to SendStatisticsProxy and reported to UMA and logs.

Bug: webrtc:8355
Change-Id: I1f9bdfea9cbf17cf38b3cb2f55d406ffdb06614f
Reviewed-on: https://webrtc-review.googlesource.com/14580
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20421}
diff --git a/modules/video_coding/generic_encoder.cc b/modules/video_coding/generic_encoder.cc
index c4affcf..b616523 100644
--- a/modules/video_coding/generic_encoder.cc
+++ b/modules/video_coding/generic_encoder.cc
@@ -65,6 +65,7 @@
                   << settings->plName;
     return -1;
   }
+  vcm_encoded_frame_callback_->Reset();
   encoder_->RegisterEncodeCompleteCallback(vcm_encoded_frame_callback_);
   return 0;
 }
@@ -144,8 +145,6 @@
     const std::vector<FrameType>& frame_types) {
   RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
 
-  for (size_t i = 0; i < streams_or_svc_num_; ++i)
-    vcm_encoded_frame_callback_->OnEncodeStarted(0, i);
   // TODO(nisse): Used only with internal source. Delete as soon as
   // that feature is removed. The only implementation I've been able
   // to find ignores what's in the frame. With one exception: It seems
@@ -213,11 +212,26 @@
 
 void VCMEncodedFrameCallback::OnEncodeStarted(int64_t capture_time_ms,
                                               size_t simulcast_svc_idx) {
+  if (internal_source_) {
+    return;
+  }
   rtc::CritScope crit(&timing_params_lock_);
   if (timing_frames_info_.size() < simulcast_svc_idx + 1)
     timing_frames_info_.resize(simulcast_svc_idx + 1);
-  timing_frames_info_[simulcast_svc_idx].encode_start_time_ms[capture_time_ms] =
-      rtc::TimeMillis();
+  RTC_DCHECK(
+      timing_frames_info_[simulcast_svc_idx].encode_start_list.empty() ||
+      rtc::TimeDiff(capture_time_ms, timing_frames_info_[simulcast_svc_idx]
+                                         .encode_start_list.back()
+                                         .capture_time_ms) >= 0);
+  if (timing_frames_info_[simulcast_svc_idx].encode_start_list.size() ==
+      kMaxEncodeStartTimeListSize) {
+    LOG(LS_WARNING) << "Too many frames in the encode_start_list."
+                       " Did encoder stall?";
+    post_encode_callback_->OnDroppedFrame(DropReason::kDroppedByEncoder);
+    timing_frames_info_[simulcast_svc_idx].encode_start_list.pop_front();
+  }
+  timing_frames_info_[simulcast_svc_idx].encode_start_list.emplace_back(
+      capture_time_ms, rtc::TimeMillis());
 }
 
 EncodedImageCallback::Result VCMEncodedFrameCallback::OnEncodedImage(
@@ -242,27 +256,29 @@
   rtc::Optional<int64_t> encode_start_ms;
   size_t num_simulcast_svc_streams = 1;
   uint8_t timing_flags = TimingFrameFlags::kInvalid;
-  {
+  if (!internal_source_) {
     rtc::CritScope crit(&timing_params_lock_);
 
     // Encoders with internal sources do not call OnEncodeStarted and
     // OnFrameRateChanged. |timing_frames_info_| may be not filled here.
     num_simulcast_svc_streams = timing_frames_info_.size();
     if (simulcast_svc_idx < num_simulcast_svc_streams) {
-      auto encode_start_map =
-          &timing_frames_info_[simulcast_svc_idx].encode_start_time_ms;
-      auto it = encode_start_map->find(encoded_image.capture_time_ms_);
-      if (it != encode_start_map->end()) {
-        encode_start_ms.emplace(it->second);
-        // Assuming all encoders do not reorder frames within single stream,
-        // there may be some dropped frames with smaller timestamps. These
-        // should be purged.
-        encode_start_map->erase(encode_start_map->begin(), it);
-        encode_start_map->erase(it);
-      } else {
-        // Encoder is with internal source: free our records of any frames just
-        // in case to free memory.
-        encode_start_map->clear();
+      auto encode_start_list =
+          &timing_frames_info_[simulcast_svc_idx].encode_start_list;
+      // Skip frames for which there was OnEncodeStarted but no OnEncodedImage
+      // call. These are dropped by encoder internally.
+      while (!encode_start_list->empty() &&
+             encode_start_list->front().capture_time_ms <
+                 encoded_image.capture_time_ms_) {
+        post_encode_callback_->OnDroppedFrame(DropReason::kDroppedByEncoder);
+        encode_start_list->pop_front();
+      }
+      if (encode_start_list->size() > 0 &&
+          encode_start_list->front().capture_time_ms ==
+              encoded_image.capture_time_ms_) {
+        encode_start_ms.emplace(
+            encode_start_list->front().encode_start_time_ms);
+        encode_start_list->pop_front();
       }
 
       size_t target_bitrate =