Commit f746ba85 authored by David Staessens's avatar David Staessens Committed by Commit Bot

media/gpu/V4L2VEA: Adapt V4L2 encode accelerator to use the V4L2 device poller.

The V4L2 encode accelerator currently has its own routines and thread to manage
polling the V4L2 device. This CL changes the encoder to make use of the V4L2
device poller that was introduced recently.

TEST=./video_encode_accelerator_unittest on hana

BUG=None

Change-Id: I7fb003ab3850c4a72b299a682a9a7f971777aa34
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1994545Reviewed-by: default avatarAlexandre Courbot <acourbot@chromium.org>
Commit-Queue: David Staessens <dstaessens@chromium.org>
Cr-Commit-Position: refs/heads/master@{#732748}
parent 862d9d7b
...@@ -168,8 +168,7 @@ V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator( ...@@ -168,8 +168,7 @@ V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator(
// thread by V4L2DevicePoller. // thread by V4L2DevicePoller.
encoder_task_runner_(base::CreateSingleThreadTaskRunner( encoder_task_runner_(base::CreateSingleThreadTaskRunner(
{base::ThreadPool(), base::WithBaseSyncPrimitives()}, {base::ThreadPool(), base::WithBaseSyncPrimitives()},
base::SingleThreadTaskRunnerThreadMode::DEDICATED)), base::SingleThreadTaskRunnerThreadMode::DEDICATED)) {
device_poll_thread_("V4L2EncoderDevicePollThread") {
DCHECK_CALLED_ON_VALID_SEQUENCE(child_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(child_sequence_checker_);
DETACH_FROM_SEQUENCE(encoder_sequence_checker_); DETACH_FROM_SEQUENCE(encoder_sequence_checker_);
...@@ -178,7 +177,6 @@ V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator( ...@@ -178,7 +177,6 @@ V4L2VideoEncodeAccelerator::V4L2VideoEncodeAccelerator(
V4L2VideoEncodeAccelerator::~V4L2VideoEncodeAccelerator() { V4L2VideoEncodeAccelerator::~V4L2VideoEncodeAccelerator() {
DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_);
DCHECK(!device_poll_thread_.IsRunning());
VLOGF(2); VLOGF(2);
} }
...@@ -816,7 +814,7 @@ void V4L2VideoEncodeAccelerator::DestroyTask() { ...@@ -816,7 +814,7 @@ void V4L2VideoEncodeAccelerator::DestroyTask() {
FROM_HERE, base::BindOnce(std::move(flush_callback_), false)); FROM_HERE, base::BindOnce(std::move(flush_callback_), false));
} }
// Stop streaming and the device_poll_thread_. // Stop streaming and the V4L2 device poller.
StopDevicePoll(); StopDevicePoll();
DestroyInputBuffers(); DestroyInputBuffers();
...@@ -825,7 +823,7 @@ void V4L2VideoEncodeAccelerator::DestroyTask() { ...@@ -825,7 +823,7 @@ void V4L2VideoEncodeAccelerator::DestroyTask() {
delete this; delete this;
} }
void V4L2VideoEncodeAccelerator::ServiceDeviceTask() { void V4L2VideoEncodeAccelerator::ServiceDeviceTask(bool /*event*/) {
DVLOGF(3); DVLOGF(3);
DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_);
DCHECK_NE(encoder_state_, kUninitialized); DCHECK_NE(encoder_state_, kUninitialized);
...@@ -839,29 +837,6 @@ void V4L2VideoEncodeAccelerator::ServiceDeviceTask() { ...@@ -839,29 +837,6 @@ void V4L2VideoEncodeAccelerator::ServiceDeviceTask() {
Dequeue(); Dequeue();
Enqueue(); Enqueue();
// Clear the interrupt fd.
if (!device_->ClearDevicePollInterrupt())
return;
// Device can be polled as soon as either input or output buffers are queued.
bool poll_device = (input_queue_->QueuedBuffersCount() +
output_queue_->QueuedBuffersCount() >
0);
// ServiceDeviceTask() should only ever be scheduled from DevicePollTask(),
// so either:
// * device_poll_thread_ is running normally
// * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down,
// in which case we're in kError state, and we should have early-outed
// already.
DCHECK(device_poll_thread_.task_runner());
// Queue the DevicePollTask() now.
// base::Unretained(this) is safe, because device_poll_thread_ is owned by
// *this and stops before *this destruction.
device_poll_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&V4L2VideoEncodeAccelerator::DevicePollTask,
base::Unretained(this), poll_device));
DVLOGF(3) << encoder_input_queue_.size() << "] => DEVICE[" DVLOGF(3) << encoder_input_queue_.size() << "] => DEVICE["
<< input_queue_->FreeBuffersCount() << "+" << input_queue_->FreeBuffersCount() << "+"
<< input_queue_->QueuedBuffersCount() << "/" << input_queue_->QueuedBuffersCount() << "/"
...@@ -918,10 +893,6 @@ void V4L2VideoEncodeAccelerator::Enqueue() { ...@@ -918,10 +893,6 @@ void V4L2VideoEncodeAccelerator::Enqueue() {
return; return;
} }
if (old_inputs_queued == 0 && input_queue_->QueuedBuffersCount() != 0) { if (old_inputs_queued == 0 && input_queue_->QueuedBuffersCount() != 0) {
// We just started up a previously empty queue.
// Queue state changed; signal interrupt.
if (!device_->SetDevicePollInterrupt())
return;
// Shall call VIDIOC_STREAMON if we haven't yet. // Shall call VIDIOC_STREAMON if we haven't yet.
do_streamon = !input_queue_->IsStreaming(); do_streamon = !input_queue_->IsStreaming();
} }
...@@ -934,17 +905,10 @@ void V4L2VideoEncodeAccelerator::Enqueue() { ...@@ -934,17 +905,10 @@ void V4L2VideoEncodeAccelerator::Enqueue() {
} }
// Enqueue all the outputs we can. // Enqueue all the outputs we can.
const size_t old_outputs_queued = output_queue_->QueuedBuffersCount();
while (auto output_buffer = output_queue_->GetFreeBuffer()) { while (auto output_buffer = output_queue_->GetFreeBuffer()) {
if (!EnqueueOutputRecord(std::move(*output_buffer))) if (!EnqueueOutputRecord(std::move(*output_buffer)))
return; return;
} }
if (old_outputs_queued == 0 && output_queue_->QueuedBuffersCount() != 0) {
// We just started up a previously empty queue.
// Queue state changed; signal interrupt.
if (!device_->SetDevicePollInterrupt())
return;
}
// STREAMON in CAPTURE queue first and then OUTPUT queue. // STREAMON in CAPTURE queue first and then OUTPUT queue.
// This is a workaround of a tegra driver bug that STREAMON in CAPTURE queue // This is a workaround of a tegra driver bug that STREAMON in CAPTURE queue
...@@ -1213,21 +1177,18 @@ bool V4L2VideoEncodeAccelerator::EnqueueOutputRecord( ...@@ -1213,21 +1177,18 @@ bool V4L2VideoEncodeAccelerator::EnqueueOutputRecord(
bool V4L2VideoEncodeAccelerator::StartDevicePoll() { bool V4L2VideoEncodeAccelerator::StartDevicePoll() {
DVLOGF(3); DVLOGF(3);
DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_);
DCHECK(!device_poll_thread_.IsRunning());
// Start up the device poll thread and schedule its first DevicePollTask(). // We need to make sure here not to use base::Unretained(this), as the
if (!device_poll_thread_.Start()) { // |encoder_task_runner_| seems to outlive this class.
if (!device_->StartPolling(
base::BindRepeating(&V4L2VideoEncodeAccelerator::ServiceDeviceTask,
weak_this_),
base::BindRepeating(&V4L2VideoEncodeAccelerator::OnPollError,
weak_this_))) {
VLOGF(1) << "StartDevicePoll(): Device thread failed to start"; VLOGF(1) << "StartDevicePoll(): Device thread failed to start";
NOTIFY_ERROR(kPlatformFailureError); NOTIFY_ERROR(kPlatformFailureError);
return false; return false;
} }
// Enqueue a poll task with no devices to poll on -- it will wait only on the
// interrupt fd.
// base::Unretained(this) is safe, because device_poll_thread_ is owned by
// *this and stops before *this destruction.
device_poll_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&V4L2VideoEncodeAccelerator::DevicePollTask,
base::Unretained(this), false));
return true; return true;
} }
...@@ -1236,12 +1197,7 @@ bool V4L2VideoEncodeAccelerator::StopDevicePoll() { ...@@ -1236,12 +1197,7 @@ bool V4L2VideoEncodeAccelerator::StopDevicePoll() {
DVLOGF(3); DVLOGF(3);
DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_);
// Signal the DevicePollTask() to stop, and stop the device poll thread. if (!device_->StopPolling())
if (!device_->SetDevicePollInterrupt())
return false;
device_poll_thread_.Stop();
// Clear the interrupt now, to be sure.
if (!device_->ClearDevicePollInterrupt())
return false; return false;
// Tegra driver cannot call Streamoff() when the stream is off, so we check // Tegra driver cannot call Streamoff() when the stream is off, so we check
...@@ -1267,21 +1223,8 @@ bool V4L2VideoEncodeAccelerator::StopDevicePoll() { ...@@ -1267,21 +1223,8 @@ bool V4L2VideoEncodeAccelerator::StopDevicePoll() {
return true; return true;
} }
void V4L2VideoEncodeAccelerator::DevicePollTask(bool poll_device) { void V4L2VideoEncodeAccelerator::OnPollError() {
DVLOGF(4); NOTIFY_ERROR(kPlatformFailureError);
DCHECK(device_poll_thread_.task_runner()->BelongsToCurrentThread());
bool event_pending;
if (!device_->Poll(poll_device, &event_pending)) {
NOTIFY_ERROR(kPlatformFailureError);
return;
}
// All processing should happen on ServiceDeviceTask(), since we shouldn't
// touch encoder state from this thread.
encoder_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&V4L2VideoEncodeAccelerator::ServiceDeviceTask,
weak_this_));
} }
void V4L2VideoEncodeAccelerator::NotifyError(Error error) { void V4L2VideoEncodeAccelerator::NotifyError(Error error) {
......
...@@ -145,9 +145,10 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator ...@@ -145,9 +145,10 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator
// any error occurs, |flush_callback| will be called to notify client. // any error occurs, |flush_callback| will be called to notify client.
void FlushTask(FlushCallback flush_callback); void FlushTask(FlushCallback flush_callback);
// Service I/O on the V4L2 devices. This task should only be scheduled from // Service I/O on the V4L2 devices, called by the V4L2 device poller on the
// DevicePollTask(). // |encoder_task_runner_|. |event| is set to true if a V4L2 event was
void ServiceDeviceTask(); // detected.
void ServiceDeviceTask(bool event);
// Handle the device queues. // Handle the device queues.
void Enqueue(); void Enqueue();
...@@ -156,16 +157,13 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator ...@@ -156,16 +157,13 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator
bool EnqueueInputRecord(V4L2WritableBufferRef input_buf); bool EnqueueInputRecord(V4L2WritableBufferRef input_buf);
bool EnqueueOutputRecord(V4L2WritableBufferRef output_buf); bool EnqueueOutputRecord(V4L2WritableBufferRef output_buf);
// Attempt to start/stop device_poll_thread_. // Attempt to start/stop the V4L2 device poller.
bool StartDevicePoll(); bool StartDevicePoll();
bool StopDevicePoll(); bool StopDevicePoll();
// // Called by the V4L2 device poller on the |encoder_task_runner_| whenever an
// Device tasks, to be run on device_poll_thread_. // error occurred.
// void OnPollError();
// The device task.
void DevicePollTask(bool poll_device);
// //
// Safe from any thread. // Safe from any thread.
...@@ -338,10 +336,6 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator ...@@ -338,10 +336,6 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator
const scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_; const scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_;
SEQUENCE_CHECKER(encoder_sequence_checker_); SEQUENCE_CHECKER(encoder_sequence_checker_);
// The device polling thread handles notifications of V4L2 device changes.
// TODO(sheu): replace this thread with an TYPE_IO encoder_thread_.
base::Thread device_poll_thread_;
// To expose client callbacks from VideoEncodeAccelerator. // To expose client callbacks from VideoEncodeAccelerator.
// NOTE: all calls to these objects *MUST* be executed on // NOTE: all calls to these objects *MUST* be executed on
// |child_task_runner_|. // |child_task_runner_|.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment