Android: Generate all C++ -> Java JNI code for VideoEncoder

The first example CL for generating JNI code
(https://webrtc-review.googlesource.com/c/src/+/4500) seems to stick, so
this CL updates the rest of the VideoEncoder. The JNI code for
Java -> C++ is still done manually.

This CL puts the necessary helper Java methods in a class called
VideoEncoderWrapper.

Bug: webrtc:8278
Change-Id: Ic3a6defe59c094f67ffd8ea86d6c272c676980ae
Reviewed-on: https://webrtc-review.googlesource.com/20871
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Commit-Queue: Magnus Jedvert <magjed@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20587}
diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn
index b2bef9e..5bb7300 100644
--- a/sdk/android/BUILD.gn
+++ b/sdk/android/BUILD.gn
@@ -103,8 +103,10 @@
 
 generate_jni("generated_video_jni") {
   sources = [
+    "api/org/webrtc/VideoCodecStatus.java",
     "api/org/webrtc/VideoEncoder.java",
     "api/org/webrtc/VideoSink.java",
+    "src/java/org/webrtc/VideoEncoderWrapper.java",
   ]
   jni_package = ""
   jni_generator_include = "//sdk/android/src/jni/jni_generator_helper.h"
@@ -492,7 +494,7 @@
     "src/java/org/webrtc/TextureBufferImpl.java",
     "src/java/org/webrtc/VideoCodecType.java",
     "src/java/org/webrtc/VideoDecoderWrapperCallback.java",
-    "src/java/org/webrtc/VideoEncoderWrapperCallback.java",
+    "src/java/org/webrtc/VideoEncoderWrapper.java",
     "src/java/org/webrtc/WrappedNativeI420Buffer.java",
   ]
 
diff --git a/sdk/android/api/org/webrtc/EncodedImage.java b/sdk/android/api/org/webrtc/EncodedImage.java
index 6720cd7..c6c56ce 100644
--- a/sdk/android/api/org/webrtc/EncodedImage.java
+++ b/sdk/android/api/org/webrtc/EncodedImage.java
@@ -33,15 +33,6 @@
     public int getNative() {
       return nativeIndex;
     }
-
-    public static FrameType fromNative(int nativeIndex) {
-      for (FrameType type : FrameType.values()) {
-        if (type.nativeIndex == nativeIndex) {
-          return type;
-        }
-      }
-      throw new IllegalArgumentException("Unknown native frame type: " + nativeIndex);
-    }
   }
 
   public final ByteBuffer buffer;
diff --git a/sdk/android/api/org/webrtc/VideoCodecStatus.java b/sdk/android/api/org/webrtc/VideoCodecStatus.java
index 3a7c81f..a86d6fb 100644
--- a/sdk/android/api/org/webrtc/VideoCodecStatus.java
+++ b/sdk/android/api/org/webrtc/VideoCodecStatus.java
@@ -35,6 +35,7 @@
     this.number = number;
   }
 
+  @CalledByNative
   public int getNumber() {
     return number;
   }
