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 3 // found in the LICENSE file. 4 5 #include "media/cast/sender/video_sender.h" 6 7 #include <algorithm> 8 #include <cstring> 9 10 #include "base/bind.h" 11 #include "base/debug/trace_event.h" 12 #include "base/logging.h" 13 #include "base/message_loop/message_loop.h" 14 #include "media/cast/cast_defines.h" 15 #include "media/cast/net/cast_transport_config.h" 16 #include "media/cast/sender/external_video_encoder.h" 17 #include "media/cast/sender/video_encoder_impl.h" 18 19 namespace media { 20 namespace cast { 21 22 namespace { 23 24 // The following two constants are used to adjust the target 25 // playout delay (when allowed). They were calculated using 26 // a combination of cast_benchmark runs and manual testing. 27 // 28 // This is how many round trips we think we need on the network. 29 const int kRoundTripsNeeded = 4; 30 // This is an estimate of all the the constant time needed independent of 31 // network quality (e.g., additional time that accounts for encode and decode 32 // time). 33 const int kConstantTimeMs = 75; 34 35 } // namespace 36 37 // Note, we use a fixed bitrate value when external video encoder is used. 38 // Some hardware encoder shows bad behavior if we set the bitrate too 39 // frequently, e.g. quality drop, not abiding by target bitrate, etc. 40 // See details: crbug.com/392086. 41 VideoSender::VideoSender( 42 scoped_refptr<CastEnvironment> cast_environment, 43 const VideoSenderConfig& video_config, 44 const CastInitializationCallback& initialization_cb, 45 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, 46 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, 47 CastTransportSender* const transport_sender, 48 const PlayoutDelayChangeCB& playout_delay_change_cb) 49 : FrameSender( 50 cast_environment, 51 false, 52 transport_sender, 53 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval), 54 kVideoFrequency, 55 video_config.ssrc, 56 video_config.max_frame_rate, 57 video_config.min_playout_delay, 58 video_config.max_playout_delay, 59 NewFixedCongestionControl( 60 (video_config.min_bitrate + video_config.max_bitrate) / 2)), 61 frames_in_encoder_(0), 62 last_bitrate_(0), 63 playout_delay_change_cb_(playout_delay_change_cb), 64 weak_factory_(this) { 65 cast_initialization_status_ = STATUS_VIDEO_UNINITIALIZED; 66 VLOG(1) << "max_unacked_frames is " << max_unacked_frames_ 67 << " for target_playout_delay=" 68 << target_playout_delay_.InMilliseconds() << " ms" 69 << " and max_frame_rate=" << video_config.max_frame_rate; 70 DCHECK_GT(max_unacked_frames_, 0); 71 72 if (video_config.use_external_encoder) { 73 video_encoder_.reset(new ExternalVideoEncoder( 74 cast_environment, 75 video_config, 76 base::Bind(&VideoSender::OnEncoderInitialized, 77 weak_factory_.GetWeakPtr(), initialization_cb), 78 create_vea_cb, 79 create_video_encode_mem_cb)); 80 } else { 81 // Software encoder is initialized immediately. 82 congestion_control_.reset( 83 NewAdaptiveCongestionControl(cast_environment->Clock(), 84 video_config.max_bitrate, 85 video_config.min_bitrate, 86 max_unacked_frames_)); 87 video_encoder_.reset(new VideoEncoderImpl( 88 cast_environment, video_config, max_unacked_frames_)); 89 cast_initialization_status_ = STATUS_VIDEO_INITIALIZED; 90 } 91 92 if (cast_initialization_status_ == STATUS_VIDEO_INITIALIZED) { 93 cast_environment->PostTask( 94 CastEnvironment::MAIN, 95 FROM_HERE, 96 base::Bind(initialization_cb, cast_initialization_status_)); 97 } 98 99 media::cast::CastTransportRtpConfig transport_config; 100 transport_config.ssrc = video_config.ssrc; 101 transport_config.feedback_ssrc = video_config.incoming_feedback_ssrc; 102 transport_config.rtp_payload_type = video_config.rtp_payload_type; 103 transport_config.aes_key = video_config.aes_key; 104 transport_config.aes_iv_mask = video_config.aes_iv_mask; 105 106 transport_sender->InitializeVideo( 107 transport_config, 108 base::Bind(&VideoSender::OnReceivedCastFeedback, 109 weak_factory_.GetWeakPtr()), 110 base::Bind(&VideoSender::OnMeasuredRoundTripTime, 111 weak_factory_.GetWeakPtr())); 112 } 113 114 VideoSender::~VideoSender() { 115 } 116 117 void VideoSender::InsertRawVideoFrame( 118 const scoped_refptr<media::VideoFrame>& video_frame, 119 const base::TimeTicks& capture_time) { 120 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 121 if (cast_initialization_status_ != STATUS_VIDEO_INITIALIZED) { 122 NOTREACHED(); 123 return; 124 } 125 DCHECK(video_encoder_.get()) << "Invalid state"; 126 127 RtpTimestamp rtp_timestamp = GetVideoRtpTimestamp(capture_time); 128 cast_environment_->Logging()->InsertFrameEvent( 129 capture_time, FRAME_CAPTURE_BEGIN, VIDEO_EVENT, 130 rtp_timestamp, kFrameIdUnknown); 131 cast_environment_->Logging()->InsertFrameEvent( 132 cast_environment_->Clock()->NowTicks(), 133 FRAME_CAPTURE_END, VIDEO_EVENT, 134 rtp_timestamp, 135 kFrameIdUnknown); 136 137 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc 138 TRACE_EVENT_INSTANT2( 139 "cast_perf_test", "InsertRawVideoFrame", 140 TRACE_EVENT_SCOPE_THREAD, 141 "timestamp", capture_time.ToInternalValue(), 142 "rtp_timestamp", rtp_timestamp); 143 144 // Drop the frame if its reference timestamp is not an increase over the last 145 // frame's. This protects: 1) the duration calculations that assume 146 // timestamps are monotonically non-decreasing, and 2) assumptions made deeper 147 // in the implementation where each frame's RTP timestamp needs to be unique. 148 if (!last_enqueued_frame_reference_time_.is_null() && 149 capture_time <= last_enqueued_frame_reference_time_) { 150 VLOG(1) << "Dropping video frame: Reference time did not increase."; 151 return; 152 } 153 154 // Two video frames are needed to compute the exact media duration added by 155 // the next frame. If there are no frames in the encoder, compute a guess 156 // based on the configured |max_frame_rate_|. Any error introduced by this 157 // guess will be eliminated when |duration_in_encoder_| is updated in 158 // OnEncodedVideoFrame(). 159 const base::TimeDelta duration_added_by_next_frame = frames_in_encoder_ > 0 ? 160 capture_time - last_enqueued_frame_reference_time_ : 161 base::TimeDelta::FromSecondsD(1.0 / max_frame_rate_); 162 163 if (ShouldDropNextFrame(duration_added_by_next_frame)) { 164 base::TimeDelta new_target_delay = std::min( 165 current_round_trip_time_ * kRoundTripsNeeded + 166 base::TimeDelta::FromMilliseconds(kConstantTimeMs), 167 max_playout_delay_); 168 if (new_target_delay > target_playout_delay_) { 169 VLOG(1) << "New target delay: " << new_target_delay.InMilliseconds(); 170 playout_delay_change_cb_.Run(new_target_delay); 171 } 172 return; 173 } 174 175 uint32 bitrate = congestion_control_->GetBitrate( 176 capture_time + target_playout_delay_, target_playout_delay_); 177 if (bitrate != last_bitrate_) { 178 video_encoder_->SetBitRate(bitrate); 179 last_bitrate_ = bitrate; 180 } 181 182 if (video_encoder_->EncodeVideoFrame( 183 video_frame, 184 capture_time, 185 base::Bind(&VideoSender::OnEncodedVideoFrame, 186 weak_factory_.GetWeakPtr(), 187 bitrate))) { 188 frames_in_encoder_++; 189 duration_in_encoder_ += duration_added_by_next_frame; 190 last_enqueued_frame_reference_time_ = capture_time; 191 } else { 192 VLOG(1) << "Encoder rejected a frame. Skipping..."; 193 } 194 } 195 196 int VideoSender::GetNumberOfFramesInEncoder() const { 197 return frames_in_encoder_; 198 } 199 200 base::TimeDelta VideoSender::GetInFlightMediaDuration() const { 201 if (GetUnacknowledgedFrameCount() > 0) { 202 const uint32 oldest_unacked_frame_id = latest_acked_frame_id_ + 1; 203 return last_enqueued_frame_reference_time_ - 204 GetRecordedReferenceTime(oldest_unacked_frame_id); 205 } else { 206 return duration_in_encoder_; 207 } 208 } 209 210 void VideoSender::OnAck(uint32 frame_id) { 211 video_encoder_->LatestFrameIdToReference(frame_id); 212 } 213 214 void VideoSender::OnEncoderInitialized( 215 const CastInitializationCallback& initialization_cb, 216 CastInitializationStatus status) { 217 cast_initialization_status_ = status; 218 initialization_cb.Run(status); 219 } 220 221 void VideoSender::OnEncodedVideoFrame( 222 int encoder_bitrate, 223 scoped_ptr<EncodedFrame> encoded_frame) { 224 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 225 226 frames_in_encoder_--; 227 DCHECK_GE(frames_in_encoder_, 0); 228 229 duration_in_encoder_ = 230 last_enqueued_frame_reference_time_ - encoded_frame->reference_time; 231 232 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); 233 } 234 235 } // namespace cast 236 } // namespace media 237