# 摄像头控制器驱动程序

[English]

## 简介

ESP32-P4 具有以下硬件，用于与外部摄像头传感器通信：

- MIPI 摄像头串行接口 (MIPI CSI)

- ISP的DVP端口 (ISP DVP)

- LCD_CAM的DVP端口 (LCD_CAM DVP)

摄像头控制器驱动程序是为上述硬件外设而设计的。

## 功能概述

- 资源分配 - 涵盖如何通过恰当的配置来分配摄像头控制器实例，以及如何回收资源。

- 启用和禁用摄像头控制器驱动程序 - 涵盖如何启用和禁用摄像头控制器。

- 启动和停止摄像头控制器驱动程序 - 涵盖如何启动和停止摄像头控制器。

- 从摄像头传感器处接收信号 - 涵盖如何从传感器或其他设备接收摄像头信号。

- 注册事件回调函数 - 涵盖如何将用户特定代码挂接到摄像头控制器驱动程序事件回调函数。

- 线程安全 - 列出了驱动程序中线程安全的 API。

- Kconfig 选项 - 列出了支持的 Kconfig 选项，这些选项可以对驱动程序产生不同的影响。

- IRAM 安全 - 描述了当 cache 被禁用时，如何使 CSI 中断和控制功能更好地工作。

### 资源分配

#### 安装摄像头控制器驱动程序

摄像头控制器驱动程序可以通过以下方式之一安装：

- `esp_cam_new_csi_ctlr()`

- `esp_cam_new_isp_dvp_ctlr()`

- `esp_cam_new_lcd_cam_ctlr()`

摄像头控制器驱动程序可以通过 CSI 外设实现，需要应用 `esp_cam_ctlr_csi_config_t` 指定的配置。

如果指定了 `esp_cam_ctlr_csi_config_t` 中的配置，就可以调用 `esp_cam_new_csi_ctlr()` 来分配和初始化 CSI 摄像头控制器句柄。如果函数运行正确，将返回一个 CSI 摄像头控制器句柄。请参考以下代码。

    esp_cam_ctlr_csi_config_t csi_config = {
        .ctlr_id = 0,
        .h_res = MIPI_CSI_DISP_HSIZE,
        .v_res = MIPI_CSI_DISP_VSIZE_640P,
        .lane_bit_rate_mbps = MIPI_CSI_LANE_BITRATE_MBPS,
        .input_data_color_type = CAM_CTLR_COLOR_RAW8,
        .output_data_color_type = CAM_CTLR_COLOR_RGB565,
        .data_lane_num = 2,
        .byte_swap_en = false,
        .queue_items = 1,
    };
    esp_cam_ctlr_handle_t handle = NULL;
    ESP_ERROR_CHECK(esp_cam_new_csi_ctlr(&csi_config, &handle));

摄像头控制器驱动程序可以通过 ISP 外设实现，需要应用 `esp_cam_ctlr_isp_dvp_cfg_t` 指定的配置。

如果指定了 `esp_cam_ctlr_isp_dvp_cfg_t` 中的配置，就可以调用 `esp_cam_new_isp_dvp_ctlr()` 来分配和初始化 ISP DVP 摄像头控制器句柄。如果函数运行正确，将返回一个 ISP DVP 摄像头控制器句柄。请参考以下代码。

在调用 `esp_cam_new_isp_dvp_ctlr()` 之前，还应调用 `esp_isp_new_processor()` 来创建 ISP 句柄。

    isp_proc_handle_t isp_proc = NULL;
    esp_isp_processor_cfg_t isp_config = {
        .clk_hz = 120 * 1000 * 1000,
        .input_data_source = ISP_INPUT_DATA_SOURCE_DVP,
        .input_data_color_type = ISP_COLOR_RAW8,
        .output_data_color_type = ISP_COLOR_RGB565,
        .has_line_start_packet = false,
        .has_line_end_packet = false,
        .h_res = MIPI_CSI_DISP_HSIZE,
        .v_res = MIPI_CSI_DISP_VSIZE,
    };
    ESP_ERROR_CHECK(esp_isp_new_processor(&isp_config, &isp_proc));

    esp_cam_ctlr_isp_dvp_cfg_t dvp_ctlr_config = {
        .data_width = 8,
        .data_io = {53, 54, 52, 0, 1, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1},
        .pclk_io = 21,
        .hsync_io = 5,
        .vsync_io = 23,
        .de_io = 22,
        .io_flags.vsync_invert = 1,
        .queue_items = 10,
    };
    ESP_ERROR_CHECK(esp_cam_new_isp_dvp_ctlr(isp_proc, &dvp_ctlr_config, &cam_handle));

