Respond with QuotaExceededError when IndexedDB has no disk space on open.
[chromium-blink-merge.git] / content / common / gpu / media / gpu_video_decode_accelerator.cc
blobc5de2df00e2004741ebbc645d9f1e3c246251659
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/common/gpu/media/gpu_video_decode_accelerator.h"
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/stl_util.h"
15 #include "content/common/gpu/gpu_channel.h"
16 #include "content/common/gpu/gpu_messages.h"
17 #include "content/public/common/content_switches.h"
18 #include "gpu/command_buffer/common/command_buffer.h"
19 #include "ipc/ipc_message_macros.h"
20 #include "ipc/ipc_message_utils.h"
21 #include "ui/gl/gl_context.h"
22 #include "ui/gl/gl_surface_egl.h"
24 #if defined(OS_WIN)
25 #include "base/win/windows_version.h"
26 #include "content/common/gpu/media/dxva_video_decode_accelerator.h"
27 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
28 #include "content/common/gpu/media/exynos_video_decode_accelerator.h"
29 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
30 #include "ui/gl/gl_context_glx.h"
31 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h"
32 #elif defined(OS_ANDROID)
33 #include "content/common/gpu/media/android_video_decode_accelerator.h"
34 #endif
36 #include "gpu/command_buffer/service/texture_manager.h"
37 #include "ui/gfx/size.h"
39 using gpu::gles2::TextureManager;
41 namespace content {
43 static bool MakeDecoderContextCurrent(
44 const base::WeakPtr<GpuCommandBufferStub> stub) {
45 if (!stub.get()) {
46 DLOG(ERROR) << "Stub is gone; won't MakeCurrent().";
47 return false;
50 if (!stub->decoder()->MakeCurrent()) {
51 DLOG(ERROR) << "Failed to MakeCurrent()";
52 return false;
55 return true;
58 class GpuVideoDecodeAccelerator::MessageFilter
59 : public IPC::ChannelProxy::MessageFilter {
60 public:
61 MessageFilter(GpuVideoDecodeAccelerator* owner, int32 host_route_id)
62 : owner_(owner), host_route_id_(host_route_id) {}
64 virtual void OnChannelError() OVERRIDE { channel_ = NULL; }
66 virtual void OnChannelClosing() OVERRIDE { channel_ = NULL; }
68 virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE {
69 channel_ = channel;
72 virtual void OnFilterRemoved() OVERRIDE {
73 // This will delete |owner_| and |this|.
74 owner_->OnFilterRemoved();
77 virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
78 if (msg.routing_id() != host_route_id_)
79 return false;
81 IPC_BEGIN_MESSAGE_MAP(MessageFilter, msg)
82 IPC_MESSAGE_FORWARD(AcceleratedVideoDecoderMsg_Decode, owner_,
83 GpuVideoDecodeAccelerator::OnDecode)
84 IPC_MESSAGE_UNHANDLED(return false;)
85 IPC_END_MESSAGE_MAP()
86 return true;
89 bool SendOnIOThread(IPC::Message* message) {
90 DCHECK(!message->is_sync());
91 if (!channel_) {
92 delete message;
93 return false;
95 return channel_->Send(message);
98 protected:
99 virtual ~MessageFilter() {}
101 private:
102 GpuVideoDecodeAccelerator* owner_;
103 int32 host_route_id_;
104 // The channel to which this filter was added.
105 IPC::Channel* channel_;
108 GpuVideoDecodeAccelerator::GpuVideoDecodeAccelerator(
109 int32 host_route_id,
110 GpuCommandBufferStub* stub,
111 const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
112 : init_done_msg_(NULL),
113 host_route_id_(host_route_id),
114 stub_(stub),
115 texture_target_(0),
116 io_message_loop_(io_message_loop),
117 weak_factory_for_io_(this) {
118 DCHECK(stub_);
119 stub_->AddDestructionObserver(this);
120 stub_->channel()->AddRoute(host_route_id_, this);
121 child_message_loop_ = base::MessageLoopProxy::current();
122 make_context_current_ =
123 base::Bind(&MakeDecoderContextCurrent, stub_->AsWeakPtr());
126 GpuVideoDecodeAccelerator::~GpuVideoDecodeAccelerator() {
127 if (video_decode_accelerator_)
128 video_decode_accelerator_.release()->Destroy();
131 bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) {
132 DCHECK(stub_);
133 if (!video_decode_accelerator_)
134 return false;
135 bool handled = true;
136 IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAccelerator, msg)
137 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Decode, OnDecode)
138 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_AssignPictureBuffers,
139 OnAssignPictureBuffers)
140 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_ReusePictureBuffer,
141 OnReusePictureBuffer)
142 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Flush, OnFlush)
143 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Reset, OnReset)
144 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Destroy, OnDestroy)
145 IPC_MESSAGE_UNHANDLED(handled = false)
146 IPC_END_MESSAGE_MAP()
147 return handled;
150 void GpuVideoDecodeAccelerator::ProvidePictureBuffers(
151 uint32 requested_num_of_buffers,
152 const gfx::Size& dimensions,
153 uint32 texture_target) {
154 if (!Send(new AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers(
155 host_route_id_, requested_num_of_buffers, dimensions,
156 texture_target))) {
157 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers) "
158 << "failed";
160 texture_target_ = texture_target;
163 void GpuVideoDecodeAccelerator::DismissPictureBuffer(
164 int32 picture_buffer_id) {
165 // Notify client that picture buffer is now unused.
166 if (!Send(new AcceleratedVideoDecoderHostMsg_DismissPictureBuffer(
167 host_route_id_, picture_buffer_id))) {
168 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer) "
169 << "failed";
173 void GpuVideoDecodeAccelerator::PictureReady(
174 const media::Picture& picture) {
175 if (!Send(new AcceleratedVideoDecoderHostMsg_PictureReady(
176 host_route_id_,
177 picture.picture_buffer_id(),
178 picture.bitstream_buffer_id()))) {
179 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_PictureReady) failed";
183 void GpuVideoDecodeAccelerator::NotifyError(
184 media::VideoDecodeAccelerator::Error error) {
185 if (init_done_msg_) {
186 // If we get an error while we're initializing, NotifyInitializeDone won't
187 // be called, so we need to send the reply (with an error) here.
188 GpuCommandBufferMsg_CreateVideoDecoder::WriteReplyParams(
189 init_done_msg_, -1);
190 if (!Send(init_done_msg_))
191 DLOG(ERROR) << "Send(init_done_msg_) failed";
192 init_done_msg_ = NULL;
193 return;
195 if (!Send(new AcceleratedVideoDecoderHostMsg_ErrorNotification(
196 host_route_id_, error))) {
197 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ErrorNotification) "
198 << "failed";
202 void GpuVideoDecodeAccelerator::Initialize(
203 const media::VideoCodecProfile profile,
204 IPC::Message* init_done_msg) {
205 DCHECK(stub_);
206 DCHECK(!video_decode_accelerator_.get());
207 DCHECK(!init_done_msg_);
208 DCHECK(init_done_msg);
209 init_done_msg_ = init_done_msg;
211 #if !defined(OS_WIN)
212 // Ensure we will be able to get a GL context at all before initializing
213 // non-Windows VDAs.
214 if (!make_context_current_.Run()) {
215 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
216 return;
218 #endif
220 #if defined(OS_WIN)
221 if (base::win::GetVersion() < base::win::VERSION_WIN7) {
222 NOTIMPLEMENTED() << "HW video decode acceleration not available.";
223 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
224 return;
226 DLOG(INFO) << "Initializing DXVA HW decoder for windows.";
227 video_decode_accelerator_.reset(new DXVAVideoDecodeAccelerator(
228 this, make_context_current_));
229 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
230 video_decode_accelerator_.reset(new ExynosVideoDecodeAccelerator(
231 gfx::GLSurfaceEGL::GetHardwareDisplay(),
232 stub_->decoder()->GetGLContext()->GetHandle(),
233 this,
234 weak_factory_for_io_.GetWeakPtr(),
235 make_context_current_,
236 io_message_loop_));
237 #elif defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY) && defined(USE_X11)
238 gfx::GLContextGLX* glx_context =
239 static_cast<gfx::GLContextGLX*>(stub_->decoder()->GetGLContext());
240 GLXContext glx_context_handle =
241 static_cast<GLXContext>(glx_context->GetHandle());
242 video_decode_accelerator_.reset(new VaapiVideoDecodeAccelerator(
243 glx_context->display(), glx_context_handle, this,
244 make_context_current_));
245 #elif defined(OS_ANDROID)
246 video_decode_accelerator_.reset(new AndroidVideoDecodeAccelerator(
247 this,
248 stub_->decoder()->AsWeakPtr(),
249 make_context_current_));
250 #else
251 NOTIMPLEMENTED() << "HW video decode acceleration not available.";
252 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
253 return;
254 #endif
256 if (video_decode_accelerator_->CanDecodeOnIOThread()) {
257 filter_ = new MessageFilter(this, host_route_id_);
258 stub_->channel()->AddFilter(filter_.get());
261 if (!video_decode_accelerator_->Initialize(profile))
262 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
265 // Runs on IO thread if video_decode_accelerator_->CanDecodeOnIOThread() is
266 // true, otherwise on the main thread.
267 void GpuVideoDecodeAccelerator::OnDecode(
268 base::SharedMemoryHandle handle, int32 id, uint32 size) {
269 DCHECK(video_decode_accelerator_.get());
270 if (id < 0) {
271 DLOG(FATAL) << "BitstreamBuffer id " << id << " out of range";
272 if (child_message_loop_->BelongsToCurrentThread()) {
273 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT);
274 } else {
275 child_message_loop_->PostTask(
276 FROM_HERE,
277 base::Bind(&GpuVideoDecodeAccelerator::NotifyError,
278 base::Unretained(this),
279 media::VideoDecodeAccelerator::INVALID_ARGUMENT));
281 return;
283 video_decode_accelerator_->Decode(media::BitstreamBuffer(id, handle, size));
286 void GpuVideoDecodeAccelerator::OnAssignPictureBuffers(
287 const std::vector<int32>& buffer_ids,
288 const std::vector<uint32>& texture_ids,
289 const std::vector<gfx::Size>& sizes) {
290 DCHECK(stub_);
291 if (buffer_ids.size() != texture_ids.size() ||
292 buffer_ids.size() != sizes.size()) {
293 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT);
294 return;
297 gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder();
298 gpu::gles2::TextureManager* texture_manager =
299 command_decoder->GetContextGroup()->texture_manager();
301 std::vector<media::PictureBuffer> buffers;
302 for (uint32 i = 0; i < buffer_ids.size(); ++i) {
303 if (buffer_ids[i] < 0) {
304 DLOG(FATAL) << "Buffer id " << buffer_ids[i] << " out of range";
305 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT);
306 return;
308 gpu::gles2::TextureRef* texture_ref = texture_manager->GetTexture(
309 texture_ids[i]);
310 if (!texture_ref) {
311 DLOG(FATAL) << "Failed to find texture id " << texture_ids[i];
312 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT);
313 return;
315 gpu::gles2::Texture* info = texture_ref->texture();
316 if (info->target() != texture_target_) {
317 DLOG(FATAL) << "Texture target mismatch for texture id "
318 << texture_ids[i];
319 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT);
320 return;
322 // GL_TEXTURE_EXTERNAL_OES textures have their dimensions defined by the
323 // underlying EGLImage.
324 if (texture_target_ != GL_TEXTURE_EXTERNAL_OES) {
325 GLsizei width = 0, height = 0;
326 info->GetLevelSize(texture_target_, 0, &width, &height);
327 if (width != sizes[i].width() || height != sizes[i].height()) {
328 DLOG(FATAL) << "Size mismatch for texture id " << texture_ids[i];
329 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT);
330 return;
333 if (!texture_manager->ClearRenderableLevels(command_decoder, texture_ref)) {
334 DLOG(FATAL) << "Failed to Clear texture id " << texture_ids[i];
335 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
336 return;
338 uint32 service_texture_id;
339 if (!command_decoder->GetServiceTextureId(
340 texture_ids[i], &service_texture_id)) {
341 DLOG(FATAL) << "Failed to translate texture!";
342 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
343 return;
345 buffers.push_back(media::PictureBuffer(
346 buffer_ids[i], sizes[i], service_texture_id));
348 video_decode_accelerator_->AssignPictureBuffers(buffers);
351 void GpuVideoDecodeAccelerator::OnReusePictureBuffer(
352 int32 picture_buffer_id) {
353 DCHECK(video_decode_accelerator_.get());
354 video_decode_accelerator_->ReusePictureBuffer(picture_buffer_id);
357 void GpuVideoDecodeAccelerator::OnFlush() {
358 DCHECK(video_decode_accelerator_.get());
359 video_decode_accelerator_->Flush();
362 void GpuVideoDecodeAccelerator::OnReset() {
363 DCHECK(video_decode_accelerator_.get());
364 video_decode_accelerator_->Reset();
367 void GpuVideoDecodeAccelerator::OnDestroy() {
368 DCHECK(video_decode_accelerator_.get());
369 DCHECK(stub_);
370 stub_->channel()->RemoveRoute(host_route_id_);
371 stub_->RemoveDestructionObserver(this);
372 if (filter_.get()) {
373 // Remove the filter first because the member variables can be accessed on
374 // IO thread. When filter is removed, OnFilterRemoved will delete |this|.
375 stub_->channel()->RemoveFilter(filter_.get());
376 } else {
377 delete this;
381 void GpuVideoDecodeAccelerator::OnFilterRemoved() {
382 // We're destroying; cancel all callbacks.
383 weak_factory_for_io_.InvalidateWeakPtrs();
384 child_message_loop_->DeleteSoon(FROM_HERE, this);
387 void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer(
388 int32 bitstream_buffer_id) {
389 if (!Send(new AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed(
390 host_route_id_, bitstream_buffer_id))) {
391 DLOG(ERROR)
392 << "Send(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed) "
393 << "failed";
397 void GpuVideoDecodeAccelerator::NotifyInitializeDone() {
398 GpuCommandBufferMsg_CreateVideoDecoder::WriteReplyParams(
399 init_done_msg_, host_route_id_);
400 if (!Send(init_done_msg_))
401 DLOG(ERROR) << "Send(init_done_msg_) failed";
402 init_done_msg_ = NULL;
405 void GpuVideoDecodeAccelerator::NotifyFlushDone() {
406 if (!Send(new AcceleratedVideoDecoderHostMsg_FlushDone(host_route_id_)))
407 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_FlushDone) failed";
410 void GpuVideoDecodeAccelerator::NotifyResetDone() {
411 if (!Send(new AcceleratedVideoDecoderHostMsg_ResetDone(host_route_id_)))
412 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ResetDone) failed";
415 void GpuVideoDecodeAccelerator::OnWillDestroyStub() { OnDestroy(); }
417 bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) {
418 DCHECK(stub_);
419 if (filter_.get() && io_message_loop_->BelongsToCurrentThread())
420 return filter_->SendOnIOThread(message);
421 DCHECK(child_message_loop_->BelongsToCurrentThread());
422 return stub_->channel()->Send(message);
425 } // namespace content