Add option to print peer connection factory Java stack traces.

Removing static declaration for media codec thread to allow
running multiple HW codec instances.

R=wzh@webrtc.org

Review URL: https://codereview.webrtc.org/1393203005 .

Cr-Commit-Position: refs/heads/master@{#10258}
diff --git a/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java b/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java
index ec68ed5..27a7d9b 100644
--- a/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java
+++ b/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java
@@ -35,7 +35,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.SystemClock;
-import android.text.StaticLayout;
 import android.view.Surface;
 import android.view.WindowManager;
 
@@ -217,6 +216,18 @@
     return capturer;
   }
 
+  public void printStackTrace() {
+    if (cameraThread != null) {
+      StackTraceElement[] cameraStackTraces = cameraThread.getStackTrace();
+      if (cameraStackTraces.length > 0) {
+        Logging.d(TAG, "VideoCapturerAndroid stacks trace:");
+        for (StackTraceElement stackTrace : cameraStackTraces) {
+          Logging.d(TAG, stackTrace.toString());
+        }
+      }
+    }
+  }
+
   // Switch camera to the next valid camera id. This can only be called while
   // the camera is running.
   public void switchCamera(final CameraSwitchHandler handler) {
diff --git a/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java b/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
index afaebf6..1d413b8 100644
--- a/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
+++ b/talk/app/webrtc/java/android/org/webrtc/VideoRendererGui.java
@@ -36,12 +36,10 @@
 import android.annotation.SuppressLint;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
 import android.opengl.EGL14;
 import android.opengl.EGLContext;
 import android.opengl.GLES20;
 import android.opengl.GLSurfaceView;
-import android.opengl.Matrix;
 
 import org.webrtc.Logging;
 import org.webrtc.VideoRenderer.I420Frame;
@@ -77,6 +75,9 @@
   // Current SDK version.
   private static final int CURRENT_SDK_VERSION =
       android.os.Build.VERSION.SDK_INT;
+  // Render and draw threads.
+  private static Thread renderFrameThread;
+  private static Thread drawThread;
 
   private VideoRendererGui(GLSurfaceView surface) {
     this.surface = surface;
@@ -372,6 +373,9 @@
         VideoRenderer.renderFrameDone(frame);
         return;
       }
+      if (renderFrameThread == null) {
+        renderFrameThread = Thread.currentThread();
+      }
       if (!seenFrame && rendererEvents != null) {
         Logging.d(TAG, "ID: " + id + ". Reporting first rendered frame.");
         rendererEvents.onFirstFrameRendered();
@@ -394,6 +398,7 @@
           // Skip rendering of this frame if previous frame was not rendered yet.
           framesDropped++;
           VideoRenderer.renderFrameDone(frame);
+          seenFrame = true;
           return;
         }
         pendingFrame = frame;
@@ -430,6 +435,8 @@
       }
       instance.yuvImageRenderers.clear();
     }
+    renderFrameThread = null;
+    drawThread = null;
     instance.surface = null;
     eglContext = null;
     eglContextReady = null;
@@ -565,6 +572,26 @@
     }
   }
 
+  private static void printStackTrace(Thread thread, String threadName) {
+    if (thread != null) {
+      StackTraceElement[] stackTraces = thread.getStackTrace();
+      if (stackTraces.length > 0) {
+        Logging.d(TAG, threadName + " stacks trace:");
+        for (StackTraceElement stackTrace : stackTraces) {
+          Logging.d(TAG, stackTrace.toString());
+        }
+      }
+    }
+  }
+
+  public static synchronized void printStackTraces() {
+    if (instance == null) {
+      return;
+    }
+    printStackTrace(renderFrameThread, "Render frame thread");
+    printStackTrace(drawThread, "Draw thread");
+  }
+
   @SuppressLint("NewApi")
   @Override
   public void onSurfaceCreated(GL10 unused, EGLConfig config) {
@@ -613,6 +640,9 @@
 
   @Override
   public void onDrawFrame(GL10 unused) {
+    if (drawThread == null) {
+      drawThread = Thread.currentThread();
+    }
     GLES20.glViewport(0, 0, screenWidth, screenHeight);
     GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
     synchronized (yuvImageRenderers) {
diff --git a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java
index 91de811..a1cc041 100644
--- a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java
+++ b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java
@@ -32,9 +32,6 @@
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecList;
 import android.media.MediaFormat;
-import android.opengl.EGLContext;
-import android.opengl.GLES11Ext;
-import android.opengl.GLES20;
 import android.os.Build;
 import android.view.Surface;
 
@@ -65,6 +62,7 @@
   }
 
   private static final int DEQUEUE_INPUT_TIMEOUT = 500000;  // 500 ms timeout.
+  private static MediaCodecVideoDecoder instance;
   private Thread mediaCodecThread;
   private MediaCodec mediaCodec;
   private ByteBuffer[] inputBuffers;
@@ -100,7 +98,7 @@
   private Surface surface = null;
 
   private MediaCodecVideoDecoder() {
-    mediaCodecThread = null;
+    instance = this;
   }
 
   // Helper struct for findVp8Decoder() below.
@@ -175,6 +173,18 @@
     return findDecoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes) != null;
   }
 
