media/gpu/v4l2ip: allocate/destroy buffers in device thread

We want to switch V4L2IP to V4L2Queue, but V4L2Queue is more strict
about all device access being done from the device thread. Currently
buffer allocation and deallocation is being done in the client thread,
so move them to be performed by the device thread instead.

BUG=792790
TEST=Checked that VDA passed on Hana and VEA on Peach

Change-Id: I4b06b3bb10676c3a902e5e91657da2ecca7b737c
Reviewed-on: https://chromium-review.googlesource.com/c/1071496
Commit-Queue: Alexandre Courbot <acourbot@chromium.org>
Reviewed-by: Hirokazu Honda <hiroh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#629119}
diff --git a/media/gpu/v4l2/v4l2_image_processor.cc b/media/gpu/v4l2/v4l2_image_processor.cc
index 0b408d9..76b576f 100644
--- a/media/gpu/v4l2/v4l2_image_processor.cc
+++ b/media/gpu/v4l2/v4l2_image_processor.cc
@@ -99,9 +99,6 @@
 
   DCHECK(!device_thread_.IsRunning());
   DCHECK(!device_poll_thread_.IsRunning());
-
-  DestroyInputBuffers();
-  DestroyOutputBuffers();
 }
 
 void V4L2ImageProcessor::NotifyError() {
@@ -296,14 +293,22 @@
     return false;
   }
 
-  if (!CreateInputBuffers() || !CreateOutputBuffers())
-    return false;
-
   if (!device_thread_.Start()) {
     VLOGF(1) << "Initialize(): device thread failed to start";
     return false;
   }
 
+  // Call to AllocateBuffers must be asynchronous.
+  base::WaitableEvent done;
+  bool result;
+  device_thread_.task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&V4L2ImageProcessor::AllocateBuffersTask,
+                                base::Unretained(this), &result, &done));
+  done.Wait();
+  if (!result) {
+    return false;
+  }
+
   // StartDevicePoll will NotifyError on failure.
   device_thread_.task_runner()->PostTask(
       FROM_HERE,
@@ -465,6 +470,9 @@
     device_thread_.task_runner()->PostTask(
         FROM_HERE, base::BindOnce(&V4L2ImageProcessor::StopDevicePoll,
                                   base::Unretained(this)));
+    device_thread_.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&V4L2ImageProcessor::DestroyBuffersTask,
+                              base::Unretained(this)));
     // Wait for tasks to finish/early-exit.
     device_thread_.Stop();
   } else {
@@ -475,8 +483,7 @@
 
 bool V4L2ImageProcessor::CreateInputBuffers() {
   VLOGF(2);
-  DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
-
+  DCHECK(device_thread_.task_runner()->BelongsToCurrentThread());
   DCHECK(!input_streamon_);
 
   struct v4l2_control control;
@@ -543,7 +550,7 @@
 
 bool V4L2ImageProcessor::CreateOutputBuffers() {
   VLOGF(2);
-  DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
+  DCHECK(device_thread_.task_runner()->BelongsToCurrentThread());
   DCHECK(!output_streamon_);
 
   struct v4l2_rect visible_rect;
@@ -600,7 +607,7 @@
 
 void V4L2ImageProcessor::DestroyInputBuffers() {
   VLOGF(2);
-  DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
+  DCHECK(device_thread_.task_runner()->BelongsToCurrentThread());
   DCHECK(!input_streamon_);
 
   struct v4l2_requestbuffers reqbufs;
@@ -616,7 +623,7 @@
 
 void V4L2ImageProcessor::DestroyOutputBuffers() {
   VLOGF(2);
-  DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
+  DCHECK(device_thread_.task_runner()->BelongsToCurrentThread());
   DCHECK(!output_streamon_);
 
   output_buffer_map_.clear();
@@ -896,6 +903,23 @@
   return true;
 }
 
+void V4L2ImageProcessor::AllocateBuffersTask(bool* result,
+                                             base::WaitableEvent* done) {
+  VLOGF(2);
+  DCHECK(device_thread_.task_runner()->BelongsToCurrentThread());
+
+  *result = CreateInputBuffers() && CreateOutputBuffers();
+  done->Signal();
+}
+
+void V4L2ImageProcessor::DestroyBuffersTask() {
+  VLOGF(2);
+  DCHECK(device_thread_.task_runner()->BelongsToCurrentThread());
+
+  DestroyInputBuffers();
+  DestroyOutputBuffers();
+}
+
 void V4L2ImageProcessor::StartDevicePoll() {
   DVLOGF(3) << "starting device poll";
   DCHECK(device_thread_.task_runner()->BelongsToCurrentThread());
diff --git a/media/gpu/v4l2/v4l2_image_processor.h b/media/gpu/v4l2/v4l2_image_processor.h
index 8d9936b..78e180f1 100644
--- a/media/gpu/v4l2/v4l2_image_processor.h
+++ b/media/gpu/v4l2/v4l2_image_processor.h
@@ -149,6 +149,10 @@
   void ProcessTask(std::unique_ptr<JobRecord> job_record);
   void ServiceDeviceTask();
 
+  // Allocate/Destroy the input/output V4L2 buffers.
+  void AllocateBuffersTask(bool* result, base::WaitableEvent* done);
+  void DestroyBuffersTask();
+
   // Attempt to start/stop device_poll_thread_.
   void StartDevicePoll();
   void StopDevicePoll();