| 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 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 void VideoSender::InsertRawVideoFrame( | 144 void VideoSender::InsertRawVideoFrame( |
| 145 const scoped_refptr<media::VideoFrame>& video_frame, | 145 const scoped_refptr<media::VideoFrame>& video_frame, |
| 146 const base::TimeTicks& reference_time) { | 146 const base::TimeTicks& reference_time) { |
| 147 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 147 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 148 | 148 |
| 149 if (!video_encoder_) { | 149 if (!video_encoder_) { |
| 150 NOTREACHED(); | 150 NOTREACHED(); |
| 151 return; | 151 return; |
| 152 } | 152 } |
| 153 | 153 |
| 154 const RtpTimestamp rtp_timestamp = | 154 const RtpTimeTicks rtp_timestamp = |
| 155 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency); | 155 RtpTimeTicks::FromTimeDelta(video_frame->timestamp(), kVideoFrequency); |
| 156 LogVideoCaptureTimestamps(cast_environment_.get(), *video_frame, | 156 LogVideoCaptureTimestamps(cast_environment_.get(), *video_frame, |
| 157 rtp_timestamp); | 157 rtp_timestamp); |
| 158 | 158 |
| 159 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc | 159 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc |
| 160 TRACE_EVENT_INSTANT2( | 160 TRACE_EVENT_INSTANT2( |
| 161 "cast_perf_test", "InsertRawVideoFrame", | 161 "cast_perf_test", "InsertRawVideoFrame", |
| 162 TRACE_EVENT_SCOPE_THREAD, | 162 TRACE_EVENT_SCOPE_THREAD, |
| 163 "timestamp", reference_time.ToInternalValue(), | 163 "timestamp", reference_time.ToInternalValue(), |
| 164 "rtp_timestamp", rtp_timestamp); | 164 "rtp_timestamp", rtp_timestamp.lower_32_bits()); |
| 165 | 165 |
| 166 bool low_latency_mode; | 166 bool low_latency_mode; |
| 167 if (video_frame->metadata()->GetBoolean( | 167 if (video_frame->metadata()->GetBoolean( |
| 168 VideoFrameMetadata::INTERACTIVE_CONTENT, &low_latency_mode)) { | 168 VideoFrameMetadata::INTERACTIVE_CONTENT, &low_latency_mode)) { |
| 169 if (low_latency_mode && !low_latency_mode_) { | 169 if (low_latency_mode && !low_latency_mode_) { |
| 170 VLOG(1) << "Interactive mode playout time " << min_playout_delay_; | 170 VLOG(1) << "Interactive mode playout time " << min_playout_delay_; |
| 171 playout_delay_change_cb_.Run(min_playout_delay_); | 171 playout_delay_change_cb_.Run(min_playout_delay_); |
| 172 } | 172 } |
| 173 low_latency_mode_ = low_latency_mode; | 173 low_latency_mode_ = low_latency_mode; |
| 174 } | 174 } |
| 175 | 175 |
| 176 // Drop the frame if either its RTP or reference timestamp is not an increase | 176 // Drop the frame if either its RTP or reference timestamp is not an increase |
| 177 // over the last frame's. This protects: 1) the duration calculations that | 177 // over the last frame's. This protects: 1) the duration calculations that |
| 178 // assume timestamps are monotonically non-decreasing, and 2) assumptions made | 178 // assume timestamps are monotonically non-decreasing, and 2) assumptions made |
| 179 // deeper in the implementation where each frame's RTP timestamp needs to be | 179 // deeper in the implementation where each frame's RTP timestamp needs to be |
| 180 // unique. | 180 // unique. |
| 181 if (!last_enqueued_frame_reference_time_.is_null() && | 181 if (!last_enqueued_frame_reference_time_.is_null() && |
| 182 (!IsNewerRtpTimestamp(rtp_timestamp, | 182 (rtp_timestamp <= last_enqueued_frame_rtp_timestamp_ || |
| 183 last_enqueued_frame_rtp_timestamp_) || | |
| 184 reference_time <= last_enqueued_frame_reference_time_)) { | 183 reference_time <= last_enqueued_frame_reference_time_)) { |
| 185 VLOG(1) << "Dropping video frame: RTP or reference time did not increase."; | 184 VLOG(1) << "Dropping video frame: RTP or reference time did not increase."; |
| 186 TRACE_EVENT_INSTANT2("cast.stream", "Video Frame Drop", | 185 TRACE_EVENT_INSTANT2("cast.stream", "Video Frame Drop", |
| 187 TRACE_EVENT_SCOPE_THREAD, | 186 TRACE_EVENT_SCOPE_THREAD, |
| 188 "rtp_timestamp", rtp_timestamp, | 187 "rtp_timestamp", rtp_timestamp.lower_32_bits(), |
| 189 "reason", "time did not increase"); | 188 "reason", "time did not increase"); |
| 190 return; | 189 return; |
| 191 } | 190 } |
| 192 | 191 |
| 193 // Two video frames are needed to compute the exact media duration added by | 192 // Two video frames are needed to compute the exact media duration added by |
| 194 // the next frame. If there are no frames in the encoder, compute a guess | 193 // the next frame. If there are no frames in the encoder, compute a guess |
| 195 // based on the configured |max_frame_rate_|. Any error introduced by this | 194 // based on the configured |max_frame_rate_|. Any error introduced by this |
| 196 // guess will be eliminated when |duration_in_encoder_| is updated in | 195 // guess will be eliminated when |duration_in_encoder_| is updated in |
| 197 // OnEncodedVideoFrame(). | 196 // OnEncodedVideoFrame(). |
| 198 const base::TimeDelta duration_added_by_next_frame = frames_in_encoder_ > 0 ? | 197 const base::TimeDelta duration_added_by_next_frame = frames_in_encoder_ > 0 ? |
| 199 reference_time - last_enqueued_frame_reference_time_ : | 198 reference_time - last_enqueued_frame_reference_time_ : |
| (...skipping 21 matching lines...) Expand all Loading... |
| 221 } | 220 } |
| 222 | 221 |
| 223 // Some encoder implementations have a frame window for analysis. Since we | 222 // Some encoder implementations have a frame window for analysis. Since we |
| 224 // are dropping this frame, unless we instruct the encoder to flush all the | 223 // are dropping this frame, unless we instruct the encoder to flush all the |
| 225 // frames that have been enqueued for encoding, frames_in_encoder_ and | 224 // frames that have been enqueued for encoding, frames_in_encoder_ and |
| 226 // last_enqueued_frame_reference_time_ will never be updated and we will | 225 // last_enqueued_frame_reference_time_ will never be updated and we will |
| 227 // drop every subsequent frame for the rest of the session. | 226 // drop every subsequent frame for the rest of the session. |
| 228 video_encoder_->EmitFrames(); | 227 video_encoder_->EmitFrames(); |
| 229 | 228 |
| 230 TRACE_EVENT_INSTANT2("cast.stream", "Video Frame Drop", | 229 TRACE_EVENT_INSTANT2("cast.stream", "Video Frame Drop", |
| 231 TRACE_EVENT_SCOPE_THREAD, | 230 TRACE_EVENT_SCOPE_THREAD, |
| 232 "rtp_timestamp", rtp_timestamp, | 231 "rtp_timestamp", rtp_timestamp.lower_32_bits(), |
| 233 "reason", "too much in flight"); | 232 "reason", "too much in flight"); |
| 234 return; | 233 return; |
| 235 } | 234 } |
| 236 | 235 |
| 237 if (video_frame->visible_rect().IsEmpty()) { | 236 if (video_frame->visible_rect().IsEmpty()) { |
| 238 VLOG(1) << "Rejecting empty video frame."; | 237 VLOG(1) << "Rejecting empty video frame."; |
| 239 return; | 238 return; |
| 240 } | 239 } |
| 241 | 240 |
| 242 const int bitrate = congestion_control_->GetBitrate( | 241 const int bitrate = congestion_control_->GetBitrate( |
| 243 reference_time + target_playout_delay_, target_playout_delay_, | 242 reference_time + target_playout_delay_, target_playout_delay_, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 256 video_frame.get()); | 255 video_frame.get()); |
| 257 | 256 |
| 258 if (video_encoder_->EncodeVideoFrame( | 257 if (video_encoder_->EncodeVideoFrame( |
| 259 video_frame, | 258 video_frame, |
| 260 reference_time, | 259 reference_time, |
| 261 base::Bind(&VideoSender::OnEncodedVideoFrame, | 260 base::Bind(&VideoSender::OnEncodedVideoFrame, |
| 262 weak_factory_.GetWeakPtr(), | 261 weak_factory_.GetWeakPtr(), |
| 263 video_frame, | 262 video_frame, |
| 264 bitrate))) { | 263 bitrate))) { |
| 265 TRACE_EVENT_ASYNC_BEGIN1("cast.stream", "Video Encode", video_frame.get(), | 264 TRACE_EVENT_ASYNC_BEGIN1("cast.stream", "Video Encode", video_frame.get(), |
| 266 "rtp_timestamp", rtp_timestamp); | 265 "rtp_timestamp", rtp_timestamp.lower_32_bits()); |
| 267 frames_in_encoder_++; | 266 frames_in_encoder_++; |
| 268 duration_in_encoder_ += duration_added_by_next_frame; | 267 duration_in_encoder_ += duration_added_by_next_frame; |
| 269 last_enqueued_frame_rtp_timestamp_ = rtp_timestamp; | 268 last_enqueued_frame_rtp_timestamp_ = rtp_timestamp; |
| 270 last_enqueued_frame_reference_time_ = reference_time; | 269 last_enqueued_frame_reference_time_ = reference_time; |
| 271 } else { | 270 } else { |
| 272 VLOG(1) << "Encoder rejected a frame. Skipping..."; | 271 VLOG(1) << "Encoder rejected a frame. Skipping..."; |
| 273 TRACE_EVENT_INSTANT1("cast.stream", "Video Encode Reject", | 272 TRACE_EVENT_INSTANT1("cast.stream", "Video Encode Reject", |
| 274 TRACE_EVENT_SCOPE_THREAD, | 273 TRACE_EVENT_SCOPE_THREAD, |
| 275 "rtp_timestamp", rtp_timestamp); | 274 "rtp_timestamp", rtp_timestamp.lower_32_bits()); |
| 276 } | 275 } |
| 277 } | 276 } |
| 278 | 277 |
| 279 scoped_ptr<VideoFrameFactory> VideoSender::CreateVideoFrameFactory() { | 278 scoped_ptr<VideoFrameFactory> VideoSender::CreateVideoFrameFactory() { |
| 280 return video_encoder_ ? video_encoder_->CreateVideoFrameFactory() : nullptr; | 279 return video_encoder_ ? video_encoder_->CreateVideoFrameFactory() : nullptr; |
| 281 } | 280 } |
| 282 | 281 |
| 283 int VideoSender::GetNumberOfFramesInEncoder() const { | 282 int VideoSender::GetNumberOfFramesInEncoder() const { |
| 284 return frames_in_encoder_; | 283 return frames_in_encoder_; |
| 285 } | 284 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 media::VideoFrameMetadata::RESOURCE_UTILIZATION, | 378 media::VideoFrameMetadata::RESOURCE_UTILIZATION, |
| 380 encoded_frame->dependency == EncodedFrame::KEY ? | 379 encoded_frame->dependency == EncodedFrame::KEY ? |
| 381 std::min(1.0, attenuated_utilization) : attenuated_utilization); | 380 std::min(1.0, attenuated_utilization) : attenuated_utilization); |
| 382 } | 381 } |
| 383 | 382 |
| 384 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); | 383 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); |
| 385 } | 384 } |
| 386 | 385 |
| 387 } // namespace cast | 386 } // namespace cast |
| 388 } // namespace media | 387 } // namespace media |
| OLD | NEW |