Convert VP8 descriptor to generic descriptor.

Also adds a running picture id for the old generic format when
kVideoCodecGeneric is used (behind "WebRTC-GenericPictureId" field trial).

Bug: webrtc:9361
Change-Id: I6f232a2663bb60257c97ed3473eb07044d325b90
Reviewed-on: https://webrtc-review.googlesource.com/94842
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24449}
diff --git a/call/rtp_payload_params.cc b/call/rtp_payload_params.cc
index d61d40f..608688b 100644
--- a/call/rtp_payload_params.cc
+++ b/call/rtp_payload_params.cc
@@ -13,8 +13,10 @@
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/video_coding/include/video_codec_interface.h"
 #include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
 #include "rtc_base/random.h"
 #include "rtc_base/timeutils.h"
+#include "system_wrappers/include/field_trial.h"
 
 namespace webrtc {
 
@@ -107,17 +109,26 @@
 
 RtpPayloadParams::RtpPayloadParams(const uint32_t ssrc,
                                    const RtpPayloadState* state)
-    : ssrc_(ssrc) {
+    : ssrc_(ssrc),
+      generic_picture_id_experiment_(
+          field_trial::IsEnabled("WebRTC-GenericPictureId")) {
+  for (auto& spatial_layer : last_shared_frame_id_)
+    spatial_layer.fill(-1);
+
   Random random(rtc::TimeMicros());
   state_.picture_id =
       state ? state->picture_id : (random.Rand<int16_t>() & 0x7FFF);
   state_.tl0_pic_idx = state ? state->tl0_pic_idx : (random.Rand<uint8_t>());
 }
+
+RtpPayloadParams::RtpPayloadParams(const RtpPayloadParams& other) = default;
+
 RtpPayloadParams::~RtpPayloadParams() {}
 
 RTPVideoHeader RtpPayloadParams::GetRtpVideoHeader(
     const EncodedImage& image,
-    const CodecSpecificInfo* codec_specific_info) {
+    const CodecSpecificInfo* codec_specific_info,
+    int64_t shared_frame_id) {
   RTPVideoHeader rtp_video_header;
   if (codec_specific_info) {
     PopulateRtpWithCodecSpecifics(*codec_specific_info, &rtp_video_header);
@@ -128,12 +139,15 @@
 
   SetVideoTiming(image, &rtp_video_header.video_timing);
 
-  // Sets picture id and tl0 pic idx.
+  const bool is_keyframe = image._frameType == kVideoFrameKey;
   const bool first_frame_in_picture =
       (codec_specific_info && codec_specific_info->codecType == kVideoCodecVP9)
           ? codec_specific_info->codecSpecific.VP9.first_frame_in_picture
           : true;
-  Set(&rtp_video_header, first_frame_in_picture);
+
+  SetCodecSpecific(&rtp_video_header, first_frame_in_picture);
+  SetGeneric(shared_frame_id, is_keyframe, &rtp_video_header);
+
   return rtp_video_header;
 }
 
@@ -145,8 +159,8 @@
   return state_;
 }
 
-void RtpPayloadParams::Set(RTPVideoHeader* rtp_video_header,
-                           bool first_frame_in_picture) {
+void RtpPayloadParams::SetCodecSpecific(RTPVideoHeader* rtp_video_header,
+                                        bool first_frame_in_picture) {
   // Always set picture id. Set tl0_pic_idx iff temporal index is set.
   if (first_frame_in_picture) {
     state_.picture_id = (static_cast<uint16_t>(state_.picture_id) + 1) & 0x7FFF;
@@ -179,5 +193,84 @@
       vp9_header.tl0_pic_idx = state_.tl0_pic_idx;
     }
   }
+  // There are currently two generic descriptors in WebRTC. The old descriptor
+  // can not share a picture id space between simulcast streams, so we use the
+  // |picture_id| in this case. We let the |picture_id| tag along in |frame_id|
+  // until the old generic format can be removed.
+  // TODO(philipel): Remove this when the new generic format has been fully
+  //                 implemented.
+  if (generic_picture_id_experiment_ &&
+      rtp_video_header->codec == kVideoCodecGeneric) {
+    rtp_video_header->generic.emplace().frame_id = state_.picture_id;
+  }
 }
+
+void RtpPayloadParams::SetGeneric(int64_t frame_id,
+                                  bool is_keyframe,
+                                  RTPVideoHeader* rtp_video_header) {
+  if (rtp_video_header->codec == kVideoCodecVP8) {
+    Vp8ToGeneric(frame_id, is_keyframe, rtp_video_header);
+  }
+
+  // TODO(philipel): Implement VP9 to new generic descriptor.
+  // TODO(philipel): Implement H264 to new generic descriptor.
+  // TODO(philipel): Implement generic codec to new generic descriptor.
+}
+
+void RtpPayloadParams::Vp8ToGeneric(int64_t shared_frame_id,
+                                    bool is_keyframe,
+                                    RTPVideoHeader* rtp_video_header) {
+  const auto& vp8_header =
+      absl::get<RTPVideoHeaderVP8>(rtp_video_header->video_type_header);
+  const int spatial_index = 0;
+  const int temporal_index =
+      vp8_header.temporalIdx != kNoTemporalIdx ? vp8_header.temporalIdx : 0;
+
+  if (temporal_index >= RtpGenericFrameDescriptor::kMaxTemporalLayers ||
+      spatial_index >= RtpGenericFrameDescriptor::kMaxSpatialLayers) {
+    RTC_LOG(LS_WARNING) << "Temporal and/or spatial index is too high to be "
+                           "used with generic frame descriptor.";
+    return;
+  }
+
+  RTPVideoHeader::GenericDescriptorInfo& generic =
+      rtp_video_header->generic.emplace();
+
+  generic.frame_id = shared_frame_id;
+  generic.spatial_index = spatial_index;
+  generic.temporal_index = temporal_index;
+
+  if (is_keyframe) {
+    RTC_DCHECK_EQ(temporal_index, 0);
+    last_shared_frame_id_[spatial_index].fill(-1);
+    last_shared_frame_id_[spatial_index][temporal_index] = shared_frame_id;
+    return;
+  }
+
+  if (vp8_header.layerSync) {
+    int64_t tl0_frame_id = last_shared_frame_id_[spatial_index][0];
+
+    for (int i = 1; i < RtpGenericFrameDescriptor::kMaxTemporalLayers; ++i) {
+      if (last_shared_frame_id_[spatial_index][i] < tl0_frame_id) {
+        last_shared_frame_id_[spatial_index][i] = -1;
+      }
+    }
+
+    RTC_DCHECK_GE(tl0_frame_id, 0);
+    RTC_DCHECK_LT(tl0_frame_id, shared_frame_id);
+    generic.dependencies.push_back(tl0_frame_id);
+  } else {
+    for (int i = 0; i <= temporal_index; ++i) {
+      int64_t frame_id = last_shared_frame_id_[spatial_index][i];
+
+      if (frame_id != -1) {
+        RTC_DCHECK_LT(frame_id, shared_frame_id);
+        generic.dependencies.push_back(frame_id);
+      }
+    }
+  }
+
+  last_shared_frame_id_[spatial_index][temporal_index] = shared_frame_id;
+}
+
 }  // namespace webrtc