아래 본문의 6단계 과정부터 수행하시면 됩니다.




비디오 캡처 장치 중 V4L2를 선택했을 시 장치는 'ipu6', 입력은 'Intel IPU6 ISYS Capture 47'로 표시 되고 있다.


비디오 캡처 장치 중 PipeWire를 선택했을 시에는 카메라 접근 권한 요청 팝업이 뜬다. 권한 허용 했을 시 장치는 'ipu6(V4L2)' 라고 표시된다.
용어 설명
- IPU6
IPU6(Intel Image Processing Unit 6)는 최신 Intel 플랫폼에서 사용되는 카메라 전용 이미지 처리 하드웨어 블록이다. 주로 MIPI CSI 방식의 내장 노트북 카메라를 처리하며, 기존의 단순 UVC USB 카메라와 달리 ISP(Image Signal Processor) 파이프라인을 통해 노이즈 제거, 색 보정, 자동 노출 등 복잡한 영상 처리를 수행한다. Ubuntu에서 IPU6 기반 카메라는 일반 UVC 드라이버로는 동작하지 않으며, 전용 커널 드라이버와 사용자 공간 라이브러리가 필요하다.
- PipeWire
PipeWire 는 Linux에서 오디오와 비디오 스트림을 통합 관리하는 멀티미디어 서버이다. 기존의 PulseAudio(오디오)와 일부 JACK 기능을 대체하며, 최근 Ubuntu에서는 기본 오디오/영상 세션 매니저로 사용된다. 웹캠의 경우 V4L2에서 전달된 비디오 스트림을 사용자 애플리케이션(예: 브라우저, Zoom, Cheese)으로 연결해 주는 역할을 하며, 권한 관리 및 스트림 라우팅을 담당한다.
- V4L2
Video4Linux2 는 Linux 커널의 비디오 장치 인터페이스 표준이다. 웹캠, TV 튜너, 캡처 카드 등의 장치를/dev/video*형태의 디바이스 노드로 노출하며, 사용자 공간 프로그램이 이를 통해 영상 데이터를 읽고 제어할 수 있게 한다. 일반 USB UVC 카메라는 V4L2 드라이버(예: uvcvideo)로 바로 동작하지만, IPU6 기반 카메라는 내부적으로 ISYS/PSYS 레이어를 거쳐 V4L2 인터페이스로 연결된다.
- Intel IPU6 ISYS Capture 47
“Intel IPU6 ISYS Capture 47”은 IPU6의 ISYS(Input System) 파이프라인을 통해 노출되는 V4L2 캡처 디바이스 이름 중 하나이다. ISYS는 카메라 센서에서 들어오는 원시(raw) 데이터를 수집하는 단계이며, 이후 PSYS(Processing System)에서 영상 처리 과정을 수행한다.v4l2-ctl --list-devices실행 시 해당 이름이 보인다면, 커널 차원에서 IPU6 입력 장치는 인식되었음을 의미하지만, 실제 영상 출력이 가능하려면 추가 사용자 공간 드라이버 및 미디어 스택 구성이 필요하다.
- MIPI CSI
MIPI CSI(Camera Serial Interface)는 모바일 및 노트북에서 널리 사용되는 고속 직렬 카메라 인터페이스 표준이다. 센서에서 SoC로 원시 영상 데이터를 직접 전송하며, USB처럼 자체 비디오 프로토콜을 포함하지 않는다. 따라서 반드시 ISP나 전용 이미지 처리 장치(IPU 등)를 거쳐야 화면 출력이 가능하다.
- UVC USB 카메라
UVC(USB Video Class)는 USB 표준에 포함된 비디오 장치 규격이다. UVC 카메라는 자체적으로 비디오 스트림 포맷을 제공하므로, Linux에서는uvcvideo드라이버만으로 바로/dev/videoX장치가 생성된다. 별도의 ISP 파이프라인 없이도 비교적 단순하게 동작한다는 점에서 MIPI CSI 카메라와 구조적으로 다르다.
- 커널 드라이버
커널 드라이버는 운영체제 커널 공간에서 하드웨어를 제어하는 소프트웨어 모듈이다. IPU6의 경우 센서 제어, DMA 처리, 인터럽트 관리 등을 수행하며, V4L2 인터페이스로 사용자 공간에 장치를 노출한다. 드라이버가 로드되지 않으면 장치는 물리적으로 존재하더라도/dev/videoX가 생성되지 않는다.
- JACK 기능
JACK(Jack Audio Connection Kit)은 저지연 오디오 처리를 위한 Linux 오디오 서버이다. 전문 음악 제작 환경에서 오디오 애플리케이션 간 실시간 라우팅을 지원한다. PipeWire는 JACK의 저지연 처리 기능과 연결 모델을 부분적으로 흡수하여, 오디오 및 비디오 스트림을 통합적으로 관리할 수 있도록 설계되었다.
위 증상을 해석하기 위해서는 IPU6 기반 카메라가 Ubuntu 24.04에서 어떤 경로로 동작하는지 먼저 이해할 필요가 있다.
IPU6 기반 내장 카메라는 일반 USB 웹캠과 구조가 다르다. 전체 흐름은 다음과 같다.
1단계 — 이미지 센서 입력
노트북 내부 카메라는 일반적으로 MIPI CSI 인터페이스를 통해 SoC로 영상 신호를 전달한다. 이 신호는 USB처럼 완성된 비디오 스트림이 아니라, 원시(raw) 센서 데이터 형태로 들어온다.
2단계 — IPU6 ISYS 처리
Intel IPU6의 ISYS(Input System)는 센서로부터 들어온 MIPI CSI 신호를 수집하고 프레임 단위로 구성한다. 이 단계에서 물리적 링크 관리와 DMA 전송이 수행된다.
3단계 — IPU6 PSYS 영상 처리
PSYS(Processing System)는 ISP 파이프라인을 통해 자동 노출(AE), 자동 화이트밸런스(AWB), 노이즈 제거, 색 보정 등을 수행한다. 이 과정을 거쳐 사람이 볼 수 있는 YUV/RGB 프레임으로 변환된다.
4단계 — 커널 공간에서 V4L2 디바이스 노출
처리된 영상 스트림은 Video4Linux2 인터페이스를 통해 /dev/videoX 형태의 장치 노드로 사용자 공간에 노출된다. 이 시점에서 시스템은 이를 “웹캠 장치”로 인식한다.
5단계 — 사용자 공간 미디어 서버 연결
Ubuntu 24.04에서는 PipeWire가 기본 미디어 서버로 동작한다. PipeWire는 V4L2 디바이스를 감지하고 이를 내부 스트림 그래프에 연결한다.
6단계 — 애플리케이션 전달
Discord, OBS Studio, 브라우저 등은 PipeWire를 통해 영상 스트림을 수신한다. 이 단계에서 권한 확인, 세션 관리, 스트림 라우팅이 처리된다.
요약 구조는 다음과 같다.
MIPI 센서 → IPU6(ISYS → PSYS) → V4L2(/dev/videoX) → PipeWire → 애플리케이션
OBS에서 장치를 “Intel IPU6 ISYS Capture 47”로 인식한다는 것은 최소한 V4L2 장치 노출까지는 이루어졌음을 의미한다. 즉, IPU6 ISYS 드라이버가 로드되어 /dev/videoX가 생성된 상태이다.
그러나 화면이 출력되지 않는다는 것은, 커널 및 미디어 파이프라인 단계에서 실제 프레임 생성이 이루어지지 않았을 가능성을 시사한다. 가능한 원인은 다음과 같다.
이 경우는 “디바이스 노드는 존재하지만, 커널 내부에서 프레임이 생성되지 않는 상태”에 해당한다. 즉, /dev/videoX는 생성되었으나 실제 영상 데이터가 사용자 공간으로 전달되지 않는 구조적 문제이다.
용어 설명
- 포맷 협상 (Format Negotiation)
포맷 협상은 카메라 장치와 애플리케이션 사이에서 어떤 해상도, 픽셀 포맷(YUYV, NV12, RGB 등), 프레임레이트를 사용할지 결정하는 과정이다. V4L2 장치는 여러 포맷을 지원할 수 있으며, 애플리케이션은 자신이 처리 가능한 포맷을 요청한다. 이때 양측이 공통으로 지원하는 포맷이 합의되어야 영상이 정상적으로 출력된다. IPU6 환경에서는 ISP 출력 포맷과 PipeWire 또는 애플리케이션이 요구하는 포맷이 일치하지 않으면 협상에 실패할 수 있으며, 그 결과 장치는 보이지만 화면은 검게 표시되는 현상이 발생할 수 있다.
- 미디어 컨트롤러 (Media Controller)
미디어 컨트롤러는 Linux 커널의 V4L2 하위 프레임워크로, 복잡한 카메라 파이프라인 구조를 그래프 형태로 관리하는 시스템이다. 단순 UVC USB 카메라는 하나의 장치 노드로 끝나지만, IPU6와 같은 MIPI 기반 카메라는 센서, ISYS, PSYS, ISP, 메모리 노드 등 여러 하드웨어 블록이 연결된 구조를 가진다. 미디어 컨트롤러는 이러한 구성 요소들을 엔티티(entity)와 링크(link)로 표현하며, 올바른 연결이 설정되어야 프레임이 생성된다. 설정이 불완전하면/dev/videoX는 존재하더라도 실제 영상 데이터가 흐르지 않을 수 있다.
IPU6 기반 카메라는 단순 UVC USB 카메라와 달리, 커널 드라이버만으로 완전 동작하지 않는다. 커널에서 V4L2 장치를 노출하더라도, 사용자 공간에서 ISP 파이프라인을 구성하는 추가 구성요소가 필요하다. 이 계층에서 발생할 수 있는 문제는 다음과 같다.
이 경우는 “커널 단계는 통과했으나, 사용자 공간 영상 처리 체인이 완성되지 않은 상태”에 해당한다. 즉, /dev/videoX는 존재하고 장치도 인식되지만, ISP 제어 및 프레임 처리 로직이 정상적으로 구성되지 않아 실제 영상 출력이 이루어지지 않는다.
용어 설명
- 사용자 공간 (User Space)
사용자 공간은 운영체제에서 일반 애플리케이션과 라이브러리가 실행되는 영역을 의미한다. Linux는 크게 커널 공간(kernel space)과 사용자 공간(user space)으로 구분되며, 하드웨어 직접 제어는 커널이 담당하고, 실제 프로그램 실행은 사용자 공간에서 이루어진다. IPU6 맥락에서 커널 드라이버는/dev/videoX장치를 생성하지만, libcamera나 PipeWire 같은 구성 요소는 사용자 공간에서 동작하며 영상 스트림을 처리하고 애플리케이션에 전달한다. 따라서 “사용자 공간 라이브러리 누락”이라는 것은 커널은 정상이나, 그 위에서 동작해야 할 영상 처리 스택이 완성되지 않았음을 의미한다.
- ISP(Image Signal Processor) 제어
ISP 제어는 이미지 센서에서 들어온 원시 데이터를 사람이 볼 수 있는 영상으로 변환하기 위해 수행되는 처리 파라미터를 설정·조정하는 과정을 의미한다. ISP는 자동 노출(AE), 자동 화이트밸런스(AWB), 색 보정, 노이즈 제거, 감마 보정 등의 연산을 수행하는데, 이 값들은 고정되어 있지 않고 센서 상태와 조명 환경에 따라 동적으로 조절된다. IPU6 환경에서는 커널 드라이버와 사용자 공간 라이브러리가 협력하여 ISP 블록에 필요한 설정을 전달한다. 이 제어가 이루어지지 않으면 센서는 동작하더라도 영상은 생성되지 않거나, 생성되더라도 정상적인 프레임으로 출력되지 않을 수 있다.
PipeWire를 선택했을 때 카메라 접근 권한 팝업이 뜨는 것은, V4L2 장치를 PipeWire가 감지하고 있음을 의미한다.
그러나:
이 경우는 다음을 의심할 수 있다.
즉, 커널 단계는 통과했으나 사용자 공간 미디어 스택에서 실패했을 가능성이다.
용어 설명
- 세션 매니저 (Session Manager)
세션 매니저는 PipeWire 내부에서 오디오·비디오 장치와 애플리케이션 간의 연결 정책을 관리하는 구성 요소이다. Ubuntu 24.04에서는 기본적으로 wireplumber가 세션 매니저로 동작하며, 어떤 장치를 어떤 애플리케이션에 연결할지, 권한은 어떻게 처리할지, 기본 장치는 무엇으로 설정할지 등을 결정한다. 단순히 장치가 존재한다고 해서 자동으로 스트림이 연결되는 것이 아니라, 세션 매니저의 정책에 따라 실제 링크가 생성된다. 따라서 wireplumber 설정 오류나 비정상 상태가 발생하면 장치는 보이지만 영상이 전달되지 않을 수 있다.
- 포털 (xdg-desktop-portal)
포털은 샌드박스 환경이나 보안 모델 하에서 애플리케이션이 시스템 자원에 접근할 수 있도록 중개하는 인터페이스 계층이다. Ubuntu에서는 xdg-desktop-portal이 카메라, 마이크, 화면 공유 등의 접근 요청을 처리하며, 사용자가 허용 여부를 선택할 수 있도록 팝업을 생성한다. PipeWire와 연동하여 카메라 접근 권한을 승인받은 후에만 스트림 연결이 이루어진다. 포털 연동에 문제가 생기면 권한 팝업은 뜨지만 실제 스트림이 애플리케이션으로 전달되지 않는 상황이 발생할 수 있다.
- 노드 연결 (Node Linking)
PipeWire는 오디오·비디오 구성 요소를 “노드(node)” 단위로 표현한다. 예를 들어 V4L2 카메라 장치도 하나의 노드이며, Discord나 OBS 같은 애플리케이션도 입력을 소비하는 노드로 표현된다. 노드 연결은 이들 사이에 실제 데이터 경로를 생성하는 과정을 의미한다. 연결이 성공해야 카메라 프레임이 애플리케이션으로 전달된다. 노드가 존재하더라도 링크(link)가 생성되지 않으면 스트림은 흐르지 않는다.
- 스트림 negotiation (Stream Negotiation)
스트림 negotiation은 PipeWire 내부에서 두 노드가 데이터 포맷, 해상도, 프레임레이트 등을 합의하는 과정이다. 이는 V4L2 단계의 포맷 협상과 유사하지만, PipeWire 그래프 내에서 다시 한 번 수행된다. 예를 들어 카메라가 NV12 포맷을 출력하고 애플리케이션이 RGB만 처리 가능하다면, 변환 노드가 삽입되거나 협상이 실패할 수 있다. 이 협상이 실패하면 장치는 정상 인식되지만 영상이 출력되지 않거나 애플리케이션에서 오류 코드가 발생할 수 있다.
이 단계의 목표는 “장치가 보인다” 수준을 넘어서, 프레임이 실제로 생성되는지와 어느 계층에서 끊기는지를 분리하는 것이다. IPU6 문제는 대체로 다음 3계층 중 하나에서 발생한다.
uname -r
cat /proc/cpuinfo | grep "model name" | head -1

