summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorglaznev@webrtc.org <glaznev@webrtc.org>2014-10-02 16:58:05 +0000
committerglaznev@webrtc.org <glaznev@webrtc.org>2014-10-02 16:58:05 +0000
commit82879aa0ad673396619ac98c045b85507c3756d0 (patch)
treec64b3d7fe0510ab831fcb015234cb5ef932b27f6 /app
parent73bd0010ca660942b2b5dff514414ba271f79df2 (diff)
downloadtalk-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.cc28
-rw-r--r--app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java31
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);
}