| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 <errno.h> | 5 #include <errno.h> |
| 6 #include <fcntl.h> | 6 #include <fcntl.h> |
| 7 #include <linux/videodev2.h> | 7 #include <linux/videodev2.h> |
| 8 #include <poll.h> | 8 #include <poll.h> |
| 9 #include <string.h> | 9 #include <string.h> |
| 10 #include <sys/eventfd.h> | 10 #include <sys/eventfd.h> |
| 11 #include <sys/ioctl.h> | 11 #include <sys/ioctl.h> |
| 12 #include <sys/mman.h> | 12 #include <sys/mman.h> |
| 13 | 13 |
| 14 #include "base/bind.h" | 14 #include "base/bind.h" |
| 15 #include "base/bind_helpers.h" | 15 #include "base/bind_helpers.h" |
| 16 #include "base/callback.h" | 16 #include "base/callback.h" |
| 17 #include "base/callback_helpers.h" | 17 #include "base/callback_helpers.h" |
| 18 #include "base/command_line.h" | 18 #include "base/command_line.h" |
| 19 #include "base/macros.h" | 19 #include "base/macros.h" |
| 20 #include "base/memory/ptr_util.h" |
| 20 #include "base/numerics/safe_conversions.h" | 21 #include "base/numerics/safe_conversions.h" |
| 21 #include "base/strings/stringprintf.h" | 22 #include "base/strings/stringprintf.h" |
| 22 #include "content/common/gpu/media/shared_memory_region.h" | 23 #include "content/common/gpu/media/shared_memory_region.h" |
| 23 #include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h" | 24 #include "content/common/gpu/media/v4l2_slice_video_decode_accelerator.h" |
| 24 #include "media/base/bind_to_current_loop.h" | 25 #include "media/base/bind_to_current_loop.h" |
| 25 #include "media/base/media_switches.h" | 26 #include "media/base/media_switches.h" |
| 26 #include "ui/gl/gl_context.h" | 27 #include "ui/gl/gl_context.h" |
| 27 #include "ui/gl/scoped_binders.h" | 28 #include "ui/gl/scoped_binders.h" |
| 28 | 29 |
| 29 #define LOGF(level) LOG(level) << __FUNCTION__ << "(): " | 30 #define LOGF(level) LOG(level) << __FUNCTION__ << "(): " |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 address(nullptr), | 156 address(nullptr), |
| 156 length(0), | 157 length(0), |
| 157 bytes_used(0), | 158 bytes_used(0), |
| 158 at_device(false) { | 159 at_device(false) { |
| 159 } | 160 } |
| 160 | 161 |
| 161 V4L2SliceVideoDecodeAccelerator::OutputRecord::OutputRecord() | 162 V4L2SliceVideoDecodeAccelerator::OutputRecord::OutputRecord() |
| 162 : at_device(false), | 163 : at_device(false), |
| 163 at_client(false), | 164 at_client(false), |
| 164 picture_id(-1), | 165 picture_id(-1), |
| 166 texture_id(0), |
| 165 egl_image(EGL_NO_IMAGE_KHR), | 167 egl_image(EGL_NO_IMAGE_KHR), |
| 166 egl_sync(EGL_NO_SYNC_KHR), | 168 egl_sync(EGL_NO_SYNC_KHR), |
| 167 cleared(false) { | 169 cleared(false) {} |
| 168 } | |
| 169 | 170 |
| 170 struct V4L2SliceVideoDecodeAccelerator::BitstreamBufferRef { | 171 struct V4L2SliceVideoDecodeAccelerator::BitstreamBufferRef { |
| 171 BitstreamBufferRef( | 172 BitstreamBufferRef( |
| 172 base::WeakPtr<VideoDecodeAccelerator::Client>& client, | 173 base::WeakPtr<VideoDecodeAccelerator::Client>& client, |
| 173 const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, | 174 const scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, |
| 174 SharedMemoryRegion* shm, | 175 SharedMemoryRegion* shm, |
| 175 int32_t input_id); | 176 int32_t input_id); |
| 176 ~BitstreamBufferRef(); | 177 ~BitstreamBufferRef(); |
| 177 const base::WeakPtr<VideoDecodeAccelerator::Client> client; | 178 const base::WeakPtr<VideoDecodeAccelerator::Client> client; |
| 178 const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner; | 179 const scoped_refptr<base::SingleThreadTaskRunner> client_task_runner; |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 device_(device), | 389 device_(device), |
| 389 decoder_thread_("V4L2SliceVideoDecodeAcceleratorThread"), | 390 decoder_thread_("V4L2SliceVideoDecodeAcceleratorThread"), |
| 390 device_poll_thread_("V4L2SliceVideoDecodeAcceleratorDevicePollThread"), | 391 device_poll_thread_("V4L2SliceVideoDecodeAcceleratorDevicePollThread"), |
| 391 input_streamon_(false), | 392 input_streamon_(false), |
| 392 input_buffer_queued_count_(0), | 393 input_buffer_queued_count_(0), |
| 393 output_streamon_(false), | 394 output_streamon_(false), |
| 394 output_buffer_queued_count_(0), | 395 output_buffer_queued_count_(0), |
| 395 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), | 396 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), |
| 396 output_format_fourcc_(0), | 397 output_format_fourcc_(0), |
| 397 state_(kUninitialized), | 398 state_(kUninitialized), |
| 399 output_mode_(Config::OutputMode::ALLOCATE), |
| 398 decoder_flushing_(false), | 400 decoder_flushing_(false), |
| 399 decoder_resetting_(false), | 401 decoder_resetting_(false), |
| 400 surface_set_change_pending_(false), | 402 surface_set_change_pending_(false), |
| 401 picture_clearing_count_(0), | 403 picture_clearing_count_(0), |
| 402 pictures_assigned_(false, false), | |
| 403 egl_display_(egl_display), | 404 egl_display_(egl_display), |
| 404 get_gl_context_cb_(get_gl_context_cb), | 405 get_gl_context_cb_(get_gl_context_cb), |
| 405 make_context_current_cb_(make_context_current_cb), | 406 make_context_current_cb_(make_context_current_cb), |
| 406 weak_this_factory_(this) { | 407 weak_this_factory_(this) { |
| 407 weak_this_ = weak_this_factory_.GetWeakPtr(); | 408 weak_this_ = weak_this_factory_.GetWeakPtr(); |
| 408 } | 409 } |
| 409 | 410 |
| 410 V4L2SliceVideoDecodeAccelerator::~V4L2SliceVideoDecodeAccelerator() { | 411 V4L2SliceVideoDecodeAccelerator::~V4L2SliceVideoDecodeAccelerator() { |
| 411 DVLOGF(2); | 412 DVLOGF(2); |
| 412 | 413 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 431 client_ptr_factory_.reset(); | 432 client_ptr_factory_.reset(); |
| 432 } | 433 } |
| 433 } | 434 } |
| 434 | 435 |
| 435 bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config, | 436 bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config, |
| 436 Client* client) { | 437 Client* client) { |
| 437 DVLOGF(3) << "profile: " << config.profile; | 438 DVLOGF(3) << "profile: " << config.profile; |
| 438 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 439 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 439 DCHECK_EQ(state_, kUninitialized); | 440 DCHECK_EQ(state_, kUninitialized); |
| 440 | 441 |
| 441 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { | 442 if (!device_->SupportsDecodeProfileForV4L2PixelFormats( |
| 442 NOTREACHED() << "GL callbacks are required for this VDA"; | 443 config.profile, arraysize(supported_input_fourccs_), |
| 444 supported_input_fourccs_)) { |
| 445 DVLOGF(1) << "unsupported profile " << config.profile; |
| 443 return false; | 446 return false; |
| 444 } | 447 } |
| 445 | 448 |
| 446 if (config.is_encrypted) { | 449 if (config.is_encrypted) { |
| 447 NOTREACHED() << "Encrypted streams are not supported for this VDA"; | 450 NOTREACHED() << "Encrypted streams are not supported for this VDA"; |
| 448 return false; | 451 return false; |
| 449 } | 452 } |
| 450 | 453 |
| 451 if (!device_->SupportsDecodeProfileForV4L2PixelFormats( | 454 if (config.output_mode != Config::OutputMode::ALLOCATE && |
| 452 config.profile, arraysize(supported_input_fourccs_), | 455 config.output_mode != Config::OutputMode::IMPORT) { |
| 453 supported_input_fourccs_)) { | 456 NOTREACHED() << "Only ALLOCATE and IMPORT OutputModes are supported"; |
| 454 DVLOGF(1) << "unsupported profile " << config.profile; | |
| 455 return false; | 457 return false; |
| 456 } | 458 } |
| 457 | 459 |
| 458 client_ptr_factory_.reset( | 460 client_ptr_factory_.reset( |
| 459 new base::WeakPtrFactory<VideoDecodeAccelerator::Client>(client)); | 461 new base::WeakPtrFactory<VideoDecodeAccelerator::Client>(client)); |
| 460 client_ = client_ptr_factory_->GetWeakPtr(); | 462 client_ = client_ptr_factory_->GetWeakPtr(); |
| 461 // If we haven't been set up to decode on separate thread via | 463 // If we haven't been set up to decode on separate thread via |
| 462 // TryToSetupDecodeOnSeparateThread(), use the main thread/client for | 464 // TryToSetupDecodeOnSeparateThread(), use the main thread/client for |
| 463 // decode tasks. | 465 // decode tasks. |
| 464 if (!decode_task_runner_) { | 466 if (!decode_task_runner_) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 485 // TODO(posciak): This needs to be queried once supported. | 487 // TODO(posciak): This needs to be queried once supported. |
| 486 input_planes_count_ = 1; | 488 input_planes_count_ = 1; |
| 487 output_planes_count_ = 1; | 489 output_planes_count_ = 1; |
| 488 | 490 |
| 489 if (egl_display_ == EGL_NO_DISPLAY) { | 491 if (egl_display_ == EGL_NO_DISPLAY) { |
| 490 LOG(ERROR) << "Initialize(): could not get EGLDisplay"; | 492 LOG(ERROR) << "Initialize(): could not get EGLDisplay"; |
| 491 return false; | 493 return false; |
| 492 } | 494 } |
| 493 | 495 |
| 494 // We need the context to be initialized to query extensions. | 496 // We need the context to be initialized to query extensions. |
| 495 if (!make_context_current_cb_.Run()) { | 497 if (!make_context_current_cb_.is_null()) { |
| 496 LOG(ERROR) << "Initialize(): could not make context current"; | 498 if (!make_context_current_cb_.Run()) { |
| 497 return false; | 499 LOG(ERROR) << "Initialize(): could not make context current"; |
| 498 } | 500 return false; |
| 501 } |
| 499 | 502 |
| 500 if (!gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) { | 503 if (!gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync) { |
| 501 LOG(ERROR) << "Initialize(): context does not have EGL_KHR_fence_sync"; | 504 LOG(ERROR) << "Initialize(): context does not have EGL_KHR_fence_sync"; |
| 502 return false; | 505 return false; |
| 506 } |
| 507 } else { |
| 508 DVLOG(1) << "No GL callbacks provided, initializing without GL support"; |
| 503 } | 509 } |
| 504 | 510 |
| 505 // Capabilities check. | 511 // Capabilities check. |
| 506 struct v4l2_capability caps; | 512 struct v4l2_capability caps; |
| 507 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; | 513 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; |
| 508 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); | 514 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); |
| 509 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { | 515 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { |
| 510 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP" | 516 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP" |
| 511 ", caps check failed: 0x" << std::hex << caps.capabilities; | 517 ", caps check failed: 0x" << std::hex << caps.capabilities; |
| 512 return false; | 518 return false; |
| 513 } | 519 } |
| 514 | 520 |
| 515 if (!SetupFormats()) | 521 if (!SetupFormats()) |
| 516 return false; | 522 return false; |
| 517 | 523 |
| 518 if (!decoder_thread_.Start()) { | 524 if (!decoder_thread_.Start()) { |
| 519 DLOG(ERROR) << "Initialize(): device thread failed to start"; | 525 DLOG(ERROR) << "Initialize(): device thread failed to start"; |
| 520 return false; | 526 return false; |
| 521 } | 527 } |
| 522 decoder_thread_task_runner_ = decoder_thread_.task_runner(); | 528 decoder_thread_task_runner_ = decoder_thread_.task_runner(); |
| 523 | 529 |
| 524 state_ = kInitialized; | 530 state_ = kInitialized; |
| 531 output_mode_ = config.output_mode; |
| 525 | 532 |
| 526 // InitializeTask will NOTIFY_ERROR on failure. | 533 // InitializeTask will NOTIFY_ERROR on failure. |
| 527 decoder_thread_task_runner_->PostTask( | 534 decoder_thread_task_runner_->PostTask( |
| 528 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::InitializeTask, | 535 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::InitializeTask, |
| 529 base::Unretained(this))); | 536 base::Unretained(this))); |
| 530 | 537 |
| 531 DVLOGF(1) << "V4L2SliceVideoDecodeAccelerator initialized"; | 538 DVLOGF(1) << "V4L2SliceVideoDecodeAccelerator initialized"; |
| 532 return true; | 539 return true; |
| 533 } | 540 } |
| 534 | 541 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 547 | 554 |
| 548 void V4L2SliceVideoDecodeAccelerator::Destroy() { | 555 void V4L2SliceVideoDecodeAccelerator::Destroy() { |
| 549 DVLOGF(3); | 556 DVLOGF(3); |
| 550 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 557 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 551 | 558 |
| 552 if (decoder_thread_.IsRunning()) { | 559 if (decoder_thread_.IsRunning()) { |
| 553 decoder_thread_task_runner_->PostTask( | 560 decoder_thread_task_runner_->PostTask( |
| 554 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DestroyTask, | 561 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DestroyTask, |
| 555 base::Unretained(this))); | 562 base::Unretained(this))); |
| 556 | 563 |
| 557 // Wake up decoder thread in case we are waiting in CreateOutputBuffers | |
| 558 // for client to provide pictures. Since this is Destroy, we won't be | |
| 559 // getting them anymore (AssignPictureBuffers won't be called). | |
| 560 pictures_assigned_.Signal(); | |
| 561 | |
| 562 // Wait for tasks to finish/early-exit. | 564 // Wait for tasks to finish/early-exit. |
| 563 decoder_thread_.Stop(); | 565 decoder_thread_.Stop(); |
| 564 } | 566 } |
| 565 | 567 |
| 566 delete this; | 568 delete this; |
| 567 DVLOGF(3) << "Destroyed"; | 569 DVLOGF(3) << "Destroyed"; |
| 568 } | 570 } |
| 569 | 571 |
| 570 void V4L2SliceVideoDecodeAccelerator::DestroyTask() { | 572 void V4L2SliceVideoDecodeAccelerator::DestroyTask() { |
| 571 DVLOGF(3); | 573 DVLOGF(3); |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 753 DVLOGF(3) << "buffer_count=" << num_pictures | 755 DVLOGF(3) << "buffer_count=" << num_pictures |
| 754 << ", visible size=" << visible_size_.ToString() | 756 << ", visible size=" << visible_size_.ToString() |
| 755 << ", coded size=" << coded_size_.ToString(); | 757 << ", coded size=" << coded_size_.ToString(); |
| 756 | 758 |
| 757 child_task_runner_->PostTask( | 759 child_task_runner_->PostTask( |
| 758 FROM_HERE, | 760 FROM_HERE, |
| 759 base::Bind(&VideoDecodeAccelerator::Client::ProvidePictureBuffers, | 761 base::Bind(&VideoDecodeAccelerator::Client::ProvidePictureBuffers, |
| 760 client_, num_pictures, 1, coded_size_, | 762 client_, num_pictures, 1, coded_size_, |
| 761 device_->GetTextureTarget())); | 763 device_->GetTextureTarget())); |
| 762 | 764 |
| 763 // Wait for the client to call AssignPictureBuffers() on the Child thread. | 765 // Go into kAwaitingPictureBuffers to prevent us from doing any more decoding |
| 764 // We do this, because if we continue decoding without finishing buffer | 766 // or event handling while we are waiting for AssignPictureBuffers(). Not |
| 765 // allocation, we may end up Resetting before AssignPictureBuffers arrives, | 767 // having Pictures available would not have prevented us from making decoding |
| 766 // resulting in unnecessary complications and subtle bugs. | 768 // progress entirely e.g. in the case of H.264 where we could further decode |
| 767 pictures_assigned_.Wait(); | 769 // non-slice NALUs and could even get another resolution change before we were |
| 768 | 770 // done with this one. After we get the buffers, we'll go back into kIdle and |
| 771 // kick off further event processing, and eventually go back into kDecoding |
| 772 // once no more events are pending (if any). |
| 773 state_ = kAwaitingPictureBuffers; |
| 769 return true; | 774 return true; |
| 770 } | 775 } |
| 771 | 776 |
| 772 void V4L2SliceVideoDecodeAccelerator::DestroyInputBuffers() { | 777 void V4L2SliceVideoDecodeAccelerator::DestroyInputBuffers() { |
| 773 DVLOGF(3); | 778 DVLOGF(3); |
| 774 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread() || | 779 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread() || |
| 775 !decoder_thread_.IsRunning()); | 780 !decoder_thread_.IsRunning()); |
| 776 DCHECK(!input_streamon_); | 781 DCHECK(!input_streamon_); |
| 777 | 782 |
| 778 for (auto& input_record : input_buffer_map_) { | 783 for (auto& input_record : input_buffer_map_) { |
| 779 if (input_record.address != nullptr) | 784 if (input_record.address != nullptr) |
| 780 device_->Munmap(input_record.address, input_record.length); | 785 device_->Munmap(input_record.address, input_record.length); |
| 781 } | 786 } |
| 782 | 787 |
| 783 struct v4l2_requestbuffers reqbufs; | 788 struct v4l2_requestbuffers reqbufs; |
| 784 memset(&reqbufs, 0, sizeof(reqbufs)); | 789 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 785 reqbufs.count = 0; | 790 reqbufs.count = 0; |
| 786 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 791 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 787 reqbufs.memory = V4L2_MEMORY_MMAP; | 792 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 788 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 793 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
| 789 | 794 |
| 790 input_buffer_map_.clear(); | 795 input_buffer_map_.clear(); |
| 791 free_input_buffers_.clear(); | 796 free_input_buffers_.clear(); |
| 792 } | 797 } |
| 793 | 798 |
| 794 void V4L2SliceVideoDecodeAccelerator::DismissPictures( | 799 void V4L2SliceVideoDecodeAccelerator::DismissPictures( |
| 795 std::vector<int32_t> picture_buffer_ids, | 800 const std::vector<int32_t>& picture_buffer_ids, |
| 796 base::WaitableEvent* done) { | 801 base::WaitableEvent* done) { |
| 797 DVLOGF(3); | 802 DVLOGF(3); |
| 798 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 803 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 799 | 804 |
| 800 for (auto picture_buffer_id : picture_buffer_ids) { | 805 for (auto picture_buffer_id : picture_buffer_ids) { |
| 801 DVLOGF(1) << "dismissing PictureBuffer id=" << picture_buffer_id; | 806 DVLOGF(1) << "dismissing PictureBuffer id=" << picture_buffer_id; |
| 802 client_->DismissPictureBuffer(picture_buffer_id); | 807 client_->DismissPictureBuffer(picture_buffer_id); |
| 803 } | 808 } |
| 804 | 809 |
| 805 done->Signal(); | 810 done->Signal(); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 899 DVLOGF(3); | 904 DVLOGF(3); |
| 900 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 905 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 901 | 906 |
| 902 struct v4l2_buffer dqbuf; | 907 struct v4l2_buffer dqbuf; |
| 903 struct v4l2_plane planes[VIDEO_MAX_PLANES]; | 908 struct v4l2_plane planes[VIDEO_MAX_PLANES]; |
| 904 while (input_buffer_queued_count_ > 0) { | 909 while (input_buffer_queued_count_ > 0) { |
| 905 DCHECK(input_streamon_); | 910 DCHECK(input_streamon_); |
| 906 memset(&dqbuf, 0, sizeof(dqbuf)); | 911 memset(&dqbuf, 0, sizeof(dqbuf)); |
| 907 memset(&planes, 0, sizeof(planes)); | 912 memset(&planes, 0, sizeof(planes)); |
| 908 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 913 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 909 dqbuf.memory = V4L2_MEMORY_USERPTR; | 914 dqbuf.memory = V4L2_MEMORY_MMAP; |
| 910 dqbuf.m.planes = planes; | 915 dqbuf.m.planes = planes; |
| 911 dqbuf.length = input_planes_count_; | 916 dqbuf.length = input_planes_count_; |
| 912 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { | 917 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
| 913 if (errno == EAGAIN) { | 918 if (errno == EAGAIN) { |
| 914 // EAGAIN if we're just out of buffers to dequeue. | 919 // EAGAIN if we're just out of buffers to dequeue. |
| 915 break; | 920 break; |
| 916 } | 921 } |
| 917 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; | 922 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; |
| 918 NOTIFY_ERROR(PLATFORM_FAILURE); | 923 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 919 return; | 924 return; |
| 920 } | 925 } |
| 921 InputRecord& input_record = input_buffer_map_[dqbuf.index]; | 926 InputRecord& input_record = input_buffer_map_[dqbuf.index]; |
| 922 DCHECK(input_record.at_device); | 927 DCHECK(input_record.at_device); |
| 923 input_record.at_device = false; | 928 input_record.at_device = false; |
| 924 ReuseInputBuffer(dqbuf.index); | 929 ReuseInputBuffer(dqbuf.index); |
| 925 input_buffer_queued_count_--; | 930 input_buffer_queued_count_--; |
| 926 DVLOGF(4) << "Dequeued input=" << dqbuf.index | 931 DVLOGF(4) << "Dequeued input=" << dqbuf.index |
| 927 << " count: " << input_buffer_queued_count_; | 932 << " count: " << input_buffer_queued_count_; |
| 928 } | 933 } |
| 929 | 934 |
| 930 while (output_buffer_queued_count_ > 0) { | 935 while (output_buffer_queued_count_ > 0) { |
| 931 DCHECK(output_streamon_); | 936 DCHECK(output_streamon_); |
| 932 memset(&dqbuf, 0, sizeof(dqbuf)); | 937 memset(&dqbuf, 0, sizeof(dqbuf)); |
| 933 memset(&planes, 0, sizeof(planes)); | 938 memset(&planes, 0, sizeof(planes)); |
| 934 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 939 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 935 dqbuf.memory = V4L2_MEMORY_MMAP; | 940 dqbuf.memory = |
| 941 (output_mode_ == Config::OutputMode::ALLOCATE ? V4L2_MEMORY_MMAP |
| 942 : V4L2_MEMORY_DMABUF); |
| 936 dqbuf.m.planes = planes; | 943 dqbuf.m.planes = planes; |
| 937 dqbuf.length = output_planes_count_; | 944 dqbuf.length = output_planes_count_; |
| 938 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { | 945 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
| 939 if (errno == EAGAIN) { | 946 if (errno == EAGAIN) { |
| 940 // EAGAIN if we're just out of buffers to dequeue. | 947 // EAGAIN if we're just out of buffers to dequeue. |
| 941 break; | 948 break; |
| 942 } | 949 } |
| 943 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; | 950 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; |
| 944 NOTIFY_ERROR(PLATFORM_FAILURE); | 951 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 945 return; | 952 return; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 961 it->second->SetDecoded(); | 968 it->second->SetDecoded(); |
| 962 surfaces_at_device_.erase(it); | 969 surfaces_at_device_.erase(it); |
| 963 } | 970 } |
| 964 | 971 |
| 965 // A frame was decoded, see if we can output it. | 972 // A frame was decoded, see if we can output it. |
| 966 TryOutputSurfaces(); | 973 TryOutputSurfaces(); |
| 967 | 974 |
| 968 ProcessPendingEventsIfNeeded(); | 975 ProcessPendingEventsIfNeeded(); |
| 969 } | 976 } |
| 970 | 977 |
| 978 void V4L2SliceVideoDecodeAccelerator::NewEventPending() { |
| 979 // Switch to event processing mode if we are decoding. Otherwise we are either |
| 980 // already in it, or we will potentially switch to it later, after finishing |
| 981 // other tasks. |
| 982 if (state_ == kDecoding) |
| 983 state_ = kIdle; |
| 984 |
| 985 ProcessPendingEventsIfNeeded(); |
| 986 } |
| 987 |
| 988 bool V4L2SliceVideoDecodeAccelerator::FinishEventProcessing() { |
| 989 DCHECK_EQ(state_, kIdle); |
| 990 |
| 991 state_ = kDecoding; |
| 992 ScheduleDecodeBufferTaskIfNeeded(); |
| 993 |
| 994 return true; |
| 995 } |
| 996 |
| 971 void V4L2SliceVideoDecodeAccelerator::ProcessPendingEventsIfNeeded() { | 997 void V4L2SliceVideoDecodeAccelerator::ProcessPendingEventsIfNeeded() { |
| 998 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 999 |
| 972 // Process pending events, if any, in the correct order. | 1000 // Process pending events, if any, in the correct order. |
| 973 // We always first process the surface set change, as it is an internal | 1001 // We always first process the surface set change, as it is an internal |
| 974 // event from the decoder and interleaving it with external requests would | 1002 // event from the decoder and interleaving it with external requests would |
| 975 // put the decoder in an undefined state. | 1003 // put the decoder in an undefined state. |
| 976 FinishSurfaceSetChangeIfNeeded(); | 1004 using ProcessFunc = bool (V4L2SliceVideoDecodeAccelerator::*)(); |
| 1005 const ProcessFunc process_functions[] = { |
| 1006 &V4L2SliceVideoDecodeAccelerator::FinishSurfaceSetChange, |
| 1007 &V4L2SliceVideoDecodeAccelerator::FinishFlush, |
| 1008 &V4L2SliceVideoDecodeAccelerator::FinishReset, |
| 1009 &V4L2SliceVideoDecodeAccelerator::FinishEventProcessing, |
| 1010 }; |
| 977 | 1011 |
| 978 // Process external (client) requests. | 1012 for (const auto& fn : process_functions) { |
| 979 FinishFlushIfNeeded(); | 1013 if (state_ != kIdle) |
| 980 FinishResetIfNeeded(); | 1014 return; |
| 1015 |
| 1016 if (!(this->*fn)()) |
| 1017 return; |
| 1018 } |
| 981 } | 1019 } |
| 982 | 1020 |
| 983 void V4L2SliceVideoDecodeAccelerator::ReuseInputBuffer(int index) { | 1021 void V4L2SliceVideoDecodeAccelerator::ReuseInputBuffer(int index) { |
| 984 DVLOGF(4) << "Reusing input buffer, index=" << index; | 1022 DVLOGF(4) << "Reusing input buffer, index=" << index; |
| 985 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1023 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 986 | 1024 |
| 987 DCHECK_LT(index, static_cast<int>(input_buffer_map_.size())); | 1025 DCHECK_LT(index, static_cast<int>(input_buffer_map_.size())); |
| 988 InputRecord& input_record = input_buffer_map_[index]; | 1026 InputRecord& input_record = input_buffer_map_[index]; |
| 989 | 1027 |
| 990 DCHECK(!input_record.at_device); | 1028 DCHECK(!input_record.at_device); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1043 } | 1081 } |
| 1044 | 1082 |
| 1045 bool V4L2SliceVideoDecodeAccelerator::EnqueueOutputRecord(int index) { | 1083 bool V4L2SliceVideoDecodeAccelerator::EnqueueOutputRecord(int index) { |
| 1046 DVLOGF(3); | 1084 DVLOGF(3); |
| 1047 DCHECK_LT(index, static_cast<int>(output_buffer_map_.size())); | 1085 DCHECK_LT(index, static_cast<int>(output_buffer_map_.size())); |
| 1048 | 1086 |
| 1049 // Enqueue an output (VIDEO_CAPTURE) buffer. | 1087 // Enqueue an output (VIDEO_CAPTURE) buffer. |
| 1050 OutputRecord& output_record = output_buffer_map_[index]; | 1088 OutputRecord& output_record = output_buffer_map_[index]; |
| 1051 DCHECK(!output_record.at_device); | 1089 DCHECK(!output_record.at_device); |
| 1052 DCHECK(!output_record.at_client); | 1090 DCHECK(!output_record.at_client); |
| 1053 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
| 1054 DCHECK_NE(output_record.picture_id, -1); | 1091 DCHECK_NE(output_record.picture_id, -1); |
| 1055 | 1092 |
| 1056 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 1093 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
| 1057 // If we have to wait for completion, wait. Note that | 1094 // If we have to wait for completion, wait. Note that |
| 1058 // free_output_buffers_ is a FIFO queue, so we always wait on the | 1095 // free_output_buffers_ is a FIFO queue, so we always wait on the |
| 1059 // buffer that has been in the queue the longest. | 1096 // buffer that has been in the queue the longest. |
| 1060 if (eglClientWaitSyncKHR(egl_display_, output_record.egl_sync, 0, | 1097 if (eglClientWaitSyncKHR(egl_display_, output_record.egl_sync, 0, |
| 1061 EGL_FOREVER_KHR) == EGL_FALSE) { | 1098 EGL_FOREVER_KHR) == EGL_FALSE) { |
| 1062 // This will cause tearing, but is safe otherwise. | 1099 // This will cause tearing, but is safe otherwise. |
| 1063 DVLOGF(1) << "eglClientWaitSyncKHR failed!"; | 1100 DVLOGF(1) << "eglClientWaitSyncKHR failed!"; |
| 1064 } | 1101 } |
| 1065 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 1102 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
| 1066 LOGF(ERROR) << "eglDestroySyncKHR failed!"; | 1103 LOGF(ERROR) << "eglDestroySyncKHR failed!"; |
| 1067 NOTIFY_ERROR(PLATFORM_FAILURE); | 1104 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1068 return false; | 1105 return false; |
| 1069 } | 1106 } |
| 1070 output_record.egl_sync = EGL_NO_SYNC_KHR; | 1107 output_record.egl_sync = EGL_NO_SYNC_KHR; |
| 1071 } | 1108 } |
| 1072 | 1109 |
| 1073 struct v4l2_buffer qbuf; | 1110 struct v4l2_buffer qbuf; |
| 1074 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; | 1111 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; |
| 1075 memset(&qbuf, 0, sizeof(qbuf)); | 1112 memset(&qbuf, 0, sizeof(qbuf)); |
| 1076 memset(qbuf_planes, 0, sizeof(qbuf_planes)); | 1113 memset(qbuf_planes, 0, sizeof(qbuf_planes)); |
| 1077 qbuf.index = index; | 1114 qbuf.index = index; |
| 1078 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1115 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1079 qbuf.memory = V4L2_MEMORY_MMAP; | 1116 if (output_mode_ == Config::OutputMode::ALLOCATE) { |
| 1117 qbuf.memory = V4L2_MEMORY_MMAP; |
| 1118 } else { |
| 1119 qbuf.memory = V4L2_MEMORY_DMABUF; |
| 1120 DCHECK_EQ(output_planes_count_, output_record.dmabuf_fds.size()); |
| 1121 for (size_t i = 0; i < output_record.dmabuf_fds.size(); ++i) { |
| 1122 DCHECK(output_record.dmabuf_fds[i].is_valid()); |
| 1123 qbuf_planes[i].m.fd = output_record.dmabuf_fds[i].get(); |
| 1124 } |
| 1125 } |
| 1080 qbuf.m.planes = qbuf_planes; | 1126 qbuf.m.planes = qbuf_planes; |
| 1081 qbuf.length = output_planes_count_; | 1127 qbuf.length = output_planes_count_; |
| 1082 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 1128 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
| 1083 output_record.at_device = true; | 1129 output_record.at_device = true; |
| 1084 output_buffer_queued_count_++; | 1130 output_buffer_queued_count_++; |
| 1085 DVLOGF(4) << "Enqueued output=" << qbuf.index | 1131 DVLOGF(4) << "Enqueued output=" << qbuf.index |
| 1086 << " count: " << output_buffer_queued_count_; | 1132 << " count: " << output_buffer_queued_count_; |
| 1087 | 1133 |
| 1088 return true; | 1134 return true; |
| 1089 } | 1135 } |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1295 DVLOGF(1) << "Error decoding stream"; | 1341 DVLOGF(1) << "Error decoding stream"; |
| 1296 NOTIFY_ERROR(PLATFORM_FAILURE); | 1342 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1297 return; | 1343 return; |
| 1298 } | 1344 } |
| 1299 } | 1345 } |
| 1300 } | 1346 } |
| 1301 | 1347 |
| 1302 void V4L2SliceVideoDecodeAccelerator::InitiateSurfaceSetChange() { | 1348 void V4L2SliceVideoDecodeAccelerator::InitiateSurfaceSetChange() { |
| 1303 DVLOGF(2); | 1349 DVLOGF(2); |
| 1304 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1350 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1305 | |
| 1306 DCHECK_EQ(state_, kDecoding); | 1351 DCHECK_EQ(state_, kDecoding); |
| 1307 state_ = kIdle; | |
| 1308 | 1352 |
| 1309 DCHECK(!surface_set_change_pending_); | 1353 DCHECK(!surface_set_change_pending_); |
| 1310 surface_set_change_pending_ = true; | 1354 surface_set_change_pending_ = true; |
| 1311 | 1355 NewEventPending(); |
| 1312 FinishSurfaceSetChangeIfNeeded(); | |
| 1313 } | 1356 } |
| 1314 | 1357 |
| 1315 void V4L2SliceVideoDecodeAccelerator::FinishSurfaceSetChangeIfNeeded() { | 1358 bool V4L2SliceVideoDecodeAccelerator::FinishSurfaceSetChange() { |
| 1316 DVLOGF(2); | 1359 DVLOGF(2); |
| 1317 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1360 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1318 | 1361 |
| 1319 if (!surface_set_change_pending_ || !surfaces_at_device_.empty()) | 1362 if (!surface_set_change_pending_) |
| 1320 return; | 1363 return true; |
| 1364 |
| 1365 if (!surfaces_at_device_.empty()) |
| 1366 return false; |
| 1321 | 1367 |
| 1322 DCHECK_EQ(state_, kIdle); | 1368 DCHECK_EQ(state_, kIdle); |
| 1323 DCHECK(decoder_display_queue_.empty()); | 1369 DCHECK(decoder_display_queue_.empty()); |
| 1324 // All output buffers should've been returned from decoder and device by now. | 1370 // All output buffers should've been returned from decoder and device by now. |
| 1325 // The only remaining owner of surfaces may be display (client), and we will | 1371 // The only remaining owner of surfaces may be display (client), and we will |
| 1326 // dismiss them when destroying output buffers below. | 1372 // dismiss them when destroying output buffers below. |
| 1327 DCHECK_EQ(free_output_buffers_.size() + surfaces_at_display_.size(), | 1373 DCHECK_EQ(free_output_buffers_.size() + surfaces_at_display_.size(), |
| 1328 output_buffer_map_.size()); | 1374 output_buffer_map_.size()); |
| 1329 | 1375 |
| 1330 // Keep input queue running while we switch outputs. | 1376 // Keep input queue running while we switch outputs. |
| 1331 if (!StopDevicePoll(true)) { | 1377 if (!StopDevicePoll(true)) { |
| 1332 NOTIFY_ERROR(PLATFORM_FAILURE); | 1378 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1333 return; | 1379 return false; |
| 1334 } | 1380 } |
| 1335 | 1381 |
| 1336 // This will return only once all buffers are dismissed and destroyed. | 1382 // This will return only once all buffers are dismissed and destroyed. |
| 1337 // This does not wait until they are displayed however, as display retains | 1383 // This does not wait until they are displayed however, as display retains |
| 1338 // references to the buffers bound to textures and will release them | 1384 // references to the buffers bound to textures and will release them |
| 1339 // after displaying. | 1385 // after displaying. |
| 1340 if (!DestroyOutputs(true)) { | 1386 if (!DestroyOutputs(true)) { |
| 1341 NOTIFY_ERROR(PLATFORM_FAILURE); | 1387 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1342 return; | 1388 return false; |
| 1343 } | 1389 } |
| 1344 | 1390 |
| 1345 if (!CreateOutputBuffers()) { | 1391 if (!CreateOutputBuffers()) { |
| 1346 NOTIFY_ERROR(PLATFORM_FAILURE); | 1392 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1347 return; | 1393 return false; |
| 1348 } | 1394 } |
| 1349 | 1395 |
| 1350 if (!StartDevicePoll()) { | |
| 1351 NOTIFY_ERROR(PLATFORM_FAILURE); | |
| 1352 return; | |
| 1353 } | |
| 1354 | |
| 1355 DVLOGF(3) << "Surface set change finished"; | |
| 1356 | |
| 1357 surface_set_change_pending_ = false; | 1396 surface_set_change_pending_ = false; |
| 1358 state_ = kDecoding; | 1397 DVLOG(3) << "Surface set change finished"; |
| 1359 ScheduleDecodeBufferTaskIfNeeded(); | 1398 return true; |
| 1360 } | 1399 } |
| 1361 | 1400 |
| 1362 bool V4L2SliceVideoDecodeAccelerator::DestroyOutputs(bool dismiss) { | 1401 bool V4L2SliceVideoDecodeAccelerator::DestroyOutputs(bool dismiss) { |
| 1363 DVLOGF(3); | 1402 DVLOGF(3); |
| 1364 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1403 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1365 std::vector<EGLImageKHR> egl_images_to_destroy; | |
| 1366 std::vector<int32_t> picture_buffers_to_dismiss; | 1404 std::vector<int32_t> picture_buffers_to_dismiss; |
| 1367 | 1405 |
| 1368 if (output_buffer_map_.empty()) | 1406 if (output_buffer_map_.empty()) |
| 1369 return true; | 1407 return true; |
| 1370 | 1408 |
| 1371 for (auto output_record : output_buffer_map_) { | 1409 for (const auto& output_record : output_buffer_map_) { |
| 1372 DCHECK(!output_record.at_device); | 1410 DCHECK(!output_record.at_device); |
| 1373 | 1411 |
| 1374 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 1412 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
| 1375 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) | 1413 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) |
| 1376 DVLOGF(1) << "eglDestroySyncKHR failed."; | 1414 DVLOGF(1) << "eglDestroySyncKHR failed."; |
| 1377 } | 1415 } |
| 1378 | 1416 |
| 1379 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { | 1417 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { |
| 1380 child_task_runner_->PostTask( | 1418 child_task_runner_->PostTask( |
| 1381 FROM_HERE, | 1419 FROM_HERE, |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1439 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); | 1477 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); |
| 1440 | 1478 |
| 1441 return true; | 1479 return true; |
| 1442 } | 1480 } |
| 1443 | 1481 |
| 1444 void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffers( | 1482 void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffers( |
| 1445 const std::vector<media::PictureBuffer>& buffers) { | 1483 const std::vector<media::PictureBuffer>& buffers) { |
| 1446 DVLOGF(3); | 1484 DVLOGF(3); |
| 1447 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1485 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1448 | 1486 |
| 1487 decoder_thread_task_runner_->PostTask( |
| 1488 FROM_HERE, |
| 1489 base::Bind(&V4L2SliceVideoDecodeAccelerator::AssignPictureBuffersTask, |
| 1490 base::Unretained(this), buffers)); |
| 1491 } |
| 1492 |
| 1493 void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffersTask( |
| 1494 const std::vector<media::PictureBuffer>& buffers) { |
| 1495 DVLOGF(3); |
| 1496 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1497 DCHECK_EQ(state_, kAwaitingPictureBuffers); |
| 1498 |
| 1449 const uint32_t req_buffer_count = decoder_->GetRequiredNumOfPictures(); | 1499 const uint32_t req_buffer_count = decoder_->GetRequiredNumOfPictures(); |
| 1450 | 1500 |
| 1451 if (buffers.size() < req_buffer_count) { | 1501 if (buffers.size() < req_buffer_count) { |
| 1452 DLOG(ERROR) << "Failed to provide requested picture buffers. " | 1502 DLOG(ERROR) << "Failed to provide requested picture buffers. " |
| 1453 << "(Got " << buffers.size() | 1503 << "(Got " << buffers.size() |
| 1454 << ", requested " << req_buffer_count << ")"; | 1504 << ", requested " << req_buffer_count << ")"; |
| 1455 NOTIFY_ERROR(INVALID_ARGUMENT); | 1505 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 1456 return; | 1506 return; |
| 1457 } | 1507 } |
| 1458 | 1508 |
| 1459 gfx::GLContext* gl_context = get_gl_context_cb_.Run(); | |
| 1460 if (!gl_context || !make_context_current_cb_.Run()) { | |
| 1461 DLOG(ERROR) << "No GL context"; | |
| 1462 NOTIFY_ERROR(PLATFORM_FAILURE); | |
| 1463 return; | |
| 1464 } | |
| 1465 | |
| 1466 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); | |
| 1467 | |
| 1468 // It's safe to manipulate all the buffer state here, because the decoder | |
| 1469 // thread is waiting on pictures_assigned_. | |
| 1470 | |
| 1471 // Allocate the output buffers. | 1509 // Allocate the output buffers. |
| 1472 struct v4l2_requestbuffers reqbufs; | 1510 struct v4l2_requestbuffers reqbufs; |
| 1473 memset(&reqbufs, 0, sizeof(reqbufs)); | 1511 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 1474 reqbufs.count = buffers.size(); | 1512 reqbufs.count = buffers.size(); |
| 1475 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1513 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1476 reqbufs.memory = V4L2_MEMORY_MMAP; | 1514 reqbufs.memory = |
| 1515 (output_mode_ == Config::OutputMode::ALLOCATE ? V4L2_MEMORY_MMAP |
| 1516 : V4L2_MEMORY_DMABUF); |
| 1477 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); | 1517 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); |
| 1478 | 1518 |
| 1479 if (reqbufs.count != buffers.size()) { | 1519 if (reqbufs.count != buffers.size()) { |
| 1480 DLOG(ERROR) << "Could not allocate enough output buffers"; | 1520 DLOG(ERROR) << "Could not allocate enough output buffers"; |
| 1481 NOTIFY_ERROR(PLATFORM_FAILURE); | 1521 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1482 return; | 1522 return; |
| 1483 } | 1523 } |
| 1484 | 1524 |
| 1525 DCHECK(free_output_buffers_.empty()); |
| 1526 DCHECK(output_buffer_map_.empty()); |
| 1485 output_buffer_map_.resize(buffers.size()); | 1527 output_buffer_map_.resize(buffers.size()); |
| 1486 | |
| 1487 DCHECK(free_output_buffers_.empty()); | |
| 1488 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 1528 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
| 1489 DCHECK(buffers[i].size() == coded_size_); | 1529 DCHECK(buffers[i].size() == coded_size_); |
| 1530 DCHECK_EQ(1u, buffers[i].texture_ids().size()); |
| 1490 | 1531 |
| 1491 OutputRecord& output_record = output_buffer_map_[i]; | 1532 OutputRecord& output_record = output_buffer_map_[i]; |
| 1492 DCHECK(!output_record.at_device); | 1533 DCHECK(!output_record.at_device); |
| 1493 DCHECK(!output_record.at_client); | 1534 DCHECK(!output_record.at_client); |
| 1494 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | 1535 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
| 1495 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 1536 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
| 1496 DCHECK_EQ(output_record.picture_id, -1); | 1537 DCHECK_EQ(output_record.picture_id, -1); |
| 1538 DCHECK(output_record.dmabuf_fds.empty()); |
| 1497 DCHECK_EQ(output_record.cleared, false); | 1539 DCHECK_EQ(output_record.cleared, false); |
| 1498 | 1540 |
| 1499 DCHECK_LE(1u, buffers[i].texture_ids().size()); | 1541 output_record.picture_id = buffers[i].id(); |
| 1500 EGLImageKHR egl_image = device_->CreateEGLImage( | 1542 output_record.texture_id = buffers[i].texture_ids()[0]; |
| 1501 egl_display_, gl_context->GetHandle(), buffers[i].texture_ids()[0], | 1543 // This will remain true until ImportBufferForPicture is called, either by |
| 1502 buffers[i].size(), i, output_format_fourcc_, output_planes_count_); | 1544 // the client, or by ourselves, if we are allocating. |
| 1503 if (egl_image == EGL_NO_IMAGE_KHR) { | 1545 output_record.at_client = true; |
| 1504 LOGF(ERROR) << "Could not create EGLImageKHR"; | 1546 if (output_mode_ == Config::OutputMode::ALLOCATE) { |
| 1505 // Ownership of EGLImages allocated in previous iterations of this loop | 1547 std::vector<base::ScopedFD> dmabuf_fds = |
| 1506 // has been transferred to output_buffer_map_. After we error-out here | 1548 std::move(device_->GetDmabufsForV4L2Buffer( |
| 1507 // the destructor will handle their cleanup. | 1549 i, output_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)); |
| 1508 NOTIFY_ERROR(PLATFORM_FAILURE); | 1550 if (dmabuf_fds.empty()) { |
| 1509 return; | 1551 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1552 return; |
| 1553 } |
| 1554 |
| 1555 auto passed_dmabuf_fds(base::WrapUnique( |
| 1556 new std::vector<base::ScopedFD>(std::move(dmabuf_fds)))); |
| 1557 ImportBufferForPictureTask(output_record.picture_id, |
| 1558 std::move(passed_dmabuf_fds)); |
| 1559 } // else we'll get triggered via ImportBufferForPicture() from client. |
| 1560 DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id; |
| 1561 } |
| 1562 |
| 1563 if (!StartDevicePoll()) { |
| 1564 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1565 return; |
| 1566 } |
| 1567 |
| 1568 // Put us in kIdle to allow further event processing. |
| 1569 // ProcessPendingEventsIfNeeded() will put us back into kDecoding after all |
| 1570 // other pending events are processed successfully. |
| 1571 state_ = kIdle; |
| 1572 ProcessPendingEventsIfNeeded(); |
| 1573 } |
| 1574 |
| 1575 void V4L2SliceVideoDecodeAccelerator::CreateEGLImageFor( |
| 1576 size_t buffer_index, |
| 1577 int32_t picture_buffer_id, |
| 1578 std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds, |
| 1579 GLuint texture_id, |
| 1580 const gfx::Size& size, |
| 1581 uint32_t fourcc) { |
| 1582 DVLOGF(3) << "index=" << buffer_index; |
| 1583 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1584 |
| 1585 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { |
| 1586 DLOG(ERROR) << "GL callbacks required for binding to EGLImages"; |
| 1587 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 1588 return; |
| 1589 } |
| 1590 |
| 1591 gfx::GLContext* gl_context = get_gl_context_cb_.Run(); |
| 1592 if (!gl_context || !make_context_current_cb_.Run()) { |
| 1593 DLOG(ERROR) << "No GL context"; |
| 1594 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1595 return; |
| 1596 } |
| 1597 |
| 1598 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); |
| 1599 |
| 1600 EGLImageKHR egl_image = |
| 1601 device_->CreateEGLImage(egl_display_, gl_context->GetHandle(), texture_id, |
| 1602 size, buffer_index, fourcc, *passed_dmabuf_fds); |
| 1603 if (egl_image == EGL_NO_IMAGE_KHR) { |
| 1604 LOGF(ERROR) << "Could not create EGLImageKHR," |
| 1605 << " index=" << buffer_index << " texture_id=" << texture_id; |
| 1606 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1607 return; |
| 1608 } |
| 1609 |
| 1610 decoder_thread_task_runner_->PostTask( |
| 1611 FROM_HERE, |
| 1612 base::Bind(&V4L2SliceVideoDecodeAccelerator::AssignEGLImage, |
| 1613 base::Unretained(this), buffer_index, picture_buffer_id, |
| 1614 egl_image, base::Passed(&passed_dmabuf_fds))); |
| 1615 } |
| 1616 |
| 1617 void V4L2SliceVideoDecodeAccelerator::AssignEGLImage( |
| 1618 size_t buffer_index, |
| 1619 int32_t picture_buffer_id, |
| 1620 EGLImageKHR egl_image, |
| 1621 std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds) { |
| 1622 DVLOGF(3) << "index=" << buffer_index; |
| 1623 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1624 |
| 1625 // It's possible that while waiting for the EGLImages to be allocated and |
| 1626 // assigned, we have already decoded more of the stream and saw another |
| 1627 // resolution change. This is a normal situation, in such a case either there |
| 1628 // is no output record with this index awaiting an EGLImage to be assigned to |
| 1629 // it, or the record is already updated to use a newer PictureBuffer and is |
| 1630 // awaiting an EGLImage associated with a different picture_buffer_id. If so, |
| 1631 // just discard this image, we will get the one we are waiting for later. |
| 1632 if (buffer_index >= output_buffer_map_.size() || |
| 1633 output_buffer_map_[buffer_index].picture_id != picture_buffer_id) { |
| 1634 DVLOGF(3) << "Picture set already changed, dropping EGLImage"; |
| 1635 child_task_runner_->PostTask( |
| 1636 FROM_HERE, base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), |
| 1637 device_, egl_display_, egl_image)); |
| 1638 return; |
| 1639 } |
| 1640 |
| 1641 OutputRecord& output_record = output_buffer_map_[buffer_index]; |
| 1642 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
| 1643 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
| 1644 DCHECK(!output_record.at_client); |
| 1645 DCHECK(!output_record.at_device); |
| 1646 |
| 1647 output_record.egl_image = egl_image; |
| 1648 if (output_mode_ == Config::OutputMode::IMPORT) { |
| 1649 DCHECK(output_record.dmabuf_fds.empty()); |
| 1650 output_record.dmabuf_fds = std::move(*passed_dmabuf_fds); |
| 1651 } |
| 1652 |
| 1653 DCHECK_EQ(std::count(free_output_buffers_.begin(), free_output_buffers_.end(), |
| 1654 buffer_index), |
| 1655 0); |
| 1656 free_output_buffers_.push_back(buffer_index); |
| 1657 ScheduleDecodeBufferTaskIfNeeded(); |
| 1658 } |
| 1659 |
| 1660 void V4L2SliceVideoDecodeAccelerator::ImportBufferForPicture( |
| 1661 int32_t picture_buffer_id, |
| 1662 const std::vector<gfx::GpuMemoryBufferHandle>& gpu_memory_buffer_handles) { |
| 1663 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; |
| 1664 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1665 |
| 1666 auto passed_dmabuf_fds(base::WrapUnique(new std::vector<base::ScopedFD>())); |
| 1667 for (const auto& handle : gpu_memory_buffer_handles) { |
| 1668 int fd = -1; |
| 1669 #if defined(USE_OZONE) |
| 1670 fd = handle.native_pixmap_handle.fd.fd; |
| 1671 #endif |
| 1672 DCHECK_NE(fd, -1); |
| 1673 passed_dmabuf_fds->push_back(base::ScopedFD(fd)); |
| 1674 } |
| 1675 |
| 1676 if (output_mode_ != Config::OutputMode::IMPORT) { |
| 1677 LOGF(ERROR) << "Cannot import in non-import mode"; |
| 1678 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 1679 return; |
| 1680 } |
| 1681 |
| 1682 decoder_thread_task_runner_->PostTask( |
| 1683 FROM_HERE, |
| 1684 base::Bind(&V4L2SliceVideoDecodeAccelerator::ImportBufferForPictureTask, |
| 1685 base::Unretained(this), picture_buffer_id, |
| 1686 base::Passed(&passed_dmabuf_fds))); |
| 1687 } |
| 1688 |
| 1689 void V4L2SliceVideoDecodeAccelerator::ImportBufferForPictureTask( |
| 1690 int32_t picture_buffer_id, |
| 1691 std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds) { |
| 1692 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; |
| 1693 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1694 |
| 1695 const auto iter = |
| 1696 std::find_if(output_buffer_map_.begin(), output_buffer_map_.end(), |
| 1697 [picture_buffer_id](const OutputRecord& output_record) { |
| 1698 return output_record.picture_id == picture_buffer_id; |
| 1699 }); |
| 1700 if (iter == output_buffer_map_.end()) { |
| 1701 LOGF(ERROR) << "Invalid picture_buffer_id=" << picture_buffer_id; |
| 1702 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 1703 return; |
| 1704 } |
| 1705 |
| 1706 if (!iter->at_client) { |
| 1707 LOGF(ERROR) << "Cannot import buffer that not owned by client"; |
| 1708 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 1709 return; |
| 1710 } |
| 1711 |
| 1712 size_t index = iter - output_buffer_map_.begin(); |
| 1713 DCHECK_EQ(std::count(free_output_buffers_.begin(), free_output_buffers_.end(), |
| 1714 index), |
| 1715 0); |
| 1716 |
| 1717 DCHECK(!iter->at_device); |
| 1718 iter->at_client = false; |
| 1719 if (iter->texture_id != 0) { |
| 1720 if (iter->egl_image != EGL_NO_IMAGE_KHR) { |
| 1721 child_task_runner_->PostTask( |
| 1722 FROM_HERE, |
| 1723 base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), device_, |
| 1724 egl_display_, iter->egl_image)); |
| 1510 } | 1725 } |
| 1511 | 1726 |
| 1512 output_record.egl_image = egl_image; | 1727 child_task_runner_->PostTask( |
| 1513 output_record.picture_id = buffers[i].id(); | 1728 FROM_HERE, |
| 1514 free_output_buffers_.push_back(i); | 1729 base::Bind(&V4L2SliceVideoDecodeAccelerator::CreateEGLImageFor, |
| 1515 DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id; | 1730 weak_this_, index, picture_buffer_id, |
| 1516 } | 1731 base::Passed(&passed_dmabuf_fds), iter->texture_id, |
| 1517 | 1732 coded_size_, output_format_fourcc_)); |
| 1518 pictures_assigned_.Signal(); | 1733 } else { |
| 1734 // No need for an EGLImage, start using this buffer now. |
| 1735 DCHECK_EQ(output_planes_count_, passed_dmabuf_fds->size()); |
| 1736 iter->dmabuf_fds.swap(*passed_dmabuf_fds); |
| 1737 free_output_buffers_.push_back(index); |
| 1738 ScheduleDecodeBufferTaskIfNeeded(); |
| 1739 } |
| 1519 } | 1740 } |
| 1520 | 1741 |
| 1521 void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( | 1742 void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( |
| 1522 int32_t picture_buffer_id) { | 1743 int32_t picture_buffer_id) { |
| 1523 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1744 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1524 DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; | 1745 DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; |
| 1525 | 1746 |
| 1526 if (!make_context_current_cb_.Run()) { | 1747 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref; |
| 1527 LOGF(ERROR) << "could not make context current"; | 1748 |
| 1528 NOTIFY_ERROR(PLATFORM_FAILURE); | 1749 if (!make_context_current_cb_.is_null()) { |
| 1529 return; | 1750 if (!make_context_current_cb_.Run()) { |
| 1530 } | 1751 LOGF(ERROR) << "could not make context current"; |
| 1531 | 1752 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1532 EGLSyncKHR egl_sync = | 1753 return; |
| 1533 eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); | 1754 } |
| 1534 if (egl_sync == EGL_NO_SYNC_KHR) { | 1755 |
| 1535 LOGF(ERROR) << "eglCreateSyncKHR() failed"; | 1756 EGLSyncKHR egl_sync = |
| 1536 NOTIFY_ERROR(PLATFORM_FAILURE); | 1757 eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); |
| 1537 return; | 1758 if (egl_sync == EGL_NO_SYNC_KHR) { |
| 1538 } | 1759 LOGF(ERROR) << "eglCreateSyncKHR() failed"; |
| 1539 | 1760 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1540 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref( | 1761 return; |
| 1541 new EGLSyncKHRRef(egl_display_, egl_sync)); | 1762 } |
| 1763 |
| 1764 egl_sync_ref.reset(new EGLSyncKHRRef(egl_display_, egl_sync)); |
| 1765 } |
| 1766 |
| 1542 decoder_thread_task_runner_->PostTask( | 1767 decoder_thread_task_runner_->PostTask( |
| 1543 FROM_HERE, | 1768 FROM_HERE, |
| 1544 base::Bind(&V4L2SliceVideoDecodeAccelerator::ReusePictureBufferTask, | 1769 base::Bind(&V4L2SliceVideoDecodeAccelerator::ReusePictureBufferTask, |
| 1545 base::Unretained(this), picture_buffer_id, | 1770 base::Unretained(this), picture_buffer_id, |
| 1546 base::Passed(&egl_sync_ref))); | 1771 base::Passed(&egl_sync_ref))); |
| 1547 } | 1772 } |
| 1548 | 1773 |
| 1549 void V4L2SliceVideoDecodeAccelerator::ReusePictureBufferTask( | 1774 void V4L2SliceVideoDecodeAccelerator::ReusePictureBufferTask( |
| 1550 int32_t picture_buffer_id, | 1775 int32_t picture_buffer_id, |
| 1551 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref) { | 1776 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1568 OutputRecord& output_record = output_buffer_map_[it->second->output_record()]; | 1793 OutputRecord& output_record = output_buffer_map_[it->second->output_record()]; |
| 1569 if (output_record.at_device || !output_record.at_client) { | 1794 if (output_record.at_device || !output_record.at_client) { |
| 1570 DVLOGF(1) << "picture_buffer_id not reusable"; | 1795 DVLOGF(1) << "picture_buffer_id not reusable"; |
| 1571 NOTIFY_ERROR(INVALID_ARGUMENT); | 1796 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 1572 return; | 1797 return; |
| 1573 } | 1798 } |
| 1574 | 1799 |
| 1575 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 1800 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
| 1576 DCHECK(!output_record.at_device); | 1801 DCHECK(!output_record.at_device); |
| 1577 output_record.at_client = false; | 1802 output_record.at_client = false; |
| 1578 output_record.egl_sync = egl_sync_ref->egl_sync; | 1803 if (egl_sync_ref) { |
| 1579 // Take ownership of the EGLSync. | 1804 output_record.egl_sync = egl_sync_ref->egl_sync; |
| 1580 egl_sync_ref->egl_sync = EGL_NO_SYNC_KHR; | 1805 // Take ownership of the EGLSync. |
| 1806 egl_sync_ref->egl_sync = EGL_NO_SYNC_KHR; |
| 1807 } |
| 1808 |
| 1581 surfaces_at_display_.erase(it); | 1809 surfaces_at_display_.erase(it); |
| 1582 } | 1810 } |
| 1583 | 1811 |
| 1584 void V4L2SliceVideoDecodeAccelerator::Flush() { | 1812 void V4L2SliceVideoDecodeAccelerator::Flush() { |
| 1585 DVLOGF(3); | 1813 DVLOGF(3); |
| 1586 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1814 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1587 | 1815 |
| 1588 decoder_thread_task_runner_->PostTask( | 1816 decoder_thread_task_runner_->PostTask( |
| 1589 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::FlushTask, | 1817 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::FlushTask, |
| 1590 base::Unretained(this))); | 1818 base::Unretained(this))); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1604 } | 1832 } |
| 1605 | 1833 |
| 1606 // No more inputs pending, so just finish flushing here. | 1834 // No more inputs pending, so just finish flushing here. |
| 1607 InitiateFlush(); | 1835 InitiateFlush(); |
| 1608 } | 1836 } |
| 1609 | 1837 |
| 1610 void V4L2SliceVideoDecodeAccelerator::InitiateFlush() { | 1838 void V4L2SliceVideoDecodeAccelerator::InitiateFlush() { |
| 1611 DVLOGF(3); | 1839 DVLOGF(3); |
| 1612 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1840 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1613 | 1841 |
| 1614 DCHECK(!decoder_flushing_); | |
| 1615 DCHECK_EQ(state_, kDecoding); | |
| 1616 state_ = kIdle; | |
| 1617 | |
| 1618 // This will trigger output for all remaining surfaces in the decoder. | 1842 // This will trigger output for all remaining surfaces in the decoder. |
| 1619 // However, not all of them may be decoded yet (they would be queued | 1843 // However, not all of them may be decoded yet (they would be queued |
| 1620 // in hardware then). | 1844 // in hardware then). |
| 1621 if (!decoder_->Flush()) { | 1845 if (!decoder_->Flush()) { |
| 1622 DVLOGF(1) << "Failed flushing the decoder."; | 1846 DVLOGF(1) << "Failed flushing the decoder."; |
| 1623 NOTIFY_ERROR(PLATFORM_FAILURE); | 1847 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1624 return; | 1848 return; |
| 1625 } | 1849 } |
| 1626 | 1850 |
| 1627 // Put the decoder in an idle state, ready to resume. | 1851 // Put the decoder in an idle state, ready to resume. |
| 1628 decoder_->Reset(); | 1852 decoder_->Reset(); |
| 1629 | 1853 |
| 1854 DCHECK(!decoder_flushing_); |
| 1630 decoder_flushing_ = true; | 1855 decoder_flushing_ = true; |
| 1631 | 1856 NewEventPending(); |
| 1632 decoder_thread_task_runner_->PostTask( | |
| 1633 FROM_HERE, | |
| 1634 base::Bind(&V4L2SliceVideoDecodeAccelerator::FinishFlushIfNeeded, | |
| 1635 base::Unretained(this))); | |
| 1636 } | 1857 } |
| 1637 | 1858 |
| 1638 void V4L2SliceVideoDecodeAccelerator::FinishFlushIfNeeded() { | 1859 bool V4L2SliceVideoDecodeAccelerator::FinishFlush() { |
| 1639 DVLOGF(3); | 1860 DVLOGF(3); |
| 1640 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1861 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1641 | 1862 |
| 1642 if (!decoder_flushing_ || !surfaces_at_device_.empty()) | 1863 if (!decoder_flushing_) |
| 1643 return; | 1864 return true; |
| 1865 |
| 1866 if (!surfaces_at_device_.empty()) |
| 1867 return false; |
| 1644 | 1868 |
| 1645 DCHECK_EQ(state_, kIdle); | 1869 DCHECK_EQ(state_, kIdle); |
| 1646 | 1870 |
| 1647 // At this point, all remaining surfaces are decoded and dequeued, and since | 1871 // At this point, all remaining surfaces are decoded and dequeued, and since |
| 1648 // we have already scheduled output for them in InitiateFlush(), their | 1872 // we have already scheduled output for them in InitiateFlush(), their |
| 1649 // respective PictureReady calls have been posted (or they have been queued on | 1873 // respective PictureReady calls have been posted (or they have been queued on |
| 1650 // pending_picture_ready_). So at this time, once we SendPictureReady(), | 1874 // pending_picture_ready_). So at this time, once we SendPictureReady(), |
| 1651 // we will have all remaining PictureReady() posted to the client and we | 1875 // we will have all remaining PictureReady() posted to the client and we |
| 1652 // can post NotifyFlushDone(). | 1876 // can post NotifyFlushDone(). |
| 1653 DCHECK(decoder_display_queue_.empty()); | 1877 DCHECK(decoder_display_queue_.empty()); |
| 1654 | 1878 |
| 1655 // Decoder should have already returned all surfaces and all surfaces are | 1879 // Decoder should have already returned all surfaces and all surfaces are |
| 1656 // out of hardware. There can be no other owners of input buffers. | 1880 // out of hardware. There can be no other owners of input buffers. |
| 1657 DCHECK_EQ(free_input_buffers_.size(), input_buffer_map_.size()); | 1881 DCHECK_EQ(free_input_buffers_.size(), input_buffer_map_.size()); |
| 1658 | 1882 |
| 1659 SendPictureReady(); | 1883 SendPictureReady(); |
| 1660 | 1884 |
| 1885 decoder_flushing_ = false; |
| 1886 DVLOGF(3) << "Flush finished"; |
| 1887 |
| 1661 child_task_runner_->PostTask(FROM_HERE, | 1888 child_task_runner_->PostTask(FROM_HERE, |
| 1662 base::Bind(&Client::NotifyFlushDone, client_)); | 1889 base::Bind(&Client::NotifyFlushDone, client_)); |
| 1663 | 1890 |
| 1664 decoder_flushing_ = false; | 1891 return true; |
| 1665 | |
| 1666 DVLOGF(3) << "Flush finished"; | |
| 1667 state_ = kDecoding; | |
| 1668 ScheduleDecodeBufferTaskIfNeeded(); | |
| 1669 } | 1892 } |
| 1670 | 1893 |
| 1671 void V4L2SliceVideoDecodeAccelerator::Reset() { | 1894 void V4L2SliceVideoDecodeAccelerator::Reset() { |
| 1672 DVLOGF(3); | 1895 DVLOGF(3); |
| 1673 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1896 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 1674 | 1897 |
| 1675 decoder_thread_task_runner_->PostTask( | 1898 decoder_thread_task_runner_->PostTask( |
| 1676 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::ResetTask, | 1899 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::ResetTask, |
| 1677 base::Unretained(this))); | 1900 base::Unretained(this))); |
| 1678 } | 1901 } |
| 1679 | 1902 |
| 1680 void V4L2SliceVideoDecodeAccelerator::ResetTask() { | 1903 void V4L2SliceVideoDecodeAccelerator::ResetTask() { |
| 1681 DVLOGF(3); | 1904 DVLOGF(3); |
| 1682 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1905 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1683 | 1906 |
| 1684 if (decoder_resetting_) { | 1907 if (decoder_resetting_) { |
| 1685 // This is a bug in the client, multiple Reset()s before NotifyResetDone() | 1908 // This is a bug in the client, multiple Reset()s before NotifyResetDone() |
| 1686 // are not allowed. | 1909 // are not allowed. |
| 1687 NOTREACHED() << "Client should not be requesting multiple Reset()s"; | 1910 NOTREACHED() << "Client should not be requesting multiple Reset()s"; |
| 1688 return; | 1911 return; |
| 1689 } | 1912 } |
| 1690 | 1913 |
| 1691 DCHECK_EQ(state_, kDecoding); | |
| 1692 state_ = kIdle; | |
| 1693 | |
| 1694 // Put the decoder in an idle state, ready to resume. | 1914 // Put the decoder in an idle state, ready to resume. |
| 1695 decoder_->Reset(); | 1915 decoder_->Reset(); |
| 1696 | 1916 |
| 1697 decoder_resetting_ = true; | |
| 1698 | |
| 1699 // Drop all remaining inputs. | 1917 // Drop all remaining inputs. |
| 1700 decoder_current_bitstream_buffer_.reset(); | 1918 decoder_current_bitstream_buffer_.reset(); |
| 1701 while (!decoder_input_queue_.empty()) | 1919 while (!decoder_input_queue_.empty()) |
| 1702 decoder_input_queue_.pop(); | 1920 decoder_input_queue_.pop(); |
| 1703 | 1921 |
| 1704 FinishResetIfNeeded(); | 1922 decoder_resetting_ = true; |
| 1923 NewEventPending(); |
| 1705 } | 1924 } |
| 1706 | 1925 |
| 1707 void V4L2SliceVideoDecodeAccelerator::FinishResetIfNeeded() { | 1926 bool V4L2SliceVideoDecodeAccelerator::FinishReset() { |
| 1708 DVLOGF(3); | 1927 DVLOGF(3); |
| 1709 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1928 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 1710 | 1929 |
| 1711 if (!decoder_resetting_ || !surfaces_at_device_.empty()) | 1930 if (!decoder_resetting_) |
| 1712 return; | 1931 return true; |
| 1932 |
| 1933 if (!surfaces_at_device_.empty()) |
| 1934 return false; |
| 1713 | 1935 |
| 1714 DCHECK_EQ(state_, kIdle); | 1936 DCHECK_EQ(state_, kIdle); |
| 1715 DCHECK(!decoder_flushing_); | 1937 DCHECK(!decoder_flushing_); |
| 1716 SendPictureReady(); | 1938 SendPictureReady(); |
| 1717 | 1939 |
| 1718 // Drop any pending outputs. | 1940 // Drop any pending outputs. |
| 1719 while (!decoder_display_queue_.empty()) | 1941 while (!decoder_display_queue_.empty()) |
| 1720 decoder_display_queue_.pop(); | 1942 decoder_display_queue_.pop(); |
| 1721 | 1943 |
| 1722 // At this point we can have no input buffers in the decoder, because we | 1944 // At this point we can have no input buffers in the decoder, because we |
| 1723 // Reset()ed it in ResetTask(), and have not scheduled any new Decode()s | 1945 // Reset()ed it in ResetTask(), and have not scheduled any new Decode()s |
| 1724 // having been in kIdle since. We don't have any surfaces in the HW either - | 1946 // having been in kIdle since. We don't have any surfaces in the HW either - |
| 1725 // we just checked that surfaces_at_device_.empty(), and inputs are tied | 1947 // we just checked that surfaces_at_device_.empty(), and inputs are tied |
| 1726 // to surfaces. Since there can be no other owners of input buffers, we can | 1948 // to surfaces. Since there can be no other owners of input buffers, we can |
| 1727 // simply mark them all as available. | 1949 // simply mark them all as available. |
| 1728 DCHECK_EQ(input_buffer_queued_count_, 0); | 1950 DCHECK_EQ(input_buffer_queued_count_, 0); |
| 1729 free_input_buffers_.clear(); | 1951 free_input_buffers_.clear(); |
| 1730 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { | 1952 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { |
| 1731 DCHECK(!input_buffer_map_[i].at_device); | 1953 DCHECK(!input_buffer_map_[i].at_device); |
| 1732 ReuseInputBuffer(i); | 1954 ReuseInputBuffer(i); |
| 1733 } | 1955 } |
| 1734 | 1956 |
| 1735 decoder_resetting_ = false; | 1957 decoder_resetting_ = false; |
| 1958 DVLOGF(3) << "Reset finished"; |
| 1736 | 1959 |
| 1737 child_task_runner_->PostTask(FROM_HERE, | 1960 child_task_runner_->PostTask(FROM_HERE, |
| 1738 base::Bind(&Client::NotifyResetDone, client_)); | 1961 base::Bind(&Client::NotifyResetDone, client_)); |
| 1739 | 1962 |
| 1740 DVLOGF(3) << "Reset finished"; | 1963 return true; |
| 1741 | |
| 1742 state_ = kDecoding; | |
| 1743 ScheduleDecodeBufferTaskIfNeeded(); | |
| 1744 } | 1964 } |
| 1745 | 1965 |
| 1746 void V4L2SliceVideoDecodeAccelerator::SetErrorState(Error error) { | 1966 void V4L2SliceVideoDecodeAccelerator::SetErrorState(Error error) { |
| 1747 // We can touch decoder_state_ only if this is the decoder thread or the | 1967 // We can touch decoder_state_ only if this is the decoder thread or the |
| 1748 // decoder thread isn't running. | 1968 // decoder thread isn't running. |
| 1749 if (decoder_thread_.IsRunning() && | 1969 if (decoder_thread_.IsRunning() && |
| 1750 !decoder_thread_task_runner_->BelongsToCurrentThread()) { | 1970 !decoder_thread_task_runner_->BelongsToCurrentThread()) { |
| 1751 decoder_thread_task_runner_->PostTask( | 1971 decoder_thread_task_runner_->PostTask( |
| 1752 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::SetErrorState, | 1972 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::SetErrorState, |
| 1753 base::Unretained(this), error)); | 1973 base::Unretained(this), error)); |
| (...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2453 OutputRecord& output_record = | 2673 OutputRecord& output_record = |
| 2454 output_buffer_map_[dec_surface->output_record()]; | 2674 output_buffer_map_[dec_surface->output_record()]; |
| 2455 | 2675 |
| 2456 bool inserted = | 2676 bool inserted = |
| 2457 surfaces_at_display_.insert(std::make_pair(output_record.picture_id, | 2677 surfaces_at_display_.insert(std::make_pair(output_record.picture_id, |
| 2458 dec_surface)).second; | 2678 dec_surface)).second; |
| 2459 DCHECK(inserted); | 2679 DCHECK(inserted); |
| 2460 | 2680 |
| 2461 DCHECK(!output_record.at_client); | 2681 DCHECK(!output_record.at_client); |
| 2462 DCHECK(!output_record.at_device); | 2682 DCHECK(!output_record.at_device); |
| 2463 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
| 2464 DCHECK_NE(output_record.picture_id, -1); | 2683 DCHECK_NE(output_record.picture_id, -1); |
| 2465 output_record.at_client = true; | 2684 output_record.at_client = true; |
| 2466 | 2685 |
| 2467 // TODO(posciak): Use visible size from decoder here instead | 2686 // TODO(posciak): Use visible size from decoder here instead |
| 2468 // (crbug.com/402760). Passing (0, 0) results in the client using the | 2687 // (crbug.com/402760). Passing (0, 0) results in the client using the |
| 2469 // visible size extracted from the container instead. | 2688 // visible size extracted from the container instead. |
| 2470 media::Picture picture(output_record.picture_id, dec_surface->bitstream_id(), | 2689 media::Picture picture(output_record.picture_id, dec_surface->bitstream_id(), |
| 2471 gfx::Rect(0, 0), false); | 2690 gfx::Rect(0, 0), false); |
| 2472 DVLOGF(3) << dec_surface->ToString() | 2691 DVLOGF(3) << dec_surface->ToString() |
| 2473 << ", bitstream_id: " << picture.bitstream_buffer_id() | 2692 << ", bitstream_id: " << picture.bitstream_buffer_id() |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2559 } | 2778 } |
| 2560 | 2779 |
| 2561 bool V4L2SliceVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( | 2780 bool V4L2SliceVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( |
| 2562 const base::WeakPtr<Client>& decode_client, | 2781 const base::WeakPtr<Client>& decode_client, |
| 2563 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { | 2782 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { |
| 2564 decode_client_ = decode_client_; | 2783 decode_client_ = decode_client_; |
| 2565 decode_task_runner_ = decode_task_runner; | 2784 decode_task_runner_ = decode_task_runner; |
| 2566 return true; | 2785 return true; |
| 2567 } | 2786 } |
| 2568 | 2787 |
| 2788 media::VideoPixelFormat V4L2SliceVideoDecodeAccelerator::GetOutputFormat() |
| 2789 const { |
| 2790 return V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_); |
| 2791 } |
| 2792 |
| 2569 // static | 2793 // static |
| 2570 media::VideoDecodeAccelerator::SupportedProfiles | 2794 media::VideoDecodeAccelerator::SupportedProfiles |
| 2571 V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles() { | 2795 V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles() { |
| 2572 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); | 2796 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); |
| 2573 if (!device) | 2797 if (!device) |
| 2574 return SupportedProfiles(); | 2798 return SupportedProfiles(); |
| 2575 | 2799 |
| 2576 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), | 2800 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), |
| 2577 supported_input_fourccs_); | 2801 supported_input_fourccs_); |
| 2578 } | 2802 } |
| 2579 | 2803 |
| 2580 } // namespace content | 2804 } // namespace content |
| OLD | NEW |