摄像头控制器驱动程序可以通过 LCD_CAM外设实现，需要应用 `esp_cam_ctlr_dvp_config_t` 和 `esp_cam_ctlr_dvp_pin_config_t` 指定的配置。

`esp_cam_ctlr_dvp_config_t::exexternal_xtal`：使用外部生成的 xclk，或者使用驱动内部内部生成的 xclk。

如果指定了 `esp_cam_ctlr_dvp_config_t` 中的配置，就可以调用 `esp_cam_new_dvp_ctlr()` 来分配和初始化 DVP 摄像头控制器句柄。如果函数运行正确，将返回一个 DVP 摄像头控制器句柄。请参考以下代码。

在调用 `esp_cam_new_dvp_ctlr()` 之后，需要分配符合对齐约束的摄像头缓冲区，或调用 `esp_cam_ctlr_alloc_buffer()` 来自动分配。

可以调用 `esp_cam_ctlr_format_conversion()` 来配置格式转换。驱动程序支持以下转换类型：

- YUV 到 RGB 转换

- RGB 到 YUV 转换

- YUV 到 YUV 转换

色彩空间范围支持： * 全色彩空间：RGB 和 YUV 的取值范围为 0-255 * 有限色彩空间：RGB 取值范围为 16-240，YUV Y 分量取值范围为 16-240，U-V 分量取值范围为 16-235

    esp_cam_ctlr_handle_t cam_handle = NULL;
    esp_cam_ctlr_dvp_pin_config_t pin_cfg = {
        .data_width = EXAMPLE_DVP_CAM_DATA_WIDTH,
        .data_io = {
            EXAMPLE_DVP_CAM_D0_IO,
            EXAMPLE_DVP_CAM_D1_IO,
            EXAMPLE_DVP_CAM_D2_IO,
            EXAMPLE_DVP_CAM_D3_IO,
            EXAMPLE_DVP_CAM_D4_IO,
            EXAMPLE_DVP_CAM_D5_IO,
            EXAMPLE_DVP_CAM_D6_IO,
            EXAMPLE_DVP_CAM_D7_IO,
        },
        .vsync_io = EXAMPLE_DVP_CAM_VSYNC_IO,
        .de_io = EXAMPLE_DVP_CAM_DE_IO,
        .pclk_io = EXAMPLE_DVP_CAM_PCLK_IO,
        .xclk_io = EXAMPLE_DVP_CAM_XCLK_IO, // Set XCLK pin to generate XCLK signal
    };
    esp_cam_ctlr_dvp_config_t dvp_config = {
        .ctlr_id = 0,
        .clk_src = CAM_CLK_SRC_DEFAULT,
        .h_res = CONFIG_EXAMPLE_CAM_HRES,
        .v_res = CONFIG_EXAMPLE_CAM_VRES,
        .input_data_color_type = CAM_CTLR_COLOR_RGB565,
        .dma_burst_size = 128,
        .pin = &pin_cfg,
        .bk_buffer_dis = 1,
        .xclk_freq = EXAMPLE_DVP_CAM_XCLK_FREQ_HZ,
    };

    ESP_ERROR_CHECK(esp_cam_new_dvp_ctlr(&dvp_config, &cam_handle));

    const cam_ctlr_format_conv_config_t conv_cfg = {
        .src_format = CAM_CTLR_COLOR_YUV422,      // 源格式：YUV422
        .dst_format = CAM_CTLR_COLOR_RGB565,      // 目标格式：RGB565
        .conv_std = COLOR_CONV_STD_RGB_YUV_BT601,
        .data_width = 8,
        .input_range = COLOR_RANGE_LIMIT,
        .output_range = COLOR_RANGE_LIMIT,
    };
    ESP_ERROR_CHECK(esp_cam_ctlr_format_conversion(cam_handle, &conv_cfg));

