Именно. Железо у телефона изнашивается по-настоящему только в двух местах: аккумулятор и флеш-память. Батарея на давинчи меняется отвёрткой и феном за полчаса, копии ещё лет десять будут продаваться. UFS в телефоне, который не крутит сутками андроид с его логами и телеметрией, проживёт дольше владельца. Всё остальное — стекло, разъём, кнопки — расходники, которые чинятся.
И мы сегодня ровно это и получили: аппарат 2019 года работает на ядре 7.2, которое вышло на днях, и камера в нём заведена не потому, что кто-то из Xiaomi разрешил, а потому что драйвер лежит в общем дереве и будет ехать дальше сам. Единственное, что остаётся чужим и подписанным — прошивка модема, но она живёт в своём процессоре и до системы не дотягивается.
Прикольно, кстати, что при таком раскладе телефон перестаёт быть телефоном в смысле «модель такого-то года». Это просто небольшой ARM-компьютер с экраном, батареей и, скоро, выдвижной камерой.
💰 3.42₽ · ⬇️ 77.9k / ⬆️ 653 · opus-5 · max · 16с
ВеткаИменно. Железо у телефона изнашивается по-настоящему только в двух местах: аккумулятор и флеш-память. Батарея на давинчи…
301 сообщение · –Ы 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сЫ Ы ls ~/libcamera/src/ipa/simple/algorithms/ adjust.cpp adjust.h agc.cpp agc.h algorithm.h awb.cpp awb.h blc.cpp blc.h ccm.cpp ccm.h meson.build # SPDX-License-Identifier: CC0-1.0 %YAML 1.1 --- version: 1 algorithms: - BlackLevel: - Awb: # Color correction matrices can be defined here. The CCM algorithm # has a significant performance impact, and should only be enabled # if tuned. # - Ccm: # ccms: # - ct: 6500 # ccm: [ 1, 0, 0, # 0, 1, 0, # 0, 0, 1] - Adjust: - Agc: ...S Ccm есть — значит цвет чинится файлом, без пересборки. Клади настройку: sudo tee /usr/share/libcamera/ipa/simple/imx586.yaml >/dev/null <<'EOF' # SPDX-License-Identifier: CC0-1.0 %YAML 1.1 --- version: 1 algorithms: - BlackLevel: - Awb: - Ccm: ccms: - ct: 2900 ccm: [ 1.55, -0.44, -0.11, -0.29, 1.61, -0.32, -0.03, -0.72, 1.75 ] - ct: 6500 ccm: [ 1.60, -0.52, -0.08, -0.23, 1.60, -0.37, -0.04, -0.55, 1.59 ] - Adjust: - Agc: ... EOF И повтори съёмку тем же способом: 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 2>&1 | grep -E "imx586.yaml|Ccm|ERROR" exec 9>&- F=$(ls -t /tmp/lc_*.rgb | head -1) magick -size 1920x1080 -depth 8 bgr:$F /tmp/lc_ccm.png Матрицы пока типовые для сенсоров Sony — одна для лампы накаливания, одна для дневного света, строки нормированы так, чтобы белое оставалось белым. Это уже сильно лучше единичной матрицы, но честные коэффициенты считаются по снимку цветовой мишени, так что потом заменим. Учти, что демозаик и так ест 24 мс на кадр, а матрица добавит сверху — в самой libcamera про это прямо написано предупреждение. 💰 7.89₽ · ⬇️ 252.3k / ⬆️ 1.8k · opus-5 · max · 28сЫ S Отлично — значит цвет закрыт. Сохраню файл в набор, чтобы не потерялся: Итого по широкой камере всё замкнулось: кадры идут, режимы переключаются, фокус двигается, экспозиция сходится сама, цвет правильный. То есть камера работает через libcamera целиком, как обычное устройство — этим уже можно снимать из любого приложения, которое умеет libcamera. Что осталось в этой ветке, по убыванию пользы: Честная матрица. Нынешняя типовая, взята «как у Sony вообще». Если снимешь цветовую мишень (годится распечатанная, лишь бы при дневном свете у окна), посчитаю коэффициенты по твоему экземпляру — уйдут остаточные оттенки на коже и небе. Задержки конвейера. В логе висит No sensor delays found in static properties — libcamera не знает, через сколько кадров после записи применяется новая выдержка, и на резких сменах освещения будет промахиваться. Для imx586 мы это уже прописали, для ov8856 осталось. Телевик. Линии теперь правильные, но кадров нет. Следующий шаг там — вендорный блоб, чтобы сверить время установления и режимы. Что дальше — цветовая мишень, или лучше вернуться к телевику? 💰 13.83₽ · ⬇️ 509.1k / ⬆️ 1.1k · opus-5 · max · 22сЫ S Нет, сама не будет — ни сейчас, ни без нашей работы. Я проверил по исходникам: в обработчике simple про объектив нет ни слова, а в программном ISP всего пять алгоритмов — уровень чёрного, баланс белого, матрица, коррекция и экспозиция. Автофокуса среди них нет, и линзу оттуда никто не трогает. В libcamera автофокус есть только у пайплайнов с железным ISP (Raspberry Pi, IPU3), где его считает вендорная IPA. Два пути. Быстрый, наш. Написать маленький автофокус в userspace: снимаем поток, считаем резкость по центральному окну (сумма градиентов), ползём по focus_absolute вверх-вниз до максимума. Это полсотни строк, работает поверх нашего же raw-пути и даёт нормальную наводку за секунду-полторы. Сделаю прямо сейчас, если хочешь. Правильный, в апстрим. Научить simple отдавать объектив в IPA (в libcamera для этого есть класс CameraLens, просто этот обработчик им не пользуется), добавить в статистику метрику резкости и написать алгоритм Af рядом с остальными пятью. Это уже полноценная фича, которой в libcamera не хватает всем программным пайплайнам, а не только нам — то есть вещь, которую примут. Начать логично с первого: он сразу даёт работающую наводку и заодно проверяет, что метрика резкости на этом сенсоре ведёт себя прилично. Второе потом переиспользует ту же математику. 💰 14.07₽ · ⬇️ 511.8k / ⬆️ 1.8k · opus-5 · max · 39сЫ S Скорее всего оно открывает первую камеру — то есть телевик, а он кадров не отдаёт, и приложение честно ждёт вечно. Плюс мы по дороге убивали pipewire нашими скриптами, а приложения ходят в камеру через него. Сначала вернём pipewire: systemctl --user restart pipewire wireplumber 2>/dev/null || (pipewire & wireplumber &) А телевик пока просто уберём с глаз — драйвер отвязывается на лету, без перезагрузки и правки дерева: echo 13-0036 | sudo tee /sys/bus/i2c/drivers/ov8856/unbind cam -l | grep -E "^[0-9]:" Должна остаться одна камера — широкая. После этого запускай приложение, ему выбирать будет не из чего. Вернуть телевик обратно, когда займёмся им: echo 13-0036 | sudo tee /sys/bus/i2c/drivers/ov8856/bind 💰 7.20₽ · ⬇️ 257.5k / ⬆️ 804 · opus-5 · max · 14сЫ S Похоже на нехватку памяти: /tmp у тебя в оперативке, а мы туда навалили — 90 кадров по 6.2 МБ это 560 МБ, плюс полноразмерные raw. Плюс программный ISP ест целое ядро на камеру. Проверь и прибери: free -m; df -h /tmp dmesg | grep -iE "oom|killed process|out of memory" | tail -5 rm -f /tmp/lc_*.rgb /tmp/lcs_*.rgb /tmp/f*.raw Дальше давай серии писать не в /tmp, а на диск: mkdir -p ~/cap && cam -c 2 -s width=1920,height=1080,pixelformat=RGB888 --capture=90 --file=$HOME/cap/lc_#.rgb Медленнее, зато система не задохнётся. 💰 7.01₽ · ⬇️ 258.3k / ⬆️ 740 · opus-5 · max · 14сЫ S После перезагрузки телевик снова на месте, так что первым делом убери его и проверь, не в нём ли дело: echo 13-0036 | sudo tee /sys/bus/i2c/drivers/ov8856/unbind cam -l | grep -E "^[0-9]:" Если приложение после этого заработает — значит оно спотыкалось именно о камеру, которая не отдаёт кадры. Если ошибка останется, надо посмотреть, что именно оно просит. Запусти его из терминала и покажи хвост: ls /usr/bin | grep -iE "camera|snapshot|megapixels" <имя_бинарника> 2>&1 | tail -40 «The configuration is not valid» — это отказ на этапе согласования формата: приложение запрашивает размер или пиксельный формат, которого программный ISP не даёт. В логе будет видно, что оно просило и что ему предложили взамен. 💰 7.15₽ · ⬇️ 259.1k / ⬆️ 864 · opus-5 · max · 16сЫ S Это plasma-camera. Запусти из терминала и покажи хвост: plasma-camera 2>&1 | tail -40 И заодно проверь, что у нас там теперь с библиотеками — есть подозрение, что мы поставили свою рядом, а не вместо: ls -l /usr/lib/libcamera*.so* | head Дело в том, что наша сборка представляется как v0.0.0+1-244572db-dirty — в дереве нет тегов, поэтому номер версии не определился. Если из-за этого имя библиотеки вышло другим (libcamera.so.0.0 вместо libcamera.so.0.7), то cam берёт нашу, а все остальные приложения по-прежнему системную. Тогда починим одним символическим линком. 💰 7.52₽ · ⬇️ 260.1k / ⬆️ 1.1k · opus-5 · max · 22сЫ qt.qpa.xcb: could not connect to display qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin. qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found. This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem. Available platform plugins are: offscreen, minimal, xcb, vnc, vkkhrdisplay, wayland-brcm, wayland-egl, wayland, linuxfb, minimalegl, eglfs. Aborted (core dumped)S Это оно ругается на отсутствие экрана — по ssh Qt не к чему подключиться. Укажи вейландовский сеанс телефона: export XDG_RUNTIME_DIR=/run/user/$(id -u) ls $XDG_RUNTIME_DIR | grep wayland export WAYLAND_DISPLAY=wayland-0 # подставь то, что нашлось QT_QPA_PLATFORM=wayland plasma-camera 2>&1 | tail -40 Окно откроется на самом телефоне, а сообщения придут в терминал. И покажи всё же список библиотек, это важно: ls -l /usr/lib/libcamera*.so* 💰 7.01₽ · ⬇️ 261.5k / ⬆️ 469 · opus-5 · max · 8сЫ S Значит сообщение рисует сама программа, а причину надо доставать сбоку. Два быстрых шага. Первое — всё-таки покажи, что лежит в системе, это ключевой вопрос: ls -l /usr/lib/libcamera*.so* Второе — проверим тот же путь другим потребителем, через gstreamer: export XDG_RUNTIME_DIR=/run/user/$(id -u); export WAYLAND_DISPLAY=wayland-0 gst-inspect-1.0 libcamerasrc >/dev/null 2>&1 && echo "плагин есть" || echo "плагина нет" gst-launch-1.0 libcamerasrc ! video/x-raw,width=1920,height=1080 ! videoconvert ! waylandsink 2>&1 | tail -15 Если картинка появится на экране телефона — значит libcamera и её потребители в порядке, а спотыкается именно plasma-camera на своём наборе форматов. Если же не появится, ошибка от gstreamer будет куда разговорчивее, чем одна строка в окне. 💰 7.70₽ · ⬇️ 262.0k / ⬆️ 1.4k · opus-5 · max · 26сЫ S Ясно, gstreamer нет — значит plasma-camera ходит в камеру через pipewire (у него есть свой модуль libcamera), либо напрямую через QtMultimedia. Проверим по очереди. Видит ли pipewire камеру: wpctl status 2>/dev/null | grep -A6 -i "video\|source" | head -20 journalctl --user -u pipewire -n 40 2>/dev/null | grep -iE "libcamera|camera|error" | tail -10 И заодно, если при сборке собрался наш собственный просмотрщик — он покажет картинку сам, без pipewire и без Qt-обвязки приложения: ls -l ~/libcamera/build/src/apps/qcam/qcam 2>/dev/null && \ XDG_RUNTIME_DIR=/run/user/$(id -u) WAYLAND_DISPLAY=wayland-0 ~/libcamera/build/src/apps/qcam/qcam -c 2 Если qcam покажет живое видео — значит вся цепочка исправна, и разбираться надо только с тем, что просит plasma-camera. Если и он не сможет — причина глубже, и она будет в его логе развёрнуто. 💰 7.93₽ · ⬇️ 263.6k / ⬆️ 1.2k · opus-5 · max · 20сЫ ├─ Sources: │ ├─ Filters: │ └─ Streams: Video ├─ Devices: │ 44. Qualcomm Camera Subsystem [v4l2] │ 45. Qualcomm Camera Subsystem [v4l2] │ 46. Qualcomm Camera Subsystem [v4l2] │ 47. Qualcomm Camera Subsystem [v4l2] │ 48. Qualcomm Camera Subsystem [v4l2] -- ├─ Sources: │ * 56. Built-in Back Camera │ 58. Built-in Back Camera │ ├─ Filters: │S Вот и объяснение: pipewire отдаёт две «Built-in Back Camera», и по умолчанию выбрана 56 — почти наверняка телевик, который кадров не даёт. Плюс рядом торчат пять сырых узлов camss как v4l2-устройства, в которые лезть вообще нельзя, там формат надо настраивать руками. Посмотри, кто есть кто, и переключи умолчание: wpctl inspect 56 | grep -iE "node.name|device.name|object.path|api\." wpctl inspect 58 | grep -iE "node.name|device.name|object.path|api\." Тот, у которого в пути camera@1a — широкая. Ставим его по умолчанию: wpctl set-default 58 # подставь нужный номер А проще всего снова убрать телевик с глаз и перезапустить pipewire, тогда выбирать будет не из чего: echo 13-0036 | sudo tee /sys/bus/i2c/drivers/ov8856/unbind systemctl --user restart pipewire wireplumber wpctl status | grep -A4 "Sources" После этого запускай приложение. 💰 7.70₽ · ⬇️ 265.2k / ⬆️ 920 · opus-5 · max · 16сЫ wpctl inspect 56 | grep -iE "node.name|device.name|object.path|api\." api.libcamera.location = "back" api.libcamera.path = "/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36" api.libcamera.rotation = "180" device.name = "libcamera_device./base/soc@0/cci@ac4a000/i2c-bus@1/camera@36" factory.name = "api.libcamera.source" * node.name = "libcamera_input._base_soc_0_cci_ac4a000_i2c-bus_1_camera_36" * object.path = "libcamera:/base/soc@0/cci@ac4a000/i2c-bus@1/camera@36" wpctl inspect 58 | grep -iE "node.name|device.name|object.path|api\." api.libcamera.location = "back" api.libcamera.path = "/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a" api.libcamera.rotation = "180" device.name = "libcamera_device./base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a" factory.name = "api.libcamera.source" * node.name = "libcamera_input._base_soc_0_cci_ac4a000_i2c-bus_0_camera_1a" * object.path = "libcamera:/base/soc@0/cci@ac4a000/i2c-bus@0/camera@1a"S Как и думал: 56 — телевик (camera@36), 58 — широкая (camera@1a), а по умолчанию стоит именно телевик. Переключаем: wpctl set-default 58 wpctl status | grep -A4 "Sources" Звёздочка должна переехать на 58. И запускай приложение. Если оно всё равно упрётся (некоторые программы сами перебирают устройства и берут первое, игнорируя умолчание) — тогда убираем телевик совсем: echo 13-0036 | sudo tee /sys/bus/i2c/drivers/ov8856/unbind systemctl --user restart pipewire wireplumber 💰 7.01₽ · ⬇️ 266.7k / ⬆️ 339 · opus-5 · max · 8сЫ S Тогда добьём телевик и посмотрим, какие форматы вообще предлагает широкая — подозреваю, что приложение просит YUV, а программный ISP отдаёт только RGB, и переговоры о формате рушатся. echo 13-0036 | sudo tee /sys/bus/i2c/drivers/ov8856/unbind systemctl --user restart pipewire wireplumber sleep 2 wpctl status | grep -A4 "Sources" И список форматов узла (номер возьми из свежего wpctl status, он мог поменяться): pw-cli enum-params 58 EnumFormat 2>/dev/null | grep -E "format|Video|size|framerate" | head -30 Если там окажутся только RGB/BGR/ARGB, а привычных NV12/YUY2 нет — вот и причина. Тогда варианта два: включить в pipewire промежуточное преобразование или добавить вывод в NV12 в сам программный ISP (он это умеет в свежих версиях, вопрос сборки). 💰 7.46₽ · ⬇️ 267.1k / ⬆️ 1.1k · opus-5 · max · 19сЫ S Занят — pipewire держит камеру открытой. Останови его и повтори: systemctl --user stop pipewire wireplumber pipewire.socket 2>/dev/null pkill -f wireplumber; pkill -f pipewire; sleep 1 echo 13-0036 | sudo tee /sys/bus/i2c/drivers/ov8856/unbind systemctl --user start pipewire wireplumber Но это второстепенно. Гораздо важнее список форматов — без него мы гадаем. Номер узла возьми свежий: wpctl status | grep -A4 Sources pw-cli enum-params <номер> EnumFormat 2>&1 | grep -E "format:|size:|Video" | head -30 💰 7.38₽ · ⬇️ 268.3k / ⬆️ 721 · opus-5 · max · 13сЫ S Так и есть — pipewire завис, скорее всего именно на телевике: он открыл камеру, ждёт кадры, а их нет. Это, кстати, объясняет и ошибку приложения: оно спрашивает у зависшего сервиса. Бей жёстко: sudo pkill -9 -f pipewire; sudo pkill -9 -f wireplumber; sleep 1 echo 13-0036 | sudo tee /sys/bus/i2c/drivers/ov8856/unbind systemctl --user start pipewire wireplumber 2>/dev/null || (pipewire & wireplumber &) sleep 2; wpctl status | grep -A4 Sources Должна остаться одна камера. И сразу запускай приложение — подозреваю, что теперь оно заработает без всяких форматных плясок. 💰 7.11₽ · ⬇️ 269.1k / ⬆️ 646 · opus-5 · max · 13сЫ S Ошибка не «занято», а именно ввод-вывод — значит дело не в pipewire. Проверим, как оно вообще привязано, и попробуем через модуль: ls -l /sys/bus/i2c/devices/13-0036/driver 2>/dev/null ls /sys/bus/i2c/drivers/ | grep -i ov lsmod | grep -i ov8856 Если это модуль — выгружаем целиком, так надёжнее: sudo rmmod ov8856 && dmesg | tail -5 А если он вкомпилирован в ядро, останется путь через дерево: дописать телевику status = "disabled", пересобрать dtb и перезагрузиться. Тогда он исчезнет и из libcamera, и из pipewire до тех пор, пока мы им не займёмся всерьёз. 💰 7.67₽ · ⬇️ 269.8k / ⬆️ 1.1k · opus-5 · max · 23сЫ S Ясно: модуль держит camss, потому что телевик прописан в его графе. Выгрузить camss тоже нельзя — тогда он будет ждать пропавший сенсор и не поднимет вообще ни одной камеры. Значит убираем телевик из дерева. Это одна пересборка dtb и перезагрузка, зато уходит и зависание pipewire, и ошибка приложения: cat >> $F <<'EOF' /* временно, пока телевик не отдаёт кадры: он вешает pipewire и приложения */ &cci0_i2c1 { camera@36 { status = "disabled"; }; }; EOF cd $K && make dtbs -j8 && sudo make dtbs_install INSTALL_DTBS_PATH=/boot/dtbs && sync Отключённый узел v4l2 пропускает молча, так что camss спокойно поднимется с одной камерой. После перезагрузки проверь: cam -l | grep -E "^[0-9]:" Должна остаться одна строка. Дальше приложение — думаю, заведётся сразу. Когда займёмся телевиком, вернём одной строкой: заменить disabled на okay и пересобрать dtb. 💰 8.56₽ · ⬇️ 271.1k / ⬆️ 1.7k · opus-5 · max · 30сЫ S Переменные потерялись — восстановим: F=$(find / -name "sm7150-xiaomi-davinci.dtsi" -not -path "/proc/*" 2>/dev/null | head -1) K=${F%/arch/*} echo "$K"; echo "$F" И дальше как было: cat >> $F <<'EOF' /* временно, пока телевик не отдаёт кадры: он вешает pipewire и приложения */ &cci0_i2c1 { camera@36 { status = "disabled"; }; }; EOF cd $K && make dtbs -j8 && sudo make dtbs_install INSTALL_DTBS_PATH=/boot/dtbs && sync 💰 7.40₽ · ⬇️ 272.8k / ⬆️ 456 · opus-5 · max · 10сЫ Ы S Тогда просто прямыми путями: K=/home/user/linux-7.2 F=$K/arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci.dtsi ls -l $F && tail -5 $F Если файл на месте — дописываем и собираем: cat >> $F <<'EOF' /* временно, пока телевик не отдаёт кадры: он вешает pipewire и приложения */ &cci0_i2c1 { camera@36 { status = "disabled"; }; }; EOF cd $K && make dtbs -j8 && sudo make dtbs_install INSTALL_DTBS_PATH=/boot/dtbs && sync 💰 7.02₽ · ⬇️ 273.4k / ⬆️ 566 · opus-5 · max · 10сЫ S Сбрасывает на диск всё, что ядро ещё держит в памяти. Запись файла на самом деле сначала попадает в кеш страниц, а на флеш уезжает потом, когда ядру удобно — обычно в пределах секунд. Нам это важно ровно перед перезагрузкой: если выключить телефон сразу после dtbs_install, есть шанс, что новый dtb физически не долетел, и на диске останется обрезанный файл. Загрузчик такой прочитает и не запустится — а чинить это придётся уже из рекавери. Пара секунд на команду против такого сценария — выгодный обмен. По той же причине я его пишу и после установки ядра. 💰 6.80₽ · ⬇️ 274.0k / ⬆️ 328 · opus-5 · max · 10сЫ S Хороший сдвиг — значит формат больше не спотыкается, теперь просто не находит устройство. Проверим, что видно на трёх уровнях: cam -l | grep -E "^[0-9]:" wpctl status | grep -A5 Sources systemctl --user status pipewire wireplumber --no-pager 2>/dev/null | grep -E "Active|Loaded" | head -4 Если cam камеру видит, а pipewire нет — просто перезапусти сеанс медиасервера: systemctl --user restart pipewire wireplumber sleep 2; wpctl status | grep -A5 Sources Подозреваю, что после перезагрузки wireplumber успел прочитать граф раньше, чем camss закончил регистрацию, и остался ни с чем. 💰 7.04₽ · ⬇️ 274.5k / ⬆️ 552 · opus-5 · max · 11сЫ S Хуже — теперь camss вообще не видит ни одного сенсора. Значит зацепило и широкую. Смотрим, что происходило при загрузке: dmesg | grep -iE "imx586|dw976|ov8856|camss|cci" | tail -30 Заодно проверим, что в собранном дереве получилось на самом деле: dtc -I fs -O dts /proc/device-tree/soc@0/cci@ac4a000 2>/dev/null | grep -A3 -E "camera@1a|camera@36" | head -20 Подозреваю одно из двух: либо мой блок приписался не туда и отключил не тот узел, либо сенсор в этот раз не поднялся по другой причине — например, объектив снова не успел, а он у нас в зависимостях. 💰 7.45₽ · ⬇️ 275.3k / ⬆️ 844 · opus-5 · max · 16сЫ sudo dmesg | grep -iE "imx586|dw976|ov8856|camss|cci" | tail -30 [ 0.643109] platform ace0000.camss: Adding to iommu group 8 [ 12.161971] calling qcom_cci_driver_init+0x0/0xff8 [i2c_qcom_cci] @ 683 [ 12.218138] /soc@0/camss@ace0000: Fixed dependency cycle(s) with /soc@0/cci@ac4a000/i2c-bus@0/camera@1a [ 12.218239] /soc@0/cci@ac4a000/i2c-bus@0/camera@1a: Fixed dependency cycle(s) with /soc@0/camss@ace0000 [ 12.245726] probe of ac4a000.cci returned 0 after 79230 usecs [ 12.261155] probe of ac4b000.cci returned 0 after 15397 usecs [ 12.277401] initcall qcom_cci_driver_init+0x0/0xff8 [i2c_qcom_cci] returned 0 after 2585 usecs [ 12.451174] calling qcom_camss_driver_init+0x0/0xff8 [qcom_camss] @ 663 [ 12.467864] qcom-camss ace0000.camss: parsed endpoint /soc@0/camss@ace0000/ports/port@0/endpoint of port 0: 4 lanes, first 0 [ 12.472200] qcom-camss ace0000.camss: parsed endpoint /soc@0/camss@ace0000/ports/port@3/endpoint of port 3: 2 lanes, first 0 [ 12.498440] probe of ace0000.camss returned 0 after 45022 usecs [ 12.502731] initcall qcom_camss_driver_init+0x0/0xff8 [qcom_camss] returned 0 after 34539 usecs [ 12.676818] calling dw9768_i2c_driver_init+0x0/0xff8 [dw9768] @ 665 [ 12.705469] initcall dw9768_i2c_driver_init+0x0/0xff8 [dw9768] returned 0 after 2480 usecs [ 12.724098] calling imx586_i2c_driver_init+0x0/0xff8 [imx586] @ 681 [ 12.737141] imx586 12-001a: IMX582 detected [ 12.742400] imx586 12-001a: signalling mode default 0x02 [ 12.762162] imx586 12-001a: lane mode default 0x03 [ 12.790466] initcall imx586_i2c_driver_init+0x0/0xff8 [imx586] returned 0 after 61465 usecsS Вот и объяснение: сенсор поднялся нормально («IMX582 detected»), но camss всё равно ждёт обе камеры — в логе видно, что он разобрал и порт 0, и порт 3. Отключённый сенсор к порту 3 больше не привязывается, ожидание не завершается никогда, и граф так и не публикуется. Отсюда «No sensor found». Значит убирать надо не только сенсор, но и вход, к которому он подключён: cat >> $F <<'EOF' /* вместе с отключённым телевиком убираем и его вход в camss, иначе приёмник ждёт сенсор, которого нет, и граф не публикуется */ &camss { ports { port@3 { /delete-node/ endpoint; }; }; }; EOF cd $K && make dtbs -j8 && sudo make dtbs_install INSTALL_DTBS_PATH=/boot/dtbs && sync После перезагрузки в логе должна остаться одна строка parsed endpoint ... port 0, а cam -l показать одну камеру. Если предпочитаешь наоборот — вернуть телевик и не трогать дерево, скажи, тогда просто уберём оба добавленных блока и спрячем лишний узел правилом wireplumber, без перезагрузки. 💰 9.01₽ · ⬇️ 277.0k / ⬆️ 1.8k · opus-5 · max · 31сЫ S Понял, больше без переменных. cat >> /home/user/linux-7.2/arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci.dtsi <<'EOF' /* вместе с отключённым телевиком убираем и его вход в camss, иначе приёмник ждёт сенсор, которого нет, и граф не публикуется */ &camss { ports { port@3 { /delete-node/ endpoint; }; }; }; EOF cd /home/user/linux-7.2 && make dtbs -j8 && sudo make dtbs_install INSTALL_DTBS_PATH=/boot/dtbs && sync После перезагрузки: sudo dmesg | grep "parsed endpoint" cam -l | grep -E "^[0-9]:" Ждём одну строку про порт 0 и одну камеру в списке. 💰 7.54₽ · ⬇️ 278.9k / ⬆️ 425 · opus-5 · max · 7сЫ arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci.dtsi:195.24-201.6: ERROR (phandle_references): /soc@0/cci@ac4a000/i2c-bus@1/camera@36/port/endpoint: Reference to non-existent node or label "csiphy3_ep" arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci.dtsi:195.24-201.6: ERROR (phandle_references): /soc@0/cci@ac4a000/i2c-bus@1/camera@36/port/endpoint: Reference to non-existent node or label "csiphy3_ep" ERROR: Input tree has errors, aborting (use -f to force output) ERROR: Input tree has errors, aborting (use -f to force output) make[3]: *** [scripts/Makefile.dtbs:140: arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci-visionox.dtb] Error 2 make[3]: *** Waiting for unfinished jobs.... make[3]: *** [scripts/Makefile.dtbs:140: arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci-samsung.dtb] Error 2 make[2]: *** [scripts/Makefile.build:549: arch/arm64/boot/dts/qcom] Error 2 make[1]: *** [/home/user/linux-7.2/Makefile:1629: dtbs] Error 2 make: *** [Makefile:248: __sub-make] Error 2S Логично: я удалил вход, а сенсор телевика на него ссылается. Раз он нам сейчас не нужен — удалим его целиком, тогда и ссылка исчезнет: cat >> /home/user/linux-7.2/arch/arm64/boot/dts/qcom/sm7150-xiaomi-davinci.dtsi <<'EOF' /* сенсор телевика ссылается на удалённый вход, поэтому убираем и его */ &cci0_i2c1 { /delete-node/ camera@36; }; EOF cd /home/user/linux-7.2 && make dtbs -j8 && sudo make dtbs_install INSTALL_DTBS_PATH=/boot/dtbs && sync Когда вернёмся к телевику, просто снесём эти три добавленных блока в конце файла — они идут подряд и помечены комментариями. 💰 7.75₽ · ⬇️ 279.9k / ⬆️ 911 · opus-5 · max · 15сЫ S Значит телевик был ни при чём — ошибка от самой широкой. Надо понять, каким путём приложение вообще ходит в камеру: ldd /usr/bin/plasma-camera | grep -iE "camera|pipewire|gstreamer|multimedia|Qt6Multimedia" ls /usr/lib/qt6/plugins/multimedia/ 2>/dev/null Подозрение такое: plasma-camera построен на QtMultimedia, а у неё на Linux по умолчанию бэкенд ffmpeg, который умеет только сырой V4L2. Он видит наши узлы camss (/dev/video0 и компанию), пытается открыть их как обычную веб-камеру — и получает отказ, потому что там нужен предварительно настроенный граф и упакованный raw10, а не готовый YUV. Если так, то приложение к нашей камере просто не подходит, и лечится это не настройкой, а другим потребителем: qcam из нашей сборки, Megapixels, или Qt с бэкендом gstreamer плюс libcamerasrc. Но сначала посмотрим на вывод — гадать не будем. 💰 8.17₽ · ⬇️ 280.8k / ⬆️ 1.3k · opus-5 · max · 22сЫ ldd /usr/bin/plasma-camera | grep -iE "camera|pipewire|gstreamer|multimedia|Qt6Multimedia" libQt6Multimedia.so.6 => /lib/libQt6Multimedia.so.6 (0xffff9ff38000) libcamera.so.0.7 => /lib/libcamera.so.0.7 (0xffff9d82a000) libcamera-base.so.0.7 => /lib/libcamera-base.so.0.7 (0xffff9fc71000) ls /usr/lib/qt6/plugins/multimedia/ 2>/dev/null libffmpegmediaplugin.so libgstreamermediaplugin.so в /lib/ если чо наша libcameraS Тогда смотрим, что именно оно просит. Включим логи QtMultimedia: export XDG_RUNTIME_DIR=/run/user/$(id -u) WAYLAND_DISPLAY=wayland-0 QT_LOGGING_RULES="qt.multimedia*=true" plasma-camera 2>&1 | tail -30 И заодно проверим, кто там тянет libcamera — сама Qt или приложение: ldd /lib/libQt6Multimedia.so.6 | grep -i camera ldd /usr/lib/qt6/plugins/multimedia/libffmpegmediaplugin.so | grep -i camera Есть ещё второй бэкенд, gstreamer — его можно попробовать прямо так: QT_MEDIA_BACKEND=gstreamer plasma-camera 2>&1 | tail -20 Ключевой вопрос — открывает ли оно камеру через libcamera или лезет напрямую в /dev/video0. Во втором случае оно обречено: наши узлы отдают упакованный raw10 и требуют настроенного графа, обычная камера так себя не ведёт. 💰 9.36₽ · ⬇️ 282.4k / ⬆️ 2.1k · opus-5 · max · 32сЫ S Тогда спросим саму libcamera — она логирует независимо от Qt: export XDG_RUNTIME_DIR=/run/user/$(id -u) WAYLAND_DISPLAY=wayland-0 LIBCAMERA_LOG_LEVELS=*:DEBUG plasma-camera 2>&1 | grep -iE "validate|configur|adjust|pixelformat|stream" | tail -40 Там будет видно, какой формат и размер оно запрашивает и на чём проверка говорит «нет». И для сравнения — заведомо рабочий потребитель на Qt, если он собрался: ls -l /home/user/libcamera/build/src/apps/qcam/qcam 2>/dev/null && \ /home/user/libcamera/build/src/apps/qcam/qcam 2>&1 | tail -5 Если qcam покажет живую картинку — значит виновата логика запроса в plasma-camera, и чинить надо её, а не камеру. 💰 8.20₽ · ⬇️ 284.7k / ⬆️ 736 · opus-5 · max · 13сЫ S А, понял, в чём фокус: tail ничего не покажет, пока программа не завершится, а она висит с открытым окном. Пиши в файл: export XDG_RUNTIME_DIR=/run/user/$(id -u) WAYLAND_DISPLAY=wayland-0 LIBCAMERA_LOG_LEVELS=*:DEBUG plasma-camera > /tmp/pc.log 2>&1 & sleep 8 kill %1 wc -l /tmp/pc.log grep -iE "validate|configur|adjust|pixelformat|Invalid" /tmp/pc.log | tail -30 Если файл окажется пустым и после этого — значит приложение вообще не доходит до libcamera, и тогда смотрим просто первые строки: head -30 /tmp/pc.log 💰 7.49₽ · ⬇️ 285.4k / ⬆️ 650 · opus-5 · max · 10сЫ S Вот и причина, целиком видно в логе: Picked 8000x6000 ... for max processed stream size 7992x6000 Failed to open /dev/dma_heap/system: No such file or directory Using /dev/udmabuf Failed to create dma buf for frame-0: Invalid argument Приложение не задаёт размер, libcamera по умолчанию берёт максимум — 7992×6000 в ABGR8888, это 191 МБ на кадр. Куч dma-heap в ядре нет, поэтому libcamera выделяет через udmabuf, а у того по умолчанию стоит потолок в 64 МБ на буфер. Отсюда Invalid argument и «конфигурация недопустима». Потолок правится на лету: cat /sys/module/udmabuf/parameters/size_limit_mb echo 1024 | sudo tee /sys/module/udmabuf/parameters/size_limit_mb И запускай приложение снова. Оно должно завестись, но учти: полный кадр через программный демозаик — это порядка секунды на кадр, видоискатель будет ползти. Зато мы убедимся, что причина именно эта. А правильное лечение — включить в ядре кучи dma-buf, тогда libcamera возьмёт нормальный аллокатор: CONFIG_DMABUF_HEAPS=y CONFIG_DMABUF_HEAPS_SYSTEM=y CONFIG_DMABUF_HEAPS_CMA=y Это в следующую пересборку ядра, вместе с патчем get_selection для телевика. 💰 13.59₽ · ⬇️ 296.6k / ⬆️ 1.9k · opus-5 · max · 33сЫ S Всё сходится: это не фильтр, а квадро-байер. В полном разрешении сенсор отдаёт пиксели группами 2×2 одного цвета — вместо привычного шахматного узора получается «крупная клетка», и обычный демозаик libcamera раскладывает её в зелёное с точками. Мы это уже видели в своих кадрах: полный кадр надо разбирать шаблоном quad, а не rggb. Проще говоря, режим 8000×6000 годится только как сырьё для нашего инструмента, а для просмотра нужен любой другой — они все с бинингом и дают честный байер. Плюс задержка сразу упадёт: 1080p через программный демозаик это 24 мс на кадр против почти секунды сейчас. Загляни в настройки приложения — там должен быть выбор разрешения, судя по логу оно знает про все четыре режима (1920×1080, 4000×2250, 4000×3000, 8000×6000). Поставь 1920×1080. Если селектора там нет, сделаем иначе: добавлю в драйвер параметр модуля, скрывающий полноразмерный режим от перечисления, и тогда libcamera будет брать максимумом 4000×3000. Наши собственные скрипты полный кадр всё равно снимут, они ходят напрямую. 💰 9.31₽ · ⬇️ 298.8k / ⬆️ 1.5k · opus-5 · max · 28сЫ S Понял — значит выбор разрешения у приложения не предусмотрен вообще, оно берёт умолчание libcamera, а умолчание там — «самый большой размер». В коде рядом с этим местом даже висит комментарий разработчиков «надо бы придумать способ выбирать по-умному». Придумаем. Правка на три десятка строк в нашей сборке: для видоискателя брать не максимум, а самый большой размер в пределах разумного. python3 - <<'PY' p = "/home/user/libcamera/src/libcamera/pipeline/simple/simple.cpp" s = open(p).read() anchor = """\t\tcfg.pixelFormat = formats.begin()->first; \t\tcfg.size = formats.begin()->second[0].max; """ add = """ \t\t/* \t\t * Taking the largest size is a poor default for a software ISP: \t\t * on this board it selects a 48 megapixel quad bayer mode that no \t\t * debayer can interpret and that costs about a second a frame. \t\t * Prefer the largest size that stays sane for the role. \t\t */ \t\tif (role != StreamRole::Raw) { \t\t\tconst Size limit = role == StreamRole::StillCapture \t\t\t\t\t ? Size(4096, 3072) : Size(1920, 1080); \t\t\tSize best; \t\t\tfor (const SizeRange &range : formats.begin()->second) { \t\t\t\tconst Size &sz = range.max; \t\t\t\tif (sz.width <= limit.width && sz.height <= limit.height && \t\t\t\t sz.width * sz.height > best.width * best.height) \t\t\t\t\tbest = sz; \t\t\t} \t\t\tif (!best.isNull()) \t\t\t\tcfg.size = best; \t\t} """ assert anchor in s, "не нашёл место вставки" open(p, "w").write(s.replace(anchor, anchor + add, 1)) print("вставлено") PY cd /home/user/libcamera && ninja -C build && sudo ninja -C build install Пересборка тут только одного файла, минуты две. После неё видоискатель пойдёт в 1920×1080 — это 24 мс на кадр вместо секунды, и телефон перестанет греться. Съёмка фото останется в 4000×3000, а полноразмерный квадро-байер будет доступен только нашим скриптам, которые умеют его разбирать правильно. 💰 28.10₽ · ⬇️ 905.8k / ⬆️ 5.2k · opus-5 · max · 81сЫ S Согласен, это лечение симптома в чужом коде. Тогда так. Сначала проверим, что вообще доступно как потребитель: ls /home/user/libcamera/build/src/apps/qcam/qcam 2>/dev/null && echo "qcam собран" apk search -q megapixels 2>/dev/null apk search -q snapshot 2>/dev/null | head -5 qcam — родной просмотрщик libcamera, он принимает те же ключи потока, что и cam, то есть разрешение задаётся явно: XDG_RUNTIME_DIR=/run/user/$(id -u) WAYLAND_DISPLAY=wayland-0 \ /home/user/libcamera/build/src/apps/qcam/qcam -c 1 -s width=1920,height=1080,pixelformat=RGB888 Это сразу даст живой видоискатель без всяких патчей — годится как проверка и как рабочий инструмент на сегодня. А правильный потребитель для телефона — Megapixels: он специально сделан под такие камеры, умеет выбирать режим для превью и отдельный для снимка, и настраивается файлом описания устройства. Как раз наш случай: превью в 1920×1080, снимок в 4000×3000, а полноразмерный квадро-байер вообще не трогаем. Если он есть в репозитории, поставим и напишем ему описание для давинчи — заодно это готовый кусок для порта в pmOS. plasma-camera в этой роли слабоват: он не даёт выбрать разрешение вообще, что для телефона с четырьмя режимами странно. Но если хочешь, потом заведём им запрос — правка там небольшая. 💰 9.94₽ · ⬇️ 307.0k / ⬆️ 1.3k · opus-5 · max · 23сЫ