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:
committed by
Commit Bot
parent
aeb5d88dee
commit
0371e10584
@ -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",
|
||||
]
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -35,6 +35,7 @@ public enum VideoCodecStatus {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
@CalledByNative
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
80
sdk/android/src/java/org/webrtc/VideoEncoderWrapper.java
Normal file
80
sdk/android/src/java/org/webrtc/VideoEncoderWrapper.java
Normal 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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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");
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user