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 <cstring> | 8 #include <cstring> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 rtp_timestamp, | 112 rtp_timestamp, |
113 kFrameIdUnknown); | 113 kFrameIdUnknown); |
114 | 114 |
115 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc | 115 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc |
116 TRACE_EVENT_INSTANT2( | 116 TRACE_EVENT_INSTANT2( |
117 "cast_perf_test", "InsertRawVideoFrame", | 117 "cast_perf_test", "InsertRawVideoFrame", |
118 TRACE_EVENT_SCOPE_THREAD, | 118 TRACE_EVENT_SCOPE_THREAD, |
119 "timestamp", capture_time.ToInternalValue(), | 119 "timestamp", capture_time.ToInternalValue(), |
120 "rtp_timestamp", rtp_timestamp); | 120 "rtp_timestamp", rtp_timestamp); |
121 | 121 |
122 if (AreTooManyFramesInFlight()) { | 122 if (ShouldDropNextFrame(capture_time)) { |
123 VLOG(1) << "Dropping frame due to too many frames currently in-flight."; | 123 VLOG(1) << "Dropping frame due to too many frames currently in-flight."; |
124 return; | 124 return; |
125 } | 125 } |
126 | 126 |
127 uint32 bitrate = fixed_bitrate_; | 127 uint32 bitrate = fixed_bitrate_; |
128 if (!bitrate) { | 128 if (!bitrate) { |
129 bitrate = congestion_control_.GetBitrate( | 129 bitrate = congestion_control_.GetBitrate( |
130 capture_time + target_playout_delay_, target_playout_delay_); | 130 capture_time + target_playout_delay_, target_playout_delay_); |
131 DCHECK(bitrate); | 131 DCHECK(bitrate); |
132 video_encoder_->SetBitRate(bitrate); | 132 video_encoder_->SetBitRate(bitrate); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 } | 171 } |
172 | 172 |
173 VLOG_IF(1, encoded_frame->dependency == EncodedFrame::KEY) | 173 VLOG_IF(1, encoded_frame->dependency == EncodedFrame::KEY) |
174 << "Send encoded key frame; frame_id: " << frame_id; | 174 << "Send encoded key frame; frame_id: " << frame_id; |
175 | 175 |
176 cast_environment_->Logging()->InsertEncodedFrameEvent( | 176 cast_environment_->Logging()->InsertEncodedFrameEvent( |
177 last_send_time_, FRAME_ENCODED, VIDEO_EVENT, encoded_frame->rtp_timestamp, | 177 last_send_time_, FRAME_ENCODED, VIDEO_EVENT, encoded_frame->rtp_timestamp, |
178 frame_id, static_cast<int>(encoded_frame->data.size()), | 178 frame_id, static_cast<int>(encoded_frame->data.size()), |
179 encoded_frame->dependency == EncodedFrame::KEY, | 179 encoded_frame->dependency == EncodedFrame::KEY, |
180 requested_bitrate_before_encode); | 180 requested_bitrate_before_encode); |
181 // Only use lowest 8 bits as key. | 181 |
182 frame_id_to_rtp_timestamp_[frame_id & 0xff] = encoded_frame->rtp_timestamp; | 182 RecordLatestFrameTimestamps(frame_id, |
| 183 encoded_frame->reference_time, |
| 184 encoded_frame->rtp_timestamp); |
183 | 185 |
184 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc | 186 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc |
185 TRACE_EVENT_INSTANT1( | 187 TRACE_EVENT_INSTANT1( |
186 "cast_perf_test", "VideoFrameEncoded", | 188 "cast_perf_test", "VideoFrameEncoded", |
187 TRACE_EVENT_SCOPE_THREAD, | 189 TRACE_EVENT_SCOPE_THREAD, |
188 "rtp_timestamp", encoded_frame->rtp_timestamp); | 190 "rtp_timestamp", encoded_frame->rtp_timestamp); |
189 | 191 |
190 DCHECK(!encoded_frame->reference_time.is_null()); | |
191 rtp_timestamp_helper_.StoreLatestTime(encoded_frame->reference_time, | |
192 encoded_frame->rtp_timestamp); | |
193 | |
194 // At the start of the session, it's important to send reports before each | 192 // At the start of the session, it's important to send reports before each |
195 // frame so that the receiver can properly compute playout times. The reason | 193 // frame so that the receiver can properly compute playout times. The reason |
196 // more than one report is sent is because transmission is not guaranteed, | 194 // more than one report is sent is because transmission is not guaranteed, |
197 // only best effort, so send enough that one should almost certainly get | 195 // only best effort, so send enough that one should almost certainly get |
198 // through. | 196 // through. |
199 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { | 197 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { |
200 // SendRtcpReport() will schedule future reports to be made if this is the | 198 // SendRtcpReport() will schedule future reports to be made if this is the |
201 // last "aggressive report." | 199 // last "aggressive report." |
202 ++num_aggressive_rtcp_reports_sent_; | 200 ++num_aggressive_rtcp_reports_sent_; |
203 const bool is_last_aggressive_report = | 201 const bool is_last_aggressive_report = |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 } | 266 } |
269 } else { | 267 } else { |
270 // Only count duplicated ACKs if there is no NACK request in between. | 268 // Only count duplicated ACKs if there is no NACK request in between. |
271 // This is to avoid aggresive resend. | 269 // This is to avoid aggresive resend. |
272 duplicate_ack_counter_ = 0; | 270 duplicate_ack_counter_ = 0; |
273 } | 271 } |
274 | 272 |
275 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 273 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
276 congestion_control_.AckFrame(cast_feedback.ack_frame_id, now); | 274 congestion_control_.AckFrame(cast_feedback.ack_frame_id, now); |
277 | 275 |
278 RtpTimestamp rtp_timestamp = | 276 cast_environment_->Logging()->InsertFrameEvent( |
279 frame_id_to_rtp_timestamp_[cast_feedback.ack_frame_id & 0xff]; | 277 now, |
280 cast_environment_->Logging()->InsertFrameEvent(now, | 278 FRAME_ACK_RECEIVED, |
281 FRAME_ACK_RECEIVED, | 279 VIDEO_EVENT, |
282 VIDEO_EVENT, | 280 GetRecordedRtpTimestamp(cast_feedback.ack_frame_id), |
283 rtp_timestamp, | 281 cast_feedback.ack_frame_id); |
284 cast_feedback.ack_frame_id); | |
285 | 282 |
286 const bool is_acked_out_of_order = | 283 const bool is_acked_out_of_order = |
287 static_cast<int32>(cast_feedback.ack_frame_id - | 284 static_cast<int32>(cast_feedback.ack_frame_id - |
288 latest_acked_frame_id_) < 0; | 285 latest_acked_frame_id_) < 0; |
289 VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "") | 286 VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "") |
290 << " for frame " << cast_feedback.ack_frame_id; | 287 << " for frame " << cast_feedback.ack_frame_id; |
291 if (!is_acked_out_of_order) { | 288 if (!is_acked_out_of_order) { |
292 // Cancel resends of acked frames. | 289 // Cancel resends of acked frames. |
293 std::vector<uint32> cancel_sending_frames; | 290 std::vector<uint32> cancel_sending_frames; |
294 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) { | 291 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) { |
295 latest_acked_frame_id_++; | 292 latest_acked_frame_id_++; |
296 cancel_sending_frames.push_back(latest_acked_frame_id_); | 293 cancel_sending_frames.push_back(latest_acked_frame_id_); |
297 } | 294 } |
298 transport_sender_->CancelSendingFrames(ssrc_, cancel_sending_frames); | 295 transport_sender_->CancelSendingFrames(ssrc_, cancel_sending_frames); |
299 latest_acked_frame_id_ = cast_feedback.ack_frame_id; | 296 latest_acked_frame_id_ = cast_feedback.ack_frame_id; |
300 } | 297 } |
301 } | 298 } |
302 | 299 |
303 bool VideoSender::AreTooManyFramesInFlight() const { | 300 bool VideoSender::ShouldDropNextFrame(base::TimeTicks capture_time) const { |
304 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 301 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
305 int frames_in_flight = frames_in_encoder_; | 302 int frames_in_flight = 0; |
| 303 base::TimeDelta duration_in_flight; |
306 if (!last_send_time_.is_null()) { | 304 if (!last_send_time_.is_null()) { |
307 frames_in_flight += | 305 frames_in_flight = |
308 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_); | 306 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_); |
| 307 if (frames_in_flight > 0) { |
| 308 const uint32 oldest_unacked_frame_id = latest_acked_frame_id_ + 1; |
| 309 duration_in_flight = |
| 310 capture_time - GetRecordedReferenceTime(oldest_unacked_frame_id); |
| 311 } |
309 } | 312 } |
| 313 frames_in_flight += frames_in_encoder_; |
310 VLOG(2) << frames_in_flight | 314 VLOG(2) << frames_in_flight |
311 << " frames in flight; last sent: " << last_sent_frame_id_ | 315 << " frames in flight; last sent: " << last_sent_frame_id_ |
312 << " latest acked: " << latest_acked_frame_id_ | 316 << "; latest acked: " << latest_acked_frame_id_ |
313 << " frames in encoder: " << frames_in_encoder_; | 317 << "; frames in encoder: " << frames_in_encoder_ |
314 return frames_in_flight >= max_unacked_frames_; | 318 << "; duration in flight: " |
| 319 << duration_in_flight.InMicroseconds() << " usec (" |
| 320 << (target_playout_delay_ > base::TimeDelta() ? |
| 321 100 * duration_in_flight / target_playout_delay_ : |
| 322 kint64max) << "%)"; |
| 323 return frames_in_flight >= max_unacked_frames_ || |
| 324 duration_in_flight >= target_playout_delay_; |
315 } | 325 } |
316 | 326 |
317 } // namespace cast | 327 } // namespace cast |
318 } // namespace media | 328 } // namespace media |
OLD | NEW |