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

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

Issue 1394103005: Revert "Android MediaCodecVideoDecoder: Manage lifetime of texture frames" (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Uncomment android capture code and add bug number Created 5 years, 2 months 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,
11 * this list of conditions and the following disclaimer in the documentation 11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution. 12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products 13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
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.graphics.SurfaceTexture;
30 import android.media.MediaCodec; 31 import android.media.MediaCodec;
31 import android.media.MediaCodecInfo; 32 import android.media.MediaCodecInfo;
32 import android.media.MediaCodecInfo.CodecCapabilities; 33 import android.media.MediaCodecInfo.CodecCapabilities;
33 import android.media.MediaCodecList; 34 import android.media.MediaCodecList;
34 import android.media.MediaFormat; 35 import android.media.MediaFormat;
36 import android.opengl.EGLContext;
37 import android.opengl.GLES11Ext;
38 import android.opengl.GLES20;
35 import android.os.Build; 39 import android.os.Build;
36 import android.view.Surface; 40 import android.view.Surface;
37 41
38 import org.webrtc.Logging; 42 import org.webrtc.Logging;
39 43
40 import java.nio.ByteBuffer; 44 import java.nio.ByteBuffer;
41 import java.util.Arrays; 45 import java.util.Arrays;
42 import java.util.List; 46 import java.util.List;
43 import java.util.concurrent.TimeUnit;
44 47
45 // Java-side of peerconnection_jni.cc:MediaCodecVideoDecoder. 48 // Java-side of peerconnection_jni.cc:MediaCodecVideoDecoder.
46 // This class is an implementation detail of the Java PeerConnection API. 49 // This class is an implementation detail of the Java PeerConnection API.
47 // MediaCodec is thread-hostile so this class must be operated on a single 50 // MediaCodec is thread-hostile so this class must be operated on a single
48 // thread. 51 // thread.
49 public class MediaCodecVideoDecoder { 52 public class MediaCodecVideoDecoder {
50 // This class is constructed, operated, and destroyed by its C++ incarnation, 53 // This class is constructed, operated, and destroyed by its C++ incarnation,
51 // 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
52 // 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
53 // possibly to minimize the amount of translation work necessary. 56 // possibly to minimize the amount of translation work necessary.
(...skipping 30 matching lines...) Expand all
84 CodecCapabilities.COLOR_FormatYUV420Planar, 87 CodecCapabilities.COLOR_FormatYUV420Planar,
85 CodecCapabilities.COLOR_FormatYUV420SemiPlanar, 88 CodecCapabilities.COLOR_FormatYUV420SemiPlanar,
86 CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, 89 CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar,
87 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m); 90 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m);
88 private int colorFormat; 91 private int colorFormat;
89 private int width; 92 private int width;
90 private int height; 93 private int height;
91 private int stride; 94 private int stride;
92 private int sliceHeight; 95 private int sliceHeight;
93 private boolean useSurface; 96 private boolean useSurface;
94 // |isWaitingForTexture| is true when waiting for the transition: 97 private int textureID = 0;
95 // MediaCodec.releaseOutputBuffer() -> onTextureFrameAvailable(). 98 private SurfaceTexture surfaceTexture = null;
96 private boolean isWaitingForTexture = false;
97 private TextureListener textureListener;
98 private Surface surface = null; 99 private Surface surface = null;
100 private EglBase eglBase;
99 101
100 private MediaCodecVideoDecoder() { 102 private MediaCodecVideoDecoder() {
101 instance = this; 103 instance = this;
102 } 104 }
103 105
104 // Helper struct for findVp8Decoder() below. 106 // Helper struct for findVp8Decoder() below.
105 private static class DecoderProperties { 107 private static class DecoderProperties {
106 public DecoderProperties(String codecName, int colorFormat) { 108 public DecoderProperties(String codecName, int colorFormat) {
107 this.codecName = codecName; 109 this.codecName = codecName;
108 this.colorFormat = colorFormat; 110 this.colorFormat = colorFormat;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 } 188 }
187 189
188 private void checkOnMediaCodecThread() throws IllegalStateException { 190 private void checkOnMediaCodecThread() throws IllegalStateException {
189 if (mediaCodecThread.getId() != Thread.currentThread().getId()) { 191 if (mediaCodecThread.getId() != Thread.currentThread().getId()) {
190 throw new IllegalStateException( 192 throw new IllegalStateException(
191 "MediaCodecVideoDecoder previously operated on " + mediaCodecThread + 193 "MediaCodecVideoDecoder previously operated on " + mediaCodecThread +
192 " but is now called on " + Thread.currentThread()); 194 " but is now called on " + Thread.currentThread());
193 } 195 }
194 } 196 }
195 197
196 // Pass null in |surfaceTextureHelper| to configure the codec for ByteBuffer o utput. 198 // Pass null in |sharedContext| to configure the codec for ByteBuffer output.
197 private boolean initDecode( 199 private boolean initDecode(VideoCodecType type, int width, int height, EGLCont ext sharedContext) {
198 VideoCodecType type, int width, int height, SurfaceTextureHelper surfaceTe xtureHelper) {
199 if (mediaCodecThread != null) { 200 if (mediaCodecThread != null) {
200 throw new RuntimeException("Forgot to release()?"); 201 throw new RuntimeException("Forgot to release()?");
201 } 202 }
202 useSurface = (surfaceTextureHelper != null); 203 useSurface = (sharedContext != null);
203 String mime = null; 204 String mime = null;
204 String[] supportedCodecPrefixes = null; 205 String[] supportedCodecPrefixes = null;
205 if (type == VideoCodecType.VIDEO_CODEC_VP8) { 206 if (type == VideoCodecType.VIDEO_CODEC_VP8) {
206 mime = VP8_MIME_TYPE; 207 mime = VP8_MIME_TYPE;
207 supportedCodecPrefixes = supportedVp8HwCodecPrefixes; 208 supportedCodecPrefixes = supportedVp8HwCodecPrefixes;
208 } else if (type == VideoCodecType.VIDEO_CODEC_H264) { 209 } else if (type == VideoCodecType.VIDEO_CODEC_H264) {
209 mime = H264_MIME_TYPE; 210 mime = H264_MIME_TYPE;
210 supportedCodecPrefixes = supportedH264HwCodecPrefixes; 211 supportedCodecPrefixes = supportedH264HwCodecPrefixes;
211 } else { 212 } else {
212 throw new RuntimeException("Non supported codec " + type); 213 throw new RuntimeException("Non supported codec " + type);
213 } 214 }
214 DecoderProperties properties = findDecoder(mime, supportedCodecPrefixes); 215 DecoderProperties properties = findDecoder(mime, supportedCodecPrefixes);
215 if (properties == null) { 216 if (properties == null) {
216 throw new RuntimeException("Cannot find HW decoder for " + type); 217 throw new RuntimeException("Cannot find HW decoder for " + type);
217 } 218 }
218 Logging.d(TAG, "Java initDecode: " + type + " : "+ width + " x " + height + 219 Logging.d(TAG, "Java initDecode: " + type + " : "+ width + " x " + height +
219 ". Color: 0x" + Integer.toHexString(properties.colorFormat) + 220 ". Color: 0x" + Integer.toHexString(properties.colorFormat) +
220 ". Use Surface: " + useSurface); 221 ". Use Surface: " + useSurface);
222 if (sharedContext != null) {
223 Logging.d(TAG, "Decoder shared EGL Context: " + sharedContext);
224 }
221 mediaCodecThread = Thread.currentThread(); 225 mediaCodecThread = Thread.currentThread();
222 try { 226 try {
223 this.width = width; 227 this.width = width;
224 this.height = height; 228 this.height = height;
225 stride = width; 229 stride = width;
226 sliceHeight = height; 230 sliceHeight = height;
227 231
228 if (useSurface) { 232 if (useSurface) {
229 textureListener = new TextureListener(surfaceTextureHelper); 233 // Create shared EGL context.
230 surface = new Surface(surfaceTextureHelper.getSurfaceTexture()); 234 eglBase = new EglBase(sharedContext, EglBase.ConfigType.PIXEL_BUFFER);
235 eglBase.createDummyPbufferSurface();
236 eglBase.makeCurrent();
237
238 // Create output surface
239 textureID = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
240 Logging.d(TAG, "Video decoder TextureID = " + textureID);
241 surfaceTexture = new SurfaceTexture(textureID);
242 surface = new Surface(surfaceTexture);
231 } 243 }
232 244
233 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); 245 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
234 if (!useSurface) { 246 if (!useSurface) {
235 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat); 247 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
236 } 248 }
237 Logging.d(TAG, " Format: " + format); 249 Logging.d(TAG, " Format: " + format);
238 mediaCodec = 250 mediaCodec =
239 MediaCodecVideoEncoder.createByCodecName(properties.codecName); 251 MediaCodecVideoEncoder.createByCodecName(properties.codecName);
240 if (mediaCodec == null) { 252 if (mediaCodec == null) {
(...skipping 22 matching lines...) Expand all
263 mediaCodec.release(); 275 mediaCodec.release();
264 } catch (IllegalStateException e) { 276 } catch (IllegalStateException e) {
265 Logging.e(TAG, "release failed", e); 277 Logging.e(TAG, "release failed", e);
266 } 278 }
267 mediaCodec = null; 279 mediaCodec = null;
268 mediaCodecThread = null; 280 mediaCodecThread = null;
269 instance = null; 281 instance = null;
270 if (useSurface) { 282 if (useSurface) {
271 surface.release(); 283 surface.release();
272 surface = null; 284 surface = null;
273 textureListener.release(); 285 Logging.d(TAG, "Delete video decoder TextureID " + textureID);
286 GLES20.glDeleteTextures(1, new int[] {textureID}, 0);
287 textureID = 0;
288 eglBase.release();
289 eglBase = null;
274 } 290 }
275 Logging.d(TAG, "Java releaseDecoder done"); 291 Logging.d(TAG, "Java releaseDecoder done");
276 } 292 }
277 293
278 // Dequeue an input buffer and return its index, -1 if no input buffer is 294 // Dequeue an input buffer and return its index, -1 if no input buffer is
279 // available, or -2 if the codec is no longer operative. 295 // available, or -2 if the codec is no longer operative.
280 private int dequeueInputBuffer() { 296 private int dequeueInputBuffer() {
281 checkOnMediaCodecThread(); 297 checkOnMediaCodecThread();
282 try { 298 try {
283 return mediaCodec.dequeueInputBuffer(DEQUEUE_INPUT_TIMEOUT); 299 return mediaCodec.dequeueInputBuffer(DEQUEUE_INPUT_TIMEOUT);
(...skipping 28 matching lines...) Expand all
312 } 328 }
313 329
314 private final int index; 330 private final int index;
315 private final int offset; 331 private final int offset;
316 private final int size; 332 private final int size;
317 private final long presentationTimestampUs; 333 private final long presentationTimestampUs;
318 } 334 }
319 335
320 private static class DecodedTextureBuffer { 336 private static class DecodedTextureBuffer {
321 private final int textureID; 337 private final int textureID;
322 private final float[] transformMatrix; 338 private final long presentationTimestampUs;
323 private final long timestampNs;
324 339
325 public DecodedTextureBuffer(int textureID, float[] transformMatrix, long tim estampNs) { 340 public DecodedTextureBuffer(int textureID, long presentationTimestampUs) {
326 this.textureID = textureID; 341 this.textureID = textureID;
327 this.transformMatrix = transformMatrix; 342 this.presentationTimestampUs = presentationTimestampUs;
328 this.timestampNs = timestampNs;
329 } 343 }
330 } 344 }
331 345
332 // Poll based texture listener.
333 private static class TextureListener
334 implements SurfaceTextureHelper.OnTextureFrameAvailableListener {
335 private final SurfaceTextureHelper surfaceTextureHelper;
336 private DecodedTextureBuffer textureBuffer;
337 // |newFrameLock| is used to synchronize arrival of new frames with wait()/n otifyAll().
338 private final Object newFrameLock = new Object();
339
340 public TextureListener(SurfaceTextureHelper surfaceTextureHelper) {
341 this.surfaceTextureHelper = surfaceTextureHelper;
342 surfaceTextureHelper.setListener(this);
343 }
344
345 // Callback from |surfaceTextureHelper|. May be called on an arbitrary threa d.
346 @Override
347 public void onTextureFrameAvailable(
348 int oesTextureId, float[] transformMatrix, long timestampNs) {
349 synchronized (newFrameLock) {
350 if (textureBuffer != null) {
351 Logging.e(TAG,
352 "Unexpected onTextureFrameAvailable() called while already holding a texture.");
353 throw new IllegalStateException("Already holding a texture.");
354 }
355 textureBuffer = new DecodedTextureBuffer(oesTextureId, transformMatrix, timestampNs);
356 newFrameLock.notifyAll();
357 }
358 }
359
360 // Dequeues and returns a texture buffer if available, or null otherwise.
361 public DecodedTextureBuffer dequeueTextureFrame(int timeoutMs) {
362 synchronized (newFrameLock) {
363 if (textureBuffer == null && timeoutMs > 0) {
364 try {
365 newFrameLock.wait(timeoutMs);
366 } catch(InterruptedException e) {
367 // Restore the interrupted status by reinterrupting the thread.
368 Thread.currentThread().interrupt();
369 }
370 }
371 final DecodedTextureBuffer textureBuffer = this.textureBuffer;
372 this.textureBuffer = null;
373 return textureBuffer;
374 }
375 }
376
377 public void release() {
378 // SurfaceTextureHelper.disconnect() will block until any onTextureFrameAv ailable() in
379 // progress is done. Therefore, the call to disconnect() must be outside a ny synchronized
380 // statement that is also used in the onTextureFrameAvailable() above to a void deadlocks.
381 surfaceTextureHelper.disconnect();
382 synchronized (newFrameLock) {
383 if (textureBuffer != null) {
384 surfaceTextureHelper.returnTextureFrame();
385 textureBuffer = null;
386 }
387 }
388 }
389 }
390
391 // Returns null if no decoded buffer is available, and otherwise either a Deco dedByteBuffer or 346 // Returns null if no decoded buffer is available, and otherwise either a Deco dedByteBuffer or
392 // DecodedTexturebuffer depending on |useSurface| configuration. 347 // DecodedTexturebuffer depending on |useSurface| configuration.
393 // Throws IllegalStateException if call is made on the wrong thread, if color format changes to an 348 // Throws IllegalStateException if call is made on the wrong thread, if color format changes to an
394 // unsupported format, or if |mediaCodec| is not in the Executing state. Throw s CodecException 349 // unsupported format, or if |mediaCodec| is not in the Executing state. Throw s CodecException
395 // upon codec error. 350 // upon codec error.
396 private Object dequeueOutputBuffer(int dequeueTimeoutMs) 351 private Object dequeueOutputBuffer(int dequeueTimeoutUs)
397 throws IllegalStateException, MediaCodec.CodecException { 352 throws IllegalStateException, MediaCodec.CodecException {
398 checkOnMediaCodecThread(); 353 checkOnMediaCodecThread();
399 // Calling multiple MediaCodec.releaseOutputBuffer() with render=true in a r ow will result in
400 // dropped texture frames. Therefore, wait for any pending onTextureFrameAva ilable() before
401 // proceeding.
402 if (isWaitingForTexture) {
403 final DecodedTextureBuffer textureBuffer =
404 textureListener.dequeueTextureFrame(dequeueTimeoutMs);
405 isWaitingForTexture = (textureBuffer == null);
406 return textureBuffer;
407 }
408
409 // Drain the decoder until receiving a decoded buffer or hitting 354 // Drain the decoder until receiving a decoded buffer or hitting
410 // MediaCodec.INFO_TRY_AGAIN_LATER. 355 // MediaCodec.INFO_TRY_AGAIN_LATER.
411 final MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 356 final MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
412 while (true) { 357 while (true) {
413 final int result = mediaCodec.dequeueOutputBuffer( 358 final int result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs);
414 info, TimeUnit.MILLISECONDS.toMicros(dequeueTimeoutMs));
415 switch (result) { 359 switch (result) {
416 case MediaCodec.INFO_TRY_AGAIN_LATER: 360 case MediaCodec.INFO_TRY_AGAIN_LATER:
417 return null; 361 return null;
418 case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: 362 case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
419 outputBuffers = mediaCodec.getOutputBuffers(); 363 outputBuffers = mediaCodec.getOutputBuffers();
420 Logging.d(TAG, "Decoder output buffers changed: " + outputBuffers.leng th); 364 Logging.d(TAG, "Decoder output buffers changed: " + outputBuffers.leng th);
421 break; 365 break;
422 case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: 366 case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
423 MediaFormat format = mediaCodec.getOutputFormat(); 367 MediaFormat format = mediaCodec.getOutputFormat();
424 Logging.d(TAG, "Decoder format changed: " + format.toString()); 368 Logging.d(TAG, "Decoder format changed: " + format.toString());
(...skipping 13 matching lines...) Expand all
438 sliceHeight = format.getInteger("slice-height"); 382 sliceHeight = format.getInteger("slice-height");
439 } 383 }
440 Logging.d(TAG, "Frame stride and slice height: " + stride + " x " + sl iceHeight); 384 Logging.d(TAG, "Frame stride and slice height: " + stride + " x " + sl iceHeight);
441 stride = Math.max(width, stride); 385 stride = Math.max(width, stride);
442 sliceHeight = Math.max(height, sliceHeight); 386 sliceHeight = Math.max(height, sliceHeight);
443 break; 387 break;
444 default: 388 default:
445 // Output buffer decoded. 389 // Output buffer decoded.
446 if (useSurface) { 390 if (useSurface) {
447 mediaCodec.releaseOutputBuffer(result, true /* render */); 391 mediaCodec.releaseOutputBuffer(result, true /* render */);
448 final DecodedTextureBuffer textureBuffer = 392 // TODO(magjed): Wait for SurfaceTexture.onFrameAvailable() before r eturning a texture
449 textureListener.dequeueTextureFrame(dequeueTimeoutMs); 393 // frame.
450 isWaitingForTexture = (textureBuffer == null); 394 return new DecodedTextureBuffer(textureID, info.presentationTimeUs);
451 return textureBuffer;
452 } else { 395 } else {
453 return new DecodedByteBuffer(result, info.offset, info.size, info.pr esentationTimeUs); 396 return new DecodedByteBuffer(result, info.offset, info.size, info.pr esentationTimeUs);
454 } 397 }
455 } 398 }
456 } 399 }
457 } 400 }
458 401
459 // Release a dequeued output byte buffer back to the codec for re-use. Should only be called for 402 // Release a dequeued output byte buffer back to the codec for re-use. Should only be called for
460 // non-surface decoding. 403 // non-surface decoding.
461 // Throws IllegalStateException if the call is made on the wrong thread, if co dec is configured 404 // Throws IllegalStateException if the call is made on the wrong thread, if co dec is configured
462 // for surface decoding, or if |mediaCodec| is not in the Executing state. Thr ows 405 // for surface decoding, or if |mediaCodec| is not in the Executing state. Thr ows
463 // MediaCodec.CodecException upon codec error. 406 // MediaCodec.CodecException upon codec error.
464 private void returnDecodedByteBuffer(int index) 407 private void returnDecodedByteBuffer(int index)
465 throws IllegalStateException, MediaCodec.CodecException { 408 throws IllegalStateException, MediaCodec.CodecException {
466 checkOnMediaCodecThread(); 409 checkOnMediaCodecThread();
467 if (useSurface) { 410 if (useSurface) {
468 throw new IllegalStateException("returnDecodedByteBuffer() called for surf ace decoding."); 411 throw new IllegalStateException("returnDecodedByteBuffer() called for surf ace decoding.");
469 } 412 }
470 mediaCodec.releaseOutputBuffer(index, false /* render */); 413 mediaCodec.releaseOutputBuffer(index, false /* render */);
471 } 414 }
472 } 415 }
OLDNEW
« no previous file with comments | « talk/app/webrtc/java/jni/surfacetexturehelper_jni.cc ('k') | talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698