diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index 09696370ef..c6839fa629 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -229,9 +229,6 @@ if (is_android) { "api/org/webrtc/VideoSink.java", ] - # TODO(sakal): These should be moved to video_java but cannot because of dependencies. - java_files += [ "api/org/webrtc/JavaI420Buffer.java" ] - deps = [ ":base_java", "//rtc_base:base_java", @@ -246,6 +243,7 @@ if (is_android) { "api/org/webrtc/GlShader.java", "api/org/webrtc/GlTextureFrameBuffer.java", "api/org/webrtc/GlUtil.java", + "api/org/webrtc/JavaI420Buffer.java", "api/org/webrtc/RendererCommon.java", "api/org/webrtc/SurfaceTextureHelper.java", "api/org/webrtc/TextureBufferImpl.java", @@ -529,6 +527,7 @@ if (is_android) { "src/jni/encodedimage.cc", "src/jni/encodedimage.h", "src/jni/h264utils.cc", + "src/jni/javai420buffer.cc", "src/jni/jni_generator_helper.h", "src/jni/nativecapturerobserver.cc", "src/jni/nativecapturerobserver.h", @@ -923,8 +922,6 @@ if (is_android) { "../../rtc_base:checks", "../../rtc_base:rtc_base", "../../rtc_base:rtc_base_approved", - "../../rtc_base/memory:aligned_malloc", - "//third_party/libyuv", ] } @@ -1110,6 +1107,7 @@ if (is_android) { generate_jni("generated_video_jni") { sources = [ "api/org/webrtc/EncodedImage.java", + "api/org/webrtc/JavaI420Buffer.java", "api/org/webrtc/MediaCodecVideoDecoder.java", "api/org/webrtc/MediaCodecVideoEncoder.java", "api/org/webrtc/VideoCodecInfo.java", diff --git a/sdk/android/api/org/webrtc/JavaI420Buffer.java b/sdk/android/api/org/webrtc/JavaI420Buffer.java index 7231fdab91..9bbd9b2d91 100644 --- a/sdk/android/api/org/webrtc/JavaI420Buffer.java +++ b/sdk/android/api/org/webrtc/JavaI420Buffer.java @@ -163,7 +163,37 @@ public class JavaI420Buffer implements VideoFrame.I420Buffer { @Override public VideoFrame.Buffer cropAndScale( int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight) { - return VideoFrame.cropAndScaleI420( - this, cropX, cropY, cropWidth, cropHeight, scaleWidth, scaleHeight); + return cropAndScaleI420(this, cropX, cropY, cropWidth, cropHeight, scaleWidth, scaleHeight); } + + public static VideoFrame.Buffer cropAndScaleI420(final I420Buffer buffer, int cropX, int cropY, + int cropWidth, int cropHeight, int scaleWidth, int scaleHeight) { + if (cropWidth == scaleWidth && cropHeight == scaleHeight) { + // No scaling. + ByteBuffer dataY = buffer.getDataY(); + ByteBuffer dataU = buffer.getDataU(); + ByteBuffer dataV = buffer.getDataV(); + + dataY.position(cropX + cropY * buffer.getStrideY()); + dataU.position(cropX / 2 + cropY / 2 * buffer.getStrideU()); + dataV.position(cropX / 2 + cropY / 2 * buffer.getStrideV()); + + buffer.retain(); + return JavaI420Buffer.wrap(scaleWidth, scaleHeight, dataY.slice(), buffer.getStrideY(), + dataU.slice(), buffer.getStrideU(), dataV.slice(), buffer.getStrideV(), buffer::release); + } + + JavaI420Buffer newBuffer = JavaI420Buffer.allocate(scaleWidth, scaleHeight); + nativeCropAndScaleI420(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, + scaleHeight); + return newBuffer; + } + + private static native void nativeCropAndScaleI420(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/api/org/webrtc/VideoFrame.java b/sdk/android/api/org/webrtc/VideoFrame.java index 4afe78266a..fb733af7db 100644 --- a/sdk/android/api/org/webrtc/VideoFrame.java +++ b/sdk/android/api/org/webrtc/VideoFrame.java @@ -188,37 +188,4 @@ public class VideoFrame implements RefCounted { public void release() { buffer.release(); } - - // TODO(sakal): This file should be strictly an interface. This method should be moved somewhere - // else. - public static VideoFrame.Buffer cropAndScaleI420(final I420Buffer buffer, int cropX, int cropY, - int cropWidth, int cropHeight, int scaleWidth, int scaleHeight) { - if (cropWidth == scaleWidth && cropHeight == scaleHeight) { - // No scaling. - ByteBuffer dataY = buffer.getDataY(); - ByteBuffer dataU = buffer.getDataU(); - ByteBuffer dataV = buffer.getDataV(); - - dataY.position(cropX + cropY * buffer.getStrideY()); - dataU.position(cropX / 2 + cropY / 2 * buffer.getStrideU()); - dataV.position(cropX / 2 + cropY / 2 * buffer.getStrideV()); - - buffer.retain(); - return JavaI420Buffer.wrap(scaleWidth, scaleHeight, dataY.slice(), buffer.getStrideY(), - dataU.slice(), buffer.getStrideU(), dataV.slice(), buffer.getStrideV(), buffer::release); - } - - JavaI420Buffer newBuffer = JavaI420Buffer.allocate(scaleWidth, scaleHeight); - nativeCropAndScaleI420(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, - scaleHeight); - return newBuffer; - } - - private static native void nativeCropAndScaleI420(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/WrappedNativeI420Buffer.java b/sdk/android/src/java/org/webrtc/WrappedNativeI420Buffer.java index 8b698cad01..0461660fcf 100644 --- a/sdk/android/src/java/org/webrtc/WrappedNativeI420Buffer.java +++ b/sdk/android/src/java/org/webrtc/WrappedNativeI420Buffer.java @@ -104,7 +104,7 @@ class WrappedNativeI420Buffer implements VideoFrame.I420Buffer { @Override public VideoFrame.Buffer cropAndScale( int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight) { - return VideoFrame.cropAndScaleI420( + return JavaI420Buffer.cropAndScaleI420( this, cropX, cropY, cropWidth, cropHeight, scaleWidth, scaleHeight); } } diff --git a/sdk/android/src/jni/javai420buffer.cc b/sdk/android/src/jni/javai420buffer.cc new file mode 100644 index 0000000000..a98462fa7a --- /dev/null +++ b/sdk/android/src/jni/javai420buffer.cc @@ -0,0 +1,64 @@ +/* + * Copyright 2015 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/generated_video_jni/jni/JavaI420Buffer_jni.h" +#include "third_party/libyuv/include/libyuv/scale.h" + +namespace webrtc { +namespace jni { + +static void JNI_JavaI420Buffer_CropAndScaleI420( + JNIEnv* jni, + const JavaParamRef&, + const JavaParamRef& j_src_y, + jint src_stride_y, + const JavaParamRef& j_src_u, + jint src_stride_u, + const JavaParamRef& j_src_v, + jint src_stride_v, + jint crop_x, + jint crop_y, + jint crop_width, + jint crop_height, + const JavaParamRef& j_dst_y, + jint dst_stride_y, + const JavaParamRef& j_dst_u, + jint dst_stride_u, + const JavaParamRef& 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.obj())); + uint8_t const* src_u = + static_cast(jni->GetDirectBufferAddress(j_src_u.obj())); + uint8_t const* src_v = + static_cast(jni->GetDirectBufferAddress(j_src_v.obj())); + uint8_t* dst_y = + static_cast(jni->GetDirectBufferAddress(j_dst_y.obj())); + uint8_t* dst_u = + static_cast(jni->GetDirectBufferAddress(j_dst_u.obj())); + uint8_t* dst_v = + static_cast(jni->GetDirectBufferAddress(j_dst_v.obj())); + + // 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/videoframe.cc b/sdk/android/src/jni/videoframe.cc index aeb43bcefc..dd13cb3522 100644 --- a/sdk/android/src/jni/videoframe.cc +++ b/sdk/android/src/jni/videoframe.cc @@ -17,13 +17,11 @@ #include "rtc_base/checks.h" #include "rtc_base/keep_ref_until_done.h" #include "rtc_base/logging.h" -#include "rtc_base/memory/aligned_malloc.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/jni_helpers.h" #include "sdk/android/src/jni/wrapped_native_i420_buffer.h" -#include "third_party/libyuv/include/libyuv/scale.h" namespace webrtc { namespace jni { @@ -230,51 +228,5 @@ void ReleaseJavaVideoFrame(JNIEnv* jni, const JavaRef& j_video_frame) { Java_VideoFrame_release(jni, j_video_frame); } -static void JNI_VideoFrame_CropAndScaleI420( - JNIEnv* jni, - const JavaParamRef&, - const JavaParamRef& j_src_y, - jint src_stride_y, - const JavaParamRef& j_src_u, - jint src_stride_u, - const JavaParamRef& j_src_v, - jint src_stride_v, - jint crop_x, - jint crop_y, - jint crop_width, - jint crop_height, - const JavaParamRef& j_dst_y, - jint dst_stride_y, - const JavaParamRef& j_dst_u, - jint dst_stride_u, - const JavaParamRef& 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.obj())); - uint8_t const* src_u = - static_cast(jni->GetDirectBufferAddress(j_src_u.obj())); - uint8_t const* src_v = - static_cast(jni->GetDirectBufferAddress(j_src_v.obj())); - uint8_t* dst_y = - static_cast(jni->GetDirectBufferAddress(j_dst_y.obj())); - uint8_t* dst_u = - static_cast(jni->GetDirectBufferAddress(j_dst_u.obj())); - uint8_t* dst_v = - static_cast(jni->GetDirectBufferAddress(j_dst_v.obj())); - - // 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