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> |
11 #include <poll.h> | 11 #include <poll.h> |
12 #include <string.h> | 12 #include <string.h> |
13 #include <sys/eventfd.h> | 13 #include <sys/eventfd.h> |
14 #include <sys/ioctl.h> | 14 #include <sys/ioctl.h> |
15 #include <sys/mman.h> | 15 #include <sys/mman.h> |
16 | 16 |
17 #include "base/bind.h" | 17 #include "base/bind.h" |
18 #include "base/command_line.h" | 18 #include "base/command_line.h" |
19 #include "base/message_loop/message_loop.h" | 19 #include "base/message_loop/message_loop.h" |
20 #include "base/numerics/safe_conversions.h" | 20 #include "base/numerics/safe_conversions.h" |
21 #include "base/posix/eintr_wrapper.h" | |
21 #include "base/single_thread_task_runner.h" | 22 #include "base/single_thread_task_runner.h" |
22 #include "base/threading/thread_task_runner_handle.h" | 23 #include "base/threading/thread_task_runner_handle.h" |
23 #include "base/trace_event/trace_event.h" | 24 #include "base/trace_event/trace_event.h" |
24 #include "build/build_config.h" | 25 #include "build/build_config.h" |
25 #include "media/base/bind_to_current_loop.h" | 26 #include "media/base/bind_to_current_loop.h" |
26 #include "media/base/media_switches.h" | 27 #include "media/base/media_switches.h" |
27 #include "media/filters/h264_parser.h" | 28 #include "media/filters/h264_parser.h" |
28 #include "media/gpu/shared_memory_region.h" | 29 #include "media/gpu/shared_memory_region.h" |
29 #include "ui/gfx/geometry/rect.h" | 30 #include "ui/gfx/geometry/rect.h" |
30 #include "ui/gl/gl_context.h" | 31 #include "ui/gl/gl_context.h" |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
131 V4L2VideoDecodeAccelerator::InputRecord::InputRecord() | 132 V4L2VideoDecodeAccelerator::InputRecord::InputRecord() |
132 : at_device(false), address(NULL), length(0), bytes_used(0), input_id(-1) {} | 133 : at_device(false), address(NULL), length(0), bytes_used(0), input_id(-1) {} |
133 | 134 |
134 V4L2VideoDecodeAccelerator::InputRecord::~InputRecord() {} | 135 V4L2VideoDecodeAccelerator::InputRecord::~InputRecord() {} |
135 | 136 |
136 V4L2VideoDecodeAccelerator::OutputRecord::OutputRecord() | 137 V4L2VideoDecodeAccelerator::OutputRecord::OutputRecord() |
137 : state(kFree), | 138 : state(kFree), |
138 egl_image(EGL_NO_IMAGE_KHR), | 139 egl_image(EGL_NO_IMAGE_KHR), |
139 egl_sync(EGL_NO_SYNC_KHR), | 140 egl_sync(EGL_NO_SYNC_KHR), |
140 picture_id(-1), | 141 picture_id(-1), |
142 texture_id(0), | |
141 cleared(false) {} | 143 cleared(false) {} |
142 | 144 |
143 V4L2VideoDecodeAccelerator::OutputRecord::~OutputRecord() {} | 145 V4L2VideoDecodeAccelerator::OutputRecord::~OutputRecord() {} |
144 | 146 |
145 V4L2VideoDecodeAccelerator::PictureRecord::PictureRecord(bool cleared, | 147 V4L2VideoDecodeAccelerator::PictureRecord::PictureRecord(bool cleared, |
146 const Picture& picture) | 148 const Picture& picture) |
147 : cleared(cleared), picture(picture) {} | 149 : cleared(cleared), picture(picture) {} |
148 | 150 |
149 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} | 151 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} |
150 | 152 |
151 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( | 153 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( |
152 EGLDisplay egl_display, | 154 EGLDisplay egl_display, |
153 const GetGLContextCallback& get_gl_context_cb, | 155 const GetGLContextCallback& get_gl_context_cb, |
154 const MakeGLContextCurrentCallback& make_context_current_cb, | 156 const MakeGLContextCurrentCallback& make_context_current_cb, |
155 const scoped_refptr<V4L2Device>& device) | 157 const scoped_refptr<V4L2Device>& device) |
156 : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 158 : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
157 decoder_thread_("V4L2DecoderThread"), | 159 decoder_thread_("V4L2DecoderThread"), |
158 decoder_state_(kUninitialized), | 160 decoder_state_(kUninitialized), |
161 output_mode_(Config::OutputMode::ALLOCATE), | |
159 device_(device), | 162 device_(device), |
160 decoder_delay_bitstream_buffer_id_(-1), | 163 decoder_delay_bitstream_buffer_id_(-1), |
161 decoder_current_input_buffer_(-1), | 164 decoder_current_input_buffer_(-1), |
162 decoder_decode_buffer_tasks_scheduled_(0), | 165 decoder_decode_buffer_tasks_scheduled_(0), |
163 decoder_frames_at_client_(0), | 166 decoder_frames_at_client_(0), |
164 decoder_flushing_(false), | 167 decoder_flushing_(false), |
165 reset_pending_(false), | 168 reset_pending_(false), |
166 decoder_partial_frame_pending_(false), | 169 decoder_partial_frame_pending_(false), |
167 input_streamon_(false), | 170 input_streamon_(false), |
168 input_buffer_queued_count_(0), | 171 input_buffer_queued_count_(0), |
(...skipping 12 matching lines...) Expand all Loading... | |
181 egl_image_planes_count_(0), | 184 egl_image_planes_count_(0), |
182 weak_this_factory_(this) { | 185 weak_this_factory_(this) { |
183 weak_this_ = weak_this_factory_.GetWeakPtr(); | 186 weak_this_ = weak_this_factory_.GetWeakPtr(); |
184 } | 187 } |
185 | 188 |
186 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { | 189 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { |
187 DCHECK(!decoder_thread_.IsRunning()); | 190 DCHECK(!decoder_thread_.IsRunning()); |
188 DCHECK(!device_poll_thread_.IsRunning()); | 191 DCHECK(!device_poll_thread_.IsRunning()); |
189 | 192 |
190 DestroyInputBuffers(); | 193 DestroyInputBuffers(); |
194 DestroyEGLImages(); | |
191 DestroyOutputBuffers(); | 195 DestroyOutputBuffers(); |
192 | 196 |
193 // These maps have members that should be manually destroyed, e.g. file | 197 // These maps have members that should be manually destroyed, e.g. file |
194 // descriptors, mmap() segments, etc. | 198 // descriptors, mmap() segments, etc. |
195 DCHECK(input_buffer_map_.empty()); | 199 DCHECK(input_buffer_map_.empty()); |
196 DCHECK(output_buffer_map_.empty()); | 200 DCHECK(output_buffer_map_.empty()); |
197 } | 201 } |
198 | 202 |
199 bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, | 203 bool V4L2VideoDecodeAccelerator::Initialize(const Config& config, |
200 Client* client) { | 204 Client* client) { |
201 DVLOGF(3) << "profile: " << config.profile; | 205 DVLOGF(3) << "profile: " << config.profile; |
202 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 206 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
203 DCHECK_EQ(decoder_state_, kUninitialized); | 207 DCHECK_EQ(decoder_state_, kUninitialized); |
204 | 208 |
205 if (!device_->SupportsDecodeProfileForV4L2PixelFormats( | 209 if (!device_->SupportsDecodeProfileForV4L2PixelFormats( |
206 config.profile, arraysize(supported_input_fourccs_), | 210 config.profile, arraysize(supported_input_fourccs_), |
207 supported_input_fourccs_)) { | 211 supported_input_fourccs_)) { |
208 DVLOGF(1) << "unsupported profile=" << config.profile; | 212 DVLOGF(1) << "unsupported profile=" << config.profile; |
209 return false; | 213 return false; |
210 } | 214 } |
211 | 215 |
212 if (config.is_encrypted) { | 216 if (config.is_encrypted) { |
213 NOTREACHED() << "Encrypted streams are not supported for this VDA"; | 217 NOTREACHED() << "Encrypted streams are not supported for this VDA"; |
214 return false; | 218 return false; |
215 } | 219 } |
216 | 220 |
217 if (config.output_mode != Config::OutputMode::ALLOCATE) { | 221 if (config.output_mode != Config::OutputMode::ALLOCATE && |
218 NOTREACHED() << "Only ALLOCATE OutputMode is supported by this VDA"; | 222 config.output_mode != Config::OutputMode::IMPORT) { |
223 NOTREACHED() << "Only ALLOCATE and IMPORT OutputModes are supported"; | |
219 return false; | 224 return false; |
220 } | 225 } |
221 | 226 |
222 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { | |
223 NOTREACHED() << "GL callbacks are required for this VDA"; | |
224 return false; | |
225 } | |
226 | |
227 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); | 227 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); |
228 client_ = client_ptr_factory_->GetWeakPtr(); | 228 client_ = client_ptr_factory_->GetWeakPtr(); |
229 // If we haven't been set up to decode on separate thread via | 229 // If we haven't been set up to decode on separate thread via |
230 // TryToSetupDecodeOnSeparateThread(), use the main thread/client for | 230 // TryToSetupDecodeOnSeparateThread(), use the main thread/client for |
231 // decode tasks. | 231 // decode tasks. |
232 if (!decode_task_runner_) { | 232 if (!decode_task_runner_) { |
233 decode_task_runner_ = child_task_runner_; | 233 decode_task_runner_ = child_task_runner_; |
234 DCHECK(!decode_client_); | 234 DCHECK(!decode_client_); |
235 decode_client_ = client_; | 235 decode_client_ = client_; |
236 } | 236 } |
237 | 237 |
238 video_profile_ = config.profile; | 238 video_profile_ = config.profile; |
239 | 239 |
240 if (egl_display_ == EGL_NO_DISPLAY) { | 240 if (egl_display_ == EGL_NO_DISPLAY) { |
241 LOGF(ERROR) << "could not get EGLDisplay"; | 241 LOGF(ERROR) << "could not get EGLDisplay"; |
242 return false; | 242 return false; |
243 } | 243 } |
244 | 244 |
245 // We need the context to be initialized to query extensions. | 245 // We need the context to be initialized to query extensions. |
246 if (!make_context_current_cb_.Run()) { | 246 if (!make_context_current_cb_.is_null()) { |
247 LOGF(ERROR) << "could not make context current"; | 247 if (!make_context_current_cb_.Run()) { |
248 return false; | 248 LOGF(ERROR) << "could not make context current"; |
249 } | 249 return false; |
250 } | |
250 | 251 |
251 // TODO(posciak): crbug.com/450898. | 252 // TODO(posciak): crbug.com/450898. |
252 #if defined(ARCH_CPU_ARMEL) | 253 #if defined(ARCH_CPU_ARMEL) |
253 if (!gl::g_driver_egl.ext.b_EGL_KHR_fence_sync) { | 254 if (!gl::g_driver_egl.ext.b_EGL_KHR_fence_sync) { |
254 LOGF(ERROR) << "context does not have EGL_KHR_fence_sync"; | 255 LOGF(ERROR) << "context does not have EGL_KHR_fence_sync"; |
255 return false; | 256 return false; |
257 } | |
258 #endif | |
259 } else { | |
260 DVLOGF(1) << "No GL callbacks provided, initializing without GL support"; | |
256 } | 261 } |
257 #endif | |
258 | 262 |
259 // Capabilities check. | 263 // Capabilities check. |
260 struct v4l2_capability caps; | 264 struct v4l2_capability caps; |
261 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; | 265 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; |
262 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); | 266 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); |
263 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { | 267 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { |
264 LOGF(ERROR) << "ioctl() failed: VIDIOC_QUERYCAP" | 268 LOGF(ERROR) << "ioctl() failed: VIDIOC_QUERYCAP" |
265 << ", caps check failed: 0x" << std::hex << caps.capabilities; | 269 << ", caps check failed: 0x" << std::hex << caps.capabilities; |
266 return false; | 270 return false; |
267 } | 271 } |
(...skipping 13 matching lines...) Expand all Loading... | |
281 | 285 |
282 if (!CreateInputBuffers()) | 286 if (!CreateInputBuffers()) |
283 return false; | 287 return false; |
284 | 288 |
285 if (!decoder_thread_.Start()) { | 289 if (!decoder_thread_.Start()) { |
286 LOGF(ERROR) << "decoder thread failed to start"; | 290 LOGF(ERROR) << "decoder thread failed to start"; |
287 return false; | 291 return false; |
288 } | 292 } |
289 | 293 |
290 decoder_state_ = kInitialized; | 294 decoder_state_ = kInitialized; |
295 output_mode_ = config.output_mode; | |
291 | 296 |
292 // StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here. | 297 // StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here. |
293 decoder_thread_.task_runner()->PostTask( | 298 decoder_thread_.task_runner()->PostTask( |
294 FROM_HERE, base::Bind(base::IgnoreResult( | 299 FROM_HERE, base::Bind(base::IgnoreResult( |
295 &V4L2VideoDecodeAccelerator::StartDevicePoll), | 300 &V4L2VideoDecodeAccelerator::StartDevicePoll), |
296 base::Unretained(this))); | 301 base::Unretained(this))); |
297 | 302 |
298 return true; | 303 return true; |
299 } | 304 } |
300 | 305 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
352 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 357 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
353 reqbufs.memory = V4L2_MEMORY_MMAP; | 358 reqbufs.memory = V4L2_MEMORY_MMAP; |
354 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); | 359 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); |
355 | 360 |
356 if (reqbufs.count != buffers.size()) { | 361 if (reqbufs.count != buffers.size()) { |
357 DLOGF(ERROR) << "Could not allocate enough output buffers"; | 362 DLOGF(ERROR) << "Could not allocate enough output buffers"; |
358 NOTIFY_ERROR(PLATFORM_FAILURE); | 363 NOTIFY_ERROR(PLATFORM_FAILURE); |
359 return; | 364 return; |
360 } | 365 } |
361 | 366 |
362 if (image_processor_device_) { | 367 DCHECK(free_output_buffers_.empty()); |
363 DCHECK(!image_processor_); | 368 DCHECK(output_buffer_map_.empty()); |
364 image_processor_.reset(new V4L2ImageProcessor(image_processor_device_)); | 369 output_buffer_map_.resize(buffers.size()); |
365 // Unretained is safe because |this| owns image processor and there will be | 370 if (image_processor_device_ && output_mode_ == Config::OutputMode::ALLOCATE) { |
366 // no callbacks after processor destroys. | 371 if (!CreateImageProcessor()) |
367 if (!image_processor_->Initialize( | |
368 V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_), | |
369 V4L2Device::V4L2PixFmtToVideoPixelFormat(egl_image_format_fourcc_), | |
370 V4L2_MEMORY_DMABUF, visible_size_, coded_size_, visible_size_, | |
371 visible_size_, buffers.size(), | |
372 base::Bind(&V4L2VideoDecodeAccelerator::ImageProcessorError, | |
373 base::Unretained(this)))) { | |
374 LOGF(ERROR) << "Initialize image processor failed"; | |
375 NOTIFY_ERROR(PLATFORM_FAILURE); | |
376 return; | 372 return; |
377 } | |
378 DCHECK(image_processor_->output_allocated_size() == egl_image_size_); | |
379 if (image_processor_->input_allocated_size() != coded_size_) { | |
380 LOGF(ERROR) << "Image processor should be able to take the output coded " | |
381 << "size of decoder " << coded_size_.ToString() | |
382 << " without adjusting to " | |
383 << image_processor_->input_allocated_size().ToString(); | |
384 NOTIFY_ERROR(PLATFORM_FAILURE); | |
385 return; | |
386 } | |
387 } | 373 } |
388 | 374 |
389 child_task_runner_->PostTask( | 375 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
390 FROM_HERE, | 376 DCHECK(buffers[i].size() == egl_image_size_); |
391 base::Bind(&V4L2VideoDecodeAccelerator::CreateEGLImages, weak_this_, | 377 |
392 buffers, egl_image_format_fourcc_, egl_image_planes_count_)); | 378 OutputRecord& output_record = output_buffer_map_[i]; |
379 DCHECK_EQ(output_record.state, kFree); | |
380 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
381 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | |
382 DCHECK_EQ(output_record.picture_id, -1); | |
383 DCHECK_EQ(output_record.cleared, false); | |
384 DCHECK_EQ(1u, buffers[i].texture_ids().size()); | |
385 DCHECK(output_record.processor_input_fds.empty()); | |
386 | |
387 output_record.picture_id = buffers[i].id(); | |
388 output_record.texture_id = buffers[i].texture_ids()[0]; | |
389 // This will remain kAtClient until ImportBufferForPicture is called, either | |
390 // by the client, or by ourselves, if we are allocating. | |
391 output_record.state = kAtClient; | |
392 | |
393 if (image_processor_device_) { | |
394 std::vector<base::ScopedFD> dmabuf_fds = device_->GetDmabufsForV4L2Buffer( | |
395 i, output_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | |
396 if (dmabuf_fds.empty()) { | |
397 LOGF(ERROR) << "Failed to get DMABUFs of decoder."; | |
398 NOTIFY_ERROR(PLATFORM_FAILURE); | |
399 return; | |
400 } | |
401 output_record.processor_input_fds = std::move(dmabuf_fds); | |
402 } | |
403 | |
404 if (output_mode_ == Config::OutputMode::ALLOCATE) { | |
405 std::vector<base::ScopedFD> dmabuf_fds; | |
406 dmabuf_fds = egl_image_device_->GetDmabufsForV4L2Buffer( | |
407 i, egl_image_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | |
408 if (dmabuf_fds.empty()) { | |
409 LOGF(ERROR) << "Failed to get DMABUFs for EGLImage."; | |
410 NOTIFY_ERROR(PLATFORM_FAILURE); | |
411 return; | |
412 } | |
413 ImportBufferForPictureTask(output_record.picture_id, | |
414 std::move(dmabuf_fds), | |
415 egl_image_size_.width()); | |
416 } // else we'll get triggered via ImportBufferForPicture() from client. | |
417 | |
418 DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id; | |
419 } | |
393 } | 420 } |
394 | 421 |
395 void V4L2VideoDecodeAccelerator::CreateEGLImages( | 422 void V4L2VideoDecodeAccelerator::CreateEGLImageFor( |
396 const std::vector<media::PictureBuffer>& buffers, | 423 size_t buffer_index, |
397 uint32_t output_format_fourcc, | 424 int32_t picture_buffer_id, |
398 size_t output_planes_count) { | 425 std::vector<base::ScopedFD> dmabuf_fds, |
399 DVLOGF(3); | 426 GLuint texture_id, |
427 const gfx::Size& size, | |
428 uint32_t fourcc) { | |
429 DVLOGF(3) << "index=" << buffer_index; | |
400 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 430 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
401 | 431 |
402 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { | 432 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) { |
403 DLOGF(ERROR) << "GL callbacks required for binding to EGLImages"; | 433 DLOGF(ERROR) << "GL callbacks required for binding to EGLImages"; |
404 NOTIFY_ERROR(INVALID_ARGUMENT); | 434 NOTIFY_ERROR(INVALID_ARGUMENT); |
405 return; | 435 return; |
406 } | 436 } |
407 | 437 |
408 gl::GLContext* gl_context = get_gl_context_cb_.Run(); | 438 gl::GLContext* gl_context = get_gl_context_cb_.Run(); |
409 if (!gl_context || !make_context_current_cb_.Run()) { | 439 if (!gl_context || !make_context_current_cb_.Run()) { |
410 DLOGF(ERROR) << "No GL context"; | 440 DLOGF(ERROR) << "No GL context"; |
411 NOTIFY_ERROR(PLATFORM_FAILURE); | 441 NOTIFY_ERROR(PLATFORM_FAILURE); |
412 return; | 442 return; |
413 } | 443 } |
414 | 444 |
415 gl::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); | 445 gl::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); |
416 | 446 |
417 std::vector<EGLImageKHR> egl_images; | 447 EGLImageKHR egl_image = egl_image_device_->CreateEGLImage( |
418 for (size_t i = 0; i < buffers.size(); ++i) { | 448 egl_display_, gl_context->GetHandle(), texture_id, size, buffer_index, |
419 std::vector<base::ScopedFD> dmabuf_fds; | 449 fourcc, dmabuf_fds); |
420 dmabuf_fds = egl_image_device_->GetDmabufsForV4L2Buffer( | 450 if (egl_image == EGL_NO_IMAGE_KHR) { |
421 i, egl_image_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | 451 LOGF(ERROR) << "could not create EGLImageKHR," |
422 if (dmabuf_fds.empty()) { | 452 << " index=" << buffer_index << " texture_id=" << texture_id; |
423 LOGF(ERROR) << "Failed to get DMABUFs for EGLImage."; | 453 NOTIFY_ERROR(PLATFORM_FAILURE); |
424 NOTIFY_ERROR(PLATFORM_FAILURE); | 454 return; |
425 return; | |
426 } | |
427 | |
428 EGLImageKHR egl_image = egl_image_device_->CreateEGLImage( | |
429 egl_display_, gl_context->GetHandle(), buffers[i].texture_ids()[0], | |
430 buffers[i].size(), i, egl_image_format_fourcc_, dmabuf_fds); | |
431 if (egl_image == EGL_NO_IMAGE_KHR) { | |
432 LOGF(ERROR) << "could not create EGLImageKHR," | |
433 << " index=" << i | |
434 << " texture_id=" << buffers[i].texture_ids()[0]; | |
435 for (EGLImageKHR image : egl_images) { | |
436 if (egl_image_device_->DestroyEGLImage(egl_display_, image) != EGL_TRUE) | |
437 DVLOGF(1) << "DestroyEGLImage failed."; | |
438 } | |
439 NOTIFY_ERROR(PLATFORM_FAILURE); | |
440 return; | |
441 } | |
442 egl_images.push_back(egl_image); | |
443 } | 455 } |
444 | 456 |
445 decoder_thread_.task_runner()->PostTask( | 457 decoder_thread_.task_runner()->PostTask( |
446 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::AssignEGLImages, | 458 FROM_HERE, |
447 base::Unretained(this), buffers, egl_images)); | 459 base::Bind(&V4L2VideoDecodeAccelerator::AssignEGLImage, |
460 base::Unretained(this), buffer_index, picture_buffer_id, | |
461 egl_image, base::Passed(&dmabuf_fds))); | |
448 } | 462 } |
449 | 463 |
450 void V4L2VideoDecodeAccelerator::AssignEGLImages( | 464 void V4L2VideoDecodeAccelerator::AssignEGLImage( |
451 const std::vector<media::PictureBuffer>& buffers, | 465 size_t buffer_index, |
452 const std::vector<EGLImageKHR>& egl_images) { | 466 int32_t picture_buffer_id, |
453 DVLOGF(3); | 467 EGLImageKHR egl_image, |
468 std::vector<base::ScopedFD> dmabuf_fds) { | |
469 DVLOGF(3) << "index=" << buffer_index << ", picture_id=" << picture_buffer_id; | |
454 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 470 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
455 DCHECK_EQ(buffers.size(), egl_images.size()); | |
456 DCHECK(free_output_buffers_.empty()); | |
457 DCHECK(output_buffer_map_.empty()); | |
458 | 471 |
459 output_buffer_map_.resize(buffers.size()); | 472 // It's possible that while waiting for the EGLImages to be allocated and |
460 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 473 // assigned, we have already decoded more of the stream and saw another |
461 DCHECK(buffers[i].size() == egl_image_size_); | 474 // resolution change. This is a normal situation, in such a case either there |
462 | 475 // is no output record with this index awaiting an EGLImage to be assigned to |
463 OutputRecord& output_record = output_buffer_map_[i]; | 476 // it, or the record is already updated to use a newer PictureBuffer and is |
464 DCHECK_EQ(output_record.state, kFree); | 477 // awaiting an EGLImage associated with a different picture_buffer_id. If so, |
465 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); | 478 // just discard this image, we will get the one we are waiting for later. |
466 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 479 if (buffer_index >= output_buffer_map_.size() || |
467 DCHECK_EQ(output_record.picture_id, -1); | 480 output_buffer_map_[buffer_index].picture_id != picture_buffer_id) { |
468 DCHECK_EQ(output_record.cleared, false); | 481 DVLOGF(3) << "Picture set already changed, dropping EGLImage"; |
469 DCHECK_LE(1u, buffers[i].texture_ids().size()); | 482 child_task_runner_->PostTask( |
470 | 483 FROM_HERE, base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), |
471 if (image_processor_device_) { | 484 device_, egl_display_, egl_image)); |
472 std::vector<base::ScopedFD> fds = device_->GetDmabufsForV4L2Buffer( | 485 return; |
473 i, output_planes_count_, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | |
474 if (fds.empty()) { | |
475 LOGF(ERROR) << "Failed to get DMABUFs of decoder."; | |
476 NOTIFY_ERROR(PLATFORM_FAILURE); | |
477 return; | |
478 } | |
479 output_record.fds = std::move(fds); | |
480 } | |
481 | |
482 output_record.egl_image = egl_images[i]; | |
483 output_record.picture_id = buffers[i].id(); | |
484 | |
485 free_output_buffers_.push(i); | |
486 DVLOGF(3) << "buffer[" << i << "]: picture_id=" << output_record.picture_id; | |
487 } | 486 } |
488 | 487 |
489 decoder_state_ = kDecoding; | 488 OutputRecord& output_record = output_buffer_map_[buffer_index]; |
490 Enqueue(); | 489 DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR); |
490 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | |
491 DCHECK_EQ(output_record.state, kFree); | |
492 DCHECK_EQ(std::count(free_output_buffers_.begin(), free_output_buffers_.end(), | |
493 buffer_index), | |
494 0); | |
495 output_record.egl_image = egl_image; | |
496 free_output_buffers_.push_back(buffer_index); | |
497 if (decoder_state_ == kAwaitingPictureBuffers) { | |
498 DVLOGF(1) << "Change state to kDecoding"; | |
499 decoder_state_ = kDecoding; | |
500 } | |
491 if (reset_pending_) { | 501 if (reset_pending_) { |
492 FinishReset(); | 502 FinishReset(); |
493 return; | 503 return; |
494 } | 504 } |
505 if (decoder_state_ != kChangingResolution) { | |
506 Enqueue(); | |
507 ScheduleDecodeBufferTaskIfNeeded(); | |
508 } | |
509 } | |
495 | 510 |
496 ScheduleDecodeBufferTaskIfNeeded(); | 511 void V4L2VideoDecodeAccelerator::ImportBufferForPicture( |
512 int32_t picture_buffer_id, | |
513 const gfx::GpuMemoryBufferHandle& gpu_memory_buffer_handle) { | |
514 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; | |
515 DCHECK(child_task_runner_->BelongsToCurrentThread()); | |
516 | |
517 if (output_mode_ != Config::OutputMode::IMPORT) { | |
518 LOGF(ERROR) << "Cannot import in non-import mode"; | |
519 NOTIFY_ERROR(INVALID_ARGUMENT); | |
520 return; | |
521 } | |
522 | |
523 std::vector<base::ScopedFD> dmabuf_fds; | |
524 int32_t stride = 0; | |
525 #if defined(USE_OZONE) | |
526 for (const auto& fd : gpu_memory_buffer_handle.native_pixmap_handle.fds) { | |
527 DCHECK_NE(fd.fd, -1); | |
528 dmabuf_fds.push_back(base::ScopedFD(fd.fd)); | |
529 } | |
530 stride = gpu_memory_buffer_handle.native_pixmap_handle.planes[0].stride; | |
531 for (const auto& plane : | |
532 gpu_memory_buffer_handle.native_pixmap_handle.planes) { | |
533 DVLOGF(3) << ": offset=" << plane.offset << ", stride=" << plane.stride; | |
534 } | |
535 #endif | |
536 | |
537 decoder_thread_.message_loop()->PostTask( | |
538 FROM_HERE, | |
539 base::Bind(&V4L2VideoDecodeAccelerator::ImportBufferForPictureTask, | |
540 base::Unretained(this), picture_buffer_id, | |
541 base::Passed(&dmabuf_fds), stride)); | |
542 } | |
543 | |
544 void V4L2VideoDecodeAccelerator::ImportBufferForPictureTask( | |
545 int32_t picture_buffer_id, | |
546 std::vector<base::ScopedFD> dmabuf_fds, | |
547 int32_t stride) { | |
548 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id | |
549 << ", dmabuf_fds.size()=" << dmabuf_fds.size() | |
550 << ", stride=" << stride; | |
551 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | |
552 DCHECK(image_processor_device_); | |
553 | |
554 int plane_horiz_bits_per_pixel = VideoFrame::PlaneHorizontalBitsPerPixel( | |
555 V4L2Device::V4L2PixFmtToVideoPixelFormat(egl_image_format_fourcc_), 0); | |
Pawel Osciak
2016/09/14 04:17:29
We should probably verify plane_horiz_bits_per_pix
wuchengli
2016/09/14 05:17:27
Done.
| |
556 int adjusted_coded_width = stride * 8 / plane_horiz_bits_per_pixel; | |
Pawel Osciak
2016/09/14 04:17:29
Do we need to align up or error out in case (strid
wuchengli
2016/09/14 05:17:27
Done.
| |
557 if (!image_processor_) { | |
558 // The client may adjust the coded width. We don't have the final coded size | |
559 // in AssignPictureBuffers yet. Use the adjusted coded width to create the | |
560 // image processor. | |
561 DVLOGF(3) << "Original egl_image_size=" << egl_image_size_.ToString() | |
562 << ", adjusted coded width=" << adjusted_coded_width; | |
563 egl_image_size_.set_width(adjusted_coded_width); | |
564 if (!CreateImageProcessor()) | |
565 return; | |
566 } else { | |
567 DCHECK_EQ(egl_image_size_.width(), adjusted_coded_width); | |
568 } | |
569 | |
570 const auto iter = | |
571 std::find_if(output_buffer_map_.begin(), output_buffer_map_.end(), | |
572 [picture_buffer_id](const OutputRecord& output_record) { | |
573 return output_record.picture_id == picture_buffer_id; | |
574 }); | |
575 if (iter == output_buffer_map_.end()) { | |
576 // It's possible that we've already posted a DismissPictureBuffer for this | |
577 // picture, but it has not yet executed when this ImportBufferForPicture was | |
578 // posted to us by the client. In that case just ignore this (we've already | |
579 // dismissed it and accounted for that). | |
580 DVLOGF(3) << "got picture id=" << picture_buffer_id | |
581 << " not in use (anymore?)."; | |
582 return; | |
583 } | |
584 | |
585 if (iter->state != kAtClient) { | |
586 LOGF(ERROR) << "Cannot import buffer not owned by client"; | |
587 NOTIFY_ERROR(INVALID_ARGUMENT); | |
588 return; | |
589 } | |
590 | |
591 size_t index = iter - output_buffer_map_.begin(); | |
592 DCHECK_EQ(std::count(free_output_buffers_.begin(), free_output_buffers_.end(), | |
593 index), | |
594 0); | |
595 | |
596 iter->state = kFree; | |
597 if (iter->texture_id != 0) { | |
598 if (iter->egl_image != EGL_NO_IMAGE_KHR) { | |
599 child_task_runner_->PostTask( | |
600 FROM_HERE, | |
601 base::Bind(base::IgnoreResult(&V4L2Device::DestroyEGLImage), device_, | |
602 egl_display_, iter->egl_image)); | |
603 } | |
604 | |
605 child_task_runner_->PostTask( | |
606 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::CreateEGLImageFor, | |
607 weak_this_, index, picture_buffer_id, | |
608 base::Passed(&dmabuf_fds), iter->texture_id, | |
609 egl_image_size_, egl_image_format_fourcc_)); | |
610 } else { | |
611 // No need for an EGLImage, start using this buffer now. | |
612 DCHECK_EQ(egl_image_planes_count_, dmabuf_fds.size()); | |
613 iter->processor_output_fds.swap(dmabuf_fds); | |
614 free_output_buffers_.push_back(index); | |
615 if (decoder_state_ == kAwaitingPictureBuffers) { | |
616 DVLOGF(1) << "Change state to kDecoding"; | |
617 decoder_state_ = kDecoding; | |
618 } | |
619 if (decoder_state_ != kChangingResolution) { | |
620 Enqueue(); | |
621 ScheduleDecodeBufferTaskIfNeeded(); | |
622 } | |
623 } | |
497 } | 624 } |
498 | 625 |
499 void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) { | 626 void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) { |
500 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; | 627 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; |
501 // Must be run on child thread, as we'll insert a sync in the EGL context. | 628 // Must be run on child thread, as we'll insert a sync in the EGL context. |
502 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 629 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
503 | 630 |
504 if (!make_context_current_cb_.Run()) { | 631 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref; |
505 LOGF(ERROR) << "could not make context current"; | |
506 NOTIFY_ERROR(PLATFORM_FAILURE); | |
507 return; | |
508 } | |
509 | 632 |
510 EGLSyncKHR egl_sync = EGL_NO_SYNC_KHR; | 633 if (!make_context_current_cb_.is_null()) { |
634 if (!make_context_current_cb_.Run()) { | |
635 LOGF(ERROR) << "could not make context current"; | |
636 NOTIFY_ERROR(PLATFORM_FAILURE); | |
637 return; | |
638 } | |
639 | |
640 EGLSyncKHR egl_sync = EGL_NO_SYNC_KHR; | |
511 // TODO(posciak): crbug.com/450898. | 641 // TODO(posciak): crbug.com/450898. |
512 #if defined(ARCH_CPU_ARMEL) | 642 #if defined(ARCH_CPU_ARMEL) |
513 egl_sync = eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); | 643 egl_sync = eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); |
514 if (egl_sync == EGL_NO_SYNC_KHR) { | 644 if (egl_sync == EGL_NO_SYNC_KHR) { |
515 LOGF(ERROR) << "eglCreateSyncKHR() failed"; | 645 LOGF(ERROR) << "eglCreateSyncKHR() failed"; |
516 NOTIFY_ERROR(PLATFORM_FAILURE); | 646 NOTIFY_ERROR(PLATFORM_FAILURE); |
517 return; | 647 return; |
518 } | 648 } |
519 #endif | 649 #endif |
520 | 650 |
521 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref( | 651 egl_sync_ref.reset(new EGLSyncKHRRef(egl_display_, egl_sync)); |
522 new EGLSyncKHRRef(egl_display_, egl_sync)); | 652 } |
523 | 653 |
524 decoder_thread_.task_runner()->PostTask( | 654 decoder_thread_.task_runner()->PostTask( |
525 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::ReusePictureBufferTask, | 655 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::ReusePictureBufferTask, |
526 base::Unretained(this), picture_buffer_id, | 656 base::Unretained(this), picture_buffer_id, |
527 base::Passed(&egl_sync_ref))); | 657 base::Passed(&egl_sync_ref))); |
528 } | 658 } |
529 | 659 |
530 void V4L2VideoDecodeAccelerator::Flush() { | 660 void V4L2VideoDecodeAccelerator::Flush() { |
531 DVLOGF(3); | 661 DVLOGF(3); |
532 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 662 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
(...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1196 if (errno == EAGAIN) { | 1326 if (errno == EAGAIN) { |
1197 // EAGAIN if we're just out of buffers to dequeue. | 1327 // EAGAIN if we're just out of buffers to dequeue. |
1198 break; | 1328 break; |
1199 } | 1329 } |
1200 PLOGF(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; | 1330 PLOGF(ERROR) << "ioctl() failed: VIDIOC_DQBUF"; |
1201 NOTIFY_ERROR(PLATFORM_FAILURE); | 1331 NOTIFY_ERROR(PLATFORM_FAILURE); |
1202 return; | 1332 return; |
1203 } | 1333 } |
1204 OutputRecord& output_record = output_buffer_map_[dqbuf.index]; | 1334 OutputRecord& output_record = output_buffer_map_[dqbuf.index]; |
1205 DCHECK_EQ(output_record.state, kAtDevice); | 1335 DCHECK_EQ(output_record.state, kAtDevice); |
1206 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
1207 DCHECK_NE(output_record.picture_id, -1); | 1336 DCHECK_NE(output_record.picture_id, -1); |
1208 output_buffer_queued_count_--; | 1337 output_buffer_queued_count_--; |
1209 if (dqbuf.m.planes[0].bytesused == 0) { | 1338 if (dqbuf.m.planes[0].bytesused == 0) { |
1210 // This is an empty output buffer returned as part of a flush. | 1339 // This is an empty output buffer returned as part of a flush. |
1211 output_record.state = kFree; | 1340 output_record.state = kFree; |
1212 free_output_buffers_.push(dqbuf.index); | 1341 free_output_buffers_.push_back(dqbuf.index); |
1213 } else { | 1342 } else { |
1214 int32_t bitstream_buffer_id = dqbuf.timestamp.tv_sec; | 1343 int32_t bitstream_buffer_id = dqbuf.timestamp.tv_sec; |
1215 DCHECK_GE(bitstream_buffer_id, 0); | 1344 DCHECK_GE(bitstream_buffer_id, 0); |
1216 DVLOGF(3) << "Dequeue output buffer: dqbuf index=" << dqbuf.index | 1345 DVLOGF(3) << "Dequeue output buffer: dqbuf index=" << dqbuf.index |
1217 << " bitstream input_id=" << bitstream_buffer_id; | 1346 << " bitstream input_id=" << bitstream_buffer_id; |
1218 if (image_processor_device_) { | 1347 if (image_processor_device_) { |
1219 output_record.state = kAtProcessor; | 1348 if (!ProcessFrame(bitstream_buffer_id, dqbuf.index)) { |
1220 image_processor_bitstream_buffer_ids_.push(bitstream_buffer_id); | 1349 DLOGF(ERROR) << "Processing frame failed"; |
1221 std::vector<int> fds; | 1350 NOTIFY_ERROR(PLATFORM_FAILURE); |
1222 for (auto& fd : output_record.fds) { | 1351 return; |
1223 fds.push_back(fd.get()); | |
1224 } | 1352 } |
1225 scoped_refptr<VideoFrame> frame = VideoFrame::WrapExternalDmabufs( | |
1226 V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_), | |
1227 coded_size_, gfx::Rect(visible_size_), visible_size_, fds, | |
1228 base::TimeDelta()); | |
1229 // Unretained is safe because |this| owns image processor and there will | |
1230 // be no callbacks after processor destroys. Also, this class ensures it | |
1231 // is safe to post a task from child thread to decoder thread using | |
1232 // Unretained. | |
1233 image_processor_->Process( | |
1234 frame, dqbuf.index, | |
1235 BindToCurrentLoop( | |
1236 base::Bind(&V4L2VideoDecodeAccelerator::FrameProcessed, | |
1237 base::Unretained(this), bitstream_buffer_id))); | |
1238 } else { | 1353 } else { |
1239 output_record.state = kAtClient; | 1354 output_record.state = kAtClient; |
1240 decoder_frames_at_client_++; | 1355 decoder_frames_at_client_++; |
1241 const Picture picture(output_record.picture_id, bitstream_buffer_id, | 1356 const Picture picture(output_record.picture_id, bitstream_buffer_id, |
1242 gfx::Rect(visible_size_), false); | 1357 gfx::Rect(visible_size_), false); |
1243 pending_picture_ready_.push( | 1358 pending_picture_ready_.push( |
1244 PictureRecord(output_record.cleared, picture)); | 1359 PictureRecord(output_record.cleared, picture)); |
1245 SendPictureReady(); | 1360 SendPictureReady(); |
1246 output_record.cleared = true; | 1361 output_record.cleared = true; |
1247 } | 1362 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1280 } | 1395 } |
1281 | 1396 |
1282 bool V4L2VideoDecodeAccelerator::EnqueueOutputRecord() { | 1397 bool V4L2VideoDecodeAccelerator::EnqueueOutputRecord() { |
1283 DCHECK(!free_output_buffers_.empty()); | 1398 DCHECK(!free_output_buffers_.empty()); |
1284 | 1399 |
1285 // Enqueue an output (VIDEO_CAPTURE) buffer. | 1400 // Enqueue an output (VIDEO_CAPTURE) buffer. |
1286 const int buffer = free_output_buffers_.front(); | 1401 const int buffer = free_output_buffers_.front(); |
1287 DVLOGF(3) << "buffer " << buffer; | 1402 DVLOGF(3) << "buffer " << buffer; |
1288 OutputRecord& output_record = output_buffer_map_[buffer]; | 1403 OutputRecord& output_record = output_buffer_map_[buffer]; |
1289 DCHECK_EQ(output_record.state, kFree); | 1404 DCHECK_EQ(output_record.state, kFree); |
1290 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
1291 DCHECK_NE(output_record.picture_id, -1); | 1405 DCHECK_NE(output_record.picture_id, -1); |
1292 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 1406 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
1293 TRACE_EVENT0("Video Decoder", | 1407 TRACE_EVENT0("Video Decoder", |
1294 "V4L2VDA::EnqueueOutputRecord: eglClientWaitSyncKHR"); | 1408 "V4L2VDA::EnqueueOutputRecord: eglClientWaitSyncKHR"); |
1295 // If we have to wait for completion, wait. Note that | 1409 // If we have to wait for completion, wait. Note that |
1296 // free_output_buffers_ is a FIFO queue, so we always wait on the | 1410 // free_output_buffers_ is a FIFO queue, so we always wait on the |
1297 // buffer that has been in the queue the longest. | 1411 // buffer that has been in the queue the longest. |
1298 if (eglClientWaitSyncKHR(egl_display_, output_record.egl_sync, 0, | 1412 if (eglClientWaitSyncKHR(egl_display_, output_record.egl_sync, 0, |
1299 EGL_FOREVER_KHR) == EGL_FALSE) { | 1413 EGL_FOREVER_KHR) == EGL_FALSE) { |
1300 // This will cause tearing, but is safe otherwise. | 1414 // This will cause tearing, but is safe otherwise. |
(...skipping 10 matching lines...) Expand all Loading... | |
1311 std::unique_ptr<struct v4l2_plane[]> qbuf_planes( | 1425 std::unique_ptr<struct v4l2_plane[]> qbuf_planes( |
1312 new v4l2_plane[output_planes_count_]); | 1426 new v4l2_plane[output_planes_count_]); |
1313 memset(&qbuf, 0, sizeof(qbuf)); | 1427 memset(&qbuf, 0, sizeof(qbuf)); |
1314 memset(qbuf_planes.get(), 0, | 1428 memset(qbuf_planes.get(), 0, |
1315 sizeof(struct v4l2_plane) * output_planes_count_); | 1429 sizeof(struct v4l2_plane) * output_planes_count_); |
1316 qbuf.index = buffer; | 1430 qbuf.index = buffer; |
1317 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1431 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1318 qbuf.memory = V4L2_MEMORY_MMAP; | 1432 qbuf.memory = V4L2_MEMORY_MMAP; |
1319 qbuf.m.planes = qbuf_planes.get(); | 1433 qbuf.m.planes = qbuf_planes.get(); |
1320 qbuf.length = output_planes_count_; | 1434 qbuf.length = output_planes_count_; |
1435 DVLOGF(2) << "qbuf.index=" << qbuf.index | |
1436 << ", output_mode_=" << static_cast<int>(output_mode_) | |
1437 << ", output_planes_count_=" << output_planes_count_; | |
1321 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 1438 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
1322 free_output_buffers_.pop(); | 1439 free_output_buffers_.pop_front(); |
1323 output_record.state = kAtDevice; | 1440 output_record.state = kAtDevice; |
1324 output_buffer_queued_count_++; | 1441 output_buffer_queued_count_++; |
1325 return true; | 1442 return true; |
1326 } | 1443 } |
1327 | 1444 |
1328 void V4L2VideoDecodeAccelerator::ReusePictureBufferTask( | 1445 void V4L2VideoDecodeAccelerator::ReusePictureBufferTask( |
1329 int32_t picture_buffer_id, | 1446 int32_t picture_buffer_id, |
1330 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref) { | 1447 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref) { |
1331 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; | 1448 DVLOGF(3) << "picture_buffer_id=" << picture_buffer_id; |
1332 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 1449 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
(...skipping 27 matching lines...) Expand all Loading... | |
1360 } | 1477 } |
1361 | 1478 |
1362 OutputRecord& output_record = output_buffer_map_[index]; | 1479 OutputRecord& output_record = output_buffer_map_[index]; |
1363 if (output_record.state != kAtClient) { | 1480 if (output_record.state != kAtClient) { |
1364 LOGF(ERROR) << "picture_buffer_id not reusable"; | 1481 LOGF(ERROR) << "picture_buffer_id not reusable"; |
1365 NOTIFY_ERROR(INVALID_ARGUMENT); | 1482 NOTIFY_ERROR(INVALID_ARGUMENT); |
1366 return; | 1483 return; |
1367 } | 1484 } |
1368 | 1485 |
1369 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 1486 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
1370 output_record.egl_sync = egl_sync_ref->egl_sync; | |
1371 output_record.state = kFree; | 1487 output_record.state = kFree; |
1372 free_output_buffers_.push(index); | 1488 free_output_buffers_.push_back(index); |
1373 decoder_frames_at_client_--; | 1489 decoder_frames_at_client_--; |
1374 // Take ownership of the EGLSync. | 1490 if (egl_sync_ref) { |
1375 egl_sync_ref->egl_sync = EGL_NO_SYNC_KHR; | 1491 output_record.egl_sync = egl_sync_ref->egl_sync; |
1492 // Take ownership of the EGLSync. | |
1493 egl_sync_ref->egl_sync = EGL_NO_SYNC_KHR; | |
1494 } | |
1376 // We got a buffer back, so enqueue it back. | 1495 // We got a buffer back, so enqueue it back. |
1377 Enqueue(); | 1496 Enqueue(); |
1378 } | 1497 } |
1379 | 1498 |
1380 void V4L2VideoDecodeAccelerator::FlushTask() { | 1499 void V4L2VideoDecodeAccelerator::FlushTask() { |
1381 DVLOGF(3); | 1500 DVLOGF(3); |
1382 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 1501 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
1383 TRACE_EVENT0("Video Decoder", "V4L2VDA::FlushTask"); | 1502 TRACE_EVENT0("Video Decoder", "V4L2VDA::FlushTask"); |
1384 | 1503 |
1385 // Flush outstanding buffers. | 1504 // Flush outstanding buffers. |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1631 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF, &type); | 1750 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF, &type); |
1632 output_streamon_ = false; | 1751 output_streamon_ = false; |
1633 | 1752 |
1634 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 1753 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
1635 // After streamoff, the device drops ownership of all buffers, even if we | 1754 // After streamoff, the device drops ownership of all buffers, even if we |
1636 // don't dequeue them explicitly. Some of them may still be owned by the | 1755 // don't dequeue them explicitly. Some of them may still be owned by the |
1637 // client however. Reuse only those that aren't. | 1756 // client however. Reuse only those that aren't. |
1638 OutputRecord& output_record = output_buffer_map_[i]; | 1757 OutputRecord& output_record = output_buffer_map_[i]; |
1639 if (output_record.state == kAtDevice) { | 1758 if (output_record.state == kAtDevice) { |
1640 output_record.state = kFree; | 1759 output_record.state = kFree; |
1641 free_output_buffers_.push(i); | 1760 free_output_buffers_.push_back(i); |
1642 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); | 1761 DCHECK_EQ(output_record.egl_sync, EGL_NO_SYNC_KHR); |
1643 } | 1762 } |
1644 } | 1763 } |
1645 output_buffer_queued_count_ = 0; | 1764 output_buffer_queued_count_ = 0; |
1646 return true; | 1765 return true; |
1647 } | 1766 } |
1648 | 1767 |
1649 bool V4L2VideoDecodeAccelerator::StopInputStream() { | 1768 bool V4L2VideoDecodeAccelerator::StopInputStream() { |
1650 DVLOGF(3); | 1769 DVLOGF(3); |
1651 if (!input_streamon_) | 1770 if (!input_streamon_) |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1701 void V4L2VideoDecodeAccelerator::FinishResolutionChange() { | 1820 void V4L2VideoDecodeAccelerator::FinishResolutionChange() { |
1702 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 1821 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
1703 DCHECK_EQ(decoder_state_, kChangingResolution); | 1822 DCHECK_EQ(decoder_state_, kChangingResolution); |
1704 DVLOGF(3); | 1823 DVLOGF(3); |
1705 | 1824 |
1706 if (decoder_state_ == kError) { | 1825 if (decoder_state_ == kError) { |
1707 DVLOGF(2) << "early out: kError state"; | 1826 DVLOGF(2) << "early out: kError state"; |
1708 return; | 1827 return; |
1709 } | 1828 } |
1710 | 1829 |
1830 DestroyOutputBuffers(); | |
1831 | |
1711 struct v4l2_format format; | 1832 struct v4l2_format format; |
1712 bool again; | 1833 bool again; |
1713 gfx::Size visible_size; | 1834 gfx::Size visible_size; |
1714 bool ret = GetFormatInfo(&format, &visible_size, &again); | 1835 bool ret = GetFormatInfo(&format, &visible_size, &again); |
1715 if (!ret || again) { | 1836 if (!ret || again) { |
1716 LOGF(ERROR) << "Couldn't get format information after resolution change"; | 1837 LOGF(ERROR) << "Couldn't get format information after resolution change"; |
1717 NOTIFY_ERROR(PLATFORM_FAILURE); | 1838 NOTIFY_ERROR(PLATFORM_FAILURE); |
1718 return; | 1839 return; |
1719 } | 1840 } |
1720 | 1841 |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1830 &egl_image_planes_count_)) { | 1951 &egl_image_planes_count_)) { |
1831 LOGF(ERROR) << "Fail to get output size and plane count of processor"; | 1952 LOGF(ERROR) << "Fail to get output size and plane count of processor"; |
1832 return false; | 1953 return false; |
1833 } | 1954 } |
1834 } else { | 1955 } else { |
1835 egl_image_size_ = coded_size_; | 1956 egl_image_size_ = coded_size_; |
1836 egl_image_planes_count_ = output_planes_count_; | 1957 egl_image_planes_count_ = output_planes_count_; |
1837 } | 1958 } |
1838 DVLOGF(3) << "new resolution: " << coded_size_.ToString() | 1959 DVLOGF(3) << "new resolution: " << coded_size_.ToString() |
1839 << ", visible size: " << visible_size_.ToString() | 1960 << ", visible size: " << visible_size_.ToString() |
1840 << ", EGLImage size: " << egl_image_size_.ToString(); | 1961 << ", EGLImage size: " << egl_image_size_.ToString() |
1962 << ", plane count: " << egl_image_planes_count_; | |
1841 | 1963 |
1842 return CreateOutputBuffers(); | 1964 return CreateOutputBuffers(); |
1843 } | 1965 } |
1844 | 1966 |
1845 gfx::Size V4L2VideoDecodeAccelerator::GetVisibleSize( | 1967 gfx::Size V4L2VideoDecodeAccelerator::GetVisibleSize( |
1846 const gfx::Size& coded_size) { | 1968 const gfx::Size& coded_size) { |
1847 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 1969 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
1848 | 1970 |
1849 struct v4l2_crop crop_arg; | 1971 struct v4l2_crop crop_arg; |
1850 memset(&crop_arg, 0, sizeof(crop_arg)); | 1972 memset(&crop_arg, 0, sizeof(crop_arg)); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1996 LOGF(ERROR) << "Can't find a usable input format from image processor"; | 2118 LOGF(ERROR) << "Can't find a usable input format from image processor"; |
1997 return false; | 2119 return false; |
1998 } | 2120 } |
1999 egl_image_format_fourcc_ = FindImageProcessorOutputFormat(); | 2121 egl_image_format_fourcc_ = FindImageProcessorOutputFormat(); |
2000 if (egl_image_format_fourcc_ == 0) { | 2122 if (egl_image_format_fourcc_ == 0) { |
2001 LOGF(ERROR) << "Can't find a usable output format from image processor"; | 2123 LOGF(ERROR) << "Can't find a usable output format from image processor"; |
2002 return false; | 2124 return false; |
2003 } | 2125 } |
2004 egl_image_device_ = image_processor_device_; | 2126 egl_image_device_ = image_processor_device_; |
2005 } else { | 2127 } else { |
2128 if (output_mode_ == Config::OutputMode::IMPORT) { | |
2129 LOGF(ERROR) << "Import mode is unsupported without image processor."; | |
2130 return false; | |
2131 } | |
2006 egl_image_format_fourcc_ = output_format_fourcc_; | 2132 egl_image_format_fourcc_ = output_format_fourcc_; |
2007 egl_image_device_ = device_; | 2133 egl_image_device_ = device_; |
2008 } | 2134 } |
2009 DVLOGF(2) << "Output format=" << output_format_fourcc_; | 2135 DVLOGF(2) << "Output format=" << output_format_fourcc_; |
2010 | 2136 |
2011 // Just set the fourcc for output; resolution, etc., will come from the | 2137 // Just set the fourcc for output; resolution, etc., will come from the |
2012 // driver once it extracts it from the stream. | 2138 // driver once it extracts it from the stream. |
2013 memset(&format, 0, sizeof(format)); | 2139 memset(&format, 0, sizeof(format)); |
2014 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 2140 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
2015 format.fmt.pix_mp.pixelformat = output_format_fourcc_; | 2141 format.fmt.pix_mp.pixelformat = output_format_fourcc_; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2062 for (uint32_t processor_output_format : processor_output_formats) { | 2188 for (uint32_t processor_output_format : processor_output_formats) { |
2063 if (device_->CanCreateEGLImageFrom(processor_output_format)) { | 2189 if (device_->CanCreateEGLImageFrom(processor_output_format)) { |
2064 DVLOGF(1) << "Image processor output format=" << processor_output_format; | 2190 DVLOGF(1) << "Image processor output format=" << processor_output_format; |
2065 return processor_output_format; | 2191 return processor_output_format; |
2066 } | 2192 } |
2067 } | 2193 } |
2068 | 2194 |
2069 return 0; | 2195 return 0; |
2070 } | 2196 } |
2071 | 2197 |
2198 bool V4L2VideoDecodeAccelerator::CreateImageProcessor() { | |
2199 DVLOGF(3); | |
2200 DCHECK(!image_processor_); | |
2201 image_processor_.reset(new V4L2ImageProcessor(image_processor_device_)); | |
2202 v4l2_memory output_memory_type = | |
2203 (output_mode_ == Config::OutputMode::ALLOCATE ? V4L2_MEMORY_MMAP | |
2204 : V4L2_MEMORY_DMABUF); | |
2205 // Unretained is safe because |this| owns image processor and there will be | |
2206 // no callbacks after processor destroys. | |
2207 if (!image_processor_->Initialize( | |
2208 V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_), | |
2209 V4L2Device::V4L2PixFmtToVideoPixelFormat(egl_image_format_fourcc_), | |
2210 V4L2_MEMORY_DMABUF, output_memory_type, visible_size_, coded_size_, | |
2211 visible_size_, egl_image_size_, output_buffer_map_.size(), | |
2212 base::Bind(&V4L2VideoDecodeAccelerator::ImageProcessorError, | |
2213 base::Unretained(this)))) { | |
2214 LOGF(ERROR) << "Initialize image processor failed"; | |
2215 NOTIFY_ERROR(PLATFORM_FAILURE); | |
2216 return false; | |
2217 } | |
2218 DCHECK(image_processor_->output_allocated_size() == egl_image_size_); | |
2219 DVLOGF(3) << "image_processor_->output_allocated_size()=" | |
2220 << image_processor_->output_allocated_size().ToString(); | |
2221 if (image_processor_->input_allocated_size() != coded_size_) { | |
2222 LOGF(ERROR) << "Image processor should be able to take the output coded " | |
2223 << "size of decoder " << coded_size_.ToString() | |
2224 << " without adjusting to " | |
2225 << image_processor_->input_allocated_size().ToString(); | |
2226 NOTIFY_ERROR(PLATFORM_FAILURE); | |
2227 return false; | |
2228 } | |
2229 return true; | |
2230 } | |
2231 | |
2232 bool V4L2VideoDecodeAccelerator::ProcessFrame(int32_t bitstream_buffer_id, | |
2233 int output_buffer_index) { | |
2234 DVLOGF(3); | |
2235 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | |
2236 | |
2237 OutputRecord& output_record = output_buffer_map_[output_buffer_index]; | |
2238 output_record.state = kAtProcessor; | |
2239 image_processor_bitstream_buffer_ids_.push(bitstream_buffer_id); | |
2240 std::vector<int> processor_input_fds; | |
2241 for (auto& fd : output_record.processor_input_fds) { | |
2242 processor_input_fds.push_back(fd.get()); | |
2243 } | |
2244 scoped_refptr<VideoFrame> input_frame = VideoFrame::WrapExternalDmabufs( | |
2245 V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc_), | |
2246 coded_size_, gfx::Rect(visible_size_), visible_size_, processor_input_fds, | |
2247 base::TimeDelta()); | |
2248 | |
2249 std::vector<base::ScopedFD> processor_output_fds; | |
2250 if (output_mode_ == Config::OutputMode::IMPORT) { | |
2251 for (auto& fd : output_record.processor_output_fds) { | |
2252 processor_output_fds.push_back( | |
2253 base::ScopedFD(HANDLE_EINTR(dup(fd.get())))); | |
2254 if (!processor_output_fds.back().is_valid()) { | |
2255 PLOGF(ERROR) << "Failed duplicating a dmabuf fd"; | |
2256 return false; | |
2257 } | |
2258 } | |
2259 } | |
2260 // Unretained is safe because |this| owns image processor and there will | |
2261 // be no callbacks after processor destroys. Also, this class ensures it | |
2262 // is safe to post a task from child thread to decoder thread using | |
2263 // Unretained. | |
2264 image_processor_->Process( | |
2265 input_frame, output_buffer_index, std::move(processor_output_fds), | |
2266 BindToCurrentLoop(base::Bind(&V4L2VideoDecodeAccelerator::FrameProcessed, | |
2267 base::Unretained(this), | |
2268 bitstream_buffer_id))); | |
2269 return true; | |
2270 } | |
2271 | |
2072 bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { | 2272 bool V4L2VideoDecodeAccelerator::CreateOutputBuffers() { |
2073 DVLOGF(3); | 2273 DVLOGF(3); |
2074 DCHECK(decoder_state_ == kInitialized || | 2274 DCHECK(decoder_state_ == kInitialized || |
2075 decoder_state_ == kChangingResolution); | 2275 decoder_state_ == kChangingResolution); |
2076 DCHECK(!output_streamon_); | 2276 DCHECK(!output_streamon_); |
2077 DCHECK(output_buffer_map_.empty()); | 2277 DCHECK(output_buffer_map_.empty()); |
2078 | 2278 |
2079 // Number of output buffers we need. | 2279 // Number of output buffers we need. |
2080 struct v4l2_control ctrl; | 2280 struct v4l2_control ctrl; |
2081 memset(&ctrl, 0, sizeof(ctrl)); | 2281 memset(&ctrl, 0, sizeof(ctrl)); |
2082 ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE; | 2282 ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE; |
2083 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_CTRL, &ctrl); | 2283 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_CTRL, &ctrl); |
2084 output_dpb_size_ = ctrl.value; | 2284 output_dpb_size_ = ctrl.value; |
2085 | 2285 |
2086 // Output format setup in Initialize(). | 2286 // Output format setup in Initialize(). |
2087 | 2287 |
2088 const uint32_t buffer_count = output_dpb_size_ + kDpbOutputBufferExtraCount; | 2288 const uint32_t buffer_count = output_dpb_size_ + kDpbOutputBufferExtraCount; |
2089 DVLOGF(3) << "buffer_count=" << buffer_count | 2289 DVLOGF(3) << "buffer_count=" << buffer_count |
2090 << ", coded_size=" << egl_image_size_.ToString(); | 2290 << ", coded_size=" << egl_image_size_.ToString(); |
2091 | 2291 |
2292 // With ALLOCATE mode the client can sample it as RGB and doesn't need to | |
2293 // know the precise format. | |
2294 VideoPixelFormat pixel_format = | |
2295 (output_mode_ == Config::OutputMode::IMPORT) | |
2296 ? V4L2Device::V4L2PixFmtToVideoPixelFormat(egl_image_format_fourcc_) | |
2297 : PIXEL_FORMAT_UNKNOWN; | |
2298 | |
2092 child_task_runner_->PostTask( | 2299 child_task_runner_->PostTask( |
2093 FROM_HERE, base::Bind(&Client::ProvidePictureBuffers, client_, | 2300 FROM_HERE, base::Bind(&Client::ProvidePictureBuffers, client_, |
2094 buffer_count, PIXEL_FORMAT_UNKNOWN, 1, | 2301 buffer_count, pixel_format, 1, egl_image_size_, |
2095 egl_image_size_, device_->GetTextureTarget())); | 2302 device_->GetTextureTarget())); |
2096 | 2303 |
2097 // Go into kAwaitingPictureBuffers to prevent us from doing any more decoding | 2304 // Go into kAwaitingPictureBuffers to prevent us from doing any more decoding |
2098 // or event handling while we are waiting for AssignPictureBuffers(). Not | 2305 // or event handling while we are waiting for AssignPictureBuffers(). Not |
2099 // having Pictures available would not have prevented us from making decoding | 2306 // having Pictures available would not have prevented us from making decoding |
2100 // progress entirely e.g. in the case of H.264 where we could further decode | 2307 // progress entirely e.g. in the case of H.264 where we could further decode |
2101 // non-slice NALUs and could even get another resolution change before we were | 2308 // non-slice NALUs and could even get another resolution change before we were |
2102 // done with this one. After we get the buffers, we'll go back into kIdle and | 2309 // done with this one. After we get the buffers, we'll go back into kIdle and |
2103 // kick off further event processing, and eventually go back into kDecoding | 2310 // kick off further event processing, and eventually go back into kDecoding |
2104 // once no more events are pending (if any). | 2311 // once no more events are pending (if any). |
2105 decoder_state_ = kAwaitingPictureBuffers; | 2312 decoder_state_ = kAwaitingPictureBuffers; |
(...skipping 18 matching lines...) Expand all Loading... | |
2124 reqbufs.count = 0; | 2331 reqbufs.count = 0; |
2125 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 2332 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
2126 reqbufs.memory = V4L2_MEMORY_MMAP; | 2333 reqbufs.memory = V4L2_MEMORY_MMAP; |
2127 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 2334 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
2128 | 2335 |
2129 input_buffer_map_.clear(); | 2336 input_buffer_map_.clear(); |
2130 free_input_buffers_.clear(); | 2337 free_input_buffers_.clear(); |
2131 } | 2338 } |
2132 | 2339 |
2133 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { | 2340 bool V4L2VideoDecodeAccelerator::DestroyOutputBuffers() { |
2341 struct v4l2_requestbuffers reqbufs; | |
2342 memset(&reqbufs, 0, sizeof(reqbufs)); | |
2343 reqbufs.count = 0; | |
2344 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
2345 reqbufs.memory = V4L2_MEMORY_MMAP; | |
2346 if (device_->Ioctl(VIDIOC_REQBUFS, &reqbufs) != 0) { | |
2347 PLOGF(ERROR) << "ioctl() failed: VIDIOC_REQBUFS"; | |
2348 NOTIFY_ERROR(PLATFORM_FAILURE); | |
2349 return false; | |
2350 } | |
2351 | |
2352 output_buffer_map_.clear(); | |
2353 while (!free_output_buffers_.empty()) | |
2354 free_output_buffers_.pop_front(); | |
2355 output_buffer_queued_count_ = 0; | |
2356 // The client may still hold some buffers. The texture holds a reference to | |
2357 // the buffer. It is OK to free the buffer and destroy EGLImage here. | |
2358 decoder_frames_at_client_ = 0; | |
2359 return true; | |
2360 } | |
2361 | |
2362 bool V4L2VideoDecodeAccelerator::DestroyEGLImages() { | |
2134 DVLOGF(3); | 2363 DVLOGF(3); |
2135 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 2364 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
2136 DCHECK(!output_streamon_); | 2365 DCHECK(!output_streamon_); |
2137 bool success = true; | 2366 bool success = true; |
2138 | 2367 |
2139 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { | 2368 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { |
2140 OutputRecord& output_record = output_buffer_map_[i]; | 2369 OutputRecord& output_record = output_buffer_map_[i]; |
2141 | 2370 |
2142 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { | 2371 if (output_record.egl_image != EGL_NO_IMAGE_KHR) { |
2143 if (egl_image_device_->DestroyEGLImage( | 2372 if (egl_image_device_->DestroyEGLImage( |
2144 egl_display_, output_record.egl_image) != EGL_TRUE) { | 2373 egl_display_, output_record.egl_image) != EGL_TRUE) { |
2145 DVLOGF(1) << "DestroyEGLImage failed."; | 2374 DVLOGF(1) << "DestroyEGLImage failed."; |
2146 success = false; | 2375 success = false; |
2147 } | 2376 } |
2148 } | 2377 } |
2149 | 2378 |
2150 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { | 2379 if (output_record.egl_sync != EGL_NO_SYNC_KHR) { |
2151 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { | 2380 if (eglDestroySyncKHR(egl_display_, output_record.egl_sync) != EGL_TRUE) { |
2152 DVLOGF(1) << "eglDestroySyncKHR failed."; | 2381 DVLOGF(1) << "eglDestroySyncKHR failed."; |
2153 success = false; | 2382 success = false; |
2154 } | 2383 } |
2155 } | 2384 } |
2156 | 2385 |
2157 DVLOGF(1) << "dismissing PictureBuffer id=" << output_record.picture_id; | 2386 DVLOGF(1) << "dismissing PictureBuffer id=" << output_record.picture_id; |
2158 child_task_runner_->PostTask( | 2387 child_task_runner_->PostTask( |
2159 FROM_HERE, base::Bind(&Client::DismissPictureBuffer, client_, | 2388 FROM_HERE, base::Bind(&Client::DismissPictureBuffer, client_, |
2160 output_record.picture_id)); | 2389 output_record.picture_id)); |
2161 } | 2390 } |
2162 | 2391 |
2163 struct v4l2_requestbuffers reqbufs; | |
2164 memset(&reqbufs, 0, sizeof(reqbufs)); | |
2165 reqbufs.count = 0; | |
2166 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
2167 reqbufs.memory = V4L2_MEMORY_MMAP; | |
2168 if (device_->Ioctl(VIDIOC_REQBUFS, &reqbufs) != 0) { | |
2169 PLOGF(ERROR) << "ioctl() failed: VIDIOC_REQBUFS"; | |
2170 success = false; | |
2171 } | |
2172 | |
2173 output_buffer_map_.clear(); | |
2174 while (!free_output_buffers_.empty()) | |
2175 free_output_buffers_.pop(); | |
2176 output_buffer_queued_count_ = 0; | |
2177 // The client may still hold some buffers. The texture holds a reference to | |
2178 // the buffer. It is OK to free the buffer and destroy EGLImage here. | |
2179 decoder_frames_at_client_ = 0; | |
2180 | |
2181 return success; | 2392 return success; |
2182 } | 2393 } |
2183 | 2394 |
2184 void V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers() { | 2395 void V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers() { |
2185 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 2396 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
2186 DVLOGF(3); | 2397 DVLOGF(3); |
2187 | 2398 |
2188 if (!DestroyOutputBuffers()) { | 2399 if (!DestroyEGLImages()) { |
2189 LOGF(ERROR) << "Failed destroying output buffers."; | 2400 LOGF(ERROR) << "Failed destroying output buffers."; |
2190 NOTIFY_ERROR(PLATFORM_FAILURE); | 2401 NOTIFY_ERROR(PLATFORM_FAILURE); |
2191 return; | 2402 return; |
2192 } | 2403 } |
2193 | 2404 |
2194 // Finish resolution change on decoder thread. | 2405 // Finish resolution change on decoder thread. |
2195 decoder_thread_.task_runner()->PostTask( | 2406 decoder_thread_.task_runner()->PostTask( |
2196 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::FinishResolutionChange, | 2407 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::FinishResolutionChange, |
2197 base::Unretained(this))); | 2408 base::Unretained(this))); |
2198 } | 2409 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2253 << ", bitstream_buffer_id=" << bitstream_buffer_id; | 2464 << ", bitstream_buffer_id=" << bitstream_buffer_id; |
2254 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 2465 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
2255 DCHECK_GE(output_buffer_index, 0); | 2466 DCHECK_GE(output_buffer_index, 0); |
2256 DCHECK_LT(output_buffer_index, static_cast<int>(output_buffer_map_.size())); | 2467 DCHECK_LT(output_buffer_index, static_cast<int>(output_buffer_map_.size())); |
2257 | 2468 |
2258 OutputRecord& output_record = output_buffer_map_[output_buffer_index]; | 2469 OutputRecord& output_record = output_buffer_map_[output_buffer_index]; |
2259 DCHECK_EQ(output_record.state, kAtProcessor); | 2470 DCHECK_EQ(output_record.state, kAtProcessor); |
2260 if (!image_processor_bitstream_buffer_ids_.empty() && | 2471 if (!image_processor_bitstream_buffer_ids_.empty() && |
2261 image_processor_bitstream_buffer_ids_.front() == bitstream_buffer_id) { | 2472 image_processor_bitstream_buffer_ids_.front() == bitstream_buffer_id) { |
2262 DVLOGF(3) << "picture_id=" << output_record.picture_id; | 2473 DVLOGF(3) << "picture_id=" << output_record.picture_id; |
2263 DCHECK_NE(output_record.egl_image, EGL_NO_IMAGE_KHR); | |
2264 DCHECK_NE(output_record.picture_id, -1); | 2474 DCHECK_NE(output_record.picture_id, -1); |
2265 // Send the processed frame to render. | 2475 // Send the processed frame to render. |
2266 output_record.state = kAtClient; | 2476 output_record.state = kAtClient; |
2267 decoder_frames_at_client_++; | 2477 decoder_frames_at_client_++; |
2268 image_processor_bitstream_buffer_ids_.pop(); | 2478 image_processor_bitstream_buffer_ids_.pop(); |
2269 const Picture picture(output_record.picture_id, bitstream_buffer_id, | 2479 const Picture picture(output_record.picture_id, bitstream_buffer_id, |
2270 gfx::Rect(visible_size_), false); | 2480 gfx::Rect(visible_size_), false); |
2271 pending_picture_ready_.push(PictureRecord(output_record.cleared, picture)); | 2481 pending_picture_ready_.push(PictureRecord(output_record.cleared, picture)); |
2272 SendPictureReady(); | 2482 SendPictureReady(); |
2273 output_record.cleared = true; | 2483 output_record.cleared = true; |
2274 // Flush or resolution change may be waiting image processor to finish. | 2484 // Flush or resolution change may be waiting image processor to finish. |
2275 if (image_processor_bitstream_buffer_ids_.empty()) { | 2485 if (image_processor_bitstream_buffer_ids_.empty()) { |
2276 NotifyFlushDoneIfNeeded(); | 2486 NotifyFlushDoneIfNeeded(); |
2277 if (decoder_state_ == kChangingResolution) | 2487 if (decoder_state_ == kChangingResolution) |
2278 StartResolutionChange(); | 2488 StartResolutionChange(); |
2279 } | 2489 } |
2280 } else { | 2490 } else { |
2281 DVLOGF(2) << "Bitstream buffer id " << bitstream_buffer_id << " not found " | 2491 DVLOGF(2) << "Bitstream buffer id " << bitstream_buffer_id << " not found " |
2282 << "because of Reset. Drop the buffer"; | 2492 << "because of Reset. Drop the buffer"; |
2283 output_record.state = kFree; | 2493 output_record.state = kFree; |
2284 free_output_buffers_.push(output_buffer_index); | 2494 free_output_buffers_.push_back(output_buffer_index); |
2285 // Do not queue the buffer if a resolution change is in progress. The queue | 2495 // Do not queue the buffer if a resolution change is in progress. The queue |
2286 // is about to be destroyed anyway. Otherwise, the queue will be started in | 2496 // is about to be destroyed anyway. Otherwise, the queue will be started in |
2287 // Enqueue and REQBUFS(0) will fail. | 2497 // Enqueue and REQBUFS(0) will fail. |
2288 if (decoder_state_ != kChangingResolution) | 2498 if (decoder_state_ != kChangingResolution) |
2289 Enqueue(); | 2499 Enqueue(); |
2290 } | 2500 } |
2291 } | 2501 } |
2292 | 2502 |
2293 void V4L2VideoDecodeAccelerator::ImageProcessorError() { | 2503 void V4L2VideoDecodeAccelerator::ImageProcessorError() { |
2294 LOGF(ERROR) << "Image processor error"; | 2504 LOGF(ERROR) << "Image processor error"; |
2295 NOTIFY_ERROR(PLATFORM_FAILURE); | 2505 NOTIFY_ERROR(PLATFORM_FAILURE); |
2296 } | 2506 } |
2297 | 2507 |
2298 } // namespace media | 2508 } // namespace media |
OLD | NEW |