+  public static void printStackTrace() {
+    if (instance != null && instance.mediaCodecThread != null) {
+      StackTraceElement[] mediaCodecStackTraces = instance.mediaCodecThread.getStackTrace();
+      if (mediaCodecStackTraces.length > 0) {
+        Logging.d(TAG, "MediaCodecVideoDecoder stacks trace:");
+        for (StackTraceElement stackTrace : mediaCodecStackTraces) {
+          Logging.d(TAG, stackTrace.toString());
+        }
+      }
+    }
+  }
+
   private void checkOnMediaCodecThread() throws IllegalStateException {
     if (mediaCodecThread.getId() != Thread.currentThread().getId()) {
       throw new IllegalStateException(
@@ -228,6 +238,7 @@
       mediaCodec =
           MediaCodecVideoEncoder.createByCodecName(properties.codecName);
       if (mediaCodec == null) {
+        Logging.e(TAG, "Can not create media decoder");
         return false;
       }
       mediaCodec.configure(format, surface, null, 0);
@@ -255,11 +266,13 @@
     }
     mediaCodec = null;
     mediaCodecThread = null;
+    instance = null;
     if (useSurface) {
       surface.release();
       surface = null;
       textureListener.release();
     }
+    Logging.d(TAG, "Java releaseDecoder done");
   }
 
   // Dequeue an input buffer and return its index, -1 if no input buffer is
diff --git a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
index 6a218fd..0af2133 100644
--- a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
+++ b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
@@ -25,7 +25,6 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-
 package org.webrtc;
 
 import android.media.MediaCodec;
@@ -62,6 +61,7 @@
   }
 
   private static final int DEQUEUE_TIMEOUT = 0;  // Non-blocking, no wait.
+  private static MediaCodecVideoEncoder instance = null;
   private Thread mediaCodecThread;
   private MediaCodec mediaCodec;
   private ByteBuffer[] outputBuffers;
@@ -103,7 +103,7 @@
   private ByteBuffer configData = null;
 
   MediaCodecVideoEncoder() {
-    mediaCodecThread = null;
+    instance = this;
   }
 
   // Helper struct for findHwEncoder() below.
@@ -199,6 +199,18 @@
     }
   }
 
+  public static void printStackTrace() {
+    if (instance != null && instance.mediaCodecThread != null) {
+      StackTraceElement[] mediaCodecStackTraces = instance.mediaCodecThread.getStackTrace();
+      if (mediaCodecStackTraces.length > 0) {
+        Logging.d(TAG, "MediaCodecVideoEncoder stacks trace:");
+        for (StackTraceElement stackTrace : mediaCodecStackTraces) {
+          Logging.d(TAG, stackTrace.toString());
+        }
+      }
+    }
+  }
+
   static MediaCodec createByCodecName(String codecName) {
     try {
       // In the L-SDK this call can throw IOException so in order to work in
@@ -245,6 +257,7 @@
       mediaCodec = createByCodecName(properties.codecName);
       this.type = type;
       if (mediaCodec == null) {
+        Logging.e(TAG, "Can not create media encoder");
         return false;
       }
       mediaCodec.configure(
@@ -302,6 +315,8 @@
     }
     mediaCodec = null;
     mediaCodecThread = null;
+    instance = null;
+    Logging.d(TAG, "Java releaseEncoder done");
   }
 
   private boolean setRates(int kbps, int frameRateIgnored) {
diff --git a/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java b/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java
index 6bc8189..0460624 100644
--- a/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java
+++ b/talk/app/webrtc/java/src/org/webrtc/PeerConnectionFactory.java
@@ -148,19 +148,21 @@
     nativeThreadsCallbacks(nativeFactory);
   }
 
+  private static void printStackTrace(Thread thread, String threadName) {
+    if (thread != null) {
+      StackTraceElement[] stackTraces = thread.getStackTrace();
+      if (stackTraces.length > 0) {
+        Logging.d(TAG, threadName + " stacks trace:");
+        for (StackTraceElement stackTrace : stackTraces) {
+          Logging.d(TAG, stackTrace.toString());
+        }
+      }
+    }
+  }
+
   public static void printStackTraces() {
-    if (workerThread != null) {
-      Logging.d(TAG, "Worker thread stacks trace:");
-      for (StackTraceElement stackTrace : workerThread.getStackTrace()) {
-        Logging.d(TAG, stackTrace.toString());
-      }
-    }
-    if (signalingThread != null) {
-      Logging.d(TAG, "Signaling thread stacks trace:");
-      for (StackTraceElement stackTrace : signalingThread.getStackTrace()) {
-        Logging.d(TAG, stackTrace.toString());
-      }
-    }
+    printStackTrace(workerThread, "Worker thread");
+    printStackTrace(signalingThread, "Signaling thread");
   }
 
   private static void onWorkerThreadReady() {