| 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/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/message_loop/message_loop.h" | |
| 13 #include "base/trace_event/trace_event.h" | 12 #include "base/trace_event/trace_event.h" |
| 14 #include "media/cast/cast_defines.h" | 13 #include "media/cast/cast_defines.h" |
| 15 #include "media/cast/net/cast_transport_config.h" | 14 #include "media/cast/net/cast_transport_config.h" |
| 16 #include "media/cast/sender/external_video_encoder.h" | 15 #include "media/cast/sender/external_video_encoder.h" |
| 17 #include "media/cast/sender/video_encoder_impl.h" | 16 #include "media/cast/sender/video_encoder_impl.h" |
| 18 #include "media/cast/sender/video_frame_factory.h" | 17 #include "media/cast/sender/video_frame_factory.h" |
| 19 | 18 |
| 20 #if defined(OS_MACOSX) | 19 #if defined(OS_MACOSX) |
| 21 #include "media/cast/sender/h264_vt_encoder.h" | 20 #include "media/cast/sender/h264_vt_encoder.h" |
| 22 #endif | 21 #endif |
| (...skipping 16 matching lines...) Expand all Loading... |
| 39 | 38 |
| 40 } // namespace | 39 } // namespace |
| 41 | 40 |
| 42 // Note, we use a fixed bitrate value when external video encoder is used. | 41 // Note, we use a fixed bitrate value when external video encoder is used. |
| 43 // Some hardware encoder shows bad behavior if we set the bitrate too | 42 // Some hardware encoder shows bad behavior if we set the bitrate too |
| 44 // frequently, e.g. quality drop, not abiding by target bitrate, etc. | 43 // frequently, e.g. quality drop, not abiding by target bitrate, etc. |
| 45 // See details: crbug.com/392086. | 44 // See details: crbug.com/392086. |
| 46 VideoSender::VideoSender( | 45 VideoSender::VideoSender( |
| 47 scoped_refptr<CastEnvironment> cast_environment, | 46 scoped_refptr<CastEnvironment> cast_environment, |
| 48 const VideoSenderConfig& video_config, | 47 const VideoSenderConfig& video_config, |
| 49 const CastInitializationCallback& initialization_cb, | 48 const StatusChangeCallback& status_change_cb, |
| 50 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, | 49 const CreateVideoEncodeAcceleratorCallback& create_vea_cb, |
| 51 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, | 50 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, |
| 52 CastTransportSender* const transport_sender, | 51 CastTransportSender* const transport_sender, |
| 53 const PlayoutDelayChangeCB& playout_delay_change_cb) | 52 const PlayoutDelayChangeCB& playout_delay_change_cb) |
| 54 : FrameSender( | 53 : FrameSender( |
| 55 cast_environment, | 54 cast_environment, |
| 56 false, | 55 false, |
| 57 transport_sender, | 56 transport_sender, |
| 58 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval), | 57 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval), |
| 59 kVideoFrequency, | 58 kVideoFrequency, |
| 60 video_config.ssrc, | 59 video_config.ssrc, |
| 61 video_config.max_frame_rate, | 60 video_config.max_frame_rate, |
| 62 video_config.min_playout_delay, | 61 video_config.min_playout_delay, |
| 63 video_config.max_playout_delay, | 62 video_config.max_playout_delay, |
| 64 video_config.use_external_encoder ? | 63 video_config.use_external_encoder ? |
| 65 NewFixedCongestionControl( | 64 NewFixedCongestionControl( |
| 66 (video_config.min_bitrate + video_config.max_bitrate) / 2) : | 65 (video_config.min_bitrate + video_config.max_bitrate) / 2) : |
| 67 NewAdaptiveCongestionControl(cast_environment->Clock(), | 66 NewAdaptiveCongestionControl(cast_environment->Clock(), |
| 68 video_config.max_bitrate, | 67 video_config.max_bitrate, |
| 69 video_config.min_bitrate, | 68 video_config.min_bitrate, |
| 70 video_config.max_frame_rate)), | 69 video_config.max_frame_rate)), |
| 71 frames_in_encoder_(0), | 70 frames_in_encoder_(0), |
| 72 last_bitrate_(0), | 71 last_bitrate_(0), |
| 73 playout_delay_change_cb_(playout_delay_change_cb), | 72 playout_delay_change_cb_(playout_delay_change_cb), |
| 74 weak_factory_(this) { | 73 weak_factory_(this) { |
| 75 cast_initialization_status_ = STATUS_VIDEO_UNINITIALIZED; | |
| 76 | |
| 77 #if defined(OS_MACOSX) | 74 #if defined(OS_MACOSX) |
| 78 // On Apple platforms, use the hardware H.264 encoder if possible. It is the | 75 // On Apple platforms, use the hardware H.264 encoder if possible. It is the |
| 79 // only reasonable option for iOS. | 76 // only reasonable option for iOS. |
| 80 if (!video_config.use_external_encoder && | 77 if (!video_config.use_external_encoder && |
| 81 video_config.codec == CODEC_VIDEO_H264) { | 78 video_config.codec == CODEC_VIDEO_H264) { |
| 82 video_encoder_.reset(new H264VideoToolboxEncoder( | 79 video_encoder_.reset(new H264VideoToolboxEncoder( |
| 83 cast_environment, | 80 cast_environment, |
| 84 video_config, | 81 video_config, |
| 85 gfx::Size(video_config.width, video_config.height), | 82 gfx::Size(video_config.width, video_config.height), |
| 86 base::Bind(&VideoSender::OnEncoderInitialized, | 83 status_change_cb)); |
| 87 weak_factory_.GetWeakPtr(), | |
| 88 initialization_cb))); | |
| 89 } | 84 } |
| 90 #endif // defined(OS_MACOSX) | 85 #endif // defined(OS_MACOSX) |
| 91 #if !defined(OS_IOS) | 86 #if !defined(OS_IOS) |
| 92 if (video_config.use_external_encoder) { | 87 if (video_config.use_external_encoder) { |
| 93 video_encoder_.reset(new ExternalVideoEncoder( | 88 video_encoder_.reset(new ExternalVideoEncoder( |
| 94 cast_environment, | 89 cast_environment, |
| 95 video_config, | 90 video_config, |
| 96 gfx::Size(video_config.width, video_config.height), | 91 gfx::Size(video_config.width, video_config.height), |
| 97 base::Bind(&VideoSender::OnEncoderInitialized, | 92 status_change_cb, |
| 98 weak_factory_.GetWeakPtr(), initialization_cb), | |
| 99 create_vea_cb, | 93 create_vea_cb, |
| 100 create_video_encode_mem_cb)); | 94 create_video_encode_mem_cb)); |
| 101 } else if (!video_encoder_) { | 95 } else if (!video_encoder_) { |
| 102 // Software encoder is initialized immediately. | 96 // Software encoder is initialized immediately. |
| 103 video_encoder_.reset(new VideoEncoderImpl( | 97 video_encoder_.reset(new VideoEncoderImpl( |
| 104 cast_environment, video_config, initialization_cb)); | 98 cast_environment, video_config, status_change_cb)); |
| 105 cast_initialization_status_ = STATUS_VIDEO_INITIALIZED; | |
| 106 } | 99 } |
| 107 #endif // !defined(OS_IOS) | 100 #endif // !defined(OS_IOS) |
| 108 | 101 |
| 102 if (!video_encoder_) { |
| 103 cast_environment_->PostTask( |
| 104 CastEnvironment::MAIN, |
| 105 FROM_HERE, |
| 106 base::Bind(status_change_cb, STATUS_UNSUPPORTED_CODEC)); |
| 107 } |
| 108 |
| 109 media::cast::CastTransportRtpConfig transport_config; | 109 media::cast::CastTransportRtpConfig transport_config; |
| 110 transport_config.ssrc = video_config.ssrc; | 110 transport_config.ssrc = video_config.ssrc; |
| 111 transport_config.feedback_ssrc = video_config.receiver_ssrc; | 111 transport_config.feedback_ssrc = video_config.receiver_ssrc; |
| 112 transport_config.rtp_payload_type = video_config.rtp_payload_type; | 112 transport_config.rtp_payload_type = video_config.rtp_payload_type; |
| 113 transport_config.aes_key = video_config.aes_key; | 113 transport_config.aes_key = video_config.aes_key; |
| 114 transport_config.aes_iv_mask = video_config.aes_iv_mask; | 114 transport_config.aes_iv_mask = video_config.aes_iv_mask; |
| 115 | 115 |
| 116 transport_sender->InitializeVideo( | 116 transport_sender->InitializeVideo( |
| 117 transport_config, | 117 transport_config, |
| 118 base::Bind(&VideoSender::OnReceivedCastFeedback, | 118 base::Bind(&VideoSender::OnReceivedCastFeedback, |
| 119 weak_factory_.GetWeakPtr()), | 119 weak_factory_.GetWeakPtr()), |
| 120 base::Bind(&VideoSender::OnMeasuredRoundTripTime, | 120 base::Bind(&VideoSender::OnMeasuredRoundTripTime, |
| 121 weak_factory_.GetWeakPtr())); | 121 weak_factory_.GetWeakPtr())); |
| 122 } | 122 } |
| 123 | 123 |
| 124 VideoSender::~VideoSender() { | 124 VideoSender::~VideoSender() { |
| 125 } | 125 } |
| 126 | 126 |
| 127 void VideoSender::InsertRawVideoFrame( | 127 void VideoSender::InsertRawVideoFrame( |
| 128 const scoped_refptr<media::VideoFrame>& video_frame, | 128 const scoped_refptr<media::VideoFrame>& video_frame, |
| 129 const base::TimeTicks& reference_time) { | 129 const base::TimeTicks& reference_time) { |
| 130 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 130 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 131 if (cast_initialization_status_ != STATUS_VIDEO_INITIALIZED) { | 131 |
| 132 if (!video_encoder_) { |
| 132 NOTREACHED(); | 133 NOTREACHED(); |
| 133 return; | 134 return; |
| 134 } | 135 } |
| 135 DCHECK(video_encoder_.get()) << "Invalid state"; | |
| 136 | 136 |
| 137 const RtpTimestamp rtp_timestamp = | 137 const RtpTimestamp rtp_timestamp = |
| 138 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency); | 138 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency); |
| 139 const base::TimeTicks insertion_time = cast_environment_->Clock()->NowTicks(); | 139 const base::TimeTicks insertion_time = cast_environment_->Clock()->NowTicks(); |
| 140 // TODO(miu): Plumb in capture timestamps. For now, make it look like capture | 140 // TODO(miu): Plumb in capture timestamps. For now, make it look like capture |
| 141 // took zero time by setting the BEGIN and END event to the same timestamp. | 141 // took zero time by setting the BEGIN and END event to the same timestamp. |
| 142 cast_environment_->Logging()->InsertFrameEvent( | 142 cast_environment_->Logging()->InsertFrameEvent( |
| 143 insertion_time, FRAME_CAPTURE_BEGIN, VIDEO_EVENT, rtp_timestamp, | 143 insertion_time, FRAME_CAPTURE_BEGIN, VIDEO_EVENT, rtp_timestamp, |
| 144 kFrameIdUnknown); | 144 kFrameIdUnknown); |
| 145 cast_environment_->Logging()->InsertFrameEvent( | 145 cast_environment_->Logging()->InsertFrameEvent( |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 frames_in_encoder_++; | 211 frames_in_encoder_++; |
| 212 duration_in_encoder_ += duration_added_by_next_frame; | 212 duration_in_encoder_ += duration_added_by_next_frame; |
| 213 last_enqueued_frame_rtp_timestamp_ = rtp_timestamp; | 213 last_enqueued_frame_rtp_timestamp_ = rtp_timestamp; |
| 214 last_enqueued_frame_reference_time_ = reference_time; | 214 last_enqueued_frame_reference_time_ = reference_time; |
| 215 } else { | 215 } else { |
| 216 VLOG(1) << "Encoder rejected a frame. Skipping..."; | 216 VLOG(1) << "Encoder rejected a frame. Skipping..."; |
| 217 } | 217 } |
| 218 } | 218 } |
| 219 | 219 |
| 220 scoped_ptr<VideoFrameFactory> VideoSender::CreateVideoFrameFactory() { | 220 scoped_ptr<VideoFrameFactory> VideoSender::CreateVideoFrameFactory() { |
| 221 DCHECK(cast_initialization_status_ == STATUS_VIDEO_INITIALIZED); | 221 return video_encoder_ ? video_encoder_->CreateVideoFrameFactory() : nullptr; |
| 222 DCHECK(video_encoder_.get()) << "Invalid state"; | |
| 223 return video_encoder_->CreateVideoFrameFactory(); | |
| 224 } | 222 } |
| 225 | 223 |
| 226 int VideoSender::GetNumberOfFramesInEncoder() const { | 224 int VideoSender::GetNumberOfFramesInEncoder() const { |
| 227 return frames_in_encoder_; | 225 return frames_in_encoder_; |
| 228 } | 226 } |
| 229 | 227 |
| 230 base::TimeDelta VideoSender::GetInFlightMediaDuration() const { | 228 base::TimeDelta VideoSender::GetInFlightMediaDuration() const { |
| 231 if (GetUnacknowledgedFrameCount() > 0) { | 229 if (GetUnacknowledgedFrameCount() > 0) { |
| 232 const uint32 oldest_unacked_frame_id = latest_acked_frame_id_ + 1; | 230 const uint32 oldest_unacked_frame_id = latest_acked_frame_id_ + 1; |
| 233 return last_enqueued_frame_reference_time_ - | 231 return last_enqueued_frame_reference_time_ - |
| 234 GetRecordedReferenceTime(oldest_unacked_frame_id); | 232 GetRecordedReferenceTime(oldest_unacked_frame_id); |
| 235 } else { | 233 } else { |
| 236 return duration_in_encoder_; | 234 return duration_in_encoder_; |
| 237 } | 235 } |
| 238 } | 236 } |
| 239 | 237 |
| 240 void VideoSender::OnAck(uint32 frame_id) { | 238 void VideoSender::OnAck(uint32 frame_id) { |
| 241 video_encoder_->LatestFrameIdToReference(frame_id); | 239 video_encoder_->LatestFrameIdToReference(frame_id); |
| 242 } | 240 } |
| 243 | 241 |
| 244 void VideoSender::OnEncoderInitialized( | |
| 245 const CastInitializationCallback& initialization_cb, | |
| 246 CastInitializationStatus status) { | |
| 247 cast_initialization_status_ = status; | |
| 248 initialization_cb.Run(status); | |
| 249 } | |
| 250 | |
| 251 void VideoSender::OnEncodedVideoFrame( | 242 void VideoSender::OnEncodedVideoFrame( |
| 252 int encoder_bitrate, | 243 int encoder_bitrate, |
| 253 scoped_ptr<EncodedFrame> encoded_frame) { | 244 scoped_ptr<EncodedFrame> encoded_frame) { |
| 254 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 245 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 255 | 246 |
| 256 frames_in_encoder_--; | 247 frames_in_encoder_--; |
| 257 DCHECK_GE(frames_in_encoder_, 0); | 248 DCHECK_GE(frames_in_encoder_, 0); |
| 258 | 249 |
| 259 duration_in_encoder_ = | 250 duration_in_encoder_ = |
| 260 last_enqueued_frame_reference_time_ - encoded_frame->reference_time; | 251 last_enqueued_frame_reference_time_ - encoded_frame->reference_time; |
| 261 | 252 |
| 262 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); | 253 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass()); |
| 263 } | 254 } |
| 264 | 255 |
| 265 } // namespace cast | 256 } // namespace cast |
| 266 } // namespace media | 257 } // namespace media |
| OLD | NEW |