Index: media/gpu/android_video_surface_chooser_impl.cc |
diff --git a/media/gpu/android_video_surface_chooser_impl.cc b/media/gpu/android_video_surface_chooser_impl.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..fe4698f149edaf3f6ed99cbc8223c9776c77c63a |
--- /dev/null |
+++ b/media/gpu/android_video_surface_chooser_impl.cc |
@@ -0,0 +1,141 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "media/gpu/android_video_surface_chooser_impl.h" |
+ |
+namespace media { |
+ |
+AndroidVideoSurfaceChooserImpl::AndroidVideoSurfaceChooserImpl() |
+ : weak_factory_(this) {} |
+ |
+AndroidVideoSurfaceChooserImpl::~AndroidVideoSurfaceChooserImpl() {} |
+ |
+void AndroidVideoSurfaceChooserImpl::Initialize( |
+ UseOverlayCB use_overlay_cb, |
+ UseSurfaceTextureCB use_surface_texture_cb, |
+ StopUsingOverlayImmediatelyCB stop_immediately_cb, |
+ std::unique_ptr<AndroidOverlayFactory> initial_factory) { |
+ use_overlay_cb_ = std::move(use_overlay_cb); |
+ use_surface_texture_cb_ = std::move(use_surface_texture_cb); |
+ stop_immediately_cb_ = std::move(stop_immediately_cb); |
+ |
+ if (initial_factory) { |
+ // We requested an overlay. Wait to see if it succeeds or fails, since |
+ // hopefully this will be fast. On M+, we could ask it to start with a |
+ // SurfaceTexture either way. Before M, we can't switch surfaces. In that |
+ // case, it's important not to request a SurfaceTexture if we have an |
+ // overlay pending, so that we know not to transition to SurfaceTexture. |
+ client_notification_pending_ = true; |
+ ReplaceOverlayFactory(std::move(initial_factory)); |
+ } |
+ |
+ if (!overlay_) { |
+ // We haven't requested an overlay yet. Just ask the client to start with |
+ // SurfaceTexture now. |
+ use_surface_texture_cb_.Run(); |
+ return; |
+ } |
+} |
+ |
+void AndroidVideoSurfaceChooserImpl::ReplaceOverlayFactory( |
+ std::unique_ptr<AndroidOverlayFactory> factory) { |
+ // If we have an overlay, then we should transition away from it. It |
+ // doesn't matter if we have a new factory or no factory; the old overlay goes |
+ // with the old factory. |
+ |
+ // Notify the client to transition to SurfaceTexture, which it might already |
+ // be using. If |!client_notification_pending_|, then we're still during |
+ // initial startup, so we don't switch the client. Otherwise, we'd cause |
+ // pre-M to break, since we'd start with a SurfaceTexture in all cases. |
+ if (!client_notification_pending_) |
+ use_surface_texture_cb_.Run(); |
+ |
+ // If we started construction of an overlay, but it's not ready yet, then |
+ // just drop it. |
+ if (overlay_) |
+ overlay_ = nullptr; |
+ |
+ overlay_factory_ = std::move(factory); |
+ |
+ // If we don't have a new factory, then just stop here. |
+ if (!overlay_factory_) |
+ return; |
+ |
+ // We just got an overlay factory. Get an overlay immediately. This is |
+ // the right behavior to match what AVDA does with CVV. For DS, we should |
+ // probably check to see if it's a good idea, at least on M+. |
+ // Also note that for pre-M, AVDA depends on this behavior, else it will get |
+ // a SurfaceTexture then be unable to switch. Perhaps there should be a |
+ // pre-M implementation of this class that guarantees that it won't change |
+ // between the two. |
+ AndroidOverlay::Config config; |
+ // We bind all of our callbacks with weak ptrs, since we don't know how long |
+ // the client will hold on to overlays. They could, in principle, show up |
+ // long after the client is destroyed too, if codec destruction hangs. |
+ config.ready_cb = base::Bind(&AndroidVideoSurfaceChooserImpl::OnOverlayReady, |
+ weak_factory_.GetWeakPtr()); |
+ config.failed_cb = |
+ base::Bind(&AndroidVideoSurfaceChooserImpl::OnOverlayFailed, |
+ weak_factory_.GetWeakPtr()); |
+ config.destroyed_cb = |
+ base::Bind(&AndroidVideoSurfaceChooserImpl::OnSurfaceDestroyed, |
+ weak_factory_.GetWeakPtr()); |
+ // TODO(liberato): where do we get the initial size from? For CVV, it's |
+ // set via the natural size, and this is ignored anyway. The client should |
+ // provide this. |
+ config.rect = gfx::Rect(0, 0, 1, 1); |
+ overlay_ = overlay_factory_->CreateOverlay(config); |
+} |
+ |
+void AndroidVideoSurfaceChooserImpl::OnOverlayReady(AndroidOverlay* overlay) { |
+ // We |overlay_| is the only overlay for which we haven't gotten a ready |
watk
2017/05/02 21:00:01
The "We" needs deleting?
liberato (no reviews please)
2017/05/02 21:50:05
Done.
|
+ // callback yet. |
+ DCHECK_EQ(overlay, overlay_.get()); |
+ |
+ // If we haven't sent the client notification yet, we're doing so now. |
+ client_notification_pending_ = false; |
+ |
+ use_overlay_cb_.Run(std::move(overlay_)); |
+} |
+ |
+void AndroidVideoSurfaceChooserImpl::OnOverlayFailed(AndroidOverlay* overlay) { |
+ // We shouldn't get a failure for any overlay except the incoming one. |
+ DCHECK_EQ(overlay, overlay_.get()); |
+ |
+ // If we owe the client a notification callback, then send it. |
+ if (client_notification_pending_) { |
+ // The overlay that we requested failed, so notify the client to try |
+ // using SurfaceTexture instead. |
+ client_notification_pending_ = false; |
+ use_surface_texture_cb_.Run(); |
+ } |
+ |
+ overlay_ = nullptr; |
+} |
+ |
+void AndroidVideoSurfaceChooserImpl::OnSurfaceDestroyed( |
+ AndroidOverlay* overlay) { |
+ // We shouldn't get OnSurfaceDestroyed unless we previously got Ready. In |
+ // that case, we should have notified the client then. |
+ DCHECK(!client_notification_pending_); |
+ |
+ // We should not get OnSurfaceDestroyed for the incoming overlay, since we |
+ // should't get OnSurfaceDestroyed before OnSurfaceReady. OnSurfaceReady |
+ // should imply that this isn't the incoming overlay. |
+ DCHECK_NE(overlay_.get(), overlay); |
+ |
+ // We unconditionally send 'stop immediately', since we don't know what |
+ // overlay this is. Even if we revoked the overlay before, we may have done |
+ // so with the slow transition, which isn't good enough now. The client has |
+ // to be smart enoug to understand if it's currently using |overlay| or not. |
+ |
+ // Also remember that we don't know when the client drops the overlay, after |
+ // we revoke it. We can get callbacks until that happens, even if (for |
+ // example), the overlay is waiting for MediaCodec destruction. So, it's |
+ // likely that we'll send callbacks for overlays that the client is already |
+ // not using. |
+ stop_immediately_cb_.Run(overlay); |
+} |
+ |
+} // namespace media |