Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 29 commits into from
May 3, 2023

Conversation

acoutts
Copy link
Contributor

@acoutts acoutts commented Feb 23, 2023

Note: this is a re-created PR from flutter/plugins#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.

If you had to change anything in the flutter/tests repo, include a link to the migration guide as per the breaking change policy.

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the relevant style guides and ran the auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages repo does use dart format.)
  • I signed the CLA.
  • The title of the PR starts with the name of the package surrounded by square brackets, e.g. [shared_preferences]
  • I listed at least one issue that this PR fixes in the description above.
  • I updated pubspec.yaml with an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.
  • I updated CHANGELOG.md to add a description of the change, following repository CHANGELOG style.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Copy link
Contributor

@camsim99 camsim99 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, this looks great! Thanks for this and especially for wrapping ImageReader :) just left a few comments.


// We will convert the YUV data to NV21 which is a single-plane image
ByteBuffer bytes =
imageStreamReaderUtils.yuv420ThreePlanesToNV21(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not catch the illegal state exception here? Just wondering if this may not be the only cause.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted for doing it in the other way because I wanted to make sure we post an exception to dart and close the image after. If we catch it here then i'm not sure how we'd still return an error to dart because line 101 would presumedly return normally, which would then have the plugin try and post an image back to dart.

byte[] out = new byte[imageSize + 2 * (imageSize / 4)];

if (areUVPlanesNV21(yuv420888planes, width, height)) {
// Log.i("flutter", "planes are NV21");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: remember to remove the logs!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e0b5716

imageStreamReader.onImageAvailable(mockImage, mockCaptureProps, mockEventSink);

// Make sure we processed the frame with parsePlanesForNv21
verify(mockImageStreamReaderUtils).yuv420ThreePlanesToNV21(any(), anyInt(), anyInt());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you verify the parameters for this call too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c170fe0

Copy link
Contributor

@bparrishMines bparrishMines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me, but the platform interface and android implementation are missing tests. You should be able to do something along the lines of: https://github.com/flutter/packages/blob/main/packages/camera/camera_platform_interface/test/method_channel/type_conversion_test.dart#L64

packages/camera/camera/CHANGELOG.md Show resolved Hide resolved
## 0.10.5

* Adds support for NV21 as a new streaming format in Android which includes correct handling of image padding when present.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove extra space

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 000e783

@@ -1,3 +1,6 @@
## 2.5.0
* Adds NV21 as an image stream format (suitable for Android).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a space above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 000e783

@acoutts
Copy link
Contributor Author

acoutts commented Mar 9, 2023

This looks good to me, but the platform interface and android implementation are missing tests. You should be able to do something along the lines of: https://github.com/flutter/packages/blob/main/packages/camera/camera_platform_interface/test/method_channel/type_conversion_test.dart#L64

Tests added in cb8dc5e

Copy link
Contributor

@bparrishMines bparrishMines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with one more comment

It also looks like this was made before we updated the .gitignore from the repo merge. You will need to remove all the added gradle related files in camera/example and pull from main.

@acoutts
Copy link
Contributor Author

acoutts commented Mar 13, 2023

@bparrishMines i'm fixing one bug I've found today where sometimes imageStreamReader can be null when we try to subscribe a listener.

@acoutts
Copy link
Contributor Author

acoutts commented Mar 13, 2023

Ok that's pushed.

Copy link
Contributor

@camsim99 camsim99 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Android part looks good to me! Looks like you may need to fix some formatting. There was an Android test failure, too, but I think it just needed a re-run.

@acoutts
Copy link
Contributor Author

acoutts commented Mar 13, 2023

Merged main, fixed formatting issue and ran the android tests locally to confirm they are all passing. The one that failed before seems to be a JVM out of memory error. I made the test image smaller to fix that issue in the test.

@bparrishMines
Copy link
Contributor

@acoutts You can go ahead and create a separate PR that updates only the camera_platform_interface package.

@acoutts
Copy link
Contributor Author

acoutts commented May 2, 2023

Whooohoo! Cleaned it up and bumped the pubspec versions. One thing i'm confused on now, it looks like the test case for bgra8888 in camera_image_test was overwritten / replaced with the nv21 one, so I fixed that as well.

@stuartmorgan stuartmorgan added the autosubmit Merge PR when tree becomes green via auto submit App label May 3, 2023
@auto-submit auto-submit bot merged commit 4c4bb46 into flutter:main May 3, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 4, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 4, 2023
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request May 4, 2023
flutter/packages@407b7da...6bd59cd

2023-05-04 41930132+hellohuanlin@users.noreply.github.com [pigeon][reland]enable treat warnings as errors for swift code in unit test (flutter/packages#3901)
2023-05-04 stuartmorgan@google.com [video_player] Fix Android lints (flutter/packages#3886)
2023-05-04 stuartmorgan@google.com [quick_actions] Fix Android lint issues (flutter/packages#3885)
2023-05-03 andrewjohncoutts@gmail.com [camera_platform_interface] [camera] [camera_android] Add NV21 as an image stream format (flutter/packages#3277)
2023-05-03 stuartmorgan@google.com Revert "[pigeon]enable treat warning as errors for swift code in unit test" (flutter/packages#3898)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
nploi pushed a commit to nploi/packages that referenced this pull request Jul 16, 2023
nploi pushed a commit to nploi/packages that referenced this pull request Jul 16, 2023
…image stream format (flutter#3277)

### Note: this is a re-created PR from flutter/plugins#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.*

- flutter/flutter#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].*
@caiofreitas
Copy link

Still facing this issue on these devices:
motorola edge 30 neo, poco x4 pro, poco x3 pro

@ghost
Copy link

ghost commented Jul 31, 2023

It's been merged for a while now. Make sure you're using nv21 on android too. It uses yuv by default.

@caiofreitas
Copy link

It's been merged for a while now. Make sure you're using nv21 on android too. It uses yuv by default.

It was exactly that. My bad...

CameraController(frontCamera, ResolutionPreset.ultraHigh,
enableAudio: false, imageFormatGroup: ImageFormatGroup.nv21);

@arrrrny
Copy link

arrrrny commented Oct 29, 2024

as of the latest version [0.11.0+2] this feature does not work. Only works at 0.10.6 and 0.10.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App p: camera
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[camera] Image stream data is corrupt on some Android devices (Vivo, Xiaomi, Motorola)
8 participants