| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <dlfcn.h> | 5 #include <dlfcn.h> |
| 6 #include <errno.h> | 6 #include <errno.h> |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <linux/videodev2.h> | 8 #include <linux/videodev2.h> |
| 9 #include <poll.h> | 9 #include <poll.h> |
| 10 #include <sys/eventfd.h> | 10 #include <sys/eventfd.h> |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 std::vector<PictureBufferRef> picture_buffers; | 97 std::vector<PictureBufferRef> picture_buffers; |
| 98 }; | 98 }; |
| 99 | 99 |
| 100 struct ExynosVideoDecodeAccelerator::EGLSyncKHRRef { | 100 struct ExynosVideoDecodeAccelerator::EGLSyncKHRRef { |
| 101 EGLSyncKHRRef(EGLDisplay egl_display, EGLSyncKHR egl_sync); | 101 EGLSyncKHRRef(EGLDisplay egl_display, EGLSyncKHR egl_sync); |
| 102 ~EGLSyncKHRRef(); | 102 ~EGLSyncKHRRef(); |
| 103 EGLDisplay const egl_display; | 103 EGLDisplay const egl_display; |
| 104 EGLSyncKHR egl_sync; | 104 EGLSyncKHR egl_sync; |
| 105 }; | 105 }; |
| 106 | 106 |
| 107 struct ExynosVideoDecodeAccelerator::PictureRecord { |
| 108 PictureRecord(bool cleared, const media::Picture& picture); |
| 109 ~PictureRecord(); |
| 110 bool cleared; // Whether the texture is cleared and safe to render from. |
| 111 media::Picture picture; // The decoded picture. |
| 112 }; |
| 113 |
| 107 ExynosVideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef( | 114 ExynosVideoDecodeAccelerator::BitstreamBufferRef::BitstreamBufferRef( |
| 108 base::WeakPtr<Client>& client, | 115 base::WeakPtr<Client>& client, |
| 109 scoped_refptr<base::MessageLoopProxy>& client_message_loop_proxy, | 116 scoped_refptr<base::MessageLoopProxy>& client_message_loop_proxy, |
| 110 base::SharedMemory* shm, size_t size, int32 input_id) | 117 base::SharedMemory* shm, size_t size, int32 input_id) |
| 111 : client(client), | 118 : client(client), |
| 112 client_message_loop_proxy(client_message_loop_proxy), | 119 client_message_loop_proxy(client_message_loop_proxy), |
| 113 shm(shm), | 120 shm(shm), |
| 114 size(size), | 121 size(size), |
| 115 bytes_used(0), | 122 bytes_used(0), |
| 116 input_id(input_id) { | 123 input_id(input_id) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 | 195 |
| 189 ExynosVideoDecodeAccelerator::GscInputRecord::~GscInputRecord() { | 196 ExynosVideoDecodeAccelerator::GscInputRecord::~GscInputRecord() { |
| 190 } | 197 } |
| 191 | 198 |
| 192 ExynosVideoDecodeAccelerator::GscOutputRecord::GscOutputRecord() | 199 ExynosVideoDecodeAccelerator::GscOutputRecord::GscOutputRecord() |
| 193 : at_device(false), | 200 : at_device(false), |
| 194 at_client(false), | 201 at_client(false), |
| 195 fd(-1), | 202 fd(-1), |
| 196 egl_image(EGL_NO_IMAGE_KHR), | 203 egl_image(EGL_NO_IMAGE_KHR), |
| 197 egl_sync(EGL_NO_SYNC_KHR), | 204 egl_sync(EGL_NO_SYNC_KHR), |
| 198 picture_id(-1) { | 205 picture_id(-1), |
| 199 } | 206 cleared(false) {} |
| 200 | 207 |
| 201 ExynosVideoDecodeAccelerator::GscOutputRecord::~GscOutputRecord() { | 208 ExynosVideoDecodeAccelerator::GscOutputRecord::~GscOutputRecord() { |
| 202 } | 209 } |
| 203 | 210 |
| 211 ExynosVideoDecodeAccelerator::PictureRecord::PictureRecord( |
| 212 bool cleared, |
| 213 const media::Picture& picture) |
| 214 : cleared(cleared), picture(picture) {} |
| 215 |
| 216 ExynosVideoDecodeAccelerator::PictureRecord::~PictureRecord() {} |
| 217 |
| 204 ExynosVideoDecodeAccelerator::ExynosVideoDecodeAccelerator( | 218 ExynosVideoDecodeAccelerator::ExynosVideoDecodeAccelerator( |
| 205 EGLDisplay egl_display, | 219 EGLDisplay egl_display, |
| 206 EGLContext egl_context, | 220 EGLContext egl_context, |
| 207 Client* client, | 221 Client* client, |
| 208 const base::WeakPtr<Client>& io_client, | 222 const base::WeakPtr<Client>& io_client, |
| 209 const base::Callback<bool(void)>& make_context_current, | 223 const base::Callback<bool(void)>& make_context_current, |
| 210 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy) | 224 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy) |
| 211 : child_message_loop_proxy_(base::MessageLoopProxy::current()), | 225 : child_message_loop_proxy_(base::MessageLoopProxy::current()), |
| 212 io_message_loop_proxy_(io_message_loop_proxy), | 226 io_message_loop_proxy_(io_message_loop_proxy), |
| 213 weak_this_(base::AsWeakPtr(this)), | 227 weak_this_(base::AsWeakPtr(this)), |
| (...skipping 15 matching lines...) Expand all Loading... |
| 229 mfc_input_buffer_queued_count_(0), | 243 mfc_input_buffer_queued_count_(0), |
| 230 mfc_output_streamon_(false), | 244 mfc_output_streamon_(false), |
| 231 mfc_output_buffer_queued_count_(0), | 245 mfc_output_buffer_queued_count_(0), |
| 232 mfc_output_buffer_pixelformat_(0), | 246 mfc_output_buffer_pixelformat_(0), |
| 233 mfc_output_dpb_size_(0), | 247 mfc_output_dpb_size_(0), |
| 234 gsc_fd_(-1), | 248 gsc_fd_(-1), |
| 235 gsc_input_streamon_(false), | 249 gsc_input_streamon_(false), |
| 236 gsc_input_buffer_queued_count_(0), | 250 gsc_input_buffer_queued_count_(0), |
| 237 gsc_output_streamon_(false), | 251 gsc_output_streamon_(false), |
| 238 gsc_output_buffer_queued_count_(0), | 252 gsc_output_buffer_queued_count_(0), |
| 253 picture_clearing_count_(0), |
| 239 device_poll_thread_("ExynosDevicePollThread"), | 254 device_poll_thread_("ExynosDevicePollThread"), |
| 240 device_poll_interrupt_fd_(-1), | 255 device_poll_interrupt_fd_(-1), |
| 241 make_context_current_(make_context_current), | 256 make_context_current_(make_context_current), |
| 242 egl_display_(egl_display), | 257 egl_display_(egl_display), |
| 243 egl_context_(egl_context), | 258 egl_context_(egl_context), |
| 244 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN) {} | 259 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN) {} |
| 245 | 260 |
| 246 ExynosVideoDecodeAccelerator::~ExynosVideoDecodeAccelerator() { | 261 ExynosVideoDecodeAccelerator::~ExynosVideoDecodeAccelerator() { |
| 247 DCHECK(!decoder_thread_.IsRunning()); | 262 DCHECK(!decoder_thread_.IsRunning()); |
| 248 DCHECK(!device_poll_thread_.IsRunning()); | 263 DCHECK(!device_poll_thread_.IsRunning()); |
| (...skipping 796 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1045 } | 1060 } |
| 1046 | 1061 |
| 1047 DCHECK_EQ(pic_buffers->picture_buffers.size(), gsc_output_buffer_map_.size()); | 1062 DCHECK_EQ(pic_buffers->picture_buffers.size(), gsc_output_buffer_map_.size()); |
| 1048 for (size_t i = 0; i < gsc_output_buffer_map_.size(); ++i) { | 1063 for (size_t i = 0; i < gsc_output_buffer_map_.size(); ++i) { |
| 1049 // We should be blank right now. | 1064 // We should be blank right now. |
| 1050 GscOutputRecord& output_record = gsc_output_buffer_map_[i]; | 1065 GscOutputRecord& output_record = gsc_output_buffer_map_[i]; |
| 1051 DCHECK_EQ(output_record.fd, -1); | 1066 DCHECK_EQ(output_record.fd, -1); |
| 1052 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | 1067 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
| 1053 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 1068 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
| 1054 DCHECK_EQ(output_record.picture_id, -1); | 1069 DCHECK_EQ(output_record.picture_id, -1); |
| 1070 DCHECK_EQ(output_record.cleared, false); |
| 1055 PictureBufferArrayRef::PictureBufferRef& buffer = | 1071 PictureBufferArrayRef::PictureBufferRef& buffer = |
| 1056 pic_buffers->picture_buffers[i]; | 1072 pic_buffers->picture_buffers[i]; |
| 1057 output_record.fd = buffer.egl_image_fd; | 1073 output_record.fd = buffer.egl_image_fd; |
| 1058 output_record.egl_image = buffer.egl_image; | 1074 output_record.egl_image = buffer.egl_image; |
| 1059 output_record.picture_id = buffer.client_id; | 1075 output_record.picture_id = buffer.client_id; |
| 1060 | 1076 |
| 1061 // Take ownership of the EGLImage and fd. | 1077 // Take ownership of the EGLImage and fd. |
| 1062 buffer.egl_image = EGL_NO_IMAGE_KHR; | 1078 buffer.egl_image = EGL_NO_IMAGE_KHR; |
| 1063 buffer.egl_image_fd = -1; | 1079 buffer.egl_image_fd = -1; |
| 1064 // And add this buffer to the free list. | 1080 // And add this buffer to the free list. |
| (...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1408 } | 1424 } |
| 1409 GscOutputRecord& output_record = gsc_output_buffer_map_[dqbuf.index]; | 1425 GscOutputRecord& output_record = gsc_output_buffer_map_[dqbuf.index]; |
| 1410 DCHECK(output_record.at_device); | 1426 DCHECK(output_record.at_device); |
| 1411 DCHECK(!output_record.at_client); | 1427 DCHECK(!output_record.at_client); |
| 1412 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 1428 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
| 1413 output_record.at_device = false; | 1429 output_record.at_device = false; |
| 1414 output_record.at_client = true; | 1430 output_record.at_client = true; |
| 1415 gsc_output_buffer_queued_count_--; | 1431 gsc_output_buffer_queued_count_--; |
| 1416 DVLOG(3) << "DequeueGsc(): returning input_id=" << dqbuf.timestamp.tv_sec | 1432 DVLOG(3) << "DequeueGsc(): returning input_id=" << dqbuf.timestamp.tv_sec |
| 1417 << " as picture_id=" << output_record.picture_id; | 1433 << " as picture_id=" << output_record.picture_id; |
| 1418 io_message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 1434 const media::Picture& picture = |
| 1419 &Client::PictureReady, io_client_, media::Picture( | 1435 media::Picture(output_record.picture_id, dqbuf.timestamp.tv_sec); |
| 1420 output_record.picture_id, dqbuf.timestamp.tv_sec))); | 1436 pending_picture_ready_.push(PictureRecord(output_record.cleared, picture)); |
| 1437 SendPictureReady(); |
| 1438 output_record.cleared = true; |
| 1421 decoder_frames_at_client_++; | 1439 decoder_frames_at_client_++; |
| 1422 } | 1440 } |
| 1423 | 1441 |
| 1424 NotifyFlushDoneIfNeeded(); | 1442 NotifyFlushDoneIfNeeded(); |
| 1425 } | 1443 } |
| 1426 | 1444 |
| 1427 bool ExynosVideoDecodeAccelerator::EnqueueMfcInputRecord() { | 1445 bool ExynosVideoDecodeAccelerator::EnqueueMfcInputRecord() { |
| 1428 DVLOG(3) << "EnqueueMfcInputRecord()"; | 1446 DVLOG(3) << "EnqueueMfcInputRecord()"; |
| 1429 DCHECK(!mfc_input_ready_queue_.empty()); | 1447 DCHECK(!mfc_input_ready_queue_.empty()); |
| 1430 | 1448 |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1622 } | 1640 } |
| 1623 | 1641 |
| 1624 // We don't support stacked flushing. | 1642 // We don't support stacked flushing. |
| 1625 DCHECK(!decoder_flushing_); | 1643 DCHECK(!decoder_flushing_); |
| 1626 | 1644 |
| 1627 // Queue up an empty buffer -- this triggers the flush. | 1645 // Queue up an empty buffer -- this triggers the flush. |
| 1628 decoder_input_queue_.push_back(linked_ptr<BitstreamBufferRef>( | 1646 decoder_input_queue_.push_back(linked_ptr<BitstreamBufferRef>( |
| 1629 new BitstreamBufferRef(io_client_, io_message_loop_proxy_, NULL, 0, | 1647 new BitstreamBufferRef(io_client_, io_message_loop_proxy_, NULL, 0, |
| 1630 kFlushBufferId))); | 1648 kFlushBufferId))); |
| 1631 decoder_flushing_ = true; | 1649 decoder_flushing_ = true; |
| 1650 SendPictureReady(); // Send all pending PictureReady. |
| 1632 | 1651 |
| 1633 ScheduleDecodeBufferTaskIfNeeded(); | 1652 ScheduleDecodeBufferTaskIfNeeded(); |
| 1634 } | 1653 } |
| 1635 | 1654 |
| 1636 void ExynosVideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { | 1655 void ExynosVideoDecodeAccelerator::NotifyFlushDoneIfNeeded() { |
| 1637 if (!decoder_flushing_) | 1656 if (!decoder_flushing_) |
| 1638 return; | 1657 return; |
| 1639 | 1658 |
| 1640 // Pipeline is empty when: | 1659 // Pipeline is empty when: |
| 1641 // * Decoder input queue is empty of non-delayed buffers. | 1660 // * Decoder input queue is empty of non-delayed buffers. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1715 | 1734 |
| 1716 decoder_current_input_buffer_ = -1; | 1735 decoder_current_input_buffer_ = -1; |
| 1717 | 1736 |
| 1718 // If we were flushing, we'll never return any more BitstreamBuffers or | 1737 // If we were flushing, we'll never return any more BitstreamBuffers or |
| 1719 // PictureBuffers; they have all been dropped and returned by now. | 1738 // PictureBuffers; they have all been dropped and returned by now. |
| 1720 NotifyFlushDoneIfNeeded(); | 1739 NotifyFlushDoneIfNeeded(); |
| 1721 | 1740 |
| 1722 // Mark that we're resetting, then enqueue a ResetDoneTask(). All intervening | 1741 // Mark that we're resetting, then enqueue a ResetDoneTask(). All intervening |
| 1723 // jobs will early-out in the kResetting state. | 1742 // jobs will early-out in the kResetting state. |
| 1724 decoder_state_ = kResetting; | 1743 decoder_state_ = kResetting; |
| 1744 SendPictureReady(); // Send all pending PictureReady. |
| 1725 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 1745 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 1726 &ExynosVideoDecodeAccelerator::ResetDoneTask, base::Unretained(this))); | 1746 &ExynosVideoDecodeAccelerator::ResetDoneTask, base::Unretained(this))); |
| 1727 } | 1747 } |
| 1728 | 1748 |
| 1729 void ExynosVideoDecodeAccelerator::ResetDoneTask() { | 1749 void ExynosVideoDecodeAccelerator::ResetDoneTask() { |
| 1730 DVLOG(3) << "ResetDoneTask()"; | 1750 DVLOG(3) << "ResetDoneTask()"; |
| 1731 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1751 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1732 TRACE_EVENT0("Video Decoder", "EVDA::ResetDoneTask"); | 1752 TRACE_EVENT0("Video Decoder", "EVDA::ResetDoneTask"); |
| 1733 | 1753 |
| 1734 if (decoder_state_ == kError) { | 1754 if (decoder_state_ == kError) { |
| (...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2443 DestroyGscInputBuffers(); | 2463 DestroyGscInputBuffers(); |
| 2444 DestroyGscOutputBuffers(); | 2464 DestroyGscOutputBuffers(); |
| 2445 DestroyMfcOutputBuffers(); | 2465 DestroyMfcOutputBuffers(); |
| 2446 | 2466 |
| 2447 // Finish resolution change on decoder thread. | 2467 // Finish resolution change on decoder thread. |
| 2448 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 2468 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 2449 &ExynosVideoDecodeAccelerator::FinishResolutionChange, | 2469 &ExynosVideoDecodeAccelerator::FinishResolutionChange, |
| 2450 base::Unretained(this))); | 2470 base::Unretained(this))); |
| 2451 } | 2471 } |
| 2452 | 2472 |
| 2473 void ExynosVideoDecodeAccelerator::SendPictureReady() { |
| 2474 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 2475 bool resetting_or_flushing = |
| 2476 (decoder_state_ == kResetting || decoder_flushing_); |
| 2477 while (pending_picture_ready_.size() > 0) { |
| 2478 bool cleared = pending_picture_ready_.front().cleared; |
| 2479 const media::Picture& picture = pending_picture_ready_.front().picture; |
| 2480 if (cleared && picture_clearing_count_ == 0) { |
| 2481 // This picture is cleared. Post it to IO thread to reduce latency. This |
| 2482 // should be the case after all pictures are cleared at the beginning. |
| 2483 io_message_loop_proxy_->PostTask( |
| 2484 FROM_HERE, base::Bind(&Client::PictureReady, io_client_, picture)); |
| 2485 pending_picture_ready_.pop(); |
| 2486 } else if (!cleared || resetting_or_flushing) { |
| 2487 DVLOG(3) << "SendPictureReady()" |
| 2488 << ". cleared=" << pending_picture_ready_.front().cleared |
| 2489 << ", decoder_state_=" << decoder_state_ |
| 2490 << ", decoder_flushing_=" << decoder_flushing_ |
| 2491 << ", picture_clearing_count_=" << picture_clearing_count_; |
| 2492 // If the picture is not cleared, post it to the child thread because it |
| 2493 // has to be cleared in the child thread. A picture only needs to be |
| 2494 // cleared once. If the decoder is resetting or flushing, send all |
| 2495 // pictures to ensure PictureReady arrive before reset or flush done. |
| 2496 child_message_loop_proxy_->PostTaskAndReply( |
| 2497 FROM_HERE, |
| 2498 base::Bind(&Client::PictureReady, client_, picture), |
| 2499 // Unretained is safe. If Client::PictureReady gets to run, |this| is |
| 2500 // alive. Destroy() will wait the decode thread to finish. |
| 2501 base::Bind(&ExynosVideoDecodeAccelerator::PictureCleared, |
| 2502 base::Unretained(this))); |
| 2503 picture_clearing_count_++; |
| 2504 pending_picture_ready_.pop(); |
| 2505 } else { |
| 2506 // This picture is cleared. But some pictures are about to be cleared on |
| 2507 // the child thread. To preserve the order, do not send this until those |
| 2508 // pictures are cleared. |
| 2509 break; |
| 2510 } |
| 2511 } |
| 2512 } |
| 2513 |
| 2514 void ExynosVideoDecodeAccelerator::PictureCleared() { |
| 2515 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; |
| 2516 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 2517 DCHECK_GT(picture_clearing_count_, 0); |
| 2518 picture_clearing_count_--; |
| 2519 SendPictureReady(); |
| 2520 } |
| 2521 |
| 2453 } // namespace content | 2522 } // namespace content |
| OLD | NEW |