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

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: 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
« no previous file with comments | « no previous file | talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.atomic.AtomicBoolean;
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 // MediaCodec is thread-hostile so this class must be operated on a single
52 // thread. 53 // thread.
53 public class MediaCodecVideoDecoder { 54 public class MediaCodecVideoDecoder {
54 // This class is constructed, operated, and destroyed by its C++ incarnation, 55 // 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 56 // 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 57 // class exposes aims to mimic the webrtc::VideoDecoder API as closely as
57 // possibly to minimize the amount of translation work necessary. 58 // possibly to minimize the amount of translation work necessary.
58 59
59 private static final String TAG = "MediaCodecVideoDecoder"; 60 private static final String TAG = "MediaCodecVideoDecoder";
60 61
61 // Tracks webrtc::VideoCodecType. 62 // Tracks webrtc::VideoCodecType.
62 public enum VideoCodecType { 63 public enum VideoCodecType {
63 VIDEO_CODEC_VP8, 64 VIDEO_CODEC_VP8,
64 VIDEO_CODEC_VP9, 65 VIDEO_CODEC_VP9,
65 VIDEO_CODEC_H264 66 VIDEO_CODEC_H264
66 } 67 }
67 68
68 private static final int DEQUEUE_INPUT_TIMEOUT = 500000; // 500 ms timeout. 69 private static final int DEQUEUE_INPUT_TIMEOUT = 500000; // 500 ms timeout.
70 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) 71 // Active running decoder instance. Set in initDecode() (called from native co de)
70 // and reset to null in release() call. 72 // and reset to null in release() call.
71 private static MediaCodecVideoDecoder runningInstance = null; 73 private static MediaCodecVideoDecoder runningInstance = null;
74 private static MediaCodecVideoDecoderErrorCallback errorCallback = null;
magjed_webrtc 2015/10/30 14:01:57 We signal other MediaCodec errors with exceptions
AlexG 2015/10/30 20:07:59 These are different errors. Exceptions and other m
75 private static int codecErrors = 0;
magjed_webrtc 2015/10/30 14:01:57 Why do we need to report the number of codec error
AlexG 2015/10/30 20:07:58 See comment above
76
72 private Thread mediaCodecThread; 77 private Thread mediaCodecThread;
73 private MediaCodec mediaCodec; 78 private MediaCodec mediaCodec;
74 private ByteBuffer[] inputBuffers; 79 private ByteBuffer[] inputBuffers;
75 private ByteBuffer[] outputBuffers; 80 private ByteBuffer[] outputBuffers;
76 private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8"; 81 private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8";
77 private static final String H264_MIME_TYPE = "video/avc"; 82 private static final String H264_MIME_TYPE = "video/avc";
78 // List of supported HW VP8 decoders. 83 // List of supported HW VP8 decoders.
79 private static final String[] supportedVp8HwCodecPrefixes = 84 private static final String[] supportedVp8HwCodecPrefixes =
80 {"OMX.qcom.", "OMX.Nvidia.", "OMX.Exynos.", "OMX.Intel." }; 85 {"OMX.qcom.", "OMX.Nvidia.", "OMX.Exynos.", "OMX.Intel." };
81 // List of supported HW H.264 decoders. 86 // List of supported HW H.264 decoders.
(...skipping 16 matching lines...) Expand all
98 private int sliceHeight; 103 private int sliceHeight;
99 private boolean useSurface; 104 private boolean useSurface;
100 private int textureID = 0; 105 private int textureID = 0;
101 private SurfaceTexture surfaceTexture = null; 106 private SurfaceTexture surfaceTexture = null;
102 private Surface surface = null; 107 private Surface surface = null;
103 private EglBase eglBase; 108 private EglBase eglBase;
104 109
105 private MediaCodecVideoDecoder() { 110 private MediaCodecVideoDecoder() {
106 } 111 }
107 112
113 // MediaCodec error handler - invoked when critical error happens
114 // which prevents further use of media codec API.
115 public static interface MediaCodecVideoDecoderErrorCallback {
116 void onMediaCodecVideoDecoderError(int codecErrors);
117 }
118
119 public static void setErrorCallback(MediaCodecVideoDecoderErrorCallback errorC allback) {
magjed_webrtc 2015/10/30 14:01:57 I really don't like hooking stuff up with static f
AlexG 2015/10/30 20:07:58 There is similar to VideoCapturerAndroid.create()
120 Logging.d(TAG, "Set error callback");
121 MediaCodecVideoDecoder.errorCallback = errorCallback;
122 }
123
108 // Helper struct for findVp8Decoder() below. 124 // Helper struct for findVp8Decoder() below.
109 private static class DecoderProperties { 125 private static class DecoderProperties {
110 public DecoderProperties(String codecName, int colorFormat) { 126 public DecoderProperties(String codecName, int colorFormat) {
111 this.codecName = codecName; 127 this.codecName = codecName;
112 this.colorFormat = colorFormat; 128 this.colorFormat = colorFormat;
113 } 129 }
114 public final String codecName; // OpenMax component name for VP8 codec. 130 public final String codecName; // OpenMax component name for VP8 codec.
115 public final int colorFormat; // Color format supported by codec. 131 public final int colorFormat; // Color format supported by codec.
116 } 132 }
117 133
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 return true; 282 return true;
267 } catch (IllegalStateException e) { 283 } catch (IllegalStateException e) {
268 Logging.e(TAG, "initDecode failed", e); 284 Logging.e(TAG, "initDecode failed", e);
269 return false; 285 return false;
270 } 286 }
271 } 287 }
272 288
273 private void release() { 289 private void release() {
274 Logging.d(TAG, "Java releaseDecoder"); 290 Logging.d(TAG, "Java releaseDecoder");
275 checkOnMediaCodecThread(); 291 checkOnMediaCodecThread();
276 try { 292
277 mediaCodec.stop(); 293 // Run Mediacodec stop() and release() on separate thread since sometime
278 mediaCodec.release(); 294 // Mediacodec.stop() may hang.
279 } catch (IllegalStateException e) { 295 final AtomicBoolean releaseDone = new AtomicBoolean(false);
magjed_webrtc 2015/10/30 14:01:57 I think it would be cleaner to write this with a C
AlexG 2015/10/30 20:07:59 Done.
280 Logging.e(TAG, "release failed", e); 296
297 Runnable runMediaCodecRelease = new Runnable() {
298 @Override
299 public void run() {
300 try {
301 Logging.d(TAG, "Java releaseDecoder on release thread");
302 mediaCodec.stop();
303 mediaCodec.release();
304 Logging.d(TAG, "Java releaseDecoder on release thread done");
305 } catch (Exception e) {
306 Logging.e(TAG, "Media decoder release failed", e);
307 }
308 synchronized (releaseDone) {
309 releaseDone.set(true);
310 releaseDone.notifyAll();
311 }
312 }
313 };
314 new Thread(runMediaCodecRelease).start();
magjed_webrtc 2015/10/30 14:01:57 We have this comment at the top of this file: "Med
AlexG 2015/10/30 20:07:58 I didn't see this requirement in Android docs - I
315
316 if (!releaseDone.get()) {
317 synchronized(releaseDone) {
318 try {
319 releaseDone.wait(MEDIA_CODEC_RELEASE_TIMEOUT_MS);
magjed_webrtc 2015/10/30 14:01:57 You should not swallow InterruptedException, i.e.
AlexG 2015/10/30 20:07:58 Done. Thanks! I moved your ThreadUtils changes to
magjed_webrtc 2015/10/30 21:50:37 If you want, just submit the ThreadUtils change in
320 } catch (InterruptedException e) {
321 Logging.e(TAG, "Wait exception.", e);
322 }
323 }
281 } 324 }
325 if (!releaseDone.get()) {
326 Logging.e(TAG, "Media decoder release timeout");
327 codecErrors++;
328 if (errorCallback != null) {
329 Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors);
330 errorCallback.onMediaCodecVideoDecoderError(codecErrors);
331 }
332 }
333
282 mediaCodec = null; 334 mediaCodec = null;
283 mediaCodecThread = null; 335 mediaCodecThread = null;
284 runningInstance = null; 336 runningInstance = null;
285 if (useSurface) { 337 if (useSurface) {
286 surface.release(); 338 surface.release();
287 surface = null; 339 surface = null;
288 Logging.d(TAG, "Delete video decoder TextureID " + textureID); 340 Logging.d(TAG, "Delete video decoder TextureID " + textureID);
289 GLES20.glDeleteTextures(1, new int[] {textureID}, 0); 341 GLES20.glDeleteTextures(1, new int[] {textureID}, 0);
290 textureID = 0; 342 textureID = 0;
291 eglBase.release(); 343 eglBase.release();
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 // MediaCodec.CodecException upon codec error. 461 // MediaCodec.CodecException upon codec error.
410 private void returnDecodedByteBuffer(int index) 462 private void returnDecodedByteBuffer(int index)
411 throws IllegalStateException, MediaCodec.CodecException { 463 throws IllegalStateException, MediaCodec.CodecException {
412 checkOnMediaCodecThread(); 464 checkOnMediaCodecThread();
413 if (useSurface) { 465 if (useSurface) {
414 throw new IllegalStateException("returnDecodedByteBuffer() called for surf ace decoding."); 466 throw new IllegalStateException("returnDecodedByteBuffer() called for surf ace decoding.");
415 } 467 }
416 mediaCodec.releaseOutputBuffer(index, false /* render */); 468 mediaCodec.releaseOutputBuffer(index, false /* render */);
417 } 469 }
418 } 470 }
OLDNEW
« no previous file with comments | « no previous file | talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698