从 ffmpeg 获取实时输出以在进度条中使用(PyQt4,stdout)

发布于 2024-12-07 17:58:54 字数 2010 浏览 0 评论 0原文

我已经查看了很多问题,但仍然无法完全弄清楚。我正在使用 PyQt,并且希望运行 ffmpeg -i file.mp4 file.avi 并在流式传输时获取输出,以便我可以创建进度条。

我看过这些问题: ffmpeg可以显示进度条吗? 从子进程实时捕获标准

输出我能够看到rsync 命令,使用以下代码:

import subprocess, time, os, sys

cmd = "rsync -vaz -P source/ dest/"
p, line = True, 'start'


p = subprocess.Popen(cmd,
                     shell=True,
                     bufsize=64,
                     stdin=subprocess.PIPE,
                     stderr=subprocess.PIPE,
                     stdout=subprocess.PIPE)

for line in p.stdout:
    print("OUTPUT>>> " + str(line.rstrip()))
    p.stdout.flush()

但是当我将命令更改为 ffmpeg -i file.mp4 file.avi 时,我没有收到任何输出。我猜这与标准输出/输出缓冲有关,但我对如何读取看起来像

frame=   51 fps= 27 q=31.0 Lsize=     769kB time=2.04 bitrate=3092.8kbits/s

我可以用来找出进度的行感到困惑。

有人可以向我展示一个如何将此信息从 ffmpeg 获取到 python 的示例,无论是否使用 PyQt(如果可能)


编辑: 我最终采用了 jlp 的解决方案,我的代码如下所示:

#!/usr/bin/python
import pexpect

cmd = 'ffmpeg -i file.MTS file.avi'
thread = pexpect.spawn(cmd)
print "started %s" % cmd
cpl = thread.compile_pattern_list([
    pexpect.EOF,
    "frame= *\d+",
    '(.+)'
])
while True:
    i = thread.expect_list(cpl, timeout=None)
    if i == 0: # EOF
        print "the sub process exited"
        break
    elif i == 1:
        frame_number = thread.match.group(0)
        print frame_number
        thread.close
    elif i == 2:
        #unknown_line = thread.match.group(0)
        #print unknown_line
        pass

给出了以下输出:

started ffmpeg -i file.MTS file.avi
frame=   13
frame=   31
frame=   48
frame=   64
frame=   80
frame=   97
frame=  115
frame=  133
frame=  152
frame=  170
frame=  188
frame=  205
frame=  220
frame=  226
the sub process exited

完美!

I've looked at a number of questions but still can't quite figure this out. I'm using PyQt, and am hoping to run ffmpeg -i file.mp4 file.avi and get the output as it streams so I can create a progress bar.

I've looked at these questions:
Can ffmpeg show a progress bar?
catching stdout in realtime from subprocess

I'm able to see the output of a rsync command, using this code:

import subprocess, time, os, sys

cmd = "rsync -vaz -P source/ dest/"
p, line = True, 'start'


p = subprocess.Popen(cmd,
                     shell=True,
                     bufsize=64,
                     stdin=subprocess.PIPE,
                     stderr=subprocess.PIPE,
                     stdout=subprocess.PIPE)

for line in p.stdout:
    print("OUTPUT>>> " + str(line.rstrip()))
    p.stdout.flush()

But when I change the command to ffmpeg -i file.mp4 file.avi I receive no output. I'm guessing this has something to do with stdout / output buffering, but I'm stuck as to how to read the line that looks like

frame=   51 fps= 27 q=31.0 Lsize=     769kB time=2.04 bitrate=3092.8kbits/s

Which I could use to figure out progress.

Can someone show me an example of how to get this info from ffmpeg into python, with or without the use of PyQt (if possible)


EDIT:
I ended up going with jlp's solution, my code looked like this:

#!/usr/bin/python
import pexpect

cmd = 'ffmpeg -i file.MTS file.avi'
thread = pexpect.spawn(cmd)
print "started %s" % cmd
cpl = thread.compile_pattern_list([
    pexpect.EOF,
    "frame= *\d+",
    '(.+)'
])
while True:
    i = thread.expect_list(cpl, timeout=None)
    if i == 0: # EOF
        print "the sub process exited"
        break
    elif i == 1:
        frame_number = thread.match.group(0)
        print frame_number
        thread.close
    elif i == 2:
        #unknown_line = thread.match.group(0)
        #print unknown_line
        pass

Which gives this output:

