OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/gpu/ipc/service/gpu_video_decode_accelerator.h" | 5 #include "media/gpu/ipc/service/gpu_video_decode_accelerator.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 DLOG(ERROR) | 216 DLOG(ERROR) |
217 << "Send(AcceleratedVideoDecoderHostMsg_InitializationComplete) failed"; | 217 << "Send(AcceleratedVideoDecoderHostMsg_InitializationComplete) failed"; |
218 } | 218 } |
219 | 219 |
220 void GpuVideoDecodeAccelerator::ProvidePictureBuffers( | 220 void GpuVideoDecodeAccelerator::ProvidePictureBuffers( |
221 uint32_t requested_num_of_buffers, | 221 uint32_t requested_num_of_buffers, |
222 VideoPixelFormat format, | 222 VideoPixelFormat format, |
223 uint32_t textures_per_buffer, | 223 uint32_t textures_per_buffer, |
224 const gfx::Size& dimensions, | 224 const gfx::Size& dimensions, |
225 uint32_t texture_target) { | 225 uint32_t texture_target) { |
226 if (dimensions.width() > media::limits::kMaxDimension || | 226 if (dimensions.width() > limits::kMaxDimension || |
227 dimensions.height() > media::limits::kMaxDimension || | 227 dimensions.height() > limits::kMaxDimension || |
228 dimensions.GetArea() > media::limits::kMaxCanvas) { | 228 dimensions.GetArea() > limits::kMaxCanvas) { |
229 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | 229 NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE); |
230 return; | 230 return; |
231 } | 231 } |
232 if (!Send(new AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers( | 232 if (!Send(new AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers( |
233 host_route_id_, requested_num_of_buffers, format, textures_per_buffer, | 233 host_route_id_, requested_num_of_buffers, format, textures_per_buffer, |
234 dimensions, texture_target))) { | 234 dimensions, texture_target))) { |
235 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers) " | 235 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers) " |
236 << "failed"; | 236 << "failed"; |
237 } | 237 } |
238 texture_dimensions_ = dimensions; | 238 texture_dimensions_ = dimensions; |
239 textures_per_buffer_ = textures_per_buffer; | 239 textures_per_buffer_ = textures_per_buffer; |
240 texture_target_ = texture_target; | 240 texture_target_ = texture_target; |
241 } | 241 } |
242 | 242 |
243 void GpuVideoDecodeAccelerator::DismissPictureBuffer( | 243 void GpuVideoDecodeAccelerator::DismissPictureBuffer( |
244 int32_t picture_buffer_id) { | 244 int32_t picture_buffer_id) { |
245 // Notify client that picture buffer is now unused. | 245 // Notify client that picture buffer is now unused. |
246 if (!Send(new AcceleratedVideoDecoderHostMsg_DismissPictureBuffer( | 246 if (!Send(new AcceleratedVideoDecoderHostMsg_DismissPictureBuffer( |
247 host_route_id_, picture_buffer_id))) { | 247 host_route_id_, picture_buffer_id))) { |
248 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer) " | 248 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer) " |
249 << "failed"; | 249 << "failed"; |
250 } | 250 } |
251 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); | 251 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); |
252 uncleared_textures_.erase(picture_buffer_id); | 252 uncleared_textures_.erase(picture_buffer_id); |
253 } | 253 } |
254 | 254 |
255 void GpuVideoDecodeAccelerator::PictureReady(const media::Picture& picture) { | 255 void GpuVideoDecodeAccelerator::PictureReady(const Picture& picture) { |
256 // VDA may call PictureReady on IO thread. SetTextureCleared should run on | 256 // VDA may call PictureReady on IO thread. SetTextureCleared should run on |
257 // the child thread. VDA is responsible to call PictureReady on the child | 257 // the child thread. VDA is responsible to call PictureReady on the child |
258 // thread when a picture buffer is delivered the first time. | 258 // thread when a picture buffer is delivered the first time. |
259 if (child_task_runner_->BelongsToCurrentThread()) { | 259 if (child_task_runner_->BelongsToCurrentThread()) { |
260 SetTextureCleared(picture); | 260 SetTextureCleared(picture); |
261 } else { | 261 } else { |
262 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 262 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
263 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); | 263 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); |
264 DCHECK_EQ(0u, uncleared_textures_.count(picture.picture_buffer_id())); | 264 DCHECK_EQ(0u, uncleared_textures_.count(picture.picture_buffer_id())); |
265 } | 265 } |
(...skipping 20 matching lines...) Expand all Loading... |
286 if (!Send(new AcceleratedVideoDecoderHostMsg_FlushDone(host_route_id_))) | 286 if (!Send(new AcceleratedVideoDecoderHostMsg_FlushDone(host_route_id_))) |
287 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_FlushDone) failed"; | 287 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_FlushDone) failed"; |
288 } | 288 } |
289 | 289 |
290 void GpuVideoDecodeAccelerator::NotifyResetDone() { | 290 void GpuVideoDecodeAccelerator::NotifyResetDone() { |
291 if (!Send(new AcceleratedVideoDecoderHostMsg_ResetDone(host_route_id_))) | 291 if (!Send(new AcceleratedVideoDecoderHostMsg_ResetDone(host_route_id_))) |
292 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ResetDone) failed"; | 292 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ResetDone) failed"; |
293 } | 293 } |
294 | 294 |
295 void GpuVideoDecodeAccelerator::NotifyError( | 295 void GpuVideoDecodeAccelerator::NotifyError( |
296 media::VideoDecodeAccelerator::Error error) { | 296 VideoDecodeAccelerator::Error error) { |
297 if (!Send(new AcceleratedVideoDecoderHostMsg_ErrorNotification(host_route_id_, | 297 if (!Send(new AcceleratedVideoDecoderHostMsg_ErrorNotification(host_route_id_, |
298 error))) { | 298 error))) { |
299 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ErrorNotification) " | 299 DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ErrorNotification) " |
300 << "failed"; | 300 << "failed"; |
301 } | 301 } |
302 } | 302 } |
303 | 303 |
304 void GpuVideoDecodeAccelerator::OnWillDestroyStub() { | 304 void GpuVideoDecodeAccelerator::OnWillDestroyStub() { |
305 // The stub is going away, so we have to stop and destroy VDA here, before | 305 // The stub is going away, so we have to stop and destroy VDA here, before |
306 // returning, because the VDA may need the GL context to run and/or do its | 306 // returning, because the VDA may need the GL context to run and/or do its |
(...skipping 16 matching lines...) Expand all Loading... |
323 } | 323 } |
324 | 324 |
325 bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) { | 325 bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) { |
326 if (filter_ && io_task_runner_->BelongsToCurrentThread()) | 326 if (filter_ && io_task_runner_->BelongsToCurrentThread()) |
327 return filter_->SendOnIOThread(message); | 327 return filter_->SendOnIOThread(message); |
328 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 328 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
329 return stub_->channel()->Send(message); | 329 return stub_->channel()->Send(message); |
330 } | 330 } |
331 | 331 |
332 bool GpuVideoDecodeAccelerator::Initialize( | 332 bool GpuVideoDecodeAccelerator::Initialize( |
333 const media::VideoDecodeAccelerator::Config& config) { | 333 const VideoDecodeAccelerator::Config& config) { |
334 DCHECK(!video_decode_accelerator_); | 334 DCHECK(!video_decode_accelerator_); |
335 | 335 |
336 if (!stub_->channel()->AddRoute(host_route_id_, stub_->stream_id(), this)) { | 336 if (!stub_->channel()->AddRoute(host_route_id_, stub_->stream_id(), this)) { |
337 DLOG(ERROR) << "Initialize(): failed to add route"; | 337 DLOG(ERROR) << "Initialize(): failed to add route"; |
338 return false; | 338 return false; |
339 } | 339 } |
340 | 340 |
341 #if !defined(OS_WIN) | 341 #if !defined(OS_WIN) |
342 // Ensure we will be able to get a GL context at all before initializing | 342 // Ensure we will be able to get a GL context at all before initializing |
343 // non-Windows VDAs. | 343 // non-Windows VDAs. |
(...skipping 28 matching lines...) Expand all Loading... |
372 filter_ = new MessageFilter(this, host_route_id_); | 372 filter_ = new MessageFilter(this, host_route_id_); |
373 stub_->channel()->AddFilter(filter_.get()); | 373 stub_->channel()->AddFilter(filter_.get()); |
374 } | 374 } |
375 | 375 |
376 return true; | 376 return true; |
377 } | 377 } |
378 | 378 |
379 // Runs on IO thread if VDA::TryToSetupDecodeOnSeparateThread() succeeded, | 379 // Runs on IO thread if VDA::TryToSetupDecodeOnSeparateThread() succeeded, |
380 // otherwise on the main thread. | 380 // otherwise on the main thread. |
381 void GpuVideoDecodeAccelerator::OnDecode( | 381 void GpuVideoDecodeAccelerator::OnDecode( |
382 const media::BitstreamBuffer& bitstream_buffer) { | 382 const BitstreamBuffer& bitstream_buffer) { |
383 DCHECK(video_decode_accelerator_); | 383 DCHECK(video_decode_accelerator_); |
384 video_decode_accelerator_->Decode(bitstream_buffer); | 384 video_decode_accelerator_->Decode(bitstream_buffer); |
385 } | 385 } |
386 | 386 |
387 void GpuVideoDecodeAccelerator::OnAssignPictureBuffers( | 387 void GpuVideoDecodeAccelerator::OnAssignPictureBuffers( |
388 const std::vector<int32_t>& buffer_ids, | 388 const std::vector<int32_t>& buffer_ids, |
389 const std::vector<media::PictureBuffer::TextureIds>& texture_ids) { | 389 const std::vector<PictureBuffer::TextureIds>& texture_ids) { |
390 if (buffer_ids.size() != texture_ids.size()) { | 390 if (buffer_ids.size() != texture_ids.size()) { |
391 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 391 NotifyError(VideoDecodeAccelerator::INVALID_ARGUMENT); |
392 return; | 392 return; |
393 } | 393 } |
394 | 394 |
395 gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder(); | 395 gpu::gles2::GLES2Decoder* command_decoder = stub_->decoder(); |
396 gpu::gles2::TextureManager* texture_manager = | 396 gpu::gles2::TextureManager* texture_manager = |
397 command_decoder->GetContextGroup()->texture_manager(); | 397 command_decoder->GetContextGroup()->texture_manager(); |
398 | 398 |
399 std::vector<media::PictureBuffer> buffers; | 399 std::vector<PictureBuffer> buffers; |
400 std::vector<std::vector<scoped_refptr<gpu::gles2::TextureRef>>> textures; | 400 std::vector<std::vector<scoped_refptr<gpu::gles2::TextureRef>>> textures; |
401 for (uint32_t i = 0; i < buffer_ids.size(); ++i) { | 401 for (uint32_t i = 0; i < buffer_ids.size(); ++i) { |
402 if (buffer_ids[i] < 0) { | 402 if (buffer_ids[i] < 0) { |
403 DLOG(ERROR) << "Buffer id " << buffer_ids[i] << " out of range"; | 403 DLOG(ERROR) << "Buffer id " << buffer_ids[i] << " out of range"; |
404 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 404 NotifyError(VideoDecodeAccelerator::INVALID_ARGUMENT); |
405 return; | 405 return; |
406 } | 406 } |
407 std::vector<scoped_refptr<gpu::gles2::TextureRef>> current_textures; | 407 std::vector<scoped_refptr<gpu::gles2::TextureRef>> current_textures; |
408 media::PictureBuffer::TextureIds buffer_texture_ids = texture_ids[i]; | 408 PictureBuffer::TextureIds buffer_texture_ids = texture_ids[i]; |
409 media::PictureBuffer::TextureIds service_ids; | 409 PictureBuffer::TextureIds service_ids; |
410 if (buffer_texture_ids.size() != textures_per_buffer_) { | 410 if (buffer_texture_ids.size() != textures_per_buffer_) { |
411 DLOG(ERROR) << "Requested " << textures_per_buffer_ | 411 DLOG(ERROR) << "Requested " << textures_per_buffer_ |
412 << " textures per picture buffer, got " | 412 << " textures per picture buffer, got " |
413 << buffer_texture_ids.size(); | 413 << buffer_texture_ids.size(); |
414 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 414 NotifyError(VideoDecodeAccelerator::INVALID_ARGUMENT); |
415 return; | 415 return; |
416 } | 416 } |
417 for (size_t j = 0; j < textures_per_buffer_; j++) { | 417 for (size_t j = 0; j < textures_per_buffer_; j++) { |
418 gpu::gles2::TextureRef* texture_ref = | 418 gpu::gles2::TextureRef* texture_ref = |
419 texture_manager->GetTexture(buffer_texture_ids[j]); | 419 texture_manager->GetTexture(buffer_texture_ids[j]); |
420 if (!texture_ref) { | 420 if (!texture_ref) { |
421 DLOG(ERROR) << "Failed to find texture id " << buffer_texture_ids[j]; | 421 DLOG(ERROR) << "Failed to find texture id " << buffer_texture_ids[j]; |
422 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 422 NotifyError(VideoDecodeAccelerator::INVALID_ARGUMENT); |
423 return; | 423 return; |
424 } | 424 } |
425 gpu::gles2::Texture* info = texture_ref->texture(); | 425 gpu::gles2::Texture* info = texture_ref->texture(); |
426 if (info->target() != texture_target_) { | 426 if (info->target() != texture_target_) { |
427 DLOG(ERROR) << "Texture target mismatch for texture id " | 427 DLOG(ERROR) << "Texture target mismatch for texture id " |
428 << buffer_texture_ids[j]; | 428 << buffer_texture_ids[j]; |
429 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 429 NotifyError(VideoDecodeAccelerator::INVALID_ARGUMENT); |
430 return; | 430 return; |
431 } | 431 } |
432 if (texture_target_ == GL_TEXTURE_EXTERNAL_OES || | 432 if (texture_target_ == GL_TEXTURE_EXTERNAL_OES || |
433 texture_target_ == GL_TEXTURE_RECTANGLE_ARB) { | 433 texture_target_ == GL_TEXTURE_RECTANGLE_ARB) { |
434 // These textures have their dimensions defined by the underlying | 434 // These textures have their dimensions defined by the underlying |
435 // storage. | 435 // storage. |
436 // Use |texture_dimensions_| for this size. | 436 // Use |texture_dimensions_| for this size. |
437 texture_manager->SetLevelInfo(texture_ref, texture_target_, 0, GL_RGBA, | 437 texture_manager->SetLevelInfo(texture_ref, texture_target_, 0, GL_RGBA, |
438 texture_dimensions_.width(), | 438 texture_dimensions_.width(), |
439 texture_dimensions_.height(), 1, 0, | 439 texture_dimensions_.height(), 1, 0, |
440 GL_RGBA, 0, gfx::Rect()); | 440 GL_RGBA, 0, gfx::Rect()); |
441 } else { | 441 } else { |
442 // For other targets, texture dimensions should already be defined. | 442 // For other targets, texture dimensions should already be defined. |
443 GLsizei width = 0, height = 0; | 443 GLsizei width = 0, height = 0; |
444 info->GetLevelSize(texture_target_, 0, &width, &height, nullptr); | 444 info->GetLevelSize(texture_target_, 0, &width, &height, nullptr); |
445 if (width != texture_dimensions_.width() || | 445 if (width != texture_dimensions_.width() || |
446 height != texture_dimensions_.height()) { | 446 height != texture_dimensions_.height()) { |
447 DLOG(ERROR) << "Size mismatch for texture id " | 447 DLOG(ERROR) << "Size mismatch for texture id " |
448 << buffer_texture_ids[j]; | 448 << buffer_texture_ids[j]; |
449 NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT); | 449 NotifyError(VideoDecodeAccelerator::INVALID_ARGUMENT); |
450 return; | 450 return; |
451 } | 451 } |
452 | 452 |
453 // TODO(dshwang): after moving to D3D11, remove this. crbug.com/438691 | 453 // TODO(dshwang): after moving to D3D11, remove this. crbug.com/438691 |
454 GLenum format = | 454 GLenum format = |
455 video_decode_accelerator_.get()->GetSurfaceInternalFormat(); | 455 video_decode_accelerator_.get()->GetSurfaceInternalFormat(); |
456 if (format != GL_RGBA) { | 456 if (format != GL_RGBA) { |
457 texture_manager->SetLevelInfo(texture_ref, texture_target_, 0, format, | 457 texture_manager->SetLevelInfo(texture_ref, texture_target_, 0, format, |
458 width, height, 1, 0, format, 0, | 458 width, height, 1, 0, format, 0, |
459 gfx::Rect()); | 459 gfx::Rect()); |
460 } | 460 } |
461 } | 461 } |
462 service_ids.push_back(texture_ref->service_id()); | 462 service_ids.push_back(texture_ref->service_id()); |
463 current_textures.push_back(texture_ref); | 463 current_textures.push_back(texture_ref); |
464 } | 464 } |
465 textures.push_back(current_textures); | 465 textures.push_back(current_textures); |
466 buffers.push_back(media::PictureBuffer(buffer_ids[i], texture_dimensions_, | 466 buffers.push_back(PictureBuffer(buffer_ids[i], texture_dimensions_, |
467 service_ids, buffer_texture_ids)); | 467 service_ids, buffer_texture_ids)); |
468 } | 468 } |
469 { | 469 { |
470 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); | 470 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); |
471 for (uint32_t i = 0; i < buffer_ids.size(); ++i) | 471 for (uint32_t i = 0; i < buffer_ids.size(); ++i) |
472 uncleared_textures_[buffer_ids[i]] = textures[i]; | 472 uncleared_textures_[buffer_ids[i]] = textures[i]; |
473 } | 473 } |
474 video_decode_accelerator_->AssignPictureBuffers(buffers); | 474 video_decode_accelerator_->AssignPictureBuffers(buffers); |
475 } | 475 } |
476 | 476 |
477 void GpuVideoDecodeAccelerator::OnReusePictureBuffer( | 477 void GpuVideoDecodeAccelerator::OnReusePictureBuffer( |
(...skipping 16 matching lines...) Expand all Loading... |
494 DCHECK(video_decode_accelerator_); | 494 DCHECK(video_decode_accelerator_); |
495 OnWillDestroyStub(); | 495 OnWillDestroyStub(); |
496 } | 496 } |
497 | 497 |
498 void GpuVideoDecodeAccelerator::OnFilterRemoved() { | 498 void GpuVideoDecodeAccelerator::OnFilterRemoved() { |
499 // We're destroying; cancel all callbacks. | 499 // We're destroying; cancel all callbacks. |
500 weak_factory_for_io_.InvalidateWeakPtrs(); | 500 weak_factory_for_io_.InvalidateWeakPtrs(); |
501 filter_removed_.Signal(); | 501 filter_removed_.Signal(); |
502 } | 502 } |
503 | 503 |
504 void GpuVideoDecodeAccelerator::SetTextureCleared( | 504 void GpuVideoDecodeAccelerator::SetTextureCleared(const Picture& picture) { |
505 const media::Picture& picture) { | |
506 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 505 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
507 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); | 506 DebugAutoLock auto_lock(debug_uncleared_textures_lock_); |
508 auto it = uncleared_textures_.find(picture.picture_buffer_id()); | 507 auto it = uncleared_textures_.find(picture.picture_buffer_id()); |
509 if (it == uncleared_textures_.end()) | 508 if (it == uncleared_textures_.end()) |
510 return; // the texture has been cleared | 509 return; // the texture has been cleared |
511 | 510 |
512 for (auto texture_ref : it->second) { | 511 for (auto texture_ref : it->second) { |
513 GLenum target = texture_ref->texture()->target(); | 512 GLenum target = texture_ref->texture()->target(); |
514 gpu::gles2::TextureManager* texture_manager = | 513 gpu::gles2::TextureManager* texture_manager = |
515 stub_->decoder()->GetContextGroup()->texture_manager(); | 514 stub_->decoder()->GetContextGroup()->texture_manager(); |
516 DCHECK(!texture_ref->texture()->IsLevelCleared(target, 0)); | 515 DCHECK(!texture_ref->texture()->IsLevelCleared(target, 0)); |
517 texture_manager->SetLevelCleared(texture_ref.get(), target, 0, true); | 516 texture_manager->SetLevelCleared(texture_ref.get(), target, 0, true); |
518 } | 517 } |
519 uncleared_textures_.erase(it); | 518 uncleared_textures_.erase(it); |
520 } | 519 } |
521 | 520 |
522 } // namespace media | 521 } // namespace media |
OLD | NEW |