From 0371e10584728e3ca10531135601fc491ae2ab3b Mon Sep 17 00:00:00 2001 From: Magnus Jedvert Date: Tue, 7 Nov 2017 14:23:44 +0100 Subject: [PATCH] Android: Generate all C++ -> Java JNI code for VideoEncoder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Commit-Queue: Magnus Jedvert Cr-Commit-Position: refs/heads/master@{#20587} --- sdk/android/BUILD.gn | 4 +- sdk/android/api/org/webrtc/EncodedImage.java | 9 -- .../api/org/webrtc/VideoCodecStatus.java | 1 + .../java/org/webrtc/VideoEncoderWrapper.java | 80 +++++++++++++++++ .../webrtc/VideoEncoderWrapperCallback.java | 35 -------- sdk/android/src/jni/classreferenceholder.cc | 5 -- sdk/android/src/jni/videoencoderwrapper.cc | 90 ++++++------------- sdk/android/src/jni/videoencoderwrapper.h | 23 +---- 8 files changed, 110 insertions(+), 137 deletions(-) create mode 100644 sdk/android/src/java/org/webrtc/VideoEncoderWrapper.java delete mode 100644 sdk/android/src/java/org/webrtc/VideoEncoderWrapperCallback.java diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index b2bef9ed3cb..5bb7300ca5d 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -103,8 +103,10 @@ rtc_static_library("null_audio_jni") { 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 @@ android_library("libjingle_peerconnection_java") { "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 6720cd7f568..c6c56ce5324 100644 --- a/sdk/android/api/org/webrtc/EncodedImage.java +++ b/sdk/android/api/org/webrtc/EncodedImage.java @@ -33,15 +33,6 @@ private FrameType(int nativeIndex) { 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 3a7c81f0be3..a86d6fbf676 100644 --- a/sdk/android/api/org/webrtc/VideoCodecStatus.java +++ b/sdk/android/api/org/webrtc/VideoCodecStatus.java @@ -35,6 +35,7 @@ private VideoCodecStatus(int number) { 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 00000000000..6d7924a91e5 --- /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 0a8a8a686a3..00000000000 --- 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 e4ff16f88d2..0aa3e627a2d 100644 --- a/sdk/android/src/jni/classreferenceholder.cc +++ b/sdk/android/src/jni/classreferenceholder.cc @@ -111,11 +111,6 @@ ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni) { 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 7c76b4e33da..d85844c9752 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 @@ static const int kMaxJavaEncoderResets = 3; 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_, "", "(IIIIIZ)V"); - - encode_info_constructor_ = jni->GetMethodID( - *encode_info_class_, "", "([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_, "", "([[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 @@ int32_t VideoEncoderWrapper::InitEncodeInternal(JNIEnv* jni) { 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, "", "(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 @@ int32_t VideoEncoderWrapper::Encode( 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((*frame_types)[i])); + jobject j_frame_type = Java_VideoEncoderWrapper_createFrameType( + jni, static_cast((*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 @@ VideoEncoderWrapper::ScalingSettings VideoEncoderWrapper::GetScalingSettings() 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 @@ void VideoEncoderWrapper::OnEncodedFrame(JNIEnv* jni, 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 @@ void VideoEncoderWrapper::OnEncodedFrame(JNIEnv* jni, } 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 @@ jobject VideoEncoderWrapper::ToJavaBitrateAllocation( 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 @@ std::string VideoEncoderWrapper::GetImplementationName(JNIEnv* jni) const { } 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 866002afc4d..7717eb8e431 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 @@ class VideoEncoderWrapper : public VideoEncoder { std::string GetImplementationName(JNIEnv* jni) const; const ScopedGlobalRef encoder_; - const ScopedGlobalRef settings_class_; - const ScopedGlobalRef encode_info_class_; const ScopedGlobalRef frame_type_class_; - const ScopedGlobalRef bitrate_allocation_class_; const ScopedGlobalRef 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_;