started ffmpeg -i file.MTS file.avi
frame=   13
frame=   31
frame=   48
frame=   64
frame=   80
frame=   97
frame=  115
frame=  133
frame=  152
frame=  170
frame=  188
frame=  205
frame=  220
frame=  226
the sub process exited

Perfect!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

眼眸印温柔 2024-12-14 17:58:54

在这种捕获 ffmpeg 状态输出(进入 STDERR)的特定情况下,这个问题为我解决了这个问题: FFMPEG 和 Python 子进程

技巧是将 universal_newlines=True 添加到 subprocess.Popen() 调用中,因为ffmpeg 的输出实际上是无缓冲的,但带有换行符。

cmd = "ffmpeg -i in.mp4 -y out.avi"
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,universal_newlines=True)
for line in process.stdout:
    print(line)

另请注意,在此代码示例中,STDERR 状态输出直接重定向到 subprocess.STDOUT

In this specific case for capturing ffmpeg's status output (which goes to STDERR), this SO question solved it for me: FFMPEG and Pythons subprocess

The trick is to add universal_newlines=True to the subprocess.Popen() call, because ffmpeg's output is in fact unbuffered but comes with newline-characters.

cmd = "ffmpeg -i in.mp4 -y out.avi"
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,universal_newlines=True)
for line in process.stdout:
    print(line)

Also note that in this code sample the STDERR status output is directly redirected to subprocess.STDOUT

一曲琵琶半遮面シ 2024-12-14 17:58:54

我发现从子进程获取动态反馈/输出的唯一方法是使用类似 pexpect 的东西:

#! /usr/bin/python

import pexpect

cmd = "foo.sh"
thread = pexpect.spawn(cmd)
print "started %s" % cmd
cpl = thread.compile_pattern_list([pexpect.EOF,
                                   'waited (\d+)'])
while True:
    i = thread.expect_list(cpl, timeout=None)
    if i == 0: # EOF
        print "the sub process exited"
        break
    elif i == 1:
        waited_time = thread.match.group(1)
        print "the sub process waited %d seconds" % int(waited_time)
thread.close()

被调用的子进程 foo.sh 只是等待 10 到 20 秒之间的随机时间,下面是它的代码:

#! /bin/sh

n=5
while [ $n -gt 0 ]; do
    ns=`date +%N`
    p=`expr $ns % 10 + 10`
    sleep $p
    echo waited $p
    n=`expr $n - 1`
done

您将需要使用一些与从 ffmpeg 获得的输出相匹配的正则表达式,并对其进行某种计算以显示进度条,但这至少会为您提供来自 ffmpeg 的无缓冲输出。

The only way I've found to get dynamic feedback/output from a child process is to use something like pexpect:

#! /usr/bin/python

import pexpect

cmd = "foo.sh"
thread = pexpect.spawn(cmd)
print "started %s" % cmd
cpl = thread.compile_pattern_list([pexpect.EOF,
                                   'waited (\d+)'])
while True:
    i = thread.expect_list(cpl, timeout=None)
    if i == 0: # EOF
        print "the sub process exited"
        break
    elif i == 1:
        waited_time = thread.match.group(1)
        print "the sub process waited %d seconds" % int(waited_time)
thread.close()

the called sub process foo.sh just waits a random amount of time between 10 and 20 seconds, here's the code for it:

#! /bin/sh

n=5
while [ $n -gt 0 ]; do
    ns=`date +%N`
    p=`expr $ns % 10 + 10`
    sleep $p
    echo waited $p
    n=`expr $n - 1`
done

You'll want to use some regular expression that matches the output you're getting from ffmpeg and does some kind of calculation on it to show the progress bar, but this will at least get you the unbuffered output from ffmpeg.

平定天下 2024-12-14 17:58:54
  1. 通常不需要从 shell 调用。
  2. 根据经验,我知道 ffmpeg 输出的一部分来自 stderr,而不是 stdout

如果您只想打印输出行,就像上面的示例一样,那么只需这样做:

import subprocess

cmd = 'ffmpeg -i file.mp4 file.avi'
args = cmd.split()

p = subprocess.Popen(args)

请注意,ffmpeg chat 的行以 \r 终止,因此它将覆盖同一条线!我认为这意味着您无法像处理 rsync 示例那样迭代 p.stderr 中的行。要构建自己的进度条,您可能需要自己处理阅读,这应该可以帮助您开始:

