Rockchip · AI & Linux Hub

Камеры и видео

Rockchip Linux 4.4 Camera: V4L2, ISP, 3A и приложения

Rockchip Linux 4.4 Camera: V4L2, ISP, 3A и приложения · V2.0.0

· · 35 мин чтения

Справка платформы: V2.0.0 производителя, RK3399, RK3326/PX30, RK3288, RK312x/PX3SE, RK180x; Linux 4.4. Полные разделы ниже посвящены драйверам камеры, подключению сенсоров, захвату и отладке. Конкретные сочетания платы ArmSoM/BSP/SDK/ядра не проверены; сверьте схему, интерфейсы, питание/такты, драйверы и IQ-файлы. Примеры и измерения производителя не являются тестами ArmSoM; команды не выполнялись. ZH использует китайские оригинальные рисунки, EN/RU/DE — английские.

Техническое предисловие: структура ISP/CIF, разработка/перенос сенсоров, отладка верхнего уровня, API приложений и 3A. Драйверы ориентированы на V4L2 и предоставляют интерфейсы переноса/приложений; нужны знания инструментов и понятий V4L2.

ArmSoM Docs · Rockchip Linux

SoC Kernel ISP CIF
RK3399 4.4 2 —
RK3326/PX30 4.4 1 1
RK3288 4.4 1 1
RK312x/PX3SE 4.4 — 1
RK180x 4.4 1 1

1. Версии и терминология

1.1 Термины

3A — алгоритмы автофокуса AF, автоэкспозиции AE и автобаланса белого AWB либо библиотека algorithms.so.

Async Sub Device — асинхронное подустройство V4L2 в Media Controller, например сенсор или MIPI DPHY. Bayer Raw/Raw Bayer — кадры RGGB, BGGR, GBRG, GRBG от сенсора/ISP. Buildroot — семейство Linux SDK Rockchip на основе Buildroot. Camera — система VIP/ISP, подключённого сенсора и их драйверов. CIF — модуль VIP, принимающий данные сенсора в память без функций ISP. DVP — параллельный Digital Video Port. Entity — узел Media Controller. FCC/FourCC — четырёхсимвольный код формата изображения в Linux, см. соответствующий раздел. HSYNC — строчная синхронизация DVP. ISP — Image Signal Processing, приём и обработка изображения; термин включает аппаратную часть и драйвер. IOMMU — Input-Output Memory Management Unit, отображает физически разрозненные страницы в непрерывное адресное пространство CIF/ISP; включает аппаратный модуль и драйвер. Английский оригинал здесь пишет iohmu. IQ — Image Quality, настроенный XML Bayer Raw-камеры для 3A. Media Controller — инфраструктура ядра для управления медиатопологией. MIPI — протокол MIPI. MIPI-DPHY — протокол D-PHY либо совместимый контроллер Rockchip. MP — Main Path, выход ISP полного разрешения для фотографий и RAW. PCLK — пиксельный такт сенсора. Pipeline — цепь связанных Entity. RKCIF — имя драйвера CIF. RKISP1 — имя драйвера ISP.

SP — Self Path, выход ISP максимум 1080p. Userspace — пользовательское пространство Linux в отличие от ядра. V4L2 — Video4Linux2, видеоподсистема ядра. VIP — Video Input Processor, прежнее альтернативное название CIF. VSYNC — кадровая синхронизация DVP.

1.2 История драйверов ISP/CIF

RKISP1 и RKCIF основаны на Media Controller, V4L2 Framework и VB2. Сенсор регистрируется асинхронно как Async Sub Device. Код: drivers/media/platform/rockchip/isp1/ и drivers/media/platform/rockchip/cif/; сенсоры — drivers/media/i2c. Старые версии больше не обновляются регулярно либо не поддерживаются. Таблица:

Драйвер Тип Kernel В рамках статьи Расположение кода
RKISP1 ISP 4.4 Да drivers/media/platform/rockchip/isp1
RKCIF CIF 4.4 Да drivers/media/platform/rockchip/cif
RK-ISP10 ISP 4.4 Нет drivers/media/platform/rk-isp10/
RK-
CAMSYS
CIF 4.4 Нет drivers/media/video

1.3 Документ FAQ

Для отладки сенсора используйте Rockchip_Trouble_Shooting_Linux4.4_Camera_CN, обычно в том же каталоге.

2. Разработка и перенос драйвера сенсора

Драйверы находятся в drivers/media/i2c. Здесь рассматриваются драйверы Media Controller, не drivers/media/i2c/soc_camera. Сенсор максимально независим от RKCIF/RKISP1; регистрация асинхронная, связь задаётся remote-endpoint в DTS. Такой драйвер подходит обоим.

Сенсор выступает Sub Device и связывается Pad с Rkcif/Rkisp1/Mipi Dphy. Рассмотрены код, DTS и отладка. Пять задач переноса: последовательность vdd/reset/powerdown/clk по datasheet; регистры требуемого разрешения/формата; callbacks struct v4l2_subdev_ops, обычно set_fmt/get_fmt/s_stream/s_power; V4L2 controls fps/exposure/gain/test pattern; probe() и инициализация Media Control/Sub Device. Добавьте документацию по примеру Documentation/devicetree/bindings/media/i2c/, чтобы настроить плату. В board DTS задайте clk и iomux, regulator/gpio по схеме, дочерний port для связи CIF/ISP. Примеры — ov5695 и ov2685.

2.1 Последовательность питания

Требования различаются. Многим OV достаточно правильных mclk/vdd/reset/powerdown без строгого порядка и задержек, но OV2685 требует строгой последовательности. Следуйте диаграмме datasheet. Ниже сокращённая __ov5695_power_on() из drivers/media/i2c/ov5695.c:

static int __ov5695_power_on(struct ov5695 *ov5695)
{
  int ret;
  u32 delay_us;
  struct device *dev = &ov5695->client->dev;

  ret = clk_set_rate(ov5695->xvclk, OV5695_XVCLK_FREQ);

  if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ)
   dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
  ret = clk_prepare_enable(ov5695->xvclk);
  if (!IS_ERR(ov5695->reset_gpio))
   gpiod_set_value_cansleep(ov5695->reset_gpio, 1);

  ret = regulator_bulk_enable(OV5695_NUM_SUPPLIES, ov5695->supplies);

  if (!IS_ERR(ov5695->reset_gpio))
   gpiod_set_value_cansleep(ov5695->reset_gpio, 0);

  if (!IS_ERR(ov5695->pwdn_gpio))
   gpiod_set_value_cansleep(ov5695->pwdn_gpio, 1);

  /* 8192 cycles prior to first SCCB transaction */
  delay_us = ov5695_cal_delay(8192);
  usleep_range(delay_us, delay_us * 2);

  return 0;
}

