Chromium Code Reviews| 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/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" |
| 11 #include "base/debug/trace_event.h" | 11 #include "base/debug/trace_event.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
| 14 #include "media/cast/cast_defines.h" | 14 #include "media/cast/cast_defines.h" |
| 15 #include "media/cast/net/cast_transport_config.h" | 15 #include "media/cast/net/cast_transport_config.h" |
| 16 #include "media/cast/net/rtcp/rtcp_defines.h" | 16 #include "media/cast/net/rtcp/rtcp_defines.h" |
|
miu
2014/07/16 19:58:03
Remove this include.
Alpha Left Google
2014/07/17 01:01:46
Done.
| |
| 17 #include "media/cast/sender/external_video_encoder.h" | 17 #include "media/cast/sender/external_video_encoder.h" |
| 18 #include "media/cast/sender/video_encoder_impl.h" | 18 #include "media/cast/sender/video_encoder_impl.h" |
| 19 | 19 |
| 20 namespace media { | 20 namespace media { |
| 21 namespace cast { | 21 namespace cast { |
| 22 | 22 |
| 23 const int kNumAggressiveReportsSentAtStart = 100; | 23 const int kNumAggressiveReportsSentAtStart = 100; |
| 24 const int kMinSchedulingDelayMs = 1; | 24 const int kMinSchedulingDelayMs = 1; |
| 25 | 25 |
| 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 CastTransportSender* const transport_sender) | 31 CastTransportSender* const transport_sender) |
| 32 : cast_environment_(cast_environment), | 32 : FrameSender( |
| 33 cast_environment, | |
| 34 transport_sender, | |
| 35 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval), | |
| 36 kVideoFrequency, | |
| 37 false), | |
| 33 target_playout_delay_(video_config.target_playout_delay), | 38 target_playout_delay_(video_config.target_playout_delay), |
| 34 transport_sender_(transport_sender), | |
| 35 max_unacked_frames_( | 39 max_unacked_frames_( |
| 36 std::min(kMaxUnackedFrames, | 40 std::min(kMaxUnackedFrames, |
| 37 1 + static_cast<int>(target_playout_delay_ * | 41 1 + static_cast<int>(target_playout_delay_ * |
| 38 video_config.max_frame_rate / | 42 video_config.max_frame_rate / |
| 39 base::TimeDelta::FromSeconds(1)))), | 43 base::TimeDelta::FromSeconds(1)))), |
| 40 rtcp_(cast_environment_, | |
| 41 this, | |
| 42 transport_sender_, | |
| 43 NULL, // paced sender. | |
| 44 NULL, | |
| 45 video_config.rtcp_mode, | |
| 46 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval), | |
| 47 video_config.ssrc, | |
| 48 video_config.incoming_feedback_ssrc, | |
| 49 video_config.rtcp_c_name, | |
| 50 VIDEO_EVENT), | |
| 51 rtp_timestamp_helper_(kVideoFrequency), | |
| 52 num_aggressive_rtcp_reports_sent_(0), | 44 num_aggressive_rtcp_reports_sent_(0), |
| 53 frames_in_encoder_(0), | 45 frames_in_encoder_(0), |
| 54 last_sent_frame_id_(0), | 46 last_sent_frame_id_(0), |
| 55 latest_acked_frame_id_(0), | 47 latest_acked_frame_id_(0), |
| 56 duplicate_ack_counter_(0), | 48 duplicate_ack_counter_(0), |
| 57 congestion_control_(cast_environment->Clock(), | 49 congestion_control_(cast_environment->Clock(), |
| 58 video_config.max_bitrate, | 50 video_config.max_bitrate, |
| 59 video_config.min_bitrate, | 51 video_config.min_bitrate, |
| 60 max_unacked_frames_), | 52 max_unacked_frames_), |
| 61 cast_initialization_status_(STATUS_VIDEO_UNINITIALIZED), | 53 cast_initialization_status_(STATUS_VIDEO_UNINITIALIZED), |
| 62 weak_factory_(this) { | 54 weak_factory_(this) { |
| 63 VLOG(1) << "max_unacked_frames " << max_unacked_frames_; | 55 VLOG(1) << "max_unacked_frames " << max_unacked_frames_; |
| 64 DCHECK_GT(max_unacked_frames_, 0); | 56 DCHECK_GT(max_unacked_frames_, 0); |
| 65 | 57 |
| 66 if (video_config.use_external_encoder) { | 58 if (video_config.use_external_encoder) { |
| 67 video_encoder_.reset(new ExternalVideoEncoder(cast_environment, | 59 video_encoder_.reset(new ExternalVideoEncoder(cast_environment, |
| 68 video_config, | 60 video_config, |
| 69 create_vea_cb, | 61 create_vea_cb, |
| 70 create_video_encode_mem_cb)); | 62 create_video_encode_mem_cb)); |
| 71 } else { | 63 } else { |
| 72 video_encoder_.reset(new VideoEncoderImpl( | 64 video_encoder_.reset(new VideoEncoderImpl( |
| 73 cast_environment, video_config, max_unacked_frames_)); | 65 cast_environment, video_config, max_unacked_frames_)); |
| 74 } | 66 } |
| 75 cast_initialization_status_ = STATUS_VIDEO_INITIALIZED; | 67 cast_initialization_status_ = STATUS_VIDEO_INITIALIZED; |
| 76 | 68 |
| 77 media::cast::CastTransportRtpConfig transport_config; | 69 media::cast::CastTransportRtpConfig transport_config; |
| 78 transport_config.ssrc = video_config.ssrc; | 70 transport_config.ssrc = video_config.ssrc; |
| 71 transport_config.feedback_ssrc = video_config.incoming_feedback_ssrc; | |
| 72 transport_config.c_name = video_config.rtcp_c_name; | |
| 79 transport_config.rtp_payload_type = video_config.rtp_payload_type; | 73 transport_config.rtp_payload_type = video_config.rtp_payload_type; |
| 80 transport_config.stored_frames = max_unacked_frames_; | 74 transport_config.stored_frames = max_unacked_frames_; |
| 81 transport_config.aes_key = video_config.aes_key; | 75 transport_config.aes_key = video_config.aes_key; |
| 82 transport_config.aes_iv_mask = video_config.aes_iv_mask; | 76 transport_config.aes_iv_mask = video_config.aes_iv_mask; |
| 83 transport_sender_->InitializeVideo(transport_config); | |
| 84 | 77 |
| 85 rtcp_.SetCastReceiverEventHistorySize(kReceiverRtcpEventHistorySize); | 78 transport_sender->InitializeVideo( |
| 79 transport_config, | |
| 80 base::Bind(&VideoSender::OnReceivedCastFeedback, | |
| 81 weak_factory_.GetWeakPtr()), | |
| 82 base::Bind(&VideoSender::OnReceivedRtt, weak_factory_.GetWeakPtr())); | |
| 86 | 83 |
| 87 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_)); | 84 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_)); |
| 88 } | 85 } |
| 89 | 86 |
| 90 VideoSender::~VideoSender() { | 87 VideoSender::~VideoSender() { |
| 91 } | 88 } |
| 92 | 89 |
| 93 void VideoSender::InsertRawVideoFrame( | 90 void VideoSender::InsertRawVideoFrame( |
| 94 const scoped_refptr<media::VideoFrame>& video_frame, | 91 const scoped_refptr<media::VideoFrame>& video_frame, |
| 95 const base::TimeTicks& capture_time) { | 92 const base::TimeTicks& capture_time) { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 195 VLOG_IF(1, is_last_aggressive_report) << "Sending last aggressive report."; | 192 VLOG_IF(1, is_last_aggressive_report) << "Sending last aggressive report."; |
| 196 SendRtcpReport(is_last_aggressive_report); | 193 SendRtcpReport(is_last_aggressive_report); |
| 197 } | 194 } |
| 198 | 195 |
| 199 congestion_control_.SendFrameToTransport( | 196 congestion_control_.SendFrameToTransport( |
| 200 frame_id, encoded_frame->data.size() * 8, last_send_time_); | 197 frame_id, encoded_frame->data.size() * 8, last_send_time_); |
| 201 | 198 |
| 202 transport_sender_->InsertCodedVideoFrame(*encoded_frame); | 199 transport_sender_->InsertCodedVideoFrame(*encoded_frame); |
| 203 } | 200 } |
| 204 | 201 |
| 205 void VideoSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) { | 202 void VideoSender::ResendCheck() { |
| 206 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 203 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 207 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); | 204 DCHECK(!last_send_time_.is_null()); |
| 208 } | 205 const base::TimeDelta time_since_last_send = |
| 209 | 206 cast_environment_->Clock()->NowTicks() - last_send_time_; |
| 210 void VideoSender::ScheduleNextRtcpReport() { | 207 if (time_since_last_send > target_playout_delay_) { |
| 211 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 208 if (latest_acked_frame_id_ == last_sent_frame_id_) { |
| 212 base::TimeDelta time_to_next = rtcp_.TimeToSendNextRtcpReport() - | 209 // Last frame acked, no point in doing anything |
| 213 cast_environment_->Clock()->NowTicks(); | 210 } else { |
| 214 | 211 VLOG(1) << "ACK timeout; last acked frame: " << latest_acked_frame_id_; |
| 215 time_to_next = std::max( | 212 ResendForKickstart(); |
| 216 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 213 } |
| 217 | |
| 218 cast_environment_->PostDelayedTask( | |
| 219 CastEnvironment::MAIN, | |
| 220 FROM_HERE, | |
| 221 base::Bind(&VideoSender::SendRtcpReport, | |
| 222 weak_factory_.GetWeakPtr(), | |
| 223 true), | |
| 224 time_to_next); | |
| 225 } | |
| 226 | |
| 227 void VideoSender::SendRtcpReport(bool schedule_future_reports) { | |
| 228 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
| 229 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | |
| 230 uint32 now_as_rtp_timestamp = 0; | |
| 231 if (rtp_timestamp_helper_.GetCurrentTimeAsRtpTimestamp( | |
| 232 now, &now_as_rtp_timestamp)) { | |
| 233 rtcp_.SendRtcpFromRtpSender(now, now_as_rtp_timestamp); | |
| 234 } else { | |
| 235 // |rtp_timestamp_helper_| should have stored a mapping by this point. | |
| 236 NOTREACHED(); | |
| 237 } | 214 } |
| 238 if (schedule_future_reports) | 215 ScheduleNextResendCheck(); |
| 239 ScheduleNextRtcpReport(); | |
| 240 } | 216 } |
| 241 | 217 |
| 242 void VideoSender::ScheduleNextResendCheck() { | 218 void VideoSender::ScheduleNextResendCheck() { |
| 243 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 219 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 244 DCHECK(!last_send_time_.is_null()); | 220 DCHECK(!last_send_time_.is_null()); |
| 245 base::TimeDelta time_to_next = | 221 base::TimeDelta time_to_next = |
| 246 last_send_time_ - cast_environment_->Clock()->NowTicks() + | 222 last_send_time_ - cast_environment_->Clock()->NowTicks() + |
| 247 target_playout_delay_; | 223 target_playout_delay_; |
| 248 time_to_next = std::max( | 224 time_to_next = std::max( |
| 249 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 225 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); |
| 250 cast_environment_->PostDelayedTask( | 226 cast_environment_->PostDelayedTask( |
| 251 CastEnvironment::MAIN, | 227 CastEnvironment::MAIN, |
| 252 FROM_HERE, | 228 FROM_HERE, |
| 253 base::Bind(&VideoSender::ResendCheck, weak_factory_.GetWeakPtr()), | 229 base::Bind(&VideoSender::ResendCheck, weak_factory_.GetWeakPtr()), |
| 254 time_to_next); | 230 time_to_next); |
| 255 } | 231 } |
| 256 | 232 |
| 257 void VideoSender::ResendCheck() { | |
| 258 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
| 259 DCHECK(!last_send_time_.is_null()); | |
| 260 const base::TimeDelta time_since_last_send = | |
| 261 cast_environment_->Clock()->NowTicks() - last_send_time_; | |
| 262 if (time_since_last_send > target_playout_delay_) { | |
| 263 if (latest_acked_frame_id_ == last_sent_frame_id_) { | |
| 264 // Last frame acked, no point in doing anything | |
| 265 } else { | |
| 266 VLOG(1) << "ACK timeout; last acked frame: " << latest_acked_frame_id_; | |
| 267 ResendForKickstart(); | |
| 268 } | |
| 269 } | |
| 270 ScheduleNextResendCheck(); | |
| 271 } | |
| 272 | |
| 273 void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { | 233 void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { |
| 274 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 234 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 275 | 235 |
| 276 base::TimeDelta rtt; | 236 base::TimeDelta rtt; |
| 277 base::TimeDelta avg_rtt; | 237 base::TimeDelta avg_rtt; |
| 278 base::TimeDelta min_rtt; | 238 base::TimeDelta min_rtt; |
| 279 base::TimeDelta max_rtt; | 239 base::TimeDelta max_rtt; |
| 280 if (rtcp_.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt)) { | 240 if (is_rtt_available()) { |
| 241 rtt = rtt_; | |
| 242 avg_rtt = avg_rtt_; | |
| 243 min_rtt = min_rtt_; | |
| 244 max_rtt = max_rtt_; | |
| 245 | |
| 281 congestion_control_.UpdateRtt(rtt); | 246 congestion_control_.UpdateRtt(rtt); |
| 282 | 247 |
| 283 // Don't use a RTT lower than our average. | 248 // Don't use a RTT lower than our average. |
| 284 rtt = std::max(rtt, avg_rtt); | 249 rtt = std::max(rtt, avg_rtt); |
| 285 | 250 |
| 286 // Having the RTT values implies the receiver sent back a receiver report | 251 // Having the RTT values implies the receiver sent back a receiver report |
| 287 // based on it having received a report from here. Therefore, ensure this | 252 // based on it having received a report from here. Therefore, ensure this |
| 288 // sender stops aggressively sending reports. | 253 // sender stops aggressively sending reports. |
| 289 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { | 254 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { |
| 290 VLOG(1) << "No longer a need to send reports aggressively (sent " | 255 VLOG(1) << "No longer a need to send reports aggressively (sent " |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 377 // Send the first packet of the last encoded frame to kick start | 342 // Send the first packet of the last encoded frame to kick start |
| 378 // retransmission. This gives enough information to the receiver what | 343 // retransmission. This gives enough information to the receiver what |
| 379 // packets and frames are missing. | 344 // packets and frames are missing. |
| 380 MissingFramesAndPacketsMap missing_frames_and_packets; | 345 MissingFramesAndPacketsMap missing_frames_and_packets; |
| 381 PacketIdSet missing; | 346 PacketIdSet missing; |
| 382 missing.insert(kRtcpCastLastPacket); | 347 missing.insert(kRtcpCastLastPacket); |
| 383 missing_frames_and_packets.insert( | 348 missing_frames_and_packets.insert( |
| 384 std::make_pair(last_sent_frame_id_, missing)); | 349 std::make_pair(last_sent_frame_id_, missing)); |
| 385 last_send_time_ = cast_environment_->Clock()->NowTicks(); | 350 last_send_time_ = cast_environment_->Clock()->NowTicks(); |
| 386 | 351 |
| 387 base::TimeDelta rtt; | |
| 388 base::TimeDelta avg_rtt; | |
| 389 base::TimeDelta min_rtt; | |
| 390 base::TimeDelta max_rtt; | |
| 391 rtcp_.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt); | |
| 392 | |
| 393 // Sending this extra packet is to kick-start the session. There is | 352 // Sending this extra packet is to kick-start the session. There is |
| 394 // no need to optimize re-transmission for this case. | 353 // no need to optimize re-transmission for this case. |
| 395 transport_sender_->ResendPackets(false, missing_frames_and_packets, | 354 transport_sender_->ResendPackets(false, missing_frames_and_packets, |
| 396 false, rtt); | 355 false, rtt_); |
| 397 } | 356 } |
| 398 | 357 |
| 399 } // namespace cast | 358 } // namespace cast |
| 400 } // namespace media | 359 } // namespace media |
| OLD | NEW |