237 lines
5.1 KiB
Bash
Executable File
237 lines
5.1 KiB
Bash
Executable File
#!/bin/sh
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
# Copyright (C) 2019, Google Inc.
|
|
#
|
|
# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
#
|
|
# Capture processed frames from cameras based on the Rockchip ISP1
|
|
#
|
|
# The scripts makes use of the following tools, which are expected to be
|
|
# executable from the system-wide path or from the local directory:
|
|
#
|
|
# - media-ctl (from v4l-utils git://linuxtv.org/v4l-utils.git)
|
|
# - raw2rgbpnm (from git://git.retiisi.org.uk/~sailus/raw2rgbpnm.git)
|
|
# - yavta (from git://git.ideasonboard.org/yavta.git)
|
|
|
|
# Return the entity connected to a given pad
|
|
# $1: The pad, expressed as "entity":index
|
|
mc_remote_entity() {
|
|
local entity="${1%:*}"
|
|
local pad="${1#*:}"
|
|
|
|
${mediactl} -p | awk '
|
|
/^- entity / {
|
|
in_entity=0
|
|
}
|
|
|
|
/^- entity [0-9]+: '"${entity}"' / {
|
|
in_entity=1
|
|
}
|
|
|
|
/^[ \t]+pad/ {
|
|
in_pad=0
|
|
}
|
|
|
|
/^[ \t]+pad'"${pad}"': / {
|
|
in_pad=1
|
|
}
|
|
|
|
/^[ \t]+(<-|->) "[^"]+"/ {
|
|
if (in_entity && in_pad) {
|
|
print gensub(/^[^"]+"([^"]+)":([0-9]+).*$/, "\\1", "g")
|
|
exit
|
|
}
|
|
}'
|
|
}
|
|
|
|
# Locate the sensor entity
|
|
find_sensor() {
|
|
local bus
|
|
local sensor_name=$1
|
|
|
|
bus=$(grep "$sensor_name " /sys/class/video4linux/v4l-subdev*/name | cut -d ' ' -f 2)
|
|
if [[ -z $bus ]]; then
|
|
echo "Sensor '$sensor_name' not found." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "$sensor_name $bus"
|
|
}
|
|
|
|
# Locate the CSI-2 receiver
|
|
find_csi2_rx() {
|
|
local sensor_name=$1
|
|
local csi2_rx
|
|
|
|
csi2_rx=$(mc_remote_entity "$sensor_name:0")
|
|
if [ "$csi2_rx" != rkisp1_isp ] ; then
|
|
echo "$csi2_rx"
|
|
fi
|
|
}
|
|
|
|
# Locate the media device
|
|
find_media_device() {
|
|
local mdev
|
|
local name=$1
|
|
|
|
for mdev in /dev/media* ; do
|
|
media-ctl -d $mdev -p | grep -q "^driver[ \t]*$name$" && break
|
|
mdev=
|
|
done
|
|
|
|
if [[ -z $mdev ]] ; then
|
|
echo "$name media device not found." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo $mdev
|
|
}
|
|
|
|
# Get the sensor format
|
|
get_sensor_format() {
|
|
local format
|
|
local sensor=$1
|
|
|
|
format=$($mediactl --get-v4l2 "'$sensor':0" | grep 'fmt:' | sed 's/.*\(fmt:\S*\).*/\1/')
|
|
sensor_mbus_code=$(echo $format | sed 's/fmt:\([A-Z0-9_]*\).*/\1/')
|
|
sensor_size=$(echo $format | sed 's/[^\/]*\/\([0-9x]*\).*/\1/')
|
|
|
|
echo "Capturing ${sensor_size} from sensor $sensor in ${sensor_mbus_code}"
|
|
}
|
|
|
|
# Configure the pipeline
|
|
configure_pipeline() {
|
|
local format="fmt:$sensor_mbus_code/$sensor_size"
|
|
local capture_mbus_code=$1
|
|
local capture_size=$2
|
|
local csi2_rx
|
|
|
|
echo "Configuring pipeline for $sensor in $format"
|
|
|
|
csi2_rx=$(find_csi2_rx "$sensor")
|
|
|
|
$mediactl -r
|
|
|
|
if [ -n "$csi2_rx" ] ; then
|
|
$mediactl -l "'$sensor':0 -> '$csi2_rx':0 [1]"
|
|
$mediactl -l "'$csi2_rx':1 -> 'rkisp1_isp':0 [1]"
|
|
else
|
|
$mediactl -l "'$sensor':0 -> 'rkisp1_isp':0 [1]"
|
|
fi
|
|
$mediactl -l "'rkisp1_isp':2 -> 'rkisp1_resizer_mainpath':0 [1]"
|
|
|
|
$mediactl -V "\"$sensor\":0 [$format]"
|
|
if [ -n "$csi2_rx" ] ; then
|
|
$mediactl -V "'$csi2_rx':0 [$format]"
|
|
$mediactl -V "'$csi2_rx':1 [$format]"
|
|
fi
|
|
$mediactl -V "'rkisp1_isp':0 [$format crop:(0,0)/$sensor_size]"
|
|
$mediactl -V "'rkisp1_isp':2 [fmt:$capture_mbus_code/$sensor_size crop:(0,0)/$sensor_size]"
|
|
$mediactl -V "'rkisp1_resizer_mainpath':0 [fmt:$capture_mbus_code/$sensor_size crop:(0,0)/$sensor_size]"
|
|
$mediactl -V "'rkisp1_resizer_mainpath':1 [fmt:$capture_mbus_code/$capture_size]"
|
|
}
|
|
|
|
# Capture frames
|
|
capture_frames() {
|
|
local file_op
|
|
local capture_format=$1
|
|
local capture_size=$2
|
|
local frame_count=$3
|
|
local save_file=$4
|
|
|
|
if [[ $save_file -eq 1 ]]; then
|
|
file_op="--file=/tmp/frame-#.bin"
|
|
rm -f /tmp/frame-*.bin
|
|
fi
|
|
|
|
yavta -c$frame_count -n5 -I -f $capture_format -s $capture_size \
|
|
$file_op $($mediactl -e "rkisp1_mainpath")
|
|
}
|
|
|
|
# Convert captured files to ppm
|
|
convert_files() {
|
|
local format=$1
|
|
local size=$2
|
|
local frame_count=$3
|
|
|
|
echo "Converting ${frame_count} frames (${size})"
|
|
|
|
for i in `seq 0 $(($frame_count - 1))`; do
|
|
i=$(printf %06u $i)
|
|
raw2rgbpnm -f $format -s $size /tmp/frame-$i.bin /tmp/frame-$i.ppm
|
|
done
|
|
}
|
|
|
|
# Print usage message
|
|
usage() {
|
|
echo "Usage: $1 [options] sensor-name"
|
|
echo "Supported options:"
|
|
echo "-c,--count n Number of frame to capture"
|
|
echo "--no-save Do not save captured frames to disk"
|
|
echo "-r, --raw Capture RAW frames"
|
|
echo "-s, --size wxh Frame size"
|
|
}
|
|
|
|
# Parse command line arguments
|
|
capture_size=1024x768
|
|
frame_count=10
|
|
raw=false
|
|
save_file=1
|
|
|
|
while [[ $# -ne 0 ]] ; do
|
|
case $1 in
|
|
-c|--count)
|
|
frame_count=$2
|
|
shift 2
|
|
;;
|
|
--no-save)
|
|
save_file=0
|
|
shift
|
|
;;
|
|
|
|
-r|--raw)
|
|
raw=true
|
|
shift
|
|
;;
|
|
-s|--size)
|
|
capture_size=$2
|
|
shift 2
|
|
;;
|
|
-*)
|
|
echo "Unsupported option $1" >&2
|
|
usage $0
|
|
exit 1
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ $# -ne 1 ]] ; then
|
|
usage $0
|
|
exit 1
|
|
fi
|
|
|
|
sensor_name=$1
|
|
|
|
modprobe phy_rockchip_dphy_rx0
|
|
modprobe rockchip_isp1
|
|
|
|
sensor=$(find_sensor $sensor_name) || exit
|
|
mdev=$(find_media_device rkisp1) || exit
|
|
mediactl="media-ctl -d $mdev"
|
|
|
|
get_sensor_format "$sensor"
|
|
if [[ $raw == true ]] ; then
|
|
capture_format=$(echo $sensor_mbus_code | sed 's/_[0-9X]*$//')
|
|
capture_mbus_code=$sensor_mbus_code
|
|
else
|
|
capture_format=YUYV
|
|
capture_mbus_code=YUYV8_2X8
|
|
fi
|
|
|
|
configure_pipeline $capture_mbus_code $capture_size
|
|
capture_frames $capture_format $capture_size $frame_count $save_file
|
|
[[ $save_file -eq 1 ]] && convert_files $capture_format $capture_size $frame_count
|