OV5695: сначала xvclk/mclk, затем reset, затем источники vdd. regulator_bulk подходит, поскольку vdd/vodd/avdd не требуют порядка; при строгой последовательности управляйте отдельно, как OV2685. Переведите reset/powerdown в рабочее состояние согласно корпусу и схеме; может требоваться только один из них. Затем выдержите 8192 тактов по OV5695. Даже если сенсор работает при иной последовательности, надёжнее соблюдать datasheet. Аналогично реализуйте требуемое выключение.

2.1.1 Проверка включения

На этапе .probe() читается chip id, например ov5695_check_sensor_id(). Правильный ID обычно подтверждает питание и работоспособную связь I2C.

2.2 Список начальных регистров

struct ov5695_mode и struct ov2685_mode описывают режимы: разрешение, Mbus Code, fps, список регистров. Заполняйте регистры по данным производителя. Список заканчивается REG_NULL; этот маркер не должен совпадать с адресом регистра.

2.3 Обратные вызовы v4l2_subdev_ops

Это основа управления сенсором; полный интерфейс в include/media/v4l2-subdev.h. Минимально рекомендуются: .open() при открытии /dev/v4l-subdev? из userspace, необходим для отдельной настройки controls; .s_power() включение/выключение; .s_stream() запуск/остановка, обычно запись регистров выдачи кадров; .enum_mbus_code() форматы; .enum_frame_size() разрешения; .get_fmt() текущий формат/размер, без него media-ctl не покажет формат Entity; .set_fmt() установка. Сложнее всего питание и поток: OV5695 использует pm_runtime, а .s_stream() вызывает v4l2_ctrl_handler_setup() для фактической записи controls, которые могли измениться при выключенном сенсоре.

2.4 V4L2 controls

Для динамической экспозиции, усиления и blanking, особенно RAW Bayer, реализуйте controls. ov5695_initialize_controls() объявляет набор и границы. struct v4l2_ctrl_ops задаёт ov5695_set_ctrl(), через который приложение устанавливает значения.

2.5 Probe, media entity и v4l2 subdev

probe разбирает DTS для regulator/gpio/clk питания, затем регистрирует media entity, v4l2 subdev и controls. Регистрация subdev асинхронная. v4l2_i2c_subdev_init() задаёт subdev и callbacks; ov5695_initialize_controls() — controls; media_entity_init() — entity, у OV5695 один выход Source Pad; v4l2_async_register_subdev() обязателен, поскольку RKISP1/RKCIF используют асинхронную регистрацию.

2.6 Пример DTS: MIPI-сенсор

По схеме настройте pinctrl/iomux, clk, gpio и remote port. Пример OV5695 в rk3326-evb-lp3-v10-linux.dts:

ov5695: ov5695@36 {
  compatible = "ovti,ov5695";
  reg = <0x36>;

  clocks = <&cru SCLK_CIF_OUT>;
  clock-names = "xvclk";

  avdd-supply = <&vcc2v8_dvp>;
  dovdd-supply = <&vcc1v8_dvp>;
  dvdd-supply = <&vdd1v5_dvp>;

  /*reset-gpios = <&gpio2 14 GPIO_ACTIVE_HIGH>;*/
  pwdn-gpios = <&gpio2 14 GPIO_ACTIVE_HIGH>;

  rockchip,camera-module-index = <0>;
  rockchip,camera-module-facing = "back";
  rockchip,camera-module-name = "TongJu";
  rockchip,camera-module-lens-name = "CHT842-MD";

  port {
   ucam_out: endpoint {
     remote-endpoint = <&mipi_in_ucam>;
     data-lanes = <1 2>;
   };
  };
};

pinctrl инициализирует reset и clk iomux. clock называется xvclk, как ожидает драйвер, частота 24M. OV5695 требует три питания. port/endpoint связывается с mipi_in_wcam, а MIPI DPHY ссылается на wcam_out. data-lanes задаёт две линии OV5695 и должен совпадать в wcam_out.

2.7 Пример DTS: DVP-сенсор

В отличие от MIPI, DVP не имеет data-lanes, endpoint связан с CIF; прочее аналогично. Для gc2155 в arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10-linux.dts remote-endpoint указывает cif_in; data-lanes не нужен.

2.8 Отладка сенсора

После переноса проверьте работу. При проблемах сначала используйте FAQ.

2.8.1 Успешность регистрации

Первое — I2C и правильный chip id, подтверждающий питание. Обычно драйвер печатает соответствующий журнал, разный для каждого сенсора. Второе — сенсор должен присутствовать как Entity в топологии media-ctl. Тогда регистрация успешна.

2.8.2 Выход инструментов захвата

Захватите кадры через v4l2-ctl, GStreamer или приложение камеры.

2.8.3 Проверка controls

Через v4l2-ctl измените gain/exposure/blanking и проверьте кадры: растёт ли яркость при усилении/экспозиции, падает ли fps при увеличении blanking.

3. Инструменты отладки и команды

Длинные команды разбиты обратной косой чертой \ для удобства. При копировании переносы можно сохранить; если объединяете в одну строку, удалите символ продолжения .

3.1 v4l-utils

В SDK пакет интегрирован по умолчанию; включается/выключается настройкой Buildroot:

# grep -rn LIBV4L_UTILS - buildroot/configs/rockchip/camera.config
BR2_PACKAGE_LIBV4L_UTILS=y

Исходники доступны на www.linuxtv.org. В Ubuntu пакет устанавливается apt:

# sudo apt-get install v4l-utils

3.2 Топология через media-ctl

media-ctl входит в v4l-utils и проверяет/настраивает format, crop, link enable каждой Entity. Это даёт гибкость, но для обычных сценариев достаточно стандартных настроек.

3.2.1 Просмотр топологии

Следующая команда выводит топологию. При CIF+ISP, нескольких ISP или USB-камере возможно несколько устройств /dev/media0, /dev/media1, /dev/media2.

# media-ctl -p -d /dev/media0

Проверьте Entity сенсора. Её отсутствие означает проблему регистрации, см. FAQ. Сокращённый вывод OV5695 на RK3326:

# media-ctl -p -d /dev/media1
- entity 9: m00_b_ov5695 2-0036 (1 pad, 1 link)
     type V4L2 subdev subtype Sensor flags 0
     device node name /dev/v4l-subdev2
   pad0: Source
       [fmt:SBGGR10_1X10/2592x1944@10000/300000 field:none]
       -> "rockchip-mipi-dphy-rx":0 [ENABLED,DYNAMIC]

Entity m00_b_ov5695 2-0036 — V4L2 subdev Sensor, узел /dev/v4l-subdev2, доступный приложению/v4l2-ctl. Единственный выход Source — pad0. Формат [fmt:SBGGR10_1X10/2592x1944@10000/300000 field:none]; SBGGR10_1X10 — mbus-code. Source pad0 связан с pad0 “rockchip-mipi-dphy-rx”, состояние ENABLED. DYNAMIC разрешает переключить DISABLED. Если один ISP/CIF подключён к двум сенсорам, активен только один. Пример:

