VideoCapturerAndroid allocates direct buffers so that the frame buffers can be used in C++ without a copy. However byte[] array = ByteBuffer.array() seems to point to the beginning of the underlaying buffer and that is what the camera fills. But it turns out that ByteBuffer.arrayOffset() returns an offset and it seems like the pointer returned by jni->GetDirectBufferAddress(j_frame). This cl reverts back to pass the byte[] to c++ and use jni->GetByteArrayElements to get the address of the buffer.

R=glaznev@webrtc.org, magjed@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/35349004

Cr-Commit-Position: refs/heads/master@{#8535}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8535 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
perkj@webrtc.org 2015-02-27 18:50:53 +00:00
parent 07dcf60ee0
commit 41d8fda12d
3 changed files with 33 additions and 25 deletions

View File

@ -33,7 +33,6 @@ import android.test.suitebuilder.annotation.SmallTest;
import org.webrtc.VideoCapturerAndroid.CaptureFormat; import org.webrtc.VideoCapturerAndroid.CaptureFormat;
import org.webrtc.VideoRenderer.I420Frame; import org.webrtc.VideoRenderer.I420Frame;
import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@ -79,12 +78,11 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
} }
@Override @Override
public void OnFrameCaptured(ByteBuffer frame, int rotation, public void OnFrameCaptured(byte[] frame, int length, int rotation,
long timeStamp) { long timeStamp) {
assertTrue(frame.isDirect());
synchronized (frameLock) { synchronized (frameLock) {
++framesCaptured; ++framesCaptured;
frameSize = frame.capacity(); frameSize = length;
frameLock.notify(); frameLock.notify();
} }
} }

View File

@ -178,13 +178,20 @@ void AndroidVideoCapturerJni::OnIncomingFrame_w(void* video_frame,
JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); } JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); }
JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnFrameCaptured) 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) { jint rotation, jlong ts) {
void* bytes = jni->GetDirectBufferAddress(j_frame); jboolean is_copy = true;
DCHECK(bytes != NULL); jbyte* bytes = jni->GetByteArrayElements(j_frame, &is_copy);
jlong length = jni->GetDirectBufferCapacity(j_frame); if (!is_copy) {
reinterpret_cast<AndroidVideoCapturerJni*>( reinterpret_cast<AndroidVideoCapturerJni*>(
j_capturer)->OnIncomingFrame(bytes, length, rotation, ts); 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) JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeCapturerStarted)

View File

@ -536,10 +536,11 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
rotation = 360 - rotation; rotation = 360 - rotation;
} }
rotation = (info.orientation + rotation) % 360; rotation = (info.orientation + rotation) % 360;
// Mark the frame owning |data| as used.
frameObserver.OnFrameCaptured( // Note that since data is directBuffer,
videoBuffers.reserveByteBuffer(data, captureTimeMs), // data.length >= videoBuffers.frameSize.
rotation, videoBuffers.reserveByteBuffer(data, captureTimeMs);
frameObserver.OnFrameCaptured(data, videoBuffers.frameSize, rotation,
captureTimeMs); 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). // potentially stalling the capturer if it runs out of buffers to write to).
private static int numCaptureBuffers = 3; private static int numCaptureBuffers = 3;
private final Frame cameraFrames[]; private final Frame cameraFrames[];
public final int frameSize;
private static class Frame { private static class Frame {
public final ByteBuffer buffer; private final ByteBuffer buffer;
public long timeStamp = -1; public long timeStamp = -1;
Frame(int width, int height, int format) { Frame(int frameSize) {
int bufSize = width * height * ImageFormat.getBitsPerPixel(format) / 8; buffer = ByteBuffer.allocateDirect(frameSize);
buffer = ByteBuffer.allocateDirect(bufSize);
} }
byte[] data() { byte[] data() {
@ -595,8 +596,9 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
FramePool(int width, int height, int format) { FramePool(int width, int height, int format) {
cameraFrames = new Frame[numCaptureBuffers]; cameraFrames = new Frame[numCaptureBuffers];
frameSize = width * height * ImageFormat.getBitsPerPixel(format) / 8;
for (int i = 0; i < numCaptureBuffers; i++) { 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) { for (Frame frame : cameraFrames) {
if (data == frame.data()) { if (data == frame.data()) {
frame.timeStamp = timeStamp; frame.timeStamp = timeStamp;
return frame.buffer; return;
} }
} }
throw new RuntimeException("unknown data buffer?!?"); 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 // Delivers a captured frame. Called on a Java thread owned by
// VideoCapturerAndroid. // 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 // An implementation of CapturerObserver that forwards all calls from
@ -657,14 +660,14 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
} }
@Override @Override
public void OnFrameCaptured(ByteBuffer byteBuffer, int rotation, public void OnFrameCaptured(byte[] data, int length, int rotation,
long timeStamp) { long timeStamp) {
nativeOnFrameCaptured(nativeCapturer, byteBuffer, rotation, timeStamp); nativeOnFrameCaptured(nativeCapturer, data, length, rotation, timeStamp);
} }
private native void nativeCapturerStarted(long nativeCapturer, private native void nativeCapturerStarted(long nativeCapturer,
boolean success); boolean success);
private native void nativeOnFrameCaptured(long nativeCapturer, private native void nativeOnFrameCaptured(long nativeCapturer,
ByteBuffer byteBuffer, int rotation, long timeStamp); byte[] data, int length, int rotation, long timeStamp);
} }
} }