media/gpu/v4l2vd: use buffer affinity tracker

When using DMABUFs, it is preferable to use the same V4L2 buffer with
the same underlying buffer, as failure to do so results in memory
unmappings/remappings in the driver. Use the newly introduced buffer
affinity tracker and V4L2Queue::GetFreeBufferForFrame() method to
achieve this transparently in the video decoder.

Furthermore, it is a requirement of the V4L2 stateful decoder interface
that V4L2 buffers are always backed by the same underlying memory, lest
some reference frames lifetime tracking might be incorrect.

BUG=b:159688625
BUG=b:167412992
TEST=video.DecodeAccel.h264 passes on Trogdor.

(cherry picked from commit 2ca56c5955a7fd3acde86a492385e661e3cdaeb1)

Change-Id: I220a321d5584f50406480c105844a82dd96e63c6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2415909
Commit-Queue: Alexandre Courbot <[email protected]>
Reviewed-by: Fritz Koenig <[email protected]>
Cr-Original-Commit-Position: refs/heads/master@{#813178}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2459405
Reviewed-by: Alexandre Courbot <[email protected]>
Cr-Commit-Position: refs/branch-heads/4280@{#131}
Cr-Branched-From: ea420fb963f9658c9969b6513c56b8f47efa1a2a-refs/heads/master@{#812852}
diff --git a/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc b/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc
index f959ec6..25f77a7 100644
--- a/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc
+++ b/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc
@@ -258,12 +258,19 @@
   DVLOGF(3);
   const v4l2_memory mem_type = output_queue_->GetMemoryType();
 
-  while (base::Optional<V4L2WritableBufferRef> buffer =
-             output_queue_->GetFreeBuffer()) {
+  while (true) {
     bool ret = false;
+    bool no_buffer = false;
 
+    base::Optional<V4L2WritableBufferRef> buffer;
     switch (mem_type) {
       case V4L2_MEMORY_MMAP:
+        buffer = output_queue_->GetFreeBuffer();
+        if (!buffer) {
+          no_buffer = true;
+          break;
+        }
+
         ret = std::move(*buffer).QueueMMap();
         break;
       case V4L2_MEMORY_DMABUF: {
@@ -272,6 +279,12 @@
         // once frames are available.
         if (!video_frame)
           return;
+        buffer = output_queue_->GetFreeBufferForFrame(*video_frame);
+        if (!buffer) {
+          no_buffer = true;
+          break;
+        }
+
         ret = std::move(*buffer).QueueDMABuf(std::move(video_frame));
         break;
       }
@@ -279,6 +292,11 @@
         NOTREACHED();
     }
 
+    // Running out of V4L2 buffers is not an error, so just exit the loop
+    // gracefully.
+    if (no_buffer)
+      break;
+
     if (!ret)
       client_->OnBackendError();
   }