[root@rk3326_64:/]# media-ctl -p -d /dev/media1
-entity 9: irs16x5c 1-003d (1 pad, 1 link)
     type V4L2 subdev subtype Sensor flags 0
     device node name /dev/v4l-subdev2
   pad0: Source
       [fmt:SBGGR12_1X12/224x1557@10000/300000 field:none]
       -> "rockchip-mipi-dphy-rx":0 [ENABLED,DYNAMIC]

-entity 10: irs16x5c 2-003d (1 pad, 1 link)
      type V4L2 subdev subtype Sensor flags 0
      device node name /dev/v4l-subdev3
   pad0: Source
       [fmt:SBGGR12_1X12/224x1557@10000/300000 field:none]
       -> "rockchip-mipi-dphy-rx":0 [DYNAMIC]

В этом примере:

Оба irs16x5c подключены к “rockchip-mipi-dphy-rx”:0, но ENABLED только entity 9. Переключать можно лишь при остановленной цепи; менять Entity во время захвата нельзя.

3.2.2 Переключение сенсора

При нескольких подключённых сенсорах используются следующие команды:

# media-ctl -d /dev/media0 \
  -l '"ov5695 7-0036":0->"rockchip-sy-mipi-dphy":0[0]'
# media-ctl -d /dev/media0 \
  -l '"ov2685 7-003c":0->"rockchip-sy-mipi-dphy":0[1]'

Формат: media-ctl -l’“entity name”:pad->“entity name”:pad[Status]’. Вся связь заключена в одинарные кавычки из-за > [ ]; имена — в двойные из-за пробелов. Status задаёт включение/выключение значениями 0/1; сверяйте конкретное значение по примеру и media-ctl.

3.2.3 Формат и размер Entity

Пример 1: OV5695 по умолчанию 2592x1944, изменим на 1920x1080.

# media-ctl -d /dev/media1 \
  --set-v4l2 '"m00_b_ov5695 2-0036":0[fmt:SBGGR10_1X10/1920x1080]'

Затем соответственно измените rkisp1-isp-subdev и crop видеоустройства: последующая стадия не должна быть больше предыдущей.

# media-ctl -d /dev/media1 \
  --set-v4l2 '"rkisp1-isp-subdev":0[fmt:SBGGR10_1X10/1920x1080]'
# media-ctl -d /dev/media1 \
  --set-v4l2 '"rkisp1-isp-subdev":0[crop:(0,0)/1920x1080]'
# media-ctl -d /dev/media1 \
  --set-v4l2 '"rkisp1-isp-subdev":2[crop:(0,0)/1920x1080]'
# v4l2-ctl -d /dev/video1 \
  --set-selection=target=crop,top=0,left=0,width=1920,height=1080

Пример 2: Для Bayer RAW rkisp1 по умолчанию выдаёт YUV. Измените fmt rkisp1-isp-subdev на формат сенсора, чтобы MP выдавал RAW.

# media-ctl -d /dev/media1 \
  --set-v4l2 '"rkisp1-isp-subdev":2[fmt:SBGGR10/2592x1944]'

Обратите внимание:

Спецсимволы требуют одинарных/двойных кавычек; не изменяйте пробелы внутри них. Подробности — media-ctl –help.

3.2.4 Форматы mbus-code

Media Bus Pixel Codes описывают передачу по физической шине, например сенсор→ISP через MIPI DPHY либо внутри ISP. Не путайте с FourCC, описывающим формат в памяти. Определения находятся в include/uapi/linux/media-bus-format.h. Используемые коды:

Макрос ядра Сокращение Mbus-code Тип Bpp Ширина шины Отсчёты
MEDIA_BUS_FMT_SBGGR8_1X8 SBGGR8_1X8 Bayer
Raw
8 8 1
MEDIA_BUS_FMT_SRGGB8_1X8 SRGGB8_1X8 Bayer
Raw
8 8 1
MEDIA_BUS_FMT_SBGGR10_1X10 SBGGR10_1X10 Bayer
Raw
10 10 1
MEDIA_BUS_FMT_SRGGB10_1X10 SRGGB10_1X10 Bayer
Raw
10 10 1
MEDIA_BUS_FMT_SBGGR12_1X12 SBGGR12_1X12 Bayer
Raw
12 12 1
MEDIA_BUS_FMT_SRGGB12_1X12 SRGGB12_1X12 Bayer
Raw
12 12 1
MEDIA_BUS_FMT_YUYV8_2X8 YVYU8_2X8 YUV
422
16 8 2
MEDIA_BUS_FMT_UYUV8_2X8 UYUV8_2X8 YUV
422
16 8 2
MEDIA_BUS_FMT_Y8_1X8 Y8_1X8 YUV
GREY
8 8 1
MEDIA_BUS_FMT_RGB888_1X24 RGB888_1X24 RGB
888
24 24 1

media-ctl может перечислить поддерживаемые mbus-code:

# media-ctl --known-mbus-fmts

3.2.5 Поиск видеоустройств

Sub Device соответствует /dev/v4l-subdev, Video Device — /dev/video. При нескольких устройствах важно найти выдающий кадры узел.

# media-ctl -d /dev/media1 -e "rkisp1_selfpath"
/dev/video2
# media-ctl -d /dev/media1 -e "rkisp1_mainpath"
/dev/video1

Две команды показывают пути SP и MP в /dev/media1. RKISP1 имеет два видеовыхода, оба дают кадры. Для RKCIF аналогично:

# media-ctl -d /dev/media0 -e "stream_cif"
/dev/video0

Команда показывает RKCIF в /dev/media0. У RKCIF один видеовыход.

# v4l2-ctl -d /dev/video1 --all

Команда показывает основные параметры /dev/video1: crop, fmt, controls.

3.3 Захват через v4l2-ctl

media-ctl через /dev/media0 управляет format/size/link узлов топологии (английский оригинал пишет /dev/medio0). v4l2-ctl работает с /dev/video0 и /dev/video1, выполняя set_fmt/reqbuf/qbuf/dqbuf/stream_on/stream_off. Здесь он захватывает кадры и задаёт exposure/gain/VTS. Сначала изучите справку, особенно streaming и vidcap. Краткая справка:

# v4l2-ctl --help

Полная подробная справка:

# v4l2-ctl --help-all

Параметры streaming:

# v4l2-ctl --help-streaming

Параметры vidcap, главным образом get-fmt/set-fmt:

# v4l2-ctl --help-vidcap

3.3.1 Захват кадров v4l2-ctl

Пример 1: один кадр NV12 640x480 от RKCIF в /tmp/nv12.bin, первые три кадра отбрасываются: они возвращаются userspace, но не сохраняются.

