New VideoEncoderFactoryTemplate.

The VideoEncoderFactoryTemplate takes encoder implementations as template arguments, making it possible to easily implement a VideoEncoderFactory only using the implementations required for the particular application. This will replace the BuiltinVideoEncoderFactory.

Change-Id: Ifb0e93d0d4491664fb7f7acf085190d8a90ddc0e
Bug: webrtc:13573
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/251904
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36216}
This commit is contained in:
philipel
2022-03-16 12:11:42 +01:00
committed by WebRTC LUCI CQ
parent 7ddc7d548c
commit 6160ca53d1
9 changed files with 496 additions and 0 deletions

View File

@ -312,6 +312,10 @@ specific_include_rules = {
"+rtc_base/thread_annotations.h",
],
"video_encoder_factory_template.*\.h": [
"+modules/video_coding",
],
# .cc files in api/ should not be restricted in what they can #include,
# so we re-add all the top-level directories here. (That's because .h
# files leak their #includes to whoever's #including them, but .cc files

View File

@ -112,6 +112,50 @@ rtc_library("builtin_video_encoder_factory") {
absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
}
rtc_source_set("video_encoder_factory_template") {
visibility = [ "*" ]
allow_poison = [ "software_video_codecs" ]
public = [ "video_encoder_factory_template.h" ]
deps = [ ":video_codecs_api" ]
absl_deps = [ "//third_party/abseil-cpp/absl/algorithm:container" ]
}
rtc_source_set("video_encoder_factory_template_libvpx_vp8_adapter") {
visibility = [ "*" ]
allow_poison = [ "software_video_codecs" ]
public = [ "video_encoder_factory_template_libvpx_vp8_adapter.h" ]
deps = [ "../../modules/video_coding:webrtc_vp8" ]
}
rtc_source_set("video_encoder_factory_template_libvpx_vp9_adapter") {
visibility = [ "*" ]
allow_poison = [ "software_video_codecs" ]
public = [ "video_encoder_factory_template_libvpx_vp9_adapter.h" ]
deps = [ "../../modules/video_coding:webrtc_vp9" ]
}
rtc_source_set("video_encoder_factory_template_open_h264_adapter") {
visibility = [ "*" ]
allow_poison = [ "software_video_codecs" ]
public = [ "video_encoder_factory_template_open_h264_adapter.h" ]
deps = [ "../../modules/video_coding:webrtc_h264" ]
}
rtc_source_set("video_encoder_factory_template_libaom_av1_adapter") {
visibility = [ "*" ]
allow_poison = [ "software_video_codecs" ]
public = [ "video_encoder_factory_template_libaom_av1_adapter.h" ]
deps = [
"../../modules/video_coding/codecs/av1:libaom_av1_encoder",
"../../modules/video_coding/svc:scalability_structures",
]
}
rtc_library("vp8_temporal_layers_factory") {
visibility = [ "*" ]
allow_poison = [ "software_video_codecs" ]

View File

@ -20,6 +20,7 @@ if (rtc_include_tests) {
]
deps = [
":video_encoder_factory_template_tests",
"..:builtin_video_encoder_factory",
"..:rtc_software_fallback_wrappers",
"..:video_codecs_api",
@ -43,4 +44,20 @@ if (rtc_include_tests) {
]
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",
]
}
}

View File

