Android学习20 -- NDK5--操作camera(TODO)
在 Android NDK 环境中,直接用 C++ 操作摄像头,可以使用 Native Camera API(通过 NdkCamera2
提供的接口)。以下是一个完整的示例,展示如何在 NDK 环境中用 C++ 打开摄像头并预览图像。
1. 设置 Android 项目权限
在 AndroidManifest.xml
中,添加摄像头权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
2. Native C++ 代码实现
native-lib.cpp
#include <jni.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include <camera/NdkCameraManager.h>
#include <camera/NdkCameraDevice.h>
#include <camera/NdkCaptureRequest.h>
#include <camera/NdkCameraMetadataTags.h>
#include <android/log.h>
#define LOG_TAG "NativeCamera"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
ACameraManager *cameraManager = nullptr;
ACameraDevice *cameraDevice = nullptr;
ACaptureRequest *captureRequest = nullptr;
ACameraCaptureSession *captureSession = nullptr;
extern "C" JNIEXPORT void JNICALL
Java_com_example_ndkcamera_NativeCamera_initCamera(JNIEnv *env, jobject, jobject surface) {
// 获取 CameraManager
cameraManager = ACameraManager_create();
// 获取摄像头 ID 列表
ACameraIdList *cameraIdList = nullptr;
ACameraManager_getCameraIdList(cameraManager, &cameraIdList);
if (cameraIdList->numCameras < 1) {
LOGD("No cameras found");
return;
}
const char *cameraId = cameraIdList->cameraIds[0];
LOGD("Using camera ID: %s", cameraId);
// 打开摄像头
ACameraDevice_StateCallbacks deviceStateCallbacks = {
.onDisconnected = [](void *context, ACameraDevice *device) {
LOGD("Camera disconnected");
ACameraDevice_close(device);
},
.onError = [](void *context, ACameraDevice *device, int error) {
LOGD("Camera error: %d", error);
ACameraDevice_close(device);
}};
ACameraManager_openCamera(cameraManager, cameraId, &deviceStateCallbacks, &cameraDevice);
// 创建捕获请求
ACaptureRequest_alloc(ACAMERA_REQUEST_TEMPLATE_PREVIEW, &captureRequest);
// 获取 NativeWindow
ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, surface);
ACameraOutputTarget *outputTarget = nullptr;
ACameraOutputTarget_create(nativeWindow, &outputTarget);
ACaptureRequest_addTarget(captureRequest, outputTarget);
// 创建会话
ACameraCaptureSession_stateCallbacks sessionCallbacks = {
.onActive = [](void *context, ACameraCaptureSession *session) {
LOGD("Capture session active");
},
.onClosed = [](void *context, ACameraCaptureSession *session) {
LOGD("Capture session closed");
},
.onReady = [](void *context, ACameraCaptureSession *session) {
LOGD("Capture session ready");
}};
ACameraDevice_createCaptureSession(cameraDevice, 1, &outputTarget, &sessionCallbacks, &captureSession);
// 启动预览
ACameraCaptureSession_setRepeatingRequest(captureSession, nullptr, captureRequest, nullptr);
// 释放资源
ACameraOutputTarget_free(outputTarget);
ACameraIdList_free(cameraIdList);
}
3. Java 代码调用 Native 方法
NativeCamera.java
package com.example.ndkcamera;
import android.view.Surface;
public class NativeCamera {
static {
System.loadLibrary("native-lib");
}
public native void initCamera(Surface surface);
}
MainActivity.java
package com.example.ndkcamera;
import android.os.Bundle;
import android.view.TextureView;
import android.view.Surface;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private NativeCamera nativeCamera;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextureView textureView = new TextureView(this);
setContentView(textureView);
nativeCamera = new NativeCamera();
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Surface previewSurface = new Surface(surface);
nativeCamera.initCamera(previewSurface);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
});
}
}
4. 配置 CMake 文件
CMakeLists.txt
cmake_minimum_required(VERSION 3.10.2)
project("ndkcamera")
add_library(native-lib SHARED native-lib.cpp)
find_library(log-lib log)
find_library(camera2-lib camera2ndk)
target_link_libraries(native-lib ${log-lib} ${camera2-lib})
5. 项目结构
app/
├── src/
│ ├── main/
│ │ ├── java/com/example/ndkcamera/ # Java 文件
│ │ │ ├── MainActivity.java
│ │ │ ├── NativeCamera.java
│ │ ├── cpp/ # C++ 文件
│ │ │ ├── native-lib.cpp
│ │ ├── AndroidManifest.xml
├── CMakeLists.txt
运行结果
- 运行应用后,
TextureView
将显示摄像头的实时预览。 - 所有 NDK 摄像头操作都通过
NdkCamera2
接口完成。
此示例演示了如何通过 NDK 的 Camera2 API 用 C++ 操作摄像头,包括打开摄像头、配置预览会话和显示图像。