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

Unified Diff: talk/app/webrtc/java/jni/androidmediaencoder_jni.cc

Issue 1587943004: Add QP statistics logging to Android HW encoder. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc@master
Patch Set: Address comments Created 4 years, 11 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 | « talk/app/webrtc/java/jni/androidmediadecoder_jni.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
diff --git a/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc b/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
index 64831c3174e18e908e4272f2573f15c1fd52f41f..7f558c0551b07e657d2163df58167a4734ecf06d 100644
--- a/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
+++ b/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc
@@ -71,6 +71,25 @@ namespace webrtc_jni {
#define MAX_VIDEO_HEIGHT 1280
// Maximum supported HW video encoder fps.
#define MAX_VIDEO_FPS 30
+// Maximum allowed fps value in SetRates() call.
+#define MAX_ALLOWED_VIDEO_FPS 60
+// Maximum allowed frames in encoder input queue.
+#define MAX_ENCODER_Q_SIZE 2
+// Maximum allowed latency in ms.
+#define MAX_ENCODER_LATENCY_MS 70
+
+
+// Logging macros.
+#define TAG_ENCODER "MediaCodecVideoEncoder"
+#ifdef TRACK_BUFFER_TIMING
+#define ALOGV(...)
+ __android_log_print(ANDROID_LOG_VERBOSE, TAG_ENCODER, __VA_ARGS__)
+#else
+#define ALOGV(...)
+#endif
+#define ALOGD LOG_TAG(rtc::LS_INFO, TAG_ENCODER)
+#define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_ENCODER)
+#define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_ENCODER)
// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
@@ -206,6 +225,7 @@ class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
int64_t start_time_ms_; // Start time for statistics.
int current_frames_; // Number of frames in the current statistics interval.
int current_bytes_; // Encoded bytes in the current statistics interval.
+ int current_acc_qp_; // Accumulated QP in the current statistics interval.
int current_encoding_time_ms_; // Overall encoding time in the current second
int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame.
int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame.
@@ -467,13 +487,13 @@ int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
kbps = last_set_bitrate_kbps_;
}
if (fps == 0) {
- fps = last_set_fps_;
+ fps = MAX_VIDEO_FPS;
}
width_ = width;
height_ = height;
last_set_bitrate_kbps_ = kbps;
- last_set_fps_ = fps;
+ last_set_fps_ = (fps < MAX_VIDEO_FPS) ? fps : MAX_VIDEO_FPS;
yuv_size_ = width_ * height_ * 3 / 2;
frames_received_ = 0;
frames_encoded_ = 0;
@@ -483,6 +503,7 @@ int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
start_time_ms_ = GetCurrentTimeMs();
current_frames_ = 0;
current_bytes_ = 0;
+ current_acc_qp_ = 0;
current_encoding_time_ms_ = 0;
last_input_timestamp_ms_ = -1;
last_output_timestamp_ms_ = -1;
@@ -569,15 +590,37 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
if (!ResetCodecOnCodecThread())
return WEBRTC_VIDEO_CODEC_ERROR;
}
+ if (frames_encoded_ < kMaxEncodedLogFrames) {
+ ALOGD << "Encoder frame in # " << (frames_received_ - 1) << ". TS: " <<
+ (int)(current_timestamp_us_ / 1000) << ". Q: " << frames_in_queue_ <<
+ ". Fps: " << last_set_fps_ << ". Kbps: " << last_set_bitrate_kbps_;
+ }
if (drop_next_input_frame_) {
ALOGW << "Encoder drop frame - failed callback.";
drop_next_input_frame_ = false;
+ current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_;
+ OnDroppedFrame();
return WEBRTC_VIDEO_CODEC_OK;
}
RTC_CHECK(frame_types->size() == 1) << "Unexpected stream count";
+ // Check if we accumulated too many frames in encoder input buffers
+ // or the encoder latency exceeds 70 ms and drop frame if so.
+ if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) {
+ int encoder_latency_ms = last_input_timestamp_ms_ -
+ last_output_timestamp_ms_;
+ if (frames_in_queue_ > MAX_ENCODER_Q_SIZE ||
+ encoder_latency_ms > MAX_ENCODER_LATENCY_MS) {
+ ALOGD << "Drop frame - encoder is behind by " << encoder_latency_ms <<
+ " ms. Q size: " << frames_in_queue_;
+ current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_;
+ OnDroppedFrame();
+ return WEBRTC_VIDEO_CODEC_OK;
+ }
+ }
+
VideoFrame input_frame = frame;
if (scale_) {
// Check framerate before spatial resolution change.
@@ -605,20 +648,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
return WEBRTC_VIDEO_CODEC_ERROR;
}
- // Check if we accumulated too many frames in encoder input buffers
- // or the encoder latency exceeds 70 ms and drop frame if so.
- if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) {
- int encoder_latency_ms = last_input_timestamp_ms_ -
- last_output_timestamp_ms_;
- if (frames_in_queue_ > 2 || encoder_latency_ms > 70) {
- ALOGD << "Drop frame - encoder is behind by " << encoder_latency_ms <<
- " ms. Q size: " << frames_in_queue_;
- frames_dropped_++;
- // Report dropped frame to quality_scaler_.
- OnDroppedFrame();
- return WEBRTC_VIDEO_CODEC_OK;
- }
- }
+ // Save time when input frame is sent to the encoder input.
+ frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
const bool key_frame = frame_types->front() != webrtc::kVideoFrameDelta;
bool encode_status = true;
@@ -629,9 +660,8 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
if (j_input_buffer_index == -1) {
// Video codec falls behind - no input buffer available.
ALOGW << "Encoder drop frame - no input buffers available";
- frames_dropped_++;
- // Report dropped frame to quality_scaler_.
- OnDroppedFrame();
+ current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_;
+ frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
}
if (j_input_buffer_index == -2) {
@@ -657,7 +687,6 @@ int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
// Save input image timestamps for later output
timestamps_.push_back(input_frame.timestamp());
render_times_ms_.push_back(input_frame.render_time_ms());
- frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_;
if (!DeliverPendingOutputs(jni)) {
@@ -705,9 +734,6 @@ bool MediaCodecVideoEncoder::EncodeByteBufferOnCodecThread(JNIEnv* jni,
RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
RTC_CHECK(!use_surface_);
- ALOGV("Encoder frame in # %d. TS: %lld. Q: %d",
- frames_received_ - 1, current_timestamp_us_ / 1000, frames_in_queue_);
-
jobject j_input_buffer = input_buffers_[input_buffer_index];
uint8_t* yuv_buffer =
reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
@@ -783,6 +809,8 @@ int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
uint32_t frame_rate) {
RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
+ frame_rate = (frame_rate < MAX_ALLOWED_VIDEO_FPS) ?
+ frame_rate : MAX_ALLOWED_VIDEO_FPS;
if (last_set_bitrate_kbps_ == new_bit_rate &&
last_set_fps_ == frame_rate) {
return WEBRTC_VIDEO_CODEC_OK;
@@ -875,32 +903,12 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
jni->GetDirectBufferAddress(j_output_buffer));
CHECK_EXCEPTION(jni);
- ALOGV("Encoder frame out # %d. Key: %d. Size: %d. TS: %lld."
- " Latency: %lld. EncTime: %lld",
- frames_encoded_, key_frame, payload_size,
- last_output_timestamp_ms_,
- last_input_timestamp_ms_ - last_output_timestamp_ms_,
- frame_encoding_time_ms);
-
- // Calculate and print encoding statistics - every 3 seconds.
- frames_encoded_++;
- current_frames_++;
- current_bytes_ += payload_size;
- current_encoding_time_ms_ += frame_encoding_time_ms;
- int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
- if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
- current_frames_ > 0) {
- ALOGD << "Encoded frames: " << frames_encoded_ << ". Bitrate: " <<
- (current_bytes_ * 8 / statistic_time_ms) <<
- ", target: " << last_set_bitrate_kbps_ << " kbps, fps: " <<
- ((current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms)
- << ", encTime: " <<
- (current_encoding_time_ms_ / current_frames_) << " for last " <<
- statistic_time_ms << " ms.";
- start_time_ms_ = GetCurrentTimeMs();
- current_frames_ = 0;
- current_bytes_ = 0;
- current_encoding_time_ms_ = 0;
+ if (frames_encoded_ < kMaxEncodedLogFrames) {
+ ALOGD << "Encoder frame out # " << frames_encoded_ << ". Key: " <<
+ key_frame << ". Size: " << payload_size << ". TS: " <<
+ (int)last_output_timestamp_ms_ << ". Latency: " <<
+ (int)(last_input_timestamp_ms_ - last_output_timestamp_ms_) <<
+ ". EncTime: " << frame_encoding_time_ms;
}
// Callback - return encoded frame.
@@ -966,15 +974,19 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
header.fragmentationTimeDiff[0] = 0;
if (codecType_ == kVideoCodecVP8 && scale_) {
int qp;
- if (webrtc::vp8::GetQp(payload, payload_size, &qp))
+ if (webrtc::vp8::GetQp(payload, payload_size, &qp)) {
+ current_acc_qp_ += qp;
quality_scaler_.ReportQP(qp);
+ }
}
} else if (codecType_ == kVideoCodecH264) {
if (scale_) {
h264_bitstream_parser_.ParseBitstream(payload, payload_size);
int qp;
- if (h264_bitstream_parser_.GetLastSliceQp(&qp))
+ if (h264_bitstream_parser_.GetLastSliceQp(&qp)) {
+ current_acc_qp_ += qp;
quality_scaler_.ReportQP(qp);
+ }
}
// For H.264 search for start codes.
int32_t scPositions[MAX_NALUS_PERFRAME + 1] = {};
@@ -1022,6 +1034,29 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
return false;
}
+ // Calculate and print encoding statistics - every 3 seconds.
+ frames_encoded_++;
+ current_frames_++;
+ current_bytes_ += payload_size;
+ current_encoding_time_ms_ += frame_encoding_time_ms;
+ int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
+ if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
+ current_frames_ > 0) {
+ ALOGD << "Encoded frames: " << frames_encoded_ << ". Bitrate: " <<
+ (current_bytes_ * 8 / statistic_time_ms) <<
+ ", target: " << last_set_bitrate_kbps_ << " kbps, fps: " <<
+ ((current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms)
+ << ", encTime: " <<
+ (current_encoding_time_ms_ / current_frames_) << ". QP: " <<
+ (current_acc_qp_ / current_frames_) << " for last " <<
+ statistic_time_ms << " ms.";
+ start_time_ms_ = GetCurrentTimeMs();
+ current_frames_ = 0;
+ current_bytes_ = 0;
+ current_acc_qp_ = 0;
+ current_encoding_time_ms_ = 0;
+ }
+
if (callback_status > 0) {
drop_next_input_frame_ = true;
// Theoretically could handle callback_status<0 here, but unclear what
@@ -1065,6 +1100,8 @@ int32_t MediaCodecVideoEncoder::NextNaluPosition(
}
void MediaCodecVideoEncoder::OnDroppedFrame() {
+ frames_dropped_++;
+ // Report dropped frame to quality_scaler_.
if (scale_)
quality_scaler_.ReportDroppedFrame();
}
« no previous file with comments | « talk/app/webrtc/java/jni/androidmediadecoder_jni.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698