Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Side by Side Diff: talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java

Issue 1425143005: Call MediaCodec.stop() on separate thread. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc@master
Patch Set: Address comments Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * libjingle 2 * libjingle
3 * Copyright 2014 Google Inc. 3 * Copyright 2014 Google Inc.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright notice, 8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer. 9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * 2. Redistributions in binary form must reproduce the above copyright notice,
(...skipping 25 matching lines...) Expand all
36 import android.opengl.GLES11Ext; 36 import android.opengl.GLES11Ext;
37 import android.opengl.GLES20; 37 import android.opengl.GLES20;
38 import android.os.Build; 38 import android.os.Build;
39 import android.view.Surface; 39 import android.view.Surface;
40 40
41 import org.webrtc.Logging; 41 import org.webrtc.Logging;
42 42
43 import java.nio.ByteBuffer; 43 import java.nio.ByteBuffer;
44 import java.util.Arrays; 44 import java.util.Arrays;
45 import java.util.List; 45 import java.util.List;
46 import java.util.concurrent.CountDownLatch;
46 47
47 import javax.microedition.khronos.egl.EGLContext; 48 import javax.microedition.khronos.egl.EGLContext;
48 49
49 // Java-side of peerconnection_jni.cc:MediaCodecVideoDecoder. 50 // Java-side of peerconnection_jni.cc:MediaCodecVideoDecoder.
50 // This class is an implementation detail of the Java PeerConnection API. 51 // This class is an implementation detail of the Java PeerConnection API.
51 // MediaCodec is thread-hostile so this class must be operated on a single
52 // thread.
53 public class MediaCodecVideoDecoder { 52 public class MediaCodecVideoDecoder {
54 // This class is constructed, operated, and destroyed by its C++ incarnation, 53 // This class is constructed, operated, and destroyed by its C++ incarnation,
55 // so the class and its methods have non-public visibility. The API this 54 // so the class and its methods have non-public visibility. The API this
56 // class exposes aims to mimic the webrtc::VideoDecoder API as closely as 55 // class exposes aims to mimic the webrtc::VideoDecoder API as closely as
57 // possibly to minimize the amount of translation work necessary. 56 // possibly to minimize the amount of translation work necessary.
58 57
59 private static final String TAG = "MediaCodecVideoDecoder"; 58 private static final String TAG = "MediaCodecVideoDecoder";
60 59
61 // Tracks webrtc::VideoCodecType. 60 // Tracks webrtc::VideoCodecType.
62 public enum VideoCodecType { 61 public enum VideoCodecType {
63 VIDEO_CODEC_VP8, 62 VIDEO_CODEC_VP8,
64 VIDEO_CODEC_VP9, 63 VIDEO_CODEC_VP9,
65 VIDEO_CODEC_H264 64 VIDEO_CODEC_H264
66 } 65 }
67 66
68 private static final int DEQUEUE_INPUT_TIMEOUT = 500000; // 500 ms timeout. 67 private static final int DEQUEUE_INPUT_TIMEOUT = 500000; // 500 ms timeout.
68 private static final int MEDIA_CODEC_RELEASE_TIMEOUT_MS = 5000; // Timeout for codec releasing.
69 // Active running decoder instance. Set in initDecode() (called from native co de) 69 // Active running decoder instance. Set in initDecode() (called from native co de)
70 // and reset to null in release() call. 70 // and reset to null in release() call.
71 private static MediaCodecVideoDecoder runningInstance = null; 71 private static MediaCodecVideoDecoder runningInstance = null;
72 private static MediaCodecVideoDecoderErrorCallback errorCallback = null;
73 private static int codecErrors = 0;
74
72 private Thread mediaCodecThread; 75 private Thread mediaCodecThread;
73 private MediaCodec mediaCodec; 76 private MediaCodec mediaCodec;
74 private ByteBuffer[] inputBuffers; 77 private ByteBuffer[] inputBuffers;
75 private ByteBuffer[] outputBuffers; 78 private ByteBuffer[] outputBuffers;
76 private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8"; 79 private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8";
77 private static final String H264_MIME_TYPE = "video/avc"; 80 private static final String H264_MIME_TYPE = "video/avc";
78 // List of supported HW VP8 decoders. 81 // List of supported HW VP8 decoders.
79 private static final String[] supportedVp8HwCodecPrefixes = 82 private static final String[] supportedVp8HwCodecPrefixes =
80 {"OMX.qcom.", "OMX.Nvidia.", "OMX.Exynos.", "OMX.Intel." }; 83 {"OMX.qcom.", "OMX.Nvidia.", "OMX.Exynos.", "OMX.Intel." };
81 // List of supported HW H.264 decoders. 84 // List of supported HW H.264 decoders.
(...skipping 16 matching lines...) Expand all
98 private int sliceHeight; 101 private int sliceHeight;
99 private boolean useSurface; 102 private boolean useSurface;
100 private int textureID = 0; 103 private int textureID = 0;
101 private SurfaceTexture surfaceTexture = null; 104 private SurfaceTexture surfaceTexture = null;
102 private Surface surface = null; 105 private Surface surface = null;
103 private EglBase eglBase; 106 private EglBase eglBase;
104 107
105 private MediaCodecVideoDecoder() { 108 private MediaCodecVideoDecoder() {
106 } 109 }
107 110
111 // MediaCodec error handler - invoked when critical error happens which may pr event
112 // further use of media codec API. Now it means that one of media codec instan ces
113 // is hanging and can no longer be used in the next call.
114 public static interface MediaCodecVideoDecoderErrorCallback {
115 void onMediaCodecVideoDecoderCriticalError(int codecErrors);
116 }
117
118 public static void setErrorCallback(MediaCodecVideoDecoderErrorCallback errorC allback) {
119 Logging.d(TAG, "Set error callback");
120 MediaCodecVideoDecoder.errorCallback = errorCallback;
121 }
122
108 // Helper struct for findVp8Decoder() below. 123 // Helper struct for findVp8Decoder() below.
109 private static class DecoderProperties { 124 private static class DecoderProperties {
110 public DecoderProperties(String codecName, int colorFormat) { 125 public DecoderProperties(String codecName, int colorFormat) {
111 this.codecName = codecName; 126 this.codecName = codecName;
112 this.colorFormat = colorFormat; 127 this.colorFormat = colorFormat;
113 } 128 }
114 public final String codecName; // OpenMax component name for VP8 codec. 129 public final String codecName; // OpenMax component name for VP8 codec.
115 public final int colorFormat; // Color format supported by codec. 130 public final int colorFormat; // Color format supported by codec.
116 } 131 }
117 132
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 return true; 281 return true;
267 } catch (IllegalStateException e) { 282 } catch (IllegalStateException e) {
268 Logging.e(TAG, "initDecode failed", e); 283 Logging.e(TAG, "initDecode failed", e);
269 return false; 284 return false;
270 } 285 }
271 } 286 }
272 287
273 private void release() { 288 private void release() {
274 Logging.d(TAG, "Java releaseDecoder"); 289 Logging.d(TAG, "Java releaseDecoder");
275 checkOnMediaCodecThread(); 290 checkOnMediaCodecThread();
276 try { 291
277 mediaCodec.stop(); 292 // Run Mediacodec stop() and release() on separate thread since sometime
278 mediaCodec.release(); 293 // Mediacodec.stop() may hang.
279 } catch (IllegalStateException e) { 294 final CountDownLatch releaseDone = new CountDownLatch(1);
280 Logging.e(TAG, "release failed", e); 295
296 Runnable runMediaCodecRelease = new Runnable() {
297 @Override
298 public void run() {
299 try {
300 Logging.d(TAG, "Java releaseDecoder on release thread");
301 mediaCodec.stop();
302 mediaCodec.release();
303 Logging.d(TAG, "Java releaseDecoder on release thread done");
304 } catch (Exception e) {
305 Logging.e(TAG, "Media decoder release failed", e);
306 }
307 releaseDone.countDown();
308 }
309 };
310 new Thread(runMediaCodecRelease).start();
311
312 if (!ThreadUtils.awaitUninterruptibly(releaseDone, MEDIA_CODEC_RELEASE_TIMEO UT_MS)) {
313 Logging.e(TAG, "Media decoder release timeout");
314 codecErrors++;
315 if (errorCallback != null) {
316 Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors);
317 errorCallback.onMediaCodecVideoDecoderCriticalError(codecErrors);
318 }
281 } 319 }
320
282 mediaCodec = null; 321 mediaCodec = null;
283 mediaCodecThread = null; 322 mediaCodecThread = null;
284 runningInstance = null; 323 runningInstance = null;
285 if (useSurface) { 324 if (useSurface) {
286 surface.release(); 325 surface.release();
287 surface = null; 326 surface = null;
288 Logging.d(TAG, "Delete video decoder TextureID " + textureID); 327 Logging.d(TAG, "Delete video decoder TextureID " + textureID);
289 GLES20.glDeleteTextures(1, new int[] {textureID}, 0); 328 GLES20.glDeleteTextures(1, new int[] {textureID}, 0);
290 textureID = 0; 329 textureID = 0;
291 eglBase.release(); 330 eglBase.release();
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 } 386 }
348 387
349 // Returns null if no decoded buffer is available, and otherwise either a Deco dedByteBuffer or 388 // Returns null if no decoded buffer is available, and otherwise either a Deco dedByteBuffer or
350 // DecodedTexturebuffer depending on |useSurface| configuration. 389 // DecodedTexturebuffer depending on |useSurface| configuration.
351 // Throws IllegalStateException if call is made on the wrong thread, if color format changes to an 390 // Throws IllegalStateException if call is made on the wrong thread, if color format changes to an
352 // unsupported format, or if |mediaCodec| is not in the Executing state. Throw s CodecException 391 // unsupported format, or if |mediaCodec| is not in the Executing state. Throw s CodecException
353 // upon codec error. 392 // upon codec error.
354 private Object dequeueOutputBuffer(int dequeueTimeoutUs) 393 private Object dequeueOutputBuffer(int dequeueTimeoutUs)
355 throws IllegalStateException, MediaCodec.CodecException { 394 throws IllegalStateException, MediaCodec.CodecException {
356 checkOnMediaCodecThread(); 395 checkOnMediaCodecThread();
396
357 // Drain the decoder until receiving a decoded buffer or hitting 397 // Drain the decoder until receiving a decoded buffer or hitting
358 // MediaCodec.INFO_TRY_AGAIN_LATER. 398 // MediaCodec.INFO_TRY_AGAIN_LATER.
359 final MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 399 final MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
360 while (true) { 400 while (true) {
361 final int result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs); 401 final int result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs);
362 switch (result) { 402 switch (result) {
363 case MediaCodec.INFO_TRY_AGAIN_LATER: 403 case MediaCodec.INFO_TRY_AGAIN_LATER:
364 return null; 404 return null;
365 case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: 405 case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
366 outputBuffers = mediaCodec.getOutputBuffers(); 406 outputBuffers = mediaCodec.getOutputBuffers();
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 // MediaCodec.CodecException upon codec error. 449 // MediaCodec.CodecException upon codec error.
410 private void returnDecodedByteBuffer(int index) 450 private void returnDecodedByteBuffer(int index)
411 throws IllegalStateException, MediaCodec.CodecException { 451 throws IllegalStateException, MediaCodec.CodecException {
412 checkOnMediaCodecThread(); 452 checkOnMediaCodecThread();
413 if (useSurface) { 453 if (useSurface) {
414 throw new IllegalStateException("returnDecodedByteBuffer() called for surf ace decoding."); 454 throw new IllegalStateException("returnDecodedByteBuffer() called for surf ace decoding.");
415 } 455 }
416 mediaCodec.releaseOutputBuffer(index, false /* render */); 456 mediaCodec.releaseOutputBuffer(index, false /* render */);
417 } 457 }
418 } 458 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698