• 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 "remoting/client/jni/jni_frame_consumer.h"
6 
7 #include "base/android/jni_android.h"
8 #include "base/logging.h"
9 #include "base/stl_util.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "remoting/base/util.h"
12 #include "remoting/client/frame_producer.h"
13 #include "remoting/client/jni/chromoting_jni_instance.h"
14 #include "remoting/client/jni/chromoting_jni_runtime.h"
15 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
17 #include "ui/gfx/android/java_bitmap.h"
18 
19 namespace remoting {
20 
JniFrameConsumer(ChromotingJniRuntime * jni_runtime,scoped_refptr<ChromotingJniInstance> jni_instance)21 JniFrameConsumer::JniFrameConsumer(
22     ChromotingJniRuntime* jni_runtime,
23     scoped_refptr<ChromotingJniInstance> jni_instance)
24     : jni_runtime_(jni_runtime),
25       jni_instance_(jni_instance),
26       frame_producer_(NULL) {
27 }
28 
~JniFrameConsumer()29 JniFrameConsumer::~JniFrameConsumer() {
30   // The producer should now return any pending buffers. At this point, however,
31   // ReturnBuffer() tasks scheduled by the producer will not be delivered,
32   // so we free all the buffers once the producer's queue is empty.
33   base::WaitableEvent done_event(true, false);
34   frame_producer_->RequestReturnBuffers(
35       base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done_event)));
36   done_event.Wait();
37 
38   STLDeleteElements(&buffers_);
39 }
40 
set_frame_producer(FrameProducer * producer)41 void JniFrameConsumer::set_frame_producer(FrameProducer* producer) {
42   frame_producer_ = producer;
43 }
44 
ApplyBuffer(const webrtc::DesktopSize & view_size,const webrtc::DesktopRect & clip_area,webrtc::DesktopFrame * buffer,const webrtc::DesktopRegion & region,const webrtc::DesktopRegion & shape)45 void JniFrameConsumer::ApplyBuffer(const webrtc::DesktopSize& view_size,
46                                    const webrtc::DesktopRect& clip_area,
47                                    webrtc::DesktopFrame* buffer,
48                                    const webrtc::DesktopRegion& region,
49                                    const webrtc::DesktopRegion& shape) {
50   DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
51 
52   if (bitmap_->size().width() != buffer->size().width() ||
53       bitmap_->size().height() != buffer->size().height()) {
54     // Drop the frame, since the data belongs to the previous generation,
55     // before SetSourceSize() called SetOutputSizeAndClip().
56     FreeBuffer(buffer);
57     return;
58   }
59 
60   // Copy pixels from |buffer| into the Java Bitmap.
61   // TODO(lambroslambrou): Optimize away this copy by having the VideoDecoder
62   // decode directly into the Bitmap's pixel memory. This currently doesn't
63   // work very well because the VideoDecoder writes the decoded data in BGRA,
64   // and then the R/B channels are swapped in place (on the decoding thread).
65   // If a repaint is triggered from a Java event handler, the unswapped pixels
66   // can sometimes appear on the display.
67   uint8* dest_buffer = static_cast<uint8*>(bitmap_->pixels());
68   webrtc::DesktopRect buffer_rect = webrtc::DesktopRect::MakeSize(view_size);
69 
70   for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) {
71     const webrtc::DesktopRect& rect(i.rect());
72     CopyRGB32Rect(buffer->data(), buffer->stride(), buffer_rect, dest_buffer,
73                   bitmap_->stride(), buffer_rect, rect);
74   }
75 
76   // TODO(lambroslambrou): Optimize this by only repainting the changed pixels.
77   base::TimeTicks start_time = base::TimeTicks::Now();
78   jni_runtime_->RedrawCanvas();
79   jni_instance_->RecordPaintTime(
80       (base::TimeTicks::Now() - start_time).InMilliseconds());
81 
82   // Supply |frame_producer_| with a buffer to render the next frame into.
83   frame_producer_->DrawBuffer(buffer);
84 }
85 
ReturnBuffer(webrtc::DesktopFrame * buffer)86 void JniFrameConsumer::ReturnBuffer(webrtc::DesktopFrame* buffer) {
87   DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
88   FreeBuffer(buffer);
89 }
90 
SetSourceSize(const webrtc::DesktopSize & source_size,const webrtc::DesktopVector & dpi)91 void JniFrameConsumer::SetSourceSize(const webrtc::DesktopSize& source_size,
92                                      const webrtc::DesktopVector& dpi) {
93   DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
94 
95   // We currently render the desktop 1:1 and perform pan/zoom scaling
96   // and cropping on the managed canvas.
97   clip_area_ = webrtc::DesktopRect::MakeSize(source_size);
98   frame_producer_->SetOutputSizeAndClip(source_size, clip_area_);
99 
100   // Allocate buffer and start drawing frames onto it.
101   AllocateBuffer(source_size);
102 }
103 
GetPixelFormat()104 FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() {
105   return FORMAT_RGBA;
106 }
107 
AllocateBuffer(const webrtc::DesktopSize & source_size)108 void JniFrameConsumer::AllocateBuffer(const webrtc::DesktopSize& source_size) {
109   DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
110 
111   webrtc::DesktopSize size(source_size.width(), source_size.height());
112 
113   // Allocate a new Bitmap, store references here, and pass it to Java.
114   JNIEnv* env = base::android::AttachCurrentThread();
115 
116   // |bitmap_| must be deleted before |bitmap_global_ref_| is released.
117   bitmap_.reset();
118   bitmap_global_ref_.Reset(env, jni_runtime_->NewBitmap(size).obj());
119   bitmap_.reset(new gfx::JavaBitmap(bitmap_global_ref_.obj()));
120   jni_runtime_->UpdateFrameBitmap(bitmap_global_ref_.obj());
121 
122   webrtc::DesktopFrame* buffer = new webrtc::BasicDesktopFrame(size);
123   buffers_.push_back(buffer);
124   frame_producer_->DrawBuffer(buffer);
125 }
126 
FreeBuffer(webrtc::DesktopFrame * buffer)127 void JniFrameConsumer::FreeBuffer(webrtc::DesktopFrame* buffer) {
128   DCHECK(std::find(buffers_.begin(), buffers_.end(), buffer) != buffers_.end());
129 
130   buffers_.remove(buffer);
131   delete buffer;
132 }
133 
134 }  // namespace remoting
135