From c2ac3c663f679578271838823ee34a30d51d032d Mon Sep 17 00:00:00 2001 From: Magnus Jedvert Date: Tue, 14 Nov 2017 17:08:59 +0100 Subject: [PATCH] Android: Annotate and generate JNI code for VideoFrame.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL also merged native_handle_impl.cc and videoframe_jni.cc to keep all JNI code for the same Java class in the same file, and also renames this file to jni/videoframe.cc. The classes AndroidVideoBufferFactory and JavaVideoFrameFactory are now unnecessary since we cache everything and can be simplified to global static functions instead. Bug: webrtc:8278 Change-Id: I03d7b0bbde64cfb407cd6210478ddf9d5599cd8c Reviewed-on: https://webrtc-review.googlesource.com/22923 Commit-Queue: Magnus Jedvert Reviewed-by: Sami Kalliomäki Cr-Commit-Position: refs/heads/master@{#20677} --- sdk/android/BUILD.gn | 6 +- sdk/android/api/org/webrtc/VideoFrame.java | 35 ++- .../src/java/org/webrtc/CalledByNative.java | 7 +- .../src/jni/androidmediadecoder_jni.cc | 8 +- .../src/jni/androidmediaencoder_jni.cc | 16 +- .../src/jni/androidvideotracksource.cc | 3 +- sdk/android/src/jni/androidvideotracksource.h | 3 +- .../src/jni/surfacetexturehelper_jni.h | 2 +- sdk/android/src/jni/video_renderer_jni.cc | 2 +- sdk/android/src/jni/videodecoderwrapper.cc | 7 +- sdk/android/src/jni/videodecoderwrapper.h | 3 +- sdk/android/src/jni/videoencoderwrapper.cc | 6 +- sdk/android/src/jni/videoencoderwrapper.h | 3 +- .../{native_handle_impl.cc => videoframe.cc} | 262 +++++++----------- .../{native_handle_impl.h => videoframe.h} | 84 ++---- sdk/android/src/jni/videoframe_jni.cc | 64 ----- sdk/android/src/jni/videotrack_jni.cc | 8 +- 17 files changed, 170 insertions(+), 349 deletions(-) rename sdk/android/src/jni/{native_handle_impl.cc => videoframe.cc} (60%) rename sdk/android/src/jni/{native_handle_impl.h => videoframe.h} (63%) delete mode 100644 sdk/android/src/jni/videoframe_jni.cc diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index e1b9a60a6e..e1c4df2e64 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -106,6 +106,7 @@ generate_jni("generated_video_jni") { "api/org/webrtc/SurfaceTextureHelper.java", "api/org/webrtc/VideoCodecStatus.java", "api/org/webrtc/VideoEncoder.java", + "api/org/webrtc/VideoFrame.java", "api/org/webrtc/VideoSink.java", "src/java/org/webrtc/VideoEncoderWrapper.java", "src/java/org/webrtc/WrappedNativeVideoDecoder.java", @@ -127,8 +128,6 @@ rtc_static_library("video_jni") { "src/jni/androidvideotracksource_jni.cc", "src/jni/defaultvideoencoderfactory.cc", "src/jni/jni_generator_helper.h", - "src/jni/native_handle_impl.cc", - "src/jni/native_handle_impl.h", "src/jni/nv12buffer_jni.cc", "src/jni/nv21buffer_jni.cc", "src/jni/pc/video_jni.cc", @@ -147,7 +146,8 @@ rtc_static_library("video_jni") { "src/jni/videoencoderwrapper.cc", "src/jni/videoencoderwrapper.h", "src/jni/videofilerenderer_jni.cc", - "src/jni/videoframe_jni.cc", + "src/jni/videoframe.cc", + "src/jni/videoframe.h", "src/jni/videotrack_jni.cc", "src/jni/vp8codec.cc", "src/jni/vp9codec.cc", diff --git a/sdk/android/api/org/webrtc/VideoFrame.java b/sdk/android/api/org/webrtc/VideoFrame.java index da9542b3af..0a5a67e04e 100644 --- a/sdk/android/api/org/webrtc/VideoFrame.java +++ b/sdk/android/api/org/webrtc/VideoFrame.java @@ -30,22 +30,22 @@ public class VideoFrame { /** * Resolution of the buffer in pixels. */ - int getWidth(); - int getHeight(); + @CalledByNative("Buffer") int getWidth(); + @CalledByNative("Buffer") int getHeight(); /** * Returns a memory-backed frame in I420 format. If the pixel data is in another format, a * conversion will take place. All implementations must provide a fallback to I420 for * compatibility with e.g. the internal WebRTC software encoders. */ - I420Buffer toI420(); + @CalledByNative("Buffer") I420Buffer toI420(); /** * Reference counting is needed since a video buffer can be shared between multiple VideoSinks, * and the buffer needs to be returned to the VideoSource as soon as all references are gone. */ - void retain(); - void release(); + @CalledByNative("Buffer") void retain(); + @CalledByNative("Buffer") void release(); /** * Crops a region defined by |cropx|, |cropY|, |cropWidth| and |cropHeight|. Scales it to size @@ -65,25 +65,25 @@ public class VideoFrame { * be 0. Callers may mutate the ByteBuffer (eg. through relative-read operations), so * implementations must return a new ByteBuffer or slice for each call. */ - ByteBuffer getDataY(); + @CalledByNative("I420Buffer") ByteBuffer getDataY(); /** * Returns a direct ByteBuffer containing U-plane data. The buffer capacity is at least * getStrideU() * ((getHeight() + 1) / 2) bytes. The position of the returned buffer is ignored * and must be 0. Callers may mutate the ByteBuffer (eg. through relative-read operations), so * implementations must return a new ByteBuffer or slice for each call. */ - ByteBuffer getDataU(); + @CalledByNative("I420Buffer") ByteBuffer getDataU(); /** * Returns a direct ByteBuffer containing V-plane data. The buffer capacity is at least * getStrideV() * ((getHeight() + 1) / 2) bytes. The position of the returned buffer is ignored * and must be 0. Callers may mutate the ByteBuffer (eg. through relative-read operations), so * implementations must return a new ByteBuffer or slice for each call. */ - ByteBuffer getDataV(); + @CalledByNative("I420Buffer") ByteBuffer getDataV(); - int getStrideY(); - int getStrideU(); - int getStrideV(); + @CalledByNative("I420Buffer") int getStrideY(); + @CalledByNative("I420Buffer") int getStrideU(); + @CalledByNative("I420Buffer") int getStrideV(); } /** @@ -132,6 +132,7 @@ public class VideoFrame { this.timestampNs = timestampNs; } + @CalledByNative public Buffer getBuffer() { return buffer; } @@ -139,6 +140,7 @@ public class VideoFrame { /** * Rotation of the frame in degrees. */ + @CalledByNative public int getRotation() { return rotation; } @@ -146,6 +148,7 @@ public class VideoFrame { /** * Timestamp of the frame in nano seconds. */ + @CalledByNative public long getTimestampNs() { return timestampNs; } @@ -194,7 +197,7 @@ public class VideoFrame { } JavaI420Buffer newBuffer = JavaI420Buffer.allocate(scaleWidth, scaleHeight); - nativeCropAndScaleI420(buffer.getDataY(), buffer.getStrideY(), buffer.getDataU(), + cropAndScaleI420Native(buffer.getDataY(), buffer.getStrideY(), buffer.getDataU(), buffer.getStrideU(), buffer.getDataV(), buffer.getStrideV(), cropX, cropY, cropWidth, cropHeight, newBuffer.getDataY(), newBuffer.getStrideY(), newBuffer.getDataU(), newBuffer.getStrideU(), newBuffer.getDataV(), newBuffer.getStrideV(), scaleWidth, @@ -202,7 +205,13 @@ public class VideoFrame { return newBuffer; } - private static native void nativeCropAndScaleI420(ByteBuffer srcY, int srcStrideY, + // TODO(bugs.webrtc.org/8278): Add a way to generate JNI code for constructors directly. + @CalledByNative + static VideoFrame create(Buffer buffer, int rotation, long timestampNs) { + return new VideoFrame(buffer, rotation, timestampNs); + } + + private static native void cropAndScaleI420Native(ByteBuffer srcY, int srcStrideY, ByteBuffer srcU, int srcStrideU, ByteBuffer srcV, int srcStrideV, int cropX, int cropY, int cropWidth, int cropHeight, ByteBuffer dstY, int dstStrideY, ByteBuffer dstU, int dstStrideU, ByteBuffer dstV, int dstStrideV, int scaleWidth, int scaleHeight); diff --git a/sdk/android/src/java/org/webrtc/CalledByNative.java b/sdk/android/src/java/org/webrtc/CalledByNative.java index 7e08328e27..42487ff772 100644 --- a/sdk/android/src/java/org/webrtc/CalledByNative.java +++ b/sdk/android/src/java/org/webrtc/CalledByNative.java @@ -21,4 +21,9 @@ import java.lang.annotation.Target; */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.CLASS) -@interface CalledByNative {} +@interface CalledByNative { + /* + * If present, tells which inner class the method belongs to. + */ + public String value() default ""; +} diff --git a/sdk/android/src/jni/androidmediadecoder_jni.cc b/sdk/android/src/jni/androidmediadecoder_jni.cc index 344a4ca0b5..613bb54cd0 100644 --- a/sdk/android/src/jni/androidmediadecoder_jni.cc +++ b/sdk/android/src/jni/androidmediadecoder_jni.cc @@ -17,9 +17,6 @@ // androidmediacodeccommon.h to avoid build errors. #include "sdk/android/src/jni/androidmediadecoder_jni.h" -#include "third_party/libyuv/include/libyuv/convert.h" -#include "third_party/libyuv/include/libyuv/convert_from.h" -#include "third_party/libyuv/include/libyuv/video_common.h" #include "common_video/h264/h264_bitstream_parser.h" #include "common_video/include/i420_buffer_pool.h" #include "modules/video_coding/include/video_codec_interface.h" @@ -32,8 +29,11 @@ #include "rtc_base/timeutils.h" #include "sdk/android/src/jni/androidmediacodeccommon.h" #include "sdk/android/src/jni/classreferenceholder.h" -#include "sdk/android/src/jni/native_handle_impl.h" #include "sdk/android/src/jni/surfacetexturehelper_jni.h" +#include "sdk/android/src/jni/videoframe.h" +#include "third_party/libyuv/include/libyuv/convert.h" +#include "third_party/libyuv/include/libyuv/convert_from.h" +#include "third_party/libyuv/include/libyuv/video_common.h" using rtc::Bind; using rtc::Thread; diff --git a/sdk/android/src/jni/androidmediaencoder_jni.cc b/sdk/android/src/jni/androidmediaencoder_jni.cc index a7d528d487..1b8c4d987c 100644 --- a/sdk/android/src/jni/androidmediaencoder_jni.cc +++ b/sdk/android/src/jni/androidmediaencoder_jni.cc @@ -18,9 +18,6 @@ #include #include -#include "third_party/libyuv/include/libyuv/convert.h" -#include "third_party/libyuv/include/libyuv/convert_from.h" -#include "third_party/libyuv/include/libyuv/video_common.h" #include "api/video_codecs/video_encoder.h" #include "common_types.h" // NOLINT(build/include) #include "common_video/h264/h264_bitstream_parser.h" @@ -43,8 +40,11 @@ #include "sdk/android/src/jni/androidmediacodeccommon.h" #include "sdk/android/src/jni/classreferenceholder.h" #include "sdk/android/src/jni/jni_helpers.h" -#include "sdk/android/src/jni/native_handle_impl.h" +#include "sdk/android/src/jni/videoframe.h" #include "system_wrappers/include/field_trial.h" +#include "third_party/libyuv/include/libyuv/convert.h" +#include "third_party/libyuv/include/libyuv/convert_from.h" +#include "third_party/libyuv/include/libyuv/video_common.h" using rtc::Bind; using rtc::Thread; @@ -230,7 +230,6 @@ class MediaCodecVideoEncoder : public VideoEncoder { jfieldID j_info_is_key_frame_field_; jfieldID j_info_presentation_timestamp_us_field_; - const JavaVideoFrameFactory video_frame_factory_; ScopedGlobalRef j_video_frame_texture_buffer_class_; // State that is valid only between InitEncode() and the next Release(). @@ -342,7 +341,6 @@ MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni, *j_media_codec_video_encoder_class_, "", "()V"))), - video_frame_factory_(jni), j_video_frame_texture_buffer_class_( jni, FindClass(jni, "org/webrtc/VideoFrame$TextureBuffer")), @@ -801,9 +799,9 @@ int32_t MediaCodecVideoEncoder::Encode( encode_status = EncodeTexture(jni, key_frame, input_frame); break; case AndroidVideoFrameBuffer::AndroidType::kJavaBuffer: - encode_status = EncodeJavaFrame( - jni, key_frame, video_frame_factory_.ToJavaFrame(jni, input_frame), - j_input_buffer_index); + encode_status = + EncodeJavaFrame(jni, key_frame, NativeToJavaFrame(jni, input_frame), + j_input_buffer_index); break; default: RTC_NOTREACHED(); diff --git a/sdk/android/src/jni/androidvideotracksource.cc b/sdk/android/src/jni/androidvideotracksource.cc index 3913ed036c..ba31f7e6de 100644 --- a/sdk/android/src/jni/androidvideotracksource.cc +++ b/sdk/android/src/jni/androidvideotracksource.cc @@ -33,7 +33,6 @@ AndroidVideoTrackSource::AndroidVideoTrackSource( surface_texture_helper_(new rtc::RefCountedObject( jni, j_surface_texture_helper)), - video_buffer_factory_(jni), is_screencast_(is_screencast) { RTC_LOG(LS_INFO) << "AndroidVideoTrackSource ctor"; camera_thread_checker_.DetachFromThread(); @@ -189,7 +188,7 @@ void AndroidVideoTrackSource::OnFrameCaptured(JNIEnv* jni, crop_height, adapted_width, adapted_height); rtc::scoped_refptr buffer = - video_buffer_factory_.WrapBuffer(jni, j_adapted_video_frame_buffer); + AndroidVideoBuffer::Adopt(jni, j_adapted_video_frame_buffer); // AdaptedVideoTrackSource handles applying rotation for I420 frames. if (apply_rotation() && rotation != kVideoRotation_0) { diff --git a/sdk/android/src/jni/androidvideotracksource.h b/sdk/android/src/jni/androidvideotracksource.h index fca4148148..641c10f3cc 100644 --- a/sdk/android/src/jni/androidvideotracksource.h +++ b/sdk/android/src/jni/androidvideotracksource.h @@ -20,8 +20,8 @@ #include "rtc_base/checks.h" #include "rtc_base/thread_checker.h" #include "rtc_base/timestampaligner.h" -#include "sdk/android/src/jni/native_handle_impl.h" #include "sdk/android/src/jni/surfacetexturehelper_jni.h" +#include "sdk/android/src/jni/videoframe.h" namespace webrtc { namespace jni { @@ -84,7 +84,6 @@ class AndroidVideoTrackSource : public rtc::AdaptedVideoTrackSource { NV12ToI420Scaler nv12toi420_scaler_; I420BufferPool buffer_pool_; rtc::scoped_refptr surface_texture_helper_; - AndroidVideoBufferFactory video_buffer_factory_; const bool is_screencast_; jmethodID j_crop_and_scale_id_; diff --git a/sdk/android/src/jni/surfacetexturehelper_jni.h b/sdk/android/src/jni/surfacetexturehelper_jni.h index 3d264d2a75..b227b52cc0 100644 --- a/sdk/android/src/jni/surfacetexturehelper_jni.h +++ b/sdk/android/src/jni/surfacetexturehelper_jni.h @@ -17,7 +17,7 @@ #include "rtc_base/refcount.h" #include "rtc_base/scoped_ref_ptr.h" #include "sdk/android/src/jni/jni_helpers.h" -#include "sdk/android/src/jni/native_handle_impl.h" +#include "sdk/android/src/jni/videoframe.h" namespace webrtc { namespace jni { diff --git a/sdk/android/src/jni/video_renderer_jni.cc b/sdk/android/src/jni/video_renderer_jni.cc index 4bd51593d8..ba439b9de1 100644 --- a/sdk/android/src/jni/video_renderer_jni.cc +++ b/sdk/android/src/jni/video_renderer_jni.cc @@ -14,7 +14,7 @@ #include "media/base/videosinkinterface.h" #include "sdk/android/src/jni/classreferenceholder.h" #include "sdk/android/src/jni/jni_helpers.h" -#include "sdk/android/src/jni/native_handle_impl.h" +#include "sdk/android/src/jni/videoframe.h" namespace webrtc { namespace jni { diff --git a/sdk/android/src/jni/videodecoderwrapper.cc b/sdk/android/src/jni/videodecoderwrapper.cc index 69b5c2d656..afa1f2eed1 100644 --- a/sdk/android/src/jni/videodecoderwrapper.cc +++ b/sdk/android/src/jni/videodecoderwrapper.cc @@ -22,8 +22,7 @@ namespace webrtc { namespace jni { VideoDecoderWrapper::VideoDecoderWrapper(JNIEnv* jni, jobject decoder) - : android_video_buffer_factory_(jni), - decoder_(jni, decoder), + : decoder_(jni, decoder), encoded_image_class_(jni, FindClass(jni, "org/webrtc/EncodedImage")), frame_type_class_(jni, FindClass(jni, "org/webrtc/EncodedImage$FrameType")), @@ -187,8 +186,8 @@ void VideoDecoderWrapper::OnDecodedFrame(JNIEnv* jni, // find a matching timestamp. } while (frame_extra_info.capture_time_ns != capture_time_ns); - VideoFrame frame = android_video_buffer_factory_.CreateFrame( - jni, jframe, frame_extra_info.timestamp_rtp); + VideoFrame frame = + JavaToNativeFrame(jni, jframe, frame_extra_info.timestamp_rtp); rtc::Optional decoding_time_ms; if (jdecode_time_ms != nullptr) { diff --git a/sdk/android/src/jni/videodecoderwrapper.h b/sdk/android/src/jni/videodecoderwrapper.h index 978be871e7..f56b49eb42 100644 --- a/sdk/android/src/jni/videodecoderwrapper.h +++ b/sdk/android/src/jni/videodecoderwrapper.h @@ -17,7 +17,7 @@ #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/native_handle_impl.h" +#include "sdk/android/src/jni/videoframe.h" namespace webrtc { namespace jni { @@ -78,7 +78,6 @@ class VideoDecoderWrapper : public VideoDecoder { int32_t number_of_cores_; bool initialized_; - AndroidVideoBufferFactory android_video_buffer_factory_; std::deque frame_extra_infos_; bool qp_parsing_enabled_; H264BitstreamParser h264_bitstream_parser_; diff --git a/sdk/android/src/jni/videoencoderwrapper.cc b/sdk/android/src/jni/videoencoderwrapper.cc index d8e1546d50..958d0290f9 100644 --- a/sdk/android/src/jni/videoencoderwrapper.cc +++ b/sdk/android/src/jni/videoencoderwrapper.cc @@ -35,8 +35,7 @@ VideoEncoderWrapper::VideoEncoderWrapper(JNIEnv* jni, jobject j_encoder) : encoder_(jni, j_encoder), frame_type_class_(jni, GetClass(jni, "org/webrtc/EncodedImage$FrameType")), - int_array_class_(jni, jni->FindClass("[I")), - video_frame_factory_(jni) { + int_array_class_(jni, jni->FindClass("[I")) { implementation_name_ = GetImplementationName(jni); initialized_ = false; @@ -137,8 +136,7 @@ int32_t VideoEncoderWrapper::Encode( frame_extra_infos_.push_back(info); jobject ret = Java_VideoEncoder_encode( - jni, *encoder_, video_frame_factory_.ToJavaFrame(jni, frame), - encode_info); + jni, *encoder_, NativeToJavaFrame(jni, frame), encode_info); return HandleReturnCode(jni, ret); } diff --git a/sdk/android/src/jni/videoencoderwrapper.h b/sdk/android/src/jni/videoencoderwrapper.h index 06f59031bd..629f28a6ec 100644 --- a/sdk/android/src/jni/videoencoderwrapper.h +++ b/sdk/android/src/jni/videoencoderwrapper.h @@ -21,7 +21,7 @@ #include "modules/video_coding/codecs/vp9/include/vp9_globals.h" #include "rtc_base/task_queue.h" #include "sdk/android/src/jni/jni_helpers.h" -#include "sdk/android/src/jni/native_handle_impl.h" +#include "sdk/android/src/jni/videoframe.h" namespace webrtc { namespace jni { @@ -95,7 +95,6 @@ class VideoEncoderWrapper : public VideoEncoder { std::string implementation_name_; rtc::TaskQueue* encoder_queue_; - JavaVideoFrameFactory video_frame_factory_; std::deque frame_extra_infos_; EncodedImageCallback* callback_; bool initialized_; diff --git a/sdk/android/src/jni/native_handle_impl.cc b/sdk/android/src/jni/videoframe.cc similarity index 60% rename from sdk/android/src/jni/native_handle_impl.cc rename to sdk/android/src/jni/videoframe.cc index ea1e04ed11..5e24002fc1 100644 --- a/sdk/android/src/jni/native_handle_impl.cc +++ b/sdk/android/src/jni/videoframe.cc @@ -8,17 +8,19 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "sdk/android/src/jni/native_handle_impl.h" +#include "sdk/android/src/jni/videoframe.h" #include #include "common_video/include/video_frame_buffer.h" +#include "libyuv/scale.h" #include "rtc_base/bind.h" #include "rtc_base/checks.h" #include "rtc_base/keep_ref_until_done.h" #include "rtc_base/logging.h" #include "rtc_base/scoped_ref_ptr.h" #include "rtc_base/timeutils.h" +#include "sdk/android/generated_video_jni/jni/VideoFrame_jni.h" #include "sdk/android/src/jni/classreferenceholder.h" #include "sdk/android/src/jni/jni_helpers.h" #include "sdk/android/src/jni/wrapped_native_i420_buffer.h" @@ -31,26 +33,16 @@ namespace { class AndroidVideoI420Buffer : public I420BufferInterface { public: - // Wraps an existing reference to a Java VideoBuffer. Retain will not be - // called but release will be called when the C++ object is destroyed. - static rtc::scoped_refptr WrapReference( - JNIEnv* jni, - jmethodID j_release_id, - int width, - int height, - jobject j_video_frame_buffer); + // Adopts and takes ownership of the Java VideoFrame.Buffer. I.e. retain() + // will not be called, but release() will be called when the returned + // AndroidVideoBuffer is destroyed. + static rtc::scoped_refptr + Adopt(JNIEnv* jni, int width, int height, jobject j_video_frame_buffer); protected: + // Should not be called directly. Adopts the buffer. Use Adopt() instead for + // clarity. AndroidVideoI420Buffer(JNIEnv* jni, - jmethodID j_retain_id, - jmethodID j_release_id, - int width, - int height, - jobject j_video_frame_buffer); - // Should not be called directly. Wraps a reference. Use - // AndroidVideoI420Buffer::WrapReference instead for clarity. - AndroidVideoI420Buffer(JNIEnv* jni, - jmethodID j_release_id, int width, int height, jobject j_video_frame_buffer); @@ -68,7 +60,6 @@ class AndroidVideoI420Buffer : public I420BufferInterface { int width() const override { return width_; } int height() const override { return height_; } - const jmethodID j_release_id_; const int width_; const int height_; // Holds a VideoFrame.I420Buffer. @@ -82,73 +73,38 @@ class AndroidVideoI420Buffer : public I420BufferInterface { int stride_v_; }; -rtc::scoped_refptr -AndroidVideoI420Buffer::WrapReference(JNIEnv* jni, - jmethodID j_release_id, - int width, - int height, - jobject j_video_frame_buffer) { +rtc::scoped_refptr AndroidVideoI420Buffer::Adopt( + JNIEnv* jni, + int width, + int height, + jobject j_video_frame_buffer) { return new rtc::RefCountedObject( - jni, j_release_id, width, height, j_video_frame_buffer); + jni, width, height, j_video_frame_buffer); } AndroidVideoI420Buffer::AndroidVideoI420Buffer(JNIEnv* jni, - jmethodID j_retain_id, - jmethodID j_release_id, int width, int height, jobject j_video_frame_buffer) - : AndroidVideoI420Buffer(jni, - j_release_id, - width, - height, - j_video_frame_buffer) { - jni->CallVoidMethod(j_video_frame_buffer, j_retain_id); -} - -AndroidVideoI420Buffer::AndroidVideoI420Buffer(JNIEnv* jni, - jmethodID j_release_id, - int width, - int height, - jobject j_video_frame_buffer) - : j_release_id_(j_release_id), - width_(width), + : width_(width), height_(height), j_video_frame_buffer_(jni, j_video_frame_buffer) { - jclass j_video_frame_i420_buffer_class = - FindClass(jni, "org/webrtc/VideoFrame$I420Buffer"); - jmethodID j_get_data_y_id = jni->GetMethodID( - j_video_frame_i420_buffer_class, "getDataY", "()Ljava/nio/ByteBuffer;"); - jmethodID j_get_data_u_id = jni->GetMethodID( - j_video_frame_i420_buffer_class, "getDataU", "()Ljava/nio/ByteBuffer;"); - jmethodID j_get_data_v_id = jni->GetMethodID( - j_video_frame_i420_buffer_class, "getDataV", "()Ljava/nio/ByteBuffer;"); - jmethodID j_get_stride_y_id = - jni->GetMethodID(j_video_frame_i420_buffer_class, "getStrideY", "()I"); - jmethodID j_get_stride_u_id = - jni->GetMethodID(j_video_frame_i420_buffer_class, "getStrideU", "()I"); - jmethodID j_get_stride_v_id = - jni->GetMethodID(j_video_frame_i420_buffer_class, "getStrideV", "()I"); - - jobject j_data_y = - jni->CallObjectMethod(j_video_frame_buffer, j_get_data_y_id); - jobject j_data_u = - jni->CallObjectMethod(j_video_frame_buffer, j_get_data_u_id); - jobject j_data_v = - jni->CallObjectMethod(j_video_frame_buffer, j_get_data_v_id); + jobject j_data_y = Java_I420Buffer_getDataY(jni, j_video_frame_buffer); + jobject j_data_u = Java_I420Buffer_getDataU(jni, j_video_frame_buffer); + jobject j_data_v = Java_I420Buffer_getDataV(jni, j_video_frame_buffer); data_y_ = static_cast(jni->GetDirectBufferAddress(j_data_y)); data_u_ = static_cast(jni->GetDirectBufferAddress(j_data_u)); data_v_ = static_cast(jni->GetDirectBufferAddress(j_data_v)); - stride_y_ = jni->CallIntMethod(j_video_frame_buffer, j_get_stride_y_id); - stride_u_ = jni->CallIntMethod(j_video_frame_buffer, j_get_stride_u_id); - stride_v_ = jni->CallIntMethod(j_video_frame_buffer, j_get_stride_v_id); + stride_y_ = Java_I420Buffer_getStrideY(jni, j_video_frame_buffer); + stride_u_ = Java_I420Buffer_getStrideU(jni, j_video_frame_buffer); + stride_v_ = Java_I420Buffer_getStrideV(jni, j_video_frame_buffer); } AndroidVideoI420Buffer::~AndroidVideoI420Buffer() { JNIEnv* jni = AttachCurrentThreadIfNeeded(); - jni->CallVoidMethod(*j_video_frame_buffer_, j_release_id_); + Java_Buffer_release(jni, *j_video_frame_buffer_); } } // namespace @@ -297,7 +253,7 @@ rtc::scoped_refptr AndroidTextureBuffer::ToI420() { // See YuvConverter.java for the required layout. uint8_t* y_data = yuv_data.get(); uint8_t* u_data = y_data + height() * stride; - uint8_t* v_data = u_data + stride/2; + uint8_t* v_data = u_data + stride / 2; rtc::scoped_refptr copy = webrtc::WrapI420Buffer( width(), height(), y_data, stride, u_data, stride, v_data, stride, @@ -326,43 +282,29 @@ rtc::scoped_refptr AndroidTextureBuffer::ToI420() { return copy; } -rtc::scoped_refptr AndroidVideoBuffer::WrapReference( +rtc::scoped_refptr AndroidVideoBuffer::Adopt( JNIEnv* jni, - jmethodID j_release_id, - int width, - int height, jobject j_video_frame_buffer) { - return new rtc::RefCountedObject( - jni, j_release_id, width, height, j_video_frame_buffer); + return new rtc::RefCountedObject(jni, + j_video_frame_buffer); +} + +rtc::scoped_refptr AndroidVideoBuffer::Create( + JNIEnv* jni, + jobject j_video_frame_buffer) { + Java_Buffer_retain(jni, j_video_frame_buffer); + return Adopt(jni, j_video_frame_buffer); } AndroidVideoBuffer::AndroidVideoBuffer(JNIEnv* jni, - jmethodID j_retain_id, - jmethodID j_release_id, - int width, - int height, jobject j_video_frame_buffer) - : AndroidVideoBuffer(jni, - j_release_id, - width, - height, - j_video_frame_buffer) { - jni->CallVoidMethod(j_video_frame_buffer, j_retain_id); -} - -AndroidVideoBuffer::AndroidVideoBuffer(JNIEnv* jni, - jmethodID j_release_id, - int width, - int height, - jobject j_video_frame_buffer) - : j_release_id_(j_release_id), - width_(width), - height_(height), + : width_(Java_Buffer_getWidth(jni, j_video_frame_buffer)), + height_(Java_Buffer_getHeight(jni, j_video_frame_buffer)), j_video_frame_buffer_(jni, j_video_frame_buffer) {} AndroidVideoBuffer::~AndroidVideoBuffer() { JNIEnv* jni = AttachCurrentThreadIfNeeded(); - jni->CallVoidMethod(*j_video_frame_buffer_, j_release_id_); + Java_Buffer_release(jni, *j_video_frame_buffer_); } jobject AndroidVideoBuffer::video_frame_buffer() const { @@ -384,20 +326,11 @@ int AndroidVideoBuffer::height() const { rtc::scoped_refptr AndroidVideoBuffer::ToI420() { JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedLocalRefFrame local_ref_frame(jni); - - jclass j_video_frame_buffer_class = - FindClass(jni, "org/webrtc/VideoFrame$Buffer"); - jmethodID j_to_i420_id = - jni->GetMethodID(j_video_frame_buffer_class, "toI420", - "()Lorg/webrtc/VideoFrame$I420Buffer;"); - - jobject j_i420_buffer = - jni->CallObjectMethod(*j_video_frame_buffer_, j_to_i420_id); + jobject j_i420_buffer = Java_Buffer_toI420(jni, *j_video_frame_buffer_); // We don't need to retain the buffer because toI420 returns a new object that // we are assumed to take the ownership of. - return AndroidVideoI420Buffer::WrapReference(jni, j_release_id_, width_, - height_, j_i420_buffer); + return AndroidVideoI420Buffer::Adopt(jni, width_, height_, j_i420_buffer); } jobject AndroidVideoBuffer::ToJavaI420Frame(JNIEnv* jni, int rotation) { @@ -415,69 +348,19 @@ jobject AndroidVideoBuffer::ToJavaI420Frame(JNIEnv* jni, int rotation) { *j_video_frame_buffer_, jlongFromPointer(native_frame)); } -AndroidVideoBufferFactory::AndroidVideoBufferFactory(JNIEnv* jni) - : j_video_frame_class_(jni, FindClass(jni, "org/webrtc/VideoFrame")), - j_get_buffer_id_(GetMethodID(jni, - *j_video_frame_class_, - "getBuffer", - "()Lorg/webrtc/VideoFrame$Buffer;")), - j_get_rotation_id_( - GetMethodID(jni, *j_video_frame_class_, "getRotation", "()I")), - j_get_timestamp_ns_id_( - GetMethodID(jni, *j_video_frame_class_, "getTimestampNs", "()J")), - j_video_frame_buffer_class_( - jni, - FindClass(jni, "org/webrtc/VideoFrame$Buffer")), - j_retain_id_( - GetMethodID(jni, *j_video_frame_buffer_class_, "retain", "()V")), - j_release_id_( - GetMethodID(jni, *j_video_frame_buffer_class_, "release", "()V")), - j_get_width_id_( - GetMethodID(jni, *j_video_frame_buffer_class_, "getWidth", "()I")), - j_get_height_id_( - GetMethodID(jni, *j_video_frame_buffer_class_, "getHeight", "()I")) {} - -VideoFrame AndroidVideoBufferFactory::CreateFrame( - JNIEnv* jni, - jobject j_video_frame, - uint32_t timestamp_rtp) const { - jobject j_video_frame_buffer = - jni->CallObjectMethod(j_video_frame, j_get_buffer_id_); - int rotation = jni->CallIntMethod(j_video_frame, j_get_rotation_id_); - uint32_t timestamp_ns = - jni->CallLongMethod(j_video_frame, j_get_timestamp_ns_id_); +VideoFrame JavaToNativeFrame(JNIEnv* jni, + jobject j_video_frame, + 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); rtc::scoped_refptr buffer = - CreateBuffer(jni, j_video_frame_buffer); + AndroidVideoBuffer::Create(jni, j_video_frame_buffer); return VideoFrame(buffer, timestamp_rtp, timestamp_ns / rtc::kNumNanosecsPerMillisec, static_cast(rotation)); } -rtc::scoped_refptr AndroidVideoBufferFactory::WrapBuffer( - JNIEnv* jni, - jobject j_video_frame_buffer) const { - int width = jni->CallIntMethod(j_video_frame_buffer, j_get_width_id_); - int height = jni->CallIntMethod(j_video_frame_buffer, j_get_height_id_); - return AndroidVideoBuffer::WrapReference(jni, j_release_id_, width, height, - j_video_frame_buffer); -} - -rtc::scoped_refptr AndroidVideoBufferFactory::CreateBuffer( - JNIEnv* jni, - jobject j_video_frame_buffer) const { - int width = jni->CallIntMethod(j_video_frame_buffer, j_get_width_id_); - int height = jni->CallIntMethod(j_video_frame_buffer, j_get_height_id_); - return new rtc::RefCountedObject( - jni, j_retain_id_, j_release_id_, width, height, j_video_frame_buffer); -} - -JavaVideoFrameFactory::JavaVideoFrameFactory(JNIEnv* jni) - : j_video_frame_class_(jni, FindClass(jni, "org/webrtc/VideoFrame")) { - j_video_frame_constructor_id_ = - GetMethodID(jni, *j_video_frame_class_, "", - "(Lorg/webrtc/VideoFrame$Buffer;IJ)V"); -} - static bool IsJavaVideoBuffer(rtc::scoped_refptr buffer) { if (buffer->type() != VideoFrameBuffer::Type::kNative) { return false; @@ -488,8 +371,7 @@ static bool IsJavaVideoBuffer(rtc::scoped_refptr buffer) { AndroidVideoFrameBuffer::AndroidType::kJavaBuffer; } -jobject JavaVideoFrameFactory::ToJavaFrame(JNIEnv* jni, - const VideoFrame& frame) const { +jobject NativeToJavaFrame(JNIEnv* jni, const VideoFrame& frame) { rtc::scoped_refptr buffer = frame.video_frame_buffer(); jobject j_buffer; if (IsJavaVideoBuffer(buffer)) { @@ -504,11 +386,53 @@ jobject JavaVideoFrameFactory::ToJavaFrame(JNIEnv* jni, } else { j_buffer = WrapI420Buffer(jni, buffer->ToI420()); } - return jni->NewObject( - *j_video_frame_class_, j_video_frame_constructor_id_, j_buffer, - static_cast(frame.rotation()), + return Java_VideoFrame_create( + jni, j_buffer, static_cast(frame.rotation()), static_cast(frame.timestamp_us() * rtc::kNumNanosecsPerMicrosec)); } +extern "C" JNIEXPORT void JNICALL +Java_org_webrtc_VideoFrame_cropAndScaleI420Native(JNIEnv* jni, + jclass, + jobject j_src_y, + jint src_stride_y, + jobject j_src_u, + jint src_stride_u, + jobject j_src_v, + jint src_stride_v, + jint crop_x, + jint crop_y, + jint crop_width, + jint crop_height, + jobject j_dst_y, + jint dst_stride_y, + jobject j_dst_u, + jint dst_stride_u, + jobject j_dst_v, + jint dst_stride_v, + jint scale_width, + jint scale_height) { + uint8_t const* src_y = + static_cast(jni->GetDirectBufferAddress(j_src_y)); + uint8_t const* src_u = + static_cast(jni->GetDirectBufferAddress(j_src_u)); + uint8_t const* src_v = + static_cast(jni->GetDirectBufferAddress(j_src_v)); + uint8_t* dst_y = static_cast(jni->GetDirectBufferAddress(j_dst_y)); + uint8_t* dst_u = static_cast(jni->GetDirectBufferAddress(j_dst_u)); + uint8_t* dst_v = static_cast(jni->GetDirectBufferAddress(j_dst_v)); + + // Perform cropping using pointer arithmetic. + src_y += crop_x + crop_y * src_stride_y; + src_u += crop_x / 2 + crop_y / 2 * src_stride_u; + src_v += crop_x / 2 + crop_y / 2 * src_stride_v; + + bool ret = libyuv::I420Scale( + src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v, crop_width, + crop_height, dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, + dst_stride_v, scale_width, scale_height, libyuv::kFilterBox); + RTC_DCHECK_EQ(ret, 0) << "I420Scale failed"; +} + } // namespace jni } // namespace webrtc diff --git a/sdk/android/src/jni/native_handle_impl.h b/sdk/android/src/jni/videoframe.h similarity index 63% rename from sdk/android/src/jni/native_handle_impl.h rename to sdk/android/src/jni/videoframe.h index 10c0d19727..c477286a10 100644 --- a/sdk/android/src/jni/native_handle_impl.h +++ b/sdk/android/src/jni/videoframe.h @@ -8,8 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ -#ifndef SDK_ANDROID_SRC_JNI_NATIVE_HANDLE_IMPL_H_ -#define SDK_ANDROID_SRC_JNI_NATIVE_HANDLE_IMPL_H_ +#ifndef SDK_ANDROID_SRC_JNI_VIDEOFRAME_H_ +#define SDK_ANDROID_SRC_JNI_VIDEOFRAME_H_ #include @@ -104,28 +104,18 @@ class AndroidTextureBuffer : public AndroidVideoFrameBuffer { class AndroidVideoBuffer : public AndroidVideoFrameBuffer { public: - // Wraps an existing reference to a Java VideoBuffer. Retain will not be - // called but release will be called when the C++ object is destroyed. - static rtc::scoped_refptr WrapReference( + // Creates a native VideoFrameBuffer from a Java VideoFrame.Buffer. + static rtc::scoped_refptr Create( + JNIEnv* jni, + jobject j_video_frame_buffer); + + // Similar to the Create() above, but adopts and takes ownership of the Java + // VideoFrame.Buffer. I.e. retain() will not be called, but release() will be + // called when the returned AndroidVideoBuffer is destroyed. + static rtc::scoped_refptr Adopt( JNIEnv* jni, - jmethodID j_release_id, - int width, - int height, jobject j_video_frame_buffer); - AndroidVideoBuffer(JNIEnv* jni, - jmethodID j_retain_id, - jmethodID j_release_id, - int width, - int height, - jobject j_video_frame_buffer); - // Should not be called directly. Wraps a reference. Use - // AndroidVideoBuffer::WrapReference instead for clarity. - AndroidVideoBuffer(JNIEnv* jni, - jmethodID j_release_id, - int width, - int height, - jobject j_video_frame_buffer); ~AndroidVideoBuffer() override; jobject video_frame_buffer() const; @@ -133,6 +123,11 @@ class AndroidVideoBuffer : public AndroidVideoFrameBuffer { // Returns an instance of VideoRenderer.I420Frame (deprecated) jobject ToJavaI420Frame(JNIEnv* jni, int rotation); + protected: + // Should not be called directly. Adopts the Java VideoFrame.Buffer. Use + // Create() or Adopt() instead for clarity. + AndroidVideoBuffer(JNIEnv* jni, jobject j_video_frame_buffer); + private: Type type() const override; int width() const override; @@ -142,56 +137,19 @@ class AndroidVideoBuffer : public AndroidVideoFrameBuffer { AndroidType android_type() override { return AndroidType::kJavaBuffer; } - const jmethodID j_release_id_; const int width_; const int height_; // Holds a VideoFrame.Buffer. const ScopedGlobalRef j_video_frame_buffer_; }; -class AndroidVideoBufferFactory { - public: - explicit AndroidVideoBufferFactory(JNIEnv* jni); +VideoFrame JavaToNativeFrame(JNIEnv* jni, + jobject j_video_frame, + uint32_t timestamp_rtp); - VideoFrame CreateFrame(JNIEnv* jni, - jobject j_video_frame, - uint32_t timestamp_rtp) const; - - // Wraps a buffer to AndroidVideoBuffer without incrementing the reference - // count. - rtc::scoped_refptr WrapBuffer( - JNIEnv* jni, - jobject j_video_frame_buffer) const; - - rtc::scoped_refptr CreateBuffer( - JNIEnv* jni, - jobject j_video_frame_buffer) const; - - private: - ScopedGlobalRef j_video_frame_class_; - jmethodID j_get_buffer_id_; - jmethodID j_get_rotation_id_; - jmethodID j_get_timestamp_ns_id_; - - ScopedGlobalRef j_video_frame_buffer_class_; - jmethodID j_retain_id_; - jmethodID j_release_id_; - jmethodID j_get_width_id_; - jmethodID j_get_height_id_; -}; - -class JavaVideoFrameFactory { - public: - JavaVideoFrameFactory(JNIEnv* jni); - - jobject ToJavaFrame(JNIEnv* jni, const VideoFrame& frame) const; - - private: - ScopedGlobalRef j_video_frame_class_; - jmethodID j_video_frame_constructor_id_; -}; +jobject NativeToJavaFrame(JNIEnv* jni, const VideoFrame& frame); } // namespace jni } // namespace webrtc -#endif // SDK_ANDROID_SRC_JNI_NATIVE_HANDLE_IMPL_H_ +#endif // SDK_ANDROID_SRC_JNI_VIDEOFRAME_H_ diff --git a/sdk/android/src/jni/videoframe_jni.cc b/sdk/android/src/jni/videoframe_jni.cc deleted file mode 100644 index 7533f9c6b2..0000000000 --- a/sdk/android/src/jni/videoframe_jni.cc +++ /dev/null @@ -1,64 +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. - */ - -#include - -#include "libyuv/scale.h" - -#include "rtc_base/checks.h" - -namespace webrtc { -namespace jni { - -extern "C" JNIEXPORT void JNICALL -Java_org_webrtc_VideoFrame_nativeCropAndScaleI420(JNIEnv* jni, - jclass, - jobject j_src_y, - jint src_stride_y, - jobject j_src_u, - jint src_stride_u, - jobject j_src_v, - jint src_stride_v, - jint crop_x, - jint crop_y, - jint crop_width, - jint crop_height, - jobject j_dst_y, - jint dst_stride_y, - jobject j_dst_u, - jint dst_stride_u, - jobject j_dst_v, - jint dst_stride_v, - jint scale_width, - jint scale_height) { - uint8_t const* src_y = - static_cast(jni->GetDirectBufferAddress(j_src_y)); - uint8_t const* src_u = - static_cast(jni->GetDirectBufferAddress(j_src_u)); - uint8_t const* src_v = - static_cast(jni->GetDirectBufferAddress(j_src_v)); - uint8_t* dst_y = static_cast(jni->GetDirectBufferAddress(j_dst_y)); - uint8_t* dst_u = static_cast(jni->GetDirectBufferAddress(j_dst_u)); - uint8_t* dst_v = static_cast(jni->GetDirectBufferAddress(j_dst_v)); - - // Perform cropping using pointer arithmetic. - src_y += crop_x + crop_y * src_stride_y; - src_u += crop_x / 2 + crop_y / 2 * src_stride_u; - src_v += crop_x / 2 + crop_y / 2 * src_stride_v; - - bool ret = libyuv::I420Scale( - src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v, crop_width, - crop_height, dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, - dst_stride_v, scale_width, scale_height, libyuv::kFilterBox); - RTC_DCHECK_EQ(ret, 0) << "I420Scale failed"; -} - -} // namespace jni -} // namespace webrtc diff --git a/sdk/android/src/jni/videotrack_jni.cc b/sdk/android/src/jni/videotrack_jni.cc index 98b1bd2c17..7a9dcd0c46 100644 --- a/sdk/android/src/jni/videotrack_jni.cc +++ b/sdk/android/src/jni/videotrack_jni.cc @@ -15,7 +15,7 @@ #include "sdk/android/generated_video_jni/jni/VideoSink_jni.h" #include "sdk/android/src/jni/classreferenceholder.h" #include "sdk/android/src/jni/jni_helpers.h" -#include "sdk/android/src/jni/native_handle_impl.h" +#include "sdk/android/src/jni/videoframe.h" namespace webrtc { namespace jni { @@ -30,18 +30,16 @@ class VideoSinkWrapper : public rtc::VideoSinkInterface { private: void OnFrame(const VideoFrame& frame) override; - const JavaVideoFrameFactory java_video_frame_factory_; const ScopedGlobalRef j_sink_; }; VideoSinkWrapper::VideoSinkWrapper(JNIEnv* jni, jobject j_sink) - : java_video_frame_factory_(jni), j_sink_(jni, j_sink) {} + : j_sink_(jni, j_sink) {} void VideoSinkWrapper::OnFrame(const VideoFrame& frame) { JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedLocalRefFrame local_ref_frame(jni); - Java_VideoSink_onFrame(jni, *j_sink_, - java_video_frame_factory_.ToJavaFrame(jni, frame)); + Java_VideoSink_onFrame(jni, *j_sink_, NativeToJavaFrame(jni, frame)); } } // namespace