OLD | NEW |
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 14 matching lines...) Expand all Loading... |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 */ | 26 */ |
27 | 27 |
28 package org.webrtc; | 28 package org.webrtc; |
29 | 29 |
30 import android.media.MediaCodec; | 30 import android.media.MediaCodec; |
31 import android.media.MediaCodecInfo; | 31 import android.media.MediaCodecInfo; |
32 import android.media.MediaCodecInfo.CodecCapabilities; | 32 import android.media.MediaCodecInfo.CodecCapabilities; |
33 import android.media.MediaCodecList; | 33 import android.media.MediaCodecList; |
34 import android.media.MediaFormat; | 34 import android.media.MediaFormat; |
35 import android.opengl.EGLContext; | |
36 import android.opengl.GLES11Ext; | |
37 import android.opengl.GLES20; | |
38 import android.os.Build; | 35 import android.os.Build; |
39 import android.view.Surface; | 36 import android.view.Surface; |
40 | 37 |
41 import org.webrtc.Logging; | 38 import org.webrtc.Logging; |
42 | 39 |
43 import java.nio.ByteBuffer; | 40 import java.nio.ByteBuffer; |
44 import java.util.Arrays; | 41 import java.util.Arrays; |
45 import java.util.List; | 42 import java.util.List; |
46 import java.util.concurrent.TimeUnit; | 43 import java.util.concurrent.TimeUnit; |
47 | 44 |
(...skipping 10 matching lines...) Expand all Loading... |
58 private static final String TAG = "MediaCodecVideoDecoder"; | 55 private static final String TAG = "MediaCodecVideoDecoder"; |
59 | 56 |
60 // Tracks webrtc::VideoCodecType. | 57 // Tracks webrtc::VideoCodecType. |
61 public enum VideoCodecType { | 58 public enum VideoCodecType { |
62 VIDEO_CODEC_VP8, | 59 VIDEO_CODEC_VP8, |
63 VIDEO_CODEC_VP9, | 60 VIDEO_CODEC_VP9, |
64 VIDEO_CODEC_H264 | 61 VIDEO_CODEC_H264 |
65 } | 62 } |
66 | 63 |
67 private static final int DEQUEUE_INPUT_TIMEOUT = 500000; // 500 ms timeout. | 64 private static final int DEQUEUE_INPUT_TIMEOUT = 500000; // 500 ms timeout. |
| 65 private static MediaCodecVideoDecoder instance; |
68 private Thread mediaCodecThread; | 66 private Thread mediaCodecThread; |
69 private MediaCodec mediaCodec; | 67 private MediaCodec mediaCodec; |
70 private ByteBuffer[] inputBuffers; | 68 private ByteBuffer[] inputBuffers; |
71 private ByteBuffer[] outputBuffers; | 69 private ByteBuffer[] outputBuffers; |
72 private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8"; | 70 private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8"; |
73 private static final String H264_MIME_TYPE = "video/avc"; | 71 private static final String H264_MIME_TYPE = "video/avc"; |
74 // List of supported HW VP8 decoders. | 72 // List of supported HW VP8 decoders. |
75 private static final String[] supportedVp8HwCodecPrefixes = | 73 private static final String[] supportedVp8HwCodecPrefixes = |
76 {"OMX.qcom.", "OMX.Nvidia.", "OMX.Exynos.", "OMX.Intel." }; | 74 {"OMX.qcom.", "OMX.Nvidia.", "OMX.Exynos.", "OMX.Intel." }; |
77 // List of supported HW H.264 decoders. | 75 // List of supported HW H.264 decoders. |
(...skipping 15 matching lines...) Expand all Loading... |
93 private int stride; | 91 private int stride; |
94 private int sliceHeight; | 92 private int sliceHeight; |
95 private boolean useSurface; | 93 private boolean useSurface; |
96 // |isWaitingForTexture| is true when waiting for the transition: | 94 // |isWaitingForTexture| is true when waiting for the transition: |
97 // MediaCodec.releaseOutputBuffer() -> onTextureFrameAvailable(). | 95 // MediaCodec.releaseOutputBuffer() -> onTextureFrameAvailable(). |
98 private boolean isWaitingForTexture = false; | 96 private boolean isWaitingForTexture = false; |
99 private TextureListener textureListener; | 97 private TextureListener textureListener; |
100 private Surface surface = null; | 98 private Surface surface = null; |
101 | 99 |
102 private MediaCodecVideoDecoder() { | 100 private MediaCodecVideoDecoder() { |
103 mediaCodecThread = null; | 101 instance = this; |
104 } | 102 } |
105 | 103 |
106 // Helper struct for findVp8Decoder() below. | 104 // Helper struct for findVp8Decoder() below. |
107 private static class DecoderProperties { | 105 private static class DecoderProperties { |
108 public DecoderProperties(String codecName, int colorFormat) { | 106 public DecoderProperties(String codecName, int colorFormat) { |
109 this.codecName = codecName; | 107 this.codecName = codecName; |
110 this.colorFormat = colorFormat; | 108 this.colorFormat = colorFormat; |
111 } | 109 } |
112 public final String codecName; // OpenMax component name for VP8 codec. | 110 public final String codecName; // OpenMax component name for VP8 codec. |
113 public final int colorFormat; // Color format supported by codec. | 111 public final int colorFormat; // Color format supported by codec. |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 } | 166 } |
169 | 167 |
170 public static boolean isVp8HwSupported() { | 168 public static boolean isVp8HwSupported() { |
171 return findDecoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes) != null; | 169 return findDecoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes) != null; |
172 } | 170 } |
173 | 171 |
174 public static boolean isH264HwSupported() { | 172 public static boolean isH264HwSupported() { |
175 return findDecoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes) != null; | 173 return findDecoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes) != null; |
176 } | 174 } |
177 | 175 |
| 176 public static void printStackTrace() { |
| 177 if (instance != null && instance.mediaCodecThread != null) { |
| 178 StackTraceElement[] mediaCodecStackTraces = instance.mediaCodecThread.getS
tackTrace(); |
| 179 if (mediaCodecStackTraces.length > 0) { |
| 180 Logging.d(TAG, "MediaCodecVideoDecoder stacks trace:"); |
| 181 for (StackTraceElement stackTrace : mediaCodecStackTraces) { |
| 182 Logging.d(TAG, stackTrace.toString()); |
| 183 } |
| 184 } |
| 185 } |
| 186 } |
| 187 |
178 private void checkOnMediaCodecThread() throws IllegalStateException { | 188 private void checkOnMediaCodecThread() throws IllegalStateException { |
179 if (mediaCodecThread.getId() != Thread.currentThread().getId()) { | 189 if (mediaCodecThread.getId() != Thread.currentThread().getId()) { |
180 throw new IllegalStateException( | 190 throw new IllegalStateException( |
181 "MediaCodecVideoDecoder previously operated on " + mediaCodecThread + | 191 "MediaCodecVideoDecoder previously operated on " + mediaCodecThread + |
182 " but is now called on " + Thread.currentThread()); | 192 " but is now called on " + Thread.currentThread()); |
183 } | 193 } |
184 } | 194 } |
185 | 195 |
186 // Pass null in |surfaceTextureHelper| to configure the codec for ByteBuffer o
utput. | 196 // Pass null in |surfaceTextureHelper| to configure the codec for ByteBuffer o
utput. |
187 private boolean initDecode( | 197 private boolean initDecode( |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 } | 231 } |
222 | 232 |
223 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); | 233 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); |
224 if (!useSurface) { | 234 if (!useSurface) { |
225 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat); | 235 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat); |
226 } | 236 } |
227 Logging.d(TAG, " Format: " + format); | 237 Logging.d(TAG, " Format: " + format); |
228 mediaCodec = | 238 mediaCodec = |
229 MediaCodecVideoEncoder.createByCodecName(properties.codecName); | 239 MediaCodecVideoEncoder.createByCodecName(properties.codecName); |
230 if (mediaCodec == null) { | 240 if (mediaCodec == null) { |
| 241 Logging.e(TAG, "Can not create media decoder"); |
231 return false; | 242 return false; |
232 } | 243 } |
233 mediaCodec.configure(format, surface, null, 0); | 244 mediaCodec.configure(format, surface, null, 0); |
234 mediaCodec.start(); | 245 mediaCodec.start(); |
235 colorFormat = properties.colorFormat; | 246 colorFormat = properties.colorFormat; |
236 outputBuffers = mediaCodec.getOutputBuffers(); | 247 outputBuffers = mediaCodec.getOutputBuffers(); |
237 inputBuffers = mediaCodec.getInputBuffers(); | 248 inputBuffers = mediaCodec.getInputBuffers(); |
238 Logging.d(TAG, "Input buffers: " + inputBuffers.length + | 249 Logging.d(TAG, "Input buffers: " + inputBuffers.length + |
239 ". Output buffers: " + outputBuffers.length); | 250 ". Output buffers: " + outputBuffers.length); |
240 return true; | 251 return true; |
241 } catch (IllegalStateException e) { | 252 } catch (IllegalStateException e) { |
242 Logging.e(TAG, "initDecode failed", e); | 253 Logging.e(TAG, "initDecode failed", e); |
243 return false; | 254 return false; |
244 } | 255 } |
245 } | 256 } |
246 | 257 |
247 private void release() { | 258 private void release() { |
248 Logging.d(TAG, "Java releaseDecoder"); | 259 Logging.d(TAG, "Java releaseDecoder"); |
249 checkOnMediaCodecThread(); | 260 checkOnMediaCodecThread(); |
250 try { | 261 try { |
251 mediaCodec.stop(); | 262 mediaCodec.stop(); |
252 mediaCodec.release(); | 263 mediaCodec.release(); |
253 } catch (IllegalStateException e) { | 264 } catch (IllegalStateException e) { |
254 Logging.e(TAG, "release failed", e); | 265 Logging.e(TAG, "release failed", e); |
255 } | 266 } |
256 mediaCodec = null; | 267 mediaCodec = null; |
257 mediaCodecThread = null; | 268 mediaCodecThread = null; |
| 269 instance = null; |
258 if (useSurface) { | 270 if (useSurface) { |
259 surface.release(); | 271 surface.release(); |
260 surface = null; | 272 surface = null; |
261 textureListener.release(); | 273 textureListener.release(); |
262 } | 274 } |
| 275 Logging.d(TAG, "Java releaseDecoder done"); |
263 } | 276 } |
264 | 277 |
265 // Dequeue an input buffer and return its index, -1 if no input buffer is | 278 // Dequeue an input buffer and return its index, -1 if no input buffer is |
266 // available, or -2 if the codec is no longer operative. | 279 // available, or -2 if the codec is no longer operative. |
267 private int dequeueInputBuffer() { | 280 private int dequeueInputBuffer() { |
268 checkOnMediaCodecThread(); | 281 checkOnMediaCodecThread(); |
269 try { | 282 try { |
270 return mediaCodec.dequeueInputBuffer(DEQUEUE_INPUT_TIMEOUT); | 283 return mediaCodec.dequeueInputBuffer(DEQUEUE_INPUT_TIMEOUT); |
271 } catch (IllegalStateException e) { | 284 } catch (IllegalStateException e) { |
272 Logging.e(TAG, "dequeueIntputBuffer failed", e); | 285 Logging.e(TAG, "dequeueIntputBuffer failed", e); |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 // MediaCodec.CodecException upon codec error. | 463 // MediaCodec.CodecException upon codec error. |
451 private void returnDecodedByteBuffer(int index) | 464 private void returnDecodedByteBuffer(int index) |
452 throws IllegalStateException, MediaCodec.CodecException { | 465 throws IllegalStateException, MediaCodec.CodecException { |
453 checkOnMediaCodecThread(); | 466 checkOnMediaCodecThread(); |
454 if (useSurface) { | 467 if (useSurface) { |
455 throw new IllegalStateException("returnDecodedByteBuffer() called for surf
ace decoding."); | 468 throw new IllegalStateException("returnDecodedByteBuffer() called for surf
ace decoding."); |
456 } | 469 } |
457 mediaCodec.releaseOutputBuffer(index, false /* render */); | 470 mediaCodec.releaseOutputBuffer(index, false /* render */); |
458 } | 471 } |
459 } | 472 } |
OLD | NEW |