modules/video_capture: add NV12 support on Linux

Add native NV12 support on Linux v4l2 video_capture module.

Bug: webrtc:14650
Change-Id: I97e2010be4f15168b218da4855be8b0e985008a5
Signed-off-by: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/282841
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38753}
diff --git a/AUTHORS b/AUTHORS
index c991ce8..7c7cb34 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -138,6 +138,7 @@
 Agora IO <*@agora.io>
 ARM Holdings <*@arm.com>
 BroadSoft Inc. <*@broadsoft.com>
+Canonical Ltd <*@canonical.com>
 CoSMo Software Consulting, Pte Ltd <*@cosmosoftware.io>
 Facebook Inc. <*@fb.com>
 Google Inc. <*@google.com>
diff --git a/modules/video_capture/device_info_impl.cc b/modules/video_capture/device_info_impl.cc
index ac78cbc..ff32a78 100644
--- a/modules/video_capture/device_info_impl.cc
+++ b/modules/video_capture/device_info_impl.cc
@@ -148,7 +148,8 @@
                     (capability.videoType == requested.videoType ||
                      capability.videoType == VideoType::kI420 ||
                      capability.videoType == VideoType::kYUY2 ||
-                     capability.videoType == VideoType::kYV12)) {
+                     capability.videoType == VideoType::kYV12 ||
+                     capability.videoType == VideoType::kNV12)) {
                   bestVideoType = capability.videoType;
                   bestformatIndex = tmp;
                 }
diff --git a/modules/video_capture/linux/device_info_v4l2.cc b/modules/video_capture/linux/device_info_v4l2.cc
index c1062d4..5af5801 100644
--- a/modules/video_capture/linux/device_info_v4l2.cc
+++ b/modules/video_capture/linux/device_info_v4l2.cc
@@ -228,9 +228,10 @@
   video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   video_fmt.fmt.pix.sizeimage = 0;
 
-  int totalFmts = 4;
+  int totalFmts = 5;
   unsigned int videoFormats[] = {V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV420,
-                                 V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY};
+                                 V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY,
+                                 V4L2_PIX_FMT_NV12};
 
   int sizes = 13;
   unsigned int size[][2] = {{128, 96},   {160, 120},  {176, 144},  {320, 240},
@@ -258,6 +259,8 @@
             cap.videoType = VideoType::kMJPEG;
           } else if (videoFormats[fmts] == V4L2_PIX_FMT_UYVY) {
             cap.videoType = VideoType::kUYVY;
+          } else if (videoFormats[fmts] == V4L2_PIX_FMT_NV12) {
+            cap.videoType = VideoType::kNV12;
           }
 
           // get fps of current camera mode
diff --git a/modules/video_capture/linux/video_capture_v4l2.cc b/modules/video_capture/linux/video_capture_v4l2.cc
index 2655fbe..5101a67 100644
--- a/modules/video_capture/linux/video_capture_v4l2.cc
+++ b/modules/video_capture/linux/video_capture_v4l2.cc
@@ -115,20 +115,22 @@
   // Supported video formats in preferred order.
   // If the requested resolution is larger than VGA, we prefer MJPEG. Go for
   // I420 otherwise.
-  const int nFormats = 5;
+  const int nFormats = 6;
   unsigned int fmts[nFormats];
   if (capability.width > 640 || capability.height > 480) {
     fmts[0] = V4L2_PIX_FMT_MJPEG;
     fmts[1] = V4L2_PIX_FMT_YUV420;
     fmts[2] = V4L2_PIX_FMT_YUYV;
     fmts[3] = V4L2_PIX_FMT_UYVY;
-    fmts[4] = V4L2_PIX_FMT_JPEG;
+    fmts[4] = V4L2_PIX_FMT_NV12;
+    fmts[5] = V4L2_PIX_FMT_JPEG;
   } else {
     fmts[0] = V4L2_PIX_FMT_YUV420;
     fmts[1] = V4L2_PIX_FMT_YUYV;
     fmts[2] = V4L2_PIX_FMT_UYVY;
-    fmts[3] = V4L2_PIX_FMT_MJPEG;
-    fmts[4] = V4L2_PIX_FMT_JPEG;
+    fmts[3] = V4L2_PIX_FMT_NV12;
+    fmts[4] = V4L2_PIX_FMT_MJPEG;
+    fmts[5] = V4L2_PIX_FMT_JPEG;
   }
 
   // Enumerate image formats.
@@ -173,6 +175,8 @@
     _captureVideoType = VideoType::kI420;
   else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
     _captureVideoType = VideoType::kUYVY;
+  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
+    _captureVideoType = VideoType::kNV12;
   else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG ||
            video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
     _captureVideoType = VideoType::kMJPEG;