Skip to content

Migrate CameraX from SurfaceTexture to SurfaceProducer. #6462

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

Merged
merged 12 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/camera/camera_android_camerax/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.6.5+4

* [Supports Impeller](https://docs.flutter.dev/release/breaking-changes/android-surface-plugins).

## 0.6.5+3

* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
package io.flutter.plugins.camerax;

import android.app.Activity;
import android.graphics.SurfaceTexture;
import android.util.Size;
import android.view.Surface;
import androidx.annotation.NonNull;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
Expand Down Expand Up @@ -51,11 +49,6 @@ public class CameraXProxy {
return new Preview.Builder();
}

/** Creates a {@link Surface} instance from the specified {@link SurfaceTexture}. */
public @NonNull Surface createSurface(@NonNull SurfaceTexture surfaceTexture) {
return new Surface(surfaceTexture);
}

/**
* Creates an instance of the {@link SystemServicesFlutterApiImpl}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

package io.flutter.plugins.camerax;

import android.graphics.SurfaceTexture;
import android.util.Size;
import android.view.Surface;
import androidx.annotation.NonNull;
Expand All @@ -25,7 +24,7 @@ public class PreviewHostApiImpl implements PreviewHostApi {
private final TextureRegistry textureRegistry;

@VisibleForTesting public @NonNull CameraXProxy cameraXProxy = new CameraXProxy();
@VisibleForTesting public @Nullable TextureRegistry.SurfaceTextureEntry flutterSurfaceTexture;
@VisibleForTesting public @Nullable TextureRegistry.SurfaceProducer flutterSurfaceProducer;

public PreviewHostApiImpl(
@NonNull BinaryMessenger binaryMessenger,
Expand Down Expand Up @@ -62,12 +61,11 @@ public void create(
@Override
public @NonNull Long setSurfaceProvider(@NonNull Long identifier) {
Preview preview = getPreviewInstance(identifier);
flutterSurfaceTexture = textureRegistry.createSurfaceTexture();
SurfaceTexture surfaceTexture = flutterSurfaceTexture.surfaceTexture();
Preview.SurfaceProvider surfaceProvider = createSurfaceProvider(surfaceTexture);
flutterSurfaceProducer = textureRegistry.createSurfaceProducer();
Preview.SurfaceProvider surfaceProvider = createSurfaceProvider(flutterSurfaceProducer);
preview.setSurfaceProvider(surfaceProvider);

return flutterSurfaceTexture.id();
return flutterSurfaceProducer.id();
}

/**
Expand All @@ -76,13 +74,13 @@ public void create(
*/
@VisibleForTesting
public @NonNull Preview.SurfaceProvider createSurfaceProvider(
@NonNull SurfaceTexture surfaceTexture) {
@NonNull TextureRegistry.SurfaceProducer surfaceProducer) {
return new Preview.SurfaceProvider() {
@Override
public void onSurfaceRequested(@NonNull SurfaceRequest request) {
surfaceTexture.setDefaultBufferSize(
surfaceProducer.setSize(
request.getResolution().getWidth(), request.getResolution().getHeight());
Surface flutterSurface = cameraXProxy.createSurface(surfaceTexture);
Surface flutterSurface = surfaceProducer.getSurface();
request.provideSurface(
flutterSurface,
Executors.newSingleThreadExecutor(),
Expand Down Expand Up @@ -133,8 +131,8 @@ String getProvideSurfaceErrorDescription(int resultCode) {
*/
@Override
public void releaseFlutterSurfaceTexture() {
if (flutterSurfaceTexture != null) {
flutterSurfaceTexture.release();
if (flutterSurfaceProducer != null) {
flutterSurfaceProducer.release();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.graphics.SurfaceTexture;
import android.util.Size;
import android.view.Surface;
import androidx.camera.core.Preview;
Expand Down Expand Up @@ -86,59 +85,60 @@ public void create_createsPreviewWithCorrectConfiguration() {
public void setSurfaceProviderTest_createsSurfaceProviderAndReturnsTextureEntryId() {
final PreviewHostApiImpl previewHostApi =
spy(new PreviewHostApiImpl(mockBinaryMessenger, testInstanceManager, mockTextureRegistry));
final TextureRegistry.SurfaceTextureEntry mockSurfaceTextureEntry =
mock(TextureRegistry.SurfaceTextureEntry.class);
final SurfaceTexture mockSurfaceTexture = mock(SurfaceTexture.class);
final TextureRegistry.SurfaceProducer mockSurfaceProducer =
mock(TextureRegistry.SurfaceProducer.class);
final Long previewIdentifier = 5L;
final Long surfaceTextureEntryId = 120L;
final Long surfaceProducerEntryId = 120L;

previewHostApi.cameraXProxy = mockCameraXProxy;
testInstanceManager.addDartCreatedInstance(mockPreview, previewIdentifier);

when(mockTextureRegistry.createSurfaceTexture()).thenReturn(mockSurfaceTextureEntry);
when(mockSurfaceTextureEntry.surfaceTexture()).thenReturn(mockSurfaceTexture);
when(mockSurfaceTextureEntry.id()).thenReturn(surfaceTextureEntryId);
when(mockTextureRegistry.createSurfaceProducer()).thenReturn(mockSurfaceProducer);
when(mockSurfaceProducer.id()).thenReturn(surfaceProducerEntryId);

final ArgumentCaptor<Preview.SurfaceProvider> surfaceProviderCaptor =
ArgumentCaptor.forClass(Preview.SurfaceProvider.class);
final ArgumentCaptor<Surface> surfaceCaptor = ArgumentCaptor.forClass(Surface.class);

// Test that surface provider was set and the surface texture ID was returned.
assertEquals(previewHostApi.setSurfaceProvider(previewIdentifier), surfaceTextureEntryId);
assertEquals(previewHostApi.setSurfaceProvider(previewIdentifier), surfaceProducerEntryId);
verify(mockPreview).setSurfaceProvider(surfaceProviderCaptor.capture());
verify(previewHostApi).createSurfaceProvider(mockSurfaceTexture);
verify(previewHostApi).createSurfaceProvider(mockSurfaceProducer);
}

@Test
public void createSurfaceProvider_createsExpectedPreviewSurfaceProvider() {
final PreviewHostApiImpl previewHostApi =
new PreviewHostApiImpl(mockBinaryMessenger, testInstanceManager, mockTextureRegistry);
final SurfaceTexture mockSurfaceTexture = mock(SurfaceTexture.class);
final TextureRegistry.SurfaceProducer mockSurfaceProducer =
mock(TextureRegistry.SurfaceProducer.class);
final Surface mockSurface = mock(Surface.class);
final SurfaceRequest mockSurfaceRequest = mock(SurfaceRequest.class);
final SurfaceRequest.Result mockSurfaceRequestResult = mock(SurfaceRequest.Result.class);
final SystemServicesFlutterApiImpl mockSystemServicesFlutterApi =
mock(SystemServicesFlutterApiImpl.class);
final int resolutionWidth = 200;
final int resolutionHeight = 500;
final Long surfaceProducerEntryId = 120L;

previewHostApi.cameraXProxy = mockCameraXProxy;
when(mockCameraXProxy.createSurface(mockSurfaceTexture)).thenReturn(mockSurface);
when(mockSurfaceRequest.getResolution())
.thenReturn(new Size(resolutionWidth, resolutionHeight));
when(mockCameraXProxy.createSystemServicesFlutterApiImpl(mockBinaryMessenger))
.thenReturn(mockSystemServicesFlutterApi);
when(mockTextureRegistry.createSurfaceProducer()).thenReturn(mockSurfaceProducer);
when(mockSurfaceProducer.id()).thenReturn(surfaceProducerEntryId);
when(mockSurfaceProducer.getSurface()).thenReturn(mockSurface);

final ArgumentCaptor<Surface> surfaceCaptor = ArgumentCaptor.forClass(Surface.class);
@SuppressWarnings("unchecked")
final ArgumentCaptor<Consumer<SurfaceRequest.Result>> consumerCaptor =
ArgumentCaptor.forClass(Consumer.class);

Preview.SurfaceProvider previewSurfaceProvider =
previewHostApi.createSurfaceProvider(mockSurfaceTexture);
previewHostApi.createSurfaceProvider(mockSurfaceProducer);
previewSurfaceProvider.onSurfaceRequested(mockSurfaceRequest);

verify(mockSurfaceTexture).setDefaultBufferSize(resolutionWidth, resolutionHeight);
verify(mockSurfaceProducer).setSize(resolutionWidth, resolutionHeight);
verify(mockSurfaceRequest)
.provideSurface(surfaceCaptor.capture(), any(Executor.class), consumerCaptor.capture());

Expand Down Expand Up @@ -189,13 +189,13 @@ public void createSurfaceProvider_createsExpectedPreviewSurfaceProvider() {
public void releaseFlutterSurfaceTexture_makesCallToReleaseFlutterSurfaceTexture() {
final PreviewHostApiImpl previewHostApi =
new PreviewHostApiImpl(mockBinaryMessenger, testInstanceManager, mockTextureRegistry);
final TextureRegistry.SurfaceTextureEntry mockSurfaceTextureEntry =
mock(TextureRegistry.SurfaceTextureEntry.class);
final TextureRegistry.SurfaceProducer mockSurfaceProducer =
mock(TextureRegistry.SurfaceProducer.class);

previewHostApi.flutterSurfaceTexture = mockSurfaceTextureEntry;
previewHostApi.flutterSurfaceProducer = mockSurfaceProducer;

previewHostApi.releaseFlutterSurfaceTexture();
verify(mockSurfaceTextureEntry).release();
verify(mockSurfaceProducer).release();
}

@Test
Expand Down
2 changes: 1 addition & 1 deletion packages/camera/camera_android_camerax/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: camera_android_camerax
description: Android implementation of the camera plugin using the CameraX library.
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android_camerax
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
version: 0.6.5+3
version: 0.6.5+4

environment:
sdk: ^3.4.0
Expand Down