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

Side by Side Diff: talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.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
« no previous file with comments | « talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java ('k') | no next file » | 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 2013 Google Inc. 3 * Copyright 2013 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 22 matching lines...) Expand all
33 import android.media.MediaCodecList; 33 import android.media.MediaCodecList;
34 import android.media.MediaFormat; 34 import android.media.MediaFormat;
35 import android.os.Build; 35 import android.os.Build;
36 import android.os.Bundle; 36 import android.os.Bundle;
37 37
38 import org.webrtc.Logging; 38 import org.webrtc.Logging;
39 39
40 import java.nio.ByteBuffer; 40 import java.nio.ByteBuffer;
41 import java.util.Arrays; 41 import java.util.Arrays;
42 import java.util.List; 42 import java.util.List;
43 import java.util.concurrent.CountDownLatch;
43 44
44 // Java-side of peerconnection_jni.cc:MediaCodecVideoEncoder. 45 // Java-side of peerconnection_jni.cc:MediaCodecVideoEncoder.
45 // This class is an implementation detail of the Java PeerConnection API. 46 // This class is an implementation detail of the Java PeerConnection API.
46 // MediaCodec is thread-hostile so this class must be operated on a single
47 // thread.
48 public class MediaCodecVideoEncoder { 47 public class MediaCodecVideoEncoder {
49 // This class is constructed, operated, and destroyed by its C++ incarnation, 48 // This class is constructed, operated, and destroyed by its C++ incarnation,
50 // so the class and its methods have non-public visibility. The API this 49 // so the class and its methods have non-public visibility. The API this
51 // class exposes aims to mimic the webrtc::VideoEncoder API as closely as 50 // class exposes aims to mimic the webrtc::VideoEncoder API as closely as
52 // possibly to minimize the amount of translation work necessary. 51 // possibly to minimize the amount of translation work necessary.
53 52
54 private static final String TAG = "MediaCodecVideoEncoder"; 53 private static final String TAG = "MediaCodecVideoEncoder";
55 54
56 // Tracks webrtc::VideoCodecType. 55 // Tracks webrtc::VideoCodecType.
57 public enum VideoCodecType { 56 public enum VideoCodecType {
58 VIDEO_CODEC_VP8, 57 VIDEO_CODEC_VP8,
59 VIDEO_CODEC_VP9, 58 VIDEO_CODEC_VP9,
60 VIDEO_CODEC_H264 59 VIDEO_CODEC_H264
61 } 60 }
62 61
62 private static final int MEDIA_CODEC_RELEASE_TIMEOUT_MS = 5000; // Timeout for codec releasing.
63 private static final int DEQUEUE_TIMEOUT = 0; // Non-blocking, no wait. 63 private static final int DEQUEUE_TIMEOUT = 0; // Non-blocking, no wait.
64 // Active running encoder instance. Set in initDecode() (called from native co de) 64 // Active running encoder instance. Set in initDecode() (called from native co de)
65 // and reset to null in release() call. 65 // and reset to null in release() call.
66 private static MediaCodecVideoEncoder runningInstance = null; 66 private static MediaCodecVideoEncoder runningInstance = null;
67 private static MediaCodecVideoEncoderErrorCallback errorCallback = null;
68 private static int codecErrors = 0;
69
67 private Thread mediaCodecThread; 70 private Thread mediaCodecThread;
68 private MediaCodec mediaCodec; 71 private MediaCodec mediaCodec;
69 private ByteBuffer[] outputBuffers; 72 private ByteBuffer[] outputBuffers;
70 private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8"; 73 private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8";
71 private static final String H264_MIME_TYPE = "video/avc"; 74 private static final String H264_MIME_TYPE = "video/avc";
72 // List of supported HW VP8 codecs. 75 // List of supported HW VP8 codecs.
73 private static final String[] supportedVp8HwCodecPrefixes = 76 private static final String[] supportedVp8HwCodecPrefixes =
74 {"OMX.qcom.", "OMX.Intel." }; 77 {"OMX.qcom.", "OMX.Intel." };
75 // List of supported HW H.264 codecs. 78 // List of supported HW H.264 codecs.
76 private static final String[] supportedH264HwCodecPrefixes = 79 private static final String[] supportedH264HwCodecPrefixes =
(...skipping 24 matching lines...) Expand all
101 }; 104 };
102 private int colorFormat; 105 private int colorFormat;
103 // Video encoder type. 106 // Video encoder type.
104 private VideoCodecType type; 107 private VideoCodecType type;
105 // SPS and PPS NALs (Config frame) for H.264. 108 // SPS and PPS NALs (Config frame) for H.264.
106 private ByteBuffer configData = null; 109 private ByteBuffer configData = null;
107 110
108 private MediaCodecVideoEncoder() { 111 private MediaCodecVideoEncoder() {
109 } 112 }
110 113
114 // MediaCodec error handler - invoked when critical error happens which may pr event
115 // further use of media codec API. Now it means that one of media codec instan ces
116 // is hanging and can no longer be used in the next call.
117 public static interface MediaCodecVideoEncoderErrorCallback {
118 void onMediaCodecVideoEncoderCriticalError(int codecErrors);
119 }
120
121 public static void setErrorCallback(MediaCodecVideoEncoderErrorCallback errorC allback) {
122 Logging.d(TAG, "Set error callback");
123 MediaCodecVideoEncoder.errorCallback = errorCallback;
124 }
125
111 // Helper struct for findHwEncoder() below. 126 // Helper struct for findHwEncoder() below.
112 private static class EncoderProperties { 127 private static class EncoderProperties {
113 public EncoderProperties(String codecName, int colorFormat) { 128 public EncoderProperties(String codecName, int colorFormat) {
114 this.codecName = codecName; 129 this.codecName = codecName;
115 this.colorFormat = colorFormat; 130 this.colorFormat = colorFormat;
116 } 131 }
117 public final String codecName; // OpenMax component name for HW codec. 132 public final String codecName; // OpenMax component name for HW codec.
118 public final int colorFormat; // Color format supported by codec. 133 public final int colorFormat; // Color format supported by codec.
119 } 134 }
120 135
121 private static EncoderProperties findHwEncoder( 136 private static EncoderProperties findHwEncoder(
122 String mime, String[] supportedHwCodecPrefixes) { 137 String mime, String[] supportedHwCodecPrefixes) {
123 // MediaCodec.setParameters is missing for JB and below, so bitrate 138 // MediaCodec.setParameters is missing for JB and below, so bitrate
124 // can not be adjusted dynamically. 139 // can not be adjusted dynamically.
125 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 140 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
126 return null; 141 return null;
127 } 142 }
128 143
129 // Check if device is in H.264 exception list. 144 // Check if device is in H.264 exception list.
130 if (mime.equals(H264_MIME_TYPE)) { 145 if (mime.equals(H264_MIME_TYPE)) {
131 List<String> exceptionModels = Arrays.asList(H264_HW_EXCEPTION_MODELS); 146 List<String> exceptionModels = Arrays.asList(H264_HW_EXCEPTION_MODELS);
132 if (exceptionModels.contains(Build.MODEL)) { 147 if (exceptionModels.contains(Build.MODEL)) {
133 Logging.w(TAG, "Model: " + Build.MODEL + 148 Logging.w(TAG, "Model: " + Build.MODEL + " has black listed H.264 encode r.");
134 " has black listed H.264 encoder.");
135 return null; 149 return null;
136 } 150 }
137 } 151 }
138 152
139 for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) { 153 for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) {
140 MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); 154 MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
141 if (!info.isEncoder()) { 155 if (!info.isEncoder()) {
142 continue; 156 continue;
143 } 157 }
144 String name = null; 158 String name = null;
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
299 } 313 }
300 catch (IllegalStateException e) { 314 catch (IllegalStateException e) {
301 Logging.e(TAG, "encode failed", e); 315 Logging.e(TAG, "encode failed", e);
302 return false; 316 return false;
303 } 317 }
304 } 318 }
305 319
306 private void release() { 320 private void release() {
307 Logging.d(TAG, "Java releaseEncoder"); 321 Logging.d(TAG, "Java releaseEncoder");
308 checkOnMediaCodecThread(); 322 checkOnMediaCodecThread();
309 try { 323
310 mediaCodec.stop(); 324 // Run Mediacodec stop() and release() on separate thread since sometime
311 mediaCodec.release(); 325 // Mediacodec.stop() may hang.
312 } catch (IllegalStateException e) { 326 final CountDownLatch releaseDone = new CountDownLatch(1);
313 Logging.e(TAG, "release failed", e); 327
328 Runnable runMediaCodecRelease = new Runnable() {
329 @Override
330 public void run() {
331 try {
332 Logging.d(TAG, "Java releaseEncoder on release thread");
333 mediaCodec.stop();
334 mediaCodec.release();
335 Logging.d(TAG, "Java releaseEncoder on release thread done");
336 } catch (Exception e) {
337 Logging.e(TAG, "Media encoder release failed", e);
338 }
339 releaseDone.countDown();
340 }
341 };
342 new Thread(runMediaCodecRelease).start();
343
344 if (!ThreadUtils.awaitUninterruptibly(releaseDone, MEDIA_CODEC_RELEASE_TIMEO UT_MS)) {
345 Logging.e(TAG, "Media encoder release timeout");
346 codecErrors++;
347 if (errorCallback != null) {
348 Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors);
349 errorCallback.onMediaCodecVideoEncoderCriticalError(codecErrors);
350 }
314 } 351 }
352
315 mediaCodec = null; 353 mediaCodec = null;
316 mediaCodecThread = null; 354 mediaCodecThread = null;
317 runningInstance = null; 355 runningInstance = null;
318 Logging.d(TAG, "Java releaseEncoder done"); 356 Logging.d(TAG, "Java releaseEncoder done");
319 } 357 }
320 358
321 private boolean setRates(int kbps, int frameRateIgnored) { 359 private boolean setRates(int kbps, int frameRateIgnored) {
322 // frameRate argument is ignored - HW encoder is supposed to use 360 // frameRate argument is ignored - HW encoder is supposed to use
323 // video frame timestamps for bit allocation. 361 // video frame timestamps for bit allocation.
324 checkOnMediaCodecThread(); 362 checkOnMediaCodecThread();
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 checkOnMediaCodecThread(); 476 checkOnMediaCodecThread();
439 try { 477 try {
440 mediaCodec.releaseOutputBuffer(index, false); 478 mediaCodec.releaseOutputBuffer(index, false);
441 return true; 479 return true;
442 } catch (IllegalStateException e) { 480 } catch (IllegalStateException e) {
443 Logging.e(TAG, "releaseOutputBuffer failed", e); 481 Logging.e(TAG, "releaseOutputBuffer failed", e);
444 return false; 482 return false;
445 } 483 }
446 } 484 }
447 } 485 }
OLDNEW
« no previous file with comments | « talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698