이 정보는 커널이 IPU6 드라이버와 관련 패치를 포함하고 있을 가능성을 가늠하는 “환경 컨텍스트”다. 다만 여기서 바로 지원 여부를 단정할 수 없으므로, 다음 단계에서 실제 장치 노출과 파이프라인 상태를 확인한다.
sudo apt install -y v4l-utils
v4l2-ctl --list-devices


수많은 /dev/videoX 노드가 보인다는 것은 IPU6 드라이버가 로드되어 V4L2 인터페이스를 생성했음을 의미한다. 그러나 이 출력만으로는 다음을 알 수 없다.
따라서 이 단계는 “장치 노출 확인”에 해당하며, 실제 영상 생성 여부는 다음 단계에서 별도로 검증해야 한다
lsmod | grep -i ipu

출력 결과 intel_ipu6 및 intel_ipu6_isys는 로드되어 있었으나, intel_ipu6_psys 모듈은 확인되지 않았다. 이는 커널이 IPU6 입력 시스템(ISYS)을 통해 센서 신호를 수집할 준비는 되어 있으나, ISP 처리 파이프라인을 담당하는 PSYS가 커널 레벨에서 활성화되지 않았을 가능성을 시사한다. 결과적으로 /dev/videoX 노드가 다수 생성되더라도, 프레임을 YUV/RGB로 변환·출력하는 처리 단계가 구성되지 않아 “장치는 보이지만 화면은 나오지 않는” 증상으로 이어질 수 있다.
psys 모듈이 “안 보이는 이유”는 크게 3가지.
그래서 다음 단계(2-4)에서는 “psys 모듈 파일 자체가 존재하는지”를 확인해보기로 한다.
modinfo intel_ipu6_psys 2>/dev/null | head

grep -iE 'IPU6|PSYS|ISYS' /boot/config-$(uname -r)

find /lib/modules/$(uname -r) -iname '*ipu6*psys*.ko*'

ntel_ipu6_isys모듈은 로드되어 있으나 ntel_ipu6_psys모듈은 확인되지 않았다. 또한 odinfo intel_ipu6_psys 정보를 반환하지 않았고, lib/modules/$(uname -r)에서 *ipu6*psys*.ko*파일도 발견되지 않았다. 이는 현재 커널 빌드(6.17.0-14-generic)에서 IPU6 PSYS 드라이버가 모듈 형태로 제공되지 않음을 의미한다. 결과적으로 입력(ISYS) 계층은 존재하지만, 영상 처리(PSYS/ISP) 계층이 누락되어 “장치는 보이나 프레임이 생성되지 않는” 증상으로 이어질 수 있다.
여기까지의 관찰만 놓고 보면 “PSYS 모듈이 없으니 PSYS만 설치하면 끝”처럼 보이지만, IPU6 카메라 스택은 그렇게 단순하지 않다. IPU6 기반 MIPI 카메라는 커널 드라이버(ISYS/PSYS)만으로 완전 동작하지 않고, 사용자 공간에서 libcamera 파이프라인(IPA 모듈, 펌웨어/튜닝 데이터)과 PipeWire 스트림 협상까지 연결되어야 애플리케이션에서 실제 프레임이 나온다. 따라서 다음 단계에서는 문제를 “PSYS 부재”로 단정하기 전에, 영상 파이프라인이 어느 계층에서 끊기는지(A/B/C)부터 다시 분리해 확인한다.
V4L2에서 /dev/videoX가 보인다고 해서 곧바로 “카메라가 동작한다”라고 말할 수는 없다. IPU6 계열은 특히 커널 드라이버(장치 노출)와 사용자 공간 파이프라인 구성(실제 영상 생성)이 분리되어 있는 경우가 많다.
즉, 커널 단계에서 ISYS까지 올라와 /dev/videoX가 생성되더라도, 사용자 공간에서 ISP 파이프라인(IPA 모듈, 튜닝 데이터, 펌웨어 등)이 제대로 잡히지 않으면 화면은 끝까지 나오지 않는다.
이때 가장 빠른 검증 도구가 libcamera다. libcamera는 단순히 V4L2 장치를 “열어보는” 수준이 아니라, 카메라 파이프라인을 구성하고 실제 프레임을 요청하는 흐름까지 수행한다. 따라서 libcamera가 카메라를 정상적으로 열 수 있는지는 “사용자 공간 스택이 완성됐는지(가설 B)”를 판단하는 강한 신호가 된다.
아래 순서로 확인한다.
sudo apt install -y libcamera-tools
cam -l
cam -c 0

cam -l 결과에서 Available cameras가 비어 있거나, No IPA found in '/usr/lib/x86_64-linux-gnu/libcamera'와 같은 경고가 뜬다면 사용자 공간에서 IPA(파이프라인 알고리즘 플러그인)를 로딩하지 못해 파이프라인 초기화 자체가 불가능한 상태일 수 있다. 이 경우는 커널에서 장치 노드가 보이더라도 실제 영상 처리가 구성되지 않으므로 가설 B(사용자 공간 스택 미완성) 를 우선으로 본다.
반대로 cam -c 0에서 정상적으로 프레임이 나오는데 Discord/OBS에서만 실패한다면, 프레임 생성 자체는 성공한 것이므로 문제는 PipeWire/포털/세션 연결 또는 포맷 변환(가설 C) 로 좁혀진다.
용어 설명
- IPA (Image Processing Algorithms)
IPA는 libcamera가 카메라 ISP를 제어하기 위해 사용하는 사용자 공간 알고리즘 모듈이다. IPU6 기반 카메라는 센서 데이터만으로는 영상이 생성되지 않으며, 자동 노출·화이트밸런스·색 보정 등의 처리 알고리즘이 적용되어야 정상적인 프레임이 만들어진다. libcamera는 해당 하드웨어에 맞는 IPA를 로드해 ISP 파이프라인을 초기화하고 제어한다. IPA가 없거나 로드되지 않으면 커널에서 장치가 보이더라도 libcamera 단계에서 파이프라인이 열리지 않으며, 결과적으로 영상이 출력되지 않는다.
PipeWire 환경에서는 “카메라가 보인다”와 “카메라 스트림이 실제로 연결되어 흐른다”가 다르다.
권한 팝업이 뜨는 것은 포털(xdg-desktop-portal)이 장치 접근 요청을 받았고, PipeWire가 장치를 감지했다는 의미일 뿐이다. 그 다음 단계(노드 생성 → 링크 생성 → 포맷 협상)가 실패하면, 애플리케이션에서는 장치가 보이더라도 검은 화면 또는 오류 코드(예: Discord의 에러)로 끝난다.
PipeWire 쪽 상태는 서비스 상태 + 로그 두 축으로 확인한다.
systemctl --user status pipewire wireplumber xdg-desktop-portal
journalctl --user -u pipewire -u wireplumber -u xdg-desktop-portal -e
여기서 확인할 포인트는 다음과 같다.
이런 메시지가 확인되면, PipeWire-Portal-Session(=wireplumber) 레벨에서 스트림이 완성되지 못하는 문제, 즉 가설 C로 방향을 잡는 게 논리적으로 맞다.


SPA handle 'api.libcamera.enum.manager' could not be loaded; is it installed?
PipeWire's libcamera SPA missing or broken. libcamera not supported.
이 메시지는 매우 직접적이다.
PipeWire가 libcamera 기반 카메라를 감지하려 했지만, libcamera SPA 플러그인을 로드하지 못했다는 뜻이다.
즉, PipeWire는 실행 중이지만 libcamera를 입력 소스로 사용할 수 없는 상태다. 이것은 포맷 협상 실패나 노드 링크 실패 같은 가설 C(미디어 세션/포털 문제)가 아니라, libcamera 계층 자체가 불완전하다는 가설 B(사용자 공간 스택 미완성)를 강하게 지지한다.
지금까지는 ipu6, isys, psys처럼 IPU6 계열 키워드를 중심으로 확인했다. 하지만 실제 부팅 로그에서는 문제가 꼭 ipu6라는 문자열로만 나타나지 않는다.
예를 들어 다음과 같은 경우가 있다.
ov02..., ov08..., imx..., gc...) 초기화 실패즉, /dev/videoX가 생성되어도 실제 원인은 IPU6 본체가 아니라 센서 드라이버나 주변 초기화 단계에 있을 수 있다.
따라서 dmesg 확인 단계에서는 특정 드라이버명만 찾지 말고, 카메라 스택 전반을 넓게 검색하는 것이 더 안전하다.
dmesg | grep -iE 'ipu|isys|psys|camera|sensor|v4l2|media|uvc|mipi|csi|i2c|ov[0-9]+|imx[0-9]+|gc[0-9]+'
이 명령은 다음 범주의 로그를 한 번에 확인하기 위한 것이다.
ipu, isys, psyscamera, sensor, v4l2, mediamipi, csi, i2cov..., imx..., gc...uvc특히 노트북 내장 카메라는 센서명이 직접 로그에 찍히는 경우가 많으므로, ov..., imx..., gc... 패턴까지 같이 보는 것이 좋다.
단순 키워드 검색만으로는 정상 로그와 오류 로그가 섞여서 보이기 때문에, 그다음에는 실패 패턴을 중심으로 한 번 더 필터링한다.
dmesg | grep -iE 'ipu|isys|psys|camera|sensor|v4l2|media|uvc|mipi|csi|i2c|ov[0-9]+|imx[0-9]+|gc[0-9]+' | grep -iE 'fail|error|warn|timeout|probe|unable|not found|no such|invalid|unsupported|cannot|can.t|firmware'
커널 로그는 실패를 여러 표현으로 남기므로, fail처럼 어근 단위로 잡는 편이 더 낫다. 예를 들어 다음과 같은 로그를 잡아낼 수 있다.
probe failedfailed to register subdeviceerror -22firmware not foundunable to loadtimeout waiting for responseunsupported pixel format배포판에 따라 dmesg보다 journalctl -b -k가 읽기 더 편한 경우도 있다.
journalctl -b -k | grep -iE 'ipu|isys|psys|camera|sensor|v4l2|media|uvc|mipi|csi|i2c|ov[0-9]+|imx[0-9]+|gc[0-9]+' | grep -iE 'fail|error|warn|timeout|probe|unable|not found|no such|invalid|unsupported|cannot|can.t|firmware'


위 두 출력에서 가장 핵심적인 메시지는 아래와 같다.
ov02c10 i2c-OVTI02C1:00: error -EINVAL: external clock 26000000 is not supported
ov02c10 i2c-OVTI02C1:00: probe with driver ov02c10 failed with error -22
의미를 풀면 다음과 같다 :
ov02c10으로 인식하려고 시도했다.26,000,000 Hz (26MHz)를 받았는데, 현재 드라이버 또는 해당 구성에서는 이 클럭값을 지원하지 않는다고 판단했다.probe가 실패했다.error -22는 리눅스 커널에서 EINVAL(Invalid argument) 이다. 즉, 드라이버가 받은 파라미터나 하드웨어 설정값이 자신이 처리할 수 있는 범위와 맞지 않는다는 뜻이다.이건 단순한 경고가 아니라, 커널 레벨에서 센서 드라이버가 실제로 장치 바인딩에 실패했다는 뜻이다.
원칙적으로는 여기서 다음을 더 확인할 수도 있다.
하지만 이번 글에서는 이 탐색을 더 이어가지 않기로 한다.
이유는 이미 충분히 많은 간접 정황이 쌓였고, 무엇보다 커널 로그가 센서 probe 실패를 매우 직접적으로 가리키고 있기 때문이다. 즉, 더 많은 검색과 패키지 비교를 반복하기보다, 문제의 진원지로 보이는 센서 드라이버 코드 자체를 확인하고 수정하는 편이 오히려 더 빠르다고 판단했다.
따라서 현 단계의 중간 결론은 다음과 같다.
ov02c10 드라이버가 26MHz external clock 구성을 수용하지 못해 probe에 실패하고 있다.ov02c10 센서 드라이버 소스를 직접 열어 클럭 허용 조건과 probe 경로를 확인하는 방식으로 접근한다.즉, 이제부터의 문제 해결 방향은 “환경을 더 검색해보는 것”이 아니라, “센서 드라이버 코드가 왜 26MHz를 거부하는지 직접 확인하고 수정하는 것”이다.
ov02c10 센서 드라이버 소스 수정 및 반영하기ov02c10 소스 코드 수정그래서 다음 단계는 “ov02c10 드라이버 소스가 실제로 어디에 있고, 어떤 커널 패키지에서 빌드되었는지”를 확인하는 것이다. 이걸 확인해야 패치가 가능하다.
현재 로드된 모듈이 어느 패키지 소스에서 왔는지부터 확인했다.
apt-cache show linux-modules-$(uname -r) | egrep -i '^(Package|Version|Source):'

