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