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:
parent
8546666cb9
commit
c3fcee7c3a
@ -35,7 +35,4 @@ specific_include_rules = {
|
||||
"create_frame_generator\.h": [
|
||||
"+system_wrappers/include/clock.h",
|
||||
],
|
||||
"videocodec_test_fixture\.h": [
|
||||
"+media/base/h264_profile_level_id.h"
|
||||
],
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ class VideoCodecTestFixture {
|
||||
class EncodedFrameChecker {
|
||||
public:
|
||||
virtual ~EncodedFrameChecker() = default;
|
||||
virtual void CheckEncodedFrame(webrtc::VideoCodecType codec,
|
||||
virtual void CheckEncodedFrame(VideoCodecType codec,
|
||||
const EncodedImage& encoded_frame) const = 0;
|
||||
};
|
||||
|
||||
@ -123,16 +123,16 @@ class VideoCodecTestFixture {
|
||||
bool encode_in_real_time = false;
|
||||
|
||||
// Codec settings to use.
|
||||
webrtc::VideoCodec codec_settings;
|
||||
VideoCodec codec_settings;
|
||||
|
||||
// Name of the codec being tested.
|
||||
std::string codec_name;
|
||||
|
||||
// H.264 specific settings.
|
||||
struct H264CodecSettings {
|
||||
H264::Profile profile = H264::kProfileConstrainedBaseline;
|
||||
H264Profile profile = H264Profile::kProfileConstrainedBaseline;
|
||||
H264PacketizationMode packetization_mode =
|
||||
webrtc::H264PacketizationMode::NonInterleaved;
|
||||
H264PacketizationMode::NonInterleaved;
|
||||
} h264_codec_settings;
|
||||
|
||||
// Custom checker that will be called for each frame.
|
||||
|
||||
@ -15,6 +15,8 @@ if (is_android) {
|
||||
rtc_library("video_codecs_api") {
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
"h264_profile_level_id.cc",
|
||||
"h264_profile_level_id.h",
|
||||
"sdp_video_format.cc",
|
||||
"sdp_video_format.h",
|
||||
"spatial_layer.cc",
|
||||
@ -35,6 +37,8 @@ rtc_library("video_codecs_api") {
|
||||
"vp8_frame_config.h",
|
||||
"vp8_temporal_layers.cc",
|
||||
"vp8_temporal_layers.h",
|
||||
"vp9_profile.cc",
|
||||
"vp9_profile.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
@ -138,7 +142,6 @@ rtc_library("rtc_software_fallback_wrappers") {
|
||||
":video_codecs_api",
|
||||
"..:fec_controller_api",
|
||||
"../../api/video:video_frame",
|
||||
"../../media:rtc_h264_profile_id",
|
||||
"../../media:rtc_media_base",
|
||||
"../../modules/video_coding:video_codec_interface",
|
||||
"../../modules/video_coding:video_coding_utility",
|
||||
|
||||
252
api/video_codecs/h264_profile_level_id.cc
Normal file
252
api/video_codecs/h264_profile_level_id.cc
Normal 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
|
||||
91
api/video_codecs/h264_profile_level_id.h
Normal file
91
api/video_codecs/h264_profile_level_id.h
Normal 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_
|
||||
@ -13,6 +13,7 @@ if (rtc_include_tests) {
|
||||
testonly = true
|
||||
sources = [
|
||||
"builtin_video_encoder_factory_unittest.cc",
|
||||
"h264_profile_level_id_unittest.cc",
|
||||
"video_decoder_software_fallback_wrapper_unittest.cc",
|
||||
"video_encoder_software_fallback_wrapper_unittest.cc",
|
||||
]
|
||||
|
||||
171
api/video_codecs/test/h264_profile_level_id_unittest.cc
Normal file
171
api/video_codecs/test/h264_profile_level_id_unittest.cc
Normal 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
|
||||
@ -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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "media/base/vp9_profile.h"
|
||||
#include "api/video_codecs/vp9_profile.h"
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
@ -59,7 +59,7 @@ absl::optional<VP9Profile> ParseSdpForVP9Profile(
|
||||
return StringToVP9Profile(profile_str);
|
||||
}
|
||||
|
||||
bool IsSameVP9Profile(const SdpVideoFormat::Parameters& params1,
|
||||
bool VP9IsSameProfile(const SdpVideoFormat::Parameters& params1,
|
||||
const SdpVideoFormat::Parameters& params2) {
|
||||
const absl::optional<VP9Profile> profile = ParseSdpForVP9Profile(params1);
|
||||
const absl::optional<VP9Profile> other_profile =
|
||||
53
api/video_codecs/vp9_profile.h
Normal file
53
api/video_codecs/vp9_profile.h
Normal 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_
|
||||
@ -21,7 +21,6 @@ rtc_library("common_video") {
|
||||
"h264/h264_common.h",
|
||||
"h264/pps_parser.cc",
|
||||
"h264/pps_parser.h",
|
||||
"h264/profile_level_id.h",
|
||||
"h264/sps_parser.cc",
|
||||
"h264/sps_parser.h",
|
||||
"h264/sps_vui_rewriter.cc",
|
||||
@ -52,7 +51,7 @@ rtc_library("common_video") {
|
||||
"../api/video:video_frame",
|
||||
"../api/video:video_rtp_headers",
|
||||
"../api/video_codecs:bitstream_parser_api",
|
||||
"../media:rtc_h264_profile_id",
|
||||
"../api/video_codecs:video_codecs_api",
|
||||
"../rtc_base",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:rtc_task_queue",
|
||||
@ -90,7 +89,6 @@ if (rtc_include_tests && !build_with_chromium) {
|
||||
"frame_rate_estimator_unittest.cc",
|
||||
"h264/h264_bitstream_parser_unittest.cc",
|
||||
"h264/pps_parser_unittest.cc",
|
||||
"h264/profile_level_id_unittest.cc",
|
||||
"h264/sps_parser_unittest.cc",
|
||||
"h264/sps_vui_rewriter_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_i010",
|
||||
"../api/video:video_rtp_headers",
|
||||
"../media:rtc_h264_profile_id",
|
||||
"../api/video_codecs:video_codecs_api",
|
||||
"../rtc_base",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -23,20 +23,15 @@ config("rtc_media_defines_config") {
|
||||
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 = [ "*" ]
|
||||
sources = [
|
||||
"base/h264_profile_level_id.cc",
|
||||
"base/h264_profile_level_id.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"../rtc_base",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base/system:rtc_export",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
public_deps = # no-presubmit-check TODO(webrtc:8603)
|
||||
[ "../api/video_codecs:video_codecs_api" ]
|
||||
}
|
||||
|
||||
rtc_source_set("rtc_media_config") {
|
||||
@ -44,30 +39,24 @@ rtc_source_set("rtc_media_config") {
|
||||
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 = [ "*" ]
|
||||
sources = [
|
||||
"base/vp9_profile.cc",
|
||||
"base/vp9_profile.h",
|
||||
]
|
||||
|
||||
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" ]
|
||||
sources = [ "base/vp9_profile.h" ]
|
||||
public_deps = # no-presubmit-check TODO(webrtc:8603)
|
||||
[ "../api/video_codecs:video_codecs_api" ]
|
||||
}
|
||||
|
||||
rtc_library("rtc_sdp_fmtp_utils") {
|
||||
rtc_library("rtc_sdp_video_format_utils") {
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
"base/sdp_fmtp_utils.cc",
|
||||
"base/sdp_fmtp_utils.h",
|
||||
"base/sdp_video_format_utils.cc",
|
||||
"base/sdp_video_format_utils.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"../api/video_codecs:video_codecs_api",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:stringutils",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
@ -78,9 +67,7 @@ rtc_library("rtc_media_base") {
|
||||
defines = []
|
||||
libs = []
|
||||
deps = [
|
||||
":rtc_h264_profile_id",
|
||||
":rtc_media_config",
|
||||
":rtc_vp9_profile",
|
||||
"../api:array_view",
|
||||
"../api:audio_options_api",
|
||||
"../api:frame_transformer_interface",
|
||||
@ -221,7 +208,6 @@ rtc_library("rtc_internal_video_codecs") {
|
||||
libs = []
|
||||
deps = [
|
||||
":rtc_encoder_simulcast_proxy",
|
||||
":rtc_h264_profile_id",
|
||||
":rtc_media_base",
|
||||
":rtc_simulcast_encoder_adapter",
|
||||
"../api/video:encoded_image",
|
||||
@ -555,9 +541,8 @@ if (rtc_include_tests) {
|
||||
":rtc_media_base",
|
||||
":rtc_media_engine_defaults",
|
||||
":rtc_media_tests_utils",
|
||||
":rtc_sdp_fmtp_utils",
|
||||
":rtc_sdp_video_format_utils",
|
||||
":rtc_simulcast_encoder_adapter",
|
||||
":rtc_vp9_profile",
|
||||
"../api:create_simulcast_test_fixture_api",
|
||||
"../api:libjingle_peerconnection_api",
|
||||
"../api:mock_video_bitrate_allocator",
|
||||
@ -586,7 +571,6 @@ if (rtc_include_tests) {
|
||||
"../audio",
|
||||
"../call:call_interfaces",
|
||||
"../common_video",
|
||||
"../media:rtc_h264_profile_id",
|
||||
"../modules/audio_device:mock_audio_device",
|
||||
"../modules/audio_processing",
|
||||
"../modules/audio_processing:api",
|
||||
@ -627,7 +611,7 @@ if (rtc_include_tests) {
|
||||
"base/codec_unittest.cc",
|
||||
"base/media_engine_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/turn_utils_unittest.cc",
|
||||
"base/video_adapter_unittest.cc",
|
||||
|
||||
@ -12,8 +12,8 @@
|
||||
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "media/base/h264_profile_level_id.h"
|
||||
#include "media/base/vp9_profile.h"
|
||||
#include "api/video_codecs/h264_profile_level_id.h"
|
||||
#include "api/video_codecs/vp9_profile.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/string_encode.h"
|
||||
@ -51,10 +51,10 @@ bool IsSameCodecSpecific(const std::string& name1,
|
||||
absl::EqualsIgnoreCase(name, name2);
|
||||
};
|
||||
if (either_name_matches(kH264CodecName))
|
||||
return webrtc::H264::IsSameH264Profile(params1, params2) &&
|
||||
return webrtc::H264IsSameProfile(params1, params2) &&
|
||||
IsSameH264PacketizationMode(params1, params2);
|
||||
if (either_name_matches(kVp9CodecName))
|
||||
return webrtc::IsSameVP9Profile(params1, params2);
|
||||
return webrtc::VP9IsSameProfile(params1, params2);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -473,15 +473,16 @@ void AddH264ConstrainedBaselineProfileToSupportedFormats(
|
||||
for (auto it = supported_formats->cbegin(); it != supported_formats->cend();
|
||||
++it) {
|
||||
if (it->name == cricket::kH264CodecName) {
|
||||
const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
|
||||
webrtc::H264::ParseSdpProfileLevelId(it->parameters);
|
||||
if (profile_level_id && profile_level_id->profile !=
|
||||
webrtc::H264::kProfileConstrainedBaseline) {
|
||||
const absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
|
||||
webrtc::ParseSdpForH264ProfileLevelId(it->parameters);
|
||||
if (profile_level_id &&
|
||||
profile_level_id->profile !=
|
||||
webrtc::H264Profile::kProfileConstrainedBaseline) {
|
||||
webrtc::SdpVideoFormat cbp_format = *it;
|
||||
webrtc::H264::ProfileLevelId cbp_profile = *profile_level_id;
|
||||
cbp_profile.profile = webrtc::H264::kProfileConstrainedBaseline;
|
||||
webrtc::H264ProfileLevelId cbp_profile = *profile_level_id;
|
||||
cbp_profile.profile = webrtc::H264Profile::kProfileConstrainedBaseline;
|
||||
cbp_format.parameters[cricket::kH264FmtpProfileLevelId] =
|
||||
*webrtc::H264::ProfileLevelIdToString(cbp_profile);
|
||||
*webrtc::H264ProfileLevelIdToString(cbp_profile);
|
||||
cbr_supported_formats.push_back(cbp_format);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,8 +12,8 @@
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "media/base/h264_profile_level_id.h"
|
||||
#include "media/base/vp9_profile.h"
|
||||
#include "api/video_codecs/h264_profile_level_id.h"
|
||||
#include "api/video_codecs/vp9_profile.h"
|
||||
#include "modules/video_coding/codecs/h264/include/h264.h"
|
||||
#include "rtc_base/gunit.h"
|
||||
|
||||
@ -457,10 +457,10 @@ TEST(CodecTest, TestToCodecParameters) {
|
||||
|
||||
TEST(CodecTest, H264CostrainedBaselineIsAddedIfH264IsSupported) {
|
||||
const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = {
|
||||
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
|
||||
webrtc::H264::kLevel3_1, "1"),
|
||||
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
|
||||
webrtc::H264::kLevel3_1, "0")};
|
||||
webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
|
||||
webrtc::H264Level::kLevel3_1, "1"),
|
||||
webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
|
||||
webrtc::H264Level::kLevel3_1, "0")};
|
||||
|
||||
std::vector<webrtc::SdpVideoFormat> supported_formats =
|
||||
kExplicitlySupportedFormats;
|
||||
@ -468,11 +468,11 @@ TEST(CodecTest, H264CostrainedBaselineIsAddedIfH264IsSupported) {
|
||||
&supported_formats);
|
||||
|
||||
const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization1 =
|
||||
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
|
||||
webrtc::H264::kLevel3_1, "1");
|
||||
webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
|
||||
webrtc::H264Level::kLevel3_1, "1");
|
||||
const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization0 =
|
||||
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
|
||||
webrtc::H264::kLevel3_1, "0");
|
||||
webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
|
||||
webrtc::H264Level::kLevel3_1, "0");
|
||||
|
||||
EXPECT_EQ(supported_formats[0], kExplicitlySupportedFormats[0]);
|
||||
EXPECT_EQ(supported_formats[1], kExplicitlySupportedFormats[1]);
|
||||
@ -497,14 +497,14 @@ TEST(CodecTest, H264CostrainedBaselineIsNotAddedIfH264IsUnsupported) {
|
||||
|
||||
TEST(CodecTest, H264CostrainedBaselineNotAddedIfAlreadySpecified) {
|
||||
const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = {
|
||||
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
|
||||
webrtc::H264::kLevel3_1, "1"),
|
||||
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
|
||||
webrtc::H264::kLevel3_1, "0"),
|
||||
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
|
||||
webrtc::H264::kLevel3_1, "1"),
|
||||
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
|
||||
webrtc::H264::kLevel3_1, "0")};
|
||||
webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
|
||||
webrtc::H264Level::kLevel3_1, "1"),
|
||||
webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
|
||||
webrtc::H264Level::kLevel3_1, "0"),
|
||||
webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
|
||||
webrtc::H264Level::kLevel3_1, "1"),
|
||||
webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
|
||||
webrtc::H264Level::kLevel3_1, "0")};
|
||||
|
||||
std::vector<webrtc::SdpVideoFormat> supported_formats =
|
||||
kExplicitlySupportedFormats;
|
||||
|
||||
@ -10,301 +10,33 @@
|
||||
|
||||
#include "media/base/h264_profile_level_id.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "rtc_base/arraysize.h"
|
||||
#include "rtc_base/checks.h"
|
||||
// TODO(crbug.com/1187565): Remove this file once downstream projects stop
|
||||
// depend on it.
|
||||
|
||||
namespace webrtc {
|
||||
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) {
|
||||
// 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.
|
||||
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;
|
||||
return webrtc::ParseH264ProfileLevelId(str);
|
||||
}
|
||||
|
||||
absl::optional<ProfileLevelId> ParseSdpProfileLevelId(
|
||||
const CodecParameterMap& 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 ProfileLevelId kDefaultProfileLevelId(
|
||||
kProfileConstrainedBaseline, kLevel3_1);
|
||||
const SdpVideoFormat::Parameters& params) {
|
||||
return webrtc::ParseSdpForH264ProfileLevelId(params);
|
||||
}
|
||||
|
||||
const auto profile_level_id_it = params.find(kProfileLevelId);
|
||||
return (profile_level_id_it == params.end())
|
||||
? kDefaultProfileLevelId
|
||||
: ParseProfileLevelId(profile_level_id_it->second.c_str());
|
||||
absl::optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps) {
|
||||
return webrtc::H264SupportedLevel(max_frame_pixel_count, max_fps);
|
||||
}
|
||||
|
||||
absl::optional<std::string> ProfileLevelIdToString(
|
||||
const ProfileLevelId& profile_level_id) {
|
||||
// Handle special case level == 1b.
|
||||
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};
|
||||
return webrtc::H264ProfileLevelIdToString(profile_level_id);
|
||||
}
|
||||
|
||||
// Set level according to https://tools.ietf.org/html/rfc6184#section-8.2.2.
|
||||
void GenerateProfileLevelIdForAnswer(
|
||||
const CodecParameterMap& local_supported_params,
|
||||
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;
|
||||
bool IsSameH264Profile(const SdpVideoFormat::Parameters& params1,
|
||||
const SdpVideoFormat::Parameters& params2) {
|
||||
return webrtc::H264IsSameProfile(params1, params2);
|
||||
}
|
||||
|
||||
} // namespace H264
|
||||
|
||||
@ -11,54 +11,45 @@
|
||||
#ifndef MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
|
||||
#define MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "rtc_base/system/rtc_export.h"
|
||||
#include "api/video_codecs/h264_profile_level_id.h"
|
||||
|
||||
// TODO(crbug.com/1187565): Remove this file once downstream projects stop
|
||||
// depend on it.
|
||||
|
||||
namespace webrtc {
|
||||
namespace H264 {
|
||||
|
||||
enum Profile {
|
||||
kProfileConstrainedBaseline,
|
||||
kProfileBaseline,
|
||||
kProfileMain,
|
||||
kProfileConstrainedHigh,
|
||||
kProfileHigh,
|
||||
};
|
||||
typedef H264Profile Profile;
|
||||
typedef H264Level Level;
|
||||
typedef H264ProfileLevelId ProfileLevelId;
|
||||
|
||||
// Map containting SDP codec parameters.
|
||||
typedef std::map<std::string, std::string> CodecParameterMap;
|
||||
constexpr H264Profile kProfileConstrainedBaseline =
|
||||
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
|
||||
// special.
|
||||
enum Level {
|
||||
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 ProfileLevelId {
|
||||
constexpr ProfileLevelId(Profile profile, Level level)
|
||||
: profile(profile), level(level) {}
|
||||
Profile profile;
|
||||
Level level;
|
||||
};
|
||||
constexpr H264Level kLevel1_b = H264Level::kLevel1_b;
|
||||
constexpr H264Level kLevel1 = H264Level::kLevel1;
|
||||
constexpr H264Level kLevel1_1 = H264Level::kLevel1_1;
|
||||
constexpr H264Level kLevel1_2 = H264Level::kLevel1_2;
|
||||
constexpr H264Level kLevel1_3 = H264Level::kLevel1_3;
|
||||
constexpr H264Level kLevel2 = H264Level::kLevel2;
|
||||
constexpr H264Level kLevel2_1 = H264Level::kLevel2_1;
|
||||
constexpr H264Level kLevel2_2 = H264Level::kLevel2_2;
|
||||
constexpr H264Level kLevel3 = H264Level::kLevel3;
|
||||
constexpr H264Level kLevel3_1 = H264Level::kLevel3_1;
|
||||
constexpr H264Level kLevel3_2 = H264Level::kLevel3_2;
|
||||
constexpr H264Level kLevel4 = H264Level::kLevel4;
|
||||
constexpr H264Level kLevel4_1 = H264Level::kLevel4_1;
|
||||
constexpr H264Level kLevel4_2 = H264Level::kLevel4_2;
|
||||
constexpr H264Level kLevel5 = H264Level::kLevel5;
|
||||
constexpr H264Level kLevel5_1 = H264Level::kLevel5_1;
|
||||
constexpr H264Level kLevel5_2 = H264Level::kLevel5_2;
|
||||
|
||||
// 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
|
||||
@ -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
|
||||
// the key is present but the string is invalid.
|
||||
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 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(
|
||||
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
|
||||
// H264::Profile (Baseline, High, etc).
|
||||
bool IsSameH264Profile(const CodecParameterMap& params1,
|
||||
const CodecParameterMap& params2);
|
||||
RTC_EXPORT bool IsSameH264Profile(const SdpVideoFormat::Parameters& params1,
|
||||
const SdpVideoFormat::Parameters& params2);
|
||||
|
||||
} // namespace H264
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
|
||||
|
||||
@ -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
|
||||
@ -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__
|
||||
@ -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
|
||||
121
media/base/sdp_video_format_utils.cc
Normal file
121
media/base/sdp_video_format_utils.cc
Normal 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
|
||||
52
media/base/sdp_video_format_utils.h
Normal file
52
media/base/sdp_video_format_utils.h
Normal 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_
|
||||
115
media/base/sdp_video_format_utils_unittest.cc
Normal file
115
media/base/sdp_video_format_utils_unittest.cc
Normal 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
|
||||
@ -11,43 +11,9 @@
|
||||
#ifndef 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"
|
||||
#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 IsSameVP9Profile(const SdpVideoFormat::Parameters& params1,
|
||||
const SdpVideoFormat::Parameters& params2);
|
||||
|
||||
} // namespace webrtc
|
||||
// TODO(crbug.com/1187565): Remove this file once downstream projects stop
|
||||
// depend on it.
|
||||
|
||||
#endif // MEDIA_BASE_VP9_PROFILE_H_
|
||||
|
||||
@ -12,8 +12,8 @@
|
||||
|
||||
#include "api/video_codecs/sdp_video_format.h"
|
||||
#include "api/video_codecs/video_decoder.h"
|
||||
#include "api/video_codecs/vp9_profile.h"
|
||||
#include "media/base/media_constants.h"
|
||||
#include "media/base/vp9_profile.h"
|
||||
#include "modules/video_coding/codecs/av1/libaom_av1_decoder.h"
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
@ -35,12 +35,12 @@
|
||||
#include "api/video/video_bitrate_allocation.h"
|
||||
#include "api/video_codecs/builtin_video_decoder_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/video_decoder_factory.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
#include "api/video_codecs/video_encoder_factory.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_network_interface.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
|
||||
// adding RTX codecs for unrecognized codec names.
|
||||
TEST_F(WebRtcVideoEngineTest, RtxCodecAddedForH264Codec) {
|
||||
using webrtc::H264::kLevel1;
|
||||
using webrtc::H264::ProfileLevelId;
|
||||
using webrtc::H264::ProfileLevelIdToString;
|
||||
using webrtc::H264Level;
|
||||
using webrtc::H264Profile;
|
||||
using webrtc::H264ProfileLevelId;
|
||||
using webrtc::H264ProfileLevelIdToString;
|
||||
webrtc::SdpVideoFormat h264_constrained_baseline("H264");
|
||||
h264_constrained_baseline.parameters[kH264FmtpProfileLevelId] =
|
||||
*ProfileLevelIdToString(
|
||||
ProfileLevelId(webrtc::H264::kProfileConstrainedBaseline, kLevel1));
|
||||
*H264ProfileLevelIdToString(H264ProfileLevelId(
|
||||
H264Profile::kProfileConstrainedBaseline, H264Level::kLevel1));
|
||||
webrtc::SdpVideoFormat h264_constrained_high("H264");
|
||||
h264_constrained_high.parameters[kH264FmtpProfileLevelId] =
|
||||
*ProfileLevelIdToString(
|
||||
ProfileLevelId(webrtc::H264::kProfileConstrainedHigh, kLevel1));
|
||||
*H264ProfileLevelIdToString(H264ProfileLevelId(
|
||||
H264Profile::kProfileConstrainedHigh, H264Level::kLevel1));
|
||||
webrtc::SdpVideoFormat h264_high("H264");
|
||||
h264_high.parameters[kH264FmtpProfileLevelId] = *ProfileLevelIdToString(
|
||||
ProfileLevelId(webrtc::H264::kProfileHigh, kLevel1));
|
||||
h264_high.parameters[kH264FmtpProfileLevelId] = *H264ProfileLevelIdToString(
|
||||
H264ProfileLevelId(H264Profile::kProfileHigh, H264Level::kLevel1));
|
||||
|
||||
encoder_factory_->AddSupportedVideoCodec(h264_constrained_baseline);
|
||||
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
|
||||
// an internal H264 codec from the engine with a different H264 profile.
|
||||
if (absl::EqualsIgnoreCase(name.c_str(), kH264CodecName)) {
|
||||
const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
|
||||
webrtc::H264::ParseSdpProfileLevelId(engine_codec.params);
|
||||
const absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
|
||||
webrtc::ParseSdpForH264ProfileLevelId(engine_codec.params);
|
||||
if (profile_level_id->profile !=
|
||||
webrtc::H264::kProfileConstrainedBaseline) {
|
||||
webrtc::H264Profile::kProfileConstrainedBaseline) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -592,7 +592,6 @@ rtc_library("webrtc_vp9") {
|
||||
"../../api/video_codecs:video_codecs_api",
|
||||
"../../common_video",
|
||||
"../../media:rtc_media_base",
|
||||
"../../media:rtc_vp9_profile",
|
||||
"../../rtc_base",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base/experiments:encoder_info_settings",
|
||||
@ -814,7 +813,6 @@ if (rtc_include_tests) {
|
||||
"../../call:video_stream_api",
|
||||
"../../common_video",
|
||||
"../../media:rtc_audio_video",
|
||||
"../../media:rtc_h264_profile_id",
|
||||
"../../media:rtc_internal_video_codecs",
|
||||
"../../media:rtc_media_base",
|
||||
"../../rtc_base:checks",
|
||||
@ -904,11 +902,9 @@ if (rtc_include_tests) {
|
||||
"../../api/video_codecs:video_codecs_api",
|
||||
"../../common_video",
|
||||
"../../common_video/test:utilities",
|
||||
"../../media:rtc_h264_profile_id",
|
||||
"../../media:rtc_internal_video_codecs",
|
||||
"../../media:rtc_media_base",
|
||||
"../../media:rtc_simulcast_encoder_adapter",
|
||||
"../../media:rtc_vp9_profile",
|
||||
"../../rtc_base",
|
||||
"../../test:explicit_key_value_config",
|
||||
"../../test:field_trial",
|
||||
|
||||
@ -45,11 +45,11 @@ bool IsH264CodecSupported() {
|
||||
|
||||
} // namespace
|
||||
|
||||
SdpVideoFormat CreateH264Format(H264::Profile profile,
|
||||
H264::Level level,
|
||||
SdpVideoFormat CreateH264Format(H264Profile profile,
|
||||
H264Level level,
|
||||
const std::string& packetization_mode) {
|
||||
const absl::optional<std::string> profile_string =
|
||||
H264::ProfileLevelIdToString(H264::ProfileLevelId(profile, level));
|
||||
H264ProfileLevelIdToString(H264ProfileLevelId(profile, level));
|
||||
RTC_CHECK(profile_string);
|
||||
return SdpVideoFormat(
|
||||
cricket::kH264CodecName,
|
||||
@ -76,12 +76,14 @@ std::vector<SdpVideoFormat> SupportedH264Codecs() {
|
||||
//
|
||||
// We support both packetization modes 0 (mandatory) and 1 (optional,
|
||||
// preferred).
|
||||
return {
|
||||
CreateH264Format(H264::kProfileBaseline, H264::kLevel3_1, "1"),
|
||||
CreateH264Format(H264::kProfileBaseline, H264::kLevel3_1, "0"),
|
||||
CreateH264Format(H264::kProfileConstrainedBaseline, H264::kLevel3_1, "1"),
|
||||
CreateH264Format(H264::kProfileConstrainedBaseline, H264::kLevel3_1,
|
||||
"0")};
|
||||
return {CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1,
|
||||
"1"),
|
||||
CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1,
|
||||
"0"),
|
||||
CreateH264Format(H264Profile::kProfileConstrainedBaseline,
|
||||
H264Level::kLevel3_1, "1"),
|
||||
CreateH264Format(H264Profile::kProfileConstrainedBaseline,
|
||||
H264Level::kLevel3_1, "0")};
|
||||
}
|
||||
|
||||
std::unique_ptr<H264Encoder> H264Encoder::Create(
|
||||
|
||||
@ -27,8 +27,8 @@ struct SdpVideoFormat;
|
||||
|
||||
// Creates an H264 SdpVideoFormat entry with specified paramters.
|
||||
RTC_EXPORT SdpVideoFormat
|
||||
CreateH264Format(H264::Profile profile,
|
||||
H264::Level level,
|
||||
CreateH264Format(H264Profile profile,
|
||||
H264Level level,
|
||||
const std::string& packetization_mode);
|
||||
|
||||
// Set to disable the H.264 encoder/decoder implementations that are provided if
|
||||
|
||||
@ -25,12 +25,12 @@
|
||||
#include "api/array_view.h"
|
||||
#include "api/transport/field_trial_based_config.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/video_codec.h"
|
||||
#include "api/video_codecs/video_decoder.h"
|
||||
#include "api/video_codecs/video_encoder_config.h"
|
||||
#include "common_video/h264/h264_common.h"
|
||||
#include "media/base/h264_profile_level_id.h"
|
||||
#include "media/base/media_constants.h"
|
||||
#include "media/engine/internal_decoder_factory.h"
|
||||
#include "media/engine/internal_encoder_factory.h"
|
||||
@ -302,11 +302,11 @@ std::string VideoCodecTestFixtureImpl::Config::CodecName() const {
|
||||
name = CodecTypeToPayloadString(codec_settings.codecType);
|
||||
}
|
||||
if (codec_settings.codecType == kVideoCodecH264) {
|
||||
if (h264_codec_settings.profile == H264::kProfileConstrainedHigh) {
|
||||
if (h264_codec_settings.profile == H264Profile::kProfileConstrainedHigh) {
|
||||
return name + "-CHP";
|
||||
} else {
|
||||
RTC_DCHECK_EQ(h264_codec_settings.profile,
|
||||
H264::kProfileConstrainedBaseline);
|
||||
H264Profile::kProfileConstrainedBaseline);
|
||||
return name + "-CBP";
|
||||
}
|
||||
}
|
||||
@ -613,8 +613,8 @@ bool VideoCodecTestFixtureImpl::CreateEncoderAndDecoder() {
|
||||
? "1"
|
||||
: "0";
|
||||
params = {{cricket::kH264FmtpProfileLevelId,
|
||||
*H264::ProfileLevelIdToString(H264::ProfileLevelId(
|
||||
config_.h264_codec_settings.profile, H264::kLevel3_1))},
|
||||
*H264ProfileLevelIdToString(H264ProfileLevelId(
|
||||
config_.h264_codec_settings.profile, H264Level::kLevel3_1))},
|
||||
{cricket::kH264FmtpPacketizationMode, packetization_mode}};
|
||||
} else {
|
||||
params = {};
|
||||
|
||||
@ -95,7 +95,7 @@ TEST(VideoCodecTestMediaCodec, DISABLED_ForemanCif500kbpsH264CHP) {
|
||||
const auto frame_checker =
|
||||
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.SetCodecSettings(cricket::kH264CodecName, 1, 1, 1, false, false, false,
|
||||
352, 288);
|
||||
|
||||
@ -71,7 +71,7 @@ MAYBE_TEST(VideoCodecTestVideoToolbox, ForemanCif500kbpsH264CHP) {
|
||||
const auto frame_checker =
|
||||
std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>();
|
||||
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,
|
||||
352, 288);
|
||||
config.encoded_frame_checker = frame_checker.get();
|
||||
|
||||
@ -21,8 +21,8 @@
|
||||
#include "api/fec_controller_override.h"
|
||||
#include "api/transport/webrtc_key_value_config.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 "media/base/vp9_profile.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/vp9_frame_buffer_pool.h"
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
#include "api/video/color_space.h"
|
||||
#include "api/video/i420_buffer.h"
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
#include "api/video_codecs/vp9_profile.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/video_coding/codecs/interface/libvpx_interface.h"
|
||||
#include "modules/video_coding/codecs/interface/mock_libvpx_interface.h"
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
#include "api/transport/field_trial_based_config.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_encoder.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
@ -102,6 +102,7 @@ rtc_library("rtc_pc_base") {
|
||||
"../api/video:video_bitrate_allocator_factory",
|
||||
"../api/video:video_frame",
|
||||
"../api/video:video_rtp_headers",
|
||||
"../api/video_codecs:video_codecs_api",
|
||||
"../call:call_interfaces",
|
||||
"../call:rtp_interfaces",
|
||||
"../call:rtp_receiver",
|
||||
@ -109,9 +110,9 @@ rtc_library("rtc_pc_base") {
|
||||
"../common_video:common_video",
|
||||
"../logging:ice_log",
|
||||
"../media:rtc_data_sctp_transport_internal",
|
||||
"../media:rtc_h264_profile_id",
|
||||
"../media:rtc_media_base",
|
||||
"../media:rtc_media_config",
|
||||
"../media:rtc_sdp_video_format_utils",
|
||||
"../modules/rtp_rtcp:rtp_rtcp",
|
||||
"../modules/rtp_rtcp:rtp_rtcp_format",
|
||||
"../p2p:rtc_p2p",
|
||||
|
||||
@ -24,9 +24,10 @@
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/crypto_params.h"
|
||||
#include "api/video_codecs/h264_profile_level_id.h"
|
||||
#include "media/base/codec.h"
|
||||
#include "media/base/h264_profile_level_id.h"
|
||||
#include "media/base/media_constants.h"
|
||||
#include "media/base/sdp_video_format_utils.h"
|
||||
#include "media/sctp/sctp_transport_internal.h"
|
||||
#include "p2p/base/p2p_constants.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)) {
|
||||
webrtc::H264::GenerateProfileLevelIdForAnswer(
|
||||
ours.params, theirs.params, &negotiated.params);
|
||||
webrtc::H264GenerateProfileLevelIdForAnswer(ours.params, theirs.params,
|
||||
&negotiated.params);
|
||||
}
|
||||
negotiated.id = theirs.id;
|
||||
negotiated.name = theirs.name;
|
||||
|
||||
@ -1655,6 +1655,7 @@ if (is_ios || is_mac) {
|
||||
":video_toolbox_cc",
|
||||
":videocodec_objc",
|
||||
":videoframebuffer_objc",
|
||||
"../api/video_codecs:video_codecs_api",
|
||||
"../common_video",
|
||||
"../modules/video_coding:video_codec_interface",
|
||||
"../rtc_base:checks",
|
||||
|
||||
@ -8,10 +8,9 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "sdk/android/src/jni/video_codec_info.h"
|
||||
|
||||
#include "common_video/h264/profile_level_id.h"
|
||||
#include "api/video_codecs/h264_profile_level_id.h"
|
||||
#include "sdk/android/generated_video_jni/H264Utils_jni.h"
|
||||
#include "sdk/android/src/jni/video_codec_info.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace jni {
|
||||
@ -20,8 +19,8 @@ static jboolean JNI_H264Utils_IsSameH264Profile(
|
||||
JNIEnv* env,
|
||||
const JavaParamRef<jobject>& params1,
|
||||
const JavaParamRef<jobject>& params2) {
|
||||
return H264::IsSameH264Profile(JavaToNativeStringMap(env, params1),
|
||||
JavaToNativeStringMap(env, params2));
|
||||
return H264IsSameProfile(JavaToNativeStringMap(env, params1),
|
||||
JavaToNativeStringMap(env, params2));
|
||||
}
|
||||
|
||||
} // namespace jni
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
#import "UIDevice+H264Profile.h"
|
||||
#endif
|
||||
|
||||
#include "media/base/h264_profile_level_id.h"
|
||||
#include "api/video_codecs/h264_profile_level_id.h"
|
||||
#include "media/base/media_constants.h"
|
||||
|
||||
namespace {
|
||||
@ -38,13 +38,12 @@ namespace {
|
||||
|
||||
#if defined(WEBRTC_IOS)
|
||||
|
||||
using namespace webrtc::H264;
|
||||
|
||||
NSString *MaxSupportedLevelForProfile(Profile profile) {
|
||||
const absl::optional<ProfileLevelId> profileLevelId = [UIDevice maxSupportedH264Profile];
|
||||
NSString *MaxSupportedLevelForProfile(webrtc::H264Profile profile) {
|
||||
const absl::optional<webrtc::H264ProfileLevelId> profileLevelId =
|
||||
[UIDevice maxSupportedH264Profile];
|
||||
if (profileLevelId && profileLevelId->profile >= profile) {
|
||||
const absl::optional<std::string> profileString =
|
||||
ProfileLevelIdToString(ProfileLevelId(profile, profileLevelId->level));
|
||||
H264ProfileLevelIdToString(webrtc::H264ProfileLevelId(profile, profileLevelId->level));
|
||||
if (profileString) {
|
||||
return [NSString stringForStdString:*profileString];
|
||||
}
|
||||
@ -55,7 +54,7 @@ NSString *MaxSupportedLevelForProfile(Profile profile) {
|
||||
|
||||
NSString *MaxSupportedProfileLevelConstrainedBaseline() {
|
||||
#if defined(WEBRTC_IOS)
|
||||
NSString *profile = MaxSupportedLevelForProfile(webrtc::H264::kProfileConstrainedBaseline);
|
||||
NSString *profile = MaxSupportedLevelForProfile(webrtc::H264Profile::kProfileConstrainedBaseline);
|
||||
if (profile != nil) {
|
||||
return profile;
|
||||
}
|
||||
@ -65,7 +64,7 @@ NSString *MaxSupportedProfileLevelConstrainedBaseline() {
|
||||
|
||||
NSString *MaxSupportedProfileLevelConstrainedHigh() {
|
||||
#if defined(WEBRTC_IOS)
|
||||
NSString *profile = MaxSupportedLevelForProfile(webrtc::H264::kProfileConstrainedHigh);
|
||||
NSString *profile = MaxSupportedLevelForProfile(webrtc::H264Profile::kProfileConstrainedHigh);
|
||||
if (profile != nil) {
|
||||
return profile;
|
||||
}
|
||||
@ -94,8 +93,8 @@ NSString *MaxSupportedProfileLevelConstrainedHigh() {
|
||||
if (self = [super init]) {
|
||||
self.hexString = hexString;
|
||||
|
||||
absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
|
||||
webrtc::H264::ParseProfileLevelId([hexString cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
|
||||
webrtc::ParseH264ProfileLevelId([hexString cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
if (profile_level_id.has_value()) {
|
||||
self.profile = static_cast<RTCH264Profile>(profile_level_id->profile);
|
||||
self.level = static_cast<RTCH264Level>(profile_level_id->level);
|
||||
@ -110,8 +109,8 @@ NSString *MaxSupportedProfileLevelConstrainedHigh() {
|
||||
self.level = level;
|
||||
|
||||
absl::optional<std::string> hex_string =
|
||||
webrtc::H264::ProfileLevelIdToString(webrtc::H264::ProfileLevelId(
|
||||
static_cast<webrtc::H264::Profile>(profile), static_cast<webrtc::H264::Level>(level)));
|
||||
webrtc::H264ProfileLevelIdToString(webrtc::H264ProfileLevelId(
|
||||
static_cast<webrtc::H264Profile>(profile), static_cast<webrtc::H264Level>(level)));
|
||||
self.hexString =
|
||||
[NSString stringWithCString:hex_string.value_or("").c_str() encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
@ -28,8 +28,8 @@
|
||||
#import "components/video_frame_buffer/RTCCVPixelBuffer.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/profile_level_id.h"
|
||||
#include "common_video/include/bitrate_adjuster.h"
|
||||
#include "modules/video_coding/include/video_error_codes.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
|
||||
// returned. The user must initialize the encoder with a resolution and
|
||||
// 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) {
|
||||
case webrtc::H264::kProfileConstrainedBaseline:
|
||||
case webrtc::H264::kProfileBaseline:
|
||||
case webrtc::H264Profile::kProfileConstrainedBaseline:
|
||||
case webrtc::H264Profile::kProfileBaseline:
|
||||
switch (profile_level_id.level) {
|
||||
case webrtc::H264::kLevel3:
|
||||
case webrtc::H264Level::kLevel3:
|
||||
return kVTProfileLevel_H264_Baseline_3_0;
|
||||
case webrtc::H264::kLevel3_1:
|
||||
case webrtc::H264Level::kLevel3_1:
|
||||
return kVTProfileLevel_H264_Baseline_3_1;
|
||||
case webrtc::H264::kLevel3_2:
|
||||
case webrtc::H264Level::kLevel3_2:
|
||||
return kVTProfileLevel_H264_Baseline_3_2;
|
||||
case webrtc::H264::kLevel4:
|
||||
case webrtc::H264Level::kLevel4:
|
||||
return kVTProfileLevel_H264_Baseline_4_0;
|
||||
case webrtc::H264::kLevel4_1:
|
||||
case webrtc::H264Level::kLevel4_1:
|
||||
return kVTProfileLevel_H264_Baseline_4_1;
|
||||
case webrtc::H264::kLevel4_2:
|
||||
case webrtc::H264Level::kLevel4_2:
|
||||
return kVTProfileLevel_H264_Baseline_4_2;
|
||||
case webrtc::H264::kLevel5:
|
||||
case webrtc::H264Level::kLevel5:
|
||||
return kVTProfileLevel_H264_Baseline_5_0;
|
||||
case webrtc::H264::kLevel5_1:
|
||||
case webrtc::H264Level::kLevel5_1:
|
||||
return kVTProfileLevel_H264_Baseline_5_1;
|
||||
case webrtc::H264::kLevel5_2:
|
||||
case webrtc::H264Level::kLevel5_2:
|
||||
return kVTProfileLevel_H264_Baseline_5_2;
|
||||
case webrtc::H264::kLevel1:
|
||||
case webrtc::H264::kLevel1_b:
|
||||
case webrtc::H264::kLevel1_1:
|
||||
case webrtc::H264::kLevel1_2:
|
||||
case webrtc::H264::kLevel1_3:
|
||||
case webrtc::H264::kLevel2:
|
||||
case webrtc::H264::kLevel2_1:
|
||||
case webrtc::H264::kLevel2_2:
|
||||
case webrtc::H264Level::kLevel1:
|
||||
case webrtc::H264Level::kLevel1_b:
|
||||
case webrtc::H264Level::kLevel1_1:
|
||||
case webrtc::H264Level::kLevel1_2:
|
||||
case webrtc::H264Level::kLevel1_3:
|
||||
case webrtc::H264Level::kLevel2:
|
||||
case webrtc::H264Level::kLevel2_1:
|
||||
case webrtc::H264Level::kLevel2_2:
|
||||
return kVTProfileLevel_H264_Baseline_AutoLevel;
|
||||
}
|
||||
|
||||
case webrtc::H264::kProfileMain:
|
||||
case webrtc::H264Profile::kProfileMain:
|
||||
switch (profile_level_id.level) {
|
||||
case webrtc::H264::kLevel3:
|
||||
case webrtc::H264Level::kLevel3:
|
||||
return kVTProfileLevel_H264_Main_3_0;
|
||||
case webrtc::H264::kLevel3_1:
|
||||
case webrtc::H264Level::kLevel3_1:
|
||||
return kVTProfileLevel_H264_Main_3_1;
|
||||
case webrtc::H264::kLevel3_2:
|
||||
case webrtc::H264Level::kLevel3_2:
|
||||
return kVTProfileLevel_H264_Main_3_2;
|
||||
case webrtc::H264::kLevel4:
|
||||
case webrtc::H264Level::kLevel4:
|
||||
return kVTProfileLevel_H264_Main_4_0;
|
||||
case webrtc::H264::kLevel4_1:
|
||||
case webrtc::H264Level::kLevel4_1:
|
||||
return kVTProfileLevel_H264_Main_4_1;
|
||||
case webrtc::H264::kLevel4_2:
|
||||
case webrtc::H264Level::kLevel4_2:
|
||||
return kVTProfileLevel_H264_Main_4_2;
|
||||
case webrtc::H264::kLevel5:
|
||||
case webrtc::H264Level::kLevel5:
|
||||
return kVTProfileLevel_H264_Main_5_0;
|
||||
case webrtc::H264::kLevel5_1:
|
||||
case webrtc::H264Level::kLevel5_1:
|
||||
return kVTProfileLevel_H264_Main_5_1;
|
||||
case webrtc::H264::kLevel5_2:
|
||||
case webrtc::H264Level::kLevel5_2:
|
||||
return kVTProfileLevel_H264_Main_5_2;
|
||||
case webrtc::H264::kLevel1:
|
||||
case webrtc::H264::kLevel1_b:
|
||||
case webrtc::H264::kLevel1_1:
|
||||
case webrtc::H264::kLevel1_2:
|
||||
case webrtc::H264::kLevel1_3:
|
||||
case webrtc::H264::kLevel2:
|
||||
case webrtc::H264::kLevel2_1:
|
||||
case webrtc::H264::kLevel2_2:
|
||||
case webrtc::H264Level::kLevel1:
|
||||
case webrtc::H264Level::kLevel1_b:
|
||||
case webrtc::H264Level::kLevel1_1:
|
||||
case webrtc::H264Level::kLevel1_2:
|
||||
case webrtc::H264Level::kLevel1_3:
|
||||
case webrtc::H264Level::kLevel2:
|
||||
case webrtc::H264Level::kLevel2_1:
|
||||
case webrtc::H264Level::kLevel2_2:
|
||||
return kVTProfileLevel_H264_Main_AutoLevel;
|
||||
}
|
||||
|
||||
case webrtc::H264::kProfileConstrainedHigh:
|
||||
case webrtc::H264::kProfileHigh:
|
||||
case webrtc::H264Profile::kProfileConstrainedHigh:
|
||||
case webrtc::H264Profile::kProfileHigh:
|
||||
switch (profile_level_id.level) {
|
||||
case webrtc::H264::kLevel3:
|
||||
case webrtc::H264Level::kLevel3:
|
||||
return kVTProfileLevel_H264_High_3_0;
|
||||
case webrtc::H264::kLevel3_1:
|
||||
case webrtc::H264Level::kLevel3_1:
|
||||
return kVTProfileLevel_H264_High_3_1;
|
||||
case webrtc::H264::kLevel3_2:
|
||||
case webrtc::H264Level::kLevel3_2:
|
||||
return kVTProfileLevel_H264_High_3_2;
|
||||
case webrtc::H264::kLevel4:
|
||||
case webrtc::H264Level::kLevel4:
|
||||
return kVTProfileLevel_H264_High_4_0;
|
||||
case webrtc::H264::kLevel4_1:
|
||||
case webrtc::H264Level::kLevel4_1:
|
||||
return kVTProfileLevel_H264_High_4_1;
|
||||
case webrtc::H264::kLevel4_2:
|
||||
case webrtc::H264Level::kLevel4_2:
|
||||
return kVTProfileLevel_H264_High_4_2;
|
||||
case webrtc::H264::kLevel5:
|
||||
case webrtc::H264Level::kLevel5:
|
||||
return kVTProfileLevel_H264_High_5_0;
|
||||
case webrtc::H264::kLevel5_1:
|
||||
case webrtc::H264Level::kLevel5_1:
|
||||
return kVTProfileLevel_H264_High_5_1;
|
||||
case webrtc::H264::kLevel5_2:
|
||||
case webrtc::H264Level::kLevel5_2:
|
||||
return kVTProfileLevel_H264_High_5_2;
|
||||
case webrtc::H264::kLevel1:
|
||||
case webrtc::H264::kLevel1_b:
|
||||
case webrtc::H264::kLevel1_1:
|
||||
case webrtc::H264::kLevel1_2:
|
||||
case webrtc::H264::kLevel1_3:
|
||||
case webrtc::H264::kLevel2:
|
||||
case webrtc::H264::kLevel2_1:
|
||||
case webrtc::H264::kLevel2_2:
|
||||
case webrtc::H264Level::kLevel1:
|
||||
case webrtc::H264Level::kLevel1_b:
|
||||
case webrtc::H264Level::kLevel1_1:
|
||||
case webrtc::H264Level::kLevel1_2:
|
||||
case webrtc::H264Level::kLevel1_3:
|
||||
case webrtc::H264Level::kLevel2:
|
||||
case webrtc::H264Level::kLevel2_1:
|
||||
case webrtc::H264Level::kLevel2_2:
|
||||
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|.
|
||||
// See https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.264-201610-S!!PDF-E&type=items
|
||||
// for details.
|
||||
NSUInteger GetMaxSampleRate(const webrtc::H264::ProfileLevelId &profile_level_id) {
|
||||
NSUInteger GetMaxSampleRate(const webrtc::H264ProfileLevelId &profile_level_id) {
|
||||
switch (profile_level_id.level) {
|
||||
case webrtc::H264::kLevel3:
|
||||
case webrtc::H264Level::kLevel3:
|
||||
return 10368000;
|
||||
case webrtc::H264::kLevel3_1:
|
||||
case webrtc::H264Level::kLevel3_1:
|
||||
return 27648000;
|
||||
case webrtc::H264::kLevel3_2:
|
||||
case webrtc::H264Level::kLevel3_2:
|
||||
return 55296000;
|
||||
case webrtc::H264::kLevel4:
|
||||
case webrtc::H264::kLevel4_1:
|
||||
case webrtc::H264Level::kLevel4:
|
||||
case webrtc::H264Level::kLevel4_1:
|
||||
return 62914560;
|
||||
case webrtc::H264::kLevel4_2:
|
||||
case webrtc::H264Level::kLevel4_2:
|
||||
return 133693440;
|
||||
case webrtc::H264::kLevel5:
|
||||
case webrtc::H264Level::kLevel5:
|
||||
return 150994944;
|
||||
case webrtc::H264::kLevel5_1:
|
||||
case webrtc::H264Level::kLevel5_1:
|
||||
return 251658240;
|
||||
case webrtc::H264::kLevel5_2:
|
||||
case webrtc::H264Level::kLevel5_2:
|
||||
return 530841600;
|
||||
case webrtc::H264::kLevel1:
|
||||
case webrtc::H264::kLevel1_b:
|
||||
case webrtc::H264::kLevel1_1:
|
||||
case webrtc::H264::kLevel1_2:
|
||||
case webrtc::H264::kLevel1_3:
|
||||
case webrtc::H264::kLevel2:
|
||||
case webrtc::H264::kLevel2_1:
|
||||
case webrtc::H264::kLevel2_2:
|
||||
case webrtc::H264Level::kLevel1:
|
||||
case webrtc::H264Level::kLevel1_b:
|
||||
case webrtc::H264Level::kLevel1_1:
|
||||
case webrtc::H264Level::kLevel1_2:
|
||||
case webrtc::H264Level::kLevel1_3:
|
||||
case webrtc::H264Level::kLevel2:
|
||||
case webrtc::H264Level::kLevel2_1:
|
||||
case webrtc::H264Level::kLevel2_2:
|
||||
// Zero means auto rate setting.
|
||||
return 0;
|
||||
}
|
||||
@ -317,7 +317,7 @@ NSUInteger GetMaxSampleRate(const webrtc::H264::ProfileLevelId &profile_level_id
|
||||
uint32_t _encoderFrameRate;
|
||||
uint32_t _maxAllowedFrameRate;
|
||||
RTCH264PacketizationMode _packetizationMode;
|
||||
absl::optional<webrtc::H264::ProfileLevelId> _profile_level_id;
|
||||
absl::optional<webrtc::H264ProfileLevelId> _profile_level_id;
|
||||
RTCVideoEncoderCallback _callback;
|
||||
int32_t _width;
|
||||
int32_t _height;
|
||||
@ -342,7 +342,7 @@ NSUInteger GetMaxSampleRate(const webrtc::H264::ProfileLevelId &profile_level_id
|
||||
_bitrateAdjuster.reset(new webrtc::BitrateAdjuster(.5, .95));
|
||||
_packetizationMode = RTCH264PacketizationModeNonInterleaved;
|
||||
_profile_level_id =
|
||||
webrtc::H264::ParseSdpProfileLevelId([codecInfo nativeSdpVideoFormat].parameters);
|
||||
webrtc::ParseSdpForH264ProfileLevelId([codecInfo nativeSdpVideoFormat].parameters);
|
||||
RTC_DCHECK(_profile_level_id);
|
||||
RTC_LOG(LS_INFO) << "Using profile " << CFStringToString(ExtractProfile(*_profile_level_id));
|
||||
RTC_CHECK([codecInfo.name isEqualToString:kRTCVideoCodecH264Name]);
|
||||
|
||||
@ -10,10 +10,10 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#include "media/base/h264_profile_level_id.h"
|
||||
#include "api/video_codecs/h264_profile_level_id.h"
|
||||
|
||||
@interface UIDevice (H264Profile)
|
||||
|
||||
+ (absl::optional<webrtc::H264::ProfileLevelId>)maxSupportedH264Profile;
|
||||
+ (absl::optional<webrtc::H264ProfileLevelId>)maxSupportedH264Profile;
|
||||
|
||||
@end
|
||||
|
||||
@ -15,99 +15,156 @@
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace webrtc::H264;
|
||||
using namespace webrtc;
|
||||
|
||||
struct SupportedH264Profile {
|
||||
const RTCDeviceType deviceType;
|
||||
const ProfileLevelId profile;
|
||||
const H264ProfileLevelId profile;
|
||||
};
|
||||
|
||||
constexpr SupportedH264Profile kH264MaxSupportedProfiles[] = {
|
||||
// iPhones with at least iOS 9
|
||||
{RTCDeviceTypeIPhone12ProMax, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP832
|
||||
{RTCDeviceTypeIPhone12Pro, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP831
|
||||
{RTCDeviceTypeIPhone12, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP830
|
||||
{RTCDeviceTypeIPhone12Mini, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP829
|
||||
{RTCDeviceTypeIPhone11ProMax, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP806
|
||||
{RTCDeviceTypeIPhone11Pro, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP805
|
||||
{RTCDeviceTypeIPhone11, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP804
|
||||
{RTCDeviceTypeIPhoneXS, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP779
|
||||
{RTCDeviceTypeIPhoneXSMax, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP780
|
||||
{RTCDeviceTypeIPhoneXR, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP781
|
||||
{RTCDeviceTypeIPhoneX, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP770
|
||||
{RTCDeviceTypeIPhone8, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP767
|
||||
{RTCDeviceTypeIPhone8Plus, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP768
|
||||
{RTCDeviceTypeIPhone7, {kProfileHigh, kLevel5_1}}, // https://support.apple.com/kb/SP743
|
||||
{RTCDeviceTypeIPhone7Plus, {kProfileHigh, kLevel5_1}}, // https://support.apple.com/kb/SP744
|
||||
{RTCDeviceTypeIPhoneSE, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP738
|
||||
{RTCDeviceTypeIPhone6S, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP726
|
||||
{RTCDeviceTypeIPhone6SPlus, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP727
|
||||
{RTCDeviceTypeIPhone6, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP705
|
||||
{RTCDeviceTypeIPhone6Plus, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP706
|
||||
{RTCDeviceTypeIPhone5SGSM, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP685
|
||||
{RTCDeviceTypeIPhone12ProMax,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP832
|
||||
{RTCDeviceTypeIPhone12Pro,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP831
|
||||
{RTCDeviceTypeIPhone12,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP830
|
||||
{RTCDeviceTypeIPhone12Mini,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP829
|
||||
{RTCDeviceTypeIPhone11ProMax,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP806
|
||||
{RTCDeviceTypeIPhone11Pro,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP805
|
||||
{RTCDeviceTypeIPhone11,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP804
|
||||
{RTCDeviceTypeIPhoneXS,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP779
|
||||
{RTCDeviceTypeIPhoneXSMax,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP780
|
||||
{RTCDeviceTypeIPhoneXR,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP781
|
||||
{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,
|
||||
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP685
|
||||
{RTCDeviceTypeIPhone5GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP655
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP685
|
||||
{RTCDeviceTypeIPhone5GSM,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP655
|
||||
{RTCDeviceTypeIPhone5GSM_CDMA,
|
||||
{kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP655
|
||||
{RTCDeviceTypeIPhone5CGSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP684
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP655
|
||||
{RTCDeviceTypeIPhone5CGSM,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP684
|
||||
{RTCDeviceTypeIPhone5CGSM_CDMA,
|
||||
{kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP684
|
||||
{RTCDeviceTypeIPhone4S, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP643
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP684
|
||||
{RTCDeviceTypeIPhone4S,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP643
|
||||
|
||||
// iPods with at least iOS 9
|
||||
{RTCDeviceTypeIPodTouch7G, {kProfileMain, kLevel4_1}}, // https://support.apple.com/kb/SP796
|
||||
{RTCDeviceTypeIPodTouch6G, {kProfileMain, kLevel4_1}}, // https://support.apple.com/kb/SP720
|
||||
{RTCDeviceTypeIPodTouch5G, {kProfileMain, kLevel3_1}}, // https://support.apple.com/kb/SP657
|
||||
{RTCDeviceTypeIPodTouch7G,
|
||||
{H264Profile::kProfileMain, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP796
|
||||
{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
|
||||
{RTCDeviceTypeIPadAir4Gen, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP828
|
||||
{RTCDeviceTypeIPad8, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP822
|
||||
{RTCDeviceTypeIPadPro4Gen12Inch, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP815
|
||||
{RTCDeviceTypeIPadPro4Gen11Inch, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP814
|
||||
{RTCDeviceTypeIPadAir3Gen, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP787
|
||||
{RTCDeviceTypeIPadMini5Gen, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP788
|
||||
{RTCDeviceTypeIPadAir4Gen,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP828
|
||||
{RTCDeviceTypeIPad8,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP822
|
||||
{RTCDeviceTypeIPadPro4Gen12Inch,
|
||||
{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,
|
||||
{kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP785
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP785
|
||||
{RTCDeviceTypeIPadPro3Gen11Inch,
|
||||
{kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP784
|
||||
{RTCDeviceTypeIPad7Gen10Inch, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP807
|
||||
{RTCDeviceTypeIPad2Wifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622
|
||||
{RTCDeviceTypeIPad2GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622
|
||||
{RTCDeviceTypeIPad2CDMA, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622
|
||||
{RTCDeviceTypeIPad2Wifi2, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622
|
||||
{RTCDeviceTypeIPadMiniWifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP661
|
||||
{RTCDeviceTypeIPadMiniGSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP661
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP784
|
||||
{RTCDeviceTypeIPad7Gen10Inch,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP807
|
||||
{RTCDeviceTypeIPad2Wifi,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP622
|
||||
{RTCDeviceTypeIPad2GSM,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP622
|
||||
{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,
|
||||
{kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP661
|
||||
{RTCDeviceTypeIPad3Wifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP647
|
||||
{RTCDeviceTypeIPad3GSM_CDMA, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP647
|
||||
{RTCDeviceTypeIPad3GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP647
|
||||
{RTCDeviceTypeIPad4Wifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP662
|
||||
{RTCDeviceTypeIPad4GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP662
|
||||
{RTCDeviceTypeIPad4GSM_CDMA, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP662
|
||||
{RTCDeviceTypeIPad5, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP751
|
||||
{RTCDeviceTypeIPad6, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP774
|
||||
{RTCDeviceTypeIPadAirWifi, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP692
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP661
|
||||
{RTCDeviceTypeIPad3Wifi,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP647
|
||||
{RTCDeviceTypeIPad3GSM_CDMA,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP647
|
||||
{RTCDeviceTypeIPad3GSM,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP647
|
||||
{RTCDeviceTypeIPad4Wifi,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP662
|
||||
{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,
|
||||
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP692
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP692
|
||||
{RTCDeviceTypeIPadAirWifiCellular,
|
||||
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP692
|
||||
{RTCDeviceTypeIPadAir2, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP708
|
||||
{RTCDeviceTypeIPadMini2GWifi, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP693
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP692
|
||||
{RTCDeviceTypeIPadAir2,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP708
|
||||
{RTCDeviceTypeIPadMini2GWifi,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP693
|
||||
{RTCDeviceTypeIPadMini2GCellular,
|
||||
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP693
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP693
|
||||
{RTCDeviceTypeIPadMini2GWifiCellular,
|
||||
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP693
|
||||
{RTCDeviceTypeIPadMini3, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP709
|
||||
{RTCDeviceTypeIPadMini4, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP725
|
||||
{RTCDeviceTypeIPadPro9Inch, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP739
|
||||
{RTCDeviceTypeIPadPro12Inch, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/sp723
|
||||
{RTCDeviceTypeIPadPro12Inch2, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP761
|
||||
{RTCDeviceTypeIPadPro10Inch, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP762
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP693
|
||||
{RTCDeviceTypeIPadMini3,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP709
|
||||
{RTCDeviceTypeIPadMini4,
|
||||
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP725
|
||||
{RTCDeviceTypeIPadPro9Inch,
|
||||
{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),
|
||||
std::end(kH264MaxSupportedProfiles),
|
||||
[deviceType](const SupportedH264Profile& supportedProfile) {
|
||||
@ -123,7 +180,7 @@ absl::optional<ProfileLevelId> FindMaxSupportedProfileForDevice(RTCDeviceType de
|
||||
|
||||
@implementation UIDevice (H264Profile)
|
||||
|
||||
+ (absl::optional<webrtc::H264::ProfileLevelId>)maxSupportedH264Profile {
|
||||
+ (absl::optional<webrtc::H264ProfileLevelId>)maxSupportedH264Profile {
|
||||
return FindMaxSupportedProfileForDevice([self deviceType]);
|
||||
}
|
||||
|
||||
|
||||
@ -84,7 +84,6 @@ rtc_library("video") {
|
||||
"../call:rtp_sender",
|
||||
"../call:video_stream_api",
|
||||
"../common_video",
|
||||
"../media:rtc_h264_profile_id",
|
||||
"../modules:module_api",
|
||||
"../modules:module_api_public",
|
||||
"../modules/pacing",
|
||||
@ -175,7 +174,6 @@ rtc_source_set("video_legacy") {
|
||||
"../call:rtp_receiver", # For RtxReceiveStream.
|
||||
"../call:video_stream_api",
|
||||
"../common_video",
|
||||
"../media:rtc_h264_profile_id",
|
||||
"../modules:module_api",
|
||||
"../modules/pacing",
|
||||
"../modules/remote_bitrate_estimator",
|
||||
@ -431,7 +429,6 @@ if (rtc_include_tests) {
|
||||
"../api:test_dependency_factory",
|
||||
"../api:video_quality_test_fixture_api",
|
||||
"../api/video_codecs:video_codecs_api",
|
||||
"../media:rtc_vp9_profile",
|
||||
"../modules/pacing",
|
||||
"../modules/video_coding:webrtc_vp9",
|
||||
"../rtc_base/experiments:alr_experiment",
|
||||
@ -463,8 +460,8 @@ if (rtc_include_tests) {
|
||||
"../api:peer_connection_quality_test_fixture_api",
|
||||
"../api:simulated_network_api",
|
||||
"../api:time_controller",
|
||||
"../api/video_codecs:video_codecs_api",
|
||||
"../call:simulated_network",
|
||||
"../media:rtc_vp9_profile",
|
||||
"../modules/video_coding:webrtc_vp9",
|
||||
"../system_wrappers:field_trial",
|
||||
"../test:field_trial",
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
#include "api/video_codecs/sdp_video_format.h"
|
||||
#include "api/video_codecs/video_codec.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 "system_wrappers/include/field_trial.h"
|
||||
#include "test/field_trial.h"
|
||||
|
||||
@ -21,8 +21,8 @@
|
||||
#include "api/test/peerconnection_quality_test_fixture.h"
|
||||
#include "api/test/simulated_network.h"
|
||||
#include "api/test/time_controller.h"
|
||||
#include "api/video_codecs/vp9_profile.h"
|
||||
#include "call/simulated_network.h"
|
||||
#include "media/base/vp9_profile.h"
|
||||
#include "modules/video_coding/codecs/vp9/include/vp9.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
#include "test/field_trial.h"
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "api/array_view.h"
|
||||
#include "api/crypto/frame_decryptor_interface.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/video_codec.h"
|
||||
#include "api/video_codecs/video_decoder_factory.h"
|
||||
@ -31,7 +32,6 @@
|
||||
#include "call/rtp_stream_receiver_controller_interface.h"
|
||||
#include "call/rtx_receive_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/video_coding/include/video_codec_interface.h"
|
||||
#include "modules/video_coding/include/video_coding_defines.h"
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "api/array_view.h"
|
||||
#include "api/crypto/frame_decryptor_interface.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/video_codec.h"
|
||||
#include "api/video_codecs/video_decoder_factory.h"
|
||||
@ -31,7 +32,6 @@
|
||||
#include "call/rtp_stream_receiver_controller_interface.h"
|
||||
#include "call/rtx_receive_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_coding_defines.h"
|
||||
#include "modules/video_coding/include/video_error_codes.h"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user