OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2015 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 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 int frames_dropped_media_encoder_; // Number of frames dropped by encoder. | 219 int frames_dropped_media_encoder_; // Number of frames dropped by encoder. |
220 // Number of dropped frames caused by full queue. | 220 // Number of dropped frames caused by full queue. |
221 int consecutive_full_queue_frame_drops_; | 221 int consecutive_full_queue_frame_drops_; |
222 int64_t stat_start_time_ms_; // Start time for statistics. | 222 int64_t stat_start_time_ms_; // Start time for statistics. |
223 int current_frames_; // Number of frames in the current statistics interval. | 223 int current_frames_; // Number of frames in the current statistics interval. |
224 int current_bytes_; // Encoded bytes in the current statistics interval. | 224 int current_bytes_; // Encoded bytes in the current statistics interval. |
225 int current_acc_qp_; // Accumulated QP in the current statistics interval. | 225 int current_acc_qp_; // Accumulated QP in the current statistics interval. |
226 int current_encoding_time_ms_; // Overall encoding time in the current second | 226 int current_encoding_time_ms_; // Overall encoding time in the current second |
227 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame. | 227 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame. |
228 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame. | 228 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame. |
229 bool output_delivery_loop_running_; // Is the onMessage loop running | |
230 | 229 |
231 struct InputFrameInfo { | 230 struct InputFrameInfo { |
232 InputFrameInfo(int64_t encode_start_time, | 231 InputFrameInfo(int64_t encode_start_time, |
233 int32_t frame_timestamp, | 232 int32_t frame_timestamp, |
234 int64_t frame_render_time_ms, | 233 int64_t frame_render_time_ms, |
235 webrtc::VideoRotation rotation) | 234 webrtc::VideoRotation rotation) |
236 : encode_start_time(encode_start_time), | 235 : encode_start_time(encode_start_time), |
237 frame_timestamp(frame_timestamp), | 236 frame_timestamp(frame_timestamp), |
238 frame_render_time_ms(frame_render_time_ms), | 237 frame_render_time_ms(frame_render_time_ms), |
239 rotation(rotation) {} | 238 rotation(rotation) {} |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 j_media_codec_video_encoder_( | 299 j_media_codec_video_encoder_( |
301 jni, | 300 jni, |
302 jni->NewObject(*j_media_codec_video_encoder_class_, | 301 jni->NewObject(*j_media_codec_video_encoder_class_, |
303 GetMethodID(jni, | 302 GetMethodID(jni, |
304 *j_media_codec_video_encoder_class_, | 303 *j_media_codec_video_encoder_class_, |
305 "<init>", | 304 "<init>", |
306 "()V"))), | 305 "()V"))), |
307 inited_(false), | 306 inited_(false), |
308 use_surface_(false), | 307 use_surface_(false), |
309 picture_id_(0), | 308 picture_id_(0), |
310 output_delivery_loop_running_(false), | |
311 egl_context_(egl_context) { | 309 egl_context_(egl_context) { |
312 ScopedLocalRefFrame local_ref_frame(jni); | 310 ScopedLocalRefFrame local_ref_frame(jni); |
313 // It would be nice to avoid spinning up a new thread per MediaCodec, and | 311 // It would be nice to avoid spinning up a new thread per MediaCodec, and |
314 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug | 312 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug |
315 // 2732 means that deadlocks abound. This class synchronously trampolines | 313 // 2732 means that deadlocks abound. This class synchronously trampolines |
316 // to |codec_thread_|, so if anything else can be coming to _us_ from | 314 // to |codec_thread_|, so if anything else can be coming to _us_ from |
317 // |codec_thread_|, or from any thread holding the |_sendCritSect| described | 315 // |codec_thread_|, or from any thread holding the |_sendCritSect| described |
318 // in the bug, we have a problem. For now work around that with a dedicated | 316 // in the bug, we have a problem. For now work around that with a dedicated |
319 // thread. | 317 // thread. |
320 codec_thread_->SetName("MediaCodecVideoEncoder", NULL); | 318 codec_thread_->SetName("MediaCodecVideoEncoder", NULL); |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 RTC_CHECK(!msg->pdata) << "Unexpected message!"; | 463 RTC_CHECK(!msg->pdata) << "Unexpected message!"; |
466 if (!inited_) { | 464 if (!inited_) { |
467 return; | 465 return; |
468 } | 466 } |
469 | 467 |
470 // It would be nice to recover from a failure here if one happened, but it's | 468 // It would be nice to recover from a failure here if one happened, but it's |
471 // unclear how to signal such a failure to the app, so instead we stay silent | 469 // unclear how to signal such a failure to the app, so instead we stay silent |
472 // about it and let the next app-called API method reveal the borkedness. | 470 // about it and let the next app-called API method reveal the borkedness. |
473 DeliverPendingOutputs(jni); | 471 DeliverPendingOutputs(jni); |
474 | 472 |
475 // If there aren't more frames to deliver, we can stop the loop | 473 // If there aren't more frames to deliver, we can start polling at lower rate. |
476 if (!input_frame_infos_.empty()) { | 474 if (input_frame_infos_.empty()) { |
| 475 codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollNoFramesMs, this); |
| 476 } else { |
477 codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this); | 477 codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this); |
478 } else { | |
479 output_delivery_loop_running_ = false; | |
480 } | 478 } |
| 479 |
| 480 // Call log statistics here so it's called even if no frames are being |
| 481 // delivered. |
| 482 LogStatistics(false); |
481 } | 483 } |
482 | 484 |
483 bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() { | 485 bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() { |
484 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 486 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
485 ALOGE << "ResetOnCodecThread"; | 487 ALOGE << "ResetOnCodecThread"; |
486 if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK || | 488 if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK || |
487 InitEncodeOnCodecThread(width_, height_, 0, 0, false) != | 489 InitEncodeOnCodecThread(width_, height_, 0, 0, false) != |
488 WEBRTC_VIDEO_CODEC_OK) { | 490 WEBRTC_VIDEO_CODEC_OK) { |
489 // TODO(fischman): wouldn't it be nice if there was a way to gracefully | 491 // TODO(fischman): wouldn't it be nice if there was a way to gracefully |
490 // degrade to a SW encoder at this point? There isn't one AFAICT :( | 492 // degrade to a SW encoder at this point? There isn't one AFAICT :( |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
730 // Save input image timestamps for later output. | 732 // Save input image timestamps for later output. |
731 input_frame_infos_.emplace_back( | 733 input_frame_infos_.emplace_back( |
732 time_before_calling_encode, input_frame.timestamp(), | 734 time_before_calling_encode, input_frame.timestamp(), |
733 input_frame.render_time_ms(), input_frame.rotation()); | 735 input_frame.render_time_ms(), input_frame.rotation()); |
734 | 736 |
735 last_input_timestamp_ms_ = | 737 last_input_timestamp_ms_ = |
736 current_timestamp_us_ / rtc::kNumMicrosecsPerMillisec; | 738 current_timestamp_us_ / rtc::kNumMicrosecsPerMillisec; |
737 | 739 |
738 current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; | 740 current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; |
739 | 741 |
740 if (!output_delivery_loop_running_) { | 742 codec_thread_->Clear(this); |
741 output_delivery_loop_running_ = true; | 743 codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this); |
742 codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this); | |
743 } | |
744 | 744 |
745 if (!DeliverPendingOutputs(jni)) { | 745 if (!DeliverPendingOutputs(jni)) { |
746 ALOGE << "Failed deliver pending outputs."; | 746 ALOGE << "Failed deliver pending outputs."; |
747 ResetCodecOnCodecThread(); | 747 ResetCodecOnCodecThread(); |
748 return WEBRTC_VIDEO_CODEC_ERROR; | 748 return WEBRTC_VIDEO_CODEC_ERROR; |
749 } | 749 } |
750 return WEBRTC_VIDEO_CODEC_OK; | 750 return WEBRTC_VIDEO_CODEC_OK; |
751 } | 751 } |
752 | 752 |
753 bool MediaCodecVideoEncoder::MaybeReconfigureEncoderOnCodecThread( | 753 bool MediaCodecVideoEncoder::MaybeReconfigureEncoderOnCodecThread( |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
852 ". Dropped: " << frames_dropped_media_encoder_; | 852 ". Dropped: " << frames_dropped_media_encoder_; |
853 ScopedLocalRefFrame local_ref_frame(jni); | 853 ScopedLocalRefFrame local_ref_frame(jni); |
854 for (size_t i = 0; i < input_buffers_.size(); ++i) | 854 for (size_t i = 0; i < input_buffers_.size(); ++i) |
855 jni->DeleteGlobalRef(input_buffers_[i]); | 855 jni->DeleteGlobalRef(input_buffers_[i]); |
856 input_buffers_.clear(); | 856 input_buffers_.clear(); |
857 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_); | 857 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_); |
858 CHECK_EXCEPTION(jni); | 858 CHECK_EXCEPTION(jni); |
859 rtc::MessageQueueManager::Clear(this); | 859 rtc::MessageQueueManager::Clear(this); |
860 inited_ = false; | 860 inited_ = false; |
861 use_surface_ = false; | 861 use_surface_ = false; |
862 output_delivery_loop_running_ = false; | |
863 ALOGD << "EncoderReleaseOnCodecThread done."; | 862 ALOGD << "EncoderReleaseOnCodecThread done."; |
864 return WEBRTC_VIDEO_CODEC_OK; | 863 return WEBRTC_VIDEO_CODEC_OK; |
865 } | 864 } |
866 | 865 |
867 int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate, | 866 int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate, |
868 uint32_t frame_rate) { | 867 uint32_t frame_rate) { |
869 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 868 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
870 frame_rate = (frame_rate < MAX_ALLOWED_VIDEO_FPS) ? | 869 frame_rate = (frame_rate < MAX_ALLOWED_VIDEO_FPS) ? |
871 frame_rate : MAX_ALLOWED_VIDEO_FPS; | 870 frame_rate : MAX_ALLOWED_VIDEO_FPS; |
872 if (last_set_bitrate_kbps_ == new_bit_rate && | 871 if (last_set_bitrate_kbps_ == new_bit_rate && |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
916 | 915 |
917 jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs( | 916 jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs( |
918 JNIEnv* jni, | 917 JNIEnv* jni, |
919 jobject j_output_buffer_info) { | 918 jobject j_output_buffer_info) { |
920 return GetLongField( | 919 return GetLongField( |
921 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_); | 920 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_); |
922 } | 921 } |
923 | 922 |
924 bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) { | 923 bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) { |
925 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 924 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
| 925 |
926 while (true) { | 926 while (true) { |
927 jobject j_output_buffer_info = jni->CallObjectMethod( | 927 jobject j_output_buffer_info = jni->CallObjectMethod( |
928 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_); | 928 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_); |
929 CHECK_EXCEPTION(jni); | 929 CHECK_EXCEPTION(jni); |
930 if (IsNull(jni, j_output_buffer_info)) { | 930 if (IsNull(jni, j_output_buffer_info)) { |
931 break; | 931 break; |
932 } | 932 } |
933 | 933 |
934 int output_buffer_index = | 934 int output_buffer_index = |
935 GetOutputBufferInfoIndex(jni, j_output_buffer_info); | 935 GetOutputBufferInfoIndex(jni, j_output_buffer_info); |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1111 drop_next_input_frame_ = true; | 1111 drop_next_input_frame_ = true; |
1112 // Theoretically could handle callback_status<0 here, but unclear what | 1112 // Theoretically could handle callback_status<0 here, but unclear what |
1113 // that would mean for us. | 1113 // that would mean for us. |
1114 } | 1114 } |
1115 } | 1115 } |
1116 return true; | 1116 return true; |
1117 } | 1117 } |
1118 | 1118 |
1119 void MediaCodecVideoEncoder::LogStatistics(bool force_log) { | 1119 void MediaCodecVideoEncoder::LogStatistics(bool force_log) { |
1120 int statistic_time_ms = rtc::TimeMillis() - stat_start_time_ms_; | 1120 int statistic_time_ms = rtc::TimeMillis() - stat_start_time_ms_; |
1121 if ((statistic_time_ms >= kMediaCodecStatisticsIntervalMs || force_log) && | 1121 if ((statistic_time_ms >= kMediaCodecStatisticsIntervalMs || force_log) |
1122 current_frames_ > 0 && statistic_time_ms > 0) { | 1122 && statistic_time_ms > 0) { |
| 1123 // Prevent division by zero. |
| 1124 int current_frames_divider = current_frames_ != 0 ? current_frames_ : 1; |
| 1125 |
1123 int current_bitrate = current_bytes_ * 8 / statistic_time_ms; | 1126 int current_bitrate = current_bytes_ * 8 / statistic_time_ms; |
1124 int current_fps = | 1127 int current_fps = |
1125 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms; | 1128 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms; |
1126 ALOGD << "Encoded frames: " << frames_encoded_ << | 1129 ALOGD << "Encoded frames: " << frames_encoded_ << |
1127 ". Bitrate: " << current_bitrate << | 1130 ". Bitrate: " << current_bitrate << |
1128 ", target: " << last_set_bitrate_kbps_ << " kbps" << | 1131 ", target: " << last_set_bitrate_kbps_ << " kbps" << |
1129 ", fps: " << current_fps << | 1132 ", fps: " << current_fps << |
1130 ", encTime: " << (current_encoding_time_ms_ / current_frames_) << | 1133 ", encTime: " << (current_encoding_time_ms_ / current_frames_divider) << |
1131 ". QP: " << (current_acc_qp_ / current_frames_) << | 1134 ". QP: " << (current_acc_qp_ / current_frames_divider) << |
1132 " for last " << statistic_time_ms << " ms."; | 1135 " for last " << statistic_time_ms << " ms."; |
1133 stat_start_time_ms_ = rtc::TimeMillis(); | 1136 stat_start_time_ms_ = rtc::TimeMillis(); |
1134 current_frames_ = 0; | 1137 current_frames_ = 0; |
1135 current_bytes_ = 0; | 1138 current_bytes_ = 0; |
1136 current_acc_qp_ = 0; | 1139 current_acc_qp_ = 0; |
1137 current_encoding_time_ms_ = 0; | 1140 current_encoding_time_ms_ = 0; |
1138 } | 1141 } |
1139 } | 1142 } |
1140 | 1143 |
1141 int32_t MediaCodecVideoEncoder::NextNaluPosition( | 1144 int32_t MediaCodecVideoEncoder::NextNaluPosition( |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1273 return supported_codecs_; | 1276 return supported_codecs_; |
1274 } | 1277 } |
1275 | 1278 |
1276 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( | 1279 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( |
1277 webrtc::VideoEncoder* encoder) { | 1280 webrtc::VideoEncoder* encoder) { |
1278 ALOGD << "Destroy video encoder."; | 1281 ALOGD << "Destroy video encoder."; |
1279 delete encoder; | 1282 delete encoder; |
1280 } | 1283 } |
1281 | 1284 |
1282 } // namespace webrtc_jni | 1285 } // namespace webrtc_jni |
OLD | NEW |