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": [
|
"create_frame_generator\.h": [
|
||||||
"+system_wrappers/include/clock.h",
|
"+system_wrappers/include/clock.h",
|
||||||
],
|
],
|
||||||
"videocodec_test_fixture\.h": [
|
|
||||||
"+media/base/h264_profile_level_id.h"
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,7 +59,7 @@ class VideoCodecTestFixture {
|
|||||||
class EncodedFrameChecker {
|
class EncodedFrameChecker {
|
||||||
public:
|
public:
|
||||||
virtual ~EncodedFrameChecker() = default;
|
virtual ~EncodedFrameChecker() = default;
|
||||||
virtual void CheckEncodedFrame(webrtc::VideoCodecType codec,
|
virtual void CheckEncodedFrame(VideoCodecType codec,
|
||||||
const EncodedImage& encoded_frame) const = 0;
|
const EncodedImage& encoded_frame) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -123,16 +123,16 @@ class VideoCodecTestFixture {
|
|||||||
bool encode_in_real_time = false;
|
bool encode_in_real_time = false;
|
||||||
|
|
||||||
// Codec settings to use.
|
// Codec settings to use.
|
||||||
webrtc::VideoCodec codec_settings;
|
VideoCodec codec_settings;
|
||||||
|
|
||||||
// Name of the codec being tested.
|
// Name of the codec being tested.
|
||||||
std::string codec_name;
|
std::string codec_name;
|
||||||
|
|
||||||
// H.264 specific settings.
|
// H.264 specific settings.
|
||||||
struct H264CodecSettings {
|
struct H264CodecSettings {
|
||||||
H264::Profile profile = H264::kProfileConstrainedBaseline;
|
H264Profile profile = H264Profile::kProfileConstrainedBaseline;
|
||||||
H264PacketizationMode packetization_mode =
|
H264PacketizationMode packetization_mode =
|
||||||
webrtc::H264PacketizationMode::NonInterleaved;
|
H264PacketizationMode::NonInterleaved;
|
||||||
} h264_codec_settings;
|
} h264_codec_settings;
|
||||||
|
|
||||||
// Custom checker that will be called for each frame.
|
// Custom checker that will be called for each frame.
|
||||||
|
|||||||
@ -15,6 +15,8 @@ if (is_android) {
|
|||||||
rtc_library("video_codecs_api") {
|
rtc_library("video_codecs_api") {
|
||||||
visibility = [ "*" ]
|
visibility = [ "*" ]
|
||||||
sources = [
|
sources = [
|
||||||
|
"h264_profile_level_id.cc",
|
||||||
|
"h264_profile_level_id.h",
|
||||||
"sdp_video_format.cc",
|
"sdp_video_format.cc",
|
||||||
"sdp_video_format.h",
|
"sdp_video_format.h",
|
||||||
"spatial_layer.cc",
|
"spatial_layer.cc",
|
||||||
@ -35,6 +37,8 @@ rtc_library("video_codecs_api") {
|
|||||||
"vp8_frame_config.h",
|
"vp8_frame_config.h",
|
||||||
"vp8_temporal_layers.cc",
|
"vp8_temporal_layers.cc",
|
||||||
"vp8_temporal_layers.h",
|
"vp8_temporal_layers.h",
|
||||||
|
"vp9_profile.cc",
|
||||||
|
"vp9_profile.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
@ -138,7 +142,6 @@ rtc_library("rtc_software_fallback_wrappers") {
|
|||||||
":video_codecs_api",
|
":video_codecs_api",
|
||||||
"..:fec_controller_api",
|
"..:fec_controller_api",
|
||||||
"../../api/video:video_frame",
|
"../../api/video:video_frame",
|
||||||
"../../media:rtc_h264_profile_id",
|
|
||||||
"../../media:rtc_media_base",
|
"../../media:rtc_media_base",
|
||||||
"../../modules/video_coding:video_codec_interface",
|
"../../modules/video_coding:video_codec_interface",
|
||||||
"../../modules/video_coding:video_coding_utility",
|
"../../modules/video_coding:video_coding_utility",
|
||||||
|
|||||||
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
|
testonly = true
|
||||||
sources = [
|
sources = [
|
||||||
"builtin_video_encoder_factory_unittest.cc",
|
"builtin_video_encoder_factory_unittest.cc",
|
||||||
|
"h264_profile_level_id_unittest.cc",
|
||||||
"video_decoder_software_fallback_wrapper_unittest.cc",
|
"video_decoder_software_fallback_wrapper_unittest.cc",
|
||||||
"video_encoder_software_fallback_wrapper_unittest.cc",
|
"video_encoder_software_fallback_wrapper_unittest.cc",
|
||||||
]
|
]
|
||||||
|
|||||||
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
|
* Use of this source code is governed by a BSD-style license
|
||||||
* that can be found in the LICENSE file in the root of the source
|
* that can be found in the LICENSE file in the root of the source
|
||||||
@ -8,7 +8,7 @@
|
|||||||
* be found in the AUTHORS file in the root of the source tree.
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "media/base/vp9_profile.h"
|
#include "api/video_codecs/vp9_profile.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -59,7 +59,7 @@ absl::optional<VP9Profile> ParseSdpForVP9Profile(
|
|||||||
return StringToVP9Profile(profile_str);
|
return StringToVP9Profile(profile_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSameVP9Profile(const SdpVideoFormat::Parameters& params1,
|
bool VP9IsSameProfile(const SdpVideoFormat::Parameters& params1,
|
||||||
const SdpVideoFormat::Parameters& params2) {
|
const SdpVideoFormat::Parameters& params2) {
|
||||||
const absl::optional<VP9Profile> profile = ParseSdpForVP9Profile(params1);
|
const absl::optional<VP9Profile> profile = ParseSdpForVP9Profile(params1);
|
||||||
const absl::optional<VP9Profile> other_profile =
|
const absl::optional<VP9Profile> other_profile =
|
||||||
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/h264_common.h",
|
||||||
"h264/pps_parser.cc",
|
"h264/pps_parser.cc",
|
||||||
"h264/pps_parser.h",
|
"h264/pps_parser.h",
|
||||||
"h264/profile_level_id.h",
|
|
||||||
"h264/sps_parser.cc",
|
"h264/sps_parser.cc",
|
||||||
"h264/sps_parser.h",
|
"h264/sps_parser.h",
|
||||||
"h264/sps_vui_rewriter.cc",
|
"h264/sps_vui_rewriter.cc",
|
||||||
@ -52,7 +51,7 @@ rtc_library("common_video") {
|
|||||||
"../api/video:video_frame",
|
"../api/video:video_frame",
|
||||||
"../api/video:video_rtp_headers",
|
"../api/video:video_rtp_headers",
|
||||||
"../api/video_codecs:bitstream_parser_api",
|
"../api/video_codecs:bitstream_parser_api",
|
||||||
"../media:rtc_h264_profile_id",
|
"../api/video_codecs:video_codecs_api",
|
||||||
"../rtc_base",
|
"../rtc_base",
|
||||||
"../rtc_base:checks",
|
"../rtc_base:checks",
|
||||||
"../rtc_base:rtc_task_queue",
|
"../rtc_base:rtc_task_queue",
|
||||||
@ -90,7 +89,6 @@ if (rtc_include_tests && !build_with_chromium) {
|
|||||||
"frame_rate_estimator_unittest.cc",
|
"frame_rate_estimator_unittest.cc",
|
||||||
"h264/h264_bitstream_parser_unittest.cc",
|
"h264/h264_bitstream_parser_unittest.cc",
|
||||||
"h264/pps_parser_unittest.cc",
|
"h264/pps_parser_unittest.cc",
|
||||||
"h264/profile_level_id_unittest.cc",
|
|
||||||
"h264/sps_parser_unittest.cc",
|
"h264/sps_parser_unittest.cc",
|
||||||
"h264/sps_vui_rewriter_unittest.cc",
|
"h264/sps_vui_rewriter_unittest.cc",
|
||||||
"libyuv/libyuv_unittest.cc",
|
"libyuv/libyuv_unittest.cc",
|
||||||
@ -105,7 +103,7 @@ if (rtc_include_tests && !build_with_chromium) {
|
|||||||
"../api/video:video_frame",
|
"../api/video:video_frame",
|
||||||
"../api/video:video_frame_i010",
|
"../api/video:video_frame_i010",
|
||||||
"../api/video:video_rtp_headers",
|
"../api/video:video_rtp_headers",
|
||||||
"../media:rtc_h264_profile_id",
|
"../api/video_codecs:video_codecs_api",
|
||||||
"../rtc_base",
|
"../rtc_base",
|
||||||
"../rtc_base:checks",
|
"../rtc_base:checks",
|
||||||
"../rtc_base:rtc_base_approved",
|
"../rtc_base:rtc_base_approved",
|
||||||
|
|||||||
@ -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" ]
|
defines = [ "HAVE_WEBRTC_VIDEO" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_library("rtc_h264_profile_id") {
|
# Remove once downstream projects stop depend on this.
|
||||||
|
rtc_source_set("rtc_h264_profile_id") {
|
||||||
visibility = [ "*" ]
|
visibility = [ "*" ]
|
||||||
sources = [
|
sources = [
|
||||||
"base/h264_profile_level_id.cc",
|
"base/h264_profile_level_id.cc",
|
||||||
"base/h264_profile_level_id.h",
|
"base/h264_profile_level_id.h",
|
||||||
]
|
]
|
||||||
|
public_deps = # no-presubmit-check TODO(webrtc:8603)
|
||||||
deps = [
|
[ "../api/video_codecs:video_codecs_api" ]
|
||||||
"../rtc_base",
|
|
||||||
"../rtc_base:checks",
|
|
||||||
"../rtc_base:rtc_base_approved",
|
|
||||||
"../rtc_base/system:rtc_export",
|
|
||||||
]
|
|
||||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_source_set("rtc_media_config") {
|
rtc_source_set("rtc_media_config") {
|
||||||
@ -44,30 +39,24 @@ rtc_source_set("rtc_media_config") {
|
|||||||
sources = [ "base/media_config.h" ]
|
sources = [ "base/media_config.h" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_library("rtc_vp9_profile") {
|
# Remove once downstream projects stop depend on this.
|
||||||
|
rtc_source_set("rtc_vp9_profile") {
|
||||||
visibility = [ "*" ]
|
visibility = [ "*" ]
|
||||||
sources = [
|
sources = [ "base/vp9_profile.h" ]
|
||||||
"base/vp9_profile.cc",
|
public_deps = # no-presubmit-check TODO(webrtc:8603)
|
||||||
"base/vp9_profile.h",
|
[ "../api/video_codecs:video_codecs_api" ]
|
||||||
]
|
|
||||||
|
|
||||||
deps = [
|
|
||||||
"../api/video_codecs:video_codecs_api",
|
|
||||||
"../rtc_base:rtc_base_approved",
|
|
||||||
"../rtc_base/system:rtc_export",
|
|
||||||
]
|
|
||||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rtc_library("rtc_sdp_fmtp_utils") {
|
rtc_library("rtc_sdp_video_format_utils") {
|
||||||
visibility = [ "*" ]
|
visibility = [ "*" ]
|
||||||
sources = [
|
sources = [
|
||||||
"base/sdp_fmtp_utils.cc",
|
"base/sdp_video_format_utils.cc",
|
||||||
"base/sdp_fmtp_utils.h",
|
"base/sdp_video_format_utils.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
"../api/video_codecs:video_codecs_api",
|
"../api/video_codecs:video_codecs_api",
|
||||||
|
"../rtc_base:checks",
|
||||||
"../rtc_base:stringutils",
|
"../rtc_base:stringutils",
|
||||||
]
|
]
|
||||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||||
@ -78,9 +67,7 @@ rtc_library("rtc_media_base") {
|
|||||||
defines = []
|
defines = []
|
||||||
libs = []
|
libs = []
|
||||||
deps = [
|
deps = [
|
||||||
":rtc_h264_profile_id",
|
|
||||||
":rtc_media_config",
|
":rtc_media_config",
|
||||||
":rtc_vp9_profile",
|
|
||||||
"../api:array_view",
|
"../api:array_view",
|
||||||
"../api:audio_options_api",
|
"../api:audio_options_api",
|
||||||
"../api:frame_transformer_interface",
|
"../api:frame_transformer_interface",
|
||||||
@ -221,7 +208,6 @@ rtc_library("rtc_internal_video_codecs") {
|
|||||||
libs = []
|
libs = []
|
||||||
deps = [
|
deps = [
|
||||||
":rtc_encoder_simulcast_proxy",
|
":rtc_encoder_simulcast_proxy",
|
||||||
":rtc_h264_profile_id",
|
|
||||||
":rtc_media_base",
|
":rtc_media_base",
|
||||||
":rtc_simulcast_encoder_adapter",
|
":rtc_simulcast_encoder_adapter",
|
||||||
"../api/video:encoded_image",
|
"../api/video:encoded_image",
|
||||||
@ -555,9 +541,8 @@ if (rtc_include_tests) {
|
|||||||
":rtc_media_base",
|
":rtc_media_base",
|
||||||
":rtc_media_engine_defaults",
|
":rtc_media_engine_defaults",
|
||||||
":rtc_media_tests_utils",
|
":rtc_media_tests_utils",
|
||||||
":rtc_sdp_fmtp_utils",
|
":rtc_sdp_video_format_utils",
|
||||||
":rtc_simulcast_encoder_adapter",
|
":rtc_simulcast_encoder_adapter",
|
||||||
":rtc_vp9_profile",
|
|
||||||
"../api:create_simulcast_test_fixture_api",
|
"../api:create_simulcast_test_fixture_api",
|
||||||
"../api:libjingle_peerconnection_api",
|
"../api:libjingle_peerconnection_api",
|
||||||
"../api:mock_video_bitrate_allocator",
|
"../api:mock_video_bitrate_allocator",
|
||||||
@ -586,7 +571,6 @@ if (rtc_include_tests) {
|
|||||||
"../audio",
|
"../audio",
|
||||||
"../call:call_interfaces",
|
"../call:call_interfaces",
|
||||||
"../common_video",
|
"../common_video",
|
||||||
"../media:rtc_h264_profile_id",
|
|
||||||
"../modules/audio_device:mock_audio_device",
|
"../modules/audio_device:mock_audio_device",
|
||||||
"../modules/audio_processing",
|
"../modules/audio_processing",
|
||||||
"../modules/audio_processing:api",
|
"../modules/audio_processing:api",
|
||||||
@ -627,7 +611,7 @@ if (rtc_include_tests) {
|
|||||||
"base/codec_unittest.cc",
|
"base/codec_unittest.cc",
|
||||||
"base/media_engine_unittest.cc",
|
"base/media_engine_unittest.cc",
|
||||||
"base/rtp_utils_unittest.cc",
|
"base/rtp_utils_unittest.cc",
|
||||||
"base/sdp_fmtp_utils_unittest.cc",
|
"base/sdp_video_format_utils_unittest.cc",
|
||||||
"base/stream_params_unittest.cc",
|
"base/stream_params_unittest.cc",
|
||||||
"base/turn_utils_unittest.cc",
|
"base/turn_utils_unittest.cc",
|
||||||
"base/video_adapter_unittest.cc",
|
"base/video_adapter_unittest.cc",
|
||||||
|
|||||||
@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
#include "absl/algorithm/container.h"
|
#include "absl/algorithm/container.h"
|
||||||
#include "absl/strings/match.h"
|
#include "absl/strings/match.h"
|
||||||
#include "media/base/h264_profile_level_id.h"
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
#include "media/base/vp9_profile.h"
|
#include "api/video_codecs/vp9_profile.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
#include "rtc_base/logging.h"
|
#include "rtc_base/logging.h"
|
||||||
#include "rtc_base/string_encode.h"
|
#include "rtc_base/string_encode.h"
|
||||||
@ -51,10 +51,10 @@ bool IsSameCodecSpecific(const std::string& name1,
|
|||||||
absl::EqualsIgnoreCase(name, name2);
|
absl::EqualsIgnoreCase(name, name2);
|
||||||
};
|
};
|
||||||
if (either_name_matches(kH264CodecName))
|
if (either_name_matches(kH264CodecName))
|
||||||
return webrtc::H264::IsSameH264Profile(params1, params2) &&
|
return webrtc::H264IsSameProfile(params1, params2) &&
|
||||||
IsSameH264PacketizationMode(params1, params2);
|
IsSameH264PacketizationMode(params1, params2);
|
||||||
if (either_name_matches(kVp9CodecName))
|
if (either_name_matches(kVp9CodecName))
|
||||||
return webrtc::IsSameVP9Profile(params1, params2);
|
return webrtc::VP9IsSameProfile(params1, params2);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,15 +473,16 @@ void AddH264ConstrainedBaselineProfileToSupportedFormats(
|
|||||||
for (auto it = supported_formats->cbegin(); it != supported_formats->cend();
|
for (auto it = supported_formats->cbegin(); it != supported_formats->cend();
|
||||||
++it) {
|
++it) {
|
||||||
if (it->name == cricket::kH264CodecName) {
|
if (it->name == cricket::kH264CodecName) {
|
||||||
const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
|
const absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
|
||||||
webrtc::H264::ParseSdpProfileLevelId(it->parameters);
|
webrtc::ParseSdpForH264ProfileLevelId(it->parameters);
|
||||||
if (profile_level_id && profile_level_id->profile !=
|
if (profile_level_id &&
|
||||||
webrtc::H264::kProfileConstrainedBaseline) {
|
profile_level_id->profile !=
|
||||||
|
webrtc::H264Profile::kProfileConstrainedBaseline) {
|
||||||
webrtc::SdpVideoFormat cbp_format = *it;
|
webrtc::SdpVideoFormat cbp_format = *it;
|
||||||
webrtc::H264::ProfileLevelId cbp_profile = *profile_level_id;
|
webrtc::H264ProfileLevelId cbp_profile = *profile_level_id;
|
||||||
cbp_profile.profile = webrtc::H264::kProfileConstrainedBaseline;
|
cbp_profile.profile = webrtc::H264Profile::kProfileConstrainedBaseline;
|
||||||
cbp_format.parameters[cricket::kH264FmtpProfileLevelId] =
|
cbp_format.parameters[cricket::kH264FmtpProfileLevelId] =
|
||||||
*webrtc::H264::ProfileLevelIdToString(cbp_profile);
|
*webrtc::H264ProfileLevelIdToString(cbp_profile);
|
||||||
cbr_supported_formats.push_back(cbp_format);
|
cbr_supported_formats.push_back(cbp_format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
#include "media/base/h264_profile_level_id.h"
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
#include "media/base/vp9_profile.h"
|
#include "api/video_codecs/vp9_profile.h"
|
||||||
#include "modules/video_coding/codecs/h264/include/h264.h"
|
#include "modules/video_coding/codecs/h264/include/h264.h"
|
||||||
#include "rtc_base/gunit.h"
|
#include "rtc_base/gunit.h"
|
||||||
|
|
||||||
@ -457,10 +457,10 @@ TEST(CodecTest, TestToCodecParameters) {
|
|||||||
|
|
||||||
TEST(CodecTest, H264CostrainedBaselineIsAddedIfH264IsSupported) {
|
TEST(CodecTest, H264CostrainedBaselineIsAddedIfH264IsSupported) {
|
||||||
const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = {
|
const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = {
|
||||||
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
|
webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
|
||||||
webrtc::H264::kLevel3_1, "1"),
|
webrtc::H264Level::kLevel3_1, "1"),
|
||||||
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
|
webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
|
||||||
webrtc::H264::kLevel3_1, "0")};
|
webrtc::H264Level::kLevel3_1, "0")};
|
||||||
|
|
||||||
std::vector<webrtc::SdpVideoFormat> supported_formats =
|
std::vector<webrtc::SdpVideoFormat> supported_formats =
|
||||||
kExplicitlySupportedFormats;
|
kExplicitlySupportedFormats;
|
||||||
@ -468,11 +468,11 @@ TEST(CodecTest, H264CostrainedBaselineIsAddedIfH264IsSupported) {
|
|||||||
&supported_formats);
|
&supported_formats);
|
||||||
|
|
||||||
const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization1 =
|
const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization1 =
|
||||||
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
|
webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
|
||||||
webrtc::H264::kLevel3_1, "1");
|
webrtc::H264Level::kLevel3_1, "1");
|
||||||
const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization0 =
|
const webrtc::SdpVideoFormat kH264ConstrainedBasedlinePacketization0 =
|
||||||
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
|
webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
|
||||||
webrtc::H264::kLevel3_1, "0");
|
webrtc::H264Level::kLevel3_1, "0");
|
||||||
|
|
||||||
EXPECT_EQ(supported_formats[0], kExplicitlySupportedFormats[0]);
|
EXPECT_EQ(supported_formats[0], kExplicitlySupportedFormats[0]);
|
||||||
EXPECT_EQ(supported_formats[1], kExplicitlySupportedFormats[1]);
|
EXPECT_EQ(supported_formats[1], kExplicitlySupportedFormats[1]);
|
||||||
@ -497,14 +497,14 @@ TEST(CodecTest, H264CostrainedBaselineIsNotAddedIfH264IsUnsupported) {
|
|||||||
|
|
||||||
TEST(CodecTest, H264CostrainedBaselineNotAddedIfAlreadySpecified) {
|
TEST(CodecTest, H264CostrainedBaselineNotAddedIfAlreadySpecified) {
|
||||||
const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = {
|
const std::vector<webrtc::SdpVideoFormat> kExplicitlySupportedFormats = {
|
||||||
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
|
webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
|
||||||
webrtc::H264::kLevel3_1, "1"),
|
webrtc::H264Level::kLevel3_1, "1"),
|
||||||
webrtc::CreateH264Format(webrtc::H264::kProfileBaseline,
|
webrtc::CreateH264Format(webrtc::H264Profile::kProfileBaseline,
|
||||||
webrtc::H264::kLevel3_1, "0"),
|
webrtc::H264Level::kLevel3_1, "0"),
|
||||||
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
|
webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
|
||||||
webrtc::H264::kLevel3_1, "1"),
|
webrtc::H264Level::kLevel3_1, "1"),
|
||||||
webrtc::CreateH264Format(webrtc::H264::kProfileConstrainedBaseline,
|
webrtc::CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline,
|
||||||
webrtc::H264::kLevel3_1, "0")};
|
webrtc::H264Level::kLevel3_1, "0")};
|
||||||
|
|
||||||
std::vector<webrtc::SdpVideoFormat> supported_formats =
|
std::vector<webrtc::SdpVideoFormat> supported_formats =
|
||||||
kExplicitlySupportedFormats;
|
kExplicitlySupportedFormats;
|
||||||
|
|||||||
@ -10,301 +10,33 @@
|
|||||||
|
|
||||||
#include "media/base/h264_profile_level_id.h"
|
#include "media/base/h264_profile_level_id.h"
|
||||||
|
|
||||||
#include <cstdio>
|
// TODO(crbug.com/1187565): Remove this file once downstream projects stop
|
||||||
#include <cstdlib>
|
// depend on it.
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include "rtc_base/arraysize.h"
|
|
||||||
#include "rtc_base/checks.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
namespace H264 {
|
namespace H264 {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const char kProfileLevelId[] = "profile-level-id";
|
|
||||||
const char kLevelAsymmetryAllowed[] = "level-asymmetry-allowed";
|
|
||||||
|
|
||||||
// For level_idc=11 and profile_idc=0x42, 0x4D, or 0x58, the constraint set3
|
|
||||||
// flag specifies if level 1b or level 1.1 is used.
|
|
||||||
const uint8_t kConstraintSet3Flag = 0x10;
|
|
||||||
|
|
||||||
// Convert a string of 8 characters into a byte where the positions containing
|
|
||||||
// character c will have their bit set. For example, c = 'x', str = "x1xx0000"
|
|
||||||
// will return 0b10110000. constexpr is used so that the pattern table in
|
|
||||||
// kProfilePatterns is statically initialized.
|
|
||||||
constexpr uint8_t ByteMaskString(char c, const char (&str)[9]) {
|
|
||||||
return (str[0] == c) << 7 | (str[1] == c) << 6 | (str[2] == c) << 5 |
|
|
||||||
(str[3] == c) << 4 | (str[4] == c) << 3 | (str[5] == c) << 2 |
|
|
||||||
(str[6] == c) << 1 | (str[7] == c) << 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Class for matching bit patterns such as "x1xx0000" where 'x' is allowed to be
|
|
||||||
// either 0 or 1.
|
|
||||||
class BitPattern {
|
|
||||||
public:
|
|
||||||
explicit constexpr BitPattern(const char (&str)[9])
|
|
||||||
: mask_(~ByteMaskString('x', str)),
|
|
||||||
masked_value_(ByteMaskString('1', str)) {}
|
|
||||||
|
|
||||||
bool IsMatch(uint8_t value) const { return masked_value_ == (value & mask_); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
const uint8_t mask_;
|
|
||||||
const uint8_t masked_value_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Table for converting between profile_idc/profile_iop to H264::Profile.
|
|
||||||
struct ProfilePattern {
|
|
||||||
const uint8_t profile_idc;
|
|
||||||
const BitPattern profile_iop;
|
|
||||||
const Profile profile;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is from https://tools.ietf.org/html/rfc6184#section-8.1.
|
|
||||||
constexpr ProfilePattern kProfilePatterns[] = {
|
|
||||||
{0x42, BitPattern("x1xx0000"), kProfileConstrainedBaseline},
|
|
||||||
{0x4D, BitPattern("1xxx0000"), kProfileConstrainedBaseline},
|
|
||||||
{0x58, BitPattern("11xx0000"), kProfileConstrainedBaseline},
|
|
||||||
{0x42, BitPattern("x0xx0000"), kProfileBaseline},
|
|
||||||
{0x58, BitPattern("10xx0000"), kProfileBaseline},
|
|
||||||
{0x4D, BitPattern("0x0x0000"), kProfileMain},
|
|
||||||
{0x64, BitPattern("00000000"), kProfileHigh},
|
|
||||||
{0x64, BitPattern("00001100"), kProfileConstrainedHigh}};
|
|
||||||
|
|
||||||
// Compare H264 levels and handle the level 1b case.
|
|
||||||
bool IsLess(Level a, Level b) {
|
|
||||||
if (a == kLevel1_b)
|
|
||||||
return b != kLevel1 && b != kLevel1_b;
|
|
||||||
if (b == kLevel1_b)
|
|
||||||
return a == kLevel1;
|
|
||||||
return a < b;
|
|
||||||
}
|
|
||||||
|
|
||||||
Level Min(Level a, Level b) {
|
|
||||||
return IsLess(a, b) ? a : b;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsLevelAsymmetryAllowed(const CodecParameterMap& params) {
|
|
||||||
const auto it = params.find(kLevelAsymmetryAllowed);
|
|
||||||
return it != params.end() && strcmp(it->second.c_str(), "1") == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LevelConstraint {
|
|
||||||
const int max_macroblocks_per_second;
|
|
||||||
const int max_macroblock_frame_size;
|
|
||||||
const webrtc::H264::Level level;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is from ITU-T H.264 (02/2016) Table A-1 – Level limits.
|
|
||||||
static constexpr LevelConstraint kLevelConstraints[] = {
|
|
||||||
{1485, 99, webrtc::H264::kLevel1},
|
|
||||||
{1485, 99, webrtc::H264::kLevel1_b},
|
|
||||||
{3000, 396, webrtc::H264::kLevel1_1},
|
|
||||||
{6000, 396, webrtc::H264::kLevel1_2},
|
|
||||||
{11880, 396, webrtc::H264::kLevel1_3},
|
|
||||||
{11880, 396, webrtc::H264::kLevel2},
|
|
||||||
{19800, 792, webrtc::H264::kLevel2_1},
|
|
||||||
{20250, 1620, webrtc::H264::kLevel2_2},
|
|
||||||
{40500, 1620, webrtc::H264::kLevel3},
|
|
||||||
{108000, 3600, webrtc::H264::kLevel3_1},
|
|
||||||
{216000, 5120, webrtc::H264::kLevel3_2},
|
|
||||||
{245760, 8192, webrtc::H264::kLevel4},
|
|
||||||
{245760, 8192, webrtc::H264::kLevel4_1},
|
|
||||||
{522240, 8704, webrtc::H264::kLevel4_2},
|
|
||||||
{589824, 22080, webrtc::H264::kLevel5},
|
|
||||||
{983040, 36864, webrtc::H264::kLevel5_1},
|
|
||||||
{2073600, 36864, webrtc::H264::kLevel5_2},
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
absl::optional<ProfileLevelId> ParseProfileLevelId(const char* str) {
|
absl::optional<ProfileLevelId> ParseProfileLevelId(const char* str) {
|
||||||
// The string should consist of 3 bytes in hexadecimal format.
|
return webrtc::ParseH264ProfileLevelId(str);
|
||||||
if (strlen(str) != 6u)
|
|
||||||
return absl::nullopt;
|
|
||||||
const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16);
|
|
||||||
if (profile_level_id_numeric == 0)
|
|
||||||
return absl::nullopt;
|
|
||||||
|
|
||||||
// Separate into three bytes.
|
|
||||||
const uint8_t level_idc =
|
|
||||||
static_cast<uint8_t>(profile_level_id_numeric & 0xFF);
|
|
||||||
const uint8_t profile_iop =
|
|
||||||
static_cast<uint8_t>((profile_level_id_numeric >> 8) & 0xFF);
|
|
||||||
const uint8_t profile_idc =
|
|
||||||
static_cast<uint8_t>((profile_level_id_numeric >> 16) & 0xFF);
|
|
||||||
|
|
||||||
// Parse level based on level_idc and constraint set 3 flag.
|
|
||||||
Level level;
|
|
||||||
switch (level_idc) {
|
|
||||||
case kLevel1_1:
|
|
||||||
level = (profile_iop & kConstraintSet3Flag) != 0 ? kLevel1_b : kLevel1_1;
|
|
||||||
break;
|
|
||||||
case kLevel1:
|
|
||||||
case kLevel1_2:
|
|
||||||
case kLevel1_3:
|
|
||||||
case kLevel2:
|
|
||||||
case kLevel2_1:
|
|
||||||
case kLevel2_2:
|
|
||||||
case kLevel3:
|
|
||||||
case kLevel3_1:
|
|
||||||
case kLevel3_2:
|
|
||||||
case kLevel4:
|
|
||||||
case kLevel4_1:
|
|
||||||
case kLevel4_2:
|
|
||||||
case kLevel5:
|
|
||||||
case kLevel5_1:
|
|
||||||
case kLevel5_2:
|
|
||||||
level = static_cast<Level>(level_idc);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Unrecognized level_idc.
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse profile_idc/profile_iop into a Profile enum.
|
|
||||||
for (const ProfilePattern& pattern : kProfilePatterns) {
|
|
||||||
if (profile_idc == pattern.profile_idc &&
|
|
||||||
pattern.profile_iop.IsMatch(profile_iop)) {
|
|
||||||
return ProfileLevelId(pattern.profile, level);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unrecognized profile_idc/profile_iop combination.
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
absl::optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps) {
|
|
||||||
static const int kPixelsPerMacroblock = 16 * 16;
|
|
||||||
|
|
||||||
for (int i = arraysize(kLevelConstraints) - 1; i >= 0; --i) {
|
|
||||||
const LevelConstraint& level_constraint = kLevelConstraints[i];
|
|
||||||
if (level_constraint.max_macroblock_frame_size * kPixelsPerMacroblock <=
|
|
||||||
max_frame_pixel_count &&
|
|
||||||
level_constraint.max_macroblocks_per_second <=
|
|
||||||
max_fps * level_constraint.max_macroblock_frame_size) {
|
|
||||||
return level_constraint.level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No level supported.
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::optional<ProfileLevelId> ParseSdpProfileLevelId(
|
absl::optional<ProfileLevelId> ParseSdpProfileLevelId(
|
||||||
const CodecParameterMap& params) {
|
const SdpVideoFormat::Parameters& params) {
|
||||||
// TODO(magjed): The default should really be kProfileBaseline and kLevel1
|
return webrtc::ParseSdpForH264ProfileLevelId(params);
|
||||||
// according to the spec: https://tools.ietf.org/html/rfc6184#section-8.1. In
|
}
|
||||||
// order to not break backwards compatibility with older versions of WebRTC
|
|
||||||
// where external codecs don't have any parameters, use
|
|
||||||
// kProfileConstrainedBaseline kLevel3_1 instead. This workaround will only be
|
|
||||||
// done in an interim period to allow external clients to update their code.
|
|
||||||
// http://crbug/webrtc/6337.
|
|
||||||
static const ProfileLevelId kDefaultProfileLevelId(
|
|
||||||
kProfileConstrainedBaseline, kLevel3_1);
|
|
||||||
|
|
||||||
const auto profile_level_id_it = params.find(kProfileLevelId);
|
absl::optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps) {
|
||||||
return (profile_level_id_it == params.end())
|
return webrtc::H264SupportedLevel(max_frame_pixel_count, max_fps);
|
||||||
? kDefaultProfileLevelId
|
|
||||||
: ParseProfileLevelId(profile_level_id_it->second.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::optional<std::string> ProfileLevelIdToString(
|
absl::optional<std::string> ProfileLevelIdToString(
|
||||||
const ProfileLevelId& profile_level_id) {
|
const ProfileLevelId& profile_level_id) {
|
||||||
// Handle special case level == 1b.
|
return webrtc::H264ProfileLevelIdToString(profile_level_id);
|
||||||
if (profile_level_id.level == kLevel1_b) {
|
|
||||||
switch (profile_level_id.profile) {
|
|
||||||
case kProfileConstrainedBaseline:
|
|
||||||
return {"42f00b"};
|
|
||||||
case kProfileBaseline:
|
|
||||||
return {"42100b"};
|
|
||||||
case kProfileMain:
|
|
||||||
return {"4d100b"};
|
|
||||||
// Level 1b is not allowed for other profiles.
|
|
||||||
default:
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* profile_idc_iop_string;
|
|
||||||
switch (profile_level_id.profile) {
|
|
||||||
case kProfileConstrainedBaseline:
|
|
||||||
profile_idc_iop_string = "42e0";
|
|
||||||
break;
|
|
||||||
case kProfileBaseline:
|
|
||||||
profile_idc_iop_string = "4200";
|
|
||||||
break;
|
|
||||||
case kProfileMain:
|
|
||||||
profile_idc_iop_string = "4d00";
|
|
||||||
break;
|
|
||||||
case kProfileConstrainedHigh:
|
|
||||||
profile_idc_iop_string = "640c";
|
|
||||||
break;
|
|
||||||
case kProfileHigh:
|
|
||||||
profile_idc_iop_string = "6400";
|
|
||||||
break;
|
|
||||||
// Unrecognized profile.
|
|
||||||
default:
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
char str[7];
|
|
||||||
snprintf(str, 7u, "%s%02x", profile_idc_iop_string, profile_level_id.level);
|
|
||||||
return {str};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set level according to https://tools.ietf.org/html/rfc6184#section-8.2.2.
|
bool IsSameH264Profile(const SdpVideoFormat::Parameters& params1,
|
||||||
void GenerateProfileLevelIdForAnswer(
|
const SdpVideoFormat::Parameters& params2) {
|
||||||
const CodecParameterMap& local_supported_params,
|
return webrtc::H264IsSameProfile(params1, params2);
|
||||||
const CodecParameterMap& remote_offered_params,
|
|
||||||
CodecParameterMap* answer_params) {
|
|
||||||
// If both local and remote haven't set profile-level-id, they are both using
|
|
||||||
// the default profile. In this case, don't set profile-level-id in answer
|
|
||||||
// either.
|
|
||||||
if (!local_supported_params.count(kProfileLevelId) &&
|
|
||||||
!remote_offered_params.count(kProfileLevelId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse profile-level-ids.
|
|
||||||
const absl::optional<ProfileLevelId> local_profile_level_id =
|
|
||||||
ParseSdpProfileLevelId(local_supported_params);
|
|
||||||
const absl::optional<ProfileLevelId> remote_profile_level_id =
|
|
||||||
ParseSdpProfileLevelId(remote_offered_params);
|
|
||||||
// The local and remote codec must have valid and equal H264 Profiles.
|
|
||||||
RTC_DCHECK(local_profile_level_id);
|
|
||||||
RTC_DCHECK(remote_profile_level_id);
|
|
||||||
RTC_DCHECK_EQ(local_profile_level_id->profile,
|
|
||||||
remote_profile_level_id->profile);
|
|
||||||
|
|
||||||
// Parse level information.
|
|
||||||
const bool level_asymmetry_allowed =
|
|
||||||
IsLevelAsymmetryAllowed(local_supported_params) &&
|
|
||||||
IsLevelAsymmetryAllowed(remote_offered_params);
|
|
||||||
const Level local_level = local_profile_level_id->level;
|
|
||||||
const Level remote_level = remote_profile_level_id->level;
|
|
||||||
const Level min_level = Min(local_level, remote_level);
|
|
||||||
|
|
||||||
// Determine answer level. When level asymmetry is not allowed, level upgrade
|
|
||||||
// is not allowed, i.e., the level in the answer must be equal to or lower
|
|
||||||
// than the level in the offer.
|
|
||||||
const Level answer_level = level_asymmetry_allowed ? local_level : min_level;
|
|
||||||
|
|
||||||
// Set the resulting profile-level-id in the answer parameters.
|
|
||||||
(*answer_params)[kProfileLevelId] = *ProfileLevelIdToString(
|
|
||||||
ProfileLevelId(local_profile_level_id->profile, answer_level));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsSameH264Profile(const CodecParameterMap& params1,
|
|
||||||
const CodecParameterMap& params2) {
|
|
||||||
const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
|
|
||||||
webrtc::H264::ParseSdpProfileLevelId(params1);
|
|
||||||
const absl::optional<webrtc::H264::ProfileLevelId> other_profile_level_id =
|
|
||||||
webrtc::H264::ParseSdpProfileLevelId(params2);
|
|
||||||
// Compare H264 profiles, but not levels.
|
|
||||||
return profile_level_id && other_profile_level_id &&
|
|
||||||
profile_level_id->profile == other_profile_level_id->profile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace H264
|
} // namespace H264
|
||||||
|
|||||||
@ -11,54 +11,45 @@
|
|||||||
#ifndef MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
|
#ifndef MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
|
||||||
#define MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
|
#define MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "absl/types/optional.h"
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
#include "rtc_base/system/rtc_export.h"
|
|
||||||
|
// TODO(crbug.com/1187565): Remove this file once downstream projects stop
|
||||||
|
// depend on it.
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
namespace H264 {
|
namespace H264 {
|
||||||
|
|
||||||
enum Profile {
|
typedef H264Profile Profile;
|
||||||
kProfileConstrainedBaseline,
|
typedef H264Level Level;
|
||||||
kProfileBaseline,
|
typedef H264ProfileLevelId ProfileLevelId;
|
||||||
kProfileMain,
|
|
||||||
kProfileConstrainedHigh,
|
|
||||||
kProfileHigh,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Map containting SDP codec parameters.
|
constexpr H264Profile kProfileConstrainedBaseline =
|
||||||
typedef std::map<std::string, std::string> CodecParameterMap;
|
H264Profile::kProfileConstrainedBaseline;
|
||||||
|
constexpr H264Profile kProfileBaseline = H264Profile::kProfileBaseline;
|
||||||
|
constexpr H264Profile kProfileMain = H264Profile::kProfileMain;
|
||||||
|
constexpr H264Profile kProfileConstrainedHigh =
|
||||||
|
H264Profile::kProfileConstrainedHigh;
|
||||||
|
constexpr H264Profile kProfileHigh = H264Profile::kProfileHigh;
|
||||||
|
|
||||||
// All values are equal to ten times the level number, except level 1b which is
|
constexpr H264Level kLevel1_b = H264Level::kLevel1_b;
|
||||||
// special.
|
constexpr H264Level kLevel1 = H264Level::kLevel1;
|
||||||
enum Level {
|
constexpr H264Level kLevel1_1 = H264Level::kLevel1_1;
|
||||||
kLevel1_b = 0,
|
constexpr H264Level kLevel1_2 = H264Level::kLevel1_2;
|
||||||
kLevel1 = 10,
|
constexpr H264Level kLevel1_3 = H264Level::kLevel1_3;
|
||||||
kLevel1_1 = 11,
|
constexpr H264Level kLevel2 = H264Level::kLevel2;
|
||||||
kLevel1_2 = 12,
|
constexpr H264Level kLevel2_1 = H264Level::kLevel2_1;
|
||||||
kLevel1_3 = 13,
|
constexpr H264Level kLevel2_2 = H264Level::kLevel2_2;
|
||||||
kLevel2 = 20,
|
constexpr H264Level kLevel3 = H264Level::kLevel3;
|
||||||
kLevel2_1 = 21,
|
constexpr H264Level kLevel3_1 = H264Level::kLevel3_1;
|
||||||
kLevel2_2 = 22,
|
constexpr H264Level kLevel3_2 = H264Level::kLevel3_2;
|
||||||
kLevel3 = 30,
|
constexpr H264Level kLevel4 = H264Level::kLevel4;
|
||||||
kLevel3_1 = 31,
|
constexpr H264Level kLevel4_1 = H264Level::kLevel4_1;
|
||||||
kLevel3_2 = 32,
|
constexpr H264Level kLevel4_2 = H264Level::kLevel4_2;
|
||||||
kLevel4 = 40,
|
constexpr H264Level kLevel5 = H264Level::kLevel5;
|
||||||
kLevel4_1 = 41,
|
constexpr H264Level kLevel5_1 = H264Level::kLevel5_1;
|
||||||
kLevel4_2 = 42,
|
constexpr H264Level kLevel5_2 = H264Level::kLevel5_2;
|
||||||
kLevel5 = 50,
|
|
||||||
kLevel5_1 = 51,
|
|
||||||
kLevel5_2 = 52
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ProfileLevelId {
|
|
||||||
constexpr ProfileLevelId(Profile profile, Level level)
|
|
||||||
: profile(profile), level(level) {}
|
|
||||||
Profile profile;
|
|
||||||
Level level;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse profile level id that is represented as a string of 3 hex bytes.
|
// Parse profile level id that is represented as a string of 3 hex bytes.
|
||||||
// Nothing will be returned if the string is not a recognized H264
|
// Nothing will be returned if the string is not a recognized H264
|
||||||
@ -70,7 +61,7 @@ absl::optional<ProfileLevelId> ParseProfileLevelId(const char* str);
|
|||||||
// returned if the profile-level-id key is missing. Nothing will be returned if
|
// returned if the profile-level-id key is missing. Nothing will be returned if
|
||||||
// the key is present but the string is invalid.
|
// the key is present but the string is invalid.
|
||||||
RTC_EXPORT absl::optional<ProfileLevelId> ParseSdpProfileLevelId(
|
RTC_EXPORT absl::optional<ProfileLevelId> ParseSdpProfileLevelId(
|
||||||
const CodecParameterMap& params);
|
const SdpVideoFormat::Parameters& params);
|
||||||
|
|
||||||
// Given that a decoder supports up to a given frame size (in pixels) at up to a
|
// Given that a decoder supports up to a given frame size (in pixels) at up to a
|
||||||
// given number of frames per second, return the highest H.264 level where it
|
// given number of frames per second, return the highest H.264 level where it
|
||||||
@ -84,33 +75,11 @@ RTC_EXPORT absl::optional<Level> SupportedLevel(int max_frame_pixel_count,
|
|||||||
RTC_EXPORT absl::optional<std::string> ProfileLevelIdToString(
|
RTC_EXPORT absl::optional<std::string> ProfileLevelIdToString(
|
||||||
const ProfileLevelId& profile_level_id);
|
const ProfileLevelId& profile_level_id);
|
||||||
|
|
||||||
// Generate codec parameters that will be used as answer in an SDP negotiation
|
|
||||||
// based on local supported parameters and remote offered parameters. Both
|
|
||||||
// |local_supported_params|, |remote_offered_params|, and |answer_params|
|
|
||||||
// represent sendrecv media descriptions, i.e they are a mix of both encode and
|
|
||||||
// decode capabilities. In theory, when the profile in |local_supported_params|
|
|
||||||
// represent a strict superset of the profile in |remote_offered_params|, we
|
|
||||||
// could limit the profile in |answer_params| to the profile in
|
|
||||||
// |remote_offered_params|. However, to simplify the code, each supported H264
|
|
||||||
// profile should be listed explicitly in the list of local supported codecs,
|
|
||||||
// even if they are redundant. Then each local codec in the list should be
|
|
||||||
// tested one at a time against the remote codec, and only when the profiles are
|
|
||||||
// equal should this function be called. Therefore, this function does not need
|
|
||||||
// to handle profile intersection, and the profile of |local_supported_params|
|
|
||||||
// and |remote_offered_params| must be equal before calling this function. The
|
|
||||||
// parameters that are used when negotiating are the level part of
|
|
||||||
// profile-level-id and level-asymmetry-allowed.
|
|
||||||
void GenerateProfileLevelIdForAnswer(
|
|
||||||
const CodecParameterMap& local_supported_params,
|
|
||||||
const CodecParameterMap& remote_offered_params,
|
|
||||||
CodecParameterMap* answer_params);
|
|
||||||
|
|
||||||
// Returns true if the parameters have the same H264 profile, i.e. the same
|
// Returns true if the parameters have the same H264 profile, i.e. the same
|
||||||
// H264::Profile (Baseline, High, etc).
|
// H264::Profile (Baseline, High, etc).
|
||||||
bool IsSameH264Profile(const CodecParameterMap& params1,
|
RTC_EXPORT bool IsSameH264Profile(const SdpVideoFormat::Parameters& params1,
|
||||||
const CodecParameterMap& params2);
|
const SdpVideoFormat::Parameters& params2);
|
||||||
|
|
||||||
} // namespace H264
|
} // namespace H264
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
||||||
#endif // MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
|
#endif // MEDIA_BASE_H264_PROFILE_LEVEL_ID_H_
|
||||||
|
|||||||
@ -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_
|
#ifndef MEDIA_BASE_VP9_PROFILE_H_
|
||||||
#define MEDIA_BASE_VP9_PROFILE_H_
|
#define MEDIA_BASE_VP9_PROFILE_H_
|
||||||
|
|
||||||
#include <string>
|
#include "api/video_codecs/vp9_profile.h"
|
||||||
|
|
||||||
#include "absl/types/optional.h"
|
// TODO(crbug.com/1187565): Remove this file once downstream projects stop
|
||||||
#include "api/video_codecs/sdp_video_format.h"
|
// depend on it.
|
||||||
#include "rtc_base/system/rtc_export.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
// Profile information for VP9 video.
|
|
||||||
extern RTC_EXPORT const char kVP9FmtpProfileId[];
|
|
||||||
|
|
||||||
enum class VP9Profile {
|
|
||||||
kProfile0,
|
|
||||||
kProfile1,
|
|
||||||
kProfile2,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper functions to convert VP9Profile to std::string. Returns "0" by
|
|
||||||
// default.
|
|
||||||
RTC_EXPORT std::string VP9ProfileToString(VP9Profile profile);
|
|
||||||
|
|
||||||
// Helper functions to convert std::string to VP9Profile. Returns null if given
|
|
||||||
// an invalid profile string.
|
|
||||||
absl::optional<VP9Profile> StringToVP9Profile(const std::string& str);
|
|
||||||
|
|
||||||
// Parse profile that is represented as a string of single digit contained in an
|
|
||||||
// SDP key-value map. A default profile(kProfile0) will be returned if the
|
|
||||||
// profile key is missing. Nothing will be returned if the key is present but
|
|
||||||
// the string is invalid.
|
|
||||||
RTC_EXPORT absl::optional<VP9Profile> ParseSdpForVP9Profile(
|
|
||||||
const SdpVideoFormat::Parameters& params);
|
|
||||||
|
|
||||||
// Returns true if the parameters have the same VP9 profile, or neither contains
|
|
||||||
// VP9 profile.
|
|
||||||
bool IsSameVP9Profile(const SdpVideoFormat::Parameters& params1,
|
|
||||||
const SdpVideoFormat::Parameters& params2);
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
#endif // MEDIA_BASE_VP9_PROFILE_H_
|
#endif // MEDIA_BASE_VP9_PROFILE_H_
|
||||||
|
|||||||
@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
#include "api/video_codecs/sdp_video_format.h"
|
#include "api/video_codecs/sdp_video_format.h"
|
||||||
#include "api/video_codecs/video_decoder.h"
|
#include "api/video_codecs/video_decoder.h"
|
||||||
|
#include "api/video_codecs/vp9_profile.h"
|
||||||
#include "media/base/media_constants.h"
|
#include "media/base/media_constants.h"
|
||||||
#include "media/base/vp9_profile.h"
|
|
||||||
#include "modules/video_coding/codecs/av1/libaom_av1_decoder.h"
|
#include "modules/video_coding/codecs/av1/libaom_av1_decoder.h"
|
||||||
#include "test/gmock.h"
|
#include "test/gmock.h"
|
||||||
#include "test/gtest.h"
|
#include "test/gtest.h"
|
||||||
|
|||||||
@ -35,12 +35,12 @@
|
|||||||
#include "api/video/video_bitrate_allocation.h"
|
#include "api/video/video_bitrate_allocation.h"
|
||||||
#include "api/video_codecs/builtin_video_decoder_factory.h"
|
#include "api/video_codecs/builtin_video_decoder_factory.h"
|
||||||
#include "api/video_codecs/builtin_video_encoder_factory.h"
|
#include "api/video_codecs/builtin_video_encoder_factory.h"
|
||||||
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
#include "api/video_codecs/sdp_video_format.h"
|
#include "api/video_codecs/sdp_video_format.h"
|
||||||
#include "api/video_codecs/video_decoder_factory.h"
|
#include "api/video_codecs/video_decoder_factory.h"
|
||||||
#include "api/video_codecs/video_encoder.h"
|
#include "api/video_codecs/video_encoder.h"
|
||||||
#include "api/video_codecs/video_encoder_factory.h"
|
#include "api/video_codecs/video_encoder_factory.h"
|
||||||
#include "call/flexfec_receive_stream.h"
|
#include "call/flexfec_receive_stream.h"
|
||||||
#include "common_video/h264/profile_level_id.h"
|
|
||||||
#include "media/base/fake_frame_source.h"
|
#include "media/base/fake_frame_source.h"
|
||||||
#include "media/base/fake_network_interface.h"
|
#include "media/base/fake_network_interface.h"
|
||||||
#include "media/base/fake_video_renderer.h"
|
#include "media/base/fake_video_renderer.h"
|
||||||
@ -581,20 +581,21 @@ TEST_F(WebRtcVideoEngineTest, UseFactoryForVp8WhenSupported) {
|
|||||||
// TODO(deadbeef): This test should be updated if/when we start
|
// TODO(deadbeef): This test should be updated if/when we start
|
||||||
// adding RTX codecs for unrecognized codec names.
|
// adding RTX codecs for unrecognized codec names.
|
||||||
TEST_F(WebRtcVideoEngineTest, RtxCodecAddedForH264Codec) {
|
TEST_F(WebRtcVideoEngineTest, RtxCodecAddedForH264Codec) {
|
||||||
using webrtc::H264::kLevel1;
|
using webrtc::H264Level;
|
||||||
using webrtc::H264::ProfileLevelId;
|
using webrtc::H264Profile;
|
||||||
using webrtc::H264::ProfileLevelIdToString;
|
using webrtc::H264ProfileLevelId;
|
||||||
|
using webrtc::H264ProfileLevelIdToString;
|
||||||
webrtc::SdpVideoFormat h264_constrained_baseline("H264");
|
webrtc::SdpVideoFormat h264_constrained_baseline("H264");
|
||||||
h264_constrained_baseline.parameters[kH264FmtpProfileLevelId] =
|
h264_constrained_baseline.parameters[kH264FmtpProfileLevelId] =
|
||||||
*ProfileLevelIdToString(
|
*H264ProfileLevelIdToString(H264ProfileLevelId(
|
||||||
ProfileLevelId(webrtc::H264::kProfileConstrainedBaseline, kLevel1));
|
H264Profile::kProfileConstrainedBaseline, H264Level::kLevel1));
|
||||||
webrtc::SdpVideoFormat h264_constrained_high("H264");
|
webrtc::SdpVideoFormat h264_constrained_high("H264");
|
||||||
h264_constrained_high.parameters[kH264FmtpProfileLevelId] =
|
h264_constrained_high.parameters[kH264FmtpProfileLevelId] =
|
||||||
*ProfileLevelIdToString(
|
*H264ProfileLevelIdToString(H264ProfileLevelId(
|
||||||
ProfileLevelId(webrtc::H264::kProfileConstrainedHigh, kLevel1));
|
H264Profile::kProfileConstrainedHigh, H264Level::kLevel1));
|
||||||
webrtc::SdpVideoFormat h264_high("H264");
|
webrtc::SdpVideoFormat h264_high("H264");
|
||||||
h264_high.parameters[kH264FmtpProfileLevelId] = *ProfileLevelIdToString(
|
h264_high.parameters[kH264FmtpProfileLevelId] = *H264ProfileLevelIdToString(
|
||||||
ProfileLevelId(webrtc::H264::kProfileHigh, kLevel1));
|
H264ProfileLevelId(H264Profile::kProfileHigh, H264Level::kLevel1));
|
||||||
|
|
||||||
encoder_factory_->AddSupportedVideoCodec(h264_constrained_baseline);
|
encoder_factory_->AddSupportedVideoCodec(h264_constrained_baseline);
|
||||||
encoder_factory_->AddSupportedVideoCodec(h264_constrained_high);
|
encoder_factory_->AddSupportedVideoCodec(h264_constrained_high);
|
||||||
@ -721,10 +722,10 @@ size_t WebRtcVideoEngineTest::GetEngineCodecIndex(
|
|||||||
// The tests only use H264 Constrained Baseline. Make sure we don't return
|
// The tests only use H264 Constrained Baseline. Make sure we don't return
|
||||||
// an internal H264 codec from the engine with a different H264 profile.
|
// an internal H264 codec from the engine with a different H264 profile.
|
||||||
if (absl::EqualsIgnoreCase(name.c_str(), kH264CodecName)) {
|
if (absl::EqualsIgnoreCase(name.c_str(), kH264CodecName)) {
|
||||||
const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
|
const absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
|
||||||
webrtc::H264::ParseSdpProfileLevelId(engine_codec.params);
|
webrtc::ParseSdpForH264ProfileLevelId(engine_codec.params);
|
||||||
if (profile_level_id->profile !=
|
if (profile_level_id->profile !=
|
||||||
webrtc::H264::kProfileConstrainedBaseline) {
|
webrtc::H264Profile::kProfileConstrainedBaseline) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -592,7 +592,6 @@ rtc_library("webrtc_vp9") {
|
|||||||
"../../api/video_codecs:video_codecs_api",
|
"../../api/video_codecs:video_codecs_api",
|
||||||
"../../common_video",
|
"../../common_video",
|
||||||
"../../media:rtc_media_base",
|
"../../media:rtc_media_base",
|
||||||
"../../media:rtc_vp9_profile",
|
|
||||||
"../../rtc_base",
|
"../../rtc_base",
|
||||||
"../../rtc_base:checks",
|
"../../rtc_base:checks",
|
||||||
"../../rtc_base/experiments:encoder_info_settings",
|
"../../rtc_base/experiments:encoder_info_settings",
|
||||||
@ -814,7 +813,6 @@ if (rtc_include_tests) {
|
|||||||
"../../call:video_stream_api",
|
"../../call:video_stream_api",
|
||||||
"../../common_video",
|
"../../common_video",
|
||||||
"../../media:rtc_audio_video",
|
"../../media:rtc_audio_video",
|
||||||
"../../media:rtc_h264_profile_id",
|
|
||||||
"../../media:rtc_internal_video_codecs",
|
"../../media:rtc_internal_video_codecs",
|
||||||
"../../media:rtc_media_base",
|
"../../media:rtc_media_base",
|
||||||
"../../rtc_base:checks",
|
"../../rtc_base:checks",
|
||||||
@ -904,11 +902,9 @@ if (rtc_include_tests) {
|
|||||||
"../../api/video_codecs:video_codecs_api",
|
"../../api/video_codecs:video_codecs_api",
|
||||||
"../../common_video",
|
"../../common_video",
|
||||||
"../../common_video/test:utilities",
|
"../../common_video/test:utilities",
|
||||||
"../../media:rtc_h264_profile_id",
|
|
||||||
"../../media:rtc_internal_video_codecs",
|
"../../media:rtc_internal_video_codecs",
|
||||||
"../../media:rtc_media_base",
|
"../../media:rtc_media_base",
|
||||||
"../../media:rtc_simulcast_encoder_adapter",
|
"../../media:rtc_simulcast_encoder_adapter",
|
||||||
"../../media:rtc_vp9_profile",
|
|
||||||
"../../rtc_base",
|
"../../rtc_base",
|
||||||
"../../test:explicit_key_value_config",
|
"../../test:explicit_key_value_config",
|
||||||
"../../test:field_trial",
|
"../../test:field_trial",
|
||||||
|
|||||||
@ -45,11 +45,11 @@ bool IsH264CodecSupported() {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SdpVideoFormat CreateH264Format(H264::Profile profile,
|
SdpVideoFormat CreateH264Format(H264Profile profile,
|
||||||
H264::Level level,
|
H264Level level,
|
||||||
const std::string& packetization_mode) {
|
const std::string& packetization_mode) {
|
||||||
const absl::optional<std::string> profile_string =
|
const absl::optional<std::string> profile_string =
|
||||||
H264::ProfileLevelIdToString(H264::ProfileLevelId(profile, level));
|
H264ProfileLevelIdToString(H264ProfileLevelId(profile, level));
|
||||||
RTC_CHECK(profile_string);
|
RTC_CHECK(profile_string);
|
||||||
return SdpVideoFormat(
|
return SdpVideoFormat(
|
||||||
cricket::kH264CodecName,
|
cricket::kH264CodecName,
|
||||||
@ -76,12 +76,14 @@ std::vector<SdpVideoFormat> SupportedH264Codecs() {
|
|||||||
//
|
//
|
||||||
// We support both packetization modes 0 (mandatory) and 1 (optional,
|
// We support both packetization modes 0 (mandatory) and 1 (optional,
|
||||||
// preferred).
|
// preferred).
|
||||||
return {
|
return {CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1,
|
||||||
CreateH264Format(H264::kProfileBaseline, H264::kLevel3_1, "1"),
|
"1"),
|
||||||
CreateH264Format(H264::kProfileBaseline, H264::kLevel3_1, "0"),
|
CreateH264Format(H264Profile::kProfileBaseline, H264Level::kLevel3_1,
|
||||||
CreateH264Format(H264::kProfileConstrainedBaseline, H264::kLevel3_1, "1"),
|
"0"),
|
||||||
CreateH264Format(H264::kProfileConstrainedBaseline, H264::kLevel3_1,
|
CreateH264Format(H264Profile::kProfileConstrainedBaseline,
|
||||||
"0")};
|
H264Level::kLevel3_1, "1"),
|
||||||
|
CreateH264Format(H264Profile::kProfileConstrainedBaseline,
|
||||||
|
H264Level::kLevel3_1, "0")};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<H264Encoder> H264Encoder::Create(
|
std::unique_ptr<H264Encoder> H264Encoder::Create(
|
||||||
|
|||||||
@ -27,8 +27,8 @@ struct SdpVideoFormat;
|
|||||||
|
|
||||||
// Creates an H264 SdpVideoFormat entry with specified paramters.
|
// Creates an H264 SdpVideoFormat entry with specified paramters.
|
||||||
RTC_EXPORT SdpVideoFormat
|
RTC_EXPORT SdpVideoFormat
|
||||||
CreateH264Format(H264::Profile profile,
|
CreateH264Format(H264Profile profile,
|
||||||
H264::Level level,
|
H264Level level,
|
||||||
const std::string& packetization_mode);
|
const std::string& packetization_mode);
|
||||||
|
|
||||||
// Set to disable the H.264 encoder/decoder implementations that are provided if
|
// Set to disable the H.264 encoder/decoder implementations that are provided if
|
||||||
|
|||||||
@ -25,12 +25,12 @@
|
|||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "api/transport/field_trial_based_config.h"
|
#include "api/transport/field_trial_based_config.h"
|
||||||
#include "api/video/video_bitrate_allocation.h"
|
#include "api/video/video_bitrate_allocation.h"
|
||||||
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
#include "api/video_codecs/sdp_video_format.h"
|
#include "api/video_codecs/sdp_video_format.h"
|
||||||
#include "api/video_codecs/video_codec.h"
|
#include "api/video_codecs/video_codec.h"
|
||||||
#include "api/video_codecs/video_decoder.h"
|
#include "api/video_codecs/video_decoder.h"
|
||||||
#include "api/video_codecs/video_encoder_config.h"
|
#include "api/video_codecs/video_encoder_config.h"
|
||||||
#include "common_video/h264/h264_common.h"
|
#include "common_video/h264/h264_common.h"
|
||||||
#include "media/base/h264_profile_level_id.h"
|
|
||||||
#include "media/base/media_constants.h"
|
#include "media/base/media_constants.h"
|
||||||
#include "media/engine/internal_decoder_factory.h"
|
#include "media/engine/internal_decoder_factory.h"
|
||||||
#include "media/engine/internal_encoder_factory.h"
|
#include "media/engine/internal_encoder_factory.h"
|
||||||
@ -302,11 +302,11 @@ std::string VideoCodecTestFixtureImpl::Config::CodecName() const {
|
|||||||
name = CodecTypeToPayloadString(codec_settings.codecType);
|
name = CodecTypeToPayloadString(codec_settings.codecType);
|
||||||
}
|
}
|
||||||
if (codec_settings.codecType == kVideoCodecH264) {
|
if (codec_settings.codecType == kVideoCodecH264) {
|
||||||
if (h264_codec_settings.profile == H264::kProfileConstrainedHigh) {
|
if (h264_codec_settings.profile == H264Profile::kProfileConstrainedHigh) {
|
||||||
return name + "-CHP";
|
return name + "-CHP";
|
||||||
} else {
|
} else {
|
||||||
RTC_DCHECK_EQ(h264_codec_settings.profile,
|
RTC_DCHECK_EQ(h264_codec_settings.profile,
|
||||||
H264::kProfileConstrainedBaseline);
|
H264Profile::kProfileConstrainedBaseline);
|
||||||
return name + "-CBP";
|
return name + "-CBP";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -613,8 +613,8 @@ bool VideoCodecTestFixtureImpl::CreateEncoderAndDecoder() {
|
|||||||
? "1"
|
? "1"
|
||||||
: "0";
|
: "0";
|
||||||
params = {{cricket::kH264FmtpProfileLevelId,
|
params = {{cricket::kH264FmtpProfileLevelId,
|
||||||
*H264::ProfileLevelIdToString(H264::ProfileLevelId(
|
*H264ProfileLevelIdToString(H264ProfileLevelId(
|
||||||
config_.h264_codec_settings.profile, H264::kLevel3_1))},
|
config_.h264_codec_settings.profile, H264Level::kLevel3_1))},
|
||||||
{cricket::kH264FmtpPacketizationMode, packetization_mode}};
|
{cricket::kH264FmtpPacketizationMode, packetization_mode}};
|
||||||
} else {
|
} else {
|
||||||
params = {};
|
params = {};
|
||||||
|
|||||||
@ -95,7 +95,7 @@ TEST(VideoCodecTestMediaCodec, DISABLED_ForemanCif500kbpsH264CHP) {
|
|||||||
const auto frame_checker =
|
const auto frame_checker =
|
||||||
std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>();
|
std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>();
|
||||||
|
|
||||||
config.h264_codec_settings.profile = H264::kProfileConstrainedHigh;
|
config.h264_codec_settings.profile = H264Profile::kProfileConstrainedHigh;
|
||||||
config.encoded_frame_checker = frame_checker.get();
|
config.encoded_frame_checker = frame_checker.get();
|
||||||
config.SetCodecSettings(cricket::kH264CodecName, 1, 1, 1, false, false, false,
|
config.SetCodecSettings(cricket::kH264CodecName, 1, 1, 1, false, false, false,
|
||||||
352, 288);
|
352, 288);
|
||||||
|
|||||||
@ -71,7 +71,7 @@ MAYBE_TEST(VideoCodecTestVideoToolbox, ForemanCif500kbpsH264CHP) {
|
|||||||
const auto frame_checker =
|
const auto frame_checker =
|
||||||
std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>();
|
std::make_unique<VideoCodecTestFixtureImpl::H264KeyframeChecker>();
|
||||||
auto config = CreateConfig();
|
auto config = CreateConfig();
|
||||||
config.h264_codec_settings.profile = H264::kProfileConstrainedHigh;
|
config.h264_codec_settings.profile = H264Profile::kProfileConstrainedHigh;
|
||||||
config.SetCodecSettings(cricket::kH264CodecName, 1, 1, 1, false, false, false,
|
config.SetCodecSettings(cricket::kH264CodecName, 1, 1, 1, false, false, false,
|
||||||
352, 288);
|
352, 288);
|
||||||
config.encoded_frame_checker = frame_checker.get();
|
config.encoded_frame_checker = frame_checker.get();
|
||||||
|
|||||||
@ -21,8 +21,8 @@
|
|||||||
#include "api/fec_controller_override.h"
|
#include "api/fec_controller_override.h"
|
||||||
#include "api/transport/webrtc_key_value_config.h"
|
#include "api/transport/webrtc_key_value_config.h"
|
||||||
#include "api/video_codecs/video_encoder.h"
|
#include "api/video_codecs/video_encoder.h"
|
||||||
|
#include "api/video_codecs/vp9_profile.h"
|
||||||
#include "common_video/include/video_frame_buffer_pool.h"
|
#include "common_video/include/video_frame_buffer_pool.h"
|
||||||
#include "media/base/vp9_profile.h"
|
|
||||||
#include "modules/video_coding/codecs/interface/libvpx_interface.h"
|
#include "modules/video_coding/codecs/interface/libvpx_interface.h"
|
||||||
#include "modules/video_coding/codecs/vp9/include/vp9.h"
|
#include "modules/video_coding/codecs/vp9/include/vp9.h"
|
||||||
#include "modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h"
|
#include "modules/video_coding/codecs/vp9/vp9_frame_buffer_pool.h"
|
||||||
|
|||||||
@ -15,8 +15,8 @@
|
|||||||
#include "api/video/color_space.h"
|
#include "api/video/color_space.h"
|
||||||
#include "api/video/i420_buffer.h"
|
#include "api/video/i420_buffer.h"
|
||||||
#include "api/video_codecs/video_encoder.h"
|
#include "api/video_codecs/video_encoder.h"
|
||||||
|
#include "api/video_codecs/vp9_profile.h"
|
||||||
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
||||||
#include "media/base/vp9_profile.h"
|
|
||||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||||
#include "modules/video_coding/codecs/interface/libvpx_interface.h"
|
#include "modules/video_coding/codecs/interface/libvpx_interface.h"
|
||||||
#include "modules/video_coding/codecs/interface/mock_libvpx_interface.h"
|
#include "modules/video_coding/codecs/interface/mock_libvpx_interface.h"
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#include "api/transport/field_trial_based_config.h"
|
#include "api/transport/field_trial_based_config.h"
|
||||||
#include "api/video_codecs/sdp_video_format.h"
|
#include "api/video_codecs/sdp_video_format.h"
|
||||||
#include "media/base/vp9_profile.h"
|
#include "api/video_codecs/vp9_profile.h"
|
||||||
#include "modules/video_coding/codecs/vp9/libvpx_vp9_decoder.h"
|
#include "modules/video_coding/codecs/vp9/libvpx_vp9_decoder.h"
|
||||||
#include "modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h"
|
#include "modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
|
|||||||
@ -102,6 +102,7 @@ rtc_library("rtc_pc_base") {
|
|||||||
"../api/video:video_bitrate_allocator_factory",
|
"../api/video:video_bitrate_allocator_factory",
|
||||||
"../api/video:video_frame",
|
"../api/video:video_frame",
|
||||||
"../api/video:video_rtp_headers",
|
"../api/video:video_rtp_headers",
|
||||||
|
"../api/video_codecs:video_codecs_api",
|
||||||
"../call:call_interfaces",
|
"../call:call_interfaces",
|
||||||
"../call:rtp_interfaces",
|
"../call:rtp_interfaces",
|
||||||
"../call:rtp_receiver",
|
"../call:rtp_receiver",
|
||||||
@ -109,9 +110,9 @@ rtc_library("rtc_pc_base") {
|
|||||||
"../common_video:common_video",
|
"../common_video:common_video",
|
||||||
"../logging:ice_log",
|
"../logging:ice_log",
|
||||||
"../media:rtc_data_sctp_transport_internal",
|
"../media:rtc_data_sctp_transport_internal",
|
||||||
"../media:rtc_h264_profile_id",
|
|
||||||
"../media:rtc_media_base",
|
"../media:rtc_media_base",
|
||||||
"../media:rtc_media_config",
|
"../media:rtc_media_config",
|
||||||
|
"../media:rtc_sdp_video_format_utils",
|
||||||
"../modules/rtp_rtcp:rtp_rtcp",
|
"../modules/rtp_rtcp:rtp_rtcp",
|
||||||
"../modules/rtp_rtcp:rtp_rtcp_format",
|
"../modules/rtp_rtcp:rtp_rtcp_format",
|
||||||
"../p2p:rtc_p2p",
|
"../p2p:rtc_p2p",
|
||||||
|
|||||||
@ -24,9 +24,10 @@
|
|||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "api/crypto_params.h"
|
#include "api/crypto_params.h"
|
||||||
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
#include "media/base/codec.h"
|
#include "media/base/codec.h"
|
||||||
#include "media/base/h264_profile_level_id.h"
|
|
||||||
#include "media/base/media_constants.h"
|
#include "media/base/media_constants.h"
|
||||||
|
#include "media/base/sdp_video_format_utils.h"
|
||||||
#include "media/sctp/sctp_transport_internal.h"
|
#include "media/sctp/sctp_transport_internal.h"
|
||||||
#include "p2p/base/p2p_constants.h"
|
#include "p2p/base/p2p_constants.h"
|
||||||
#include "pc/channel_manager.h"
|
#include "pc/channel_manager.h"
|
||||||
@ -801,8 +802,8 @@ static void NegotiateCodecs(const std::vector<C>& local_codecs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
|
if (absl::EqualsIgnoreCase(ours.name, kH264CodecName)) {
|
||||||
webrtc::H264::GenerateProfileLevelIdForAnswer(
|
webrtc::H264GenerateProfileLevelIdForAnswer(ours.params, theirs.params,
|
||||||
ours.params, theirs.params, &negotiated.params);
|
&negotiated.params);
|
||||||
}
|
}
|
||||||
negotiated.id = theirs.id;
|
negotiated.id = theirs.id;
|
||||||
negotiated.name = theirs.name;
|
negotiated.name = theirs.name;
|
||||||
|
|||||||
@ -1655,6 +1655,7 @@ if (is_ios || is_mac) {
|
|||||||
":video_toolbox_cc",
|
":video_toolbox_cc",
|
||||||
":videocodec_objc",
|
":videocodec_objc",
|
||||||
":videoframebuffer_objc",
|
":videoframebuffer_objc",
|
||||||
|
"../api/video_codecs:video_codecs_api",
|
||||||
"../common_video",
|
"../common_video",
|
||||||
"../modules/video_coding:video_codec_interface",
|
"../modules/video_coding:video_codec_interface",
|
||||||
"../rtc_base:checks",
|
"../rtc_base:checks",
|
||||||
|
|||||||
@ -8,10 +8,9 @@
|
|||||||
* be found in the AUTHORS file in the root of the source tree.
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sdk/android/src/jni/video_codec_info.h"
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
|
|
||||||
#include "common_video/h264/profile_level_id.h"
|
|
||||||
#include "sdk/android/generated_video_jni/H264Utils_jni.h"
|
#include "sdk/android/generated_video_jni/H264Utils_jni.h"
|
||||||
|
#include "sdk/android/src/jni/video_codec_info.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
namespace jni {
|
namespace jni {
|
||||||
@ -20,8 +19,8 @@ static jboolean JNI_H264Utils_IsSameH264Profile(
|
|||||||
JNIEnv* env,
|
JNIEnv* env,
|
||||||
const JavaParamRef<jobject>& params1,
|
const JavaParamRef<jobject>& params1,
|
||||||
const JavaParamRef<jobject>& params2) {
|
const JavaParamRef<jobject>& params2) {
|
||||||
return H264::IsSameH264Profile(JavaToNativeStringMap(env, params1),
|
return H264IsSameProfile(JavaToNativeStringMap(env, params1),
|
||||||
JavaToNativeStringMap(env, params2));
|
JavaToNativeStringMap(env, params2));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace jni
|
} // namespace jni
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
#import "UIDevice+H264Profile.h"
|
#import "UIDevice+H264Profile.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "media/base/h264_profile_level_id.h"
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
#include "media/base/media_constants.h"
|
#include "media/base/media_constants.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -38,13 +38,12 @@ namespace {
|
|||||||
|
|
||||||
#if defined(WEBRTC_IOS)
|
#if defined(WEBRTC_IOS)
|
||||||
|
|
||||||
using namespace webrtc::H264;
|
NSString *MaxSupportedLevelForProfile(webrtc::H264Profile profile) {
|
||||||
|
const absl::optional<webrtc::H264ProfileLevelId> profileLevelId =
|
||||||
NSString *MaxSupportedLevelForProfile(Profile profile) {
|
[UIDevice maxSupportedH264Profile];
|
||||||
const absl::optional<ProfileLevelId> profileLevelId = [UIDevice maxSupportedH264Profile];
|
|
||||||
if (profileLevelId && profileLevelId->profile >= profile) {
|
if (profileLevelId && profileLevelId->profile >= profile) {
|
||||||
const absl::optional<std::string> profileString =
|
const absl::optional<std::string> profileString =
|
||||||
ProfileLevelIdToString(ProfileLevelId(profile, profileLevelId->level));
|
H264ProfileLevelIdToString(webrtc::H264ProfileLevelId(profile, profileLevelId->level));
|
||||||
if (profileString) {
|
if (profileString) {
|
||||||
return [NSString stringForStdString:*profileString];
|
return [NSString stringForStdString:*profileString];
|
||||||
}
|
}
|
||||||
@ -55,7 +54,7 @@ NSString *MaxSupportedLevelForProfile(Profile profile) {
|
|||||||
|
|
||||||
NSString *MaxSupportedProfileLevelConstrainedBaseline() {
|
NSString *MaxSupportedProfileLevelConstrainedBaseline() {
|
||||||
#if defined(WEBRTC_IOS)
|
#if defined(WEBRTC_IOS)
|
||||||
NSString *profile = MaxSupportedLevelForProfile(webrtc::H264::kProfileConstrainedBaseline);
|
NSString *profile = MaxSupportedLevelForProfile(webrtc::H264Profile::kProfileConstrainedBaseline);
|
||||||
if (profile != nil) {
|
if (profile != nil) {
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
@ -65,7 +64,7 @@ NSString *MaxSupportedProfileLevelConstrainedBaseline() {
|
|||||||
|
|
||||||
NSString *MaxSupportedProfileLevelConstrainedHigh() {
|
NSString *MaxSupportedProfileLevelConstrainedHigh() {
|
||||||
#if defined(WEBRTC_IOS)
|
#if defined(WEBRTC_IOS)
|
||||||
NSString *profile = MaxSupportedLevelForProfile(webrtc::H264::kProfileConstrainedHigh);
|
NSString *profile = MaxSupportedLevelForProfile(webrtc::H264Profile::kProfileConstrainedHigh);
|
||||||
if (profile != nil) {
|
if (profile != nil) {
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
@ -94,8 +93,8 @@ NSString *MaxSupportedProfileLevelConstrainedHigh() {
|
|||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
self.hexString = hexString;
|
self.hexString = hexString;
|
||||||
|
|
||||||
absl::optional<webrtc::H264::ProfileLevelId> profile_level_id =
|
absl::optional<webrtc::H264ProfileLevelId> profile_level_id =
|
||||||
webrtc::H264::ParseProfileLevelId([hexString cStringUsingEncoding:NSUTF8StringEncoding]);
|
webrtc::ParseH264ProfileLevelId([hexString cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||||
if (profile_level_id.has_value()) {
|
if (profile_level_id.has_value()) {
|
||||||
self.profile = static_cast<RTCH264Profile>(profile_level_id->profile);
|
self.profile = static_cast<RTCH264Profile>(profile_level_id->profile);
|
||||||
self.level = static_cast<RTCH264Level>(profile_level_id->level);
|
self.level = static_cast<RTCH264Level>(profile_level_id->level);
|
||||||
@ -110,8 +109,8 @@ NSString *MaxSupportedProfileLevelConstrainedHigh() {
|
|||||||
self.level = level;
|
self.level = level;
|
||||||
|
|
||||||
absl::optional<std::string> hex_string =
|
absl::optional<std::string> hex_string =
|
||||||
webrtc::H264::ProfileLevelIdToString(webrtc::H264::ProfileLevelId(
|
webrtc::H264ProfileLevelIdToString(webrtc::H264ProfileLevelId(
|
||||||
static_cast<webrtc::H264::Profile>(profile), static_cast<webrtc::H264::Level>(level)));
|
static_cast<webrtc::H264Profile>(profile), static_cast<webrtc::H264Level>(level)));
|
||||||
self.hexString =
|
self.hexString =
|
||||||
[NSString stringWithCString:hex_string.value_or("").c_str() encoding:NSUTF8StringEncoding];
|
[NSString stringWithCString:hex_string.value_or("").c_str() encoding:NSUTF8StringEncoding];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,8 +28,8 @@
|
|||||||
#import "components/video_frame_buffer/RTCCVPixelBuffer.h"
|
#import "components/video_frame_buffer/RTCCVPixelBuffer.h"
|
||||||
#import "helpers.h"
|
#import "helpers.h"
|
||||||
|
|
||||||
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
#include "common_video/h264/h264_bitstream_parser.h"
|
#include "common_video/h264/h264_bitstream_parser.h"
|
||||||
#include "common_video/h264/profile_level_id.h"
|
|
||||||
#include "common_video/include/bitrate_adjuster.h"
|
#include "common_video/include/bitrate_adjuster.h"
|
||||||
#include "modules/video_coding/include/video_error_codes.h"
|
#include "modules/video_coding/include/video_error_codes.h"
|
||||||
#include "rtc_base/buffer.h"
|
#include "rtc_base/buffer.h"
|
||||||
@ -173,100 +173,100 @@ void compressionOutputCallback(void *encoder,
|
|||||||
// no specific VideoToolbox profile for the specified level, AutoLevel will be
|
// no specific VideoToolbox profile for the specified level, AutoLevel will be
|
||||||
// returned. The user must initialize the encoder with a resolution and
|
// returned. The user must initialize the encoder with a resolution and
|
||||||
// framerate conforming to the selected H264 level regardless.
|
// framerate conforming to the selected H264 level regardless.
|
||||||
CFStringRef ExtractProfile(const webrtc::H264::ProfileLevelId &profile_level_id) {
|
CFStringRef ExtractProfile(const webrtc::H264ProfileLevelId &profile_level_id) {
|
||||||
switch (profile_level_id.profile) {
|
switch (profile_level_id.profile) {
|
||||||
case webrtc::H264::kProfileConstrainedBaseline:
|
case webrtc::H264Profile::kProfileConstrainedBaseline:
|
||||||
case webrtc::H264::kProfileBaseline:
|
case webrtc::H264Profile::kProfileBaseline:
|
||||||
switch (profile_level_id.level) {
|
switch (profile_level_id.level) {
|
||||||
case webrtc::H264::kLevel3:
|
case webrtc::H264Level::kLevel3:
|
||||||
return kVTProfileLevel_H264_Baseline_3_0;
|
return kVTProfileLevel_H264_Baseline_3_0;
|
||||||
case webrtc::H264::kLevel3_1:
|
case webrtc::H264Level::kLevel3_1:
|
||||||
return kVTProfileLevel_H264_Baseline_3_1;
|
return kVTProfileLevel_H264_Baseline_3_1;
|
||||||
case webrtc::H264::kLevel3_2:
|
case webrtc::H264Level::kLevel3_2:
|
||||||
return kVTProfileLevel_H264_Baseline_3_2;
|
return kVTProfileLevel_H264_Baseline_3_2;
|
||||||
case webrtc::H264::kLevel4:
|
case webrtc::H264Level::kLevel4:
|
||||||
return kVTProfileLevel_H264_Baseline_4_0;
|
return kVTProfileLevel_H264_Baseline_4_0;
|
||||||
case webrtc::H264::kLevel4_1:
|
case webrtc::H264Level::kLevel4_1:
|
||||||
return kVTProfileLevel_H264_Baseline_4_1;
|
return kVTProfileLevel_H264_Baseline_4_1;
|
||||||
case webrtc::H264::kLevel4_2:
|
case webrtc::H264Level::kLevel4_2:
|
||||||
return kVTProfileLevel_H264_Baseline_4_2;
|
return kVTProfileLevel_H264_Baseline_4_2;
|
||||||
case webrtc::H264::kLevel5:
|
case webrtc::H264Level::kLevel5:
|
||||||
return kVTProfileLevel_H264_Baseline_5_0;
|
return kVTProfileLevel_H264_Baseline_5_0;
|
||||||
case webrtc::H264::kLevel5_1:
|
case webrtc::H264Level::kLevel5_1:
|
||||||
return kVTProfileLevel_H264_Baseline_5_1;
|
return kVTProfileLevel_H264_Baseline_5_1;
|
||||||
case webrtc::H264::kLevel5_2:
|
case webrtc::H264Level::kLevel5_2:
|
||||||
return kVTProfileLevel_H264_Baseline_5_2;
|
return kVTProfileLevel_H264_Baseline_5_2;
|
||||||
case webrtc::H264::kLevel1:
|
case webrtc::H264Level::kLevel1:
|
||||||
case webrtc::H264::kLevel1_b:
|
case webrtc::H264Level::kLevel1_b:
|
||||||
case webrtc::H264::kLevel1_1:
|
case webrtc::H264Level::kLevel1_1:
|
||||||
case webrtc::H264::kLevel1_2:
|
case webrtc::H264Level::kLevel1_2:
|
||||||
case webrtc::H264::kLevel1_3:
|
case webrtc::H264Level::kLevel1_3:
|
||||||
case webrtc::H264::kLevel2:
|
case webrtc::H264Level::kLevel2:
|
||||||
case webrtc::H264::kLevel2_1:
|
case webrtc::H264Level::kLevel2_1:
|
||||||
case webrtc::H264::kLevel2_2:
|
case webrtc::H264Level::kLevel2_2:
|
||||||
return kVTProfileLevel_H264_Baseline_AutoLevel;
|
return kVTProfileLevel_H264_Baseline_AutoLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
case webrtc::H264::kProfileMain:
|
case webrtc::H264Profile::kProfileMain:
|
||||||
switch (profile_level_id.level) {
|
switch (profile_level_id.level) {
|
||||||
case webrtc::H264::kLevel3:
|
case webrtc::H264Level::kLevel3:
|
||||||
return kVTProfileLevel_H264_Main_3_0;
|
return kVTProfileLevel_H264_Main_3_0;
|
||||||
case webrtc::H264::kLevel3_1:
|
case webrtc::H264Level::kLevel3_1:
|
||||||
return kVTProfileLevel_H264_Main_3_1;
|
return kVTProfileLevel_H264_Main_3_1;
|
||||||
case webrtc::H264::kLevel3_2:
|
case webrtc::H264Level::kLevel3_2:
|
||||||
return kVTProfileLevel_H264_Main_3_2;
|
return kVTProfileLevel_H264_Main_3_2;
|
||||||
case webrtc::H264::kLevel4:
|
case webrtc::H264Level::kLevel4:
|
||||||
return kVTProfileLevel_H264_Main_4_0;
|
return kVTProfileLevel_H264_Main_4_0;
|
||||||
case webrtc::H264::kLevel4_1:
|
case webrtc::H264Level::kLevel4_1:
|
||||||
return kVTProfileLevel_H264_Main_4_1;
|
return kVTProfileLevel_H264_Main_4_1;
|
||||||
case webrtc::H264::kLevel4_2:
|
case webrtc::H264Level::kLevel4_2:
|
||||||
return kVTProfileLevel_H264_Main_4_2;
|
return kVTProfileLevel_H264_Main_4_2;
|
||||||
case webrtc::H264::kLevel5:
|
case webrtc::H264Level::kLevel5:
|
||||||
return kVTProfileLevel_H264_Main_5_0;
|
return kVTProfileLevel_H264_Main_5_0;
|
||||||
case webrtc::H264::kLevel5_1:
|
case webrtc::H264Level::kLevel5_1:
|
||||||
return kVTProfileLevel_H264_Main_5_1;
|
return kVTProfileLevel_H264_Main_5_1;
|
||||||
case webrtc::H264::kLevel5_2:
|
case webrtc::H264Level::kLevel5_2:
|
||||||
return kVTProfileLevel_H264_Main_5_2;
|
return kVTProfileLevel_H264_Main_5_2;
|
||||||
case webrtc::H264::kLevel1:
|
case webrtc::H264Level::kLevel1:
|
||||||
case webrtc::H264::kLevel1_b:
|
case webrtc::H264Level::kLevel1_b:
|
||||||
case webrtc::H264::kLevel1_1:
|
case webrtc::H264Level::kLevel1_1:
|
||||||
case webrtc::H264::kLevel1_2:
|
case webrtc::H264Level::kLevel1_2:
|
||||||
case webrtc::H264::kLevel1_3:
|
case webrtc::H264Level::kLevel1_3:
|
||||||
case webrtc::H264::kLevel2:
|
case webrtc::H264Level::kLevel2:
|
||||||
case webrtc::H264::kLevel2_1:
|
case webrtc::H264Level::kLevel2_1:
|
||||||
case webrtc::H264::kLevel2_2:
|
case webrtc::H264Level::kLevel2_2:
|
||||||
return kVTProfileLevel_H264_Main_AutoLevel;
|
return kVTProfileLevel_H264_Main_AutoLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
case webrtc::H264::kProfileConstrainedHigh:
|
case webrtc::H264Profile::kProfileConstrainedHigh:
|
||||||
case webrtc::H264::kProfileHigh:
|
case webrtc::H264Profile::kProfileHigh:
|
||||||
switch (profile_level_id.level) {
|
switch (profile_level_id.level) {
|
||||||
case webrtc::H264::kLevel3:
|
case webrtc::H264Level::kLevel3:
|
||||||
return kVTProfileLevel_H264_High_3_0;
|
return kVTProfileLevel_H264_High_3_0;
|
||||||
case webrtc::H264::kLevel3_1:
|
case webrtc::H264Level::kLevel3_1:
|
||||||
return kVTProfileLevel_H264_High_3_1;
|
return kVTProfileLevel_H264_High_3_1;
|
||||||
case webrtc::H264::kLevel3_2:
|
case webrtc::H264Level::kLevel3_2:
|
||||||
return kVTProfileLevel_H264_High_3_2;
|
return kVTProfileLevel_H264_High_3_2;
|
||||||
case webrtc::H264::kLevel4:
|
case webrtc::H264Level::kLevel4:
|
||||||
return kVTProfileLevel_H264_High_4_0;
|
return kVTProfileLevel_H264_High_4_0;
|
||||||
case webrtc::H264::kLevel4_1:
|
case webrtc::H264Level::kLevel4_1:
|
||||||
return kVTProfileLevel_H264_High_4_1;
|
return kVTProfileLevel_H264_High_4_1;
|
||||||
case webrtc::H264::kLevel4_2:
|
case webrtc::H264Level::kLevel4_2:
|
||||||
return kVTProfileLevel_H264_High_4_2;
|
return kVTProfileLevel_H264_High_4_2;
|
||||||
case webrtc::H264::kLevel5:
|
case webrtc::H264Level::kLevel5:
|
||||||
return kVTProfileLevel_H264_High_5_0;
|
return kVTProfileLevel_H264_High_5_0;
|
||||||
case webrtc::H264::kLevel5_1:
|
case webrtc::H264Level::kLevel5_1:
|
||||||
return kVTProfileLevel_H264_High_5_1;
|
return kVTProfileLevel_H264_High_5_1;
|
||||||
case webrtc::H264::kLevel5_2:
|
case webrtc::H264Level::kLevel5_2:
|
||||||
return kVTProfileLevel_H264_High_5_2;
|
return kVTProfileLevel_H264_High_5_2;
|
||||||
case webrtc::H264::kLevel1:
|
case webrtc::H264Level::kLevel1:
|
||||||
case webrtc::H264::kLevel1_b:
|
case webrtc::H264Level::kLevel1_b:
|
||||||
case webrtc::H264::kLevel1_1:
|
case webrtc::H264Level::kLevel1_1:
|
||||||
case webrtc::H264::kLevel1_2:
|
case webrtc::H264Level::kLevel1_2:
|
||||||
case webrtc::H264::kLevel1_3:
|
case webrtc::H264Level::kLevel1_3:
|
||||||
case webrtc::H264::kLevel2:
|
case webrtc::H264Level::kLevel2:
|
||||||
case webrtc::H264::kLevel2_1:
|
case webrtc::H264Level::kLevel2_1:
|
||||||
case webrtc::H264::kLevel2_2:
|
case webrtc::H264Level::kLevel2_2:
|
||||||
return kVTProfileLevel_H264_High_AutoLevel;
|
return kVTProfileLevel_H264_High_AutoLevel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,33 +276,33 @@ CFStringRef ExtractProfile(const webrtc::H264::ProfileLevelId &profile_level_id)
|
|||||||
// can be processed by given encoder with |profile_level_id|.
|
// can be processed by given encoder with |profile_level_id|.
|
||||||
// See https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.264-201610-S!!PDF-E&type=items
|
// See https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-H.264-201610-S!!PDF-E&type=items
|
||||||
// for details.
|
// for details.
|
||||||
NSUInteger GetMaxSampleRate(const webrtc::H264::ProfileLevelId &profile_level_id) {
|
NSUInteger GetMaxSampleRate(const webrtc::H264ProfileLevelId &profile_level_id) {
|
||||||
switch (profile_level_id.level) {
|
switch (profile_level_id.level) {
|
||||||
case webrtc::H264::kLevel3:
|
case webrtc::H264Level::kLevel3:
|
||||||
return 10368000;
|
return 10368000;
|
||||||
case webrtc::H264::kLevel3_1:
|
case webrtc::H264Level::kLevel3_1:
|
||||||
return 27648000;
|
return 27648000;
|
||||||
case webrtc::H264::kLevel3_2:
|
case webrtc::H264Level::kLevel3_2:
|
||||||
return 55296000;
|
return 55296000;
|
||||||
case webrtc::H264::kLevel4:
|
case webrtc::H264Level::kLevel4:
|
||||||
case webrtc::H264::kLevel4_1:
|
case webrtc::H264Level::kLevel4_1:
|
||||||
return 62914560;
|
return 62914560;
|
||||||
case webrtc::H264::kLevel4_2:
|
case webrtc::H264Level::kLevel4_2:
|
||||||
return 133693440;
|
return 133693440;
|
||||||
case webrtc::H264::kLevel5:
|
case webrtc::H264Level::kLevel5:
|
||||||
return 150994944;
|
return 150994944;
|
||||||
case webrtc::H264::kLevel5_1:
|
case webrtc::H264Level::kLevel5_1:
|
||||||
return 251658240;
|
return 251658240;
|
||||||
case webrtc::H264::kLevel5_2:
|
case webrtc::H264Level::kLevel5_2:
|
||||||
return 530841600;
|
return 530841600;
|
||||||
case webrtc::H264::kLevel1:
|
case webrtc::H264Level::kLevel1:
|
||||||
case webrtc::H264::kLevel1_b:
|
case webrtc::H264Level::kLevel1_b:
|
||||||
case webrtc::H264::kLevel1_1:
|
case webrtc::H264Level::kLevel1_1:
|
||||||
case webrtc::H264::kLevel1_2:
|
case webrtc::H264Level::kLevel1_2:
|
||||||
case webrtc::H264::kLevel1_3:
|
case webrtc::H264Level::kLevel1_3:
|
||||||
case webrtc::H264::kLevel2:
|
case webrtc::H264Level::kLevel2:
|
||||||
case webrtc::H264::kLevel2_1:
|
case webrtc::H264Level::kLevel2_1:
|
||||||
case webrtc::H264::kLevel2_2:
|
case webrtc::H264Level::kLevel2_2:
|
||||||
// Zero means auto rate setting.
|
// Zero means auto rate setting.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -317,7 +317,7 @@ NSUInteger GetMaxSampleRate(const webrtc::H264::ProfileLevelId &profile_level_id
|
|||||||
uint32_t _encoderFrameRate;
|
uint32_t _encoderFrameRate;
|
||||||
uint32_t _maxAllowedFrameRate;
|
uint32_t _maxAllowedFrameRate;
|
||||||
RTCH264PacketizationMode _packetizationMode;
|
RTCH264PacketizationMode _packetizationMode;
|
||||||
absl::optional<webrtc::H264::ProfileLevelId> _profile_level_id;
|
absl::optional<webrtc::H264ProfileLevelId> _profile_level_id;
|
||||||
RTCVideoEncoderCallback _callback;
|
RTCVideoEncoderCallback _callback;
|
||||||
int32_t _width;
|
int32_t _width;
|
||||||
int32_t _height;
|
int32_t _height;
|
||||||
@ -342,7 +342,7 @@ NSUInteger GetMaxSampleRate(const webrtc::H264::ProfileLevelId &profile_level_id
|
|||||||
_bitrateAdjuster.reset(new webrtc::BitrateAdjuster(.5, .95));
|
_bitrateAdjuster.reset(new webrtc::BitrateAdjuster(.5, .95));
|
||||||
_packetizationMode = RTCH264PacketizationModeNonInterleaved;
|
_packetizationMode = RTCH264PacketizationModeNonInterleaved;
|
||||||
_profile_level_id =
|
_profile_level_id =
|
||||||
webrtc::H264::ParseSdpProfileLevelId([codecInfo nativeSdpVideoFormat].parameters);
|
webrtc::ParseSdpForH264ProfileLevelId([codecInfo nativeSdpVideoFormat].parameters);
|
||||||
RTC_DCHECK(_profile_level_id);
|
RTC_DCHECK(_profile_level_id);
|
||||||
RTC_LOG(LS_INFO) << "Using profile " << CFStringToString(ExtractProfile(*_profile_level_id));
|
RTC_LOG(LS_INFO) << "Using profile " << CFStringToString(ExtractProfile(*_profile_level_id));
|
||||||
RTC_CHECK([codecInfo.name isEqualToString:kRTCVideoCodecH264Name]);
|
RTC_CHECK([codecInfo.name isEqualToString:kRTCVideoCodecH264Name]);
|
||||||
|
|||||||
@ -10,10 +10,10 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#include "media/base/h264_profile_level_id.h"
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
|
|
||||||
@interface UIDevice (H264Profile)
|
@interface UIDevice (H264Profile)
|
||||||
|
|
||||||
+ (absl::optional<webrtc::H264::ProfileLevelId>)maxSupportedH264Profile;
|
+ (absl::optional<webrtc::H264ProfileLevelId>)maxSupportedH264Profile;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -15,99 +15,156 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using namespace webrtc::H264;
|
using namespace webrtc;
|
||||||
|
|
||||||
struct SupportedH264Profile {
|
struct SupportedH264Profile {
|
||||||
const RTCDeviceType deviceType;
|
const RTCDeviceType deviceType;
|
||||||
const ProfileLevelId profile;
|
const H264ProfileLevelId profile;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr SupportedH264Profile kH264MaxSupportedProfiles[] = {
|
constexpr SupportedH264Profile kH264MaxSupportedProfiles[] = {
|
||||||
// iPhones with at least iOS 9
|
// iPhones with at least iOS 9
|
||||||
{RTCDeviceTypeIPhone12ProMax, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP832
|
{RTCDeviceTypeIPhone12ProMax,
|
||||||
{RTCDeviceTypeIPhone12Pro, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP831
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP832
|
||||||
{RTCDeviceTypeIPhone12, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP830
|
{RTCDeviceTypeIPhone12Pro,
|
||||||
{RTCDeviceTypeIPhone12Mini, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP829
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP831
|
||||||
{RTCDeviceTypeIPhone11ProMax, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP806
|
{RTCDeviceTypeIPhone12,
|
||||||
{RTCDeviceTypeIPhone11Pro, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP805
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP830
|
||||||
{RTCDeviceTypeIPhone11, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP804
|
{RTCDeviceTypeIPhone12Mini,
|
||||||
{RTCDeviceTypeIPhoneXS, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP779
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP829
|
||||||
{RTCDeviceTypeIPhoneXSMax, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP780
|
{RTCDeviceTypeIPhone11ProMax,
|
||||||
{RTCDeviceTypeIPhoneXR, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP781
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP806
|
||||||
{RTCDeviceTypeIPhoneX, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP770
|
{RTCDeviceTypeIPhone11Pro,
|
||||||
{RTCDeviceTypeIPhone8, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP767
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP805
|
||||||
{RTCDeviceTypeIPhone8Plus, {kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP768
|
{RTCDeviceTypeIPhone11,
|
||||||
{RTCDeviceTypeIPhone7, {kProfileHigh, kLevel5_1}}, // https://support.apple.com/kb/SP743
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP804
|
||||||
{RTCDeviceTypeIPhone7Plus, {kProfileHigh, kLevel5_1}}, // https://support.apple.com/kb/SP744
|
{RTCDeviceTypeIPhoneXS,
|
||||||
{RTCDeviceTypeIPhoneSE, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP738
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP779
|
||||||
{RTCDeviceTypeIPhone6S, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP726
|
{RTCDeviceTypeIPhoneXSMax,
|
||||||
{RTCDeviceTypeIPhone6SPlus, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP727
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP780
|
||||||
{RTCDeviceTypeIPhone6, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP705
|
{RTCDeviceTypeIPhoneXR,
|
||||||
{RTCDeviceTypeIPhone6Plus, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP706
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP781
|
||||||
{RTCDeviceTypeIPhone5SGSM, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP685
|
{RTCDeviceTypeIPhoneX,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP770
|
||||||
|
{RTCDeviceTypeIPhone8,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP767
|
||||||
|
{RTCDeviceTypeIPhone8Plus,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP768
|
||||||
|
{RTCDeviceTypeIPhone7,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel5_1}}, // https://support.apple.com/kb/SP743
|
||||||
|
{RTCDeviceTypeIPhone7Plus,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel5_1}}, // https://support.apple.com/kb/SP744
|
||||||
|
{RTCDeviceTypeIPhoneSE,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP738
|
||||||
|
{RTCDeviceTypeIPhone6S,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP726
|
||||||
|
{RTCDeviceTypeIPhone6SPlus,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP727
|
||||||
|
{RTCDeviceTypeIPhone6,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP705
|
||||||
|
{RTCDeviceTypeIPhone6Plus,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP706
|
||||||
|
{RTCDeviceTypeIPhone5SGSM,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP685
|
||||||
{RTCDeviceTypeIPhone5SGSM_CDMA,
|
{RTCDeviceTypeIPhone5SGSM_CDMA,
|
||||||
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP685
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP685
|
||||||
{RTCDeviceTypeIPhone5GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP655
|
{RTCDeviceTypeIPhone5GSM,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP655
|
||||||
{RTCDeviceTypeIPhone5GSM_CDMA,
|
{RTCDeviceTypeIPhone5GSM_CDMA,
|
||||||
{kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP655
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP655
|
||||||
{RTCDeviceTypeIPhone5CGSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP684
|
{RTCDeviceTypeIPhone5CGSM,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP684
|
||||||
{RTCDeviceTypeIPhone5CGSM_CDMA,
|
{RTCDeviceTypeIPhone5CGSM_CDMA,
|
||||||
{kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP684
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP684
|
||||||
{RTCDeviceTypeIPhone4S, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP643
|
{RTCDeviceTypeIPhone4S,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP643
|
||||||
|
|
||||||
// iPods with at least iOS 9
|
// iPods with at least iOS 9
|
||||||
{RTCDeviceTypeIPodTouch7G, {kProfileMain, kLevel4_1}}, // https://support.apple.com/kb/SP796
|
{RTCDeviceTypeIPodTouch7G,
|
||||||
{RTCDeviceTypeIPodTouch6G, {kProfileMain, kLevel4_1}}, // https://support.apple.com/kb/SP720
|
{H264Profile::kProfileMain, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP796
|
||||||
{RTCDeviceTypeIPodTouch5G, {kProfileMain, kLevel3_1}}, // https://support.apple.com/kb/SP657
|
{RTCDeviceTypeIPodTouch6G,
|
||||||
|
{H264Profile::kProfileMain, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP720
|
||||||
|
{RTCDeviceTypeIPodTouch5G,
|
||||||
|
{H264Profile::kProfileMain, H264Level::kLevel3_1}}, // https://support.apple.com/kb/SP657
|
||||||
|
|
||||||
// iPads with at least iOS 9
|
// iPads with at least iOS 9
|
||||||
{RTCDeviceTypeIPadAir4Gen, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP828
|
{RTCDeviceTypeIPadAir4Gen,
|
||||||
{RTCDeviceTypeIPad8, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP822
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP828
|
||||||
{RTCDeviceTypeIPadPro4Gen12Inch, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP815
|
{RTCDeviceTypeIPad8,
|
||||||
{RTCDeviceTypeIPadPro4Gen11Inch, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP814
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP822
|
||||||
{RTCDeviceTypeIPadAir3Gen, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP787
|
{RTCDeviceTypeIPadPro4Gen12Inch,
|
||||||
{RTCDeviceTypeIPadMini5Gen, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP788
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP815
|
||||||
|
{RTCDeviceTypeIPadPro4Gen11Inch,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP814
|
||||||
|
{RTCDeviceTypeIPadAir3Gen,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP787
|
||||||
|
{RTCDeviceTypeIPadMini5Gen,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP788
|
||||||
{RTCDeviceTypeIPadPro3Gen12Inch,
|
{RTCDeviceTypeIPadPro3Gen12Inch,
|
||||||
{kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP785
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP785
|
||||||
{RTCDeviceTypeIPadPro3Gen11Inch,
|
{RTCDeviceTypeIPadPro3Gen11Inch,
|
||||||
{kProfileHigh, kLevel5_2}}, // https://support.apple.com/kb/SP784
|
{H264Profile::kProfileHigh, H264Level::kLevel5_2}}, // https://support.apple.com/kb/SP784
|
||||||
{RTCDeviceTypeIPad7Gen10Inch, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP807
|
{RTCDeviceTypeIPad7Gen10Inch,
|
||||||
{RTCDeviceTypeIPad2Wifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP807
|
||||||
{RTCDeviceTypeIPad2GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622
|
{RTCDeviceTypeIPad2Wifi,
|
||||||
{RTCDeviceTypeIPad2CDMA, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP622
|
||||||
{RTCDeviceTypeIPad2Wifi2, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP622
|
{RTCDeviceTypeIPad2GSM,
|
||||||
{RTCDeviceTypeIPadMiniWifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP661
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP622
|
||||||
{RTCDeviceTypeIPadMiniGSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP661
|
{RTCDeviceTypeIPad2CDMA,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP622
|
||||||
|
{RTCDeviceTypeIPad2Wifi2,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP622
|
||||||
|
{RTCDeviceTypeIPadMiniWifi,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP661
|
||||||
|
{RTCDeviceTypeIPadMiniGSM,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP661
|
||||||
{RTCDeviceTypeIPadMiniGSM_CDMA,
|
{RTCDeviceTypeIPadMiniGSM_CDMA,
|
||||||
{kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP661
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP661
|
||||||
{RTCDeviceTypeIPad3Wifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP647
|
{RTCDeviceTypeIPad3Wifi,
|
||||||
{RTCDeviceTypeIPad3GSM_CDMA, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP647
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP647
|
||||||
{RTCDeviceTypeIPad3GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP647
|
{RTCDeviceTypeIPad3GSM_CDMA,
|
||||||
{RTCDeviceTypeIPad4Wifi, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP662
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP647
|
||||||
{RTCDeviceTypeIPad4GSM, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP662
|
{RTCDeviceTypeIPad3GSM,
|
||||||
{RTCDeviceTypeIPad4GSM_CDMA, {kProfileHigh, kLevel4_1}}, // https://support.apple.com/kb/SP662
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP647
|
||||||
{RTCDeviceTypeIPad5, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP751
|
{RTCDeviceTypeIPad4Wifi,
|
||||||
{RTCDeviceTypeIPad6, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP774
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP662
|
||||||
{RTCDeviceTypeIPadAirWifi, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP692
|
{RTCDeviceTypeIPad4GSM,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP662
|
||||||
|
{RTCDeviceTypeIPad4GSM_CDMA,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_1}}, // https://support.apple.com/kb/SP662
|
||||||
|
{RTCDeviceTypeIPad5,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP751
|
||||||
|
{RTCDeviceTypeIPad6,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP774
|
||||||
|
{RTCDeviceTypeIPadAirWifi,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP692
|
||||||
{RTCDeviceTypeIPadAirCellular,
|
{RTCDeviceTypeIPadAirCellular,
|
||||||
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP692
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP692
|
||||||
{RTCDeviceTypeIPadAirWifiCellular,
|
{RTCDeviceTypeIPadAirWifiCellular,
|
||||||
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP692
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP692
|
||||||
{RTCDeviceTypeIPadAir2, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP708
|
{RTCDeviceTypeIPadAir2,
|
||||||
{RTCDeviceTypeIPadMini2GWifi, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP693
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP708
|
||||||
|
{RTCDeviceTypeIPadMini2GWifi,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP693
|
||||||
{RTCDeviceTypeIPadMini2GCellular,
|
{RTCDeviceTypeIPadMini2GCellular,
|
||||||
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP693
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP693
|
||||||
{RTCDeviceTypeIPadMini2GWifiCellular,
|
{RTCDeviceTypeIPadMini2GWifiCellular,
|
||||||
{kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP693
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP693
|
||||||
{RTCDeviceTypeIPadMini3, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP709
|
{RTCDeviceTypeIPadMini3,
|
||||||
{RTCDeviceTypeIPadMini4, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP725
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP709
|
||||||
{RTCDeviceTypeIPadPro9Inch, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP739
|
{RTCDeviceTypeIPadMini4,
|
||||||
{RTCDeviceTypeIPadPro12Inch, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/sp723
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP725
|
||||||
{RTCDeviceTypeIPadPro12Inch2, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP761
|
{RTCDeviceTypeIPadPro9Inch,
|
||||||
{RTCDeviceTypeIPadPro10Inch, {kProfileHigh, kLevel4_2}}, // https://support.apple.com/kb/SP762
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP739
|
||||||
|
{RTCDeviceTypeIPadPro12Inch,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/sp723
|
||||||
|
{RTCDeviceTypeIPadPro12Inch2,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP761
|
||||||
|
{RTCDeviceTypeIPadPro10Inch,
|
||||||
|
{H264Profile::kProfileHigh, H264Level::kLevel4_2}}, // https://support.apple.com/kb/SP762
|
||||||
};
|
};
|
||||||
|
|
||||||
absl::optional<ProfileLevelId> FindMaxSupportedProfileForDevice(RTCDeviceType deviceType) {
|
absl::optional<H264ProfileLevelId> FindMaxSupportedProfileForDevice(RTCDeviceType deviceType) {
|
||||||
const auto* result = std::find_if(std::begin(kH264MaxSupportedProfiles),
|
const auto* result = std::find_if(std::begin(kH264MaxSupportedProfiles),
|
||||||
std::end(kH264MaxSupportedProfiles),
|
std::end(kH264MaxSupportedProfiles),
|
||||||
[deviceType](const SupportedH264Profile& supportedProfile) {
|
[deviceType](const SupportedH264Profile& supportedProfile) {
|
||||||
@ -123,7 +180,7 @@ absl::optional<ProfileLevelId> FindMaxSupportedProfileForDevice(RTCDeviceType de
|
|||||||
|
|
||||||
@implementation UIDevice (H264Profile)
|
@implementation UIDevice (H264Profile)
|
||||||
|
|
||||||
+ (absl::optional<webrtc::H264::ProfileLevelId>)maxSupportedH264Profile {
|
+ (absl::optional<webrtc::H264ProfileLevelId>)maxSupportedH264Profile {
|
||||||
return FindMaxSupportedProfileForDevice([self deviceType]);
|
return FindMaxSupportedProfileForDevice([self deviceType]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -84,7 +84,6 @@ rtc_library("video") {
|
|||||||
"../call:rtp_sender",
|
"../call:rtp_sender",
|
||||||
"../call:video_stream_api",
|
"../call:video_stream_api",
|
||||||
"../common_video",
|
"../common_video",
|
||||||
"../media:rtc_h264_profile_id",
|
|
||||||
"../modules:module_api",
|
"../modules:module_api",
|
||||||
"../modules:module_api_public",
|
"../modules:module_api_public",
|
||||||
"../modules/pacing",
|
"../modules/pacing",
|
||||||
@ -175,7 +174,6 @@ rtc_source_set("video_legacy") {
|
|||||||
"../call:rtp_receiver", # For RtxReceiveStream.
|
"../call:rtp_receiver", # For RtxReceiveStream.
|
||||||
"../call:video_stream_api",
|
"../call:video_stream_api",
|
||||||
"../common_video",
|
"../common_video",
|
||||||
"../media:rtc_h264_profile_id",
|
|
||||||
"../modules:module_api",
|
"../modules:module_api",
|
||||||
"../modules/pacing",
|
"../modules/pacing",
|
||||||
"../modules/remote_bitrate_estimator",
|
"../modules/remote_bitrate_estimator",
|
||||||
@ -431,7 +429,6 @@ if (rtc_include_tests) {
|
|||||||
"../api:test_dependency_factory",
|
"../api:test_dependency_factory",
|
||||||
"../api:video_quality_test_fixture_api",
|
"../api:video_quality_test_fixture_api",
|
||||||
"../api/video_codecs:video_codecs_api",
|
"../api/video_codecs:video_codecs_api",
|
||||||
"../media:rtc_vp9_profile",
|
|
||||||
"../modules/pacing",
|
"../modules/pacing",
|
||||||
"../modules/video_coding:webrtc_vp9",
|
"../modules/video_coding:webrtc_vp9",
|
||||||
"../rtc_base/experiments:alr_experiment",
|
"../rtc_base/experiments:alr_experiment",
|
||||||
@ -463,8 +460,8 @@ if (rtc_include_tests) {
|
|||||||
"../api:peer_connection_quality_test_fixture_api",
|
"../api:peer_connection_quality_test_fixture_api",
|
||||||
"../api:simulated_network_api",
|
"../api:simulated_network_api",
|
||||||
"../api:time_controller",
|
"../api:time_controller",
|
||||||
|
"../api/video_codecs:video_codecs_api",
|
||||||
"../call:simulated_network",
|
"../call:simulated_network",
|
||||||
"../media:rtc_vp9_profile",
|
|
||||||
"../modules/video_coding:webrtc_vp9",
|
"../modules/video_coding:webrtc_vp9",
|
||||||
"../system_wrappers:field_trial",
|
"../system_wrappers:field_trial",
|
||||||
"../test:field_trial",
|
"../test:field_trial",
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
#include "api/video_codecs/sdp_video_format.h"
|
#include "api/video_codecs/sdp_video_format.h"
|
||||||
#include "api/video_codecs/video_codec.h"
|
#include "api/video_codecs/video_codec.h"
|
||||||
#include "api/video_codecs/video_encoder_config.h"
|
#include "api/video_codecs/video_encoder_config.h"
|
||||||
#include "media/base/vp9_profile.h"
|
#include "api/video_codecs/vp9_profile.h"
|
||||||
#include "modules/video_coding/codecs/vp9/include/vp9.h"
|
#include "modules/video_coding/codecs/vp9/include/vp9.h"
|
||||||
#include "system_wrappers/include/field_trial.h"
|
#include "system_wrappers/include/field_trial.h"
|
||||||
#include "test/field_trial.h"
|
#include "test/field_trial.h"
|
||||||
|
|||||||
@ -21,8 +21,8 @@
|
|||||||
#include "api/test/peerconnection_quality_test_fixture.h"
|
#include "api/test/peerconnection_quality_test_fixture.h"
|
||||||
#include "api/test/simulated_network.h"
|
#include "api/test/simulated_network.h"
|
||||||
#include "api/test/time_controller.h"
|
#include "api/test/time_controller.h"
|
||||||
|
#include "api/video_codecs/vp9_profile.h"
|
||||||
#include "call/simulated_network.h"
|
#include "call/simulated_network.h"
|
||||||
#include "media/base/vp9_profile.h"
|
|
||||||
#include "modules/video_coding/codecs/vp9/include/vp9.h"
|
#include "modules/video_coding/codecs/vp9/include/vp9.h"
|
||||||
#include "system_wrappers/include/field_trial.h"
|
#include "system_wrappers/include/field_trial.h"
|
||||||
#include "test/field_trial.h"
|
#include "test/field_trial.h"
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "api/crypto/frame_decryptor_interface.h"
|
#include "api/crypto/frame_decryptor_interface.h"
|
||||||
#include "api/video/encoded_image.h"
|
#include "api/video/encoded_image.h"
|
||||||
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
#include "api/video_codecs/sdp_video_format.h"
|
#include "api/video_codecs/sdp_video_format.h"
|
||||||
#include "api/video_codecs/video_codec.h"
|
#include "api/video_codecs/video_codec.h"
|
||||||
#include "api/video_codecs/video_decoder_factory.h"
|
#include "api/video_codecs/video_decoder_factory.h"
|
||||||
@ -31,7 +32,6 @@
|
|||||||
#include "call/rtp_stream_receiver_controller_interface.h"
|
#include "call/rtp_stream_receiver_controller_interface.h"
|
||||||
#include "call/rtx_receive_stream.h"
|
#include "call/rtx_receive_stream.h"
|
||||||
#include "common_video/include/incoming_video_stream.h"
|
#include "common_video/include/incoming_video_stream.h"
|
||||||
#include "media/base/h264_profile_level_id.h"
|
|
||||||
#include "modules/utility/include/process_thread.h"
|
#include "modules/utility/include/process_thread.h"
|
||||||
#include "modules/video_coding/include/video_codec_interface.h"
|
#include "modules/video_coding/include/video_codec_interface.h"
|
||||||
#include "modules/video_coding/include/video_coding_defines.h"
|
#include "modules/video_coding/include/video_coding_defines.h"
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "api/crypto/frame_decryptor_interface.h"
|
#include "api/crypto/frame_decryptor_interface.h"
|
||||||
#include "api/video/encoded_image.h"
|
#include "api/video/encoded_image.h"
|
||||||
|
#include "api/video_codecs/h264_profile_level_id.h"
|
||||||
#include "api/video_codecs/sdp_video_format.h"
|
#include "api/video_codecs/sdp_video_format.h"
|
||||||
#include "api/video_codecs/video_codec.h"
|
#include "api/video_codecs/video_codec.h"
|
||||||
#include "api/video_codecs/video_decoder_factory.h"
|
#include "api/video_codecs/video_decoder_factory.h"
|
||||||
@ -31,7 +32,6 @@
|
|||||||
#include "call/rtp_stream_receiver_controller_interface.h"
|
#include "call/rtp_stream_receiver_controller_interface.h"
|
||||||
#include "call/rtx_receive_stream.h"
|
#include "call/rtx_receive_stream.h"
|
||||||
#include "common_video/include/incoming_video_stream.h"
|
#include "common_video/include/incoming_video_stream.h"
|
||||||
#include "media/base/h264_profile_level_id.h"
|
|
||||||
#include "modules/video_coding/include/video_codec_interface.h"
|
#include "modules/video_coding/include/video_codec_interface.h"
|
||||||
#include "modules/video_coding/include/video_coding_defines.h"
|
#include "modules/video_coding/include/video_coding_defines.h"
|
||||||
#include "modules/video_coding/include/video_error_codes.h"
|
#include "modules/video_coding/include/video_error_codes.h"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user