| 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 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2120 // done with this one. After we get the buffers, we'll go back into kIdle and | 2120 // done with this one. After we get the buffers, we'll go back into kIdle and |
| 2121 // kick off further event processing, and eventually go back into kDecoding | 2121 // kick off further event processing, and eventually go back into kDecoding |
| 2122 // once no more events are pending (if any). | 2122 // once no more events are pending (if any). |
| 2123 decoder_state_ = kAwaitingPictureBuffers; | 2123 decoder_state_ = kAwaitingPictureBuffers; |
| 2124 | 2124 |
| 2125 return true; | 2125 return true; |
| 2126 } | 2126 } |
| 2127 | 2127 |
| 2128 void V4L2VideoDecodeAccelerator::DestroyInputBuffers() { | 2128 void V4L2VideoDecodeAccelerator::DestroyInputBuffers() { |
| 2129 DVLOGF(3); | 2129 DVLOGF(3); |
| 2130 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 2130 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 2131 DCHECK(!input_streamon_); | 2131 DCHECK(!input_streamon_); |
| 2132 | 2132 |
| 2133 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { | 2133 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { |
| 2134 if (input_buffer_map_[i].address != NULL) { | 2134 if (input_buffer_map_[i].address != NULL) { |
| 2135 device_->Munmap(input_buffer_map_[i].address, | 2135 device_->Munmap(input_buffer_map_[i].address, |
| 2136 input_buffer_map_[i].length); | 2136 input_buffer_map_[i].length); |
| 2137 } | 2137 } |
| 2138 } | 2138 } |
| 2139 | 2139 |
| 2140 struct v4l2_requestbuffers reqbufs; | 2140 struct v4l2_requestbuffers reqbufs; |
| 2141 memset(&reqbufs, 0, sizeof(reqbufs)); | 2141 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 2142 reqbufs.count = 0; | 2142 reqbufs.count = 0; |
| 2143 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 2143 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 2144 reqbufs.memory = V4L2_MEMORY_MMAP; | 2144 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 2145 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 2145 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
| 2146 | 2146 |
| 2147 input_buffer_map_.clear(); | 2147 input_buffer_map_.clear(); |
| 2148 free_input_buffers_.clear(); | 2148 free_input_buffers_.clear(); |
| 2149 } | 2149 } |
| 2150 | 2150 |
| 2151 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { | 2151 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { |
| 2152 DVLOGF(3); | 2152 DVLOGF(3); |
| 2153 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 2153 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 2154 DCHECK(!output_streamon_); | 2154 DCHECK(!output_streamon_); |
| 2155 bool success = true; | 2155 bool success = true; |
| 2156 | 2156 |
| 2157 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 2157 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
| 2158 OutputRecord& output_record = output_buffer_map_[i]; | 2158 OutputRecord& output_record = output_buffer_map_[i]; |
| 2159 | 2159 |
| 2160 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { | 2160 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { |
| 2161 if (egl_image_device_->DestroyEGLImage( | 2161 child_task_runner_->PostTask( |
| 2162 egl_display_, output_record.egl_image) != EGL_TRUE) { | 2162 FROM_HERE, |
| 2163 DVLOGF(1) << "DestroyEGLImage failed."; | 2163 base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), device_, |
| 2164 success = false; | 2164 egl_display_, output_record.egl_image)); |
| 2165 } | |
| 2166 } | 2165 } |
| 2167 | 2166 |
| 2168 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 2167 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
| 2169 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 2168 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
| 2170 DVLOGF(1) << "eglDestroySyncKHR failed."; | 2169 DVLOGF(1) << "eglDestroySyncKHR failed."; |
| 2171 success = false; | 2170 success = false; |
| 2172 } | 2171 } |
| 2173 } | 2172 } |
| 2174 | 2173 |
| 2175 DVLOGF(1) << "dismissing PictureBuffer id=" << output_record.picture_id; | 2174 DVLOGF(1) << "dismissing PictureBuffer id=" << output_record.picture_id; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2192 while (!free_output_buffers_.empty()) | 2191 while (!free_output_buffers_.empty()) |
| 2193 free_output_buffers_.pop(); | 2192 free_output_buffers_.pop(); |
| 2194 output_buffer_queued_count_ = 0; | 2193 output_buffer_queued_count_ = 0; |
| 2195 // The client may still hold some buffers. The texture holds a reference to | 2194 // The client may still hold some buffers. The texture holds a reference to |
| 2196 // the buffer. It is OK to free the buffer and destroy EGLImage here. | 2195 // the buffer. It is OK to free the buffer and destroy EGLImage here. |
| 2197 decoder_frames_at_client_ = 0; | 2196 decoder_frames_at_client_ = 0; |
| 2198 | 2197 |
| 2199 return success; | 2198 return success; |
| 2200 } | 2199 } |
| 2201 | 2200 |
| 2202 void V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers() { | |
| 2203 DCHECK(child_task_runner_->BelongsToCurrentThread()); | |
| 2204 DVLOGF(3); | |
| 2205 | |
| 2206 if (!DestroyOutputBuffers()) { | |
| 2207 LOGF(ERROR) << "Failed destroying output buffers."; | |
| 2208 NOTIFY_ERROR(PLATFORM_FAILURE); | |
| 2209 return; | |
| 2210 } | |
| 2211 | |
| 2212 // Finish resolution change on decoder thread. | |
| 2213 decoder_thread_.task_runner()->PostTask( | |
| 2214 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::FinishResolutionChange, | |
| 2215 base::Unretained(this))); | |
| 2216 } | |
| 2217 | |
| 2218 void V4L2VideoDecodeAccelerator::SendPictureReady() { | 2201 void V4L2VideoDecodeAccelerator::SendPictureReady() { |
| 2219 DVLOGF(3); | 2202 DVLOGF(3); |
| 2220 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 2203 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 2221 bool resetting_or_flushing = | 2204 bool resetting_or_flushing = |
| 2222 (decoder_state_ == kResetting || decoder_flushing_); | 2205 (decoder_state_ == kResetting || decoder_flushing_); |
| 2223 while (pending_picture_ready_.size() > 0) { | 2206 while (pending_picture_ready_.size() > 0) { |
| 2224 bool cleared = pending_picture_ready_.front().cleared; | 2207 bool cleared = pending_picture_ready_.front().cleared; |
| 2225 const Picture& picture = pending_picture_ready_.front().picture; | 2208 const Picture& picture = pending_picture_ready_.front().picture; |
| 2226 if (cleared && picture_clearing_count_ == 0) { | 2209 if (cleared && picture_clearing_count_ == 0) { |
| 2227 // This picture is cleared. It can be posted to a thread different than | 2210 // 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... |
| 2297 StartResolutionChange(); | 2280 StartResolutionChange(); |
| 2298 } | 2281 } |
| 2299 } | 2282 } |
| 2300 | 2283 |
| 2301 void V4L2VideoDecodeAccelerator::ImageProcessorError() { | 2284 void V4L2VideoDecodeAccelerator::ImageProcessorError() { |
| 2302 LOGF(ERROR) << "Image processor error"; | 2285 LOGF(ERROR) << "Image processor error"; |
| 2303 NOTIFY_ERROR(PLATFORM_FAILURE); | 2286 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 2304 } | 2287 } |
| 2305 | 2288 |
| 2306 } // namespace media | 2289 } // namespace media |
| OLD | NEW |