@ -0,0 +1,160 @@
/*
* 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::Each;
using ::testing::Eq;
using ::testing::Field;
using ::testing::IsEmpty;
using ::testing::Ne;
using ::testing::Not;
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(
const absl::string_view scalability_mode) {
return scalability_mode == "L1T2" || scalability_mode == "L1T3";
}
};
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(
const absl::string_view scalability_mode) {
return scalability_mode == "L1T2" || scalability_mode == "L1T3" ||
scalability_mode == "S2T2" || scalability_mode == "S2T3";
}
};
TEST(VideoEncoderFactoryTemplate, OneTemplateAdapterCreateEncoder) {
VideoEncoderFactoryTemplate<FooEncoderTemplateAdapter> factory;
EXPECT_THAT(factory.GetSupportedFormats(), UnorderedElementsAre(kFooSdp));
EXPECT_THAT(factory.CreateVideoEncoder(kFooSdp), Ne(nullptr));
EXPECT_THAT(factory.CreateVideoEncoder(SdpVideoFormat("FooX")), Eq(nullptr));
}
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, "S2T3"),
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), Ne(nullptr));
EXPECT_THAT(factory.CreateVideoEncoder(kBarLowSdp), Ne(nullptr));
EXPECT_THAT(factory.CreateVideoEncoder(kBarHighSdp), Ne(nullptr));
EXPECT_THAT(factory.CreateVideoEncoder(SdpVideoFormat("FooX")), Eq(nullptr));
EXPECT_THAT(factory.CreateVideoEncoder(SdpVideoFormat("Bar")), Eq(nullptr));
}
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, "S2T3"),
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, "S2T2"),
Field(&CodecSupport::is_supported, true));
EXPECT_THAT(factory.QueryCodecSupport(kBarHighSdp, "S3T2"),
Field(&CodecSupport::is_supported, false));
}
TEST(VideoEncoderFactoryTemplate, LibvpxVp8) {
VideoEncoderFactoryTemplate<LibvpxVp8EncoderTemplateAdapter> factory;
const SdpVideoFormat kVp8Sdp("VP8");
EXPECT_THAT(factory.GetSupportedFormats(), UnorderedElementsAre(kVp8Sdp));
EXPECT_THAT(factory.CreateVideoEncoder(kVp8Sdp), Ne(nullptr));
}
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(factory.CreateVideoEncoder(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(VideoEncoderFactoryTemplate, OpenH264) {
VideoEncoderFactoryTemplate<OpenH264EncoderTemplateAdapter> factory;
auto formats = factory.GetSupportedFormats();
EXPECT_THAT(formats, Not(IsEmpty()));
EXPECT_THAT(formats, Each(Field(&SdpVideoFormat::name, "H264")));
EXPECT_THAT(factory.CreateVideoEncoder(formats[0]), Ne(nullptr));
}
#endif // defined(WEBRTC_USE_H264)
TEST(VideoEncoderFactoryTemplate, LibaomAv1) {
VideoEncoderFactoryTemplate<LibaomAv1EncoderTemplateAdapter> factory;
const SdpVideoFormat kAv1Sdp("AV1");
EXPECT_THAT(factory.GetSupportedFormats(), UnorderedElementsAre(kAv1Sdp));
EXPECT_THAT(factory.CreateVideoEncoder(kAv1Sdp), Ne(nullptr));
}
} // namespace
} // namespace webrtc

View File

@ -0,0 +1,116 @@
/*
* 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.
*/
#ifndef API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_H_
#define API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_H_
#include <memory>
#include <string>
#include <vector>
#include "absl/algorithm/container.h"
#include "api/video_codecs/video_encoder.h"
#include "api/video_codecs/video_encoder_factory.h"
namespace webrtc {
// The VideoEncoderFactoryTemplate supports encoders implementations given as
// template arguments.
//
// To include an encoder in the factory it requires three static members
// functions to be defined:
//
// // Returns the supported SdpVideoFormats this encoder can produce.
// static std::vector<SdpVideoFormat> SupportedFormats();
//
// // Creates an encoder instance for the given format.
// static std::unique_ptr<VideoEncoder>
// CreateEncoder(const SdpVideoFormat& format);
//
// // Returns true if the encoder supports the given scalability mode.
// static bool
// IsScalabilityModeSupported(const absl::string_view scalability_mode);
//
// Note that the order of the template arguments matter as the factory will
// query/return the first encoder implementation supporting the given
// SdpVideoFormat.
template <typename... Ts>
class VideoEncoderFactoryTemplate : public VideoEncoderFactory {
public:
std::vector<SdpVideoFormat> GetSupportedFormats() const override {
std::vector<SdpVideoFormat> formats;
GetSupportedFormatsInternal<Ts...>(formats);
return formats;
}
std::unique_ptr<VideoEncoder> CreateVideoEncoder(
const SdpVideoFormat& format) override {
return CreateVideoEncoderInternal<Ts...>(format);
}
CodecSupport QueryCodecSupport(
const SdpVideoFormat& format,
absl::optional<std::string> scalability_mode) const override {
return QueryCodecSupportInternal<Ts...>(format, scalability_mode);
}
private:
template <typename V>
bool IsFormatSupported(const SdpVideoFormat& format) const {
return absl::c_count(V::SupportedFormats(), format) > 0;
}
template <typename V, typename... Vs>
void GetSupportedFormatsInternal(std::vector<SdpVideoFormat>& formats) const {
auto supported_formats = V::SupportedFormats();
for (const auto& format : supported_formats) {
if (absl::c_count(formats, format) == 0) {
formats.push_back(format);
}
}
if constexpr (sizeof...(Vs) > 0) {
return GetSupportedFormatsInternal<Vs...>(formats);
}
}
template <typename V, typename... Vs>
std::unique_ptr<VideoEncoder> CreateVideoEncoderInternal(
const SdpVideoFormat& format) {
if (IsFormatSupported<V>(format)) {
return V::CreateEncoder(format);
}
if constexpr (sizeof...(Vs) > 0) {
return CreateVideoEncoderInternal<Vs...>(format);
}
return nullptr;
}
template <typename V, typename... Vs>
CodecSupport QueryCodecSupportInternal(
const SdpVideoFormat& format,
const absl::optional<std::string>& scalability_mode) const {
if (IsFormatSupported<V>(format)) {
return {.is_supported = !scalability_mode ||
V::IsScalabilityModeSupported(*scalability_mode)};
}
if constexpr (sizeof...(Vs) > 0) {
return QueryCodecSupportInternal<Vs...>(format, scalability_mode);
}
return {.is_supported = false};
}
};
} // namespace webrtc
#endif // API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_H_