# v4l2-ctl -d /dev/video0 \
  --set-fmt-video=width=640,height=480,pixelformat=NV12 \
  --stream-mmap=3 \
  --stream-skip=3 \
  --stream-to=/tmp/nv12.bin \
  --stream-count=1 \
  --stream-poll

Пример 2: десять кадров NV12 1920x1080 от RKISP в /tmp/nv12.bin.

# v4l2-ctl -d /dev/video1 \
  --set-selection=target=crop,top=0,left=0,width=1920,height=1080
  --set-fmt-video=width=1920,height=1080,pixelformat=NV12 \
  --stream-mmap=3 \
  --stream-to=/tmp/nv12.bin \
  --stream-count=10 \
  --stream-poll

Параметры: -d выбирает /dev/video0. –set-selection задаёт crop, не больше выхода предыдущей стадии RKISP1; для RKCIF используется –set-crop. –set-fmt-video задаёт ширину/высоту и FourCC pixelformat, здесь NV12. –stream-mmap выбирает выделенный ядром физически непрерывный либо отображённый IOMMU буфер. –stream-skip пропускает первые три кадра без записи. –stream-to задаёт файл. –stream-count — число сохраняемых кадров без пропущенных. –stream-poll использует асинхронный IO/select перед dqbuf, чтобы тот не блокировался; без опции dqbuf ждёт кадр.

3.3.2 Экспозиция, усиление и другие controls

Если драйвер реализует controls, v4l2-ctl задаёт exposure/gain до захвата. RKCIF/RKISP наследуют controls подустройства, поэтому сенсор виден через /dev/video3. Пример OV5695 на RK3326 с exposure/gain/blanking/test_pattern:

# v4l2-ctl -d /dev/video1 -l

User Controls

    exposure 0x00980911 (int) : min=4 max=2228 step=1 default=1104 value=1104
      gain 0x00980913 (int) : min=0 max=16383 step=1 default=1024 value=1024

Image Source Controls

vertical_blanking 0x009e0901 (int) : min=1152 max=31687 step=1 default=1152 value=1152
  analogue_gain 0x009e0903 (int) : min=16 max=248 step=1 default=248 value=248

Image Processing Controls

   test_pattern 0x009f0903 (menu): min=0 max=4 default=0 value=0

Изменение exposure и analogue_gain через v4l2-ctl:

# v4l2-ctl -d /dev/video3 --set-ctrl'exposure=1216,analogue_gain=10'

3.3.3 Захват RAW

MP RKISP1 захватывает RAW в ISP bypass без настройки изображения. Пример OV5695: SBGGR10_1X10, 2592x1944.

# media-ctl -d /dev/media0 \
  --set-v4l2 '"ov5695 7-0036":0[fmt:SBGGR10_1X10/2592x1944]'
# media-ctl -d /dev/media0 \
  --set-v4l2 '"rkisp1-isp-subdev":0[fmt:SBGGR10_1X10/2592x1944]'
# media-ctl -d /dev/media0 \
  --set-v4l2 '"rkisp1-isp-subdev":0[crop:(0,0)/2592x1944]'
# media-ctl -d /dev/media0 \
  --set-v4l2 '"rkisp1-isp-subdev":2[fmt:SBGGR10_1X10/2592x1944]'
# media-ctl -d /dev/media0 \
  --set-v4l2 '"rkisp1-isp-subdev":2[crop:(0,0)/2592x1944]'
# v4l2-ctl -d /dev/video4 \
  --set-ctrl 'exposure=1216,analogue_gain=10' \
--set-selection=target=crop,top=0,left=0,width=2592,height=1944 \
--set-fmt-video=width=2592,height=1944,pixelformat=BG10 \
--stream-mmap=3 \
--stream-to=/tmp/mp.raw.out \
--stream-count=1 \
--stream-poll

Строка 4 media-ctl согласует fmt isp-subdev с сенсором. Строки 3/5 задают crop равным сенсору, без обрезки. В строке 6 можно поднять expo/gain для тёмного кадра, если драйвер реализует controls. Строки 7/8 отключают crop через selection и выбирают FourCC BG10. Хотя ISP не обрабатывает RAW, 10/12-битные пиксели дополняются младшими нулями до 16 бит. Для просмотра в Ubuntu добавьте к RAW трёхстрочный заголовок PGM. Пример:

# cat > /tmp/raw.pgm << EOF
P5
2592 1944
65535
EOF

# cat /tmp/mp.raw.out >> /tmp/raw.pgm

Строка 2 — постоянный идентификатор P5; строка 3 — ширина/высота через пробел; строка 4 — глубина, 65535 для 16 бит или 255 для 8. Строка 7 добавляет RAW после заголовка. Заголовок содержит ровно три строки, без лишних пустых.

3.3.4 Форматы FourCC

Four Character Codes кодирует имя формата четырьмя символами, 32 бит. Макрос Linux:

#define v4l2_fourcc(a,b,c,d) \
  (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))

FourCC описывает хранение изображения/видео в памяти, в отличие от mbus-code. Используемые форматы ниже; полный список в videodev2.h.

Макрос ядра FourCC
V4L2_PIX_FMT_NV12 NV12
V4L2_PIX_FMT_NV21 NV21
V4L2_PIX_FMT_NV16 NV16
V4L2_PIX_FMT_NV61 NV61
V4L2_PIX_FMT_NV12M NM12
V4L2_PIX_FMT_YUYV YUYV
V4L2_PIX_FMT_YUV420 YU12
V4L2_PIX_FMT_SBGGR10 BG10
V4L2_PIX_FMT_SGBRG10 GB10
V4L2_PIX_FMT_SGRBG10 BA10
V4L2_PIX_FMT_SRGGB10 RG10
V4L2_PIX_FMT_GREY GREY

3.4 Просмотр YUV в Ubuntu через mplayer

Сохранённые предыдущими командами кадры можно просматривать mplayer. Установка через apt:

# sudo apt-get install mplayer

NV12 640x480:

# W=640; H=480; mplayer /tmp/nv12.bin -loop 0 -demuxer rawvideo -fps 30 \
  -rawvideo w=${W}:h=${H}:size=$((${W}*${H}*3/2)):format=NV12

YUYV 640x480:

# W=640; H=480; mplayer /tmp/yuyv.bin -loop 0 -demuxer rawvideo -fps 30 \
  -rawvideo w=${W}:h=${H}:size=$((${W}*${H}*2)):format=YUY2

W/H — переменные ширины/высоты для последующего использования.

fps задаёт скорость: 1 означает один кадр в секунду. size — размер кадра, format — формат; mplayer -rawvideo format=help перечисляет варианты. Под Windows используйте, например, 7yuv.

3.5 GStreamer

