Move SPS/PPS/IDR requirement from RtpFrameObject to PacketBuffer.

BUG=webrtc:8423

Change-Id: I0f0d59461afead700c20c9a2ed9b2bc991590b4a
Reviewed-on: https://webrtc-review.googlesource.com/15101
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20559}
diff --git a/modules/video_coding/packet_buffer.cc b/modules/video_coding/packet_buffer.cc
index 7b9b659..0e4ef6a 100644
--- a/modules/video_coding/packet_buffer.cc
+++ b/modules/video_coding/packet_buffer.cc
@@ -12,6 +12,7 @@
 
 #include <algorithm>
 #include <limits>
+#include <sstream>
 #include <utility>
 
 #include "common_video/h264/h264_common.h"
@@ -20,6 +21,7 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "system_wrappers/include/clock.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 namespace video_coding {
@@ -45,7 +47,9 @@
       is_cleared_to_first_seq_num_(false),
       data_buffer_(start_buffer_size),
       sequence_buffer_(start_buffer_size),
-      received_frame_callback_(received_frame_callback) {
+      received_frame_callback_(received_frame_callback),
+      sps_pps_idr_is_h264_keyframe_(
+          field_trial::IsEnabled("WebRTC-SpsPpsIdrIsH264Keyframe")) {
   RTC_DCHECK_LE(start_buffer_size, max_buffer_size);
   // Buffer size must always be a power of 2.
   RTC_DCHECK((start_buffer_size & (start_buffer_size - 1)) == 0);
@@ -269,11 +273,15 @@
       // the |frame_begin| flag is set.
       int start_index = index;
       size_t tested_packets = 0;
-
-      bool is_h264 = data_buffer_[start_index].codec == kVideoCodecH264;
-      bool is_h264_keyframe = false;
       int64_t frame_timestamp = data_buffer_[start_index].timestamp;
 
+      // Identify H.264 keyframes by means of SPS, PPS, and IDR.
+      bool is_h264 = data_buffer_[start_index].codec == kVideoCodecH264;
+      bool has_h264_sps = false;
+      bool has_h264_pps = false;
+      bool has_h264_idr = false;
+      bool is_h264_keyframe = false;
+
       while (true) {
         ++tested_packets;
         frame_size += data_buffer_[start_index].sizeBytes;
@@ -287,12 +295,20 @@
         if (is_h264 && !is_h264_keyframe) {
           const RTPVideoHeaderH264& header =
               data_buffer_[start_index].video_header.codecHeader.H264;
-          for (size_t i = 0; i < header.nalus_length; ++i) {
-            if (header.nalus[i].type == H264::NaluType::kIdr) {
-              is_h264_keyframe = true;
-              break;
+          for (size_t j = 0; j < header.nalus_length; ++j) {
+            if (header.nalus[j].type == H264::NaluType::kSps) {
+              has_h264_sps = true;
+            } else if (header.nalus[j].type == H264::NaluType::kPps) {
+              has_h264_pps = true;
+            } else if (header.nalus[j].type == H264::NaluType::kIdr) {
+              has_h264_idr = true;
             }
           }
+          if ((sps_pps_idr_is_h264_keyframe_ && has_h264_idr && has_h264_sps &&
+               has_h264_pps) ||
+              (!sps_pps_idr_is_h264_keyframe_ && has_h264_idr)) {
+            is_h264_keyframe = true;
+          }
         }
 
         if (tested_packets == size_)
@@ -315,18 +331,45 @@
         --start_seq_num;
       }
 
-      // If this is H264 but not a keyframe, make sure there are no gaps in the
-      // packet sequence numbers up until this point.
-      if (is_h264 && !is_h264_keyframe &&
-          missing_packets_.upper_bound(start_seq_num) !=
-              missing_packets_.begin()) {
-        uint16_t stop_index = (index + 1) % size_;
-        while (start_index != stop_index) {
-          sequence_buffer_[start_index].frame_created = false;
-          start_index = (start_index + 1) % size_;
+      if (is_h264) {
+        // Warn if this is an unsafe frame.
+        if (has_h264_idr && (!has_h264_sps || !has_h264_pps)) {
+          std::stringstream ss;
+          ss << "Received H.264-IDR frame "
+             << "(SPS: " << has_h264_sps << ", PPS: " << has_h264_pps << "). ";
+          if (sps_pps_idr_is_h264_keyframe_) {
+            ss << "Treating as delta frame since "
+                  "WebRTC-SpsPpsIdrIsH264Keyframe is enabled.";
+          } else {
+            ss << "Treating as key frame since "
+                  "WebRTC-SpsPpsIdrIsH264Keyframe is disabled.";
+          }
+          LOG(LS_WARNING) << ss.str();
         }
 
-        return found_frames;
+        // Now that we have decided whether to treat this frame as a key frame
+        // or delta frame in the frame buffer, we update the field that
+        // determines if the RtpFrameObject is a key frame or delta frame.
+        const size_t first_packet_index = start_seq_num % size_;
+        RTC_CHECK_LT(first_packet_index, size_);
+        if (is_h264_keyframe) {
+          data_buffer_[first_packet_index].frameType = kVideoFrameKey;
+        } else {
+          data_buffer_[first_packet_index].frameType = kVideoFrameDelta;
+        }
+
+        // If this is not a keyframe, make sure there are no gaps in the
+        // packet sequence numbers up until this point.
+        if (!is_h264_keyframe && missing_packets_.upper_bound(start_seq_num) !=
+                                     missing_packets_.begin()) {
+          uint16_t stop_index = (index + 1) % size_;
+          while (start_index != stop_index) {
+            sequence_buffer_[start_index].frame_created = false;
+            start_index = (start_index + 1) % size_;
+          }
+
+          return found_frames;
+        }
       }
 
       missing_packets_.erase(missing_packets_.begin(),