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.
5 #include "remoting/client/jni/jni_frame_consumer.h"
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"
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
) {
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
)));
38 STLDeleteElements(&buffers_
);
41 void JniFrameConsumer::set_frame_producer(FrameProducer
* producer
) {
42 frame_producer_
= producer
;
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());
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().
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
);
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
);
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());
82 // Supply |frame_producer_| with a buffer to render the next frame into.
83 frame_producer_
->DrawBuffer(buffer
);
86 void JniFrameConsumer::ReturnBuffer(webrtc::DesktopFrame
* buffer
) {
87 DCHECK(jni_runtime_
->display_task_runner()->BelongsToCurrentThread());
91 void JniFrameConsumer::SetSourceSize(const webrtc::DesktopSize
& source_size
,
92 const webrtc::DesktopVector
& dpi
) {
93 DCHECK(jni_runtime_
->display_task_runner()->BelongsToCurrentThread());
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_
);
100 // Allocate buffer and start drawing frames onto it.
101 AllocateBuffer(source_size
);
104 FrameConsumer::PixelFormat
JniFrameConsumer::GetPixelFormat() {
108 void JniFrameConsumer::AllocateBuffer(const webrtc::DesktopSize
& source_size
) {
109 DCHECK(jni_runtime_
->display_task_runner()->BelongsToCurrentThread());
111 webrtc::DesktopSize
size(source_size
.width(), source_size
.height());
113 // Allocate a new Bitmap, store references here, and pass it to Java.
114 JNIEnv
* env
= base::android::AttachCurrentThread();
116 // |bitmap_| must be deleted before |bitmap_global_ref_| is released.
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());
122 webrtc::DesktopFrame
* buffer
= new webrtc::BasicDesktopFrame(size
);
123 buffers_
.push_back(buffer
);
124 frame_producer_
->DrawBuffer(buffer
);
127 void JniFrameConsumer::FreeBuffer(webrtc::DesktopFrame
* buffer
) {
128 DCHECK(std::find(buffers_
.begin(), buffers_
.end(), buffer
) != buffers_
.end());
130 buffers_
.remove(buffer
);
134 } // namespace remoting