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 <sys/eventfd.h> | 8 #include <sys/eventfd.h> |
9 #include <sys/ioctl.h> | 9 #include <sys/ioctl.h> |
10 #include <sys/mman.h> | 10 #include <sys/mman.h> |
11 | 11 |
12 #include "base/callback.h" | 12 #include "base/callback.h" |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/debug/trace_event.h" | 14 #include "base/debug/trace_event.h" |
15 #include "base/message_loop/message_loop_proxy.h" | 15 #include "base/message_loop/message_loop_proxy.h" |
16 #include "base/numerics/safe_conversions.h" | 16 #include "base/numerics/safe_conversions.h" |
17 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h" | 17 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h" |
18 #include "content/public/common/content_switches.h" | 18 #include "content/public/common/content_switches.h" |
19 #include "media/base/bitstream_buffer.h" | 19 #include "media/base/bitstream_buffer.h" |
20 | 20 |
21 #define NOTIFY_ERROR(x) \ | 21 #define NOTIFY_ERROR(x) \ |
22 do { \ | 22 do { \ |
23 SetEncoderState(kError); \ | 23 LOG(ERROR) << "Setting error state:" << x; \ |
24 LOG(ERROR) << "calling NotifyError(): " << x; \ | 24 SetErrorState(x); \ |
25 NotifyError(x); \ | |
26 } while (0) | 25 } while (0) |
27 | 26 |
28 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value) \ | 27 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value) \ |
29 do { \ | 28 do { \ |
30 if (device_->Ioctl(type, arg) != 0) { \ | 29 if (device_->Ioctl(type, arg) != 0) { \ |
31 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ | 30 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ |
32 NOTIFY_ERROR(kPlatformFailureError); \ | 31 NOTIFY_ERROR(kPlatformFailureError); \ |
33 return value; \ | 32 return value; \ |
34 } \ | 33 } \ |
35 } while (0) | 34 } while (0) |
(...skipping 27 matching lines...) Expand all Loading... |
63 } | 62 } |
64 | 63 |
65 V4L2VideoEncodeAccelerator::OutputRecord::OutputRecord() | 64 V4L2VideoEncodeAccelerator::OutputRecord::OutputRecord() |
66 : at_device(false), address(NULL), length(0) { | 65 : at_device(false), address(NULL), length(0) { |
67 } | 66 } |
68 | 67 |
69 V4L2VideoEncodeAccelerator::OutputRecord::~OutputRecord() { | 68 V4L2VideoEncodeAccelerator::OutputRecord::~OutputRecord() { |
70 } | 69 } |
71 | 70 |
72 V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator( | 71 V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator( |
73 scoped_ptr<V4L2Device> device) | 72 scoped_refptr<V4L2Device> device) |
74 : child_message_loop_proxy_(base::MessageLoopProxy::current()), | 73 : child_message_loop_proxy_(base::MessageLoopProxy::current()), |
75 output_buffer_byte_size_(0), | 74 output_buffer_byte_size_(0), |
76 device_input_format_(media::VideoFrame::UNKNOWN), | 75 device_input_format_(media::VideoFrame::UNKNOWN), |
77 input_planes_count_(0), | 76 input_planes_count_(0), |
78 output_format_fourcc_(0), | 77 output_format_fourcc_(0), |
79 encoder_state_(kUninitialized), | 78 encoder_state_(kUninitialized), |
80 stream_header_size_(0), | 79 stream_header_size_(0), |
81 device_(device.Pass()), | 80 device_(device), |
82 input_streamon_(false), | 81 input_streamon_(false), |
83 input_buffer_queued_count_(0), | 82 input_buffer_queued_count_(0), |
84 input_memory_type_(V4L2_MEMORY_USERPTR), | 83 input_memory_type_(V4L2_MEMORY_USERPTR), |
85 output_streamon_(false), | 84 output_streamon_(false), |
86 output_buffer_queued_count_(0), | 85 output_buffer_queued_count_(0), |
87 encoder_thread_("V4L2EncoderThread"), | 86 encoder_thread_("V4L2EncoderThread"), |
88 device_poll_thread_("V4L2EncoderDevicePollThread"), | 87 device_poll_thread_("V4L2EncoderDevicePollThread"), |
89 weak_this_ptr_factory_(this) { | 88 weak_this_ptr_factory_(this) { |
90 weak_this_ = weak_this_ptr_factory_.GetWeakPtr(); | 89 weak_this_ = weak_this_ptr_factory_.GetWeakPtr(); |
91 } | 90 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 | 131 |
133 if (!SetFormats(input_format, output_profile)) { | 132 if (!SetFormats(input_format, output_profile)) { |
134 LOG(ERROR) << "Failed setting up formats"; | 133 LOG(ERROR) << "Failed setting up formats"; |
135 return false; | 134 return false; |
136 } | 135 } |
137 | 136 |
138 if (input_format != device_input_format_) { | 137 if (input_format != device_input_format_) { |
139 DVLOG(1) << "Input format not supported by the HW, will convert to " | 138 DVLOG(1) << "Input format not supported by the HW, will convert to " |
140 << media::VideoFrame::FormatToString(device_input_format_); | 139 << media::VideoFrame::FormatToString(device_input_format_); |
141 | 140 |
142 scoped_ptr<V4L2Device> device = | 141 scoped_refptr<V4L2Device> device = |
143 V4L2Device::Create(V4L2Device::kImageProcessor); | 142 V4L2Device::Create(V4L2Device::kImageProcessor); |
144 image_processor_.reset(new V4L2ImageProcessor(device.Pass())); | 143 image_processor_.reset(new V4L2ImageProcessor(device)); |
145 | 144 |
146 // Convert from input_format to device_input_format_, keeping the size | 145 // Convert from input_format to device_input_format_, keeping the size |
147 // at visible_size_ and requiring the output buffers to be of at least | 146 // at visible_size_ and requiring the output buffers to be of at least |
148 // input_allocated_size_. | 147 // input_allocated_size_. |
149 if (!image_processor_->Initialize( | 148 if (!image_processor_->Initialize( |
150 input_format, | 149 input_format, |
151 device_input_format_, | 150 device_input_format_, |
152 visible_size_, | 151 visible_size_, |
153 visible_size_, | 152 visible_size_, |
154 input_allocated_size_, | 153 input_allocated_size_, |
(...skipping 10 matching lines...) Expand all Loading... |
165 if (!CreateOutputBuffers()) | 164 if (!CreateOutputBuffers()) |
166 return false; | 165 return false; |
167 | 166 |
168 if (!encoder_thread_.Start()) { | 167 if (!encoder_thread_.Start()) { |
169 LOG(ERROR) << "Initialize(): encoder thread failed to start"; | 168 LOG(ERROR) << "Initialize(): encoder thread failed to start"; |
170 return false; | 169 return false; |
171 } | 170 } |
172 | 171 |
173 RequestEncodingParametersChange(initial_bitrate, kInitialFramerate); | 172 RequestEncodingParametersChange(initial_bitrate, kInitialFramerate); |
174 | 173 |
175 SetEncoderState(kInitialized); | 174 encoder_state_ = kInitialized; |
176 | 175 |
177 child_message_loop_proxy_->PostTask( | 176 child_message_loop_proxy_->PostTask( |
178 FROM_HERE, | 177 FROM_HERE, |
179 base::Bind(&Client::RequireBitstreamBuffers, | 178 base::Bind(&Client::RequireBitstreamBuffers, |
180 client_, | 179 client_, |
181 kInputBufferCount, | 180 kInputBufferCount, |
182 image_processor_.get() ? | 181 image_processor_.get() ? |
183 image_processor_->input_allocated_size() : | 182 image_processor_->input_allocated_size() : |
184 input_allocated_size_, | 183 input_allocated_size_, |
185 output_buffer_byte_size_)); | 184 output_buffer_byte_size_)); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 base::Unretained(this))); | 273 base::Unretained(this))); |
275 // DestroyTask() will put the encoder into kError state and cause all tasks | 274 // DestroyTask() will put the encoder into kError state and cause all tasks |
276 // to no-op. | 275 // to no-op. |
277 encoder_thread_.Stop(); | 276 encoder_thread_.Stop(); |
278 } else { | 277 } else { |
279 // Otherwise, call the destroy task directly. | 278 // Otherwise, call the destroy task directly. |
280 DestroyTask(); | 279 DestroyTask(); |
281 } | 280 } |
282 | 281 |
283 // Set to kError state just in case. | 282 // Set to kError state just in case. |
284 SetEncoderState(kError); | 283 encoder_state_ = kError; |
285 | 284 |
286 delete this; | 285 delete this; |
287 } | 286 } |
288 | 287 |
289 std::vector<media::VideoEncodeAccelerator::SupportedProfile> | 288 std::vector<media::VideoEncodeAccelerator::SupportedProfile> |
290 V4L2VideoEncodeAccelerator::GetSupportedProfiles() { | 289 V4L2VideoEncodeAccelerator::GetSupportedProfiles() { |
291 std::vector<SupportedProfile> profiles; | 290 std::vector<SupportedProfile> profiles; |
292 SupportedProfile profile; | 291 SupportedProfile profile; |
293 profile.max_resolution.SetSize(1920, 1088); | 292 profile.max_resolution.SetSize(1920, 1088); |
294 profile.max_framerate_numerator = 30; | 293 profile.max_framerate_numerator = 30; |
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
776 &V4L2VideoEncodeAccelerator::NotifyError, weak_this_, error)); | 775 &V4L2VideoEncodeAccelerator::NotifyError, weak_this_, error)); |
777 return; | 776 return; |
778 } | 777 } |
779 | 778 |
780 if (client_) { | 779 if (client_) { |
781 client_->NotifyError(error); | 780 client_->NotifyError(error); |
782 client_ptr_factory_.reset(); | 781 client_ptr_factory_.reset(); |
783 } | 782 } |
784 } | 783 } |
785 | 784 |
786 void V4L2VideoEncodeAccelerator::SetEncoderState(State state) { | 785 void V4L2VideoEncodeAccelerator::SetErrorState(Error error) { |
787 DVLOG(3) << "SetEncoderState(): state=" << state; | |
788 | |
789 // We can touch encoder_state_ only if this is the encoder thread or the | 786 // We can touch encoder_state_ only if this is the encoder thread or the |
790 // encoder thread isn't running. | 787 // encoder thread isn't running. |
791 if (encoder_thread_.message_loop() != NULL && | 788 if (encoder_thread_.message_loop() != NULL && |
792 encoder_thread_.message_loop() != base::MessageLoop::current()) { | 789 encoder_thread_.message_loop() != base::MessageLoop::current()) { |
793 encoder_thread_.message_loop()->PostTask( | 790 encoder_thread_.message_loop()->PostTask( |
794 FROM_HERE, | 791 FROM_HERE, base::Bind(&V4L2VideoEncodeAccelerator::SetErrorState, |
795 base::Bind(&V4L2VideoEncodeAccelerator::SetEncoderState, | 792 base::Unretained(this), error)); |
796 base::Unretained(this), | 793 return; |
797 state)); | |
798 } else { | |
799 encoder_state_ = state; | |
800 } | 794 } |
| 795 |
| 796 // Post NotifyError only if we are already initialized, as the API does |
| 797 // not allow doing so before that. |
| 798 if (encoder_state_ != kError && encoder_state_ != kUninitialized) |
| 799 NotifyError(error); |
| 800 |
| 801 encoder_state_ = kError; |
801 } | 802 } |
802 | 803 |
803 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask( | 804 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask( |
804 uint32 bitrate, | 805 uint32 bitrate, |
805 uint32 framerate) { | 806 uint32 framerate) { |
806 DVLOG(3) << "RequestEncodingParametersChangeTask(): bitrate=" << bitrate | 807 DVLOG(3) << "RequestEncodingParametersChangeTask(): bitrate=" << bitrate |
807 << ", framerate=" << framerate; | 808 << ", framerate=" << framerate; |
808 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); | 809 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current()); |
809 | 810 |
810 if (bitrate < 1) | 811 if (bitrate < 1) |
(...skipping 23 matching lines...) Expand all Loading... |
834 IOCTL_OR_ERROR_RETURN(VIDIOC_S_PARM, &parms); | 835 IOCTL_OR_ERROR_RETURN(VIDIOC_S_PARM, &parms); |
835 } | 836 } |
836 | 837 |
837 bool V4L2VideoEncodeAccelerator::SetOutputFormat( | 838 bool V4L2VideoEncodeAccelerator::SetOutputFormat( |
838 media::VideoCodecProfile output_profile) { | 839 media::VideoCodecProfile output_profile) { |
839 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 840 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
840 DCHECK(!input_streamon_); | 841 DCHECK(!input_streamon_); |
841 DCHECK(!output_streamon_); | 842 DCHECK(!output_streamon_); |
842 | 843 |
843 output_format_fourcc_ = | 844 output_format_fourcc_ = |
844 V4L2Device::VideoCodecProfileToV4L2PixFmt(output_profile); | 845 V4L2Device::VideoCodecProfileToV4L2PixFmt(output_profile, false); |
845 if (!output_format_fourcc_) { | 846 if (!output_format_fourcc_) { |
846 LOG(ERROR) << "Initialize(): invalid output_profile=" << output_profile; | 847 LOG(ERROR) << "Initialize(): invalid output_profile=" << output_profile; |
847 return false; | 848 return false; |
848 } | 849 } |
849 | 850 |
850 output_buffer_byte_size_ = kOutputBufferSize; | 851 output_buffer_byte_size_ = kOutputBufferSize; |
851 | 852 |
852 struct v4l2_format format; | 853 struct v4l2_format format; |
853 memset(&format, 0, sizeof(format)); | 854 memset(&format, 0, sizeof(format)); |
854 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 855 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1144 reqbufs.count = 0; | 1145 reqbufs.count = 0; |
1145 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | 1146 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
1146 reqbufs.memory = V4L2_MEMORY_MMAP; | 1147 reqbufs.memory = V4L2_MEMORY_MMAP; |
1147 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); | 1148 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs); |
1148 | 1149 |
1149 output_buffer_map_.clear(); | 1150 output_buffer_map_.clear(); |
1150 free_output_buffers_.clear(); | 1151 free_output_buffers_.clear(); |
1151 } | 1152 } |
1152 | 1153 |
1153 } // namespace content | 1154 } // namespace content |
OLD | NEW |