I've seen some people achieving to scrape out live progress data from ffmpeg subprocess. But for non-command line execution, how could this be accomplished?
For example I want to store this real-time information on the command line output line by line or get the progress percentage to the completion.
import ffmpeg
import threading
def ffmpeg_func(path1, path2, path3):
global out, err
video_part = ffmpeg.input(path1)
audio_part = ffmpeg.input(path2)
ffm = ffmpeg.output(audio_part, video_part, path3).overwrite_output().run_async(pipe_stdout=True)
out, err = ffm.communicate()
threading.Thread(target=ffmpeg_func, args=(<<vid_part_path>>, <<audio_part_path>>, <<output_path>>)).start()
I used threading.Thread
because I'm intending to execute multiple ffmpeg process at the same time.
Thanks to @Rotem, I implemented his or her answer to my code.
import subprocess as sp
import shlex
import json
from threading import Thread
import time
def progress_reader(procs, q):
while True:
if procs.poll() is not None:
break
progress_text = procs.stdout.readline()
if progress_text is None:
break
progress_text = progress_text.decode("utf-8")
if progress_text.startswith("frame="):
frame = int(progress_text.partition('=')[-1])
q[0] = frame
data = sp.run(shlex.split('ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 -of json vid.mp4'), stdout=sp.PIPE).stdout
dict = json.loads(data)
tot_n_frames = float(dict['streams'][0]['nb_read_packets'])
process = sp.Popen(shlex.split('ffmpeg -y -loglevel error -i vid.mp4 -i aud.mp3 -progress pipe:1 output.mp4'), stdout=sp.PIPE)
q = [0]
progress_reader_thread = Thread(target=progress_reader, args=(process, q))
progress_reader_thread.start()
while True:
if process.poll() is not None:
break
time.sleep(1)
n_frame = q[0]
progress_percent = (n_frame/tot_n_frames)*100
print(f'Progress [%]: {progress_percent:.2f}')
process.stdout.close()
progress_reader_thread.join()
process.wait()