| Index: remoting/host/screen_recorder.cc
|
| diff --git a/remoting/host/screen_recorder.cc b/remoting/host/screen_recorder.cc
|
| index cf3417ce4129cc102007c17ec40f1244bbfd312c..76ebcc8e4128d177bd74bbf2f198916fa4d9aec2 100644
|
| --- a/remoting/host/screen_recorder.cc
|
| +++ b/remoting/host/screen_recorder.cc
|
| @@ -45,7 +45,8 @@ ScreenRecorder::ScreenRecorder(
|
| network_loop_(network_loop),
|
| capturer_(capturer),
|
| encoder_(encoder),
|
| - started_(false),
|
| + is_recording_(false),
|
| + network_stopped_(false),
|
| recordings_(0),
|
| frame_skipped_(false),
|
| max_rate_(kDefaultCaptureRate) {
|
| @@ -55,7 +56,6 @@ ScreenRecorder::ScreenRecorder(
|
| }
|
|
|
| ScreenRecorder::~ScreenRecorder() {
|
| - connections_.clear();
|
| }
|
|
|
| // Public methods --------------------------------------------------------------
|
| @@ -65,9 +65,9 @@ void ScreenRecorder::Start() {
|
| FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoStart));
|
| }
|
|
|
| -void ScreenRecorder::Pause() {
|
| +void ScreenRecorder::Stop(Task* done_task) {
|
| capture_loop_->PostTask(
|
| - FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoPause));
|
| + FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoStop, done_task));
|
| }
|
|
|
| void ScreenRecorder::SetMaxRate(double rate) {
|
| @@ -116,30 +116,49 @@ Encoder* ScreenRecorder::encoder() {
|
|
|
| void ScreenRecorder::DoStart() {
|
| DCHECK_EQ(capture_loop_, MessageLoop::current());
|
| - DCHECK(!started_);
|
|
|
| - if (started_) {
|
| + if (is_recording_) {
|
| NOTREACHED() << "Record session already started.";
|
| return;
|
| }
|
|
|
| - started_ = true;
|
| + is_recording_ = true;
|
| StartCaptureTimer();
|
|
|
| // Capture first frame immedately.
|
| DoCapture();
|
| }
|
|
|
| -void ScreenRecorder::DoPause() {
|
| +void ScreenRecorder::DoStop(Task* done_task) {
|
| DCHECK_EQ(capture_loop_, MessageLoop::current());
|
|
|
| - if (!started_) {
|
| + if (!is_recording_) {
|
| NOTREACHED() << "Record session not started.";
|
| return;
|
| }
|
|
|
| capture_timer_.Stop();
|
| - started_ = false;
|
| + is_recording_ = false;
|
| +
|
| + DCHECK_GE(recordings_, 0);
|
| + if (recordings_) {
|
| + network_loop_->PostTask(
|
| + FROM_HERE,
|
| + NewTracedMethod(this,
|
| + &ScreenRecorder::DoStopOnNetworkThread, done_task));
|
| + return;
|
| + }
|
| +
|
| + DoCompleteStop(done_task);
|
| +}
|
| +
|
| +void ScreenRecorder::DoCompleteStop(Task* done_task) {
|
| + DCHECK_EQ(capture_loop_, MessageLoop::current());
|
| +
|
| + if (done_task) {
|
| + done_task->Run();
|
| + delete done_task;
|
| + }
|
| }
|
|
|
| void ScreenRecorder::DoSetMaxRate(double max_rate) {
|
| @@ -151,7 +170,7 @@ void ScreenRecorder::DoSetMaxRate(double max_rate) {
|
| max_rate_ = max_rate;
|
|
|
| // Restart the timer with the new rate.
|
| - if (started_) {
|
| + if (is_recording_) {
|
| capture_timer_.Stop();
|
| StartCaptureTimer();
|
| }
|
| @@ -170,7 +189,7 @@ void ScreenRecorder::DoCapture() {
|
| // Make sure we have at most two oustanding recordings. We can simply return
|
| // if we can't make a capture now, the next capture will be started by the
|
| // end of an encode operation.
|
| - if (recordings_ >= kMaxRecordings || !started_) {
|
| + if (recordings_ >= kMaxRecordings || !is_recording_) {
|
| frame_skipped_ = true;
|
| return;
|
| }
|
| @@ -184,6 +203,7 @@ void ScreenRecorder::DoCapture() {
|
|
|
| // At this point we are going to perform one capture so save the current time.
|
| ++recordings_;
|
| + DCHECK_LE(recordings_, kMaxRecordings);
|
|
|
| // And finally perform one capture.
|
| capturer()->CaptureInvalidRects(
|
| @@ -192,21 +212,27 @@ void ScreenRecorder::DoCapture() {
|
|
|
| void ScreenRecorder::CaptureDoneCallback(
|
| scoped_refptr<CaptureData> capture_data) {
|
| - // TODO(hclam): There is a bug if the capturer doesn't produce any dirty
|
| - // rects.
|
| DCHECK_EQ(capture_loop_, MessageLoop::current());
|
| +
|
| + if (!is_recording_)
|
| + return;
|
| +
|
| TraceContext::tracer()->PrintString("Capture Done");
|
| encode_loop_->PostTask(
|
| FROM_HERE,
|
| NewTracedMethod(this, &ScreenRecorder::DoEncode, capture_data));
|
| }
|
|
|
| -void ScreenRecorder::DoFinishSend() {
|
| +void ScreenRecorder::DoFinishOneRecording() {
|
| DCHECK_EQ(capture_loop_, MessageLoop::current());
|
|
|
| + if (!is_recording_)
|
| + return;
|
| +
|
| // Decrement the number of recording in process since we have completed
|
| // one cycle.
|
| --recordings_;
|
| + DCHECK_GE(recordings_, 0);
|
|
|
| // Try to do a capture again. Note that the following method may do nothing
|
| // if it is too early to perform a capture.
|
| @@ -222,14 +248,23 @@ void ScreenRecorder::DoSendVideoPacket(VideoPacket* packet) {
|
|
|
| bool last = (packet->flags() & VideoPacket::LAST_PARTITION) != 0;
|
|
|
| + if (network_stopped_) {
|
| + delete packet;
|
| + return;
|
| + }
|
| +
|
| for (ConnectionToClientList::const_iterator i = connections_.begin();
|
| i < connections_.end(); ++i) {
|
| Task* done_task = NULL;
|
|
|
| - // Call OnFrameSent() only for the last packet in the first connection.
|
| + // Call FrameSentCallback() only for the last packet in the first
|
| + // connection.
|
| if (last && i == connections_.begin()) {
|
| - done_task = NewTracedMethod(this, &ScreenRecorder::OnFrameSent, packet);
|
| + done_task = NewTracedMethod(this, &ScreenRecorder::FrameSentCallback,
|
| + packet);
|
| } else {
|
| + // TODO(hclam): Fix this code since it causes multiple deletion if there's
|
| + // more than one connection.
|
| done_task = new DeleteTask<VideoPacket>(packet);
|
| }
|
|
|
| @@ -239,10 +274,14 @@ void ScreenRecorder::DoSendVideoPacket(VideoPacket* packet) {
|
| TraceContext::tracer()->PrintString("DoSendVideoPacket done");
|
| }
|
|
|
| -void ScreenRecorder::OnFrameSent(VideoPacket* packet) {
|
| +void ScreenRecorder::FrameSentCallback(VideoPacket* packet) {
|
| delete packet;
|
| +
|
| + if (network_stopped_)
|
| + return;
|
| +
|
| capture_loop_->PostTask(
|
| - FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoFinishSend));
|
| + FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoFinishOneRecording));
|
| }
|
|
|
| void ScreenRecorder::DoAddConnection(
|
| @@ -272,6 +311,22 @@ void ScreenRecorder::DoRemoveAllClients() {
|
| connections_.clear();
|
| }
|
|
|
| +void ScreenRecorder::DoStopOnNetworkThread(Task* done_task) {
|
| + DCHECK_EQ(network_loop_, MessageLoop::current());
|
| +
|
| + // There could be tasks on the network thread when this method is being
|
| + // executed. By setting the flag we'll not post anymore tasks from network
|
| + // thread.
|
| + //
|
| + // After that a task is posted on encode thread to continue the stop
|
| + // sequence.
|
| + network_stopped_ = true;
|
| +
|
| + encode_loop_->PostTask(
|
| + FROM_HERE,
|
| + NewTracedMethod(this, &ScreenRecorder::DoStopOnEncodeThread, done_task));
|
| +}
|
| +
|
| // Encoder thread --------------------------------------------------------------
|
|
|
| void ScreenRecorder::DoEncode(
|
| @@ -282,19 +337,31 @@ void ScreenRecorder::DoEncode(
|
| // Early out if there's nothing to encode.
|
| if (!capture_data->dirty_rects().size()) {
|
| capture_loop_->PostTask(
|
| - FROM_HERE, NewTracedMethod(this, &ScreenRecorder::DoFinishSend));
|
| + FROM_HERE,
|
| + NewTracedMethod(this, &ScreenRecorder::DoFinishOneRecording));
|
| return;
|
| }
|
|
|
| - // TODO(hclam): Enable |force_refresh| if a new connection was
|
| - // added.
|
| + // TODO(hclam): Invalidate the full screen if there is a new connection added.
|
| TraceContext::tracer()->PrintString("Encode start");
|
| - encoder()->Encode(capture_data, false,
|
| - NewCallback(this, &ScreenRecorder::EncodeDataAvailableTask));
|
| + encoder()->Encode(
|
| + capture_data, false,
|
| + NewCallback(this, &ScreenRecorder::EncodedDataAvailableCallback));
|
| TraceContext::tracer()->PrintString("Encode Done");
|
| }
|
|
|
| -void ScreenRecorder::EncodeDataAvailableTask(VideoPacket* packet) {
|
| +void ScreenRecorder::DoStopOnEncodeThread(Task* done_task) {
|
| + DCHECK_EQ(encode_loop_, MessageLoop::current());
|
| +
|
| + // When this method is being executed there are no more tasks on encode thread
|
| + // for this object. We can then post a task to capture thread to finish the
|
| + // stop sequence.
|
| + capture_loop_->PostTask(
|
| + FROM_HERE,
|
| + NewTracedMethod(this, &ScreenRecorder::DoCompleteStop, done_task));
|
| +}
|
| +
|
| +void ScreenRecorder::EncodedDataAvailableCallback(VideoPacket* packet) {
|
| DCHECK_EQ(encode_loop_, MessageLoop::current());
|
|
|
| network_loop_->PostTask(
|
|
|