diff options
author | halliwell <halliwell@chromium.org> | 2015-06-26 14:41:14 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-26 21:41:55 +0000 |
commit | 80201d111bd6f4221b70dd2cf101153e71945fca (patch) | |
tree | 57496c7e67b7bbdb087ccf6946fe407590a4b063 /chromecast | |
parent | 1d1de23ef899e6cb6b4ba519532743317ff23bcd (diff) | |
download | chromium_src-80201d111bd6f4221b70dd2cf101153e71945fca.zip chromium_src-80201d111bd6f4221b70dd2cf101153e71945fca.tar.gz chromium_src-80201d111bd6f4221b70dd2cf101153e71945fca.tar.bz2 |
Enables use of overlays for Cast video playback
This updates Cast media pipeline to use overlays instead of VIDEO_HOLE
codepath for placing video into a separate hardware plane. A switch
has been added to allow reverting to the old behaviour, we can remove
this once the new path has had some testing.
BUG=469374
Review URL: https://codereview.chromium.org/1210903003
Cr-Commit-Position: refs/heads/master@{#336460}
Diffstat (limited to 'chromecast')
-rw-r--r-- | chromecast/base/chromecast_switches.cc | 5 | ||||
-rw-r--r-- | chromecast/base/chromecast_switches.h | 1 | ||||
-rw-r--r-- | chromecast/browser/cast_content_browser_client.cc | 2 | ||||
-rw-r--r-- | chromecast/media/DEPS | 1 | ||||
-rw-r--r-- | chromecast/media/cma/filters/cma_renderer.cc | 21 | ||||
-rw-r--r-- | chromecast/media/cma/filters/cma_renderer.h | 10 | ||||
-rw-r--r-- | chromecast/media/cma/filters/hole_frame_factory.cc | 76 | ||||
-rw-r--r-- | chromecast/media/cma/filters/hole_frame_factory.h | 50 | ||||
-rw-r--r-- | chromecast/media/cma/test/cma_end_to_end_test.cc | 19 | ||||
-rw-r--r-- | chromecast/media/media.gyp | 4 | ||||
-rw-r--r-- | chromecast/renderer/cast_content_renderer_client.cc | 3 | ||||
-rw-r--r-- | chromecast/renderer/cast_content_renderer_client.h | 1 | ||||
-rw-r--r-- | chromecast/renderer/media/chromecast_media_renderer_factory.cc | 6 | ||||
-rw-r--r-- | chromecast/renderer/media/chromecast_media_renderer_factory.h | 3 |
14 files changed, 185 insertions, 17 deletions
diff --git a/chromecast/base/chromecast_switches.cc b/chromecast/base/chromecast_switches.cc index 1379f3d..643e95a 100644 --- a/chromecast/base/chromecast_switches.cc +++ b/chromecast/base/chromecast_switches.cc @@ -12,6 +12,11 @@ const char kEnableCmaMediaPipeline[] = "enable-cma-media-pipeline"; // The bitmask of codecs (media_caps.h) supported by the current HDMI sink. const char kHdmiSinkSupportedCodecs[] = "hdmi-sink-supported-codecs"; +// Enables old (VIDEO_HOLE) hole punching codepath for video plane. +// TODO(halliwell): remove switch and old codepath once overlays +// are well established. +const char kEnableLegacyHolePunching[] = "enable-legacy-hole-punching"; + // Enable file accesses. It should not be enabled for most Cast devices. const char kEnableLocalFileAccesses[] = "enable-local-file-accesses"; diff --git a/chromecast/base/chromecast_switches.h b/chromecast/base/chromecast_switches.h index c5ba5cb..5fff8bb 100644 --- a/chromecast/base/chromecast_switches.h +++ b/chromecast/base/chromecast_switches.h @@ -12,6 +12,7 @@ namespace switches { // Media switches extern const char kEnableCmaMediaPipeline[]; extern const char kHdmiSinkSupportedCodecs[]; +extern const char kEnableLegacyHolePunching[]; // Content-implementation switches extern const char kEnableLocalFileAccesses[]; diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index 6f4f4d0..5b2c054 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc @@ -196,6 +196,8 @@ void CastContentBrowserClient::AppendExtraCommandLineSwitches( if (browser_command_line->HasSwitch(switches::kEnableCmaMediaPipeline)) command_line->AppendSwitch(switches::kEnableCmaMediaPipeline); + if (browser_command_line->HasSwitch(switches::kEnableLegacyHolePunching)) + command_line->AppendSwitch(switches::kEnableLegacyHolePunching); } #if defined(OS_LINUX) diff --git a/chromecast/media/DEPS b/chromecast/media/DEPS index f2506bb..f980e38 100644 --- a/chromecast/media/DEPS +++ b/chromecast/media/DEPS @@ -1,4 +1,5 @@ include_rules = [ + "+gpu", "+media/base", "+media/cdm", "+media/renderers", diff --git a/chromecast/media/cma/filters/cma_renderer.cc b/chromecast/media/cma/filters/cma_renderer.cc index 9d0a5ba..276d477 100644 --- a/chromecast/media/cma/filters/cma_renderer.cc +++ b/chromecast/media/cma/filters/cma_renderer.cc @@ -12,6 +12,7 @@ #include "chromecast/media/cma/base/balanced_media_task_runner_factory.h" #include "chromecast/media/cma/base/cma_logging.h" #include "chromecast/media/cma/filters/demuxer_stream_adapter.h" +#include "chromecast/media/cma/filters/hole_frame_factory.h" #include "chromecast/media/cma/pipeline/audio_pipeline.h" #include "chromecast/media/cma/pipeline/av_pipeline_client.h" #include "chromecast/media/cma/pipeline/media_pipeline.h" @@ -22,8 +23,8 @@ #include "media/base/demuxer_stream_provider.h" #include "media/base/pipeline_status.h" #include "media/base/time_delta_interpolator.h" -#include "media/base/video_frame.h" #include "media/base/video_renderer_sink.h" +#include "media/renderers/gpu_video_accelerator_factories.h" #include "ui/gfx/geometry/size.h" namespace chromecast { @@ -38,8 +39,10 @@ const base::TimeDelta kMaxDeltaFetcher( } // namespace -CmaRenderer::CmaRenderer(scoped_ptr<MediaPipeline> media_pipeline, - ::media::VideoRendererSink* video_renderer_sink) +CmaRenderer::CmaRenderer( + scoped_ptr<MediaPipeline> media_pipeline, + ::media::VideoRendererSink* video_renderer_sink, + const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories) : media_task_runner_factory_( new BalancedMediaTaskRunnerFactory(kMaxDeltaFetcher)), media_pipeline_(media_pipeline.Pass()), @@ -54,6 +57,7 @@ CmaRenderer::CmaRenderer(scoped_ptr<MediaPipeline> media_pipeline, received_video_eos_(false), initial_natural_size_(gfx::Size()), initial_video_hole_created_(false), + gpu_factories_(gpu_factories), time_interpolator_( new ::media::TimeDeltaInterpolator(&default_tick_clock_)), playback_rate_(1.0), @@ -95,6 +99,9 @@ void CmaRenderer::Initialize( DCHECK(demuxer_stream_provider->GetStream(::media::DemuxerStream::AUDIO) || demuxer_stream_provider->GetStream(::media::DemuxerStream::VIDEO)); + // Deferred from ctor so as to initialise on correct thread. + hole_frame_factory_.reset(new HoleFrameFactory(gpu_factories_)); + BeginStateTransition(); demuxer_stream_provider_ = demuxer_stream_provider; @@ -152,7 +159,6 @@ void CmaRenderer::StartPlayingFrom(base::TimeDelta time) { return; } -#if defined(VIDEO_HOLE) // Create a video hole frame just before starting playback. // Note that instead of creating the video hole frame in Initialize(), we do // it here because paint_cb_ (which eventually calls OnOpacityChanged) @@ -163,9 +169,8 @@ void CmaRenderer::StartPlayingFrom(base::TimeDelta time) { if (!initial_video_hole_created_) { initial_video_hole_created_ = true; video_renderer_sink_->PaintFrameUsingOldRenderingPath( - ::media::VideoFrame::CreateHoleFrame(initial_natural_size_)); + hole_frame_factory_->CreateHoleFrame(initial_natural_size_)); } -#endif { base::AutoLock auto_lock(time_interpolator_lock_); @@ -383,10 +388,8 @@ void CmaRenderer::OnStatisticsUpdated( void CmaRenderer::OnNaturalSizeChanged(const gfx::Size& size) { DCHECK(thread_checker_.CalledOnValidThread()); -#if defined(VIDEO_HOLE) video_renderer_sink_->PaintFrameUsingOldRenderingPath( - ::media::VideoFrame::CreateHoleFrame(size)); -#endif + hole_frame_factory_->CreateHoleFrame(size)); } void CmaRenderer::OnPlaybackTimeUpdated( diff --git a/chromecast/media/cma/filters/cma_renderer.h b/chromecast/media/cma/filters/cma_renderer.h index eb4c600..f76226b 100644 --- a/chromecast/media/cma/filters/cma_renderer.h +++ b/chromecast/media/cma/filters/cma_renderer.h @@ -21,6 +21,7 @@ class SingleThreadTaskRunner; namespace media { class DemuxerStreamProvider; +class GpuVideoAcceleratorFactories; class TimeDeltaInterpolator; class VideoFrame; class VideoRendererSink; @@ -30,13 +31,16 @@ namespace chromecast { namespace media { class AudioPipeline; class BalancedMediaTaskRunnerFactory; +class HoleFrameFactory; class MediaPipeline; class VideoPipeline; class CmaRenderer : public ::media::Renderer { public: CmaRenderer(scoped_ptr<MediaPipeline> media_pipeline, - ::media::VideoRendererSink* video_renderer_sink); + ::media::VideoRendererSink* video_renderer_sink, + const scoped_refptr<::media::GpuVideoAcceleratorFactories>& + gpu_factories); ~CmaRenderer() override; // ::media::Renderer implementation: @@ -125,9 +129,11 @@ class CmaRenderer : public ::media::Renderer { bool received_audio_eos_; bool received_video_eos_; - // Data members for helping the creation of the initial video hole frame. + // Data members for helping the creation of the video hole frame. gfx::Size initial_natural_size_; bool initial_video_hole_created_; + scoped_refptr<::media::GpuVideoAcceleratorFactories> gpu_factories_; + scoped_ptr<HoleFrameFactory> hole_frame_factory_; // Lock protecting access to |time_interpolator_|. base::Lock time_interpolator_lock_; diff --git a/chromecast/media/cma/filters/hole_frame_factory.cc b/chromecast/media/cma/filters/hole_frame_factory.cc new file mode 100644 index 0000000..dfb9a33 --- /dev/null +++ b/chromecast/media/cma/filters/hole_frame_factory.cc @@ -0,0 +1,76 @@ +// Copyright 2015 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 "chromecast/media/cma/filters/hole_frame_factory.h" + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/location.h" +#include "chromecast/base/chromecast_switches.h" +#include "gpu/GLES2/gl2extchromium.h" +#include "gpu/command_buffer/client/gles2_interface.h" +#include "media/base/video_frame.h" +#include "media/renderers/gpu_video_accelerator_factories.h" + +namespace chromecast { +namespace media { + +HoleFrameFactory::HoleFrameFactory( + const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories) + : gpu_factories_(gpu_factories), + texture_(0), + image_id_(0), + use_legacy_hole_punching_( + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableLegacyHolePunching)) { + if (!use_legacy_hole_punching_) { + gpu::gles2::GLES2Interface* gl = gpu_factories_->GetGLES2Interface(); + CHECK(gl); + + gl->GenTextures(1, &texture_); + gl->BindTexture(GL_TEXTURE_2D, texture_); + image_id_ = gl->CreateGpuMemoryBufferImageCHROMIUM(1, 1, GL_RGBA, + GL_SCANOUT_CHROMIUM); + gl->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id_); + + gl->GenMailboxCHROMIUM(mailbox_.name); + gl->ProduceTextureDirectCHROMIUM(texture_, GL_TEXTURE_2D, mailbox_.name); + } +} + +HoleFrameFactory::~HoleFrameFactory() { + if (texture_ != 0) { + gpu::gles2::GLES2Interface* gl = gpu_factories_->GetGLES2Interface(); + gl->BindTexture(GL_TEXTURE_2D, texture_); + gl->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id_); + gl->DeleteTextures(1, &texture_); + gl->DestroyImageCHROMIUM(image_id_); + } +} + +scoped_refptr<::media::VideoFrame> HoleFrameFactory::CreateHoleFrame( + const gfx::Size& size) { + if (use_legacy_hole_punching_) { +#if defined(VIDEO_HOLE) + return ::media::VideoFrame::CreateHoleFrame(size); +#endif + NOTREACHED(); + } + + scoped_refptr<::media::VideoFrame> frame = + ::media::VideoFrame::WrapNativeTexture( + ::media::VideoFrame::XRGB, + gpu::MailboxHolder(mailbox_, GL_TEXTURE_2D, 0), + ::media::VideoFrame::ReleaseMailboxCB(), + size, // coded_size + gfx::Rect(size), // visible rect + size, // natural size + base::TimeDelta()); // timestamp + frame->metadata()->SetBoolean(::media::VideoFrameMetadata::ALLOW_OVERLAY, + true); + return frame; +} + +} // namespace media +} // namespace chromecast diff --git a/chromecast/media/cma/filters/hole_frame_factory.h b/chromecast/media/cma/filters/hole_frame_factory.h new file mode 100644 index 0000000..0b08cbf --- /dev/null +++ b/chromecast/media/cma/filters/hole_frame_factory.h @@ -0,0 +1,50 @@ +// Copyright 2015 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. + +#ifndef CHROMECAST_MEDIA_CMA_FILTERS_HOLE_FRAME_FACTORY_H_ +#define CHROMECAST_MEDIA_CMA_FILTERS_HOLE_FRAME_FACTORY_H_ + +#include <GLES2/gl2.h> + +#include "base/memory/ref_counted.h" +#include "gpu/command_buffer/common/mailbox.h" + +namespace gfx { +class Size; +} + +namespace media { +class GpuVideoAcceleratorFactories; +class VideoFrame; +} + +namespace chromecast { +namespace media { + +// Creates VideoFrames for CMA - currently supports both overlay frames +// (native textures that get turned into transparent holes in the browser +// compositor), and legacy VIDEO_HOLE codepath. +// All calls (including ctor/dtor) must be on media thread. +class HoleFrameFactory { + public: + HoleFrameFactory(const scoped_refptr<::media::GpuVideoAcceleratorFactories>& + gpu_factories); + ~HoleFrameFactory(); + + scoped_refptr<::media::VideoFrame> CreateHoleFrame(const gfx::Size& size); + + private: + scoped_refptr<::media::GpuVideoAcceleratorFactories> gpu_factories_; + gpu::Mailbox mailbox_; + GLuint texture_; + GLuint image_id_; + bool use_legacy_hole_punching_; + + DISALLOW_COPY_AND_ASSIGN(HoleFrameFactory); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_FILTERS_HOLE_FRAME_FACTORY_H_ diff --git a/chromecast/media/cma/test/cma_end_to_end_test.cc b/chromecast/media/cma/test/cma_end_to_end_test.cc index 34dd699..9a8e4cd 100644 --- a/chromecast/media/cma/test/cma_end_to_end_test.cc +++ b/chromecast/media/cma/test/cma_end_to_end_test.cc @@ -13,9 +13,11 @@ #include "chromecast/media/cma/base/buffering_defs.h" #include "chromecast/media/cma/filters/cma_renderer.h" #include "chromecast/media/cma/pipeline/media_pipeline_impl.h" +#include "gpu/command_buffer/client/gles2_interface_stub.h" #include "media/base/demuxer_stream_provider.h" #include "media/base/fake_demuxer_stream.h" #include "media/base/null_video_sink.h" +#include "media/renderers/mock_gpu_video_accelerator_factories.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -26,7 +28,9 @@ namespace { class CmaEndToEndTest : public testing::Test { public: - CmaEndToEndTest() { + CmaEndToEndTest() {} + + void SetUp() override { demuxer_stream_provider_.reset( new ::media::FakeDemuxerStreamProvider(1, 1, false)); null_sink_.reset(new ::media::NullVideoSink( @@ -38,12 +42,20 @@ class CmaEndToEndTest : public testing::Test { scoped_ptr<MediaPipelineDeviceFactory> factory = make_scoped_ptr(new MediaPipelineDeviceFactoryDefault()); + gles2_.reset(new gpu::gles2::GLES2InterfaceStub()); + mock_gpu_factories_ = new ::media::MockGpuVideoAcceleratorFactories(); + + EXPECT_CALL(*mock_gpu_factories_.get(), GetGLES2Interface()) + .WillRepeatedly(testing::Return(gles2_.get())); + media_pipeline->Initialize( kLoadTypeMediaSource, make_scoped_ptr(new MediaPipelineDevice(factory.Pass()))); - renderer_.reset(new CmaRenderer(media_pipeline.Pass(), null_sink_.get())); + renderer_.reset(new CmaRenderer(media_pipeline.Pass(), null_sink_.get(), + mock_gpu_factories_)); } + void TearDown() override { message_loop_.RunUntilIdle(); } ~CmaEndToEndTest() override {} @@ -51,6 +63,8 @@ class CmaEndToEndTest : public testing::Test { base::MessageLoop message_loop_; scoped_ptr<::media::FakeDemuxerStreamProvider> demuxer_stream_provider_; scoped_ptr<CmaRenderer> renderer_; + scoped_refptr<::media::MockGpuVideoAcceleratorFactories> mock_gpu_factories_; + scoped_ptr<gpu::gles2::GLES2Interface> gles2_; class MockCB { public: @@ -84,7 +98,6 @@ TEST_F(CmaEndToEndTest, TestInitialization) { base::Bind(&MockCB::OnWaitingForDecryptionKey, base::Unretained(&mock_))); EXPECT_CALL(mock_, OnInitialized(::media::PIPELINE_OK)); - message_loop_.RunUntilIdle(); } diff --git a/chromecast/media/media.gyp b/chromecast/media/media.gyp index ecb76e0..51ddfc4 100644 --- a/chromecast/media/media.gyp +++ b/chromecast/media/media.gyp @@ -250,6 +250,8 @@ 'cma/filters/cma_renderer.h', 'cma/filters/demuxer_stream_adapter.cc', 'cma/filters/demuxer_stream_adapter.h', + 'cma/filters/hole_frame_factory.cc', + 'cma/filters/hole_frame_factory.h', ], }, { @@ -274,10 +276,12 @@ '../../base/base.gyp:base_i18n', '../../base/base.gyp:test_support_base', '../../chromecast/chromecast.gyp:cast_metrics_test_support', + '../../gpu/gpu.gyp:gpu_unittest_utils', '../../media/media.gyp:media_test_support', '../../testing/gmock.gyp:gmock', '../../testing/gtest.gyp:gtest', '../../testing/gtest.gyp:gtest_main', + '../../ui/gfx/gfx.gyp:gfx_test_support', ], 'sources': [ 'cdm/chromecast_init_data_unittest.cc', diff --git a/chromecast/renderer/cast_content_renderer_client.cc b/chromecast/renderer/cast_content_renderer_client.cc index 3f48cb4..4837dab 100644 --- a/chromecast/renderer/cast_content_renderer_client.cc +++ b/chromecast/renderer/cast_content_renderer_client.cc @@ -191,6 +191,7 @@ void CastContentRendererClient::AddKeySystems( scoped_ptr<::media::RendererFactory> CastContentRendererClient::CreateMediaRendererFactory( ::content::RenderFrame* render_frame, + const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories, const scoped_refptr<::media::MediaLog>& media_log) { const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); if (!cmd_line->HasSwitch(switches::kEnableCmaMediaPipeline)) @@ -198,7 +199,7 @@ CastContentRendererClient::CreateMediaRendererFactory( return scoped_ptr<::media::RendererFactory>( new chromecast::media::ChromecastMediaRendererFactory( - media_log, render_frame->GetRoutingID())); + gpu_factories, media_log, render_frame->GetRoutingID())); } #endif diff --git a/chromecast/renderer/cast_content_renderer_client.h b/chromecast/renderer/cast_content_renderer_client.h index a29d2d1..0ee87ed 100644 --- a/chromecast/renderer/cast_content_renderer_client.h +++ b/chromecast/renderer/cast_content_renderer_client.h @@ -46,6 +46,7 @@ class CastContentRendererClient : public content::ContentRendererClient { #if !defined(OS_ANDROID) scoped_ptr<::media::RendererFactory> CreateMediaRendererFactory( content::RenderFrame* render_frame, + const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories, const scoped_refptr<::media::MediaLog>& media_log) override; #endif blink::WebPrescientNetworking* GetPrescientNetworking() override; diff --git a/chromecast/renderer/media/chromecast_media_renderer_factory.cc b/chromecast/renderer/media/chromecast_media_renderer_factory.cc index eb4d24f..f2c9bfb 100644 --- a/chromecast/renderer/media/chromecast_media_renderer_factory.cc +++ b/chromecast/renderer/media/chromecast_media_renderer_factory.cc @@ -18,9 +18,11 @@ namespace chromecast { namespace media { ChromecastMediaRendererFactory::ChromecastMediaRendererFactory( + const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories, const scoped_refptr<::media::MediaLog>& media_log, int render_frame_id) : render_frame_id_(render_frame_id), + gpu_factories_(gpu_factories), media_log_(media_log) { } @@ -62,8 +64,8 @@ scoped_ptr<::media::Renderer> ChromecastMediaRendererFactory::CreateRenderer( render_frame_id_, content::RenderThread::Get()->GetIOMessageLoopProxy(), cma_load_type)); - scoped_ptr<CmaRenderer> cma_renderer( - new CmaRenderer(cma_media_pipeline.Pass(), video_renderer_sink)); + scoped_ptr<CmaRenderer> cma_renderer(new CmaRenderer( + cma_media_pipeline.Pass(), video_renderer_sink, gpu_factories_)); scoped_ptr<::media::Renderer> default_media_render( default_render_factory_->CreateRenderer(media_task_runner, audio_renderer_sink, diff --git a/chromecast/renderer/media/chromecast_media_renderer_factory.h b/chromecast/renderer/media/chromecast_media_renderer_factory.h index 89ac195..ab2b078 100644 --- a/chromecast/renderer/media/chromecast_media_renderer_factory.h +++ b/chromecast/renderer/media/chromecast_media_renderer_factory.h @@ -11,6 +11,7 @@ namespace media { class AudioHardwareConfig; +class GpuVideoAcceleratorFactories; class MediaLog; class DefaultRendererFactory; } @@ -21,6 +22,7 @@ namespace media { class ChromecastMediaRendererFactory : public ::media::RendererFactory { public: ChromecastMediaRendererFactory( + const scoped_refptr<::media::GpuVideoAcceleratorFactories>& gpu_factories, const scoped_refptr<::media::MediaLog>& media_log, int render_frame_id); ~ChromecastMediaRendererFactory() final; @@ -33,6 +35,7 @@ class ChromecastMediaRendererFactory : public ::media::RendererFactory { private: int render_frame_id_; + scoped_refptr<::media::GpuVideoAcceleratorFactories> gpu_factories_; scoped_refptr<::media::MediaLog> media_log_; scoped_ptr<::media::DefaultRendererFactory> default_render_factory_; |