В SDK GStreamer обеспечивает предпросмотр и кодирование. v4l2src получает кадры с видеоустройства; rkisp_3A_server по умолчанию запускает настройку правильной яркости/цвета.

3.5.1 Отображение GStreamer

Следующая команда показывает камеру на экране:

# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/gstreamer-1.0
# export XDG_RUNTIME_DIR=/tmp/.xdg
# gst-launch-1.0 v4l2src device=/dev/video1 ! \
  video/x-raw,format=NV12,width=2592,height=1944,framerate=30/1 ! kmssink

3.5.2 Кодирование видео и изображений

SDK поддерживает аппаратное кодирование; команды кодируют поток в файл:

# gst-launch-1.0 v4l2src device=/dev/video1 num-buffers=100 ! \
  video/x-raw,format=NV12,width=1920,height=1088,framerate=30/1 ! \
  videoconvert ! mpph264enc ! h264parse ! mp4mux ! \
  filesink location=/tmp/h264.mp4
# gst-launch-1.0 -v v4l2src device=/dev/video1 num-buffers=10 ! \
  video/x-raw,format=NV12,width=1920,height=1080 ! mppjpegenc ! \
  multifilesink location=/tmp/test%05d.jpg

mppjpegenc/mpph264enc — аппаратные кодировщики плагина rockchipmpp. MPP требует высоту, кратную 16; нужен патч fea937b015e7 media: rockchip: isp1/cif: set height alignment to 16 in queue_setup.

3.6 Отладка без экрана

librkuvc.so позволяет плате выступать UVC-камерой, подключённой USB OTG к ПК. Код примера приведён в разделе разработки приложений.

3.7 Включение отладочного вывода

RKISP1/RKCIF содержат v4l2_dbg(); включение:

# echo 1 > /sys/module/video_rkcif/parameters/debug

Или:

# echo 1 > /sys/module/video_rkisp1/parameters/debug

У VB2/V4L2 также есть переключатели. Журнал VB2:

# echo 7 > /sys/module/videobuf2_core/parameters/debug

VB2 показывает оборот буферов reqbuf/qbuf/dqbuf и изменение состояния. Переключатель общий: включится вывод всех пользователей VB2, включая VPU/ISP. Далее включается весь V4L2-журнал, например ioctl:

# echo 0x1f > /sys/class/video4linux/video0/dev_debug

Можно включить только часть сообщений. Биты определены макросами include/media/v4l2-ioctl.h; задайте нужный бит:

/* Just log the ioctl name + error code */
#define V4L2_DEV_DEBUG_IOCTL     0x01
/* Log the ioctl name arguments + error code */
#define V4L2_DEV_DEBUG_IOCTL_ARG   0x02
/* Log the file operations open, release, mmap and get_unmapped_area */
#define V4L2_DEV_DEBUG_FOP      0x04
/* Log the read and write file operations and the VIDIOC_(D)QBUF ioctls */
#define V4L2_DEV_DEBUG_STREAMING   0x08
/* Log poll() */
#define V4L2_DEV_DEBUG_POLL      0x10

4. Интеграция 3A

Раздел только для RKISP1; RKCIF не имеет ISP и не требует 3A. Раньше приложение связывалось с librkisp.so либо использовало rkisp/rkv4l2src GStreamer. Это усложняло разработку и плохо подходило VLC/Chrome. Начиная с RKISP1 v0.1.5 и camera_engine_rkisp v2.2.0 rkisp_3A_server автоматически выполняет 3A. Приложение занимается лишь потоком и не требует librkisp.so; стандартные v4l2src/VLC получают корректное изображение.

4.1 rkisp_3A_server

Состоит из драйвера RKISP1, camera_engine_rkisp и скриптов запуска. В соответствующем SDK интеграция по умолчанию включает: RKISP1 v0.1.5+ (версия в kernel/drivers/media/platform/rockchip/isp1/version.h); camera_engine_rkisp v2.2.0+ в external/camera_engine_rkisp; скрипты сборки/автозапуска в buildroot/package/rockchip/camera_engine_rkisp. Результаты сборки:

/usr/bin/rkisp_3A_server
/usr/lib/librkisp.so
/usr/lib/librkisp_api.so
/usr/lib/rkisp/
      ├── ae
      │ └── librkisp_aec.so
      ├── af
      │ └── librkisp_af.so
      └── awb
        └── librkisp_awb.so
/etc/iqfiles/
/etc/init.d/S40rkisp_3A

Примечания:

rkisp_3A_server — программа мониторинга и запуска 3A по необходимости. librkisp.so реализует основные API и вызывает закрытые библиотеки aec/af/awb. iqfiles хранит IQ XML сенсоров. S40rkisp_3A запускает сервер при загрузке. В Debian Rockchip логика аналогична, отличается способ запуска.

4.2 Журнал rkisp_3A_server

Задайте переменную среды; пример AEC:

# export persist_camera_engine_log=0x40

Добавьте строку в /etc/init.d/S40rkisp_3A; журнал идёт в /var/log/messages. При ротации появляются messages.0/messages.1; при сборе захватывайте все файлы:

# tar zcvf /tmp/camera-log.tar.gz /var/log/messages*

Выбор модуля журнала:

bits: 31-28 27-24 23-20 19-16 15-12 11-8 7-4 3-0
module: [u]  [u]  [xcore] [ISP] [AF] [AWB] [AEC] [NO]
   *[u] means unused now.
each module log has following ascending levels:
   0: error
   1: warning
   2: info
   3: verbose
   4: debug
   5: low1
   6-7: unused, now the same as debug

При ручном запуске rkisp_3A_server с журналом перенаправляйте вывод в файл: его слишком много для медленного последовательного порта или стандартного вывода shell.

# /etc/init.d/S40rkisp_3A stop
# export persist_camera_engine_log=0x40
# /usr/bin/rkisp_3A_server --mmedia=/dev/media0 > /tmp/log 2>&1

Сначала остановите сервис, задайте окружение, затем запустите сервер вручную с перенаправлением в /tmp/log.

Техническая схема оригинала · EN PDF p.24

4.3 Ускорение загрузки XML

Для быстрого старта изображения доступно ускорение XML. Включите опцию:

# make menuconfig

│ │ --- Rockchip BSP packages                    │ │
│ │ [*] Rockchip Camera Engine for linux               │ │
│ │ [*] Rockchip Camera Engine 3A service run in booting       │ │
│ │   Specify a directory to store xml speed up bin (disabled) ---> │ │
│ │ ()  Rockchip Camera Engine IQ xml file             │ │

Выберите Specify a directory to store xml speed up bin с учётом возможности записи rootfs.

│ │       (X) disabled             │ │
│ │       ( ) /etc/iqfiles-db          │ │
│ │       ( ) /userdata/iqfiles-db        │ │

При read-only rootfs выбирайте /userdata/iqfiles-db. Каталог двоичного кэша XML должен находиться на доступной для записи ФС.

