Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Fix handling of external texture transforms on Android #24888

Merged
merged 4 commits into from
Aug 5, 2022

Conversation

ds84182
Copy link
Contributor

@ds84182 ds84182 commented Mar 9, 2021

Android provides a transformation matrix for SurfaceTextures to allow decoders, cameras, etc. to have the flexibility with the buffers they output, while allowing applications to sample them regardless of layout. However, outside of identity matrices, Flutter was not using this correctly:

  • Android returns a 4x4 matrix, Skia accepts a 3x3. The "conversion" between the two was incorrect.
  • ScaleToFill is a hack added due to the previous point, and ends up (weirdly) normalizing the scale transforms.
  • The surface transform was applied to the surface rectangle itself, not the texture lookup, which causes the surface to escape its layer bounds depending on the incoming transform.

Fixes: flutter/flutter#58138 (And possibly more issues with stranger device buffer layouts)

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 Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See testing the engine for instructions on
    writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.
  • The reviewer has submitted any presubmit flakes in this PR using the engine presubmit flakes form before re-triggering the failure.

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

@google-cla google-cla bot added the cla: yes label Mar 9, 2021
@ds84182 ds84182 marked this pull request as ready for review April 12, 2021 21:50
@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@ds84182 ds84182 requested a review from gaaclarke April 12, 2021 21:51
Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

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

I think the change sounds reasonable. I had a few questions that I added. You're going to have to add tests. It's difficult to run the math through your head and know that it draws correctly. I think the best thing would be to add a golden image test that shows the texture getting drawn correctly. You can see an example golden image test here:


SkPaint paint;
paint.setShader(shader);
canvas.drawRect(SkRect::MakeWH(1, 1), paint);
Copy link
Member

Choose a reason for hiding this comment

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

Will this work for images that aren't square? It seems like the transform may not include the scalar for the aspect ratio considering how it is used in the else branch.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The call to canvas.scale above applies the aspect ratio needed to present the layer. After scaling, canvas coordinates from [0, 1] map directly to [bounds.x/y, +bounds.width/height] in their respective dimensions.

Comment on lines 79 to 87

SkMatrix inverted;
if (!transform.invert(&inverted)) {
FML_LOG(FATAL) << "Invalid SurfaceTexture transformation matrix";
}
transform = inverted;

transform.preScale(1.0, -1.0);
transform.postTranslate(0.0, -1.0);
Copy link
Member

Choose a reason for hiding this comment

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

Would it be more appropriate to fix the math in the java layer? It seems like keeping the lower level more dumb would be preferable, unless that is breaking user's code.

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'm not entirely sure if this should live in the Java layer. The SurfaceTexture transform matrix is defined as transformations on texture coordinate lookup.

The only reason we need to invert, scale, and translate, is that we aren't able to supply a matrix that transforms texture lookup to Skia, but we are able to supply a matrix that transforms the image inside of a fixed size box (which is the inverse). It's inherently tied to how we present the surface inside the engine.

Also, Android only has APIs exposed for working on 4x4 matrices, and lacks some pieces that Skia provides us (like preScale).

Comment on lines +1299 to +1368
// Skia (Row Major):
// | m[0] m[1] m[2] |
// | m[3] m[4] m[5] |
// | m[6] m[7] m[8] |
Copy link
Member

Choose a reason for hiding this comment

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

Why is the skia format described here? I'm not seeing a translation of the matrix to convert between column major and row major. The matrix3 format looks like like the column major format you describe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If this were a row-major -> row-major conversion, the matrix accesses below would be in the form:

m[0], m[1], m[2],
...

since this would produce an identical matrix.

The formats described above are the formats when written in standard matrix notation, which is row-major when read from left to right.

@gaaclarke
Copy link
Member

cc @chinmaygarde, I gave this PR a review but I think you might be the person that knows the most about this code, so heads up.

@chinmaygarde
Copy link
Member

chinmaygarde commented Apr 22, 2021

It hard for me to verify the math here. I'll take a closer look in a but @ds84182, are you able to setup a test for this like Aaron suggested?

@ds84182
Copy link
Contributor Author

ds84182 commented Apr 22, 2021

I haven't had a chance to setup the test yet, I'll try to get to that later this week @chinmaygarde

@chinmaygarde
Copy link
Member

@ds84182 Any updates?

@ds84182
Copy link
Contributor Author

ds84182 commented Apr 30, 2021

I've been a little swamped the past week so I haven't had a chance to write the screenshot test. Preferably we should also compare against what SurfaceView gives for the same surface, right?

@chinmaygarde
Copy link
Member

I am not sure if that strict expectation can be satisfied. But it is certainly worth a shot.

