| 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 <fcntl.h> | 5 #include <fcntl.h> |
| 6 #include <linux/videodev2.h> | 6 #include <linux/videodev2.h> |
| 7 #include <poll.h> | 7 #include <poll.h> |
| 8 #include <string.h> | 8 #include <string.h> |
| 9 #include <sys/eventfd.h> | 9 #include <sys/eventfd.h> |
| 10 #include <sys/ioctl.h> | 10 #include <sys/ioctl.h> |
| 11 #include <sys/mman.h> | 11 #include <sys/mman.h> |
| 12 #include <utility> | 12 #include <utility> |
| 13 | 13 |
| 14 #include "base/callback.h" | 14 #include "base/callback.h" |
| 15 #include "base/command_line.h" | 15 #include "base/command_line.h" |
| 16 #include "base/macros.h" | 16 #include "base/macros.h" |
| 17 #include "base/numerics/safe_conversions.h" | 17 #include "base/numerics/safe_conversions.h" |
| 18 #include "base/thread_task_runner_handle.h" | 18 #include "base/thread_task_runner_handle.h" |
| 19 #include "base/trace_event/trace_event.h" | 19 #include "base/trace_event/trace_event.h" |
| 20 #include "content/common/gpu/media/shared_memory_region.h" | |
| 21 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h" | |
| 22 #include "media/base/bind_to_current_loop.h" | 20 #include "media/base/bind_to_current_loop.h" |
| 23 #include "media/base/bitstream_buffer.h" | 21 #include "media/base/bitstream_buffer.h" |
| 22 #include "media/gpu/shared_memory_region.h" |
| 23 #include "media/gpu/v4l2_video_encode_accelerator.h" |
| 24 | 24 |
| 25 #define NOTIFY_ERROR(x) \ | 25 #define NOTIFY_ERROR(x) \ |
| 26 do { \ | 26 do { \ |
| 27 LOG(ERROR) << "Setting error state:" << x; \ | 27 LOG(ERROR) << "Setting error state:" << x; \ |
| 28 SetErrorState(x); \ | 28 SetErrorState(x); \ |
| 29 } while (0) | 29 } while (0) |
| 30 | 30 |
| 31 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \ | 31 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \ |
| 32 do { \ | 32 do { \ |
| 33 if (device_->Ioctl(type, arg) != 0) { \ | 33 if (device_->Ioctl(type, arg) != 0) { \ |
| 34 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << type_str; \ | 34 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << type_str; \ |
| 35 NOTIFY_ERROR(kPlatformFailureError); \ | 35 NOTIFY_ERROR(kPlatformFailureError); \ |
| 36 return value; \ | 36 return value; \ |
| 37 } \ | 37 } \ |
| 38 } while (0) | 38 } while (0) |
| 39 | 39 |
| 40 #define IOCTL_OR_ERROR_RETURN(type, arg) \ | 40 #define IOCTL_OR_ERROR_RETURN(type, arg) \ |
| 41 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0), #type) | 41 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0), #type) |
| 42 | 42 |
| 43 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \ | 43 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \ |
| 44 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type) | 44 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false, #type) |
| 45 | 45 |
| 46 #define IOCTL_OR_LOG_ERROR(type, arg) \ | 46 #define IOCTL_OR_LOG_ERROR(type, arg) \ |
| 47 do { \ | 47 do { \ |
| 48 if (device_->Ioctl(type, arg) != 0) \ | 48 if (device_->Ioctl(type, arg) != 0) \ |
| 49 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ | 49 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ |
| 50 } while (0) | 50 } while (0) |
| 51 | 51 |
| 52 namespace content { | 52 namespace media { |
| 53 | 53 |
| 54 struct V4L2VideoEncodeAccelerator::BitstreamBufferRef { | 54 struct V4L2VideoEncodeAccelerator::BitstreamBufferRef { |
| 55 BitstreamBufferRef(int32_t id, std::unique_ptr<SharedMemoryRegion> shm) | 55 BitstreamBufferRef(int32_t id, std::unique_ptr<SharedMemoryRegion> shm) |
| 56 : id(id), shm(std::move(shm)) {} | 56 : id(id), shm(std::move(shm)) {} |
| 57 const int32_t id; | 57 const int32_t id; |
| 58 const std::unique_ptr<SharedMemoryRegion> shm; | 58 const std::unique_ptr<SharedMemoryRegion> shm; |
| 59 }; | 59 }; |
| 60 | 60 |
| 61 V4L2VideoEncodeAccelerator::InputRecord::InputRecord() : at_device(false) { | 61 V4L2VideoEncodeAccelerator::InputRecord::InputRecord() : at_device(false) {} |
| 62 } | |
| 63 | 62 |
| 64 V4L2VideoEncodeAccelerator::InputRecord::~InputRecord() { | 63 V4L2VideoEncodeAccelerator::InputRecord::~InputRecord() {} |
| 65 } | |
| 66 | 64 |
| 67 V4L2VideoEncodeAccelerator::OutputRecord::OutputRecord() | 65 V4L2VideoEncodeAccelerator::OutputRecord::OutputRecord() |
| 68 : at_device(false), address(NULL), length(0) { | 66 : at_device(false), address(NULL), length(0) {} |
| 69 } | |
| 70 | 67 |
| 71 V4L2VideoEncodeAccelerator::OutputRecord::~OutputRecord() { | 68 V4L2VideoEncodeAccelerator::OutputRecord::~OutputRecord() {} |
| 72 } | |
| 73 | 69 |
| 74 V4L2VideoEncodeAccelerator::ImageProcessorInputRecord:: | 70 V4L2VideoEncodeAccelerator::ImageProcessorInputRecord:: |
| 75 ImageProcessorInputRecord() | 71 ImageProcessorInputRecord() |
| 76 : force_keyframe(false) {} | 72 : force_keyframe(false) {} |
| 77 | 73 |
| 78 V4L2VideoEncodeAccelerator::ImageProcessorInputRecord:: | 74 V4L2VideoEncodeAccelerator::ImageProcessorInputRecord:: |
| 79 ~ImageProcessorInputRecord() {} | 75 ~ImageProcessorInputRecord() {} |
| 80 | 76 |
| 81 V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator( | 77 V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator( |
| 82 const scoped_refptr<V4L2Device>& device) | 78 const scoped_refptr<V4L2Device>& device) |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 | 123 |
| 128 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 124 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 129 DCHECK_EQ(encoder_state_, kUninitialized); | 125 DCHECK_EQ(encoder_state_, kUninitialized); |
| 130 | 126 |
| 131 struct v4l2_capability caps; | 127 struct v4l2_capability caps; |
| 132 memset(&caps, 0, sizeof(caps)); | 128 memset(&caps, 0, sizeof(caps)); |
| 133 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; | 129 const __u32 kCapsRequired = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; |
| 134 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); | 130 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps); |
| 135 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { | 131 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { |
| 136 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: " | 132 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: " |
| 137 "caps check failed: 0x" << std::hex << caps.capabilities; | 133 "caps check failed: 0x" |
| 134 << std::hex << caps.capabilities; |
| 138 return false; | 135 return false; |
| 139 } | 136 } |
| 140 | 137 |
| 141 if (!SetFormats(input_format, output_profile)) { | 138 if (!SetFormats(input_format, output_profile)) { |
| 142 DLOG(ERROR) << "Failed setting up formats"; | 139 DLOG(ERROR) << "Failed setting up formats"; |
| 143 return false; | 140 return false; |
| 144 } | 141 } |
| 145 | 142 |
| 146 if (input_format != device_input_format_) { | 143 if (input_format != device_input_format_) { |
| 147 DVLOG(1) << "Input format not supported by the HW, will convert to " | 144 DVLOG(1) << "Input format not supported by the HW, will convert to " |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 base::Bind(&V4L2VideoEncodeAccelerator::FrameProcessed, weak_this_, | 217 base::Bind(&V4L2VideoEncodeAccelerator::FrameProcessed, weak_this_, |
| 221 force_keyframe, frame->timestamp())); | 218 force_keyframe, frame->timestamp())); |
| 222 } else { | 219 } else { |
| 223 ImageProcessorInputRecord record; | 220 ImageProcessorInputRecord record; |
| 224 record.frame = frame; | 221 record.frame = frame; |
| 225 record.force_keyframe = force_keyframe; | 222 record.force_keyframe = force_keyframe; |
| 226 image_processor_input_queue_.push(record); | 223 image_processor_input_queue_.push(record); |
| 227 } | 224 } |
| 228 } else { | 225 } else { |
| 229 encoder_thread_.message_loop()->PostTask( | 226 encoder_thread_.message_loop()->PostTask( |
| 230 FROM_HERE, | 227 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask, |
| 231 base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask, | 228 base::Unretained(this), frame, force_keyframe)); |
| 232 base::Unretained(this), | |
| 233 frame, | |
| 234 force_keyframe)); | |
| 235 } | 229 } |
| 236 } | 230 } |
| 237 | 231 |
| 238 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBuffer( | 232 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBuffer( |
| 239 const media::BitstreamBuffer& buffer) { | 233 const media::BitstreamBuffer& buffer) { |
| 240 DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer.id(); | 234 DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer.id(); |
| 241 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 235 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 242 | 236 |
| 243 if (buffer.size() < output_buffer_byte_size_) { | 237 if (buffer.size() < output_buffer_byte_size_) { |
| 244 NOTIFY_ERROR(kInvalidArgumentError); | 238 NOTIFY_ERROR(kInvalidArgumentError); |
| 245 return; | 239 return; |
| 246 } | 240 } |
| 247 | 241 |
| 248 std::unique_ptr<SharedMemoryRegion> shm( | 242 std::unique_ptr<SharedMemoryRegion> shm( |
| 249 new SharedMemoryRegion(buffer, false)); | 243 new SharedMemoryRegion(buffer, false)); |
| 250 if (!shm->Map()) { | 244 if (!shm->Map()) { |
| 251 NOTIFY_ERROR(kPlatformFailureError); | 245 NOTIFY_ERROR(kPlatformFailureError); |
| 252 return; | 246 return; |
| 253 } | 247 } |
| 254 | 248 |
| 255 std::unique_ptr<BitstreamBufferRef> buffer_ref( | 249 std::unique_ptr<BitstreamBufferRef> buffer_ref( |
| 256 new BitstreamBufferRef(buffer.id(), std::move(shm))); | 250 new BitstreamBufferRef(buffer.id(), std::move(shm))); |
| 257 encoder_thread_.message_loop()->PostTask( | 251 encoder_thread_.message_loop()->PostTask( |
| 258 FROM_HERE, | 252 FROM_HERE, |
| 259 base::Bind(&V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask, | 253 base::Bind(&V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask, |
| 260 base::Unretained(this), | 254 base::Unretained(this), base::Passed(&buffer_ref))); |
| 261 base::Passed(&buffer_ref))); | |
| 262 } | 255 } |
| 263 | 256 |
| 264 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChange( | 257 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChange( |
| 265 uint32_t bitrate, | 258 uint32_t bitrate, |
| 266 uint32_t framerate) { | 259 uint32_t framerate) { |
| 267 DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate | 260 DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate |
| 268 << ", framerate=" << framerate; | 261 << ", framerate=" << framerate; |
| 269 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 262 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 270 | 263 |
| 271 encoder_thread_.message_loop()->PostTask( | 264 encoder_thread_.message_loop()->PostTask( |
| 272 FROM_HERE, | 265 FROM_HERE, |
| 273 base::Bind( | 266 base::Bind( |
| 274 &V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask, | 267 &V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask, |
| 275 base::Unretained(this), | 268 base::Unretained(this), bitrate, framerate)); |
| 276 bitrate, | |
| 277 framerate)); | |
| 278 } | 269 } |
| 279 | 270 |
| 280 void V4L2VideoEncodeAccelerator::Destroy() { | 271 void V4L2VideoEncodeAccelerator::Destroy() { |
| 281 DVLOG(3) << "Destroy()"; | 272 DVLOG(3) << "Destroy()"; |
| 282 DCHECK(child_task_runner_->BelongsToCurrentThread()); | 273 DCHECK(child_task_runner_->BelongsToCurrentThread()); |
| 283 | 274 |
| 284 // We're destroying; cancel all callbacks. | 275 // We're destroying; cancel all callbacks. |
| 285 client_ptr_factory_.reset(); | 276 client_ptr_factory_.reset(); |
| 286 weak_this_ptr_factory_.InvalidateWeakPtrs(); | 277 weak_this_ptr_factory_.InvalidateWeakPtrs(); |
| 287 | 278 |
| 288 if (image_processor_.get()) | 279 if (image_processor_.get()) |
| 289 image_processor_.release()->Destroy(); | 280 image_processor_.release()->Destroy(); |
| 290 | 281 |
| 291 // If the encoder thread is running, destroy using posted task. | 282 // If the encoder thread is running, destroy using posted task. |
| 292 if (encoder_thread_.IsRunning()) { | 283 if (encoder_thread_.IsRunning()) { |
| 293 encoder_thread_.message_loop()->PostTask( | 284 encoder_thread_.message_loop()->PostTask( |
| 294 FROM_HERE, | 285 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::DestroyTask, |
| 295 base::Bind(&V4L2VideoEncodeAccelerator::DestroyTask, | 286 base::Unretained(this))); |
| 296 base::Unretained(this))); | |
| 297 // DestroyTask() will put the encoder into kError state and cause all tasks | 287 // DestroyTask() will put the encoder into kError state and cause all tasks |
| 298 // to no-op. | 288 // to no-op. |
| 299 encoder_thread_.Stop(); | 289 encoder_thread_.Stop(); |
| 300 } else { | 290 } else { |
| 301 // Otherwise, call the destroy task directly. | 291 // Otherwise, call the destroy task directly. |
| 302 DestroyTask(); | 292 DestroyTask(); |
| 303 } | 293 } |
| 304 | 294 |
| 305 // Set to kError state just in case. | 295 // Set to kError state just in case. |
| 306 encoder_state_ = kError; | 296 encoder_state_ = kError; |
| 307 | 297 |
| 308 delete this; | 298 delete this; |
| 309 } | 299 } |
| 310 | 300 |
| 311 media::VideoEncodeAccelerator::SupportedProfiles | 301 media::VideoEncodeAccelerator::SupportedProfiles |
| 312 V4L2VideoEncodeAccelerator::GetSupportedProfiles() { | 302 V4L2VideoEncodeAccelerator::GetSupportedProfiles() { |
| 313 SupportedProfiles profiles; | 303 SupportedProfiles profiles; |
| 314 SupportedProfile profile; | 304 SupportedProfile profile; |
| 315 profile.max_framerate_numerator = 30; | 305 profile.max_framerate_numerator = 30; |
| 316 profile.max_framerate_denominator = 1; | 306 profile.max_framerate_denominator = 1; |
| 317 | 307 |
| 318 gfx::Size min_resolution; | 308 gfx::Size min_resolution; |
| 319 v4l2_fmtdesc fmtdesc; | 309 v4l2_fmtdesc fmtdesc; |
| 320 memset(&fmtdesc, 0, sizeof(fmtdesc)); | 310 memset(&fmtdesc, 0, sizeof(fmtdesc)); |
| 321 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 311 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 322 for (; device_->Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) { | 312 for (; device_->Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) { |
| 323 device_->GetSupportedResolution(fmtdesc.pixelformat, | 313 device_->GetSupportedResolution(fmtdesc.pixelformat, &min_resolution, |
| 324 &min_resolution, &profile.max_resolution); | 314 &profile.max_resolution); |
| 325 switch (fmtdesc.pixelformat) { | 315 switch (fmtdesc.pixelformat) { |
| 326 case V4L2_PIX_FMT_H264: | 316 case V4L2_PIX_FMT_H264: |
| 327 profile.profile = media::H264PROFILE_MAIN; | 317 profile.profile = media::H264PROFILE_MAIN; |
| 328 profiles.push_back(profile); | 318 profiles.push_back(profile); |
| 329 break; | 319 break; |
| 330 case V4L2_PIX_FMT_VP8: | 320 case V4L2_PIX_FMT_VP8: |
| 331 profile.profile = media::VP8PROFILE_ANY; | 321 profile.profile = media::VP8PROFILE_ANY; |
| 332 profiles.push_back(profile); | 322 profiles.push_back(profile); |
| 333 break; | 323 break; |
| 334 case V4L2_PIX_FMT_VP9: | 324 case V4L2_PIX_FMT_VP9: |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 | 481 |
| 492 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), | 482 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(), |
| 493 // so either: | 483 // so either: |
| 494 // * device_poll_thread_ is running normally | 484 // * device_poll_thread_ is running normally |
| 495 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down, | 485 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down, |
| 496 // in which case we're in kError state, and we should have early-outed | 486 // in which case we're in kError state, and we should have early-outed |
| 497 // already. | 487 // already. |
| 498 DCHECK(device_poll_thread_.message_loop()); | 488 DCHECK(device_poll_thread_.message_loop()); |
| 499 // Queue the DevicePollTask() now. | 489 // Queue the DevicePollTask() now. |
| 500 device_poll_thread_.message_loop()->PostTask( | 490 device_poll_thread_.message_loop()->PostTask( |
| 501 FROM_HERE, | 491 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask, |
| 502 base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask, | 492 base::Unretained(this), poll_device)); |
| 503 base::Unretained(this), | |
| 504 poll_device)); | |
| 505 | 493 |
| 506 DVLOG(2) << __func__ << ": buffer counts: ENC[" | 494 DVLOG(2) << __func__ << ": buffer counts: ENC[" << encoder_input_queue_.size() |
| 507 << encoder_input_queue_.size() << "] => DEVICE[" | 495 << "] => DEVICE[" << free_input_buffers_.size() << "+" |
| 508 << free_input_buffers_.size() << "+" | 496 << input_buffer_queued_count_ << "/" << input_buffer_map_.size() |
| 509 << input_buffer_queued_count_ << "/" | 497 << "->" << free_output_buffers_.size() << "+" |
| 510 << input_buffer_map_.size() << "->" | 498 << output_buffer_queued_count_ << "/" << output_buffer_map_.size() |
| 511 << free_output_buffers_.size() << "+" | 499 << "] => OUT[" << encoder_output_queue_.size() << "]"; |
| 512 << output_buffer_queued_count_ << "/" | |
| 513 << output_buffer_map_.size() << "] => OUT[" | |
| 514 << encoder_output_queue_.size() << "]"; | |
| 515 } | 500 } |
| 516 | 501 |
| 517 void V4L2VideoEncodeAccelerator::Enqueue() { | 502 void V4L2VideoEncodeAccelerator::Enqueue() { |
| 518 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); | 503 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); |
| 519 | 504 |
| 520 DVLOG(3) << "Enqueue() " | 505 DVLOG(3) << "Enqueue() " |
| 521 << "free_input_buffers: " << free_input_buffers_.size() | 506 << "free_input_buffers: " << free_input_buffers_.size() |
| 522 << "input_queue: " << encoder_input_queue_.size(); | 507 << "input_queue: " << encoder_input_queue_.size(); |
| 523 | 508 |
| 524 // Enqueue all the inputs we can. | 509 // Enqueue all the inputs we can. |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 643 memcpy(target_data + stream_header_size_, output_data, output_size); | 628 memcpy(target_data + stream_header_size_, output_data, output_size); |
| 644 output_size += stream_header_size_; | 629 output_size += stream_header_size_; |
| 645 } else { | 630 } else { |
| 646 memcpy(target_data, output_data, output_size); | 631 memcpy(target_data, output_data, output_size); |
| 647 } | 632 } |
| 648 } else { | 633 } else { |
| 649 memcpy(target_data, output_data, output_size); | 634 memcpy(target_data, output_data, output_size); |
| 650 } | 635 } |
| 651 | 636 |
| 652 DVLOG(3) << "Dequeue(): returning " | 637 DVLOG(3) << "Dequeue(): returning " |
| 653 "bitstream_buffer_id=" << output_record.buffer_ref->id | 638 "bitstream_buffer_id=" |
| 654 << ", size=" << output_size << ", key_frame=" << key_frame; | 639 << output_record.buffer_ref->id << ", size=" << output_size |
| 640 << ", key_frame=" << key_frame; |
| 655 child_task_runner_->PostTask( | 641 child_task_runner_->PostTask( |
| 656 FROM_HERE, | 642 FROM_HERE, |
| 657 base::Bind(&Client::BitstreamBufferReady, client_, | 643 base::Bind(&Client::BitstreamBufferReady, client_, |
| 658 output_record.buffer_ref->id, output_size, key_frame)); | 644 output_record.buffer_ref->id, output_size, key_frame)); |
| 659 output_record.at_device = false; | 645 output_record.at_device = false; |
| 660 output_record.buffer_ref.reset(); | 646 output_record.buffer_ref.reset(); |
| 661 free_output_buffers_.push_back(dqbuf.index); | 647 free_output_buffers_.push_back(dqbuf.index); |
| 662 output_buffer_queued_count_--; | 648 output_buffer_queued_count_--; |
| 663 } | 649 } |
| 664 } | 650 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 676 struct v4l2_buffer qbuf; | 662 struct v4l2_buffer qbuf; |
| 677 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; | 663 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES]; |
| 678 memset(&qbuf, 0, sizeof(qbuf)); | 664 memset(&qbuf, 0, sizeof(qbuf)); |
| 679 memset(qbuf_planes, 0, sizeof(qbuf_planes)); | 665 memset(qbuf_planes, 0, sizeof(qbuf_planes)); |
| 680 qbuf.index = index; | 666 qbuf.index = index; |
| 681 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 667 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 682 qbuf.m.planes = qbuf_planes; | 668 qbuf.m.planes = qbuf_planes; |
| 683 | 669 |
| 684 DCHECK_EQ(device_input_format_, frame->format()); | 670 DCHECK_EQ(device_input_format_, frame->format()); |
| 685 for (size_t i = 0; i < input_planes_count_; ++i) { | 671 for (size_t i = 0; i < input_planes_count_; ++i) { |
| 686 qbuf.m.planes[i].bytesused = | 672 qbuf.m.planes[i].bytesused = base::checked_cast<__u32>( |
| 687 base::checked_cast<__u32>(media::VideoFrame::PlaneSize( | 673 media::VideoFrame::PlaneSize(frame->format(), i, input_allocated_size_) |
| 688 frame->format(), i, input_allocated_size_).GetArea()); | 674 .GetArea()); |
| 689 | 675 |
| 690 switch (input_memory_type_) { | 676 switch (input_memory_type_) { |
| 691 case V4L2_MEMORY_USERPTR: | 677 case V4L2_MEMORY_USERPTR: |
| 692 qbuf.m.planes[i].length = qbuf.m.planes[i].bytesused; | 678 qbuf.m.planes[i].length = qbuf.m.planes[i].bytesused; |
| 693 qbuf.m.planes[i].m.userptr = | 679 qbuf.m.planes[i].m.userptr = |
| 694 reinterpret_cast<unsigned long>(frame->data(i)); | 680 reinterpret_cast<unsigned long>(frame->data(i)); |
| 695 DCHECK(qbuf.m.planes[i].m.userptr); | 681 DCHECK(qbuf.m.planes[i].m.userptr); |
| 696 break; | 682 break; |
| 697 | 683 |
| 698 case V4L2_MEMORY_DMABUF: | 684 case V4L2_MEMORY_DMABUF: |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 754 | 740 |
| 755 // Start up the device poll thread and schedule its first DevicePollTask(). | 741 // Start up the device poll thread and schedule its first DevicePollTask(). |
| 756 if (!device_poll_thread_.Start()) { | 742 if (!device_poll_thread_.Start()) { |
| 757 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; | 743 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; |
| 758 NOTIFY_ERROR(kPlatformFailureError); | 744 NOTIFY_ERROR(kPlatformFailureError); |
| 759 return false; | 745 return false; |
| 760 } | 746 } |
| 761 // Enqueue a poll task with no devices to poll on -- it will wait only on the | 747 // Enqueue a poll task with no devices to poll on -- it will wait only on the |
| 762 // interrupt fd. | 748 // interrupt fd. |
| 763 device_poll_thread_.message_loop()->PostTask( | 749 device_poll_thread_.message_loop()->PostTask( |
| 764 FROM_HERE, | 750 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask, |
| 765 base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask, | 751 base::Unretained(this), false)); |
| 766 base::Unretained(this), | |
| 767 false)); | |
| 768 | 752 |
| 769 return true; | 753 return true; |
| 770 } | 754 } |
| 771 | 755 |
| 772 bool V4L2VideoEncodeAccelerator::StopDevicePoll() { | 756 bool V4L2VideoEncodeAccelerator::StopDevicePoll() { |
| 773 DVLOG(3) << "StopDevicePoll()"; | 757 DVLOG(3) << "StopDevicePoll()"; |
| 774 | 758 |
| 775 // Signal the DevicePollTask() to stop, and stop the device poll thread. | 759 // Signal the DevicePollTask() to stop, and stop the device poll thread. |
| 776 if (!device_->SetDevicePollInterrupt()) | 760 if (!device_->SetDevicePollInterrupt()) |
| 777 return false; | 761 return false; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 825 | 809 |
| 826 bool event_pending; | 810 bool event_pending; |
| 827 if (!device_->Poll(poll_device, &event_pending)) { | 811 if (!device_->Poll(poll_device, &event_pending)) { |
| 828 NOTIFY_ERROR(kPlatformFailureError); | 812 NOTIFY_ERROR(kPlatformFailureError); |
| 829 return; | 813 return; |
| 830 } | 814 } |
| 831 | 815 |
| 832 // All processing should happen on ServiceDeviceTask(), since we shouldn't | 816 // All processing should happen on ServiceDeviceTask(), since we shouldn't |
| 833 // touch encoder state from this thread. | 817 // touch encoder state from this thread. |
| 834 encoder_thread_.message_loop()->PostTask( | 818 encoder_thread_.message_loop()->PostTask( |
| 835 FROM_HERE, | 819 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::ServiceDeviceTask, |
| 836 base::Bind(&V4L2VideoEncodeAccelerator::ServiceDeviceTask, | 820 base::Unretained(this))); |
| 837 base::Unretained(this))); | |
| 838 } | 821 } |
| 839 | 822 |
| 840 void V4L2VideoEncodeAccelerator::NotifyError(Error error) { | 823 void V4L2VideoEncodeAccelerator::NotifyError(Error error) { |
| 841 DVLOG(1) << "NotifyError(): error=" << error; | 824 DVLOG(1) << "NotifyError(): error=" << error; |
| 842 | 825 |
| 843 if (!child_task_runner_->BelongsToCurrentThread()) { | 826 if (!child_task_runner_->BelongsToCurrentThread()) { |
| 844 child_task_runner_->PostTask( | 827 child_task_runner_->PostTask( |
| 845 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::NotifyError, | 828 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::NotifyError, |
| 846 weak_this_, error)); | 829 weak_this_, error)); |
| 847 return; | 830 return; |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1184 struct v4l2_plane planes[1]; | 1167 struct v4l2_plane planes[1]; |
| 1185 struct v4l2_buffer buffer; | 1168 struct v4l2_buffer buffer; |
| 1186 memset(&buffer, 0, sizeof(buffer)); | 1169 memset(&buffer, 0, sizeof(buffer)); |
| 1187 memset(planes, 0, sizeof(planes)); | 1170 memset(planes, 0, sizeof(planes)); |
| 1188 buffer.index = i; | 1171 buffer.index = i; |
| 1189 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1172 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1190 buffer.memory = V4L2_MEMORY_MMAP; | 1173 buffer.memory = V4L2_MEMORY_MMAP; |
| 1191 buffer.m.planes = planes; | 1174 buffer.m.planes = planes; |
| 1192 buffer.length = arraysize(planes); | 1175 buffer.length = arraysize(planes); |
| 1193 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer); | 1176 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer); |
| 1194 void* address = device_->Mmap(NULL, | 1177 void* address = |
| 1195 buffer.m.planes[0].length, | 1178 device_->Mmap(NULL, buffer.m.planes[0].length, PROT_READ | PROT_WRITE, |
| 1196 PROT_READ | PROT_WRITE, | 1179 MAP_SHARED, buffer.m.planes[0].m.mem_offset); |
| 1197 MAP_SHARED, | |
| 1198 buffer.m.planes[0].m.mem_offset); | |
| 1199 if (address == MAP_FAILED) { | 1180 if (address == MAP_FAILED) { |
| 1200 PLOG(ERROR) << "CreateOutputBuffers(): mmap() failed"; | 1181 PLOG(ERROR) << "CreateOutputBuffers(): mmap() failed"; |
| 1201 return false; | 1182 return false; |
| 1202 } | 1183 } |
| 1203 output_buffer_map_[i].address = address; | 1184 output_buffer_map_[i].address = address; |
| 1204 output_buffer_map_[i].length = buffer.m.planes[0].length; | 1185 output_buffer_map_[i].length = buffer.m.planes[0].length; |
| 1205 free_output_buffers_.push_back(i); | 1186 free_output_buffers_.push_back(i); |
| 1206 } | 1187 } |
| 1207 | 1188 |
| 1208 return true; | 1189 return true; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1239 memset(&reqbufs, 0, sizeof(reqbufs)); | 1220 memset(&reqbufs, 0, sizeof(reqbufs)); |
| 1240 reqbufs.count = 0; | 1221 reqbufs.count = 0; |
| 1241 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1222 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| 1242 reqbufs.memory = V4L2_MEMORY_MMAP; | 1223 reqbufs.memory = V4L2_MEMORY_MMAP; |
| 1243 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 1224 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
| 1244 | 1225 |
| 1245 output_buffer_map_.clear(); | 1226 output_buffer_map_.clear(); |
| 1246 free_output_buffers_.clear(); | 1227 free_output_buffers_.clear(); |
| 1247 } | 1228 } |
| 1248 | 1229 |
| 1249 } // namespace content | 1230 } // namespace media |
| OLD | NEW |