이 드라이버는 linux-hwe-6.17 소스 트리에서 빌드된 결과물이다. 그리고 실제 소스 트리를 받기 위해 다음을 실행했다.
apt-get source linux-hwe-6.17

Ubuntu는 기본적으로 소스 패키지 저장소(deb-src)를 비활성화해 두기 때문에 apt-get source가 바로 동작하지 않는다. 따라서 sources.list에 deb-src를 활성화해야 한다.

Ubuntu 24.04부터는 예전 방식(/etc/apt/sources.list)이 아니라
새로운 *.sources 파일 형식을 사용한다. 그래서 sources.list를 수정하는 게 아니라 ubuntu.sources 파일을 수정해야 한다.
sudo nano /etc/apt/sources.list.d/ubuntu.sources


Types 줄에 deb-src를 추가하고 저장한다.
sudo apt update
이제 source repository가 활성화된다.
apt-get source linux-hwe-6.17
현재 디렉터리에 linux-hwe-6.17-6.17.x 폴더가 생성되었다.


폴더 내부에서 drivers/media/i2c/ov02c10.c 경로에서 우리가 수정해야할 드라이브를 찾을 수 있다.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2022 Intel Corporation.
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/version.h>
#include <media/v4l2-cci.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#define OV02C10_LINK_FREQ_400MHZ 400000000ULL
#define OV02C10_MCLK 19200000
/* 중략 */
/* Try to force expected MCLK if a controllable clock is provided */
if (ov02c10->img_clk && mclk != OV02C10_MCLK) {
ret = clk_set_rate(ov02c10->img_clk, OV02C10_MCLK);
if (!ret)
mclk = clk_get_rate(ov02c10->img_clk);
}
/*
* Upstream driver expects 19.2MHz, but some platforms wire 26MHz.
* Allow 26MHz as a pragmatic quirk so probe can continue.
*/
if (mclk != OV02C10_MCLK && mclk != 26000000) {
fwnode_handle_put(ep);
return dev_err_probe(dev, -EINVAL,
"external clock %u is not supported\n",
mclk);
}
if (mclk == 26000000)
dev_warn(dev, "using non-standard external clock %uHz (expected %uHz)\n",
mclk, OV02C10_MCLK);
ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
fwnode_handle_put(ep);
if (ret)
return dev_err_probe(dev, ret, "parsing endpoint failed\n");
/* 중략 */
module_i2c_driver(ov02c10_i2c_driver);
MODULE_AUTHOR("Hao Yao <hao.yao@intel.com>");
MODULE_AUTHOR("Heimir Thor Sverrisson <heimir.sverrisson@gmail.com>");
MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
MODULE_DESCRIPTION("OmniVision OV02C10 sensor driver");
MODULE_LICENSE("GPL");
ov02c10_check_hwcfg() 로직을 수정하였다. 해당 함수는 드라이버가 센서를 실제로 등록하기 전에, 플랫폼이 제공하는 하드웨어 구성(클럭 주파수, CSI2 lane 구성, link frequency 등)이 드라이버가 가정하는 조건과 일치하는지를 점검하는 “게이트” 역할을 한다. 여기서 -EINVAL로 리턴되면 probe는 즉시 중단되고, 이후 계층(CamHAL, icamerasrc, libcamera)은 정상적인 센서 파이프라인을 열 기회를 얻지 못한다.
클럭을 강제로 맞출 수 없거나(하드웨어 고정), ACPI/펌웨어가 이미 26MHz로 설정해 둔 플랫폼을 고려해, 기존에는 즉시 실패하던 조건을 완화하여 26MHz를 예외적으로 허용하도록 변경했다. 즉, 19.2MHz만 허용하던 “하드 실패(hard fail)” 정책을 “경고 후 진행(warn-and-continue)” 정책으로 바꾸었다.
ov02c10.c 소스를 수정했다고 해서 바로 시스템에 반영되는 것은 아니다. 리눅스 커널 드라이버는 커널 모듈 형태로 빌드되어 /lib/modules/<kernel-version>/ 아래에 설치되기 때문에, 수정한 코드를 실제로 사용하려면 해당 모듈을 다시 빌드하여 커널이 로드하도록 만들어야 한다.
이때 선택지는 크게 두 가지가 있다.
1. 커널 전체를 다시 빌드하는 방법
2. 해당 드라이버 모듈만 별도로 빌드하여 덮어쓰는 방법
첫 번째 방법은 안정적이지만 시간과 작업량이 크다. 이번 경우처럼 특정 센서 드라이버 하나만 수정한 상황에서는 모듈만 재빌드하는 방식이 훨씬 현실적이다.
또한 단순히 한 번 빌드해 /lib/modules에 복사하는 방식은 커널 업데이트 시 다시 원복될 가능성이 있다. 이 문제를 해결하기 위해 사용하는 것이 DKMS(Dynamic Kernel Module Support)이다.
DKMS는 수정한 모듈 소스를 시스템에 등록해 두고,
/lib/modules/<kernel>/updates/dkms/ 아래에 설치한다.즉, 커널 업데이트 이후에도 패치가 유지되는 구조를 만들 수 있다.
먼저 모듈을 빌드할 수 있도록 필요한 패키지를 설치한다.
sudo apt update
sudo apt install -y dkms build-essential linux-headers-$(uname -r)
dkms : 모듈 자동 재빌드 관리build-essential : gcc, make 등 기본 빌드 도구linux-headers : 현재 커널에 맞는 커널 헤더DKMS는 /usr/src/<module-name>-<version>/ 경로에 소스를 저장한다
sudo mkdir -p /usr/src/ov02c10-1.0
여기서 1.0은 임의의 버전이다. 추후 패치를 수정하면 1.1, 1.2 등으로 올릴 수 있다.
앞서 받아 둔 커널 소스 트리에서 수정한 ov02c10.c를 복사한다.
sudo cp ~/linux-hwe-6.17-6.17.x/drivers/media/i2c/ov02c10.c \
/usr/src/ov02c10-1.0/
DKMS가 모듈을
빌드할 때 사용할 Makefile을 작성한다.
sudo nano /usr/src/ov02c10-1.0/Makefile
내용은 다음과 같다.
obj-m += ov02c10.o
KDIR := /lib/modules/$(KERNEL_VERSION)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
여기서 $(KERNEL_VERSION)은 DKMS가 빌드 시 자동으로 전달한다.
DKMS에게 이 모듈을 어떻게 빌드하고 어디에 설치할지 알려주는 설정 파일을 만든다.
sudo nano /usr/src/ov02c10-1.0/dkms.conf
내용은 다음과 같다
PACKAGE_NAME="ov02c10"
PACKAGE_VERSION="1.0"
BUILT_MODULE_NAME[0]="ov02c10"
DEST_MODULE_LOCATION[0]="/kernel/drivers/media/i2c"
AUTOINSTALL="yes"
AUTOINSTALL="yes"는 매우 중요한 옵션이다. 커널이 업데이트될 때마다 자동으로 모듈을 다시 빌드하도록 지시한다.
이제 DKMS에 모듈을 등록하고 빌드를 수행한다.
sudo dkms add -m ov02c10 -v 1.0
sudo dkms build -m ov02c10 -v 1.0
sudo dkms install -m ov02c10 -v 1.0

정상적으로 완료되면 DKMS는 수정된 ov02c10 모듈을 다음 위치에 설치한다
/lib/modules/<kernel-version>/updates/dkms/
이 경로에 설치된 모듈은 기본 커널 모듈보다 우선적으로 로드된다.
모듈이 실제로 적용되었는지 확인하기 위해 시스템을 재부팅한다.
sudo reboot
부팅 후 다시 dmesg를 확인한다.
dmesg | grep -i ov02c10

현재 dmesg를 보면 가장 중요한 변화는 이미 확인되었다. 기존의 핵심 실패 원인이었던
external clock 26000000 is not supported
로그가 더 이상 나타나지 않고, 대신 다음과 같이 출력된다.
using non-standard external clock 26000000Hz (expected 19200000Hz)
부팅 초기에 ov02c10 probe가 실행될 때, 우리가 DKMS로 설치한 수정 모듈이 실제로 사용되었음을 의미한다. 즉, 26MHz 클럭 검증 게이트는 더 이상 probe를 중단시키지 않는다.
이어지는 로그:
supply dovdd not found, using dummy regulator
supply dvdd not found, using dummy regulator
이 단계는 probe가 “전원/레귤레이터 확인 단계”로 진입했음을 보여준다. ACPI나 DT에 해당 regulator가 명시되지 않았거나, 플랫폼이 상시전원 구조이기 때문에 더미 레귤레이터로 진행하는 상태다. 여기까지는 실패가 아니라 진행 중 로그다.
설치된 DKMS 모듈은 다음 명령으로 확인할 수 있다.
dkms status

이 상태라면 이후 커널 업데이트가 발생하더라도 DKMS가 자동으로 해당 모듈을 재빌드하여 유지한다.
다음 단계에서는 실제로 센서가 media graph에 등록되었는지와 libcamera 경로가 정상 동작하는지를 확인한다.
DKMS를 통해 수정된 ov02c10 드라이버 모듈을 시스템에 적용했다면, 다음 단계는 실제로 센서가 커널의 media graph에 등록되었는지와 userspace 카메라 스택(libcamera)이 정상적으로 동작하는지를 확인하는 것이다.
센서 probe가 더 이상 초기 단계에서 실패하지 않는다고 해서 곧바로 카메라가 정상 동작하는 것은 아니다. 커널 레벨에서 센서가 등록된 이후에도 다음과 같은 여러 계층을 거쳐야 실제 영상이 사용자 프로그램까지 전달된다.
ov02c10)ipu6, isys, psys)따라서 이 단계에서는 먼저 커널 media graph에 센서가 실제로 등록되었는지부터 확인한다.
다음 명령으로 현재 카메라 파이프라인을 출력할 수 있다.
media-ctl -p -d /dev/media0
출력 결과에는 IPU6 capture 노드와 함께 여러 sub-device들이 나타난다. 여기서 중요한 것은 ov02c10 또는 OVTI02C1과 같은 센서 엔티티가 실제로 등록되어 있는지 여부이다.
필터링해서 보면 다음과 같이 확인할 수 있다.
media-ctl -p -d /dev/media0 | grep -i ov02
또는
media-ctl -p -d /dev/media0 | grep -i sensor
센서가 정상적으로 등록되었다면 media graph 어딘가에 ov02c10 관련 엔티티가 나타난다.
만약 아무 결과도 나오지 않는다면 probe는 여전히 중간 단계에서 실패했을 가능성이 있다.


media-ctl 출력에서 ov02c10 센서 엔티티가 확인되고, 해당 센서가 Intel IPU6 CSI2 노드와 [ENABLED] 상태로 연결되어 있는 것을 확인했다. 이는 커널 레벨에서 센서 드라이버 probe와 media graph 등록이 정상적으로 완료되었음을 의미한다.
센서가 media graph에 등록되어 있다면, 다음 단계는 libcamera가 해당 장치를 인식하는지 확인하는 것이다.
cam -l
정상적인 경우 다음과 같이 내부 카메라가 하나 이상 표시된다.
Available cameras:
1: Internal front camera
이 단계에서 카메라가 나타난다면 최소한 다음 경로는 정상적으로 연결된 것이다
sensor → IPU6 → V4L2 → libcamera
만약 카메라 목록이 비어 있다면 다음 두 가지 가능성을 의심해야 한다.

여기서 두 가지 중요한 사실을 확인할 수 있다.
첫째, 현재 실행 중인 libcamera 버전은 Ubuntu 기본 패키지에 포함된 libcamera 0.2.0이다.
둘째, libcamera가 IPA(Image Processing Algorithm) 모듈을 찾지 못하고 있다.
IPA는 센서에서 출력된 RAW 이미지를 처리하기 위한 ISP 알고리즘 모듈로, 노출 제어(AE), 화이트 밸런스(AWB), 색 보정(CCM) 등의 기능을 담당한다. 이 모듈이 로드되지 않으면 libcamera는 카메라 파이프라인을 초기화할 수 없다.
실제로 Available cameras: 아래에 아무 장치도 표시되지 않는 것을 확인할 수 있다.
즉 현재 상태는 다음과 같이 정리할 수 있다.
ov02c10 sensor driver ✓ 정상
IPU6 media graph ✓ 정상
libcamera pipeline ✗ 실패
따라서 문제의 원인은 더 이상 커널 드라이버가 아니라 libcamera userspace 스택에 있는 것으로 판단할 수 있다.
다음 단계에서는 Ubuntu 기본 libcamera 패키지와 수동 빌드한 libcamera 사이에서 발생할 수 있는 버전 충돌 문제를 정리하고, IPU6 카메라가 정상 동작하도록 libcamera 환경을 재구성한다.
앞 단계에서 cam -l 결과를 통해 현재 userspace 카메라 스택이 Ubuntu 기본 libcamera 0.2 계열이며, 동시에 IPA 모듈이 로드되지 않는 상태임을 확인했다. 따라서 이 장에서는 먼저 현재 0.2 스택을 보완할 수 있는지 확인하고, 필요할 경우 libcamera를 직접 빌드하는 방향으로 userspace 환경을 재구성한다.
먼저 시스템에 설치된 libcamera 관련 패키지를 확인한다
dpkg -l | grep libcamera
출력 결과는 아래와 같다.

