Added java interface VideoEncoderFactory.VideoEncoderSelector and implemented VideoEncoderSelectorWrapper.

Bug: webrtc:11341
Change-Id: Ic15658e09643aec119a97ddfaebfdb72ba3407c7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168487
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Commit-Queue: Philip Eliasson <philipel@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30519}
diff --git a/sdk/android/api/org/webrtc/VideoEncoderFactory.java b/sdk/android/api/org/webrtc/VideoEncoderFactory.java
index b318e8b..9c0f2b4 100644
--- a/sdk/android/api/org/webrtc/VideoEncoderFactory.java
+++ b/sdk/android/api/org/webrtc/VideoEncoderFactory.java
@@ -14,6 +14,25 @@
 
 /** Factory for creating VideoEncoders. */
 public interface VideoEncoderFactory {
+  public interface VideoEncoderSelector {
+    /** Called with the VideoCodecInfo of the currently used encoder. */
+    @CalledByNative("VideoEncoderSelector") void onCurrentEncoder(VideoCodecInfo info);
+
+    /**
+     * Called with the current encoding bitrate. Returns null if the encoder
+     * selector which to keep the current encoder or a VideoCodecInfo if a
+     * new encoder is preferred.
+     */
+    @Nullable @CalledByNative("VideoEncoderSelector") VideoCodecInfo onEncodingBitrate(int kbps);
+
+    /**
+     * Called when the currently used encoder signal itself as broken. Returns
+     * null if the encoder selector which to keep the current encoder or a
+     * VideoCodecInfo if a new encoder is preferred.
+     */
+    @Nullable @CalledByNative("VideoEncoderSelector") VideoCodecInfo onEncoderBroken();
+  }
+
   /** Creates an encoder for the given video codec. */
   @Nullable @CalledByNative VideoEncoder createEncoder(VideoCodecInfo info);
 
@@ -32,4 +51,13 @@
   default VideoCodecInfo[] getImplementations() {
     return getSupportedCodecs();
   }
+
+  /**
+   * Returns a VideoEncoderSelector if implemented by the VideoEncoderFactory,
+   * null otherwise.
+   */
+  @CalledByNative
+  default VideoEncoderSelector getEncoderSelector() {
+    return null;
+  }
 }
diff --git a/sdk/android/src/jni/video_encoder_factory_wrapper.cc b/sdk/android/src/jni/video_encoder_factory_wrapper.cc
index 538cc5b..795f82b 100644
--- a/sdk/android/src/jni/video_encoder_factory_wrapper.cc
+++ b/sdk/android/src/jni/video_encoder_factory_wrapper.cc
@@ -20,6 +20,49 @@
 
 namespace webrtc {
 namespace jni {
+namespace {
+class VideoEncoderSelectorWrapper
+    : public VideoEncoderFactory::EncoderSelectorInterface {
+ public:
+  VideoEncoderSelectorWrapper(JNIEnv* jni,
+                              const JavaRef<jobject>& encoder_selector)
+      : encoder_selector_(jni, encoder_selector) {}
+
+  void OnCurrentEncoder(const SdpVideoFormat& format) override {
+    JNIEnv* jni = AttachCurrentThreadIfNeeded();
+    ScopedJavaLocalRef<jobject> j_codec_info =
+        SdpVideoFormatToVideoCodecInfo(jni, format);
+    Java_VideoEncoderSelector_onCurrentEncoder(jni, encoder_selector_,
+                                               j_codec_info);
+  }
+
+  absl::optional<SdpVideoFormat> OnEncodingBitrate(
+      const DataRate& rate) override {
+    JNIEnv* jni = AttachCurrentThreadIfNeeded();
+    ScopedJavaLocalRef<jobject> codec_info =
+        Java_VideoEncoderSelector_onEncodingBitrate(jni, encoder_selector_,
+                                                    rate.kbps<int>());
+    if (codec_info.is_null()) {
+      return absl::nullopt;
+    }
+    return VideoCodecInfoToSdpVideoFormat(jni, codec_info);
+  }
+
+  absl::optional<SdpVideoFormat> OnEncoderBroken() override {
+    JNIEnv* jni = AttachCurrentThreadIfNeeded();
+    ScopedJavaLocalRef<jobject> codec_info =
+        Java_VideoEncoderSelector_onEncoderBroken(jni, encoder_selector_);
+    if (codec_info.is_null()) {
+      return absl::nullopt;
+    }
+    return VideoCodecInfoToSdpVideoFormat(jni, codec_info);
+  }
+
+ private:
+  const ScopedJavaGlobalRef<jobject> encoder_selector_;
+};
+
+}  // namespace
 
 VideoEncoderFactoryWrapper::VideoEncoderFactoryWrapper(
     JNIEnv* jni,
@@ -73,5 +116,17 @@
   return codec_info;
 }
 
+std::unique_ptr<VideoEncoderFactory::EncoderSelectorInterface>
+VideoEncoderFactoryWrapper::GetEncoderSelector() const {
+  JNIEnv* jni = AttachCurrentThreadIfNeeded();
+  ScopedJavaLocalRef<jobject> selector =
+      Java_VideoEncoderFactory_getEncoderSelector(jni, encoder_factory_);
+  if (selector.is_null()) {
+    return nullptr;
+  }
+
+  return std::make_unique<VideoEncoderSelectorWrapper>(jni, selector);
+}
+
 }  // namespace jni
 }  // namespace webrtc
diff --git a/sdk/android/src/jni/video_encoder_factory_wrapper.h b/sdk/android/src/jni/video_encoder_factory_wrapper.h
index 7f033ae..799ae0f 100644
--- a/sdk/android/src/jni/video_encoder_factory_wrapper.h
+++ b/sdk/android/src/jni/video_encoder_factory_wrapper.h
@@ -39,6 +39,8 @@
 
   CodecInfo QueryVideoEncoder(const SdpVideoFormat& format) const override;
 
+  std::unique_ptr<EncoderSelectorInterface> GetEncoderSelector() const override;
+
  private:
   const ScopedJavaGlobalRef<jobject> encoder_factory_;
   std::vector<SdpVideoFormat> supported_formats_;