From c8f3134b29b4faa3f9b2376a57896353a358dc73 Mon Sep 17 00:00:00 2001 From: Johannes Kron Date: Thu, 19 Dec 2019 15:05:20 +0100 Subject: [PATCH] Parse max-fr and max-fs from SDP FMTP line max-fr and max-fs are mandatory fields for VP8 and VP9. Add parsing as a first step to enable use of these fields. Bug: chromium:1032518 Change-Id: I4fd8f7f84f6303d646fb3f5313a02d6cf4160346 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/162801 Commit-Queue: Johannes Kron Reviewed-by: Ilya Nikolaevskiy Cr-Commit-Position: refs/heads/master@{#30114} --- media/BUILD.gn | 16 +++++++ media/base/sdp_fmtp_utils.cc | 55 ++++++++++++++++++++++ media/base/sdp_fmtp_utils.h | 32 +++++++++++++ media/base/sdp_fmtp_utils_unittest.cc | 68 +++++++++++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 media/base/sdp_fmtp_utils.cc create mode 100644 media/base/sdp_fmtp_utils.h create mode 100644 media/base/sdp_fmtp_utils_unittest.cc diff --git a/media/BUILD.gn b/media/BUILD.gn index 50d8ea34b3..b3394660f2 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -63,6 +63,20 @@ rtc_library("rtc_vp9_profile") { ] } +rtc_library("rtc_sdp_fmtp_utils") { + visibility = [ "*" ] + sources = [ + "base/sdp_fmtp_utils.cc", + "base/sdp_fmtp_utils.h", + ] + + deps = [ + "../api/video_codecs:video_codecs_api", + "../rtc_base:stringutils", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + rtc_library("rtc_media_base") { visibility = [ "*" ] defines = [] @@ -523,6 +537,7 @@ if (rtc_include_tests) { ":rtc_media_base", ":rtc_media_engine_defaults", ":rtc_media_tests_utils", + ":rtc_sdp_fmtp_utils", ":rtc_simulcast_encoder_adapter", ":rtc_vp9_profile", "../:webrtc_common", @@ -589,6 +604,7 @@ if (rtc_include_tests) { "base/codec_unittest.cc", "base/rtp_data_engine_unittest.cc", "base/rtp_utils_unittest.cc", + "base/sdp_fmtp_utils_unittest.cc", "base/stream_params_unittest.cc", "base/turn_utils_unittest.cc", "base/video_adapter_unittest.cc", diff --git a/media/base/sdp_fmtp_utils.cc b/media/base/sdp_fmtp_utils.cc new file mode 100644 index 0000000000..4ffc3b9696 --- /dev/null +++ b/media/base/sdp_fmtp_utils.cc @@ -0,0 +1,55 @@ +/* + * 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 "media/base/sdp_fmtp_utils.h" + +#include +#include + +#include "rtc_base/string_to_number.h" + +namespace webrtc { +namespace { +// Max frame rate for VP8 and VP9 video. +const char kVPxFmtpMaxFrameRate[] = "max-fr"; +// Max frame size for VP8 and VP9 video. +const char kVPxFmtpMaxFrameSize[] = "max-fs"; +const int kVPxFmtpFrameSizeSubBlockPixels = 256; + +absl::optional ParsePositiveNumberFromParams( + const SdpVideoFormat::Parameters& params, + const char* parameter_name) { + const auto max_frame_rate_it = params.find(parameter_name); + if (max_frame_rate_it == params.end()) + return absl::nullopt; + + const absl::optional i = + rtc::StringToNumber(max_frame_rate_it->second); + if (!i.has_value() || i.value() <= 0) + return absl::nullopt; + return i; +} + +} // namespace + +absl::optional ParseSdpForVPxMaxFrameRate( + const SdpVideoFormat::Parameters& params) { + return ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameRate); +} + +absl::optional ParseSdpForVPxMaxFrameSize( + const SdpVideoFormat::Parameters& params) { + const absl::optional i = + ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameSize); + return i ? absl::make_optional(i.value() * kVPxFmtpFrameSizeSubBlockPixels) + : absl::nullopt; +} + +} // namespace webrtc diff --git a/media/base/sdp_fmtp_utils.h b/media/base/sdp_fmtp_utils.h new file mode 100644 index 0000000000..04e9183614 --- /dev/null +++ b/media/base/sdp_fmtp_utils.h @@ -0,0 +1,32 @@ +/* + * 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 MEDIA_BASE_SDP_FMTP_UTILS_H_ +#define MEDIA_BASE_SDP_FMTP_UTILS_H_ + +#include "absl/types/optional.h" +#include "api/video_codecs/sdp_video_format.h" + +namespace webrtc { + +// Parse max frame rate from SDP FMTP line. absl::nullopt is returned if the +// field is missing or not a number. +absl::optional ParseSdpForVPxMaxFrameRate( + const SdpVideoFormat::Parameters& params); + +// Parse max frame size from SDP FMTP line. absl::nullopt is returned if the +// field is missing or not a number. Please note that the value is stored in sub +// blocks but the returned value is in total number of pixels. +absl::optional ParseSdpForVPxMaxFrameSize( + const SdpVideoFormat::Parameters& params); + +} // namespace webrtc + +#endif // MEDIA_BASE_SDP_FMTP_UTILS_H__ diff --git a/media/base/sdp_fmtp_utils_unittest.cc b/media/base/sdp_fmtp_utils_unittest.cc new file mode 100644 index 0000000000..0ff12ffbe1 --- /dev/null +++ b/media/base/sdp_fmtp_utils_unittest.cc @@ -0,0 +1,68 @@ +/* + * 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 "media/base/sdp_fmtp_utils.h" + +#include +#include +#include + +#include "rtc_base/string_to_number.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { +// Max frame rate for VP8 and VP9 video. +const char kVPxFmtpMaxFrameRate[] = "max-fr"; +// Max frame size for VP8 and VP9 video. +const char kVPxFmtpMaxFrameSize[] = "max-fs"; +} // namespace + +TEST(SdpFmtpUtilsTest, MaxFrameRateIsMissingOrInvalid) { + SdpVideoFormat::Parameters params; + absl::optional empty = ParseSdpForVPxMaxFrameRate(params); + EXPECT_FALSE(empty); + params[kVPxFmtpMaxFrameRate] = "-1"; + EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params)); + params[kVPxFmtpMaxFrameRate] = "0"; + EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params)); + params[kVPxFmtpMaxFrameRate] = "abcde"; + EXPECT_FALSE(ParseSdpForVPxMaxFrameRate(params)); +} + +TEST(SdpFmtpUtilsTest, MaxFrameRateIsSpecified) { + SdpVideoFormat::Parameters params; + params[kVPxFmtpMaxFrameRate] = "30"; + EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 30); + params[kVPxFmtpMaxFrameRate] = "60"; + EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 60); +} + +TEST(SdpFmtpUtilsTest, MaxFrameSizeIsMissingOrInvalid) { + SdpVideoFormat::Parameters params; + absl::optional empty = ParseSdpForVPxMaxFrameSize(params); + EXPECT_FALSE(empty); + params[kVPxFmtpMaxFrameSize] = "-1"; + EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params)); + params[kVPxFmtpMaxFrameSize] = "0"; + EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params)); + params[kVPxFmtpMaxFrameSize] = "abcde"; + EXPECT_FALSE(ParseSdpForVPxMaxFrameSize(params)); +} + +TEST(SdpFmtpUtilsTest, MaxFrameSizeIsSpecified) { + SdpVideoFormat::Parameters params; + params[kVPxFmtpMaxFrameSize] = "8100"; // 1920 x 1080 / (16^2) + EXPECT_EQ(ParseSdpForVPxMaxFrameSize(params), 1920 * 1080); + params[kVPxFmtpMaxFrameSize] = "32400"; // 3840 x 2160 / (16^2) + EXPECT_EQ(ParseSdpForVPxMaxFrameSize(params), 3840 * 2160); +} + +} // namespace webrtc