diff --git a/sdk/android/src/java/org/webrtc/VideoEncoderWrapper.java b/sdk/android/src/java/org/webrtc/VideoEncoderWrapper.java
new file mode 100644
index 0000000..6d7924a
--- /dev/null
+++ b/sdk/android/src/java/org/webrtc/VideoEncoderWrapper.java
@@ -0,0 +1,80 @@
+/*
+ *  Copyright 2017 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.
+ */
+
+package org.webrtc;
+
+// Explicit imports necessary for JNI generation.
+import org.webrtc.EncodedImage;
+import org.webrtc.VideoEncoder;
+import java.nio.ByteBuffer;
+
+/**
+ * This class contains the Java glue code for JNI generation of VideoEncoder.
+ */
+class VideoEncoderWrapper {
+  @CalledByNative
+  static VideoEncoder.Settings createSettings(int numberOfCores, int width, int height,
+      int startBitrate, int maxFramerate, boolean automaticResizeOn) {
+    return new VideoEncoder.Settings(
+        numberOfCores, width, height, startBitrate, maxFramerate, automaticResizeOn);
+  }
+
+  @CalledByNative
+  static VideoEncoder.EncodeInfo createEncodeInfo(EncodedImage.FrameType[] frameTypes) {
+    return new VideoEncoder.EncodeInfo(frameTypes);
+  }
+
+  @CalledByNative
+  static VideoEncoder.BitrateAllocation createBitrateAllocation(int[][] bitratesBbs) {
+    return new VideoEncoder.BitrateAllocation(bitratesBbs);
+  }
+
+  @CalledByNative
+  static EncodedImage.FrameType createFrameType(int nativeIndex) {
+    for (EncodedImage.FrameType type : EncodedImage.FrameType.values()) {
+      if (type.getNative() == nativeIndex) {
+        return type;
+      }
+    }
+    throw new IllegalArgumentException("Unknown native frame type: " + nativeIndex);
+  }
+
+  @CalledByNative
+  static boolean getScalingSettingsOn(VideoEncoder.ScalingSettings scalingSettings) {
+    return scalingSettings.on;
+  }
+
+  @CalledByNative
+  static Integer getScalingSettingsLow(VideoEncoder.ScalingSettings scalingSettings) {
+    return scalingSettings.low;
+  }
+
+  @CalledByNative
+  static Integer getScalingSettingsHigh(VideoEncoder.ScalingSettings scalingSettings) {
+    return scalingSettings.high;
+  }
+
+  @CalledByNative
+  static int getIntValue(Integer i) {
+    return i.intValue();
+  }
+
+  @CalledByNative
+  static VideoEncoder.Callback createEncoderCallback(final long nativeEncoder) {
+    return (EncodedImage frame, VideoEncoder.CodecSpecificInfo info)
+               -> onEncodedFrame(nativeEncoder, frame.buffer, frame.encodedWidth,
+                   frame.encodedHeight, frame.captureTimeNs, frame.frameType.getNative(),
+                   frame.rotation, frame.completeFrame, frame.qp);
+  }
+
+  private static native void onEncodedFrame(long nativeEncoder, ByteBuffer buffer, int encodedWidth,
+      int encodedHeight, long captureTimeNs, int frameType, int rotation, boolean completeFrame,
+      Integer qp);
+}
diff --git a/sdk/android/src/java/org/webrtc/VideoEncoderWrapperCallback.java b/sdk/android/src/java/org/webrtc/VideoEncoderWrapperCallback.java
deleted file mode 100644
index 0a8a8a6..0000000
--- a/sdk/android/src/java/org/webrtc/VideoEncoderWrapperCallback.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-package org.webrtc;
-
-import java.nio.ByteBuffer;
-
-/**
- * VideoEncoder callback that calls VideoEncoderWrapper.OnEncodedFrame for the Encoded frames.
- */
-class VideoEncoderWrapperCallback implements VideoEncoder.Callback {
-  private final long nativeEncoder;
-
-  public VideoEncoderWrapperCallback(long nativeEncoder) {
-    this.nativeEncoder = nativeEncoder;
-  }
-
-  @Override
-  public void onEncodedFrame(EncodedImage frame, VideoEncoder.CodecSpecificInfo info) {
-    nativeOnEncodedFrame(nativeEncoder, frame.buffer, frame.encodedWidth, frame.encodedHeight,
-        frame.captureTimeNs, frame.frameType.getNative(), frame.rotation, frame.completeFrame,
-        frame.qp);
-  }
-
-  private native static void nativeOnEncodedFrame(long nativeEncoder, ByteBuffer buffer,
-      int encodedWidth, int encodedHeight, long captureTimeNs, int frameType, int rotation,
-      boolean completeFrame, Integer qp);
-}
diff --git a/sdk/android/src/jni/classreferenceholder.cc b/sdk/android/src/jni/classreferenceholder.cc
index e4ff16f..0aa3e62 100644
--- a/sdk/android/src/jni/classreferenceholder.cc
+++ b/sdk/android/src/jni/classreferenceholder.cc
@@ -111,11 +111,6 @@
   LoadClass(jni, "org/webrtc/VideoCodecStatus");
   LoadClass(jni, "org/webrtc/VideoDecoder$Settings");
   LoadClass(jni, "org/webrtc/VideoDecoderWrapperCallback");
