diff --git a/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java b/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java index 227c5a40c5..b009893ba7 100644 --- a/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java +++ b/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java @@ -621,9 +621,24 @@ public class MediaCodecVideoEncoder { eglBase.swapBuffers(frame.getTimestampNs()); } else { VideoFrame.I420Buffer i420Buffer = buffer.toI420(); - nativeFillBuffer(nativeEncoder, bufferIndex, i420Buffer.getDataY(), i420Buffer.getStrideY(), - i420Buffer.getDataU(), i420Buffer.getStrideU(), i420Buffer.getDataV(), - i420Buffer.getStrideV()); + final int chromaHeight = (height + 1) / 2; + final ByteBuffer dataY = i420Buffer.getDataY(); + final ByteBuffer dataU = i420Buffer.getDataU(); + final ByteBuffer dataV = i420Buffer.getDataV(); + final int strideY = i420Buffer.getStrideY(); + final int strideU = i420Buffer.getStrideU(); + final int strideV = i420Buffer.getStrideV(); + if (dataY.capacity() < strideY * height) { + throw new RuntimeException("Y-plane buffer size too small."); + } + if (dataU.capacity() < strideU * chromaHeight) { + throw new RuntimeException("U-plane buffer size too small."); + } + if (dataV.capacity() < strideV * chromaHeight) { + throw new RuntimeException("V-plane buffer size too small."); + } + nativeFillBuffer( + nativeEncoder, bufferIndex, dataY, strideY, dataU, strideU, dataV, strideV); i420Buffer.release(); // I420 consists of one full-resolution and two half-resolution planes. // 1 + 1 / 4 + 1 / 4 = 3 / 2 diff --git a/sdk/android/api/org/webrtc/VideoFrame.java b/sdk/android/api/org/webrtc/VideoFrame.java index a13112105e..6ff5412e4c 100644 --- a/sdk/android/api/org/webrtc/VideoFrame.java +++ b/sdk/android/api/org/webrtc/VideoFrame.java @@ -58,21 +58,24 @@ public class VideoFrame { */ public interface I420Buffer extends Buffer { /** - * Returns a direct ByteBuffer containing Y-plane data. The buffer size is at least getStrideY() - * * getHeight() bytes. Callers may mutate the ByteBuffer (eg. through relative-read - * operations), so implementations must return a new ByteBuffer or slice for each call. + * Returns a direct ByteBuffer containing Y-plane data. The buffer capacity is at least + * getStrideY() * getHeight() 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 getDataY(); /** - * Returns a direct ByteBuffer containing U-plane data. The buffer size is at least getStrideU() - * * ((getHeight() + 1) / 2) bytes. Callers may mutate the ByteBuffer (eg. through relative-read - * operations), so implementations must return a new ByteBuffer or slice for each call. + * 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(); /** - * Returns a direct ByteBuffer containing V-plane data. The buffer size is at least getStrideV() - * * ((getHeight() + 1) / 2) bytes. Callers may mutate the ByteBuffer (eg. through relative-read - * operations), so implementations must return a new ByteBuffer or slice for each call. + * 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(); diff --git a/sdk/android/src/jni/androidmediaencoder_jni.cc b/sdk/android/src/jni/androidmediaencoder_jni.cc index 07a6339f1f..3882c9001f 100644 --- a/sdk/android/src/jni/androidmediaencoder_jni.cc +++ b/sdk/android/src/jni/androidmediaencoder_jni.cc @@ -1478,6 +1478,13 @@ JNI_FUNCTION_DECLARATION(void, uint8_t* buffer_v = static_cast(jni->GetDirectBufferAddress(j_buffer_v)); + RTC_DCHECK(buffer_y) << "GetDirectBufferAddress returned null. Ensure that " + "getDataY returns a direct ByteBuffer."; + RTC_DCHECK(buffer_u) << "GetDirectBufferAddress returned null. Ensure that " + "getDataU returns a direct ByteBuffer."; + RTC_DCHECK(buffer_v) << "GetDirectBufferAddress returned null. Ensure that " + "getDataV returns a direct ByteBuffer."; + reinterpret_cast(native_encoder) ->FillInputBuffer(jni, input_buffer, buffer_y, stride_y, buffer_u, stride_u, buffer_v, stride_v);