diff --git a/Basic-Video-Driver-Java/app/src/main/java/com/tokbox/sample/basicvideodriver/InvertedColorsVideoRenderer.java b/Basic-Video-Driver-Java/app/src/main/java/com/tokbox/sample/basicvideodriver/InvertedColorsVideoRenderer.java index 3605f087..1373e229 100644 --- a/Basic-Video-Driver-Java/app/src/main/java/com/tokbox/sample/basicvideodriver/InvertedColorsVideoRenderer.java +++ b/Basic-Video-Driver-Java/app/src/main/java/com/tokbox/sample/basicvideodriver/InvertedColorsVideoRenderer.java @@ -202,49 +202,53 @@ void setupTextures(Frame frame) { textureHeight = frame.getHeight(); } + void GlTexSubImage2D(int width, int height, int stride, + ByteBuffer buf) { + if (stride == width) { + // Yay! We can upload the entire plane in a single GL call. + GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width, + height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, + buf); + } else { + for (int row = 0; row < height; ++row) { + buf.position( row * stride); + GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, row, width, + 1, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, + buf); + } + } + } + void updateTextures(Frame frame) { int width = frame.getWidth(); int height = frame.getHeight(); int half_width = (width + 1) >> 1; int half_height = (height + 1) >> 1; - int y_size = width * height; - int uv_size = half_width * half_height; ByteBuffer bb = frame.getBuffer(); - // If we are reusing this frame, make sure we reset position and - // limit bb.clear(); - - if (bb.remaining() == y_size + uv_size * 2) { - bb.position(0); - - GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); - GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1); - - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width, - height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, - bb); - - bb.position(y_size); - GLES20.glActiveTexture(GLES20.GL_TEXTURE1); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[1]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, - half_width, half_height, GLES20.GL_LUMINANCE, - GLES20.GL_UNSIGNED_BYTE, bb); - - bb.position(y_size + uv_size); - GLES20.glActiveTexture(GLES20.GL_TEXTURE2); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[2]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, - half_width, half_height, GLES20.GL_LUMINANCE, - GLES20.GL_UNSIGNED_BYTE, bb); - } else { + //check if buffer data is correctly sized. + if (bb.remaining() != frame.getYplaneSize() + frame.getUVplaneSize() * 2) { textureWidth = 0; textureHeight = 0; + return; } + + bb.position(0); + GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); + GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]); + GlTexSubImage2D(width, height, frame.getYstride(), frame.getYplane()); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE1); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[1]); + GlTexSubImage2D(half_width, half_height, frame.getUvStride(), frame.getUplane()); + GLES20.glActiveTexture(GLES20.GL_TEXTURE2); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[2]); + GlTexSubImage2D(half_width, half_height, frame.getUvStride(), frame.getVplane()); } @Override diff --git a/Basic-Video-Renderer-Java/app/src/main/java/com/tokbox/sample/basicvideorenderer/InvertedColorsVideoRenderer.java b/Basic-Video-Renderer-Java/app/src/main/java/com/tokbox/sample/basicvideorenderer/InvertedColorsVideoRenderer.java index 88714bc8..7f0c2a5d 100644 --- a/Basic-Video-Renderer-Java/app/src/main/java/com/tokbox/sample/basicvideorenderer/InvertedColorsVideoRenderer.java +++ b/Basic-Video-Renderer-Java/app/src/main/java/com/tokbox/sample/basicvideorenderer/InvertedColorsVideoRenderer.java @@ -77,7 +77,7 @@ static class MyRenderer implements GLSurfaceView.Renderer { + " v=texture2D(Vtex,vec2(nx,ny)).r;\n" + " y=1.0-1.1643*(y-0.0625);\n" // this line produces the inverted effect - // + " y=1.1643*(y-0.0625);\n" // use this line instead if you want to have normal colors + // + " y=1.1643*(y-0.0625);\n" // use this line instead if you want to have normal colors + " u=u-0.5;\n" + " v=v-0.5;\n" + " r=y+1.5958*v;\n" + " g=y-0.39173*u-0.81290*v;\n" + " b=y+2.017*u;\n" @@ -202,49 +202,52 @@ void setupTextures(Frame frame) { textureHeight = frame.getHeight(); } + void GlTexSubImage2D(int width, int height, int stride, + ByteBuffer buf) { + if (stride == width) { + // Yay! We can upload the entire plane in a single GL call. + GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width, + height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, + buf); + } else { + for (int row = 0; row < height; ++row) { + buf.position( row * stride); + GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, row, width, + 1, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, + buf); + } + } + } + void updateTextures(Frame frame) { int width = frame.getWidth(); int height = frame.getHeight(); int half_width = (width + 1) >> 1; int half_height = (height + 1) >> 1; - int y_size = width * height; - int uv_size = half_width * half_height; ByteBuffer bb = frame.getBuffer(); - // If we are reusing this frame, make sure we reset position and - // limit bb.clear(); - - if (bb.remaining() == y_size + uv_size * 2) { - bb.position(0); - - GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); - GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1); - - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width, - height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, - bb); - - bb.position(y_size); - GLES20.glActiveTexture(GLES20.GL_TEXTURE1); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[1]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, - half_width, half_height, GLES20.GL_LUMINANCE, - GLES20.GL_UNSIGNED_BYTE, bb); - - bb.position(y_size + uv_size); - GLES20.glActiveTexture(GLES20.GL_TEXTURE2); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[2]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, - half_width, half_height, GLES20.GL_LUMINANCE, - GLES20.GL_UNSIGNED_BYTE, bb); - } else { + //check if buffer data is correctly sized. + if (bb.remaining() != frame.getYplaneSize() + frame.getUVplaneSize() * 2) { textureWidth = 0; textureHeight = 0; + return; } + bb.position(0); + GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); + GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]); + GlTexSubImage2D(width, height, frame.getYstride(), frame.getYplane()); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE1); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[1]); + GlTexSubImage2D(half_width, half_height, frame.getUvStride(), frame.getUplane()); + GLES20.glActiveTexture(GLES20.GL_TEXTURE2); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[2]); + GlTexSubImage2D(half_width, half_height, frame.getUvStride(), frame.getVplane()); } @Override diff --git a/Frame-Metadata-Java/app/src/main/java/com/tokbox/sample/framemetadata/ReceiveFrameMetaDataRenderer.java b/Frame-Metadata-Java/app/src/main/java/com/tokbox/sample/framemetadata/ReceiveFrameMetaDataRenderer.java index 30015d80..90eaba7b 100644 --- a/Frame-Metadata-Java/app/src/main/java/com/tokbox/sample/framemetadata/ReceiveFrameMetaDataRenderer.java +++ b/Frame-Metadata-Java/app/src/main/java/com/tokbox/sample/framemetadata/ReceiveFrameMetaDataRenderer.java @@ -198,49 +198,53 @@ void setupTextures(Frame frame) { textureHeight = frame.getHeight(); } + void GlTexSubImage2D(int width, int height, int stride, + ByteBuffer buf) { + if (stride == width) { + // Yay! We can upload the entire plane in a single GL call. + GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width, + height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, + buf); + } else { + for (int row = 0; row < height; ++row) { + buf.position( row * stride); + GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, row, width, + 1, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, + buf); + } + } + } + void updateTextures(Frame frame) { int width = frame.getWidth(); int height = frame.getHeight(); int half_width = (width + 1) >> 1; int half_height = (height + 1) >> 1; - int y_size = width * height; - int uv_size = half_width * half_height; ByteBuffer bb = frame.getBuffer(); - // If we are reusing this frame, make sure we reset position and - // limit bb.clear(); - - if (bb.remaining() == y_size + uv_size * 2) { - bb.position(0); - - GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); - GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1); - - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width, - height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, - bb); - - bb.position(y_size); - GLES20.glActiveTexture(GLES20.GL_TEXTURE1); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[1]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, - half_width, half_height, GLES20.GL_LUMINANCE, - GLES20.GL_UNSIGNED_BYTE, bb); - - bb.position(y_size + uv_size); - GLES20.glActiveTexture(GLES20.GL_TEXTURE2); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[2]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, - half_width, half_height, GLES20.GL_LUMINANCE, - GLES20.GL_UNSIGNED_BYTE, bb); - } else { + //check if buffer data is correctly sized. + if (bb.remaining() != frame.getYplaneSize() + frame.getUVplaneSize() * 2) { textureWidth = 0; textureHeight = 0; + return; } + bb.position(0); + GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); + GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]); + GlTexSubImage2D(width, height, frame.getYstride(), frame.getYplane()); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE1); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[1]); + GlTexSubImage2D(half_width, half_height, frame.getUvStride(), frame.getUplane()); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE2); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[2]); + GlTexSubImage2D(half_width, half_height, frame.getUvStride(), frame.getVplane()); } @Override diff --git a/Live-Photo-Capture-Java/app/src/main/java/com/tokbox/sample/livephotocapture/ScreenshotVideoRenderer.java b/Live-Photo-Capture-Java/app/src/main/java/com/tokbox/sample/livephotocapture/ScreenshotVideoRenderer.java index 3ef02590..3360dcf8 100644 --- a/Live-Photo-Capture-Java/app/src/main/java/com/tokbox/sample/livephotocapture/ScreenshotVideoRenderer.java +++ b/Live-Photo-Capture-Java/app/src/main/java/com/tokbox/sample/livephotocapture/ScreenshotVideoRenderer.java @@ -198,44 +198,53 @@ void setupTextures(Frame frame) { textureHeight = frame.getHeight(); } + void GlTexSubImage2D(int width, int height, int stride, + ByteBuffer buf) { + if (stride == width) { + // Yay! We can upload the entire plane in a single GL call. + GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width, + height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, + buf); + } else { + for (int row = 0; row < height; ++row) { + buf.position( row * stride); + GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, row, width, + 1, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, + buf); + } + } + } + void updateTextures(Frame frame) { int width = frame.getWidth(); int height = frame.getHeight(); int half_width = (width + 1) >> 1; int half_height = (height + 1) >> 1; - int y_size = width * height; - int uv_size = half_width * half_height; ByteBuffer bb = frame.getBuffer(); - // If we are reusing this frame, make sure we reset position and - // limit bb.clear(); - - if (bb.remaining() == y_size + uv_size * 2) { - bb.position(0); - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width, - height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, - bb); - - bb.position(y_size); - GLES20.glActiveTexture(GLES20.GL_TEXTURE1); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[1]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, - half_width, half_height, GLES20.GL_LUMINANCE, - GLES20.GL_UNSIGNED_BYTE, bb); - - bb.position(y_size + uv_size); - GLES20.glActiveTexture(GLES20.GL_TEXTURE2); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[2]); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, - half_width, half_height, GLES20.GL_LUMINANCE, - GLES20.GL_UNSIGNED_BYTE, bb); - } else { + //check if buffer data is correctly sized. + if (bb.remaining() != frame.getYplaneSize() + frame.getUVplaneSize() * 2) { textureWidth = 0; textureHeight = 0; + return; } + + bb.position(0); + GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1); + GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]); + GlTexSubImage2D(width, height, frame.getYstride(), frame.getYplane()); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE1); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[1]); + GlTexSubImage2D(half_width, half_height, frame.getUvStride(), frame.getUplane()); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE2); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[2]); + GlTexSubImage2D(half_width, half_height, frame.getUvStride(), frame.getVplane()); } @Override diff --git a/Live-Photo-Capture-Kotlin/app/src/main/java/com/tokbox/sample/livephotocapture/ScreenshotVideoRenderer.kt b/Live-Photo-Capture-Kotlin/app/src/main/java/com/tokbox/sample/livephotocapture/ScreenshotVideoRenderer.kt index 6308d241..add4bcea 100644 --- a/Live-Photo-Capture-Kotlin/app/src/main/java/com/tokbox/sample/livephotocapture/ScreenshotVideoRenderer.kt +++ b/Live-Photo-Capture-Kotlin/app/src/main/java/com/tokbox/sample/livephotocapture/ScreenshotVideoRenderer.kt @@ -127,46 +127,54 @@ void main(void) { textureHeight = frame.height } + private fun GlTexSubImage2D(width: Int, height: Int, stride: Int, + buf: ByteBuffer) { + if (stride == width) { + // Yay! We can upload the entire plane in a single GL call. + GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width, + height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, + buf) + } else { + for (row in 0 until height) { + buf.position( row * stride) + GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, row, width, + 1, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, + buf) + } + } + } + private fun updateTextures(frame: Frame) { - val width = frame.width - val height = frame.height + val width = frame.getWidth() + val height = frame.getHeight() val half_width = width + 1 shr 1 val half_height = height + 1 shr 1 - val y_size = width * height - val uv_size = half_width * half_height + val bb = frame.buffer // If we are reusing this frame, make sure we reset position and // limit bb.clear() - if (bb.remaining() == y_size + uv_size * 2) { - bb.position(0) - GLES20.glActiveTexture(GLES20.GL_TEXTURE0) - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]) - GLES20.glTexSubImage2D( - GLES20.GL_TEXTURE_2D, 0, 0, 0, width, - height, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, - bb - ) - bb.position(y_size) - GLES20.glActiveTexture(GLES20.GL_TEXTURE1) - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[1]) - GLES20.glTexSubImage2D( - GLES20.GL_TEXTURE_2D, 0, 0, 0, - half_width, half_height, GLES20.GL_LUMINANCE, - GLES20.GL_UNSIGNED_BYTE, bb - ) - bb.position(y_size + uv_size) - GLES20.glActiveTexture(GLES20.GL_TEXTURE2) - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[2]) - GLES20.glTexSubImage2D( - GLES20.GL_TEXTURE_2D, 0, 0, 0, - half_width, half_height, GLES20.GL_LUMINANCE, - GLES20.GL_UNSIGNED_BYTE, bb - ) - } else { + if (bb.remaining() != frame.getYplaneSize() + frame.getUVplaneSize() * 2) { textureWidth = 0 textureHeight = 0 + return } + + bb.position(0) + GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1) + GLES20.glPixelStorei(GLES20.GL_PACK_ALIGNMENT, 1) + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0) + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]) + GlTexSubImage2D(width, height, frame.getYstride(), frame.getYplane()) + + GLES20.glActiveTexture(GLES20.GL_TEXTURE1) + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[1]) + GlTexSubImage2D(half_width, half_height, frame.getUvStride(), frame.getUplane()) + + GLES20.glActiveTexture(GLES20.GL_TEXTURE2) + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[2]) + GlTexSubImage2D(half_width, half_height, frame.getUvStride(), frame.getVplane()) } override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) { @@ -433,4 +441,4 @@ void main(void) { view.setRenderer(renderer) view.renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY } -} \ No newline at end of file +}