ffmpy icon indicating copy to clipboard operation
ffmpy copied to clipboard

how to screen capture with ffmpy

Open ReenigneArcher opened this issue 2 years ago • 3 comments

I am attempting to use ffmpy and ffmpeg to screen capture the desktop, then send the frames to another device.

from ffmpy import FFmpeg
import numpy as np
import subprocess

ff = FFmpeg(
    executable=os.path.join('ffmpeg', 'bin', 'ffmpeg.exe'),
    inputs={'desktop': '-f gdigrab -framerate 30'},
    outputs={'pipe:1': '-c:v h264'}
)

pipe = ff.run(stdout=subprocess.PIPE)

while True:
    # read 1920*1080*3 bytes (= 1 frame)
    raw_image = pipe.stdout.read(1920 * 1080 * 3)
    # transform the byte read into a numpy array
    frame = np.fromstring(raw_image, dtype='uint8')
    # throw away the data in the pipe's buffer.
    pipe.stdout.flush()

I get the following:

(venv) C:\Users\ReenigneArcher\Documents\GitHub\RetroArcher\py_stream>python test.py
ffmpeg version n5.0.1-5-g240d82f26e-20220626 Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 11.2.0 (crosstool-NG 1.24.0.533_681aaef)
  configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --disable-w32threads
 --enable-pthreads --enable-iconv --enable-libxml2 --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-lzma --enable-fontconfig --enable-libvorbis --enable-opencl --disable-libpulse --enable-libvmaf --disa
ble-libxcb --disable-xlib --enable-amf --enable-libaom --enable-libaribb24 --enable-avisynth --enable-libdav1d --enable-libdavs2 --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --enable-frei0r --enable-libgme --enable-l
ibass --enable-libbluray --enable-libmp3lame --enable-libopus --enable-librist --enable-libtheora --enable-libvpx --enable-libwebp --enable-lv2 --enable-libmfx --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopen
h264 --enable-libopenjpeg --enable-libopenmpt --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --disable-libdrm --d
isable-vaapi --enable-libvidstab --enable-vulkan --enable-libshaderc --enable-libplacebo --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --enable-libzvbi --extra-cflags=-DLIBTWOLAME_STATIC --extra-cxxflags= --extra-ldflags=-pthread --extra-ldexeflags= --extra-libs=-lgomp --extra-version=20220626
  libavutil      57. 17.100 / 57. 17.100
  libavcodec     59. 18.100 / 59. 18.100
  libavformat    59. 16.100 / 59. 16.100
  libavdevice    59.  4.100 / 59.  4.100
  libavfilter     8. 24.100 /  8. 24.100
  libswscale      6.  4.100 /  6.  4.100
  libswresample   4.  3.100 /  4.  3.100
  libpostproc    56.  3.100 / 56.  3.100
[gdigrab @ 000002c5622b2980] Capturing whole desktop as 1920x1080x32 at (0,0)
[gdigrab @ 000002c5622b2980] Stream #0: not enough frames to estimate rate; consider increasing probesize
Input #0, gdigrab, from 'desktop':
  Duration: N/A, start: 1656372396.709033, bitrate: 1990668 kb/s
  Stream #0:0: Video: bmp, bgra, 1920x1080, 1990668 kb/s, 30 fps, 1000k tbr, 1000k tbn
[NULL @ 000002c560479080] Unable to find a suitable output format for 'pipe:1'
pipe:1: Invalid argument
Traceback (most recent call last):
  File "C:\Users\ReenigneArcher\Documents\GitHub\RetroArcher\py_stream\test.py", line 31, in <module>
    pipe = ff.run(stdout=subprocess.PIPE)
  File "C:\Users\ReenigneArcher\Documents\GitHub\RetroArcher\py_stream\venv\lib\site-packages\ffmpy.py", line 106, in run
    raise FFRuntimeError(self.cmd, self.process.returncode, out[0], out[1])
ffmpy.FFRuntimeError: `ffmpeg5\bin\ffmpeg.exe -f gdigrab -framerate 30 -i desktop -c:v h264 pipe:1` exited with status 1

STDOUT:


STDERR:

This command works in command line.

ffmpeg -f gdigrab -framerate 30 -i desktop output.mkv

ReenigneArcher avatar Jun 27 '22 23:06 ReenigneArcher

Looks like the command is not correct. The equivalent of what ffmpy is trying to run is ffmpeg5\bin\ffmpeg.exe -f gdigrab -framerate 30 -i desktop -c:v h264 pipe:1. And it actually says that in the output:

[NULL @ 000002c560479080] Unable to find a suitable output format for 'pipe:1'
pipe:1: Invalid argument

Try specifying the output format, like so: ffmpeg5\bin\ffmpeg.exe -f gdigrab -framerate 30 -i desktop -c:v h264 -f avi pipe:1

Ch00k avatar Jun 29 '22 14:06 Ch00k

Okay, thanks for taking the time to answer! Adding -f avi does get it to pipe the output to stdout. Any idea why avi works, but others like mp4 and mkv do not? Do you have any good references on ffmpeg command line? A lot of this stuff is lacking in the ffmpeg documentation.

Also, I want to read the frames in real time. I guess ffmpy doesn't have a subprocess.popen equivalent? The run function is blocking. It's okay if it doesn't I can just switch to the build in subprocess.

ReenigneArcher avatar Jun 29 '22 22:06 ReenigneArcher

avi was just an example of how you should set an output format. Not sure why mp4 or mkv don't work for you, but there is probably a hint to that in ffmpeg's output if you try to run such a command in the terminal.

As for the documentation, in my opinion the best source is https://ffmpeg.org/ffmpeg-all.html

The FFmpeg.run is indeed blocking, but I guess you could try running your frame capturing code in a separate thread.

Ch00k avatar Jun 30 '22 05:06 Ch00k