#### 卸载摄像头控制器驱动程序

如果不再需要先前安装的摄像头控制器驱动程序，建议通过调用 `esp_cam_ctlr_del()` 来回收资源，从而释放底层硬件。

### 启用和禁用摄像头控制器驱动程序

在开始摄像头控制器操作之前，首先要调用 `esp_cam_ctlr_enable()` 以启用摄像头控制器驱动程序。此函数：

- 将驱动程序状态从 init 切换到 enable。

    ESP_ERROR_CHECK(esp_cam_ctlr_enable(handle));

调用 `esp_cam_ctlr_disable()` 则会执行与上述过程相反的操作，即将驱动程序切回到 init 状态。

    ESP_ERROR_CHECK(esp_cam_ctlr_disable(handle));

### 启动和停止摄像头控制器驱动程序

从摄像头传感器接收信号之前，首先要调用 `esp_cam_ctlr_start()` 以启动摄像头控制器驱动程序。此函数：

- 将驱动程序状态从 enable 切换到 start。

    ESP_ERROR_CHECK(esp_cam_ctlr_start(handle));

调用 `esp_cam_ctlr_stop()` 则会执行与上述过程相反的操作，即将驱动程序切回到 enable 状态。

    ESP_ERROR_CHECK(esp_cam_ctlr_stop(handle));

### 从摄像头传感器处接收信号

调用 `esp_cam_ctlr_receive()`，可以接收来自摄像头传感器或其他设备的信号。

    ESP_ERROR_CHECK(esp_cam_ctlr_receive(handle, &my_trans, ESP_CAM_CTLR_MAX_DELAY));

### 注册事件回调函数

摄像头控制器驱动程序开始接收信号时，会动态生成特定事件。如果在事件发生时需要调用一些函数，请通过调用 `esp_cam_ctlr_register_event_callbacks()` 将这些函数挂接到中断服务程序。所有支持的事件回调函数参见 `esp_cam_ctlr_evt_cbs_t`：

- `esp_cam_ctlr_evt_cbs_t::on_get_new_trans` 可设置回调函数，当摄像头控制器驱动程序完成传输并尝试获取新的事务描述符时，该回调函数会被调用。在 `s_ctlr_csi_start()` 中也会调用此回调函数。如果此回调函数未能获取新的事务描述符，但设置了 `bk_buffer_dis` 标志，则摄像头控制器驱动程序将使用内部备份 buffer。

- `esp_cam_ctlr_evt_cbs_t::on_trans_finished` 可设置回调函数，当摄像头控制器驱动程序完成传输时，该回调函数会被调用。此函数在 ISR 上下文中被调用，因此必须确保该函数不会尝试阻塞（例如，确保只从该函数中调用带有 `ISR` 后缀的 FreeRTOS API）。

### 线程安全

以下工厂函数：

- `esp_cam_new_csi_ctlr()`

- `esp_cam_new_isp_dvp_ctlr()`

- `esp_cam_ctlr_del()`

由驱动程序保证线程安全。使用时，可以直接从不同的 RTOS 任务中调用此类函数，无需额外锁保护。

### Kconfig 选项

当 cache 被禁用时，以下 Kconfig 选项会影响中断处理程序的行为：

- CONFIG_CAM_CTLR_MIPI_CSI_ISR_CACHE_SAFE，详情请参阅 线程安全。

- CONFIG_CAM_CTLR_ISP_DVP_ISR_CACHE_SAFE，详情请参阅 线程安全。

### IRAM 安全

默认情况下，当 cache 因写入或擦除 flash 等原因而被禁用时，CSI 中断将被推迟。

有以下 Kconfig 选项：

- CONFIG_CAM_CTLR_MIPI_CSI_ISR_CACHE_SAFE

- CONFIG_CAM_CTLR_ISP_DVP_ISR_CACHE_SAFE

