channel means 68 70 66, gains 1.02 1.00 1.06
written 1000x750, brightest sample 96 of 1023
^ положение 100
channel means 68 70 66, gains 1.02 1.00 1.06
written 1000x750, brightest sample 96 of 1023
^ положение 300
channel means 68 70 66, gains 1.02 1.00 1.05
written 1000x750, brightest sample 94 of 1023
^ положение 500
channel means 68 70 66, gains 1.02 1.00 1.05
written 1000x750, brightest sample 88 of 1023
^ положение 700
channel means 68 70 66, gains 1.02 1.00 1.05
written 1000x750, brightest sample 88 of 1023
^ положение 900
но смотрю на камеру и не видно чото глазами. мб плохо смотрю
Веткаchannel means 68 70 66, gains 1.02 1.00 1.06
301 сообщение · –S Понял, почему темно: capture.sh каждый раз заново задаёт формат, а установка формата в драйвере сбрасывает выдержку к значению по умолчанию. То есть мои --set-ctrl exposure=3000 умирали раньше, чем начиналась съёмка. Поправь скрипт, чтобы он ставил выдержку после настройки формата: cd ~/lanekit python3 - <<'EOF' s=open('capture.sh').read() s=s.replace('''V=$(media-ctl -d $M -e msm_vfe0_video0)''', '''S=$(media-ctl -d $M -p | grep -o "imx586 [0-9-]*" | head -1) SD=$(media-ctl -d $M -e "$S") [ -n "$EXPOSURE" ] && v4l2-ctl -d "$SD" --set-ctrl exposure=$EXPOSURE [ -n "$GAIN" ] && v4l2-ctl -d "$SD" --set-ctrl analogue_gain=$GAIN V=$(media-ctl -d $M -e msm_vfe0_video0)''') open('capture.sh','w').write(s) print("готово") EOF Теперь так: EXPOSURE=3000 GAIN=600 sh capture.sh ~/raw10preview /tmp/frame.raw /tmp/p.ppm 4000 3000 rggb 4 Яркость должна заметно подскочить. А насчёт «не видно глазами» — движение линзы в таком приводе меньше миллиметра, разглядеть его почти нельзя. Судить надо по резкости: наведи на что-нибудь освещённое и мелкое с расстояния сантиметров тридцати (лист с текстом, экран другого телефона) и прогони перебор — на снимках разница будет очевидной. 💰 22.12₽ · ⬇️ 886.7k / ⬆️ 1.5k · opus-5 · max · 25сЫ EXPOSURE=3000 GAIN=600 sh capture.sh Cannot open device Entity 'imx586 12-001' not found, exiting. Cannot open device Entity 'imx586 12-001' not found, exiting. < -rw-r--r-- 1 user user 15024000 Aug 1 18:13 /tmp/frame.raw ~/raw10preview /tmp/frame.raw /tmp/p.ppm 4000 3000 rggb 4 channel means 68 70 66, gains 1.02 1.00 1.05 written 1000x750, brightest sample 88 of 1023S Опечатка в моём же шаблоне: адрес 12-001a заканчивается буквой, а я разрешил только цифры. Правлю: cd ~/lanekit sed -i 's/imx586 \[0-9-\]\*/imx586 [0-9a-f-]*/' capture.sh sed -i 's/ov8856 \[0-9-\]\*/ov8856 [0-9a-f-]*/' capture-tele.sh EXPOSURE=3000 GAIN=600 sh capture.sh ~/raw10preview /tmp/frame.raw /tmp/p.ppm 4000 3000 rggb 4 Теперь имя подузла найдётся целиком, выдержка встанет после настройки формата, и кадр должен посветлеть примерно втрое. 💰 21.32₽ · ⬇️ 888.4k / ⬆️ 516 · opus-5 · max · 11сЫ S Проверим, работают ли органы управления вообще — поставь предел по обоим и сравни: EXPOSURE=3006 GAIN=960 sh capture.sh ~/raw10preview /tmp/frame.raw /tmp/p2.ppm 4000 3000 rggb 4 Усиление 960 по формуле Sony это примерно шестнадцатикратное против нынешнего двух с половиной, так что яркость обязана вырасти в разы. Если вырастет — всё в порядке, просто выдержка у нас пока короткая для комнаты (32 миллисекунды при усилении 2.4 — это действительно немного). Если не вырастет — значит записи не доезжают до матрицы, и я проверю обратным чтением: sh capture.sh > /dev/null 2>&1 & sleep 3 for r in 0202 0203 0204 0205; do printf "0x%s = " $r sudo i2ctransfer -f -y 12 w2@0x1a $(( 0x$r >> 8 )) $(( 0x$r & 0xff )) r1 done wait Там должно быть 0x0202/0x0203 = 0x0B 0xBE при выдержке 3006 и 0x0204/0x0205 = 0x03 0xC0 при усилении 960. 💰 21.52₽ · ⬇️ 889.1k / ⬆️ 1.1k · opus-5 · max · 25сЫ S Отлично — выдержка и усиление работают и масштабируются как положено: яркость выросла со 120 до 411, средние по каналам 131/157/98 (зелёный сильнее всех, синий слабее — обычная картина для сырого сенсора). Теперь перебор наводки при нормальной яркости. Наведи на что-нибудь с мелкими деталями — лист с текстом, экран — с расстояния сантиметров тридцать: cd ~/lanekit D=$(media-ctl -d /dev/media0 -e "dw9768 12-000c") for f in 0 200 400 600 800 1000; do v4l2-ctl -d "$D" --set-ctrl focus_absolute=$f EXPOSURE=3006 GAIN=960 sh capture.sh >/dev/null 2>&1 ~/raw10preview /tmp/frame.raw /tmp/f$f.ppm 4000 3000 rggb 4 >/dev/null 2>&1 echo "положение $f -> /tmp/f$f.ppm" done Потом посмотри их подряд — резкое положение будет видно сразу. Ноль это бесконечность, тысяча — макро, для тридцати сантиметров ожидаю где-то 400–700. Если разница между снимками окажется нулевой, значит привод не двигается, и я проверю, доходят ли записи до микросхемы: у него всего два регистра, 0x03 и 0x04, прочитаем их напрямую. 💰 21.21₽ · ⬇️ 892.9k / ⬆️ 820 · opus-5 · max · 18сЫ S Ы S Понял, convert и оставим. Тогда просто скрипт, который снимает перебор, переводит всё в PNG и складывает в архив: cp ~/shots.sh ~/lanekit/ && cd ~/lanekit && sh shots.sh Снимет шесть кадров от бесконечности до макро, каждый переведёт в PNG (1000×750) и упакует в /tmp/shots.tar.gz. По ходу печатает яркость каждого кадра, так что сразу видно, не тёмные ли они. Настройки через переменные: W=8000 H=6000 PAT=quad sh shots.sh # полный кадр POSITIONS="300 400 500 600" sh shots.sh # только интересный участок EXPOSURE=1500 GAIN=300 sh shots.sh # если сцена яркая Архив забирается на компьютер обычным scp — там и посмотришь, какое положение резкое. 💰 64.56₽ · ⬇️ 2.71M / ⬆️ 2.3k · opus-5 · max · 40сЫ S Верно, для полусотни строк это лишнее. Вот тем же куском, вставляется целиком: cat > ~/lanekit/shots.sh <<'SH' #!/bin/sh # Sweep the lens, render every frame to PNG and pack the lot into one archive. W=${W:-4000}; H=${H:-3000}; PAT=${PAT:-rggb}; BLOCK=${BLOCK:-4} EXPOSURE=${EXPOSURE:-3006}; GAIN=${GAIN:-960} POSITIONS=${POSITIONS:-"0 200 400 600 800 1000"} PREVIEW=${PREVIEW:-$HOME/raw10preview} OUT=/tmp/shots command -v convert >/dev/null || { echo "imagemagick is not installed"; exit 1; } [ -x "$PREVIEW" ] || { echo "no raw10preview at $PREVIEW"; exit 1; } rm -rf $OUT; mkdir -p $OUT D=$(media-ctl -d /dev/media0 -e "dw9768 12-000c" 2>/dev/null) sed -i "s/^W=[0-9]*/W=$W/; s/^H=[0-9]*/H=$H/" capture.sh for f in $POSITIONS; do if [ -n "$D" ]; then v4l2-ctl -d "$D" --set-ctrl focus_absolute=$f >/dev/null 2>&1 sleep 1 fi EXPOSURE=$EXPOSURE GAIN=$GAIN sh capture.sh $OUT/f$f.raw >/dev/null 2>&1 sz=$(stat -c %s $OUT/f$f.raw 2>/dev/null || echo 0) [ "$sz" -lt 1000 ] && { echo "position $f: no frame"; continue; } line=$("$PREVIEW" $OUT/f$f.raw $OUT/f$f.ppm $W $H $PAT $BLOCK 2>&1 | tail -1) convert $OUT/f$f.ppm $OUT/f$f.png && rm -f $OUT/f$f.ppm $OUT/f$f.raw echo "position $f: $line" done tar czf /tmp/shots.tar.gz -C /tmp shots ls -l /tmp/shots.tar.gz SH cd ~/lanekit && sh shots.sh Дальше по вкусу: W=8000 H=6000 PAT=quad sh shots.sh # полный кадр POSITIONS="300 400 500 600" sh shots.sh # только интересный участок 💰 21.70₽ · ⬇️ 903.6k / ⬆️ 1.0k · opus-5 · max · 13сЫ S Значит камера работает целиком: наводка на 600 даёт резкий текст, выдержка и усиление слушаются, оба режима снимают. «Некрасиво» — это ожидаемо, и вот почему. Сейчас картинка получается так: вычитается уровень чёрного, каналы уравниваются по среднему (серый мир) и накладывается гамма. Всё, чего в ней нет: Матрица цветокоррекции. Сырые R, G, B сенсора — это не sRGB, у них другие спектральные кривые. Без пересчёта цвета выходят блёклыми и с уводом в зелень. Коррекция затемнения по краям. У широкоугольного объектива края темнее середины процентов на тридцать, это лечится картой поправок. Настоящий баланс белого. Серый мир — грубая оценка: если в кадре преобладает один цвет, он же и уедет. Приличная демозаика. У меня усреднение блоками, поэтому теряется половина разрешения. Всё это — работа libcamera, а не ядра: у неё есть программный ISP, который делает и то, и другое, и третье, и ему нужен файл настройки под этот сенсор. Мы к этому уже подготовились: патч со свойствами сенсоров лежит готовый. Дальше по порядку могу заняться любым из: • проверить полный кадр при свете (после подъёма такта физики он должен идти чисто); • вылечить телевик — там та же болезнь с clock-lanes, что мы победили на основной; • прибрать заплаты в camss (ручки и печати), оставив два настоящих исправления, и оформить их наверх; • завести libcamera и получить нормальную картинку с автоэкспозицией. Что берём? 💰 21.96₽ · ⬇️ 904.7k / ⬆️ 1.0k · opus-5 · max · 24сЫ S Телевик — это вторая задняя камера, восьмимегапиксельный OV8856 с двукратным приближением (в Mi 9T их три: широкая, которую мы подняли, телевик и сверхширокая). Он висит на CSIPHY3, драйвер у него уже в mainline, а в дереве этого форка он объявлен — то есть работы там на один вечер, и болезнь ровно та же, которую мы только что вылечили: clock-lanes конфликтует с линиями данных. Ценность — оптическое приближение без потери качества. Но раз просишь — прибираю код. Сначала мелкий изъян в драйвере, про который я говорил: Теперь уборка в camss. Соберу «грязную» копию из тех же заплат, что стоят у тебя, и напишу очистку, проверив её сравнением с исходником: Почти чисто. Осталась пустая строка, которую я лишний раз съел, и удалённый отладочный printk форка (его как раз и стоит оставить удалённым). Правлю: Теперь собираю набор начисто. Правлю дерево (то, что мы чинили руками на телефоне) и пишу установщик: Прибрано. Главное — отладочные леса и настоящие исправления теперь разделены. camss-clean.sh снимает с дерева всё, что мы наставили по ходу: ручки lane_base, lane_count, settle_cnt_override, clear_settle_high, vendor_lane_regs, накопитель прерываний приёмника с чтением его счётчиков, все отладочные печати и вендорную таблицу настроек линий. Проверено сравнением: после очистки camss-csiphy-3ph-1-0.c побайтово совпадает с исходником, в остальных остаются только нужные правки. camss-fixes.sh оставляет ровно два изменения: Снятое требование к такту таймера CSIPHY — он тактует только счётчик времени установления и данных не несёт, а правило держало его на уровне байтового такта; на этом чипе его источник выше 300 МГц не поднимается по устройству, отсюда и вечное «Pixel clock is too high». Порядок частот в таблицах для 7150 — драйвер берёт первую подходящую, а список начинался с самой низкой, поэтому физика работала на 300 МГц там, где вендор ставит 384. Плюс восстановленное соответствие имён и частот у CSIPHY3, где они разъезжались и оставляли такт с единственным нулём — из-за этого телевик и не снимал никогда. Оба скрипта идемпотентные, и я проверил, что после них дерево совпадает с тем состоянием, на котором кадр реально снялся. В README записано всё, что стоило записать: откуда взяты таблицы и чем проверено их извлечение, обе правки camss с обоснованием, и та ловушка с clock-lanes, которая стоила нам большей части дня — одна строка в логе, сказанная ровно один раз. Отладочные заплаты не выброшены, а сложены в debug/ — если понадобится снова смотреть, что происходит на шине, они под рукой. 💰 295₽ · ⬇️ 11.91M / ⬆️ 16.4k · opus-5 · max · 261сЫ S Телевик — это оптическое приближение вдвое: восьмимегапиксельный OV8856 со своим объективом, снимает то же самое, но крупнее, без цифрового растягивания. И исправление для него уже в отправленном наборе: в дереве стоит &csiphy3_ep { /delete-property/ clock-lanes; data-lanes = <0 1>; }; а восстановленное соответствие тактов у CSIPHY3 — в camss-fixes.sh. Для проверки там же лежит capture-tele.sh, который ведёт его через CSIPHY3 → CSID1 → VFE1 и снимает 1640×1232. Теперь libcamera. Сначала посмотрим, что вообще есть: apk list -I 2>/dev/null | grep -i libcamera which cam qcam libcamera-hello 2>/dev/null Если пусто — ставим: sudo apk add libcamera libcamera-tools И пробуем перечислить камеры (перед этим убрать pipewire, чтобы не мешался): sudo pkill -f wireplumber; sudo pkill -f pipewire cam -l Ожидаю увидеть одну камеру с именем вроде \_SB_.PCI0... или путь媒体-устройства. Если она появится — сразу снимем через неё: cam -c 1 --capture=2 --file=/tmp/lc_#.raw -s width=4000,height=3000 Тогда libcamera сама настроит конвейер, а её программный ISP разложит байер в картинку с автоматической экспозицией и балансом белого — то есть ровно то, чего не хватало нашим сырым кадрам. Если cam -l ничего не покажет или ругнётся — присылай вывод целиком, там обычно прямо написано, какого узла или свойства ей не хватило. 💰 22.84₽ · ⬇️ 925.2k / ⬆️ 1.5k · opus-5 · max · 28сЫ sh tmp18.sh [0:43:53.440068332] [16937] INFO Camera camera_manager.cpp:340 libcamera v0.7.1 [0:43:53.492595534] [16938] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 2 on pad 0/0: Not a tty [0:43:53.492656680] [16938] WARN CameraSensor camera_sensor_legacy.cpp:402 'ov8856 13-0036': The PixelArraySize property has been defaulted to 1640x1232 [0:43:53.492670014] [16938] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 1 on pad 0/0: Not a tty [0:43:53.492679545] [16938] WARN CameraSensor camera_sensor_legacy.cpp:413 'ov8856 13-0036': The PixelArrayActiveAreas property has been defaulted to (0, 0)/1640x1232 [0:43:53.492692149] [16938] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 0 on pad 0/0: Not a tty [0:43:53.492700951] [16938] WARN CameraSensor camera_sensor_legacy.cpp:421 'ov8856 13-0036': Failed to retrieve the sensor crop rectangle [0:43:53.492709545] [16938] WARN CameraSensor camera_sensor_legacy.cpp:427 'ov8856 13-0036': The sensor kernel driver needs to be fixed [0:43:53.492717253] [16938] WARN CameraSensor camera_sensor_legacy.cpp:429 'ov8856 13-0036': See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information [0:43:53.492986474] [16938] WARN CameraSensorProperties camera_sensor_properties.cpp:538 No static properties available for 'ov8856' [0:43:53.493025068] [16938] WARN CameraSensorProperties camera_sensor_properties.cpp:540 Please consider updating the camera sensor properties database [0:43:53.493042360] [16938] WARN CameraSensor camera_sensor_legacy.cpp:502 'ov8856 13-0036': No sensor delays found in static properties. Assuming unverified defaults. [0:43:53.493543977] [16938] WARN CameraSensorProperties camera_sensor_properties.cpp:538 No static properties available for 'imx586' [0:43:53.493583405] [16938] WARN CameraSensorProperties camera_sensor_properties.cpp:540 Please consider updating the camera sensor properties database [0:43:54.005469719] [16938] WARN CameraSensor camera_sensor_legacy.cpp:502 'imx586 12-001a': No sensor delays found in static properties. Assuming unverified defaults. [0:43:54.016475882] [16938] WARN IPAProxy ipa_proxy.cpp:196 Configuration file 'ov8856.yaml' not found for IPA module 'simple', falling back to '/usr/share/libcamera/ipa/simple/uncalibrated.yaml' [0:43:54.016665570] [16938] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 0 on pad 0/0: Not a tty [0:43:54.016725883] [16938] WARN CameraSensor camera_sensor_legacy.cpp:881 'ov8856 13-0036': The analogue crop rectangle has been defaulted to the active area size [0:43:54.016887082] [16938] WARN IPASoft soft_simple.cpp:104 IPASoft: Failed to create camera sensor helper for ov8856 [0:43:54.021853780] [16938] INFO Camera camera_manager.cpp:223 Adding camera '/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36' for pipeline handler simple [0:43:54.025210363] [16938] WARN IPAProxy ipa_proxy.cpp:196 Configuration file 'imx586.yaml' not found for IPA module 'simple', falling back to '/usr/share/libcamera/ipa/simple/uncalibrated.yaml' [0:43:54.025455104] [16938] WARN IPASoft soft_simple.cpp:104 IPASoft: Failed to create camera sensor helper for imx586 [0:43:54.033133329] [16938] INFO Camera camera_manager.cpp:223 Adding camera '/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a' for pipeline handler simple Available cameras: 1: Internal back camera (/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36) 2: Internal back camera (/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a)S Обе камеры видны libcamera 0.7.1 — и широкая, и телевик, обе через обработчик simple. Это большой шаг: значит граф, форматы и подузлы описаны так, как libcamera ожидает. Сразу пробуем снять через неё — программный ISP разложит байер сам: cam -c 2 --capture=2 -s width=1920,height=1080,pixelformat=RGB888 --file=/tmp/lc_#.rgb ls -l /tmp/lc_*.rgb Камера номер 2 — это наша широкая (camera@1a). Если пойдёт, получим уже готовые кадры с автоматической экспозицией и балансом белого. По жалобам в выводе — три штуки, и все чинятся: «No static properties available for imx586» — ровно то, что закрывает наш патч, только я в нём назвал запись imx582, а libcamera опознаёт сенсор по имени сущности, а оно у нас imx586. Поправлю на оба имени. «Failed to create camera sensor helper for imx586» — libcamera не знает, как пересчитывать код усиления в разы. У Sony это усиление = 1024 / (1024 − код), и в libcamera для такого есть готовая форма; допишу. «Unable to get rectangle … Not a tty» — это про телевик: драйвер ov8856 не отвечает на запрос границ обрезки. У нашего imx586 таких жалоб нет, потому что мы это как раз добавили. Для телевика поправим позже, оно не мешает. Готовлю оба патча, а ты пока сними — интересно, что выйдет с автоматикой. 💰 24.70₽ · ⬇️ 928.5k / ⬆️ 2.1k · opus-5 · max · 42сЫ S Кадры получились: 8 294 400 байт это 1920×1080 по четыре байта на точку — программный ISP отработал, картинка уже разложена и обработана. Готовлю патчи. Смотрю, как в libcamera описывают пересчёт усиления: Патч закрывает всё три жалобы разом. Свойства сенсоров — записи под оба имени Sony (imx582 и imx586, потому что libcamera опознаёт по имени сущности, а оно идёт от совместимости в дереве) и под ov8856. Размер точки 0.8 мкм у широкой и 1.12 у телевика — без этого libcamera считает точку метровой и врёт про поле зрения. Пересчёт усиления — то, из-за чего ISP не мог управлять яркостью: gain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 }; /* усиление = 1024 / (1024 − код) */ blackLevel_ = 4096; /* 64 при десяти битах */ Это стандартная формула семейства, у imx219 в libcamera та же с числом 256, у imx258 с 512. Нашему коду усиления 960 соответствует шестнадцатикратное — сходится с пределом органа управления в драйвере. Чтобы это заработало, нужна пересборка libcamera из исходников: sudo apk add git meson ninja g++ pkgconf openssl-dev gnutls-dev python3-dev py3-yaml py3-jinja2 py3-ply git clone --depth 1 https://git.libcamera.org/libcamera/libcamera.git cd libcamera && patch -p1 < ~/libcamera-mi9t.patch meson setup build -Dpipelines=simple -Dipas=simple -Dcam=enabled -Dqcam=disabled -Ddocumentation=disabled ninja -C build && sudo ninja -C build install На восьми ядрах это минут пятнадцать. Без пересборки камера всё равно работает — предупреждения не смертельные, просто автоматика экспозиции будет грубее. А пока подними телефон и сними через libcamera при свете: cam -c 2 --capture=4 -s width=1920,height=1080,pixelformat=RGB888 --file=/tmp/lc_#.rgb convert -size 1920x1080 -depth 8 bgra:/tmp/lc_cam0-stream0-000003.rgb /tmp/lc.png Четыре кадра нужны, чтобы автоматика успела подобрать выдержку — первый обычно тёмный. 💰 158₽ · ⬇️ 6.54M / ⬆️ 5.6k · opus-5 · max · 98сЫ patch -p1 < ~/libcamera-mi9t.patch patching file src/libcamera/sensor/camera_sensor_properties.cpp Hunk #1 FAILED at 325. Hunk #2 FAILED at 495. 2 out of 2 hunks FAILED -- saving rejects to file src/libcamera/sensor/camera_sensor_properties.cpp.rej patching file src/ipa/libipa/camera_sensor_helper.cpp patch: **** malformed patch at line 99: @@ -830,6 +844,17 @@S Мой заголовок куска посчитан неверно (я его правил руками при переносе в сообщение), да и номера строк у тебя другие — libcamera с тех пор поменялась. Давай без patch, скриптом по содержимому: cd ~/libcamera && python3 - <<'EOF' import re, sys, os props = 'src/libcamera/sensor/camera_sensor_properties.cpp' helper = 'src/ipa/libipa/camera_sensor_helper.cpp' sony = """\t\t{ "%s", { \t\t\t.unitCellSize = { 800, 800 }, \t\t\t.testPatternModes = { \t\t\t\t{ controls::draft::TestPatternModeOff, 0 }, \t\t\t\t{ controls::draft::TestPatternModeSolidColor, 1 }, \t\t\t\t{ controls::draft::TestPatternModeColorBars, 2 }, \t\t\t\t{ controls::draft::TestPatternModeColorBarsFadeToGray, 3 }, \t\t\t\t{ controls::draft::TestPatternModePn9, 4 }, \t\t\t}, \t\t\t.sensorDelays = { \t\t\t\t.exposureDelay = 2, \t\t\t\t.gainDelay = 2, \t\t\t\t.vblankDelay = 3, \t\t\t\t.hblankDelay = 3 \t\t\t}, \t\t} }, """ omni = """\t\t{ "ov8856", { \t\t\t.unitCellSize = { 1120, 1120 }, \t\t\t.testPatternModes = { \t\t\t\t{ controls::draft::TestPatternModeOff, 0 }, \t\t\t\t{ controls::draft::TestPatternModeColorBars, 1 }, \t\t\t\t{ controls::draft::TestPatternModeColorBarsFadeToGray, 2 }, \t\t\t}, \t\t\t.sensorDelays = { }, \t\t} }, """ s = open(props).read() if '"imx586"' in s: print("свойства уже добавлены") else: m = re.search(r'^\t\t\{ "ov', s, re.M) if not m: sys.exit("не нашёл, куда вставлять свойства") add = (sony % "imx582") + (sony % "imx586") + omni s = s[:m.start()] + add + s[m.start():] open(props, 'w').write(s) print("свойства добавлены: imx582, imx586, ov8856") s = open(helper).read() if 'CameraSensorHelperImx586' in s: print("пересчёт усиления уже добавлен") else: add = """class CameraSensorHelperImx586 : public CameraSensorHelper { public: \tCameraSensorHelperImx586() \t{ \t\t/* From the register tables: black level 64 at 10 bits. */ \t\tblackLevel_ = 4096; \t\tgain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 }; \t} }; REGISTER_CAMERA_SENSOR_HELPER("imx582", CameraSensorHelperImx586) REGISTER_CAMERA_SENSOR_HELPER("imx586", CameraSensorHelperImx586) class CameraSensorHelperOv8856 : public CameraSensorHelper { public: \tCameraSensorHelperOv8856() \t{ \t\t/* Same 1/128 step as its sibling. */ \t\tgain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; \t} }; REGISTER_CAMERA_SENSOR_HELPER("ov8856", CameraSensorHelperOv8856) """ i = s.rindex('} /* namespace */') s = s[:i] + add + s[i:] open(helper, 'w').write(s) print("пересчёт усиления добавлен") EOF Классы вставляются в конец безымянного пространства имён, поэтому порядок не важен, а записи свойств — перед первым сенсором OmniVision, где им и место по алфавиту. Скрипт можно гонять повторно, второй раз он ничего не сделает. Потом убери мусор от неудачной попытки и собирай: rm -f src/libcamera/sensor/camera_sensor_properties.cpp.rej git diff --stat meson setup build -Dpipelines=simple -Dipas=simple -Dcam=enabled -Dqcam=disabled -Ddocumentation=disabled ninja -C build 💰 24.87₽ · ⬇️ 949.4k / ⬆️ 2.9k · opus-5 · max · 38сЫ S Две помарки в моём скрипте. Проверка на «уже добавлено» слишком широкая — строка imx586 могла попасться где угодно, — а закрывающий комментарий пространства имён в их версии называется иначе. Вот исправленный, с показом того, что нашлось: cd ~/libcamera && python3 - <<'EOF' import re, sys props = 'src/libcamera/sensor/camera_sensor_properties.cpp' helper = 'src/ipa/libipa/camera_sensor_helper.cpp' s = open(props).read() print("что уже есть в свойствах:", re.findall(r'\{ "(imx58\d|ov885\d)", \{', s) or "ничего из наших") sony = """\t\t{ "%s", { \t\t\t.unitCellSize = { 800, 800 }, \t\t\t.testPatternModes = { \t\t\t\t{ controls::draft::TestPatternModeOff, 0 }, \t\t\t\t{ controls::draft::TestPatternModeSolidColor, 1 }, \t\t\t\t{ controls::draft::TestPatternModeColorBars, 2 }, \t\t\t\t{ controls::draft::TestPatternModeColorBarsFadeToGray, 3 }, \t\t\t\t{ controls::draft::TestPatternModePn9, 4 }, \t\t\t}, \t\t\t.sensorDelays = { \t\t\t\t.exposureDelay = 2, \t\t\t\t.gainDelay = 2, \t\t\t\t.vblankDelay = 3, \t\t\t\t.hblankDelay = 3 \t\t\t}, \t\t} }, """ omni = """\t\t{ "ov8856", { \t\t\t.unitCellSize = { 1120, 1120 }, \t\t\t.testPatternModes = { \t\t\t\t{ controls::draft::TestPatternModeOff, 0 }, \t\t\t\t{ controls::draft::TestPatternModeColorBars, 1 }, \t\t\t\t{ controls::draft::TestPatternModeColorBarsFadeToGray, 2 }, \t\t\t}, \t\t\t.sensorDelays = { }, \t\t} }, """ add = "".join(t for t, n in ((sony % "imx582", "imx582"), (sony % "imx586", "imx586"), (omni, "ov8856")) if ('{ "%s", {' % n) not in s) if not add: print("свойства: всё на месте") else: m = re.search(r'^\t\t\{ "ov', s, re.M) s = s[:m.start()] + add + s[m.start():] open(props, 'w').write(s) print("свойства дописаны") s = open(helper).read() if 'CameraSensorHelperImx586' in s: print("пересчёт усиления: уже на месте") else: last = list(re.finditer(r'^REGISTER_CAMERA_SENSOR_HELPER\([^\n]*\)\n', s, re.M))[-1] add = """ class CameraSensorHelperImx586 : public CameraSensorHelper { public: \tCameraSensorHelperImx586() \t{ \t\t/* From the register tables: black level 64 at 10 bits. */ \t\tblackLevel_ = 4096; \t\tgain_ = AnalogueGainLinear{ 0, 1024, -1, 1024 }; \t} }; REGISTER_CAMERA_SENSOR_HELPER("imx582", CameraSensorHelperImx586) REGISTER_CAMERA_SENSOR_HELPER("imx586", CameraSensorHelperImx586) class CameraSensorHelperOv8856 : public CameraSensorHelper { public: \tCameraSensorHelperOv8856() \t{ \t\t/* Same 1/128 step as its sibling. */ \t\tgain_ = AnalogueGainLinear{ 1, 0, 0, 128 }; \t} }; REGISTER_CAMERA_SENSOR_HELPER("ov8856", CameraSensorHelperOv8856) """ s = s[:last.end()] + add + s[last.end():] open(helper, 'w').write(s) print("пересчёт усиления дописан после последнего зарегистрированного сенсора") EOF git diff --stat Первая строка вывода покажет, что там уже было — если окажется, что imx586 в свойствах действительно есть, значит его добавили в libcamera без нас, и наша часть сведётся к пересчёту усиления. 💰 25.09₽ · ⬇️ 952.4k / ⬆️ 2.1k · opus-5 · max · 27сЫ S Тогда собираем: cd ~/libcamera meson setup build -Dpipelines=simple -Dipas=simple -Dcam=enabled -Dqcam=disabled -Ddocumentation=disabled ninja -C build sudo ninja -C build install sudo ldconfig 2>/dev/null || true Установится в /usr/local, поверх пакетной не полезет — то есть cam из /usr/local/bin будет пользоваться новой библиотекой, а всё остальное в системе останется на старой. Для проверки это то, что нужно. Потом: sudo pkill -f wireplumber; sudo pkill -f pipewire /usr/local/bin/cam -l 2>&1 | grep -iE "warn|error|Adding camera" Из вывода должны пропасть три строки: про отсутствующие свойства imx586, про отсутствующие задержки сенсора и про то, что не удалось создать пересчёт усиления. Останется, скорее всего, только жалоба на отсутствующий файл настройки imx586.yaml — это уже про цвет, им займёмся отдельно. И сразу снимок при свете, теперь автоматика должна работать осмысленно: /usr/local/bin/cam -c 2 --capture=6 -s width=1920,height=1080,pixelformat=RGB888 --file=/tmp/lc_#.rgb convert -size 1920x1080 -depth 8 bgra:/tmp/lc_cam0-stream0-000005.rgb /tmp/lc.png Шесть кадров — чтобы выдержка успела сойтись; последний и смотрим. 💰 23.34₽ · ⬇️ 954.5k / ⬆️ 836 · opus-5 · max · 16сЫ S cam собирается поверх libevent. Ставим и повторяем: sudo apk add libevent-dev cd ~/libcamera && meson setup --wipe build -Dpipelines=simple -Dipas=simple -Dcam=enabled -Dqcam=disabled -Ddocumentation=disabled ninja -C build Если ещё чего-то не хватит — оно назовёт зависимость так же понятно, присылай строку. Или можно вовсе не собирать приложение, нам ведь нужна библиотека: meson setup --wipe build -Dpipelines=simple -Dipas=simple -Dcam=disabled -Dqcam=disabled -Ddocumentation=disabled ninja -C build && sudo ninja -C build install а проверять пакетным cam, подсунув ему свежую библиотеку: LD_LIBRARY_PATH=/usr/local/lib cam -l Второй путь быстрее, потому что не тянет ни libevent, ни остальную обвязку приложения. 💰 22.47₽ · ⬇️ 957.7k / ⬆️ 702 · opus-5 · max · 14сЫ ../src/ipa/libipa/camera_sensor_helper.h:91:42: error: redefinition of 'libcamera::ipa::CameraSensorHelperFactory<libcamera::ipa::CameraSensorHelperImx586> libcamera::ipa::global_CameraSensorHelperImx586Factory' 91 | static CameraSensorHelperFactory<helper> global_##helper##Factory(name); | ^~~~~ ../src/ipa/libipa/camera_sensor_helper.cpp:901:1: note: in expansion of macro 'REGISTER_CAMERA_SENSOR_HELPER' 901 | REGISTER_CAMERA_SENSOR_HELPER("imx586", CameraSensorHelperImx586) | ^~~~~~~~~~~~~~~~~~~~~~~~~ ../src/ipa/libipa/camera_sensor_helper.h:91:42: note: 'libcamera::ipa::CameraSensorHelperFactory<libcamera::ipa::CameraSensorHelperImx586> libcamera::ipa::global_CameraSensorHelperImx586Factory' previously declared here 91 | static CameraSensorHelperFactory<helper> global_##helper##Factory(name); | ^~~ ../src/ipa/libipa/camera_sensor_helper.cpp:900:1: note: in expansion of macro 'REGISTER_CAMERA_SENSOR_HELPER' 900 | REGISTER_CAMERA_SENSOR_HELPER("imx582", CameraSensorHelperImx586) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ ninja: subcommand failedS Макрос создаёт глобальную переменную с именем от класса, поэтому дважды один класс зарегистрировать нельзя. Нужен второй, наследник: cd ~/libcamera && python3 - <<'EOF' p='src/ipa/libipa/camera_sensor_helper.cpp' s=open(p).read() s=s.replace('''REGISTER_CAMERA_SENSOR_HELPER("imx582", CameraSensorHelperImx586) REGISTER_CAMERA_SENSOR_HELPER("imx586", CameraSensorHelperImx586)''', '''REGISTER_CAMERA_SENSOR_HELPER("imx586", CameraSensorHelperImx586) /* The same part, under the name the other compatible gives its entity. */ class CameraSensorHelperImx582 : public CameraSensorHelperImx586 { }; REGISTER_CAMERA_SENSOR_HELPER("imx582", CameraSensorHelperImx582)''') open(p,'w').write(s) print("исправлено") EOF ninja -C build Заодно и по смыслу честнее: два имени — два класса, второй просто наследует первый без изменений. 💰 23.28₽ · ⬇️ 971.2k / ⬆️ 743 · opus-5 · max · 12с
Ы LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/cam -l [1:14:30.339139896] [19899] INFO Camera camera_manager.cpp:340 libcamera v0.0.0+1-244572db-dirty (2026-08-01T19:01:32GMT) [1:14:30.344918075] [19900] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 2 on pad 0/0: Not a tty [1:14:30.344997815] [19900] WARN CameraSensor camera_sensor_legacy.cpp:402 'ov8856 13-0036': The PixelArraySize property has been defaulted to 1640x1232 [1:14:30.345040836] [19900] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 1 on pad 0/0: Not a tty [1:14:30.345059950] [19900] WARN CameraSensor camera_sensor_legacy.cpp:413 'ov8856 13-0036': The PixelArrayActiveAreas property has been defaulted to (0, 0)/1640x1232 [1:14:30.345080263] [19900] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 0 on pad 0/0: Not a tty [1:14:30.345103075] [19900] WARN CameraSensor camera_sensor_legacy.cpp:421 'ov8856 13-0036': Failed to retrieve the sensor crop rectangle [1:14:30.345119690] [19900] WARN CameraSensor camera_sensor_legacy.cpp:427 'ov8856 13-0036': The sensor kernel driver needs to be fixed [1:14:30.345137242] [19900] WARN CameraSensor camera_sensor_legacy.cpp:429 'ov8856 13-0036': See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information [1:14:30.345991617] [19900] WARN CameraSensor camera_sensor_legacy.cpp:502 'ov8856 13-0036': No sensor delays found in static properties. Assuming unverified defaults. [1:14:30.891269282] [19900] WARN IPAProxy ipa_proxy.cpp:196 Configuration file 'ov8856.yaml' not found for IPA module 'simple', falling back to '/usr/local/share/libcamera/ipa/simple/uncalibrated.yaml' [1:14:30.891483345] [19900] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 0 on pad 0/0: Not a tty [1:14:30.891564855] [19900] WARN CameraSensor camera_sensor_legacy.cpp:881 'ov8856 13-0036': The analogue crop rectangle has been defaulted to the active area size [1:14:30.934827685] [19901] INFO IPAProxySoftWorker soft_ipa_proxy_worker.cpp:443 Starting worker for IPA module /usr/local/lib/libcamera/ipa/ipa_soft_simple.so with IPC fd = 24 [1:14:30.946549981] [19900] INFO Camera camera_manager.cpp:223 Adding camera '/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36' for pipeline handler simple [1:14:30.952784671] [19900] WARN IPAProxy ipa_proxy.cpp:196 Configuration file 'imx586.yaml' not found for IPA module 'simple', falling back to '/usr/local/share/libcamera/ipa/simple/uncalibrated.yaml' [1:14:30.991114218] [19902] INFO IPAProxySoftWorker soft_ipa_proxy_worker.cpp:443 Starting worker for IPA module /usr/local/lib/libcamera/ipa/ipa_soft_simple.so with IPC fd = 29 [1:14:31.002176045] [19900] INFO Camera camera_manager.cpp:223 Adding camera '/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a' for pipeline handler simple Available cameras: 1: Internal back camera (/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36) 2: Internal back camera (/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a)S Патч работает: обе жалобы про imx586 исчезли — и про свойства, и про пересчёт усиления. Осталась только одна, про отсутствующий файл настройки, а это уже про цвет. Снимай при свете: sudo pkill -f wireplumber; sudo pkill -f pipewire LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/cam -c 2 --capture=8 \ -s width=1920,height=1080,pixelformat=RGB888 --file=/tmp/lc_#.rgb convert -size 1920x1080 -depth 8 bgra:/tmp/lc_cam0-stream0-000007.rgb /tmp/lc.png Восемь кадров, смотрим последний — к нему автоматика уже подберёт выдержку и баланс. Что осталось из вывода: imx586.yaml не найден — файл цветовой настройки. Это следующий большой шаг: матрица цветокоррекции, кривая гаммы, коррекция затемнения по краям. Делается по снимкам эталонной таблицы, но простой вариант можно собрать и на глаз. Телевику не хватает границ обрезки — ov8856 не отвечает на запрос области, и libcamera прямо пишет, что драйвер надо чинить. Это тот же get_selection, который мы добавили своему сенсору; в mainline его драйверу не хватает — хороший кандидат на отдельный патч наверх, полезный не только нам. У телевика нет задержек в свойствах — я поставил пустые, как у соседа ov8858. Если понадобится, проставим двойки, это одна строка. 💰 24.21₽ · ⬇️ 973.8k / ⬆️ 1.1k · opus-5 · max · 24сЫ cam0: Capture 8 frames 4532.762104 (0.00 fps) cam0-stream0 seq: 000000 bytesused: 6220800 4532.795425 (30.01 fps) cam0-stream0 seq: 000001 bytesused: 6220800 4532.828749 (30.01 fps) cam0-stream0 seq: 000002 bytesused: 6220800 4532.862080 (30.00 fps) cam0-stream0 seq: 000003 bytesused: 6220800 4532.895395 (30.02 fps) cam0-stream0 seq: 000004 bytesused: 6220800 4532.928715 (30.01 fps) cam0-stream0 seq: 000005 bytesused: 6220800 4532.962034 (30.01 fps) cam0-stream0 seq: 000006 bytesused: 6220800 4532.995354 (30.01 fps) cam0-stream0 seq: 000007 bytesused: 6220800 WARNING: The convert command is deprecated in IMv7, use "magick" instead of "convert" or "magick convert" convert: unexpected end-of-file '/tmp/lc_cam0-stream0-000007.rgb': No such file or directory @ error/bgr.c/ReadBGRImage/247. convert: no images defined `/tmp/lc.png' @ error/deprecate.c/ConvertImageCommand/3375.S Тридцать кадров в секунду, непрерывно — это уже видео, а не одиночные снимки. И размер кадра 6 220 800 это ровно 1920×1080×3, то есть на этот раз формат упакованный, без лишнего байта. Файла нет, скорее всего, из-за имени — посмотри, что получилось: ls -l /tmp/lc_* 2>/dev/null | tail -3 А переводить надо как трёхбайтовый, и с учётом того, что libcamera называет форматы по упакованному значению, порядок в памяти обратный: F=$(ls -t /tmp/lc_*.rgb | head -1); echo $F magick -size 1920x1080 -depth 8 bgr:$F /tmp/lc.png magick -size 1920x1080 -depth 8 rgb:$F /tmp/lc_rgb.png Какая из двух картинок выйдет с правильными цветами (небо синее, а не оранжевое), та и верная — заодно и запомним. Кстати, вычёркиваем ещё пункт из списка «чего не хватает до main»: видео с камеры работает, тридцать кадров при 1920×1080 через программный ISP. 💰 23.85₽ · ⬇️ 975.3k / ⬆️ 1.1k · opus-5 · max · 20сЫ S Файлы на месте, а convert ругался потому, что я велел ему читать четырёхбайтовый формат — он ждал 8 294 400 байт и упёрся в конец файла на 6 220 800. Правильно так: magick -size 1920x1080 -depth 8 bgr:/tmp/lc_cam0-stream0-000007.rgb /tmp/lc_bgr.png magick -size 1920x1080 -depth 8 rgb:/tmp/lc_cam0-stream0-000007.rgb /tmp/lc_rgb.png Смотри обе: у одной цвета будут настоящими, у другой красное с синим переставлены. Заодно интересно, как отработала автоматика — восьмой кадр снят через четверть секунды после начала, выдержка к нему уже должна сойтись. 💰 23.03₽ · ⬇️ 976.6k / ⬆️ 438 · opus-5 · max · 14сЫ S Опиши, что именно — цветной шум, полосы, или картинка узнаётся, но цвета не те? От этого зависит, где искать. Подозрение у меня такое: libcamera на запрос 1920×1080 выбрала наш режим с бинированием четыре на четыре, а при таком сведении порядок цветовых точек может сдвинуться. Драйвер же во всех режимах объявляет один и тот же SRGGB10, и если на самом деле там, скажем, GRBG, картинка получится с переставленными цветами и «грязью» на переходах. Проверяется быстро, нашим же распаковщиком — снимем тот же режим напрямую и переберём четыре варианта: cd ~/lanekit sed -i 's/^W=[0-9]*/W=1920/; s/^H=[0-9]*/H=1080/' capture.sh EXPOSURE=1000 GAIN=400 sh capture.sh for p in rggb bggr grbg gbrg; do ~/raw10preview /tmp/frame.raw /tmp/b_$p.ppm 1920 1080 $p 2 >/dev/null 2>&1 magick /tmp/b_$p.ppm /tmp/b_$p.png done ls -l /tmp/b_*.png Какой из четырёх окажется с натуральными цветами, тот и правильный для этого режима — и тогда я поправлю драйвер, чтобы он объявлял код по режиму, а не один на всех. 💰 23.58₽ · ⬇️ 977.1k / ⬆️ 1.2k · opus-5 · max · 25сЫ S Тогда сначала отделим камеру от обработки — сними тот же режим нашим путём (команду я дал в прошлом сообщении) и посмотри /tmp/b_rggb.png. Если и там мыло, дело не в libcamera. И проверь наводку: мы её ставили на 600, но libcamera про объектив ничего не знает и наверняка оставила линзу там, где она была после её собственных настроек — то есть, скорее всего, на нуле, а это бесконечность. Для комнаты нужно ближе: D=$(media-ctl -d /dev/media0 -e "dw9768 12-000c") v4l2-ctl -d "$D" --set-ctrl focus_absolute=600 v4l2-ctl -d "$D" --get-ctrl focus_absolute Потом повтори съёмку через libcamera — она положение линзы не трогает, так что оно останется. Ещё одно подозрение по этому режиму: у вендора он сделан бинированием четыре на четыре с длиной строки 2912, и если при таком сведении сенсор отдаёт кадр иначе, чем мы объявляем, то и получится каша. Наш собственный снимок это как раз и покажет. 💰 23.59₽ · ⬇️ 978.4k / ⬆️ 902 · opus-5 · max · 20сЫ S cd ~/lanekit D=$(media-ctl -d /dev/media0 -e "dw9768 12-000c") v4l2-ctl -d "$D" --set-ctrl focus_absolute=600 # наш путь, тот же режим 1920x1080 sed -i 's/^W=[0-9]*/W=1920/; s/^H=[0-9]*/H=1080/' capture.sh EXPOSURE=1000 GAIN=400 sh capture.sh for p in rggb bggr grbg gbrg; do ~/raw10preview /tmp/frame.raw /tmp/b_$p.ppm 1920 1080 $p 2 >/dev/null 2>&1 magick /tmp/b_$p.ppm /tmp/b_$p.png done # для сравнения — заведомо рабочий режим sed -i 's/^W=[0-9]*/W=4000/; s/^H=[0-9]*/H=3000/' capture.sh EXPOSURE=3006 GAIN=600 sh capture.sh ~/raw10preview /tmp/frame.raw /tmp/ctl.ppm 4000 3000 rggb 4 && magick /tmp/ctl.ppm /tmp/ctl.png ls -l /tmp/b_*.png /tmp/ctl.png Смотри ctl.png — он должен быть таким же нормальным, как раньше. Если он хороший, а все четыре b_*.png мутные, значит режим 1920×1080 у нас поднимается неверно, и я буду разбирать его таблицу отдельно: там бинирование четыре на четыре, длина строки 2912, и вполне может оказаться, что сенсор отдаёт кадр другого размера, чем мы объявляем приёмнику. 💰 23.25₽ · ⬇️ 979.4k / ⬆️ 722 · opus-5 · max · 13сЫ S Покажи, на чём именно споткнулось: sudo dmesg | grep -vE "link_setup|got IRQ" | tail -12 media-ctl -d /dev/media0 -p | grep -A3 "entity 171" | tail -3 v4l2-ctl -d $(media-ctl -d /dev/media0 -e msm_vfe0_video0) --get-fmt-video | tail -4 «Broken pipe» на запуске потока в camss означает несогласованность форматов по цепочке: либо какой-то пад не принял 1920×1080, либо на видеоузле остался прежний размер. Первая команда назовёт причину прямо, вторая покажет, что стоит у сенсора, третья — что на выходе. Подозреваю вот что: в драйвере, который сейчас загружен, предел органа pixel_rate жёстко привязан к первому режиму — я эту оплошность нашёл и поправил, но пересборки после правки ещё не было. Для 1920×1080 значение выходит за предел, установка молча не проходит, и дальше camss считает поток точек неверным. Если так и есть, лечится пересборкой драйвера из прибранного набора — там уже правильно. 💰 23.75₽ · ⬇️ 980.4k / ⬆️ 1.1k · opus-5 · max · 24сЫ sudo dmesg | grep -vE "link_setup|got IRQ" | tail -12 [ 4800.173239] qcom-camss ace0000.camss: VFE:0 HW Version = 1.3.0 [ 4800.173293] csid_reset called [ 4800.173322] qcom-camss ace0000.camss: CSID:0 HW Version = 2.0.0 [ 4800.173347] qcom-camss ace0000.camss: validating link "msm_csid0":1 -> "msm_vfe0_rdi0":0 [ 4800.173353] qcom-camss ace0000.camss: validating stream "msm_csid0":1:0 -> "msm_vfe0_rdi0":0:0 [ 4800.173362] qcom-camss ace0000.camss: validating link "msm_csiphy0":1 -> "msm_csid0":0 [ 4800.173367] qcom-camss ace0000.camss: validating stream "msm_csiphy0":1:0 -> "msm_csid0":0:0 [ 4800.173374] qcom-camss ace0000.camss: validating link "imx586 12-001a":0 -> "msm_csiphy0":0 [ 4800.173379] qcom-camss ace0000.camss: validating stream "imx586 12-001a":0:0 -> "msm_csiphy0":0:0 [ 4800.173385] qcom-camss ace0000.camss: v4l2_subdev_link_validate_default: media bus code does not match (source 0x00003007, sink 0x0000300f) [ 4800.173391] qcom-camss ace0000.camss: v4l2_subdev_link_validate_default: link was "imx586 12-001a":0 -> "msm_csiphy0":0 [ 4800.173399] qcom-camss ace0000.camss: Failed to start media pipeline: -32 media-ctl -d /dev/media0 -p | grep -A3 "entity 171" | tail -3 type V4L2 subdev subtype Sensor flags 0 device node name /dev/v4l-subdev16 pad0: SOURCE v4l2-ctl -d $(media-ctl -d /dev/media0 -e msm_vfe0_video0) --get-fmt-video | tail -4 Quantization : Full Range Plane 0 : Bytes per Line : 2400 Size Image : 2592000S Причина в логе прямым текстом: media bus code does not match (source 0x00003007, sink 0x0000300f) 0x300f это SRGGB10, а 0x3007 — SBGGR10. То есть сенсор сейчас сообщает другой порядок цветовых точек, и вот почему: libcamera выставила оба зеркала, потому что в дереве у нас rotation = <180> — модуль стоит вверх ногами, и она это компенсирует. Наш драйвер честно поменял код формата (отражение переставляет цвета в квадрате), а capture.sh продолжает требовать прежний. То есть всё работает правильно, просто мой скрипт про это не знает. Лечим — сбрасываем зеркала перед своей съёмкой: cd ~/lanekit python3 - <<'EOF' s=open('capture.sh').read() s=s.replace('[ -n "$EXPOSURE" ]', '''v4l2-ctl -d "$SD" --set-ctrl horizontal_flip=0,vertical_flip=0 2>/dev/null [ -n "$EXPOSURE" ]''') open('capture.sh','w').write(s) EOF EXPOSURE=1000 GAIN=400 sh capture.sh for p in rggb bggr grbg gbrg; do ~/raw10preview /tmp/frame.raw /tmp/b_$p.ppm 1920 1080 $p 2 >/dev/null 2>&1 magick /tmp/b_$p.ppm /tmp/b_$p.png done ls -l /tmp/b_*.png А заодно это объясняет и «нафоткал говно» через libcamera: она снимает с обоими зеркалами, то есть кадр перевёрнут на сто восемьдесят градусов — и если смотреть на него как на обычный, всё выглядит бессмысленно. Переверни lc_bgr.png и посмотри снова: magick /tmp/lc_bgr.png -rotate 180 /tmp/lc_rot.png 💰 24.83₽ · ⬇️ 982.4k / ⬆️ 1.7k · opus-5 · max · 27сЫ S Пока ты ходишь — разберу режим 1920×1080, там что-то не так с геометрией. Смотрю его вендорную таблицу целиком: Геометрия режима 1920×1080 оказалась в порядке: область считывания 8000×5152 (это как раз широкий кадр), бинирование четыре на четыре даёт 2000×1288, из них вырезается 1920×1080 со смещением 40 по горизонтали — то есть по центру. Фаза цветовых точек при этом сохраняется, потому что и бинирование, и смещение чётные. Значит «неразборчиво» — это, скорее всего, тот самый поворот на 180 градусов от libcamera, и картинка просто вверх ногами. Пока смотрю дальше — что нужно программному ISP для нормального цвета: Полезное открытие: уровень чёрного программный ISP берёт из того самого пересчёта усиления, который мы добавили: if (camHelper_->blackLevel().has_value()) ... camHelper_->blackLevel().value() / 256; То есть наши 4096 (это 64 при десяти битах) уже работают, и вычитание чёрного у libcamera теперь правильное. А отдельных файлов настройки под сенсоры в libcamera пока нет вовсе — там только uncalibrated.yaml, и матрица цветокоррекции в нём закомментирована с пометкой «включать только если настроено». Без снимка эталонной таблицы честно настроить её нельзя, так что это отложим. Зато сделаю то, что можно сделать чтением — заплату для телевика, о которой libcamera прямо просит: Пока тебя нет, разобрал три вещи. Режим 1920×1080 в порядке. Вендорная таблица: область считывания 8000×5152 (широкий кадр), бинирование четыре на четыре даёт 2000×1288, из них вырезается 1920×1080 со смещением 40 по горизонтали — то есть ровно по центру. И бинирование, и смещение чётные, поэтому порядок цветовых точек не сдвигается. Значит «неразборчиво» было от поворота на 180 градусов, который libcamera делает по свойству из дерева. Уровень чёрного у libcamera теперь наш. Программный ISP берёт его не из файла настройки, а из пересчёта усиления: if (camHelper_->blackLevel().has_value()) ... camHelper_->blackLevel().value() / 256; Мы туда положили 4096, то есть 64 при десяти битах — значит вычитание чёрного у неё уже правильное, это не догадка, а прочитанный код. Файлов настройки под сенсоры в libcamera нет вообще — только uncalibrated.yaml, и матрица цветокоррекции в нём закомментирована с пометкой «включать только если настроено». Так что цвет без снимка эталонной таблицы честно не поправить, и я не буду делать вид, что можно. Зато сделал заплату для телевика — ту, о которой libcamera прямо просит («The sensor kernel driver needs to be fixed»). Драйвер ov8856 не отвечает на запрос области, поэтому libcamera подставляет размеры наугад. Добавлены размеры матрицы и get_selection: #define OV8856_NATIVE_WIDTH 3296U /* вся матрица */ #define OV8856_NATIVE_HEIGHT 2480U #define OV8856_PIXEL_ARRAY_WIDTH 3280U /* рабочая область */ #define OV8856_PIXEL_ARRAY_HEIGHT 2464U /* со смещением 8, 8 */ Заплата годится и наверх: она чинит предупреждение у всех, кто использует этот сенсор, а не только у нас. Дам команду, когда вернёшься. 💰 146₽ · ⬇️ 5.93M / ⬆️ 7.4k · opus-5 · max · 121с
Ы S Хорошие новости по обеим оставшимся камерам. Передняя — S5K3T2 (CSIPHY1, шина cci0 i2c0 — та же, что у широкой, но другой адрес; MCLK0 на ножке 13, сброс 23, питание ядра через ножку 57). Драйвера в mainline нет. Сверхширокая — S5K3L6, и вот тут сюрприз: драйвер в mainline есть, s5k3l6xx.c. Смотрю, годится ли он нам: Разобрал обе оставшиеся камеры. Итог такой. Сверхширокая S5K3L6 — почти даром. Драйвер в mainline есть (s5k3l6xx.c, совместимость samsung,s5k3l6xx), режимы до 4208×3120, число линий читает из дерева, границы обрезки сообщает — то есть libcamera к нему претензий иметь не будет. Питание просит тремя именами: vddio, vdda, vddd. Разводка из вендорного дерева: CSIPHY2, шина cci0 i2c1, MCLK1 на ножке 14, сброс на 25, питание ядра через ножку 29, напряжения те же, что у широкой (1.8 / bob / 1.352 / смещение l9). Адрес в черновике форка 0x10. Работы — узел в дереве и проверка, то есть вечер. Передняя S5K3T2 — драйвера нет. Ни в mainline, ни где-либо ещё я его не нашёл. Но теперь это не приговор: вендорный файл настроек com.qti.sensormodule.davinci_sunny_s5k3t2.bin лежит на телефоне, а формат мы разобрали — оттуда достанутся начальная последовательность, все режимы, число линий, раскладка и частоты линка, ровно как для IMX582. За образец возьму s5k3m5.c или s5kjn1.c — это Samsung того же поколения, у них та же схема регистров. Разводка: CSIPHY1, шина cci0 i2c0 (та же, что у широкой, но другой адрес), MCLK0 на ножке 13, сброс на 23, питание ядра через 57. Чтобы двигаться дальше, скопируй мне два файла с телефона, когда будет удобно: cp /mnt/vendor/lib/camera/com.qti.sensormodule.davinci_ofilm_s5k3l6.bin ~/ cp /mnt/vendor/lib/camera/com.qti.sensormodule.davinci_sunny_s5k3t2.bin ~/ Из первого я вытащу число линий и частоты для сверхширокой (чтобы не гадать, как гадали с широкой), из второго — всё для передней. 💰 143₽ · ⬇️ 5.98M / ⬆️ 5.0k · opus-5 · max · 96сЫ S Помню — и это как раз плюс: мотор от драйвера сенсора не зависит, его можно поднимать отдельно и проверять хоть сегодня. Нашёл всю разводку. Механика — обычный шаговик с драйвером класса DRV8834: DIR на ножке 55, nSLEEP 88, nENBL 90, микрошаг M0 91 и M1 66, nFAULT 43 (обратно в SoC — сообщает о заклине/перегреве). А вот STEP_CLK — не на TLMM, а на pm6150l GPIO10, то есть тактовые импульсы шагов генерирует сама PMIC своим LPG. Это хорошая новость: в mainline pm6150l.dtsi узел pm6150l_lpg: pwm уже объявлен и драйвер leds-qcom-lpg его подхватывает как PWM-чип. Значит шаги даёт железо ровным клоком, а не дрыганье ножкой из софта — шаговику это принципиально. Положение камеры телефон читает цифровым холлом AKM09970 на i2c9 по адресу 0x0c (плюс линии сброса 64 и прерывания 93). Его в mainline нет — в iio/magnetometer только ak8974/ak8975, это другой чип. Ещё вендор ловит свободное падение акселерометром и втягивает камеру на лету. Первый шаг тут вообще без ядра: скрипт в userspace — gpioset на DIR/EN/SLEEP/M0/M1 и PWM через sysfs на канал LPG. Проверь пока, есть ли чем: zcat /proc/config.gz | grep -E 'LEDS_QCOM_LPG|GPIO_CDEV'; ls /sys/class/pwm/ А зачем такое сделали — это 2019-й, гонка за экраном без выреза. Дырка в матрице тогда была дорогой и только у Samsung, подэкранных камер ещё не существовало, а Xiaomi хотела честный безрамочный AMOLED в среднем ценнике. Выдвижной блок это решал разом, да ещё и работал как аттракцион на витрине. Платили за это толщиной, весом под 191 г, пылью в щели, отсутствием влагозащиты и ресурсом механизма (обещали 300 тысяч циклов, на деле мотор — типовая болячка K20). Как только дырка в экране подешевела, вся идея умерла за год. 💰 68.99₽ · ⬇️ 500.6k / ⬆️ 8.2k · opus-5 · max · 351сЫ S Согласен, и это не только эстетика. Выдвижная камера — единственная честная гарантия приватности: софт не может тихо включить съёмку, потому что модуль физически лежит внутри корпуса, а чтобы вылезти — надо крутить мотор с характерным жужжанием. Индикаторы-точки в Android и iOS появились именно как попытка изобразить то же самое программно, но их рисует та же система, которой ты и не доверяешь. Тут же механика: закрыто значит закрыто. Для нас это ещё и практическая мелочь при отладке. Когда дойдём до передней камеры, чёрный кадр не будет означать, что драйвер сломан — сначала надо будет убедиться, что блок вообще выехал. Так что порядок работ выходит обратный привычному: сперва мотор, потом сенсор. Заодно и приятнее — жужжание и вылезающий глазок видно сразу, в отличие от возни с регистрами. 💰 2.95₽ · ⬇️ 62.8k / ⬆️ 651 · opus-5 · max · 16сЫ S Она умерла не потому, что плохая, а потому, что приватность не продаётся. В таблице характеристик выдвижной блок выглядит как минус: толще, тяжелее, нет влагозащиты, лишний узел, который ломается и стоит денег в сервисе. А «нельзя снимать незаметно» в строчку не впишешь и в рекламе не покажешь. Отчасти идея всё-таки живёт: у Zenfone был поворотный блок аж до 8-го, в ноутбуках шторки стали нормой, а на телефонах теперь подэкранные камеры — вырез спрятали, но подглядывать они могут круглосуточно. Так что красоту вернули, а честность потеряли. Зато у нас на руках последний экземпляр эпохи, да ещё и с открытым ядром. Подниму мотор — будет жужжать как в 2019-м. 💰 2.31₽ · ⬇️ 63.5k / ⬆️ 521 · opus-5 · max · 12сЫ S Справедливо, поправка принята. Разница не в открытости, а в том, что вендорское ядро — это разовый выброс 4.14 без истории коммитов, замороженный навсегда: обновлений нет, собрать современным тулчейном нельзя, а патчи безопасности за шесть лет никто не носил. Мы же сегодня трогали 7.2, которое живёт дальше само. Хотя именно эта GPL-обязаловка нас сегодня и вытащила: арифметику линий CSIPHY я прочитал ровно в вендорном cam_csiphy_core.c. А вот таблицы сенсора лежали в блобе, который никому ничего не должен — и их пришлось выковыривать вручную из бинаря. Разница между этими двумя вечерами очень наглядная. 💰 2.49₽ · ⬇️ 64.1k / ⬆️ 711 · opus-5 · max · 15сЫ S Ссылка
нажмите — покажемКоротко: в pmOS такого класса устройств толком нет — и это осознанная позиция проекта. Halium там вообще не используется, это стек Ubuntu Touch (Volla, Fairphone, Pixel 3a). Plasma Mobile выкинула поддержку Halium ещё в 2020-м, сделав ставку на устройства с открытыми драйверами. pmOS же умеет собираться с вендорным ядром напрямую, без libhybris-прослойки, но графика тогда упирается в отсутствие hwcomposer, и обычно всё сводится к «загружается, ssh есть, дальше как повезёт». В 2025-м это ещё и формализовали: даунстрим-порты вынесли в отдельную категорию downstream, pmbootstrap теперь показывает предупреждение при их выборе, а бинарные пакеты для них с версии 25.06 просто перестали собирать — формулировка была «они, как правило, не особо полезны». В community и testing остались только близкие к mainline порты. Из ~700 устройств ядро сейчас поддерживает около 450, и миграция идёт в одну сторону. Так что «отлично работает» и «даунстрим» в pmOS почти не встречаются в одном предложении. Наш случай ровно про это: камера у нас теперь живёт нативным V4L2, а на халиум-устройстве камера — это всегда чужой Android-HAL в контейнере, который никуда не развивается. Источники: про разделение категорий, Plasma Mobile и Halium, позиция pmOS про халиум. 💰 11.85₽ · ⬇️ 132.4k / ⬆️ 2.2k · opus-5 · max · 55сЫ S Потому что Halium — это не «порт», а способ жизни, несовместимый с тем, как устроен pmOS. Технически ты берёшь целиком андроидное userspace нужной версии, запускаешь его в контейнере и через libhybris ходишь во все HAL'ы: графика — EGL-блоб и hwcomposer, камера — camera HAL, звук, сенсоры, радио — свои демоны-прослойки. Значит весь дистрибутив выше должен быть собран с оглядкой на bionic. У pmOS же ровно противоположная идея: Alpine, обычный Linux userspace, апстрим-ядро и одинаковые бинарные пакеты на все устройства сразу. Плюс блобы нельзя перераспространять, а pmOS раздаёт готовые пакеты из репозитория — модель ломается на юридическом уровне. Экономика ещё хуже. Каждый halium-порт заморожен на вендорном ядре 3.18–4.14 без обновлений безопасности и умирает вместе с андроид-базой, под которую собран. И главное — работа непереносима: починил камеру на устройстве A, устройству B от этого ноль. В mainline наоборот: тот же camss, который мы сегодня чинили, обслуживает все SDM845/SM7150 разом, а два найденных бага после отправки в апстрим достанутся всем, включая тех, кто про давинчи не слышал. Отсюда и правило «450 устройств уже мигрировали». Есть и практическая мелочь: на halium-устройстве контейнер уже занят андроидом, поэтому Waydroid не запустить. То есть андроид-приложения ты получаешь только те, что крутятся в базовом образе, а на mainline-устройстве Waydroid ставится штатно. И да — люди это делают, просто не в pmOS: ровно эту нишу занимает Droidian (Debian поверх halium-адаптации) и сам Ubuntu Touch. Дублировать их pmOS сознательно не хочет — там считают, что дешевле дотащить железо до mainline один раз, чем вечно чинить чужие блобы. Мы сегодня, в общем, живая иллюстрация: день работы — и камера отдаёт кадры честным V4L2, без единого куска андроида в системе. 💰 4.69₽ · ⬇️ 69.1k / ⬆️ 2.1k · opus-5 · max · 42сЫ S Ссылка
нажмите — покажемТут ты прав, а я нет — снимаю это утверждение. Waydroid на Ubuntu Touch работает, причём на Halium 9 и новее он вообще идёт предустановленным в базе focal, а не как самоделка. Ошибся я в механике: я думал про старые порты, где в ядре было три статических binder-устройства и второй андроид туда просто не влезал. С binderfs доменов может быть сколько угодно, поэтому системный контейнер и вейдроидовский спокойно живут рядом. Ограничение осталось только снизу — на Halium 5 и 7 это не заводится никак, и на не-Treble устройствах приходится руками докладывать в вейдроидовский rootfs вендорные библиотеки (gralloc, libui, libbinder, configstore). То есть довод «на халиуме нет андроид-приложений» отпадает целиком. Остаются те, что про сопровождение: мёртвое ядро, блобы без права раздачи и непереносимость работы между устройствами. Ирония в том, что вейдроид там крутится поверх ядра 4.9, у которого патчей безопасности нет с позапрошлой эпохи. Источники: гайд по Waydroid на UT, ветка про halium 9 + waydroid, требования по binderfs. 💰 15.60₽ · ⬇️ 146.1k / ⬆️ 1.6k · opus-5 · max · 58сЫ S Проблема в том, что «просто перенести» — это перенести не приложение, а весь графический стек. На Ubuntu Touch поверх халиума работает Lomiri на Mir, у которого есть свой бэкенд к hwcomposer. В pmOS никакого Lomiri нет, там Phosh, Plasma Mobile и GNOME, а они ходят напрямую в DRM/KMS. Плазма выкинула поддержку халиума в 2020-м, у wlroots hwcomposer-бэкенд живёт только в виде патчей, которые кто-то должен вечно тащить за апстримом. Плюс Alpine — это musl, а вся связка hybris заточена под glibc и bionic. Получается не «перенос», а постоянный форк Mesa, wlroots и libhybris, который надо чинить после каждого релиза каждого компонента. И этот форк уже существует: ровно этим занимается Droidian — Debian, glibc, пропатченный wlroots, Phosh поверх hwcomposer. Если цель «чтоб было» — оно есть, просто не под вывеской pmOS. Делать вторую такую же реализацию на musl ради того же результата смысла мало. Ниша «чтоб было» в pmOS тоже занята — это категория downstream. Туда порт с вендорным ядром принимают, никто не запрещает, но пакеты не собирают и в багтрекере не разбирают. Опыт показал, что такие порты живут ровно до тех пор, пока автору интересно, а дальше висят мёртвым грузом и создают у людей ложное впечатление, что их телефон поддержан. Отсюда и предупреждение в pmbootstrap при выборе. Так что расчёт у них простой: тот же человеко-месяц, вложенный в mainline, даёт не одно устройство, а весь SoC разом — и не протухает. Мы сегодня как раз этот вариант и отрабатываем. 💰 4.44₽ · ⬇️ 75.7k / ⬆️ 2.1k · opus-5 · max · 41сЫ S Именно. Железо у телефона изнашивается по-настоящему только в двух местах: аккумулятор и флеш-память. Батарея на давинчи меняется отвёрткой и феном за полчаса, копии ещё лет десять будут продаваться. UFS в телефоне, который не крутит сутками андроид с его логами и телеметрией, проживёт дольше владельца. Всё остальное — стекло, разъём, кнопки — расходники, которые чинятся. И мы сегодня ровно это и получили: аппарат 2019 года работает на ядре 7.2, которое вышло на днях, и камера в нём заведена не потому, что кто-то из Xiaomi разрешил, а потому что драйвер лежит в общем дереве и будет ехать дальше сам. Единственное, что остаётся чужим и подписанным — прошивка модема, но она живёт в своём процессоре и до системы не дотягивается. Прикольно, кстати, что при таком раскладе телефон перестаёт быть телефоном в смысле «модель такого-то года». Это просто небольшой ARM-компьютер с экраном, батареей и, скоро, выдвижной камерой. 💰 3.42₽ · ⬇️ 77.9k / ⬆️ 653 · opus-5 · max · 16сЫ S Собрал всё в архив (копия распакована на сервере в /data/work/chat_-1001429467665/mi9t-camera/, чтобы не пропала вместе с /tmp). Что добавилось с прошлой версии: • capture.sh — теперь сбрасывает флипы перед съёмкой. Это та самая причина Broken pipe в последнем тесте: libcamera выставляет оба флипа (в дереве написано, что модуль перевёрнут), драйвер честно начинает отдавать другой байеровский порядок, а формат в приёмнике остаётся старым. Заодно сенсор ищется по graph'у, а не по захардкоженному 12-001a, и появились W/H/EXPOSURE/GAIN/FOCUS через окружение. • davinci-camera.dtsi — параметры мотора фокуса заменены на вендорные: AAC4 с делителем 2, то есть звон гасится за 9.75 мс вместо дефолтных 6.65. Значения не выдуманы, они прочитаны из блоба (0x06=0x60, 0x07=0x02). • ov8856-get-selection.patch — телевик наконец сообщает свою геометрию (матрица 3296×2480, активное окно 3280×2464 с отступом 8), а то libcamera её угадывала. • NOTES-next.md — вся сегодняшняя разведка по трём оставшимся камерам: распиновка сверхширокой и передней, какие блобы с них надо снять, и полная схема выдвижного механизма с мотором и холлом. Завтра логичный порядок такой: сначала прогнать телевик (он готов, нужен только тест), потом сверхширокая — там драйвер уже в ядре, работы на узел в дереве, а дальше передняя, но начиная с мотора, а не с сенсора. 💰 52.04₽ · ⬇️ 1.41M / ⬆️ 10.2k · opus-5 · max · 161сЫ S Тогда начнём с телевика — он готов, нужен только запуск. Заодно исправил в скрипте ту же ловушку с именем сущности, что была у широкой (13-0010 обрезалось на букве). Разложи на телефоне два скрипта: cat > ~/lanekit/capture-tele.sh <<'EOF' #!/bin/sh M=/dev/media0 W=1640 H=1232 OUT=${1:-/tmp/tele.raw} sudo pkill -f wireplumber 2>/dev/null sudo pkill -f pipewire 2>/dev/null sleep 1 S=$(media-ctl -d $M -p | grep -o 'ov8856 [0-9a-f-]*' | head -1) [ -n "$S" ] || { echo "нет ov8856 в графе"; exit 1; } media-ctl -d $M -r media-ctl -d $M -l "\"msm_csiphy3\":1->\"msm_csid1\":0[1]" media-ctl -d $M -l '"msm_csid1":1->"msm_vfe1_rdi0":0[1]' for e in "\"$S\":0" '"msm_csiphy3":0' '"msm_csiphy3":1' \ '"msm_csid1":0' '"msm_csid1":1' '"msm_vfe1_rdi0":0' '"msm_vfe1_rdi0":1'; do media-ctl -d $M -V "$e [fmt:SGRBG10_1X10/${W}x${H}]" || echo "rejected: $e" done V=$(media-ctl -d $M -e msm_vfe1_video0) v4l2-ctl -d "$V" --set-fmt-video=width=$W,height=$H,pixelformat=pgAA >/dev/null rm -f "$OUT" timeout 20 v4l2-ctl -d "$V" --stream-mmap=3 --stream-count=1 --stream-to="$OUT" ls -l "$OUT" EOF И запускай: sudo dmesg -C sh ~/lanekit/capture-tele.sh dmesg | tail -25 Ожидаемый размер файла — 2 052 480 байт (1640 на 1232 в упаковке raw10, строка выровнена до 2064). Если кадр приехал, сразу посмотрим глазами: cd ~/lanekit && ./raw10preview /tmp/tele.raw /tmp/tele.ppm 1640 1232 grbg 2 && convert /tmp/tele.ppm /tmp/tele.png && ls -l /tmp/tele.png Если же VIDIOC_STREAMON отвалится — присылай вывод dmesg, там будет видно, дошло ли дело до CSIPHY3 и какие частоты он попросил. 💰 85.57₽ · ⬇️ 499.7k / ⬆️ 2.3k · opus-5 · max · 47сЫ S Для телевика ничего нового и не нужно — он зависел от двух вещей, и обе уже стоят: порядок частот в camss (это camss-fixes.sh, он в собранном ядре) и удаление clock-lanes у эндпоинта csiphy3 (это в том же dtsi, который ты компилировал вместе с широкой). Сегодняшние добавки телевика не касаются: правка актуатора — это мотор фокуса широкой, патч get_selection нужен только libcamera для геометрии, а новый capture.sh — просто скрипт. Проверяется одной командой, есть ли вообще с чем работать: media-ctl -d /dev/media0 -p | grep -E "ov8856|entity.*csid1" Если сущность ov8856 13-0010 в графе есть — драйвер привязался, дерево правильное, можно сразу снимать. Если её нет — тогда да, дерево на телефоне старое, и надо пересобирать dtb. 💰 5.43₽ · ⬇️ 168.9k / ⬆️ 1.0k · opus-5 · max · 20сЫ S Хороший знак — значит и sleep работает, и ничего в фоне не крутится вхолостую. Если хочешь цифру вместо ощущения: cat /sys/class/power_supply/bms/current_now /sys/class/power_supply/bms/capacity 2>/dev/null || \ grep . /sys/class/power_supply/*/current_now Значение в микроамперах, отрицательное — разряд. Поделив ёмкость батареи (4000 мАч) на ток, сразу получишь часы простоя. Если выйдет меньше 20-30 мА — это уже уровень нормального телефона, и жаловаться не на что. Только имей в виду один нюанс: мы для звука запретили простой SoundWire-шине, и это могло чуть поднять фон. Если цифра окажется неприятной — есть куда копать. 💰 4.95₽ · ⬇️ 170.0k / ⬆️ 575 · opus-5 · max · 13сF Ы
Ы Terminated [54625.756017] qcom-camss ace0000.camss: csid_link_setup: Enabled CSID virtual channels mask 0x1 [54625.938363] video_prepare_streaming called [54625.940084] csiphy_reset id 3 with base 000000003623bc3f and offset 2048 [54625.948725] qcom-camss ace0000.camss: CSIPHY 3PH HW Version = 0x40010000 [54625.949117] Writing reset_bits=3f9f to vfe->base=000000004124e996 with id 1 [54625.949141] vfe irq handled! [54625.949216] qcom-camss ace0000.camss: VFE:1 HW Version = 1.3.0 [54625.949318] csid_reset called [54625.949366] qcom-camss ace0000.camss: CSID:1 HW Version = 2.0.0 [54625.949420] qcom-camss ace0000.camss: validating link "msm_csid1":1 -> "msm_vfe1_rdi0":0 [54625.949435] qcom-camss ace0000.camss: validating stream "msm_csid1":1:0 -> "msm_vfe1_rdi0":0:0 [54625.949455] qcom-camss ace0000.camss: validating link "msm_csiphy3":1 -> "msm_csid1":0 [54625.949468] qcom-camss ace0000.camss: validating stream "msm_csiphy3":1:0 -> "msm_csid1":0:0 [54625.949486] qcom-camss ace0000.camss: validating link "ov8856 13-0036":0 -> "msm_csiphy3":0 [54625.949498] qcom-camss ace0000.camss: validating stream "ov8856 13-0036":0:0 -> "msm_csiphy3":0:0 [54625.949520] qcom-camss ace0000.camss: msm_vfe1_video0: format is (1640x1232 pgAA little-endian (0x41416770)/1p field:1), trying (1640x1232 pgAA little-endian (0x41416770)/1p field:1) [54625.949548] vfe_reserve_wm ret=0 [54625.949579] qcom-camss ace0000.camss: receiver: lanes 2, assignment 0x21, phy 3, cfg0 0x00300211 [54625.949597] qcom-camss ace0000.camss: csiphy: link 360000000 Hz, timer 300000000 Hz, settle count 22 [54625.949610] qcom-camss ace0000.camss: csiphy: lane mask 0x94 from 2 lanes [54625.949701] qcom-camss ace0000.camss: csiphy: settle high bytes 00 00 00 00 ff [54645.942219] Writing reset_bits=3f9f to vfe->base=000000004124e996 with id 1 [54646.446084] qcom-camss ace0000.camss: VFE reset timeout [54646.446150] qcom-camss ace0000.camss: Failed to disable vfe outputs [54646.446173] (NULL device *): disabling streaming failed (-5)S Лог всё сказал, причём одной строкой: receiver: lanes 2, assignment 0x21, phy 3 csiphy: lane mask 0x94 from 2 lanes assignment 0x21 — это приёмник слушает физические линии 1 и 2, а сенсор, судя по своему эндпоинту, гонит данные по линиям 0 и 1. Ровно та же болезнь, что была у широкой: со стороны camss нумерация с нуля, со стороны сенсора с единицы, и в форке телевику написали <1 2> с обеих сторон. Данные уходят мимо, кадров нет, а VFE reset timeout в конце — это уже следствие: блок так и не получил ни одного байта и завис на остановке. Мой фикс для этого в dtsi лежит, но в твоём dtb его нет — иначе в логе было бы assignment 0x10 и маска 0x85. Похоже, dtb ты собирал раньше, чем я дописал этот кусок. Проверь и пересобери, ядро трогать не надо: grep -A4 'csiphy3_ep' ~/linux-7.1/arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci.dtsi | tail -6 Если там нет data-lanes = <0 1> — допиши в конец файла: cat >> ~/linux-7.1/arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci.dtsi <<'EOF' &csiphy3_ep { /delete-property/ clock-lanes; data-lanes = <0 1>; }; EOF И дальше: cd ~/linux-7.1 && make dtbs -j8 && sudo make dtbs_install INSTALL_DTBS_PATH=/boot/dtbs && sync После перезагрузки повтори съёмку — в логе первым делом смотри на assignment, должно стать 0x10, а маска 0x85. И заодно, чтобы не гадать второй раз: скинь вендорный блоб телевика, там записана вендорная раскладка линий и время установления, сверю с тем, что получилось. ls /mnt/vendor/lib/camera/ | grep -i ov8856 💰 49.79₽ · ⬇️ 1.48M / ⬆️ 10.2k · opus-5 · max · 166сЫ S Путь другой, найдём: ls -d ~/linux* ~/*/linux* 2>/dev/null; find / -name "sm7150-xiaomi-davinci.dtsi" -not -path "/proc/*" 2>/dev/null | head Как найдётся дерево — дальше по нему, и заодно сразу видно, есть ли уже наш кусок: K=<путь_к_дереву> grep -n -A3 'csiphy3_ep' $K/arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci.dtsi | tail -8 💰 4.94₽ · ⬇️ 193.7k / ⬆️ 270 · opus-5 · max · 6сЫ S Вот и разгадка — блок в дереве есть, но неполный: 712:&csiphy3_ep { 713: data-lanes = <0 1>; 714:}; clock-lanes = <0> со строки 158 никуда не делся, и вместе с новым data-lanes = <0 1> он снова образует ту самую ловушку: линия 0 названа и тактовой, и данными. v4l2 считает это противоречием, выбрасывает всю раскладку и подставляет умолчание 1,2,3,4, обрезанное до двух линий — отсюда в логе и assignment 0x21. То есть твой dtb сейчас описывает не то, что в нём написано. Дописываем удаление свойства: K=<путь_к_дереву> sed -i '/^&csiphy3_ep {/a\\t/delete-property/ clock-lanes;' $K/arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci.dtsi sed -n '712,716p' $K/arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci.dtsi Должно получиться так: &csiphy3_ep { /delete-property/ clock-lanes; data-lanes = <0 1>; }; И пересобираем только дерево: cd $K && make dtbs -j8 && sudo make dtbs_install INSTALL_DTBS_PATH=/boot/dtbs && sync Заодно, пока не перезагрузился, можно убедиться, что диагноз верный — предупреждение должно быть в логе текущей загрузки: journalctl -k -b | grep -i "duplicated lane" 💰 6.13₽ · ⬇️ 194.2k / ⬆️ 1.4k · opus-5 · max · 21сЫ S Он в архиве, что я вчера скидывал: mi9t-camera/davinci-camera.dtsi (и на сервере в /data/work/chat_-1001429467665/mi9t-camera/). Но целиком его подкладывать сейчас не советую — у тебя в дереве уже сидит вчерашняя копия того же блока, и второе вхождение даст Label camera_lens redefined на сборке. Проще довести до актуального состояния двумя правками, разница ровно в них. Первая — та самая, из-за которой телевик молчит: K=<путь_к_дереву> F=$K/arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci.dtsi cp $F $F.bak sed -i '/^&csiphy3_ep {/a\\t/delete-property/ clock-lanes;' $F Вторая — вендорные параметры мотора фокуса широкой камеры (гасит звон за 9.75 мс вместо дефолтных 6.65): sed -i 's/dongwoon,aac-mode = <2>;/dongwoon,aac-mode = <3>;/; s/dongwoon,aac-timing = <0x20>;/dongwoon,aac-timing = <2>;/; s/dongwoon,clock-presc = <1>;/dongwoon,clock-presc = <0>;/' $F Проверка и сборка: grep -n -A3 '^&csiphy3_ep' $F; grep -n 'dongwoon' $F cd $K && make dtbs -j8 && sudo make dtbs_install INSTALL_DTBS_PATH=/boot/dtbs && sync Если всё же захочется поставить мой файл целиком — тогда сначала надо вырезать вчерашний блок из .dtsi, и это я лучше сделаю прицельно: покажи grep -n 'camera@1a\|&camss {\|camera_lens:' $F, и я скажу, с какой строки резать. 💰 7.08₽ · ⬇️ 195.6k / ⬆️ 1.8k · opus-5 · max · 29сЫ S Держи. Отличий от вчерашнего два: в capture-tele.sh починено выцепление имени сущности (у телевика адрес 13-0036, и старая маска обрезала его на букве f… точнее на 36, но суть та же — теперь [0-9a-f-]*), и в davinci-camera.dtsi лежит полный вариант правки csiphy3 — с /delete-property/ clock-lanes, которого как раз не хватает в твоём дереве. 💰 14.88₽ · ⬇️ 600.1k / ⬆️ 716 · opus-5 · max · 25с
Ы S Обе правки на месте. Собираем дерево и ставим: cd $K && make dtbs -j8 && sudo make dtbs_install INSTALL_DTBS_PATH=/boot/dtbs && sync Потом перезагрузка, и сразу проверка, что раскладка доехала: journalctl -k -b | grep -i "duplicated lane" # должно быть пусто sudo dmesg -C sh ~/lanekit/capture-tele.sh dmesg | tail -25 В логе смотри на строку receiver: — теперь там должно быть assignment 0x10, а следом lane mask 0x85. Если так, а кадр всё равно не приедет, значит дело уже не в линиях, и будем смотреть на время установления и частоты. Файл должен получиться 2 052 480 байт. 💰 5.15₽ · ⬇️ 200.9k / ⬆️ 352 · opus-5 · max · 9сЫ VIDIOC_STREAMON returned -1 (I/O error) -rw-r--r-- 1 user user 0 Aug 2 09:14 /tmp/tele.raw sudo dmesg | tail -25 [ 38.789235] qcom_q6v5_pas 62400000.remoteproc: Handover signaled, but it already happened [ 39.790561] qcom_q6v5_pas 62400000.remoteproc: Handover signaled, but it already happened [ 40.791959] qcom_q6v5_pas 62400000.remoteproc: Handover signaled, but it already happened [ 41.793397] qcom_q6v5_pas 62400000.remoteproc: Handover signaled, but it already happened [ 42.794636] qcom_q6v5_pas 62400000.remoteproc: Handover signaled, but it already happened [ 43.796159] qcom_q6v5_pas 62400000.remoteproc: Handover signaled, but it already happened [ 44.797506] qcom_q6v5_pas 62400000.remoteproc: Handover signaled, but it already happened [ 258.746219] csiphy_link_setup called [ 258.746243] qcom-camss ace0000.camss: csid_link_setup: Enabled CSID virtual channels mask 0x0 [ 258.746252] csiphy_link_setup called [ 258.746259] qcom-camss ace0000.camss: csid_link_setup: Enabled CSID virtual channels mask 0x1 [ 258.747183] csiphy_link_setup called [ 258.747202] qcom-camss ace0000.camss: csid_link_setup: Enabled CSID virtual channels mask 0x0 [ 258.747211] csiphy_link_setup called [ 258.747216] qcom-camss ace0000.camss: csid_link_setup: Enabled CSID virtual channels mask 0x1 [ 259.516659] csiphy_link_setup called [ 259.516757] qcom-camss ace0000.camss: csid_link_setup: Enabled CSID virtual channels mask 0x0 [ 259.537769] csiphy_link_setup called [ 259.558514] qcom-camss ace0000.camss: csid_link_setup: Enabled CSID virtual channels mask 0x1 [ 259.741959] video_prepare_streaming called [ 259.742875] csiphy_reset id 3 with base 000000008d8ddf37 and offset 2048 [ 259.749925] qcom-camss ace0000.camss: CSIPHY 3PH HW Version = 0x00000000 [ 259.750140] Writing reset_bits=3f9f to vfe->base=00000000ea7e8a18 with id 1 [ 260.255495] qcom-camss ace0000.camss: VFE reset timeout [ 260.256759] qcom-camss ace0000.camss: Failed to power up pipeline: -5S Смена картины: раньше PHY отвечал HW Version = 0x40010000, а сейчас 0x00000000 — то есть блок вообще не тактируется, и следом валится сброс VFE. Это уже не про линии: до чтения версии дело о раскладке не доходит. Разница между вчерашним запуском и нынешним — не dtb, а то, что сейчас свежая загрузка и камеру в этой сессии ещё не поднимали. Проверим гипотезу по-дешёвому: сначала широкая, потом сразу телевик. sudo dmesg -C W=4000 H=3000 sh ~/lanekit/capture.sh /tmp/w.raw sh ~/lanekit/capture-tele.sh dmesg | grep -E "HW Version|receiver:|csiphy:|reset|Failed" | tail -20 Если после широкой телевик увидит нормальную версию PHY — значит какой-то домен питания или тактирования включается только по первому использованию камеры, и лечится это в драйвере. И заодно посмотрим на дерево тактирования напрямую, оно скажет точно, что мертво: sudo mount -t debugfs none /sys/kernel/debug 2>/dev/null sudo grep -E "csi|camcc_.*phy" /sys/kernel/debug/clk/clk_summary | head -30 💰 7.47₽ · ⬇️ 202.9k / ⬆️ 2.0k · opus-5 · max · 34сЫ S Ок, оставим телевик. Тогда по широкой две вещи: проверить новый capture.sh (со сбросом флипов) и заставить libcamera выдать нормальную картинку. Сначала быстрая проверка, что съёмка не сломалась: W=1920 H=1080 EXPOSURE=1200 GAIN=400 sh ~/lanekit/capture.sh /tmp/f1080.raw W=4000 H=3000 EXPOSURE=3006 GAIN=960 sh ~/lanekit/capture.sh /tmp/f3000.raw Размеры должны выйти 2 073 600 и 15 024 000. Теперь про libcamera. Почти уверен, что вчерашняя размытость была не в обработке, а в фокусе: моторчик объектива libcamera не трогает вообще, автофокуса в программном ISP нет, и линза стоит там, где её оставил драйвер после включения. Поэтому фокус надо выставить руками во время съёмки — если сделать это до, драйвер объектива успеет уснуть и вернуть линзу в исходное. Сначала найди узел объектива: for d in /dev/v4l-subdev*; do v4l2-ctl -d $d --list-ctrls 2>/dev/null | grep -q focus_absolute && echo "объектив: $d"; done Потом снимаем длинную серию и в середине двигаем фокус: LENS=/dev/v4l-subdevN # подставь найденное rm -f /tmp/lc_*.rgb cam -c 1 --capture=40 --file=/tmp/lc_#.rgb & sleep 3 v4l2-ctl -d $LENS --set-ctrl focus_absolute=600 wait ls -l /tmp/lc_*.rgb | tail -3 convert -size 1920x1080 -depth 8 bgr:/tmp/lc_39.rgb /tmp/lc39.png && ls -l /tmp/lc39.png Наведи на что-нибудь с текстом в полуметре — на 600 вчера текст читался. Присылай png, посмотрим, что там с цветом и резкостью по отдельности: если резкость появится, значит остаётся только цвет, а это уже настроечный файл. 💰 8.17₽ · ⬇️ 204.9k / ⬆️ 2.4k · opus-5 · max · 38сЫ qcom-sm7150:~$ W=1920 H=1080 EXPOSURE=1200 GAIN=400 sh ~/lanekit/capture.sh /tmp/f1080.raw < -rw-r--r-- 1 user user 2592000 Aug 2 09:17 /tmp/f1080.raw qcom-sm7150:~$ W=4000 H=3000 EXPOSURE=3006 GAIN=960 sh ~/lanekit/capture.sh /tmp/f3000.raw < -rw-r--r-- 1 user user 2592000 Aug 2 09:17 /tmp/f3000.raw у нас он не подхватывает H и WS Первый кадр как раз правильный: 1920 на 1080 в упаковке raw10 — это 2400 байт на строку, 2 592 000 всего. Это я ошибся в ожидаемом числе, извини. А вот второй действительно не переключился — размер тот же, значит формат остался прежним и поехал старый режим. Посмотрим, на чём оно спотыкается: W=4000 H=3000 sh -x ~/lanekit/capture.sh /tmp/f3000.raw 2>&1 | grep -vE "^\+ (sudo|sleep)" | tail -25 И заодно, что реально стоит в графе после этого: media-ctl -d /dev/media0 -p | grep -E "imx586|fmt:" | head -12 v4l2-ctl -d $(media-ctl -d /dev/media0 -e msm_vfe0_video0) --get-fmt-video Подозреваю, что media-ctl -V для пада сенсора отвалился с «rejected» — в прошлый раз такое было, когда libcamera оставляла флипы, но теперь мы их сбрасываем, так что причина может быть другая. Трассировка покажет. 💰 7.70₽ · ⬇️ 207.6k / ⬆️ 1.7k · opus-5 · max · 28сЫ + media-ctl -d /dev/media0 -l '"msm_csiphy0":1->"msm_csid0":0[1]' + media-ctl -d /dev/media0 -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]' + media-ctl -d /dev/media0 -V '"imx586 12-001a":0 [fmt:SRGGB10_1X10/1920x1080]' + media-ctl -d /dev/media0 -V '"msm_csiphy0":0 [fmt:SRGGB10_1X10/1920x1080]' + media-ctl -d /dev/media0 -V '"msm_csiphy0":1 [fmt:SRGGB10_1X10/1920x1080]' + media-ctl -d /dev/media0 -V '"msm_csid0":0 [fmt:SRGGB10_1X10/1920x1080]' + media-ctl -d /dev/media0 -V '"msm_csid0":1 [fmt:SRGGB10_1X10/1920x1080]' + media-ctl -d /dev/media0 -V '"msm_vfe0_rdi0":0 [fmt:SRGGB10_1X10/1920x1080]' + media-ctl -d /dev/media0 -V '"msm_vfe0_rdi0":1 [fmt:SRGGB10_1X10/1920x1080]' + media-ctl -d /dev/media0 -p + grep -o 'imx586 [0-9a-f-]*' + head -1 + S='imx586 12-001a' + media-ctl -d /dev/media0 -e 'imx586 12-001a' + SD=/dev/v4l-subdev17 + '[' -n ] + '[' -n ] + media-ctl -d /dev/media0 -e msm_vfe0_video0 + V=/dev/video0 + v4l2-ctl -d /dev/video0 '--set-fmt-video=width=1920,height=1080,pixelformat=pRAA' + rm -f /tmp/f3000.raw + timeout 20 v4l2-ctl -d /dev/video0 '--stream-mmap=3' '--stream-count=1' '--stream-to=/tmp/f3000.raw' < + ls -l /tmp/f3000.raw -rw-r--r-- 1 user user 2592000 Aug 2 09:19 /tmp/f3000.rawS Всё ясно: у тебя на телефоне лежит вчерашняя версия скрипта, где 1920×1080 зашиты, а сброса флипов нет. Видно по трассировке — переменные называются S/SD, поиск сенсора идёт после установки форматов, и проверок [ -n ... ] только две. Клади новый: cat > ~/lanekit/capture.sh <<'EOF' #!/bin/sh M=${M:-/dev/media0} W=${W:-8000} H=${H:-6000} OUT=${1:-/tmp/frame.raw} sudo pkill -f wireplumber 2>/dev/null sudo pkill -f pipewire 2>/dev/null sleep 1 SENSOR=$(media-ctl -d $M -p 2>/dev/null | grep -o 'imx586 [0-9a-f-]*' | head -1) [ -n "$SENSOR" ] || { echo "нет imx586 в графе"; exit 1; } SD=$(media-ctl -d $M -e "$SENSOR") v4l2-ctl -d "$SD" --set-ctrl horizontal_flip=0,vertical_flip=0 2>/dev/null media-ctl -d $M -r media-ctl -d $M -l '"msm_csiphy0":1->"msm_csid0":0[1]' media-ctl -d $M -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]' for e in "\"$SENSOR\":0" '"msm_csiphy0":0' '"msm_csiphy0":1' \ '"msm_csid0":0' '"msm_csid0":1' '"msm_vfe0_rdi0":0' '"msm_vfe0_rdi0":1'; do media-ctl -d $M -V "$e [fmt:SRGGB10_1X10/${W}x${H}]" || echo "rejected: $e" done [ -n "$EXPOSURE" ] && v4l2-ctl -d "$SD" --set-ctrl exposure=$EXPOSURE [ -n "$GAIN" ] && v4l2-ctl -d "$SD" --set-ctrl analogue_gain=$GAIN [ -n "$FOCUS" ] && v4l2-ctl -d "$SD" --set-ctrl focus_absolute=$FOCUS 2>/dev/null V=$(media-ctl -d $M -e msm_vfe0_video0) v4l2-ctl -d "$V" --set-fmt-video=width=$W,height=$H,pixelformat=pRAA >/dev/null rm -f "$OUT" timeout 20 v4l2-ctl -d "$V" --stream-mmap=3 --stream-count=1 --stream-to="$OUT" ls -l "$OUT" EOF И повтори обе съёмки: W=1920 H=1080 EXPOSURE=1200 GAIN=400 sh ~/lanekit/capture.sh /tmp/f1080.raw W=4000 H=3000 EXPOSURE=3006 GAIN=960 sh ~/lanekit/capture.sh /tmp/f3000.raw Ждём 2 592 000 и 15 024 000 байт. 💰 8.17₽ · ⬇️ 210.1k / ⬆️ 2.1k · opus-5 · max · 27сЫ qcom-sm7150:~$ W=1920 H=1080 EXPOSURE=1200 GAIN=400 sh ~/lanekit/capture.sh /tmp/f1080.raw < -rw-r--r-- 1 user user 2592000 Aug 2 09:20 /tmp/f1080.raw qcom-sm7150:~$ W=4000 H=3000 EXPOSURE=3006 GAIN=960 sh ~/lanekit/capture.sh /tmp/f3000.raw < -rw-r--r-- 1 user user 15024000 Aug 2 09:20 /tmp/f3000.rawS Оба правильные. Смотрим глазами: cd ~/lanekit ./raw10preview /tmp/f1080.raw /tmp/p1080.ppm 1920 1080 rggb 2 && convert /tmp/p1080.ppm /tmp/p1080.png ./raw10preview /tmp/f3000.raw /tmp/p3000.ppm 4000 3000 rggb 4 && convert /tmp/p3000.ppm /tmp/p3000.png ls -l /tmp/p1080.png /tmp/p3000.png Если оба нормальные — значит сброс флипов встал на место и режимы переключаются как надо. Кидай картинки, а дальше сразу займёмся libcamera: найдём узел объектива и снимем серию с фокусом на ходу. 💰 6.46₽ · ⬇️ 212.5k / ⬆️ 605 · opus-5 · max · 10сЫ S Так и должно быть: в режиме 1080p кадр вчетверо короче по времени (frame length 1262 строки против 3054), поэтому выдержка физически упирается примерно в 1240 строк — почти столько ты и поставил. Дальше добирать можно только усилением: W=1920 H=1080 EXPOSURE=1240 GAIN=896 sh ~/lanekit/capture.sh /tmp/f1080b.raw Теперь libcamera. Сперва найдём узел объектива: for d in /dev/v4l-subdev*; do v4l2-ctl -d $d --list-ctrls 2>/dev/null | grep -q focus_absolute && echo "объектив: $d"; done Потом снимаем серию и двигаем фокус прямо во время съёмки — если выставить заранее, драйвер объектива успевает уснуть и линза возвращается в исходное: LENS=/dev/v4l-subdevN rm -f /tmp/lc_*.rgb cam -c 1 --capture=40 --file=/tmp/lc_#.rgb & sleep 3 v4l2-ctl -d $LENS --set-ctrl focus_absolute=600 wait convert -size 1920x1080 -depth 8 bgr:/tmp/lc_39.rgb /tmp/lc39.png && ls -l /tmp/lc39.png Наведи на текст в полуметре. Если резкость появится — останется только цвет, и это уже вопрос настроечного файла, а не пайплайна. 💰 6.14₽ · ⬇️ 213.1k / ⬆️ 945 · opus-5 · max · 17сЫ S Так это и есть развилка: резкость мы получали своим путём, руками двигая линзу через v4l2-ctl. А libcamera мотор объектива не трогает вообще — в программном ISP автофокуса нет, и линза всё время стоит там, где её оставили после включения. Поэтому наши кадры выходили резкими, а cam снимал размыто на той же камере. Отсюда и предложение: не менять ничего в libcamera, а просто подвинуть фокус, пока она снимает. Если после этого её кадр станет резким — значит весь пайплайн исправен и остаётся только цвет. Если фокус ты уже ставил именно во время работы cam и картинка всё равно мыльная — тогда дело не в линзе, и я полезу смотреть, как программный ISP собирает кадр: там свой демозаик, и при неправильном порядке байеровских пикселей картинка выглядит именно замыленной, с цветной сеткой по краям контрастных границ. 💰 6.13₽ · ⬇️ 214.2k / ⬆️ 775 · opus-5 · max · 18с
Ы S Это была заглушка — надо подставить найденный узел. Давай сразу одним куском, без ручной подстановки: LENS=$(for d in /dev/v4l-subdev*; do v4l2-ctl -d $d --list-ctrls 2>/dev/null | grep -q focus_absolute && { echo $d; break; }; done) echo "объектив: $LENS" rm -f /tmp/lc_*.rgb cam -c 1 --capture=40 --file=/tmp/lc_#.rgb & sleep 3 v4l2-ctl -d $LENS --set-ctrl focus_absolute=600 wait convert -size 1920x1080 -depth 8 bgr:/tmp/lc_39.rgb /tmp/lc39.png && ls -l /tmp/lc39.png Если строка «объектив:» окажется пустой — значит узел dw9768 в системе не поднялся, и тогда сначала смотрим dmesg | grep -i dw976. 💰 5.90₽ · ⬇️ 215.0k / ⬆️ 631 · opus-5 · max · 10сЫ S Нет, не снимает — 40 кадров при 30 в секунду должны улететь за полторы секунды. Жми Ctrl+C и смотрим, на чём встало: dmesg | tail -25 ls -l /tmp/lc_*.rgb 2>/dev/null | tail -3 И повтори коротко с логом самой libcamera: LIBCAMERA_LOG_LEVELS=*:INFO cam -c 1 --capture=4 --file=/tmp/lc_#.rgb 2>&1 | tail -30 Скорее всего наши ручные съёмки оставили граф в состоянии, которое ей не нравится: мы принудительно ставили формат 4000×3000 и пересобирали связи, а она ожидает настроить всё сама. Если так — вылечится сбросом графа перед запуском: media-ctl -d /dev/media0 -r 💰 6.46₽ · ⬇️ 215.9k / ⬆️ 1.1k · opus-5 · max · 19сЫ [ 937.317038] csiphy_link_setup called [ 937.317043] qcom-camss ace0000.camss: csid_link_setup: Enabled CSID virtual channels mask 0x1 [ 937.341334] video_prepare_streaming called [ 937.342149] csiphy_reset id 3 with base 000000008d8ddf37 and offset 2048 [ 937.349478] qcom-camss ace0000.camss: CSIPHY 3PH HW Version = 0x40010000 [ 937.349733] Writing reset_bits=3f9f to vfe->base=00000000a8151b8c with id 0 [ 937.349747] vfe irq handled! [ 937.349805] qcom-camss ace0000.camss: VFE:0 HW Version = 1.3.0 [ 937.349857] csid_reset called [ 937.349889] qcom-camss ace0000.camss: CSID:0 HW Version = 2.0.0 [ 937.349909] qcom-camss ace0000.camss: validating link "msm_csid0":1 -> "msm_vfe0_rdi0":0 [ 937.349915] qcom-camss ace0000.camss: validating stream "msm_csid0":1:0 -> "msm_vfe0_rdi0":0:0 [ 937.349923] qcom-camss ace0000.camss: validating link "msm_csiphy3":1 -> "msm_csid0":0 [ 937.349928] qcom-camss ace0000.camss: validating stream "msm_csiphy3":1:0 -> "msm_csid0":0:0 [ 937.349935] qcom-camss ace0000.camss: validating link "ov8856 13-0036":0 -> "msm_csiphy3":0 [ 937.349939] qcom-camss ace0000.camss: validating stream "ov8856 13-0036":0:0 -> "msm_csiphy3":0:0 [ 937.349947] qcom-camss ace0000.camss: msm_vfe0_video0: format is (1640x1232 pBAA little-endian (0x41414270)/1p field:1), trying (1640x1232 pBAA little-endian (0x41414270)/1p field:1) [ 937.349963] vfe_reserve_wm ret=0 [ 937.349979] qcom-camss ace0000.camss: receiver: lanes 2, assignment 0x10, phy 3, cfg0 0x00300101 [ 937.349987] qcom-camss ace0000.camss: csiphy: link 360000000 Hz, timer 300000000 Hz, settle count 22 [ 937.349992] qcom-camss ace0000.camss: csiphy: lane mask 0x85 from 2 lanes [ 937.350073] qcom-camss ace0000.camss: csiphy: settle high bytes 00 00 00 00 ff [ 1020.840236] qcom_q6v5_pas 62400000.remoteproc: Handover signaled, but it already happened [ 1065.306063] Writing reset_bits=3f9f to vfe->base=00000000a8151b8c with id 0 [ 1065.306120] vfe irq handled!S Оно снимало телевик! Смотри на граф в логе: ov8856 13-0036 → msm_csiphy3 → msm_csid0 → msm_vfe0_rdi0, формат 1640×1232. То есть cam -c 1 — это у libcamera вторая камера, а не широкая. Отсюда и минута ожидания: телевик кадров не даёт, мы это только что выяснили. Заодно два полезных факта из этого же лога: assignment 0x10 и lane mask 0x85 — наша правка дерева доехала, линии теперь правильные. И версия PHY читается нормально (0x40010000), то есть утренний ноль был именно из-за холодного старта. Выбери широкую по списку: cam -l Там будут две строки вида 1: 'imx586 ...' и 2: 'ov8856 ...' — бери индекс с imx586 и повтори: LENS=$(for d in /dev/v4l-subdev*; do v4l2-ctl -d $d --list-ctrls 2>/dev/null | grep -q focus_absolute && { echo $d; break; }; done) rm -f /tmp/lc_*.rgb cam -c 2 --capture=40 --file=/tmp/lc_#.rgb & # подставь нужный индекс sleep 3 v4l2-ctl -d $LENS --set-ctrl focus_absolute=600 wait convert -size 1920x1080 -depth 8 bgr:/tmp/lc_39.rgb /tmp/lc39.png && ls -l /tmp/lc39.png 💰 7.21₽ · ⬇️ 218.0k / ⬆️ 1.2k · opus-5 · max · 21сЫ [0:19:01.069409524] [3891] INFO Camera camera_manager.cpp:340 libcamera v0.7.1 [0:19:01.115365700] [3892] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 2 on pad 0/0: Not a tty [0:19:01.115424502] [3892] WARN CameraSensor camera_sensor_legacy.cpp:402 'ov8856 13-0036': The PixelArraySize property has been defaulted to 1640x1232 [0:19:01.115441013] [3892] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 1 on pad 0/0: Not a tty [0:19:01.115457471] [3892] WARN CameraSensor camera_sensor_legacy.cpp:413 'ov8856 13-0036': The PixelArrayActiveAreas property has been defaulted to (0, 0)/1640x1232 [0:19:01.115474294] [3892] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 0 on pad 0/0: Not a tty [0:19:01.115488878] [3892] WARN CameraSensor camera_sensor_legacy.cpp:421 'ov8856 13-0036': Failed to retrieve the sensor crop rectangle [0:19:01.115500336] [3892] WARN CameraSensor camera_sensor_legacy.cpp:427 'ov8856 13-0036': The sensor kernel driver needs to be fixed [0:19:01.115512003] [3892] WARN CameraSensor camera_sensor_legacy.cpp:429 'ov8856 13-0036': See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information [0:19:01.115761432] [3892] WARN CameraSensorProperties camera_sensor_properties.cpp:538 No static properties available for 'ov8856' [0:19:01.115787161] [3892] WARN CameraSensorProperties camera_sensor_properties.cpp:540 Please consider updating the camera sensor properties database [0:19:01.115809557] [3892] WARN CameraSensor camera_sensor_legacy.cpp:502 'ov8856 13-0036': No sensor delays found in static properties. Assuming unverified defaults. [0:19:01.116314612] [3892] WARN CameraSensorProperties camera_sensor_properties.cpp:538 No static properties available for 'imx586' [0:19:01.116344612] [3892] WARN CameraSensorProperties camera_sensor_properties.cpp:540 Please consider updating the camera sensor properties database [0:19:01.116388831] [3892] WARN CameraSensor camera_sensor_legacy.cpp:502 'imx586 12-001a': No sensor delays found in static properties. Assuming unverified defaults. [0:19:01.118515147] [3892] WARN IPAProxy ipa_proxy.cpp:196 Configuration file 'ov8856.yaml' not found for IPA module 'simple', falling back to '/usr/share/libcamera/ipa/simple/uncalibrated.yaml' [0:19:01.118566033] [3892] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 0 on pad 0/0: Not a tty [0:19:01.118583585] [3892] WARN CameraSensor camera_sensor_legacy.cpp:881 'ov8856 13-0036': The analogue crop rectangle has been defaulted to the active area size [0:19:01.118629523] [3892] WARN IPASoft soft_simple.cpp:104 IPASoft: Failed to create camera sensor helper for ov8856 [0:19:01.119068640] [3892] INFO Camera camera_manager.cpp:223 Adding camera '/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36' for pipeline handler simple [0:19:01.119662029] [3892] WARN IPAProxy ipa_proxy.cpp:196 Configuration file 'imx586.yaml' not found for IPA module 'simple', falling back to '/usr/share/libcamera/ipa/simple/uncalibrated.yaml' [0:19:01.119720988] [3892] WARN IPASoft soft_simple.cpp:104 IPASoft: Failed to create camera sensor helper for imx586 [0:19:01.120157188] [3892] INFO Camera camera_manager.cpp:223 Adding camera '/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a' for pipeline handler simple Available cameras: 1: Internal back camera (/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36) 2: Internal back camera (/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a)S Два вывода из лога. Первый: это не наш libcamera. Все вчерашние предупреждения вернулись — «No static properties available for imx586», «Failed to create camera sensor helper». Значит запускается системная сборка из /usr, а наша пропатченная лежит в /usr/local и после перезагрузки перестала подхватываться. Второй: широкая камера — это индекс 2 (i2c-bus@0/camera@1a), а первая как раз телевик. Проверь, где что: which -a cam; ls -l /usr/local/bin/cam 2>/dev/null; ls /usr/local/lib/*/libcamera.so* /usr/local/lib/libcamera.so* 2>/dev/null | head И запусти нашей сборкой явно: export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib/aarch64-linux-gnu /usr/local/bin/cam -l 2>&1 | grep -E "properties|helper|^[0-9]:" Если предупреждения про imx586 исчезли — сборка подхватилась, и тогда сразу съёмка с фокусом: LENS=$(for d in /dev/v4l-subdev*; do v4l2-ctl -d $d --list-ctrls 2>/dev/null | grep -q focus_absolute && { echo $d; break; }; done) rm -f /tmp/lc_*.rgb /usr/local/bin/cam -c 2 --capture=40 --file=/tmp/lc_#.rgb & sleep 3 v4l2-ctl -d $LENS --set-ctrl focus_absolute=600 wait convert -size 1920x1080 -depth 8 bgr:/tmp/lc_39.rgb /tmp/lc39.png && ls -l /tmp/lc39.png 💰 8.04₽ · ⬇️ 221.1k / ⬆️ 1.6k · opus-5 · max · 22сЫ /usr/local/bin/cam -l [0:20:03.817512167] [3953] INFO Camera camera_manager.cpp:340 libcamera v0.7.1 [0:20:03.871970442] [3954] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 2 on pad 0/0: Not a tty [0:20:03.872054765] [3954] WARN CameraSensor camera_sensor_legacy.cpp:402 'ov8856 13-0036': The PixelArraySize property has been defaulted to 1640x1232 [0:20:03.872076380] [3954] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 1 on pad 0/0: Not a tty [0:20:03.872097422] [3954] WARN CameraSensor camera_sensor_legacy.cpp:413 'ov8856 13-0036': The PixelArrayActiveAreas property has been defaulted to (0, 0)/1640x1232 [0:20:03.872119713] [3954] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 0 on pad 0/0: Not a tty [0:20:03.872135390] [3954] WARN CameraSensor camera_sensor_legacy.cpp:421 'ov8856 13-0036': Failed to retrieve the sensor crop rectangle [0:20:03.872153047] [3954] WARN CameraSensor camera_sensor_legacy.cpp:427 'ov8856 13-0036': The sensor kernel driver needs to be fixed [0:20:03.872167630] [3954] WARN CameraSensor camera_sensor_legacy.cpp:429 'ov8856 13-0036': See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information [0:20:03.872462424] [3954] WARN CameraSensorProperties camera_sensor_properties.cpp:538 No static properties available for 'ov8856' [0:20:03.872488778] [3954] WARN CameraSensorProperties camera_sensor_properties.cpp:540 Please consider updating the camera sensor properties database [0:20:03.872513622] [3954] WARN CameraSensor camera_sensor_legacy.cpp:502 'ov8856 13-0036': No sensor delays found in static properties. Assuming unverified defaults. [0:20:03.873057687] [3954] WARN CameraSensorProperties camera_sensor_properties.cpp:538 No static properties available for 'imx586' [0:20:03.873084615] [3954] WARN CameraSensorProperties camera_sensor_properties.cpp:540 Please consider updating the camera sensor properties database [0:20:04.314528137] [3954] WARN CameraSensor camera_sensor_legacy.cpp:502 'imx586 12-001a': No sensor delays found in static properties. Assuming unverified defaults. [0:20:04.325256792] [3954] WARN IPAProxy ipa_proxy.cpp:196 Configuration file 'ov8856.yaml' not found for IPA module 'simple', falling back to '/usr/share/libcamera/ipa/simple/uncalibrated.yaml' [0:20:04.325471689] [3954] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 0 on pad 0/0: Not a tty [0:20:04.325566689] [3954] WARN CameraSensor camera_sensor_legacy.cpp:881 'ov8856 13-0036': The analogue crop rectangle has been defaulted to the active area size [0:20:04.325763149] [3954] WARN IPASoft soft_simple.cpp:104 IPASoft: Failed to create camera sensor helper for ov8856 [0:20:04.327715660] [3954] INFO Camera camera_manager.cpp:223 Adding camera '/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36' for pipeline handler simple [0:20:04.330399373] [3954] WARN IPAProxy ipa_proxy.cpp:196 Configuration file 'imx586.yaml' not found for IPA module 'simple', falling back to '/usr/share/libcamera/ipa/simple/uncalibrated.yaml' [0:20:04.330690832] [3954] WARN IPASoft soft_simple.cpp:104 IPASoft: Failed to create camera sensor helper for imx586 [0:20:04.333111159] [3954] INFO Camera camera_manager.cpp:223 Adding camera '/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a' for pipeline handler simple Available cameras: 1: Internal back camera (/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36) 2: Internal back camera (/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a)Ы S Значит подхватывается всё равно системная библиотека — двоичный файл наш, а libcamera.so он берёт из /usr. Проверим: ldd /usr/local/bin/cam | grep -i camera ls -l /usr/local/lib/*/libcamera.so* /usr/local/lib/libcamera.so* 2>/dev/null ls -l /usr/lib/libcamera.so* 2>/dev/null | head -3 ls -d /usr/local/lib/*/libcamera 2>/dev/null Обрати внимание на даты: у нашей сборки они вчерашние, у системной — из пакета. Если наша библиотека на месте, надо ещё указать, откуда брать модули IPA — иначе он и их возьмёт системные: L=$(dirname $(ls /usr/local/lib/*/libcamera.so.* /usr/local/lib/libcamera.so.* 2>/dev/null | head -1)) export LD_LIBRARY_PATH=$L export LIBCAMERA_IPA_MODULE_PATH=$L/libcamera /usr/local/bin/cam -l 2>&1 | grep -E "properties|helper|^[0-9]:" Предупреждения про imx586 должны исчезнуть — тогда среда правильная, и можно снимать. Если же выяснится, что в /usr/local библиотеки вообще нет, значит вчера мы собрали, но не установили, и я дам команду доустановить. 💰 7.95₽ · ⬇️ 224.5k / ⬆️ 1.3k · opus-5 · max · 21сЫ S Ясно: наш cam слинкован с системной библиотекой из /lib, поэтому патчей и не видит. Посмотрим, что осталось от вчерашней сборки: ls -d ~/libcamera ~/libcamera/build 2>/dev/null ls -l ~/libcamera/build/src/libcamera/libcamera.so* 2>/dev/null | head -3 grep -c "imx586" ~/libcamera/src/libcamera/sensor/camera_sensor_properties.cpp 2>/dev/null ls -l /usr/local/lib/ 2>/dev/null | head Если исходник пропатчен и в build лежит свежая библиотека — проще всего запускать прямо из дерева сборки, без установки: cd ~/libcamera LD_LIBRARY_PATH=$PWD/build/src/libcamera:$PWD/build/src/libcamera/base \ LIBCAMERA_IPA_MODULE_PATH=$PWD/build/src/ipa \ LIBCAMERA_IPA_FORCE_ISOLATION=0 \ ./build/src/apps/cam/cam -l 2>&1 | grep -E "properties|helper|^[0-9]:" А если сборки не осталось — тогда переустановим поверх системной, с префиксом /usr, чтобы больше не путаться. 💰 7.13₽ · ⬇️ 225.9k / ⬆️ 1.3k · opus-5 · max · 21сЫ S Разумно — так и сделаем, чтобы всё в системе (включая pipewire) видело пропатченную версию. cd ~/libcamera grep -m1 -A2 "^project(" meson.build # версия должна быть 0.7.x, иначе имя so не совпадёт Если версия сходится, ставим поверх системной. Сначала запомним, чем откатываться: apk info -W /usr/lib/libcamera.so.0.7 2>/dev/null || apk info -W /lib/libcamera.so.0.7 Дальше сборка с правильным префиксом (если каталога build нет — первая команда его создаст): meson setup build --prefix=/usr --libdir=lib --buildtype=release 2>/dev/null || \ meson configure build --prefix=/usr --libdir=lib ninja -C build sudo ninja -C build install И проверка: ldd $(which cam) | grep -i camera cam -l 2>&1 | grep -E "properties|helper|^[0-9]:" Должно исчезнуть всё про imx586/ov8856 и остаться только список камер. Откатиться, если что, одной командой: sudo apk fix libcamera вернёт файлы из пакета. 💰 7.09₽ · ⬇️ 227.2k / ⬆️ 1.2k · opus-5 · max · 20сЫ [0:28:20.723190277] [5459] WARN CameraSensor camera_sensor_legacy.cpp:502 'ov8856 13-0036': No sensor delays found in static properties. Assuming unverified defaults. 1: Internal back camera (/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36) 2: Internal back camera (/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a)S Отлично — про imx586 предупреждений больше нет, значит наша сборка встала системной. У ov8856 осталась только жалоба на задержки конвейера, это мелочь и правится потом. Снимаем широкой с фокусом на ходу: LENS=$(for d in /dev/v4l-subdev*; do v4l2-ctl -d $d --list-ctrls 2>/dev/null | grep -q focus_absolute && { echo $d; break; }; done) echo "объектив: $LENS" rm -f /tmp/lc_*.rgb cam -c 2 --capture=40 --file=/tmp/lc_#.rgb & sleep 3 v4l2-ctl -d $LENS --set-ctrl focus_absolute=600 wait ls -l /tmp/lc_*.rgb | tail -2 convert -size 1920x1080 -depth 8 bgr:/tmp/lc_39.rgb /tmp/lc39.png && ls -l /tmp/lc39.png Наведи на текст в полуметре. Присылай lc39.png — по нему сразу будет видно, что осталось: резкость мы этим чиним, а если цвет поедет, то это уже настроечный файл. 💰 6.44₽ · ⬇️ 228.7k / ⬆️ 602 · opus-5 · max · 11сЫ объектив: /dev/v4l-subdev18 [0:29:05.924783733] [5533] INFO Camera camera_manager.cpp:340 libcamera v0.0.0+1-244572db-dirty (2026-08-02T09:37:10GMT) [0:29:05.932660062] [5535] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 2 on pad 0/0: Not a tty [0:29:05.932751469] [5535] WARN CameraSensor camera_sensor_legacy.cpp:402 'ov8856 13-0036': The PixelArraySize property has been defaulted to 1640x1232 [0:29:05.932778396] [5535] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 1 on pad 0/0: Not a tty [0:29:05.932801156] [5535] WARN CameraSensor camera_sensor_legacy.cpp:413 'ov8856 13-0036': The PixelArrayActiveAreas property has been defaulted to (0, 0)/1640x1232 [0:29:05.932828188] [5535] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 0 on pad 0/0: Not a tty [0:29:05.932848917] [5535] WARN CameraSensor camera_sensor_legacy.cpp:421 'ov8856 13-0036': Failed to retrieve the sensor crop rectangle [0:29:05.932868448] [5535] WARN CameraSensor camera_sensor_legacy.cpp:427 'ov8856 13-0036': The sensor kernel driver needs to be fixed [0:29:05.932905636] [5535] WARN CameraSensor camera_sensor_legacy.cpp:429 'ov8856 13-0036': See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information [0:29:05.933634128] [5535] WARN CameraSensor camera_sensor_legacy.cpp:502 'ov8856 13-0036': No sensor delays found in static properties. Assuming unverified defaults. [0:29:05.938520968] [5535] WARN IPAProxy ipa_proxy.cpp:196 Configuration file 'ov8856.yaml' not found for IPA module 'simple', falling back to '/usr/share/libcamera/ipa/simple/uncalibrated.yaml' [0:29:05.938790083] [5535] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov8856 13-0036': Unable to get rectangle 0 on pad 0/0: Not a tty [0:29:05.938937584] [5535] WARN CameraSensor camera_sensor_legacy.cpp:881 'ov8856 13-0036': The analogue crop rectangle has been defaulted to the active area size [0:29:05.960402813] [5536] INFO IPAProxySoftWorker soft_ipa_proxy_worker.cpp:443 Starting worker for IPA module /usr/lib/libcamera/ipa/ipa_soft_simple.so with IPC fd = 24 [0:29:05.964452567] [5535] INFO Camera camera_manager.cpp:223 Adding camera '/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36' for pipeline handler simple [0:29:05.966677678] [5535] WARN IPAProxy ipa_proxy.cpp:196 Configuration file 'imx586.yaml' not found for IPA module 'simple', falling back to '/usr/share/libcamera/ipa/simple/uncalibrated.yaml' [0:29:05.990261249] [5537] INFO IPAProxySoftWorker soft_ipa_proxy_worker.cpp:443 Starting worker for IPA module /usr/lib/libcamera/ipa/ipa_soft_simple.so with IPC fd = 29 [0:29:05.995499704] [5535] INFO Camera camera_manager.cpp:223 Adding camera '/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a' for pipeline handler simple Using camera /base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a as cam0 [0:29:05.995929028] [5533] INFO Camera camera.cpp:1216 configuring streams: (0) 7992x6000-ABGR8888/sRGB [0:29:05.996474916] [5537] INFO IPASoft soft_simple.cpp:258 IPASoft: Exposure 4-6010, gain 1-16 (0.15) [0:29:05.996942209] [5535] INFO SoftwareIsp software_isp.cpp:299 Input 8000x6000-BGGR-10-CSI2P stride 10000 [0:29:05.997289866] [5535] ERROR DmaBufAllocator dma_buf_allocator.cpp:153 Failed to create dma buf for frame-0: Invalid argument [0:29:05.997389815] [5535] ERROR DmaBufAllocator dma_buf_allocator.cpp:231 Unable to create buffer [0:29:05.997703722] [5533] ERROR Allocator framebuffer_allocator.cpp:97 Stream is not part of /base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a active configuration Can't allocate buffers Failed to start camera sessionS Теперь видно, что происходит: libcamera выбрала полное разрешение — 7992x6000, вход 8000x6000-BGGR-10. Кадр в ABGR8888 весит 192 МБ, и аллокатор dma-buf на таком размере отваливается с «Invalid argument». Вчера мы задавали размер явно, поэтому и работало. Задаём поток руками: LENS=/dev/v4l-subdev18 rm -f /tmp/lc_*.rgb cam -c 2 -s width=1920,height=1080,pixelformat=RGB888 --capture=40 --file=/tmp/lc_#.rgb & sleep 3 v4l2-ctl -d $LENS --set-ctrl focus_absolute=600 wait ls -l /tmp/lc_*.rgb | tail -2 convert -size 1920x1080 -depth 8 bgr:/tmp/lc_39.rgb /tmp/lc39.png && ls -l /tmp/lc39.png Кстати, в логе уже видно, что наш помощник сенсора заработал: строка IPASoft: Exposure 4-6010, gain 1-16 — это наши пределы выдержки и усиления, раньше их не было. 💰 7.54₽ · ⬇️ 231.3k / ⬆️ 1.1k · opus-5 · max · 17сЫ cam0: Capture 40 frames 1811.679601 (0.00 fps) cam0-stream0 seq: 000000 bytesused: 6220800 1811.712923 (30.01 fps) cam0-stream0 seq: 000001 bytesused: 6220800 1811.746126 (30.12 fps) cam0-stream0 seq: 000002 bytesused: 6220800 1811.779450 (30.01 fps) cam0-stream0 seq: 000003 bytesused: 6220800 1811.813072 (29.74 fps) cam0-stream0 seq: 000004 bytesused: 6220800 1811.846080 (30.30 fps) cam0-stream0 seq: 000005 bytesused: 6220800 1811.879662 (29.78 fps) cam0-stream0 seq: 000006 bytesused: 6220800 1811.912707 (30.26 fps) cam0-stream0 seq: 000007 bytesused: 6220800 1811.946052 (29.99 fps) cam0-stream0 seq: 000008 bytesused: 6220800 1811.979355 (30.03 fps) cam0-stream0 seq: 000009 bytesused: 6220800 1812.012667 (30.02 fps) cam0-stream0 seq: 000010 bytesused: 6220800 1812.046018 (29.98 fps) cam0-stream0 seq: 000011 bytesused: 6220800 1812.079308 (30.04 fps) cam0-stream0 seq: 000012 bytesused: 6220800 1812.112627 (30.01 fps) cam0-stream0 seq: 000013 bytesused: 6220800 1812.145966 (29.99 fps) cam0-stream0 seq: 000014 bytesused: 6220800 1812.179289 (30.01 fps) cam0-stream0 seq: 000015 bytesused: 6220800 1812.212607 (30.01 fps) cam0-stream0 seq: 000016 bytesused: 6220800 1812.245913 (30.02 fps) cam0-stream0 seq: 000017 bytesused: 6220800 1812.279362 (29.90 fps) cam0-stream0 seq: 000018 bytesused: 6220800 1812.312559 (30.12 fps) cam0-stream0 seq: 000019 bytesused: 6220800 1812.345873 (30.02 fps) cam0-stream0 seq: 000020 bytesused: 6220800 1812.379196 (30.01 fps) cam0-stream0 seq: 000021 bytesused: 6220800 1812.412534 (30.00 fps) cam0-stream0 seq: 000022 bytesused: 6220800 1812.445837 (30.03 fps) cam0-stream0 seq: 000023 bytesused: 6220800 1812.479157 (30.01 fps) cam0-stream0 seq: 000024 bytesused: 6220800 1812.512496 (29.99 fps) cam0-stream0 seq: 000025 bytesused: 6220800 1812.545919 (29.92 fps) cam0-stream0 seq: 000026 bytesused: 6220800 1812.579400 (29.87 fps) cam0-stream0 seq: 000027 bytesused: 6220800 1812.612601 (30.12 fps) cam0-stream0 seq: 000028 bytesused: 6220800 1812.645942 (29.99 fps) cam0-stream0 seq: 000029 bytesused: 6220800 1812.679318 (29.96 fps) cam0-stream0 seq: 000030 bytesused: 6220800 1812.712652 (30.00 fps) cam0-stream0 seq: 000031 bytesused: 6220800 1812.745800 (30.17 fps) cam0-stream0 seq: 000032 bytesused: 6220800 1812.779317 (29.84 fps) cam0-stream0 seq: 000033 bytesused: 6220800 1812.812500 (30.14 fps) cam0-stream0 seq: 000034 bytesused: 6220800 1812.845845 (29.99 fps) cam0-stream0 seq: 000035 bytesused: 6220800 1812.879181 (30.00 fps) cam0-stream0 seq: 000036 bytesused: 6220800 1812.912394 (30.11 fps) cam0-stream0 seq: 000037 bytesused: 6220800 1812.945866 (29.88 fps) cam0-stream0 seq: 000038 bytesused: 6220800 1812.979090 (30.10 fps) cam0-stream0 seq: 000039 bytesused: 6220800 -rw-r--r-- 1 user user 6220800 Aug 2 09:40 /tmp/lc_cam0-stream0-000038.rgb -rw-r--r-- 1 user user 6220800 Aug 2 09:40 /tmp/lc_cam0-stream0-000039.rgb WARNING: The convert command is deprecated in IMv7, use "magick" instead of "convert" or "magick convert" convert: unable to open image '/tmp/lc_39.rgb': No such file or directory @ error/blob.c/OpenBlob/3655. convert: no images defined `/tmp/lc39.png' @ error/deprecate.c/ConvertImageCommand/3375.S Кадры пошли ровно 30 в секунду, но 40 штук улетели за полторы секунды — то есть фокус я подвинул уже после съёмки. И имя файла у cam своё, # разворачивается в полное. Сделаем аккуратнее: подержим объектив включённым через открытый дескриптор (драйвер усыпляет мотор, как только последний закрывает узел, и линза уезжает в исходное), выставим фокус и снимем всего десяток кадров. LENS=/dev/v4l-subdev18 rm -f /tmp/lc_*.rgb exec 9<>$LENS # держим мотор под питанием v4l2-ctl -d $LENS --set-ctrl focus_absolute=600 cam -c 2 -s width=1920,height=1080,pixelformat=RGB888 --capture=10 --file=/tmp/lc_#.rgb exec 9>&- F=$(ls -t /tmp/lc_*.rgb | head -1) magick -size 1920x1080 -depth 8 bgr:$F /tmp/lc.png && ls -l /tmp/lc.png Если картинка выйдет резкой — значит остаётся только цвет. Если всё ещё мыло, попробуй прямо во время съёмки прогнать несколько значений, чтобы исключить неудачную дистанцию: exec 9<>$LENS cam -c 2 -s width=1920,height=1080,pixelformat=RGB888 --capture=120 --file=/tmp/lcs_#.rgb & for f in 200 400 600 800; do sleep 0.8; v4l2-ctl -d $LENS --set-ctrl focus_absolute=$f; done wait; exec 9>&- 💰 9.26₽ · ⬇️ 234.2k / ⬆️ 2.4k · opus-5 · max · 38сЫ S Проверим, чёрная она по-настоящему или просто тёмная — глазами на глаз это не отличить: F=$(ls -t /tmp/lc_*.rgb | head -1) python3 -c " d=open('$F','rb').read(); print('мин',min(d),'макс',max(d),'среднее',round(sum(d)/len(d),1))" Если максимум ноль — кадр действительно пустой. Если максимум хоть сколько-то есть, то это просто недоэкспозиция: у программного ISP автоэкспозиция сходится за десяток-другой кадров, а мы снимали всего десять. Тогда дай ей время: LENS=/dev/v4l-subdev18 rm -f /tmp/lc_*.rgb exec 9<>$LENS v4l2-ctl -d $LENS --set-ctrl focus_absolute=600 cam -c 2 -s width=1920,height=1080,pixelformat=RGB888 --capture=60 --file=/tmp/lc_#.rgb exec 9>&- F=$(ls -t /tmp/lc_*.rgb | head -1) magick -size 1920x1080 -depth 8 bgr:$F /tmp/lc.png И для сравнения — наш собственный путь на том же сюжете, он заведомо рабочий: W=1920 H=1080 EXPOSURE=1240 GAIN=896 sh ~/lanekit/capture.sh /tmp/f1080c.raw cd ~/lanekit && ./raw10preview /tmp/f1080c.raw /tmp/p.ppm 1920 1080 rggb 2 && magick /tmp/p.ppm /tmp/p1080c.png Если наш кадр видно, а у libcamera чернота — значит дело в её управлении выдержкой, и я знаю, куда смотреть. И на всякий случай: телефон сейчас не лежит объективом вниз? 💰 7.94₽ · ⬇️ 236.7k / ⬆️ 1.4k · opus-5 · max · 29сЫ S Полный ноль — значит либо сенсор отдаёт темноту, либо ISP съедает всё вычитанием уровня чёрного. Разница принципиальная, и меряется она одним запуском: посмотрим, что libcamera выставляет сенсору прямо во время съёмки. SD=$(media-ctl -d /dev/media0 -e "imx586 12-001a") LENS=/dev/v4l-subdev18 rm -f /tmp/lc_*.rgb exec 9<>$LENS v4l2-ctl -d $LENS --set-ctrl focus_absolute=600 cam -c 2 -s width=1920,height=1080,pixelformat=RGB888 --capture=90 --file=/tmp/lc_#.rgb & sleep 2; echo "-- через 2 с:"; v4l2-ctl -d $SD --get-ctrl exposure,analogue_gain,horizontal_flip,vertical_flip sleep 1; echo "-- через 3 с:"; v4l2-ctl -d $SD --get-ctrl exposure,analogue_gain wait; exec 9>&- F=$(ls -t /tmp/lc_*.rgb | head -1) python3 -c "d=open('$F','rb').read(); print('макс',max(d),'среднее',round(sum(d)/len(d),2))" Что я жду увидеть: если автоматика работает, выдержка за пару секунд уползёт к максимуму режима (около 1240 строк), а усиление к 960. Если же она стоит на 4 — значит IPA вообще не пишет в сенсор, и копать надо туда. Кстати, вчера картинка была хоть и плохая, но видимая — и это важная зацепка: вчера работала системная libcamera без нашего помощника, то есть без уровня чёрного, и ничего не вычиталось. Сегодня помощник появился, и вместе с ним вычитание 16 единиц из восьмибитного кадра. В тёмной сцене этого хватит, чтобы всё ушло в ноль. 💰 23.14₽ · ⬇️ 720.1k / ⬆️ 4.4k · opus-5 · max · 75сЫ cam0: Capture 90 frames 2196.868027 (0.00 fps) cam0-stream0 seq: 000000 bytesused: 6220800 2196.901477 (29.90 fps) cam0-stream0 seq: 000001 bytesused: 6220800 2196.934740 (30.06 fps) cam0-stream0 seq: 000002 bytesused: 6220800 2196.968110 (29.97 fps) cam0-stream0 seq: 000003 bytesused: 6220800 2197.001322 (30.11 fps) cam0-stream0 seq: 000004 bytesused: 6220800 2197.034670 (29.99 fps) cam0-stream0 seq: 000005 bytesused: 6220800 2197.068159 (29.86 fps) cam0-stream0 seq: 000006 bytesused: 6220800 2197.101506 (29.99 fps) cam0-stream0 seq: 000007 bytesused: 6220800 2197.134708 (30.12 fps) cam0-stream0 seq: 000008 bytesused: 6220800 2197.168118 (29.93 fps) cam0-stream0 seq: 000009 bytesused: 6220800 2197.201225 (30.21 fps) cam0-stream0 seq: 000010 bytesused: 6220800 2197.234638 (29.93 fps) cam0-stream0 seq: 000011 bytesused: 6220800 2197.267906 (30.06 fps) cam0-stream0 seq: 000012 bytesused: 6220800 2197.301070 (30.15 fps) cam0-stream0 seq: 000013 bytesused: 6220800 2197.334645 (29.78 fps) cam0-stream0 seq: 000014 bytesused: 6220800 2197.367964 (30.01 fps) cam0-stream0 seq: 000015 bytesused: 6220800 2197.401297 (30.00 fps) cam0-stream0 seq: 000016 bytesused: 6220800 2197.434511 (30.11 fps) cam0-stream0 seq: 000017 bytesused: 6220800 2197.467667 (30.16 fps) cam0-stream0 seq: 000018 bytesused: 6220800 2197.501154 (29.86 fps) cam0-stream0 seq: 000019 bytesused: 6220800 2197.534599 (29.90 fps) cam0-stream0 seq: 000020 bytesused: 6220800 2197.567945 (29.99 fps) cam0-stream0 seq: 000021 bytesused: 6220800 2197.601116 (30.15 fps) cam0-stream0 seq: 000022 bytesused: 6220800 2197.634574 (29.89 fps) cam0-stream0 seq: 000023 bytesused: 6220800 2197.667629 (30.25 fps) cam0-stream0 seq: 000024 bytesused: 6220800 2197.701264 (29.73 fps) cam0-stream0 seq: 000025 bytesused: 6220800 2197.734541 (30.05 fps) cam0-stream0 seq: 000026 bytesused: 6220800 2197.767680 (30.18 fps) cam0-stream0 seq: 000027 bytesused: 6220800 2197.801140 (29.89 fps) cam0-stream0 seq: 000028 bytesused: 6220800 2197.834477 (30.00 fps) cam0-stream0 seq: 000029 bytesused: 6220800 2197.867817 (29.99 fps) cam0-stream0 seq: 000030 bytesused: 6220800 2197.901108 (30.04 fps) cam0-stream0 seq: 000031 bytesused: 6220800 2197.934288 (30.14 fps) cam0-stream0 seq: 000032 bytesused: 6220800 2197.967708 (29.92 fps) cam0-stream0 seq: 000033 bytesused: 6220800 2198.001035 (30.01 fps) cam0-stream0 seq: 000034 bytesused: 6220800 2198.034368 (30.00 fps) cam0-stream0 seq: 000035 bytesused: 6220800 2198.067566 (30.12 fps) cam0-stream0 seq: 000036 bytesused: 6220800 2198.100922 (29.98 fps) cam0-stream0 seq: 000037 bytesused: 6220800 2198.134443 (29.83 fps) cam0-stream0 seq: 000038 bytesused: 6220800 2198.167532 (30.22 fps) cam0-stream0 seq: 000039 bytesused: 6220800 2198.200811 (30.05 fps) cam0-stream0 seq: 000040 bytesused: 6220800 2198.234227 (29.93 fps) cam0-stream0 seq: 000041 bytesused: 6220800 2198.267591 (29.97 fps) cam0-stream0 seq: 000042 bytesused: 6220800 2198.300980 (29.95 fps) cam0-stream0 seq: 000043 bytesused: 6220800 2198.334087 (30.21 fps) cam0-stream0 seq: 000044 bytesused: 6220800 2198.367433 (29.99 fps) cam0-stream0 seq: 000045 bytesused: 6220800 2198.400699 (30.06 fps) cam0-stream0 seq: 000046 bytesused: 6220800 2198.434322 (29.74 fps) cam0-stream0 seq: 000047 bytesused: 6220800 2198.467442 (30.19 fps) cam0-stream0 seq: 000048 bytesused: 6220800 2198.500683 (30.08 fps) cam0-stream0 seq: 000049 bytesused: 6220800 -- через 2 с: 2198.534097 (29.93 fps) cam0-stream0 seq: 000050 bytesused: 6220800 exposure: 2260 horizontal_flip: 1 vertical_flip: 1 analogue_gain: 960 2198.567458 (29.98 fps) cam0-stream0 seq: 000051 bytesused: 6220800 2198.600719 (30.07 fps) cam0-stream0 seq: 000052 bytesused: 6220800 2198.634234 (29.84 fps) cam0-stream0 seq: 000053 bytesused: 6220800 2198.667583 (29.99 fps) cam0-stream0 seq: 000054 bytesused: 6220800 2198.700614 (30.27 fps) cam0-stream0 seq: 000055 bytesused: 6220800 2198.734105 (29.86 fps) cam0-stream0 seq: 000056 bytesused: 6220800 2198.767506 (29.94 fps) cam0-stream0 seq: 000057 bytesused: 6220800S
Ы 2198.800465 (30.34 fps) cam0-stream0 seq: 000058 bytesused: 6220800 [0:36:38.864768209] [6060] INFO Benchmark benchmark.cpp:89 Debayer processed 30 frames in 711840us, 23728 us/frame 2198.834043 (29.78 fps) cam0-stream0 seq: 000059 bytesused: 6220800 2198.867121 (30.23 fps) cam0-stream0 seq: 000060 bytesused: 6220800 2198.900599 (29.87 fps) cam0-stream0 seq: 000061 bytesused: 6220800 2198.934039 (29.90 fps) cam0-stream0 seq: 000062 bytesused: 6220800 2198.967409 (29.97 fps) cam0-stream0 seq: 000063 bytesused: 6220800 2199.000483 (30.24 fps) cam0-stream0 seq: 000064 bytesused: 6220800 2199.033803 (30.01 fps) cam0-stream0 seq: 000065 bytesused: 6220800 2199.067188 (29.95 fps) cam0-stream0 seq: 000066 bytesused: 6220800 2199.100448 (30.07 fps) cam0-stream0 seq: 000067 bytesused: 6220800 2199.134004 (29.80 fps) cam0-stream0 seq: 000068 bytesused: 6220800 2199.167120 (30.20 fps) cam0-stream0 seq: 000069 bytesused: 6220800 2199.200566 (29.90 fps) cam0-stream0 seq: 000070 bytesused: 6220800 2199.234022 (29.89 fps) cam0-stream0 seq: 000071 bytesused: 6220800 2199.267062 (30.27 fps) cam0-stream0 seq: 000072 bytesused: 6220800 2199.300364 (30.03 fps) cam0-stream0 seq: 000073 bytesused: 6220800 2199.333918 (29.80 fps) cam0-stream0 seq: 000074 bytesused: 6220800 2199.367267 (29.99 fps) cam0-stream0 seq: 000075 bytesused: 6220800 2199.400368 (30.21 fps) cam0-stream0 seq: 000076 bytesused: 6220800 2199.433722 (29.98 fps) cam0-stream0 seq: 000077 bytesused: 6220800 2199.467192 (29.88 fps) cam0-stream0 seq: 000078 bytesused: 6220800 2199.500564 (29.97 fps) cam0-stream0 seq: 000079 bytesused: 6220800 2199.533604 (30.27 fps) cam0-stream0 seq: 000080 bytesused: 6220800 -- через 3 с: exposure: 2260 analogue_gain: 960 2199.567149 (29.81 fps) cam0-stream0 seq: 000081 bytesused: 6220800 2199.600250 (30.21 fps) cam0-stream0 seq: 000082 bytesused: 6220800 2199.633587 (30.00 fps) cam0-stream0 seq: 000083 bytesused: 6220800 2199.667142 (29.80 fps) cam0-stream0 seq: 000084 bytesused: 6220800 2199.700182 (30.27 fps) cam0-stream0 seq: 000085 bytesused: 6220800 2199.733764 (29.78 fps) cam0-stream0 seq: 000086 bytesused: 6220800 2199.766741 (30.32 fps) cam0-stream0 seq: 000087 bytesused: 6220800 2199.800391 (29.72 fps) cam0-stream0 seq: 000088 bytesused: 6220800 2199.833509 (30.20 fps) cam0-stream0 seq: 000089 bytesused: 6220800 макс 205 среднее 124.37S Вот теперь всё в порядке: максимум 205, среднее 124 — нормально проэкспонированный кадр. Чернота была из-за того, что десяти кадров не хватало: автоматика стартует с минимальной выдержки, а вычитание уровня чёрного добивало остатки в ноль. Сейчас она сошлась на выдержке 2260 и усилении 960. Смотрим картинку: F=$(ls -t /tmp/lc_*.rgb | head -1) magick -size 1920x1080 -depth 8 bgr:$F /tmp/lc.png && ls -l /tmp/lc.png Кидай сюда — интересует резкость (фокус мы держали на 600 с открытым дескриптором) и цвет. Заодно из лога видно цену программной обработки: 23.7 мс на кадр, то есть демозаик съедает почти целое ядро на 30 кадрах в секунду. 💰 8.30₽ · ⬇️ 249.6k / ⬆️ 927 · opus-5 · max · 18сЫ S Отлично — значит пайплайн целиком рабочий, остался только цвет. Холодит по двум причинам: в программном ISP сейчас нет цветовой матрицы (без неё сырой отклик сенсора всегда уходит в синь), а баланс белого работает по «серому миру» и на сцене с преобладанием тёплых поверхностей уводит картинку в холод. Лечится настроечным файлом. Посмотрим, что твоя версия libcamera умеет: ls ~/libcamera/src/ipa/simple/algorithms/ cat /usr/share/libcamera/ipa/simple/uncalibrated.yaml Если среди алгоритмов есть ccm — сделаем imx586.yaml с матрицей и гаммой, и цвет сразу станет人ским. Если нет, тогда доступны только уровень чёрного, гамма и баланс, и я подберу их. Ну и в идеале сфотографировать цветовую мишень, чтобы матрицу посчитать честно, а не на глаз. Подойдёт даже распечатанная — но это уже следующий шаг. 💰 7.37₽ · ⬇️ 250.6k / ⬆️ 1.2k · opus-5 · max · 22сЫ