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

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

Issue 1288063004: Simplify FrameConsumer interface. Remove FrameProducer interface. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 4 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') | remoting/client/plugin/chromoting_instance.cc » ('j') | 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/stl_util.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "remoting/base/util.h" 9 #include "remoting/base/util.h"
12 #include "remoting/client/frame_producer.h"
13 #include "remoting/client/jni/chromoting_jni_instance.h" 10 #include "remoting/client/jni/chromoting_jni_instance.h"
14 #include "remoting/client/jni/chromoting_jni_runtime.h" 11 #include "remoting/client/jni/chromoting_jni_runtime.h"
15 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 12 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" 13 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
17 #include "ui/gfx/android/java_bitmap.h" 14 #include "ui/gfx/android/java_bitmap.h"
18 15
19 namespace remoting { 16 namespace remoting {
20 17
21 JniFrameConsumer::JniFrameConsumer( 18 class JniFrameConsumer::Renderer {
22 ChromotingJniRuntime* jni_runtime, 19 public:
23 scoped_refptr<ChromotingJniInstance> jni_instance) 20 Renderer(ChromotingJniRuntime* jni_runtime) : jni_runtime_(jni_runtime) {}
24 : jni_runtime_(jni_runtime), 21 ~Renderer() {
25 jni_instance_(jni_instance), 22 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
26 frame_producer_(nullptr) {
27 }
28
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
41 void JniFrameConsumer::set_frame_producer(FrameProducer* producer) {
42 frame_producer_ = producer;
43 }
44
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 DCHECK(!shape);
52
53 if (bitmap_->size().width() != buffer->size().width() ||
54 bitmap_->size().height() != buffer->size().height()) {
55 // Drop the frame, since the data belongs to the previous generation,
56 // before SetSourceSize() called SetOutputSizeAndClip().
57 FreeBuffer(buffer);
58 return;
59 } 23 }
60 24
61 // Copy pixels from |buffer| into the Java Bitmap. 25 void RenderFrame(scoped_ptr<webrtc::DesktopFrame> frame);
26
27 private:
28 // Used to obtain task runner references and make calls to Java methods.
29 ChromotingJniRuntime* jni_runtime_;
30
31 // This global reference is required, instead of a local reference, so it
32 // remains valid for the lifetime of |bitmap_| - gfx::JavaBitmap does not
33 // create its own global reference internally. And this global ref must be
34 // destroyed (released) after |bitmap_| is destroyed.
35 base::android::ScopedJavaGlobalRef<jobject> bitmap_global_ref_;
36
37 // Reference to the frame bitmap that is passed to Java when the frame is
38 // allocated. This provides easy access to the underlying pixels.
39 scoped_ptr<gfx::JavaBitmap> bitmap_;
40 };
41
42 // Function called on the display thread to render the frame.
43 void JniFrameConsumer::Renderer::RenderFrame(
44 scoped_ptr<webrtc::DesktopFrame> frame) {
45 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
46
47 if (!bitmap_ || bitmap_->size().width() != frame->size().width() ||
48 bitmap_->size().height() != frame->size().height()) {
49 // Allocate a new Bitmap, store references here, and pass it to Java.
50 JNIEnv* env = base::android::AttachCurrentThread();
51
52 // |bitmap_| must be deleted before |bitmap_global_ref_| is released.
53 bitmap_.reset();
54 bitmap_global_ref_.Reset(
55 env,
56 jni_runtime_->NewBitmap(frame->size().width(), frame->size().height())
57 .obj());
58 bitmap_.reset(new gfx::JavaBitmap(bitmap_global_ref_.obj()));
59 jni_runtime_->UpdateFrameBitmap(bitmap_global_ref_.obj());
60 }
61
62 // Copy pixels from |frame| into the Java Bitmap.
62 // TODO(lambroslambrou): Optimize away this copy by having the VideoDecoder 63 // TODO(lambroslambrou): Optimize away this copy by having the VideoDecoder
63 // decode directly into the Bitmap's pixel memory. This currently doesn't 64 // decode directly into the Bitmap's pixel memory. This currently doesn't
64 // work very well because the VideoDecoder writes the decoded data in BGRA, 65 // work very well because the VideoDecoder writes the decoded data in BGRA,
65 // and then the R/B channels are swapped in place (on the decoding thread). 66 // and then the R/B channels are swapped in place (on the decoding thread).
66 // If a repaint is triggered from a Java event handler, the unswapped pixels 67 // If a repaint is triggered from a Java event handler, the unswapped pixels
67 // can sometimes appear on the display. 68 // can sometimes appear on the display.
68 uint8* dest_buffer = static_cast<uint8*>(bitmap_->pixels()); 69 uint8* dest_buffer = static_cast<uint8*>(bitmap_->pixels());
69 webrtc::DesktopRect buffer_rect = webrtc::DesktopRect::MakeSize(view_size); 70 webrtc::DesktopRect buffer_rect =
70 71 webrtc::DesktopRect::MakeSize(frame->size());
71 for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) { 72 for (webrtc::DesktopRegion::Iterator i(frame->updated_region()); !i.IsAtEnd();
72 const webrtc::DesktopRect& rect(i.rect()); 73 i.Advance()) {
73 CopyRGB32Rect(buffer->data(), buffer->stride(), buffer_rect, dest_buffer, 74 CopyRGB32Rect(frame->data(), frame->stride(), buffer_rect, dest_buffer,
74 bitmap_->stride(), buffer_rect, rect); 75 bitmap_->stride(), buffer_rect, i.rect());
75 } 76 }
76 77
77 // TODO(lambroslambrou): Optimize this by only repainting the changed pixels.
78 base::TimeTicks start_time = base::TimeTicks::Now();
79 jni_runtime_->RedrawCanvas(); 78 jni_runtime_->RedrawCanvas();
80 jni_instance_->RecordPaintTime(
Lambros 2015/08/17 22:17:44 Are we recording the paint time stats somewhere el
Sergey Ulanov 2015/08/17 22:36:41 Yes, see SoftwareVideoRenderer, so this logic is n
81 (base::TimeTicks::Now() - start_time).InMilliseconds());
82
83 // Supply |frame_producer_| with a buffer to render the next frame into.
84 frame_producer_->DrawBuffer(buffer);
85 } 79 }
86 80
87 void JniFrameConsumer::ReturnBuffer(webrtc::DesktopFrame* buffer) { 81 JniFrameConsumer::JniFrameConsumer(
88 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread()); 82 ChromotingJniRuntime* jni_runtime)
89 FreeBuffer(buffer); 83 : jni_runtime_(jni_runtime),
84 renderer_(new Renderer(jni_runtime)),
85 weak_factory_(this) {}
86
87 JniFrameConsumer::~JniFrameConsumer() {
88 jni_runtime_->display_task_runner()->DeleteSoon(FROM_HERE,
89 renderer_.release());
90 } 90 }
91 91
92 void JniFrameConsumer::SetSourceSize(const webrtc::DesktopSize& source_size, 92 scoped_ptr<webrtc::DesktopFrame> JniFrameConsumer::AllocateFrame(
93 const webrtc::DesktopVector& dpi) { 93 const webrtc::DesktopSize& size) {
94 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread()); 94 return make_scoped_ptr(new webrtc::BasicDesktopFrame(size));
95 }
95 96
96 // We currently render the desktop 1:1 and perform pan/zoom scaling 97 void JniFrameConsumer::DrawFrame(scoped_ptr<webrtc::DesktopFrame> frame,
97 // and cropping on the managed canvas. 98 const base::Closure& done) {
98 clip_area_ = webrtc::DesktopRect::MakeSize(source_size); 99 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
99 frame_producer_->SetOutputSizeAndClip(source_size, clip_area_);
100 100
101 // Allocate buffer and start drawing frames onto it. 101 jni_runtime_->display_task_runner()->PostTaskAndReply(
102 AllocateBuffer(source_size); 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));
107 }
108
109 void JniFrameConsumer::OnFrameRendered(const base::Closure& done) {
110 DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
111
112 done.Run()
103 } 113 }
104 114
105 FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() { 115 FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() {
106 return FORMAT_RGBA; 116 return FORMAT_RGBA;
107 } 117 }
108 118
109 void JniFrameConsumer::AllocateBuffer(const webrtc::DesktopSize& source_size) {
110 DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
111
112 webrtc::DesktopSize size(source_size.width(), source_size.height());
113
114 // Allocate a new Bitmap, store references here, and pass it to Java.
115 JNIEnv* env = base::android::AttachCurrentThread();
116
117 // |bitmap_| must be deleted before |bitmap_global_ref_| is released.
118 bitmap_.reset();
119 bitmap_global_ref_.Reset(env, jni_runtime_->NewBitmap(size).obj());
120 bitmap_.reset(new gfx::JavaBitmap(bitmap_global_ref_.obj()));
121 jni_runtime_->UpdateFrameBitmap(bitmap_global_ref_.obj());
122
123 webrtc::DesktopFrame* buffer = new webrtc::BasicDesktopFrame(size);
124 buffers_.push_back(buffer);
125 frame_producer_->DrawBuffer(buffer);
126 }
127
128 void JniFrameConsumer::FreeBuffer(webrtc::DesktopFrame* buffer) {
129 DCHECK(std::find(buffers_.begin(), buffers_.end(), buffer) != buffers_.end());
130
131 buffers_.remove(buffer);
132 delete buffer;
133 }
134
135 } // namespace remoting 119 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/client/jni/jni_frame_consumer.h ('k') | remoting/client/plugin/chromoting_instance.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698