// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef REMOTING_HOST_VIDEO_SCHEDULER_H_
#define REMOTING_HOST_VIDEO_SCHEDULER_H_
#include <vector>
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "remoting/codec/video_encoder.h"
#include "remoting/host/capture_scheduler.h"
#include "remoting/proto/video.pb.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
#include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h"
namespace base {
class SingleThreadTaskRunner;
} // namespace base
namespace media {
class DesktopCapturer;
} // namespace media
namespace remoting {
class CursorShapeInfo;
namespace protocol {
class CursorShapeInfo;
class CursorShapeStub;
class VideoStub;
} // namespace protocol
// Class responsible for scheduling frame captures from a
// webrtc::DesktopCapturer, delivering them to a VideoEncoder to encode, and
// finally passing the encoded video packets to the specified VideoStub to send
// on the network.
//
// THREADING
//
// This class is supplied TaskRunners to use for capture, encode and network
// operations. Capture, encode and network transmission tasks are interleaved
// as illustrated below:
//
// | CAPTURE ENCODE NETWORK
// | .............
// | . Capture .
// | .............
// | ............
// | . .
// | ............. . .
// | . Capture . . Encode .
// | ............. . .
// | . .
// | ............
// | ............. ............ ..........
// | . Capture . . . . Send .
// | ............. . . ..........
// | . Encode .
// | . .
// | . .
// | ............
// | Time
// v
//
// VideoScheduler would ideally schedule captures so as to saturate the slowest
// of the capture, encode and network processes. However, it also needs to
// rate-limit captures to avoid overloading the host system, either by consuming
// too much CPU, or hogging the host's graphics subsystem.
class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler>,
public webrtc::DesktopCapturer::Callback,
public webrtc::MouseCursorMonitor::Callback {
public:
// Enables timestamps for generated frames. Used for testing.
static void EnableTimestampsForTests();
// Creates a VideoScheduler running capture, encode and network tasks on the
// supplied TaskRunners. Video and cursor shape updates will be pumped to
// |video_stub| and |client_stub|, which must remain valid until Stop() is
// called. |capturer| is used to capture frames.
VideoScheduler(
scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
scoped_ptr<webrtc::DesktopCapturer> capturer,
scoped_ptr<webrtc::MouseCursorMonitor> mouse_cursor_monitor,
scoped_ptr<VideoEncoder> encoder,
protocol::CursorShapeStub* cursor_stub,
protocol::VideoStub* video_stub);
// webrtc::DesktopCapturer::Callback implementation.
virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE;
virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE;
// webrtc::MouseCursorMonitor::Callback implementation.
virtual void OnMouseCursor(
webrtc::MouseCursor* mouse_cursor) OVERRIDE;
virtual void OnMouseCursorPosition(
webrtc::MouseCursorMonitor::CursorState state,
const webrtc::DesktopVector& position) OVERRIDE;
// Starts scheduling frame captures.
void Start();
// Stop scheduling frame captures. This object cannot be re-used once
// it has been stopped.
void Stop();
// Pauses or resumes scheduling of frame captures. Pausing/resuming captures
// only affects capture scheduling and does not stop/start the capturer.
void Pause(bool pause);
// Updates the sequence number embedded in VideoPackets.
// Sequence numbers are used for performance measurements.
void UpdateSequenceNumber(int64 sequence_number);
// Sets whether the video encoder should be requested to encode losslessly,
// or to use a lossless color space (typically requiring higher bandwidth).
void SetLosslessEncode(bool want_lossless);
void SetLosslessColor(bool want_lossless);
private:
friend class base::RefCountedThreadSafe<VideoScheduler>;
virtual ~VideoScheduler();
// Capturer thread ----------------------------------------------------------
// Starts the capturer on the capture thread.
void StartOnCaptureThread();
// Stops scheduling frame captures on the capture thread.
void StopOnCaptureThread();
// Schedules the next call to CaptureNextFrame.
void ScheduleNextCapture();
// Starts the next frame capture, unless there are already too many pending.
void CaptureNextFrame();
// Called when a frame capture has been encoded & sent to the client.
void FrameCaptureCompleted();
// Network thread -----------------------------------------------------------
// Send |packet| to the client, unless we are in the process of stopping.
void SendVideoPacket(scoped_ptr<VideoPacket> packet);
// Callback passed to |video_stub_| for the last packet in each frame, to
// rate-limit frame captures to network throughput.
void OnVideoPacketSent();
// Called by |keep_alive_timer_|.
void SendKeepAlivePacket();
// Callback for |video_stub_| called after a keep-alive packet is sent.
void OnKeepAlivePacketSent();
// Send updated cursor shape to client.
void SendCursorShape(scoped_ptr<protocol::CursorShapeInfo> cursor_shape);
// Encoder thread -----------------------------------------------------------
// Encode a frame, passing generated VideoPackets to SendVideoPacket().
void EncodeFrame(scoped_ptr<webrtc::DesktopFrame> frame,
int64 sequence_number,
base::TimeTicks timestamp);
void EncodedDataAvailableCallback(int64 sequence_number,
scoped_ptr<VideoPacket> packet);
// Task runners used by this class.
scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
// Used to capture frames. Always accessed on the capture thread.
scoped_ptr<webrtc::DesktopCapturer> capturer_;
// Used to capture mouse cursor shapes. Always accessed on the capture thread.
scoped_ptr<webrtc::MouseCursorMonitor> mouse_cursor_monitor_;
// Used to encode captured frames. Always accessed on the encode thread.
scoped_ptr<VideoEncoder> encoder_;
// Interfaces through which video frames and cursor shapes are passed to the
// client. These members are always accessed on the network thread.
protocol::CursorShapeStub* cursor_stub_;
protocol::VideoStub* video_stub_;
// Timer used to schedule CaptureNextFrame().
scoped_ptr<base::OneShotTimer<VideoScheduler> > capture_timer_;
// Timer used to ensure that we send empty keep-alive frames to the client
// even when the video stream is paused or encoder is busy.
scoped_ptr<base::DelayTimer<VideoScheduler> > keep_alive_timer_;
// The number of frames being processed, i.e. frames that we are currently
// capturing, encoding or sending. The value is capped at 2 to minimize
// latency.
int pending_frames_;
// Set when the capturer is capturing a frame.
bool capture_pending_;
// True if the previous scheduled capture was skipped.
bool did_skip_frame_;
// True if capture of video frames is paused.
bool is_paused_;
// Number updated by the caller to trace performance.
int64 sequence_number_;
// An object to schedule capturing.
CaptureScheduler scheduler_;
DISALLOW_COPY_AND_ASSIGN(VideoScheduler);
};
} // namespace remoting
#endif // REMOTING_HOST_VIDEO_SCHEDULER_H_