-  LoadClass(jni, "org/webrtc/VideoEncoder$BitrateAllocation");
-  LoadClass(jni, "org/webrtc/VideoEncoder$EncodeInfo");
-  LoadClass(jni, "org/webrtc/VideoEncoder$ScalingSettings");
-  LoadClass(jni, "org/webrtc/VideoEncoder$Settings");
-  LoadClass(jni, "org/webrtc/VideoEncoderWrapperCallback");
   LoadClass(jni, "org/webrtc/VideoFrame");
   LoadClass(jni, "org/webrtc/VideoFrame$Buffer");
   LoadClass(jni, "org/webrtc/VideoFrame$I420Buffer");
diff --git a/sdk/android/src/jni/videoencoderwrapper.cc b/sdk/android/src/jni/videoencoderwrapper.cc
index 7c76b4e..d85844c 100644
--- a/sdk/android/src/jni/videoencoderwrapper.cc
+++ b/sdk/android/src/jni/videoencoderwrapper.cc
@@ -21,8 +21,10 @@
 #include "rtc_base/logging.h"
 #include "rtc_base/random.h"
 #include "rtc_base/timeutils.h"
+#include "sdk/android/generated_video_jni/jni/VideoCodecStatus_jni.h"
+#include "sdk/android/generated_video_jni/jni/VideoEncoderWrapper_jni.h"
 #include "sdk/android/generated_video_jni/jni/VideoEncoder_jni.h"