즉 현재 시스템에는 Ubuntu 기본 패키지인 libcamera 0.2 계열만 설치되어 있다.
이 버전은 Ubuntu에서 기본 제공하는 userspace 카메라 스택으로, 일반적인 USB UVC 카메라 환경에서는 문제없이 동작한다. 그러나 IPU6 기반 노트북 카메라의 경우에는 다음과 같은 이유로 정상 동작하지 않는 경우가 많다.
현재 설치된 패키지 목록에는 libcamera-tools, libcamera0.2만 보이고, libcamera-ipa는 보이지 않는다. 따라서 우선 배포판 저장소에서 IPA 패키지가 제공되는지 확인한다.
apt-cache search libcamera | grep ipa
또는
apt-cache policy libcamera-ipa
패키지가 존재한다면 다음과 같이 설치한다.
sudo apt install libcamera-ipa

설치 후 다시 다음 명령으로 카메라 인식 여부를 확인한다.
cam -l
이 단계에서 카메라가 정상적으로 나타난다면, 별도의 직접 빌드 없이 Ubuntu 기본 0.2 스택만으로도 userspace 문제가 해결된 것이다. 반대로 여전히 No IPA found 또는 빈 카메라 목록이 유지된다면, 그때는 기본 패키지 조합만으로는 IPU6 파이프라인을 제대로 지원하지 못하는 것으로 보고 직접 빌드 단계로 넘어간다.

여기서 두 가지 사실을 확인할 수 있다.
첫째, 현재 시스템에서 사용 중인 libcamera는 Ubuntu 기본 패키지에 포함된 libcamera 0.2.0이다.
둘째, Available cameras: 아래에 어떤 장치도 표시되지 않는다.
이 결과는 단순히 IPA 모듈이 없는 문제가 아니라, libcamera가 카메라 파이프라인 자체를 생성하지 못하고 있다는 뜻이다.
앞 단계에서 확인했듯이 커널 레벨에서는 이미 다음 경로가 정상적으로 구성되어 있다.
ov02c10 sensor driver ✓ 정상
IPU6 media graph ✓ 정상
/dev/video0 ✓ 생성됨
즉 센서와 IPU6 드라이버는 정상적으로 초기화되었으며, media graph에서도 센서 노드가 등록된 상태다.
따라서 현재 실패 지점은 커널이 아니라 libcamera userspace 파이프라인 초기화 단계라고 볼 수 있다.
Ubuntu 기본 libcamera 0.2는 일부 플랫폼에서는 문제없이 동작하지만, IPU6 기반 노트북 카메라 환경에서는 pipeline handler 지원이 충분하지 않은 경우가 있다. 이 경우 media graph에 장치가 존재하더라도 libcamera가 이를 실제 카메라로 등록하지 못한다.
따라서 다음 단계에서는 Ubuntu 기본 패키지 대신 libcamera를 직접 빌드하여 최신 userspace 스택으로 교체한다.
이 단계에서는 Ubuntu 기본 패키지를 그대로 유지하는 대신, libcamera를 직접 빌드하여 userspace 스택을 최신 버전으로 재구성한다.
먼저 기존 Ubuntu 패키지로 설치된 libcamera를 제거한다.
sudo apt remove --purge libcamera0.2 libcamera-tools libcamera-ipa
패키지를 제거한 뒤에는 불필요한 의존성을 정리한다.
sudo apt autoremove
이 과정을 통해 시스템에는 더 이상 Ubuntu 패키지로 설치된 libcamera 라이브러리가 남지 않게 된다.
이후에는 /usr/local 경로에 직접 빌드한 libcamera를 설치하여 userspace 카메라 스택을 구성하게 된다.
다음 단계에서는 libcamera 소스 코드를 다운로드하고, 최신 버전을 직접 빌드하여 시스템에 설치한다.
Ubuntu 기본 패키지를 제거했다면, 이제 libcamera userspace 스택을 직접 빌드하여 설치할 수 있다. libcamera는 공식 Git 저장소에서 소스를 내려받아 빌드하는 방식으로 설치할 수 있다.
먼저 빌드에 필요한 기본 도구와 의존 패키지를 설치한다.
sudo apt update
sudo apt install -y \
git meson ninja-build pkg-config \
libdrm-dev libexif-dev \
libjpeg-dev libtiff-dev \
libpng-dev \
libgnutls28-dev \
libevent-dev \
python3-pip python3-yaml \
python3-jinja2
이 패키지들은 libcamera의 핵심 라이브러리, GStreamer 연동, 이미지 포맷 처리, 그리고 빌드 시스템(meson)에서 사용하는 의존성들이다.
이제 libcamera 소스를 다운로드한다.
cd /tmp
git clone https://git.libcamera.org/libcamera/libcamera.git
cd libcamera
libcamera는 활발하게 개발되는 프로젝트이기 때문에, 특정 안정 버전을 체크아웃하여 빌드하는 것이 좋다. 여기서는 비교적 안정적인 v0.4.0 태그를 사용한다.
git checkout v0.4.0
이렇게 하면 /tmp/libcamera 디렉터리에 libcamera 0.4.0 소스 트리가 준비된다.

소스를 다운로드했다면 meson과 ninja를 이용해 빌드를 진행한다. 먼저 빌드 디렉터리를 생성하고 설정을 수행한다.
meson setup build \
-Dpipelines=auto \
-Dipas=auto \
-Dgstreamer=enabled \
-Dv4l2=true \
--prefix=/usr/local
여기서 주요 옵션의 의미는 다음과 같다.
Dpipelines=auto : 시스템에서 사용할 수 있는 pipeline handler를 자동으로 활성화한다.
Dipas=auto : 사용 가능한 IPA(Image Processing Algorithm) 모듈을 자동으로 빌드한다.
Dgstreamer=enabled : GStreamer 플러그인을 함께 빌드하여 멀티미디어 파이프라인에서 libcamera를 사용할 수 있도록 한다.
-prefix=/usr/local : Ubuntu 기본 패키지와 충돌하지 않도록 /usr/local 경로에 설치한다.

빌드 과정에서 발생한 에러메시지는 다음과 같다.
ERROR: Options "auto" are not in allowed choices: "ipu3, mali-c55, rkisp1, rpi/vc4, simple, vimc"
이 메시지는 현재 체크아웃한 libcamera v0.4.0 소스 트리에서 auto가 허용되는 옵션이 아니며, 동시에 이 버전의 공식 소스 트리에는 ipu6 pipeline handler가 직접 포함되어 있지 않다는 뜻이다.
이 경우 libcamera는 특정 ISP에 특화된 pipeline 대신, generic media graph를 해석할 수 있는 simple pipeline handler를 사용해 카메라를 구성할 수 있다.
simple pipeline은 다음과 같은 특징을 가진다.
즉 IPU6가 전용 pipeline handler로 지원되지 않는 환경에서도, media graph가 정상적으로 구성되어 있다면 simple pipeline을 통해 카메라 파이프라인을 생성할 수 있다.
앞 단계에서 이미 다음 사실을 확인했다.
ov02c10 sensor driver ✓ 정상
IPU6 media graph ✓ 정상
/dev/video0 ✓ 생성됨
즉 커널 레벨에서 media graph가 정상적으로 구성되어 있기 때문에, libcamera userspace에서는 generic media graph 기반 pipeline인 simple handler를 사용하여 카메라 파이프라인을 생성하는 접근이 가능하다.
따라서 libcamera 빌드 옵션을 다음과 같이 조정한다.
rm -rf build
meson setup build \
-Dpipelines=simple \
-Dipas=simple \
-Dgstreamer=enabled \
-Dv4l2=true \
--prefix=/usr/local
이 설정은 libcamera가 simple pipeline과 simple IPA 모듈을 함께 빌드하도록 하여, IPU6 media graph를 기반으로 userspace 카메라 파이프라인을 구성할 수 있도록 한다.
참고로cmake가 없다면 빌드에 실패하므로 libcamera 빌드에서 자주 필요한 도구들과 의존성들을 먼저 함께 설치한다.
sudo apt install cmake pkg-config python3-yaml python3-jinja2 python3-ply
sudo apt install \
libglib2.0-dev \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libdrm-dev \
libexif-dev \
libjpeg-dev \
libtiff-dev \
libpng-dev \
libgnutls28-dev \
libevent-dev \
libyaml-dev
이미 실패한 빌드 디렉터리가 있다면 먼저 삭제하고 다시 빌드를 진행한다.
cd /tmp/libcamera
rm -rf build
meson setup build \
-Dpipelines=simple \
-Dipas=simple \
-Dgstreamer=enabled \
-Dv4l2=true \
--prefix=/usr/local
libcamera는 다양한 기능(GStreamer 연동, 이미지 포맷 지원 등)을 선택적으로 빌드하기 때문에, 시스템에 필요한 개발 패키지가 없으면 Meson 단계에서 의존성 오류가 발생한다. 이런 경우에는 오류 메시지에 나타난 라이브러리의 -dev 패키지를 설치한 뒤 Meson 설정을 다시 실행하면 된다.
madhamster@treadmill:/tmp/libcamera$ meson setup build -Dpipelines=simple -Dipas=simple -Dgstreamer=enabled -Dv4l2=true --prefix=/usr/local
The Meson build system
Version: 1.3.2
Source dir: /tmp/libcamera
Build dir: /tmp/libcamera/build
Build type: native build
Project name: libcamera
Project version: 0.4.0
C compiler for the host machine: cc (gcc 13.3.0 "cc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0")
C linker for the host machine: cc ld.bfd 2.42
C++ compiler for the host machine: c++ (gcc 13.3.0 "c++ (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0")
C++ linker for the host machine: c++ ld.bfd 2.42
Host machine cpu family: x86_64
Host machine cpu: x86_64
Header "fcntl.h" has symbol "F_ADD_SEALS" : YES
Header "unistd.h" has symbol "issetugid" : NO
Header "locale.h" has symbol "locale_t" : YES
Header "sys/mman.h" has symbol "memfd_create" : YES
Header "stdlib.h" has symbol "secure_getenv" : YES
Compiler for C supports arguments -Wno-c99-designator: NO
Found pkg-config: YES (/usr/bin/pkg-config) 1.8.1
Found CMake: /usr/bin/cmake (3.28.3)
Run-time dependency lttng-ust found: NO (tried pkgconfig and cmake)
Program ./parser.py found: YES (/tmp/libcamera/utils/codegen/ipc/./parser.py)
Program ./generate.py found: YES (/tmp/libcamera/utils/codegen/ipc/./generate.py)
Program ./extract-docs.py found: YES (/tmp/libcamera/utils/codegen/ipc/./extract-docs.py)
Configuring version.h using configuration
Program openssl found: YES (/usr/bin/openssl)
Run-time dependency libyuv found: NO (tried pkgconfig and cmake)
Library atomic found: YES
Run-time dependency threads found: YES
Run-time dependency libdw found: YES 0.190
Run-time dependency libunwind found: YES 1.6.2
Header "execinfo.h" has symbol "backtrace" : YES
Checking for function "dlopen" : YES
Run-time dependency libudev found: YES 255
Run-time dependency yaml-0.1 found: YES 0.2.5
Run-time dependency gnutls found: YES 3.8.3
Dependency libexif skipped: feature android disabled
Dependency libjpeg skipped: feature android disabled
Run-time dependency libevent_pthreads found: YES 2.1.12-stable
Run-time dependency libtiff-4 found: YES 4.5.1
Run-time dependency GTest found: NO (tried pkgconfig and system)
Looking for a fallback subproject for the dependency gtest
Executing subproject gtest
gtest| Project name: gtest
gtest| Project version: 1.11.0
gtest| C++ compiler for the host machine: c++ (gcc 13.3.0 "c++ (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0")
gtest| C++ linker for the host machine: c++ ld.bfd 2.42
gtest| Dependency threads found: YES unknown (cached)
gtest| Dependency threads found: YES unknown (cached)
gtest| Dependency threads found: YES unknown (cached)
gtest| Dependency threads found: YES unknown (cached)
gtest| Build targets in project: 36
gtest| Subproject gtest finished.
Dependency gtest from subproject subprojects/googletest-release-1.11.0 found: YES 1.11.0
Run-time dependency libdrm found: YES 2.4.125
Run-time dependency libjpeg found: YES 2.1.5
sdl2-config found: NO
Run-time dependency sdl2 found: NO (tried pkgconfig, config-tool and cmake)
Run-time dependency qt6 (modules: Core, Gui, OpenGL, OpenGLWidgets, Widgets) found: NO (tried pkgconfig)
Run-time dependency glib-2.0 found: YES 2.80.0
Run-time dependency gstreamer-video-1.0 found: YES 1.24.2
Run-time dependency gstreamer-allocators-1.0 found: YES 1.24.2
Run-time dependency python3 found: YES 3.12
pybind11-config found: NO
Run-time dependency pybind11 found: NO (tried pkgconfig, config-tool and cmake)
Configuring libcamerify using configuration
Program doxygen found: NO
Program dot found: NO
Program sphinx-build-3 found: NO
Program sphinx-build found: NO
Configuring config.h using configuration
Program python3 (jinja2, yaml, jinja2, ply) found: YES (/usr/bin/python3) modules: jinja2, yaml, jinja2, ply
Build targets in project: 42
libcamera 0.4.0
Versions
Sources : 0.4.0
Paths
LIBCAMERA_DATA_DIR : "/usr/local/share/libcamera"
LIBCAMERA_SYSCONF_DIR : "/usr/local/etc/libcamera"
IPA_PROXY_DIR : "/usr/local/libexec/libcamera"
IPA_CONFIG_DIR : "/usr/local/etc/libcamera/ipa:/usr/local/share/libcamera/ipa"
IPA_MODULE_DIR : "/usr/local/lib/x86_64-linux-gnu/libcamera"
Configuration
SoftISP support : true
IPA modules signed with : gnutls
Enabled pipelines : simple
Enabled IPA modules : simple
Controls files : control_ids_core.yaml
control_ids_debug.yaml
control_ids_draft.yaml
Properties files : property_ids_draft.yaml
property_ids_core.yaml
Hotplug support : YES
Tracing support : NO
Android support : NO
GStreamer support : YES
Python bindings : NO
V4L2 emulation support : YES
cam application : YES
qcam application : NO
lc-compliance application: YES
Unit tests : NO
Subprojects
gtest : YES
User defined options
prefix : /usr/local
gstreamer : enabled
ipas : simple
pipelines : simple
v4l2 : true
Found ninja-1.11.1 at /usr/bin/ninja
이번 설정 로그에서 가장 중요한 부분은 아래 항목들이다.
Enabled pipelines : simple
Enabled IPA modules : simple
GStreamer support : YES
V4L2 emulation support : YES
cam application : YES
이 설정은 현재 libcamera가 다음 구성을 기준으로 빌드될 것임을 의미한다.
simple pipeline handler 사용simple IPA 모듈 사용cam 테스트 도구 포함앞서 확인했듯이 사용 중인 libcamera 0.4.0 공식 소스 트리에는 IPU6 전용 pipeline handler가 직접 포함되어 있지 않다. 따라서 이 단계에서는 IPU6 전용 handler를 활성화하는 대신, 이미 정상적으로 구성된 media graph를 기반으로 동작할 수 있는 generic pipeline handler인 simple을 사용하도록 설정한 것이다.
로그의 경로 정보도 중요하다.
LIBCAMERA_DATA_DIR : "/usr/local/share/libcamera"
LIBCAMERA_SYSCONF_DIR : "/usr/local/etc/libcamera"
IPA_PROXY_DIR : "/usr/local/libexec/libcamera"
IPA_CONFIG_DIR : "/usr/local/etc/libcamera/ipa:/usr/local/share/libcamera/ipa"
IPA_MODULE_DIR : "/usr/local/lib/x86_64-linux-gnu/libcamera"
즉 설치가 완료되면 libcamera 관련 파일은 Ubuntu 기본 패키지 경로(/usr/lib, /usr/bin)가 아니라 /usr/local 아래에 배치된다. 이는 배포판 기본 libcamera와 직접 빌드한 libcamera를 논리적으로 분리하기 위한 것이다.
이제 설정 단계는 끝났으므로, 다음 단계에서는 실제 컴파일과 설치를 수행한다.
ninja -C build

