[WebRTC] Removing `CopyAndFixBitstream` separate calls for H264 & H265 17/297817/1
authorAdam Bujalski <a.bujalski@samsung.com>
Thu, 27 Apr 2023 12:14:52 +0000 (14:14 +0200)
committerj.gajownik2 <j.gajownik2@samsung.com>
Thu, 24 Aug 2023 16:16:00 +0000 (18:16 +0200)
Currently WebRTC pipeline copies H264 & H265 bitstream and inserts
needed start codes and codec parameters (SPS, PPS and VPS). This copy is
redundant, so this patch fixes stream on the fly during video frame
assembling.

Bug: https://cam.sprc.samsung.pl/browse/VDGAME-249
Change-Id: Ibd4fcbda49d95534c5b282cd2578ebed68f5b2c1

25 files changed:
third_party/webrtc/modules/rtp_rtcp/source/rtp_packetizer_av1_unittest.cc
third_party/webrtc/modules/rtp_rtcp/source/video_rtp_depacketizer.cc
third_party/webrtc/modules/rtp_rtcp/source/video_rtp_depacketizer.h
third_party/webrtc/modules/rtp_rtcp/source/video_rtp_depacketizer_av1.cc
third_party/webrtc/modules/rtp_rtcp/source/video_rtp_depacketizer_av1.h
third_party/webrtc/modules/rtp_rtcp/source/video_rtp_depacketizer_av1_unittest.cc
third_party/webrtc/modules/rtp_rtcp/source/video_rtp_depacketizer_h264.cc
third_party/webrtc/modules/rtp_rtcp/source/video_rtp_depacketizer_h264.h
third_party/webrtc/modules/rtp_rtcp/source/video_rtp_depacketizer_h264_unittest.cc
third_party/webrtc/modules/rtp_rtcp/source/video_rtp_depacketizer_h265.cc
third_party/webrtc/modules/rtp_rtcp/source/video_rtp_depacketizer_h265.h
third_party/webrtc/modules/video_coding/BUILD.gn
third_party/webrtc/modules/video_coding/codecs/h264/include/h264_globals.h
third_party/webrtc/modules/video_coding/codecs/h265/include/h265_globals.h
third_party/webrtc/modules/video_coding/h264_sps_pps_tracker.cc [deleted file]
third_party/webrtc/modules/video_coding/h264_sps_pps_tracker.h [deleted file]
third_party/webrtc/modules/video_coding/h264_sps_pps_tracker_unittest.cc [deleted file]
third_party/webrtc/modules/video_coding/h265_vps_sps_pps_tracker.cc [deleted file]
third_party/webrtc/modules/video_coding/h265_vps_sps_pps_tracker.h [deleted file]
third_party/webrtc/video/rtp_video_stream_receiver.cc
third_party/webrtc/video/rtp_video_stream_receiver.h
third_party/webrtc/video/rtp_video_stream_receiver2.cc
third_party/webrtc/video/rtp_video_stream_receiver2.h
third_party/webrtc/video/rtp_video_stream_receiver2_unittest.cc
third_party/webrtc/video/rtp_video_stream_receiver_unittest.cc

index 2151a59295415c7d87f37e0d2f515cafee0ab436..3b50fe9aa4f9f673052e2ad7687fcfe424010e14 100644 (file)
@@ -34,6 +34,7 @@ using ::testing::ElementsAre;
 using ::testing::ElementsAreArray;
 using ::testing::Le;
 using ::testing::SizeIs;
+using RtpPacketView = VideoRtpDepacketizer::RtpPacketView;
 
 constexpr uint8_t kNewCodedVideoSequenceBit = 0b00'00'1000;
 
@@ -92,9 +93,9 @@ std::vector<RtpPayload> Packetize(
 }
 
 Av1Frame ReassembleFrame(rtc::ArrayView<const RtpPayload> rtp_payloads) {
-  std::vector<rtc::ArrayView<const uint8_t>> payloads(rtp_payloads.size());
-  for (size_t i = 0; i < rtp_payloads.size(); ++i) {
-    payloads[i] = rtp_payloads[i];
+  std::vector<RtpPacketView> payloads;
+  for (const auto& payload : rtp_payloads) {
+    payloads.emplace_back(nullptr, payload);
   }
   return Av1Frame(VideoRtpDepacketizerAv1().AssembleFrame(payloads));
 }
index bb0bf09e905765ac3c4600c72afb186760d8f1ea..81e2895ab33ae5ce66836f1e4e2e4800778c993f 100644 (file)
 namespace webrtc {
 
 rtc::scoped_refptr<EncodedImageBuffer> VideoRtpDepacketizer::AssembleFrame(
-    rtc::ArrayView<const rtc::ArrayView<const uint8_t>> rtp_payloads) {
+    rtc::ArrayView<RtpPacketView> rtp_payloads) {
   size_t frame_size = 0;
-  for (rtc::ArrayView<const uint8_t> payload : rtp_payloads) {
-    frame_size += payload.size();
+  for (const auto& packet : rtp_payloads) {
+    frame_size += packet.payload.size();
   }
 
   rtc::scoped_refptr<EncodedImageBuffer> bitstream =
       EncodedImageBuffer::Create(frame_size);
 
   uint8_t* write_at = bitstream->data();
-  for (rtc::ArrayView<const uint8_t> payload : rtp_payloads) {
-    memcpy(write_at, payload.data(), payload.size());
-    write_at += payload.size();
+  for (const auto& packet : rtp_payloads) {
+    memcpy(write_at, packet.payload.data(), packet.payload.size());
+    write_at += packet.payload.size();
   }
   RTC_DCHECK_EQ(write_at - bitstream->data(), bitstream->size());
   return bitstream;
 }
 
+void VideoRtpDepacketizer::SetCodecParams(
+    const std::map<std::string, std::string>& codec_params) {}
+
+VideoRtpDepacketizer::PacketAction VideoRtpDepacketizer::GetPacketAction(
+    rtc::ArrayView<const uint8_t> bitstream,
+    RTPVideoHeader* video_header) {
+  return kInsert;
+}
+
+void VideoRtpDepacketizer::AppendData(uint8_t** buf,
+                                      const uint8_t* data,
+                                      size_t size) {
+  memcpy(*buf, data, size);
+  *buf += size;
+}
+
 }  // namespace webrtc
index 226612079966d8d2d6d17717b7106fd2642e777d..c0cbb5ca4e61f77ae56c07391577930a6fa976d2 100644 (file)
 #ifndef MODULES_RTP_RTCP_SOURCE_VIDEO_RTP_DEPACKETIZER_H_
 #define MODULES_RTP_RTCP_SOURCE_VIDEO_RTP_DEPACKETIZER_H_
 
-#include <stdint.h>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
 
 #include "absl/types/optional.h"
 #include "api/array_view.h"
@@ -29,11 +32,35 @@ class VideoRtpDepacketizer {
     rtc::CopyOnWriteBuffer video_payload;
   };
 
+  struct RtpPacketView {
+    const RTPVideoHeader* video_header;
+    const rtc::ArrayView<const uint8_t> payload;
+
+    RtpPacketView(const RTPVideoHeader* header,
+                  const rtc::ArrayView<const uint8_t> rtp_payload)
+        : video_header(header), payload(rtp_payload) {}
+  };
+
+  enum PacketAction { kInsert, kDrop, kRequestKeyframe };
+
   virtual ~VideoRtpDepacketizer() = default;
   virtual absl::optional<ParsedRtpPayload> Parse(
       rtc::CopyOnWriteBuffer rtp_payload) = 0;
   virtual rtc::scoped_refptr<EncodedImageBuffer> AssembleFrame(
-      rtc::ArrayView<const rtc::ArrayView<const uint8_t>> rtp_payloads);
+      rtc::ArrayView<RtpPacketView> rtp_payloads);
+  virtual void SetCodecParams(
+      const std::map<std::string, std::string>& codec_params);
+  virtual PacketAction GetPacketAction(rtc::ArrayView<const uint8_t> bitstream,
+                                       RTPVideoHeader* video_header);
+
+ protected:
+  template <typename T, size_t N>
+  std::enable_if_t<sizeof(T) == 1> AppendData(uint8_t** buf,
+                                              const T (&array)[N]) {
+    AppendData(buf, reinterpret_cast<const uint8_t*>(array), N);
+  }
+
+  void AppendData(uint8_t** buf, const uint8_t* data, size_t size);
 };
 
 }  // namespace webrtc
