🌐
Readthedocs
python-ffmpeg.readthedocs.io › en › stable › examples › asynchronous-listeners
Asynchronous listeners - python-ffmpeg - Read the Docs
import asyncio from ffmpeg import Progress from ffmpeg.asyncio import FFmpeg async def main(): ffmpeg = ( FFmpeg() .option("y") .input("input.mov") .output( "output.mp4", codec="copy", ) ) @ffmpeg.on("progress") async def on_progress(progress: Progress): await asyncio.sleep(1) print(progress) @ffmpeg.on("completed") def on_completed(): print("Completed") await ffmpeg.execute() if __name__ == "__main__": asyncio.run(main())
🌐
PyPI
pypi.org › project › asyncffmpeg
asyncffmpeg · PyPI
This package supports FFmpeg asynchronously invoke with async / await pattern wrapping ffmpeg.run_async() of ffmpeg-python and returned subprocess.Popen.
      » pip install asyncffmpeg
    
Published   Feb 24, 2026
Version   1.3.1
🌐
GitHub
github.com › jonghwanhyeon › python-ffmpeg
GitHub - jonghwanhyeon/python-ffmpeg: A python binding for FFmpeg which provides sync and async APIs · GitHub
from ffmpeg import FFmpeg def main(): ffmpeg = ( FFmpeg() .option("y") .input("input.mp4") .output( "output.mp4", {"codec:v": "libx264"}, vf="scale=1280:-1", preset="veryslow", crf=24, ) ) ffmpeg.execute() if __name__ == "__main__": main() import asyncio from ffmpeg.asyncio import FFmpeg async def main(): ffmpeg = ( FFmpeg() .option("y") .input("input.mp4") .output( "output.mp4", {"codec:v": "libx264"}, vf="scale=1280:-1", preset="veryslow", crf=24, ) ) await ffmpeg.execute() if __name__ == "__main__": asyncio.run(main())
Starred by 382 users
Forked by 52 users
Languages   Python
🌐
PyPI
pypi.org › project › ffmpeg-asyncio
ffmpeg-asyncio · PyPI
May 18, 2024 - A fork of the excellent python-ffmpeg binding for FFmpeg, updated for native async API support only.
      » pip install ffmpeg-asyncio
    
