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}
This commit is contained in:
Magnus Jedvert
2017-11-07 14:23:44 +01:00
committed by Commit Bot
parent aeb5d88dee
commit 0371e10584
8 changed files with 110 additions and 137 deletions

View File

@ -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",
]

View File

@ -33,15 +33,6 @@ public class EncodedImage {
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;

View File

@ -35,6 +35,7 @@ public enum VideoCodecStatus {
this.number = number;
}
@CalledByNative
public int getNumber() {
return number;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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");

View File

@ -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_, "<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 @@ 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,
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 @@ 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<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 @@ 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,

View File

@ -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<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_;