Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / remoting / client / jni / jni_frame_consumer.cc
blob8c84dba2db2f0221855a7aa3ea4ccb67b96a90b0
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/android/scoped_java_ref.h"
9 #include "base/logging.h"
10 #include "remoting/base/util.h"
11 #include "remoting/client/jni/chromoting_jni_instance.h"
12 #include "remoting/client/jni/chromoting_jni_runtime.h"
13 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
14 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
15 #include "ui/gfx/android/java_bitmap.h"
17 namespace remoting {
19 class JniFrameConsumer::Renderer {
20 public:
21 Renderer(ChromotingJniRuntime* jni_runtime) : jni_runtime_(jni_runtime) {}
22 ~Renderer() {
23 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
26 void RenderFrame(scoped_ptr<webrtc::DesktopFrame> frame);
28 private:
29 // Used to obtain task runner references and make calls to Java methods.
30 ChromotingJniRuntime* jni_runtime_;
32 // This global reference is required, instead of a local reference, so it
33 // remains valid for the lifetime of |bitmap_| - gfx::JavaBitmap does not
34 // create its own global reference internally. And this global ref must be
35 // destroyed (released) after |bitmap_| is destroyed.
36 base::android::ScopedJavaGlobalRef<jobject> bitmap_global_ref_;
38 // Reference to the frame bitmap that is passed to Java when the frame is
39 // allocated. This provides easy access to the underlying pixels.
40 scoped_ptr<gfx::JavaBitmap> bitmap_;
43 // Function called on the display thread to render the frame.
44 void JniFrameConsumer::Renderer::RenderFrame(
45 scoped_ptr<webrtc::DesktopFrame> frame) {
46 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
48 if (!bitmap_ || bitmap_->size().width() != frame->size().width() ||
49 bitmap_->size().height() != frame->size().height()) {
50 // Allocate a new Bitmap, store references here, and pass it to Java.
51 JNIEnv* env = base::android::AttachCurrentThread();
53 // |bitmap_| must be deleted before |bitmap_global_ref_| is released.
54 bitmap_.reset();
55 bitmap_global_ref_.Reset(
56 env,
57 jni_runtime_->NewBitmap(frame->size().width(), frame->size().height())
58 .obj());
59 bitmap_.reset(new gfx::JavaBitmap(bitmap_global_ref_.obj()));
60 jni_runtime_->UpdateFrameBitmap(bitmap_global_ref_.obj());
63 // Copy pixels from |frame| into the Java Bitmap.
64 // TODO(lambroslambrou): Optimize away this copy by having the VideoDecoder
65 // decode directly into the Bitmap's pixel memory. This currently doesn't
66 // work very well because the VideoDecoder writes the decoded data in BGRA,
67 // and then the R/B channels are swapped in place (on the decoding thread).
68 // If a repaint is triggered from a Java event handler, the unswapped pixels
69 // can sometimes appear on the display.
70 uint8* dest_buffer = static_cast<uint8*>(bitmap_->pixels());
71 webrtc::DesktopRect buffer_rect =
72 webrtc::DesktopRect::MakeSize(frame->size());
73 for (webrtc::DesktopRegion::Iterator i(frame->updated_region()); !i.IsAtEnd();
74 i.Advance()) {
75 CopyRGB32Rect(frame->data(), frame->stride(), buffer_rect, dest_buffer,
76 bitmap_->stride(), buffer_rect, i.rect());
79 jni_runtime_->RedrawCanvas();
82 JniFrameConsumer::JniFrameConsumer(ChromotingJniRuntime* jni_runtime)
83 : jni_runtime_(jni_runtime),
84 renderer_(new Renderer(jni_runtime)),
85 weak_factory_(this) {}
87 JniFrameConsumer::~JniFrameConsumer() {
88 jni_runtime_->display_task_runner()->DeleteSoon(FROM_HERE,
89 renderer_.release());
92 scoped_ptr<webrtc::DesktopFrame> JniFrameConsumer::AllocateFrame(
93 const webrtc::DesktopSize& size) {
94 return make_scoped_ptr(new webrtc::BasicDesktopFrame(size));
97 void JniFrameConsumer::DrawFrame(scoped_ptr<webrtc::DesktopFrame> frame,
98 const base::Closure& done) {
99 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
101 jni_runtime_->display_task_runner()->PostTaskAndReply(
102 FROM_HERE,
103 base::Bind(&Renderer::RenderFrame, base::Unretained(renderer_.get()),
104 base::Passed(&frame)),
105 base::Bind(&JniFrameConsumer::OnFrameRendered, weak_factory_.GetWeakPtr(),
106 done));
109 void JniFrameConsumer::OnFrameRendered(const base::Closure& done) {
110 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
112 if (!done.is_null())
113 done.Run();
116 FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() {
117 return FORMAT_RGBA;
120 } // namespace remoting