Add checks for buffer size in MediaCodecVideoEncoder.

This should help users of the library to more easily debug issues.

Bug: None
Change-Id: I85d8101d3b26ccbc34c8beded069461252e61293
Reviewed-on: https://webrtc-review.googlesource.com/4663
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Commit-Queue: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20073}
diff --git a/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java b/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java
index 227c5a4..b009893 100644
--- a/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java
+++ b/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java
@@ -621,9 +621,24 @@
         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 a131121..6ff5412 100644
--- a/sdk/android/api/org/webrtc/VideoFrame.java
+++ b/sdk/android/api/org/webrtc/VideoFrame.java
@@ -58,21 +58,24 @@
    */
   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 07a6339..3882c90 100644
--- a/sdk/android/src/jni/androidmediaencoder_jni.cc
+++ b/sdk/android/src/jni/androidmediaencoder_jni.cc
@@ -1478,6 +1478,13 @@
   uint8_t* buffer_v =
       static_cast<uint8_t*>(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<MediaCodecVideoEncoder*>(native_encoder)
       ->FillInputBuffer(jni, input_buffer, buffer_y, stride_y, buffer_u,
                         stride_u, buffer_v, stride_v);