虚拟摄像头之三: 重构android8.1 的 v4l2_camera_HAL 支持虚拟摄像头

本文详细解析了Android Camera HAL 中V4L2CameraHAL如何与相机设备进行交互,从打开设备、获取摄像头配置到构建V4L2Camera对象的过程。通过分析`v4l2_camera_hal.cpp`和`v4l2_camera.h`等源码,了解到摄像头初始化涉及的步骤,包括探测/dev/video节点、查询摄像头参数、构建metadata,并通过`V4L2Camera`类管理摄像头操作。此外,还介绍了拍照过程中数据流走向,从用户空间发起拍照请求到数据返回的整个流程。

前言

接下来将了解Android HAL是如何与相机设备进行交互的,一般各硬件厂商的 camera HAL会有个
v4l2_camera_hal.cpp 文件,在这个文件中向frameworks提供HAL的对外接口,该文件会通过
HAL_MODULE_INFO_SYM 修饰一个 camera_module_t 结构体;camera Provider服务就是
通过 HAL_MODULE_INFO_SYM 找到 camera_module_t,从而操作Camera HAL达到操作camera设备。
下一篇《谁在调用 v4l2_camera_HAL 摄像头驱动》中会描述android系统frameworks装载cameraHAL
模块过程,我们共同梳理系统是如何通过C/S模式向android系统上用户提供camera服务功能。

本篇只关注 camera HAL框架实现内容,因笔者需要使用虚拟摄像头给android用户提供摄像头功能,
续重构 camera hal部分源码,因此我们以android系统提供的camera-hal样本例程为分析对象。

camera-hal 模块入口在哪里

源码路径 @hardware/libhardware/modules/camera/3_4/ 下,其中v4l2_camera_hal.cpp是入口
函数

static int open_dev(const hw_module_t* module,
                    const char* name,
                    hw_device_t** device) {
   
   
  return gCameraHAL.openDevice(module, name, device);
}

}  // namespace v4l2_camera_hal

static hw_module_methods_t v4l2_module_methods = {
   
   
    .open = v4l2_camera_hal::open_dev};

camera_module_t HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
   
   
    .common =
        {
   
   
            .tag = HARDWARE_MODULE_TAG,
            .module_api_version = CAMERA_MODULE_API_VERSION_2_4,
            .hal_api_version = HARDWARE_HAL_API_VERSION,
            .id = CAMERA_HARDWARE_MODULE_ID,
            .name = "V4L2 Camera HAL v3",
            .author = "The Android Open Source Project",
            .methods = &v4l2_module_methods,
            .dso = nullptr,
            .reserved = {
   
   0},
        },
    .get_number_of_cameras = v4l2_camera_hal::get_number_of_cameras,
    .get_camera_info = v4l2_camera_hal::get_camera_info,
    .set_callbacks = v4l2_camera_hal::set_callbacks,
    .get_vendor_tag_ops = v4l2_camera_hal::get_vendor_tag_ops,
    .open_legacy = v4l2_camera_hal::open_legacy,
    .set_torch_mode = v4l2_camera_hal::set_torch_mode,
    .init = nullptr,
    .reserved = {
   
   nullptr, nullptr, nullptr, nullptr, nullptr}};

static V4L2CameraHAL gCameraHAL 是静态全局变量,申明也在此文件中,V4L2CameraHAL的构造函数和申明如下:

namespace v4l2_camera_hal {

// Default global camera hal.
static V4L2CameraHAL gCameraHAL;

V4L2CameraHAL::V4L2CameraHAL() : mCameras(), mCallbacks(NULL) {
  HAL_LOG_ENTER();
  // Adds all available V4L2 devices.
  // List /dev nodes.
  DIR* dir = opendir("/dev");
  if (dir == NULL) {
    HAL_LOGE("Failed to open /dev");
    return;
  }
  // Find /dev/video* nodes.
  dirent* ent;
  std::vector<std::string> nodes;
  while ((ent = readdir(dir))) {
    std::string desired = "video";
    size_t len = desired.size();
    if (strncmp(desired.c_str(), ent->d_name, len) == 0) {
      if (strlen(ent->d_name) > len && isdigit(ent->d_name[len])) {
        // ent is a numbered video node.
        nodes.push_back(std::string("/dev/") + ent->d_name);
        HAL_LOGV("Found video node %s.", nodes.back().c_str());
      }
    }
  }
  // Test each for V4L2 support and uniqueness.
  std::unordered_set<std::string> buses;
  std::string bus;
  v4l2_capability cap;
  int fd;
  int id = 0;
  for (const auto& node : nodes) {
    // Open the node.
    fd = TEMP_FAILURE_RETRY(open(node.c_str(), O_RDWR));
    if (fd < 0) {
      HAL_LOGE("failed to open %s (%s).", node.c_str(), strerror(errno));
      continue;
    }
    // Read V4L2 capabilities.
    if (TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_QUERYCAP, &cap)) != 0) {
      HAL_LOGE(
          "VIDIOC_QUERYCAP on %s fail: %s.", node.c_str(), strerror(errno));
    } else if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
      HAL_LOGE("%s is not a V4L2 video capture device.", node.c_str());
    } else {
      // If the node is unique, add a camera for it.
      bus = reinterpret_cast<char*>(cap.bus_info);
      if (buses.insert(bus).second) {
        HAL_LOGV("Found unique bus at %s.", node.c_str());
        std::unique_ptr<V4L2Camera> cam(V4L2Camera::NewV4L2Camera(id++, node));
        if (cam) {
          mCameras.push_back(std::move(cam));
        } else {
          HAL_LOGE("Failed to initialize camera at %s.", node.c_str());
        }
      }
    }
    TEMP_FAILURE_RETRY(close(fd));
  }
}
};