index af2ed0c1839112890081a6baf5b99e9e93641e39..449a5b1b29e36058424124663de8dc04fb1f8ea8 100644 (file)
@@ -183,10 +183,11 @@ int RtpStartsNewCodedVideoSequence(uint8_t aggregation_header) {
 // fills ObuInfo::data field.
 // Returns empty vector on error.
 VectorObuInfo ParseObus(
-    rtc::ArrayView<const rtc::ArrayView<const uint8_t>> rtp_payloads) {
+    rtc::ArrayView<VideoRtpDepacketizer::RtpPacketView> rtp_payloads) {
   VectorObuInfo obu_infos;
   bool expect_continues_obu = false;
-  for (rtc::ArrayView<const uint8_t> rtp_payload : rtp_payloads) {
+  for (const auto& rtp_packet : rtp_payloads) {
+    rtc::ArrayView<const uint8_t> rtp_payload = rtp_packet.payload;
     rtc::ByteBufferReader payload(
         reinterpret_cast<const char*>(rtp_payload.data()), rtp_payload.size());
     uint8_t aggregation_header;
@@ -336,7 +337,7 @@ bool CalculateObuSizes(ObuInfo* obu_info) {
 }  // namespace
 
 rtc::scoped_refptr<EncodedImageBuffer> VideoRtpDepacketizerAv1::AssembleFrame(
-    rtc::ArrayView<const rtc::ArrayView<const uint8_t>> rtp_payloads) {
+    rtc::ArrayView<RtpPacketView> rtp_payloads) {
   VectorObuInfo obu_infos = ParseObus(rtp_payloads);
   if (obu_infos.empty()) {
     return nullptr;
index ac8c7e6d11a36bbc7b963445d4ae8f361b93ca03..eb367a71226e2aeb978023b5019435223c505969 100644 (file)
@@ -31,8 +31,7 @@ class VideoRtpDepacketizerAv1 : public VideoRtpDepacketizer {
   ~VideoRtpDepacketizerAv1() override = default;
 
   rtc::scoped_refptr<EncodedImageBuffer> AssembleFrame(
-      rtc::ArrayView<const rtc::ArrayView<const uint8_t>> rtp_payloads)
-      override;
+      rtc::ArrayView<RtpPacketView> rtp_payloads) override;
 
   absl::optional<ParsedRtpPayload> Parse(
       rtc::CopyOnWriteBuffer rtp_payload) override;
index e9ad1a1b8e2fa3481725aff8229e2e8327a3197a..bec93ae43987c1ec621b5aa708d7900019a87962 100644 (file)
@@ -17,6 +17,7 @@ namespace webrtc {
 namespace {
 
 using ::testing::ElementsAre;
+using RtpPacketView = VideoRtpDepacketizer::RtpPacketView;
 
 // Signals number of the OBU (fragments) in the packet.
 constexpr uint8_t kObuCountOne = 0b00'01'0000;
@@ -117,7 +118,7 @@ TEST(VideoRtpDepacketizerAv1Test, AssembleFrameSetsOBUPayloadSizeWhenAbsent) {
   const uint8_t payload1[] = {0b00'01'0000,  // aggregation header
                               0b0'0110'000,  // /  Frame
                               20, 30, 40};   // \  OBU
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1};
+  RtpPacketView payloads[] = {{nullptr, payload1}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   rtc::ArrayView<const uint8_t> frame_view(*frame);
@@ -132,7 +133,7 @@ TEST(VideoRtpDepacketizerAv1Test, AssembleFrameSetsOBUPayloadSizeWhenPresent) {
                               20,
                               30,
                               40};  // \  obu_payload
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1};
+  RtpPacketView payloads[] = {{nullptr, payload1}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   rtc::ArrayView<const uint8_t> frame_view(*frame);
@@ -146,7 +147,7 @@ TEST(VideoRtpDepacketizerAv1Test,
                               0b0'0110'100,           // /  Frame
                               0b010'01'000,           // | extension_header
                               20,           30, 40};  // \  OBU
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1};
+  RtpPacketView payloads[] = {{nullptr, payload1}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   rtc::ArrayView<const uint8_t> frame_view(*frame);
@@ -163,7 +164,7 @@ TEST(VideoRtpDepacketizerAv1Test,
                               20,
                               30,
                               40};  // \  obu_payload
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1};
+  RtpPacketView payloads[] = {{nullptr, payload1}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   rtc::ArrayView<const uint8_t> frame_view(*frame);
@@ -175,7 +176,7 @@ TEST(VideoRtpDepacketizerAv1Test, AssembleFrameFromOnePacketWithOneObu) {
   const uint8_t payload1[] = {0b00'01'0000,  // aggregation header
                               0b0'0110'000,  // /  Frame
                               20};           // \  OBU
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1};
+  RtpPacketView payloads[] = {{nullptr, payload1}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   EXPECT_THAT(rtc::ArrayView<const uint8_t>(*frame),
@@ -189,7 +190,7 @@ TEST(VideoRtpDepacketizerAv1Test, AssembleFrameFromOnePacketWithTwoObus) {
                               10,            // \  OBU
                               0b0'0110'000,  // /  Frame
                               20};           // \  OBU
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1};
+  RtpPacketView payloads[] = {{nullptr, payload1}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   EXPECT_THAT(rtc::ArrayView<const uint8_t>(*frame),
@@ -202,7 +203,7 @@ TEST(VideoRtpDepacketizerAv1Test, AssembleFrameFromTwoPacketsWithOneObu) {
                               0b0'0110'000, 20, 30};
   const uint8_t payload2[] = {0b10'01'0000,  // aggregation header
                               40};
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1, payload2};
+  RtpPacketView payloads[] = {{nullptr, payload1}, {nullptr, payload2}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   EXPECT_THAT(rtc::ArrayView<const uint8_t>(*frame),
@@ -219,7 +220,7 @@ TEST(VideoRtpDepacketizerAv1Test, AssembleFrameFromTwoPacketsWithTwoObu) {
                               30};           //
   const uint8_t payload2[] = {0b10'01'0000,  // aggregation header
                               40};           //
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1, payload2};
+  RtpPacketView payloads[] = {{nullptr, payload1}, {nullptr, payload2}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   EXPECT_THAT(rtc::ArrayView<const uint8_t>(*frame),
@@ -250,7 +251,7 @@ TEST(VideoRtpDepacketizerAv1Test,
   const uint8_t payload2[] = {0b10'01'0000,  // aggregation header
                               70, 80, 90};   // \  tail of the frame OBU
 
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1, payload2};
+  RtpPacketView payloads[] = {{nullptr, payload1}, {nullptr, payload2}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   EXPECT_THAT(rtc::ArrayView<const uint8_t>(*frame),
@@ -274,8 +275,10 @@ TEST(VideoRtpDepacketizerAv1Test, AssembleFrameWithOneObuFromManyPackets) {
   const uint8_t payload4[] = {0b10'01'0000,  // aggregation header
                               18};
 
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1, payload2, payload3,
-                                              payload4};
+  RtpPacketView payloads[] = {{nullptr, payload1},
+                              {nullptr, payload2},
+                              {nullptr, payload3},
+                              {nullptr, payload4}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   EXPECT_THAT(rtc::ArrayView<const uint8_t>(*frame),
@@ -306,8 +309,10 @@ TEST(VideoRtpDepacketizerAv1Test,
                               32};
   const uint8_t payload4[] = {0b10'01'0000,  // aggregation header
                               33, 34, 35, 36};
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1, payload2, payload3,
-                                              payload4};
+  RtpPacketView payloads[] = {{nullptr, payload1},
+                              {nullptr, payload2},
+                              {nullptr, payload3},
+                              {nullptr, payload4}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   EXPECT_THAT(rtc::ArrayView<const uint8_t>(*frame),
@@ -326,7 +331,7 @@ TEST(VideoRtpDepacketizerAv1Test,
   payload1[2] = 0x01;          // in two bytes
   payload1[3] = 0b0'0110'000;  // obu_header with size and extension bits unset.
   payload1[4 + 42] = 0x42;
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1};
+  RtpPacketView payloads[] = {{nullptr, payload1}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   EXPECT_EQ(frame->size(), 2 + 127u);
@@ -351,7 +356,7 @@ TEST(VideoRtpDepacketizerAv1Test,
   payload2[1] = 96;            // leb128 encoded size of 96 bytes in one byte
   payload2[2 + 20] = 0x20;
 
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1, payload2};
+  RtpPacketView payloads[] = {{nullptr, payload1}, {nullptr, payload2}};
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
   EXPECT_EQ(frame->size(), 3 + 128u);
@@ -368,7 +373,7 @@ TEST(VideoRtpDepacketizerAv1Test,
      AssembleFrameFromAlmostEmptyPacketStartingAnOBU) {
   const uint8_t payload1[] = {0b01'01'0000};
   const uint8_t payload2[] = {0b10'01'0000, 0b0'0110'000, 10, 20, 30};
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1, payload2};
+  RtpPacketView payloads[] = {{nullptr, payload1}, {nullptr, payload2}};
 
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
@@ -380,7 +385,7 @@ TEST(VideoRtpDepacketizerAv1Test,
      AssembleFrameFromAlmostEmptyPacketFinishingAnOBU) {
   const uint8_t payload1[] = {0b01'01'0000, 0b0'0110'000, 10, 20, 30};
   const uint8_t payload2[] = {0b10'01'0000};
-  rtc::ArrayView<const uint8_t> payloads[] = {payload1, payload2};
+  RtpPacketView payloads[] = {{nullptr, payload1}, {nullptr, payload2}};
 
   auto frame = VideoRtpDepacketizerAv1().AssembleFrame(payloads);
   ASSERT_TRUE(frame);
index e87be031a802fc441171d783ec1564b46af69913..496fcbdfd237167c44ff5049f18671b2cd75f00c 100644 (file)
@@ -12,6 +12,8 @@
 
 #include <cstddef>
 #include <cstdint>
+#include <map>
+#include <string>
 #include <utility>
 #include <vector>
 
 #include "common_video/h264/pps_parser.h"
 #include "common_video/h264/sps_parser.h"
 #include "common_video/h264/sps_vui_rewriter.h"
+#include "media/base/media_constants.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
 #include "modules/rtp_rtcp/source/video_rtp_depacketizer.h"
+#include "modules/video_coding/codecs/h264/include/h264_globals.h"
+#include "modules/video_coding/h264_sprop_parameter_sets.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/copy_on_write_buffer.h"
 #include "rtc_base/logging.h"
@@ -31,6 +36,8 @@
 namespace webrtc {
 namespace {
 
+const uint8_t start_code_h264[] = {0, 0, 0, 1};
+
 constexpr size_t kNalHeaderSize = 1;
 constexpr size_t kFuAHeaderSize = 2;
 constexpr size_t kLengthFieldSize = 2;
@@ -261,16 +268,11 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ParseFuaNalu(
              "unit with original type: "
           << static_cast<int>(nalu.type);
     }
-    uint8_t original_nal_header = fnri | original_nal_type;
-    rtp_payload =
-        rtp_payload.Slice(kNalHeaderSize, rtp_payload.size() - kNalHeaderSize);
-    rtp_payload.MutableData()[0] = original_nal_header;
-    parsed_payload->video_payload = std::move(rtp_payload);
-  } else {
-    parsed_payload->video_payload =
-        rtp_payload.Slice(kFuAHeaderSize, rtp_payload.size() - kFuAHeaderSize);
   }
 
+  parsed_payload->video_payload =
+      rtp_payload.Slice(kFuAHeaderSize, rtp_payload.size() - kFuAHeaderSize);
+
   if (original_nal_type == H264::NaluType::kIdr) {
     parsed_payload->video_header.frame_type = VideoFrameType::kVideoFrameKey;
   } else {
@@ -288,6 +290,7 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ParseFuaNalu(
   if (first_fragment) {
     h264_header.nalus[h264_header.nalus_length] = nalu;
     h264_header.nalus_length = 1;
+    h264_header.original_nal_header = fnri | original_nal_type;
   }
   return parsed_payload;
 }
@@ -313,4 +316,291 @@ VideoRtpDepacketizerH264::Parse(rtc::CopyOnWriteBuffer rtp_payload) {
   }
 }
 
+void VideoRtpDepacketizerH264::SetCodecParams(
+    const std::map<std::string, std::string>& codec_params) {
+  webrtc::H264SpropParameterSets sprop_decoder;
+  auto sprop_base64_it =
+      codec_params.find(cricket::kH264FmtpSpropParameterSets);
+
+  if (sprop_base64_it == codec_params.end())
+    return;
+
+  if (!sprop_decoder.DecodeSprop(sprop_base64_it->second.c_str()))
+    return;
+
+  const std::vector<uint8_t>& sps = sprop_decoder.sps_nalu();
+  const std::vector<uint8_t>& pps = sprop_decoder.pps_nalu();
+  constexpr size_t kNaluHeaderOffset = 1;
+  if (sps.size() < kNaluHeaderOffset) {
+    RTC_LOG(LS_WARNING) << "SPS size  " << sps.size() << " is smaller than "
+                        << kNaluHeaderOffset;
+    return;
+  }
+  if ((sps[0] & 0x1f) != H264::NaluType::kSps) {
+    RTC_LOG(LS_WARNING) << "SPS Nalu header missing";
+    return;
+  }
+  if (pps.size() < kNaluHeaderOffset) {
+    RTC_LOG(LS_WARNING) << "PPS size  " << pps.size() << " is smaller than "
+                        << kNaluHeaderOffset;
+    return;
+  }
+  if ((pps[0] & 0x1f) != H264::NaluType::kPps) {
+    RTC_LOG(LS_WARNING) << "SPS Nalu header missing";
+    return;
+  }
+  absl::optional<SpsParser::SpsState> parsed_sps = SpsParser::ParseSps(
+      sps.data() + kNaluHeaderOffset, sps.size() - kNaluHeaderOffset);
+  absl::optional<PpsParser::PpsState> parsed_pps = PpsParser::ParsePps(
+      pps.data() + kNaluHeaderOffset, pps.size() - kNaluHeaderOffset);
+
+  if (!parsed_sps) {
+    RTC_LOG(LS_WARNING) << "Failed to parse SPS.";
+  }
+
+  if (!parsed_pps) {
+    RTC_LOG(LS_WARNING) << "Failed to parse PPS.";
+  }
+
+  if (!parsed_pps || !parsed_sps) {
+    return;
+  }
+
+  H264SpsInfo sps_info;
+  sps_info.size = sps.size();
+  sps_info.width = parsed_sps->width;
+  sps_info.height = parsed_sps->height;
+  sps_info.data.resize(sps_info.size);
+  memcpy(sps_info.data.data(), sps.data(), sps_info.size);
+  sps_data_[parsed_sps->id] = std::move(sps_info);
+
+  H264PpsInfo pps_info;
+  pps_info.size = pps.size();
+  pps_info.sps_id = parsed_pps->sps_id;
+  pps_info.data.resize(pps_info.size);
+  memcpy(pps_info.data.data(), pps.data(), pps_info.size);
+  pps_data_[parsed_pps->id] = std::move(pps_info);
+
+  RTC_LOG(LS_INFO) << "Inserted SPS id " << parsed_sps->id << " and PPS id "
+                   << parsed_pps->id << " (referencing SPS "
+                   << parsed_pps->sps_id << ")";
+}
+
+VideoRtpDepacketizer::PacketAction VideoRtpDepacketizerH264::GetPacketAction(
+    rtc::ArrayView<const uint8_t> bitstream,
+    RTPVideoHeader* video_header) {
+  RTC_DCHECK(video_header);
+  RTC_DCHECK(video_header->codec == kVideoCodecH264);
+  RTC_DCHECK_GT(bitstream.size(), 0);
+
+  auto& h264_header =
+      absl::get<RTPVideoHeaderH264>(video_header->video_type_header);
+
+  bool append_sps_pps = false;
+  auto sps = sps_data_.end();
+  auto pps = pps_data_.end();
+
+  for (size_t i = 0; i < h264_header.nalus_length; ++i) {
+    const NaluInfo& nalu = h264_header.nalus[i];
+    switch (nalu.type) {
+      case H264::NaluType::kSps: {
+        H264SpsInfo& sps_info = sps_data_[nalu.sps_id];
+        sps_info.width = video_header->width;
+        sps_info.height = video_header->height;
+        break;
+      }
+      case H264::NaluType::kPps: {
+        pps_data_[nalu.pps_id].sps_id = nalu.sps_id;
+        break;
+      }
+      case H264::NaluType::kIdr: {
+        // If this is the first packet of an IDR, make sure we have the required
+        // SPS/PPS and also calculate how much extra space we need in the buffer
+        // to prepend the SPS/PPS to the bitstream with start codes.
+        if (video_header->is_first_packet_in_frame) {
+          if (nalu.pps_id == -1) {
+            RTC_LOG(LS_WARNING) << "No PPS id in IDR nalu.";
+            return kRequestKeyframe;
+          }
+
+          pps = pps_data_.find(nalu.pps_id);
+          if (pps == pps_data_.end()) {
+            RTC_LOG(LS_WARNING)
+                << "No PPS with id << " << nalu.pps_id << " received";
+            return kRequestKeyframe;
+          }
+
+          sps = sps_data_.find(pps->second.sps_id);
+          if (sps == sps_data_.end()) {
+            RTC_LOG(LS_WARNING)
+                << "No SPS with id << " << pps->second.sps_id << " received";
+            return kRequestKeyframe;
+          }
+
+          // Since the first packet of every keyframe should have its width and
+          // height set we set it here in the case of it being supplied out of
+          // band.
+          video_header->width = sps->second.width;
+          video_header->height = sps->second.height;
+
+          // If the SPS/PPS was supplied out of band then we will have saved
+          // the actual bitstream in `data`.
+          if (!sps->second.data.empty() && !pps->second.data.empty()) {
+            RTC_DCHECK_GT(sps->second.size, 0);
+            RTC_DCHECK_GT(pps->second.size, 0);
+            append_sps_pps = true;
+          }
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+
+  RTC_CHECK(!append_sps_pps ||
+            (sps != sps_data_.end() && pps != pps_data_.end()));
+  if (append_sps_pps) {
+    h264_header.extra_data =
+        absl::make_optional(std::make_tuple(pps->second, sps->second));
+
+    // Update codec header to reflect the newly added SPS and PPS.
+    NaluInfo sps_info;
+    sps_info.type = H264::NaluType::kSps;
+    sps_info.sps_id = sps->first;
+    sps_info.pps_id = -1;
+    NaluInfo pps_info;
+    pps_info.type = H264::NaluType::kPps;
+    pps_info.sps_id = sps->first;
+    pps_info.pps_id = pps->first;
+    if (h264_header.nalus_length + 2 <= kMaxNalusPerPacket) {
+      h264_header.nalus[h264_header.nalus_length++] = sps_info;
+      h264_header.nalus[h264_header.nalus_length++] = pps_info;
+    } else {
+      RTC_LOG(LS_WARNING) << "Not enough space in H.264 codec header to insert "
+                             "SPS/PPS provided out-of-band.";
+    }
+  }
+
+  if (h264_header.packetization_type == kH264StapA) {
+    const uint8_t* nalu_ptr = bitstream.data() + 1;
+    while (nalu_ptr < bitstream.data() + bitstream.size() - 1) {
+      // The first two bytes describe the length of a segment.
+      uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
+      nalu_ptr += 2;
+
+      size_t copy_end = nalu_ptr - bitstream.data() + segment_length;
+      if (copy_end > bitstream.size()) {
+        return kDrop;
+      }
+
+      nalu_ptr += segment_length;
+    }
+  }
+
+  return kInsert;
+}
+
+rtc::scoped_refptr<EncodedImageBuffer> VideoRtpDepacketizerH264::AssembleFrame(
+    rtc::ArrayView<RtpPacketView> rtp_payloads) {
+  size_t frame_size = 0;
+  for (const auto& packet : rtp_payloads) {
+    frame_size += CalculatePacketSize(packet);
+  }
+
+  rtc::scoped_refptr<EncodedImageBuffer> bitstream =
+      EncodedImageBuffer::Create(frame_size);
+
+  uint8_t* buf = bitstream->data();
+  for (const auto& packet : rtp_payloads) {
+    AppendPacket(&buf, packet);
+  }
+  RTC_DCHECK_EQ(buf - bitstream->data(), bitstream->size());
+  return bitstream;
+}
+
+size_t VideoRtpDepacketizerH264::CalculatePacketSize(
+    const RtpPacketView& packet) {
+  const auto& h264_header =
+      absl::get<RTPVideoHeaderH264>(packet.video_header->video_type_header);
+
+  size_t required_size = 0;
+
+  if (h264_header.extra_data) {
+    required_size += sizeof(start_code_h264);
+    required_size += std::get<H264SpsInfo>(*h264_header.extra_data).size;
+    required_size += sizeof(start_code_h264);
+    required_size += std::get<H264PpsInfo>(*h264_header.extra_data).size;
+  }
+
+  if (h264_header.packetization_type == kH264StapA) {
+    const uint8_t* nalu_ptr = packet.payload.data() + 1;
+    while (nalu_ptr < packet.payload.data() + packet.payload.size() - 1) {
+      RTC_DCHECK(packet.video_header->is_first_packet_in_frame);
+      required_size += sizeof(start_code_h264);
+
+      // The first two bytes describe the length of a segment.
+      uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
+      nalu_ptr += 2;
+
+      required_size += segment_length;
+      nalu_ptr += segment_length;
+    }
+  } else {
+    if (h264_header.nalus_length > 0) {
+      required_size += sizeof(start_code_h264);
+    }
+    if (h264_header.nalus_length > 0 &&
+        h264_header.packetization_type == kH264FuA) {
+      required_size += 1;
+    }
+    required_size += packet.payload.size();
+  }
+
+  return required_size;
+}
+
+void VideoRtpDepacketizerH264::AppendPacket(uint8_t** buf,
+                                            const RtpPacketView& packet) {
+  const auto& h264_header =
+      absl::get<RTPVideoHeaderH264>(packet.video_header->video_type_header);
+  if (h264_header.extra_data) {
+    // Insert SPS.
+    const auto& sps = std::get<H264SpsInfo>(*h264_header.extra_data);
+    AppendData(buf, start_code_h264);
+    AppendData(buf, sps.data.data(), sps.size);
+
+    // Insert PPS.
+    const auto& pps = std::get<H264PpsInfo>(*h264_header.extra_data);
+    AppendData(buf, start_code_h264);
+    AppendData(buf, pps.data.data(), pps.size);
+  }
+
+  // Copy the rest of the bitstream and insert start codes.
+  if (h264_header.packetization_type == kH264StapA) {
+    const uint8_t* nalu_ptr = packet.payload.data() + 1;
+    while (nalu_ptr < packet.payload.data() + packet.payload.size() - 1) {
+      AppendData(buf, start_code_h264);
+
+      // The first two bytes describe the length of a segment.
+      uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
+      nalu_ptr += 2;
+
+      size_t copy_end = nalu_ptr - packet.payload.data() + segment_length;
+      RTC_DCHECK_LE(copy_end, packet.payload.size());
+
+      AppendData(buf, nalu_ptr, segment_length);
+      nalu_ptr += segment_length;
+    }
+  } else {
+    if (h264_header.nalus_length > 0) {
+      AppendData(buf, start_code_h264);
+      if (h264_header.packetization_type == kH264FuA) {
+        AppendData(buf, &h264_header.original_nal_header, 1);
+      }
+    }
+    AppendData(buf, packet.payload.data(), packet.payload.size());
+  }
+}
+
 }  // namespace webrtc
index cbea86004999ffd183bc24eccaf259456a1897bc..2681c9ffb257fdecaea3ff7ac4f798d8008b0ff3 100644 (file)
@@ -11,6 +11,9 @@
 #ifndef MODULES_RTP_RTCP_SOURCE_VIDEO_RTP_DEPACKETIZER_H264_H_
 #define MODULES_RTP_RTCP_SOURCE_VIDEO_RTP_DEPACKETIZER_H264_H_
 
+#include <map>
+#include <string>
+
 #include "absl/types/optional.h"
 #include "modules/rtp_rtcp/source/video_rtp_depacketizer.h"
 #include "rtc_base/copy_on_write_buffer.h"
@@ -22,6 +25,21 @@ class VideoRtpDepacketizerH264 : public VideoRtpDepacketizer {
 
   absl::optional<ParsedRtpPayload> Parse(
       rtc::CopyOnWriteBuffer rtp_payload) override;
+
+  rtc::scoped_refptr<EncodedImageBuffer> AssembleFrame(
+      rtc::ArrayView<RtpPacketView> rtp_packets) override;
+
+  void SetCodecParams(
+      const std::map<std::string, std::string>& codec_params) override;
+  PacketAction GetPacketAction(rtc::ArrayView<const uint8_t> bitstream,
+                               RTPVideoHeader* video_header) override;
+
+ private:
+  size_t CalculatePacketSize(const RtpPacketView& packet);
+  void AppendPacket(uint8_t** buf, const RtpPacketView& packet);
+
+  std::map<uint32_t, H264PpsInfo> pps_data_;
+  std::map<uint32_t, H264SpsInfo> sps_data_;
 };
 }  // namespace webrtc
 
index d335af0244c5cbcb9b8f38cc78851e4200c90fdd..cbf063d00188d4b7468e443e4f9b0db9af811ef1 100644 (file)
 #include "absl/types/optional.h"
 #include "api/array_view.h"
 #include "common_video/h264/h264_common.h"
-#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
+#include "media/base/media_constants.h"
 #include "modules/rtp_rtcp/source/byte_io.h"
+#include "modules/rtp_rtcp/source/video_rtp_depacketizer.h"
 #include "rtc_base/copy_on_write_buffer.h"
+#include "rtc_base/third_party/base64/base64.h"
 #include "test/gmock.h"
 #include "test/gtest.h"
 
@@ -32,6 +34,8 @@ using ::testing::Eq;
 using ::testing::IsEmpty;
 using ::testing::SizeIs;
 
+using RtpPacketView = VideoRtpDepacketizer::RtpPacketView;
+
 enum Nalu {
   kSlice = 1,
   kIdr = 5,
@@ -56,6 +60,51 @@ constexpr uint8_t kRewrittenSps[] = {kSps, 0x00, 0x00, 0x03, 0x03,
 constexpr uint8_t kIdrOne[] = {kIdr, 0xFF, 0x00, 0x00, 0x04};
 constexpr uint8_t kIdrTwo[] = {kIdr, 0xFF, 0x00, 0x11};
 
+const uint8_t start_code[] = {0, 0, 0, 1};
+
+rtc::ArrayView<const uint8_t> Bitstream(const EncodedImageBuffer& fixed) {
+  return fixed;
+}
+
+void ExpectSpsPpsIdr(const RTPVideoHeaderH264& codec_header,
+                     uint8_t sps_id,
+                     uint8_t pps_id) {
+  bool contains_sps = false;
+  bool contains_pps = false;
+  bool contains_idr = false;
+  for (const auto& nalu : codec_header.nalus) {
+    if (nalu.type == H264::NaluType::kSps) {
+      EXPECT_EQ(sps_id, nalu.sps_id);
+      contains_sps = true;
+    } else if (nalu.type == H264::NaluType::kPps) {
+      EXPECT_EQ(sps_id, nalu.sps_id);
+      EXPECT_EQ(pps_id, nalu.pps_id);
+      contains_pps = true;
+    } else if (nalu.type == H264::NaluType::kIdr) {
+      EXPECT_EQ(pps_id, nalu.pps_id);
+      contains_idr = true;
+    }
+  }
+  EXPECT_TRUE(contains_sps);
+  EXPECT_TRUE(contains_pps);
+  EXPECT_TRUE(contains_idr);
+}
+
+class H264VideoHeader : public RTPVideoHeader {
+ public:
+  H264VideoHeader() {
+    codec = kVideoCodecH264;
+    is_first_packet_in_frame = false;
+    auto& h264_header = video_type_header.emplace<RTPVideoHeaderH264>();
+    h264_header.nalus_length = 0;
+    h264_header.packetization_type = kH264SingleNalu;
+  }
+
+  RTPVideoHeaderH264& h264() {
+    return absl::get<RTPVideoHeaderH264>(video_type_header);
+  }
+};
+
 TEST(VideoRtpDepacketizerH264Test, SingleNalu) {
   uint8_t packet[2] = {0x05, 0xFF};  // F=0, NRI=0, Type=5 (IDR).
   rtc::CopyOnWriteBuffer rtp_payload(packet);
@@ -319,11 +368,17 @@ TEST(VideoRtpDepacketizerH264Test, FuA) {
   absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> parsed1 =
       depacketizer.Parse(rtc::CopyOnWriteBuffer(packet1));
   ASSERT_TRUE(parsed1);
-  // We expect that the first packet is one byte shorter since the FU-A header
-  // has been replaced by the original nal header.
-  EXPECT_THAT(rtc::MakeArrayView(parsed1->video_payload.cdata(),
-                                 parsed1->video_payload.size()),
-              ElementsAreArray(kExpected1));
+  std::vector<uint8_t> parsed1_data;
+  // We expect that for the first packet is returned video header carries
+  // the original nal header extracted from FU-A header and payload will
+  // be 2 bytes shorter.
+  parsed1_data.push_back(
+      absl::get<RTPVideoHeaderH264>(parsed1->video_header.video_type_header)
+          .original_nal_header);
+  parsed1_data.insert(
+      parsed1_data.end(), parsed1->video_payload.cdata(),
+      parsed1->video_payload.cdata() + parsed1->video_payload.size());
+  EXPECT_THAT(parsed1_data, ElementsAreArray(kExpected1));
   EXPECT_EQ(parsed1->video_header.frame_type, VideoFrameType::kVideoFrameKey);
   EXPECT_EQ(parsed1->video_header.codec, kVideoCodecH264);
   EXPECT_TRUE(parsed1->video_header.is_first_packet_in_frame);
@@ -426,5 +481,311 @@ TEST(VideoRtpDepacketizerH264Test, SeiPacket) {
   EXPECT_EQ(h264.nalus[0].pps_id, -1);
 }
 
+class TestH264SpsPpsTracker : public ::testing::Test {
+ public:
+  void AddSps(H264VideoHeader* header,
+              uint8_t sps_id,
+              std::vector<uint8_t>* data) {
+    NaluInfo info;
+    info.type = H264::NaluType::kSps;
+    info.sps_id = sps_id;
+    info.pps_id = -1;
+    data->push_back(H264::NaluType::kSps);
+    data->push_back(sps_id);  // The sps data, just a single byte.
+
+    header->h264().nalus[header->h264().nalus_length++] = info;
+  }
+
+  void AddPps(H264VideoHeader* header,
+              uint8_t sps_id,
+              uint8_t pps_id,
+              std::vector<uint8_t>* data) {
+    NaluInfo info;
+    info.type = H264::NaluType::kPps;
+    info.sps_id = sps_id;
+    info.pps_id = pps_id;
+    data->push_back(H264::NaluType::kPps);
+    data->push_back(pps_id);  // The pps data, just a single byte.
+
+    header->h264().nalus[header->h264().nalus_length++] = info;
+  }
+
+  void AddIdr(H264VideoHeader* header, int pps_id) {
+    NaluInfo info;
+    info.type = H264::NaluType::kIdr;
+    info.sps_id = -1;
+    info.pps_id = pps_id;
+
+    header->h264().nalus[header->h264().nalus_length++] = info;
+  }
+
+  void SetCodecParams(const std::vector<uint8_t>& sps,
+                      const std::vector<uint8_t>& pps) {
+    std::string sps_str;
+    rtc::Base64::EncodeFromArray(sps.data(), sps.size(), &sps_str);
+    std::string pps_str;
+    rtc::Base64::EncodeFromArray(pps.data(), pps.size(), &pps_str);
+    std::map<std::string, std::string> codec_params = {
+        {cricket::kH264FmtpSpropParameterSets, sps_str + "," + pps_str}};
+    tracker_.SetCodecParams(codec_params);
+  }
+
+ protected:
+  VideoRtpDepacketizerH264 tracker_;
+};
+
+TEST_F(TestH264SpsPpsTracker, NoNalus) {
+  uint8_t data[] = {1, 2, 3};
+  H264VideoHeader header;
+  header.h264().packetization_type = kH264FuA;
+
+  auto action = tracker_.GetPacketAction(data, &header);
+  RtpPacketView packets[] = {{&header, data}};
+  auto frame = tracker_.AssembleFrame(packets);
+
+  EXPECT_EQ(action, VideoRtpDepacketizer::kInsert);
+  EXPECT_THAT(Bitstream(*frame), ElementsAreArray(data));
+}
+
+TEST_F(TestH264SpsPpsTracker, FuAFirstPacket) {
+  uint8_t data[] = {1, 2, 3};
+  H264VideoHeader header;
+  header.h264().packetization_type = kH264FuA;
+  header.h264().nalus_length = 1;
+  header.h264().original_nal_header = kIdr;
+  header.is_first_packet_in_frame = true;
+
+  auto action = tracker_.GetPacketAction(data, &header);
+  RtpPacketView packets[] = {{&header, data}};
+  auto frame = tracker_.AssembleFrame(packets);
+
+  EXPECT_EQ(action, VideoRtpDepacketizer::kInsert);
+  std::vector<uint8_t> expected;
+  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
+  expected.insert(expected.end(), {kIdr, 1, 2, 3});
+  EXPECT_THAT(Bitstream(*frame), ElementsAreArray(expected));
+}
+
+TEST_F(TestH264SpsPpsTracker, StapAIncorrectSegmentLength) {
+  uint8_t data[] = {0, 0, 2, 0};
+  H264VideoHeader header;
+  header.h264().packetization_type = kH264StapA;
+  header.is_first_packet_in_frame = true;
+
+  EXPECT_EQ(tracker_.GetPacketAction(data, &header),
+            VideoRtpDepacketizer::kDrop);
+}
+
+TEST_F(TestH264SpsPpsTracker, SingleNaluInsertStartCode) {
+  uint8_t data[] = {1, 2, 3};
+  H264VideoHeader header;
+  header.h264().nalus_length = 1;
+
+  auto action = tracker_.GetPacketAction(data, &header);
+  RtpPacketView packets[] = {{&header, data}};
+  auto frame = tracker_.AssembleFrame(packets);
+
+  EXPECT_EQ(action, VideoRtpDepacketizer::kInsert);
+  std::vector<uint8_t> expected;
+  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
+  expected.insert(expected.end(), {1, 2, 3});
+  EXPECT_THAT(Bitstream(*frame), ElementsAreArray(expected));
+}
+
+TEST_F(TestH264SpsPpsTracker, NoStartCodeInsertedForSubsequentFuAPacket) {
+  std::vector<uint8_t> data = {1, 2, 3};
+  H264VideoHeader header;
+  header.h264().packetization_type = kH264FuA;
+  // Since no NALU begin in this packet the nalus_length is zero.
+  header.h264().nalus_length = 0;
+
+  auto action = tracker_.GetPacketAction(data, &header);
+  RtpPacketView packets[] = {{&header, data}};
+  auto frame = tracker_.AssembleFrame(packets);
+
+  EXPECT_EQ(action, VideoRtpDepacketizer::kInsert);
+  EXPECT_THAT(Bitstream(*frame), ElementsAreArray(data));
+}
+
+TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsPpsInserted) {
+  std::vector<uint8_t> data = {1, 2, 3};
+  H264VideoHeader header;
+  header.is_first_packet_in_frame = true;
+  AddIdr(&header, 0);
+
+  EXPECT_EQ(tracker_.GetPacketAction(data, &header),
+            VideoRtpDepacketizer::kRequestKeyframe);
+}
+
+TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoPpsInserted) {
+  std::vector<uint8_t> data = {1, 2, 3};
+  H264VideoHeader header;
+  header.is_first_packet_in_frame = true;
+  AddSps(&header, 0, &data);
+  AddIdr(&header, 0);
+
+  EXPECT_EQ(tracker_.GetPacketAction(data, &header),
+            VideoRtpDepacketizer::kRequestKeyframe);
+}
+
+TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsInserted) {
+  std::vector<uint8_t> data = {1, 2, 3};
+  H264VideoHeader header;
+  header.is_first_packet_in_frame = true;
+  AddPps(&header, 0, 0, &data);
+  AddIdr(&header, 0);
+
+  EXPECT_EQ(tracker_.GetPacketAction(data, &header),
+            VideoRtpDepacketizer::kRequestKeyframe);
+}
+
+TEST_F(TestH264SpsPpsTracker, SpsPpsPacketThenIdrFirstPacket) {
+  std::vector<uint8_t> data;
+  H264VideoHeader sps_pps_header;
+  // Insert SPS/PPS
+  AddSps(&sps_pps_header, 0, &data);
+  AddPps(&sps_pps_header, 0, 1, &data);
+
+  EXPECT_EQ(tracker_.GetPacketAction(data, &sps_pps_header),
+            VideoRtpDepacketizer::kInsert);
+
+  // Insert first packet of the IDR
+  H264VideoHeader idr_header;
+  idr_header.is_first_packet_in_frame = true;
+  AddIdr(&idr_header, 1);
+  data = {1, 2, 3};
+
+  auto action = tracker_.GetPacketAction(data, &idr_header);
+  RtpPacketView packets[] = {{&idr_header, data}};
+  auto frame = tracker_.AssembleFrame(packets);
+  EXPECT_EQ(action, VideoRtpDepacketizer::kInsert);
+
+  std::vector<uint8_t> expected;
+  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
+  expected.insert(expected.end(), {1, 2, 3});
+  EXPECT_THAT(Bitstream(*frame), ElementsAreArray(expected));
+}
+
+TEST_F(TestH264SpsPpsTracker, SpsPpsIdrInStapA) {
+  std::vector<uint8_t> data;
+  H264VideoHeader header;
+  header.h264().packetization_type = kH264StapA;
+  header.is_first_packet_in_frame = true;  // Always true for StapA
+
+  data.insert(data.end(), {0});     // First byte is ignored
+  data.insert(data.end(), {0, 2});  // Length of segment
+  AddSps(&header, 13, &data);
+  data.insert(data.end(), {0, 2});  // Length of segment
+  AddPps(&header, 13, 27, &data);
+  data.insert(data.end(), {0, 5});  // Length of segment
+  AddIdr(&header, 27);
+  data.insert(data.end(), {1, 2, 3, 2, 1});
+
+  auto action = tracker_.GetPacketAction(data, &header);
+  RtpPacketView packets[] = {{&header, data}};
+  auto frame = tracker_.AssembleFrame(packets);
+
+  EXPECT_THAT(action, VideoRtpDepacketizer::kInsert);
+
+  std::vector<uint8_t> expected;
+  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
+  expected.insert(expected.end(), {H264::NaluType::kSps, 13});
+  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
+  expected.insert(expected.end(), {H264::NaluType::kPps, 27});
+  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
+  expected.insert(expected.end(), {1, 2, 3, 2, 1});
+  EXPECT_THAT(Bitstream(*frame), ElementsAreArray(expected));
+}
+
+TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBand) {
+  constexpr uint8_t kData[] = {1, 2, 3};
+
+  // Generated by "ffmpeg -r 30 -f avfoundation -i "default" out.h264" on macos.
+  // width: 320, height: 240
+  const std::vector<uint8_t> sps(
+      {0x67, 0x7a, 0x00, 0x0d, 0xbc, 0xd9, 0x41, 0x41, 0xfa, 0x10, 0x00, 0x00,
+       0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0xc0, 0xf1, 0x42, 0x99, 0x60});
+  const std::vector<uint8_t> pps({0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0});
+  SetCodecParams(sps, pps);
+
+  // Insert first packet of the IDR.
+  H264VideoHeader idr_header;
+  idr_header.is_first_packet_in_frame = true;
+  AddIdr(&idr_header, 0);
+  EXPECT_EQ(idr_header.h264().nalus_length, 1u);
+
+  auto action = tracker_.GetPacketAction(kData, &idr_header);
+  EXPECT_THAT(action, VideoRtpDepacketizer::kInsert);
+
+  EXPECT_EQ(idr_header.h264().nalus_length, 3u);
+  EXPECT_EQ(idr_header.width, 320u);
+  EXPECT_EQ(idr_header.height, 240u);
+  ExpectSpsPpsIdr(idr_header.h264(), 0, 0);
+}
+
+TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBandWrongNaluHeader) {
+  constexpr uint8_t kData[] = {1, 2, 3};
+
+  // Generated by "ffmpeg -r 30 -f avfoundation -i "default" out.h264" on macos.
+  // Nalu headers manupilated afterwards.
+  const std::vector<uint8_t> sps(
+      {0xff, 0x7a, 0x00, 0x0d, 0xbc, 0xd9, 0x41, 0x41, 0xfa, 0x10, 0x00, 0x00,
+       0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0xc0, 0xf1, 0x42, 0x99, 0x60});
+  const std::vector<uint8_t> pps({0xff, 0xeb, 0xe3, 0xcb, 0x22, 0xc0});
+  SetCodecParams(sps, pps);
+
+  // Insert first packet of the IDR.
+  H264VideoHeader idr_header;
+  idr_header.is_first_packet_in_frame = true;
+  AddIdr(&idr_header, 0);
+
+  EXPECT_EQ(tracker_.GetPacketAction(kData, &idr_header),
+            VideoRtpDepacketizer::kRequestKeyframe);
+}
+
+TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBandIncompleteNalu) {
+  constexpr uint8_t kData[] = {1, 2, 3};
+
+  // Generated by "ffmpeg -r 30 -f avfoundation -i "default" out.h264" on macos.
+  // Nalus damaged afterwards.
+  const std::vector<uint8_t> sps({0x67, 0x7a, 0x00, 0x0d, 0xbc, 0xd9});
+  const std::vector<uint8_t> pps({0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0});
+  SetCodecParams(sps, pps);
+
+  // Insert first packet of the IDR.
+  H264VideoHeader idr_header;
+  idr_header.is_first_packet_in_frame = true;
+  AddIdr(&idr_header, 0);
+
+  EXPECT_EQ(tracker_.GetPacketAction(kData, &idr_header),
+            VideoRtpDepacketizer::kRequestKeyframe);
+}
+
+TEST_F(TestH264SpsPpsTracker, SaveRestoreWidthHeight) {
+  std::vector<uint8_t> data;
+
+  // Insert an SPS/PPS packet with width/height and make sure
+  // that information is set on the first IDR packet.
+  H264VideoHeader sps_pps_header;
+  AddSps(&sps_pps_header, 0, &data);
+  AddPps(&sps_pps_header, 0, 1, &data);
+  sps_pps_header.width = 320;
+  sps_pps_header.height = 240;
+
+  EXPECT_EQ(tracker_.GetPacketAction(data, &sps_pps_header),
+            VideoRtpDepacketizer::kInsert);
+
+  H264VideoHeader idr_header;
+  idr_header.is_first_packet_in_frame = true;
+  AddIdr(&idr_header, 1);
+  data.insert(data.end(), {1, 2, 3});
+
+  EXPECT_EQ(tracker_.GetPacketAction(data, &idr_header),
+            VideoRtpDepacketizer::kInsert);
+
+  EXPECT_EQ(idr_header.width, 320);
+  EXPECT_EQ(idr_header.height, 240);
+}
+
 }  // namespace
 }  // namespace webrtc
index 74e18faa051cc23dbff91a67b2bf8c88635fca56..f3bd6027665c161ec758969d0d534a2ab99932be 100644 (file)
 
 #include <cstddef>
 #include <cstdint>
+#include <map>
 #include <memory>
+#include <string>
+#include <tuple>
 #include <utility>
 #include <vector>
 
-#include "absl/base/macros.h"
 #include "absl/types/optional.h"
 #include "absl/types/variant.h"
-#include "common_video/h264/h264_common.h"
 #include "common_video/h265/h265_common.h"
 #include "common_video/h265/h265_pps_parser.h"
 #include "common_video/h265/h265_sps_parser.h"
@@ -33,6 +34,8 @@
 namespace webrtc {
 namespace {
 
+const uint8_t start_code_h265[] = {0, 0, 0, 1};
+
 enum NaluType {
   kTrailN = 0,
   kTrailR = 1,
@@ -145,6 +148,7 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ProcessApOrSingleNalu(
     nalu_start_offsets.push_back(0);
   }
   h265_header.nalu_type = nal_type;
+  h265_header.first_fragment = true;
   parsed_payload->video_header.frame_type = VideoFrameType::kVideoFrameDelta;
 
   nalu_start_offsets.push_back(rtp_payload.size() +
@@ -299,15 +303,10 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ParseFuNalu(
              "unit with original type: "
           << static_cast<int>(nalu.type);
     }
-    rtp_payload = rtp_payload.Slice(1, rtp_payload.size() - 1);
-    rtp_payload.MutableData()[0] = f | original_nal_type << 1 | layer_id_h;
-    rtp_payload.MutableData()[1] = layer_id_l_unshifted | tid;
-    parsed_payload->video_payload = std::move(rtp_payload);
-  } else {
-    parsed_payload->video_payload = rtp_payload.Slice(
-        kHevcNalHeaderSize + kHevcFuHeaderSize,
-        rtp_payload.size() - kHevcNalHeaderSize - kHevcFuHeaderSize);
   }
+  parsed_payload->video_payload = rtp_payload.Slice(
+      kHevcNalHeaderSize + kHevcFuHeaderSize,
+      rtp_payload.size() - kHevcNalHeaderSize - kHevcFuHeaderSize);
 
   if (original_nal_type == H265::NaluType::kIdrWRadl ||
       original_nal_type == H265::NaluType::kIdrNLp ||
@@ -324,9 +323,12 @@ absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> ParseFuNalu(
                           .emplace<RTPVideoHeaderH265>();
   h265_header.packetization_type = kH265FU;
   h265_header.nalu_type = original_nal_type;
+  h265_header.first_fragment = first_fragment;
   if (first_fragment) {
     h265_header.nalus[h265_header.nalus_length] = nalu;
     h265_header.nalus_length = 1;
+    h265_header.fau_nal_header[0] = f | original_nal_type << 1 | layer_id_h;
+    h265_header.fau_nal_header[1] = layer_id_l_unshifted | tid;
   }
   return parsed_payload;
 }
@@ -353,4 +355,258 @@ VideoRtpDepacketizerH265::Parse(rtc::CopyOnWriteBuffer rtp_payload) {
   }
 }
 
+void VideoRtpDepacketizerH265::SetCodecParams(
+    const std::map<std::string, std::string>& codec_params) {
+  RTC_LOG(LS_WARNING) << "VideoRtpDepacketizerH265 add parsing out-of-band "
+                      << "codec parameters...";
+}
+
+VideoRtpDepacketizer::PacketAction VideoRtpDepacketizerH265::GetPacketAction(
+    rtc::ArrayView<const uint8_t> bitstream,
+    RTPVideoHeader* video_header) {
+  RTC_DCHECK(video_header);
+  RTC_DCHECK(video_header->codec == kVideoCodecH265);
+
+  auto& h265_header =
+      absl::get<RTPVideoHeaderH265>(video_header->video_type_header);
+
+  bool append_vps_sps_pps = false;
+  auto vps = vps_data_.end();
+  auto sps = sps_data_.end();
+  auto pps = pps_data_.end();
+
+  for (size_t i = 0; i < h265_header.nalus_length; ++i) {
+    const H265NaluInfo& nalu = h265_header.nalus[i];
+    switch (nalu.type) {
+      case H265::NaluType::kVps: {
+        vps_data_[nalu.vps_id].size = 0;
+        break;
+      }
+      case H265::NaluType::kSps: {
+        sps_data_[nalu.sps_id].vps_id = nalu.vps_id;
+        sps_data_[nalu.sps_id].width = video_header->width;
+        sps_data_[nalu.sps_id].height = video_header->height;
+        break;
+      }
+      case H265::NaluType::kPps: {
+        pps_data_[nalu.pps_id].sps_id = nalu.sps_id;
+        break;
+      }
+      case H265::NaluType::kIdrWRadl:
+      case H265::NaluType::kIdrNLp:
+      case H265::NaluType::kCra: {
+        // If this is the first packet of an IDR, make sure we have the required
+        // SPS/PPS and also calculate how much extra space we need in the buffer
+        // to prepend the SPS/PPS to the bitstream with start codes.
+        if (video_header->is_first_packet_in_frame) {
+          if (nalu.pps_id == -1) {
+            RTC_LOG(LS_WARNING) << "No PPS id in IDR nalu.";
+            return kRequestKeyframe;
+          }
+
+          pps = pps_data_.find(nalu.pps_id);
+          if (pps == pps_data_.end()) {
+            RTC_LOG(LS_WARNING)
+                << "No PPS with id " << nalu.pps_id << " received";
+            return kRequestKeyframe;
+          }
+
+          sps = sps_data_.find(pps->second.sps_id);
+          if (sps == sps_data_.end()) {
+            RTC_LOG(LS_WARNING)
+                << "No SPS with id << " << pps->second.sps_id << " received";
+            return kRequestKeyframe;
+          }
+
+          vps = vps_data_.find(sps->second.vps_id);
+          if (vps == vps_data_.end()) {
+            RTC_LOG(LS_WARNING)
+                << "No VPS with id " << sps->second.vps_id << " received";
+            return kRequestKeyframe;
+          }
+
+          // Since the first packet of every keyframe should have its width and
+          // height set we set it here in the case of it being supplied out of
+          // band.
+          video_header->width = sps->second.width;
+          video_header->height = sps->second.height;
+
+          // If the VPS/SPS/PPS was supplied out of band then we will have saved
+          // the actual bitstream in |data|.
+          // This branch is not verified.
+          if (!vps->second.data.empty() && !sps->second.data.empty() &&
+              !pps->second.data.empty()) {
+            RTC_DCHECK_GT(vps->second.size, 0);
+            RTC_DCHECK_GT(sps->second.size, 0);
+            RTC_DCHECK_GT(pps->second.size, 0);
+            append_vps_sps_pps = true;
+          }
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+
+  RTC_CHECK(!append_vps_sps_pps ||
+            (sps != sps_data_.end() && pps != pps_data_.end()));
+
+  if (append_vps_sps_pps) {
+    h265_header.extra_data = absl::make_optional(
+        std::make_tuple(vps->second, pps->second, sps->second));
+
+    // Update codec header to reflect the newly added SPS and PPS.
+    H265NaluInfo vps_info;
+    vps_info.type = H265::NaluType::kVps;
+    vps_info.vps_id = vps->first;
+    vps_info.sps_id = -1;
+    vps_info.pps_id = -1;
+    H265NaluInfo sps_info;
+    sps_info.type = H265::NaluType::kSps;
+    sps_info.vps_id = vps->first;
+    sps_info.sps_id = sps->first;
+    sps_info.pps_id = -1;
+    H265NaluInfo pps_info;
+    pps_info.type = H265::NaluType::kPps;
+    pps_info.vps_id = vps->first;
+    pps_info.sps_id = sps->first;
+    pps_info.pps_id = pps->first;
+    if (h265_header.nalus_length + 2 <= kMaxNalusPerPacket) {
+      h265_header.nalus[h265_header.nalus_length++] = vps_info;
+      h265_header.nalus[h265_header.nalus_length++] = sps_info;
+      h265_header.nalus[h265_header.nalus_length++] = pps_info;
+    } else {
+      RTC_LOG(LS_WARNING) << "Not enough space in H.265 codec header to insert "
+                             "SPS/PPS provided out-of-band.";
+    }
+  }
+
+  if (h265_header.packetization_type == kH265AP) {
+    const uint8_t* nalu_ptr = bitstream.data() + 1;
+    while (nalu_ptr < bitstream.data() + bitstream.size()) {
+      // The first two bytes describe the length of a segment.
+      uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
+      nalu_ptr += 2;
+
+      size_t copy_end = nalu_ptr - bitstream.data() + segment_length;
+      if (copy_end > bitstream.size()) {
+        return kDrop;
+      }
+
+      nalu_ptr += segment_length;
+    }
+  }
+
+  return kInsert;
+}
+
+rtc::scoped_refptr<EncodedImageBuffer> VideoRtpDepacketizerH265::AssembleFrame(
+    rtc::ArrayView<RtpPacketView> rtp_payloads) {
+  size_t frame_size = 0;
+  for (const auto& packet : rtp_payloads) {
+    frame_size += CalculatePacketSize(packet);
+  }
+
+  rtc::scoped_refptr<EncodedImageBuffer> bitstream =
+      EncodedImageBuffer::Create(frame_size);
+
+  uint8_t* buf = bitstream->data();
+  for (const auto& packet : rtp_payloads) {
+    AppendPacket(&buf, packet);
+  }
+  RTC_DCHECK_EQ(buf - bitstream->data(), bitstream->size());
+  return bitstream;
+}
+
+size_t VideoRtpDepacketizerH265::CalculatePacketSize(
+    const RtpPacketView& packet) {
+  auto& h265_header =
+      absl::get<RTPVideoHeaderH265>(packet.video_header->video_type_header);
+  size_t required_size = 0;
+
+  if (h265_header.extra_data) {
+    required_size += sizeof(start_code_h265);
+    required_size += std::get<H265VpsInfo>(*h265_header.extra_data).size;
+    required_size += sizeof(start_code_h265);
+    required_size += std::get<H265SpsInfo>(*h265_header.extra_data).size;
+    required_size += sizeof(start_code_h265);
+    required_size += std::get<H265PpsInfo>(*h265_header.extra_data).size;
+  }
+
+  if (h265_header.packetization_type == kH265AP) {
+    const uint8_t* nalu_ptr = packet.payload.data() + 1;
+    while (nalu_ptr < packet.payload.data() + packet.payload.size()) {
+      RTC_DCHECK(h265_header.first_fragment);
+      required_size += sizeof(start_code_h265);
+
+      // The first two bytes describe the length of a segment.
+      uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
+      nalu_ptr += 2;
+
+      required_size += segment_length;
+      nalu_ptr += segment_length;
+    }
+  } else {
+    // Note: In h.264 this is "h264_header.nalus_length > 0"
+    if (h265_header.first_fragment) {
+      required_size += sizeof(start_code_h265);
+      required_size += (h265_header.packetization_type == kH265FU ? 2 : 0);
+    }
+    required_size += packet.payload.size();
+  }
+
+  return required_size;
+}
+
+void VideoRtpDepacketizerH265::AppendPacket(uint8_t** buf,
+                                            const RtpPacketView& packet) {
+  auto& h265_header =
+      absl::get<RTPVideoHeaderH265>(packet.video_header->video_type_header);
+
+  if (h265_header.extra_data) {
+    // Insert VPS.
+    const auto& vps = std::get<H265VpsInfo>(*h265_header.extra_data);
+    AppendData(buf, start_code_h265);
+    AppendData(buf, vps.data.data(), vps.size);
+
+    // Insert SPS.
+    const auto& sps = std::get<H265SpsInfo>(*h265_header.extra_data);
+    AppendData(buf, start_code_h265);
+    AppendData(buf, sps.data.data(), sps.size);
+
+    // Insert PPS.
+    const auto& pps = std::get<H265PpsInfo>(*h265_header.extra_data);
+    AppendData(buf, start_code_h265);
+    AppendData(buf, pps.data.data(), pps.size);
+  }
+
+  // Copy the rest of the bitstream and insert start codes.
+  if (h265_header.packetization_type == kH265AP) {
+    const uint8_t* nalu_ptr = packet.payload.data() + 1;
+    while (nalu_ptr < packet.payload.data() + packet.payload.size()) {
+      AppendData(buf, start_code_h265);
+
+      // The first two bytes describe the length of a segment.
+      uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
+      nalu_ptr += 2;
+
+      size_t copy_end = nalu_ptr - packet.payload.data() + segment_length;
+      RTC_DCHECK_LE(copy_end, packet.payload.size());
+
+      AppendData(buf, nalu_ptr, segment_length);
+      nalu_ptr += segment_length;
+    }
+  } else {
+    // For h.264 it is "h264_header.nalus_length > 0"
+    if (h265_header.first_fragment) {
+      AppendData(buf, start_code_h265);
+      if (h265_header.packetization_type == kH265FU) {
+        AppendData(buf, h265_header.fau_nal_header, 2);
+      }
+    }
+    AppendData(buf, packet.payload.data(), packet.payload.size());
+  }
+}
+
 }  // namespace webrtc
index f2e7a2f24d9028f8dc2cd369657541bdeb062292..536deaa4738eb2f75a04c34f23e4eb5c6d6ff312 100644 (file)
@@ -11,6 +11,9 @@
 #ifndef THIRD_PARTY_WEBRTC_MODULES_RTP_RTCP_SOURCE_VIDEO_RTP_DEPACKETIZER_H265_H_
 #define THIRD_PARTY_WEBRTC_MODULES_RTP_RTCP_SOURCE_VIDEO_RTP_DEPACKETIZER_H265_H_
 
+#include <map>
+#include <string>
+
 #include "absl/types/optional.h"
 #include "modules/rtp_rtcp/source/video_rtp_depacketizer.h"
 #include "rtc_base/copy_on_write_buffer.h"
@@ -22,6 +25,22 @@ class VideoRtpDepacketizerH265 : public VideoRtpDepacketizer {
 
   absl::optional<ParsedRtpPayload> Parse(
       rtc::CopyOnWriteBuffer rtp_payload) override;
+
+  rtc::scoped_refptr<EncodedImageBuffer> AssembleFrame(
+      rtc::ArrayView<RtpPacketView> rtp_packets) override;
+
+  void SetCodecParams(
+      const std::map<std::string, std::string>& codec_params) override;
+  PacketAction GetPacketAction(rtc::ArrayView<const uint8_t> bitstream,
+                               RTPVideoHeader* video_header) override;
+
+ private:
+  size_t CalculatePacketSize(const RtpPacketView& packet);
+  void AppendPacket(uint8_t** buf, const RtpPacketView& packet);
+
+  std::map<uint32_t, H265VpsInfo> vps_data_;
+  std::map<uint32_t, H265PpsInfo> pps_data_;
+  std::map<uint32_t, H265SpsInfo> sps_data_;
 };
 }  // namespace webrtc
 
index 4b3adff2b3bbc6ac0ccd1a2922473473c9793d89..03f933064dd15ea0968fe3a69fcbe9d9fdafaa23 100644 (file)
@@ -117,8 +117,6 @@ rtc_library("video_coding") {
     "generic_decoder.h",
     "h264_sprop_parameter_sets.cc",
     "h264_sprop_parameter_sets.h",
-    "h264_sps_pps_tracker.cc",
-    "h264_sps_pps_tracker.h",
     "include/video_codec_initializer.h",
     "inter_frame_delay.cc",
     "inter_frame_delay.h",
@@ -156,13 +154,6 @@ rtc_library("video_coding") {
     "video_receiver2.h",
   ]
 
-  if (tizen_product_tv && enable_platform_hevc) {
-    sources += [
-      "h265_vps_sps_pps_tracker.cc",
-      "h265_vps_sps_pps_tracker.h",
-    ]
-  }
-
   deps = [
     ":codec_globals_headers",
     ":encoded_frame",
@@ -974,7 +965,6 @@ if (rtc_include_tests) {
       "frame_dependencies_calculator_unittest.cc",
       "generic_decoder_unittest.cc",
       "h264_sprop_parameter_sets_unittest.cc",
-      "h264_sps_pps_tracker_unittest.cc",
       "histogram_unittest.cc",
       "jitter_buffer_unittest.cc",
       "jitter_estimator_tests.cc",
index 073d8f9a81e9d555db332cccb6f5f606da49036a..2ba373edee942bb1124317ce20c01cf8c7c989ef 100644 (file)
 #define MODULES_VIDEO_CODING_CODECS_H264_INCLUDE_H264_GLOBALS_H_
 
 #include <string>
+#include <tuple>
+#include <vector>
 
+#include "absl/types/optional.h"
 #include "modules/video_coding/codecs/interface/common_constants.h"
 #include "rtc_base/checks.h"
 
@@ -64,6 +67,19 @@ struct NaluInfo {
 
 const size_t kMaxNalusPerPacket = 10;
 
+struct H264PpsInfo {
+  int sps_id = -1;
+  size_t size = 0;
+  std::vector<uint8_t> data;  // TODO(a.bujalski) shared_ptr to array?
+};
+
+struct H264SpsInfo {
+  size_t size = 0;
+  int width = -1;
+  int height = -1;
+  std::vector<uint8_t> data;
+};
+
 struct RTPVideoHeaderH264 {
   // The NAL unit type. If this is a header for a
   // fragmented packet, it's the NAL unit type of
@@ -78,8 +94,10 @@ struct RTPVideoHeaderH264 {
   // The packetization mode of this transport. Packetization mode
   // determines which packetization types are allowed when packetizing.
   H264PacketizationMode packetization_mode;
+  // valid only for first packet of kH264FuA
+  uint8_t original_nal_header;
+  absl::optional<std::tuple<H264PpsInfo, H264SpsInfo>> extra_data;
 };
-
 }  // namespace webrtc
 
 #endif  // MODULES_VIDEO_CODING_CODECS_H264_INCLUDE_H264_GLOBALS_H_
index ffc70198006a0191a7dd514a0c2c6ffda384951b..7ed421f5529ad6dd90a7a106af11786c8096606d 100644 (file)
 #ifndef THIRD_PARTY_WEBRTC_MODULES_VIDEO_CODING_CODECS_H265_INCLUDE_H265_GLOBALS_H_
 #define THIRD_PARTY_WEBRTC_MODULES_VIDEO_CODING_CODECS_H265_INCLUDE_H265_GLOBALS_H_
 
+#include <tuple>
+#include <vector>
+
+#include "absl/types/optional.h"
 #include "modules/video_coding/codecs/h264/include/h264_globals.h"
 
 namespace webrtc {
@@ -41,6 +45,27 @@ enum class H265PacketizationMode {
   SingleNalUnit        // Mode 0 - only single NALU allowed
 };
 
+struct H265VpsInfo {
+  size_t size = 0;
+  std::vector<uint8_t> data;
+};
+
+// Maybe alias as this is the same as H264PpsInfo?
+struct H265PpsInfo {
+  int sps_id = -1;
+  size_t size = 0;
+  std::vector<uint8_t> data;
+};
+
+// What about inheritance from H264SpsInfo as there is only one field added?
+struct H265SpsInfo {
+  int vps_id = -1;
+  size_t size = 0;
+  int width = -1;
+  int height = -1;
+  std::vector<uint8_t> data;
+};
+
 struct RTPVideoHeaderH265 {
   // The NAL unit type. If this is a header for a fragmented packet, it's the
   // NAL unit type of the original data. If this is the header for an aggregated
@@ -51,6 +76,10 @@ struct RTPVideoHeaderH265 {
   size_t nalus_length;
   // The packetization type of this buffer - single, aggregated or fragmented.
   H265PacketizationMode packetization_mode;
+  bool first_fragment;  // Is this first NAL framgment/packet
+  // valid only for `first_fragment` of kH265FU
+  uint8_t fau_nal_header[2];
+  absl::optional<std::tuple<H265VpsInfo, H265PpsInfo, H265SpsInfo>> extra_data;
 };
 
 }  // namespace webrtc
diff --git a/third_party/webrtc/modules/video_coding/h264_sps_pps_tracker.cc b/third_party/webrtc/modules/video_coding/h264_sps_pps_tracker.cc
deleted file mode 100644 (file)
index 0741a26..0000000
+++ /dev/null
@@ -1,271 +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 "modules/video_coding/h264_sps_pps_tracker.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "absl/types/variant.h"
-#include "common_video/h264/h264_common.h"
-#include "common_video/h264/pps_parser.h"
-#include "common_video/h264/sps_parser.h"
-#include "modules/video_coding/codecs/h264/include/h264_globals.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-
-namespace webrtc {
-namespace video_coding {
-
-namespace {
-const uint8_t start_code_h264[] = {0, 0, 0, 1};
-}  // namespace
-
-H264SpsPpsTracker::H264SpsPpsTracker() = default;
-H264SpsPpsTracker::~H264SpsPpsTracker() = default;
-
-H264SpsPpsTracker::PpsInfo::PpsInfo() = default;
-H264SpsPpsTracker::PpsInfo::PpsInfo(PpsInfo&& rhs) = default;
-H264SpsPpsTracker::PpsInfo& H264SpsPpsTracker::PpsInfo::operator=(
-    PpsInfo&& rhs) = default;
-H264SpsPpsTracker::PpsInfo::~PpsInfo() = default;
-
-H264SpsPpsTracker::SpsInfo::SpsInfo() = default;
-H264SpsPpsTracker::SpsInfo::SpsInfo(SpsInfo&& rhs) = default;
-H264SpsPpsTracker::SpsInfo& H264SpsPpsTracker::SpsInfo::operator=(
-    SpsInfo&& rhs) = default;
-H264SpsPpsTracker::SpsInfo::~SpsInfo() = default;
-
-H264SpsPpsTracker::FixedBitstream H264SpsPpsTracker::CopyAndFixBitstream(
-    rtc::ArrayView<const uint8_t> bitstream,
-    RTPVideoHeader* video_header) {
-  RTC_DCHECK(video_header);
-  RTC_DCHECK(video_header->codec == kVideoCodecH264);
-  RTC_DCHECK_GT(bitstream.size(), 0);
-
-  auto& h264_header =
-      absl::get<RTPVideoHeaderH264>(video_header->video_type_header);
-
-  bool append_sps_pps = false;
-  auto sps = sps_data_.end();
-  auto pps = pps_data_.end();
-
-  for (size_t i = 0; i < h264_header.nalus_length; ++i) {
-    const NaluInfo& nalu = h264_header.nalus[i];
-    switch (nalu.type) {
-      case H264::NaluType::kSps: {
-        SpsInfo& sps_info = sps_data_[nalu.sps_id];
-        sps_info.width = video_header->width;
-        sps_info.height = video_header->height;
-        break;
-      }
-      case H264::NaluType::kPps: {
-        pps_data_[nalu.pps_id].sps_id = nalu.sps_id;
-        break;
-      }
-      case H264::NaluType::kIdr: {
-        // If this is the first packet of an IDR, make sure we have the required
-        // SPS/PPS and also calculate how much extra space we need in the buffer
-        // to prepend the SPS/PPS to the bitstream with start codes.
-        if (video_header->is_first_packet_in_frame) {
-          if (nalu.pps_id == -1) {
-            RTC_LOG(LS_WARNING) << "No PPS id in IDR nalu.";
-            return {kRequestKeyframe};
-          }
-
-          pps = pps_data_.find(nalu.pps_id);
-          if (pps == pps_data_.end()) {
-            RTC_LOG(LS_WARNING)
-                << "No PPS with id << " << nalu.pps_id << " received";
-            return {kRequestKeyframe};
-          }
-
-          sps = sps_data_.find(pps->second.sps_id);
-          if (sps == sps_data_.end()) {
-            RTC_LOG(LS_WARNING)
-                << "No SPS with id << " << pps->second.sps_id << " received";
-            return {kRequestKeyframe};
-          }
-
-          // Since the first packet of every keyframe should have its width and
-          // height set we set it here in the case of it being supplied out of
-          // band.
-          video_header->width = sps->second.width;
-          video_header->height = sps->second.height;
-
-          // If the SPS/PPS was supplied out of band then we will have saved
-          // the actual bitstream in `data`.
-          if (sps->second.data && pps->second.data) {
-            RTC_DCHECK_GT(sps->second.size, 0);
-            RTC_DCHECK_GT(pps->second.size, 0);
-            append_sps_pps = true;
-          }
-        }
-        break;
-      }
-      default:
-        break;
-    }
-  }
-
-  RTC_CHECK(!append_sps_pps ||
-            (sps != sps_data_.end() && pps != pps_data_.end()));
-
-  // Calculate how much space we need for the rest of the bitstream.
-  size_t required_size = 0;
-
-  if (append_sps_pps) {
-    required_size += sps->second.size + sizeof(start_code_h264);
-    required_size += pps->second.size + sizeof(start_code_h264);
-  }
-
-  if (h264_header.packetization_type == kH264StapA) {
-    const uint8_t* nalu_ptr = bitstream.data() + 1;
-    while (nalu_ptr < bitstream.data() + bitstream.size() - 1) {
-      RTC_DCHECK(video_header->is_first_packet_in_frame);
-      required_size += sizeof(start_code_h264);
-
-      // The first two bytes describe the length of a segment.
-      uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
-      nalu_ptr += 2;
-
-      required_size += segment_length;
-      nalu_ptr += segment_length;
-    }
-  } else {
-    if (h264_header.nalus_length > 0) {
-      required_size += sizeof(start_code_h264);
-    }
-    required_size += bitstream.size();
-  }
-
-  // Then we copy to the new buffer.
-  H264SpsPpsTracker::FixedBitstream fixed;
-  fixed.bitstream.EnsureCapacity(required_size);
-
-  if (append_sps_pps) {
-    // Insert SPS.
-    fixed.bitstream.AppendData(start_code_h264);
-    fixed.bitstream.AppendData(sps->second.data.get(), sps->second.size);
-
-    // Insert PPS.
-    fixed.bitstream.AppendData(start_code_h264);
-    fixed.bitstream.AppendData(pps->second.data.get(), pps->second.size);
-
-    // Update codec header to reflect the newly added SPS and PPS.
-    NaluInfo sps_info;
-    sps_info.type = H264::NaluType::kSps;
-    sps_info.sps_id = sps->first;
-    sps_info.pps_id = -1;
-    NaluInfo pps_info;
-    pps_info.type = H264::NaluType::kPps;
-    pps_info.sps_id = sps->first;
-    pps_info.pps_id = pps->first;
-    if (h264_header.nalus_length + 2 <= kMaxNalusPerPacket) {
-      h264_header.nalus[h264_header.nalus_length++] = sps_info;
-      h264_header.nalus[h264_header.nalus_length++] = pps_info;
-    } else {
-      RTC_LOG(LS_WARNING) << "Not enough space in H.264 codec header to insert "
-                             "SPS/PPS provided out-of-band.";
-    }
-  }
-
-  // Copy the rest of the bitstream and insert start codes.
-  if (h264_header.packetization_type == kH264StapA) {
-    const uint8_t* nalu_ptr = bitstream.data() + 1;
-    while (nalu_ptr < bitstream.data() + bitstream.size() - 1) {
-      fixed.bitstream.AppendData(start_code_h264);
-
-      // The first two bytes describe the length of a segment.
-      uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
-      nalu_ptr += 2;
-
-      size_t copy_end = nalu_ptr - bitstream.data() + segment_length;
-      if (copy_end > bitstream.size()) {
-        return {kDrop};
-      }
-
-      fixed.bitstream.AppendData(nalu_ptr, segment_length);
-      nalu_ptr += segment_length;
-    }
-  } else {
-    if (h264_header.nalus_length > 0) {
-      fixed.bitstream.AppendData(start_code_h264);
-    }
-    fixed.bitstream.AppendData(bitstream.data(), bitstream.size());
-  }
-
-  fixed.action = kInsert;
-  return fixed;
-}
-
-void H264SpsPpsTracker::InsertSpsPpsNalus(const std::vector<uint8_t>& sps,
-                                          const std::vector<uint8_t>& pps) {
-  constexpr size_t kNaluHeaderOffset = 1;
-  if (sps.size() < kNaluHeaderOffset) {
-    RTC_LOG(LS_WARNING) << "SPS size  " << sps.size() << " is smaller than "
-                        << kNaluHeaderOffset;
-    return;
-  }
-  if ((sps[0] & 0x1f) != H264::NaluType::kSps) {
-    RTC_LOG(LS_WARNING) << "SPS Nalu header missing";
-    return;
-  }
-  if (pps.size() < kNaluHeaderOffset) {
-    RTC_LOG(LS_WARNING) << "PPS size  " << pps.size() << " is smaller than "
-                        << kNaluHeaderOffset;
-    return;
-  }
-  if ((pps[0] & 0x1f) != H264::NaluType::kPps) {
-    RTC_LOG(LS_WARNING) << "SPS Nalu header missing";
-    return;
-  }
-  absl::optional<SpsParser::SpsState> parsed_sps = SpsParser::ParseSps(
-      sps.data() + kNaluHeaderOffset, sps.size() - kNaluHeaderOffset);
-  absl::optional<PpsParser::PpsState> parsed_pps = PpsParser::ParsePps(
-      pps.data() + kNaluHeaderOffset, pps.size() - kNaluHeaderOffset);
-
-  if (!parsed_sps) {
-    RTC_LOG(LS_WARNING) << "Failed to parse SPS.";
-  }
-
-  if (!parsed_pps) {
-    RTC_LOG(LS_WARNING) << "Failed to parse PPS.";
-  }
-
-  if (!parsed_pps || !parsed_sps) {
-    return;
-  }
-
-  SpsInfo sps_info;
-  sps_info.size = sps.size();
-  sps_info.width = parsed_sps->width;
-  sps_info.height = parsed_sps->height;
-  uint8_t* sps_data = new uint8_t[sps_info.size];
-  memcpy(sps_data, sps.data(), sps_info.size);
-  sps_info.data.reset(sps_data);
-  sps_data_[parsed_sps->id] = std::move(sps_info);
-
-  PpsInfo pps_info;
-  pps_info.size = pps.size();
-  pps_info.sps_id = parsed_pps->sps_id;
-  uint8_t* pps_data = new uint8_t[pps_info.size];
-  memcpy(pps_data, pps.data(), pps_info.size);
-  pps_info.data.reset(pps_data);
-  pps_data_[parsed_pps->id] = std::move(pps_info);
-
-  RTC_LOG(LS_INFO) << "Inserted SPS id " << parsed_sps->id << " and PPS id "
-                   << parsed_pps->id << " (referencing SPS "
-                   << parsed_pps->sps_id << ")";
-}
-
-}  // namespace video_coding
-}  // namespace webrtc
diff --git a/third_party/webrtc/modules/video_coding/h264_sps_pps_tracker.h b/third_party/webrtc/modules/video_coding/h264_sps_pps_tracker.h
deleted file mode 100644 (file)
index 600e2ee..0000000
+++ /dev/null
@@ -1,76 +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 MODULES_VIDEO_CODING_H264_SPS_PPS_TRACKER_H_
-#define MODULES_VIDEO_CODING_H264_SPS_PPS_TRACKER_H_
-
-#include <cstddef>
-#include <cstdint>
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "api/array_view.h"
-#include "modules/rtp_rtcp/source/rtp_video_header.h"
-#include "rtc_base/copy_on_write_buffer.h"
-
-namespace webrtc {
-namespace video_coding {
-
-class H264SpsPpsTracker {
- public:
-  enum PacketAction { kInsert, kDrop, kRequestKeyframe };
-  struct FixedBitstream {
-    PacketAction action;
-    rtc::CopyOnWriteBuffer bitstream;
-  };
-
-  H264SpsPpsTracker();
-  ~H264SpsPpsTracker();
-
-  // Returns fixed bitstream and modifies `video_header`.
-  FixedBitstream CopyAndFixBitstream(rtc::ArrayView<const uint8_t> bitstream,
-                                     RTPVideoHeader* video_header);
-
-  void InsertSpsPpsNalus(const std::vector<uint8_t>& sps,
-                         const std::vector<uint8_t>& pps);
-
- private:
-  struct PpsInfo {
-    PpsInfo();
-    PpsInfo(PpsInfo&& rhs);
-    PpsInfo& operator=(PpsInfo&& rhs);
-    ~PpsInfo();
-
-    int sps_id = -1;
-    size_t size = 0;
-    std::unique_ptr<uint8_t[]> data;
-  };
-
-  struct SpsInfo {
-    SpsInfo();
-    SpsInfo(SpsInfo&& rhs);
-    SpsInfo& operator=(SpsInfo&& rhs);
-    ~SpsInfo();
-
-    size_t size = 0;
-    int width = -1;
-    int height = -1;
-    std::unique_ptr<uint8_t[]> data;
-  };
-
-  std::map<uint32_t, PpsInfo> pps_data_;
-  std::map<uint32_t, SpsInfo> sps_data_;
-};
-
-}  // namespace video_coding
-}  // namespace webrtc
-
-#endif  // MODULES_VIDEO_CODING_H264_SPS_PPS_TRACKER_H_
diff --git a/third_party/webrtc/modules/video_coding/h264_sps_pps_tracker_unittest.cc b/third_party/webrtc/modules/video_coding/h264_sps_pps_tracker_unittest.cc
deleted file mode 100644 (file)
index 04abb75..0000000
+++ /dev/null
@@ -1,368 +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 "modules/video_coding/h264_sps_pps_tracker.h"
-
-#include <string.h>
-
-#include <vector>
-
-#include "absl/types/variant.h"
-#include "common_video/h264/h264_common.h"
-#include "modules/rtp_rtcp/source/rtp_video_header.h"
-#include "modules/video_coding/codecs/h264/include/h264_globals.h"
-#include "modules/video_coding/packet.h"
-#include "test/gmock.h"
-#include "test/gtest.h"
-
-namespace webrtc {
-namespace video_coding {
-namespace {
-
-using ::testing::ElementsAreArray;
-
-const uint8_t start_code[] = {0, 0, 0, 1};
-
-rtc::ArrayView<const uint8_t> Bitstream(
-    const H264SpsPpsTracker::FixedBitstream& fixed) {
-  return fixed.bitstream;
-}
-
-void ExpectSpsPpsIdr(const RTPVideoHeaderH264& codec_header,
-                     uint8_t sps_id,
-                     uint8_t pps_id) {
-  bool contains_sps = false;
-  bool contains_pps = false;
-  bool contains_idr = false;
-  for (const auto& nalu : codec_header.nalus) {
-    if (nalu.type == H264::NaluType::kSps) {
-      EXPECT_EQ(sps_id, nalu.sps_id);
-      contains_sps = true;
-    } else if (nalu.type == H264::NaluType::kPps) {
-      EXPECT_EQ(sps_id, nalu.sps_id);
-      EXPECT_EQ(pps_id, nalu.pps_id);
-      contains_pps = true;
-    } else if (nalu.type == H264::NaluType::kIdr) {
-      EXPECT_EQ(pps_id, nalu.pps_id);
-      contains_idr = true;
-    }
-  }
-  EXPECT_TRUE(contains_sps);
-  EXPECT_TRUE(contains_pps);
-  EXPECT_TRUE(contains_idr);
-}
-
-class H264VideoHeader : public RTPVideoHeader {
- public:
-  H264VideoHeader() {
-    codec = kVideoCodecH264;
-    is_first_packet_in_frame = false;
-    auto& h264_header = video_type_header.emplace<RTPVideoHeaderH264>();
-    h264_header.nalus_length = 0;
-    h264_header.packetization_type = kH264SingleNalu;
-  }
-
-  RTPVideoHeaderH264& h264() {
-    return absl::get<RTPVideoHeaderH264>(video_type_header);
-  }
-};
-
-}  // namespace
-
-class TestH264SpsPpsTracker : public ::testing::Test {
- public:
-  void AddSps(H264VideoHeader* header,
-              uint8_t sps_id,
-              std::vector<uint8_t>* data) {
-    NaluInfo info;
-    info.type = H264::NaluType::kSps;
-    info.sps_id = sps_id;
-    info.pps_id = -1;
-    data->push_back(H264::NaluType::kSps);
-    data->push_back(sps_id);  // The sps data, just a single byte.
-
-    header->h264().nalus[header->h264().nalus_length++] = info;
-  }
-
-  void AddPps(H264VideoHeader* header,
-              uint8_t sps_id,
-              uint8_t pps_id,
-              std::vector<uint8_t>* data) {
-    NaluInfo info;
-    info.type = H264::NaluType::kPps;
-    info.sps_id = sps_id;
-    info.pps_id = pps_id;
-    data->push_back(H264::NaluType::kPps);
-    data->push_back(pps_id);  // The pps data, just a single byte.
-
-    header->h264().nalus[header->h264().nalus_length++] = info;
-  }
-
-  void AddIdr(H264VideoHeader* header, int pps_id) {
-    NaluInfo info;
-    info.type = H264::NaluType::kIdr;
-    info.sps_id = -1;
-    info.pps_id = pps_id;
-
-    header->h264().nalus[header->h264().nalus_length++] = info;
-  }
-
- protected:
-  H264SpsPpsTracker tracker_;
-};
-
-TEST_F(TestH264SpsPpsTracker, NoNalus) {
-  uint8_t data[] = {1, 2, 3};
-  H264VideoHeader header;
-  header.h264().packetization_type = kH264FuA;
-
-  H264SpsPpsTracker::FixedBitstream fixed =
-      tracker_.CopyAndFixBitstream(data, &header);
-
-  EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
-  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(data));
-}
-
-TEST_F(TestH264SpsPpsTracker, FuAFirstPacket) {
-  uint8_t data[] = {1, 2, 3};
-  H264VideoHeader header;
-  header.h264().packetization_type = kH264FuA;
-  header.h264().nalus_length = 1;
-  header.is_first_packet_in_frame = true;
-
-  H264SpsPpsTracker::FixedBitstream fixed =
-      tracker_.CopyAndFixBitstream(data, &header);
-
-  EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
-  std::vector<uint8_t> expected;
-  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
-  expected.insert(expected.end(), {1, 2, 3});
-  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
-}
-
-TEST_F(TestH264SpsPpsTracker, StapAIncorrectSegmentLength) {
-  uint8_t data[] = {0, 0, 2, 0};
-  H264VideoHeader header;
-  header.h264().packetization_type = kH264StapA;
-  header.is_first_packet_in_frame = true;
-
-  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
-            H264SpsPpsTracker::kDrop);
-}
-
-TEST_F(TestH264SpsPpsTracker, SingleNaluInsertStartCode) {
-  uint8_t data[] = {1, 2, 3};
-  H264VideoHeader header;
-  header.h264().nalus_length = 1;
-
-  H264SpsPpsTracker::FixedBitstream fixed =
-      tracker_.CopyAndFixBitstream(data, &header);
-
-  EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
-  std::vector<uint8_t> expected;
-  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
-  expected.insert(expected.end(), {1, 2, 3});
-  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
-}
-
-TEST_F(TestH264SpsPpsTracker, NoStartCodeInsertedForSubsequentFuAPacket) {
-  std::vector<uint8_t> data = {1, 2, 3};
-  H264VideoHeader header;
-  header.h264().packetization_type = kH264FuA;
-  // Since no NALU begin in this packet the nalus_length is zero.
-  header.h264().nalus_length = 0;
-
-  H264SpsPpsTracker::FixedBitstream fixed =
-      tracker_.CopyAndFixBitstream(data, &header);
-
-  EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
-  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(data));
-}
-
-TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsPpsInserted) {
-  std::vector<uint8_t> data = {1, 2, 3};
-  H264VideoHeader header;
-  header.is_first_packet_in_frame = true;
-  AddIdr(&header, 0);
-
-  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
-            H264SpsPpsTracker::kRequestKeyframe);
-}
-
-TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoPpsInserted) {
-  std::vector<uint8_t> data = {1, 2, 3};
-  H264VideoHeader header;
-  header.is_first_packet_in_frame = true;
-  AddSps(&header, 0, &data);
-  AddIdr(&header, 0);
-
-  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
-            H264SpsPpsTracker::kRequestKeyframe);
-}
-
-TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsInserted) {
-  std::vector<uint8_t> data = {1, 2, 3};
-  H264VideoHeader header;
-  header.is_first_packet_in_frame = true;
-  AddPps(&header, 0, 0, &data);
-  AddIdr(&header, 0);
-
-  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &header).action,
-            H264SpsPpsTracker::kRequestKeyframe);
-}
-
-TEST_F(TestH264SpsPpsTracker, SpsPpsPacketThenIdrFirstPacket) {
-  std::vector<uint8_t> data;
-  H264VideoHeader sps_pps_header;
-  // Insert SPS/PPS
-  AddSps(&sps_pps_header, 0, &data);
-  AddPps(&sps_pps_header, 0, 1, &data);
-
-  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &sps_pps_header).action,
-            H264SpsPpsTracker::kInsert);
-
-  // Insert first packet of the IDR
-  H264VideoHeader idr_header;
-  idr_header.is_first_packet_in_frame = true;
-  AddIdr(&idr_header, 1);
-  data = {1, 2, 3};
-
-  H264SpsPpsTracker::FixedBitstream fixed =
-      tracker_.CopyAndFixBitstream(data, &idr_header);
-  EXPECT_EQ(fixed.action, H264SpsPpsTracker::kInsert);
-
-  std::vector<uint8_t> expected;
-  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
-  expected.insert(expected.end(), {1, 2, 3});
-  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
-}
-
-TEST_F(TestH264SpsPpsTracker, SpsPpsIdrInStapA) {
-  std::vector<uint8_t> data;
-  H264VideoHeader header;
-  header.h264().packetization_type = kH264StapA;
-  header.is_first_packet_in_frame = true;  // Always true for StapA
-
-  data.insert(data.end(), {0});     // First byte is ignored
-  data.insert(data.end(), {0, 2});  // Length of segment
-  AddSps(&header, 13, &data);
-  data.insert(data.end(), {0, 2});  // Length of segment
-  AddPps(&header, 13, 27, &data);
-  data.insert(data.end(), {0, 5});  // Length of segment
-  AddIdr(&header, 27);
-  data.insert(data.end(), {1, 2, 3, 2, 1});
-
-  H264SpsPpsTracker::FixedBitstream fixed =
-      tracker_.CopyAndFixBitstream(data, &header);
-
-  EXPECT_THAT(fixed.action, H264SpsPpsTracker::kInsert);
-
-  std::vector<uint8_t> expected;
-  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
-  expected.insert(expected.end(), {H264::NaluType::kSps, 13});
-  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
-  expected.insert(expected.end(), {H264::NaluType::kPps, 27});
-  expected.insert(expected.end(), start_code, start_code + sizeof(start_code));
-  expected.insert(expected.end(), {1, 2, 3, 2, 1});
-  EXPECT_THAT(Bitstream(fixed), ElementsAreArray(expected));
-}
-
-TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBand) {
-  constexpr uint8_t kData[] = {1, 2, 3};
-
-  // Generated by "ffmpeg -r 30 -f avfoundation -i "default" out.h264" on macos.
-  // width: 320, height: 240
-  const std::vector<uint8_t> sps(
-      {0x67, 0x7a, 0x00, 0x0d, 0xbc, 0xd9, 0x41, 0x41, 0xfa, 0x10, 0x00, 0x00,
-       0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0xc0, 0xf1, 0x42, 0x99, 0x60});
-  const std::vector<uint8_t> pps({0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0});
-  tracker_.InsertSpsPpsNalus(sps, pps);
-
-  // Insert first packet of the IDR.
-  H264VideoHeader idr_header;
-  idr_header.is_first_packet_in_frame = true;
-  AddIdr(&idr_header, 0);
-  EXPECT_EQ(idr_header.h264().nalus_length, 1u);
-
-  H264SpsPpsTracker::FixedBitstream fixed =
-      tracker_.CopyAndFixBitstream(kData, &idr_header);
-
-  EXPECT_EQ(idr_header.h264().nalus_length, 3u);
-  EXPECT_EQ(idr_header.width, 320u);
-  EXPECT_EQ(idr_header.height, 240u);
-  ExpectSpsPpsIdr(idr_header.h264(), 0, 0);
-}
-
-TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBandWrongNaluHeader) {
-  constexpr uint8_t kData[] = {1, 2, 3};
-
-  // Generated by "ffmpeg -r 30 -f avfoundation -i "default" out.h264" on macos.
-  // Nalu headers manupilated afterwards.
-  const std::vector<uint8_t> sps(
-      {0xff, 0x7a, 0x00, 0x0d, 0xbc, 0xd9, 0x41, 0x41, 0xfa, 0x10, 0x00, 0x00,
-       0x03, 0x00, 0x10, 0x00, 0x00, 0x03, 0x03, 0xc0, 0xf1, 0x42, 0x99, 0x60});
-  const std::vector<uint8_t> pps({0xff, 0xeb, 0xe3, 0xcb, 0x22, 0xc0});
-  tracker_.InsertSpsPpsNalus(sps, pps);
-
-  // Insert first packet of the IDR.
-  H264VideoHeader idr_header;
-  idr_header.is_first_packet_in_frame = true;
-  AddIdr(&idr_header, 0);
-
-  EXPECT_EQ(tracker_.CopyAndFixBitstream(kData, &idr_header).action,
-            H264SpsPpsTracker::kRequestKeyframe);
-}
-
-TEST_F(TestH264SpsPpsTracker, SpsPpsOutOfBandIncompleteNalu) {
-  constexpr uint8_t kData[] = {1, 2, 3};
-
-  // Generated by "ffmpeg -r 30 -f avfoundation -i "default" out.h264" on macos.
-  // Nalus damaged afterwards.
-  const std::vector<uint8_t> sps({0x67, 0x7a, 0x00, 0x0d, 0xbc, 0xd9});
-  const std::vector<uint8_t> pps({0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0});
-  tracker_.InsertSpsPpsNalus(sps, pps);
-
-  // Insert first packet of the IDR.
-  H264VideoHeader idr_header;
-  idr_header.is_first_packet_in_frame = true;
-  AddIdr(&idr_header, 0);
-
-  EXPECT_EQ(tracker_.CopyAndFixBitstream(kData, &idr_header).action,
-            H264SpsPpsTracker::kRequestKeyframe);
-}
-
-TEST_F(TestH264SpsPpsTracker, SaveRestoreWidthHeight) {
-  std::vector<uint8_t> data;
-
-  // Insert an SPS/PPS packet with width/height and make sure
-  // that information is set on the first IDR packet.
-  H264VideoHeader sps_pps_header;
-  AddSps(&sps_pps_header, 0, &data);
-  AddPps(&sps_pps_header, 0, 1, &data);
-  sps_pps_header.width = 320;
-  sps_pps_header.height = 240;
-
-  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &sps_pps_header).action,
-            H264SpsPpsTracker::kInsert);
-
-  H264VideoHeader idr_header;
-  idr_header.is_first_packet_in_frame = true;
-  AddIdr(&idr_header, 1);
-  data.insert(data.end(), {1, 2, 3});
-
-  EXPECT_EQ(tracker_.CopyAndFixBitstream(data, &idr_header).action,
-            H264SpsPpsTracker::kInsert);
-
-  EXPECT_EQ(idr_header.width, 320);
-  EXPECT_EQ(idr_header.height, 240);
-}
-
-}  // namespace video_coding
-}  // namespace webrtc
diff --git a/third_party/webrtc/modules/video_coding/h265_vps_sps_pps_tracker.cc b/third_party/webrtc/modules/video_coding/h265_vps_sps_pps_tracker.cc
deleted file mode 100644 (file)
index 3bf666f..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- *  Copyright (c) 2018 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 "modules/video_coding/h265_vps_sps_pps_tracker.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "absl/types/variant.h"
-#include "common_video/h264/h264_common.h"
-#include "common_video/h265/h265_common.h"
-#include "common_video/h265/h265_pps_parser.h"
-#include "common_video/h265/h265_sps_parser.h"
-#include "common_video/h265/h265_vps_parser.h"
-#include "modules/video_coding/codecs/h264/include/h264_globals.h"
-#include "modules/video_coding/codecs/h265/include/h265_globals.h"
-#include "modules/video_coding/frame_object.h"
-#include "modules/video_coding/packet_buffer.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/logging.h"
-
-namespace webrtc {
-namespace video_coding {
-
-namespace {
-const uint8_t start_code_h265[] = {0, 0, 0, 1};
-}  // namespace
-
-H265VpsSpsPpsTracker::FixedBitstream H265VpsSpsPpsTracker::CopyAndFixBitstream(
-    rtc::ArrayView<const uint8_t> bitstream,
-    RTPVideoHeader* video_header) {
-  RTC_DCHECK(video_header);
-  RTC_DCHECK(video_header->codec == kVideoCodecH265);
-
-  auto& h265_header =
-      absl::get<RTPVideoHeaderH265>(video_header->video_type_header);
-
-  bool append_vps_sps_pps = false;
-  auto vps = vps_data_.end();
-  auto sps = sps_data_.end();
-  auto pps = pps_data_.end();
-
-  for (size_t i = 0; i < h265_header.nalus_length; ++i) {
-    const H265NaluInfo& nalu = h265_header.nalus[i];
-    switch (nalu.type) {
-      case H265::NaluType::kVps: {
-        vps_data_[nalu.vps_id].size = 0;
-        break;
-      }
-      case H265::NaluType::kSps: {
-        sps_data_[nalu.sps_id].vps_id = nalu.vps_id;
-        sps_data_[nalu.sps_id].width = video_header->width;
-        sps_data_[nalu.sps_id].height = video_header->height;
-        break;
-      }
-      case H265::NaluType::kPps: {
-        pps_data_[nalu.pps_id].sps_id = nalu.sps_id;
-        break;
-      }
-      case H265::NaluType::kIdrWRadl:
-      case H265::NaluType::kIdrNLp:
-      case H265::NaluType::kCra: {
-        // If this is the first packet of an IDR, make sure we have the required
-        // SPS/PPS and also calculate how much extra space we need in the buffer
-        // to prepend the SPS/PPS to the bitstream with start codes.
-        if (video_header->is_first_packet_in_frame) {
-          if (nalu.pps_id == -1) {
-            RTC_LOG(LS_WARNING) << "No PPS id in IDR nalu.";
-            return {kRequestKeyframe};
-          }
-
-          pps = pps_data_.find(nalu.pps_id);
-          if (pps == pps_data_.end()) {
-            RTC_LOG(LS_WARNING)
-                << "No PPS with id " << nalu.pps_id << " received";
-            return {kRequestKeyframe};
-          }
-
-          sps = sps_data_.find(pps->second.sps_id);
-          if (sps == sps_data_.end()) {
-            RTC_LOG(LS_WARNING)
-                << "No SPS with id << " << pps->second.sps_id << " received";
-            return {kRequestKeyframe};
-          }
-
-          vps = vps_data_.find(sps->second.vps_id);
-          if (vps == vps_data_.end()) {
-            RTC_LOG(LS_WARNING)
-                << "No VPS with id " << sps->second.vps_id << " received";
-            return {kRequestKeyframe};
-          }
-
-          // Since the first packet of every keyframe should have its width and
-          // height set we set it here in the case of it being supplied out of
-          // band.
-          video_header->width = sps->second.width;
-          video_header->height = sps->second.height;
-
-          // If the VPS/SPS/PPS was supplied out of band then we will have saved
-          // the actual bitstream in |data|.
-          // This branch is not verified.
-          if (vps->second.data && sps->second.data && pps->second.data) {
-            RTC_DCHECK_GT(vps->second.size, 0);
-            RTC_DCHECK_GT(sps->second.size, 0);
-            RTC_DCHECK_GT(pps->second.size, 0);
-            append_vps_sps_pps = true;
-          }
-        }
-        break;
-      }
-      default:
-        break;
-    }
-  }
-
-  RTC_CHECK(!append_vps_sps_pps ||
-            (sps != sps_data_.end() && pps != pps_data_.end()));
-
-  // Calculate how much space we need for the rest of the bitstream.
-  size_t required_size = 0;
-
-  if (append_vps_sps_pps) {
-    required_size += vps->second.size + sizeof(start_code_h265);
-    required_size += sps->second.size + sizeof(start_code_h265);
-    required_size += pps->second.size + sizeof(start_code_h265);
-  }
-
-  if (h265_header.packetization_type == kH265AP) {
-    const uint8_t* nalu_ptr = bitstream.data() + 1;
-    while (nalu_ptr < bitstream.data() + bitstream.size()) {
-      RTC_DCHECK(video_header->is_first_packet_in_frame);
-      required_size += sizeof(start_code_h265);
-
-      // The first two bytes describe the length of a segment.
-      uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
-      nalu_ptr += 2;
-
-      required_size += segment_length;
-      nalu_ptr += segment_length;
-    }
-  } else {
-    // TODO: in h.264 this is "h264_header.nalus_length > 0"
-    if (video_header->is_first_packet_in_frame)
-      required_size += sizeof(start_code_h265);
-    required_size += bitstream.size();
-  }
-
-  // Then we copy to the new buffer.
-  H265VpsSpsPpsTracker::FixedBitstream fixed;
-  fixed.bitstream.EnsureCapacity(required_size);
-
-  if (append_vps_sps_pps) {
-    // Insert VPS.
-    fixed.bitstream.AppendData(start_code_h265);
-    fixed.bitstream.AppendData(vps->second.data.get(), vps->second.size);
-
-    // Insert SPS.
-    fixed.bitstream.AppendData(start_code_h265);
-    fixed.bitstream.AppendData(sps->second.data.get(), sps->second.size);
-
-    // Insert PPS.
-    fixed.bitstream.AppendData(start_code_h265);
-    fixed.bitstream.AppendData(pps->second.data.get(), pps->second.size);
-
-    // Update codec header to reflect the newly added SPS and PPS.
-    H265NaluInfo vps_info;
-    vps_info.type = H265::NaluType::kVps;
-    vps_info.vps_id = vps->first;
-    vps_info.sps_id = -1;
-    vps_info.pps_id = -1;
-    H265NaluInfo sps_info;
-    sps_info.type = H265::NaluType::kSps;
-    sps_info.vps_id = vps->first;
-    sps_info.sps_id = sps->first;
-    sps_info.pps_id = -1;
-    H265NaluInfo pps_info;
-    pps_info.type = H265::NaluType::kPps;
-    pps_info.vps_id = vps->first;
-    pps_info.sps_id = sps->first;
-    pps_info.pps_id = pps->first;
-    if (h265_header.nalus_length + 2 <= kMaxNalusPerPacket) {
-      h265_header.nalus[h265_header.nalus_length++] = vps_info;
-      h265_header.nalus[h265_header.nalus_length++] = sps_info;
-      h265_header.nalus[h265_header.nalus_length++] = pps_info;
-    } else {
-      RTC_LOG(LS_WARNING) << "Not enough space in H.265 codec header to insert "
-                             "SPS/PPS provided out-of-band.";
-    }
-  }
-
-  // Copy the rest of the bitstream and insert start codes.
-  if (h265_header.packetization_type == kH265AP) {
-    const uint8_t* nalu_ptr = bitstream.data() + 1;
-    while (nalu_ptr < bitstream.data() + bitstream.size()) {
-      fixed.bitstream.AppendData(start_code_h265);
-
-      // The first two bytes describe the length of a segment.
-      uint16_t segment_length = nalu_ptr[0] << 8 | nalu_ptr[1];
-      nalu_ptr += 2;
-
-      size_t copy_end = nalu_ptr - bitstream.data() + segment_length;
-      if (copy_end > bitstream.size()) {
-        return {kDrop};
-      }
-
-      fixed.bitstream.AppendData(nalu_ptr, segment_length);
-      nalu_ptr += segment_length;
-    }
-  } else {
-    // For h.264 it is "h264_header.nalus_length > 0"
-    if (video_header->is_first_packet_in_frame) {
-      fixed.bitstream.AppendData(start_code_h265);
-    }
-    fixed.bitstream.AppendData(bitstream.data(), bitstream.size());
-  }
-
-  fixed.action = kInsert;
-  return fixed;
-}
-
-}  // namespace video_coding
-}  // namespace webrtc
diff --git a/third_party/webrtc/modules/video_coding/h265_vps_sps_pps_tracker.h b/third_party/webrtc/modules/video_coding/h265_vps_sps_pps_tracker.h
deleted file mode 100644 (file)
index 9347cdc..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- *  Copyright (c) 2018 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 THIRD_PARTY_WEBRTC_MODULES_VIDEO_CODING_H265_VPS_SPS_PPS_TRACKER_H_
-#define THIRD_PARTY_WEBRTC_MODULES_VIDEO_CODING_H265_VPS_SPS_PPS_TRACKER_H_
-
-#include <cstddef>
-#include <cstdint>
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "api/array_view.h"
-#include "modules/rtp_rtcp/source/rtp_video_header.h"
-#include "rtc_base/copy_on_write_buffer.h"
-
-namespace webrtc {
-namespace video_coding {
-
-class H265VpsSpsPpsTracker {
- public:
-  enum PacketAction { kInsert, kDrop, kRequestKeyframe };
-  struct FixedBitstream {
-    PacketAction action;
-    rtc::CopyOnWriteBuffer bitstream;
-  };
-
-  FixedBitstream CopyAndFixBitstream(rtc::ArrayView<const uint8_t> bitstream,
-                                     RTPVideoHeader* video_header);
-
- private:
-  struct VpsInfo {
-    size_t size = 0;
-    std::unique_ptr<uint8_t[]> data;
-  };
-
-  struct PpsInfo {
-    int sps_id = -1;
-    size_t size = 0;
-    std::unique_ptr<uint8_t[]> data;
-  };
-
-  struct SpsInfo {
-    int vps_id = -1;
-    size_t size = 0;
-    int width = -1;
-    int height = -1;
-    std::unique_ptr<uint8_t[]> data;
-  };
-
-  std::map<uint32_t, VpsInfo> vps_data_;
-  std::map<uint32_t, PpsInfo> pps_data_;
-  std::map<uint32_t, SpsInfo> sps_data_;
-};
-
-}  // namespace video_coding
-}  // namespace webrtc
-
-#endif  // THIRD_PARTY_WEBRTC_MODULES_VIDEO_CODING_H265_VPS_SPS_PPS_TRACKER_H_
index 506d2bf7942319a863f6679e63ef11bd8147d4cf..efe7d57967e7817bc2b5aa2209fa6eb4eab3d0a7 100644 (file)
@@ -40,8 +40,6 @@
 #include "modules/utility/include/process_thread.h"
 #include "modules/video_coding/deprecated/nack_module.h"
 #include "modules/video_coding/frame_object.h"
-#include "modules/video_coding/h264_sprop_parameter_sets.h"
-#include "modules/video_coding/h264_sps_pps_tracker.h"
 #include "modules/video_coding/packet_buffer.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/location.h"
@@ -370,7 +368,7 @@ void RtpVideoStreamReceiver::AddReceiveCodec(
       payload_type, raw_payload
                         ? std::make_unique<VideoRtpDepacketizerRaw>()
                         : CreateVideoRtpDepacketizer(video_codec.codecType));
-  pt_codec_params_.emplace(payload_type, codec_params);
+  payload_type_map_[payload_type]->SetCodecParams(codec_params);
 }
 
 absl::optional<Syncable::Info> RtpVideoStreamReceiver::GetSyncInfo() const {
@@ -603,61 +601,22 @@ void RtpVideoStreamReceiver::OnReceivedPayloadData(
     return;
   }
 
-  if (packet->codec() == kVideoCodecH264) {
-    // Only when we start to receive packets will we know what payload type
-    // that will be used. When we know the payload type insert the correct
-    // sps/pps into the tracker.
-    if (packet->payload_type != last_payload_type_) {
-      last_payload_type_ = packet->payload_type;
-      InsertSpsPpsIntoTracker(packet->payload_type);
-    }
-
-    video_coding::H264SpsPpsTracker::FixedBitstream fixed =
-        tracker_.CopyAndFixBitstream(
-            rtc::MakeArrayView(codec_payload.cdata(), codec_payload.size()),
-            &packet->video_header);
-
-    switch (fixed.action) {
-      case video_coding::H264SpsPpsTracker::kRequestKeyframe:
-        rtcp_feedback_buffer_.RequestKeyFrame();
-        rtcp_feedback_buffer_.SendBufferedRtcpFeedback();
-        ABSL_FALLTHROUGH_INTENDED;
-      case video_coding::H264SpsPpsTracker::kDrop:
-        return;
-      case video_coding::H264SpsPpsTracker::kInsert:
-        packet->video_payload = std::move(fixed.bitstream);
-        break;
-    }
-
-
-#if defined(OS_TIZEN_TV_PRODUCT) && BUILDFLAG(ENABLE_PLATFORM_HEVC)
-  } else if (packet->codec() == kVideoCodecH265) {
-    // Only when we start to receive packets will we know what payload type
-    // that will be used. When we know the payload type insert the correct
-    // sps/pps into the tracker.
-    if (packet->payload_type != last_payload_type_) {
-      last_payload_type_ = packet->payload_type;
-      InsertSpsPpsIntoTracker(packet->payload_type);
-    }
-    video_coding::H265VpsSpsPpsTracker::FixedBitstream fixed =
-        h265_tracker_.CopyAndFixBitstream(
-            rtc::MakeArrayView(codec_payload.cdata(), codec_payload.size()),
-            &packet->video_header);
-    switch (fixed.action) {
-      case video_coding::H265VpsSpsPpsTracker::kRequestKeyframe:
-        rtcp_feedback_buffer_.RequestKeyFrame();
-        rtcp_feedback_buffer_.SendBufferedRtcpFeedback();
-        ABSL_FALLTHROUGH_INTENDED;
-      case video_coding::H265VpsSpsPpsTracker::kDrop:
-        return;
-      case video_coding::H265VpsSpsPpsTracker::kInsert:
-        packet->video_payload = std::move(fixed.bitstream);
-        break;
-    }
-#endif
-
-  } else {
-    packet->video_payload = std::move(codec_payload);
+  const auto type_it = payload_type_map_.find(rtp_packet.PayloadType());
+  if (type_it == payload_type_map_.end()) {
+    return;
+  }
+  auto packet_action =
+      type_it->second->GetPacketAction(codec_payload, &packet->video_header);
+  switch (packet_action) {
+    case VideoRtpDepacketizer::kRequestKeyframe:
+      rtcp_feedback_buffer_.RequestKeyFrame();
+      rtcp_feedback_buffer_.SendBufferedRtcpFeedback();
+      ABSL_FALLTHROUGH_INTENDED;
+    case VideoRtpDepacketizer::kDrop:
+      return;
+    case VideoRtpDepacketizer::kInsert:
+      packet->video_payload = std::move(codec_payload);
+      break;
   }
 
   rtcp_feedback_buffer_.SendBufferedRtcpFeedback();
@@ -777,7 +736,7 @@ void RtpVideoStreamReceiver::OnInsertedPacket(
     int max_nack_count;
     int64_t min_recv_time;
     int64_t max_recv_time;
-    std::vector<rtc::ArrayView<const uint8_t>> payloads;
+    std::vector<VideoRtpDepacketizer::RtpPacketView> payloads;
     RtpPacketInfos::vector_type packet_infos;
 
     bool frame_boundary = true;
@@ -800,7 +759,7 @@ void RtpVideoStreamReceiver::OnInsertedPacket(
         max_recv_time =
             std::max(max_recv_time, packet_info.receive_time().ms());
       }
-      payloads.emplace_back(packet->video_payload);
+      payloads.emplace_back(&packet->video_header, packet->video_payload);
       packet_infos.push_back(packet_info);
 
       frame_boundary = packet->is_last_packet_in_frame();
@@ -1215,29 +1174,6 @@ void RtpVideoStreamReceiver::UpdateHistograms() {
   }
 }
 
-void RtpVideoStreamReceiver::InsertSpsPpsIntoTracker(uint8_t payload_type) {
-  auto codec_params_it = pt_codec_params_.find(payload_type);
-  if (codec_params_it == pt_codec_params_.end())
-    return;
-
-  RTC_LOG(LS_INFO) << "Found out of band supplied codec parameters for"
-                      " payload type: "
-                   << static_cast<int>(payload_type);
-
-  H264SpropParameterSets sprop_decoder;
-  auto sprop_base64_it =
-      codec_params_it->second.find(cricket::kH264FmtpSpropParameterSets);
-
-  if (sprop_base64_it == codec_params_it->second.end())
-    return;
-
-  if (!sprop_decoder.DecodeSprop(sprop_base64_it->second.c_str()))
-    return;
-
-  tracker_.InsertSpsPpsNalus(sprop_decoder.sps_nalu(),
-                             sprop_decoder.pps_nalu());
-}
-
 void RtpVideoStreamReceiver::UpdatePacketReceiveTimestamps(
     const RtpPacketReceived& packet,
     bool is_keyframe) {
index 8e33c8e65c343e20ba34cc18375ba7e60b9b21ab..6a98c9f57c9192fb2c139231f8b9407f0b6e8995 100644 (file)
@@ -39,7 +39,6 @@
 #include "modules/rtp_rtcp/source/rtp_packet_received.h"
 #include "modules/rtp_rtcp/source/rtp_video_header.h"
 #include "modules/rtp_rtcp/source/video_rtp_depacketizer.h"
-#include "modules/video_coding/h264_sps_pps_tracker.h"
 #include "modules/video_coding/loss_notification_controller.h"
 #include "modules/video_coding/packet_buffer.h"
 #include "modules/video_coding/rtp_frame_reference_finder.h"
@@ -310,7 +309,6 @@ class RtpVideoStreamReceiver : public LossNotificationSender,
   void NotifyReceiverOfEmptyPacket(uint16_t seq_num);
   void UpdateHistograms();
   bool IsRedEnabled() const;
-  void InsertSpsPpsIntoTracker(uint8_t payload_type);
   void OnInsertedPacket(video_coding::PacketBuffer::InsertResult result);
   ParseGenericDependenciesResult ParseGenericDependenciesExtension(
       const RtpPacketReceived& rtp_packet,
@@ -375,21 +373,10 @@ class RtpVideoStreamReceiver : public LossNotificationSender,
   Mutex last_seq_num_mutex_;
   std::map<int64_t, uint16_t> last_seq_num_for_pic_id_
       RTC_GUARDED_BY(last_seq_num_mutex_);
-  video_coding::H264SpsPpsTracker tracker_;
 
   // Maps payload id to the depacketizer.
   flat_map<uint8_t, std::unique_ptr<VideoRtpDepacketizer>> payload_type_map_;
 
-#if defined(OS_TIZEN_TV_PRODUCT) && BUILDFLAG(ENABLE_PLATFORM_HEVC)
-  video_coding::H265VpsSpsPpsTracker h265_tracker_;
-#endif
-
-  // TODO(johan): Remove pt_codec_params_ once
-  // https://bugs.chromium.org/p/webrtc/issues/detail?id=6883 is resolved.
-  // Maps a payload type to a map of out-of-band supplied codec parameters.
-  flat_map<uint8_t, std::map<std::string, std::string>> pt_codec_params_;
-  int16_t last_payload_type_ = -1;
-
   bool has_received_frame_;
 
   std::vector<RtpPacketSinkInterface*> secondary_sinks_
index d753cce181eac37cd93b2577e850372e2a522be5..91748769572a36cd6af3c4c03bd352cbfe5d6a36 100644 (file)
@@ -38,8 +38,6 @@
 #include "modules/rtp_rtcp/source/video_rtp_depacketizer.h"
 #include "modules/rtp_rtcp/source/video_rtp_depacketizer_raw.h"
 #include "modules/video_coding/frame_object.h"
-#include "modules/video_coding/h264_sprop_parameter_sets.h"
-#include "modules/video_coding/h264_sps_pps_tracker.h"
 #include "modules/video_coding/nack_requester.h"
 #include "modules/video_coding/packet_buffer.h"
 #include "rtc_base/checks.h"
@@ -337,7 +335,7 @@ void RtpVideoStreamReceiver2::AddReceiveCodec(
   payload_type_map_.emplace(
       payload_type, raw_payload ? std::make_unique<VideoRtpDepacketizerRaw>()
                                 : CreateVideoRtpDepacketizer(video_codec));
-  pt_codec_params_.emplace(payload_type, codec_params);
+  payload_type_map_[payload_type]->SetCodecParams(codec_params);
 }
 
 absl::optional<Syncable::Info> RtpVideoStreamReceiver2::GetSyncInfo() const {
@@ -586,60 +584,22 @@ void RtpVideoStreamReceiver2::OnReceivedPayloadData(
     return;
   }
 
-  if (packet->codec() == kVideoCodecH264) {
-    // Only when we start to receive packets will we know what payload type
-    // that will be used. When we know the payload type insert the correct
-    // sps/pps into the tracker.
-    if (packet->payload_type != last_payload_type_) {
-      last_payload_type_ = packet->payload_type;
-      InsertSpsPpsIntoTracker(packet->payload_type);
-    }
-
-    video_coding::H264SpsPpsTracker::FixedBitstream fixed =
-        tracker_.CopyAndFixBitstream(
-            rtc::MakeArrayView(codec_payload.cdata(), codec_payload.size()),
-            &packet->video_header);
-
-    switch (fixed.action) {
-      case video_coding::H264SpsPpsTracker::kRequestKeyframe:
-        rtcp_feedback_buffer_.RequestKeyFrame();
-        rtcp_feedback_buffer_.SendBufferedRtcpFeedback();
-        ABSL_FALLTHROUGH_INTENDED;
-      case video_coding::H264SpsPpsTracker::kDrop:
-        return;
-      case video_coding::H264SpsPpsTracker::kInsert:
-        packet->video_payload = std::move(fixed.bitstream);
-        break;
-    }
-
-#if defined(OS_TIZEN_TV_PRODUCT) && BUILDFLAG(ENABLE_PLATFORM_HEVC)
-  } else if (packet->codec() == kVideoCodecH265) {
-    // Only when we start to receive packets will we know what payload type
-    // that will be used. When we know the payload type insert the correct
-    // sps/pps into the tracker.
-    if (packet->payload_type != last_payload_type_) {
-      last_payload_type_ = packet->payload_type;
-      InsertSpsPpsIntoTracker(packet->payload_type);
-    }
-    video_coding::H265VpsSpsPpsTracker::FixedBitstream fixed =
-        h265_tracker_.CopyAndFixBitstream(
-            rtc::MakeArrayView(codec_payload.cdata(), codec_payload.size()),
-            &packet->video_header);
-    switch (fixed.action) {
-      case video_coding::H265VpsSpsPpsTracker::kRequestKeyframe:
-        rtcp_feedback_buffer_.RequestKeyFrame();
-        rtcp_feedback_buffer_.SendBufferedRtcpFeedback();
-        ABSL_FALLTHROUGH_INTENDED;
-      case video_coding::H265VpsSpsPpsTracker::kDrop:
-        return;
-      case video_coding::H265VpsSpsPpsTracker::kInsert:
-        packet->video_payload = std::move(fixed.bitstream);
-        break;
-    }
-#endif
-
-  } else {
-    packet->video_payload = std::move(codec_payload);
+  const auto type_it = payload_type_map_.find(rtp_packet.PayloadType());
+  if (type_it == payload_type_map_.end()) {
+    return;
+  }
+  auto packet_action =
+      type_it->second->GetPacketAction(codec_payload, &packet->video_header);
+  switch (packet_action) {
+    case VideoRtpDepacketizer::kRequestKeyframe:
+      rtcp_feedback_buffer_.RequestKeyFrame();
+      rtcp_feedback_buffer_.SendBufferedRtcpFeedback();
+      ABSL_FALLTHROUGH_INTENDED;
+    case VideoRtpDepacketizer::kDrop:
+      return;
+    case VideoRtpDepacketizer::kInsert:
+      packet->video_payload = std::move(codec_payload);
+      break;
   }
 
   rtcp_feedback_buffer_.SendBufferedRtcpFeedback();
@@ -741,7 +701,7 @@ void RtpVideoStreamReceiver2::OnInsertedPacket(
   int max_nack_count;
   int64_t min_recv_time;
   int64_t max_recv_time;
-  std::vector<rtc::ArrayView<const uint8_t>> payloads;
+  std::vector<VideoRtpDepacketizer::RtpPacketView> payloads;
   RtpPacketInfos::vector_type packet_infos;
 
   bool frame_boundary = true;
@@ -762,7 +722,7 @@ void RtpVideoStreamReceiver2::OnInsertedPacket(
       min_recv_time = std::min(min_recv_time, packet_info.receive_time().ms());
       max_recv_time = std::max(max_recv_time, packet_info.receive_time().ms());
     }
-    payloads.emplace_back(packet->video_payload);
+    payloads.emplace_back(&packet->video_header, packet->video_payload);
     packet_infos.push_back(packet_info);
 
     frame_boundary = packet->is_last_packet_in_frame();
@@ -1138,32 +1098,6 @@ void RtpVideoStreamReceiver2::UpdateHistograms() {
   }
 }
 
-// RTC_RUN_ON(packet_sequence_checker_)
-void RtpVideoStreamReceiver2::InsertSpsPpsIntoTracker(uint8_t payload_type) {
-  RTC_DCHECK_RUN_ON(&worker_task_checker_);
-
-  auto codec_params_it = pt_codec_params_.find(payload_type);
-  if (codec_params_it == pt_codec_params_.end())
-    return;
-
-  RTC_LOG(LS_INFO) << "Found out of band supplied codec parameters for"
-                      " payload type: "
-                   << static_cast<int>(payload_type);
-
-  H264SpropParameterSets sprop_decoder;
-  auto sprop_base64_it =
-      codec_params_it->second.find(cricket::kH264FmtpSpropParameterSets);
-
-  if (sprop_base64_it == codec_params_it->second.end())
-    return;
-
-  if (!sprop_decoder.DecodeSprop(sprop_base64_it->second.c_str()))
-    return;
-
-  tracker_.InsertSpsPpsNalus(sprop_decoder.sps_nalu(),
-                             sprop_decoder.pps_nalu());
-}
-
 void RtpVideoStreamReceiver2::UpdatePacketReceiveTimestamps(
     const RtpPacketReceived& packet,
     bool is_keyframe) {
index 89f7e522bafd09dab009a05766e95e3180f264fc..c58661d7a98f02d2da8f2bfb175a44dc71fad87e 100644 (file)
@@ -37,7 +37,6 @@
 #include "modules/rtp_rtcp/source/rtp_rtcp_interface.h"
 #include "modules/rtp_rtcp/source/rtp_video_header.h"
 #include "modules/rtp_rtcp/source/video_rtp_depacketizer.h"
-#include "modules/video_coding/h264_sps_pps_tracker.h"
 #include "modules/video_coding/loss_notification_controller.h"
 #include "modules/video_coding/nack_requester.h"
 #include "modules/video_coding/packet_buffer.h"
 #include "video/buffered_frame_decryptor.h"
 #include "video/rtp_video_stream_receiver_frame_transformer_delegate.h"
 
-#if defined(OS_TIZEN_TV_PRODUCT) && BUILDFLAG(ENABLE_PLATFORM_HEVC)
-#include "modules/video_coding/h265_vps_sps_pps_tracker.h"
-#endif
-
 namespace webrtc {
 
 class NackRequester;
@@ -275,8 +270,6 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender,
       RTC_RUN_ON(packet_sequence_checker_);
   void UpdateHistograms();
   bool IsRedEnabled() const;
-  void InsertSpsPpsIntoTracker(uint8_t payload_type)
-      RTC_RUN_ON(packet_sequence_checker_);
   void OnInsertedPacket(video_coding::PacketBuffer::InsertResult result)
       RTC_RUN_ON(packet_sequence_checker_);
   ParseGenericDependenciesResult ParseGenericDependenciesExtension(
@@ -350,24 +343,11 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender,
 
   std::map<int64_t, uint16_t> last_seq_num_for_pic_id_
       RTC_GUARDED_BY(packet_sequence_checker_);
-  video_coding::H264SpsPpsTracker tracker_
-      RTC_GUARDED_BY(packet_sequence_checker_);
 
   // Maps payload id to the depacketizer.
   flat_map<uint8_t, std::unique_ptr<VideoRtpDepacketizer>> payload_type_map_
       RTC_GUARDED_BY(packet_sequence_checker_);
 
-#if defined(OS_TIZEN_TV_PRODUCT) && BUILDFLAG(ENABLE_PLATFORM_HEVC)
-  video_coding::H265VpsSpsPpsTracker h265_tracker_;
-#endif
-
-  // TODO(johan): Remove pt_codec_params_ once
-  // https://bugs.chromium.org/p/webrtc/issues/detail?id=6883 is resolved.
-  // Maps a payload type to a map of out-of-band supplied codec parameters.
-  flat_map<uint8_t, std::map<std::string, std::string>> pt_codec_params_
-      RTC_GUARDED_BY(packet_sequence_checker_);
-  int16_t last_payload_type_ RTC_GUARDED_BY(packet_sequence_checker_) = -1;
-
   bool has_received_frame_ RTC_GUARDED_BY(packet_sequence_checker_);
 
   absl::optional<uint32_t> last_received_rtp_timestamp_
index b92a553cd56882209b6a269ba821bb8a384345c9..29a5e4e77564071ddfdced4ac5f22e7e0a8c4bfb 100644 (file)
@@ -148,6 +148,8 @@ class RtpVideoStreamReceiver2Test : public ::testing::Test,
  public:
   RtpVideoStreamReceiver2Test() : RtpVideoStreamReceiver2Test("") {}
   explicit RtpVideoStreamReceiver2Test(std::string field_trials)
+      : RtpVideoStreamReceiver2Test(field_trials, kVideoCodecGeneric) {}
+  RtpVideoStreamReceiver2Test(std::string field_trials, VideoCodecType codec)
       : time_controller_(Timestamp::Millis(100)),
         task_queue_(time_controller_.GetTaskQueueFactory()->CreateTaskQueue(
             "RtpVideoStreamReceiver2Test",
@@ -163,8 +165,7 @@ class RtpVideoStreamReceiver2Test : public ::testing::Test,
         nullptr, &nack_periodic_processor_, &mock_nack_sender_,
         &mock_key_frame_request_sender_, &mock_on_complete_frame_callback_,
         nullptr, nullptr);
-    rtp_video_stream_receiver_->AddReceiveCodec(kPayloadType,
-                                                kVideoCodecGeneric, {},
+    rtp_video_stream_receiver_->AddReceiveCodec(kPayloadType, codec, {},
                                                 /*raw_payload=*/false);
   }
 
@@ -504,7 +505,8 @@ class RtpVideoStreamReceiver2TestH264
     : public RtpVideoStreamReceiver2Test,
       public ::testing::WithParamInterface<std::string> {
  protected:
-  RtpVideoStreamReceiver2TestH264() : RtpVideoStreamReceiver2Test(GetParam()) {}
+  RtpVideoStreamReceiver2TestH264()
+      : RtpVideoStreamReceiver2Test(GetParam(), kVideoCodecH264) {}
 };
 
 INSTANTIATE_TEST_SUITE_P(SpsPpsIdrIsKeyframe,
index 22cb37fa1676f49db95ee18b5e4054436f50cb5d..5fdf9816b795c8fe08b55cd0e6a44bc4644f7133 100644 (file)
@@ -144,6 +144,9 @@ class RtpVideoStreamReceiverTest : public ::testing::Test {
  public:
   RtpVideoStreamReceiverTest() : RtpVideoStreamReceiverTest("") {}
   explicit RtpVideoStreamReceiverTest(std::string field_trials)
+      : RtpVideoStreamReceiverTest(field_trials, kVideoCodecGeneric) {}
+  RtpVideoStreamReceiverTest(std::string field_trials,
+                             VideoCodecType codec_type)
       : override_field_trials_(field_trials),
         config_(CreateConfig()),
         process_thread_(ProcessThread::Create("TestThread")) {
@@ -155,7 +158,7 @@ class RtpVideoStreamReceiverTest : public ::testing::Test {
         &mock_nack_sender_, &mock_key_frame_request_sender_,
         &mock_on_complete_frame_callback_, nullptr, nullptr);
     VideoCodec codec;
-    codec.codecType = kVideoCodecGeneric;
+    codec.codecType = codec_type;
     rtp_video_stream_receiver_->AddReceiveCodec(kPayloadType, codec, {},
                                                 /*raw_payload=*/false);
   }
@@ -486,7 +489,8 @@ class RtpVideoStreamReceiverTestH264
     : public RtpVideoStreamReceiverTest,
       public ::testing::WithParamInterface<std::string> {
  protected:
-  RtpVideoStreamReceiverTestH264() : RtpVideoStreamReceiverTest(GetParam()) {}
+  RtpVideoStreamReceiverTestH264()
+      : RtpVideoStreamReceiverTest(GetParam(), kVideoCodecH264) {}
 };
 
 INSTANTIATE_TEST_SUITE_P(SpsPpsIdrIsKeyframe,
@@ -543,6 +547,7 @@ TEST_P(RtpVideoStreamReceiverTestH264, InBandSpsPps) {
 TEST_P(RtpVideoStreamReceiverTestH264, OutOfBandFmtpSpsPps) {
   constexpr int kPayloadType = 99;
   VideoCodec codec;
+  codec.codecType = kVideoCodecH264;
   std::map<std::string, std::string> codec_params;
   // Example parameter sets from https://tools.ietf.org/html/rfc3984#section-8.2
   // .
@@ -584,6 +589,7 @@ TEST_P(RtpVideoStreamReceiverTestH264, OutOfBandFmtpSpsPps) {
 TEST_P(RtpVideoStreamReceiverTestH264, ForceSpsPpsIdrIsKeyframe) {
   constexpr int kPayloadType = 99;
   VideoCodec codec;
+  codec.codecType = kVideoCodecH264;
   std::map<std::string, std::string> codec_params;
   if (GetParam() ==
       "") {  // Forcing can be done either with field trial or codec_params.