이 명령은 /tmp/libcamera/build 디렉터리의 설정을 바탕으로 libcamera 라이브러리, cam 도구, GStreamer 플러그인, 그리고 simple IPA 모듈을 컴파일한다.
컴파일이 끝나면 다음 명령으로 시스템에 설치한다.
sudo ninja -C build install
sudo ldconfig
설치가 완료되면 주요 파일들은 다음과 같은 경로에 배치된다.
libcamera 라이브러리 : /usr/local/lib/x86_64-linux-gnu/
IPA 모듈 : /usr/local/lib/x86_64-linux-gnu/libcamera/
IPA proxy : /usr/local/libexec/libcamera/
설정 및 데이터 파일 :
/usr/local/share/libcamera/
실행 파일 (cam, libcamerify 등) : /usr/local/bin/
이 단계까지 완료되면 시스템은 더 이상 Ubuntu 기본 패키지의 libcamera 0.2만을 사용하는 것이 아니라, /usr/local에 직접 설치한 libcamera 0.4.0 기반 userspace 스택을 사용할 준비가 된 상태가 된다.
설치가 끝난 뒤에는 먼저 libcamera 관련 파일이 실제로 생성되었는지 확인한다. ldconfig 명령은 정상적으로 실행되더라도 별도의 성공 메시지를 출력하지 않는 경우가 많으므로, 실제 파일과 라이브러리 경로를 직접 확인하는 것이 더 확실하다.
먼저 IPA 모듈이 설치되었는지 확인한다.
ls -al /usr/local/lib/x86_64-linux-gnu/libcamera/

정상적으로 설치되었다면 최소한 다음 파일들이 보여야 한다.
ipa_soft_simple.soipa_soft_simple.so.sign다음으로 라이브러리 로더에 새 libcamera가 등록되었는지 확인한다.
ldconfig -p | grep libcamera

정상적인 경우 /usr/local/lib/x86_64-linux-gnu 아래의 libcamera.so.0.4 와 libcamera-base.so.0.4 가 표시된다.
또한 실제 cam 실행 파일이 어디를 가리키는지도 함께 확인한다.
which cam
ldd $(which cam) | grep libcamera

이때 cam이 /usr/local/bin/cam 을 가리키고, ldd 결과에서 /usr/local/lib/x86_64-linux-gnu/libcamera.so.0.4 가 나타나면 직접 빌드한 libcamera 0.4 userspace 스택이 실제로 사용되는 상태라고 볼 수 있다.
libcamera 0.4 설치가 끝난 뒤 다시 cam -l을 실행하여 카메라 장치 인식 여부를 확인했다
cam -l

출력 결과는 다음과 같다.
Available cameras:
1: Internal front camera (\_SB_.PC00.LNK0)
이 결과는 libcamera가 실제 카메라 장치를 정상적으로 등록했음을 의미한다. 즉 다음 경로가 모두 정상적으로 연결된 상태다.
ov02c10 sensor
→ IPU6 media graph
→ libcamera pipeline
→ userspace camera device
로그에는 여러 경고 메시지가 함께 출력된다. 예를 들어 다음과 같은 메시지가 나타난다.
The sensor kernel driver needs to be fixed
No static properties available for 'ov02c10'
Failed to retrieve the sensor crop rectangle
이 메시지들은 센서 드라이버가 일부 메타데이터(예: crop 영역, sensor properties)를 제공하지 않기 때문에 발생하는 경고이다. 그러나 실제 카메라 장치 생성에는 영향을 주지 않는다. 또한 다음 메시지도 확인할 수 있다.
Could not open any dma-buf provider
Failed to create DmaBufAllocator
이는 하드웨어 ISP나 GPU 기반 DMA 버퍼를 사용할 수 없는 환경에서 나타나는 로그로, libcamera가 software pipeline으로 동작하도록 fallback 했음을 의미한다.
중요한 점은 카메라 장치 자체는 정상적으로 생성되었다는 것이다.
따라서 다음 단계에서는 실제 영상 스트림을 확인하기 위해 libcamera 테스트 도구와 ffmpeg를 이용해 카메라 동작을 검증한다.
cam -c1 --capture=10

이 로그는 카메라 스트림이 실제로 동작하고 있음을 증명한다. 다음 단계에서는 일반적인 멀티미디어 도구가 이 카메라 스트림을 사용할 수 있는지 확인하기 위해 ffmpeg 기반 테스트를 진행했다.
libcamerify ffplay /dev/video0
이 명령은 libcamera의 V4L2 호환 계층을 통해 /dev/video0 장치를 ffmpeg에서 사용할 수 있도록 시도한다. 즉 내부적으로 다음과 같은 경로로 동작한다.
ffplay
→ V4L2 인터페이스
→ libcamera V4L2 compatibility layer
→ libcamera pipeline
→ 센서 스트림


실행 결과 로그에는 다음과 같은 메시지가 나타난다.
V4L2Compat: Camera does not support FrameDurationLimits
Cannot find a proper format for codec 'none'
pixel format 'none'
이 메시지는 ffmpeg가 사용할 수 있는 영상 포맷을 찾지 못했다는 의미다. 원인은 센서가 출력하는 원본 데이터 포맷에 있다.
현재 cam 실행 로그에서 확인한 스트림 포맷은 다음과 같다.
1928x1092-SRGGB10
여기서 SRGGB10은 다음을 의미한다.
즉 이 카메라는 RGB나 YUV 같은 일반적인 영상 포맷을 직접 출력하는 것이 아니라, 다음과 같은 형태의 데이터를 전달한다.
10bit Bayer RAW (SRGGB10)
일반적인 웹캠은 보통 다음과 같은 포맷을 제공한다.
YUYV
MJPEG
NV12
이 포맷들은 대부분의 영상 프로그램에서 바로 처리할 수 있다. 그러나 Bayer RAW 데이터는 색 보정, 디베이어링(demosaic), 화이트밸런스 등의 ISP 처리를 거쳐야 정상적인 영상으로 변환된다.
libcamera는 이러한 처리를 담당하는 IPA(Image Processing Algorithm) 또는 ISP 경로를 통해 RAW 데이터를 영상 포맷으로 변환할 수 있다. 하지만 ffmpeg가 /dev/video0을 통해 직접 접근하는 경우에는 이 처리 단계가 적용되지 않는다.

디스코드 실행시 장치 이름이 ipu6로 보이고 여전히 카메라 연결에 실패하고 있다.
Discord는 libcamera를 직접 사용하는 프로그램이 아니다. Linux 환경에서 Discord는 일반적으로 다음 경로를 통해 카메라를 사용한다.
Discord
→ PipeWire
→ libcamera plugin
→ IPU6
즉 Discord가 카메라에 접근하려면 PipeWire가 libcamera 카메라를 인식해야 한다. 따라서 Discord에서 “카메라 연결 실패”가 발생하는 경우 대부분 문제는 PipeWire ↔ libcamera 브리지 계층에서 발생한다.
IPU6 카메라를 PipeWire가 인식하려면 다음 플러그인이 필요하다.
libspa-0.2-libcamera
이 플러그인은 PipeWire가 libcamera 기반 카메라 장치를 PipeWire 노드로 변환하는 역할을 한다. 설치 여부는 다음 명령으로 확인할 수 있다.
dpkg -l | grep libspa

정상적인 경우 해당 패키지가 목록에 포함되어 있어야 한다. 만약 없다면 다음 명령으로 설치한다.
sudo apt install libspa-0.2-libcamera
설치 후 PipeWire를 재시작한다.
systemctl --user restart pipewire pipewire-pulse wireplumber
재부팅하여 아래 명령을 실행한다.
pw-cli ls Node

PipeWire는 libcamera 카메라가 아니라 V4L2 장치를 카메라로 사용하고 있다. 이 구조를 정리하면 현재 시스템의 카메라 경로는 다음과 같다.
sensor
→ IPU6
→ libcamera
→ V4L2 compatibility layer
→ /dev/video0
→ PipeWire
→ Discord
여기서 /dev/video0 장치는 실제 하드웨어 장치가 아니라 libcamera의 V4L2 compatibility layer가 생성한 가상 장치이다. libcamera는 다음 모듈을 통해 이 장치를 생성한다.
/usr/local/libexec/libcamera/v4l2-compat.so
이 모듈의 역할은 libcamera 기반 카메라를 일반적인 V4L2 장치처럼 보이도록 변환하는 것이다. 덕분에 ffmpeg, PipeWire, 브라우저, Discord 같은 프로그램들이 /dev/video0 장치를 카메라처럼 사용할 수 있게 된다.
/usr/local libcamera를 찾는지 확인이번 과정에서는 libcamera를 직접 빌드하여 다음 경로에 설치했다.
/usr/local/lib/x86_64-linux-gnu
하지만 일부 PipeWire 환경에서는 기본적으로 다음 경로만 검색한다.
/usr/lib/x86_64-linux-gnu
이 경우 PipeWire가 libcamera 라이브러리를 로드하지 못하는 상황이 발생할 수 있다. 먼저 시스템 라이브러리 로더에 등록되었는지 확인한다.
ldconfig -p | grep libcamera
이미 이전 단계에서 /usr/local/lib/x86_64-linux-gnu/libcamera.so.0.4 가 등록된 것을 확인했지만, PipeWire가 여전히 찾지 못하는 경우에는 IPA 모듈 경로를 직접 지정할 수도 있다.

첨부한 스크린샷 결과를 보면 한 가지 중요한 사실을 확인할 수 있다.
libcamera.so.0.4 → /usr/local/lib/x86_64-linux-gnu
libcamera.so.0.2 → /lib/x86_64-linux-gnu
즉 현재 시스템에는 두 개의 libcamera 버전이 동시에 존재한다.
libcamera 0.2libcamera 0.4Linux에서는 보통 /usr/local 경로가 /usr보다 우선순위가 높기 때문에, 직접 빌드한 프로그램들은 다음 라이브러리를 사용하게 된다.
/usr/local/lib/x86_64-linux-gnu/libcamera.so.0.4
하지만 PipeWire 플러그인의 경우 상황이 조금 다르다. Ubuntu에서 제공되는 PipeWire의 libcamera 플러그인은 보통 배포판에 포함된 libcamera 버전을 기준으로 빌드되어 있다.
즉 내부적으로 다음 라이브러리를 기대하는 경우가 많다.
/lib/x86_64-linux-gnu/libcamera.so.0.2
반면 현재 시스템에서 실제 카메라 스택은 다음 구조를 사용하고 있다.
libcamera 0.4
→ /usr/local/lib/x86_64-linux-gnu
이 경우 PipeWire 플러그인이 직접 빌드한 libcamera를 제대로 로드하지 못하면 다음과 같은 상황이 발생할 수 있다.
PipeWire
→ libcamera plugin 로드 실패
→ V4L2 장치 fallback
실제로 앞 단계에서 pw-cli ls Node 결과를 보면 PipeWire가 libcamera 카메라가 아니라 V4L2 장치를 카메라로 사용하고 있는 것을 확인할 수 있었다.
object.path = "v4l2:/dev/video0"
node.description = "ipu6 (V4L2)"
이는 PipeWire가 libcamera 카메라 노드를 직접 생성하지 못하고, 대신 /dev/video0 장치를 통해 카메라에 접근하고 있음을 의미한다.
이 문제를 확인하기 위해 libcamera IPA 모듈 경로를 직접 지정해 보았다.
export LIBCAMERA_IPA_MODULE_PATH=/usr/local/lib/x86_64-linux-gnu/libcamera
systemctl --user import-environment LIBCAMERA_IPA_MODULE_PATH
systemctl --user restart wireplumber pipewire pipewire-pulse
이후 환경 변수가 실제로 반영되었는지 확인했다.
printenv LIBCAMERA_IPA_MODULE_PATH
또한 PipeWire와 WirePlumber 로그에 libcamera 관련 메시지가 남는지 확인했다.
journalctl --user -u wireplumber -u pipewire --since "5 min ago" | grep -iE 'libcamera|spa|camera|v4l2'

