diff --git a/webrtc-jni/src/main/cpp/include/JNI_NativeI420Buffer.h b/webrtc-jni/src/main/cpp/include/JNI_NativeI420Buffer.h index 89f5aed0..09f2303d 100644 --- a/webrtc-jni/src/main/cpp/include/JNI_NativeI420Buffer.h +++ b/webrtc-jni/src/main/cpp/include/JNI_NativeI420Buffer.h @@ -9,10 +9,10 @@ extern "C" { #endif /* * Class: dev_onvoid_webrtc_media_video_NativeI420Buffer - * Method: allocate + * Method: allocateBuffer * Signature: (II)Ldev/onvoid/webrtc/media/video/NativeI420Buffer; */ - JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_media_video_NativeI420Buffer_allocate + JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_media_video_NativeI420Buffer_allocateBuffer (JNIEnv *, jclass, jint, jint); /* diff --git a/webrtc-jni/src/main/cpp/src/JNI_NativeI420Buffer.cpp b/webrtc-jni/src/main/cpp/src/JNI_NativeI420Buffer.cpp index d0110be1..2d03b04c 100644 --- a/webrtc-jni/src/main/cpp/src/JNI_NativeI420Buffer.cpp +++ b/webrtc-jni/src/main/cpp/src/JNI_NativeI420Buffer.cpp @@ -23,7 +23,7 @@ #include "common_video/include/video_frame_buffer.h" #include "libyuv/scale.h" -JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_media_video_NativeI420Buffer_allocate +JNIEXPORT jobject JNICALL Java_dev_onvoid_webrtc_media_video_NativeI420Buffer_allocateBuffer (JNIEnv * env, jclass caller, jint width, jint height) { try { diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/NativeI420Buffer.java b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/NativeI420Buffer.java index 556c3d4f..73c4c8c8 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/media/video/NativeI420Buffer.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/media/video/NativeI420Buffer.java @@ -121,8 +121,31 @@ public NativeI420Buffer copy() { /** * Allocates an empty I420Buffer suitable for an image of the given dimensions. + * + * @param width The width of the image in pixels. + * @param height The height of the image in pixels. + * + * @return A new buffer of the given dimensions. + * + * @throws IllegalArgumentException if a dimension is not positive or all three planes together + * are larger than {@link Integer#MAX_VALUE} bytes. */ - public static native NativeI420Buffer allocate(int width, int height); + public static NativeI420Buffer allocate(int width, int height) { + // WebRTC aborts the process on dimensions it cannot allocate, rather than failing the call. + if (width <= 0 || height <= 0) { + throw new IllegalArgumentException("Invalid buffer size " + width + "x" + height); + } + + long chromaSize = ((width + 1L) / 2) * ((height + 1L) / 2); + + if ((long) width * height + 2 * chromaSize > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Buffer size " + width + "x" + height + " is too large"); + } + + return allocateBuffer(width, height); + } + + private static native NativeI420Buffer allocateBuffer(int width, int height); /** * Creates a copy of an I420 buffer with the given dimensions and data. diff --git a/webrtc/src/test/java/dev/onvoid/webrtc/media/video/NativeI420BufferTest.java b/webrtc/src/test/java/dev/onvoid/webrtc/media/video/NativeI420BufferTest.java index 6defa8f6..0e734ade 100644 --- a/webrtc/src/test/java/dev/onvoid/webrtc/media/video/NativeI420BufferTest.java +++ b/webrtc/src/test/java/dev/onvoid/webrtc/media/video/NativeI420BufferTest.java @@ -98,6 +98,35 @@ void cropOutsideBuffer() { source.release(); } + @Test + void allocateInvalidSize() { + assertThrows(IllegalArgumentException.class, () -> NativeI420Buffer.allocate(0, 8)); + assertThrows(IllegalArgumentException.class, () -> NativeI420Buffer.allocate(8, 0)); + assertThrows(IllegalArgumentException.class, () -> NativeI420Buffer.allocate(-8, 8)); + assertThrows(IllegalArgumentException.class, () -> NativeI420Buffer.allocate(8, Integer.MIN_VALUE)); + } + + @Test + void allocateTooLarge() { + // The planes would exceed what WebRTC can address with an int. + assertThrows(IllegalArgumentException.class, () -> NativeI420Buffer.allocate(Integer.MAX_VALUE, Integer.MAX_VALUE)); + assertThrows(IllegalArgumentException.class, () -> NativeI420Buffer.allocate(46341, 46341)); + assertThrows(IllegalArgumentException.class, () -> NativeI420Buffer.allocate(Integer.MAX_VALUE, 1)); + } + + @Test + void allocateOddSize() { + NativeI420Buffer buffer = NativeI420Buffer.allocate(3, 1); + + assertEquals(3, buffer.getWidth()); + assertEquals(1, buffer.getHeight()); + assertEquals(3, buffer.getDataY().capacity()); + assertEquals(2, buffer.getDataU().capacity()); + assertEquals(2, buffer.getDataV().capacity()); + + buffer.release(); + } + @Test void pushReleasedBuffer() { CustomVideoSource videoSource = new CustomVideoSource();