p = subprocess.Popen(args, stderr=subprocess.PIPE)

while True:
  chatter = p.stderr.read(1024)
  print("OUTPUT>>> " + chatter.rstrip())
  1. Calling from the shell is generally not required.
  2. I know from experince that part of the ffmpeg output comes on stderr, not stdout.

If all you want to do is print the output line, like in your example above, then simply this will do:

import subprocess

cmd = 'ffmpeg -i file.mp4 file.avi'
args = cmd.split()

p = subprocess.Popen(args)

Note that the line of ffmpeg chat is terminated with \r, so it will overwrite in the same line! I think this means you can't iterate over the lines in p.stderr, as you do with your rsync example. To build your own progress bar, then, you may need to handle the reading yourself, this should get you started:

p = subprocess.Popen(args, stderr=subprocess.PIPE)

while True:
  chatter = p.stderr.read(1024)
  print("OUTPUT>>> " + chatter.rstrip())
心安伴我暖 2024-12-14 17:58:54

我编写了一个专用包,为您提供了 Python 中 ffmpeg 进度的生成器函数: ffmpeg-进度产量

只需运行:

pip3 install ffmpeg-progress-yield

然后,只需执行:

from ffmpeg_progress_yield import FfmpegProgress

cmd = [
    "ffmpeg", "-i", "test/test.mp4", "-c:v", "libx264", "-vf", "scale=1920x1080", "-preset", "fast", "-f", "null", "/dev/null",
]

ff = FfmpegProgress(cmd)
for progress in ff.run_command_with_progress():
    print(f"{progress}/100")

请注意,这仅适用于预先知道持续时间的输入文件。

I wrote a dedicated package that gives you a generator function for ffmpeg progress in Python: ffmpeg-progress-yield.

Simply run:

pip3 install ffmpeg-progress-yield

Then, simply do:

from ffmpeg_progress_yield import FfmpegProgress

cmd = [
    "ffmpeg", "-i", "test/test.mp4", "-c:v", "libx264", "-vf", "scale=1920x1080", "-preset", "fast", "-f", "null", "/dev/null",
]

ff = FfmpegProgress(cmd)
for progress in ff.run_command_with_progress():
    print(f"{progress}/100")

Note that this only works for input files where the duration is known in advance.

辞旧 2024-12-14 17:58:54

这个答案对我不起作用:/这是我的做法。

它来自我的项目 KoalaBeatzHunter

享受!

def convertMp4ToMp3(mp4f, mp3f, odir, kbps, callback=None, efsize=None):
    """
    mp4f:     mp4 file
    mp3f:     mp3 file
    odir:     output directory
    kbps:     quality in kbps, ex: 320000
    callback: callback() to recieve progress
    efsize:   estimated file size, if there is will callback() with %
    Important:
    communicate() blocks until the child process returns, so the rest of the lines 
    in your loop will only get executed after the child process has finished running. 
    Reading from stderr will block too, unless you read character by character like here.
    """
    cmdf = "ffmpeg -i "+ odir+mp4f +" -f mp3 -ab "+ str(kbps) +" -vn "+ odir+mp3f
    lineAfterCarriage = ''

    print deleteFile(odir + mp3f)

    child = subprocess.Popen(cmdf, shell=True, stderr=subprocess.PIPE)

    while True:
        char = child.stderr.read(1)
        if char == '' and child.poll() != None:
            break
        if char != '':
            # simple print to console
#             sys.stdout.write(char)
#             sys.stdout.flush()
            lineAfterCarriage += char
            if char == '\r':
                if callback:
                    size = int(extractFFmpegFileSize(lineAfterCarriage)[0])
                    # kb to bytes
                    size *= 1024
                    if efsize:
                        callback(size, efsize)
                lineAfterCarriage = ''

接下来,您还需要 3 个函数来实现它。

def executeShellCommand(cmd):
    p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
    out, err = p.communicate()
    return out.rstrip(), err.rstrip(), p.returncode

def getFFmpegFileDurationInSeconds(filename):
    cmd = "ffmpeg -i "+ filename +" 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//"
    time = executeShellCommand(cmd)[0]
    h = int(time[0:2])
    m = int(time[3:5])
    s = int(time[6:8])
    ms = int(time[9:11])
    ts = (h * 60 * 60) + (m * 60) + s + (ms/60)
    return ts

