OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/video_sender/video_sender.h" | 5 #include "media/cast/video_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 15 matching lines...) Expand all Loading... |
26 VideoSender::VideoSender( | 26 VideoSender::VideoSender( |
27 scoped_refptr<CastEnvironment> cast_environment, | 27 scoped_refptr<CastEnvironment> cast_environment, |
28 const VideoSenderConfig& video_config, | 28 const VideoSenderConfig& video_config, |
29 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, | 29 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, |
30 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, | 30 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, |
31 transport::CastTransportSender* const transport_sender) | 31 transport::CastTransportSender* const transport_sender) |
32 : cast_environment_(cast_environment), | 32 : cast_environment_(cast_environment), |
33 target_playout_delay_(base::TimeDelta::FromMilliseconds( | 33 target_playout_delay_(base::TimeDelta::FromMilliseconds( |
34 video_config.rtp_config.max_delay_ms)), | 34 video_config.rtp_config.max_delay_ms)), |
35 transport_sender_(transport_sender), | 35 transport_sender_(transport_sender), |
36 max_unacked_frames_(std::min( | 36 max_unacked_frames_( |
37 kMaxUnackedFrames, | 37 std::min(kMaxUnackedFrames, |
38 1 + static_cast<int>( | 38 1 + static_cast<int>(target_playout_delay_ * |
39 target_playout_delay_ * video_config.max_frame_rate / | 39 video_config.max_frame_rate / |
40 base::TimeDelta::FromSeconds(1)))), | 40 base::TimeDelta::FromSeconds(1)))), |
41 rtcp_(cast_environment_, | 41 rtcp_(cast_environment_, |
42 this, | 42 this, |
43 transport_sender_, | 43 transport_sender_, |
44 NULL, // paced sender. | 44 NULL, // paced sender. |
45 NULL, | 45 NULL, |
46 video_config.rtcp_mode, | 46 video_config.rtcp_mode, |
47 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval), | 47 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval), |
48 video_config.rtp_config.ssrc, | 48 video_config.rtp_config.ssrc, |
49 video_config.incoming_feedback_ssrc, | 49 video_config.incoming_feedback_ssrc, |
50 video_config.rtcp_c_name, | 50 video_config.rtcp_c_name, |
51 VIDEO_EVENT), | 51 VIDEO_EVENT), |
52 rtp_timestamp_helper_(kVideoFrequency), | 52 rtp_timestamp_helper_(kVideoFrequency), |
53 num_aggressive_rtcp_reports_sent_(0), | 53 num_aggressive_rtcp_reports_sent_(0), |
54 frames_in_encoder_(0), | 54 frames_in_encoder_(0), |
55 last_sent_frame_id_(0), | 55 last_sent_frame_id_(0), |
56 latest_acked_frame_id_(0), | 56 latest_acked_frame_id_(0), |
57 duplicate_ack_counter_(0), | 57 duplicate_ack_counter_(0), |
58 current_requested_bitrate_(video_config.start_bitrate), | |
59 congestion_control_(cast_environment->Clock(), | 58 congestion_control_(cast_environment->Clock(), |
60 video_config.congestion_control_back_off, | |
61 video_config.max_bitrate, | 59 video_config.max_bitrate, |
62 video_config.min_bitrate, | 60 video_config.min_bitrate, |
63 video_config.start_bitrate), | 61 max_unacked_frames_), |
64 cast_initialization_status_(STATUS_VIDEO_UNINITIALIZED), | 62 cast_initialization_status_(STATUS_VIDEO_UNINITIALIZED), |
65 weak_factory_(this) { | 63 weak_factory_(this) { |
66 VLOG(1) << "max_unacked_frames " << max_unacked_frames_; | 64 VLOG(1) << "max_unacked_frames " << max_unacked_frames_; |
67 DCHECK_GT(max_unacked_frames_, 0); | 65 DCHECK_GT(max_unacked_frames_, 0); |
68 | 66 |
69 if (video_config.use_external_encoder) { | 67 if (video_config.use_external_encoder) { |
70 video_encoder_.reset(new ExternalVideoEncoder(cast_environment, | 68 video_encoder_.reset(new ExternalVideoEncoder(cast_environment, |
71 video_config, | 69 video_config, |
72 create_vea_cb, | 70 create_vea_cb, |
73 create_video_encode_mem_cb)); | 71 create_video_encode_mem_cb)); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 "cast_perf_test", "InsertRawVideoFrame", | 114 "cast_perf_test", "InsertRawVideoFrame", |
117 TRACE_EVENT_SCOPE_THREAD, | 115 TRACE_EVENT_SCOPE_THREAD, |
118 "timestamp", capture_time.ToInternalValue(), | 116 "timestamp", capture_time.ToInternalValue(), |
119 "rtp_timestamp", rtp_timestamp); | 117 "rtp_timestamp", rtp_timestamp); |
120 | 118 |
121 if (AreTooManyFramesInFlight()) { | 119 if (AreTooManyFramesInFlight()) { |
122 VLOG(1) << "Dropping frame due to too many frames currently in-flight."; | 120 VLOG(1) << "Dropping frame due to too many frames currently in-flight."; |
123 return; | 121 return; |
124 } | 122 } |
125 | 123 |
| 124 uint32 bitrate = congestion_control_.GetBitrate( |
| 125 capture_time + target_playout_delay_, target_playout_delay_); |
| 126 |
| 127 video_encoder_->SetBitRate(bitrate); |
| 128 |
126 if (video_encoder_->EncodeVideoFrame( | 129 if (video_encoder_->EncodeVideoFrame( |
127 video_frame, | 130 video_frame, |
128 capture_time, | 131 capture_time, |
129 base::Bind(&VideoSender::SendEncodedVideoFrame, | 132 base::Bind(&VideoSender::SendEncodedVideoFrame, |
130 weak_factory_.GetWeakPtr(), | 133 weak_factory_.GetWeakPtr(), |
131 current_requested_bitrate_))) { | 134 bitrate))) { |
132 frames_in_encoder_++; | 135 frames_in_encoder_++; |
133 } else { | 136 } else { |
134 VLOG(1) << "Encoder rejected a frame. Skipping..."; | 137 VLOG(1) << "Encoder rejected a frame. Skipping..."; |
135 } | 138 } |
136 } | 139 } |
137 | 140 |
138 void VideoSender::SendEncodedVideoFrame( | 141 void VideoSender::SendEncodedVideoFrame( |
139 int requested_bitrate_before_encode, | 142 int requested_bitrate_before_encode, |
140 scoped_ptr<transport::EncodedFrame> encoded_frame) { | 143 scoped_ptr<transport::EncodedFrame> encoded_frame) { |
141 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 144 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { | 188 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { |
186 // SendRtcpReport() will schedule future reports to be made if this is the | 189 // SendRtcpReport() will schedule future reports to be made if this is the |
187 // last "aggressive report." | 190 // last "aggressive report." |
188 ++num_aggressive_rtcp_reports_sent_; | 191 ++num_aggressive_rtcp_reports_sent_; |
189 const bool is_last_aggressive_report = | 192 const bool is_last_aggressive_report = |
190 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart); | 193 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart); |
191 VLOG_IF(1, is_last_aggressive_report) << "Sending last aggressive report."; | 194 VLOG_IF(1, is_last_aggressive_report) << "Sending last aggressive report."; |
192 SendRtcpReport(is_last_aggressive_report); | 195 SendRtcpReport(is_last_aggressive_report); |
193 } | 196 } |
194 | 197 |
| 198 congestion_control_.SendFrameToTransport( |
| 199 frame_id, encoded_frame->data.size() * 8, last_send_time_); |
| 200 |
195 transport_sender_->InsertCodedVideoFrame(*encoded_frame); | 201 transport_sender_->InsertCodedVideoFrame(*encoded_frame); |
196 } | 202 } |
197 | 203 |
198 void VideoSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) { | 204 void VideoSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) { |
199 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 205 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
200 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); | 206 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); |
201 } | 207 } |
202 | 208 |
203 void VideoSender::ScheduleNextRtcpReport() { | 209 void VideoSender::ScheduleNextRtcpReport() { |
204 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 210 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 } | 270 } |
265 | 271 |
266 void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { | 272 void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { |
267 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 273 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
268 | 274 |
269 base::TimeDelta rtt; | 275 base::TimeDelta rtt; |
270 base::TimeDelta avg_rtt; | 276 base::TimeDelta avg_rtt; |
271 base::TimeDelta min_rtt; | 277 base::TimeDelta min_rtt; |
272 base::TimeDelta max_rtt; | 278 base::TimeDelta max_rtt; |
273 if (rtcp_.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)) { | 279 if (rtcp_.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)) { |
| 280 congestion_control_.UpdateRtt(rtt); |
| 281 |
274 // Don't use a RTT lower than our average. | 282 // Don't use a RTT lower than our average. |
275 rtt = std::max(rtt, avg_rtt); | 283 rtt = std::max(rtt, avg_rtt); |
276 | 284 |
277 // Having the RTT values implies the receiver sent back a receiver report | 285 // Having the RTT values implies the receiver sent back a receiver report |
278 // based on it having received a report from here. Therefore, ensure this | 286 // based on it having received a report from here. Therefore, ensure this |
279 // sender stops aggressively sending reports. | 287 // sender stops aggressively sending reports. |
280 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { | 288 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { |
281 VLOG(1) << "No longer a need to send reports aggressively (sent " | 289 VLOG(1) << "No longer a need to send reports aggressively (sent " |
282 << num_aggressive_rtcp_reports_sent_ << ")."; | 290 << num_aggressive_rtcp_reports_sent_ << ")."; |
283 num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart; | 291 num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart; |
284 ScheduleNextRtcpReport(); | 292 ScheduleNextRtcpReport(); |
285 } | 293 } |
286 } else { | 294 } else { |
287 // We have no measured value use default. | 295 // We have no measured value use default. |
288 rtt = base::TimeDelta::FromMilliseconds(kStartRttMs); | 296 rtt = base::TimeDelta::FromMilliseconds(kStartRttMs); |
289 } | 297 } |
290 | 298 |
291 if (last_send_time_.is_null()) | 299 if (last_send_time_.is_null()) |
292 return; // Cannot get an ACK without having first sent a frame. | 300 return; // Cannot get an ACK without having first sent a frame. |
293 | 301 |
294 if (cast_feedback.missing_frames_and_packets_.empty()) { | 302 if (cast_feedback.missing_frames_and_packets_.empty()) { |
295 video_encoder_->LatestFrameIdToReference(cast_feedback.ack_frame_id_); | 303 video_encoder_->LatestFrameIdToReference(cast_feedback.ack_frame_id_); |
296 | 304 |
297 if ((latest_acked_frame_id_ + 1) == cast_feedback.ack_frame_id_) { | |
298 uint32 new_bitrate = 0; | |
299 if (congestion_control_.OnAck(rtt, &new_bitrate)) { | |
300 UpdateBitrate(new_bitrate); | |
301 } | |
302 } | |
303 // We only count duplicate ACKs when we have sent newer frames. | 305 // We only count duplicate ACKs when we have sent newer frames. |
304 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id_ && | 306 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id_ && |
305 latest_acked_frame_id_ != last_sent_frame_id_) { | 307 latest_acked_frame_id_ != last_sent_frame_id_) { |
306 duplicate_ack_counter_++; | 308 duplicate_ack_counter_++; |
307 } else { | 309 } else { |
308 duplicate_ack_counter_ = 0; | 310 duplicate_ack_counter_ = 0; |
309 } | 311 } |
310 // TODO(miu): The values "2" and "3" should be derived from configuration. | 312 // TODO(miu): The values "2" and "3" should be derived from configuration. |
311 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) { | 313 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) { |
312 VLOG(1) << "Received duplicate ACK for frame " << latest_acked_frame_id_; | 314 VLOG(1) << "Received duplicate ACK for frame " << latest_acked_frame_id_; |
313 ResendForKickstart(); | 315 ResendForKickstart(); |
314 } | 316 } |
315 } else { | 317 } else { |
316 // Only count duplicated ACKs if there is no NACK request in between. | 318 // Only count duplicated ACKs if there is no NACK request in between. |
317 // This is to avoid aggresive resend. | 319 // This is to avoid aggresive resend. |
318 duplicate_ack_counter_ = 0; | 320 duplicate_ack_counter_ = 0; |
319 transport_sender_->ResendPackets( | 321 transport_sender_->ResendPackets( |
320 false, cast_feedback.missing_frames_and_packets_); | 322 false, cast_feedback.missing_frames_and_packets_); |
321 uint32 new_bitrate = 0; | |
322 if (congestion_control_.OnNack(rtt, &new_bitrate)) { | |
323 UpdateBitrate(new_bitrate); | |
324 } | |
325 } | 323 } |
326 | 324 |
| 325 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
| 326 congestion_control_.AckFrame(cast_feedback.ack_frame_id_, now); |
| 327 |
327 RtpTimestamp rtp_timestamp = | 328 RtpTimestamp rtp_timestamp = |
328 frame_id_to_rtp_timestamp_[cast_feedback.ack_frame_id_ & 0xff]; | 329 frame_id_to_rtp_timestamp_[cast_feedback.ack_frame_id_ & 0xff]; |
329 cast_environment_->Logging()->InsertFrameEvent( | 330 cast_environment_->Logging()->InsertFrameEvent(now, |
330 cast_environment_->Clock()->NowTicks(), FRAME_ACK_RECEIVED, VIDEO_EVENT, | 331 FRAME_ACK_RECEIVED, |
331 rtp_timestamp, cast_feedback.ack_frame_id_); | 332 VIDEO_EVENT, |
| 333 rtp_timestamp, |
| 334 cast_feedback.ack_frame_id_); |
332 | 335 |
333 const bool is_acked_out_of_order = | 336 const bool is_acked_out_of_order = |
334 static_cast<int32>(cast_feedback.ack_frame_id_ - | 337 static_cast<int32>(cast_feedback.ack_frame_id_ - |
335 latest_acked_frame_id_) < 0; | 338 latest_acked_frame_id_) < 0; |
336 VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "") | 339 VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "") |
337 << " for frame " << cast_feedback.ack_frame_id_; | 340 << " for frame " << cast_feedback.ack_frame_id_; |
338 if (!is_acked_out_of_order) | 341 if (!is_acked_out_of_order) |
339 latest_acked_frame_id_ = cast_feedback.ack_frame_id_; | 342 latest_acked_frame_id_ = cast_feedback.ack_frame_id_; |
340 } | 343 } |
341 | 344 |
(...skipping 21 matching lines...) Expand all Loading... |
363 // packets and frames are missing. | 366 // packets and frames are missing. |
364 MissingFramesAndPacketsMap missing_frames_and_packets; | 367 MissingFramesAndPacketsMap missing_frames_and_packets; |
365 PacketIdSet missing; | 368 PacketIdSet missing; |
366 missing.insert(0); | 369 missing.insert(0); |
367 missing_frames_and_packets.insert( | 370 missing_frames_and_packets.insert( |
368 std::make_pair(last_sent_frame_id_, missing)); | 371 std::make_pair(last_sent_frame_id_, missing)); |
369 last_send_time_ = cast_environment_->Clock()->NowTicks(); | 372 last_send_time_ = cast_environment_->Clock()->NowTicks(); |
370 transport_sender_->ResendPackets(false, missing_frames_and_packets); | 373 transport_sender_->ResendPackets(false, missing_frames_and_packets); |
371 } | 374 } |
372 | 375 |
373 void VideoSender::UpdateBitrate(int new_bitrate) { | |
374 // Make sure we don't set the bitrate too insanely low. | |
375 DCHECK_GT(new_bitrate, 1000); | |
376 video_encoder_->SetBitRate(new_bitrate); | |
377 current_requested_bitrate_ = new_bitrate; | |
378 } | |
379 | |
380 } // namespace cast | 376 } // namespace cast |
381 } // namespace media | 377 } // namespace media |
OLD | NEW |