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

Unified 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: Keep track of buffers in JniFrameConsumer 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « remoting/client/jni/jni_frame_consumer.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: remoting/client/jni/jni_frame_consumer.cc
diff --git a/remoting/client/jni/jni_frame_consumer.cc b/remoting/client/jni/jni_frame_consumer.cc
index 36a81841771a0f9d9f4c537b3e653425ecff99db..1a560e93110f1a4f19ff28a9f371ccfd3572f597 100644
--- a/remoting/client/jni/jni_frame_consumer.cc
+++ b/remoting/client/jni/jni_frame_consumer.cc
@@ -6,57 +6,32 @@
#include "base/android/jni_android.h"
#include "base/logging.h"
+#include "base/stl_util.h"
#include "base/synchronization/waitable_event.h"
+#include "remoting/base/util.h"
#include "remoting/client/frame_producer.h"
#include "remoting/client/jni/chromoting_jni_runtime.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
-
-namespace {
-
-// Allocates its buffer within a Java direct byte buffer, where it can be
-// accessed by both native and managed code.
-class DirectDesktopFrame : public webrtc::BasicDesktopFrame {
- public:
- DirectDesktopFrame(int width, int height);
-
- virtual ~DirectDesktopFrame();
-
- jobject buffer() const {
- return buffer_;
- }
-
- private:
- jobject buffer_;
-};
-
-DirectDesktopFrame::DirectDesktopFrame(int width, int height)
- : webrtc::BasicDesktopFrame(webrtc::DesktopSize(width, height)) {
- JNIEnv* env = base::android::AttachCurrentThread();
- buffer_ = env->NewDirectByteBuffer(data(), stride()*height);
-}
-
-DirectDesktopFrame::~DirectDesktopFrame() {}
-
-} // namespace
+#include "ui/gfx/android/java_bitmap.h"
namespace remoting {
JniFrameConsumer::JniFrameConsumer(ChromotingJniRuntime* jni_runtime)
: jni_runtime_(jni_runtime),
- in_dtor_(false),
frame_producer_(NULL) {
}
JniFrameConsumer::~JniFrameConsumer() {
- // Stop giving the producer a buffer to work with.
- in_dtor_ = true;
-
- // Don't destroy the object until we've deleted the buffer.
+ // The producer should now return any pending buffers. At this point, however,
+ // ReturnBuffer() tasks scheduled by the producer will not be delivered,
+ // so we free all the buffers once the producer's queue is empty.
base::WaitableEvent done_event(true, false);
frame_producer_->RequestReturnBuffers(
base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done_event)));
done_event.Wait();
+
+ STLDeleteElements(&buffers_);
}
void JniFrameConsumer::set_frame_producer(FrameProducer* producer) {
@@ -69,29 +44,40 @@ void JniFrameConsumer::ApplyBuffer(const webrtc::DesktopSize& view_size,
const webrtc::DesktopRegion& region) {
DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
- scoped_ptr<webrtc::DesktopFrame> buffer_scoped(buffer);
- jni_runtime_->RedrawCanvas();
-
- if (view_size.width() > view_size_.width() ||
- view_size.height() > view_size_.height()) {
- LOG(INFO) << "Existing buffer is too small";
- view_size_ = view_size;
+ if (!view_size_.equals(view_size)) {
+ // Drop the frame, since the data belongs to the previous generation,
+ // before SetSourceSize() called SetOutputSizeAndClip().
+ FreeBuffer(buffer);
+ return;
+ }
- // Manually destroy the old buffer before allocating a new one to prevent
- // our memory footprint from temporarily ballooning.
- buffer_scoped.reset();
- AllocateBuffer();
+ // Copy pixels from |buffer| into the Java Bitmap.
+ // TODO(lambroslambrou): Optimize away this copy by having the VideoDecoder
+ // decode directly into the Bitmap's pixel memory. This currently doesn't
+ // work very well because the VideoDecoder writes the decoded data in BGRA,
+ // and then the R/B channels are swapped in place (on the decoding thread).
+ // If a repaint is triggered from a Java event handler, the unswapped pixels
+ // can sometimes appear on the display.
+ uint8* dest_buffer = static_cast<uint8*>(bitmap_->pixels());
+ webrtc::DesktopRect buffer_rect = webrtc::DesktopRect::MakeSize(view_size);
+
+ for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) {
+ const webrtc::DesktopRect& rect(i.rect());
+ CopyRGB32Rect(buffer->data(), buffer->stride(), buffer_rect, dest_buffer,
+ bitmap_->stride(), buffer_rect, rect);
}
+ // TODO(lambroslambrou): Optimize this by only repainting the changed pixels.
+ jni_runtime_->RedrawCanvas();
+
// Supply |frame_producer_| with a buffer to render the next frame into.
- if (!in_dtor_)
- frame_producer_->DrawBuffer(buffer_scoped.release());
+ frame_producer_->DrawBuffer(buffer);
}
void JniFrameConsumer::ReturnBuffer(webrtc::DesktopFrame* buffer) {
DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
LOG(INFO) << "Returning image buffer";
- delete buffer;
+ FreeBuffer(buffer);
}
void JniFrameConsumer::SetSourceSize(const webrtc::DesktopSize& source_size,
@@ -104,9 +90,8 @@ void JniFrameConsumer::SetSourceSize(const webrtc::DesktopSize& source_size,
clip_area_ = webrtc::DesktopRect::MakeSize(view_size_);
frame_producer_->SetOutputSizeAndClip(view_size_, clip_area_);
- // Unless being destructed, allocate buffer and start drawing frames onto it.
- frame_producer_->RequestReturnBuffers(base::Bind(
- &JniFrameConsumer::AllocateBuffer, base::Unretained(this)));
+ // Allocate buffer and start drawing frames onto it.
+ AllocateBuffer();
}
FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() {
@@ -114,25 +99,29 @@ FrameConsumer::PixelFormat JniFrameConsumer::GetPixelFormat() {
}
void JniFrameConsumer::AllocateBuffer() {
- // Only do anything if we're not being destructed.
- if (!in_dtor_) {
- if (!jni_runtime_->display_task_runner()->BelongsToCurrentThread()) {
- jni_runtime_->display_task_runner()->PostTask(FROM_HERE,
- base::Bind(&JniFrameConsumer::AllocateBuffer,
- base::Unretained(this)));
- return;
- }
-
- DirectDesktopFrame* buffer = new DirectDesktopFrame(view_size_.width(),
- view_size_.height());
-
- // Update Java's reference to the buffer and record of its dimensions.
- jni_runtime_->UpdateImageBuffer(view_size_.width(),
- view_size_.height(),
- buffer->buffer());
-
- frame_producer_->DrawBuffer(buffer);
- }
+ DCHECK(jni_runtime_->display_task_runner()->BelongsToCurrentThread());
+
+ webrtc::DesktopSize size(view_size_.width(), view_size_.height());
+
+ // Allocate a new Bitmap, store references here, and pass it to Java.
+ JNIEnv* env = base::android::AttachCurrentThread();
+
+ // |bitmap_| must be deleted before |bitmap_global_ref_| is released.
+ bitmap_.reset();
+ bitmap_global_ref_.Reset(env, jni_runtime_->NewBitmap(size).obj());
+ bitmap_.reset(new gfx::JavaBitmap(bitmap_global_ref_.obj()));
+ jni_runtime_->UpdateFrameBitmap(bitmap_global_ref_.obj());
+
+ webrtc::DesktopFrame* buffer = new webrtc::BasicDesktopFrame(size);
+ buffers_.push_back(buffer);
+ frame_producer_->DrawBuffer(buffer);
+}
+
+void JniFrameConsumer::FreeBuffer(webrtc::DesktopFrame* buffer) {
+ DCHECK(std::find(buffers_.begin(), buffers_.end(), buffer) != buffers_.end());
+
+ buffers_.remove(buffer);
+ delete buffer;
}
} // namespace remoting
« 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