def estimateFFmpegMp4toMp3NewFileSizeInBytes(duration, kbps):
    """
    * Very close but not exact.
    duration: current file duration in seconds
    kbps: quality in kbps, ex: 320000
    Ex:
        estim.:    12,200,000
        real:      12,215,118
    """
    return ((kbps * duration) / 8)

最后你做到了:

# get new mp3 estimated size
secs = utls.getFFmpegFileDurationInSeconds(filename)
efsize = utls.estimateFFmpegMp4toMp3NewFileSizeInBytes(secs, 320000)
print efsize

utls.convertMp4ToMp3("AwesomeKoalaBeat.mp4", "AwesomeKoalaBeat.mp3",
                "../../tmp/", 320000, utls.callbackPrint, efsize)

希望这会有所帮助!

This answers didn't worked for me :/ Here is the way I did it.

Its from my project KoalaBeatzHunter.

Enjoy!

def convertMp4ToMp3(mp4f, mp3f, odir, kbps, callback=None, efsize=None):
    """
    mp4f:     mp4 file
    mp3f:     mp3 file
    odir:     output directory
    kbps:     quality in kbps, ex: 320000
    callback: callback() to recieve progress
    efsize:   estimated file size, if there is will callback() with %
    Important:
    communicate() blocks until the child process returns, so the rest of the lines 
    in your loop will only get executed after the child process has finished running. 
    Reading from stderr will block too, unless you read character by character like here.
    """
    cmdf = "ffmpeg -i "+ odir+mp4f +" -f mp3 -ab "+ str(kbps) +" -vn "+ odir+mp3f
    lineAfterCarriage = ''

    print deleteFile(odir + mp3f)

    child = subprocess.Popen(cmdf, shell=True, stderr=subprocess.PIPE)

    while True:
        char = child.stderr.read(1)
        if char == '' and child.poll() != None:
            break
        if char != '':
            # simple print to console
#             sys.stdout.write(char)
#             sys.stdout.flush()
            lineAfterCarriage += char
            if char == '\r':
                if callback:
                    size = int(extractFFmpegFileSize(lineAfterCarriage)[0])
                    # kb to bytes
                    size *= 1024
                    if efsize:
                        callback(size, efsize)
                lineAfterCarriage = ''

Next, you need 3 more functions to implement it.

def executeShellCommand(cmd):
    p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
    out, err = p.communicate()
    return out.rstrip(), err.rstrip(), p.returncode

def getFFmpegFileDurationInSeconds(filename):
    cmd = "ffmpeg -i "+ filename +" 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//"
    time = executeShellCommand(cmd)[0]
    h = int(time[0:2])
    m = int(time[3:5])
    s = int(time[6:8])
    ms = int(time[9:11])
    ts = (h * 60 * 60) + (m * 60) + s + (ms/60)
    return ts

def estimateFFmpegMp4toMp3NewFileSizeInBytes(duration, kbps):
    """
    * Very close but not exact.
    duration: current file duration in seconds
    kbps: quality in kbps, ex: 320000
    Ex:
        estim.:    12,200,000
        real:      12,215,118
    """
    return ((kbps * duration) / 8)

And finally you do:

# get new mp3 estimated size
secs = utls.getFFmpegFileDurationInSeconds(filename)
efsize = utls.estimateFFmpegMp4toMp3NewFileSizeInBytes(secs, 320000)
print efsize

utls.convertMp4ToMp3("AwesomeKoalaBeat.mp4", "AwesomeKoalaBeat.mp3",
                "../../tmp/", 320000, utls.callbackPrint, efsize)

Hope this will help!

终难遇 2024-12-14 17:58:54

您还可以使用 PyQt4 的 QProcess(如原始问题中所要求的)通过将 QProcess 中的插槽连接到 QTextEdit 或其他内容来非常清楚地完成此操作。我对 python 和 pyqt 还很陌生,但我是这样做的:

import sys
from PyQt4 import QtCore, QtGui

class ffmpegBatch(QtGui.QWidget):
    def __init__(self):
        super(ffmpegBatch, self).__init__()
        self.initUI()

    def initUI(self):
        layout = QtGui.QVBoxLayout()
        self.edit = QtGui.QTextEdit()
        self.edit.setGeometry(300, 300, 300, 300)
        run = QtGui.QPushButton("Run process")

        layout.addWidget(self.edit)
        layout.addWidget(run)

        self.setLayout(layout)

        run.clicked.connect(self.run)

    def run(self):
        # your commandline whatnot here, I just used this for demonstration
        cmd = "systeminfo"

        proc = QtCore.QProcess(self)
        proc.setProcessChannelMode(proc.MergedChannels)
        proc.start(cmd)
        proc.readyReadStandardOutput.connect(lambda: self.readStdOutput(proc))


    def readStdOutput(self, proc):
        self.edit.append(QtCore.QString(proc.readAllStandardOutput()))

