Revert of Support multiple video decoders and encoders (patchset #14 id:260001 of...
[chromium-blink-merge.git] / content / common / gpu / media / v4l2_video_encode_accelerator.cc
blobf18d7576ed610a5a0b93437f7cdcc5ca9b54dd22
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
3 // found in the LICENSE file.
5 #include <fcntl.h>
6 #include <linux/videodev2.h>
7 #include <poll.h>
8 #include <sys/eventfd.h>
9 #include <sys/ioctl.h>
10 #include <sys/mman.h>
12 #include "base/callback.h"
13 #include "base/command_line.h"
14 #include "base/debug/trace_event.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/numerics/safe_conversions.h"
17 #include "content/common/gpu/media/v4l2_video_encode_accelerator.h"
18 #include "content/public/common/content_switches.h"
19 #include "media/base/bitstream_buffer.h"
21 #define NOTIFY_ERROR(x) \
22 do { \
23 SetEncoderState(kError); \
24 LOG(ERROR) << "calling NotifyError(): " << x; \
25 NotifyError(x); \
26 } while (0)
28 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value) \
29 do { \
30 if (device_->Ioctl(type, arg) != 0) { \
31 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
32 NOTIFY_ERROR(kPlatformFailureError); \
33 return value; \
34 } \
35 } while (0)
37 #define IOCTL_OR_ERROR_RETURN(type, arg) \
38 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, ((void)0))
40 #define IOCTL_OR_ERROR_RETURN_FALSE(type, arg) \
41 IOCTL_OR_ERROR_RETURN_VALUE(type, arg, false)
43 #define IOCTL_OR_LOG_ERROR(type, arg) \
44 do { \
45 if (device_->Ioctl(type, arg) != 0) \
46 PLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
47 } while (0)
49 namespace content {
51 struct V4L2VideoEncodeAccelerator::BitstreamBufferRef {
52 BitstreamBufferRef(int32 id, scoped_ptr<base::SharedMemory> shm, size_t size)
53 : id(id), shm(shm.Pass()), size(size) {}
54 const int32 id;
55 const scoped_ptr<base::SharedMemory> shm;
56 const size_t size;
59 V4L2VideoEncodeAccelerator::InputRecord::InputRecord() : at_device(false) {
62 V4L2VideoEncodeAccelerator::OutputRecord::OutputRecord()
63 : at_device(false), address(NULL), length(0) {
66 V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator(
67 scoped_ptr<V4L2Device> device)
68 : child_message_loop_proxy_(base::MessageLoopProxy::current()),
69 output_buffer_byte_size_(0),
70 device_input_format_(media::VideoFrame::UNKNOWN),
71 input_planes_count_(0),
72 output_format_fourcc_(0),
73 encoder_state_(kUninitialized),
74 stream_header_size_(0),
75 device_(device.Pass()),
76 input_streamon_(false),
77 input_buffer_queued_count_(0),
78 input_memory_type_(V4L2_MEMORY_USERPTR),
79 output_streamon_(false),
80 output_buffer_queued_count_(0),
81 encoder_thread_("V4L2EncoderThread"),
82 device_poll_thread_("V4L2EncoderDevicePollThread"),
83 weak_this_ptr_factory_(this) {
84 weak_this_ = weak_this_ptr_factory_.GetWeakPtr();
87 V4L2VideoEncodeAccelerator::~V4L2VideoEncodeAccelerator() {
88 DCHECK(!encoder_thread_.IsRunning());
89 DCHECK(!device_poll_thread_.IsRunning());
90 DVLOG(4) << __func__;
92 DestroyInputBuffers();
93 DestroyOutputBuffers();
96 bool V4L2VideoEncodeAccelerator::Initialize(
97 media::VideoFrame::Format input_format,
98 const gfx::Size& input_visible_size,
99 media::VideoCodecProfile output_profile,
100 uint32 initial_bitrate,
101 Client* client) {
102 DVLOG(3) << __func__ << ": input_format="
103 << media::VideoFrame::FormatToString(input_format)
104 << ", input_visible_size=" << input_visible_size.ToString()
105 << ", output_profile=" << output_profile
106 << ", initial_bitrate=" << initial_bitrate;
108 visible_size_ = input_visible_size;
110 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
111 client_ = client_ptr_factory_->GetWeakPtr();
113 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
114 DCHECK_EQ(encoder_state_, kUninitialized);
116 struct v4l2_capability caps;
117 memset(&caps, 0, sizeof(caps));
118 const __u32 kCapsRequired = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
119 V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING;
120 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYCAP, &caps);
121 if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
122 LOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
123 "caps check failed: 0x" << std::hex << caps.capabilities;
124 return false;
127 if (!SetFormats(input_format, output_profile)) {
128 LOG(ERROR) << "Failed setting up formats";
129 return false;
132 if (input_format != device_input_format_) {
133 DVLOG(1) << "Input format not supported by the HW, will convert to "
134 << media::VideoFrame::FormatToString(device_input_format_);
136 scoped_ptr<V4L2Device> device =
137 V4L2Device::Create(V4L2Device::kImageProcessor);
138 image_processor_.reset(new V4L2ImageProcessor(device.Pass()));
140 // Convert from input_format to device_input_format_, keeping the size
141 // at visible_size_ and requiring the output buffers to be of at least
142 // input_allocated_size_.
143 if (!image_processor_->Initialize(
144 input_format,
145 device_input_format_,
146 visible_size_,
147 visible_size_,
148 input_allocated_size_,
149 base::Bind(&V4L2VideoEncodeAccelerator::ImageProcessorError,
150 weak_this_))) {
151 LOG(ERROR) << "Failed initializing image processor";
152 return false;
156 if (!InitControls())
157 return false;
159 if (!CreateOutputBuffers())
160 return false;
162 if (!encoder_thread_.Start()) {
163 LOG(ERROR) << "Initialize(): encoder thread failed to start";
164 return false;
167 RequestEncodingParametersChange(initial_bitrate, kInitialFramerate);
169 SetEncoderState(kInitialized);
171 child_message_loop_proxy_->PostTask(
172 FROM_HERE,
173 base::Bind(&Client::RequireBitstreamBuffers,
174 client_,
175 kInputBufferCount,
176 image_processor_.get() ?
177 image_processor_->input_allocated_size() :
178 input_allocated_size_,
179 output_buffer_byte_size_));
180 return true;
183 void V4L2VideoEncodeAccelerator::ImageProcessorError() {
184 LOG(ERROR) << "Image processor error";
185 NOTIFY_ERROR(kPlatformFailureError);
188 void V4L2VideoEncodeAccelerator::Encode(
189 const scoped_refptr<media::VideoFrame>& frame,
190 bool force_keyframe) {
191 DVLOG(3) << "Encode(): force_keyframe=" << force_keyframe;
192 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
194 if (image_processor_) {
195 image_processor_->Process(
196 frame,
197 base::Bind(&V4L2VideoEncodeAccelerator::FrameProcessed,
198 weak_this_,
199 force_keyframe));
200 } else {
201 encoder_thread_.message_loop()->PostTask(
202 FROM_HERE,
203 base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask,
204 base::Unretained(this),
205 frame,
206 force_keyframe));
210 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBuffer(
211 const media::BitstreamBuffer& buffer) {
212 DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer.id();
213 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
215 if (buffer.size() < output_buffer_byte_size_) {
216 NOTIFY_ERROR(kInvalidArgumentError);
217 return;
220 scoped_ptr<base::SharedMemory> shm(
221 new base::SharedMemory(buffer.handle(), false));
222 if (!shm->Map(buffer.size())) {
223 NOTIFY_ERROR(kPlatformFailureError);
224 return;
227 scoped_ptr<BitstreamBufferRef> buffer_ref(
228 new BitstreamBufferRef(buffer.id(), shm.Pass(), buffer.size()));
229 encoder_thread_.message_loop()->PostTask(
230 FROM_HERE,
231 base::Bind(&V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask,
232 base::Unretained(this),
233 base::Passed(&buffer_ref)));
236 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChange(
237 uint32 bitrate,
238 uint32 framerate) {
239 DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate
240 << ", framerate=" << framerate;
241 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
243 encoder_thread_.message_loop()->PostTask(
244 FROM_HERE,
245 base::Bind(
246 &V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask,
247 base::Unretained(this),
248 bitrate,
249 framerate));
252 void V4L2VideoEncodeAccelerator::Destroy() {
253 DVLOG(3) << "Destroy()";
254 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
256 // We're destroying; cancel all callbacks.
257 client_ptr_factory_.reset();
258 weak_this_ptr_factory_.InvalidateWeakPtrs();
260 if (image_processor_.get())
261 image_processor_.release()->Destroy();
263 // If the encoder thread is running, destroy using posted task.
264 if (encoder_thread_.IsRunning()) {
265 encoder_thread_.message_loop()->PostTask(
266 FROM_HERE,
267 base::Bind(&V4L2VideoEncodeAccelerator::DestroyTask,
268 base::Unretained(this)));
269 // DestroyTask() will put the encoder into kError state and cause all tasks
270 // to no-op.
271 encoder_thread_.Stop();
272 } else {
273 // Otherwise, call the destroy task directly.
274 DestroyTask();
277 // Set to kError state just in case.
278 SetEncoderState(kError);
280 delete this;
283 std::vector<media::VideoEncodeAccelerator::SupportedProfile>
284 V4L2VideoEncodeAccelerator::GetSupportedProfiles() {
285 std::vector<SupportedProfile> profiles;
286 SupportedProfile profile;
287 profile.max_resolution.SetSize(1920, 1088);
288 profile.max_framerate_numerator = 30;
289 profile.max_framerate_denominator = 1;
291 v4l2_fmtdesc fmtdesc;
292 memset(&fmtdesc, 0, sizeof(fmtdesc));
293 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
294 for (; device_->Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) {
295 switch (fmtdesc.pixelformat) {
296 case V4L2_PIX_FMT_H264:
297 profile.profile = media::H264PROFILE_MAIN;
298 profiles.push_back(profile);
299 break;
300 case V4L2_PIX_FMT_VP8:
301 profile.profile = media::VP8PROFILE_ANY;
302 profiles.push_back(profile);
303 break;
307 return profiles;
310 void V4L2VideoEncodeAccelerator::FrameProcessed(
311 bool force_keyframe,
312 const scoped_refptr<media::VideoFrame>& frame) {
313 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
314 DVLOG(3) << "FrameProcessed(): force_keyframe=" << force_keyframe;
316 encoder_thread_.message_loop()->PostTask(
317 FROM_HERE,
318 base::Bind(&V4L2VideoEncodeAccelerator::EncodeTask,
319 base::Unretained(this),
320 frame,
321 force_keyframe));
324 void V4L2VideoEncodeAccelerator::EncodeTask(
325 const scoped_refptr<media::VideoFrame>& frame,
326 bool force_keyframe) {
327 DVLOG(3) << "EncodeTask(): force_keyframe=" << force_keyframe;
328 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
329 DCHECK_NE(encoder_state_, kUninitialized);
331 if (encoder_state_ == kError) {
332 DVLOG(2) << "EncodeTask(): early out: kError state";
333 return;
336 encoder_input_queue_.push_back(frame);
337 Enqueue();
339 if (force_keyframe) {
340 // TODO(posciak): this presently makes for slightly imprecise encoding
341 // parameters updates. To precisely align the parameter updates with the
342 // incoming input frame, we should queue the parameters together with the
343 // frame onto encoder_input_queue_ and apply them when the input is about
344 // to be queued to the codec.
345 struct v4l2_ext_control ctrls[1];
346 struct v4l2_ext_controls control;
347 memset(&ctrls, 0, sizeof(ctrls));
348 memset(&control, 0, sizeof(control));
349 ctrls[0].id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE;
350 ctrls[0].value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME;
351 control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
352 control.count = 1;
353 control.controls = ctrls;
354 IOCTL_OR_ERROR_RETURN(VIDIOC_S_EXT_CTRLS, &control);
358 void V4L2VideoEncodeAccelerator::UseOutputBitstreamBufferTask(
359 scoped_ptr<BitstreamBufferRef> buffer_ref) {
360 DVLOG(3) << "UseOutputBitstreamBufferTask(): id=" << buffer_ref->id;
361 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
363 encoder_output_queue_.push_back(
364 linked_ptr<BitstreamBufferRef>(buffer_ref.release()));
365 Enqueue();
367 if (encoder_state_ == kInitialized) {
368 // Finish setting up our OUTPUT queue. See: Initialize().
369 // VIDIOC_REQBUFS on OUTPUT queue.
370 if (!CreateInputBuffers())
371 return;
372 if (!StartDevicePoll())
373 return;
374 encoder_state_ = kEncoding;
378 void V4L2VideoEncodeAccelerator::DestroyTask() {
379 DVLOG(3) << "DestroyTask()";
381 // DestroyTask() should run regardless of encoder_state_.
383 // Stop streaming and the device_poll_thread_.
384 StopDevicePoll();
386 // Set our state to kError, and early-out all tasks.
387 encoder_state_ = kError;
390 void V4L2VideoEncodeAccelerator::ServiceDeviceTask() {
391 DVLOG(3) << "ServiceDeviceTask()";
392 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
393 DCHECK_NE(encoder_state_, kUninitialized);
394 DCHECK_NE(encoder_state_, kInitialized);
396 if (encoder_state_ == kError) {
397 DVLOG(2) << "ServiceDeviceTask(): early out: kError state";
398 return;
401 Dequeue();
402 Enqueue();
404 // Clear the interrupt fd.
405 if (!device_->ClearDevicePollInterrupt())
406 return;
408 // Device can be polled as soon as either input or output buffers are queued.
409 bool poll_device =
410 (input_buffer_queued_count_ + output_buffer_queued_count_ > 0);
412 // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(),
413 // so either:
414 // * device_poll_thread_ is running normally
415 // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down,
416 // in which case we're in kError state, and we should have early-outed
417 // already.
418 DCHECK(device_poll_thread_.message_loop());
419 // Queue the DevicePollTask() now.
420 device_poll_thread_.message_loop()->PostTask(
421 FROM_HERE,
422 base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask,
423 base::Unretained(this),
424 poll_device));
426 DVLOG(2) << __func__ << ": buffer counts: ENC["
427 << encoder_input_queue_.size() << "] => DEVICE["
428 << free_input_buffers_.size() << "+"
429 << input_buffer_queued_count_ << "/"
430 << input_buffer_map_.size() << "->"
431 << free_output_buffers_.size() << "+"
432 << output_buffer_queued_count_ << "/"
433 << output_buffer_map_.size() << "] => OUT["
434 << encoder_output_queue_.size() << "]";
437 void V4L2VideoEncodeAccelerator::Enqueue() {
438 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
440 DVLOG(3) << "Enqueue() "
441 << "free_input_buffers: " << free_input_buffers_.size()
442 << "input_queue: " << encoder_input_queue_.size();
444 // Enqueue all the inputs we can.
445 const int old_inputs_queued = input_buffer_queued_count_;
446 // while (!ready_input_buffers_.empty()) {
447 while (!encoder_input_queue_.empty() && !free_input_buffers_.empty()) {
448 if (!EnqueueInputRecord())
449 return;
451 if (old_inputs_queued == 0 && input_buffer_queued_count_ != 0) {
452 // We just started up a previously empty queue.
453 // Queue state changed; signal interrupt.
454 if (!device_->SetDevicePollInterrupt())
455 return;
456 // Start VIDIOC_STREAMON if we haven't yet.
457 if (!input_streamon_) {
458 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
459 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type);
460 input_streamon_ = true;
464 // Enqueue all the outputs we can.
465 const int old_outputs_queued = output_buffer_queued_count_;
466 while (!free_output_buffers_.empty() && !encoder_output_queue_.empty()) {
467 if (!EnqueueOutputRecord())
468 return;
470 if (old_outputs_queued == 0 && output_buffer_queued_count_ != 0) {
471 // We just started up a previously empty queue.
472 // Queue state changed; signal interrupt.
473 if (!device_->SetDevicePollInterrupt())
474 return;
475 // Start VIDIOC_STREAMON if we haven't yet.
476 if (!output_streamon_) {
477 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
478 IOCTL_OR_ERROR_RETURN(VIDIOC_STREAMON, &type);
479 output_streamon_ = true;
484 void V4L2VideoEncodeAccelerator::Dequeue() {
485 DVLOG(3) << "Dequeue()";
486 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
488 // Dequeue completed input (VIDEO_OUTPUT) buffers, and recycle to the free
489 // list.
490 struct v4l2_buffer dqbuf;
491 struct v4l2_plane planes[VIDEO_MAX_PLANES];
492 while (input_buffer_queued_count_ > 0) {
493 DVLOG(4) << "inputs queued: " << input_buffer_queued_count_;
494 DCHECK(input_streamon_);
495 memset(&dqbuf, 0, sizeof(dqbuf));
496 memset(&planes, 0, sizeof(planes));
497 dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
498 dqbuf.memory = V4L2_MEMORY_MMAP;
499 dqbuf.m.planes = planes;
500 dqbuf.length = input_planes_count_;
501 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
502 if (errno == EAGAIN) {
503 // EAGAIN if we're just out of buffers to dequeue.
504 break;
506 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF";
507 NOTIFY_ERROR(kPlatformFailureError);
508 return;
510 InputRecord& input_record = input_buffer_map_[dqbuf.index];
511 DCHECK(input_record.at_device);
512 input_record.at_device = false;
514 input_record.frame = NULL;
515 free_input_buffers_.push_back(dqbuf.index);
516 input_buffer_queued_count_--;
519 // Dequeue completed output (VIDEO_CAPTURE) buffers, and recycle to the
520 // free list. Notify the client that an output buffer is complete.
521 while (output_buffer_queued_count_ > 0) {
522 DCHECK(output_streamon_);
523 memset(&dqbuf, 0, sizeof(dqbuf));
524 memset(planes, 0, sizeof(planes));
525 dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
526 dqbuf.memory = V4L2_MEMORY_MMAP;
527 dqbuf.m.planes = planes;
528 dqbuf.length = 1;
529 if (device_->Ioctl(VIDIOC_DQBUF, &dqbuf) != 0) {
530 if (errno == EAGAIN) {
531 // EAGAIN if we're just out of buffers to dequeue.
532 break;
534 PLOG(ERROR) << "Dequeue(): ioctl() failed: VIDIOC_DQBUF";
535 NOTIFY_ERROR(kPlatformFailureError);
536 return;
538 const bool key_frame = ((dqbuf.flags & V4L2_BUF_FLAG_KEYFRAME) != 0);
539 OutputRecord& output_record = output_buffer_map_[dqbuf.index];
540 DCHECK(output_record.at_device);
541 DCHECK(output_record.buffer_ref.get());
543 void* output_data = output_record.address;
544 size_t output_size = dqbuf.m.planes[0].bytesused;
545 // This shouldn't happen, but just in case. We should be able to recover
546 // after next keyframe after showing some corruption.
547 DCHECK_LE(output_size, output_buffer_byte_size_);
548 if (output_size > output_buffer_byte_size_)
549 output_size = output_buffer_byte_size_;
550 uint8* target_data =
551 reinterpret_cast<uint8*>(output_record.buffer_ref->shm->memory());
552 if (output_format_fourcc_ == V4L2_PIX_FMT_H264) {
553 if (stream_header_size_ == 0) {
554 // Assume that the first buffer dequeued is the stream header.
555 stream_header_size_ = output_size;
556 stream_header_.reset(new uint8[stream_header_size_]);
557 memcpy(stream_header_.get(), output_data, stream_header_size_);
559 if (key_frame &&
560 output_buffer_byte_size_ - stream_header_size_ >= output_size) {
561 // Insert stream header before every keyframe.
562 memcpy(target_data, stream_header_.get(), stream_header_size_);
563 memcpy(target_data + stream_header_size_, output_data, output_size);
564 output_size += stream_header_size_;
565 } else {
566 memcpy(target_data, output_data, output_size);
568 } else {
569 memcpy(target_data, output_data, output_size);
572 DVLOG(3) << "Dequeue(): returning "
573 "bitstream_buffer_id=" << output_record.buffer_ref->id
574 << ", size=" << output_size << ", key_frame=" << key_frame;
575 child_message_loop_proxy_->PostTask(
576 FROM_HERE,
577 base::Bind(&Client::BitstreamBufferReady,
578 client_,
579 output_record.buffer_ref->id,
580 output_size,
581 key_frame));
582 output_record.at_device = false;
583 output_record.buffer_ref.reset();
584 free_output_buffers_.push_back(dqbuf.index);
585 output_buffer_queued_count_--;
589 bool V4L2VideoEncodeAccelerator::EnqueueInputRecord() {
590 DVLOG(3) << "EnqueueInputRecord()";
591 DCHECK(!free_input_buffers_.empty());
592 DCHECK(!encoder_input_queue_.empty());
594 // Enqueue an input (VIDEO_OUTPUT) buffer.
595 scoped_refptr<media::VideoFrame> frame = encoder_input_queue_.front();
596 const int index = free_input_buffers_.back();
597 InputRecord& input_record = input_buffer_map_[index];
598 DCHECK(!input_record.at_device);
599 struct v4l2_buffer qbuf;
600 struct v4l2_plane qbuf_planes[VIDEO_MAX_PLANES];
601 memset(&qbuf, 0, sizeof(qbuf));
602 memset(qbuf_planes, 0, sizeof(qbuf_planes));
603 qbuf.index = index;
604 qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
605 qbuf.m.planes = qbuf_planes;
607 DCHECK_EQ(device_input_format_, frame->format());
608 for (size_t i = 0; i < input_planes_count_; ++i) {
609 qbuf.m.planes[i].bytesused =
610 base::checked_cast<__u32>(media::VideoFrame::PlaneAllocationSize(
611 frame->format(), i, input_allocated_size_));
613 switch (input_memory_type_) {
614 case V4L2_MEMORY_USERPTR:
615 qbuf.m.planes[i].length = qbuf.m.planes[i].bytesused;
616 qbuf.m.planes[i].m.userptr =
617 reinterpret_cast<unsigned long>(frame->data(i));
618 DCHECK(qbuf.m.planes[i].m.userptr);
619 break;
621 case V4L2_MEMORY_DMABUF:
622 qbuf.m.planes[i].m.fd = frame->dmabuf_fd(i);
623 DCHECK_NE(qbuf.m.planes[i].m.fd, -1);
624 break;
626 default:
627 NOTREACHED();
628 return false;
632 qbuf.memory = input_memory_type_;
633 qbuf.length = input_planes_count_;
635 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
636 input_record.at_device = true;
637 input_record.frame = frame;
638 encoder_input_queue_.pop_front();
639 free_input_buffers_.pop_back();
640 input_buffer_queued_count_++;
641 return true;
644 bool V4L2VideoEncodeAccelerator::EnqueueOutputRecord() {
645 DVLOG(3) << "EnqueueOutputRecord()";
646 DCHECK(!free_output_buffers_.empty());
647 DCHECK(!encoder_output_queue_.empty());
649 // Enqueue an output (VIDEO_CAPTURE) buffer.
650 linked_ptr<BitstreamBufferRef> output_buffer = encoder_output_queue_.back();
651 const int index = free_output_buffers_.back();
652 OutputRecord& output_record = output_buffer_map_[index];
653 DCHECK(!output_record.at_device);
654 DCHECK(!output_record.buffer_ref.get());
655 struct v4l2_buffer qbuf;
656 struct v4l2_plane qbuf_planes[1];
657 memset(&qbuf, 0, sizeof(qbuf));
658 memset(qbuf_planes, 0, sizeof(qbuf_planes));
659 qbuf.index = index;
660 qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
661 qbuf.memory = V4L2_MEMORY_MMAP;
662 qbuf.m.planes = qbuf_planes;
663 qbuf.length = 1;
664 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
665 output_record.at_device = true;
666 output_record.buffer_ref = output_buffer;
667 encoder_output_queue_.pop_back();
668 free_output_buffers_.pop_back();
669 output_buffer_queued_count_++;
670 return true;
673 bool V4L2VideoEncodeAccelerator::StartDevicePoll() {
674 DVLOG(3) << "StartDevicePoll()";
675 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
676 DCHECK(!device_poll_thread_.IsRunning());
678 // Start up the device poll thread and schedule its first DevicePollTask().
679 if (!device_poll_thread_.Start()) {
680 LOG(ERROR) << "StartDevicePoll(): Device thread failed to start";
681 NOTIFY_ERROR(kPlatformFailureError);
682 return false;
684 // Enqueue a poll task with no devices to poll on -- it will wait only on the
685 // interrupt fd.
686 device_poll_thread_.message_loop()->PostTask(
687 FROM_HERE,
688 base::Bind(&V4L2VideoEncodeAccelerator::DevicePollTask,
689 base::Unretained(this),
690 false));
692 return true;
695 bool V4L2VideoEncodeAccelerator::StopDevicePoll() {
696 DVLOG(3) << "StopDevicePoll()";
698 // Signal the DevicePollTask() to stop, and stop the device poll thread.
699 if (!device_->SetDevicePollInterrupt())
700 return false;
701 device_poll_thread_.Stop();
702 // Clear the interrupt now, to be sure.
703 if (!device_->ClearDevicePollInterrupt())
704 return false;
706 if (input_streamon_) {
707 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
708 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF, &type);
710 input_streamon_ = false;
712 if (output_streamon_) {
713 __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
714 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF, &type);
716 output_streamon_ = false;
718 // Reset all our accounting info.
719 encoder_input_queue_.clear();
720 free_input_buffers_.clear();
721 for (size_t i = 0; i < input_buffer_map_.size(); ++i) {
722 InputRecord& input_record = input_buffer_map_[i];
723 input_record.at_device = false;
724 input_record.frame = NULL;
725 free_input_buffers_.push_back(i);
727 input_buffer_queued_count_ = 0;
729 free_output_buffers_.clear();
730 for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
731 OutputRecord& output_record = output_buffer_map_[i];
732 output_record.at_device = false;
733 output_record.buffer_ref.reset();
734 free_output_buffers_.push_back(i);
736 output_buffer_queued_count_ = 0;
738 encoder_output_queue_.clear();
740 DVLOG(3) << "StopDevicePoll(): device poll stopped";
741 return true;
744 void V4L2VideoEncodeAccelerator::DevicePollTask(bool poll_device) {
745 DVLOG(3) << "DevicePollTask()";
746 DCHECK_EQ(device_poll_thread_.message_loop(), base::MessageLoop::current());
748 bool event_pending;
749 if (!device_->Poll(poll_device, &event_pending)) {
750 NOTIFY_ERROR(kPlatformFailureError);
751 return;
754 // All processing should happen on ServiceDeviceTask(), since we shouldn't
755 // touch encoder state from this thread.
756 encoder_thread_.message_loop()->PostTask(
757 FROM_HERE,
758 base::Bind(&V4L2VideoEncodeAccelerator::ServiceDeviceTask,
759 base::Unretained(this)));
762 void V4L2VideoEncodeAccelerator::NotifyError(Error error) {
763 DVLOG(1) << "NotifyError(): error=" << error;
765 if (!child_message_loop_proxy_->BelongsToCurrentThread()) {
766 child_message_loop_proxy_->PostTask(
767 FROM_HERE,
768 base::Bind(
769 &V4L2VideoEncodeAccelerator::NotifyError, weak_this_, error));
770 return;
773 if (client_) {
774 client_->NotifyError(error);
775 client_ptr_factory_.reset();
779 void V4L2VideoEncodeAccelerator::SetEncoderState(State state) {
780 DVLOG(3) << "SetEncoderState(): state=" << state;
782 // We can touch encoder_state_ only if this is the encoder thread or the
783 // encoder thread isn't running.
784 if (encoder_thread_.message_loop() != NULL &&
785 encoder_thread_.message_loop() != base::MessageLoop::current()) {
786 encoder_thread_.message_loop()->PostTask(
787 FROM_HERE,
788 base::Bind(&V4L2VideoEncodeAccelerator::SetEncoderState,
789 base::Unretained(this),
790 state));
791 } else {
792 encoder_state_ = state;
796 void V4L2VideoEncodeAccelerator::RequestEncodingParametersChangeTask(
797 uint32 bitrate,
798 uint32 framerate) {
799 DVLOG(3) << "RequestEncodingParametersChangeTask(): bitrate=" << bitrate
800 << ", framerate=" << framerate;
801 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
803 if (bitrate < 1)
804 bitrate = 1;
805 if (framerate < 1)
806 framerate = 1;
808 struct v4l2_ext_control ctrls[1];
809 struct v4l2_ext_controls control;
810 memset(&ctrls, 0, sizeof(ctrls));
811 memset(&control, 0, sizeof(control));
812 ctrls[0].id = V4L2_CID_MPEG_VIDEO_BITRATE;
813 ctrls[0].value = bitrate;
814 control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
815 control.count = arraysize(ctrls);
816 control.controls = ctrls;
817 IOCTL_OR_ERROR_RETURN(VIDIOC_S_EXT_CTRLS, &control);
819 struct v4l2_streamparm parms;
820 memset(&parms, 0, sizeof(parms));
821 parms.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
822 // Note that we are provided "frames per second" but V4L2 expects "time per
823 // frame"; hence we provide the reciprocal of the framerate here.
824 parms.parm.output.timeperframe.numerator = 1;
825 parms.parm.output.timeperframe.denominator = framerate;
826 IOCTL_OR_ERROR_RETURN(VIDIOC_S_PARM, &parms);
829 bool V4L2VideoEncodeAccelerator::SetOutputFormat(
830 media::VideoCodecProfile output_profile) {
831 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
832 DCHECK(!input_streamon_);
833 DCHECK(!output_streamon_);
835 output_format_fourcc_ =
836 V4L2Device::VideoCodecProfileToV4L2PixFmt(output_profile);
837 if (!output_format_fourcc_) {
838 LOG(ERROR) << "Initialize(): invalid output_profile=" << output_profile;
839 return false;
842 output_buffer_byte_size_ = kOutputBufferSize;
844 struct v4l2_format format;
845 memset(&format, 0, sizeof(format));
846 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
847 format.fmt.pix_mp.width = visible_size_.width();
848 format.fmt.pix_mp.height = visible_size_.height();
849 format.fmt.pix_mp.pixelformat = output_format_fourcc_;
850 format.fmt.pix_mp.plane_fmt[0].sizeimage =
851 base::checked_cast<__u32>(output_buffer_byte_size_);
852 format.fmt.pix_mp.num_planes = 1;
853 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
855 // Device might have adjusted the required output size.
856 size_t adjusted_output_buffer_size =
857 base::checked_cast<size_t>(format.fmt.pix_mp.plane_fmt[0].sizeimage);
858 DCHECK_GE(adjusted_output_buffer_size, output_buffer_byte_size_);
859 output_buffer_byte_size_ = adjusted_output_buffer_size;
861 return true;
864 bool V4L2VideoEncodeAccelerator::NegotiateInputFormat(
865 media::VideoFrame::Format input_format) {
866 DVLOG(3) << "NegotiateInputFormat()";
867 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
868 DCHECK(!input_streamon_);
869 DCHECK(!output_streamon_);
871 device_input_format_ = media::VideoFrame::UNKNOWN;
872 input_planes_count_ = 0;
874 uint32 input_format_fourcc =
875 V4L2Device::VideoFrameFormatToV4L2PixFmt(input_format);
876 if (!input_format_fourcc) {
877 LOG(ERROR) << "Unsupported input format";
878 return false;
881 size_t input_planes_count = media::VideoFrame::NumPlanes(input_format);
882 DCHECK_LE(input_planes_count, static_cast<size_t>(VIDEO_MAX_PLANES));
884 // First see if we the device can use the provided input_format directly.
885 struct v4l2_format format;
886 memset(&format, 0, sizeof(format));
887 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
888 format.fmt.pix_mp.width = visible_size_.width();
889 format.fmt.pix_mp.height = visible_size_.height();
890 format.fmt.pix_mp.pixelformat = input_format_fourcc;
891 format.fmt.pix_mp.num_planes = input_planes_count;
892 if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0) {
893 // Error or format unsupported by device, try to negotiate a fallback.
894 input_format_fourcc = device_->PreferredInputFormat();
895 input_format =
896 V4L2Device::V4L2PixFmtToVideoFrameFormat(input_format_fourcc);
897 if (input_format == media::VideoFrame::UNKNOWN)
898 return false;
900 input_planes_count = media::VideoFrame::NumPlanes(input_format);
901 DCHECK_LE(input_planes_count, static_cast<size_t>(VIDEO_MAX_PLANES));
903 // Device might have adjusted parameters, reset them along with the format.
904 memset(&format, 0, sizeof(format));
905 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
906 format.fmt.pix_mp.width = visible_size_.width();
907 format.fmt.pix_mp.height = visible_size_.height();
908 format.fmt.pix_mp.pixelformat = input_format_fourcc;
909 format.fmt.pix_mp.num_planes = input_planes_count;
910 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_FMT, &format);
911 DCHECK_EQ(format.fmt.pix_mp.num_planes, input_planes_count);
914 // Take device-adjusted sizes for allocated size.
915 input_allocated_size_ = V4L2Device::CodedSizeFromV4L2Format(format);
916 DCHECK(gfx::Rect(input_allocated_size_).Contains(gfx::Rect(visible_size_)));
918 device_input_format_ = input_format;
919 input_planes_count_ = input_planes_count;
920 return true;
923 bool V4L2VideoEncodeAccelerator::SetFormats(
924 media::VideoFrame::Format input_format,
925 media::VideoCodecProfile output_profile) {
926 DVLOG(3) << "SetFormats()";
927 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
928 DCHECK(!input_streamon_);
929 DCHECK(!output_streamon_);
931 if (!SetOutputFormat(output_profile))
932 return false;
934 if (!NegotiateInputFormat(input_format))
935 return false;
937 struct v4l2_crop crop;
938 memset(&crop, 0, sizeof(crop));
939 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
940 crop.c.left = 0;
941 crop.c.top = 0;
942 crop.c.width = visible_size_.width();
943 crop.c.height = visible_size_.height();
944 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_CROP, &crop);
946 return true;
949 bool V4L2VideoEncodeAccelerator::InitControls() {
950 struct v4l2_ext_control ctrls[9];
951 struct v4l2_ext_controls control;
952 memset(&ctrls, 0, sizeof(ctrls));
953 memset(&control, 0, sizeof(control));
954 // No B-frames, for lowest decoding latency.
955 ctrls[0].id = V4L2_CID_MPEG_VIDEO_B_FRAMES;
956 ctrls[0].value = 0;
957 // Enable frame-level bitrate control.
958 ctrls[1].id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE;
959 ctrls[1].value = 1;
960 // Enable "tight" bitrate mode. For this to work properly, frame- and mb-level
961 // bitrate controls have to be enabled as well.
962 ctrls[2].id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF;
963 ctrls[2].value = 1;
964 // Force bitrate control to average over a GOP (for tight bitrate
965 // tolerance).
966 ctrls[3].id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT;
967 ctrls[3].value = 1;
968 // Quantization parameter maximum value (for variable bitrate control).
969 ctrls[4].id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP;
970 ctrls[4].value = 51;
971 // Separate stream header so we can cache it and insert into the stream.
972 ctrls[5].id = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
973 ctrls[5].value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE;
974 // Enable macroblock-level bitrate control.
975 ctrls[6].id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE;
976 ctrls[6].value = 1;
977 // Use H.264 level 4.0 to match the supported max resolution.
978 ctrls[7].id = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
979 ctrls[7].value = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
980 // Disable periodic key frames.
981 ctrls[8].id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
982 ctrls[8].value = 0;
983 control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
984 control.count = arraysize(ctrls);
985 control.controls = ctrls;
986 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_S_EXT_CTRLS, &control);
988 return true;
991 bool V4L2VideoEncodeAccelerator::CreateInputBuffers() {
992 DVLOG(3) << "CreateInputBuffers()";
993 // This function runs on encoder_thread_ after output buffers have been
994 // provided by the client.
995 DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
996 DCHECK(!input_streamon_);
998 struct v4l2_requestbuffers reqbufs;
999 memset(&reqbufs, 0, sizeof(reqbufs));
1000 // Driver will modify to the appropriate number of buffers.
1001 reqbufs.count = 1;
1002 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1003 // TODO(posciak): Once we start doing zero-copy, we should decide based on
1004 // the current pipeline setup which memory type to use. This should probably
1005 // be decided based on an argument to Initialize().
1006 if (image_processor_.get())
1007 input_memory_type_ = V4L2_MEMORY_DMABUF;
1008 else
1009 input_memory_type_ = V4L2_MEMORY_USERPTR;
1011 reqbufs.memory = input_memory_type_;
1012 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
1014 DCHECK(input_buffer_map_.empty());
1015 input_buffer_map_.resize(reqbufs.count);
1016 for (size_t i = 0; i < input_buffer_map_.size(); ++i)
1017 free_input_buffers_.push_back(i);
1019 return true;
1022 bool V4L2VideoEncodeAccelerator::CreateOutputBuffers() {
1023 DVLOG(3) << "CreateOutputBuffers()";
1024 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
1025 DCHECK(!output_streamon_);
1027 struct v4l2_requestbuffers reqbufs;
1028 memset(&reqbufs, 0, sizeof(reqbufs));
1029 reqbufs.count = kOutputBufferCount;
1030 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1031 reqbufs.memory = V4L2_MEMORY_MMAP;
1032 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_REQBUFS, &reqbufs);
1034 DCHECK(output_buffer_map_.empty());
1035 output_buffer_map_.resize(reqbufs.count);
1036 for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
1037 struct v4l2_plane planes[1];
1038 struct v4l2_buffer buffer;
1039 memset(&buffer, 0, sizeof(buffer));
1040 memset(planes, 0, sizeof(planes));
1041 buffer.index = i;
1042 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1043 buffer.memory = V4L2_MEMORY_MMAP;
1044 buffer.m.planes = planes;
1045 buffer.length = arraysize(planes);
1046 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QUERYBUF, &buffer);
1047 void* address = device_->Mmap(NULL,
1048 buffer.m.planes[0].length,
1049 PROT_READ | PROT_WRITE,
1050 MAP_SHARED,
1051 buffer.m.planes[0].m.mem_offset);
1052 if (address == MAP_FAILED) {
1053 PLOG(ERROR) << "CreateOutputBuffers(): mmap() failed";
1054 return false;
1056 output_buffer_map_[i].address = address;
1057 output_buffer_map_[i].length = buffer.m.planes[0].length;
1058 free_output_buffers_.push_back(i);
1061 return true;
1064 void V4L2VideoEncodeAccelerator::DestroyInputBuffers() {
1065 DVLOG(3) << "DestroyInputBuffers()";
1066 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
1067 DCHECK(!input_streamon_);
1069 struct v4l2_requestbuffers reqbufs;
1070 memset(&reqbufs, 0, sizeof(reqbufs));
1071 reqbufs.count = 0;
1072 reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1073 reqbufs.memory = input_memory_type_;
1074 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs);
1076 input_buffer_map_.clear();
1077 free_input_buffers_.clear();
1080 void V4L2VideoEncodeAccelerator::DestroyOutputBuffers() {
1081 DVLOG(3) << "DestroyOutputBuffers()";
1082 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
1083 DCHECK(!output_streamon_);
1085 for (size_t i = 0; i < output_buffer_map_.size(); ++i) {
1086 if (output_buffer_map_[i].address != NULL)
1087 device_->Munmap(output_buffer_map_[i].address,
1088 output_buffer_map_[i].length);
1091 struct v4l2_requestbuffers reqbufs;
1092 memset(&reqbufs, 0, sizeof(reqbufs));
1093 reqbufs.count = 0;
1094 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1095 reqbufs.memory = V4L2_MEMORY_MMAP;
1096 IOCTL_OR_LOG_ERROR(VIDIOC_REQBUFS, &reqbufs);
1098 output_buffer_map_.clear();
1099 free_output_buffers_.clear();
1102 } // namespace content