@ds84182
Copy link
Contributor Author

ds84182 commented May 12, 2021

So I've got a test written that compares a SurfaceView with Flutter, which helped me find a bug with this PR. I'll split the test from this change since it's a bit larger than the PR itself.

Getting Android to produce Surfaces with correct transforms and crops has been an.. experience to say the least.

  • On API 18+, we're able to test that identity surfaces match between Flutter and Native Android.
  • On API 21+, we're able to test surface rotations. This requires decoding a video through MediaCodec with the rotation parameter set. Android framework source basically passes through the rotation parameter to the underlying Surface.
  • On API 23+, we're able to test surface rotations and crops. This requires the use of ImageReader (21+) and ImageWriter (23+). MediaCodec presents directly into the ImageReader, the crop rect is set on the acquired Images, and then the images are sent to ImageWriter which presents to the screen. The crop rect (which we now control) and rotation (passed from MediaCodec) are applied directly to the underlying Surface. Note that "Image" is a bit of a misnomer, they're actually just presentable hardware buffers.

@chinmaygarde
Copy link
Member

cc @gaaclarke for followups and @blasten for routing.

@blasten
Copy link

blasten commented Jun 10, 2021

@ds84182 @gaaclarke , is there any action item left?

@ds84182
Copy link
Contributor Author

ds84182 commented Jun 11, 2021

This is waiting on #26109, then I'll add the new goldens to this PR.

@chinmaygarde
Copy link
Member

The linked PR was just closed as stale. Closing this dependency. Please reopen if progress can be made.

@ds84182 ds84182 reopened this Jun 22, 2022
@flutter-dashboard flutter-dashboard bot changed the base branch from master to main June 22, 2022 21:34
@flutter-dashboard
Copy link

This pull request was opened against a branch other than main. Since Flutter pull requests should not normally be opened against branches other than main, I have changed the base to main. If this was intended, you may modify the base back to master. See the Release Process for information about how other branches get updated.

Reviewers: Use caution before merging pull requests to branches other than main, unless this is an intentional hotfix/cherrypick.

@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat (don't just cc him here, he won't see it! He's on Discord!).

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

1 similar comment
@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat (don't just cc him here, he won't see it! He's on Discord!).

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@ds84182
Copy link
Contributor Author

ds84182 commented Jun 22, 2022

Reopening this now that external textures have tests on Android. May need to add an ASSERT if the incoming SkPaint already has an SkShader, which is less than ideal. I'll investigate if there's a way to avoid using SkShader for this.

@dnfield dnfield added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 5, 2022
@auto-submit auto-submit bot merged commit e4f93b8 into flutter:main Aug 5, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Aug 5, 2022
betrevisan pushed a commit to betrevisan/engine that referenced this pull request Aug 5, 2022
@yauheniprakapenka
Copy link

It works fine on Android with 3.1.0-0.0.pre.2225 master

Who want to test it:
$ flutter channel master
$ flutter upgrade

Flutter 3.1.0-0.0.pre.2225 • channel master • https://github.com/flutter/flutter.git
Framework • revision 3070baf (37 minutes ago) • 2022-08-11 10:59:51 -0700
Engine • revision 492cf91
Tools • Dart 2.19.0 (build 2.19.0-81.0.dev) • DevTools 2.16.0

pubspec:
video_player: ^2.4.6

image

Thank a lot for this fix

@pingbird
Copy link
Member

unknown-197

emilyabest pushed a commit to emilyabest/engine that referenced this pull request Aug 12, 2022
@RafaelCarpetres
Copy link

works like charm, thanks!. Now I have to solve video queue issues in my app

@infinitysush
Copy link

awesome! when would this be on stable channel?

@cool2apps
Copy link

I am using flutter 3.3.9 and this problem still exists. flutter 3.3.9 has this fix?

@RafaelCarpetres
Copy link

RafaelCarpetres commented Nov 30, 2022 via email

@cool2apps
Copy link

When it will be available on stable releases? Should I switch to master branch until it will be on stable?

@RafaelCarpetres
Copy link

RafaelCarpetres commented Nov 30, 2022 via email

@cool2apps
Copy link

Switched to master channel and problem has gone. I hope it will be merged to stable channel as soon as possible.

AlessandroToschi pushed a commit to AlessandroToschi/engine that referenced this pull request Dec 2, 2022
@rafaeliga
Copy link

rafaeliga commented Jan 5, 2023

How do we know that its on stable?

It will show on flutter releases, for example flutter release changelog 3.3.0?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
autosubmit Merge PR when tree becomes green via auto submit App cla: yes platform-android will affect goldens
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Texture rendering not real aspect ratio when i play 960x540 videos