jonghwanhyeon / python-ffmpeg

A python binding for FFmpeg which provides sync and async APIs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Progress not working

pdc1 opened this issue · comments

Hello,

I am using python 3.11 (Windows), ffmpeg 6.1.1 (cygwin), python-ffmpeg 2.0.10.

I tried a simple example converting MP3 to Opus, and it worked just fine. Then I added @ffmpeg.on("progress") and now it appears to hang (no CPU usage, no progress displayed).

When I kill the run with ^C, I get:

d:/cygwin64/bin/ffmpeg.exe -loglevel warning -i input.mp3 -codec:a libopus -b:a 32k -application voip output.opus
Traceback (most recent call last):
  File "D:\Projects\MiscScripts\process_audiobooks.py", line 47, in <module>
    main()
  File "D:\Projects\MiscScripts\process_audiobooks.py", line 43, in main
    ffmpeg.execute()
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\site-packages\ffmpeg\ffmpeg.py", line 188, in execute
    done, pending = concurrent.futures.wait(futures, return_when=concurrent.futures.FIRST_EXCEPTION)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\concurrent\futures\_base.py", line 305, in wait
    waiter.event.wait(timeout)
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\threading.py", line 622, in wait
    signaled = self._cond.wait(timeout)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Paul\AppData\Local\Programs\Python\Python311\Lib\threading.py", line 320, in wait
    waiter.acquire()
KeyboardInterrupt

My script is based on one of the examples:

from ffmpeg import FFmpeg, Progress

FFMPEG_EXE = "d:/cygwin64/bin/ffmpeg.exe"


def main():
    ffmpeg = (
        FFmpeg(FFMPEG_EXE)
        .option("loglevel", value="warning")  # <- don't do this! (see below)
        .input("input.mp3")
        .output(
            "output.opus",
            {"codec:a": "libopus", "b:a": "32k", "application": "voip"},
        )
    )
    print(" ".join(ffmpeg.arguments))

    @ffmpeg.on("progress")
    def on_progress(progress: Progress):
        print("progress:", progress)
        if progress.frame > 200:
            ffmpeg.terminate()

    ffmpeg.execute()


if __name__ == "__main__":
    main()

I spent some time investigating and found that I needed .option("y") to overwrite the output file (which existed from an earlier test), and I removed the .option("loglevel", value="warning") so it will output the statistics (oops!). Now the ffmpeg runs (and completes), but still there are no progress updates.

If I run the ffmpeg command normally, I get status updates like:
size= 768kB time=00:04:16.23 bitrate= 24.6kbits/s speed=39.4x

I notice in ffmpeg / statistics.py that it looks like the class is expecting frame, fps, size, time, bitrate, and speed, and will not return status unless all are present. My output is missing frame and fps.

Might this be a difference in a newer version of ffmpeg? Or perhaps is a function of doing an audio-only operation?

I found that commenting out the check for all fields allowed my example to work! In ffmpeg / statistics.py:

@dataclass(frozen=True)
class Statistics:
    frame: int = 0
    fps: float = 0.0
    size: int = 0
    time: timedelta = field(default_factory=timedelta)
    bitrate: float = 0.0
    speed: float = 0.0

    @classmethod
    def from_line(cls, line: str) -> Optional[Self]:
        statistics = {key: value for key, value in _pattern.findall(line)}
here -> # if len(statistics) != len(_field_factory):
     -> #     return None

        fields = {key: _field_factory[key](value) for key, value in statistics.items() if value != "N/A"}
        return Statistics(**fields)

Looks like some versions of ffmpeg use KiB and some use kB in the size. Changing ffmpeg versions or updating line 19 in statistics.py resolved the issue for me.

Looking at the git history, this was introduced in version 2.0.9. Downgrading to 2.0.8 solves this problem. However, this "feature" is not very useful and I support the above pull request as a long term fix.

Solved on version 2.0.11