4.4 Последовательность rkisp_3A_server

Диаграмма последовательности:

Участники: userspace_app, kernel_rkisp1_driver, rkisp_3A_server, 3A_Tunning_Thread. Приложение начинает захват.

Последовательность: захват → RAW требует 3A → запуск потока настройки → успешный запуск → сообщение/тайм-аут возобновляет захват; непрерывные изображения и настройка; конец захвата → готовность к выходу → выход потока → настройка завершена → сообщение/тайм-аут завершает захват.

Подготовка к завершению; завершение потока настройки; настройка завершена; после сообщения потока или тайм-аута завершается захват.

Участники: userspace_app, kernel_rkisp1_driver, rkisp_3A_server, 3A_Tunning_Thread.

5. Разработка приложений

Кроме v4l2-ctl/GStreamer/VLC можно написать V4L2-приложение для захвата и обработки. Связавшись с librkisp.so, оно получает ручное управление экспозицией/gain, веса экспозиции и точечный замер, статистику средней яркости областей/гистограмму всего кадра, управление максимальным fps/gain. При таком подходе сначала остановите rkisp_3A_server: инициализация и запуск 3A выполняются самим приложением.

# /etc/init.d/S40rkisp_3A stop

Либо непосредственно удалите S40rkisp_3A.

# rm /etc/init.d/S40rkisp_3A

5.1 Интерфейс librkisp_api.so

camera_engine_rkisp предоставляет rkisp_api в librkisp_api.so для прямого вызова или как пример. Основные API объявлены в rkisp_api.h. Пример 1: открытие и захват 1920x1080.

int test_capture_mmap_quick()
{
  const struct rkisp_api_ctx *ctx;
  const struct rkisp_api_buf *buf;
  int count = 10;

  ctx = rkisp_open_device("/dev/video1", 0);
  if (ctx == NULL)
   return -1;

  rkisp_set_fmt(ctx, 1920, 1080, ctx->fcc);

  if (rkisp_start_capture(ctx))
   return -1;

  do {
   buf = rkisp_get_frame(ctx, 0);
   /* Deal with the buffer */

   rkisp_put_frame(ctx, buf);
  } while (count--);

  rkisp_stop_capture(ctx);
  rkisp_close_device(ctx);

  return 0;
}

В этом примере 3A всё ещё выполняет rkisp_3A_server. Для доступа к дополнительной статистике измените параметр открытия:

ctx = rkisp_open_device("/dev/video1", 1);

Полученный buf содержит дополнительную статистику. Пример 2: изменить выход OV5695 на 1920x1080.

const struct rkisp_api_ctx *ctx;

ctx = rkisp_open_device("/dev/video1", 0);
if (ctx == NULL)
  return -1;
rkisp_set_sensor_fmt(ctx, 1920, 1080, MEDIA_BUS_FMT_SBGGR10_1X10);

5.2 Общая память DMA Buffer

Общий буфер сокращает копирование между Camera/RGA/DRM/MPP. По умолчанию rkisp_api выделяет память ядра через mmap и может экспортировать её как DMA Buffer другим модулям. Также принимает их буферы и заполняет кадром сразу целевой буфер, избегая копии. Пример 1: экспорт MMAP-буфера.

const struct rkisp_api_ctx *ctx;
const struct rkisp_api_buf *buf;

ctx = rkisp_open_device("/dev/video1", 0);
if (ctx == NULL || rkisp_start_capture(ctx))
  return -1;

rkisp_get_frame(ctx, 0);
printf("size: %d, dmabuf fd: %d\n", buf->size, buf->fd);

buf->fd — дескриптор DMA Buffer для других модулей. Пока они используют данные, нельзя вызывать rkisp_put_frame(); после использования обязательно вызовите его. Пример 2: заполнение буфера другого модуля напрямую данными камеры.

int test_capture_ext_dmabuf()
{
  ctx = rkisp_open_device("/dev/video1", 0);
  if (ctx == NULL)
   return -1;

  for (i = 0, ret = 0; i < buf_count; i++) {
   if (drmGetBuffer(dev.drm_fd, width, height, FORMAT, &buf[i]))
     goto out;
   dmabuf_fd[i] = buf[i].dmabuf_fd;
  }
  rkisp_set_fmt(ctx, width, height, ctx->fcc);
  rkisp_set_buf(ctx, buf_count, dmabuf_fd, buf[0].size);

  if (rkisp_start_capture(ctx))
   goto out;

  buf = rkisp_get_frame(ctx, 0);
  printf("The ext buf fd is: %d\n", buf->fd);
  rkisp_put_frame(ctx, buf);

  rkisp_stop_capture(ctx);

out:
  while (--i >= 0)
   drmPutBuffer(dev.drm_fd, &buf[i]);

  rkisp_close_device(ctx);
}

rkisp_set_buf() передаёт камере DMA Buffer, выделенный DRM. Здесь показан API rkisp; подробности drmGetBuffer()/drmPutBuffer() опущены в оригинале.

5.3 Веса экспозиции областей

Глобальная экспозиция иногда не оптимальна. Увеличение веса важной области повышает её яркость, но другие области могут стать пересвеченными или тёмными. Пример: распознавание лица против света без HDR — после обнаружения лица увеличьте вес этой области.

Другой пример — робот-пылесос распознаёт предметы на полу. Нижняя часть важнее, а отражения создают разницу яркости сверху/снизу; увеличьте вес нижней части. Вызов API:

unsigned char weights[] = {
  1, 1, 5, 9, 15, 31, 15, 5, 1,
  1, 1, 5, 9, 15, 31, 15, 5, 1,
  1, 1, 5, 9, 15, 31, 15, 5, 1,
  1, 1, 5, 9, 15, 31, 15, 5, 1,
  1, 1, 5, 9, 15, 31, 15, 5, 1,
  1, 1, 5, 9, 15, 31, 15, 5, 1,
  1, 1, 5, 9, 15, 31, 15, 5, 1,
  1, 1, 5, 9, 15, 31, 15, 5, 1,
  1, 1, 5, 9, 15, 31, 15, 5, 1,
};
rkisp_set_expo_weights(ctx, weights, 81);

Массив 9×9 задаёт веса 81 области; диапазон каждого элемента [1, 31], большее значение означает больший вес.

5.4 UVC-камера через librkuvc.so

SDK включает librkuvc.so, исходники external/uvc_app. Полученные кадры сжимаются и передаются ПК. Пример:

#include "uvc_control.h"
#include "uvc_video.h"

