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

Side by Side Diff: webrtc/sdk/android/api/org/webrtc/MediaCodecVideoEncoder.java

Issue 2748123002: Better handling of error condition in MediaCodecVideoEncoder. (Closed)
Patch Set: Change error message. Created 3 years, 9 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 * Copyright 2013 The WebRTC project authors. All Rights Reserved. 2 * Copyright 2013 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 format.setInteger(MediaFormat.KEY_BIT_RATE, targetBitrateBps); 447 format.setInteger(MediaFormat.KEY_BIT_RATE, targetBitrateBps);
448 format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); 448 format.setInteger("bitrate-mode", VIDEO_ControlRateConstant);
449 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat); 449 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
450 format.setInteger(MediaFormat.KEY_FRAME_RATE, targetFps); 450 format.setInteger(MediaFormat.KEY_FRAME_RATE, targetFps);
451 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec); 451 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec);
452 Logging.d(TAG, " Format: " + format); 452 Logging.d(TAG, " Format: " + format);
453 mediaCodec = createByCodecName(properties.codecName); 453 mediaCodec = createByCodecName(properties.codecName);
454 this.type = type; 454 this.type = type;
455 if (mediaCodec == null) { 455 if (mediaCodec == null) {
456 Logging.e(TAG, "Can not create media encoder"); 456 Logging.e(TAG, "Can not create media encoder");
457 release();
457 return false; 458 return false;
458 } 459 }
459 mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE) ; 460 mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE) ;
460 461
461 if (useSurface) { 462 if (useSurface) {
462 eglBase = new EglBase14(sharedContext, EglBase.CONFIG_RECORDABLE); 463 eglBase = new EglBase14(sharedContext, EglBase.CONFIG_RECORDABLE);
463 // Create an input surface and keep a reference since we must release th e surface when done. 464 // Create an input surface and keep a reference since we must release th e surface when done.
464 inputSurface = mediaCodec.createInputSurface(); 465 inputSurface = mediaCodec.createInputSurface();
465 eglBase.createSurface(inputSurface); 466 eglBase.createSurface(inputSurface);
466 drawer = new GlRectDrawer(); 467 drawer = new GlRectDrawer();
467 } 468 }
468 mediaCodec.start(); 469 mediaCodec.start();
469 outputBuffers = mediaCodec.getOutputBuffers(); 470 outputBuffers = mediaCodec.getOutputBuffers();
470 Logging.d(TAG, "Output buffers: " + outputBuffers.length); 471 Logging.d(TAG, "Output buffers: " + outputBuffers.length);
471 472
472 } catch (IllegalStateException e) { 473 } catch (IllegalStateException e) {
473 Logging.e(TAG, "initEncode failed", e); 474 Logging.e(TAG, "initEncode failed", e);
475 release();
474 return false; 476 return false;
475 } 477 }
476 return true; 478 return true;
477 } 479 }
478 480
479 ByteBuffer[] getInputBuffers() { 481 ByteBuffer[] getInputBuffers() {
480 ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers(); 482 ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
481 Logging.d(TAG, "Input buffers: " + inputBuffers.length); 483 Logging.d(TAG, "Input buffers: " + inputBuffers.length);
482 return inputBuffers; 484 return inputBuffers;
483 } 485 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 } catch (RuntimeException e) { 539 } catch (RuntimeException e) {
538 Logging.e(TAG, "encodeTexture failed", e); 540 Logging.e(TAG, "encodeTexture failed", e);
539 return false; 541 return false;
540 } 542 }
541 } 543 }
542 544
543 void release() { 545 void release() {
544 Logging.d(TAG, "Java releaseEncoder"); 546 Logging.d(TAG, "Java releaseEncoder");
545 checkOnMediaCodecThread(); 547 checkOnMediaCodecThread();
546 548
547 // Run Mediacodec stop() and release() on separate thread since sometime 549 class CaughtException {
548 // Mediacodec.stop() may hang. 550 Exception e;
549 final CountDownLatch releaseDone = new CountDownLatch(1); 551 }
552 final CaughtException caughtException = new CaughtException();
553 boolean stopHung = false;
550 554
551 Runnable runMediaCodecRelease = new Runnable() { 555 if (mediaCodec != null) {
552 @Override 556 // Run Mediacodec stop() and release() on separate thread since sometime
553 public void run() { 557 // Mediacodec.stop() may hang.
554 try { 558 final CountDownLatch releaseDone = new CountDownLatch(1);
559
560 Runnable runMediaCodecRelease = new Runnable() {
561 @Override
562 public void run() {
555 Logging.d(TAG, "Java releaseEncoder on release thread"); 563 Logging.d(TAG, "Java releaseEncoder on release thread");
556 mediaCodec.stop(); 564 try {
557 mediaCodec.release(); 565 mediaCodec.stop();
566 } catch (Exception e) {
567 Logging.e(TAG, "Media encoder stop failed", e);
568 }
569 try {
570 mediaCodec.release();
571 } catch (Exception e) {
572 Logging.e(TAG, "Media encoder release failed", e);
573 caughtException.e = e;
574 }
558 Logging.d(TAG, "Java releaseEncoder on release thread done"); 575 Logging.d(TAG, "Java releaseEncoder on release thread done");
559 } catch (Exception e) { 576
560 Logging.e(TAG, "Media encoder release failed", e); 577 releaseDone.countDown();
561 } 578 }
562 releaseDone.countDown(); 579 };
580 new Thread(runMediaCodecRelease).start();
581
582 if (!ThreadUtils.awaitUninterruptibly(releaseDone, MEDIA_CODEC_RELEASE_TIM EOUT_MS)) {
583 Logging.e(TAG, "Media encoder release timeout");
584 stopHung = true;
563 } 585 }
564 };
565 new Thread(runMediaCodecRelease).start();
566 586
567 if (!ThreadUtils.awaitUninterruptibly(releaseDone, MEDIA_CODEC_RELEASE_TIMEO UT_MS)) { 587 mediaCodec = null;
568 Logging.e(TAG, "Media encoder release timeout");
569 codecErrors++;
570 if (errorCallback != null) {
571 Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors);
572 errorCallback.onMediaCodecVideoEncoderCriticalError(codecErrors);
573 }
574 } 588 }
575 589
576 mediaCodec = null;
577 mediaCodecThread = null; 590 mediaCodecThread = null;
578 if (drawer != null) { 591 if (drawer != null) {
579 drawer.release(); 592 drawer.release();
580 drawer = null; 593 drawer = null;
581 } 594 }
582 if (eglBase != null) { 595 if (eglBase != null) {
583 eglBase.release(); 596 eglBase.release();
584 eglBase = null; 597 eglBase = null;
585 } 598 }
586 if (inputSurface != null) { 599 if (inputSurface != null) {
587 inputSurface.release(); 600 inputSurface.release();
588 inputSurface = null; 601 inputSurface = null;
589 } 602 }
590 runningInstance = null; 603 runningInstance = null;
604
605 if (stopHung) {
606 codecErrors++;
607 if (errorCallback != null) {
608 Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors);
609 errorCallback.onMediaCodecVideoEncoderCriticalError(codecErrors);
610 }
611 throw new RuntimeException("Media encoder release timeout.");
612 }
613
614 // Re-throw any runtime exception caught inside the other thread. Since this is an invoke, add
615 // stack trace for the waiting thread as well.
616 if (caughtException.e != null) {
617 final RuntimeException runtimeException = new RuntimeException(caughtExcep tion.e);
618 runtimeException.setStackTrace(ThreadUtils.concatStackTraces(
619 caughtException.e.getStackTrace(), runtimeException.getStackTrace()));
620 throw runtimeException;
621 }
622
591 Logging.d(TAG, "Java releaseEncoder done"); 623 Logging.d(TAG, "Java releaseEncoder done");
592 } 624 }
593 625
594 private boolean setRates(int kbps, int frameRate) { 626 private boolean setRates(int kbps, int frameRate) {
595 checkOnMediaCodecThread(); 627 checkOnMediaCodecThread();
596 628
597 int codecBitrateBps = 1000 * kbps; 629 int codecBitrateBps = 1000 * kbps;
598 if (bitrateAdjustmentType == BitrateAdjustmentType.DYNAMIC_ADJUSTMENT) { 630 if (bitrateAdjustmentType == BitrateAdjustmentType.DYNAMIC_ADJUSTMENT) {
599 bitrateAccumulatorMax = codecBitrateBps / 8.0; 631 bitrateAccumulatorMax = codecBitrateBps / 8.0;
600 if (targetBitrateBps > 0 && codecBitrateBps < targetBitrateBps) { 632 if (targetBitrateBps > 0 && codecBitrateBps < targetBitrateBps) {
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 checkOnMediaCodecThread(); 813 checkOnMediaCodecThread();
782 try { 814 try {
783 mediaCodec.releaseOutputBuffer(index, false); 815 mediaCodec.releaseOutputBuffer(index, false);
784 return true; 816 return true;
785 } catch (IllegalStateException e) { 817 } catch (IllegalStateException e) {
786 Logging.e(TAG, "releaseOutputBuffer failed", e); 818 Logging.e(TAG, "releaseOutputBuffer failed", e);
787 return false; 819 return false;
788 } 820 }
789 } 821 }
790 } 822 }
OLDNEW
« no previous file with comments | « webrtc/base/java/src/org/webrtc/ThreadUtils.java ('k') | webrtc/sdk/android/src/jni/androidmediaencoder_jni.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698