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 <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/sender/external_video_encoder.h" | 16 #include "media/cast/sender/external_video_encoder.h" |
| 17 #include "media/cast/sender/video_encoder_impl.h" | 17 #include "media/cast/sender/video_encoder_impl.h" |
| 18 | 18 |
| 19 namespace media { | 19 namespace media { |
| 20 namespace cast { | 20 namespace cast { |
| 21 | 21 |
| 22 namespace { | |
| 23 | |
| 22 // The following two constants are used to adjust the target | 24 // The following two constants are used to adjust the target |
| 23 // playout delay (when allowed). They were calculated using | 25 // playout delay (when allowed). They were calculated using |
| 24 // a combination of cast_benchmark runs and manual testing. | 26 // a combination of cast_benchmark runs and manual testing. |
| 25 | 27 // |
| 26 // This is how many round trips we think we need on the network. | 28 // This is how many round trips we think we need on the network. |
| 27 const int kRoundTripsNeeded = 4; | 29 const int kRoundTripsNeeded = 4; |
| 28 // This is an estimate of all the the constant time needed | 30 // This is an estimate of all the the constant time needed independent of |
| 29 // independent of network quality. | 31 // network quality (e.g., additional time that accounts for encode and decode |
| 32 // time). | |
| 30 const int kConstantTimeMs = 75; | 33 const int kConstantTimeMs = 75; |
| 31 | 34 |
| 35 } // namespace | |
| 36 | |
| 32 // Note, we use a fixed bitrate value when external video encoder is used. | 37 // Note, we use a fixed bitrate value when external video encoder is used. |
| 33 // Some hardware encoder shows bad behavior if we set the bitrate too | 38 // Some hardware encoder shows bad behavior if we set the bitrate too |
| 34 // frequently, e.g. quality drop, not abiding by target bitrate, etc. | 39 // frequently, e.g. quality drop, not abiding by target bitrate, etc. |
| 35 // See details: crbug.com/392086. | 40 // See details: crbug.com/392086. |
| 36 VideoSender::VideoSender( | 41 VideoSender::VideoSender( |
| 37 scoped_refptr<CastEnvironment> cast_environment, | 42 scoped_refptr<CastEnvironment> cast_environment, |
| 38 const VideoSenderConfig& video_config, | 43 const VideoSenderConfig& video_config, |
| 39 const CastInitializationCallback& initialization_cb, | 44 const CastInitializationCallback& initialization_cb, |
| 40 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, | 45 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, |
| 41 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, | 46 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 88 cast_environment->PostTask( | 93 cast_environment->PostTask( |
| 89 CastEnvironment::MAIN, | 94 CastEnvironment::MAIN, |
| 90 FROM_HERE, | 95 FROM_HERE, |
| 91 base::Bind(initialization_cb, cast_initialization_status_)); | 96 base::Bind(initialization_cb, cast_initialization_status_)); |
| 92 } | 97 } |
| 93 | 98 |
| 94 media::cast::CastTransportRtpConfig transport_config; | 99 media::cast::CastTransportRtpConfig transport_config; |
| 95 transport_config.ssrc = video_config.ssrc; | 100 transport_config.ssrc = video_config.ssrc; |
| 96 transport_config.feedback_ssrc = video_config.incoming_feedback_ssrc; | 101 transport_config.feedback_ssrc = video_config.incoming_feedback_ssrc; |
| 97 transport_config.rtp_payload_type = video_config.rtp_payload_type; | 102 transport_config.rtp_payload_type = video_config.rtp_payload_type; |
| 98 transport_config.stored_frames = | |
| 99 std::min(kMaxUnackedFrames, | |
| 100 1 + static_cast<int>(max_playout_delay_ * | |
| 101 max_frame_rate_ / | |
| 102 base::TimeDelta::FromSeconds(1))); | |
| 103 transport_config.aes_key = video_config.aes_key; | 103 transport_config.aes_key = video_config.aes_key; |
| 104 transport_config.aes_iv_mask = video_config.aes_iv_mask; | 104 transport_config.aes_iv_mask = video_config.aes_iv_mask; |
| 105 | 105 |
| 106 transport_sender->InitializeVideo( | 106 transport_sender->InitializeVideo( |
| 107 transport_config, | 107 transport_config, |
| 108 base::Bind(&VideoSender::OnReceivedCastFeedback, | 108 base::Bind(&VideoSender::OnReceivedCastFeedback, |
| 109 weak_factory_.GetWeakPtr()), | 109 weak_factory_.GetWeakPtr()), |
| 110 base::Bind(&VideoSender::OnMeasuredRoundTripTime, | 110 base::Bind(&VideoSender::OnMeasuredRoundTripTime, |
| 111 weak_factory_.GetWeakPtr())); | 111 weak_factory_.GetWeakPtr())); |
| 112 } | 112 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 134 rtp_timestamp, | 134 rtp_timestamp, |
| 135 kFrameIdUnknown); | 135 kFrameIdUnknown); |
| 136 | 136 |
| 137 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc | 137 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc |
| 138 TRACE_EVENT_INSTANT2( | 138 TRACE_EVENT_INSTANT2( |
| 139 "cast_perf_test", "InsertRawVideoFrame", | 139 "cast_perf_test", "InsertRawVideoFrame", |
| 140 TRACE_EVENT_SCOPE_THREAD, | 140 TRACE_EVENT_SCOPE_THREAD, |
| 141 "timestamp", capture_time.ToInternalValue(), | 141 "timestamp", capture_time.ToInternalValue(), |
| 142 "rtp_timestamp", rtp_timestamp); | 142 "rtp_timestamp", rtp_timestamp); |
| 143 | 143 |
| 144 if (ShouldDropNextFrame(capture_time)) { | 144 // Drop frames that are out-of-order since the duration calculations assume |
| 145 VLOG(1) << "Dropping frame due to too many frames currently in-flight."; | 145 // frame timestamps are monotonically non-decreasing. |
| 146 if (!last_enqueued_frame_reference_time_.is_null() && | |
| 147 capture_time < last_enqueued_frame_reference_time_) { | |
|
hubbe
2014/09/18 17:56:05
We don't want frames where capture time is identic
miu
2014/09/18 21:38:43
Done.
| |
| 148 VLOG(1) << "Dropping video frame: Reference time is out-of-order."; | |
| 149 return; | |
| 150 } | |
| 151 | |
| 152 // Two video frames are needed to compute the exact media duration added by | |
| 153 // the next frame. If there are no frames in the encoder, compute a guess | |
| 154 // based on the configured |max_frame_rate_|. Any error introduced by this | |
| 155 // guess will be eliminated when |duration_in_encoder_| is updated in | |
| 156 // OnEncodedVideoFrame(). | |
| 157 const base::TimeDelta duration_added_by_next_frame = frames_in_encoder_ > 0 ? | |
| 158 capture_time - last_enqueued_frame_reference_time_ : | |
| 159 base::TimeDelta::FromMicroseconds(1000000.0 / max_frame_rate_ + 0.5); | |
|
hubbe
2014/09/18 17:56:05
why + 0.5 ?
miu
2014/09/18 21:38:43
Rounding to nearest int. I made this more explici
hubbe
2014/09/18 22:22:59
Why not just use TimeDelta::FromSecondsD(1.0 / max
miu
2014/09/19 19:39:43
Because that would be the right way to do it. ;-)
| |
| 160 | |
| 161 if (ShouldDropNextFrame(duration_added_by_next_frame)) { | |
| 146 base::TimeDelta new_target_delay = std::min( | 162 base::TimeDelta new_target_delay = std::min( |
| 147 current_round_trip_time_ * kRoundTripsNeeded + | 163 current_round_trip_time_ * kRoundTripsNeeded + |
| 148 base::TimeDelta::FromMilliseconds(kConstantTimeMs), | 164 base::TimeDelta::FromMilliseconds(kConstantTimeMs), |
| 149 max_playout_delay_); | 165 max_playout_delay_); |
| 150 if (new_target_delay > target_playout_delay_) { | 166 if (new_target_delay > target_playout_delay_) { |
| 151 VLOG(1) << "New target delay: " << new_target_delay.InMilliseconds(); | 167 VLOG(1) << "New target delay: " << new_target_delay.InMilliseconds(); |
| 152 playout_delay_change_cb_.Run(new_target_delay); | 168 playout_delay_change_cb_.Run(new_target_delay); |
| 153 } | 169 } |
| 154 return; | 170 return; |
| 155 } | 171 } |
| 156 | 172 |
| 157 uint32 bitrate = congestion_control_->GetBitrate( | 173 uint32 bitrate = congestion_control_->GetBitrate( |
| 158 capture_time + target_playout_delay_, target_playout_delay_); | 174 capture_time + target_playout_delay_, target_playout_delay_); |
| 159 if (bitrate != last_bitrate_) { | 175 if (bitrate != last_bitrate_) { |
| 160 video_encoder_->SetBitRate(bitrate); | 176 video_encoder_->SetBitRate(bitrate); |
| 161 last_bitrate_ = bitrate; | 177 last_bitrate_ = bitrate; |
| 162 } | 178 } |
| 163 | 179 |
| 164 if (video_encoder_->EncodeVideoFrame( | 180 if (video_encoder_->EncodeVideoFrame( |
| 165 video_frame, | 181 video_frame, |
| 166 capture_time, | 182 capture_time, |
| 167 base::Bind(&VideoSender::OnEncodedVideoFrame, | 183 base::Bind(&VideoSender::OnEncodedVideoFrame, |
| 168 weak_factory_.GetWeakPtr(), | 184 weak_factory_.GetWeakPtr(), |
| 169 bitrate))) { | 185 bitrate))) { |
| 170 frames_in_encoder_++; | 186 frames_in_encoder_++; |
| 187 duration_in_encoder_ += duration_added_by_next_frame; | |
| 188 last_enqueued_frame_reference_time_ = capture_time; | |
| 171 } else { | 189 } else { |
| 172 VLOG(1) << "Encoder rejected a frame. Skipping..."; | 190 VLOG(1) << "Encoder rejected a frame. Skipping..."; |
| 173 } | 191 } |
| 174 } | 192 } |
| 175 | 193 |
| 176 int VideoSender::GetNumberOfFramesInEncoder() const { | 194 int VideoSender::GetNumberOfFramesInEncoder() const { |
| 177 return frames_in_encoder_; | 195 return frames_in_encoder_; |
| 178 } | 196 } |
| 179 | 197 |
| 198 base::TimeDelta VideoSender::GetInFlightMediaDuration() const { | |
| 199 if (GetUnacknowledgedFrameCount() > 0) { | |
| 200 const uint32 oldest_unacked_frame_id = latest_acked_frame_id_ + 1; | |
| 201 return duration_in_encoder_ + | |
|
hubbe
2014/09/18 17:56:05
Isn't this equivalent to:
GetRecordedReferenceTim
miu
2014/09/18 21:38:43
Ah, good point. But, I think you meant:
last_e
| |
| 202 (GetRecordedReferenceTime(last_sent_frame_id_) - | |
| 203 GetRecordedReferenceTime(oldest_unacked_frame_id)); | |
| 204 } else { | |
| 205 return duration_in_encoder_; | |
| 206 } | |
| 207 } | |
| 208 | |
| 180 void VideoSender::OnAck(uint32 frame_id) { | 209 void VideoSender::OnAck(uint32 frame_id) { |
| 181 video_encoder_->LatestFrameIdToReference(frame_id); | 210 video_encoder_->LatestFrameIdToReference(frame_id); |
| 182 } | 211 } |
| 183 | 212 |
| 184 void VideoSender::OnEncoderInitialized( | 213 void VideoSender::OnEncoderInitialized( |
| 185 const CastInitializationCallback& initialization_cb, | 214 const CastInitializationCallback& initialization_cb, |
| 186 CastInitializationStatus status) { | 215 CastInitializationStatus status) { |
| 187 cast_initialization_status_ = status; | 216 cast_initialization_status_ = status; |
| 188 initialization_cb.Run(status); | 217 initialization_cb.Run(status); |
| 189 } | 218 } |
| 190 | 219 |
| 191 void VideoSender::OnEncodedVideoFrame( | 220 void VideoSender::OnEncodedVideoFrame( |
| 192 int encoder_bitrate, | 221 int encoder_bitrate, |
| 193 scoped_ptr<EncodedFrame> encoded_frame) { | 222 scoped_ptr<EncodedFrame> encoded_frame) { |
| 194 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 223 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 195 | 224 |
| 196 frames_in_encoder_--; | 225 frames_in_encoder_--; |
| 197 DCHECK_GE(frames_in_encoder_, 0); | 226 DCHECK_GE(frames_in_encoder_, 0); |
| 198 | 227 |
| 228 duration_in_encoder_ = | |
| 229 last_enqueued_frame_reference_time_ - encoded_frame->reference_time; | |
| 230 | |
| 199 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); | 231 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); |
| 200 } | 232 } |
| 201 | 233 |
| 202 } // namespace cast | 234 } // namespace cast |
| 203 } // namespace media | 235 } // namespace media |
| OLD | NEW |