Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(200)

Side by Side Diff: media/gpu/v4l2_video_decode_accelerator.cc

Issue 2335573002: V4L2VideoDecodeAccelerator: destroy buffers in decoder thread. (Closed)
Patch Set: address Pawel's nits in PS4 Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/gpu/v4l2_video_decode_accelerator.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « media/gpu/v4l2_video_decode_accelerator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698