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 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
752 | 754 |
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 |
wuchengli
2016/04/13 10:54:25
Please document what the state is before setting i
Pawel Osciak
2016/04/18 06:17:32
Done.
| |
763 // Wait for the client to call AssignPictureBuffers() on the Child thread. | 765 state_ = kAwaitingPictureBuffers; |
764 // We do this, because if we continue decoding without finishing buffer | |
765 // allocation, we may end up Resetting before AssignPictureBuffers arrives, | |
766 // resulting in unnecessary complications and subtle bugs. | |
767 pictures_assigned_.Wait(); | |
768 | |
769 return true; | 766 return true; |
770 } | 767 } |
771 | 768 |
772 void V4L2SliceVideoDecodeAccelerator::DestroyInputBuffers() { | 769 void V4L2SliceVideoDecodeAccelerator::DestroyInputBuffers() { |
773 DVLOGF(3); | 770 DVLOGF(3); |
774 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread() || | 771 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread() || |
775 !decoder_thread_.IsRunning()); | 772 !decoder_thread_.IsRunning()); |
776 DCHECK(!input_streamon_); | 773 DCHECK(!input_streamon_); |
777 | 774 |
778 for (auto& input_record : input_buffer_map_) { | 775 for (auto& input_record : input_buffer_map_) { |
779 if (input_record.address != nullptr) | 776 if (input_record.address != nullptr) |
780 device_->Munmap(input_record.address, input_record.length); | 777 device_->Munmap(input_record.address, input_record.length); |
781 } | 778 } |
782 | 779 |
783 struct v4l2_requestbuffers reqbufs; | 780 struct v4l2_requestbuffers reqbufs; |
784 memset(&reqbufs, 0, sizeof(reqbufs)); | 781 memset(&reqbufs, 0, sizeof(reqbufs)); |
785 reqbufs.count = 0; | 782 reqbufs.count = 0; |
786 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 783 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
787 reqbufs.memory = V4L2_MEMORY_MMAP; | 784 reqbufs.memory = V4L2_MEMORY_MMAP; |
788 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 785 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
789 | 786 |
790 input_buffer_map_.clear(); | 787 input_buffer_map_.clear(); |
791 free_input_buffers_.clear(); | 788 free_input_buffers_.clear(); |
792 } | 789 } |
793 | 790 |
794 void V4L2SliceVideoDecodeAccelerator::DismissPictures( | 791 void V4L2SliceVideoDecodeAccelerator::DismissPictures( |
795 std::vector<int32_t> picture_buffer_ids, | 792 const std::vector<int32_t>& picture_buffer_ids, |
796 base::WaitableEvent* done) { | 793 base::WaitableEvent* done) { |
797 DVLOGF(3); | 794 DVLOGF(3); |
798 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 795 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
799 | 796 |
800 for (auto picture_buffer_id : picture_buffer_ids) { | 797 for (auto picture_buffer_id : picture_buffer_ids) { |
801 DVLOGF(1) << "dismissing PictureBuffer id=" << picture_buffer_id; | 798 DVLOGF(1) << "dismissing PictureBuffer id=" << picture_buffer_id; |
802 client_->DismissPictureBuffer(picture_buffer_id); | 799 client_->DismissPictureBuffer(picture_buffer_id); |
803 } | 800 } |
804 | 801 |
805 done->Signal(); | 802 done->Signal(); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
899 DVLOGF(3); | 896 DVLOGF(3); |
900 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 897 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
901 | 898 |
902 struct v4l2_buffer dqbuf; | 899 struct v4l2_buffer dqbuf; |
903 struct v4l2_plane planes[VIDEO_MAX_PLANES]; | 900 struct v4l2_plane planes[VIDEO_MAX_PLANES]; |
904 while (input_buffer_queued_count_ > 0) { | 901 while (input_buffer_queued_count_ > 0) { |
905 DCHECK(input_streamon_); | 902 DCHECK(input_streamon_); |
906 memset(&dqbuf, 0, sizeof(dqbuf)); | 903 memset(&dqbuf, 0, sizeof(dqbuf)); |
907 memset(&planes, 0, sizeof(planes)); | 904 memset(&planes, 0, sizeof(planes)); |
908 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 905 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
909 dqbuf.memory = V4L2_MEMORY_USERPTR; | 906 dqbuf.memory = V4L2_MEMORY_MMAP; |
910 dqbuf.m.planes = planes; | 907 dqbuf.m.planes = planes; |
911 dqbuf.length = input_planes_count_; | 908 dqbuf.length = input_planes_count_; |
912 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { | 909 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
913 if (errno == EAGAIN) { | 910 if (errno == EAGAIN) { |
914 // EAGAIN if we're just out of buffers to dequeue. | 911 // EAGAIN if we're just out of buffers to dequeue. |
915 break; | 912 break; |
916 } | 913 } |
917 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; | 914 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; |
918 NOTIFY_ERROR(PLATFORM_FAILURE); | 915 NOTIFY_ERROR(PLATFORM_FAILURE); |
919 return; | 916 return; |
920 } | 917 } |
921 InputRecord& input_record = input_buffer_map_[dqbuf.index]; | 918 InputRecord& input_record = input_buffer_map_[dqbuf.index]; |
922 DCHECK(input_record.at_device); | 919 DCHECK(input_record.at_device); |
923 input_record.at_device = false; | 920 input_record.at_device = false; |
924 ReuseInputBuffer(dqbuf.index); | 921 ReuseInputBuffer(dqbuf.index); |
925 input_buffer_queued_count_--; | 922 input_buffer_queued_count_--; |
926 DVLOGF(4) << "Dequeued input=" << dqbuf.index | 923 DVLOGF(4) << "Dequeued input=" << dqbuf.index |
927 << " count: " << input_buffer_queued_count_; | 924 << " count: " << input_buffer_queued_count_; |
928 } | 925 } |
929 | 926 |
930 while (output_buffer_queued_count_ > 0) { | 927 while (output_buffer_queued_count_ > 0) { |
931 DCHECK(output_streamon_); | 928 DCHECK(output_streamon_); |
932 memset(&dqbuf, 0, sizeof(dqbuf)); | 929 memset(&dqbuf, 0, sizeof(dqbuf)); |
933 memset(&planes, 0, sizeof(planes)); | 930 memset(&planes, 0, sizeof(planes)); |
934 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 931 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
935 dqbuf.memory = V4L2_MEMORY_MMAP; | 932 dqbuf.memory = |
933 (output_mode_ == Config::OutputMode::ALLOCATE ? V4L2_MEMORY_MMAP | |
934 : V4L2_MEMORY_DMABUF); | |
936 dqbuf.m.planes = planes; | 935 dqbuf.m.planes = planes; |
937 dqbuf.length = output_planes_count_; | 936 dqbuf.length = output_planes_count_; |
938 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { | 937 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
939 if (errno == EAGAIN) { | 938 if (errno == EAGAIN) { |
940 // EAGAIN if we're just out of buffers to dequeue. | 939 // EAGAIN if we're just out of buffers to dequeue. |
941 break; | 940 break; |
942 } | 941 } |
943 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; | 942 PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; |
944 NOTIFY_ERROR(PLATFORM_FAILURE); | 943 NOTIFY_ERROR(PLATFORM_FAILURE); |
945 return; | 944 return; |
(...skipping 15 matching lines...) Expand all Loading... | |
961 it->second->SetDecoded(); | 960 it->second->SetDecoded(); |
962 surfaces_at_device_.erase(it); | 961 surfaces_at_device_.erase(it); |
963 } | 962 } |
964 | 963 |
965 // A frame was decoded, see if we can output it. | 964 // A frame was decoded, see if we can output it. |
966 TryOutputSurfaces(); | 965 TryOutputSurfaces(); |
967 | 966 |
968 ProcessPendingEventsIfNeeded(); | 967 ProcessPendingEventsIfNeeded(); |
969 } | 968 } |
970 | 969 |
970 void V4L2SliceVideoDecodeAccelerator::NewEventPending() { | |
971 // Switch to event processing mode if we are decoding. Otherwise we are either | |
972 // already in it, or we will potentially switch to it later, after finishing | |
973 // other tasks. | |
974 if (state_ == kDecoding) | |
975 state_ = kIdle; | |
976 | |
977 ProcessPendingEventsIfNeeded(); | |
978 } | |
979 | |
980 bool V4L2SliceVideoDecodeAccelerator::FinishEventProcessing() { | |
981 DCHECK_EQ(state_, kIdle); | |
982 | |
983 state_ = kDecoding; | |
984 ScheduleDecodeBufferTaskIfNeeded(); | |
985 | |
986 return true; | |
987 } | |
988 | |
971 void V4L2SliceVideoDecodeAccelerator::ProcessPendingEventsIfNeeded() { | 989 void V4L2SliceVideoDecodeAccelerator::ProcessPendingEventsIfNeeded() { |
990 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | |
991 | |
972 // Process pending events, if any, in the correct order. | 992 // Process pending events, if any, in the correct order. |
973 // We always first process the surface set change, as it is an internal | 993 // 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 | 994 // event from the decoder and interleaving it with external requests would |
975 // put the decoder in an undefined state. | 995 // put the decoder in an undefined state. |
976 FinishSurfaceSetChangeIfNeeded(); | 996 using ProcessFunc = bool (V4L2SliceVideoDecodeAccelerator::*)(); |
997 const ProcessFunc process_functions[] = { | |
998 &V4L2SliceVideoDecodeAccelerator::FinishSurfaceSetChange, | |
999 &V4L2SliceVideoDecodeAccelerator::FinishFlush, | |
1000 &V4L2SliceVideoDecodeAccelerator::FinishReset, | |
1001 &V4L2SliceVideoDecodeAccelerator::FinishEventProcessing, | |
1002 }; | |
977 | 1003 |
978 // Process external (client) requests. | 1004 for (const auto& fn : process_functions) { |
979 FinishFlushIfNeeded(); | 1005 if (state_ != kIdle) |
980 FinishResetIfNeeded(); | 1006 return; |
1007 | |
1008 if (!(this->*fn)()) | |
1009 return; | |
1010 } | |
981 } | 1011 } |
982 | 1012 |
983 void V4L2SliceVideoDecodeAccelerator::ReuseInputBuffer(int index) { | 1013 void V4L2SliceVideoDecodeAccelerator::ReuseInputBuffer(int index) { |
984 DVLOGF(4) << "Reusing input buffer, index=" << index; | 1014 DVLOGF(4) << "Reusing input buffer, index=" << index; |
985 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1015 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
986 | 1016 |
987 DCHECK_LT(index, static_cast<int>(input_buffer_map_.size())); | 1017 DCHECK_LT(index, static_cast<int>(input_buffer_map_.size())); |
988 InputRecord& input_record = input_buffer_map_[index]; | 1018 InputRecord& input_record = input_buffer_map_[index]; |
989 | 1019 |
990 DCHECK(!input_record.at_device); | 1020 DCHECK(!input_record.at_device); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1043 } | 1073 } |
1044 | 1074 |
1045 bool V4L2SliceVideoDecodeAccelerator::EnqueueOutputRecord(int index) { | 1075 bool V4L2SliceVideoDecodeAccelerator::EnqueueOutputRecord(int index) { |
1046 DVLOGF(3); | 1076 DVLOGF(3); |
1047 DCHECK_LT(index, static_cast<int>(output_buffer_map_.size())); | 1077 DCHECK_LT(index, static_cast<int>(output_buffer_map_.size())); |
1048 | 1078 |
1049 // Enqueue an output (VIDEO_CAPTURE) buffer. | 1079 // Enqueue an output (VIDEO_CAPTURE) buffer. |
1050 OutputRecord& output_record = output_buffer_map_[index]; | 1080 OutputRecord& output_record = output_buffer_map_[index]; |
1051 DCHECK(!output_record.at_device); | 1081 DCHECK(!output_record.at_device); |
1052 DCHECK(!output_record.at_client); | 1082 DCHECK(!output_record.at_client); |
1053 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
1054 DCHECK_NE(output_record.picture_id, -1); | 1083 DCHECK_NE(output_record.picture_id, -1); |
1055 | 1084 |
1056 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 1085 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
1057 // If we have to wait for completion, wait. Note that | 1086 // If we have to wait for completion, wait. Note that |
1058 // free_output_buffers_ is a FIFO queue, so we always wait on the | 1087 // free_output_buffers_ is a FIFO queue, so we always wait on the |
1059 // buffer that has been in the queue the longest. | 1088 // buffer that has been in the queue the longest. |
1060 if (eglClientWaitSyncKHR(egl_display_, output_record.egl_sync, 0, | 1089 if (eglClientWaitSyncKHR(egl_display_, output_record.egl_sync, 0, |
1061 EGL_FOREVER_KHR) == EGL_FALSE) { | 1090 EGL_FOREVER_KHR) == EGL_FALSE) { |
1062 // This will cause tearing, but is safe otherwise. | 1091 // This will cause tearing, but is safe otherwise. |
1063 DVLOGF(1) << "eglClientWaitSyncKHR failed!"; | 1092 DVLOGF(1) << "eglClientWaitSyncKHR failed!"; |
1064 } | 1093 } |
1065 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 1094 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
1066 LOGF(ERROR) << "eglDestroySyncKHR failed!"; | 1095 LOGF(ERROR) << "eglDestroySyncKHR failed!"; |
1067 NOTIFY_ERROR(PLATFORM_FAILURE); | 1096 NOTIFY_ERROR(PLATFORM_FAILURE); |
1068 return false; | 1097 return false; |
1069 } | 1098 } |
1070 output_record.egl_sync = EGL_NO_SYNC_KHR; | 1099 output_record.egl_sync = EGL_NO_SYNC_KHR; |
1071 } | 1100 } |
1072 | 1101 |
1073 struct v4l2_buffer qbuf; | 1102 struct v4l2_buffer qbuf; |
1074 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; | 1103 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; |
1075 memset(&qbuf, 0, sizeof(qbuf)); | 1104 memset(&qbuf, 0, sizeof(qbuf)); |
1076 memset(qbuf_planes, 0, sizeof(qbuf_planes)); | 1105 memset(qbuf_planes, 0, sizeof(qbuf_planes)); |
1077 qbuf.index = index; | 1106 qbuf.index = index; |
1078 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1107 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1079 qbuf.memory = V4L2_MEMORY_MMAP; | 1108 if (output_mode_ == Config::OutputMode::ALLOCATE) { |
1109 qbuf.memory = V4L2_MEMORY_MMAP; | |
1110 } else { | |
1111 qbuf.memory = V4L2_MEMORY_DMABUF; | |
1112 DCHECK_EQ(output_planes_count_, output_record.dmabuf_fds.size()); | |
1113 for (size_t i = 0; i < output_record.dmabuf_fds.size(); ++i) { | |
1114 DCHECK(output_record.dmabuf_fds[i].is_valid()); | |
1115 qbuf_planes[i].m.fd = output_record.dmabuf_fds[i].get(); | |
1116 } | |
1117 } | |
1080 qbuf.m.planes = qbuf_planes; | 1118 qbuf.m.planes = qbuf_planes; |
1081 qbuf.length = output_planes_count_; | 1119 qbuf.length = output_planes_count_; |
1082 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 1120 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
1083 output_record.at_device = true; | 1121 output_record.at_device = true; |
1084 output_buffer_queued_count_++; | 1122 output_buffer_queued_count_++; |
1085 DVLOGF(4) << "Enqueued output=" << qbuf.index | 1123 DVLOGF(4) << "Enqueued output=" << qbuf.index |
1086 << " count: " << output_buffer_queued_count_; | 1124 << " count: " << output_buffer_queued_count_; |
1087 | 1125 |
1088 return true; | 1126 return true; |
1089 } | 1127 } |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1295 DVLOGF(1) << "Error decoding stream"; | 1333 DVLOGF(1) << "Error decoding stream"; |
1296 NOTIFY_ERROR(PLATFORM_FAILURE); | 1334 NOTIFY_ERROR(PLATFORM_FAILURE); |
1297 return; | 1335 return; |
1298 } | 1336 } |
1299 } | 1337 } |
1300 } | 1338 } |
1301 | 1339 |
1302 void V4L2SliceVideoDecodeAccelerator::InitiateSurfaceSetChange() { | 1340 void V4L2SliceVideoDecodeAccelerator::InitiateSurfaceSetChange() { |
1303 DVLOGF(2); | 1341 DVLOGF(2); |
1304 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1342 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
1305 | |
1306 DCHECK_EQ(state_, kDecoding); | 1343 DCHECK_EQ(state_, kDecoding); |
1307 state_ = kIdle; | |
1308 | 1344 |
1309 DCHECK(!surface_set_change_pending_); | 1345 DCHECK(!surface_set_change_pending_); |
1310 surface_set_change_pending_ = true; | 1346 surface_set_change_pending_ = true; |
1311 | 1347 NewEventPending(); |
1312 FinishSurfaceSetChangeIfNeeded(); | |
1313 } | 1348 } |
1314 | 1349 |
1315 void V4L2SliceVideoDecodeAccelerator::FinishSurfaceSetChangeIfNeeded() { | 1350 bool V4L2SliceVideoDecodeAccelerator::FinishSurfaceSetChange() { |
1316 DVLOGF(2); | 1351 DVLOGF(2); |
1317 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1352 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
1318 | 1353 |
1319 if (!surface_set_change_pending_ || !surfaces_at_device_.empty()) | 1354 if (!surface_set_change_pending_) |
1320 return; | 1355 return true; |
1356 | |
1357 if (!surfaces_at_device_.empty()) | |
1358 return false; | |
1321 | 1359 |
1322 DCHECK_EQ(state_, kIdle); | 1360 DCHECK_EQ(state_, kIdle); |
1323 DCHECK(decoder_display_queue_.empty()); | 1361 DCHECK(decoder_display_queue_.empty()); |
1324 // All output buffers should've been returned from decoder and device by now. | 1362 // 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 | 1363 // The only remaining owner of surfaces may be display (client), and we will |
1326 // dismiss them when destroying output buffers below. | 1364 // dismiss them when destroying output buffers below. |
1327 DCHECK_EQ(free_output_buffers_.size() + surfaces_at_display_.size(), | 1365 DCHECK_EQ(free_output_buffers_.size() + surfaces_at_display_.size(), |
1328 output_buffer_map_.size()); | 1366 output_buffer_map_.size()); |
1329 | 1367 |
1330 // Keep input queue running while we switch outputs. | 1368 // Keep input queue running while we switch outputs. |
1331 if (!StopDevicePoll(true)) { | 1369 if (!StopDevicePoll(true)) { |
1332 NOTIFY_ERROR(PLATFORM_FAILURE); | 1370 NOTIFY_ERROR(PLATFORM_FAILURE); |
1333 return; | 1371 return false; |
1334 } | 1372 } |
1335 | 1373 |
1336 // This will return only once all buffers are dismissed and destroyed. | 1374 // This will return only once all buffers are dismissed and destroyed. |
1337 // This does not wait until they are displayed however, as display retains | 1375 // This does not wait until they are displayed however, as display retains |
1338 // references to the buffers bound to textures and will release them | 1376 // references to the buffers bound to textures and will release them |
1339 // after displaying. | 1377 // after displaying. |
1340 if (!DestroyOutputs(true)) { | 1378 if (!DestroyOutputs(true)) { |
1341 NOTIFY_ERROR(PLATFORM_FAILURE); | 1379 NOTIFY_ERROR(PLATFORM_FAILURE); |
1342 return; | 1380 return false; |
1343 } | 1381 } |
1344 | 1382 |
1345 if (!CreateOutputBuffers()) { | 1383 if (!CreateOutputBuffers()) { |
1346 NOTIFY_ERROR(PLATFORM_FAILURE); | 1384 NOTIFY_ERROR(PLATFORM_FAILURE); |
1347 return; | 1385 return false; |
1348 } | 1386 } |
1349 | 1387 |
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; | 1388 surface_set_change_pending_ = false; |
1358 state_ = kDecoding; | 1389 DVLOG(3) << "Surface set change finished"; |
1359 ScheduleDecodeBufferTaskIfNeeded(); | 1390 return true; |
1360 } | 1391 } |
1361 | 1392 |
1362 bool V4L2SliceVideoDecodeAccelerator::DestroyOutputs(bool dismiss) { | 1393 bool V4L2SliceVideoDecodeAccelerator::DestroyOutputs(bool dismiss) { |
1363 DVLOGF(3); | 1394 DVLOGF(3); |
1364 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1395 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
1365 std::vector<EGLImageKHR> egl_images_to_destroy; | |
1366 std::vector<int32_t> picture_buffers_to_dismiss; | 1396 std::vector<int32_t> picture_buffers_to_dismiss; |
1367 | 1397 |
1368 if (output_buffer_map_.empty()) | 1398 if (output_buffer_map_.empty()) |
1369 return true; | 1399 return true; |
1370 | 1400 |
1371 for (auto output_record : output_buffer_map_) { | 1401 for (const auto& output_record : output_buffer_map_) { |
1372 DCHECK(!output_record.at_device); | 1402 DCHECK(!output_record.at_device); |
1373 | 1403 |
1374 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 1404 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
1375 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) | 1405 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) |
1376 DVLOGF(1) << "eglDestroySyncKHR failed."; | 1406 DVLOGF(1) << "eglDestroySyncKHR failed."; |
1377 } | 1407 } |
1378 | 1408 |
1379 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { | 1409 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { |
1380 child_task_runner_->PostTask( | 1410 child_task_runner_->PostTask( |
1381 FROM_HERE, | 1411 FROM_HERE, |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1439 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); | 1469 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); |
1440 | 1470 |
1441 return true; | 1471 return true; |
1442 } | 1472 } |
1443 | 1473 |
1444 void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffers( | 1474 void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffers( |
1445 const std::vector<media::PictureBuffer>& buffers) { | 1475 const std::vector<media::PictureBuffer>& buffers) { |
1446 DVLOGF(3); | 1476 DVLOGF(3); |
1447 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1477 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
1448 | 1478 |
1479 decoder_thread_task_runner_->PostTask( | |
1480 FROM_HERE, | |
1481 base::Bind(&V4L2SliceVideoDecodeAccelerator::AssignPictureBuffersTask, | |
1482 base::Unretained(this), buffers)); | |
1483 } | |
1484 | |
1485 void V4L2SliceVideoDecodeAccelerator::AssignPictureBuffersTask( | |
1486 const std::vector<media::PictureBuffer>& buffers) { | |
1487 DVLOGF(3); | |
1488 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | |
1489 DCHECK_EQ(state_, kAwaitingPictureBuffers); | |
1490 | |
1449 const uint32_t req_buffer_count = decoder_->GetRequiredNumOfPictures(); | 1491 const uint32_t req_buffer_count = decoder_->GetRequiredNumOfPictures(); |
1450 | 1492 |
1451 if (buffers.size() < req_buffer_count) { | 1493 if (buffers.size() < req_buffer_count) { |
1452 DLOG(ERROR) << "Failed to provide requested picture buffers. " | 1494 DLOG(ERROR) << "Failed to provide requested picture buffers. " |
1453 << "(Got " << buffers.size() | 1495 << "(Got " << buffers.size() |
1454 << ", requested " << req_buffer_count << ")"; | 1496 << ", requested " << req_buffer_count << ")"; |
1455 NOTIFY_ERROR(INVALID_ARGUMENT); | 1497 NOTIFY_ERROR(INVALID_ARGUMENT); |
1456 return; | 1498 return; |
1457 } | 1499 } |
1458 | 1500 |
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. | 1501 // Allocate the output buffers. |
1472 struct v4l2_requestbuffers reqbufs; | 1502 struct v4l2_requestbuffers reqbufs; |
1473 memset(&reqbufs, 0, sizeof(reqbufs)); | 1503 memset(&reqbufs, 0, sizeof(reqbufs)); |
1474 reqbufs.count = buffers.size(); | 1504 reqbufs.count = buffers.size(); |
1475 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1505 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1476 reqbufs.memory = V4L2_MEMORY_MMAP; | 1506 reqbufs.memory = |
1507 (output_mode_ == Config::OutputMode::ALLOCATE ? V4L2_MEMORY_MMAP | |
1508 : V4L2_MEMORY_DMABUF); | |
1477 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); | 1509 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); |
1478 | 1510 |
1479 if (reqbufs.count != buffers.size()) { | 1511 if (reqbufs.count != buffers.size()) { |
1480 DLOG(ERROR) << "Could not allocate enough output buffers"; | 1512 DLOG(ERROR) << "Could not allocate enough output buffers"; |
1481 NOTIFY_ERROR(PLATFORM_FAILURE); | 1513 NOTIFY_ERROR(PLATFORM_FAILURE); |
1482 return; | 1514 return; |
1483 } | 1515 } |
1484 | 1516 |
1517 DCHECK(free_output_buffers_.empty()); | |
1518 DCHECK(output_buffer_map_.empty()); | |
1485 output_buffer_map_.resize(buffers.size()); | 1519 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) { | 1520 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
1489 DCHECK(buffers[i].size() == coded_size_); | 1521 DCHECK(buffers[i].size() == coded_size_); |
1522 DCHECK_EQ(1u, buffers[i].texture_ids().size()); | |
1490 | 1523 |
1491 OutputRecord& output_record = output_buffer_map_[i]; | 1524 OutputRecord& output_record = output_buffer_map_[i]; |
1492 DCHECK(!output_record.at_device); | 1525 DCHECK(!output_record.at_device); |
1493 DCHECK(!output_record.at_client); | 1526 DCHECK(!output_record.at_client); |
1494 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | 1527 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
1495 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 1528 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
1496 DCHECK_EQ(output_record.picture_id, -1); | 1529 DCHECK_EQ(output_record.picture_id, -1); |
1530 DCHECK(output_record.dmabuf_fds.empty()); | |
1497 DCHECK_EQ(output_record.cleared, false); | 1531 DCHECK_EQ(output_record.cleared, false); |
1498 | 1532 |
1499 DCHECK_LE(1u, buffers[i].texture_ids().size()); | 1533 output_record.picture_id = buffers[i].id(); |
1500 EGLImageKHR egl_image = device_->CreateEGLImage( | 1534 output_record.texture_id = buffers[i].texture_ids()[0]; |
1501 egl_display_, gl_context->GetHandle(), buffers[i].texture_ids()[0], | 1535 // This will remain true until ImportBufferForPicture is called, either by |
1502 buffers[i].size(), i, output_format_fourcc_, output_planes_count_); | 1536 // the client, or by ourselves, if we are allocating. |
1503 if (egl_image == EGL_NO_IMAGE_KHR) { | 1537 output_record.at_client = true; |
1504 LOGF(ERROR) << "Could not create EGLImageKHR"; | 1538 if (output_mode_ == Config::OutputMode::ALLOCATE) { |
1505 // Ownership of EGLImages allocated in previous iterations of this loop | 1539 std::vector<base::ScopedFD> dmabuf_fds = |
1506 // has been transferred to output_buffer_map_. After we error-out here | 1540 std::move(device_->GetDmabufsForV4L2Buffer( |
1507 // the destructor will handle their cleanup. | 1541 i, output_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)); |
1508 NOTIFY_ERROR(PLATFORM_FAILURE); | 1542 if (dmabuf_fds.empty()) { |
1509 return; | 1543 NOTIFY_ERROR(PLATFORM_FAILURE); |
1544 return; | |
1545 } | |
1546 | |
1547 auto passed_dmabuf_fds(base::WrapUnique( | |
1548 new std::vector<base::ScopedFD>(std::move(dmabuf_fds)))); | |
1549 ImportBufferForPictureTask(output_record.picture_id, | |
1550 std::move(passed_dmabuf_fds)); | |
1551 } // else we'll get triggered via ImportBufferForPicture() from client. | |
1552 DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id; | |
1553 } | |
1554 | |
1555 if (!StartDevicePoll()) { | |
1556 NOTIFY_ERROR(PLATFORM_FAILURE); | |
1557 return; | |
1558 } | |
1559 | |
1560 // Put us in kIdle to allow further event processing. | |
1561 // ProcessPendingEventsIfNeeded() will put us back into kDecoding after all | |
1562 // other pending events are processed successfully. | |
1563 state_ = kIdle; | |
1564 ProcessPendingEventsIfNeeded(); | |
1565 } | |
1566 | |
1567 void V4L2SliceVideoDecodeAccelerator::CreateEGLImageFor( | |
1568 size_t buffer_index, | |
1569 int32_t picture_buffer_id, | |
1570 std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds, | |
1571 GLuint texture_id, | |
1572 const gfx::Size& size, | |
1573 uint32_t fourcc) { | |
1574 DVLOGF(3) << "index=" << buffer_index; | |
1575 DCHECK(child_task_runner_->BelongsToCurrentThread()); | |
1576 | |
1577 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { | |
1578 DLOG(ERROR) << "GL callbacks required for binding to EGLImages"; | |
1579 NOTIFY_ERROR(INVALID_ARGUMENT); | |
1580 return; | |
1581 } | |
1582 | |
1583 gfx::GLContext* gl_context = get_gl_context_cb_.Run(); | |
1584 if (!gl_context || !make_context_current_cb_.Run()) { | |
1585 DLOG(ERROR) << "No GL context"; | |
1586 NOTIFY_ERROR(PLATFORM_FAILURE); | |
1587 return; | |
1588 } | |
1589 | |
1590 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); | |
1591 | |
1592 EGLImageKHR egl_image = | |
1593 device_->CreateEGLImage(egl_display_, gl_context->GetHandle(), texture_id, | |
1594 size, buffer_index, fourcc, *passed_dmabuf_fds); | |
1595 if (egl_image == EGL_NO_IMAGE_KHR) { | |
1596 LOGF(ERROR) << "Could not create EGLImageKHR," | |
1597 << " index=" << buffer_index << " texture_id=" << texture_id; | |
1598 NOTIFY_ERROR(PLATFORM_FAILURE); | |
1599 return; | |
1600 } | |
1601 | |
1602 decoder_thread_task_runner_->PostTask( | |
1603 FROM_HERE, | |
1604 base::Bind(&V4L2SliceVideoDecodeAccelerator::AssignEGLImage, | |
1605 base::Unretained(this), buffer_index, picture_buffer_id, | |
1606 egl_image, base::Passed(&passed_dmabuf_fds))); | |
1607 } | |
1608 | |
1609 void V4L2SliceVideoDecodeAccelerator::AssignEGLImage( | |
1610 size_t buffer_index, | |
1611 int32_t picture_buffer_id, | |
1612 EGLImageKHR egl_image, | |
1613 std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds) { | |
1614 DVLOGF(3) << "index=" << buffer_index; | |
1615 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | |
1616 | |
1617 // It's possible that while waiting for the EGLImages to be allocated and | |
1618 // assigned, we have already decoded more of the stream and saw another | |
1619 // resolution change. This is a normal situation, in such a case either there | |
1620 // is no output record with this index awaiting an EGLImage to be assigned to | |
1621 // it, or the record is already updated to use a newer PictureBuffer and is | |
1622 // awaiting an EGLImage associated with a different picture_buffer_id. If so, | |
1623 // just discard this image, we will get the one we are waiting for later. | |
1624 if (buffer_index >= output_buffer_map_.size() || | |
1625 output_buffer_map_[buffer_index].picture_id != picture_buffer_id) { | |
1626 DVLOGF(3) << "Picture set already changed, dropping EGLImage"; | |
1627 child_task_runner_->PostTask( | |
1628 FROM_HERE, base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), | |
1629 device_, egl_display_, egl_image)); | |
1630 return; | |
1631 } | |
1632 | |
1633 OutputRecord& output_record = output_buffer_map_[buffer_index]; | |
1634 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
1635 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | |
1636 DCHECK(!output_record.at_client); | |
1637 DCHECK(!output_record.at_device); | |
1638 | |
1639 output_record.egl_image = egl_image; | |
1640 if (output_mode_ == Config::OutputMode::IMPORT) { | |
1641 DCHECK(output_record.dmabuf_fds.empty()); | |
1642 output_record.dmabuf_fds = std::move(*passed_dmabuf_fds); | |
1643 } | |
1644 | |
1645 DCHECK_EQ(std::count(free_output_buffers_.begin(), free_output_buffers_.end(), | |
1646 buffer_index), | |
1647 0); | |
1648 free_output_buffers_.push_back(buffer_index); | |
1649 ScheduleDecodeBufferTaskIfNeeded(); | |
1650 } | |
1651 | |
1652 void V4L2SliceVideoDecodeAccelerator::ImportBufferForPicture( | |
1653 int32_t picture_buffer_id, | |
1654 const std::vector<gfx::GpuMemoryBufferHandle>& gpu_memory_buffer_handles) { | |
1655 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; | |
1656 DCHECK(child_task_runner_->BelongsToCurrentThread()); | |
1657 | |
1658 auto passed_dmabuf_fds(base::WrapUnique(new std::vector<base::ScopedFD>())); | |
1659 for (const auto& handle : gpu_memory_buffer_handles) { | |
1660 int fd = -1; | |
1661 #if defined(USE_OZONE) | |
1662 fd = handle.native_pixmap_handle.fd.fd; | |
1663 #endif | |
1664 DCHECK_NE(fd, -1); | |
1665 passed_dmabuf_fds->push_back(base::ScopedFD(fd)); | |
1666 } | |
1667 | |
1668 if (output_mode_ != Config::OutputMode::IMPORT) { | |
1669 LOGF(ERROR) << "Cannot import in non-import mode"; | |
1670 NOTIFY_ERROR(INVALID_ARGUMENT); | |
1671 return; | |
1672 } | |
1673 | |
1674 decoder_thread_task_runner_->PostTask( | |
1675 FROM_HERE, | |
1676 base::Bind(&V4L2SliceVideoDecodeAccelerator::ImportBufferForPictureTask, | |
1677 base::Unretained(this), picture_buffer_id, | |
1678 base::Passed(&passed_dmabuf_fds))); | |
1679 } | |
1680 | |
1681 void V4L2SliceVideoDecodeAccelerator::ImportBufferForPictureTask( | |
1682 int32_t picture_buffer_id, | |
1683 std::unique_ptr<std::vector<base::ScopedFD>> passed_dmabuf_fds) { | |
1684 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; | |
1685 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | |
1686 | |
1687 const auto iter = | |
1688 std::find_if(output_buffer_map_.begin(), output_buffer_map_.end(), | |
1689 [picture_buffer_id](const OutputRecord& output_record) { | |
1690 return output_record.picture_id == picture_buffer_id; | |
1691 }); | |
1692 if (iter == output_buffer_map_.end()) { | |
1693 LOGF(ERROR) << "Invalid picture_buffer_id=" << picture_buffer_id; | |
1694 NOTIFY_ERROR(INVALID_ARGUMENT); | |
1695 return; | |
1696 } | |
1697 | |
1698 if (!iter->at_client) { | |
1699 LOGF(ERROR) << "Cannot import buffer that not owned by client"; | |
1700 NOTIFY_ERROR(INVALID_ARGUMENT); | |
1701 return; | |
1702 } | |
1703 | |
1704 size_t index = iter - output_buffer_map_.begin(); | |
1705 DCHECK_EQ(std::count(free_output_buffers_.begin(), free_output_buffers_.end(), | |
1706 index), | |
1707 0); | |
1708 | |
1709 DCHECK(!iter->at_device); | |
1710 iter->at_client = false; | |
1711 if (iter->texture_id != 0) { | |
1712 if (iter->egl_image != EGL_NO_IMAGE_KHR) { | |
1713 child_task_runner_->PostTask( | |
1714 FROM_HERE, | |
1715 base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), device_, | |
1716 egl_display_, iter->egl_image)); | |
1510 } | 1717 } |
1511 | 1718 |
1512 output_record.egl_image = egl_image; | 1719 child_task_runner_->PostTask( |
1513 output_record.picture_id = buffers[i].id(); | 1720 FROM_HERE, |
1514 free_output_buffers_.push_back(i); | 1721 base::Bind(&V4L2SliceVideoDecodeAccelerator::CreateEGLImageFor, |
1515 DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id; | 1722 weak_this_, index, picture_buffer_id, |
1516 } | 1723 base::Passed(&passed_dmabuf_fds), iter->texture_id, |
1517 | 1724 coded_size_, output_format_fourcc_)); |
1518 pictures_assigned_.Signal(); | 1725 } else { |
1726 // No need for an EGLImage, start using this buffer now. | |
1727 DCHECK_EQ(output_planes_count_, passed_dmabuf_fds->size()); | |
1728 iter->dmabuf_fds.swap(*passed_dmabuf_fds); | |
1729 free_output_buffers_.push_back(index); | |
1730 ScheduleDecodeBufferTaskIfNeeded(); | |
1731 } | |
1519 } | 1732 } |
1520 | 1733 |
1521 void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( | 1734 void V4L2SliceVideoDecodeAccelerator::ReusePictureBuffer( |
1522 int32_t picture_buffer_id) { | 1735 int32_t picture_buffer_id) { |
1523 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1736 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
1524 DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; | 1737 DVLOGF(4) << "picture_buffer_id=" << picture_buffer_id; |
1525 | 1738 |
1526 if (!make_context_current_cb_.Run()) { | 1739 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref; |
1527 LOGF(ERROR) << "could not make context current"; | 1740 |
1528 NOTIFY_ERROR(PLATFORM_FAILURE); | 1741 if (!make_context_current_cb_.is_null()) { |
1529 return; | 1742 if (!make_context_current_cb_.Run()) { |
1530 } | 1743 LOGF(ERROR) << "could not make context current"; |
1531 | 1744 NOTIFY_ERROR(PLATFORM_FAILURE); |
1532 EGLSyncKHR egl_sync = | 1745 return; |
1533 eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); | 1746 } |
1534 if (egl_sync == EGL_NO_SYNC_KHR) { | 1747 |
1535 LOGF(ERROR) << "eglCreateSyncKHR() failed"; | 1748 EGLSyncKHR egl_sync = |
1536 NOTIFY_ERROR(PLATFORM_FAILURE); | 1749 eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); |
1537 return; | 1750 if (egl_sync == EGL_NO_SYNC_KHR) { |
1538 } | 1751 LOGF(ERROR) << "eglCreateSyncKHR() failed"; |
1539 | 1752 NOTIFY_ERROR(PLATFORM_FAILURE); |
1540 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref( | 1753 return; |
1541 new EGLSyncKHRRef(egl_display_, egl_sync)); | 1754 } |
1755 | |
1756 egl_sync_ref.reset(new EGLSyncKHRRef(egl_display_, egl_sync)); | |
1757 } | |
1758 | |
1542 decoder_thread_task_runner_->PostTask( | 1759 decoder_thread_task_runner_->PostTask( |
1543 FROM_HERE, | 1760 FROM_HERE, |
1544 base::Bind(&V4L2SliceVideoDecodeAccelerator::ReusePictureBufferTask, | 1761 base::Bind(&V4L2SliceVideoDecodeAccelerator::ReusePictureBufferTask, |
1545 base::Unretained(this), picture_buffer_id, | 1762 base::Unretained(this), picture_buffer_id, |
1546 base::Passed(&egl_sync_ref))); | 1763 base::Passed(&egl_sync_ref))); |
1547 } | 1764 } |
1548 | 1765 |
1549 void V4L2SliceVideoDecodeAccelerator::ReusePictureBufferTask( | 1766 void V4L2SliceVideoDecodeAccelerator::ReusePictureBufferTask( |
1550 int32_t picture_buffer_id, | 1767 int32_t picture_buffer_id, |
1551 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref) { | 1768 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()]; | 1785 OutputRecord& output_record = output_buffer_map_[it->second->output_record()]; |
1569 if (output_record.at_device || !output_record.at_client) { | 1786 if (output_record.at_device || !output_record.at_client) { |
1570 DVLOGF(1) << "picture_buffer_id not reusable"; | 1787 DVLOGF(1) << "picture_buffer_id not reusable"; |
1571 NOTIFY_ERROR(INVALID_ARGUMENT); | 1788 NOTIFY_ERROR(INVALID_ARGUMENT); |
1572 return; | 1789 return; |
1573 } | 1790 } |
1574 | 1791 |
1575 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 1792 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
1576 DCHECK(!output_record.at_device); | 1793 DCHECK(!output_record.at_device); |
1577 output_record.at_client = false; | 1794 output_record.at_client = false; |
1578 output_record.egl_sync = egl_sync_ref->egl_sync; | 1795 if (egl_sync_ref) { |
1579 // Take ownership of the EGLSync. | 1796 output_record.egl_sync = egl_sync_ref->egl_sync; |
1580 egl_sync_ref->egl_sync = EGL_NO_SYNC_KHR; | 1797 // Take ownership of the EGLSync. |
1798 egl_sync_ref->egl_sync = EGL_NO_SYNC_KHR; | |
1799 } | |
1800 | |
1581 surfaces_at_display_.erase(it); | 1801 surfaces_at_display_.erase(it); |
1582 } | 1802 } |
1583 | 1803 |
1584 void V4L2SliceVideoDecodeAccelerator::Flush() { | 1804 void V4L2SliceVideoDecodeAccelerator::Flush() { |
1585 DVLOGF(3); | 1805 DVLOGF(3); |
1586 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1806 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
1587 | 1807 |
1588 decoder_thread_task_runner_->PostTask( | 1808 decoder_thread_task_runner_->PostTask( |
1589 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::FlushTask, | 1809 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::FlushTask, |
1590 base::Unretained(this))); | 1810 base::Unretained(this))); |
(...skipping 13 matching lines...) Expand all Loading... | |
1604 } | 1824 } |
1605 | 1825 |
1606 // No more inputs pending, so just finish flushing here. | 1826 // No more inputs pending, so just finish flushing here. |
1607 InitiateFlush(); | 1827 InitiateFlush(); |
1608 } | 1828 } |
1609 | 1829 |
1610 void V4L2SliceVideoDecodeAccelerator::InitiateFlush() { | 1830 void V4L2SliceVideoDecodeAccelerator::InitiateFlush() { |
1611 DVLOGF(3); | 1831 DVLOGF(3); |
1612 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1832 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
1613 | 1833 |
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. | 1834 // 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 | 1835 // However, not all of them may be decoded yet (they would be queued |
1620 // in hardware then). | 1836 // in hardware then). |
1621 if (!decoder_->Flush()) { | 1837 if (!decoder_->Flush()) { |
1622 DVLOGF(1) << "Failed flushing the decoder."; | 1838 DVLOGF(1) << "Failed flushing the decoder."; |
1623 NOTIFY_ERROR(PLATFORM_FAILURE); | 1839 NOTIFY_ERROR(PLATFORM_FAILURE); |
1624 return; | 1840 return; |
1625 } | 1841 } |
1626 | 1842 |
1627 // Put the decoder in an idle state, ready to resume. | 1843 // Put the decoder in an idle state, ready to resume. |
1628 decoder_->Reset(); | 1844 decoder_->Reset(); |
1629 | 1845 |
1846 DCHECK(!decoder_flushing_); | |
1630 decoder_flushing_ = true; | 1847 decoder_flushing_ = true; |
1631 | 1848 NewEventPending(); |
1632 decoder_thread_task_runner_->PostTask( | |
1633 FROM_HERE, | |
1634 base::Bind(&V4L2SliceVideoDecodeAccelerator::FinishFlushIfNeeded, | |
1635 base::Unretained(this))); | |
1636 } | 1849 } |
1637 | 1850 |
1638 void V4L2SliceVideoDecodeAccelerator::FinishFlushIfNeeded() { | 1851 bool V4L2SliceVideoDecodeAccelerator::FinishFlush() { |
1639 DVLOGF(3); | 1852 DVLOGF(3); |
1640 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1853 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
1641 | 1854 |
1642 if (!decoder_flushing_ || !surfaces_at_device_.empty()) | 1855 if (!decoder_flushing_) |
1643 return; | 1856 return true; |
1857 | |
1858 if (!surfaces_at_device_.empty()) | |
1859 return false; | |
1644 | 1860 |
1645 DCHECK_EQ(state_, kIdle); | 1861 DCHECK_EQ(state_, kIdle); |
1646 | 1862 |
1647 // At this point, all remaining surfaces are decoded and dequeued, and since | 1863 // At this point, all remaining surfaces are decoded and dequeued, and since |
1648 // we have already scheduled output for them in InitiateFlush(), their | 1864 // we have already scheduled output for them in InitiateFlush(), their |
1649 // respective PictureReady calls have been posted (or they have been queued on | 1865 // respective PictureReady calls have been posted (or they have been queued on |
1650 // pending_picture_ready_). So at this time, once we SendPictureReady(), | 1866 // pending_picture_ready_). So at this time, once we SendPictureReady(), |
1651 // we will have all remaining PictureReady() posted to the client and we | 1867 // we will have all remaining PictureReady() posted to the client and we |
1652 // can post NotifyFlushDone(). | 1868 // can post NotifyFlushDone(). |
1653 DCHECK(decoder_display_queue_.empty()); | 1869 DCHECK(decoder_display_queue_.empty()); |
1654 | 1870 |
1655 // Decoder should have already returned all surfaces and all surfaces are | 1871 // Decoder should have already returned all surfaces and all surfaces are |
1656 // out of hardware. There can be no other owners of input buffers. | 1872 // out of hardware. There can be no other owners of input buffers. |
1657 DCHECK_EQ(free_input_buffers_.size(), input_buffer_map_.size()); | 1873 DCHECK_EQ(free_input_buffers_.size(), input_buffer_map_.size()); |
1658 | 1874 |
1659 SendPictureReady(); | 1875 SendPictureReady(); |
1660 | 1876 |
1877 decoder_flushing_ = false; | |
1878 DVLOGF(3) << "Flush finished"; | |
1879 | |
1661 child_task_runner_->PostTask(FROM_HERE, | 1880 child_task_runner_->PostTask(FROM_HERE, |
1662 base::Bind(&Client::NotifyFlushDone, client_)); | 1881 base::Bind(&Client::NotifyFlushDone, client_)); |
1663 | 1882 |
1664 decoder_flushing_ = false; | 1883 return true; |
1665 | |
1666 DVLOGF(3) << "Flush finished"; | |
1667 state_ = kDecoding; | |
1668 ScheduleDecodeBufferTaskIfNeeded(); | |
1669 } | 1884 } |
1670 | 1885 |
1671 void V4L2SliceVideoDecodeAccelerator::Reset() { | 1886 void V4L2SliceVideoDecodeAccelerator::Reset() { |
1672 DVLOGF(3); | 1887 DVLOGF(3); |
1673 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 1888 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
1674 | 1889 |
1675 decoder_thread_task_runner_->PostTask( | 1890 decoder_thread_task_runner_->PostTask( |
1676 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::ResetTask, | 1891 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::ResetTask, |
1677 base::Unretained(this))); | 1892 base::Unretained(this))); |
1678 } | 1893 } |
1679 | 1894 |
1680 void V4L2SliceVideoDecodeAccelerator::ResetTask() { | 1895 void V4L2SliceVideoDecodeAccelerator::ResetTask() { |
1681 DVLOGF(3); | 1896 DVLOGF(3); |
1682 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1897 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
1683 | 1898 |
1684 if (decoder_resetting_) { | 1899 if (decoder_resetting_) { |
1685 // This is a bug in the client, multiple Reset()s before NotifyResetDone() | 1900 // This is a bug in the client, multiple Reset()s before NotifyResetDone() |
1686 // are not allowed. | 1901 // are not allowed. |
1687 NOTREACHED() << "Client should not be requesting multiple Reset()s"; | 1902 NOTREACHED() << "Client should not be requesting multiple Reset()s"; |
1688 return; | 1903 return; |
1689 } | 1904 } |
1690 | 1905 |
1691 DCHECK_EQ(state_, kDecoding); | |
1692 state_ = kIdle; | |
1693 | |
1694 // Put the decoder in an idle state, ready to resume. | 1906 // Put the decoder in an idle state, ready to resume. |
1695 decoder_->Reset(); | 1907 decoder_->Reset(); |
1696 | 1908 |
1697 decoder_resetting_ = true; | |
1698 | |
1699 // Drop all remaining inputs. | 1909 // Drop all remaining inputs. |
1700 decoder_current_bitstream_buffer_.reset(); | 1910 decoder_current_bitstream_buffer_.reset(); |
1701 while (!decoder_input_queue_.empty()) | 1911 while (!decoder_input_queue_.empty()) |
1702 decoder_input_queue_.pop(); | 1912 decoder_input_queue_.pop(); |
1703 | 1913 |
1704 FinishResetIfNeeded(); | 1914 decoder_resetting_ = true; |
1915 NewEventPending(); | |
1705 } | 1916 } |
1706 | 1917 |
1707 void V4L2SliceVideoDecodeAccelerator::FinishResetIfNeeded() { | 1918 bool V4L2SliceVideoDecodeAccelerator::FinishReset() { |
1708 DVLOGF(3); | 1919 DVLOGF(3); |
1709 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 1920 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
1710 | 1921 |
1711 if (!decoder_resetting_ || !surfaces_at_device_.empty()) | 1922 if (!decoder_resetting_) |
1712 return; | 1923 return true; |
1924 | |
1925 if (!surfaces_at_device_.empty()) | |
1926 return false; | |
1713 | 1927 |
1714 DCHECK_EQ(state_, kIdle); | 1928 DCHECK_EQ(state_, kIdle); |
1715 DCHECK(!decoder_flushing_); | 1929 DCHECK(!decoder_flushing_); |
1716 SendPictureReady(); | 1930 SendPictureReady(); |
1717 | 1931 |
1718 // Drop any pending outputs. | 1932 // Drop any pending outputs. |
1719 while (!decoder_display_queue_.empty()) | 1933 while (!decoder_display_queue_.empty()) |
1720 decoder_display_queue_.pop(); | 1934 decoder_display_queue_.pop(); |
1721 | 1935 |
1722 // At this point we can have no input buffers in the decoder, because we | 1936 // 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 | 1937 // 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 - | 1938 // 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 | 1939 // 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 | 1940 // to surfaces. Since there can be no other owners of input buffers, we can |
1727 // simply mark them all as available. | 1941 // simply mark them all as available. |
1728 DCHECK_EQ(input_buffer_queued_count_, 0); | 1942 DCHECK_EQ(input_buffer_queued_count_, 0); |
1729 free_input_buffers_.clear(); | 1943 free_input_buffers_.clear(); |
1730 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { | 1944 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { |
1731 DCHECK(!input_buffer_map_[i].at_device); | 1945 DCHECK(!input_buffer_map_[i].at_device); |
1732 ReuseInputBuffer(i); | 1946 ReuseInputBuffer(i); |
1733 } | 1947 } |
1734 | 1948 |
1735 decoder_resetting_ = false; | 1949 decoder_resetting_ = false; |
1950 DVLOGF(3) << "Reset finished"; | |
1736 | 1951 |
1737 child_task_runner_->PostTask(FROM_HERE, | 1952 child_task_runner_->PostTask(FROM_HERE, |
1738 base::Bind(&Client::NotifyResetDone, client_)); | 1953 base::Bind(&Client::NotifyResetDone, client_)); |
1739 | 1954 |
1740 DVLOGF(3) << "Reset finished"; | 1955 return true; |
1741 | |
1742 state_ = kDecoding; | |
1743 ScheduleDecodeBufferTaskIfNeeded(); | |
1744 } | 1956 } |
1745 | 1957 |
1746 void V4L2SliceVideoDecodeAccelerator::SetErrorState(Error error) { | 1958 void V4L2SliceVideoDecodeAccelerator::SetErrorState(Error error) { |
1747 // We can touch decoder_state_ only if this is the decoder thread or the | 1959 // We can touch decoder_state_ only if this is the decoder thread or the |
1748 // decoder thread isn't running. | 1960 // decoder thread isn't running. |
1749 if (decoder_thread_.IsRunning() && | 1961 if (decoder_thread_.IsRunning() && |
1750 !decoder_thread_task_runner_->BelongsToCurrentThread()) { | 1962 !decoder_thread_task_runner_->BelongsToCurrentThread()) { |
1751 decoder_thread_task_runner_->PostTask( | 1963 decoder_thread_task_runner_->PostTask( |
1752 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::SetErrorState, | 1964 FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::SetErrorState, |
1753 base::Unretained(this), error)); | 1965 base::Unretained(this), error)); |
(...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2453 OutputRecord& output_record = | 2665 OutputRecord& output_record = |
2454 output_buffer_map_[dec_surface->output_record()]; | 2666 output_buffer_map_[dec_surface->output_record()]; |
2455 | 2667 |
2456 bool inserted = | 2668 bool inserted = |
2457 surfaces_at_display_.insert(std::make_pair(output_record.picture_id, | 2669 surfaces_at_display_.insert(std::make_pair(output_record.picture_id, |
2458 dec_surface)).second; | 2670 dec_surface)).second; |
2459 DCHECK(inserted); | 2671 DCHECK(inserted); |
2460 | 2672 |
2461 DCHECK(!output_record.at_client); | 2673 DCHECK(!output_record.at_client); |
2462 DCHECK(!output_record.at_device); | 2674 DCHECK(!output_record.at_device); |
2463 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
2464 DCHECK_NE(output_record.picture_id, -1); | 2675 DCHECK_NE(output_record.picture_id, -1); |
2465 output_record.at_client = true; | 2676 output_record.at_client = true; |
2466 | 2677 |
2467 // TODO(posciak): Use visible size from decoder here instead | 2678 // TODO(posciak): Use visible size from decoder here instead |
2468 // (crbug.com/402760). Passing (0, 0) results in the client using the | 2679 // (crbug.com/402760). Passing (0, 0) results in the client using the |
2469 // visible size extracted from the container instead. | 2680 // visible size extracted from the container instead. |
2470 media::Picture picture(output_record.picture_id, dec_surface->bitstream_id(), | 2681 media::Picture picture(output_record.picture_id, dec_surface->bitstream_id(), |
2471 gfx::Rect(0, 0), false); | 2682 gfx::Rect(0, 0), false); |
2472 DVLOGF(3) << dec_surface->ToString() | 2683 DVLOGF(3) << dec_surface->ToString() |
2473 << ", bitstream_id: " << picture.bitstream_buffer_id() | 2684 << ", bitstream_id: " << picture.bitstream_buffer_id() |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2559 } | 2770 } |
2560 | 2771 |
2561 bool V4L2SliceVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( | 2772 bool V4L2SliceVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread( |
2562 const base::WeakPtr<Client>& decode_client, | 2773 const base::WeakPtr<Client>& decode_client, |
2563 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { | 2774 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) { |
2564 decode_client_ = decode_client_; | 2775 decode_client_ = decode_client_; |
2565 decode_task_runner_ = decode_task_runner; | 2776 decode_task_runner_ = decode_task_runner; |
2566 return true; | 2777 return true; |
2567 } | 2778 } |
2568 | 2779 |
2780 media::VideoPixelFormat V4L2SliceVideoDecodeAccelerator::GetOutputFormat() | |
2781 const { | |
2782 return V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_); | |
2783 } | |
2784 | |
2569 // static | 2785 // static |
2570 media::VideoDecodeAccelerator::SupportedProfiles | 2786 media::VideoDecodeAccelerator::SupportedProfiles |
2571 V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles() { | 2787 V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles() { |
2572 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); | 2788 scoped_refptr<V4L2Device> device = V4L2Device::Create(V4L2Device::kDecoder); |
2573 if (!device) | 2789 if (!device) |
2574 return SupportedProfiles(); | 2790 return SupportedProfiles(); |
2575 | 2791 |
2576 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), | 2792 return device->GetSupportedDecodeProfiles(arraysize(supported_input_fourccs_), |
2577 supported_input_fourccs_); | 2793 supported_input_fourccs_); |
2578 } | 2794 } |
2579 | 2795 |
2580 } // namespace content | 2796 } // namespace content |
OLD | NEW |