여기서 확인되는 핵심은 두 가지다.
첫째, LIBCAMERA_IPA_MODULE_PATH 자체는 정상적으로 설정되었다.
즉 /usr/local/lib/x86_64-linux-gnu/libcamera 경로에 설치된 IPA 모듈은 현재 셸 기준으로는 참조 가능한 상태다.
둘째, PipeWire와 WirePlumber 로그에는 libcamera 관련 메시지가 나타나지 않았다.
이 점이 중요하다. 만약 PipeWire가 직접 빌드한 libcamera 0.4 기반 플러그인을 실제로 로드하고 있었다면, 최소한 libcamera 관련 초기화 흔적이나 SPA 플러그인 로드 메시지가 로그에 남는 편이 자연스럽다. 그런데 관련 로그가 비어 있다는 것은, 현재 PipeWire가 libcamera 경로를 적극적으로 타고 있다기보다 이미 생성된 V4L2 장치를 camera source로 취급하고 있을 가능성이 더 높다는 뜻이다.
4장까지의 작업을 통해 커널 드라이버, media graph, libcamera userspace 스택까지는 상당 부분 복구되었다. 실제로 cam 명령으로 프레임 캡처가 가능했고, PipeWire에서도 카메라 source 자체가 완전히 사라진 상태는 아니었다. 그럼에도 Discord에서는 여전히 카메라 연결 실패가 발생했다.
즉 이 시점의 문제는 더 이상 “센서가 인식되지 않는다”거나 “libcamera가 전혀 동작하지 않는다”는 초기 단계의 문제가 아니었다. 오히려 다음과 같은 복합적인 접합 문제에 가까웠다.
이처럼 문제 지점이 한 계층이 아니라 여러 계층에 걸쳐 있었기 때문에, 단순한 패키지 재설치나 환경 변수 조정만으로는 최종 사용자 앱까지 일관되게 동작시키기 어려웠다. 이 시점에서 비슷한 하드웨어 조합에 대해 이미 정리된 해결 절차가 있는지 찾아보게 되었다.
찾아낸 webcam-fix-libcamera/install.sh는 지금까지 수동으로 확인했던 문제들을 전부 하나의 순서로 엮어 자동화한 형태에 가깝다. 스크립트가 전제하는 기본 파이프라인은 다음과 같다.
IVSC → OV02C10 → IPU6 ISYS → libcamera SimplePipeline → PipeWire
그리고 PipeWire를 직접 쓰지 않는 애플리케이션을 위해 별도의 relay 경로를 둔다.
libcamera → camera-relay → v4l2loopback → /dev/videoX → non-PipeWire 앱
즉 이 스크립트는 “카메라를 보이게 만드는 것”만이 아니라, 최종적으로 브라우저·Discord·Zoom·OBS 같은 앱에서 실제로 사용할 수 있는 카메라 장치를 제공하는 것을 목표로 한다.
스크립트의 내용을 보면, 수행하는 작업은 크게 여섯 부류로 나눌 수 있다.
스크립트는 먼저 현재 시스템이 실제로 지원 대상인지부터 확인한다.
IPU6 세대(Meteor Lake / Raptor Lake), OV02C10 ACPI 센서 존재 여부, IVSC 펌웨어 파일 존재 여부를 점검한다.
이 단계는 단순한 친절 기능이 아니라 중요하다.
왜냐하면 지금까지의 디버깅 과정에서도 확인했듯, IPU6 카메라 문제는 “웹캠이 안 된다”는 표면 증상은 같아도 실제 원인이 하드웨어 식별 실패, 센서 ACPI 누락, 펌웨어 부재 등으로 완전히 달라질 수 있기 때문이다.
이 스크립트에서 가장 눈에 띄는 부분 중 하나는, dmesg에서 다음 오류를 직접 감지한다는 점이다.
external clock 26000000 is not supported
즉 사용자가 별도로 커널 로그를 뒤져 원인을 추론하지 않아도, 스크립트가 이미 known issue로 인식하고 DKMS 패치 설치를 제안한다.
이 부분은 앞서 수동으로 진행했던 작업과 정확히 대응된다.
즉 우리가 직접 ov02c10.c를 수정하고 DKMS로 배포했던 26MHz 허용 패치가, 이 스크립트에서는 하나의 분기 처리로 포함되어 있다.
다시 말해 이 스크립트는 “IPU6 카메라가 안 된다”는 현상을 막연히 다루는 것이 아니라, Book3/Book4 계열에서 실제로 반복되는 ov02c10 external clock mismatch 문제를 이미 별도의 해결 단계로 분리해 두고 있다.
스크립트는 mei-vsc, mei-vsc-hw, ivsc-ace, ivsc-csi 모듈을 로드하고, 이들이 부팅 시점부터 먼저 올라오도록 설정한다.
또한 softdep ov02c10 pre: ... 규칙을 추가해, 센서가 probe되기 전에 IVSC 계열 모듈이 준비되도록 만든다.
이 조치는 매우 실전적이다.
센서 드라이버가 코드상으로는 맞아도, 부팅 시점에 필요한 하위 모듈이 아직 준비되지 않았으면 probe가 실패하거나 defer가 누적될 수 있다. 즉 이 단계는 단순 로딩이 아니라 부팅 타이밍 경쟁 조건을 줄이는 작업이다.
이 부분은 수동 디버깅 과정에서는 놓치기 쉬운 지점인데, 스크립트는 이 문제까지 고려하고 있다.
스크립트는 Ubuntu 계열에서 설치된 libcamera 버전을 확인한 뒤, 최소 요구 버전보다 낮으면 직접 소스 빌드를 수행한다.
특히 여기서 흥미로운 점은 단순히 최신 버전을 빌드하는 데서 끝나지 않고, OV02C10 sensor helper 패치까지 적용한다는 점이다.
즉 단순히 “0.X 이상이면 된다”가 아니라, OV02C10 센서에 대해 auto exposure / gain이 제대로 동작하지 않아 이미지가 지나치게 어두워지는 문제까지 염두에 두고 있다.
또한 빌드 옵션도 다음처럼 명확하다.
simple pipeline 사용simple IPA 사용gstreamer 활성화v4l2 emulation 활성화즉 이 스크립트는 IPU6 전용 proprietary pipeline이 아니라, open-source libcamera SimplePipeline을 명시적으로 채택하고 있다.
스크립트에서 가장 중요한 부분 중 하나는 Ubuntu에서 PipeWire의 libcamera SPA plugin을 직접 다시 빌드하는 로직이다.
이 부분이 중요한 이유는 앞 단계에서 이미 드러난 문제와 맞닿아 있기 때문이다.
즉 직접 빌드한 libcamera는 /usr/local 아래의 최신 버전을 사용하지만, Ubuntu 기본 PipeWire plugin은 배포판 libcamera를 기준으로 빌드되어 있기 때문에 ABI가 어긋날 수 있다.
스크립트는 이 문제를 알고 있으며, 다음과 같은 판단을 수행한다.
libspa-libcamera.so를 다시 빌드즉 우리가 이미 한 차례 겪었던 “libcamera 0.4는 잘 돌아가는데 PipeWire는 여전히 native node를 못 띄우는 문제”를, 이 스크립트는 아예 해결 대상의 핵심으로 보고 있다.
스크립트는 raw Intel IPU6 ISYS Capture* 노드를 udev 규칙과 WirePlumber 설정으로 숨긴다.
이 조치의 목적은 명확하다. 사용자는 실제로 사용할 수 없는 수십 개의 raw node 대신, 최종적으로 의미 있는 카메라 장치만 보게 해야 한다.
또한 PipeWire-native 앱이 아닌 프로그램을 위해 camera-relay와 v4l2loopback을 설치한다.
이 relay는 상시 무겁게 동작하는 것이 아니라, 앱이 장치를 열었을 때만 GStreamer 파이프라인을 시작하는 on-demand 방식이다.
즉 여기서 relay는 임시 우회책이 아니라, non-PipeWire 앱 호환성을 위한 별도 사용자 공간 장치 제공 계층으로 구현된다.
여기까지의 수동 작업만으로도 이미 많은 문제를 해결했다.
그러나 남아 있던 마지막 문제는 단일 계층의 오류가 아니었다.
즉 마지막 단계는 “어느 패키지 하나를 더 설치하면 끝나는 문제”가 아니라, 서로 다른 계층의 조합을 올바른 순서로 맞추는 문제였다.
이 점에서 이 스크립트는 설득력이 있었다.
단순한 팁 모음이 아니라, 지금까지 직접 확인했던 병목들을 실제 실행 순서로 연결해 놓았기 때문이다.
스크립트의 내용이 제법 많은 과정을 담고 있었기에 아예 우분투를 재설치하고 다음 스크립트를 실행해보기로 했다.
다음 명령어를 실행한다.
curl -sL https://github.com/Andycodeman/samsung-galaxy-book4-linux-fixes/archive/refs/heads/main.tar.gz | tar xz && cd samsung-galaxy-book4-linux-fixes-main/webcam-fix-libcamera && ./install.sh && sudo reboot


설치 스크립트는 커널 모듈, libcamera, PipeWire SPA 플러그인까지 한 번에 구성하도록 작성되어 있었지만, Ubuntu 기본 개발 환경이 충분하지 않은 경우 PipeWire 플러그인 재빌드 단계에서 멈출 수 있었다. 실제로 이번 실행에서는 dbus-1 의존성을 찾지 못해 Meson 설정 단계가 실패했다. 로그를 보면 libsystemd도 함께 누락되어 있었기 때문에, Ubuntu에서 libdbus-1-dev, libsystemd-dev 패키지를 추가로 설치한 뒤 스크립트를 다시 실행하는 방식으로 진행했다.
sudo apt update
sudo apt install -y libdbus-1-dev libsystemd-dev
cd ~/samsung-galaxy-book4-linux-fixes-main/webcam-fix-libcamera
./install.sh

설치가 완료되었다는 메시지를 확인했다면 재부팅을 수행한다.
sudo reboot
dmesg | grep -iE 'ov02c10|OVTI02C1|ipu6|ivsc|external clock|probe|error|failed'

초기에 발견했던 문제가 다시 발생하고 있다. webcam-fix-libcamera repository 내부에 dkms 패치가 있는지 확인해본다.


레포 구조를 살펴보니 센서 패치는 별도 스크립트였음이 드러났다.
cd ~/samsung-galaxy-book4-linux-fixes-main/ov02c10-26mhz-fix
sudo ./install.sh

다음으로 No IPA 문제를 점검해본다.
cam -l
ls /usr/local/lib/x86_64-linux-gnu/libcamera
ls /usr/local/lib/x86_64-linux-gnu/libcamera/ipu

ipa 파일은 있지만 IPAManger가 엉뚱한 곳에서 ipa 파일을 찾고 있다.
ls -l /usr/local/lib/x86_64-linux-gnu/libcamera/ipa

ldd $(which cam) | grep libcamera

