Android: Generate JNI code for VideoDecoder
Bug: webrtc:8278 Change-Id: I985fa63b0c5a9cdd0fb1817730646bcd4b30288a Reviewed-on: https://webrtc-review.googlesource.com/24221 Commit-Queue: Magnus Jedvert <magjed@webrtc.org> Reviewed-by: Sami Kalliomäki <sakal@webrtc.org> Cr-Commit-Position: refs/heads/master@{#20803}
This commit is contained in:
committed by
Commit Bot
parent
4171afb186
commit
4eb0188cb6
34
sdk/android/src/java/org/webrtc/VideoDecoderWrapper.java
Normal file
34
sdk/android/src/java/org/webrtc/VideoDecoderWrapper.java
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 org.webrtc.VideoDecoder;
|
||||
|
||||
/**
|
||||
* This class contains the Java glue code for JNI generation of VideoDecoder.
|
||||
*/
|
||||
class VideoDecoderWrapper {
|
||||
// TODO(bugs.webrtc.org/8551) Remove.
|
||||
@CalledByNative
|
||||
static VideoDecoder.Settings createSettings(int numberOfCores, int width, int height) {
|
||||
return new VideoDecoder.Settings(numberOfCores, width, height);
|
||||
}
|
||||
|
||||
@CalledByNative
|
||||
static VideoDecoder.Callback createDecoderCallback(final long nativeDecoder) {
|
||||
return (VideoFrame frame, Integer decodeTimeMs,
|
||||
Integer qp) -> nativeOnDecodedFrame(nativeDecoder, frame, decodeTimeMs, qp);
|
||||
}
|
||||
|
||||
@NativeClassQualifiedName("webrtc::jni::VideoDecoderWrapper")
|
||||
private static native void nativeOnDecodedFrame(
|
||||
long nativeDecoder, VideoFrame frame, Integer decodeTimeMs, Integer qp);
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 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;
|
||||
|
||||
/**
|
||||
* VideoDecoder callback that calls VideoDecoderWrapper.OnDecodedFrame for the decoded frames.
|
||||
*/
|
||||
class VideoDecoderWrapperCallback implements VideoDecoder.Callback {
|
||||
private final long nativeDecoder;
|
||||
|
||||
public VideoDecoderWrapperCallback(long nativeDecoder) {
|
||||
this.nativeDecoder = nativeDecoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDecodedFrame(VideoFrame frame, Integer decodeTimeMs, Integer qp) {
|
||||
nativeOnDecodedFrame(nativeDecoder, frame, decodeTimeMs, qp);
|
||||
}
|
||||
|
||||
private native static void nativeOnDecodedFrame(
|
||||
long nativeDecoder, VideoFrame frame, Integer decodeTimeMs, Integer qp);
|
||||
}
|
||||
@ -36,16 +36,6 @@ class VideoEncoderWrapper {
|
||||
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;
|
||||
|
||||
@ -113,8 +113,6 @@ ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni) {
|
||||
LoadClass(jni, "org/webrtc/VideoCapturer");
|
||||
LoadClass(jni, "org/webrtc/VideoCodecInfo");
|
||||
LoadClass(jni, "org/webrtc/VideoCodecStatus");
|
||||
LoadClass(jni, "org/webrtc/VideoDecoder$Settings");
|
||||
LoadClass(jni, "org/webrtc/VideoDecoderWrapperCallback");
|
||||
LoadClass(jni, "org/webrtc/VideoFrame");
|
||||
LoadClass(jni, "org/webrtc/VideoFrame$Buffer");
|
||||
LoadClass(jni, "org/webrtc/VideoFrame$I420Buffer");
|
||||
|
||||
35
sdk/android/src/jni/encodedimage.cc
Normal file
35
sdk/android/src/jni/encodedimage.cc
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 "sdk/android/src/jni/encodedimage.h"
|
||||
|
||||
#include "common_video/include/video_frame.h"
|
||||
#include "rtc_base/timeutils.h"
|
||||
#include "sdk/android/generated_video_jni/jni/EncodedImage_jni.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace jni {
|
||||
|
||||
jobject NativeToJavaFrameType(JNIEnv* env, FrameType frame_type) {
|
||||
return Java_FrameType_fromNativeIndex(env, frame_type);
|
||||
}
|
||||
|
||||
jobject NativeToJavaEncodedImage(JNIEnv* jni, const EncodedImage& image) {
|
||||
jobject buffer = jni->NewDirectByteBuffer(image._buffer, image._length);
|
||||
jobject frame_type = NativeToJavaFrameType(jni, image._frameType);
|
||||
jobject qp = (image.qp_ == -1) ? nullptr : JavaIntegerFromInt(jni, image.qp_);
|
||||
return Java_EncodedImage_create(
|
||||
jni, buffer, image._encodedWidth, image._encodedHeight,
|
||||
image.capture_time_ms_ * rtc::kNumNanosecsPerMillisec, frame_type,
|
||||
static_cast<jint>(image.rotation_), image._completeFrame, qp);
|
||||
}
|
||||
|
||||
} // namespace jni
|
||||
} // namespace webrtc
|
||||
31
sdk/android/src/jni/encodedimage.h
Normal file
31
sdk/android/src/jni/encodedimage.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SDK_ANDROID_SRC_JNI_ENCODEDIMAGE_H_
|
||||
#define SDK_ANDROID_SRC_JNI_ENCODEDIMAGE_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "api/video/video_rotation.h"
|
||||
#include "common_types.h" // NOLINT(build/include)
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class EncodedImage;
|
||||
|
||||
namespace jni {
|
||||
|
||||
jobject NativeToJavaFrameType(JNIEnv* env, FrameType frame_type);
|
||||
jobject NativeToJavaEncodedImage(JNIEnv* jni, const EncodedImage& image);
|
||||
|
||||
} // namespace jni
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // SDK_ANDROID_SRC_JNI_ENCODEDIMAGE_H_
|
||||
24
sdk/android/src/jni/videocodecstatus.cc
Normal file
24
sdk/android/src/jni/videocodecstatus.cc
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 "sdk/android/src/jni/videocodecstatus.h"
|
||||
|
||||
#include "sdk/android/generated_video_jni/jni/VideoCodecStatus_jni.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace jni {
|
||||
|
||||
int32_t JavaToNativeVideoCodecStatus(JNIEnv* env,
|
||||
jobject j_video_codec_status) {
|
||||
return Java_VideoCodecStatus_getNumber(env, j_video_codec_status);
|
||||
}
|
||||
|
||||
} // namespace jni
|
||||
} // namespace webrtc
|
||||
23
sdk/android/src/jni/videocodecstatus.h
Normal file
23
sdk/android/src/jni/videocodecstatus.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SDK_ANDROID_SRC_JNI_VIDEOCODECSTATUS_H_
|
||||
#define SDK_ANDROID_SRC_JNI_VIDEOCODECSTATUS_H_
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace webrtc {
|
||||
namespace jni {
|
||||
int32_t JavaToNativeVideoCodecStatus(JNIEnv* env, jobject j_video_codec_status);
|
||||
} // namespace jni
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // SDK_ANDROID_SRC_JNI_VIDEOCODECSTATUS_H_
|
||||
@ -15,9 +15,12 @@
|
||||
#include "modules/video_coding/utility/vp8_header_parser.h"
|
||||
#include "modules/video_coding/utility/vp9_uncompressed_header_parser.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/safe_conversions.h"
|
||||
#include "rtc_base/timeutils.h"
|
||||
#include "sdk/android/generated_video_jni/jni/VideoDecoderWrapper_jni.h"
|
||||
#include "sdk/android/generated_video_jni/jni/VideoDecoder_jni.h"
|
||||
#include "sdk/android/src/jni/classreferenceholder.h"
|
||||
#include "sdk/android/src/jni/encodedimage.h"
|
||||
#include "sdk/android/src/jni/videocodecstatus.h"
|
||||
#include "sdk/android/src/jni/videoframe.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace jni {
|
||||
@ -31,58 +34,13 @@ inline rtc::Optional<Dst> cast_optional(const rtc::Optional<Src>& value) {
|
||||
} // namespace
|
||||
|
||||
VideoDecoderWrapper::VideoDecoderWrapper(JNIEnv* jni, jobject decoder)
|
||||
: decoder_(jni, decoder),
|
||||
encoded_image_class_(jni, FindClass(jni, "org/webrtc/EncodedImage")),
|
||||
frame_type_class_(jni,
|
||||
FindClass(jni, "org/webrtc/EncodedImage$FrameType")),
|
||||
settings_class_(jni, FindClass(jni, "org/webrtc/VideoDecoder$Settings")),
|
||||
video_frame_class_(jni, FindClass(jni, "org/webrtc/VideoFrame")),
|
||||
video_codec_status_class_(jni,
|
||||
FindClass(jni, "org/webrtc/VideoCodecStatus")),
|
||||
integer_class_(jni, jni->FindClass("java/lang/Integer")) {
|
||||
encoded_image_constructor_ =
|
||||
jni->GetMethodID(*encoded_image_class_, "<init>",
|
||||
"(Ljava/nio/ByteBuffer;IIJLorg/webrtc/"
|
||||
"EncodedImage$FrameType;IZLjava/lang/Integer;)V");
|
||||
settings_constructor_ =
|
||||
jni->GetMethodID(*settings_class_, "<init>", "(III)V");
|
||||
|
||||
empty_frame_field_ = jni->GetStaticFieldID(
|
||||
*frame_type_class_, "EmptyFrame", "Lorg/webrtc/EncodedImage$FrameType;");
|
||||
video_frame_key_field_ =
|
||||
jni->GetStaticFieldID(*frame_type_class_, "VideoFrameKey",
|
||||
"Lorg/webrtc/EncodedImage$FrameType;");
|
||||
video_frame_delta_field_ =
|
||||
jni->GetStaticFieldID(*frame_type_class_, "VideoFrameDelta",
|
||||
"Lorg/webrtc/EncodedImage$FrameType;");
|
||||
|
||||
video_frame_get_timestamp_ns_method_ =
|
||||
jni->GetMethodID(*video_frame_class_, "getTimestampNs", "()J");
|
||||
|
||||
jclass decoder_class = jni->GetObjectClass(decoder);
|
||||
init_decode_method_ =
|
||||
jni->GetMethodID(decoder_class, "initDecode",
|
||||
"(Lorg/webrtc/VideoDecoder$Settings;Lorg/webrtc/"
|
||||
"VideoDecoder$Callback;)Lorg/webrtc/VideoCodecStatus;");
|
||||
release_method_ = jni->GetMethodID(decoder_class, "release",
|
||||
"()Lorg/webrtc/VideoCodecStatus;");
|
||||
decode_method_ = jni->GetMethodID(decoder_class, "decode",
|
||||
"(Lorg/webrtc/EncodedImage;Lorg/webrtc/"
|
||||
"VideoDecoder$DecodeInfo;)Lorg/webrtc/"
|
||||
"VideoCodecStatus;");
|
||||
get_prefers_late_decoding_method_ =
|
||||
jni->GetMethodID(decoder_class, "getPrefersLateDecoding", "()Z");
|
||||
get_implementation_name_method_ = jni->GetMethodID(
|
||||
decoder_class, "getImplementationName", "()Ljava/lang/String;");
|
||||
|
||||
get_number_method_ =
|
||||
jni->GetMethodID(*video_codec_status_class_, "getNumber", "()I");
|
||||
|
||||
: decoder_(jni, decoder) {
|
||||
initialized_ = false;
|
||||
// QP parsing starts enabled and we disable it if the decoder provides frames.
|
||||
qp_parsing_enabled_ = true;
|
||||
|
||||
implementation_name_ = GetImplementationName(jni);
|
||||
implementation_name_ = JavaToStdString(
|
||||
jni, Java_VideoDecoder_getImplementationName(jni, decoder));
|
||||
}
|
||||
|
||||
int32_t VideoDecoderWrapper::InitDecode(const VideoCodec* codec_settings,
|
||||
@ -96,20 +54,15 @@ int32_t VideoDecoderWrapper::InitDecode(const VideoCodec* codec_settings,
|
||||
}
|
||||
|
||||
int32_t VideoDecoderWrapper::InitDecodeInternal(JNIEnv* jni) {
|
||||
jobject settings =
|
||||
jni->NewObject(*settings_class_, settings_constructor_, number_of_cores_,
|
||||
codec_settings_.width, codec_settings_.height);
|
||||
jobject settings = Java_VideoDecoderWrapper_createSettings(
|
||||
jni, number_of_cores_, codec_settings_.width, codec_settings_.height);
|
||||
|
||||
jclass callback_class =
|
||||
FindClass(jni, "org/webrtc/VideoDecoderWrapperCallback");
|
||||
jmethodID callback_constructor =
|
||||
jni->GetMethodID(callback_class, "<init>", "(J)V");
|
||||
jobject callback = jni->NewObject(callback_class, callback_constructor,
|
||||
jlongFromPointer(this));
|
||||
jobject callback = Java_VideoDecoderWrapper_createDecoderCallback(
|
||||
jni, jlongFromPointer(this));
|
||||
|
||||
jobject ret =
|
||||
jni->CallObjectMethod(*decoder_, init_decode_method_, settings, callback);
|
||||
if (jni->CallIntMethod(ret, get_number_method_) == WEBRTC_VIDEO_CODEC_OK) {
|
||||
Java_VideoDecoder_initDecode(jni, *decoder_, settings, callback);
|
||||
if (JavaToNativeVideoCodecStatus(jni, ret) == WEBRTC_VIDEO_CODEC_OK) {
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
@ -142,10 +95,8 @@ int32_t VideoDecoderWrapper::Decode(
|
||||
qp_parsing_enabled_ ? ParseQP(input_image) : rtc::nullopt;
|
||||
frame_extra_infos_.push_back(frame_extra_info);
|
||||
|
||||
jobject jinput_image =
|
||||
ConvertEncodedImageToJavaEncodedImage(jni, input_image);
|
||||
jobject ret =
|
||||
jni->CallObjectMethod(*decoder_, decode_method_, jinput_image, nullptr);
|
||||
jobject jinput_image = NativeToJavaEncodedImage(jni, input_image);
|
||||
jobject ret = Java_VideoDecoder_decode(jni, *decoder_, jinput_image, nullptr);
|
||||
return HandleReturnCode(jni, ret);
|
||||
}
|
||||
|
||||
@ -158,7 +109,7 @@ int32_t VideoDecoderWrapper::RegisterDecodeCompleteCallback(
|
||||
int32_t VideoDecoderWrapper::Release() {
|
||||
JNIEnv* jni = AttachCurrentThreadIfNeeded();
|
||||
ScopedLocalRefFrame local_ref_frame(jni);
|
||||
jobject ret = jni->CallObjectMethod(*decoder_, release_method_);
|
||||
jobject ret = Java_VideoDecoder_release(jni, *decoder_);
|
||||
frame_extra_infos_.clear();
|
||||
initialized_ = false;
|
||||
return HandleReturnCode(jni, ret);
|
||||
@ -166,19 +117,20 @@ int32_t VideoDecoderWrapper::Release() {
|
||||
|
||||
bool VideoDecoderWrapper::PrefersLateDecoding() const {
|
||||
JNIEnv* jni = AttachCurrentThreadIfNeeded();
|
||||
return jni->CallBooleanMethod(*decoder_, get_prefers_late_decoding_method_);
|
||||
return Java_VideoDecoder_getPrefersLateDecoding(jni, *decoder_);
|
||||
}
|
||||
|
||||
const char* VideoDecoderWrapper::ImplementationName() const {
|
||||
return implementation_name_.c_str();
|
||||
}
|
||||
|
||||
void VideoDecoderWrapper::OnDecodedFrame(JNIEnv* jni,
|
||||
jobject jframe,
|
||||
jobject jdecode_time_ms,
|
||||
jobject jqp) {
|
||||
const jlong capture_time_ns =
|
||||
jni->CallLongMethod(jframe, video_frame_get_timestamp_ns_method_);
|
||||
void VideoDecoderWrapper::OnDecodedFrame(JNIEnv* env,
|
||||
jobject j_caller,
|
||||
jobject j_frame,
|
||||
jobject j_decode_time_ms,
|
||||
jobject j_qp) {
|
||||
const uint64_t capture_time_ns = GetJavaVideoFrameTimestampNs(env, j_frame);
|
||||
|
||||
FrameExtraInfo frame_extra_info;
|
||||
do {
|
||||
if (frame_extra_infos_.empty()) {
|
||||
@ -193,13 +145,13 @@ void VideoDecoderWrapper::OnDecodedFrame(JNIEnv* jni,
|
||||
} while (frame_extra_info.capture_time_ns != capture_time_ns);
|
||||
|
||||
VideoFrame frame =
|
||||
JavaToNativeFrame(jni, jframe, frame_extra_info.timestamp_rtp);
|
||||
JavaToNativeFrame(env, j_frame, frame_extra_info.timestamp_rtp);
|
||||
|
||||
rtc::Optional<int32_t> decoding_time_ms =
|
||||
JavaIntegerToOptionalInt(jni, jdecode_time_ms);
|
||||
JavaIntegerToOptionalInt(env, j_decode_time_ms);
|
||||
|
||||
rtc::Optional<uint8_t> decoder_qp =
|
||||
cast_optional<uint8_t, int32_t>(JavaIntegerToOptionalInt(jni, jqp));
|
||||
cast_optional<uint8_t, int32_t>(JavaIntegerToOptionalInt(env, j_qp));
|
||||
// If the decoder provides QP values itself, no need to parse the bitstream.
|
||||
// Enable QP parsing if decoder does not provide QP values itself.
|
||||
qp_parsing_enabled_ = !decoder_qp.has_value();
|
||||
@ -207,41 +159,8 @@ void VideoDecoderWrapper::OnDecodedFrame(JNIEnv* jni,
|
||||
decoder_qp ? decoder_qp : frame_extra_info.qp);
|
||||
}
|
||||
|
||||
jobject VideoDecoderWrapper::ConvertEncodedImageToJavaEncodedImage(
|
||||
JNIEnv* jni,
|
||||
const EncodedImage& image) {
|
||||
jobject buffer = jni->NewDirectByteBuffer(image._buffer, image._length);
|
||||
jfieldID frame_type_field;
|
||||
switch (image._frameType) {
|
||||
case kEmptyFrame:
|
||||
frame_type_field = empty_frame_field_;
|
||||
break;
|
||||
case kVideoFrameKey:
|
||||
frame_type_field = video_frame_key_field_;
|
||||
break;
|
||||
case kVideoFrameDelta:
|
||||
frame_type_field = video_frame_delta_field_;
|
||||
break;
|
||||
default:
|
||||
RTC_NOTREACHED();
|
||||
return nullptr;
|
||||
}
|
||||
jobject frame_type =
|
||||
jni->GetStaticObjectField(*frame_type_class_, frame_type_field);
|
||||
jobject qp = nullptr;
|
||||
if (image.qp_ != -1) {
|
||||
qp = JavaIntegerFromInt(jni, image.qp_);
|
||||
}
|
||||
return jni->NewObject(
|
||||
*encoded_image_class_, encoded_image_constructor_, buffer,
|
||||
static_cast<jint>(image._encodedWidth),
|
||||
static_cast<jint>(image._encodedHeight),
|
||||
static_cast<jlong>(image.capture_time_ms_ * rtc::kNumNanosecsPerMillisec),
|
||||
frame_type, static_cast<jint>(image.rotation_), image._completeFrame, qp);
|
||||
}
|
||||
|
||||
int32_t VideoDecoderWrapper::HandleReturnCode(JNIEnv* jni, jobject code) {
|
||||
int32_t value = jni->CallIntMethod(code, get_number_method_);
|
||||
int32_t value = JavaToNativeVideoCodecStatus(jni, code);
|
||||
if (value < 0) { // Any errors are represented by negative values.
|
||||
// Reset the codec.
|
||||
if (Release() == WEBRTC_VIDEO_CODEC_OK) {
|
||||
@ -292,24 +211,5 @@ rtc::Optional<uint8_t> VideoDecoderWrapper::ParseQP(
|
||||
return qp;
|
||||
}
|
||||
|
||||
std::string VideoDecoderWrapper::GetImplementationName(JNIEnv* jni) const {
|
||||
jstring jname = reinterpret_cast<jstring>(
|
||||
jni->CallObjectMethod(*decoder_, get_implementation_name_method_));
|
||||
return JavaToStdString(jni, jname);
|
||||
}
|
||||
|
||||
JNI_FUNCTION_DECLARATION(void,
|
||||
VideoDecoderWrapperCallback_nativeOnDecodedFrame,
|
||||
JNIEnv* jni,
|
||||
jclass,
|
||||
jlong jnative_decoder,
|
||||
jobject jframe,
|
||||
jobject jdecode_time_ms,
|
||||
jobject jqp) {
|
||||
VideoDecoderWrapper* native_decoder =
|
||||
reinterpret_cast<VideoDecoderWrapper*>(jnative_decoder);
|
||||
native_decoder->OnDecodedFrame(jni, jframe, jdecode_time_ms, jqp);
|
||||
}
|
||||
|
||||
} // namespace jni
|
||||
} // namespace webrtc
|
||||
|
||||
@ -17,14 +17,11 @@
|
||||
#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/videoframe.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace jni {
|
||||
|
||||
// Wraps a Java decoder and delegates all calls to it. Passes
|
||||
// VideoDecoderWrapperCallback to the decoder on InitDecode. Wraps the received
|
||||
// frames to AndroidVideoBuffer.
|
||||
// Wraps a Java decoder and delegates all calls to it.
|
||||
class VideoDecoderWrapper : public VideoDecoder {
|
||||
public:
|
||||
VideoDecoderWrapper(JNIEnv* jni, jobject decoder);
|
||||
@ -51,10 +48,11 @@ class VideoDecoderWrapper : public VideoDecoder {
|
||||
const char* ImplementationName() const override;
|
||||
|
||||
// Wraps the frame to a AndroidVideoBuffer and passes it to the callback.
|
||||
void OnDecodedFrame(JNIEnv* jni,
|
||||
jobject jframe,
|
||||
jobject jdecode_time_ms,
|
||||
jobject jqp);
|
||||
void OnDecodedFrame(JNIEnv* env,
|
||||
jobject j_caller,
|
||||
jobject j_frame,
|
||||
jobject j_decode_time_ms,
|
||||
jobject j_qp);
|
||||
|
||||
private:
|
||||
struct FrameExtraInfo {
|
||||
@ -72,8 +70,6 @@ class VideoDecoderWrapper : public VideoDecoder {
|
||||
|
||||
rtc::Optional<uint8_t> ParseQP(const EncodedImage& input_image);
|
||||
|
||||
std::string GetImplementationName(JNIEnv* jni) const;
|
||||
|
||||
VideoCodec codec_settings_;
|
||||
int32_t number_of_cores_;
|
||||
|
||||
@ -86,32 +82,6 @@ class VideoDecoderWrapper : public VideoDecoder {
|
||||
DecodedImageCallback* callback_;
|
||||
|
||||
const ScopedGlobalRef<jobject> decoder_;
|
||||
const ScopedGlobalRef<jclass> encoded_image_class_;
|
||||
const ScopedGlobalRef<jclass> frame_type_class_;
|
||||
const ScopedGlobalRef<jclass> settings_class_;
|
||||
const ScopedGlobalRef<jclass> video_frame_class_;
|
||||
const ScopedGlobalRef<jclass> video_codec_status_class_;
|
||||
const ScopedGlobalRef<jclass> integer_class_;
|
||||
|
||||
jmethodID encoded_image_constructor_;
|
||||
jmethodID settings_constructor_;
|
||||
|
||||
jfieldID empty_frame_field_;
|
||||
jfieldID video_frame_key_field_;
|
||||
jfieldID video_frame_delta_field_;
|
||||
|
||||
jmethodID video_frame_get_timestamp_ns_method_;
|
||||
|
||||
jmethodID init_decode_method_;
|
||||
jmethodID release_method_;
|
||||
jmethodID decode_method_;
|
||||
jmethodID get_prefers_late_decoding_method_;
|
||||
jmethodID get_implementation_name_method_;
|
||||
|
||||
jmethodID get_number_method_;
|
||||
|
||||
jobject ConvertEncodedImageToJavaEncodedImage(JNIEnv* jni,
|
||||
const EncodedImage& image);
|
||||
};
|
||||
|
||||
} // namespace jni
|
||||
|
||||
@ -21,10 +21,11 @@
|
||||
#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/class_loader.h"
|
||||
#include "sdk/android/src/jni/encodedimage.h"
|
||||
#include "sdk/android/src/jni/videocodecstatus.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace jni {
|
||||
@ -84,7 +85,7 @@ int32_t VideoEncoderWrapper::InitEncodeInternal(JNIEnv* jni) {
|
||||
jobject ret =
|
||||
Java_VideoEncoder_initEncode(jni, *encoder_, settings, callback);
|
||||
|
||||
if (Java_VideoCodecStatus_getNumber(jni, ret) == WEBRTC_VIDEO_CODEC_OK) {
|
||||
if (JavaToNativeVideoCodecStatus(jni, ret) == WEBRTC_VIDEO_CODEC_OK) {
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
@ -123,8 +124,7 @@ 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 = Java_VideoEncoderWrapper_createFrameType(
|
||||
jni, static_cast<jint>((*frame_types)[i]));
|
||||
jobject j_frame_type = NativeToJavaFrameType(jni, (*frame_types)[i]);
|
||||
jni->SetObjectArrayElement(j_frame_types, i, j_frame_type);
|
||||
}
|
||||
jobject encode_info =
|
||||
@ -245,7 +245,7 @@ void VideoEncoderWrapper::OnEncodedFrame(JNIEnv* jni,
|
||||
}
|
||||
|
||||
int32_t VideoEncoderWrapper::HandleReturnCode(JNIEnv* jni, jobject code) {
|
||||
int32_t value = Java_VideoCodecStatus_getNumber(jni, code);
|
||||
int32_t value = JavaToNativeVideoCodecStatus(jni, code);
|
||||
if (value < 0) { // Any errors are represented by negative values.
|
||||
// Try resetting the codec.
|
||||
if (++num_resets_ <= kMaxJavaEncoderResets &&
|
||||
|
||||
@ -109,6 +109,10 @@ AndroidVideoI420Buffer::~AndroidVideoI420Buffer() {
|
||||
|
||||
} // namespace
|
||||
|
||||
int64_t GetJavaVideoFrameTimestampNs(JNIEnv* jni, jobject j_video_frame) {
|
||||
return Java_VideoFrame_getTimestampNs(jni, j_video_frame);
|
||||
}
|
||||
|
||||
Matrix::Matrix(JNIEnv* jni, jfloatArray a) {
|
||||
RTC_CHECK_EQ(16, jni->GetArrayLength(a));
|
||||
jfloat* ptr = jni->GetFloatArrayElements(a, nullptr);
|
||||
@ -366,7 +370,7 @@ VideoFrame JavaToNativeFrame(JNIEnv* jni,
|
||||
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);
|
||||
int64_t timestamp_ns = Java_VideoFrame_getTimestampNs(jni, j_video_frame);
|
||||
rtc::scoped_refptr<AndroidVideoBuffer> buffer =
|
||||
AndroidVideoBuffer::Create(jni, j_video_frame_buffer);
|
||||
return VideoFrame(buffer, timestamp_rtp,
|
||||
|
||||
@ -159,6 +159,8 @@ VideoFrame JavaToNativeFrame(JNIEnv* jni,
|
||||
|
||||
jobject NativeToJavaFrame(JNIEnv* jni, const VideoFrame& frame);
|
||||
|
||||
int64_t GetJavaVideoFrameTimestampNs(JNIEnv* jni, jobject j_video_frame);
|
||||
|
||||
} // namespace jni
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
Reference in New Issue
Block a user