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++ 操作摄像头,包括打开摄像头、配置预览会话和显示图像。

# NDK Camera [![Build Status](https://travis-ci.org/luncliff/NdkCamera.svg?branch=master)](https://travis-ci.org/luncliff/NdkCamera) > If there is an issue with this library, please mail to luncliff@gmail.com Simplified [Android Camera 2 API](https://www.youtube.com/watch?v=Bi4QjMfSOE0). Available for both Java/JNI. - API level: 24+ - NDK ### Reference - Personal Template Project: https://github.com/luncliff/Muffin - [API Reference](https://developer.android.com/ndk/reference/group/camera) - [Android Camera Overview](https://source.android.com/devices/camera) - Camera HAL3: https://source.android.com/devices/camera/camera3 - HAL Subsystem: https://source.android.com/devices/camera/camera3_requests_hal - Multi-Camera Support: https://source.android.com/devices/camera/multi-camera - Version Support: https://source.android.com/devices/camera/versioning - Android Media - https://source.android.com/devices/media/framework-hardening ## How to ### Build For **Windows** environment, latest [Android Studio](https://developer.android.com/studio/) is recommended. For **Linux/MacOS**, [Gradle 4.10.2](https://gradle.org/) will be enough. ```console $ git clone https://github.com/luncliff/NdkCamera $ cd ./NdkCamera $ gradle assemble # Build: libndk_camera.so & NdkCamera.aar ``` ### Test Connect your device and run the test with Gradle. Please reference the [test codes](./android/test/ndcam/). ```console $ gradle connectedAndroidTest # Run test ``` ### Use The following code shows working with `SurfaceView` class. ```java package dev.example; // ... import dev.ndcam.*; // Expect we already have a camera permission public class SurfaceDisplay implements SurfaceHolder.Callback { SurfaceView surfaceView; Surface surface; ndcam.Device camera; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... // Load/Init library ndcam.CameraModel.Init(); surfaceView = findViewById(R.id.surfaceView); SurfaceHolder holder = surfaceView.getHolder(); holder.setFixedSize(1920, 1080); holder.setFormat(ImageFormat.YUV_420_888); holder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { // Get all devices in array form for(ndcam.Device device : ndcam.CameraModel.GetDevices()) if(device.facing() == CameraCharacteristics.LENS_FACING_BACK) camera = device; } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) { // Make a repeating caputre request with surface surface = surfaceHolder.getSurface(); camera.repeat(surface); } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { // No more capture if(camera != null) camera.stopRepeat(); } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值