summaryrefslogtreecommitdiffstats
path: root/content/renderer/media
diff options
context:
space:
mode:
authorscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-15 17:44:32 +0000
committerscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-15 17:44:32 +0000
commit75e145a8f1304b8b16490f4a43b65764df264471 (patch)
treed18f45a2de5993031b99917b19c1a337adf3bbe1 /content/renderer/media
parentfdd7f8589d39672f556d79bc8c95d021fd8f088f (diff)
downloadchromium_src-75e145a8f1304b8b16490f4a43b65764df264471.zip
chromium_src-75e145a8f1304b8b16490f4a43b65764df264471.tar.gz
chromium_src-75e145a8f1304b8b16490f4a43b65764df264471.tar.bz2
Migrate VideoDecoder::HasAlpha() and associated plumbing into VideoFrameCompositor.
Opacity can be derived by inspecting the format of the video frames as they pass through VideoFrameCompositor. Similar to changes in natural size, changes in opacity are now detected. Finally, make the call directly to WebLayerImpl instead of plumbing values through HTMLMediaElement. BUG=110814 Review URL: https://codereview.chromium.org/235933012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@263906 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer/media')
-rw-r--r--content/renderer/media/video_frame_compositor.cc37
-rw-r--r--content/renderer/media/video_frame_compositor.h11
-rw-r--r--content/renderer/media/video_frame_compositor_unittest.cc49
-rw-r--r--content/renderer/media/webmediaplayer_impl.cc32
-rw-r--r--content/renderer/media/webmediaplayer_impl.h9
-rw-r--r--content/renderer/media/webmediaplayer_ms.cc2
6 files changed, 120 insertions, 20 deletions
diff --git a/content/renderer/media/video_frame_compositor.cc b/content/renderer/media/video_frame_compositor.cc
index bf11d15..e991357 100644
--- a/content/renderer/media/video_frame_compositor.cc
+++ b/content/renderer/media/video_frame_compositor.cc
@@ -13,13 +13,34 @@
namespace content {
+static bool IsOpaque(const scoped_refptr<media::VideoFrame>& frame) {
+ switch (frame->format()) {
+ case media::VideoFrame::UNKNOWN:
+ case media::VideoFrame::YV12:
+ case media::VideoFrame::YV12J:
+ case media::VideoFrame::YV16:
+ case media::VideoFrame::I420:
+ return true;
+
+ case media::VideoFrame::YV12A:
+#if defined(VIDEO_HOLE)
+ case media::VideoFrame::HOLE:
+#endif // defined(VIDEO_HOLE)
+ case media::VideoFrame::NATIVE_TEXTURE:
+ break;
+ }
+ return false;
+}
+
class VideoFrameCompositor::Internal : public cc::VideoFrameProvider {
public:
Internal(
const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner,
- const base::Callback<void(gfx::Size)>& natural_size_changed_cb)
+ const base::Callback<void(gfx::Size)>& natural_size_changed_cb,
+ const base::Callback<void(bool)>& opacity_changed_cb)
: compositor_task_runner_(compositor_task_runner),
natural_size_changed_cb_(natural_size_changed_cb),
+ opacity_changed_cb_(opacity_changed_cb),
client_(NULL),
compositor_notification_pending_(false),
frames_dropped_before_compositor_was_notified_(0) {}
@@ -41,6 +62,10 @@ class VideoFrameCompositor::Internal : public cc::VideoFrameProvider {
natural_size_changed_cb_.Run(frame->natural_size());
}
+ if (!current_frame_ || IsOpaque(current_frame_) != IsOpaque(frame)) {
+ opacity_changed_cb_.Run(IsOpaque(frame));
+ }
+
current_frame_ = frame;
// Count frames as dropped if and only if we updated the frame but didn't
@@ -94,7 +119,8 @@ class VideoFrameCompositor::Internal : public cc::VideoFrameProvider {
}
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
- base::Callback<void(gfx::Size)>natural_size_changed_cb_;
+ base::Callback<void(gfx::Size)> natural_size_changed_cb_;
+ base::Callback<void(bool)> opacity_changed_cb_;
cc::VideoFrameProvider::Client* client_;
@@ -108,8 +134,11 @@ class VideoFrameCompositor::Internal : public cc::VideoFrameProvider {
VideoFrameCompositor::VideoFrameCompositor(
const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner,
- const base::Callback<void(gfx::Size)>& natural_size_changed_cb)
- : internal_(new Internal(compositor_task_runner, natural_size_changed_cb)) {
+ const base::Callback<void(gfx::Size)>& natural_size_changed_cb,
+ const base::Callback<void(bool)>& opacity_changed_cb)
+ : internal_(new Internal(compositor_task_runner,
+ natural_size_changed_cb,
+ opacity_changed_cb)) {
}
VideoFrameCompositor::~VideoFrameCompositor() {
diff --git a/content/renderer/media/video_frame_compositor.h b/content/renderer/media/video_frame_compositor.h
index 7a8b0a8..21654bd 100644
--- a/content/renderer/media/video_frame_compositor.h
+++ b/content/renderer/media/video_frame_compositor.h
@@ -41,9 +41,18 @@ class CONTENT_EXPORT VideoFrameCompositor {
// frame whenever a change in natural size is detected. It is not called the
// first time UpdateCurrentFrame() is called. Run on the same thread as the
// caller of UpdateCurrentFrame().
+ //
+ // |opacity_changed_cb| is run when a change in opacity is detected. It *is*
+ // called the first time UpdateCurrentFrame() is called. Run on the same
+ // thread as the caller of UpdateCurrentFrame().
+ //
+ // TODO(scherkus): Investigate the inconsistency between the callbacks with
+ // respect to why we don't call |natural_size_changed_cb| on the first frame.
+ // I suspect it was for historical reasons that no longer make sense.
VideoFrameCompositor(
const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner,
- const base::Callback<void(gfx::Size)>& natural_size_changed_cb);
+ const base::Callback<void(gfx::Size)>& natural_size_changed_cb,
+ const base::Callback<void(bool)>& opacity_changed_cb);
~VideoFrameCompositor();
cc::VideoFrameProvider* GetVideoFrameProvider();
diff --git a/content/renderer/media/video_frame_compositor_unittest.cc b/content/renderer/media/video_frame_compositor_unittest.cc
index 19c12bd..7aecad0 100644
--- a/content/renderer/media/video_frame_compositor_unittest.cc
+++ b/content/renderer/media/video_frame_compositor_unittest.cc
@@ -20,9 +20,13 @@ class VideoFrameCompositorTest : public testing::Test,
: compositor_(new VideoFrameCompositor(
message_loop_.message_loop_proxy(),
base::Bind(&VideoFrameCompositorTest::NaturalSizeChanged,
+ base::Unretained(this)),
+ base::Bind(&VideoFrameCompositorTest::OpacityChanged,
base::Unretained(this)))),
did_receive_frame_count_(0),
- natural_size_changed_count_(0) {
+ natural_size_changed_count_(0),
+ opacity_changed_count_(0),
+ opaque_(false) {
provider()->SetVideoFrameProviderClient(this);
}
@@ -41,6 +45,9 @@ class VideoFrameCompositorTest : public testing::Test,
int natural_size_changed_count() { return natural_size_changed_count_; }
gfx::Size natural_size() { return natural_size_; }
+ int opacity_changed_count() { return opacity_changed_count_; }
+ bool opaque() { return opaque_; }
+
private:
// cc::VideoFrameProvider::Client implementation.
virtual void StopUsingProvider() OVERRIDE {}
@@ -54,11 +61,18 @@ class VideoFrameCompositorTest : public testing::Test,
natural_size_ = natural_size;
}
+ void OpacityChanged(bool opaque) {
+ ++opacity_changed_count_;
+ opaque_ = opaque;
+ }
+
base::MessageLoop message_loop_;
scoped_ptr<VideoFrameCompositor> compositor_;
int did_receive_frame_count_;
int natural_size_changed_count_;
gfx::Size natural_size_;
+ int opacity_changed_count_;
+ bool opaque_;
DISALLOW_COPY_AND_ASSIGN(VideoFrameCompositorTest);
};
@@ -125,6 +139,39 @@ TEST_F(VideoFrameCompositorTest, NaturalSizeChanged) {
EXPECT_EQ(2, natural_size_changed_count());
}
+TEST_F(VideoFrameCompositorTest, OpacityChanged) {
+ gfx::Size size(8, 8);
+ gfx::Rect rect(gfx::Point(0, 0), size);
+ scoped_refptr<VideoFrame> opaque_frame = VideoFrame::CreateFrame(
+ VideoFrame::YV12, size, rect, size, base::TimeDelta());
+ scoped_refptr<VideoFrame> not_opaque_frame = VideoFrame::CreateFrame(
+ VideoFrame::YV12A, size, rect, size, base::TimeDelta());
+
+ // Initial expectations.
+ EXPECT_FALSE(opaque());
+ EXPECT_EQ(0, opacity_changed_count());
+
+ // Callback is fired for the first frame.
+ compositor()->UpdateCurrentFrame(not_opaque_frame);
+ EXPECT_FALSE(opaque());
+ EXPECT_EQ(1, opacity_changed_count());
+
+ // Callback shouldn't be first subsequent times with same opaqueness.
+ compositor()->UpdateCurrentFrame(not_opaque_frame);
+ EXPECT_FALSE(opaque());
+ EXPECT_EQ(1, opacity_changed_count());
+
+ // Callback is fired when using opacity changes.
+ compositor()->UpdateCurrentFrame(opaque_frame);
+ EXPECT_TRUE(opaque());
+ EXPECT_EQ(2, opacity_changed_count());
+
+ // Callback shouldn't be first subsequent times with same opaqueness.
+ compositor()->UpdateCurrentFrame(opaque_frame);
+ EXPECT_TRUE(opaque());
+ EXPECT_EQ(2, opacity_changed_count());
+}
+
TEST_F(VideoFrameCompositorTest, GetFramesDroppedBeforeCompositorWasNotified) {
scoped_refptr<VideoFrame> frame = VideoFrame::CreateEOSFrame();
diff --git a/content/renderer/media/webmediaplayer_impl.cc b/content/renderer/media/webmediaplayer_impl.cc
index afce478..919f636 100644
--- a/content/renderer/media/webmediaplayer_impl.cc
+++ b/content/renderer/media/webmediaplayer_impl.cc
@@ -154,6 +154,7 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()),
media_log_(new RenderMediaLog()),
pipeline_(media_loop_, media_log_.get()),
+ opaque_(false),
paused_(true),
seeking_(false),
playback_rate_(0.0f),
@@ -173,7 +174,8 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
(RenderThreadImpl::current()->compositor_message_loop_proxy()
? RenderThreadImpl::current()->compositor_message_loop_proxy()
: base::MessageLoopProxy::current()),
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnNaturalSizeChange)),
+ BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnNaturalSizeChanged),
+ BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnOpacityChanged)),
text_track_index_(0),
web_cdm_(NULL) {
media_log_->AddEvent(
@@ -981,7 +983,11 @@ void WebMediaPlayerImpl::OnPipelineMetadata(
DCHECK(!video_weblayer_);
video_weblayer_.reset(new webkit::WebLayerImpl(
cc::VideoLayer::Create(compositor_.GetVideoFrameProvider())));
+
client_->setWebLayer(video_weblayer_.get());
+ // TODO(scherkus): Remove once plumbing from HTMLMediaElement is removed.
+ client_->setOpaque(opaque_);
+ video_weblayer_->setOpaque(opaque_);
}
// TODO(scherkus): This should be handled by HTMLMediaElement and controls
@@ -1103,12 +1109,6 @@ void WebMediaPlayerImpl::OnKeyMessage(const std::string& session_id,
default_url_gurl);
}
-void WebMediaPlayerImpl::SetOpaque(bool opaque) {
- DCHECK(main_loop_->BelongsToCurrentThread());
-
- client_->setOpaque(opaque);
-}
-
void WebMediaPlayerImpl::DataSourceInitialized(const GURL& gurl, bool success) {
DCHECK(main_loop_->BelongsToCurrentThread());
@@ -1204,7 +1204,6 @@ void WebMediaPlayerImpl::StartPipeline() {
video_decoders.Pass(),
set_decryptor_ready_cb,
base::Bind(&WebMediaPlayerImpl::FrameReady, base::Unretained(this)),
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::SetOpaque),
true));
filter_collection->SetVideoRenderer(video_renderer.Pass());
@@ -1226,7 +1225,7 @@ void WebMediaPlayerImpl::StartPipeline() {
BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineSeek),
BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineMetadata),
BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelinePrerollCompleted),
- BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChange));
+ BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged));
}
void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
@@ -1273,14 +1272,14 @@ double WebMediaPlayerImpl::GetPipelineDuration() const {
return duration.InSecondsF();
}
-void WebMediaPlayerImpl::OnDurationChange() {
+void WebMediaPlayerImpl::OnDurationChanged() {
if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
return;
client_->durationChanged();
}
-void WebMediaPlayerImpl::OnNaturalSizeChange(gfx::Size size) {
+void WebMediaPlayerImpl::OnNaturalSizeChanged(gfx::Size size) {
DCHECK(main_loop_->BelongsToCurrentThread());
DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged");
@@ -1292,6 +1291,17 @@ void WebMediaPlayerImpl::OnNaturalSizeChange(gfx::Size size) {
client_->sizeChanged();
}
+void WebMediaPlayerImpl::OnOpacityChanged(bool opaque) {
+ DCHECK(main_loop_->BelongsToCurrentThread());
+ DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing);
+
+ opaque_ = opaque;
+ // TODO(scherkus): Remove once plumbing from HTMLMediaElement is removed.
+ client_->setOpaque(opaque);
+ if (video_weblayer_)
+ video_weblayer_->setOpaque(opaque_);
+}
+
void WebMediaPlayerImpl::FrameReady(
const scoped_refptr<media::VideoFrame>& frame) {
compositor_.UpdateCurrentFrame(frame);
diff --git a/content/renderer/media/webmediaplayer_impl.h b/content/renderer/media/webmediaplayer_impl.h
index 2a16e22..ed089a2 100644
--- a/content/renderer/media/webmediaplayer_impl.h
+++ b/content/renderer/media/webmediaplayer_impl.h
@@ -184,7 +184,6 @@ class WebMediaPlayerImpl
const std::vector<uint8>& init_data);
void OnAddTextTrack(const media::TextTrackConfig& config,
const media::AddTextTrackDoneCB& done_cb);
- void SetOpaque(bool);
private:
// Called after |defer_load_cb_| has decided to allow the load. If
@@ -228,8 +227,9 @@ class WebMediaPlayerImpl
double GetPipelineDuration() const;
// Callbacks from |pipeline_| that are forwarded to |client_|.
- void OnDurationChange();
- void OnNaturalSizeChange(gfx::Size size);
+ void OnDurationChanged();
+ void OnNaturalSizeChanged(gfx::Size size);
+ void OnOpacityChanged(bool opaque);
// Called by VideoRendererImpl on its internal thread with the new frame to be
// painted.
@@ -265,6 +265,9 @@ class WebMediaPlayerImpl
// Cache of metadata for answering hasAudio(), hasVideo(), and naturalSize().
media::PipelineMetadata pipeline_metadata_;
+ // Whether the video is known to be opaque or not.
+ bool opaque_;
+
// Playback state.
//
// TODO(scherkus): we have these because Pipeline favours the simplicity of a
diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc
index 6533bd0..d4d4d4a 100644
--- a/content/renderer/media/webmediaplayer_ms.cc
+++ b/content/renderer/media/webmediaplayer_ms.cc
@@ -152,6 +152,7 @@ void WebMediaPlayerMS::load(LoadType load_type,
RenderFrame::FromWebFrame(frame_)->GetRoutingID());
if (video_frame_provider_.get() || audio_renderer_.get()) {
+ // TODO(scherkus): Remove once plumbing from HTMLMediaElement is removed.
GetClient()->setOpaque(true);
if (audio_renderer_.get())
audio_renderer_->Start();
@@ -417,6 +418,7 @@ void WebMediaPlayerMS::OnFrameAvailable(
if (video_frame_provider_) {
video_weblayer_.reset(
new webkit::WebLayerImpl(cc::VideoLayer::Create(this)));
+ video_weblayer_->setOpaque(true);
GetClient()->setWebLayer(video_weblayer_.get());
}
}