Android: Annotate and generate JNI code for VideoFrame.java

This CL also merged native_handle_impl.cc and videoframe_jni.cc to keep
all JNI code for the same Java class in the same file, and also renames
this file to jni/videoframe.cc.

The classes AndroidVideoBufferFactory and JavaVideoFrameFactory are
now unnecessary since we cache everything and can be simplified to
global static functions instead.

Bug: webrtc:8278
Change-Id: I03d7b0bbde64cfb407cd6210478ddf9d5599cd8c
Reviewed-on: https://webrtc-review.googlesource.com/22923
Commit-Queue: Magnus Jedvert <magjed@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20677}
diff --git a/sdk/android/src/java/org/webrtc/CalledByNative.java b/sdk/android/src/java/org/webrtc/CalledByNative.java
index 7e08328..42487ff 100644
--- a/sdk/android/src/java/org/webrtc/CalledByNative.java
+++ b/sdk/android/src/java/org/webrtc/CalledByNative.java
@@ -21,4 +21,9 @@
  */
 @Target(ElementType.METHOD)
 @Retention(RetentionPolicy.CLASS)
-@interface CalledByNative {}
+@interface CalledByNative {
+  /*
+   *  If present, tells which inner class the method belongs to.
+   */
+  public String value() default "";
+}
diff --git a/sdk/android/src/jni/androidmediadecoder_jni.cc b/sdk/android/src/jni/androidmediadecoder_jni.cc
index 344a4ca..613bb54 100644
--- a/sdk/android/src/jni/androidmediadecoder_jni.cc
+++ b/sdk/android/src/jni/androidmediadecoder_jni.cc
@@ -17,9 +17,6 @@
 // androidmediacodeccommon.h to avoid build errors.
 #include "sdk/android/src/jni/androidmediadecoder_jni.h"
 
-#include "third_party/libyuv/include/libyuv/convert.h"
-#include "third_party/libyuv/include/libyuv/convert_from.h"
-#include "third_party/libyuv/include/libyuv/video_common.h"
 #include "common_video/h264/h264_bitstream_parser.h"
 #include "common_video/include/i420_buffer_pool.h"
 #include "modules/video_coding/include/video_codec_interface.h"
@@ -32,8 +29,11 @@
 #include "rtc_base/timeutils.h"
 #include "sdk/android/src/jni/androidmediacodeccommon.h"
 #include "sdk/android/src/jni/classreferenceholder.h"
-#include "sdk/android/src/jni/native_handle_impl.h"
 #include "sdk/android/src/jni/surfacetexturehelper_jni.h"
+#include "sdk/android/src/jni/videoframe.h"
+#include "third_party/libyuv/include/libyuv/convert.h"
+#include "third_party/libyuv/include/libyuv/convert_from.h"
+#include "third_party/libyuv/include/libyuv/video_common.h"
 
 using rtc::Bind;
 using rtc::Thread;
diff --git a/sdk/android/src/jni/androidmediaencoder_jni.cc b/sdk/android/src/jni/androidmediaencoder_jni.cc
index a7d528d..1b8c4d9 100644
--- a/sdk/android/src/jni/androidmediaencoder_jni.cc
+++ b/sdk/android/src/jni/androidmediaencoder_jni.cc
@@ -18,9 +18,6 @@
 #include <string>
 #include <utility>
 
-#include "third_party/libyuv/include/libyuv/convert.h"
-#include "third_party/libyuv/include/libyuv/convert_from.h"
-#include "third_party/libyuv/include/libyuv/video_common.h"
 #include "api/video_codecs/video_encoder.h"
 #include "common_types.h"  // NOLINT(build/include)
 #include "common_video/h264/h264_bitstream_parser.h"
@@ -43,8 +40,11 @@
 #include "sdk/android/src/jni/androidmediacodeccommon.h"
 #include "sdk/android/src/jni/classreferenceholder.h"
 #include "sdk/android/src/jni/jni_helpers.h"
-#include "sdk/android/src/jni/native_handle_impl.h"
+#include "sdk/android/src/jni/videoframe.h"
 #include "system_wrappers/include/field_trial.h"
+#include "third_party/libyuv/include/libyuv/convert.h"
+#include "third_party/libyuv/include/libyuv/convert_from.h"
+#include "third_party/libyuv/include/libyuv/video_common.h"
 
 using rtc::Bind;
 using rtc::Thread;
@@ -230,7 +230,6 @@
   jfieldID j_info_is_key_frame_field_;
   jfieldID j_info_presentation_timestamp_us_field_;
 
-  const JavaVideoFrameFactory video_frame_factory_;
   ScopedGlobalRef<jclass> j_video_frame_texture_buffer_class_;
 
   // State that is valid only between InitEncode() and the next Release().
@@ -342,7 +341,6 @@
                                      *j_media_codec_video_encoder_class_,
                                      "<init>",
                                      "()V"))),
-      video_frame_factory_(jni),
       j_video_frame_texture_buffer_class_(
           jni,
           FindClass(jni, "org/webrtc/VideoFrame$TextureBuffer")),
@@ -801,9 +799,9 @@
         encode_status = EncodeTexture(jni, key_frame, input_frame);
         break;
       case AndroidVideoFrameBuffer::AndroidType::kJavaBuffer:
