1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/cast/video_sender/video_sender.h"
10 #include "base/bind.h"
11 #include "base/debug/trace_event.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "media/cast/cast_defines.h"
15 #include "media/cast/rtcp/rtcp_defines.h"
16 #include "media/cast/rtcp/sender_rtcp_event_subscriber.h"
17 #include "media/cast/transport/cast_transport_config.h"
18 #include "media/cast/video_sender/external_video_encoder.h"
19 #include "media/cast/video_sender/video_encoder_impl.h"
24 const int64 kMinSchedulingDelayMs
= 1;
26 // This is the maxmimum number of sender frame log messages that can fit in a
27 // single RTCP packet.
28 const int64 kMaxEventSubscriberEntries
=
29 (kMaxIpPacketSize
- kRtcpCastLogHeaderSize
) / kRtcpSenderFrameLogSize
;
31 class LocalRtcpVideoSenderFeedback
: public RtcpSenderFeedback
{
33 explicit LocalRtcpVideoSenderFeedback(VideoSender
* video_sender
)
34 : video_sender_(video_sender
) {}
36 virtual void OnReceivedCastFeedback(const RtcpCastMessage
& cast_feedback
)
38 video_sender_
->OnReceivedCastFeedback(cast_feedback
);
42 VideoSender
* video_sender_
;
44 DISALLOW_IMPLICIT_CONSTRUCTORS(LocalRtcpVideoSenderFeedback
);
47 VideoSender::VideoSender(
48 scoped_refptr
<CastEnvironment
> cast_environment
,
49 const VideoSenderConfig
& video_config
,
50 const CreateVideoEncodeAcceleratorCallback
& create_vea_cb
,
51 const CreateVideoEncodeMemoryCallback
& create_video_encode_mem_cb
,
52 const CastInitializationCallback
& cast_initialization_cb
,
53 transport::CastTransportSender
* const transport_sender
)
54 : rtp_max_delay_(base::TimeDelta::FromMilliseconds(
55 video_config
.rtp_config
.max_delay_ms
)),
56 max_frame_rate_(video_config
.max_frame_rate
),
57 cast_environment_(cast_environment
),
58 transport_sender_(transport_sender
),
59 event_subscriber_(kMaxEventSubscriberEntries
),
60 rtp_stats_(kVideoFrequency
),
61 rtcp_feedback_(new LocalRtcpVideoSenderFeedback(this)),
62 last_acked_frame_id_(-1),
63 last_sent_frame_id_(-1),
64 frames_in_encoder_(0),
67 current_requested_bitrate_(video_config
.start_bitrate
),
68 congestion_control_(cast_environment
->Clock(),
69 video_config
.congestion_control_back_off
,
70 video_config
.max_bitrate
,
71 video_config
.min_bitrate
,
72 video_config
.start_bitrate
),
74 active_session_(false),
77 1 + static_cast<uint8
>(video_config
.rtp_config
.max_delay_ms
*
78 max_frame_rate_
/ 1000);
79 VLOG(1) << "max_unacked_frames " << static_cast<int>(max_unacked_frames_
);
80 DCHECK_GT(max_unacked_frames_
, 0) << "Invalid argument";
82 if (video_config
.use_external_encoder
) {
83 video_encoder_
.reset(new ExternalVideoEncoder(cast_environment
,
86 create_video_encode_mem_cb
));
88 video_encoder_
.reset(new VideoEncoderImpl(
89 cast_environment
, video_config
, max_unacked_frames_
));
93 media::cast::transport::CastTransportVideoConfig transport_config
;
94 transport_config
.codec
= video_config
.codec
;
95 transport_config
.rtp
.config
= video_config
.rtp_config
;
96 transport_config
.rtp
.max_outstanding_frames
= max_unacked_frames_
+ 1;
97 transport_sender_
->InitializeVideo(transport_config
);
100 new Rtcp(cast_environment_
,
101 rtcp_feedback_
.get(),
103 NULL
, // paced sender.
105 video_config
.rtcp_mode
,
106 base::TimeDelta::FromMilliseconds(video_config
.rtcp_interval
),
107 video_config
.rtp_config
.ssrc
,
108 video_config
.incoming_feedback_ssrc
,
109 video_config
.rtcp_c_name
));
110 rtcp_
->SetCastReceiverEventHistorySize(kReceiverRtcpEventHistorySize
);
112 // TODO(pwestin): pass cast_initialization_cb to |video_encoder_|
113 // and remove this call.
114 cast_environment_
->PostTask(
115 CastEnvironment::MAIN
,
117 base::Bind(cast_initialization_cb
, STATUS_VIDEO_INITIALIZED
));
118 cast_environment_
->Logging()->AddRawEventSubscriber(&event_subscriber_
);
120 memset(frame_id_to_rtp_timestamp_
, 0, sizeof(frame_id_to_rtp_timestamp_
));
122 transport_sender_
->SubscribeVideoRtpStatsCallback(
123 base::Bind(&VideoSender::StoreStatistics
, weak_factory_
.GetWeakPtr()));
126 VideoSender::~VideoSender() {
127 cast_environment_
->Logging()->RemoveRawEventSubscriber(&event_subscriber_
);
130 void VideoSender::InitializeTimers() {
131 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
134 ScheduleNextResendCheck();
135 ScheduleNextSkippedFramesCheck();
139 void VideoSender::InsertRawVideoFrame(
140 const scoped_refptr
<media::VideoFrame
>& video_frame
,
141 const base::TimeTicks
& capture_time
) {
142 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
143 DCHECK(video_encoder_
.get()) << "Invalid state";
145 RtpTimestamp rtp_timestamp
= GetVideoRtpTimestamp(capture_time
);
146 cast_environment_
->Logging()->InsertFrameEvent(
147 capture_time
, kVideoFrameCaptureBegin
, rtp_timestamp
, kFrameIdUnknown
);
148 cast_environment_
->Logging()->InsertFrameEvent(
149 cast_environment_
->Clock()->NowTicks(),
150 kVideoFrameCaptureEnd
,
154 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
155 TRACE_EVENT_INSTANT2(
156 "cast_perf_test", "InsertRawVideoFrame",
157 TRACE_EVENT_SCOPE_THREAD
,
158 "timestamp", capture_time
.ToInternalValue(),
159 "rtp_timestamp", GetVideoRtpTimestamp(capture_time
));
161 if (video_encoder_
->EncodeVideoFrame(
164 base::Bind(&VideoSender::SendEncodedVideoFrameMainThread
,
165 weak_factory_
.GetWeakPtr()))) {
166 frames_in_encoder_
++;
167 UpdateFramesInFlight();
171 void VideoSender::SendEncodedVideoFrameMainThread(
172 scoped_ptr
<transport::EncodedVideoFrame
> encoded_frame
,
173 const base::TimeTicks
& capture_time
) {
174 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
175 last_send_time_
= cast_environment_
->Clock()->NowTicks();
176 if (encoded_frame
->key_frame
) {
177 VLOG(1) << "Send encoded key frame; frame_id:"
178 << static_cast<int>(encoded_frame
->frame_id
);
181 DCHECK_GT(frames_in_encoder_
, 0);
182 frames_in_encoder_
--;
183 uint32 frame_id
= encoded_frame
->frame_id
;
184 cast_environment_
->Logging()->InsertEncodedFrameEvent(
185 last_send_time_
, kVideoFrameEncoded
, encoded_frame
->rtp_timestamp
,
186 frame_id
, static_cast<int>(encoded_frame
->data
.size()),
187 encoded_frame
->key_frame
, current_requested_bitrate_
);
189 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
190 TRACE_EVENT_INSTANT1(
191 "cast_perf_test", "VideoFrameEncoded",
192 TRACE_EVENT_SCOPE_THREAD
,
193 "rtp_timestamp", GetVideoRtpTimestamp(capture_time
));
195 // Only use lowest 8 bits as key.
196 frame_id_to_rtp_timestamp_
[frame_id
& 0xff] = encoded_frame
->rtp_timestamp
;
198 last_sent_frame_id_
= static_cast<int>(encoded_frame
->frame_id
);
199 transport_sender_
->InsertCodedVideoFrame(encoded_frame
.get(), capture_time
);
200 UpdateFramesInFlight();
204 void VideoSender::IncomingRtcpPacket(scoped_ptr
<Packet
> packet
) {
205 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
206 rtcp_
->IncomingRtcpPacket(&packet
->front(), packet
->size());
209 void VideoSender::ScheduleNextRtcpReport() {
210 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
211 base::TimeDelta time_to_next
= rtcp_
->TimeToSendNextRtcpReport() -
212 cast_environment_
->Clock()->NowTicks();
214 time_to_next
= std::max(
215 time_to_next
, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs
));
217 cast_environment_
->PostDelayedTask(
218 CastEnvironment::MAIN
,
220 base::Bind(&VideoSender::SendRtcpReport
, weak_factory_
.GetWeakPtr()),
224 void VideoSender::StoreStatistics(
225 const transport::RtcpSenderInfo
& sender_info
,
226 base::TimeTicks time_sent
,
227 uint32 rtp_timestamp
) {
228 rtp_stats_
.Store(sender_info
, time_sent
, rtp_timestamp
);
231 void VideoSender::SendRtcpReport() {
232 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
234 transport::RtcpSenderLogMessage sender_log_message
;
235 RtcpEventMap rtcp_events
;
236 event_subscriber_
.GetRtcpEventsAndReset(&rtcp_events
);
238 for (RtcpEventMap::iterator it
= rtcp_events
.begin(); it
!= rtcp_events
.end();
240 CastLoggingEvent event_type
= it
->second
.type
;
241 if (event_type
== kVideoFrameCaptureBegin
||
242 event_type
== kVideoFrameSentToEncoder
||
243 event_type
== kVideoFrameEncoded
) {
244 transport::RtcpSenderFrameLogMessage frame_message
;
245 frame_message
.rtp_timestamp
= it
->first
;
246 switch (event_type
) {
247 case kVideoFrameCaptureBegin
:
248 frame_message
.frame_status
=
249 transport::kRtcpSenderFrameStatusDroppedByFlowControl
;
251 case kVideoFrameSentToEncoder
:
252 frame_message
.frame_status
=
253 transport::kRtcpSenderFrameStatusDroppedByEncoder
;
255 case kVideoFrameEncoded
:
256 frame_message
.frame_status
=
257 transport::kRtcpSenderFrameStatusSentToNetwork
;
263 sender_log_message
.push_back(frame_message
);
265 // This shouldn't happen because RtcpEventMap isn't supposed to contain
266 // other event types.
267 NOTREACHED() << "Got unknown event type in RtcpEventMap: " << event_type
;
271 rtp_stats_
.UpdateInfo(cast_environment_
->Clock()->NowTicks());
273 rtcp_
->SendRtcpFromRtpSender(sender_log_message
, rtp_stats_
.sender_info());
274 if (!sender_log_message
.empty()) {
275 VLOG(1) << "Failed to send all log messages";
277 ScheduleNextRtcpReport();
280 void VideoSender::ScheduleNextResendCheck() {
281 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
282 base::TimeDelta time_to_next
;
283 if (last_send_time_
.is_null()) {
284 time_to_next
= rtp_max_delay_
;
286 time_to_next
= last_send_time_
- cast_environment_
->Clock()->NowTicks() +
289 time_to_next
= std::max(
290 time_to_next
, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs
));
292 cast_environment_
->PostDelayedTask(
293 CastEnvironment::MAIN
,
295 base::Bind(&VideoSender::ResendCheck
, weak_factory_
.GetWeakPtr()),
299 void VideoSender::ResendCheck() {
300 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
301 if (!last_send_time_
.is_null() && last_sent_frame_id_
!= -1) {
302 base::TimeDelta time_since_last_send
=
303 cast_environment_
->Clock()->NowTicks() - last_send_time_
;
304 if (time_since_last_send
> rtp_max_delay_
) {
305 if (!active_session_
) {
306 // We have not received any acks, resend the first encoded frame (id 0),
307 // which must also be a key frame.
308 VLOG(1) << "ACK timeout resend first key frame";
311 if (last_acked_frame_id_
== last_sent_frame_id_
) {
312 // Last frame acked, no point in doing anything
314 DCHECK_LE(0, last_acked_frame_id_
);
315 uint32 frame_id
= static_cast<uint32
>(last_acked_frame_id_
+ 1);
316 VLOG(1) << "ACK timeout resend frame:" << static_cast<int>(frame_id
);
317 ResendFrame(frame_id
);
322 ScheduleNextResendCheck();
325 void VideoSender::ScheduleNextSkippedFramesCheck() {
326 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
327 base::TimeDelta time_to_next
;
328 if (last_checked_skip_count_time_
.is_null()) {
330 base::TimeDelta::FromMilliseconds(kSkippedFramesCheckPeriodkMs
);
333 last_checked_skip_count_time_
- cast_environment_
->Clock()->NowTicks() +
334 base::TimeDelta::FromMilliseconds(kSkippedFramesCheckPeriodkMs
);
336 time_to_next
= std::max(
337 time_to_next
, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs
));
339 cast_environment_
->PostDelayedTask(
340 CastEnvironment::MAIN
,
342 base::Bind(&VideoSender::SkippedFramesCheck
, weak_factory_
.GetWeakPtr()),
346 void VideoSender::SkippedFramesCheck() {
347 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
348 int skip_count
= video_encoder_
->NumberOfSkippedFrames();
349 if (skip_count
- last_skip_count_
>
350 kSkippedFramesThreshold
* max_frame_rate_
) {
351 // TODO(pwestin): Propagate this up to the application.
353 last_skip_count_
= skip_count
;
354 last_checked_skip_count_time_
= cast_environment_
->Clock()->NowTicks();
355 ScheduleNextSkippedFramesCheck();
358 void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage
& cast_feedback
) {
359 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
361 base::TimeDelta avg_rtt
;
362 base::TimeDelta min_rtt
;
363 base::TimeDelta max_rtt
;
365 // Update delay and max number of frames in flight based on the the new
366 // received target delay.
368 base::TimeDelta::FromMilliseconds(cast_feedback
.target_delay_ms_
);
369 max_unacked_frames_
= 1 + static_cast<uint8
>(cast_feedback
.target_delay_ms_
*
370 max_frame_rate_
/ 1000);
371 if (rtcp_
->Rtt(&rtt
, &avg_rtt
, &min_rtt
, &max_rtt
)) {
372 // Don't use a RTT lower than our average.
373 rtt
= std::max(rtt
, avg_rtt
);
375 // We have no measured value use default.
376 rtt
= base::TimeDelta::FromMilliseconds(kStartRttMs
);
378 if (cast_feedback
.missing_frames_and_packets_
.empty()) {
380 int resend_frame
= -1;
381 if (last_sent_frame_id_
== -1)
384 video_encoder_
->LatestFrameIdToReference(cast_feedback
.ack_frame_id_
);
386 if (static_cast<uint32
>(last_acked_frame_id_
+ 1) ==
387 cast_feedback
.ack_frame_id_
) {
388 uint32 new_bitrate
= 0;
389 if (congestion_control_
.OnAck(rtt
, &new_bitrate
)) {
390 video_encoder_
->SetBitRate(new_bitrate
);
391 current_requested_bitrate_
= new_bitrate
;
394 // We only count duplicate ACKs when we have sent newer frames.
395 if (static_cast<uint32
>(last_acked_frame_id_
) ==
396 cast_feedback
.ack_frame_id_
&&
397 IsNewerFrameId(last_sent_frame_id_
, last_acked_frame_id_
)) {
402 if (duplicate_ack_
>= 2 && duplicate_ack_
% 3 == 2) {
403 // Resend last ACK + 1 frame.
404 resend_frame
= static_cast<uint32
>(last_acked_frame_id_
+ 1);
406 if (resend_frame
!= -1) {
407 DCHECK_LE(0, resend_frame
);
408 VLOG(1) << "Received duplicate ACK for frame:"
409 << static_cast<int>(resend_frame
);
410 ResendFrame(static_cast<uint32
>(resend_frame
));
413 transport_sender_
->ResendPackets(
414 false, cast_feedback
.missing_frames_and_packets_
);
415 uint32 new_bitrate
= 0;
416 if (congestion_control_
.OnNack(rtt
, &new_bitrate
)) {
417 video_encoder_
->SetBitRate(new_bitrate
);
418 current_requested_bitrate_
= new_bitrate
;
421 ReceivedAck(cast_feedback
.ack_frame_id_
);
424 void VideoSender::ReceivedAck(uint32 acked_frame_id
) {
425 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
426 if (acked_frame_id
== UINT32_C(0xFFFFFFFF)) {
427 // Receiver is sending a status message before any frames are ready to
431 // Start sending RTCP packets only after receiving the first ACK, i.e. only
432 // after establishing that the receiver is active.
433 if (last_acked_frame_id_
== -1) {
434 ScheduleNextRtcpReport();
436 last_acked_frame_id_
= static_cast<int>(acked_frame_id
);
437 base::TimeTicks now
= cast_environment_
->Clock()->NowTicks();
439 RtpTimestamp rtp_timestamp
=
440 frame_id_to_rtp_timestamp_
[acked_frame_id
& 0xff];
441 cast_environment_
->Logging()->InsertFrameEvent(
442 now
, kVideoAckReceived
, rtp_timestamp
, acked_frame_id
);
444 VLOG(2) << "ReceivedAck:" << static_cast<int>(acked_frame_id
);
445 active_session_
= true;
446 DCHECK_NE(-1, last_acked_frame_id_
);
447 UpdateFramesInFlight();
450 void VideoSender::UpdateFramesInFlight() {
451 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
452 if (last_sent_frame_id_
!= -1) {
453 DCHECK_LE(0, last_sent_frame_id_
);
454 uint32 frames_in_flight
= 0;
455 if (last_acked_frame_id_
!= -1) {
456 DCHECK_LE(0, last_acked_frame_id_
);
457 frames_in_flight
= static_cast<uint32
>(last_sent_frame_id_
) -
458 static_cast<uint32
>(last_acked_frame_id_
);
460 frames_in_flight
= static_cast<uint32
>(last_sent_frame_id_
) + 1;
462 frames_in_flight
+= frames_in_encoder_
;
463 VLOG(2) << frames_in_flight
464 << " Frames in flight; last sent: " << last_sent_frame_id_
465 << " last acked:" << last_acked_frame_id_
466 << " frames in encoder: " << frames_in_encoder_
;
467 if (frames_in_flight
>= max_unacked_frames_
) {
468 video_encoder_
->SkipNextFrame(true);
471 DCHECK(frames_in_flight
<= max_unacked_frames_
);
473 video_encoder_
->SkipNextFrame(false);
476 void VideoSender::ResendFrame(uint32 resend_frame_id
) {
477 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
478 MissingFramesAndPacketsMap missing_frames_and_packets
;
480 missing_frames_and_packets
.insert(std::make_pair(resend_frame_id
, missing
));
481 last_send_time_
= cast_environment_
->Clock()->NowTicks();
482 transport_sender_
->ResendPackets(false, missing_frames_and_packets
);