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.
|
// Check input frame parameters.
|
||||||
if (frame.yuvFrame) {
|
if (frame.yuvFrame) {
|
||||||
if (!(frame.yuvStrides[0] == frame.width &&
|
if (frame.yuvStrides[0] < frame.width ||
|
||||||
frame.yuvStrides[1] == frame.width / 2 &&
|
frame.yuvStrides[1] < frame.width / 2 ||
|
||||||
frame.yuvStrides[2] == frame.width / 2)) {
|
frame.yuvStrides[2] < frame.width / 2) {
|
||||||
Log.e(TAG, "Incorrect strides " + frame.yuvStrides[0] + ", " +
|
Log.e(TAG, "Incorrect strides " + frame.yuvStrides[0] + ", " +
|
||||||
frame.yuvStrides[1] + ", " + frame.yuvStrides[2]);
|
frame.yuvStrides[1] + ", " + frame.yuvStrides[2]);
|
||||||
return;
|
return;
|
||||||
|
@ -3223,6 +3223,32 @@ JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
|
|||||||
return (jlong)renderer.release();
|
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) {
|
JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
|
||||||
cricket::VideoCapturer* capturer =
|
cricket::VideoCapturer* capturer =
|
||||||
reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
|
reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
|
||||||
|
@ -61,8 +61,8 @@ public class VideoRenderer {
|
|||||||
if (yuvPlanes == null) {
|
if (yuvPlanes == null) {
|
||||||
yuvPlanes = new ByteBuffer[3];
|
yuvPlanes = new ByteBuffer[3];
|
||||||
yuvPlanes[0] = ByteBuffer.allocateDirect(yuvStrides[0] * height);
|
yuvPlanes[0] = ByteBuffer.allocateDirect(yuvStrides[0] * height);
|
||||||
yuvPlanes[1] = ByteBuffer.allocateDirect(yuvStrides[1] * height);
|
yuvPlanes[1] = ByteBuffer.allocateDirect(yuvStrides[1] * height / 2);
|
||||||
yuvPlanes[2] = ByteBuffer.allocateDirect(yuvStrides[2] * height);
|
yuvPlanes[2] = ByteBuffer.allocateDirect(yuvStrides[2] * height / 2);
|
||||||
}
|
}
|
||||||
this.yuvPlanes = yuvPlanes;
|
this.yuvPlanes = yuvPlanes;
|
||||||
this.yuvFrame = true;
|
this.yuvFrame = true;
|
||||||
@ -89,14 +89,16 @@ public class VideoRenderer {
|
|||||||
*/
|
*/
|
||||||
public I420Frame copyFrom(I420Frame source) {
|
public I420Frame copyFrom(I420Frame source) {
|
||||||
if (source.yuvFrame && yuvFrame) {
|
if (source.yuvFrame && yuvFrame) {
|
||||||
if (!Arrays.equals(yuvStrides, source.yuvStrides) ||
|
if (width != source.width || height != source.height) {
|
||||||
width != source.width || height != source.height) {
|
|
||||||
throw new RuntimeException("Mismatched dimensions! Source: " +
|
throw new RuntimeException("Mismatched dimensions! Source: " +
|
||||||
source.toString() + ", destination: " + toString());
|
source.toString() + ", destination: " + toString());
|
||||||
}
|
}
|
||||||
copyPlane(source.yuvPlanes[0], yuvPlanes[0]);
|
nativeCopyPlane(source.yuvPlanes[0], width, height,
|
||||||
copyPlane(source.yuvPlanes[1], yuvPlanes[1]);
|
source.yuvStrides[0], yuvPlanes[0], yuvStrides[0]);
|
||||||
copyPlane(source.yuvPlanes[2], yuvPlanes[2]);
|
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;
|
return this;
|
||||||
} else if (!source.yuvFrame && !yuvFrame) {
|
} else if (!source.yuvFrame && !yuvFrame) {
|
||||||
textureObject = source.textureObject;
|
textureObject = source.textureObject;
|
||||||
@ -130,21 +132,16 @@ public class VideoRenderer {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return width + "x" + height + ":" + yuvStrides[0] + ":" + yuvStrides[1] +
|
return width + "x" + height + ":" + yuvStrides[0] + ":" + yuvStrides[1] +
|
||||||
":" + yuvStrides[2];
|
":" + yuvStrides[2];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Copy the bytes out of |src| and into |dst|, ignoring and overwriting
|
// Helper native function to do a video frame plane copying.
|
||||||
// positon & limit in both buffers.
|
private static native void nativeCopyPlane(ByteBuffer src, int width,
|
||||||
private void copyPlane(ByteBuffer src, ByteBuffer dst) {
|
int height, int srcStride, ByteBuffer dst, int dstStride);
|
||||||
src.position(0).limit(src.capacity());
|
|
||||||
dst.put(src);
|
|
||||||
dst.position(0).limit(dst.capacity());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The real meat of VideoRendererInterface. */
|
/** The real meat of VideoRendererInterface. */
|
||||||
public static interface Callbacks {
|
public static interface Callbacks {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user