int test_uvc_mmap()
{
  const struct rkisp_api_ctx *ctx;
  const struct rkisp_api_buf *buf;
  uint32_t flags = 0;
  int extra_cnt = 0;

  ctx = rkisp_open_device("/dev/video1", 0);

  if (ctx == NULL)
   return -1;

  if (rkisp_set_fmt(ctx, 640, 480, V4L2_PIX_FMT_NV12))
   return -1;

  if (rkisp_start_capture(ctx))
   return -1;
  flags = UVC_CONTROL_LOOP_ONCE;
  uvc_control_run(flags);

  do {
   buf = rkisp_get_frame(ctx, 0);
   extra_cnt++;
   uvc_read_camera_buffer(buf->buf, buf->fd, buf->size, &extra_cnt, sizeof(extra_cnt));

   rkisp_put_frame(ctx, buf);
  } while (1);

  uvc_control_join(flags);

  rkisp_stop_capture(ctx);
  rkisp_close_device(ctx);

  return 0;
}

Память выделяет драйвер камеры; DMA Buffer передаётся UVC-кодированию.

# GCC=buildroot/output/rockchip_rk3326_64/host/bin/aarch64-buildroot-linux-gnu-gcc
# SYSROOT=buildroot/output/rockchip_rk3326_64/staging
# ENGINE=external/camera_engine_rkisp
# $GCC --sysroot=$SYSROOT camera_uvc.c \
   -L$ENGINE/build/lib/ -lrkisp -lrkisp_api \
   -L $SYSROOT/usr/lib/ -lrkuvc \
   -I $SYSROOT/usr/include/uvc/ \
   -I./ \
   -o camera_uvc

Соберите camera_uvc, скопируйте в /usr/bin и запустите на плате:

# /usr/bin/uvc_MJPEG.sh
# /usr/bin/camera_uvc

uvc_MJPEG.sh достаточно инициализировать один раз после загрузки. Поддерживаются 640x480, 1280x720, 1920x1080, 2560x1440; актуальный список в /usr/bin/uvc_MJPEG.sh. MPP требует высоту буфера, кратную 16, иначе возможен выход за границы памяти.

6. Драйвер RKISP1

Код в drivers/media/platform/rockchip/isp1. На основе V4L2/Media Framework он настраивает оборудование, обрабатывает прерывания, управляет буферами и питанием подустройств MIPI DPHY/сенсоров. Файлы:

# tree drivers/media/platform/rockchip/isp1/
drivers/media/platform/rockchip/isp1/
├── capture.c  #Contains the configuration of mp/sp and vb2, frame interrupt processing
├── dev.c   #Include probe, sensor registration, clock, pipeline, iommu
├── isp_params.c #3A Related parameter settings
├── isp_stats.c #3A related statistics
├── regs.c   #register related read and write operations
├── rkisp1.c  #corresponding to rkisp-isp-sd entity, including receiving data from mipi/dvp and crop
function

MIPI DPHY в drivers/phy/rockchip/phy-rockchip-mipi-rx.c также является V4L2 subdevice. Ниже связи от сенсора до выходов ISP.

Техническая схема оригинала · EN PDF p.31

Приложение userspace.

MP: видеоустройство Main Path; SP: видеоустройство Self Path; у каждого интерфейс памяти.

Масштабирование MpOutResize / SpOutResize.

Входное кадрирование Main Path / Self Path.

Isp Sub Device и выходное кадрирование ISP Out Crop.

Входное кадрирование ISP In Crop.

Входы DVP Sensor и MIPI DPHY.

MIPI Sensor A / MIPI Sensor B.

RKISP1 поддерживает DVP/MIPI, для MIPI нужен DPHY. Можно подключить несколько сенсоров, но активен только один. Одно входное изображение разделяется на MP/SP, обрабатывается каждым и может выводиться одновременно. MP выдаёт полное разрешение до 4416x3312, YUV или RAW; только MP поддерживает RAW.

SP ограничен 1920x1080, выдаёт YUV/RGB, не RAW. Crop/resize MP и SP независимы. Сравнение:

Устройство вывода Макс. разрешение Форматы Кадрирование/масштаб
SP 1920x1080 YUV, RGB Поддерживается
MP 4416x3312 YUV, RAW Поддерживается

rkisp1-input-params и rkisp1-statistics предназначены для 3A. rkisp1_rawpath/rkisp1_dmapath используются в специальных случаях, обычно не нужны приложению.

6.1 Конфигурация RKISP1 в DTS платы

SDK уже определяет узлы для поддерживаемых SoC: rkisp1 в rk3288-rkisp1.dtsi, rkisp1_0/rkisp1_1 в rk3399.dtsi. Таблица:

Чип Узел DTS MIPI DPHY IOMMU
RK3399 rkisp1_0 mipi_dphy_rx0 isp0_mmu
RK3399 rkisp1_1 mipi_dphy_tx1rx1 isp1_mmu
RK3288 rkisp1 mipi_phy_rx0 or mipi_phy_tx1rx1 isp_mmu
PX30/RK3326 rkisp1 mipi_dphy_rx0 isp_mmu
RK1808 rkisp1 mipi_dphy_rx isp_mmu

RK3399 имеет два ISP с отдельными DPHY/MMU. RK3288 имеет один ISP, DPHY можно выбрать rx0 либо tx1rx1. На плате включите нужные узлы и свяжите remote-endpoint. Пример arch/arm64/boot/dts/rockchip/rk3326-evb-lp3-v10-linux.dts: sensor, mipi_dphy_rx0, rkisp1, isp_mmu. Для MIPI параметры data-lane сенсора и mipi_dphy_rx0 должны быть одинаковыми и правильными.

7. Драйвер RKCIF

TODO — раздел не заполнен в оригинале.

Различия кода оригиналов

Основной текст соответствует языку оригинала; RU/DE переведены с EN. Ниже сохранены отличающиеся фрагменты другого оригинала, включая комментарии/разметку. Это независимые примеры, не единый исполняемый сценарий; параметры источника не подменены.

CN PDF p.6 · 13

static int __ov5695_power_on(struct ov5695 *ov5695)
{
  int ret;
  u32 delay_us;
  struct device *dev = &ov5695->client->dev;

  ret = clk_set_rate(ov5695->xvclk, OV5695_XVCLK_FREQ);

  if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ)
   dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
  ret = clk_prepare_enable(ov5695->xvclk);

  if (!IS_ERR(ov5695->reset_gpio))
   gpiod_set_value_cansleep(ov5695->reset_gpio, 1);

  ret = regulator_bulk_enable(OV5695_NUM_SUPPLIES, ov5695->supplies);

  if (!IS_ERR(ov5695->reset_gpio))
   gpiod_set_value_cansleep(ov5695->reset_gpio, 0);

  if (!IS_ERR(ov5695->pwdn_gpio))
   gpiod_set_value_cansleep(ov5695->pwdn_gpio, 1);

  /* 8192 cycles prior to first SCCB transaction */
  delay_us = ov5695_cal_delay(8192);
  usleep_range(delay_us, delay_us * 2);

  return 0;
}

CN PDF p.8 · 28

