An attempt at getting image data back
This commit is contained in:
182
spider-cam/libcamera/utils/ipu3/ipu3-capture.sh
Executable file
182
spider-cam/libcamera/utils/ipu3/ipu3-capture.sh
Executable file
@@ -0,0 +1,182 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Copyright (C) 2018, Google Inc.
|
||||
#
|
||||
# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
#
|
||||
# Capture raw frames from cameras based on the Intel IPU3
|
||||
#
|
||||
# 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)
|
||||
# - raw2pnm (from nvt https://github.com/intel/nvt.git)
|
||||
# - yavta (from git://git.ideasonboard.org/yavta.git)
|
||||
|
||||
# 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 media device
|
||||
find_media_device() {
|
||||
local mdev
|
||||
|
||||
for mdev in /dev/media* ; do
|
||||
media-ctl -d $mdev -p | grep -q "^driver[ \t]*ipu3-cio2$" && break
|
||||
mdev=
|
||||
done
|
||||
|
||||
if [[ -z $mdev ]] ; then
|
||||
echo "IPU3 media device not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo $mdev
|
||||
}
|
||||
|
||||
# Locate the CSI2 and CIO2 and get the sensor format
|
||||
parse_pipeline() {
|
||||
local cio2_queue
|
||||
local resolution
|
||||
local sensor=$1
|
||||
|
||||
read cio2_queue bus_format sensor_size <<< $($mediactl -p | awk "
|
||||
/^- entity [0-9]*:/ {
|
||||
sensor=0;
|
||||
}
|
||||
|
||||
/^- entity [0-9]*: $sensor/ {
|
||||
sensor=1;
|
||||
}
|
||||
|
||||
/^[ \t]*(stream:0)?\[fmt:/ {
|
||||
if (sensor) {
|
||||
gsub(\".*fmt:\", \"\");
|
||||
gsub(\"[] ].*\", \"\");
|
||||
sub(\"/\", \" \");
|
||||
sub(\"@[0-9]+/[0-9]+\", \"\");
|
||||
format=\$0;
|
||||
}
|
||||
}
|
||||
|
||||
/^[ \t]*->/ {
|
||||
if (sensor)
|
||||
cio2=substr(\$3, 0, 1);
|
||||
}
|
||||
|
||||
END {
|
||||
print cio2 \" \" format;
|
||||
}
|
||||
")
|
||||
|
||||
ipu3_csi2="ipu3-csi2 $cio2_queue"
|
||||
ipu3_capture="ipu3-cio2 $cio2_queue"
|
||||
|
||||
sensor_width=$(echo $sensor_size | cut -d 'x' -f 1)
|
||||
sensor_height=$(echo $sensor_size | cut -d 'x' -f 2)
|
||||
|
||||
echo "Using device $mdev with IPU3 CIO2 queue $cio2_queue"
|
||||
}
|
||||
|
||||
# Configure the pipeline
|
||||
configure_pipeline() {
|
||||
local format="fmt:$bus_format/$sensor_size"
|
||||
|
||||
echo "Configuring pipeline for $sensor in $format"
|
||||
|
||||
$mediactl -r
|
||||
|
||||
$mediactl -l "\"$sensor\":0 -> \"$ipu3_csi2\":0[1]"
|
||||
$mediactl -l "\"$ipu3_csi2\":1 -> \"$ipu3_capture\":0[1]"
|
||||
|
||||
$mediactl -V "\"$sensor\":0 [$format]"
|
||||
$mediactl -V "\"$ipu3_csi2\":1 [$format]"
|
||||
}
|
||||
|
||||
# Capture frames
|
||||
capture_frames() {
|
||||
local file_op
|
||||
local frame_count=$1
|
||||
local ipu3_format=IPU3_${bus_format/_1X10/}
|
||||
local save_file=$2
|
||||
|
||||
if [[ $save_file -eq 1 ]]; then
|
||||
file_op="--file=/tmp/frame-#.bin"
|
||||
fi
|
||||
|
||||
yavta -c$frame_count -n5 -I -f $ipu3_format -s $sensor_size $file_op \
|
||||
$($mediactl -e "$ipu3_capture")
|
||||
}
|
||||
|
||||
# Convert captured files to ppm
|
||||
convert_files() {
|
||||
local frame_count=$1
|
||||
local format=${bus_format/_1X10/}
|
||||
local padded_width=$(expr \( $sensor_width + 49 \) / 50 \* 50)
|
||||
|
||||
echo "Converting ${sensor_width}x${sensor_height} (${padded_width}x${sensor_height})"
|
||||
|
||||
for i in `seq -f '%06.0f' 0 $(($frame_count - 1))`; do
|
||||
ipu3-unpack /tmp/frame-$i.bin /tmp/frame-$i.raw
|
||||
raw2pnm -x$padded_width -y$sensor_height -f$format /tmp/frame-$i.raw /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"
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
frame_count=10
|
||||
save_file=1
|
||||
|
||||
while (( "$#" )) ; do
|
||||
case $1 in
|
||||
-c|--count)
|
||||
frame_count=$2
|
||||
shift 2
|
||||
;;
|
||||
--no-save)
|
||||
save_file=0
|
||||
shift
|
||||
;;
|
||||
-*)
|
||||
echo "Unsupported option $1" >&2
|
||||
usage $0
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ $# -ne 1 ]] ; then
|
||||
usage $0
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sensor_name=$1
|
||||
|
||||
sensor=$(find_sensor $sensor_name) || exit
|
||||
mdev=$(find_media_device) || exit
|
||||
mediactl="media-ctl -d $mdev"
|
||||
|
||||
parse_pipeline $sensor
|
||||
configure_pipeline
|
||||
capture_frames $frame_count $save_file
|
||||
[[ $save_file -eq 1 ]] && convert_files $frame_count
|
||||
101
spider-cam/libcamera/utils/ipu3/ipu3-pack.c
Normal file
101
spider-cam/libcamera/utils/ipu3/ipu3-pack.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* ipu3-pack - Convert unpacked RAW10 Bayer data to the IPU3 packed Bayer formats
|
||||
*
|
||||
* Copyright 2022 Umang Jain <umang.jain@ideasonboard.com>
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void usage(char *argv0)
|
||||
{
|
||||
printf("Usage: %s input-file output-file\n", basename(argv0));
|
||||
printf("Convert unpacked RAW10 Bayer data to the IPU3 packed Bayer formats\n");
|
||||
printf("If the output-file '-', output data will be written to standard output\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int in_fd;
|
||||
int out_fd;
|
||||
int ret;
|
||||
|
||||
if (argc != 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
in_fd = open(argv[1], O_RDONLY);
|
||||
if (in_fd == -1) {
|
||||
fprintf(stderr, "Failed to open input file '%s': %s\n",
|
||||
argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[2], "-") == 0) {
|
||||
out_fd = STDOUT_FILENO;
|
||||
} else {
|
||||
out_fd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644);
|
||||
if (out_fd == -1) {
|
||||
fprintf(stderr, "Failed to open output file '%s': %s\n",
|
||||
argv[2], strerror(errno));
|
||||
close(in_fd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
uint16_t in_data[25];
|
||||
uint8_t out_data[32];
|
||||
unsigned int i;
|
||||
|
||||
ret = read(in_fd, in_data, sizeof(in_data));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to read input data: %s\n",
|
||||
strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((unsigned)ret < sizeof(in_data)) {
|
||||
if (ret != 0)
|
||||
fprintf(stderr, "%u bytes of stray data at end of input\n",
|
||||
ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < 30; ++i) {
|
||||
unsigned int index = (i * 8) / 10;
|
||||
unsigned int msb_shift = (i * 8) % 10;
|
||||
unsigned int lsb_shift = 10 - msb_shift;
|
||||
|
||||
out_data[i] = ((in_data[index] >> msb_shift) & 0xff)
|
||||
| ((in_data[index+1] << lsb_shift) & 0xff);
|
||||
}
|
||||
|
||||
out_data[30] = (in_data[24] >> 0) & 0xff;
|
||||
out_data[31] = (in_data[24] >> 8) & 0x03;
|
||||
|
||||
ret = write(out_fd, out_data, sizeof(out_data));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to write output data: %s\n",
|
||||
strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
close(in_fd);
|
||||
if (out_fd != STDOUT_FILENO)
|
||||
close(out_fd);
|
||||
|
||||
return ret ? 1 : 0;
|
||||
}
|
||||
198
spider-cam/libcamera/utils/ipu3/ipu3-process.sh
Executable file
198
spider-cam/libcamera/utils/ipu3/ipu3-process.sh
Executable file
@@ -0,0 +1,198 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Copyright (C) 2018, Google Inc.
|
||||
#
|
||||
# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
#
|
||||
# Process raw frames with the Intel IPU3
|
||||
#
|
||||
# The scripts makes use of the following tools, which are expected to be
|
||||
# found in $PATH:
|
||||
#
|
||||
# - media-ctl (from v4l-utils git://linuxtv.org/v4l-utils.git)
|
||||
# - raw2pnm (from nvt https://github.com/intel/nvt.git)
|
||||
# - yavta (from git://git.ideasonboard.org/yavta.git)
|
||||
|
||||
imgu_entity="ipu3-imgu 0"
|
||||
|
||||
# Locate the media device
|
||||
find_media_device() {
|
||||
local mdev
|
||||
|
||||
for mdev in /dev/media* ; do
|
||||
media-ctl -d $mdev -p | grep -q "^driver[ \t]*ipu3-imgu$" && break
|
||||
mdev=
|
||||
done
|
||||
|
||||
if [[ -z $mdev ]] ; then
|
||||
echo "IPU3 media device not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo $mdev
|
||||
}
|
||||
|
||||
# Configure the pipeline
|
||||
configure_pipeline() {
|
||||
local enable_3a=1
|
||||
local enable_out=1
|
||||
local enable_vf=1
|
||||
local mode=0
|
||||
|
||||
# Configure the links
|
||||
$mediactl -r
|
||||
$mediactl -l "\"$imgu_entity input\":0 -> \"$imgu_entity\":0[1]"
|
||||
$mediactl -l "\"$imgu_entity\":2 -> \"$imgu_entity output\":0[$enable_out]"
|
||||
$mediactl -l "\"$imgu_entity\":3 -> \"$imgu_entity viewfinder\":0[$enable_vf]"
|
||||
$mediactl -l "\"$imgu_entity\":4 -> \"$imgu_entity 3a stat\":0[$enable_3a]"
|
||||
|
||||
# Select processing mode (0 for video, 1 for still image)
|
||||
yavta --no-query -w "0x009819c1 $mode" $($mediactl -e "$imgu_entity")
|
||||
|
||||
# Set formats. The media bus code doesn't matter as it is ignored by the
|
||||
# driver. We should use the FIXED format, but media-ctl doesn't support
|
||||
# it.
|
||||
$mediactl -V "\"$imgu_entity\":0 [fmt:SBGGR10_1X10/$out_size crop:(0,0)/$in_size compose:(0,0)/$in_size]"
|
||||
$mediactl -V "\"$imgu_entity\":2 [fmt:SBGGR10_1X10/$out_size]"
|
||||
$mediactl -V "\"$imgu_entity\":3 [fmt:SBGGR10_1X10/$vf_size]"
|
||||
$mediactl -V "\"$imgu_entity\":4 [fmt:SBGGR10_1X10/$out_size]"
|
||||
}
|
||||
|
||||
# Perform frame processing through the IMGU
|
||||
process_frames() {
|
||||
configure_pipeline
|
||||
|
||||
local yavta="yavta -n $nbufs -c$frame_count"
|
||||
|
||||
# Save the main and viewfinder outputs to disk, capture and drop 3A
|
||||
# statistics. Sleep 500ms between each execution of yavta to keep the
|
||||
# stdout messages readable.
|
||||
$yavta -f $IMGU_OUT_PIXELFORMAT -s $out_size "-F$output_dir/frame-out-#.bin" \
|
||||
$($mediactl -e "$imgu_entity output") &
|
||||
sleep 0.5
|
||||
$yavta -f $IMGU_VF_PIXELFORMAT -s $vf_size "-F$output_dir/frame-vf-#.bin" \
|
||||
$($mediactl -e "$imgu_entity viewfinder") &
|
||||
sleep 0.5
|
||||
$yavta $($mediactl -e "$imgu_entity 3a stat") &
|
||||
sleep 0.5
|
||||
|
||||
# Feed the IMGU input.
|
||||
$yavta -f $IMGU_IN_PIXELFORMAT -s $in_size "-F$in_file" \
|
||||
$($mediactl -e "$imgu_entity input")
|
||||
}
|
||||
|
||||
# Convert captured files to ppm
|
||||
convert_files() {
|
||||
local index=$1
|
||||
local type=$2
|
||||
local size=$3
|
||||
local format=$4
|
||||
|
||||
local width=$(echo $size | awk -F 'x' '{print $1}')
|
||||
local height=$(echo $size | awk -F 'x' '{print $2}')
|
||||
local padded_width=$(expr $(expr $width + 63) / 64 \* 64)
|
||||
|
||||
raw2pnm -x$padded_width -y$height -f$format \
|
||||
$output_dir/frame-$type-$index.bin \
|
||||
$output_dir/frame-$type-$index.ppm
|
||||
}
|
||||
|
||||
run_test() {
|
||||
IMGU_IN_PIXELFORMAT=IPU3_SGRBG10
|
||||
IMGU_OUT_PIXELFORMAT=NV12
|
||||
IMGU_VF_PIXELFORMAT=NV12
|
||||
|
||||
echo "==== Test ===="
|
||||
echo "input: $in_file"
|
||||
echo "output: $IMGU_OUT_PIXELFORMAT/$out_size"
|
||||
echo "vf: $IMGU_VF_PIXELFORMAT/$vf_size"
|
||||
|
||||
process_frames
|
||||
|
||||
for i in `seq -f '%06.0f' 0 $(($frame_count - 1))`; do
|
||||
convert_files $i out $out_size $IMGU_OUT_PIXELFORMAT
|
||||
convert_files $i vf $vf_size $IMGU_VF_PIXELFORMAT
|
||||
done
|
||||
}
|
||||
|
||||
validate_size() {
|
||||
local size=$1
|
||||
local width=$(echo $size | awk -F 'x' '{print $1}')
|
||||
local height=$(echo $size | awk -F 'x' '{print $2}')
|
||||
|
||||
[[ "x${size}" == "x${width}x${height}" ]]
|
||||
}
|
||||
|
||||
# Print usage message
|
||||
usage() {
|
||||
echo "Usage: $(basename $1) [options] <input-file>"
|
||||
echo "Supported options:"
|
||||
echo "--out size output frame size (defaults to input size)"
|
||||
echo "--vf size viewfinder frame size (defaults to input size)"
|
||||
echo ""
|
||||
echo "Where the input file name and size are"
|
||||
echo ""
|
||||
echo "input-file = prefix '-' width 'x' height '.' extension"
|
||||
echo "size = width 'x' height"
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
while (( "$#" )) ; do
|
||||
case $1 in
|
||||
--out)
|
||||
out_size=$2
|
||||
if ! validate_size $out_size ; then
|
||||
echo "Invalid size '$out_size'"
|
||||
usage $0
|
||||
exit 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
--vf)
|
||||
vf_size=$2
|
||||
if ! validate_size $vf_size ; then
|
||||
echo "Invalid size '$vf_size'"
|
||||
usage $0
|
||||
exit 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
-*)
|
||||
echo "Unsupported option $1" >&2
|
||||
usage $0
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ $# != 1 ] ; then
|
||||
usage $0
|
||||
exit 1
|
||||
fi
|
||||
|
||||
in_file=$1
|
||||
|
||||
# Parse the size from the input file name and perform minimal sanity
|
||||
# checks.
|
||||
in_size=$(echo $in_file | sed 's/.*-\([0-9]*\)x\([0-9]*\)\.[a-z0-9]*$/\1x\2/')
|
||||
validate_size $in_size
|
||||
if [[ $? != 0 ]] ; then
|
||||
echo "Invalid input file name $in_file" >&2
|
||||
usage $0
|
||||
exit 1
|
||||
fi
|
||||
|
||||
out_size=${out_size:-$in_size}
|
||||
vf_size=${vf_size:-$in_size}
|
||||
|
||||
mdev=$(find_media_device) || exit
|
||||
mediactl="media-ctl -d $mdev"
|
||||
echo "Using device $mdev"
|
||||
|
||||
output_dir="/tmp"
|
||||
frame_count=5
|
||||
nbufs=7
|
||||
run_test
|
||||
94
spider-cam/libcamera/utils/ipu3/ipu3-unpack.c
Normal file
94
spider-cam/libcamera/utils/ipu3/ipu3-unpack.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* ipu3-unpack - Unpack IPU3 raw Bayer format to 16-bit Bayer
|
||||
*
|
||||
* Copyright 2018 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void usage(char *argv0)
|
||||
{
|
||||
printf("Usage: %s input-file output-file\n", basename(argv0));
|
||||
printf("Unpack the IPU3 raw Bayer format to 16-bit Bayer\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int in_fd;
|
||||
int out_fd;
|
||||
int ret;
|
||||
|
||||
if (argc != 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
in_fd = open(argv[1], O_RDONLY);
|
||||
if (in_fd == -1) {
|
||||
fprintf(stderr, "Failed to open input file '%s': %s\n",
|
||||
argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
out_fd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644);
|
||||
if (out_fd == -1) {
|
||||
fprintf(stderr, "Failed to open output file '%s': %s\n",
|
||||
argv[2], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
uint8_t in_data[32];
|
||||
uint8_t out_data[50];
|
||||
unsigned int i;
|
||||
|
||||
ret = read(in_fd, in_data, 32);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "Failed to read input data: %s\n",
|
||||
strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ret < 32) {
|
||||
if (ret != 0)
|
||||
fprintf(stderr, "%u bytes of stray data at end of input\n",
|
||||
ret);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < 25; ++i) {
|
||||
unsigned int index = (i * 10) / 8;
|
||||
unsigned int lsb_shift = (i * 10) % 8;
|
||||
unsigned int msb_shift = 8 - lsb_shift;
|
||||
uint16_t pixel;
|
||||
|
||||
pixel = ((in_data[index+1] << msb_shift) & 0x3ff)
|
||||
| ((in_data[index+0] >> lsb_shift) & 0x3ff);
|
||||
out_data[i*2+0] = (pixel >> 0) & 0xff;
|
||||
out_data[i*2+1] = (pixel >> 8) & 0xff;
|
||||
}
|
||||
|
||||
ret = write(out_fd, out_data, 50);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "Failed to write output data: %s\n",
|
||||
strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
close(in_fd);
|
||||
close(out_fd);
|
||||
|
||||
return ret ? 1 : 0;
|
||||
}
|
||||
4
spider-cam/libcamera/utils/ipu3/meson.build
Normal file
4
spider-cam/libcamera/utils/ipu3/meson.build
Normal file
@@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
ipu3_pack = executable('ipu3-pack', 'ipu3-pack.c')
|
||||
ipu3_unpack = executable('ipu3-unpack', 'ipu3-unpack.c')
|
||||
Reference in New Issue
Block a user