Fix Android video renderer to support video frames
with stride > width. Recent libvpx update generates output video frames with stride value greater than width, which was not supported by Android OpenGL video renderer (Android GLES2 doesn't have GL_UNPACK_ROW_LENGTH to provide stride information for buffer in glTexImage2D call). Fix it by implementing native frame copying for Java VideoRenderer.I420Frame implementation. BUG=4248 R=braveyao@webrtc.org Review URL: https://webrtc-codereview.appspot.com/40639004 Cr-Commit-Position: refs/heads/master@{#8252} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8252 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
cc64a9cc4f
commit
f6932297e7
@ -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;
|
||||
|
@ -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<uint8_t*>(jni->GetDirectBufferAddress(j_src_buffer));
|
||||
uint8_t *dst =
|
||||
reinterpret_cast<uint8_t*>(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<VideoSourceInterface*>(j_p)->GetVideoCapturer();
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user