Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(298)

Side by Side Diff: media/cast/sender/video_sender.cc

Issue 560223002: [Cast] Limit frames in flight by duration, and not by number of frames. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Account for faster input than configured max FPS. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698