export LIBCAMERA_IPA_PATH=/usr/local/lib/x86_64-linux-gnu/libcamera/ipa
LIBCAMERA_LOG_LEVELS=*:DEBUG \
LIBCAMERA_IPA_PATH=/usr/local/lib/x86_64-linux-gnu/libcamera/ipa \
cam -l
madhamster@treadmill:~$ LIBCAMERA_LOG_LEVELS=*:DEBUG \
LIBCAMERA_IPA_PATH=/usr/local/lib/x86_64-linux-gnu/libcamera/ipa \
cam -l
[0:26:04.215679383] [9836] WARN IPAManager ipa_manager.cpp:134 No IPA found in '/usr/local/lib/x86_64-linux-gnu/libcamera'
[0:26:04.215880734] [9836] DEBUG IPAModule ipa_module.cpp:333 ipa_soft_simple.so: IPA module /usr/local/lib/x86_64-linux-gnu/libcamera/ipa/ipa_soft_simple.so is signed
[0:26:04.215923401] [9836] DEBUG IPAManager ipa_manager.cpp:239 Loaded IPA module '/usr/local/lib/x86_64-linux-gnu/libcamera/ipa/ipa_soft_simple.so'
[0:26:04.215992387] [9836] INFO Camera camera_manager.cpp:340 libcamera v0.7.0
[0:26:04.216352551] [9837] DEBUG Camera camera_manager.cpp:74 Starting camera manager
[0:26:04.226103265] [9837] DEBUG DeviceEnumerator device_enumerator.cpp:267 New media device "intel-ipu6" created from /dev/media0
[0:26:04.226464200] [9837] DEBUG DeviceEnumerator device_enumerator_udev.cpp:111 Defer media device /dev/media0 due to 49 missing dependencies
[0:26:04.228741840] [9837] DEBUG DeviceEnumerator device_enumerator_udev.cpp:346 All dependencies for media device /dev/media0 found
[0:26:04.228761966] [9837] DEBUG DeviceEnumerator device_enumerator.cpp:295 Added device /dev/media0: intel-ipu6
[0:26:04.229235758] [9837] DEBUG Camera camera_manager.cpp:143 Found registered pipeline handler 'simple'
[0:26:04.229385856] [9837] DEBUG DeviceEnumerator device_enumerator.cpp:355 Successful match for media device "intel-ipu6"
[0:26:04.229474145] [9837] DEBUG SimplePipeline simple.cpp:1903 Sensor found for /dev/media0
[0:26:04.230039384] [9837] DEBUG SimplePipeline simple.cpp:501 Found capture device Intel IPU6 ISYS Capture 32
[0:26:04.230082122] [9837] DEBUG CameraSensor camera_sensor_raw.cpp:213 ov02c10 3-0036: unsupported number of sinks (0) or sources (1)
[0:26:04.230180436] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Exposure (0x00980911)
[0:26:04.230335725] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Horizontal Flip (0x00980914)
[0:26:04.230361154] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Vertical Flip (0x00980915)
[0:26:04.230371393] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Camera Orientation (0x009a0922)
[0:26:04.230409094] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Camera Sensor Rotation (0x009a0923)
[0:26:04.230416737] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Vertical Blanking (0x009e0901)
[0:26:04.230423308] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Horizontal Blanking (0x009e0902)
[0:26:04.230430306] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Analogue Gain (0x009e0903)
[0:26:04.230436869] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Link Frequency (0x009f0901)
[0:26:04.230445370] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Pixel Rate (0x009f0902)
[0:26:04.230452440] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Test Pattern (0x009f0903)
[0:26:04.230462016] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Digital Gain (0x009f0905)
[0:26:04.230731454] [9837] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov02c10 3-0036': Unable to get rectangle 2 on pad 0/0: Inappropriate ioctl for device
[0:26:04.230743271] [9837] WARN CameraSensor camera_sensor_legacy.cpp:402 'ov02c10 3-0036': The PixelArraySize property has been defaulted to 1928x1092
[0:26:04.230748324] [9837] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov02c10 3-0036': Unable to get rectangle 1 on pad 0/0: Inappropriate ioctl for device
[0:26:04.230753084] [9837] WARN CameraSensor camera_sensor_legacy.cpp:413 'ov02c10 3-0036': The PixelArrayActiveAreas property has been defaulted to (0, 0)/1928x1092
[0:26:04.230761599] [9837] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov02c10 3-0036': Unable to get rectangle 0 on pad 0/0: Inappropriate ioctl for device
[0:26:04.230764757] [9837] WARN CameraSensor camera_sensor_legacy.cpp:421 'ov02c10 3-0036': Failed to retrieve the sensor crop rectangle
[0:26:04.230767084] [9837] WARN CameraSensor camera_sensor_legacy.cpp:427 'ov02c10 3-0036': The sensor kernel driver needs to be fixed
[0:26:04.230770286] [9837] WARN CameraSensor camera_sensor_legacy.cpp:429 'ov02c10 3-0036': See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information
[0:26:04.231657303] [9837] WARN CameraSensorProperties camera_sensor_properties.cpp:538 No static properties available for 'ov02c10'
[0:26:04.231667915] [9837] WARN CameraSensorProperties camera_sensor_properties.cpp:540 Please consider updating the camera sensor properties database
[0:26:04.231714434] [9837] DEBUG CameraSensor camera_sensor.cpp:476 Entity 'ov02c10 3-0036' matched by CameraSensorLegacy
[0:26:04.231750259] [9837] WARN CameraSensor camera_sensor_legacy.cpp:502 'ov02c10 3-0036': No sensor delays found in static properties. Assuming unverified defaults.
[0:26:04.231833773] [9837] DEBUG DelayedControls delayed_controls.cpp:99 Set a delay of 2 and priority write flag 0 for Exposure
[0:26:04.231846440] [9837] DEBUG DelayedControls delayed_controls.cpp:99 Set a delay of 1 and priority write flag 0 for Analogue Gain
[0:26:04.231925401] [9837] DEBUG SimplePipeline simple.cpp:575 Found pipeline: [ov02c10 3-0036|0] -> [0|Intel IPU6 CSI2 4|1] -> [0|Intel IPU6 ISYS Capture 32]
[0:26:04.232071970] [9837] DEBUG V4L2 v4l2_videodevice.cpp:633 /dev/video33[12:cap]: Opened device PCI:0000:00:05.0: isys: ipu6
[0:26:04.232254278] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Exposure (0x00980911)
[0:26:04.232277183] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Horizontal Flip (0x00980914)
[0:26:04.232285906] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Vertical Flip (0x00980915)
[0:26:04.232293005] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Camera Orientation (0x009a0922)
[0:26:04.232304402] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Camera Sensor Rotation (0x009a0923)
[0:26:04.232311759] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Vertical Blanking (0x009e0901)
[0:26:04.232318150] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Horizontal Blanking (0x009e0902)
[0:26:04.232324684] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Analogue Gain (0x009e0903)
[0:26:04.232331335] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Link Frequency (0x009f0901)
[0:26:04.232339091] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Pixel Rate (0x009f0902)
[0:26:04.232345897] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Test Pattern (0x009f0903)
[0:26:04.232355830] [9837] DEBUG V4L2 v4l2_device.cpp:742 'ov02c10 3-0036': Control: Digital Gain (0x009f0905)
[0:26:04.232420944] [9837] DEBUG DmaBufAllocator dma_buf_allocator.cpp:106 Failed to open /dev/dma_heap/linux,cma: No such file or directory
[0:26:04.232427699] [9837] DEBUG DmaBufAllocator dma_buf_allocator.cpp:106 Failed to open /dev/dma_heap/reserved: No such file or directory
[0:26:04.232431762] [9837] DEBUG DmaBufAllocator dma_buf_allocator.cpp:106 Failed to open /dev/dma_heap/system: Permission denied
[0:26:04.232435775] [9837] DEBUG DmaBufAllocator dma_buf_allocator.cpp:106 Failed to open /dev/udmabuf: Permission denied
[0:26:04.232438029] [9837] ERROR DmaBufAllocator dma_buf_allocator.cpp:119 Could not open any dma-buf provider
[0:26:04.232453248] [9837] ERROR SoftwareIsp software_isp.cpp:88 Failed to create DmaBufAllocator object
[0:26:04.232471443] [9837] WARN SimplePipeline simple.cpp:620 Failed to create software ISP, disabling software debayering
[0:26:04.232548347] [9837] DEBUG MediaDevice media_device.cpp:854 /dev/media0[intel-ipu6]: 'Intel IPU6 CSI2 4'[1] -> 'Intel IPU6 ISYS Capture 32'[0]: 0
[0:26:04.232555583] [9837] DEBUG MediaDevice media_device.cpp:854 /dev/media0[intel-ipu6]: 'Intel IPU6 CSI2 4'[1] -> 'Intel IPU6 ISYS Capture 32'[0]: 1
[0:26:04.232629676] [9837] DEBUG SimplePipeline simple.cpp:870 Link 'ov02c10 3-0036'[0] -> 'Intel IPU6 CSI2 4'[0]: configured with format 1928x1092-SGRBG10_1X10/Unset
[0:26:04.232645548] [9837] DEBUG SimplePipeline simple.cpp:870 Link 'Intel IPU6 CSI2 4'[1] -> 'Intel IPU6 ISYS Capture 32'[0]: configured with format 1928x1092-SGRBG10_1X10/Unset
[0:26:04.232695258] [9837] DEBUG SimplePipeline simple.cpp:716 Adding configuration for 1928x1092 in pixel formats [ BA10, pgAA ]
[0:26:04.232806196] [9837] DEBUG SimplePipeline simple.cpp:674 Using frameStart signal from 'Intel IPU6 CSI2 4'
[0:26:04.232937075] [9837] INFO Camera camera_manager.cpp:223 Adding camera '\_SB_.PC00.LNK0' for pipeline handler simple
[0:26:04.232962765] [9837] DEBUG SimplePipeline simple.cpp:2027 Matched on device: /dev/media0
[0:26:04.232967014] [9837] DEBUG Camera camera_manager.cpp:164 Pipeline handler "simple" matched
Available cameras:
1: Internal front camera (\_SB_.PC00.LNK0)
상기 로그에서 다음 부분에 주목해본다.
[0:32:39.455346359] [9960] DEBUG DmaBufAllocator dma_buf_allocator.cpp:106 Failed to open /dev/dma_heap/linux,cma: No such file or directory
[0:32:39.455353293] [9960] DEBUG DmaBufAllocator dma_buf_allocator.cpp:106 Failed to open /dev/dma_heap/reserved: No such file or directory
[0:32:39.455357323] [9960] DEBUG DmaBufAllocator dma_buf_allocator.cpp:106 Failed to open /dev/dma_heap/system: Permission denied
[0:32:39.455361091] [9960] DEBUG DmaBufAllocator dma_buf_allocator.cpp:106 Failed to open /dev/udmabuf: Permission denied
[0:32:39.455364017] [9960] ERROR DmaBufAllocator dma_buf_allocator.cpp:119 Could not open any dma-buf provider
[0:32:39.455379012] [9960] ERROR SoftwareIsp software_isp.cpp:88 Failed to create DmaBufAllocator object
[0:32:39.455396594] [9960] WARN SimplePipeline simple.cpp:620 Failed to create software ISP, disabling software debayering
권한을 확인해본다
ls -l /dev/dma_heap/system /dev/udmabuf
ls -ld /dev/dma_heap /dev/dma_heap/system

sudo usermod -aG kvm $USER
sudo chmod 666 /dev/dma_heap/system
sudo reboot
cam -l

로그를 보면 DmaBufAllocator 문제는 해결된 것으로 보인다. 다만 문제는
Unable to get rectangle 2 on pad 0/0
Unable to get rectangle 1 on pad 0/0
Unable to get rectangle 0 on pad 0/0
와 같은 오류들 때문에
'ov02c10 3-0036': The sensor kernel driver needs to be fixed
위와 같은 로그가 뜨고 있는 점이다.
cam -c1 --capture=10

v4l2-ctl --list-devices


gst-launch-1.0 libcamerasrc ! v4l2sink

명령어를 실행하자 libcamerasrc를 찾을 수 없다고 한다.

그러나 libcamerasrc는 엄연히 존재하고 있었다.
sudo nano /etc/environment
위 명령어를 실행한 후 아래 내용을 추가한다.
GST_PLUGIN_PATH="/usr/local/lib/x86_64-linux-gnu/gstreamer-1.0"
LD_LIBRARY_PATH="/usr/local/lib/x86_64-linux-gnu:/usr/local/lib"

madhamster@treadmill:~$ gst-launch-1.0 libcamerasrc ! videoconvert ! v4l2sink device=/dev/video0
이제 위 명령어를 실행하면 아래와 같은 로그가 나온다.
파이프라인을 PAUSED로 만드는 중 ...
[0:17:37.076141490] [4916] WARN IPAManager ipa_manager.cpp:134 No IPA found in '/usr/local/lib/x86_64-linux-gnu/libcamera'
[0:17:37.076288395] [4916] INFO Camera camera_manager.cpp:340 libcamera v0.7.0
[0:17:37.088204604] [4918] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov02c10 3-0036': Unable to get rectangle 2 on pad 0/0: 장치에 대해 부적절한 ioctl
[0:17:37.088242071] [4918] WARN CameraSensor camera_sensor_legacy.cpp:402 'ov02c10 3-0036': The PixelArraySize property has been defaulted to 1928x1092
[0:17:37.088249780] [4918] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov02c10 3-0036': Unable to get rectangle 1 on pad 0/0: 장치에 대해 부적절한 ioctl
[0:17:37.088255465] [4918] WARN CameraSensor camera_sensor_legacy.cpp:413 'ov02c10 3-0036': The PixelArrayActiveAreas property has been defaulted to (0, 0)/1928x1092
[0:17:37.088261377] [4918] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov02c10 3-0036': Unable to get rectangle 0 on pad 0/0: 장치에 대해 부적절한 ioctl
[0:17:37.088266160] [4918] WARN CameraSensor camera_sensor_legacy.cpp:421 'ov02c10 3-0036': Failed to retrieve the sensor crop rectangle
[0:17:37.088270463] [4918] WARN CameraSensor camera_sensor_legacy.cpp:427 'ov02c10 3-0036': The sensor kernel driver needs to be fixed
[0:17:37.088274293] [4918] WARN CameraSensor camera_sensor_legacy.cpp:429 'ov02c10 3-0036': See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information
[0:17:37.089101819] [4918] WARN CameraSensorProperties camera_sensor_properties.cpp:538 No static properties available for 'ov02c10'
[0:17:37.089113329] [4918] WARN CameraSensorProperties camera_sensor_properties.cpp:540 Please consider updating the camera sensor properties database
[0:17:37.089142515] [4918] WARN CameraSensor camera_sensor_legacy.cpp:502 'ov02c10 3-0036': No sensor delays found in static properties. Assuming unverified defaults.
[0:17:37.092556229] [4918] INFO IPAProxy ipa_proxy.cpp:180 Using tuning file /usr/local/share/libcamera/ipa/simple/ov02c10.yaml
[0:17:37.092583275] [4918] ERROR V4L2 v4l2_subdevice.cpp:1192 'ov02c10 3-0036': Unable to get rectangle 0 on pad 0/0: 장치에 대해 부적절한 ioctl
[0:17:37.092593324] [4918] WARN CameraSensor camera_sensor_legacy.cpp:881 'ov02c10 3-0036': The analogue crop rectangle has been defaulted to the active area size
[0:17:37.092699054] [4918] WARN IPASoft soft_simple.cpp:104 IPASoft: Failed to create camera sensor helper for ov02c10
[0:17:37.093571546] [4918] INFO Camera camera_manager.cpp:223 Adding camera '\_SB_.PC00.LNK0' for pipeline handler simple
파이프라인이 살아있으므로 PREROLL이 필요하지 않음 ...
파이프라인이 PREROLL됨...
파이프라인을 재생중으로 변경중 ...
New clock: GstSystemClock
[0:17:37.096714995] [4919] INFO Camera camera.cpp:1215 configuring streams: (0) 1920x1080-ABGR8888/sRGB
[0:17:37.097182866] [4918] INFO IPASoft soft_simple.cpp:258 IPASoft: Exposure 4-2320, gain 16-248 (1)
ERROR: from element /GstPipeline:pipeline0/GstV4l2Sink:v4l2sink0: Device '/dev/video0' is busy
Additional debug info:
../sys/v4l2/gstv4l2object.c(4417): gst_v4l2_object_set_format_full (): /GstPipeline:pipeline0/GstV4l2Sink:v4l2sink0:
Call to S_FMT failed for YUYV @ 1920x1080: 장치나 자원이 동작 중
ERROR: from element /GstPipeline:pipeline0/GstV4l2Sink:v4l2sink0: Device '/dev/video0' is busy
Additional debug info:
../sys/v4l2/gstv4l2object.c(4417): gst_v4l2_object_set_format_full (): /GstPipeline:pipeline0/GstV4l2Sink:v4l2sink0:
Call to S_FMT failed for YUYV @ 1920x1080: 장치나 자원이 동작 중
Execution ended after 0:00:00.004549685
파이프라인을 NULL로 만드는 중 ...
[0:17:37.125190562] [4922] INFO eGL egl.cpp:305 EGL: EGL_VERSION: 1.5
[0:17:37.125226134] [4922] INFO eGL egl.cpp:306 EGL: EGL_VENDOR: Mesa Project
[0:17:37.125228636] [4922] INFO eGL egl.cpp:307 EGL: EGL_CLIENT_APIS: OpenGL OpenGL_ES
[0:17:37.125230761] [4922] INFO eGL egl.cpp:308 EGL: EGL_EXTENSIONS: EGL_ANDROID_blob_cache EGL_ANDROID_native_fence_sync EGL_EXT_config_select_group EGL_EXT_create_context_robustness EGL_EXT_image_dma_buf_import EGL_EXT_image_dma_buf_import_modifiers EGL_EXT_protected_content EGL_EXT_query_reset_notification_strategy EGL_EXT_surface_compression EGL_IMG_context_priority EGL_KHR_cl_event2 EGL_KHR_config_attribs EGL_KHR_context_flush_control EGL_KHR_create_context EGL_KHR_create_context_no_error EGL_KHR_fence_sync EGL_KHR_get_all_proc_addresses EGL_KHR_gl_colorspace EGL_KHR_gl_renderbuffer_image EGL_KHR_gl_texture_2D_image EGL_KHR_gl_texture_3D_image EGL_KHR_gl_texture_cubemap_image EGL_KHR_image_base EGL_KHR_no_config_context EGL_KHR_partial_update EGL_KHR_reusable_sync EGL_KHR_surfaceless_context EGL_EXT_pixel_format_float EGL_KHR_wait_sync EGL_MESA_configless_context EGL_MESA_gl_interop EGL_MESA_image_dma_buf_export EGL_MESA_query_driver EGL_MESA_x11_native_visual_id
[0:17:37.127292973] [4922] INFO eGL egl.cpp:349 EGL: GL_VERSION: OpenGL ES 3.2 Mesa 25.2.8-0ubuntu0.24.04.1
파이프라인 비우는 중 ...
위 로그에서 주목할만한 부분은 아래와 같다.
ERROR: from element /GstPipeline:pipeline0/GstV4l2Sink:v4l2sink0: Device '/dev/video0' is busy
누가 /dev/video0을 점유하고 있는지 확인한다
fuser -v /dev/video0
# 또는
lsof /dev/video0

