Create a VideoFrameTrackingId RTP header extension.

Bug: webrtc:12594
Change-Id: I518b549b18143f4711728b4637a4689772474c45
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/212084
Reviewed-by: Artem Titov <titovartem@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Jeremy Leconte <jleconte@google.com>
Cr-Commit-Position: refs/heads/master@{#33567}
diff --git a/docs/native-code/rtp-hdrext/video-frame-tracking-id/README.md b/docs/native-code/rtp-hdrext/video-frame-tracking-id/README.md
new file mode 100644
index 0000000..d1c6097
--- /dev/null
+++ b/docs/native-code/rtp-hdrext/video-frame-tracking-id/README.md
@@ -0,0 +1,27 @@
+# Video Frame Tracking Id
+
+The Video Frame Tracking Id extension is meant for media quality testing
+purpose and shouldn't be used in production. It tracks webrtc::VideoFrame id
+field from the sender to the receiver to gather referenced base media quality
+metrics such as PSNR or SSIM.
+Contact <jleconte@google.com> for more info.
+
+**Name:** "Video Frame Tracking Id"
+
+**Formal name:**
+<http://www.webrtc.org/experiments/rtp-hdrext/video-frame-tracking-id>
+
+**Status:** This extension is defined to allow for media quality testing. It is
+enabled by using a field trial and should only be used in a testing environment.
+
+### Data layout overview
+     1-byte header + 2 bytes of data:
+
+      0                   1                   2
+      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     |  ID   | L=1   |    video-frame-tracking-id    |
+     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+Notes: The extension shoud be present only in the first packet of each frame.
+If attached to other packets it can be ignored.
\ No newline at end of file
diff --git a/modules/rtp_rtcp/include/rtp_rtcp_defines.h b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
index cbc2d92..2e460e4 100644
--- a/modules/rtp_rtcp/include/rtp_rtcp_defines.h
+++ b/modules/rtp_rtcp/include/rtp_rtcp_defines.h
@@ -74,6 +74,7 @@
   kRtpExtensionGenericFrameDescriptor = kRtpExtensionGenericFrameDescriptor00,
   kRtpExtensionGenericFrameDescriptor02,
   kRtpExtensionColorSpace,
+  kRtpExtensionVideoFrameTrackingId,
   kRtpExtensionNumberOfExtensions  // Must be the last entity in the enum.
 };
 
diff --git a/modules/rtp_rtcp/source/rtp_header_extension_map.cc b/modules/rtp_rtcp/source/rtp_header_extension_map.cc
index c16dcaf..aebe884 100644
--- a/modules/rtp_rtcp/source/rtp_header_extension_map.cc
+++ b/modules/rtp_rtcp/source/rtp_header_extension_map.cc
@@ -50,6 +50,7 @@
     CreateExtensionInfo<RtpDependencyDescriptorExtension>(),
     CreateExtensionInfo<ColorSpaceExtension>(),
     CreateExtensionInfo<InbandComfortNoiseExtension>(),
+    CreateExtensionInfo<VideoFrameTrackingIdExtension>(),
 };
 
 // Because of kRtpExtensionNone, NumberOfExtension is 1 bigger than the actual
diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.cc b/modules/rtp_rtcp/source/rtp_header_extensions.cc
index b540e4b..1c3073e 100644
--- a/modules/rtp_rtcp/source/rtp_header_extensions.cc
+++ b/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -823,4 +823,32 @@
   return true;
 }
 
+// VideoFrameTrackingIdExtension
+//
+//   0                   1                   2
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |  ID   | L=1   |    video-frame-tracking-id    |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+constexpr RTPExtensionType VideoFrameTrackingIdExtension::kId;
+constexpr uint8_t VideoFrameTrackingIdExtension::kValueSizeBytes;
+constexpr const char VideoFrameTrackingIdExtension::kUri[];
+
+bool VideoFrameTrackingIdExtension::Parse(rtc::ArrayView<const uint8_t> data,
+                                          uint16_t* video_frame_tracking_id) {
+  if (data.size() != kValueSizeBytes) {
+    return false;
+  }
+  *video_frame_tracking_id = ByteReader<uint16_t>::ReadBigEndian(data.data());
+  return true;
+}
+
+bool VideoFrameTrackingIdExtension::Write(rtc::ArrayView<uint8_t> data,
+                                          uint16_t video_frame_tracking_id) {
+  RTC_DCHECK_EQ(data.size(), kValueSizeBytes);
+  ByteWriter<uint16_t>::WriteBigEndian(data.data(), video_frame_tracking_id);
+  return true;
+}
+
 }  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.h b/modules/rtp_rtcp/source/rtp_header_extensions.h
