OLD | NEW |
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 15 matching lines...) Expand all Loading... |
26 */ | 26 */ |
27 | 27 |
28 package org.webrtc; | 28 package org.webrtc; |
29 | 29 |
30 import android.annotation.TargetApi; | 30 import android.annotation.TargetApi; |
31 import android.media.MediaCodec; | 31 import android.media.MediaCodec; |
32 import android.media.MediaCodecInfo.CodecCapabilities; | 32 import android.media.MediaCodecInfo.CodecCapabilities; |
33 import android.media.MediaCodecInfo; | 33 import android.media.MediaCodecInfo; |
34 import android.media.MediaCodecList; | 34 import android.media.MediaCodecList; |
35 import android.media.MediaFormat; | 35 import android.media.MediaFormat; |
| 36 import android.opengl.GLES20; |
36 import android.os.Build; | 37 import android.os.Build; |
37 import android.os.Bundle; | 38 import android.os.Bundle; |
| 39 import android.view.Surface; |
38 | 40 |
39 import org.webrtc.Logging; | 41 import org.webrtc.Logging; |
40 | 42 |
41 import java.nio.ByteBuffer; | 43 import java.nio.ByteBuffer; |
42 import java.util.Arrays; | 44 import java.util.Arrays; |
43 import java.util.List; | 45 import java.util.List; |
44 import java.util.concurrent.CountDownLatch; | 46 import java.util.concurrent.CountDownLatch; |
45 | 47 |
| 48 import javax.microedition.khronos.egl.EGLContext; |
| 49 |
46 // Java-side of peerconnection_jni.cc:MediaCodecVideoEncoder. | 50 // Java-side of peerconnection_jni.cc:MediaCodecVideoEncoder. |
47 // This class is an implementation detail of the Java PeerConnection API. | 51 // This class is an implementation detail of the Java PeerConnection API. |
48 @TargetApi(19) | 52 @TargetApi(19) |
49 @SuppressWarnings("deprecation") | 53 @SuppressWarnings("deprecation") |
50 public class MediaCodecVideoEncoder { | 54 public class MediaCodecVideoEncoder { |
51 // This class is constructed, operated, and destroyed by its C++ incarnation, | 55 // This class is constructed, operated, and destroyed by its C++ incarnation, |
52 // 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 |
53 // class exposes aims to mimic the webrtc::VideoEncoder API as closely as | 57 // class exposes aims to mimic the webrtc::VideoEncoder API as closely as |
54 // possibly to minimize the amount of translation work necessary. | 58 // possibly to minimize the amount of translation work necessary. |
55 | 59 |
(...skipping 10 matching lines...) Expand all Loading... |
66 private static final int DEQUEUE_TIMEOUT = 0; // Non-blocking, no wait. | 70 private static final int DEQUEUE_TIMEOUT = 0; // Non-blocking, no wait. |
67 // Active running encoder instance. Set in initEncode() (called from native co
de) | 71 // Active running encoder instance. Set in initEncode() (called from native co
de) |
68 // and reset to null in release() call. | 72 // and reset to null in release() call. |
69 private static MediaCodecVideoEncoder runningInstance = null; | 73 private static MediaCodecVideoEncoder runningInstance = null; |
70 private static MediaCodecVideoEncoderErrorCallback errorCallback = null; | 74 private static MediaCodecVideoEncoderErrorCallback errorCallback = null; |
71 private static int codecErrors = 0; | 75 private static int codecErrors = 0; |
72 | 76 |
73 private Thread mediaCodecThread; | 77 private Thread mediaCodecThread; |
74 private MediaCodec mediaCodec; | 78 private MediaCodec mediaCodec; |
75 private ByteBuffer[] outputBuffers; | 79 private ByteBuffer[] outputBuffers; |
| 80 private EglBase eglBase; |
| 81 private Surface inputSurface; |
| 82 private GlRectDrawer drawer; |
76 private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8"; | 83 private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8"; |
77 private static final String VP9_MIME_TYPE = "video/x-vnd.on2.vp9"; | 84 private static final String VP9_MIME_TYPE = "video/x-vnd.on2.vp9"; |
78 private static final String H264_MIME_TYPE = "video/avc"; | 85 private static final String H264_MIME_TYPE = "video/avc"; |
79 // List of supported HW VP8 codecs. | 86 // List of supported HW VP8 codecs. |
80 private static final String[] supportedVp8HwCodecPrefixes = | 87 private static final String[] supportedVp8HwCodecPrefixes = |
81 {"OMX.qcom.", "OMX.Intel." }; | 88 {"OMX.qcom.", "OMX.Intel." }; |
82 // List of supported HW VP9 decoders. | 89 // List of supported HW VP9 decoders. |
83 private static final String[] supportedVp9HwCodecPrefixes = | 90 private static final String[] supportedVp9HwCodecPrefixes = |
84 {"OMX.qcom."}; | 91 {"OMX.qcom."}; |
85 // List of supported HW H.264 codecs. | 92 // List of supported HW H.264 codecs. |
(...skipping 16 matching lines...) Expand all Loading... |
102 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h | 109 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h |
103 private static final int | 110 private static final int |
104 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04; | 111 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04; |
105 // Allowable color formats supported by codec - in order of preference. | 112 // Allowable color formats supported by codec - in order of preference. |
106 private static final int[] supportedColorList = { | 113 private static final int[] supportedColorList = { |
107 CodecCapabilities.COLOR_FormatYUV420Planar, | 114 CodecCapabilities.COLOR_FormatYUV420Planar, |
108 CodecCapabilities.COLOR_FormatYUV420SemiPlanar, | 115 CodecCapabilities.COLOR_FormatYUV420SemiPlanar, |
109 CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, | 116 CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, |
110 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m | 117 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m |
111 }; | 118 }; |
| 119 private static final int[] supportedSurfaceColorList = { |
| 120 CodecCapabilities.COLOR_FormatSurface |
| 121 }; |
112 private VideoCodecType type; | 122 private VideoCodecType type; |
113 private int colorFormat; // Used by native code. | 123 private int colorFormat; // Used by native code. |
114 | 124 |
115 // SPS and PPS NALs (Config frame) for H.264. | 125 // SPS and PPS NALs (Config frame) for H.264. |
116 private ByteBuffer configData = null; | 126 private ByteBuffer configData = null; |
117 | 127 |
118 // MediaCodec error handler - invoked when critical error happens which may pr
event | 128 // MediaCodec error handler - invoked when critical error happens which may pr
event |
119 // further use of media codec API. Now it means that one of media codec instan
ces | 129 // further use of media codec API. Now it means that one of media codec instan
ces |
120 // is hanging and can no longer be used in the next call. | 130 // is hanging and can no longer be used in the next call. |
121 public static interface MediaCodecVideoEncoderErrorCallback { | 131 public static interface MediaCodecVideoEncoderErrorCallback { |
122 void onMediaCodecVideoEncoderCriticalError(int codecErrors); | 132 void onMediaCodecVideoEncoderCriticalError(int codecErrors); |
123 } | 133 } |
124 | 134 |
125 public static void setErrorCallback(MediaCodecVideoEncoderErrorCallback errorC
allback) { | 135 public static void setErrorCallback(MediaCodecVideoEncoderErrorCallback errorC
allback) { |
126 Logging.d(TAG, "Set error callback"); | 136 Logging.d(TAG, "Set error callback"); |
127 MediaCodecVideoEncoder.errorCallback = errorCallback; | 137 MediaCodecVideoEncoder.errorCallback = errorCallback; |
128 } | 138 } |
129 | 139 |
130 // Helper struct for findHwEncoder() below. | 140 // Helper struct for findHwEncoder() below. |
131 private static class EncoderProperties { | 141 private static class EncoderProperties { |
132 public EncoderProperties(String codecName, int colorFormat) { | 142 public EncoderProperties(String codecName, int colorFormat) { |
133 this.codecName = codecName; | 143 this.codecName = codecName; |
134 this.colorFormat = colorFormat; | 144 this.colorFormat = colorFormat; |
135 } | 145 } |
136 public final String codecName; // OpenMax component name for HW codec. | 146 public final String codecName; // OpenMax component name for HW codec. |
137 public final int colorFormat; // Color format supported by codec. | 147 public final int colorFormat; // Color format supported by codec. |
138 } | 148 } |
139 | 149 |
140 private static EncoderProperties findHwEncoder( | 150 private static EncoderProperties findHwEncoder( |
141 String mime, String[] supportedHwCodecPrefixes) { | 151 String mime, String[] supportedHwCodecPrefixes, int[] colorList) { |
142 // MediaCodec.setParameters is missing for JB and below, so bitrate | 152 // MediaCodec.setParameters is missing for JB and below, so bitrate |
143 // can not be adjusted dynamically. | 153 // can not be adjusted dynamically. |
144 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { | 154 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { |
145 return null; | 155 return null; |
146 } | 156 } |
147 | 157 |
148 // Check if device is in H.264 exception list. | 158 // Check if device is in H.264 exception list. |
149 if (mime.equals(H264_MIME_TYPE)) { | 159 if (mime.equals(H264_MIME_TYPE)) { |
150 List<String> exceptionModels = Arrays.asList(H264_HW_EXCEPTION_MODELS); | 160 List<String> exceptionModels = Arrays.asList(H264_HW_EXCEPTION_MODELS); |
151 if (exceptionModels.contains(Build.MODEL)) { | 161 if (exceptionModels.contains(Build.MODEL)) { |
(...skipping 29 matching lines...) Expand all Loading... |
181 } | 191 } |
182 if (!supportedCodec) { | 192 if (!supportedCodec) { |
183 continue; | 193 continue; |
184 } | 194 } |
185 | 195 |
186 CodecCapabilities capabilities = info.getCapabilitiesForType(mime); | 196 CodecCapabilities capabilities = info.getCapabilitiesForType(mime); |
187 for (int colorFormat : capabilities.colorFormats) { | 197 for (int colorFormat : capabilities.colorFormats) { |
188 Logging.v(TAG, " Color: 0x" + Integer.toHexString(colorFormat)); | 198 Logging.v(TAG, " Color: 0x" + Integer.toHexString(colorFormat)); |
189 } | 199 } |
190 | 200 |
191 // Check if codec supports either yuv420 or nv12. | 201 for (int supportedColorFormat : colorList) { |
192 for (int supportedColorFormat : supportedColorList) { | |
193 for (int codecColorFormat : capabilities.colorFormats) { | 202 for (int codecColorFormat : capabilities.colorFormats) { |
194 if (codecColorFormat == supportedColorFormat) { | 203 if (codecColorFormat == supportedColorFormat) { |
195 // Found supported HW encoder. | 204 // Found supported HW encoder. |
196 Logging.d(TAG, "Found target encoder for mime " + mime + " : " + nam
e + | 205 Logging.d(TAG, "Found target encoder for mime " + mime + " : " + nam
e + |
197 ". Color: 0x" + Integer.toHexString(codecColorFormat)); | 206 ". Color: 0x" + Integer.toHexString(codecColorFormat)); |
198 return new EncoderProperties(name, codecColorFormat); | 207 return new EncoderProperties(name, codecColorFormat); |
199 } | 208 } |
200 } | 209 } |
201 } | 210 } |
202 } | 211 } |
203 return null; // No HW encoder. | 212 return null; // No HW encoder. |
204 } | 213 } |
205 | 214 |
206 public static boolean isVp8HwSupported() { | 215 public static boolean isVp8HwSupported() { |
207 return findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes) != null; | 216 return findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes, supportedCo
lorList) != null; |
208 } | 217 } |
209 | 218 |
210 public static boolean isVp9HwSupported() { | 219 public static boolean isVp9HwSupported() { |
211 return findHwEncoder(VP9_MIME_TYPE, supportedVp9HwCodecPrefixes) != null; | 220 return findHwEncoder(VP9_MIME_TYPE, supportedVp9HwCodecPrefixes, supportedCo
lorList) != null; |
212 } | 221 } |
| 222 |
213 public static boolean isH264HwSupported() { | 223 public static boolean isH264HwSupported() { |
214 return findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes) != null; | 224 return findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes, supported
ColorList) != null; |
| 225 } |
| 226 |
| 227 public static boolean isVp8HwSupportedUsingTextures() { |
| 228 return findHwEncoder( |
| 229 VP8_MIME_TYPE, supportedVp8HwCodecPrefixes, supportedSurfaceColorList) !
= null; |
| 230 } |
| 231 |
| 232 public static boolean isVp9HwSupportedUsingTextures() { |
| 233 return findHwEncoder( |
| 234 VP9_MIME_TYPE, supportedVp9HwCodecPrefixes, supportedSurfaceColorList) !
= null; |
| 235 } |
| 236 |
| 237 public static boolean isH264HwSupportedUsingTextures() { |
| 238 return findHwEncoder( |
| 239 H264_MIME_TYPE, supportedH264HwCodecPrefixes, supportedSurfaceColorList)
!= null; |
215 } | 240 } |
216 | 241 |
217 private void checkOnMediaCodecThread() { | 242 private void checkOnMediaCodecThread() { |
218 if (mediaCodecThread.getId() != Thread.currentThread().getId()) { | 243 if (mediaCodecThread.getId() != Thread.currentThread().getId()) { |
219 throw new RuntimeException( | 244 throw new RuntimeException( |
220 "MediaCodecVideoEncoder previously operated on " + mediaCodecThread + | 245 "MediaCodecVideoEncoder previously operated on " + mediaCodecThread + |
221 " but is now called on " + Thread.currentThread()); | 246 " but is now called on " + Thread.currentThread()); |
222 } | 247 } |
223 } | 248 } |
224 | 249 |
(...skipping 12 matching lines...) Expand all Loading... |
237 static MediaCodec createByCodecName(String codecName) { | 262 static MediaCodec createByCodecName(String codecName) { |
238 try { | 263 try { |
239 // In the L-SDK this call can throw IOException so in order to work in | 264 // In the L-SDK this call can throw IOException so in order to work in |
240 // both cases catch an exception. | 265 // both cases catch an exception. |
241 return MediaCodec.createByCodecName(codecName); | 266 return MediaCodec.createByCodecName(codecName); |
242 } catch (Exception e) { | 267 } catch (Exception e) { |
243 return null; | 268 return null; |
244 } | 269 } |
245 } | 270 } |
246 | 271 |
247 // Returns false if the hardware encoder currently can't be used. | 272 boolean initEncode(VideoCodecType type, int width, int height, int kbps, int f
ps, |
248 boolean initEncode(VideoCodecType type, int width, int height, int kbps, int f
ps) { | 273 EGLContext sharedContext) { |
| 274 final boolean useSurface = sharedContext != null; |
249 Logging.d(TAG, "Java initEncode: " + type + " : " + width + " x " + height + | 275 Logging.d(TAG, "Java initEncode: " + type + " : " + width + " x " + height + |
250 ". @ " + kbps + " kbps. Fps: " + fps + "."); | 276 ". @ " + kbps + " kbps. Fps: " + fps + ". Encode from texture : " + useS
urface); |
251 | 277 |
252 if (mediaCodecThread != null) { | 278 if (mediaCodecThread != null) { |
253 throw new RuntimeException("Forgot to release()?"); | 279 throw new RuntimeException("Forgot to release()?"); |
254 } | 280 } |
255 EncoderProperties properties = null; | 281 EncoderProperties properties = null; |
256 String mime = null; | 282 String mime = null; |
257 int keyFrameIntervalSec = 0; | 283 int keyFrameIntervalSec = 0; |
258 if (type == VideoCodecType.VIDEO_CODEC_VP8) { | 284 if (type == VideoCodecType.VIDEO_CODEC_VP8) { |
259 mime = VP8_MIME_TYPE; | 285 mime = VP8_MIME_TYPE; |
260 properties = findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes); | 286 properties = findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes, |
| 287 useSurface ? supportedSurfaceColorList : supportedColorList); |
261 keyFrameIntervalSec = 100; | 288 keyFrameIntervalSec = 100; |
262 } else if (type == VideoCodecType.VIDEO_CODEC_VP9) { | 289 } else if (type == VideoCodecType.VIDEO_CODEC_VP9) { |
263 mime = VP9_MIME_TYPE; | 290 mime = VP9_MIME_TYPE; |
264 properties = findHwEncoder(VP9_MIME_TYPE, supportedH264HwCodecPrefixes); | 291 properties = findHwEncoder(VP9_MIME_TYPE, supportedH264HwCodecPrefixes, |
| 292 useSurface ? supportedSurfaceColorList : supportedColorList); |
265 keyFrameIntervalSec = 100; | 293 keyFrameIntervalSec = 100; |
266 } else if (type == VideoCodecType.VIDEO_CODEC_H264) { | 294 } else if (type == VideoCodecType.VIDEO_CODEC_H264) { |
267 mime = H264_MIME_TYPE; | 295 mime = H264_MIME_TYPE; |
268 properties = findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes); | 296 properties = findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes, |
| 297 useSurface ? supportedSurfaceColorList : supportedColorList); |
269 keyFrameIntervalSec = 20; | 298 keyFrameIntervalSec = 20; |
270 } | 299 } |
271 if (properties == null) { | 300 if (properties == null) { |
272 throw new RuntimeException("Can not find HW encoder for " + type); | 301 throw new RuntimeException("Can not find HW encoder for " + type); |
273 } | 302 } |
274 runningInstance = this; // Encoder is now running and can be queried for sta
ck traces. | 303 runningInstance = this; // Encoder is now running and can be queried for sta
ck traces. |
275 colorFormat = properties.colorFormat; | 304 colorFormat = properties.colorFormat; |
276 Logging.d(TAG, "Color format: " + colorFormat); | 305 Logging.d(TAG, "Color format: " + colorFormat); |
277 | 306 |
278 mediaCodecThread = Thread.currentThread(); | 307 mediaCodecThread = Thread.currentThread(); |
279 try { | 308 try { |
280 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); | 309 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); |
281 format.setInteger(MediaFormat.KEY_BIT_RATE, 1000 * kbps); | 310 format.setInteger(MediaFormat.KEY_BIT_RATE, 1000 * kbps); |
282 format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); | 311 format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); |
283 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat); | 312 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat); |
284 format.setInteger(MediaFormat.KEY_FRAME_RATE, fps); | 313 format.setInteger(MediaFormat.KEY_FRAME_RATE, fps); |
285 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec); | 314 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec); |
286 Logging.d(TAG, " Format: " + format); | 315 Logging.d(TAG, " Format: " + format); |
287 mediaCodec = createByCodecName(properties.codecName); | 316 mediaCodec = createByCodecName(properties.codecName); |
288 this.type = type; | 317 this.type = type; |
289 if (mediaCodec == null) { | 318 if (mediaCodec == null) { |
290 Logging.e(TAG, "Can not create media encoder"); | 319 Logging.e(TAG, "Can not create media encoder"); |
291 return false; | 320 return false; |
292 } | 321 } |
293 mediaCodec.configure( | 322 mediaCodec.configure( |
294 format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); | 323 format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); |
295 | 324 |
| 325 if (useSurface) { |
| 326 eglBase = new EglBase(sharedContext, EglBase.ConfigType.RECORDABLE); |
| 327 // Create an input surface and keep a reference since we must release th
e surface when done. |
| 328 inputSurface = mediaCodec.createInputSurface(); |
| 329 eglBase.createSurface(inputSurface); |
| 330 drawer = new GlRectDrawer(); |
| 331 } |
296 mediaCodec.start(); | 332 mediaCodec.start(); |
297 outputBuffers = mediaCodec.getOutputBuffers(); | 333 outputBuffers = mediaCodec.getOutputBuffers(); |
298 Logging.d(TAG, "Output buffers: " + outputBuffers.length); | 334 Logging.d(TAG, "Output buffers: " + outputBuffers.length); |
299 | 335 |
300 } catch (IllegalStateException e) { | 336 } catch (IllegalStateException e) { |
301 Logging.e(TAG, "initEncode failed", e); | 337 Logging.e(TAG, "initEncode failed", e); |
302 return false; | 338 return false; |
303 } | 339 } |
304 return true; | 340 return true; |
305 } | 341 } |
(...skipping 22 matching lines...) Expand all Loading... |
328 mediaCodec.queueInputBuffer( | 364 mediaCodec.queueInputBuffer( |
329 inputBuffer, 0, size, presentationTimestampUs, 0); | 365 inputBuffer, 0, size, presentationTimestampUs, 0); |
330 return true; | 366 return true; |
331 } | 367 } |
332 catch (IllegalStateException e) { | 368 catch (IllegalStateException e) { |
333 Logging.e(TAG, "encodeBuffer failed", e); | 369 Logging.e(TAG, "encodeBuffer failed", e); |
334 return false; | 370 return false; |
335 } | 371 } |
336 } | 372 } |
337 | 373 |
| 374 boolean encodeTexture(boolean isKeyframe, int oesTextureId, float[] transforma
tionMatrix, |
| 375 long presentationTimestampUs) { |
| 376 checkOnMediaCodecThread(); |
| 377 try { |
| 378 if (isKeyframe) { |
| 379 Logging.d(TAG, "Sync frame request"); |
| 380 Bundle b = new Bundle(); |
| 381 b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0); |
| 382 mediaCodec.setParameters(b); |
| 383 } |
| 384 eglBase.makeCurrent(); |
| 385 drawer.drawOes(oesTextureId, transformationMatrix); |
| 386 // TODO(perkj): Do we have to call EGLExt.eglPresentationTimeANDROID ? |
| 387 // If not, remove |presentationTimestampUs|. |
| 388 eglBase.swapBuffers(); |
| 389 return true; |
| 390 } |
| 391 catch (RuntimeException e) { |
| 392 Logging.e(TAG, "encodeTexture failed", e); |
| 393 return false; |
| 394 } |
| 395 } |
| 396 |
338 void release() { | 397 void release() { |
339 Logging.d(TAG, "Java releaseEncoder"); | 398 Logging.d(TAG, "Java releaseEncoder"); |
340 checkOnMediaCodecThread(); | 399 checkOnMediaCodecThread(); |
341 | 400 |
342 // Run Mediacodec stop() and release() on separate thread since sometime | 401 // Run Mediacodec stop() and release() on separate thread since sometime |
343 // Mediacodec.stop() may hang. | 402 // Mediacodec.stop() may hang. |
344 final CountDownLatch releaseDone = new CountDownLatch(1); | 403 final CountDownLatch releaseDone = new CountDownLatch(1); |
345 | 404 |
346 Runnable runMediaCodecRelease = new Runnable() { | 405 Runnable runMediaCodecRelease = new Runnable() { |
347 @Override | 406 @Override |
(...skipping 15 matching lines...) Expand all Loading... |
363 Logging.e(TAG, "Media encoder release timeout"); | 422 Logging.e(TAG, "Media encoder release timeout"); |
364 codecErrors++; | 423 codecErrors++; |
365 if (errorCallback != null) { | 424 if (errorCallback != null) { |
366 Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors); | 425 Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors); |
367 errorCallback.onMediaCodecVideoEncoderCriticalError(codecErrors); | 426 errorCallback.onMediaCodecVideoEncoderCriticalError(codecErrors); |
368 } | 427 } |
369 } | 428 } |
370 | 429 |
371 mediaCodec = null; | 430 mediaCodec = null; |
372 mediaCodecThread = null; | 431 mediaCodecThread = null; |
| 432 if (drawer != null) { |
| 433 drawer.release(); |
| 434 drawer = null; |
| 435 } |
| 436 if (eglBase != null) { |
| 437 eglBase.release(); |
| 438 eglBase = null; |
| 439 } |
| 440 if (inputSurface != null) { |
| 441 inputSurface.release(); |
| 442 inputSurface = null; |
| 443 } |
373 runningInstance = null; | 444 runningInstance = null; |
374 Logging.d(TAG, "Java releaseEncoder done"); | 445 Logging.d(TAG, "Java releaseEncoder done"); |
375 } | 446 } |
376 | 447 |
377 private boolean setRates(int kbps, int frameRateIgnored) { | 448 private boolean setRates(int kbps, int frameRateIgnored) { |
378 // frameRate argument is ignored - HW encoder is supposed to use | 449 // frameRate argument is ignored - HW encoder is supposed to use |
379 // video frame timestamps for bit allocation. | 450 // video frame timestamps for bit allocation. |
380 checkOnMediaCodecThread(); | 451 checkOnMediaCodecThread(); |
381 Logging.v(TAG, "setRates: " + kbps + " kbps. Fps: " + frameRateIgnored); | 452 Logging.v(TAG, "setRates: " + kbps + " kbps. Fps: " + frameRateIgnored); |
382 try { | 453 try { |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
494 checkOnMediaCodecThread(); | 565 checkOnMediaCodecThread(); |
495 try { | 566 try { |
496 mediaCodec.releaseOutputBuffer(index, false); | 567 mediaCodec.releaseOutputBuffer(index, false); |
497 return true; | 568 return true; |
498 } catch (IllegalStateException e) { | 569 } catch (IllegalStateException e) { |
499 Logging.e(TAG, "releaseOutputBuffer failed", e); | 570 Logging.e(TAG, "releaseOutputBuffer failed", e); |
500 return false; | 571 return false; |
501 } | 572 } |
502 } | 573 } |
503 } | 574 } |
OLD | NEW |