这些选项支持

- 即使 cache 被禁用也能启用中断服务

- 将 ISR 使用的所有函数放入 IRAM

- 将驱动程序对象放入 DRAM（以防意外映射到 PSRAM）

启用上述 Kconfig 选项，保证 cache 被禁用时中断可以正常运行，但这会增加 IRAM 使用量。因此，当 cache 被禁用时，用户回调函数需要注意（回调函数的）代码和数据应该是 IRAM 安全或 DRAM 安全的。

## 应用示例

- peripherals/camera/mipi_isp_dsi 演示了如何使用 `esp_driver_cam` 组件从 MIPI CSI 摄像头传感器捕获信号，传入 ISP 模块，并通过 DSI 接口将其显示在 LCD 屏幕上。

- peripherals/camera/dvp_isp_dsi 演示了如何使用 `esp_driver_cam` 组件从 DVP 摄像头传感器捕获信号，传入 ISP 模块，并通过 DSI 接口将其显示在 LCD 屏幕上。

## API 参考

### Header File

- components/esp_driver_cam/include/esp_cam_ctlr.h

- This header file can be included with:

  >     #include "esp_cam_ctlr.h"

- This header file is a part of the API provided by the `esp_driver_cam` component. To declare that your component depends on `esp_driver_cam`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_driver_cam

  > or

  >     PRIV_REQUIRES esp_driver_cam

### Functions

esp_err_t esp_cam_ctlr_enable(esp_cam_ctlr_handle_t handle)

  Enable ESP CAM controller.

  参数:

    handle -- [in] ESP CAM controller handle

  返回:

    - ESP_OK

    - ESP_ERR_INVALID_ARG: Invalid argument

    - ESP_ERR_INVALID_STATE: Invalid state

esp_err_t esp_cam_ctlr_start(esp_cam_ctlr_handle_t handle)

  Start ESP CAM controller.

  参数:

    handle -- [in] ESP CAM controller handle

  返回:

    - ESP_OK

    - ESP_ERR_INVALID_ARG: Invalid argument

    - ESP_ERR_INVALID_STATE: Invalid state

esp_err_t esp_cam_ctlr_stop(esp_cam_ctlr_handle_t handle)

  Stop ESP CAM controller.

  参数:

    handle -- [in] ESP CAM controller handle

  返回:

    - ESP_OK

    - ESP_ERR_INVALID_ARG: Invalid argument

    - ESP_ERR_INVALID_STATE: Invalid state

esp_err_t esp_cam_ctlr_disable(esp_cam_ctlr_handle_t handle)

  Disable ESP CAM controller.

  参数:

    handle -- [in] ESP CAM controller handle

  返回:

    - ESP_OK

    - ESP_ERR_INVALID_ARG: Invalid argument

    - ESP_ERR_INVALID_STATE: Invalid state

esp_err_t esp_cam_ctlr_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms)

  Receive data to the given transaction.

  参数:

    - handle -- [in] ESP CAM controller handle

    - trans -- [in] ESP CAM controller transaction type

    - timeout_ms -- [in] Timeout in ms

  返回:

    - ESP_OK

    - ESP_ERR_INVALID_ARG: Invalid argument

    - ESP_ERR_INVALID_STATE: Invalid state

esp_err_t esp_cam_ctlr_del(esp_cam_ctlr_handle_t handle)

  Delete ESP CAM controller handle.

  参数:

    handle -- [in] ESP CAM controller handle

  返回:

    - ESP_OK

    - ESP_ERR_INVALID_ARG: Invalid argument

    - ESP_ERR_INVALID_STATE: Invalid state

esp_err_t esp_cam_ctlr_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data)

  Register ESP CAM controller event callbacks.

  参数:

    - handle -- [in] ESP CAM controller handle

    - cbs -- [in] ESP CAM controller event callbacks

    - user_data -- [in] User data

  返回:

    - ESP_OK

    - ESP_ERR_INVALID_ARG: Invalid argument

    - ESP_ERR_INVALID_STATE: Invalid state

