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

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: Address comments 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
« no previous file with comments | « remoting/client/jni/jni_frame_consumer.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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() {
52 // Stop giving the producer a buffer to work with. 26 // Stop giving the producer a buffer to work with.
53 in_dtor_ = true; 27 in_dtor_ = true;
Sergey Ulanov 2013/10/11 20:32:17 Don't need this.
Lambros 2013/10/15 23:50:33 Done.
54 28
55 // Don't destroy the object until we've deleted the buffer. 29 // Don't destroy the object until we've deleted the buffer.
56 base::WaitableEvent done_event(true, false); 30 base::WaitableEvent done_event(true, false);
57 frame_producer_->RequestReturnBuffers( 31 frame_producer_->RequestReturnBuffers(
58 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done_event))); 32 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done_event)));
Sergey Ulanov 2013/10/11 20:32:17 This doesn't really cleanup the buffers. ReturnBuf
Lambros 2013/10/15 23:50:33 Done.
59 done_event.Wait(); 33 done_event.Wait();
60 } 34 }
61 35
62 void JniFrameConsumer::set_frame_producer(FrameProducer* producer) { 36 void JniFrameConsumer::set_frame_producer(FrameProducer* producer) {
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);
47
48 if (!view_size_.equals(view_size)) {
49 // Drop the frame, since the data belongs to the previous generation,
50 // before SetSourceSize() called SetOutputSizeAndClip().
51 return;
52 }
53
54 // Copy pixels from |buffer| into the Java Bitmap.
55 // TODO(lambroslambrou): Optimize away this copy by having the VideoDecoder
56 // decode directly into the Bitmap's pixel memory. This currently doesn't
57 // work very well because the VideoDecoder writes the decoded data in BGRA,
58 // and then the R/B channels are swapped in place (on the decoding thread).
59 // If a repaint is triggered from a Java event handler, the unswapped pixels
60 // can sometimes appear on the display.
61 uint8* dest_buffer = static_cast<uint8*>(bitmap_->pixels());
62 webrtc::DesktopRect buffer_rect = webrtc::DesktopRect::MakeSize(view_size);
63
64 for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) {
65 webrtc::DesktopRect rect(i.rect());
Sergey Ulanov 2013/10/11 20:32:17 nit: make this a reference.
Lambros 2013/10/15 23:50:33 Done.
66 CopyRGB32Rect(buffer->data(), buffer->stride(), buffer_rect, dest_buffer,
67 bitmap_->stride(), buffer_rect, rect);
68 }
69
70 // TODO(lambroslambrou): Optimize this by only repainting the changed pixels.
73 jni_runtime_->RedrawCanvas(); 71 jni_runtime_->RedrawCanvas();
74 72
75 if (view_size.width() > view_size_.width() ||
76 view_size.height() > view_size_.height()) {
77 LOG(INFO) << "Existing buffer is too small";
78 view_size_ = view_size;
79
80 // Manually destroy the old buffer before allocating a new one to prevent
81 // our memory footprint from temporarily ballooning.
82 buffer_scoped.reset();
83 AllocateBuffer();
84 }
85
86 // Supply |frame_producer_| with a buffer to render the next frame into. 73 // Supply |frame_producer_| with a buffer to render the next frame into.
87 if (!in_dtor_) 74 if (!in_dtor_)
Sergey Ulanov 2013/10/11 20:32:17 Don't need this. This method will not be called fr
Lambros 2013/10/15 23:50:33 Done.
88 frame_producer_->DrawBuffer(buffer_scoped.release()); 75 frame_producer_->DrawBuffer(buffer_scoped.release());
89 } 76 }
90 77
91 void JniFrameConsumer::ReturnBuffer(webrtc::DesktopFrame* buffer) { 78 void JniFrameConsumer::ReturnBuffer(webrtc::DesktopFrame* buffer) {
92 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread()); 79 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
93 LOG(INFO) << "Returning image buffer"; 80 LOG(INFO) << "Returning image buffer";
94 delete buffer; 81 delete buffer;
95 } 82 }
96 83
97 void JniFrameConsumer::SetSourceSize(const webrtc::DesktopSize& source_size, 84 void JniFrameConsumer::SetSourceSize(const webrtc::DesktopSize& source_size,
98 const webrtc::DesktopVector& dpi) { 85 const webrtc::DesktopVector& dpi) {
99 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread()); 86 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
100 87
101 // We currently render the desktop 1:1 and perform pan/zoom scaling 88 // We currently render the desktop 1:1 and perform pan/zoom scaling
102 // and cropping on the managed canvas. 89 // and cropping on the managed canvas.
103 view_size_ = source_size; 90 view_size_ = source_size;
104 clip_area_ = webrtc::DesktopRect::MakeSize(view_size_); 91 clip_area_ = webrtc::DesktopRect::MakeSize(view_size_);
105 frame_producer_->SetOutputSizeAndClip(view_size_, clip_area_); 92 frame_producer_->SetOutputSizeAndClip(view_size_, clip_area_);
106 93
107 // Unless being destructed, allocate buffer and start drawing frames onto it. 94 // Unless being destructed, allocate buffer and start drawing frames onto it.
108 frame_producer_->RequestReturnBuffers(base::Bind( 95 AllocateBuffer();
109 &JniFrameConsumer::AllocateBuffer, base::Unretained(this)));
110 } 96 }
111 97
112 FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() { 98 FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() {
113 return FORMAT_RGBA; 99 return FORMAT_RGBA;
114 } 100 }
115 101
116 void JniFrameConsumer::AllocateBuffer() { 102 void JniFrameConsumer::AllocateBuffer() {
103 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
104
117 // Only do anything if we're not being destructed. 105 // Only do anything if we're not being destructed.
118 if (!in_dtor_) { 106 if (in_dtor_)
Sergey Ulanov 2013/10/11 20:32:17 Don't need this.
Lambros 2013/10/15 23:50:33 Done.
119 if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) { 107 return;
120 jni_runtime_->display_task_runner()->PostTask(FROM_HERE,
121 base::Bind(&JniFrameConsumer::AllocateBuffer,
122 base::Unretained(this)));
123 return;
124 }
125 108
126 DirectDesktopFrame* buffer = new DirectDesktopFrame(view_size_.width(), 109 webrtc::DesktopSize size(view_size_.width(), view_size_.height());
127 view_size_.height()); 110 webrtc::DesktopFrame* buffer = new webrtc::BasicDesktopFrame(size);
Sergey Ulanov 2013/10/11 20:32:17 nit: move this line just before DrawBuffer.
Lambros 2013/10/15 23:50:33 Done.
128 111
129 // Update Java's reference to the buffer and record of its dimensions. 112 // Allocate a new Bitmap, store references here, and pass it to Java.
130 jni_runtime_->UpdateImageBuffer(view_size_.width(), 113 JNIEnv* env = base::android::AttachCurrentThread();
131 view_size_.height(),
132 buffer->buffer());
133 114
134 frame_producer_->DrawBuffer(buffer); 115 // |bitmap_| must be deleted before |bitmap_global_ref_| is released.
135 } 116 bitmap_.reset();
117 bitmap_global_ref_.Reset(env, jni_runtime_->NewBitmap(size).obj());
118 bitmap_.reset(new gfx::JavaBitmap(bitmap_global_ref_.obj()));
119 jni_runtime_->UpdateFrameBitmap(bitmap_global_ref_.obj());
120
121 frame_producer_->DrawBuffer(buffer);
136 } 122 }
137 123
138 } // namespace remoting 124 } // namespace remoting
OLDNEW
« no previous file with comments | « 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