Python bindings for FFmpeg - with almost all filters support, even `gltransition` filter.
Project description
FFmpeg Generator
A FFmpeg command generator and actuator.
Python bindings for FFmpeg - with almost all filters support, even gltransition
filter.
- FFmpeg Generator
- Overview
- Installation
- Documents
- GLTransition Filter
- Video Sources
- More Examples
- Get Stream Info
- Play a Video
- Generate Thumbnail for Video
- Convert Video to Numpy Array
- Read Single Video Frame as JPEG
- Convert Sound to Raw PCM Audio
- Assemble Video from Sequence of Frames
- Audio/Video Pipeline
- Mono to Stereo with Offsets and Video
- Process Frames
- FaceTime Webcam Input
- Stream from a Local Video to HTTP Server
- Stream from RTSP Server to TCP Socket
- Special Thanks
Overview
This project is based on ffmpeg-python
. But rewrite all.
- support video sources
- support almost all filters
- support FFplay&FFprobe
- enable cuda hwaccel by default
Installation
pip install -U ffmpeg-generator
Documents
FFmpeg comes with more than 450 audio and video media filters. It is recommended to read the official documentation.
Or read my study notes, plan to demonstrate all the filters, but written in Chinese. Not all done yet.
GLTransition Filter
from ffmpeg import avfilters, input, vfilters, vtools
from ffmpeg.transitions import GLTransition, GLTransitionAll
from tests import data
# OpenGL Transition
"""Combine two videos with transition effects."""
for e in GLTransitionAll:
vtools.concat_2_videos_with_gltransition(data.TEST_OUTPUTS_DIR / (e + ".mp4"),
data.SHORT0, data.SHORT1, offset=1,
duration=2, source=eval("transitions." + e))
"""Combine multiple videos with transition effects."""
in0 = input(data.SHORT0).video
in1 = input(data.SHORT1).video
in2 = input(data.SHORT2).video
in0_split = in0.split()
in0_0, in0_1 = in0_split[0], in0_split[1]
in0_0 = in0_0.trim(start=0, end=3)
in0_1 = in0_1.trim(start=3, end=4).setpts()
in1_split = in1.split()
in1_0, in1_1 = in1_split[0], in1_split[1]
in1_0 = in1_0.trim(start=0, end=3)
in1_1 = in1_1.trim(start=3, end=4).setpts()
in2_split = in2.split()
in2_0, in2_1 = in2_split[0], in2_split[1]
in2_0 = in2_0.trim(start=0, end=3)
in2_1 = in2_1.trim(start=3, end=4).setpts()
gl0_1 = vfilters.gltransition(in0_1, in1_0, source=GLTransition.Angular)
gl1_2 = vfilters.gltransition(in1_1, in2_0, source=GLTransition.ButterflyWaveScrawler)
# transition
_ = avfilters.concat(in0_0, gl0_1, gl1_2, in2_1).output(
data.TEST_OUTPUTS_DIR / "3_transition.mp4",
vcodec="libx264",
v_profile="baseline",
preset="slow",
movflags="faststart",
pixel_format="yuv420p",
).run()
# transition + image watermark
v_input = avfilters.concat(in0_0, gl0_1, gl1_2, in2_1)
i_input = input(data.I1).scale(w=100, h=100)
v_input.overlay(i_input, x=30, y=30).output(
data.TEST_OUTPUTS_DIR / "3_transition_image.mp4",
vcodec="libx264",
v_profile="baseline",
preset="slow",
movflags="faststart",
pixel_format="yuv420p",
).run()
# transition + image watermark + text watermark
v_input = avfilters.concat(in0_0, gl0_1, gl1_2, in2_1). \
drawtext(text="Watermark", x=150, y=150, fontsize=36, fontfile=data.FONT1)
i_input = input(data.I1).scale(w=100, h=100)
v_input.overlay(i_input, x=30, y=30).output(
data.TEST_OUTPUTS_DIR / "3_transition_image_text.mp4",
vcodec="libx264",
v_profile="baseline",
preset="slow",
movflags="faststart",
pixel_format="yuv420p",
).run()
# transition + image watermark + text watermark + music
v_input = avfilters.concat(in0_0, gl0_1, gl1_2, in2_1). \
drawtext(text="Watermark", x=150, y=150, fontsize=36, fontfile=data.FONT1)
i_input = input(data.I1).scale(w=100, h=100)
a_input = input(data.A1).audio
v_input.overlay(i_input, x=30, y=30).output(
a_input,
data.TEST_OUTPUTS_DIR / "3_transition_image_text_music.mp4",
acodec="copy",
vcodec="libx264",
v_profile="baseline",
shortest=True,
preset="slow",
movflags="faststart",
pixel_format="yuv420p",
).run()
Video Sources
Play by FFplay
from ffmpeg import run_ffplay
_ = run_ffplay("allrgb", f="lavfi")
_ = run_ffplay("allyuv", f="lavfi")
_ = run_ffplay("color=c=red@0.2:s=1600x900:r=10", f="lavfi")
_ = run_ffplay("haldclutsrc", f="lavfi")
_ = run_ffplay("pal75bars", f="lavfi")
_ = run_ffplay("allyuv", f="lavfi")
_ = run_ffplay("allyuv", f="lavfi")
_ = run_ffplay("rgbtestsrc=size=900x600:rate=60", f="lavfi")
_ = run_ffplay("smptebars=size=900x600:rate=60", f="lavfi")
_ = run_ffplay("smptehdbars=size=900x600:rate=60", f="lavfi")
_ = run_ffplay("testsrc=size=900x600:rate=60", f="lavfi")
_ = run_ffplay("testsrc2=s=900x600:rate=60", f="lavfi")
_ = run_ffplay("yuvtestsrc=s=900x600:rate=60", f="lavfi")
Preview by FFmpeg
from ffmpeg import input_source
_ = input_source("testsrc", size="900x600", rate=60).output(preview=True).run_async()
_ = input_source("testsrc2", size="900x600", rate=60).output(preview=True).run_async()
Save Video from video sources
from ffmpeg import input_source
_ = input_source("testsrc", size="900x600", rate=60, duration=30).output("source_testsrc.mp4").run()
More Examples
Get Stream Info
from ffmpeg import FFprobe
meta = FFprobe("path/to/file")
# all stream
print(meta.metadata)
# video stream
print(meta.video)
print(meta.video_duration)
print(meta.video_scale)
# audio stream
print(meta.audio)
print(meta.audio_duration)
Play a Video
from ffmpeg import ffplay_video
from tests import data
ffplay_video(data.V1, vf='transpose=1')
ffplay_video(data.V1, vf='hflip')
ffplay_video(data.V1, af='atempo=2')
ffplay_video(data.V1, vf='setpts=PTS/2')
ffplay_video(data.V1, vf='transpose=1,setpts=PTS/2', af='atempo=2')
Generate Thumbnail for Video
from ffmpeg import vtools
vtools.generate_video_thumbnail(src="src", dst="dst", start_position=3, width=400, height=-1)
Convert Video to Numpy Array
from ffmpeg import vtools
vtools.convert_video_to_np_array(src="src")
Read Single Video Frame as JPEG
from ffmpeg import vtools
vtools.read_frame_as_jpeg(src="src", frame=10)
Convert Sound to Raw PCM Audio
from ffmpeg import atools
atools.convert_audio_to_raw_pcm(src="src")
Assemble Video from Sequence of Frames
from ffmpeg import vtools
# on Linux
vtools.assemble_video_from_images('/path/to/jpegs/*.jpg', pattern_type='glob', frame_rate=25)
# on Windows
vtools.assemble_video_from_images('/path/to/jpegs/%02d.jpg', pattern_type=None, frame_rate=25)
With additional filtering:
import ffmpeg
ffmpeg.input('/path/to/jpegs/*.jpg', pattern_type='glob', framerate=25). \
filter('deflicker', mode='pm', size=10). \
filter('scale', size='hd1080', force_original_aspect_ratio='increase'). \
output('movie.mp4', crf=20, preset='slower', movflags='faststart', pix_fmt='yuv420p'). \
view(save_path='filter_graph').run()
Audio/Video Pipeline
import ffmpeg
from ffmpeg import avfilters
in1 = ffmpeg.input("input.mp4")
in2 = ffmpeg.input("input.mp4")
v1 = in1.video.hflip()
a1 = in2.audio
v2 = in2.video.reverse().hue(s=0)
a2 = in2.audio.areverse().aphaser()
joined = avfilters.concat(v1, a1, v2, a2, v=1, a=1).Node
v3 = joined[0]
a3 = joined[1].volume(0.8)
v3.output(a3, 'v1_v2_pipeline.mp4').run()
Mono to Stereo with Offsets and Video
import ffmpeg
from ffmpeg import afilters
from tests import data
input_video = ffmpeg.input(data.V1)
audio_left = ffmpeg.input(data.A1).atrim(start=15).asetpts("PTS-STARTPTS")
audio_right = ffmpeg.input(data.A1).atrim(start=10).asetpts("PTS-STARTPTS")
afilters.join(audio_left, audio_right, inputs=2, channel_layout="stereo"). \
output(input_video.video, "stereo_video.mp4", shortest=None, vcodec="copy").run()
Process Frames
- Decode input video with ffmpeg
- Process each video frame with python
- Encode output video with ffmpeg
import subprocess
import numpy as np
from ffmpeg import constants, FFprobe, input, settings
from tests import data
settings.CUDA_ENABLE = False
def ffmpeg_input_process(src):
return input(src).output(constants.PIPE, format="rawvideo",
pixel_format="rgb24").run_async(pipe_stdout=True)
def ffmpeg_output_process(dst, width, height):
return input(constants.PIPE, format="rawvideo", pixel_format="rgb24",
width=width, height=height).output(dst, pixel_format="yuv420p"). \
run_async(pipe_stdin=True)
def read_frame_from_stdout(process: subprocess.Popen, width, height):
frame_size = width * height * 3
input_bytes = process.stdout.read(frame_size)
if not input_bytes:
return
assert len(input_bytes) == frame_size
return np.frombuffer(input_bytes, np.uint8).reshape([height, width, 3])
def process_frame_simple(frame):
# deep dream
return frame * 0.3
def write_frame_to_stdin(process: subprocess.Popen, frame):
process.stdin.write(frame.astype(np.uint8).tobytes())
def run(src, dst, process_frame):
width, height = FFprobe(src).video_scale
input_process = ffmpeg_input_process(src)
output_process = ffmpeg_output_process(dst, width, height)
while True:
input_frame = read_frame_from_stdout(input_process, width, height)
if input_frame is None:
break
write_frame_to_stdin(output_process, process_frame(input_frame))
input_process.wait()
output_process.stdin.close()
output_process.wait()
if __name__ == '__main__':
run(data.SHORT0, data.TEST_OUTPUTS_DIR / "process_frame.mp4", process_frame_simple)
FaceTime Webcam Input
import ffmpeg
def facetime():
ffmpeg.input("FaceTime", format="avfoundation",
pixel_format="uyvy422", framerate=30). \
output("facetime.mp4", pixel_format="yuv420p", frame_size=100).run()
Stream from a Local Video to HTTP Server
from ffmpeg import input
input("video.mp4").output("http://127.0.0.1:8080",
codec="copy", # use same codecs of the original video
listen=1, # enables HTTP server
f="flv").\
with_global_args("-re").\
run() # argument to act as a live stream
To receive the video you can use ffplay in the terminal:
ffplay -f flv http://localhost:8080
Stream from RTSP Server to TCP Socket
import socket
from ffmpeg import input
server = socket.socket()
process = input('rtsp://%s:8554/default').\
output('-', format='h264').\
run_async(pipe_stdout=True)
while process.poll() is None:
packet = process.stdout.read(4096)
try:
server.send(packet)
except socket.error:
process.stdout.close()
process.wait()
break
Special Thanks
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
ffmpeg-generator-1.0.0.tar.gz
(48.7 kB
view details)
File details
Details for the file ffmpeg-generator-1.0.0.tar.gz
.
File metadata
- Download URL: ffmpeg-generator-1.0.0.tar.gz
- Upload date:
- Size: 48.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/49.2.1 requests-toolbelt/0.9.1 tqdm/4.47.0 CPython/3.8.8
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | c01ff8e0819f1abafe44bd74cca6a385a3ea7d739660059299eb9a7147d620b4 |
|
MD5 | 82dd2bd0360ef28574dda80c30f4be1d |
|
BLAKE2b-256 | 7afc630cca75f50566e7c67fee69a007ae0f6837451a031e3101525965abdb35 |