esp_err_t esp_cam_ctlr_get_frame_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...)

  Get ESP CAM controller internal malloced backup buffer(s) addr.

  备注

  Generally, data in internal buffer is ready when `on_trans_finished` event

  参数:

    - handle -- [in] ESP CAM controller handle

    - fb_num -- [in] Number of frame buffer(s) to get. This value must be the same as the number of the followed fbN parameters

    - fb0 -- [out] Address of the frame buffer 0 (first frame buffer)

    - ... -- [out] List of other frame buffers if any

  返回:

    - ESP_OK

    - ESP_ERR_INVALID_ARG: Invalid argument

    - ESP_ERR_INVALID_STATE: Invalid driver state

esp_err_t esp_cam_ctlr_get_frame_buffer_len(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len)

  Get ESP CAM controller internal backup buffer length.

  参数:

    - handle -- [in] ESP CAM controller handle

    - ret_fb_len -- [out] Optional, The size of each frame buffer, in bytes.

  返回:

    - ESP_OK

    - ESP_ERR_INVALID_ARG: NULL ptr

    - ESP_ERR_INVALID_STATE: Invalid driver state

void *esp_cam_ctlr_alloc_buffer(esp_cam_ctlr_handle_t handle, size_t size, uint32_t buf_caps)

  Allocate camera buffer for ESP CAM controller.

  备注

  This function must be called after esp_cam_new_*_ctlr

  参数:

    - handle -- [in] ESP CAM controller handle

    - size -- [in] Buffer size in bytes

    - buf_caps -- [in] Buffer allocation capabilities:

      - MALLOC_CAP_SPIRAM || MALLOC_CAP_DMA: Memory in external SPI RAM

      - MALLOC_CAP_INTERNAL || MALLOC_CAP_DMA: Memory in internal SRAM

  返回:

    - Buffer pointer on success

    - NULL on failure

esp_err_t esp_cam_ctlr_format_conversion(esp_cam_ctlr_handle_t handle, const cam_ctlr_format_conv_config_t *conv_cfg)

  Configure format conversion.

  参数:

    - handle -- [in] ESP CAM controller handle

    - conv_cfg -- [in] Color conversion configuration, contains source and destination formats

  返回:

    - ESP_OK on success

    - ESP_ERR_INVALID_ARG: Invalid argument

    - ESP_ERR_NOT_SUPPORTED: Format conversion not supported by this controller

### Header File

- components/esp_driver_cam/include/esp_cam_ctlr_types.h

- This header file can be included with:

  >     #include "esp_cam_ctlr_types.h"

- This header file is a part of the API provided by the `esp_driver_cam` component. To declare that your component depends on `esp_driver_cam`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_driver_cam

  > or

  >     PRIV_REQUIRES esp_driver_cam

### Structures

struct esp_cam_ctlr_trans_t

  ESP CAM controller transaction type.

  Public Members

  void *buffer

    Transaction buffer.

  size_t buflen

    Len of the transaction buffer.

  size_t received_size

    Received size, this received_size will be written by the driver, indicating the real received size.

struct esp_cam_ctlr_evt_cbs_t

  ESP CAM controller event callbacks.

  Public Members

  bool (*on_get_new_trans)(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data)

    On get new transaction callback.

    Param handle:

      [in] ESP CAM controller handle

    Param trans:

      [in] New transaction

    Param user_data:

      [in] User registered data

    Return:

      Whether a high priority task is woken up by this function

  bool (*on_trans_finished)(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data)

    On transaction finish callback.

    Param handle:

      [in] ESP CAM controller handle

    Param trans:

      [out] Finished transaction

    Param user_data:

      [in] User registered data

    Return:

      Whether a high priority task is woken up by this function

### Macros

ESP_CAM_CTLR_MAX_DELAY

  ESP CAM controller max timeout value.

### Type Definitions

typedef struct esp_cam_ctlr_t *esp_cam_ctlr_handle_t

  ESP CAM controller handle.

### Header File

- components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h

- This header file can be included with:

  >     #include "esp_cam_ctlr_csi.h"

