发送摄像头数据给c++

This commit is contained in:
xsl
2025-09-11 14:20:58 +08:00
parent bf99aeb1db
commit 80ff2a091a
@@ -17,7 +17,10 @@ import android.widget.FrameLayout;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.CameraSelector; import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview; import androidx.camera.core.Preview;
import androidx.camera.core.SurfaceRequest; import androidx.camera.core.SurfaceRequest;
import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.camera.lifecycle.ProcessCameraProvider;
@@ -26,38 +29,16 @@ import androidx.core.content.ContextCompat;
import com.google.androidgamesdk.GameActivity; import com.google.androidgamesdk.GameActivity;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.nio.ByteBuffer;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends GameActivity { public class MainActivity extends GameActivity {
private TextureView textureView; // 使用 TextureView 替代 PreviewView
private ProcessCameraProvider cameraProvider; private ProcessCameraProvider cameraProvider;
private FrameLayout containerLayout;
private void initCamera(){ private void initCamera(){
// 获取 GameActivity 的根视图 backgroundExecutor = Executors.newSingleThreadExecutor();
ViewGroup rootView = (ViewGroup) getWindow().getDecorView();
// 创建容器布局
containerLayout = new FrameLayout(this);
containerLayout.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
// 创建 TextureView 用于摄像头预览
textureView = new TextureView(this);
textureView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
// 将 TextureView 添加到容器
containerLayout.addView(textureView);
// 将容器添加到根视图的底部(作为背景)
//rootView.addView(containerLayout); // 添加到索引0(最底层)
rootView.addView(containerLayout, 0);
if (hasCameraPermission()) { if (hasCameraPermission()) {
startCamera(); startCamera();
} else { } else {
@@ -76,7 +57,7 @@ public class MainActivity extends GameActivity {
} }
String[] argArray = new String[2]; String[] argArray = new String[2];
argArray[0] = "sample"; argArray[0] = "sample";
argArray[1] = "hello_triangle"; argArray[1] = "texture_loading";//"hello_triangle";
sendArgumentsToPlatform(argArray); sendArgumentsToPlatform(argArray);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -97,6 +78,8 @@ public class MainActivity extends GameActivity {
} }
private static final int REQUEST_CAMERA_PERMISSION = 1001; private static final int REQUEST_CAMERA_PERMISSION = 1001;
ImageAnalysis imageAnalyzer;
ExecutorService backgroundExecutor;
private void startCamera() { private void startCamera() {
ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
@@ -106,26 +89,32 @@ public class MainActivity extends GameActivity {
try { try {
cameraProvider = cameraProviderFuture.get(); cameraProvider = cameraProviderFuture.get();
Preview preview = new Preview.Builder().build();
CameraSelector cameraSelector = new CameraSelector.Builder() CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK) .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
.build(); .build();
// 使用 TextureView 的 SurfaceTexture imageAnalyzer = new ImageAnalysis.Builder()
SurfaceTexture surfaceTexture = textureView.getSurfaceTexture(); .setTargetAspectRatio(AspectRatio.RATIO_4_3)
if (surfaceTexture != null) { .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
Surface surface = new Surface(surfaceTexture); .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
preview.setSurfaceProvider(new Preview.SurfaceProvider() { .build();
@Override
public void onSurfaceRequested(@NonNull SurfaceRequest request) {
request.provideSurface(surface, ContextCompat.getMainExecutor(MainActivity.this),
result -> {});
}
});
}
cameraProvider.bindToLifecycle(this, cameraSelector, preview);
imageAnalyzer.setAnalyzer(backgroundExecutor, new ImageAnalysis.Analyzer() {
@Override
public void analyze(@NonNull ImageProxy image) {
try {
Log.d("Camera", "Received image: " + image.getWidth() + "x" + image.getHeight());
processImageForVulkan(image);
} finally {
image.close(); // 确保在这里关闭
Log.d("Camera", "Image closed, ready for next frame");
}
}
});
cameraProvider.bindToLifecycle(this, cameraSelector, imageAnalyzer);
} catch (ExecutionException | InterruptedException e) { } catch (ExecutionException | InterruptedException e) {
Log.e("MainActivity", "Error starting camera: " + e.getMessage()); Log.e("MainActivity", "Error starting camera: " + e.getMessage());
@@ -133,6 +122,33 @@ public class MainActivity extends GameActivity {
}, ContextCompat.getMainExecutor(this)); }, ContextCompat.getMainExecutor(this));
} }
private void processImageForVulkan(ImageProxy image) {
// 获取图像信息
int width = image.getWidth();
int height = image.getHeight();
int format = image.getFormat();
// 获取图像数据平面
ImageProxy.PlaneProxy[] planes = image.getPlanes();
// 对于 RGBA_8888 格式,通常只有一个平面
if (planes.length > 0) {
ImageProxy.PlaneProxy plane = planes[0];
ByteBuffer buffer = plane.getBuffer();
int rowStride = plane.getRowStride();
int pixelStride = plane.getPixelStride();
// 调用 Native 方法处理图像
processImageNative(buffer, width, height, format,
rowStride, pixelStride, image.getImageInfo().getRotationDegrees());
}
}
// Native 方法
private native void processImageNative(ByteBuffer buffer, int width, int height,
int format, int rowStride, int pixelStride,
int rotation);
private static final int REQUEST_CODE_PERMISSIONS = 1001; private static final int REQUEST_CODE_PERMISSIONS = 1001;
private static final String[] REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA}; private static final String[] REQUIRED_PERMISSIONS = new String[]{Manifest.permission.CAMERA};