#include "media/cast/cast_config.h"
#include "media/cast/cast_environment.h"
#include "media/cast/cast_receiver.h"
+#include "media/cast/framer/framer.h"
#include "media/cast/rtcp/receiver_rtcp_event_subscriber.h"
#include "media/cast/rtcp/rtcp.h"
#include "media/cast/rtp_receiver/rtp_receiver.h"
#include "media/cast/transport/utility/transport_encryption_handler.h"
namespace media {
+
+class VideoFrame;
+
namespace cast {
-class Framer;
-class LocalRtpVideoFeedback;
-class PeerVideoReceiver;
-class Rtcp;
-class RtpReceiverStatistics;
class VideoDecoder;
-// Callback used by the video receiver to inform the audio receiver of the new
-// delay used to compute the playout and render times.
-typedef base::Callback<void(base::TimeDelta)> SetTargetDelayCallback;
-
-// Should only be called from the Main cast thread.
-class VideoReceiver : public base::NonThreadSafe,
- public base::SupportsWeakPtr<VideoReceiver>,
- public RtpReceiver {
+// VideoReceiver receives packets out-of-order while clients make requests for
+// complete frames in-order. (A frame consists of one or more packets.)
+//
+// VideoReceiver also includes logic for computing the playout time for each
+// frame, accounting for a constant targeted playout delay. The purpose of the
+// playout delay is to provide a fixed window of time between the capture event
+// on the sender and the playout on the receiver. This is important because
+// each step of the pipeline (i.e., encode frame, then transmit/retransmit from
+// the sender, then receive and re-order packets on the receiver, then decode
+// frame) can vary in duration and is typically very hard to predict.
+// Heuristics will determine when the targeted playout delay is insufficient in
+// the current environment; and the receiver can then increase the playout
+// delay, notifying the sender, to account for the extra variance.
+// TODO(miu): Make the last sentence true. http://crbug.com/360111
+//
+// Two types of frames can be requested: 1) A frame of decoded video data; or 2)
+// a frame of still-encoded video data, to be passed into an external video
+// decoder. Each request for a frame includes a callback which VideoReceiver
+// guarantees will be called at some point in the future unless the
+// VideoReceiver is destroyed. Clients should generally limit the number of
+// outstanding requests (perhaps to just one or two).
+//
+// This class is not thread safe. Should only be called from the Main cast
+// thread.
+class VideoReceiver : public RtpReceiver,
+ public RtpPayloadFeedback,
+ public base::NonThreadSafe,
+ public base::SupportsWeakPtr<VideoReceiver> {
public:
VideoReceiver(scoped_refptr<CastEnvironment> cast_environment,
const VideoReceiverConfig& video_config,
- transport::PacedPacketSender* const packet_sender,
- const SetTargetDelayCallback& target_delay_cb);
+ transport::PacedPacketSender* const packet_sender);
virtual ~VideoReceiver();
- // Request a raw frame. Will return frame via callback when available.
+ // Request a decoded video frame.
+ //
+ // The given |callback| is guaranteed to be run at some point in the future,
+ // even if to respond with NULL at shutdown time.
void GetRawVideoFrame(const VideoFrameDecodedCallback& callback);
- // Request an encoded frame. Will return frame via callback when available.
+ // Request an encoded video frame.
+ //
+ // The given |callback| is guaranteed to be run at some point in the future,
+ // even if to respond with NULL at shutdown time.
void GetEncodedVideoFrame(const VideoFrameEncodedCallback& callback);
- // Insert a RTP packet to the video receiver.
+ // Deliver another packet, possibly a duplicate, and possibly out-of-order.
void IncomingPacket(scoped_ptr<Packet> packet);
+ protected:
+ friend class VideoReceiverTest; // Invoked OnReceivedPayloadData().
+
virtual void OnReceivedPayloadData(const uint8* payload_data,
size_t payload_size,
const RtpCastHeader& rtp_header) OVERRIDE;
- protected:
- void DecodeVideoFrameThread(
- scoped_ptr<transport::EncodedVideoFrame> encoded_frame,
- const base::TimeTicks render_time,
- const VideoFrameDecodedCallback& frame_decoded_callback);
+ // RtpPayloadFeedback implementation.
+ virtual void CastFeedback(const RtcpCastMessage& cast_message) OVERRIDE;
private:
- friend class LocalRtpVideoFeedback;
-
- void CastFeedback(const RtcpCastMessage& cast_message);
-
- void DecodeVideoFrame(const VideoFrameDecodedCallback& callback,
- scoped_ptr<transport::EncodedVideoFrame> encoded_frame,
- const base::TimeTicks& render_time);
-
- bool DecryptVideoFrame(scoped_ptr<transport::EncodedVideoFrame>* video_frame);
-
- bool PullEncodedVideoFrame(
- bool next_frame,
- scoped_ptr<transport::EncodedVideoFrame>* encoded_frame,
- base::TimeTicks* render_time);
-
- void PlayoutTimeout();
+ // Processes ready-to-consume packets from |framer_|, decrypting each packet's
+ // payload data, and then running the enqueued callbacks in order (one for
+ // each packet). This method may post a delayed task to re-invoke itself in
+ // the future to wait for missing/incomplete frames.
+ void EmitAvailableEncodedFrames();
+
+ // Clears the |is_waiting_for_consecutive_frame_| flag and invokes
+ // EmitAvailableEncodedFrames().
+ void EmitAvailableEncodedFramesAfterWaiting();
+
+ // Feeds an EncodedVideoFrame into |video_decoder_|. GetRawVideoFrame() uses
+ // this as a callback for GetEncodedVideoFrame().
+ void DecodeEncodedVideoFrame(
+ const VideoFrameDecodedCallback& callback,
+ scoped_ptr<transport::EncodedVideoFrame> encoded_frame,
+ const base::TimeTicks& playout_time);
- // Returns Render time based on current time and the rtp timestamp.
- base::TimeTicks GetRenderTime(base::TimeTicks now, uint32 rtp_timestamp);
+ // Return the playout time based on the current time and rtp timestamp.
+ base::TimeTicks GetPlayoutTime(base::TimeTicks now, uint32 rtp_timestamp);
void InitializeTimers();
// Actually send the next RTCP report.
void SendNextRtcpReport();
- // Update the target delay based on past information. Will also update the
- // rtcp module and the audio receiver.
- void UpdateTargetDelay();
-
- scoped_ptr<VideoDecoder> video_decoder_;
- scoped_refptr<CastEnvironment> cast_environment_;
+ // Receives a VideoFrame from |video_decoder_|, logs the event, and passes the
+ // data on by running the given |callback|. This method is static to ensure
+ // it can be called after a VideoReceiver instance is destroyed.
+ // DecodeEncodedVideoFrame() uses this as a callback for
+ // VideoDecoder::DecodeFrame().
+ static void EmitRawVideoFrame(
+ const scoped_refptr<CastEnvironment>& cast_environment,
+ const VideoFrameDecodedCallback& callback,
+ uint32 frame_id,
+ uint32 rtp_timestamp,
+ const base::TimeTicks& playout_time,
+ const scoped_refptr<VideoFrame>& video_frame,
+ bool is_continuous);
+
+ const scoped_refptr<CastEnvironment> cast_environment_;
// Subscribes to raw events.
// Processes raw audio events to be sent over to the cast sender via RTCP.
ReceiverRtcpEventSubscriber event_subscriber_;
- scoped_ptr<Framer> framer_;
const transport::VideoCodec codec_;
- base::TimeDelta target_delay_delta_;
- base::TimeDelta frame_delay_;
- scoped_ptr<LocalRtpVideoFeedback> incoming_payload_feedback_;
- scoped_ptr<Rtcp> rtcp_;
+ const base::TimeDelta target_delay_delta_;
+ const base::TimeDelta expected_frame_duration_;
+ Framer framer_;
+ scoped_ptr<VideoDecoder> video_decoder_;
+ Rtcp rtcp_;
base::TimeDelta time_offset_; // Sender-receiver offset estimation.
int time_offset_counter_;
- transport::TransportEncryptionHandler decryptor_;
- std::list<VideoFrameEncodedCallback> queued_encoded_callbacks_;
bool time_incoming_packet_updated_;
base::TimeTicks time_incoming_packet_;
uint32 incoming_rtp_timestamp_;
- base::TimeTicks last_render_time_;
- SetTargetDelayCallback target_delay_cb_;
+ transport::TransportEncryptionHandler decryptor_;
+
+ // Outstanding callbacks to run to deliver on client requests for frames.
+ std::list<VideoFrameEncodedCallback> frame_request_queue_;
+
+ // True while there's an outstanding task to re-invoke
+ // EmitAvailableEncodedFrames().
+ bool is_waiting_for_consecutive_frame_;
// This mapping allows us to log kVideoAckSent as a frame event. In addition
// it allows the event to be transmitted via RTCP.