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 <cmath> | 8 #include <cmath> |
9 #include <cstring> | 9 #include <cstring> |
10 | 10 |
(...skipping 25 matching lines...) Expand all Loading... |
36 // The target maximum utilization of the encoder and network resources. This is | 36 // The target maximum utilization of the encoder and network resources. This is |
37 // used to attenuate the actual measured utilization values in order to provide | 37 // used to attenuate the actual measured utilization values in order to provide |
38 // "breathing room" (i.e., to ensure there will be sufficient CPU and bandwidth | 38 // "breathing room" (i.e., to ensure there will be sufficient CPU and bandwidth |
39 // available to handle the occasional more-complex frames). | 39 // available to handle the occasional more-complex frames). |
40 const int kTargetUtilizationPercentage = 75; | 40 const int kTargetUtilizationPercentage = 75; |
41 | 41 |
42 // Extract capture begin/end timestamps from |video_frame|'s metadata and log | 42 // Extract capture begin/end timestamps from |video_frame|'s metadata and log |
43 // it. | 43 // it. |
44 void LogVideoCaptureTimestamps(CastEnvironment* cast_environment, | 44 void LogVideoCaptureTimestamps(CastEnvironment* cast_environment, |
45 const media::VideoFrame& video_frame, | 45 const media::VideoFrame& video_frame, |
46 RtpTimestamp rtp_timestamp) { | 46 RtpTimeTicks rtp_timestamp) { |
47 scoped_ptr<FrameEvent> capture_begin_event(new FrameEvent()); | 47 scoped_ptr<FrameEvent> capture_begin_event(new FrameEvent()); |
48 capture_begin_event->type = FRAME_CAPTURE_BEGIN; | 48 capture_begin_event->type = FRAME_CAPTURE_BEGIN; |
49 capture_begin_event->media_type = VIDEO_EVENT; | 49 capture_begin_event->media_type = VIDEO_EVENT; |
50 capture_begin_event->rtp_timestamp = rtp_timestamp; | 50 capture_begin_event->rtp_timestamp = rtp_timestamp; |
51 | 51 |
52 scoped_ptr<FrameEvent> capture_end_event(new FrameEvent()); | 52 scoped_ptr<FrameEvent> capture_end_event(new FrameEvent()); |
53 capture_end_event->type = FRAME_CAPTURE_END; | 53 capture_end_event->type = FRAME_CAPTURE_END; |
54 capture_end_event->media_type = VIDEO_EVENT; | 54 capture_end_event->media_type = VIDEO_EVENT; |
55 capture_end_event->rtp_timestamp = rtp_timestamp; | 55 capture_end_event->rtp_timestamp = rtp_timestamp; |
56 capture_end_event->width = video_frame.visible_rect().width(); | 56 capture_end_event->width = video_frame.visible_rect().width(); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 void VideoSender::InsertRawVideoFrame( | 142 void VideoSender::InsertRawVideoFrame( |
143 const scoped_refptr<media::VideoFrame>& video_frame, | 143 const scoped_refptr<media::VideoFrame>& video_frame, |
144 const base::TimeTicks& reference_time) { | 144 const base::TimeTicks& reference_time) { |
145 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 145 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
146 | 146 |
147 if (!video_encoder_) { | 147 if (!video_encoder_) { |
148 NOTREACHED(); | 148 NOTREACHED(); |
149 return; | 149 return; |
150 } | 150 } |
151 | 151 |
152 const RtpTimestamp rtp_timestamp = | 152 const RtpTimeTicks rtp_timestamp = |
153 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency); | 153 RtpTimeTicks::FromTimeDelta(video_frame->timestamp(), kVideoFrequency); |
154 LogVideoCaptureTimestamps(cast_environment_.get(), *video_frame, | 154 LogVideoCaptureTimestamps(cast_environment_.get(), *video_frame, |
155 rtp_timestamp); | 155 rtp_timestamp); |
156 | 156 |
157 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc | 157 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc |
158 TRACE_EVENT_INSTANT2( | 158 TRACE_EVENT_INSTANT2( |
159 "cast_perf_test", "InsertRawVideoFrame", | 159 "cast_perf_test", "InsertRawVideoFrame", |
160 TRACE_EVENT_SCOPE_THREAD, | 160 TRACE_EVENT_SCOPE_THREAD, |
161 "timestamp", reference_time.ToInternalValue(), | 161 "timestamp", reference_time.ToInternalValue(), |
162 "rtp_timestamp", rtp_timestamp); | 162 "rtp_timestamp", rtp_timestamp.lower_32_bits()); |
163 | 163 |
164 // Drop the frame if either its RTP or reference timestamp is not an increase | 164 // Drop the frame if either its RTP or reference timestamp is not an increase |
165 // over the last frame's. This protects: 1) the duration calculations that | 165 // over the last frame's. This protects: 1) the duration calculations that |
166 // assume timestamps are monotonically non-decreasing, and 2) assumptions made | 166 // assume timestamps are monotonically non-decreasing, and 2) assumptions made |
167 // deeper in the implementation where each frame's RTP timestamp needs to be | 167 // deeper in the implementation where each frame's RTP timestamp needs to be |
168 // unique. | 168 // unique. |
169 if (!last_enqueued_frame_reference_time_.is_null() && | 169 if (!last_enqueued_frame_reference_time_.is_null() && |
170 (!IsNewerRtpTimestamp(rtp_timestamp, | 170 (rtp_timestamp <= last_enqueued_frame_rtp_timestamp_ || |
171 last_enqueued_frame_rtp_timestamp_) || | |
172 reference_time <= last_enqueued_frame_reference_time_)) { | 171 reference_time <= last_enqueued_frame_reference_time_)) { |
173 VLOG(1) << "Dropping video frame: RTP or reference time did not increase."; | 172 VLOG(1) << "Dropping video frame: RTP or reference time did not increase."; |
174 TRACE_EVENT_INSTANT2("cast.stream", "Video Frame Drop", | 173 TRACE_EVENT_INSTANT2("cast.stream", "Video Frame Drop", |
175 TRACE_EVENT_SCOPE_THREAD, | 174 TRACE_EVENT_SCOPE_THREAD, |
176 "rtp_timestamp", rtp_timestamp, | 175 "rtp_timestamp", rtp_timestamp.lower_32_bits(), |
177 "reason", "time did not increase"); | 176 "reason", "time did not increase"); |
178 return; | 177 return; |
179 } | 178 } |
180 | 179 |
181 // Two video frames are needed to compute the exact media duration added by | 180 // Two video frames are needed to compute the exact media duration added by |
182 // the next frame. If there are no frames in the encoder, compute a guess | 181 // the next frame. If there are no frames in the encoder, compute a guess |
183 // based on the configured |max_frame_rate_|. Any error introduced by this | 182 // based on the configured |max_frame_rate_|. Any error introduced by this |
184 // guess will be eliminated when |duration_in_encoder_| is updated in | 183 // guess will be eliminated when |duration_in_encoder_| is updated in |
185 // OnEncodedVideoFrame(). | 184 // OnEncodedVideoFrame(). |
186 const base::TimeDelta duration_added_by_next_frame = frames_in_encoder_ > 0 ? | 185 const base::TimeDelta duration_added_by_next_frame = frames_in_encoder_ > 0 ? |
187 reference_time - last_enqueued_frame_reference_time_ : | 186 reference_time - last_enqueued_frame_reference_time_ : |
(...skipping 10 matching lines...) Expand all Loading... |
198 } | 197 } |
199 | 198 |
200 // Some encoder implementations have a frame window for analysis. Since we | 199 // Some encoder implementations have a frame window for analysis. Since we |
201 // are dropping this frame, unless we instruct the encoder to flush all the | 200 // are dropping this frame, unless we instruct the encoder to flush all the |
202 // frames that have been enqueued for encoding, frames_in_encoder_ and | 201 // frames that have been enqueued for encoding, frames_in_encoder_ and |
203 // last_enqueued_frame_reference_time_ will never be updated and we will | 202 // last_enqueued_frame_reference_time_ will never be updated and we will |
204 // drop every subsequent frame for the rest of the session. | 203 // drop every subsequent frame for the rest of the session. |
205 video_encoder_->EmitFrames(); | 204 video_encoder_->EmitFrames(); |
206 | 205 |
207 TRACE_EVENT_INSTANT2("cast.stream", "Video Frame Drop", | 206 TRACE_EVENT_INSTANT2("cast.stream", "Video Frame Drop", |
208 TRACE_EVENT_SCOPE_THREAD, | 207 TRACE_EVENT_SCOPE_THREAD, |
209 "rtp_timestamp", rtp_timestamp, | 208 "rtp_timestamp", rtp_timestamp.lower_32_bits(), |
210 "reason", "too much in flight"); | 209 "reason", "too much in flight"); |
211 return; | 210 return; |
212 } | 211 } |
213 | 212 |
214 if (video_frame->visible_rect().IsEmpty()) { | 213 if (video_frame->visible_rect().IsEmpty()) { |
215 VLOG(1) << "Rejecting empty video frame."; | 214 VLOG(1) << "Rejecting empty video frame."; |
216 return; | 215 return; |
217 } | 216 } |
218 | 217 |
219 const int bitrate = congestion_control_->GetBitrate( | 218 const int bitrate = congestion_control_->GetBitrate( |
220 reference_time + target_playout_delay_, target_playout_delay_, | 219 reference_time + target_playout_delay_, target_playout_delay_, |
(...skipping 12 matching lines...) Expand all Loading... |
233 video_frame.get()); | 232 video_frame.get()); |
234 | 233 |
235 if (video_encoder_->EncodeVideoFrame( | 234 if (video_encoder_->EncodeVideoFrame( |
236 video_frame, | 235 video_frame, |
237 reference_time, | 236 reference_time, |
238 base::Bind(&VideoSender::OnEncodedVideoFrame, | 237 base::Bind(&VideoSender::OnEncodedVideoFrame, |
239 weak_factory_.GetWeakPtr(), | 238 weak_factory_.GetWeakPtr(), |
240 video_frame, | 239 video_frame, |
241 bitrate))) { | 240 bitrate))) { |
242 TRACE_EVENT_ASYNC_BEGIN1("cast.stream", "Video Encode", video_frame.get(), | 241 TRACE_EVENT_ASYNC_BEGIN1("cast.stream", "Video Encode", video_frame.get(), |
243 "rtp_timestamp", rtp_timestamp); | 242 "rtp_timestamp", rtp_timestamp.lower_32_bits()); |
244 frames_in_encoder_++; | 243 frames_in_encoder_++; |
245 duration_in_encoder_ += duration_added_by_next_frame; | 244 duration_in_encoder_ += duration_added_by_next_frame; |
246 last_enqueued_frame_rtp_timestamp_ = rtp_timestamp; | 245 last_enqueued_frame_rtp_timestamp_ = rtp_timestamp; |
247 last_enqueued_frame_reference_time_ = reference_time; | 246 last_enqueued_frame_reference_time_ = reference_time; |
248 } else { | 247 } else { |
249 VLOG(1) << "Encoder rejected a frame. Skipping..."; | 248 VLOG(1) << "Encoder rejected a frame. Skipping..."; |
250 TRACE_EVENT_INSTANT1("cast.stream", "Video Encode Reject", | 249 TRACE_EVENT_INSTANT1("cast.stream", "Video Encode Reject", |
251 TRACE_EVENT_SCOPE_THREAD, | 250 TRACE_EVENT_SCOPE_THREAD, |
252 "rtp_timestamp", rtp_timestamp); | 251 "rtp_timestamp", rtp_timestamp.lower_32_bits()); |
253 } | 252 } |
254 } | 253 } |
255 | 254 |
256 scoped_ptr<VideoFrameFactory> VideoSender::CreateVideoFrameFactory() { | 255 scoped_ptr<VideoFrameFactory> VideoSender::CreateVideoFrameFactory() { |
257 return video_encoder_ ? video_encoder_->CreateVideoFrameFactory() : nullptr; | 256 return video_encoder_ ? video_encoder_->CreateVideoFrameFactory() : nullptr; |
258 } | 257 } |
259 | 258 |
260 int VideoSender::GetNumberOfFramesInEncoder() const { | 259 int VideoSender::GetNumberOfFramesInEncoder() const { |
261 return frames_in_encoder_; | 260 return frames_in_encoder_; |
262 } | 261 } |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 media::VideoFrameMetadata::RESOURCE_UTILIZATION, | 355 media::VideoFrameMetadata::RESOURCE_UTILIZATION, |
357 encoded_frame->dependency == EncodedFrame::KEY ? | 356 encoded_frame->dependency == EncodedFrame::KEY ? |
358 std::min(1.0, attenuated_utilization) : attenuated_utilization); | 357 std::min(1.0, attenuated_utilization) : attenuated_utilization); |
359 } | 358 } |
360 | 359 |
361 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); | 360 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); |
362 } | 361 } |
363 | 362 |
364 } // namespace cast | 363 } // namespace cast |
365 } // namespace media | 364 } // namespace media |
OLD | NEW |