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

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

Issue 2274493002: V4L2VEA: Improve H264 stream header handling. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/gpu/v4l2_video_encode_accelerator.h" 5 #include "media/gpu/v4l2_video_encode_accelerator.h"
6 6
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <linux/videodev2.h> 8 #include <linux/videodev2.h>
9 #include <poll.h> 9 #include <poll.h>
10 #include <string.h> 10 #include <string.h>
11 #include <sys/eventfd.h> 11 #include <sys/eventfd.h>
12 #include <sys/ioctl.h> 12 #include <sys/ioctl.h>
13 #include <sys/mman.h> 13 #include <sys/mman.h>
14 14
15 #include <utility> 15 #include <utility>
16 16
17 #include "base/callback.h" 17 #include "base/callback.h"
18 #include "base/command_line.h" 18 #include "base/command_line.h"
19 #include "base/macros.h" 19 #include "base/macros.h"
20 #include "base/numerics/safe_conversions.h" 20 #include "base/numerics/safe_conversions.h"
21 #include "base/single_thread_task_runner.h" 21 #include "base/single_thread_task_runner.h"
22 #include "base/threading/thread_task_runner_handle.h" 22 #include "base/threading/thread_task_runner_handle.h"
23 #include "base/trace_event/trace_event.h" 23 #include "base/trace_event/trace_event.h"
24 #include "media/base/bind_to_current_loop.h" 24 #include "media/base/bind_to_current_loop.h"
25 #include "media/base/bitstream_buffer.h" 25 #include "media/base/bitstream_buffer.h"
26 #include "media/filters/h264_parser.h"
26 #include "media/gpu/shared_memory_region.h" 27 #include "media/gpu/shared_memory_region.h"
27 28
28 #define NOTIFY_ERROR(x) \ 29 #define NOTIFY_ERROR(x) \
29 do { \ 30 do { \
30 LOG(ERROR) << "Setting error state:" << x; \ 31 LOG(ERROR) << "Setting error state:" << x; \
31 SetErrorState(x); \ 32 SetErrorState(x); \
32 } while (0) 33 } while (0)
33 34
34 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \ 35 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str) \
35 do { \ 36 do { \
(...skipping 23 matching lines...) Expand all
59 : id(id), shm(std::move(shm)) {} 60 : id(id), shm(std::move(shm)) {}
60 const int32_t id; 61 const int32_t id;
61 const std::unique_ptr<SharedMemoryRegion> shm; 62 const std::unique_ptr<SharedMemoryRegion> shm;
62 }; 63 };
63 64
64 V4L2VideoEncodeAccelerator::InputRecord::InputRecord() : at_device(false) {} 65 V4L2VideoEncodeAccelerator::InputRecord::InputRecord() : at_device(false) {}
65 66
66 V4L2VideoEncodeAccelerator::InputRecord::~InputRecord() {} 67 V4L2VideoEncodeAccelerator::InputRecord::~InputRecord() {}
67 68
68 V4L2VideoEncodeAccelerator::OutputRecord::OutputRecord() 69 V4L2VideoEncodeAccelerator::OutputRecord::OutputRecord()
69 : at_device(false), address(NULL), length(0) {} 70 : at_device(false), buffer_ref(nullptr), address(nullptr), length(0) {}
kcwu 2016/08/23 10:02:21 Isn't buffer_ref nullptr by default ctor?
Pawel Osciak 2016/08/24 07:42:50 Good point.
70 71
71 V4L2VideoEncodeAccelerator::OutputRecord::~OutputRecord() {} 72 V4L2VideoEncodeAccelerator::OutputRecord::~OutputRecord() {}
72 73
73 V4L2VideoEncodeAccelerator::ImageProcessorInputRecord:: 74 V4L2VideoEncodeAccelerator::ImageProcessorInputRecord::
74 ImageProcessorInputRecord() 75 ImageProcessorInputRecord()
75 : force_keyframe(false) {} 76 : force_keyframe(false) {}
76 77
77 V4L2VideoEncodeAccelerator::ImageProcessorInputRecord:: 78 V4L2VideoEncodeAccelerator::ImageProcessorInputRecord::
78 ~ImageProcessorInputRecord() {} 79 ~ImageProcessorInputRecord() {}
79 80
80 V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator( 81 V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator(
81 const scoped_refptr<V4L2Device>& device) 82 const scoped_refptr<V4L2Device>& device)
82 : child_task_runner_(base::ThreadTaskRunnerHandle::Get()), 83 : child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
83 output_buffer_byte_size_(0), 84 output_buffer_byte_size_(0),
84 device_input_format_(PIXEL_FORMAT_UNKNOWN), 85 device_input_format_(PIXEL_FORMAT_UNKNOWN),
85 input_planes_count_(0), 86 input_planes_count_(0),
86 output_format_fourcc_(0), 87 output_format_fourcc_(0),
87 encoder_state_(kUninitialized), 88 encoder_state_(kUninitialized),
88 stream_header_size_(0),
89 device_(device), 89 device_(device),
90 input_streamon_(false), 90 input_streamon_(false),
91 input_buffer_queued_count_(0), 91 input_buffer_queued_count_(0),
92 input_memory_type_(V4L2_MEMORY_USERPTR), 92 input_memory_type_(V4L2_MEMORY_USERPTR),
93 output_streamon_(false), 93 output_streamon_(false),
94 output_buffer_queued_count_(0), 94 output_buffer_queued_count_(0),
95 encoder_thread_("V4L2EncoderThread"), 95 encoder_thread_("V4L2EncoderThread"),
96 device_poll_thread_("V4L2EncoderDevicePollThread"), 96 device_poll_thread_("V4L2EncoderDevicePollThread"),
97 weak_this_ptr_factory_(this) { 97 weak_this_ptr_factory_(this) {
98 weak_this_ = weak_this_ptr_factory_.GetWeakPtr(); 98 weak_this_ = weak_this_ptr_factory_.GetWeakPtr();
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 DCHECK(child_task_runner_->BelongsToCurrentThread()); 395 DCHECK(child_task_runner_->BelongsToCurrentThread());
396 DVLOG(3) << __func__ << ": output_buffer_index=" << output_buffer_index; 396 DVLOG(3) << __func__ << ": output_buffer_index=" << output_buffer_index;
397 free_image_processor_output_buffers_.push_back(output_buffer_index); 397 free_image_processor_output_buffers_.push_back(output_buffer_index);
398 if (!image_processor_input_queue_.empty()) { 398 if (!image_processor_input_queue_.empty()) {
399 ImageProcessorInputRecord record = image_processor_input_queue_.front(); 399 ImageProcessorInputRecord record = image_processor_input_queue_.front();
400 image_processor_input_queue_.pop(); 400 image_processor_input_queue_.pop();
401 Encode(record.frame, record.force_keyframe); 401 Encode(record.frame, record.force_keyframe);
402 } 402 }
403 } 403 }
404 404
405 namespace {
kcwu 2016/08/23 10:02:21 Move to beginning of this file? Looks like no rule
Pawel Osciak 2016/08/24 07:42:50 Done.
406 const uint8_t kH264StartCode[] = {0, 0, 0, 1};
407 const size_t kH264StartCodeSize = sizeof(kH264StartCode);
408
409 // Copy a H.264 NALU of size |src_size| (without start code), located at |src|,
410 // into a buffer starting at |dst| of size |dst_size|, prepending it with
411 // a H.264 start code (as long as both fit). After copying, update |dst| to
412 // point to the address immediately after the copied data, and update |dst_size|
413 // to contain remaining destination buffer size.
414 static void CopyNALUPrependingStartCode(const uint8_t* src,
415 size_t src_size,
416 uint8_t** dst,
417 size_t* dst_size) {
418 size_t size_to_copy = src_size + kH264StartCodeSize;
kcwu 2016/08/23 10:02:21 I'd like to write kH264StartCodeSize + src_size to
Pawel Osciak 2016/08/24 07:42:50 Yes, I like that too. Done.
419 if (size_to_copy > *dst_size) {
420 DVLOG(1) << "Could not copy a NALU, not enough space in destination buffer";
421 return;
422 }
423
424 memcpy(*dst, kH264StartCode, kH264StartCodeSize);
425 memcpy(*dst + kH264StartCodeSize, src, src_size);
426
427 *dst += size_to_copy;
428 *dst_size -= size_to_copy;
429 }
430 }
431
432 size_t V4L2VideoEncodeAccelerator::CopyIntoOutputBuffer(
433 const uint8_t* bitstream_data,
434 size_t bitstream_size,
435 std::unique_ptr<BitstreamBufferRef> buffer_ref) {
436 uint8_t* dst_ptr = static_cast<uint8_t*>(buffer_ref->shm->memory());
437 size_t remaining_dst_size = buffer_ref->shm->size();
438
439 if (!inject_sps_and_pps_) {
440 if (bitstream_size <= remaining_dst_size) {
441 memcpy(dst_ptr, bitstream_data, bitstream_size);
442 return bitstream_size;
443 } else {
444 DVLOG(1) << "Output data did not fit in the BitstreamBuffer";
kcwu 2016/08/23 10:02:22 Original code will still copy up to remaining_dst_
Pawel Osciak 2016/08/24 07:42:50 0-sized buffer will tell the client we dropped som
445 return 0;
446 }
447 }
448
449 // Cache the newest SPS and PPS found in the stream, and inject them before
450 // each IDR found.
451 H264Parser parser;
452 parser.SetStream(bitstream_data, bitstream_size);
453 H264NALU nalu;
454
455 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) {
kcwu 2016/08/23 10:02:22 Two questions: 1. Are SPS and PPS always before ID
kcwu 2016/08/24 07:16:44 Please ignore above questions. I learned how it wo
456 // nalu.size is always without the start code, regardless of the NALU type.
457 if (nalu.size + kH264StartCodeSize > remaining_dst_size) {
458 DVLOG(1) << "Output data did not fit in the BitstreamBuffer";
459 break;
460 }
461
462 switch (nalu.nal_unit_type) {
463 case H264NALU::kSPS:
464 cached_sps_.resize(nalu.size);
465 memcpy(cached_sps_.data(), nalu.data, nalu.size);
466 cached_h264_header_size_ =
467 cached_sps_.size() + cached_pps_.size() + 2 * kH264StartCodeSize;
468 break;
469
470 case H264NALU::kPPS:
471 cached_pps_.resize(nalu.size);
472 memcpy(cached_pps_.data(), nalu.data, nalu.size);
473 cached_h264_header_size_ =
474 cached_sps_.size() + cached_pps_.size() + 2 * kH264StartCodeSize;
475 break;
476
477 case H264NALU::kIDRSlice:
478 // Only inject if we have both headers cached, and enough space for both
479 // the headers and the NALU itself.
480 if (cached_sps_.empty() || cached_pps_.empty() ||
481 cached_h264_header_size_ + nalu.size + kH264StartCodeSize >=
kcwu 2016/08/23 10:02:22 == is ok?
Pawel Osciak 2016/08/24 07:42:50 Done.
482 remaining_dst_size)
483 break;
484
485 CopyNALUPrependingStartCode(cached_sps_.data(), cached_sps_.size(),
486 &dst_ptr, &remaining_dst_size);
487 CopyNALUPrependingStartCode(cached_pps_.data(), cached_pps_.size(),
488 &dst_ptr, &remaining_dst_size);
489 DVLOG(2) << "Stream header injected before IDR";
490 break;
491 }
492
493 CopyNALUPrependingStartCode(nalu.data, nalu.size, &dst_ptr,
494 &remaining_dst_size);
495 }
496
497 return buffer_ref->shm->size() - remaining_dst_size;
498 }
499
405 void V4L2VideoEncodeAccelerator::EncodeTask( 500 void V4L2VideoEncodeAccelerator::EncodeTask(
406 const scoped_refptr<VideoFrame>& frame, 501 const scoped_refptr<VideoFrame>& frame,
407 bool force_keyframe) { 502 bool force_keyframe) {
408 DVLOG(3) << "EncodeTask(): force_keyframe=" << force_keyframe; 503 DVLOG(3) << "EncodeTask(): force_keyframe=" << force_keyframe;
409 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread()); 504 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread());
410 DCHECK_NE(encoder_state_, kUninitialized); 505 DCHECK_NE(encoder_state_, kUninitialized);
411 506
412 if (encoder_state_ == kError) { 507 if (encoder_state_ == kError) {
413 DVLOG(2) << "EncodeTask(): early out: kError state"; 508 DVLOG(2) << "EncodeTask(): early out: kError state";
414 return; 509 return;
(...skipping 19 matching lines...) Expand all
434 return; 529 return;
435 } 530 }
436 } 531 }
437 } 532 }
438 533
439 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask( 534 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask(
440 std::unique_ptr<BitstreamBufferRef> buffer_ref) { 535 std::unique_ptr<BitstreamBufferRef> buffer_ref) {
441 DVLOG(3) << "UseOutputBitstreamBufferTask(): id=" << buffer_ref->id; 536 DVLOG(3) << "UseOutputBitstreamBufferTask(): id=" << buffer_ref->id;
442 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread()); 537 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread());
443 538
444 encoder_output_queue_.push_back( 539 encoder_output_queue_.push_back(std::move(buffer_ref));
445 linked_ptr<BitstreamBufferRef>(buffer_ref.release()));
446 Enqueue(); 540 Enqueue();
447 541
448 if (encoder_state_ == kInitialized) { 542 if (encoder_state_ == kInitialized) {
449 // Finish setting up our OUTPUT queue. See: Initialize(). 543 // Finish setting up our OUTPUT queue. See: Initialize().
450 // VIDIOC_REQBUFS on OUTPUT queue. 544 // VIDIOC_REQBUFS on OUTPUT queue.
451 if (!CreateInputBuffers()) 545 if (!CreateInputBuffers())
452 return; 546 return;
453 if (!StartDevicePoll()) 547 if (!StartDevicePoll())
454 return; 548 return;
455 encoder_state_ = kEncoding; 549 encoder_state_ = kEncoding;
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 // EAGAIN if we're just out of buffers to dequeue. 704 // EAGAIN if we're just out of buffers to dequeue.
611 break; 705 break;
612 } 706 }
613 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF"; 707 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF";
614 NOTIFY_ERROR(kPlatformFailureError); 708 NOTIFY_ERROR(kPlatformFailureError);
615 return; 709 return;
616 } 710 }
617 const bool key_frame = ((dqbuf.flags & V4L2_BUF_FLAG_KEYFRAME) != 0); 711 const bool key_frame = ((dqbuf.flags & V4L2_BUF_FLAG_KEYFRAME) != 0);
618 OutputRecord& output_record = output_buffer_map_[dqbuf.index]; 712 OutputRecord& output_record = output_buffer_map_[dqbuf.index];
619 DCHECK(output_record.at_device); 713 DCHECK(output_record.at_device);
620 DCHECK(output_record.buffer_ref.get()); 714 DCHECK(output_record.buffer_ref);
621 715
622 void* output_data = output_record.address; 716 int32_t bitstream_buffer_id = output_record.buffer_ref->id;
623 size_t output_size = dqbuf.m.planes[0].bytesused; 717 size_t output_data_size = CopyIntoOutputBuffer(
624 // This shouldn't happen, but just in case. We should be able to recover 718 static_cast<uint8_t*>(output_record.address),
625 // after next keyframe after showing some corruption. 719 base::checked_cast<size_t>(dqbuf.m.planes[0].bytesused),
626 DCHECK_LE(output_size, output_buffer_byte_size_); 720 std::move(output_record.buffer_ref));
627 if (output_size > output_buffer_byte_size_)
628 output_size = output_buffer_byte_size_;
629 uint8_t* target_data =
630 reinterpret_cast<uint8_t*>(output_record.buffer_ref->shm->memory());
631 if (output_format_fourcc_ == V4L2_PIX_FMT_H264) {
632 if (stream_header_size_ == 0) {
633 // Assume that the first buffer dequeued is the stream header.
634 stream_header_size_ = output_size;
635 stream_header_.reset(new uint8_t[stream_header_size_]);
636 memcpy(stream_header_.get(), output_data, stream_header_size_);
637 }
638 if (key_frame &&
639 output_buffer_byte_size_ - stream_header_size_ >= output_size) {
640 // Insert stream header before every keyframe.
641 memcpy(target_data, stream_header_.get(), stream_header_size_);
642 memcpy(target_data + stream_header_size_, output_data, output_size);
643 output_size += stream_header_size_;
644 } else {
645 memcpy(target_data, output_data, output_size);
646 }
647 } else {
648 memcpy(target_data, output_data, output_size);
649 }
650 721
651 DVLOG(3) << "Dequeue(): returning " 722 DVLOG(3) << "Dequeue(): returning "
652 << "bitstream_buffer_id=" << output_record.buffer_ref->id 723 << "bitstream_buffer_id=" << bitstream_buffer_id
653 << ", size=" << output_size 724 << ", size=" << output_data_size << ", key_frame=" << key_frame;
654 << ", key_frame=" << key_frame; 725
655 child_task_runner_->PostTask( 726 child_task_runner_->PostTask(
656 FROM_HERE, 727 FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_,
657 base::Bind( 728 bitstream_buffer_id, output_data_size, key_frame,
658 &Client::BitstreamBufferReady, client_, 729 base::TimeDelta::FromMicroseconds(
659 output_record.buffer_ref->id, output_size, key_frame, 730 dqbuf.timestamp.tv_usec +
660 base::TimeDelta::FromMicroseconds( 731 dqbuf.timestamp.tv_sec *
661 dqbuf.timestamp.tv_usec + 732 base::Time::kMicrosecondsPerSecond)));
662 dqbuf.timestamp.tv_sec * base::Time::kMicrosecondsPerSecond))); 733
663 output_record.at_device = false; 734 output_record.at_device = false;
664 output_record.buffer_ref.reset();
665 free_output_buffers_.push_back(dqbuf.index); 735 free_output_buffers_.push_back(dqbuf.index);
666 output_buffer_queued_count_--; 736 output_buffer_queued_count_--;
667 } 737 }
668 } 738 }
669 739
670 bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() { 740 bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() {
671 DVLOG(3) << "EnqueueInputRecord()"; 741 DVLOG(3) << "EnqueueInputRecord()";
672 DCHECK(!free_input_buffers_.empty()); 742 DCHECK(!free_input_buffers_.empty());
673 DCHECK(!encoder_input_queue_.empty()); 743 DCHECK(!encoder_input_queue_.empty());
674 744
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 input_buffer_queued_count_++; 795 input_buffer_queued_count_++;
726 return true; 796 return true;
727 } 797 }
728 798
729 bool V4L2VideoEncodeAccelerator::EnqueueOutputRecord() { 799 bool V4L2VideoEncodeAccelerator::EnqueueOutputRecord() {
730 DVLOG(3) << "EnqueueOutputRecord()"; 800 DVLOG(3) << "EnqueueOutputRecord()";
731 DCHECK(!free_output_buffers_.empty()); 801 DCHECK(!free_output_buffers_.empty());
732 DCHECK(!encoder_output_queue_.empty()); 802 DCHECK(!encoder_output_queue_.empty());
733 803
734 // Enqueue an output (VIDEO_CAPTURE) buffer. 804 // Enqueue an output (VIDEO_CAPTURE) buffer.
735 linked_ptr<BitstreamBufferRef> output_buffer = encoder_output_queue_.back();
736 const int index = free_output_buffers_.back(); 805 const int index = free_output_buffers_.back();
737 OutputRecord& output_record = output_buffer_map_[index]; 806 OutputRecord& output_record = output_buffer_map_[index];
738 DCHECK(!output_record.at_device); 807 DCHECK(!output_record.at_device);
739 DCHECK(!output_record.buffer_ref.get()); 808 DCHECK(!output_record.buffer_ref);
740 struct v4l2_buffer qbuf; 809 struct v4l2_buffer qbuf;
741 struct v4l2_plane qbuf_planes[1]; 810 struct v4l2_plane qbuf_planes[1];
742 memset(&qbuf, 0, sizeof(qbuf)); 811 memset(&qbuf, 0, sizeof(qbuf));
743 memset(qbuf_planes, 0, sizeof(qbuf_planes)); 812 memset(qbuf_planes, 0, sizeof(qbuf_planes));
744 qbuf.index = index; 813 qbuf.index = index;
745 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 814 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
746 qbuf.memory = V4L2_MEMORY_MMAP; 815 qbuf.memory = V4L2_MEMORY_MMAP;
747 qbuf.m.planes = qbuf_planes; 816 qbuf.m.planes = qbuf_planes;
748 qbuf.length = 1; 817 qbuf.length = 1;
749 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf); 818 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
750 output_record.at_device = true; 819 output_record.at_device = true;
751 output_record.buffer_ref = output_buffer; 820 output_record.buffer_ref = std::move(encoder_output_queue_.back());
752 encoder_output_queue_.pop_back(); 821 encoder_output_queue_.pop_back();
753 free_output_buffers_.pop_back(); 822 free_output_buffers_.pop_back();
754 output_buffer_queued_count_++; 823 output_buffer_queued_count_++;
755 return true; 824 return true;
756 } 825 }
757 826
758 bool V4L2VideoEncodeAccelerator::StartDevicePoll() { 827 bool V4L2VideoEncodeAccelerator::StartDevicePoll() {
759 DVLOG(3) << "StartDevicePoll()"; 828 DVLOG(3) << "StartDevicePoll()";
760 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread()); 829 DCHECK(encoder_thread_.task_runner()->BelongsToCurrentThread());
761 DCHECK(!device_poll_thread_.IsRunning()); 830 DCHECK(!device_poll_thread_.IsRunning());
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after
1037 // The width and height might be adjusted by driver. 1106 // The width and height might be adjusted by driver.
1038 // Need to read it back and set to visible_size_. 1107 // Need to read it back and set to visible_size_.
1039 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_CROP, &crop); 1108 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_G_CROP, &crop);
1040 visible_size_.SetSize(crop.c.width, crop.c.height); 1109 visible_size_.SetSize(crop.c.width, crop.c.height);
1041 DVLOG(3) << "After adjusted by driver, visible_size_=" 1110 DVLOG(3) << "After adjusted by driver, visible_size_="
1042 << visible_size_.ToString(); 1111 << visible_size_.ToString();
1043 1112
1044 return true; 1113 return true;
1045 } 1114 }
1046 1115
1116 bool V4L2VideoEncodeAccelerator::IsCtrlExposed(uint32_t ctrl_id) {
1117 struct v4l2_queryctrl query_ctrl;
1118 memset(&query_ctrl, 0, sizeof(query_ctrl));
1119 query_ctrl.id = ctrl_id;
1120
1121 return device_->Ioctl(VIDIOC_QUERYCTRL, &query_ctrl) == 0;
1122 }
1123
1047 bool V4L2VideoEncodeAccelerator::SetExtCtrls( 1124 bool V4L2VideoEncodeAccelerator::SetExtCtrls(
1048 std::vector<struct v4l2_ext_control> ctrls) { 1125 std::vector<struct v4l2_ext_control> ctrls) {
1049 struct v4l2_ext_controls ext_ctrls; 1126 struct v4l2_ext_controls ext_ctrls;
1050 memset(&ext_ctrls, 0, sizeof(ext_ctrls)); 1127 memset(&ext_ctrls, 0, sizeof(ext_ctrls));
1051 ext_ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG; 1128 ext_ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
1052 ext_ctrls.count = ctrls.size(); 1129 ext_ctrls.count = ctrls.size();
1053 ext_ctrls.controls = &ctrls[0]; 1130 ext_ctrls.controls = &ctrls[0];
1054 return device_->Ioctl(VIDIOC_S_EXT_CTRLS, &ext_ctrls) == 0; 1131 return device_->Ioctl(VIDIOC_S_EXT_CTRLS, &ext_ctrls) == 0;
1055 } 1132 }
1056 1133
1057 bool V4L2VideoEncodeAccelerator::InitControls() { 1134 bool V4L2VideoEncodeAccelerator::InitControls() {
1058 std::vector<struct v4l2_ext_control> ctrls; 1135 std::vector<struct v4l2_ext_control> ctrls;
1059 struct v4l2_ext_control ctrl; 1136 struct v4l2_ext_control ctrl;
1060 1137
1061 // Enable frame-level bitrate control. This is the only mandatory control. 1138 // Enable frame-level bitrate control. This is the only mandatory control.
1062 memset(&ctrl, 0, sizeof(ctrl)); 1139 memset(&ctrl, 0, sizeof(ctrl));
1063 ctrl.id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE; 1140 ctrl.id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE;
1064 ctrl.value = 1; 1141 ctrl.value = 1;
1065 ctrls.push_back(ctrl); 1142 ctrls.push_back(ctrl);
1066 if (!SetExtCtrls(ctrls)) { 1143 if (!SetExtCtrls(ctrls)) {
1067 LOG(ERROR) << "Failed enabling bitrate control"; 1144 LOG(ERROR) << "Failed enabling bitrate control";
1068 NOTIFY_ERROR(kPlatformFailureError); 1145 NOTIFY_ERROR(kPlatformFailureError);
1069 return false; 1146 return false;
1070 } 1147 }
1071 1148
1072 // Optional controls.
1073 ctrls.clear(); 1149 ctrls.clear();
1074 if (output_format_fourcc_ == V4L2_PIX_FMT_H264) { 1150 if (output_format_fourcc_ == V4L2_PIX_FMT_H264) {
1151 #ifndef V4L2_CID_MPEG_VIDEO_H264_SPS_PPS_BEFORE_IDR
1152 #define V4L2_CID_MPEG_VIDEO_H264_SPS_PPS_BEFORE_IDR (V4L2_CID_MPEG_BASE + 388)
1153 #endif
1154 // Request to inject SPS and PPS before each IDR, if the device supports
1155 // that feature. Otherwise we'll have to cache and inject ourselves.
1156 if (IsCtrlExposed(V4L2_CID_MPEG_VIDEO_H264_SPS_PPS_BEFORE_IDR)) {
1157 memset(&ctrl, 0, sizeof(ctrl));
1158 ctrl.id = V4L2_CID_MPEG_VIDEO_H264_SPS_PPS_BEFORE_IDR;
1159 ctrl.value = 1;
1160 ctrls.push_back(ctrl);
1161 if (!SetExtCtrls(ctrls)) {
1162 NOTIFY_ERROR(kPlatformFailureError);
1163 return false;
1164 }
1165 ctrls.clear();
1166 inject_sps_and_pps_ = false;
1167 DVLOG(1) << "Device supports injecting SPS+PPS before each IDR";
1168 } else {
1169 inject_sps_and_pps_ = true;
1170 DVLOG(1) << "Will inject SPS+PPS before each IDR, unsupported by device";
1171 }
1172
1173 // Optional controls.
1075 // No B-frames, for lowest decoding latency. 1174 // No B-frames, for lowest decoding latency.
1076 memset(&ctrl, 0, sizeof(ctrl)); 1175 memset(&ctrl, 0, sizeof(ctrl));
1077 ctrl.id = V4L2_CID_MPEG_VIDEO_B_FRAMES; 1176 ctrl.id = V4L2_CID_MPEG_VIDEO_B_FRAMES;
1078 ctrl.value = 0; 1177 ctrl.value = 0;
1079 ctrls.push_back(ctrl); 1178 ctrls.push_back(ctrl);
1080 1179
1081 // Quantization parameter maximum value (for variable bitrate control). 1180 // Quantization parameter maximum value (for variable bitrate control).
1082 memset(&ctrl, 0, sizeof(ctrl)); 1181 memset(&ctrl, 0, sizeof(ctrl));
1083 ctrl.id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP; 1182 ctrl.id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP;
1084 ctrl.value = 51; 1183 ctrl.value = 51;
1085 ctrls.push_back(ctrl); 1184 ctrls.push_back(ctrl);
1086 1185
1087 // Use H.264 level 4.0 to match the supported max resolution. 1186 // Use H.264 level 4.0 to match the supported max resolution.
1088 memset(&ctrl, 0, sizeof(ctrl)); 1187 memset(&ctrl, 0, sizeof(ctrl));
1089 ctrl.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL; 1188 ctrl.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
1090 ctrl.value = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; 1189 ctrl.value = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
1091 ctrls.push_back(ctrl); 1190 ctrls.push_back(ctrl);
1092 1191
1093 // Separate stream header so we can cache it and insert into the stream. 1192 // Ask not to put SPS and PPS into separate bitstream buffers.
1094 memset(&ctrl, 0, sizeof(ctrl)); 1193 memset(&ctrl, 0, sizeof(ctrl));
1095 ctrl.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE; 1194 ctrl.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
1096 ctrl.value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE; 1195 ctrl.value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME;
1097 ctrls.push_back(ctrl); 1196 ctrls.push_back(ctrl);
1098 } 1197 }
1099 1198
1100 // Enable macroblock-level bitrate control. 1199 // Enable macroblock-level bitrate control.
1101 memset(&ctrl, 0, sizeof(ctrl)); 1200 memset(&ctrl, 0, sizeof(ctrl));
1102 ctrl.id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE; 1201 ctrl.id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE;
1103 ctrl.value = 1; 1202 ctrl.value = 1;
1104 ctrls.push_back(ctrl); 1203 ctrls.push_back(ctrl);
1105 1204
1106 // Disable periodic key frames. 1205 // Disable periodic key frames.
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1171 DCHECK(!output_streamon_); 1270 DCHECK(!output_streamon_);
1172 1271
1173 struct v4l2_requestbuffers reqbufs; 1272 struct v4l2_requestbuffers reqbufs;
1174 memset(&reqbufs, 0, sizeof(reqbufs)); 1273 memset(&reqbufs, 0, sizeof(reqbufs));
1175 reqbufs.count = kOutputBufferCount; 1274 reqbufs.count = kOutputBufferCount;
1176 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 1275 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1177 reqbufs.memory = V4L2_MEMORY_MMAP; 1276 reqbufs.memory = V4L2_MEMORY_MMAP;
1178 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs); 1277 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
1179 1278
1180 DCHECK(output_buffer_map_.empty()); 1279 DCHECK(output_buffer_map_.empty());
1181 output_buffer_map_.resize(reqbufs.count); 1280 output_buffer_map_ = std::vector<OutputRecord>(reqbufs.count);
1182 for (size_t i = 0; i < output_buffer_map_.size(); ++i) { 1281 for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
1183 struct v4l2_plane planes[1]; 1282 struct v4l2_plane planes[1];
1184 struct v4l2_buffer buffer; 1283 struct v4l2_buffer buffer;
1185 memset(&buffer, 0, sizeof(buffer)); 1284 memset(&buffer, 0, sizeof(buffer));
1186 memset(planes, 0, sizeof(planes)); 1285 memset(planes, 0, sizeof(planes));
1187 buffer.index = i; 1286 buffer.index = i;
1188 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 1287 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1189 buffer.memory = V4L2_MEMORY_MMAP; 1288 buffer.memory = V4L2_MEMORY_MMAP;
1190 buffer.m.planes = planes; 1289 buffer.m.planes = planes;
1191 buffer.length = arraysize(planes); 1290 buffer.length = arraysize(planes);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1239 reqbufs.count = 0; 1338 reqbufs.count = 0;
1240 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 1339 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1241 reqbufs.memory = V4L2_MEMORY_MMAP; 1340 reqbufs.memory = V4L2_MEMORY_MMAP;
1242 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); 1341 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs);
1243 1342
1244 output_buffer_map_.clear(); 1343 output_buffer_map_.clear();
1245 free_output_buffers_.clear(); 1344 free_output_buffers_.clear();
1246 } 1345 }
1247 1346
1248 } // namespace media 1347 } // namespace media
OLDNEW
« no previous file with comments | « media/gpu/v4l2_video_encode_accelerator.h ('k') | media/gpu/video_encode_accelerator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698