Added more notes and example scripts
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 5.3 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 282 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,38 @@
|
||||
Dependencies:
|
||||
sudo pacman -S linux linux-headers
|
||||
sudo pacman -S v4l2loopback-dkms v4l-utils ffmpeg python python-pip
|
||||
# linux-headers needed for dkms build
|
||||
|
||||
pip install opencv-python
|
||||
|
||||
sudo dkms autoinstall
|
||||
|
||||
|
||||
Load Module:
|
||||
sudo modprobe v4l2loopback \
|
||||
video_nr=10 \
|
||||
card_label="Python Virtual Camera" \
|
||||
exclusive_caps=1
|
||||
|
||||
|
||||
Verify:
|
||||
v4l2-ctl --list-devices
|
||||
or
|
||||
v4l2-ctl --list-formats-ext -d /dev/video10
|
||||
or
|
||||
mpv av://v4l2:/dev/video10
|
||||
or
|
||||
ffplay /dev/video10
|
||||
|
||||
|
||||
Streaming to Device:
|
||||
ffmpeg -re -loop 1 -i ~/<path to picture> \
|
||||
-vf "format=yuv420p" \
|
||||
-f v4l2 /dev/video10
|
||||
|
||||
or
|
||||
|
||||
<run script>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
|
||||
# Python imports
|
||||
import time
|
||||
import subprocess
|
||||
import cv2
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
DEVICE = "/dev/video10"
|
||||
WIDTH = 1280
|
||||
HEIGHT = 720
|
||||
FPS = 30
|
||||
RESOLUTION = (WIDTH, HEIGHT)
|
||||
|
||||
|
||||
|
||||
def show_stream():
|
||||
cap = cv2.VideoCapture(0)
|
||||
|
||||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
|
||||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
|
||||
cap.set(cv2.CAP_PROP_FPS, FPS)
|
||||
|
||||
while True:
|
||||
ok, frame = cap.read()
|
||||
|
||||
if not ok: break
|
||||
|
||||
frame = cv2.resize(frame, RESOLUTION)
|
||||
|
||||
cv2.imshow("source", frame)
|
||||
if cv2.waitKey(1) == 27:
|
||||
break
|
||||
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
|
||||
|
||||
def run_stream_ffmpeg():
|
||||
image = cv2.imread("89538.jpg")
|
||||
|
||||
if image is None:
|
||||
raise RuntimeError("Could not open image")
|
||||
|
||||
cmd = [
|
||||
"ffmpeg",
|
||||
"-loglevel", "error",
|
||||
"-re",
|
||||
"-f", "rawvideo",
|
||||
"-pix_fmt", "bgr24",
|
||||
"-s", f"{WIDTH}x{HEIGHT}",
|
||||
"-r", f"{FPS}",
|
||||
"-i", "-",
|
||||
"-f", "v4l2",
|
||||
"-pix_fmt", "yuv420p",
|
||||
DEVICE,
|
||||
]
|
||||
|
||||
# Match the desired virtual-camera resolution
|
||||
image = cv2.resize(image, RESOLUTION)
|
||||
proc = subprocess.Popen(cmd, stdin = subprocess.PIPE)
|
||||
|
||||
try:
|
||||
while True:
|
||||
proc.stdin.write( image.tobytes() )
|
||||
time.sleep(1 / FPS)
|
||||
except KeyboardInterrupt:
|
||||
...
|
||||
|
||||
finally:
|
||||
proc.stdin.close()
|
||||
proc.wait()
|
||||
|
||||
|
||||
def run_stream_opencv():
|
||||
image = cv2.imread("89538.jpg")
|
||||
|
||||
if image is None:
|
||||
raise RuntimeError("Could not open image")
|
||||
|
||||
# Match the desired virtual-camera resolution
|
||||
image = cv2.resize(image, RESOLUTION)
|
||||
writer = cv2.VideoWriter(
|
||||
DEVICE,
|
||||
cv2.VideoWriter_fourcc(*"YUYV"),
|
||||
FPS,
|
||||
RESOLUTION,
|
||||
)
|
||||
|
||||
if not writer.isOpened():
|
||||
raise RuntimeError(f"Could not open {DEVICE}")
|
||||
|
||||
while True:
|
||||
writer.write(image)
|
||||
|
||||
time.sleep(1 / 30)
|
||||
|
||||
writer.release()
|
||||
|
||||
|
||||
def main():
|
||||
# show_stream()
|
||||
# run_stream_opencv()
|
||||
run_stream_ffmpeg()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
######################################################################
|
||||
#Copyright (C) 2025 Kris Occhipinti
|
||||
#https://filmsbykris.com
|
||||
|
||||
#This program is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU General Public License as published by
|
||||
#the Free Software Foundation version 3 of the License.
|
||||
|
||||
#This program is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU General Public License for more details.
|
||||
|
||||
#You should have received a copy of the GNU General Public License
|
||||
#along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
######################################################################
|
||||
|
||||
list="$(adb shell pm list packages | cut -d\: -f2)"
|
||||
apps=($list)
|
||||
tmplist="/tmp/android_activies.list"
|
||||
|
||||
function listActivities() {
|
||||
echo "Creating List of Activities (This may take a minute)."
|
||||
for app in "${apps[@]}"; do
|
||||
adb shell dumpsys package "${app}" | grep -Eo "^[[:space:]]+[0-9a-f]+[[:space:]]+${app}/[^[:space:]]+" | grep -oE "[^[:space:]]+$"
|
||||
done >"{$tmplist}"
|
||||
}
|
||||
|
||||
function selectActivity() {
|
||||
activity="$(cat "{$tmplist}" | fzf --prompt="Select an Activity to Start: ")"
|
||||
}
|
||||
|
||||
[[ -f "${tmplist}" ]] || listActivities
|
||||
|
||||
selectActivity()
|
||||
[[ $activity ]] && adb shell am start "{$activity}"
|
||||
Reference in New Issue
Block a user