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

Unified Diff: webrtc/api/android/jni/androidmediaencoder_jni.cc

Issue 2263043003: Make MediaCodecEncoder fallback to a software encoder on failure. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fallback instead of trying to reset the encoder. Created 4 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | webrtc/video/video_encoder.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/api/android/jni/androidmediaencoder_jni.cc
diff --git a/webrtc/api/android/jni/androidmediaencoder_jni.cc b/webrtc/api/android/jni/androidmediaencoder_jni.cc
index 8d0d3b54bd512557401dcf652b94d62d930388f4..bdd308ce93a8e38ac7895dadbb6a62c69dc968bc 100644
--- a/webrtc/api/android/jni/androidmediaencoder_jni.cc
+++ b/webrtc/api/android/jni/androidmediaencoder_jni.cc
@@ -126,11 +126,6 @@ class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
const char* ImplementationName() const override;
private:
- // ResetCodecOnCodecThread() calls ReleaseOnCodecThread() and
- // InitEncodeOnCodecThread() in an attempt to restore the codec to an
- // operable state. Necessary after all manner of OMX-layer errors.
- bool ResetCodecOnCodecThread();
-
// Implementation of webrtc::VideoEncoder methods above, all running on the
// codec thread exclusively.
//
@@ -282,6 +277,8 @@ class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
int64_t last_frame_received_ms_;
int frames_received_since_last_key_;
webrtc::VideoCodecMode codec_mode_;
+
+ bool sw_fallback_required_;
};
MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
@@ -289,25 +286,27 @@ MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
Release();
}
-MediaCodecVideoEncoder::MediaCodecVideoEncoder(
- JNIEnv* jni, VideoCodecType codecType, jobject egl_context) :
- codecType_(codecType),
- callback_(NULL),
- codec_thread_(new Thread()),
- j_media_codec_video_encoder_class_(
- jni,
- FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
- j_media_codec_video_encoder_(
- jni,
- jni->NewObject(*j_media_codec_video_encoder_class_,
- GetMethodID(jni,
- *j_media_codec_video_encoder_class_,
- "<init>",
- "()V"))),
- inited_(false),
- use_surface_(false),
- picture_id_(0),
- egl_context_(egl_context) {
+MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni,
+ VideoCodecType codecType,
+ jobject egl_context)
+ : codecType_(codecType),
+ callback_(NULL),
+ codec_thread_(new Thread()),
+ j_media_codec_video_encoder_class_(
+ jni,
+ FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
+ j_media_codec_video_encoder_(
+ jni,
+ jni->NewObject(*j_media_codec_video_encoder_class_,
+ GetMethodID(jni,
+ *j_media_codec_video_encoder_class_,
+ "<init>",
+ "()V"))),
+ inited_(false),
+ use_surface_(false),
+ picture_id_(0),
+ egl_context_(egl_context),
+ sw_fallback_required_(false) {
ScopedLocalRefFrame local_ref_frame(jni);
// It would be nice to avoid spinning up a new thread per MediaCodec, and
// instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
@@ -361,7 +360,10 @@ MediaCodecVideoEncoder::MediaCodecVideoEncoder(
GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
j_info_presentation_timestamp_us_field_ = GetFieldID(
jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
- CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed";
+ if (CheckException(jni)) {
+ ALOGW << "MediaCodecVideoEncoder ctor failed. Falling back to SW encoder.";
+ sw_fallback_required_ = true;
+ }
srand(time(NULL));
AllowBlockingCalls();
}
@@ -491,23 +493,12 @@ void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
LogStatistics(false);
}
-bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() {
- RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
- ALOGE << "ResetOnCodecThread";
- if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK ||
- InitEncodeOnCodecThread(width_, height_, 0, 0, false) !=
- WEBRTC_VIDEO_CODEC_OK) {
- // TODO(fischman): wouldn't it be nice if there was a way to gracefully
- // degrade to a SW encoder at this point? There isn't one AFAICT :(
- // https://code.google.com/p/webrtc/issues/detail?id=2920
- return false;
- }
- return true;
-}
-
int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
int width, int height, int kbps, int fps, bool use_surface) {
RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
+ if (sw_fallback_required_) {
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+ }
RTC_CHECK(!use_surface || egl_context_ != nullptr) << "EGL context not set.";
JNIEnv* jni = AttachCurrentThreadIfNeeded();
ScopedLocalRefFrame local_ref_frame(jni);
@@ -562,13 +553,22 @@ int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
ALOGE << "Failed to configure encoder.";
return WEBRTC_VIDEO_CODEC_ERROR;
AlexG 2016/08/31 00:25:57 fallback to sw encoder here. Still return error, b
sakal 2016/09/02 08:08:00 Done.
}
- CHECK_EXCEPTION(jni);
+ if (CheckException(jni)) {
+ ALOGE << "Exception in init encode. Falling back to SW encoder.";
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
AlexG 2016/08/31 00:25:58 return WEBRTC_VIDEO_CODEC_ERROR? In decoder WEBRT
sakal 2016/09/02 08:08:00 Done.
+ }
if (!use_surface) {
jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
jni->CallObjectMethod(*j_media_codec_video_encoder_,
j_get_input_buffers_method_));
- CHECK_EXCEPTION(jni);
+ if (CheckException(jni)) {
+ ALOGE << "Exception in get input buffers. Falling back to SW encoder.";
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+ }
+
if (IsNull(jni, input_buffers)) {
return WEBRTC_VIDEO_CODEC_ERROR;
AlexG 2016/08/31 00:25:57 set sw_fallback_required_ = true
sakal 2016/09/02 08:08:01 Done.
}
@@ -596,7 +596,12 @@ int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
int64_t yuv_buffer_capacity =
jni->GetDirectBufferCapacity(input_buffers_[i]);
- CHECK_EXCEPTION(jni);
+ if (CheckException(jni)) {
+ ALOGE << "Exception in get direct buffer capacity. Falling back to SW "
+ "encoder.";
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+ }
RTC_CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity";
}
}
@@ -610,6 +615,9 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
const std::vector<webrtc::FrameType>* frame_types,
const int64_t frame_input_time_ms) {
RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
+ if (sw_fallback_required_) {
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+ }
JNIEnv* jni = AttachCurrentThreadIfNeeded();
ScopedLocalRefFrame local_ref_frame(jni);
@@ -636,8 +644,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
frames_received_++;
if (!DeliverPendingOutputs(jni)) {
- if (!ResetCodecOnCodecThread())
- return WEBRTC_VIDEO_CODEC_ERROR;
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
}
if (frames_encoded_ < kMaxEncodedLogFrames) {
ALOGD << "Encoder frame in # " << (frames_received_ - 1)
@@ -670,8 +678,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
if (consecutive_full_queue_frame_drops_ >=
ENCODER_STALL_FRAMEDROP_THRESHOLD) {
ALOGE << "Encoder got stuck. Reset.";
- ResetCodecOnCodecThread();
- return WEBRTC_VIDEO_CODEC_ERROR;
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
}
frames_dropped_media_encoder_++;
OnDroppedFrameOnCodecThread();
@@ -715,7 +723,11 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
if (!input_frame.video_frame_buffer()->native_handle()) {
int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
j_dequeue_input_buffer_method_);
- CHECK_EXCEPTION(jni);
+ if (CheckException(jni)) {
+ ALOGE << "Exception in dequeu input buffer. Falling back to SW encoder.";
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+ }
if (j_input_buffer_index == -1) {
// Video codec falls behind - no input buffer available.
ALOGW << "Encoder drop frame - no input buffers available";
@@ -731,8 +743,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
}
return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
} else if (j_input_buffer_index == -2) {
- ResetCodecOnCodecThread();
- return WEBRTC_VIDEO_CODEC_ERROR;
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
}
encode_status = EncodeByteBufferOnCodecThread(jni, key_frame, input_frame,
j_input_buffer_index);
@@ -742,8 +754,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
if (!encode_status) {
ALOGE << "Failed encode frame with timestamp: " << input_frame.timestamp();
- ResetCodecOnCodecThread();
- return WEBRTC_VIDEO_CODEC_ERROR;
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
}
// Save input image timestamps for later output.
@@ -761,8 +773,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
if (!DeliverPendingOutputs(jni)) {
ALOGE << "Failed deliver pending outputs.";
- ResetCodecOnCodecThread();
- return WEBRTC_VIDEO_CODEC_ERROR;
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
}
return WEBRTC_VIDEO_CODEC_OK;
}
@@ -810,7 +822,12 @@ bool MediaCodecVideoEncoder::EncodeByteBufferOnCodecThread(JNIEnv* jni,
jobject j_input_buffer = input_buffers_[input_buffer_index];
uint8_t* yuv_buffer =
reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
- CHECK_EXCEPTION(jni);
+ if (CheckException(jni)) {
+ ALOGE << "Exception in get direct buffer address. Falling back to SW "
+ "encoder.";
+ sw_fallback_required_ = true;
AlexG 2016/08/31 00:25:57 We can not fallback to SW encoder for H.264 codec
sakal 2016/09/02 08:08:00 Done.
+ return false;
+ }
RTC_CHECK(yuv_buffer) << "Indirect buffer??";
RTC_CHECK(!libyuv::ConvertFromI420(
frame.video_frame_buffer()->DataY(),
@@ -828,7 +845,11 @@ bool MediaCodecVideoEncoder::EncodeByteBufferOnCodecThread(JNIEnv* jni,
input_buffer_index,
yuv_size_,
current_timestamp_us_);
- CHECK_EXCEPTION(jni);
+ if (CheckException(jni)) {
+ ALOGE << "Exception in encode buffer. Falling back to SW encoder.";
+ sw_fallback_required_ = true;
+ return false;
+ }
return encode_status;
}
@@ -845,7 +866,11 @@ bool MediaCodecVideoEncoder::EncodeTextureOnCodecThread(JNIEnv* jni,
handle->oes_texture_id,
sampling_matrix,
current_timestamp_us_);
- CHECK_EXCEPTION(jni);
+ if (CheckException(jni)) {
+ ALOGE << "Exception in encode texture. Falling back to SW encoder.";
+ sw_fallback_required_ = true;
+ return false;
+ }
return encode_status;
}
@@ -872,7 +897,11 @@ int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
jni->DeleteGlobalRef(input_buffers_[i]);
input_buffers_.clear();
jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
- CHECK_EXCEPTION(jni);
+ if (CheckException(jni)) {
+ ALOGE << "Exception in release. Falling back to SW encoder.";
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
AlexG 2016/08/31 00:25:58 Return error here?
sakal 2016/09/02 08:08:01 Done.
+ }
rtc::MessageQueueManager::Clear(this);
inited_ = false;
use_surface_ = false;
@@ -883,6 +912,9 @@ int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
uint32_t frame_rate) {
RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
+ if (sw_fallback_required_) {
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
AlexG 2016/08/31 00:25:58 Return WEBRTC_VIDEO_CODEC_OK here? WEBRTC_VIDEO_CO
sakal 2016/09/02 08:08:00 Done.
+ }
frame_rate = (frame_rate < MAX_ALLOWED_VIDEO_FPS) ?
frame_rate : MAX_ALLOWED_VIDEO_FPS;
if (last_set_bitrate_kbps_ == new_bit_rate &&
@@ -904,10 +936,9 @@ int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
j_set_rates_method_,
last_set_bitrate_kbps_,
last_set_fps_);
- CHECK_EXCEPTION(jni);
- if (!ret) {
- ResetCodecOnCodecThread();
- return WEBRTC_VIDEO_CODEC_ERROR;
+ if (CheckException(jni) || !ret) {
+ sw_fallback_required_ = true;
AlexG 2016/08/31 00:25:58 ditto: Return WEBRTC_VIDEO_CODEC_OK here, but keep
sakal 2016/09/02 08:08:00 Done.
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
}
return WEBRTC_VIDEO_CODEC_OK;
}
@@ -943,7 +974,12 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
while (true) {
jobject j_output_buffer_info = jni->CallObjectMethod(
*j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
- CHECK_EXCEPTION(jni);
+ if (CheckException(jni)) {
+ ALOGE << "Exception in set dequeue output buffer. Falling back to SW "
+ "encoder.";
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+ }
if (IsNull(jni, j_output_buffer_info)) {
break;
}
@@ -951,7 +987,7 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
int output_buffer_index =
GetOutputBufferInfoIndex(jni, j_output_buffer_info);
if (output_buffer_index == -1) {
- ResetCodecOnCodecThread();
+ sw_fallback_required_ = true;
return false;
}
@@ -979,7 +1015,12 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
uint8_t* payload = reinterpret_cast<uint8_t*>(
jni->GetDirectBufferAddress(j_output_buffer));
- CHECK_EXCEPTION(jni);
+ if (CheckException(jni)) {
+ ALOGE << "Exception in get direct buffer address. Falling back to SW "
+ "encoder.";
+ sw_fallback_required_ = true;
+ return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+ }
// Callback - return encoded frame.
int32_t callback_status = 0;
@@ -1079,7 +1120,7 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
ALOGE << "Data:" << image->_buffer[0] << " " << image->_buffer[1]
<< " " << image->_buffer[2] << " " << image->_buffer[3]
<< " " << image->_buffer[4] << " " << image->_buffer[5];
- ResetCodecOnCodecThread();
+ sw_fallback_required_ = true;
AlexG 2016/08/31 00:25:58 You can not fallback to SW for H.264 encoder - we
sakal 2016/09/02 08:08:01 Done.
return false;
}
scPositions[scPositionsLength] = payload_size;
@@ -1100,9 +1141,8 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
j_release_output_buffer_method_,
output_buffer_index);
- CHECK_EXCEPTION(jni);
- if (!success) {
- ResetCodecOnCodecThread();
+ if (CheckException(jni) || !success) {
+ sw_fallback_required_ = true;
return false;
}
« no previous file with comments | « no previous file | webrtc/video/video_encoder.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698