diff options
author | posciak <posciak@chromium.org> | 2016-03-24 23:02:23 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-25 06:03:50 +0000 |
commit | 6977e5243786901a766a38c2c291464875dffbd6 (patch) | |
tree | cdda3912792594e80978880986bce932dfca9b4d /content | |
parent | e582c0b02df6a3f4406bb075b22f71f3d931f581 (diff) | |
download | chromium_src-6977e5243786901a766a38c2c291464875dffbd6.zip chromium_src-6977e5243786901a766a38c2c291464875dffbd6.tar.gz chromium_src-6977e5243786901a766a38c2c291464875dffbd6.tar.bz2 |
Introduce GpuVideoDecodeAcceleratorFactory.
- Move platform-specific code from GpuVideoDecodeAccelerator to
GpuVideoDecodeAcceleratorFactory.
- Make GVDAFactory a content/public interface, to provide the ability to
instantiate VDAs from outside content/.
- Unify how we obtain access to various GL functionality/classes from VDAs
by introducing a set of callbacks provided by the client.
- Replace VDA::CanDecodeOnIOThread() with
VDA::TryInitializeDecodeOnSeparateThread(). This allows us to remove
additional client/taskrunner arguments from VDA constructors, and give client
the option to use a separate thread to decode, instead of having to make this
decision in the factory, and enforcing these arguments in the constructors.
- Deduplicate VDA creation code across users (currently GVDA and vdaunittest).
BUG=b/27687678
TEST=compile/run various VDA impls
CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel
Review URL: https://codereview.chromium.org/1745903002
Cr-Commit-Position: refs/heads/master@{#383256}
Diffstat (limited to 'content')
35 files changed, 1054 insertions, 562 deletions
diff --git a/content/common/gpu/media/android_video_decode_accelerator.cc b/content/common/gpu/media/android_video_decode_accelerator.cc index e4d7802..13b54ee 100644 --- a/content/common/gpu/media/android_video_decode_accelerator.cc +++ b/content/common/gpu/media/android_video_decode_accelerator.cc @@ -251,35 +251,22 @@ static base::LazyInstance<AVDATimerManager>::Leaky g_avda_timer = LAZY_INSTANCE_INITIALIZER; AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator( - const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder, - const base::Callback<bool(void)>& make_context_current) + const MakeGLContextCurrentCallback& make_context_current_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb) : client_(NULL), - make_context_current_(make_context_current), + make_context_current_cb_(make_context_current_cb), + get_gles2_decoder_cb_(get_gles2_decoder_cb), codec_(media::kCodecH264), is_encrypted_(false), needs_protected_surface_(false), state_(NO_ERROR), picturebuffers_requested_(false), - gl_decoder_(decoder), media_drm_bridge_cdm_context_(nullptr), cdm_registration_id_(0), pending_input_buf_index_(-1), error_sequence_token_(0), defer_errors_(false), - weak_this_factory_(this) { - const gpu::GpuPreferences& gpu_preferences = - gl_decoder_->GetContextGroup()->gpu_preferences(); - if (UseDeferredRenderingStrategy(gpu_preferences)) { - // TODO(liberato, watk): Figure out what we want to do about zero copy for - // fullscreen external SurfaceView in WebView. http://crbug.com/582170. - DCHECK(!gl_decoder_->GetContextGroup()->mailbox_manager()->UsesSync()); - DVLOG(1) << __FUNCTION__ << ", using deferred rendering strategy."; - strategy_.reset(new AndroidDeferredRenderingBackingStrategy(this)); - } else { - DVLOG(1) << __FUNCTION__ << ", using copy back strategy."; - strategy_.reset(new AndroidCopyingBackingStrategy(this)); - } -} + weak_this_factory_(this) {} AndroidVideoDecodeAccelerator::~AndroidVideoDecodeAccelerator() { DCHECK(thread_checker_.CalledOnValidThread()); @@ -302,6 +289,11 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, DVLOG(1) << __FUNCTION__ << ": " << config.AsHumanReadableString(); + if (make_context_current_cb_.is_null() || get_gles2_decoder_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + DCHECK(client); client_ = client; codec_ = VideoCodecProfileToVideoCodec(config.profile); @@ -324,13 +316,28 @@ bool AndroidVideoDecodeAccelerator::Initialize(const Config& config, codec_, media::MEDIA_CODEC_DECODER)); } - if (!make_context_current_.Run()) { - LOG(ERROR) << "Failed to make this decoder's GL context current."; + auto gles_decoder = get_gles2_decoder_cb_.Run(); + if (!gles_decoder) { + LOG(ERROR) << "Failed to get gles2 decoder instance."; return false; } - if (!gl_decoder_) { - LOG(ERROR) << "Failed to get gles2 decoder instance."; + const gpu::GpuPreferences& gpu_preferences = + gles_decoder->GetContextGroup()->gpu_preferences(); + + if (UseDeferredRenderingStrategy(gpu_preferences)) { + // TODO(liberato, watk): Figure out what we want to do about zero copy for + // fullscreen external SurfaceView in WebView. http://crbug.com/582170. + DCHECK(!gles_decoder->GetContextGroup()->mailbox_manager()->UsesSync()); + DVLOG(1) << __FUNCTION__ << ", using deferred rendering strategy."; + strategy_.reset(new AndroidDeferredRenderingBackingStrategy(this)); + } else { + DVLOG(1) << __FUNCTION__ << ", using copy back strategy."; + strategy_.reset(new AndroidCopyingBackingStrategy(this)); + } + + if (!make_context_current_cb_.Run()) { + LOG(ERROR) << "Failed to make this decoder's GL context current."; return false; } @@ -714,7 +721,7 @@ void AndroidVideoDecodeAccelerator::SendDecodedFrameToClient( DCHECK(!free_picture_ids_.empty()); TRACE_EVENT0("media", "AVDA::SendDecodedFrameToClient"); - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { POST_ERROR(PLATFORM_FAILURE, "Failed to make the GL context current."); return; } @@ -992,7 +999,7 @@ void AndroidVideoDecodeAccelerator::Reset() { void AndroidVideoDecodeAccelerator::Destroy() { DCHECK(thread_checker_.CalledOnValidThread()); - bool have_context = make_context_current_.Run(); + bool have_context = make_context_current_cb_.Run(); if (!have_context) LOG(WARNING) << "Failed make GL context current for Destroy, continuing."; @@ -1012,7 +1019,9 @@ void AndroidVideoDecodeAccelerator::Destroy() { delete this; } -bool AndroidVideoDecodeAccelerator::CanDecodeOnIOThread() { +bool AndroidVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { return false; } @@ -1027,18 +1036,19 @@ const base::ThreadChecker& AndroidVideoDecodeAccelerator::ThreadChecker() base::WeakPtr<gpu::gles2::GLES2Decoder> AndroidVideoDecodeAccelerator::GetGlDecoder() const { - return gl_decoder_; + return get_gles2_decoder_cb_.Run(); } gpu::gles2::TextureRef* AndroidVideoDecodeAccelerator::GetTextureForPicture( const media::PictureBuffer& picture_buffer) { - RETURN_ON_FAILURE(this, gl_decoder_, "Null gl_decoder_", ILLEGAL_STATE, - nullptr); - RETURN_ON_FAILURE(this, gl_decoder_->GetContextGroup(), - "Null gl_decoder_->GetContextGroup()", ILLEGAL_STATE, + auto gles_decoder = GetGlDecoder(); + RETURN_ON_FAILURE(this, gles_decoder, "Failed to get GL decoder", + ILLEGAL_STATE, nullptr); + RETURN_ON_FAILURE(this, gles_decoder->GetContextGroup(), + "Null gles_decoder->GetContextGroup()", ILLEGAL_STATE, nullptr); gpu::gles2::TextureManager* texture_manager = - gl_decoder_->GetContextGroup()->texture_manager(); + gles_decoder->GetContextGroup()->texture_manager(); RETURN_ON_FAILURE(this, texture_manager, "Null texture_manager", ILLEGAL_STATE, nullptr); gpu::gles2::TextureRef* texture_ref = diff --git a/content/common/gpu/media/android_video_decode_accelerator.h b/content/common/gpu/media/android_video_decode_accelerator.h index 9e6645b..badb64c 100644 --- a/content/common/gpu/media/android_video_decode_accelerator.h +++ b/content/common/gpu/media/android_video_decode_accelerator.h @@ -18,6 +18,7 @@ #include "base/timer/timer.h" #include "content/common/content_export.h" #include "content/common/gpu/media/avda_state_provider.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/gpu_preferences.h" #include "media/base/android/media_drm_bridge_cdm_context.h" @@ -110,8 +111,8 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator }; AndroidVideoDecodeAccelerator( - const base::WeakPtr<gpu::gles2::GLES2Decoder> decoder, - const base::Callback<bool(void)>& make_context_current); + const MakeGLContextCurrentCallback& make_context_current_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb); ~AndroidVideoDecodeAccelerator() override; @@ -125,7 +126,10 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; // AVDAStateProvider implementation: const gfx::Size& GetSize() const override; @@ -241,7 +245,10 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator Client* client_; // Callback to set the correct gl context. - base::Callback<bool(void)> make_context_current_; + MakeGLContextCurrentCallback make_context_current_cb_; + + // Callback to get the GLES2Decoder instance. + GetGLES2DecoderCallback get_gles2_decoder_cb_; // Codec type. Used when we configure media codec. media::VideoCodec codec_; @@ -299,9 +306,6 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator // NotifyEndOfBitstreamBuffer() before getting output from the bitstream. std::list<int32_t> bitstreams_notified_in_advance_; - // Owner of the GL context. Used to restore the context state. - base::WeakPtr<gpu::gles2::GLES2Decoder> gl_decoder_; - // Backing strategy that we'll use to connect PictureBuffers to frames. scoped_ptr<BackingStrategy> strategy_; diff --git a/content/common/gpu/media/android_video_decode_accelerator_unittest.cc b/content/common/gpu/media/android_video_decode_accelerator_unittest.cc index 751933a..f050044 100644 --- a/content/common/gpu/media/android_video_decode_accelerator_unittest.cc +++ b/content/common/gpu/media/android_video_decode_accelerator_unittest.cc @@ -27,6 +27,11 @@ bool MockMakeContextCurrent() { return true; } +static base::WeakPtr<gpu::gles2::GLES2Decoder> MockGetGLES2Decoder( + const base::WeakPtr<gpu::gles2::GLES2Decoder>& decoder) { + return decoder; +} + } // namespace namespace content { @@ -67,7 +72,8 @@ class AndroidVideoDecodeAcceleratorTest : public testing::Test { scoped_ptr<MockVideoDecodeAcceleratorClient> client( new MockVideoDecodeAcceleratorClient()); accelerator_.reset(new AndroidVideoDecodeAccelerator( - decoder->AsWeakPtr(), base::Bind(&MockMakeContextCurrent))); + base::Bind(&MockMakeContextCurrent), + base::Bind(&MockGetGLES2Decoder, decoder->AsWeakPtr()))); } bool Configure(media::VideoCodec codec) { diff --git a/content/common/gpu/media/dxva_video_decode_accelerator_win.cc b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc index 8557bcc..e42159b 100644 --- a/content/common/gpu/media/dxva_video_decode_accelerator_win.cc +++ b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc @@ -814,8 +814,8 @@ DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {} DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( - const base::Callback<bool(void)>& make_context_current, - gfx::GLContext* gl_context, + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, bool enable_accelerated_vpx_decode) : client_(NULL), dev_manager_reset_token_(0), @@ -825,14 +825,14 @@ DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( pictures_requested_(false), inputs_before_decode_(0), sent_drain_message_(false), - make_context_current_(make_context_current), + get_gl_context_cb_(get_gl_context_cb), + make_context_current_cb_(make_context_current_cb), codec_(media::kUnknownVideoCodec), decoder_thread_("DXVAVideoDecoderThread"), pending_flush_(false), use_dx11_(false), use_keyed_mutex_(false), dx11_video_format_converter_media_type_needs_init_(true), - gl_context_(gl_context), using_angle_device_(false), enable_accelerated_vpx_decode_(enable_accelerated_vpx_decode), weak_this_factory_(this) { @@ -847,6 +847,11 @@ DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, Client* client) { + if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + if (config.is_encrypted) { NOTREACHED() << "Encrypted streams are not supported for this VDA"; return false; @@ -1211,7 +1216,7 @@ void DXVAVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) { base::Unretained(this))); } } else { - RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), + RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), "Failed to make context current", PLATFORM_FAILURE, ); it->second->ResetReuseFence(); @@ -1233,7 +1238,7 @@ void DXVAVideoDecodeAccelerator::WaitForOutputBuffer(int32_t picture_buffer_id, DCHECK(picture_buffer->waiting_to_reuse()); gfx::GLFence* fence = picture_buffer->reuse_fence(); - RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), + RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), "Failed to make context current", PLATFORM_FAILURE, ); if (count <= kMaxIterationsForANGLEReuseFlush && !fence->HasCompleted()) { @@ -1327,7 +1332,9 @@ void DXVAVideoDecodeAccelerator::Destroy() { delete this; } -bool DXVAVideoDecodeAccelerator::CanDecodeOnIOThread() { +bool DXVAVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { return false; } @@ -1511,15 +1518,16 @@ bool DXVAVideoDecodeAccelerator::CheckDecoderDxvaSupport() { DVLOG(1) << "Failed to set Low latency mode on decoder. Error: " << hr; } + auto gl_context = get_gl_context_cb_.Run(); + RETURN_ON_FAILURE(gl_context, "Couldn't get GL context", false); + // The decoder should use DX11 iff // 1. The underlying H/W decoder supports it. // 2. We have a pointer to the MFCreateDXGIDeviceManager function needed for // this. This should always be true for Windows 8+. // 3. ANGLE is using DX11. - DCHECK(gl_context_); if (create_dxgi_device_manager_ && - (gl_context_->GetGLRenderer().find("Direct3D11") != - std::string::npos)) { + (gl_context->GetGLRenderer().find("Direct3D11") != std::string::npos)) { UINT32 dx11_aware = 0; attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware); use_dx11_ = !!dx11_aware; @@ -1721,8 +1729,9 @@ void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { if (!output_picture_buffers_.size()) return; - RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), - "Failed to make context current", PLATFORM_FAILURE,); + RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), + "Failed to make context current", + PLATFORM_FAILURE, ); OutputBuffers::iterator index; @@ -2243,8 +2252,9 @@ void DXVAVideoDecodeAccelerator::CopySurfaceComplete( if (picture_buffer->available()) return; - RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), - "Failed to make context current", PLATFORM_FAILURE,); + RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(), + "Failed to make context current", + PLATFORM_FAILURE, ); DCHECK(!output_picture_buffers_.empty()); diff --git a/content/common/gpu/media/dxva_video_decode_accelerator_win.h b/content/common/gpu/media/dxva_video_decode_accelerator_win.h index 56087b3..f4f474a 100644 --- a/content/common/gpu/media/dxva_video_decode_accelerator_win.h +++ b/content/common/gpu/media/dxva_video_decode_accelerator_win.h @@ -29,6 +29,7 @@ #include "base/threading/thread.h" #include "base/win/scoped_comptr.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "media/video/video_decode_accelerator.h" interface IMFSample; @@ -97,8 +98,8 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator // Does not take ownership of |client| which must outlive |*this|. DXVAVideoDecodeAccelerator( - const base::Callback<bool(void)>& make_context_current, - gfx::GLContext* gl_context, + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, bool enable_accelerated_vpx_decode); ~DXVAVideoDecodeAccelerator() override; @@ -111,7 +112,10 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; GLenum GetSurfaceInternalFormat() const override; static media::VideoDecodeAccelerator::SupportedProfiles @@ -391,8 +395,10 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator typedef std::list<base::win::ScopedComPtr<IMFSample>> PendingInputs; PendingInputs pending_input_buffers_; + // Callback to get current GLContext. + GetGLContextCallback get_gl_context_cb_; // Callback to set the correct gl context. - base::Callback<bool(void)> make_context_current_; + MakeGLContextCurrentCallback make_context_current_cb_; // Which codec we are decoding with hardware acceleration. media::VideoCodec codec_; @@ -432,9 +438,6 @@ class CONTENT_EXPORT DXVAVideoDecodeAccelerator // be initialized. Defaults to true. bool dx11_video_format_converter_media_type_needs_init_; - // The GLContext to be used by the decoder. - scoped_refptr<gfx::GLContext> gl_context_; - // Set to true if we are sharing ANGLE's device. bool using_angle_device_; diff --git a/content/common/gpu/media/fake_video_decode_accelerator.cc b/content/common/gpu/media/fake_video_decode_accelerator.cc index 230c4f3..48e7925 100644 --- a/content/common/gpu/media/fake_video_decode_accelerator.cc +++ b/content/common/gpu/media/fake_video_decode_accelerator.cc @@ -29,17 +29,14 @@ static const unsigned int kNumBuffers = media::limits::kMaxVideoFrames + (media::limits::kMaxVideoFrames & 1u); FakeVideoDecodeAccelerator::FakeVideoDecodeAccelerator( - gfx::GLContext* gl, - gfx::Size size, - const base::Callback<bool(void)>& make_context_current) + const gfx::Size& size, + const MakeGLContextCurrentCallback& make_context_current_cb) : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), client_(NULL), - make_context_current_(make_context_current), - gl_(gl), + make_context_current_cb_(make_context_current_cb), frame_buffer_size_(size), flushing_(false), - weak_this_factory_(this) { -} + weak_this_factory_(this) {} FakeVideoDecodeAccelerator::~FakeVideoDecodeAccelerator() { } @@ -103,7 +100,7 @@ void FakeVideoDecodeAccelerator::AssignPictureBuffers( memset(black_data.get(), 0, frame_buffer_size_.width() * frame_buffer_size_.height() * 4); - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { LOG(ERROR) << "ReusePictureBuffer(): could not make context current"; return; } @@ -162,8 +159,10 @@ void FakeVideoDecodeAccelerator::Destroy() { delete this; } -bool FakeVideoDecodeAccelerator::CanDecodeOnIOThread() { - return true; +bool FakeVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { + return false; } void FakeVideoDecodeAccelerator::DoPictureReady() { diff --git a/content/common/gpu/media/fake_video_decode_accelerator.h b/content/common/gpu/media/fake_video_decode_accelerator.h index 7dcbfda..10d4782 100644 --- a/content/common/gpu/media/fake_video_decode_accelerator.h +++ b/content/common/gpu/media/fake_video_decode_accelerator.h @@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "media/video/video_decode_accelerator.h" #include "ui/gfx/geometry/size_f.h" #include "ui/gl/gl_context.h" @@ -23,9 +24,8 @@ class CONTENT_EXPORT FakeVideoDecodeAccelerator : public media::VideoDecodeAccelerator { public: FakeVideoDecodeAccelerator( - gfx::GLContext* gl, - gfx::Size size, - const base::Callback<bool(void)>& make_context_current); + const gfx::Size& size, + const MakeGLContextCurrentCallback& make_context_current_cb); ~FakeVideoDecodeAccelerator() override; bool Initialize(const Config& config, Client* client) override; @@ -36,7 +36,10 @@ class CONTENT_EXPORT FakeVideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; private: void DoPictureReady(); @@ -49,8 +52,7 @@ class CONTENT_EXPORT FakeVideoDecodeAccelerator Client* client_; // Make our context current before running any GL entry points. - base::Callback<bool(void)> make_context_current_; - gfx::GLContext* gl_; + MakeGLContextCurrentCallback make_context_current_cb_; // Output picture size. gfx::Size frame_buffer_size_; diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc index daa096a..3f96e0d 100644 --- a/content/common/gpu/media/gpu_video_decode_accelerator.cc +++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc @@ -18,42 +18,32 @@ #include "content/common/gpu/gpu_channel.h" #include "content/common/gpu/gpu_channel_manager.h" #include "content/common/gpu/media/gpu_video_accelerator_util.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h" #include "content/common/gpu/media/media_messages.h" #include "gpu/command_buffer/common/command_buffer.h" -#include "gpu/command_buffer/service/gpu_preferences.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_utils.h" #include "ipc/message_filter.h" #include "media/base/limits.h" +#include "ui/gfx/geometry/size.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_image.h" -#include "ui/gl/gl_surface_egl.h" - -#if defined(OS_WIN) -#include "base/win/windows_version.h" -#include "content/common/gpu/media/dxva_video_decode_accelerator_win.h" -#elif defined(OS_MACOSX) -#include "content/common/gpu/media/vt_video_decode_accelerator_mac.h" -#elif defined(OS_CHROMEOS) -#if defined(USE_V4L2_CODEC) -#include "content/common/gpu/media/v4l2_device.h" -#include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h" -#include "content/common/gpu/media/v4l2_video_decode_accelerator.h" -#endif -#if defined(ARCH_CPU_X86_FAMILY) -#include "content/common/gpu/media/vaapi_video_decode_accelerator.h" -#include "ui/gl/gl_implementation.h" -#endif -#elif defined(OS_ANDROID) -#include "content/common/gpu/media/android_video_decode_accelerator.h" -#endif - -#include "ui/gfx/geometry/size.h" namespace content { +namespace { +static gfx::GLContext* GetGLContext( + const base::WeakPtr<GpuCommandBufferStub>& stub) { + if (!stub) { + DLOG(ERROR) << "Stub is gone; no GLContext."; + return nullptr; + } + + return stub->decoder()->GetGLContext(); +} + static bool MakeDecoderContextCurrent( - const base::WeakPtr<GpuCommandBufferStub> stub) { + const base::WeakPtr<GpuCommandBufferStub>& stub) { if (!stub) { DLOG(ERROR) << "Stub is gone; won't MakeCurrent()."; return false; @@ -67,6 +57,43 @@ static bool MakeDecoderContextCurrent( return true; } +#if (defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)) || defined(OS_MACOSX) +static bool BindImage(const base::WeakPtr<GpuCommandBufferStub>& stub, + uint32_t client_texture_id, + uint32_t texture_target, + const scoped_refptr<gl::GLImage>& image, + bool can_bind_to_sampler) { + if (!stub) { + DLOG(ERROR) << "Stub is gone; won't BindImage()."; + return false; + } + + gpu::gles2::GLES2Decoder* command_decoder = stub->decoder(); + gpu::gles2::TextureManager* texture_manager = + command_decoder->GetContextGroup()->texture_manager(); + gpu::gles2::TextureRef* ref = texture_manager->GetTexture(client_texture_id); + if (ref) { + texture_manager->SetLevelImage(ref, texture_target, 0, image.get(), + can_bind_to_sampler + ? gpu::gles2::Texture::BOUND + : gpu::gles2::Texture::UNBOUND); + } + + return true; +} +#endif + +static base::WeakPtr<gpu::gles2::GLES2Decoder> GetGLES2Decoder( + const base::WeakPtr<GpuCommandBufferStub>& stub) { + if (!stub) { + DLOG(ERROR) << "Stub is gone; no GLES2Decoder."; + return base::WeakPtr<gpu::gles2::GLES2Decoder>(); + } + + return stub->decoder()->AsWeakPtr(); +} +} // anonymous namespace + // DebugAutoLock works like AutoLock but only acquires the lock when // DCHECK is on. #if DCHECK_IS_ON() @@ -138,8 +165,13 @@ GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator( weak_factory_for_io_(this) { DCHECK(stub_); stub_->AddDestructionObserver(this); - make_context_current_ = + get_gl_context_cb_ = base::Bind(&GetGLContext, stub_->AsWeakPtr()); + make_context_current_cb_ = base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr()); +#if (defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)) || defined(OS_MACOSX) + bind_image_cb_ = base::Bind(&BindImage, stub_->AsWeakPtr()); +#endif + get_gles2_decoder_cb_ = base::Bind(&GetGLES2Decoder, stub_->AsWeakPtr()); } GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() { @@ -152,40 +184,8 @@ GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() { gpu::VideoDecodeAcceleratorCapabilities GpuVideoDecodeAccelerator::GetCapabilities( const gpu::GpuPreferences& gpu_preferences) { - media::VideoDecodeAccelerator::Capabilities capabilities; - if (gpu_preferences.disable_accelerated_video_decode) - return gpu::VideoDecodeAcceleratorCapabilities(); - - // Query supported profiles for each VDA. The order of querying VDAs should - // be the same as the order of initializing VDAs. Then the returned profile - // can be initialized by corresponding VDA successfully. -#if defined(OS_WIN) - capabilities.supported_profiles = - DXVAVideoDecodeAccelerator::GetSupportedProfiles(); -#elif defined(OS_CHROMEOS) - media::VideoDecodeAccelerator::SupportedProfiles vda_profiles; -#if defined(USE_V4L2_CODEC) - vda_profiles = V4L2VideoDecodeAccelerator::GetSupportedProfiles(); - GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( - vda_profiles, &capabilities.supported_profiles); - vda_profiles = V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles(); - GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( - vda_profiles, &capabilities.supported_profiles); -#endif -#if defined(ARCH_CPU_X86_FAMILY) - vda_profiles = VaapiVideoDecodeAccelerator::GetSupportedProfiles(); - GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( - vda_profiles, &capabilities.supported_profiles); -#endif -#elif defined(OS_MACOSX) - capabilities.supported_profiles = - VTVideoDecodeAccelerator::GetSupportedProfiles(); -#elif defined(OS_ANDROID) - capabilities = - AndroidVideoDecodeAccelerator::GetCapabilities(gpu_preferences); -#endif - return GpuVideoAcceleratorUtil::ConvertMediaToGpuDecodeCapabilities( - capabilities); + return GpuVideoDecodeAcceleratorFactoryImpl::GetDecoderCapabilities( + gpu_preferences); } bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) { @@ -328,11 +328,6 @@ bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) { bool GpuVideoDecodeAccelerator::Initialize( const media::VideoDecodeAccelerator::Config& config) { - const gpu::GpuPreferences& gpu_preferences = - stub_->channel()->gpu_channel_manager()->gpu_preferences(); - if (gpu_preferences.disable_accelerated_video_decode) - return false; - DCHECK(!video_decode_accelerator_); if (!stub_->channel()->AddRoute(host_route_id_, stub_->stream_id(), this)) { @@ -343,159 +338,48 @@ bool GpuVideoDecodeAccelerator::Initialize( #if !defined(OS_WIN) // Ensure we will be able to get a GL context at all before initializing // non-Windows VDAs. - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) return false; - } #endif - // Array of Create..VDA() function pointers, maybe applicable to the current - // platform. This list is ordered by priority of use and it should be the - // same as the order of querying supported profiles of VDAs. - const GpuVideoDecodeAccelerator::CreateVDAFp create_vda_fps[] = { -#if defined(OS_WIN) - &GpuVideoDecodeAccelerator::CreateDXVAVDA, -#endif -#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) - &GpuVideoDecodeAccelerator::CreateV4L2VDA, - &GpuVideoDecodeAccelerator::CreateV4L2SliceVDA, -#endif -#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) - &GpuVideoDecodeAccelerator::CreateVaapiVDA, -#endif -#if defined(OS_MACOSX) - &GpuVideoDecodeAccelerator::CreateVTVDA, -#endif -#if defined(OS_ANDROID) - &GpuVideoDecodeAccelerator::CreateAndroidVDA, -#endif - }; + scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> vda_factory = + GpuVideoDecodeAcceleratorFactoryImpl::CreateWithGLES2Decoder( + get_gl_context_cb_, make_context_current_cb_, bind_image_cb_, + get_gles2_decoder_cb_); - for (const auto& create_vda_function : create_vda_fps) { - video_decode_accelerator_ = (this->*create_vda_function)(); - if (!video_decode_accelerator_ || - !video_decode_accelerator_->Initialize(config, this)) - continue; - - if (video_decode_accelerator_->CanDecodeOnIOThread()) { - filter_ = new MessageFilter(this, host_route_id_); - stub_->channel()->AddFilter(filter_.get()); - } - return true; + if (!vda_factory) { + LOG(ERROR) << "Failed creating the VDA factory"; + return false; } - video_decode_accelerator_.reset(); - LOG(ERROR) << "HW video decode not available for profile " << config.profile - << (config.is_encrypted ? " with encryption" : ""); - return false; -} -#if defined(OS_WIN) -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateDXVAVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; const gpu::GpuPreferences& gpu_preferences = stub_->channel()->gpu_channel_manager()->gpu_preferences(); - if (base::win::GetVersion() >= base::win::VERSION_WIN7) { - DVLOG(0) << "Initializing DXVA HW decoder for windows."; - decoder.reset(new DXVAVideoDecodeAccelerator( - make_context_current_, stub_->decoder()->GetGLContext(), - gpu_preferences.enable_accelerated_vpx_decode)); - } else { - NOTIMPLEMENTED() << "HW video decode acceleration not available."; - } - return decoder; -} -#endif - -#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateV4L2VDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; - scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); - if (device.get()) { - decoder.reset(new V4L2VideoDecodeAccelerator( - gfx::GLSurfaceEGL::GetHardwareDisplay(), - stub_->decoder()->GetGLContext()->GetHandle(), - weak_factory_for_io_.GetWeakPtr(), - make_context_current_, - device, - io_task_runner_)); + video_decode_accelerator_ = + vda_factory->CreateVDA(this, config, gpu_preferences); + if (!video_decode_accelerator_) { + LOG(ERROR) << "HW video decode not available for profile " << config.profile + << (config.is_encrypted ? " with encryption" : ""); + return false; } - return decoder; -} -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateV4L2SliceVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; - scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); - if (device.get()) { - decoder.reset(new V4L2SliceVideoDecodeAccelerator( - device, - gfx::GLSurfaceEGL::GetHardwareDisplay(), - stub_->decoder()->GetGLContext()->GetHandle(), - weak_factory_for_io_.GetWeakPtr(), - make_context_current_, - io_task_runner_)); + // Attempt to set up performing decoding tasks on IO thread, if supported by + // the VDA. + if (video_decode_accelerator_->TryToSetupDecodeOnSeparateThread( + weak_factory_for_io_.GetWeakPtr(), io_task_runner_)) { + filter_ = new MessageFilter(this, host_route_id_); + stub_->channel()->AddFilter(filter_.get()); } - return decoder; -} -#endif -#if (defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)) || defined(OS_MACOSX) -void GpuVideoDecodeAccelerator::BindImage(uint32_t client_texture_id, - uint32_t texture_target, - scoped_refptr<gl::GLImage> image, - bool can_bind_to_sampler) { - gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder(); - gpu::gles2::TextureManager* texture_manager = - command_decoder->GetContextGroup()->texture_manager(); - gpu::gles2::TextureRef* ref = texture_manager->GetTexture(client_texture_id); - if (ref) { - texture_manager->SetLevelImage(ref, texture_target, 0, image.get(), - can_bind_to_sampler - ? gpu::gles2::Texture::BOUND - : gpu::gles2::Texture::UNBOUND); - } -} -#endif - -#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateVaapiVDA() { - return make_scoped_ptr<media::VideoDecodeAccelerator>( - new VaapiVideoDecodeAccelerator( - make_context_current_, - base::Bind(&GpuVideoDecodeAccelerator::BindImage, - base::Unretained(this)))); -} -#endif - -#if defined(OS_MACOSX) -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateVTVDA() { - return make_scoped_ptr<media::VideoDecodeAccelerator>( - new VTVideoDecodeAccelerator( - make_context_current_, - base::Bind(&GpuVideoDecodeAccelerator::BindImage, - base::Unretained(this)))); -} -#endif - -#if defined(OS_ANDROID) -scoped_ptr<media::VideoDecodeAccelerator> -GpuVideoDecodeAccelerator::CreateAndroidVDA() { - return make_scoped_ptr<media::VideoDecodeAccelerator>( - new AndroidVideoDecodeAccelerator(stub_->decoder()->AsWeakPtr(), - make_context_current_)); + return true; } -#endif void GpuVideoDecodeAccelerator::OnSetCdm(int cdm_id) { DCHECK(video_decode_accelerator_); video_decode_accelerator_->SetCdm(cdm_id); } -// Runs on IO thread if video_decode_accelerator_->CanDecodeOnIOThread() is -// true, otherwise on the main thread. +// Runs on IO thread if VDA::TryToSetupDecodeOnSeparateThread() succeeded, +// otherwise on the main thread. void GpuVideoDecodeAccelerator::OnDecode( const media::BitstreamBuffer& bitstream_buffer) { DCHECK(video_decode_accelerator_); diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.h b/content/common/gpu/media/gpu_video_decode_accelerator.h index ddfe884..8b4b74e 100644 --- a/content/common/gpu/media/gpu_video_decode_accelerator.h +++ b/content/common/gpu/media/gpu_video_decode_accelerator.h @@ -16,6 +16,7 @@ #include "base/memory/shared_memory.h" #include "base/synchronization/waitable_event.h" #include "content/common/gpu/gpu_command_buffer_stub.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "gpu/command_buffer/service/texture_manager.h" #include "gpu/config/gpu_info.h" #include "ipc/ipc_listener.h" @@ -77,31 +78,8 @@ class GpuVideoDecodeAccelerator bool Initialize(const media::VideoDecodeAccelerator::Config& config); private: - typedef scoped_ptr<media::VideoDecodeAccelerator> ( - GpuVideoDecodeAccelerator::*CreateVDAFp)(); - class MessageFilter; -#if defined(OS_WIN) - scoped_ptr<media::VideoDecodeAccelerator> CreateDXVAVDA(); -#endif -#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) - scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2VDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2SliceVDA(); -#endif -#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) - scoped_ptr<media::VideoDecodeAccelerator> CreateVaapiVDA(); -#endif -#if defined(OS_MACOSX) - scoped_ptr<media::VideoDecodeAccelerator> CreateVTVDA(); -#endif -#if !defined(OS_CHROMEOS) && defined(USE_OZONE) - scoped_ptr<media::VideoDecodeAccelerator> CreateOzoneVDA(); -#endif -#if defined(OS_ANDROID) - scoped_ptr<media::VideoDecodeAccelerator> CreateAndroidVDA(); -#endif - // We only allow self-delete, from OnWillDestroyStub(), after cleanup there. ~GpuVideoDecodeAccelerator() override; @@ -121,16 +99,6 @@ class GpuVideoDecodeAccelerator // Sets the texture to cleared. void SetTextureCleared(const media::Picture& picture); -#if (defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)) || defined(OS_MACOSX) - // Helper to bind |image| to the texture specified by |client_texture_id|. If - // |can_bind_to_sampler| is true, then the image may be used as a sampler - // directly, otherwise a copy to a staging buffer is required. - void BindImage(uint32_t client_texture_id, - uint32_t texture_target, - scoped_refptr<gl::GLImage> image, - bool can_bind_to_sampler); -#endif - // Route ID to communicate with the host. const int32_t host_route_id_; @@ -142,9 +110,17 @@ class GpuVideoDecodeAccelerator // The underlying VideoDecodeAccelerator. scoped_ptr<media::VideoDecodeAccelerator> video_decode_accelerator_; + // Callback to return current GLContext, if available. + GetGLContextCallback get_gl_context_cb_; + // Callback for making the relevant context current for GL calls. - // Returns false if failed. - base::Callback<bool(void)> make_context_current_; + MakeGLContextCurrentCallback make_context_current_cb_; + + // Callback to bind a GLImage to a given texture id and target. + BindGLImageCallback bind_image_cb_; + + // Callback to return a WeakPtr to GLES2Decoder. + GetGLES2DecoderCallback get_gles2_decoder_cb_; // The texture dimensions as requested by ProvidePictureBuffers(). gfx::Size texture_dimensions_; diff --git a/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.cc b/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.cc new file mode 100644 index 0000000..04ab770 --- /dev/null +++ b/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.cc @@ -0,0 +1,241 @@ +// Copyright 2016 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 "content/common/gpu/media/gpu_video_accelerator_util.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h" +#include "gpu/command_buffer/service/gpu_preferences.h" + +#if defined(OS_WIN) +#include "base/win/windows_version.h" +#include "content/common/gpu/media/dxva_video_decode_accelerator_win.h" +#elif defined(OS_MACOSX) +#include "content/common/gpu/media/vt_video_decode_accelerator_mac.h" +#elif defined(OS_CHROMEOS) +#if defined(USE_V4L2_CODEC) +#include "content/common/gpu/media/v4l2_device.h" +#include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h" +#include "content/common/gpu/media/v4l2_video_decode_accelerator.h" +#include "ui/gl/gl_surface_egl.h" +#endif +#if defined(ARCH_CPU_X86_FAMILY) +#include "content/common/gpu/media/vaapi_video_decode_accelerator.h" +#include "ui/gl/gl_implementation.h" +#endif +#elif defined(OS_ANDROID) +#include "content/common/gpu/media/android_video_decode_accelerator.h" +#endif + +namespace content { + +namespace { +static base::WeakPtr<gpu::gles2::GLES2Decoder> GetEmptyGLES2Decoder() { + NOTREACHED() << "VDA requests a GLES2Decoder, but client did not provide it"; + return base::WeakPtr<gpu::gles2::GLES2Decoder>(); +} +} + +// static +scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> +GpuVideoDecodeAcceleratorFactoryImpl::Create( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb) { + return make_scoped_ptr(new GpuVideoDecodeAcceleratorFactoryImpl( + get_gl_context_cb, make_context_current_cb, bind_image_cb, + base::Bind(&GetEmptyGLES2Decoder))); +} + +// static +scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> +GpuVideoDecodeAcceleratorFactoryImpl::CreateWithGLES2Decoder( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb) { + return make_scoped_ptr(new GpuVideoDecodeAcceleratorFactoryImpl( + get_gl_context_cb, make_context_current_cb, bind_image_cb, + get_gles2_decoder_cb)); +} + +// static +gpu::VideoDecodeAcceleratorCapabilities +GpuVideoDecodeAcceleratorFactoryImpl::GetDecoderCapabilities( + const gpu::GpuPreferences& gpu_preferences) { + media::VideoDecodeAccelerator::Capabilities capabilities; + if (gpu_preferences.disable_accelerated_video_decode) + return gpu::VideoDecodeAcceleratorCapabilities(); + + // Query VDAs for their capabilities and construct a set of supported + // profiles for current platform. This must be done in the same order as in + // CreateVDA(), as we currently preserve additional capabilities (such as + // resolutions supported) only for the first VDA supporting the given codec + // profile (instead of calculating a superset). + // TODO(posciak,henryhsu): improve this so that we choose a superset of + // resolutions and other supported profile parameters. +#if defined(OS_WIN) + capabilities.supported_profiles = + DXVAVideoDecodeAccelerator::GetSupportedProfiles(); +#elif defined(OS_CHROMEOS) + media::VideoDecodeAccelerator::SupportedProfiles vda_profiles; +#if defined(USE_V4L2_CODEC) + vda_profiles = V4L2VideoDecodeAccelerator::GetSupportedProfiles(); + GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( + vda_profiles, &capabilities.supported_profiles); + vda_profiles = V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles(); + GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( + vda_profiles, &capabilities.supported_profiles); +#endif +#if defined(ARCH_CPU_X86_FAMILY) + vda_profiles = VaapiVideoDecodeAccelerator::GetSupportedProfiles(); + GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( + vda_profiles, &capabilities.supported_profiles); +#endif +#elif defined(OS_MACOSX) + capabilities.supported_profiles = + VTVideoDecodeAccelerator::GetSupportedProfiles(); +#elif defined(OS_ANDROID) + capabilities = AndroidVideoDecodeAccelerator::GetCapabilities( + gpu_preferences); +#endif + return GpuVideoAcceleratorUtil::ConvertMediaToGpuDecodeCapabilities( + capabilities); +} + +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateVDA( + media::VideoDecodeAccelerator::Client* client, + const media::VideoDecodeAccelerator::Config& config, + const gpu::GpuPreferences& gpu_preferences) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (gpu_preferences.disable_accelerated_video_decode) + return nullptr; + + // Array of Create..VDA() function pointers, potentially usable on current + // platform. This list is ordered by priority, from most to least preferred, + // if applicable. This list must be in the same order as the querying order + // in GetDecoderCapabilities() above. + using CreateVDAFp = scoped_ptr<media::VideoDecodeAccelerator> ( + GpuVideoDecodeAcceleratorFactoryImpl::*)(const gpu::GpuPreferences&) + const; + const CreateVDAFp create_vda_fps[] = { +#if defined(OS_WIN) + &GpuVideoDecodeAcceleratorFactoryImpl::CreateDXVAVDA, +#endif +#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) + &GpuVideoDecodeAcceleratorFactoryImpl::CreateV4L2VDA, + &GpuVideoDecodeAcceleratorFactoryImpl::CreateV4L2SVDA, +#endif +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) + &GpuVideoDecodeAcceleratorFactoryImpl::CreateVaapiVDA, +#endif +#if defined(OS_MACOSX) + &GpuVideoDecodeAcceleratorFactoryImpl::CreateVTVDA, +#endif +#if defined(OS_ANDROID) + &GpuVideoDecodeAcceleratorFactoryImpl::CreateAndroidVDA, +#endif + }; + + scoped_ptr<media::VideoDecodeAccelerator> vda; + + for (const auto& create_vda_function : create_vda_fps) { + vda = (this->*create_vda_function)(gpu_preferences); + if (vda && vda->Initialize(config, client)) + return vda; + } + + return nullptr; +} + +#if defined(OS_WIN) +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateDXVAVDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + if (base::win::GetVersion() >= base::win::VERSION_WIN7) { + DVLOG(0) << "Initializing DXVA HW decoder for windows."; + decoder.reset(new DXVAVideoDecodeAccelerator( + get_gl_context_cb_, make_context_current_cb_, + gpu_preferences.enable_accelerated_vpx_decode)); + } + return decoder; +} +#endif + +#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateV4L2VDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); + if (device.get()) { + decoder.reset(new V4L2VideoDecodeAccelerator( + gfx::GLSurfaceEGL::GetHardwareDisplay(), get_gl_context_cb_, + make_context_current_cb_, device)); + } + return decoder; +} + +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateV4L2SVDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); + if (device.get()) { + decoder.reset(new V4L2SliceVideoDecodeAccelerator( + device, gfx::GLSurfaceEGL::GetHardwareDisplay(), get_gl_context_cb_, + make_context_current_cb_)); + } + return decoder; +} +#endif + +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateVaapiVDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + decoder.reset(new VaapiVideoDecodeAccelerator(make_context_current_cb_, + bind_image_cb_)); + return decoder; +} +#endif + +#if defined(OS_MACOSX) +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateVTVDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + decoder.reset( + new VTVideoDecodeAccelerator(make_context_current_cb_, bind_image_cb_)); + return decoder; +} +#endif + +#if defined(OS_ANDROID) +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactoryImpl::CreateAndroidVDA( + const gpu::GpuPreferences& gpu_preferences) const { + scoped_ptr<media::VideoDecodeAccelerator> decoder; + decoder.reset(new AndroidVideoDecodeAccelerator(make_context_current_cb_, + get_gles2_decoder_cb_)); + return decoder; +} +#endif + +GpuVideoDecodeAcceleratorFactoryImpl::GpuVideoDecodeAcceleratorFactoryImpl( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb) + : get_gl_context_cb_(get_gl_context_cb), + make_context_current_cb_(make_context_current_cb), + bind_image_cb_(bind_image_cb), + get_gles2_decoder_cb_(get_gles2_decoder_cb) {} + +GpuVideoDecodeAcceleratorFactoryImpl::~GpuVideoDecodeAcceleratorFactoryImpl() {} + +} // namespace content diff --git a/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h b/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h new file mode 100644 index 0000000..de3db4c --- /dev/null +++ b/content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h @@ -0,0 +1,126 @@ +// Copyright 2016 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 CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_FACTORY_IMPL_H_ +#define CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_FACTORY_IMPL_H_ + +#include "base/callback.h" +#include "base/threading/thread_checker.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "gpu/config/gpu_info.h" +#include "media/video/video_decode_accelerator.h" + +namespace gfx { +class GLContext; +} + +namespace gl { +class GLImage; +} + +namespace gpu { +struct GpuPreferences; + +namespace gles2 { +class GLES2Decoder; +} +} + +namespace content { + +// TODO(posciak): this class should be an implementation of +// content::GpuVideoDecodeAcceleratorFactory, however that can only be achieved +// once this is moved out of content/common, see crbug.com/597150 and related. +class GpuVideoDecodeAcceleratorFactoryImpl { + public: + ~GpuVideoDecodeAcceleratorFactoryImpl(); + + // Return current GLContext. + using GetGLContextCallback = base::Callback<gfx::GLContext*(void)>; + + // Make the applicable GL context current. To be called by VDAs before + // executing any GL calls. Return true on success, false otherwise. + using MakeGLContextCurrentCallback = base::Callback<bool(void)>; + + // Bind |image| to |client_texture_id| given |texture_target|. If + // |can_bind_to_sampler| is true, then the image may be used as a sampler + // directly, otherwise a copy to a staging buffer is required. + // Return true on success, false otherwise. + using BindGLImageCallback = + base::Callback<bool(uint32_t client_texture_id, + uint32_t texture_target, + const scoped_refptr<gl::GLImage>& image, + bool can_bind_to_sampler)>; + + // Return a WeakPtr to a GLES2Decoder, if one is available. + using GetGLES2DecoderCallback = + base::Callback<base::WeakPtr<gpu::gles2::GLES2Decoder>(void)>; + + static scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> Create( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb); + + static scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> + CreateWithGLES2Decoder( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb); + + static gpu::VideoDecodeAcceleratorCapabilities GetDecoderCapabilities( + const gpu::GpuPreferences& gpu_preferences); + + scoped_ptr<media::VideoDecodeAccelerator> CreateVDA( + media::VideoDecodeAccelerator::Client* client, + const media::VideoDecodeAccelerator::Config& config, + const gpu::GpuPreferences& gpu_preferences); + + private: + GpuVideoDecodeAcceleratorFactoryImpl( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb); + +#if defined(OS_WIN) + scoped_ptr<media::VideoDecodeAccelerator> CreateDXVAVDA( + const gpu::GpuPreferences& gpu_preferences) const; +#endif +#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) + scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2VDA( + const gpu::GpuPreferences& gpu_preferences) const; + scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2SVDA( + const gpu::GpuPreferences& gpu_preferences) const; +#endif +#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) + scoped_ptr<media::VideoDecodeAccelerator> CreateVaapiVDA( + const gpu::GpuPreferences& gpu_preferences) const; +#endif +#if defined(OS_MACOSX) + scoped_ptr<media::VideoDecodeAccelerator> CreateVTVDA( + const gpu::GpuPreferences& gpu_preferences) const; +#endif +#if !defined(OS_CHROMEOS) && defined(USE_OZONE) + scoped_ptr<media::VideoDecodeAccelerator> CreateOzoneVDA( + const gpu::GpuPreferences& gpu_preferences) const; +#endif +#if defined(OS_ANDROID) + scoped_ptr<media::VideoDecodeAccelerator> CreateAndroidVDA( + const gpu::GpuPreferences& gpu_preferences) const; +#endif + + const GetGLContextCallback get_gl_context_cb_; + const MakeGLContextCurrentCallback make_context_current_cb_; + const BindGLImageCallback bind_image_cb_; + const GetGLES2DecoderCallback get_gles2_decoder_cb_; + + base::ThreadChecker thread_checker_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(GpuVideoDecodeAcceleratorFactoryImpl); +}; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_FACTORY_IMPL_H_ diff --git a/content/common/gpu/media/gpu_video_decode_accelerator_helpers.h b/content/common/gpu/media/gpu_video_decode_accelerator_helpers.h new file mode 100644 index 0000000..1717f59 --- /dev/null +++ b/content/common/gpu/media/gpu_video_decode_accelerator_helpers.h @@ -0,0 +1,59 @@ +// Copyright 2016 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 CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_HELPERS_H_ +#define CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_HELPERS_H_ + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" + +namespace gfx { +class GLContext; +} + +namespace gl { +class GLImage; +} + +namespace gpu { +namespace gles2 { +class GLES2Decoder; +} +} + +namespace content { + +// Helpers/defines for specific VideoDecodeAccelerator implementations in GPU +// process. Which callbacks are required depends on the implementation. +// +// Note that these callbacks may be called more than once, and so must own/share +// ownership of any objects bound to them. +// +// Unless specified otherwise, these callbacks must be executed on the GPU Child +// thread (i.e. the thread which the VDAs are initialized on). + +// Return current GLContext. +using GetGLContextCallback = base::Callback<gfx::GLContext*(void)>; + +// Make the applicable GL context current. To be called by VDAs before +// executing any GL calls. Return true on success, false otherwise. +using MakeGLContextCurrentCallback = base::Callback<bool(void)>; + +// Bind |image| to |client_texture_id| given |texture_target|. If +// |can_bind_to_sampler| is true, then the image may be used as a sampler +// directly, otherwise a copy to a staging buffer is required. +// Return true on success, false otherwise. +using BindGLImageCallback = + base::Callback<bool(uint32_t client_texture_id, + uint32_t texture_target, + const scoped_refptr<gl::GLImage>& image, + bool can_bind_to_sampler)>; + +// Return a WeakPtr to a GLES2Decoder, if one is available. +using GetGLES2DecoderCallback = + base::Callback<base::WeakPtr<gpu::gles2::GLES2Decoder>(void)>; + +} // namespace content + +#endif // CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_DECODE_ACCELERATOR_HELPERS_H_ diff --git a/content/common/gpu/media/rendering_helper.cc b/content/common/gpu/media/rendering_helper.cc index 85bfe0a..b3bde44 100644 --- a/content/common/gpu/media/rendering_helper.cc +++ b/content/common/gpu/media/rendering_helper.cc @@ -665,12 +665,8 @@ void RenderingHelper::DeleteTexture(uint32_t texture_id) { CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); } -scoped_refptr<gfx::GLContext> RenderingHelper::GetGLContext() { - return gl_context_; -} - -void* RenderingHelper::GetGLContextHandle() { - return gl_context_->GetHandle(); +gfx::GLContext* RenderingHelper::GetGLContext() { + return gl_context_.get(); } void* RenderingHelper::GetGLDisplay() { diff --git a/content/common/gpu/media/rendering_helper.h b/content/common/gpu/media/rendering_helper.h index 8a6c28b..ad178f5 100644 --- a/content/common/gpu/media/rendering_helper.h +++ b/content/common/gpu/media/rendering_helper.h @@ -135,10 +135,7 @@ class RenderingHelper { void* GetGLDisplay(); // Get the GL context. - scoped_refptr<gfx::GLContext> GetGLContext(); - - // Get the platform specific handle to the OpenGL context. - void* GetGLContextHandle(); + gfx::GLContext* GetGLContext(); // Get rendered thumbnails as RGB. // Sets alpha_solid to true if the alpha channel is entirely 0xff. diff --git a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc index a338cc2..1e0943d 100644 --- a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc +++ b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc @@ -23,6 +23,7 @@ #include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h" #include "media/base/bind_to_current_loop.h" #include "media/base/media_switches.h" +#include "ui/gl/gl_context.h" #include "ui/gl/scoped_binders.h" #define LOGF(level) LOG(level) << __FUNCTION__ << "(): " @@ -379,15 +380,11 @@ V4L2VP8Picture::~V4L2VP8Picture() { V4L2SliceVideoDecodeAccelerator::V4L2SliceVideoDecodeAccelerator( const scoped_refptr<V4L2Device>& device, EGLDisplay egl_display, - EGLContext egl_context, - const base::WeakPtr<Client>& io_client, - const base::Callback<bool(void)>& make_context_current, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb) : input_planes_count_(0), output_planes_count_(0), child_task_runner_(base::ThreadTaskRunnerHandle::Get()), - io_task_runner_(io_task_runner), - io_client_(io_client), device_(device), decoder_thread_("V4L2SliceVideoDecodeAcceleratorThread"), device_poll_thread_("V4L2SliceVideoDecodeAcceleratorDevicePollThread"), @@ -402,9 +399,9 @@ V4L2SliceVideoDecodeAccelerator::V4L2SliceVideoDecodeAccelerator( decoder_resetting_(false), surface_set_change_pending_(false), picture_clearing_count_(0), - make_context_current_(make_context_current), egl_display_(egl_display), - egl_context_(egl_context), + get_gl_context_cb_(get_gl_context_cb), + make_context_current_cb_(make_context_current_cb), weak_this_factory_(this) { weak_this_ = weak_this_factory_.GetWeakPtr(); } @@ -440,6 +437,11 @@ bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config, DCHECK(child_task_runner_->BelongsToCurrentThread()); DCHECK_EQ(state_, kUninitialized); + if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + if (config.is_encrypted) { NOTREACHED() << "Encrypted streams are not supported for this VDA"; return false; @@ -455,6 +457,14 @@ bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config, client_ptr_factory_.reset( new base::WeakPtrFactory<VideoDecodeAccelerator::Client>(client)); client_ = client_ptr_factory_->GetWeakPtr(); + // If we haven't been set up to decode on separate thread via + // TryToSetupDecodeOnSeparateThread(), use the main thread/client for + // decode tasks. + if (!decode_task_runner_) { + decode_task_runner_ = child_task_runner_; + DCHECK(!decode_client_); + decode_client_ = client_; + } video_profile_ = config.profile; @@ -481,7 +491,7 @@ bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config, } // We need the context to be initialized to query extensions. - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { LOG(ERROR) << "Initialize(): could not make context current"; return false; } @@ -1185,7 +1195,7 @@ void V4L2SliceVideoDecodeAccelerator::Decode( const media::BitstreamBuffer& bitstream_buffer) { DVLOGF(3) << "input_id=" << bitstream_buffer.id() << ", size=" << bitstream_buffer.size(); - DCHECK(io_task_runner_->BelongsToCurrentThread()); + DCHECK(decode_task_runner_->BelongsToCurrentThread()); if (bitstream_buffer.id() < 0) { LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); @@ -1207,7 +1217,7 @@ void V4L2SliceVideoDecodeAccelerator::DecodeTask( DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( - io_client_, io_task_runner_, + decode_client_, decode_task_runner_, new SharedMemoryRegion(bitstream_buffer, true), bitstream_buffer.id())); if (!bitstream_record->shm->Map()) { LOGF(ERROR) << "Could not map bitstream_buffer"; @@ -1488,8 +1498,9 @@ void V4L2SliceVideoDecodeAccelerator::CreateEGLImages( DVLOGF(3); DCHECK(child_task_runner_->BelongsToCurrentThread()); - if (!make_context_current_.Run()) { - DLOG(ERROR) << "could not make context current"; + gfx::GLContext* gl_context = get_gl_context_cb_.Run(); + if (!gl_context || !make_context_current_cb_.Run()) { + DLOG(ERROR) << "No GL context"; NOTIFY_ERROR(PLATFORM_FAILURE); return; } @@ -1499,7 +1510,7 @@ void V4L2SliceVideoDecodeAccelerator::CreateEGLImages( std::vector<EGLImageKHR> egl_images; for (size_t i = 0; i < buffers.size(); ++i) { EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, - egl_context_, + gl_context->GetHandle(), buffers[i].texture_id(), buffers[i].size(), i, @@ -1565,7 +1576,7 @@ void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( DCHECK(child_task_runner_->BelongsToCurrentThread()); DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { LOGF(ERROR) << "could not make context current"; NOTIFY_ERROR(PLATFORM_FAILURE); return; @@ -1641,7 +1652,7 @@ void V4L2SliceVideoDecodeAccelerator::FlushTask() { // which - when reached - will trigger flush sequence. decoder_input_queue_.push( linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( - io_client_, io_task_runner_, nullptr, kFlushBufferId))); + decode_client_, decode_task_runner_, nullptr, kFlushBufferId))); return; } @@ -2552,12 +2563,14 @@ void V4L2SliceVideoDecodeAccelerator::SendPictureReady() { bool cleared = pending_picture_ready_.front().cleared; const media::Picture& picture = pending_picture_ready_.front().picture; if (cleared && picture_clearing_count_ == 0) { - DVLOGF(4) << "Posting picture ready to IO for: " + DVLOGF(4) << "Posting picture ready to decode task runner for: " << picture.picture_buffer_id(); - // This picture is cleared. Post it to IO thread to reduce latency. This - // should be the case after all pictures are cleared at the beginning. - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture)); + // This picture is cleared. It can be posted to a thread different than + // the main GPU thread to reduce latency. This should be the case after + // all pictures are cleared at the beginning. + decode_task_runner_->PostTask( + FROM_HERE, + base::Bind(&Client::PictureReady, decode_client_, picture)); pending_picture_ready_.pop(); } else if (!cleared || resetting_or_flushing) { DVLOGF(3) << "cleared=" << pending_picture_ready_.front().cleared @@ -2595,7 +2608,11 @@ void V4L2SliceVideoDecodeAccelerator::PictureCleared() { SendPictureReady(); } -bool V4L2SliceVideoDecodeAccelerator::CanDecodeOnIOThread() { +bool V4L2SliceVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { + decode_client_ = decode_client_; + decode_task_runner_ = decode_task_runner; return true; } diff --git a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h index 87fe196..9171e44 100644 --- a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h +++ b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.h @@ -19,6 +19,7 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "content/common/gpu/media/h264_decoder.h" #include "content/common/gpu/media/v4l2_device.h" #include "content/common/gpu/media/vp8_decoder.h" @@ -38,10 +39,8 @@ class CONTENT_EXPORT V4L2SliceVideoDecodeAccelerator V4L2SliceVideoDecodeAccelerator( const scoped_refptr<V4L2Device>& device, EGLDisplay egl_display, - EGLContext egl_context, - const base::WeakPtr<Client>& io_client_, - const base::Callback<bool(void)>& make_context_current, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner); + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb); ~V4L2SliceVideoDecodeAccelerator() override; // media::VideoDecodeAccelerator implementation. @@ -53,7 +52,10 @@ class CONTENT_EXPORT V4L2SliceVideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; static media::VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles(); @@ -303,8 +305,8 @@ class CONTENT_EXPORT V4L2SliceVideoDecodeAccelerator // GPU Child thread task runner. const scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_; - // IO thread task runner. - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + // Task runner Decode() and PictureReady() run on. + scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner_; // WeakPtr<> pointing to |this| for use in posting tasks from the decoder or // device worker threads back to the child thread. @@ -316,8 +318,8 @@ class CONTENT_EXPORT V4L2SliceVideoDecodeAccelerator scoped_ptr<base::WeakPtrFactory<VideoDecodeAccelerator::Client>> client_ptr_factory_; base::WeakPtr<VideoDecodeAccelerator::Client> client_; - // Callbacks to |io_client_| must be executed on |io_task_runner_|. - base::WeakPtr<Client> io_client_; + // Callbacks to |decode_client_| must be executed on |decode_task_runner_|. + base::WeakPtr<Client> decode_client_; // V4L2 device in use. scoped_refptr<V4L2Device> device_; @@ -398,12 +400,13 @@ class CONTENT_EXPORT V4L2SliceVideoDecodeAccelerator // The number of pictures that are sent to PictureReady and will be cleared. int picture_clearing_count_; - // Make the GL context current callback. - base::Callback<bool(void)> make_context_current_; - // EGL state EGLDisplay egl_display_; - EGLContext egl_context_; + + // Callback to get current GLContext. + GetGLContextCallback get_gl_context_cb_; + // Callback to set the correct gl context. + MakeGLContextCurrentCallback make_context_current_cb_; // The WeakPtrFactory for |weak_this_|. base::WeakPtrFactory<V4L2SliceVideoDecodeAccelerator> weak_this_factory_; diff --git a/content/common/gpu/media/v4l2_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_video_decode_accelerator.cc index 3554be5..3deddf0 100644 --- a/content/common/gpu/media/v4l2_video_decode_accelerator.cc +++ b/content/common/gpu/media/v4l2_video_decode_accelerator.cc @@ -25,6 +25,7 @@ #include "media/base/media_switches.h" #include "media/filters/h264_parser.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gl/gl_context.h" #include "ui/gl/scoped_binders.h" #define NOTIFY_ERROR(x) \ @@ -153,14 +154,10 @@ V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( EGLDisplay egl_display, - EGLContext egl_context, - const base::WeakPtr<Client>& io_client, - const base::Callback<bool(void)>& make_context_current, - const scoped_refptr<V4L2Device>& device, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const scoped_refptr<V4L2Device>& device) : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), - io_task_runner_(io_task_runner), - io_client_(io_client), decoder_thread_("V4L2DecoderThread"), decoder_state_(kUninitialized), device_(device), @@ -180,9 +177,9 @@ V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( picture_clearing_count_(0), pictures_assigned_(false, false), device_poll_thread_("V4L2DevicePollThread"), - make_context_current_(make_context_current), egl_display_(egl_display), - egl_context_(egl_context), + get_gl_context_cb_(get_gl_context_cb), + make_context_current_cb_(make_context_current_cb), video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), output_format_fourcc_(0), weak_this_factory_(this) { @@ -208,6 +205,11 @@ bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, DCHECK(child_task_runner_->BelongsToCurrentThread()); DCHECK_EQ(decoder_state_, kUninitialized); + if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + if (config.is_encrypted) { NOTREACHED() << "Encrypted streams are not supported for this VDA"; return false; @@ -222,6 +224,14 @@ bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); client_ = client_ptr_factory_->GetWeakPtr(); + // If we haven't been set up to decode on separate thread via + // TryToSetupDecodeOnSeparateThread(), use the main thread/client for + // decode tasks. + if (!decode_task_runner_) { + decode_task_runner_ = child_task_runner_; + DCHECK(!decode_client_); + decode_client_ = client_; + } video_profile_ = config.profile; @@ -231,7 +241,7 @@ bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, } // We need the context to be initialized to query extensions. - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { LOG(ERROR) << "Initialize(): could not make context current"; return false; } @@ -292,7 +302,7 @@ void V4L2VideoDecodeAccelerator::Decode( const media::BitstreamBuffer& bitstream_buffer) { DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() << ", size=" << bitstream_buffer.size(); - DCHECK(io_task_runner_->BelongsToCurrentThread()); + DCHECK(decode_task_runner_->BelongsToCurrentThread()); if (bitstream_buffer.id() < 0) { LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); @@ -324,7 +334,8 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers( return; } - if (!make_context_current_.Run()) { + gfx::GLContext* gl_context = get_gl_context_cb_.Run(); + if (!gl_context || !make_context_current_cb_.Run()) { LOG(ERROR) << "AssignPictureBuffers(): could not make context current"; NOTIFY_ERROR(PLATFORM_FAILURE); return; @@ -364,7 +375,7 @@ void V4L2VideoDecodeAccelerator::AssignPictureBuffers( DCHECK_EQ(output_record.cleared, false); EGLImageKHR egl_image = device_->CreateEGLImage(egl_display_, - egl_context_, + gl_context->GetHandle(), buffers[i].texture_id(), coded_size_, i, @@ -394,7 +405,7 @@ void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) { // Must be run on child thread, as we'll insert a sync in the EGL context. DCHECK(child_task_runner_->BelongsToCurrentThread()); - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { LOG(ERROR) << "ReusePictureBuffer(): could not make context current"; NOTIFY_ERROR(PLATFORM_FAILURE); return; @@ -455,7 +466,13 @@ void V4L2VideoDecodeAccelerator::Destroy() { delete this; } -bool V4L2VideoDecodeAccelerator::CanDecodeOnIOThread() { return true; } +bool V4L2VideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { + decode_client_ = decode_client_; + decode_task_runner_ = decode_task_runner; + return true; +} // static media::VideoDecodeAccelerator::SupportedProfiles @@ -477,7 +494,7 @@ void V4L2VideoDecodeAccelerator::DecodeTask( bitstream_buffer.id()); scoped_ptr<BitstreamBufferRef> bitstream_record(new BitstreamBufferRef( - io_client_, io_task_runner_, + decode_client_, decode_task_runner_, scoped_ptr<SharedMemoryRegion>( new SharedMemoryRegion(bitstream_buffer, true)), bitstream_buffer.id())); @@ -1270,7 +1287,7 @@ void V4L2VideoDecodeAccelerator::FlushTask() { // Queue up an empty buffer -- this triggers the flush. decoder_input_queue_.push( linked_ptr<BitstreamBufferRef>(new BitstreamBufferRef( - io_client_, io_task_runner_, nullptr, kFlushBufferId))); + decode_client_, decode_task_runner_, nullptr, kFlushBufferId))); decoder_flushing_ = true; SendPictureReady(); // Send all pending PictureReady. @@ -1993,10 +2010,12 @@ void V4L2VideoDecodeAccelerator::SendPictureReady() { bool cleared = pending_picture_ready_.front().cleared; const media::Picture& picture = pending_picture_ready_.front().picture; if (cleared && picture_clearing_count_ == 0) { - // This picture is cleared. Post it to IO thread to reduce latency. This - // should be the case after all pictures are cleared at the beginning. - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture)); + // This picture is cleared. It can be posted to a thread different than + // the main GPU thread to reduce latency. This should be the case after + // all pictures are cleared at the beginning. + decode_task_runner_->PostTask( + FROM_HERE, + base::Bind(&Client::PictureReady, decode_client_, picture)); pending_picture_ready_.pop(); } else if (!cleared || resetting_or_flushing) { DVLOG(3) << "SendPictureReady()" diff --git a/content/common/gpu/media/v4l2_video_decode_accelerator.h b/content/common/gpu/media/v4l2_video_decode_accelerator.h index 3d06665..cb74956 100644 --- a/content/common/gpu/media/v4l2_video_decode_accelerator.h +++ b/content/common/gpu/media/v4l2_video_decode_accelerator.h @@ -23,6 +23,7 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "content/common/gpu/media/v4l2_device.h" #include "media/base/limits.h" #include "media/base/video_decoder_config.h" @@ -78,11 +79,9 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator public: V4L2VideoDecodeAccelerator( EGLDisplay egl_display, - EGLContext egl_context, - const base::WeakPtr<Client>& io_client_, - const base::Callback<bool(void)>& make_context_current, - const scoped_refptr<V4L2Device>& device, - const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner); + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const scoped_refptr<V4L2Device>& device); ~V4L2VideoDecodeAccelerator() override; // media::VideoDecodeAccelerator implementation. @@ -95,7 +94,10 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; static media::VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles(); @@ -316,8 +318,8 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator // Our original calling task runner for the child thread. scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_; - // Task runner of the IO thread. - scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + // Task runner Decode() and PictureReady() run on. + scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner_; // WeakPtr<> pointing to |this| for use in posting tasks from the decoder or // device worker threads back to the child thread. Because the worker threads @@ -332,8 +334,8 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator // child_task_runner_. scoped_ptr<base::WeakPtrFactory<Client> > client_ptr_factory_; base::WeakPtr<Client> client_; - // Callbacks to |io_client_| must be executed on |io_task_runner_|. - base::WeakPtr<Client> io_client_; + // Callbacks to |decode_client_| must be executed on |decode_task_runner_|. + base::WeakPtr<Client> decode_client_; // // Decoder state, owned and operated by decoder_thread_. @@ -438,12 +440,13 @@ class CONTENT_EXPORT V4L2VideoDecodeAccelerator // Other state, held by the child (main) thread. // - // Make our context current before running any EGL entry points. - base::Callback<bool(void)> make_context_current_; - // EGL state EGLDisplay egl_display_; - EGLContext egl_context_; + + // Callback to get current GLContext. + GetGLContextCallback get_gl_context_cb_; + // Callback to set the correct gl context. + MakeGLContextCurrentCallback make_context_current_cb_; // The codec we'll be decoding for. media::VideoCodecProfile video_profile_; diff --git a/content/common/gpu/media/vaapi_drm_picture.cc b/content/common/gpu/media/vaapi_drm_picture.cc index f207164..ab5a4f2 100644 --- a/content/common/gpu/media/vaapi_drm_picture.cc +++ b/content/common/gpu/media/vaapi_drm_picture.cc @@ -27,16 +27,16 @@ namespace content { VaapiDrmPicture::VaapiDrmPicture( const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)>& make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size) : VaapiPicture(picture_buffer_id, texture_id, size), vaapi_wrapper_(vaapi_wrapper), - make_context_current_(make_context_current) {} + make_context_current_cb_(make_context_current_cb) {} VaapiDrmPicture::~VaapiDrmPicture() { - if (gl_image_ && make_context_current_.Run()) { + if (gl_image_ && make_context_current_cb_.Run()) { gl_image_->ReleaseTexImage(GL_TEXTURE_EXTERNAL_OES); gl_image_->Destroy(true); @@ -67,7 +67,7 @@ bool VaapiDrmPicture::Initialize() { pixmap_->SetProcessingCallback( base::Bind(&VaapiWrapper::ProcessPixmap, vaapi_wrapper_)); - if (!make_context_current_.Run()) + if (!make_context_current_cb_.Run()) return false; gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES, diff --git a/content/common/gpu/media/vaapi_drm_picture.h b/content/common/gpu/media/vaapi_drm_picture.h index 066192b..7f5fc8a 100644 --- a/content/common/gpu/media/vaapi_drm_picture.h +++ b/content/common/gpu/media/vaapi_drm_picture.h @@ -11,7 +11,6 @@ #include <stdint.h> -#include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -35,7 +34,7 @@ class VaapiWrapper; class VaapiDrmPicture : public VaapiPicture { public: VaapiDrmPicture(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)>& make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size); @@ -52,7 +51,7 @@ class VaapiDrmPicture : public VaapiPicture { private: scoped_refptr<VaapiWrapper> vaapi_wrapper_; - base::Callback<bool(void)> make_context_current_; + MakeGLContextCurrentCallback make_context_current_cb_; // Ozone buffer, the storage of the EGLImage and the VASurface. scoped_refptr<ui::NativePixmap> pixmap_; diff --git a/content/common/gpu/media/vaapi_picture.cc b/content/common/gpu/media/vaapi_picture.cc index 5222bd2..cdf8c35 100644 --- a/content/common/gpu/media/vaapi_picture.cc +++ b/content/common/gpu/media/vaapi_picture.cc @@ -18,16 +18,16 @@ namespace content { // static linked_ptr<VaapiPicture> VaapiPicture::CreatePicture( const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)> make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size) { linked_ptr<VaapiPicture> picture; #if defined(USE_X11) - picture.reset(new VaapiTFPPicture(vaapi_wrapper, make_context_current, + picture.reset(new VaapiTFPPicture(vaapi_wrapper, make_context_current_cb, picture_buffer_id, texture_id, size)); #elif defined(USE_OZONE) - picture.reset(new VaapiDrmPicture(vaapi_wrapper, make_context_current, + picture.reset(new VaapiDrmPicture(vaapi_wrapper, make_context_current_cb, picture_buffer_id, texture_id, size)); #endif // USE_X11 diff --git a/content/common/gpu/media/vaapi_picture.h b/content/common/gpu/media/vaapi_picture.h index 921f803..4bd51e1 100644 --- a/content/common/gpu/media/vaapi_picture.h +++ b/content/common/gpu/media/vaapi_picture.h @@ -12,11 +12,11 @@ #include <stdint.h> -#include "base/callback.h" #include "base/macros.h" #include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" #include "base/threading/non_thread_safe.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "ui/gfx/geometry/size.h" namespace gl { @@ -52,10 +52,10 @@ class VaapiPicture : public base::NonThreadSafe { // Create a VaapiPicture of |size| to be associated with // |picture_buffer_id| and bound to |texture_id|. - // |make_context_current| is provided for the GL operations. + // |make_context_current_cb| is provided for the GL operations. static linked_ptr<VaapiPicture> CreatePicture( const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)> make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size); diff --git a/content/common/gpu/media/vaapi_tfp_picture.cc b/content/common/gpu/media/vaapi_tfp_picture.cc index 3de593b..074ba98 100644 --- a/content/common/gpu/media/vaapi_tfp_picture.cc +++ b/content/common/gpu/media/vaapi_tfp_picture.cc @@ -14,18 +14,18 @@ namespace content { VaapiTFPPicture::VaapiTFPPicture( const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)> make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size) : VaapiPicture(picture_buffer_id, texture_id, size), vaapi_wrapper_(vaapi_wrapper), - make_context_current_(make_context_current), + make_context_current_cb_(make_context_current_cb), x_display_(gfx::GetXDisplay()), x_pixmap_(0) {} VaapiTFPPicture::~VaapiTFPPicture() { - if (glx_image_.get() && make_context_current_.Run()) { + if (glx_image_.get() && make_context_current_cb_.Run()) { glx_image_->ReleaseTexImage(GL_TEXTURE_2D); glx_image_->Destroy(true); DCHECK_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR)); @@ -36,7 +36,7 @@ VaapiTFPPicture::~VaapiTFPPicture() { } bool VaapiTFPPicture::Initialize() { - if (!make_context_current_.Run()) + if (!make_context_current_cb_.Run()) return false; XWindowAttributes win_attr; diff --git a/content/common/gpu/media/vaapi_tfp_picture.h b/content/common/gpu/media/vaapi_tfp_picture.h index 3b66e10..5ef3565 100644 --- a/content/common/gpu/media/vaapi_tfp_picture.h +++ b/content/common/gpu/media/vaapi_tfp_picture.h @@ -11,7 +11,6 @@ #include <stdint.h> -#include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "content/common/gpu/media/vaapi_picture.h" @@ -34,7 +33,7 @@ class VaapiWrapper; class VaapiTFPPicture : public VaapiPicture { public: VaapiTFPPicture(const scoped_refptr<VaapiWrapper>& vaapi_wrapper, - const base::Callback<bool(void)> make_context_current, + const MakeGLContextCurrentCallback& make_context_current_cb, int32_t picture_buffer_id, uint32_t texture_id, const gfx::Size& size); @@ -50,7 +49,7 @@ class VaapiTFPPicture : public VaapiPicture { private: scoped_refptr<VaapiWrapper> vaapi_wrapper_; - base::Callback<bool(void)> make_context_current_; + MakeGLContextCurrentCallback make_context_current_cb_; Display* x_display_; Pixmap x_pixmap_; diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc index 2ede678..18d3b9a 100644 --- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc +++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc @@ -292,10 +292,9 @@ VaapiPicture* VaapiVideoDecodeAccelerator::PictureById( } VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( - const MakeContextCurrentCallback& make_context_current, - const BindImageCallback& bind_image) - : make_context_current_(make_context_current), - state_(kUninitialized), + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb) + : state_(kUninitialized), input_ready_(&lock_), surfaces_available_(&lock_), message_loop_(base::MessageLoop::current()), @@ -305,7 +304,8 @@ VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( finish_flush_pending_(false), awaiting_va_surfaces_recycle_(false), requested_num_pics_(0), - bind_image_(bind_image), + make_context_current_cb_(make_context_current_cb), + bind_image_cb_(bind_image_cb), weak_this_factory_(this) { weak_this_ = weak_this_factory_.GetWeakPtr(); va_surface_release_cb_ = media::BindToCurrentLoop( @@ -320,6 +320,11 @@ bool VaapiVideoDecodeAccelerator::Initialize(const Config& config, Client* client) { DCHECK_EQ(message_loop_, base::MessageLoop::current()); + if (make_context_current_cb_.is_null() || bind_image_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + if (config.is_encrypted) { NOTREACHED() << "Encrypted streams are not supported for this VDA"; return false; @@ -741,13 +746,15 @@ void VaapiVideoDecodeAccelerator::AssignPictureBuffers( << " VASurfaceID: " << va_surface_ids[i]; linked_ptr<VaapiPicture> picture(VaapiPicture::CreatePicture( - vaapi_wrapper_, make_context_current_, buffers[i].id(), + vaapi_wrapper_, make_context_current_cb_, buffers[i].id(), buffers[i].texture_id(), requested_pic_size_)); scoped_refptr<gl::GLImage> image = picture->GetImageToBind(); if (image) { - bind_image_.Run(buffers[i].internal_texture_id(), - VaapiPicture::GetGLTextureTarget(), image, true); + RETURN_AND_NOTIFY_ON_FAILURE( + bind_image_cb_.Run(buffers[i].internal_texture_id(), + VaapiPicture::GetGLTextureTarget(), image, true), + "Failed to bind image", PLATFORM_FAILURE, ); } RETURN_AND_NOTIFY_ON_FAILURE( @@ -962,7 +969,9 @@ void VaapiVideoDecodeAccelerator::Destroy() { delete this; } -bool VaapiVideoDecodeAccelerator::CanDecodeOnIOThread() { +bool VaapiVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { return false; } diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.h b/content/common/gpu/media/vaapi_video_decode_accelerator.h index d14b06a..f9cfb90 100644 --- a/content/common/gpu/media/vaapi_video_decode_accelerator.h +++ b/content/common/gpu/media/vaapi_video_decode_accelerator.h @@ -26,6 +26,7 @@ #include "base/synchronization/lock.h" #include "base/threading/thread.h" #include "content/common/content_export.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "content/common/gpu/media/shared_memory_region.h" #include "content/common/gpu/media/vaapi_wrapper.h" #include "media/base/bitstream_buffer.h" @@ -55,8 +56,9 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator class VaapiDecodeSurface; VaapiVideoDecodeAccelerator( - const MakeContextCurrentCallback& make_context_current, - const BindImageCallback& bind_image); + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb); + ~VaapiVideoDecodeAccelerator() override; // media::VideoDecodeAccelerator implementation. @@ -68,7 +70,10 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; static media::VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles(); @@ -179,10 +184,6 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator // available. scoped_refptr<VaapiDecodeSurface> CreateSurface(); - - // Client-provided GL state. - MakeContextCurrentCallback make_context_current_; - // VAVDA state. enum State { // Initialize() not called yet or failed. @@ -303,9 +304,11 @@ class CONTENT_EXPORT VaapiVideoDecodeAccelerator size_t requested_num_pics_; gfx::Size requested_pic_size_; - // Binds the provided GLImage to a givenr client texture ID & texture target - // combination in GLES. - BindImageCallback bind_image_; + // Callback to make GL context current. + MakeGLContextCurrentCallback make_context_current_cb_; + + // Callback to bind a GLImage to a given texture. + BindGLImageCallback bind_image_cb_; // The WeakPtrFactory for |weak_this_|. base::WeakPtrFactory<VaapiVideoDecodeAccelerator> weak_this_factory_; diff --git a/content/common/gpu/media/video_decode_accelerator_unittest.cc b/content/common/gpu/media/video_decode_accelerator_unittest.cc index c7ca0d2..a04e7c8 100644 --- a/content/common/gpu/media/video_decode_accelerator_unittest.cc +++ b/content/common/gpu/media/video_decode_accelerator_unittest.cc @@ -47,8 +47,10 @@ #include "base/threading/thread.h" #include "build/build_config.h" #include "content/common/gpu/media/fake_video_decode_accelerator.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h" #include "content/common/gpu/media/rendering_helper.h" #include "content/common/gpu/media/video_accelerator_unittest_helpers.h" +#include "gpu/command_buffer/service/gpu_preferences.h" #include "media/filters/h264_parser.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/codec/png_codec.h" @@ -358,17 +360,6 @@ class GLRenderingVDAClient private: typedef std::map<int32_t, scoped_refptr<TextureRef>> TextureRefMap; - scoped_ptr<media::VideoDecodeAccelerator> CreateFakeVDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateDXVAVDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2VDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateV4L2SliceVDA(); - scoped_ptr<media::VideoDecodeAccelerator> CreateVaapiVDA(); - - void BindImage(uint32_t client_texture_id, - uint32_t texture_target, - scoped_refptr<gl::GLImage> image, - bool can_bind_as_sampler); - void SetState(ClientState new_state); void FinishInitialization(); void ReturnPicture(int32_t picture_buffer_id); @@ -401,8 +392,10 @@ class GLRenderingVDAClient int next_bitstream_buffer_id_; ClientStateNotification<ClientState>* note_; scoped_ptr<VideoDecodeAccelerator> decoder_; - scoped_ptr<base::WeakPtrFactory<VideoDecodeAccelerator> > - weak_decoder_factory_; + base::WeakPtr<VideoDecodeAccelerator> weak_vda_; + scoped_ptr<base::WeakPtrFactory<VideoDecodeAccelerator>> + weak_vda_ptr_factory_; + scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> vda_factory_; int remaining_play_throughs_; int reset_after_frame_num_; int delete_decoder_state_; @@ -440,9 +433,23 @@ class GLRenderingVDAClient int32_t next_picture_buffer_id_; + base::WeakPtr<GLRenderingVDAClient> weak_this_; + base::WeakPtrFactory<GLRenderingVDAClient> weak_this_factory_; + DISALLOW_IMPLICIT_CONSTRUCTORS(GLRenderingVDAClient); }; +static bool DoNothingReturnTrue() { + return true; +} + +static bool DummyBindImage(uint32_t client_texture_id, + uint32_t texture_target, + const scoped_refptr<gl::GLImage>& image, + bool can_bind_to_sampler) { + return true; +} + GLRenderingVDAClient::GLRenderingVDAClient( size_t window_id, RenderingHelper* rendering_helper, @@ -483,7 +490,8 @@ GLRenderingVDAClient::GLRenderingVDAClient( delay_reuse_after_frame_num_(delay_reuse_after_frame_num), decode_calls_per_second_(decode_calls_per_second), render_as_thumbnails_(render_as_thumbnails), - next_picture_buffer_id_(1) { + next_picture_buffer_id_(1), + weak_this_factory_(this) { LOG_ASSERT(num_in_flight_decodes > 0); LOG_ASSERT(num_play_throughs > 0); // |num_in_flight_decodes_| is unsupported if |decode_calls_per_second_| > 0. @@ -494,6 +502,8 @@ GLRenderingVDAClient::GLRenderingVDAClient( profile_ = (profile != media::VIDEO_CODEC_PROFILE_UNKNOWN ? profile : media::H264PROFILE_BASELINE); + + weak_this_ = weak_this_factory_.GetWeakPtr(); } GLRenderingVDAClient::~GLRenderingVDAClient() { @@ -502,114 +512,35 @@ GLRenderingVDAClient::~GLRenderingVDAClient() { SetState(CS_DESTROYED); } -static bool DoNothingReturnTrue() { return true; } +void GLRenderingVDAClient::CreateAndStartDecoder() { + LOG_ASSERT(decoder_deleted()); + LOG_ASSERT(!decoder_.get()); -scoped_ptr<media::VideoDecodeAccelerator> -GLRenderingVDAClient::CreateFakeVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; if (fake_decoder_) { - decoder.reset(new FakeVideoDecodeAccelerator( - static_cast<gfx::GLContext*> (rendering_helper_->GetGLContextHandle()), - frame_size_, - base::Bind(&DoNothingReturnTrue))); - } - return decoder; -} - -scoped_ptr<media::VideoDecodeAccelerator> -GLRenderingVDAClient::CreateDXVAVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_WIN) - if (base::win::GetVersion() >= base::win::VERSION_WIN7) { - const bool enable_accelerated_vpx_decode = false; - decoder.reset(new DXVAVideoDecodeAccelerator( - base::Bind(&DoNothingReturnTrue), - rendering_helper_->GetGLContext().get(), - enable_accelerated_vpx_decode)); - } -#endif - return decoder; -} - -scoped_ptr<media::VideoDecodeAccelerator> -GLRenderingVDAClient::CreateV4L2VDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) - scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); - if (device.get()) { - base::WeakPtr<VideoDecodeAccelerator::Client> weak_client = AsWeakPtr(); - decoder.reset(new V4L2VideoDecodeAccelerator( - static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()), - static_cast<EGLContext>(rendering_helper_->GetGLContextHandle()), - weak_client, base::Bind(&DoNothingReturnTrue), device, - base::ThreadTaskRunnerHandle::Get())); - } -#endif - return decoder; -} + decoder_.reset(new FakeVideoDecodeAccelerator( + frame_size_, base::Bind(&DoNothingReturnTrue))); + LOG_ASSERT(decoder_->Initialize(profile_, this)); + } else { + if (!vda_factory_) { + vda_factory_ = GpuVideoDecodeAcceleratorFactoryImpl::Create( + base::Bind(&RenderingHelper::GetGLContext, + base::Unretained(rendering_helper_)), + base::Bind(&DoNothingReturnTrue), base::Bind(&DummyBindImage)); + LOG_ASSERT(vda_factory_); + } -scoped_ptr<media::VideoDecodeAccelerator> -GLRenderingVDAClient::CreateV4L2SliceVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_CHROMEOS) && defined(USE_V4L2_CODEC) - scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); - if (device.get()) { - base::WeakPtr<VideoDecodeAccelerator::Client> weak_client = AsWeakPtr(); - decoder.reset(new V4L2SliceVideoDecodeAccelerator( - device, static_cast<EGLDisplay>(rendering_helper_->GetGLDisplay()), - static_cast<EGLContext>(rendering_helper_->GetGLContextHandle()), - weak_client, base::Bind(&DoNothingReturnTrue), - base::ThreadTaskRunnerHandle::Get())); + VideoDecodeAccelerator::Config config(profile_); + gpu::GpuPreferences gpu_preferences; + decoder_ = vda_factory_->CreateVDA(this, config, gpu_preferences); } -#endif - return decoder; -} -scoped_ptr<media::VideoDecodeAccelerator> -GLRenderingVDAClient::CreateVaapiVDA() { - scoped_ptr<media::VideoDecodeAccelerator> decoder; -#if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) - decoder.reset(new VaapiVideoDecodeAccelerator( - base::Bind(&DoNothingReturnTrue), - base::Bind(&GLRenderingVDAClient::BindImage, base::Unretained(this)))); -#endif - return decoder; -} + LOG_ASSERT(decoder_) << "Failed creating a VDA"; -void GLRenderingVDAClient::BindImage(uint32_t client_texture_id, - uint32_t texture_target, - scoped_refptr<gl::GLImage> image, - bool can_bind_to_sampler) {} + decoder_->TryToSetupDecodeOnSeparateThread( + weak_this_, base::ThreadTaskRunnerHandle::Get()); -void GLRenderingVDAClient::CreateAndStartDecoder() { - LOG_ASSERT(decoder_deleted()); - LOG_ASSERT(!decoder_.get()); - - VideoDecodeAccelerator::Client* client = this; - - scoped_ptr<media::VideoDecodeAccelerator> decoders[] = { - CreateFakeVDA(), - CreateDXVAVDA(), - CreateV4L2VDA(), - CreateV4L2SliceVDA(), - CreateVaapiVDA(), - }; - - for (size_t i = 0; i < arraysize(decoders); ++i) { - if (!decoders[i]) - continue; - decoder_ = std::move(decoders[i]); - weak_decoder_factory_.reset( - new base::WeakPtrFactory<VideoDecodeAccelerator>(decoder_.get())); - if (decoder_->Initialize(profile_, client)) { - SetState(CS_DECODER_SET); - FinishInitialization(); - return; - } - } - // Decoders are all initialize failed. - LOG(ERROR) << "VideoDecodeAccelerator::Initialize() failed"; - LOG_ASSERT(false); + SetState(CS_DECODER_SET); + FinishInitialization(); } void GLRenderingVDAClient::ProvidePictureBuffers( @@ -713,10 +644,8 @@ void GLRenderingVDAClient::ReturnPicture(int32_t picture_buffer_id) { if (num_decoded_frames_ > delay_reuse_after_frame_num_) { base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&VideoDecodeAccelerator::ReusePictureBuffer, - weak_decoder_factory_->GetWeakPtr(), - picture_buffer_id), + FROM_HERE, base::Bind(&VideoDecodeAccelerator::ReusePictureBuffer, + weak_vda_, picture_buffer_id), kReuseDelay); } else { decoder_->ReusePictureBuffer(picture_buffer_id); @@ -838,7 +767,7 @@ void GLRenderingVDAClient::FinishInitialization() { void GLRenderingVDAClient::DeleteDecoder() { if (decoder_deleted()) return; - weak_decoder_factory_.reset(); + weak_vda_ptr_factory_.reset(); decoder_.reset(); STLClearObject(&encoded_data_); active_textures_.clear(); diff --git a/content/common/gpu/media/vt_video_decode_accelerator_mac.cc b/content/common/gpu/media/vt_video_decode_accelerator_mac.cc index 50e144b..69e1517 100644 --- a/content/common/gpu/media/vt_video_decode_accelerator_mac.cc +++ b/content/common/gpu/media/vt_video_decode_accelerator_mac.cc @@ -283,10 +283,10 @@ bool VTVideoDecodeAccelerator::FrameOrder::operator()( } VTVideoDecodeAccelerator::VTVideoDecodeAccelerator( - const MakeContextCurrentCallback& make_context_current, - const BindImageCallback& bind_image) - : make_context_current_(make_context_current), - bind_image_(bind_image), + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb) + : make_context_current_cb_(make_context_current_cb), + bind_image_cb_(bind_image_cb), client_(nullptr), state_(STATE_DECODING), format_(nullptr), @@ -298,7 +298,6 @@ VTVideoDecodeAccelerator::VTVideoDecodeAccelerator( gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()), decoder_thread_("VTDecoderThread"), weak_this_factory_(this) { - DCHECK(!make_context_current_.is_null()); callback_.decompressionOutputCallback = OutputThunk; callback_.decompressionOutputRefCon = this; weak_this_ = weak_this_factory_.GetWeakPtr(); @@ -312,6 +311,11 @@ bool VTVideoDecodeAccelerator::Initialize(const Config& config, Client* client) { DCHECK(gpu_thread_checker_.CalledOnValidThread()); + if (make_context_current_cb_.is_null() || bind_image_cb_.is_null()) { + NOTREACHED() << "GL callbacks are required for this VDA"; + return false; + } + if (config.is_encrypted) { NOTREACHED() << "Encrypted streams are not supported for this VDA"; return false; @@ -1022,7 +1026,7 @@ bool VTVideoDecodeAccelerator::SendFrame(const Frame& frame) { DCHECK(!picture_info->cv_image); DCHECK(!picture_info->gl_image); - if (!make_context_current_.Run()) { + if (!make_context_current_cb_.Run()) { DLOG(ERROR) << "Failed to make GL context current"; NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); return false; @@ -1041,8 +1045,12 @@ bool VTVideoDecodeAccelerator::SendFrame(const Frame& frame) { // Mark that the image is not bound for sampling. 4:2:0 images need to // undergo a separate copy to be displayed. - bind_image_.Run(picture_info->client_texture_id, GL_TEXTURE_RECTANGLE_ARB, - gl_image, false); + if (!bind_image_cb_.Run(picture_info->client_texture_id, + GL_TEXTURE_RECTANGLE_ARB, gl_image, false)) { + DLOG(ERROR) << "Failed to bind image"; + NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); + return false; + } // Assign the new image(s) to the the picture info. picture_info->gl_image = gl_image; @@ -1118,7 +1126,9 @@ void VTVideoDecodeAccelerator::Destroy() { QueueFlush(TASK_DESTROY); } -bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { +bool VTVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { return false; } diff --git a/content/common/gpu/media/vt_video_decode_accelerator_mac.h b/content/common/gpu/media/vt_video_decode_accelerator_mac.h index c3e75e9..031b46a 100644 --- a/content/common/gpu/media/vt_video_decode_accelerator_mac.h +++ b/content/common/gpu/media/vt_video_decode_accelerator_mac.h @@ -17,6 +17,7 @@ #include "base/message_loop/message_loop.h" #include "base/threading/thread.h" #include "base/threading/thread_checker.h" +#include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h" #include "content/common/gpu/media/vt_mac.h" #include "media/filters/h264_parser.h" #include "media/video/h264_poc.h" @@ -35,8 +36,9 @@ bool InitializeVideoToolbox(); class VTVideoDecodeAccelerator : public media::VideoDecodeAccelerator { public: explicit VTVideoDecodeAccelerator( - const MakeContextCurrentCallback& make_context_current, - const BindImageCallback& bind_image); + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb); + ~VTVideoDecodeAccelerator() override; // VideoDecodeAccelerator implementation. @@ -48,7 +50,10 @@ class VTVideoDecodeAccelerator : public media::VideoDecodeAccelerator { void Flush() override; void Reset() override; void Destroy() override; - bool CanDecodeOnIOThread() override; + bool TryToSetupDecodeOnSeparateThread( + const base::WeakPtr<Client>& decode_client, + const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) + override; // Called by OutputThunk() when VideoToolbox finishes decoding a frame. void Output( @@ -188,8 +193,8 @@ class VTVideoDecodeAccelerator : public media::VideoDecodeAccelerator { // // GPU thread state. // - MakeContextCurrentCallback make_context_current_; - BindImageCallback bind_image_; + MakeGLContextCurrentCallback make_context_current_cb_; + BindGLImageCallback bind_image_cb_; media::VideoDecodeAccelerator::Client* client_; State state_; diff --git a/content/content_common.gypi b/content/content_common.gypi index 5550b37..d449b45 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -407,6 +407,9 @@ 'common/gpu/media/gpu_video_accelerator_util.h', 'common/gpu/media/gpu_video_decode_accelerator.cc', 'common/gpu/media/gpu_video_decode_accelerator.h', + 'common/gpu/media/gpu_video_decode_accelerator_factory_impl.cc', + 'common/gpu/media/gpu_video_decode_accelerator_factory_impl.h', + 'common/gpu/media/gpu_video_decode_accelerator_helpers.h', 'common/gpu/media/gpu_video_encode_accelerator.cc', 'common/gpu/media/gpu_video_encode_accelerator.h', 'common/gpu/media/media_channel.cc', diff --git a/content/content_gpu.gypi b/content/content_gpu.gypi index f134890..47599e7 100644 --- a/content/content_gpu.gypi +++ b/content/content_gpu.gypi @@ -23,6 +23,8 @@ 'gpu/in_process_gpu_thread.cc', 'gpu/in_process_gpu_thread.h', 'public/gpu/content_gpu_client.h', + 'public/gpu/gpu_video_decode_accelerator_factory.cc', + 'public/gpu/gpu_video_decode_accelerator_factory.h', ], 'include_dirs': [ '..', diff --git a/content/public/gpu/BUILD.gn b/content/public/gpu/BUILD.gn index 708d8b6..c4c12f0 100644 --- a/content/public/gpu/BUILD.gn +++ b/content/public/gpu/BUILD.gn @@ -20,6 +20,8 @@ source_set("gpu_sources") { sources = [ "content_gpu_client.h", + "gpu_video_decode_accelerator_factory.cc", + "gpu_video_decode_accelerator_factory.h", ] deps = [ @@ -27,6 +29,9 @@ source_set("gpu_sources") { "//content:export", "//content/gpu:gpu_sources", "//content/public/common:common_sources", + "//gpu/command_buffer/service:service_sources", + "//gpu/config:config_sources", + "//media:media", ] allow_circular_includes_from = [ "//content/gpu:gpu_sources" ] diff --git a/content/public/gpu/DEPS b/content/public/gpu/DEPS new file mode 100644 index 0000000..3059074 --- /dev/null +++ b/content/public/gpu/DEPS @@ -0,0 +1,9 @@ +specific_include_rules = { + ".*\.cc": [ + "+content/common", + ], + "gpu_video_decode_accelerator_factory.h": [ + "+gpu", + "+media", + ], +} diff --git a/content/public/gpu/gpu_video_decode_accelerator_factory.cc b/content/public/gpu/gpu_video_decode_accelerator_factory.cc new file mode 100644 index 0000000..57b46a8 --- /dev/null +++ b/content/public/gpu/gpu_video_decode_accelerator_factory.cc @@ -0,0 +1,68 @@ +// Copyright 2016 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 "content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h" +#include "content/public/gpu/gpu_video_decode_accelerator_factory.h" + +namespace content { + +GpuVideoDecodeAcceleratorFactory::~GpuVideoDecodeAcceleratorFactory() {} + +// static +scoped_ptr<GpuVideoDecodeAcceleratorFactory> +GpuVideoDecodeAcceleratorFactory::Create( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb) { + auto gvdafactory_impl = GpuVideoDecodeAcceleratorFactoryImpl::Create( + get_gl_context_cb, make_context_current_cb, bind_image_cb); + if (!gvdafactory_impl) + return nullptr; + + return make_scoped_ptr( + new GpuVideoDecodeAcceleratorFactory(std::move(gvdafactory_impl))); +} + +// static +scoped_ptr<GpuVideoDecodeAcceleratorFactory> +GpuVideoDecodeAcceleratorFactory::CreateWithGLES2Decoder( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb) { + auto gvdafactory_impl = + GpuVideoDecodeAcceleratorFactoryImpl::CreateWithGLES2Decoder( + get_gl_context_cb, make_context_current_cb, bind_image_cb, + get_gles2_decoder_cb); + if (!gvdafactory_impl) + return nullptr; + + return make_scoped_ptr( + new GpuVideoDecodeAcceleratorFactory(std::move(gvdafactory_impl))); +} + +// static +gpu::VideoDecodeAcceleratorCapabilities +GpuVideoDecodeAcceleratorFactory::GetDecoderCapabilities( + const gpu::GpuPreferences& gpu_preferences) { + return GpuVideoDecodeAcceleratorFactoryImpl::GetDecoderCapabilities( + gpu_preferences); +} + +scoped_ptr<media::VideoDecodeAccelerator> +GpuVideoDecodeAcceleratorFactory::CreateVDA( + media::VideoDecodeAccelerator::Client* client, + const media::VideoDecodeAccelerator::Config& config, + const gpu::GpuPreferences& gpu_preferences) { + if (!gvdafactory_impl_) + return nullptr; + + return gvdafactory_impl_->CreateVDA(client, config, gpu_preferences); +} + +GpuVideoDecodeAcceleratorFactory::GpuVideoDecodeAcceleratorFactory( + scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> gvdafactory_impl) + : gvdafactory_impl_(std::move(gvdafactory_impl)) {} + +} // namespace content diff --git a/content/public/gpu/gpu_video_decode_accelerator_factory.h b/content/public/gpu/gpu_video_decode_accelerator_factory.h new file mode 100644 index 0000000..b02ceea --- /dev/null +++ b/content/public/gpu/gpu_video_decode_accelerator_factory.h @@ -0,0 +1,96 @@ +// Copyright 2016 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 CONTENT_PUBLIC_GPU_GPU_VIDEO_DECODE_ACCELERATOR_FACTORY_H_ +#define CONTENT_PUBLIC_GPU_GPU_VIDEO_DECODE_ACCELERATOR_FACTORY_H_ + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "content/common/content_export.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "gpu/config/gpu_info.h" +#include "media/video/video_decode_accelerator.h" + +namespace gfx { +class GLContext; +} + +namespace gl { +class GLImage; +} + +namespace gpu { +namespace gles2 { +class GLES2Decoder; +} +} + +namespace content { + +class GpuVideoDecodeAcceleratorFactoryImpl; + +// This factory allows creation of VideoDecodeAccelerator implementations, +// providing the most applicable VDA for current platform and given +// configuration. To be used in GPU process only. +class CONTENT_EXPORT GpuVideoDecodeAcceleratorFactory { + public: + virtual ~GpuVideoDecodeAcceleratorFactory(); + + // Return current GLContext. + using GetGLContextCallback = base::Callback<gfx::GLContext*(void)>; + + // Make the applicable GL context current. To be called by VDAs before + // executing any GL calls. Return true on success, false otherwise. + using MakeGLContextCurrentCallback = base::Callback<bool(void)>; + + // Bind |image| to |client_texture_id| given |texture_target|. If + // |can_bind_to_sampler| is true, then the image may be used as a sampler + // directly, otherwise a copy to a staging buffer is required. + // Return true on success, false otherwise. + using BindGLImageCallback = + base::Callback<bool(uint32_t client_texture_id, + uint32_t texture_target, + const scoped_refptr<gl::GLImage>& image, + bool can_bind_to_sampler)>; + + // Return a WeakPtr to a GLES2Decoder, if one is available. + using GetGLES2DecoderCallback = + base::Callback<base::WeakPtr<gpu::gles2::GLES2Decoder>(void)>; + + // Create a factory capable of producing VDA instances for current platform. + static scoped_ptr<GpuVideoDecodeAcceleratorFactory> Create( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb); + + static scoped_ptr<GpuVideoDecodeAcceleratorFactory> CreateWithGLES2Decoder( + const GetGLContextCallback& get_gl_context_cb, + const MakeGLContextCurrentCallback& make_context_current_cb, + const BindGLImageCallback& bind_image_cb, + const GetGLES2DecoderCallback& get_gles2_decoder_cb); + + // Return decoder capabilities supported on the current platform. + static gpu::VideoDecodeAcceleratorCapabilities GetDecoderCapabilities( + const gpu::GpuPreferences& gpu_preferences); + + // Create a VDA for the current platform for |client| with the given |config| + // and for given |gpu_preferences|. Return nullptr on failure. + virtual scoped_ptr<media::VideoDecodeAccelerator> CreateVDA( + media::VideoDecodeAccelerator::Client* client, + const media::VideoDecodeAccelerator::Config& config, + const gpu::GpuPreferences& gpu_preferences); + + private: + // TODO(posciak): This is temporary and will not be needed once + // GpuVideoDecodeAcceleratorFactoryImpl implements + // GpuVideoDecodeAcceleratorFactory, see crbug.com/597150 and related. + GpuVideoDecodeAcceleratorFactory( + scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> gvdafactory_impl); + + scoped_ptr<GpuVideoDecodeAcceleratorFactoryImpl> gvdafactory_impl_; +}; + +} // namespace content + +#endif // CONTENT_PUBLIC_GPU_GPU_VIDEO_DECODE_ACCELERATOR_FACTORY_H_ |