- This header file is a part of the API provided by the `esp_driver_cam` component. To declare that your component depends on `esp_driver_cam`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_driver_cam

  > or

  >     PRIV_REQUIRES esp_driver_cam

### Functions

esp_err_t esp_cam_new_csi_ctlr(const esp_cam_ctlr_csi_config_t *config, esp_cam_ctlr_handle_t *ret_handle)

  New ESP CAM CSI controller.

  参数:

    - config -- [in] CSI controller configurations

    - ret_handle -- [out] Returned ESP CAM controller handle

  返回:

    - ESP_OK

    - ESP_ERR_INVALID_ARG: Invalid argument

    - ESP_ERR_NO_MEM: Out of memory

    - ESP_ERR_NOT_SUPPORTED: Currently not support modes or types

    - ESP_ERR_NOT_FOUND: CSI is registered already

### Structures

struct esp_cam_ctlr_csi_config_t

  ESP CAM CSI controller configurations.

  Public Members

  int ctlr_id

    CSI controller ID.

  mipi_csi_phy_clock_source_t clk_src

    CSI phy clock source.

  uint32_t h_res

    Input horizontal resolution, i.e. the number of pixels in a line.

  uint32_t v_res

    Input vertical resolution, i.e. the number of lines in a frame.

  uint8_t data_lane_num

    Data lane num.

  int lane_bit_rate_mbps

    Lane bit rate in Mbps.

  cam_ctlr_color_t input_data_color_type

    Input color type.

  cam_ctlr_color_t output_data_color_type

    Output color type.

  int queue_items

    Queue items.

  uint32_t byte_swap_en

    Enable byte swap.

  uint32_t bk_buffer_dis

    Disable backup buffer.

  struct esp_cam_ctlr_csi_config_t

    Boolean Flags.

### Header File

- components/esp_driver_cam/isp_dvp/include/esp_cam_ctlr_isp_dvp.h

- This header file can be included with:

  >     #include "esp_cam_ctlr_isp_dvp.h"

- This header file is a part of the API provided by the `esp_driver_cam` component. To declare that your component depends on `esp_driver_cam`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_driver_cam

  > or

  >     PRIV_REQUIRES esp_driver_cam

### Functions

esp_err_t esp_cam_new_isp_dvp_ctlr(isp_proc_handle_t isp_proc, const esp_cam_ctlr_isp_dvp_cfg_t *ctlr_config, esp_cam_ctlr_handle_t *ret_handle)

  New ESP CAM ISP DVP controller.

  参数:

    - isp_proc -- [in] Processor handle

    - ctlr_config -- [in] ISP DVP controller configurations

    - ret_handle -- [out] Returned ESP CAM controller handle

  返回:

    - ESP_OK

    - ESP_ERR_INVALID_ARG: Invalid argument

    - ESP_ERR_NO_MEM: Out of memory

    - ESP_ERR_NOT_SUPPORTED: Currently not support modes or types

    - ESP_ERR_NOT_FOUND: ISP DVP is registered already

### Structures

struct esp_cam_ctlr_isp_dvp_cfg_t

  ESP CAM ISP DVP controller configurations.

  Public Members

  cam_ctlr_data_width_t data_width

    Number of data lines.

  int data_io[ISP_DVP_DATA_SIG_NUM]

    ISP DVP data-in IO numbers.

  int pclk_io

    ISP DVP pclk IO numbers.

  int hsync_io

    ISP DVP hsync IO numbers.

  int vsync_io

    ISP DVP vsync IO numbers.

  int de_io

    ISP DVP de IO numbers.

  uint32_t pclk_invert

    The pclk is inverted.

  uint32_t hsync_invert

    The hsync signal is inverted (i.e. active low)

  uint32_t vsync_invert

    The vsync signal is inverted (i.e. active high)

  uint32_t de_invert

    The de signal is inverted (i.e. active low)

  struct esp_cam_ctlr_isp_dvp_cfg_t io_flags

    ISP DVP IO flags.

  int queue_items

    Queue items.

  uint32_t byte_swap_en

    Enable byte swap.

  uint32_t bk_buffer_dis

    Disable backup buffer.

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。