Published   Jul 09, 2024
Version   0.1.3
🌐
Readthedocs
python-ffmpeg.readthedocs.io
python-ffmpeg
from ffmpeg import FFmpeg def main(): ffmpeg = ( FFmpeg() .option("y") .input("input.mp4") .output( "output.mp4", {"codec:v": "libx264"}, vf="scale=1280:-1", preset="veryslow", crf=24, ) ) ffmpeg.execute() if __name__ == "__main__": main() import asyncio from ffmpeg.asyncio import FFmpeg async def main(): ffmpeg = ( FFmpeg() .option("y") .input("input.mp4") .output( "output.mp4", {"codec:v": "libx264"}, vf="scale=1280:-1", preset="veryslow", crf=24, ) ) await ffmpeg.execute() if __name__ == "__main__": asyncio.run(main())
🌐
FFmpeg Python
kkroening.github.io › ffmpeg-python
ffmpeg-python: Python bindings for FFmpeg — ffmpeg-python documentation
process = ( ffmpeg .input('pipe:', format='rawvideo', pix_fmt='rgb24', s='{}x{}'.format(width, height)) .output(out_filename, pix_fmt='yuv420p') .overwrite_output() .run_async(pipe_stdin=True) ) process.communicate(input=input_data)
🌐
GitHub
github.com › kkroening › ffmpeg-python › issues › 200
Asyncio support async/await · Issue #200 · kkroening/ffmpeg-python
May 4, 2019 - process = await ( ffmpeg .input('input.mp4') .output('pipe:', format='rawvideo', pix_fmt='rgb24')['v'] .run_asyncio(pipe_stdout=True, quiet=False) ) while True: frame_bytes = await process.stdout.read(video_frame_size) if len(frame_bytes) == 0: break await process.wait()
Author   akolpakov
🌐
Stack Overflow
stackoverflow.com › questions › 65747723 › run-ffmpeg-in-an-async-subprocess-then-kill-after-condition-complete
python - Run FFMPEG in an Async Subprocess then Kill after condition complete? - Stack Overflow
In this example, and most examples using process.terminate() and process.kill(), the process ends abruptly without letting ffmpeg do a clean exit. Attempting to add await to process throws an error since it cannot be awaited. ... process = await asyncio.create_subprocess_shell( command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE )
Find elsewhere
🌐
Readthedocs
python-ffmpeg.readthedocs.io › en › latest › examples › asynchronous-listeners
Asynchronous listeners - python-ffmpeg
import asyncio from ffmpeg import Progress from ffmpeg.asyncio import FFmpeg async def main(): ffmpeg = ( FFmpeg() .option("y") .input("input.mov") .output( "output.mp4", codec="copy", ) ) @ffmpeg.on("progress") async def on_progress(progress: Progress): await asyncio.sleep(1) print(progress) @ffmpeg.on("completed") def on_completed(): print("Completed") await ffmpeg.execute() if __name__ == "__main__": asyncio.run(main())
🌐
GitHub
github.com › regulad › asyncio-ffmpeg
GitHub - regulad/asyncio-ffmpeg: Async Python bindings for FFmpeg - with complex filtering support
November 7, 2025 - Async Python bindings for FFmpeg - with complex filtering support - regulad/asyncio-ffmpeg
Author   regulad
🌐
Readthedocs
python-ffmpeg.readthedocs.io › en › latest
Overview - python-ffmpeg
from ffmpeg import FFmpeg def main(): ffmpeg = ( FFmpeg() .option("y") .input("input.mp4") .output( "output.mp4", {"codec:v": "libx264"}, vf="scale=1280:-1", preset="veryslow", crf=24, ) ) ffmpeg.execute() if __name__ == "__main__": main() import asyncio from ffmpeg.asyncio import FFmpeg async def main(): ffmpeg = ( FFmpeg() .option("y") .input("input.mp4") .output( "output.mp4", {"codec:v": "libx264"}, vf="scale=1280:-1", preset="veryslow", crf=24, ) ) await ffmpeg.execute() if __name__ == "__main__": asyncio.run(main())
🌐
Medium
kitfucoda.medium.com › video-data-io-through-ffmpeg-subprocess-c5f1ee42e43d
Video data IO through ffmpeg subprocess | by KitFu Coda | Medium
December 18, 2024 - Now time to code the implementation, as I wanted to both read from and write to ffmpeg concurrently, so this is going to be an asyncio application.
🌐
GitHub
github.com › scivision › asyncio-subprocess-ffmpeg
GitHub - scivision/asyncio-subprocess-ffmpeg: Examples of Python asyncio.subprocess · GitHub
Examples of Python asyncio.subprocess with FFmpeg and also traditional synchronous processes.
Author   scivision
🌐
GitHub
github.com › sumebrius › python-ffmpeg-asyncio
GitHub - sumebrius/python-ffmpeg-asyncio
import asyncio from ffmpeg_asyncio import FFmpeg, Progress async def main(): ffmpeg = ( FFmpeg() .input("input.mp4") .output("output.mp4") ) @ffmpeg.on("progress") def on_progress(progress: Progress): print(progress) @ffmpeg.on("completed") def completed(): print("Finished!") @ffmpeg.on("terminated") def exited(return_code: int): print("Oh no!") await ffmpeg.execute() if __name__ == "__main__": asyncio.run(main())
Author   sumebrius
🌐
GitHub
github.com › yukihiko-shinoda › asyncffmpeg
GitHub - yukihiko-shinoda/asyncffmpeg: Supports async / await pattern for FFmpeg operations. · GitHub
This package supports FFmpeg asynchronously invoke with async / await pattern wrapping ffmpeg.run_async() of ffmpeg-python and returned subprocess.Popen.
Starred by 19 users
Forked by 2 users
Languages   Python 98.6% | Dockerfile 1.4%
🌐
GitHub
github.com › kkroening › ffmpeg-python › blob › master › ffmpeg › _run.py
ffmpeg-python/ffmpeg/_run.py at master · kkroening/ffmpeg-python
""" if isinstance(cmd, ... quiet=False, overwrite_output=False, cwd=None, ): """Asynchronously invoke ffmpeg for the supplied node graph....
Author   kkroening
🌐
piwheels
piwheels.org › project › ffmpeg-asyncio
piwheels - ffmpeg-asyncio
A fork of the excellent python-ffmpeg binding for FFmpeg, updated for native async API support only.
Top answer
1 of 1
2