-        encode_status = EncodeJavaFrame(
-            jni, key_frame, video_frame_factory_.ToJavaFrame(jni, input_frame),
-            j_input_buffer_index);
+        encode_status =
+            EncodeJavaFrame(jni, key_frame, NativeToJavaFrame(jni, input_frame),
+                            j_input_buffer_index);
         break;
       default:
         RTC_NOTREACHED();
diff --git a/sdk/android/src/jni/androidvideotracksource.cc b/sdk/android/src/jni/androidvideotracksource.cc
index 3913ed0..ba31f7e 100644
--- a/sdk/android/src/jni/androidvideotracksource.cc
+++ b/sdk/android/src/jni/androidvideotracksource.cc
@@ -33,7 +33,6 @@
       surface_texture_helper_(new rtc::RefCountedObject<SurfaceTextureHelper>(
           jni,
           j_surface_texture_helper)),
-      video_buffer_factory_(jni),
       is_screencast_(is_screencast) {
   RTC_LOG(LS_INFO) << "AndroidVideoTrackSource ctor";
   camera_thread_checker_.DetachFromThread();
@@ -189,7 +188,7 @@
       crop_height, adapted_width, adapted_height);
 
   rtc::scoped_refptr<VideoFrameBuffer> buffer =
-      video_buffer_factory_.WrapBuffer(jni, j_adapted_video_frame_buffer);
+      AndroidVideoBuffer::Adopt(jni, j_adapted_video_frame_buffer);
 
   // AdaptedVideoTrackSource handles applying rotation for I420 frames.
   if (apply_rotation() && rotation != kVideoRotation_0) {
diff --git a/sdk/android/src/jni/androidvideotracksource.h b/sdk/android/src/jni/androidvideotracksource.h
index fca4148..641c10f 100644
--- a/sdk/android/src/jni/androidvideotracksource.h
+++ b/sdk/android/src/jni/androidvideotracksource.h
@@ -20,8 +20,8 @@
 #include "rtc_base/checks.h"
 #include "rtc_base/thread_checker.h"
 #include "rtc_base/timestampaligner.h"
-#include "sdk/android/src/jni/native_handle_impl.h"
 #include "sdk/android/src/jni/surfacetexturehelper_jni.h"
+#include "sdk/android/src/jni/videoframe.h"
 
 namespace webrtc {
 namespace jni {
@@ -84,7 +84,6 @@
   NV12ToI420Scaler nv12toi420_scaler_;
   I420BufferPool buffer_pool_;
   rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
-  AndroidVideoBufferFactory video_buffer_factory_;
   const bool is_screencast_;
 
   jmethodID j_crop_and_scale_id_;
diff --git a/sdk/android/src/jni/surfacetexturehelper_jni.h b/sdk/android/src/jni/surfacetexturehelper_jni.h
index 3d264d2..b227b52 100644
--- a/sdk/android/src/jni/surfacetexturehelper_jni.h
+++ b/sdk/android/src/jni/surfacetexturehelper_jni.h
@@ -17,7 +17,7 @@
 #include "rtc_base/refcount.h"
 #include "rtc_base/scoped_ref_ptr.h"
 #include "sdk/android/src/jni/jni_helpers.h"
-#include "sdk/android/src/jni/native_handle_impl.h"
+#include "sdk/android/src/jni/videoframe.h"
 
 namespace webrtc {
 namespace jni {
diff --git a/sdk/android/src/jni/video_renderer_jni.cc b/sdk/android/src/jni/video_renderer_jni.cc
index 4bd5159..ba439b9 100644
--- a/sdk/android/src/jni/video_renderer_jni.cc
+++ b/sdk/android/src/jni/video_renderer_jni.cc
@@ -14,7 +14,7 @@
 #include "media/base/videosinkinterface.h"
 #include "sdk/android/src/jni/classreferenceholder.h"
 #include "sdk/android/src/jni/jni_helpers.h"
-#include "sdk/android/src/jni/native_handle_impl.h"
+#include "sdk/android/src/jni/videoframe.h"
 
 namespace webrtc {
 namespace jni {
diff --git a/sdk/android/src/jni/videodecoderwrapper.cc b/sdk/android/src/jni/videodecoderwrapper.cc
index 69b5c2d..afa1f2e 100644
--- a/sdk/android/src/jni/videodecoderwrapper.cc
+++ b/sdk/android/src/jni/videodecoderwrapper.cc
@@ -22,8 +22,7 @@
 namespace jni {
 
 VideoDecoderWrapper::VideoDecoderWrapper(JNIEnv* jni, jobject decoder)
-    : android_video_buffer_factory_(jni),
-      decoder_(jni, decoder),
+    : decoder_(jni, decoder),
       encoded_image_class_(jni, FindClass(jni, "org/webrtc/EncodedImage")),
       frame_type_class_(jni,
                         FindClass(jni, "org/webrtc/EncodedImage$FrameType")),
@@ -187,8 +186,8 @@
     // find a matching timestamp.
   } while (frame_extra_info.capture_time_ns != capture_time_ns);
 
-  VideoFrame frame = android_video_buffer_factory_.CreateFrame(
-      jni, jframe, frame_extra_info.timestamp_rtp);
+  VideoFrame frame =
+      JavaToNativeFrame(jni, jframe, frame_extra_info.timestamp_rtp);
 
   rtc::Optional<int32_t> decoding_time_ms;
   if (jdecode_time_ms != nullptr) {
diff --git a/sdk/android/src/jni/videodecoderwrapper.h b/sdk/android/src/jni/videodecoderwrapper.h
index 978be87..f56b49e 100644
--- a/sdk/android/src/jni/videodecoderwrapper.h
+++ b/sdk/android/src/jni/videodecoderwrapper.h
@@ -17,7 +17,7 @@
 #include "api/video_codecs/video_decoder.h"
 #include "common_video/h264/h264_bitstream_parser.h"
 #include "sdk/android/src/jni/jni_helpers.h"
-#include "sdk/android/src/jni/native_handle_impl.h"
+#include "sdk/android/src/jni/videoframe.h"
 
 namespace webrtc {
 namespace jni {
@@ -78,7 +78,6 @@
   int32_t number_of_cores_;
 
   bool initialized_;
-  AndroidVideoBufferFactory android_video_buffer_factory_;
   std::deque<FrameExtraInfo> frame_extra_infos_;
   bool qp_parsing_enabled_;
   H264BitstreamParser h264_bitstream_parser_;
diff --git a/sdk/android/src/jni/videoencoderwrapper.cc b/sdk/android/src/jni/videoencoderwrapper.cc
index d8e1546..958d029 100644
--- a/sdk/android/src/jni/videoencoderwrapper.cc
+++ b/sdk/android/src/jni/videoencoderwrapper.cc
@@ -35,8 +35,7 @@
     : encoder_(jni, j_encoder),
       frame_type_class_(jni,
                         GetClass(jni, "org/webrtc/EncodedImage$FrameType")),
-      int_array_class_(jni, jni->FindClass("[I")),
-      video_frame_factory_(jni) {
+      int_array_class_(jni, jni->FindClass("[I")) {
   implementation_name_ = GetImplementationName(jni);
 
   initialized_ = false;
@@ -137,8 +136,7 @@
   frame_extra_infos_.push_back(info);
 
   jobject ret = Java_VideoEncoder_encode(
-      jni, *encoder_, video_frame_factory_.ToJavaFrame(jni, frame),
-      encode_info);
+      jni, *encoder_, NativeToJavaFrame(jni, frame), encode_info);
   return HandleReturnCode(jni, ret);
 }
 
diff --git a/sdk/android/src/jni/videoencoderwrapper.h b/sdk/android/src/jni/videoencoderwrapper.h
index 06f5903..629f28a 100644
--- a/sdk/android/src/jni/videoencoderwrapper.h
+++ b/sdk/android/src/jni/videoencoderwrapper.h
@@ -21,7 +21,7 @@
 #include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
 #include "rtc_base/task_queue.h"
 #include "sdk/android/src/jni/jni_helpers.h"
-#include "sdk/android/src/jni/native_handle_impl.h"
+#include "sdk/android/src/jni/videoframe.h"
 
 namespace webrtc {
 namespace jni {
@@ -95,7 +95,6 @@
   std::string implementation_name_;
 
   rtc::TaskQueue* encoder_queue_;
-  JavaVideoFrameFactory video_frame_factory_;
   std::deque<FrameExtraInfo> frame_extra_infos_;
   EncodedImageCallback* callback_;
   bool initialized_;
diff --git a/sdk/android/src/jni/native_handle_impl.cc b/sdk/android/src/jni/videoframe.cc
similarity index 60%
rename from sdk/android/src/jni/native_handle_impl.cc
rename to sdk/android/src/jni/videoframe.cc
index ea1e04e..5e24002 100644
--- a/sdk/android/src/jni/native_handle_impl.cc
+++ b/sdk/android/src/jni/videoframe.cc
@@ -8,17 +8,19 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "sdk/android/src/jni/native_handle_impl.h"
+#include "sdk/android/src/jni/videoframe.h"
 
 #include <memory>
 
 #include "common_video/include/video_frame_buffer.h"
+#include "libyuv/scale.h"
 #include "rtc_base/bind.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/keep_ref_until_done.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/scoped_ref_ptr.h"
 #include "rtc_base/timeutils.h"
+#include "sdk/android/generated_video_jni/jni/VideoFrame_jni.h"
 #include "sdk/android/src/jni/classreferenceholder.h"
 #include "sdk/android/src/jni/jni_helpers.h"
 #include "sdk/android/src/jni/wrapped_native_i420_buffer.h"
@@ -31,26 +33,16 @@
 
 class AndroidVideoI420Buffer : public I420BufferInterface {
  public:
-  // Wraps an existing reference to a Java VideoBuffer. Retain will not be
-  // called but release will be called when the C++ object is destroyed.
-  static rtc::scoped_refptr<AndroidVideoI420Buffer> WrapReference(
-      JNIEnv* jni,
-      jmethodID j_release_id,
-      int width,
-      int height,
-      jobject j_video_frame_buffer);
+  // Adopts and takes ownership of the Java VideoFrame.Buffer. I.e. retain()
+  // will not be called, but release() will be called when the returned
+  // AndroidVideoBuffer is destroyed.
+  static rtc::scoped_refptr<AndroidVideoI420Buffer>
+  Adopt(JNIEnv* jni, int width, int height, jobject j_video_frame_buffer);
 
  protected:
+  // Should not be called directly. Adopts the buffer. Use Adopt() instead for
+  // clarity.
   AndroidVideoI420Buffer(JNIEnv* jni,
-                         jmethodID j_retain_id,
-                         jmethodID j_release_id,
-                         int width,
-                         int height,
-                         jobject j_video_frame_buffer);
-  // Should not be called directly. Wraps a reference. Use
-  // AndroidVideoI420Buffer::WrapReference instead for clarity.
-  AndroidVideoI420Buffer(JNIEnv* jni,
-                         jmethodID j_release_id,
                          int width,
                          int height,
                          jobject j_video_frame_buffer);
@@ -68,7 +60,6 @@
   int width() const override { return width_; }
   int height() const override { return height_; }
 
-  const jmethodID j_release_id_;
   const int width_;
   const int height_;
   // Holds a VideoFrame.I420Buffer.
@@ -82,73 +73,38 @@
   int stride_v_;
 };
 
-rtc::scoped_refptr<AndroidVideoI420Buffer>
-AndroidVideoI420Buffer::WrapReference(JNIEnv* jni,
-                                      jmethodID j_release_id,
-                                      int width,
-                                      int height,
-                                      jobject j_video_frame_buffer) {
+rtc::scoped_refptr<AndroidVideoI420Buffer> AndroidVideoI420Buffer::Adopt(
+    JNIEnv* jni,
+    int width,
+    int height,
+    jobject j_video_frame_buffer) {
   return new rtc::RefCountedObject<AndroidVideoI420Buffer>(
-      jni, j_release_id, width, height, j_video_frame_buffer);
+      jni, width, height, j_video_frame_buffer);
 }
 
 AndroidVideoI420Buffer::AndroidVideoI420Buffer(JNIEnv* jni,
-                                               jmethodID j_retain_id,
-                                               jmethodID j_release_id,
                                                int width,
                                                int height,
                                                jobject j_video_frame_buffer)
-    : AndroidVideoI420Buffer(jni,
-                             j_release_id,
-                             width,
-                             height,
-                             j_video_frame_buffer) {
-  jni->CallVoidMethod(j_video_frame_buffer, j_retain_id);
-}
-
-AndroidVideoI420Buffer::AndroidVideoI420Buffer(JNIEnv* jni,
-                                               jmethodID j_release_id,
-                                               int width,
-                                               int height,
-                                               jobject j_video_frame_buffer)
-    : j_release_id_(j_release_id),
-      width_(width),
+    : width_(width),
       height_(height),
       j_video_frame_buffer_(jni, j_video_frame_buffer) {
-  jclass j_video_frame_i420_buffer_class =
-      FindClass(jni, "org/webrtc/VideoFrame$I420Buffer");
-  jmethodID j_get_data_y_id = jni->GetMethodID(
-      j_video_frame_i420_buffer_class, "getDataY", "()Ljava/nio/ByteBuffer;");
-  jmethodID j_get_data_u_id = jni->GetMethodID(
-      j_video_frame_i420_buffer_class, "getDataU", "()Ljava/nio/ByteBuffer;");
-  jmethodID j_get_data_v_id = jni->GetMethodID(
-      j_video_frame_i420_buffer_class, "getDataV", "()Ljava/nio/ByteBuffer;");
-  jmethodID j_get_stride_y_id =
-      jni->GetMethodID(j_video_frame_i420_buffer_class, "getStrideY", "()I");
-  jmethodID j_get_stride_u_id =
-      jni->GetMethodID(j_video_frame_i420_buffer_class, "getStrideU", "()I");
-  jmethodID j_get_stride_v_id =
-      jni->GetMethodID(j_video_frame_i420_buffer_class, "getStrideV", "()I");
-
-  jobject j_data_y =
-      jni->CallObjectMethod(j_video_frame_buffer, j_get_data_y_id);
-  jobject j_data_u =
-      jni->CallObjectMethod(j_video_frame_buffer, j_get_data_u_id);
-  jobject j_data_v =
-      jni->CallObjectMethod(j_video_frame_buffer, j_get_data_v_id);
+  jobject j_data_y = Java_I420Buffer_getDataY(jni, j_video_frame_buffer);
+  jobject j_data_u = Java_I420Buffer_getDataU(jni, j_video_frame_buffer);
+  jobject j_data_v = Java_I420Buffer_getDataV(jni, j_video_frame_buffer);
 
   data_y_ = static_cast<const uint8_t*>(jni->GetDirectBufferAddress(j_data_y));
   data_u_ = static_cast<const uint8_t*>(jni->GetDirectBufferAddress(j_data_u));
   data_v_ = static_cast<const uint8_t*>(jni->GetDirectBufferAddress(j_data_v));
 
-  stride_y_ = jni->CallIntMethod(j_video_frame_buffer, j_get_stride_y_id);
-  stride_u_ = jni->CallIntMethod(j_video_frame_buffer, j_get_stride_u_id);
-  stride_v_ = jni->CallIntMethod(j_video_frame_buffer, j_get_stride_v_id);
+  stride_y_ = Java_I420Buffer_getStrideY(jni, j_video_frame_buffer);
+  stride_u_ = Java_I420Buffer_getStrideU(jni, j_video_frame_buffer);
+  stride_v_ = Java_I420Buffer_getStrideV(jni, j_video_frame_buffer);
 }
 
 AndroidVideoI420Buffer::~AndroidVideoI420Buffer() {
   JNIEnv* jni = AttachCurrentThreadIfNeeded();
-  jni->CallVoidMethod(*j_video_frame_buffer_, j_release_id_);
+  Java_Buffer_release(jni, *j_video_frame_buffer_);
 }
 
 }  // namespace
@@ -297,7 +253,7 @@
   // See YuvConverter.java for the required layout.
   uint8_t* y_data = yuv_data.get();
   uint8_t* u_data = y_data + height() * stride;
-  uint8_t* v_data = u_data + stride/2;
+  uint8_t* v_data = u_data + stride / 2;
 
   rtc::scoped_refptr<I420BufferInterface> copy = webrtc::WrapI420Buffer(
       width(), height(), y_data, stride, u_data, stride, v_data, stride,
@@ -326,43 +282,29 @@
   return copy;
 }
 
-rtc::scoped_refptr<AndroidVideoBuffer> AndroidVideoBuffer::WrapReference(
+rtc::scoped_refptr<AndroidVideoBuffer> AndroidVideoBuffer::Adopt(
     JNIEnv* jni,
-    jmethodID j_release_id,
-    int width,
-    int height,
     jobject j_video_frame_buffer) {
-  return new rtc::RefCountedObject<AndroidVideoBuffer>(
-      jni, j_release_id, width, height, j_video_frame_buffer);
+  return new rtc::RefCountedObject<AndroidVideoBuffer>(jni,
+                                                       j_video_frame_buffer);
+}
+
+rtc::scoped_refptr<AndroidVideoBuffer> AndroidVideoBuffer::Create(
+    JNIEnv* jni,
+    jobject j_video_frame_buffer) {
+  Java_Buffer_retain(jni, j_video_frame_buffer);
+  return Adopt(jni, j_video_frame_buffer);
 }
 
 AndroidVideoBuffer::AndroidVideoBuffer(JNIEnv* jni,
-                                       jmethodID j_retain_id,
-                                       jmethodID j_release_id,
-                                       int width,
-                                       int height,
                                        jobject j_video_frame_buffer)
-    : AndroidVideoBuffer(jni,
-                         j_release_id,
-                         width,
-                         height,
-                         j_video_frame_buffer) {
-  jni->CallVoidMethod(j_video_frame_buffer, j_retain_id);
-}
-
-AndroidVideoBuffer::AndroidVideoBuffer(JNIEnv* jni,
-                                       jmethodID j_release_id,
-                                       int width,
-                                       int height,
-                                       jobject j_video_frame_buffer)
-    : j_release_id_(j_release_id),
-      width_(width),
-      height_(height),
+    : width_(Java_Buffer_getWidth(jni, j_video_frame_buffer)),
+      height_(Java_Buffer_getHeight(jni, j_video_frame_buffer)),
       j_video_frame_buffer_(jni, j_video_frame_buffer) {}
 
 AndroidVideoBuffer::~AndroidVideoBuffer() {
   JNIEnv* jni = AttachCurrentThreadIfNeeded();
-  jni->CallVoidMethod(*j_video_frame_buffer_, j_release_id_);
+  Java_Buffer_release(jni, *j_video_frame_buffer_);
 }
 
 jobject AndroidVideoBuffer::video_frame_buffer() const {
@@ -384,20 +326,11 @@
 rtc::scoped_refptr<I420BufferInterface> AndroidVideoBuffer::ToI420() {
   JNIEnv* jni = AttachCurrentThreadIfNeeded();
   ScopedLocalRefFrame local_ref_frame(jni);
-
-  jclass j_video_frame_buffer_class =
-      FindClass(jni, "org/webrtc/VideoFrame$Buffer");
-  jmethodID j_to_i420_id =
-      jni->GetMethodID(j_video_frame_buffer_class, "toI420",
-                       "()Lorg/webrtc/VideoFrame$I420Buffer;");
-
-  jobject j_i420_buffer =
-      jni->CallObjectMethod(*j_video_frame_buffer_, j_to_i420_id);
+  jobject j_i420_buffer = Java_Buffer_toI420(jni, *j_video_frame_buffer_);
 
   // We don't need to retain the buffer because toI420 returns a new object that
   // we are assumed to take the ownership of.
-  return AndroidVideoI420Buffer::WrapReference(jni, j_release_id_, width_,
-                                               height_, j_i420_buffer);
+  return AndroidVideoI420Buffer::Adopt(jni, width_, height_, j_i420_buffer);
 }
 
 jobject AndroidVideoBuffer::ToJavaI420Frame(JNIEnv* jni, int rotation) {
@@ -415,69 +348,19 @@
                         *j_video_frame_buffer_, jlongFromPointer(native_frame));
 }
 
-AndroidVideoBufferFactory::AndroidVideoBufferFactory(JNIEnv* jni)
-    : j_video_frame_class_(jni, FindClass(jni, "org/webrtc/VideoFrame")),
-      j_get_buffer_id_(GetMethodID(jni,
-                                   *j_video_frame_class_,
-                                   "getBuffer",
-                                   "()Lorg/webrtc/VideoFrame$Buffer;")),
-      j_get_rotation_id_(
-          GetMethodID(jni, *j_video_frame_class_, "getRotation", "()I")),
-      j_get_timestamp_ns_id_(
-          GetMethodID(jni, *j_video_frame_class_, "getTimestampNs", "()J")),
-      j_video_frame_buffer_class_(
-          jni,
-          FindClass(jni, "org/webrtc/VideoFrame$Buffer")),
-      j_retain_id_(
-          GetMethodID(jni, *j_video_frame_buffer_class_, "retain", "()V")),
-      j_release_id_(
-          GetMethodID(jni, *j_video_frame_buffer_class_, "release", "()V")),
-      j_get_width_id_(
-          GetMethodID(jni, *j_video_frame_buffer_class_, "getWidth", "()I")),
-      j_get_height_id_(
-          GetMethodID(jni, *j_video_frame_buffer_class_, "getHeight", "()I")) {}
-
-VideoFrame AndroidVideoBufferFactory::CreateFrame(
-    JNIEnv* jni,
-    jobject j_video_frame,
-    uint32_t timestamp_rtp) const {
-  jobject j_video_frame_buffer =
-      jni->CallObjectMethod(j_video_frame, j_get_buffer_id_);
-  int rotation = jni->CallIntMethod(j_video_frame, j_get_rotation_id_);
-  uint32_t timestamp_ns =
-      jni->CallLongMethod(j_video_frame, j_get_timestamp_ns_id_);
+VideoFrame JavaToNativeFrame(JNIEnv* jni,
+                             jobject j_video_frame,
+                             uint32_t timestamp_rtp) {
+  jobject j_video_frame_buffer = Java_VideoFrame_getBuffer(jni, j_video_frame);
+  int rotation = Java_VideoFrame_getRotation(jni, j_video_frame);
+  uint32_t timestamp_ns = Java_VideoFrame_getTimestampNs(jni, j_video_frame);
   rtc::scoped_refptr<AndroidVideoBuffer> buffer =
-      CreateBuffer(jni, j_video_frame_buffer);
+      AndroidVideoBuffer::Create(jni, j_video_frame_buffer);
   return VideoFrame(buffer, timestamp_rtp,
                     timestamp_ns / rtc::kNumNanosecsPerMillisec,
                     static_cast<VideoRotation>(rotation));
 }
 
-rtc::scoped_refptr<AndroidVideoBuffer> AndroidVideoBufferFactory::WrapBuffer(
-    JNIEnv* jni,
-    jobject j_video_frame_buffer) const {
-  int width = jni->CallIntMethod(j_video_frame_buffer, j_get_width_id_);
-  int height = jni->CallIntMethod(j_video_frame_buffer, j_get_height_id_);
-  return AndroidVideoBuffer::WrapReference(jni, j_release_id_, width, height,
-                                           j_video_frame_buffer);
-}
-
-rtc::scoped_refptr<AndroidVideoBuffer> AndroidVideoBufferFactory::CreateBuffer(
-    JNIEnv* jni,
-    jobject j_video_frame_buffer) const {
-  int width = jni->CallIntMethod(j_video_frame_buffer, j_get_width_id_);
-  int height = jni->CallIntMethod(j_video_frame_buffer, j_get_height_id_);
-  return new rtc::RefCountedObject<AndroidVideoBuffer>(
-      jni, j_retain_id_, j_release_id_, width, height, j_video_frame_buffer);
-}
-
-JavaVideoFrameFactory::JavaVideoFrameFactory(JNIEnv* jni)
-    : j_video_frame_class_(jni, FindClass(jni, "org/webrtc/VideoFrame")) {
-  j_video_frame_constructor_id_ =
-      GetMethodID(jni, *j_video_frame_class_, "<init>",
-                  "(Lorg/webrtc/VideoFrame$Buffer;IJ)V");
-}
-
 static bool IsJavaVideoBuffer(rtc::scoped_refptr<VideoFrameBuffer> buffer) {
   if (buffer->type() != VideoFrameBuffer::Type::kNative) {
     return false;
@@ -488,8 +371,7 @@
          AndroidVideoFrameBuffer::AndroidType::kJavaBuffer;
 }
 
-jobject JavaVideoFrameFactory::ToJavaFrame(JNIEnv* jni,
-                                           const VideoFrame& frame) const {
+jobject NativeToJavaFrame(JNIEnv* jni, const VideoFrame& frame) {
   rtc::scoped_refptr<VideoFrameBuffer> buffer = frame.video_frame_buffer();
   jobject j_buffer;
   if (IsJavaVideoBuffer(buffer)) {
@@ -504,11 +386,53 @@
   } else {
     j_buffer = WrapI420Buffer(jni, buffer->ToI420());
   }
-  return jni->NewObject(
-      *j_video_frame_class_, j_video_frame_constructor_id_, j_buffer,
-      static_cast<jint>(frame.rotation()),
+  return Java_VideoFrame_create(
+      jni, j_buffer, static_cast<jint>(frame.rotation()),
       static_cast<jlong>(frame.timestamp_us() * rtc::kNumNanosecsPerMicrosec));
 }
 
+extern "C" JNIEXPORT void JNICALL
+Java_org_webrtc_VideoFrame_cropAndScaleI420Native(JNIEnv* jni,
+                                                  jclass,
+                                                  jobject j_src_y,
+                                                  jint src_stride_y,
+                                                  jobject j_src_u,
+                                                  jint src_stride_u,
+                                                  jobject j_src_v,
+                                                  jint src_stride_v,
+                                                  jint crop_x,
+                                                  jint crop_y,
+                                                  jint crop_width,
+                                                  jint crop_height,
+                                                  jobject j_dst_y,
+                                                  jint dst_stride_y,
+                                                  jobject j_dst_u,
+                                                  jint dst_stride_u,
+                                                  jobject j_dst_v,
+                                                  jint dst_stride_v,
+                                                  jint scale_width,
+                                                  jint scale_height) {
+  uint8_t const* src_y =
+      static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_y));
+  uint8_t const* src_u =
+      static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_u));
+  uint8_t const* src_v =
+      static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_v));
+  uint8_t* dst_y = static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_y));
+  uint8_t* dst_u = static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_u));
+  uint8_t* dst_v = static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_v));
+
+  // Perform cropping using pointer arithmetic.
+  src_y += crop_x + crop_y * src_stride_y;
+  src_u += crop_x / 2 + crop_y / 2 * src_stride_u;
+  src_v += crop_x / 2 + crop_y / 2 * src_stride_v;
+
+  bool ret = libyuv::I420Scale(
+      src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v, crop_width,
+      crop_height, dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v,
+      dst_stride_v, scale_width, scale_height, libyuv::kFilterBox);
+  RTC_DCHECK_EQ(ret, 0) << "I420Scale failed";
+}
+
 }  // namespace jni
 }  // namespace webrtc
diff --git a/sdk/android/src/jni/native_handle_impl.h b/sdk/android/src/jni/videoframe.h
similarity index 63%
rename from sdk/android/src/jni/native_handle_impl.h
rename to sdk/android/src/jni/videoframe.h
index 10c0d19..c477286 100644
--- a/sdk/android/src/jni/native_handle_impl.h
+++ b/sdk/android/src/jni/videoframe.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef SDK_ANDROID_SRC_JNI_NATIVE_HANDLE_IMPL_H_
-#define SDK_ANDROID_SRC_JNI_NATIVE_HANDLE_IMPL_H_
+#ifndef SDK_ANDROID_SRC_JNI_VIDEOFRAME_H_
+#define SDK_ANDROID_SRC_JNI_VIDEOFRAME_H_
 
 #include <jni.h>
 
@@ -104,28 +104,18 @@
 
 class AndroidVideoBuffer : public AndroidVideoFrameBuffer {
  public:
-  // Wraps an existing reference to a Java VideoBuffer. Retain will not be
-  // called but release will be called when the C++ object is destroyed.
-  static rtc::scoped_refptr<AndroidVideoBuffer> WrapReference(
+  // Creates a native VideoFrameBuffer from a Java VideoFrame.Buffer.
+  static rtc::scoped_refptr<AndroidVideoBuffer> Create(
       JNIEnv* jni,
-      jmethodID j_release_id,
-      int width,
-      int height,
       jobject j_video_frame_buffer);
 
-  AndroidVideoBuffer(JNIEnv* jni,
-                     jmethodID j_retain_id,
-                     jmethodID j_release_id,
-                     int width,
-                     int height,
-                     jobject j_video_frame_buffer);
-  // Should not be called directly. Wraps a reference. Use
-  // AndroidVideoBuffer::WrapReference instead for clarity.
-  AndroidVideoBuffer(JNIEnv* jni,
-                     jmethodID j_release_id,
-                     int width,
-                     int height,
-                     jobject j_video_frame_buffer);
+  // Similar to the Create() above, but adopts and takes ownership of the Java
+  // VideoFrame.Buffer. I.e. retain() will not be called, but release() will be
+  // called when the returned AndroidVideoBuffer is destroyed.
+  static rtc::scoped_refptr<AndroidVideoBuffer> Adopt(
+      JNIEnv* jni,
+      jobject j_video_frame_buffer);
+
   ~AndroidVideoBuffer() override;
 
   jobject video_frame_buffer() const;
@@ -133,6 +123,11 @@
   // Returns an instance of VideoRenderer.I420Frame (deprecated)
   jobject ToJavaI420Frame(JNIEnv* jni, int rotation);
 
+ protected:
+  // Should not be called directly. Adopts the Java VideoFrame.Buffer. Use
+  // Create() or Adopt() instead for clarity.
+  AndroidVideoBuffer(JNIEnv* jni, jobject j_video_frame_buffer);
+
  private:
   Type type() const override;
   int width() const override;
@@ -142,56 +137,19 @@
 
   AndroidType android_type() override { return AndroidType::kJavaBuffer; }
 
-  const jmethodID j_release_id_;
   const int width_;
   const int height_;
   // Holds a VideoFrame.Buffer.
   const ScopedGlobalRef<jobject> j_video_frame_buffer_;
 };
 
-class AndroidVideoBufferFactory {
- public:
-  explicit AndroidVideoBufferFactory(JNIEnv* jni);
+VideoFrame JavaToNativeFrame(JNIEnv* jni,
+                             jobject j_video_frame,
+                             uint32_t timestamp_rtp);
 
-  VideoFrame CreateFrame(JNIEnv* jni,
-                         jobject j_video_frame,
-                         uint32_t timestamp_rtp) const;
-
-  // Wraps a buffer to AndroidVideoBuffer without incrementing the reference
-  // count.
-  rtc::scoped_refptr<AndroidVideoBuffer> WrapBuffer(
-      JNIEnv* jni,
-      jobject j_video_frame_buffer) const;
-
-  rtc::scoped_refptr<AndroidVideoBuffer> CreateBuffer(
-      JNIEnv* jni,
-      jobject j_video_frame_buffer) const;
-
- private:
-  ScopedGlobalRef<jclass> j_video_frame_class_;
-  jmethodID j_get_buffer_id_;
-  jmethodID j_get_rotation_id_;
-  jmethodID j_get_timestamp_ns_id_;
-
-  ScopedGlobalRef<jclass> j_video_frame_buffer_class_;
-  jmethodID j_retain_id_;
-  jmethodID j_release_id_;
-  jmethodID j_get_width_id_;
-  jmethodID j_get_height_id_;
-};
-
-class JavaVideoFrameFactory {
- public:
-  JavaVideoFrameFactory(JNIEnv* jni);
-
-  jobject ToJavaFrame(JNIEnv* jni, const VideoFrame& frame) const;
-
- private:
-  ScopedGlobalRef<jclass> j_video_frame_class_;
-  jmethodID j_video_frame_constructor_id_;
-};
+jobject NativeToJavaFrame(JNIEnv* jni, const VideoFrame& frame);
 
 }  // namespace jni
 }  // namespace webrtc
 
-#endif  // SDK_ANDROID_SRC_JNI_NATIVE_HANDLE_IMPL_H_
+#endif  // SDK_ANDROID_SRC_JNI_VIDEOFRAME_H_
diff --git a/sdk/android/src/jni/videoframe_jni.cc b/sdk/android/src/jni/videoframe_jni.cc
deleted file mode 100644
index 7533f9c..0000000
--- a/sdk/android/src/jni/videoframe_jni.cc
+++ /dev/null
@@ -1,64 +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.
- */
-
-#include <jni.h>
-
-#include "libyuv/scale.h"
-
-#include "rtc_base/checks.h"
-
-namespace webrtc {
-namespace jni {
-
-extern "C" JNIEXPORT void JNICALL
-Java_org_webrtc_VideoFrame_nativeCropAndScaleI420(JNIEnv* jni,
-                                                  jclass,
-                                                  jobject j_src_y,
-                                                  jint src_stride_y,
-                                                  jobject j_src_u,
-                                                  jint src_stride_u,
-                                                  jobject j_src_v,
-                                                  jint src_stride_v,
-                                                  jint crop_x,
-                                                  jint crop_y,
-                                                  jint crop_width,
-                                                  jint crop_height,
-                                                  jobject j_dst_y,
-                                                  jint dst_stride_y,
-                                                  jobject j_dst_u,
-                                                  jint dst_stride_u,
-                                                  jobject j_dst_v,
-                                                  jint dst_stride_v,
-                                                  jint scale_width,
-                                                  jint scale_height) {
-  uint8_t const* src_y =
-      static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_y));
-  uint8_t const* src_u =
-      static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_u));
-  uint8_t const* src_v =
-      static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_v));
-  uint8_t* dst_y = static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_y));
-  uint8_t* dst_u = static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_u));
-  uint8_t* dst_v = static_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_v));
-
-  // Perform cropping using pointer arithmetic.
-  src_y += crop_x + crop_y * src_stride_y;
-  src_u += crop_x / 2 + crop_y / 2 * src_stride_u;
-  src_v += crop_x / 2 + crop_y / 2 * src_stride_v;
-
-  bool ret = libyuv::I420Scale(
-      src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v, crop_width,
-      crop_height, dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v,
-      dst_stride_v, scale_width, scale_height, libyuv::kFilterBox);
-  RTC_DCHECK_EQ(ret, 0) << "I420Scale failed";
-}
-
-}  // namespace jni
-}  // namespace webrtc
diff --git a/sdk/android/src/jni/videotrack_jni.cc b/sdk/android/src/jni/videotrack_jni.cc
index 98b1bd2..7a9dcd0 100644
--- a/sdk/android/src/jni/videotrack_jni.cc
+++ b/sdk/android/src/jni/videotrack_jni.cc
@@ -15,7 +15,7 @@
 #include "sdk/android/generated_video_jni/jni/VideoSink_jni.h"
 #include "sdk/android/src/jni/classreferenceholder.h"
 #include "sdk/android/src/jni/jni_helpers.h"
-#include "sdk/android/src/jni/native_handle_impl.h"
+#include "sdk/android/src/jni/videoframe.h"
 
 namespace webrtc {
 namespace jni {
@@ -30,18 +30,16 @@
  private:
   void OnFrame(const VideoFrame& frame) override;
 
-  const JavaVideoFrameFactory java_video_frame_factory_;
   const ScopedGlobalRef<jobject> j_sink_;
 };
 
 VideoSinkWrapper::VideoSinkWrapper(JNIEnv* jni, jobject j_sink)
-    : java_video_frame_factory_(jni), j_sink_(jni, j_sink) {}
+    : j_sink_(jni, j_sink) {}
 
 void VideoSinkWrapper::OnFrame(const VideoFrame& frame) {
   JNIEnv* jni = AttachCurrentThreadIfNeeded();
   ScopedLocalRefFrame local_ref_frame(jni);
-  Java_VideoSink_onFrame(jni, *j_sink_,
-                         java_video_frame_factory_.ToJavaFrame(jni, frame));
+  Java_VideoSink_onFrame(jni, *j_sink_, NativeToJavaFrame(jni, frame));
 }
 
 }  // namespace