View File

@ -0,0 +1,40 @@
/*
* 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.
*/
#ifndef API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_LIBAOM_AV1_ADAPTER_H_
#define API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_LIBAOM_AV1_ADAPTER_H_
#include <memory>
#include <vector>
#include "modules/video_coding/codecs/av1/libaom_av1_encoder.h"
#include "modules/video_coding/svc/create_scalability_structure.h"
namespace webrtc {
struct LibaomAv1EncoderTemplateAdapter {
static std::vector<SdpVideoFormat> SupportedFormats() {
return {SdpVideoFormat("AV1")};
}
static std::unique_ptr<VideoEncoder> CreateEncoder(
const SdpVideoFormat& format) {
return CreateLibaomAv1Encoder();
}
static bool IsScalabilityModeSupported(absl::string_view scalability_mode) {
// For libaom AV1, the scalability mode is supported if we can create the
// scalability structure.
return ScalabilityStructureConfig(scalability_mode) != absl::nullopt;
}
};
} // namespace webrtc
#endif // API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_LIBAOM_AV1_ADAPTER_H_

View File

@ -0,0 +1,37 @@
/*
* 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.
*/
#ifndef API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_LIBVPX_VP8_ADAPTER_H_
#define API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_LIBVPX_VP8_ADAPTER_H_
#include <memory>
#include <vector>
#include "modules/video_coding/codecs/vp8/include/vp8.h"
namespace webrtc {
struct LibvpxVp8EncoderTemplateAdapter {
static std::vector<SdpVideoFormat> SupportedFormats() {
return {SdpVideoFormat("VP8")};
}
static std::unique_ptr<VideoEncoder> CreateEncoder(
const SdpVideoFormat& format) {
return VP8Encoder::Create();
}
static bool IsScalabilityModeSupported(
const absl::string_view scalability_mode) {
return VP8Encoder::SupportsScalabilityMode(scalability_mode);
}
};
} // namespace webrtc
#endif // API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_LIBVPX_VP8_ADAPTER_H_

View File

@ -0,0 +1,37 @@
/*
* 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.
*/
#ifndef API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_LIBVPX_VP9_ADAPTER_H_
#define API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_LIBVPX_VP9_ADAPTER_H_
#include <memory>
#include <vector>
#include "modules/video_coding/codecs/vp9/include/vp9.h"
namespace webrtc {
struct LibvpxVp9EncoderTemplateAdapter {
static std::vector<SdpVideoFormat> SupportedFormats() {
return SupportedVP9Codecs();
}
static std::unique_ptr<VideoEncoder> CreateEncoder(
const SdpVideoFormat& format) {
return VP9Encoder::Create();
}
static bool IsScalabilityModeSupported(
const absl::string_view scalability_mode) {
return VP9Encoder::SupportsScalabilityMode(scalability_mode);
}
};
} // namespace webrtc
#endif // API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_LIBVPX_VP9_ADAPTER_H_

View File

@ -0,0 +1,41 @@
/*
* 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.
*/
#ifndef API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_OPEN_H264_ADAPTER_H_
#define API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_OPEN_H264_ADAPTER_H_
#include <memory>
#include <vector>
#include "modules/video_coding/codecs/h264/include/h264.h"
namespace webrtc {
// TODO(bugs.webrtc.org/13573): When OpenH264 is no longer a conditional build
// target remove this #ifdef.
#if defined(WEBRTC_USE_H264)
struct OpenH264EncoderTemplateAdapter {
static std::vector<SdpVideoFormat> SupportedFormats() {
return SupportedH264Codecs();
}
static std::unique_ptr<VideoEncoder> CreateEncoder(
const SdpVideoFormat& format) {
return H264Encoder::Create(cricket::VideoCodec(format));
}
static bool IsScalabilityModeSupported(
const absl::string_view scalability_mode) {
return H264Encoder::SupportsScalabilityMode(scalability_mode);
}
};
#endif // defined(WEBRTC_USE_H264)
} // namespace webrtc
#endif // API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_OPEN_H264_ADAPTER_H_