在加载 camera.v4l2.so 库时,将会调用 V4L2CameraHAL 类的构造函数,在构造函数中,主要是探测 /dev/ 目录下有多少个 video 节点且支持V4L2 video capture,
并将探测结果保存在 std::vector<std::unique_ptr<default_camera_hal::Camera>> mCameras; 容器中,此容器是 V4L2CameraHAL 类的私有变量。该容器中存放
的对象是 v4l2_camera_hal::V4L2Camera 类的实例,该 V4L2Camera类是继承 v4l2_camera_hal::Camera 类。程序中调用mCameras对象方法就是来源与上述两个类。

camera 对象构造过程

当系统启动 camera-provider-2-4 服务时、会加载 camera.v4l2.so 库,调用 V4L2CameraHAL 构造函数,此构造函数中调用 V4L2Camera::NewV4L2Camera(id++, node)
构造摄像头对象,我们先了解下相关类的定义:
@hardware/libhardware/modules/camera/3_4/v4l2_camera.h

namespace v4l2_camera_hal {
   
   
// V4L2Camera is a specific V4L2-supported camera device. The Camera object
// contains all logic common between all cameras (e.g. front and back cameras),
// while a specific camera device (e.g. V4L2Camera) holds all specific
// metadata and logic about that device.
class V4L2Camera : public default_camera_hal::Camera {
   
   
 public:
  // Use this method to create V4L2Camera objects. Functionally equivalent
  // to "new V4L2Camera", except that it may return nullptr in case of failure.
  static V4L2Camera* NewV4L2Camera(int id, const std::string path);
  ~V4L2Camera();

 private:
  // Constructor private to allow failing on bad input.
  // Use NewV4L2Camera instead.
  V4L2Camera(int id,
             std::shared_ptr<V4L2Wrapper> v4l2_wrapper,
             std::unique_ptr<Metadata> metadata);

  int enqueueRequest(
      std::shared_ptr<default_camera_hal::CaptureRequest> request) override;

  / Async request processing helpers.
  // Dequeue a request from the waiting queue.
  // Blocks until a request is available.
  std::shared_ptr<default_camera_hal::CaptureRequest> dequeueRequest();

  std::unique_ptr<Metadata> metadata_;
  std::mutex request_queue_lock_;
  std::queue<std::shared_ptr<default_camera_hal::CaptureRequest>>
      request_queue_;
  std::mutex in_flight_lock_;
  // Maps buffer index : request.
  std::map<uint32_t, std::shared_ptr<default_camera_hal::CaptureRequest>>
      in_flight_;
  // Threads require holding an Android strong pointer.
  android::sp<android::Thread> buffer_enqueuer_;
  android::sp<android::Thread> buffer_dequeuer_;
  std::condition_variable requests_available_;
  std::condition_variable buffers_in_flight_;

  int32_t max_input_streams_;
  std::array<int, 3> max_output_streams_;  // {raw, non-stalling, stalling}.
}

@hardware/libhardware/modules/camera/3_4/camera.h

namespace default_camera_hal {
   
   
// Camera represents a physical camera on a device.
// This is constructed when the HAL module is loaded, one per physical camera.
// TODO(b/29185945): Support hotplugging.
// It is opened by the framework, and must be closed before it can be opened
// again.
// This is an abstract class, containing all logic and data shared between all
// camera devices (front, back, etc) and common to the ISP.
class Camera {
   
   
    public:
        // id is used to distinguish cameras. 0 <= id < NUM_CAMERAS.
        // module is a handle to the HAL module, used when the device is opened.
        Camera(int id);
        virtual ~Camera();

        // Common Camera Device Operations (see <hardware/camera_common.h>)
        int openDevice(const hw_module_t *module, hw_device_t **device);
        int getInfo(struct camera_info *info);
        int close();

        // Camera v3 Device Operations (see <hardware/camera3.h>)
        int initialize(const camera3_callback_ops_t *callback_ops);
        int configureStreams(camera3_stream_configuration_t *stream_list);
        const camera_metadata_t *constructDefaultRequestSettings(int type);
        int processCaptureRequest(camera3_capture_request_t *temp_request);
        void dump(int fd);
        int flush();

    protected:
    	
    	...  //> 省略纯虚方法声明内容

        // Callback for when the device has filled in the requested data.
        // Fills in the result struct, validates the data, sends appropriate
        // notifications, and returns the result to the framework.
        void completeRequest(
            std::shared_ptr<CaptureRequest> request, int err);
        // Prettyprint template names
        const char* templateToString(int type);

