diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index f2baf6ecc2..4f082ecf4b 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn @@ -213,6 +213,8 @@ rtc_library("rtp_rtcp") { "source/ulpfec_receiver_impl.cc", "source/ulpfec_receiver_impl.h", "source/video_rtp_depacketizer.h", + "source/video_rtp_depacketizer_generic.cc", + "source/video_rtp_depacketizer_generic.h", "source/video_rtp_depacketizer_raw.cc", "source/video_rtp_depacketizer_raw.h", "source/video_rtp_depacketizer_vp8.cc", @@ -483,6 +485,7 @@ if (rtc_include_tests) { "source/ulpfec_generator_unittest.cc", "source/ulpfec_header_reader_writer_unittest.cc", "source/ulpfec_receiver_unittest.cc", + "source/video_rtp_depacketizer_generic_unittest.cc", "source/video_rtp_depacketizer_raw_unittest.cc", "source/video_rtp_depacketizer_vp8_unittest.cc", "source/video_rtp_depacketizer_vp9_unittest.cc", diff --git a/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc b/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc index 604c6415e7..35db947dd1 100644 --- a/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc +++ b/modules/rtp_rtcp/source/create_video_rtp_depacketizer.cc @@ -16,6 +16,7 @@ #include "absl/types/optional.h" #include "modules/rtp_rtcp/source/rtp_format.h" #include "modules/rtp_rtcp/source/video_rtp_depacketizer.h" +#include "modules/rtp_rtcp/source/video_rtp_depacketizer_generic.h" #include "modules/rtp_rtcp/source/video_rtp_depacketizer_vp8.h" #include "modules/rtp_rtcp/source/video_rtp_depacketizer_vp9.h" #include "rtc_base/checks.h" @@ -56,15 +57,18 @@ class LegacyRtpDepacketizer : public VideoRtpDepacketizer { std::unique_ptr CreateVideoRtpDepacketizer( VideoCodecType codec) { - // TODO(bugs.webrtc.org/11152): switch on codec and create specialized - // VideoRtpDepacketizers when they are migrated to new interface. switch (codec) { + case kVideoCodecH264: + return std::make_unique(codec); case kVideoCodecVP8: return std::make_unique(); case kVideoCodecVP9: return std::make_unique(); - default: + case kVideoCodecAV1: return std::make_unique(codec); + case kVideoCodecGeneric: + case kVideoCodecMultiplex: + return std::make_unique(); } } diff --git a/modules/rtp_rtcp/source/video_rtp_depacketizer_generic.cc b/modules/rtp_rtcp/source/video_rtp_depacketizer_generic.cc new file mode 100644 index 0000000000..e601eae614 --- /dev/null +++ b/modules/rtp_rtcp/source/video_rtp_depacketizer_generic.cc @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019 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/rtp_rtcp/source/video_rtp_depacketizer_generic.h" + +#include +#include + +#include + +#include "absl/types/optional.h" +#include "modules/rtp_rtcp/source/rtp_video_header.h" +#include "modules/rtp_rtcp/source/video_rtp_depacketizer.h" +#include "rtc_base/copy_on_write_buffer.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace { +constexpr uint8_t kKeyFrameBit = 0b0000'0001; +constexpr uint8_t kFirstPacketBit = 0b0000'0010; +// If this bit is set, there will be an extended header contained in this +// packet. This was added later so old clients will not send this. +constexpr uint8_t kExtendedHeaderBit = 0b0000'0100; + +constexpr size_t kGenericHeaderLength = 1; +constexpr size_t kExtendedHeaderLength = 2; +} // namespace + +absl::optional +VideoRtpDepacketizerGeneric::Parse(rtc::CopyOnWriteBuffer rtp_payload) { + if (rtp_payload.size() == 0) { + RTC_LOG(LS_WARNING) << "Empty payload."; + return absl::nullopt; + } + absl::optional parsed(absl::in_place); + const uint8_t* payload_data = rtp_payload.cdata(); + + uint8_t generic_header = payload_data[0]; + size_t offset = kGenericHeaderLength; + + parsed->video_header.frame_type = (generic_header & kKeyFrameBit) + ? VideoFrameType::kVideoFrameKey + : VideoFrameType::kVideoFrameDelta; + parsed->video_header.is_first_packet_in_frame = + (generic_header & kFirstPacketBit) != 0; + parsed->video_header.codec = kVideoCodecGeneric; + parsed->video_header.width = 0; + parsed->video_header.height = 0; + + if (generic_header & kExtendedHeaderBit) { + if (rtp_payload.size() < offset + kExtendedHeaderLength) { + RTC_LOG(LS_WARNING) << "Too short payload for generic header."; + return absl::nullopt; + } + parsed->video_header.generic.emplace(); + parsed->video_header.generic->frame_id = + ((payload_data[1] & 0x7F) << 8) | payload_data[2]; + offset += kExtendedHeaderLength; + } + + parsed->video_payload = + rtp_payload.Slice(offset, rtp_payload.size() - offset); + return parsed; +} +} // namespace webrtc diff --git a/modules/rtp_rtcp/source/video_rtp_depacketizer_generic.h b/modules/rtp_rtcp/source/video_rtp_depacketizer_generic.h new file mode 100644 index 0000000000..27056da481 --- /dev/null +++ b/modules/rtp_rtcp/source/video_rtp_depacketizer_generic.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019 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_RTP_RTCP_SOURCE_VIDEO_RTP_DEPACKETIZER_GENERIC_H_ +#define MODULES_RTP_RTCP_SOURCE_VIDEO_RTP_DEPACKETIZER_GENERIC_H_ + +#include "absl/types/optional.h" +#include "modules/rtp_rtcp/source/video_rtp_depacketizer.h" +#include "rtc_base/copy_on_write_buffer.h" + +namespace webrtc { + +class VideoRtpDepacketizerGeneric : public VideoRtpDepacketizer { + public: + ~VideoRtpDepacketizerGeneric() override = default; + + absl::optional Parse( + rtc::CopyOnWriteBuffer rtp_payload) override; +}; + +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_VIDEO_RTP_DEPACKETIZER_GENERIC_H_ diff --git a/modules/rtp_rtcp/source/video_rtp_depacketizer_generic_unittest.cc b/modules/rtp_rtcp/source/video_rtp_depacketizer_generic_unittest.cc new file mode 100644 index 0000000000..524fc3f775 --- /dev/null +++ b/modules/rtp_rtcp/source/video_rtp_depacketizer_generic_unittest.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019 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/rtp_rtcp/source/video_rtp_depacketizer_generic.h" + +#include + +#include "absl/types/optional.h" +#include "rtc_base/copy_on_write_buffer.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::SizeIs; + +TEST(VideoRtpDepacketizerGeneric, NonExtendedHeaderNoFrameId) { + const size_t kRtpPayloadSize = 10; + const uint8_t kPayload[kRtpPayloadSize] = {0x01}; + rtc::CopyOnWriteBuffer rtp_payload(kPayload); + + VideoRtpDepacketizerGeneric depacketizer; + absl::optional parsed = + depacketizer.Parse(rtp_payload); + + ASSERT_TRUE(parsed); + EXPECT_EQ(parsed->video_header.generic, absl::nullopt); + EXPECT_THAT(parsed->video_payload, SizeIs(kRtpPayloadSize - 1)); +} + +TEST(VideoRtpDepacketizerGeneric, ExtendedHeaderParsesFrameId) { + const size_t kRtpPayloadSize = 10; + const uint8_t kPayload[kRtpPayloadSize] = {0x05, 0x13, 0x37}; + rtc::CopyOnWriteBuffer rtp_payload(kPayload); + + VideoRtpDepacketizerGeneric depacketizer; + absl::optional parsed = + depacketizer.Parse(rtp_payload); + + ASSERT_TRUE(parsed); + ASSERT_TRUE(parsed->video_header.generic); + EXPECT_EQ(parsed->video_header.generic->frame_id, 0x1337); + EXPECT_THAT(parsed->video_payload, SizeIs(kRtpPayloadSize - 3)); +} + +TEST(VideoRtpDepacketizerGeneric, PassRtpPayloadAsVideoPayload) { + const uint8_t kPayload[] = {0x01, 0x25, 0x52}; + rtc::CopyOnWriteBuffer rtp_payload(kPayload); + + VideoRtpDepacketizerGeneric depacketizer; + absl::optional parsed = + depacketizer.Parse(rtp_payload); + + ASSERT_TRUE(parsed); + // Check there was no memcpy involved by verifying return and original buffers + // point to the same buffer. + EXPECT_EQ(parsed->video_payload.cdata(), rtp_payload.cdata() + 1); +} + +} // namespace +} // namespace webrtc