[camera_platform_interface] [camera] [camera_android] Add NV21 as an image stream format (#3277)

### Note: this is a re-created PR from https://github.com/flutter/plugins/pull/6985
---

This PR adds NV21 as an image stream format for android devices. This is the format required for things like MLKit. Unfortunately a lot of people tend to implement the yuv->nv21 incorrectly in dart, which results in countless issues of users saying the image stream doesn't work, or that mlkit doesn't work.

By allowing the plugin to send NV21 to dart, this will fix all of those yuv conversion issues.

Highlights:

-   Added an abstraction around `ImageReader` called `ImageStreamReader` and moved the image stream logic into this class to clean up the `Camera` class. This allows us to test the image stream handler in isolation.
-   Added tests for `ImageStreamReader` to make sure it only calls the `removePlaneBufferPadding` function for planes that contain padding.
-   Added a new utility class called `ImageStreamReaderUtils` which contains the logic for trimming the padding.
-   Added tests for `ImageStreamReaderUtils` to make sure it only removes padding when a given buffer contains padding to be removed.
-   There are tests to confirm both that `removePlaneBufferPadding` is only called when padding is present, and to confirm that if `removePlaneBufferPadding` does happen to be called with a buffer containing no padding, it still returns a valid buffer.

*List which issues are fixed by this PR. You must list at least one issue.*

- https://github.com/flutter/flutter/issues/118350

*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md
index 1a783b1..b6dc896 100644
--- a/packages/camera/camera/CHANGELOG.md
+++ b/packages/camera/camera/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.10.5
+
+* Adds NV21 as an image streaming option for Android.
+
 ## 0.10.4
 
 * Allows camera to be switched while video recording.
diff --git a/packages/camera/camera/lib/src/camera_image.dart b/packages/camera/camera/lib/src/camera_image.dart
index bfcad66..e1303f6 100644
--- a/packages/camera/camera/lib/src/camera_image.dart
+++ b/packages/camera/camera/lib/src/camera_image.dart
@@ -90,6 +90,9 @@
       // android.graphics.ImageFormat.JPEG
       case 256:
         return ImageFormatGroup.jpeg;
+      // android.graphics.ImageFormat.NV21
+      case 17:
+        return ImageFormatGroup.nv21;
     }
   }
 
diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml
index 839f064..28648ad 100644
--- a/packages/camera/camera/pubspec.yaml
+++ b/packages/camera/camera/pubspec.yaml
@@ -4,7 +4,7 @@
   Dart.
 repository: https://github.com/flutter/packages/tree/main/packages/camera/camera
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
-version: 0.10.4
+version: 0.10.5
 
 environment:
   sdk: ">=2.18.0 <4.0.0"
@@ -21,9 +21,9 @@
         default_package: camera_web
 
 dependencies:
-  camera_android: ^0.10.5
+  camera_android: ^0.10.7
   camera_avfoundation: ^0.9.13
-  camera_platform_interface: ^2.4.0
+  camera_platform_interface: ^2.5.0
   camera_web: ^0.3.1
   flutter:
     sdk: flutter
diff --git a/packages/camera/camera/test/camera_image_test.dart b/packages/camera/camera/test/camera_image_test.dart
index ecf4b50..5a04651 100644
--- a/packages/camera/camera/test/camera_image_test.dart
+++ b/packages/camera/camera/test/camera_image_test.dart
@@ -139,6 +139,30 @@
       expect(cameraImage.format.group, ImageFormatGroup.yuv420);
     });
 
+    test('$CameraImage has ImageFormatGroup.nv21 for android', () {
+      debugDefaultTargetPlatformOverride = TargetPlatform.android;
+
+      final CameraImage cameraImage =
+          CameraImage.fromPlatformData(<dynamic, dynamic>{
+        'format': 17,
+        'height': 1,
+        'width': 4,
+        'lensAperture': 1.8,
+        'sensorExposureTime': 9991324,
+        'sensorSensitivity': 92.0,
+        'planes': <dynamic>[
+          <dynamic, dynamic>{
+            'bytes': Uint8List.fromList(<int>[1, 2, 3, 4]),
+            'bytesPerPixel': 1,
+            'bytesPerRow': 4,
+            'height': 1,
+            'width': 4
+          }
+        ]
+      });
+      expect(cameraImage.format.group, ImageFormatGroup.nv21);
+    });
+
     test('$CameraImage has ImageFormatGroup.bgra8888 for iOS', () {
       debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
 
@@ -162,6 +186,7 @@
       });
       expect(cameraImage.format.group, ImageFormatGroup.bgra8888);
     });
+
     test('$CameraImage has ImageFormatGroup.unknown', () {
       final CameraImage cameraImage =
           CameraImage.fromPlatformData(<dynamic, dynamic>{