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

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

Issue 2335573002: V4L2VideoDecodeAccelerator: destroy buffers in decoder thread. (Closed)
Patch Set: V4L2VideoDecodeAccelerator: destroy buffers in decoder thread. 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 1367 matching lines...) Expand 10 before | Expand all | Expand 10 after
1569 decoder_frames_at_client_ = 0; 1566 decoder_frames_at_client_ = 0;
1570 while (!decoder_input_queue_.empty()) 1567 while (!decoder_input_queue_.empty())
1571 decoder_input_queue_.pop(); 1568 decoder_input_queue_.pop();
1572 decoder_flushing_ = false; 1569 decoder_flushing_ = false;
1573 1570
1574 if (image_processor_) 1571 if (image_processor_)
1575 image_processor_.release()->Destroy(); 1572 image_processor_.release()->Destroy();
1576 1573
1577 // Set our state to kError. Just in case. 1574 // Set our state to kError. Just in case.
1578 decoder_state_ = kError; 1575 decoder_state_ = kError;
1576
1577 DestroyInputBuffers();
1578 DestroyOutputBuffers();
1579 } 1579 }
1580 1580
1581 bool V4L2VideoDecodeAccelerator::StartDevicePoll() { 1581 bool V4L2VideoDecodeAccelerator::StartDevicePoll() {
1582 DVLOGF(3); 1582 DVLOGF(3);
1583 DCHECK(!device_poll_thread_.IsRunning()); 1583 DCHECK(!device_poll_thread_.IsRunning());
1584 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 1584 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
1585 1585
1586 // Start up the device poll thread and schedule its first DevicePollTask(). 1586 // Start up the device poll thread and schedule its first DevicePollTask().
1587 if (!device_poll_thread_.Start()) { 1587 if (!device_poll_thread_.Start()) {
1588 LOGF(ERROR) << "Device thread failed to start"; 1588 LOGF(ERROR) << "Device thread failed to start";
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
1682 decoder_state_ = kChangingResolution; 1682 decoder_state_ = kChangingResolution;
1683 1683
1684 if (!image_processor_bitstream_buffer_ids_.empty()) { 1684 if (!image_processor_bitstream_buffer_ids_.empty()) {
1685 DVLOGF(3) << "Wait image processor to finish before destroying buffers."; 1685 DVLOGF(3) << "Wait image processor to finish before destroying buffers.";
1686 return; 1686 return;
1687 } 1687 }
1688 1688
1689 if (image_processor_) 1689 if (image_processor_)
1690 image_processor_.release()->Destroy(); 1690 image_processor_.release()->Destroy();
1691 1691
1692 // Post a task to clean up buffers on child thread. This will also ensure 1692 if (!DestroyOutputBuffers()) {
1693 // that we won't accept ReusePictureBuffer() anymore after that. 1693 LOGF(ERROR) << "Failed destroying output buffers.";
1694 child_task_runner_->PostTask( 1694 NOTIFY_ERROR(PLATFORM_FAILURE);
1695 FROM_HERE, 1695 return;
1696 base::Bind(&V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers, 1696 }
1697 weak_this_)); 1697
1698 FinishResolutionChange();
1698 } 1699 }
1699 1700
1700 void V4L2VideoDecodeAccelerator::FinishResolutionChange() { 1701 void V4L2VideoDecodeAccelerator::FinishResolutionChange() {
1701 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 1702 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
1702 DCHECK_EQ(decoder_state_, kChangingResolution); 1703 DCHECK_EQ(decoder_state_, kChangingResolution);
1703 DVLOGF(3); 1704 DVLOGF(3);
1704 1705
1705 if (decoder_state_ == kError) { 1706 if (decoder_state_ == kError) {
1706 DVLOGF(2) << "early out: kError state"; 1707 DVLOGF(2) << "early out: kError state";
1707 return; 1708 return;
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after
2117 // done with this one. After we get the buffers, we'll go back into kIdle and 2118 // 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 2119 // kick off further event processing, and eventually go back into kDecoding
2119 // once no more events are pending (if any). 2120 // once no more events are pending (if any).
2120 decoder_state_ = kAwaitingPictureBuffers; 2121 decoder_state_ = kAwaitingPictureBuffers;
2121 2122
2122 return true; 2123 return true;
2123 } 2124 }
2124 2125
2125 void V4L2VideoDecodeAccelerator::DestroyInputBuffers() { 2126 void V4L2VideoDecodeAccelerator::DestroyInputBuffers() {
2126 DVLOGF(3); 2127 DVLOGF(3);
2127 DCHECK(child_task_runner_->BelongsToCurrentThread()); 2128 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
2128 DCHECK(!input_streamon_); 2129 DCHECK(!input_streamon_);
2129 2130
2130 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { 2131 for (size_t i = 0; i < input_buffer_map_.size(); ++i) {
2131 if (input_buffer_map_[i].address != NULL) { 2132 if (input_buffer_map_[i].address != NULL) {
2132 device_->Munmap(input_buffer_map_[i].address, 2133 device_->Munmap(input_buffer_map_[i].address,
2133 input_buffer_map_[i].length); 2134 input_buffer_map_[i].length);
2134 } 2135 }
2135 } 2136 }
2136 2137
2137 struct v4l2_requestbuffers reqbufs; 2138 struct v4l2_requestbuffers reqbufs;
2138 memset(&reqbufs, 0, sizeof(reqbufs)); 2139 memset(&reqbufs, 0, sizeof(reqbufs));
2139 reqbufs.count = 0; 2140 reqbufs.count = 0;
2140 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 2141 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
2141 reqbufs.memory = V4L2_MEMORY_MMAP; 2142 reqbufs.memory = V4L2_MEMORY_MMAP;
2142 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); 2143 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs);
2143 2144
2144 input_buffer_map_.clear(); 2145 input_buffer_map_.clear();
2145 free_input_buffers_.clear(); 2146 free_input_buffers_.clear();
2146 } 2147 }
2147 2148
2148 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { 2149 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() {
2149 DVLOGF(3); 2150 DVLOGF(3);
2150 DCHECK(child_task_runner_->BelongsToCurrentThread()); 2151 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
2151 DCHECK(!output_streamon_); 2152 DCHECK(!output_streamon_);
2152 bool success = true; 2153 bool success = true;
2153 2154
2154 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { 2155 for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
2155 OutputRecord& output_record = output_buffer_map_[i]; 2156 OutputRecord& output_record = output_buffer_map_[i];
2156 2157
2157 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { 2158 if (output_record.egl_image != EGL_NO_IMAGE_KHR) {
2158 if (egl_image_device_->DestroyEGLImage( 2159 child_task_runner_->PostTask(
2159 egl_display_, output_record.egl_image) != EGL_TRUE) { 2160 FROM_HERE,
2160 DVLOGF(1) << "DestroyEGLImage failed."; 2161 base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), device_,
kcwu 2016/09/12 10:59:48 Add log if destroy failed at least.
wuchengli 2016/09/12 11:15:36 V4L2SVDA has three base::IgnoreResult(&V4L2Device:
2161 success = false; 2162 egl_display_, output_record.egl_image));
2162 }
2163 } 2163 }
2164 2164
2165 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { 2165 if (output_record.egl_sync != EGL_NO_SYNC_KHR) {
2166 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { 2166 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) {
kcwu 2016/09/12 10:59:48 Is it okay to call eglDestroySyncKHR on non-child
wuchengli 2016/09/12 11:15:36 Yes. It's OK. Also see line 1296. eglDestroySyncKH
2167 DVLOGF(1) << "eglDestroySyncKHR failed."; 2167 DVLOGF(1) << "eglDestroySyncKHR failed.";
2168 success = false; 2168 success = false;
2169 } 2169 }
2170 } 2170 }
2171 2171
2172 DVLOGF(1) << "dismissing PictureBuffer id=" << output_record.picture_id; 2172 DVLOGF(1) << "dismissing PictureBuffer id=" << output_record.picture_id;
2173 child_task_runner_->PostTask( 2173 child_task_runner_->PostTask(
2174 FROM_HERE, base::Bind(&Client::DismissPictureBuffer, client_, 2174 FROM_HERE, base::Bind(&Client::DismissPictureBuffer, client_,
2175 output_record.picture_id)); 2175 output_record.picture_id));
2176 } 2176 }
(...skipping 12 matching lines...) Expand all
2189 while (!free_output_buffers_.empty()) 2189 while (!free_output_buffers_.empty())
2190 free_output_buffers_.pop(); 2190 free_output_buffers_.pop();
2191 output_buffer_queued_count_ = 0; 2191 output_buffer_queued_count_ = 0;
2192 // The client may still hold some buffers. The texture holds a reference to 2192 // 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. 2193 // the buffer. It is OK to free the buffer and destroy EGLImage here.
2194 decoder_frames_at_client_ = 0; 2194 decoder_frames_at_client_ = 0;
2195 2195
2196 return success; 2196 return success;
2197 } 2197 }
2198 2198
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() { 2199 void V4L2VideoDecodeAccelerator::SendPictureReady() {
2216 DVLOGF(3); 2200 DVLOGF(3);
2217 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); 2201 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
2218 bool resetting_or_flushing = 2202 bool resetting_or_flushing =
2219 (decoder_state_ == kResetting || decoder_flushing_); 2203 (decoder_state_ == kResetting || decoder_flushing_);
2220 while (pending_picture_ready_.size() > 0) { 2204 while (pending_picture_ready_.size() > 0) {
2221 bool cleared = pending_picture_ready_.front().cleared; 2205 bool cleared = pending_picture_ready_.front().cleared;
2222 const Picture& picture = pending_picture_ready_.front().picture; 2206 const Picture& picture = pending_picture_ready_.front().picture;
2223 if (cleared && picture_clearing_count_ == 0) { 2207 if (cleared && picture_clearing_count_ == 0) {
2224 // This picture is cleared. It can be posted to a thread different than 2208 // 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
2294 StartResolutionChange(); 2278 StartResolutionChange();
2295 } 2279 }
2296 } 2280 }
2297 2281
2298 void V4L2VideoDecodeAccelerator::ImageProcessorError() { 2282 void V4L2VideoDecodeAccelerator::ImageProcessorError() {
2299 LOGF(ERROR) << "Image processor error"; 2283 LOGF(ERROR) << "Image processor error";
2300 NOTIFY_ERROR(PLATFORM_FAILURE); 2284 NOTIFY_ERROR(PLATFORM_FAILURE);
2301 } 2285 }
2302 2286
2303 } // namespace media 2287 } // 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