### Enable and Start Camera Streamer Service Source: https://github.com/ayufan/camera-streamer/blob/main/RELEASE.md Lists available example services and then enables and starts a specific camera streamer service. Ensure the service name matches your configuration. ```bash ls -al /usr/share/camera-streamer/examples/ systemctl enable /usr/share/camera-streamer/examples/camera-streamer-raspi-v3-12MP.service systemctl start camera-streamer-raspi-v3-12MP ``` -------------------------------- ### Enable and Start Systemd Service Source: https://github.com/ayufan/camera-streamer/blob/main/docs/install-manual.md Enable a preconfigured systemd service for camera streamer and start it. This example uses a service for the Arducam 16MP camera. ```bash systemctl enable $PWD/service/camera-streamer-arducam-16MP.service systemctl start camera-streamer-arducam-16MP ``` -------------------------------- ### Download and Install Camera Streamer Package Source: https://github.com/ayufan/camera-streamer/blob/main/RELEASE.md This script determines the correct package name based on the system and downloads it using wget. It then installs the package using apt. Ensure you have the correct variant and system information. ```bash PACKAGE=camera-streamer-$(test -e /etc/default/raspberrypi-kernel && echo raspi || echo generic)_#{GIT_VERSION}.$(. /etc/os-release; echo $VERSION_CODENAME)_$(dpkg --print-architecture).deb wget "https://github.com/ayufan/camera-streamer/releases/download/v#{GIT_VERSION}/$PACKAGE" sudo apt install "$PWD/$PACKAGE" ``` -------------------------------- ### Compile Camera Streamer from Source Source: https://github.com/ayufan/camera-streamer/blob/main/docs/install-manual.md Clone the repository, install necessary dependencies, and compile the camera streamer project using make. ```bash git clone https://github.com/ayufan-research/camera-streamer.git --recursive apt-get -y install libavformat-dev libavutil-dev libavcodec-dev libcamera-dev liblivemedia-dev v4l-utils pkg-config xxd build-essential cmake libssl-dev cd camera-streamer/ make sudo make install ``` -------------------------------- ### Copy, Edit, and Start Custom Camera Streamer Service Source: https://github.com/ayufan/camera-streamer/blob/main/RELEASE.md Copies an existing service file to a custom location for modification, then enables and starts the custom service. This allows for fine-tuning the service configuration. ```bash cp /usr/share/camera-streamer/examples/camera-streamer-raspi-v3-12MP.service /etc/systemd/system/camera-streamer.service edit /etc/systemd/system/camera-streamer.service systemctl enable camera-streamer systemctl start camera-streamer ``` -------------------------------- ### Specify Camera, ISP, Video, or Snapshot Options Source: https://github.com/ayufan/camera-streamer/blob/main/docs/configure.md Examples of how to specify options for different components like the camera, ISP, video codec (H264), or snapshot output. These options control specific parameters for each component. ```bash # specify camera option --camera-options=brightness=1000 # specify ISP option --camera-isp.options=digital_gain=1000 # specify H264 option --camera-video.options=bitrate=10000000 # specify snapshot option --camera-snapshot.options=compression_quality=60 --camera-stream.options=compression_quality=60 ``` -------------------------------- ### Start USB camera streaming with MJPEG format Source: https://github.com/ayufan/camera-streamer/blob/main/docs/v4l2-usb-mode.md Initiates streaming using MJPEG format from a USB camera. This is the recommended format for stable high-performance streaming. ```bash tools/usb_camera.sh -camera-format=MJPEG ... ``` -------------------------------- ### GET /control Source: https://github.com/ayufan/camera-streamer/blob/main/html/index.html Provides access to all configurable camera options. Allows setting specific camera parameters via query parameters. ```APIDOC ## GET /control ### Description See all configurable camera options. ### Method GET ### Endpoint /control ### Query Parameters - **device** (string) - Required - The camera device name. - **key** (string) - Required - The configuration key to set. - **value** (string) - Required - The value to set for the configuration key. ### Example `/option?device=CAMERA&key=AfMode&value=auto` ### Response #### Success Response (200) - **(No specific response body defined, likely indicates success or returns current status)** ### Response Example (Success indicator or status) ``` -------------------------------- ### Start USB camera streaming with H264 format Source: https://github.com/ayufan/camera-streamer/blob/main/docs/v4l2-usb-mode.md Initiates streaming using H264 format from a USB camera. Note that H264 support is currently considered unstable or broken. ```bash tools/usb_camera.sh -camera-format=H264 ... ``` -------------------------------- ### Inspect /dev/video6 Device Information Source: https://github.com/ayufan/camera-streamer/blob/main/debug/btt-pi2.txt Use v4l2-ctl to get detailed information about the /dev/video6 device, including driver details, capabilities, and supported output formats. ```bash v4l2-ctl -d /dev/video6 --info --list-formats-ext --list-fields --list-formats-out --list-fields-out --list-ctrls ``` -------------------------------- ### Start WebRTC Connection Source: https://github.com/ayufan/camera-streamer/blob/main/html/webrtc.html Initiates a WebRTC connection by creating a peer connection, setting up event listeners for tracks and ICE candidates, and exchanging SDP offers and answers. It also handles data channels for keep-alive messages. ```javascript function startWebRTC() { const iceServers = [ { urls: ['stun:stun.l.google.com:19302'] } ]; var pc = null; const urlSearchParams = new URLSearchParams(window.location.search); const params = Object.fromEntries(urlSearchParams.entries()); const body = { type: 'request', res: params.res, iceServers: iceServers, keepAlive: true }; if (typeof timeout_s === 'number') { body.timeout_s = timeout_s; } fetch(window.location.href, { body: JSON.stringify(body), headers: { 'Content-Type': 'application/json' }, method: 'POST' }).then(function(response) { return response.json(); }).then(function(request) { pc = new RTCPeerConnection({ sdpSemantics: 'unified-plan', iceServers: request.iceServers }); pc.addEventListener('datachannel', function(e) { const dc = e.channel; if (dc.label === 'keepalive') { dc.addEventListener('message', function(e) { dc.send('pong'); }); } }); pc.remote_pc_id = request.id; pc.addTransceiver('video', { direction: 'recvonly' }); pc.addEventListener('track', function(evt) { if (document.getElementById('stream')) document.getElementById('stream').srcObject = evt.streams[0]; }); pc.addEventListener("icecandidate", function(e) { if (e.candidate) { return fetch(window.location.href, { body: JSON.stringify({ type: 'remote_candidate', id: pc.remote_pc_id, candidates: [e.candidate] }), headers: { 'Content-Type': 'application/json' }, method: 'POST' }).catch(function(e) { console.log("Failed to send ICE WebRTC: "+e); }); } }); return pc.setRemoteDescription(request); }).then(function() { return pc.createAnswer(); }).then(function(answer) { return pc.setLocalDescription(answer); }).then(function() { var offer = pc.localDescription; return fetch(window.location.href, { body: JSON.stringify({ type: offer.type, id: pc.remote_pc_id, sdp: offer.sdp, }), headers: { 'Content-Type': 'application/json' }, method: 'POST' }) }).then(function(response) { return response.json(); }).catch(function(e) { console.log(e); }); } ``` -------------------------------- ### GET /video.mkv Source: https://github.com/ayufan/camera-streamer/blob/main/html/index.html Retrieves a live video stream in MKV format, primarily for Chrome browsers. Latency is around 2 seconds if FFMPEG is enabled. ```APIDOC ## GET /video.mkv ### Description Get a live video stream in MKV format (Chrome, with latency of around 2s if FFMPEG enabled). ### Method GET ### Endpoint /video.mkv ### Response #### Success Response (200) - **video/x-matroska** - The MKV video stream. ### Response Example (MKV video stream data) ``` -------------------------------- ### GET /?action=snapshot Source: https://github.com/ayufan/camera-streamer/blob/main/html/index.html Alias for the /snapshot endpoint, providing a high-resolution snapshot image. ```APIDOC ## GET / ### Description Alias to the [/snapshot](snapshot) endpoint. ### Method GET ### Endpoint /?action=snapshot ### Response #### Success Response (200) - **image/jpeg** - The snapshot image data. ### Response Example (Binary JPEG data) ``` -------------------------------- ### Start MJPEG Stream Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Stops the current stream and sets the source for an MJPEG stream view. Scrolls the view into visibility. ```javascript document.getElementById('mjpeg-stream').onclick = () => { stopStream(); const view = document.getElementById("stream-view"); view.src = `${streamURL}?_cb=${Date.now()}`; view.scrollIntoView(false); show(streamContainer); } ``` -------------------------------- ### GET /video.m3u8 Source: https://github.com/ayufan/camera-streamer/blob/main/html/index.html Retrieves a live video stream in HLS format, compatible with Safari browsers. Latency is approximately 1 second. ```APIDOC ## GET /video.m3u8 ### Description Get a live video stream in HLS format (Safari, with latency of around 1s). ### Method GET ### Endpoint /video.m3u8 ### Response #### Success Response (200) - **application/vnd.apple.mpegurl** - The HLS video stream manifest. ### Response Example (HLS manifest data) ``` -------------------------------- ### GET /?action=stream Source: https://github.com/ayufan/camera-streamer/blob/main/html/index.html Alias for the /stream endpoint, providing a live MJPEG video stream. ```APIDOC ## GET / ### Description Alias to the [/stream](stream) endpoint. ### Method GET ### Endpoint /?action=stream ### Response #### Success Response (200) - **multipart/x-mixed-replace; boundary=frame** - The MJPEG stream data. ### Response Example (MJPEG stream data) ``` -------------------------------- ### GET /status Source: https://github.com/ayufan/camera-streamer/blob/main/html/index.html Returns the current JSON status of the camera-streamer service. ```APIDOC ## GET /status ### Description See the JSON status of camera-streamer. ### Method GET ### Endpoint /status ### Response #### Success Response (200) - **application/json** - The status information in JSON format. ### Response Example ```json { "status": "ok", "uptime": 12345 } ``` ``` -------------------------------- ### Get Still Image Stream Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Stops the current stream and sets the source for a still image view. Scrolls the view into visibility. ```javascript document.getElementById('get-still').onclick = () => { stopStream(); const view = document.getElementById("stream-view"); view.src = `${snapshotURL}?_cb=${Date.now()}`; view.scrollIntoView(false); show(streamContainer); } ``` -------------------------------- ### GET /stream Source: https://github.com/ayufan/camera-streamer/blob/main/html/index.html Provides a live MJPEG video stream. This endpoint is widely compatible but can consume significant bandwidth. The stream resolution is determined by server-side configuration. ```APIDOC ## GET /stream ### Description Get a live stream in MJPEG format. Works everywhere, but consumes a ton of bandwidth. Uses resolution specified by _-camera-stream.height=_ ### Method GET ### Endpoint /stream ### Response #### Success Response (200) - **multipart/x-mixed-replace; boundary=frame** - The MJPEG stream data. ### Response Example (MJPEG stream data) ``` -------------------------------- ### GET /webrtc Source: https://github.com/ayufan/camera-streamer/blob/main/html/index.html Establishes a live video stream using WebRTC, offering low-latency (around 100ms). The stream resolution is configured server-side. It has a default timeout after which the stream disconnects, which can be customized. ```APIDOC ## GET /webrtc ### Description Get a live video using WebRTC (low-latency streaming with latency of around 100ms). Uses resolution specified by _-camera-video.height=_. Uses a default timeout specified by _--webrtc-timeout_s_ or 3600 seconds (1 hour) after which the stream disconnects. ### Method GET ### Endpoint /webrtc ### Query Parameters - **timeout_s** (integer) - Optional - The timeout in seconds after which the stream disconnects. Defaults to 3600 seconds. ### Response #### Success Response (200) - **video/webm** or similar - The WebRTC video stream. ### Response Example (WebRTC stream data) ``` -------------------------------- ### GET /video Source: https://github.com/ayufan/camera-streamer/blob/main/html/index.html Provides a live H264 video stream, optimized for browser compatibility. It automatically selects the best format between MP4, MKV, and HLS. Resolution is configured server-side. ```APIDOC ## GET /video ### Description Get a live (H264) video stream best suited to current browser in a maximum compatibility mode choosing automatically between one of the below formats. Uses resolution specified by _-camera-video.height=_ ### Method GET ### Endpoint /video ### Response #### Success Response (200) - **video/mp4, video/x-matroska, application/vnd.apple.mpegurl** - The H264 video stream in the most compatible format. ### Response Example (H264 video stream data) ``` -------------------------------- ### GET /video.mp4 Source: https://github.com/ayufan/camera-streamer/blob/main/html/index.html Retrieves a live video stream in MP4 format, suitable for browsers like Firefox. Latency is approximately 1 second if FFMPEG is enabled. ```APIDOC ## GET /video.mp4 ### Description Get a live video stream in MP4 format (Firefox, with latency of around 1s if FFMPEG enabled). ### Method GET ### Endpoint /video.mp4 ### Response #### Success Response (200) - **video/mp4** - The MP4 video stream. ### Response Example (MP4 video stream data) ``` -------------------------------- ### GET /snapshot Source: https://github.com/ayufan/camera-streamer/blob/main/html/index.html Retrieves a high-resolution snapshot image from the server. The resolution can be controlled via a server-side configuration. It supports fetching a snapshot captured exactly now or a cached one within a specified delay. ```APIDOC ## GET /snapshot ### Description Get a high-resolution snapshot image from the server. Uses resolution specified by _-camera-snapshot.height=_ ### Method GET ### Endpoint /snapshot ### Query Parameters - **max_delay** (integer) - Optional - Maximum delay in milliseconds for a cached snapshot. Defaults to 300ms. ### Response #### Success Response (200) - **image/jpeg** - The snapshot image data. ### Request Example ``` GET /snapshot?max_delay=0 HTTP/1.1 Host: your-camera-streamer-host ``` ### Response Example (Binary JPEG data) ``` -------------------------------- ### Display libcamera Help Source: https://github.com/ayufan/camera-streamer/blob/main/docs/raspi-libcamera.md Use this command to display the available help options for the libcamera_camera.sh script. ```bash tools/libcamera_camera.sh -help ``` -------------------------------- ### Initialize Peer Connection Configuration Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Sets up the initial configuration for the RTCPeerConnection, specifying SDP semantics. ```javascript const rtcPeerConfig = { sdpSemantics: 'unified-plan' }; let rtcPeerConnection = new RTCPeerConnection(rtcPeerConfig); ``` -------------------------------- ### Display help for usb_camera.sh Source: https://github.com/ayufan/camera-streamer/blob/main/docs/v4l2-usb-mode.md Use this command to view all available options and arguments for the usb_camera.sh script. ```bash tools/usb_camera.sh -help ``` -------------------------------- ### List All Available Camera Controls Source: https://github.com/ayufan/camera-streamer/blob/main/docs/configure.md Lists all available configuration parameters for the camera. Add `--log-verbose` to a camera command to see these options. ```bash tools/libcamera_camera.sh --camera-list_options ... ``` -------------------------------- ### Recommended Camera Format Configuration Source: https://github.com/ayufan/camera-streamer/blob/main/docs/configure.md Provides recommended camera format configurations for libcamera and USB cameras. For libcamera, YUYV or YUV420 are advised. For USB cameras, MJPEG is recommended. ```bash tools/*_camera.sh --camera-type=libcamera --camera-format=YUYV # better image quality tools/*_camera.sh --camera-type=libcamera --camera-format=YUV420 # better performance tools/*_camera.sh --camera-type=libcamera --camera-format=MJPEG ``` -------------------------------- ### Run CSI Camera Script with Help and Format Options Source: https://github.com/ayufan/camera-streamer/blob/main/docs/v4l2-isp-mode.md This snippet shows how to use the `csi_camera.sh` script to display help information and to set the camera format. It is intended for configuring the camera for high-performance ISP mode. ```bash # This script uses dumped IMX519 parametrs that are feed into bcm2385 ISP module # This does not provide automatic brightness control # Other sensors can be supported the same way as long as ISP parameters are adapted tools/csi_camera.sh -help tools/csi_camera.sh -camera-format=RG10 ... ``` -------------------------------- ### Fetch Initial Status and Configure Controls Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Fetches the initial device status and then configures the UI controls based on the received state. ```javascript fetch(`${baseURL}status`) .then(function (response) { return response.json() }) .then(function (state) { hide(waitSettings); show(settings); configureEndpoints(state); createControls(state); }) ``` -------------------------------- ### List Available Capture Formats Source: https://github.com/ayufan/camera-streamer/blob/main/docs/configure.md Lists all available capture formats for a given video device. This command helps in identifying compatible formats for the camera. ```bash v4l2-ctl -d /dev/video0 --list-formats-ext ``` -------------------------------- ### Configure GPU Memory in config.txt Source: https://github.com/ayufan/camera-streamer/blob/main/docs/install-manual.md Ensure sufficient GPU memory is allocated in /boot/config.txt, especially for JPEG re-encoding. Adjust 'gpu_mem' and add relevant 'dtoverlay' based on your camera model. ```text # Example for IMX519 dtoverlay=vc4-kms-v3d,cma-128 gpu_mem=128 # preferred 160 or 256MB dtoverlay=imx519 # Example for Arducam 64MP gpu_mem=128 dtoverlay=arducam_64mp,media-controller=1 # Example for USB cam gpu_mem=128 ``` -------------------------------- ### Initialize WebRTC on Page Load Source: https://github.com/ayufan/camera-streamer/blob/main/html/webrtc.html Calls the startWebRTC function when the page has finished loading. ```javascript window.onload = function() { startWebRTC(); } ``` -------------------------------- ### Inspect /dev/video8 Device Information Source: https://github.com/ayufan/camera-streamer/blob/main/debug/btt-pi2.txt Use v4l2-ctl to query the /dev/video8 device for its driver information, capabilities, and other relevant device parameters. ```bash v4l2-ctl -d /dev/video8 --info --list-formats-ext --list-fields --list-formats-out --list-fields-out --list-ctrls ``` -------------------------------- ### Inspect /dev/video7 Device Information Source: https://github.com/ayufan/camera-streamer/blob/main/debug/btt-pi2.txt Use v4l2-ctl to retrieve comprehensive information for the /dev/video7 device, covering driver specifics, media driver details, and interface information. ```bash v4l2-ctl -d /dev/video7 --info --list-formats-ext --list-fields --list-formats-out --list-fields-out --list-ctrls ``` -------------------------------- ### Clone camera-streamer Repository Source: https://github.com/ayufan/camera-streamer/blob/main/README.md Use this command to clone the camera-streamer repository, ensuring all submodules are included. ```bash git clone --recurse-submodules https://github.com/ayufan/camera-streamer.git ``` -------------------------------- ### Initiate WebRTC Stream Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Stops the current stream, shows the video container, and initiates a WebRTC connection. Handles ICE servers and track events. ```javascript document.getElementById('webrtc-stream').onclick = () => { stopStream(); show(videoContainer); const iceServers = [ { urls: ['stun:stun.l.google.com:19302'] } ]; fetch(baseURL + webrtcURL, { body: JSON.stringify({ type: 'request', iceServers: iceServers, keepAlive: true }), headers: {'Content-Type': 'application/json'}, method: 'POST' }).then(function(response) { return response.json(); }).then(function(request) { rtcPeerConnection = new RTCPeerConnection({ sdpSemantics: 'unified-plan', iceServers: request.iceServers }); rtcPeerConnection.addEventListener('datachannel', function(e) { const dc = e.channel; if (dc.label === 'keepalive') { dc.addEventListener('message', function(e) { dc.send('pong'); }); } }); rtcPeerConnection.addTransceiver('video', {direction: 'recvonly'}); //pc.addTransceiver('audio', {direction: 'recvonly'}); rtcPeerConnection.addEventListener('track', function(evt) { console.log("track event " + evt.track.kind); if (evt.track.kind == 'video') { const view = document.getElementById("video-view"); view.srcObject = evt.streams[0]; view.scrollIntoView(false); } }); rtcPeerConnection.addEventListener("icecandidate", function(e) { if (e.candidate) { return fetch(baseURL + webrtcURL, { body: JSON.stringify({ type: 'remote_candidate', id: rtcPeerConnection.remote_pc_id, candidates: [e.candidate] }), headers: { 'Content-Type': 'application/json' }, method: 'POST' }).catch(function(e) { console.log("Failed to send ICE WebRTC: "+e); }); } }); rtcPeerConnection.remote_pc_id = request.id; return rtcPeerConnection.setRemoteDescription(request); }).then(function() { return rtcPeerConnection.createAnswer(); }).then(function(answer) { return rtcPeerConnection.setLocalDescription(answer); }).then(function(answer) { const offer = rtcPeerConnection.localDescription; return fetch(baseURL + webrtcURL, { body: JSON.stringify({ type: offer.t ``` -------------------------------- ### Create Device Controls Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Iterates through devices and their options to create corresponding control elements on the page. ```javascript const createControls = (state) => { for (let device of state.devices) { const heading = insertControl("h1"); heading.textContent = device.name; for (let key in device.options) { createDeviceOption(device, key, device.options[key]); } } }; ``` -------------------------------- ### Set Camera Format with libcamera Source: https://github.com/ayufan/camera-streamer/blob/main/docs/raspi-libcamera.md This command sets the camera output format to YUYV using the libcamera_camera.sh script. ```bash tools/libcamera_camera.sh -camera-format=YUYV ``` -------------------------------- ### Validate System Devices Source: https://github.com/ayufan/camera-streamer/blob/main/docs/install-manual.md Use this command to check for the presence of required video devices (ISP, encoders, decoders) on your system. ```bash uname -a v4l2-ctl --list-devices ``` -------------------------------- ### 2328x1748@10fps Performance Test Source: https://github.com/ayufan/camera-streamer/blob/main/docs/performance-analysis.md Performance logs for Arducam 16MP at 2328x1748 resolution and 10fps. Compares libcamera and direct ISP-mode. ```shell # libcamera $ ./camera_streamer -camera-path=/base/soc/i2c0mux/i2c@1/imx519@1a -camera-type=libcamera -camera-format=YUYV -camera-fps=10 -camera-width=2328 -camera-height=1748 -camera-high_res_factor=1.5 -log-filter=buffer_lock device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf2 (refs=2), frame=585/0, processing_ms=155.3, frame_ms=100.0 device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf0 (refs=2), frame=586/0, processing_ms=155.5, frame_ms=100.2 # direct ISP-mode $ ./camera_streamer -camera-path=/dev/video0 -camera-format=RG10 -camera-fps=10 -camera-width=2328 -camera-height=1748 -camera-high_res_factor=1.5 -log-filter=buffer_lock device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf1 (refs=2), frame=260/0, processing_ms=57.5, frame_ms=99.7 device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf2 (refs=2), frame=261/0, processing_ms=57.6, frame_ms=100.0 device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf0 (refs=2), frame=262/0, processing_ms=58.0, frame_ms=100.4 ``` -------------------------------- ### List Available Cameras Source: https://github.com/ayufan/camera-streamer/blob/main/docs/configure.md Lists available cameras and their supported modes and resolutions. This is useful for determining the native resolution of your camera sensor. ```text libcamera-still --list-cameras Available cameras ----------------- 0 : imx708_wide [4608x2592] (/base/soc/i2c0mux/i2c@1/imx708@1a) Modes: 'SRGGB10_CSI2P' : 1536x864 [120.13 fps - (0, 0)/4608x2592 crop] 2304x1296 [56.03 fps - (0, 0)/4608x2592 crop] 4608x2592 [14.35 fps - (0, 0)/4608x2592 crop] ``` -------------------------------- ### 2328x1748@30fps Performance Test Source: https://github.com/ayufan/camera-streamer/blob/main/docs/performance-analysis.md Performance logs for Arducam 16MP at 2328x1748 resolution and 30fps. Compares libcamera and direct ISP-mode. ```shell # libcamera $ ./camera_streamer -camera-path=/base/soc/i2c0mux/i2c@1/imx519@1a -camera-type=libcamera -camera-format=YUYV -camera-fps=120 -camera-width=2328 -camera-height=1748 -camera-high_res_factor=1.5 -log-filter=buffer_lock device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf2 (refs=2), frame=63/0, processing_ms=101.1, frame_ms=33.1 device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf0 (refs=2), frame=64/0, processing_ms=99.2, frame_ms=31.9 device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf1 (refs=2), frame=65/0, processing_ms=99.6, frame_ms=34.8 # direct ISP-mode $ ./camera_streamer -camera-path=/dev/video0 -camera-format=RG10 -camera-fps=30 -camera-width=2328 -camera-height=1748 -camera-high_res_factor=1.5 -log-filter=buffer_lock device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf1 (refs=2), frame=32/0, processing_ms=49.7, frame_ms=33.3 device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf2 (refs=2), frame=33/0, processing_ms=49.7, frame_ms=33.3 device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf0 (refs=2), frame=34/0, processing_ms=49.7, frame_ms=33.4 ``` -------------------------------- ### Create Text Input Control Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Generates a text input element for device options. Includes an optional description element below the input. ```javascript } else { const divEl = document.createElement("div"); divEl.className = "text"; groupEl.appendChild(divEl); const inputEl = document.createElement("input"); inputEl.id = id_key; inputEl.type = "text"; inputEl.className = "default-action"; if (option.value) inputEl.value = option.value; else inputEl.value = "?"; divEl.appendChild(inputEl); if (option.description) { const divDescriptionEl = document.createElement("div"); divDescriptionEl.className = "range-max"; divDescriptionEl.textContent = option.description; divEl.appendChild(divDescriptionEl); } inputEl.onchange = () => { sendOptionValue(device.name, key, inputEl.value); } ``` -------------------------------- ### Create Range and Number Input Controls Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Generates linked range and number input elements for device options. Ensures the step value is at least 1. ```javascript if (stepValue < 1) stepValue = 1; } const inputRangeEl = document.createElement("input"); inputRangeEl.id = id_key; inputRangeEl.type = "range"; inputRangeEl.className = "default-action"; inputRangeEl.min = minValue; inputRangeEl.max = maxValue; inputRangeEl.step = stepValue; inputRangeEl.style = "width: 100px"; if (option.value) inputRangeEl.value = Number(option.value); else inputRangeEl.value = "?"; groupEl.appendChild(inputRangeEl); const inputNumberEl = document.createElement("input"); inputNumberEl.id = id_key; inputNumberEl.type = "number"; //inputNumberEl.className = "default-action"; inputNumberEl.className = "range-max"; inputNumberEl.style = "width: 20px"; inputNumberEl.min = minValue; inputNumberEl.max = maxValue; inputNumberEl.step = stepValue; inputNumberEl.size = "4"; if (option.value) inputNumberEl.value = Number(option.value); else inputNumberEl.value = "?"; groupEl.appendChild(inputNumberEl); inputRangeEl.onchange = () => { sendOptionValue(device.name, key, inputRangeEl.value); inputNumberEl.value = inputRangeEl.value; } inputNumberEl.onchange = () => { sendOptionValue(device.name, key, inputNumberEl.value); inputRangeEl.value = inputNumberEl.value; } ``` -------------------------------- ### Specify Camera Capture Format Source: https://github.com/ayufan/camera-streamer/blob/main/docs/configure.md Sets the camera capture format for streamer. Recommended formats include YUYV for better image quality or YUV420 for better performance with libcamera, and MJPEG for USB cameras. ```bash tools/*_camera.sh --camera-format=RG10 # Bayer 10 packed tools/*_camera.sh --camera-format=YUYV tools/*_camera.sh --camera-format=MJPEG tools/*_camera.sh --camera-format=H264 # This is unstable due to h264 key frames support ``` -------------------------------- ### View Systemd Service Logs Source: https://github.com/ayufan/camera-streamer/blob/main/docs/install-manual.md Use journalctl to view error messages and logs for a specific camera streamer systemd service, such as the Arducam 16MP service. ```bash journalctl -xef -u camera-streamer-arducam-16MP ``` -------------------------------- ### Configure Camera Resolution with Cropped Output Source: https://github.com/ayufan/camera-streamer/blob/main/docs/configure.md Configures camera capture with a resolution that is not the native sensor resolution, resulting in a cropped output. Use this when the full sensor resolution is not desired or available. ```text --camera-width=1920 --camera-height=1080 --camera-snapshot.height=1080 --camera-video.height=720 --camera-stream.height=480 ``` -------------------------------- ### 1280x720@120fps Performance Test for Arducam 16MP Source: https://github.com/ayufan/camera-streamer/blob/main/docs/performance-analysis.md Performance logs for Arducam 16MP at 1280x720 resolution and 120fps. Compares libcamera and direct ISP-mode. ```shell # libcamera $ ./camera_streamer -camera-path=/base/soc/i2c0mux/i2c@1/imx519@1a -camera-type=libcamera -camera-format=YUYV -camera-fps=120 -camera-width=1280 -camera-height=720 -log-filter=buffer_lock device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf0 (refs=2), frame=139/0, processing_ms=20.1, frame_ms=7.9 device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf1 (refs=2), frame=140/0, processing_ms=20.6, frame_ms=8.8 device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf2 (refs=2), frame=141/0, processing_ms=19.8, frame_ms=8.1 # direct ISP-mode $ ./camera_streamer -camera-path=/dev/video0 -camera-format=RG10 -camera-fps=120 -camera-width=1280 -camera-height=720 -log-filter=buffer_lock device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf0 (refs=2), frame=157/0, processing_ms=18.5, frame_ms=8.4 device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf1 (refs=2), frame=158/0, processing_ms=18.5, frame_ms=8.3 device/buffer_lock.c: http_jpeg: Captured buffer JPEG:capture:mplane:buf2 (refs=2), frame=159/0, processing_ms=18.5, frame_ms=8.3 ``` -------------------------------- ### Configure Camera Resolution for Best Quality Source: https://github.com/ayufan/camera-streamer/blob/main/docs/configure.md Sets camera capture resolution to the native sensor resolution and then scales down for snapshot, video, and stream outputs. This ensures the highest possible quality for each stream type. ```text --camera-width=2304 --camera-height=1296 --camera-snapshot.height=1080 --camera-video.height=720 --camera-stream.height=480 ``` -------------------------------- ### Arducam 16MP Configuration Source: https://github.com/ayufan/camera-streamer/blob/main/docs/performance-analysis.md Configuration for the Arducam 16MP sensor on Raspberry Pi OS. Includes settings for `/boot/config.txt` and `/etc/modules-load.d/modules.conf`. ```shell # /boot/config.txt dtoverlay=imx519,media-controller=0 gpu_mem=160 # at least 128 # /etc/modules-load.d/modules.conf i2c-dev # after starting camera execute to control the focus with `0xXX`, any value between `0x00` to `0xff` # RPI02W (and possible 2+, 3+): i2ctransfer -y 22 w4@0x0c 0x0 0x85 0x00 0x00 # RPI4: i2ctransfer -y 11 w4@0x0c 0x0 0xXX 0x00 0x00 ``` -------------------------------- ### Create Device Option Control Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Dynamically creates and inserts UI controls for device options, supporting boolean checkboxes, select menus for enumerated values, and range sliders for numerical inputs. ```javascript const createDeviceOption = (device, key, option) => { const id_key = `${device.name}_${key}`; const groupEl = insertControl("div"); groupEl.className = "input-group"; const labelEl = document.createElement("label"); labelEl.setAttribute("for", id_key); labelEl.textContent = option.name; groupEl.appendChild(labelEl); switch (option.type) { case "bool": const divEl = document.createElement("div"); divEl.className = "switch"; groupEl.appendChild(divEl); const inputEl = document.createElement("input"); inputEl.id = id_key; inputEl.type = "checkbox"; inputEl.className = "default-action"; divEl.appendChild(inputEl); const labelSliderEl = document.createElement("label"); labelSliderEl.setAttribute("for", id_key); labelSliderEl.className = "slider"; divEl.appendChild(labelSliderEl); if (option.value) inputEl.checked = option.value == '1'; inputEl.onclick = () => { sendOptionValue(device.name, key, inputEl.checked ? 1 : 0); } break; case "integer": case "integer64": case "float": if (option.menu) { const selectEl = document.createElement("select"); selectEl.className = "default-action"; selectEl.id = id_key; selectEl.value = option.value; groupEl.appendChild(selectEl); if (!option.value) { const optionEl = document.createElement("option"); optionEl.text = "?"; selectEl.add(optionEl); } for (let value in option.menu) { const optionEl = document.createElement("option"); optionEl.value = value; optionEl.text = option.menu[value]; selectEl.add(optionEl); if (optionEl.text == option.value) selectEl.value = value; } selectEl.onchange = () => { sendOptionValue(device.name, key, selectEl.value); } } else if (option.description && (!option.elems || option.elems == 1) && (range = option.description.match("^\\\\[(.\*)\\\.\\(.\*)\\\\\]$"))) { const minValue = Number(range[1]); const maxValue = Number(range[2]); let stepValue = (maxValue - minValue) / 20; if (option.type != "float") { stepValue = Math.round(stepValue); if ``` -------------------------------- ### Send WebRTC Offer Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Sends a WebRTC offer to a remote peer using an HTTP POST request. This is typically used to initiate a connection. ```javascript fetch("/api/v1/webrtc/offer", { body: JSON.stringify({ type: rtcPeerConnection.remote_pc_id, sdp: offer.sdp }), headers: { 'Content-Type': 'application/json' }, method: 'POST' }).then(function(response) { return response.json(); }).catch(function(e) { console.log(e); }); ``` -------------------------------- ### Configure Camera Streamer Endpoints Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Enables or disables various camera stream endpoints based on the provided state. Updates version and revision information. Displays endpoint URIs if enabled. ```javascript const configureEndpoints =(state) => { enable2(document.getElementById('get-still'), state.endpoints.snapshot.enabled); enable2(document.getElementById('mjpeg-stream'), state.endpoints.stream.enabled); enable2(document.getElementById('webrtc-stream'), state.endpoints.webrtc.enabled); document.getElementById('git_version').textContent = state.version; document.getElementById('git_revision').textContent = state.revision; for (let type of ["snapshot", "stream", "video", "webrtc", "rtsp"]) { if (!state.endpoints[type].enabled) continue; let groupView = document.getElementById(`${type}-group`); let urlView = document.getElementById(`${type}_url`); show(groupView); urlView.href = urlView.innerHTML = state.endpoints[type].uri; } }; ``` -------------------------------- ### Send Camera Option Value Source: https://github.com/ayufan/camera-streamer/blob/main/html/control.html Sends a specific option value for a given camera device. The device, key, and value are URL-encoded before being sent via a POST request. ```javascript const sendOptionValue = (device, key, value) => { device = encodeURIComponent(device); key = encodeURIComponent(key); value = encodeURIComponent(value); return fetch(`${baseURL}option?device=${device}&key=${key}&value=${value}`, { method: 'POST' }).then(function (response) { return response; }); }; ```