Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/cast/sender/video_sender.h" | 5 #include "media/cast/sender/video_sender.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <cstring> | 9 #include <cstring> |
| 10 | 10 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 // network quality (e.g., additional time that accounts for encode and decode | 32 // network quality (e.g., additional time that accounts for encode and decode |
| 33 // time). | 33 // time). |
| 34 const int kConstantTimeMs = 75; | 34 const int kConstantTimeMs = 75; |
| 35 | 35 |
| 36 // The target maximum utilization of the encoder and network resources. This is | 36 // The target maximum utilization of the encoder and network resources. This is |
| 37 // used to attenuate the actual measured utilization values in order to provide | 37 // used to attenuate the actual measured utilization values in order to provide |
| 38 // "breathing room" (i.e., to ensure there will be sufficient CPU and bandwidth | 38 // "breathing room" (i.e., to ensure there will be sufficient CPU and bandwidth |
| 39 // available to handle the occasional more-complex frames). | 39 // available to handle the occasional more-complex frames). |
| 40 const int kTargetUtilizationPercentage = 75; | 40 const int kTargetUtilizationPercentage = 75; |
| 41 | 41 |
| 42 // Minimum number of user interactions before we consider the user to be in | |
| 43 // interactive mode. The goal is to prevent user interactions to launch | |
| 44 // animated content from causing target playout time flip-flop. | |
| 45 const int kMinUserInteractionsForInteractiveMode = 5; | |
| 46 | |
| 42 // Extract capture begin/end timestamps from |video_frame|'s metadata and log | 47 // Extract capture begin/end timestamps from |video_frame|'s metadata and log |
| 43 // it. | 48 // it. |
| 44 void LogVideoCaptureTimestamps(CastEnvironment* cast_environment, | 49 void LogVideoCaptureTimestamps(CastEnvironment* cast_environment, |
| 45 const media::VideoFrame& video_frame, | 50 const media::VideoFrame& video_frame, |
| 46 RtpTimestamp rtp_timestamp) { | 51 RtpTimestamp rtp_timestamp) { |
| 47 scoped_ptr<FrameEvent> capture_begin_event(new FrameEvent()); | 52 scoped_ptr<FrameEvent> capture_begin_event(new FrameEvent()); |
| 48 capture_begin_event->type = FRAME_CAPTURE_BEGIN; | 53 capture_begin_event->type = FRAME_CAPTURE_BEGIN; |
| 49 capture_begin_event->media_type = VIDEO_EVENT; | 54 capture_begin_event->media_type = VIDEO_EVENT; |
| 50 capture_begin_event->rtp_timestamp = rtp_timestamp; | 55 capture_begin_event->rtp_timestamp = rtp_timestamp; |
| 51 | 56 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 98 video_config.use_external_encoder | 103 video_config.use_external_encoder |
| 99 ? NewFixedCongestionControl( | 104 ? NewFixedCongestionControl( |
| 100 (video_config.min_bitrate + video_config.max_bitrate) / 2) | 105 (video_config.min_bitrate + video_config.max_bitrate) / 2) |
| 101 : NewAdaptiveCongestionControl(cast_environment->Clock(), | 106 : NewAdaptiveCongestionControl(cast_environment->Clock(), |
| 102 video_config.max_bitrate, | 107 video_config.max_bitrate, |
| 103 video_config.min_bitrate, | 108 video_config.min_bitrate, |
| 104 video_config.max_frame_rate)), | 109 video_config.max_frame_rate)), |
| 105 frames_in_encoder_(0), | 110 frames_in_encoder_(0), |
| 106 last_bitrate_(0), | 111 last_bitrate_(0), |
| 107 playout_delay_change_cb_(playout_delay_change_cb), | 112 playout_delay_change_cb_(playout_delay_change_cb), |
| 113 animation_content_(true), | |
| 114 user_interaction_(false), | |
| 115 user_interaction_count_(0), | |
| 116 interactive_mode_(false), | |
| 108 last_reported_deadline_utilization_(-1.0), | 117 last_reported_deadline_utilization_(-1.0), |
| 109 last_reported_lossy_utilization_(-1.0), | 118 last_reported_lossy_utilization_(-1.0), |
| 110 weak_factory_(this) { | 119 weak_factory_(this) { |
| 111 video_encoder_ = VideoEncoder::Create( | 120 video_encoder_ = VideoEncoder::Create( |
| 112 cast_environment_, | 121 cast_environment_, |
| 113 video_config, | 122 video_config, |
| 114 status_change_cb, | 123 status_change_cb, |
| 115 create_vea_cb, | 124 create_vea_cb, |
| 116 create_video_encode_mem_cb); | 125 create_video_encode_mem_cb); |
| 117 if (!video_encoder_) { | 126 if (!video_encoder_) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 LogVideoCaptureTimestamps(cast_environment_.get(), *video_frame, | 163 LogVideoCaptureTimestamps(cast_environment_.get(), *video_frame, |
| 155 rtp_timestamp); | 164 rtp_timestamp); |
| 156 | 165 |
| 157 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc | 166 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc |
| 158 TRACE_EVENT_INSTANT2( | 167 TRACE_EVENT_INSTANT2( |
| 159 "cast_perf_test", "InsertRawVideoFrame", | 168 "cast_perf_test", "InsertRawVideoFrame", |
| 160 TRACE_EVENT_SCOPE_THREAD, | 169 TRACE_EVENT_SCOPE_THREAD, |
| 161 "timestamp", reference_time.ToInternalValue(), | 170 "timestamp", reference_time.ToInternalValue(), |
| 162 "rtp_timestamp", rtp_timestamp); | 171 "rtp_timestamp", rtp_timestamp); |
| 163 | 172 |
| 173 bool prev_user_interaction = user_interaction_; | |
| 174 if (video_frame->metadata()->GetBoolean(VideoFrameMetadata::ANIMATION_CONTENT, | |
| 175 &animation_content_) && | |
| 176 video_frame->metadata()->GetBoolean(VideoFrameMetadata::USER_INTERACTION, | |
| 177 &user_interaction_)) { | |
| 178 if (user_interaction_ && !prev_user_interaction) { | |
| 179 user_interaction_count_++; | |
|
miu
2015/12/01 21:15:27
IIUC, this is counting the number of frames where
Irfan
2015/12/02 22:32:44
This has moved to capture side now.
| |
| 180 } | |
| 181 if (user_interaction_count_ > kMinUserInteractionsForInteractiveMode && | |
| 182 !animation_content_ && !interactive_mode_) { | |
|
miu
2015/12/01 21:15:27
Perhaps we should only consider the "user interact
Irfan
2015/12/02 22:37:55
As discussed f2f, I think we should be more conser
| |
| 183 interactive_mode_ = true; | |
| 184 VLOG(1) << "Interactive mode playout time " | |
| 185 << media::cast::kInteractiveModeStartPlayoutTimeMs; | |
| 186 playout_delay_change_cb_.Run(base::TimeDelta::FromMilliseconds( | |
| 187 media::cast::kInteractiveModeStartPlayoutTimeMs)); | |
| 188 } else if (animation_content_) { | |
| 189 // Reset user interactions when animating content is playing. | |
| 190 user_interaction_count_ = 0; | |
| 191 interactive_mode_ = false; | |
| 192 } | |
| 193 } | |
| 194 | |
|
miu
2015/12/01 21:15:27
BTW--What about audio? If we change video's playo
Irfan
2015/12/02 22:32:44
This already works as you describe :-)
| |
| 164 // Drop the frame if either its RTP or reference timestamp is not an increase | 195 // Drop the frame if either its RTP or reference timestamp is not an increase |
| 165 // over the last frame's. This protects: 1) the duration calculations that | 196 // over the last frame's. This protects: 1) the duration calculations that |
| 166 // assume timestamps are monotonically non-decreasing, and 2) assumptions made | 197 // assume timestamps are monotonically non-decreasing, and 2) assumptions made |
| 167 // deeper in the implementation where each frame's RTP timestamp needs to be | 198 // deeper in the implementation where each frame's RTP timestamp needs to be |
| 168 // unique. | 199 // unique. |
| 169 if (!last_enqueued_frame_reference_time_.is_null() && | 200 if (!last_enqueued_frame_reference_time_.is_null() && |
| 170 (!IsNewerRtpTimestamp(rtp_timestamp, | 201 (!IsNewerRtpTimestamp(rtp_timestamp, |
| 171 last_enqueued_frame_rtp_timestamp_) || | 202 last_enqueued_frame_rtp_timestamp_) || |
| 172 reference_time <= last_enqueued_frame_reference_time_)) { | 203 reference_time <= last_enqueued_frame_reference_time_)) { |
| 173 VLOG(1) << "Dropping video frame: RTP or reference time did not increase."; | 204 VLOG(1) << "Dropping video frame: RTP or reference time did not increase."; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 185 // OnEncodedVideoFrame(). | 216 // OnEncodedVideoFrame(). |
| 186 const base::TimeDelta duration_added_by_next_frame = frames_in_encoder_ > 0 ? | 217 const base::TimeDelta duration_added_by_next_frame = frames_in_encoder_ > 0 ? |
| 187 reference_time - last_enqueued_frame_reference_time_ : | 218 reference_time - last_enqueued_frame_reference_time_ : |
| 188 base::TimeDelta::FromSecondsD(1.0 / max_frame_rate_); | 219 base::TimeDelta::FromSecondsD(1.0 / max_frame_rate_); |
| 189 | 220 |
| 190 if (ShouldDropNextFrame(duration_added_by_next_frame)) { | 221 if (ShouldDropNextFrame(duration_added_by_next_frame)) { |
| 191 base::TimeDelta new_target_delay = std::min( | 222 base::TimeDelta new_target_delay = std::min( |
| 192 current_round_trip_time_ * kRoundTripsNeeded + | 223 current_round_trip_time_ * kRoundTripsNeeded + |
| 193 base::TimeDelta::FromMilliseconds(kConstantTimeMs), | 224 base::TimeDelta::FromMilliseconds(kConstantTimeMs), |
| 194 max_playout_delay_); | 225 max_playout_delay_); |
| 195 if (new_target_delay > target_playout_delay_) { | 226 // In case of interactive mode, we prefer frame drops over increasing |
| 227 // playout time. | |
| 228 if (!interactive_mode_ && new_target_delay > target_playout_delay_) { | |
| 229 // In case we detect user is no more in an interactive mode and there is | |
| 230 // a need to drop a frame, we ensure the playout delay is at-least the | |
| 231 // the starting value that is known to work well. | |
| 232 // This is intentended to minimize freeze when moving from an interactive | |
| 233 // session to watching animating content while being limited by end-to-end | |
| 234 // delay. | |
| 235 VLOG(1) << "Ensure playout time is at least " | |
| 236 << media::cast::kNonInteractiveModeStartPlayoutTimeMs; | |
| 237 if (new_target_delay.InMilliseconds() < | |
| 238 media::cast::kNonInteractiveModeStartPlayoutTimeMs) | |
| 239 new_target_delay = base::TimeDelta::FromMilliseconds( | |
| 240 kNonInteractiveModeStartPlayoutTimeMs); | |
| 196 VLOG(1) << "New target delay: " << new_target_delay.InMilliseconds(); | 241 VLOG(1) << "New target delay: " << new_target_delay.InMilliseconds(); |
| 197 playout_delay_change_cb_.Run(new_target_delay); | 242 playout_delay_change_cb_.Run(new_target_delay); |
| 198 } | 243 } |
| 199 | 244 |
| 200 // Some encoder implementations have a frame window for analysis. Since we | 245 // Some encoder implementations have a frame window for analysis. Since we |
| 201 // are dropping this frame, unless we instruct the encoder to flush all the | 246 // are dropping this frame, unless we instruct the encoder to flush all the |
| 202 // frames that have been enqueued for encoding, frames_in_encoder_ and | 247 // frames that have been enqueued for encoding, frames_in_encoder_ and |
| 203 // last_enqueued_frame_reference_time_ will never be updated and we will | 248 // last_enqueued_frame_reference_time_ will never be updated and we will |
| 204 // drop every subsequent frame for the rest of the session. | 249 // drop every subsequent frame for the rest of the session. |
| 205 video_encoder_->EmitFrames(); | 250 video_encoder_->EmitFrames(); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 356 media::VideoFrameMetadata::RESOURCE_UTILIZATION, | 401 media::VideoFrameMetadata::RESOURCE_UTILIZATION, |
| 357 encoded_frame->dependency == EncodedFrame::KEY ? | 402 encoded_frame->dependency == EncodedFrame::KEY ? |
| 358 std::min(1.0, attenuated_utilization) : attenuated_utilization); | 403 std::min(1.0, attenuated_utilization) : attenuated_utilization); |
| 359 } | 404 } |
| 360 | 405 |
| 361 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); | 406 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); |
| 362 } | 407 } |
| 363 | 408 |
| 364 } // namespace cast | 409 } // namespace cast |
| 365 } // namespace media | 410 } // namespace media |
| OLD | NEW |