Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 14:04:28 +01:00
parent 81b91f4139
commit f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions

View file

@ -0,0 +1,89 @@
# Copyright (c) 2018 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.
import("../../../webrtc.gni")
if (rtc_include_tests) {
rtc_library("video_codecs_api_unittests") {
testonly = true
sources = [
"builtin_video_encoder_factory_unittest.cc",
"h264_profile_level_id_unittest.cc",
"sdp_video_format_unittest.cc",
"video_decoder_software_fallback_wrapper_unittest.cc",
"video_encoder_software_fallback_wrapper_unittest.cc",
]
if (rtc_use_h265) {
sources += [ "h265_profile_tier_level_unittest.cc" ]
}
deps = [
":video_decoder_factory_template_tests",
":video_encoder_factory_template_tests",
"..:builtin_video_encoder_factory",
"..:rtc_software_fallback_wrappers",
"..:video_codecs_api",
"../..:fec_controller_api",
"../..:mock_video_encoder",
"../../../api:scoped_refptr",
"../../../media:media_constants",
"../../../media:rtc_media_base",
"../../../modules/video_coding:video_codec_interface",
"../../../modules/video_coding:video_coding_utility",
"../../../modules/video_coding:webrtc_vp8",
"../../../rtc_base:checks",
"../../../rtc_base:rtc_base_tests_utils",
"../../../test:explicit_key_value_config",
"../../../test:fake_video_codecs",
"../../../test:field_trial",
"../../../test:test_support",
"../../../test:video_test_common",
"../../environment",
"../../environment:environment_factory",
"../../video:encoded_image",
"../../video:video_bitrate_allocation",
"../../video:video_frame",
"../../video:video_rtp_headers",
"//testing/gtest",
]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}
rtc_library("video_encoder_factory_template_tests") {
testonly = true
sources = [ "video_encoder_factory_template_tests.cc" ]
deps = [
"..:video_encoder_factory_template",
"..:video_encoder_factory_template_libaom_av1_adapter",
"..:video_encoder_factory_template_libvpx_vp8_adapter",
"..:video_encoder_factory_template_libvpx_vp9_adapter",
"..:video_encoder_factory_template_open_h264_adapter",
"../../:mock_video_encoder",
"../../../test:test_support",
"//testing/gtest",
]
}
rtc_library("video_decoder_factory_template_tests") {
testonly = true
sources = [ "video_decoder_factory_template_tests.cc" ]
deps = [
"..:video_decoder_factory_template",
"..:video_decoder_factory_template_dav1d_adapter",
"..:video_decoder_factory_template_libvpx_vp8_adapter",
"..:video_decoder_factory_template_libvpx_vp9_adapter",
"..:video_decoder_factory_template_open_h264_adapter",
"../../:mock_video_decoder",
"../../../test:test_support",
"//testing/gtest",
]
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2018 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/builtin_video_encoder_factory.h"
#include <memory>
#include <string>
#include <vector>
#include "api/video_codecs/sdp_video_format.h"
#include "test/gtest.h"
namespace webrtc {
TEST(BuiltinVideoEncoderFactoryTest, AnnouncesVp9AccordingToBuildFlags) {
std::unique_ptr<VideoEncoderFactory> factory =
CreateBuiltinVideoEncoderFactory();
bool claims_vp9_support = false;
for (const SdpVideoFormat& format : factory->GetSupportedFormats()) {
if (format.name == "VP9") {
claims_vp9_support = true;
break;
}
}
#if defined(RTC_ENABLE_VP9)
EXPECT_TRUE(claims_vp9_support);
#else
EXPECT_FALSE(claims_vp9_support);
#endif // defined(RTC_ENABLE_VP9)
}
} // namespace webrtc

View file

@ -0,0 +1,171 @@
/*
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "api/video_codecs/h264_profile_level_id.h"
#include <map>
#include <string>
#include "absl/types/optional.h"
#include "test/gtest.h"
namespace webrtc {
TEST(H264ProfileLevelId, TestParsingInvalid) {
// Malformed strings.
EXPECT_FALSE(ParseH264ProfileLevelId(""));
EXPECT_FALSE(ParseH264ProfileLevelId(" 42e01f"));
EXPECT_FALSE(ParseH264ProfileLevelId("4242e01f"));
EXPECT_FALSE(ParseH264ProfileLevelId("e01f"));
EXPECT_FALSE(ParseH264ProfileLevelId("gggggg"));
// Invalid level.
EXPECT_FALSE(ParseH264ProfileLevelId("42e000"));
EXPECT_FALSE(ParseH264ProfileLevelId("42e00f"));
EXPECT_FALSE(ParseH264ProfileLevelId("42e0ff"));
// Invalid profile.
EXPECT_FALSE(ParseH264ProfileLevelId("42e11f"));
EXPECT_FALSE(ParseH264ProfileLevelId("58601f"));
EXPECT_FALSE(ParseH264ProfileLevelId("64e01f"));
}
TEST(H264ProfileLevelId, TestParsingLevel) {
EXPECT_EQ(H264Level::kLevel3_1, ParseH264ProfileLevelId("42e01f")->level);
EXPECT_EQ(H264Level::kLevel1_1, ParseH264ProfileLevelId("42e00b")->level);
EXPECT_EQ(H264Level::kLevel1_b, ParseH264ProfileLevelId("42f00b")->level);
EXPECT_EQ(H264Level::kLevel4_2, ParseH264ProfileLevelId("42C02A")->level);
EXPECT_EQ(H264Level::kLevel5_2, ParseH264ProfileLevelId("640c34")->level);
}
TEST(H264ProfileLevelId, TestParsingConstrainedBaseline) {
EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
ParseH264ProfileLevelId("42e01f")->profile);
EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
ParseH264ProfileLevelId("42C02A")->profile);
EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
ParseH264ProfileLevelId("4de01f")->profile);
EXPECT_EQ(H264Profile::kProfileConstrainedBaseline,
ParseH264ProfileLevelId("58f01f")->profile);
}
TEST(H264ProfileLevelId, TestParsingBaseline) {
EXPECT_EQ(H264Profile::kProfileBaseline,
ParseH264ProfileLevelId("42a01f")->profile);
EXPECT_EQ(H264Profile::kProfileBaseline,
ParseH264ProfileLevelId("58A01F")->profile);
}
TEST(H264ProfileLevelId, TestParsingMain) {
EXPECT_EQ(H264Profile::kProfileMain,
ParseH264ProfileLevelId("4D401f")->profile);
}
TEST(H264ProfileLevelId, TestParsingHigh) {
EXPECT_EQ(H264Profile::kProfileHigh,
ParseH264ProfileLevelId("64001f")->profile);
}
TEST(H264ProfileLevelId, TestParsingConstrainedHigh) {
EXPECT_EQ(H264Profile::kProfileConstrainedHigh,
ParseH264ProfileLevelId("640c1f")->profile);
}
TEST(H264ProfileLevelId, TestSupportedLevel) {
EXPECT_EQ(H264Level::kLevel2_1, *H264SupportedLevel(640 * 480, 25));
EXPECT_EQ(H264Level::kLevel3_1, *H264SupportedLevel(1280 * 720, 30));
EXPECT_EQ(H264Level::kLevel4_2, *H264SupportedLevel(1920 * 1280, 60));
}
// Test supported level below level 1 requirements.
TEST(H264ProfileLevelId, TestSupportedLevelInvalid) {
EXPECT_FALSE(H264SupportedLevel(0, 0));
// All levels support fps > 5.
EXPECT_FALSE(H264SupportedLevel(1280 * 720, 5));
// All levels support frame sizes > 183 * 137.
EXPECT_FALSE(H264SupportedLevel(183 * 137, 30));
}
TEST(H264ProfileLevelId, TestToString) {
EXPECT_EQ("42e01f", *H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileConstrainedBaseline,
H264Level::kLevel3_1)));
EXPECT_EQ("42000a", *H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileBaseline, H264Level::kLevel1)));
EXPECT_EQ("4d001f", H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileMain, H264Level::kLevel3_1)));
EXPECT_EQ("640c2a",
*H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileConstrainedHigh, H264Level::kLevel4_2)));
EXPECT_EQ("64002a", *H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileHigh, H264Level::kLevel4_2)));
}
TEST(H264ProfileLevelId, TestToStringLevel1b) {
EXPECT_EQ("42f00b", *H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileConstrainedBaseline,
H264Level::kLevel1_b)));
EXPECT_EQ("42100b",
*H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileBaseline, H264Level::kLevel1_b)));
EXPECT_EQ("4d100b", *H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileMain, H264Level::kLevel1_b)));
}
TEST(H264ProfileLevelId, TestToStringRoundTrip) {
EXPECT_EQ("42e01f",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("42e01f")));
EXPECT_EQ("42e01f",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("42E01F")));
EXPECT_EQ("4d100b",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("4d100b")));
EXPECT_EQ("4d100b",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("4D100B")));
EXPECT_EQ("640c2a",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("640c2a")));
EXPECT_EQ("640c2a",
*H264ProfileLevelIdToString(*ParseH264ProfileLevelId("640C2A")));
}
TEST(H264ProfileLevelId, TestToStringInvalid) {
EXPECT_FALSE(H264ProfileLevelIdToString(
H264ProfileLevelId(H264Profile::kProfileHigh, H264Level::kLevel1_b)));
EXPECT_FALSE(H264ProfileLevelIdToString(H264ProfileLevelId(
H264Profile::kProfileConstrainedHigh, H264Level::kLevel1_b)));
EXPECT_FALSE(H264ProfileLevelIdToString(
H264ProfileLevelId(static_cast<H264Profile>(255), H264Level::kLevel3_1)));
}
TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdEmpty) {
const absl::optional<H264ProfileLevelId> profile_level_id =
ParseSdpForH264ProfileLevelId(CodecParameterMap());
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) {
CodecParameterMap 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) {
CodecParameterMap params;
params["profile-level-id"] = "foobar";
EXPECT_FALSE(ParseSdpForH264ProfileLevelId(params));
}
} // namespace webrtc

View file

@ -0,0 +1,248 @@
/*
* Copyright (c) 2023 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/h265_profile_tier_level.h"
#include <string>
#include "absl/types/optional.h"
#include "test/gtest.h"
namespace webrtc {
TEST(H265ProfileTierLevel, TestLevelToString) {
EXPECT_EQ(H265LevelToString(H265Level::kLevel1), "30");
EXPECT_EQ(H265LevelToString(H265Level::kLevel2), "60");
EXPECT_EQ(H265LevelToString(H265Level::kLevel2_1), "63");
EXPECT_EQ(H265LevelToString(H265Level::kLevel3), "90");
EXPECT_EQ(H265LevelToString(H265Level::kLevel3_1), "93");
EXPECT_EQ(H265LevelToString(H265Level::kLevel4), "120");
EXPECT_EQ(H265LevelToString(H265Level::kLevel4_1), "123");
EXPECT_EQ(H265LevelToString(H265Level::kLevel5), "150");
EXPECT_EQ(H265LevelToString(H265Level::kLevel5_1), "153");
EXPECT_EQ(H265LevelToString(H265Level::kLevel5_2), "156");
EXPECT_EQ(H265LevelToString(H265Level::kLevel6), "180");
EXPECT_EQ(H265LevelToString(H265Level::kLevel6_1), "183");
EXPECT_EQ(H265LevelToString(H265Level::kLevel6_2), "186");
}
TEST(H265ProfileTierLevel, TestProfileToString) {
EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMain), "1");
EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMain10), "2");
EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMainStill), "3");
EXPECT_EQ(H265ProfileToString(H265Profile::kProfileRangeExtensions), "4");
EXPECT_EQ(H265ProfileToString(H265Profile::kProfileHighThroughput), "5");
EXPECT_EQ(H265ProfileToString(H265Profile::kProfileMultiviewMain), "6");
EXPECT_EQ(H265ProfileToString(H265Profile::kProfileScalableMain), "7");
EXPECT_EQ(H265ProfileToString(H265Profile::kProfile3dMain), "8");
EXPECT_EQ(H265ProfileToString(H265Profile::kProfileScreenContentCoding), "9");
EXPECT_EQ(H265ProfileToString(H265Profile::kProfileScalableRangeExtensions),
"10");
EXPECT_EQ(H265ProfileToString(
H265Profile::kProfileHighThroughputScreenContentCoding),
"11");
}
TEST(H265ProfileTierLevel, TestTierToString) {
EXPECT_EQ(H265TierToString(H265Tier::kTier0), "0");
EXPECT_EQ(H265TierToString(H265Tier::kTier1), "1");
}
TEST(H265ProfileTierLevel, TestStringToProfile) {
// Invalid profiles.
EXPECT_FALSE(StringToH265Profile("0"));
EXPECT_FALSE(StringToH265Profile("12"));
// Malformed profiles
EXPECT_FALSE(StringToH265Profile(""));
EXPECT_FALSE(StringToH265Profile(" 1"));
EXPECT_FALSE(StringToH265Profile("12x"));
EXPECT_FALSE(StringToH265Profile("x12"));
EXPECT_FALSE(StringToH265Profile("gggg"));
// Valid profiles.
EXPECT_EQ(StringToH265Profile("1"), H265Profile::kProfileMain);
EXPECT_EQ(StringToH265Profile("2"), H265Profile::kProfileMain10);
EXPECT_EQ(StringToH265Profile("4"), H265Profile::kProfileRangeExtensions);
}
TEST(H265ProfileTierLevel, TestStringToLevel) {
// Invalid levels.
EXPECT_FALSE(StringToH265Level("0"));
EXPECT_FALSE(StringToH265Level("200"));
// Malformed levels.
EXPECT_FALSE(StringToH265Level(""));
EXPECT_FALSE(StringToH265Level(" 30"));
EXPECT_FALSE(StringToH265Level("30x"));
EXPECT_FALSE(StringToH265Level("x30"));
EXPECT_FALSE(StringToH265Level("ggggg"));
// Valid levels.
EXPECT_EQ(StringToH265Level("30"), H265Level::kLevel1);
EXPECT_EQ(StringToH265Level("93"), H265Level::kLevel3_1);
EXPECT_EQ(StringToH265Level("183"), H265Level::kLevel6_1);
}
TEST(H265ProfileTierLevel, TestStringToTier) {
// Invalid tiers.
EXPECT_FALSE(StringToH265Tier("4"));
EXPECT_FALSE(StringToH265Tier("-1"));
// Malformed tiers.
EXPECT_FALSE(StringToH265Tier(""));
EXPECT_FALSE(StringToH265Tier(" 1"));
EXPECT_FALSE(StringToH265Tier("t1"));
// Valid tiers.
EXPECT_EQ(StringToH265Tier("0"), H265Tier::kTier0);
EXPECT_EQ(StringToH265Tier("1"), H265Tier::kTier1);
}
TEST(H265ProfileTierLevel, TestParseSdpProfileTierLevelAllEmpty) {
const absl::optional<H265ProfileTierLevel> profile_tier_level =
ParseSdpForH265ProfileTierLevel(CodecParameterMap());
EXPECT_TRUE(profile_tier_level);
EXPECT_EQ(H265Profile::kProfileMain, profile_tier_level->profile);
EXPECT_EQ(H265Level::kLevel3_1, profile_tier_level->level);
EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier);
}
TEST(H265ProfileTierLevel, TestParseSdpProfileTierLevelPartialEmpty) {
CodecParameterMap params;
params["profile-id"] = "1";
params["tier-flag"] = "0";
absl::optional<H265ProfileTierLevel> profile_tier_level =
ParseSdpForH265ProfileTierLevel(params);
EXPECT_TRUE(profile_tier_level);
EXPECT_EQ(H265Profile::kProfileMain, profile_tier_level->profile);
EXPECT_EQ(H265Level::kLevel3_1, profile_tier_level->level);
EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier);
params.clear();
params["profile-id"] = "2";
profile_tier_level = ParseSdpForH265ProfileTierLevel(params);
EXPECT_TRUE(profile_tier_level);
EXPECT_EQ(H265Profile::kProfileMain10, profile_tier_level->profile);
EXPECT_EQ(H265Level::kLevel3_1, profile_tier_level->level);
EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier);
params.clear();
params["level-id"] = "180";
profile_tier_level = ParseSdpForH265ProfileTierLevel(params);
EXPECT_TRUE(profile_tier_level);
EXPECT_EQ(H265Profile::kProfileMain, profile_tier_level->profile);
EXPECT_EQ(H265Level::kLevel6, profile_tier_level->level);
EXPECT_EQ(H265Tier::kTier0, profile_tier_level->tier);
}
TEST(H265ProfileTierLevel, TestParseSdpProfileTierLevelInvalid) {
CodecParameterMap params;
// Invalid profile-tier-level combination.
params["profile-id"] = "1";
params["tier-flag"] = "1";
params["level-id"] = "93";
absl::optional<H265ProfileTierLevel> profile_tier_level =
ParseSdpForH265ProfileTierLevel(params);
EXPECT_FALSE(profile_tier_level);
params.clear();
params["profile-id"] = "1";
params["tier-flag"] = "4";
params["level-id"] = "180";
profile_tier_level = ParseSdpForH265ProfileTierLevel(params);
EXPECT_FALSE(profile_tier_level);
// Valid profile-tier-level combination.
params.clear();
params["profile-id"] = "1";
params["tier-flag"] = "0";
params["level-id"] = "153";
profile_tier_level = ParseSdpForH265ProfileTierLevel(params);
EXPECT_TRUE(profile_tier_level);
}
TEST(H265ProfileTierLevel, TestToStringRoundTrip) {
CodecParameterMap params;
params["profile-id"] = "1";
params["tier-flag"] = "0";
params["level-id"] = "93";
absl::optional<H265ProfileTierLevel> profile_tier_level =
ParseSdpForH265ProfileTierLevel(params);
EXPECT_TRUE(profile_tier_level);
EXPECT_EQ("1", H265ProfileToString(profile_tier_level->profile));
EXPECT_EQ("0", H265TierToString(profile_tier_level->tier));
EXPECT_EQ("93", H265LevelToString(profile_tier_level->level));
params.clear();
params["profile-id"] = "2";
params["tier-flag"] = "1";
params["level-id"] = "180";
profile_tier_level = ParseSdpForH265ProfileTierLevel(params);
EXPECT_TRUE(profile_tier_level);
EXPECT_EQ("2", H265ProfileToString(profile_tier_level->profile));
EXPECT_EQ("1", H265TierToString(profile_tier_level->tier));
EXPECT_EQ("180", H265LevelToString(profile_tier_level->level));
}
TEST(H265ProfileTierLevel, TestProfileTierLevelCompare) {
CodecParameterMap params1;
CodecParameterMap params2;
// None of profile-id/tier-flag/level-id is specified,
EXPECT_TRUE(H265IsSameProfileTierLevel(params1, params2));
// Same non-empty PTL
params1["profile-id"] = "1";
params1["tier-flag"] = "0";
params1["level-id"] = "120";
params2["profile-id"] = "1";
params2["tier-flag"] = "0";
params2["level-id"] = "120";
EXPECT_TRUE(H265IsSameProfileTierLevel(params1, params2));
// Different profiles.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "2";
EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2));
// Different levels.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "1";
params1["level-id"] = "93";
params2["level-id"] = "183";
EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2));
// Different tiers.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "1";
params1["level-id"] = "93";
params2["level-id"] = "93";
params1["tier-flag"] = "0";
params2["tier-flag"] = "1";
EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2));
// One of the CodecParameterMap is invalid.
params1.clear();
params2.clear();
params1["profile-id"] = "1";
params2["profile-id"] = "1";
params1["tier-flag"] = "0";
params2["tier-flag"] = "4";
EXPECT_FALSE(H265IsSameProfileTierLevel(params1, params2));
}
} // namespace webrtc

View file

@ -0,0 +1,155 @@
/*
* 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/sdp_video_format.h"
#include <stdint.h>
#include "media/base/media_constants.h"
#include "test/gtest.h"
namespace webrtc {
typedef SdpVideoFormat Sdp;
typedef CodecParameterMap Params;
TEST(SdpVideoFormatTest, SameCodecNameNoParameters) {
EXPECT_TRUE(Sdp("H264").IsSameCodec(Sdp("h264")));
EXPECT_TRUE(Sdp("VP8").IsSameCodec(Sdp("vp8")));
EXPECT_TRUE(Sdp("VP9").IsSameCodec(Sdp("vp9")));
EXPECT_TRUE(Sdp("AV1").IsSameCodec(Sdp("Av1")));
#ifdef RTC_ENABLE_H265
EXPECT_TRUE(Sdp("H265").IsSameCodec(Sdp("h265")));
#endif
}
TEST(SdpVideoFormatTest, DifferentCodecNameNoParameters) {
EXPECT_FALSE(Sdp("H264").IsSameCodec(Sdp("VP8")));
EXPECT_FALSE(Sdp("VP8").IsSameCodec(Sdp("VP9")));
EXPECT_FALSE(Sdp("AV1").IsSameCodec(Sdp("VP8")));
#ifdef RTC_ENABLE_H265
EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp("VP8")));
#endif
}
TEST(SdpVideoFormatTest, SameCodecNameSameParameters) {
EXPECT_TRUE(Sdp("VP9").IsSameCodec(Sdp("VP9", Params{{"profile-id", "0"}})));
EXPECT_TRUE(Sdp("VP9", Params{{"profile-id", "0"}})
.IsSameCodec(Sdp("VP9", Params{{"profile-id", "0"}})));
EXPECT_TRUE(Sdp("VP9", Params{{"profile-id", "2"}})
.IsSameCodec(Sdp("VP9", Params{{"profile-id", "2"}})));
EXPECT_TRUE(
Sdp("H264", Params{{"profile-level-id", "42e01f"}})
.IsSameCodec(Sdp("H264", Params{{"profile-level-id", "42e01f"}})));
EXPECT_TRUE(
Sdp("H264", Params{{"profile-level-id", "640c34"}})
.IsSameCodec(Sdp("H264", Params{{"profile-level-id", "640c34"}})));
EXPECT_TRUE(Sdp("AV1").IsSameCodec(Sdp("AV1", Params{{"profile", "0"}})));
EXPECT_TRUE(Sdp("AV1", Params{{"profile", "0"}})
.IsSameCodec(Sdp("AV1", Params{{"profile", "0"}})));
EXPECT_TRUE(Sdp("AV1", Params{{"profile", "2"}})
.IsSameCodec(Sdp("AV1", Params{{"profile", "2"}})));
#ifdef RTC_ENABLE_H265
EXPECT_TRUE(Sdp("H265").IsSameCodec(Sdp(
"H265",
Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "93"}})));
EXPECT_TRUE(
Sdp("H265",
Params{{"profile-id", "2"}, {"tier-flag", "0"}, {"level-id", "93"}})
.IsSameCodec(Sdp("H265", Params{{"profile-id", "2"},
{"tier-flag", "0"},
{"level-id", "93"}})));
#endif
}
TEST(SdpVideoFormatTest, SameCodecNameDifferentParameters) {
EXPECT_FALSE(Sdp("VP9").IsSameCodec(Sdp("VP9", Params{{"profile-id", "2"}})));
EXPECT_FALSE(Sdp("VP9", Params{{"profile-id", "0"}})
.IsSameCodec(Sdp("VP9", Params{{"profile-id", "1"}})));
EXPECT_FALSE(Sdp("VP9", Params{{"profile-id", "2"}})
.IsSameCodec(Sdp("VP9", Params{{"profile-id", "0"}})));
EXPECT_FALSE(
Sdp("H264", Params{{"profile-level-id", "42e01f"}})
.IsSameCodec(Sdp("H264", Params{{"profile-level-id", "640c34"}})));
EXPECT_FALSE(
Sdp("H264", Params{{"profile-level-id", "640c34"}})
.IsSameCodec(Sdp("H264", Params{{"profile-level-id", "42f00b"}})));
EXPECT_FALSE(Sdp("AV1").IsSameCodec(Sdp("AV1", Params{{"profile", "1"}})));
EXPECT_FALSE(Sdp("AV1", Params{{"profile", "0"}})
.IsSameCodec(Sdp("AV1", Params{{"profile", "1"}})));
EXPECT_FALSE(Sdp("AV1", Params{{"profile", "1"}})
.IsSameCodec(Sdp("AV1", Params{{"profile", "2"}})));
#ifdef RTC_ENABLE_H265
EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp(
"H265",
Params{{"profile-id", "0"}, {"tier-flag", "0"}, {"level-id", "93"}})));
EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp(
"H265",
Params{{"profile-id", "1"}, {"tier-flag", "1"}, {"level-id", "93"}})));
EXPECT_FALSE(Sdp("H265").IsSameCodec(Sdp(
"H265",
Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "90"}})));
EXPECT_FALSE(
Sdp("H265",
Params{{"profile-id", "2"}, {"tier-flag", "0"}, {"level-id", "93"}})
.IsSameCodec(Sdp("H265", Params{{"profile-id", "1"},
{"tier-flag", "0"},
{"level-id", "93"}})));
EXPECT_FALSE(
Sdp("H265",
Params{{"profile-id", "1"}, {"tier-flag", "1"}, {"level-id", "120"}})
.IsSameCodec(Sdp("H265", Params{{"profile-id", "1"},
{"tier-flag", "0"},
{"level-id", "120"}})));
EXPECT_FALSE(
Sdp("H265",
Params{{"profile-id", "1"}, {"tier-flag", "0"}, {"level-id", "93"}})
.IsSameCodec(Sdp("H265", Params{{"profile-id", "1"},
{"tier-flag", "0"},
{"level-id", "90"}})));
#endif
}
TEST(SdpVideoFormatTest, DifferentCodecNameSameParameters) {
EXPECT_FALSE(Sdp("VP9", Params{{"profile-id", "0"}})
.IsSameCodec(Sdp("H264", Params{{"profile-id", "0"}})));
EXPECT_FALSE(Sdp("VP9", Params{{"profile-id", "2"}})
.IsSameCodec(Sdp("VP8", Params{{"profile-id", "2"}})));
EXPECT_FALSE(
Sdp("H264", Params{{"profile-level-id", "42e01f"}})
.IsSameCodec(Sdp("VP9", Params{{"profile-level-id", "42e01f"}})));
EXPECT_FALSE(
Sdp("H264", Params{{"profile-level-id", "640c34"}})
.IsSameCodec(Sdp("VP8", Params{{"profile-level-id", "640c34"}})));
EXPECT_FALSE(Sdp("AV1", Params{{"profile", "0"}})
.IsSameCodec(Sdp("H264", Params{{"profile", "0"}})));
EXPECT_FALSE(Sdp("AV1", Params{{"profile", "2"}})
.IsSameCodec(Sdp("VP9", Params{{"profile", "2"}})));
#ifdef RTC_ENABLE_H265
EXPECT_FALSE(Sdp("H265", Params{{"profile-id", "0"}})
.IsSameCodec(Sdp("H264", Params{{"profile-id", "0"}})));
EXPECT_FALSE(Sdp("H265", Params{{"profile-id", "2"}})
.IsSameCodec(Sdp("VP9", Params{{"profile-id", "2"}})));
#endif
}
TEST(SdpVideoFormatTest, H264PacketizationMode) {
// The default packetization mode is 0.
EXPECT_TRUE(Sdp("H264", Params{{cricket::kH264FmtpPacketizationMode, "0"}})
.IsSameCodec(Sdp("H264")));
EXPECT_FALSE(Sdp("H264", Params{{cricket::kH264FmtpPacketizationMode, "1"}})
.IsSameCodec(Sdp("H264")));
EXPECT_TRUE(
Sdp("H264", Params{{cricket::kH264FmtpPacketizationMode, "1"}})
.IsSameCodec(
Sdp("H264", Params{{cricket::kH264FmtpPacketizationMode, "1"}})));
}
} // namespace webrtc

View file

@ -0,0 +1,123 @@
/*
* Copyright (c) 2022 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/test/mock_video_decoder.h"
#include "api/video_codecs/video_decoder_factory_template.h"
#include "api/video_codecs/video_decoder_factory_template_dav1d_adapter.h"
#include "api/video_codecs/video_decoder_factory_template_libvpx_vp8_adapter.h"
#include "api/video_codecs/video_decoder_factory_template_libvpx_vp9_adapter.h"
#include "api/video_codecs/video_decoder_factory_template_open_h264_adapter.h"
#include "test/gmock.h"
#include "test/gtest.h"
using ::testing::Contains;
using ::testing::Each;
using ::testing::Eq;
using ::testing::Field;
using ::testing::IsEmpty;
using ::testing::Ne;
using ::testing::Not;
using ::testing::UnorderedElementsAre;
namespace webrtc {
namespace {
const SdpVideoFormat kFooSdp("Foo");
const SdpVideoFormat kBarLowSdp("Bar", {{"profile", "low"}});
const SdpVideoFormat kBarHighSdp("Bar", {{"profile", "high"}});
struct FooDecoderTemplateAdapter {
static std::vector<SdpVideoFormat> SupportedFormats() { return {kFooSdp}; }
static std::unique_ptr<VideoDecoder> CreateDecoder(
const SdpVideoFormat& format) {
auto decoder = std::make_unique<testing::StrictMock<MockVideoDecoder>>();
EXPECT_CALL(*decoder, Destruct);
return decoder;
}
};
struct BarDecoderTemplateAdapter {
static std::vector<SdpVideoFormat> SupportedFormats() {
return {kBarLowSdp, kBarHighSdp};
}
static std::unique_ptr<VideoDecoder> CreateDecoder(
const SdpVideoFormat& format) {
auto decoder = std::make_unique<testing::StrictMock<MockVideoDecoder>>();
EXPECT_CALL(*decoder, Destruct);
return decoder;
}
};
TEST(VideoDecoderFactoryTemplate, OneTemplateAdapterCreateDecoder) {
VideoDecoderFactoryTemplate<FooDecoderTemplateAdapter> factory;
EXPECT_THAT(factory.GetSupportedFormats(), UnorderedElementsAre(kFooSdp));
EXPECT_THAT(factory.CreateVideoDecoder(kFooSdp), Ne(nullptr));
EXPECT_THAT(factory.CreateVideoDecoder(SdpVideoFormat("FooX")), Eq(nullptr));
}
TEST(VideoDecoderFactoryTemplate, TwoTemplateAdaptersNoDuplicates) {
VideoDecoderFactoryTemplate<FooDecoderTemplateAdapter,
FooDecoderTemplateAdapter>
factory;
EXPECT_THAT(factory.GetSupportedFormats(), UnorderedElementsAre(kFooSdp));
}
TEST(VideoDecoderFactoryTemplate, TwoTemplateAdaptersCreateDecoders) {
VideoDecoderFactoryTemplate<FooDecoderTemplateAdapter,
BarDecoderTemplateAdapter>
factory;
EXPECT_THAT(factory.GetSupportedFormats(),
UnorderedElementsAre(kFooSdp, kBarLowSdp, kBarHighSdp));
EXPECT_THAT(factory.CreateVideoDecoder(kFooSdp), Ne(nullptr));
EXPECT_THAT(factory.CreateVideoDecoder(kBarLowSdp), Ne(nullptr));
EXPECT_THAT(factory.CreateVideoDecoder(kBarHighSdp), Ne(nullptr));
EXPECT_THAT(factory.CreateVideoDecoder(SdpVideoFormat("FooX")), Eq(nullptr));
EXPECT_THAT(factory.CreateVideoDecoder(SdpVideoFormat("Bar")), Eq(nullptr));
}
TEST(VideoDecoderFactoryTemplate, LibvpxVp8) {
VideoDecoderFactoryTemplate<LibvpxVp8DecoderTemplateAdapter> factory;
auto formats = factory.GetSupportedFormats();
EXPECT_THAT(formats.size(), 1);
EXPECT_THAT(formats[0], Field(&SdpVideoFormat::name, "VP8"));
EXPECT_THAT(factory.CreateVideoDecoder(formats[0]), Ne(nullptr));
}
TEST(VideoDecoderFactoryTemplate, LibvpxVp9) {
VideoDecoderFactoryTemplate<LibvpxVp9DecoderTemplateAdapter> factory;
auto formats = factory.GetSupportedFormats();
EXPECT_THAT(formats, Not(IsEmpty()));
EXPECT_THAT(formats, Each(Field(&SdpVideoFormat::name, "VP9")));
EXPECT_THAT(factory.CreateVideoDecoder(formats[0]), Ne(nullptr));
}
// TODO(bugs.webrtc.org/13573): When OpenH264 is no longer a conditional build
// target remove this #ifdef.
#if defined(WEBRTC_USE_H264)
TEST(VideoDecoderFactoryTemplate, OpenH264) {
VideoDecoderFactoryTemplate<OpenH264DecoderTemplateAdapter> factory;
auto formats = factory.GetSupportedFormats();
EXPECT_THAT(formats, Not(IsEmpty()));
EXPECT_THAT(formats, Each(Field(&SdpVideoFormat::name, "H264")));
EXPECT_THAT(factory.CreateVideoDecoder(formats[0]), Ne(nullptr));
}
#endif // defined(WEBRTC_USE_H264)
TEST(VideoDecoderFactoryTemplate, Dav1d) {
VideoDecoderFactoryTemplate<Dav1dDecoderTemplateAdapter> factory;
auto formats = factory.GetSupportedFormats();
EXPECT_THAT(formats, Not(IsEmpty()));
EXPECT_THAT(formats, Each(Field(&SdpVideoFormat::name, "AV1")));
EXPECT_THAT(factory.CreateVideoDecoder(formats[0]), Ne(nullptr));
}
} // namespace
} // namespace webrtc

View file

@ -0,0 +1,309 @@
/*
* Copyright (c) 2015 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/video_decoder_software_fallback_wrapper.h"
#include <stdint.h>
#include "absl/types/optional.h"
#include "api/environment/environment.h"
#include "api/environment/environment_factory.h"
#include "api/video/encoded_image.h"
#include "api/video/video_frame.h"
#include "api/video_codecs/video_decoder.h"
#include "modules/video_coding/codecs/vp8/include/vp8.h"
#include "modules/video_coding/include/video_codec_interface.h"
#include "modules/video_coding/include/video_error_codes.h"
#include "rtc_base/checks.h"
#include "test/explicit_key_value_config.h"
#include "test/gtest.h"
namespace webrtc {
class VideoDecoderSoftwareFallbackWrapperTest : public ::testing::Test {
protected:
VideoDecoderSoftwareFallbackWrapperTest()
: VideoDecoderSoftwareFallbackWrapperTest("") {}
explicit VideoDecoderSoftwareFallbackWrapperTest(
const std::string& field_trials)
: field_trials_(field_trials),
env_(CreateEnvironment(&field_trials_)),
fake_decoder_(new CountingFakeDecoder()),
fallback_wrapper_(CreateVideoDecoderSoftwareFallbackWrapper(
env_,
CreateVp8Decoder(env_),
std::unique_ptr<VideoDecoder>(fake_decoder_))) {}
class CountingFakeDecoder : public VideoDecoder {
public:
bool Configure(const Settings& settings) override {
++configure_count_;
return configure_return_value_;
}
int32_t Decode(const EncodedImage& input_image,
int64_t render_time_ms) override {
++decode_count_;
return decode_return_code_;
}
int32_t RegisterDecodeCompleteCallback(
DecodedImageCallback* callback) override {
decode_complete_callback_ = callback;
return WEBRTC_VIDEO_CODEC_OK;
}
int32_t Release() override {
++release_count_;
return WEBRTC_VIDEO_CODEC_OK;
}
const char* ImplementationName() const override { return "fake-decoder"; }
int configure_count_ = 0;
int decode_count_ = 0;
bool configure_return_value_ = true;
int32_t decode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
DecodedImageCallback* decode_complete_callback_ = nullptr;
int release_count_ = 0;
int reset_count_ = 0;
};
test::ExplicitKeyValueConfig field_trials_;
const Environment env_;
// `fake_decoder_` is owned and released by `fallback_wrapper_`.
CountingFakeDecoder* fake_decoder_;
std::unique_ptr<VideoDecoder> fallback_wrapper_;
};
TEST_F(VideoDecoderSoftwareFallbackWrapperTest, InitializesDecoder) {
fallback_wrapper_->Configure({});
EXPECT_EQ(1, fake_decoder_->configure_count_);
EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameKey;
fallback_wrapper_->Decode(encoded_image, -1);
EXPECT_EQ(1, fake_decoder_->configure_count_)
<< "Initialized decoder should not be reinitialized.";
EXPECT_EQ(1, fake_decoder_->decode_count_);
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
UsesFallbackDecoderAfterAnyInitDecodeFailure) {
fake_decoder_->configure_return_value_ = false;
fallback_wrapper_->Configure({});
EXPECT_EQ(1, fake_decoder_->configure_count_);
EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameKey;
fallback_wrapper_->Decode(encoded_image, -1);
EXPECT_EQ(1, fake_decoder_->configure_count_)
<< "Should not have attempted reinitializing the fallback decoder on "
"keyframe.";
// Unfortunately faking a VP8 frame is hard. Rely on no Decode -> using SW
// decoder.
EXPECT_EQ(0, fake_decoder_->decode_count_)
<< "Decoder used even though no InitDecode had succeeded.";
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest, IsSoftwareFallbackSticky) {
fallback_wrapper_->Configure({});
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
EncodedImage encoded_image;
fallback_wrapper_->Decode(encoded_image, -1);
EXPECT_EQ(1, fake_decoder_->decode_count_);
// Software fallback should be sticky, fake_decoder_ shouldn't be used.
encoded_image._frameType = VideoFrameType::kVideoFrameKey;
fallback_wrapper_->Decode(encoded_image, -1);
EXPECT_EQ(1, fake_decoder_->decode_count_)
<< "Decoder shouldn't be used after failure.";
// fake_decoder_ should have only been initialized once during the test.
EXPECT_EQ(1, fake_decoder_->configure_count_);
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest, DoesNotFallbackOnEveryError) {
fallback_wrapper_->Configure({});
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
EncodedImage encoded_image;
EXPECT_EQ(fake_decoder_->decode_return_code_,
fallback_wrapper_->Decode(encoded_image, -1));
EXPECT_EQ(1, fake_decoder_->decode_count_);
fallback_wrapper_->Decode(encoded_image, -1);
EXPECT_EQ(2, fake_decoder_->decode_count_)
<< "Decoder should be active even though previous decode failed.";
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest, UsesHwDecoderAfterReinit) {
fallback_wrapper_->Configure({});
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
EncodedImage encoded_image;
fallback_wrapper_->Decode(encoded_image, -1);
EXPECT_EQ(1, fake_decoder_->decode_count_);
fallback_wrapper_->Release();
fallback_wrapper_->Configure({});
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
fallback_wrapper_->Decode(encoded_image, -1);
EXPECT_EQ(2, fake_decoder_->decode_count_)
<< "Should not be using fallback after reinit.";
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest, ForwardsReleaseCall) {
fallback_wrapper_->Configure({});
fallback_wrapper_->Release();
EXPECT_EQ(1, fake_decoder_->release_count_);
fallback_wrapper_->Configure({});
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
EncodedImage encoded_image;
fallback_wrapper_->Decode(encoded_image, -1);
EXPECT_EQ(2, fake_decoder_->release_count_)
<< "Decoder should be released during fallback.";
fallback_wrapper_->Release();
EXPECT_EQ(2, fake_decoder_->release_count_);
}
// TODO(pbos): Fake a VP8 frame well enough to actually receive a callback from
// the software decoder.
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
ForwardsRegisterDecodeCompleteCallback) {
class FakeDecodedImageCallback : public DecodedImageCallback {
int32_t Decoded(VideoFrame& decodedImage) override { return 0; }
int32_t Decoded(webrtc::VideoFrame& decodedImage,
int64_t decode_time_ms) override {
RTC_DCHECK_NOTREACHED();
return -1;
}
void Decoded(webrtc::VideoFrame& decodedImage,
absl::optional<int32_t> decode_time_ms,
absl::optional<uint8_t> qp) override {
RTC_DCHECK_NOTREACHED();
}
} callback;
fallback_wrapper_->Configure({});
fallback_wrapper_->RegisterDecodeCompleteCallback(&callback);
EXPECT_EQ(&callback, fake_decoder_->decode_complete_callback_);
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
ReportsFallbackImplementationName) {
fallback_wrapper_->Configure({});
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
EncodedImage encoded_image;
fallback_wrapper_->Decode(encoded_image, -1);
// Hard coded expected value since libvpx is the software implementation name
// for VP8. Change accordingly if the underlying implementation does.
EXPECT_STREQ("libvpx (fallback from: fake-decoder)",
fallback_wrapper_->ImplementationName());
fallback_wrapper_->Release();
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest, FallbacksOnTooManyErrors) {
fallback_wrapper_->Configure({});
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameKey;
// Doesn't fallback from a single error.
fallback_wrapper_->Decode(encoded_image, -1);
EXPECT_STREQ("fake-decoder", fallback_wrapper_->ImplementationName());
// However, many frames with the same error, fallback should happen.
const int kNumFramesToEncode = 10;
for (int i = 0; i < kNumFramesToEncode; ++i) {
fallback_wrapper_->Decode(encoded_image, -1);
}
// Hard coded expected value since libvpx is the software implementation name
// for VP8. Change accordingly if the underlying implementation does.
EXPECT_STREQ("libvpx (fallback from: fake-decoder)",
fallback_wrapper_->ImplementationName());
fallback_wrapper_->Release();
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
DoesNotFallbackOnDeltaFramesErrors) {
fallback_wrapper_->Configure({});
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
// Many decoded frames with the same error
const int kNumFramesToEncode = 10;
for (int i = 0; i < kNumFramesToEncode; ++i) {
fallback_wrapper_->Decode(encoded_image, -1);
}
EXPECT_STREQ("fake-decoder", fallback_wrapper_->ImplementationName());
fallback_wrapper_->Release();
}
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
DoesNotFallbacksOnNonConsequtiveErrors) {
fallback_wrapper_->Configure({});
EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameKey;
const int kNumFramesToEncode = 10;
for (int i = 0; i < kNumFramesToEncode; ++i) {
// Interleaved errors and successful decodes.
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
fallback_wrapper_->Decode(encoded_image, -1);
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
fallback_wrapper_->Decode(encoded_image, -1);
}
EXPECT_STREQ("fake-decoder", fallback_wrapper_->ImplementationName());
fallback_wrapper_->Release();
}
class ForcedSoftwareDecoderFallbackTest
: public VideoDecoderSoftwareFallbackWrapperTest {
public:
ForcedSoftwareDecoderFallbackTest()
: VideoDecoderSoftwareFallbackWrapperTest(
"WebRTC-Video-ForcedSwDecoderFallback/Enabled/") {
fake_decoder_ = new CountingFakeDecoder();
sw_fallback_decoder_ = new CountingFakeDecoder();
fallback_wrapper_ = CreateVideoDecoderSoftwareFallbackWrapper(
env_, std::unique_ptr<VideoDecoder>(sw_fallback_decoder_),
std::unique_ptr<VideoDecoder>(fake_decoder_));
}
CountingFakeDecoder* sw_fallback_decoder_;
};
TEST_F(ForcedSoftwareDecoderFallbackTest, UsesForcedFallback) {
fallback_wrapper_->Configure({});
EXPECT_EQ(1, sw_fallback_decoder_->configure_count_);
EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameKey;
fallback_wrapper_->Decode(encoded_image, -1);
EXPECT_EQ(1, sw_fallback_decoder_->configure_count_);
EXPECT_EQ(1, sw_fallback_decoder_->decode_count_);
fallback_wrapper_->Release();
EXPECT_EQ(1, sw_fallback_decoder_->release_count_);
// Only fallback decoder should have been used.
EXPECT_EQ(0, fake_decoder_->configure_count_);
EXPECT_EQ(0, fake_decoder_->decode_count_);
EXPECT_EQ(0, fake_decoder_->release_count_);
}
} // namespace webrtc

View file

@ -0,0 +1,173 @@
/*
* Copyright (c) 2022 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/test/mock_video_encoder.h"
#include "api/video_codecs/video_encoder_factory_template.h"
#include "api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.h"
#include "api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h"
#include "api/video_codecs/video_encoder_factory_template_libvpx_vp9_adapter.h"
#include "api/video_codecs/video_encoder_factory_template_open_h264_adapter.h"
#include "test/gmock.h"
#include "test/gtest.h"
using ::testing::Contains;
using ::testing::Each;
using ::testing::Eq;
using ::testing::Field;
using ::testing::IsEmpty;
using ::testing::IsNull;
using ::testing::Not;
using ::testing::NotNull;
using ::testing::UnorderedElementsAre;
namespace webrtc {
namespace {
using CodecSupport = VideoEncoderFactory::CodecSupport;
const SdpVideoFormat kFooSdp("Foo");
const SdpVideoFormat kBarLowSdp("Bar", {{"profile", "low"}});
const SdpVideoFormat kBarHighSdp("Bar", {{"profile", "high"}});
struct FooEncoderTemplateAdapter {
static std::vector<SdpVideoFormat> SupportedFormats() { return {kFooSdp}; }
static std::unique_ptr<VideoEncoder> CreateEncoder(
const SdpVideoFormat& format) {
return std::make_unique<testing::StrictMock<MockVideoEncoder>>();
}
static bool IsScalabilityModeSupported(ScalabilityMode scalability_mode) {
return scalability_mode == ScalabilityMode::kL1T2 ||
scalability_mode == ScalabilityMode::kL1T3;
}
};
struct BarEncoderTemplateAdapter {
static std::vector<SdpVideoFormat> SupportedFormats() {
return {kBarLowSdp, kBarHighSdp};
}
static std::unique_ptr<VideoEncoder> CreateEncoder(
const SdpVideoFormat& format) {
return std::make_unique<testing::StrictMock<MockVideoEncoder>>();
}
static bool IsScalabilityModeSupported(ScalabilityMode scalability_mode) {
return scalability_mode == ScalabilityMode::kL1T2 ||
scalability_mode == ScalabilityMode::kL1T3 ||
scalability_mode == ScalabilityMode::kS2T1 ||
scalability_mode == ScalabilityMode::kS3T3;
}
};
TEST(VideoEncoderFactoryTemplate, OneTemplateAdapterCreateEncoder) {
VideoEncoderFactoryTemplate<FooEncoderTemplateAdapter> factory;
EXPECT_THAT(factory.GetSupportedFormats(), UnorderedElementsAre(kFooSdp));
EXPECT_THAT(factory.CreateVideoEncoder(kFooSdp), NotNull());
EXPECT_THAT(factory.CreateVideoEncoder(SdpVideoFormat("FooX")), IsNull());
}
TEST(VideoEncoderFactoryTemplate, OneTemplateAdapterCodecSupport) {
VideoEncoderFactoryTemplate<FooEncoderTemplateAdapter> factory;
EXPECT_THAT(factory.QueryCodecSupport(kFooSdp, absl::nullopt),
Field(&CodecSupport::is_supported, true));
EXPECT_THAT(factory.QueryCodecSupport(kFooSdp, "L1T2"),
Field(&CodecSupport::is_supported, true));
EXPECT_THAT(factory.QueryCodecSupport(kFooSdp, "S3T3"),
Field(&CodecSupport::is_supported, false));
EXPECT_THAT(factory.QueryCodecSupport(SdpVideoFormat("FooX"), absl::nullopt),
Field(&CodecSupport::is_supported, false));
}
TEST(VideoEncoderFactoryTemplate, TwoTemplateAdaptersNoDuplicates) {
VideoEncoderFactoryTemplate<FooEncoderTemplateAdapter,
FooEncoderTemplateAdapter>
factory;
EXPECT_THAT(factory.GetSupportedFormats(), UnorderedElementsAre(kFooSdp));
}
TEST(VideoEncoderFactoryTemplate, TwoTemplateAdaptersCreateEncoders) {
VideoEncoderFactoryTemplate<FooEncoderTemplateAdapter,
BarEncoderTemplateAdapter>
factory;
EXPECT_THAT(factory.GetSupportedFormats(),
UnorderedElementsAre(kFooSdp, kBarLowSdp, kBarHighSdp));
EXPECT_THAT(factory.CreateVideoEncoder(kFooSdp), NotNull());
EXPECT_THAT(factory.CreateVideoEncoder(kBarLowSdp), NotNull());
EXPECT_THAT(factory.CreateVideoEncoder(kBarHighSdp), NotNull());
EXPECT_THAT(factory.CreateVideoEncoder(SdpVideoFormat("FooX")), IsNull());
EXPECT_THAT(factory.CreateVideoEncoder(SdpVideoFormat("Bar")), NotNull());
}
TEST(VideoEncoderFactoryTemplate, TwoTemplateAdaptersCodecSupport) {
VideoEncoderFactoryTemplate<FooEncoderTemplateAdapter,
BarEncoderTemplateAdapter>
factory;
EXPECT_THAT(factory.QueryCodecSupport(kFooSdp, absl::nullopt),
Field(&CodecSupport::is_supported, true));
EXPECT_THAT(factory.QueryCodecSupport(kFooSdp, "L1T2"),
Field(&CodecSupport::is_supported, true));
EXPECT_THAT(factory.QueryCodecSupport(kFooSdp, "S3T3"),
Field(&CodecSupport::is_supported, false));
EXPECT_THAT(factory.QueryCodecSupport(kBarLowSdp, absl::nullopt),
Field(&CodecSupport::is_supported, true));
EXPECT_THAT(factory.QueryCodecSupport(kBarHighSdp, absl::nullopt),
Field(&CodecSupport::is_supported, true));
EXPECT_THAT(factory.QueryCodecSupport(kBarLowSdp, "S2T1"),
Field(&CodecSupport::is_supported, true));
EXPECT_THAT(factory.QueryCodecSupport(kBarHighSdp, "S3T2"),
Field(&CodecSupport::is_supported, false));
}
TEST(VideoEncoderFactoryTemplate, LibvpxVp8) {
VideoEncoderFactoryTemplate<LibvpxVp8EncoderTemplateAdapter> factory;
auto formats = factory.GetSupportedFormats();
EXPECT_THAT(formats.size(), 1);
EXPECT_THAT(formats[0], Field(&SdpVideoFormat::name, "VP8"));
EXPECT_THAT(formats[0], Field(&SdpVideoFormat::scalability_modes,
Contains(ScalabilityMode::kL1T3)));
EXPECT_THAT(factory.CreateVideoEncoder(formats[0]), NotNull());
}
TEST(VideoEncoderFactoryTemplate, LibvpxVp9) {
VideoEncoderFactoryTemplate<LibvpxVp9EncoderTemplateAdapter> factory;
auto formats = factory.GetSupportedFormats();
EXPECT_THAT(formats, Not(IsEmpty()));
EXPECT_THAT(formats, Each(Field(&SdpVideoFormat::name, "VP9")));
EXPECT_THAT(formats, Each(Field(&SdpVideoFormat::scalability_modes,
Contains(ScalabilityMode::kL3T3_KEY))));
EXPECT_THAT(factory.CreateVideoEncoder(formats[0]), NotNull());
}
// TODO(bugs.webrtc.org/13573): When OpenH264 is no longer a conditional build
// target remove this #ifdef.
#if defined(WEBRTC_USE_H264)
TEST(VideoEncoderFactoryTemplate, OpenH264) {
VideoEncoderFactoryTemplate<OpenH264EncoderTemplateAdapter> factory;
auto formats = factory.GetSupportedFormats();
EXPECT_THAT(formats, Not(IsEmpty()));
EXPECT_THAT(formats, Each(Field(&SdpVideoFormat::name, "H264")));
EXPECT_THAT(formats, Each(Field(&SdpVideoFormat::scalability_modes,
Contains(ScalabilityMode::kL1T3))));
EXPECT_THAT(factory.CreateVideoEncoder(formats[0]), NotNull());
}
#endif // defined(WEBRTC_USE_H264)
TEST(VideoEncoderFactoryTemplate, LibaomAv1) {
VideoEncoderFactoryTemplate<LibaomAv1EncoderTemplateAdapter> factory;
auto formats = factory.GetSupportedFormats();
EXPECT_THAT(formats.size(), 1);
EXPECT_THAT(formats[0], Field(&SdpVideoFormat::name, "AV1"));
EXPECT_THAT(formats[0], Field(&SdpVideoFormat::scalability_modes,
Contains(ScalabilityMode::kL3T3_KEY)));
EXPECT_THAT(factory.CreateVideoEncoder(formats[0]), NotNull());
}
} // namespace
} // namespace webrtc