• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "media/cast/video_receiver/video_receiver.h"
6 
7 #include <algorithm>
8 
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "crypto/encryptor.h"
13 #include "crypto/symmetric_key.h"
14 #include "media/cast/cast_defines.h"
15 #include "media/cast/framer/framer.h"
16 #include "media/cast/video_receiver/video_decoder.h"
17 
18 namespace media {
19 namespace cast {
20 
21 const int64 kMinSchedulingDelayMs = 1;
22 
23 static const int64 kMinTimeBetweenOffsetUpdatesMs = 2000;
24 static const int kTimeOffsetFilter = 8;
25 static const int64_t kMinProcessIntervalMs = 5;
26 
27 // Local implementation of RtpData (defined in rtp_rtcp_defines.h).
28 // Used to pass payload data into the video receiver.
29 class LocalRtpVideoData : public RtpData {
30  public:
LocalRtpVideoData(VideoReceiver * video_receiver)31   explicit LocalRtpVideoData(VideoReceiver* video_receiver)
32       : video_receiver_(video_receiver) {}
33 
~LocalRtpVideoData()34   virtual ~LocalRtpVideoData() {}
35 
OnReceivedPayloadData(const uint8 * payload_data,size_t payload_size,const RtpCastHeader * rtp_header)36   virtual void OnReceivedPayloadData(const uint8* payload_data,
37                                      size_t payload_size,
38                                      const RtpCastHeader* rtp_header) OVERRIDE {
39     video_receiver_->IncomingParsedRtpPacket(payload_data, payload_size,
40                                              *rtp_header);
41   }
42 
43  private:
44   VideoReceiver* video_receiver_;
45 };
46 
47 // Local implementation of RtpPayloadFeedback (defined in rtp_defines.h)
48 // Used to convey cast-specific feedback from receiver to sender.
49 // Callback triggered by the Framer (cast message builder).
50 class LocalRtpVideoFeedback : public RtpPayloadFeedback {
51  public:
LocalRtpVideoFeedback(VideoReceiver * video_receiver)52   explicit LocalRtpVideoFeedback(VideoReceiver* video_receiver)
53       : video_receiver_(video_receiver) {
54   }
55 
CastFeedback(const RtcpCastMessage & cast_message)56   virtual void CastFeedback(const RtcpCastMessage& cast_message) OVERRIDE {
57     video_receiver_->CastFeedback(cast_message);
58   }
59 
60  private:
61   VideoReceiver* video_receiver_;
62 };
63 
64 // Local implementation of RtpReceiverStatistics (defined by rtcp.h).
65 // Used to pass statistics data from the RTP module to the RTCP module.
66 class LocalRtpReceiverStatistics : public RtpReceiverStatistics {
67  public:
LocalRtpReceiverStatistics(RtpReceiver * rtp_receiver)68   explicit LocalRtpReceiverStatistics(RtpReceiver* rtp_receiver)
69      : rtp_receiver_(rtp_receiver) {
70   }
71 
GetStatistics(uint8 * fraction_lost,uint32 * cumulative_lost,uint32 * extended_high_sequence_number,uint32 * jitter)72   virtual void GetStatistics(uint8* fraction_lost,
73                              uint32* cumulative_lost,  // 24 bits valid.
74                              uint32* extended_high_sequence_number,
75                              uint32* jitter) OVERRIDE {
76     rtp_receiver_->GetStatistics(fraction_lost,
77                                  cumulative_lost,
78                                  extended_high_sequence_number,
79                                  jitter);
80   }
81 
82  private:
83   RtpReceiver* rtp_receiver_;
84 };
85 
VideoReceiver(scoped_refptr<CastEnvironment> cast_environment,const VideoReceiverConfig & video_config,PacedPacketSender * const packet_sender)86 VideoReceiver::VideoReceiver(scoped_refptr<CastEnvironment> cast_environment,
87                              const VideoReceiverConfig& video_config,
88                              PacedPacketSender* const packet_sender)
89       : cast_environment_(cast_environment),
90         codec_(video_config.codec),
91         target_delay_delta_(
92             base::TimeDelta::FromMilliseconds(video_config.rtp_max_delay_ms)),
93         frame_delay_(base::TimeDelta::FromMilliseconds(
94             1000 / video_config.max_frame_rate)),
95         incoming_payload_callback_(new LocalRtpVideoData(this)),
96         incoming_payload_feedback_(new LocalRtpVideoFeedback(this)),
97         rtp_receiver_(cast_environment_->Clock(), NULL, &video_config,
98                       incoming_payload_callback_.get()),
99         rtp_video_receiver_statistics_(
100             new LocalRtpReceiverStatistics(&rtp_receiver_)),
101         time_incoming_packet_updated_(false),
102         incoming_rtp_timestamp_(0),
103         weak_factory_(this) {
104   int max_unacked_frames = video_config.rtp_max_delay_ms *
105       video_config.max_frame_rate / 1000;
106   DCHECK(max_unacked_frames) << "Invalid argument";
107 
108   if (video_config.aes_iv_mask.size() == kAesKeySize &&
109       video_config.aes_key.size() == kAesKeySize) {
110     iv_mask_ = video_config.aes_iv_mask;
111     crypto::SymmetricKey* key = crypto::SymmetricKey::Import(
112         crypto::SymmetricKey::AES, video_config.aes_key);
113     decryptor_.reset(new crypto::Encryptor());
114     decryptor_->Init(key, crypto::Encryptor::CTR, std::string());
115   } else if (video_config.aes_iv_mask.size() != 0 ||
116              video_config.aes_key.size() != 0) {
117     DCHECK(false) << "Invalid crypto configuration";
118   }
119 
120   framer_.reset(new Framer(cast_environment->Clock(),
121                            incoming_payload_feedback_.get(),
122                            video_config.incoming_ssrc,
123                            video_config.decoder_faster_than_max_frame_rate,
124                            max_unacked_frames));
125   if (!video_config.use_external_decoder) {
126     video_decoder_.reset(new VideoDecoder(video_config, cast_environment));
127   }
128 
129   rtcp_.reset(
130       new Rtcp(cast_environment_,
131                NULL,
132                packet_sender,
133                NULL,
134                rtp_video_receiver_statistics_.get(),
135                video_config.rtcp_mode,
136                base::TimeDelta::FromMilliseconds(video_config.rtcp_interval),
137                video_config.feedback_ssrc,
138                video_config.incoming_ssrc,
139                video_config.rtcp_c_name));
140 }
141 
~VideoReceiver()142 VideoReceiver::~VideoReceiver() {}
143 
InitializeTimers()144 void VideoReceiver::InitializeTimers() {
145   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
146   ScheduleNextRtcpReport();
147   ScheduleNextCastMessage();
148 }
149 
GetRawVideoFrame(const VideoFrameDecodedCallback & callback)150 void VideoReceiver::GetRawVideoFrame(
151     const VideoFrameDecodedCallback& callback) {
152   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
153   GetEncodedVideoFrame(base::Bind(&VideoReceiver::DecodeVideoFrame,
154                                   base::Unretained(this), callback));
155 }
156 
157 // Called when we have a frame to decode.
DecodeVideoFrame(const VideoFrameDecodedCallback & callback,scoped_ptr<EncodedVideoFrame> encoded_frame,const base::TimeTicks & render_time)158 void VideoReceiver::DecodeVideoFrame(
159     const VideoFrameDecodedCallback& callback,
160     scoped_ptr<EncodedVideoFrame> encoded_frame,
161     const base::TimeTicks& render_time) {
162   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
163   // Hand the ownership of the encoded frame to the decode thread.
164   cast_environment_->PostTask(CastEnvironment::VIDEO_DECODER, FROM_HERE,
165       base::Bind(&VideoReceiver::DecodeVideoFrameThread, base::Unretained(this),
166                  base::Passed(&encoded_frame), render_time, callback));
167 }
168 
169 // Utility function to run the decoder on a designated decoding thread.
DecodeVideoFrameThread(scoped_ptr<EncodedVideoFrame> encoded_frame,const base::TimeTicks render_time,const VideoFrameDecodedCallback & frame_decoded_callback)170 void VideoReceiver::DecodeVideoFrameThread(
171     scoped_ptr<EncodedVideoFrame> encoded_frame,
172     const base::TimeTicks render_time,
173     const VideoFrameDecodedCallback& frame_decoded_callback) {
174   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::VIDEO_DECODER));
175   DCHECK(video_decoder_);
176 
177   if (!(video_decoder_->DecodeVideoFrame(encoded_frame.get(), render_time,
178         frame_decoded_callback))) {
179     // This will happen if we decide to decode but not show a frame.
180     cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
181         base::Bind(&VideoReceiver::GetRawVideoFrame, base::Unretained(this),
182                    frame_decoded_callback));
183   }
184 }
185 
DecryptVideoFrame(scoped_ptr<EncodedVideoFrame> * video_frame)186 bool VideoReceiver::DecryptVideoFrame(
187     scoped_ptr<EncodedVideoFrame>* video_frame) {
188   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
189   DCHECK(decryptor_) << "Invalid state";
190 
191   if (!decryptor_->SetCounter(GetAesNonce((*video_frame)->frame_id,
192                                           iv_mask_))) {
193     NOTREACHED() << "Failed to set counter";
194     return false;
195   }
196   std::string decrypted_video_data;
197   if (!decryptor_->Decrypt((*video_frame)->data, &decrypted_video_data)) {
198     VLOG(1) << "Decryption error";
199     // Give up on this frame, release it from jitter buffer.
200     framer_->ReleaseFrame((*video_frame)->frame_id);
201     return false;
202   }
203   (*video_frame)->data.swap(decrypted_video_data);
204   return true;
205 }
206 
207 // Called from the main cast thread.
GetEncodedVideoFrame(const VideoFrameEncodedCallback & callback)208 void VideoReceiver::GetEncodedVideoFrame(
209     const VideoFrameEncodedCallback& callback) {
210   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
211   scoped_ptr<EncodedVideoFrame> encoded_frame(new EncodedVideoFrame());
212   uint32 rtp_timestamp = 0;
213   bool next_frame = false;
214 
215   if (!framer_->GetEncodedVideoFrame(encoded_frame.get(), &rtp_timestamp,
216                                      &next_frame)) {
217     // We have no video frames. Wait for new packet(s).
218     queued_encoded_callbacks_.push_back(callback);
219     return;
220   }
221 
222   if (decryptor_ && !DecryptVideoFrame(&encoded_frame)) {
223     // Logging already done.
224     queued_encoded_callbacks_.push_back(callback);
225     return;
226   }
227 
228   base::TimeTicks render_time;
229   if (PullEncodedVideoFrame(rtp_timestamp, next_frame, &encoded_frame,
230                             &render_time)) {
231     cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
232         base::Bind(callback, base::Passed(&encoded_frame), render_time));
233   } else {
234     // We have a video frame; however we are missing packets and we have time
235     // to wait for new packet(s).
236     queued_encoded_callbacks_.push_back(callback);
237   }
238 }
239 
240 // Should we pull the encoded video frame from the framer? decided by if this is
241 // the next frame or we are running out of time and have to pull the following
242 // frame.
243 // If the frame is too old to be rendered we set the don't show flag in the
244 // video bitstream where possible.
PullEncodedVideoFrame(uint32 rtp_timestamp,bool next_frame,scoped_ptr<EncodedVideoFrame> * encoded_frame,base::TimeTicks * render_time)245 bool VideoReceiver::PullEncodedVideoFrame(uint32 rtp_timestamp,
246     bool next_frame, scoped_ptr<EncodedVideoFrame>* encoded_frame,
247     base::TimeTicks* render_time) {
248   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
249   base::TimeTicks now = cast_environment_->Clock()->NowTicks();
250   *render_time = GetRenderTime(now, rtp_timestamp);
251 
252   // TODO(mikhal): Store actual render time and not diff.
253   cast_environment_->Logging()->InsertFrameEventWithDelay(kVideoRenderDelay,
254       rtp_timestamp, (*encoded_frame)->frame_id, now - *render_time);
255 
256   // Minimum time before a frame is due to be rendered before we pull it for
257   // decode.
258   base::TimeDelta min_wait_delta = frame_delay_;
259   base::TimeDelta time_until_render = *render_time - now;
260   if (!next_frame && (time_until_render > min_wait_delta)) {
261     // Example:
262     // We have decoded frame 1 and we have received the complete frame 3, but
263     // not frame 2. If we still have time before frame 3 should be rendered we
264     // will wait for 2 to arrive, however if 2 never show up this timer will hit
265     // and we will pull out frame 3 for decoding and rendering.
266     base::TimeDelta time_until_release = time_until_render - min_wait_delta;
267     cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE,
268         base::Bind(&VideoReceiver::PlayoutTimeout, weak_factory_.GetWeakPtr()),
269         time_until_release);
270     VLOG(1) << "Wait before releasing frame "
271             << static_cast<int>((*encoded_frame)->frame_id)
272             << " time " << time_until_release.InMilliseconds();
273     return false;
274   }
275 
276   base::TimeDelta dont_show_timeout_delta =
277       base::TimeDelta::FromMilliseconds(-kDontShowTimeoutMs);
278   if (codec_ == kVp8 && time_until_render < dont_show_timeout_delta) {
279     (*encoded_frame)->data[0] &= 0xef;
280     VLOG(1) << "Don't show frame "
281             << static_cast<int>((*encoded_frame)->frame_id)
282             << " time_until_render:" << time_until_render.InMilliseconds();
283   } else {
284     VLOG(1) << "Show frame "
285             << static_cast<int>((*encoded_frame)->frame_id)
286             << " time_until_render:" << time_until_render.InMilliseconds();
287   }
288   // We have a copy of the frame, release this one.
289   framer_->ReleaseFrame((*encoded_frame)->frame_id);
290   (*encoded_frame)->codec = codec_;
291   return true;
292 }
293 
PlayoutTimeout()294 void VideoReceiver::PlayoutTimeout() {
295   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
296   if (queued_encoded_callbacks_.empty()) return;
297 
298   uint32 rtp_timestamp = 0;
299   bool next_frame = false;
300   scoped_ptr<EncodedVideoFrame> encoded_frame(new EncodedVideoFrame());
301 
302   if (!framer_->GetEncodedVideoFrame(encoded_frame.get(), &rtp_timestamp,
303                                      &next_frame)) {
304     // We have no video frames. Wait for new packet(s).
305     // Since the application can post multiple VideoFrameEncodedCallback and
306     // we only check the next frame to play out we might have multiple timeout
307     // events firing after each other; however this should be a rare event.
308     VLOG(1) << "Failed to retrieved a complete frame at this point in time";
309     return;
310   }
311   VLOG(1) << "PlayoutTimeout retrieved frame "
312           << static_cast<int>(encoded_frame->frame_id);
313 
314   if (decryptor_ && !DecryptVideoFrame(&encoded_frame)) {
315     // Logging already done.
316     return;
317   }
318 
319   base::TimeTicks render_time;
320   if (PullEncodedVideoFrame(rtp_timestamp, next_frame, &encoded_frame,
321                             &render_time)) {
322     if (!queued_encoded_callbacks_.empty()) {
323       VideoFrameEncodedCallback callback = queued_encoded_callbacks_.front();
324       queued_encoded_callbacks_.pop_front();
325       cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
326           base::Bind(callback, base::Passed(&encoded_frame), render_time));
327     }
328   } else {
329     // We have a video frame; however we are missing packets and we have time
330     // to wait for new packet(s).
331   }
332 }
333 
GetRenderTime(base::TimeTicks now,uint32 rtp_timestamp)334 base::TimeTicks VideoReceiver::GetRenderTime(base::TimeTicks now,
335                                              uint32 rtp_timestamp) {
336   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
337   // Senders time in ms when this frame was captured.
338   // Note: the senders clock and our local clock might not be synced.
339   base::TimeTicks rtp_timestamp_in_ticks;
340 
341   if (time_offset_.InMilliseconds() == 0) {
342     if (!rtcp_->RtpTimestampInSenderTime(kVideoFrequency,
343                                          incoming_rtp_timestamp_,
344                                          &rtp_timestamp_in_ticks)) {
345       // We have not received any RTCP to sync the stream play it out as soon as
346       // possible.
347       return now;
348     }
349     time_offset_ = time_incoming_packet_ - rtp_timestamp_in_ticks;
350   } else if (time_incoming_packet_updated_) {
351     if (rtcp_->RtpTimestampInSenderTime(kVideoFrequency,
352                                         incoming_rtp_timestamp_,
353                                         &rtp_timestamp_in_ticks)) {
354       // Time to update the time_offset.
355       base::TimeDelta time_offset =
356           time_incoming_packet_ - rtp_timestamp_in_ticks;
357       time_offset_ = ((kTimeOffsetFilter - 1) * time_offset_ + time_offset)
358           / kTimeOffsetFilter;
359     }
360   }
361   // Reset |time_incoming_packet_updated_| to enable a future measurement.
362   time_incoming_packet_updated_ = false;
363   if (!rtcp_->RtpTimestampInSenderTime(kVideoFrequency,
364                                        rtp_timestamp,
365                                        &rtp_timestamp_in_ticks)) {
366     // This can fail if we have not received any RTCP packets in a long time.
367     return now;
368   }
369   return (rtp_timestamp_in_ticks + time_offset_ + target_delay_delta_);
370 }
371 
IncomingPacket(const uint8 * packet,size_t length,const base::Closure callback)372 void VideoReceiver::IncomingPacket(const uint8* packet, size_t length,
373                                    const base::Closure callback) {
374   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
375   if (Rtcp::IsRtcpPacket(packet, length)) {
376     rtcp_->IncomingRtcpPacket(packet, length);
377   } else {
378     rtp_receiver_.ReceivedPacket(packet, length);
379   }
380   cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, callback);
381 }
382 
IncomingParsedRtpPacket(const uint8 * payload_data,size_t payload_size,const RtpCastHeader & rtp_header)383 void VideoReceiver::IncomingParsedRtpPacket(const uint8* payload_data,
384                                             size_t payload_size,
385                                             const RtpCastHeader& rtp_header) {
386   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
387 
388   base::TimeTicks now = cast_environment_->Clock()->NowTicks();
389   if (time_incoming_packet_.is_null() || now - time_incoming_packet_ >
390       base::TimeDelta::FromMilliseconds(kMinTimeBetweenOffsetUpdatesMs)) {
391     if (time_incoming_packet_.is_null()) InitializeTimers();
392     incoming_rtp_timestamp_ = rtp_header.webrtc.header.timestamp;
393     time_incoming_packet_ = now;
394     time_incoming_packet_updated_ = true;
395   }
396 
397   cast_environment_->Logging()->InsertPacketEvent(kPacketReceived,
398       rtp_header.webrtc.header.timestamp, rtp_header.frame_id,
399       rtp_header.packet_id, rtp_header.max_packet_id, payload_size);
400 
401   bool complete = framer_->InsertPacket(payload_data, payload_size, rtp_header);
402 
403   if (!complete) return;  // Video frame not complete; wait for more packets.
404   if (queued_encoded_callbacks_.empty()) return;  // No pending callback.
405 
406   VideoFrameEncodedCallback callback = queued_encoded_callbacks_.front();
407   queued_encoded_callbacks_.pop_front();
408   cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
409       base::Bind(&VideoReceiver::GetEncodedVideoFrame,
410           weak_factory_.GetWeakPtr(), callback));
411 }
412 
413 // Send a cast feedback message. Actual message created in the framer (cast
414 // message builder).
CastFeedback(const RtcpCastMessage & cast_message)415 void VideoReceiver::CastFeedback(const RtcpCastMessage& cast_message) {
416   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
417   // TODO(pwestin): wire up log messages.
418   rtcp_->SendRtcpFromRtpReceiver(&cast_message, NULL);
419   time_last_sent_cast_message_= cast_environment_->Clock()->NowTicks();
420 }
421 
422 // Cast messages should be sent within a maximum interval. Schedule a call
423 // if not triggered elsewhere, e.g. by the cast message_builder.
ScheduleNextCastMessage()424 void VideoReceiver::ScheduleNextCastMessage() {
425   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
426   base::TimeTicks send_time;
427   framer_->TimeToSendNextCastMessage(&send_time);
428 
429   base::TimeDelta time_to_send = send_time -
430       cast_environment_->Clock()->NowTicks();
431   time_to_send = std::max(time_to_send,
432       base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
433   cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE,
434       base::Bind(&VideoReceiver::SendNextCastMessage,
435                  weak_factory_.GetWeakPtr()), time_to_send);
436 }
437 
SendNextCastMessage()438 void VideoReceiver::SendNextCastMessage() {
439   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
440   framer_->SendCastMessage();  // Will only send a message if it is time.
441   ScheduleNextCastMessage();
442 }
443 
444 // Schedule the next RTCP report to be sent back to the sender.
ScheduleNextRtcpReport()445 void VideoReceiver::ScheduleNextRtcpReport() {
446   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
447   base::TimeDelta time_to_next = rtcp_->TimeToSendNextRtcpReport() -
448       cast_environment_->Clock()->NowTicks();
449 
450   time_to_next = std::max(time_to_next,
451       base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
452 
453   cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE,
454       base::Bind(&VideoReceiver::SendNextRtcpReport,
455                 weak_factory_.GetWeakPtr()), time_to_next);
456 }
457 
SendNextRtcpReport()458 void VideoReceiver::SendNextRtcpReport() {
459   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
460   rtcp_->SendRtcpFromRtpReceiver(NULL, NULL);
461   ScheduleNextRtcpReport();
462 }
463 
464 }  // namespace cast
465 }  // namespace media
466