pkill -f camera-relay
fuser -v /dev/video0

점유하고 있는 프로그램이 없음을 확인하고 다시 명령어를 실행한다.
gst-launch-1.0 -v libcamerasrc ! queue ! videoconvert ! queue ! autovideosink


sudo apt install linux-modules-ipu6-generic-hwe-24.04
재부팅 후 아래 명령어 실행
lsmod | grep ipu6
ls /dev | grep ipu

sudo dmesg | grep -i ipu6

dpkg -l | grep -Ei 'ipu6|camhal|libcamhal|camera-hal|camera-bins'

sudo add-apt-repository ppa:oem-solutions-group/intel-ipu6
sudo apt update
sudo apt install ipu6-camera-bins ipu6-camera-hal libcamhal-ipu6

apt search libcamhal
apt search icamera
apt search v4l2-relayd
apt search ipu6 | sed -n '1,120p'



madhamster@treadmill:~$ apt search ipu6 | sed -n '1,120p'
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
정렬 중...
전체 텍스트 검색...
gstreamer1.0-icamera/noble 0~git202509260937.4fb31db~ubuntu24.04.7 amd64
MIPI camera through Intel IPU6 plugin for GStreamer
intel-ipu6-dkms/noble-updates 0~git202406240945.aecec2aa-0ubuntu2~24.04.3 amd64
Intel Integrated Image Processing Unit 6 (IPU6) driver
intel-usbio-dkms/noble-updates 0~git202312141918.78ffb706-0ubuntu2.2 amd64
USBIO Bridge drivers for Intel MeteoLake platform with Lattice AIC
libbroxton-ia-pal-dev/noble 0~git202310270317.0dad591-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera (development files)
libbroxton-ia-pal-ipu6-0/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera
libbroxton-ia-pal-ipu6-dev/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera (development files)
libbroxton-ia-pal-ipu60/noble 0~git202410220058.e00b29f-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera
libbroxton-ia-pal-ipu6ep-dev/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera (development files)
libbroxton-ia-pal-ipu6ep0/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera
libbroxton-ia-pal-ipu6epmtl-dev/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera (development files)
libbroxton-ia-pal-ipu6epmtl0/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera
libbroxton-ia-pal0/noble 0~git202310270317.0dad591-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera
libcamhal-common/noble 0~git202601200757.9899efa~ubuntu24.04.1 all
HAL library for MIPI camera through Intel IPU6 - common files
libcamhal-dev/noble 0~git202601200757.9899efa~ubuntu24.04.1 amd64
HAL library for MIPI camera through Intel IPU6 - development kit
libcamhal-ipu6/noble 0~git202601200757.9899efa~ubuntu24.04.1 amd64
Dynamic loading plugin for IPU6 camera (ipu6)
libcamhal-ipu6-common/noble 0~git202601200757.9899efa~ubuntu24.04.1 all
Common files for for MIPI camera through Intel IPU6 (ipu6)
libcamhal-ipu6-dev/noble 0~git202601200757.9899efa~ubuntu24.04.1 amd64
Dynamic loading plugin for IPU6 camera (ipu6) - development kit
libcamhal-ipu6ep/noble 0~git202601200757.9899efa~ubuntu24.04.1 amd64
Dynamic loading plugin for IPU6 camera (ipu6ep)
libcamhal-ipu6ep-common/noble 0~git202601200757.9899efa~ubuntu24.04.1 all
Common files for for MIPI camera through Intel IPU6 (ipu6ep)
libcamhal-ipu6ep-dev/noble 0~git202601200757.9899efa~ubuntu24.04.1 amd64
Dynamic loading plugin for IPU6 camera (ipu6ep) - development kit
libcamhal-ipu6ep0/noble 0~git202410220058.74ffeab~ubuntu24.04.2 amd64
Transitional package for libcamhal0
libcamhal-ipu6epmtl/noble 0~git202601200757.9899efa~ubuntu24.04.1 amd64
Dynamic loading plugin for IPU6 camera (ipu6epmtl)
libcamhal-ipu6epmtl-common/noble 0~git202601200757.9899efa~ubuntu24.04.1 all
Common files for for MIPI camera through Intel IPU6 (ipu6epmtl)
libcamhal-ipu6epmtl-dev/noble 0~git202601200757.9899efa~ubuntu24.04.1 amd64
Dynamic loading plugin for IPU6 camera (ipu6epmtl) - development kit
libcamhal0/noble 0~git202601200757.9899efa~ubuntu24.04.1 amd64
HAL library for MIPI camera through Intel IPU6
libgcss-dev/noble 0~git202310270317.0dad591-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera (development files)
libgcss-ipu6-0/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera
libgcss-ipu6-dev/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera (development files)
libgcss-ipu60/noble 0~git202410220058.e00b29f-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera
libgcss-ipu6ep-dev/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera (development files)
libgcss-ipu6ep0/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera
libgcss-ipu6epmtl-dev/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera (development files)
libgcss-ipu6epmtl0/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera
libgcss0/noble 0~git202310270317.0dad591-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera
libgsticamerainterface-1.0-1/noble 0~git202509260937.4fb31db~ubuntu24.04.7 amd64
GStreamer MIPI camera through Intel IPU6 interface (shared library)
libgsticamerainterface-1.0-dev/noble 0~git202509260937.4fb31db~ubuntu24.04.7 amd64
GStreamer MIPI camera through Intel IPU6 interface (development files)
libia-aiq-dev/noble 0~git202310270317.0dad591-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera (development files)
libia-aiq-file-debug-dev/noble 0~git202310270317.0dad591-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera (development files)
libia-aiq-file-debug-ipu6-0/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
API library for Intel IPU6 camera
libia-aiq-file-debug-ipu6-dev/noble 0~git202506270118.30e8766-1~ubuntu24.04.1 amd64
위와 같이 정보를 확인하였으면 적당한 것을 설치한다.
sudo apt install libcamhal0 libcamhal-common libcamhal-ipu6 gstreamer1.0-icamera
설치후 재부팅하는 것을 잊지 않는다.
gst-inspect-1.0 icamerasrc

어딘가 이상한 로그. 아래 명령어를 실행한다.
sudo apt install libcamhal-ipu6epmtl libcamhal-ipu6epmtl-common

실행 후 다시 테스트해본다.
madhamster@treadmill:~$ gst-launch-1.0 icamerasrc ! autovideosink
파이프라인을 PAUSED로 만드는 중 ...
[03-09 01:57:14.313] CamHAL[INF] aiqb file name OV02C10_1BG203N3_ADL.aiqb
[03-09 01:57:14.313] CamHAL[INF] aiqb file name OV02C10_1BG203N3_ADL.aiqb
[03-09 01:57:14.314] CamHAL[INF] aiqb file name OV02C10_1SG204N3_ADL.aiqb
[03-09 01:57:14.314] CamHAL[INF] aiqb file name OV02C10_1SG204N3_ADL.aiqb
[03-09 01:57:14.314] CamHAL[INF] aiqb file name OV02C10_CIFME14_ADL.aiqb
[03-09 01:57:14.314] CamHAL[INF] aiqb file name OV02C10_CIFME14_ADL.aiqb
[03-09 01:57:14.314] CamHAL[INF] aiqb file name AR0234_TGL_10bits.aiqb
[03-09 01:57:14.314] CamHAL[INF] aiqb file name AR0234_TGL_10bits.aiqb
[03-09 01:57:14.314] CamHAL[INF] aiqb file name AR0234_TGL_10bits.aiqb
[03-09 01:57:14.314] CamHAL[INF] aiqb file name AR0234_TGL_10bits.aiqb
[03-09 01:57:14.315] CamHAL[INF] aiqb file name AR0234_TGL_10bits.aiqb
[03-09 01:57:14.315] CamHAL[INF] aiqb file name AR0234_TGL_10bits.aiqb
[03-09 01:57:14.315] CamHAL[INF] aiqb file name AR0234_TGL_10bits.aiqb
[03-09 01:57:14.315] CamHAL[INF] aiqb file name AR0234_TGL_10bits.aiqb
파이프라인이 살아있으므로 PREROLL이 필요하지 않음 ...
파이프라인이 PREROLL됨...
파이프라인을 재생중으로 변경중 ...
New clock: GstSystemClock
[03-09 01:57:14.348] CamHAL[ERR] Failed to open PSYS, error: 허가 거부
[03-09 01:57:14.348] CamHAL[ERR] Failed to initialize Context
[03-09 01:57:14.348] CamHAL[ERR] create PG 187 error
[03-09 01:57:14.348] CamHAL[ERR] Failed to create PGs for executor: ipu6_lb_video_bayer
[03-09 01:57:14.348] CamHAL[ERR] Failed to create pipe for executor:ipu6_lb_video_bayer
[03-09 01:57:14.348] CamHAL[ERR] @configure, create psys executors failed
[03-09 01:57:14.348] CamHAL[ERR] @configure configure psys dag failed:-2147483648
[03-09 01:57:14.348] CamHAL[ERR] Configure processor failed with:-2147483648
[03-09 01:57:14.348] CamHAL[ERR] @configure configure post processor failed with:-2147483648
[03-09 01:57:14.348] CamHAL[ERR] failed to config streams.
ERROR: from element /GstPipeline:pipeline0/Gstcamerasrc:camerasrc0: src pad: Internal data flow error.
Additional debug info:
gstcambasesrc.cpp(3156): gst_cam_base_src_loop (): /GstPipeline:pipeline0/Gstcamerasrc:camerasrc0:
streaming task paused, reason not-negotiated (-4)
Execution ended after 0:00:00.029366162
파이프라인을 NULL로 만드는 중 ...
[03-09 01:57:14.348] CamHAL[WAR] Failed to open file /run/camera/ov02c10-uf_VIDEO.aiqd, error 그런 파일이나 디렉터리가 없습니다
파이프라인 비우는 중 ...
psys 실행을 하지 못하는 권한 문제가 있으므로 아래 명령어를 실행한다
sudo chgrp video /dev/ipu-psys0
sudo chmod 660 /dev/ipu-psys0
sudo usermod -aG video $USER
sudo nano /etc/udev/rules.d/99-ipu6.rules
위 명령어를 실행하며 내용으로는 아래와 같이 쓴다.
KERNEL=="ipu-psys*", MODE="0660", GROUP="video"
KERNEL=="ipu*", MODE="0660", GROUP="video"
적용은 아래와 같이 한다.
sudo udevadm control --reload-rules
sudo udevadm trigger
재부팅 후 재실행
gst-launch-1.0 icamerasrc ! autovideosink

그럼 뒤집어지긴 했지만 일단은 영상이 나온다.
gst-launch-1.0 icamerasrc ! videoflip method=rotate-180 ! videoconvert ! autovideosink
명령어를 위와 같이 실행하면 180도 회전된 화면으로 나온다

디스코드에서는 거꾸로인 화면으로 나온다.

화면 조정 하는 부분은 다른 분께서 해주실 것 같아서 멈추기로 한다.