| 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 "content/common/gpu/media/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/thread_task_runner_handle.h" | 21 #include "base/thread_task_runner_handle.h" |
| 22 #include "base/trace_event/trace_event.h" | 22 #include "base/trace_event/trace_event.h" |
| 23 #include "build/build_config.h" | 23 #include "build/build_config.h" |
| 24 #include "content/common/gpu/media/shared_memory_region.h" | |
| 25 #include "media/base/bind_to_current_loop.h" | 24 #include "media/base/bind_to_current_loop.h" |
| 26 #include "media/base/media_switches.h" | 25 #include "media/base/media_switches.h" |
| 27 #include "media/filters/h264_parser.h" | 26 #include "media/filters/h264_parser.h" |
| 27 #include "media/gpu/shared_memory_region.h" |
| 28 #include "ui/gfx/geometry/rect.h" | 28 #include "ui/gfx/geometry/rect.h" |
| 29 #include "ui/gl/gl_context.h" | 29 #include "ui/gl/gl_context.h" |
| 30 #include "ui/gl/scoped_binders.h" | 30 #include "ui/gl/scoped_binders.h" |
| 31 | 31 |
| 32 #define NOTIFY_ERROR(x) \ | 32 #define NOTIFY_ERROR(x) \ |
| 33 do { \ | 33 do { \ |
| 34 LOG(ERROR) << "Setting error state:" << x; \ | 34 LOG(ERROR) << "Setting error state:" << x; \ |
| 35 SetErrorState(x); \ | 35 SetErrorState(x); \ |
| 36 } while (0) | 36 } while (0) |
| 37 | 37 |
| 38 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \ | 38 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \ |
| 39 do { \ | 39 do { \ |
| 40 if (device_->Ioctl(type, arg) != 0) { \ | 40 if (device_->Ioctl(type, arg) != 0) { \ |
| 41 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << type_str; \ | 41 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << type_str; \ |
| 42 NOTIFY_ERROR(PLATFORM_FAILURE); \ | 42 NOTIFY_ERROR(PLATFORM_FAILURE); \ |
| 43 return value; \ | 43 return value; \ |
| 44 } \ | 44 } \ |
| 45 } while (0) | 45 } while (0) |
| 46 | 46 |
| 47 #define IOCTL_OR_ERROR_RETURN(type, arg) \ | 47 #define IOCTL_OR_ERROR_RETURN(type, arg) \ |
| 48 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0), #type) | 48 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0), #type) |
| 49 | 49 |
| 50 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \ | 50 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \ |
| 51 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type) | 51 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type) |
| 52 | 52 |
| 53 #define IOCTL_OR_LOG_ERROR(type, arg) \ | 53 #define IOCTL_OR_LOG_ERROR(type, arg) \ |
| 54 do { \ | 54 do { \ |
| 55 if (device_->Ioctl(type, arg) != 0) \ | 55 if (device_->Ioctl(type, arg) != 0) \ |
| 56 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ | 56 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ |
| 57 } while (0) | 57 } while (0) |
| 58 | 58 |
| 59 namespace content { | 59 namespace media { |
| 60 | 60 |
| 61 // static | 61 // static |
| 62 const uint32_t V4L2VideoDecodeAccelerator::supported_input_fourccs_[] = { | 62 const uint32_t V4L2VideoDecodeAccelerator::supported_input_fourccs_[] = { |
| 63 V4L2_PIX_FMT_H264, V4L2_PIX_FMT_VP8, V4L2_PIX_FMT_VP9, | 63 V4L2_PIX_FMT_H264, V4L2_PIX_FMT_VP8, V4L2_PIX_FMT_VP9, |
| 64 }; | 64 }; |
| 65 | 65 |
| 66 struct V4L2VideoDecodeAccelerator::BitstreamBufferRef { | 66 struct V4L2VideoDecodeAccelerator::BitstreamBufferRef { |
| 67 BitstreamBufferRef( | 67 BitstreamBufferRef( |
| 68 base::WeakPtr<Client>& client, | 68 base::WeakPtr<Client>& client, |
| 69 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, | 69 scoped_refptr<base::SingleThreadTaskRunner>& client_task_runner, |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 input_id(input_id) {} | 103 input_id(input_id) {} |
| 104 | 104 |
| 105 V4L2VideoDecodeAccelerator::BitstreamBufferRef::~BitstreamBufferRef() { | 105 V4L2VideoDecodeAccelerator::BitstreamBufferRef::~BitstreamBufferRef() { |
| 106 if (input_id >= 0) { | 106 if (input_id >= 0) { |
| 107 client_task_runner->PostTask( | 107 client_task_runner->PostTask( |
| 108 FROM_HERE, | 108 FROM_HERE, |
| 109 base::Bind(&Client::NotifyEndOfBitstreamBuffer, client, input_id)); | 109 base::Bind(&Client::NotifyEndOfBitstreamBuffer, client, input_id)); |
| 110 } | 110 } |
| 111 } | 111 } |
| 112 | 112 |
| 113 V4L2VideoDecodeAccelerator::EGLSyncKHRRef::EGLSyncKHRRef( | 113 V4L2VideoDecodeAccelerator::EGLSyncKHRRef::EGLSyncKHRRef(EGLDisplay egl_display, |
| 114 EGLDisplay egl_display, EGLSyncKHR egl_sync) | 114 EGLSyncKHR egl_sync) |
| 115 : egl_display(egl_display), | 115 : egl_display(egl_display), egl_sync(egl_sync) {} |
| 116 egl_sync(egl_sync) { | |
| 117 } | |
| 118 | 116 |
| 119 V4L2VideoDecodeAccelerator::EGLSyncKHRRef::~EGLSyncKHRRef() { | 117 V4L2VideoDecodeAccelerator::EGLSyncKHRRef::~EGLSyncKHRRef() { |
| 120 // We don't check for eglDestroySyncKHR failures, because if we get here | 118 // We don't check for eglDestroySyncKHR failures, because if we get here |
| 121 // with a valid sync object, something went wrong and we are getting | 119 // with a valid sync object, something went wrong and we are getting |
| 122 // destroyed anyway. | 120 // destroyed anyway. |
| 123 if (egl_sync != EGL_NO_SYNC_KHR) | 121 if (egl_sync != EGL_NO_SYNC_KHR) |
| 124 eglDestroySyncKHR(egl_display, egl_sync); | 122 eglDestroySyncKHR(egl_display, egl_sync); |
| 125 } | 123 } |
| 126 | 124 |
| 127 V4L2VideoDecodeAccelerator::InputRecord::InputRecord() | 125 V4L2VideoDecodeAccelerator::InputRecord::InputRecord() |
| 128 : at_device(false), | 126 : at_device(false), address(NULL), length(0), bytes_used(0), input_id(-1) {} |
| 129 address(NULL), | |
| 130 length(0), | |
| 131 bytes_used(0), | |
| 132 input_id(-1) { | |
| 133 } | |
| 134 | 127 |
| 135 V4L2VideoDecodeAccelerator::InputRecord::~InputRecord() { | 128 V4L2VideoDecodeAccelerator::InputRecord::~InputRecord() {} |
| 136 } | |
| 137 | 129 |
| 138 V4L2VideoDecodeAccelerator::OutputRecord::OutputRecord() | 130 V4L2VideoDecodeAccelerator::OutputRecord::OutputRecord() |
| 139 : state(kFree), | 131 : state(kFree), |
| 140 egl_image(EGL_NO_IMAGE_KHR), | 132 egl_image(EGL_NO_IMAGE_KHR), |
| 141 egl_sync(EGL_NO_SYNC_KHR), | 133 egl_sync(EGL_NO_SYNC_KHR), |
| 142 picture_id(-1), | 134 picture_id(-1), |
| 143 cleared(false) { | 135 cleared(false) {} |
| 144 } | |
| 145 | 136 |
| 146 V4L2VideoDecodeAccelerator::OutputRecord::~OutputRecord() {} | 137 V4L2VideoDecodeAccelerator::OutputRecord::~OutputRecord() {} |
| 147 | 138 |
| 148 V4L2VideoDecodeAccelerator::PictureRecord::PictureRecord( | 139 V4L2VideoDecodeAccelerator::PictureRecord::PictureRecord( |
| 149 bool cleared, | 140 bool cleared, |
| 150 const media::Picture& picture) | 141 const media::Picture& picture) |
| 151 : cleared(cleared), picture(picture) {} | 142 : cleared(cleared), picture(picture) {} |
| 152 | 143 |
| 153 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} | 144 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} |
| 154 | 145 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 return false; | 251 return false; |
| 261 } | 252 } |
| 262 #endif | 253 #endif |
| 263 | 254 |
| 264 // Capabilities check. | 255 // Capabilities check. |
| 265 struct v4l2_capability caps; | 256 struct v4l2_capability caps; |
| 266 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; | 257 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; |
| 267 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); | 258 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); |
| 268 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { | 259 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { |
| 269 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP" | 260 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP" |
| 270 ", caps check failed: 0x" << std::hex << caps.capabilities; | 261 ", caps check failed: 0x" |
| 262 << std::hex << caps.capabilities; |
| 271 return false; | 263 return false; |
| 272 } | 264 } |
| 273 | 265 |
| 274 if (!SetupFormats()) | 266 if (!SetupFormats()) |
| 275 return false; | 267 return false; |
| 276 | 268 |
| 277 // Subscribe to the resolution change event. | 269 // Subscribe to the resolution change event. |
| 278 struct v4l2_event_subscription sub; | 270 struct v4l2_event_subscription sub; |
| 279 memset(&sub, 0, sizeof(sub)); | 271 memset(&sub, 0, sizeof(sub)); |
| 280 sub.type = V4L2_EVENT_SOURCE_CHANGE; | 272 sub.type = V4L2_EVENT_SOURCE_CHANGE; |
| 281 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub); | 273 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_SUBSCRIBE_EVENT, &sub); |
| 282 | 274 |
| 283 if (video_profile_ >= media::H264PROFILE_MIN && | 275 if (video_profile_ >= media::H264PROFILE_MIN && |
| 284 video_profile_ <= media::H264PROFILE_MAX) { | 276 video_profile_ <= media::H264PROFILE_MAX) { |
| 285 decoder_h264_parser_.reset(new media::H264Parser()); | 277 decoder_h264_parser_.reset(new media::H264Parser()); |
| 286 } | 278 } |
| 287 | 279 |
| 288 if (!CreateInputBuffers()) | 280 if (!CreateInputBuffers()) |
| 289 return false; | 281 return false; |
| 290 | 282 |
| 291 if (!decoder_thread_.Start()) { | 283 if (!decoder_thread_.Start()) { |
| 292 LOG(ERROR) << "Initialize(): decoder thread failed to start"; | 284 LOG(ERROR) << "Initialize(): decoder thread failed to start"; |
| 293 return false; | 285 return false; |
| 294 } | 286 } |
| 295 | 287 |
| 296 decoder_state_ = kInitialized; | 288 decoder_state_ = kInitialized; |
| 297 | 289 |
| 298 // StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here. | 290 // StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here. |
| 299 decoder_thread_.message_loop()->PostTask( | 291 decoder_thread_.message_loop()->PostTask( |
| 300 FROM_HERE, | 292 FROM_HERE, base::Bind(base::IgnoreResult( |
| 301 base::Bind( | 293 &V4L2VideoDecodeAccelerator::StartDevicePoll), |
| 302 base::IgnoreResult(&V4L2VideoDecodeAccelerator::StartDevicePoll), | 294 base::Unretained(this))); |
| 303 base::Unretained(this))); | |
| 304 | 295 |
| 305 return true; | 296 return true; |
| 306 } | 297 } |
| 307 | 298 |
| 308 void V4L2VideoDecodeAccelerator::Decode( | 299 void V4L2VideoDecodeAccelerator::Decode( |
| 309 const media::BitstreamBuffer& bitstream_buffer) { | 300 const media::BitstreamBuffer& bitstream_buffer) { |
| 310 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() | 301 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() |
| 311 << ", size=" << bitstream_buffer.size(); | 302 << ", size=" << bitstream_buffer.size(); |
| 312 DCHECK(decode_task_runner_->BelongsToCurrentThread()); | 303 DCHECK(decode_task_runner_->BelongsToCurrentThread()); |
| 313 | 304 |
| 314 if (bitstream_buffer.id() < 0) { | 305 if (bitstream_buffer.id() < 0) { |
| 315 LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); | 306 LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id(); |
| 316 if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) | 307 if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle())) |
| 317 base::SharedMemory::CloseHandle(bitstream_buffer.handle()); | 308 base::SharedMemory::CloseHandle(bitstream_buffer.handle()); |
| 318 NOTIFY_ERROR(INVALID_ARGUMENT); | 309 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 319 return; | 310 return; |
| 320 } | 311 } |
| 321 | 312 |
| 322 // DecodeTask() will take care of running a DecodeBufferTask(). | 313 // DecodeTask() will take care of running a DecodeBufferTask(). |
| 323 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 314 decoder_thread_.message_loop()->PostTask( |
| 324 &V4L2VideoDecodeAccelerator::DecodeTask, base::Unretained(this), | 315 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::DecodeTask, |
| 325 bitstream_buffer)); | 316 base::Unretained(this), bitstream_buffer)); |
| 326 } | 317 } |
| 327 | 318 |
| 328 void V4L2VideoDecodeAccelerator::AssignPictureBuffers( | 319 void V4L2VideoDecodeAccelerator::AssignPictureBuffers( |
| 329 const std::vector<media::PictureBuffer>& buffers) { | 320 const std::vector<media::PictureBuffer>& buffers) { |
| 330 DVLOG(3) << "AssignPictureBuffers(): buffer_count=" << buffers.size(); | 321 DVLOG(3) << "AssignPictureBuffers(): buffer_count=" << buffers.size(); |
| 331 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 322 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 332 | 323 |
| 333 const uint32_t req_buffer_count = | 324 const uint32_t req_buffer_count = |
| 334 output_dpb_size_ + kDpbOutputBufferExtraCount; | 325 output_dpb_size_ + kDpbOutputBufferExtraCount; |
| 335 | 326 |
| 336 if (buffers.size() < req_buffer_count) { | 327 if (buffers.size() < req_buffer_count) { |
| 337 LOG(ERROR) << "AssignPictureBuffers(): Failed to provide requested picture" | 328 LOG(ERROR) << "AssignPictureBuffers(): Failed to provide requested picture" |
| 338 " buffers. (Got " << buffers.size() | 329 " buffers. (Got " |
| 339 << ", requested " << req_buffer_count << ")"; | 330 << buffers.size() << ", requested " << req_buffer_count << ")"; |
| 340 NOTIFY_ERROR(INVALID_ARGUMENT); | 331 NOTIFY_ERROR(INVALID_ARGUMENT); |
| 341 return; | 332 return; |
| 342 } | 333 } |
| 343 | 334 |
| 344 gfx::GLContext* gl_context = get_gl_context_cb_.Run(); | 335 gfx::GLContext* gl_context = get_gl_context_cb_.Run(); |
| 345 if (!gl_context || !make_context_current_cb_.Run()) { | 336 if (!gl_context || !make_context_current_cb_.Run()) { |
| 346 LOG(ERROR) << "AssignPictureBuffers(): could not make context current"; | 337 LOG(ERROR) << "AssignPictureBuffers(): could not make context current"; |
| 347 NOTIFY_ERROR(PLATFORM_FAILURE); | 338 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 348 return; | 339 return; |
| 349 } | 340 } |
| 350 | 341 |
| 351 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); | 342 gfx::ScopedTextureBinder bind_restore(GL_TEXTURE_EXTERNAL_OES, 0); |
| 352 | 343 |
| 353 // It's safe to manipulate all the buffer state here, because the decoder | 344 // It's safe to manipulate all the buffer state here, because the decoder |
| 354 // thread is waiting on pictures_assigned_. | 345 // thread is waiting on pictures_assigned_. |
| 355 | 346 |
| 356 // Allocate the output buffers. | 347 // Allocate the output buffers. |
| 357 struct v4l2_requestbuffers reqbufs; | 348 struct v4l2_requestbuffers reqbufs; |
| 358 memset(&reqbufs, 0, sizeof(reqbufs)); | 349 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 359 reqbufs.count = buffers.size(); | 350 reqbufs.count = buffers.size(); |
| 360 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 351 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 361 reqbufs.memory = V4L2_MEMORY_MMAP; | 352 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 362 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); | 353 IOCTL_OR_ERROR_RETURN(VIDIOC_REQBUFS, &reqbufs); |
| 363 | 354 |
| 364 if (reqbufs.count != buffers.size()) { | 355 if (reqbufs.count != buffers.size()) { |
| 365 DLOG(ERROR) << "Could not allocate enough output buffers"; | 356 DLOG(ERROR) << "Could not allocate enough output buffers"; |
| 366 NOTIFY_ERROR(PLATFORM_FAILURE); | 357 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 367 return; | 358 return; |
| 368 } | 359 } |
| 369 | 360 |
| 370 if (image_processor_device_) { | 361 if (image_processor_device_) { |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 egl_sync = eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); | 459 egl_sync = eglCreateSyncKHR(egl_display_, EGL_SYNC_FENCE_KHR, NULL); |
| 469 if (egl_sync == EGL_NO_SYNC_KHR) { | 460 if (egl_sync == EGL_NO_SYNC_KHR) { |
| 470 LOG(ERROR) << "ReusePictureBuffer(): eglCreateSyncKHR() failed"; | 461 LOG(ERROR) << "ReusePictureBuffer(): eglCreateSyncKHR() failed"; |
| 471 NOTIFY_ERROR(PLATFORM_FAILURE); | 462 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 472 return; | 463 return; |
| 473 } | 464 } |
| 474 #endif | 465 #endif |
| 475 | 466 |
| 476 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref( | 467 std::unique_ptr<EGLSyncKHRRef> egl_sync_ref( |
| 477 new EGLSyncKHRRef(egl_display_, egl_sync)); | 468 new EGLSyncKHRRef(egl_display_, egl_sync)); |
| 478 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 469 decoder_thread_.message_loop()->PostTask( |
| 479 &V4L2VideoDecodeAccelerator::ReusePictureBufferTask, | 470 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::ReusePictureBufferTask, |
| 480 base::Unretained(this), picture_buffer_id, base::Passed(&egl_sync_ref))); | 471 base::Unretained(this), picture_buffer_id, |
| 472 base::Passed(&egl_sync_ref))); |
| 481 } | 473 } |
| 482 | 474 |
| 483 void V4L2VideoDecodeAccelerator::Flush() { | 475 void V4L2VideoDecodeAccelerator::Flush() { |
| 484 DVLOG(3) << "Flush()"; | 476 DVLOG(3) << "Flush()"; |
| 485 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 477 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 486 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 478 decoder_thread_.message_loop()->PostTask( |
| 487 &V4L2VideoDecodeAccelerator::FlushTask, base::Unretained(this))); | 479 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::FlushTask, |
| 480 base::Unretained(this))); |
| 488 } | 481 } |
| 489 | 482 |
| 490 void V4L2VideoDecodeAccelerator::Reset() { | 483 void V4L2VideoDecodeAccelerator::Reset() { |
| 491 DVLOG(3) << "Reset()"; | 484 DVLOG(3) << "Reset()"; |
| 492 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 485 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 493 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 486 decoder_thread_.message_loop()->PostTask( |
| 494 &V4L2VideoDecodeAccelerator::ResetTask, base::Unretained(this))); | 487 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::ResetTask, |
| 488 base::Unretained(this))); |
| 495 } | 489 } |
| 496 | 490 |
| 497 void V4L2VideoDecodeAccelerator::Destroy() { | 491 void V4L2VideoDecodeAccelerator::Destroy() { |
| 498 DVLOG(3) << "Destroy()"; | 492 DVLOG(3) << "Destroy()"; |
| 499 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 493 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 500 | 494 |
| 501 // We're destroying; cancel all callbacks. | 495 // We're destroying; cancel all callbacks. |
| 502 client_ptr_factory_.reset(); | 496 client_ptr_factory_.reset(); |
| 503 weak_this_factory_.InvalidateWeakPtrs(); | 497 weak_this_factory_.InvalidateWeakPtrs(); |
| 504 | 498 |
| 505 // If the decoder thread is running, destroy using posted task. | 499 // If the decoder thread is running, destroy using posted task. |
| 506 if (decoder_thread_.IsRunning()) { | 500 if (decoder_thread_.IsRunning()) { |
| 507 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 501 decoder_thread_.message_loop()->PostTask( |
| 508 &V4L2VideoDecodeAccelerator::DestroyTask, base::Unretained(this))); | 502 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::DestroyTask, |
| 503 base::Unretained(this))); |
| 509 pictures_assigned_.Signal(); | 504 pictures_assigned_.Signal(); |
| 510 // DestroyTask() will cause the decoder_thread_ to flush all tasks. | 505 // DestroyTask() will cause the decoder_thread_ to flush all tasks. |
| 511 decoder_thread_.Stop(); | 506 decoder_thread_.Stop(); |
| 512 } else { | 507 } else { |
| 513 // Otherwise, call the destroy task directly. | 508 // Otherwise, call the destroy task directly. |
| 514 DestroyTask(); | 509 DestroyTask(); |
| 515 } | 510 } |
| 516 | 511 |
| 517 delete this; | 512 delete this; |
| 518 } | 513 } |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 790 | 785 |
| 791 void V4L2VideoDecodeAccelerator::ScheduleDecodeBufferTaskIfNeeded() { | 786 void V4L2VideoDecodeAccelerator::ScheduleDecodeBufferTaskIfNeeded() { |
| 792 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 787 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 793 | 788 |
| 794 // If we're behind on tasks, schedule another one. | 789 // If we're behind on tasks, schedule another one. |
| 795 int buffers_to_decode = decoder_input_queue_.size(); | 790 int buffers_to_decode = decoder_input_queue_.size(); |
| 796 if (decoder_current_bitstream_buffer_ != NULL) | 791 if (decoder_current_bitstream_buffer_ != NULL) |
| 797 buffers_to_decode++; | 792 buffers_to_decode++; |
| 798 if (decoder_decode_buffer_tasks_scheduled_ < buffers_to_decode) { | 793 if (decoder_decode_buffer_tasks_scheduled_ < buffers_to_decode) { |
| 799 decoder_decode_buffer_tasks_scheduled_++; | 794 decoder_decode_buffer_tasks_scheduled_++; |
| 800 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 795 decoder_thread_.message_loop()->PostTask( |
| 801 &V4L2VideoDecodeAccelerator::DecodeBufferTask, | 796 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::DecodeBufferTask, |
| 802 base::Unretained(this))); | 797 base::Unretained(this))); |
| 803 } | 798 } |
| 804 } | 799 } |
| 805 | 800 |
| 806 bool V4L2VideoDecodeAccelerator::DecodeBufferInitial( | 801 bool V4L2VideoDecodeAccelerator::DecodeBufferInitial(const void* data, |
| 807 const void* data, size_t size, size_t* endpos) { | 802 size_t size, |
| 803 size_t* endpos) { |
| 808 DVLOG(3) << "DecodeBufferInitial(): data=" << data << ", size=" << size; | 804 DVLOG(3) << "DecodeBufferInitial(): data=" << data << ", size=" << size; |
| 809 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 805 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 810 DCHECK_NE(decoder_state_, kUninitialized); | 806 DCHECK_NE(decoder_state_, kUninitialized); |
| 811 DCHECK_NE(decoder_state_, kDecoding); | 807 DCHECK_NE(decoder_state_, kDecoding); |
| 812 // Initial decode. We haven't been able to get output stream format info yet. | 808 // Initial decode. We haven't been able to get output stream format info yet. |
| 813 // Get it, and start decoding. | 809 // Get it, and start decoding. |
| 814 | 810 |
| 815 // Copy in and send to HW. | 811 // Copy in and send to HW. |
| 816 if (!AppendToInputFrame(data, size)) | 812 if (!AppendToInputFrame(data, size)) |
| 817 return false; | 813 return false; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 846 // Success! Setup our parameters. | 842 // Success! Setup our parameters. |
| 847 if (!CreateBuffersForFormat(format, visible_size)) | 843 if (!CreateBuffersForFormat(format, visible_size)) |
| 848 return false; | 844 return false; |
| 849 } | 845 } |
| 850 | 846 |
| 851 decoder_state_ = kDecoding; | 847 decoder_state_ = kDecoding; |
| 852 ScheduleDecodeBufferTaskIfNeeded(); | 848 ScheduleDecodeBufferTaskIfNeeded(); |
| 853 return true; | 849 return true; |
| 854 } | 850 } |
| 855 | 851 |
| 856 bool V4L2VideoDecodeAccelerator::DecodeBufferContinue( | 852 bool V4L2VideoDecodeAccelerator::DecodeBufferContinue(const void* data, |
| 857 const void* data, size_t size) { | 853 size_t size) { |
| 858 DVLOG(3) << "DecodeBufferContinue(): data=" << data << ", size=" << size; | 854 DVLOG(3) << "DecodeBufferContinue(): data=" << data << ", size=" << size; |
| 859 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 855 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 860 DCHECK_EQ(decoder_state_, kDecoding); | 856 DCHECK_EQ(decoder_state_, kDecoding); |
| 861 | 857 |
| 862 // Both of these calls will set kError state if they fail. | 858 // Both of these calls will set kError state if they fail. |
| 863 // Only flush the frame if it's complete. | 859 // Only flush the frame if it's complete. |
| 864 return (AppendToInputFrame(data, size) && | 860 return (AppendToInputFrame(data, size) && |
| 865 (decoder_partial_frame_pending_ || FlushInputFrame())); | 861 (decoder_partial_frame_pending_ || FlushInputFrame())); |
| 866 } | 862 } |
| 867 | 863 |
| 868 bool V4L2VideoDecodeAccelerator::AppendToInputFrame( | 864 bool V4L2VideoDecodeAccelerator::AppendToInputFrame(const void* data, |
| 869 const void* data, size_t size) { | 865 size_t size) { |
| 870 DVLOG(3) << "AppendToInputFrame()"; | 866 DVLOG(3) << "AppendToInputFrame()"; |
| 871 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 867 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 872 DCHECK_NE(decoder_state_, kUninitialized); | 868 DCHECK_NE(decoder_state_, kUninitialized); |
| 873 DCHECK_NE(decoder_state_, kResetting); | 869 DCHECK_NE(decoder_state_, kResetting); |
| 874 DCHECK_NE(decoder_state_, kError); | 870 DCHECK_NE(decoder_state_, kError); |
| 875 // This routine can handle data == NULL and size == 0, which occurs when | 871 // This routine can handle data == NULL and size == 0, which occurs when |
| 876 // we queue an empty buffer for the purposes of flushing the pipe. | 872 // we queue an empty buffer for the purposes of flushing the pipe. |
| 877 | 873 |
| 878 // Flush if we're too big | 874 // Flush if we're too big |
| 879 if (decoder_current_input_buffer_ != -1) { | 875 if (decoder_current_input_buffer_ != -1) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 909 | 905 |
| 910 DCHECK(data != NULL || size == 0); | 906 DCHECK(data != NULL || size == 0); |
| 911 if (size == 0) { | 907 if (size == 0) { |
| 912 // If we asked for an empty buffer, return now. We return only after | 908 // If we asked for an empty buffer, return now. We return only after |
| 913 // getting the next input buffer, since we might actually want an empty | 909 // getting the next input buffer, since we might actually want an empty |
| 914 // input buffer for flushing purposes. | 910 // input buffer for flushing purposes. |
| 915 return true; | 911 return true; |
| 916 } | 912 } |
| 917 | 913 |
| 918 // Copy in to the buffer. | 914 // Copy in to the buffer. |
| 919 InputRecord& input_record = | 915 InputRecord& input_record = input_buffer_map_[decoder_current_input_buffer_]; |
| 920 input_buffer_map_[decoder_current_input_buffer_]; | |
| 921 if (size > input_record.length - input_record.bytes_used) { | 916 if (size > input_record.length - input_record.bytes_used) { |
| 922 LOG(ERROR) << "AppendToInputFrame(): over-size frame, erroring"; | 917 LOG(ERROR) << "AppendToInputFrame(): over-size frame, erroring"; |
| 923 NOTIFY_ERROR(UNREADABLE_INPUT); | 918 NOTIFY_ERROR(UNREADABLE_INPUT); |
| 924 return false; | 919 return false; |
| 925 } | 920 } |
| 926 memcpy(reinterpret_cast<uint8_t*>(input_record.address) + | 921 memcpy(reinterpret_cast<uint8_t*>(input_record.address) + |
| 927 input_record.bytes_used, | 922 input_record.bytes_used, |
| 928 data, size); | 923 data, size); |
| 929 input_record.bytes_used += size; | 924 input_record.bytes_used += size; |
| 930 | 925 |
| 931 return true; | 926 return true; |
| 932 } | 927 } |
| 933 | 928 |
| 934 bool V4L2VideoDecodeAccelerator::FlushInputFrame() { | 929 bool V4L2VideoDecodeAccelerator::FlushInputFrame() { |
| 935 DVLOG(3) << "FlushInputFrame()"; | 930 DVLOG(3) << "FlushInputFrame()"; |
| 936 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 931 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 937 DCHECK_NE(decoder_state_, kUninitialized); | 932 DCHECK_NE(decoder_state_, kUninitialized); |
| 938 DCHECK_NE(decoder_state_, kResetting); | 933 DCHECK_NE(decoder_state_, kResetting); |
| 939 DCHECK_NE(decoder_state_, kError); | 934 DCHECK_NE(decoder_state_, kError); |
| 940 | 935 |
| 941 if (decoder_current_input_buffer_ == -1) | 936 if (decoder_current_input_buffer_ == -1) |
| 942 return true; | 937 return true; |
| 943 | 938 |
| 944 InputRecord& input_record = | 939 InputRecord& input_record = input_buffer_map_[decoder_current_input_buffer_]; |
| 945 input_buffer_map_[decoder_current_input_buffer_]; | |
| 946 DCHECK_NE(input_record.input_id, -1); | 940 DCHECK_NE(input_record.input_id, -1); |
| 947 DCHECK(input_record.input_id != kFlushBufferId || | 941 DCHECK(input_record.input_id != kFlushBufferId || |
| 948 input_record.bytes_used == 0); | 942 input_record.bytes_used == 0); |
| 949 // * if input_id >= 0, this input buffer was prompted by a bitstream buffer we | 943 // * if input_id >= 0, this input buffer was prompted by a bitstream buffer we |
| 950 // got from the client. We can skip it if it is empty. | 944 // got from the client. We can skip it if it is empty. |
| 951 // * if input_id < 0 (should be kFlushBufferId in this case), this input | 945 // * if input_id < 0 (should be kFlushBufferId in this case), this input |
| 952 // buffer was prompted by a flush buffer, and should be queued even when | 946 // buffer was prompted by a flush buffer, and should be queued even when |
| 953 // empty. | 947 // empty. |
| 954 if (input_record.input_id >= 0 && input_record.bytes_used == 0) { | 948 if (input_record.input_id >= 0 && input_record.bytes_used == 0) { |
| 955 input_record.input_id = -1; | 949 input_record.input_id = -1; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1006 | 1000 |
| 1007 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), | 1001 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), |
| 1008 // so either: | 1002 // so either: |
| 1009 // * device_poll_thread_ is running normally | 1003 // * device_poll_thread_ is running normally |
| 1010 // * device_poll_thread_ scheduled us, but then a ResetTask() or DestroyTask() | 1004 // * device_poll_thread_ scheduled us, but then a ResetTask() or DestroyTask() |
| 1011 // shut it down, in which case we're either in kResetting or kError states | 1005 // shut it down, in which case we're either in kResetting or kError states |
| 1012 // respectively, and we should have early-outed already. | 1006 // respectively, and we should have early-outed already. |
| 1013 DCHECK(device_poll_thread_.message_loop()); | 1007 DCHECK(device_poll_thread_.message_loop()); |
| 1014 // Queue the DevicePollTask() now. | 1008 // Queue the DevicePollTask() now. |
| 1015 device_poll_thread_.message_loop()->PostTask( | 1009 device_poll_thread_.message_loop()->PostTask( |
| 1016 FROM_HERE, | 1010 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::DevicePollTask, |
| 1017 base::Bind(&V4L2VideoDecodeAccelerator::DevicePollTask, | 1011 base::Unretained(this), poll_device)); |
| 1018 base::Unretained(this), | |
| 1019 poll_device)); | |
| 1020 | 1012 |
| 1021 DVLOG(1) << "ServiceDeviceTask(): buffer counts: DEC[" | 1013 DVLOG(1) << "ServiceDeviceTask(): buffer counts: DEC[" |
| 1022 << decoder_input_queue_.size() << "->" | 1014 << decoder_input_queue_.size() << "->" |
| 1023 << input_ready_queue_.size() << "] => DEVICE[" | 1015 << input_ready_queue_.size() << "] => DEVICE[" |
| 1024 << free_input_buffers_.size() << "+" | 1016 << free_input_buffers_.size() << "+" |
| 1025 << input_buffer_queued_count_ << "/" | 1017 << input_buffer_queued_count_ << "/" |
| 1026 << input_buffer_map_.size() << "->" | 1018 << input_buffer_map_.size() << "->" |
| 1027 << free_output_buffers_.size() << "+" | 1019 << free_output_buffers_.size() << "+" |
| 1028 << output_buffer_queued_count_ << "/" | 1020 << output_buffer_queued_count_ << "/" |
| 1029 << output_buffer_map_.size() << "] => PROCESSOR[" | 1021 << output_buffer_map_.size() << "] => PROCESSOR[" |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1116 TRACE_EVENT0("Video Decoder", "V4L2VDA::Dequeue"); | 1108 TRACE_EVENT0("Video Decoder", "V4L2VDA::Dequeue"); |
| 1117 | 1109 |
| 1118 // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free | 1110 // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free |
| 1119 // list. | 1111 // list. |
| 1120 while (input_buffer_queued_count_ > 0) { | 1112 while (input_buffer_queued_count_ > 0) { |
| 1121 DCHECK(input_streamon_); | 1113 DCHECK(input_streamon_); |
| 1122 struct v4l2_buffer dqbuf; | 1114 struct v4l2_buffer dqbuf; |
| 1123 struct v4l2_plane planes[1]; | 1115 struct v4l2_plane planes[1]; |
| 1124 memset(&dqbuf, 0, sizeof(dqbuf)); | 1116 memset(&dqbuf, 0, sizeof(dqbuf)); |
| 1125 memset(planes, 0, sizeof(planes)); | 1117 memset(planes, 0, sizeof(planes)); |
| 1126 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 1118 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 1127 dqbuf.memory = V4L2_MEMORY_MMAP; | 1119 dqbuf.memory = V4L2_MEMORY_MMAP; |
| 1128 dqbuf.m.planes = planes; | 1120 dqbuf.m.planes = planes; |
| 1129 dqbuf.length = 1; | 1121 dqbuf.length = 1; |
| 1130 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { | 1122 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
| 1131 if (errno == EAGAIN) { | 1123 if (errno == EAGAIN) { |
| 1132 // EAGAIN if we're just out of buffers to dequeue. | 1124 // EAGAIN if we're just out of buffers to dequeue. |
| 1133 break; | 1125 break; |
| 1134 } | 1126 } |
| 1135 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; | 1127 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; |
| 1136 NOTIFY_ERROR(PLATFORM_FAILURE); | 1128 NOTIFY_ERROR(PLATFORM_FAILURE); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1147 | 1139 |
| 1148 // Dequeue completed output (VIDEO_CAPTURE) buffers, and queue to the | 1140 // Dequeue completed output (VIDEO_CAPTURE) buffers, and queue to the |
| 1149 // completed queue. | 1141 // completed queue. |
| 1150 while (output_buffer_queued_count_ > 0) { | 1142 while (output_buffer_queued_count_ > 0) { |
| 1151 DCHECK(output_streamon_); | 1143 DCHECK(output_streamon_); |
| 1152 struct v4l2_buffer dqbuf; | 1144 struct v4l2_buffer dqbuf; |
| 1153 std::unique_ptr<struct v4l2_plane[]> planes( | 1145 std::unique_ptr<struct v4l2_plane[]> planes( |
| 1154 new v4l2_plane[output_planes_count_]); | 1146 new v4l2_plane[output_planes_count_]); |
| 1155 memset(&dqbuf, 0, sizeof(dqbuf)); | 1147 memset(&dqbuf, 0, sizeof(dqbuf)); |
| 1156 memset(planes.get(), 0, sizeof(struct v4l2_plane) * output_planes_count_); | 1148 memset(planes.get(), 0, sizeof(struct v4l2_plane) * output_planes_count_); |
| 1157 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1149 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1158 dqbuf.memory = V4L2_MEMORY_MMAP; | 1150 dqbuf.memory = V4L2_MEMORY_MMAP; |
| 1159 dqbuf.m.planes = planes.get(); | 1151 dqbuf.m.planes = planes.get(); |
| 1160 dqbuf.length = output_planes_count_; | 1152 dqbuf.length = output_planes_count_; |
| 1161 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { | 1153 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) { |
| 1162 if (errno == EAGAIN) { | 1154 if (errno == EAGAIN) { |
| 1163 // EAGAIN if we're just out of buffers to dequeue. | 1155 // EAGAIN if we're just out of buffers to dequeue. |
| 1164 break; | 1156 break; |
| 1165 } | 1157 } |
| 1166 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; | 1158 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; |
| 1167 NOTIFY_ERROR(PLATFORM_FAILURE); | 1159 NOTIFY_ERROR(PLATFORM_FAILURE); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1224 DCHECK(!input_ready_queue_.empty()); | 1216 DCHECK(!input_ready_queue_.empty()); |
| 1225 | 1217 |
| 1226 // Enqueue an input (VIDEO_OUTPUT) buffer. | 1218 // Enqueue an input (VIDEO_OUTPUT) buffer. |
| 1227 const int buffer = input_ready_queue_.front(); | 1219 const int buffer = input_ready_queue_.front(); |
| 1228 InputRecord& input_record = input_buffer_map_[buffer]; | 1220 InputRecord& input_record = input_buffer_map_[buffer]; |
| 1229 DCHECK(!input_record.at_device); | 1221 DCHECK(!input_record.at_device); |
| 1230 struct v4l2_buffer qbuf; | 1222 struct v4l2_buffer qbuf; |
| 1231 struct v4l2_plane qbuf_plane; | 1223 struct v4l2_plane qbuf_plane; |
| 1232 memset(&qbuf, 0, sizeof(qbuf)); | 1224 memset(&qbuf, 0, sizeof(qbuf)); |
| 1233 memset(&qbuf_plane, 0, sizeof(qbuf_plane)); | 1225 memset(&qbuf_plane, 0, sizeof(qbuf_plane)); |
| 1234 qbuf.index = buffer; | 1226 qbuf.index = buffer; |
| 1235 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 1227 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 1236 qbuf.timestamp.tv_sec = input_record.input_id; | 1228 qbuf.timestamp.tv_sec = input_record.input_id; |
| 1237 qbuf.memory = V4L2_MEMORY_MMAP; | 1229 qbuf.memory = V4L2_MEMORY_MMAP; |
| 1238 qbuf.m.planes = &qbuf_plane; | 1230 qbuf.m.planes = &qbuf_plane; |
| 1239 qbuf.m.planes[0].bytesused = input_record.bytes_used; | 1231 qbuf.m.planes[0].bytesused = input_record.bytes_used; |
| 1240 qbuf.length = 1; | 1232 qbuf.length = 1; |
| 1241 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 1233 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
| 1242 input_ready_queue_.pop(); | 1234 input_ready_queue_.pop(); |
| 1243 input_record.at_device = true; | 1235 input_record.at_device = true; |
| 1244 input_buffer_queued_count_++; | 1236 input_buffer_queued_count_++; |
| 1245 DVLOG(3) << "EnqueueInputRecord(): enqueued input_id=" | 1237 DVLOG(3) << "EnqueueInputRecord(): enqueued input_id=" |
| 1246 << input_record.input_id << " size=" << input_record.bytes_used; | 1238 << input_record.input_id << " size=" << input_record.bytes_used; |
| 1247 return true; | 1239 return true; |
| 1248 } | 1240 } |
| 1249 | 1241 |
| 1250 bool V4L2VideoDecodeAccelerator::EnqueueOutputRecord() { | 1242 bool V4L2VideoDecodeAccelerator::EnqueueOutputRecord() { |
| 1251 DVLOG(3) << "EnqueueOutputRecord()"; | 1243 DVLOG(3) << "EnqueueOutputRecord()"; |
| 1252 DCHECK(!free_output_buffers_.empty()); | 1244 DCHECK(!free_output_buffers_.empty()); |
| 1253 | 1245 |
| 1254 // Enqueue an output (VIDEO_CAPTURE) buffer. | 1246 // Enqueue an output (VIDEO_CAPTURE) buffer. |
| 1255 const int buffer = free_output_buffers_.front(); | 1247 const int buffer = free_output_buffers_.front(); |
| 1256 OutputRecord& output_record = output_buffer_map_[buffer]; | 1248 OutputRecord& output_record = output_buffer_map_[buffer]; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1272 LOG(ERROR) << __func__ << " eglDestroySyncKHR failed!"; | 1264 LOG(ERROR) << __func__ << " eglDestroySyncKHR failed!"; |
| 1273 NOTIFY_ERROR(PLATFORM_FAILURE); | 1265 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1274 return false; | 1266 return false; |
| 1275 } | 1267 } |
| 1276 output_record.egl_sync = EGL_NO_SYNC_KHR; | 1268 output_record.egl_sync = EGL_NO_SYNC_KHR; |
| 1277 } | 1269 } |
| 1278 struct v4l2_buffer qbuf; | 1270 struct v4l2_buffer qbuf; |
| 1279 std::unique_ptr<struct v4l2_plane[]> qbuf_planes( | 1271 std::unique_ptr<struct v4l2_plane[]> qbuf_planes( |
| 1280 new v4l2_plane[output_planes_count_]); | 1272 new v4l2_plane[output_planes_count_]); |
| 1281 memset(&qbuf, 0, sizeof(qbuf)); | 1273 memset(&qbuf, 0, sizeof(qbuf)); |
| 1282 memset( | 1274 memset(qbuf_planes.get(), 0, |
| 1283 qbuf_planes.get(), 0, sizeof(struct v4l2_plane) * output_planes_count_); | 1275 sizeof(struct v4l2_plane) * output_planes_count_); |
| 1284 qbuf.index = buffer; | 1276 qbuf.index = buffer; |
| 1285 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1277 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1286 qbuf.memory = V4L2_MEMORY_MMAP; | 1278 qbuf.memory = V4L2_MEMORY_MMAP; |
| 1287 qbuf.m.planes = qbuf_planes.get(); | 1279 qbuf.m.planes = qbuf_planes.get(); |
| 1288 qbuf.length = output_planes_count_; | 1280 qbuf.length = output_planes_count_; |
| 1289 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); | 1281 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); |
| 1290 free_output_buffers_.pop(); | 1282 free_output_buffers_.pop(); |
| 1291 output_record.state = kAtDevice; | 1283 output_record.state = kAtDevice; |
| 1292 output_buffer_queued_count_++; | 1284 output_buffer_queued_count_++; |
| 1293 return true; | 1285 return true; |
| 1294 } | 1286 } |
| 1295 | 1287 |
| 1296 void V4L2VideoDecodeAccelerator::ReusePictureBufferTask( | 1288 void V4L2VideoDecodeAccelerator::ReusePictureBufferTask( |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1472 image_processor_bitstream_buffer_ids_.pop(); | 1464 image_processor_bitstream_buffer_ids_.pop(); |
| 1473 | 1465 |
| 1474 // If we were flushing, we'll never return any more BitstreamBuffers or | 1466 // If we were flushing, we'll never return any more BitstreamBuffers or |
| 1475 // PictureBuffers; they have all been dropped and returned by now. | 1467 // PictureBuffers; they have all been dropped and returned by now. |
| 1476 NotifyFlushDoneIfNeeded(); | 1468 NotifyFlushDoneIfNeeded(); |
| 1477 | 1469 |
| 1478 // Mark that we're resetting, then enqueue a ResetDoneTask(). All intervening | 1470 // Mark that we're resetting, then enqueue a ResetDoneTask(). All intervening |
| 1479 // jobs will early-out in the kResetting state. | 1471 // jobs will early-out in the kResetting state. |
| 1480 decoder_state_ = kResetting; | 1472 decoder_state_ = kResetting; |
| 1481 SendPictureReady(); // Send all pending PictureReady. | 1473 SendPictureReady(); // Send all pending PictureReady. |
| 1482 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 1474 decoder_thread_.message_loop()->PostTask( |
| 1483 &V4L2VideoDecodeAccelerator::ResetDoneTask, base::Unretained(this))); | 1475 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::ResetDoneTask, |
| 1476 base::Unretained(this))); |
| 1484 } | 1477 } |
| 1485 | 1478 |
| 1486 void V4L2VideoDecodeAccelerator::ResetDoneTask() { | 1479 void V4L2VideoDecodeAccelerator::ResetDoneTask() { |
| 1487 DVLOG(3) << "ResetDoneTask()"; | 1480 DVLOG(3) << "ResetDoneTask()"; |
| 1488 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1481 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1489 TRACE_EVENT0("Video Decoder", "V4L2VDA::ResetDoneTask"); | 1482 TRACE_EVENT0("Video Decoder", "V4L2VDA::ResetDoneTask"); |
| 1490 | 1483 |
| 1491 if (decoder_state_ == kError) { | 1484 if (decoder_state_ == kError) { |
| 1492 DVLOG(2) << "ResetDoneTask(): early out: kError state"; | 1485 DVLOG(2) << "ResetDoneTask(): early out: kError state"; |
| 1493 return; | 1486 return; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1547 DVLOG(3) << "StartDevicePoll()"; | 1540 DVLOG(3) << "StartDevicePoll()"; |
| 1548 DCHECK(!device_poll_thread_.IsRunning()); | 1541 DCHECK(!device_poll_thread_.IsRunning()); |
| 1549 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1542 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 1550 | 1543 |
| 1551 // Start up the device poll thread and schedule its first DevicePollTask(). | 1544 // Start up the device poll thread and schedule its first DevicePollTask(). |
| 1552 if (!device_poll_thread_.Start()) { | 1545 if (!device_poll_thread_.Start()) { |
| 1553 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; | 1546 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; |
| 1554 NOTIFY_ERROR(PLATFORM_FAILURE); | 1547 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1555 return false; | 1548 return false; |
| 1556 } | 1549 } |
| 1557 device_poll_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 1550 device_poll_thread_.message_loop()->PostTask( |
| 1558 &V4L2VideoDecodeAccelerator::DevicePollTask, | 1551 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::DevicePollTask, |
| 1559 base::Unretained(this), | 1552 base::Unretained(this), 0)); |
| 1560 0)); | |
| 1561 | 1553 |
| 1562 return true; | 1554 return true; |
| 1563 } | 1555 } |
| 1564 | 1556 |
| 1565 bool V4L2VideoDecodeAccelerator::StopDevicePoll() { | 1557 bool V4L2VideoDecodeAccelerator::StopDevicePoll() { |
| 1566 DVLOG(3) << "StopDevicePoll()"; | 1558 DVLOG(3) << "StopDevicePoll()"; |
| 1567 | 1559 |
| 1568 if (!device_poll_thread_.IsRunning()) | 1560 if (!device_poll_thread_.IsRunning()) |
| 1569 return true; | 1561 return true; |
| 1570 | 1562 |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1708 | 1700 |
| 1709 bool event_pending = false; | 1701 bool event_pending = false; |
| 1710 | 1702 |
| 1711 if (!device_->Poll(poll_device, &event_pending)) { | 1703 if (!device_->Poll(poll_device, &event_pending)) { |
| 1712 NOTIFY_ERROR(PLATFORM_FAILURE); | 1704 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 1713 return; | 1705 return; |
| 1714 } | 1706 } |
| 1715 | 1707 |
| 1716 // All processing should happen on ServiceDeviceTask(), since we shouldn't | 1708 // All processing should happen on ServiceDeviceTask(), since we shouldn't |
| 1717 // touch decoder state from this thread. | 1709 // touch decoder state from this thread. |
| 1718 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 1710 decoder_thread_.message_loop()->PostTask( |
| 1719 &V4L2VideoDecodeAccelerator::ServiceDeviceTask, | 1711 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::ServiceDeviceTask, |
| 1720 base::Unretained(this), event_pending)); | 1712 base::Unretained(this), event_pending)); |
| 1721 } | 1713 } |
| 1722 | 1714 |
| 1723 void V4L2VideoDecodeAccelerator::NotifyError(Error error) { | 1715 void V4L2VideoDecodeAccelerator::NotifyError(Error error) { |
| 1724 DVLOG(2) << "NotifyError()"; | 1716 DVLOG(2) << "NotifyError()"; |
| 1725 | 1717 |
| 1726 if (!child_task_runner_->BelongsToCurrentThread()) { | 1718 if (!child_task_runner_->BelongsToCurrentThread()) { |
| 1727 child_task_runner_->PostTask( | 1719 child_task_runner_->PostTask( |
| 1728 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::NotifyError, | 1720 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::NotifyError, |
| 1729 weak_this_, error)); | 1721 weak_this_, error)); |
| 1730 return; | 1722 return; |
| 1731 } | 1723 } |
| 1732 | 1724 |
| 1733 if (client_) { | 1725 if (client_) { |
| 1734 client_->NotifyError(error); | 1726 client_->NotifyError(error); |
| 1735 client_ptr_factory_.reset(); | 1727 client_ptr_factory_.reset(); |
| 1736 } | 1728 } |
| 1737 } | 1729 } |
| 1738 | 1730 |
| 1739 void V4L2VideoDecodeAccelerator::SetErrorState(Error error) { | 1731 void V4L2VideoDecodeAccelerator::SetErrorState(Error error) { |
| 1740 // We can touch decoder_state_ only if this is the decoder thread or the | 1732 // We can touch decoder_state_ only if this is the decoder thread or the |
| 1741 // decoder thread isn't running. | 1733 // decoder thread isn't running. |
| 1742 if (decoder_thread_.message_loop() != NULL && | 1734 if (decoder_thread_.message_loop() != NULL && |
| 1743 decoder_thread_.message_loop() != base::MessageLoop::current()) { | 1735 decoder_thread_.message_loop() != base::MessageLoop::current()) { |
| 1744 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 1736 decoder_thread_.message_loop()->PostTask( |
| 1745 &V4L2VideoDecodeAccelerator::SetErrorState, | 1737 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::SetErrorState, |
| 1746 base::Unretained(this), error)); | 1738 base::Unretained(this), error)); |
| 1747 return; | 1739 return; |
| 1748 } | 1740 } |
| 1749 | 1741 |
| 1750 // Post NotifyError only if we are already initialized, as the API does | 1742 // Post NotifyError only if we are already initialized, as the API does |
| 1751 // not allow doing so before that. | 1743 // not allow doing so before that. |
| 1752 if (decoder_state_ != kError && decoder_state_ != kUninitialized) | 1744 if (decoder_state_ != kError && decoder_state_ != kUninitialized) |
| 1753 NotifyError(error); | 1745 NotifyError(error); |
| 1754 | 1746 |
| 1755 decoder_state_ = kError; | 1747 decoder_state_ = kError; |
| 1756 } | 1748 } |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1854 | 1846 |
| 1855 bool V4L2VideoDecodeAccelerator::CreateInputBuffers() { | 1847 bool V4L2VideoDecodeAccelerator::CreateInputBuffers() { |
| 1856 DVLOG(3) << "CreateInputBuffers()"; | 1848 DVLOG(3) << "CreateInputBuffers()"; |
| 1857 // We always run this as we prepare to initialize. | 1849 // We always run this as we prepare to initialize. |
| 1858 DCHECK_EQ(decoder_state_, kUninitialized); | 1850 DCHECK_EQ(decoder_state_, kUninitialized); |
| 1859 DCHECK(!input_streamon_); | 1851 DCHECK(!input_streamon_); |
| 1860 DCHECK(input_buffer_map_.empty()); | 1852 DCHECK(input_buffer_map_.empty()); |
| 1861 | 1853 |
| 1862 struct v4l2_requestbuffers reqbufs; | 1854 struct v4l2_requestbuffers reqbufs; |
| 1863 memset(&reqbufs, 0, sizeof(reqbufs)); | 1855 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 1864 reqbufs.count = kInputBufferCount; | 1856 reqbufs.count = kInputBufferCount; |
| 1865 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 1857 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 1866 reqbufs.memory = V4L2_MEMORY_MMAP; | 1858 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 1867 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); | 1859 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); |
| 1868 input_buffer_map_.resize(reqbufs.count); | 1860 input_buffer_map_.resize(reqbufs.count); |
| 1869 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { | 1861 for (size_t i = 0; i < input_buffer_map_.size(); ++i) { |
| 1870 free_input_buffers_.push_back(i); | 1862 free_input_buffers_.push_back(i); |
| 1871 | 1863 |
| 1872 // Query for the MEMORY_MMAP pointer. | 1864 // Query for the MEMORY_MMAP pointer. |
| 1873 struct v4l2_plane planes[1]; | 1865 struct v4l2_plane planes[1]; |
| 1874 struct v4l2_buffer buffer; | 1866 struct v4l2_buffer buffer; |
| 1875 memset(&buffer, 0, sizeof(buffer)); | 1867 memset(&buffer, 0, sizeof(buffer)); |
| 1876 memset(planes, 0, sizeof(planes)); | 1868 memset(planes, 0, sizeof(planes)); |
| 1877 buffer.index = i; | 1869 buffer.index = i; |
| 1878 buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 1870 buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 1879 buffer.memory = V4L2_MEMORY_MMAP; | 1871 buffer.memory = V4L2_MEMORY_MMAP; |
| 1880 buffer.m.planes = planes; | 1872 buffer.m.planes = planes; |
| 1881 buffer.length = 1; | 1873 buffer.length = 1; |
| 1882 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer); | 1874 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer); |
| 1883 void* address = device_->Mmap(NULL, | 1875 void* address = |
| 1884 buffer.m.planes[0].length, | 1876 device_->Mmap(NULL, buffer.m.planes[0].length, PROT_READ | PROT_WRITE, |
| 1885 PROT_READ | PROT_WRITE, | 1877 MAP_SHARED, buffer.m.planes[0].m.mem_offset); |
| 1886 MAP_SHARED, | |
| 1887 buffer.m.planes[0].m.mem_offset); | |
| 1888 if (address == MAP_FAILED) { | 1878 if (address == MAP_FAILED) { |
| 1889 PLOG(ERROR) << "CreateInputBuffers(): mmap() failed"; | 1879 PLOG(ERROR) << "CreateInputBuffers(): mmap() failed"; |
| 1890 return false; | 1880 return false; |
| 1891 } | 1881 } |
| 1892 input_buffer_map_[i].address = address; | 1882 input_buffer_map_[i].address = address; |
| 1893 input_buffer_map_[i].length = buffer.m.planes[0].length; | 1883 input_buffer_map_[i].length = buffer.m.planes[0].length; |
| 1894 } | 1884 } |
| 1895 | 1885 |
| 1896 return true; | 1886 return true; |
| 1897 } | 1887 } |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2151 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 2141 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 2152 DVLOG(3) << "ResolutionChangeDestroyBuffers()"; | 2142 DVLOG(3) << "ResolutionChangeDestroyBuffers()"; |
| 2153 | 2143 |
| 2154 if (!DestroyOutputBuffers()) { | 2144 if (!DestroyOutputBuffers()) { |
| 2155 LOG(ERROR) << __func__ << " Failed destroying output buffers."; | 2145 LOG(ERROR) << __func__ << " Failed destroying output buffers."; |
| 2156 NOTIFY_ERROR(PLATFORM_FAILURE); | 2146 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 2157 return; | 2147 return; |
| 2158 } | 2148 } |
| 2159 | 2149 |
| 2160 // Finish resolution change on decoder thread. | 2150 // Finish resolution change on decoder thread. |
| 2161 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 2151 decoder_thread_.message_loop()->PostTask( |
| 2162 &V4L2VideoDecodeAccelerator::FinishResolutionChange, | 2152 FROM_HERE, base::Bind(&V4L2VideoDecodeAccelerator::FinishResolutionChange, |
| 2163 base::Unretained(this))); | 2153 base::Unretained(this))); |
| 2164 } | 2154 } |
| 2165 | 2155 |
| 2166 void V4L2VideoDecodeAccelerator::SendPictureReady() { | 2156 void V4L2VideoDecodeAccelerator::SendPictureReady() { |
| 2167 DVLOG(3) << "SendPictureReady()"; | 2157 DVLOG(3) << "SendPictureReady()"; |
| 2168 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 2158 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 2169 bool resetting_or_flushing = | 2159 bool resetting_or_flushing = |
| 2170 (decoder_state_ == kResetting || decoder_flushing_); | 2160 (decoder_state_ == kResetting || decoder_flushing_); |
| 2171 while (pending_picture_ready_.size() > 0) { | 2161 while (pending_picture_ready_.size() > 0) { |
| 2172 bool cleared = pending_picture_ready_.front().cleared; | 2162 bool cleared = pending_picture_ready_.front().cleared; |
| 2173 const media::Picture& picture = pending_picture_ready_.front().picture; | 2163 const media::Picture& picture = pending_picture_ready_.front().picture; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2251 free_output_buffers_.push(output_buffer_index); | 2241 free_output_buffers_.push(output_buffer_index); |
| 2252 Enqueue(); | 2242 Enqueue(); |
| 2253 } | 2243 } |
| 2254 } | 2244 } |
| 2255 | 2245 |
| 2256 void V4L2VideoDecodeAccelerator::ImageProcessorError() { | 2246 void V4L2VideoDecodeAccelerator::ImageProcessorError() { |
| 2257 LOG(ERROR) << "Image processor error"; | 2247 LOG(ERROR) << "Image processor error"; |
| 2258 NOTIFY_ERROR(PLATFORM_FAILURE); | 2248 NOTIFY_ERROR(PLATFORM_FAILURE); |
| 2259 } | 2249 } |
| 2260 | 2250 |
| 2261 } // namespace content | 2251 } // namespace media |
| OLD | NEW |