    private:
        // Camera device handle returned to framework for use
        camera3_device_t mDevice;
        // Get static info from the device and store it in mStaticInfo.
        int loadStaticInfo();
        // Confirm that a stream configuration is valid.
        int validateStreamConfiguration(
            const camera3_stream_configuration_t* stream_config);
        // Verify settings are valid for reprocessing an input buffer
        bool isValidReprocessSettings(const camera_metadata_t *settings);
        // Pre-process an output buffer
        int preprocessCaptureBuffer(camera3_stream_buffer_t *buffer);
        // Send a shutter notify message with start of exposure time
        void notifyShutter(uint32_t frame_number, uint64_t timestamp);
        // Send an error message and return the errored out result.
        void completeRequestWithError(std::shared_ptr<CaptureRequest> request);
        // Send a capture result for a request.
        void sendResult(std::shared_ptr<CaptureRequest> request);
        // Is type a valid template type (and valid index into mTemplates)
        bool isValidTemplateType(int type);

        // Identifier used by framework to distinguish cameras
        const int mId;
        // CameraMetadata containing static characteristics
        std::unique_ptr<StaticProperties> mStaticInfo;
        // Flag indicating if settings have been set since
        // the last configure_streams() call.
        bool mSettingsSet;
        // Busy flag indicates camera is in use
        bool mBusy;
        // Camera device operations handle shared by all devices
        const static camera3_device_ops_t sOps;
        // Methods used to call back into the framework
        const camera3_callback_ops_t *mCallbackOps;
        // Lock protecting the Camera object for modifications
        android::Mutex mDeviceLock;
        // Lock protecting only static camera characteristics, which may
        // be accessed without the camera device open
        android::Mutex mStaticInfoLock;
        android::Mutex mFlushLock;
        // Standard camera settings templates
        std::unique_ptr<const android::CameraMetadata> mTemplates[CAMERA3_TEMPLATE_COUNT];
        // Track in flight requests.
        std::unique_ptr<RequestTracker> mInFlightTracker;
};
}  // namespace default_camera_hal

这两个头文件基本上涵盖了V4L2camera对象成员变量和方法内容, NewV4L2Camera() 构造方法返回是 static V4L2Camera 对象,
被存放到容器中,我们简单分析一下摄像头构造过程源码。
@hardware/libhardware/modules/camera/3_4/v4l2_camera.cpp

V4L2Camera* V4L2Camera::NewV4L2Camera(int id, const std::string path) {
   
   
  HAL_LOG_ENTER();
  //> 1. 构造 v4l2_wrapper 对象
  std::shared_ptr<V4L2Wrapper> v4l2_wrapper(V4L2Wrapper::NewV4L2Wrapper(path));
  if (!v4l2_wrapper) {
   
   
    HAL_LOGE("Failed to initialize V4L2 wrapper.");
    return nullptr;
  }

  //> 2. 获取该摄像头配置参数
  std::unique_ptr<Metadata> metadata;
  int res = GetV4L2Metadata(v4l2_wrapper, &metadata);
  if (res) {
   
   
    HAL_LOGE("Failed to initialize V4L2 metadata: %d", res);
    return nullptr;
  }
  //> 3. 构造出 V4L2Camera 对象
  return new V4L2Camera(id, std::move(v4l2_wrapper), std::move(metadata));
}

我们看到创建 V4L2Camera 对象,分为三步,

  1. 构造 v4l2_wrapper 对象;
  2. 获取该摄像头配置参数;
  3. 构造出 V4L2Camera 对象.

接下来我们把每步都梳理:

第一步 构造 v4l2_wrapper 对象

path 的内容 ‘/dev/videoX’ 其中 X 是编号,是 KERNEL 驱动创建的 video 设备,本例中是 V4L2loopback.ko 加载到内核
后生成的 摄像头是 /dev/video4 , v4l2_wrapper(V4L2Wrapper::NewV4L2Wrapper(path)) 对象申明执行内容如下:

V4L2Wrapper* V4L2Wrapper::NewV4L2Wrapper(const std::string device_path) {
   
   
  std::unique_ptr<V4L2Gralloc> gralloc(V4L2Gralloc::NewV4L2Gralloc());
  if (!gralloc) {
   
   
    HAL_LOGE("Failed to initialize gralloc helper.");
    return nullptr;
  }

  return new V4L2Wrapper(device_path, std::move(gralloc));
}

V4L2Wrapper::V4L2Wrapper(const std::string device_path,
                         std::unique_ptr<V4L2Gralloc> gralloc)
    : device_path_(std::move(device_path)),
      gralloc_(std::move(gralloc)),
      connection_count_(0) {
   
    HAL_LOG_ENTER(); }

构造 v4l2_wrapper 对象时,同时创建 V4L2Gralloc 对象出来,在 V4L2Wrapper类中定义如下:

// The underlying gralloc module.
  std::unique_ptr<V4L2Gralloc> gralloc_;

至于 V4L2Gralloc 类我们暂时不做展开梳理,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值