ov5695: ov5695@36 {
  compatible = "ovti,ov5695";
  reg = <0x36>;

  clocks = <&cru SCLK_CIF_OUT>;
  clock-names = "xvclk";

  avdd-supply = <&vcc2v8_dvp>;
  dovdd-supply = <&vcc1v8_dvp>;
  dvdd-supply = <&vdd1v5_dvp>;

  /*reset-gpios = <&gpio2 14 GPIO_ACTIVE_HIGH>;*/
  pwdn-gpios = <&gpio2 14 GPIO_ACTIVE_HIGH>;

  rockchip,camera-module-index = <0>;
  rockchip,camera-module-facing = "back";
  rockchip,camera-module-name = "TongJu";
  rockchip,camera-module-lens-name = "CHT842-MD";

  port {
   ucam_out: endpoint {
     remote-endpoint = <&mipi_in_ucam>;

CN PDF p.9 · 29

     data-lanes = <1 2>;
   };
  };
};

CN PDF p.10 · 45

# grep -rn LIBV4L_UTILS -- buildroot/configs/rockchip/camera.config
BR2_PACKAGE_LIBV4L_UTILS=y

CN PDF p.11 · 56

[root@rk3326_64:/]# media-ctl -p -d /dev/media1
- entity 9: irs16x5c 1-003d (1 pad, 1 link)
     type V4L2 subdev subtype Sensor flags 0
     device node name /dev/v4l-subdev2
   pad0: Source
       [fmt:SBGGR12_1X12/224x1557@10000/300000 field:none]
       -> "rockchip-mipi-dphy-rx":0 [ENABLED,DYNAMIC]

- entity 10: irs16x5c 2-003d (1 pad, 1 link)
      type V4L2 subdev subtype Sensor flags 0
      device node name /dev/v4l-subdev3
   pad0: Source
       [fmt:SBGGR12_1X12/224x1557@10000/300000 field:none]
       -> "rockchip-mipi-dphy-rx":0 [DYNAMIC]

CN PDF p.16 · 103

# v4l2-ctl -d /dev/video3 --set-ctrl 'exposure=1216,analogue_gain=10'

CN PDF p.16 · 106

# media-ctl -d /dev/media0 \
  --set-v4l2 '"ov5695 7-0036":0[fmt:SBGGR10_1X10/2592x1944]'
# media-ctl -d /dev/media0 \
  --set-v4l2 '"rkisp1-isp-subdev":0[fmt:SBGGR10_1X10/2592x1944]'
# media-ctl -d /dev/media0 \
  --set-v4l2 '"rkisp1-isp-subdev":0[crop:(0,0)/2592x1944]'
# media-ctl -d /dev/media0 \
  --set-v4l2 '"rkisp1-isp-subdev":2[fmt:SBGGR10_1X10/2592x1944]'
# media-ctl -d /dev/media0 \
  --set-v4l2 '"rkisp1-isp-subdev":2[crop:(0,0)/2592x1944]'
# v4l2-ctl -d /dev/video4 \
  --set-ctrl 'exposure=1216,analogue_gain=10' \
  --set-selection=target=crop,top=0,left=0,width=2592,height=1944 \
  --set-fmt-video=width=2592,height=1944,pixelformat=BG10 \
  --stream-mmap=3 \
  --stream-to=/tmp/mp.raw.out \
  --stream-count=1 \
  --stream-poll

CN PDF p.24 · 182

int test_capture_mmap_quick()
{
  const struct rkisp_api_ctx *ctx;
  const struct rkisp_api_buf *buf;
  int count = 10;

  ctx = rkisp_open_device("/dev/video1", 0);
  if (ctx == NULL)
   return -1;

  rkisp_set_fmt(ctx, 1920, 1080, ctx->fcc);

  if (rkisp_start_capture(ctx))
   return -1;

  do {
   buf = rkisp_get_frame(ctx, 0);

   /* Deal with the buffer */

   rkisp_put_frame(ctx, buf);
  } while (count--);

  rkisp_stop_capture(ctx);
  rkisp_close_device(ctx);

  return 0;
}

CN PDF p.25 · 191

int test_capture_ext_dmabuf()
{
  ctx = rkisp_open_device("/dev/video1", 0);
  if (ctx == NULL)
   return -1;

  for (i = 0, ret = 0; i < buf_count; i++) {
   if (drmGetBuffer(dev.drm_fd, width, height, FORMAT, &buf[i]))
     goto out;
   dmabuf_fd[i] = buf[i].dmabuf_fd;
  }
  rkisp_set_fmt(ctx, width, height, ctx->fcc);
  rkisp_set_buf(ctx, buf_count, dmabuf_fd, buf[0].size);

  if (rkisp_start_capture(ctx))
   goto out;

  buf = rkisp_get_frame(ctx, 0);
  printf("The ext buf fd is: %d\n", buf->fd);
  rkisp_put_frame(ctx, buf);

  rkisp_stop_capture(ctx);

out:
  while (--i >= 0)
   drmPutBuffer(dev.drm_fd, &buf[i]);

CN PDF p.26 · 192

  rkisp_close_device(ctx);
}

CN PDF p.26 · 200

#include "uvc_control.h"
#include "uvc_video.h"

int test_uvc_mmap()
{
  const struct rkisp_api_ctx *ctx;
  const struct rkisp_api_buf *buf;

CN PDF p.27 · 201

  uint32_t flags = 0;
  int extra_cnt = 0;

  ctx = rkisp_open_device("/dev/video1", 0);

  if (ctx == NULL)
   return -1;

  if (rkisp_set_fmt(ctx, 640, 480, V4L2_PIX_FMT_NV12))
   return -1;

  if (rkisp_start_capture(ctx))
   return -1;

  flags = UVC_CONTROL_LOOP_ONCE;
  uvc_control_run(flags);

  do {
   buf = rkisp_get_frame(ctx, 0);
   extra_cnt++;
   uvc_read_camera_buffer(buf->buf, buf->fd, buf->size, &extra_cnt, sizeof(extra_cnt));

   rkisp_put_frame(ctx, buf);
  } while (1);

  uvc_control_join(flags);

  rkisp_stop_capture(ctx);
  rkisp_close_device(ctx);

  return 0;
}

CN PDF p.28 · 210

# tree drivers/media/platform/rockchip/isp1/
drivers/media/platform/rockchip/isp1/
├── capture.c  #包含 mp/sp 的配置及 vb2,帧中断处理
├── dev.c   #包含 probe、Sensor注册、clock、pipeline、iommu
├── isp_params.c #3A 相关参数设置
├── isp_stats.c #3A 相关统计
├── regs.c   #寄存器相关的读写操作
├── rkisp1.c  #对应 rkisp-isp-sd entity,包含从mipi/dvp接收数据及crop功能

Другие статьи по теме → · Учебные маршруты →