Skip to content

Instantly share code, notes, and snippets.

@baptx
Last active March 3, 2026 19:45
Show Gist options
  • Select an option

  • Save baptx/7faaaf876ef38db040ce0e25bde41625 to your computer and use it in GitHub Desktop.

Select an option

Save baptx/7faaaf876ef38db040ce0e25bde41625 to your computer and use it in GitHub Desktop.
PinePhone video recording using ffmpeg with preview
#!/usr/bin/env bash
# PinePhone video recording using ffmpeg with preview
# Based on https://gitlab.com/Alaraajavamma/fastvideo
# Video recording requires a recent Linux kernel version like 6.6: https://forum.pine64.org/showthread.php?tid=16539&pid=122700#pid122700
# Video recording with front camera does not seem to be working since Mobian 13.
# Recording will start directly after pressing a record button to not waste time and battery (preview before recording can be done with another app like Megapixels if necessary).
# Recording can be stopped by closing ffmpeg preview window (which will produce errors but still work) or by pressing "q" in the ffmpeg terminal window
# Video recording does not work when using rear camera if Megapixels was closed after switching to front camera (error "Not a video capture device", can be fixed by reopening Megapixels).
# If the camera is still not working, the issue may happen on Megapixels too and it could be a problem during startup that a reboot can fix (checking if the camera preview of Megapixels works after boot can save time)
# There is no autofocus so if we want to read what is displayed for example when getting close to a computer screen, a workaround is to start Megapixels during preview, which will auto-close its GUI but autofocus will work!
#
# For quick access, you can create a file like ~/.local/share/applications/megavideo.desktop with this content (without # at the beginnning of lines, adjust executable path if needed):
# [Desktop Entry]
# Name=MegaVideo
# Exec=/opt/megavideo/pinephone_record_with_preview_gui.sh
# Terminal=false
# Icon=camera-video
# Type=Application
# X-Purism-FormFactor=Workstation;Mobile;
#
# And this content in /opt/megavideo/pinephone_record_with_preview_gui.sh:
# yad --title="Video recording" --text="Recording will start directly after button press" --form --field="Record rear camera":fbtn "/opt/megavideo/pinephone_record_with_preview.sh" --field="Record front camera":fbtn "/opt/megavideo/pinephone_record_with_preview.sh front" --buttons-layout=center --button="Quit"
WIDTH=1280
HEIGHT=720
FPS=20 # using lower FPS to avoid crashing the phone for recording videos with preview (crashed with 24 FPS or above at around 2 minutes but did not crash with 20 FPS when recording more than 5 minutes)
# enable default profile, unmute microphone audio and set volume to 100% in case it was changed (for example with pavucontrol)
pactl set-card-profile 0 HiFi
amixer set Capture cap 100%
CAMERA="ov5640"
SECONDARY_CAMERA="gc2145"
if [ "$1" == "front" ]; then
CAMERA="gc2145"
SECONDARY_CAMERA="ov5640"
fi
MATCH="$(media-ctl -d1 -p | grep sun6i-csi)"
if [ "$MATCH" ]; then
DEVICE="1"
else
DEVICE="0"
fi
MAIN_SENSOR="$(media-ctl -d$DEVICE -p | awk '/: '"$CAMERA"'/ {print "\"" $4, $5 "\""}')"
SECONDARY_SENSOR="$(media-ctl -d$DEVICE -p | awk '/: '"$SECONDARY_CAMERA"'/ {print "\"" $4, $5 "\""}')"
VIDEO_SOURCE="$(media-ctl -d$DEVICE -p | awk '/\/dev\/video/ {print $NF}')"
media-ctl -d$DEVICE -l"$SECONDARY_SENSOR:0->1:0[0],$MAIN_SENSOR:0->1:0[1]"
media-ctl -d$DEVICE -V"$MAIN_SENSOR:0[fmt:UYVY8_2X8/${WIDTH}x${HEIGHT}@1/$FPS]"
# Use same date format as Megapixels app based on ISO 8601
TIMENOW="VID"$(date +%Y%m%d%H%M%S)
# libx264 recording without preview
#ffmpeg -input_format yuv420p -s ${WIDTH}x${HEIGHT} -f video4linux2 -thread_queue_size 4096 -i $VIDEO_SOURCE -f pulse -thread_queue_size 256 -i alsa_input.platform-sound.HiFi__hw_PinePhone_0__source -c:a aac -c:v libx264 -preset ultrafast -qp 23 ~/Videos/$TIMENOW.mp4
# mjpeg configuration (does not work for front camera: "No JPEG data found in image")
# https://www.reddit.com/r/PINE64official/comments/olyqor/how_i_record_video_on_my_pinephone_in_tolerable/
# https://www.reddit.com/r/pinephone/comments/p7eg2c/video_recording_using_gstreamer_on_the_pinephone/
#media-ctl -d$DEVICE --set-v4l2 "$MAIN_SENSOR:0[fmt:JPEG_1X8/${WIDTH}x${HEIGHT}@1/$FPS]"
#v4l2-ctl --device $VIDEO_SOURCE --set-fmt-video="width=$WIDTH,height=$HEIGHT,pixelformat=JPEG"
# mjpeg recording with preview
#ffmpeg -f v4l2 -framerate 30 -video_size ${WIDTH}x${HEIGHT} -input_format mjpeg -i $VIDEO_SOURCE -f pulse -i alsa_input.platform-sound.HiFi__hw_PinePhone_0__source -c:a pcm_s16le -c:v mjpeg -b:v 64000k ~/Videos/$TIMENOW.avi -map 0:v -vf "format=yuv420p" -f xv display
# attempt to rotate recording and preview did not work: https://raspberrypi.stackexchange.com/questions/111713/is-there-a-way-to-rotate-the-cameras-image-at-the-driver-level-not-processing/114253#114253
#if [ "$2" == "portrait" ]; then
# v4l2-ctl --device $VIDEO_SOURCE --set-ctrl=rotate=90
#fi
# libx264 recording with preview (delay in preview at 30 or 24 FPS but 20 FPS ok: https://superuser.com/questions/343586/how-to-display-and-capture-webcam-stream-at-the-same-time/1551806#1551806)
# if 20 FPS was configured in the script, it may result in an FPS of around 15 FPS but the video should be smooth enough
# use a terminal like kgx to see time spent recording and if there are ffmpeg errors after recording (other than usual errors when ending stream by closing ffmpeg preview window)
# gnome-session-inhibit command is needed to prevent locking screen when recording (if using ffmpeg command only instead of a player like ffplay)
# crf should be better than qp (crf default value is 23: https://trac.ffmpeg.org/wiki/Encode/H.264)
# https://stackoverflow.com/questions/40668616/whats-the-difference-with-crf-and-qp-in-ffmpeg
# https://www.reddit.com/r/AV1/comments/omflyh/using_libsvtav1_what_qp_value_is_considered/
kgx -e gnome-session-inhibit --inhibit idle ffmpeg -input_format yuv420p -s ${WIDTH}x${HEIGHT} -f video4linux2 -thread_queue_size 4096 -i $VIDEO_SOURCE -f pulse -thread_queue_size 256 -i alsa_input.platform-sound.HiFi__hw_PinePhone_0__source -c:a aac -c:v libx264 -preset ultrafast ~/Videos/$TIMENOW.mp4 -f xv display
# libx264 recording with preview (no delay in preview but needs 20 FPS recording and 5 FPS preview with latest v4l2loopback: https://askubuntu.com/questions/165727/is-it-possible-for-two-processes-to-access-the-webcam-at-the-same-time/1244152#1244152)
# modprobe commands with root password are not needed when adding "options v4l2loopback exclusive_caps=1 video_nr=4" in a file like /etc/modprobe.d/dkms.conf and "v4l2loopback" in /etc/modules-load.d/modules.conf or /etc/modules (https://unix.stackexchange.com/questions/680689/load-kernel-module-at-boot-time-with-options/680698#680698)
# use video_nr=4 if the first video device that does not exist yet is /dev/video4 and so on
# since Mobian 13, a command like "sudo modprobe v4l2loopback devices=2" should be executed manually after boot instead of using startup files if there is an error "Error submitting a packet to the muxer: Invalid argument"
# if you have an error "Module v4l2loopback not found in directory" after upgrading to Mobian 13, you may need to replace old kernel headers with the new ones, e.g: sudo apt purge linux-headers-6.6-sunxi64; sudo apt install linux-headers-6.12-sunxi64; sudo apt reinstall v4l2loopback-dkms
# quit and recording functions are not used if not using v4l2loopback
quit() {
# don't kill the ffmpeg source PID after the sleep in case we want to record another video before the previous encoding has finished (not needed anymore)
pkill -nf "libx264 -preset ultrafast -fps_mode vfr $HOME/Videos/$TIMENOW.mp4" # kill the current ffmpeg recording process to avoid killing new recordings (-n parameter to match newest process ffmpeg instead of kgx terminal)
pkill -f 'rawvideo -pix_fmt yuv420p /dev/video4'
#killall ffmpeg
#killall yad # close GUI automatically to know when the recording is finished is not needed with the encoding preview since closing it ends the recording (killing all ffmpeg and yad processes is ok as long as you don't have others running at the same time)
#sudo modprobe -r v4l2loopback
}
recording() {
# the parameter "-fps_mode vfr (which replaces deprecated parameter "-vsync vfr" https://superuser.com/questions/460332/how-do-set-output-framerate-same-as-source-in-ffmpeg/1514949#1514949) is used to avoid warning "more than 1000 frames duplicated", to avoid encoding delay and reduce file size
# thread_queue_size for audio increased to 4096 (2048 and values below were not enough) due to error "Thread message queue blocking; consider raising the thread_queue_size option" that appeared sometimes for example when typing on a keyboard close to the microphone and moving the camera fast or walking (default value was 8)
kgx -e ffmpeg -input_format yuv420p -s ${WIDTH}x${HEIGHT} -f video4linux2 -thread_queue_size 4096 -i /dev/video4 -f pulse -thread_queue_size 4096 -i alsa_input.platform-sound.HiFi__hw_PinePhone_0__source -c:a aac -c:v libx264 -preset ultrafast -fps_mode vfr ~/Videos/$TIMENOW.mp4 &
ffplay /dev/video5
quit
}
#sudo modprobe -r v4l2loopback # can fix issue "Some buffers are still owned by the caller on close"
#sudo modprobe v4l2loopback exclusive_caps=1 video_nr=4 devices=2 # (devices=2 may be needed since Mobian 13 to avoid "Device or resource busy" error: https://unix.stackexchange.com/questions/343832/how-to-read-a-webcam-that-is-already-used-by-a-background-capture/343837#343837 / https://github.com/v4l2loopback/v4l2loopback/issues/566#issuecomment-2007587016)
# force 5 FPS in preview to have a smooth recording when using 2 devices with v4l2loopback
#ffmpeg -i $VIDEO_SOURCE -f v4l2 -codec:v rawvideo -pix_fmt yuv420p /dev/video4 -f v4l2 -codec:v rawvideo -pix_fmt yuv420p -vf "fps=5" /dev/video5 &
#sleep 1 # avoid error "Not a video capture device" (does not seem needed anymore)
#ffplay -vf "drawtext=text='Close window to start recording':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2" /dev/video5 # preview and start recording when the first preview window is closed (https://stackoverflow.com/questions/17623676/text-on-video-ffmpeg/17624103#17624103)
#recording
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment