Skip to content

Commit

Permalink
Android: Generate all C++ -> Java JNI code for VideoEncoder
Browse files Browse the repository at this point in the history
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 <[email protected]>
Commit-Queue: Magnus Jedvert <[email protected]>
Cr-Commit-Position: refs/heads/master@{#20587}
  • Loading branch information
Hnoo112233 authored and Commit Bot committed Nov 7, 2017
1 parent aeb5d88 commit 0371e10
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 137 deletions.
4 changes: 3 additions & 1 deletion sdk/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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",
]

Expand Down
9 changes: 0 additions & 9 deletions sdk/android/api/org/webrtc/EncodedImage.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions sdk/android/api/org/webrtc/VideoCodecStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ private VideoCodecStatus(int number) {
this.number = number;
}

@CalledByNative
public int getNumber() {
return number;
}
Expand Down
80 changes: 80 additions & 0 deletions sdk/android/src/java/org/webrtc/VideoEncoderWrapper.java
Original file line number Diff line number Diff line change
@@ -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);
}
35 changes: 0 additions & 35 deletions sdk/android/src/java/org/webrtc/VideoEncoderWrapperCallback.java

This file was deleted.

5 changes: 0 additions & 5 deletions sdk/android/src/jni/classreferenceholder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
90 changes: 25 additions & 65 deletions sdk/android/src/jni/videoencoderwrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -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, "<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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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 &&
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
Expand Down
23 changes: 1 addition & 22 deletions sdk/android/src/jni/videoencoderwrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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_;
Expand Down

0 comments on commit 0371e10

Please sign in to comment.