Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(225)

Side by Side Diff: remoting/client/jni/jni_frame_consumer.cc

Issue 24072012: Hold video frame in Bitmap instead of keeping a ByteBuffer reference. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Allow FrameConsumer to operate directly on Bitmap pixels Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/client/jni/jni_frame_consumer.h" 5 #include "remoting/client/jni/jni_frame_consumer.h"
6 6
7 #include "base/android/jni_android.h" 7 #include "base/android/jni_android.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/synchronization/waitable_event.h" 9 #include "base/synchronization/waitable_event.h"
10 #include "remoting/base/util.h"
10 #include "remoting/client/frame_producer.h" 11 #include "remoting/client/frame_producer.h"
11 #include "remoting/client/jni/chromoting_jni_runtime.h" 12 #include "remoting/client/jni/chromoting_jni_runtime.h"
12 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 13 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
13 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" 14 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
14 15 #include "ui/gfx/android/java_bitmap.h"
15 namespace {
16
17 // Allocates its buffer within a Java direct byte buffer, where it can be
18 // accessed by both native and managed code.
19 class DirectDesktopFrame : public webrtc::BasicDesktopFrame {
20 public:
21 DirectDesktopFrame(int width, int height);
22
23 virtual ~DirectDesktopFrame();
24
25 jobject buffer() const {
26 return buffer_;
27 }
28
29 private:
30 jobject buffer_;
31 };
32
33 DirectDesktopFrame::DirectDesktopFrame(int width, int height)
34 : webrtc::BasicDesktopFrame(webrtc::DesktopSize(width, height)) {
35 JNIEnv* env = base::android::AttachCurrentThread();
36 buffer_ = env->NewDirectByteBuffer(data(), stride()*height);
37 }
38
39 DirectDesktopFrame::~DirectDesktopFrame() {}
40
41 } // namespace
42 16
43 namespace remoting { 17 namespace remoting {
44 18
45 JniFrameConsumer::JniFrameConsumer(ChromotingJniRuntime* jni_runtime) 19 JniFrameConsumer::JniFrameConsumer(ChromotingJniRuntime* jni_runtime)
46 : jni_runtime_(jni_runtime), 20 : jni_runtime_(jni_runtime),
47 in_dtor_(false), 21 in_dtor_(false),
48 frame_producer_(NULL) { 22 frame_producer_(NULL) {
49 } 23 }
50 24
51 JniFrameConsumer::~JniFrameConsumer() { 25 JniFrameConsumer::~JniFrameConsumer() {
(...skipping 11 matching lines...) Expand all
63 frame_producer_ = producer; 37 frame_producer_ = producer;
64 } 38 }
65 39
66 void JniFrameConsumer::ApplyBuffer(const webrtc::DesktopSize& view_size, 40 void JniFrameConsumer::ApplyBuffer(const webrtc::DesktopSize& view_size,
67 const webrtc::DesktopRect& clip_area, 41 const webrtc::DesktopRect& clip_area,
68 webrtc::DesktopFrame* buffer, 42 webrtc::DesktopFrame* buffer,
69 const webrtc::DesktopRegion& region) { 43 const webrtc::DesktopRegion& region) {
70 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread()); 44 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
71 45
72 scoped_ptr<webrtc::DesktopFrame> buffer_scoped(buffer); 46 scoped_ptr<webrtc::DesktopFrame> buffer_scoped(buffer);
73 jni_runtime_->RedrawCanvas();
74 47
75 if (view_size.width() > view_size_.width() || 48 if (view_size.width() > view_size_.width() ||
76 view_size.height() > view_size_.height()) { 49 view_size.height() > view_size_.height()) {
Sergey Ulanov 2013/10/08 22:15:02 I think if you get different view_size you can jus
Lambros 2013/10/10 01:35:58 Done.
77 LOG(INFO) << "Existing buffer is too small"; 50 LOG(INFO) << "Existing buffer is too small";
78 view_size_ = view_size; 51 view_size_ = view_size;
79 52
80 // Manually destroy the old buffer before allocating a new one to prevent 53 // Manually destroy the old buffer before allocating a new one to prevent
81 // our memory footprint from temporarily ballooning. 54 // our memory footprint from temporarily ballooning.
82 buffer_scoped.reset(); 55 buffer_scoped.reset();
83 AllocateBuffer(); 56 AllocateBuffer();
Sergey Ulanov 2013/10/08 22:15:02 This also calls DrawBuffer() internally. That does
Lambros 2013/10/10 01:35:58 I think that's OK. Whenever you allocate a new buf
84 } 57 }
85 58
59 // Copy pixels from |buffer| into the Java Bitmap.
60 // TODO(lambroslambrou): Optimize away this copy by having the VideoDecoder
61 // decode directly into the Bitmap's pixel memory. This currently doesn't
62 // work very well because the VideoDecoder writes the decoded data in BGRA,
63 // and then the R/B channels are swapped in place (on the decoding thread).
64 // If a repaint is triggered from a Java event handler, the unswapped pixels
65 // can sometimes appear on the display.
66 uint8* dest_buffer = static_cast<uint8*>(bitmap_->pixels());
67 webrtc::DesktopRect buffer_rect = webrtc::DesktopRect::MakeSize(view_size);
68
69 for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) {
70 webrtc::DesktopRect rect(i.rect());
71 CopyRGB32Rect(buffer->data(), buffer->stride(), buffer_rect, dest_buffer,
72 bitmap_->stride(), buffer_rect, rect);
73 }
74
75 // TODO(lambroslambrou): Optimize this by only repainting the changed pixels.
76 jni_runtime_->RedrawCanvas();
77
86 // Supply |frame_producer_| with a buffer to render the next frame into. 78 // Supply |frame_producer_| with a buffer to render the next frame into.
87 if (!in_dtor_) 79 if (!in_dtor_)
88 frame_producer_->DrawBuffer(buffer_scoped.release()); 80 frame_producer_->DrawBuffer(buffer_scoped.release());
89 } 81 }
90 82
91 void JniFrameConsumer::ReturnBuffer(webrtc::DesktopFrame* buffer) { 83 void JniFrameConsumer::ReturnBuffer(webrtc::DesktopFrame* buffer) {
92 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread()); 84 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
93 LOG(INFO) << "Returning image buffer"; 85 LOG(INFO) << "Returning image buffer";
94 delete buffer; 86 delete buffer;
95 } 87 }
96 88
97 void JniFrameConsumer::SetSourceSize(const webrtc::DesktopSize& source_size, 89 void JniFrameConsumer::SetSourceSize(const webrtc::DesktopSize& source_size,
98 const webrtc::DesktopVector& dpi) { 90 const webrtc::DesktopVector& dpi) {
99 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread()); 91 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
100 92
101 // We currently render the desktop 1:1 and perform pan/zoom scaling 93 // We currently render the desktop 1:1 and perform pan/zoom scaling
102 // and cropping on the managed canvas. 94 // and cropping on the managed canvas.
103 view_size_ = source_size; 95 view_size_ = source_size;
104 clip_area_ = webrtc::DesktopRect::MakeSize(view_size_); 96 clip_area_ = webrtc::DesktopRect::MakeSize(view_size_);
105 frame_producer_->SetOutputSizeAndClip(view_size_, clip_area_); 97 frame_producer_->SetOutputSizeAndClip(view_size_, clip_area_);
106 98
107 // Unless being destructed, allocate buffer and start drawing frames onto it. 99 // Unless being destructed, allocate buffer and start drawing frames onto it.
108 frame_producer_->RequestReturnBuffers(base::Bind( 100 frame_producer_->RequestReturnBuffers(base::Bind(
Sergey Ulanov 2013/10/08 22:15:02 I'm not sure why we need this. Frame producer shou
Lambros 2013/10/10 01:35:58 Done.
109 &JniFrameConsumer::AllocateBuffer, base::Unretained(this))); 101 &JniFrameConsumer::AllocateBuffer, base::Unretained(this)));
110 } 102 }
111 103
112 FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() { 104 FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() {
113 return FORMAT_RGBA; 105 return FORMAT_RGBA;
114 } 106 }
115 107
116 void JniFrameConsumer::AllocateBuffer() { 108 void JniFrameConsumer::AllocateBuffer() {
117 // Only do anything if we're not being destructed. 109 // Only do anything if we're not being destructed.
118 if (!in_dtor_) { 110 if (!in_dtor_) {
119 if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) { 111 if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
120 jni_runtime_->display_task_runner()->PostTask(FROM_HERE, 112 jni_runtime_->display_task_runner()->PostTask(FROM_HERE,
121 base::Bind(&JniFrameConsumer::AllocateBuffer, 113 base::Bind(&JniFrameConsumer::AllocateBuffer,
122 base::Unretained(this))); 114 base::Unretained(this)));
123 return; 115 return;
124 } 116 }
125 117
126 DirectDesktopFrame* buffer = new DirectDesktopFrame(view_size_.width(), 118 webrtc::DesktopSize size(view_size_.width(), view_size_.height());
127 view_size_.height()); 119 webrtc::DesktopFrame* buffer = new webrtc::BasicDesktopFrame(size);
128 120
129 // Update Java's reference to the buffer and record of its dimensions. 121 // Allocate a new Bitmap, store references here, and pass it to Java.
130 jni_runtime_->UpdateImageBuffer(view_size_.width(), 122 JNIEnv* env = base::android::AttachCurrentThread();
131 view_size_.height(), 123 jobject bitmap_global_ref = env->NewGlobalRef(
Sergey Ulanov 2013/10/08 22:15:02 Do you need to call NewGlobalRef() here? ScopedJav
Yaron 2013/10/09 06:42:30 This is why our base APIs are designed to return S
Lambros 2013/10/10 01:35:58 Ouch! I thought I checked this, but I messed up.
Yaron 2013/10/10 11:13:37 I think when used in concert with ScopedJavaLocalR
132 buffer->buffer()); 124 jni_runtime_->NewBitmap(size).obj());
125 bitmap_global_ref_.Reset(env, bitmap_global_ref);
126 bitmap_.reset(new gfx::JavaBitmap(bitmap_global_ref));
127 jni_runtime_->UpdateFrameBitmap(bitmap_global_ref);
133 128
134 frame_producer_->DrawBuffer(buffer); 129 frame_producer_->DrawBuffer(buffer);
135 } 130 }
136 } 131 }
137 132
138 } // namespace remoting 133 } // namespace remoting
OLDNEW
« remoting/client/jni/jni_frame_consumer.h ('K') | « remoting/client/jni/jni_frame_consumer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698