| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/gpu/v4l2_video_decode_accelerator.h" | 5 #include "media/gpu/v4l2_video_decode_accelerator.h" |
| 6 | 6 |
| 7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
| 8 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <fcntl.h> | 9 #include <fcntl.h> |
| 10 #include <linux/videodev2.h> | 10 #include <linux/videodev2.h> |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 egl_image_format_fourcc_(0), | 179 egl_image_format_fourcc_(0), |
| 180 egl_image_planes_count_(0), | 180 egl_image_planes_count_(0), |
| 181 weak_this_factory_(this) { | 181 weak_this_factory_(this) { |
| 182 weak_this_ = weak_this_factory_.GetWeakPtr(); | 182 weak_this_ = weak_this_factory_.GetWeakPtr(); |
| 183 } | 183 } |
| 184 | 184 |
| 185 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { | 185 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { |
| 186 DCHECK(!decoder_thread_.IsRunning()); | 186 DCHECK(!decoder_thread_.IsRunning()); |
| 187 DCHECK(!device_poll_thread_.IsRunning()); | 187 DCHECK(!device_poll_thread_.IsRunning()); |
| 188 | 188 |
| 189 DestroyInputBuffers(); | |
| 190 DestroyOutputBuffers(); | |
| 191 | |
| 192 // These maps have members that should be manually destroyed, e.g. file | 189 // These maps have members that should be manually destroyed, e.g. file |
| 193 // descriptors, mmap() segments, etc. | 190 // descriptors, mmap() segments, etc. |
| 194 DCHECK(input_buffer_map_.empty()); | 191 DCHECK(input_buffer_map_.empty()); |
| 195 DCHECK(output_buffer_map_.empty()); | 192 DCHECK(output_buffer_map_.empty()); |
| 196 } | 193 } |
| 197 | 194 |
| 198 bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, | 195 bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, |
| 199 Client* client) { | 196 Client* client) { |
| 200 DVLOGF(3) << "profile: " << config.profile; | 197 DVLOGF(3) << "profile: " << config.profile; |
| 201 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 198 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 } | 422 } |
| 426 | 423 |
| 427 EGLImageKHR egl_image = egl_image_device_->CreateEGLImage( | 424 EGLImageKHR egl_image = egl_image_device_->CreateEGLImage( |
| 428 egl_display_, gl_context->GetHandle(), buffers[i].texture_ids()[0], | 425 egl_display_, gl_context->GetHandle(), buffers[i].texture_ids()[0], |
| 429 buffers[i].size(), i, egl_image_format_fourcc_, dmabuf_fds); | 426 buffers[i].size(), i, egl_image_format_fourcc_, dmabuf_fds); |
| 430 if (egl_image == EGL_NO_IMAGE_KHR) { | 427 if (egl_image == EGL_NO_IMAGE_KHR) { |
| 431 LOGF(ERROR) << "could not create EGLImageKHR," | 428 LOGF(ERROR) << "could not create EGLImageKHR," |
| 432 << " index=" << i | 429 << " index=" << i |
| 433 << " texture_id=" << buffers[i].texture_ids()[0]; | 430 << " texture_id=" << buffers[i].texture_ids()[0]; |
| 434 for (EGLImageKHR image : egl_images) { | 431 for (EGLImageKHR image : egl_images) { |
| 435 if (egl_image_device_->DestroyEGLImage(egl_display_, image) != EGL_TRUE) | 432 egl_image_device_->DestroyEGLImage(egl_display_, image); |
| 436 DVLOGF(1) << "DestroyEGLImage failed."; | |
| 437 } | 433 } |
| 438 NOTIFY_ERROR(PLATFORM_FAILURE); | 434 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 439 return; | 435 return; |
| 440 } | 436 } |
| 441 egl_images.push_back(egl_image); | 437 egl_images.push_back(egl_image); |
| 442 } | 438 } |
| 443 | 439 |
| 444 decoder_thread_.task_runner()->PostTask( | 440 decoder_thread_.task_runner()->PostTask( |
| 445 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::AssignEGLImages, | 441 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::AssignEGLImages, |
| 446 base::Unretained(this), buffers, egl_images)); | 442 base::Unretained(this), buffers, egl_images)); |
| (...skipping 1122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1569 decoder_frames_at_client_ = 0; | 1565 decoder_frames_at_client_ = 0; |
| 1570 while (!decoder_input_queue_.empty()) | 1566 while (!decoder_input_queue_.empty()) |
| 1571 decoder_input_queue_.pop(); | 1567 decoder_input_queue_.pop(); |
| 1572 decoder_flushing_ = false; | 1568 decoder_flushing_ = false; |
| 1573 | 1569 |
| 1574 if (image_processor_) | 1570 if (image_processor_) |
| 1575 image_processor_.release()->Destroy(); | 1571 image_processor_.release()->Destroy(); |
| 1576 | 1572 |
| 1577 // Set our state to kError. Just in case. | 1573 // Set our state to kError. Just in case. |
| 1578 decoder_state_ = kError; | 1574 decoder_state_ = kError; |
| 1575 |
| 1576 DestroyInputBuffers(); |
| 1577 DestroyOutputBuffers(); |
| 1579 } | 1578 } |
| 1580 | 1579 |
| 1581 bool V4L2VideoDecodeAccelerator::StartDevicePoll() { | 1580 bool V4L2VideoDecodeAccelerator::StartDevicePoll() { |
| 1582 DVLOGF(3); | 1581 DVLOGF(3); |
| 1583 DCHECK(!device_poll_thread_.IsRunning()); | 1582 DCHECK(!device_poll_thread_.IsRunning()); |
| 1584 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 1583 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 1585 | 1584 |
| 1586 // Start up the device poll thread and schedule its first DevicePollTask(). | 1585 // Start up the device poll thread and schedule its first DevicePollTask(). |
| 1587 if (!device_poll_thread_.Start()) { | 1586 if (!device_poll_thread_.Start()) { |
| 1588 LOGF(ERROR) << "Device thread failed to start"; | 1587 LOGF(ERROR) << "Device thread failed to start"; |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1682 decoder_state_ = kChangingResolution; | 1681 decoder_state_ = kChangingResolution; |
| 1683 | 1682 |
| 1684 if (!image_processor_bitstream_buffer_ids_.empty()) { | 1683 if (!image_processor_bitstream_buffer_ids_.empty()) { |
| 1685 DVLOGF(3) << "Wait image processor to finish before destroying buffers."; | 1684 DVLOGF(3) << "Wait image processor to finish before destroying buffers."; |
| 1686 return; | 1685 return; |
| 1687 } | 1686 } |
| 1688 | 1687 |
| 1689 if (image_processor_) | 1688 if (image_processor_) |
| 1690 image_processor_.release()->Destroy(); | 1689 image_processor_.release()->Destroy(); |
| 1691 | 1690 |
| 1692 // Post a task to clean up buffers on child thread. This will also ensure | 1691 if (!DestroyOutputBuffers()) { |
| 1693 // that we won't accept ReusePictureBuffer() anymore after that. | 1692 LOGF(ERROR) << "Failed destroying output buffers."; |
| 1694 child_task_runner_->PostTask( | 1693 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1695 FROM_HERE, | 1694 return; |
| 1696 base::Bind(&V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers, | 1695 } |
| 1697 weak_this_)); | 1696 |
| 1697 FinishResolutionChange(); |
| 1698 } | 1698 } |
| 1699 | 1699 |
| 1700 void V4L2VideoDecodeAccelerator::FinishResolutionChange() { | 1700 void V4L2VideoDecodeAccelerator::FinishResolutionChange() { |
| 1701 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 1701 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 1702 DCHECK_EQ(decoder_state_, kChangingResolution); | 1702 DCHECK_EQ(decoder_state_, kChangingResolution); |
| 1703 DVLOGF(3); | 1703 DVLOGF(3); |
| 1704 | 1704 |
| 1705 if (decoder_state_ == kError) { | 1705 if (decoder_state_ == kError) { |
| 1706 DVLOGF(2) << "early out: kError state"; | 1706 DVLOGF(2) << "early out: kError state"; |
| 1707 return; | 1707 return; |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2117 // done with this one. After we get the buffers, we'll go back into kIdle and | 2117 // done with this one. After we get the buffers, we'll go back into kIdle and |
| 2118 // kick off further event processing, and eventually go back into kDecoding | 2118 // kick off further event processing, and eventually go back into kDecoding |
| 2119 // once no more events are pending (if any). | 2119 // once no more events are pending (if any). |
| 2120 decoder_state_ = kAwaitingPictureBuffers; | 2120 decoder_state_ = kAwaitingPictureBuffers; |
| 2121 | 2121 |
| 2122 return true; | 2122 return true; |
| 2123 } | 2123 } |
| 2124 | 2124 |
| 2125 void V4L2VideoDecodeAccelerator::DestroyInputBuffers() { | 2125 void V4L2VideoDecodeAccelerator::DestroyInputBuffers() { |
| 2126 DVLOGF(3); | 2126 DVLOGF(3); |
| 2127 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 2127 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 2128 DCHECK(!input_streamon_); | 2128 DCHECK(!input_streamon_); |
| 2129 | 2129 |
| 2130 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { | 2130 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { |
| 2131 if (input_buffer_map_[i].address != NULL) { | 2131 if (input_buffer_map_[i].address != NULL) { |
| 2132 device_->Munmap(input_buffer_map_[i].address, | 2132 device_->Munmap(input_buffer_map_[i].address, |
| 2133 input_buffer_map_[i].length); | 2133 input_buffer_map_[i].length); |
| 2134 } | 2134 } |
| 2135 } | 2135 } |
| 2136 | 2136 |
| 2137 struct v4l2_requestbuffers reqbufs; | 2137 struct v4l2_requestbuffers reqbufs; |
| 2138 memset(&reqbufs, 0, sizeof(reqbufs)); | 2138 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 2139 reqbufs.count = 0; | 2139 reqbufs.count = 0; |
| 2140 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 2140 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 2141 reqbufs.memory = V4L2_MEMORY_MMAP; | 2141 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 2142 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 2142 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
| 2143 | 2143 |
| 2144 input_buffer_map_.clear(); | 2144 input_buffer_map_.clear(); |
| 2145 free_input_buffers_.clear(); | 2145 free_input_buffers_.clear(); |
| 2146 } | 2146 } |
| 2147 | 2147 |
| 2148 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { | 2148 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { |
| 2149 DVLOGF(3); | 2149 DVLOGF(3); |
| 2150 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 2150 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 2151 DCHECK(!output_streamon_); | 2151 DCHECK(!output_streamon_); |
| 2152 bool success = true; | 2152 bool success = true; |
| 2153 | 2153 |
| 2154 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 2154 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
| 2155 OutputRecord& output_record = output_buffer_map_[i]; | 2155 OutputRecord& output_record = output_buffer_map_[i]; |
| 2156 | 2156 |
| 2157 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { | 2157 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { |
| 2158 if (egl_image_device_->DestroyEGLImage( | 2158 child_task_runner_->PostTask( |
| 2159 egl_display_, output_record.egl_image) != EGL_TRUE) { | 2159 FROM_HERE, |
| 2160 DVLOGF(1) << "DestroyEGLImage failed."; | 2160 base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), device_, |
| 2161 success = false; | 2161 egl_display_, output_record.egl_image)); |
| 2162 } | |
| 2163 } | 2162 } |
| 2164 | 2163 |
| 2165 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 2164 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
| 2166 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 2165 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
| 2167 DVLOGF(1) << "eglDestroySyncKHR failed."; | 2166 DVLOGF(1) << "eglDestroySyncKHR failed."; |
| 2168 success = false; | 2167 success = false; |
| 2169 } | 2168 } |
| 2170 } | 2169 } |
| 2171 | 2170 |
| 2172 DVLOGF(1) << "dismissing PictureBuffer id=" << output_record.picture_id; | 2171 DVLOGF(1) << "dismissing PictureBuffer id=" << output_record.picture_id; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2189 while (!free_output_buffers_.empty()) | 2188 while (!free_output_buffers_.empty()) |
| 2190 free_output_buffers_.pop(); | 2189 free_output_buffers_.pop(); |
| 2191 output_buffer_queued_count_ = 0; | 2190 output_buffer_queued_count_ = 0; |
| 2192 // The client may still hold some buffers. The texture holds a reference to | 2191 // The client may still hold some buffers. The texture holds a reference to |
| 2193 // the buffer. It is OK to free the buffer and destroy EGLImage here. | 2192 // the buffer. It is OK to free the buffer and destroy EGLImage here. |
| 2194 decoder_frames_at_client_ = 0; | 2193 decoder_frames_at_client_ = 0; |
| 2195 | 2194 |
| 2196 return success; | 2195 return success; |
| 2197 } | 2196 } |
| 2198 | 2197 |
| 2199 void V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers() { | |
| 2200 DCHECK(child_task_runner_->BelongsToCurrentThread()); | |
| 2201 DVLOGF(3); | |
| 2202 | |
| 2203 if (!DestroyOutputBuffers()) { | |
| 2204 LOGF(ERROR) << "Failed destroying output buffers."; | |
| 2205 NOTIFY_ERROR(PLATFORM_FAILURE); | |
| 2206 return; | |
| 2207 } | |
| 2208 | |
| 2209 // Finish resolution change on decoder thread. | |
| 2210 decoder_thread_.task_runner()->PostTask( | |
| 2211 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::FinishResolutionChange, | |
| 2212 base::Unretained(this))); | |
| 2213 } | |
| 2214 | |
| 2215 void V4L2VideoDecodeAccelerator::SendPictureReady() { | 2198 void V4L2VideoDecodeAccelerator::SendPictureReady() { |
| 2216 DVLOGF(3); | 2199 DVLOGF(3); |
| 2217 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 2200 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 2218 bool resetting_or_flushing = | 2201 bool resetting_or_flushing = |
| 2219 (decoder_state_ == kResetting || decoder_flushing_); | 2202 (decoder_state_ == kResetting || decoder_flushing_); |
| 2220 while (pending_picture_ready_.size() > 0) { | 2203 while (pending_picture_ready_.size() > 0) { |
| 2221 bool cleared = pending_picture_ready_.front().cleared; | 2204 bool cleared = pending_picture_ready_.front().cleared; |
| 2222 const Picture& picture = pending_picture_ready_.front().picture; | 2205 const Picture& picture = pending_picture_ready_.front().picture; |
| 2223 if (cleared && picture_clearing_count_ == 0) { | 2206 if (cleared && picture_clearing_count_ == 0) { |
| 2224 // This picture is cleared. It can be posted to a thread different than | 2207 // This picture is cleared. It can be posted to a thread different than |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2294 StartResolutionChange(); | 2277 StartResolutionChange(); |
| 2295 } | 2278 } |
| 2296 } | 2279 } |
| 2297 | 2280 |
| 2298 void V4L2VideoDecodeAccelerator::ImageProcessorError() { | 2281 void V4L2VideoDecodeAccelerator::ImageProcessorError() { |
| 2299 LOGF(ERROR) << "Image processor error"; | 2282 LOGF(ERROR) << "Image processor error"; |
| 2300 NOTIFY_ERROR(PLATFORM_FAILURE); | 2283 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 2301 } | 2284 } |
| 2302 | 2285 |
| 2303 } // namespace media | 2286 } // namespace media |
| OLD | NEW |