diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java index 73ed381ad9..0fe827d1f9 100644 --- a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java +++ b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java @@ -35,7 +35,6 @@ import android.util.Size; import org.webrtc.CameraEnumerationAndroid.CaptureFormat; import org.webrtc.VideoRenderer.I420Frame; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -105,11 +104,11 @@ public class VideoCapturerAndroidTest extends ActivityTestCase { } @Override - public void OnFrameCaptured(ByteBuffer frame, int width, int height, + public void OnFrameCaptured(byte[] frame, int length, int width, int height, int rotation, long timeStamp) { synchronized (frameLock) { ++framesCaptured; - frameSize = frame.capacity(); + frameSize = length; timestamps.add(timeStamp); frameLock.notify(); } diff --git a/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java b/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java index 72b62c3f9f..ee01eede9e 100644 --- a/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java +++ b/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java @@ -569,11 +569,12 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba } rotation = (info.orientation + rotation) % 360; // Mark the frame owning |data| as used. - final ByteBuffer buffer = videoBuffers.reserveByteBuffer(data, captureTimeNs); - if (buffer != null) { + // Note that since data is directBuffer, + // data.length >= videoBuffers.frameSize. + if (videoBuffers.reserveByteBuffer(data, captureTimeNs)) { cameraFramesCount++; - frameObserver.OnFrameCaptured(buffer, captureFormat.width, captureFormat.height, - rotation, captureTimeNs); + frameObserver.OnFrameCaptured(data, videoBuffers.frameSize, captureFormat.width, + captureFormat.height, rotation, captureTimeNs); } else { Logging.w(TAG, "reserveByteBuffer failed - dropping frame."); } @@ -655,8 +656,7 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba : " Pending buffers: " + pendingFramesTimeStamps() + ".")); } - // Returns the reserved byte buffer, or null on failure. - public ByteBuffer reserveByteBuffer(byte[] data, long timeStamp) { + public boolean reserveByteBuffer(byte[] data, long timeStamp) { checkIsOnValidThread(); final ByteBuffer buffer = queuedBuffers.remove(data); if (buffer == null) { @@ -664,21 +664,21 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba // capture format in |startPreviewOnCameraThread|. Drop these old frames. Logging.w(TAG, "Received callback buffer from previous configuration with length: " + (data == null ? "null" : data.length)); - return null; + return false; } if (buffer.capacity() != frameSize) { throw new IllegalStateException("Callback buffer has unexpected frame size"); } if (pendingBuffers.containsKey(timeStamp)) { Logging.e(TAG, "Timestamp already present in pending buffers - they need to be unique"); - return null; + return false; } pendingBuffers.put(timeStamp, buffer); if (queuedBuffers.isEmpty()) { Logging.v(TAG, "Camera is running out of capture buffers." + " Pending buffers: " + pendingFramesTimeStamps()); } - return buffer; + return true; } public void returnBuffer(long timeStamp) { @@ -722,8 +722,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 width, int height, int rotation, - long timeStamp); + abstract void OnFrameCaptured(byte[] data, int length, int width, int height, + int rotation, long timeStamp); // Requests an output format from the video capturer. Captured frames // by the camera will be scaled/or dropped by the video capturer. @@ -746,9 +746,9 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba } @Override - public void OnFrameCaptured(ByteBuffer buffer, int width, int height, int rotation, - long timeStamp) { - nativeOnFrameCaptured(nativeCapturer, buffer, width, height, rotation, timeStamp); + public void OnFrameCaptured(byte[] data, int length, int width, int height, + int rotation, long timeStamp) { + nativeOnFrameCaptured(nativeCapturer, data, length, width, height, rotation, timeStamp); } @Override @@ -759,7 +759,7 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba private native void nativeCapturerStarted(long nativeCapturer, boolean success); private native void nativeOnFrameCaptured(long nativeCapturer, - ByteBuffer buffer, int width, int height, int rotation, long timeStamp); + byte[] data, int length, int width, int height, int rotation, long timeStamp); private native void nativeOnOutputFormatRequest(long nativeCapturer, int width, int height, int fps); } diff --git a/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc b/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc index eae87bd8ce..74a9372d86 100644 --- a/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc +++ b/talk/app/webrtc/java/jni/androidvideocapturer_jni.cc @@ -176,13 +176,13 @@ void AndroidVideoCapturerJni::OnCapturerStarted(bool success) { success); } -void AndroidVideoCapturerJni::OnIncomingFrame(const uint8_t* video_frame, +void AndroidVideoCapturerJni::OnIncomingFrame(void* video_frame, int length, int width, int height, int rotation, int64 time_stamp) { - const uint8_t* y_plane = video_frame; + const uint8_t* y_plane = static_cast(video_frame); // Android guarantees that the stride is a multiple of 16. // http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFormat%28int%29 int y_stride; @@ -215,14 +215,20 @@ void AndroidVideoCapturerJni::OnOutputFormatRequest(int width, JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); } JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnFrameCaptured) - (JNIEnv* jni, jclass, jlong j_capturer, jobject j_byte_buffer, + (JNIEnv* jni, jclass, jlong j_capturer, jbyteArray j_frame, jint length, jint width, jint height, jint rotation, jlong ts) { - const uint8_t* bytes = - static_cast(jni->GetDirectBufferAddress(j_byte_buffer)); - const int length = jni->GetDirectBufferCapacity(j_byte_buffer); - RTC_CHECK(bytes != nullptr && length != -1) << "ByteBuffer is not direct"; + jboolean is_copy = true; + jbyte* bytes = jni->GetByteArrayElements(j_frame, &is_copy); + // 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|. + // TODO(magjed): Move ReleaseByteArrayElements() into ReturnBuffer() and + // remove this check. + RTC_CHECK(!is_copy) + << "NativeObserver_nativeOnFrameCaptured: frame is a copy"; reinterpret_cast(j_capturer) ->OnIncomingFrame(bytes, length, width, height, rotation, ts); + jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT); } JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeCapturerStarted) diff --git a/talk/app/webrtc/java/jni/androidvideocapturer_jni.h b/talk/app/webrtc/java/jni/androidvideocapturer_jni.h index 0c2b5fd925..c270439377 100644 --- a/talk/app/webrtc/java/jni/androidvideocapturer_jni.h +++ b/talk/app/webrtc/java/jni/androidvideocapturer_jni.h @@ -61,7 +61,7 @@ class AndroidVideoCapturerJni : public webrtc::AndroidVideoCapturerDelegate { // Called from VideoCapturerAndroid::NativeObserver on a Java thread. void OnCapturerStarted(bool success); - void OnIncomingFrame(const uint8_t* video_frame, + void OnIncomingFrame(void* video_frame, int length, int width, int height,