def main():
    app = QtGui.QApplication(sys.argv)
    ex = ffmpegBatch()
    ex.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

You can also do it pretty clearly with PyQt4's QProcess (as asked in the original question) by connecting a slot from the QProcess to a QTextEdit or whatever. I'm still pretty new to python and pyqt but here's how I just managed to do it:

import sys
from PyQt4 import QtCore, QtGui

class ffmpegBatch(QtGui.QWidget):
    def __init__(self):
        super(ffmpegBatch, self).__init__()
        self.initUI()

    def initUI(self):
        layout = QtGui.QVBoxLayout()
        self.edit = QtGui.QTextEdit()
        self.edit.setGeometry(300, 300, 300, 300)
        run = QtGui.QPushButton("Run process")

        layout.addWidget(self.edit)
        layout.addWidget(run)

        self.setLayout(layout)

        run.clicked.connect(self.run)

    def run(self):
        # your commandline whatnot here, I just used this for demonstration
        cmd = "systeminfo"

        proc = QtCore.QProcess(self)
        proc.setProcessChannelMode(proc.MergedChannels)
        proc.start(cmd)
        proc.readyReadStandardOutput.connect(lambda: self.readStdOutput(proc))


    def readStdOutput(self, proc):
        self.edit.append(QtCore.QString(proc.readAllStandardOutput()))

def main():
    app = QtGui.QApplication(sys.argv)
    ex = ffmpegBatch()
    ex.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
不离久伴 2024-12-14 17:58:54

ffmpeg-python github 上有一个示例 - 对于 Windows 机器(使用 unix 套接字),不能开箱即用... https://github.com/kkroening/ffmpeg-python/blob/master/examples/show_progress.py

一个简单的(IMO,更好...:))视频转换器脚本,带有进度(ffmpeg-python 和 tq​​dm_rich):
https://gist.github.com/pbouill/fddf767221b47f83c97d7813c03569c4

示例视频编码/进度转换

无需覆盖 sys.stdout/stderr,然后像某些 tqdm 文档建议的那样恢复以获取子进程输出/拦截控制台输出(https://github.com/tqdm/tqdm/blob/master/examples/ redirect_print.py)。

只需通过提供输入文件路径来创建视频转换器实例:

vc = VideoConverter(input_path=pathlib.Path('./path/to/my/file'))
vc.convert()

如果未提供输出路径,则输出视频将放置在与输入文件相同的目录中,并附加“-converted.mp4”。您也可以调整输出/转换 kwargs...默认情况下它使用:

class VideoConverter:
    FF_OUTPUT_KWARGS = {
        'vcodec': 'libx265',
        'crf': 35 
    }
    ...

例如,

vc = VideoConverter(
    input_path=pathlib.Path('./path/to/my/input_file.mp4'), 
    output_path=pathlib.Path('./path/to/my/output_file.mp4')),
    output_kwargs={
        'crf': 30,
        'vcodec': 'libx264'
    }
)
vc.convert()

您可以通过在调用“转换”时提供进度指标选择来基于视频时间的进度报告或基于帧的进度报告:

class VideoConverter:
    ...
    class ProgressMetric(Enum):
            FRAMES = auto()
            TIME = auto()
    ...

vc.convert(self, progress_metric = VideoConverter.ProgressMetric.TIME)

您可以转换所有内容在脚本目录中,只需调用:(

VideoConverter.convert_all()

也可以指定输入目录、输出目录、output_kwargs 作为此函数的关键字参数)

希望这有帮助!

There's an example on the ffmpeg-python github -- doesn't work out of the box for windows machines machines (uses unix sockets)... https://github.com/kkroening/ffmpeg-python/blob/master/examples/show_progress.py

A simple, (IMO, better... :)) video converter script w/ progress (ffmpeg-python and tqdm_rich) here:
https://gist.github.com/pbouill/fddf767221b47f83c97d7813c03569c4

example video encoding/conversion with progress

