Move h264_profile_level_id and vp9_profile to api/video_codecs

This is a refactor to simplify a follow-up CL of adding
SdpVideoFormat::IsSameCodec.

The original files media/base/h264_profile_level_id.* and
media/base/vp9_profile.h must be kept until downstream projects
stop using them.

Bug: chroimium:1187565
Change-Id: Ib39eca095a3d61939a914d9bffaf4b891ddd222f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/215236
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Johannes Kron <kron@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33782}
This commit is contained in:
Johannes Kron 2021-04-19 09:09:26 +02:00 committed by Commit Bot
parent 8546666cb9
commit c3fcee7c3a
48 changed files with 1236 additions and 1051 deletions

View File

@ -35,7 +35,4 @@ specific_include_rules = {
"create_frame_generator\.h": [ "create_frame_generator\.h": [
"+system_wrappers/include/clock.h", "+system_wrappers/include/clock.h",
], ],
"videocodec_test_fixture\.h": [
"+media/base/h264_profile_level_id.h"
],
} }

View File

@ -59,7 +59,7 @@ class VideoCodecTestFixture {
class EncodedFrameChecker { class EncodedFrameChecker {
public: public:
virtual ~EncodedFrameChecker() = default; virtual ~EncodedFrameChecker() = default;
virtual void CheckEncodedFrame(webrtc::VideoCodecType codec, virtual void CheckEncodedFrame(VideoCodecType codec,
const EncodedImage& encoded_frame) const = 0; const EncodedImage& encoded_frame) const = 0;
}; };
@ -123,16 +123,16 @@ class VideoCodecTestFixture {
bool encode_in_real_time = false; bool encode_in_real_time = false;
// Codec settings to use. // Codec settings to use.
webrtc::VideoCodec codec_settings; VideoCodec codec_settings;
// Name of the codec being tested. // Name of the codec being tested.
std::string codec_name; std::string codec_name;
// H.264 specific settings. // H.264 specific settings.
struct H264CodecSettings { struct H264CodecSettings {
H264::Profile profile = H264::kProfileConstrainedBaseline; H264Profile profile = H264Profile::kProfileConstrainedBaseline;
H264PacketizationMode packetization_mode = H264PacketizationMode packetization_mode =
webrtc::H264PacketizationMode::NonInterleaved; H264PacketizationMode::NonInterleaved;
} h264_codec_settings; } h264_codec_settings;
// Custom checker that will be called for each frame. // Custom checker that will be called for each frame.

View File

@ -15,6 +15,8 @@ if (is_android) {
rtc_library("video_codecs_api") { rtc_library("video_codecs_api") {
visibility = [ "*" ] visibility = [ "*" ]
sources = [ sources = [
"h264_profile_level_id.cc",
"h264_profile_level_id.h",
"sdp_video_format.cc", "sdp_video_format.cc",
"sdp_video_format.h", "sdp_video_format.h",
"spatial_layer.cc", "spatial_layer.cc",
@ -35,6 +37,8 @@ rtc_library("video_codecs_api") {
"vp8_frame_config.h", "vp8_frame_config.h",
"vp8_temporal_layers.cc", "vp8_temporal_layers.cc",
"vp8_temporal_layers.h", "vp8_temporal_layers.h",
"vp9_profile.cc",
"vp9_profile.h",
] ]
deps = [ deps = [
@ -138,7 +142,6 @@ rtc_library("rtc_software_fallback_wrappers") {
":video_codecs_api", ":video_codecs_api",
"..:fec_controller_api", "..:fec_controller_api",
"../../api/video:video_frame", "../../api/video:video_frame",
"../../media:rtc_h264_profile_id",
"../../media:rtc_media_base", "../../media:rtc_media_base",
"../../modules/video_coding:video_codec_interface", "../../modules/video_coding:video_codec_interface",
"../../modules/video_coding:video_coding_utility", "../../modules/video_coding:video_coding_utility",

View File

@ -0,0 +1,252 @@
/*
* Copyright (c) 2021 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 "api/video_codecs/h264_profile_level_id.h"
#include <cstdio>
#include <cstdlib>
#include <string>
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
namespace webrtc {
namespace {
const char kProfileLevelId[] = "profile-level-id";
// For level_idc=11 and profile_idc=0x42, 0x4D, or 0x58, the constraint set3
// flag specifies if level 1b or level 1.1 is used.
const uint8_t kConstraintSet3Flag = 0x10;
// Convert a string of 8 characters into a byte where the positions containing
// character c will have their bit set. For example, c = 'x', str = "x1xx0000"
// will return 0b10110000. constexpr is used so that the pattern table in
// kProfilePatterns is statically initialized.
constexpr uint8_t ByteMaskString(char c, const char (&str)[9]) {
return (str[0] == c) << 7 | (str[1] == c) << 6 | (str[2] == c) << 5 |
(str[3] == c) << 4 | (str[4] == c) << 3 | (str[5] == c) << 2 |
(str[6] == c) << 1 | (str[7] == c) << 0;
}
// Class for matching bit patterns such as "x1xx0000" where 'x' is allowed to be
// either 0 or 1.
class BitPattern {
public:
explicit constexpr BitPattern(const char (&str)[9])
: mask_(~ByteMaskString('x', str)),
masked_value_(ByteMaskString('1', str)) {}
bool IsMatch(uint8_t value) const { return masked_value_ == (value & mask_); }
private:
const uint8_t mask_;
const uint8_t masked_value_;
};
// Table for converting between profile_idc/profile_iop to H264Profile.
struct ProfilePattern {
const uint8_t profile_idc;
const BitPattern profile_iop;
const H264Profile profile;
};
// This is from https://tools.ietf.org/html/rfc6184#section-8.1.
constexpr ProfilePattern kProfilePatterns[] = {
{0x42, BitPattern("x1xx0000"), H264Profile::kProfileConstrainedBaseline},
{0x4D, BitPattern("1xxx0000"), H264Profile::kProfileConstrainedBaseline},
{0x58, BitPattern("11xx0000"), H264Profile::kProfileConstrainedBaseline},
{0x42, BitPattern("x0xx0000"), H264Profile::kProfileBaseline},
{0x58, BitPattern("10xx0000"), H264Profile::kProfileBaseline},
{0x4D, BitPattern("0x0x0000"), H264Profile::kProfileMain},
{0x64, BitPattern("00000000"), H264Profile::kProfileHigh},
{0x64, BitPattern("00001100"), H264Profile::kProfileConstrainedHigh}};
struct LevelConstraint {
const int max_macroblocks_per_second;
const int max_macroblock_frame_size;
const H264Level level;
};
// This is from ITU-T H.264 (02/2016) Table A-1 Level limits.
static constexpr LevelConstraint kLevelConstraints[] = {
{1485, 99, H264Level::kLevel1},
{1485, 99, H264Level::kLevel1_b},
{3000, 396, H264Level::kLevel1_1},
{6000, 396, H264Level::kLevel1_2},
{11880, 396, H264Level::kLevel1_3},
{11880, 396, H264Level::kLevel2},
{19800, 792, H264Level::kLevel2_1},
{20250, 1620, H264Level::kLevel2_2},
{40500, 1620, H264Level::kLevel3},
{108000, 3600, H264Level::kLevel3_1},
{216000, 5120, H264Level::kLevel3_2},
{245760, 8192, H264Level::kLevel4},
{245760, 8192, H264Level::kLevel4_1},
{522240, 8704, H264Level::kLevel4_2},
{589824, 22080, H264Level::kLevel5},
{983040, 36864, H264Level::kLevel5_1},
{2073600, 36864, H264Level::kLevel5_2},
};
} // anonymous namespace
absl::optional<H264ProfileLevelId> ParseH264ProfileLevelId(const char* str) {
// The string should consist of 3 bytes in hexadecimal format.
if (strlen(str) != 6u)
return absl::nullopt;
const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16);
if (profile_level_id_numeric == 0)
return absl::nullopt;
// Separate into three bytes.
const uint8_t level_idc =
static_cast<uint8_t>(profile_level_id_numeric & 0xFF);
const uint8_t profile_iop =
static_cast<uint8_t>((profile_level_id_numeric >> 8) & 0xFF);
const uint8_t profile_idc =
static_cast<uint8_t>((profile_level_id_numeric >> 16) & 0xFF);
// Parse level based on level_idc and constraint set 3 flag.
H264Level level_casted = static_cast<H264Level>(level_idc);
H264Level level;
switch (level_casted) {
case H264Level::kLevel1_1:
level = (profile_iop & kConstraintSet3Flag) != 0 ? H264Level::kLevel1_b
: H264Level::kLevel1_1;
break;
case H264Level::kLevel1:
case H264Level::kLevel1_2:
case H264Level::kLevel1_3:
case H264Level::kLevel2:
case H264Level::kLevel2_1:
case H264Level::kLevel2_2:
case H264Level::kLevel3:
case H264Level::kLevel3_1:
case H264Level::kLevel3_2:
case H264Level::kLevel4:
case H264Level::kLevel4_1:
case H264Level::kLevel4_2:
case H264Level::kLevel5:
case H264Level::kLevel5_1:
case H264Level::kLevel5_2:
level = level_casted;
break;
default:
// Unrecognized level_idc.
return absl::nullopt;
}
// Parse profile_idc/profile_iop into a Profile enum.
for (const ProfilePattern& pattern : kProfilePatterns) {
if (profile_idc == pattern.profile_idc &&
pattern.profile_iop.IsMatch(profile_iop)) {
return H264ProfileLevelId(pattern.profile, level);
}
}
// Unrecognized profile_idc/profile_iop combination.
return absl::nullopt;
}
absl::optional<H264Level> H264SupportedLevel(int max_frame_pixel_count,
float max_fps) {
static const int kPixelsPerMacroblock = 16 * 16;
for (int i = arraysize(kLevelConstraints) - 1; i >= 0; --i) {
const LevelConstraint& level_constraint = kLevelConstraints[i];
if (level_constraint.max_macroblock_frame_size * kPixelsPerMacroblock <=
max_frame_pixel_count &&
level_constraint.max_macroblocks_per_second <=
max_fps * level_constraint.max_macroblock_frame_size) {
return level_constraint.level;
}
}
// No level supported.
return absl::nullopt;
}
absl::optional<H264ProfileLevelId> ParseSdpForH264ProfileLevelId(
const SdpVideoFormat::Parameters& params) {
// TODO(magjed): The default should really be kProfileBaseline and kLevel1
// according to the spec: https://tools.ietf.org/html/rfc6184#section-8.1. In
// order to not break backwards compatibility with older versions of WebRTC
// where external codecs don't have any parameters, use
// kProfileConstrainedBaseline kLevel3_1 instead. This workaround will only be
// done in an interim period to allow external clients to update their code.
// http://crbug/webrtc/6337.
static const H264ProfileLevelId kDefaultProfileLevelId(
H264Profile::kProfileConstrainedBaseline, H264Level::kLevel3_1);
const auto profile_level_id_it = params.find(kProfileLevelId);
return (profile_level_id_it == params.end())
? kDefaultProfileLevelId
: ParseH264ProfileLevelId(profile_level_id_it->second.c_str());
}
absl::optional<std::string> H264ProfileLevelIdToString(
const H264ProfileLevelId& profile_level_id) {
// Handle special case level == 1b.
if (profile_level_id.level == H264Level::kLevel1_b) {
switch (profile_level_id.profile) {
case H264Profile::kProfileConstrainedBaseline:
return {"42f00b"};
case H264Profile::kProfileBaseline:
return {"42100b"};
case H264Profile::kProfileMain:
return {"4d100b"};
// Level 1b is not allowed for other profiles.
default:
return absl::nullopt;
}
}
const char* profile_idc_iop_string;
switch (profile_level_id.profile) {
case H264Profile::kProfileConstrainedBaseline:
profile_idc_iop_string = "42e0";
break;
case H264Profile::kProfileBaseline:
profile_idc_iop_string = "4200";
break;
case H264Profile::kProfileMain:
profile_idc_iop_string = "4d00";
break;
case H264Profile::kProfileConstrainedHigh:
profile_idc_iop_string = "640c";
break;
case H264Profile::kProfileHigh:
profile_idc_iop_string = "6400";
break;
// Unrecognized profile.
default:
return absl::nullopt;
}
char str[7];
snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level);
return {str};
}
bool H264IsSameProfile(const SdpVideoFormat::Parameters& params1,
const SdpVideoFormat::Parameters& params2) {
const absl::optional<H264ProfileLevelId> profile_level_id =
ParseSdpForH264ProfileLevelId(params1);
const absl::optional<H264ProfileLevelId> other_profile_level_id =
ParseSdpForH264ProfileLevelId(params2);
// Compare H264 profiles, but not levels.
return profile_level_id && other_profile_level_id &&
profile_level_id->profile == other_profile_level_id->profile;
}
} // namespace webrtc

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2021 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 API_VIDEO_CODECS_H264_PROFILE_LEVEL_ID_H_
#define API_VIDEO_CODECS_H264_PROFILE_LEVEL_ID_H_
#include <string>
#include "absl/types/optional.h"
#include "api/video_codecs/sdp_video_format.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
enum class H264Profile {
kProfileConstrainedBaseline,
kProfileBaseline,
kProfileMain,
kProfileConstrainedHigh,
kProfileHigh,
};
// All values are equal to ten times the level number, except level 1b which is
// special.
enum class H264Level {
kLevel1_b = 0,
kLevel1 = 10,
kLevel1_1 = 11,
kLevel1_2 = 12,
kLevel1_3 = 13,
kLevel2 = 20,
kLevel2_1 = 21,
kLevel2_2 = 22,
kLevel3 = 30,
kLevel3_1 = 31,
kLevel3_2 = 32,
kLevel4 = 40,
kLevel4_1 = 41,
kLevel4_2 = 42,
kLevel5 = 50,
kLevel5_1 = 51,
kLevel5_2 = 52
};
struct H264ProfileLevelId {
constexpr H264ProfileLevelId(H264Profile profile, H264Level level)
: profile(profile), level(level) {}
H264Profile profile;
H264Level level;
};
// Parse profile level id that is represented as a string of 3 hex bytes.
// Nothing will be returned if the string is not a recognized H264
// profile level id.
absl::optional<H264ProfileLevelId> ParseH264ProfileLevelId(const char* str);
// Parse profile level id that is represented as a string of 3 hex bytes
// contained in an SDP key-value map. A default profile level id will be
// returned if the profile-level-id key is missing. Nothing will be returned if
// the key is present but the string is invalid.
RTC_EXPORT absl::optional<H264ProfileLevelId> ParseSdpForH264ProfileLevelId(
const SdpVideoFormat::Parameters& params);
// Given that a decoder supports up to a given frame size (in pixels) at up to a
// given number of frames per second, return the highest H.264 level where it
// can guarantee that it will be able to support all valid encoded streams that
// are within that level.
RTC_EXPORT absl::optional<H264Level> H264SupportedLevel(
int max_frame_pixel_count,
float max_fps);
// Returns canonical string representation as three hex bytes of the profile
// level id, or returns nothing for invalid profile level ids.
RTC_EXPORT absl::optional<std::string> H264ProfileLevelIdToString(
const H264ProfileLevelId& profile_level_id);
// Returns true if the parameters have the same H264 profile (Baseline, High,
// etc).
RTC_EXPORT bool H264IsSameProfile(const SdpVideoFormat::Parameters& params1,
const SdpVideoFormat::Parameters& params2);
} // namespace webrtc
#endif // API_VIDEO_CODECS_H264_PROFILE_LEVEL_ID_H_

View File

@ -13,6 +13,7 @@ if (rtc_include_tests) {
testonly = true testonly = true
sources = [ sources = [
"builtin_video_encoder_factory_unittest.cc", "builtin_video_encoder_factory_unittest.cc",
"h264_profile_level_id_unittest.cc",
"video_decoder_software_fallback_wrapper_unittest.cc", "video_decoder_software_fallback_wrapper_unittest.cc",
"video_encoder_software_fallback_wrapper_unittest.cc", "video_encoder_software_fallback_wrapper_unittest.cc",
] ]

View File

@ -0,0 +1,171 @@
/*
* Copyright (c) 2021 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 "api/video_codecs/h264_profile_level_id.h"
#include <map>
#include <string>
#include "absl/types/optional.h"
#include "test/gtest.h"
namespace webrtc {
TEST(H264ProfileLevelId, TestParsingInvalid) {
// Malformed strings.
EXPECT_FALSE(ParseH264ProfileLevelId(""));
EXPECT_FALSE(ParseH264ProfileLevelId(" 42e01f"));
EXPECT_FALSE(ParseH264ProfileLevelId("4242e01f"));
EXPECT_FALSE(ParseH264ProfileLevelId("e01f"));
EXPECT_FALSE(ParseH264ProfileLevelId("gggggg"));
// Invalid level.
EXPECT_FALSE(ParseH264ProfileLevelId("42e000"));
EXPECT_FALSE(ParseH264ProfileLevelId("42e00f"));
EXPECT_FALSE(ParseH264ProfileLevelId("42e0ff"));
// Invalid profile.
EXPECT_FALSE(ParseH264ProfileLevelId("42e11f"));
EXPECT_FALSE(ParseH264ProfileLevelId("58601f"));
EXPECT_FALSE(ParseH264ProfileLevelId("64e01f"));
}
TEST(H264ProfileLevelId, TestParsingLevel) {
EXPECT_EQ(H264Level::kLevel3_1, ParseH264ProfileLevelId("42e01f")->level);
EXPECT_EQ(H264Level::kLevel1_1, ParseH264ProfileLevelId("42e00b")->level);
EXPECT_EQ(H264Level::kLevel1_b, ParseH264ProfileLevelId("42f00b")->level);
EXPECT_EQ(H264Level::kLevel4_2, ParseH264ProfileLevelId("42C02A")->level);
EXPECT_EQ(H264Level::kLevel5_2, ParseH264ProfileLevelId("640c34")->level);
}
TEST(H264ProfileLevelId, TestParsingConstrainedBaseline) {
EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
ParseH264ProfileLevelId("42e01f")->profile);
EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
ParseH264ProfileLevelId("42C02A")->profile);
EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
ParseH264ProfileLevelId("4de01f")->profile);
EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
ParseH264ProfileLevelId("58f01f")->profile);
}
TEST(H264ProfileLevelId, TestParsingBaseline) {
EXPECT_EQ(H264Profile::kProfileBaseline,
ParseH264ProfileLevelId("42a01f")->profile);
EXPECT_EQ(H264Profile::kProfileBaseline,
ParseH264ProfileLevelId("58A01F")->profile);
}
TEST(H264ProfileLevelId, TestParsingMain) {
EXPECT_EQ(H264Profile::kProfileMain,
ParseH264ProfileLevelId("4D401f")->profile);
}
TEST(H264ProfileLevelId, TestParsingHigh) {
EXPECT_EQ(H264Profile::kProfileHigh,
ParseH264ProfileLevelId("64001f")->profile);
}
TEST(H264ProfileLevelId, TestParsingConstrainedHigh) {
EXPECT_EQ(H264Profile::kProfileConstrainedHigh,
ParseH264ProfileLevelId("640c1f")->profile);
}
TEST(H264ProfileLevelId, TestSupportedLevel) {
EXPECT_EQ(H264Level::kLevel2_1, *H264SupportedLevel(640 * 480, 25));
EXPECT_EQ(H264Level::kLevel3_1, *H264SupportedLevel(1280 * 720, 30));
EXPECT_EQ(H264Level::kLevel4_2, *H264SupportedLevel(1920 * 1280, 60));
}
// Test supported level below level 1 requirements.
TEST(H264ProfileLevelId, TestSupportedLevelInvalid) {
EXPECT_FALSE(H264SupportedLevel(0, 0));
// All levels support fps > 5.
EXPECT_FALSE(H264SupportedLevel(1280 * 720, 5));
// All levels support frame sizes > 183 * 137.
EXPECT_FALSE(H264SupportedLevel(183 * 137, 30));
}
TEST(H264ProfileLevelId, TestToString) {
EXPECT_EQ("42e01f", *H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileConstrainedBaseline,
H264Level::kLevel3_1)));
EXPECT_EQ("42000a", *H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileBaseline, H264Level::kLevel1)));
EXPECT_EQ("4d001f", H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileMain, H264Level::kLevel3_1)));
EXPECT_EQ("640c2a",
*H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileConstrainedHigh, H264Level::kLevel4_2)));
EXPECT_EQ("64002a", *H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileHigh, H264Level::kLevel4_2)));
}
TEST(H264ProfileLevelId, TestToStringLevel1b) {
EXPECT_EQ("42f00b", *H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileConstrainedBaseline,
H264Level::kLevel1_b)));
EXPECT_EQ("42100b",
*H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileBaseline, H264Level::kLevel1_b)));
EXPECT_EQ("4d100b", *H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileMain, H264Level::kLevel1_b)));
}
TEST(H264ProfileLevelId, TestToStringRoundTrip) {
EXPECT_EQ("42e01f",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("42e01f")));
EXPECT_EQ("42e01f",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("42E01F")));
EXPECT_EQ("4d100b",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("4d100b")));
EXPECT_EQ("4d100b",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("4D100B")));
EXPECT_EQ("640c2a",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("640c2a")));
EXPECT_EQ("640c2a",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("640C2A")));
}
TEST(H264ProfileLevelId, TestToStringInvalid) {
EXPECT_FALSE(H264ProfileLevelIdToString(
H264ProfileLevelId(H264Profile::kProfileHigh, H264Level::kLevel1_b)));
EXPECT_FALSE(H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileConstrainedHigh, H264Level::kLevel1_b)));
EXPECT_FALSE(H264ProfileLevelIdToString(
H264ProfileLevelId(static_cast<H264Profile>(255), H264Level::kLevel3_1)));
}
TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdEmpty) {
const absl::optional<H264ProfileLevelId> profile_level_id =
ParseSdpForH264ProfileLevelId(SdpVideoFormat::Parameters());
EXPECT_TRUE(profile_level_id);
EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
profile_level_id->profile);
EXPECT_EQ(H264Level::kLevel3_1, profile_level_id->level);
}
TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdConstrainedHigh) {
SdpVideoFormat::Parameters params;
params["profile-level-id"] = "640c2a";
const absl::optional<H264ProfileLevelId> profile_level_id =
ParseSdpForH264ProfileLevelId(params);
EXPECT_TRUE(profile_level_id);
EXPECT_EQ(H264Profile::kProfileConstrainedHigh, profile_level_id->profile);
EXPECT_EQ(H264Level::kLevel4_2, profile_level_id->level);
}
TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdInvalid) {
SdpVideoFormat::Parameters params;
params["profile-level-id"] = "foobar";
EXPECT_FALSE(ParseSdpForH264ProfileLevelId(params));
}
} // namespace webrtc

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
* *
* Use of this source code is governed by a BSD-style license * 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 * that can be found in the LICENSE file in the root of the source
@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "media/base/vp9_profile.h" #include "api/video_codecs/vp9_profile.h"
#include <map> #include <map>
#include <utility> #include <utility>
@ -59,7 +59,7 @@ absl::optional<VP9Profile> ParseSdpForVP9Profile(
return StringToVP9Profile(profile_str); return StringToVP9Profile(profile_str);
} }
bool IsSameVP9Profile(const SdpVideoFormat::Parameters& params1, bool VP9IsSameProfile(const SdpVideoFormat::Parameters& params1,
const SdpVideoFormat::Parameters& params2) { const SdpVideoFormat::Parameters& params2) {
const absl::optional<VP9Profile> profile = ParseSdpForVP9Profile(params1); const absl::optional<VP9Profile> profile = ParseSdpForVP9Profile(params1);
const absl::optional<VP9Profile> other_profile = const absl::optional<VP9Profile> other_profile =

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2021 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 API_VIDEO_CODECS_VP9_PROFILE_H_
#define API_VIDEO_CODECS_VP9_PROFILE_H_
#include <string>
#include "absl/types/optional.h"
#include "api/video_codecs/sdp_video_format.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
// Profile information for VP9 video.
extern RTC_EXPORT const char kVP9FmtpProfileId[];
enum class VP9Profile {
kProfile0,
kProfile1,
kProfile2,
};
// Helper functions to convert VP9Profile to std::string. Returns "0" by
// default.
RTC_EXPORT std::string VP9ProfileToString(VP9Profile profile);
// Helper functions to convert std::string to VP9Profile. Returns null if given
// an invalid profile string.
absl::optional<VP9Profile> StringToVP9Profile(const std::string& str);
// Parse profile that is represented as a string of single digit contained in an
// SDP key-value map. A default profile(kProfile0) will be returned if the
// profile key is missing. Nothing will be returned if the key is present but
// the string is invalid.
RTC_EXPORT absl::optional<VP9Profile> ParseSdpForVP9Profile(
const SdpVideoFormat::Parameters& params);
// Returns true if the parameters have the same VP9 profile, or neither contains
// VP9 profile.
bool VP9IsSameProfile(const SdpVideoFormat::Parameters& params1,
const SdpVideoFormat::Parameters& params2);
} // namespace webrtc
#endif // API_VIDEO_CODECS_VP9_PROFILE_H_

View File

@ -21,7 +21,6 @@ rtc_library("common_video") {
"h264/h264_common.h", "h264/h264_common.h",
"h264/pps_parser.cc", "h264/pps_parser.cc",
"h264/pps_parser.h", "h264/pps_parser.h",
"h264/profile_level_id.h",
"h264/sps_parser.cc", "h264/sps_parser.cc",
"h264/sps_parser.h", "h264/sps_parser.h",
"h264/sps_vui_rewriter.cc", "h264/sps_vui_rewriter.cc",
@ -52,7 +51,7 @@ rtc_library("common_video") {
"../api/video:video_frame", "../api/video:video_frame",
"../api/video:video_rtp_headers", "../api/video:video_rtp_headers",
"../api/video_codecs:bitstream_parser_api", "../api/video_codecs:bitstream_parser_api",
"../media:rtc_h264_profile_id", "../api/video_codecs:video_codecs_api",
"../rtc_base", "../rtc_base",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:rtc_task_queue", "../rtc_base:rtc_task_queue",
@ -90,7 +89,6 @@ if (rtc_include_tests && !build_with_chromium) {
"frame_rate_estimator_unittest.cc", "frame_rate_estimator_unittest.cc",
"h264/h264_bitstream_parser_unittest.cc", "h264/h264_bitstream_parser_unittest.cc",
"h264/pps_parser_unittest.cc", "h264/pps_parser_unittest.cc",
"h264/profile_level_id_unittest.cc",
"h264/sps_parser_unittest.cc", "h264/sps_parser_unittest.cc",
"h264/sps_vui_rewriter_unittest.cc", "h264/sps_vui_rewriter_unittest.cc",
"libyuv/libyuv_unittest.cc", "libyuv/libyuv_unittest.cc",
@ -105,7 +103,7 @@ if (rtc_include_tests && !build_with_chromium) {
"../api/video:video_frame", "../api/video:video_frame",
"../api/video:video_frame_i010", "../api/video:video_frame_i010",
"../api/video:video_rtp_headers", "../api/video:video_rtp_headers",
"../media:rtc_h264_profile_id", "../api/video_codecs:video_codecs_api",
"../rtc_base", "../rtc_base",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_approved",

View File

@ -1,19 +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 COMMON_VIDEO_H264_PROFILE_LEVEL_ID_H_
#define COMMON_VIDEO_H264_PROFILE_LEVEL_ID_H_
#include "media/base/h264_profile_level_id.h"
// TODO(zhihuang): Delete this file once dependent applications switch to
// including "webrtc/media/base/h264_profile_level_id.h" directly.
#endif // COMMON_VIDEO_H264_PROFILE_LEVEL_ID_H_

View File

@ -1,201 +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 "common_video/h264/profile_level_id.h"
#include <map>
#include <string>
#include "absl/types/optional.h"
#include "media/base/h264_profile_level_id.h"
#include "test/gtest.h"
namespace webrtc {
namespace H264 {
TEST(H264ProfileLevelId, TestParsingInvalid) {
// Malformed strings.
EXPECT_FALSE(ParseProfileLevelId(""));
EXPECT_FALSE(ParseProfileLevelId(" 42e01f"));
EXPECT_FALSE(ParseProfileLevelId("4242e01f"));
EXPECT_FALSE(ParseProfileLevelId("e01f"));
EXPECT_FALSE(ParseProfileLevelId("gggggg"));
// Invalid level.
EXPECT_FALSE(ParseProfileLevelId("42e000"));
EXPECT_FALSE(ParseProfileLevelId("42e00f"));
EXPECT_FALSE(ParseProfileLevelId("42e0ff"));
// Invalid profile.
EXPECT_FALSE(ParseProfileLevelId("42e11f"));
EXPECT_FALSE(ParseProfileLevelId("58601f"));
EXPECT_FALSE(ParseProfileLevelId("64e01f"));
}
TEST(H264ProfileLevelId, TestParsingLevel) {
EXPECT_EQ(kLevel3_1, ParseProfileLevelId("42e01f")->level);
EXPECT_EQ(kLevel1_1, ParseProfileLevelId("42e00b")->level);
EXPECT_EQ(kLevel1_b, ParseProfileLevelId("42f00b")->level);
EXPECT_EQ(kLevel4_2, ParseProfileLevelId("42C02A")->level);
EXPECT_EQ(kLevel5_2, ParseProfileLevelId("640c34")->level);
}
TEST(H264ProfileLevelId, TestParsingConstrainedBaseline) {
EXPECT_EQ(kProfileConstrainedBaseline,
ParseProfileLevelId("42e01f")->profile);
EXPECT_EQ(kProfileConstrainedBaseline,
ParseProfileLevelId("42C02A")->profile);
EXPECT_EQ(kProfileConstrainedBaseline,
ParseProfileLevelId("4de01f")->profile);
EXPECT_EQ(kProfileConstrainedBaseline,
ParseProfileLevelId("58f01f")->profile);
}
TEST(H264ProfileLevelId, TestParsingBaseline) {
EXPECT_EQ(kProfileBaseline, ParseProfileLevelId("42a01f")->profile);
EXPECT_EQ(kProfileBaseline, ParseProfileLevelId("58A01F")->profile);
}
TEST(H264ProfileLevelId, TestParsingMain) {
EXPECT_EQ(kProfileMain, ParseProfileLevelId("4D401f")->profile);
}
TEST(H264ProfileLevelId, TestParsingHigh) {
EXPECT_EQ(kProfileHigh, ParseProfileLevelId("64001f")->profile);
}
TEST(H264ProfileLevelId, TestParsingConstrainedHigh) {
EXPECT_EQ(kProfileConstrainedHigh, ParseProfileLevelId("640c1f")->profile);
}
TEST(H264ProfileLevelId, TestSupportedLevel) {
EXPECT_EQ(kLevel2_1, *SupportedLevel(640 * 480, 25));
EXPECT_EQ(kLevel3_1, *SupportedLevel(1280 * 720, 30));
EXPECT_EQ(kLevel4_2, *SupportedLevel(1920 * 1280, 60));
}
// Test supported level below level 1 requirements.
TEST(H264ProfileLevelId, TestSupportedLevelInvalid) {
EXPECT_FALSE(SupportedLevel(0, 0));
// All levels support fps > 5.
EXPECT_FALSE(SupportedLevel(1280 * 720, 5));
// All levels support frame sizes > 183 * 137.
EXPECT_FALSE(SupportedLevel(183 * 137, 30));
}
TEST(H264ProfileLevelId, TestToString) {
EXPECT_EQ("42e01f", *ProfileLevelIdToString(ProfileLevelId(
kProfileConstrainedBaseline, kLevel3_1)));
EXPECT_EQ("42000a",
*ProfileLevelIdToString(ProfileLevelId(kProfileBaseline, kLevel1)));
EXPECT_EQ("4d001f",
ProfileLevelIdToString(ProfileLevelId(kProfileMain, kLevel3_1)));
EXPECT_EQ("640c2a", *ProfileLevelIdToString(
ProfileLevelId(kProfileConstrainedHigh, kLevel4_2)));
EXPECT_EQ("64002a",
*ProfileLevelIdToString(ProfileLevelId(kProfileHigh, kLevel4_2)));
}
TEST(H264ProfileLevelId, TestToStringLevel1b) {
EXPECT_EQ("42f00b", *ProfileLevelIdToString(ProfileLevelId(
kProfileConstrainedBaseline, kLevel1_b)));
EXPECT_EQ("42100b", *ProfileLevelIdToString(
ProfileLevelId(kProfileBaseline, kLevel1_b)));
EXPECT_EQ("4d100b",
*ProfileLevelIdToString(ProfileLevelId(kProfileMain, kLevel1_b)));
}
TEST(H264ProfileLevelId, TestToStringRoundTrip) {
EXPECT_EQ("42e01f", *ProfileLevelIdToString(*ParseProfileLevelId("42e01f")));
EXPECT_EQ("42e01f", *ProfileLevelIdToString(*ParseProfileLevelId("42E01F")));
EXPECT_EQ("4d100b", *ProfileLevelIdToString(*ParseProfileLevelId("4d100b")));
EXPECT_EQ("4d100b", *ProfileLevelIdToString(*ParseProfileLevelId("4D100B")));
EXPECT_EQ("640c2a", *ProfileLevelIdToString(*ParseProfileLevelId("640c2a")));
EXPECT_EQ("640c2a", *ProfileLevelIdToString(*ParseProfileLevelId("640C2A")));
}
TEST(H264ProfileLevelId, TestToStringInvalid) {
EXPECT_FALSE(ProfileLevelIdToString(ProfileLevelId(kProfileHigh, kLevel1_b)));
EXPECT_FALSE(ProfileLevelIdToString(
ProfileLevelId(kProfileConstrainedHigh, kLevel1_b)));
EXPECT_FALSE(ProfileLevelIdToString(
ProfileLevelId(static_cast<Profile>(255), kLevel3_1)));
}
TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdEmpty) {
const absl::optional<ProfileLevelId> profile_level_id =
ParseSdpProfileLevelId(CodecParameterMap());
EXPECT_TRUE(profile_level_id);
EXPECT_EQ(kProfileConstrainedBaseline, profile_level_id->profile);
EXPECT_EQ(kLevel3_1, profile_level_id->level);
}
TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdConstrainedHigh) {
CodecParameterMap params;
params["profile-level-id"] = "640c2a";
const absl::optional<ProfileLevelId> profile_level_id =
ParseSdpProfileLevelId(params);
EXPECT_TRUE(profile_level_id);
EXPECT_EQ(kProfileConstrainedHigh, profile_level_id->profile);
EXPECT_EQ(kLevel4_2, profile_level_id->level);
}
TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdInvalid) {
CodecParameterMap params;
params["profile-level-id"] = "foobar";
EXPECT_FALSE(ParseSdpProfileLevelId(params));
}
TEST(H264ProfileLevelId, TestGenerateProfileLevelIdForAnswerEmpty) {
CodecParameterMap answer_params;
GenerateProfileLevelIdForAnswer(CodecParameterMap(), CodecParameterMap(),
&answer_params);
EXPECT_TRUE(answer_params.empty());
}
TEST(H264ProfileLevelId,
TestGenerateProfileLevelIdForAnswerLevelSymmetryCapped) {
CodecParameterMap low_level;
low_level["profile-level-id"] = "42e015";
CodecParameterMap high_level;
high_level["profile-level-id"] = "42e01f";
// Level asymmetry is not allowed; test that answer level is the lower of the
// local and remote levels.
CodecParameterMap answer_params;
GenerateProfileLevelIdForAnswer(low_level /* local_supported */,
high_level /* remote_offered */,
&answer_params);
EXPECT_EQ("42e015", answer_params["profile-level-id"]);
CodecParameterMap answer_params2;
GenerateProfileLevelIdForAnswer(high_level /* local_supported */,
low_level /* remote_offered */,
&answer_params2);
EXPECT_EQ("42e015", answer_params2["profile-level-id"]);
}
TEST(H264ProfileLevelId,
TestGenerateProfileLevelIdForAnswerConstrainedBaselineLevelAsymmetry) {
CodecParameterMap local_params;
local_params["profile-level-id"] = "42e01f";
local_params["level-asymmetry-allowed"] = "1";
CodecParameterMap remote_params;
remote_params["profile-level-id"] = "42e015";
remote_params["level-asymmetry-allowed"] = "1";
CodecParameterMap answer_params;
GenerateProfileLevelIdForAnswer(local_params, remote_params, &answer_params);
// When level asymmetry is allowed, we can answer a higher level than what was
// offered.
EXPECT_EQ("42e01f", answer_params["profile-level-id"]);
}
} // namespace H264
} // namespace webrtc

View File

@ -23,20 +23,15 @@ config("rtc_media_defines_config") {
defines = [ "HAVE_WEBRTC_VIDEO" ] defines = [ "HAVE_WEBRTC_VIDEO" ]
} }
rtc_library("rtc_h264_profile_id") { # Remove once downstream projects stop depend on this.
rtc_source_set("rtc_h264_profile_id") {
visibility = [ "*" ] visibility = [ "*" ]
sources = [ sources = [
"base/h264_profile_level_id.cc", "base/h264_profile_level_id.cc",
"base/h264_profile_level_id.h", "base/h264_profile_level_id.h",
] ]
public_deps = # no-presubmit-check TODO(webrtc:8603)
deps = [ [ "../api/video_codecs:video_codecs_api" ]
"../rtc_base",
"../rtc_base:checks",
"../rtc_base:rtc_base_approved",
"../rtc_base/system:rtc_export",
]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
} }
rtc_source_set("rtc_media_config") { rtc_source_set("rtc_media_config") {
@ -44,30 +39,24 @@ rtc_source_set("rtc_media_config") {
sources = [ "base/media_config.h" ] sources = [ "base/media_config.h" ]
} }
rtc_library("rtc_vp9_profile") { # Remove once downstream projects stop depend on this.
rtc_source_set("rtc_vp9_profile") {
visibility = [ "*" ] visibility = [ "*" ]
sources = [ sources = [ "base/vp9_profile.h" ]
"base/vp9_profile.cc", public_deps = # no-presubmit-check TODO(webrtc:8603)
"base/vp9_profile.h", [ "../api/video_codecs:video_codecs_api" ]
]
deps = [
"../api/video_codecs:video_codecs_api",
"../rtc_base:rtc_base_approved",
"../rtc_base/system:rtc_export",
]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
} }
rtc_library("rtc_sdp_fmtp_utils") { rtc_library("rtc_sdp_video_format_utils") {
visibility = [ "*" ] visibility = [ "*" ]
sources = [ sources = [
"base/sdp_fmtp_utils.cc", "base/sdp_video_format_utils.cc",
"base/sdp_fmtp_utils.h", "base/sdp_video_format_utils.h",
] ]
deps = [ deps = [
"../api/video_codecs:video_codecs_api", "../api/video_codecs:video_codecs_api",
"../rtc_base:checks",
"../rtc_base:stringutils", "../rtc_base:stringutils",
] ]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
@ -78,9 +67,7 @@ rtc_library("rtc_media_base") {
defines = [] defines = []
libs = [] libs = []
deps = [ deps = [
":rtc_h264_profile_id",
":rtc_media_config", ":rtc_media_config",
":rtc_vp9_profile",
"../api:array_view", "../api:array_view",
"../api:audio_options_api", "../api:audio_options_api",
"../api:frame_transformer_interface", "../api:frame_transformer_interface",
@ -221,7 +208,6 @@ rtc_library("rtc_internal_video_codecs") {
libs = [] libs = []
deps = [ deps = [
":rtc_encoder_simulcast_proxy", ":rtc_encoder_simulcast_proxy",
":rtc_h264_profile_id",
":rtc_media_base", ":rtc_media_base",
":rtc_simulcast_encoder_adapter", ":rtc_simulcast_encoder_adapter",
"../api/video:encoded_image", "../api/video:encoded_image",
@ -555,9 +541,8 @@ if (rtc_include_tests) {
":rtc_media_base", ":rtc_media_base",
":rtc_media_engine_defaults", ":rtc_media_engine_defaults",
":rtc_media_tests_utils", ":rtc_media_tests_utils",
":rtc_sdp_fmtp_utils", ":rtc_sdp_video_format_utils",
":rtc_simulcast_encoder_adapter", ":rtc_simulcast_encoder_adapter",
":rtc_vp9_profile",
"../api:create_simulcast_test_fixture_api", "../api:create_simulcast_test_fixture_api",
"../api:libjingle_peerconnection_api", "../api:libjingle_peerconnection_api",
"../api:mock_video_bitrate_allocator", "../api:mock_video_bitrate_allocator",
@ -586,7 +571,6 @@ if (rtc_include_tests) {
"../audio", "../audio",
"../call:call_interfaces", "../call:call_interfaces",
"../common_video", "../common_video",
"../media:rtc_h264_profile_id",
"../modules/audio_device:mock_audio_device", "../modules/audio_device:mock_audio_device",
"../modules/audio_processing", "../modules/audio_processing",
"../modules/audio_processing:api", "../modules/audio_processing:api",
@ -627,7 +611,7 @@ if (rtc_include_tests) {
"base/codec_unittest.cc", "base/codec_unittest.cc",
"base/media_engine_unittest.cc", "base/media_engine_unittest.cc",
"base/rtp_utils_unittest.cc", "base/rtp_utils_unittest.cc",
"base/sdp_fmtp_utils_unittest.cc", "base/sdp_video_format_utils_unittest.cc",
"base/stream_params_unittest.cc", "base/stream_params_unittest.cc",
"base/turn_utils_unittest.cc", "base/turn_utils_unittest.cc",
"base/video_adapter_unittest.cc", "base/video_adapter_unittest.cc",

View File

@ -12,8 +12,8 @@
#include "absl/algorithm/container.h" #include "absl/algorithm/container.h"
#include "absl/strings/match.h" #include "absl/strings/match.h"
#include "media/base/h264_profile_level_id.h" #include "api/video_codecs/h264_profile_level_id.h"
#include "media/base/vp9_profile.h" #include "api/video_codecs/vp9_profile.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/logging.h" #include "rtc_base/logging.h"
#include "rtc_base/string_encode.h" #include "rtc_base/string_encode.h"
@ -51,10 +51,10 @@ bool IsSameCodecSpecific(const std::string& name1,
absl::EqualsIgnoreCase(name, name2); absl::EqualsIgnoreCase(name, name2);
}; };
if (either_name_matches(kH264CodecName)) if (either_name_matches(kH264CodecName))
return webrtc::H264::IsSameH264Profile(params1, params2) && return webrtc::H264IsSameProfile(params1, params2) &&
IsSameH264PacketizationMode(params1, params2); IsSameH264PacketizationMode(params1, params2);
if (either_name_matches(kVp9CodecName)) if (either_name_matches(kVp9CodecName))
return webrtc::IsSameVP9Profile(params1, params2); return webrtc::VP9IsSameProfile(params1, params2);
return true; return true;
} }
@ -473,15 +473,16 @@ void AddH264ConstrainedBaselineProfileToSupportedFormats(
for (auto it = supported_formats->cbegin(); it != supported_formats->cend(); for (auto it = supported_formats->cbegin(); it != supported_formats->cend();
++it) { ++it) {
if (it->name == cricket::kH264CodecName) { if (it->name == cricket::kH264CodecName) {
const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id = const absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
webrtc::H264::ParseSdpProfileLevelId(it->parameters); webrtc::ParseSdpForH264ProfileLevelId(it->parameters);
if (profile_level_id && profile_level_id->profile != if (profile_level_id &&
webrtc::H264::kProfileConstrainedBaseline) { profile_level_id->profile !=
webrtc::H264Profile::kProfileConstrainedBaseline) {
webrtc::SdpVideoFormat cbp_format = *it; webrtc::SdpVideoFormat cbp_format = *it;
webrtc::H264::ProfileLevelId cbp_profile = *profile_level_id; webrtc::H264ProfileLevelId cbp_profile = *profile_level_id;
cbp_profile.profile = webrtc::H264::kProfileConstrainedBaseline; cbp_profile.profile = webrtc::H264Profile::kProfileConstrainedBaseline;
cbp_format.parameters[cricket::kH264FmtpProfileLevelId] = cbp_format.parameters[cricket::kH264FmtpProfileLevelId] =
*webrtc::H264::ProfileLevelIdToString(cbp_profile); *webrtc::H264ProfileLevelIdToString(cbp_profile);
cbr_supported_formats.push_back(cbp_format); cbr_supported_formats.push_back(cbp_format);
} }
} }

View File

@ -12,8 +12,8 @@
#include <tuple> #include <tuple>
#include "media/base/h264_profile_level_id.h" #include "api/video_codecs/h264_profile_level_id.h"
#include "media/base/vp9_profile.h" #include "api/video_codecs/vp9_profile.h"
#include "modules/video_coding/codecs/h264/include/h264.h" #include "modules/video_coding/codecs/h264/include/h264.h"
#include "rtc_base/gunit.h" #include "rtc_base/gunit.h"
@ -457,10 +457,10 @@ TEST(CodecTest, TestToCodecParameters) {
TEST(CodecTest, H264CostrainedBaselineIsAddedIfH264IsSupported) { TEST(CodecTest, H264CostrainedBaselineIsAddedIfH264IsSupported) {
const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = { const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = {
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline, webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
webrtc::H264::kLevel3_1, "1"), webrtc::H264Level::kLevel3_1, "1"),
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline, webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
webrtc::H264::kLevel3_1, "0")}; webrtc::H264Level::kLevel3_1, "0")};
std::vector<webrtc::SdpVideoFormat> supported_formats = std::vector<webrtc::SdpVideoFormat> supported_formats =
kExplicitlySupportedFormats; kExplicitlySupportedFormats;
@ -468,11 +468,11 @@ TEST(CodecTest, H264CostrainedBaselineIsAddedIfH264IsSupported) {
&supported_formats); &supported_formats);
const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization1 = const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization1 =
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline, webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
webrtc::H264::kLevel3_1, "1"); webrtc::H264Level::kLevel3_1, "1");
const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization0 = const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization0 =
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline, webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
webrtc::H264::kLevel3_1, "0"); webrtc::H264Level::kLevel3_1, "0");
EXPECT_EQ(supported_formats[0], kExplicitlySupportedFormats[0]); EXPECT_EQ(supported_formats[0], kExplicitlySupportedFormats[0]);
EXPECT_EQ(supported_formats[1], kExplicitlySupportedFormats[1]); EXPECT_EQ(supported_formats[1], kExplicitlySupportedFormats[1]);
@ -497,14 +497,14 @@ TEST(CodecTest, H264CostrainedBaselineIsNotAddedIfH264IsUnsupported) {
TEST(CodecTest, H264CostrainedBaselineNotAddedIfAlreadySpecified) { TEST(CodecTest, H264CostrainedBaselineNotAddedIfAlreadySpecified) {
const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = { const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = {
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline, webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
webrtc::H264::kLevel3_1, "1"), webrtc::H264Level::kLevel3_1, "1"),
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline, webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
webrtc::H264::kLevel3_1, "0"), webrtc::H264Level::kLevel3_1, "0"),
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline, webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
webrtc::H264::kLevel3_1, "1"), webrtc::H264Level::kLevel3_1, "1"),
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline, webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
webrtc::H264::kLevel3_1, "0")}; webrtc::H264Level::kLevel3_1, "0")};
std::vector<webrtc::SdpVideoFormat> supported_formats = std::vector<webrtc::SdpVideoFormat> supported_formats =
kExplicitlySupportedFormats; kExplicitlySupportedFormats;

View File

@ -10,301 +10,33 @@
#include "media/base/h264_profile_level_id.h" #include "media/base/h264_profile_level_id.h"
#include <cstdio> // TODO(crbug.com/1187565): Remove this file once downstream projects stop
#include <cstdlib> // depend on it.
#include <cstring>
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
namespace webrtc { namespace webrtc {
namespace H264 { namespace H264 {
namespace {
const char kProfileLevelId[] = "profile-level-id";
const char kLevelAsymmetryAllowed[] = "level-asymmetry-allowed";
// For level_idc=11 and profile_idc=0x42, 0x4D, or 0x58, the constraint set3
// flag specifies if level 1b or level 1.1 is used.
const uint8_t kConstraintSet3Flag = 0x10;
// Convert a string of 8 characters into a byte where the positions containing
// character c will have their bit set. For example, c = 'x', str = "x1xx0000"
// will return 0b10110000. constexpr is used so that the pattern table in
// kProfilePatterns is statically initialized.
constexpr uint8_t ByteMaskString(char c, const char (&str)[9]) {
return (str[0] == c) << 7 | (str[1] == c) << 6 | (str[2] == c) << 5 |
(str[3] == c) << 4 | (str[4] == c) << 3 | (str[5] == c) << 2 |
(str[6] == c) << 1 | (str[7] == c) << 0;
}
// Class for matching bit patterns such as "x1xx0000" where 'x' is allowed to be
// either 0 or 1.
class BitPattern {
public:
explicit constexpr BitPattern(const char (&str)[9])
: mask_(~ByteMaskString('x', str)),
masked_value_(ByteMaskString('1', str)) {}
bool IsMatch(uint8_t value) const { return masked_value_ == (value & mask_); }
private:
const uint8_t mask_;
const uint8_t masked_value_;
};
// Table for converting between profile_idc/profile_iop to H264::Profile.
struct ProfilePattern {
const uint8_t profile_idc;
const BitPattern profile_iop;
const Profile profile;
};
// This is from https://tools.ietf.org/html/rfc6184#section-8.1.
constexpr ProfilePattern kProfilePatterns[] = {
{0x42, BitPattern("x1xx0000"), kProfileConstrainedBaseline},
{0x4D, BitPattern("1xxx0000"), kProfileConstrainedBaseline},
{0x58, BitPattern("11xx0000"), kProfileConstrainedBaseline},
{0x42, BitPattern("x0xx0000"), kProfileBaseline},
{0x58, BitPattern("10xx0000"), kProfileBaseline},
{0x4D, BitPattern("0x0x0000"), kProfileMain},
{0x64, BitPattern("00000000"), kProfileHigh},
{0x64, BitPattern("00001100"), kProfileConstrainedHigh}};
// Compare H264 levels and handle the level 1b case.
bool IsLess(Level a, Level b) {
if (a == kLevel1_b)
return b != kLevel1 && b != kLevel1_b;
if (b == kLevel1_b)
return a == kLevel1;
return a < b;
}
Level Min(Level a, Level b) {
return IsLess(a, b) ? a : b;
}
bool IsLevelAsymmetryAllowed(const CodecParameterMap& params) {
const auto it = params.find(kLevelAsymmetryAllowed);
return it != params.end() && strcmp(it->second.c_str(), "1") == 0;
}
struct LevelConstraint {
const int max_macroblocks_per_second;
const int max_macroblock_frame_size;
const webrtc::H264::Level level;
};
// This is from ITU-T H.264 (02/2016) Table A-1 Level limits.
static constexpr LevelConstraint kLevelConstraints[] = {
{1485, 99, webrtc::H264::kLevel1},
{1485, 99, webrtc::H264::kLevel1_b},
{3000, 396, webrtc::H264::kLevel1_1},
{6000, 396, webrtc::H264::kLevel1_2},
{11880, 396, webrtc::H264::kLevel1_3},
{11880, 396, webrtc::H264::kLevel2},
{19800, 792, webrtc::H264::kLevel2_1},
{20250, 1620, webrtc::H264::kLevel2_2},
{40500, 1620, webrtc::H264::kLevel3},
{108000, 3600, webrtc::H264::kLevel3_1},
{216000, 5120, webrtc::H264::kLevel3_2},
{245760, 8192, webrtc::H264::kLevel4},
{245760, 8192, webrtc::H264::kLevel4_1},
{522240, 8704, webrtc::H264::kLevel4_2},
{589824, 22080, webrtc::H264::kLevel5},
{983040, 36864, webrtc::H264::kLevel5_1},
{2073600, 36864, webrtc::H264::kLevel5_2},
};
} // anonymous namespace
absl::optional<ProfileLevelId> ParseProfileLevelId(const char* str) { absl::optional<ProfileLevelId> ParseProfileLevelId(const char* str) {
// The string should consist of 3 bytes in hexadecimal format. return webrtc::ParseH264ProfileLevelId(str);
if (strlen(str) != 6u)
return absl::nullopt;
const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16);
if (profile_level_id_numeric == 0)
return absl::nullopt;
// Separate into three bytes.
const uint8_t level_idc =
static_cast<uint8_t>(profile_level_id_numeric & 0xFF);
const uint8_t profile_iop =
static_cast<uint8_t>((profile_level_id_numeric >> 8) & 0xFF);
const uint8_t profile_idc =
static_cast<uint8_t>((profile_level_id_numeric >> 16) & 0xFF);
// Parse level based on level_idc and constraint set 3 flag.
Level level;
switch (level_idc) {
case kLevel1_1:
level = (profile_iop & kConstraintSet3Flag) != 0 ? kLevel1_b : kLevel1_1;
break;
case kLevel1:
case kLevel1_2:
case kLevel1_3:
case kLevel2:
case kLevel2_1:
case kLevel2_2:
case kLevel3:
case kLevel3_1:
case kLevel3_2:
case kLevel4:
case kLevel4_1:
case kLevel4_2:
case kLevel5:
case kLevel5_1:
case kLevel5_2:
level = static_cast<Level>(level_idc);
break;
default:
// Unrecognized level_idc.
return absl::nullopt;
}
// Parse profile_idc/profile_iop into a Profile enum.
for (const ProfilePattern& pattern : kProfilePatterns) {
if (profile_idc == pattern.profile_idc &&
pattern.profile_iop.IsMatch(profile_iop)) {
return ProfileLevelId(pattern.profile, level);
}
}
// Unrecognized profile_idc/profile_iop combination.
return absl::nullopt;
}
absl::optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps) {
static const int kPixelsPerMacroblock = 16 * 16;
for (int i = arraysize(kLevelConstraints) - 1; i >= 0; --i) {
const LevelConstraint& level_constraint = kLevelConstraints[i];
if (level_constraint.max_macroblock_frame_size * kPixelsPerMacroblock <=
max_frame_pixel_count &&
level_constraint.max_macroblocks_per_second <=
max_fps * level_constraint.max_macroblock_frame_size) {
return level_constraint.level;
}
}
// No level supported.
return absl::nullopt;
} }
absl::optional<ProfileLevelId> ParseSdpProfileLevelId( absl::optional<ProfileLevelId> ParseSdpProfileLevelId(
const CodecParameterMap& params) { const SdpVideoFormat::Parameters& params) {
// TODO(magjed): The default should really be kProfileBaseline and kLevel1 return webrtc::ParseSdpForH264ProfileLevelId(params);
// according to the spec: https://tools.ietf.org/html/rfc6184#section-8.1. In }
// order to not break backwards compatibility with older versions of WebRTC
// where external codecs don't have any parameters, use
// kProfileConstrainedBaseline kLevel3_1 instead. This workaround will only be
// done in an interim period to allow external clients to update their code.
// http://crbug/webrtc/6337.
static const ProfileLevelId kDefaultProfileLevelId(
kProfileConstrainedBaseline, kLevel3_1);
const auto profile_level_id_it = params.find(kProfileLevelId); absl::optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps) {
return (profile_level_id_it == params.end()) return webrtc::H264SupportedLevel(max_frame_pixel_count, max_fps);
? kDefaultProfileLevelId
: ParseProfileLevelId(profile_level_id_it->second.c_str());
} }
absl::optional<std::string> ProfileLevelIdToString( absl::optional<std::string> ProfileLevelIdToString(
const ProfileLevelId& profile_level_id) { const ProfileLevelId& profile_level_id) {
// Handle special case level == 1b. return webrtc::H264ProfileLevelIdToString(profile_level_id);
if (profile_level_id.level == kLevel1_b) {
switch (profile_level_id.profile) {
case kProfileConstrainedBaseline:
return {"42f00b"};
case kProfileBaseline:
return {"42100b"};
case kProfileMain:
return {"4d100b"};
// Level 1b is not allowed for other profiles.
default:
return absl::nullopt;
}
}
const char* profile_idc_iop_string;
switch (profile_level_id.profile) {
case kProfileConstrainedBaseline:
profile_idc_iop_string = "42e0";
break;
case kProfileBaseline:
profile_idc_iop_string = "4200";
break;
case kProfileMain:
profile_idc_iop_string = "4d00";
break;
case kProfileConstrainedHigh:
profile_idc_iop_string = "640c";
break;
case kProfileHigh:
profile_idc_iop_string = "6400";
break;
// Unrecognized profile.
default:
return absl::nullopt;
}
char str[7];
snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level);
return {str};
} }
// Set level according to https://tools.ietf.org/html/rfc6184#section-8.2.2. bool IsSameH264Profile(const SdpVideoFormat::Parameters& params1,
void GenerateProfileLevelIdForAnswer( const SdpVideoFormat::Parameters& params2) {
const CodecParameterMap& local_supported_params, return webrtc::H264IsSameProfile(params1, params2);
const CodecParameterMap& remote_offered_params,
CodecParameterMap* answer_params) {
// If both local and remote haven't set profile-level-id, they are both using
// the default profile. In this case, don't set profile-level-id in answer
// either.
if (!local_supported_params.count(kProfileLevelId) &&
!remote_offered_params.count(kProfileLevelId)) {
return;
}
// Parse profile-level-ids.
const absl::optional<ProfileLevelId> local_profile_level_id =
ParseSdpProfileLevelId(local_supported_params);
const absl::optional<ProfileLevelId> remote_profile_level_id =
ParseSdpProfileLevelId(remote_offered_params);
// The local and remote codec must have valid and equal H264 Profiles.
RTC_DCHECK(local_profile_level_id);
RTC_DCHECK(remote_profile_level_id);
RTC_DCHECK_EQ(local_profile_level_id->profile,
remote_profile_level_id->profile);
// Parse level information.
const bool level_asymmetry_allowed =
IsLevelAsymmetryAllowed(local_supported_params) &&
IsLevelAsymmetryAllowed(remote_offered_params);
const Level local_level = local_profile_level_id->level;
const Level remote_level = remote_profile_level_id->level;
const Level min_level = Min(local_level, remote_level);
// Determine answer level. When level asymmetry is not allowed, level upgrade
// is not allowed, i.e., the level in the answer must be equal to or lower
// than the level in the offer.
const Level answer_level = level_asymmetry_allowed ? local_level : min_level;
// Set the resulting profile-level-id in the answer parameters.
(*answer_params)[kProfileLevelId] = *ProfileLevelIdToString(
ProfileLevelId(local_profile_level_id->profile, answer_level));
}
bool IsSameH264Profile(const CodecParameterMap& params1,
const CodecParameterMap& params2) {
const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
webrtc::H264::ParseSdpProfileLevelId(params1);
const absl::optional<webrtc::H264::ProfileLevelId> other_profile_level_id =
webrtc::H264::ParseSdpProfileLevelId(params2);
// Compare H264 profiles, but not levels.
return profile_level_id && other_profile_level_id &&
profile_level_id->profile == other_profile_level_id->profile;
} }
} // namespace H264 } // namespace H264

View File

@ -11,54 +11,45 @@
#ifndef MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_ #ifndef MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
#define MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_ #define MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
#include <map>
#include <string> #include <string>
#include "absl/types/optional.h" #include "api/video_codecs/h264_profile_level_id.h"
#include "rtc_base/system/rtc_export.h"
// TODO(crbug.com/1187565): Remove this file once downstream projects stop
// depend on it.
namespace webrtc { namespace webrtc {
namespace H264 { namespace H264 {
enum Profile { typedef H264Profile Profile;
kProfileConstrainedBaseline, typedef H264Level Level;
kProfileBaseline, typedef H264ProfileLevelId ProfileLevelId;
kProfileMain,
kProfileConstrainedHigh,
kProfileHigh,
};
// Map containting SDP codec parameters. constexpr H264Profile kProfileConstrainedBaseline =
typedef std::map<std::string, std::string> CodecParameterMap; H264Profile::kProfileConstrainedBaseline;
constexpr H264Profile kProfileBaseline = H264Profile::kProfileBaseline;
constexpr H264Profile kProfileMain = H264Profile::kProfileMain;
constexpr H264Profile kProfileConstrainedHigh =
H264Profile::kProfileConstrainedHigh;
constexpr H264Profile kProfileHigh = H264Profile::kProfileHigh;
// All values are equal to ten times the level number, except level 1b which is constexpr H264Level kLevel1_b = H264Level::kLevel1_b;
// special. constexpr H264Level kLevel1 = H264Level::kLevel1;
enum Level { constexpr H264Level kLevel1_1 = H264Level::kLevel1_1;
kLevel1_b = 0, constexpr H264Level kLevel1_2 = H264Level::kLevel1_2;
kLevel1 = 10, constexpr H264Level kLevel1_3 = H264Level::kLevel1_3;
kLevel1_1 = 11, constexpr H264Level kLevel2 = H264Level::kLevel2;
kLevel1_2 = 12, constexpr H264Level kLevel2_1 = H264Level::kLevel2_1;
kLevel1_3 = 13, constexpr H264Level kLevel2_2 = H264Level::kLevel2_2;
kLevel2 = 20, constexpr H264Level kLevel3 = H264Level::kLevel3;
kLevel2_1 = 21, constexpr H264Level kLevel3_1 = H264Level::kLevel3_1;
kLevel2_2 = 22, constexpr H264Level kLevel3_2 = H264Level::kLevel3_2;
kLevel3 = 30, constexpr H264Level kLevel4 = H264Level::kLevel4;
kLevel3_1 = 31, constexpr H264Level kLevel4_1 = H264Level::kLevel4_1;
kLevel3_2 = 32, constexpr H264Level kLevel4_2 = H264Level::kLevel4_2;
kLevel4 = 40, constexpr H264Level kLevel5 = H264Level::kLevel5;
kLevel4_1 = 41, constexpr H264Level kLevel5_1 = H264Level::kLevel5_1;
kLevel4_2 = 42, constexpr H264Level kLevel5_2 = H264Level::kLevel5_2;
kLevel5 = 50,
kLevel5_1 = 51,
kLevel5_2 = 52
};
struct ProfileLevelId {
constexpr ProfileLevelId(Profile profile, Level level)
: profile(profile), level(level) {}
Profile profile;
Level level;
};
// Parse profile level id that is represented as a string of 3 hex bytes. // Parse profile level id that is represented as a string of 3 hex bytes.
// Nothing will be returned if the string is not a recognized H264 // Nothing will be returned if the string is not a recognized H264
@ -70,7 +61,7 @@ absl::optional<ProfileLevelId> ParseProfileLevelId(const char* str);
// returned if the profile-level-id key is missing. Nothing will be returned if // returned if the profile-level-id key is missing. Nothing will be returned if
// the key is present but the string is invalid. // the key is present but the string is invalid.
RTC_EXPORT absl::optional<ProfileLevelId> ParseSdpProfileLevelId( RTC_EXPORT absl::optional<ProfileLevelId> ParseSdpProfileLevelId(
const CodecParameterMap& params); const SdpVideoFormat::Parameters& params);
// Given that a decoder supports up to a given frame size (in pixels) at up to a // Given that a decoder supports up to a given frame size (in pixels) at up to a
// given number of frames per second, return the highest H.264 level where it // given number of frames per second, return the highest H.264 level where it
@ -84,33 +75,11 @@ RTC_EXPORT absl::optional<Level> SupportedLevel(int max_frame_pixel_count,
RTC_EXPORT absl::optional<std::string> ProfileLevelIdToString( RTC_EXPORT absl::optional<std::string> ProfileLevelIdToString(
const ProfileLevelId& profile_level_id); const ProfileLevelId& profile_level_id);
// Generate codec parameters that will be used as answer in an SDP negotiation
// based on local supported parameters and remote offered parameters. Both
// |local_supported_params|, |remote_offered_params|, and |answer_params|
// represent sendrecv media descriptions, i.e they are a mix of both encode and
// decode capabilities. In theory, when the profile in |local_supported_params|
// represent a strict superset of the profile in |remote_offered_params|, we
// could limit the profile in |answer_params| to the profile in
// |remote_offered_params|. However, to simplify the code, each supported H264
// profile should be listed explicitly in the list of local supported codecs,
// even if they are redundant. Then each local codec in the list should be
// tested one at a time against the remote codec, and only when the profiles are
// equal should this function be called. Therefore, this function does not need
// to handle profile intersection, and the profile of |local_supported_params|
// and |remote_offered_params| must be equal before calling this function. The
// parameters that are used when negotiating are the level part of
// profile-level-id and level-asymmetry-allowed.
void GenerateProfileLevelIdForAnswer(
const CodecParameterMap& local_supported_params,
const CodecParameterMap& remote_offered_params,
CodecParameterMap* answer_params);
// Returns true if the parameters have the same H264 profile, i.e. the same // Returns true if the parameters have the same H264 profile, i.e. the same
// H264::Profile (Baseline, High, etc). // H264::Profile (Baseline, High, etc).
bool IsSameH264Profile(const CodecParameterMap& params1, RTC_EXPORT bool IsSameH264Profile(const SdpVideoFormat::Parameters& params1,
const CodecParameterMap& params2); const SdpVideoFormat::Parameters& params2);
} // namespace H264 } // namespace H264
} // namespace webrtc } // namespace webrtc
#endif // MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_ #endif // MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_

View File

@ -1,55 +0,0 @@
/*
* 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 <map>
#include <utility>
#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<int> 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<int> i =
rtc::StringToNumber<int>(max_frame_rate_it->second);
if (!i.has_value() || i.value() <= 0)
return absl::nullopt;
return i;
}
} // namespace
absl::optional<int> ParseSdpForVPxMaxFrameRate(
const SdpVideoFormat::Parameters& params) {
return ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameRate);
}
absl::optional<int> ParseSdpForVPxMaxFrameSize(
const SdpVideoFormat::Parameters& params) {
const absl::optional<int> i =
ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameSize);
return i ? absl::make_optional(i.value() * kVPxFmtpFrameSizeSubBlockPixels)
: absl::nullopt;
}
} // namespace webrtc

View File

@ -1,32 +0,0 @@
/*
* 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<int> 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<int> ParseSdpForVPxMaxFrameSize(
const SdpVideoFormat::Parameters& params);
} // namespace webrtc
#endif // MEDIA_BASE_SDP_FMTP_UTILS_H__

View File

@ -1,68 +0,0 @@
/*
* 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 <string.h>
#include <map>
#include <utility>
#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<int> 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<int> 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

View File

@ -0,0 +1,121 @@
/*
* 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_video_format_utils.h"
#include <cstring>
#include <map>
#include <utility>
#include "api/video_codecs/h264_profile_level_id.h"
#include "rtc_base/checks.h"
#include "rtc_base/string_to_number.h"
namespace webrtc {
namespace {
const char kProfileLevelId[] = "profile-level-id";
const char kH264LevelAsymmetryAllowed[] = "level-asymmetry-allowed";
// 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;
bool IsH264LevelAsymmetryAllowed(const SdpVideoFormat::Parameters& params) {
const auto it = params.find(kH264LevelAsymmetryAllowed);
return it != params.end() && strcmp(it->second.c_str(), "1") == 0;
}
// Compare H264 levels and handle the level 1b case.
bool H264LevelIsLess(H264Level a, H264Level b) {
if (a == H264Level::kLevel1_b)
return b != H264Level::kLevel1 && b != H264Level::kLevel1_b;
if (b == H264Level::kLevel1_b)
return a == H264Level::kLevel1;
return a < b;
}
H264Level H264LevelMin(H264Level a, H264Level b) {
return H264LevelIsLess(a, b) ? a : b;
}
absl::optional<int> 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<int> i =
rtc::StringToNumber<int>(max_frame_rate_it->second);
if (!i.has_value() || i.value() <= 0)
return absl::nullopt;
return i;
}
} // namespace
// Set level according to https://tools.ietf.org/html/rfc6184#section-8.2.2.
void H264GenerateProfileLevelIdForAnswer(
const SdpVideoFormat::Parameters& local_supported_params,
const SdpVideoFormat::Parameters& remote_offered_params,
SdpVideoFormat::Parameters* answer_params) {
// If both local and remote haven't set profile-level-id, they are both using
// the default profile. In this case, don't set profile-level-id in answer
// either.
if (!local_supported_params.count(kProfileLevelId) &&
!remote_offered_params.count(kProfileLevelId)) {
return;
}
// Parse profile-level-ids.
const absl::optional<H264ProfileLevelId> local_profile_level_id =
ParseSdpForH264ProfileLevelId(local_supported_params);
const absl::optional<H264ProfileLevelId> remote_profile_level_id =
ParseSdpForH264ProfileLevelId(remote_offered_params);
// The local and remote codec must have valid and equal H264 Profiles.
RTC_DCHECK(local_profile_level_id);
RTC_DCHECK(remote_profile_level_id);
RTC_DCHECK_EQ(local_profile_level_id->profile,
remote_profile_level_id->profile);
// Parse level information.
const bool level_asymmetry_allowed =
IsH264LevelAsymmetryAllowed(local_supported_params) &&
IsH264LevelAsymmetryAllowed(remote_offered_params);
const H264Level local_level = local_profile_level_id->level;
const H264Level remote_level = remote_profile_level_id->level;
const H264Level min_level = H264LevelMin(local_level, remote_level);
// Determine answer level. When level asymmetry is not allowed, level upgrade
// is not allowed, i.e., the level in the answer must be equal to or lower
// than the level in the offer.
const H264Level answer_level =
level_asymmetry_allowed ? local_level : min_level;
// Set the resulting profile-level-id in the answer parameters.
(*answer_params)[kProfileLevelId] = *H264ProfileLevelIdToString(
H264ProfileLevelId(local_profile_level_id->profile, answer_level));
}
absl::optional<int> ParseSdpForVPxMaxFrameRate(
const SdpVideoFormat::Parameters& params) {
return ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameRate);
}
absl::optional<int> ParseSdpForVPxMaxFrameSize(
const SdpVideoFormat::Parameters& params) {
const absl::optional<int> i =
ParsePositiveNumberFromParams(params, kVPxFmtpMaxFrameSize);
return i ? absl::make_optional(i.value() * kVPxFmtpFrameSizeSubBlockPixels)
: absl::nullopt;
}
} // namespace webrtc

View File

@ -0,0 +1,52 @@
/*
* 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_VIDEO_FORMAT_UTILS_H_
#define MEDIA_BASE_SDP_VIDEO_FORMAT_UTILS_H_
#include "absl/types/optional.h"
#include "api/video_codecs/sdp_video_format.h"
namespace webrtc {
// Generate codec parameters that will be used as answer in an SDP negotiation
// based on local supported parameters and remote offered parameters. Both
// |local_supported_params|, |remote_offered_params|, and |answer_params|
// represent sendrecv media descriptions, i.e they are a mix of both encode and
// decode capabilities. In theory, when the profile in |local_supported_params|
// represent a strict superset of the profile in |remote_offered_params|, we
// could limit the profile in |answer_params| to the profile in
// |remote_offered_params|. However, to simplify the code, each supported H264
// profile should be listed explicitly in the list of local supported codecs,
// even if they are redundant. Then each local codec in the list should be
// tested one at a time against the remote codec, and only when the profiles are
// equal should this function be called. Therefore, this function does not need
// to handle profile intersection, and the profile of |local_supported_params|
// and |remote_offered_params| must be equal before calling this function. The
// parameters that are used when negotiating are the level part of
// profile-level-id and level-asymmetry-allowed.
void H264GenerateProfileLevelIdForAnswer(
const SdpVideoFormat::Parameters& local_supported_params,
const SdpVideoFormat::Parameters& remote_offered_params,
SdpVideoFormat::Parameters* answer_params);
// Parse max frame rate from SDP FMTP line. absl::nullopt is returned if the
// field is missing or not a number.
absl::optional<int> 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<int> ParseSdpForVPxMaxFrameSize(
const SdpVideoFormat::Parameters& params);
} // namespace webrtc
#endif // MEDIA_BASE_SDP_VIDEO_FORMAT_UTILS_H_

View File

@ -0,0 +1,115 @@
/*
* 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_video_format_utils.h"
#include <string.h>
#include <map>
#include <utility>
#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(SdpVideoFormatUtilsTest, TestH264GenerateProfileLevelIdForAnswerEmpty) {
SdpVideoFormat::Parameters answer_params;
H264GenerateProfileLevelIdForAnswer(SdpVideoFormat::Parameters(),
SdpVideoFormat::Parameters(),
&answer_params);
EXPECT_TRUE(answer_params.empty());
}
TEST(SdpVideoFormatUtilsTest,
TestH264GenerateProfileLevelIdForAnswerLevelSymmetryCapped) {
SdpVideoFormat::Parameters low_level;
low_level["profile-level-id"] = "42e015";
SdpVideoFormat::Parameters high_level;
high_level["profile-level-id"] = "42e01f";
// Level asymmetry is not allowed; test that answer level is the lower of the
// local and remote levels.
SdpVideoFormat::Parameters answer_params;
H264GenerateProfileLevelIdForAnswer(low_level /* local_supported */,
high_level /* remote_offered */,
&answer_params);
EXPECT_EQ("42e015", answer_params["profile-level-id"]);
SdpVideoFormat::Parameters answer_params2;
H264GenerateProfileLevelIdForAnswer(high_level /* local_supported */,
low_level /* remote_offered */,
&answer_params2);
EXPECT_EQ("42e015", answer_params2["profile-level-id"]);
}
TEST(SdpVideoFormatUtilsTest,
TestH264GenerateProfileLevelIdForAnswerConstrainedBaselineLevelAsymmetry) {
SdpVideoFormat::Parameters local_params;
local_params["profile-level-id"] = "42e01f";
local_params["level-asymmetry-allowed"] = "1";
SdpVideoFormat::Parameters remote_params;
remote_params["profile-level-id"] = "42e015";
remote_params["level-asymmetry-allowed"] = "1";
SdpVideoFormat::Parameters answer_params;
H264GenerateProfileLevelIdForAnswer(local_params, remote_params,
&answer_params);
// When level asymmetry is allowed, we can answer a higher level than what was
// offered.
EXPECT_EQ("42e01f", answer_params["profile-level-id"]);
}
TEST(SdpVideoFormatUtilsTest, MaxFrameRateIsMissingOrInvalid) {
SdpVideoFormat::Parameters params;
absl::optional<int> 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(SdpVideoFormatUtilsTest, MaxFrameRateIsSpecified) {
SdpVideoFormat::Parameters params;
params[kVPxFmtpMaxFrameRate] = "30";
EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 30);
params[kVPxFmtpMaxFrameRate] = "60";
EXPECT_EQ(ParseSdpForVPxMaxFrameRate(params), 60);
}
TEST(SdpVideoFormatUtilsTest, MaxFrameSizeIsMissingOrInvalid) {
SdpVideoFormat::Parameters params;
absl::optional<int> 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(SdpVideoFormatUtilsTest, 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

View File

@ -11,43 +11,9 @@
#ifndef MEDIA_BASE_VP9_PROFILE_H_ #ifndef MEDIA_BASE_VP9_PROFILE_H_
#define MEDIA_BASE_VP9_PROFILE_H_ #define MEDIA_BASE_VP9_PROFILE_H_
#include <string> #include "api/video_codecs/vp9_profile.h"
#include "absl/types/optional.h" // TODO(crbug.com/1187565): Remove this file once downstream projects stop
#include "api/video_codecs/sdp_video_format.h" // depend on it.
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
// Profile information for VP9 video.
extern RTC_EXPORT const char kVP9FmtpProfileId[];
enum class VP9Profile {
kProfile0,
kProfile1,
kProfile2,
};
// Helper functions to convert VP9Profile to std::string. Returns "0" by
// default.
RTC_EXPORT std::string VP9ProfileToString(VP9Profile profile);
// Helper functions to convert std::string to VP9Profile. Returns null if given
// an invalid profile string.
absl::optional<VP9Profile> StringToVP9Profile(const std::string& str);
// Parse profile that is represented as a string of single digit contained in an
// SDP key-value map. A default profile(kProfile0) will be returned if the
// profile key is missing. Nothing will be returned if the key is present but
// the string is invalid.
RTC_EXPORT absl::optional<VP9Profile> ParseSdpForVP9Profile(
const SdpVideoFormat::Parameters& params);
// Returns true if the parameters have the same VP9 profile, or neither contains
// VP9 profile.
bool IsSameVP9Profile(const SdpVideoFormat::Parameters& params1,
const SdpVideoFormat::Parameters& params2);
} // namespace webrtc
#endif // MEDIA_BASE_VP9_PROFILE_H_ #endif // MEDIA_BASE_VP9_PROFILE_H_

View File

@ -12,8 +12,8 @@
#include "api/video_codecs/sdp_video_format.h" #include "api/video_codecs/sdp_video_format.h"
#include "api/video_codecs/video_decoder.h" #include "api/video_codecs/video_decoder.h"
#include "api/video_codecs/vp9_profile.h"
#include "media/base/media_constants.h" #include "media/base/media_constants.h"
#include "media/base/vp9_profile.h"
#include "modules/video_coding/codecs/av1/libaom_av1_decoder.h" #include "modules/video_coding/codecs/av1/libaom_av1_decoder.h"
#include "test/gmock.h" #include "test/gmock.h"
#include "test/gtest.h" #include "test/gtest.h"

View File

@ -35,12 +35,12 @@
#include "api/video/video_bitrate_allocation.h" #include "api/video/video_bitrate_allocation.h"
#include "api/video_codecs/builtin_video_decoder_factory.h" #include "api/video_codecs/builtin_video_decoder_factory.h"
#include "api/video_codecs/builtin_video_encoder_factory.h" #include "api/video_codecs/builtin_video_encoder_factory.h"
#include "api/video_codecs/h264_profile_level_id.h"
#include "api/video_codecs/sdp_video_format.h" #include "api/video_codecs/sdp_video_format.h"
#include "api/video_codecs/video_decoder_factory.h" #include "api/video_codecs/video_decoder_factory.h"
#include "api/video_codecs/video_encoder.h" #include "api/video_codecs/video_encoder.h"
#include "api/video_codecs/video_encoder_factory.h" #include "api/video_codecs/video_encoder_factory.h"
#include "call/flexfec_receive_stream.h" #include "call/flexfec_receive_stream.h"
#include "common_video/h264/profile_level_id.h"
#include "media/base/fake_frame_source.h" #include "media/base/fake_frame_source.h"
#include "media/base/fake_network_interface.h" #include "media/base/fake_network_interface.h"
#include "media/base/fake_video_renderer.h" #include "media/base/fake_video_renderer.h"
@ -581,20 +581,21 @@ TEST_F(WebRtcVideoEngineTest, UseFactoryForVp8WhenSupported) {
// TODO(deadbeef): This test should be updated if/when we start // TODO(deadbeef): This test should be updated if/when we start
// adding RTX codecs for unrecognized codec names. // adding RTX codecs for unrecognized codec names.
TEST_F(WebRtcVideoEngineTest, RtxCodecAddedForH264Codec) { TEST_F(WebRtcVideoEngineTest, RtxCodecAddedForH264Codec) {
using webrtc::H264::kLevel1; using webrtc::H264Level;
using webrtc::H264::ProfileLevelId; using webrtc::H264Profile;
using webrtc::H264::ProfileLevelIdToString; using webrtc::H264ProfileLevelId;
using webrtc::H264ProfileLevelIdToString;
webrtc::SdpVideoFormat h264_constrained_baseline("H264"); webrtc::SdpVideoFormat h264_constrained_baseline("H264");
h264_constrained_baseline.parameters[kH264FmtpProfileLevelId] = h264_constrained_baseline.parameters[kH264FmtpProfileLevelId] =
*ProfileLevelIdToString( *H264ProfileLevelIdToString(H264ProfileLevelId(
ProfileLevelId(webrtc::H264::kProfileConstrainedBaseline, kLevel1)); H264Profile::kProfileConstrainedBaseline, H264Level::kLevel1));
webrtc::SdpVideoFormat h264_constrained_high("H264"); webrtc::SdpVideoFormat h264_constrained_high("H264");
h264_constrained_high.parameters[kH264FmtpProfileLevelId] = h264_constrained_high.parameters[kH264FmtpProfileLevelId] =
*ProfileLevelIdToString( *H264ProfileLevelIdToString(H264ProfileLevelId(
ProfileLevelId(webrtc::H264::kProfileConstrainedHigh, kLevel1)); H264Profile::kProfileConstrainedHigh, H264Level::kLevel1));
webrtc::SdpVideoFormat h264_high("H264"); webrtc::SdpVideoFormat h264_high("H264");
h264_high.parameters[kH264FmtpProfileLevelId] = *ProfileLevelIdToString( h264_high.parameters[kH264FmtpProfileLevelId] = *H264ProfileLevelIdToString(
ProfileLevelId(webrtc::H264::kProfileHigh, kLevel1)); H264ProfileLevelId(H264Profile::kProfileHigh, H264Level::kLevel1));
encoder_factory_->AddSupportedVideoCodec(h264_constrained_baseline); encoder_factory_->AddSupportedVideoCodec(h264_constrained_baseline);
encoder_factory_->AddSupportedVideoCodec(h264_constrained_high); encoder_factory_->AddSupportedVideoCodec(h264_constrained_high);
@ -721,10 +722,10 @@ size_t WebRtcVideoEngineTest::GetEngineCodecIndex(
// The tests only use H264 Constrained Baseline. Make sure we don't return // The tests only use H264 Constrained Baseline. Make sure we don't return
// an internal H264 codec from the engine with a different H264 profile. // an internal H264 codec from the engine with a different H264 profile.
if (absl::EqualsIgnoreCase(name.c_str(), kH264CodecName)) { if (absl::EqualsIgnoreCase(name.c_str(), kH264CodecName)) {
const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id = const absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
webrtc::H264::ParseSdpProfileLevelId(engine_codec.params); webrtc::ParseSdpForH264ProfileLevelId(engine_codec.params);
if (profile_level_id->profile != if (profile_level_id->profile !=
webrtc::H264::kProfileConstrainedBaseline) { webrtc::H264Profile::kProfileConstrainedBaseline) {
continue; continue;
} }
} }

View File

@ -592,7 +592,6 @@ rtc_library("webrtc_vp9") {
"../../api/video_codecs:video_codecs_api", "../../api/video_codecs:video_codecs_api",
"../../common_video", "../../common_video",
"../../media:rtc_media_base", "../../media:rtc_media_base",
"../../media:rtc_vp9_profile",
"../../rtc_base", "../../rtc_base",
"../../rtc_base:checks", "../../rtc_base:checks",
"../../rtc_base/experiments:encoder_info_settings", "../../rtc_base/experiments:encoder_info_settings",
@ -814,7 +813,6 @@ if (rtc_include_tests) {
"../../call:video_stream_api", "../../call:video_stream_api",
"../../common_video", "../../common_video",
"../../media:rtc_audio_video", "../../media:rtc_audio_video",
"../../media:rtc_h264_profile_id",
"../../media:rtc_internal_video_codecs", "../../media:rtc_internal_video_codecs",
"../../media:rtc_media_base", "../../media:rtc_media_base",
"../../rtc_base:checks", "../../rtc_base:checks",
@ -904,11 +902,9 @@ if (rtc_include_tests) {
"../../api/video_codecs:video_codecs_api", "../../api/video_codecs:video_codecs_api",
"../../common_video", "../../common_video",
"../../common_video/test:utilities", "../../common_video/test:utilities",
"../../media:rtc_h264_profile_id",
"../../media:rtc_internal_video_codecs", "../../media:rtc_internal_video_codecs",
"../../media:rtc_media_base", "../../media:rtc_media_base",
"../../media:rtc_simulcast_encoder_adapter", "../../media:rtc_simulcast_encoder_adapter",
"../../media:rtc_vp9_profile",
"../../rtc_base", "../../rtc_base",
"../../test:explicit_key_value_config", "../../test:explicit_key_value_config",
"../../test:field_trial", "../../test:field_trial",

View File

@ -45,11 +45,11 @@ bool IsH264CodecSupported() {
} // namespace } // namespace
SdpVideoFormat CreateH264Format(H264::Profile profile, SdpVideoFormat CreateH264Format(H264Profile profile,
H264::Level level, H264Level level,
const std::string& packetization_mode) { const std::string& packetization_mode) {
const absl::optional<std::string> profile_string = const absl::optional<std::string> profile_string =
H264::ProfileLevelIdToString(H264::ProfileLevelId(profile, level)); H264ProfileLevelIdToString(H264ProfileLevelId(profile, level));
RTC_CHECK(profile_string); RTC_CHECK(profile_string);
return SdpVideoFormat( return SdpVideoFormat(
cricket::kH264CodecName, cricket::kH264CodecName,
@ -76,12 +76,14 @@ std::vector<SdpVideoFormat> SupportedH264Codecs() {
// //
// We support both packetization modes 0 (mandatory) and 1 (optional, // We support both packetization modes 0 (mandatory) and 1 (optional,
// preferred). // preferred).
return { return {CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1,
CreateH264Format(H264::kProfileBaseline, H264::kLevel3_1, "1"), "1"),
CreateH264Format(H264::kProfileBaseline, H264::kLevel3_1, "0"), CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1,
CreateH264Format(H264::kProfileConstrainedBaseline, H264::kLevel3_1, "1"), "0"),
CreateH264Format(H264::kProfileConstrainedBaseline, H264::kLevel3_1, CreateH264Format(H264Profile::kProfileConstrainedBaseline,
"0")}; H264Level::kLevel3_1, "1"),
CreateH264Format(H264Profile::kProfileConstrainedBaseline,
H264Level::kLevel3_1, "0")};
} }
std::unique_ptr<H264Encoder> H264Encoder::Create( std::unique_ptr<H264Encoder> H264Encoder::Create(

View File

@ -27,8 +27,8 @@ struct SdpVideoFormat;
// Creates an H264 SdpVideoFormat entry with specified paramters. // Creates an H264 SdpVideoFormat entry with specified paramters.
RTC_EXPORT SdpVideoFormat RTC_EXPORT SdpVideoFormat
CreateH264Format(H264::Profile profile, CreateH264Format(H264Profile profile,
H264::Level level, H264Level level,
const std::string& packetization_mode); const std::string& packetization_mode);
// Set to disable the H.264 encoder/decoder implementations that are provided if // Set to disable the H.264 encoder/decoder implementations that are provided if

View File

@ -25,12 +25,12 @@
#include "api/array_view.h" #include "api/array_view.h"
#include "api/transport/field_trial_based_config.h" #include "api/transport/field_trial_based_config.h"
#include "api/video/video_bitrate_allocation.h" #include "api/video/video_bitrate_allocation.h"
#include "api/video_codecs/h264_profile_level_id.h"
#include "api/video_codecs/sdp_video_format.h" #include "api/video_codecs/sdp_video_format.h"
#include "api/video_codecs/video_codec.h" #include "api/video_codecs/video_codec.h"
#include "api/video_codecs/video_decoder.h" #include "api/video_codecs/video_decoder.h"
#include "api/video_codecs/video_encoder_config.h" #include "api/video_codecs/video_encoder_config.h"
#include "common_video/h264/h264_common.h" #include "common_video/h264/h264_common.h"
#include "media/base/h264_profile_level_id.h"
#include "media/base/media_constants.h" #include "media/base/media_constants.h"
#include "media/engine/internal_decoder_factory.h" #include "media/engine/internal_decoder_factory.h"
#include "media/engine/internal_encoder_factory.h" #include "media/engine/internal_encoder_factory.h"
@ -302,11 +302,11 @@ std::string VideoCodecTestFixtureImpl::Config::CodecName() const {
name = CodecTypeToPayloadString(codec_settings.codecType); name = CodecTypeToPayloadString(codec_settings.codecType);
} }
if (codec_settings.codecType == kVideoCodecH264) { if (codec_settings.codecType == kVideoCodecH264) {
if (h264_codec_settings.profile == H264::kProfileConstrainedHigh) { if (h264_codec_settings.profile == H264Profile::kProfileConstrainedHigh) {
return name + "-CHP"; return name + "-CHP";
} else { } else {
RTC_DCHECK_EQ(h264_codec_settings.profile, RTC_DCHECK_EQ(h264_codec_settings.profile,
H264::kProfileConstrainedBaseline); H264Profile::kProfileConstrainedBaseline);
return name + "-CBP"; return name + "-CBP";
} }
} }
@ -613,8 +613,8 @@ bool VideoCodecTestFixtureImpl::CreateEncoderAndDecoder() {
? "1" ? "1"
: "0"; : "0";
params = {{cricket::kH264FmtpProfileLevelId, params = {{cricket::kH264FmtpProfileLevelId,
*H264::ProfileLevelIdToString(H264::ProfileLevelId( *H264ProfileLevelIdToString(H264ProfileLevelId(
config_.h264_codec_settings.profile, H264::kLevel3_1))}, config_.h264_codec_settings.profile, H264Level::kLevel3_1))},
{cricket::kH264FmtpPacketizationMode, packetization_mode}}; {cricket::kH264FmtpPacketizationMode, packetization_mode}};
} else { } else {
params = {}; params = {};

View File

@ -95,7 +95,7 @@ TEST(VideoCodecTestMediaCodec, DISABLED_ForemanCif500kbpsH264CHP) {
const auto frame_checker = const auto frame_checker =
std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>(); std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>();
config.h264_codec_settings.profile = H264::kProfileConstrainedHigh; config.h264_codec_settings.profile = H264Profile::kProfileConstrainedHigh;
config.encoded_frame_checker = frame_checker.get(); config.encoded_frame_checker = frame_checker.get();
config.SetCodecSettings(cricket::kH264CodecName, 1, 1, 1, false, false, false, config.SetCodecSettings(cricket::kH264CodecName, 1, 1, 1, false, false, false,
352, 288); 352, 288);

View File

@ -71,7 +71,7 @@ MAYBE_TEST(VideoCodecTestVideoToolbox, ForemanCif500kbpsH264CHP) {
const auto frame_checker = const auto frame_checker =
std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>(); std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>();
auto config = CreateConfig(); auto config = CreateConfig();
config.h264_codec_settings.profile = H264::kProfileConstrainedHigh; config.h264_codec_settings.profile = H264Profile::kProfileConstrainedHigh;
config.SetCodecSettings(cricket::kH264CodecName, 1, 1, 1, false, false, false, config.SetCodecSettings(cricket::kH264CodecName, 1, 1, 1, false, false, false,
352, 288); 352, 288);
config.encoded_frame_checker = frame_checker.get(); config.encoded_frame_checker = frame_checker.get();

View File

@ -21,8 +21,8 @@
#include "api/fec_controller_override.h" #include "api/fec_controller_override.h"
#include "api/transport/webrtc_key_value_config.h" #include "api/transport/webrtc_key_value_config.h"
#include "api/video_codecs/video_encoder.h" #include "api/video_codecs/video_encoder.h"
#include "api/video_codecs/vp9_profile.h"
#include "common_video/include/video_frame_buffer_pool.h" #include "common_video/include/video_frame_buffer_pool.h"
#include "media/base/vp9_profile.h"
#include "modules/video_coding/codecs/interface/libvpx_interface.h" #include "modules/video_coding/codecs/interface/libvpx_interface.h"
#include "modules/video_coding/codecs/vp9/include/vp9.h" #include "modules/video_coding/codecs/vp9/include/vp9.h"
#include "modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h" #include "modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h"

View File

@ -15,8 +15,8 @@
#include "api/video/color_space.h" #include "api/video/color_space.h"
#include "api/video/i420_buffer.h" #include "api/video/i420_buffer.h"
#include "api/video_codecs/video_encoder.h" #include "api/video_codecs/video_encoder.h"
#include "api/video_codecs/vp9_profile.h"
#include "common_video/libyuv/include/webrtc_libyuv.h" #include "common_video/libyuv/include/webrtc_libyuv.h"
#include "media/base/vp9_profile.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/video_coding/codecs/interface/libvpx_interface.h" #include "modules/video_coding/codecs/interface/libvpx_interface.h"
#include "modules/video_coding/codecs/interface/mock_libvpx_interface.h" #include "modules/video_coding/codecs/interface/mock_libvpx_interface.h"

View File

@ -14,7 +14,7 @@
#include "api/transport/field_trial_based_config.h" #include "api/transport/field_trial_based_config.h"
#include "api/video_codecs/sdp_video_format.h" #include "api/video_codecs/sdp_video_format.h"
#include "media/base/vp9_profile.h" #include "api/video_codecs/vp9_profile.h"
#include "modules/video_coding/codecs/vp9/libvpx_vp9_decoder.h" #include "modules/video_coding/codecs/vp9/libvpx_vp9_decoder.h"
#include "modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h" #include "modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"

View File

@ -102,6 +102,7 @@ rtc_library("rtc_pc_base") {
"../api/video:video_bitrate_allocator_factory", "../api/video:video_bitrate_allocator_factory",
"../api/video:video_frame", "../api/video:video_frame",
"../api/video:video_rtp_headers", "../api/video:video_rtp_headers",
"../api/video_codecs:video_codecs_api",
"../call:call_interfaces", "../call:call_interfaces",
"../call:rtp_interfaces", "../call:rtp_interfaces",
"../call:rtp_receiver", "../call:rtp_receiver",
@ -109,9 +110,9 @@ rtc_library("rtc_pc_base") {
"../common_video:common_video", "../common_video:common_video",
"../logging:ice_log", "../logging:ice_log",
"../media:rtc_data_sctp_transport_internal", "../media:rtc_data_sctp_transport_internal",
"../media:rtc_h264_profile_id",
"../media:rtc_media_base", "../media:rtc_media_base",
"../media:rtc_media_config", "../media:rtc_media_config",
"../media:rtc_sdp_video_format_utils",
"../modules/rtp_rtcp:rtp_rtcp", "../modules/rtp_rtcp:rtp_rtcp",
"../modules/rtp_rtcp:rtp_rtcp_format", "../modules/rtp_rtcp:rtp_rtcp_format",
"../p2p:rtc_p2p", "../p2p:rtc_p2p",

View File

@ -24,9 +24,10 @@
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "api/crypto_params.h" #include "api/crypto_params.h"
#include "api/video_codecs/h264_profile_level_id.h"
#include "media/base/codec.h" #include "media/base/codec.h"
#include "media/base/h264_profile_level_id.h"
#include "media/base/media_constants.h" #include "media/base/media_constants.h"
#include "media/base/sdp_video_format_utils.h"
#include "media/sctp/sctp_transport_internal.h" #include "media/sctp/sctp_transport_internal.h"
#include "p2p/base/p2p_constants.h" #include "p2p/base/p2p_constants.h"
#include "pc/channel_manager.h" #include "pc/channel_manager.h"
@ -801,8 +802,8 @@ static void NegotiateCodecs(const std::vector<C>& local_codecs,
} }
} }
if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) { if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
webrtc::H264::GenerateProfileLevelIdForAnswer( webrtc::H264GenerateProfileLevelIdForAnswer(ours.params, theirs.params,
ours.params, theirs.params, &negotiated.params); &negotiated.params);
} }
negotiated.id = theirs.id; negotiated.id = theirs.id;
negotiated.name = theirs.name; negotiated.name = theirs.name;

View File

@ -1655,6 +1655,7 @@ if (is_ios || is_mac) {
":video_toolbox_cc", ":video_toolbox_cc",
":videocodec_objc", ":videocodec_objc",
":videoframebuffer_objc", ":videoframebuffer_objc",
"../api/video_codecs:video_codecs_api",
"../common_video", "../common_video",
"../modules/video_coding:video_codec_interface", "../modules/video_coding:video_codec_interface",
"../rtc_base:checks", "../rtc_base:checks",

View File

@ -8,10 +8,9 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "sdk/android/src/jni/video_codec_info.h" #include "api/video_codecs/h264_profile_level_id.h"
#include "common_video/h264/profile_level_id.h"
#include "sdk/android/generated_video_jni/H264Utils_jni.h" #include "sdk/android/generated_video_jni/H264Utils_jni.h"
#include "sdk/android/src/jni/video_codec_info.h"
namespace webrtc { namespace webrtc {
namespace jni { namespace jni {
@ -20,7 +19,7 @@ static jboolean JNI_H264Utils_IsSameH264Profile(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jobject>& params1, const JavaParamRef<jobject>& params1,
const JavaParamRef<jobject>& params2) { const JavaParamRef<jobject>& params2) {
return H264::IsSameH264Profile(JavaToNativeStringMap(env, params1), return H264IsSameProfile(JavaToNativeStringMap(env, params1),
JavaToNativeStringMap(env, params2)); JavaToNativeStringMap(env, params2));
} }

View File

@ -16,7 +16,7 @@
#import "UIDevice+H264Profile.h" #import "UIDevice+H264Profile.h"
#endif #endif
#include "media/base/h264_profile_level_id.h" #include "api/video_codecs/h264_profile_level_id.h"
#include "media/base/media_constants.h" #include "media/base/media_constants.h"
namespace { namespace {
@ -38,13 +38,12 @@ namespace {
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
using namespace webrtc::H264; NSString *MaxSupportedLevelForProfile(webrtc::H264Profile profile) {
const absl::optional<webrtc::H264ProfileLevelId> profileLevelId =
NSString *MaxSupportedLevelForProfile(Profile profile) { [UIDevice maxSupportedH264Profile];
const absl::optional<ProfileLevelId> profileLevelId = [UIDevice maxSupportedH264Profile];
if (profileLevelId && profileLevelId->profile >= profile) { if (profileLevelId && profileLevelId->profile >= profile) {
const absl::optional<std::string> profileString = const absl::optional<std::string> profileString =
ProfileLevelIdToString(ProfileLevelId(profile, profileLevelId->level)); H264ProfileLevelIdToString(webrtc::H264ProfileLevelId(profile, profileLevelId->level));
if (profileString) { if (profileString) {
return [NSString stringForStdString:*profileString]; return [NSString stringForStdString:*profileString];
} }
@ -55,7 +54,7 @@ NSString *MaxSupportedLevelForProfile(Profile profile) {
NSString *MaxSupportedProfileLevelConstrainedBaseline() { NSString *MaxSupportedProfileLevelConstrainedBaseline() {
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
NSString *profile = MaxSupportedLevelForProfile(webrtc::H264::kProfileConstrainedBaseline); NSString *profile = MaxSupportedLevelForProfile(webrtc::H264Profile::kProfileConstrainedBaseline);
if (profile != nil) { if (profile != nil) {
return profile; return profile;
} }
@ -65,7 +64,7 @@ NSString *MaxSupportedProfileLevelConstrainedBaseline() {
NSString *MaxSupportedProfileLevelConstrainedHigh() { NSString *MaxSupportedProfileLevelConstrainedHigh() {
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
NSString *profile = MaxSupportedLevelForProfile(webrtc::H264::kProfileConstrainedHigh); NSString *profile = MaxSupportedLevelForProfile(webrtc::H264Profile::kProfileConstrainedHigh);
if (profile != nil) { if (profile != nil) {
return profile; return profile;
} }
@ -94,8 +93,8 @@ NSString *MaxSupportedProfileLevelConstrainedHigh() {
if (self = [super init]) { if (self = [super init]) {
self.hexString = hexString; self.hexString = hexString;
absl::optional<webrtc::H264::ProfileLevelId> profile_level_id = absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
webrtc::H264::ParseProfileLevelId([hexString cStringUsingEncoding:NSUTF8StringEncoding]); webrtc::ParseH264ProfileLevelId([hexString cStringUsingEncoding:NSUTF8StringEncoding]);
if (profile_level_id.has_value()) { if (profile_level_id.has_value()) {
self.profile = static_cast<RTCH264Profile>(profile_level_id->profile); self.profile = static_cast<RTCH264Profile>(profile_level_id->profile);
self.level = static_cast<RTCH264Level>(profile_level_id->level); self.level = static_cast<RTCH264Level>(profile_level_id->level);
@ -110,8 +109,8 @@ NSString *MaxSupportedProfileLevelConstrainedHigh() {
self.level = level; self.level = level;
absl::optional<std::string> hex_string = absl::optional<std::string> hex_string =
webrtc::H264::ProfileLevelIdToString(webrtc::H264::ProfileLevelId( webrtc::H264ProfileLevelIdToString(webrtc::H264ProfileLevelId(
static_cast<webrtc::H264::Profile>(profile), static_cast<webrtc::H264::Level>(level))); static_cast<webrtc::H264Profile>(profile), static_cast<webrtc::H264Level>(level)));
self.hexString = self.hexString =
[NSString stringWithCString:hex_string.value_or("").c_str() encoding:NSUTF8StringEncoding]; [NSString stringWithCString:hex_string.value_or("").c_str() encoding:NSUTF8StringEncoding];
} }

View File

@ -28,8 +28,8 @@
#import "components/video_frame_buffer/RTCCVPixelBuffer.h" #import "components/video_frame_buffer/RTCCVPixelBuffer.h"
#import "helpers.h" #import "helpers.h"
#include "api/video_codecs/h264_profile_level_id.h"
#include "common_video/h264/h264_bitstream_parser.h" #include "common_video/h264/h264_bitstream_parser.h"
#include "common_video/h264/profile_level_id.h"
#include "common_video/include/bitrate_adjuster.h" #include "common_video/include/bitrate_adjuster.h"
#include "modules/video_coding/include/video_error_codes.h" #include "modules/video_coding/include/video_error_codes.h"
#include "rtc_base/buffer.h" #include "rtc_base/buffer.h"
@ -173,100 +173,100 @@ void compressionOutputCallback(void *encoder,
// no specific VideoToolbox profile for the specified level, AutoLevel will be // no specific VideoToolbox profile for the specified level, AutoLevel will be
// returned. The user must initialize the encoder with a resolution and // returned. The user must initialize the encoder with a resolution and
// framerate conforming to the selected H264 level regardless. // framerate conforming to the selected H264 level regardless.
CFStringRef ExtractProfile(const webrtc::H264::ProfileLevelId &profile_level_id) { CFStringRef ExtractProfile(const webrtc::H264ProfileLevelId &profile_level_id) {
switch (profile_level_id.profile) { switch (profile_level_id.profile) {
case webrtc::H264::kProfileConstrainedBaseline: case webrtc::H264Profile::kProfileConstrainedBaseline:
case webrtc::H264::kProfileBaseline: case webrtc::H264Profile::kProfileBaseline:
switch (profile_level_id.level) { switch (profile_level_id.level) {
case webrtc::H264::kLevel3: case webrtc::H264Level::kLevel3:
return kVTProfileLevel_H264_Baseline_3_0; return kVTProfileLevel_H264_Baseline_3_0;
case webrtc::H264::kLevel3_1: case webrtc::H264Level::kLevel3_1:
return kVTProfileLevel_H264_Baseline_3_1; return kVTProfileLevel_H264_Baseline_3_1;
case webrtc::H264::kLevel3_2: case webrtc::H264Level::kLevel3_2:
return kVTProfileLevel_H264_Baseline_3_2; return kVTProfileLevel_H264_Baseline_3_2;
case webrtc::H264::kLevel4: case webrtc::H264Level::kLevel4:
return kVTProfileLevel_H264_Baseline_4_0; return kVTProfileLevel_H264_Baseline_4_0;
case webrtc::H264::kLevel4_1: case webrtc::H264Level::kLevel4_1:
return kVTProfileLevel_H264_Baseline_4_1; return kVTProfileLevel_H264_Baseline_4_1;
case webrtc::H264::kLevel4_2: case webrtc::H264Level::kLevel4_2:
return kVTProfileLevel_H264_Baseline_4_2; return kVTProfileLevel_H264_Baseline_4_2;
case webrtc::H264::kLevel5: case webrtc::H264Level::kLevel5:
return kVTProfileLevel_H264_Baseline_5_0; return kVTProfileLevel_H264_Baseline_5_0;
case webrtc::H264::kLevel5_1: case webrtc::H264Level::kLevel5_1:
return kVTProfileLevel_H264_Baseline_5_1; return kVTProfileLevel_H264_Baseline_5_1;
case webrtc::H264::kLevel5_2: case webrtc::H264Level::kLevel5_2:
return kVTProfileLevel_H264_Baseline_5_2; return kVTProfileLevel_H264_Baseline_5_2;
case webrtc::H264::kLevel1: case webrtc::H264Level::kLevel1:
case webrtc::H264::kLevel1_b: case webrtc::H264Level::kLevel1_b:
case webrtc::H264::kLevel1_1: case webrtc::H264Level::kLevel1_1:
case webrtc::H264::kLevel1_2: case webrtc::H264Level::kLevel1_2:
case webrtc::H264::kLevel1_3: case webrtc::H264Level::kLevel1_3:
case webrtc::H264::kLevel2: case webrtc::H264Level::kLevel2:
case webrtc::H264::kLevel2_1: case webrtc::H264Level::kLevel2_1:
case webrtc::H264::kLevel2_2: case webrtc::H264Level::kLevel2_2:
return kVTProfileLevel_H264_Baseline_AutoLevel; return kVTProfileLevel_H264_Baseline_AutoLevel;
} }
case webrtc::H264::kProfileMain: case webrtc::H264Profile::kProfileMain:
switch (profile_level_id.level) { switch (profile_level_id.level) {
case webrtc::H264::kLevel3: case webrtc::H264Level::kLevel3:
return kVTProfileLevel_H264_Main_3_0; return kVTProfileLevel_H264_Main_3_0;
case webrtc::H264::kLevel3_1: case webrtc::H264Level::kLevel3_1:
return kVTProfileLevel_H264_Main_3_1; return kVTProfileLevel_H264_Main_3_1;
case webrtc::H264::kLevel3_2: case webrtc::H264Level::kLevel3_2:
return kVTProfileLevel_H264_Main_3_2; return kVTProfileLevel_H264_Main_3_2;
case webrtc::H264::kLevel4: case webrtc::H264Level::kLevel4:
return kVTProfileLevel_H264_Main_4_0; return kVTProfileLevel_H264_Main_4_0;
case webrtc::H264::kLevel4_1: case webrtc::H264Level::kLevel4_1:
return kVTProfileLevel_H264_Main_4_1; return kVTProfileLevel_H264_Main_4_1;
case webrtc::H264::kLevel4_2: case webrtc::H264Level::kLevel4_2:
return kVTProfileLevel_H264_Main_4_2; return kVTProfileLevel_H264_Main_4_2;
case webrtc::H264::kLevel5: case webrtc::H264Level::kLevel5:
return kVTProfileLevel_H264_Main_5_0; return kVTProfileLevel_H264_Main_5_0;
case webrtc::H264::kLevel5_1: case webrtc::H264Level::kLevel5_1:
return kVTProfileLevel_H264_Main_5_1; return kVTProfileLevel_H264_Main_5_1;
case webrtc::H264::kLevel5_2: case webrtc::H264Level::kLevel5_2:
return kVTProfileLevel_H264_Main_5_2; return kVTProfileLevel_H264_Main_5_2;
case webrtc::H264::kLevel1: case webrtc::H264Level::kLevel1:
case webrtc::H264::kLevel1_b: case webrtc::H264Level::kLevel1_b:
case webrtc::H264::kLevel1_1: case webrtc::H264Level::kLevel1_1:
case webrtc::H264::kLevel1_2: case webrtc::H264Level::kLevel1_2:
case webrtc::H264::kLevel1_3: case webrtc::H264Level::kLevel1_3:
case webrtc::H264::kLevel2: case webrtc::H264Level::kLevel2:
case webrtc::H264::kLevel2_1: case webrtc::H264Level::kLevel2_1:
case webrtc::H264::kLevel2_2: case webrtc::H264Level::kLevel2_2:
return kVTProfileLevel_H264_Main_AutoLevel; return kVTProfileLevel_H264_Main_AutoLevel;
} }
case webrtc::H264::kProfileConstrainedHigh: case webrtc::H264Profile::kProfileConstrainedHigh:
case webrtc::H264::kProfileHigh: case webrtc::H264Profile::kProfileHigh:
switch (profile_level_id.level) { switch (profile_level_id.level) {
case webrtc::H264::kLevel3: case webrtc::H264Level::kLevel3:
return kVTProfileLevel_H264_High_3_0; return kVTProfileLevel_H264_High_3_0;
case webrtc::H264::kLevel3_1: case webrtc::H264Level::kLevel3_1:
return kVTProfileLevel_H264_High_3_1; return kVTProfileLevel_H264_High_3_1;
case webrtc::H264::kLevel3_2: case webrtc::H264Level::kLevel3_2:
return kVTProfileLevel_H264_High_3_2; return kVTProfileLevel_H264_High_3_2;
case webrtc::H264::kLevel4: case webrtc::H264Level::kLevel4:
return kVTProfileLevel_H264_High_4_0; return kVTProfileLevel_H264_High_4_0;
case webrtc::H264::kLevel4_1: case webrtc::H264Level::kLevel4_1:
return kVTProfileLevel_H264_High_4_1; return kVTProfileLevel_H264_High_4_1;
case webrtc::H264::kLevel4_2: case webrtc::H264Level::kLevel4_2:
return kVTProfileLevel_H264_High_4_2; return kVTProfileLevel_H264_High_4_2;
case webrtc::H264::kLevel5: case webrtc::H264Level::kLevel5:
return kVTProfileLevel_H264_High_5_0; return kVTProfileLevel_H264_High_5_0;
case webrtc::H264::kLevel5_1: case webrtc::H264Level::kLevel5_1:
return kVTProfileLevel_H264_High_5_1; return kVTProfileLevel_H264_High_5_1;
case webrtc::H264::kLevel5_2: case webrtc::H264Level::kLevel5_2:
return kVTProfileLevel_H264_High_5_2; return kVTProfileLevel_H264_High_5_2;
case webrtc::H264::kLevel1: case webrtc::H264Level::kLevel1:
case webrtc::H264::kLevel1_b: case webrtc::H264Level::kLevel1_b:
case webrtc::H264::kLevel1_1: case webrtc::H264Level::kLevel1_1:
case webrtc::H264::kLevel1_2: case webrtc::H264Level::kLevel1_2:
case webrtc::H264::kLevel1_3: case webrtc::H264Level::kLevel1_3:
case webrtc::H264::kLevel2: case webrtc::H264Level::kLevel2:
case webrtc::H264::kLevel2_1: case webrtc::H264Level::kLevel2_1:
case webrtc::H264::kLevel2_2: case webrtc::H264Level::kLevel2_2:
return kVTProfileLevel_H264_High_AutoLevel; return kVTProfileLevel_H264_High_AutoLevel;
} }
} }
@ -276,33 +276,33 @@ CFStringRef ExtractProfile(const webrtc::H264::ProfileLevelId &profile_level_id)
// can be processed by given encoder with |profile_level_id|. // can be processed by given encoder with |profile_level_id|.
// See https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.264-201610-S!!PDF-E&type=items // See https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.264-201610-S!!PDF-E&type=items
// for details. // for details.
NSUInteger GetMaxSampleRate(const webrtc::H264::ProfileLevelId &profile_level_id) { NSUInteger GetMaxSampleRate(const webrtc::H264ProfileLevelId &profile_level_id) {
switch (profile_level_id.level) { switch (profile_level_id.level) {
case webrtc::H264::kLevel3: case webrtc::H264Level::kLevel3:
return 10368000; return 10368000;
case webrtc::H264::kLevel3_1: case webrtc::H264Level::kLevel3_1:
return 27648000; return 27648000;
case webrtc::H264::kLevel3_2: case webrtc::H264Level::kLevel3_2:
return 55296000; return 55296000;
case webrtc::H264::kLevel4: case webrtc::H264Level::kLevel4:
case webrtc::H264::kLevel4_1: case webrtc::H264Level::kLevel4_1:
return 62914560; return 62914560;
case webrtc::H264::kLevel4_2: case webrtc::H264Level::kLevel4_2:
return 133693440; return 133693440;
case webrtc::H264::kLevel5: case webrtc::H264Level::kLevel5:
return 150994944; return 150994944;
case webrtc::H264::kLevel5_1: case webrtc::H264Level::kLevel5_1:
return 251658240; return 251658240;
case webrtc::H264::kLevel5_2: case webrtc::H264Level::kLevel5_2:
return 530841600; return 530841600;
case webrtc::H264::kLevel1: case webrtc::H264Level::kLevel1:
case webrtc::H264::kLevel1_b: case webrtc::H264Level::kLevel1_b:
case webrtc::H264::kLevel1_1: case webrtc::H264Level::kLevel1_1:
case webrtc::H264::kLevel1_2: case webrtc::H264Level::kLevel1_2:
case webrtc::H264::kLevel1_3: case webrtc::H264Level::kLevel1_3:
case webrtc::H264::kLevel2: case webrtc::H264Level::kLevel2:
case webrtc::H264::kLevel2_1: case webrtc::H264Level::kLevel2_1:
case webrtc::H264::kLevel2_2: case webrtc::H264Level::kLevel2_2:
// Zero means auto rate setting. // Zero means auto rate setting.
return 0; return 0;
} }
@ -317,7 +317,7 @@ NSUInteger GetMaxSampleRate(const webrtc::H264::ProfileLevelId &profile_level_id
uint32_t _encoderFrameRate; uint32_t _encoderFrameRate;
uint32_t _maxAllowedFrameRate; uint32_t _maxAllowedFrameRate;
RTCH264PacketizationMode _packetizationMode; RTCH264PacketizationMode _packetizationMode;
absl::optional<webrtc::H264::ProfileLevelId> _profile_level_id; absl::optional<webrtc::H264ProfileLevelId> _profile_level_id;
RTCVideoEncoderCallback _callback; RTCVideoEncoderCallback _callback;
int32_t _width; int32_t _width;
int32_t _height; int32_t _height;
@ -342,7 +342,7 @@ NSUInteger GetMaxSampleRate(const webrtc::H264::ProfileLevelId &profile_level_id
_bitrateAdjuster.reset(new webrtc::BitrateAdjuster(.5, .95)); _bitrateAdjuster.reset(new webrtc::BitrateAdjuster(.5, .95));
_packetizationMode = RTCH264PacketizationModeNonInterleaved; _packetizationMode = RTCH264PacketizationModeNonInterleaved;
_profile_level_id = _profile_level_id =
webrtc::H264::ParseSdpProfileLevelId([codecInfo nativeSdpVideoFormat].parameters); webrtc::ParseSdpForH264ProfileLevelId([codecInfo nativeSdpVideoFormat].parameters);
RTC_DCHECK(_profile_level_id); RTC_DCHECK(_profile_level_id);
RTC_LOG(LS_INFO) << "Using profile " << CFStringToString(ExtractProfile(*_profile_level_id)); RTC_LOG(LS_INFO) << "Using profile " << CFStringToString(ExtractProfile(*_profile_level_id));
RTC_CHECK([codecInfo.name isEqualToString:kRTCVideoCodecH264Name]); RTC_CHECK([codecInfo.name isEqualToString:kRTCVideoCodecH264Name]);

View File

@ -10,10 +10,10 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#include "media/base/h264_profile_level_id.h" #include "api/video_codecs/h264_profile_level_id.h"
@interface UIDevice (H264Profile) @interface UIDevice (H264Profile)
+ (absl::optional<webrtc::H264::ProfileLevelId>)maxSupportedH264Profile; + (absl::optional<webrtc::H264ProfileLevelId>)maxSupportedH264Profile;
@end @end

View File

@ -15,99 +15,156 @@
namespace { namespace {
using namespace webrtc::H264; using namespace webrtc;
struct SupportedH264Profile { struct SupportedH264Profile {
const RTCDeviceType deviceType; const RTCDeviceType deviceType;
const ProfileLevelId profile; const H264ProfileLevelId profile;
}; };
constexpr SupportedH264Profile kH264MaxSupportedProfiles[] = { constexpr SupportedH264Profile kH264MaxSupportedProfiles[] = {
// iPhones with at least iOS 9 // iPhones with at least iOS 9
{RTCDeviceTypeIPhone12ProMax, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP832 {RTCDeviceTypeIPhone12ProMax,
{RTCDeviceTypeIPhone12Pro, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP831 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP832
{RTCDeviceTypeIPhone12, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP830 {RTCDeviceTypeIPhone12Pro,
{RTCDeviceTypeIPhone12Mini, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP829 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP831
{RTCDeviceTypeIPhone11ProMax, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP806 {RTCDeviceTypeIPhone12,
{RTCDeviceTypeIPhone11Pro, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP805 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP830
{RTCDeviceTypeIPhone11, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP804 {RTCDeviceTypeIPhone12Mini,
{RTCDeviceTypeIPhoneXS, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP779 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP829
{RTCDeviceTypeIPhoneXSMax, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP780 {RTCDeviceTypeIPhone11ProMax,
{RTCDeviceTypeIPhoneXR, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP781 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP806
{RTCDeviceTypeIPhoneX, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP770 {RTCDeviceTypeIPhone11Pro,
{RTCDeviceTypeIPhone8, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP767 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP805
{RTCDeviceTypeIPhone8Plus, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP768 {RTCDeviceTypeIPhone11,
{RTCDeviceTypeIPhone7, {kProfileHigh, kLevel5_1}}, // https://support.apple.com/kb/SP743 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP804
{RTCDeviceTypeIPhone7Plus, {kProfileHigh, kLevel5_1}}, // https://support.apple.com/kb/SP744 {RTCDeviceTypeIPhoneXS,
{RTCDeviceTypeIPhoneSE, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP738 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP779
{RTCDeviceTypeIPhone6S, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP726 {RTCDeviceTypeIPhoneXSMax,
{RTCDeviceTypeIPhone6SPlus, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP727 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP780
{RTCDeviceTypeIPhone6, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP705 {RTCDeviceTypeIPhoneXR,
{RTCDeviceTypeIPhone6Plus, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP706 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP781
{RTCDeviceTypeIPhone5SGSM, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP685 {RTCDeviceTypeIPhoneX,
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP770
{RTCDeviceTypeIPhone8,
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP767
{RTCDeviceTypeIPhone8Plus,
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP768
{RTCDeviceTypeIPhone7,
{H264Profile::kProfileHigh, H264Level::kLevel5_1}}, // https://support.apple.com/kb/SP743
{RTCDeviceTypeIPhone7Plus,
{H264Profile::kProfileHigh, H264Level::kLevel5_1}}, // https://support.apple.com/kb/SP744
{RTCDeviceTypeIPhoneSE,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP738
{RTCDeviceTypeIPhone6S,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP726
{RTCDeviceTypeIPhone6SPlus,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP727
{RTCDeviceTypeIPhone6,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP705
{RTCDeviceTypeIPhone6Plus,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP706
{RTCDeviceTypeIPhone5SGSM,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP685
{RTCDeviceTypeIPhone5SGSM_CDMA, {RTCDeviceTypeIPhone5SGSM_CDMA,
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP685 {H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP685
{RTCDeviceTypeIPhone5GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP655 {RTCDeviceTypeIPhone5GSM,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP655
{RTCDeviceTypeIPhone5GSM_CDMA, {RTCDeviceTypeIPhone5GSM_CDMA,
{kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP655 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP655
{RTCDeviceTypeIPhone5CGSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP684 {RTCDeviceTypeIPhone5CGSM,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP684
{RTCDeviceTypeIPhone5CGSM_CDMA, {RTCDeviceTypeIPhone5CGSM_CDMA,
{kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP684 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP684
{RTCDeviceTypeIPhone4S, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP643 {RTCDeviceTypeIPhone4S,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP643
// iPods with at least iOS 9 // iPods with at least iOS 9
{RTCDeviceTypeIPodTouch7G, {kProfileMain, kLevel4_1}}, // https://support.apple.com/kb/SP796 {RTCDeviceTypeIPodTouch7G,
{RTCDeviceTypeIPodTouch6G, {kProfileMain, kLevel4_1}}, // https://support.apple.com/kb/SP720 {H264Profile::kProfileMain, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP796
{RTCDeviceTypeIPodTouch5G, {kProfileMain, kLevel3_1}}, // https://support.apple.com/kb/SP657 {RTCDeviceTypeIPodTouch6G,
{H264Profile::kProfileMain, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP720
{RTCDeviceTypeIPodTouch5G,
{H264Profile::kProfileMain, H264Level::kLevel3_1}}, // https://support.apple.com/kb/SP657
// iPads with at least iOS 9 // iPads with at least iOS 9
{RTCDeviceTypeIPadAir4Gen, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP828 {RTCDeviceTypeIPadAir4Gen,
{RTCDeviceTypeIPad8, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP822 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP828
{RTCDeviceTypeIPadPro4Gen12Inch, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP815 {RTCDeviceTypeIPad8,
{RTCDeviceTypeIPadPro4Gen11Inch, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP814 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP822
{RTCDeviceTypeIPadAir3Gen, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP787 {RTCDeviceTypeIPadPro4Gen12Inch,
{RTCDeviceTypeIPadMini5Gen, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP788 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP815
{RTCDeviceTypeIPadPro4Gen11Inch,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP814
{RTCDeviceTypeIPadAir3Gen,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP787
{RTCDeviceTypeIPadMini5Gen,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP788
{RTCDeviceTypeIPadPro3Gen12Inch, {RTCDeviceTypeIPadPro3Gen12Inch,
{kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP785 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP785
{RTCDeviceTypeIPadPro3Gen11Inch, {RTCDeviceTypeIPadPro3Gen11Inch,
{kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP784 {H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP784
{RTCDeviceTypeIPad7Gen10Inch, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP807 {RTCDeviceTypeIPad7Gen10Inch,
{RTCDeviceTypeIPad2Wifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP807
{RTCDeviceTypeIPad2GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622 {RTCDeviceTypeIPad2Wifi,
{RTCDeviceTypeIPad2CDMA, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP622
{RTCDeviceTypeIPad2Wifi2, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622 {RTCDeviceTypeIPad2GSM,
{RTCDeviceTypeIPadMiniWifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP661 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP622
{RTCDeviceTypeIPadMiniGSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP661 {RTCDeviceTypeIPad2CDMA,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP622
{RTCDeviceTypeIPad2Wifi2,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP622
{RTCDeviceTypeIPadMiniWifi,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP661
{RTCDeviceTypeIPadMiniGSM,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP661
{RTCDeviceTypeIPadMiniGSM_CDMA, {RTCDeviceTypeIPadMiniGSM_CDMA,
{kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP661 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP661
{RTCDeviceTypeIPad3Wifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP647 {RTCDeviceTypeIPad3Wifi,
{RTCDeviceTypeIPad3GSM_CDMA, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP647 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP647
{RTCDeviceTypeIPad3GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP647 {RTCDeviceTypeIPad3GSM_CDMA,
{RTCDeviceTypeIPad4Wifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP662 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP647
{RTCDeviceTypeIPad4GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP662 {RTCDeviceTypeIPad3GSM,
{RTCDeviceTypeIPad4GSM_CDMA, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP662 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP647
{RTCDeviceTypeIPad5, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP751 {RTCDeviceTypeIPad4Wifi,
{RTCDeviceTypeIPad6, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP774 {H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP662
{RTCDeviceTypeIPadAirWifi, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP692 {RTCDeviceTypeIPad4GSM,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP662
{RTCDeviceTypeIPad4GSM_CDMA,
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP662
{RTCDeviceTypeIPad5,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP751
{RTCDeviceTypeIPad6,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP774
{RTCDeviceTypeIPadAirWifi,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP692
{RTCDeviceTypeIPadAirCellular, {RTCDeviceTypeIPadAirCellular,
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP692 {H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP692
{RTCDeviceTypeIPadAirWifiCellular, {RTCDeviceTypeIPadAirWifiCellular,
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP692 {H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP692
{RTCDeviceTypeIPadAir2, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP708 {RTCDeviceTypeIPadAir2,
{RTCDeviceTypeIPadMini2GWifi, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP693 {H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP708
{RTCDeviceTypeIPadMini2GWifi,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP693
{RTCDeviceTypeIPadMini2GCellular, {RTCDeviceTypeIPadMini2GCellular,
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP693 {H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP693
{RTCDeviceTypeIPadMini2GWifiCellular, {RTCDeviceTypeIPadMini2GWifiCellular,
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP693 {H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP693
{RTCDeviceTypeIPadMini3, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP709 {RTCDeviceTypeIPadMini3,
{RTCDeviceTypeIPadMini4, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP725 {H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP709
{RTCDeviceTypeIPadPro9Inch, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP739 {RTCDeviceTypeIPadMini4,
{RTCDeviceTypeIPadPro12Inch, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/sp723 {H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP725
{RTCDeviceTypeIPadPro12Inch2, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP761 {RTCDeviceTypeIPadPro9Inch,
{RTCDeviceTypeIPadPro10Inch, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP762 {H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP739
{RTCDeviceTypeIPadPro12Inch,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/sp723
{RTCDeviceTypeIPadPro12Inch2,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP761
{RTCDeviceTypeIPadPro10Inch,
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP762
}; };
absl::optional<ProfileLevelId> FindMaxSupportedProfileForDevice(RTCDeviceType deviceType) { absl::optional<H264ProfileLevelId> FindMaxSupportedProfileForDevice(RTCDeviceType deviceType) {
const auto* result = std::find_if(std::begin(kH264MaxSupportedProfiles), const auto* result = std::find_if(std::begin(kH264MaxSupportedProfiles),
std::end(kH264MaxSupportedProfiles), std::end(kH264MaxSupportedProfiles),
[deviceType](const SupportedH264Profile& supportedProfile) { [deviceType](const SupportedH264Profile& supportedProfile) {
@ -123,7 +180,7 @@ absl::optional<ProfileLevelId> FindMaxSupportedProfileForDevice(RTCDeviceType de
@implementation UIDevice (H264Profile) @implementation UIDevice (H264Profile)
+ (absl::optional<webrtc::H264::ProfileLevelId>)maxSupportedH264Profile { + (absl::optional<webrtc::H264ProfileLevelId>)maxSupportedH264Profile {
return FindMaxSupportedProfileForDevice([self deviceType]); return FindMaxSupportedProfileForDevice([self deviceType]);
} }

View File

@ -84,7 +84,6 @@ rtc_library("video") {
"../call:rtp_sender", "../call:rtp_sender",
"../call:video_stream_api", "../call:video_stream_api",
"../common_video", "../common_video",
"../media:rtc_h264_profile_id",
"../modules:module_api", "../modules:module_api",
"../modules:module_api_public", "../modules:module_api_public",
"../modules/pacing", "../modules/pacing",
@ -175,7 +174,6 @@ rtc_source_set("video_legacy") {
"../call:rtp_receiver", # For RtxReceiveStream. "../call:rtp_receiver", # For RtxReceiveStream.
"../call:video_stream_api", "../call:video_stream_api",
"../common_video", "../common_video",
"../media:rtc_h264_profile_id",
"../modules:module_api", "../modules:module_api",
"../modules/pacing", "../modules/pacing",
"../modules/remote_bitrate_estimator", "../modules/remote_bitrate_estimator",
@ -431,7 +429,6 @@ if (rtc_include_tests) {
"../api:test_dependency_factory", "../api:test_dependency_factory",
"../api:video_quality_test_fixture_api", "../api:video_quality_test_fixture_api",
"../api/video_codecs:video_codecs_api", "../api/video_codecs:video_codecs_api",
"../media:rtc_vp9_profile",
"../modules/pacing", "../modules/pacing",
"../modules/video_coding:webrtc_vp9", "../modules/video_coding:webrtc_vp9",
"../rtc_base/experiments:alr_experiment", "../rtc_base/experiments:alr_experiment",
@ -463,8 +460,8 @@ if (rtc_include_tests) {
"../api:peer_connection_quality_test_fixture_api", "../api:peer_connection_quality_test_fixture_api",
"../api:simulated_network_api", "../api:simulated_network_api",
"../api:time_controller", "../api:time_controller",
"../api/video_codecs:video_codecs_api",
"../call:simulated_network", "../call:simulated_network",
"../media:rtc_vp9_profile",
"../modules/video_coding:webrtc_vp9", "../modules/video_coding:webrtc_vp9",
"../system_wrappers:field_trial", "../system_wrappers:field_trial",
"../test:field_trial", "../test:field_trial",

View File

@ -21,7 +21,7 @@
#include "api/video_codecs/sdp_video_format.h" #include "api/video_codecs/sdp_video_format.h"
#include "api/video_codecs/video_codec.h" #include "api/video_codecs/video_codec.h"
#include "api/video_codecs/video_encoder_config.h" #include "api/video_codecs/video_encoder_config.h"
#include "media/base/vp9_profile.h" #include "api/video_codecs/vp9_profile.h"
#include "modules/video_coding/codecs/vp9/include/vp9.h" #include "modules/video_coding/codecs/vp9/include/vp9.h"
#include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/field_trial.h"
#include "test/field_trial.h" #include "test/field_trial.h"

View File

@ -21,8 +21,8 @@
#include "api/test/peerconnection_quality_test_fixture.h" #include "api/test/peerconnection_quality_test_fixture.h"
#include "api/test/simulated_network.h" #include "api/test/simulated_network.h"
#include "api/test/time_controller.h" #include "api/test/time_controller.h"
#include "api/video_codecs/vp9_profile.h"
#include "call/simulated_network.h" #include "call/simulated_network.h"
#include "media/base/vp9_profile.h"
#include "modules/video_coding/codecs/vp9/include/vp9.h" #include "modules/video_coding/codecs/vp9/include/vp9.h"
#include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/field_trial.h"
#include "test/field_trial.h" #include "test/field_trial.h"

View File

@ -24,6 +24,7 @@
#include "api/array_view.h" #include "api/array_view.h"
#include "api/crypto/frame_decryptor_interface.h" #include "api/crypto/frame_decryptor_interface.h"
#include "api/video/encoded_image.h" #include "api/video/encoded_image.h"
#include "api/video_codecs/h264_profile_level_id.h"
#include "api/video_codecs/sdp_video_format.h" #include "api/video_codecs/sdp_video_format.h"
#include "api/video_codecs/video_codec.h" #include "api/video_codecs/video_codec.h"
#include "api/video_codecs/video_decoder_factory.h" #include "api/video_codecs/video_decoder_factory.h"
@ -31,7 +32,6 @@
#include "call/rtp_stream_receiver_controller_interface.h" #include "call/rtp_stream_receiver_controller_interface.h"
#include "call/rtx_receive_stream.h" #include "call/rtx_receive_stream.h"
#include "common_video/include/incoming_video_stream.h" #include "common_video/include/incoming_video_stream.h"
#include "media/base/h264_profile_level_id.h"
#include "modules/utility/include/process_thread.h" #include "modules/utility/include/process_thread.h"
#include "modules/video_coding/include/video_codec_interface.h" #include "modules/video_coding/include/video_codec_interface.h"
#include "modules/video_coding/include/video_coding_defines.h" #include "modules/video_coding/include/video_coding_defines.h"

View File

@ -24,6 +24,7 @@
#include "api/array_view.h" #include "api/array_view.h"
#include "api/crypto/frame_decryptor_interface.h" #include "api/crypto/frame_decryptor_interface.h"
#include "api/video/encoded_image.h" #include "api/video/encoded_image.h"
#include "api/video_codecs/h264_profile_level_id.h"
#include "api/video_codecs/sdp_video_format.h" #include "api/video_codecs/sdp_video_format.h"
#include "api/video_codecs/video_codec.h" #include "api/video_codecs/video_codec.h"
#include "api/video_codecs/video_decoder_factory.h" #include "api/video_codecs/video_decoder_factory.h"
@ -31,7 +32,6 @@
#include "call/rtp_stream_receiver_controller_interface.h" #include "call/rtp_stream_receiver_controller_interface.h"
#include "call/rtx_receive_stream.h" #include "call/rtx_receive_stream.h"
#include "common_video/include/incoming_video_stream.h" #include "common_video/include/incoming_video_stream.h"
#include "media/base/h264_profile_level_id.h"
#include "modules/video_coding/include/video_codec_interface.h" #include "modules/video_coding/include/video_codec_interface.h"
#include "modules/video_coding/include/video_coding_defines.h" #include "modules/video_coding/include/video_coding_defines.h"
#include "modules/video_coding/include/video_error_codes.h" #include "modules/video_coding/include/video_error_codes.h"