summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/common/gpu/media/android_video_decode_accelerator.cc72
-rw-r--r--content/common/gpu/media/android_video_decode_accelerator.h18
-rw-r--r--content/common/gpu/media/android_video_decode_accelerator_unittest.cc8
-rw-r--r--content/common/gpu/media/dxva_video_decode_accelerator_win.cc38
-rw-r--r--content/common/gpu/media/dxva_video_decode_accelerator_win.h17
-rw-r--r--content/common/gpu/media/fake_video_decode_accelerator.cc19
-rw-r--r--content/common/gpu/media/fake_video_decode_accelerator.h14
-rw-r--r--content/common/gpu/media/gpu_video_decode_accelerator.cc280
-rw-r--r--content/common/gpu/media/gpu_video_decode_accelerator.h46
-rw-r--r--content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.cc241
-rw-r--r--content/common/gpu/media/gpu_video_decode_accelerator_factory_impl.h126
-rw-r--r--content/common/gpu/media/gpu_video_decode_accelerator_helpers.h59
-rw-r--r--content/common/gpu/media/rendering_helper.cc8
-rw-r--r--content/common/gpu/media/rendering_helper.h5
-rw-r--r--content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc61
-rw-r--r--content/common/gpu/media/v4l2_slice_video_decode_accelerator.h29
-rw-r--r--content/common/gpu/media/v4l2_video_decode_accelerator.cc61
-rw-r--r--content/common/gpu/media/v4l2_video_decode_accelerator.h31
-rw-r--r--content/common/gpu/media/vaapi_drm_picture.cc8
-rw-r--r--content/common/gpu/media/vaapi_drm_picture.h5
-rw-r--r--content/common/gpu/media/vaapi_picture.cc6
-rw-r--r--content/common/gpu/media/vaapi_picture.h6
-rw-r--r--content/common/gpu/media/vaapi_tfp_picture.cc8
-rw-r--r--content/common/gpu/media/vaapi_tfp_picture.h5
-rw-r--r--content/common/gpu/media/vaapi_video_decode_accelerator.cc27
-rw-r--r--content/common/gpu/media/vaapi_video_decode_accelerator.h23
-rw-r--r--content/common/gpu/media/video_decode_accelerator_unittest.cc169
-rw-r--r--content/common/gpu/media/vt_video_decode_accelerator_mac.cc28
-rw-r--r--content/common/gpu/media/vt_video_decode_accelerator_mac.h15
-rw-r--r--content/content_common.gypi3
-rw-r--r--content/content_gpu.gypi2
-rw-r--r--content/public/gpu/BUILD.gn5
-rw-r--r--content/public/gpu/DEPS9
-rw-r--r--content/public/gpu/gpu_video_decode_accelerator_factory.cc68
-rw-r--r--content/public/gpu/gpu_video_decode_accelerator_factory.h96
-rw-r--r--gpu/command_buffer/service/BUILD.gn1
-rw-r--r--gpu/config/BUILD.gn1
-rw-r--r--media/video/mock_video_decode_accelerator.h4
-rw-r--r--media/video/video_decode_accelerator.cc8
-rw-r--r--media/video/video_decode_accelerator.h54
40 files changed, 1103 insertions, 581 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_
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 7ad6816..fc8ad968 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -19,6 +19,7 @@ group("service") {
source_set("service_sources") {
visibility = [
+ "//content/public/gpu/*",
"//gpu/*",
"//mojo/gles2:gles2",
]
diff --git a/gpu/config/BUILD.gn b/gpu/config/BUILD.gn
index 3ca9edf..fa9a972 100644
--- a/gpu/config/BUILD.gn
+++ b/gpu/config/BUILD.gn
@@ -25,6 +25,7 @@ group("config") {
source_set("config_sources") {
visibility = [
"//components/mus/gles2:*",
+ "//content/public/gpu/*",
"//gpu/*",
]
diff --git a/media/video/mock_video_decode_accelerator.h b/media/video/mock_video_decode_accelerator.h
index 63aeaad..89978987 100644
--- a/media/video/mock_video_decode_accelerator.h
+++ b/media/video/mock_video_decode_accelerator.h
@@ -34,7 +34,9 @@ class MockVideoDecodeAccelerator : public VideoDecodeAccelerator {
MOCK_METHOD0(Flush, void());
MOCK_METHOD0(Reset, void());
MOCK_METHOD0(Destroy, void());
- MOCK_METHOD0(CanDecodeOnIOThread, bool());
+ MOCK_METHOD2(TryToSetupDecodeOnSeparateThread,
+ bool(const base::WeakPtr<Client>&,
+ const scoped_refptr<base::SingleThreadTaskRunner>&));
private:
void DeleteThis();
diff --git a/media/video/video_decode_accelerator.cc b/media/video/video_decode_accelerator.cc
index f99787a..00ae88c 100644
--- a/media/video/video_decode_accelerator.cc
+++ b/media/video/video_decode_accelerator.cc
@@ -34,9 +34,11 @@ void VideoDecodeAccelerator::SetCdm(int cdm_id) {
NOTREACHED() << "By default CDM is not supported.";
}
-bool VideoDecodeAccelerator::CanDecodeOnIOThread() {
- // GPU process subclasses must override this.
- LOG(FATAL) << "This should only get called in the GPU process";
+bool VideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread(
+ const base::WeakPtr<Client>& decode_client,
+ const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) {
+ // Implementations in the process that VDA runs in must override this.
+ LOG(FATAL) << "This may only be called in the same process as VDA impl.";
return false; // not reached
}
diff --git a/media/video/video_decode_accelerator.h b/media/video/video_decode_accelerator.h
index a840750..4552973 100644
--- a/media/video/video_decode_accelerator.h
+++ b/media/video/video_decode_accelerator.h
@@ -10,15 +10,20 @@
#include <memory>
#include <vector>
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "media/base/bitstream_buffer.h"
#include "media/base/surface_manager.h"
#include "media/base/video_decoder_config.h"
#include "media/video/picture.h"
#include "ui/gfx/geometry/size.h"
-#include "ui/gl/gl_image.h"
typedef unsigned int GLenum;
+namespace base {
+class SingleThreadTaskRunner;
+}
+
namespace media {
// Video decoder interface.
@@ -38,10 +43,6 @@ class MEDIA_EXPORT VideoDecodeAccelerator {
};
using SupportedProfiles = std::vector<SupportedProfile>;
- using MakeContextCurrentCallback = base::Callback<bool(void)>;
- using BindImageCallback = base::Callback<
- void(uint32_t, uint32_t, scoped_refptr<gl::GLImage>, bool)>;
-
struct MEDIA_EXPORT Capabilities {
Capabilities();
Capabilities(const Capabilities& other);
@@ -229,16 +230,39 @@ class MEDIA_EXPORT VideoDecodeAccelerator {
// unconditionally, so make sure to drop all pointers to it!
virtual void Destroy() = 0;
- // GPU PROCESS ONLY. Implementations of this interface in the
- // content/common/gpu/media should implement this, and implementations in
- // other processes should not override the default implementation.
- // Returns true if VDA::Decode and VDA::Client callbacks can run on the IO
- // thread. Otherwise they will run on the GPU child thread. The purpose of
- // running Decode on the IO thread is to reduce decode latency. Note Decode
- // should return as soon as possible and not block on the IO thread. Also,
- // PictureReady should be run on the child thread if a picture is delivered
- // the first time so it can be cleared.
- virtual bool CanDecodeOnIOThread();
+ // TO BE CALLED IN THE SAME PROCESS AS THE VDA IMPLEMENTATION ONLY.
+ //
+ // A decode "task" is a sequence that includes a Decode() call from Client,
+ // as well as corresponding callbacks to return the input BitstreamBuffer
+ // after use, and the resulting output Picture(s).
+ //
+ // If the Client can support running these three calls on a separate thread,
+ // it may call this method to try to set up the VDA implementation to do so.
+ // If the VDA can support this as well, return true, otherwise return false.
+ // If true is returned, the client may submit each Decode() call (but no other
+ // calls) on |decode_task_runner|, and should then expect that
+ // NotifyEndOfBitstreamBuffer() and PictureReady() callbacks may come on
+ // |decode_task_runner| as well, called on |decode_client|, instead of client
+ // provided to Initialize().
+ //
+ // This method may be called at any time.
+ //
+ // NOTE 1: some callbacks may still have to come on the main thread and the
+ // Client should handle both callbacks coming on main and |decode_task_runner|
+ // thread.
+ //
+ // NOTE 2: VDA implementations of Decode() must return as soon as possible and
+ // never block, as |decode_task_runner| may be a latency critical thread
+ // (such as the GPU IO thread).
+ //
+ // One application of this is offloading the GPU Child thread. In general,
+ // calls to VDA in GPU process have to be done on the GPU Child thread, as
+ // they may require GL context to be current. However, some VDAs may be able
+ // to run decode operations without GL context, which helps reduce latency and
+ // offloads the GPU Child thread.
+ virtual bool TryToSetupDecodeOnSeparateThread(
+ const base::WeakPtr<Client>& decode_client,
+ const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner);
// Windows creates a BGRA texture.
// TODO(dshwang): after moving to D3D11, remove this. crbug.com/438691