OLD | NEW |
---|---|
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2015 Google Inc. | 3 * Copyright 2015 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
181 jlong GetOutputBufferInfoPresentationTimestampUs( | 181 jlong GetOutputBufferInfoPresentationTimestampUs( |
182 JNIEnv* jni, jobject j_output_buffer_info); | 182 JNIEnv* jni, jobject j_output_buffer_info); |
183 | 183 |
184 // Deliver any outputs pending in the MediaCodec to our |callback_| and return | 184 // Deliver any outputs pending in the MediaCodec to our |callback_| and return |
185 // true on success. | 185 // true on success. |
186 bool DeliverPendingOutputs(JNIEnv* jni); | 186 bool DeliverPendingOutputs(JNIEnv* jni); |
187 | 187 |
188 // Search for H.264 start codes. | 188 // Search for H.264 start codes. |
189 int32_t NextNaluPosition(uint8_t *buffer, size_t buffer_size); | 189 int32_t NextNaluPosition(uint8_t *buffer, size_t buffer_size); |
190 | 190 |
191 // Displays encoder statistics. | |
192 void LogStatistics(bool force_log); | |
193 | |
191 // Type of video codec. | 194 // Type of video codec. |
192 VideoCodecType codecType_; | 195 VideoCodecType codecType_; |
193 | 196 |
194 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to | 197 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to |
195 // |codec_thread_| synchronously. | 198 // |codec_thread_| synchronously. |
196 webrtc::EncodedImageCallback* callback_; | 199 webrtc::EncodedImageCallback* callback_; |
197 | 200 |
198 // State that is constant for the lifetime of this object once the ctor | 201 // State that is constant for the lifetime of this object once the ctor |
199 // returns. | 202 // returns. |
200 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec. | 203 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec. |
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
595 const std::vector<webrtc::FrameType>* frame_types) { | 598 const std::vector<webrtc::FrameType>* frame_types) { |
596 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 599 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
597 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 600 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
598 ScopedLocalRefFrame local_ref_frame(jni); | 601 ScopedLocalRefFrame local_ref_frame(jni); |
599 | 602 |
600 if (!inited_) { | 603 if (!inited_) { |
601 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 604 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
602 } | 605 } |
603 | 606 |
604 bool send_key_frame = false; | 607 bool send_key_frame = false; |
605 if (codecType_ == kVideoCodecVP8 && codec_mode_ == webrtc::kRealtimeVideo) { | 608 if ((codecType_ == kVideoCodecVP8 || codecType_ == kVideoCodecH264) |
perkj_webrtc
2016/02/01 09:20:53
remove check for codectType_ ? Always do this rega
AlexG
2016/02/01 20:13:35
Done.
| |
609 && codec_mode_ == webrtc::kRealtimeVideo) { | |
606 ++frames_received_since_last_key_; | 610 ++frames_received_since_last_key_; |
607 int64_t now_ms = GetCurrentTimeMs(); | 611 int64_t now_ms = GetCurrentTimeMs(); |
608 if (last_frame_received_ms_ != -1 && | 612 if (last_frame_received_ms_ != -1 && |
609 (now_ms - last_frame_received_ms_) > kFrameDiffThresholdMs) { | 613 (now_ms - last_frame_received_ms_) > kFrameDiffThresholdMs) { |
610 // Add limit to prevent triggering a key for every frame for very low | 614 // Add limit to prevent triggering a key for every frame for very low |
611 // framerates (e.g. if frame diff > kFrameDiffThresholdMs). | 615 // framerates (e.g. if frame diff > kFrameDiffThresholdMs). |
612 if (frames_received_since_last_key_ > kMinKeyFrameInterval) { | 616 if (frames_received_since_last_key_ > kMinKeyFrameInterval) { |
613 ALOGD << "Send key, frame diff: " << (now_ms - last_frame_received_ms_); | 617 ALOGD << "Send key, frame diff: " << (now_ms - last_frame_received_ms_); |
614 send_key_frame = true; | 618 send_key_frame = true; |
615 } | 619 } |
(...skipping 25 matching lines...) Expand all Loading... | |
641 RTC_CHECK(frame_types->size() == 1) << "Unexpected stream count"; | 645 RTC_CHECK(frame_types->size() == 1) << "Unexpected stream count"; |
642 | 646 |
643 // Check if we accumulated too many frames in encoder input buffers | 647 // Check if we accumulated too many frames in encoder input buffers |
644 // or the encoder latency exceeds 70 ms and drop frame if so. | 648 // or the encoder latency exceeds 70 ms and drop frame if so. |
645 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) { | 649 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) { |
646 int encoder_latency_ms = last_input_timestamp_ms_ - | 650 int encoder_latency_ms = last_input_timestamp_ms_ - |
647 last_output_timestamp_ms_; | 651 last_output_timestamp_ms_; |
648 if (frames_in_queue_ > MAX_ENCODER_Q_SIZE || | 652 if (frames_in_queue_ > MAX_ENCODER_Q_SIZE || |
649 encoder_latency_ms > MAX_ENCODER_LATENCY_MS) { | 653 encoder_latency_ms > MAX_ENCODER_LATENCY_MS) { |
650 ALOGD << "Drop frame - encoder is behind by " << encoder_latency_ms << | 654 ALOGD << "Drop frame - encoder is behind by " << encoder_latency_ms << |
651 " ms. Q size: " << frames_in_queue_ << ". Consecutive drops: " << | 655 " ms. Q size: " << frames_in_queue_ << ". TS: " << |
652 consecutive_full_queue_frame_drops_; | 656 (int)(current_timestamp_us_ / 1000) << ". Fps: " << last_set_fps_ << |
657 ". Consecutive drops: " << consecutive_full_queue_frame_drops_ ; | |
653 current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; | 658 current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; |
654 consecutive_full_queue_frame_drops_++; | 659 consecutive_full_queue_frame_drops_++; |
655 if (consecutive_full_queue_frame_drops_ >= | 660 if (consecutive_full_queue_frame_drops_ >= |
656 ENCODER_STALL_FRAMEDROP_THRESHOLD) { | 661 ENCODER_STALL_FRAMEDROP_THRESHOLD) { |
657 ALOGE << "Encoder got stuck. Reset."; | 662 ALOGE << "Encoder got stuck. Reset."; |
658 ResetCodecOnCodecThread(); | 663 ResetCodecOnCodecThread(); |
659 return WEBRTC_VIDEO_CODEC_ERROR; | 664 return WEBRTC_VIDEO_CODEC_ERROR; |
660 } | 665 } |
661 frames_dropped_media_encoder_++; | 666 frames_dropped_media_encoder_++; |
662 OnDroppedFrame(); | 667 OnDroppedFrame(); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
751 const bool is_texture_frame = frame.native_handle() != nullptr; | 756 const bool is_texture_frame = frame.native_handle() != nullptr; |
752 const bool reconfigure_due_to_format = is_texture_frame != use_surface_; | 757 const bool reconfigure_due_to_format = is_texture_frame != use_surface_; |
753 const bool reconfigure_due_to_size = | 758 const bool reconfigure_due_to_size = |
754 frame.width() != width_ || frame.height() != height_; | 759 frame.width() != width_ || frame.height() != height_; |
755 | 760 |
756 if (reconfigure_due_to_format) { | 761 if (reconfigure_due_to_format) { |
757 ALOGD << "Reconfigure encoder due to format change. " | 762 ALOGD << "Reconfigure encoder due to format change. " |
758 << (use_surface_ ? | 763 << (use_surface_ ? |
759 "Reconfiguring to encode from byte buffer." : | 764 "Reconfiguring to encode from byte buffer." : |
760 "Reconfiguring to encode from texture."); | 765 "Reconfiguring to encode from texture."); |
766 LogStatistics(true); | |
761 } | 767 } |
762 if (reconfigure_due_to_size) { | 768 if (reconfigure_due_to_size) { |
763 ALOGD << "Reconfigure encoder due to frame resolution change from " | 769 ALOGW << "Reconfigure encoder due to frame resolution change from " |
764 << width_ << " x " << height_ << " to " << frame.width() << " x " | 770 << width_ << " x " << height_ << " to " << frame.width() << " x " |
765 << frame.height(); | 771 << frame.height(); |
772 LogStatistics(true); | |
766 width_ = frame.width(); | 773 width_ = frame.width(); |
767 height_ = frame.height(); | 774 height_ = frame.height(); |
768 } | 775 } |
769 | 776 |
770 if (!reconfigure_due_to_format && !reconfigure_due_to_size) | 777 if (!reconfigure_due_to_format && !reconfigure_due_to_size) |
771 return true; | 778 return true; |
772 | 779 |
773 ReleaseOnCodecThread(); | 780 ReleaseOnCodecThread(); |
774 | 781 |
775 return InitEncodeOnCodecThread(width_, height_, 0, 0 , is_texture_frame) == | 782 return InitEncodeOnCodecThread(width_, height_, 0, 0 , is_texture_frame) == |
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1082 if (!success) { | 1089 if (!success) { |
1083 ResetCodecOnCodecThread(); | 1090 ResetCodecOnCodecThread(); |
1084 return false; | 1091 return false; |
1085 } | 1092 } |
1086 | 1093 |
1087 // Calculate and print encoding statistics - every 3 seconds. | 1094 // Calculate and print encoding statistics - every 3 seconds. |
1088 frames_encoded_++; | 1095 frames_encoded_++; |
1089 current_frames_++; | 1096 current_frames_++; |
1090 current_bytes_ += payload_size; | 1097 current_bytes_ += payload_size; |
1091 current_encoding_time_ms_ += frame_encoding_time_ms; | 1098 current_encoding_time_ms_ += frame_encoding_time_ms; |
1092 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_; | 1099 LogStatistics(false); |
1093 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs && | |
1094 current_frames_ > 0) { | |
1095 ALOGD << "Encoded frames: " << frames_encoded_ << ". Bitrate: " << | |
1096 (current_bytes_ * 8 / statistic_time_ms) << | |
1097 ", target: " << last_set_bitrate_kbps_ << " kbps, fps: " << | |
1098 ((current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms) | |
1099 << ", encTime: " << | |
1100 (current_encoding_time_ms_ / current_frames_) << ". QP: " << | |
1101 (current_acc_qp_ / current_frames_) << " for last " << | |
1102 statistic_time_ms << " ms."; | |
1103 start_time_ms_ = GetCurrentTimeMs(); | |
1104 current_frames_ = 0; | |
1105 current_bytes_ = 0; | |
1106 current_acc_qp_ = 0; | |
1107 current_encoding_time_ms_ = 0; | |
1108 } | |
1109 | 1100 |
1110 if (callback_status > 0) { | 1101 if (callback_status > 0) { |
1111 drop_next_input_frame_ = true; | 1102 drop_next_input_frame_ = true; |
1112 // Theoretically could handle callback_status<0 here, but unclear what | 1103 // Theoretically could handle callback_status<0 here, but unclear what |
1113 // that would mean for us. | 1104 // that would mean for us. |
1114 } | 1105 } |
1115 } | 1106 } |
1107 return true; | |
1108 } | |
1116 | 1109 |
1117 return true; | 1110 void MediaCodecVideoEncoder::LogStatistics(bool force_log) { |
1111 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_; | |
1112 if ((statistic_time_ms >= kMediaCodecStatisticsIntervalMs || force_log) && | |
1113 current_frames_ > 0 && statistic_time_ms > 0) { | |
1114 ALOGD << "Encoded frames: " << frames_encoded_ << ". Bitrate: " << | |
1115 (current_bytes_ * 8 / statistic_time_ms) << | |
1116 ", target: " << last_set_bitrate_kbps_ << " kbps, fps: " << | |
1117 ((current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms) | |
1118 << ", encTime: " << | |
perkj_webrtc
2016/02/01 09:20:53
Can this be aligned in a more readable way.
AlexG
2016/02/01 20:13:35
Done. And for other similar logs in encoder and de
| |
1119 (current_encoding_time_ms_ / current_frames_) << ". QP: " << | |
1120 (current_acc_qp_ / current_frames_) << " for last " << | |
1121 statistic_time_ms << " ms."; | |
1122 start_time_ms_ = GetCurrentTimeMs(); | |
perkj_webrtc
2016/02/01 09:20:53
change name of start_time_ms_ to something more d
AlexG
2016/02/01 20:13:35
Done.
| |
1123 current_frames_ = 0; | |
1124 current_bytes_ = 0; | |
1125 current_acc_qp_ = 0; | |
1126 current_encoding_time_ms_ = 0; | |
1127 } | |
1118 } | 1128 } |
1119 | 1129 |
1120 int32_t MediaCodecVideoEncoder::NextNaluPosition( | 1130 int32_t MediaCodecVideoEncoder::NextNaluPosition( |
1121 uint8_t *buffer, size_t buffer_size) { | 1131 uint8_t *buffer, size_t buffer_size) { |
1122 if (buffer_size < H264_SC_LENGTH) { | 1132 if (buffer_size < H264_SC_LENGTH) { |
1123 return -1; | 1133 return -1; |
1124 } | 1134 } |
1125 uint8_t *head = buffer; | 1135 uint8_t *head = buffer; |
1126 // Set end buffer pointer to 4 bytes before actual buffer end so we can | 1136 // Set end buffer pointer to 4 bytes before actual buffer end so we can |
1127 // access head[1], head[2] and head[3] in a loop without buffer overrun. | 1137 // access head[1], head[2] and head[3] in a loop without buffer overrun. |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1237 } | 1247 } |
1238 | 1248 |
1239 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( | 1249 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( |
1240 webrtc::VideoEncoder* encoder) { | 1250 webrtc::VideoEncoder* encoder) { |
1241 ALOGD << "Destroy video encoder."; | 1251 ALOGD << "Destroy video encoder."; |
1242 delete encoder; | 1252 delete encoder; |
1243 } | 1253 } |
1244 | 1254 |
1245 } // namespace webrtc_jni | 1255 } // namespace webrtc_jni |
1246 | 1256 |
OLD | NEW |