diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index 55091a27ff..8b14286dad 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -544,6 +544,7 @@ if (current_os == "linux" || is_android) { "src/jni/pc/audio.h", "src/jni/pc/logging.cc", "src/jni/pc/video.h", + "src/jni/scoped_java_ref_counted.cc", "src/jni/scoped_java_ref_counted.h", ] diff --git a/sdk/android/api/org/webrtc/EncodedImage.java b/sdk/android/api/org/webrtc/EncodedImage.java index 682d9c4fa0..fabf36a60e 100644 --- a/sdk/android/api/org/webrtc/EncodedImage.java +++ b/sdk/android/api/org/webrtc/EncodedImage.java @@ -71,6 +71,7 @@ public class EncodedImage implements RefCounted { // A false return value means that the encoder expects that the buffer is no longer used after // VideoEncoder.Callback.onEncodedFrame returns. + @CalledByNative boolean maybeRetain() { if (supportsRetain) { retain(); diff --git a/sdk/android/src/jni/encoded_image.cc b/sdk/android/src/jni/encoded_image.cc index 0cc0a5b901..5c97bdb19c 100644 --- a/sdk/android/src/jni/encoded_image.cc +++ b/sdk/android/src/jni/encoded_image.cc @@ -11,14 +11,42 @@ #include "sdk/android/src/jni/encoded_image.h" #include "api/video/encoded_image.h" +#include "rtc_base/ref_counted_object.h" #include "rtc_base/time_utils.h" #include "sdk/android/generated_video_jni/EncodedImage_jni.h" #include "sdk/android/native_api/jni/java_types.h" #include "sdk/android/src/jni/jni_helpers.h" +#include "sdk/android/src/jni/scoped_java_ref_counted.h" namespace webrtc { namespace jni { +namespace { + +class JavaEncodedImageBuffer : public EncodedImageBufferInterface { + public: + JavaEncodedImageBuffer(JNIEnv* env, + const JavaRef& j_encoded_image, + const uint8_t* payload, + size_t size) + : j_encoded_image_(ScopedJavaRefCounted::Adopt(env, j_encoded_image)), + data_(const_cast(payload)), + size_(size) {} + + const uint8_t* data() const override { return data_; } + uint8_t* data() override { return data_; } + size_t size() const override { return size_; } + + private: + // The Java object owning the buffer. + const ScopedJavaRefCounted j_encoded_image_; + + // TODO(bugs.webrtc.org/9378): Make const, and delete above const_cast. + uint8_t* const data_; + size_t const size_; +}; +} // namespace + ScopedJavaLocalRef NativeToJavaFrameType(JNIEnv* env, VideoFrameType frame_type) { return Java_FrameType_fromNativeIndex(env, static_cast(frame_type)); @@ -62,9 +90,14 @@ EncodedImage JavaToNativeEncodedImage(JNIEnv* env, const size_t buffer_size = env->GetDirectBufferCapacity(j_buffer.obj()); EncodedImage frame; - frame.Allocate(buffer_size); - frame.set_size(buffer_size); - memcpy(frame.data(), buffer, buffer_size); + if (Java_EncodedImage_maybeRetain(env, j_encoded_image)) { + frame.SetEncodedData(new rtc::RefCountedObject( + env, j_encoded_image, buffer, buffer_size)); + } else { + // Encoder doesn't support retain/release, so make a copy. + frame.SetEncodedData(EncodedImageBuffer::Create(buffer, buffer_size)); + } + frame._encodedWidth = Java_EncodedImage_getEncodedWidth(env, j_encoded_image); frame._encodedHeight = Java_EncodedImage_getEncodedHeight(env, j_encoded_image); diff --git a/sdk/android/src/jni/scoped_java_ref_counted.cc b/sdk/android/src/jni/scoped_java_ref_counted.cc new file mode 100644 index 0000000000..aa6d817225 --- /dev/null +++ b/sdk/android/src/jni/scoped_java_ref_counted.cc @@ -0,0 +1,28 @@ +/* + * Copyright 2019 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/scoped_java_ref_counted.h" + +#include "sdk/android/generated_base_jni/RefCounted_jni.h" + +namespace webrtc { +namespace jni { + +ScopedJavaRefCounted::~ScopedJavaRefCounted() { + if (!j_object_.is_null()) { + JNIEnv* jni = AttachCurrentThreadIfNeeded(); + Java_RefCounted_release(jni, j_object_); + CHECK_EXCEPTION(jni) + << "Unexpected java exception from ScopedJavaRefCounted.release()"; + } +} + +} // namespace jni +} // namespace webrtc diff --git a/sdk/android/src/jni/scoped_java_ref_counted.h b/sdk/android/src/jni/scoped_java_ref_counted.h index 33cc6eba7d..a5f7ae0e62 100644 --- a/sdk/android/src/jni/scoped_java_ref_counted.h +++ b/sdk/android/src/jni/scoped_java_ref_counted.h @@ -31,14 +31,7 @@ class ScopedJavaRefCounted { ScopedJavaRefCounted(const ScopedJavaRefCounted& other) = delete; ScopedJavaRefCounted& operator=(const ScopedJavaRefCounted&) = delete; - ~ScopedJavaRefCounted() { - if (!j_object_.is_null()) { - JNIEnv* jni = AttachCurrentThreadIfNeeded(); - Java_RefCounted_release(jni, j_object_); - CHECK_EXCEPTION(jni) - << "Unexpected java exception from ScopedJavaRefCounted.release()"; - } - } + ~ScopedJavaRefCounted(); private: // Adopts reference.