index 1352611..f6e7a57 100644
--- a/modules/rtp_rtcp/source/rtp_header_extensions.h
+++ b/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -307,5 +307,21 @@
                     absl::optional<uint8_t> level);
 };
 
+class VideoFrameTrackingIdExtension {
+ public:
+  using value_type = uint16_t;
+  static constexpr RTPExtensionType kId = kRtpExtensionVideoFrameTrackingId;
+  static constexpr uint8_t kValueSizeBytes = 2;
+  static constexpr const char kUri[] =
+      "http://www.webrtc.org/experiments/rtp-hdrext/video-frame-tracking-id";
+  static bool Parse(rtc::ArrayView<const uint8_t> data,
+                    uint16_t* video_frame_tracking_id);
+  static size_t ValueSize(uint16_t /*video_frame_tracking_id*/) {
+    return kValueSizeBytes;
+  }
+  static bool Write(rtc::ArrayView<uint8_t> data,
+                    uint16_t video_frame_tracking_id);
+};
+
 }  // namespace webrtc
 #endif  // MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
diff --git a/modules/rtp_rtcp/source/rtp_packet.cc b/modules/rtp_rtcp/source/rtp_packet.cc
index 38d29cc..84769d0 100644
--- a/modules/rtp_rtcp/source/rtp_packet.cc
+++ b/modules/rtp_rtcp/source/rtp_packet.cc
@@ -198,7 +198,8 @@
       case RTPExtensionType::kRtpExtensionVideoContentType:
       case RTPExtensionType::kRtpExtensionVideoLayersAllocation:
       case RTPExtensionType::kRtpExtensionVideoRotation:
-      case RTPExtensionType::kRtpExtensionInbandComfortNoise: {
+      case RTPExtensionType::kRtpExtensionInbandComfortNoise:
+      case RTPExtensionType::kRtpExtensionVideoFrameTrackingId: {
         // Non-mutable extension. Don't change it.
         break;
       }
diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc
index c8ea999..8435e5f 100644
--- a/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/modules/rtp_rtcp/source/rtp_sender.cc
@@ -121,6 +121,7 @@
     case kRtpExtensionVideoTiming:
     case kRtpExtensionRepairedRtpStreamId:
     case kRtpExtensionColorSpace:
+    case kRtpExtensionVideoFrameTrackingId:
       return false;
     case kRtpExtensionNone:
     case kRtpExtensionNumberOfExtensions:
diff --git a/modules/rtp_rtcp/source/rtp_utility.cc b/modules/rtp_rtcp/source/rtp_utility.cc
index a3d6d6f..a22785f 100644
--- a/modules/rtp_rtcp/source/rtp_utility.cc
+++ b/modules/rtp_rtcp/source/rtp_utility.cc
@@ -536,6 +536,10 @@
           RTC_LOG(WARNING) << "Inband comfort noise extension unsupported by "
                               "rtp header parser.";
           break;
+        case kRtpExtensionVideoFrameTrackingId:
+          RTC_LOG(WARNING)
+              << "VideoFrameTrackingId unsupported by rtp header parser.";
+          break;
         case kRtpExtensionNone:
         case kRtpExtensionNumberOfExtensions: {
           RTC_NOTREACHED() << "Invalid extension type: " << type;
diff --git a/test/fuzzers/rtp_packet_fuzzer.cc b/test/fuzzers/rtp_packet_fuzzer.cc
index 3f03114..9e8fd6f 100644
--- a/test/fuzzers/rtp_packet_fuzzer.cc
+++ b/test/fuzzers/rtp_packet_fuzzer.cc
@@ -148,6 +148,11 @@
         packet.GetExtension<RtpVideoLayersAllocationExtension>(&allocation);
         break;
       }
+      case kRtpExtensionVideoFrameTrackingId: {
+        uint16_t tracking_id;
+        packet.GetExtension<VideoFrameTrackingIdExtension>(&tracking_id);
+        break;
+      }
       case kRtpExtensionGenericFrameDescriptor02:
         // This extension requires state to read and so complicated that
         // deserves own fuzzer.