Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

progress event support #23

Open
astroza opened this issue Oct 17, 2017 · 8 comments
Open

progress event support #23

astroza opened this issue Oct 17, 2017 · 8 comments

Comments

@astroza
Copy link

astroza commented Oct 17, 2017

Hi,

I was working on a transcoding platform and I found your module to wrapping ffmpeg. I'm interested to make improvements that would be useful to everyone involved in this niche.

I'm planning to replace Popen.communicate call to achieve the goals:

  • Make ffmpy efficient in memory usage
  • Give it progress reporting support

Popen.communicate() is inefficient because of stdout and stderr buffering. Let's see some cases:

Use case 1:

you want to send transcoded data over network as fast as available. If communicate() is used, you must to accumulate the entire transcoded movie on a memory buffer to send it.

Use case 2:

you want to know the transcoding state (output size, time, bitrate) in real time. If communicate() is used, you can't do it because this method is consuming the stderr pipe

I have a experimental branch with a on_progress callback implemented here:
https://github.com/astroza/ffmpy/tree/progress_support

An usage example is:

def on_progress(state):
        print state.time

ff = ffmpy.FFmpeg(
        global_options="-hide_banner -nostdin -y -stats",
        inputs={local_input_path: None},
        outputs={local_output_path: None},
        on_progress=on_progress
)
ff.run(stderr=subprocess.PIPE)

Now I'm working to make it backwards compatible. The branch break your API

UPDATE

https://github.com/astroza/ffmpy/tree/progress_support_v2 keeps backward compatibility

Usage:

def on_progress(state):
        print state.time

ff = ffmpy.FFmpeg(
        global_options="-hide_banner -nostdin -y -stats",
        inputs={local_input_path: None},
        outputs={local_output_path: None}
)
print(ff.run(on_progress=on_progress)[1])
@astroza astroza changed the title Discussion about ffmpy features: progress event support Discussion about ffmpy progress event support Oct 17, 2017
@astroza astroza changed the title Discussion about ffmpy progress event support progress event support Oct 17, 2017
@yarodevuci
Copy link

yarodevuci commented Mar 21, 2018

@astroza is there any way to get progress of remaining time or something like that ? or like 50% complete

@horamarques
Copy link

Hi
any plans to add error messages on the progress output?
any ideia on how to do it?

thanks

@Benny739
Copy link

Any news on this?

@astroza
Copy link
Author

astroza commented Jun 15, 2020

Hi @Benny739, I have had no response from the repo owner. Nevertheless, you can find an working branch (it's used on a company) here https://github.com/astroza/ffmpy/tree/progress_support_v2

movie_description = ....

def on_progress(state):
       progress = (float(state.time or state.start_time) / movie_description.duration) * 100
       print(progress)

ff = ffmpy.FFmpeg(
        global_options="-hide_banner -nostdin -y -stats",
        inputs={local_input_path: None},
        outputs={local_output_path: None}
)
print(ff.run(on_progress=on_progress)[1])

state object has all what you need

@Benny739
Copy link

Thanks a lot, this is exactly what I was looking for.

@Ch00k merging this into the package would be wonderful.

@Benny739
Copy link

Benny739 commented Jun 16, 2020

Hi @astroza,
I'm having unclosed files now, any idea how I can close them?

/Users/benny/angular/video/python/integ_test/tests/integ_test_convert.py:31: ResourceWarning: unclosed file <_io.BufferedWriter name=4>
  converter.generate_thumbnails()
Object allocated at (most recent call last):
  File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/subprocess.py", lineno 778
    self.stdin = io.open(p2cwrite, 'wb', bufsize)
/Users/benny/angular/video/python/integ_test/tests/integ_test_convert.py:31: ResourceWarning: unclosed file <_io.BufferedReader name=5>
  converter.generate_thumbnails()
Object allocated at (most recent call last):
  File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/subprocess.py", lineno 789
    self.stderr = io.open(errread, 'rb', bufsize)

I'm basically using your code.

@astroza
Copy link
Author

astroza commented Jun 16, 2020

Sorry I can’t help you, it seems unrelated to the library (according you stack trace) and I can’t see your code

@Benny739
Copy link

Benny739 commented Jun 17, 2020

I found the bug, it's caused by piping and not closing stdin and stderr. In the wait function after the while loop I close stdin and stderr now, and the warning is gone.

    def wait(self, on_progress=None, stderr_ring_size=30):
        stderr_ring = []
        is_running = True
        stderr_fileno = self.process.stderr.fileno()
        ff_state = FFstate()
        while is_running:
            latest_update = os.read(stderr_fileno, self.update_size)
            if ff_state.consume(latest_update) and on_progress is not None:
                on_progress(ff_state)
            stderr_ring.append(latest_update.decode())
            if len(stderr_ring) > stderr_ring_size:
                del stderr_ring[0]
            is_running = self.process.poll() is None

        stderr_out = str.join("", stderr_ring)

        self.process.stdin.close()
        self.process.stderr.close()

        if self.process.returncode != 0:
            raise FFRuntimeError(self.cmd, self.process.returncode, stderr_out)

        return stderr_out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants