video_encoder_factory_template.h (5530B)
1 /* 2 * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_H_ 12 #define API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_H_ 13 14 #include <memory> 15 #include <optional> 16 #include <string> 17 #include <vector> 18 19 #include "absl/algorithm/container.h" 20 #include "api/array_view.h" 21 #include "api/environment/environment.h" 22 #include "api/video_codecs/scalability_mode.h" 23 #include "api/video_codecs/sdp_video_format.h" 24 #include "api/video_codecs/video_encoder.h" 25 #include "api/video_codecs/video_encoder_factory.h" 26 #include "modules/video_coding/svc/scalability_mode_util.h" 27 28 namespace webrtc { 29 // The VideoEncoderFactoryTemplate supports encoders implementations given as 30 // template arguments. 31 // 32 // To include an encoder in the factory it requires three static members 33 // functions to be defined: 34 // 35 // // Returns the supported SdpVideoFormats this encoder can produce. 36 // static std::vector<SdpVideoFormat> SupportedFormats(); 37 // 38 // // Creates an encoder instance for the given format. 39 // static std::unique_ptr<VideoEncoder> 40 // CreateEncoder(const Environment& env, 41 // const SdpVideoFormat& format); 42 // 43 // // Returns true if the encoder supports the given scalability mode. 44 // static bool 45 // IsScalabilityModeSupported(ScalabilityMode scalability_mode); 46 // 47 // Note that the order of the template arguments matter as the factory will 48 // query/return the first encoder implementation supporting the given 49 // SdpVideoFormat. 50 template <typename... Ts> 51 class VideoEncoderFactoryTemplate : public VideoEncoderFactory { 52 public: 53 std::vector<SdpVideoFormat> GetSupportedFormats() const override { 54 return GetSupportedFormatsInternal<Ts...>(); 55 } 56 57 std::unique_ptr<VideoEncoder> Create(const Environment& env, 58 const SdpVideoFormat& format) override { 59 // We fuzzy match the specified format for both valid and not so valid 60 // reasons. The valid reason is that there are many standardized codec 61 // specific fmtp parameters that have not been implemented, and in those 62 // cases we should not fail to instantiate an encoder just because we don't 63 // recognize the parameter. The not so valid reason is that we have started 64 // adding parameters completely unrelated to the SDP to the SdpVideoFormat. 65 // TODO: bugs.webrtc.org/13868 - Remove FuzzyMatchSdpVideoFormat 66 std::optional<SdpVideoFormat> matched = 67 FuzzyMatchSdpVideoFormat(GetSupportedFormats(), format); 68 return CreateInternal<Ts...>(env, matched.value_or(format)); 69 } 70 71 CodecSupport QueryCodecSupport( 72 const SdpVideoFormat& format, 73 std::optional<std::string> scalability_mode) const override { 74 return QueryCodecSupportInternal<Ts...>(format, scalability_mode); 75 } 76 77 private: 78 bool IsFormatInList(const SdpVideoFormat& format, 79 ArrayView<const SdpVideoFormat> supported_formats) const { 80 return absl::c_any_of( 81 supported_formats, [&](const SdpVideoFormat& supported_format) { 82 return supported_format.name == format.name && 83 supported_format.parameters == format.parameters; 84 }); 85 } 86 87 template <typename V> 88 bool IsScalabilityModeSupported( 89 const std::optional<std::string>& scalability_mode_string) const { 90 if (!scalability_mode_string.has_value()) { 91 return true; 92 } 93 std::optional<ScalabilityMode> scalability_mode = 94 ScalabilityModeFromString(*scalability_mode_string); 95 return scalability_mode.has_value() && 96 V::IsScalabilityModeSupported(*scalability_mode); 97 } 98 99 template <typename V, typename... Vs> 100 std::vector<SdpVideoFormat> GetSupportedFormatsInternal() const { 101 auto supported_formats = V::SupportedFormats(); 102 103 if constexpr (sizeof...(Vs) > 0) { 104 // Supported formats may overlap between implementations, so duplicates 105 // should be filtered out. 106 for (const auto& other_format : GetSupportedFormatsInternal<Vs...>()) { 107 if (!IsFormatInList(other_format, supported_formats)) { 108 supported_formats.push_back(other_format); 109 } 110 } 111 } 112 113 return supported_formats; 114 } 115 116 template <typename V, typename... Vs> 117 std::unique_ptr<VideoEncoder> CreateInternal(const Environment& env, 118 const SdpVideoFormat& format) { 119 if (IsFormatInList(format, V::SupportedFormats())) { 120 return V::CreateEncoder(env, format); 121 } 122 123 if constexpr (sizeof...(Vs) > 0) { 124 return CreateInternal<Vs...>(env, format); 125 } 126 127 return nullptr; 128 } 129 130 template <typename V, typename... Vs> 131 CodecSupport QueryCodecSupportInternal( 132 const SdpVideoFormat& format, 133 const std::optional<std::string>& scalability_mode) const { 134 if (IsFormatInList(format, V::SupportedFormats())) { 135 return {.is_supported = IsScalabilityModeSupported<V>(scalability_mode)}; 136 } 137 138 if constexpr (sizeof...(Vs) > 0) { 139 return QueryCodecSupportInternal<Vs...>(format, scalability_mode); 140 } 141 142 return {.is_supported = false}; 143 } 144 }; 145 146 } // namespace webrtc 147 148 #endif // API_VIDEO_CODECS_VIDEO_ENCODER_FACTORY_TEMPLATE_H_