diff options
author | glaznev@webrtc.org <glaznev@webrtc.org> | 2014-10-02 16:58:05 +0000 |
---|---|---|
committer | glaznev@webrtc.org <glaznev@webrtc.org> | 2014-10-02 16:58:05 +0000 |
commit | 82879aa0ad673396619ac98c045b85507c3756d0 (patch) | |
tree | c64b3d7fe0510ab831fcb015234cb5ef932b27f6 /app | |
parent | 73bd0010ca660942b2b5dff514414ba271f79df2 (diff) | |
download | talk-82879aa0ad673396619ac98c045b85507c3756d0.tar.gz |
Switch to SW video decoder on Android after getting 2 or more
critical errors from HW decoder.
BUG=410730
R=tkchin@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/23819004
git-svn-id: http://webrtc.googlecode.com/svn/trunk/talk@7368 4adac7df-926f-26a2-2b94-8c16560cd09d
Diffstat (limited to 'app')
-rw-r--r-- | app/webrtc/java/jni/peerconnection_jni.cc | 28 | ||||
-rw-r--r-- | app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java | 31 |
2 files changed, 40 insertions, 19 deletions
diff --git a/app/webrtc/java/jni/peerconnection_jni.cc b/app/webrtc/java/jni/peerconnection_jni.cc index 92acd7b..f482848 100644 --- a/app/webrtc/java/jni/peerconnection_jni.cc +++ b/app/webrtc/java/jni/peerconnection_jni.cc @@ -1993,6 +1993,7 @@ class MediaCodecVideoDecoder : public webrtc::VideoDecoder, bool key_frame_required_; bool inited_; bool use_surface_; + int error_count_; VideoCodec codec_; I420VideoFrame decoded_image_; NativeHandleImpl native_handle_; @@ -2072,6 +2073,7 @@ int MediaCodecVideoDecoder::SetAndroidObjects(JNIEnv* jni, MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni) : key_frame_required_(true), inited_(false), + error_count_(0), codec_thread_(new Thread()), j_media_codec_video_decoder_class_( jni, @@ -2089,7 +2091,7 @@ MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni) j_init_decode_method_ = GetMethodID( jni, *j_media_codec_video_decoder_class_, "initDecode", - "(IIZLandroid/opengl/EGLContext;)Z"); + "(IIZZLandroid/opengl/EGLContext;)Z"); j_release_method_ = GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V"); j_dequeue_input_buffer_method_ = GetMethodID( @@ -2176,13 +2178,19 @@ int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() { CheckOnCodecThread(); JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedLocalRefFrame local_ref_frame(jni); - ALOGD("InitDecodeOnCodecThread: %d x %d. fps: %d", - codec_.width, codec_.height, codec_.maxFramerate); + ALOGD("InitDecodeOnCodecThread: %d x %d. Fps: %d. Errors: %d", + codec_.width, codec_.height, codec_.maxFramerate, error_count_); + bool use_sw_codec = false; + if (error_count_ > 1) { + // If more than one critical errors happen for HW codec, switch to SW codec. + use_sw_codec = true; + } bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_, j_init_decode_method_, codec_.width, codec_.height, + use_sw_codec, use_surface_, render_egl_context_); CHECK_EXCEPTION(jni); @@ -2320,11 +2328,13 @@ int32_t MediaCodecVideoDecoder::DecodeOnCodecThread( if (frames_received_ > frames_decoded_ + max_pending_frames_) { ALOGV("Wait for output..."); if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) { + error_count_++; Reset(); return WEBRTC_VIDEO_CODEC_ERROR; } if (frames_received_ > frames_decoded_ + max_pending_frames_) { ALOGE("Output buffer dequeue timeout"); + error_count_++; Reset(); return WEBRTC_VIDEO_CODEC_ERROR; } @@ -2336,6 +2346,7 @@ int32_t MediaCodecVideoDecoder::DecodeOnCodecThread( CHECK_EXCEPTION(jni); if (j_input_buffer_index < 0) { ALOGE("dequeueInputBuffer error"); + error_count_++; Reset(); return WEBRTC_VIDEO_CODEC_ERROR; } @@ -2350,6 +2361,7 @@ int32_t MediaCodecVideoDecoder::DecodeOnCodecThread( if (buffer_capacity < inputImage._length) { ALOGE("Input frame size %d is bigger than buffer size %d.", inputImage._length, buffer_capacity); + error_count_++; Reset(); return WEBRTC_VIDEO_CODEC_ERROR; } @@ -2374,6 +2386,7 @@ int32_t MediaCodecVideoDecoder::DecodeOnCodecThread( CHECK_EXCEPTION(jni); if (!success) { ALOGE("queueInputBuffer error"); + error_count_++; Reset(); return WEBRTC_VIDEO_CODEC_ERROR; } @@ -2381,6 +2394,7 @@ int32_t MediaCodecVideoDecoder::DecodeOnCodecThread( // Try to drain the decoder if (!DeliverPendingOutputs(jni, 0)) { ALOGE("DeliverPendingOutputs error"); + error_count_++; Reset(); return WEBRTC_VIDEO_CODEC_ERROR; } @@ -2410,7 +2424,6 @@ bool MediaCodecVideoDecoder::DeliverPendingOutputs( GetIntField(jni, j_decoder_output_buffer_info, j_info_index_field_); if (output_buffer_index < 0) { ALOGE("dequeueOutputBuffer error : %d", output_buffer_index); - Reset(); return false; } int output_buffer_offset = @@ -2435,7 +2448,6 @@ bool MediaCodecVideoDecoder::DeliverPendingOutputs( if (!use_surface_) { if (output_buffer_size < width * height * 3 / 2) { ALOGE("Insufficient output buffer size: %d", output_buffer_size); - Reset(); return false; } jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField( @@ -2494,7 +2506,6 @@ bool MediaCodecVideoDecoder::DeliverPendingOutputs( CHECK_EXCEPTION(jni); if (!success) { ALOGE("releaseOutputBuffer error"); - Reset(); return false; } @@ -2561,7 +2572,10 @@ void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) { CHECK(!msg->pdata) << "Unexpected message!"; CheckOnCodecThread(); - DeliverPendingOutputs(jni, 0); + if (!DeliverPendingOutputs(jni, 0)) { + error_count_++; + Reset(); + } codec_thread_->PostDelayed(kMediaCodecPollMs, this); } diff --git a/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java b/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java index 9280743..fcb3d3f 100644 --- a/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java +++ b/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java @@ -68,6 +68,9 @@ class MediaCodecVideoDecoder { // List of supported HW VP8 decoders. private static final String[] supportedHwCodecPrefixes = {"OMX.qcom.", "OMX.Nvidia." }; + // List of supported SW VP8 decoders. + private static final String[] supportedSwCodecPrefixes = + {"OMX.google."}; // NV12 color format supported by QCOM codec, but not declared in MediaCodec - // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h private static final int @@ -96,7 +99,7 @@ class MediaCodecVideoDecoder { private MediaCodecVideoDecoder() { } - // Helper struct for findVp8HwDecoder() below. + // Helper struct for findVp8Decoder() below. private static class DecoderProperties { public DecoderProperties(String codecName, int colorFormat) { this.codecName = codecName; @@ -106,10 +109,14 @@ class MediaCodecVideoDecoder { public final int colorFormat; // Color format supported by codec. } - private static DecoderProperties findVp8HwDecoder() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) + private static DecoderProperties findVp8Decoder(boolean useSwCodec) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { return null; // MediaCodec.setParameters is missing. - + } + String[] supportedCodecPrefixes = supportedHwCodecPrefixes; + if (useSwCodec) { + supportedCodecPrefixes = supportedSwCodecPrefixes; + } for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) { MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); if (info.isEncoder()) { @@ -127,10 +134,10 @@ class MediaCodecVideoDecoder { } Log.d(TAG, "Found candidate decoder " + name); - // Check if this is supported HW decoder. + // Check if this is supported decoder. boolean supportedCodec = false; - for (String hwCodecPrefix : supportedHwCodecPrefixes) { - if (name.startsWith(hwCodecPrefix)) { + for (String codecPrefix : supportedCodecPrefixes) { + if (name.startsWith(codecPrefix)) { supportedCodec = true; break; } @@ -160,7 +167,7 @@ class MediaCodecVideoDecoder { } private static boolean isPlatformSupported() { - return findVp8HwDecoder() != null; + return findVp8Decoder(false) != null; } private void checkOnMediaCodecThread() { @@ -265,21 +272,21 @@ class MediaCodecVideoDecoder { } } - private boolean initDecode(int width, int height, boolean useSurface, - EGLContext sharedContext) { + private boolean initDecode(int width, int height, boolean useSwCodec, + boolean useSurface, EGLContext sharedContext) { if (mediaCodecThread != null) { throw new RuntimeException("Forgot to release()?"); } if (useSurface && sharedContext == null) { throw new RuntimeException("No shared EGL context."); } - DecoderProperties properties = findVp8HwDecoder(); + DecoderProperties properties = findVp8Decoder(useSwCodec); if (properties == null) { throw new RuntimeException("Cannot find HW VP8 decoder"); } Log.d(TAG, "Java initDecode: " + width + " x " + height + ". Color: 0x" + Integer.toHexString(properties.colorFormat) + - ". Use Surface: " + useSurface ); + ". Use Surface: " + useSurface + ". Use SW codec: " + useSwCodec); if (sharedContext != null) { Log.d(TAG, "Decoder shared EGL Context: " + sharedContext); } |