Index: webrtc/modules/video_coding/generic_encoder.cc |
diff --git a/webrtc/modules/video_coding/generic_encoder.cc b/webrtc/modules/video_coding/generic_encoder.cc |
index 89dafa77283386348af947d222faf856d71e3a51..a2c2130248ee8a99edace4e4c58051778b39b63f 100644 |
--- a/webrtc/modules/video_coding/generic_encoder.cc |
+++ b/webrtc/modules/video_coding/generic_encoder.cc |
@@ -216,9 +216,6 @@ EncodedImageCallback::Result VCMEncodedFrameCallback::OnEncodedImage( |
const RTPFragmentationHeader* fragmentation_header) { |
TRACE_EVENT_INSTANT1("webrtc", "VCMEncodedFrameCallback::Encoded", |
"timestamp", encoded_image._timeStamp); |
- bool is_timing_frame = false; |
- size_t outlier_frame_size = 0; |
- int64_t encode_start_ms = -1; |
size_t simulcast_svc_idx = 0; |
if (codec_specific->codecType == kVideoCodecVP9) { |
if (codec_specific->codecSpecific.VP9.num_spatial_layers > 1) |
@@ -231,13 +228,18 @@ EncodedImageCallback::Result VCMEncodedFrameCallback::OnEncodedImage( |
// TODO(ilnik): When h264 simulcast is landed, extract simulcast idx here. |
} |
+ // Larger than current frame size, so it will not trigger timing frame as an |
+ // outlier. If encoder didn't call OnFramerateChanged it will be used. |
+ size_t outlier_frame_size = encoded_image._length + 1; |
+ // Default best guess. If encoder didn't call OnEncodeStarted it will be used. |
+ int64_t encode_start_ms = encoded_image.capture_time_ms_; |
+ bool is_timing_frame = false; |
{ |
rtc::CritScope crit(&timing_params_lock_); |
- // TODO(ilnik): Workaround for hardware encoders, which do not call |
- // |OnEncodeStarted| correctly. Once fixed, remove conditional check. |
- if (simulcast_svc_idx < timing_frames_info_.size()) { |
- RTC_CHECK_LT(simulcast_svc_idx, timing_frames_info_.size()); |
+ // Encoders with internal sources do not call OnEncodeStarted and |
+ // OnFrameRateChanged. |timing_frames_info_| may be not filled here. |
+ if (simulcast_svc_idx < timing_frames_info_.size()) { |
auto encode_start_map = |
&timing_frames_info_[simulcast_svc_idx].encode_start_time_ms; |
auto it = encode_start_map->find(encoded_image.capture_time_ms_); |
@@ -249,45 +251,43 @@ EncodedImageCallback::Result VCMEncodedFrameCallback::OnEncodedImage( |
encode_start_map->erase(encode_start_map->begin(), it); |
encode_start_map->erase(it); |
} else { |
- // Some chromium remoting unittests use generic encoder incorrectly |
- // If timestamps do not match, purge them all. |
- encode_start_map->erase(encode_start_map->begin(), |
- encode_start_map->end()); |
+ // Encoder is with internal source: free our records of any frames just |
+ // in case to free memory. |
+ encode_start_map->clear(); |
} |
- int64_t timing_frame_delay_ms = |
- encoded_image.capture_time_ms_ - last_timing_frame_time_ms_; |
- if (last_timing_frame_time_ms_ == -1 || |
- timing_frame_delay_ms >= timing_frames_thresholds_.delay_ms || |
- timing_frame_delay_ms == 0) { |
- is_timing_frame = true; |
- last_timing_frame_time_ms_ = encoded_image.capture_time_ms_; |
- } |
- // TODO(ilnik): Once OnFramerateChanged is called correctly by hardware |
- // encoders, remove the conditional check below. |
- if (framerate_ > 0) { |
- RTC_CHECK_GT(framerate_, 0); |
- size_t average_frame_size = |
- timing_frames_info_[simulcast_svc_idx].target_bitrate_bytes_per_sec |
- / framerate_; |
+ size_t target_bitrate = |
+ timing_frames_info_[simulcast_svc_idx].target_bitrate_bytes_per_sec; |
+ if (framerate_ > 0 && target_bitrate > 0) { |
+ // framerate and target bitrate were reported by encoder. |
+ size_t average_frame_size = target_bitrate / framerate_; |
outlier_frame_size = average_frame_size * |
timing_frames_thresholds_.outlier_ratio_percent / |
100; |
- } else { |
- outlier_frame_size = encoded_image._length + 1; |
} |
- } else { |
- // We don't have any information prior to encode start, thus we can't |
- // reliably detect outliers. Set outlier size to anything larger than |
- // current frame size. |
- outlier_frame_size = encoded_image._length + 1; |
} |
- } |
- if (encoded_image._length >= outlier_frame_size) { |
- is_timing_frame = true; |
+ // Check if it's time to send a timing frame. |
+ int64_t timing_frame_delay_ms = |
+ encoded_image.capture_time_ms_ - last_timing_frame_time_ms_; |
+ // Trigger threshold if it's a first frame, too long passed since the last |
+ // timing frame, or we already sent timing frame on a different simulcast |
+ // stream with the same capture time. |
+ if (last_timing_frame_time_ms_ == -1 || |
+ timing_frame_delay_ms >= timing_frames_thresholds_.delay_ms || |
+ timing_frame_delay_ms == 0) { |
+ is_timing_frame = true; |
+ last_timing_frame_time_ms_ = encoded_image.capture_time_ms_; |
+ } |
+ |
+ // Outliers trigger timing frames, but do not affect scheduled timing |
+ // frames. |
+ if (encoded_image._length >= outlier_frame_size) { |
+ is_timing_frame = true; |
+ } |
} |
- if (encode_start_ms >= 0 && is_timing_frame) { |
+ |
+ if (is_timing_frame) { |
encoded_image.SetEncodeTime(encode_start_ms, rtc::TimeMillis()); |
} |