-#include "sdk/android/src/jni/classreferenceholder.h"
+#include "sdk/android/src/jni/class_loader.h"
 
 namespace webrtc {
 namespace jni {
@@ -31,46 +33,10 @@
 
 VideoEncoderWrapper::VideoEncoderWrapper(JNIEnv* jni, jobject j_encoder)
     : encoder_(jni, j_encoder),
-      settings_class_(jni, FindClass(jni, "org/webrtc/VideoEncoder$Settings")),
-      encode_info_class_(jni,
-                         FindClass(jni, "org/webrtc/VideoEncoder$EncodeInfo")),
       frame_type_class_(jni,
-                        FindClass(jni, "org/webrtc/EncodedImage$FrameType")),
-      bitrate_allocation_class_(
-          jni,
-          FindClass(jni, "org/webrtc/VideoEncoder$BitrateAllocation")),
+                        GetClass(jni, "org/webrtc/EncodedImage$FrameType")),
       int_array_class_(jni, jni->FindClass("[I")),
       video_frame_factory_(jni) {
-  settings_constructor_ =
-      jni->GetMethodID(*settings_class_, "<init>", "(IIIIIZ)V");
-
-  encode_info_constructor_ = jni->GetMethodID(
-      *encode_info_class_, "<init>", "([Lorg/webrtc/EncodedImage$FrameType;)V");
-
-  frame_type_from_native_method_ =
-      jni->GetStaticMethodID(*frame_type_class_, "fromNative",
-                             "(I)Lorg/webrtc/EncodedImage$FrameType;");
-
-  bitrate_allocation_constructor_ =
-      jni->GetMethodID(*bitrate_allocation_class_, "<init>", "([[I)V");
-
-  jclass video_codec_status_class =
-      FindClass(jni, "org/webrtc/VideoCodecStatus");
-  get_number_method_ =
-      jni->GetMethodID(video_codec_status_class, "getNumber", "()I");
-
-  jclass integer_class = jni->FindClass("java/lang/Integer");
-  int_value_method_ = jni->GetMethodID(integer_class, "intValue", "()I");
-
-  jclass scaling_settings_class =
-      FindClass(jni, "org/webrtc/VideoEncoder$ScalingSettings");
-  scaling_settings_on_field_ =
-      jni->GetFieldID(scaling_settings_class, "on", "Z");
-  scaling_settings_low_field_ =
-      jni->GetFieldID(scaling_settings_class, "low", "Ljava/lang/Integer;");
-  scaling_settings_high_field_ =
-      jni->GetFieldID(scaling_settings_class, "high", "Ljava/lang/Integer;");
-
   implementation_name_ = GetImplementationName(jni);
 
   initialized_ = false;
@@ -108,23 +74,18 @@
       automatic_resize_on = true;
   }
 
-  jobject settings =
-      jni->NewObject(*settings_class_, settings_constructor_, number_of_cores_,
-                     codec_settings_.width, codec_settings_.height,
-                     codec_settings_.startBitrate, codec_settings_.maxFramerate,
-                     automatic_resize_on);
+  jobject settings = Java_VideoEncoderWrapper_createSettings(
+      jni, number_of_cores_, codec_settings_.width, codec_settings_.height,
+      codec_settings_.startBitrate, codec_settings_.maxFramerate,
+      automatic_resize_on);
 
-  jclass callback_class =
-      FindClass(jni, "org/webrtc/VideoEncoderWrapperCallback");
-  jmethodID callback_constructor =
-      jni->GetMethodID(callback_class, "<init>", "(J)V");
-  jobject callback = jni->NewObject(callback_class, callback_constructor,
-                                    jlongFromPointer(this));
+  jobject callback = Java_VideoEncoderWrapper_createEncoderCallback(
+      jni, jlongFromPointer(this));
 
   jobject ret =
       Java_VideoEncoder_initEncode(jni, *encoder_, settings, callback);
 
-  if (jni->CallIntMethod(ret, get_number_method_) == WEBRTC_VIDEO_CODEC_OK) {
+  if (Java_VideoCodecStatus_getNumber(jni, ret) == WEBRTC_VIDEO_CODEC_OK) {
     initialized_ = true;
   }
 
@@ -163,13 +124,12 @@
   jobjectArray j_frame_types =
       jni->NewObjectArray(frame_types->size(), *frame_type_class_, nullptr);
   for (size_t i = 0; i < frame_types->size(); ++i) {
-    jobject j_frame_type = jni->CallStaticObjectMethod(
-        *frame_type_class_, frame_type_from_native_method_,
-        static_cast<jint>((*frame_types)[i]));
+    jobject j_frame_type = Java_VideoEncoderWrapper_createFrameType(
+        jni, static_cast<jint>((*frame_types)[i]));
     jni->SetObjectArrayElement(j_frame_types, i, j_frame_type);
   }
-  jobject encode_info = jni->NewObject(*encode_info_class_,
-                                       encode_info_constructor_, j_frame_types);
+  jobject encode_info =
+      Java_VideoEncoderWrapper_createEncodeInfo(jni, j_frame_types);
 
   FrameExtraInfo info;
   info.capture_time_ns = frame.timestamp_us() * rtc::kNumNanosecsPerMicrosec;
@@ -210,17 +170,17 @@
   jobject j_scaling_settings =
       Java_VideoEncoder_getScalingSettings(jni, *encoder_);
   bool on =
-      jni->GetBooleanField(j_scaling_settings, scaling_settings_on_field_);
+      Java_VideoEncoderWrapper_getScalingSettingsOn(jni, j_scaling_settings);
   jobject j_low =
-      jni->GetObjectField(j_scaling_settings, scaling_settings_low_field_);
+      Java_VideoEncoderWrapper_getScalingSettingsLow(jni, j_scaling_settings);
   jobject j_high =
-      jni->GetObjectField(j_scaling_settings, scaling_settings_high_field_);
+      Java_VideoEncoderWrapper_getScalingSettingsHigh(jni, j_scaling_settings);
 
   if (j_low != nullptr || j_high != nullptr) {
     RTC_DCHECK(j_low != nullptr);
     RTC_DCHECK(j_high != nullptr);
-    int low = jni->CallIntMethod(j_low, int_value_method_);
-    int high = jni->CallIntMethod(j_high, int_value_method_);
+    int low = Java_VideoEncoderWrapper_getIntValue(jni, j_low);
+    int high = Java_VideoEncoderWrapper_getIntValue(jni, j_high);
     return ScalingSettings(on, low, high);
   } else {
     return ScalingSettings(on);
@@ -248,7 +208,7 @@
   memcpy(buffer_copy.data(), buffer, buffer_size);
   int qp = -1;
   if (j_qp != nullptr) {
-    qp = jni->CallIntMethod(j_qp, int_value_method_);
+    qp = Java_VideoEncoderWrapper_getIntValue(jni, j_qp);
   }
 
   encoder_queue_->PostTask(
@@ -293,7 +253,7 @@
 }
 
 int32_t VideoEncoderWrapper::HandleReturnCode(JNIEnv* jni, jobject code) {
-  int32_t value = jni->CallIntMethod(code, get_number_method_);
+  int32_t value = Java_VideoCodecStatus_getNumber(jni, code);
   if (value < 0) {  // Any errors are represented by negative values.
     // Try resetting the codec.
     if (++num_resets_ <= kMaxJavaEncoderResets &&
@@ -433,8 +393,8 @@
     jni->SetObjectArrayElement(j_allocation_array, spatial_i,
                                j_array_spatial_layer);
   }
-  return jni->NewObject(*bitrate_allocation_class_,
-                        bitrate_allocation_constructor_, j_allocation_array);
+  return Java_VideoEncoderWrapper_createBitrateAllocation(jni,
+                                                          j_allocation_array);
 }
 
 std::string VideoEncoderWrapper::GetImplementationName(JNIEnv* jni) const {
@@ -443,7 +403,7 @@
 }
 
 JNI_FUNCTION_DECLARATION(void,
-                         VideoEncoderWrapperCallback_nativeOnEncodedFrame,
+                         VideoEncoderWrapper_onEncodedFrame,
                          JNIEnv* jni,
                          jclass,
                          jlong j_native_encoder,
diff --git a/sdk/android/src/jni/videoencoderwrapper.h b/sdk/android/src/jni/videoencoderwrapper.h
index 866002a..7717eb8 100644
--- a/sdk/android/src/jni/videoencoderwrapper.h
+++ b/sdk/android/src/jni/videoencoderwrapper.h
@@ -26,9 +26,7 @@
 namespace webrtc {
 namespace jni {
 
-// Wraps a Java decoder and delegates all calls to it. Passes
-// VideoEncoderWrapperCallback to the decoder on InitDecode. Wraps the received
-// frames to AndroidVideoBuffer.
+// Wraps a Java encoder and delegates all calls to it.
 class VideoEncoderWrapper : public VideoEncoder {
  public:
   VideoEncoderWrapper(JNIEnv* jni, jobject j_encoder);
@@ -90,28 +88,9 @@
   std::string GetImplementationName(JNIEnv* jni) const;
 
   const ScopedGlobalRef<jobject> encoder_;
-  const ScopedGlobalRef<jclass> settings_class_;
-  const ScopedGlobalRef<jclass> encode_info_class_;
   const ScopedGlobalRef<jclass> frame_type_class_;
-  const ScopedGlobalRef<jclass> bitrate_allocation_class_;
   const ScopedGlobalRef<jclass> int_array_class_;
 
-  jmethodID settings_constructor_;
-
-  jmethodID encode_info_constructor_;
-
-  jmethodID frame_type_from_native_method_;
-
-  jmethodID bitrate_allocation_constructor_;
-
-  jfieldID scaling_settings_on_field_;
-  jfieldID scaling_settings_low_field_;
-  jfieldID scaling_settings_high_field_;
-
-  jmethodID get_number_method_;
-
-  jmethodID int_value_method_;
-
   std::string implementation_name_;
 
   rtc::TaskQueue* encoder_queue_;