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 // The additional number of frames that can be in-flight when input exceeds the | |
24 // maximum frame rate. | |
25 const int kMaxFrameBurst = 5; | |
26 } | |
27 | |
22 // Note, we use a fixed bitrate value when external video encoder is used. | 28 // Note, we use a fixed bitrate value when external video encoder is used. |
23 // Some hardware encoder shows bad behavior if we set the bitrate too | 29 // Some hardware encoder shows bad behavior if we set the bitrate too |
24 // frequently, e.g. quality drop, not abiding by target bitrate, etc. | 30 // frequently, e.g. quality drop, not abiding by target bitrate, etc. |
25 // See details: crbug.com/392086. | 31 // See details: crbug.com/392086. |
26 VideoSender::VideoSender( | 32 VideoSender::VideoSender( |
27 scoped_refptr<CastEnvironment> cast_environment, | 33 scoped_refptr<CastEnvironment> cast_environment, |
28 const VideoSenderConfig& video_config, | 34 const VideoSenderConfig& video_config, |
29 const CastInitializationCallback& initialization_cb, | 35 const CastInitializationCallback& initialization_cb, |
30 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, | 36 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, |
31 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, | 37 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 cast_environment->PostTask( | 81 cast_environment->PostTask( |
76 CastEnvironment::MAIN, | 82 CastEnvironment::MAIN, |
77 FROM_HERE, | 83 FROM_HERE, |
78 base::Bind(initialization_cb, cast_initialization_status_)); | 84 base::Bind(initialization_cb, cast_initialization_status_)); |
79 } | 85 } |
80 | 86 |
81 media::cast::CastTransportRtpConfig transport_config; | 87 media::cast::CastTransportRtpConfig transport_config; |
82 transport_config.ssrc = video_config.ssrc; | 88 transport_config.ssrc = video_config.ssrc; |
83 transport_config.feedback_ssrc = video_config.incoming_feedback_ssrc; | 89 transport_config.feedback_ssrc = video_config.incoming_feedback_ssrc; |
84 transport_config.rtp_payload_type = video_config.rtp_payload_type; | 90 transport_config.rtp_payload_type = video_config.rtp_payload_type; |
85 transport_config.stored_frames = max_unacked_frames_; | |
86 transport_config.aes_key = video_config.aes_key; | 91 transport_config.aes_key = video_config.aes_key; |
87 transport_config.aes_iv_mask = video_config.aes_iv_mask; | 92 transport_config.aes_iv_mask = video_config.aes_iv_mask; |
88 | 93 |
89 transport_sender->InitializeVideo( | 94 transport_sender->InitializeVideo( |
90 transport_config, | 95 transport_config, |
91 base::Bind(&VideoSender::OnReceivedCastFeedback, | 96 base::Bind(&VideoSender::OnReceivedCastFeedback, |
92 weak_factory_.GetWeakPtr()), | 97 weak_factory_.GetWeakPtr()), |
93 base::Bind(&VideoSender::OnMeasuredRoundTripTime, | 98 base::Bind(&VideoSender::OnMeasuredRoundTripTime, |
94 weak_factory_.GetWeakPtr())); | 99 weak_factory_.GetWeakPtr())); |
95 } | 100 } |
(...skipping 21 matching lines...) Expand all Loading... | |
117 rtp_timestamp, | 122 rtp_timestamp, |
118 kFrameIdUnknown); | 123 kFrameIdUnknown); |
119 | 124 |
120 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc | 125 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc |
121 TRACE_EVENT_INSTANT2( | 126 TRACE_EVENT_INSTANT2( |
122 "cast_perf_test", "InsertRawVideoFrame", | 127 "cast_perf_test", "InsertRawVideoFrame", |
123 TRACE_EVENT_SCOPE_THREAD, | 128 TRACE_EVENT_SCOPE_THREAD, |
124 "timestamp", capture_time.ToInternalValue(), | 129 "timestamp", capture_time.ToInternalValue(), |
125 "rtp_timestamp", rtp_timestamp); | 130 "rtp_timestamp", rtp_timestamp); |
126 | 131 |
127 if (ShouldDropNextFrame(capture_time)) { | 132 // Drop frames that are out-of-order since the duration calculations assume |
hubbe
2014/09/11 23:05:06
Do we really need separate code for audio and vide
miu
2014/09/18 01:10:52
Done.
| |
128 VLOG(1) << "Dropping frame due to too many frames currently in-flight."; | 133 // frame timestamps are monotonically non-decreasing. |
134 if (!last_enqueued_frame_reference_time_.is_null() && | |
135 capture_time < last_enqueued_frame_reference_time_) { | |
136 VLOG(1) << "Dropping video frame: Reference time is out-of-order."; | |
129 return; | 137 return; |
130 } | 138 } |
131 | 139 |
140 // Check that enqueuing the next |video_frame| won't cause more frames to | |
141 // become in-flight than the system's design limit. | |
142 const int count_unacked_frames = GetUnackedFrameCount(); | |
143 const int count_frames_in_flight = frames_in_encoder_ + count_unacked_frames; | |
144 if (count_frames_in_flight >= kMaxUnackedFrames) { | |
145 VLOG(1) << "Dropping video frame: Too many frames would be in-flight."; | |
146 return; | |
147 } | |
148 | |
149 // Check that enqueuing the next |video_frame| won't exceed the configured | |
150 // frame rate, allowing for short-term bursts. | |
151 base::TimeDelta duration_in_flight = duration_in_encoder_; | |
152 if (count_unacked_frames > 0) { | |
153 const uint32 oldest_unacked_frame_id = latest_acked_frame_id_ + 1; | |
154 duration_in_flight += GetRecordedReferenceTime(last_sent_frame_id_) - | |
155 GetRecordedReferenceTime(oldest_unacked_frame_id); | |
156 } | |
157 const double max_frames_in_flight = | |
158 max_frame_rate_ * duration_in_flight.InSecondsF(); | |
159 if (count_frames_in_flight >= max_frames_in_flight + kMaxFrameBurst) { | |
160 VLOG(1) << "Dropping video frame: Safe burst threshold would be exceeded."; | |
161 return; | |
162 } | |
163 | |
164 // Check that enqueuing the next |video_frame| won't exceed the allowed | |
165 // in-flight media duration. | |
166 // | |
167 // Two video frames are needed to compute the exact media duration added by | |
168 // the next frame. If there are no frames in the encoder, compute a guess | |
169 // based on the configured |max_frame_rate_|. Any error introduced by this | |
170 // guess will be eliminated when |duration_in_encoder_| is updated in | |
171 // OnEncodedVideoFrame(). | |
172 const base::TimeDelta duration_added_by_next_frame = frames_in_encoder_ > 0 ? | |
173 capture_time - last_enqueued_frame_reference_time_ : | |
174 base::TimeDelta::FromMicroseconds(1000000.0 / max_frame_rate_ + 0.5); | |
175 const base::TimeDelta duration_would_be_in_flight = | |
176 duration_in_flight + duration_added_by_next_frame; | |
177 const base::TimeDelta allowed_in_flight = GetAllowedInFlightMediaDuration(); | |
178 VLOG(2) << "Video in-flight: " | |
179 << duration_in_flight.InMicroseconds() << " usec in-flight + " | |
180 << duration_added_by_next_frame.InMicroseconds() | |
181 << " usec for next frame would be " | |
182 << (allowed_in_flight > base::TimeDelta() ? | |
183 100 * duration_would_be_in_flight / allowed_in_flight : | |
184 kint64max) << "% of allowed in-flight."; | |
185 if (duration_would_be_in_flight > allowed_in_flight) { | |
186 VLOG(1) << "Dropping video: Too long a video duration would be in-flight."; | |
187 return; | |
188 } | |
189 | |
132 uint32 bitrate = congestion_control_->GetBitrate( | 190 uint32 bitrate = congestion_control_->GetBitrate( |
133 capture_time + target_playout_delay_, target_playout_delay_); | 191 capture_time + target_playout_delay_, target_playout_delay_); |
134 if (bitrate != last_bitrate_) { | 192 if (bitrate != last_bitrate_) { |
135 video_encoder_->SetBitRate(bitrate); | 193 video_encoder_->SetBitRate(bitrate); |
136 last_bitrate_ = bitrate; | 194 last_bitrate_ = bitrate; |
137 } | 195 } |
138 | 196 |
139 if (video_encoder_->EncodeVideoFrame( | 197 if (video_encoder_->EncodeVideoFrame( |
140 video_frame, | 198 video_frame, |
141 capture_time, | 199 capture_time, |
142 base::Bind(&VideoSender::OnEncodedVideoFrame, | 200 base::Bind(&VideoSender::OnEncodedVideoFrame, |
143 weak_factory_.GetWeakPtr(), | 201 weak_factory_.GetWeakPtr(), |
144 bitrate))) { | 202 bitrate))) { |
203 last_enqueued_frame_reference_time_ = capture_time; | |
145 frames_in_encoder_++; | 204 frames_in_encoder_++; |
205 duration_in_encoder_ += duration_added_by_next_frame; | |
146 } else { | 206 } else { |
147 VLOG(1) << "Encoder rejected a frame. Skipping..."; | 207 VLOG(1) << "Encoder rejected a frame. Skipping..."; |
148 } | 208 } |
149 } | 209 } |
150 | 210 |
151 int VideoSender::GetNumberOfFramesInEncoder() const { | |
152 return frames_in_encoder_; | |
153 } | |
154 | |
155 void VideoSender::OnAck(uint32 frame_id) { | 211 void VideoSender::OnAck(uint32 frame_id) { |
156 video_encoder_->LatestFrameIdToReference(frame_id); | 212 video_encoder_->LatestFrameIdToReference(frame_id); |
157 } | 213 } |
158 | 214 |
159 void VideoSender::OnEncoderInitialized( | 215 void VideoSender::OnEncoderInitialized( |
160 const CastInitializationCallback& initialization_cb, | 216 const CastInitializationCallback& initialization_cb, |
161 CastInitializationStatus status) { | 217 CastInitializationStatus status) { |
162 cast_initialization_status_ = status; | 218 cast_initialization_status_ = status; |
163 initialization_cb.Run(status); | 219 initialization_cb.Run(status); |
164 } | 220 } |
165 | 221 |
166 void VideoSender::OnEncodedVideoFrame( | 222 void VideoSender::OnEncodedVideoFrame( |
167 int encoder_bitrate, | 223 int encoder_bitrate, |
168 scoped_ptr<EncodedFrame> encoded_frame) { | 224 scoped_ptr<EncodedFrame> encoded_frame) { |
169 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 225 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
170 | 226 |
171 frames_in_encoder_--; | 227 frames_in_encoder_--; |
172 DCHECK_GE(frames_in_encoder_, 0); | 228 DCHECK_GE(frames_in_encoder_, 0); |
173 | 229 |
230 duration_in_encoder_ = | |
231 last_enqueued_frame_reference_time_ - encoded_frame->reference_time; | |
232 | |
174 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); | 233 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); |
175 } | 234 } |
176 | 235 |
177 } // namespace cast | 236 } // namespace cast |
178 } // namespace media | 237 } // namespace media |
OLD | NEW |