No need to overwrite sys.stdout/stderr then revert like some of the tqdm documentation suggests for grabbing subprocess outputs/intercepting console outputs (https://github.com/tqdm/tqdm/blob/master/examples/redirect_print.py).

Just create a video converter instance by supplying an input file path:

vc = VideoConverter(input_path=pathlib.Path('./path/to/my/file'))
vc.convert()

If no output path is supplied, output video will be placed in the same dir as the input file with "-converted.mp4" appended. You can adjust the output/conversion kwargs as well... by default it's using:

class VideoConverter:
    FF_OUTPUT_KWARGS = {
        'vcodec': 'libx265',
        'crf': 35 
    }
    ...

e.g.

vc = VideoConverter(
    input_path=pathlib.Path('./path/to/my/input_file.mp4'), 
    output_path=pathlib.Path('./path/to/my/output_file.mp4')),
    output_kwargs={
        'crf': 30,
        'vcodec': 'libx264'
    }
)
vc.convert()

You can video-time based progress report, or frame-based progress report by supplying a progress metric choice when calling "convert":

class VideoConverter:
    ...
    class ProgressMetric(Enum):
            FRAMES = auto()
            TIME = auto()
    ...

vc.convert(self, progress_metric = VideoConverter.ProgressMetric.TIME)

You can convert everything in the script directory by simply calling:

VideoConverter.convert_all()

(can also specify input dir, output dir, output_kwargs as keyword arguments to this function)

Hope this helps!

无人问我粥可暖 2024-12-14 17:58:54

如果您有持续时间(也可以从 FFMPEG 输出中获取),您可以通过在编码时读取经过的时间(时间)输出来计算进度。

一个简单的例子:

  pipe = subprocess.Popen(
        cmd,
        stderr=subprocess.PIPE,
        close_fds=True
  )
  fcntl.fcntl(
        pipe.stderr.fileno(),
        fcntl.F_SETFL,
        fcntl.fcntl(pipe.stderr.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK,
  )
   while True:
            readx = select.select([pipe.stderr.fileno()], [], [])[0]

            if readx: 
                chunk = pipe.stderr.read()

                if not chunk:
                    break

                result = re.search(r'\stime=(?P<time>\S+) ', chunk)
                elapsed_time = float(result.groupdict()['time'])

                # Assuming you have the duration in seconds
                progress = (elapsed_time / duration) * 100

                # Do something with progress here
                callback(progress)

        time.sleep(10)

If you have the duration (Which you can also get from the FFMPEG output) you can calculate the progress by reading the elapsed time (time) output when encoding.

A simple example:

  pipe = subprocess.Popen(
        cmd,
        stderr=subprocess.PIPE,
        close_fds=True
  )
  fcntl.fcntl(
        pipe.stderr.fileno(),
        fcntl.F_SETFL,
        fcntl.fcntl(pipe.stderr.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK,
  )
   while True:
            readx = select.select([pipe.stderr.fileno()], [], [])[0]

            if readx: 
                chunk = pipe.stderr.read()

                if not chunk:
                    break

                result = re.search(r'\stime=(?P<time>\S+) ', chunk)
                elapsed_time = float(result.groupdict()['time'])

                # Assuming you have the duration in seconds
                progress = (elapsed_time / duration) * 100

                # Do something with progress here
                callback(progress)

        time.sleep(10)
往日情怀 2024-12-14 17:58:54

在我看来,通过使用 ffmpeg 的 -progress url (global) 选项,解决方案实际上很简单:

ffmpeg -progress progress.log -i file.mp4 file.avi

文件 progress.log 将附加实时进度信息(更新周期​​使用 -stats_period 选项设置)。

该信息将如下所示:

frame=584
fps=52.40
stream_0_0_q=0.0
bitrate=N/A
total_size=762
out_time_us=0
out_time_ms=0
out_time=00:00:00.000000
dup_frames=0
drop_frames=0
speed=   0x
progress=continue

根据此信息,可以计算进度。

程序员博客中有更详细的示例

Looks to me that the solution is actually simple by using the -progress url (global) option of ffmpeg:

ffmpeg -progress progress.log -i file.mp4 file.avi

The file progress.log will be appended with progress information in real time (The update period is set using -stats_period option)

The information will look like this:

frame=584
fps=52.40
stream_0_0_q=0.0
bitrate=N/A
total_size=762
out_time_us=0
out_time_ms=0
out_time=00:00:00.000000
dup_frames=0
drop_frames=0
speed=   0x
progress=continue

From this information it is possible to calculate the progress.

A more detailed example in Programster's Blog

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文