For gracefully closing FFmpeg sub-process, we may write 'q' to stdin pipe of FFmpeg sub-process as described in my following answer.

In order to have it possible to write 'q', we may execute FFmpeg sub-process as follows:

ffmpeg_process = ffmpeg.output(audio_part, video_part, path).overwrite_output().run_async(pipe_stdin=True)

ffmpeg_process allows us to access the sub-process and terminate it.
For keeping the code simple, we may declare ffmpeg_process as global variable.

Updated ffmpeg_func method:

def ffmpeg_func(audio_part, video_part, path):
    global ffmpeg_process
    ffmpeg_process = ffmpeg.output(audio_part, video_part, path).overwrite_output().run_async(pipe_stdin=True)

Updated start_ffmpeg method:

def start_ffmpeg(audio_part, video_part, path):
    global ffmpeg_process

    # Allow only one instance of FFmpeg to be executed - ffmpeg_process = None in the first time, and ffmpeg_process.poll() is not None when FFmpeg is not running
    if (ffmpeg_process is None) or ffmpeg_process.poll():
        threading.Thread(target=ffmpeg_func, args=(audio_part, video_part, path)).start()

The above code allows executing FFmpeg only if it's not running.


Updated cancel_ffmpeg method:

def cancel_ffmpeg():
    global ffmpeg_process

    #Check if FFmpeg sub-process is running
    if (ffmpeg_process is not None) and (ffmpeg_process.poll() is None):
        # Terminate FFmpeg gracefully
        ffmpeg_process.stdin.write('q'.encode("GBK"))  # Simulate user pressing 'q' key
        ffmpeg_process.communicate()
        ffmpeg_process.wait()
        ffmpeg_process = None

Note:

Your implementation of start_ffmpeg executes threading.Thread in a loop, and that executes FFmpeg sub-process in a loop.

def start_ffmpeg(audio_part, video_part, path):
    while True:
        if is_cancelled:
            break
        threading.Thread(target=ffmpeg_func, args=(audio_part, video_part, path)).start()

We have to remove the while True from the above method.


Updated code sample:

from tkinter import *
import ffmpeg
import threading

def start_ffmpeg_thread(audio_part, video_part, path):
    threading.Thread(target=start_ffmpeg, args=(audio_part, video_part, path)).start()

def start_ffmpeg(audio_part, video_part, path):
    #while True:
    #    if is_cancelled:
    #        break
    global ffmpeg_process

    # Allow only one instance of FFmpeg to be executed - ffmpeg_process = None in the first time, and ffmpeg_process.poll() is not None when FFmpeg is not running
    if (ffmpeg_process is None) or ffmpeg_process.poll():
        threading.Thread(target=ffmpeg_func, args=(audio_part, video_part, path)).start()

def ffmpeg_func(audio_part, video_part, path):
    global ffmpeg_process
    #ffmpeg.output(audio_part, video_part, path).run(overwrite_output=True)
    ffmpeg_process = ffmpeg.output(audio_part, video_part, path).overwrite_output().run_async(pipe_stdin=True)
    

def cancel_ffmpeg():
    #global is_cancelled
    #is_cancelled = True
    global ffmpeg_process

    #Check if FFmpeg sub-process is running
    if (ffmpeg_process is not None) and (ffmpeg_process.poll() is None):
        # Terminate FFmpeg gracefully
        ffmpeg_process.stdin.write('q'.encode("GBK"))  # Simulate user pressing 'q' key
        ffmpeg_process.communicate()
        ffmpeg_process.wait()
        ffmpeg_process = None

#is_cancelled = False
ffmpeg_process = None

root = Tk()

video_part = ffmpeg.input("bunny_1080p_60fps.mp4")
audio_part = ffmpeg.input("bunny_1080p_60fps.mp4")
path = "output.mp4"

button_1 = Button(root, text="Start", command=lambda: start_ffmpeg_thread(audio_part, video_part, path))
button_1.pack(pady=30, padx=30)

button_2 = Button(root, text="Stop", command=cancel_ffmpeg)
button_2.pack(pady=30, padx=30)

root.mainloop()

In case you are planning to allow multiple instances of FFmpeg sub-processes, you may insert the ffmpeg_process into a list, for keeping track over all the sub-processes.
For closing all the sub-processes at once, just iterate the list.