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 |