summaryrefslogtreecommitdiff
path: root/remoting/ios/bridge/frame_consumer_bridge.cc
blob: fbc96066d38fcd91276278dc888ced77f76d0e7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright 2014 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.

#include "remoting/ios/bridge/frame_consumer_bridge.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/synchronization/waitable_event.h"
#include "remoting/base/util.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"

namespace remoting {

FrameConsumerBridge::FrameConsumerBridge(OnFrameCallback callback)
    : callback_(callback), frame_producer_(NULL) {}

FrameConsumerBridge::~FrameConsumerBridge() {
  // The producer should now return any pending buffers. At this point, however,
  // the buffers are returned via tasks which may not be scheduled before the
  // producer, so we free all the buffers once the producer's queue is empty.
  // And the scheduled tasks will die quietly.
  if (frame_producer_) {
    base::WaitableEvent done_event(true, false);
    frame_producer_->RequestReturnBuffers(base::Bind(
        &base::WaitableEvent::Signal, base::Unretained(&done_event)));
    done_event.Wait();
  }
}

void FrameConsumerBridge::Initialize(FrameProducer* producer) {
  DCHECK(!frame_producer_);
  frame_producer_ = producer;
  DCHECK(frame_producer_);
}

void FrameConsumerBridge::ApplyBuffer(const webrtc::DesktopSize& view_size,
                                      const webrtc::DesktopRect& clip_area,
                                      webrtc::DesktopFrame* buffer,
                                      const webrtc::DesktopRegion& region,
                                      const webrtc::DesktopRegion& shape) {
  DCHECK(frame_producer_);
  if (!view_size_.equals(view_size)) {
    // Drop the frame, since the data belongs to the previous generation,
    // before SetSourceSize() called SetOutputSizeAndClip().
    ReturnBuffer(buffer);
    return;
  }

  // This call completes synchronously.
  callback_.Run(view_size, buffer, region);

  // Recycle |buffer| by returning it to |frame_producer_| as the next buffer
  frame_producer_->DrawBuffer(buffer);
}

void FrameConsumerBridge::ReturnBuffer(webrtc::DesktopFrame* buffer) {
  DCHECK(frame_producer_);
  ScopedVector<webrtc::DesktopFrame>::iterator it =
      std::find(buffers_.begin(), buffers_.end(), buffer);

  DCHECK(it != buffers_.end());
  buffers_.erase(it);
}

void FrameConsumerBridge::SetSourceSize(const webrtc::DesktopSize& source_size,
                                        const webrtc::DesktopVector& dpi) {
  DCHECK(frame_producer_);
  view_size_ = source_size;
  webrtc::DesktopRect clip_area = webrtc::DesktopRect::MakeSize(view_size_);
  frame_producer_->SetOutputSizeAndClip(view_size_, clip_area);

  // Now that the size is well known, ask the producer to start drawing
  DrawWithNewBuffer();
}

FrameConsumerBridge::PixelFormat FrameConsumerBridge::GetPixelFormat() {
  return FORMAT_RGBA;
}

void FrameConsumerBridge::DrawWithNewBuffer() {
  DCHECK(frame_producer_);
  webrtc::DesktopFrame* buffer = new webrtc::BasicDesktopFrame(view_size_);
  buffers_.push_back(buffer);
  frame_producer_->DrawBuffer(buffer);
}

}  // namespace remoting