In thread raspivid: fpsₘₐₓ(v₂)=120, fpsₘₐₓ(v₁)=90 / 800x760: fps(v₂)=120, fps(v₁)=90 it was demonstrated, that while Raspberry documentation says v2 camera can do 90fps maximal, raspivid "-fps" option works fine until 120fps(!).
You can provide higher values, but the framerate gets capped at 120fps. @6by9 confirmed that this capping happens in closed source GPU firmware:
viewtopic.php?f=43&t=109137&p=1269504#p1269165
In very long raspiraw thread, this posting stated that @6by9 did merge all high framerate work into raspiraw master branch:
viewtopic.php?f=43&t=109137&start=375#p1266319
The high framerate work included capturing 640x128_s frames at 665fps without frame skips for v1 camera, and all the standard v2 camera modes after I captured and decoded "raspivid" I2C commands from Pi to v2 camera (under the guidance of @6by9). Although not all high framerate features work for v2 camera yet, it was possible to capture 640x480 frames at 240fps with raspiraw.
Yesterday I wanted to try out with how high framerate 640x480 frames can be captured with v2 camera and raspivid.
Because the relevant I2C commands to v2 camera are sent from GPU closed source code this was a challenge.
So I did first time "logic analyzer assisted programing":

I started by syncing @6by9's userland repo and inserted "sleep(1)" in various places in "host_applications/linux/apps/raspicam/RaspiVid.c" and comipled (without overwriting installed raspivid et al, initial build takes 6mins, this is incremental build):
Code: Select all
$ time ( ./buildme dummy )
...
-- Up-to-date: dummy/opt/vc/bin/dtmerge
-- Up-to-date: dummy/opt/vc/lib/libdtovl.so
~/userland/t/userland
real 0m49.253s
user 1m19.500s
sys 0m20.780s
$
Unfortunately the location I need to emit my own I2C command to set framerate (v2 FRM_LENGTH_A register) was inside main loop of raspivid. Even worse, I have not found a signal from GPU code on when GPU is done with sending I2C commands to camera and started capturing video. Because of that I had to usleep(200000) to get into the right spot in time.
Yes, this is a (initial) cruel hack of raspivid -- but with it I can capture 640x480 at 180fps(!!).
More importantly, this RaspiVid.c code location allows to port other raspiraw high framerate features to raspivid (--height, --vinc) allowing for 640x240 capturing at 360(?)fps and 640x120 capturing at 720(?)fps ... with full GPU support.
Because this is a hack, I wanted to have everything in just one place (including needed additional includes and defines):
Code: Select all
pi@raspberrypi2B:~/userland/t/userland $ !diff
diff -c host_applications/linux/apps/raspicam/RaspiVid.c*
*** host_applications/linux/apps/raspicam/RaspiVid.c 2018-02-07 02:27:36.751556483 +0100
--- host_applications/linux/apps/raspicam/RaspiVid.c.orig 2018-02-07 00:32:11.142714109 +0100
***************
*** 2908,2971 ****
// How to handle?
}
- /**
- * raspiraw high framerate stuff here
- *
- * initial cruel hack, but raspivid 640x480 up to 180fps(!) w/o frameskips
- *
- * for now
- * - only for v2 camera
- * - only fps option
- * - no need to do anything up to 120fps, works already
- */
- if (state.bCapturing && (state.framerate > 120))
- {
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <unistd.h>
-
- #define I2C_DEVICE_NAME_LEN 13 // "/dev/i2c-XXX"+NULL
- #define I2C_SLAVE_FORCE 0x0706
-
- #define WRITE_I2C(fd, str) (write(fd, str, sizeof(str)) != sizeof(str))
-
- int fd;
- char i2c_device_name[I2C_DEVICE_NAME_LEN];
-
- if (state.verbose) fprintf(stderr,"Now raspiraw fps ...\n");
-
- // I have no better idea yet how to get past GPU emitted I2C commands
- usleep(200000);
-
- snprintf(i2c_device_name, sizeof(i2c_device_name), "/dev/i2c-%d", state.cameraNum);
-
- fd = open(i2c_device_name, O_RDWR);
- if (!fd)
- {
- vcos_log_error("Couldn't open I2C device");
- goto error;
- }
- if (ioctl(fd, I2C_SLAVE_FORCE, 0x10/*imx219*/) < 0)
- {
- vcos_log_error("Failed to set I2C address");
- goto error;
- }
-
- // values taken from imx219_modes[]
- {
- unsigned line_time_ns = (state.sensor_mode < 6) ? 18904 : 19517;
- unsigned val = 1000000000 / (line_time_ns * state.framerate);
- unsigned char msg[] = {0x01, 0x60, val>>8, val&0xFF};
- if ( WRITE_I2C(fd, msg) )
- {
- vcos_log_error("Failed to write register FRM_LENGTH_A\n");
- goto error;
- }
- }
- close(fd);
- if (state.verbose) fprintf(stderr,"... raspiraw fps done.\n");
- }
-
// In circular buffer mode, exit and save the buffer (make sure we do this after having paused the capture
if(state.bCircularBuffer && !state.bCapturing)
{
--- 2908,2913 ----
pi@raspberrypi2B:~/userland/t/userland $
So what does this code do?
Here is tail of decoded I2C capture from the execution of raspivid command shown further below:
Code: Select all
$ tail 180.csv
1.954188500000000,I2C,0x00 + ACK
1.985222500000000,I2C,Setup Write to [0x20] + ACK
1.985312500000000,I2C,0x01 + ACK
1.985402500000000,I2C,0x60 + ACK
1.985492500000000,I2C,0x01 + ACK
1.985582500000000,I2C,0x1C + ACK
5.032943500000000,I2C,Setup Write to [0x20] + ACK
5.033033500000000,I2C,0x01 + ACK
5.033123500000000,I2C,0x00 + ACK
5.033213500000000,I2C,0x00 + ACK
$
Here is the raspivid command I used, with verbose output, so that you can see the messages emitted from above new code piece as well:
Code: Select all
$ ./build/bin/raspivid -v -md 7 -fps 180 -pts 180.pts -w 640 -h 480 -o t.h264 -t 3000 -ex off -ss 1000 -ag 1.0 -dg 1.0
raspivid Camera App v1.3.12
Width 640, Height 480, filename t.h264
bitrate 17000000, framerate 180, time delay 3000
H264 Profile high
H264 Level 4
H264 Quantisation level 0, Inline headers No
H264 Intra refresh type (null), period -1
Wait method : Simple capture
Initial state 'record'
Preview Yes, Full screen Yes
Preview window 0,0,1024,768
Opacity 255
Sharpness 0, Contrast 0, Brightness 50
Saturation 0, ISO 0, Video Stabilisation No, Exposure compensation 0
Exposure Mode 'off', AWB Mode 'auto', Image Effect 'none'
Flicker Avoid Mode 'off'
Metering Mode 'average', Colour Effect Enabled No with U = 128, V = 128
Rotation 0, hflip No, vflip No
ROI x 0.000000, y 0.000000, w 1.000000 h 1.000000
Camera component done
Encoder component done
Starting component connection stage
Connecting camera preview port to preview input port
Starting video preview
Connecting camera video port to encoder input port
Opening output file "t.h264"
Opening output file "180.pts"
Enabling encoder output port
Now raspiraw fps ...
... raspiraw fps done.
Starting video capture
Finished capture
Closing down
Close down completed, all components disconnected, disabled and destroyed
$
Before we look at the video captured, lets see frame skip+delata analysis.
First the bottom part tells us that there were 6 frames with deltas not matching 180fps. But that is OK, those are frames 2-7 of the video, taken before the new I2C command was executed!
Code: Select all
...
after skip frame indices (middle column)
8296,8296
8296,16592
8296,24888
8296,33184
8296,41480
8295,49775
1% frame skips
$
The initial part of the analysis shows that frame deltas are 5531μs ± 13μs (180fps):
Code: Select all
$ echo "1000000/5531" | bc -ql
180.79913216416561200506
$ ./ptsanalyze 180.pts 0-46-9
creating tstamp.csv
545 tstamps.csv frames were captured at 180fps
frame delta time[us] distribution
1
1 5518
2 5521
1 5525
1 5526
1 5527
3 5528
30 5529
213 5530
236 5531
39 5532
5 5533
1 5534
1 5535
1 5536
2 5540
1 5544
1 8295
5 8296
after skip frame indices (middle column)
...
Summary:
Not looking at the initial 7 frames no frame skips at 180fps!
Here you can find the taken t.h264, uploaded to youtube:
https://www.youtube.com/watch?v=9XdcxUD ... e=youtu.be
Since youtube default framerate is 25fps, the video is played 180/25=7.2 times slowed down. Therefore video length becomes 21s on youtube although only 3s got captured (at 180fps).
I used an eggbeater as "high framerate gadget" this time:
