17db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org/* 27db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * libjingle 37db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * Copyright 2014, Google Inc. 47db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * 57db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * Redistribution and use in source and binary forms, with or without 67db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * modification, are permitted provided that the following conditions are met: 77db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * 87db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * 1. Redistributions of source code must retain the above copyright notice, 97db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * this list of conditions and the following disclaimer. 107db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * 2. Redistributions in binary form must reproduce the above copyright notice, 117db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * this list of conditions and the following disclaimer in the documentation 127db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * and/or other materials provided with the distribution. 137db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * 3. The name of the author may not be used to endorse or promote products 147db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * derived from this software without specific prior written permission. 157db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * 167db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 177db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 187db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 197db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 207db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 217db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 227db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 237db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 247db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 257db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 267db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org */ 277db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 287db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.orgpackage org.webrtc; 297db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 30a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.orgimport android.graphics.SurfaceTexture; 317db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.orgimport android.media.MediaCodec; 32cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.orgimport android.media.MediaCodecInfo; 33a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.orgimport android.media.MediaCodecInfo.CodecCapabilities; 347db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.orgimport android.media.MediaCodecList; 357db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.orgimport android.media.MediaFormat; 36a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.orgimport android.opengl.EGL14; 37a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.orgimport android.opengl.EGLConfig; 38a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.orgimport android.opengl.EGLContext; 39a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.orgimport android.opengl.EGLDisplay; 40a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.orgimport android.opengl.EGLSurface; 41a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.orgimport android.opengl.GLES11Ext; 42a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.orgimport android.opengl.GLES20; 437db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.orgimport android.os.Build; 447db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.orgimport android.os.Bundle; 457db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.orgimport android.util.Log; 46a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.orgimport android.view.Surface; 47a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 487db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.orgimport java.nio.ByteBuffer; 497db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 507db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org// Java-side of peerconnection_jni.cc:MediaCodecVideoDecoder. 517db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org// This class is an implementation detail of the Java PeerConnection API. 527db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org// MediaCodec is thread-hostile so this class must be operated on a single 537db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org// thread. 547db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.orgclass MediaCodecVideoDecoder { 557db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // This class is constructed, operated, and destroyed by its C++ incarnation, 567db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // so the class and its methods have non-public visibility. The API this 577db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // class exposes aims to mimic the webrtc::VideoDecoder API as closely as 587db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // possibly to minimize the amount of translation work necessary. 597db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 607db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private static final String TAG = "MediaCodecVideoDecoder"; 617db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 62a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private static final int DEQUEUE_INPUT_TIMEOUT = 500000; // 500 ms timeout. 637db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private Thread mediaCodecThread; 647db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private MediaCodec mediaCodec; 657db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private ByteBuffer[] inputBuffers; 667db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private ByteBuffer[] outputBuffers; 677db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8"; 687db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // List of supported HW VP8 decoders. 697db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private static final String[] supportedHwCodecPrefixes = 70131bfb7802b2c9dae43de05eb7251d9098a77b15glaznev@webrtc.org {"OMX.qcom.", "OMX.Nvidia." }; 717db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // NV12 color format supported by QCOM codec, but not declared in MediaCodec - 727db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h 737db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private static final int 747db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04; 757db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // Allowable color formats supported by codec - in order of preference. 767db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private static final int[] supportedColorList = { 777db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org CodecCapabilities.COLOR_FormatYUV420Planar, 787db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org CodecCapabilities.COLOR_FormatYUV420SemiPlanar, 797db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, 807db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m 817db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org }; 827db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private int colorFormat; 837db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private int width; 847db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private int height; 857db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private int stride; 867db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private int sliceHeight; 87a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private boolean useSurface; 88a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private int textureID = -1; 89a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private SurfaceTexture surfaceTexture = null; 90a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private Surface surface = null; 91a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private float[] stMatrix = new float[16]; 92a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private EGLDisplay eglDisplay = EGL14.EGL_NO_DISPLAY; 93a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private EGLContext eglContext = EGL14.EGL_NO_CONTEXT; 94a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private EGLSurface eglSurface = EGL14.EGL_NO_SURFACE; 95a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 967db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 977db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private MediaCodecVideoDecoder() { } 987db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 997db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // Helper struct for findVp8HwDecoder() below. 1007db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private static class DecoderProperties { 101a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org public DecoderProperties(String codecName, int colorFormat) { 1027db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org this.codecName = codecName; 1037db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org this.colorFormat = colorFormat; 1047db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1057db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org public final String codecName; // OpenMax component name for VP8 codec. 1067db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org public final int colorFormat; // Color format supported by codec. 1077db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1087db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 1097db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private static DecoderProperties findVp8HwDecoder() { 1107db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) 1117db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org return null; // MediaCodec.setParameters is missing. 1127db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 1137db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) { 1147db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); 1157db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (info.isEncoder()) { 1167db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org continue; 1177db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1187db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org String name = null; 1197db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org for (String mimeType : info.getSupportedTypes()) { 1207db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (mimeType.equals(VP8_MIME_TYPE)) { 1217db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org name = info.getName(); 1227db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org break; 1237db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1247db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1257db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (name == null) { 1267db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org continue; // No VP8 support in this codec; try the next one. 1277db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1287db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.d(TAG, "Found candidate decoder " + name); 129a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 130a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org // Check if this is supported HW decoder. 131a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org boolean supportedCodec = false; 132a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org for (String hwCodecPrefix : supportedHwCodecPrefixes) { 133a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (name.startsWith(hwCodecPrefix)) { 134a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org supportedCodec = true; 135a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org break; 136a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 137a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 138a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (!supportedCodec) { 139a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org continue; 140a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 141a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 142a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org // Check if codec supports either yuv420 or nv12. 1437db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org CodecCapabilities capabilities = 1447db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org info.getCapabilitiesForType(VP8_MIME_TYPE); 1457db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org for (int colorFormat : capabilities.colorFormats) { 1467db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.d(TAG, " Color: 0x" + Integer.toHexString(colorFormat)); 1477db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 148a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org for (int supportedColorFormat : supportedColorList) { 149a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org for (int codecColorFormat : capabilities.colorFormats) { 150a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (codecColorFormat == supportedColorFormat) { 151a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org // Found supported HW VP8 decoder. 152a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org Log.d(TAG, "Found target decoder " + name + 153a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org ". Color: 0x" + Integer.toHexString(codecColorFormat)); 154a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org return new DecoderProperties(name, codecColorFormat); 1557db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1567db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1577db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1587db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1597db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org return null; // No HW VP8 decoder. 1607db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1617db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 1627db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private static boolean isPlatformSupported() { 1637db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org return findVp8HwDecoder() != null; 1647db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1657db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 1667db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private void checkOnMediaCodecThread() { 1677db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (mediaCodecThread.getId() != Thread.currentThread().getId()) { 1687db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org throw new RuntimeException( 1697db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org "MediaCodecVideoDecoder previously operated on " + mediaCodecThread + 1707db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org " but is now called on " + Thread.currentThread()); 1717db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1727db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 1737db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 174a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private void checkEglError(String msg) { 175a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org int error; 176a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) { 177a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org Log.e(TAG, msg + ": EGL Error: 0x" + Integer.toHexString(error)); 178a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org throw new RuntimeException( 179a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org msg + ": EGL error: 0x" + Integer.toHexString(error)); 180a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 181a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 182a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 183a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private void checkGlError(String msg) { 184a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org int error; 185a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 186a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org Log.e(TAG, msg + ": GL Error: 0x" + Integer.toHexString(error)); 187a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org throw new RuntimeException( 188a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org msg + ": GL Error: 0x " + Integer.toHexString(error)); 189a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 190a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 191a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 192a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private void eglSetup(EGLContext sharedContext, int width, int height) { 193a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org Log.d(TAG, "EGL setup"); 194a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (sharedContext == null) { 195a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org sharedContext = EGL14.EGL_NO_CONTEXT; 196a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 197a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); 198a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (eglDisplay == EGL14.EGL_NO_DISPLAY) { 199a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org throw new RuntimeException("Unable to get EGL14 display"); 200a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 201a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org int[] version = new int[2]; 202a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (!EGL14.eglInitialize(eglDisplay, version, 0, version, 1)) { 203a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org throw new RuntimeException("Unable to initialize EGL14"); 204a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 205a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 206a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org // Configure EGL for pbuffer and OpenGL ES 2.0. 207a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org int[] attribList = { 208a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.EGL_RED_SIZE, 8, 209a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.EGL_GREEN_SIZE, 8, 210a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.EGL_BLUE_SIZE, 8, 211a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, 212a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT, 213a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.EGL_NONE 214a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org }; 215a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGLConfig[] configs = new EGLConfig[1]; 216a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org int[] numConfigs = new int[1]; 217a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (!EGL14.eglChooseConfig(eglDisplay, attribList, 0, configs, 0, 218a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org configs.length, numConfigs, 0)) { 219a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org throw new RuntimeException("Unable to find RGB888 EGL config"); 220a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 221a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 222a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org // Configure context for OpenGL ES 2.0. 223a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org int[] attrib_list = { 224a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, 225a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.EGL_NONE 226a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org }; 227a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org eglContext = EGL14.eglCreateContext(eglDisplay, configs[0], sharedContext, 228a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org attrib_list, 0); 229a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org checkEglError("eglCreateContext"); 230a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (eglContext == null) { 231a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org throw new RuntimeException("Null EGL context"); 232a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 233a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 234a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org // Create a pbuffer surface. 235a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org int[] surfaceAttribs = { 236a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.EGL_WIDTH, width, 237a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.EGL_HEIGHT, height, 238a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.EGL_NONE 239a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org }; 240a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org eglSurface = EGL14.eglCreatePbufferSurface(eglDisplay, configs[0], 241a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org surfaceAttribs, 0); 242a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org checkEglError("eglCreatePbufferSurface"); 243a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (eglSurface == null) { 244a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org throw new RuntimeException("EGL surface was null"); 245a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 246a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 247a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 248a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private void eglRelease() { 249a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org Log.d(TAG, "EGL release"); 250a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (eglDisplay != EGL14.EGL_NO_DISPLAY) { 251a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.eglDestroySurface(eglDisplay, eglSurface); 252a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.eglDestroyContext(eglDisplay, eglContext); 253a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.eglReleaseThread(); 254a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGL14.eglTerminate(eglDisplay); 255a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 256a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org eglDisplay = EGL14.EGL_NO_DISPLAY; 257a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org eglContext = EGL14.EGL_NO_CONTEXT; 258a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org eglSurface = EGL14.EGL_NO_SURFACE; 259a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 260a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 261a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 262a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private void makeCurrent() { 263a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (!EGL14.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { 264a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org throw new RuntimeException("eglMakeCurrent failed"); 265a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 266a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 267a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 268a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private boolean initDecode(int width, int height, boolean useSurface, 269a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org EGLContext sharedContext) { 2707db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (mediaCodecThread != null) { 2717db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org throw new RuntimeException("Forgot to release()?"); 2727db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 273a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (useSurface && sharedContext == null) { 274a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org throw new RuntimeException("No shared EGL context."); 275a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 2767db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org DecoderProperties properties = findVp8HwDecoder(); 2777db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (properties == null) { 2787db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org throw new RuntimeException("Cannot find HW VP8 decoder"); 2797db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 2807db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.d(TAG, "Java initDecode: " + width + " x " + height + 281a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org ". Color: 0x" + Integer.toHexString(properties.colorFormat) + 282a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org ". Use Surface: " + useSurface ); 283a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (sharedContext != null) { 284a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org Log.d(TAG, "Decoder shared EGL Context: " + sharedContext); 285a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 2867db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org mediaCodecThread = Thread.currentThread(); 2877db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org try { 288a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org Surface decodeSurface = null; 2897db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org this.width = width; 2907db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org this.height = height; 291a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org this.useSurface = useSurface; 2927db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org stride = width; 2937db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org sliceHeight = height; 294a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 295a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (useSurface) { 296a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org // Create shared EGL context. 297a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org eglSetup(sharedContext, width, height); 298a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org makeCurrent(); 299a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 300a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org // Create output surface 301a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org int[] textures = new int[1]; 302a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org GLES20.glGenTextures(1, textures, 0); 303a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org checkGlError("glGenTextures"); 304a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org textureID = textures[0]; 305a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureID); 306a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org checkGlError("glBindTexture mTextureID"); 307a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 308a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 309a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 310a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 311a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); 312a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 313a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); 314a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 315a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); 316a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org checkGlError("glTexParameter"); 317a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org Log.d(TAG, "Video decoder TextureID = " + textureID); 318a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org surfaceTexture = new SurfaceTexture(textureID); 319a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org surface = new Surface(surfaceTexture); 320a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org decodeSurface = surface; 321a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 322a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 3237db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org MediaFormat format = 3247db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org MediaFormat.createVideoFormat(VP8_MIME_TYPE, width, height); 325a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (!useSurface) { 326a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat); 327a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 3287db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.d(TAG, " Format: " + format); 3297db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org mediaCodec = MediaCodec.createByCodecName(properties.codecName); 3307db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (mediaCodec == null) { 3317db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org return false; 3327db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 333a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org mediaCodec.configure(format, decodeSurface, null, 0); 3347db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org mediaCodec.start(); 3357db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org colorFormat = properties.colorFormat; 3367db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org outputBuffers = mediaCodec.getOutputBuffers(); 3377db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org inputBuffers = mediaCodec.getInputBuffers(); 3387db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.d(TAG, "Input buffers: " + inputBuffers.length + 3397db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org ". Output buffers: " + outputBuffers.length); 3407db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org return true; 3417db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } catch (IllegalStateException e) { 3427db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.e(TAG, "initDecode failed", e); 3437db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org return false; 3447db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 3457db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 3467db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 3477db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private void release() { 3487db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.d(TAG, "Java releaseDecoder"); 3497db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org checkOnMediaCodecThread(); 3507db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org try { 3517db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org mediaCodec.stop(); 3527db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org mediaCodec.release(); 3537db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } catch (IllegalStateException e) { 3547db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.e(TAG, "release failed", e); 3557db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 3567db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org mediaCodec = null; 3577db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org mediaCodecThread = null; 358a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (useSurface) { 359a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org surface.release(); 360a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org surface = null; 361a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org surfaceTexture = null; 362a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (textureID >= 0) { 363a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org int[] textures = new int[1]; 364a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org textures[0] = textureID; 365a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org Log.d(TAG, "Delete video decoder TextureID " + textureID); 366a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org GLES20.glDeleteTextures(1, textures, 0); 367a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org checkGlError("glDeleteTextures"); 368a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 369a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org eglRelease(); 370a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 3717db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 3727db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 3737db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // Dequeue an input buffer and return its index, -1 if no input buffer is 3747db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // available, or -2 if the codec is no longer operative. 3757db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private int dequeueInputBuffer() { 3767db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org checkOnMediaCodecThread(); 3777db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org try { 378a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org return mediaCodec.dequeueInputBuffer(DEQUEUE_INPUT_TIMEOUT); 3797db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } catch (IllegalStateException e) { 3807db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.e(TAG, "dequeueIntputBuffer failed", e); 3817db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org return -2; 3827db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 3837db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 3847db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 3857db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org private boolean queueInputBuffer( 3867db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org int inputBufferIndex, int size, long timestampUs) { 3877db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org checkOnMediaCodecThread(); 3887db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org try { 3897db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org inputBuffers[inputBufferIndex].position(0); 3907db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org inputBuffers[inputBufferIndex].limit(size); 3917db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org mediaCodec.queueInputBuffer(inputBufferIndex, 0, size, timestampUs, 0); 3927db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org return true; 3937db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 3947db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org catch (IllegalStateException e) { 3957db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.e(TAG, "decode failed", e); 3967db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org return false; 3977db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 3987db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 3997db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 400a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org // Helper struct for dequeueOutputBuffer() below. 401a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private static class DecoderOutputBufferInfo { 402a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org public DecoderOutputBufferInfo( 403a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org int index, int offset, int size, long presentationTimestampUs) { 404a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org this.index = index; 405a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org this.offset = offset; 406a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org this.size = size; 407a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org this.presentationTimestampUs = presentationTimestampUs; 408a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 409a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 410a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private final int index; 411a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private final int offset; 412a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private final int size; 413a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private final long presentationTimestampUs; 414a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 415a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org 4167db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // Dequeue and return an output buffer index, -1 if no output 4177db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // buffer available or -2 if error happened. 418a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private DecoderOutputBufferInfo dequeueOutputBuffer(int dequeueTimeoutUs) { 4197db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org checkOnMediaCodecThread(); 4207db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org try { 4217db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 422a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org int result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs); 4237db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED || 4247db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 4257db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 4267db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org outputBuffers = mediaCodec.getOutputBuffers(); 427a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org Log.d(TAG, "Output buffers changed: " + outputBuffers.length); 4287db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } else if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 4297db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org MediaFormat format = mediaCodec.getOutputFormat(); 4307db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.d(TAG, "Format changed: " + format.toString()); 4317db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org width = format.getInteger(MediaFormat.KEY_WIDTH); 4327db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org height = format.getInteger(MediaFormat.KEY_HEIGHT); 433a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (!useSurface && format.containsKey(MediaFormat.KEY_COLOR_FORMAT)) { 4347db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT); 4357db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.d(TAG, "Color: 0x" + Integer.toHexString(colorFormat)); 4367db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // Check if new color space is supported. 4377db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org boolean validColorFormat = false; 4387db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org for (int supportedColorFormat : supportedColorList) { 4397db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (colorFormat == supportedColorFormat) { 4407db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org validColorFormat = true; 4417db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org break; 4427db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 4437db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 4447db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (!validColorFormat) { 4457db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.e(TAG, "Non supported color format"); 446a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org return new DecoderOutputBufferInfo(-1, 0, 0, -1); 4477db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 4487db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 4497db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (format.containsKey("stride")) { 4507db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org stride = format.getInteger("stride"); 4517db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 4527db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org if (format.containsKey("slice-height")) { 4537db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org sliceHeight = format.getInteger("slice-height"); 4547db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 4557db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.d(TAG, "Frame stride and slice height: " 4567db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org + stride + " x " + sliceHeight); 4577db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org stride = Math.max(width, stride); 4587db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org sliceHeight = Math.max(height, sliceHeight); 4597db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 460a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs); 4617db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 462a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (result >= 0) { 463a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org return new DecoderOutputBufferInfo(result, info.offset, info.size, 464a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org info.presentationTimeUs); 465a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 466a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org return null; 4677db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } catch (IllegalStateException e) { 4687db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.e(TAG, "dequeueOutputBuffer failed", e); 469a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org return new DecoderOutputBufferInfo(-1, 0, 0, -1); 4707db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 4717db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 4727db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org 4737db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // Release a dequeued output buffer back to the codec for re-use. Return 4747db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org // false if the codec is no longer operable. 475a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org private boolean releaseOutputBuffer(int index, boolean render) { 4767db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org checkOnMediaCodecThread(); 4777db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org try { 478a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org if (!useSurface) { 479a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org render = false; 480a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org } 481a846c2043a8abdbc8fd1f7511d824e6a64a8baf5glaznev@webrtc.org mediaCodec.releaseOutputBuffer(index, render); 4827db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org return true; 4837db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } catch (IllegalStateException e) { 4847db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org Log.e(TAG, "releaseOutputBuffer failed", e); 4857db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org return false; 4867db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 4877db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org } 4887db3e8d09758a24d9e7c915ae43c7e223c1d7f52glaznev@webrtc.org} 489