diff --git a/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java b/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java index 0030d8407..67b8c8c83 100644 --- a/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java +++ b/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java @@ -555,9 +555,9 @@ public class VideoRendererGui implements GLSurfaceView.Renderer { } // Check input frame parameters. if (frame.yuvFrame) { - if (!(frame.yuvStrides[0] == frame.width && - frame.yuvStrides[1] == frame.width / 2 && - frame.yuvStrides[2] == frame.width / 2)) { + if (frame.yuvStrides[0] < frame.width || + frame.yuvStrides[1] < frame.width / 2 || + frame.yuvStrides[2] < frame.width / 2) { Log.e(TAG, "Incorrect strides " + frame.yuvStrides[0] + ", " + frame.yuvStrides[1] + ", " + frame.yuvStrides[2]); return; diff --git a/talk/app/webrtc/java/jni/peerconnection_jni.cc b/talk/app/webrtc/java/jni/peerconnection_jni.cc index d6346d988..c15d28f71 100644 --- a/talk/app/webrtc/java/jni/peerconnection_jni.cc +++ b/talk/app/webrtc/java/jni/peerconnection_jni.cc @@ -3223,6 +3223,32 @@ JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)( return (jlong)renderer.release(); } +JOW(void, VideoRenderer_nativeCopyPlane)( + JNIEnv *jni, jclass, jobject j_src_buffer, jint width, jint height, + jint src_stride, jobject j_dst_buffer, jint dst_stride) { + size_t src_size = jni->GetDirectBufferCapacity(j_src_buffer); + size_t dst_size = jni->GetDirectBufferCapacity(j_dst_buffer); + CHECK(src_stride >= width) << "Wrong source stride " << src_stride; + CHECK(dst_stride >= width) << "Wrong destination stride " << dst_stride; + CHECK(src_size >= src_stride * height) + << "Insufficient source buffer capacity " << src_size; + CHECK(dst_size >= dst_stride * height) + << "Isufficient destination buffer capacity " << dst_size; + uint8_t *src = + reinterpret_cast(jni->GetDirectBufferAddress(j_src_buffer)); + uint8_t *dst = + reinterpret_cast(jni->GetDirectBufferAddress(j_dst_buffer)); + if (src_stride == dst_stride) { + memcpy(dst, src, src_stride * height); + } else { + for (int i = 0; i < height; i++) { + memcpy(dst, src, width); + src += src_stride; + dst += dst_stride; + } + } +} + JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) { cricket::VideoCapturer* capturer = reinterpret_cast(j_p)->GetVideoCapturer(); diff --git a/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java b/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java index f700a1325..82b900203 100644 --- a/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java +++ b/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java @@ -61,8 +61,8 @@ public class VideoRenderer { if (yuvPlanes == null) { yuvPlanes = new ByteBuffer[3]; yuvPlanes[0] = ByteBuffer.allocateDirect(yuvStrides[0] * height); - yuvPlanes[1] = ByteBuffer.allocateDirect(yuvStrides[1] * height); - yuvPlanes[2] = ByteBuffer.allocateDirect(yuvStrides[2] * height); + yuvPlanes[1] = ByteBuffer.allocateDirect(yuvStrides[1] * height / 2); + yuvPlanes[2] = ByteBuffer.allocateDirect(yuvStrides[2] * height / 2); } this.yuvPlanes = yuvPlanes; this.yuvFrame = true; @@ -89,14 +89,16 @@ public class VideoRenderer { */ public I420Frame copyFrom(I420Frame source) { if (source.yuvFrame && yuvFrame) { - if (!Arrays.equals(yuvStrides, source.yuvStrides) || - width != source.width || height != source.height) { + if (width != source.width || height != source.height) { throw new RuntimeException("Mismatched dimensions! Source: " + source.toString() + ", destination: " + toString()); } - copyPlane(source.yuvPlanes[0], yuvPlanes[0]); - copyPlane(source.yuvPlanes[1], yuvPlanes[1]); - copyPlane(source.yuvPlanes[2], yuvPlanes[2]); + nativeCopyPlane(source.yuvPlanes[0], width, height, + source.yuvStrides[0], yuvPlanes[0], yuvStrides[0]); + nativeCopyPlane(source.yuvPlanes[1], width / 2, height / 2, + source.yuvStrides[1], yuvPlanes[1], yuvStrides[1]); + nativeCopyPlane(source.yuvPlanes[2], width / 2, height / 2, + source.yuvStrides[2], yuvPlanes[2], yuvStrides[2]); return this; } else if (!source.yuvFrame && !yuvFrame) { textureObject = source.textureObject; @@ -109,42 +111,37 @@ public class VideoRenderer { } public I420Frame copyFrom(byte[] yuvData) { - if (yuvData.length < width * height * 3 / 2) { - throw new RuntimeException("Wrong arrays size: " + yuvData.length); - } - if (!yuvFrame) { - throw new RuntimeException("Can not feed yuv data to texture frame"); - } - int planeSize = width * height; - ByteBuffer[] planes = new ByteBuffer[3]; - planes[0] = ByteBuffer.wrap(yuvData, 0, planeSize); - planes[1] = ByteBuffer.wrap(yuvData, planeSize, planeSize / 4); - planes[2] = ByteBuffer.wrap(yuvData, planeSize + planeSize / 4, - planeSize / 4); - for (int i = 0; i < 3; i++) { - yuvPlanes[i].position(0); - yuvPlanes[i].put(planes[i]); - yuvPlanes[i].position(0); - yuvPlanes[i].limit(yuvPlanes[i].capacity()); - } - return this; + if (yuvData.length < width * height * 3 / 2) { + throw new RuntimeException("Wrong arrays size: " + yuvData.length); } - + if (!yuvFrame) { + throw new RuntimeException("Can not feed yuv data to texture frame"); + } + int planeSize = width * height; + ByteBuffer[] planes = new ByteBuffer[3]; + planes[0] = ByteBuffer.wrap(yuvData, 0, planeSize); + planes[1] = ByteBuffer.wrap(yuvData, planeSize, planeSize / 4); + planes[2] = ByteBuffer.wrap(yuvData, planeSize + planeSize / 4, + planeSize / 4); + for (int i = 0; i < 3; i++) { + yuvPlanes[i].position(0); + yuvPlanes[i].put(planes[i]); + yuvPlanes[i].position(0); + yuvPlanes[i].limit(yuvPlanes[i].capacity()); + } + return this; + } @Override public String toString() { return width + "x" + height + ":" + yuvStrides[0] + ":" + yuvStrides[1] + ":" + yuvStrides[2]; } + } - // Copy the bytes out of |src| and into |dst|, ignoring and overwriting - // positon & limit in both buffers. - private void copyPlane(ByteBuffer src, ByteBuffer dst) { - src.position(0).limit(src.capacity()); - dst.put(src); - dst.position(0).limit(dst.capacity()); - } -} + // Helper native function to do a video frame plane copying. + private static native void nativeCopyPlane(ByteBuffer src, int width, + int height, int srcStride, ByteBuffer dst, int dstStride); /** The real meat of VideoRendererInterface. */ public static interface Callbacks {