diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java index 23cc2142a..1b0983a48 100644 --- a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java +++ b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java @@ -33,7 +33,6 @@ import android.test.suitebuilder.annotation.SmallTest; import org.webrtc.VideoCapturerAndroid.CaptureFormat; import org.webrtc.VideoRenderer.I420Frame; -import java.nio.ByteBuffer; import java.util.ArrayList; @SuppressWarnings("deprecation") @@ -79,12 +78,11 @@ public class VideoCapturerAndroidTest extends ActivityTestCase { } @Override - public void OnFrameCaptured(ByteBuffer frame, int rotation, + public void OnFrameCaptured(byte[] frame, int length, int rotation, long timeStamp) { - assertTrue(frame.isDirect()); synchronized (frameLock) { ++framesCaptured; - frameSize = frame.capacity(); + frameSize = length; frameLock.notify(); } } diff --git a/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc b/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc index b445be5aa..dfe1b1b7f 100644 --- a/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc +++ b/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc @@ -178,13 +178,20 @@ void AndroidVideoCapturerJni::OnIncomingFrame_w(void* video_frame, JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); } JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnFrameCaptured) - (JNIEnv* jni, jclass, jlong j_capturer, jobject j_frame, + (JNIEnv* jni, jclass, jlong j_capturer, jbyteArray j_frame, jint length, jint rotation, jlong ts) { - void* bytes = jni->GetDirectBufferAddress(j_frame); - DCHECK(bytes != NULL); - jlong length = jni->GetDirectBufferCapacity(j_frame); - reinterpret_cast( - j_capturer)->OnIncomingFrame(bytes, length, rotation, ts); + jboolean is_copy = true; + jbyte* bytes = jni->GetByteArrayElements(j_frame, &is_copy); + if (!is_copy) { + reinterpret_cast( + j_capturer)->OnIncomingFrame(bytes, length, rotation, ts); + } else { + // If this is a copy of the original frame, it means that the memory + // is not direct memory and thus VideoCapturerAndroid does not guarantee + // that the memory is valid when we have released |j_frame|. + DCHECK(false) << "j_frame is a copy."; + } + jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT); } JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeCapturerStarted) diff --git a/talk/app/webrtc/java/src/org/webrtc/VideoCapturerAndroid.java b/talk/app/webrtc/java/src/org/webrtc/VideoCapturerAndroid.java index 8b4771d97..bb0b338aa 100644 --- a/talk/app/webrtc/java/src/org/webrtc/VideoCapturerAndroid.java +++ b/talk/app/webrtc/java/src/org/webrtc/VideoCapturerAndroid.java @@ -536,10 +536,11 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba rotation = 360 - rotation; } rotation = (info.orientation + rotation) % 360; - - frameObserver.OnFrameCaptured( - videoBuffers.reserveByteBuffer(data, captureTimeMs), - rotation, + // Mark the frame owning |data| as used. + // Note that since data is directBuffer, + // data.length >= videoBuffers.frameSize. + videoBuffers.reserveByteBuffer(data, captureTimeMs); + frameObserver.OnFrameCaptured(data, videoBuffers.frameSize, rotation, captureTimeMs); } @@ -578,14 +579,14 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba // potentially stalling the capturer if it runs out of buffers to write to). private static int numCaptureBuffers = 3; private final Frame cameraFrames[]; + public final int frameSize; private static class Frame { - public final ByteBuffer buffer; + private final ByteBuffer buffer; public long timeStamp = -1; - Frame(int width, int height, int format) { - int bufSize = width * height * ImageFormat.getBitsPerPixel(format) / 8; - buffer = ByteBuffer.allocateDirect(bufSize); + Frame(int frameSize) { + buffer = ByteBuffer.allocateDirect(frameSize); } byte[] data() { @@ -595,8 +596,9 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba FramePool(int width, int height, int format) { cameraFrames = new Frame[numCaptureBuffers]; + frameSize = width * height * ImageFormat.getBitsPerPixel(format) / 8; for (int i = 0; i < numCaptureBuffers; i++) { - cameraFrames[i] = new Frame(width, height, format); + cameraFrames[i] = new Frame(frameSize); } } @@ -608,11 +610,11 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba } } - ByteBuffer reserveByteBuffer(byte[] data, long timeStamp) { + void reserveByteBuffer(byte[] data, long timeStamp) { for (Frame frame : cameraFrames) { if (data == frame.data()) { frame.timeStamp = timeStamp; - return frame.buffer; + return; } } throw new RuntimeException("unknown data buffer?!?"); @@ -639,7 +641,8 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba // Delivers a captured frame. Called on a Java thread owned by // VideoCapturerAndroid. - abstract void OnFrameCaptured(ByteBuffer buffer, int rotation, long timeStamp); + abstract void OnFrameCaptured(byte[] data, int length, int rotation, + long timeStamp); } // An implementation of CapturerObserver that forwards all calls from @@ -657,14 +660,14 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba } @Override - public void OnFrameCaptured(ByteBuffer byteBuffer, int rotation, + public void OnFrameCaptured(byte[] data, int length, int rotation, long timeStamp) { - nativeOnFrameCaptured(nativeCapturer, byteBuffer, rotation, timeStamp); + nativeOnFrameCaptured(nativeCapturer, data, length, rotation, timeStamp); } private native void nativeCapturerStarted(long nativeCapturer, boolean success); private native void nativeOnFrameCaptured(long nativeCapturer, - ByteBuffer byteBuffer, int rotation, long timeStamp); + byte[] data, int length, int rotation, long timeStamp); } }